コンピューター ビジョンは、依然として非常に魅力的な人工知能のアプリケーションです。戦場の要素を認識する場合でも、作物の収量を予測する場合でも、コンピューター ビジョンはおそらく、AI の中で最も商業的に価値のある (そして社会的に重要な) 分野の 1 つです。
ただし、多くの場合、最高のコンピューター ビジョン機能の導入の律速となるのは、データセットの構築と、新しい画像に対してコンピューター ビジョン タスクを実行するシンプルなエンドツーエンド システムの設計に関連する複雑さです。
このブログ投稿では、CVAT や MinIO バケット通知などのクラス最高のツールを使用してこれらの問題に対処する方法を段階的に説明します。この投稿を終えると、カスタム データセットで物体検出モデルをトレーニングし、新しい画像が表示されるたびにそれを使用して予測できるようになります。
衛星画像に存在する航空機の種類を認識できるようにしたいとします。また、事前に構築されたデータセットや事前トレーニングされたモデルがない、ゼロから始めると仮定しましょう。以下に、衛星画像で検出および認識したい 2 つのサンプル航空機を示します。
この投稿で概説した手順は、ほぼすべてのドメインに一般化できます。航空機の種類を検出する代わりに、土地利用を分類したり、回帰を実行して作物の収量を予測したりすることもできます。従来の画像を超えて、LiDAR 点群や 3D 地震画像などの他のタイプの多次元データに対してトレーニングおよび推論を実行することもできます。それは、トレーニング データがどのように見えるか (YOLO の代わりに異なる深層学習モデルが使用される可能性もあります) だけの問題になります。特定のユースケースでこれがどのようになるかについてさらに質問がある場合は、お気軽に GitHubリポジトリで問題を作成してください。
このプロジェクトでは、オンデマンド画像衛星を所有していないことが主な理由で、私は Google Earth で飛行場を訪れ、これらの航空機の一部が表示されているエリアのスクリーンショットを複数枚撮りました。この一連の画像を組み立てるのにはかなりの時間がかかったので、すべての画像を MinIO サーバー上の「object-detection」という名前のバケットに保存しました。本番環境では、収集したサンプルを MinIO に保存する利点がさらに先見の明になります。アクティブ/アクティブ レプリケーション、最高レベルの暗号化、超高速 GET/PUT (いくつか例を挙げると) により、熱心に収集されたサンプルの可用性が高く、安全性が確保されます。
ユースケースに合わせて物体検出モデルをトレーニングするには、ラベル付き (または「アノテーション付き」) データセットが必要です。これに最適なツールは、OpenCV の CVAT です。優れた機能は、CVAT がバケットの画像をデータセット アノテーション ツールに直接フィードするために、MinIO バケットを「クラウド ストレージ」として接続するユーティリティを提供することです。これを行うには、特に MinIO Server をオンプレミスまたはラップトップでローカルに実行している場合は、MinIO Server のホストが CVAT サーバーにアクセスできることを確認してください。また、注意事項として、CVAT を使用するには 2 つの方法があります: (1) app.cvat.aiで提供されている Web アプリを使用するか、(2) ローカルで実行します。いずれの場合も、CVAT を開いたら、メニュー バーの [クラウド ストレージ] をクリックします。そこから、フォームに記入して (S3 互換の) MinIO バケットを添付できます。
「タスク」の下に新しいラベル付けタスクを作成しましょう。
記入するフォームが表示されます。
タスクを作成するときは、クラス ラベルを正しく定義することが重要です (私は、検出したい 2 つの平面に対応する、「SU30」と「TU95」というタイトルの 2 つの長方形ラベルを定義しました)。
残りのステップは、以前に追加した MinIO バケットをデータ ソースとしてアタッチすることです。 「ファイルの選択」で「クラウドストレージ」をクリックし、先ほどソースに指定した名前を入力します。上記では「minio-cv-bucket」という名前を使用しました。
アップロードプロセスには数分かかります。完了すると、「ジョブ」の下に利用可能な注釈ジョブが表示されるはずです。
ここで、ジョブをクリックすると、各画像に注釈を付けることができます。警告: これは、過度に時間がかかるプロセスになる可能性があります。一般に、大規模な注釈のニーズがある実稼働環境では、このタスクを専用の社内チームまたはサードパーティのデータラベル付け会社に任せるのが最善の方法と考えられます。
注釈付けが完了したら、データセットを YOLO 形式でエクスポートします。
エクスポートされたデータセットは zip ファイルの形式になります。解凍すると、YOLO 形式の注釈テキスト ファイルが囲まれたフォルダー内にあります。ぜひご覧ください。 YOLO 形式では、各画像の注釈はテキスト ファイル内にあり、各行には境界ボックスの 2 つの隅とクラスが含まれます。クラス番号は、タスクの作成時にラベルを定義した順序に対応します。したがって、この例では、0 は Su-30 に対応し、1 は Tu-95 に対応します。
この時点で、新しい作業ディレクトリを作成します (または、すでに作成したディレクトリを入力します)。このディレクトリ内に、「dataset」というサブディレクトリを作成します。 「dataset」内に、作業ディレクトリが次のようなディレクトリを作成します。
my_cv_project (WORKING DIRECTORY) |---- dataset |----images |----train |----val |----test |----annotations |----train |----val |----test
ここで、画像とそれに対応する注釈 (テキスト ファイル) の両方に対して、train、val、test のサブディレクトリを作成する必要があります。サンプルをどのように取得して分割するかはあなた次第です。トレーニング サンプルの総量を 80% のトレーニング、10% の検証、10% のテストに分割することをお勧めします。画像を分割する前に、必ずランダムにシャッフルしてください。
個人的には、コマンド ラインで MinIO クライアントのmc cpを使用して、「オブジェクト検出」バケットからすべての画像をすばやく取得しました。あるいは、すべてのサンプル イメージがすでにローカル コンピューター上の 1 か所にある場合は、それを直接操作できます。すべてのサンプルを 1 か所に集めたら、Python スクリプトを使用して画像と注釈をシャッフル、分割し、train、val、test ディレクトリに移動しました。 便宜上提供されているスクリプトを次に示します。使用方法について質問がある場合は、お気軽にリポジトリで問題を作成してください。
最終的には、images/train、images/val、または image/test に配置した各イメージについて、一致する注釈 .txt ファイルが annotations/ ディレクトリ内の対応するサブディレクトリにも存在することを確認してください。例えば:
my_cv_project (WORKING DIRECTORY) |---- dataset |----images |----train - 5.png - 3.png - 2.png |----val - 4.png |----test - 1.png |----annotations |----train - 5.txt - 3.txt - 2.txt |----val - 4.txt |----test - 1.txt
これで、データが整いました。物体検出モデルを見てトレーニングを開始しましょう。
現在の物体認識のゴールドスタンダード (パフォーマンスと使いやすさの点で) は、YOLO (You Only Look Once) クラスのモデルです。この記事の執筆時点では、YOLOv8 が最新バージョンであり、Ultralytics によってオープンソースとして維持されています。 YOLOv8 は、新しく作成したアノテーションでモデルをトレーニングする (最終的には推論も実行する) ために利用できるシンプルな API を提供します。
YOLOv8 をダウンロードしましょう。
$ pip install ultralytics
YOLOv8 CLI ツールまたは Python SDK を使用して、トレーニング、検証、予測できるようになりました。詳細については、YOLOv8 のドキュメントを参照してください。
作業ディレクトリで、データセットの場所とクラスの詳細を指定する YAML ファイルを定義します。パスが作業ディレクトリ内に以前に作成したものと同じであることに注目してください。ファイルに「 objdetect.yaml 」という名前を付けました。また、2 つの航空機クラス ラベルは CVAT の場合と同じ順序で定義する必要があることに注意してください。
train: ./dataset/images/train/ val: ./dataset/images/val/ test: ./dataset/images/test/ # number of classes nc: 2 # class names names: ["SU-30","TU-95"]
次のコマンド (YOLO CLI ツールを使用) を使用して、データセットで YOLOv8 モデルのトレーニングを開始します。トレーニング用に構成できるさまざまなオプションの詳細については、YOLO のドキュメントを参照してください。ここでは、100 エポックのトレーニングを開始し、画像サイズを 640 ピクセルに設定しています (すべてのトレーニング画像はトレーニング中にそれに応じてスケーリングされます)。
$ yolo task=detect \ mode=train \ model=yolov8s.pt \ data=objdetect.yaml \ epochs=100 \ imgsz=640
特にラップトップで作業している場合 (私のように)、トレーニングには時間がかかるので、今が休憩を取る (または先を読む 😀) 良い時期です。
トレーニング ループの最後に、トレーニングされたモデルは、他の興味深いグラフやチャートとともに、「runs」と呼ばれる自動生成されたディレクトリに保存されます。ターミナル出力 (以下のような) には、最新の実行結果の特定の場所が示されます。モデルをトレーニングするたびに、同様のディレクトリが「runs/detect/」内に生成されます。
Results saved to runs/detect/train
注: run/detect/train/weights/ には、正確にトレーニングされた重みを含む PT ファイルが含まれます。後で使用するためにこの場所を覚えておいてください。
次のコマンドを使用して検証を実行できます。
$ yolo task=detect \ mode=val \ model=path/to/best.pt \ data=objdetect.yaml
結果は、「runs/detect/val」形式のパスを持つ作業ディレクトリ内のフォルダーに自動的に保存されます。
テスト セットで推論を実行するには、次のコマンドを使用できます。
$ yolo task=detect \ mode=predict \ model=path/to/best.pt \ conf=0.5 \ source=dataset/images/test
結果は「runs/detect/predict」に保存されます。テスト セットの予測結果の一部を次に示します。
衛星画像に存在するいくつかの航空機タイプを認識できるトレーニング済みモデルができました。それを新しい画像に簡単な方法で利用するにはどうすればよいでしょうか?
MinIO Bucket Notices はこれに最適なツールです。 Webhook を利用して、バケットにドロップされた新しい画像に対してオブジェクト検出推論を自動的に実行できるシステムを構築できます。
大まかに言うと 3 つのステップがあります。まず、トレーニングされたモデルを使用して新しい画像上でオブジェクト検出を実行するための Webhook として機能できるエンドポイントを定義する必要があります。次に、何らかのイベントが発生したときに Webhook エンドポイントにヒットするように指示する MinIO Server デプロイメント用の環境変数を構成する必要があります。 3 番目に、どのタイプのバケット イベント (つまり PUT) に作用するかを設定する必要があります。段階的に見ていきましょう。
以下は、MinIO バケットに追加された新しいイメージに対して推論を実行する、単純な Flask ベースのサーバー ( detect_server.py ) のコードです。
""" This is a simple Flask inference server implementation that serves as a webhook for the event of a new image being added to a MinIO bucket. Object detection using YOLO will be performed on that image and the resulting predictions will be returned. """ from flask import Flask, request, abort, make_response from ultralytics import YOLO import tempfile from minio import Minio # Make sure the following are populated with your MinIO details # (Best practice is to use environment variables!) MINIO_ENDPOINT = '' MINIO_ACCESS_KEY = '' MINIO_SECRET_KEY = '' model = YOLO('/PATH/TO/best.pt') # load a custom model (path to trained weights) client = Minio( MINIO_ENDPOINT, access_key=MINIO_ACCESS_KEY, secret_key=MINIO_SECRET_KEY, ) app = Flask(__name__) @app.route('/', methods=['POST']) async def inference_bucket_webhook(): """ This endpoint will be called when a new object is placed in your inference bucket """ if request.method == 'POST': # Get the request event from the 'POST' call event = request.json bucket = event['Records'][0]['s3']['bucket']['name'] obj_name = event['Records'][0]['s3']['object']['key'] with tempfile.TemporaryDirectory() as temp_dir: temp_file_name = temp_dir+'/'+obj_name client.fget_object(bucket, obj_name, temp_file_name) # See https://docs.ultralytics.com/modes/predict/ for more information about YOLO inference options results = model.predict(source=temp_file_name, conf=0.5, stream=False) # A list of bounding boxes (if any) is returned. # Each bounding box is in the format [x1, y1, x2, y2, probability, class]. result = {"results": results[0].boxes.data.tolist()} print(result) resp = make_response(result, 200) return resp else: abort(400) if __name__ == '__main__': app.run()
推論サーバーを起動しましょう。
$ python detection_server.py * Serving Flask app 'detection_server' * Debug mode: off * Running on http://127.0.0.1:5000 Press CTRL+C to quit
Flask アプリケーションが実行されているホスト名とポートをメモします。
次に、MinIO 側で Webhook の構成を開始しましょう。まず、以下の環境変数を設定します。 <YOURFUNCTIONNAME> を、選択した関数名に置き換えます。わかりやすくするために、 「推論」を使用しました。また、エンドポイント環境変数が推論サーバーの正しいホストとポートに設定されていることを確認してください。この場合、http://localhost:5000 が Flask アプリケーションが実行されている場所です。
$ export MINIO_NOTIFY_WEBHOOK_ENABLE_<YOURFUNCTIONNAME>=on $ export MINIO_NOTIFY_WEBHOOK_ENDPOINT_<YOURFUNCTIONNAME>=http://localhost:5000
次に、コマンドmc admin service restart ALIASを使用して MinIO サーバーを再起動します。サーバーを初めて起動する場合は、単にminio サーバーコマンドを使用することもできます。 MinIO サーバーの再起動の詳細については、MinIO のドキュメントを参照してください。注: ALIAS は、MinIO サーバー展開のエイリアスに置き換える必要があります。エイリアスを設定する方法、または既存のエイリアスを表示する方法の詳細については、ドキュメントを参照してください。
最後に、通知を受け取りたいバケットとイベントを追加しましょう。私たちの場合、バケット内の「 put」イベント (新しいオブジェクトの作成) について通知を受け取りたいと考えています。この目的のために「detect-inference」という名前の新しい空のバケットを作成したので、それを「BUCKET」に置き換えます。
$ mc event add ALIAS/BUCKET arn:minio:sqs::<YOURFUNCTIONNAME>:webhook --event put
次のコマンドを実行したときに「 s3:ObjectCreated:* 」が出力されるかどうかを確認することで、バケット通知の正しいイベント タイプが設定されていることを確認できます。
$ mc event ls local/detect-inference arn:minio:sqs::<YOURFUNCTIONNAME>:webhook
バケット イベントを Webhook に公開する方法の詳細については、 ドキュメントを参照してください。これで、新しい画像に対して物体検出を試す準備が整いました。
これが推論を行う新しい画像 (「1.png」というタイトル) です。
新しい画像を「detect-inference」バケットにドロップします。
ほぼ即座に、Flask サーバー上で次の結果を確認できます。
$ python detection_server.py * Serving Flask app 'detection_server' * Debug mode: off * Running on http://127.0.0.1:5000 Press CTRL+C to quit image 1/1 /var/folders/xf/q7x0z8sn5nvckccp1g0m1vpm0000gn/T/tmpo6jx3w8u/1.png: 448x736 2 SU-30s, 101.0ms Speed: 4.1ms preprocess, 101.0ms inference, 5.8ms postprocess per image at shape (1, 3, 448, 736) {'results': [[1927.78369140625, 627.7123413085938, 1995.090576171875, 715.3443603515625, 0.8142037987709045, 0.0], [1735.740234375, 477.2108154296875, 1809.181640625, 555.767578125, 0.7766116261482239, 0.0]]} 127.0.0.1 - - [14/Sep/2023 15:39:21] "POST / HTTP/1.1" 200 -
結果リスト内の検出された各境界ボックスは、YOLO 形式 [x1、y1、x2、y2、確率、クラス] であることに注意してください。元の画像に重ね合わされた境界ボックスと予測クラスは次のとおりです。
注: 運用環境や大規模な機械学習モデルの場合は、PyTorch Serve や Triton Server などの確立されたモデル提供フレームワークを使用して、推論の堅牢性と信頼性を高めることをお勧めします。これに興味がある場合は、 「MinIO と PyTorch Serve を使用した AI モデル サービングの最適化」に関する前回の投稿を参照してください。
やった! MinIO と CVAT がどのように連携して収集された画像サンプルを安全かつ利用可能に保つか、またカスタムの物体検出データセットを作成する方法について説明しました。次に、カスタム タスク用に独自のカスタム YOLO モデルをトレーニングしました。最後に、50 行強のコードで、カスタム トレーニングされたオブジェクト検出モデルを超えて新しい画像を実行できる MinIO バケット通知を使用する推論サーバーを組み立てました。
さらに、コンピューター ビジョンのほとんどのミッション クリティカルなアプリケーションでは、エッジで推論を実行するのが最善です。そうしないと、前述のアプリケーションは、ネットワーク接続障害のリスクは言うまでもなく、新しいデータをパブリック クラウドにアップロードし、クラウド内の推論サーバーから応答が返されるのを待つことに関連する遅延に対して脆弱になります。このため、データ層として MinIO を中心としたコンピューター ビジョン パイプラインの方がはるかに合理的です。飛行場上空を飛行するドローンが、完全に搭載されたハードウェアとソフトウェアを使用して、トレーニング済みのモデルをキャプチャ、保存し、新しい画像上で使用できることを想像してください。 MinIO サーバーのローカル展開により、この投稿の最後で構築したバケット通知ベースの推論システムは、このシナリオだけでなく、同様の他の無数のシナリオでも完璧に機能します。
ご質問がある場合は、 Slack チャンネルに参加するか、 [email protected]にメモを送ってください。私たちはあなたを助けるためにここにいます。
ここでも公開されています。