さくらインターネットの「高火力 DOK」上でYOLOを学習させてみた

# はじめに
株式会社晴工雨読の日高と申します。
今回はTechブログ第1弾として、先日公開されたさくらインターネットの「高火力 DOK」にて弊社プロダクト「Smart Searcher」に使用している真鯛の成長度判別AIモデルの学習を行ってみました。
晴工雨読の概要説明はこちらからご覧ください。

https://seikoudoku.co.jp/


# さくらインターネットの「高火力 DOK」とは

https://www.sakura.ad.jp/koukaryoku-dok/

さくらインターネットが提供するコンテナサービスです。
実行時間のみ課金されるため、スポット利用がしやすい料金体系になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865255/c39b2989-3516-d83a-f358-d1b72c0d298c.png)

非常に安価でハイエンドGPUを利用でき、今回はV100を使用しています。
実行時間を換算すると、200円ほどで学習することができました。
(今回は高火力DOKリリースキャンペーンとして、サービス料が無料になっております。詳細は[こちら](https://www.sakura.ad.jp/koukaryoku-dok/
)のURLから確認できますが、申し込み期限は2024年9月20日までなので、皆様お気をつけください。)

追記：2024年8月27日に[H100プランが公開されたました](https://www.sakura.ad.jp/corporate/information/newsreleases/2024/08/27/1968216352/
)。1時間あたり1,008円でH100を動かすことができるそうです。


