TadaoYamaokaの日記

山岡忠夫Homeで公開しているプログラムの開発ネタを中心に書いていきます。

TensorFlowをWindowsでGPU有効でビルドしてC++で使う

TensorFlowは公式でWindowsに対応しているが、C++APILinuxMacでしかサポートされていない。
Installing TensorFlow for C  |  TensorFlow

dllをダウンロードして、defを作成してリンクする方法もあるようだが、CPUでしか使えない。
visual studioでtensorflow - Qiita

WindowsGPUを有効にしてC++からTensorFlowを使うには、自分でビルドする必要がある。
ビルドは以前の日記に書いたCMakeを使う方法でできる。
最新版に対応した手順は、ここを参照する。
tensorflow/README.md at master · tensorflow/tensorflow · GitHub

以下に手順を示す。

関連ツール・ライブラリインストール

以下のツール・ライブラリをインストールする。

Python版のTensorFlowは公式からインストールできるので、無効にしてビルドする。

ビルド

コマンドプロンプト起動

スタートメニューから、「VS2015 x64 Native Tools コマンド プロンプト」を選択して、コマンドプロンプトを起動する。

TensorFlowのソースダウンロード

GitHubからTensorFlow 1.5のソースをダウンロードして展開する。
Releases · tensorflow/tensorflow · GitHub

以下、「C:\tensorflow-1.5.0」に展開したものとして記述する。

cmakeコマンドでビルドファイル作成

以下のコマンドを実行する。

cmake .. -A x64 -DCMAKE_BUILD_TYPE=Release ^
-DSWIG_EXECUTABLE=C:\swigwin-3.0.10\swig.exe ^
-Dtensorflow_BUILD_PYTHON_BINDINGS=OFF ^
-Dtensorflow_ENABLE_GRPC_SUPPORT=OFF ^
-Dtensorflow_ENABLE_GPU=ON ^
-DCUDNN_HOME="%CUDA_PATH%" ^
-Dtensorflow_WIN_CPU_SIMD_OPTIONS=/arch:AVX

オプションに「-Dtensorflow_ENABLE_GPU=ON」を指定することでGPUが有効になる。
AVX命令を有効にしている。
Pythonバインディングは無効にしている。

ビルド

以下のコマンドを実行する。

MSBuild /p:Configuration=Release ALL_BUILD.vcxproj

ビルドにはCore i7 4コア 4GHzのPCで、3時間かかった。

C++で使う際のプロジェクトの設定

Building a standalone C++ Tensorflow program on Windows – Joe Antognini
こちらのページのサンプルプログラムをコンパイルするための設定を示す。

GPUを有効にする場合は、上記のページの手順では不足するため、以下に設定内容を示す。

Release/x64の構成に対して行う。(TensorFlowをデバッグビルドしていない場合、Debug/x64も同じでよい。)

インクルードディレクトリ設定

以下のパスをインクルードディレクトリに追加する。

C:\tensorflow-1.5.0
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\eigen_archive
C:\tensorflow-1.5.0\third_party\eigen3
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\protobuf\src\protobuf\src
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\nsync\src\nsync\public
ライブラリディレクトリ設定

以下のパスをライブラリディレクトリに追加する。

C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\protobuf\src\protobuf\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_cc.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_cc_ops.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_cc_framework.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_cpu.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_direct_session.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_framework.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_kernels.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_lib.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_ops.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\nsync\src\nsync\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\snappy\src\snappy\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\sqlite\src\sqlite-build\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_cc_while_loop.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_stream_executor.dir\Release
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\lib\x64

最後の2行がGPUを有効するために必要。

リンクするライブラリ設定

リンクの入力に以下のライブラリを追加する。

zlib\install\lib\zlibstatic.lib
gif\install\lib\giflib.lib
png\install\lib\libpng12_static.lib
jpeg\install\lib\libjpeg.lib
lmdb\install\lib\lmdb.lib
jsoncpp\src\jsoncpp\src\lib_json\Release\jsoncpp.lib
farmhash\install\lib\farmhash.lib
fft2d\src\lib\fft2d.lib
highwayhash\install\lib\highwayhash.lib
libprotobuf.lib
tf_protos_cc.lib
tf_cc.lib
tf_cc_ops.lib
tf_cc_framework.lib
tf_core_cpu.lib
tf_core_direct_session.lib
tf_core_framework.lib
tf_core_kernels.lib
tf_core_lib.lib
tf_core_ops.lib
nsync.lib
snappy.lib
sqlite.lib
tf_cc_while_loop.lib
tf_core_gpu_kernels.lib
tf_stream_executor.lib
cuda.lib
cudart.lib
cusolver.lib
cublas.lib
curand.lib
cufft.lib
cudnn.lib

tf_core_gpu_kernels.lib以降の行がGPUを有効にするために必要。

なお、必要なライブラリは、ビルドしてリンカのエラーを表示して、

dumpbin /symbols C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_contrib_rnn_lstm_ops.dir\Release\tf_contrib_rnn_lstm_ops.lib | grep perftools::gputools::Stream::Stream

のようにして、すべての.libに対してdumpbinコマンドを実行してシンボルが含まれるライブラリを調べた。

リンカのオプション設定

リンカの追加オプションに以下を追加する。

/WHOLEARCHIVE:tf_cc.lib
/WHOLEARCHIVE:tf_cc_framework.lib
/WHOLEARCHIVE:tf_cc_ops.lib
/WHOLEARCHIVE:tf_core_cpu.lib
/WHOLEARCHIVE:tf_core_direct_session.lib
/WHOLEARCHIVE:tf_core_framework.lib
/WHOLEARCHIVE:tf_core_kernels.lib
/WHOLEARCHIVE:tf_core_lib.lib
/WHOLEARCHIVE:tf_core_ops.lib
/WHOLEARCHIVE:tf_stream_executor.lib
/WHOLEARCHIVE:libjpeg.lib

