Створіть свій перший граф
| Поле | Значення |
|---|---|
| Категорія | Графи та конвеєри |
| Складність | Початковий |
| Орієнтовний час читання | 5 minutes |
| Мітки | graph, build, run, pipeline |
Розділ 001 запустив модель у три рядки. Ця зручність приховує двокомпонентний життєвий цикл, який кожна нетривіальна програма Neat використовує безпосередньо: спочатку ви описуєте конвеєр як Graph, а потім створюєте на основі цього опису виконуваний Run. У цьому розділі цей життєвий цикл стає видимим завдяки створенню найпростішого можливого конвеєра — один вхідний вузол, з’єднаний з одним вихідним вузлом, без жодної моделі між ними — і передачі через нього одного кадру.
Результат полягає в концептуальному розумінні: Graph — це багаторазово використовуване визначення, яке ви створюєте один раз і виконуєте багато разів, а не одноразовий виклик. Під кінець ви створите граф, перетворите його на виконуваний конвеєр і зчитаєте ранг вихідного тензора, щоб довести, що кадр пройшов через нього.
Покроковий огляд
Опишіть вхідний
Перш ніж з’єднувати вузли, визначте, як виглядатиме кадр. InputOptions – це своєрідний контракт: формат пікселів format, width/height, глибина каналу depth і те, чи середовище виконання додає мітки часу до кожного буфера. Вхідний вузол, створений на основі цих параметрів, перевіряє вхідні кадри на відповідність очікуваній формі в конвеєрі.
Крім того, в C++ встановлюється значення is_live = false, щоб позначити це як неактивне (файл/тензор) джерело.
simaai::neat::InputOptions in;
in.format = "RGB";
in.width = width;
in.height = height;
in.depth = 3;
in.is_live = false;
in.do_timestamp = true;
Складіть граф
Тепер створимо структуру. Новий Graph — це порожня область для створення композиції, а add() додає вузли в певному порядку. Ми додаємо рівно два вузли: вхідний вузол (налаштований вище) і простий вихідний вузол. Це вся топологія: кадри надходять на вхід і виходять на вихід, без будь-яких проміжних етапів. Це місце, де в наступних розділах буде розміщено модель або етап попередньої обробки.
Вузли надходять з simaai::neat::nodes::Input(...) і nodes::Output().
simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::Input(in));
graph.add(simaai::neat::nodes::Output());
Створення конвеєра
build() — це перехід від опису до виконуваного коду. Він перетворює додані вузли на конкретний конвеєр, перевіряє вхідні/вихідні контракти на основі реального зразка та створює багаторазово використовуваний об’єкт Run. Ми передаємо репрезентативний кадр, щоб build() міг зафіксувати узгоджені розміри тензора; наступний крок використовує Run::run(...) для детермінованого виклику по одному.
Зразковий кадр є cv::Mat, і run_opt.output_memory = Owned просить середовище виконання повернути буфери вихідних даних, якими воно володіє.
auto run = graph.build(std::vector<cv::Mat>{input}, run_opt);
Запустіть кадр і зчитайте результат
Маючи Run, run() передає один кадр і синхронно отримує один результат. Оскільки моделі немає, вихід відображає вхідний контракт, тому достатньо прочитати ранг тензора, щоб підтвердити, що кадр завершив повний цикл. У реальних конвеєрах саме цей run()/push/pull механізм використовується для здійснення обчислень.
run() повертає TensorList; прочитайте sample.front().shape.size().
simaai::neat::TensorList sample = run.run(std::vector<cv::Mat>{input}, /*timeout_ms=*/1000);
Запуск
Запустіть програму, і ви повинні побачити значення рангу тензора, що виводиться в стандартний потік виводу (stdout). Запустіть команди Python і C++ (попередньо скомпільовані) з кореневої теки встановлення Neat (теки, яка містить share/ і lib/); запустіть команди збірка з вихідного коду з кореневої теки репозиторію. Для цього розділу не потрібен архів моделі.
C++ (prebuilt):
./lib/sima-neat/tutorials/tutorial_004_build_inference_pipeline \
--width 320 --height 240
C++ (build from source):
./build.sh --target tutorial_004_build_inference_pipeline
./build/tutorials-standalone/tutorial_004_build_inference_pipeline \
--width 320 --height 240
Очікува ний результат:
tensor_rank=3
[OK] 004_build_inference_pipeline
(Збірка Python виводить output_rank=...). Щоб інтегрувати вихідний код C++ цього розділу у власний проєкт за допомогою спеціального файлу CMakeLists.txt (додаткова тека не потрібна), див. розділ Як запускати навчальні матеріали на головній сторінці.
На практиці
Як build/run, режими виконання, поверхня push/pull і RunOptions взаємодіють, коли ви переходите до кількох синхронних викликів.