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

Модель

Model завантажує скомпільований архів моделі та надає доступ до шляху, за яким Neat може виконувати обчислення.

Використовуйте Model, коли вам потрібне виконання з урахуванням моделі, без ручного налаштування кожного етапу попередньої обробки, обчислення та подальшої обробки. Спочатку перевірте специфікацію. Потім запустіть її. Жодних незрозумілих тензорів.

Що дає вам Model?​

  • input_specs() та output_specs() показують, які тензори модель очікує на вході та які генерує на виході.
  • metadata(), info() та Python summary() допомагають вам переглянути завантажену модель.
  • run(...) виконує один прямий прохід для отримання результату.
  • build(...) створює повторно використовуваний засіб для запуску моделей, який можна застосовувати для виконання завдань у режимі «push» або «pull».
  • graph() повертає маршрут моделі у вигляді фрагмента Graph, який можна повторно використовувати.
  • preprocess(), inference() та postprocess() визначають етапи маршруту для розширеної композиції.

Посилання:

Завантажте архів моделі.​

Приклади на цій сторінці передбачають, що model_path вказує на скомпільований архів моделі, створений за допомогою Model Compiler, зазвичай це .tar.gz, скопійований на машину, на якій працює Neat. Спочатку використовуйте параметри за замовчуванням; додавайте ModelOptions лише тоді, коли це вимагається умовами контракту або джерелом вхідних даних.

const std::string model_path = "resnet_50_model.tar.gz";
simaai::neat::Model model(model_path);

const auto info = model.info();
const auto inputs = model.input_specs();
const auto outputs = model.output_specs();

Якщо цей етап перевірки вас здивував, зупиніться. Відкоригуйте шлях до моделі, артефакт або контракт, перш ніж розробляти навколо цього більш масштабну програму.

Оберіть шлях виконання моделі.​

Обирайте шлях, який відповідає конкретній задачі. Зберігайте обсяг тестів на наявність помилок на мінімальному рівні; використовуйте інструменти для роботи з графами лише для вирішення задач, пов’язаних із графами.

ПотрібноВикористовуйтеПовертає
Запустіть один набір вхідних даних для моделі один раз.model.run(...)TensorList для тензорного вхідного сигналу або Sample для зразкового вхідного сигналу.
Використовуйте один і той самий маршрут моделі для багатьох вхідних даних.model.build(...) та засіб для запуску моделі.Регулювання шляхом натискання/тяжіння вздовж траєкторії моделі.
Вимірюйте лише час виконання моделі.model.benchmark(...) або інструмент для оцінювання роботи моделі.BenchmarkReport або MeasureReport
Додайте модель до робочого процесу застосунку.graph.add(model)Етап Graph.
Визначте межі маршрутів для компонування.model.graph(route_options)Повторно використовуваний фрагмент Graph.
Відлагоджуйте один етап моделі.model.fragment(ModelStage::...)Фрагмент Graph, що відповідає певній стадії.

Для підвищення впевненості використовуйте прямі виклики моделі. Використовуйте Graph, коли модель стає частиною застосунку: іменовані вхідні дані, вихідні вузли, гілки, з’єднання, візуалізація, виведення відео, виведення метаданих або кілька моделей.

Оберіть варіанти моделі.​

Почніть зі стандартних ModelOptions. Додавайте параметри лише тоді, коли це вимагається контрактом моделі або джерелом вхідних даних.

МетаВаріанти використанняПримітки
Надсилайте декодоване зображення.preprocess.kind, preprocess.preset та конкретні поля попередньої обробки, такі як зміна розміру, колір, макет, нормалізація, квантування або теселяція.Використовуйте це, коли ваш застосунок надсилає пікселі, і Neat має адаптувати їх до моделі контракту.
Передати тензори, що відповідають публічним входам моделіЗалиште параметри попередньої обробки незаданими.Зберігає потрібні адаптери Cast/Quant/Tess, зокрема для вже масштабованих і нормалізованих входів FP32.
Розшифруйте результати виявлення.decode_type, decode_type_option, score_threshold, nms_iou_threshold, top_k, num_classesМоделі виявлення потребують чітко визначеного наміру декодування.
Зберігайте отримані файли моделі для подальшого перегляду.cleanup_extracted_model_data = falseКорисно під час налагодження. Залиште значення за замовчуванням для звичайного запуску.
Запустіть декілька моделей маршрутів в одному процесі.name_suffix та префікс/суфікс назви елемента графа.Забезпечує читабельність згенерованих назв і результатів діагностики.
Зупиніть виконання маршруту моделі достроково.inference_terminalРозширений метод налагодження маршруту. Не використовуйте його для первинного запуску коду.
Налаштуйте розташування місця виконання або внутрішні черги.processcvu, processmla, advanced_executionРозширений режим. Виміряйте стандартний шлях перед налаштуванням.

Вхідне зображення з декодуванням для виявлення об’єктів.​

Використовуйте цей шаблон, коли модель передбачає попередню обробку зображень і видає результати у форматі YOLO.

