Skip to main content

Session Patterns

FieldValue
DifficultyIntermediate
Estimated Read Time15 minutes
Labelssession, composition, patterns

Concept

This chapter compares practical session composition patterns for building real applications.

The name "session patterns" here means different ways to construct a runnable Session, not different inference algorithms. In the source, you will see three common composition styles:

  • Direct session: explicitly add Input + Output nodes yourself.
  • Model-default session: use model.session() to inject the model’s default pipeline group.
  • Model-attached session: use model.session(session_options) to control appsrc/appsink inclusion and naming when attaching model groups to larger systems.

Why this matters:

  • Teams often start with direct sessions for clarity, then move to model-backed composition for scale.
  • Model::SessionOptions / ModelSessionOptions helps keep graph wiring explicit in multi-camera or multi-model deployments.
  • Consistent naming (upstream_name, name_suffix, buffer_name) improves diagnostics and backend graph readability.

Reference:

Learning Process

  1. Build a minimal direct session and validate it can run end-to-end.
  2. Construct model-backed session variants (model.session() and model.session(options)).
  3. Compare generated backend graphs with --print-gst to understand composition differences.
  4. Execute a deterministic sync run and validate completion with CHECK, SIGNATURE, and [OK].

Run

NEAT_EXTRAS_ROOT=<sima-neat-*-Linux-extras>
cd $NEAT_EXTRAS_ROOT/lib/sima-neat/tutorials
./tutorial_v2_007_session_patterns --mpk /path/to/model.tar.gz

Code

tutorials/007_session_patterns/session_patterns.cpp
// Three Session composition patterns: direct nodes, model.session(), attached session.
//
// Usage:
// tutorial_v2_007_session_patterns [--mpk /path/to/model.tar.gz]

#include "neat.h"

#include <opencv2/core.hpp>

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

} // namespace

int main(int argc, char** argv) {
try {
const int width = 224;
const int height = 224;

cv::Mat rgb(height, width, CV_8UC3, cv::Scalar(80, 40, 160));
if (!rgb.isContinuous())
rgb = rgb.clone();

// CORE LOGIC
// Pattern 1: build a Session by adding Input/Output nodes directly.
simaai::neat::Session direct;
simaai::neat::InputOptions in;
in.format = "RGB";
in.width = width;
in.height = height;
in.depth = 3;
in.do_timestamp = true;
direct.add(simaai::neat::nodes::Input(in));
direct.add(simaai::neat::nodes::Output());

std::string mpk;
if (get_arg(argc, argv, "--mpk", mpk) && fs::exists(mpk)) {
simaai::neat::Model model(mpk);

// Pattern 2: ingest the model's default session group.
simaai::neat::Session from_model;
from_model.add(model.session());
std::cout << "model_session_size=" << model.session().size() << "\n";

// Pattern 3: attach the model under an upstream name with custom options.
simaai::neat::Model::SessionOptions sopt;
sopt.include_appsrc = false;
sopt.include_appsink = true;
sopt.upstream_name = "camera0";
sopt.name_suffix = "_camera0";
sopt.buffer_name = "camera0";

simaai::neat::Session attached;
attached.add(model.session(sopt));
std::cout << "attached_session_backend=\n" << attached.describe_backend() << "\n";
}

auto run = direct.build(rgb, simaai::neat::RunMode::Sync);
auto out = run.push_and_pull(rgb, /*timeout_ms=*/1000);

if (!out.tensor.has_value())
throw std::runtime_error("direct session output missing tensor");
std::cout << "direct_rank=" << out.tensor->shape.size() << "\n";
std::cout << "[OK] 007_session_patterns\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}

Source