TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

WindowsでCaffeをビルドしてGPUで実行する

※2017/3/15追記 Windows版のリポジトリでビルド済みのバイナリが配布されています。自分でビルドしないでもそちらのバイナリを使用することをお勧めします。
ビルド済みのバイナリのインストール方法とサンプルの実行方法はこちらの日記を参照ください。

WindowsでCaffeをビルドすることができたので方法を示しておきます。

Windows版のCaffeは公式のページからGithubのレポジトリへのリンクがあるので、そのREADMEに従えばビルドできます。
ただし、GPUで実行しようとするとビルドの設定変更が必要な個所がありました。
はじめその設定がわからず以下のようなエラーが出てあきらめていましたが、某所からやり方法を教えてもらって解決しました。

check failed: error == cudasuccess (8 vs. 0) invalid device function

なお、以下の説明はコマンドもしくは、C++から利用することを想定しており、Pythonから利用する場合は、追加で対応が必要になります。詳細はREADMEを読んでください。

手順を順番を追って説明します。

ビルド/実行環境

レポジトリのダウンロード

Git for Windowsをインストール済みの前提で説明します。

コマンドラインで任意のディレクトリに移動して、Windows版のブランチをダウンロードします。

git clone -b windows https://github.com/BVLC/caffe.git

CommonSettings.propsの編集

READMEに書かれているとおり、.\windows\CommonSettings.props.exampleをコピーして、.\windows\CommonSettings.propsを作成します。

CommonSettings.propsの

<CudaArchitecture>compute_35,sm_35;compute_52,sm_52</CudaArchitecture>

の部分を、実行する環境のGPUに合わせて編集します。
NvidaのページGPUの「Compute Capability」が記載されているので、例えば、Geforce GTX 760の場合は「3.0」なので、

<CudaArchitecture>compute_30,sm_30;compute_35,sm_35;compute_52,sm_52</CudaArchitecture>

のように、「compute_30,sm_30;」を追記します。

CUDAとcuDNNのインストール

CUDA7.5をNvidiaのサイトからダウンロードしてインストールします。

cuDNN v4もしくはv5をNvidiaのサイトからダウンロードしてインストールします。
ダウンロードするには登録が必要です。個人でも特に問題なく登録できます。

インストールは、zipファイルを解凍して、cudaディレクトリの中身を、「C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5」にコピーします。

v5の場合は、後述の通りCaffeのソース修正が必要になります。

Visual Studio 2013プロジェクトの設定

windows\Caffe.slnをVisual Stuido 2013で開きます。

アクティブな構成を変更します。(例:Release/x64)

ソリューションにプロジェクトがいくつもありますが、それぞれのプロジェクトを右クリックしてプロパティを選び、構成のプロパティ→C/C++→詳細設計を選び、指定の警告を無効にするに「4819」と入力してOKを押します。
これは、CUDAのソースにASCII以外の文字が含まれいるため出力される警告を無視するために設定します。警告があるとコンパイルエラー扱いに設定されているので必須です。

cuDNN v5対応

cuDNN v5をインストールした場合は、Windows版のCaffeはcuDNN v5に対応していないので、ソース修正が必要になります。v4をインストールした場合は不要です。
Windows版のCaffeをダウンロードしたディレクトリとは別のディレクトリに、最新のCaffeをダウンロードします。

git clone https://github.com/BVLC/caffe.git

cuDNN関連のソースがビルドエラーになるので、ビルドエラーになったソースを最新版のソースに置き換えていけばよいです。cudnn.hppは、全体を置き換えるとWindows対応のコードも置き換えてしまうので、「#if !defined (_MSC_VER)」の個所は置き換えないようにしてください。

対象のソースは以下のものです。

  • include\caffe\layers\cudnn_relu_layer.hpp
  • include\caffe\layers\cudnn_sigmoid_layer.hpp
  • include\caffe\layers\cudnn_tanh_layer.hpp
  • include\caffe\util\cudnn.hpp
  • src\caffe\layers\cudnn_conv_layer.cu
  • src\caffe\layers\cudnn_relu_layer.cu
  • src\caffe\layers\cudnn_relu_layer.cpp
  • src\caffe\layers\cudnn_sigmoid_layer.cu
  • src\caffe\layers\cudnn_sigmoid_layer.cpp
  • src\caffe\layers\cudnn_tanh_layer.cu
  • src\caffe\layers\cudnn_tanh_layer.cpp


CaffeのWindowsブランチをForkしてcuDNN v5向けに変更を加えたリポジトリを公開します。
github.com

ビルド

Caffeはいろいろなライブラリに依存していますが、NuGetから自動でダウンロードするようになっているので、そのままビルドできます。

メニューからビルド→ソリューションのビルドを選択して、ビルドを行います。
ビルドが完了するまで数分かかります。

ビルドが無事完了すると、Build\x64\Releaseに、exeとdllが作成されます。

MNISTサンプルで動作確認

MNISTサンプルで動作確認を行います。
実行方法は、基本的にexamples\mnist\readme.mdに従います。

MNISTサンプルは、examples\mnistにありますが、linux用のサンプルになっているので、Windowsで実行するにはいくつか修正が必要です。

まずスクリプトbashシェルスクリプトになっているので、MSYSをインストールします。

MNISTデータダウンロード

bashを起動し、Caffeのディレクトリに移動し、

./data/mnist/get_mnist.sh

