Платформа и источник
Статья подготовлена по PDF производителя RKNN V2.5.0 и относится только к перечисленным в нём чипам и интерфейсам. Для платы ArmSoM сначала проверьте SoC, драйвер NPU, Toolkit/Runtime, SDK/BSP и версию ядра. Проверки на оборудовании ArmSoM не проводились; примеры и измерения оригинала не являются тестами ArmSoM.
Навигация по серии
- Платформы, заголовки и компоновка
- Владение памятью и общий/zero-copy процессы
- Устройство, контекст и флаги инициализации
- Запросы модели, тензоров и динамических форм
- Вход, выполнение, выход и динамические формы
- Тензоры, выделение памяти и синхронизация
- Матричное умножение и динамические формы
- Регистрация и атрибуты пользовательских операторов
- Коды состояния, тензоры, память и расширения
- Структуры матричного умножения
- Структуры операторов и миграция устаревших API
3. Общие соглашения C API
3.1 Различия платформ
Из-за аппаратных различий набор интерфейсов и параметров RKNN C API зависит от платформы. Поддержка интерфейсов приведена в таблице 3-1:
Таблица 3-1. Поддержка RKNN C API на аппаратных платформах
| RKNN C API | RV1126B/RK3562/RK3566/ RK3568 |
RK3576/ RK3588 | RV1106/RV1103/ RV1103B/RV1106B |
RK2118 | |
|---|---|---|---|---|---|
| 1 | rknn_init | √ | √ | √ | √ |
| 2 | rknn_set_core_mask | × | √ | × | × |
| 3 | rknn_dup_context | √ | √ | × | × |
| 4 | rknn_destroy | √ | √ | √ | √ |
| 5 | rknn_query | √ | √ | √ | √ |
| 6 | rknn_inputs_set | √ | √ | × | × |
| 7 | rknn_run | √ | √ | √ | √ |
| 8 | rknn_wait | × | × | × | × |
| 9 | rknn_outputs_get | √ | √ | × | × |
| 10 | rknn_outputs_release | √ | √ | × | × |
| 11 | rknn_create_mem_from_mb_blk | × | × | × | × |
| 12 | rknn_create_mem_from_phys | √ | √ | √ | √ |
| 13 | rknn_create_mem_from_fd | √ | √ | √ | × |
| 14 | rknn_create_mem | √ | √ | √ | √ |
| 15 | rknn_destroy_mem | √ | √ | √ | √ |
| 16 | rknn_set_weight_mem | √ | √ | √ | √ |
| 17 | rknn_set_internal_mem | √ | √ | √ | √ |
| 18 | rknn_set_io_mem | √ | √ | √ | √ |
| 19 | rknn_set_input_shapes | √ | √ | × | × |
| 20 | rknn_mem_sync | √ | √ | √ | √ |
| 21 | rknn_matmul_create | √ | √ | × | × |
| 22 | rknn_matmul_set_io_mem | √ | √ | × | × |
| 23 | rknn_matmul_set_core_mask | × | √ | × | × |
| 24 | rknn_matmul_run | √ | √ | × | × |
| 25 | rknn_matmul_destroy | √ | √ | × | × |
| 26 | rknn_register_custom_ops | √ | √ | × | × |
| 27 | rknn_custom_op_get_op_attr | √ | √ | × | × |
| 28 | rknn_set_batch_core_num | × | √ | × | × |
| 29 | rknn_matmul_set_quant_params | √ | √ | × | × |
| 30 | rknn_matmul_get_quant_params | √ | √ | × | × |
| 31 | rknn_matmul_create_dynamic_shape | √ | √ | × | × |
| 32 | rknn_matmul_set_dynamic_shape | √ | √ | × | × |
| 33 | rknn_B_normal_layout_to_native_layout | √ | √ | × | × |
| 34 | rknn_create_mem2 | √ | √ | √ | √ |
Поддержка параметров запроса rknn_query на разных платформах приведена в таблице 3-2:
Таблица 3-2. Поддерживаемые параметры rknn_query по платформам
| Параметры rknn_query | RV1126B/RK3562/RK3566/ RK3568 |
RK3576/ RK3588 | RV1106/RV1103/ RV1103B/RV1106B/RK2118 |
|
|---|---|---|---|---|
| 1 | RKNN_QUERY_IN_OUT_NUM | √ | √ | √ |
| 2 | RKNN_QUERY_INPUT_ATTR | √ | √ | √ |
| 3 | RKNN_QUERY_OUTPUT_ATTR | √ | √ | √ |
| 4 | RKNN_QUERY_PERF_DETAIL | √ | √ | × |
| 5 | RKNN_QUERY_PERF_RUN | √ | √ | × |
| 6 | RKNN_QUERY_SDK_VERSION | √ | √ | √ |
| 7 | RKNN_QUERY_MEM_SIZE | √ | √ | √ |
| 8 | RKNN_QUERY_CUSTOM_STRING | √ | √ | √ |
| 9 | RKNN_QUERY_NATIVE_INPUT_ATTR | √ | √ | √ |
| 10 | RKNN_QUERY_NATIVE_OUTPUT_ATTR | √ | √ | √ |
| 11 | RKNN_QUERY_NATIVE_NC1HWC2_INPUT_ATTR | √ | √ | √ |
| 12 | RKNN_QUERY_NATIVE_NC1HWC2_OUTPUT_ATTR | √ | √ | √ |
| 13 | RKNN_QUERY_NATIVE_NHWC_INPUT_ATTR | √ | √ | √ |
| 14 | RKNN_QUERY_NATIVE_NHWC_OUTPUT_ATTR | √ | √ | √ |
| 15 | RKNN_QUERY_INPUT_DYNAMIC_RANGE | √ | √ | × |
| 16 | RKNN_QUERY_DEVICE_MEM_INFO | × | × | √ |
| 17 | RKNN_QUERY_CURRENT_INPUT_ATTR | √ | √ | × |
| 18 | RKNN_QUERY_CURRENT_OUTPUT_ATTR | √ | √ | × |
| 19 | RKNN_QUERY_CURRENT_NATIVE_INPUT_ATTR | √ | √ | × |
| 20 | RKNN_QUERY_CURRENT_NATIVE_OUTPUT_ATTR | √ | √ | × |
3.2 Владение памятью
Память API: тензорная память, выделенная rknn_create_mem, принадлежит вызывающей стороне. По окончании использования её необходимо освободить rknn_destroy_mem. Не допускайте двойного освобождения.
Память пользователя: память, переданная rknn_set_weight_mem, rknn_set_internal_mem и rknn_set_io_mem, остаётся собственностью вызывающей стороны, которая освобождает её после использования.
Обёртки внешней памяти: rknn_create_mem_from_fd, rknn_create_mem_from_phys и rknn_create_mem_from_mb_blk связывают ранее выделенную память (дескриптор файла, физический адрес или mb_blk) с RKNN для zero-copy. Объект-обёртку rknn_tensor_mem также необходимо освободить через rknn_destroy_mem.
3.3 Срок действия входных и выходных данных
Массив inputs и данные, на которые указывает buf в rknn_inputs_set, должны оставаться действительными во время вызова.
Массив outputs для rknn_outputs_get пользователь создаёт заранее, задавая index. При is_prealloc=1 buf заранее выделяется пользователем и должен быть действительным во время вызова. При is_prealloc=0 buf выделяет интерфейс, и память остаётся действительной до rknn_outputs_release. После освобождения указатель buf недействителен и не должен использоваться.
Память входных/выходных тензоров, заданная rknn_set_io_mem, должна оставаться действительной во время вызова и быть установлена до rknn_run.
3.4 Возвращаемые значения и обработка ошибок
Большинство интерфейсов возвращают int: 0 означает успех, отрицательное значение — ошибку. Некоторые возвращают указатели (rknn_create_mem, rknn_create_mem_from_fd, rknn_create_mem_from_phys, rknn_create_mem_from_mb_blk) и NULL при ошибке.
Полные определения приведены в 6.1 «Коды состояния».
Проверяйте результат каждого вызова и определяйте причину по коду: например, RKNN_ERR_DEVICE_UNMATCH означает несовпадение версии, RKNN_ERR_CTX_INVALID — недействительный контекст.
3.5 Общий API и zero-copy API
При инференсе данные проходят обработку входа, выполнение модели на NPU и обработку выхода. В зависимости от формата и квантования используются общий API либо zero-copy API. Основные различия использования и последовательности вызовов:
Общий API: простой набор интерфейсов rknn_inputs_set/rknn_outputs_get/rknn_outputs_release. При каждом обновлении кадра данные внешнего модуля копируются во входную память NPU Runtime. Нормализация, квантование, преобразование компоновки и деквантование выполняются преимущественно CPU, инференс — NPU.
Zero-copy API: создаёт или оборачивает память через rknn_create_mem/rknn_create_mem_from_fd/rknn_create_mem_from_phys и задаёт её через rknn_set_io_mem. Прямое использование заранее выделенной памяти NPU Runtime или внешней системы, например DRM, уменьшает копирование, повышает производительность и снижает трафик памяти. Нормализация, квантование и инференс выполняются на NPU.
Выбор интерфейса: при наличии только виртуального адреса входных данных используется только общий API; при физическом адресе или fd — zero-copy API. Общий и zero-copy API нельзя смешивать.
Последовательность общего API (рисунок 3-1):
- Вызовите rknn_init() для инициализации модели;
- Запросите атрибуты входов/выходов через rknn_query();
- Предварительно обработайте вход;
- Задайте входные данные через rknn_inputs_set();
- Выполните инференс через rknn_run();
- Получите результаты через rknn_outputs_get();
- Обработайте выход;
- Освободите выходную память через rknn_outputs_release();
- Уничтожьте RKNN через rknn_destroy().

