はじめに
Pythonのコードを高速化するために、PythonのコードへC++で書いたコードを組み込めないか探していたところ、pybind11を知りました。
他にもPythonとC++の連携やPythonの高速化のための手段は多くあるとは思いますが(Boost.Python、Cython)、一番簡単にできそうだったので、pybind11を選びました。結果的に、手順が分かればかなり簡単でした。
現在私は、基本的にWSL上でコードを書いて、実行しているので、WSL(Ubuntu)でpybindを設定する方法を記載していきたいと思います。また、おまけとしてEigen(C++の線形代数ライブラリ)をPythonから動かすための方法も紹介します。
ちなみに私の環境は下記です。
- VSCode
- WSL2(Windows Subsystem for Linux)
- CMake
- pyenv+virtual env
- Eigen
WSL上でのPython実行環境の構築については下記の記事を参考にしていただければと思います。
PythonへC++を組み込む!
では、こちらのサイトに従って進めていきましょう。
Using pybind11 for Python Bindings of C++ code (Linux/WSL)
下準備
まずは、こちらのサイトのSet up your Linux environmentまで行いましょう。
その後、こちらのサイトのCheck if GCC is installedまで行いましょう。
ここまでで、VSCodeでWSLに接続して、Cmakeでコンパイルできる環境になります。
参考:Cmakeはこちらを参考にしてください。自分も勉強中…。勝手に作るCMake入門 その1 基本的な使い方
pybind11を実際に使ってみる
PythonBindingsディレクトリを作成します。(場所はどこでも良いですが、ここでは/home/kotoha/PythonBindings
に作ります。
mkdir /home/kotoha/PythonBindings
cd /home/kotoha/PythonBindings
VSCodeで開きます。
code .
main.cppファイルを作成します。
#include <pybind11/pybind11.h>
namespace py = pybind11;
double sum(double a, double b) {
return a + b;
}
PYBIND11_MODULE(SumFunction, var) {
var.doc() = "pybind11 example module";
var.def("sum", &sum, "This function adds two input numbers");
}
コマンドパレットから、CMake: Quick Startを選び、プロジェクト名をProjectpybind11とし、Create an executableとして、CMakeLists.txtファイルを作成します。
CMakeLists.txtを開いてみると、下記のような中身になっているはずです。
cmake_minimum_required(VERSION 3.0.0)
project(Projectpybind11 VERSION 0.1.0)
include(CTest)
enable_testing()
add_executable(Projectpybind11 main.cpp)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
次に、pybind11をクローンしてきます。
git clone https://github.com/pybind/pybind11.git
クローンできたら、インストールしていきます。もしここで何かしらwarning等が出たら、コンソールの表示に従って対処しましょう。
cd /home/kotoha/PythonBindigs
pip install pytest numpy scipy
sudo apt install -y cmake python3-dev libeigen3-dev libboost-dev git
cd pybind11
cmake -DDOWNLOAD_CATCH=1
mkdir build
cd build
cmake ..
sudo make install
cd ..
ここまでできたら、CMakeLists.txtファイルを下記のように編集します。
cmake_minimum_required(VERSION 3.0.0)
project(Projectpybind11 VERSION 0.1.0)
include(CTest)
enable_testing()
add_subdirectory(pybind11)
pybind11_add_module(SumFunction main.cpp)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
次に、Pythonファイルの作成を行います。
cd /home/kotoha/PythonBindigs
mkdir build
cd build
cmake ..
make
cd ..
touch main.py
main.pyファイルは下記のように書いておきます。
from build.SumFunction import sum
print(sum(3,2))
最後に、main.pyを実行してみます!下記のように出力が得られればOKです。
cd build
cmake ..
# -- pybind11 v2.12.0 dev1
# -- Configuring done
# -- Generating done
# -- Build files have been written to: /home/kotoha/PythonBindings/build
make
# Consolidate compiler generated dependencies of target SumFunction
# [100%] Built target SumFunction
python ../main.py
# 5.0
もし、C++のファイルを変更したら…
C++のファイルを書き換えたらどこから行えば良いでしょうか。
下記のコマンドからやり直せば、OKです。
cd /home/kotoha/PythonBindigs/build
cmake ..
make
ここまででC++の関数の準備ができるので、あとはpythonファイルを実行すればOKです。
cd /home/kotoha/PythonBindigs
python main.py
おまけ:Eigenを使ったC++コードのPythonからの実行
Eigenとは
Eigen C++の線形代数ライブラリ(あまり使ったことはないので勉強中です…)
Eigenのインストール
下記コマンドでEigenをインストールします。
sudo apt install libeigen3-dev
Eigen使用サンプルコード
main.cppを次のように書き換えます。
#include <pybind11/pybind11.h>
#include <Eigen/Dense>
#include <pybind11/eigen.h>
namespace py = pybind11;
double sum(double a, double b)
{
return a + b;
}
Eigen::MatrixXd inverse(const Eigen::MatrixXd &x)
{
return x.inverse();
}
PYBIND11_MODULE(SumFunction, var)
{
var.doc() = "pybind11 example module";
var.def("sum", &sum, "This function adds two input numbers");
var.def("inverse", &inverse);
}
CMakeLists.txtは下記のように編集します。
cmake_minimum_required(VERSION 3.0.0)
project(Projectpybind11 VERSION 0.1.0 LANGUAGES C CXX)
include(CTest)
enable_testing()
find_package(Eigen3 REQUIRED)
add_subdirectory(pybind11)
pybind11_add_module(SumFunction main.cpp)
target_link_libraries(SumFunction PRIVATE Eigen3::Eigen)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
main.pyは下記のように編集します。
import numpy as np
from build.SumFunction import inverse, sum
print(sum(3,2))
result = inverse(np.array([[1.0, 2.0], [3.0, 4.0]]))
print(result)
Eigenを使ったコードの実行
main.pyを実行します!下記と同じような結果が得られればOKです。
cd /home/kotoha/PythonBindigs
python main.py
# 5.0
# [[-2. 1. ]
# [ 1.5 -0.5]]
おわりに
以上、WSL上でPythonからC++コードを実行するためのpybindの使い方を示してきました。
気が向いたら、Armadilloを使ったC++コードでもPythonから動かせるのか試したいと思ってます。
コメント