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

Запустіть свою першу модель

ПолеЗначення
КатегоріяМоделі та інференс
СкладністьПочатковий
Орієнтовний час читання<5 minutes
Міткиmodel, inference, foundations

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

Скомпільована модель — це архів .tar.gz, який можна розгорнути, і який містить контракт для виконання висновків MPK: артефакти моделі плюс метадані Neat, необхідні для її виконання на цільовому пристрої. Вам не потрібно розпаковувати його або самостійно налаштовувати етапи — ви вказуєте Neat на архів, передаєте йому вхідні дані та зчитуєте вихідні дані. В результаті ви виконаєте обробку в три рядки та виведете індекс класу top1=.

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

Завантаження моделі

Перший рядок перетворює шлях до файлу на робочу, виконувану Model: конструктор завантажує архів і готує його до виконання.

Ви передаєте build_options(size) як другий аргумент, щоб вказати контракт вхідних даних, який очікує ця модель: колір RGB, 224×224, і нормалізацію ImageNet, з якою була навчена ResNet-50. Вказуючи це тут, ви повідомляєте середовищу виконання, як перетворити необроблене зображення на тензор, який потрібен моделі.

tutorials/001_run_your_first_model/run_your_first_model.cpp
simaai::neat::Model model(model_path, build_options(size));

Підготовка вхідних даних

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

Кадр — це cv::Mat, створений за допомогою load_rgb(...) або як сірий заповнювач.

tutorials/001_run_your_first_model/run_your_first_model.cpp
cv::Mat input = image.empty() ? cv::Mat(size, size, CV_8UC3, cv::Scalar(99, 99, 99))
: load_rgb(image, size);

Виконання висновків і зчитування результату

Третій рядок виконує фактичну роботу: run() приймає вхідні дані та timeout_ms, виконує модель синхронно та повертає вихідні дані. timeout_ms — це максимальний час очікування; 2000 мс тут означає «видавати гучну помилку, якщо пристрій не видав вихідні дані протягом двох секунд», а не зависати на невизначений час. (Передача -1 блокує на невизначений час; у реальному коді краще використовувати скінченне значення). Потім ми зводимо вихідні дані до одного індексу класу за допомогою argmax і виводимо top1=.

run() повертає TensorList; зчитайте байти першого тензора за допомогою map_read().

tutorials/001_run_your_first_model/run_your_first_model.cpp
simaai::neat::TensorList outputs = model.run(std::vector<cv::Mat>{input}, /*timeout_ms=*/2000);

Запуск

Запустіть програму, і ви повинні побачити передбачений індекс класу, який буде виведено в стандартний вивід (stdout). Запустіть команди Python і C++ (попередньо скомпільовані) з Neat встановити в кореневу директорію **(директорію, яка містить) share/ і lib/); виконайте команди збірки з вихідного коду з кореневої директорії репозиторію.

C++ (prebuilt):

./lib/sima-neat/tutorials/tutorial_001_run_your_first_model \
--model /tmp/resnet_50.tar.gz

C++ (build from source):

./build.sh --target tutorial_001_run_your_first_model
./build/tutorials-standalone/tutorial_001_run_your_first_model \
--model /tmp/resnet_50.tar.gz

Очікуваний результат (точний індекс залежить від зображення):

top1=285
[OK] 001_run_your_first_model

Щоб інтегрувати вихідний код C++, наведений у цьому розділі, у ваш власний проєкт із використанням спеціального CMakeLists.txt (додаткова тека не потрібна), див. Як запускати навчальні матеріали на головній сторінці.

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

На практиці

Де навчальні матеріали та тести шукають архіви моделей (.tar.gz) та приклади ресурсів, а також способи їх надання локально. Це є обов’язковою умовою для кожного навчального посібника, що базується на моделі.

Переконайтеся sima-cli міститься в PATH

Деякі тести викликають sima-cli з неінтерактивних оболонок. Використовуйте це один раз після встановлення. sima-cli:

SIMA_CLI_BIN_DIR="<path-to-sima-cli-bin>"
grep -Fqx "export PATH=\"${SIMA_CLI_BIN_DIR}:\$PATH\"" ~/.bashrc || echo "export PATH=\"${SIMA_CLI_BIN_DIR}:\$PATH\"" >> ~/.bashrc
source ~/.bashrc

Потім перевірте:

/bin/sh -c 'command -v sima-cli'

Розташування архіву моделі та змінні середовища

Налаштування для вилучення/розміщення в середовищі виконання:

  • SIMA_MPK_EXTRACT_ROOT=<dir> встановлює базову директорію для вилучення даних.
  • SIMA_MPK_CLEANUP_EXTRACTED=0 зберігає вилучені дані моделі proc_* після завершення процесу.
  • SIMA_MPK_EXTRACT_GC_STALE_PROC=0 вимикає очищення неактивних proc_* під час запуску.

