资讯动态

将训练好的模型转换并部署在NPU上的详细步骤(工具链功能)

发布时间:2026/8/28 8:09:19 来源:尧图企业网站定制
最近瑞芯微以及地瓜RDK上做NPU/BPU的神经网络部署所以在这里总结一下瑞芯微模型转化链接https://github.com/airockchip/rknn-toolkit2名词解释模型转换整体流程PyTorch / ONNX / TensorFlow 转成 硬件适配的格式.pt / .onnx转化为.rknn瑞芯微/.bin地瓜.rknn瑞芯微/.bin地瓜均为二进制文件解析计算图映射支持的算子保存权重和网络结构适配目标芯片的运行方式计算图Computational Graph节点Nodes代表运算操作如卷积、加法、矩阵乘法。边Edges代表数据张量Tensor的流动方向。图优化对模型的计算图做重写和精简让推理更高效。常见优化包括删除无用节点融合多个算子比如×3×2 - ×6折叠常量调整数据流顺序减少内存拷贝transpose 消除比如Conv BatchNorm ReLU 优化成一个更高效的组合执行方式。算子适配/算子映射把模型里的每一种运算映射到目标硬件或推理引擎支持的实现上。深度学习算子 NPU 适配总结表算子名称所属类别核心功能NPU 适配友好度主要适配问题 / 原因常见优化/处理方法Conv计算类图像/特征提取的核心操作进行滑窗加权求和。 原生友好无。所有NPU都为卷积设计了专门的加速单元。作为融合优化的核心常与BN、激活函数融合。BatchNorm (BN)计算类推理时对特征图进行标准化线性变换。 原生友好无。但在部署时为了性能需要被处理掉。算子融合在图优化阶段将其参数“折叠”进相邻的Conv层权重中从而被消除。ReLU激活函数引入非线性f(x) max(0, x)。 原生友好无。硬件指令集几乎都原生支持。算子融合被硬件直接吸收进Conv等算子的激活选项中零开销。SiLU (Swish)激活函数YOLOv5/v8主力激活f(x) x * sigmoid(x)。 良好较老的NPU可能无原生指令支持。融合/替换新NPU支持融合老NPU可能拆解为sigmoid mul也可考虑替换为ReLU。MaxPool池化/采样类下采样取池化窗口内的最大值。 原生友好无。NPU通常有专门指令支持。关注kernel_size、stride、padding等参数是否符合硬件限制。AveragePool池化/采样类下采样取池化窗口内的平均值。 原生友好无。NPU通常有专门指令支持。关注kernel_size、stride、padding等参数是否符合硬件限制。GlobalAveragePool池化/采样类对整个特征图取全局平均值常用于分类头。 原生友好无。通常可高效实现。常作为YOLO分类头或辅助头的输出层可直接被NPU支持。Add元素级运算类逐元素相加常用于残差连接Residual Connection。 原生友好无。这是最基础的逐元素操作。常与Conv融合形成Conv Add的优化模式。Mul元素级运算类逐元素相乘常用于注意力机制中的加权。 原生友好无。NPU支持良好。注意Mul的第二个输入是常量还是动态张量广播规则是否支持。Concat张量操作类沿指定维度拼接多个张量常用于特征融合如FPN。 良好拼接的维度信息必须在编译时确定静态。图优化在可能的情况下与前后算子融合消除。Reshape张量操作类改变张量形状但总元素数不变。 良好本身开销极小。问题在于其输入形状可能来自动态算子。图优化消除编译器常可优化掉不产生实际指令。Squeeze张量操作类移除张量中所有尺寸为1的维度。 良好无。编译时可确定。常被编译器自动优化或与Reshape合并。Unsqueeze张量操作类在指定位置插入一个尺寸为1的维度。 良好无。编译时可确定。常被编译器自动优化或与Reshape合并。Cast张量操作类改变张量的数据类型如float32 → int64。 良好需确认目标硬件是否支持该类型转换。通常在图优化阶段保留注意类型转换是否有精度损失。Flatten张量操作类将张量展平为一维。 良好无。编译时可确定。常被编译器优化或与Gemm等算子融合。Split张量操作类沿指定维度将一个张量分割成多个子张量。 良好分割的维度和数量必须静态确定。常与Concat配对出现有时可被优化消除。ConvWithBnAct融合优化类部署工具生成的融合算子并非原始模型中的独立算子。 优化产物无。这是所有NPU都追求的最终目标形态。由图优化器自动生成代表了最佳的适配结果。Resize池化/采样类上采样或下采样特征图改变空间尺寸如双线性插值、最近邻插值。 良好主要适配问题在于mode和scales是否被目标NPU支持。scales须为常量。首选modenearest硬件友好。若必须用linear确认NPU是否支持不支持时可用TransposedConv替代或写Custom Op。Softmax激活/归一化类将输入向量映射为概率分布所有元素值在(0,1)之间且和为1。 中等需确认NPU对axis沿哪个维度做Softmax参数的支持范围。某些NPU要求axis必须是最后一维。尽量确保axis-1最后一维或硬件支持的其他静态轴性能敏感时可考虑用LogSoftmax替代如果后续接NLLLoss。Transpose张量操作类交换张量维度如 NCHW - NHWC。 中等导致内存重排增加耗时且会阻断相邻算子的融合。消除/吸收通过修改相邻算子的数据布局参数来吸收或在图分析中被消除。Slice张量操作类从张量中切取一部分子集如starts和ends指定范围。 中等starts、ends、steps等参数必须为常量静态动态切片极难处理。尽量确保切片参数在编译时固定。若不可避免考虑用StridedSlice替代或写Custom Op。Gather选择/过滤类根据提供的索引从张量中取出对应数据。 中等本身功能简单。问题在于索引indices的来源。若索引来自固定常量则无问题若来自TopK等动态算子则需整体替换为Custom Op。Upsample池化/采样类注与Resize功能重叠ONNX中已统一为Resize上采样特征图。 中等与Resize相同关注mode和scales。同Resize。MatMul矩阵运算类执行矩阵乘法在注意力机制、全连接层中常见。 中等权重形状需对齐需确认NPU对批次矩阵乘BMM的支持。确保输入维度是静态的考虑是否有Conv 1x1替代的可能。ReduceSum规约运算类沿指定维度求和降低张量维度。 中等需确认axes沿哪个轴和keepdims是否保留维度的支持情况。确保axes参数是常量。ReduceMean规约运算类沿指定维度求平均降低张量维度。 中等与ReduceSum类似关注axes和keepdims。确保axes参数是常量。Mish激活函数YOLOv4/v7使用的激活函数x * tanh(ln(1exp(x)))。 困难表达式复杂老NPU无原生支持。拆解为多个基础算子后计算量大且精度可能下降。算子替换建议直接替换为SiLU并重新微调模型是性价比最高的方案。LayerNorm归一化类对特征图沿特征维度进行标准化在Transformer结构中常见。 困难无法像BN那样被融合消除需要NPU原生支持对精度敏感。确认NPU是否支持若性能不佳考虑混合精度或写Custom Op。InstanceNorm归一化类对每个样本的每个通道独立做标准化在风格迁移等任务中常见。 困难与LayerNorm类似无法简单融合需要硬件原生支持。确认NPU是否支持若支持不好考虑修改网络结构替代。Shape张量操作类获取张量各维度的大小运行时动态值。 困难输出为动态值会引入数据依赖导致NPU编译器无法进行静态内存分配。消除尽量在模型导出时固定输入尺寸避免使用依赖Shape的动态逻辑。TopK选择/过滤类在指定维度上选取数值最大或最小的前K个值及索引。 困难涉及排序或部分排序逻辑NPU的并行矩阵单元不擅长处理串行逻辑。替换/插件常与Gather配合整体替换为Custom Op如NMS插件。Exp元素级运算类逐元素计算指数e的x次方。 困难指数运算对NPU硬件支持要求较高可能精度不足或速度慢。确认NPU是否支持若精度不达标考虑替换或使用查找表LUT近似。Log元素级运算类逐元素计算自然对数。 困难与Exp类似对硬件支持要求高。确认NPU是否支持若精度不达标考虑替换或使用查找表LUT近似。Pow元素级运算类逐元素计算幂运算x的y次方。 困难指数部分须为常量否则NPU难以处理。确保指数是常量initializer若指数是动态张量基本无法适配。NonZero选择/过滤类找出张量中所有非零元素的索引。 极难非零元素数量完全动态输出形状不确定变长NPU基本无法处理。绝对避免这是NPU的“杀手算子”任何部署场景下都应极力避免。Unique选择/过滤类对张量进行去重返回唯一值。 极难去重后元素数量动态输出形状不确定与NonZero问题性质相同。绝对避免几乎无法在NPU上直接部署需在模型设计阶段规避。适配时可能会遇到硬件支持某个算子但参数有限制某些算子需要拆分成多个更基础的操作某些算子只能放到 CPU 上跑不能放到 NPU 上需要针对芯片特性做特殊实现custom op 自定义算子处理见官方文档https://github.com/airockchip/rknn-toolkit2/tree/master/rknn-toolkit2/examples/functions/custom_op/gen_custom_onnx_from_pytorch/register_pytorch_opINT8 量化把原本用 FP32float point浮点数 计算的模型参数和激活值压缩成 INT88 位整数 表示。目的更省内存推理更快更适合 NPU / 边缘设备减少模型大小加速深度学习推理的速度需要一批代表性数据做校准计算浮点到整数的映射关系尽量减少精度损失scale缩放因子和 zero_point零点估计方法Direct Min-Max直接最大最小值法Percentile / Histogram百分位 / 直方图法KL 散度相对熵模型转换整体流程以瑞芯微为例https://github.com/airockchip/rknn-toolkit2训练好的模型网络结构、权重参数、输入输出定义 校准数据↓模型解析模型文件 → 计算图权重文件 → 参数张量↓图优化↓算子映射↓量化↓生成 .rknn 文件模型部署整体流程设备端加载↓输入预处理↓rknn runtime 执行↓输出张量↓后处理—工作重点↓最终结果瑞芯微官方演示流程https://github.com/airockchip/rknn-toolkit2/tree/master/rknpu2/examples地瓜BPU模型部署Model Zoohttps://github.com/D-Robotics/rdk_model_zoo/blob/rdk_x5/README_cn.md一些训练好的模型示例原始模型PyTorch/ONNX→ 定点量化转换 → 推理运行 → 结果解析 →c/c规范samples/vision/yolov5/runtime/cpp配置结构体每个模型必须定义一个独立的配置结构体用于存放模型初始化和运行时参数模型类构造函数 - 模型对象创建职责创建模型对象本身不执行任何重资源操作、不加载模型、不分配 Tensor 内存为后续显式调用 init() 做准备init - 模型资源初始化职责加载模型如通过 Horizon DNN API查询模型元信息分配输入 / 输出 tensor 所需的内存返回值返回错误码0 表示成功非 0 表示失败推理相关函数pre_process – 预处理职责将用户输入数据转换为 runtime 所需格式对不支持的 image_format 应及时报错而非静默失败模型的input tensor必须以引用方式传递并写入便于后续多线程/并行扩展infer – 前向推理执行职责创建推理任务提交任务到 BPU 调度器等待任务完成释放任务句柄可通过参数配置底层硬件的调度参数如sched_param参数设置缺省值输入输出tensor需以形参的形式传入便于后续多线程/并行扩展返回值当推理出现底层错误时返回错误码0为无错误非0为异常post_process – 后处理职责将 raw 输出 tensor 转换为业务语义结果模型输出tensor需以形参的形式传入便于后续多线程/并行扩展算法工具链https://developer.d-robotics.cc/api/v1/fileData/x5_doc-v126cn/index.html地平线BPU架构的计算平台使用的是int8的计算精度训练后量化PTQPost-Training Quantization 量化感知训练QATQuantization-Aware Training训练后量化PTQ使用一批校准数据对训练好的模型进行校准将训练过的FP32模型直接转换为定点计算的模型过程中无需对原始模型进行任何训练只需要对几个超参数进行调整就可以完成量化过程 且过程简单快速无需训练。量化感知训练QAT是将训练过的模型量化后又再进行重训练。由于定点数值无法用于反向梯度计算实际操作过程是在某些OP前插入伪量化节点fake quantization nodes 用于在训练时获取流经该OP的数据的截断值便于在部署量化模型时对节点进行量化时进行使用。我们需要在训练中通过不断优化精度来获取最佳的量化参数。为什么定点数值无法用于反向梯度计算

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价