核心结论
RDK S100 的 BPU 不支持 FP16 加速,强制使用 FP16 会导致模型回退到 CPU 运行,速度极慢。
S100 的 BPU(Nash 架构)是专为 INT8 定点计算 优化的加速器,FP16 并非其原生支持的高效精度。当你将模型量化为 float16 时,BPU 无法有效加速,推理任务会降级到 ARM CPU 执行,导致性能远低于 INT8 模型。
原因分析
1. BPU 架构特性
- S100 BPU (Nash-E):专为 INT8 优化,硬件电路针对定点运算设计
- FP16 支持:部分算子可能支持,但效率远低于 INT8,甚至完全不支持
- 降级机制:当模型精度不匹配时,系统自动回退到 CPU 执行
2. 性能对比
| 精度 | BPU 加速 | 典型耗时 (YOLOv8n) | 说明 |
|---|---|---|---|
| INT8 | 5-10ms | 推荐使用 | |
| FP16 | 50-200ms | 回退到 CPU | |
| FP32 | 100-500ms | 纯 CPU 运行 |
正确做法:使用 INT8 量化
步骤一:准备校准数据
# 准备 100 张代表性图片(与你的实际应用场景相似)
python3 prepare_calibration.py --input_dir ./dataset --output_dir ./calibration_data --max_images 100
步骤二:配置量化 YAML
model_parameters:
onnx_model: 'yolov8n.onnx'
march: nash-e # S100 必须用 nash-e
working_dir: 'output_int8'
output_model_file_prefix: 'yolov8n_int8'
input_parameters:
input_type_rt: 'nv12' # 板端输入格式
input_type_train: 'rgb'
input_layout_train: 'NCHW'
scale_value: 0.003921568627451
calibration_parameters:
cal_data_dir: './calibration_data'
cal_data_type: 'float32'
calibration_type: 'default' # 默认 PTQ 量化
quant_config:
quantize_mode: 'w8a8' # 权重和激活都量化为 INT8
op_config:
softmax:
qtype: 'int8'
compiler_parameters:
optimize_level: 'O2' # 优化级别
compile_mode: 'latency' # 延迟优先
步骤三:执行量化编译
# 在工具链 Docker 中运行
hb_compile -c convert_int8.yaml
步骤四:验证模型精度
# 使用 hb_mapper 检查模型信息
hb_mapper check_model --model yolov8n_int8.hbm
# 确认量化类型为 INT8
# 输出应包含:quantiType: SCALE (表示已量化)
INT8 vs FP16 性能测试代码
// 在板端测试不同模型的性能
#include <chrono>
#include <iostream>
void benchmark_model(const char* model_path, int iterations = 100) {
hbDNNPackedHandle_t packed_handle;
const char* model_file = model_path;
// 加载模型
hbDNNInitializeFromFiles(&packed_handle, &model_file, 1);
// ... 准备输入输出张量 ...
// 性能测试
auto start = std::chrono::system_clock::now();
for (int i = 0; i < iterations; i++) {
hbUCPTaskHandle_t task = nullptr;
hbDNNInferV2(&task, outputs, inputs, dnn_handle);
hbUCPSubmitTask(task, &ctrl_param);
hbUCPWaitTaskDone(task, 10000);
}
auto end = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::cout << "Model: " << model_path << std::endl;
std::cout << "Average inference time: " << (float)duration / iterations << " ms" << std::endl;
}
int main() {
std::cout << "=== INT8 Model ===" << std::endl;
benchmark_model("yolov8n_int8.hbm");
std::cout << "\n=== FP16 Model ===" << std::endl;
benchmark_model("yolov8n_fp16.hbm");
return 0;
}
常见问题
Q1: 为什么我的 INT8 模型精度下降严重?
解决:
- 增加校准数据数量(建议 100-500 张)
- 确保校准数据覆盖实际场景
- 对敏感层使用混合精度(在
quant_config.op_config中指定)
quant_config:
op_config:
"model.24.cv2.0.0":
qtype: "fp16" # 对特定层使用 FP16
"model.24.cv3.0.0":
qtype: "fp16"
Q2: 如何检查模型是否在 BPU 上运行?
# 查看 BPU 利用率
top # 查看 bpu_monitor 进程
# 或使用官方工具
hb_sys_info
Q3: FP16 模型完全不能用吗?
- 可以运行,但性能差
- 适用场景:仅用于快速验证算法逻辑,不用于实际部署
- 建议:开发阶段用 ONNX 验证,部署必须用 INT8
参考资源
- 完整量化教程:RDKS100 模型量化及部署
- 工具链文档:OpenExplorer 量化指南
- Model Zoo 示例:rdk_model_zoo_s
行动建议
- 立即重新量化为 INT8:使用
hb_compile配合校准数据 - 验证性能:对比 INT8 和 FP16 的推理耗时
- 优化精度:如果 INT8 精度不达标,使用混合精度策略
预期效果:INT8 模型相比 FP16 应有 5-20 倍 的性能提升!