コンテンツにスキップ

AI のスケジューリング、統計、16 カメラでの評価

NVR には、60 秒の移動ウィンドウで集計する AI Statistics タブがあります。完了した処理の実時間の平均、P50、P95、最大値、平均待ち時間、1 秒あたりの呼び出し回数、論理バッチサイズ、未処理の作業量、累積の破棄数を表示します。サマリーは全カメラをまとめた値で、詳細のセレクターでは個々のカメラを選べます。カメラの表には、検出/トラッキングの更新レート、確定した人物数、トラッキング対象フレームの経過時間を表示します。

検出/トラッキングの頻度は、カメラごとに 0.1 ~ 10 Hz の範囲で 0.1 Hz 刻みで変更できます。埋め込みの間隔は、人物ごとに 0.1 ~ 60 秒の範囲で 0.1 秒刻みで変更できます。Enter キーを押すか入力欄から離れると変更が適用されます。変更はすぐに反映され、現在の設定に保存されます。実際の埋め込み間隔は要求した間隔より長くなる場合があるため、その値もあわせて表示します。

実行ポリシー

検出・追跡の頻度とEmbeddingの間隔で処理を調整します。モデル間で共有するGPU実行枠、優先度の引き上げ、使用率による待機、EmbeddingGemmaの20%自動制限、間隔の自動延長は廃止しました。各バックエンドは常駐ワーカーを1つ持ち、実行中ジョブを最大1件とし、モデルごとの排他は維持します。旧設定のmobileclip_gpu_budget_percentとmobileclip_npu_budget_percentは有効な値なら警告付きで読み込みますが、動作には使わず、保存時にも出力しません。

前処理、バッチの組み立て、MIGraphX推論、後処理、サムネイルは独立したnonblocking HIPストリームを使います。完了待ちは対象ストリームか準備完了イベントに限定します。ストリーム順序付きメモリ確保では、解放まで所有ストリームを保持します。MIGraphXはrun_asyncの後で自身のコンテキストとストリームの完了を待ち、呼び出し元には完了済みの結果を返します。 環境スクリプトとNVRの初期化は、HIP初期化前にGPU_MAX_HW_QUEUESの既定値を32に設定します。明示された値は維持します。HIPの既定値は4で、別々のストリームでも同じハードウェアキューに割り当てられ、待ちが伝わることがあります。AMDのHIP環境変数の説明も参照してください。独立性の契約テストでは、無関係なストリームをGPUセマフォで停止し、その解除前に推論が完了することを確認します。

ReIDではROIが変わってもVPEコンテキストを再利用します。固定したMesaの実装は倍率の変更時に係数を計算し直します。従来は人物ごとにコンテキストを作り直す処理が前処理の大半を占め、ほかの処理も待たせていました。ROIやバッチを切り替えても、初期状態での特徴量に対するコサイン類似度が0.9999以上で一致することを確認します。サムネイルのPNGはlibpngの高速フラグと出力サイズ上限を使い、サイズを調べるための圧縮を省いて1回だけ圧縮します。可逆圧縮なので画素値は維持します。前処理の名前空間、モデルの重み、DBスキーマも維持します。PNGの圧縮後サイズは増える場合がありますが、録画の容量制限には引き続き計上します。

カメラは設定のソース順に、コンパイル済みバッチサイズごとのグループに分け、周期内で開始時刻をずらします。遅れた周期は飛ばし、過去分をまとめて投入しません。入力は各カメラの最新フレームです。追跡の待機キューは最大16カメラで、同じカメラの新フレームが古いものを置き換えます。Embeddingは人物ごとに最新の対象画像を保持し、上限はsearch.queue_limit(既定128)です。立ち去った人物は期限切れにし、同じ画像は再計算しません。初回はすぐに実行可能とし、以降は要求した間隔を使います。ハードウェアの処理能力を超える設定では実際の頻度が下がる場合があります。

Embedding first result、Embedding update interval(継続して対象になっている人物)、Embedding freshnessに実際の遅延を記録します。期限超過には未処理の要求も含め、置換数とキューの破棄数で過負荷を確認できます。

