はじめに
先のページで、簡易化したFully Convolutional Networks(FCN)を Chainer を使って実装した。残念ながら、その精度は文献のものより低かった。今回以下の改良を行ったところ、格段に精度は向上した。
- FCNのソースはCaffeである。CaffeにはCropLayerなる層が実装されており、FCNはこれを利用している。Chainerにはこれに相当するものがないが、chainer.functions.deconvolution_2dのoutsizeという引数を利用すれば同じような効果が得られることが分った。この関数の利用により、任意サイズの画像を受け付けることができるようになった。従って、入力画像に対しては何も手を加えていない。前回は$224\times 224$にリサイズしたのであった。
- ラベルの情報を持つ画像(ラベル画像)はRGB画像でなく、インデックス画像である。前回はこれを理解しておらず、わざわざRGBから整数値に変換する関数を介在させていた。今回はインデックス画像としてラベル画像を読み込むようにした。
- FCNの正式な構築手順は、fcn32s $\rightarrow$ fcn16s $\rightarrow$ fcn8sである。FCNの精度は、ほぼfcn32sの精度で決まっており、fcn16s/fcn8sからの寄与は1%程度である。前回はfcn8sを実装したが、今回はfcn32sの実装を示す。
- 前回はミニバッチ処理を行ったので関数chainer.links.BatchNormalizationを導入したが、今回は1枚ずつ処理するのでこの層を削除した。
- 前回はchainer.links.Deconvolution2Dを利用して拡大時のパラメータも学習していた。今回はchainer.functions.deconvolution_2dを利用し、単純なbilinear補間による拡大を採用した。
学習曲線
最初に学習曲線を示す。
Accuracy Loss どちらも理想的な曲線となった。またテスト画像の正解率は92%弱となり前回よりも格段に向上した。このあとfcn16s/fcn8sを行えば93%程度にはなりそうである。以下詳細を記す。
計算機環境
前回と同じく、Amazon EC2 にある g2.2xlarge を利用した。GPU を搭載したインスタンスである。 ただし、今回はミニバッチ処理ができないので1枚ずつ学習する。上の結果を得るのに3.5日ほどかかっている。課金量も相当である。
データセット
前回と同じく、データセットは VOC2012 である。領域分割の教師データの数は2913枚、これを4:1に分割し、前者を訓練データ、後者をテストデータとした。
number of train | number of test |
---|---|
2330 | 583 |
前回は、訓練データ数は10で、テストデータ数は5で割り切れるように端数を切り捨てたが、今回はミニバッチ処理を行わないので、そのような操作はしていない。上述したように画像のサイズもそのままである。 カテゴリ数は前回と同じく20+1(背景)である。
label | category |
---|---|
0 | background | 1 | aeroplane | 2 | bicycle | 3 | bird | 4 | boat | 5 | bottle | 6 | bus | 7 | car | 8 | cat | 9 | chair | 10 | cow | 11 | diningtable | 12 | dog | 13 | horse | 14 | motorbike | 15 | person | 16 | potted plant | 17 | sheep | 18 | sofa | 19 | train | 20 | tv/monitor |
ネットワークの構造
ネットワークの構造は以下の通りである。 これは前回と同じである。文献では、pool5 の後ろにfc6とfc7があるが、これらを入れると拡大時の処理が煩雑となる(というかよく分らない)ので、これら2層は残念ながら今回も削除した。上記の表では224$\times$224の正方形画像を想定してその1辺の長さだけをinputに記してあるが、縦横の長さは任意で構わない。表の各項目の意味は以下の通りである。
- name: 層の名前
- input: 入力featureマップの1辺のサイズ
- in_channels: 入力featureマップ数
- out_channels: 出力featureマップ数
- ksize: カーネルのサイズ
- stride: ストライドのサイズ
- pad: paddingのサイズ
- output: 出力featureマップの1辺のサイズ
ネットワークの実装
上記の構造をそのままChainerで記述する。
-- myfcn_32s_with_any_size.py -- 物体の境界線には-1を配置し、softmax_cross_entropyの計算時に境界の寄与を無視するようにした(Chainerの仕様ではラベルが-1の画素は評価されない)。また、関数F.accuracyの引数 ignore_labelを使えば境界線上の画素を除いてaccuracyを計算することができる(前回はわざわざ実装していた)。99行目から100行目にかけて記載した関数F.deconvolution_2dでp5を32倍している。さらに、引数outsizeにtのサイズを渡すことで結果がtと同じになるようにリサイズを行う。引数padには辻褄合わせのpadding量を渡している。
訓練
訓練時のスクリプトは以下の通りである。
-- train_32s_with_any_size.py -- 関数 copy_model とVGGNet.pyは前回と同じである。 train_32s_with_any_size.pyでしていることは、
- オブジェクトmini_batch_loader_with_any_sizeを作る。
- VGGNet.pyで定義されたネットワークのオブジェクトを作る。
- MyFcn32sWithAnySize.pyで定義されたネットワークのオブジェクトを作る。
- VGGNetのパラメータをこれにコピーする。
- 最適化アルゴリズムとして MomentumSGD を選択する。
- あとは、通常の訓練過程である。
-- mini_batch_loader_with_any_size.py --
91行目から96行目までの関数load_voc_labelでは、pngのインデックス画像をインデックスのまま読み込み、値が255の画素を-1に置き換えている。データを一括読み込みすると、ビデオメモリーが足りなくなるので、要求されるごとに読み込むようにしてある。
結果画像
以下の左の列に、テスト画像に対する予測結果をテスト画像にオーバレイした画像を示す。下に記した数値はaccuracyである。ここでaccuracyとは、1枚の画像の中で何%の画素が正解したかを計算したものである(境界線上の画素は除く)。右側の列は、Ground Truthである。
このあと、fcn16s/fcn8sを行えば、物体の輪郭はもう少し正確になるだろう。
ダウンロード
ここの、タグが2016-07-09のものです。今となっては不要なファイルがたくさん残っています。
0 件のコメント:
コメントを投稿