LoginSignup
19
19

More than 3 years have passed since last update.

YOLOv4(Darknet)で異常検知モデル作成挑戦(GoogleColab)

Last updated at Posted at 2020-09-10

YOLOv4(Darknet) で異常部位の Object Detection

28467666-b7d4-4d18-a234-3270addb25bc-960x387r.png

実行環境

  • Google Colab(2020 年 9 月現在)

データセット

MVTec Anomaly Detection Dataset (MVTec AD) を使用します。
screw(ネジ)のデータを使用します。

  • train : good(異常なし良品)
  • test : 不良品
    • good
    • thread_top
    • thread_side
    • scratch_neck
    • scratch_head
    • manipulated_front

本来は良品のみで学習させるためのデータセットですが、test に用意されている不良品データを学習にも使用してモデルを作成したいと思います。
(製造ラインで不良品が滅多にでないことは重々承知。)

傷の種類は分けず全て anomaly としてラベル付けしました。

このような画像データです。(傷部分にマークつけてます。)

248d45c6-e50f-4d9e-afff-2e08893e7219-960x283r.png

0e3db855-f455-4e57-8fde-bdc699292a40-960x283r.png

1f0ef881-5795-416f-9634-469b9b6ce917-960x282r (1).png

d9852fe4-a1ef-405b-931e-aecb91b65802-960x283r.png

f047f553-ec09-4938-b737-5a632a0754b5-960x283r.png

0688c4e5-86e5-4d4d-83ea-ad4d6e20b979-960x283r.png

アノテーション

割愛します。
VOTT を使って PascalVOC 形式から YOLO 形式へ変換を行いました。
簡単に説明すると、xml 形式から txt 形式に変換します。
また、
[ object-class x_center y_center width height ]
の順番かつ、ボックス座標は 0 ~ 1 に正規化された値でなければいけません。
こんな感じ。
f988cc81-cd22-47eb-813c-a9e3adec9e60-960x174r.png

モデル学習準備

下記 2 つを参考にして進めました。
- https://github.com/pjreddie/darknet
- https://github.com/AlexeyAB/darknet

特にこれに忠実に実装しました。
How to train (to detect your custom objects)

darknetの取得
!git clone https://github.com/AlexeyAB/darknet
%cd darknet

重みの取得(YOLOv4)

ここからダウンロードして環境上にアップロードします。
How to train (to detect your custom objects)

raining Yolo v4 (and v3):

For training cfg/yolov4-custom.cfg download the pre-trained weights-file (162 MB): yolov4.conv.137 (Google drive mirror yolov4.conv.137 )

ここからオリジナルデータで学習させるための準備をしていきます。
custom というディレクトリで作業を進めることにしました。

customディレクトリを作成
!mkdir custom
%cd custom/
各データファイル作成
!mkdir data
!touch train.txt
!touch test.txt
!touch custom.data
!touch custom.names
!touch custom.cfg
!mkdir backup
  • data:画像データ + バウンディングボックスデータ
  • train.txt:学習用画像データパス
  • test.txt:テスト用画像データパス
  • custom.data:各データ参照
  • custom.names:class 名(今回は 'anomaly' のみ)
  • custom.cfg:モデル構造
  • backup:学習後の重みの保存場所

data フォルダに画像とアノテーション txt を配置します。

こんな感じ。

0138fc81-f82c-45ad-8da1-700455e7f400-960x984r.png

train.txt, test.txt に書き込み

# 画像パスの取得
from glob import glob
images = glob('custom/data/*.png')

# 学習用とテスト用に分割
n_train = int(len(images) * 0.8)
train = images[: n_train]
test = images[n_train :]

# train.txt, test.txt に書き込み
with open('custom/train.txt', 'w') as f:
    for line in train:
        f.write('%s\n' % line)

with open('custom/test.txt', 'w') as f:
    for line in test:
        f.write('%s\n' % line)

こんな感じになっているはず。(順不同で OK)
順番揃えたければ sorted(glob('')) で。

74db2d37-592f-4a09-a0c1-a3498d5b2b13-960x464r.png

