Skip to main content

Configure Model Options

FieldValue
DifficultyBeginner
Estimated Read Time5 minutes
Labelsmodel-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_type plus 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_stddev to match model training assumptions.
  • Multi-model or hybrid pipelines: use name_suffix / upstream_name to 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

  1. Build a Model::Options / ModelOptions config covering input, preproc, and postproc settings.
  2. Instantiate a model with those options and inspect input_spec(), output_spec(), and metadata.
  3. 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;
}
}

Source