NINと画像分類for 2016年の年忘れ!人工知能LT祭
大郷 友海
2016/12/22(木)
自己紹介
名前: 大郷 友海 (だいごう ともみ)
職業: プログラマ(VB.net, C++, )
最近はまっていること:
ディープラーニング(画像分類)。自作モデルで分類精度を上げたい。
話すこと
1. Chainerで画像分類を試みている
2. 正解率(accuracy)が上がらない
3. NIN(Network in Network)について
4. 自作モデルを改善する
話すこと
1. Chainerで画像分類を試みている
2. 正解率(accuracy)が上がらない
3. NIN(Network in Network)について
4. 自作モデルを改善する
1. Chainerで画像分類を試みている
Chainer
・ Python用のディープラーニングフレームワーク
・ 動的な計算グラフ構築による直感的なコードが特徴
http://chainer.org/
画像分類
・ キノコを分類したい!
http://cdn-ak.f.st-hatena.com/images/fotolife/d/defender_21/20160114/20160114085535.jpg
データセット
・ 画像検索で集めたキノコ画像742枚
・ クラス数は7
・ 256*256(カラー)に揃える
データセット内訳
2. エリンギ
1. エノキダケ
3. シイタケ
4. シメジ
5. タモギタケ
6. ナメコ
7. マイタケ
プログラム
・ chainer v1.5.01付属のexamplesより、imagenetをコピー
・ ブログ記事等を参考に動かす
・ threadingなどコードが難しいため、簡略化
・ モデルは3層CNN + 2層全結合層 を作成
試行錯誤の末・・・
1 https://github.com/pfnet/chainer/releases?after=v1.6.2
結果
テストデータの正解率(accuracy) = 56.25%
内訳・・・アルゴリズム
・ 学習用画像は540枚(全データの75%)
・ (画像-平均画像) / 標準偏差 で正規化
・ 元画像を224*224(カラー)にランダム切り抜き
・ 16枚ずつミニバッチ学習
・ epoch(学習回数)=50
・ optimizer(学習率の決定方法)はAdam
・ WeightDecay(重み減衰)=0.0005, GradientClipping(重み上限)=8.75
内訳・・・モデル定義
L.Convolution2D(3, 6, 7),
L.Convolution2D(6, 3, 5),
L.Convolution2D(3, 2, 3),
F.Linear(1152,500),
F.Linear(500,7),
in, out, ksize
内訳・・・forward計算
h = F.relu(self.conv1(x))h = F.max_pooling_2d(h, 3, stride=2)
h = F.relu(self.conv2(h))h = F.average_pooling_2d(h, 3, stride=2)
h = F.relu(self.conv3(h))h = F.average_pooling_2d(h, 3, stride=2)
h = F.dropout(F.relu(h=self.l1(h)),ratio=0.3,train=train)y = self.l2(h)
畳み込みプーリング
↓畳み込みプーリング
↓畳み込みプーリング
↓全結合全結合
2. 正解率(accuracy)が上がらない
結果
テストデータの正解率(accuracy) = 56.25%
・・・せっかくなのでもう少し上げたい。
データセット見直し
・ 画像検索で集めたキノコ画像742枚→ノイズ付加で水増し1して13,356枚に!
・ クラス数は7
・ 256*256(カラー)に揃える →64, 32pxおよびモノクロも試す
1 http://qiita.com/bohemian916/items/9630661cd5292240f8c7
アルゴリズム見直し
・ 学習用画像は540枚(全データの75%) →10,017枚
・ (画像-平均画像) / 標準偏差 で正規化
・ 元画像を224*224(カラー)にランダム切り抜き →192,128,64,32,28px等・・・
・ 16枚ずつミニバッチ学習 →20, 8枚(20枚以上は厳しい)
・ epoch(学習回数)=50 →200など(上げると過学習する)
・ optimizer(学習率の決定方法)はAdam
・ WeightDecay(重み減衰)=0.0005, GradientClipping(重み上限)=8.75→調整
モデル見直し
・ 畳み込み層L.Convolution2D(in_channels, out_channels, ksize)をひたすら調整
・ Convolution→BatchNormalization→relu→maxPooling とするとaccuracy改善するらしい1が、今回は観測できず。
・ Convolution層のチャネル数が入力から出力側へ向けて大きくなっていく構造をよく見かけた。どういうことかというと・・・
1 http://hirotaka-hachiya.hatenablog.com/entry/2016/08/06/175824
モデル見直し
・ L.Convolution2D(3, 6, 7),
・ L.Convolution2D(6, 3, 5),
・ L.Convolution2D(3, 2, 3),
・ l1=F.Linear(1152,500),
・ l2=F.Linear(500,7),
こうではなくて、
L.Convolution2D(3, 6, 7),
L.Convolution2D(6, 9, 5),
L.Convolution2D(9,12, 3),
l1=F.Linear(1152,500),
l2=F.Linear(500,7),
こう。(値は適当)
ksizeはその逆パターン?(未確認)
in, out, ksize in, out, ksize
モデル見直し
先の層へ行くほどフィーチャーマップのサイズが小さくなるため出力チャネル数が一定だとメモリに空きが出来る。
→チャネル数を増やして自由度を上げつつメモリを有効活用するためでは?
という意見を頂いた。
L.Convolution2D(3, 6, 7),
L.Convolution2D(6, 9, 5),
L.Convolution2D(9,12, 3),
l1=F.Linear(1152,500),
l2=F.Linear(500,7),
in, out, ksize
見直し結果
良さそうなものもあったが、全体的に過学習気味。
(学習 と テスト の差が非常に大きい・・・)
見直し結果
・ 大きめのミスに気づく
1epoch毎に画像をランダムに並び替えるはずが、最初の1回しか並び替えていない
修正すると・・・
見直し結果
一気に未学習気味になった。epochを上げても改善せず。
(学習データ も テストデータ も正解率が小さい・・・)
【参考】 過学習 / 未学習
● 過学習に有効
○ 学習データを増やす
○ 変数を減らす
○ λ(正則化パラメータ)を大きくする
● 高バイアスに有効
○ 変数増やす
○ 多項式にする(モデルを複雑にする)
○ λ減らす
※2
※1 "Python Machine Learning" より引用 参考: http://chezou.hatenablog.com/entry/2016/05/29/215739※2 http://lab.synergy-marketing.co.jp/blog/tech/machine-learning-stanford-3
※1
NINを試す
・ 未学習気味になったものと同じアルゴリズムで、モデルをchainer付属のnin.pyに置き換えて学習させてみると・・・
NINを試す
テストデータの正解率が63.9%に! (7.65ポイント上昇)
3. NIN(Network in Network)について
NIN(Network in Network)
・ Min Linら(2014)の提案したニューラルネットワークアーキテクチャ1
・ 従来のCNNの線形フィルタを多層パーセプトロン(MLP)に置き換える
・ CNNは層が進むほど広域をフィルタして高次の概念を生成するが、この提案は局所的な画像が統合されて高次の概念になる前により良い抽象化をすることに意義がある。
1 https://arxiv.org/abs/1312.4400
NIN(Network in Network)
http://qiita.com/muddydixon/items/11ce0e7352c82bc07fcc
↑ 論文中にあるNINの全体図。3つのMLP層とGlobalAveragePooling層が使用されている
←NIN内の各レイヤ出力の計算式。活性化関数にreluが使われている。 i,jは入力フィーチャマップpixelのインデックス。kはチャネルのインデックス、 nはMLP層の数
Global Average Pooling
1 https://arxiv.org/abs/1312.4400
・ 同論文で提案されている正則化手法(regularizer)1
・ 従来のCNNはConvolutionで特徴抽出をし、全結合層で分類するが、全結合層は過学習しやすい。
・ 本手法はこの全結合層をAveragePoolingで置き換え、CNNと各クラスへの出力を橋渡しする。(クラスラベル1つにつき1つのフィーチャーマップが出力される)
・ 学習パラメータを持たないため、過学習に強い
chainer付属nin.pyのモデル定義
w = math.sqrt(2)
mlpconv1=L.MLPConvolution2D(3, (96, 96, 96), 11, stride=4, wscale=w),mlpconv2=L.MLPConvolution2D(96, (256, 256, 256), 5, pad=2, wscale=w),mlpconv3=L.MLPConvolution2D(256, (384, 384, 384), 3, pad=1, wscale=w),mlpconv4=L.MLPConvolution2D(384, (1024, 1024, 1000), 3, pad=1,wscale=w),
chainer付属nin.pyのモデル定義
w = math.sqrt(2)
mlpconv1=L.MLPConvolution2D(3, (96, 96, 96), 11, stride=4, wscale=w),mlpconv2=L.MLPConvolution2D(96, (256, 256, 256), 5, pad=2, wscale=w),mlpconv3=L.MLPConvolution2D(256, (384, 384, 384), 3, pad=1, wscale=w),mlpconv4=L.MLPConvolution2D(384, (1024, 1024, 1000), 3, pad=1,wscale=w),
MLPConvolution2D(入力チャネル数、出力チャネル数、フィルタサイズ、ストライド、重み初期化)
chainer付属nin.pyのforward計算
h = F.relu(self.conv1(x))h = F.max_pooling_2d(h, 3, stride=2)
h = F.relu(self.conv2(h))h = F.max_pooling_2d(h, 3, stride=2)
h = F.relu(self.conv3(h))h = F.max_pooling_2d(h, 3, stride=2)
h = self.conv4(F.dropout(h, train=self.train))y = F.reshape(F.average_pooling_2d(h, 6), (x.data.shape[0], 1000))
chainer付属nin.pyのforward計算
h = F.relu(self.conv1(x))h = F.max_pooling_2d(h, 3, stride=2)
h = F.relu(self.conv2(h))h = F.max_pooling_2d(h, 3, stride=2)
h = F.relu(self.conv3(h))h = F.max_pooling_2d(h, 3, stride=2)
h = self.conv4(F.dropout(h, train=self.train))y = F.reshape(F.average_pooling_2d(h, 6), (x.data.shape[0], 1000))
畳み込みプーリング
↓畳み込みプーリング
↓畳み込みプーリング
↓畳み込み
Global AveragePooling
4. 自作モデルを改善する
モデルの改善
w = math.sqrt(2)
conv1=L.Convolution2D(3, 8, 7,wscale=w),conv2=L.Convolution2D(8, 16, 5,wscale=w),conv3=L.Convolution2D(16, 32, 3,wscale=w),conv4=L.Convolution2D(32, 48, 3,wscale=w),
モデルの改善
w = math.sqrt(2)
conv1=L.Convolution2D(3, 8, 7,wscale=w),conv2=L.Convolution2D(8, 16, 5,wscale=w),conv3=L.Convolution2D(16, 32, 3,wscale=w),conv4=L.Convolution2D(32, 48, 3,wscale=w),
in, out, ksize
重みの初期値を設定
NINに倣って4層に増やした
Linear(全結合層)をなくした
層が進むほどチャネル数が増える構造
モデルの改善(forward計算)
h = F.relu(self.conv1(x))h = F.max_pooling_2d(h, 3, stride=2)
h = F.relu(self.conv2(h))h = F.average_pooling_2d(h, 3, stride=2)
h = F.relu(self.conv3(h))h = F.average_pooling_2d(h, 3, stride=2)
h = F.relu(F.dropout(self.conv4(h), ratio=0.5,train=train))h = F.average_pooling_2d(h, 3, stride=2)
y = F.reshape(F.average_pooling_2d(h, 6), (x.data.shape[0],48))
畳み込みプーリング
↓畳み込みプーリング
↓畳み込みプーリング
↓畳み込みプーリング
↓Global Average
Pooling
改善結果
テストデータの正解率(accuracy)=61.3% !
(最初のモデルから5.05ポイントの増加)
考察
・ 層数とチャネル数(モデルの奥行きと幅)を増やして表現力を向上させたこと
・ それに伴う過学習を予防するGlobalAveragePoolingを導入したこと
・ 各層での重みの初期値を変更したことで学習を短時間で終えられた?こと
上記が正解率の向上に寄与したものと考える。
展望
・ PReLU, MaxOut, BatchNormalizationなどの他手法も調べたい
・ 今の精度測定方法が甘いのでもっと厳密に
展望
http://joehinkle.com/wordpress/wp-content/uploads/2015/04/King-Oyster-Mushrooms-150x150.jpg
大量データ(キノコ)を分類できる日も近い・・・!
ご清聴ありがとうございました。
Top Related