ARTICLE DETAIL

资讯详情

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

K230端侧目标检测全流程实战:从本地训练到AI_Cube部署

K230端侧目标检测全流程实战:从本地训练到AI_Cube部署 1. 为什么要自己跑一遍K230目标检测全流程前段时间我一直在折腾K230这块开发板想把手边一个小项目做成端侧实时目标检测。K230在圈子里讨论度不低尤其是那个“激光打蚊子”的演示靠摄像头实时识别蚊子轨迹再驱动激光击落很多人看完第一反应是“这玩意实时性能可以啊”。能把目标检测做到这种低延迟背后其实是一整套本地训练与部署流程的协作单纯把别人训练好的模型拿来用很难适配自己的场景。我这次的任务很简单做一个能识别桌面物体的检测器目标包括水杯、遥控器、手机、插线板这四类。一开始我确实想着找个现成模型挂上去跑一跑结果发现场景不匹配通用模型在固定视角下误检率很高。于是老老实实走了一遍“采集数据——标注——本地训练——模型转换——板端部署”的完整链路。整个流程跑下来最大的感触是K230的部署工具链AI_Cube并没有网上说的那么“难用”真正消耗时间的反而是数据准备和训练参数调优。打开AI_Cube时它能做什么一句话说清楚它是把PyTorch、ONNX这些框架训练出的模型转换成K230上KPU可执行的kmodel格式同时提供量化、仿真、性能分析和板端部署辅助的一整套工具链。也就是说训练还是在你自己的电脑上完成AI_Cube负责“翻译”和“压缩”模型让它能在K230这种低成本、低功耗的边缘设备上高效跑起来。为什么我强调“本地训练”这件事因为很多K230教程默认你是从MarvelMind、Open Lab等平台拉现成模型或者用在线训练平台。但实际做产品原型数据往往不出本地尤其是摄像头采集的现场数据传云端难免有隐私顾虑而且每改一次标注就要重新训练走在线流程来回传文件特别浪费时间。本地训练就是自己电脑上建好Python环境数据、训练、验证、导出全流程本地完成AI_Cube也只是本机跑的一个工具。这个模式下迭代速度会快很多改一版标注或者调一次学习率几分钟就能看到结果。适合看这篇内容的主要是手里有K230开发板、想跑通自己目标检测模型的同学不需要你有特别深厚的算法背景但至少要学会基本的Python操作能看懂命令行。我会把从环境搭建到模型上板的完整过程拆开讲中间穿插我在实际操作里遇到的问题和解决方式。2. 搭建本地训练环境从零到能跑通Hello World2.1 硬件准备K230开发板、PC和摄像头先说硬件K230开发板本身不算贵常见的有CanMV K230套件板载摄像头和屏幕接口也可以自己外接USB摄像头。我用的是一块基础版K230开发板外接了一个OV5647摄像头模组PC是普通Windows笔记本不过后面装的训练工具链我建议在Ubuntu环境里跑我是在Win10上用虚拟机装的Ubuntu 20.048G内存跑起来稍紧张但够用。说到PC配置其实训练目标检测模型不需要很夸张的独立显卡我用的是一块GTX 1660 Super的机器显存6G训练YOLOv8n这类小模型完全没问题。想要更轻也可以直接用CPU训练但时间会拉长小数据集几百张图能忍上千张贴图就难受了。如果你的数据集比较大建议至少弄一块8G显存的独立显卡或者用云GPU临时训练再把权重文件拉回本地转换。开发板和PC之间通过USB线连接K230会虚拟出一个网卡设备默认IP是192.168.1.10可以通过SSH进入板子。这块后面部署时会用到环境搭建阶段先确认连接正常。2.2 软件环境Python虚拟环境与AI_Cube安装软件这块是大多数人的第一道坎。AI_Cube工具链官方支持Linux环境我建议按这个顺序准备装好Ubuntu 20.04系统虚拟机或双系统均可更新源安装Python 3.8以上版本我用的3.8.10兼容性比较好创建独立虚拟环境避免和系统Python包冲突安装PyTorch、torchvision、onnx、onnxruntime等基础库下载AI_Cube工具链解压后按官方文档安装依赖验证工具链里自带的模型转换demo用官方示例模型跑通一次转换。这里特别提醒一句虚拟环境一定要建好。我一开始图省事直接用系统Python装结果和系统自带的numpy版本冲突导致AI_Cube的量化工具怎么都报错。后来把所有依赖都挪到conda虚拟环境里问题立刻消失。工具链这类依赖多的软件干净环境永远比硬怼省时间。AI_Cube工具链解压后目录结构大致是这样的convert目录存放模型转换相关脚本quantize目录是量化工具evaluate目录有精度仿真工具docs目录是文档里面有很详细的参数说明我最开始没看文档直接上手走了些弯路后面会专门讲踩坑。建议拿到工具链后先把官方demo跑通一遍对后续理解会很有帮助。2.3 板端环境确认板子这头也要确认两件事一是烧录的固件版本二是CanMV环境是否可用。K230的基本用法是通过MicroPython脚本控制摄像头、GPIO和KPU也可以在Linux环境下用C/C开发看你的项目需求。我用的是CanMV固件主要是开发速度快调用摄像头直接几行代码搞定。连上板子后用CanMV IDE确认板端能正常识别摄像头画面并且能执行最简单的AI模型加载脚本。这一步先确保硬件没有坏、固件能跑再进入下一步数据准备。3. 数据集准备标注工具选型和格式转换3.1 数据采集用开发板自己拍这次我没有下载公共数据集因为识别对象是固定场景里的特定物品公共数据集的图片分布和实际视角差异太大。采集方法最直接用K230开发板接上摄像头找个固定角度把物品逐一放到桌面上用MicroPython脚本每隔0.2秒保存一帧画面。一共采集了大约800张图片涵盖不同光照、不同摆放角度。采集的时候有一个细节尽量不要在完全固定的背景里只变化物品位置这样训练出来的模型会对背景过拟合。我把桌面上的杂物随机调整有时放一本笔记本有时放几支笔模拟真实使用场景的差异。数据越接近真实场景后面模型部署的效果就越好。我采集了1000多帧原始图片然后简单过滤掉模糊和重复度高的最终留下826张有效图片。这批数据规模不大但对于四类物品的识别来说已经够用了关键是要保证每个类别在各个角度、远近都有覆盖。3.2 标注工具与标签格式标注工具我用的LabelImg虽然界面朴素但胜在轻量稳定输出PASCAL VOC格式的XML文件也能直接导出YOLO格式的TXT文件。四类目标分别是cup、remote、phone、plug标注时每个目标画一个矩形框。标注过程比较枯燥826张图画了大概四个小时我的经验是分几次完成每次画一两百张避免疲劳后框选质量下降。质量差的标注会产生大量难样本直接影响训练效果。LabelImg默认输出的是XML格式VOC但我训练用的是YOLO格式每个图片对应一个TXT文件每行是类别索引 中心点x 中心点y 框宽 框高坐标值为0到1之间的小数。所以标注完需要做一次格式转换。转换脚本不长核心逻辑就是把XML里的绝对坐标换算成归一化的相对坐标import os import xml.etree.ElementTree as ET def convert_voc_to_yolo(xml_path, classes): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) return linesclasses列表固定为[cup, remote, phone, plug]转换后检查一下生成的TXT文件确认坐标值都在0到1之间没有越界。3.3 数据集划分与增强826张图按8比2随机划分训练集661张验证集165张。划分后我检查了一遍验证集确保四个类别都有覆盖避免验证集里某个类别一张都没有那样验证mAP会失真。数据增强我是靠训练框架自带的策略没有自己做离线增强。YOLOv8训练时会自动做马赛克增强、随机翻转、缩放、色域变换这些操作对小数据集来说已经足够了。如果你用的是自己写的训练脚本那可能需要额外加一些增强但用成熟的检测框架基本不需要操心这块。还有一个容易忽略的点图片尺寸的一致性。K230的KPU对输入图像尺寸有对齐要求最常见的是640x640也有用320x320做超轻量方案的。我这次统一用640x640输入。在标注转换、训练、模型转换三个阶段都要保持一致否则后面做INT8量化时会出现维度不匹配的问题。4. 训练目标检测模型参数配置与本地训练的关键细节4.1 模型选型YOLOv8n模型结构选的是YOLOv8n——当前Ultralytics YOLOv8系列里最小的一版。为什么不用YOLOv5s或者更大的YOLOv8m因为K230的KPU算力在边缘芯片里算不错的但也不是无限量的模型过大帧率就掉得厉害。YOLOv8n的参数量大约320万权重文件体积6MB左右经过INT8量化后能压缩到2到4MB非常契合“边缘部署 实时检测”这个场景。训练前需要创建一个data.yaml文件内容大概是train: ./datasets/desktop/images/train val: ./datasets/desktop/images/val nc: 4 names: [cup, remote, phone, plug]注意路径用相对路径避免后面迁移工程时出问题。4.2 训练命令与超参设置训练命令如下yolo detect train data./data.yaml modelyolov8n.pt epochs100 imgsz640 batch16 lr00.01 optimizerSGD device0这里几个关键参数我解释一下epochs100小数据集训练100轮足够过多容易过拟合过少模型欠拟合imgsz640输入尺寸和后面模型转换保持一致batch166G显存跑YOLOv8n勉强能承载这个批次如果你显存小减到8或4都行optimizerSGDYOLOv8默认是SGD也可以用AdamW但SGD在检测任务上稳定性更好lr00.01初始学习率YOLOv8自带学习率调度器会随训练过程自动调整。训练过程中可以观察每个epoch的loss输出。YOLOv8训练日志里可以看到box_loss、cls_loss、dfl_loss三个值整体趋势应该是稳步下降。我发现一个现象训练到60轮左右验证集mAP基本就稳定了后面几十轮mAP波动很小说明小数据集上模型收敛比较快。4.3 训练中为什么会“崩”经典问题是训练到一半loss突然变成nan或者mAP直接掉到0.2以下。网上很多人问“目标检测模型微调崩了”多数情况就是学习率设太大。我用YOLO默认的0.01没出问题但如果你的数据集特别小两三百张或者类别数特别少建议把学习率降到0.005甚至0.001。还有个容易被忽略的原因是标注里有非法数据比如某个框的坐标越界、某个类别索引越界训练时读入异常导致loss爆炸。所以训练前一定要做一次数据合法性检查。我这次训练还遇到过一次奇怪的问题同一个数据集第一次训练正常第二次换个随机种子训练就崩了。后来发现是缓存问题YOLO框架会把标签缓存成.cache文件如果中间改过标注文件缓存没有刷新就会读到旧数据甚至错数据。解决方法是训练前删除datasets/desktop/labels/下的缓存文件或者用cacheFalse参数强制不缓存。4.4 训练结果评估训练结束后在runs/detect/train目录下会生成weights/best.pt和weights/last.pt用best.pt做后续转换。同时有个results.png可以看到loss和mAP曲线。我这次的模型在验证集上mAP0.5在0.87左右mAP0.5:0.95在0.71左右。数据量不大这个结果符合预期。如果你的项目对精确率要求高可以考虑把epochs加到150或者换YOLOv8s但模型体积和推理帧率都会受影响需要权衡。5. 模型的导出与AI_Cube转换从PyTorch到kmodel5.1 导出ONNX注意算子版本和输入尺寸训练完成后要先把PyTorch模型导出成ONNX格式AI_Cube才能读取。YOLOv8自带导出命令yolo export model./runs/detect/train/weights/best.pt formatonnx opset11 imgsz640这里有几个容易踩的坑。第一个是opset版本AI_Cube对ONNX算子支持有一定范围opset11兼容性最好导出后如果遇到AI_Cube不支持的算子再考虑换opset。第二个是imgsz必须和训练时保持一致否则输出张量尺寸不对。第三个是YOLOv8导出ONNX时默认输出三个尺度的检测头AI_Cube转换时会对输出做后处理适配这个过程有些版本工具链会自动完成有些需要手动设置输出层数量。导出后先用onnxruntime跑一下推理验证导出的ONNX模型输出尺寸合理。我的模型输出是1x84x8400的形状其中84由4个框坐标80个COCO类别构成而我训练的是4类所以实际是448个值加上坐标。但是YOLOv8导出ONNX时会透传类别数输出应为1x8x8400。这里别忘了检查一下如果导出后还是COCO的80类输出说明导出时没有正确读取nc配置需要手动指定--nc参数或者检查模型结构。5.2 AI_Cube模型转换量化是关键AI_Cube转换流程可以分为四步验证模型、量化校准、生成kmodel、仿真评估。第一步验证模型是检查导出的ONNX能否被工具链正常解析。执行时会有一个解析日志如果里面有Unsupported Op提示说明存在不支持的算子需要回到导出环节调整。我遇到过一次模型里有一个GridSample算子不被AI_Cube支持最终通过重写检测头绕过去了。第二步量化校准这个步骤是硬核中的硬核。K230的KPU主要跑INT8推理所以浮点模型要转成INT8转换过程中会有一个校准环节用一批代表真实数据分布的图片跑一遍浮点模型收集每一层的激活值分布再根据分布计算量化参数。校准图片不需要多我用了80张训练集图片就够了但要求图片内容尽量覆盖所有类别和光照条件。校准集选不好量化后精度掉点会非常明显。量化配置里有一个关键参数:输入图像的均值、标准差、归一化方式。YOLO训练时图像归一化是除以255即像素区间从0到255变成0到1。AI_Cube转换时可能需要配置输入量化参数来保留这个归一化过程如果配置错误模型输出的坐标会整体偏移。这个参数在工具链的配置文件中对应mean和scale字段。第三步生成kmodel生成过程会输出一个.kmodel文件同时在日志里能看到每一层的推理耗时估算。这个日志很有用可以用来发现瓶颈层比如某个卷积层耗时特别长可以考虑换成更小的模型或者调整输入尺寸。第四步仿真评估AI_Cube带了一个仿真器可以在PC上模拟KPU推理验证量化后模型的输出和浮点模型差异有多大。我建议每次量化后都在仿真器里跑一次综合评估对比浮点模型和INT8模型的mAP差值如果掉点超过3个点就需要检查校准集质量或者量化配置。5.3 把kmodel部署到K230板子上生成kmodel后通过SSH把模型文件拷贝到板子同时准备一份MicroPython脚本加载模型并设置摄像头输出。K230加载模型的核心逻辑大概是from media.media import * from libs.PipeLine import PipeLine import os # 初始化管道设置图像尺寸 pipeline PipeLine() pipeline.create(input_width640, input_height640, output_width640, output_height640) pipeline.set_input_data_type(rgb888) # 加载kmodel mobj kpu.model_load(/sdcard/desktop_det.kmodel)重点注意输入图像的尺寸和色彩格式要与模型训练时保持一致。我训练用的是RGB图像归一化到0到1所以板端摄像头取流后也要做同样的预处理否则检测结果会偏差很大。K230的CanMV环境里AI_Cube工具链通常会和固件一起提供对应的Python库直接用就好。6. 实机运行效果与模型瘦身怎么把模型压到5MB级别6.1 性能实测数据kmodel部署到板子上之后我跑了几个场景测试。固定摄像头角度依次把四类物品放到画面里识别速度和准确率都记录了一下。K230上运行640x640输入的YOLOv8n INT8模型实测帧率在30到50帧之间具体数值取决于后处理方式和是否开了多线程。我的代码里对检测结果做了NMS后处理这部分在MicroPython里跑大概是CPU瓶颈帧率掉到35帧左右。如果后处理用C模块实现帧率还能继续往上走。单次推理耗时大约在20到25毫秒左右检测框准确率在4类物品平均置信度0.7以上就算很稳了。板子功耗低、发热也小连续跑一小时摸外壳只是温热这就是边缘设备比电脑有意思的地方。实时性、功耗、体积这些指标在端侧项目里往往比绝对精度更重要。6.2 模型为什么能做到5MB热搜里“macs仅5mb的目标检测模型”看起来很让人羡慕其实原理并不神秘。YOLOv8n的原始PyTorch权重约6MB经过INT8量化后参数用1字节存储体积直接缩到接近1/4自然就是2到3MB的水平。而整个kmodel里除了权重参数还有模型的图结构和后处理信息加起来5MB以内是常态。K230的AI工具链支持权重压缩实际部署文件会进一步缩小。做模型瘦身时我建议从三个层面考虑输入分辨率640x640改到320x320计算量降到原来的四分之一模型文件体积不变但帧率翻倍。代价是小目标识别能力下降。如果你检测对象是杯子、遥控器这类常规物体320x320完全够用INT8量化这一步是K230上部署的决心之选工具链AI_Cube已经帮你做好了关键在校准集质量模型结构选择从YOLOv8n再往下走可以试试更轻量的定制结构比如把Backbone换成MobileNetV3或ShuffleNetV2但需要自己改训练代码和后续的导出适配开发成本相对高。我实际部署时用的就是640x640输入的YOLOv8nkmodel文件大小4.6MB完全塞得进K230的内存。如果你要跑更多路摄像头或者更高帧率换320x320输入是性价比最高的方案。6.3 板端常见问题框体偏移和漏检实机运行中我发现两类问题比较常见检测框偏移和特定角度漏检。框体偏移多半是因为输入图像的预处理与训练时不匹配。比如训练时做了letterbox保持宽高比缩放并填充黑边而板端直接拉伸图片喂给模型坐标映射回原图时就会偏。解决方法是板端也做同样的letterbox预处理或者反过来训练时直接拉伸图两种方式选一种即可。特定角度漏检的根源是训练数据分布不均衡。如果你的数据里某类物品只出现在几个固定角度模型就很难泛化到新角度。这时候不建议盲目增加epochs而是去补拍对应角度的数据把分布补均匀。7. 实操中最容易翻车的三个坑复盘与规避7.1 训练崩溃从loss为nan说起我在前面简单提过loss为nan的坑这里详细复盘一下。第一次训练时我用了一个网上找的公开数据集类别数有20类但没有仔细检查标注文件训练到第13个epoch时loss突然变成nan。查日志发现是某个XML文件里有一个目标的坐标xmin比xmax还大标注框倒置了框架读进去后计算出负的宽高最终导致梯度爆炸。从那次之后我养成了一个习惯训练前写个小脚本扫描所有TXT标签检查坐标是否在0到1区间内、x_center加box_w的一半是否超过1、y坐标同理。这类异常在数据增强阶段会放大如果等训练崩了再回来查浪费的时间足够重新标注好几百张图了。7.2 量化掉点校准集选错直接掉10个点第二个坑发生在AI_Cube量化时。我第一次做INT8量化时图省事用训练集的前80张图做校准结果那些图全是上午拍的光照条件单一。量化后的模型在下午的测试视频里mAP直接从0.87掉到0.73框体位置也抖得厉害。后来我把校准集换成从训练集和验证集里均匀抽样的80张图覆盖白天、晚上、不同角度、不同光线量化后mAP掉点控制在1.5个点以内。所以校准集的代表性一定要重视它等价于模型再次学习真实数据分布的机会。7.3 算子兼容ONNX导出成功不等于AI_Cube能解析这两个工具链之间的“翻译”是有损耗的。ONNX作为一种通用中间格式支持的算子很多但AI_Cube只实现了其中一部分特别是自定义检测头里的一些新算子经常会出现不支持的情况。我在导出YOLOv8n时前几次都提示ONNX导出成功但在AI_Cube验证阶段报Unsupported Op具体是哪一个算子我现在记不太清了只记得当时是因为YOLOv8的输出层里有GridSample结构。解决办法是修改导出代码把检测头输出层单独剥离用标准卷积和重排算子替代那个结构。本质上是把模型结构简化到AI_Cube能理解的范围。遇到这个问题不用慌看日志定位具体算子去网上搜替代实现或者换一个更保守的模型结构都行。8. 本地训练流程的价值与后续扩展方向整套流程跑通之后我对K230这块板子的定位有了更清晰的认识。它不是一个玩具而是一个能把小型视觉AI项目落地的硬件平台。配合AI_Cube工具链从数据准备到板端推理的完整闭环一个人一台电脑就能完成这比想象中要可控得多。后续我会在这个基础上做两件事一是尝试用更小的骨干网络做检测模型往那些“5MB级别模型”的方向再走一步毕竟模型越小帧率越高能跑的场景越广二是把手边的项目从单目标检测扩展到多目标跟踪在同一套工具链下加入跟踪算法实现真正意义上的实时目标追踪系统。这次踩过的坑和积累的调试经验到时候应该都能直接复用。如果你现在正准备入手K230或者已经入手但还在观望怎么训练自己的模型我的建议是别怕折腾硬件连接、环境搭建、数据准备、训练转换每一步都会遇到问题但每一步的解法也都写在文档和社区里。卡住的地方多搜多看对照本文的流程一步步走很快你也能看到自己的模型在板子上实时识别出目标的那一刻。
返回列表