準備編
環境の準備をして blog.tottokug.com
CNTKの使い方をざっくりと理解して blog.tottokug.com
確認編
cntkにはコマンドラインで使う方法と、python から使う方法などがありますが、 まずはコマンドラインで使う方法を試してみます。
cntkのコマンドが使える状況に
$ docker run -it --rm microsoft/cntk:1.7.2-cpu-only root@9f0cb764ac5a:/cntk# cntk ------------------------------------------------------------------- Build info: Built time: Oct 1 2016 21:16:06 Last modified date: Sat Oct 1 21:14:58 2016 Build type: release Build target: CPU-only With 1bit-SGD: no Math lib: mkl Build Branch: HEAD Build SHA1: d1ad5fcc9b71c9b6122623a2a0c3d126a64cbe94 Built by philly on 9b019bb2e014 Build Path: /home/philly/jenkins/workspace/CNTK-Build-Linux ------------------------------------------------------------------- No command-line argument given. ------------------------------------------------------------------- Usage: cntk configFile=yourConfigFile For detailed information please consult the CNTK book "An Introduction to Computational Networks and the Computational Network Toolkit" -------------------------------------------------------------------
無事にcontainer上でcntkが使えています.
実践編
ここからはすべてコンテナ内での操作になります。
データのダウンロード
まずはMNIST用のデータを用意します。 データを用意するためのスクリプトがgithubに上がっているので、それをダウンロードしてきます。
# cd /cntk/Examples/Image/MNIST/Data # wget https://raw.githubusercontent.com/Microsoft/CNTK/master/Examples/Image/DataSets/MNIST/install_mnist.py # wget https://raw.githubusercontent.com/Microsoft/CNTK/master/Examples/Image/DataSets/MNIST/mnist_utils.py # python install_mnist.py 〜略〜 # ll total 127392 drwxr-xr-x. 1 1000 1000 4096 Dec 11 05:40 ./ drwxr-xr-x. 1 1000 1000 4096 Dec 8 23:21 ../ -rw-r--r--. 1 root root 18649443 Dec 11 05:40 Test-28x28_cntk_text.txt -rw-r--r--. 1 root root 111735994 Dec 11 05:40 Train-28x28_cntk_text.txt -rw-r--r--. 1 root root 637 Dec 11 05:39 install_mnist.py -rw-r--r--. 2 1000 1000 20 Oct 1 23:28 labelsmap.txt -rw-r--r--. 1 root root 2463 Dec 11 05:39 mnist_utils.py -rw-r--r--. 1 root root 2982 Dec 11 05:39 mnist_utils.pyc
無事にデータのダウンロードが完了しました。
データのフォーマット
$ head -n 1 Train-28x28_cntk_text.txt |labels 0 0 0 0 0 1 0 0 0 0 |features 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 18 18 18 126 136 175 26 166 255 247 127 0 0 0 0 0 0 0 0 0 0 0 0 30 36 94 154 170 253 253 253 253 253 225 172 253 242 195 64 0 0 0 0 0 0 0 0 0 0 0 49 238 253 253 253 253 253 253 253 253 251 93 82 82 56 39 0 0 0 0 0 0 0 0 0 0 0 0 18 219 253 253 253 253 253 198 182 247 241 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 156 107 253 253 205 11 0 43 154 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 1 154 253 90 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 139 253 190 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 190 253 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 241 225 160 108 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 81 240 253 253 119 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 45 186 253 253 150 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 93 252 253 187 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 249 253 249 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 46 130 183 253 253 207 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 148 229 253 253 253 250 182 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 114 221 253 253 253 253 201 78 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 66 213 253 253 253 253 198 81 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 171 219 253 253 253 253 195 80 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 172 226 253 253 253 253 244 133 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 136 253 253 253 212 135 132 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
これが一行の内容で、labelsには10bitで0-1の数字が記録されている。(なんかもったいない)
下記の場合は左から6番目に1が付いているので(0,1,2,3,4,5)で5を表している。
|labels 0 0 0 0 0 1 0 0 0 0 |
featuresには28x28個の0-255の値が記載されたデータが入っている。 1行に並んで居ると見づらいので、数字28個毎に改行を入れてみる。
$ head -n 1 Train-28x28_cntk_text.txt |perl -pe "s/(.*?features )((\d+ ){28})/\1\n\2\n/g" |labels 0 0 0 0 0 1 0 0 0 0 |features 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 18 18 18 126 136 175 26 166 255 247 127 0 0 0 0 0 0 0 0 0 0 0 0 30 36 94 154 170 253 253 253 253 253 225 172 253 242 195 64 0 0 0 0 0 0 0 0 0 0 0 49 238 253 253 253 253 253 253 253 253 251 93 82 82 56 39 0 0 0 0 0 0 0 0 0 0 0 0 18 219 253 253 253 253 253 198 182 247 241 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 156 107 253 253 205 11 0 43 154 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 1 154 253 90 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 139 253 190 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 190 253 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 241 225 160 108 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 81 240 253 253 119 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 45 186 253 253 150 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 93 252 253 187 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 249 253 249 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 46 130 183 253 253 207 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 148 229 253 253 253 250 182 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 114 221 253 253 253 253 201 78 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 66 213 253 253 253 253 198 81 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 171 219 253 253 253 253 195 80 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 172 226 253 253 253 253 244 133 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 136 253 253 253 212 135 132 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
改行を入れるとなんとなく5っぽいなというのも見える。
学習と検証
データ確認は済んだところで実際に学習と検証までをやってみます。
今回使用するのはContainerに最初から用意されているMNIST用の構成ファイル この構成ファイルはBrainScriptと呼ばれているようです。 '/cntk/Examples/Image/MNIST/Config/01_OneHidden.cntk'を利用します。 おそらくgithubにあるこれとほぼ同じものになると思います。
# cd /cntk/Examples/Image/MNIST/Config # date ; cntk configFile=01_OneHidden.cntk ; date Sun Dec 11 10:29:39 UTC 2016 CNTK 1.7.2 (HEAD d1ad5f, Oct 1 2016 21:16:06) on localhost at 2016/12/11 10:29:39 cntk configFile=01_OneHidden.cntk Redirecting stderr to file ../Output/01_OneHidden_bs_out Sun Dec 11 10:31:31 UTC 2016
こちらMacbook Air上のParallelsで動かしているCoreOS上のDocker(とりあえず、そこまでいいスペックではない環境)で実行して だいたい 2分くらいで完了しました。
実行中にstderrの内容は../Output/01_OneHidden_bs_outに保存してあるからと言われているので、軽く見てみます。
# cat ../Output/01_OneHidden_bs_out 〜略〜 Minibatch[1-10]: errs = 1.880% * 10000; ce = 0.06162033 * 10000 Final Results: Minibatch[1-10]: errs = 1.880% * 10000; ce = 0.06162033 * 10000; perplexity = 1.06355847
なんだかしっかりとTestまで終わってますよ的な事が出ています。 てか、上記の検証結果のようにこれ標準出力に出してくれても良いんじゃないか? と思うような内容もstderrに出ていたので要注意です。
そして、肝心の学習したモデルはというと、 BrainScriptに書いてある
modelPath = "$outputDir$/Models/01_OneHidden"
に吐き出されているはずなので、見てみます。
# cd /cntk/Examples/Image/MNIST/Output/Models # ls -la 01_OneHidden* -rw-r--r--. 1 root root 638877 Dec 11 10:31 01_OneHidden -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.0 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.1 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.10 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.11 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.12 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.13 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.14 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.15 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.16 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.17 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.18 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.19 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.2 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.20 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.21 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.22 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.23 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.24 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.25 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.26 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.27 -rw-r--r--. 1 root root 638877 Dec 11 10:30 01_OneHidden.28 -rw-r--r--. 1 root root 638877 Dec 11 10:31 01_OneHidden.29 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.3 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.4 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.5 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.6 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.7 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.8 -rw-r--r--. 1 root root 638877 Dec 11 10:29 01_OneHidden.9 -rw-r--r--. 1 root root 636600 Dec 11 10:31 01_OneHidden.ckp
きちんとできていそうです。よかった。
ちなみにExampleについている 02_Convolution.cntkとか03_ConvBatchNorm.cntkについても どうようにできますが、cpu-onlyのイメージでは全然実行が終わりません。
参考までにdocker statsで見てみると
CPUやばし、これはGPU積んでるマシンでやりましょう。
ここまでかMacbook Air
plotしてみる
Plot command · Microsoft/CNTK Wiki · GitHub ここにネットワークを描画出来るようなことが書いてあります。
This command loads a given computation network and describes the network topology (usually a DAG) using the DOT (http://www.graphviz.org/doc/info/lang.html) language. It can also optionally call a third-part tool (http://www.graphviz.org/Documentation/dotguide.pdf) to render the network topology. Note that many DOT rendering tools are optimized for DAG, and the rendered graph becomes quite messy if the network structure is non-DAG. The non-DAG structure is usually caused by the use of delay node. In this case, this command will treat all the delay nodes as leaf nodes.
描画にはgraphvizを使うようなのですが、 microsoft/cntk:1.7.2-cpu-only はUbuntu 14.04ベースで、 CNTKを動作させる環境は一通り入っては居るものの、graphbizは最初からインストールされていません。 なので、インストールします。
# apt-get update # apt-get install graphviz
そして、さっきの 01_OneHidden.cntkをコピーして編集します。
# cp 01_OneHidden{,_plot}.cntk # vi 01_OneHidden_plot.cntk
commandの最後に:で区切ってtopoplotを追加して、 さらにtopoplotのブロックを追加します。
# command = trainNetwork:testNetwork command = trainNetwork:testNetwork:topoplot # plot CONFIG topoplot = [ action = "plot" modelPath = "$modelPath$" # outputdotFile specifies the dot file to output # if the user does not specify this, it will be ${modelPath}.dot outputdotFile = "$outputDir$/Visualize/01_OneHidden.dot" # outputFile specifies the rendered image outputFile="$outputDir$/Visualize/01_OneHidden.jpg" # if RenderCmd is specified, CNTK will call the plot command after replacing # <IN> with ${outputdotFile} and <OUT> with ${outputfile} renderCmd="/usr/bin/dot -Tjpg <IN> -o<OUT>" ]
これで下記コマンドを実行すれば、/cntk/Examples/Image/MNIST/Output/Visualize には画像ファイルとdotファイルができているはずです。
# cntk configFile=01_OneHidden-plot.cntk # ll /cntk/Examples/Image/MNIST/Output/Visualize/ drwxr-xr-x. 2 root root 4096 Dec 11 12:17 ./ drwxr-xr-x. 4 root root 4096 Dec 11 12:17 ../ -rw-r--r--. 1 root root 2182 Dec 11 12:17 01_OneHidden.dot -rw-r--r--. 1 root root 130944 Dec 11 12:17 01_OneHidden.jpg
無事にできていました。
せっかくなので、手元に持ってきて表示してみます。
$ docker cp {containerID}:/cntk/Examples/Image/MNIST/Output/Visualize/01_OneHidden.jpg ./01_OneHidden.jpg $ open 01_OneHidden.jpg
すごくシンプルな有向非巡回グラフが出てきました。 なんか可視化されると嬉しい。
さいごに
dockerを使った事によって、手軽に始めることができました。
MNISTを他の構成でもやってみたかったのですが、GPUがないためか全然終わらず、、、 やはりMacbook Airには荷が重かったという事で、諦めました。
BrainScriptについてはplotまでが定義できたりと、結構便利そうだなという印象です。
Visual Studio CodeのExtensionはまだないようなので、今度時間あったら作ります。
というわけで、 CNTKの準備 から、ざっくり概念的な説明、使ってみるというところまでが終わりました。
次回は、実際にモデルを利用する事か、PythonからCNTKを使う事かのどちらかをしてみたいと思います。