tensorflow2.0 c++ apiをcmakeで利用する(Ubuntu18.04)
1. 目次
- 1. 目次
- 2. はじめに
- 3. 環境
- 4. bazel version 0.26.1 のインストール
- 5. tensorflow 2.0.0 をソースからビルド
- 6. パスを通していく
- 7. サンプルをcmakeで動かす
2. はじめに
tensorflowをpythonで利用するのは情報もたくさんあるしpipで簡単に導入できるのに、C++で利用したいとなったときに全然まとまった記事がなかったので苦労しました。知識ある人はササッとできてしまうのかもしれませんが、私みたいな素人がtensorflow c++ apiを導入しようとすると一苦労です。というか実際なかなかうまく入らずめちゃ大変でした。
Ubuntu18.04でtensorflow2.0 c++ apiを導入するためのメモを残しておきます。
新たにtensorflowをc++で利用したいって人の助けになればと思います。
3. 環境
OS | Ubuntu 18.04 |
GPU | Geforce GTX 960 |
CUDA | ver.10.2 |
cuDNN | ver.7.6 |
bazel | ver. 0.26.1 |
tensorflow | ver. 2.0.0 |
4. bazel version 0.26.1 のインストール
まず、tensorflowをソースからビルドするためにGoogle独自のビルドツールである「bazel」をインストールします。
環境に合わせて今回は、bazel 0.26.1
をインストールします。以下のリンクから.shファイルをダウンロードできます。
tensorflow, CUDA, cuDNNのバージョンによって対応するbazelのバージョンも異なってくるので注意してください。tensorflowの公式に対応表が載っているのですが、古くて使い物になりませんでした。
上記リンクから、Ubuntuの場合は次の.shファイルをダウンロード
bazel-0.26.1-installer-linux-x86_64.sh
それではインストールしていきます。
# cd ~/Download/ $ chmod +x bazel-0.26.1-installer-linux-x86_64.sh $ ./bazel-0.26.1-installer-linux-x86_64.sh --user $ source ~/.bashrc # インストールされたか確認 $ bazel version Starting local Bazel server and connecting to it... Build label: 0.26.1 Build target: bazel-out/k8-opt/bin/src/main/java/com/google/devtools/build/lib/bazel/BazelServer_deploy.jar Build time: Thu Jun 6 11:05:05 2019 (1559819105) Build timestamp: 1559819105 Build timestamp as int: 1559819105
Build label: 0.26.1
がインストールしたいバージョンと一致しているので大丈夫ですね。
もし間違っていたら、ダウンロードしてくる.shファイルを間違えている可能性があるので、再度ダウンロード・インストールを行ってください。
5. tensorflow 2.0.0 をソースからビルド
今回は、現在(2020/1)時点でstable版の最新であるtensorflow2.0.0
を導入していきます。
C++で利用するためにはソースからビルドする必要があるのでちょっと面倒です。pipインストールが楽すぎる…。しかもビルドにはGoogleしかおそらく使ってないであろうbazelを利用しなければなりません。
< ここで一点注意事項 >
bazelでビルドする際に、他のサイトでは
$ bazel build -c opt --config=cuda --copt=-march=native tensorflow:libtensorflow.so
と書かれていることが多いですが、以下のように生成する共有ライブラリはtensorflow:libtensorflow_cc.so
としてください。こちらの記事に同じ事が書かれています。
$ bazel build -c opt --config=cuda --copt=-march=native tensorflow:libtensorflow_cc.so
それではtensorflowをビルドしていきましょう。
$ git clone https://github.com/tensorflow/tensorflow.git $ cd tensorflow # 新たにブランチを作成しcheckout $ git checkout -b work_v2.0.0 v2.0.0 # CUDA設定以外は基本的にNoかDefault ./configure # third_party/nccl/build_defs.bzl.tpl 内の以下の行を削除する # "--bin2c-path=%s" % bin2c.dirname $ vim third_party/nccl/build_defs.bzl.tpl # Delete>> "--bin2c-path=%s" % bin2c.dirname # bazelでビルドする $ bazel build -c opt --config=cuda --copt=-march=native tensorflow:libtensorflow_cc.so <--略--> Target //tensorflow:libtensorflow_cc.so up-to-date: bazel-bin/tensorflow/libtensorflow_cc.so INFO: Elapsed time: 3246.956s, Critical Path: 207.09s INFO: 7346 processes: 7346 local. INFO: Build completed successfully, 12925 total actions
Build completed successfully
とでていれば、これでビルド完了。
ちゃんとビルドできているか確認します。
$ ls bazel-bin/tensorflow/ c/ libtensorflow_cc.so.2.0.0 cc/ libtensorflow_cc.so.2.0.0-2.params compiler/ libtensorflow_framework.so.2 core/ libtensorflow_framework.so.2.0.0 libtensorflow_cc.so libtensorflow_framework.so.2.0.0-2.params libtensorflow_cc.so.2 stream_executor/
以下の2つが生成されていればビルド成功です。
- "libtensorflow_cc.so.2.0.0"
- ”libtensorflow_framework.so.2.0.0”
6. パスを通していく
以下のサイトを参考
6.1. 共有ライブラリのコピー
共有ライブラリ名は以下のようにしてください。
- libtensorflow_cc.so.2
- libtensorflow_framework.so.2
他のサイトで見られるlibtensorflow_cc.so
、libtensorflow_framework.so
だとリンカーエラーになります。tensorflow2.0だからかな?
$ sudo cp bazel-bin/tensorflow/libtensorflow_cc.so.2.0.0 /usr/local/lib/libtensorflow_cc.so.2 $ sudo cp bazel-bin/tensorflow/libtensorflow_framework.so.2.0.0 /usr/local/lib/libtensorflow_framework.so.2
6.2. ヘッダファイルの抽出
以下のcopy_tensorflow_headers.shファイルを~/tensorflow/
直下において実行。こちらのコードを修正して利用します。必要以上に抽出してる気がするけど細かい部分確認していないのでとりあえずこのままで大丈夫です。
copy_tensorflow_headers.sh
#!/bin/bash -eu # -*- coding: utf-8 -*- # Referece: # [copy_tensorflow_headers.sh](https://gist.github.com/saitodev/3cde48806a32272962899693700d9669) HEADER_DIR=/usr/local/include/tensorflow if [ ! -e $HEADER_DIR ]; then mkdir -p $HEADER_DIR fi find tensorflow/core -follow -type f -name "*.h" -exec cp --parents {} $HEADER_DIR \; find tensorflow/cc -follow -type f -name "*.h" -exec cp --parents {} $HEADER_DIR \; find tensorflow/c -follow -type f -name "*.h" -exec cp --parents {} $HEADER_DIR \; find third_party/eigen3 -follow -type f -exec cp --parents {} $HEADER_DIR \; pushd bazel-genfiles find tensorflow -follow -type f -name "*.h" -exec cp --parents {} $HEADER_DIR \; popd pushd bazel-tensorflow/external/eigen_archive find Eigen -follow -type f -exec cp --parents {} $HEADER_DIR \; find unsupported -follow -type f -exec cp --parents {} $HEADER_DIR \; popd pushd bazel-tensorflow/external/com_google_protobuf/src find google -follow -type f -name "*.h" -exec cp --parents {} $HEADER_DIR \; find google -follow -type f -name "*.inc" -exec cp --parents {} $HEADER_DIR \; popd pushd bazel-tensorflow/external/com_google_absl find absl -follow -type f -name "*.h" -exec cp --parents {} $HEADER_DIR \; find absl -follow -type f -name "*.inc" -exec cp --parents {} $HEADER_DIR \; popd pushd ~/.cache/bazel/_bazel_fsato/ce9d2ac105b59fe4ccec7c9da3d0efcf/external find eigen_archive -follow -type f -name "*.h" -exec cp --parents {} $HEADER_DIR \; find com_google_protobuf -follow -type f -name "*.h" -exec cp --parents {} $HEADER_DIR \; popd
下記コマンドで実行すると、必要なヘッダーファイルがHEADER_DIR
で指定した/usr/local/include/tensorflow
内にコピーされます。
# ~/tensorflow
$ sudo bash copy_tensorflow_headers.sh
6.3. FindTensorflow.cmakeの作成
cmakeでパッケージを探せるように設定しておきます。
こちらのリンク先)のファイルFindTensorflow.cmake
を、他のFindFoo.cmake
がある場所におきます。
$ cp FindTensorflow.cmake /usr/share/cmake-3.10/Modules/
7. サンプルをcmakeで動かす
サンプルが用意されているので、その中でもよくデモとして利用されるtensorflow/examples/label_image/
を試しに動かしてみます。これは一枚の画像から物体認識を行うデモになっています。
扱いやすいようにlabel_image/
以下を好きなディレクトリにコピーしましょう。例として~/myws/
にコピーしました。
# ~/tensorflow
cp tensorflow/examples/label_image ~/myws
7.1. モデルのダウンロード
サンプルを動かすためにはモデルをダウンロードしてくる必要があります。
以下のコマンドでダウンロードできます。
$ curl -L "https://storage.googleapis.com/download.tensorflow.org/models/inception_v3_2016_08_28_frozen.pb.tar.gz" | tar -C ~/myws/label_image/data -xz
7.2. 下準備
それではlabel_imageデモを動かしてみます。
まず、main.cc
でモデルを読み込んでいる部分のパスを変更します(main文の中)。
- string image = "tensorflow/examples/label_image/data/grace_hopper.jpg"; +tring image = "../data/grace_hopper.jpg"; - string graph = "tensorflow/examples/label_image/data/inception_v3_2016_08_28_frozen.pb"; +string graph = "../data/inception_v3_2016_08_28_frozen.pb"; -string labels = "tensorflow/examples/label_image/data/imagenet_slim_labels.txt"; +string labels = "../data/imagenet_slim_labels.txt";
次にCMakeLists.txt
を作成し、~/myws/label_image
におきます。
「FindTensorflow.cmakeの作成」でCmakeで簡単に呼び出せるように設定したのでそれを利用します。ただ共有ライブラリに関してはなぜかフルパスを指定してあげないとリンカーエラーとなってしまいました。ここは調べとかないとですね。
# CMakeLists.txt cmake_minimum_required(VERSION 3.10) find_package(Tensorflow REQUIRED) include_directories(${Tensorflow_INCLUDE_DIRS}) #add_executable(hello_tensorflow hello_tensorflow.cpp) add_executable(label_image main.cc) # Link the static Tensorflow library. target_link_libraries(label_image "/usr/local/lib/libtensorflow_cc.so.2") target_link_libraries(label_image "/usr/local/lib/libtensorflow_framework.so.2")
7.3. サンプルの実行
# ~/myws/label_image $ mkdir build && cd build $ cmake .. $ make $ ./label_image
実行結果
2020-01-16 22:40:18.908806: I /label_image/main.cc:251] military uniform (653): 0.834305 2020-01-16 22:40:18.908820: I /label_image/main.cc:251] mortarboard (668): 0.0218697 2020-01-16 22:40:18.908826: I /label_image/main.cc:251] academic gown (401): 0.0103582 2020-01-16 22:40:18.908831: I /label_image/main.cc:251] pickelhaube (716): 0.00800826 2020-01-16 22:40:18.908836: I /label_image/main.cc:251] bulletproof vest (466): 0.00535093
ちゃんと認識できていることが確認できました!