サンプルプログラムのビルドと実行

ビルド

プロジェクトの構成をRelease/x64にしてビルドする。
ランタイムライブラリは、デフォルトの「マルチスレッドDLL(/MD)」とする。

実行

成功すると、以下のように表示される。

2018-02-26 23:47:33.024224: I C:\tensorflow-1.5.0\tensorflow\core\platform\cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2018-02-26 23:47:33.610718: I C:\tensorflow-1.5.0\tensorflow\core\common_runtime\gpu\gpu_device.cc:1105] Found device 0 with properties:
name: GeForce GTX 1080 major: 6 minor: 1 memoryClockRate(GHz): 1.8225
pciBusID: 0000:01:00.0
totalMemory: 8.00GiB freeMemory: 6.61GiB
2018-02-26 23:47:33.615178: I C:\tensorflow-1.5.0\tensorflow\core\common_runtime\gpu\gpu_device.cc:1195] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: GeForce GTX 1080, pci bus id: 0000:01:00.0, compute capability: 6.1)
 7 17
-1 -3

PCを起動後の初回は時間がかかるが、2回目からはすぐに結果が表示される。

2018/2/27 追記

GPUを使うサンプルになっていなかったので、TensorFlowのソースに含まれるexample_trainer.ccをビルドした。
tensorflow/example_trainer.cc at master · tensorflow/tensorflow · GitHub

プロジェクトの設定はcmakeで生成したtf_tutorials_example_trainerのプロジェクトとできるだけ合わせた。

インクルードディレクト
C:\tensorflow-1.5.0
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\zlib_archive
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\gif_archive\giflib-5.1.4
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\png_archive
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\jpeg_archive
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\lmdb
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\eigen_archive
C:\tensorflow-1.5.0\third_party\eigen3
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\gemmlowp\src\gemmlowp
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\jsoncpp\src\jsoncpp
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\farmhash_archive
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\farmhash_archive\util
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\highwayhash
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\cub\src\cub
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\nsync\public
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\protobuf\src\protobuf\src
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\re2\install\include
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\external\sqlite
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\snappy\src\snappy
ライブラリディレクト
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_cc.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_cc_ops.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_cc_framework.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_cpu.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_direct_session.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_framework.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_kernels.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_lib.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_core_ops.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_cc_while_loop.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\tf_stream_executor.dir\Release
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build
C:\tensorflow-1.5.0\tensorflow\contrib\cmake\build\Release
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\lib\x64
プリプロセッサ

以下のマクロ定義を追加

_ITERATOR_DEBUG_LEVEL=0
EIGEN_AVOID_STL_ARRAY
NOMINMAX
_WIN32_WINNT=0x0A00
LANG_CXX11
COMPILER_MSVC
OS_WIN
WIN64
WIN32_LEAN_AND_MEAN
NOGDI
PLATFORM_WINDOWS
TENSORFLOW_USE_EIGEN_THREADPOOL
EIGEN_HAS_C99_MATH
TF_COMPILE_LIBRARY
TF_USE_SNAPPY
GOOGLE_CUDA=1
ライブラリの入力設定
tf_protos_cc.lib
tf_core_gpu_kernels.lib
tf_core_cpu.lib
tf_stream_executor.lib
tf_core_direct_session.lib
tf_core_kernels.lib
tf_core_ops.lib
tf_cc_ops.lib
tf_core_framework.lib
tf_core_lib.lib
tf_cc_framework.lib
tf_cc_while_loop.lib
zlib\install\lib\zlibstatic.lib
gif\install\lib\giflib.lib
png\install\lib\libpng12_static.lib
jpeg\install\lib\libjpeg.lib
lmdb\install\lib\lmdb.lib
jsoncpp\src\jsoncpp\src\lib_json\Release\jsoncpp.lib
farmhash\install\lib\farmhash.lib
fft2d\src\lib\fft2d.lib
highwayhash\install\lib\highwayhash.lib
nsync\install\lib\nsync.lib
protobuf\src\protobuf\Release\libprotobuf.lib
re2\src\re2\Release\re2.lib
sqlite\install\lib\sqlite.lib
snappy\src\snappy\Release\snappy.lib
cuda.lib
cudart.lib
cusolver.lib
cublas.lib
curand.lib
cufft.lib
cudnn.lib
cuda.lib
cudart.lib
cusolver.lib
cublas.lib
curand.lib
cufft.lib
cudnn.lib
リンカの追加オプション
/machine:x64 /ignore:4049 /ignore:4197 /ignore:4217 /ignore:4221
/WHOLEARCHIVE:tf_cc.lib
/WHOLEARCHIVE:tf_cc_framework.lib
/WHOLEARCHIVE:tf_cc_ops.lib
/WHOLEARCHIVE:tf_core_cpu.lib
/WHOLEARCHIVE:tf_core_direct_session.lib
/WHOLEARCHIVE:tf_core_framework.lib
/WHOLEARCHIVE:tf_core_kernels.lib
/WHOLEARCHIVE:tf_core_lib.lib
/WHOLEARCHIVE:tf_core_ops.lib
/WHOLEARCHIVE:tf_stream_executor.lib
実行

実行時に「--use_gpu」を付けるとGPUが有効になる。
このサンプルだとGPUだと2.671sec、CPUだと1.462secと、CPUの方が実行時間が速かった。

なお、バイナリサイズは、238MBになる。