simaai::neat::Model::Options options;
options.preprocess.kind = simaai::neat::InputKind::Image;
options.preprocess.preset = simaai::neat::NormalizePreset::COCO_YOLO;
options.decode_type = simaai::neat::BoxDecodeType::YoloV8;
options.score_threshold = 0.25f;
options.nms_iou_threshold = 0.45f;
options.top_k = 100;

simaai::neat::Model model(model_path, options);

Дотримуйтеся чіткості налаштувань: не встановлюйте значення за замовчуванням або застарілі поля, якщо вони не змінюють контракт, який вам потрібен. Якщо метадані тензора або зображення вже містять інформацію про вихідний формат, уникайте повторення цієї інформації, якщо тільки на сторінці не пояснюється, чому це необхідно.

Посібник з ідентифікації та розшифрування сигналів​

Встановіть параметри декодування для визначення, коли маршрут має повертати декодовані обмежувальні рамки, результати визначення пози, або результати сегментації замість необроблених тензорів, отриманих у процесі виведення. Залиште поля без змін, якщо вам потрібні необроблені вихідні дані моделі.

ПолеВикористовуйте його, колиЗначення за замовчуванням.
decode_typeВам потрібен Neat, щоб додати етап BoxDecode для моделі виявлення.Unspecified; не виявлено наміру розшифрування.
decode_type_optionДля визначення порядку тензора в блоці виявлення потрібна певна варіація.Auto; нехай модель контракту та планувальник маршрутів приймуть рішення.
score_thresholdВи хочете відкинути кандидатів із низьким рівнем достовірності під час декодування.0; зберігайте список кандидатів до наступного етапу відбору.
nms_iou_thresholdПід час декодування слід застосовувати метод придушення локальних максимумів.0; зберігається значення, упаковане в модель. Якщо його немає, YOLO26 пропускає NMS, а інші декодери пригнічують кожну рамку, що перекривається.
top_kВи хочете встановити жорстке обмеження на кількість виявлених об’єктів для кожного результату.0; обмеження кількості найкращих результатів (top-K) відсутнє.
num_classesГлибину шару, що відповідає за класифікацію, неможливо надійно визначити, наприклад, у випадку з однокласовою версією YOLO, де використовується єдиний шар для класифікації.0; використовуйте метадані MPK або застарілі методи обробки.

Для більшості моделей, що використовують архітектуру YOLO, почніть з налаштування параметрів decode_type, score_threshold, nms_iou_threshold та top_k. Додайте параметр num_classes лише тоді, коли це необхідно для покращення роботи моделі. Залиште параметр decode_type_option у режимі Auto, якщо не відомо, що для обробки тензора потрібен певний селектор.

simaai::neat::Model::Options options;
options.decode_type = simaai::neat::BoxDecodeType::YoloV8;
options.score_threshold = 0.25f;
options.nms_iou_threshold = 0.45f;
options.top_k = 100;
options.num_classes = 1; // Set only when the model contract needs the class count.

simaai::neat::Model model(model_path, options);

Не використовуйте boxdecode_original_width або boxdecode_original_height у нових прикладах. Для інверсії координат використовуйте попередньо оброблені метадані; зберігайте ці метадані замість того, щоб жорстко кодувати розмір зображення.

Необроблений тензорний вхід.​

Використовуйте стандартні налаштування для тензорів, що відповідають model.input_specs(). Neat зберігає потрібні MPK тензорні адаптери.

simaai::neat::Model model(model_path);

Наявний параметр preprocess.enable = Off не вибирає виконання лише на MLA й не видаляє потрібні MPK адаптери Cast/Quant/Tess. Непорожній список preprocess.transforms має пріоритет над Off.

Підготуйте польовий довідник.​

ModelOptions.preprocess визначає, який тип вхідних даних ви надаватимете, і те, до чого Neat може адаптуватися перед виконанням обчислень.

ПотрібноПоле
Оберіть зображення або тензор як вхідні дані.preprocess.kind
Наявний перемикач попередньої обробки (потрібні MPK адаптери залишаються)preprocess.enable
Зв’язаний динамічний вхід для зображень.preprocess.input_max_width, preprocess.input_max_height, preprocess.input_max_depth
Змініть розмір, обріжте або додайте чорні смуги зверху та знизу.preprocess.resize
Перетворіть зображення у форматі RGB, BGR, NV12, I420 або відтінків сірого.preprocess.color_convert
Перетворіть порядок осей HWC, CHW або інший.preprocess.layout_convert
Застосуйте нормалізацію за допомогою середнього значення/стандартного відхилення.preprocess.normalize або preprocess.preset
Виконайте квантування перед виконанням обчислень.preprocess.quantize
Виконайте теселяцію перед виконанням обчислень.preprocess.tessellate
Замініть, використовуючи впорядкований список перетворень.preprocess.transforms

Вкажіть найменший набір параметрів, який описує вхідні дані, які ви фактично надсилаєте. Технічні характеристики є угодою; узгоджений план попередньої обробки – це підтвердження.

Перевірте характеристики та запустіть безпосередньо.​

