このブログは、株式会社フィックスターズのエンジニアが、あらゆるテーマについて自由に書いているブログです。
Intel製CPUの評価に使用できるクラウドサービスとして、Intel Developer Cloudというサービスがあります。 今回はこのサービスを使用して、画像の物体認識でよく使用されるモデルであるYOLOv8の評価を行いました。
Intel Developer CloudはIntelが提供するクラウドサービスで、Intel製CPUの評価を簡単に行うことができます。
https://www.intel.com/content/www/us/en/developer/tools/devcloud/overview.html
いくつかのサービスがあり、それぞれ仕様や利用可能なマシンが異なります。
今回はIntel Developer Cloud for the Edgeを使用してYOLOv8の評価を行います。
Intel Developer Cloudのうち、エッジ向けデバイスの評価に特化したサービスです。
一般的なPCでよく使用されているCore系CPUやAtomが評価用マシンとして用意されており、PC上で動作するアプリケーションの評価に適しています。 CPUの世代は古いものだと第6世代のインテル® Core™ i5-6500TE、新しいものだと第13世代のインテル® Core™ i9-13900TEと幅広く展開されていますので、世代間の性能を比較してハードウェア選定を行う用途にも使用できます。 当然すべてのCPUが用意されているわけではないので、その点はご注意ください。 実際に利用可能なマシンはこちらで公開されています。
Intel Developer Cloud for the EdgeではJupyterLabを使用して評価を行います。 OpenVINOやTensorFlowなど機械学習系のライブラリがインストール済みなので、すぐに使用することができます。
OpenVINO toolkitは様々なインテルデバイス上で深層学習の推論処理を高速に実行するためのツールキットです。
OpenVINO toolkitにはモデルを実行するためのランタイム以外にもいくつかのツールが含まれています。
これらのツールはすべてIntel Developer Cloud上で使用可能です。
今回はこれらのツールを活用して、精度やパフォーマンスの測定を行います。
Neural Network Compression Framework (NNCF)はOpenVINOチームが開発しているモデル最適化ツールです。
https://github.com/openvinotoolkit/nncf
OpenVINO向けに量子化をはじめとした様々なモデル最適化を適用できます。
今回はPost-Training Quantization(PTQ)をYOLOv8に適用する際に使用します。
Intel Developer Cloud for the Edgeは無償で利用可能ですが、利用のためにはアカウントが必要です。
まずは、インテルアカウントを作成します。
Intelの公式サイトを開き、右上の人型アイコンからサインイン画面を開きます。
続いて、アカウントの作成をクリックします。
その後は手順に従い、インテルアカウントを作成してください。
インテルアカウント作成後は、Intel Developer Cloudアカウントを作成します。
Intel Developer Cloud for the Edgeを開き、Create an Intel Developer Cloud Account
をクリックします。
その後は手順に従い、Intel Developer Cloudアカウントを作成します。
Intel Developer Cloudアカウントあくまで利用するための手続きであり、ログイン自体はインテルアカウントで行うためご注意ください。
Intel Developer Cloud for the Edgeを開き、Bare Metal DevelopmentのGet Started
をクリックすると、JupyterLabが起動できます。
ここからは起動したJupyterLabを使用して、YOLOv8を評価します。
評価はOpenVINO Notebooksで公開されているノートブックを使用します。
OpenVINO NotebooksではOpenVINOを使用した様々なチュートリアルが公開されており、OpenVINOライブラリの基本的な使い方から主要なタスクの実用例、量子化などのモデル最適化まで、幅広く学ぶことができます。
今回はYOLOv8の実行と量子化を扱う下記のノートブックをベースに進めます。
上記Notebookをダウンロードして、JupyterLabにアップロードします。
アップロードしたNotebookを開くとカーネルを選択する画面になるため、Python 3.10 (OpenVINO 2023.2 Latest)
を選択します。
Intel Developer Cloud上では必要なライブラリが予めインストールされているため、セル1の内容(pip installのコマンド)を全てコメントアウトもしくは削除してください。
上記書き換えが完了したら、すべてのセルを実行するだけでモデルの最適化から評価までの一通りの処理が実行されます。
ただし、Notebookを普通に実行した場合は、ログインノード(Xeonサーバ)上で処理が行われます。 エッジデバイス上の性能評価をする場合は、少し別の手順で実行する必要があります。
Intel Developer Cloudには様々なデバイスが用意されていますので、どのデバイスで評価するかを選択する必要があります。
新しいセルを作成し下記のコマンドを実行すると、使用可能なデバイスの一覧が表示されます。
!pbsnodes | grep compnode | awk '{print $3}' | sort | uniq
各マシンのCPU型番やメモリ容量などが表示されますので、評価したいマシンを選んでください。
実行時には先頭にあるID(例:idc001sk1
)を使ってマシンを指定します。
エッジデバイス上で性能評価を行うためには、実行したい内容をスクリプトとして用意する必要があります。
今回は予め用意した下記のスクリプトを使用します。
このスクリプトは、モデルと実行デバイスをいくつかの組み合わせで実行しています。 モデルは通常のモデルと量子化済みのモデルの2種類、実行デバイスはCPU、GPU(iGPU)、AUTOの3種類の中から組み合わせて実行します。 AUTOはCPUとGPU両方を組み合わせて実行するモードです。
benchmark.sh
#!/bin/sh
#PBS -v VENV_PATH
#PBS -j oe
cd $PBS_O_WORKDIR
source ${VENV_PATH}/bin/activate
MODELS=("models/yolov8n_openvino_model/yolov8n.xml" "models/yolov8n_openvino_int8_model/yolov8n.xml")
DEVICES=("CPU" "GPU" "AUTO")
for model in "${MODELS[@]}"; do
for device in "${DEVICES[@]}"; do
echo -----
echo model: $model
echo device: $device
echo -----
benchmark_app -m $model -d $device -api async -shape "[1,3,640,640]" -hint cumulative_throughput -t 120
done
done
最後の行には改行が必須なのでご注意ください。
スクリプトを保存したら、qsub
コマンドを使用してエッジデバイス上でこのスクリプトを実行するジョブを作成します。
新しいセルを作成して下記のコマンドを実行してください。
!qsub -l nodes=1:idc001skl benchmark.sh
idc001skl
の部分は、実際に使用したいマシンのIDに変更してください。
実行すると、949569.v-qsvr-1.devcloud-edge
のような出力が得られます。
このうち最初の数値の部分(例だと949569
)がジョブ番号になります。
指定したデバイスにもよりますが、数分程度待つとbenchmark.sh.o[ジョブ番号]
というファイルに結果が出力されます。 このファイルを開くと、各モデル、ハードウェアごとの実行結果が確認できます。
性能ほどではありませんが、精度もデバイスごとに異なる可能性があります。 対応命令セットの違いによる演算結果の微妙な誤差などが影響を与えるためです。
精度評価も性能評価と同様に、あらかじめ用意したスクリプトを使用します。 このスクリプトはNotebookの精度評価コードを元に、単独で実行できるように整理したものです。
そのまま実行すると、通常のモデルと量子化済みのモデルの精度評価をCPUとGPUそれぞれで実行します。評価対象や評価サンプル数などのパラメータは必要に応じて変更してください。
accuracy.sh
#!/bin/sh
#PBS -v VENV_PATH
#PBS -j oe
cd $PBS_O_WORKDIR
source ${VENV_PATH}/bin/activate
python3 accuracy.py
accuracy.py
from tqdm.notebook import tqdm
from ultralytics.yolo.utils.metrics import ConfusionMatrix
from ultralytics.yolo.utils import DEFAULT_CFG, ops
from ultralytics.yolo.cfg import get_cfg
from ultralytics.yolo.data.utils import check_det_dataset
from ultralytics import YOLO
import openvino.runtime as ov
import torch
import numpy as np
def main():
det_model = YOLO("models/yolov8n.pt")
args = get_cfg(cfg=DEFAULT_CFG)
args.data = str("datasets/coco.yaml")
det_validator = det_model.ValidatorClass(args=args)
det_validator.data = check_det_dataset(args.data)
det_data_loader = det_validator.get_dataloader("datasets/coco", 1)
det_validator.is_coco = True
det_validator.class_map = ops.coco80_to_coco91_class()
det_validator.names = det_model.model.names
det_validator.metrics.names = det_validator.names
det_validator.nc = det_model.model.model[-1].nc
NUM_TEST_SAMPLES = 300
core = ov.Core()
for model in ["models/yolov8n_openvino_model/yolov8n.xml", "models/yolov8n_openvino_int8_model/yolov8n.xml"]:
for device in ["CPU", "GPU"]:
print(f"""---
model: {model}
device: {device}
---""")
ov_model = core.read_model(model)
det_stats = test(ov_model, device, core, det_data_loader, det_validator, num_samples=NUM_TEST_SAMPLES)
print_stats(det_stats, det_validator.seen, det_validator.nt_per_class.sum())
def test(model:ov.Model, device:str, core:ov.Core, data_loader:torch.utils.data.DataLoader, validator, num_samples:int = None):
"""
OpenVINO YOLOv8 model accuracy validation function. Runs model validation on dataset and returns metrics
Parameters:
model (Model): OpenVINO model
data_loader (torch.utils.data.DataLoader): dataset loader
validator: instance of validator class
num_samples (int, *optional*, None): validate model only on specified number samples, if provided
Returns:
stats: (Dict[str, float]) - dictionary with aggregated accuracy metrics statistics, key is metric name, value is metric value
"""
validator.seen = 0
validator.jdict = []
validator.stats = []
validator.batch_i = 1
validator.confusion_matrix = ConfusionMatrix(nc=validator.nc)
model.reshape({0: [1, 3, -1, -1]})
compiled_model = core.compile_model(model, device)
for batch_i, batch in enumerate(tqdm(data_loader, total=num_samples)):
if num_samples is not None and batch_i == num_samples:
break
batch = validator.preprocess(batch)
results = compiled_model(batch["img"])
preds = torch.from_numpy(results[compiled_model.output(0)])
preds = validator.postprocess(preds)
validator.update_metrics(preds, batch)
stats = validator.get_stats()
return stats
def print_stats(stats:np.ndarray, total_images:int, total_objects:int):
"""
Helper function for printing accuracy statistic
Parameters:
stats: (Dict[str, float]) - dictionary with aggregated accuracy metrics statistics, key is metric name, value is metric value
total_images (int) - number of evaluated images
total objects (int)
Returns:
None
"""
print("Boxes:")
mp, mr, map50, mean_ap = stats['metrics/precision(B)'], stats['metrics/recall(B)'], stats['metrics/mAP50(B)'], stats['metrics/mAP50-95(B)']
# Print results
s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Labels', 'Precision', 'Recall', 'mAP@.5', 'mAP@.5:.95')
print(s)
pf = '%20s' + '%12i' * 2 + '%12.3g' * 4 # print format
print(pf % ('all', total_images, total_objects, mp, mr, map50, mean_ap))
if 'metrics/precision(M)' in stats:
s_mp, s_mr, s_map50, s_mean_ap = stats['metrics/precision(M)'], stats['metrics/recall(M)'], stats['metrics/mAP50(M)'], stats['metrics/mAP50-95(M)']
# Print results
s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Labels', 'Precision', 'Recall', 'mAP@.5', 'mAP@.5:.95')
print(s)
pf = '%20s' + '%12i' * 2 + '%12.3g' * 4 # print format
print(pf % ('all', total_images, total_objects, s_mp, s_mr, s_map50, s_mean_ap))
if __name__ == "__main__":
main()
こちらも同様にqsub
コマンドで実行します。 新しいセルを作成して下記のコマンドを実行してください。
!qsub -l nodes=1:idc001skl accuracy.sh
idc001skl
の部分は、実際に使用したいマシンのIDに変更してください。
指定したデバイスにもよりますが、十数分程度待つとaccuracy.sh.o[ジョブ番号]
というファイルに結果が出力されます。 このファイルを開くと、各モデル、ハードウェアごとの実行結果が確認できます。
今回はCPUによる性能の違いを見るために、下記の3種類のCPUで性能測定を行いました。
CPUの仕様は下記のとおりです。
インテル® Core™ i7-8700T | インテル® Core™ i7-10700T | インテル® Core™ i5-12500TE | |
---|---|---|---|
発売日 | Q2’18 | Q2’20 | Q1’22 |
CPU世代 | 第8世代 | 第10世代 | 第12世代 |
開発コード | Coffee Lake | Comet Lake | Alder Lake |
コア数 | 6 | 8 | 6 / 0 (P-Core/E-Core) |
スレッド数 | 12 | 16 | 12 |
ベース周波数 | 2.40 GHz | 2.00 GHz | 1.90 GHz |
ターボブースト時周波数 | 4.00 GHz | 4.50 GHz | 4.30 GHz |
メモリー | 最大 DDR4-2666 | 最大 DDR4-2933 | 最大 DDR5-4800 |
メモリー帯域 | 最大 41.6GB/s | 最大 45.8 GB/s | 最大 76.8 GB/s |
iGPU | Intel® UHD Graphics 630 | Intel® UHD Graphics 630 | Intel® UHD Graphics 770 |
iGPU世代 | 第9.5世代 | 第9.5世代 | 第12世代 |
iGPUクロック | 最大 1.20 GHz | 最大 1.20 GHz | 最大 1.45GHz |
OpenVINOの実行デバイスは、CPUとGPU(iGPU)の2つを測定しました。
結果は下記のようになりました。
CPU | 実行デバイス | 量子化なし | 量子化あり |
---|---|---|---|
i7-8700T | CPU | 33.25 FPS | 60.93 FPS |
i7-8700T | GPU | 44.42 FPS | 41.71 FPS |
i7-8700T | AUTO | 53.97 FPS | 70.16 FPS |
i7-10700T | CPU | 39.12 FPS | 68.38 FPS |
i7-10700T | GPU | 52.09 FPS | 48.96 FPS |
i7-10700T | AUTO | 60.27 FPS | 82.24 FPS |
i5-12500TE | CPU | 43.46 FPS | 116.65 FPS |
i5-12500TE | GPU | 78.20 FPS | 110.57 FPS |
i5-12500TE | AUTO | 79.69 FPS | 157.95 FPS |
この結果から、新しいCPUほど推論性能が上がっていることがわかります。
特に新しいi5(i5-12500TE)は古いi7(i7-10700T)よりコア数が少ないにも関わらず、性能は大きく向上しています。 これは単純な演算性能やメモリ帯域の向上のほか、CPUのVNNI(INT8行列演算向けの命令セット)追加やiGPUのINT8サポートなどが効果的に作用していると考えられます。
また、AUTOを使用することでさらなる性能向上が得られています。 これはAUTOが自動でCPUとGPUの両方を活用して高速化するためです。 ただし、場合によっては速度が低下するケースも有るため、実際に性能を確認して必要に応じて設定を調整することが大切です。
Intel Developer Cloudを使用することで、手元に環境を用意することなく手軽に物体認識の評価を行うことができました。
特にCPU間の比較のような評価を手元で行う場合は何台ものマシンを用意する必要があるため、Intel Developer Cloudのメリットが活かせます。
また、OpenVINO Notebooksでは、今回使用したノートブックのような実用例が多く公開されています。Intel Developer Cloudと組み合わせることで、最新のモデルを無料で手軽に試すことができます。
みなさんもぜひ興味のあるノートブックを元に実行してみてください。
コンピュータビジョンセミナーvol.2 開催のお知らせ - ニュース一覧 - 株式会社フィックスターズ in Realizing Self-Driving Cars with General-Purpose Processors 日本語版
[…] バージョンアップに伴い、オンラインセミナーを開催します。 本セミナーでは、...
【Docker】NVIDIA SDK Managerでエラー無く環境構築する【Jetson】 | マサキノート in NVIDIA SDK Manager on Dockerで快適なJetsonライフ
[…] 参考:https://proc-cpuinfo.fixstars.com/2019/06/nvidia-sdk-manager-on-docker/ […]...
Windowsカーネルドライバを自作してWinDbgで解析してみる① - かえるのほんだな in Windowsデバイスドライバの基本動作を確認する (1)
[…] 参考:Windowsデバイスドライバの基本動作を確認する (1) - Fixstars Tech Blog /proc/cpuinfo ...
2021年版G検定チートシート | エビワークス in ニューラルネットの共通フォーマット対決! NNEF vs ONNX
[…] ONNX(オニキス):Open Neural Network Exchange formatフレームワーク間のモデル変換ツー...
YOSHIFUJI Naoki in CUDAデバイスメモリもスマートポインタで管理したい
ありがとうございます。別に型にこだわる必要がないので、ユニバーサル参照を受けるよ...