Рисунок 3-1. Последовательность общего API
Последовательность zero-copy API (пример с памятью входа/выхода, выделенной Runtime, рисунок 3-2):
- Вызовите rknn_init() для инициализации модели;
- Запросите нативные атрибуты через rknn_query() (RKNN_QUERY_NATIVE_INPUT_ATTR/RKNN_QUERY_NATIVE_OUTPUT_ATTR);
- Предварительно обработайте вход (необязательно);
- Создайте входные/выходные rknn_tensor_mem через rknn_create_mem() (для внешней памяти используйте rknn_create_mem_from_fd()/rknn_create_mem_from_phys());
- Задайте входную/выходную память через rknn_set_io_mem();
- Выполните инференс через rknn_run();
- Прочитайте выходную память из rknn_tensor_mem и выполните постобработку;
- Освободите входную/выходную память через rknn_destroy_mem();
- Уничтожьте RKNN через rknn_destroy().

Рисунок 3-2. Последовательность zero-copy API с внутренним выделением памяти
Подробнее о rknn_set_io_mem() см. 5.4 «Тензоры и память».
Источник и редакционные примечания
Технические главы разделены по назначению. Код, идентификаторы и параметры сохранены. Китайская версия следует китайскому оригиналу; английская, русская и немецкая — английскому. В главы без иллюстраций вымышленные изображения не добавлены.
Оговорки оригинала: номера глав и примерные журналы сохранены; ранние версии SDK в журналах не являются версией этой статьи. Runtime переходит от главы 3 к 5 и повторяет номера запросов. Таблица rknn_init называет extend отключённым, но далее описывает user_key и общие веса. Текст о нативном динамическом выходе указывает RKNN_QUERY_CURRENT_OUTPUT_ATTR, пример — RKNN_QUERY_CURRENT_NATIVE_OUTPUT_ATTR. Некоторые описания native NHWC/NC1HWC2 смешивают вход и выход. Проверяйте фактические заголовки V2.5.0 и целевой SDK: поведение не подтверждено тестами. Ссылка RK2118 в оригинале называется RKNN3_RK2118_Quick_Start.pdf, а в текущем каталоге находится руководство RKNN2.