Перш ніж створити Graph, перевірте зразок контракту. У технічній документації вказано, що потрібно розподілити, надіслати та розшифрувати.

simaai::neat::Model model(model_path, options);

const auto inputs = model.input_specs();
const auto outputs = model.output_specs();
const auto metadata = model.metadata();
const auto info = model.info();

for (const auto& input : inputs) {
const auto& shape = input.shape;
}

for (const auto& output : outputs) {
const auto& shape = output.shape;
}

simaai::neat::Tensor input = simaai::neat::Tensor::from_cv_mat(
frame,
simaai::neat::ImageSpec::PixelFormat::BGR,
simaai::neat::TensorMemory::CPU);

simaai::neat::TensorList result = model.run(
simaai::neat::TensorList{input},
/*timeout_ms=*/2000);

У Python передавайте список або кортеж вхідних даних. model.run([tensor]) означає «один вхід для моделі». Це не додає розмірність пакету.

model.run(...) працює в одноразовому режимі, а не перебудовує модель при кожному виклику. Під час першого виклику внутрішній модуль виконання будується та кешується; наступні виклики повторно використовують цей модуль і передають дані через нього. Використовуйте явну функцію model.build(...), коли вам потрібні параметри маршрутизації, параметри середовища виконання, вимірювання, керування закриттям/очищенням або цикл «виробник/споживач».

У C++, з підтримкою OpenCV, також доступна функція model.run(std::vector<cv::Mat>{frame}, timeout_ms). Використовуйте явну функцію Tensor::from_cv_mat(...), коли в прикладі необхідно вказати формат пікселів або власність пам’яті.

Працюйте з кількома вхідними даними та пакетами.​

Модель може мати кілька вхідних портів, визначений розмір пакету даних або обидва ці параметри. Не слід змішувати ці поняття:

  • Кілька вхідних даних означає один тензор на кожен вхід моделі. Перевірте model.input_specs(), щоб дізнатися про очікуваний порядок і структуру даних.
  • Пакет означає, що модель була скомпільована для обробки кількох логічних зразків за один цикл обчислень. Перевірте значення model.compiled_batch_size().
  • Вхідні списки Python визначають список для вхідних даних, а не розмір пакета. model.run([tensor]) є одним із вхідних списків. Він не перетворює tensor на пакет розміром 1.
const int batch = model.compiled_batch_size();
const auto specs = model.input_specs();

// Two-input model: pass one tensor per ingress.
simaai::neat::TensorList inputs{left_tensor, right_tensor};
simaai::neat::TensorList outputs = model.run(inputs, /*timeout_ms=*/2000);

Якщо пакетна модель очікує форму [N, ...], вкажіть N у формі тензора відповідно до специфікації вхідних даних. Не передавайте N окремі елементи списку Python, якщо модель не має N вхідних портів.

Перевірте план маршруту.​

Якщо під час попередньої обробки, виведення топології або вибору маршруту виникають несподівані результати, перевірте маршрут, а не намагайтеся вгадати.

ЗапитанняПеревірте.
Які розміри тензорів і типи даних підтримує модель?input_specs() та output_specs()
Що було зазначено в скомпільованому артефакті?info() та metadata()
Які вхідні дані потрібні для попередньої обробки?preprocess_requirements()
Який шлях попередньої обробки використовував Neat під час компіляції?resolved_preprocess_plan() / Python preprocess_plan()
Який розмір пакету даних використовувався під час компіляції?compiled_batch_size()
Який формат вихідних даних мені потрібно розшифрувати?характеристики вихідних даних, а також info().output_topology.
const auto requirements = model.preprocess_requirements();
const auto plan = model.resolved_preprocess_plan();

std::cout << "preprocess: " << plan.to_debug_string() << "\n";

Узгоджений план – це журнал аудиту, який містить таку інформацію: запитані параметри, дійсні параметри, сімейство графів, вхідні контракти, контракт MLA та попередження.

Перегляньте знімок поточного маршруту моделі.​

Використовуйте info(), коли вам потрібне стисле представлення маршруту без ручного перегляду архіву моделі. Python також надає summary() для швидкого текстового перегляду; C++ використовує структурований результат info().

ЗапитанняПоле info(), яке потрібно перевірити.
Який артефакт я завантажив?model_name, mpk_json_path
Які етапи адаптації необхідні?needs
Які адаптерні стадії доступні?capabilities
Чи передбачала схема обробки попередню або кінцеву обробку?selection.include_preprocess_stage, selection.include_postprocess_stage
Чи передбачає цей маршрут лише виведення результатів?selection.infer_only
Який тип попередньої обробки графа або подальшої обробки було обрано?selection.preprocess_graph, selection.selected_post_kind
Скільки вихідних даних є фізичними, а скільки – логічними?output_topology.physical_outputs, logical_outputs, packed_outputs
Які попередження згенерував планувальник маршруту?warnings
const auto info = model.info();

std::cout << "model=" << info.model_name << "\n";
std::cout << "physical_outputs=" << info.output_topology.physical_outputs
<< " logical_outputs=" << info.output_topology.logical_outputs << "\n";