トラッカーは、既存の高信頼度/低信頼度の対応付けと外観のしきい値をそのまま使います。低スコアからの復帰のために検出信頼度 0.1 は引き続き使えますが、新しい ID には引き続き 0.6 と確定が必要です。search.min_person_height(既定は 0.1)は、ソースフレームの高さに対してこの割合より背の低い人物を、切り出し/ReID/検索の処理から除外します。今回のデモでは遠くの小さな人物をインデックスに登録する必要がないため、この設定が適しています。

YOLO の前処理、推論、後処理、実行器の合計は別々の行に表示します。重なりのある行を合計しないでください。実行器の合計はその構成要素を含み、検出の更新はスケジューリングを表すもので、追加の推論処理ではありません。1 回の ReID 呼び出しで複数の物理バッチを処理する場合があり、平均バッチの列はそのフレーム内の実際の人物数です。キューの待ち時間には意図的なペース調整が含まれます。カメラごとの検出/トラッキングの待ち時間はフレームの経過時間を表します。破棄カウンターは、異なる人物の数ではなく、拒否または置き換えた作業項目の数です。キューが満杯の間は、1 人の人物について多くの候補がスキップされることがあります。モデルの読み込みとウォームアップは除外しています。これらは実時間の計測値であり、GPU イベントによる使用率カウンターではありません。サンプル数と行数には上限があります。

NPU Embeddingの時間計測

Image embedding NPUとNPUの概要表示には、GPU前処理が完了した後の推論呼び出し時間を表示します。GStreamer/ORTの呼び出しと小さい推論結果の処理は含みますが、入力の前処理は含みません。

行 実行時間 待ち時間の列
Image embedding NPU preprocess HIPでの入力準備 起動のオーバーヘッド(アプリの実行枠なし)
Image embedding NPU NPU推論の呼び出し 0
Image embedding NPU total 前処理+推論 0

共通のImage embedding行は、デバイスのジョブ全体の時間です。これらの行は重複するので合計しないでください。意図的な待機時間は加えていません。

実行枠を廃止する前の17ソースのデモでは、合計311.27 msの内訳が、GPU待ち297.85 ms、前処理0.53 ms、推論12.89 msでした。ORTのプロファイルでも13回すべての画像推論をVitisAIExecutionProviderに割り当てており、ノードの平均時間は12.42 ms、CPU EPのノードは0でした。以前のNPU行にはGPUの順番待ちも含まれていたため、約300 msという表示はNPUの計算時間ではありません。時間計測の検証記録も参照してください。

実行時はCPU EPへのフォールバックを無効にしています。Ort::MemoryInfo::CreateCpuは共有ホスト入力領域の指定であり、実行するEPの選択ではありません。画像セッションのORTプロファイルを採取する場合は、起動前にAMDVA_NPU_PROFILE_PREFIXへ既存ディレクトリ内のファイル接頭辞を指定します。ファイル名にPIDとセッション識別子を付け、画像セッションの解放時に保存します。テキストセッションは採取対象外です。

mkdir -p artifacts/npu-profile
AMDVA_NPU_PROFILE_PREFIX="$PWD/artifacts/npu-profile/image" \
  examples/nvr/scripts/run.sh /path/to/nvr-config.json

この確認はORTのEP割り当てまでを対象とし、Vitis AI内部は調査していません。

選定した構成

段階 モデル/入力(幅 × 高さ) バッチ 理由
検出 YOLO11n FP16, 640 × 384 1/4 確認済みのデモフレームで YOLOv8n より高信頼度の再現率が高く、入力を縮小した長方形にできるため
ReID OSNet x0.25 MSMT17 FP16, 128 × 256 4 人物の高さ全体を保ったまま推論コストを下げられるため
セマンティック画像 EmbeddingGemma 2 native ROCm, 108 × 192, token budget 70 最大 4 縦長の入力で、ブロックする時間に上限を設けられるため

ランタイムは、各軸 640 までの YOLO の長方形サイズと、高さ 64–256、幅 32–128 の ReID バッチ 1–16 に対応しています。コンパイル済みモデルのテンソルの契約を検証します。YOLO11 には既存の YOLOv8 系の出力デコーダーを使います。YOLOX Nano は専用のデコーダーで別途ベンチマークしましたが、採用せず、ライブ用モデルと交換可能な出力形式としても受け付けません。

