C++でもnumpyっぽく使えるxtensorを試してみます。
インストール
まずは、インストール。次のスクリプトを実行します。
#!/bin/bash git clone https://github.com/xtensor-stack/xtensor.git git clone https://github.com/xtensor-stack/xtl.git git clone https://github.com/xtensor-stack/xsimd.git git clone https://github.com/xtensor-stack/xtensor-blas.git INSTALL_PATH=$(pwd)/root for x in xtl xsimd xtensor xtensor-blas do echo "-------- $x ----------" cd $x mkdir -p build cd build cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH .. make install cd ../.. done
行列積の計算時間
行列積の計算時間を測定してみます。測定する処理を書いたC++のコードは次の通り。10000x10000の2つの行列の積を計算し、その後、平均値を計算します。これを5回繰り返します。なお、平均値は10000になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <iostream>
#include "xtensor.hpp"
#include "xtensor-blas/xlinalg.hpp"
void dot(void){
xt::xarray<float> a = xt::ones<float>({10000, 10000});
xt::xarray<float> b = xt::ones<float>({10000, 10000});
for(int i=0; i<5; ++i){
auto d = xt::linalg::dot(a, b);
auto c = xt::average(d);
std::cout << c << std::endl;
}
}
int main(void){
dot();
return 0;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | cmake_minimum_required(VERSION 3.10)
project(xtexample VERSION 1.0)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_definitions(-DHAVE_CBLAS=1)
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
add_executable(xtexample dot.cpp)
set(XTENSOR_USE_XSIMD ON)
set(xtensor_path "/path/to/xtensor/root")
set(xtensor_DIR "${xtensor_path}/lib/cmake/xtensor")
set(xtl_DIR "${xtensor_path}/lib/cmake/xtl")
set(xsimd_DIR "${xtensor_path}/lib/cmake/xsimd")
find_package(xtensor REQUIRED)
target_include_directories(xtexample PUBLIC ${xtensor_INCLUDE_DIRS})
target_link_libraries(xtexample PUBLIC xtensor xtensor xtensor::optimize xtensor::use_xsimd
${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
|
$ mkdir build $ cd build $ cmake -DCMAKE_BUILD_TYPE=Release .. $ make処理時間を測定します。
$ for _ in {1..4}; do time ./xtexample; done結果は次の通りです。4コア8スレッドのCPUで測定しています。
Trial # | real | user | sys |
---|---|---|---|
1 | 0m43.805s | 5m17.723s | 0m23.991s |
2 | 0m46.952s | 5m44.626s | 0m21.066s |
3 | 0m49.060s | 5m59.719s | 0m22.163s |
4 | 0m50.819s | 6m9.617s | 0m25.812s |
Python numpyとの比較
比較のため、Pythonのnumpyで同じことをしてみます。測定コードは以下の通り。
1 2 3 4 5 6 7 8 9 10 11 | import numpy as np
def dot():
a = np.ones((10000, 10000), dtype=np.float32)
b = np.ones((10000, 10000), dtype=np.float32)
for i in range(5):
d = np.dot(a, b)
c = np.average(d)
print(c)
dot()
|
for _ in {1..4}; do time python3 comp.py; done結果は次の通り。
Trial # | real | user | sys |
---|---|---|---|
1 | 0m44.816s | 5m29.361s | 0m17.726s |
2 | 0m49.529s | 6m5.012s | 0m21.217s |
3 | 0m49.188s | 5m58.570s | 0m24.681s |
4 | 0m50.497s | 6m11.620s | 0m22.015s |
まとめ
C++でnumpyのように行列計算を使いたい場合は、xtensorを使えばよさそうです。 処理速度に関しても、少なくとも行列積に関してはnumpyに比べて遅いわけではないようです。