Skip to main content

Read and Interpret Model Output

FieldValue
DifficultyIntermediate
Estimated Read Time10-15 minutes
Labelsoutput, patterns, sink

Concept

Read back from run.pull() or model.run() safely. Every model returns a Sample, but Sample is a small sum type — a tensor, a bundle of fields, or both. Learn which fields to check before touching the payload.

Before you optimize throughput or add complex graph logic, you need a stable way to classify outputs (kind, tensor presence, field count) and validate output contracts. This chapter provides that baseline.

APIs introduced

  • sample.kindSampleKind.Tensor, SampleKind.Bundle, etc.
  • sample.tensor — present for tensor-kind samples; None otherwise.
  • sample.fields — list of inner samples for bundle-kind.
  • tensor.shape, tensor.dtype — inspect the payload before use.

When to use this

  • New model integration: verify output rank and tensor presence first.
  • Mixed output types: branch behavior by SampleKind and field structure.
  • Building output readers that need to handle any model the runtime serves.

Prerequisites Chapter 001.

References

Learning Process

  1. Build a deterministic sync session with explicit input/output nodes.
  2. Execute one run and summarize output structure (kind, tensor, fields).
  3. Validate output contract assumptions (non-empty tensor shape/rank).

Run

Python:

python3 share/sima-neat/tutorials/010_interpret_model_output/interpret_model_output.py

C++ (prebuilt):

./lib/sima-neat/tutorials/tutorial_010_interpret_model_output

C++ (build from source):

./build.sh --target tutorial_010_interpret_model_output
./build/tutorials-standalone/tutorial_010_interpret_model_output

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/010_interpret_model_output/interpret_model_output.cpp
// Inspect a Sample returned by a Session: kind, tensor, fields, rank.
//
// Usage:
// tutorial_010_interpret_model_output

#include "neat.h"

#include <opencv2/core.hpp>

#include <iostream>
#include <stdexcept>

int main() {
try {
cv::Mat rgb(120, 160, CV_8UC3, cv::Scalar(110, 40, 30));
if (!rgb.isContinuous())
rgb = rgb.clone();

simaai::neat::InputOptions in;
in.format = "RGB";
in.width = rgb.cols;
in.height = rgb.rows;
in.depth = rgb.channels();

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>{rgb}, simaai::neat::RunMode::Sync);

// CORE LOGIC
// push_and_pull is the one-frame synchronous shortcut; Sample has .kind,
// .tensor (optional), .fields (named sub-tensors for bundles).
simaai::neat::TensorList out = run.run(std::vector<cv::Mat>{rgb}, /*timeout_ms=*/1000);

std::cout << "outputs=" << out.size() << " has_tensor=" << (!out.empty() ? "yes" : "no")
<< " fields=" << 0 << "\n";
if (out.empty())
throw std::runtime_error("expected tensor output");
if (out.front().shape.empty())
throw std::runtime_error("output tensor shape is empty");
std::cout << "rank=" << out.front().shape.size() << "\n";
std::cout << "[OK] 010_interpret_model_output\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}

Source