netrans/docs/cookbook.md

504 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Netrans Cookbook - 实用指南
本文档提供 Netrans 的速查表、配置说明、场景示例和故障排查。
---
## 目录
1. [快速开始](#快速开始)
2. [速查表](#速查表)
3. [数据集格式](#数据集格式)
4. [导入格式兼容性](#导入格式兼容性)
5. [配置字段说明](#配置字段说明)
6. [场景示例](#场景示例)
7. [故障排查](#故障排查)
---
## 快速开始
## 安装指南
```bash
# 克隆仓库并创建 Python 3.10 环境后,在源码根目录执行
make install
source ~/.bashrc
```
请使用项目提供的 Makefile 完成安装;在源码根目录执行 `make install` 即可安装 Netrans 及所需组件。环境创建和日常更新步骤见本项目的介绍与安装页(仓库中为 `README.md`)。
### 基础转换流程
```bash
# 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 完整流程
```python
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 参数支持自动广播,无需手动填写所有通道值:
```python
# 显式指定每个通道
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 重点字段
```yaml
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 重点字段
```yaml
app_postprocs:
- lid: output_0 # 输出层 ID
postproc_params:
add_postproc_node: true # 是否嵌入后处理节点
force_float32: true # 强制输出为 float32
```
**关键字段**
- `add_postproc_node`: 设为 `true` 将反量化等后处理嵌入网络图
- `force_float32`: 强制输出数据类型为 float32
---
## 场景示例
### 场景1YOLOv5s 完整转换
```python
#!/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 模型
```python
#!/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混合量化
```python
#!/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 多核导出
```python
#!/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批量转换
```bash
#!/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精度验证
```python
#!/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 多量化类型导出
```python
#!/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 类型对精度的影响
```python
#!/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')
```
**注意事项:**
- `lid``in_out_quantized` 必须同时使用,单独指定其中之一不会生效
- 层名可以通过 `netrans dump` 查看各层名称
- 多输入模型 + 有符号整数symi8/symi16+ `in_out_quantized` + `preprocess=True` 可能触发 SDK 报 Error 65280这是 SDK 侧限制
> 完整可运行示例: [examples/custom_layer_quant/](../examples/custom_layer_quant/)
### 场景9计算模型计算量
```python
#!/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/
```
```bash
# 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/](../examples/measure/)
### 场景10多输入模型转换
多输入模型如双分支网络、Siamese 网络等)的转换流程与单输入基本一致,关键差异在于 `dataset.txt` 格式和 `channel_mean_value.txt` 配置。
```python
#!/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')
```
```bash
# 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.txt`、`dataset1.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/](../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 使用时未更新网络对象,或重新加载了浮点模型
**解决**:
```python
# ✅ 正确流程
model.quantize('asymu8') # 量化
model.export('asymu8') # 导出(使用同一实例)
# ❌ 错误:不要重新创建实例
model1 = Netrans()
model1.load('./model')
model1.quantize('asymu8')
model2 = Netrans() # 新实例!
model2.load('./model') # 加载的是浮点模型
model2.export('asymu8') # 导出的是浮点 NBG
```
### 问题2: 预处理参数不生效
**症状**: 模型输出与预期不符
**排查步骤**:
```bash
# 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
```
---
## 相关文档
- [API 参考](netrans_api.md) - Python API 详细说明
- [CLI 参考](netrans_cli.md) - 命令行工具参考
- [版本记录](release.md) - 版本发布记录