読者です 読者をやめる 読者になる 読者になる

かれ4

かれこれ4個目のブログ

The Microsoft Cognitive Toolkitで、Machine Learning 界のHello World. MNISTを試す

CNTK Microsoft HelloWorld MNIST BrainScript graphviz docker

準備編

環境の準備をして 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で見てみると

f:id:tottokug:20161211201231p:plain

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

f:id:tottokug:20161211212033j:plain すごくシンプルな有向非巡回グラフが出てきました。 なんか可視化されると嬉しい。

さいごに

dockerを使った事によって、手軽に始めることができました。

MNISTを他の構成でもやってみたかったのですが、GPUがないためか全然終わらず、、、 やはりMacbook Airには荷が重かったという事で、諦めました。

BrainScriptについてはplotまでが定義できたりと、結構便利そうだなという印象です。

f:id:tottokug:20161211213044p:plain

Visual Studio CodeのExtensionはまだないようなので、今度時間あったら作ります。

というわけで、 CNTKの準備 から、ざっくり概念的な説明、使ってみるというところまでが終わりました。

次回は、実際にモデルを利用する事か、PythonからCNTKを使う事かのどちらかをしてみたいと思います。