画像ではなく、ピクセル単位でクラス分類するSegmentationのタスク。 fast.aiにあるtiramisuが実装もあって分かりやすいので試してみた。下記のコードスニペットは、fast.aiのオリジナル実装ではなく、keras2で書き直されたjupyter notebookのコードをベースに、自分で若干の手直しをしたものを使っている。
tiramisu
- 論文は、The One Hundred Layers Tiramisu: Fully Convolutional DenseNets for Semantic Segmentation
- tiramisuはDenseNetのアイデアをSegmentationに適用したアーキテクチャ。FC-DenseNet。
- DenseNetはCVPR2017でBest paper award
tiramisuのネットワーク
- DenseNetはCVPR2017でBest paper award
- 特徴抽出を行うDown-sampling pathと入力画像サイズを復元するUp-sampling path
Down-sampling path
- Down-sampling pathの構成と実装
- DB(Dense Block)とTD(Transition Down)の繰り返しで特徴抽出
- DBの最後の出力特徴マップをUp-sampling pathのためのskip connectionとして保存
def down_path(x, nb_layers, growth_rate, keep_prob, scale): skips = [] for i, nb_layer in enumerate(nb_layers): x, added = dense_block(nb_layer, x, growth_rate, keep_prob, scale) skips.append(x) x = transition_down(x, keep_prob, scale) return skips, added
- DBの構成と実装
def dense_block(nb_layers, x, growth_rate, keep_prob, scale): added = [] for i in range(nb_layers): b = conv_relu_batch_norm( x, growth_rate, keep_prob=keep_prob, scale=scale) x = concat([x, b]) added.append(b) return x, added
- TDは空間解像度の削減、要はpoolingと同等の処理
- 論文では1x1 convolutionと2x2 poolingの組み合わせが提案されているが、fast.aiではstrideが2の1x1 convolutionを提案。
def transition_down(x, keep_prob, scale): return conv_relu_batch_norm( x, x.get_shape().as_list()[-1], ksize=1, scale=scale, keep_prob=keep_prob, stride=2)
Up-sampling path
- Up-sampling pathの構成と実装
- TU(Transition Up)、skip connectionとの連結(concat)、DBの繰り返しで入力画像サイズに復元
def up_path(added, skips, nb_layers, growth_rate, keep_prob, scale): for i, nb_layer in enumerate(nb_layers): x = transition_up(added, scale) x = concat([x, skips[i]]) x, added = dense_block(nb_layer, x, growth_rate, keep_prob, scale) return x
- TUは特徴マップをupsamplingするtransposed convolutionで構成
- 入力と同じch数で、3x3 kernel size、strides 2で2倍の特徴マップを生成
def transition_up(added, scale): x = concat(added) _, row, col, ch = x.get_shape().as_list() return Conv2DTranspose( ch, 3, kernel_initializer='he_uniform', padding='same', strides=(2, 2), kernel_regularizer=l2(scale))(x)
学習
- 56層バージョン。FC-DenseNet56
- OptimizerはRMSProp、学習率の初期値は1e-3、学習率減衰は0.00005
- L2正則化の係数1e-4、Dropout rateは0.2、growth rateは12
- データセットはcamvid、360x480から224x224をクロップして入力画像とする
- batchsizeは10、epochsは30で実行
結果
- 24epochでvalidation accuracyが85%
- 結果画像を見ると、道路と白線は分類出来ているようだが、車と背景との分離はもう一歩。Ground-Truthにはない画像右上の柱が推定出来ている。
- パラメータ数が少ないモデルという特徴があり、実際にGPUの無いMacでも学習を実行出来るのは良い点。