傷検出がなかなか進展しない*1ので,アプローチを変えることにしました.
傷検出を行う為のアルゴリズムとしては,先日ReNomで試した矩形検出*2か,元々参考にしていた論文*3で採用されているAutoEncoderになると思います.
更にもうひとつ,Segmentationで傷領域を抽出するやり方もあるでしょう.
それぞれの特徴を,浅はか極まり無い知識でまとめてみます.
アルゴリズム | メリット | デメリット |
---|---|---|
矩形検出 | 複数のラベルをつけられる(傷パターン1,傷パターン2など) | 抽出領域が矩形に限定される |
AutoEncoder | 各画素について傷情報を出力できる | 傷のパターン分けが出来ない |
Segmentation | 傷領域をダイレクトに抽出できる | 傷領域内の確率は一様になる |
僕のやりたいことは,各画素についての傷確率を求めることなので,改めてAutoEncoderが相応しいと思いました.
そこで,アルゴリズム側から実相してみることにします.
AutoEncoder(自己符号化器)とは?
理解しにくい和名ですが,,,論文を意訳すると
- エンコーダネットワークとデコーダネットワークから成る
- エンコーダネットワークは,入力画像を多次元フィーチャー画像に変換する.この過程で,豊富な意味情報(Rich semantic information)を炙りだしたフィーチャーマップを取得する.
- デコーダネットワークは,フィーチャーマップから各ピクセルのラベルを求める.出力画像は,元画像と同サイズにアップサンプリングされる.
要するに,エンコーダで特徴を抽出し,それを逆変換して位置情報を再構成するということだと思います.
ネットワーク構造はこんな感じです.
右側に進む上部の処理がエンコーダ,左に進む下部の処理がデコーダです.
実装
こちら*4を参考にしました.
AutoEncoderの特徴であるエンコーダとデコーダを,Convolution層とPool層を重ねて構成します.
def inference(x, input_size): x = tf.reshape(x, shape=[-1, IMG_SIZE, IMG_SIZE, 1]) # Encoding with tf.variable_scope("conv_1"): conv_1 = conv2d(x, [3, 3, 1, 16], [16]) pool_1 = max_pool(conv_1) with tf.variable_scope("conv_2"): conv_2 = conv2d(pool_1, [3, 3, 16, 8], [8]) pool_2 = max_pool(conv_2) with tf.variable_scope("conv_3"): conv_3 = conv2d(pool_2, [3, 3, 8, 8], [8]) pool_3 = max_pool(conv_3) # Decoding with tf.variable_scope("conv_4"): conv_4 = conv2dtranspose(pool_3, [3, 3, 8, 8], [8], [input_size, 7, 7, 8]) with tf.variable_scope("conv_5"): conv_5 = conv2dtranspose(conv_4, [3, 3, 8, 8], [8], [input_size, 14, 14, 8]) with tf.variable_scope("conv_6"): conv_6 = conv2dtranspose(conv_5, [3, 3, 16, 8], [16], [input_size, 28, 28, 16]) with tf.variable_scope("conv_7"): conv_7 = conv2d_sigmoid(conv_6, [3, 3, 16, 1], [1]) decoded = tf.reshape(conv_7, [-1, IMG_SIZE * IMG_SIZE]) return decoded
特徴的なのが,損失関数の定義ですね.
def loss(x, decoded): cross_entropy = -1. *x *tf.log(decoded) - (1. - x) *tf.log(1. - decoded) loss = tf.reduce_mean(cross_entropy) return loss
これ,確かにラベル(0とか,1とかの文字情報)を銘記しないんですが,元画像が実質的なラベルとして働くんですね.
mnist画像の場合,文字のある場所が255付近(正規化すると1),文字のない黒い部分が0なので,ネットワークからの出力に元画像をかけることで,文字部分の出力のみが残って評価されることになります.
個人的には,「たまたま教師無しになっている」という印象を持ちます.
機械学習の意味合いからすると,文字部分を1,背景を0としたラベル画像を作るのがスッキリすると思いました.
結果はこんな感じです.
今回書いたソースはここ*5です.
次は,DAGM画像をこのアルゴリズムに当ててみます.
*1:https://changlikesdesktop.hatenablog.com/entry/2019/03/08/054439
*2:https://changlikesdesktop.hatenablog.com/entry/2019/05/01/132703
*3:https://www.researchgate.net/publication/327494004_Automatic_Metallic_Surface_Defect_Detection_and_Recognition_with_Convolutional_Neural_Networks