RK3588部署yolov8过程记录
RK3588部署yolov8过程记录
一、模型训练
这一步和大多数教程写的一样,就不赘述了。获取到’.pt’格式的权重即可。
二、模型转换pt—>onnx
1.下载转换工具库
转换工具库链接:https://github.com/airockchip/ultralytics_yolov8
下载后,进入配置好的环境下进行转换。
2.配置修改
修改./ultralytics/cfg/default.yaml中的模型路径
回到项目目录下,输入:
export PYTHONPATH=./
python ./ultralytics/engine/exporter.py
如图
三、模型转换onnx—>rknn
1.配置rknn-toolkit2环境
这一部分要配置rknn-toolkit2环境,下载rknn-toolkit2:https://github.com/airockchip/rknn-toolkit2
版本需要留意一下,需要与后面的rknn_model_zoo版本一致,这里我使用的是2.3.2的版本
先创建一个python3.9的环境,单独给rknn-toolkit2使用。
conda create -n rknn-toolkit2 python=3.9 #创建虚拟环境
conda activate rknn-toolkit2 #激活该环境
cd rknn-toolkit2/rknn-toolkit2/packages/x86_64/ #进入该目录下
pip install -r requirements_cp39-2.3.2.txt -i https://pypi.tuna.tsinghua.edu.cn/simple #安装依赖
pip install rknn_toolkit2-2.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
刚才的虚拟环境下,调用python验证
from rknn.api import RKNN
2.量化配置及转换
需要选取一些图像,放置于dataset文件夹,然后新建dataset.txt文件,改txt文件中包含dataset文件夹下图像的绝对路径。
接下来利用rknn_model_zoo/examples/yolov8/python中的代码进行转换
在convert.py中修改dataset_path(量化图像路径)
在yolov8.py中修改:
在配置好rknn-toolkit2的虚拟环境下输入指令进行转换
python convert.py /home/chenjun0310/SmokeAndFire_Yolov8/ultralytics_yolov8/last.onnx rk3588

