空飛ぶ気まぐれ雑記帳

主に趣味とかプログラミングについて扱います。

C++でDNNが使えないなんてあるわけないよ in Windows

一ヶ月くらいクソ忙しかったせいで久々の更新。
書くネタは山ほどあるんだけど、またその内、連続で書きます。

はじめに

Windows環境のC++(これ重要)でDNN(Deep Nueral Network)を使おうぜって話。
DNNといえば最近流行りのものなんだけど、如何せんWindows環境。特にC++となるとグッと道が狭まる傾向にある。
正直嫌がらせでも受けてるんじゃないんですかねって言うくらいに。

実際、有名な所でGoogleのTensol Flowがあるけれども、あれもMacLinuxの64bitしか対応していない。
それで色々とC++で使えるDNNののライブラリを調べてみたわけです。
個人的な要望として、GPGPUによる高速化が成されているものがベストかなと思っています。

Tensor Flow

Googleが出した商用フリーの機械学習ライブラリで、なんかすごいらしい。
曰く、状態遷移図で表現できるあらゆる問題を解けるとか凄い話を聞いたことがある。
私は現在Windows以外のまともな環境が無いので使ったことはないけれども、学習の経過をビジュアライズまで自動でやってくれて、その結果をブラウザで確認できるのがすごく魅力的。
ただし、前述の通りWindowsでは使えないのです。

OpenCV

おそらく最も有名無い画像処理/コンピュータビジョンのライブラリ。
なのだけれども、いくら探してもOpenCVだけでDNNを使うという話が出てこない。
より正確に言うとC++OpenCVだけを使ってDNNを使うという話が出てこない。
実際に「OpenCV DeepNeuralNetwork」で検索しても上から10個が全てCaffeのモデルを読み込んでみた、という内容のものばかりだし、OpenCVのサンプル一覧を見てもそれらしいものが見あたらなかった。

DLIB

以前記事をかいたけれども、機械学習ライブラリでその中にDNNも含まれており、もちろんGPGPUを用いた高速化も可能。
なのだけれども、残念なことにWindows環境だとリンクエラーがでる。
FAQ曰く、Visual Studioの場合C++11に完全に対応しているバージョンがないので未対応とのこと。
さらに、こいつ。厄介なことに全てのパラメータがテンプレートで解決されるため、動的にパラメータを変えてどうのこうのっていうのはやり難い。
まあ、最近はAutoEncoderかなにかで事前学習して層数とかを決めるらしいからそれもあまり問題にならないのかもしれないけれども。

Tiny DNN(https://github.com/tiny-dnn/tiny-dnn)

非常にスマートなライブラリで、Windowsに対応している素敵ちゃん。
必要なライブラリとしてOpenCVを要求していることは入力インターフェースにOpenCVを使っていると思われる。
特徴としては、DLIBと違ってパラメータを動的に決定することが可能。
ただし、CPUでの学習しか対応していないので、その辺りはネックに成るかもしれない。

えっ、無くね?って話

Tiny DNNが一番良いのだけれども、GPGPUによる高速化がないと学習が終わる気しない。
Tiny DNNのトップページ曰く、

98.8% accuracy on MNIST in 13 minutes training (@Core i7-3520M)

とのことなので、6000サンプル10クラスよりも多いクラスに分けたり、サンプル数を増やしたりとしていると爆発的に計算時間が掛かりそう、というか掛かるのでやっぱりGPGPUが良い。

DLIBさんのDNNってなぜに動かないのん?

FAQに書かれている内容は以下の通りだが、どうにも納得できない。

The deep learning toolkit in dlib requires a C++11 compiler. Unfortunately, as of July 2016, no versions of Visual Studio fully support C++11, so not all the deep learning code will compile. However, all the other modules in dlib can be used in Visual Studio without any trouble.

確かに、Visual Studio 2015は結構C++11の中で対応していない機能がある。
ただ、それもUpdate 2でかなり解消されている。

それで、実際にソースコードを読み漁ってみてもどこにもそれらしいコードは見られなかった。
というわけで無理やりコンパイルしてしまえという結論に至りました。

DLIB with DNN in Windows

DLIBをDNNが使える状態でVisual Studioにてコンパイルするためにはcmakeをするときに以下のオプションを足せばOKです。

cmake -DCOMPILER_CAN_DO_CPP_11 <dlibのルートディレクトリ>

これで後は普通にコンパイルするだけです。
実際にライブラリをリンクしてコンパイルしても問題なく動作することを確認しています。

ただし、未だnvccでコンパイルが通るかどうか確認していません。
というのもCUDA8.0 RC ですらVisual Studio 2015 Update 1までしか対応していなくて、現在、私が持っている環境はUpdate2とUpdate3なので、両方共CUDAをONにしてdlibのコンパイルを出来ていません。
なので、上記の話は全てCPUで使う場合にのみ有効です。

CUDAについては、おいおい動作確認をしていきます。
それとサンプルコードも実はすでに書いたのですが、それはまた後日別記事であげますので悪しからず。

追記

今朝方、上記の方法にてDLIBをVisual Studio 2015 Update2でコンパイルしてみるとコンパイルに失敗したので、おそらくCUDAを使うことは難しそうです。

追記2

私がこの記事を上げてから、ほぼ同時か、翌日くらいにgithubにissueが上がっていたので追記。
どうやらdlib::repeatを使ってDNNのノードを定義すると、テンプレートの展開で無限ループにハマるらしくVS2015 Update3ではまだDNNを使えないようにしているらしい。

追記3

実際にDLIBを使ってDNNを使ってみたサンプル&解説記事を書きました。
elda27.hatenablog.com