はじめに
先のページで Caffe を使ったシーン認識(15分類問題)を試みた。今回は、Caffe の学習済みモデルを Chainer を使って Fine-Tuning することにより同じシーン認識を行ってみる。
計算機環境
これまでと同じく、Amazon EC2 にある g2.2xlarge を利用した。GPU を搭載したインスタンスである。
データセット
先と同じ LSP15 を利用する。このデータセットは15個のディレクトリから構成されている。
- MITcoast
- MITforest
- MIThighway
- MITinsidecity
- MITmountain
- MITopencountry
- MITstreet
- MITtallbuilding
- bedroom
- CALsuburb
- industrial
- kitchen
- livingroom
- PARoffice
- store
データセットの増量
左右反転画像を追加する。そのあと、データセットを 6:1 に分割し、前者を訓練画像、後者をテスト画像とした。最終的な画像の枚数は以下の通りである。
label | name | number of train | number of test |
---|---|---|---|
0 | MITcoast | 610 | 100 |
1 | MIThighway | 440 | 70 |
2 | MITmountain | 630 | 100 |
3 | MITstreet | 490 | 80 |
4 | MITforest | 550 | 90 |
5 | MITinsidecity | 520 | 80 |
6 | MITopencountry | 690 | 110 |
7 | MITtallbuilding | 600 | 100 |
8 | bedroom | 360 | 60 |
9 | CALsuburb | 400 | 60 |
10 | industrial | 520 | 80 |
11 | kitchen | 360 | 60 |
12 | livingroom | 490 | 80 |
13 | PARoffice | 360 | 60 |
14 | store | 540 | 90 |
7560 | 1220 |
画像の中心部分から最大の正方形を取り出し、このサイズを $256 \times 256$ に変更した。画像へのパスとラベルを記したテキストファイルを以下のように作成した。
--- test.txt --- --- train_valid.txt ---
Caffe モデルの読み込みと保存
今回は Caffe が提供するモデル bvlc_reference_caffenet.caffemodel を利用した。以下のコードで読み込む。 CaffeFunction による読み込みは時間がかかる処理である。cPickle を使って保存し直しておく。
ネットワークの実装
今回使用する Caffe モデルと等価なネットワークを Chainer を使って再現する。bvlc_reference_caffenet.caffemodel と一緒に配布されるprototxt を見ながら実装すれば良い。Chainer のソースコードに含まれるサンプル(chainer-1.6.0/examples/imagenet/alex.py)をベースにした。
--- reference_caffenet.py --- このネットワークの一番上にある fc8 層の名前を scene_fc8 に、この層の出力ユニット数を 1000 から 15 に変更する。変更後のクラスを以下に示す。
--- modified_reference_caffenet.py ---
Fine-Tuning
pickle で保存した Caffe モデルは、L.Convolution2D と L.Linear のオブジェクトを含んでおり、それらは $W$ と $b$ の学習済みパラメータを持っている。上で定義したクラス ModifiedReferenceCaffeNet は scene_fc8 以外の層は Caffe モデル と同じあるから、{conv1, conv2, conv3, conv4, conv5, fc6, fc7} が持つ $W$ と $b$ をそのままModifiedReferenceCaffeNet 側にコピーする。そのあと、今回のデータセットで学習を行えば Fine-Tuning を実現できる。
訓練
訓練時のコードを以下に示す。
--- train.py ---
- 15行目:先に保存した Caffe モデルへのパス
- 16行目:Fine-Tuning後のモデルを保存するファイルへのパス
- 17行目:平均画像へのパス
- 21行目:学習率
- 22行目:ミニバッチサイズ
- 23行目:エポック数
- 24行目:学習率のエポックごとの減衰率
- 29行目:訓練データへのパス
- 30行目:テストデータへのパス
- 33〜45行目:def test: テストデータを使った loss と accuracy の計算。全データの平均値を取る。
- 52〜63行目:データの読み込み。クラス DataLoader については後述。
- 75行目:Caffe モデルを読み込む。
- 78行目:今回使うネットワークのオブジェクトを作る。
- 81行目:学習済みパラメータ $W$ と $b$ をコピーする。最終層 scene_fc8 の $W$ と $b$ はデフォルト値に初期化されている。関数 copy_model については後述。
- 85行目:今回使うネットワークのオブジェクトを GPU 側へ転送。
- 86行目:最適化アルゴリズムとして確率的勾配降下(SGD)法を選択する。
- 87行目:最適化アルゴリズムに最適化すべき対象を渡す。
- 93〜115行目:Fine-Tuning のためのループ
- 123行目:Fine-Tuning 後のモデルを保存する。
--- data_loader.py ---
--- image_cropper.py --- 関数 copy_model についてはこちらのページに掲載されているものを使用した。
--- copy_model.py ---
訓練結果
以下に訓練データとテストデータの正解率と損失を示す。
訓練データ テスト画像
テスト画像に対する正解率は96.23%である。
識別器の作成
識別器のコードは以下の通り。本来であればこれを使って訓練すべきである。訓練をやり直すには時間とお金がかかるので今回は再度 copy_model を使うことにした。
--- modified_reference_caffenet_with_predictor.py --- 識別する際のコードは以下のようになる。
--- predict.py ---
- 12行目:テストデータへのパス
- 13行目:平均画像へのパス
- 14行目:Fine-Tuning 後のモデルへのパス
- 18行目:モデルの読み込み
- 21行目:識別器の作成
- 24行目:パラメータのコピー
- 27〜32行目:テストデータの読み込み
- 35〜40行目:テストデータの数を減らして Variable オブジェクトに格納
- 43,44行目:識別する。
特徴抽出器の作成
fc7層から特徴ベクトルを抽出する。コードは以下の通り。
--- modified_reference_caffenet_with_feature_extractor.py --- このクラスを使って、特徴ベクトルを抽出し、liblinear の入力ファイルを作成する。コードは以下の通り。
--- extract.py ---
- 59行目:Fine-Tuning したモデルを読み込む。
- 62行目:抽出器を作る。
- 65行目:Fine-Tuning したモデルから抽出器へパラメータをコピーする。
- 70,71行目:liblinear への入力ファイルを作る。
SVMの実行
以下のコードで訓練。 以下のコードで予測。 既に示したように Softmax 層を使った時は 96.23% であったから 1% ほど良くなっている。
train.pyの中でcopy_modelの部分でNameError: global name 'link' is not definedというエラーが出ます。
返信削除copy_model.pyにimportすべきライブラリ等はありますか?もしくはその他の方法が必要ですか?
このコメントは投稿者によって削除されました。
削除本文にコードを追加しました。当時はこれで動きました。
削除