当前位置:首页>排行榜>品牌活动 | 工学院学生第三党支部带你"一电就通"第五期--YOLO目标检测:从训练到K230部署

品牌活动 | 工学院学生第三党支部带你"一电就通"第五期--YOLO目标检测:从训练到K230部署

  • 更新时间 2026-10-02 09:40:30
品牌活动 | 工学院学生第三党支部带你"一电就通"第五期--YOLO目标检测:从训练到K230部署

工学院学生第三党支部

"一电就通"第五期

YOLO目标检测

从训练到K230部署

大家好,我是工学院学生第三党支部的入党积极分子陈健聪。这里是"一电就通"科普分享,我们将聚焦专业领域实用知识,用通俗的方式带大家解锁新技能,助力大家在学习路上少走弯路、轻松进步。

本期给大家介绍 YOLO目标检测模型的训练与部署全流程,以一个真实的「钢珠检测」小项目为例,从数据标注到训练,再到把模型装进K230开发板,一步步带你做出自己的"AI视觉作品"。

一、引言:YOLO 是什么?

想象一下,你给朋友发一张水果摊的照片,朋友一眼就能告诉你"这儿有3个苹果、2根香蕉"。这个"看一眼就全知道"的本事,放到计算机上,就是目标检测(Object Detection)要做的事:找出图里有哪些物体、分别在哪个位置、是什么类别。

本期我们不聊水果,聊一个更"硬核"的小目标——钢珠(ball):让摄像头盯着画面,实时找到钢珠的位置,并把坐标发出去。这正是一个完整的边缘AI项目,也是后面要一步步带你做出来的东西。

YOLO的全称是 You Only Look Once,直译过来就是"你只需要看一眼"。这个名字精准点出了它的核心思路:传统的目标检测常走"两阶段"路线——先费劲找出一堆候选框,再一个个去判断框里是什么;而YOLO把这件事一步到位,让图像只经过一次前向推理,就直接输出"框在哪里 + 是什么物体 + 置信度有多少"。

你可以把它理解成:别人是"先翻目录、再逐页找答案",YOLO是"扫一眼整页,直接圈出答案"——所以它又快又适合实时场景。

目前YOLO已经发展出多个版本,主流的有 YOLOv5、YOLOv8、YOLO11、YOLO26 等(其中YOLOv8及之后都由ultralytics团队维护,一套代码就能完成训练、验证、预测和导出)。其中 v8 / v11在K230上都可用,本文以v11的轻量版YOLO11n(nano,320×320输入)为例——"n"代表nano,是家族里的"迷你版",参数少、跑得快,特别适合塞进嵌入式小设备里。

那么问题来了:一个能"看图找钢珠"的模型,是怎么从零"养"出来的呢?接下来我们分几步走:选路线 → 备数据 → 训模型 → 部署落地。

二、开工前的选择:两条路线

在动手之前,先想清楚一件事:你的电脑有没有一块像样的NVIDIA GPU? 这个答案会决定你走哪条路。训练YOLO是"吃显卡"的活,没显卡也能跑,只是慢到怀疑人生。好在现在有两条路可选:

▪ 路线 A:在线平台训练——用浏览器在云端训练,零环境、不占本地算力,直接产出 K230 能用的 kmodel;

▪ 路线 B:本地训练全流程——在自己的电脑上跑完"数据 → 训练 → 转换"全套,可控性强、适合反复调参。

⚠️ 小贴士:无论哪条路线,最终的目标都一样——得到一个在 K230 上能跑的量化模型 yolo11n_det_320.kmodel。路线 A 把"训练+转换"都包在云端,路线 B 则要自己一步步走。下面几节按路线 B(本地全流程)详细展开,这也是最能讲清原理、最能让你"知其所以然"的走法。

三、数据准备与标注

模型不是天生的"看图高手",它是靠大量带答案的图片训练出来的。这个过程就像教小孩认钢珠:你指着一张图说"这是钢珠",指的次数多了,小孩就记住了。给模型"指图认物"的这一步,就叫数据标注。

本期项目的数据集是约300张钢珠照片(文件名photo_xxxx命名),分成训练集(train)和验证集(val)两部分。

建好数据集的"家"

YOLO训练有一套固定的目录结构(YOLO格式),建议照下面这样整理:

my_dataset/

├── images/ # 图片:train/(训练)和 val/(验证)两个子目录

│   ├── train/

│   └── val/

├── labels/ # 标注:每个图对应一个同名 .txt 文件

│   ├── train/

│   └── val/

└── data.yaml        # 数据集的"总清单"

其中 labels 里的每个 .txt 记录了这张图里每个钢珠的类别编号和坐标,它与 images 里的图片一一对应。

写一份 data.yaml"总清单"

data.yaml 是训练时的"地图",它告诉程序:数据在哪、训练集/验证集在哪、有几类物体。钢珠项目只有一类,示例如下:

path: ./my_dataset       # 数据集根目录

train: images/train

val: images/val

names:

 0: ball               # 钢珠(单类)

