无人机飞一圈,风机叶片上的裂纹、砂眼、蒙皮脱落,在高清镜头下看得清清楚楚——但现场运维人员要的不只是一张照片,而是一句能落地的判断:这个缺陷严不严重,要不要安排人上塔处理,该补胶还是该换片。过去两年我一直在做无人机风机巡检的视觉系统,最早只跑了一个YOLOv8目标检测,后来把DeepSeek接进去做诊断分析,整套系统才算真正能交付给风电场的运维团队。
今天把这条链路拆开讲一遍,从数据采集、标注、模型改进,到DeepSeek API接入、边缘端部署,再到现场踩过的各种坑。无论你是刚入门深度学习目标检测,还是已经在做无人机巡检项目,希望这篇能帮你少走点弯路。
1. 风机表面缺陷检测,为什么不能只靠一个目标检测模型
1.1 传统人工巡检的痛点,决定了必须上无人机视觉
风机叶片是高空旋转部件,常年暴露在风沙、盐雾、雷击和温差环境下,表面会出现前缘腐蚀、裂纹、砂眼、蒙皮鼓包、雷击烧蚀等缺陷。过去主要靠人工吊篮或者蜘蛛人攀爬检查,一个机位少说要半天,而且人在高空能看到的范围和精度都有限,记录全靠拍照和手写,回来还要人工整理缺陷台账。
无人机巡检把这步变成自动化的“数据采集+AI识别”。飞手按航线绕塔身和叶片飞一圈,用高倍变焦镜头拍下叶片正反面,AI模型把疑似缺陷的位置框出来。但这里有个很现实的问题:框出来之后,运维人员并不知道这个缺陷到底要不要修,什么时候修。一个几毫米的微小裂纹和一个已经贯穿的裂口,在检测框里可能看起来差不多,需要的处置方式却完全不同。
1.2 检测与诊断两段式的整体架构
所以我的方案是“检测+诊断”两段式:第一段用改进的YOLOv8做目标检测,输出缺陷框的类别、位置、置信度;第二段把检测结果以结构化JSON喂给DeepSeek大模型,让模型结合缺陷类型、尺寸、位置、叶片编号和历史运维知识,自动生成缺陷诊断报告、严重性分级和维修建议。
这套架构的核心思路,是把“看见问题”和“理解问题”分开。目标检测模型擅长在图像中找到异常区域,但它不理解“雷击损伤后期会导致叶片失速”“前缘腐蚀在翼展方向超阈值就需要灌缝修复”这类领域知识。大模型擅长推理和生成文本,但直接拿原始图像让大模型识别小尺寸缺陷,既费钱又容易漏检。两段式的好处是各司其职,推理成本也低得多。
2. 改进YOLOv8:数据、网络结构与训练调优
2.1 数据采集与标注:LabelMe标注和数据集清洗
做检测模型第一头疼的就是数据。风机缺陷数据集不像COCO那样在网上随便下载,很多风电场的缺陷照片是涉密生产数据,你拿到的往往只是几十张现场照片加一堆维修记录。我最初拿到的原始数据只有426张有效图片,其中包含裂纹的有200多张,砂眼和雷击损伤各不到150张,还有一批没有缺陷的负样本。
标注工具我用的是LabelMe,因为它可以在浏览器里用,支持多人协作,导出的JSON格式也好处理。这里有个关键选择:缺陷是框还是多边形。小裂纹和砂眼用矩形框标注就够了,但叶片轮廓、前缘腐蚀这类区域用多边形标注更准确。我的建议是,如果后续计划升级做实例分割,就统一用多边形标注,一次性把掩码数据也攒下来;如果只做检测,矩形框更快,一个熟练工一天能标300到400个实例。
标注完成后不能直接丢给训练脚本,必须先做清洗和统计。我用一个Python脚本遍历所有JSON,输出每张图的标注数量、框面积占比、类别分布,然后把明显的错误标注揪出来:比如把叶片上的污渍标成裂纹,把塔筒阴影标成缺陷,这种情况在多人标注时经常出现。数据清洗比调模型参数重要得多,我不止一次因为脏数据把模型的mAP拉低了3到5个点。
数据增强方面,除了Ultralytics YOLO自带的Mosaic、RandomAffine,我额外加了两种针对性增强。一种是模糊增强,模拟无人机运动导致的图像模糊,把高斯模糊核大小设为3到7像素随机。另一种是低对比度增强,模拟阴天、逆光和远距离拍摄的条件。这两种增强对我的场景帮助很大,因为现场照片和训练照片的成像质量差距,往往比不同缺陷之间的特征差距还要大。
2.2 网络结构改进:注意力模块和小目标检测头
我在标准YOLOv8s基础上做了三处改进,这也是“改进YOLOv8”的核心内容。
第一,在Backbone的C2f模块后面插入坐标注意力模块。风机叶片细长,缺陷往往出现在狭长形状的区域内,坐标注意力能把水平方向和垂直方向的位置信息编码进注意力权重,比单纯的SE注意力更适合我这个长条目标场景。实际测试下来,插入两层坐标注意力后,mAP50-95大约提升了1.8个点,推理速度只慢了不到9%。
第二,增加一个P2检测头,专门处理小目标。缺陷框普遍小于32×32像素,标准YOLOv8的最小检测头基于P3特征图(8倍下采样),对细小裂纹容易漏检。增加P2头意味着模型要在4倍下采样的特征图上做检测,计算量上去了,但小目标的召回率提升非常明显。我对比过,加了P2头之后,裂纹的召回率从0.74提高到0.85,代价是训练和推理时间都增加了20%左右,但叶片巡检任务对实时性要求没那么极端,这个代价完全能接受。
第三,损失函数从CIoU换成SIoU。标准YOLOv8默认的CIoU收敛已经很稳,但对旋转框不友好。叶片表面缺陷虽然是水平矩形框,但很多裂纹是有角度的,SIoU在计算损失时考虑了预测框与真实框的方向差异,收敛更快,最终mAP也略高。
这里要提醒一句:不是所有改进都是正向的。我试过在Neck里加BiFPN结构,结果mAP没提升,训练时间翻了快一倍,果断放弃。模型结构的选择永远是精度、速度、复杂度的平衡,不要为了改进而改进。
2.3 训练环境:Ubuntu 20.04 CPU能跑,GTX 1660 Ti也能练
训练环境这块,我见过很多新手卡在环境搭建上。照我的经验,最省事的方式是Ubuntu 20.04上直接用Ultralytics官方镜像或pip安装ultralytics包,Python版本3.9到3.11都可以。如果你只有CPU,也能跑通,但速度会让人怀疑人生:CPU上用640×640输入跑一遍验证集,几百张图可能要跑一个多小时。所以纯CPU环境只适合做代码连通性测试,不适合真正训练。
我实际训练用的是GTX 1660 Ti,6GB显存,比上不足比下有余。这套卡跑YOLOv8s,输入分辨率设成960×960,batch size只能开到6到8,混合精度训练开着,显存勉强够用。如果你的卡显存只有4GB,那就把输入分辨率降到640,或者直接用YOLOv8n。别逞强,显存溢出一次就要重跑,浪费的时间比什么都贵。
训练命令很简单,但有几个参数值得注意:
yolo train data=wind_turbine.yaml model=yolov8s.pt epochs=150 imgsz=960 batch=8 amp=True device=0 patience=30 seed=42patience参数是早停,我设30个epoch,如果连续30轮验证集指标不涨就自动停,防止过拟合。amp混合精度一定要开,显存省一半,训练速度快30%以上。我试过不开AMP,同样的epoch数量,loss曲线一直抖得厉害,后来发现不开AMP在小显存卡上反而更容易梯度爆炸。
2.4 训练过程的损失曲线和过拟合排查
训练完第一件事是看runs/detect/val/box_loss.png和cls_loss.png。损失曲线持续下降最后平稳就是正常,如果验证集损失下降到一定程度开始反弹,那就是过拟合。这时候优先增加数据增强,而不是加正则化,因为风机缺陷样本本来就少,你更需要泛化而不是让模型更强地记忆。
第二件事是跑验证集并打印每类的PR曲线,重点看类别之间的mAP差距。我最初训练的模型,砂眼mAP 0.91,裂纹只有0.76,差距太大,原因是裂纹样本里粗细差异太大,细裂纹经常只有2到3像素宽。后来我把细裂纹样本单独挑出来做了两次过采样,又额外标注了120张细裂纹图像,效果立刻好起来。
类别不平衡的问题在缺陷检测里比通用目标检测更严重。我的办法是设置cls_pw为类别权重的平方根,让模型给少数类别更高的分类损失权重。但别加太猛,权重超过2就会导致多数类别的误检增多。
3. DeepSeek接入:从检测框到诊断报告
3.1 DeepSeek API调用方式和模型选择
检测模型输出的是坐标和类别,要变成运维人员能看懂的报告,需要DeepSeek这类大模型来补全“为什么严重”和“怎么处理”。目前DeepSeek的API兼容OpenAI接口格式,我用Python的openai库直接调用,只是把base_url换掉,非常省事。
from openai import OpenAI client = OpenAI( api_key="sk-your-key", base_url="https://api.deepseek.com" ) resp = client.chat.completions.create( model="deepseek-chat", max_tokens=2000, temperature=0.3, messages=[ {"role": "system", "content": "你是风机运维诊断专家,根据缺陷检测结果输出诊断报告。"}, {"role": "user", "content": diagnostic_prompt_text} ] ) print(resp.choices[0].message.content)模型我用的是deepseek-chat,不是deepseek-reasoner。后者是推理增强模型,会先输出长思维链再给结论,适合复杂诊断,但响应时间慢,费用也偏高。我的场景里,缺陷诊断规则相对固定,用普通chat模型加结构化prompt就够。如果遇到那种需要权衡“是否立即停机检修”的紧急缺陷,再手动切到reasoner模式也不迟。
3.2 Prompt设计:给大模型喂什么样的上下文
这是整个DeepSeek集成里最值得打磨的地方。我踩过的坑是:一开始直接喂“风机叶片有裂纹,请分析”,模型回答全是套话,毫无参考价值。后来我改成了高度结构化的JSON上下文,效果立刻不一样。
实际诊断时,我先在Python端把检测结果聚合,只保留置信度大于0.35的检测框,并过滤掉明显重叠的框(用NMS阈值0.5),生成如下格式:
{ "turbine_id": "WT-07", "blade_id": "BL-A2", "surface": "吸力面", "detections": [ {"type": "前缘腐蚀", "bbox": [1245, 320, 1328, 355], "confidence": 0.86, "area_ratio": 0.012, "region": "叶片前缘中段"}, {"type": "雷击烧蚀", "bbox": [2234, 876, 2250, 893], "confidence": 0.92, "area_ratio": 0.001, "region": "叶尖附近"} ], "wind_condition": "6级阵风", "last_maintenance": "2025-03-01" }然后我把这段JSON拼进prompt,让模型输出一个固定模板的诊断报告。我要求模型必须包含四个部分:缺陷现象描述、严重性等级(低/中/高/紧急)、建议维修窗口、具体处置方式。并且明确告诉模型“如果信息不足,必须标注‘无法判断’,不要臆测”。
为什么要这么严格?因为在现场,模型输出是要进入工单系统的,如果格式乱,下游系统没法解析,自动生成的维修任务就会出错。让大模型“自由发挥”的代价,比想象的更大。
3.3 生成报告与维修建议的落地闭环
诊断报告生成后,我让系统自动写入两个地方:一个是数据库的检测记录表,另一个是生成Word巡检报告文档。这里有个细节:大模型偶尔会把叶片编号编造出来,比如我传的是“BL-A2”,它可能回“BL-2A”。这个不是模型不聪明,而是文本生成过程本身就可能出错。所以我在系统里做了二次校验,把报告中的叶片编号、日期、缺陷坐标,都回跟原始JSON比对一遍,不一致就把该字段留空并打回重生成,不允许直接下发。
维修建议的规则,我总结出来最好用的prompt写法,不是问“怎么修”,而是给几个固定选项让模型选。比如“对于前缘腐蚀,可选方案为:A. 打磨补胶修复 B. 注入树脂修复 C. 更换叶片”,模型根据缺陷面积和位置限选一项并给出理由。这样既发挥了模型的推理能力,又不至于生成出工段上根本做不了的方案。
4. 无人机巡检与模型部署:从实验室到风机现场
4.1 巡检航线和图像采集的质量要求
模型训练得再好,无人机拍回来的图不合格,一切白搭。风机巡检的航线规划,核心是“离得够近、拍得够全”。我用的多旋翼无人机带RTK定位,设置好塔基坐标和塔高,规划环绕航线:先在塔身外绕一圈,再飞到轮毂中心高度,对每个叶片逐一从叶根到叶尖拍两遍,正面一遍、背面一遍。
拍摄高度通常控制在30到50米,镜头用30倍光学变焦,确保叶片宽度在画面里占1/3以上。这种情况下,单个缺陷像素尺寸能到50到150像素,检测模型很轻松;如果为了省时间飞太高,叶片宽度只占画面五分之一,缺陷尺寸跌到20像素以下,再强的模型也容易漏。
航线规划还要考虑太阳角度。顺光拍摄,叶片表面细节最清晰;逆光时叶片边缘会出现强烈反光,人眼都看不清,模型更不行。我在航线里固定了“顺光航点优先”,并且要求云台稳定,减少运动模糊。做了这些之后,模型的漏检率直接降了一半,因为输入质量上来了。
4.2 模型轻量化与RK3588边缘端部署
无人机不能背着几十公斤的GPU服务器飞,边缘端才是落地赛道。我测试了两条路线:一条是NVIDIA Jetson Orin系列,部署简单,用TensorRT加速;另一条是瑞芯微RK3588,功耗低、成本低,国内供应链稳定,很多行业无人机吊舱里都有类似SoC。
RK3588部署YOLOv8的流程是:先把PyTorch模型导出为ONNX,再用瑞芯微的rknn-toolkit2转换成RKNN格式,最后做int8量化。这里有个容易踩的坑,就是torch.onnx.export时要把opset设为12,并且输入固定为batch_size=1,否则后面转RKNN会报一堆兼容性错误。
模型量化后精度掉多少是大家最关心的。我实测YOLOv8s在RK3588的NPU上,fp16推理大约每帧55ms,int8量化后大约38ms,精度mAP50从0.92掉到0.87,损失还在可接受范围。但缺陷检测场景对极端小目标敏感,int8量化可能把某些灰度接近的裂纹细节吞掉,所以我最后选择fp16模型在生产环境跑,int8只用来做快速预览。
4.3 端云协同:边缘段跑检测,云上跑诊断
最终交付的架构是端云协同。无人机或地面站的边缘设备实时跑YOLOv8,把所有检测框结果打包上传;云端服务器跑DeepSeek诊断,并结合历史数据进行综合判断。为什么不让边缘端直接跑大模型?很简单:纯推理侧部署大模型到RK3588会遇到资源和成本的双重瓶颈,而且诊断业务并不需要实时,边端先把“缺陷在哪里”算出来,云端再回答“这个问题怎么办”,任务自然分工。
端云协同还要考虑通信链路。海上风电场和山区风电场的网络环境都不好,我加了一个离线缓存机制:边缘端检测结果先写本地SQLite,网络恢复后再批量同步,避免巡检中途断网导致数据丢失。很多项目死就死在“闪断一下,整趟巡检白飞”这种问题上。
5. 落地过程中的常见问题与排查记录
5.1 误检和漏检:数据迭代不能停
最常见的问题是蓝天被识别成“裂纹”,塔筒阴影被识别成“砂眼”。在实验室测mAP看不出来,一到现场,背景环境一变,模型立刻露馅。我的诊断思路是:把误检的图按类别聚类,找出模型的“学习误区”。如果大量误检是天空背景,说明模型学的是纹理对比边缘而不是缺陷本身。
解决方法还是靠数据迭代。我把现场误检图每两周回收一次,人工确认后加入训练集,模型就越训越稳。另外,我在训练时混入了20%的纯背景负样本,让模型明白“没有缺陷时只能输出置信度0.2以下的框”,这个操作非常有效。
5.2 无人机图像模糊、反光、雾化的补救
高倍变焦拍摄对震动极其敏感,就算开了防抖,远距离拍高速旋转叶片,偶尔还是有糊的图。我的三条补救措施:第一,拍摄时开启连拍模式,同一位置拍3到5帧,检测服务选清晰度最高的那帧处理;第二,在训练数据里加入运动模糊增强,模型会自带抗模糊能力;第三,检测服务增加一个“清晰度评分”前置模块,用拉普拉斯方差判断图片是否过糊,低于阈值就自动触发重飞,不让垃圾图进入模型。
5.3 DeepSeek API的限流、超时与成本
接DeepSeek API之后,我最头疼的是调用超时和限流。巡检一次有几百个检测框,如果一张图一次调用,高峰期很容易打满限额。我的优化是“检测结果聚合后按叶片聚合”,一个叶片只调用一次大模型,显著降低调用次数和成本。
代码里必须加超时和重试机制。我的做法是用tenacity库,设置3次重试,每次的指数退避基数为1.5秒,超过5秒直接跳过该叶片并标记待人工复核。这样不会因为一个接口抖动卡住整条流水线。另外,max_tokens设2000足够,设太大不仅有浪费,还可能接近模型的单次上下文上限。
5.4 长尾缺陷和未知缺陷的兜底策略
风机缺陷种类远比训练集里那四类多,一定会有模型没见过的形态。我在系统里加了一道兜底逻辑:所有置信度在0.2到0.35之间的检测框,不直接丢弃,而是进“待确认池”,由人工远程看一眼,每周统一纠偏一轮。这个半自动方式看着“土”,但确实是把漏检率压住最有效的办法。
如果你想把“识别未知缺陷”的能力也做成自动化的,下一步可以引入视觉多模态模型,把缺陷框裁剪图直接发给DeepSeek的视觉模型做开放集合识别。我目前只在特定客户项目上做了实验,成本和性能还在磨合,但方向是对的。
最后补一句个人心得:这类系统能真正跑起来,不在于把YOLOv8的mAP刷高几个点,也不在于DeepSeek prompt写得多花哨,而在于整条链路——数据标注规范、现场图像质量、接口异常兜底、报告格式校验——每一环都稳得住。把一次真实巡检的数据完整跑通,比在训练集上刷多项榜单更有价值。毕竟风机在现场运行,等不起你又一次“离线调试”。