【Python】最新物体検知AI YOLOv8のPythonライブラリ ultralytics がすごすぎる！

 **ViT(Vision Transformer)** を除くEnd-to-Endの物体検出AIの中で、COCOのベンチマークでトップレベルのモデル(***YOLO, SSD, RetinaNet***)のうち、今回は、**YOLOの最新モデルv8**の簡単な実装方法を紹介する。

[Papers with Code](https://paperswithcode.com/task/object-detection)の物体検出AIベンチマーク
※一位はもちろん、Vision TransfomerのDETRの進化版 "Co-DETR"

<img width=10%><img width=80% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/72ca964f-8bba-ce68-c00d-664727b77cad.gif">

　2022年8月拡散モデルを利用した**Stable Diffusion**が公開され、2022年11月Transformerを利用した**ChatGPT**が公開され、画像生成・文章生成AIが業界を席捲している。生成AI以外にも人間の五感を担うような優秀なAIは沢山あり、主なところでは**画像認識AI(目)**、**音声認識AI(耳)** がある。※嗅覚や触覚認識など他に優れた有名なAIがあれば、コメントお願いします。

その内、今回は画像認識AIの中で、リアルタイムで高性能なモデル**YOLOv8**について紹介する。

https://ultralytics.com/yolov8

![AI五感.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/bc644234-c8d8-ce0f-7062-1b1bfcf13d35.png)

## Ultralytics YOLO
YOLOは物体検出AIの代表的なモデルであり、そのPython SDK「**ultralytics**」が**2023年1月**にVersion8.0.0としてリリースされ、yoloモデルを使用した物体検出AIの開発が非常に容易になった。

### 利用可能なAIタスク
物体検出以外にもセグメンテーション(meta社のSAMも利用可能！)や姿勢推定も可能である。
 - **物体の検出(Detect)**：
   画像やビデオ内で物体の存在を検出するタスク。
 - **物体のセグメンテーション(Segmentation)**：
   画像やビデオ内の各ピクセルを物体クラスに割り当てるタスク。
 - **物体の分類(Classification)**：
   画像やビデオ内の物体を事前に定義されたカテゴリに分類するタスク。
 - **姿勢推定(Pose)**：
   画像やビデオ内の物体の位置、角度、方向などの姿勢情報を推定するタスク。

![available_task.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/d6e2fa4b-899f-575d-7fbe-0faf03c79090.png)

それぞれ利用可能なモデルは以下である
 - 物体の検出(Detect)
![detect_models.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/dd05f471-a902-291f-0c37-edf14ee9e918.png)
 - 物体のセグメンテーション(Segmentation)
![segment_models.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/abbe1d21-3aa7-73c9-4164-b5a3d75d0e27.png)
 - 物体の分類(Classification)
![classification_models.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/d3797a64-aedb-3e7e-e6fc-314c0c586ef7.png)
 - 姿勢推定(Pose)
![pose_models.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/26492f43-1394-4172-4fcb-6b90c8cb7825.png)

## QuickStart
ultralyticsライブラリのインストールとPyTorchのインストールをすれば可能(簡単)

### インストール
ultralyticsライブラリのインストール
```
pip3 install ultralytics
```

Pytorchのインストール ※CPU利用版
```
pip3 install torch torchvision torchaudio
```

https://pytorch.org/get-started/locally/

![PyTorch_CPU.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/ba9536bb-d187-728f-ec1e-8a48357b06fb.png)

### 実行
正常にインストール出来たら、下記を実行する。
```Python:Detect
from ultralytics import YOLO

if __name__ == '__main__':
    # Load a model
    model = YOLO('yolov8n.pt')

    # Predict the model
    model.predict('https://ultralytics.com/images/bus.jpg', save=True, conf=0.5)
```
![bus.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/ba8b99ae-20af-1fe8-c09f-c4c483499c25.jpeg)

```Python:Segment
from ultralytics import YOLO

if __name__ == '__main__':
    # Load a model
    model = YOLO("yolov8x-seg.pt")

    # Predict the model
    model.predict('https://ultralytics.com/images/bus.jpg', save=True, conf=0.5, boxes=False)
```

![bus.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483556/1903477a-7d8d-6db5-f091-4dad8f31e43a.jpeg)

上記の通り、非常に簡単に推論を実装できる。ただ、これは学習済モデルで約80個しか検出できない。
独自ドメインのAIにするためには、下記で説明するように学習する必要がある。(学習の実装も簡単)

## アノテーション画像の作成(Labelme版)
https://github.com/wkentaro/labelme

1. pip3 install labelmeでライブラリインストール
2. labelmeで実行
3. 画像のあるフォルダを開く
4. 右クリックでCreate Rectangleを押す
5. 左クリックで対象の個所を囲む
6. Next imageで次の画像をアノテーションする
7. Jsonファイルとして保存されていく

Labelmeで保存したフォルダで、labelme2yoloライブラリのコードを実行する。
すると、下記のようにyolo学習用フォルダとして分けられる

https://github.com/GreatV/labelme2yolo

```
pip install labelme2yolo
labelme2yolo --json_dir .\labelme_dir\ --val_size 0.15 --test_size 0.15 --output_format bbox

YOLODataset
├── images
│      ├── test
│      ├── train
│      └── val
├── labels
│      ├── test
│      ├── train
│      └── val
└── dataset.yaml
```

これをyolov8の学習用データフォルダの以下の構成に変更する

```
datasets
├── test
│      ├── images
│      └── labels
├── train
│      ├── images
│      └── labels
├── valid
│      ├── images
│      └── labels
└── data.yaml
```

また、data.tamlの中身を以下のように変更する
```yaml
train: ../train/images
val: ../valid/images
test: ../test/images

nc: 1
names: ['LisencePlate']
```

## アノテーション画像の作成(roboflow版)
非常に簡単にyolov8モデルの学習に対応したデータを作成・学習・利用できるツールとして、roboflowというものがある。3か月間の無料トライアル期間があるので、個人利用ならそちらで十分利用できる。

https://www.systems.nakashima.co.jp/rf/roboflow/

### プロジェクト作成
1. https://app.roboflow.com/ を開く
2. アカウント作成
3. Create New Projectを押す
4. Project Typeを「Object Detection (Bounding Box)」
5. What Are You Detecting?にラベルを並べる
6. Project Nameにプロジェクトの名前を任意に決める
7. Licenseは商用利用不可のBY-NC-SA 4.0を選択する
 ※それ以外の選択肢は公開して商用利用可

### 画像アップロード
1. Drag and drop imagesへ画像をドラッグする
2. 左上のSave and Continueを押す
3. 次に誰にアノテーションをAssinするか決める
右側でユーザーを指定して、右下のAssin Imagesを押す
4. 右上のStart Annotatingを押す
5. Ctrlを押しながら、バウンディングボックスを当てはめていく
6. 左上の戻るを押す
7. 右上のAdd *** images to Datasetを押す
8. Add Imagesを押す
8. 右上のGenerate New Versionを押す※なければ一回他の左タブを開く
9. PreProcessningでAuto-Orientとresize640×640を選ぶ
10. AugmentationでCrop、Rotation15°、Shear15°、Saturation25%を選ぶ
11. Generateを押す
12. Export Datasetを押す
13. FormatでYOLOv8を選ぶ

## 学習

https://docs.ultralytics.com/modes/train/#arguments

```Python
"""
@software{yolov8_ultralytics,
  author       = {Glenn Jocher and Ayush Chaurasia and Jing Qiu},
  title        = {YOLO by Ultralytics},
  version      = {8.0.0},
  year         = {2023},
  url          = {https://github.com/ultralytics/ultralytics},
  orcid        = {0000-0001-5950-6979, 0000-0002-7603-6750, 0000-0003-3783-7069},
  license      = {AGPL-3.0}
}
"""
from ultralytics import YOLO

if __name__ == '__main__':
    # Load a model
    model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)

    # Train the model
    results = model.train(data=r"path/to/data.yaml", epochs=100, imgsz=640, batch=12, device=0)
    
    # Export the model
    model.export(format="torchscript")
```

## 検証

https://docs.ultralytics.com/modes/val/

```Python

from ultralytics import YOLO

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

    # Validate the model
    metrics = model.val()  # no arguments needed, dataset and settings remembered
    metrics.box.map    # map50-95
    metrics.box.map50  # map50
    metrics.box.map75  # map75
    metrics.box.maps   # a list contains map50-95 of each category
    print(metrics)

    # Predict the model
    model.predict('https://ultralytics.com/images/bus.jpg', save=True, conf=0.5)
```

## 推論

https://docs.ultralytics.com/modes/predict/

```Python
"""
@software{yolov8_ultralytics,
  author       = {Glenn Jocher and Ayush Chaurasia and Jing Qiu},
  title        = {YOLO by Ultralytics},
  version      = {8.0.0},
  year         = {2023},
  url          = {https://github.com/ultralytics/ultralytics},
  orcid        = {0000-0001-5950-6979, 0000-0002-7603-6750, 0000-0003-3783-7069},
  license      = {AGPL-3.0}
}
"""

import os
import sys
import random
import time
import datetime
import glob
import re
import shutil
import cv2
import numpy as np
import torch

from ultralytics import YOLO

# Load a model 
# detect: yolov8n.pt yolov8s.pt yolov8m.pt yolov8l.pt yolov8x.pt
# segment: yolov8s-seg.pt yolov8m-seg.pt yolov8l-seg.pt yolov8x-seg.pt
# pose: yolov8s-pose.pt yolov8m-pose.pt yolov8l-pose.pt yolov8x-pose.pt yolov8x-pose-p6
# classification: yolov8s-cls.pt yolov8m-cls.pt yolov8l-cls.pt yolov8x-cls.pt
model = YOLO(r'runs\detect\train\weights\best.pt')


print('モデルの概要', model.info())
# モデルの構造の保存
with open('./model_structure.txt', 'w') as f:
    f.write(str(model.model))
print('モデルの行うタスク', model.task) # detect
# モデルのcheckpoint objectの保存
with open('./model_checkpoint.txt', 'w') as f:
    f.write(str(model.ckpt))
print('モデルの*.yaml file', model.cfg) # None
print('モデルの*.pt file', model.ckpt_path) # yolov8x.pt
print('モデルの詳細', model.overrides) # {'task': 'detect', 'data': 'coco.yaml', 'imgsz': 640, 'single_cls': False, 'model': 'yolov8x.pt'}

# Display preds. Accepts all YOLO predict arguments
video_path = "sample.mp4"
#ここから持ってきても良い
#https://whitewell.sakura.ne.jp/OpenCV/py_tutorials/py_gui/py_video_display/vtest.avi
cap = cv2.VideoCapture(video_path)
fps = int(cap.get(cv2.CAP_PROP_FPS))
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
brightness = int(cap.get(cv2.CAP_PROP_BRIGHTNESS))
contrast = int(cap.get(cv2.CAP_PROP_CONTRAST))
auto_exposure = int(cap.get(cv2.CAP_PROP_AUTO_EXPOSURE))
auto_focus = int(cap.get(cv2.CAP_PROP_AUTOFOCUS))
auto_WB = int(cap.get(cv2.CAP_PROP_AUTO_WB))
fourcc = int(cap.get(cv2.CAP_PROP_FOURCC))

# Display size scale
scale = 0.3

# Loop through the video frames
while cap.isOpened():
    # Read a frame from the video
    success, frame = cap.read()
    if success:
        # Run YOLOv8 inference on the frame
        results = model.track(source=frame, show=False, save=True, device=0, conf=0.5, save_txt=True, save_conf=True, tracker="bytetrack.yaml")

        # get predict result
        for result in results:
            boxes = result.boxes  # Boxes object for bbox outputs
            masks = result.masks  # Masks object for segmentation masks outputs
            names = result.names
            orig_img = result.orig_img
            orig_shape = result.orig_shape
            speed = result.speed

        # Display the annotated frame
        if len(results[0]) > 0:
            results_frame = results[0].plot(line_width=5, font_size=1)
            results_frame = cv2.resize(results_frame , (int(w*scale), int(h*scale)))
            cv2.imshow("YOLOv8 Inference", results_frame)
        else:
            frame = cv2.resize(frame , (int(w*scale), int(h*scale)))
            cv2.imshow("YOLOv8 Inference", frame)

        # Break the loop if 'q' is pressed
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
    else:
        # Break the loop if the end of the video is reached
        break

# Release the video capture object and close the display window
cap.release()
cv2.destroyAllWindows()
```

学習済モデルで認識可能なラベルは以下に記載されている。

https://github.com/ultralytics/ultralytics/blob/main/ultralytics/datasets/coco128.yaml

## ライセンスについて

https://ultralytics.com/license

Ultralyticsは、デフォルトで**AGPL-3.0**ライセンスの下ですべてのユースケースに対してオープンソースソフトウェアとして無料で提供している。AGPL-3.0ライセンスは、コピーレフトを強制するライセンスであり、商用目的で開発したソフトウェアはソースコードを公開する必要がある。 これは、コピーライト(著作権)の反対の考えのもので、二次開発品にオープンソースの性質を引き継がせる目的がある。プロプライエタリとして利用したいような、商用製品開発の組織向けにエンタープライズライセンスも提供している。会社でUltralyticsソフトウェアとAIモデルを商用製品やアプリケーションに埋め込みたい場合で、かつAGPL-3.0のオープンソースの要件を満たしたくない場合、年間費用を払って契約する必要がある。

## 参考文献

https://blog.roboflow.com/how-to-train-yolov8-on-a-custom-dataset/

他のエンジニアが作ったサンプルツール

https://github.com/ultralytics/ultralytics/tree/main/examples

ライブラリのソースコード

https://github.com/ultralytics/ultralytics/tree/main/ultralytics