aws ec2, g2.2xlarge, ubuntu 14.04でfully convolutional netの学習を回せるようにする


前の[ポスト](http://qiita.com/festa78/items/40863d2f59bc8102308a)では学習済モデルでのテスト環境のみを整備した。
今回は具体的にデータを使ってモデル学習を回せるようにする。

caffeは上に書いてあるinstructionにより、BVLC/caffe:master @ 74cc497をcheckoutして使う。
https://github.com/shelhamer/fcn.berkeleyvision.org
 -> 別に74cc497をチェックアウトしなくても最新版で行けた。

用いるデータセットはPASCAL VOC 2010
http://host.robots.ox.ac.uk/pascal/VOC/voc2010/

タグデータはpascal-contextのデータの59_context_labels.tar.gzを利用
http://www.cs.stanford.edu/~roozbeh/pascal-context/

validationに使うデータは以下のサイトにあるseg11valid.txtを参照。それ以外はtrainに。
https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/data/seg11valid.txt

LMDBを作成するには以下のサイトのスクリプトをベースに行う
https://groups.google.com/forum/#!topic/caffe-users/-vWuaM3bnro


学習を回そうとした時に、
F0616 18:37:35.315524 29112 math_functions.cu:123] Check failed: status == CUBLAS_STATUS_SUCCESS (14 vs. 0)  CUBLAS_STATUS_INTERNAL_ERROR
が出る場合、出力層のラベル値が何かしら間違っている。
-> non integerだったり、負値があったり、0-60のラベルを0-255レンジの飛び飛びラベル付けをしていたり。

ネット学習中、全くloss値が減らない場合、solve.pyのfc6,fc7において
solver.net.copy_from(base_weights)
が機能せずパラメータに0値が入っている恐れがある。

```bash
I0426 23:23:46.976120  6412 net.cpp:752] Ignoring source layer fc6
I0426 23:23:46.976181  6412 net.cpp:752] Ignoring source layer fc7
```

みたいなのが出てたらダウト。
caffeのexampleにある[net_surgery](https://github.com/BVLC/caffe/blob/master/examples/net_surgery.ipynb)を参考にして手動でコピーする。以下例

```python
caffe_root = '/home/ubuntu/'  # this file is expected to be in {caffe_root}/examples                                                                          
import sys
sys.path.insert(0, caffe_root + 'python')

# Load the original network and extract the fully connected layers' parameters.                                                                               
net = caffe.Net(rootpath+'vggmodel/vgg16fc.prototxt',
                rootpath+'vggmodel/vgg16fc.caffemodel',
                caffe.TEST)
params = ['fc6-conv', 'fc7-conv']
# fc_params = {name: (weights, biases)}                                                                                                                       
fc_params = {pr: (net.params[pr][0].data, net.params[pr][1].data) for pr in params}

for fc in params:
    print '{} weights are {} dimensional and biases are {} dimensional'.format(fc, fc_params[fc][0].shape, fc_params[fc][1].shape)

params2 = ['fc6', 'fc7']
fc_params2 = {pr: (solver.net.params[pr][0].data, solver.net.params[pr][1].data) for pr in params2}
for fc in params2:
    print '{} weights are {} dimensional and biases are {} dimensional'.format(fc, fc_params2[fc][0].shape, fc_params2[fc][1].shape)

# transparent                                                                                                                                                 
for pr, pr2 in zip(params, params2):
    fc_params2[pr2][0].flat = fc_params[pr][0].flat  # flat unrolls the arrays                                                                                
    fc_params2[pr2][1][...] = fc_params[pr][1]
```

学習後モデルを使ったテスト時、モデルを読み込むと

```bash
I0426 23:23:46.976120  6412 net.cpp:752] Ignoring source layer upscore
I0426 23:23:46.976181  6412 net.cpp:752] Ignoring source layer score
```

といった表示が余計に出る場合、対応する層に関するパラメータが読めていない。
deploy.prototxtとtrain_val.prototxtを比較するなどして、ネットワーク構造の不整合を修正する。
例えばnum_output、layerの名前とかがあってなかったりする。
デフォルトで入ってるdeploy.txtはfcn8s仕様なので、fcn32s仕様にするには、upscore周りを修正する必要あり。

メモリが足りないようであれば、下の修正を適用してshared memory仕様にする。（が最終的にうまく行かなかったので注意）
https://github.com/BVLC/caffe/pull/2016/commits/839b0502648a5dcf056c3f4a6ace1d0198e6b03e
しかし以下によればg2インスタンスはこれに対応していない模様。また最新版のcudaなどではいくつかside effectがあって良くないとの事。
https://github.com/torrvision/crfasrnn/issues/4
一応CUDA 7.5にすれば動くとの事だが、g2.x2largeはCUDA 7.5がうまく動かないため以下のサイトにあるコードを実行：
https://devtalk.nvidia.com/default/topic/880246/cuda-7-5-unstable-on-ec2-/

```bash
export DEBIAN_FRONTEND=noninteractive
apt-get update -q -y
apt-get -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install linux-generic
wget http://developer.download.nvidia.com/compute/cuda/7.5/Prod/local_installers/cuda-repo-ubuntu1404-7-5-local_7.5-18_amd64.deb

dpkg -i cuda-repo-ubuntu1404-7-5-local_7.5-18_amd64.deb
apt-get update -q -y
apt-get install cuda -q -y
echo ' /usr/local/cuda/lib64
/usr/local/cuda/lib' | tee -a /etc/ld.so.conf.d/cuda.conf > /dev/null
```

ただこれをやっても結局メモリエラーが出てしまった。
結局上記shared memoryはやめて画像サイズを軒並み半分にしてなんとか動いた。
あるいは画像を手動でスライドウインドウ方式で切り取って、新たに小さい画像のデータセットを作成した。

# fcn16s, fcn8s

fcn32sの学習が終わったら、そのcaffemodelをpretrain modelにしてfcn16sを学習へ移行する事が可能。（16sから8sも同様）（vggmodelをpretrain modelにして学習する事も可）
その際の基本プロトコルは以下のサイトにあるvoc_fcn16sやvoc_fcn8sにあるものを用いると楽だった。
https://github.com/shelhamer/fcn.berkeleyvision.org

今までと違うのは、train.prototxtとval.prototxtが分かれている事と、dataの読み込みがlmdbではなくpythonベースで書かれている事。
ここはtrain.prototxtのdataの読み込み部をlmdbベースのものにTRAIN, TEST phase両方とも持ってきて置き換えてしまえばOK。するとval.prototxtはもういらない。solver.prototxtがtrainとval.prototxt双方読む設定になっているが、それも合わせて修正。
fcn32sで使ったtrain_val.prototxtと比較してnum_outputとかlayer名とかupscoreの繋げ方とかが少し違うので比較しながら修正する。deploy.prototxtに関しても同様。
なぜかdrop layerが使われなくなっているが理由は不明。

あとはsolve.pyを修正してpretrainしたfcn32sのcaffemodelからweightをfcn16sへ新しくコピーしてくるようにし、学習すれば動くはず。
この時upscoreとscore系がignoreされたと言われるけど学習は問題なく動いた。