を実行し、MNISTのデータをダウンロードします。
wgetとgunzipが使われています。不足しているコマンドがあれば、MinGWのパッケージマネージャでインストールしてください。

データ準備

examples\mnist\create_mnist.shを編集します。

  • 「BUILD=build/examples/mnist」→「BUILD=Build/x64/Release」に修正
  • 「convert_mnist_data.bin」→「convert_mnist_data.exe」に修正(2か所)

編集後、

./examples/mnist/create_mnist.sh

を実行します。

訓練実行

examples\mnist\train_lenet.shを編集します。

  • 「./build/tools/caffe」→「./Build/x64/Release/caffe」に修正

編集後、

./examples/mnist/train_lenet.sh

を実行します。

成功すれば以下のように出力されます。
デフォルトでGPUで実行されます。

bash.exe"-3.1$ ./examples/mnist/train_lenet.sh
I0619 22:48:09.056084  6428 caffe.cpp:186] Using GPUs 0
I0619 22:48:09.426971  6428 caffe.cpp:191] GPU 0: GeForce GTX 760
I0619 22:48:09.847589  6428 common.cpp:36] System entropy source not available, using fallback algorithm to generate seed instead.
I0619 22:48:09.848960  6428 solver.cpp:48] Initializing solver from parameters:
test_iter: 100
test_interval: 500
base_lr: 0.01
display: 100
max_iter: 10000
lr_policy: "inv"
gamma: 0.0001
power: 0.75
momentum: 0.9
weight_decay: 0.0005
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
solver_mode: GPU
device_id: 0
net: "examples/mnist/lenet_train_test.prototxt"
I0619 22:48:09.850059  6428 solver.cpp:91] Creating training net from net file: examples/mnist/lenet_train_test.prototxt
I0619 22:48:09.851061  6428 net.cpp:313] The NetState phase (0) differed from the phase (1) specified by a rule in layer mnist
I0619 22:48:09.851563  6428 net.cpp:313] The NetState phase (0) differed from the phase (1) specified by a rule in layer accuracy
I0619 22:48:09.852064  6428 net.cpp:49] Initializing net from parameters:
(省略)
I0619 22:48:52.758535  6428 sgd_solver.cpp:106] Iteration 9400, lr = 0.00608343
I0619 22:48:53.152582  6428 solver.cpp:337] Iteration 9500, Testing net (#0)
I0619 22:48:53.351280  6428 solver.cpp:404]     Test net output #0: accuracy = 0.988
I0619 22:48:53.351280  6428 solver.cpp:404]     Test net output #1: loss = 0.0367942 (* 1 = 0.0367942 loss)
I0619 22:48:53.353787  6428 solver.cpp:228] Iteration 9500, loss = 0.00429011
I0619 22:48:53.353787  6428 solver.cpp:244]     Train net output #0: loss = 0.00429007 (* 1 = 0.00429007 loss)
I0619 22:48:53.353787  6428 sgd_solver.cpp:106] Iteration 9500, lr = 0.00606002
I0619 22:48:53.757670  6428 solver.cpp:228] Iteration 9600, loss = 0.00273628
I0619 22:48:53.758157  6428 solver.cpp:244]     Train net output #0: loss = 0.00273624 (* 1 = 0.00273624 loss)
I0619 22:48:53.758863  6428 sgd_solver.cpp:106] Iteration 9600, lr = 0.00603682
I0619 22:48:54.157690  6428 solver.cpp:228] Iteration 9700, loss = 0.00342221
I0619 22:48:54.158474  6428 solver.cpp:244]     Train net output #0: loss = 0.00342217 (* 1 = 0.00342217 loss)
I0619 22:48:54.159108  6428 sgd_solver.cpp:106] Iteration 9700, lr = 0.00601382
I0619 22:48:54.559365  6428 solver.cpp:228] Iteration 9800, loss = 0.0139829
I0619 22:48:54.559365  6428 solver.cpp:244]     Train net output #0: loss = 0.0139829 (* 1 = 0.0139829 loss)
I0619 22:48:54.559867  6428 sgd_solver.cpp:106] Iteration 9800, lr = 0.00599102
I0619 22:48:54.960430  6428 solver.cpp:228] Iteration 9900, loss = 0.00561192
I0619 22:48:54.960681  6428 solver.cpp:244]     Train net output #0: loss = 0.00561188 (* 1 = 0.00561188 loss)
I0619 22:48:54.961184  6428 sgd_solver.cpp:106] Iteration 9900, lr = 0.00596843
I0619 22:48:55.361533  6428 solver.cpp:454] Snapshotting to binary proto file examples/mnist/lenet_iter_10000.caffemodel
I0619 22:48:57.518798  6428 sgd_solver.cpp:273] Snapshotting solver state to binary proto file examples/mnist/lenet_iter_10000.solverstate
I0619 22:48:57.525818  6428 solver.cpp:317] Iteration 10000, loss = 0.00311166
I0619 22:48:57.525818  6428 solver.cpp:337] Iteration 10000, Testing net (#0)
I0619 22:48:57.729859  6428 solver.cpp:404]     Test net output #0: accuracy = 0.9905
I0619 22:48:57.729859  6428 solver.cpp:404]     Test net output #1: loss = 0.0292506 (* 1 = 0.0292506 loss)
I0619 22:48:57.730361  6428 solver.cpp:322] Optimization Done.