Ben Hayes - Object Detection with YOLOv8 on Databricksの翻訳です。
本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
イントロダクション
最新のAIハイプサイクルで人工知能(AI)が斜陽となっていく中(IBMのDeep BlueやWatsonを考えてください)、自信満々に"I'll be back"という声を聞いたと主張した人がいても許されることでしょう。実際、2024年にさしかかる頃に、AIの知性線の上に再び太陽が登りました。AIの研究者は、そのフロンティアを探索し続け、計算資源はよりパワフル、経済的、豊富になり、ビジネスではさらに多くのデータを取り込むようになりました。現在では、主にテキストを取り扱う大規模言語モデル(LLM)が最も注目を集めていますが、このAIの復活の中でコンピュータービジョンも前進しています。このAIの分派は業界とイノベーションを強化しています - 自動運転自動車、製造欠陥の検知などの分野で。
この記事では、コンピュータービジョン、特に物体検知にフォーカスし、最近のAIに関する記事シリーズ(Getting Started with OpenAI、Hands-on with Edge AI、Getting Started with Databricks)の続きとなります。AIの広範で進化し続けるトピックに興味があるのであれば、これらの記事もチェックください!
この記事では、なぜ、YOLOv8とDatabricksが、物体検知ユースケースの開発に対してエレガントなソリューションを提供するのかをpythonのサンプルとともにディープダイブします。はじめに、YOLOv8モデルとDatabricksプラットフォームについて議論しましょう。
YOLOv8について
YOLOv8は、以下を含む多数のビジョン関連のタスクを実行できるultralytics
ライブラリでメンテナンスされているパワフルなAIモデルです:
- 画像分類(二値とマルチクラス)
- 物体位検知
- 画像セグメンテーション
- 物体追跡
- 姿勢推定
GithubのUltralytics/YOLOv8でサポートされているモデル。ソース: https://github.com/ultralytics/ultralytics
Ultralyticsは、スクラッチからのトレーニングであろうと、事前トレーニング済みであっても、数行のコードでスタートできるようにYOLOv8を使うためのインタフェースをシンプルにします。そして、同じように、Databricks上でYOLOv8、ハイパワーのGPU有効かクラスターを活用することができます。
Databricksについて
以前の記事で議論したように、Databricksはレイクハウスのアーキテクチャ/コンセプトの発明者であり、MIT Reviewによると、企業の74%が導入しているとのことです。また、Spark、Delta Lake、MLflowを含む、モダンデータアーキテクチャに含まれるテクノロジーのクリエーターでもあります。
Databricksを活用することで、構造化、半構造化、画像を含む非構造化データセットを取り扱うためのデータパイプラインを容易に構築することができます。データパイプラインや大規模なデータボリュームはこの生地の本題ではありませんが、このソリューションをスケールさせるための能力は、プロダクションのデータデプロイメントにおける重要な検討事項となります。さらに、Databricksを活用することで、データエンジニアリングのフォーカスと機械学習のフォーカスの間でシームレスにプロジェクトを移行することができます。新たに到着するデータに対応する必要がある場合には、このような機能が有用となります。Databricksでは、データエンジニアリング、データアナリティクス、データサイエンス、機械学習、人工知能プロジェクトのための長大な機能のリストがありますが、この物体検知の例で特に使う機能は以下のものとなります:
-
GPU有効化クラスター(
ultralytics
やtorch
のように容易に外部からインポートできるライブラリを含む) - モデルトラッキング、評価、サービングのためのMLflow
- Databricksボリューム(モデルチェックポイントのようなバイナリー/非テーブルデータの格納)
DatabricksにおけるYOLOv8を用いた物体検知
概要
YOLOv8とモデルやDatabricksプラットフォームを理解したので、画像内の物体を検知するためにこれらのツールを活用するサンプルに踏み出す準備ができました。我々は、解きたいと考える問題が何であるのか、どのようなオブジェクトを検知したいのか?という問いに答える必要があります。さらに、物体検知を活用する背景にある'理由'を理解することは、ソリューションが問題を確実に解決するためには重要です。価値が鍵となります。
我々のゴールは、太陽光パネルを検知するために、Databricksプラットフォーム、GPU有効化コンピュート、YOLOv8モデルを活用することです。それなしには、このタスクは手動で、時間を浪費し、コストがかかり、(専門家によるものだとしても)精度が低いものとなるために、これを達成したいと考えます。このタスクのパフォーマンスを少し改善するだけでも、ソーラーパネルフリートオーナー / 再生可能エネルギー供給者において数百万ドルの価値を解放することになります。次に、この問題に取り組むために利用できるデータセットを議論しましょう。
この例では、太陽光パネルの写真を取り扱います。我々は、
- 写真内の太陽光パネルを検知
- 太陽光パネルが故障しているか、していないかを特定
します。我々のトレーニングデータは、約200の太陽光パネルの画像から構成されています。さらに、メタデータは太陽光パネルの位置('境界ボックス')とそれぞれの太陽光パネルの状態をラベル付けしています。
参考までに、提供される画像の例は以下のようなものとなります:
ダイブしましょう!
セットアップ
我々のコードの最初のステップは、計算環境をセットアップすることです。幸運なことに、Databricksを用いることでこれはシンプルなものとなります。簡単にultralytics
ライブラリをインストールし、ノートブックにインポートすることができます。CUDA設定やデータのスキーマのようないくつかの設定を調整することで、GPUクラスターのパフォーマンスを最適化することができます。最後に、モデルとデータの操作を簡単にするために、YOLOC
というシンプルなclassを作成し、いくつかのパスを定義します。
%pip install ultralytics==8.1.14 opencv-python #==4.8.0.74
import os
os.environ["CUDA_LAUNCH_BLOCKING"] = "1"
from ultralytics import YOLO
import mlflow
import torch.distributed as dist
from ultralytics import settings
from mlflow.types.schema import Schema, ColSpec
from mlflow.models.signature import ModelSignature
os.environ["OMP_NUM_THREADS"] = "4" # Configure as needed
input_schema = Schema(
[
ColSpec("string", "image_source"),
]
)
output_schema = Schema([ColSpec("string","class_name"),
ColSpec("integer","class_num"),
ColSpec("double","confidence")]
)
signature = ModelSignature(inputs=input_schema,
outputs=output_schema)
settings.update({"mlflow":False})
##############################################################################
## Create YOLOC class to capture model results and a predict() method ##
##############################################################################
class YOLOC(mlflow.pyfunc.PythonModel):
def __init__(self, point_file):
self.point_file=point_file
def load_context(self, context):
from ultralytics import YOLO
# Config MLflow
mlflow.autolog(disable=False)
mlflow.end_run()
# Config project structure directory
project_location = '/Volumes/benhayes/demo/solar-data/dataset_1'
os.makedirs(f'{project_location}/training_runs/', exist_ok=True)
os.chdir(f'{project_location}/training_runs/')
トレーニング
次に、8つのバッチと50エポックを実行するために、トレーニングプロセスを開始し、mlflow.start_run()
を使います。事前トレーニング済みモデル('.pt'のサフィックス)としてYOLOモデルを定義し、トレーニング画像をポイントするYAMLを指定し、モデルチューニングをコントロールするパラメーターを定義します。これらのパラメーターの詳細については、YOLO documentationをご覧ください。
log_params()
とlog_model()
を用いて、パラメーターとモデルを記録するMLflowの機能を活用します。これらを用いることで、MLflowのエクスペリメントにモデルの詳細をキャプチャし、すべてのトレーニングモデルを再現したい場合には再訪することができます。
if not dist.is_initialized():
dist.init_process_group("nccl")
# Kickoff the MLflow training process
# Specify the number of batches, epoches, etc. for this experiment
with mlflow.start_run():
model = YOLO("yolov8l-seg.pt")
model.train(
batch=8,
device=[0],
data=f"{project_location}/training/data.yaml",
epochs=50,
project='/tmp/solar_panel_damage/',
exist_ok=True,
fliplr=1,
flipud=1,
perspective=0.001,
degrees=.45
)
mlflow.log_params(vars(model.trainer.model.args))
yolo_wrapper = YOLOC(model.trainer.best)
mlflow.pyfunc.log_model(artifact_path = "model",
artifacts = {'model_path': str(model.trainer.save_dir),
"best_point": str(model.trainer.best)},
python_model = yolo_wrapper,
signature = signature
)
Databricksノートブック環境のインタラクティブな性質のおかげで、クラスターがモデルをトレーニングする際にリアルタイムでアウトプットを参照できます。ここでは、UltralyticsライブラリがYAML設定を処理し、トレーニングデータセットにアクセスし、トレーニングのイテレーションを開始していることを確認できます。エポック数、GPUメモリー使用量、ロスのメトリクス、進捗のようなアウトプットを確認できます。
Ultralytics YOLOv8.1.14 🚀 Python-3.10.12 torch-2.0.1+cu118 CUDA:0 (Tesla T4, 14931MiB)
Overriding model.yaml nc=80 with nc=2
Transferred 651/657 items from pretrained weights
TensorBoard: Start with 'tensorboard --logdir /tmp/solar_panel_damage/train', view at http://localhost:6006/
Freezing layer 'model.22.dfl.conv.weight'
AMP: running Automatic Mixed Precision (AMP) checks with YOLOv8n...
AMP: checks passed ✅
train: Scanning /Volumes/benhayes/demo/solar-data/dataset_1/training/datasets/train/labels.cache... 108 images, 0 backgrounds, 0 corrupt: 100%|██████████| 108/108 [00:00<?, ?it/s]
val: Scanning /Volumes/benhayes/demo/solar-data/dataset_1/training/datasets/val/labels.cache... 6 images, 0 backgrounds, 0 corrupt: 100%|██████████| 6/6 [00:00<?, ?it/s]
Plotting labels to /tmp/solar_panel_damage/train/labels.jpg...
optimizer: 'optimizer=auto' found, ignoring 'lr0=0.01' and 'momentum=0.937' and determining best 'optimizer', 'lr0' and 'momentum' automatically...
optimizer: AdamW(lr=0.001667, momentum=0.9) with parameter groups 106 weight(decay=0.0), 117 weight(decay=0.0005), 116 bias(decay=0.0)
TensorBoard: model graph visualization added ✅
Image sizes 640 train, 640 val
Using 8 dataloader workers
Logging results to /tmp/solar_panel_damage/train
Starting training for 50 epochs...
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
1/50 10.3G 2.1 5.152 4.102 2.091 328 640: 100%|██████████| 14/14 [00:18<00:00, 1.29s/it]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 4.26it/s]
all 6 195 0.994 0.785 0.917 0.442 0.994 0.785 0.917 0.425
Epoch GPU_mem box_loss seg_loss cls_loss dfl_loss Instances Size
2/50 8.83G 0.921 2.043 1.096 1.09 297 640: 100%|██████████| 14/14 [00:10<00:00, 1.33it/s]
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 4.11it/s]
all 6 195 0.168 0.903 0.207 0.093 0.162 0.872 0.2 0.0861
...
50 epochs completed in 0.255 hours.
Optimizer stripped from /tmp/solar_panel_damage/train/weights/last.pt, 92.3MB
Optimizer stripped from /tmp/solar_panel_damage/train/weights/best.pt, 92.3MB
Validating /tmp/solar_panel_damage/train/weights/best.pt...
Ultralytics YOLOv8.1.14 🚀 Python-3.10.12 torch-2.0.1+cu118 CUDA:0 (Tesla T4, 14931MiB)
YOLOv8l-seg summary (fused): 295 layers, 45913430 parameters, 0 gradients, 220.1 GFLOPs
Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 3.45it/s]
all 6 195 0.994 0.785 0.917 0.439 0.994 0.785 0.917 0.429
working 6 195 0.994 0.785 0.917 0.439 0.994 0.785 0.917 0.429
Speed: 0.3ms preprocess, 26.7ms inference, 0.0ms loss, 4.4ms postprocess per image
Results saved to /tmp/solar_panel_damage/train
Downloading artifacts: 0%| | 0/31 [00:00<?, ?it/s]
2024/02/17 01:59:06 INFO mlflow.store.artifact.artifact_repo: The progress bar can be disabled by setting the environment variable MLFLOW_ENABLE_ARTIFACTS_PROGRESS_BAR to false
Downloading artifacts: 0%| | 0/1 [00:00<?, ?it/s]
Uploading artifacts: 0%| | 0/37 [00:00<?, ?it/s]
2024/02/17 01:59:31 INFO mlflow.store.artifact.cloud_artifact_repo: The progress bar can be disabled by setting the environment variable MLFLOW_ENABLE_ARTIFACTS_PROGRESS_BAR to false
我々のデータセットを用いてモデルをトレーニングしました。プロセスをスムーズにするために、Databricksのボリュームによるクラウドストレージ、GPU有効化コンピュート、MLflowを活用することができました!
評価
モデルをトレーニングしたので、プログラムからモデルにアクセスすることができます。Databricksに組み込まれているMLflowのUIを通じてモデルにアクセスすることができますが、プログラムからモデルを操作することにします。しかし、はじめにモデルの結果を用意かつ繰り返しアクセスできるように、2つのヘルパー関数をセットアップします。コンピュータービジョンを取り扱うので、単にテーブルから読み込むのではなく、結果を参照したいとも考えます。
2つの関数を作成します: ベストモデルで推論を行い、予測した境界ボックスを持つ画像を表示するためのpredict_on_image()
やprepare_img_w_box()
となります。
##########
# Function to predict bounding boxes given a model and an input image
##########
def predict_on_image(model, img):
import pandas as pd
import json, os
# Use model to generate bounding box predictions for the loaded img
results = {}
result_list = []
model_results = model.predict(img)
label_names, boxes, confidence = model_results[0].names, model_results[0].boxes.cpu().numpy(), model_results[0].boxes.conf.tolist()
label_result = [int(i) for i in model_results[0].boxes.cls.tolist()]
named_results = [{'class_name': label_names[i],
'class_num': i,
'confidence': confidence[count],
'box': boxes[count].xyxy[0].astype(int).tolist()} for count, i in enumerate(label_result)
]
results['labels'] = named_results
return results
##########
# Function to display an image with bounding box(es) around solar panel(s)
# given the confidence threshold is set
##########
def prepare_img_w_box(img_in, results, confidence_thresh):
# Helper function to convert box points
def _convert_box_yolo_cv2(boxpoints):
xmin, ymin, xmax, ymax = boxpoints
x, y, w, h = xmin, ymin, xmax-xmin, ymax-ymin
return x,y,w,h
# Loop through each solar panel result, place box accordingly if confidence condition met
for solar_panel in results['labels']:
if solar_panel['confidence'] > confidence_thresh:
x,y,w,h = _convert_box_yolo_cv2(solar_panel['box'])
cv2.rectangle(img_in, (x,y), (x+w,y+h), (0,255,0), 2)
cv2_imshow(img_in)
import cv2
from dbruntime.patches import cv2_imshow
# Load the image via opencv2
img_loc = f'{project_location}/images/014R.jpg'
img = cv2.imread(img_loc)
cv2_imshow(img)
これで、予測結果を生成し、results
という変数に格納するために、ヘルパー関数を呼び出すことができます。
results = predict_on_image(model, img)
results
こちらがresults
のコンテンツとなります。提供した画像のそれぞれで予測された太陽光パネルのクラス(workingとnot working)と自信度(0.0 - 1.0)を予測しました。この自信度は、ヘルパー関数で閾値レベルを設定するために使用します。
0: 512x640 16 defects, 122 workings, 85.6ms
Speed: 2.6ms preprocess, 85.6ms inference, 6.8ms postprocess per image at shape (1, 3, 512, 640)
{'labels': [{'class_name': 'working',
'class_num': 1,
'confidence': 0.9999998807907104,
'box': [26, 199, 87, 293]},
{'class_name': 'working',
'class_num': 1,
'confidence': 0.9999992847442627,
'box': [31, 287, 90, 384]},
{'class_name': 'working',
'class_num': 1,
'confidence': 0.9999960660934448,
'box': [412, 344, 470, 441]},
...
{'class_name': 'working',
'class_num': 1,
'confidence': 0.25604432821273804,
'box': [351, 128, 460, 262]}]}
prepare_img_w_box(img, results, 0.98)
注意
ここでは、画像の表示にcv2_imshow()
を使っています。これは、Databricksノートブックにアウトプットをレンダリングするヘルパー関数です。ご自身の計算資源で標準的なjupyterノートブックを使っている場合には、標準的なimshow()
を使うことができます。
限定的なエポック数とバッチサイズにしては、我々のモデルは非常にリーズナブルな仕事をしています。最低限のチューニングで、偽陽性(サンプル画像の右手をご覧ください)と偽陰性(サンプル画像の左下)の発生を削減するためにモデルのパフォーマンスを改善することができます。
ラベル付された太陽光パネルを含むサンプル画像
まとめと次のステップ
振り返りましょう。コンピュータービジョンの概念と特に物体検知の重要性を説明しました。タスクの目的を特定し、Databricksプラットフォームを用いてYOLOv8モデルをファインチューニングしました。数行で我々のモデルがリーズナブルで信頼できる予測結果を生成し、数百のラベル付きのサンプルのみを必要とすることを見てきました。このコンピュータビジョンとAI領域におけるエクササイズの意図は、太陽光パネルを検知する完璧なモデルを作り出すことではありません。専門家と同じほどに正確で、人間の能力以上にスケールするモデルを生成する能力を証明したかったのです。この点に関しては成功したと言えます。
さらに、このモデルを改善する機会が存在します:
- 設計: 他のモデルをテストする。同じMLflowエクスペリメントで別のモデルのアウトプットをキャプチャするためにDatabricksを活用。
- ラベリング: フィードバックループをクローズする助けになるAIを活用することができます。Use DINOv2 to train a YOLOv8 Classification modelをご覧ください。
- トレーニング: トレーニングスコープ(エポック、バッチ)の拡大、他のモデルパラメーターのチューニング、トレーニングデータの追加。
- デプロイ: モデルを本格運用し、後段のユーザーに民主化するために、Databricks Mosaic AIのようなツールを活用。
コンピュータービジョンで何をするのかを計画はありますか?AIテクノロジーにおけるこのような進歩をどのように活用しますか?YOLOv8やDatabricksのようなツールからの明確な価値を確認しており、AIに関する現在のハイプサイクルは保証されています。データドリブンの効率性、インフラストラクチャの強化、民主化された情報をさらに推し進めることができます - より良い未来を作り出しましょう。🦾🤖