【機械学習】GPU(RunPod) vs CPUモデル生成 の処理時間比較

## はじめに
本業はフロントエンジニアとして活動しています。

Qiitaに投稿した以下の記事の中で機械学習モデルを作成しました。
その際CPUで生成したのですが、完了するまでなんと**17時間**もかかってしまいました。

https://qiita.com/bsj-t-endo/items/8e0fa80d9f12e62388f7

本記事では、GPUを使ったらどれぐらい違うのかをGPUサーバーを提供しているクラウドプラットフォームの**RunPod**を使って検証する内容となっています。

※RunPodは従量課金制で多少お金がかかるのでご注意ください。
この記事では、0.69$/h 程度の安いGPUを使うので、数百円ぐらいですね。

### この記事の対象者
- 機械学習初心者
- GPUでモデル生成するとどれぐらい速いのか知りたい
- RunPodを使ってみたい

自分はフロント専門で機械学習は初心者です。
同じように触ったことない方でも意外と簡単に扱えることがわかったので興味がある方はこの記事を参考に触って学習してみてください。

### 動作環境・使用するツールや言語
- RunPod
- S3
- python3.11.10
- YOLO

## RunPodで学習モデルを生成する
RunPodとは、GPUを扱える環境を提供するクラウドプラットフォームです。
まずはRunPodのセットアップを行い、実際に学習モデルを生成してみてCPUとの生成時間の比較をしてみたいと思います。
最後にモデルが実際に使えるかどうかも確認します。


### 1.RubPodセットアップ
RunPodのアカウントを作成してログインします。
https://www.runpod.io/

