ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

树莓派5+YOLO目标检测:从VSCode远程开发到模型部署全流程

树莓派5+YOLO目标检测:从VSCode远程开发到模型部署全流程 去年底我在树莓派5上折腾了一套“VScode 模型训练 图片识别”的组合系统用的Ubuntu 24.04最终跑通了从数据集标注、模型训练到推理部署的完整流程。整个过程踩了不少坑尤其是ARM架构下的依赖安装、VScode远程开发的连接配置、以及模型导出后的兼容性问题。这篇学习笔记就把这套链路完整记录下来内容包括方案选型、环境搭建、数据准备、YOLO模型训练、模型转换部署以及我在实际调试中遇到的各种问题和排查思路。如果你是第一次接触边缘端AI或者想在树莓派上落地一个视觉识别项目这篇文章应该能帮你省下不少时间。1. 整体思路为什么这么拆动手之前先把方案想清楚能省掉后面大量返工。1.1 训练和推理为什么要分开我在做这套项目时最大的体会是不要试图在树莓派5上完成所有事情。树莓派5虽然比前代强了不少——四核A76、最大16GB内存、支持PCIe——但它终究是一块ARM架构的嵌入式开发板。模型训练这种高密度计算任务在CPU上即使能跑效率也低得让人难以接受。以YOLOv8n为例在树莓派5的CPU上训练100个epoch、几百张图片的小数据集可能要走几个小时甚至十几个小时。但同样的任务放到一台带GPU的PC上十几分钟就能完成。所以我的做法是PC端负责训练用GPU加速。树莓派5负责推理和部署验证。VScode通过Remote SSH插件连接树莓派作为统一的开发和调试入口这样训练脚本、部署脚本可以在同一个界面里管理。这个方案的优势在于树莓派上跑的东西是最终要交付的东西所有依赖、路径、运行环境都和实际部署一致避免了“在我电脑上没问题”的尴尬。1.2 整体流程串起来整个项目可以画成一条清晰的流水线数据采集 → 图片标注 → 数据集划分 → YOLO模型训练 → 模型导出ONNX → 树莓派部署 → 图片/视频实时推理每一步都有明确的输入输出我最开始就是按这个顺序推进的。中间卡住的地方集中在两步一是树莓派上PyTorch的安装二是ONNX Runtime的版本选择。如果前置环境没弄好后续所有操作都会跟着出问题。1.3 模型选型为什么是YOLOv8n图片识别模型有很多种分类网络ResNet、检测网络YOLO系列、SSD各有侧重。我做的是“识别指定图片中的目标”属于目标检测任务所以直接用YOLO系列。在YOLO家族里我选了YOLOv8n。原因很实际n代表nano版本模型权重只有6MB左右参数量最少推理速度在树莓派上最友好。Ultralytics这个开源库把训练、验证、导出、推理做了统一封装几乎一行命令就能完成。YOLOv8的资料在中文社区非常充足遇到问题搜一下就能解决。如果你对YOLO11感兴趣思路完全一样只是把yolov8n.pt换成yolo11n.pt命令格式基本兼容。新手建议先用YOLOv8n把流程跑通再尝试其他版本。2. 环境准备树莓派5上的Ubuntu 24.04与VScode远程开发工欲善其事必先利其器。环境这部分我折腾了两天写下来给后来人避坑。2.1 树莓派5安装Ubuntu 24.04树莓派5目前可选的系统很多官方Raspberry Pi OS、Ubuntu Server、Ubuntu Desktop等。我选Ubuntu 24.04是因为它是LTS版本软件源里的包比较新而且社区支持周期长。安装过程不复杂我用的官方Raspberry Pi Imager工具烧录Ubuntu镜像。有一点必须提醒树莓派5是ARM64架构不要下成amd64的镜像否则根本启动不了。系统烧录完成后第一次开机需要接显示器键盘完成初始配置包括创建用户、设置WiFi等。如果像我一样手头没有多余显示器可以直接在烧录时预配置好SSH和无线网络。Raspberry Pi Imager支持在烧录前设置主机名、开启SSH、添加WiFi信息非常方便。建议装Desktop版本而不是Server版本理由很简单树莓派虽然可以纯命令行操作但有时候看推理结果图片、调试显示问题时图形界面能省很多时间。不需要的时候把桌面关掉就行不影响性能。2.2 开启SSH与网络配置系统起来后先做两件事开启SSH、确认网络连接。# 如果SSH没开启执行 sudo systemctl enable --now ssh # 查看IP地址 ip addr show我把树莓派的IP固定下来静态IP避免路由器重新分配IP导致VScode远程连不上。静态IP配置在Ubuntu 24.04上可以用netplansudo nano /etc/netplan/01-config.yamlWiFi连接的典型配置network: version: 2 ethernets: eth0: dhcp4: true wifis: wlan0: dhcp4: false addresses: - 192.168.1.100/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: - 192.168.1.1 access-points: 你的WiFi名称: password: 你的WiFi密码然后sudo netplan apply重启后IP就固定了。2.3 VScode Remote SSH连接树莓派VScode本身只是编辑器但装上Remote - SSH插件后它就变成了远程开发终端。这是整个工作流里体验提升最明显的一步。操作步骤本机VScode安装扩展Remote - SSH、Python、Pylance。按F1输入Remote-SSH: Connect to Host选择Add New SSH Host。输入ssh 用户名192.168.1.100选择保存到SSH配置文件。连接后VScode会自动在远端安装VScode Server首次会稍等一会儿。打开远程文件夹后在扩展面板给远端装上Python插件选择远程解释器。这里有几点实际操作经验树莓派上首次运行VScode Server可能因为缺少libstdc等运行库导致启动失败执行sudo apt update sudo apt install -y build-essential libssl-dev libffi-dev python3-dev可以解决大部分依赖问题。如果连接后界面卡顿关掉VScode的文件自动保存、文件监视功能远程编辑大文件会流畅得多。GitHub Copilot等AI插件在远程开发模式下也能用直接在远端装就行实测体验和本地几乎没区别。2.4 Python环境与PyTorch安装树莓派上我用的Python环境是系统自带的Python 3.12。为了避免污染系统环境我为项目建了一个独立的虚拟环境python3 -m venv ~/venvs/ai_env source ~/venvs/ai_env/bin/activatePyTorch在树莓派上安装有个坑默认pip install torch会尝试安装CUDA版本的Linux x86_64包但在ARM64上会失败。正确做法是指定ARM64 CPU版本pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu实测这个方式能装上纯CPU版本的PyTorch。准确说PyTorch官方现在已经发布了支持ARM64 Linux的轮子不需要再手动源码编译。如果你下载速度不理想可以考虑从其他镜像站抓取但记住一定要带aarch64后缀。顺带把常用库一起装上pip install numpy opencv-python onnxruntime ultralytics注意在树莓派的ARM64架构下有些pip包没有预编译轮子会现场源码编译需要系统提前装好build-essential和cmake否则编译到一半报错。3. 数据准备做出“指定图片”识别模型的基础模型识别什么取决于你给它看什么数据。数据质量直接决定模型上限这部分值得花时间认真做。3.1 采集图片素材我这次做的demo是识别三种水果苹果、香蕉、橙子。每类采集了大约150张图片来源包括手机拍摄、网络公开图片、以及用USB摄像头拍的照片。采集时有几个原则背景尽量多样不要只在单一纯色背景上拍实际推理场景的背景往往更复杂多样背景能提升泛化能力。目标尺度有变化有些图片目标占画面很大有些很小让模型学会在不同尺度下识别。光照条件丰富强光、弱光、室内、室外都来一些避免模型只在特定亮度下表现好。如果你要识别的是工业零件、文档、特定物体思路一样但建议每类至少200张类别边界模糊的还得加量。3.2 标注工具与标注格式YOLO系列模型需要的是YOLO格式的标注文件。每一张图片对应一个同名.txt文件里面每一行表示一个目标class_id x_center y_center width height注意x_center、y_center、width、height都是归一化到0到1之间的小数不是像素坐标。标注工具我用的是X-AnyLabeling它的优点是支持自动标注辅助基于深度学习模型预标注能大幅减少手动工作量。如果你用不上自动标注labelImg也是经典选择轻量稳定。标注完的目录结构整理成这样datasets/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ ├── val/ ├── data.yamldata.yaml内容如下train: datasets/images/train val: datasets/images/val nc: 3 names: [apple, banana, orange]3.3 数据集划分划分比例我用的8:2即80%训练、20%验证。划分时注意打乱顺序避免同一个场景的图片全堆在训练集或验证集里。这个划分我是用Python脚本完成的import os import random import shutil IMG_DIR datasets/images LABEL_DIR datasets/labels TRAIN_RATIO 0.8 SEED 42 random.seed(SEED) images [f for f in os.listdir(IMG_DIR) if f.endswith((.jpg, .jpeg, .png))] random.shuffle(images) split_idx int(len(images) * TRAIN_RATIO) train_imgs images[:split_idx] val_imgs images[split_idx:] for split, imgs in [(train, train_imgs), (val, val_imgs)]: os.makedirs(fdatasets/images/{split}, exist_okTrue) os.makedirs(fdatasets/labels/{split}, exist_okTrue) for img_name in imgs: shutil.move(os.path.join(IMG_DIR, img_name), os.path.join(fdatasets/images/{split}, img_name)) label_name img_name.rsplit(., 1)[0] .txt if os.path.exists(os.path.join(LABEL_DIR, label_name)): shutil.move(os.path.join(LABEL_DIR, label_name), os.path.join(fdatasets/labels/{split}, label_name))这个脚本会把数据集移动到images/train/、images/val/、labels/train/、labels/val/四个目录。3.4 数据增强数据量不够又不想去补拍的时候数据增强是有效手段。YOLOv8自带了一批增强策略如随机翻转、缩放、色域变化等训练时默认开启了一部分因此不用手动预处理太多。如果你的场景有特殊需求比如产品检测需要识别特定角度的零件可以在训练前自己用OpenCV生成一批旋转、加噪声的图片但注意增强后的图片标签文件也需要相应变换否则标注就错位了。我一开始直接对图片做旋转然后沿用原标注结果训练loss一直降不下去排查半天才发现是标签和图像内容对不上。4. 模型训练YOLOv8全流程实操这一段是整套流程的核心从训练命令到参数解析再到评估指标怎么看一次讲清楚。4.1 训练前的准备在PC上安装ultralytics库pip install ultralytics确认安装版本如果网络不好建议指定版本号安装比如pip install ultralytics8.3.x避免每次拉最新版带来的API变动。训练之前先跑一个验证命令确认环境没问题yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg能输出检测结果就说明环境正常。4.2 训练命令与参数解析训练命令如下yolo detect train datadatasets/data.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0这里device0是使用第一张GPU如果没有GPU就换成devicecpu。参数含义modelyolov8n.pt加载预训练权重官方预训练模型是在COCO数据集上训练的迁移到自己的小数据集能加速收敛。epochs100训练轮数。数据量小的情况下100轮足够过大容易过拟合。imgsz640输入图片分辨率。YOLOv8默认640想加快训练可以改成320但精度会下降。batch16单批次图片数量。显存不够就调低我的GPU是8GB显存16没问题4GB显存建议8。patience20早停机制验证集指标连续20轮不提升就自动停止训练。训练过程中终端会实时显示每一轮的loss、精度、召回率、mAP等指标同时runs/detect/train/目录下会生成训练曲线图、混淆矩阵等文件。4.3 训练监控与结果评估训练完成后重点看两个文件best.pt和last.pt。best.pt是验证集上表现最好的权重部署时用这个。评估指标方面核心看这几个mAP50IoU阈值为0.5时的平均精度均值数值越接近1越好。mAP50-95多个IoU阈值从0.5到0.95步长0.05的平均精度比mAP50更严格。precision预测为正样本中真正正确比例越高说明误检越少。recall实际正样本中被找出来比例越高说明漏检越少。我这次训练的结果mAP50大约在0.93左右mAP50-95大约0.72对于一个小数据集和三分类的识别任务来说这个效果已经够用了。如果想看更细致的可视化结果VScode远程开发模式下图表还可以在终端中用tensorboard或ultralytics自带的训练结果曲线查看。4.4 训练过程中的参数调优我记得训练过程中前几十轮loss下降明显后面开始平缓。如果loss不降原因大概率出在数据集上标注错误、类别不平衡、图片分辨率过低。我第二次训练时因为标注工具导出时误用了Pascal VOC格式YOLO训练直接乱套loss反复横跳。这种低级错误检查起来很费时间建议训练前手动抽查几张图片和对应txt文件的坐标是否在合理范围。类别不平衡的明显特征是某个类的recall远低于其他类。解决思路是增加该类样本、对少数类做过采样、或者使用class_weight参数。5. 模型导出与树莓派部署跑起来才算数训练完模型不是终点部署在树莓派上能实时跑起来才是目标。5.1 导出ONNX格式PyTorch训练出的模型是best.pt里面包含的是PyTorch的权重结构树莓派上也能直接加载推理但速度不理想。更好的方案是先导出为ONNX格式再用ONNX Runtime推理速度会明显提升。导出命令yolo export modelruns/detect/train/weights/best.pt formatonnx opset12 imgsz640导出后同目录会生成best.onnx。这里有几个注意点opset12是兼容性较好的默认值ONNX Runtime在不同设备上都能解析。导出时会要求安装onnx和onnxslim直接pip install即可。导出成功的标志是终端里打印出模型摘要并提示ONNX文件保存位置。如果想进一步极限压缩可以导出为NCNN格式。但树莓派上跑NCNN需要额外编译流程比ONNX Runtime麻烦除非对性能非常敏感否则先用ONNX就够了。5.2 树莓派端环境准备把best.onnx、data.yaml、推理脚本通过scp拷贝到树莓派。在树莓派的虚拟环境里安装pip install onnxruntime opencv-python numpyonnxruntime在ARM64平台上有官方预编译包直接pip安装就行。安装完成后可以用一行代码验证ONNX模型能否正常加载python -c import onnxruntime as ort; ort.InferenceSession(best.onnx)如果不报错说明模型格式兼容可以进入下一步。5.3 图片推理脚本实现下面这个脚本是核心推理逻辑我加了详细的注释import cv2 import numpy as np import onnxruntime as ort import time CLASSES [apple, banana, orange] CONF_THRESHOLD 0.5 IOU_THRESHOLD 0.45 INPUT_SIZE 640 session ort.InferenceSession(best.onnx) def letterbox(img, new_size(640, 640)): h, w img.shape[:2] scale min(new_size[0] / h, new_size[1] / w) nw, nh int(w * scale), int(h * scale) resized cv2.resize(img, (nw, nh), interpolationcv2.INTER_LINEAR) canvas np.full((new_size[1], new_size[0], 3), 114, dtypenp.uint8) x_off, y_off (new_size[0] - nw) // 2, (new_size[1] - nh) // 2 canvas[y_off:y_off nh, x_off:x_off nw] resized return canvas, scale, x_off, y_off def detect(img_path): img0 cv2.imread(img_path) img, scale, x_off, y_off letterbox(img0) blob img[:, :, ::-1].transpose(2, 0, 1).astype(np.float32) / 255.0 blob np.expand_dims(blob, axis0) input_name session.get_inputs()[0].name outputs session.run(None, {input_name: blob})[0][0] boxes, scores, class_ids [], [], [] for pred in outputs: pred np.array(pred) cls_id int(pred[5:].argmax()) score float(pred[5 cls_id]) if score CONF_THRESHOLD: continue cx, cy, w, h pred[:4] x1 (cx - w / 2 - x_off) / scale y1 (cy - h / 2 - y_off) / scale x2 (cx w / 2 - x_off) / scale y2 (cy h / 2 - y_off) / scale boxes.append([x1, y1, x2, y2]) scores.append(score) class_ids.append(cls_id) indices cv2.dnn.NMSBoxesBatched(boxes, scores, class_ids, CONF_THRESHOLD, IOU_THRESHOLD) for i in indices: i i[0] if isinstance(i, (list, tuple)) else i x1, y1, x2, y2 map(int, boxes[i]) label f{CLASSES[class_ids[i]]} {scores[i]:.2f} cv2.rectangle(img0, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img0, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) return img0 if __name__ __main__: start time.time() result detect(test.jpg) print(fInference time: {(time.time() - start) * 1000:.2f} ms) cv2.imwrite(result.jpg, result)5.4 USB摄像头实时检测在图片推理跑通后我接上了USB摄像头做实时检测。注意树莓派5的USB摄像头默认识别为/dev/video0。OpenCV调用摄像头的代码如下cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: ret, frame cap.read() if not ret: break result detect_frame(frame) fps cap.get(cv2.CAP_PROP_FPS) cv2.putText(result, fFPS: {fps:.1f}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow(Detection, result) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()实际操作时有几个注意点树莓派的桌面环境下显示OpenCV窗口需要在带桌面的Ubuntu里运行。如果通过SSH纯命令行无法直接弹出窗口需要把图像保存下来再查看。摄像头权限如果cv2.VideoCapture(0)打不开检查当前用户是否在video组里不在的话执行sudo usermod -aG video $USER后重启。实时推理FPS很重要。树莓派5纯CPU跑YOLOv8n-ONNX640分辨率下大概能达到4-6 FPS如果卡顿得厉害把检测输入分辨率降到320或者使用NCNN优化会有明显改善。5.5 在VScode里调试整个流程树莓派上跑推理脚本时我是在VScode的远程窗口里完成的。VScode的Python调试器非常有用可以打上断点查看outputs原始shape、scores分布、以及NMS结果比盲写脚本调参高效得多。值得一提的细节VScode远程开发时直接在终端里跑python detect.py和在调试模式里跑用的解释器必须一致。如果你在VScode里选择了系统Python但终端里激活的是venv两边解释器不同会有一堆“ModuleNotFoundError”。解决办法是在VScode底部的Python解释器选到venv路径或者在settings.json里指定{ python.defaultInterpreterPath: /home/用户名/venvs/ai_env/bin/python }6. 常见问题与排查技巧实录这部分记录我在实操中遇到的高频问题整理成表格方便后续排查。问题现象可能原因解决办法VScode远程连接不上树莓派SSH服务未开启 / IP地址变化开启ssh服务固定静态IP确认同一局域网树莓派pip安装速度慢默认源在境外切换为国内常用pip镜像源pip install torch报错/找不到匹配版本下载了x86_64的包而非aarch64指定CPU版--index-url https://download.pytorch.org/whl/cpuonnxruntime安装失败ARM64下选错了包确认用pip install onnxruntime官方有aarch64 wheelcv2.VideoCapture(0)返回False用户没有video设备权限将用户加入video组并重启推理结果框位置偏移没有做letterbox反算坐标直接映射回原图推理后坐标减去padding并除以缩放比例mAP一直很低标注格式不对 / 标签类别索引错位抽检txt标注核对class_id与类别名对应关系树莓派推理太慢模型太大 / 输入分辨率高换轻量模型如YOLOv5n、降低imgsz、转换为NCNN内存不足训练过程被杀数据一次性加载太多调小batch扩大swap分区6.1 定位坐标反算错误我第一次在树莓派上跑通推理时检测框位置完全错乱。排查后发现问题是这样的输入到模型的图片经过了letterbox处理也就是把原始图等比缩放后填充到640x640的画布里。但我把模型输出的归一化坐标直接乘上原图尺寸映射回去没去掉padding、没除以缩放比例坐标自然偏了。解决方式就是上面代码里的反算公式x1 (cx - w / 2 - x_off) / scale y1 (cy - h / 2 - y_off) / scale这类问题光靠肉眼调试很难发现建议在调试模式下把预测框输出打到图片上看效果确认偏差方向再反推公式。6.2 环境一致性是最大陷阱反复出现的一个重要问题就是环境不一致。树莓派上的Python虚拟环境、系统Python、VScode选中的解释器如果各是各的就会出现“终端能跑但VScode报错”或相反的情况。建议从始至终固定一个虚拟环境所有依赖都安装在虚拟环境内不要在系统Python里乱装包。另外树莓派上如果同时装了系统版的OpenCV和虚拟环境的OpenCV版本不同可能互相干扰。我遇到过cv2.imshow在虚拟环境里报错但系统Python里能正常打开的情况后来发现是OpenCV依赖的GTK库版本不一致导致。解决方案是不要装多个OpenCV虚拟环境里装的版本和系统版本统一。6.3 swap分区设置训练或处理大批量数据时树莓派8GB内存也可能不够用。当终端抛出Killed字样时大概率是OOM。临时方案是扩大swapsudo nano /etc/dphys-swapfile # 把 CONF_SWAPSIZE 改大例如 2048 sudo systemctl restart dphys-swapfile但注意swap是SD卡或固态硬盘上的空间频繁读写会降低寿命部署推理阶段建议关闭swap或保持默认。6.4 树莓派开机自启检测脚本最后分享一个小技巧让检测脚本开机自动运行。我把推理脚本做成了systemd服务sudo nano /etc/systemd/system/detector.service内容[Unit] DescriptionYOLO Detector Afternetwork.target [Service] User你的用户名 WorkingDirectory/home/你的用户名/yolo_project ExecStart/home/你的用户名/venvs/ai_env/bin/python /home/你的用户名/yolo_project/detect.py Restartalways [Install] WantedBymulti-user.target然后sudo systemctl enable detector sudo systemctl start detector这样树莓派一开机目标检测程序就会自动运行配合VScode查看日志整个部署体验会顺畅很多。最终我是把它接在一个项目里把检测结果写入本地日志和图片目录定时回传满足了实际应用需求。这套方案从VScode远程开发、模型训练到树莓派5上的Ubuntu 24.04推理运行整条链路已经验证稳定。后续如果还想扩展可以做多路摄像头并发检测、接入mqtt上报结果、或者用TensorRT Lite进一步加速。先把手上的流程跑起来后续优化就有了基准。
返回列表