Платформа и источник
Статья подготовлена по PDF производителя RKNN V2.5.0 и относится только к перечисленным в нём чипам и интерфейсам. Для платы ArmSoM сначала проверьте SoC, драйвер NPU, Toolkit/Runtime, SDK/BSP и версию ядра. Проверки на оборудовании ArmSoM не проводились; примеры и измерения оригинала не являются тестами ArmSoM.
Навигация по серии
- Платформы, заголовки и компоновка
- Владение памятью и общий/zero-copy процессы
- Устройство, контекст и флаги инициализации
- Запросы модели, тензоров и динамических форм
- Вход, выполнение, выход и динамические формы
- Тензоры, выделение памяти и синхронизация
- Матричное умножение и динамические формы
- Регистрация и атрибуты пользовательских операторов
- Коды состояния, тензоры, память и расширения
- Структуры матричного умножения
- Структуры операторов и миграция устаревших API
5. Справочник функций
Функции API
Функциональная классификация RKNN C API:
| Категория | Описание |
|---|---|
| 5.1. Устройство и контекст | Инициализация и уничтожение контекста, настройка ядер NPU. |
| 5.2. Запросы | Запрос атрибутов модели, версии SDK, памяти и других данных. |
| 5.3. Выполнение инференса | Настройка входов, инференс, получение выходов и динамические формы. |
| 5.4. Тензоры и память | Выделение, освобождение, синхронизация тензорной памяти и назначение пользовательской памяти. |
| 5.5. Матричное умножение | Создание контекста матричного умножения, память, параметры квантования и выполнение. |
| 5.6. Пользовательские операторы | Регистрация пользовательских операторов и получение их атрибутов. |
5.1. Устройство и контекст
Инициализация и уничтожение контекста, настройка ядер NPU.
rknn_init
Функция инициализации rknn_init создаёт объект rknn_context, загружает модель RKNN и выполняет заданные действия инициализации согласно флагам и структуре rknn_init_extend.
| API | rknn_init |
|---|---|
| Описание | Инициализирует контекст rknn. |
| Параметры | rknn_context *context: указатель на объект rknn_context. |
| Параметры | void *model: двоичные данные модели RKNN или путь к ней. При size>0 — двоичные данные; при size=0 — путь модели. |
| Параметры | uint32_t size: размер модели, переданной двоичными данными; 0, если model задаёт путь. |
| Параметры | uint32_t flag: флаг инициализации; для поведения по умолчанию задайте 0. |
| Параметры | rknn_init_extend: расширенная информация специальной инициализации. Источник называет её отключённой и требует NULL, но для совместного использования весов требует указатель другого rknn_context, связанного с другой моделью. Оба утверждения сохранены. |
| Возвращаемое значение | int: Код ошибки (см. коды состояния). |
Пример кода:
rknn_context ctx;
int ret = rknn_init(&ctx, model_data, model_data_size, 0, NULL);
Флаги инициализации описаны далее:
RKNN_FLAG_PRIOR_HIGH: Высокий приоритет контекста.
RKNN_FLAG_PRIOR_MEDIUM: Средний приоритет контекста.
RKNN_FLAG_PRIOR_LOW: Низкий приоритет контекста.
RKNN_FLAG_ASYNC_MASK: Асинхронный режим. rknn_outputs_get получает результат предыдущего кадра без длительной блокировки, повышая частоту в однопоточном режиме, но не возвращая текущий кадр. Для многопоточного режима включать его не требуется.
RKNN_FLAG_COLLECT_PERF_MASK: позволяет запрашивать время выполнения каждого слоя сети.
RKNN_FLAG_MEM_ALLOC_OUTSIDE: указывает, что память входов, выходов, весов и промежуточных тензоров модели полностью выделяет пользователь. Основные назначения:
1) Вся память выделяется пользователем, что упрощает планирование памяти всей системы.
2) Для повторного использования памяти, особенно при её дефиците на RV1106/RV1103/RV1106B/RV1103B/RK2118.
Предположим, модели A и B выполняются последовательно. Тогда память промежуточных тензоров обеих моделей можно использовать повторно. Пример кода:
rknn_context ctx_a, ctx_b;
rknn_init(&ctx_a, model_path_a, 0, RKNN_FLAG_MEM_ALLOC_OUTSIDE, NULL);
rknn_query(ctx_a, RKNN_QUERY_MEM_SIZE, &mem_size_a, sizeof(mem_size_a));
rknn_init(&ctx_b, model_path_b, 0, RKNN_FLAG_MEM_ALLOC_OUTSIDE, NULL);
rknn_query(ctx_b, RKNN_QUERY_MEM_SIZE, &mem_size_b, sizeof(mem_size_b));
max_internal_size = MAX(mem_size_a.total_internal_size, mem_size_b.total_internal_size);
internal_mem_max = rknn_create_mem(ctx_a, max_internal_size);
internal_mem_a = rknn_create_mem_from_fd(ctx_a, internal_mem_max->fd,
internal_mem_max->virt_addr, mem_size_a.total_internal_size, 0);
rknn_set_internal_mem(ctx_a, internal_mem_a);
internal_mem_b = rknn_create_mem_from_fd(ctx_b, internal_mem_max->fd,
internal_mem_max->virt_addr, mem_size_b.total_internal_size, 0);
rknn_set_internal_mem(ctx_b, internal_mem_b);
RKNN_FLAG_SHARE_WEIGHT_MEM: используется для совместного использования весов другой модели. Основное назначение — имитация входа переменной длины; начиная с RKNPU Runtime 1.5.0 эта функция заменена динамическими формами. Например, речевые модели имеют переменную длину входа, но NPU не поддерживает такой вход непосредственно, поэтому создают несколько моделей RKNN разных разрешений. Только одна модель содержит полные веса, остальные — без весов. При инициализации модели без весов этот флаг позволяет текущему контексту использовать веса полной модели. Для двух моделей разрешений A и B порядок следующий:
1) Создайте RKNN-Toolkit2 модель с разрешением A.
2) Создайте модель с разрешением B без весов: в rknn.config() задайте remove_weight=True. Это уменьшает размер модели B.
3) На плате обычным образом инициализируйте A.
4) Инициализируйте B с флагом RKNN_FLAG_SHARE_WEIGHT_MEM.
5) Остальные действия прежние. Пример кода платы:
rknn_context ctx_a, ctx_b;
rknn_init(&ctx_a, model_path_a, 0, 0, NULL);
rknn_init_extend extend;
extend.ctx = ctx_a;
rknn_init(&ctx_b, model_path_b, 0, RKNN_FLAG_SHARE_WEIGHT_MEM, &extend);
RKNN_FLAG_FENCE_IN_OUTSIDE: Передать fence fd извне.
RKNN_FLAG_FENCE_OUT_OUTSIDE: Получить внутренний fence fd.
RKNN_FLAG_COLLECT_MODEL_INFO_ONLY: инициализирует пустой контекст. В нём можно только вызывать rknn_query для получения общего объёма памяти весов и промежуточных тензоров; инференс невозможен.
RKNN_FLAG_INTERNAL_ALLOC_OUTSIDE: промежуточные тензоры модели выделяет пользователь. Обычно применяется для самостоятельного управления и повторного использования их памяти между несколькими моделями.
RKNN_FLAG_EXECUTE_FALLBACK_PRIOR_DEVICE_GPU: для всех слоёв, не поддерживаемых NPU, предпочтительно выполнение на GPU, но оно не гарантируется. Фактическое устройство исполнения зависит от поддержки оператора библиотекой Runtime.
RKNN_FLAG_ENABLE_SRAM: память промежуточных тензоров по возможности выделяется в SRAM.
RKNN_FLAG_SHARE_SRAM: текущий контекст пытается совместно использовать адресное пространство SRAM другого контекста. При инициализации текущего контекста обязательно должен быть включён RKNN_FLAG_ENABLE_SRAM.
RKNN_FLAG_DISABLE_PROC_HIGH_PRIORITY: текущий контекст использует стандартный приоритет процесса. Без этого флага nice процесса равен -19.
RKNN_FLAG_DISABLE_FLUSH_INPUT_MEM_CACHE: Runtime не сбрасывает кэш входного тензора; пользователь обязан обеспечить сброс до вызова rknn_run.
RKNN_FLAG_DISABLE_FLUSH_OUTPUT_MEM_CACHE: Runtime не очищает кэш выходного тензора автоматически. Прямой доступ пользователя к output_mem->virt_addr тогда может нарушить согласованность кэша. Перед использованием output_mem->virt_addr необходимо обновить кэш через rknn_mem_sync(ctx, mem, RKNN_MEMORY_SYNC_FROM_DEVICE). Флаг обычно нужен, когда выход NPU читает не CPU, а, например, GPU или RGA.
RKNN_FLAG_MODEL_BUFFER_ZERO_COPY: переданный rknn_init буфер модели выделен через rknn_create_mem или rknn_create_mem2. Runtime не создаёт дополнительную копию буфера, уменьшая потребление памяти. Пользователь должен сохранять память модели действительной до уничтожения контекста и освобождать её после этого. При инициализации поля real_model_offset, real_model_size, model_buffer_fd и model_buffer_flags параметра rknn_init_extend функции rknn_init задаются по rknn_tensor_mem, возвращённому rknn_create_mem2.
RKNN_MEM_FLAG_ALLOC_NO_CONTEXT: при выделении памяти через rknn_create_mem2 разрешает ctx=0 или NULL. Поэтому память драйвера NPU можно получить до инициализации какого-либо контекста. Возвращённую структуру памяти необходимо освободить через rknn_destroy_mem, передав любой контекст. Пример кода:
rknn_tensor_mem* model_mem = rknn_create_mem2(ctx, model_size, RKNN_MEM_FLAG_ALLOC_NO_CONTEXT);
memcpy(model_mem->virt_addr, model_data, model_size);
rknn_init_extend init_ext;
memset(&init_ext, 0, sizeof(rknn_init_extend));
init_ext.real_model_offset = 0;
init_ext.real_model_size = model_size;
init_ext.model_buffer_fd = model_mem->fd;
init_ext.model_buffer_flags = model_mem->flags;
int ret = rknn_init(&ctx, model_mem->virt_addr, model_size, RKNN_FLAG_MODEL_BUFFER_ZERO_COPY,
&init_ext);
// do rknn inference...
rknn_destroy_mem(ctx, model_mem);
rknn_destroy(ctx);
rknn_set_core_mask
Функция задаёт конкретные ядра NPU для выполнения. В описываемом состоянии поддерживаются только RK3588 и RK3576. На платформе с одноядерной NPU возвращается код ошибки.
| API | rknn_set_core_mask |
|---|---|
| Описание | Задаёт ядра NPU. |
| Параметры | rknn_context context: объект rknn_context. |
| Параметры | rknn_core_mask core_mask: выбор ядер NPU. RKNN_NPU_CORE_AUTO — автоматический выбор свободного ядра; RKNN_NPU_CORE_0 — NPU0; RKNN_NPU_CORE_1 — NPU1; RKNN_NPU_CORE_2 — NPU2; RKNN_NPU_CORE_0_1 — одновременно NPU0 и NPU1; RKNN_NPU_CORE_0_1_2 — одновременно NPU0, NPU1 и NPU2; RKNN_NPU_CORE_ALL — все ядра NPU данной платформы. |
| Возвращаемое значение | int: Код ошибки (см. коды состояния). |
rknn_context ctx;
rknn_core_mask core_mask = RKNN_NPU_CORE_0;
int ret = rknn_set_core_mask(ctx, core_mask);
В многоядерных режимах RKNN_NPU_CORE_0_1 и RKNN_NPU_CORE_0_1_2 лучше ускоряются Conv, DepthwiseConvolution, Add, Concat, Relu, Clip, Relu6, ThresholdedRelu, Prelu и LeakyRelu. Остальные операторы продолжают работу на Core0. Источник обещает поддержку Pool и ConvTranpose в будущих обновлениях; это обещание оригинала, не подтверждение текущей реализации.
rknn_set_batch_core_num
rknn_set_batch_core_num задаёт число ядер NPU для модели RKNN с несколькими batch, экспортированной при rknn_batch_size больше 1 в RKNN-Toolkit2. Поддерживаются только RK3588 и RK3576.
| API | rknn_set_batch_core_num |
|---|---|
| Описание | Задаёт число ядер NPU для выполнения модели RKNN с несколькими batch. |
| Параметры | rknn_context context: объект rknn_context. |
| Параметры | int core_num: число используемых ядер. |
| Возвращаемое значение | int: Код ошибки (см. коды состояния). |
Пример кода:
rknn_context ctx;
int ret = rknn_set_batch_core_num(ctx, 2);
rknn_dup_context
rknn_dup_context создаёт новый контекст, ссылающийся на ту же модель. Он полезен для повторного использования весов при многопоточном выполнении одной модели. Недоступно на RV1106/RV1103/RV1106B/RV1103B/RK2118.
| API | rknn_dup_context |
|---|---|
| Описание | Создаёт новый контекст той же модели для повторного использования весов. |
| Параметры | rknn_context *context_in: указатель объекта rknn_context. По тексту источника после вызова входной контекст будет инициализирован. |
| Параметры | rknn_context *context_out: указатель выходного объекта rknn_context, в котором возвращаются сведения о новом объекте. |
| Возвращаемое значение | int: Код ошибки (см. коды состояния). |
Пример кода:
rknn_context ctx_in;
rknn_context ctx_out;
int ret = rknn_dup_context(&ctx_in, &ctx_out);
rknn_destroy
Функция освобождает rknn_context и связанные ресурсы.
| API | rknn_destroy |
|---|---|
| Описание | Уничтожает rknn_context и связанные ресурсы. |
| Параметры | rknn_context context: уничтожаемый объект rknn_context. |
| Возвращаемое значение | int: Код ошибки (см. коды состояния). |
Пример кода:
rknn_context ctx;
int ret = rknn_destroy(ctx);
Источник и редакционные примечания
Технические главы разделены по назначению. Код, идентификаторы и параметры сохранены. Китайская версия следует китайскому оригиналу; английская, русская и немецкая — английскому. В главы без иллюстраций вымышленные изображения не добавлены.
Оговорки оригинала: номера глав и примерные журналы сохранены; ранние версии 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.
