netrans/docs/cookbook.md

14 KiB
Raw Permalink Blame History

Netrans Cookbook - 实用指南

本文档提供 Netrans 的速查表、配置说明、场景示例和故障排查。


目录

  1. 快速开始
  2. 速查表
  3. 数据集格式
  4. 导入格式兼容性
  5. 配置字段说明
  6. 场景示例
  7. 故障排查

快速开始

安装指南

# 克隆仓库并创建 Python 3.10 环境后,在源码根目录执行
make install
source ~/.bashrc

请使用项目提供的 Makefile 完成安装;在源码根目录执行 make install 即可安装 Netrans 及所需组件。环境创建和日常更新步骤见本项目的介绍与安装页(仓库中为 README.md)。

基础转换流程

# 1. 加载模型
netrans load ./model --mean 0 0 0 --std 255

# 2. 量化
netrans quantize ./model asymu8 --algorithm 1 --iterations 1

# 3. 导出
netrans export ./model asymu8 --platform pnna

Python API 完整流程

from netrans import Netrans

model = Netrans()
model.load('./model', mean=[0, 0, 0], std=255)
model.quantize('asymu8')
model.export('asymu8', platform='pnna', preprocess=True, postprocess=True)

速查表

量化类型

类型 激活 权重 说明
asymu8 uint8 uint8 非对称8位
symi8 int8 int8 对称8位
symi16 int16 int16 对称16位
dfpi16 int16 int16 动态定点16位
fp16 float16 float16 半精度浮点

注意事项

  • FP16: 支持将预处理和后处理嵌入推理计算图
  • symi16: 不支持将预处理嵌入推理节点,导出时需设置 preprocess=False,或改用 dfpi16

量化算法

算法 说明 适用场景
0 normal 直接统计 min/max 快速测试
1 KL KL散度推荐 平衡精度和速度
2 moving_average 移动平均 动态范围大的数据
3 auto 自动选择 最高精度,最慢

预处理参数

自动广播

mean/std 参数支持自动广播,无需手动填写所有通道值:

# 显式指定每个通道
model.load('./model', mean=[128, 128, 128], std=[255, 255, 255])

# 使用自动广播
model.load('./model', mean=128, std=255)           # 单值自动广播到所有通道
model.load('./model', mean=[128], std=[255])       # 单元素列表也自动广播
model.load('./model', mean=[128, 128, 128], std=255)  # std 单值广播

广播规则

  • 单值(如 mean=128)→ 自动广播到所有通道
  • 单元素列表(如 mean=[128])→ 自动广播到所有通道
  • 多值列表(如 mean=[128, 128, 128])→ 原样使用,长度必须匹配通道数

常见模型的 mean/std 配置:

模型 mean std 说明
YOLOv5/v8 0[0, 0, 0] 255 归一化到 [0,1]
ResNet/ImageNet [123.675, 116.28, 103.53] [58.395, 57.12, 57.375] ImageNet 统计值
MobileNet 127.5 127.5 归一化到 [-1,1]
自定义 根据训练配置 根据训练配置 与训练时一致

std 是归一化除数;生成的 _inputmeta.yml 固定使用 scale 字段,其值为 1 / std

平台与多核

平台 多核支持 说明
pnna 不支持 默认平台,单核架构
pnna2 支持 1-4 核 多核架构

多核配置(仅 pnna2

配置值 说明
1core / 1 单核模式
2core / 2 双核模式
3core / 3 三核模式
4core / 4 四核模式

数据集格式

Netrans 量化支持以下数据集格式用于校准:

1. 文本列表 (.txt)

每行一个图像路径:

/path/to/image1.jpg
/path/to/image2.jpg
/path/to/image3.jpg

2. NumPy 数组 (.npy)

预处理后的数组数据,形状为 [N, C, H, W]

注意:使用 .npy 作为输入时Netrans 不会触发预处理mean/std 等操作),请确保数组数据已经完成预处理。

3. 自动生成(默认)

当未提供数据集时Netrans 会自动生成随机数据用于量化。

注意:随机数据会影响量化精度,生产环境建议使用真实数据。


导入格式兼容性

格式 支持版本/说明
ONNX opset 7-17ONNX 1.2-1.12
TensorFlow 1.4.x, 2.0.x, 2.3.x, 2.6.x, 2.8.x, 2.10.x, 2.12.x, 2.15.x
TFLite schema 2.15.0TensorFlow 2.15.0
PyTorch 1.5.1-2.2.2.pt 通过 ONNX 后端导入)
Caffe 标准协议及部分扩展协议,具体取决于模型层和算子
Darknet 标准模型,具体取决于模型层和算子
Keras TensorFlow 2.0.x - 2.15.x 生成的模型

配置字段说明

_inputmeta.yml 重点字段

