🦊

[Python / YOLOv8] Webえんじにゃ、物体検知をする④学習モデルを自作する

2024/03/19に公開

Webえんじにゃです
機械学習は大学時代(n>1 年前🤔)にチョトヤッタくらいのレベルです
当時とはだいぶ進化している…ので1からやっていきます
今回はPythonとYOLOv8を使って機械学習して物体検知にとりくみます

長くなるので分割して記事にしていきます
この記事は4個目です

[Python / YOLOv8] Webえんじにゃ、物体検知をする①仮想環境構築まで
[Python / YOLOv8] Webえんじにゃ、物体検知をする②YOLOv8で簡単に遊ぶ
[Python / YOLOv8] Webえんじにゃ、物体検知をする③学習の準備
[Python / YOLOv8] Webえんじにゃ、物体検知をする④学習モデルを自作する

画像ができあがったので、遂に学習させていきます
YOLOv8 の Train モードで学習後、Val モードで検証していきます
どきどきだね…(゚Д゚;)

用意するもの

おさらいです。下記が必要です

  • アノテーションを施した画像フォルダ一式(images フォルダ)
  • アノテーションを施した画像に対応するタグフォルダ一式(labels フォルダ)
  • 検証用の画像いくつか(imagesに使ってない画像)(val フォルダとします)

これらを venv直下に配置します(お好みで)
今回は下記として説明してきます

venv
└── datasets
       ├── images
       ├── labels
       └── val

設定ファイルを作成

  1. venv\Lib\site-packages\ultralytics\cfg\datasets\の中にある、 coco8.yaml をコピーして、mydatasets.yaml ファイルを作成する(名前はお好み)

  2. mydatasets.yaml (coco8.yaml)の中身を編集

ここで設定するのは大きく分けて主に2点です

  • データのパスを指定する
  • Classesを指定する

データのパスを指定する

coco8.yaml では下記のようになっています

# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/coco8 # dataset root dir
train: images/train # train images (relative to 'path') 4 images
val: images/val # val images (relative to 'path') 4 images
test: # test images (optional)

