Read and Interpret Model Output
| Field | Value |
|---|---|
| Difficulty | Intermediate |
| Estimated Read Time | 10-15 minutes |
| Labels | output, 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.kind—SampleKind.Tensor,SampleKind.Bundle, etc.sample.tensor— present for tensor-kind samples;Noneotherwise.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
SampleKindand field structure. - Building output readers that need to handle any model the runtime serves.
Prerequisites Chapter 001.
References
Learning Process
- Build a deterministic sync session with explicit input/output nodes.
- Execute one run and summarize output structure (
kind, tensor, fields). - 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;
}
}