yolov11 训练自己的数据并转换rknn部署至firefly-rk3576 并实现视频实时推理侦测 使用c++部署和python部署方式_yolov11 rknn
1. yolov11模型训练源码获取
模型训练这块直接参考官方示例,yolov11源码获取地址: https://github.com/ultralytics/ultralytics
2.Annaconda 虚拟环境管理库下载
annaconda下载地址:Download Anaconda Distribution | Anaconda
3.pycharm下载
pycharm下载地址:PyCharm: The only Python IDE you need
4.模型训练数据集准备工作
本文数据集来源paddlepaddle,下载链接:车辆识别_数据集-飞桨AI Studio星河社区
制作数据集:第一步xml转txt ,第二步划分数据集
1.xml转txt
import osimport xml.etree.ElementTree as ETdef convert_voc_to_yolo(xml_file, classes, output_dir): tree = ET.parse(xml_file) root = tree.getroot() # 获取图像尺寸 size = root.find(\'size\') width = int(size.find(\'width\').text) height = int(size.find(\'height\').text) # 创建输出TXT文件 txt_filename = os.path.splitext(os.path.basename(xml_file))[0] + \'.txt\' txt_filepath = os.path.join(output_dir, txt_filename) with open(txt_filepath, \'w\') as txt_file: for obj in root.findall(\'object\'): # 获取类别名称 class_name = obj.find(\'name\').text if class_name not in classes: continue # 如果类别不在classes列表中,跳过 # 获取类别ID class_id = classes.index(class_name) # 获取边界框坐标 bbox = obj.find(\'bndbox\') xmin = int(bbox.find(\'xmin\').text) ymin = int(bbox.find(\'ymin\').text) xmax = int(bbox.find(\'xmax\').text) ymax = int(bbox.find(\'ymax\').text) # 转换为YOLO格式 (中心点坐标和宽高,归一化到[0,1]) x_center = (xmin + xmax) / 2.0 / width y_center = (ymin + ymax) / 2.0 / height box_width = (xmax - xmin) / width box_height = (ymax - ymin) / height # 写入TXT文件 txt_file.write(f\"{class_id} {x_center} {y_center} {box_width} {box_height}\\n\")# 示例用法classes = [\'truck\', \'bus\', \'SUV\',\'taxi\',\'car\'] # 你的类别列表xml_dir = r\"E:\\car-main\\dataset\\dataset\\annotation\" # XML文件所在目录output_dir = r\"E:\\car-main\\dataset\\dataset\\labels\" # 输出TXT文件目录# 确保输出目录存在os.makedirs(output_dir, exist_ok=True)# 遍历所有XML文件并转换for xml_file in os.listdir(xml_dir): if xml_file.endswith(\'.xml\'): xml_path = os.path.join(xml_dir, xml_file) convert_voc_to_yolo(xml_path, classes, output_dir)print(\"转换完成!\")
2.划分数据集
import osimport randomimport shutildef split_dataset(image_folder, label_folder, output_folder, train_ratio=0.8, val_ratio=0.1, test_ratio=0.1): \"\"\" 划分数据集为训练集、验证集和测试集 :param image_folder: 图片文件夹路径 :param label_folder: 标签文件夹路径(TXT 文件) :param output_folder: 输出文件夹路径 :param train_ratio: 训练集比例 :param val_ratio: 验证集比例 :param test_ratio: 测试集比例 \"\"\" # 确保比例总和为 1 assert abs(train_ratio + val_ratio + test_ratio - 1.0) < 1e-5, \"比例总和必须为 1\" # 创建输出文件夹 train_image_folder = os.path.join(output_folder, \'train\', \'images\') train_label_folder = os.path.join(output_folder, \'train\', \'labels\') val_image_folder = os.path.join(output_folder, \'val\', \'images\') val_label_folder = os.path.join(output_folder, \'val\', \'labels\') test_image_folder = os.path.join(output_folder, \'test\', \'images\') test_label_folder = os.path.join(output_folder, \'test\', \'labels\') for folder in [train_image_folder, train_label_folder, val_image_folder, val_label_folder, test_image_folder, test_label_folder]: os.makedirs(folder, exist_ok=True) # 获取所有图片文件名(不带扩展名) image_files = [os.path.splitext(f)[0] for f in os.listdir(image_folder) if f.endswith(\'.jpg\')] random.shuffle(image_files) # 随机打乱顺序 # 计算划分点 num_total = len(image_files) num_train = int(num_total * train_ratio) num_val = int(num_total * val_ratio) num_test = num_total - num_train - num_val # 划分数据集 train_files = image_files[:num_train] val_files = image_files[num_train:num_train + num_val] test_files = image_files[num_train + num_val:] # 移动文件到对应的文件夹 def move_files(files, image_dest_folder, label_dest_folder): for file in files: # 移动图片文件 src_image_path = os.path.join(image_folder, file + \'.jpg\') dest_image_path = os.path.join(image_dest_folder, file + \'.jpg\') shutil.move(src_image_path, dest_image_path) # 移动标签文件 src_label_path = os.path.join(label_folder, file + \'.txt\') dest_label_path = os.path.join(label_dest_folder, file + \'.txt\') shutil.move(src_label_path, dest_label_path) # 移动训练集 move_files(train_files, train_image_folder, train_label_folder) print(f\"Moved {len(train_files)} files to train folder.\") # 移动验证集 move_files(val_files, val_image_folder, val_label_folder) print(f\"Moved {len(val_files)} files to val folder.\") # 移动测试集 move_files(test_files, test_image_folder, test_label_folder) print(f\"Moved {len(test_files)} files to test folder.\") print(\"Dataset split completed!\")# 示例调用image_folder = r\"E:\\car-main\\dataset\\dataset\\images\" # 替换为你的图片文件夹路径label_folder = r\"E:\\car-main\\dataset\\dataset\\labels\" # 替换为你的标签文件夹路径output_folder = r\"D:\\yolo\\ultralytics-main\\mytest\\myrknn_datasets\" # 替换为输出文件夹路径# 划分数据集split_dataset(image_folder, label_folder, output_folder, train_ratio=0.8, val_ratio=0.1, test_ratio=0.1)
至此我们就划分好了支持yolov11训练的数据集训练格式其存储格式方式如下:注意检查images,labels数据是否对应以及存在数据
5.模型训练:
5.1 创建配置训练自己的数据所用到的yaml
将对应位置换成自己数据集里的绝对路径,类别名称也按照自己数据的类别进行修改。
5.2 创建yolov11训练文件
5.2.1 修改yolov11yaml
在自己yolov11源码历程路径中找到 D:\\yolo\\ultralytics-main\\ultralytics\\cfg\\models\\11\\yolo11.yaml
将nc修改为自己的类别数(因为我们是做五个类别的侦测训练修改为5就行,默认是coco的80类)
5.2.2 创建train_yolov11.py训练文件
import warningswarnings.filterwarnings(\'ignore\')from ultralytics import YOLOif __name__ == \'__main__\':model = YOLO(r\'D:\\yolo\\ultralytics-main\\ultralytics\\cfg\\models\\11\\yolo11n.yaml\') # 修改为yolov11模型神经网络参数配置的版本yaml# model.load(\'yolo11n.pt\') #加载预训练权重model.train(data=r\'D:\\yolo\\ultralytics-main\\train_yolov11.yaml\', #自己制作的数据集yaml文件 imgsz=640, epochs=100,patience = 10, #10轮内若训练结果若无明显提升则自动结束训练 batch=-1, #自动调节训练批次 workers=2,#线程数 device=\'cpu\', #没显卡则将0修改为\'cpu\' optimizer=\'SGD\', amp = True, # 自动混合精度(AMP)训练 cache=False, #服务器可设置为True,训练速度变快)
这里使用的yolov11n.yaml进行训练,你若想修改为yolov11其他版本就修改其后缀为 :s,m,l,x,(rk3576目标侦测任务推荐的是yolov11n,yolov11s,yolov11m,根据实际任务需求进行选择)煮包使用的是cpu进行训练,你若想用英伟达显卡进行训练,将设置为device = 0,使用显卡显存训练,前提是你要在训练环境中安装支持你自己显卡cuda的torch torchvision torchaudio ,ultralytics官方给的pip install ultrlytics 环境默认装的是cpu版本的torch torchvision torchaudio。
注意选择适合自己英伟达显卡的cuda版本下面是pytorch官网下载地址链接:
PyTorch
查看适合自己显卡版本的cuda,win+r cmd打开控制面板 输入下面指令:
nvidia-smi
驱动版本:Driver Version: 536.67 显卡可支持的CUDA:CUDA Version: 12.2 然后对应选择版本或者下载旧版本到训练环境即可。
5.3查看训练结果
这里煮包只训练了几十轮就取消训练了 在这个路径下 就可以找到 我们模型训练好的权重文件。至此我们的模型训练就到此为止了。
6.模型转换my_best.pt 转onnx
现在我们需要将yolov11训练出的best.pt 转化为ONNX,注意:这里转换不能直接使用ultralytics训练yolov11源码里自带的export.py文件进行转化ONNX 否则后续转成rknn 部署后无法推理会报错。(具体原因是yolov11源码里没有修改模型输出结构,后处理部分跟NPU推理优化不适配等)
我们应该使用瑞芯微官网优化过后的yolov11源码里的export.py转ONNX。
芯微官网优化过后的yolov11源码获取地址:GitHub - airockchip/ultralytics_yolo11
用pycharm打开瑞芯微官网yolov11源码 创建一个用于转化onnx的Convert_onnx.py文件,将我们自己的模型best.pt拷贝过来重命名my_best.pt,虚拟环境还是使用我们训练的环境。以下是Convert_onnx.py转化代码:(format=\'rknn\'是指定转化为适配rknn类型的onnx文件)
from ultralytics import YOLOmodel = YOLO(r\'D:\\ultralytics_yolo11-main\\my_best.pt\')results = model.export(format=\'rknn\')
注意:第一次运行会提示缺少Ultralytics requirements [\'onnx>=1.12.0\', \'onnxslim==0.1.34\', \'onnxruntime\'] not found,我们到conda训练的虚拟环境下pip下载这几个包就行。
conda下载指令如下:
pip install onnx==1.12.0 onnxruntime==1.15.1 onnxslim==0.1.34
转化阶段也可能出现一些其他环境包版本兼容问题,按照上述方法到训练环境按需下载即可。
在自己的历程下找到D:\\ultralytics_yolo11-main\\ultralytics\\cfg\\default.yaml,修改两处task,model
煮包测试使用的是detect任务就不做修改,model需要修改成我们自己训练的模型的路径。(model默认的是yolov11.pt)
环境搭建完成并修改default.ymal后重新运行Convert_onnx.py代码 成功转出ONNX模型
C:\\Users\\19138\\.conda\\envs\\yolo\\python.exe D:\\ultralytics_yolo11-main\\Convert_onnx.py Ultralytics 8.3.9 🚀 Python-3.10.16 torch-2.6.0+cu118 CPU (Intel Core(TM) i7-9750H 2.60GHz)YOLO11n summary (fused): 238 layers, 2,583,127 parameters, 0 gradients, 6.3 GFLOPsPyTorch: starting from \'D:\\ultralytics_yolo11-main\\my_best.pt\' with input shape (1, 3, 640, 640) BCHW and output shape(s) ((1, 64, 80, 80), (1, 5, 80, 80), (1, 1, 80, 80), (1, 64, 40, 40), (1, 5, 40, 40), (1, 1, 40, 40), (1, 64, 20, 20), (1, 5, 20, 20), (1, 1, 20, 20)) (10.2 MB)RKNN: starting export with torch 2.6.0+cu118...RKNN: feed D:\\ultralytics_yolo11-main\\my_best.onnx to RKNN-Toolkit or RKNN-Toolkit2 to generate RKNN model.Refer https://github.com/airockchip/rknn_model_zoo/tree/main/examples/RKNN: export success ✅ 0.9s, saved as \'D:\\ultralytics_yolo11-main\\my_best.onnx\' (9.9 MB)Export complete (1.3s)Results saved to D:\\ultralytics_yolo11-mainPredict: yolo predict task=detect model=D:\\ultralytics_yolo11-main\\my_best.onnx imgsz=640 Validate: yolo val task=detect model=D:\\ultralytics_yolo11-main\\my_best.onnx imgsz=640 data=D:\\yolo\\ultralytics-main\\train_yolov11.yaml Visualize: https://netron.app进程已结束,退出代码为 0
可以使用netron.app 查看我们转化onnx模型结构 ,output有三个尺度九个头的输出就说明成功了。
到此为止我们前期的准备工作都结束了。
7.firefly rk3576 板端SDK下载以及编译环境配置
煮包这里没有按照官方的步骤进行连板测试,是直接进入板端进行编译配置环境的,所以步骤跟官方文档步骤有一定区别。
7.1进入板子系统 查看安装的系统版本
烧录这块请自行下载官网教程根据自己需要自动烧录这里不做过多赘述。
进入到firefly的板端系统 查看系统的版本(这一步很重要 后面安装SDK需要与系统版本一致)
打开终端输入以下命令:
uname -a
你会看到如下信息:
firefly@firefly:~$ uname -a
Linux firefly 6.1.75-g1b2c33009112-dirty #36 SMP Tue Sep 3 10:06:19 CST 2024 aarch64 GNU/Linux
我这里烧录的最新的firefly官方给的固件debian系统 arm64(aarch64 )架构。
7.2下载SDK以及配置相关虚拟环境
打开终端输入一下指令会下载两个RKNN相关仓库SDK
# 新建 Projects 文件夹mkdir Projects# 进入该目录cd Projects# 下载 RKNN-Toolkit2 仓库git clone https://github.com/airockchip/rknn-toolkit2.git --depth 1# 下载 RKNN Model Zoo 仓库git clone https://github.com/airockchip/rknn_model_zoo.git --depth 1
下载完SDK后我们需要配置一个虚拟环境用于执行推理rknn的PYthon代码
板端浏览器直接访问annconda官网下载miniconda (linux arm64版本)
使用以下指令安装miniconda:
#先cd到下载miniconda的目录下cd /home/firefly/Downloads/#授权安装chmod +x ./Miniconda3-latest-Linux-aarch64.sh#执行安装指令./Miniconda3-latest-Linux-aarch64.sh
一直按住enter 或空格 直至出现一个END
注意:这时需要先按一下esc 在输入:w q才会弹出确认是否同意安装的界面 。这时输入yes就行
再按一下enter 就开始安装miniconda了 直到出现下面这些信息就成功了。
You can undo this by running `conda init --reverse $SHELL`? [yes|no]
[no] >>> yes
no change /home/firefly/miniconda3/condabin/conda
no change /home/firefly/miniconda3/bin/conda
no change /home/firefly/miniconda3/bin/conda-env
no change /home/firefly/miniconda3/bin/activate
no change /home/firefly/miniconda3/bin/deactivate
no change /home/firefly/miniconda3/etc/profile.d/conda.sh
no change /home/firefly/miniconda3/etc/fish/conf.d/conda.fish
no change /home/firefly/miniconda3/shell/condabin/Conda.psm1
no change /home/firefly/miniconda3/shell/condabin/conda-hook.ps1
no change /home/firefly/miniconda3/lib/python3.12/site-packages/xontrib/conda.xsh
no change /home/firefly/miniconda3/etc/profile.d/conda.csh
modified /home/firefly/.bashrc
==> For changes to take effect, close and re-open your current shell. <==
Thank you for installing Miniconda3!
添加环境变量:
#注意路径换成自己的下载路径export PATH=/home/firefly/Downloads/miniconda3/bin/:$PATH
然后重启板端。使用以下命令查看是否可以安装成功:
conda -V
你会看到以下信息就安装成功了。
(base) firefly@firefly:~$ conda -V
conda 25.1.1
现在就开始创建一个环境指定python版本为3.8 (后面安装环境也要选择cp38相关的 38代表的就是python版本 所以我们创建环境时不能指定版本太低 或太高 以免后面环境安装不适配)
下面是创建环境指令:
conda create -n toolkit2 python=3.8
查看并激活环境:
# 查看环境是否创建成功conda env list# 激活环境conda activate toolkit2
进入到环境toolkit2后 我们终端路径进入到之前下载的toolkit2包里路径指令如下:
cd /home/firefly/Projects/rknn-toolkit2/rknn-toolkit2/packages/arm64/
cd /home/firefly/Projects/rknn-toolkit2/rknn-toolkit2/packages/arm64
在packges 路径下有两个文件 一个是arm64 一个是x86 选择你对应板端系统的版本cd进入目录
然后pip指令下载cp38(对应创建环境的python=3.8)指令如下:
pip install -r arm64_requirements_cp38.txt
下载太慢可用中科大的镜像源下载:
pip install -r arm64_requirements_cp38.txt -i https://mirrors.aliyun.com/pypi/simple/
注意如果出现缺少CMAKE和缺少便编译工具链导致的错误按照一下指令下载再运行上面指令就行:
sudo apt updatesudo apt install cmake make
sudo apt updatesudo apt install -y build-essential cmake git # 安装 gcc, g++, make, cmake, git
下载whl指令:
pip install rknn_toolkit2-2.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl