首页 / 资讯中心 / 文章详情

RK3588部署YOLOv5前先用QEMU模拟器仿真,ARM64环境搭建全指导

RK3588部署YOLOv5前先用QEMU模拟器仿真,ARM64环境搭建全指导 ★ FEATURED ARTICLE
1. 为什么先折腾PC端模拟器——给RK3588打前站的三个理由先说一下这篇的背景。我在做香橙派RK3588的YOLOv5s部署系列教程这一篇是第04集重点放在PC端模拟器仿真跑通YOLOv5。很多朋友拿到RK3588开发板第一件事就是烧系统、连屏幕、开终端恨不得当天就把YOLOv5的demo跑出来。结果往往是系统烧写不顺利、网络配不通、SDK版本对不上、日志刷屏看不懂折腾三天连Python环境都没装好热情直接凉了一半。我的做法相反——先在PC上用模拟器把整个流程预演一遍。RK3588是一块8核ARM64的SoC集成了6TOPS算力的NPU跑YOLOv5s这种轻量级检测网络完全没问题。但正因为它是ARM架构、跑的是Ubuntu根文件系统、还要跟NPU驱动打交道前期环境调试的复杂度远高于一台普通x86电脑。如果你能先在模拟器里把Ubuntu 20.04环境、YOLOv5源码、依赖库、权重推理这一条链路全部跑通后面上真机就会从容很多。我先说说为什么这个打前站的思路值得做。第一模拟器里的环境是可丢弃的。你在PC上用QEMU模拟一块aarch64的机器随时可以快照、回滚、重新创建。真机烧写一次系统至少十几分钟还不一定一次成功模拟器创建环境只需要一条命令搞坏了再起一个就是。对于教程学习来说这个试错成本差距是巨大的。第二仿真环境暴露的是纯软件问题。YOLOv5在RK3588上跑涉及的问题分两类一类是算法本身的问题比如数据集格式、模型配置、推理参数、后处理逻辑另一类是硬件平台的问题比如NPU驱动、内存带宽、算子支持度。如果你直接在板子上调试两类问题会混在一起出了问题很难定位。先在模拟器里把第一类问题解决掉上板之后只面对第二类问题排查范围小了一半。第三性能不是模拟器的目的正确性是。很多人一听模拟器就说跑得慢有什么意义。模拟器的意义根本不在于跑多快而在于验证流程和逻辑是否正确。你的YOLOv5模型在模拟器里能正确识别出一张图片里的猫和狗说明你的环境、代码、权重、推理链路是通的。换成真机同样的代码大概率也能跑只是速度更快、还能用NPU。这一篇的另外一个价值在于就算你没有RK3588板子只是想学YOLOv5目标检测的知识这套模拟器方案也能让你先接触ARM64环境下的部署流程为以后的工作打好基础。2. 模拟器环境搭建的完整过程从Ubuntu 20.04根文件系统到QEMU启动2.1 准备工具和系统镜像我用的方案是QEMU系统级模拟不是用户态模拟。两者的区别简单说用户态模拟只模拟CPU指令层你可以在x86的Linux上直接跑ARM64的二进制程序但没法模拟整个操作系统和外设系统级模拟则是一整台虚拟的ARM64机器有虚拟硬盘、虚拟网卡、串口可以像真机一样安装和运行完整的Ubuntu系统。对于我们要跑YOLOv5这种涉及Python、OpenCV、大量动态库的应用系统级模拟是唯一靠谱的选择。需要准备的材料有三样Ubuntu 20.04的aarch64根文件系统。我直接用的ubuntu-base-20.04-base-arm64.tar.gz这是Ubuntu官方提供的ARM64基础系统包没有桌面环境只有最基础的命令行工具。跑YOLOv5我们不需要桌面命令行就够了。QEMU的aarch64固件也就是EFI引导文件。用QEMU_EFI.fd这个文件它负责模拟ARM64机器的固件启动阶段。一个Linux内核镜像。我偷懒直接用了香橙派官方系统里提取出来的内核但更通用的做法是用Ubuntu ARM64的内核包。这里要提醒一句内核版本不用太新稳定就好因为模拟器里不需要板级的设备树驱动通用内核反而更省心。注意在正式开始之前先在PC上确认你的QEMU版本支持aarch64系统模拟。Ubuntu 20.04以上系统的软件源里包名叫做qemu-system-arm直接apt安装就能拿到。2.2 QEMU系统仿真的启动参数很多教程喜欢直接给一整条启动命令但我不建议直接复制而是要把每个参数吃透否则出了问题你根本不知道从哪里排查。我整理一下我实际用的启动命令qemu-system-aarch64 \ -M virt \ -cpu cortex-a76 \ -smp 8 \ -m 8192 \ -bios QEMU_EFI.fd \ -kernel vmlinuz \ -initrd initrd.img \ -drive fileubuntu_rootfs.img,ifnone,idhd0,formatraw \ -device virtio-blk-device,drivehd0 \ -netdev user,idnet0,hostfwdtcp::2222-:22 \ -device virtio-net-device,netdevnet0 \ -device virtio-gpu-pci \ -display none \ -append root/dev/vda rw consolettyAMA0逐项解释一下-M virt使用QEMU的virt通用机器类型这是ARM64模拟最常用的兼容性最好不需要关心具体板卡的差异。-cpu cortex-a76模拟Cortex-A76核心。RK3588是四核A76加四核A55的架构我在模拟器里统一用A76性能更高一些而且和真机的指令集是兼容的。实际上QEMU对ARMv8-A的支持已经很成熟这个参数影响的是仿真执行效率不是功能正确性。-smp 8模拟8个CPU核心。这里有意思的是QEMU的TCG多线程仿真在aarch64上已经支持得很好8个核能明显加快PyTorch的CPU推理速度。-m 8192分配8GB内存。YOLOv5s推理本身吃不了太多内存但PyTorch和OpenCV的加载开销不小而且Ubuntu 20.04基础系统运行也需要内存我给到8GB是为了后面训练小数据集时不至于OOM。-netdev user用QEMU的用户态网络配合hostfwd把宿主机的2222端口映射到虚拟机里的22端口这样就能通过SSH连接过去。-device virtio-gpu-pci虽然-display none关闭了图形界面但保留GPU设备是为了让系统能识别到显示设备某些程序比如OpenCV的GUI模块在初始化时会检测显示环境没有设备可能直接报错。-append传给内核的启动参数root/dev/vda指根文件系统在第一个虚拟磁盘上consolettyAMA0把控制台输出重定向到串口。2.3 网络配置和SSH登录启动之后如果看到内核日志刷屏、最后出现Ubuntu 20.04 LTS的登录提示符说明系统已经跑起来了。但模拟器里只有一个命令行终端操作体验很差所以我第一件事是配置SSH。在模拟器终端里执行apt update apt install -y openssh-server net-tools passwd root systemctl enable ssh systemctl restart ssh然后在宿主机上直接ssh rootlocalhost -p 2222就能登录到模拟环境里了。这里有个实用技巧我建议全程用SSH操作模拟器不要直接在QEMU的串口终端里输命令。SSH的终端更流畅支持复制粘贴还能用VS Code的Remote SSH插件直接连上去写代码效率完全不是同一个级别。2.4 共享目录的搭建模拟器里跑YOLOv5总要把宿主机的图片、数据集、权重文件传进去。虽然可以用scp一个个拷但我更喜欢用QEMU的virtio-9p共享目录功能直接映射宿主机的一个文件夹到虚拟机里读写共享非常方便。启动命令里加上这么一段-virtfs local,path/home/me/yolo-share,mount_taghostshare,security_modelnone,idshare0进入虚拟机后挂载mkdir -p /mnt/hostshare mount -t 9p -o transvirtio hostshare /mnt/hostshare这样宿主机/home/me/yolo-share目录下的东西在模拟器里直接就能看到。我把YOLOv5源码、测试图片、训练数据集全放在这个共享目录里模拟器里只需要做执行和调试文件管理还是交给宿主机省去了来回拷贝的麻烦。这一步完成之后整个模拟环境就是一个可以跑ARM64 Ubuntu的虚拟机器了。下一步就是在这个环境里装YOLOv5的运行环境。3. YOLOv5在模拟器里从安装到跑通的实操记录3.1 搭建Python环境和PyTorchUbuntu 20.04自带的Python版本只有3.8用来跑YOLOv5其实有点老新版本YOLOv5要求Python 3.7以上即可所以3.8是满足的。我建议用一个干净的虚拟环境来安装避免和系统Python包冲突。这是我做了很多次之后觉得最稳妥的方式apt install -y python3-pip python3-venv git wget python3 -m venv /opt/yolov5-env source /opt/yolov5-env/bin/activate激活虚拟环境之后先安装PyTorch。这里要特别注意模拟器是ARM64架构而且没有GPU所以只能装CPU版。在ARM64的Ubuntu上PyTorch官方源是有对应轮子的直接pip安装就行pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu装的时候如果速度很慢可以把PyTorch的源换成国内镜像但不要混合不同的源否则容易拉取到不匹配的包。提示模拟器里千万不要尝试装CUDA版本的PyTorch因为QEMU模拟出来的设备根本没有GPU计算能力。装CUDA版不仅浪费空间还会在运行时报找不到驱动。3.2 下载YOLOv5源码和权重YOLOv5的源码在GitHub上直接clone到共享目录里cd /mnt/hostshare git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt这里requirements.txt里有一堆依赖最好让pip自动装。如果某个包编译失败比如opencv-python-headless在ARM64源里比较少见可以改用系统的apt包替代apt install -y python3-opencv这是一个很实用的思路pip装不了的OpenCV版本用apt装系统版往往更快更稳YOLOv5需要用的核心APIimread、resize、cvtColor这些在两个版本里都是通用的。权重文件从官方仓库里下载yolov5s.ptwget https://github.com/ultralytics/yolov5/releases/download/v6.0/yolov5s.pt如果这个下载地址访问慢可以从其他镜像站拉取。yolov5s.pt大概14MB虽然不大但在模拟器网络不好的时候也可能下载超时。我的做法是在宿主机上下载好放到共享目录里模拟器直接读。3.3 用图片跑第一次推理环境搭建好之后先用一张现成的图片测试能不能正常跑通推理。我用的是YOLOv5仓库自带的测试图片data/images/bus.jpg这里我不直接介绍检测结果先看一下最基础的推理命令cd /mnt/hostshare/yolov5 python detect.py --weights yolov5s.pt --source data/images/bus.jpg --conf-thres 0.4 --iou-thres 0.5 --project runs/detect跑起来之后你会看到一堆日志包括模型的层结构、参数量、FLOPs、类别数量等。如果一切正常最后会生成一张标注好检测框的结果图保存在runs/detect/exp/目录下。第一次跑通的时间在模拟器里大概要1分多钟因为在加载PyTorch和权重文件时需要把大量动态库映射到模拟内存中。这个速度看着慢但你要知道真实RK3588板子的CPU跑同样推理也就几百毫秒到一两秒模拟器的主要目的是验证流程不是看性能。跑通一次之后我建议做一个基础验证换一张自己的图片试试。我放了一张有三瓶饮料的桌面照片进共享目录YOLOv5默认的COCO权重能识别出bottle类别如果识别结果和真实场景基本吻合说明整个推理链路已经通了——从图片读取、预处理、模型推理、后处理到结果可视化每一步都在正常工作。3.4 用视频跑推理顺便聊一下CPU模式的参数调优图像测试通过之后可以试试视频或者摄像头输入。但模拟器里的摄像头设备映射比较麻烦我建议先用视频文件。我自己做测试时用的是一段30秒的车辆行驶视频分辨率为1080p命令如下python detect.py --weights yolov5s.pt --source test_car.mp4 --conf-thres 0.5 --device cpu视频推理比图片慢得多这是正常的。因为每一帧都要做一次完整的前向推理而模拟器里CPU没有硬件加速。这里有个实际经验模拟器做视频推理的正确姿势是降低分辨率比如把视频先缩放成640x480再喂给YOLOv5速度会快很多而且YOLOv5本身会把输入缩放到640x640你送的视频分辨率太高反而浪费了缩放开销。还有一个参数值得说就是--conf-thres。这个阈值控制检测置信度阈值设得低比如0.1模型会输出很多低置信度的框漏检少但你得忍受大量误检阈值设得高比如0.8只有高置信度检测框会保留误检少但可能漏掉小目标。日常调试我习惯先用0.4看全局再根据实际效果往上下调。到这里模拟器里的YOLOv5已经能稳定跑通了。但这只是跑通了官方模型下一步才是关键我们最终要部署的是自己的数据集训练的模型这在模拟器里怎么验证答案和训练有关。我在模拟器里跑过一个2GB数据集的训练任务虽然比真机慢不少但训练流程完全能走通loss曲线正常下降最后产出的权重文件可以正常推理。这也验证了一件事香橙派RK3588的部署链路在软件层面是完全可以脱离硬件来验证的。4. 模拟器验证和真机RK3588部署的差距在哪里这是大部分教程不会专门讲的部分但我觉得恰恰是最重要的部分。很多人以为模拟器跑通了上板子就能一样跑通结果真机上一堆新的问题。核心原因在于模拟器帮你验证了软件逻辑但没有帮你验证硬件对接。4.1 指令集兼容但性能天差地别模拟器里是ARMv8-A指令集RK3588的CPU是ARMv8.2-A指令集二者在基本指令层面完全兼容所以在模拟器里编译和运行的程序可以直接拷贝到真机上执行。这是模拟器跑通流程能迁移到真机的前提。但性能差距大到不能直接参考。我用同一个YOLOv5s模型在模拟器和真机上分别测试过模拟器跑一张640x640图片前后推理大概2到3秒取决于宿主机的CPU性能真机RK3588的CPU跑同样推理实测大概0.3到0.5秒。如果NPU加速可以做到0.05秒以下。也就是说模拟器验证的是能不能跑对永远不要试图从模拟器里估算真机的实时性能。4.2 NPU加速是模拟器里没有的隐藏技能RK3588最有价值的地方是集成的NPU可以跑RKNN格式的量化模型。这一步和模拟器里跑的完全是两个体系模拟器里PyTorch标准模型FP32精度CPU推理。真机上RKNN模型INT8量化NPU推理。所以我不建议上了真机还死磕PyTorch原版推理那是浪费RK3588的能力。正确做法是在模拟器里先把YOLOv5跑通验证模型正确性然后转到工作PCx86架构上使用RKNN Toolkit完成模型转换、量化、精度验证最后把生成的RKNN模型部署到真机的RKNN运行时进行推理。这个链条里模拟器的角色定位就是中间验证站确保你在训练自己的数据集之后模型推理效果没问题这样后续在量化转换时遇到精度下降你至少能区分问题出在网络还是出在量化。4.3 模型量化与后处理的迁移要点模拟器里跑的YOLOv5后处理是Python端的NMS非极大值抑制模型输出的是三个尺寸的特征图每个特征图都有各自的anchor配置后处理需要把这些特征图解码成检测框再做NMS筛选。这部分代码在YOLOv5的models/yolo.py的Detect层里导出ONNX时会把NMS之外的解码逻辑一起导出。但到了RKNN上后处理的写法和PyTorch里完全不同。RKNN的Python接口提供自带的post_process方法而C接口则需要完全手写解码逻辑包括从NPU输出读取三个特征图的原始数据它们的排列方式是NCHW但NPU输出的内存布局可能是特殊的解码时要把每个特征图的位置信息、目标置信度和类别置信度拆开如果模型做了INT8量化输出数据不是直接的float需要反量化公式恢复成置信度最后再做NMS但RKNN输出的框坐标是相对于640x640输入尺寸的需要映射回原始图像尺寸。这些细节模拟器完全帮不上忙必须拿到真机上调试。但反过来说如果你在模拟器里已经理解了YOLOv5的后处理逻辑——每个特征图怎么解码、锚框怎么定义、置信度怎么计算——那就等于掌握了一套独立于硬件平台的算法地基。后续在RKNN上重写后处理你是在翻译逻辑而不是猜逻辑难度完全不一样。这也是我为什么坚持建议先在PC端模拟器仿真这一步它不是可有可无的过渡而是帮你把算法和硬件两个层面的问题分开解决降低最终上板的整体难度。5. 我在模拟器仿真阶段踩过的坑附完整排查思路5.1 坑一启动后卡在root filesystem挂载失败第一次启动QEMU时系统一直卡在类似VFS: Unable to mount root fs on unknown-block(254,0)的地方。原因有几种可能性我逐个排查根文件系统镜像格式不对。我最初直接把一个tar.gz文件当成磁盘镜像传给-drive那能启动才有鬼了必须先制作一个raw格式的空镜像再把tar包解压进去。内核缺少对应的virtio驱动。最开始我用的内核没有编入virtio_blk模块导致系统识别不了/dev/vda作为根设备。排查思路是这样的先确认磁盘镜像是不是raw格式且分区正确再看内核有没有virtio支持。如果两个都没问题还可以在内核参数里临时加上rootdelay5给设备初始化多留一点时间避免设备注册慢导致挂载失败。5.2 坑二模拟器里的Ubuntu磁盘空间不足这个坑我在模拟器里踩过后来发现网上不少人也遇到过。Ubuntu根文件系统默认镜像如果按1GB做的那装完PyTorch、OpenCV一堆依赖后很快报警。我最初建的镜像总共才2GB装到YOLOv5运行环境时磁盘直接满掉。排查思路是先看盘在哪df -h然后确认是系统盘满了还是共享目录满了。如果系统盘满了最简单的办法是直接把镜像扩容。QEMU的raw镜像可以用truncate直接拉大然后用parted扩容分区最后用resize2fs扩展文件系统。我给模拟器创建镜像的时候就直接用了8GB一次性到位的经验是创建镜像时宁可大一点也别抠容量。5.3 坑三YOLOv5推理时内存不足被OOM跑了视频推理时内存直接从6GB涨到接近分配上限最后进程被系统杀掉。原因是视频推理时YOLOv5会把每一帧的检测结果保留下来在输出视频时做帧序列缓存再加上中间的多帧tensor在内存里没有及时释放。面对这种情况我后来用两个方案解决增加内存分配在QEMU参数里把-m从4GB调到8GB。降低检测帧的输入分辨率把视频先缩放成640x480再输入内存占用和输入分辨率几乎是线性关系降分辨率的效果立竿见影。这个坑虽然发生在模拟器里但在真机上同样会遇到。在RK3588上做视频流检测时必须限制帧率或者做跳帧处理否则即使NPU算力够吃满系统内存也是时间问题。5.4 坑四OpenCV装不上或者说依赖冲突模拟器里pip install opencv-python极容易失败因为ARM64的轮子版本鱼龙混杂有些编译参数和Ubuntu 20.04的库不兼容。装好之后也可能在import cv2时报libGL.so.1: cannot open shared object file。看到这个报错的别慌这是典型的有头OpenCV依赖libGL库而服务器版系统里没有装图形库。我的排查思路很简单先用ldd看一下cv2依赖了哪些库缺哪个就apt补哪个ldd /opt/yolov5-env/lib/python3.8/site-packages/cv2/*.so | grep not found通常缺的都是libGL.so.1或者libgthread-2.0.so.0apt安装libgl1和libglib2.0-0就能解决。如果你不想折腾这些直接apt install python3-opencv替代pip安装是最省事的。5.5 用好QEMU快照功能等于给模拟环境上保险最后一个不是坑是技巧。QEMU提供snapshot机制可以随时把虚拟机当前的状态保存下来之后随时恢复。这个功能对新手非常友好在QEMU启动参数中加上磁盘串口信息然后用HMPHuman Monitor Protocol的savevm命令保存状态。恢复时在QEMU monitor里执行loadvm整个系统包括内存状态和磁盘状态一起还原。你的模拟环境如果因为装了某个依赖搞坏了系统一条命令就能回到装坏之前的干净状态。这比反复重建环境、重复安装依赖要省事太多。我在做这套模拟器方案的过程中QEMU快照这个功能帮我省了至少十几次重复搭建环境的操作。每次准备做一次有风险的实验前我都先快照一下实验做完不对就退回完全不用心疼。这一篇的内容写到这里已经足够完整了——从为什么先做模拟器仿真、环境怎么搭、YOLOv5怎么跑通到模拟器和真机的差异、踩坑排查思路全部串起来了。下一步就是拿着这份经验上真机烧写Ubuntu、配置RKNN环境了那部分我会在系列后续的章节里接着写。
阅读完成 · 觉得有帮助?
咨询建站