Skip to main content

Run Your First Model

FieldValue
DifficultyBeginner
Estimated Read Time<5 minutes
Labelsmodel, mpk, inference, foundations

Concept

Load a compiled ResNet-50 MPK, feed it an image, and read the top-1 class in three lines of Python. This is the shortest path from "I have a model package" to "I have a prediction."

A compiled model is a deployable model package (.tar.gz, often called an MPK) that Neat can load and execute on the target device. It contains the model artifacts and runtime metadata needed for inference — you provide input, call run(), and read outputs.

APIs introduced

  • pyneat.Model(mpk_path) — load the compiled model.
  • model.run(input, timeout_ms) — synchronous inference; returns a Sample with the model's output tensor.
    • timeout_ms is the max wall time (ms) to wait for output. -1 (the default) blocks indefinitely; any > 0 value throws on timeout so stalls surface loudly. Prefer a finite value (e.g. 2000) in production code, -1 only when you trust the runtime to always produce output.

When to use this Fastest way to verify an MPK loads and runs on hardware. For throughput, batching, or live streams, move on to chapter 002.

Prerequisites None — this is the entry chapter.

References

Learning Process

  1. Set up runtime inputs: parse CLI args, locate the compiled ResNet50 MPK, and prepare sample input data.
  2. Build the minimal model execution path for one model and one input stream.
  3. Run synchronous inference to keep behavior deterministic and easy to debug.

Run

Python:

python3 share/sima-neat/tutorials/001_run_your_first_model/run_your_first_model.py \
--mpk /tmp/resnet_50_mpk.tar.gz

C++ (prebuilt):

./lib/sima-neat/tutorials/tutorial_001_run_your_first_model \
--mpk /tmp/resnet_50_mpk.tar.gz

C++ (build from source):

./build.sh --target tutorial_001_run_your_first_model
./build/tutorials-standalone/tutorial_001_run_your_first_model \
--mpk /tmp/resnet_50_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/001_run_your_first_model/run_your_first_model.cpp
// Run a ResNet-50 model on an image in three lines of Neat.
//
// Usage:
// tutorial_001_run_your_first_model --mpk /path/to/resnet_50.tar.gz [--image /path/to.jpg]

#include "neat.h"

#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>

#include <cstring>
#include <filesystem>
#include <iostream>
#include <stdexcept>
#include <string>

namespace fs = std::filesystem;

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;
}

cv::Mat load_rgb(const fs::path& image_path, int size) {
cv::Mat bgr = cv::imread(image_path.string(), cv::IMREAD_COLOR);
if (bgr.empty())
throw std::runtime_error("failed to read image: " + image_path.string());
if (bgr.cols != size || bgr.rows != size) {
cv::resize(bgr, bgr, cv::Size(size, size), 0, 0, cv::INTER_AREA);
}
cv::Mat rgb;
cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB);
if (!rgb.isContinuous())
rgb = rgb.clone();
return rgb;
}

simaai::neat::Model::Options build_options(int size) {
simaai::neat::Model::Options opt;
opt.preprocess.color_convert.input_format = simaai::neat::PreprocessColorFormat::RGB;
opt.preprocess.input_max_width = size;
opt.preprocess.input_max_height = size;
opt.preprocess.input_max_depth = 3;
opt.preprocess.normalize.mean = {0.485f, 0.456f, 0.406f};
opt.preprocess.normalize.stddev = {0.229f, 0.224f, 0.225f};
return opt;
}

int top1_from_output(const simaai::neat::TensorList& out) {
if (out.empty())
throw std::runtime_error("no tensor output");
const simaai::neat::Mapping m = out.front().map_read();
const size_t n = m.size_bytes / sizeof(float);
const float* p = reinterpret_cast<const float*>(m.data);
int best = 0;
for (size_t i = 1; i < n && i < 1000; ++i) {
if (p[i] > p[best])
best = static_cast<int>(i);
}
return best;
}

} // namespace

int main(int argc, char** argv) {
try {
std::string mpk, image;
if (!get_arg(argc, argv, "--mpk", mpk)) {
std::cerr << "Usage: tutorial_001_run_your_first_model --mpk <path> [--image <path>]\n";
return 1;
}
get_arg(argc, argv, "--image", image);

const int size = 224;

// CORE LOGIC
// The three-line Neat story:
simaai::neat::Model model(mpk, build_options(size));
cv::Mat input = image.empty() ? cv::Mat(size, size, CV_8UC3, cv::Scalar(99, 99, 99))
: load_rgb(image, size);
simaai::neat::TensorList sample = model.run(std::vector<cv::Mat>{input}, /*timeout_ms=*/2000);

std::cout << "top1=" << top1_from_output(sample) << "\n";
std::cout << "[OK] 001_run_your_first_model\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}

Source