◆中身

  • path: データの大元のパス(今回はdatasets
  • train: path以降の、学習用画像のフォルダ(今回はimages
  • val: path以降の、検証用画像のフォルダ(今回はval
  • test: path以降の、テスト用画像のフォルダ(オプション。今回は指定しない)

つまり、mydatasets.yaml では下記のように設定すればよきです

path: ../datasets
train: images
val: val

Classesを指定する

coco8.yaml では下記のようになっています

# Classes
names:
  0: person
  1: bicycle
  2: car
  3: motorcycle
~略~

◆中身
今回アノテーションしたタグの種類をここで設定しています
(今回はlabels/classes.text
これの順番と同じように設定すればよいです

例えば classes.text が下記のように出力されている場合

fox
dog
cat

mydatasets.yaml では下記のように設定!

names:
  0: fox
  1: dog
  2: cat

順番注意してね🫶適当な順番で設定すると、きつねさんなのに猫さんで検知されたりするよ(1敗)

不要な設定は削除

例えば下記のような設定項目については、ネットに転がってるデータセットとかを使う場合で、ダウンロードがまだの場合は設定すると実行するだけで勝手にDLがはじまって幸せになれる
今回は無論不要です

# Download script/URL (optional)
download: https://ultralytics.com/assets/coco8.zip

こういったいらない設定はすべて消し消ししましょうね

YOLOv8 の設定を作成する

  1. venv\Lib\site-packages\ultralytics\cfg\models\v8\の中にある、 yolov8.yaml をコピーして、myyolo.yaml ファイルを作成する(名前はお好み)

  2. クラス数の部分だけを修正する

nc: 80 # number of classes

この部分を、mydatasets.yamlで設定したクラス(タグの種類)の数に設定します
つまり、今回は「fox」「dog」「cat」の3種類なので

nc: 3

でOK

main.py で学習コードを作成する

サンプルコードを実行してみる

公式ドキュメントでは下記がTrainモードのサンプルコードとなっています

from ultralytics import YOLO

# Load a model
model = YOLO('yolov8n.yaml')  # build a new model from YAML
model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)
model = YOLO('yolov8n.yaml').load('yolov8n.pt')  # build from YAML and transfer weights

# Train the model
results = model.train(data='coco128.yaml', epochs=100, imgsz=640)

https://github.com/ultralytics/ultralytics/blob/main/docs/en/modes/train.md#usage-examples

これを実行するとなんか色々ターミナルに書かれる

長いので省略
engine\trainer: task=detect, mode=train, model=yolov8n.pt, data=mydatasets.yaml, epochs=100, time=None, patience=100, batch=16, imgsz=640, save=True, save_period=-1, cache=False, device=None, workers=8, project=None, name=train4, exist_ok=False, pretrained=True, optimizer=auto, verbose=True, seed=0, deterministic=True, single_cls=False, rect=False, cos_lr=False, close_mosaic=10, resume=False, amp=True, fraction=1.0, profile=False, freeze=None, multi_scale=False, overlap_mask=True, mask_ratio=4, dropout=0.0, val=True, split=val, save_json=False, save_hybrid=False, conf=None, iou=0.7, max_det=300, half=False, dnn=False, plots=True, source=None, vid_stride=1, stream_buffer=False, visualize=False, augment=False, agnostic_nms=False, classes=None, retina_masks=False, embed=None, show=False, save_frames=False, save_txt=False, save_conf=False, save_crop=False, show_labels=True, show_conf=True, show_boxes=True, line_width=None, format=torchscript, keras=False, optimize=False, int8=False, dynamic=False, simplify=False, opset=None, workspace=4, nms=False, lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=7.5, cls=0.5, dfl=1.5, pose=12.0, kobj=1.0, label_smoothing=0.0, nbs=64, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0, auto_augment=randaugment, erasing=0.4, crop_fraction=1.0, cfg=None, tracker=botsort.yaml, save_dir=runs\detect\train4
Overriding model.yaml nc=80 with nc=3

ほんで読み込みが始まります

Starting training for 100 epochs...

      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
      1/100         0G      1.638      3.578       2.22         19        640: 100%|██████████| 1/1 [00:04<00:00,  4.51s/it]
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 1/1 [00:00<00:00,  1.00it/s]
                   all          5          0          0          0          0          0
~略~

そのまま放置しておくと、.runs/detect/trainフォルダが生成されます。機械学習の結果やら色々でてきてすごい

結果はあとで見るので、とりあえずコードの中身を確認していきましょう

Load a model

model = YOLO('yolov8n.yaml')
YOLOv8 の設定を読み込みます
つまり今回はmyyolo.yamlをここで読み込むようにします

model = YOLO('yolov8n.pt')
すでに学習済みの .pt ファイルを読み込みます
今回はデフォルトの学習ファイルを使用するのでそのままにします

model = YOLO('yolov8n.yaml').load('yolov8n.pt')
YOLOv8をロードします
上記に則り今回は YOLO('myyolo.yaml').load('yolov8n.pt')とすればOK

Train the model

**results = model.train(data='coco128.yaml', epochs=100, imgsz=640)
**

train モードでデータを読み込む部分です
Predict モードを触ってみたときと同じく、train モードでも色々引数を設定できます

https://docs.ultralytics.com/ja/usage/cfg/#train-settings

サンプルコードの場合は
①データの設定ファイルを読み込み(data='coco128.yaml'
②学習の精度を設定(epochs=100
③ターゲットの画像サイズを設定(imgsz=640
というかんじ

今回はとりあえず model.train(data='mydatasets.yaml', epochs=30) とでもしておこうかな

てなわけで main.py はこうなった

from ultralytics import YOLO

# Load a model
model = YOLO('myyolo.yaml')  # build a new model from YAML
model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)
YOLO('myyolo.yaml').load('yolov8n.pt')

# Train the model
results = model.train(data='mydatasets.yaml', epochs=30)

実行してみよう

実行して数分(数時間?🥺)待ち、無事に完了したことを確認しましょう
全部完了すると結果を出してくれます(下記例は100エポックですが)

100 epochs completed in 0.174 hours.
Optimizer stripped from runs\detect\train4\weights\last.pt, 6.3MB
Optimizer stripped from runs\detect\train4\weights\best.pt, 6.3MB

Validating runs\detect\train4\weights\best.pt...
Ultralytics YOLOv8.1.27 🚀 Python-3.11.0 torch-2.2.1+cpu CPU (12th Gen Intel Core(TM) i5-1235U)
Model summary (fused): 168 layers, 3006233 parameters, 0 gradients, 8.1 GFLOPs
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 1/1 [00:00<00:00,  1.09it/s]
                   all          5          0          0          0          0          0
WARNING ⚠️ no labels found in detect set, can not compute metrics without labels
Speed: 20.9ms preprocess, 122.1ms inference, 0.0ms loss, 27.0ms postprocess per image
Results saved to runs\detect\train4

何分かかったよーとか、
weights フォルダの中に last.pt、best.pt を出力したよーとか、
結果は runs\detect\train4 に出したよーとか いろいろ書いてありますね🤔

というわけで、結果何が出力されたのか見てみましょう

結果何が生み出されたのか

last.pt / best.pt

これ、誰?と思いますよね??私は思いました
.pt ファイル……🤔?って、どこかで見ませんでしたか?('ω')

そう、学習済みモデルのファイル ですね
main.py にて YOLO('yolov8n.pt') で指定したと思います
これこれ

つまり、俺流の学習モデルがこの子たち、ということですね。わが子ですよ。無事出産できました
では、これらの違いは何でしょう?

公式を引用してみると

https://docs.ultralytics.com/ja/guides/hyperparameter-tuning/#weights

weights/
This directory contains the saved PyTorch models for the last and the best
iterations during the hyperparameter tuning process.

last.pt: The last.pt are the weights from the last epoch of training.
best.pt: The best.pt weights for the iteration that achieved the best fitness score.

つまりどういうことだってばよ?

last.pt

学習の最後に保存されたモデル(の重み)のこと
例えば追加で学習したい場合など、学習を継続する場合はこっちを使用するとよいよ

best.pt

学習中に最も性能が高かったモデル(の重み)のこと
つまり、今回の学習では一番精度がよかった部分を保存してくれています
実際に predict モードで自作モデルとして使うのは best をよく使うよ

その他

もう少し詳しく結果を見たい場合はその他のファイルもみていくといいでしょう
train フォルダ直下に様々な曲線ができてると思います

例えばこんなやつとか(P_curve.png)

これは精度曲線で、閾値が変化したときに精度がどのくらい変化するかを示したものです
こまかく精度とか比較してゴリゴリ学習をさせていきたい場合は参考にするのかな?

ビジュアル出力、というやーつらしいです
https://docs.ultralytics.com/ja/guides/yolo-performance-metrics/#speed-metrics

というわけで自作モデルで predict

で触ったサンプルコードで、モデルの読み込み先を変更してみます

from ultralytics import YOLO

if __name__ == '__main__':
    # Load a model
    model = YOLO('runs/detect/train/weights/best.pt')

    # Predict the model
    model.predict('sample.jpg', save=True, conf=0.5)

これで、イイカンジの結果が得られれば学習成功!わーいだドン!

今回はここまで

業務に大体おいついたので次回は未定です

Discussion