Платформа и источник
Статья подготовлена по PDF производителя RKNN V2.5.0 и относится только к перечисленным в нём чипам и интерфейсам. Для платы ArmSoM сначала проверьте SoC, драйвер NPU, Toolkit/Runtime, SDK/BSP и версию ядра. Проверки на оборудовании ArmSoM не проводились; примеры и измерения оригинала не являются тестами ArmSoM.
Навигация по серии
- Платформы, заголовки и компоновка
- Владение памятью и общий/zero-copy процессы
- Устройство, контекст и флаги инициализации
- Запросы модели, тензоров и динамических форм
- Вход, выполнение, выход и динамические формы
- Тензоры, выделение памяти и синхронизация
- Матричное умножение и динамические формы
- Регистрация и атрибуты пользовательских операторов
- Коды состояния, тензоры, память и расширения
- Структуры матричного умножения
- Структуры операторов и миграция устаревших API
5.2. Запросы
Запрос атрибутов модели, версии SDK, памяти и других данных.
rknn_query
rknn_query запрашивает сведения о модели и SDK: входы и выходы модели, время выполнения отдельных слоёв, общее время инференса, версию SDK, потребление памяти, пользовательские строки и другую информацию.
| API | rknn_query |
|---|---|
| Описание | Запрашивает сведения о модели и SDK. |
| Параметры | rknn_context context: объект rknn_contex (написание источника). |
| Параметры | rknn_query_cmd: команда запроса. |
| Параметры | void* info: объект структуры для результата запроса. |
| Параметры | uint32_t size: размер объекта структуры info. |
| Возвращаемое значение | int: Код ошибки (см. коды состояния). |
В описываемой версии SDK поддерживает следующие команды запроса:
| Команда запроса | Структура результата | Назначение |
|---|---|---|
| RKNN_QUERY_IN_OUT_NUM | rknn_input_output_num | Число входных и выходных тензоров. |
| RKNN_QUERY_INPUT_ATTR | rknn_tensor_attr | Атрибуты входного тензора. |
| RKNN_QUERY_OUTPUT_ATTR | rknn_tensor_attr | Атрибуты выходного тензора. |
| RKNN_QUERY_PERF_DETAIL | rknn_perf_detail | Время каждого слоя сети; работает только при RKNN_FLAG_COLLECT_PERF_MASK, заданном через rknn_init. |
| RKNN_QUERY_PERF_RUN | rknn_perf_run | Общее время инференса в микросекундах без настройки входов и выходов. |
| RKNN_QUERY_SDK_VERSION | rknn_sdk_version | Версия SDK. |
| RKNN_QUERY_MEM_SIZE | rknn_mem_size | Память весов и внутренних тензоров сети. |
| RKNN_QUERY_CUSTOM_STRING | rknn_custom_string | Пользовательские строки модели RKNN. |
| Команда запроса | Структура результата | Назначение |
|---|---|---|
| RKNN_QUERY_NATIVE_INPUT_ATTR | rknn_tensor_attr | При zero-copy запрашивает нативный входной тензор, непосредственно читаемый NPU. |
| RKNN_QUERY_NATIVE_OUTPUT_ATTR | rknn_tensor_attr | При zero-copy запрашивает нативный выходной тензор непосредственно от NPU. |
| RKNN_QUERY_NATIVE_NC1HWC2_INPUT_ATTR | rknn_tensor_attr | При zero-copy запрашивает нативный входной тензор, непосредственно читаемый NPU. Совпадает с RKNN_QUERY_NATIVE_INPUT_ATTR. |
| RKNN_QUERY_NATIVE_NC1HWC2_OUTPUT_ATTR | rknn_tensor_attr | При zero-copy запрашивает нативный выходной тензор; оригинал называет его входным тензором, читаемым NPU. Совпадает с RKNN_QUERY_NATIVE_OUTPUT_ATTR. |
| RKNN_QUERY_NATIVE_NHWC_INPUT_ATTR | rknn_tensor_attr | При zero-copy запрашивает нативный входной тензор, читаемый NPU. В оригинале указано совпадение с RKNN_QUERY_NATIVE_INPUT_ATTR. |
| RKNN_QUERY_NATIVE_NHWC_OUTPUT_ATTR | rknn_tensor_attr | При zero-copy запрашивает нативный выход NHWC; оригинал называет его входными атрибутами, читаемыми NPU. |
| RKNN_QUERY_DEVICE_MEM_INFO | rknn_tensor_mem | Запрос свойств памяти буфера модели. |
| RKNN_QUERY_INPUT_DYNAMIC_RANGE | rknn_input_range | Для динамических моделей запрашивает число форм, их список, компоновку и соответствующие имена входов. |
| RKNN_QUERY_CURRENT_INPUT_ATTR | rknn_tensor_attr | Запрос входных атрибутов текущего инференса динамической модели. |
| RKNN_QUERY_CURRENT_OUTPUT_ATTR | rknn_tensor_attr | Запрос выходных атрибутов текущего инференса динамической модели. |
| RKNN_QUERY_CURRENT_NATIVE_INPUT_ATTR | rknn_tensor_attr | Запрос нативных входных атрибутов NPU для текущего инференса динамической модели. |
| RKNN_QUERY_CURRENT_NATIVE_OUTPUT_ATTR | rknn_tensor_attr | Запрос нативных выходных атрибутов NPU для текущего инференса динамической модели. |
Далее каждая команда рассмотрена подробно.
1. Запрос версии SDK
RKNN_QUERY_SDK_VERSION запрашивает версию RKNN SDK. Сначала необходимо создать объект структуры rknn_sdk_version.
Пример кода:
rknn_sdk_version version;
ret = rknn_query(ctx, RKNN_QUERY_SDK_VERSION, &version,
sizeof(rknn_sdk_version));
printf("sdk api version: %s\n", version.api_version);
printf("driver version: %s\n", version.drv_version);
2. Запрос числа входных и выходных тензоров
RKNN_QUERY_IN_OUT_NUM запрашивает число входных и выходных тензоров модели. Сначала создайте объект структуры rknn_input_output_num.
Пример кода:
rknn_input_output_num io_num;
ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));
printf("model input num: %d, output num: %d\n", io_num.n_input, io_num.n_output);
3. Запрос атрибутов входного тензора (обычный API)
RKNN_QUERY_INPUT_ATTR запрашивает атрибуты входного тензора. Сначала создайте объект rknn_tensor_attr. Примечание: на RV1106/RV1103/RV1106B/RV1103B/RK2118 запрос возвращает исходный нативный входной тензор.
Пример кода:
rknn_tensor_attr input_attrs[io_num.n_input];
memset(input_attrs, 0, sizeof(input_attrs));
for (int i = 0; i < io_num.n_input; i++) {
input_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &(input_attrs[i]), sizeof(rknn_tensor_attr));
}
4. Запрос атрибутов выходного тензора (обычный API)
RKNN_QUERY_OUTPUT_ATTR запрашивает атрибуты выходного тензора модели. Сначала создайте объект структуры rknn_tensor_attr.
Пример кода:
rknn_tensor_attr output_attrs[io_num.n_output];
memset(output_attrs, 0, sizeof(output_attrs));
for (int i = 0; i < io_num.n_output; i++) {
output_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), sizeof(rknn_tensor_attr));
}
5. Запрос времени инференса каждого слоя модели
После rknn_run команда RKNN_QUERY_PERF_DETAIL запрашивает время инференса по слоям в микросекундах. Для этого параметр flag при rknn_init должен включать RKNN_FLAG_COLLECT_PERF_MASK.
Пример кода:
rknn_context ctx;
int ret = rknn_init(&ctx, model_data, model_data_size, RKNN_FLAG_COLLECT_PERF_MASK, NULL);
...
ret = rknn_run(ctx,NULL);
...
rknn_perf_detail perf_detail;
ret = rknn_query(ctx, RKNN_QUERY_PERF_DETAIL, &perf_detail, sizeof(perf_detail));
6. Запрос общего времени инференса модели
После rknn_run команда RKNN_QUERY_PERF_RUN запрашивает время инференса модели в микросекундах, без времени настройки входов и выходов.
Пример кода:
rknn_context ctx;
int ret = rknn_init(&ctx, model_data, model_data_size, 0, NULL);
...
ret = rknn_run(ctx,NULL);
...
rknn_perf_run perf_run;
ret = rknn_query(ctx, RKNN_QUERY_PERF_RUN, &perf_run, sizeof(perf_run));
7. Запрос выделенной памяти модели
После rknn_init, если пользователь самостоятельно выделяет память сети, RKNN_QUERY_MEM_SIZE позволяет запросить память весов и внутреннюю память сети, исключая входы и выходы. Для этого параметр flag при rknn_init должен включать RKNN_FLAG_MEM_ALLOC_OUTSIDE.
Пример кода:
rknn_context ctx;
int ret = rknn_init(&ctx, model_data, model_data_size, RKNN_FLAG_MEM_ALLOC_OUTSIDE , NULL);
rknn_mem_size mem_size;
ret = rknn_query(ctx, RKNN_QUERY_MEM_SIZE, &mem_size, sizeof(mem_size));
8. Запрос пользовательской строки модели
После rknn_init команда RKNN_QUERY_CUSTOM_STRING получает пользовательскую строку, добавленную при создании модели RKNN. Например, при преобразовании модели строка “RGB” может указывать, что вход — трёхканальное изображение RGB, а не BGR. Во время выполнения по полученной строке “RGB” данные преобразуются в изображение RGB.
Пример кода:
rknn_context ctx;
int ret = rknn_init(&ctx, model_data, model_data_size, 0, NULL);
rknn_custom_string custom_string;
ret = rknn_query(ctx, RKNN_QUERY_CUSTOM_STRING, &custom_string, sizeof(custom_string));
9. Запрос нативных атрибутов входного тензора (API без копирования)
RKNN_QUERY_NATIVE_INPUT_ATTR, эквивалентная RKNN_QUERY_NATIVE_NC1HWC2_INPUT_ATTR, запрашивает нативные атрибуты входного тензора модели. Сначала создайте объект структуры rknn_tensor_attr.
Пример кода:
rknn_tensor_attr input_attrs[io_num.n_input];
memset(input_attrs, 0, sizeof(input_attrs));
for (int i = 0; i < io_num.n_input; i++) {
input_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_NATIVE_INPUT_ATTR, &(input_attrs[i]),
sizeof(rknn_tensor_attr));
}
9. Запрос нативных атрибутов выхода (zero-copy API)
RKNN_QUERY_NATIVE_OUTPUT_ATTR, эквивалентная RKNN_QUERY_NATIVE_NC1HWC2_OUTPUT_ATTR, запрашивает нативные атрибуты выходного тензора модели. Сначала создайте объект структуры rknn_tensor_attr.
Пример кода:
rknn_tensor_attr output_attrs[io_num.n_output];
memset(output_attrs, 0, sizeof(output_attrs));
for (int i = 0; i < io_num.n_output; i++) {
output_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_NATIVE_OUTPUT_ATTR,
&(output_attrs[i]), sizeof(rknn_tensor_attr));
}
10. Запрос нативных атрибутов входа (zero-copy API)
RKNN_QUERY_NATIVE_NHWC_INPUT_ATTR запрашивает атрибуты NHWC входного тензора модели. Сначала создайте объект структуры rknn_tensor_attr.
Пример кода:
rknn_tensor_attr input_attrs[io_num.n_input];
memset(input_attrs, 0, sizeof(input_attrs));
for (int i = 0; i < io_num.n_input; i++) {
input_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_NATIVE_NHWC_INPUT_ATTR,
&(input_attrs[i]), sizeof(rknn_tensor_attr));
}
11. Запрос нативных атрибутов выходного тензора (заголовок оригинала; следующий текст относится к входу, API без копирования)
RKNN_QUERY_NATIVE_NHWC_OUTPUT_ATTR запрашивает атрибуты NHWC выходного тензора модели. Сначала создайте объект структуры rknn_tensor_attr.
Пример кода:
rknn_tensor_attr output_attrs[io_num.n_output];
memset(output_attrs, 0, sizeof(output_attrs));
for (int i = 0; i < io_num.n_output; i++) {
output_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_NATIVE_NHWC_OUTPUT_ATTR,
&(output_attrs[i]), sizeof(rknn_tensor_attr));
}
12. Запрос памяти буфера модели (примечание: RV1106/RV1103/RV1106B/RV1103B/RK2118 поддерживают этот интерфейс)
После rknn_init команда RKNN_QUERY_DEVICE_MEM_INFO запрашивает атрибуты буфера модели, созданного внутри Runtime, включая fd и физический адрес.
rknn_tensor_mem mem_info;
memset(&mem_info, 0, sizeof(mem_info));
ret = rknn_query(ctx, RKNN_QUERY_DEVICE_MEM_INFO, &mem_info, sizeof(mem_info));
13. Запрос поддерживаемых моделью RKNN динамических форм входа
Примечание: RV1106/RV1103/RV1106B/RV1103B/RK2118 не поддерживают этот интерфейс.
После rknn_init передайте RKNN_QUERY_INPUT_DYNAMIC_RANGE для получения сведений о поддерживаемых формах входа: их числа, списка, размещения данных, имён и других данных. Сначала создайте объект структуры rknn_input_range.
Пример кода:
rknn_input_range dyn_range[io_num.n_input];
memset(dyn_range, 0, io_num.n_input * sizeof(rknn_input_range));
for (uint32_t i = 0; i < io_num.n_input; i++) {
dyn_range[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_INPUT_DYNAMIC_RANGE, &dyn_range[i],
sizeof(rknn_input_range));
}
14. Запрос текущей динамической формы входа модели RKNN
После rknn_set_input_shapes передайте RKNN_QUERY_CURRENT_INPUT_ATTR для запроса текущих атрибутов входа. Сначала создайте rknn_tensor_attr. RV1106/RV1103/RV1103B/RV1106B/RK2118 не поддерживают эту команду.
Пример кода:
rknn_tensor_attr cur_input_attrs[io_num.n_input];
memset(cur_input_attrs, 0, io_num.n_input * sizeof(rknn_tensor_attr));
for (uint32_t i = 0; i < io_num.n_input; i++) {
cur_input_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_CURRENT_INPUT_ATTR, &(cur_input_attrs[i]),
sizeof(rknn_tensor_attr));
}
15. Запрос текущей динамической формы выхода модели RKNN
После rknn_set_input_shapes передайте RKNN_QUERY_CURRENT_OUTPUT_ATTR для запроса текущих атрибутов выхода. Сначала создайте rknn_tensor_attr. RV1106/RV1103/RV1103B/RV1106B/RK2118 не поддерживают эту команду.
Пример кода:
rknn_tensor_attr cur_output_attrs[io_num.n_output];
memset(cur_output_attrs, 0, io_num.n_output * sizeof(rknn_tensor_attr));
for (uint32_t i = 0; i < io_num.n_output; i++) {
cur_output_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_CURRENT_OUTPUT_ATTR, &(cur_output_attrs[i]),
sizeof(rknn_tensor_attr));
}
16. Запрос текущей динамической формы нативного входа модели RKNN
После rknn_set_input_shapes передайте RKNN_QUERY_CURRENT_NATIVE_INPUT_ATTR для запроса текущих атрибутов нативного входа. Сначала создайте rknn_tensor_attr. RV1106/RV1103/RV1103B/RV1106B/RK2118 не поддерживают эту команду.
Пример кода:
rknn_tensor_attr cur_input_attrs[io_num.n_input];
memset(cur_input_attrs, 0, io_num.n_input * sizeof(rknn_tensor_attr));
for (uint32_t i = 0; i < io_num.n_input; i++) {
cur_input_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_CURRENT_NATIVE_INPUT_ATTR,
&(cur_input_attrs[i]), sizeof(rknn_tensor_attr));
}
17. Запрос текущей динамической формы нативного выхода модели RKNN
После rknn_set_input_shapes передайте RKNN_QUERY_CURRENT_OUTPUT_ATTR для запроса текущих атрибутов нативного выхода. Сначала создайте rknn_tensor_attr. RV1106/RV1103/RV1103B/RV1106B/RK2118 не поддерживают эту команду.
Пример кода:
rknn_tensor_attr cur_output_attrs[io_num.n_output];
memset(cur_output_attrs, 0, io_num.n_output * sizeof(rknn_tensor_attr));
for (uint32_t i = 0; i < io_num.n_output; i++) {
cur_output_attrs[i].index = i;
ret = rknn_query(ctx, RKNN_QUERY_CURRENT_NATIVE_OUTPUT_ATTR, &(cur_output_attrs[i]),
sizeof(rknn_tensor_attr));
}
Источник и редакционные примечания
Технические главы разделены по назначению. Код, идентификаторы и параметры сохранены. Китайская версия следует китайскому оригиналу; английская, русская и немецкая — английскому. В главы без иллюстраций вымышленные изображения не добавлены.
Оговорки оригинала: номера глав и примерные журналы сохранены; ранние версии 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.