在model文件夹下会生成对应名字的rknn格式的文件
3.精度分析
模型经过转换后,会存在一些精度损失,需要使用rknn的模拟器进行精度分析,获取优化方向。代码如下:
#!/usr/bin/env python3
"""
RKNN 模型综合精度分析脚本
1. 使用 RKNN accuracy_analysis API(模拟器模式)
2. ONNX vs RKNN 输出对比
3. 检测结果对比
"""
import os
import sys
import numpy as np
import cv2
import json
from datetime import datetime
# 添加路径
sys.path.insert(0, '/home/chenjun0310/SmokeAndFire_Yolov11/rknn_model_zoo')
from rknn.api import RKNN
import onnxruntime as ort
# ============ 配置 ============
ONNX_MODEL = '/home/chenjun0310/SmokeAndFire_Yolov8/TrainCode/runs/train/smoke_fire_default_1/weights/best.onnx'
RKNN_MODEL = '/home/chenjun0310/SmokeAndFire_Yolov11/rknn_model_zoo/examples/yolov8/model/Firesmokeyolov8.rknn'
VAL_IMG_FOLDER = '/home/chenjun0310/fireSmoke/fireSmoke_org/images/val'
QUANT_DATASET = '/home/chenjun0310/SmokeAndFire_Yolov11/rknn-toolkit2/MyCode/dataset.txt'
OUTPUT_DIR = '/home/chenjun0310/rknn_analysis_results'
TARGET_PLATFORM = 'rk3588'
# 转换参数(与 convert.py 一致)
MEAN_VALUES = [[0, 0, 0]]
STD_VALUES = [[255, 255, 255]]
def get_test_images(folder, max_count=20):
"""获取测试图像列表"""
valid_exts = ['.jpg', '.jpeg', '.png', '.bmp']
imgs = []
for f in sorted(os.listdir(folder)):
if any(f.lower().endswith(ext) for ext in valid_exts):
imgs.append(os.path.join(folder, f))
return imgs[:max_count]
def preprocess_image(img_path, input_size=640):
"""YOLOv8 预处理 - 返回归一化后的 NCHW 张量"""
img = cv2.imread(img_path)
if img is None:
return None, None
# Resize to 640x640
img_resized = cv2.resize(img, (input_size, input_size))
# BGR to RGB, normalize
img_rgb = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)
img_float = img_rgb.astype(np.float32) / 255.0
# HWC to CHW, add batch dim
img_chw = np.transpose(img_float, (2, 0, 1))
input_tensor = np.expand_dims(img_chw, axis=0)
return input_tensor, img_rgb
def cosine_similarity(a, b):
"""计算余弦相似度"""
a_flat = a.flatten().astype(np.float64)
b_flat = b.flatten().astype(np.float64)
dot = np.dot(a_flat, b_flat)
norm_a = np.linalg.norm(a_flat)
norm_b = np.linalg.norm(b_flat)
if norm_a < 1e-8 or norm_b < 1e-8:
return 1.0 if np.allclose(a_flat, b_flat) else 0.0
return dot / (norm_a * norm_b)
def analyze_tensor_diff(onnx_out, rknn_out, name):
"""分析两个张量的差异"""
onnx_arr = np.asarray(onnx_out).astype(np.float32)
rknn_arr = np.asarray(rknn_out).astype(np.float32)
diff = onnx_arr - rknn_arr
result = {
'name': name,
'shape': list(onnx_arr.shape),
'onnx_min': float(np.min(onnx_arr)),
'onnx_max': float(np.max(onnx_arr)),
'onnx_mean': float(np.mean(onnx_arr)),
'onnx_std': float(np.std(onnx_arr)),
'rknn_min': float(np.min(rknn_arr)),
'rknn_max': float(np.max(rknn_arr)),
'rknn_mean': float(np.mean(rknn_arr)),
'rknn_std': float(np.std(rknn_arr)),
'mae': float(np.mean(np.abs(diff))),
'mse': float(np.mean(diff ** 2)),
'rmse': float(np.sqrt(np.mean(diff ** 2))),
'max_abs_diff': float(np.max(np.abs(diff))),
'cosine_sim': float(cosine_similarity(onnx_arr, rknn_arr)),
}
with np.errstate(divide='ignore', invalid='ignore'):
rel_err = np.abs(diff) / (np.abs(onnx_arr) + 1e-8)
valid_rel = rel_err[np.isfinite(rel_err)]
result['mean_rel_err'] = float(np.mean(valid_rel)) if len(valid_rel) > 0 else 0.0
return result
def run_accuracy_analysis_api(onnx_path, output_dir):
"""使用 RKNN 官方 accuracy_analysis API"""
print("\n" + "=" * 80)
print("第一部分:RKNN 官方 accuracy_analysis API 分析")
print("=" * 80)
rknn = RKNN(verbose=True)
print("\n[1] 配置模型参数...")
rknn.config(
mean_values=MEAN_VALUES,
std_values=STD_VALUES,
target_platform=TARGET_PLATFORM
)
print("\n[2] 加载 ONNX 模型...")
ret = rknn.load_onnx(model=onnx_path)
if ret != 0:
print(f"ERROR: 加载 ONNX 失败 (ret={ret})")
rknn.release()
return False
print("\n[3] 构建量化模型...")
ret = rknn.build(do_quantization=True, dataset=QUANT_DATASET)
if ret != 0:
print(f"ERROR: 构建模型失败 (ret={ret})")
rknn.release()
return False
print("\n[4] 初始化运行时(模拟器模式)...")
ret = rknn.init_runtime()
if ret != 0:
print(f"ERROR: 初始化运行时失败 (ret={ret})")
rknn.release()
return False
print("\n[5] 准备精度分析数据集...")
test_images = get_test_images(VAL_IMG_FOLDER, max_count=10)
dataset_file = os.path.join(output_dir, 'test_dataset.txt')
with open(dataset_file, 'w') as f:
for img_path in test_images:
f.write(img_path + '\n')
print(f"使用 {len(test_images)} 张测试图像")
print("\n[6] 执行 accuracy_analysis()...")
accuracy_output_dir = os.path.join(output_dir, 'accuracy_analysis_output')
os.makedirs(accuracy_output_dir, exist_ok=True)
try:
ret = rknn.accuracy_analysis(
inputs=dataset_file,
output_dir=accuracy_output_dir
)
if ret == 0:
print(f"\n精度分析完成!结果保存在: {accuracy_output_dir}")
for root, dirs, files in os.walk(accuracy_output_dir):
for f in files:
print(f" - {os.path.relpath(os.path.join(root, f), accuracy_output_dir)}")
rknn.release()
return True
else:
print(f"WARNING: accuracy_analysis 返回非零值: {ret}")
except Exception as e:
print(f"WARNING: accuracy_analysis 异常: {e}")
print("将使用手动对比方法...")
rknn.release()
return False
def run_manual_comparison(onnx_path, rknn_path, output_dir):
"""手动对比 ONNX 和 RKNN 输出 - 从ONNX重新构建RKNN用于模拟器"""
print("\n" + "=" * 80)
print("第二部分:ONNX vs RKNN 逐层输出对比")
print("=" * 80)
print("\n[1] 加载 ONNX 模型...")
onnx_session = ort.InferenceSession(onnx_path, providers=['CPUExecutionProvider'])
onnx_inputs = onnx_session.get_inputs()
onnx_outputs = onnx_session.get_outputs()
print(f"ONNX 输入: {[i.name for i in onnx_inputs]}, shape: {onnx_inputs[0].shape}")
print(f"ONNX 输出: {len(onnx_outputs)} 个")
for o in onnx_outputs:
print(f" - {o.name}: {o.shape}")
print("\n[2] 从ONNX构建RKNN模型(用于模拟器推理)...")
rknn = RKNN(verbose=False)
# 配置与转换时相同的参数
rknn.config(
mean_values=MEAN_VALUES,
std_values=STD_VALUES,
target_platform=TARGET_PLATFORM
)
ret = rknn.load_onnx(model=onnx_path)
if ret != 0:
print(f"ERROR: 加载 ONNX 失败 (ret={ret})")
return None
print(" 构建量化模型...")
ret = rknn.build(do_quantization=True, dataset=QUANT_DATASET)
if ret != 0:
print(f"ERROR: 构建模型失败 (ret={ret})")
return None
ret = rknn.init_runtime() # 模拟器模式
if ret != 0:
print(f"ERROR: 初始化运行时失败 (ret={ret})")
return None
print("RKNN 初始化成功(模拟器模式)")
test_images = get_test_images(VAL_IMG_FOLDER, max_count=10)
print(f"\n[3] 使用 {len(test_images)} 张图像进行对比测试")
all_results = []
for idx, img_path in enumerate(test_images):
print(f"\n [{idx+1}/{len(test_images)}] {os.path.basename(img_path)}")
input_tensor, img_rgb = preprocess_image(img_path)
if input_tensor is None:
continue
# ONNX 推理 (NCHW, float32, 0-1)
onnx_results = onnx_session.run(
[o.name for o in onnx_outputs],
{onnx_inputs[0].name: input_tensor}
)
# RKNN 推理 (NHWC, uint8, 0-255 因为配置了 mean=[0,0,0], std=[255,255,255])
rknn_input = np.expand_dims(img_rgb, axis=0).astype(np.uint8)
rknn_results = rknn.inference(inputs=[rknn_input])
img_result = {'image': os.path.basename(img_path), 'outputs': []}
for out_idx in range(min(len(onnx_results), len(rknn_results))):
output_name = onnx_outputs[out_idx].name if out_idx < len(onnx_outputs) else f"output_{out_idx}"
diff_result = analyze_tensor_diff(onnx_results[out_idx], rknn_results[out_idx], output_name)
img_result['outputs'].append(diff_result)
print(f" 输出 {out_idx} ({output_name}): MAE={diff_result['mae']:.6f}, "
f"Cosine={diff_result['cosine_sim']:.4f}, "
f"MaxDiff={diff_result['max_abs_diff']:.6f}")
all_results.append(img_result)
rknn.release()
return all_results
def generate_report(results, output_dir):
"""生成分析报告"""
print("\n" + "=" * 80)
print("第三部分:生成分析报告")
print("=" * 80)
if not results:
print("WARNING: 没有分析结果")
return
num_outputs = len(results[0]['outputs']) if results else 0
output_stats = {i: {'mae': [], 'cosine': [], 'max_diff': [], 'rel_err': []} for i in range(num_outputs)}
for img_result in results:
for i, out in enumerate(img_result['outputs']):
output_stats[i]['mae'].append(out['mae'])
output_stats[i]['cosine'].append(out['cosine_sim'])
output_stats[i]['max_diff'].append(out['max_abs_diff'])
output_stats[i]['rel_err'].append(out['mean_rel_err'])
print("\n【汇总统计 - 所有图像平均】")
print(f"{'输出层':<20} {'MAE':<12} {'余弦相似度':<12} {'最大绝对差':<12} {'平均相对误差':<12}")
print("-" * 68)
# YOLOv8 9输出: 3尺度 × (box + class + score_sum)
output_types = ['box', 'class', 'score'] * 3
scale_names = ['80x80', '40x40', '20x20']
problem_outputs = []
for i in range(num_outputs):
mae_avg = np.mean(output_stats[i]['mae'])
cos_avg = np.mean(output_stats[i]['cosine'])
max_diff_avg = np.mean(output_stats[i]['max_diff'])
rel_err_avg = np.mean(output_stats[i]['rel_err'])
scale_idx = i // 3
type_idx = i % 3
output_type = output_types[i] if i < len(output_types) else 'unknown'
scale = scale_names[scale_idx] if scale_idx < len(scale_names) else '?'
name = f"out{i}({scale}/{output_type})"
flag = ""
if cos_avg < 0.95:
flag = " ⚠️"
problem_outputs.append({'index': i, 'scale': scale, 'type': output_type,
'cosine': cos_avg, 'mae': mae_avg})
print(f"{name:<20} {mae_avg:<12.6f} {cos_avg:<12.4f} {max_diff_avg:<12.6f} {rel_err_avg:<12.6f}{flag}")
print("\n【量化误差分析】")
if problem_outputs:
print("发现以下输出层量化误差较大:")
for p in problem_outputs:
print(f" - 输出 {p['index']} ({p['scale']}/{p['type']}): 余弦相似度={p['cosine']:.4f}, MAE={p['mae']:.6f}")
print("\n【改进建议】")
print("1. 增加量化校准数据集数量(当前80张,建议200+张)")
print("2. 考虑使用混合精度量化,对误差大的层保持 FP16")
print("3. 检查量化数据集是否包含足够多样的烟火样本")
print("4. 如果 class/score 层误差大,可能影响分类置信度,考虑调整后处理阈值")
else:
print("所有输出层量化误差在可接受范围内(余弦相似度 >= 0.95)")
# 保存 JSON 报告
report_path = os.path.join(output_dir, 'accuracy_comparison_report.json')
report_data = {
'timestamp': datetime.now().isoformat(),
'onnx_model': ONNX_MODEL,
'rknn_model': RKNN_MODEL,
'conversion_params': {
'quantization': 'INT8',
'mean_values': MEAN_VALUES,
'std_values': STD_VALUES,
'target_platform': TARGET_PLATFORM,
'quant_dataset_size': 80
},
'num_test_images': len(results),
'summary': {},
'detailed_results': results
}
for i in range(num_outputs):
report_data['summary'][f'output_{i}'] = {
'avg_mae': float(np.mean(output_stats[i]['mae'])),
'avg_cosine': float(np.mean(output_stats[i]['cosine'])),
'avg_max_diff': float(np.mean(output_stats[i]['max_diff'])),
'avg_rel_err': float(np.mean(output_stats[i]['rel_err']))
}
with open(report_path, 'w') as f:
json.dump(report_data, f, indent=2, ensure_ascii=False)
print(f"\n详细报告已保存: {report_path}")
def main():
print("=" * 80)
print("RKNN 模型综合精度分析")
print("=" * 80)
print(f"\nONNX 模型: {ONNX_MODEL}")
print(f"RKNN 模型: {RKNN_MODEL}")
print(f"验证集: {VAL_IMG_FOLDER}")
print(f"输出目录: {OUTPUT_DIR}")
os.makedirs(OUTPUT_DIR, exist_ok=True)
# 第一部分:尝试使用官方 API
api_success = run_accuracy_analysis_api(ONNX_MODEL, OUTPUT_DIR)
# 第二部分:手动对比
results = run_manual_comparison(ONNX_MODEL, RKNN_MODEL, OUTPUT_DIR)
# 第三部分:生成报告
if results:
generate_report(results, OUTPUT_DIR)
print("\n" + "=" * 80)
print("分析完成!")
print(f"结果保存在: {OUTPUT_DIR}")
print("=" * 80)
if __name__ == '__main__':
main()
运行完会输出各个输出层的余弦相似度。
4.混合量化
生成量化配置文件
在rknn_model_zoo/examples/yolov8/python中加入如下代码:
convert_hybrid_quant_step1.py,生成best.quantization.cfg 文件
#!/usr/bin/env python3
"""
#!/usr/bin/env python3
"""
YOLOv8 RKNN Hybrid Quantization - Step 1
生成量化配置文件用于分析各层对量化的敏感度
此脚本用于:
1. 加载ONNX模型
2. 执行 hybrid_quantization_step1() 自动分析各层敏感度
3. 生成 .quantization.cfg 配置文件供用户编辑
"""
import sys
import os
from rknn.api import RKNN
DATASET_PATH = '/home/chenjun0310/SmokeAndFire_Yolov11/rknn-toolkit2/MyCode/dataset.txt'
def main():
if len(sys.argv) < 3:
print("用法: python3 {} <onnx_model_path> <platform> [output_cfg_dir]".format(sys.argv[0]))
print("")
print("参数说明:")
print(" onnx_model_path : ONNX 模型路径")
print(" platform : 目标平台 (rk3588, rk3566, rk3568, rk3576, rk3562, rv1126b 等)")
print(" output_cfg_dir : 输出配置文件目录 (默认: 当前目录)")
print("")
print("示例:")
print(" python3 {} /path/to/best.onnx rk3588".format(sys.argv[0]))
sys.exit(1)
model_path = sys.argv[1]
platform = sys.argv[2]
cfg_output_dir = sys.argv[3] if len(sys.argv) > 3 else '.'
if not os.path.exists(model_path):
print(f"错误: 模型文件不存在 - {model_path}")
sys.exit(1)
print("=" * 80)
print("RKNN YOLOv8 混合精度量化 - Step 1: 生成配置文件")
print("=" * 80)
print(f"模型路径: {model_path}")
print(f"目标平台: {platform}")
print(f"数据集: {DATASET_PATH}")
print(f"输出目录: {cfg_output_dir}")
print("")
# 创建 RKNN 对象
print("--> 创建 RKNN 对象")
rknn = RKNN(verbose=True)
print("done\n")
# 配置模型
print("--> 配置模型")
rknn.config(
mean_values=[[0, 0, 0]],
std_values=[[255, 255, 255]],
target_platform=platform
)
print("done\n")
# 加载模型
print("--> 加载 ONNX 模型")
ret = rknn.load_onnx(model=model_path)
if ret != 0:
print('加载模型失败!')
rknn.release()
sys.exit(ret)
print("done\n")
# 执行 hybrid_quantization_step1
print("--> 执行 hybrid_quantization_step1 (分析各层敏感度)")
print(" 这可能需要几分钟时间...\\n")
ret = rknn.hybrid_quantization_step1(dataset=DATASET_PATH, proposal=False)
if ret != 0:
print('hybrid_quantization_step1 失败!')
rknn.release()
sys.exit(ret)
print("done\n")
# 获取模型基名
model_basename = os.path.basename(model_path)
cfg_filename = os.path.splitext(model_basename)[0] + '.quantization.cfg'
cfg_path = os.path.join(cfg_output_dir, cfg_filename)
# 输出提示信息
print("=" * 80)
print("混合精度量化配置指南")
print("=" * 80)
print("")
print("配置文件已生成: " + cfg_path)
print("")
print("配置文件说明:")
print(" - 文件格式为 YAML")
print(" - 'custom_quantize_layers' 部分列出建议需要特殊处理的层")
print("")
print("配置步骤:")
print(" 1. 编辑生成的配置文件")
print(" 2. 在 'custom_quantize_layers' 中添加需要FP16精度的输出层")
print("")
print("YOLOv8 模型推荐配置 (用于小目标检测精度优化):")
print(" custom_quantize_layers:")
print(" output7: float16 # 80x80 scale - class scores (小目标分类)")
print(" output8: float16 # 80x80 scale - score_sum")
print(" output4: float16 # 40x40 scale - class scores (中尺度分类)")
print(" output5: float16 # 40x40 scale - score_sum")
print("")
print("支持的精度类型: int4, int8, int16, float16")
print("")
print("建议策略:")
print(" - 保持 box regression (output0, output3, output6) 为 int8 (节省空间)")
print(" - 将分类层 (output1, output4, output7) 设为 float16 (保持精度)")
print(" - score_sum (output2, output5, output8) 根据需要设为 float16")
print("")
print("完成配置后,执行 Step 2:")
print(f" python3 convert_hybrid_quant_step2.py {model_path} {platform} {cfg_path}")
print("")
print("=" * 80)
rknn.release()
print("Step 1 完成!\\n")
if __name__ == '__main__':
main()
输入指令:
python3 convert_hybrid_quant_step1.py <ONNX模型路径> <目标平台> <输出目录>
如
python3 convert_hybrid_quant_step1.py \
/home/chenjun0310/SmokeAndFire_Yolov8/TrainCode/runs/train/smoke_fire_default_1/weights/best.onnx \
rk3588 \
.
会生成
这会在当前目录生成 3 个文件:
best.quantization.cfg — 量化配置(需要修改的文件)
best.model — 中间模型文件
best.data — 量化参数数据
打开生成的 best.quantization.cfg,在文件中找到 custom_quantize_layers 部分,添加需要设为 FP16 的层:
如:
custom_quantize_layers:
/model.22/cv3.0/cv3.0.2/Conv_output_0: float16 # 80x80 分类层
/model.22/ReduceSum_output_0: float16 # 80x80 score_sum
/model.22/cv3.1/cv3.1.2/Conv_output_0: float16 # 40x40 分类层
/model.22/ReduceSum_1_output_0: float16 # 40x40 score_sum
/model.22/cv3.2/cv3.2.2/Conv_output_0: float16 # 20x20 分类层
/model.22/ReduceSum_2_output_0: float16 # 20x20 score_sum
再新建convert_hybrid_quant_step2.py文件
#!/usr/bin/env python3
"""
YOLOv8 RKNN Hybrid Quantization - Step 2
根据配置文件执行混合精度量化并生成最终RKNN模型
此脚本用于:
1. 读取 Step 1 生成的量化配置文件
2. 执行 hybrid_quantization_step2() 进行混合精度量化
3. 导出最终的 RKNN 模型
4. 进行精度分析验证
"""
import sys
import os
from rknn.api import RKNN
DEFAULT_RKNN_PATH = '../model/Firesmokeyolov8_hybrid.rknn'
def main():
if len(sys.argv) < 3:
print("用法: python3 {} <onnx_model_path> <platform> <quantization_cfg> [output_rknn_path]".format(sys.argv[0]))
print("")
print("参数说明:")
print(" onnx_model_path : ONNX 模型路径")
print(" platform : 目标平台 (rk3588, rk3566, rk3568, rk3576, rk3562, rv1126b 等)")
print(" quantization_cfg : 量化配置文件路径 (由 Step 1 生成的 .quantization.cfg)")
print(" output_rknn_path : 输出 RKNN 模型路径 (默认: " + DEFAULT_RKNN_PATH + ")")
print("")
print("示例:")
print(" python3 {} /path/to/best.onnx rk3588 /path/to/best.quantization.cfg".format(sys.argv[0]))
sys.exit(1)
model_path = sys.argv[1]
platform = sys.argv[2]
cfg_path = sys.argv[3]
output_path = sys.argv[4] if len(sys.argv) > 4 else DEFAULT_RKNN_PATH
# 参数校验
if not os.path.exists(model_path):
print(f"错误: ONNX 模型文件不存在 - {model_path}")
sys.exit(1)
if not os.path.exists(cfg_path):
print(f"错误: 配置文件不存在 - {cfg_path}")
sys.exit(1)
print("=" * 80)
print("RKNN YOLOv8 混合精度量化 - Step 2: 执行混合精度量化")
print("=" * 80)
print(f"ONNX 模型: {model_path}")
print(f"目标平台: {platform}")
print(f"量化配置: {cfg_path}")
print(f"输出RKNN: {output_path}")
print("")
# 查找 Step 1 生成的 .model 和 .data 文件
# 注意: hybrid_quantization_step1() 会把文件输出到当前工作目录,而不是 ONNX 所在目录
model_basename = os.path.splitext(os.path.basename(model_path))[0]
# 候选路径列表 (按优先级排序)
search_paths = [
os.getcwd(), # 1. 当前工作目录 (Step 1 默认输出位置)
os.path.dirname(model_path), # 2. ONNX 文件所在目录
os.path.dirname(os.path.abspath(__file__)), # 3. 脚本所在目录
]
model_file = None
data_file = None
# 查找 .model 文件
for search_path in search_paths:
candidate = os.path.join(search_path, model_basename + '.model')
if os.path.exists(candidate):
model_file = candidate
break
# 查找 .data 文件
for search_path in search_paths:
candidate = os.path.join(search_path, model_basename + '.data')
if os.path.exists(candidate):
data_file = candidate
break
if model_file is None:
print(f"错误: Step 1 生成的 .model 文件不存在")
print(f"已查找的位置:")
for path in search_paths:
print(f" - {os.path.join(path, model_basename + '.model')}")
print("")
print("请先执行 Step 1 脚本生成必要的中间文件,或检查文件是否在上述位置之一")
sys.exit(1)
if data_file is None:
print(f"错误: Step 1 生成的 .data 文件不存在")
print(f"已查找的位置:")
for path in search_paths:
print(f" - {os.path.join(path, model_basename + '.data')}")
print("")
print("请先执行 Step 1 脚本生成必要的中间文件,或检查文件是否在上述位置之一")
sys.exit(1)
print(f".model 文件: {model_file}")
print(f".data 文件: {data_file}")
print("")
# 创建 RKNN 对象
print("--> 创建 RKNN 对象")
rknn = RKNN(verbose=True)
print("done\n")
# 执行 hybrid_quantization_step2
print("--> 执行 hybrid_quantization_step2")
print(" 这可能需要几分钟时间...\\n")
ret = rknn.hybrid_quantization_step2(
model_input=model_file,
data_input=data_file,
model_quantization_cfg=cfg_path
)
if ret != 0:
print('hybrid_quantization_step2 失败!')
rknn.release()
sys.exit(ret)
print("done\n")
# 创建输出目录
output_dir = os.path.dirname(output_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
# 导出 RKNN 模型
print("--> 导出 RKNN 模型")
ret = rknn.export_rknn(output_path)
if ret != 0:
print('导出 RKNN 模型失败!')
rknn.release()
sys.exit(ret)
print(f"done -> {output_path}\n")
# 精度分析 (可选)
print("--> 执行精度分析")
print(" 注: 此步骤仅在有真实验证数据时有用")
try:
# 这里需要提供实际的验证图像
# ret = rknn.accuracy_analysis(inputs=['./test_image.jpg'], output_dir=None)
# 如果没有验证图像,跳过此步骤
print("跳过精度分析 (需要提供验证数据)")
except Exception as e:
print(f"精度分析异常 (可忽略): {e}")
print("done\n")
# 初始化运行时 (可选)
print("--> 初始化运行时环境")
try:
ret = rknn.init_runtime()
if ret == 0:
print("done\n")
else:
print("初始化失败 (可能未连接 NPU 设备)\n")
except Exception as e:
print(f"初始化异常 (可忽略): {e}\n")
rknn.release()
print("=" * 80)
print("混合精度量化完成!")
print("=" * 80)
print("")
print("生成的 RKNN 模型: " + output_path)
print("")
print("后续步骤:")
print(" 1. 将 RKNN 模型部署到 RK3588 等设备上")
print(" 2. 运行推理测试,评估模型精度")
print(" 3. 如果精度不满足,可调整配置文件中的量化精度后重新执行 Step 2")
print("")
if __name__ == '__main__':
main()
开始混合量化
python3 convert_hybrid_quant_step2.py <ONNX模型路径> <目标平台> <配置文件> <输出RKNN路径>
如
python3 convert_hybrid_quant_step2.py \
/home/chenjun0310/SmokeAndFire_Yolov8/TrainCode/runs/train/smoke_fire_default_1/weights/best.onnx \
rk3588 \
best.quantization.cfg \
../model/Firesmokeyolov8_hybrid.rknn
四、PC端编译
rknn_model_zoo的pc端,确认Pc端和开发板端的gcc版本是否匹配,pc端编译,编译后拷贝到开发板进行测试。
1.确认gcc版本
我遇到的情况是PC 使用的是 Ubuntu 22.04 自带的 GCC 11.4.0。
这个版本的编译器默认生成的二进制文件需要 GLIBC 2.34+,但是 RK3588 开发板(通常是 Ubuntu 18.04 或 20.04 基础)只有 GLIBC 2.27 或 2.31。
# 1. 创建一个目录存放工具链
mkdir -p ~/toolchains
cd ~/toolchains
# 2. 下载 Linaro GCC 7.5 (2019.12 版本),这个版本非常稳定且兼容老系统
# 如果 wget 速度慢,可以尝试用 curl 或者找国内镜像
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
# 3. 解压
tar -xf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
# 4. 确认解压后的文件夹名称 (通常是 gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu)
ls
2.rknn_model_zoo/examples/yolov8/cpp代码修改
postprocess.h修改
文件路径:rknn_model_zoo/examples/yolov8/cpp/postprocess.h
// 将OBJ_CLASS_NUM从80改为2
#define OBJ_CLASS_NUM 2
postprocess.cc修改
#define LABEL_NAME_TXT_PATH "./model/labels_list.txt"

3.编译
终端进入rknn_model_zoo
指定编译器
export GCC_COMPILER=/home/chenjun0310/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu
进行编译
rm -rf build/build_rknn_yolov8_demo_rk3588_linux_aarch64_Release
编译结束后,会生成rknn_model_zoo/install文件夹
五、开发板部署
1.复制文件
将install文件夹,复制到开发板,然后准备好测试数据。
2.测试
在install/rk3588_linux_aarch64/rknn_yolov8_demo下依次输入
chmod +x rknn_yolov8_demo
chmod +x rknn_yolov8_demo_zero_copy
export LD_LIBRARY_PATH=./lib
./rknn_yolov8_demo model/yolov8.rknn model/69.jpg
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)