for (const auto& warning : info.warnings) {
std::cerr << warning << "\n";
}

Ставтеся до попереджень щодо маршруту як до першочергової інформації. Якщо планувальник маршруту повідомляє про щось незвичайне, не намагайтеся обійти це. Спочатку внесіть зміни до угоди або параметрів.

Перегляньте, що виконує модель.​

Використовуйте execution_plan(), щоб побачити вузли, які виконує модель, де виконується кожен вузол і які тензори передаються між ними. Model::execution_plan(...) приймає ті самі аргументи, що й build(...), збирає модель без обробки кадру й закриває її після зчитування плану, тому потребує пристрою.

const simaai::neat::ExecutionPlan plan = model.execution_plan();
std::cout << plan.to_json() << "\n";

JSON перелічує вузли графа моделі в порядку конвеєра й містить одне ребро між кожною парою сусідніх вузлів.

ПолеЗначення
modelНазва моделі, batch (кадрів на один запуск MLA) і memory (пам’ять пристрою на один кадр в обробці)
nodes[].kindТип вузла, наприклад Input, Preproc, Quant, ModelFragment, Dequant, SimaBoxDecode або Output
nodes[].runs_onДе виконується вузол: A65 (ядра Arm), EV74 (процесор комп’ютерного зору) або MLA
nodes[].kernelЯдро (kernel), яке виконує вузол EV74 або A65
nodes[].settingsОстаточні налаштування Preproc і SimaBoxDecode з тими самими назвами, що в PreprocOptions і BoxDecodeOptions
edges[].tensorsТензори від одного вузла до наступного: shape із пакетом першим виміром, dtype і quant (scale, zero_point) для квантованих тензорів

Налаштування SimaBoxDecode показують пороги й top_k лише тоді, коли їх задає модель або ваші параметри; інакше діє типове значення декодера. Схема: schemas/execution_plan_v1.schema.json.

Використовуйте модель у графі.​

Для загальної схеми підключення додайте модель безпосередньо між загальним входом і виходом.

simaai::neat::Graph graph("classifier");
graph.add(simaai::neat::nodes::Input("image"));
graph.add(model);
graph.add(simaai::neat::nodes::Output("classes"));

Типовий публічний Input, безпосередньо підключений до єдиного входу зображення моделі, успадковує його спосіб інтерпретації зображення та формат. Формат джерела можна задати явно; граф перевіряє його відповідність контракту моделі. Пам’ять джерела, розміри, часові позначки та параметри черги не змінюються. Для кількох споживачів або неоднозначних з’єднань задайте параметри входу явно.

Ця інтерпретація застосовується на межі входу Graph. Безпосередні виклики моделі й далі вимагають входів, що відповідають оголошеному контракту зображення або тензора моделі.

Використовуйте model.graph(...), коли вам потрібен фрагмент, який можна повторно використовувати, або чітко визначені межі маршруту.

Параметри маршруту визначають, як цей фрагмент надає доступ до свого інтерфейсу:

ПотрібноВаріант маршруту
Додайте загальнодоступний вхідний вузол до отриманого графа.include_input
Додайте загальнодоступний вузол виводу до отриманого графа.include_output
Зробіть окремі фізичні виходи доступними.expose_all_outputs
Усуньте неоднозначність у назвах згенерованих елементів.name_suffix
Підключіться до конкретного елемента, що знаходиться вище за ієрархією.upstream_name
Замініть стандартні налаштування для виконання цього маршруту.advanced_execution
simaai::neat::Model::RouteOptions route;
route.include_input = true;
route.include_output = true;
route.name_suffix = "_detector";

simaai::neat::Graph model_fragment = model.graph(route);

Межі маршруту визначаються контрактом. Додавайте їх, коли потрібно, щоб фрагмент надавав доступ до публічних вхідних або вихідних даних. Не додавайте їх, коли модель є лише одним етапом у межах більшого графа.

Використовуйте фрагменти сцен для створення складніших композицій.​

Більшість програм повинні додавати повний шлях моделі. Використовуйте фрагменти етапів лише тоді, коли ви свідомо створюєте або налагоджуєте певний шлях.

simaai::neat::Graph preprocess =
model.fragment(simaai::neat::Model::Stage::Preprocess);
simaai::neat::Graph inference =
model.fragment(simaai::neat::Model::Stage::Inference);
simaai::neat::Graph postprocess =
model.fragment(simaai::neat::Model::Stage::Postprocess);

Розширені допоміжні засоби призначені для діагностики та цілеспрямованого створення програмного коду. Не використовуйте їх у коді, який виконується під час першого запуску.