![](https://storage.googleapis.com/zenn-user-upload/66c4ef0dc309-20241207.png)

RunPodは事前に支払いをして使う分をチャージしておく仕組みになっています。
クレジットカードを使う場合は、[Billing]にて[Pay with Card]で事前にチャージしておきます。
チャージする額は最低25$からとなります。

![](https://storage.googleapis.com/zenn-user-upload/c22de021a196-20241207.png)

[Explore]でデプロイするPodのテンプレートを選びます。
今回は、YoloでPyTorch形式のモデルを生成するので、[RunPod Pytorch2.4.0](https://www.runpod.io/console/explore/runpod-torch-v240)を選びます。

クリックしたら[Deploy]ボタンを押すと以下の画面になり、GPUの種類を選択します。
以下を選び、[Deploy On-Demand]をクリックし、Podをデプロイします。

- GPU: NVIDIA/RTX 4090
- Instance Pricing: On-Demand

![](https://storage.googleapis.com/zenn-user-upload/6220547ff116-20241207.png)

![](https://storage.googleapis.com/zenn-user-upload/811feb94ca89-20241207.png)

[Pods]にデプロイしたPodsが表示されます。
すでにサーバーが立ち上がっているのでこの時点から課金されていきます。
そしたら、[Connect]>[Connect to Jupyter Lab[Port 8888]]でサーバに接続します。

![](https://storage.googleapis.com/zenn-user-upload/2bca37213e27-20241207.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796407/80765780-4d14-dcb4-358a-a2664b7049e5.png)


ブラウザ上でターミナルが立ち上がり以下の画面が表示されます。

![](https://storage.googleapis.com/zenn-user-upload/80041aa15069-20241207.png)

これでRunPodセットアップが完了しました。


### 2.パッケージをインストールする

モデル生成に必要なパッケージをインストールしていきます。
先に仮想化しておきます。

```bash
root@e23218a6d7af:/workspace# python3 -m venv myenv
root@e23218a6d7af:/workspace# source myenv/bin/activate
```

Ultralytics YOLOをインストールします。
リポジトリをcloneしてそこからultralyticsをインストールします。

```bash
(myenv)root@e23218a6d7af:/# git clone https://github.com/ultralytics/ultralytics
(myenv)root@e23218a6d7af:/# pip install -qe ultralytics
```

これでYoloが使えるようになったので、サンプルのモデルを生成します。
```
(myenv)root@e23218a6d7af:/# yolo task=detect mode=predict model=yolov8n.pt source="https://ultralytics.com/images/bus.jpg"
(myenv)root@e23218a6d7af:/# ls
yolov8n.pt
```

これでYoloコマンドと学習済みモデルが用意できました。


### 3.画像をアップロードする
大量のトレーニング用の画像が必要になるので、それをアップロードする必要があります。
今回はAWS S3に事前にアップロードして、RunPodサーバからaws-cliでコピーします。

まず、以下のディレクトリ構造でラベリング済み画像とラベリングデータと一緒にアップロードしておきます。

```bash
yolo
├── train
│   ├── classes.txt
│   ├── images
│   ├── labels
│   ├── labels.cache
│   └── notes.json
└── valid
    ├── classes.txt
    ├── images
    ├── labels
    ├── labels.cache
    └── notes.json
```

ラベリングの方法については、以下の記事の最初の部分を参考にしてください。
LabelStudioを使った方法を載せています。
https://qiita.com/bsj-t-endo/items/8e0fa80d9f12e62388f7

次にaws-cliを使ってアップロードしたフォルダごとダウンロードします。
事前にIAMでアクセスキーを発行しておき、aws-cliの設定を行います。
アクセスキーを発行する手順は省略します。

```bash
(myenv)root@e23218a6d7af:/# pip install awscli
(myenv)root@e23218a6d7af:/# aws configure
```

アップロードしたバケットを指定して、ラベル済み画像ファイルを全てインストールします。
```
(myenv)root@e23218a6d7af:/# aws s3 sync s3://[バケット名] ./
```

モデル生成の際にラベリングデータの置き場所を示すためのdata.yamlも必要ですので、以下のように作成してください。
class namesは、ラベリングした際のラベル名です。

```yaml:data.yaml
# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: /workspace/yolo/train/images
val: /workspace/yolo/valid/images

# number of classes
nc: 1

# class names
names: ["cat"]
```

最終的に以下のファイルがあるはずです。
これで全ての準備が整いました。

```bash
(myenv)root@e23218a6d7af:/workspace# ls -l
total 11900
-rw-r--r--  1 root root     248 Dec  7 04:35 data.yaml
drwxr-xr-x  3 root root      28 Dec  7 02:00 runs
drwxr-xr-x 11 root root    4096 Dec  7 04:33 ultralytics
drwxr-xr-x  6 root root     115 Dec  7 04:26 myenv
drwxr-xr-x  4 root root      65 Dec  7 03:36 yolo
-rw-r--r--  1 root root 6549796 Dec  7 02:00 yolov8n.pt
```


### 4.モデルを生成する

いよいよ、モデル作成です。
以下のコマンドでモデル作成を実行します。

```bash
(myenv)root@e23218a6d7af:/# yolo task=detect mode=train model=yolov8n.pt data=data.yaml epochs=300 imgsz=640
```

トレーニングが開始されると以下のトレーニング結果がリアルタイムで表示されていきます。
```
Starting training for 300 epochs...

      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
      1/300      2.19G      0.997      2.111       1.44          5        640: 100%|██████████| 25/25 [00:05<00:00,  4.88it/s]
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 3/3 [00:01<00:00,  2.67it/s]
                   all         72         72      0.919      0.158      0.673      0.348

      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
      2/300      2.09G      1.015      1.682      1.453          3        640: 100%|██████████| 25/25 [00:01<00:00, 12.85it/s]
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 3/3 [00:00<00:00, 11.20it/s]
                   all         72         72      0.467      0.389      0.377      0.156
```


### 5.結果

結果としては、以下のようになりました。
CPUは自身のMac(M3 Pro)で実施した結果を記載しています。

| 項目 | CPU | GPU(RunPod) |
| ---- | :---: | :---: |
| 処理時間(時間) | 17.056 | 0.236 |
| epoch数 | 238 | 300 |

圧倒的にRunPodのGPUを使った方が速いですね。
72倍高速です。

また、最終epoch数がなぜか、GPUの方が最後まで実施されました。
同じコマンドで300を指定して実施したのですが、途中改善が見られないと300を指定していても途中で終了します。
CPUの方は238でしたが、GPUはきっちり300でした。
この結果は予想していなかったのでちゃんと理解しないとですね。

### 6.動作確認

先ほど作ったモデルを使って実際に動作確認します。
実際に検知するシステムの作成方法については割愛します。
投稿したQiitaの記事を参照してください。
[まーちゃん(猫)を検知したら通れる開閉ゲートを作ってみた](https://qiita.com/bsj-t-endo/items/8e0fa80d9f12e62388f7)

以下のようにしっかり検知されました。
GPUを使った方法でも問題なかったですね。
しかも、なぜか、こちらの方が検知する精度と距離もCPUでのモデルよりも検知されやすく、誤認も少なかったです。
うーん、GPUとは違うところで変わっちゃったのかな...

![](https://storage.googleapis.com/zenn-user-upload/2a42a03b760c-20241207.png)

何はともあれ、検証もできたので目標達成です。

## 参考資料

https://dev.classmethod.jp/articles/yolov8-trial-custom-dataset/

## おわりに
機械学習は圧倒的にGPU搭載マシンで実施した方がいいことがわかりました。
当然の結果ではありますが、実際にやってみるとここまで差があるとは思っていませんでした。

もちろん、GPUのスペックにもよるとは思いますが、それでもここまで差があるものなのですね。