推奨する検索設定は次のとおりです。

{
  "ai_fps": 2,
  "search": {
    "image_size": 256,
    "interval_ms": 5000,
    "queue_limit": 128,
    "embedding_width": 108,
    "embedding_height": 192,
    "embedding_batch": 4,
    "min_person_height": 0.1
  }
}

examples/nvr/config/nvr-ai-16.json は 16 ソースの完全なサンプルで、長方形入力の検出器のメタデータには examples/nvr/config/yolo11n-rect.json を使います。起動する前に、参照しているモデルとネイティブバンドルを用意してください。

これらのフィールドは、通常の NVR 設定にあるライブラリ、バンドル、モデルのパスに追加するものです。image_sizeは保存するRGB画像の大きさの上限です。ReIDはこの上限とは独立して、元のVAフレームのROIをamdpreprocで前処理します。埋め込みにはこれとは別に、縦横比を保った小さめの入力を使い、黒で余白を埋め、拡大はしません。埋め込みの 2 つの寸法は両方とも設定する必要があります。両方を 0 のままにすると、従来の正方形の前処理の名前空間を維持します。収集間隔は 100 ms まで、要求した目標どおりに扱います。すべてのEmbeddingバックエンドで同じ間隔を使います。前処理または ReID の重みを変更すると、別の検索名前空間を選択します。古い観測結果はカタログに残り、元の設定で検索できます。自動で過去分を埋め直す機能はありません。

人物検索 に記載した、固定版の embeddinggemma2-rocm ソースと対応する ROCm/LibTorch を使い、バッチ 1、2、4、8 の縦長のネイティブプロファイルを用意してください。テキスト用のプロファイルはバンドルに残しておきます。例を次に示します。

eg2 prepare --model /path/to/google --output artifacts/embedding-portrait \
  --budgets 70 --batches 1 2 4 8 --aspect 9 16 --precision fast

examples/nvr/scripts/merge_embedding_profiles.py は、互換性のある準備済みバンドルをローカルのシンボリックリンクで結合します。ランタイムは、画像のバッチが埋まらない場合、最後の有効な画像を繰り返して埋め、余分な出力を破棄します。領域クエリでも同様です。これにより、固定の物理画像プロファイルを 1 つだけ常駐させます。そうしないと、ネイティブライブラリはバッチの形状を切り替えるたびに画像プロファイルを再読み込みします。このプロファイルはカメラの開始前にウォームアップします。テキストの推論には別のプロファイルキャッシュを使います。

計測の再現

ネイティブのベンチマークと検証の実行ファイルには、AMDVA_HARDWARE_TESTS=ON で構成したビルドが必要です。GPU のテストは、NVR を停止した状態で 1 つずつ順に実行してください。結果とあわせて、マシンの電源設定を記録してください。電源設定を変更する前に取得した時間は、最終的な比較に使わないでください。

source scripts/env.sh
.deps/model-export/bin/python examples/nvr/scripts/benchmark_ai.py --screen
# Select finalists, then rerun cached models with 20 warmups and
# at least 200 iterations AND 30 seconds, repeated three times:
.deps/model-export/bin/python examples/nvr/scripts/benchmark_ai.py \
  --models yolo11n --sizes 640x384 --batches 1 4 --remeasure
.deps/model-export/bin/python examples/nvr/scripts/benchmark_ai.py \
  --models osnet_x0_25 --sizes 128x256 --batches 1 4 --remeasure
python3 examples/nvr/scripts/benchmark_embedding.py --library /path/to/libeg2.so \
  --bundle /path/to/prepared-bundle --sizes 108x192 --batches 4

検出器/ReID のベンチマークは、入力を常駐させた状態でモデルの実行だけを計測します。ネイティブの埋め込みの計測には、前処理と出力の転送が含まれます。パイプライン全体の統計では、切り出し、前処理、キューの時間を別々に集計します。ReIDの前処理は、CPUリサイズに代わってamdpreprocのVPE/HIP経路を計測します。--seconds 3 --repeats 1 は探索的なふるい分けには役立ちますが、最終的な性能の計測にはなりません。コンパイル済みの成果物と成功した結果はキャッシュします。新しい出力はアトミックに名前を変更するため、中断した実行を再開できます。