ПомічникМоваВикористовуйте його, коли
backend_fragment(stage)C++ і PythonПід час налагодження маршруту вам потрібно перевірити фрагмент бекенду для одного з етапів моделі.
input_appsrc_options(tensor_mode)C++ і PythonДля моделі з одним входом необхідні точні параметри, отримані для вхідної межі, за допомогою InputOptions Neat.
input_appsrc_options_list(tensor_mode)C++Для багатовхідної моделі потрібні окремі InputOptions для кожного вхідного потоку.
find_config_path_by_plugin(plugin_id)C++ і PythonПід час збору доказів вам знадобиться файл конфігурації, отриманий для конкретного плагіна.
find_config_path_by_processor(processor)C++ і PythonВам потрібен файл конфігурації для процесора, наприклад, MLA, CVU або APU.
infer_output_name()C++ і PythonВам потрібна стандартна назва елемента вихідних даних на етапі логічного виведення для діагностики.

Якщо допоміжний інструмент розкриває імена внутрішніх компонентів або витягує файли, слід розглядати отримані дані як докази, а не як потік керування застосунком. Відкриті API для Model, Graph, Run, Input та Output повинні використовувати стандартний шлях застосунку.

Налаштовуйте виконання моделі лише після отримання базових результатів.​

Більшість моделей спочатку слід запускати зі стандартними налаштуваннями. Після того, як ви отримаєте правильну базову конфігурацію, використовуйте розширені поля налаштувань, щоб перевіряти зміни по черзі. Змініть одне налаштування, виміряйте результат і збережіть стандартну конфігурацію як контрольну точку.

advanced_execution є рекомендованим варіантом для нових документів і прикладів, оскільки кожне поле чітко визначає призначення. Поля, для яких не задано значення, не впливають на результат. Параметри на рівні маршруту мають пріоритет над параметрами на рівні моделі для цього маршруту.

ПотрібноПолеПримітки
Оберіть, де виконуватимуться попередні етапи обробки, якими керує модель.advanced_execution.preprocess_targetВикористовуйте цільові маркери, такі як "AUTO", "A65" або "EV74", лише під час підтвердження розташування.
Оберіть, де виконуватиметься постобробка, керована моделлю.advanced_execution.postprocess_targetВикористовуйте це для етапів постобробки, які можна виконувати для кількох цільових об’єктів.
Дозвольте виконувати попередню обробку асинхронно.advanced_execution.preprocess_asyncВиміряйте затримку та пропускну здатність до та після ввімкнення цієї функції.
Дозвольте виконувати логічні висновки MLA асинхронно.advanced_execution.inference_asyncКорисно для потокових обчислень, які забезпечують безперервність роботи.
Налаштуйте буферизацію вихідних даних під час виконання висновків.advanced_execution.inference_output_buffersЗбільшуйте лише тоді, коли вимірювання показують, що обмеження продуктивності пов’язане з буферизацією вихідних даних.
Відкладіть синхронізацію кешу виводу.advanced_execution.defer_output_cache_syncРозширений режим. Використовуйте лише тоді, коли чітко визначено термін служби пристрою та обсяг пам’яті.
Налаштувати внутрішню паралельністьadvanced_execution.internal_queue_depthОбмежує внутрішньо додані черги й місткість числового виконання Runner; не перевизначає буферизацію виходу MLA.

Про обмежене перекриття, час життя входу та вимірювання CPU на кадр див. Перекривайте кадри без необмеженого зростання черг. Збережене поле prepared_runner призначено для сумісності джерел, а не для вибору бекенду виконання. Залиште типове значення; вилучені режими спричиняють помилку під час побудови графа.

Встановіть розширені параметри виконання в найвужчій області, яка відповідає експерименту:

simaai::neat::Model::RouteOptions route;
route.name_suffix = "_lane0";
route.advanced_execution.inference_async = true;

auto runner = model.build(route);

Залиште стандартний маршрут як контрольний. Змініть одне поле, виміряйте, експортуйте дані, а потім вирішіть, чи варто зберігати цю зміну в застосунку.

C++ також надає доступ до низькорівневих полів processcvu, processmla, prepared_runner та async_queue_depth у Model::Options, Model::RouteOptions та GraphOptions. У прикладах для клієнтів віддавайте перевагу advanced_execution, якщо ви не зберігаєте наявний код C++ або не налагоджуєте конкретне низькорівневе поле.

Повторно використайте засіб запуску моделі.​

Використовуйте build(...), коли ви хочете уникнути повторного створення маршруту для кожного вхідного значення.

auto runner = model.build();

// Convenience path: push one input and wait for its output.
simaai::neat::TensorList result = runner.run(
simaai::neat::TensorList{input},
/*timeout_ms=*/2000);

// Async path: push now, pull later.
runner.push(simaai::neat::TensorList{input});
simaai::neat::Sample sample = runner.pull(/*timeout_ms=*/2000);

runner.close_input();
runner.close();

Використовуйте runner.run(...), коли кожен виклик має передавати один вхідний параметр і чекати на його вихід. Використовуйте push(...) / pull(...), коли вашій програмі потрібно підтримувати обробку даних у режимі реального часу. Використовуйте close_input(), коли більше не надходять вхідні дані, і ви хочете, щоб обробка залишку даних завершилася. Використовуйте close(), коли виконання runner-а завершено.

