人工知性を作りたい

私が日々、挑戦したことや学んだことなどを紹介していく雑記ブログです。 (新しいAI技術HTM, 専門の音声信号処理, 趣味のアニメ等も書いてます。)

global navigation menu page top

pybind11って何? ー PythonでC・C++を動かす

f:id:hiro-htm877:20190616152255j:plain





 

f:id:hiro-htm877:20190601202549p:plain

 「ループなどの実行速度はpythonよりCの方が速いので、一部の処理だけC言語で実装したい」

「nupicを使うときにpybindが出てきたけどこれ何!?」

 

 

 

そんな方の疑問に答えます

 

コードが知りたい方は目次のソースコードへ飛んでください!

本記事のテーマ

【完全初心者向け】

・pybind11の理解!

PythonでC・C++を動かす

 

(今回はCPUのエンディアンチェックをC++で実装し、pythonで動かす)

pybind11とは

pybind11はC++Pythonを連携させるためのライブラリである。以下のような特徴がある。

  • header-based libraryなのでライブラリ自体のビルドは必要ない
  • numpyとEigen間の連携が標準でサポートされている
  • C++11が使えるコンパイラが必要

(https://kivantium.net/cpp-pybind11 から引用)

pybind11のインストール!

pip install pybind11

PythonでC・C++動かす!【実装】

流れ

pybind11の連携

1. C・C++の実装したいコードを書く

2. 1と同じファイルにpybind11の連携コードを書く

3. C・C++ファイルをコンパイルする

4. pythonで実行する

(今回はCPUのエンディアンチェックをC++で実装し、pythonで動かす)

〜pybind11の連携コード

PYBIND11_MODULE()はPythonでimportする際の関数を作成する

第一引数がimportする際の名前になる!

m.def()の第二引数にpythonで実行したい関数のアドレスを入力する

 

ちなみに、C++コード内のreinterpret_cast<char*>は強制的にキャストしたいときに使うものです。今回はint型を無理やりchar型に変換しました。

code
#include<pybind11/pybind11.h>
int check_endian() {
  int src = 0x01234567;
  char* src_p;
  src_p = reinterpret_cast<char*>(&src);
  printf("int src       : 0x%x\n", src);
  printf("int src >> 24 : 0x%x\n", src >> 24);
  printf("char src_p    : 0x%x\n", *src_p);
  printf("char src_p[1] : 0x%x\n", src_p[1]);
  if(*src_p != src >> 24){
    printf("\nThis CPU is Littel Endian.\n");
    return 1;
  }else{
    printf("\nThis CPU is Big Endian.\n");
    return 0;
  }
}
//PYBIND11_MODULE()はPythonでimportする際の関数を作成する
PYBIND11_MODULE(test, m) {
    m.doc() = "pybind11 example plugin";
    m.def("check_endian", &check_endian, "A function which adds tow numbers");
}

C・C++ファイルをコンパイルする

コンパイルのコマンドは以下の通りです。

clang++ -O3 -Wall -shared -std=c++11 -fPIC `python -m pybind11 --includes` -undefined dynamic_lookup check_endian.cpp -o test`python3-config --extension-suffix`

・-oの前には連携したいC++のファイル名を書く

・-oの後にはimportする際の関数名を書く(cppファイル内の名前と揃える)

 

出力 

test.cpython-37m-darwin.so

C++の実行ファイルが作られます。

 

pythonで実行する

code 
import test

if __name__ == "__main__" :
    conclusion = test.check_endian()
    print("\n"+"###"*10)
    print("conclusion", conclusion)

出力 

int src : 0x1234567

int src >> 24 : 0x1

char src_p : 0x67

char src_p[1] : 0x45

 

This CPU is Littel Endian.

##############################

conclusion 1

完成です!

C++で書いたエンディアン判別をPythonで実行しました。

 

機械学習などで大量の計算をする際には、こういった一工夫が必要になるのではないかと思います。知ってるだけで、次に出会ったときに対処できるので一度自分で実装してみて下さい!