examples/nvr/benchmarks/person-review.json には、16 フレームから目視で確認した 53 個のボックスが含まれます。examples/nvr/benchmarks/appearance-review.json には、確認済みの人物の切り出し画像 52 枚が含まれます。~/work/videos から、独立した 1080p のコピーと品質確認用のテスト用素材を作成します。

.deps/model-export/bin/python examples/nvr/scripts/prepare_ai_fixture.py

ユーザーによると、元の 10 分間の映像 16 本に登場する人物は合計 40 人です。負荷試験用の短い抜粋では、10 分間全体を通じた人物の同一性は確認できません。ループの切れ目やカメラごとに独立した ID のため、ID の数が増えることがあります。元の映像は変更しません。品質確認スクリプトでは、信頼度 0.1/0.5/0.6 での検出器の再現率、ReID の検索とネイティブ FP16 との一致、埋め込みの入力サイズごとのテキスト検索を比較します。これらはデモに特化した小規模な確認であり、網羅的なアノテーションや、時系列のトラッキングを評価する IDF1 ベンチマークではありません。正式な IDF1 の評価と、最悪ケースの 16 × 8 人が同時にいる負荷は、別途検証が必要です。埋め込みの画素数を減らしても、トークン予算とネイティブの内部プロファイルの影響が残るため、モデルの実行時間は比例して減りません。

統合試験では、テスト用素材の一覧を配信し、専用の録画ルートを使ってください。

build/examples/rtsp-files/amdva-rtsp-files \
  --list artifacts/ai-benchmark/videos.txt --port 18569
# In another terminal with the native runtime environment configured:
build/examples/nvr/amdva-ai-validate examples/nvr/config/nvr-ai-16.json 1800 \
  artifacts/ai-benchmark/soak.jsonl

検証ツールは、頻度の設定と保存された設定を試験し、全カメラ表示、4 カメラ表示、全カメラ非表示の各フェーズを実行して、5 秒ごとの JSON スナップショットを記録し、最後に統計画面をキャプチャします。すべてのカメラで推論が継続していることと、セマンティックな観測結果が保存されていることを確認します。各フェーズの安定した区間で、レート、キュー、メモリの挙動を確認してください。ログには起動時の区間も含まれます。テキスト検索、人物のグループ化、領域検索、インライン再生、削除の確認には、別の 2 カメラ用テスト用素材で amdva-search-validate を使ってください。

このホストでの計測結果

最終的な単独計測は 2026-10-22 に、ユーザーがマシンの電源設定を下げた後、Ryzen AI 9 HX 370 / Radeon 890M (gfx1150)、カーネル 6.17.0-1033-oem で実施しました。BIOS の正確な電力上限は記録していません。3 回の繰り返しで、平均バッチ時間は次のようになりました。

モデル/入力 バッチ バッチあたり ms 画像あたり ms
YOLOv8n 640 × 640(ベースライン) 4 9.705 2.426
YOLO11n 640 × 384 1 1.553 1.553
YOLO11n 640 × 384 4 5.549 1.387
OSNet x1.0 128 × 256(ベースライン) 1 1.400 1.400
OSNet x0.25 128 × 256 1 0.690 0.690
OSNet x0.25 128 × 256 4 1.206 0.302
埋め込み 384 × 384(ベースライン) 1 52.394 52.394
埋め込み 108 × 192 4 195.666 48.917

ここでの埋め込みの削減は、画像あたり約 7% にとどまります。約 196 ms かかる横取りできないバッチが依然として最大の推論区間であるため、画素数を減らすよりも、頻度とペース調整の影響のほうが大きくなります。この単独計測のコストでは、128 人がアクティブな場合、20% の占有率の予算に収めるには埋め込みの間隔を約 31 秒にする必要があり、旧実装では適応間隔が60秒になりました。この自動制限は廃止しています。この計算は推定であり、128 人での実測のスループットではありません。

