Skip to main content

Build an Inference Pipeline

FieldValue
DifficultyBeginner
Estimated Read Time5 minutes
Labelssession, build, run, pipeline

Concept

Compose a Session by hand — input node, output node, no model — and run one frame through it. See the pipeline primitives in isolation before a model is added to the picture.

A Session is where you define pipeline structure by adding nodes and node groups in order. It is not a one-off inference call; it is a reusable runtime graph definition that can be built once and executed many times.

build(...) turns that definition into a runnable Run handle — the transition from "graph description" to "executable runtime":

  • Resolves the added nodes/groups into a concrete pipeline.
  • Validates input/output contracts for the selected input type.
  • Configures runtime behavior (sync vs async mode, output memory policy).
  • Returns a Run object for push/pull calls.

APIs introduced

  • pyneat.Session() — the composition entry point.
  • pyneat.InputOptions(), pyneat.nodes.input(opts), pyneat.nodes.output() — the most basic node pair.
  • session.build(tensor, pyneat.RunMode.Sync) — materialize the pipeline.
  • run.run(tensor, timeout_ms) — sync one-shot inference on the built pipeline.

When to use this Learning the Session / Run lifecycle without a model in the loop, or building custom pipelines from primitives.

Prerequisites Chapter 001.

References

Learning Process

  1. Create a minimal Session with explicit input and output nodes.
  2. Build the session with a concrete sample input to materialize a runnable pipeline.
  3. Execute one deterministic sync run to verify output contract behavior.

Run

Python:

python3 share/sima-neat/tutorials/003_build_inference_pipeline/build_inference_pipeline.py \
--width 320 --height 240

C++ (prebuilt):

./lib/sima-neat/tutorials/tutorial_003_build_inference_pipeline \
--width 320 --height 240

C++ (build from source):

./build.sh --target tutorial_003_build_inference_pipeline
./build/tutorials-standalone/tutorial_003_build_inference_pipeline \
--width 320 --height 240

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/003_build_inference_pipeline/build_inference_pipeline.cpp
// Build a minimal Session (Input -> Output), run a frame, read the tensor rank.
//
// Usage:
// tutorial_003_build_inference_pipeline [--width <w>] [--height <h>]

#include "neat.h"

#include <opencv2/core.hpp>

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

int parse_int_arg(int argc, char** argv, const std::string& key, int def) {
std::string value;
if (!get_arg(argc, argv, key, value))
return def;
return std::stoi(value);
}

} // namespace

int main(int argc, char** argv) {
try {
const int width = parse_int_arg(argc, argv, "--width", 320);
const int height = parse_int_arg(argc, argv, "--height", 240);

cv::Mat input(height, width, CV_8UC3, cv::Scalar(30, 60, 90));
if (!input.isContinuous())
input = input.clone();

simaai::neat::InputOptions in;
in.format = "RGB";
in.width = width;
in.height = height;
in.depth = 3;
in.is_live = false;
in.do_timestamp = true;

simaai::neat::RunOptions run_opt;
run_opt.output_memory = simaai::neat::OutputMemory::Owned;

// CORE LOGIC
// Compose a Session from Input and Output nodes, then build+run one frame.
simaai::neat::Session session;
session.add(simaai::neat::nodes::Input(in));
session.add(simaai::neat::nodes::Output());
auto run = session.build(std::vector<cv::Mat>{input}, simaai::neat::RunMode::Sync, run_opt);
simaai::neat::TensorList sample = run.run(std::vector<cv::Mat>{input}, /*timeout_ms=*/1000);

if (sample.empty())
throw std::runtime_error("missing tensor output");
std::cout << "tensor_rank=" << sample.front().shape.size() << "\n";
std::cout << "[OK] 003_build_inference_pipeline\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}

Source