custom.data 作成

  • classes:タスク(学習データ)に合わせて
  • その他はパスを指定
classes = 1
train  = /content/darknet/custom/train.txt
valid  = /content/darknet/custom/test.txt
names = /content/darknet/custom/custom.names
backup = /content/darknet/custom/backup/

custom.names

  • タスク(学習データ)に合わせて
anomaly

2f5dfcee-5bb4-4acf-bef8-9f55440daa69-960x382r.png

custom.cfg 作成

モデル構造のファイルです。
こちらは darknet/cfg/yolov4-custom.cfg をコピーしてきて必要箇所を書き換えましょう。

  • max_batches を学習させたいデータの class 数(物体数)× 2000 にします。 ただし、最低 6000 。
  • stepsmax_batches の 80%, 90%

(今回は 'anomaly' 1 クラスなので max_batches = 1* 2000 = 2000 となるが 6000、steps = 4800, 5400)

custom.cfg内
earning_rate=0.001
burn_in=1000
max_batches = 6000
policy=steps
steps=4800,5400
scales=.1,.1
  • タスクに合わせて[yolo], [convolutional] 変更 : 合計 6 箇所あります!!
  • classes:物体数
  • filters:(class + 5 ) × 3
[convolutional]
size=1
stride=1
pad=1
filters=18
activation=linear


[yolo]
mask = 0,1,2
anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401
classes=1
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
scale_x_y = 1.2
iou_thresh=0.213
cls_normalizer=1.0
iou_normalizer=0.07
iou_loss=ciou
nms_kind=greedynms
beta_nms=0.6
max_delta=5

Make

darknet/Makefile の書き換え

Makefileの下記部分書き換え
GPU=1
CUDNN=1
CUDNN_HALF=1
OPENCV=1
AVX=0
OPENMP=0
LIBSO=0
ZED_CAMERA=0
ZED_CAMERA_v2_8=0
Make
%cd /content/darknet
!make

# make 複数回してしまったらクリーンしてから !make
!make clean

学習

!./darknet detector train custom/custom.data custom/custom.cfg custom/yolov4.conv.137

このように backup フォルダに重みが保存されていきます。
デフォルトでは、1000 回ごとに重みが保存されます。(画像は 100 回ごとにコードを変更しています。)
学習後はこの重みを使って推論を行います。

12f4888f-36c4-4121-883e-16cb702a1095-960x519r.png

結果

loss が落ち着いたので 3500 エポックで終了しました。

テストデータに対して結果を確認します。(backup に保存されている _last.weights を使用します。)

!./darknet detector map custom/custom.data custom/custom.cfg custom/backup/custom_last.weights
| 24 |
| --- |
| detections_count = 23, unique_truth_count = 25 |
| class_id = 0, name = anomaly, ap = 79.28% | (TP = 16, FP = 0) |
| for conf_thresh = 0.25, precision = 1.00, recall = 0.64, F1-score = 0.78 |
| for conf_thresh = 0.25, TP = 16, FP = 0, FN = 9, average IoU = 76.83 % |
| IoU threshold = 50 %, used Area-Under-Curve for each unique Recall |
| mean average precision (mAP@0.50) = 0.792783, or 79.28 % |
| Total Detection Time: 2 Seconds |

テスト用の 24 枚に対して上記の結果です。まずまずの結果です。
2 秒で推論できているので、v4 速いのかな。

テスト 24 枚の結果

12b6601b-1e56-4ce3-af48-cb307baf8dd5-960x651r.png

60c5eb0a-b35d-409e-b2d4-6f5a1fea1714-960x653r.png

結果考察

検出したオブジェクトの信頼度は 0.99 付近で高い。
ネジの先端の曲がりなどは検出しにくかった。
そもそも先端の曲がりに、どうアノテーションすればよいのかわからない。
今回のデータ傷の場所や大きさ、形状が似たような物が多かったので
おそらく学習した 5 種類以外の傷に対しては検出できないはず。
ある意味過学習モデルな気がする。

19
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
19