確認済みの 53 ボックスのサブセットでは、YOLO11n 640 × 384 は信頼度 0.1 で 52 個、0.5 で 51 個、0.6 で 49 個のボックスに一致しました。YOLOv8n の 640 正方形のベースラインは 53/45/42、YOLOX Nano は 45/38/33 で、YOLOX Nano は不採用としました。ネイティブ FP16 の YOLO11 でも 52/51/49 という同じ数を再現しました。確認済みの切り出し画像 52 枚でのネイティブ ReID の rank-1 は、採用した OSNet x0.25 で 84.6%、x1.0 で 82.7% でした。64 × 128 では x0.25 の結果が 55.8% に下がったため、高さ全体の入力を維持しました。11 件の服装のクエリでは、セマンティックの平均 Recall@5 は 108 × 192 で 82.6%、384 正方形で 66.7% でした。どちらの形状でも、すべてのクエリで上位 5 件に関連する結果が少なくとも 1 件含まれていました。これらの小規模なテスト用素材はデモ用の選定を裏付けますが、一般的な精度を示すものではありません。

繰り返し計測の生の統計と品質確認結果の要約は、最終的な時間 と品質確認 としてリポジトリに含めています。初期のより広い組み合わせでは、主にバッチ 1 と 4 で短い探索的な実行を行いました。検出器/ReID のバッチ 8/16 のコンパイルはホストの再起動で中断したため、完了した比較としては扱っていません。検証済みのライブ構成はバッチ 4 です。

16 カメラでの統合試験の結果

1,804 秒の実行では、全カメラ表示、4 カメラ表示、全カメラ非表示の各フェーズを 10 分ずつ完了し、実際のカメラ選択とスロットの状態に照らして確認しました。安定した区間では、すべてのカメラの検出とトラッキングのレートが 1.983 ~ 2.017 Hz に収まりました。16 台すべてのカメラで観測結果が保存されました。累積の保存数は 5,401 件で、5 分の保持期間により古い行は意図的に削除されます。安定した区間の常駐メモリは 6,300 ~ 6,318 MiB で、起動時を含む RSS のピークは 7,381 MiB でした。この実行では、カメラ/検索のエラーやホストの再起動は発生しませんでした。埋め込みのキューは 128 以下に収まりました。負荷がかかると候補のスキップが発生し、実際の間隔はおおむね 30 秒でした。この結果から、すべての人物を 5 秒ごとにカバーできるとは言えません。

最終的なスクリーンショットから、非表示カメラの継続的な解析で、デコード済みフレームのタイムスタンプが設定されていないことが分かりました。この問題は表示上のフレーム経過時間/待ち時間に影響し、モデルの実行時間や更新回数には影響しません。現在はデコード済みフレームにタイムスタンプを設定し、検証ツールは古いトラッキングのタイムスタンプを明示的に拒否します。長時間実行のレポートでは、混在/非表示フェーズの無効なフレーム経過時間の待ち時間フィールドを省いています。その後の 120 秒の検証は 3 つのモードすべてで合格し、トラッキングの経過時間は 71 ~ 726 ms でした。30 分の実行全体を通じて、トラッキングのキューでの破棄は 0 件でした。

統合試験の結果 を参照してください。ソースのテスト用素材は 30 秒の 1080p の抜粋 16 本で、10 分間の元の映像全体ではありません。このスループットの実行も、確認済みの静止画のサブセットも、IDF1 を示すものではなく、40 人の実在の人物がソース映像全体を通じて 1 つの ID を保つことも示していません。トラッキングは引き続きカメラごとに独立しています。

頻度設定による構成の検証

固定負荷の設定例はexamples/nvr/config/nvr-frequency-17.jsonです。起動時にAMDVA_RYZEN_AI_VENVで準備済みのRyzen AI環境を指定します。入力サーバーのポートは18570(16動画)と18572(ダッシュボード)です。RTSPの検証入力を起動し、libamdva_copy_audit.soをプリロードしてamdva-scheduling-validate CONFIG [SECONDS=120]を実行します。15秒ウォームアップした後、17入力・16選択、検出と追跡4Hz、Embedding間隔3000msの固定構成を測定します。バックエンド測定の再現性のためプレビューは無効にします。検証器は設定頻度を下げません。カメラごとの検出頻度、対象フレーム全件に対する追跡完了率、移動窓P95の最大値、未処理要求を含む期限超過を報告します。目標は検出が設定頻度の90%以上、追跡が対象の90%以上、NPU前処理開始から推論完了までのP95が50ms以内、初回Embeddingが1秒以内、継続対象の更新間隔P95が要求間隔の1.2倍以内です。未処理の期限超過も失敗として扱います。