input_meta:
  databases:
    - ports:
        - lid: input_0          # 输入层 ID
          shape: [1, 3, 640, 640]  # [batch, channels, height, width]
          preprocess:
            mean: [0, 0, 0]     # 通道均值
            scale: [0.00392, 0.00392, 0.00392]  # 缩放系数
            preproc_node_params:
              add_preproc_node: true  # 是否嵌入预处理节点到网络
              preproc_dtype_converter:  # 数据类型转换(定点量化时)
                qtype: uint8
                quantizer: asymmetric_affine
                scale: 0.965
                zero_point: 0

关键字段

  • mean: 与 load()mean 对应;scale_inputmeta.yml 的固定字段,值为 1 / std,不是 load() 的参数名
  • add_preproc_node: 设为 true 将预处理嵌入网络图
  • preproc_dtype_converter: 定点量化时的输入数据类型转换

_postprocess_file.yml 重点字段

app_postprocs:
  - lid: output_0           # 输出层 ID
    postproc_params:
      add_postproc_node: true   # 是否嵌入后处理节点
      force_float32: true       # 强制输出为 float32

关键字段

  • add_postproc_node: 设为 true 将反量化等后处理嵌入网络图
  • force_float32: 强制输出数据类型为 float32

场景示例

场景1YOLOv5s 完整转换

#!/usr/bin/env python3
"""YOLOv5s 模型转换完整示例"""
from netrans import Netrans

model = Netrans()
model.load('./yolov5s', mean=[0, 0, 0], std=255)
model.quantize('asymu8', algorithm=1)
model.export('asymu8', platform='pnna', preprocess=True, postprocess=True)
print("✅ 转换完成: wksp/yolov5s_asymu8_nbg_unify/network_binary.nb")

场景2ResNet50 ImageNet 模型

#!/usr/bin/env python3
"""ResNet50 ImageNet 模型转换"""
from netrans import Netrans

model = Netrans()
model.load(
    './resnet50',
    mean=[123.675, 116.28, 103.53],
    std=[58.395, 57.12, 57.375]
)
model.quantize('asymu8', algorithm=1, iterations=5)
model.export('asymu8', platform='pnna')

场景3混合量化

#!/usr/bin/env python3
"""YOLO 模型混合量化 - 检测头高精度"""
from netrans import Netrans
import os

model_dir = './yolov5s'
model = Netrans()
model.load(model_dir, mean=[0, 0, 0], std=255)

# 创建混合量化配置
config_file = os.path.join(model_dir, 'cust_qnt_layers.txt')
with open(config_file, 'w') as f:
    f.write('Conv_245\nConv_269\nConv_293\n')

model.quantize_hybrid('asymu8', cust_qnt_layers=config_file)
model.export('asymu8', platform='pnna', use_hybrid=True)

场景4PNNA2 多核导出

#!/usr/bin/env python3
"""PNNA2 平台 4 核导出"""
from netrans import Netrans

model = Netrans()
model.load('./model', mean=[0, 0, 0], std=255)
model.quantize('asymu8')
model.export('asymu8', platform='pnna2', core_num='4core')

场景5批量转换

#!/bin/bash
MODELS=("yolov5s" "yolov5m" "yolov5l")

for model in "${MODELS[@]}"; do
    echo "=== 转换 $model ==="
    netrans load ./$model --mean 0 0 0 --std 255
    netrans quantize ./$model asymu8 --algorithm 1
    netrans export ./$model asymu8 --platform pnna
    echo "✅ $model 完成"
done

场景6精度验证

#!/usr/bin/env python3
"""精度验证 - 对比浮点和量化模型"""
from netrans import Netrans

model = Netrans()
model.load('./model', mean=[0, 0, 0], std=255)

# 浮点推理
model.inference('float32', iterations=1)

# 量化并推理
model.quantize('asymu8')
model.inference('asymu8', iterations=1)

# 对比 golden 目录输出
# wksp/model_float32/golden/ vs wksp/model_asymu8/golden/

场景7复用 json/data 多量化类型导出

#!/usr/bin/env python3
"""一次 load多量化类型连续导出"""
from netrans import Netrans

model = Netrans()
model.load('./model', mean=[0, 0, 0], std=255)

# 同一实例上连续量化不同类型 — 安全,无需反复 load
for qtype in ['asymu8', 'symi8', 'fp16']:
    model.quantize(qtype)
    model.export(qtype, platform='pnna')

# 原因: nn.quantize(net, rebuild=True) 会重建网络,
# 输入 net 是否已被上一次量化不影响最终结果。
# 经验证,此方式与"每次重新 load"产生的 NBG 大小完全一致。

场景8自定义层量化类型set_ioq

