CUDA Toolkit | NVIDIA Developer
ようやく、CUDA 8が正式リリースされました。
と、わざわざ書くと、私がcaffeとかですごくCUDAを使っていて毎日監視しているように見えますが、単にNVIDIAからメールが届いただけでした。
うちがXubuntu16.04環境なので、Ubunt16.04で使えるものがアカウント無しでダウンロードできるようになったというのがありがたいです。
最近やっていないから、また忘れてしまった。。
CUDA Toolkit | NVIDIA Developer
ようやく、CUDA 8が正式リリースされました。
と、わざわざ書くと、私がcaffeとかですごくCUDAを使っていて毎日監視しているように見えますが、単にNVIDIAからメールが届いただけでした。
うちがXubuntu16.04環境なので、Ubunt16.04で使えるものがアカウント無しでダウンロードできるようになったというのがありがたいです。
最近やっていないから、また忘れてしまった。。
久々に、Ubuntuを仮想環境ではなくインストールした。
14.04のDVDしかなかったので、インストールして、アップグレードしてもらった。
ときどきなぜか固まることがあるのだが、まあよかろう。
GeForce GT710という古いグラフィックスボードだが、これでもCPUで計算するよりも速い(はず)。
CaffeとCUDA8.0RCなどをインストールした。
もう使い方を覚えていないから、ネットで見ながら動作確認を行った。
CaffeでDeep Learning (2) - 桜朔
[deep learning] caffeとCIFAR-10を使って画像判別テスト(詳細) - 脳汁portal
動いたのだが、どちらの人もclassify.pyを使っていない。
io.pyを修正しても、なんかちゃんとした結果を出していないような気がするのだが、そもそも何なのかがよくわかっていないので、推測ができん。
まず思ったのは、classify.pyで省略した引数が影響しているのではないか、ということだ。
"--mean_file"があやしい。
デフォルトでは、'caffe/imagenet/ilsvrc_2012_mean.npy'を使っているのだが、これはILSVRC2012用だろう。
cifar10は、CIFAR-10のmean_fileを指定すべきではなかろうか。
ただ、python/caffeの下にはCIFAR-10用と思われるファイルがない。
このnpyファイルは、numpy array形式のファイルらしく、"data set image mean of [Channels x Height x Width]"と説明があるから、平均画像なのだろう。
CIFAR-10サンプルの平均画像は、mean.binaryprotoというファイルになるようだ。
これを指定すればよいかと思ったが、エラーになった。
形式が違うようだ。
Convert binaryproto to npy | Rachel's Memo
Pythonのコードが載っているが、open/readはしているが、writeはしていないから、arrという変数がnpy形式ということになるのか。
最後に「np.save(ファイル名, arr)」とすると、arrの内容をファイル保存するようだ。
これをclassify.pyの--mean_fileに指定すると、ずいぶん進むようになったが、今度は次元数が違っているというような感じがする。
いや、ndimじゃなくてlen()だから、次元ではないか。
io.pyでは、2か3(2だったら1足している)を通すようなのだが、変換したデータは4になっている。
変換データのshapeは(1, 3, 32, 32)だから、これが4つあるからlen()が4なのか。
最初にmean.binaryprotoを作る場合は、コマンドbuild/tools/convert_imagesetを使っている。
lmdbとあるから、lmdbフォーマットがbinaryproto形式ということか。
(1, 3, 32, 32)のうち、最後の2つはデータのWidth x Heightだろうし、その手前はRGBの3 layerだろう。
classify.pyがほしいのは"[Channels x Height x Width]"ということだから、最初の"1"がいらないだけなのかな。
「arr = np.reshape(arr, (3, 32, 32))」とすると、(3, 32, 32)になった。
import caffe
import numpy as np
import sysparam = sys.argv
blob = caffe.proto.caffe_pb2.BlobProto()
data = open( param[1] , 'rb' ).read()
blob.ParseFromString(data)
arr = np.array( caffe.io.blobproto_to_array(blob) )
arr = np.reshape(arr, (3, 32, 32))
np.save(param[2], arr)
わざわざparamに移したり、arrに2回代入したりと格好は悪いが、ネットで調べながらだから許しておくれ。
これで(3, 32, 32)になったし、classify.pyの--mean_fileに指定してもエラーにならなかったが、show_result.pyで見てもパーセントが0だ。
何か違うのか。。。
ああ、--model_defと--pretrained_modelも指定しないといかんのか。
2番目のサイトのスクリプトをまねしよう。
$ python python/classify.py ./car.jpg ./result.npy --mean_file=cifar10.npy \
--model_def=examples/cifar10/cifar10_quick.prototxt \
--pretrained_model=examples/cifar10/cifar10_quick_iter_4000.caffemodel.h5$ python python/show_npy.py result.npy
#1 | dog | 42.7%
#2 | cat | 31.8%
#3 | airplane | 11.0%
数字は出たのだが、結果がおかしいな。。。
2番目のサイトにある、猫がアップになった画像だと、こうなった。
#1 | bird | 29.0%
#2 | airplane | 20.9%
#3 | cat | 13.8%
全然違うなぁ。
同じスクリプトをうちでも動かしたが、数値は異なるもののネコが一番高くなるところは同じだ。
====================================
possibility of each categoly
0(airplane): 0.184532
1(automobile): 0.000219549
2(bird): 0.0134824
3(cat): 0.539376
4(deer): 0.0715057
5(dog): 0.021061
6(frog): 0.0255798
7(horse): 6.09221e-07
8(ship): 0.136054
9(truck): 0.00818893
====================================
I guess this image is [cat]
数字が違うというのも気にはなるのだが、半年違いがあるからネットワークが少し変わったのかもしれない、と勝手に思うことにしよう。
載っているスクリプトもmean.binaryprotoをreshape()しているから、意味として同じようなことをやってるんだと思う。
なにが、何が違う。。。。
あー、images_dimだ。
classify.pyはデフォルトだと256,256なのだが、載っているスクリプトでは省略していて、caffe/classifier.pyのデフォルトは画像サイズ、つまり32,32になっていたのだ。
なんだー、じゃあ、そこも指定して動かしておしまい。。。と思ったら、Ubuntuが死んでしまった。。。
メモリテストも正常だったし、インストールも新規だったし、あとはnVIDIAのドライバか、AMDのドライバか?
リセットして動かしたが、まだ合わない。。。
ここまで指定して、ようやく結果が一致した。
$ python python/classify.py ./cat.jpg ./result.npy --mean_file=cifar10.npy \
--model_def=examples/cifar10/cifar10_quick.prototxt \
--pretrained_model=examples/cifar10/cifar10_quick_iter_4000.caffemodel.h5 \
--images_dim=32,32 --center_only --channel_swap=0,1,2$ python python/show_result.py data/cifar10/batches.meta.txt ./result.npy
#1 | cat | 53.9%
#2 | airplane | 18.5%
#3 | ship | 13.6%
こういう目にあうと、DeepLearningはともかく、Pythonには少し近づけたかもしれない。
WindowsがHostのVirtualBoxでCUDAが使えないなら、Host側にインストールしたらいいじゃないの、と思いついてやってみた。
結果としては、caffeやCUDAはインストールできるものの、nVIDIAのボードがあるというところを認識できないようで、make runtestでコケた。
その後で、WSLでCUDAというかGPUが使えるのか調べて、使えなさそうだという掲示板を見つけたのだった。
ちょっと今はどこかわからなくなってしまったのだけど、Big Challengeとか書いてあったから、けっこう大変なのだと思う。
ちなみに、インストールするところまでは、そんなに悩まなかった。
どうやらUbuntu14.04と同じ扱いのようだ。
CUDAは、runじゃなくでdebの方じゃないとインストールできんかった。
debも、Windows側のファイルシステムからコピーせんといかんかったのだが、それくらいだ。
それ以外で動かないところは、ubuntuの解決策で調べれば良かった。
以前、CNTKで参考にしたFPGA開発日記の方もTensorFlowをインストールされたようだ。
http://msyksphinz.hatenablog.com/entry/2016/04/13/020000
うーん、みんなTensorFlow、TensorFlowいっているので、がんばってcaffeしようとしているのだが、TensorFlowだとGoogleのCloud環境でもすぐに試せるところがよいのかな。
CNTKでがんばってみようとしたのだけど、使っている人が見当たらなくて、初心者には厳しいのだ。
ものがよいとか悪いとかじゃなくて、時代の流れとか雰囲気で決まったりすることもあるから、なかなか曖昧な世界だ。
全部入れ直したし、私も全部忘れているので、もう一度同じことをやってみようと思ったが、いやあ、説明文が悪いですな。
読み返しても、何をして良いかよくわからなかった。
この辺りを参考に動かそう。
OSX10.10でCaffeをインストール、リファレンスモデルで画像を分類 - Qiita
caffeのサンプルを動かす - スチールウールの活動記録
途中までやっていて気付いたのだが、これはexamples/imagenetは関係ないんだな。。
あれはトレーニングの仕方に関するexamplesなのだろう。
説明されている内容は、こうだ。
最後にpython classify.pyを実行してクラス分けをするのだが、ここにはサンプル画像しか引数に与えていない。
モデルファイルとトレーニング済みデータは必要なのだろうか?
いや、いるのだろうけど、dataにもmodelsにも他のフォルダがあるので、どうやって使い分けているのだろうか、と心配になるではないか。
pythonはよくわからないので雰囲気で見てみよう。
https://github.com/BVLC/caffe/blob/master/python/classify.py
あれ、data/が出てこないぞ?
確かに、classify.pyを実行するときにはdata/自体がなくても動作した。
data/を使うのは、show_result.pyだけだ。
これはcaffeが提供しているわけではないので、提供元を見てみよう。
変数categoriesにタブ区切りのテキストとして読込んでいるようだ。
show_result.pyで出力される内容の、この部分ですな。
#1 | n04552348 warplane, military plane | 84.1%
#2 | n04008634 projectile, missile | 5.8%
#3 | n02690373 airliner | 5.0%
classify.pyでは「n04552348に分類される確率が84.1%です」というところまでやってくれるから、それを名前解決する役割をしていると言うことだろう。
get_ilsvrc_aux.shはトレーニング済みデータを取ってくるのかと思っていたが、それはモデルファイルと一緒に提供されると思って良いのだろう。
まあ、ネットワークとトレーニングデータはセットじゃないと意味がないだろうしね。
今回使ったbvlc_reference_caffenetには、以下のファイルが入っている。
classify.pyに与えるのは、最初の2つだけだ。
deploy.prototxtは、ネットワークの構成のようだ。
最初にこういうのが書かれていた。
input_param { shape: { dim: 10 dim: 3 dim: 227 dim: 227 } }
10 x 3 x 227x227。
227x227は画像のサイズで、3はRGBだろう。
10は?
http://docs.chainer.org/en/stable/reference/caffe.html
ミニバッチのサイズなのかな。
自分でトレーニングデータを作る必要がなければ、このようにどこかからもらってくればよいので、GPUがなくてもそんなに困らないように思う。
でも、症例をたくさん入れて診てもらう、みたいなことをしたかったら、自分でトレーニングデータを作らにゃならんだろう。
データはあるけどネットワークの構成を考えるのはちょっと・・・という場合は、既にあるprototxtを使ってトレーニングさせることができますよ、というのがexamples/imagenetサンプルのやりたいことだと思う。
うん、前よりは多少理解が早くなったように思う。
深層学習に対する理解と言うよりは、caffeなどのフレームワークを使うときの考え方への理解なのだけど、まあいいのだ。
もう、燃え尽きてきました。。。
まずは対象となるnVIDIAのボードがないと話にならないので、古いPCから持ってきた。
NVIDIA GeForce GT710とのこと。
Windows10のデバイスマネージャでは、こう見えている。
![]()
https://www.virtualbox.org/manual/ch09.html#pcipassthrough
よくわからんが、VBoxManageコマンドを使ってアタッチさせるらしい。
サイトでは「02:00.0@01:05.0」となっていて、@の前に書いてある方がlspciで見えている。
00:02.0 VGA compatible controller: InnoTek Systemberatung GmbH VirtualBox Graphics Adapter
これがうちのguestで見えているグラフィックスボードなので、まねしてみた。
> vboxmanage modifyvm "xubuntu" --pciattach 00:02.0@01:00.0
エラーが出た。
3行くらい出るのだが、最初がこう。
VBoxManage.exe: error: Host PCI attachment only supported with ICH9 chipset
Hostって、今だとWindows10側ということだよな。
ICH9チップセットしか対応していないというのは、この設定項目のことか?

