【YOLOv8で学習→物体検出】楽に学習データを用意して好きなものを検出してみよう


# はじめに

学習済みのモデルを使ってサクッと物体検出をするということと、自分で任意の内容を学習させて物体検出をするということには心理的にまあまあなハードルがあると思っています。

学習データの準備が面倒そう、学習させること自体もめんどそうだなと思います。

自分が触っていた物体検出の仕組みが用意している学習済みモデルで検出できないものを検出しないといけないことになり、重い腰を上げて一番楽そうな方法を模索したのでその結果を記事にまとめました。

学習させないといけなくなったけど、楽したいぜ、という人には意味のある内容かと思います。詳しい人は読まなくていい内容です。

## 使用する物体検出のアルゴリズム、モデル

日本語のドキュメントがあったりPyTorchでサクッと動かせたりと準備が楽そうだったので[YOLOv8](https://docs.ultralytics.com/)を使うことにしました。（実際楽でした）

## 手順
[クイックスタート](https://docs.ultralytics.com/quickstart/#install-ultralytics)に従い準備を進めていきます。と言ってもpip一回ですが。

### 1. パッケージのインストール

`Python>=3.8,PyTorch>=1.8.`である必要があります。
    
```
# Install the ultralytics package from PyPI
pip install ultralytics
```
> 環境準備が面倒という人は[Google Colab](https://colab.research.google.com/github/ultralytics/ultralytics/blob/main/examples/tutorial.ipynb)からどぞ。 

> 余談ですがYOLOはバージョンごとに作者がバラバラなので全部YOLOって言っていいのかみたいな議論もあるのですが、v8についてはUltralyticsという会社がリリースしたのでパッケージ名もこれになってます。


### 2. 早速使ってみる
とりあえず動くか試してみましょう。
```
yolo predict model=yolov8n.pt source='https://ultralytics.com/images/zidane.jpg' imgsz=320
```
前述のコマンドを実行するとこんな画像が保存されます。ちゃんと動きました。
![zidane.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556201/12db1241-2870-76d5-63ef-c53672d13cf7.jpeg)

ちなみにこちらが学習済みの内容（80個のオブジェクトがあります）です。検出したいものがこの中にあるなら追加で学習させる作業はやらなくてOKです。

<details><summary>学習済みオブジェクト一覧を開く</summary><div>

```
  0: person
  1: bicycle
  2: car
  3: motorcycle
  4: airplane
  5: bus
  6: train
  7: truck
  8: boat
  9: traffic light
  10: fire hydrant
  11: stop sign
  12: parking meter
  13: bench
  14: bird
  15: cat
  16: dog
  17: horse
  18: sheep
  19: cow
  20: elephant
  21: bear
  22: zebra
  23: giraffe
  24: backpack
  25: umbrella
  26: handbag
  27: tie
  28: suitcase
  29: frisbee
  30: skis
  31: snowboard
  32: sports ball
  33: kite
  34: baseball bat
  35: baseball glove
  36: skateboard
  37: surfboard
  38: tennis racket
  39: bottle
  40: wine glass
  41: cup
  42: fork
  43: knife
  44: spoon
  45: bowl
  46: banana
  47: apple
  48: sandwich
  49: orange
  50: broccoli
  51: carrot
  52: hot dog
  53: pizza
  54: donut
  55: cake
  56: chair
  57: couch
  58: potted plant
  59: bed
  60: dining table
  61: toilet
  62: tv
  63: laptop
  64: mouse
  65: remote
  66: keyboard
  67: cell phone
  68: microwave
  69: oven
  70: toaster
  71: sink
  72: refrigerator
  73: book
  74: clock
  75: vase
  76: scissors
  77: teddy bear
  78: hair drier
  79: toothbrush
```
</div></details>

### 3. 学習させる
今回諸事情によりバーコードを検出させる必要がありました。これは事前学習されていませんので自分でどうにかする必要があります。この記事の説明はバーコードで進みますがこちらを自身の検出したいものに置き換えて進めてください。

ちなみに、学習に関するドキュメントはこちら→[Model Training with Ultralytics YOLO](https://docs.ultralytics.com/modes/train/)

#### 3.1. 学習方法の確認
ドキュメントを見るとわかりますが、1つのCPU or GPUを使うのか、複数GPUを使うのかなど、どんなハードウェアを使うかで微妙にやり方が変わります。私はM1のMacbookを使っているのでその例を書きます。

```python
from ultralytics import YOLO

# ベースとするモデル
model = YOLO('yolov8n.pt')

# M1 macのGPUを使ってモデルを学習
results = model.train(
    data='datasets/barcode_detection_one/data.yaml', 
    epochs=3, 
    imgsz=640, 
    device='mps'
)
```
trainの引数を説明します。

`data`: これは学習に使用するデータセットの設定ファイルへのパスです。あとで出てきます。
`epochs`: エポック数です。要は学習を何回繰り返すか指定します。
`imgsz`: 入力画像のサイズの指定です。640x640ピクセルの画像サイズを使うということです。
`device`: 学習に使用するデバイスの指定です。`mps`、つまりAppleのMetal Performance Shaderフレームワークを使うぞ、という指定をしています。M1使うぞーということです。

このプログラムを動かせば学習開始できるわけですがその前に学習用のデータを準備しないとです。

#### 3.2　学習データの調達
通常学習データを準備するとなると、３種類の画像のセットを用意する必要があるかと思います。
※割合はイメージです

1. `Train（学習用データセット）`:
全データセットの大部分を占める（70-80%程度）。モデルはこの画像群からパターンを学習する。

2. `Valid（検証用データセット）`:
全体の一部を占める（10-20%程度）。トレーニング中にモデルの性能を評価するための画像群、モデルのトレーニングが適切に進行してるか確認する。

3. `Test（テスト用データセット）`:
全体の一部を占める（10-20%程度）。トレーニング中には使用されず、モデルの最終評価に使用する。未知のデータに対してうまく動作するか確認する。

これらを何百枚、何千枚と自分で用意してひたすらラベリングを…というのは、ちょっと大変なので公開されているものを使うことにしました。

[roboFlow](https://app.roboflow.com/)というモデル構築のプラットフォームがあるのですが、その中に[Roboflow Universe](https://universe.roboflow.com/)という、オープンソースのデータセットを公開してくれている大変便利なページがあります。

https://universe.roboflow.com/

ここで検出したいものを探してみてください。

私はバーコードを検出する必要があるのでバーコードのデータセットを探してみました。

![スクリーンショット 2023-12-08 11.19.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556201/fe40b69a-1c6b-6a15-e5d5-af2967bd3101.png)
便利なのはフォーマットも選べることですね。今回はYOLOv8ですがそれ以外にも色々な形式を選択できます。（ダウンロードにはアカウント登録が必要です）

ちなみに`Try Pre-Trained Model`という選択肢もあり…
![スクリーンショット 2023-12-08 11.22.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556201/929a3153-6e9c-0be2-b558-8c9c0514bf9e.png)

↓こんな感じでソースコードのサンプルもあり、API経由で学習済みのモデルをすぐ使うことができます。使いたいだけで学習方法興味ないです、という人はこの記事はここまでで良いと思います。笑
```python
from roboflow import Roboflow
rf = Roboflow(api_key="API_KEY")
project = rf.workspace().project("barcode_detection_one")
model = project.version(1).model

# infer on a local image
print(model.predict("your_image.jpg", confidence=40, overlap=30).json())

# visualize your prediction
# model.predict("your_image.jpg", confidence=40, overlap=30).save("prediction.jpg")

# infer on an image hosted elsewhere
# print(model.predict("URL_OF_YOUR_IMAGE", hosted=True, confidence=40, overlap=30).json())
```

学習させてみるぞ、という方はYOLOv8のフォーマットを選んでダウンロードしましょう。
![スクリーンショット 2023-12-08 11.26.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556201/e8782ebd-dcd9-7bc4-e95f-75fee349cf0a.png)

ダウンロードしてみた中身です。data.yamlが先ほどちょっと出てきたデータセットの設定ファイルです。
![スクリーンショット 2023-12-08 11.27.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556201/39d0c57a-04ed-0dca-48ae-be33cb3a6530.png)
`test,train,valid`それぞれのフォルダに画像ファイルとラベルのファイル（矩形領域を表したもの）が格納されてます。

#### 3.3　学習の実行
データセットが調達できたとので学習を実行してみましょう。
`data='datasets/barcode_detection_one/data.yaml', `の部分はご自身のdata.yamlのパスに書き換えて実行してください。

```python
from ultralytics import YOLO

# ベースとするモデル
model = YOLO('yolov8n.pt')

# M1 macのGPUを使ってモデルを学習
results = model.train(
    data='datasets/barcode_detection_one/data.yaml', 
    epochs=3, 
    imgsz=640, 
    device='mps'
)
```

学習が終わると、`runs/runs/detect/train/weights/`というフォルダに`last.pt`と`best.pt`という二つのファイルが生成されます。これらが学習を終えたモデルになります。
last.ptは学習の最後に保存されたモデルの重み、best.ptは学習中、最もパフォーマンスが良かった重みのファイルです。

### 4. 動作確認
早速動かしてみます！
```python
from ultralytics import YOLO

model = YOLO('runs/detect/train/weights/last.pt')

# Predict the model
model.predict('test.png', save=True, conf=0.1)
```

机の上にあった本の写真で推論させてみたところ無事バーコードが検出されました。
![スクリーンショット 2023-12-08 11.47.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556201/22b47381-8981-c04a-f696-db77c24988be.png)


# まとめ
データセットの準備が大変そうでとっつきにくかったのですが、公開されているデータセットが世の中にはroboFlowに限らず色々とあるためそこまでハードルを感じる必要もないなと思いました。~~そもそも自分で学習させなくても、APIが結構ありますが。~~