複数種類の傷を学習させるために,以前に作ったAutoEncoder*1を拡張します.
複数(=傷の種類)の出力画像を持てるようにネットワーク構造を変えればいいですね.
あれこれ調べてみると,今回やりたい事はU-Netと同じであることに気付きました.
Semantic Segmentationで有名なU-netですので,サンプルは豊富です.
ということで,U-Netベースの複数傷検出にトライしました.
入力画像
DAGM画像を↓↓の様に使いました.
使用画像 | |
---|---|
学習 | Class1_def 1-120, Class1_def 121-150 |
テスト | Class1_def 1-120, Class1_def 121-150 |
Class1とClass2に思い入れがあるわけではありません.
今回のトライがうまく行ったら,全種類の画像で学習させます.
ソース
こちら*2を参考にさせていただきました.
参照元ではtf.layers.conv2Dとtf.layers.batch_normalizationを使って正規化処理をされていたのですが,動きを良く理解していないライブラリを使うのが嫌いなので,実績のあるtf.nn.conv2Dを使いました.
ネットワークの構成も,入力画像の大きさに合わせて少し変えてあります.
また,特に理由は無いですが,padding有りで組んでいます.
少し迷ったのが,評価関数の立て方です.
def evaluate(output, y): s = tf.sign(output) z = tf.constant(0, shape=[TEST_DATA_SIZE*CATEGORY, IMG_SIZE*IMG_SIZE*CATEGORY], dtype=tf.float32) zero_cut = tf.maximum(s, z) correct_prediction = tf.multiply(zero_cut, y) accuracy = tf.reduce_sum(correct_prediction) return accuracy
mnist*3とは違って正解が領域を持つので,argmaxでの評価が難しいと思いました.
試行錯誤をして,出力値が0.0を変える領域をラベルと比較するように作ってみました.
ラベルは傷の大きさに応じて正規化しているので,60枚のテスト画像を使った今回のトライでは理想値60.0になります.
結果
こんな感じになりました.
左:元画像,左中:Class1用のラベル,中:Class2用のラベル,右中:Class1の出力画像,右:Class2の出力画像
概ね正しく傷検出できました.
ただ,Class2のネットワークは,Class1の傷にも少し反応してしまうようでした.
傷の特徴が多少似ているのかも知れないですね.
直感的には,傷の無いbackground部分のテクスチャーの違いが影響している様に感じました.
学習経過は↓です.
苦労した評価関数は,巧く動かずに暴れています(汗).
DAGMに付属しているラベルが大雑把なので,傷領域を綺麗に抽出すると,ラベルよりもずっと小さい領域になってしまうのです.
改良が必要ですね.
次回はClass6までを含めた学習にトライします.
今回書いたソースはここ*4です.