ResNet50

Порядок пошуку:

  1. SIMA_RESNET50_TAR (заміна для кожної моделі)
  2. SIMA_MODEL_TAR (спільний варіант для резервного копіювання тестів/прикладів моделі-архіву)
  3. tmp/resnet_50.tar.gz
  4. Локальні файли переміщено до tmp/ якщо знайдено: resnet_50.tar.gz, resnet-50.tar.gz

Завантажити (якщо sima-cli доступний):

sima-cli modelzoo get resnet_50

Зразки зображень

Зображення, які використовуються за замовчуванням у навчальних матеріалах/тестах:

  • tmp/coco_sample.jpg (завантажується, якщо відсутній)
  • test.jpg
  • tests/assets/preproc_dynamic/ilena_488.jpg

Ви можете змінити URL-адресу зображення COCO, що використовується в тестах, за допомогою:

SIMA_COCO_URL=<custom_url>

Куди завантажуються тестові файли

Зазвичай, тестові файли та приклади розміщують завантажені ресурси в папці tmp/ у кореневій директорії репозиторію. У разі відсутності необхідних ресурсів, навчальні матеріали коректно пропустять відповідний крок.

Усунення несправностей з ресурсами

  • Якщо навчальний матеріал виводить повідомлення SKIP: missing ..., надайте необхідний ресурс або передайте відповідний прапорець (наприклад, --model <path>, --image <path>).
  • Якщо sima-cli недоступний, встановіть змінні середовища, щоб вказати шлях до локальних архівів моделей.

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

Показати повні програми
tutorials/001_run_your_first_model/run_your_first_model.cpp
// Run a ResNet-50 model on an image in three lines of Neat.
//
// Usage:
// tutorial_001_run_your_first_model --model /path/to/resnet_50.tar.gz [--image /path/to.jpg]

#include "neat.h"

#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>

#include <cstring>
#include <filesystem>
#include <iostream>
#include <stdexcept>
#include <string>

namespace fs = std::filesystem;

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;
}

cv::Mat load_rgb(const fs::path& image_path, int size) {
cv::Mat bgr = cv::imread(image_path.string(), cv::IMREAD_COLOR);
if (bgr.empty())
throw std::runtime_error("failed to read image: " + image_path.string());
if (bgr.cols != size || bgr.rows != size) {
cv::resize(bgr, bgr, cv::Size(size, size), 0, 0, cv::INTER_AREA);
}
cv::Mat rgb;
cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB);
if (!rgb.isContinuous())
rgb = rgb.clone();
return rgb;
}

simaai::neat::Model::Options build_options(int size) {
simaai::neat::Model::Options opt;
opt.preprocess.kind = simaai::neat::InputKind::Image;
opt.preprocess.color_convert.input_format = simaai::neat::PreprocessColorFormat::RGB;
opt.preprocess.input_max_width = size;
opt.preprocess.input_max_height = size;
opt.preprocess.input_max_depth = 3;
opt.preprocess.preset = simaai::neat::NormalizePreset::ImageNet;
return opt;
}

int top1_from_output(const simaai::neat::TensorList& out) {
if (out.empty())
throw std::runtime_error("no tensor output");
const simaai::neat::Mapping m = out.front().map_read();
const size_t n = m.size_bytes / sizeof(float);
const float* p = reinterpret_cast<const float*>(m.data);
int best = 0;
for (size_t i = 1; i < n && i < 1000; ++i) {
if (p[i] > p[best])
best = static_cast<int>(i);
}
return best;
}

} // namespace

int main(int argc, char** argv) {
try {
std::string model_path, image;
if (!get_arg(argc, argv, "--model", model_path)) {
std::cerr << "Usage: tutorial_001_run_your_first_model --model <path> [--image <path>]\n";
return 1;
}
get_arg(argc, argv, "--image", image);

const int size = 224;

// CORE LOGIC
// The three-line Neat story:
simaai::neat::Model model(model_path, build_options(size));
cv::Mat input = image.empty() ? cv::Mat(size, size, CV_8UC3, cv::Scalar(99, 99, 99))
: load_rgb(image, size);
simaai::neat::TensorList outputs = model.run(std::vector<cv::Mat>{input}, /*timeout_ms=*/2000);

std::cout << "top1=" << top1_from_output(outputs) << "\n";
std::cout << "[OK] 001_run_your_first_model\n";
return 0;
} catch (const std::exception& e) {
std::cerr << "[FAIL] " << e.what() << "\n";
return 1;
}
}

Джерело