拜读维拉科技关于机器人相关信息的综合整理,涵盖企业排名、产品类型及资本市场动态:一、中国十大机器人公司(综合类)优必选UBTECH)聚焦人工智能与人形机器人研发,产品覆盖教育、娱乐及服务领域,技术处于行业前沿。基于RK3576开发板的AI算法开发流程机器人中科院旗下企业,工业机器人全品类覆盖,是国产智能工厂解决方案的核心供应商。埃斯顿自动化国产工业机器人龙头,实现控制器、伺服系统、本体一体化自研,加速替代外资品牌。遨博机器人(AUBO)协作机器人领域领先者,主打轻量化设计,适用于3C装配、教育等柔性场景。埃夫特智能国产工业机器人上市第一股,与意大利COMAU深度合作,产品稳定性突出。二、细分领域机器人产品智能陪伴机器人Gowild公子小白:情感社交机器人,主打家庭陪伴功能。CANBOT爱乐优:专注0-12岁儿童心智发育型亲子机器人。仿真人机器人目前市场以服务型机器人为主,如家庭保姆机器人(售价10万-16万区间),但高仿真人形机器人仍处研发阶段。水下机器人工业级产品多用于深海探测、管道巡检,消费级产品尚未普及。基于RK3576开发板的AI算法开发流程资本市场动态机器人概念股龙头双林股份:特斯拉Optimus关节模组核心供应商,订单排至2026年。中大力德:国产减速器龙头,谐波减速器市占率30%。金力永磁:稀土永磁材料供应商,受益于机器人电机需求增长。行业趋势2025年人形机器人赛道融资活跃,但面临商业化落地争议,头部企业加速并购整合。四、其他相关机器人视频资源:可通过专业科技平台或企业官网(如优必选、新松)获取技术演示与应用案例。价格区间:服务型机器人(如保姆机器人)普遍在10万-16万元,男性机器人13万售价属高端定制产品。
1. 概述
开发流程由以下流程组成:
2. 需求分析
算法的功能常常可以用一个短词概括,如人脸识别、司机行为检测、商场顾客行为分析等系统,但是却需要依靠多个子算法的有序运作才能达成。其原因在于子算法的结构各有不同,这些结构的差异化优化了各个子算法在其功能上的实现效果。
以下我们列出组成例子:
例子a: 人脸识别算法 = 人脸检测(检测模型)+ 矫正人脸姿态模型(关键点定位模型)+ 人脸比对模型(相似度比对模型)
例子b: 司机行为检测算法 = 人脸识别算法(具体组成如上例)+ 抽烟玩等危险动作识别(检测模型) + 疲劳驾驶检测(关键点定位模型)+ 车道线偏移检测(检测模型)
例子c: 商场分析 = 人脸识别算法(具体组成如首例)+ 人体跟踪算法(检测模型 + 相似度比对模型)
只有在确定了具体需求所需要的步骤后,我们才能有的放矢的采集数据,优化模型,训练出合乎我们需求的模型。
3. 准备数据
即使准备数据在大多数人看来是繁琐重复的工作,这期间仍有许多细节需要注意的。
数据样本需要良好的多样性。样本多样性是保证算法泛化能力的基础,例如想要识别农产品的功能中,假如我们只是搜集红苹果的数据,那么训练出来的网络就很难将绿色的苹果准确识别出。同时还需要加入充足的负样本,例如我们只是单纯地把农产品的图片数据喂给神经网络,那么我们就很难期望训练出来的神经网络可以有效区分真苹果还有塑料苹果。为了增强算法的可靠性,我们就需要充分的考虑到实际应用场景中会出现什么特殊情况,并将该种情况的数据添加进我们的训练数据里面。
数据样本是否可被压缩。单个样本数据的大小往往决定了网络模型的运行效率,在保证效果的情况下,应当尽量压缩图片的大小来提高运行效率,如112x112的图片,在相同环境下的处理速度将比224x224图片的快4倍左右。但是有些场景却是需要完整的图片来保证图片信息不会丢失,如山火检测一般需要很高的查全率,过度的压缩都会导致查全率下降导致算法效果不佳。
数据需要合适正确的标注与预处理。数据标注在一定程度上决定了训练效果能达到的高度,过多的错误标记将带来一个无效的训练结果。而数据的预处理,是指先对数据做出一定的操作,使其更容易被机器读懂,例如农产品在画面中的位置,如果是以像素点为单位,如农产品的点在左起第200个像素点,这种处理方式虽然直观准确,但是会因为不同像素点之间的差距过大,导致训练困难,这个时候就需要将距离归一化,如中心点在图中左起40%宽的位置上。而的预处理更为多样,不同的分词方式、傅里叶变换都会影响训练结果。
数据的准备不一定得在一开始就做到毫无遗漏。模型训练完成后,如果有一定的效果但还存在部分缺陷,就可以考虑添加或优化训练样本数据,对已有模型进行复训练修正。即使是后期的优化,增添合适的照片往往是最有效的效果。所以对数据的考量优化应该贯穿整个流程,不能在只是在开头阶段才关注数据样本的问题。
4. 选取模型
通常来讲,对于同一个功能,存在着不同的模型,它们在精度、计算速率上各有长处。模型来发现主要来源于学术研究、公司之间的公开比赛等,所以在研发过程中,就需从业人员持续地关注有关ai新模型的文章;同时对旧模型的积累分析也是十分重要的,这里我们在 下表 中列出目前在各个功能上较优的模型结构以供参考。
5. 训练模型
对于有AI开发经验的研发人员,可以用自己熟悉的常见框架训练即可,如、pytorch、caffe等主流框架,我们的开发套件可以将其转为EASY EAI Orin-nano的专用模型。
6. 模型转换
研发nsorflow、pytorch、caffe等自主的模型后,需先将模型转换为rknn模型。同时一般需要对模型进行量化与预编译,以达到运行效率的提升。
6.1 模型转换环境搭建
6.1.1 概述
模型转换环境搭建流程如下所示:
6.1.2 下载模型转换工具
为了保证模型转换工具顺利运行,请下载网盘里“06.AI算法开发/01.rknn-toolkit2模型转换工具/rknn-toolkit2-v2.3.0/docker/rknn-toolkit2-v2.3.0-cp38-docker.tar.gz”。
网盘下载链接:https://pan.baidu.com/s/1J86chdq1klKFnpCO1RCcEA?pwd=1234提取码:1234
6.1.3 把工具移到ubuntu20.04
把下载完成的docker镜像移到我司的虚拟机ubuntu20.04的rknn-toolkit目录,如下图所示:
6.1.4 运行模型转换工具环境
6.1.4.1 打开终端
在该目录打开终端
6.1.4.2 加载docker镜像
执行以下指令加载模型转换工具docker镜像:
6.1.4.3 进入镜像bash环境
执行以下指令进入镜像bash环境:
现象如下图所示:
输入“”加载python相关库,尝试加载rknn库,如下图环境测试成功:
至此,模型转换工具环境搭建完成。
6.2 模型转换示例
6.2.1 模型转换为RKNN
EASY EAI Monster支持.rknn后缀的模型的评估及运行,对于常见的tensorflow、tensroflow lite、caffe、darknet、onnx和Pytorch模型都可以通过我们提供的 toolkit 工具将其转换至 rknn 模型,而对于其他框架训练出来的模型,也可以先将其转至 onnx 模型再转换为 rknn 模型。
模型转换操作流程入下图所示:
6.2.2 模型转换Demo下载
下载百度网链接:https://pan.baidu.com/s/1l5vcbS-w4dGetSdKQdhAuA?pwd=1234 提取码:1234。把yolov5_model_convert.tar.bz2和quant_dataset.zip解压到虚拟机,如下图所示:
6.2.3 进入模型转换工具docker环境
执行以下指令把工作区域映射进docker镜像,其中/home/developer/rknn-toolkit2/model_convert为工作区域,/test为映射到docker镜像,/dev/bus/usb:/dev/bus/usb为映射usb到docker镜像:
执行成功如下图所示:
6.2.4 模型转换操作说明
6.2.4.1 模型转换Demo目录结构
模型转换测试Demo由yolov5_model_convert和quant_dataset组成。yolov5_model_convert存放软件脚本,quant_dataset存放量化模型所需的数据。如下图所示:
yolov5_model_convert文件夹存放以下内容,如下图所示:
6.2.4.2 生成量化图片列表
在docker环境切换到模型转换工作目录:
如下图所示:
执行gen_list.py生成量化图片列表:
命令行现象如下图所示:
生成“量化图片列表”如下文件夹所示:
6.2.4.3 onnx模型转换为rknn模型
rknn_convert.py脚本默认进行int8量化操作,脚本代码清单如下所示:
把onnx模型best.onnx放到yolov5_model_convert目录,并执行rknn_convert.py脚本进行模型转换:
生成模型如下图所示,此模型可以在rknn环境和EASY EAI Orin-nano环境运行:
6.3 模型转换API说明
6.3.1 API详细说明
6.3.1.1 RKNN初始化及释放
在使用RKNN-Toolkit2的所有API时,都需要先调用RKNN()方法初始化RKNN对象,不再使用该对象时通过调用该对象的release()方法进行释放。
初始化RKNN对象时,可以设置verbose和verbose_file参数,以打印详细的日志信息。其中verbose参数指定是否要打印详细日志信息;如果设置了verbose_file参数,且verbose参数值为True,日志信息还将写到该参数指定的文件中。
举例如下:
6.3.1.2 模型配置
在构建RKNN模型之前,需要先对模型进行通道均值、量化图片RGB2BGR转换、量化类型等的配置,这些操作可以通过config接口进行配置。
举例如下:
6.3.1.3 模型加载
RKNN-Toolkit2目前支持Caffe、TensorFlow、TensorFlow Lite、ONNX、DarkNet、PyTorch等模型的加载转换,这些模型在加载时需调用对应的接口,以下为这些接口的详细说明。
(1)Caffe模型加载接口
举例如下:
(2)TensorFlow模型加载接口
举例如下:
(3)TensorFlow Lite模型加载接口
举例如下:
(4)ONNX模型加载
举例如下:
(5)DarkNet模型加载接口
举例如下:
(6)PyTorch模型加载接口
举例如下:
6.3.1.4 构建RKNN模型
举例如下:
6.3.1.5 导出RKNN模型
通过本工具构建的RKNN模型通过该接口可以导出存储为RKNN模型文件,用于模型部署。
举例如下:
6.3.1.6 加载RKNN模型
举例如下:
6.3.1.7 初始化运行时环境
在模型推理或性能评估之前,必须先初始化运行时环境,明确模型的运行平台(具体的目标硬件平台或软件模拟器)。
举例如下:
6.3.1.8 模型推理
在进行模型推理前,必须先构建或加载一个RKNN模型。
举例如下:
对于分类模型,如mobilenet_v1,代码如下(完整代码参考example/tflite/mobilent_v1):
输出的TOP5结果如下:
6.3.1.9 评估模型性能
举例如下:
6.3.1.10 获取内存使用情况
举例如下:
如examples/caffe/mobilenet_v2,它在RK3588上运行时内存占用情况如下:
6.3.1.11 查询SDK版本
举例如下:
返回的SDK信息类似如下:
6.3.1.12 混合量化
(1)hybrid_quantization_step1
使用混合量化功能时,第一阶段调用的主要接口是hybrid_quantization_step1,用于生成临时模型文件
(.model)、数据文件(.data)和量化配置文件
(.quantization.cfg)。接口详情如下:
举例如下:
(2)hybrid_quantization_step2
用于使用混合量化功能时生成RKNN模型,接口详情如下:
举例如下:
6.3.1.13 量化精度分析
该接口的功能是进行浮点、量化推理并产生每层的数据,并进行量化精度分析。
举例如下:
6.3.1.14 获取设备列表
举例如下:
返回的设备列表信息如下:
注:使用多设备时,需要保证它们的连接模式都是一致的,否则会引起冲突,导致设备连接失败。
6.3.1.15 导出加密模型
该接口的功能是将普通的RKNN模型进行加密,得到加密后的模型。
举例如下:
6.3.1.16 注册自定义算子
该接口的功能是注册一个自定义算子。
举例如下:
6.3.1.17 生成部署示例
举例如下:
7. 模型部署
模型转换为rknn模型后,需再参考NPU API说明文档,编写应用工程。经过编译后传输至EASY EAI Orin-nano平台上实现部署。
7.1 模型部署示例
7.1.1 模型部署示例介绍
本小节展示yolov5模型的在EASY EAI Orin-nano的部署过程,该模型仅经过简单训练供示例使用,不保证模型精度。
7.1.2 准备工作
7.1.2.1 硬件准备
EASY EAI Orin-nano开发板,microUSB数据线,该模型仅经过简单训练供示例使用,不保证模型精度。
7.1.3 源码下载以及例程编译
下载yolov5 C Demo示例文件。
百度网盘链接: (https://pan.baidu.com/s/1Ah8x8Rzo-iofyZPDHfzo2w?pwd=1234 提取码:1234)。
下载程序包移至ubuntu环境后,执行以下指令解压:
下载解压后如下图所示:
通过adb接口连接EASY-EAI-Orin-nano,,连接方式如下图所示:
接下来需要通过adb把源码传输到板卡上,先切换目录然后执行以下指令:
登录到板子切换到例程目录执行编译操作:
7.1.4 在开发板执行yolov5 demo
编译成功后切换到可执行程序目录,如下所示:
运行例程命令如下所示:
执行结果如下图所示,算法执行时间为58ms:
退出板卡环境,取回测试图片:
测试结果如下图所示:
至此,yolov5目标检测例程已成功在板卡运行。
7.2 模型部署API说明
7.2.1 基础数据结构定义
7.2.1.1 rknn_sdk_version
结构体rknn_sdk_version用来表示RKNN SDK的版本信息,结构体的定义如下:
7.2.1.2 rknn_input_output_num
结构体rknn_input_output_num表示输入输出tensor个数,其结构体成员变量如下表所示:
7.2.1.3 rknn_input_range
结构体rknn_input_range表示一个输入的支持形状列表信息。它包含了输入的、支持的形状个数、数据布局格式、名称以及形状列表,具体的结构体的定义如下表所示:
7.2.1.4 rknn_tensor_attr
结构体rknn_tensor_attr表示模型的tensor的属性,结构体的定义如下表所示:
7.2.1.5 rknn_perf_detail
结构体rknn_perf_detail表示模型的性能详情,结构体的定义如下表所示(RV1106/RV1106B/RV1103/RV1103B/RK2118暂不支持):
7.2.1.6 rknn_perf_run
结构体rknn_perf_run表示模型的总体性能,结构体的定义如下表所示(RV1106/RV1106B/RV1103/RV1103B/RK2118暂不支持):
7.2.1.7 rknn_mem_size
结构体rknn_mem_size表示初始化模型时的内存分配情况,结构体的定义如下表所示:
7.2.1.8 rknn_tensor_mem
结构体rknn_tensor_mem表示tensor的内存信息。结构体的定义如下表所示:
7.2.1.9 rknn_input
结构体rknn_input表示模型的一个数据输入,用来作为参数传入给rknn_inputs_set函数。结构体的定义如下表所示:
7.2.1.10 rknn_output
结构体rknn_output表示模型的一个数据输出,用来作为参数传入给rknn_outputs_get函数,在函数执行后,结构体对象将会被赋值。结构体的定义如下表所示:
7.2.1.11 rknn_init_extend
结构体rknn_init_extend表示初始化模型时的扩展信息。结构体的定义如下表所示(RV1106/RV1106B/RV1103/RV1103B/RK2118暂不支持):
7.2.1.12 rknn_run_extend
结构体rknn_run_extend表示模型推理时的扩展信息,目前暂不支持使用。结构体的定义如下表所示:
7.2.1.13 rknn_output_extend
结构体rknn_output_extend表示获取输出的扩展信息,目前暂不支持使用。结构体的定义如下表所示:
7.2.1.14 rknn_custom_string
结构体rknn_custom_string表示转换RKNN模型时,用户设置的自定义字符串,结构体的定义如下表所示:
7.2.2 基础API说明
7.2.2.1 rknn_init
rknn_init初始化函数功能为创建rknn_context对象、加载RKNN模型以及根据flag和rknn_init_extend结构体执行特定的初始化行为。
示例代码如下:
各个初始化标志说明如下:
RKNN_FLAG_COLLECT_PERF_MASK:用于运行时查询网络各层时间;RKNN_FLAG_MEM_ALLOC_OUTSIDE:用于表示模型输入、输出、权重、中间tensor内存全部由用户分配,它主要有两方面的作用:
所有内存均是用户自行分配,便于对整个系统内存进行统筹安排。
用于内存复用,特别是针对RV1103/RV1106/RV1103B/RV1106B/RK2118这种内存极为紧张的情况。假设有模型A、B 两个模型,这两个模型在设计上串行运行的,那么这两个模型的中间tensor的内存就可以复用。示例代码如下:
RKNN_FLAG_SHARE_WEIGHT_MEM:用于共享另一个模型的weight权重。主要用于模拟不定长度模型输入(RKNPU运行时库版本大于等于1.5.0后该功能被动态shape功能替代)。比如对于某些语音模型,输入长度不定,但由于NPU无法支持不定长输入,因此需要生成几个不同分辨率的RKNN模,其中,只有一个RKNN模型的保留完整权重,其他RKNN模型不带权重。在初始化不带权重RKNN模型时,使用该标志能让当前上下文共享完整RKNN模型的权重。假设需要分辨率A、B两个模型,则使用流程如下:
使用RKNN-Toolkit2生成分辨率A的模型。
使用RKNN-Toolkit2生成不带权重的分辨率B的模型,rknn.config()中,remove_weight要设置成True,主要目的是减少模型B的大小。
在板子上,正常初始化模型A。
通过RKNN_FLAG_SHARE_WEIGHT_MEM的flags初始化模型B。
其他按照原来的方式使用。板端参考代码如下:
RKNN_FLAG_COLLECT_MODEL_INFO_ONLY:用于初始化一个空上下文,仅用于调用rknn_query接口查询模型weight内存总大小和中间tensor总大小,无法进行推理;
RKNN_FLAG_INTERNAL_ALLOC_OUTSIDE: 表示模型中间tensor由用户分配,常用于用户自行管理和复用多个模型之间的中间tensor内存;
RKNN_FLAG_EXECUTE_FALLBACK_PRIOR_DEVICE_GPU: 表示所有NPU不支持的层优先选择运行在GPU上,但并不保证运行在GPU上,实际运行的后端设备取决于运行时对该算子的支持情况;
RKNN_FLAG_ENABLE_SRAM: 表示中间tensor内存尽可能分配在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内部不主动刷新输入tensor缓存,用户必须确保输入tensor在调用 rknn_run 之前已刷新缓存。主要用于当输入数据没有CPU访问时,减少runtime内部刷cache的耗时。
RKNN_FLAG_DISABLE_FLUSH_OUTPUT_MEM_CACHE: 设置该标志后,runtime不主动清除输出tensor缓存。此时用户不能直接访问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接口的传入的模型buffer是rknn_create_mem或者rknn_create_mem2接口分配的内存,runtime内部不需要拷贝一次模型buffer,减少运行时的内存占用,但需要用户保证上下文销毁前模型内存有效,并且在销毁上下文后释放该内存。初始化上下文时,rknn_init接口的rknn_init_extend参数,其成员real_model_offset、real_model_size、model_buffer_fd和model_buffer_flags根据rknn_create_mem2接口返回的rknn_tensor_mem设置。
RKNN_MEM_FLAG_ALLOC_NO_CONTEXT:在使用rknn_create_mem2接口分配内存时,设置该标志后,允许ctx参数是0或者NULL。从而用户在未初始化任何一个上下文之前就能获取NPU驱动分配的内存,返回的内存结构体需使用rknn_destroy_mem接口释放,释放的接口可使用任意一个上下文作为参数。
示例代码如下:
7.2.2.2 rknn_set_core_mask
rknn_set_core_mask函数指定工作的NPU核心,该函数仅支持RK3576/RK3588平台,在单核NPU架构的平台上设置会返回错误。
示例代码如下:
在RKNN_NPU_CORE_0_1及RKNN_NPU_CORE_0_1_2模式下,目前以下OP能获得更好的加速:Conv、DepthwiseConvolution、Add、Concat、Relu、Clip、Relu6、ThresholdedRelu、PRelu、LeakyRelu,其余类型OP将fallback至单核Core0中运行,部分类型OP(如Pool类、ConvTranspose等)将在后续更新版本中支持。
7.2.2.3 rknn_set_batch_core_num
rknn_set_batch_core_num函数指定多batch RKNN模型(RKNN-Toolkit2转换时设置rknn_batch_size大于1导出的模型)的NPU核心数量,该函数仅支持RK3588/RK3576平台。
示例代码如下:
7.2.2.4 rknn_dup_context
rknn_dup_context生成一个指向同一个模型的新context,可用于多线程执行相同模型时的权重复用。RV1106/RV1103/RV1106B/RV1103B/RK2118平台暂不支持 。
示例代码如下:
7.2.2.5 rknn_destroy
rknn_destroy函数将释放传入的rknn_context及其相关资源。
示例代码如下:
7.2.2.6 rknn_query
rknn_query函数能够查询获取到模型输入输出信息、逐层运行时间、模型推理的总时间、SDK版本、内存占用信息、用户自定义字符串等信息。
当前SDK支持的查询命令如下表所示:
各个指令用法的详细说明,如下:
1.查询SDK版本
传入RKNN_QUERY_SDK_VERSION命令可以查询RKNN SDK的版本信息。其中需要先创建rknn_sdk_version结构体对象。
示例代码如下:
2. 查询输入输出tensor个数
在rknn_init接口调用完毕后,传入RKNN_QUERY_IN_OUT_NUM命令可以查询模型输入输出tensor的个数。其中需要先创建rknn_input_output_num结构体对象。
示例代码如下:
3. 查询输入tensor属性(用于通用API接口)
在rknn_init接口调用完毕后,传入RKNN_QUERY_INPUT_ATTR命令可以查询模型输入tensor的属性。其中需要先创建rknn_tensor_attr结构体对象 (注意:RV1106/RV1103/RV1106B/RV1103B/RK2118 查询出来的tensor是原始输入native的tensor) 。
示例代码如下:
4. 查询输出tensor属性(用于通用API接口)
在rknn_init接口调用完毕后,传入RKNN_QUERY_OUTPUT_ATTR命令可以查询模型输出tensor的属性。其中需要先创建rknn_tensor_attr结构体对象。
示例代码如下:
5. 查询模型推理的逐层耗时
在rknn_run接口调用完毕后,rknn_query接口传入RKNN_QUERY_PERF_DETAIL可以查询网络推理时逐层的耗时,单位是微秒。使用该命令的前提是,在rknn_init接口的flag参数需要包含RKNN_FLAG_COLLECT_PERF_MASK标志。
示例代码如下:
6. 查询模型推理的总耗时
在rknn_run接口调用完毕后,rknn_query接口传入RKNN_QUERY_PERF_RUN可以查询上模型推理(不包含设置输入/输出)的耗时,单位是微秒。
示例代码如下:
7. 查询模型的内存占用情况
在rknn_init接口调用完毕后,当用户需要自行分配网络的内存时,rknn_query接口传入RKNN_QUERY_MEM_SIZE可以查询模型的权重、网络中间tensor的内存(不包括输入和输出)、推演模型所用的所有DMA内存的以及SRAM内存(如果sram没开或者没有此项功能则为0)的占用情况。使用该命令的前提是在rknn_init接口的flag参数需要包含RKNN_FLAG_MEM_ALLOC_OUTSIDE标志。
示例代码如下:
8. 查询模型中用户自定义字符串
在rknn_init接口调用完毕后,当用户需要查询生成RKNN模型时加入的自定义字符串,rknn_query接口传入RKNN_QUERY_CUSTOM_STRING可以获取该字符串。例如,在转换RKNN模型时,用户填入“RGB”的自定义字符来标识RKNN模型输入是RGB格式三通道图像而不是BGR格式三通道图像,在运行时则根据查询到的“RGB”信息将数据转换成RGB图像。
示例代码如下:
9. 查询原生输入tensor属性(用于零拷贝API接口)
在rknn_init接口调用完毕后,传入RKNN_QUERY_NATIVE_INPUT_ATTR命令(同RKNN_QUERY_NATIVE_NC1HWC2_INPUT_ATTR)可以查询模型原生输入tensor的属性。其中需要先创建rknn_tensor_attr结构体对象。
示例代码如下:
10. 查询原生输出tensor属性(用于零拷贝API接口)
在rknn_init接口调用完毕后,传入RKNN_QUERY_NATIVE_OUTPUT_ATTR命令(同RKNN_QUERY_NATIVE_NC1HWC2_OUTPUT_ATTR)可以查询模型原生输出tensor的属性。其中需要先创建rknn_tensor_attr结构体对象。
示例代码如下:
11. 查询NHWC格式原生输入tensor属性(用于零拷贝API接口)
在rknn_init接口调用完毕后,传入RKNN_QUERY_NATIVE_NHWC_INPUT_ATTR命令可以查询模型NHWC格式输入tensor的属性。其中需要先创建rknn_tensor_attr结构体对象。
示例代码如下:
12. 查询NHWC格式原生输出tensor属性(用于零拷贝API接口)
在rknn_init接口调用完毕后,传入RKNN_QUERY_NATIVE_NHWC_OUTPUT_ATTR命令可以查询模型NHWC格式输出tensor的属性。其中需要先创建rknn_tensor_attr结构体对象。
示例代码如下:
13. 查询模型buffer的内存属性(注:仅RV1106/RV1103/RV1106B/RV1103B/RK2118支持该查询)
在rknn_init接口调用完毕后,传入RKNN_QUERY_DEVICE_MEM_INFO命令可以查询Runtime内部开辟的模型buffer的包括fd、物理地址等属性。
14. 查询RKNN模型支持的动态输入形状信息(注:RV1106/RV1103/RV1106B/RV1103B/RK2118不支持该接口)
在rknn_init接口调用完毕后,传入RKNN_QUERY_INPUT_DYNAMIC_RANGE命令可以查询模型支持的输入形状信息,包含输入形状个数 、输入形状列表、输入形状对应的布局和名称等信息。其中需要先创建rknn_input_range结构体对象。
示例代码如下:
15. 查询RKNN模型当前使用的输入动态形状
在rknn_set_input_shapes接口调用完毕后,传入RKNN_QUERY_CURRENT_INPUT_ATTR命令可以查询模型当前使用的输入属性信息。其中需要先创建rknn_tensor_attr结构体(注:RV1106/RV1103/RV1106B/RV1103B/RK2118不支持该命令)。
示例代码如下:
16. 查询RKNN模型当前使用的输出动态形状
在rknn_set_input_shapes接口调用完毕后,传入RKNN_QUERY_CURRENT_OUTPUT_ATTR命令可以查询模型当前使用的输出属性信息。其中需要先创建rknn_tensor_attr结构体(注:RV1106/RV1103/RV1106B/RV1103B/RK2118不支持该命令)。
示例代码如下:
17. 查询RKNN模型当前使用的原生输入动态形状
在rknn_set_input_shapes接口调用完毕后,传入RKNN_QUERY_CURRENT_NATIVE_INPUT_ATTR命令可以查询模型当前使用的原生输入属性信息。其中需要先创建rknn_tensor_attr结构体(注:RV1106/RV1103/RV1106B/RV1103B/RK2118不支持该命令)。
示例代码如下:
18. 查询RKNN模型当前使用的原生输出动态形状
在rknn_set_input_shapes接口调用完毕后,传入RKNN_QUERY_CURRENT_NATIVE_OUTPUT_ATTR命令可以查询模型当前使用的原生输出属性信息。其中需要先创建rknn_tensor_attr结构体(注:RV1106/RV1103/RV1106B/RV1103B/RK2118不支持该命令)。
示例代码如下:
7.2.2.7 rknn_inputs_set
通过rknn_inputs_set函数可以设置模型的输入数据。该函数能够支持多个输入,其中每个输入是rknn_input结构体对象,在传入之前用户需要设置该对象,注:RV1106/RV1103/RV1106B/RV1103B/RK2118不支持该接口。
示例代码如下:
7.2.2.8 rknn_run
rknn_run函数将执行一次模型推理,调用之前需要先通过rknn_inputs_set函数或者零拷贝的接口设置输入数据。
示例代码如下:
7.2.2.9 rknn_outputs_get
rknn_outputs_get函数可以获取模型推理的输出数据。该函数能够一次获取多个输出数据。其中每个输出是rknn_output结构体对象,在函数调用之前需要依次创建并设置每个rknn_output对象。
对于输出数据的buffer存放可以采用两种方式:一种是用户自行申请和释放,此时rknn_output对象的is_prealloc需要设置为1,并且将buf指针指向用户申请的buffer;另一种是由rknn来进行分配,此时rknn_output对象的is_prealloc设置为0即可,函数执行之后buf将指向输出数据。注:RV1106/RV1103/RV1106B/RV1103B/RK2118不支持该接口
示例代码如下:
7.2.2.10 rknn_outputs_release
rknn_outputs_release函数将释放rknn_outputs_get函数得到的输出的相关资源。
示例代码如下:
7.2.2.11 rknn_create_mem_from_phys
当用户需要自己分配内存让NPU使用时,通过rknn_create_mem_from_phys函数可以创建一个rknn_tensor_mem结构体并得到它的指针,该函数通过传入物理地址、虚拟地址以及大小,外部内存相关的信息会赋值给rknn_tensor_mem结构体。
示例代码如下:
7.2.2.12 rknn_create_mem_from_fd
当用户要自己分配内存让NPU使用时,rknn_create_mem_from_fd函数可以创建一个rknn_tensor_mem结构体并得到它的指针,该函数通过传入文件描述符fd、偏移、虚拟地址以及大小,外部内存相关的信息会赋值给rknn_tensor_mem结构体。
示例代码如下:
7.2.2.13 rknn_create_mem
当用户要NPU内部分配内存时,rknn_create_mem函数可以分配用户指定的内存大小,并返回一个rknn_tensor_mem结构体。
示例代码如下:
7.2.2.14 rknn_create_mem2
当用户要NPU内部分配内存时,rknn_create_mem2函数可以分配用户指定的内存大小及内存类型,并返回一个rknn_tensor_mem结构体。
rknn_create_mem2与rknn_create_mem的主要区别是rknn_create_mem2带了一个alloc_flags,可以指定分配的内存是否cacheable的,而rknn_create_mem不能指定,默认就是cacheable。
示例代码如下:
7.2.2.15 rknn_destroy_mem
rknn_destroy_mem函数会销毁rknn_tensor_mem结构体,用户分配的内存需要自行释放。
示例代码如下:
7.2.2.16 rknn_set_weight_mem
如果用户自己为网络权重分配内存,初始化相应的rknn_tensor_mem结构体后,在调用rknn_run前,通过rknn_set_weight_mem函数可以让NPU使用该内存。
示例代码如下:
7.2.2.17 rknn_set_internal_mem
如果用户自己为网络中间tensor分配内存,初始化相应的rknn_tensor_mem结构体后,在调用rknn_run前,通过rknn_set_internal_mem函数可以让NPU使用该内存。
示例代码如下:
7.2.2.18 rknn_set_io_mem
如果用户自己为网络输入/输出tensor分配内存,初始化相应的rknn_tensor_mem结构体后,在调用rknn_run前,通过rknn_set_io_mem函数可以让NPU使用该内存。
示例代码如下:
7.2.2.19 rknn_set_input_shape(deprecated)
该接口已经废弃,请使用rknn_set_input_shapes接口绑定输入形状。当前版本不可用,如要继续使用该接口,请使用1.5.0版本SDK并参考1.5.0版本的使用指南文档。
7.2.2.20 rknn_set_input_shapes
对于动态形状输入RKNN模型,在推理前必须指定当前使用的输入形状。该接口传入输入个数和rknn_tensor_attr数组,包含了每个输入形状和对应的数据布局信息,将每个rknn_tensor_attr结构体对象的索引、名称、形状(dims)和内存布局信息(fmt)必须填充,rknn_tensor_attr结构体其他成员无需设置。在使用该接口前,可先通过rknn_query函数查询RKNN模型支持的输入形状数量和动态形状列表,要求输入数据的形状在模型支持的输入形状列表中。初次运行或每次切换新的输入形状,需要调用该接口设置新的形状,否则,不需要重复调用该接口。
示例代码如下:
7.2.2.21 rknn_mem_sync
rknn_create_mem函数创建的内存默认是带cacheable标志的,对于带cacheable标志创建的内存,在被CPU和NPU同时使用时,由于cache行为会导致数据一致性问题。该接口用于同步一块带cacheable标志创建的内存,保证CPU和NPU访问这块内存的数据是一致的。
示例代码如下:
7.2.3 矩阵乘法数据结构定义
7.2.3.1 rknn_matmul_info
rknn_matmul_info表示用于执行矩阵乘法的规格信息,它包含了矩阵乘法的规模、输入和输出矩阵的数据类型和内存排布。结构体的定义如下表所示:
7.2.3.2 rknn_matmul_tensor_attr
rknn_matmul_tensor_attr表示每个矩阵tensor的属性,它包含了矩阵的名字、形状、大小和数据类型。结构体的定义如下表所示:
7.2.3.3 rknn_matmul_io_attr
rknn_matmul_io_attr表示矩阵所有输入和输出tensor的属性,它包含了矩阵A、B和C的属性。结构体的定义如下表所示:
7.2.3.4 rknn_quant_params
rknn_quant_params表示矩阵的量化参数,包括name以及scale和zero_point数组的指针和长度,name用来标识矩阵的名称,它可以从初始化矩阵上下文时得到的rknn_matmul_io_attr结构体中获取。结构体定义如下表所示:
7.2.3.5 rknn_matmul_shape
rknn_matmul_shape表示某个特定shape的矩阵乘法的M、K和N,在初始化动态shape的矩阵乘法上下文时,需要提供shape的数量,并使用rknn_matmul_shape结构体数组表示所有的输入的shape。结构体定义如下表所示:
7.2.4 矩阵乘法API说明
7.2.4.1 rknn_matmul_create
该函数的功能是根据传入的矩阵乘法规格等信息,完成矩阵乘法上下文的初始化,并返回输入和输出tensor的形状、大小和数据类型等信息。
示例代码如下:
7.2.4.2 rknn_matmul_set_io_mem
该函数用于设置矩阵乘法运算的输入/输出内存。在调用该函数前,先使用rknn_create_mem接口创建的rknn_tensor_mem结构体指针,接着将其与rknn_matmul_create函数返回的矩阵A、B或C的rknn_matmul_tensor_attr结构体指针传入该函数,把输入和输出内存设置到矩阵乘法上下文中。在调用该函数前,要根据rknn_matmul_info中配置的内存排布准备好矩阵A和矩阵B的数据。
示例代码如下:
7.2.4.3 rknn_matmul_set_core_mask
该函数用于设置矩阵乘法运算时可用的NPU核心(仅支持RK3588和RK3576平台)。在调用该函数前,需要先通过rknn_matmul_create函数初始化矩阵乘法上下文。可通过该函数设置的掩码值,指定需要使用的核心,以提高矩阵乘法运算的性能和效率。
示例代码如下:
7.2.4.4 rknn_matmul_set_quant_params
rknn_matmul_set_quant_params用于设置每个矩阵的量化参数,支持Per-Channel量化、Per-Layer量化和PerGroup量化方式的量化参数设置。当使用Per-Group量化时,rknn_quant_params中的scale和zp数组的长度等于N*K/group_size。当使用Per-Channel量化时,rknn_quant_params中的scale和zp数组的长度等于N。当使用Per-Layer量化时,rknn_quant_params中的scale和zp数组的长度为1。在rknn_matmul_run之前调用此接口设置所有矩阵的量化参数。如果不调用此接口,则默认量化方式为Per-Layer量化,scale=1.0,zero_point=0。
示例代码如下:
7.2.4.5 rknn_matmul_get_quant_params
rknn_matmul_get_quant_params用于rknn_matmul_type类型等于RKNN_INT8_MM_INT8_TO_INT32并且Per-Channel量化方式时,获取矩阵B所有通道scale归一化后的scale值,获取的scale值和A的原始scale值相乘可以得到C的scale值。可以用于在矩阵C没有真实scale时,近似计算得到C的scale。
示例代码如下:
7.2.4.6 rknn_matmul_create_dyn_shape(deprecated)
该接口已废弃,改用rknn_matmul_create_dynamic_shape接口。
7.2.4.7 rknn_matmul_create_dynamic_shape
rknn_matmul_create_dynamic_shape用于创建动态shape矩阵乘法上下文,该接口需要传入rknn_matmul_info结构体、shape数量以及对应的shape数组,shape数组会记录多个M、K和N值。在初始化成功后,会得到
rknn_matmul_io_attr的数组,数组中包含了所有的输入输出矩阵的shape、大小和数据类型等信息。目前支持设置多个不同的M,K和N。
7.2.4.8 rknn_matmul_set_dynamic_shape
rknn_matmul_set_dynamic_shape用于指定矩阵乘法使用的某一个shape。在创建动态shape的矩阵乘法上下文后,选取其中一个rknn_matmul_shape结构体作为输入参数,调用此接口设置运算使用的shape。
示例代码如下:
7.2.4.9 rknn_B_normal_layout_to_native_layout
rknn_B_normal_layout_to_native_layout用于将矩阵B的原始形状排列的数据(KxN)转换为高性能数据排列方式的数据。
示例代码如下:
7.2.4.10 rknn_matmul_run
该函数用于运行矩阵乘法运算,并将结果保存在输出矩阵C中。在调用该函数前,输入矩阵A和B需要先准备好数据,并通过rknn_matmul_set_io_mem函数设置到输入缓冲区。输出矩阵C需要先通过rknn_matmul_set_io_mem函数设置到输出缓冲区,而输出矩阵的tensor属性则通过rknn_matmul_create函数获取。
示例代码如下:
7.2.4.11 rknn_matmul_destroy
该函数用于销毁矩阵乘法运算上下文,释放相关资源。在使用完rknn_matmul_create函数创建的矩阵乘法上下文指针后,需要调用该函数进行销毁。
示例代码如下:
7.2.5 自定义算子数据结构定义
7.2.5.1 rknn_gpu_op_context
rknn_gpu_op_context表示指定GPU运行的自定义算子的上下文信息。结构体的定义如下表所示:
7.2.5.2 rknn_custom_op_context
rknn_custom_op_context表示自定义算子的上下文信息。结构体的定义如下表所示:
7.2.5.3 rknn_custom_op_tensor
rknn_custom_op_tensor表示自定义算子的输入/输出的tensor信息。结构体的定义如下表所示:
7.2.5.4 rknn_custom_op_attr
rknn_custom_op_attr表示自定义算子的参数或属性信息。结构体的定义如下表所示:
7.2.5.5 rknn_custom_op
rknn_custom_op表示自定义算子的注册信息。结构体的定义如下表所示:
7.2.6 自定义算子API说明
7.2.6.1 rknn_register_custom_ops
在初始化上下文成功后,该函数用于在上下文中注册若干个自定义算子的信息,包括自定义算子类型、运行后端类型、OpenCL内核信息以及回调函数指针。注册成功后,在推理阶段,rknn_run接口会调用开发者实现的回调函数。
示例代码如下:
7.2.6.2 rknn_custom_op_get_op_attr
该函数用于在自定义算子的回调函数中获取自定义算子的参数信息,例如Softmax算子的axis参数。它传入自定义算子参数的字段名称和一个rknn_custom_op_attr结构体指针,调用该接口后,参数值会存储rknn_custom_op_attr结构体中的data成员中,开发者根据返回的结构体内dtype成员将该指针强制转换成中特定数据类型的数组首地址,再按照元素数量读取出完整参数值。
示例代码如下:
7.2.7.RKNN返回值错误码
RKNN API函数的返回值错误码定义如下表所示:
审核编辑 黄宇
全部评论
留言在赶来的路上...
发表评论