Configure Model Options
| Field | Value |
|---|---|
| Difficulty | Beginner |
| Estimated Read Time | 5 minutes |
| Labels | model-options, configuration, contracts |
Concept
ModelOptions declares the runtime contract between your input data, the model pipeline stages, and output decoding. It is the first struct you reach for when moving past default behavior — one place to tune preprocessing, input bounds, and postprocessing together.
This chapter focuses on the options most teams use first:
format,media_type: declare incoming data type (for example raw RGB/BGR image input).input_max_width,input_max_height,input_max_depth: set dynamic input bounds for validation and runtime sizing.preproc.*: control preprocessing behavior (normalization, channel stats, image-type and resize policy overrides).decode_type,score_threshold,nms_iou_threshold,top_k: control detection-style postprocessing and filtering.original_width,original_height: provide original image geometry when postprocessing requires source-frame coordinates.name_suffix,upstream_name: stabilize/clarify generated stage naming when composing bigger pipelines.
Use-case guidance
- Prototype classification quickly: set
format+ input max dimensions, keep postproc defaults minimal. - Detection model bring-up (YOLO-style): set
decode_typeplus threshold/NMS/top-k options to shape final boxes. - Mixed input sizes in one app: set
input_max_*high enough for expected ranges to avoid runtime contract failures. - Accuracy tuning after deployment: adjust
preproc.normalize,channel_mean,channel_stddevto match model training assumptions. - Multi-model or hybrid pipelines: use
name_suffix/upstream_nameto keep pipeline graph naming explicit and debuggable.
APIs introduced
pyneat.ModelOptions()with the fields listed above.model.input_spec(),model.output_spec(),model.metadata()— inspect the resolved contract after loading.
Prerequisites Chapter 001.
References
Learning Process
- Build a
Model::Options/ModelOptionsconfig covering input, preproc, and postproc settings. - Instantiate a model with those options and inspect
input_spec(),output_spec(), and metadata. - Run one deterministic inference path and observe how options influence runtime behavior.
Run
Python:
python3 share/sima-neat/tutorials/004_configure_model_options/configure_model_options.py \
--mpk /tmp/yolo_v8s_mpk.tar.gz
C++ (prebuilt):
./lib/sima-neat/tutorials/tutorial_004_configure_model_options \
--mpk /tmp/yolo_v8s_mpk.tar.gz
C++ (build from source):
./build.sh --target tutorial_004_configure_model_options
./build/tutorials-standalone/tutorial_004_configure_model_options \
--mpk /tmp/yolo_v8s_mpk.tar.gz
To integrate this chapter's C++ source into your own project with a custom CMakeLists.txt (no extras folder required), see How to Run Tutorials on the landing page.
Code
tutorials/004_configure_model_options/configure_model_options.cpp
// Model::Options chapter: configure input/preproc/boxdecode via Options, inspect specs.
//
// Usage:
// tutorial_004_configure_model_options --mpk /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 << ": rank=" << spec.rank << " dtypes=" << spec.dtypes.size()
<< " shape_dims=" << spec.shape.size() << "\n";
}
} // namespace
int main(int argc, char** argv) {
try {
std::string mpk;
if (!get_arg(argc, argv, "--mpk", mpk)) {
std::cerr << "Usage: tutorial_004_configure_model_options --mpk <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(mpk, opt);
print_spec("input_spec", model.input_spec());
print_spec("output_spec", model.output_spec());
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);
std::cout << "outputs=" << out.size() << "\n";
std::cout << "[OK] 004_configure_model_options\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}