まんぼう日記

takataka's diary

Caffe の学習済みネットワークを Theano に移して動かす (2)

10月にうけた健康診断の結果を分析したレポートが手元に届きました.

あなたの「健康年齢」は,実年齢より上です

がびーん.家の体脂肪率計付き体重計は実年齢より15歳下って言うてくれるのに...

脂質・血糖の値が高く,注意が必要です.思い当たる生活習慣があれば見直しませんか?

健康を悪化させる生活習慣> 糖質のとり過ぎ,脂(飽和脂肪酸)のとり過ぎ,運動不足

がびがびーん.運動不足やないと思う( てくてく2年 - まんぼう日記 )ので,食生活のせいでしょうなあ.歩いたり走ったりした後にスポーツドリンクごくごくとか,多忙を言い訳にカップ麺(しかも大盛り)の昼食とか,運動してお腹すくからって脂っこいもんだらけの夕食(しかもご飯はデフォルト1合)とか,….思い当たりまくりです,反省してます,ごめんなさい.

 

 さて,そんな話はどーでもえーですな.Caffe の学習済みネットワークを Theano に移して動かす - まんぼう日記 のつづきです.Caffe を使って ImageNet の画像で学習した deep なネットワークを入手し,それを Theano で動かしてみます.

 

 

ネットワークモデルの選択と入手

Caffe | Model Zoo / Model Zoo · BVLC/caffe Wiki · GitHub を物色.メジャーなところがええやろう,ちうわけで Models used by the VGG team in ILSVRC-2014 の 16-layer のモデルを選択.以下,VGG-16 と略記します.他のんはたいてい Local Response Normalization 使ってるけど,たかたかは Theano で実装してないから,ってのも理由.VGG-16 に関する情報源はこちら:

  1. http://www.robots.ox.ac.uk/~vgg/research/very_deep/
  2. https://gist.github.com/ksimonyan/211839e770f7b538e2d8
  3. [1409.1556] Very Deep Convolutional Networks for Large-Scale Image Recognition

 

上記 2. または 3. から次の2つを入手します:

  • ネットワーク構成を定義したファイル: VGG_ILSVRC_16_layers_deploy.prototxt
  • 実際のネットワークのパラメータ:        VGG_ILSVRC_16_layers.caffemodel

どうやら入手したファイルは古いバージョンの Caffe の形式をしてるらしいです.そのままでもいい(Caffe が自動で変換する)みたいですが,手動で新しい形式に変換するプログラムがあるので,変換しときます.

$ upgrade_net_proto_text  VGG_ILSVRC_16_layers_deploy.prototxt  VGG_ILSVRC_16_layers_deploy_upgraded.prototxt
$ upgrade_net_proto_binary   VGG_ILSVRC_16_layers.caffemodel  VGG_ILSVRC_16_layers_upgraded.caffemodel

 

Theano に移すプログラムの用意

上記の deploy.prototxt を解読してたら,たかたかが作った Theano の CNN 用プログラムでは対応しきれてないことが判明.というわけで,まずはそのプログラムの修正作業.できたのがこちら: convnet160327.py · GitHub

 

次に,caffemodel を読み込んで,ネットワークのパラメータを上記のプログラムで生成したインスタンスの変数に代入するプログラムを書きます.その際に気づいた注意点...

 

(1) Caffe では convolution filter の値をそのまま保持してるが,Theano では左右上下に反転したものを保持するのがデフォルト.

http://deeplearning.net/software/theano/library/tensor/nnet/conv.html#theano.tensor.nnet.conv2d

を見ると filter_flip = True がデフォルトになっているので,Caffe の filter の値をそのまま使う場合は False にすればよい.

 

(2) VGG-16 で確認した限りでは,(1) 以外の点では theano.tensor.nnet.conv2d や theano.tensor.signal.pool.pool_2d のデフォルトは同じ設定のようだ.pool_2d の ignore_border は True.

 

(3) VGG-16 の deploy.prototxt には 

layer {
  name: "drop6"
  type: "Dropout"
  bottom: "fc6"
  top: "fc6"
  dropout_param {
    dropout_ratio: 0.5
  }
}

というように dropout するための layer が定義されているが,caffe.model に格納されているパラメータは,その影響を考慮済みのようだ.つまり,パラメータにはすでに dropout_ratio が乗算されている.

 

(4) これは Caffe や Theano の話ではないですが,VGG-16 の出力は,ILSVRC2012 および ILSVRC2014 の devkit で与えられたメタデータにおける ILSVRC2012_ID や ILSVRC2014_ID の順ではなく,WNID の順になってます.たとえば ILSVRC2012_validation_ground_truth.txt は ILSVRC2012_ID 順に番号が振られてるので,そのまま使って識別率を計算すると「あれ,全然正解できてへんやん」って悩むはめになります.要注意です.

 

これらを踏まえて,ILSVRC2012 の validation 画像を読み込んで識別するプログラムを書きました.ついでに Caffe でそのまま動かすのんも.公開してないプログラム使ってたりするので,人様の参考にならへんと思いますが,こちら:ex160328 · GitHub

 

実験

上述のプログラムを動かしてみました.GPU は GeForce GTX TITAN X です.

 

Caffe で動かすプログラム ex160328_Caffe.py での結果は次の通り:

  • top-1 error rate: 29.03%,  top-5 error rate: 10.118%
  • 計算時間 10分,GPU メモリ使用量 1376MiB

 

Theano に移して動かすプログラム ex160328_Theano.py での結果は次の通り:

  • top-1 error rate: 29.03%, top-5 error rate: 10.118%
  • 計算時間 18分,GPU メモリ使用量 2984MiB

 

まず,error rate は全く同じですので,ネットワークの出力は正しく計算できているようです(ちなみに,上でも書きましたが,最初に全結合層の dropout を 0.5 として ex160328_Theano.py を実行したら,top-1 30.05%, top-5 10.612% っちう微妙に悪い結果が出たので悩みました).

 

計算時間の違いは,たかたかの書いたプログラムの効率が悪いせいです.たぶん.それから,GPU メモリ使用量については,たぶん Caffe の方は TEST モードだから誤差逆伝播のためのパラメータの勾配用のメモリを確保してなくて,たかたかの書いた Theano のプログラムではそれ用のメモリをばっちり確保してるせいだと思います.

 

ちなみに,上記の error rate はオリジナルの値 top-5 で 8.1% より悪いですが,これは,彼らは単純に 224x224 に切り取った画像1枚を入力して得られた出力を使うのではなく,VGG-16 の全結合層を convolution 層に変換して,より大きな画像を入力してごにょごにょ…ということをやってるからです.詳しくは上述の 3. の文献を読みましょう.