Зчитування та інтерпретація результатів роботи моделі
| Поле | Значення |
|---|---|
| Категорія | Моделі та інференс |
| Складність | Середній |
| Орієнтовний час читання | 10-15 minutes |
| Мітки | output, patterns, sink |
Перш ніж оптимізувати пропускну здатність або додавати складну логіку графа, вам потрібен стабільний, надійний спосіб зчитування будь-яких даних, які повертає виконання. Результат завжди є Sample, але його форма може відрізнятися: це може бути окремий тензор або набір іменованих полів (як у розділі 009). Звернення до .tensor у наборі або припущення про форму, якої там немає, — це помилка, якої цей розділ навчить вас уникати.
Ми створюємо той самий мінімальний граф синхронізації, що й раніше, запускаємо один кадр, а потім ретельно перевіряємо результат: його kind, чи присутній тензор, скільки в ньому полів і ранг тензора. Зрештою, ви отримаєте повторно використовуваний шаблон для зчитування вихідних даних, який працюватиме для будь-якої моделі, що обслуговується середовищем виконання.
Покроковий огляд
Налаштуйте вхідний
Оголосіть вхідний контракт — формат пікселів format, width, height, depth — відповідно до кадру, який ми будемо передавати. Це той самий граничний контракт, який використовується в усіх цих розділах.
simaai::neat::InputOptions in;
in.format = "RGB";
in.width = rgb.cols;
in.height = rgb.rows;
in.depth = rgb.channels();
Складіть і створіть граф
З’єднайте вхідний вузол із вихідним вузлом і створіть синхронний build() у вигляді Run, передаючи кадр, щоб build() міг узгодити конкретні розміри. Оскільки між ними немає моделі, вихід відображає вхід — і саме це робить це ідеальним місцем для вивчення структури вихідних даних.
simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::Input(in));
graph.add(simaai::neat::nodes::Output());
// Use Graph::run(...) for a one-shot synchronous frame.
Запустіть один кадр
Передайте один кадр і синхронно отримайте один результат. Єдиний виклик run(...) є швидким способом обробки одного кадру; те, що він повертає, — це об’є кт, який ми тут збираємося детально вивчити.
run.run(...) повертає TensorList — для вихідних даних, що містять один тензор, це означає один елемент, який наступний крок перевіряє за допомогою out.size() і out.front().
// Graph::run is the one-frame synchronous shortcut.
simaai::neat::TensorList out = graph.run(std::vector<cv::Mat>{rgb});
Перевірте зразок
Ось основний принцип: спочатку прочитайте структуру, а потім дані. Спочатку перевірте наявність і тип, а потім отримайте ранг із shape тензора. Захист кожного кроку (непорожній вихід, непорожня форма) робить обробник вихідних даних надійним щодо моделей, форму яких ви не контролюєте.
Повідомте про out.size() та наявність тензора, викличте помилку, я кщо значення порожнє або якщо out.front().shape порожнє, потім виведіть rank зі значення shape.size(). (Рядок fields=0 є заповнювачем — TensorList не містить структуру полів пакета, як це робить Python Sample).
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";
Запуск
Запустіть команди Python і C++ (попередньо скомпільовані) з кореневої директорії встановлення Neat (директорії, яка містить share/ і lib/); запустіть команди збірка з вихідного коду з кореневої директорії репозиторію. Для цього розділу не потрібен архів моделі.
C++ (prebuilt):
./lib/sima-neat/tutorials/tutorial_011_interpret_model_output
C++ (build from source):
./build.sh --target tutorial_011_interpret_model_output
./build/tutorials-standalone/tutorial_011_interpret_model_output
Очікуваний вивід (C++):
outputs=1 has_tensor=yes fields=0
rank=3
[OK] 011_interpret_model_output
Збірка Python виводить ті самі дані через структуру Sample:
sample_kind=SampleKind.TensorSet
has_tensor=False
num_fields=0
output_rank=3
Щоб інтегрувати вихідний код C++ з цієї глави у власний проєкт за допомогою спеціального файлу CMakeLists.txt (додаткова тека не потрібна), див. розділ Як запускати навчальні матеріали на головній сторінці.
На практиці
Перелік перевірок для читання вихідних даних будь-якої моделі.
Класифікуйте, перш ніж читати
- Спочатку пе ревірте
kind. Якщо результат представлено одним тензором, то цеSampleKind.Tensor; якщо результат містить кілька полів, то цеSampleKind.Bundle. - Для типу «тензор» присутній
tensor, аfieldsпорожній. Для типу «набір», читайтеfieldsі не припускайте наявністьtensor.
Перевірте відповідність
- Переконайтеся, що тензор присутній, перш ніж звертатися до нього.
- Переконайтеся, що
shapeне порожній, перш ніж обчислювати ранг або індексувати розмірності. - Перевірте
tensor.dtype, коли споживачу потрібен певний тип елементів.
Повний початковий код
Показати повні програми
// Inspect a Sample returned by a Graph: kind, tensor, fields, rank.
//
// Usage:
// tutorial_011_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::Graph graph;
graph.add(simaai::neat::nodes::Input(in));
graph.add(simaai::neat::nodes::Output());
// Use Graph::run(...) for a one-shot synchronous frame.
// CORE LOGIC
// Graph::run is the one-frame synchronous shortcut.
simaai::neat::TensorList out = graph.run(std::vector<cv::Mat>{rgb});
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] 011_interpret_model_output\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}