push очікує на вільне місце у вхідній черзі. Щоб надіслати дані без очікування, використовуйте runner.try_push із Sample або TensorList у C++, чи runner.try_push_samples / runner.try_push_tensors у Python. Встановіть RunOptions.queue_depth і overflow_policy до побудови runner-а. Коли обмежена черга заповнена, KeepLatest замінює найстарішу відкладену вибірку та повертає true; Block і DropIncoming повертають false. Закритий вхід також повертає false. Тримайте парні тензори одного кадру разом в одній вибірці TensorSet. Заміна не скасовує активне інференсування, а ці методи передавання не додають копіювання корисного навантаження.

Створіть спеціалізований інструмент для виконання завдань на основі певного маршруту.​

Використовуйте спеціальний засіб виконання для певного маршруту, коли потрібно, щоб повторно використовуваний засіб виконання використовував налаштування виконання на рівні маршруту або іменування маршруту, які відрізняються від налаштувань за замовчуванням. Model::build(...) автоматично визначає межі вхідних і вихідних даних для засобу виконання.

simaai::neat::Model::RouteOptions route;
route.name_suffix = "_detector";

auto runner = model.build(route);

Запустіть процес збірки, коли необхідно перевірити сумісність вхідних даних щодо форми, формату або структури, перш ніж виконувати перше розгортання у виробниче середовище:

auto runner = model.build(simaai::neat::TensorList{input}, route);

Використовуйте збірку з попередньо визначеними параметрами для тестування та виявлення помилок на ранніх етапах, а не робіть це звичкою. Якщо стандартна збірка вже підтверджує правильність виконання, зробіть приклад меншим.

Для вхідного зображення початковий зразок задає поточну форму та формат пікселів; він не замінює preprocess.input_max_width, input_max_height або input_max_depth. Наприклад, зразок 640×640 із заданою місткістю 1920×1920 дозволяє тому самому виконавцю приймати наступні кадри 800×800 і 1920×1080. Кадри, що перевищують місткість, відхиляються. Якщо межі не задано, зберігається та сама визначена місткість, що й під час побудови без початкового зразка.

Вимірюйте час виконання моделі.​

Використовуйте model.benchmark(...) для швидкого синтетичного тестування моделі. Він генерує вхідні дані на основі input_specs() і повертає показники затримки, пропускної здатності, потужності та телеметрії плати. Використовуйте його для порівняння змін у моделі/середовищі виконання, а не для підтвердження показників пропускної здатності у виробничому середовищі.

simaai::neat::BenchmarkReport report = model.benchmark();

std::cout << "latency_ms=" << report.latency_ms
<< " fps=" << report.fps << "\n";

Для маршруту BoxDecode опишіть геометрію вихідного зображення синтетичних даних, щоб еталонний тест міг зіставити виявлені об’єкти з координатами моделі:

simaai::neat::BenchmarkOptions options;
options.num_samples = 100;
options.original_width = 1920;
options.original_height = 1080;
options.resize_mode = simaai::neat::ResizeMode::Letterbox;

simaai::neat::BenchmarkReport report = model.benchmark(options);

Встановіть original_width і original_height разом. Тест все ще генерує синтетичний тензор, що має форму моделі; ці поля містять вихідну геометрію та трансформацію зміни розміру, необхідні для метаданих BoxDecode. Якщо їх не вказати, тест визначає геометрію на основі попередньої обробки та контракту вхідних даних моделі. Ці значення для кожного запуску мають пріоритет над застарілими підказками щодо геометрії BoxDecode в ModelOptions. Існуючі виклики benchmark(num_samples) зберігають ту саму поведінку.

Щоб також виміряти час кожного шару або етапу MLA, встановіть include_mla_layer_stats або include_mla_stage_stats. Щоб зберегти результати, report.save(path) записує звіт у форматі YAML, а для шляху з .json — у форматі JSON. Обидва варіанти показано в Тестування продуктивності моделі.

Вимірювання з власними вхідними даними​

Синтетичні вхідні дані можуть спотворювати результати для моделі, вартість якої залежить від даних, наприклад для декодера виявлення або сегментації. Щоб виміряти на реальних даних, задайте в inputs тензори, які ви передали б у run(), по одному на кожен вхід моделі. Бенчмарк використовує їх і для вимірювання затримки, і для вимірювання пропускної здатності.

cv::Mat image;
cv::cvtColor(cv::imread("bus.jpg"), image, cv::COLOR_BGR2RGB); // the format input_specs() reports

simaai::neat::BenchmarkOptions options;
options.inputs = simaai::neat::TensorList{
simaai::neat::Tensor::from_cv_mat(image, simaai::neat::ImageSpec::PixelFormat::RGB,
simaai::neat::TensorMemory::EV74)};

simaai::neat::BenchmarkReport report = model.benchmark(options);
std::cout << "input=" << report.input << " fps=" << report.fps << "\n"; // input=provided

Якщо кількість, форма або тип вхідних даних не відповідають моделі, benchmark() ще до початку викидає NeatError з кодом помилки misconfig.input_shape. Колірний формат, який маршрут не може перетворити, спричиняє помилку під час побудови конвеєра, як і в run(). На маршруті з попередньою обробкою зображень зображення може мати будь-який розмір. Передавайте його в колірному форматі, який повідомляє input_specs().

