前回は評価データをExcelで可視化しました。今回は.NETから使ってみます。
注意
CNTKのソースコード自体、現在進行形で進化しています。入手できるバイナリも現時点 (2016/03/18) でも動作しません。
実行は最新ソースを取得してビルドする必要があります。
また、設定ファイルやソースコードもトライアンドエラーで試した結果です。
準備
対象データは、MNISTとします。
ネットワークモデルは、Examples\Image\MNIST にあります。
ただし、データそのものは、含まれていません。
THE MNIST DATABASE から入手できるのですが、ここから入手しても、CNTKが読み込める形式にはなっていません。
Examples\Image\MNIST\AdditionalFiles に、データの入手、変換を行うPython のスクリプトが入っているのですが、Python環境がないと使えません。
ですので、後述のサンプルプログラムにデータを含めておきました。
data\mnist.zip になります。これを解凍してできる、Train-28x28.txt、Test-28x28.txt を Examples\Image\MNIST\Data にコピーします。
次に設定ファイルを変更します。
Examples\Image\MNIST\Config\01_OneHidden.cntk を開いて、
1 | deviceId = 0 |
を
1 | deviceId = -1 |
に変更します。
1 | # stderr = "$OutputDir$/01_OneHidden_out" |
を
1 | stderr = "$OutputDir$/01_OneHidden_out" |
に変更して学習途中のログを生成することもおすすめしておきます。
以上で準備が完了です。
ビルド
最新ソースを取得してビルドします。
個人的には、GPUを使わない方が良いと思います。
ただし、3/18の時点では、ディープラーニング CNTK 雑談1 動かない api-ms-win-core-path-l1-1-0.dll がない で報告したバグが直っていないので、Windows7で動かすなら、記事を参考にソースを修正してからビルドしてください。
学習
ビルド完了後、出来上がるパスをメモします。CNTK.slnがあるディレクトリから見て、x64\Release_CpuOnly または x64\Release_CpuOnly になると思います。
コマンドプロンプトを開いて、CNTK.slnがあるディレクトリにカレントディレクトリを移動します。
そして、次のコマンドを実行します。
1 | set PATH="%CD%\x64\Release_CpuOnly";%PATH% |
これでしばらくすると、Examples\Image\MNIST\Output\Models に学習済みのモデルファイルが出来上がっているはずです。
ログは、Examples\Image\MNIST\Output\01_OneHidden_out_MNISTtrain_MNISTtest.log になります。
さらっとながめてみますと、
1 | Allocating matrices for forward and/or backward propagation. |
とあり、エラー率2.24%と出ています。まずまずです。
.NETからテスト
テスト自体は、既にログを見るとおりわかっているのですが、これを.NETから可視化します。
実は、.NETのラッパーライブラリ自体は既にサンプル付きでCNTKに含まれています。
https://github.com/Microsoft/CNTK/tree/master/Source/Extensibility がそれです。
ソースである、Program.csを見ると非常に簡単であることがわかります。
1 | using (var model = new IEvaluateModelManagedF()) |
です。
Init関数には、設定ファイルのパスを、CreateNetworkには、コマンドプロンプトで渡す記述を渡すだけです。
ただし、わかりにくいのが、inputs と outputs です。
inputsは、System.Collections.Generic.Dictionary<string, System.Collections.Generic.List
値の中身は0-255の値がランダムに入っています。
MNISTは28_28なのでそういう条件なのです。
*.cntkにも784という数字が書いてありましたが、まさしくこれです。
outputs は、System.Collections.Generic.List
今回は長さ10で、添え字0-9が、MNISTで認識する0-9の数値にそのまま対応しています。
また、各要素の値は、入力データが、添え字に対応する数字のどれに対応するか、という確率を返します。
では、**”features”** と “ol.z” は何を意味するのでしょうか? これは、入力データと出力データを識別するキーになります。
ディープラーニングでは、各レイヤー毎に複数の入出力を持つことが可能です。その入出力を識別するためのキーになります。
Caffe でいう、Bottom (入力)、Top (出力)になります。
では、この定義はどこにあるのか、というと Examples\Image\MNIST\Config\01_OneHidden.ndl を見るとわかります。
1 | FeatureNodes = (features) |
という記述がまさにそれです。
ただし、ol だけは、**”.z”** を付与しないと、実行時にエラーを投げてしまいますので、そうしています。
さて、実行するとわかりますが、戻ってくる値には、負数が含まれており、全部の数値を合計しても確率を表すと思われる、1または100になりません。
これは、後述のサンプルソースで含まれるSoftmaxメソッドで確率に変換すること目的を達成できます。
ディープラーニングでは、出力層で得られた結果をSoftmaxで確率に変換することで識別を行います。
説明はSoftmax_function でわかりますが、簡単にソースで示すと、
1 | private IList<double> Softmax(IList<float> outputs) |
になります。簡単ですね。
テストする
が、先のサンプルは、入力データがランダムな値で全くもって意味がありません。
ですので、MNISTの画像を使って実際にテストしてみたいと思います。
入力画像は28*28の8bit画像です。
これをGUIで実行するのが、
https://github.com/takuya-takeuchi/Demo/tree/master/MachineLearning/CNTK/CNTK6
になります。
ビルドする際は、CNTK6\assemblies\CNTK というフォルダを作って、そこに EvalWrapper.dll をコピーしてください。
また、実行する際は、CNTKで出力される全てのバイナリを実行フォルダにコピーしてください。
実行すると、こんな感じです。
下のリストビューに確率がでており、この画像だと6である可能性が一番高いことを示唆しています。
入力画像は8、24、32bitに対応しており、それぞれバイナリに変換します。
ですので、MNIST以外にも使えます。CIFAR-100 でも利用できます。
(CIFAR-100で最初はテストしていましたが、結果がいまいちなので、MNISTにしまいた。)
Conclusion
ついに.NET から利用できるようになりました。
これで利用までの敷居がぐっと下がったような気がします。
アプリへの組み込みも他のディープラーニングのフレームワークに比べて楽になります。
Source Code
https://github.com/takuya-takeuchi/Demo/tree/master/MachineLearning/CNTK/CNTK6/source/CNTK6