Перейти до основного вмісту

Вбудовування моделі в граф

ПолеЗначення
КатегоріяГрафи та конвеєри
СкладністьПросунутий
Орієнтовний час читання20-25 minutes
Міткиgraph, hybrid, model, mpk

Розділ 003 створив граф із простих вузлів вхідних/вихідних даних; розділ 001 запустив модель як незалежний об’єкт. У цьому розділі ці два аспекти об’єднуються: Model сам по собі є вузлом, сумісним із графом, тому ви можете включити його до загального Graph, точно так само, як і будь-який інший етап. Це шаблон «міст», який використовують системи для створення, коли їм потрібен контроль на рівні графа — кілька входів, іменовані виходи, спеціальна маршрутизація — і при цьому вони розглядають виконання моделі як один фрагмент, який можна повторно використовувати.

Основна ідея полягає в тому, що ви ніколи не змінюєте граф низького рівня, StageModelExecutorOptions, або внутрішні ідентифікатори вузлів. Ви передаєте модель до graph.add(...), і NEAT перетворює цей фрагмент (попередню обробку / виведення / подальшу обробку за потреби) на правильний внутрішній план виконання під час створення. В результаті ви створите модель у загальному графі, надрукуєте створену топологію та зчитаєте кількість вихідних даних моделі.

Покроковий огляд

Завантажте модель

Під час створення відбувається завантаження скомпільованого архіву та підготовка до виконання, як і в розділі 001. Тут ми використовуємо лише шлях — без об’єкта параметрів — оскільки цей розділ присвячений композиції, а не попередній обробці. Отриманий Model тепер є об’єктом, який розуміє шар графа.

tutorials/014_embed_model_inside_graph/embed_model_inside_graph.cpp
simaai::neat::Model model(model_path);

Складання моделі в граф

У цьому полягає головна мета розділу. До нового Graph додаються три вузли в наступному порядку: іменована вхідна межа, сама модель і іменована вихідна межа. Оскільки Model сумісний із графом, add(model) додає весь шлях моделі як єдиний фрагмент — немає спеціального API та немає необхідності звертатися до середовища виконання. Друк graph.describe() показує створену топологію, щоб ви могли переконатися, що модель розміщена між іменованими межами.

Межі походять з simaai::neat::nodes::Input("image") та nodes::Output("result"); модель передається безпосередньо в graph.add(model).

tutorials/014_embed_model_inside_graph/embed_model_inside_graph.cpp
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, щоб зробити явним підключення виходів моделі.

tutorials/014_embed_model_inside_graph/embed_model_inside_graph.cpp
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 (додаткова тека не потрібна), див. розділ Як запускати навчальні матеріали на головній сторінці.

Повний початковий код

Показати повні програми
tutorials/014_embed_model_inside_graph/embed_model_inside_graph.cpp
// 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;
}
}

Джерело