Тривалість запуску​

Тест вимірює затримку, подаючи вхідні дані по одному (single-flight), а потім виконує окремий прохід для вимірювання пропускної здатності. Кожен прохід триває, доки не виміряє щонайменше num_samples вхідних даних і не мине min_duration_ms (типово 10 с), тож обидва проходи зупиняються за одним правилом, а показники потужності й температури проходу пропускної здатності охоплюють кілька зразків телеметрії, а не короткий сплеск. latency_ms — це середня затримка проходу вимірювання затримки, а latency_p50_ms, latency_p95_ms і latency_p99_ms — її процентилі. throughput_samples і throughput_duration_ms показують, що саме виміряв прохід пропускної здатності. Для швидкої перевірки встановіть min_duration_ms на 0, щоб кожен прохід зупинявся після num_samples вхідних даних:

simaai::neat::BenchmarkOptions options;
options.min_duration_ms = 0;
simaai::neat::BenchmarkReport report = model.benchmark(options);

Потужність і телеметрія плати​

Дані про потужність і телеметрію плати надходять від Sentinel — демона телеметрії DevKit, який інсталятор Neat налаштовує на платі. Тест записує їх за допомогою TelemetryMonitor під час проходу вимірювання пропускної здатності. Він вибирає зразки після початку та до завершення вимірювання, коли завершено всі потрібні виходи. Підготовка, приєднання робочого потоку монітора й останнє читання Sentinel не подовжують вимірюване навантаження. Недопустимі часові позначки зразків або виявлені розриви годинника роблять телеметрію тесту недоступною замість вибору стороннього часового вікна. report.telemetry підсумовує ці дані:

ПолеЗначення
avg_power_watts, peak_power_wattsОцінна середня й найвища потужність SoM під час проходу вимірювання пропускної здатності.
energy_joulesЕнергія для обробки num_samples вхідних даних: середня потужність, помножена на час, який за виміряної пропускної здатності потрібен для обробки num_samples вхідних даних. Довший прохід її не збільшує.
telemetry.power_mla_watts, telemetry.power_rails_wattsПотужність шини живлення MLA та всіх шин живлення, про які повідомляє плата. Плати без шини MLA повідомляють її з samples == 0.
telemetry.die_temperatures_c, telemetry.die_temperature_max_cДатчики температури кристала в зонах MLA, APU, CVU і TOP, а також найгарячіший із них у кожному зразку.
telemetry.board_temperatures_cДатчики на верхньому й нижньому боці SoM.
telemetry.cpu_usage_pctЗавантаження CPU. Кожен зразок усереднює попередній інтервал, тож maximum відповідає найбільш завантаженому інтервалу.
telemetry.cpu_cores_usage_pctЗавантаження кожного ядра CPU в порядку ядер. Одне завантажене ядро видно тут, навіть коли cpu_usage_pct, середнє за всіма ядрами, залишається низьким.
telemetry.mla_memory_mibПам’ять, яку утримує MLA, у MiB: буфери з пулу пам’яті MLA, а також спільні буфери, які використовує лише MLA. Модель виділяє її під час завантаження, тож якщо нічого іншого не запущено, це пам’ять MLA моделі.
telemetry.ev74_memory_mibПам’ять, яку утримує EV74, у MiB, наприклад вхідні кадри, які EV74 попередньо обробляє для MLA. Спільний буфер, який використовують і EV74, і MLA, рахується тут, а не в mla_memory_mib, тож разом ці два значення дають пам’ять прискорювачів моделі. Кадри, створені відеодекодером або ISP камери, не входять у жодне з них.
telemetry.linux_memory_used_mibПам’ять, яку використовує вся плата (Linux MemTotal - MemAvailable), у MiB. Вона містить усі процеси та буфери EV74, тому не додавайте її до двох значень вище.

Кожна метрика повідомляє samples, mean, minimum, maximum і last; samples == 0 означає, що плата не повідомила цю метрику. Повідомлений нуль теж рахується як зразок: коли модель не завантажено, mla_memory_mib і ev74_memory_mib показують 0 MiB при samples > 0. Sentinel збирає зразки кожні 2 с, тож 10-секундний прохід дає близько 5 зразків. Кожне значення охоплює всю плату, зокрема інші запущені процеси.

Якщо Sentinel не запущено або прохід закороткий, щоб зібрати хоча б один зразок, тест усе одно повертає затримку та FPS. Поля потужності залишаються нульовими, telemetry.status містить причину (інакше він дорівнює "ok"), а у виведеному зведенні відображається Power: unavailable (<reason>).

Вимірюйте власний цикл​

Використовуйте вимірювання runner, коли ви контролюєте цикл вхідних даних і хочете виміряти цей цикл:

auto runner = model.build();
auto scope = runner.start_measurement();