lid + in_out_quantized 参数组合允许为模型的输入/输出层指定与主体不同的量化类型。这在以下场景中很有用:

  • 输入层需要更高精度以保留细节(如 dfpi16
  • 需要验证不同 ioq 类型对精度的影响
#!/usr/bin/env python3
"""为特定输入/输出层指定不同的量化类型"""
from netrans import Netrans

model = Netrans()
model.load('./model', mean=[0, 0, 0], std=255)

# 全模型 asymu8但输入层 input_0 使用 dfpi16更高精度
model.quantize('asymu8', lid='input_0', in_out_quantized='dfpi16')
model.export('asymu8', platform='pnna')

# 同时指定多个层,逗号分隔
model.quantize('asymu8', lid='input_0,output_0', in_out_quantized='symi16')
model.export('asymu8', platform='pnna')

注意事项:

  • lidin_out_quantized 必须同时使用,单独指定其中之一不会生效
  • 层名可以通过 netrans dump 查看各层名称
  • 多输入模型 + 有符号整数symi8/symi16+ in_out_quantized + preprocess=True 可能触发 SDK 报 Error 65280这是 SDK 侧限制

完整可运行示例: examples/custom_layer_quant/

场景9计算模型计算量

#!/usr/bin/env python3
"""统计模型 FLOPs 和参数量"""
from netrans import Netrans

model = Netrans()
model.load('./yolov5s', mean=0, std=255)

# 浮点模型计算量
model.measure('float32')
# 输出wksp/yolov5s_float32/

# 量化后模型计算量
model.quantize('asymu8')
model.measure('asymu8')
# 输出wksp/yolov5s_asymu8/

# Hybrid 量化模型计算量
model.quantize_hybrid('asymu8', cust_qnt_layers='layers.txt')
model.measure('asymu8', use_hybrid=True)
# 输出wksp/yolov5s_asymu8_hy/
# CLI 方式
netrans measure ./yolov5s float32
netrans measure ./yolov5s asymu8
netrans measure ./yolov5s asymu8 --use-hybrid

quant_type 省略时默认为 float32。非 float32 模式需要先生成对应的 .quantize 文件Hybrid 模式需要先完成 quantize_hybrid 并同时指定 --use-hybrid。输出位于模型目录下的 wksp/<model>_<quant_type>/Hybrid 为 wksp/<model>_<quant_type>_hy/)。

完整示例和前置产物说明: examples/measure/

场景10多输入模型转换

多输入模型如双分支网络、Siamese 网络等)的转换流程与单输入基本一致,关键差异在于 dataset.txt 格式和 channel_mean_value.txt 配置。

#!/usr/bin/env python3
"""多输入 Caffe 模型转换"""
from netrans import Netrans

model = Netrans()
model.load('./multi_input', mean=[0, 0, 0], std=1.0)
model.quantize('asymu8')
model.add_pre_post('asymu8', preprocess=True, postprocess=True)
model.export('asymu8')
# CLI 方式
netrans load ./multi_input --mean 0 0 0 --std 1.0
netrans quantize ./multi_input asymu8
netrans add_pre_post ./multi_input asymu8 --preprocess --postprocess
netrans export ./multi_input asymu8

多输入关键点:

要点 说明
dataset<N>.txt 格式 每个输入端口单独一个文件(dataset0.txtdataset1.txt...),文件内为图片路径
channel_mean_value.txt 当前只接受一组共享的 mean/std,会应用到所有输入端口;暂不支持每个输入端口独立配置
inputs_outputs.txt 多输出时用 --outputs 指定输出端口名
前后处理节点嵌入 同时作用于所有输入/输出端口
--lid + --in_out_quantized 多输入模型 + 有符号整数 + ioq=Y + pre=T 可能触发 SDK Error 65280

完整可运行示例: examples/multi_input/


故障排查

错误速查表

错误信息 可能原因 解决方案
xxx.quantize file does not exist 未执行 quantize 或类型不匹配 执行 netrans quantize 并确保类型一致
Warning: @{lid}:<suffix> not found hybrid 层名不匹配 使用 netrans dump 查看实际层名
模型性能分析需求 需要统计 FLOPs/参数量 使用 netrans measure 统计计算量
NBG 文件大小异常 量化未生效 确保 quantize() 后调用 export(),不要重新创建实例
预处理参数不生效 配置未正确加载 检查 channel_mean_value.txt 格式和 _inputmeta.yml

问题1: NBG 文件大小异常

症状: 量化后的 NBG 文件大小与浮点模型相近

原因: Python API 使用时未更新网络对象,或重新加载了浮点模型

解决:

# ✅ 正确流程
model.quantize('asymu8')  # 量化
model.export('asymu8')    # 导出(使用同一实例)

# ❌ 错误:不要重新创建实例
model1 = Netrans()
model1.load('./model')
model1.quantize('asymu8')

model2 = Netrans()  # 新实例!
model2.load('./model')  # 加载的是浮点模型
model2.export('asymu8')  # 导出的是浮点 NBG

问题2: 预处理参数不生效

症状: 模型输出与预期不符

排查步骤:

# 1. 检查 channel_mean_value.txt 格式
cat channel_mean_value.txt
# 应该是: "mean1 mean2 mean3 std"

# 2. 检查 _inputmeta.yml
cat *_inputmeta.yml | grep -A 10 "preprocess:"

# 3. 确认 add_preproc_node 设置
grep "add_preproc_node" *_inputmeta.yml

相关文档