バックエンド検証器を直接起動する場合も、先にRyzen AI環境を初期化します。

source scripts/env.sh
source examples/nvr/scripts/mobileclip-env.sh "$AMDVA_RYZEN_AI_VENV"
LD_PRELOAD="$PWD/build/src/gst/libamdva_copy_audit.so" \
  build/examples/nvr/amdva-scheduling-validate examples/nvr/config/nvr-frequency-17.json

実測結果と残る制約

頻度設定による構成の検証記録は、17入力・16選択、4Hz、3000msの設定を下げずに測定したものです。ウォームアップ後120.634秒で、追跡対象8134フレームの全件を処理し、待機フレームの破棄はありませんでした。NPU前処理開始から推論完了までの移動窓P95の最大値は19.69msで、アプリの入力コピーとコピー監査違反は0件でした。

期限の全基準には合格していません。 初回の期限超過が8件、更新の期限超過が6件ありました。初回の最大遅延は3074ms、継続対象の更新間隔の最大値は5083msで、NPUジョブにも約2098msかかった例があります。同じ実行中の22:52:07 JSTに、カーネルはコンテキスト10でamdxdna ... aie2_tdr_detect: TDR timeout detectedを記録しました。前の測定ではERT_CMD_STATE_TIMEOUTも返りました。常駐ワーカー化だけではこの遅延は解消していません。NPUの実行境界に問題が残っており、プロバイダーやファームウェア内部の調査と恒久対策は今回の変更には含めていません。フォールバック、頻度の自動引き下げ、失敗を隠す再試行、合格基準の緩和は加えていません。

VPEコンテキスト再利用後の30秒試験は全基準を満たしましたが、長い測定の不合格を置き換えるものではありません。基準の測定ではプレビューを無効にしています。GUIの別試験では描画や検索の動作を確認しますが、同じ17入力の遅延を保証するものではありません。高速な可逆PNG圧縮により、サムネイルの格納容量は増える場合があります。

ReIDの起動状態と実行回数

人物追跡のtracking_state/tracking_errorを、Embedding・検索のstate/errorから分離しました。Embeddingモデルの読み込みやウォームアップに失敗しても、試行したHIPグラフキャプチャが終了した後でReIDワーカーを起動します。追跡が準備できていれば、検出結果を追跡へ渡します。途中でEmbeddingが失敗した場合は、そのバックエンドと待機画像の投入を停止し、確定済みの人物IDと追跡の更新は継続します。プロバイダーのエラーは表示し、Embeddingの検索要求には明示的にエラーを返します。CPUや別デバイスへのフォールバックは行いません。

AI詳細表のSamples (60s)は直近60秒のサンプル件数なので、一定の負荷では数値が増えなくなることがあります。Completed (total)には、このプロセスで完了した処理の累積件数を表示します。ReIDが実行され続けているかは後者で確認できます。追跡の準備状態とエラーも、Embeddingとは別に表示します。

reid-isolation-contractでは、Embeddingの読み込み、ウォームアップ、実行途中の失敗を意図的に発生させ、それぞれのケースで実際のGPU ReID推論を6回処理し、確定した人物IDを維持することを確認します。AMDVA_HARDWARE_TESTS=ONに加え、AMDVA_TEST_VIDEOとAMDVA_REID_TEST_MODELに準備済みのH.264動画とOSNetモデルを指定すると有効になります。障害を起こすライブラリはテスト専用です。amdva-reid-demo-validate CONFIG SECONDS OUTPUT.jsonlでは、実際のGUIでReIDの進行、最新の確定人物ID、累積件数の表示を確認し、Embeddingのエラーはログに残します。この検証はReIDの利用可否を確認するもので、Embeddingの成功を保証するものではありません。ReIDの障害分離の検証記録も参照してください。