⚠️ 小贴士:names 里的类别顺序必须与标注时一致,而且后面部署到 K230 时,板子上的 labels 列表也要按这个顺序来写(这里就是 ["ball"]),否则就会"张冠李戴"。

四、模型训练

数据备好了,接下来就是让模型"刷题"。这里我们用 ultralytics 框架(配套PyTorch环境)来训练,它把复杂的训练过程打包成了简单命令。

一条命令启动训练

本地训练命令(教程原文):

yolo detect train data=my_dataset/data.yaml model=yolo11n.pt epochs=200 imgsz=320 batch=16 device=0

如果用脚本(train.py)方式训练,有几个Windows实用要点值得注意:

如果训练中途被打断,别慌,可以从最后一个断点接着训(断点续训),不用从头再来:

yolo train resume model=path/to/last.pt

训练产物是什么?

训练跑完后,程序会在 runs/detect/my_detection/ 目录下留下"战利品":

▪ best.pt:在验证集上指标最好的那一版权重——部署就用它;

▪ last.pt:最后一个 epoch 的权重——主要用于断点续训;

▪ results.png / results.csv:训练曲线与指标数据(损失下降、指标上升);

▪ PR_curve.png:PR 曲线;

▪ val_batch*_pred.jpg:验证集的预测效果图(图上直接画出框,一眼能看出对不对,很适合当配图);

▪ train_batch0.jpg:第一轮训练输入的样本可视化。

这些指标是什么意思?

训练日志里会蹦出一串指标:P、R、mAP50、mAP50-95…… 别被它们吓到,用"看病"打个比方就懂了:

其中 IoU 要单独解释一下:它就是预测框和真实框"重叠程度"的度量——完全重合是1,完全不沾边是0。

▪ mAP50 只要求框和真实框的 IoU 达到 0.5 就算对,门槛低、分数通常好看;

▪ mAP50-95 则把 IoU 从 0.5 一路调到 0.95(步长 0.05)逐档算一遍再取平均,既考"找到没有"、又考"框准没有",是更硬核的指标。

那训练到什么样算"练好了"?教程给出几条经验判断:mAP@0.5 大于 0.80 算好、低于 0.50 算差;box_loss(框的损失)稳定下降;训练集与验证集的损失曲线接近(没有明显过拟合);本地训练可打开 val_batch*_pred.jpg 看验证集预测效果,在线平台则看训练报告里的验证效果图——钢珠都被框对,基本就能判断模型够不够用了。

五、部署到 K230

模型在电脑上跑得好不算本事,真正有意思的是让它在一张小小的开发板上实时运行。这一步,我们把它部署到 K230 上。

为什么选 K230?

K230 是嘉楠科技推出的一款 RISC-V架构AI芯片,内部集成了一块专门的 KPU(AI推理单元),专为端侧视觉场景设计,功耗低、算力却够用,特别适合"摄像头 + AI"的边缘设备。

本期使用的开发板是 立创·庐山派CanMV-K230:它把K230做成了开发板,板载CSI2摄像头(sensor id=2)和一块800×480的LCD屏,刷上 CanMV 固件(K230的MicroPython移植版)后,用简洁的MicroPython代码就能调用AI推理,不用去啃复杂的底层驱动。

模型转换:给模型"换套衣服"

电脑上训练出的 best.pt 是给PyTorch用的,K230的KPU不认这个格式。所以我们要走一条转换链路:

best.pt → ONNX → kmodel(nncase + 量化)

第一步,用ultralytics导出ONNX:

yolo export model=runs/detect/my_detection/weights/best.pt format=onnx imgsz=320 simplify=True

⚠️ 不要加 `nms=True`!K230 板端会自己做后处理(NMS),如果导出时把 NMS 也固化进 ONNX,上板后反而会出错。

第二步,用嘉楠的 nncase 工具把ONNX转成K230能跑的 kmodel。转换关键配置如下:

▪ 版本:nncase==2.9.0 + nncase-kpu==2.9.0(注意 Python 3.8~3.10 环境;Windows 下 nncase-kpu 从 GitHub Releases 下载 whl,还需要 .NET 7.0 桌面运行时,可能还要补一个 libomp140.x86_64.dll);

▪ CompileOptions(编译选项):target="k230",preprocess=True、input_type="uint8"、input_shape=[1,3,320,320]、input_layout="NCHW"、mean [0,0,0]、std [255,255,255];

▪ PTQTensorOptions(量化选项):calibrate_method="Kld"、quant_type="uint8",校准图用 20~50 张真实场景图;

▪ 产物:best.kmodel + labels.txt(每行一个类名,这里就是 ball)。

量化的本质:把32位浮点权重压缩成8位整数,模型变小、变快,代价是精度略有损失——就像把高清照片压成小尺寸,占地方少了,细节也略打折扣。所以校准图一定要用真实场景图,量化才"压得准"。

上板跑起来:main.py 代码骨架

