Вбудовування моделі в граф
| Поле | Значення |
|---|---|
| Категорія | Графи та конвеєри |
| Складність | Просунутий |
| Орієнтовний час читання | 20-25 minutes |
| Мітки | graph, hybrid, model, mpk |
Розділ 003 створив граф із простих вузлів вхідних/вихідних даних; розділ 001 запустив модель як незалежний об’єкт. У цьому розділі ці два аспекти об’єднуються: Model сам по собі є вузлом, сумісним із графом, тому ви можете включити його до загального Graph, точно так само, як і будь-який інший етап. Це шаблон «міст», який використовують системи для створення, коли їм потрібен контроль на рівні графа — кілька входів, іменовані виходи, спеціальна маршрутизація — і при цьому вони розглядають виконання моделі як один фрагмент, який можна повторно використовувати.
Основна ідея полягає в тому, що ви ніколи не змінюєте граф низького рівня, StageModelExecutorOptions, або внутрішні ідентифікатори вузлів. Ви передаєте модель до graph.add(...), і NEAT перетворює цей фрагмент (попередню обробку / виведення / подальшу обробку за потреби) на правильний внутрішній план виконання під час створення. В результаті ви створите модель у загальному графі, надрукуєте створену топологію та зчитаєте кількість вихідних даних моделі.
Покроковий огляд
Завантажте модель
Під час створення відбувається завантаження скомпільованого архіву та підготовка до виконання, як і в розділі 001. Тут ми використовуємо лише шлях — без об’єкта параметрів — оскільки цей розділ присвячений композиції, а не попередній обробці. Отриманий Model тепер є об’єктом, який розуміє шар графа.
simaai::neat::Model model(model_path);
Складання моделі в граф
У цьому полягає головна мета розділу. До нового Graph додаються три вузли в наступному порядку: іменована вхідна межа, сама модель і іменована вихідна межа. Оскільки Model сумісний із графом, add(model) додає весь шлях моделі як єдиний фрагмент — немає спеціального API та немає необхідності звертатися до середовища виконання. Друк graph.describe() пок азує створену топологію, щоб ви могли переконатися, що модель розміщена між іменованими межами.
Межі походять з simaai::neat::nodes::Input("image") та nodes::Output("result"); модель передається безпосередньо в graph.add(model).
simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::Input("image"));
graph.add(model);
graph.add(simaai::neat::nodes::Output("result"));
std::cout << graph.describe() << "\n";
Перевірка моделі
Нарешті, ми перевіряємо, який саме внесок роб ить фрагмент моделі. Це підтверджує, що модель завантажилася правильно, і дозволяє вам побачити топологію вихідних даних, яку створить граф у подальшому.
model.info() повертає інформаційну структуру; ми виводимо model_name, а також output_topology.physical_outputs і logical_outputs, щоб зробити явним підключення виходів моделі.
const auto info = model.info();
std::cout << "model=" << (info.model_name.empty() ? "<unnamed>" : info.model_name)
<< " physical_outputs=" << info.output_topology.physical_outputs
<< " logical_outputs=" << info.output_topology.logical_outputs << "\n";
Запуск
Для цього розділу потрібен архів моделі (yolo_v8s). Запустіть команди Python і C++ (попередньо зібрані) з кореневої д иректорії встановлення Neat (директорії, яка містить share/ і lib/); запустіть команди збірка з вихідного коду з кореневої директорії репозиторію.
C++ (prebuilt):
./lib/sima-neat/tutorials/tutorial_014_embed_model_inside_graph \
--model /tmp/yolo_v8s.tar.gz
C++ (build from source):
./build.sh --target tutorial_014_embed_model_inside_graph
./build/tutorials-standalone/tutorial_014_embed_model_inside_graph \
--model /tmp/yolo_v8s.tar.gz
Очікуваний вивід (у C++ також спочатку виводиться опис зібраного графа):
model=yolo_v8s physical_outputs=1 logical_outputs=1
[OK] 014_embed_model_inside_graph
(Під час компіляції Python виводиться опис графа, після чого виводиться повідомлення model fragment added to public Graph).
Щоб інтегрувати вихідний код C++ з цього розділу у власний проєкт за допомогою спеціального файлу CMakeLists.txt (додаткова тека не потрібна), див. розділ Як запускати навчальні матеріали на головній сторінці.
Повний початковий код
Показати повні програми
// Hybrid graph composition: a Model is added directly to a public Graph.
//
// Usage:
// tutorial_014_embed_model_inside_graph --model /path/to/model.tar.gz
#include "neat.h"
#include <iostream>
#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;
}
} // namespace
int main(int argc, char** argv) {
try {
std::string model_path;
if (!get_arg(argc, argv, "--model", model_path)) {
std::cerr << "Usage: tutorial_014_embed_model_inside_graph --model <path>\n";
return 1;
}
simaai::neat::Model model(model_path);
// CORE LOGIC
// Model is now a Graph-compatible object. `graph.add(model)` appends the
// model route fragment (preprocess/inference/postprocess as needed) without
// exposing the internal low-level runtime graph.
simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::Input("image"));
graph.add(model);
graph.add(simaai::neat::nodes::Output("result"));
std::cout << graph.describe() << "\n";
const auto info = model.info();
std::cout << "model=" << (info.model_name.empty() ? "<unnamed>" : info.model_name)
<< " physical_outputs=" << info.output_topology.physical_outputs
<< " logical_outputs=" << info.output_topology.logical_outputs << "\n";
std::cout << "[OK] 014_embed_model_inside_graph\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}