後から変更して動くのかなぁ。。。やってみるけどさ。
> vboxmanage modifyvm "xubuntu" --pciattach 00:02.0@01:00.0
>
変更したら、エラーは出なかった。
では、VMを起動して・・・・しなかった。
VERR_PDM_DEVICE_NOT_FOUNDとかで、セッションが開けないんだとか。
vboxmanageを実行する前に起動させていたのだが、これは成功したので、ICH9に変更したことが理由ではなく、vboxmanageで変更した方が影響していると言うことになる。
> vboxmanage modifyvm "xubuntu" --pcidetach 00:02.0
うん、起動した。
エラーダイアログに、Extension Packがどうのこうのと出てくるが、今は5.1.2のPackが入っているので大丈夫だと思う。
ん、VirtualBoxのPCIパススルーの章の1行目になにか書いてあるぞ?
When running on Linux hosts, with a recent enough kernel (at least version
2.6.31) experimental host PCI devices passthrough is available.
ぐはぁ。。。
最初の一歩から道を踏み外していたとは。。。
VirtualBox上にXubuntu 16.04が入っているのだが、CUDAやcuDNNとnVIDIAのグラフィックスボードがあればGPUが使えるのだろうか?
VirtualBoxでも動かせるかもしれないが非常に面倒だったりマザーボード次第だったり、という記事は見つかった。
VirtualBox上のUbuntu14.04でwaifu2xを動かしたかった - 六彩庵
lspciで見てみたけど、当然出てこない。
まあ、nVIDIAのボードが入っていないから、出るはずはないのだけどね。
「InnoTek Systemberatung GmbH VirtualBox Graphics Adapter」の立ち位置にnVIDIAのボードが出てくれば良いのかな。
https://www.virtualbox.org/manual/ch09.html#pcipassthrough
これで、6番目までやったことになるはず。
で、どうしたらよいのだ?
lspciで見たけど、何も変わらんぞ。
00:02.0 VGA compatible controller: InnoTek Systemberatung GmbH VirtualBox Graphics Adapter
最初の数字がPCIバスのアドレスらしいから、それがそれぞれの数字になったりするのかと思ったのだが。
その合間に、CUDAのRC8とcuDNNをダウンロードしていた。
あきらめて、nVIDIAにユーザ登録することにしたのだ。
承認までに数日かかると書いてあるサイトもあったのだけど、特にそういうこともなくログインしてダウンロードできた。
cuDNNはv5.1があったのだけど「available soon」だったので、v5のfor Linuxをダウンロード。
cudaはapt-getでインストールしたものが残っていたけど、せっかくなのでRC8をダウンロード。
準備だけはできたんだけどねぇ。
前回、エラーで終わったので、今日も緑茶の人のを参考にしながら進めよう。
http://yusuke-ujitoko.hatenablog.com/entry/2016/06/19/203443
VirtualBoxで動かすので、CUDAなんかはいらないと思うが、apt-get以外はやらずにcaffeのmakeを行ったので、「python pipによるインストール」を抜かしていた。
これを実行すると何かしらインストールされているようなので、caffeを入れ直すときにはやった方が良いのかもしれん。
が、make cleanしてやり直しても、同じエラーが。
https://github.com/BVLC/caffe/issues/3700
opencv 3を使うなら、Makefile.configの編集が必要だと?
確かに、そういう行がコメントアウトされていた。
opencvのサイトも、2.4の方が上にあったから、そっちの方がまだメジャーなのかな?
ともかく、opencv 3対応したら、makeが通った。
やれやれ。
しかし、cntkのサンプルを動かしたときにわかったのだけど、GPUを使うのと使わないのとでは時間が全然違うのよね。。。
なんかバグってるんじゃないの?と思うくらい時間が違う。
nVIDIAの5千円もしないグラフィックスボードを使っていたのだけどねぇ。
今は、オンボードのIntelなのだが、CUDAはnVIDIA専用よね、さすがに。
古いマシンからnVIDIAのボードだけ引っ張ってきて、caffe用に使えるのかしら?
久々にXubuntuを起動したら、16.04にアップデートできるということで更新した。
ついでなので、caffeも長いこと触っていないから、全部捨てて新しくしておこう。
前にやった手順をなぞったのだが、どうにもうまくいかないので、以下を参考にすることにした。
いやあ、ありがたい。
【Caffe】はじめてCaffeをmakeするまでOn Ubuntu16.04 - 緑茶思考ブログ
最後まで進んだのだが、opencvっぽいところがリンクエラーらしきものを出していた。
「最後まで」といいつつ、前にビルドしたパッケージは更新していなかったので、そのせいじゃなかろうか。
で、今opencv 3.1を取ってきてcmakeしているのだが、うまくいかない。
「file DOWNLOAD HASH mismatch」などといっているので、ダウンロードしたファイルとハッシュが合わないとか?
https://github.com/opencv/opencv/issues/5973
-DWITH_IPP=OFFと書いておくとチェックされないようなので、それで回避したらいいんじゃなかろうか、という案を試すことにした。
うん、エラーは出なくなった。
次にmakeすると、今度はmemcpyでエラーが。
これは、緑茶の人のところにも書いてあった。。。あ、これはcaffeの方だ。
https://github.com/BVLC/caffe/issues/4046
CUDA 8だといいよ、と書いてある。
しかし、メンバーじゃないとダウンロードできない。。そこまでする気はないのだ。
というわけで、その次にあったCMakefile.txtの先頭に「set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORCE_INLINES")」を追加する方法にした。
gccのバージョンが新しくなったことに関連しているのかな。
makeが終わり、make installした。
-jしていなかったせいかもしれないが、かなり時間がかかった。
しかし、これでもまだエラーが出ている。。
.build_release/lib/libcaffe.so: undefined reference to `cv::imread(cv::String const&, int)'
済まぬ、疲れたので次回じゃ。
ゴッホ風の絵に変換するところを理解したい、といいつつ、その部分よりも前の方でつまずいているのだが、仕事でやっているわけでもないので、まあいいとしよう。
当面の目標は、畳み込みニューラルネットのフィルタはどうなっているのか調べる、だ。
[1508.06576] A Neural Algorithm of Artistic Style
こちらが元の論文らしい。
なんとなく眺めてみたが、なんとなくフィルタについては書いていないようだ。
となると、やはり元のVGGというニューラルネットがフィルタの情報を持っているんじゃなかろうか。
[1409.1556] Very Deep Convolutional Networks for Large-Scale Image Recognition
VGGは、Visual Geometry Groupの略だと思われる。
オックスフォード大学のマークが入っている。
PDFだと「Department of Engineering Science」と書いてあるので、理工学部みたいなものかな?
1ページ目にリンクが書いてある。
Modelsの16-layer modelが、使っているネットワークのモデルのようだ。
Caffe用だ。
64チャネルは最初のレイヤーだから、これの一番上にあるやつだろう。
bottomがinputで、topがoutput。つまり、"data"は画像で、このレイヤーで計算した結果が"conv1_1"になる。
レイヤーは畳み込みの"CONVOLUTION"で、出力は64枚、kernel_sizeが3なのでフィルタは3x3、出力がフィルタ後も同じサイズになるようにpadを1にしている。
フィルタ後も同じサイズにしたい場合、Cで言えば(int)(フィルタサイズ / 2.0)にするのだ(フィルタサイズは普通奇数なので)。
そういうのはわかるけど、ここにもフィルタについては情報がない。
これだけで動くのだったら、フィルタの情報は"CONVOLUTION"が持っていることになるのか。
Theanoによる畳み込みニューラルネットワークの実装 (1) - 人工知能に関する断創録
こちらを読むと、フィルタは学習して得られると書かれている。
なるほど、どこに学習する要素があるのかと思ったけど、ここだったのか。
そりゃ、話が出てこないわけだ。
畳み込みニューラル・ネットワークの使い方、わかりますか? | Altera - SDJ JP
ここの「トレーニング」にフィルタ係数のことが書かれている。
アルテラ社だからFPGAの話だけかと思ったけど、こういう記事もあるのですな。
この記事はわかりやすいと思う。
畳み込みニューラルネットが、どういう技術で構成されているか書かれているし、どここが学習する要素なのか書いてあった。
最後の方の「何か納得がいかない」には共感を得るだろう。
やはりここでも、フィルタというかカーネルは学習から得られるものとなっている。
ゴッホ風の絵でも「予め物体認識で訓練したニューラルネットを使用し」とあるが、カーネルの学習も行わないものなのだろうか?
それとも、そこは入力画像によって学習するのが当たり前のものなのだろうか。
アルテラ社の記事では、カーネルの部分と、最後のパターン解釈でニューラルネットを使うように書かれているので、「カーネルの部分は毎回学習させるけど、最後のパターン解釈は訓練済みを使う」みたいなこともできるのかもしれん。
なんとなくだけど、全部セットになって「学習」という気がするので、一部だけってのはないんじゃなかろうか。
フィルタの部分だけで誤差関数を決めるのって、できないと思うのだ。
よくわからないところも残っているが、気になったらまた考えることにしよう。
ここまでが、アルゴリズムの説明の「モデル」のVGG 16-layerの話だ。
ようやくここから、CNNで得られた中間層の結果をどう使っていくのかという話になる。
先が長い・・・。
「なるようになる」という言葉がある。
だいたい、私はそういう気分だ。
そもそも、なるようにならない、という方が言葉としてはおかしいだろう。
ただ、それでも、自分が思うようになってほしい、ということはある。
それは傲慢ではあるが、人間らしくもある。
「機械学習」といいつつも、実は機械的じゃない部分があるのではないか?、何か見えざる何者かの手が入っているのではないのか?という不安は、あまり無視できないのかもしれない。
八百万の神、みたいな概念ではなく、一神教、あるいは数の限れた多神教の考え方からするとよろしくないかもしれないので、「シンクタンク」みたいな表現の方が良いのかもしれない。
表現方法は大事だと思う。
さて、深層かどうかは置くとして、機械学習には「学習」という期間が必要になる。
学習しながら間違いを探す、というのはできないと思う。
間違って、教えてもらう、というだけだ。
自分で間違っていることがわからないからだ。
そういうわけで、深層学習においても学習の過程は大切なのだ。
今回読んでいる記事では、ゴッホ風の絵に変換するという作業に対しては新しく学習を行っていない、とある。
読んでいった感じからすると、絵の特徴を残して、それ以外の要素をなるべくそぎ落とし、そぎ落とした部分に他の絵画の特徴を付け加えることによって「○○風」という特徴を出そうとしている、と私は読んだ。
記事としては「○○風」を出すところがメインのようだけど、私としてはその手前までの過程が気になっている、というのがこの3回までの趣旨だ。
元になっているのは、④のデータだと思う。
記事の真ん中くらいにある、ネコさんだ。
特徴だけ、というわりには、かなり最初のイメージが残りすぎている気がするが、おそらくそれは、目的が「ゴッホ風の絵にする」だからだと思う。
というよりも、3x3のフィルタをちょこちょこ掛けても、そんなに元の画像から変わらないんじゃないかと思うのだ。
元のPDFの目的まではわからないのだけど、この画風変更のお話からすると、元の画像の特徴がきれいさっぱりなくなっていると意味がないので、わざと残しているのではないかと思ったのだ。
だからこそ、フィルタってどういう風に作っているのだろう、が気になるのである。
どういう画像にも合うフィルタを作るアルゴリズムがあるのなら、そっちの方がすごいと思うのだ。
この辺りは、日本語記事の「おわりに」の辺りにも書かれている。
まだ、アプローチの段階なのだ。
楽しいところではないか。
私個人としては、こういうところに自分なりの解法を見つけて、他の人に「どういう式なのか意味はさっぱりわからないけど、確かにこれでうまくいってしまう」みたいなものを見つけたいと思っているのだ。
そういうささやかな夢を楽しみたいものである。。。
ときれいに締めたいのだが、フィルタの選び方についてはわからんままなので、、わかったら記事にしよう。
前回、図まで描いて説明したフィルタだけど、『深層学習』の6.3.3章に全部書いてありますな。。。
まあ、こういった内容は、画像処理の勉強をし始めると最初の方に出てくるのだ。
輪講とかで使ったテキストを持っていれば、今役に立ったかもしれないのに。。。
そう、なので、この辺りは深層学習というよりも、画像処理の話だろう、と思いながら読んでしまうのだ。
たぶん、時系列データに向いている再帰型ニューラルネットも、私が知らないだけで、何かそういう既存の処理が応用されているんじゃなかろうか。
この辺りが深層学習の奥が深いところですな。
さて、それでは畳み込み層の64チャネルって何よ?を続けていこう。
まず、入力画像のチャネル数は、画像に使われている原色の数(でいいのかな?)になる。
普通のカラー画像なら、RGBということで3。
モノクロなら、1。
いくらグレースケールで256段階で表現されていても、そこは1なのだ。
説明図では、チャネル数がKの入力に対して、M種類のフィルタを掛ける例になっている。
フィルタ1をチャネル1~Kの画像に掛け、次にフィルタ2をチャネル1~Kの画像に掛け・・・とやっていく。
そしてその結果は・・・チャネル数がMになるのだ!
だから、入力画像のチャネル数がいくつであっても、掛けるフィルタの数で出力のチャネル数が決まるのだ。
うん、推測は当たっていた。
では、どうやって64種類ものフィルタを決めているのだろうか?
しかも次の段では128、さらに256、512まであるのだ。
『深層学習』p.102に、conv1層のフィルタという画像が96例載っている。
カラーだったりモノクロだったり、丸っぽかったりしましまだったりと、数学的に数値を1~96まで当てはめたような感じはしない。
なにか、何かあるはず。。。
私は数学の人じゃないのだけど、結果的にうまくいった、というのはあまり数学っぽくないと思うのだ。
それが良いとか悪いとかじゃなくて、太陽を見るとまぶしい、とか、この花はきれいだ、とか、そういう感触がない気がするというだけのことなのだ。
うーん「根拠」といえばよいのかな?
ここでフィルタが64だの128だのあるけれども、なにか理由があって選ばれたものなのか、なんかランダムで作ったフィルタの中でよさそうなものを選りすぐったのかというのが気になるだけだ。
もう一度、最初に読んだ日本語の記事に戻ろう。
画風を変換するアルゴリズム | Preferred Research
最初だけ読んでいったが、全体的にどういうことをしているのかを見ておくと、何か思いつくかもしれない。
ここまでが前段になるか。
やっているのは、フィルタ処理だけだから、深層学習とかニューラルネットとか、そういうものは使っていないと思う。
使っているのか?
うーん、使っていそうなところが思いつかない。
フィルタを何段階かかましているだけのように思う。
内容は気にせず、この次の流れを見てみよう。
この読み方が当たっているなら、ここで使われているディープラーニングは「弱い特徴をそぎ落とす」というフィルタ処理だろう。
イメージとしては、音楽で低音を強めにしたり、声と同じ周波数帯を強めてボーカルだけ大きくしたりとか、そういう感じか。
知能的なミッドパスフィルタ、とでも言おうか。
なるほど、そういう考え方もあるのか。
ただ、どこら辺で学習した内容を使っているのかを読み取れていない。
もしかすると「どうやってフィルタを選んでいるんだ?」のところなのか??
ネコの画像から下がお話のメインなのだろうけど、その前が気になっているのだ。
うーん、もうちょっと調べるべきか?
深層学習でやるのは、クラスタリングがメインだと思っていた。
が、よく「○○風の絵をディープラーニングでつくる」みたいな記事もある。
最初に見かけたのは、ゴッホ風の絵にする、だったと思う。
どこら辺が深層学習と結びついているのだろう?
理解できるかどうかわからんが、努力してみよう。
画風を変換するアルゴリズム | Preferred Research
日本語で説明が書いてあるので、これを読むことにする。
が、いきなり詰まった。。。
入力画像は、RGBの256x256なので、3*256*256なのはわかる。
その次が、64*256*256。
3の倍数じゃないやん!
その下にある中間層を画像化したものも、チャネル3つ分がそれぞれあるので、64*256*256が3つ分ある、でよいのかな?
つまり、①以降は、入力画像の1チャネルに対しての結果という考え方だ。
・・・違うな、数が多いから3チャネル分だけ抽出したと書かれている。
ということは、RGBをグレースケール化して計算したのかしら。
カラーからグレースケールするときには一般的な変換式があるけど、そのパターンが64あるから64チャネルになる、という考え方だ。
http://arxiv.org/pdf/1409.1556.pdf
おそらく、こちらが「VGG 16-layerのCNNモデル」と書かれている原本だと思う。
3ページ目のDが、16weightで、conv3-64, -128, -256, -512, -512と表になっているから、表の上から4つが、①~④になっていると思われる。
「conv<receptive field size>-<number of channels>」と書いてあるので、たぶんそうだろう。
receptive field sizeが3。
『深層学習』p.80にもある、受容野だ。
3x3のフィルタと考えるとよいのかな?
もしそうだったら、普通に3x3のフィルタを掛けると、上下左右で1ピクセルずつ小さくなる。
3x3のフィルタだと、たとえば画像の左上だとしたら、(0, 0)-(2, 2)になる。
このフィルタで計算できるのは、(1, 1)の画素値だ。
今は知らないけど、私が画像処理の勉強をしていた頃はこういうフィルタの書き方をしていて、画素に対してこの掛け算を行い、その総和を中央の値にするのだ。
これだと、画素が9つあって、それぞれ1/9だから、移動平均のフィルタになる。もし画像が5x5だったら、3x3のフィルタで計算できるのは黄色の範囲だけになる。
画像が小さくなるのが嫌だったら、それっぽい画素値を外側に用意してやるしかない。
というわけで、フィルタした後も256x256を保っているから、そういう計算をしたのだろう。
じゃあ、64ってのは何だろうか?
PDFを検索したけど、"2.2 CONFIGURATIONS"に「最初のレイヤーは64から始めて~」しか書いてない。
主語は、width of conv. layers。
畳み込み層の大きさか。
『深層学習』のp.87に畳み込み層の章がある。
たしかにここにも、多チャネルの画像に対して複数個のフィルタを並行して演算するようなことが書かれている。
書いてあることと、ネットで説明してあることが一致しているのはだいたいわかるのだが、あっさりと「入力では3チャネルだけど中間層では16チャネルとか256チャネルとかになります」と書かれても、納得できないではないか!
もうちょっと調べて理解を進めよう。
こんな感じでやっていきます。
2回目があるのかどうか、我ながら心配です。。
前回、リリースされているCNTKにはバグがあるようだ、ということがわかった。
それが原因か、単に私の書き方が悪いのかわからないけど、うまく動いていない。
CNTKの最新版にすることで別のバグが出てくる可能性も高いが、ビルドできるようにしておいてもいいんじゃなかろうか。
こちらを参考に、やってみる。
既にインストールされているものもあるので、それはそのままでいけるのか試そう。
1.CNTK本体は、githubからcloneする。
2.Visual Studioは、2015がインストールされているので、それを使おう。
3.CUDAは、7.0がインストールされているので、それを使う。。。
環境変数は設定していないから、あとでやろう。
4.Boost, ACML, MS-MPI, OpenCV
MS-MPIだけは、7.0.12437.6がSDKと何も無しがインストールされていた。
ACMLは、Intel Fortranの「acml5.3.1-ifort64.exe」にした。似てる名前が多くて紛らわしい。。。
MKLというのもあるらしいが、alternativeだからどちらかあればよいのだろう。Boostは、unit test用ってあるから、なくてもいいんじゃないの?と思うが、きっとビルドエラーになるんだろうな。。
msvc-12.0がいると書いてあるのだが、Visual Studio2015は14.0のようだ。
あまり詳しくないのだが、NuGetでインストールできそうだから、それでもいいのかな?
https://www.nuget.org/packages/boost
ああ・・・何かプロジェクトを開いていないとインストールできないんだ。
よくわからんが、拡張機能でboostを検索したときに出てきた「Boost Unit Test Adapter」でもインストールしておこう。OpenCVは、OPTIONALと書いてあるから、省略だ。
wikiにはzlibのことも書いてあるが、それもOPTIONALだ。
さて、ではビルドしてみよう、とwikiを見るとCUDA7.5になっていた。。。
いつの間に。。。
NVidiaからインストールしようとしているのだが、ハードウェアに互換性がないとか、Visual Studio Integrationがサポートしてないとか。。。
選択肢は3つある。
2は、きつい。
それだったら、CUDA8.0にしたいなぁ、とも思ってしまう。
じゃあ1かというと、せっかく2013をアンインストールしたのに。。。と思ってしまったのだ。
インストールし直すだけとはいえ、心理的な壁が大きい。
というわけで、今回は3を選んだ。。。
ありがちなのが、今日2013をインストールして動かして、次にやろうとしたら2015対応になっていた、というパターンなので、それに賭けることにした。
(単なる敗北ともいう。)
今週は、CNTKのチュートリアルを動かしたり、MNISTサンプルを動かしたりした。
そして、見た目だけはSimple2dとほぼ同じ形のネットワークをNDLで作成し、ちゃんと動いていないことを確認しました。。。
はい、反省はもう「ちゃんと読んでからやろうよ」に尽きます。。。
CNTKファイルの書き方をサンプルだけ見てまねしているので、ニューラルネットどうこう以前にツールの使い方が正しくなっているのかどうかが不明なのだ。
CNTK/Configuration Files.md at master · Microsoft/CNTK
ここを、全部とは言わないまでも、まねしているパラメータくらいは意味がわかっていないと、失敗しているのはわかっても対応が当てずっぽうで意味がないのだ。
今日も見ずにやってたけれど、readerのところで次元が違うとエラーが出て、理由が結局わからないままなのだ。
だって、Simple.cntkと同じ書き方をしているのに!
でも、labelTypeにRegressionを指定すると、なぜかエラーが出なくなる。
理由がわからんが、説明を読めばわかるんじゃなかろうか。
あ、2016-02-08版のこれに関連するバグ?
required parameter missing: LR.cntk:Train:reader:labels:labelMappingFile · Issue #240 · Microsoft/CNTK
ここでエラーが出てるのに気付いたけど、あれはCNTKファイルの誤記じゃなくてバグだったのか。
ということは、それに関連してバグがあったとしてもおかしくない(1列目2列目がデータで、3列目がラベルなのだけど、なぜかラベルの次元がおかしいというエラーになる)。
そ、そんな馬鹿な・・・。
CNTKのビルドは環境を作るのがめんどくさそうだからやってないのだ。
ドキュメントを読む前に、そっちが先かなぁ。。。
チュートリアルだけじゃなくて、MNISTのサンプルも参考にしよう。
MNISTサンプルもNDLで書かれたネットワークを使っているのだ。

最初、GPUではなくCPUで計算させていたのだけど、あまりにも終わらずにやめてしまった。
GPUに戻すと、そこそこの時間で終わった。
こんなに違うのね・・・。
Windowsでtimeみたいなコマンドを使いたいけど、代用品がわからないので時間は測ってない。
図を見る限りでは、少し違うけれども、TimesとPlus、Sigmoidも入っている。
最後はErrorPredictionとCrossEntropyWithSoftmax。
01_OneHidden.ndlは短いが、これはマクロとしてMacros.ndlが使われているからだ。
しかしそうは言っても、DNNSigmoidLayer()とDNNLayer()だけで、マクロの中身も、Times()とPlus()、Sigmoid()があるだけだから、そんなに特殊には見えない。
だけど、これはちゃんと結果が出るのだ。
「Starting minibatch loop」というログのあとが、自分で作ったNDLだと処理が行われているような感じがしない。
何か足りないのだろう。。。
簡単に動くと考えたのが甘かったな。
そろそろ、ちゃんとやろう。
まずはシンプルに、隠れ層がないネットワークを作ってみる。
Simple.cntkで「layerSizes = 2:50*0:2」としたとぎのグラフは、こうだ。

ノードの、PlusとTimesはチュートリアルと同じ形だからよいとして、Timesの前にあるPerDimMeanVarNormalizationが最初の山場だ。
Times()やPlus()があるんだから、PerDimMeanVarNormalization()もあるだろう・・・あった。
が、引数は3つだ、というエラーが出てきた。
PerDimMeanVarNormalizationノードには、Mean、InvStdDev、featuresの矢印が突っ込まれている。
featuresはチュートリアルにもあるからよいとして、MeanとInvStdDevは計算がいる。
が、これもMean()とInvStdDev()があった。
PerDimMeanVarNormalization()の第1引数はfeaturesにしとかないとエラーが出た(メッセージが長かったので、あんまり読んでない)。
| mn = Mean(features) |

なるほど。
グラフのノードは2行表記になっているけど、1行目の括弧の外は変数名なんだな。
Mean()の結果をmeanという変数名に入れようとすると怒られたので、大文字小文字は見てないのかもしれない。
Simple.cntkだと「W0*H-1」みたいな名前もあったが、あれは変数名にできなかった。
だから、あれはSimpleNetworkBuilderだから出せるのかもしれない。
さて、これでPlusノードまではできた。
あとは、
のノードを作るだけだ。

これで、Minusのところ以外は同じになったかな。
では、Minus()もまねしてみよう。
| # operations LR = CrossEntropyWithSoftmax(labels, z) mm = Mean(labels) |

・・・予想と違う。
作ったノードが、全部グラフから浮いてしまった。
チュートリアルでは、この後ろに「FeatureNodes()」や「LablesNodes()」がある。
ノードの意味を指示しないといけないということか。
| ndlLR=[ features=Input(SDim, 1) # parameters to learn # operations LR = CrossEntropyWithSoftmax(labels, z) ml = Mean(labels) # root nodes |

ただ、形ができただけで、ログを見ると計算ができていない。
ネストしているような警告が出ているので、そこらへんだろうか・・・いや、元から出ているな。
「Starting minibatch loop」のところから出方がずいぶん違うので、そこから見ていくか。
前回、チュートリアルのロジスティック回帰を見ていたが、そのネットワークをSimple2dで試すのを忘れていた。
前はエラーのところしか見ていなかったけど、係数が予想通りx軸に平行となるのかは見ておきたいところだ。
y = -0.0482035205 - 0.600052118 * x1 - 10.5671721 * x2
予想と違いましたな。。。
いや、ちょっと待った。
変数が2つあるけど、これはなんだっけ?
チュートリアルによると、
だそうだ。
だからこの式は、
y = (0.600052118 / (-10.5671721)) * x + (0.0482035205 / (-10.5671721))
となる。
graph.tkでグラフにしてみると、この赤線になった。

青線はテストデータの元になったグラフだ。
x軸にかなり平行な直線と言ってよかろう。
さて、NDLに戻ろう。
その前に、LDimのことを解決しておく。
以前、LDim=2にしないと動かない、と書いたのだが、このチュートリアルはLDimが1のままで、ちゃんと動いているのだ。
見比べながら変更したところ、labelsに「labelType=regression」を書くとLDim=1でも動くことがわかった。
labelsは、くくりで言うとReader blockになる。
labelTypeは、こちら。
Categoryか、Regressionか、None。
チュートリアルはロジスティック回帰だから、Regressionだったのだろう。
Categoryは、labelsみたいにcategoryというブロックを自分で作って、そこに記載するような感じがする。
labelsのデータはfloating pointで、Categoryの場合は整数部分がラベルマッピングテーブルのインデックス値に変換される、とある。
labelTypeの説明が、
labelType – [{Category},Regression,None] the type of label
となっていたから、Categoryがデフォルト値で、マッピングファイルにラベルが2つ書かれているから、LDimが2じゃないとうまく行かなかった、ということか?
じゃあ、Regressionを指定した場合はマッピングファイルの指定をしなくてもうまく動作してほしいのだけど、EXCEPTIONが発生していた。
これについては、何か説明を付けることができるのだろうか?
こういうねー、ネットワークとかの前に気になることが出てくると、なかなか着手できないのだ。
勉強しようとしたら机の周りが散らかっているのが気になり出すのと同じかもしれない。
まだ続いている、自分でニューラルネットのネットワークを書く話。
チュートリアルを見始めたけど、ロジスティック回帰なるものが出てきて、わからないなりにやったところまでが前回だ。
パラメータが1つの問題が線形回帰とか単純回帰とか呼んで、パラメータが増えると多重線形回帰になる。
多重線形回帰の成果というか結果というかが2値の場合を、ロジスティック回帰と呼ぶ、という認識でいる。
結果がAかAじゃないか、で、Aなら1.0、Aじゃないなら0.0、あとはよりどっちに近いかという値になる。
チュートリアルは2変数なので、回帰モデルはこうなる。
y = W_0 + W_1 x_1 + W_2 x_2
2元1次方程式、というやつですな。
散布図を見ると、左下が0のグループ、右上が1のグループのようだ。
図形的な解法だと、各グループの重心を求め、重心間に直線を引き、それと直交する直線で重心間の距離が等しくなるような直線を求めることになるだろう。
そういった求め方をせず、点のデータからその直線になるようなWを求めるのがこのチュートリアルになるはず。
この節の一番下に破線が追加された散布図があるが、この破線がそれですな。
うーん。
このチュートリアルでは、散布図を見ると確かに直線で分離できそうだから2元1次方程式でよいだろう。
でも、Simple2dの場合はサイン波からデータを作っているので、直線で分離するのは無理だろう。
やったとしても、x軸に平行な原点を通る直線になって、波の付近は全然ダメなはずだ。
そういう意味では、Simple2dはロジスティック回帰に適さない課題と言うことになるのか。
でも、そんなのは結果論であって、モデルがどういう風になるかわからないからディープラーニングだの何だのを使って勝手にやってもらおうとしているんじゃないか。
そうなると、簡単な話で「CNTKでロジスティック回帰の計算はできるけれども、ロジスティック回帰はディープラーニングとは関係がない」ということか。
ネットワーク図だって、全然層になってないし。。。
今ひとつ自信はないが、そういうことにしておこう。
チュートリアルのソースが、ラベルのモデルマッピングがないとかエラーが出たので、Simple2dのを付け足したものを置いておく。
一番上にあるテキストファイルは結果で、これはチュートリアルサイトの結果とも一致しているから、間違ってないのだろう。
さあ、次こそは自分でネットワークを書いてみたいぞ。
よそのサイトを見ていたら、面白そうなことをしていた。
Enjoy RFID: RFIDでディープラーニング その1
中身はわからないけど、私もこういう、自分で集めたデータで何かしてみたいのですよ。
気になったので、ロジスティック回帰について書いてある本を買ってきた。
O'Reilly Japan - 統計クイックリファレンス 第2版
統計学の本って、いろいろあるのね。。。
本屋でかなり悩んだ。
私は博多駅横にある交通センター6階にある紀伊國屋でだいたい買うのだが、その本棚の2列分が統計学だった。
その1列は、SPSSとかRとかSASとか、何かそういう言語かツールを使って実現するための本っぽかった。
この本は、分厚い。
CR2032の大きさと比較してみると、このくらいだ(関係ないけど、2032とか2016の後ろの2桁は厚みなのね)。

最初から読まなくていい、と書いてあるが、読んでいってもなかなか面白い。
以前悩んでいた、条件付き確率のことなども書いてある。
あまり重苦しい文体ではなく、文章を読んでいても面白い。
ロジスティック回帰のところまではまだ読み進んでないが、線形回帰のところを読んでいる。
例では、身長と体重の関係が題材になっている。
身長が高い人は、だいたい体重も重たくなるよね、という仮定を元に、その傾向を1次式で表す。
体重=身長×係数+定数
もちろん、これが必ずしもそうはならないのはわかるけど、まあ、だいたい、そうじゃないの?くらいで進めるようだ。
で、この推測に基づいていくつかのデータを取って、データを満たしそうな式を作る。
最小二乗法とかそういうやつですな。
この式を「回帰方程式」と呼ぶ。
じゃあ「回帰」はなにかというと、たぶんだが、こういうやり方自体を指している。
これは線形式に当てはめるので「線形回帰」とか「単純回帰」とか呼ぶようだ。
入力の変数が2つ以上だと「多重線形回帰」などになるらしい。
変数が1つじゃなかったら線形にならないんじゃないの?という気もするのだが、よく読めばわかるのかもしれない。
そして、出力結果(従属変数などと呼ぶ)が2値の場合の多重線形回帰を効果的に扱う回帰技法が「ロジスティック回帰」のようだ。
CNTKのチュートリアルやSimple2dも、ラベルは0か1の2値だ。
そこがわかれば、ひとまずはよいかな。
統計のことは勉強しても面白そうなので、もうちょっと読んでいこう。
Open Live Writerでソースコードを載せられるプラグインがあったので、使ってみよう。
あ、これってWordPress用だ。。。
Tableと組み合わせれば、まあまあいいかな。
・・・OpenLiveWriterではほどほどに見えていたのですが、アップしたら化け化けだったので消しました。
さて、このNDLとネットワーク図を見比べよう。
最初のInputであるfeaturesは、SDimになっている。
サンプルの行列はSDim行1列とあるから、こういうやつか。
![]()
ラベルは、label0かlabel1と書いてある。
じゃあ2次元やん、と思うけど、binary classficationで、p(y=0) = 1 – p(y=1)とも書いてある。
YESかYESではないか、ということで1次元というサンプルの意味になっているのかな?
ちなみに、このチュートリアルのトレーニングデータと、Simple2dのトレーニングデータは同じ並びで、3列のデータのうち、最初の2列がサンプルで、最後の1列がラベルになっている。
そして、ラベルはどちらも0か1だ。
だから、Simple2dも1次元でやることができるのだろうと思う。
データの認識の仕方が違うだけと言うことか。
これでデータの準備ができたようだ。
チュートリアルでは、ロジスティック回帰の評価式をこう定義している。
y = W_0 + W_1 x_1 + W_2 x_2 + ...
なんですっけ、マクローリン展開じゃないけど、ああいう感じがしますな。
ともかく、W_0がバイアスで「B」、W_1以降が重みで「W」と表現する、と。
それが、この部分。
B = Parameter(LDim, 1)
W = Parameter(LDim, SDim)
ナゼコウナッタ…
この辺りが、Logistic Regression(LR)として説明されているのだろうか。
英語だけわからないのであれば読んでみようと思うが、きっと確率論がわかっていないと理解できないんだ!と思い込んでしまったので、読む気にならない。。
ただ、そこに描かれているlogistic functionは、『深層学習』p.10の式と同じだ。
そういった共通の知識の下(たぶん確率論)で通じる話題なのだろう。
だから、今回は深読みせず、スルーだ。
これで決まったパラメータが、ようやくネットワークに出てくる。
t = Times(W, features)
z = Plus(t, B)

このTimesはパラメータW_1~の積和で、PlusはバイアスW_0を足すところですね。
この積和が、専用演算を持ってると1命令で計算できたりするので高速化できたのだったと思う。
積和というと、行列で物体を回転させたりとか平行移動するようなアフィン変換でも使われるので、ゲームとかの画像処理ではよく使うため、GPUでその辺りが強化されている・・・という流れで、深層学習でもGPUを使うものが多いんじゃなかろうか。
ネットワークの最後が、こう。
s = Sigmoid(z)
LR = Logistic(labels, s)
EP = SquareError(labels, s)

バイアスまで足した結果のzをシグモイド関数に突っ込んで、それがEPとLRのInputになっている。
EPとLRのInputはもう1つあって、それがlabelだ。
labelがInputになるということは、答え合わせだろう。
まずは、EP。
これは何の略だろう?
SquareErrorで検索すると、二乗誤差、とあった。
二乗誤差で検索すると、平均する結果が多く出てきた。
RMS、と略するらしい。
うーん・・・
labelは、(x1, x2)が1か0かという「正解」で、sはシグモイド関数の結果だから0.0~1.0の値だ。
ということは、シグモイド関数に通した結果が、0.0に近いのか1.0に近いのかという、分類分けの確率を想像した結果という意味になる。
えー、だって、掛けて足しただけやん!
それをシグモイド関数に通しただけで学習結果が得られるの??
もし結果が全部正解なら、誤差は0だから、二乗誤差も0になる。
そうでなくても、確率が高い方に寄っているなら、二乗誤差も小さいことになる。
じゃあ、LRはなんだ?
これはLogistic Regressionの略だろうけど、ロジスティック関数に通すのだろうか。
しかしそれならば、Inputは1つでいいはずだ。
うーーーん・・・
最終結果は、これのようだ。
Final Results: Minibatch[1-1]:
Samples Seen = 603
EP: SquareError/Sample = 0.032142105
LR: Logistic/Sample = 0.22066998
EPは、まあわかる。1サンプル辺りの二乗誤差だ。RMSだ。
LRも「/Sample」だから1サンプル辺りなのだろうけど、よくわかりませんな。
次回だ、次回。