for (const auto& input : inputs) {
(void)runner.run(simaai::neat::TensorList{input}, /*timeout_ms=*/2000);
}

simaai::neat::MeasureReport report = scope.stop();
runner.close();

Не порівнюйте одноразове тестування, яке виконується один раз, із повторним тестуванням, яке виконується кілька разів. Вони відповідають на різні запитання.

Записуйте телеметрію плати​

Використовуйте TelemetryMonitor, щоб записувати потужність, температури, завантаження CPU та пам’ять за будь-яке вибране вами вікно, наприклад за ваш власний цикл інференсу. Він читає ці дані із Sentinel і повертає таке саме зведення Telemetry, як report.telemetry:

simaai::neat::TelemetryMonitor monitor;
monitor.start();

for (const auto& input : inputs) {
(void)runner.run(simaai::neat::TensorList{input}, /*timeout_ms=*/2000);
}

simaai::neat::Telemetry telemetry = monitor.stop();
std::cout << telemetry; // YAML
telemetry.save("telemetry.json"); // .json writes JSON; other names write YAML

Типово монітор читає /run/simaai-sentinel/api.sock. Щоб використовувати Unix-сокет Sentinel, змонтований за іншим шляхом, передайте цей шлях у TelemetryMonitor(socket_path) у C++ або pyneat.TelemetryMonitor(socket_path="...") у Python. Це вибирає кінцеву точку лише для цього монітора; не змінює Model::benchmark() і не запускає Sentinel. Під час створення монітор не звертається до сокета.

  • start() починає нове вікно. Враховуються лише зразки, які Sentinel робить після цього виклику, а Sentinel збирає зразки кожні 2 с, тож коротше вікно може не мати жодного зразка; тоді про це повідомляє status.
  • read() повертає зведення на поточний момент, не зупиняючи монітор. last кожного вимірювання — його найновіше значення, а mean, minimum і maximum охоплюють вікно до цього моменту.
  • stop() повертає остаточне зведення. Повторний виклик повертає той самий результат.
  • Зведення зберігає один запис на кожне вимірювання, тож використання пам’яті не змінюється, хоч би як довго тривало вікно.
  • Кілька моніторів, в одному процесі чи в кількох, можуть працювати одночасно один з одним і з Model::benchmark().
  • Кожне значення охоплює всю плату, зокрема Sentinel, монітор та інші процеси. Кожне значення потужності отримується з одного зчитування тривалістю 250 мс на зразок, тож короткі сплески між зчитуваннями не відображаються.
  • Якщо Sentinel не запущено, монітор виводить одне попередження, status пояснює, як установити або запустити Sentinel, а монітор починає враховувати зразки, щойно Sentinel відповість. Через проблеми із Sentinel монітор ніколи не генерує винятків.
  • У Python start(), read() і stop() звільняють GIL на час очікування.

Розшифруйте вихідні дані.​

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

Вихідний контрактВикористовуйте
Необроблений тензор.Використовуйте отриманий тензор безпосередньо або конвертуйте його за допомогою to_numpy(...) / to_torch(...) у Python.
Зібрані в коробки об’єкти, представлені у вигляді тензорів.C++ simaai::neat::decode_bbox(...) / Python pyneat.decode_bbox(...)
Упаковані коробки, що містять надруковані записи.C++ simaai::neat::decode_bbox_tensor(...) / Python pyneat.detections.decode_bbox_tensor(...)
Згрупована поза.C++ simaai::neat::decode_pose(...) / Python pyneat.decode_pose(...)
Ущільнена сегментаціяC++ simaai::neat::decode_segmentation(...) / Python pyneat.decode_segmentation(...)

Використовуйте декодування тензорів, коли наступний етап потребує тензорів. Використовуйте типізоване декодування, коли коду застосунку потрібні записи з x1, y1, x2, y2, score та class_id.

const auto decoded = simaai::neat::decode_bbox_tensor(
outputs[0],
image_width,
image_height,
/*expected_topk=*/100,
/*strict=*/true);

for (const auto& box : decoded.boxes) {
handle_box(box.x1, box.y1, box.x2, box.y2, box.score, box.class_id);
}

Використовуйте допоміжні функції декодування лише для тих форматів вихідних даних, які вони підтримують.

Обробка помилок​

Графи, що керуються моделлю, використовують той самий набір діагностичних інструментів, що й базовий Graph:

  • NeatError.report().error_code для випадків збою в роботі термінала.
  • NeatError.report().repro_note для надання практичної інформації та підказок.
  • NeatError.report().bus для отримання детальної інформації про плагін або середовище виконання.
try {
auto result = model.run(simaai::neat::TensorList{input}, /*timeout_ms=*/2000);
} catch (const simaai::neat::NeatError& error) {
const auto& report = error.report();
std::cerr << report.error_code << "\n";
std::cerr << report.repro_note << "\n";
}

Почніть з перевірки значень, таких як error_code, зокрема misconfig.*, build.*, runtime.* або io.*. Переглядайте журнали шини лише після того, як структуровані повідомлення про помилки вкажуть на це.

Див. також​

Навчальні матеріали​