こんにちは、のっくんです。
今日はディープラーニングを使って、壁のヒビ割れ検出にチャレンジしてみようと思います。
ヒビ割れの検出って調べてみると論文になっていたりして研究分野としても人気があるみたい。
ヒビ割れはCrackと言います。
kerasを使って数行のコードで実装できました。
[toc]
データセット
データセットは以下のサイトにありました。
https://dataturks.com/projects/miaozh17/Crack%20Classification
1428枚のヒビ割れ画像のデータセットです。ラベルはヒビ割れかそうでないかの2値です。
JSONファイルをダウンロードし、Google Colabで読み取ります。

contentが画像のURLです。このURLから画像をダウンロードします。
images = [] for url in tqdm.tqdm(df['content']): response = requests.get(url) img = Image.open(BytesIO(response.content)) img = img.resize((224, 224)) numpy_img = img_to_array(img) img_batch = np.expand_dims(numpy_img, axis=0) images.append(img_batch.astype('float16')) images = np.vstack(images) print(images.shape)
requestsを使って、画像ファイルをダウンロードします。
224のサイズに変換して、numpyの配列として扱います。

左から2番目がCrackで、それ以外はno Crackです。
ネットワークモデル
ディープラーニングに使うモデルは、VGG16をファインチューニングすることにします。
vgg_conv = vgg16.VGG16(weights='imagenet', include_top=False, input_shape = (224, 224, 3)) for layer in vgg_conv.layers[:-8]: layer.trainable = False for layer in vgg_conv.layers: print(layer, layer.trainable)
include_topをFalseにし、全結合層を含まないようにします。
VGG16では全部で5つの畳み込みブロックがありますが、下2つの畳み込みブロックは解凍して学習可能にします。
こうすることでより、今回の画像分類に特化したモデルを作成することができます。
上記コードの出力結果は以下の通り。
<keras.engine.input_layer.InputLayer object at 0x7efeca504828> False <keras.layers.convolutional.Conv2D object at 0x7efeca7b5e48> False <keras.layers.convolutional.Conv2D object at 0x7efec73b69e8> False <keras.layers.pooling.MaxPooling2D object at 0x7efec5b2f160> False <keras.layers.convolutional.Conv2D object at 0x7efec5acd860> False <keras.layers.convolutional.Conv2D object at 0x7efec5a4c3c8> False <keras.layers.pooling.MaxPooling2D object at 0x7efec51cad68> False <keras.layers.convolutional.Conv2D object at 0x7efec51cad30> False <keras.layers.convolutional.Conv2D object at 0x7efec5173400> False <keras.layers.convolutional.Conv2D object at 0x7efec5173c88> False <keras.layers.pooling.MaxPooling2D object at 0x7efec519ec50> False <keras.layers.convolutional.Conv2D object at 0x7efec519e2b0> True <keras.layers.convolutional.Conv2D object at 0x7efec514d780> True <keras.layers.convolutional.Conv2D object at 0x7efec5164a58> True <keras.layers.pooling.MaxPooling2D object at 0x7efec50f9630> True <keras.layers.convolutional.Conv2D object at 0x7efec50f9518> True <keras.layers.convolutional.Conv2D object at 0x7efec5126be0> True <keras.layers.convolutional.Conv2D object at 0x7efec50bee48> True <keras.layers.pooling.MaxPooling2D object at 0x7efec50d09e8> True
最初の畳み込み層3ブロックが訓練不可能になっており、下の方の畳み込み層2ブロックが訓練可能になっています。
最後に、グローバルアベレージプーリングと全結合層を1層追加してネットワークは完成です。
グローバルアベレージプーリングは、各特徴マップの平均を取ることでレイヤーの数を減らす効果があります。
さらに、過学習を防いでくれます。
x = vgg_conv.output x = GlobalAveragePooling2D()(x) x = Dense(2, activation="softmax")(x) model = Model(vgg_conv.input, x) model.compile(loss = "categorical_crossentropy", optimizer = optimizers.SGD(lr=0.0001, momentum=0.9), metrics=["accuracy"])
学習
学習時にジェネレータを使ってデータ拡張を行います。
train_datagen = ImageDataGenerator( rescale = 1./255, horizontal_flip = True, fill_mode = "nearest", zoom_range = 0.3, width_shift_range = 0.3, height_shift_range=0.3, rotation_range=30) model.fit_generator(train_datagen.flow(X_train, y_train, batch_size=32), steps_per_epoch=len(X_train) / 32, epochs=20)
テスト画像を使って分類結果を表示してみます。
print(classification_report(np.argmax(y_test,axis=1), np.argmax(model.predict(X_test/255),axis=1)))
結果は以下の通り。
precision recall f1-score support 0 0.89 0.95 0.92 162 1 0.93 0.84 0.88 124 accuracy 0.90 286 macro avg 0.91 0.89 0.90 286 weighted avg 0.90 0.90 0.90 286

Crackと判別して実際にCrackだった割合が84%、no Crackと判別して実際にno Crackだった割合は95%でした。
つまり、ヒビ割れしていないと予想した時の方が信頼性が高いと言うことですね。
テスト画像での精度は、89.5% ((84+95) / 2) でした。
なかなか良いのではないでしょうか?
参考
https://towardsdatascience.com/anomaly-detection-in-images-777534980aeb