WSL上でPythonからC++を動かす!(pybind11 + Eigen)

Programming
スポンサーリンク

はじめに

Pythonのコードを高速化するために、PythonのコードへC++で書いたコードを組み込めないか探していたところ、pybind11を知りました。

他にもPythonとC++の連携やPythonの高速化のための手段は多くあるとは思いますが(Boost.PythonCython)、一番簡単にできそうだったので、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から動かせるのか試したいと思ってます。

参考

Using pybind11 for Python Bindings of C++ code (Linux/WSL) — Part I
Pybind11 Tutorial for allowing us to take advantage of C/C++ libraries from Python
Eigenのインストール方法(WSL) - Qiita
はじめにWSLでのC++の外部ライブラリの管理について - Qiitaインストール先の話など細かいところは割愛しているので,わからない場合はこちらの記事を先に読んでください.方法①aptでイ…
Why don't you need to do target_link_libraries when using Eigen with pybind11
I was trying to compile this example.cpp from a pybind11 tutorial called pybind11_examples on GitHub #include <pybind11/...
C++で書いたコードをPythonで動かすには【pybind11】

コメント

タイトルとURLをコピーしました