# 使用する物体検出モデル
背景の誤検出を抑える目的でYOLOを採用しました。
その中でもDockerHUBに公開されている[UltralyticsYOLOv8](https://hub.docker.com/r/ultralytics/ultralytics/tags)を元に、私が用意した教師データやDockerfileをまとめてビルドし自分のDockerHUBに公開、高火力DOKから実行しています。
2024年8月現在、高火力DOKは外部とのhttp通信が実装されていないためこういった形になっていますが、今後のアップデート次第では教師データをまとめてビルドする必要が無くなるのではないでしょうか。
しかし、YOLOはサイズの小さな物体の検出や重なっている物体の検出は苦手なので、この記事を書き終えたら別のモデルでも検証するつもりです。(余裕があればこちらも記事にまとめます)
なお今回使用した環境について詳細は後述しますが、実質的にはlinuxです。

# 手順
## 1. DockerHUBに公開するイメージのビルド 
### 1.1. YOLOv8のインストール
Pythonは3.8以上3.10以下、PyTorchは1.8以上が必要です。
```console:console
pip install ultralytics
git clone https://github.com/ultralytics/ultralytics.git
```
### 1.2. 自分の学習データを配置する
`yourpath/ultralytics/ultralytics/data/`に自分が用意したデータセットを配置します。
ディレクトリ構造のイメージは以下のとおりです。

```
yourpath
┗━ ultralytics
  ┗━ ultralytics
     ┗━ data
        ┣━ custom.yaml
        ┗━ custom_dataset
           ┣━ images
           ┃  ┣━ train
           ┃  ┃  ┣━ train_001.jpg
           ┃  ┃  ┣━ train_002.jpg
           ┃  ┃        ︙
           ┃  ┗━ val
           ┃     ┣━ valid_001.jpg
           ┃     ┣━ valid_002.jpg
           ┃           ︙
           ┗━ labels
              ┣━ train
              ┃  ┣━ train_001.txt
              ┃  ┣━ train_002.txt
              ┃        ︙
              ┗━ val
                 ┣━ valid_001.txt
                 ┣━ valid_002.txt
                       ︙
```
custom.yamlの中には、データセットの構造と判別するクラスの数と名前を記述してください。
```yaml:custom.yaml
train: /yourpath/ultralytics/ultralytics/data/custom_dataset/images/train # train images
val: /yourpath/ultralytics/ultralytics/data/custom_dataset/images/val # val images

# Classes
nc: 2
names: ['Defect', 'Flawless']
```
### 1.3. ビルド
以下のDockerfileを作成し、`/yourpath/ultralytics/`に配置してください。
```dockerfile:dockerfile
# Ultralytics YOLO 🚀, AGPL-3.0 license
# Builds ultralytics/ultralytics:latest image on DockerHub https://hub.docker.com/r/ultralytics/ultralytics
# Image is CUDA-optimized for YOLOv8 single/multi-GPU training and inference

FROM pytorch/pytorch:2.3.1-cuda12.1-cudnn8-runtime

# 環境変数を設定する(適宜自分の環境に合わせてください)
ENV APP_HOME /home/yourname/ultralytics
# DDPエラー "MKL_THREADING_LAYER=INTELはlibgomp.so.1ライブラリと互換性がありません "の回避https://github.com/pytorch/pytorch/issues/37377
ENV MKL_THREADING_LAYER=GNU

# ユーザー設定ファイルへのダウンロード
ADD https://github.com/ultralytics/assets/releases/download/v0.0.0/Arial.ttf \
    https://github.com/ultralytics/assets/releases/download/v0.0.0/Arial.Unicode.ttf \
    /root/.config/Ultralytics/

#Linux パッケージのインストール
# 'tflite_support' と 'lap' パッケージをビルドするために # g++ が必要で、'tflite_support' パッケージには libusb-1.0-0 が必要です。
# libqxcb が QT ベースのウィンドウを視覚化するために必要な libsm6; docker でテストするために 'QT_DEBUG_PLUGINS=1' を設定する。
RUN apt update \
    && apt install --no-install-recommends -y gcc git zip unzip curl htop libgl1 libglib2.0-0 libpython3-dev gnupg g++ libusb-1.0-0 libsm6

# セキュリティアップデート
# https://security.snyk.io/vuln/SNYK-UBUNTU1804-OPENSSL-3314796
RUN apt upgrade --no-install-recommends -y openssl tar

# 作業フォルダの設定
WORKDIR $APP_HOME

# 自分で作成したデータをコピー
COPY . $APP_HOME

# pip パッケージのインストール
RUN python3 -m pip install --upgrade pip wheel
RUN pip install --no-cache-dir -e .

# AutoInstallパッケージへのエクスポートを実行
# エッジTPUエクスポートは初回に失敗するので、ここで2回実行する
RUN yolo export model=tmp/yolov8n.pt format=edgetpu imgsz=32 || yolo export model=tmp/yolov8n.pt format=edgetpu imgsz=32
RUN yolo export model=tmp/yolov8n.pt format=ncnn imgsz=32
# <= Python 3.10 が必要、paddlepaddle==2.5.0 のバグ  https://github.com/PaddlePaddle/X2Paddle/issues/991
RUN pip install --no-cache-dir "paddlepaddle>=2.6.0" x2paddle
# エラーを修正: `np.bool`は、Testsのビルトイン`bool`セグメンテーション・エラーの非推奨エイリアスだった。
RUN pip install --no-cache-dir numpy==1.23.5
# エクスポートされたモデルを削除する
RUN rm -rf tmp
```
以下のコマンドを実行し、ビルドをしましょう。
```console:console
docker build --platform linux/amd64 --no-cache -t myyolov8:latest .
```
## 2. DockerHUBに公開
以下のDockerのドキュメントを参考に、DockerHUBに公開してください。

https://docs.docker.jp/v1.9/engine/userguide/dockerrepos.html

## 3. 「高火力 DOK」にて実行
こちらのタスク実行画面でイメージを指定し、コマンドを実行していきます。
![qiita-さくら.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865255/d9866c50-a87c-f396-733f-c5a4660e9619.png)

以下のコマンドを実行、学習を行います。
```console:console
bash -c 'yolo detect train model=yolov8n.pt data=/home/ec2-user/ultralytics/ultralytics/data/custom_dataset/custom.yaml epochs=100 batch=8 device=cuda && cp -r /home/ec2-user/ultralytics/runs/* /opt/artifact'
```
複数のコマンドを実行する場合は、`bash -c 'a && b'`のように指定します。
詳しくは[公式ドキュメント](https://arc.net/l/quote/hpxppvjs)をご覧ください。
また、`cp -r /yourpath/ultralytics/runs/* /opt/artifact` に関してですが、高火力 DOKのアーティファクト保存用のディレクトリーです。
`SAKURA_ARTIFACT_DIR`という環境変数で定義されていますが、今回は直接指定しています。

※今回はDockerHUB上にPublic Repositoryとして公開していますが、Privateのまま使いたい方はレジストリーから、DockerHUBのユーザー名とパスワードを入力してください。
(「ホスト名」の部分はそのままで使えるはずです。)
![qiita-さくら2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865255/c2bb3fbc-0c36-4600-94ce-e80c0b00af95.png)

実行後このような画面に自動で遷移しますので、タスク終了まで待ちましょう。
タスク終了後、出力やアーティファクトを確認することができます。
![qiita-さくら3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865255/e21890ce-b98a-5e8d-7e93-e616a7a88d56.png)

こんな感じで、今回学習させた成長しきった鯛がうまく検出されているのが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865255/e71e6e49-216f-1a21-9ce8-dbfba9cec257.png)

# おわりに
今回は先日公開されたさくらインターネットの「高火力 DOK」上にて、弊社プロダクトの「Smart Searcher」に使用している真鯛の成長度判別AIモデルの学習を行ってみました。
新サービスでまだ文献も少ないながら手探りで学習を行わせているので、ベストプラクティスとは言えないかもしれません。その点だけご了承いただけますと幸いです。

また、晴工雨読の概要説明はこちらからご覧ください。

https://seikoudoku.co.jp/


# 注意点
現在高火力DOKはamdアーキテクチャにしか対応していません。
私は普段appleシリコンのmacbookを利用していますが、これに気づかず混乱してました。コンテナサービスに慣れている方は問題無いと思いますが、私のような初学者には注意が必要です。
(今回は一度Amazon EC2上にデータをアップロードし、ビルドしています。)

# 参考文献
https://manual.sakura.ad.jp/cloud/manual-koukaryoku-container.html

https://knowledge.sakura.ad.jp/2210/

https://qiita.com/Mikeinu/items/530bdb2ddeeedc32eb58

https://hub.docker.com/r/ultralytics/ultralytics/tags