模型转好后,把 yolo11n_det_320.kmodel 和 labels.txt 拷到板子的 /sdcard/examples/kmodel/ 目录(用CanMV IDE拖拽,或命令行 mpremote cp),就能在板子上推理了。

下面是本项目的板端程序 main.py 的核心骨架——它做的事比"画个框"更进一步:

from libs.YOLO import YOLOv8          # 官方 YOLOv8 类,兼容 v8/v11 检测模型

from libs.PipeLine import PipeLine, ScopedTiming

from machine import UART

MODEL_PATH = "/sdcard/yolo11n_det_320.kmodel"

LABELS = ["ball"]                     # 顺序必须与训练 data.yaml 的 names 一致

MODEL_INPUT_SIZE = [320, 320]

RGB888P_SIZE = [640, 360]

SENSOR_ID = 2

DISPLAY_MODE = "lcd"

1) 初始化摄像头管线(video 模式;真实代码为 pl.create(sensor_id=SENSOR_ID, ...))

pl = PipeLine(rgb888p_size=RGB888P_SIZE, display_mode=DISPLAY_MODE)

pl.create(sensor_id=SENSOR_ID)

2) 用 YOLOv8 类加载 yolo11n kmodel(官方 YOLOv8 类兼容 v8/v11 检测模型)

yolo = YOLOv8(task_type="detect", mode="video",

             kmodel_path=MODEL_PATH, labels=LABELS,

             rgb888p_size=RGB888P_SIZE, model_input_size=MODEL_INPUT_SIZE,

             conf_thresh=0.5, nms_thresh=0.45, max_boxes_num=50, debug_mode=0)

yolo.config_preprocess()

uart = UART(UART.UART2, baudrate=115200)  # 用于把坐标发给下游 MCU

while True:

   with ScopedTiming("total", 1):

       img = pl.get_frame()          # 从摄像头取一帧

       res = yolo.run(img)           # KPU 推理,返回检测框列表

       # 3) 只保留离画面中心最近的钢珠,得到其中心坐标 (cx, cy)

       #    (遍历 res 中各框,计算框中心到画面中心 (320,180) 的距离,取最小者)

       # 4) 画框到 LCD,并显示坐标(K230 不支持 f-string,用 % 格式化)

       yolo.draw_result(res, pl.osd_img)

       # 在 OSD 上打印 "x=xx y=yy"(用 % 格式化,而非 f-string)

       # 5) UART 发送坐标与状态:帧头 55 53 + x + y + state

       #    x/y 范围 0~640 / 0~360;state=1 有钢珠、state=0 无钢珠

       pl.show_image()               # 刷新显示到 LCD

⚠️这里藏着一个双芯协作的亮点:K230 负责"看"——摄像头 + KPU 推理,得出钢珠的坐标;坐标再通过 UART(帧头 `55 53`)发给下游的 MCU(比如 STM32),由 MCU 去"动"——控制舵机、机械臂抓取钢珠。一块芯片负责视觉智能,一块芯片负责实时控制,各司其职,这就是嵌入式 AI 项目里最常见的"双芯"分工。

性能实测:到底能跑多快?

部署落地的核心指标就是帧率——一秒能处理多少帧。教程给出的实测数据(测试条件:K230板载CSI2摄像头 + LCD 800×480):

(注:以上为教程实测数据)可以看到,320输入明显更快——这也是本期模型统一用320的原因。想要更快,就用320输入 + n模型 + 让 rgb888p_size 等于 model_input_size;想要更准,才考虑640输入或换s模型。

常见坑(避坑指南)

下面是教程第7节整理的真实踩坑清单,几乎每个新手都会碰到其中一两条:

六、结语

从数据标注到训练调参,再到把模型塞进一张K230小板子里实时跑起来——这一整套流程走下来,你会发现所谓"AI视觉"并不遥远:它不过是"好教材(数据)+ 勤刷题(训练)+ 巧落地(部署)"三件事的叠加。

而当我们让K230通过一根UART线,把钢珠的坐标实时交给下游MCU的那一刻,就已经摸到了端侧AI与嵌入式系统协作的门槛——一块芯片负责"看",一块芯片负责"动",这正是一个完整的智能硬件项目该有的样子。

YOLO的一步到位,让我们看到了"效率"的优雅;K230的小身板,则让我们看到"算力"也可以离我们这么近。作为电子信息、通信、人工智能相关专业的学生,我们既是这些技术的学习者,也完全可以成为把它们亲手做出来的人——你写下的每一条命令、标注的每一个框,最终都会变成机器"看懂"世界的那双眼睛。

"一电就通" 也会持续分享更多电子、通信、AI类的实用干货,与大家一起精进专业本领。如果你也想亲手跑通自己的目标检测模型,不妨就从这一篇开始动手试试吧!

立足专业办实事

科普服务暖校园

工学院学生第三党支部

“一电就通”来稿请投:

linzhiqing_0910@qq.com

文稿丨

排版丨

初审丨

复审丨

审核丨

陈健聪

张驰斌

曹仕杰

黄荣琴 曾琦

唐玉婷

随机文章