モデルオプションの設定
| 項目 | 値 |
|---|---|
| カテゴリ | モデルと推論 |
| 難易度 | 初級 |
| 推定所要時間 | 5 minutes |
| ラベル | model-options, configuration, contracts |
第 001 章では、適切なデフォルト値を持つモデルをロードします。特に YOLOv8 のような検出モデルの場合、入力がどのようなピクセル形式とサイズで到着するか、どのように正規化されるか、そして生のネットワーク出力がどのようにフィルタリングされたボックスに変換されるかを 宣言 する必要があります。ModelOptions は、それらすべてを 1 つの構造体にまとめ、構築前に値を設定します。
この章では、YOLOv8 モデルを最初から最後まで設定し、次にランタイムがこれらのオプションから解決した契約を調べます。最後に、入力、前処理、および後処理のパラメータを設定し、解決された input_specs()/output_specs()/metadata を読み取り、設定されたモデルを通じて 1 つの決定的なフレームを実行します。
ウォークスルー
入力と前処理を宣言
最初のブロックでは、フレームがどのようなもので、ネットワークに備えるためにどのように準備するかを記述します。format (BGR、ここでは) と input_max_width/height/depth の範囲は、ランタイムが検証し、バッファのサイズを決定する入力契約を設定します。正規化フィールドは、モデルがトレーニングされたときに使用された、チャネルごとの平均値と標準偏差を提供するため、生のピクセルはネットワークが期待する範囲にスケーリングされます。
フィールドは opt.preprocess.* の下にあります: kind = InputKind::Image、color_convert.input_format = PreprocessColorFormat::BGR、および normalize.enable = AutoFlag::On。mean/stddev は std::array<float, 3> として定義されます。
opt.preprocess.kind = simaai::neat::InputKind::Image;
opt.preprocess.color_convert.input_format = simaai::neat::PreprocessColorFormat::BGR;
opt.preprocess.input_max_width = 640;
opt.preprocess.input_max_height = 640;
opt.preprocess.input_max_depth = 3;
opt.preprocess.normalize.enable = simaai::neat::AutoFlag::On;
opt.preprocess.normalize.mean = std::array<float, 3>{0.485f, 0.456f, 0.406f};
opt.preprocess.normalize.stddev = std::array<float, 3>{0.229f, 0.224f, 0.225f};
後処理を宣言
2 番目のブロックは、検出器の出力を調整します。decode_type は YOLOv8 ボックスデコードパスを選択し、score_threshold、nms_iou_threshold、および top_k は生の検出をフィルタリングします。これにより、信頼度の低いボックスが削除され、重複するボックスがマージされ、残るボックスの数が制限されます。boxdecode_original_width/boxdecode_original_height は、デコーダーに、正規化された座標をピクセルにマッピングするために必要なソースフレームのジオメトリを提供し、name_suffix は生成されたステージ名を安定化させ、他のものと組み合わせたときにパイプラインのグラフが読みやすくなるようにします。
decode_type = BoxDecodeType::YoloV8。ジオメトリフィールドは boxdecode_original_width/boxdecode_original_height です。
opt.decode_type = simaai::neat::BoxDecodeType::YoloV8;
opt.score_threshold = 0.55f;
opt.nms_iou_threshold = 0.45f;
opt.top_k = 100;
opt.boxdecode_original_width = 640;
opt.boxdecode_original_height = 640;
opt.name_suffix = "_chapter";
解決されたコントラクトをロードして確認する
これらのオプションを使用して Model を構築すると、コントラクトがモデルアーカイブに対して解決されます。次に、それを読み戻します。input_specs() と output_specs() は、ネゴシエートされたテンソルの制約を報告し、metadata() は、アーカイブに組み込まれたキー/値のコントラクトを公開します。ロード後にこれらを検査することで、ランタイムがオプションを受け入れたこと、および使用する具体的な形状が確認され、それらの形状がわかります。
仕様は TensorConstraint の値です。具体的な形状を出力します。
simaai::neat::Model model(model_path, opt);
print_spec("input_specs[0]", model.input_specs().front());
print_spec("output_specs[0]", model.output_specs().front());
std::cout << "metadata_keys=" << model.metadata().size() << "\n";
1フレームを実行する
最後に、640×640 の BGR フレームを合成し、構成されたモデルを通して実行し、コントラクト全体が最初から最後まで実行されることを確認し、出力されたテンソルの数を表示します。
フレームは cv::Mat です。run() は TensorList を返し、その size() を outputs= として出力します。
cv::Mat bgr(640, 640, CV_8UC3, cv::Scalar(10, 20, 30));
if (!bgr.isContinuous())
bgr = bgr.clone();
auto out = model.run(std::vector<cv::Mat>{bgr}, /*timeout_ms=*/2000);
if (out.empty())
throw std::runtime_error("model produced no outputs");
std::cout << "outputs=" << out.size() << "\n";
実行
実行すると、解決された仕様の形状、メタデータのキー数、および出力の合計が表示されます。Neat のインストールルート(share/ と lib/ を含むディレクトリ)から、Python および C++(事前にビルドされたもの) のコマンドを実行します。ソースからビルドする コマンドは、リポジトリのルートから実行します。
C++ (prebuilt):
./lib/sima-neat/tutorials/tutorial_005_configure_model_options \
--model /tmp/yolo_v8s.tar.gz
C++ (build from source):
./build.sh --target tutorial_005_configure_model_options
./build/tutorials-standalone/tutorial_005_configure_model_options \
--model /tmp/yolo_v8s.tar.gz
予想される出力(形状とキーの数はモデルアーカイブによって異なります。C++ ビルドは詳細な仕様の行と outputs= を出力し、Python ビルドは形状と output_count= を出力します)。
input_specs[0]: shape=[640,640,3]
output_specs[0]: shape=[]
metadata_keys=8
outputs=1
[OK] 005_configure_model_options
カスタムの CMakeLists.txt を使用して、この章の C++ ソースを独自のプロジェクトに統合する方法(追加のフォルダーは不要)については、ランディングページにある チュートリアルの実行方法 を参照してください。
実践
詳細出力プリセット
フレームワークのビルド/実行メッセージは、GraphOptions、Model::Options、および Model::RouteOptions で VerboseOptions を使用して制御されます。
現在の開発におけるデフォルト設定:VerboseOptions::debug_all()。出力を少なくしたい場合は、production() または quiet() を明示的に呼び出します。
| プリセット | 目的 |
|---|---|
VerboseOptions::quiet() | フレームワークの進行状況と詳細な出力を抑制します。 |
VerboseOptions::production() | 実行段階の進行状況のみを表示します。 |
VerboseOptions::debug_plugins() | 本番環境のユーザーエクスペリエンスを維持しつつ、プラグインと GStreamer に関する情報を表示します。 |
VerboseOptions::debug_all() | すべてのトピックに対して、完全な詳細/詳細な出力を強制的に行います。 |
ランタイムにおけるキュー/スループットの調整については、スループットとキューの深さの調整 を参照してください。
完全なソース
完全なソースプログラムを表示
// Model::Options chapter: configure input/preproc/boxdecode via Options, inspect specs.
//
// Usage:
// tutorial_005_configure_model_options --model /path/to/yolo_v8s.tar.gz
#include "neat.h"
#include <opencv2/core.hpp>
#include <array>
#include <iostream>
#include <stdexcept>
#include <string>
namespace {
bool get_arg(int argc, char** argv, const std::string& key, std::string& out) {
for (int i = 1; i + 1 < argc; ++i) {
if (key == argv[i]) {
out = argv[i + 1];
return true;
}
}
return false;
}
void print_spec(const char* label, const simaai::neat::TensorConstraint& spec) {
std::cout << label << ": shape=[";
for (std::size_t i = 0; i < spec.shape.size(); ++i) {
std::cout << (i ? "," : "") << spec.shape[i];
}
std::cout << "]\n";
}
} // namespace
int main(int argc, char** argv) {
try {
std::string model_path;
if (!get_arg(argc, argv, "--model", model_path)) {
std::cerr << "Usage: tutorial_005_configure_model_options --model <path>\n";
return 1;
}
// Model::Options groups input caps, preproc, and box-decode into one struct.
simaai::neat::Model::Options opt;
opt.preprocess.kind = simaai::neat::InputKind::Image;
opt.preprocess.color_convert.input_format = simaai::neat::PreprocessColorFormat::BGR;
opt.preprocess.input_max_width = 640;
opt.preprocess.input_max_height = 640;
opt.preprocess.input_max_depth = 3;
opt.preprocess.normalize.enable = simaai::neat::AutoFlag::On;
opt.preprocess.normalize.mean = std::array<float, 3>{0.485f, 0.456f, 0.406f};
opt.preprocess.normalize.stddev = std::array<float, 3>{0.229f, 0.224f, 0.225f};
opt.decode_type = simaai::neat::BoxDecodeType::YoloV8;
opt.score_threshold = 0.55f;
opt.nms_iou_threshold = 0.45f;
opt.top_k = 100;
opt.boxdecode_original_width = 640;
opt.boxdecode_original_height = 640;
opt.name_suffix = "_chapter";
// CORE LOGIC
simaai::neat::Model model(model_path, opt);
print_spec("input_specs[0]", model.input_specs().front());
print_spec("output_specs[0]", model.output_specs().front());
std::cout << "metadata_keys=" << model.metadata().size() << "\n";
cv::Mat bgr(640, 640, CV_8UC3, cv::Scalar(10, 20, 30));
if (!bgr.isContinuous())
bgr = bgr.clone();
auto out = model.run(std::vector<cv::Mat>{bgr}, /*timeout_ms=*/2000);
if (out.empty())
throw std::runtime_error("model produced no outputs");
std::cout << "outputs=" << out.size() << "\n";
std::cout << "[OK] 005_configure_model_options\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}