☰
基于YOLO与Django的电力绝缘子缺陷检测系统设计与部署
2026/10/22 8:13:34 网站建设 项目流程

在电力巡检的现场,绝缘子是线路上的关键部件,它的状态直接关系到供电的可靠性。以往靠人爬到杆塔上一盯就是大半天,效率低不说,有些缺陷还不容易看出来。正好深度学习检测技术已经成熟,用摄像头代替人眼,用模型代替经验,就能把绝缘子破损、自爆、闪络这类问题自动找出来。最近我把这个场景做成了一套完整的系统,核心就是YOLO系列的检测模型,后端用了Django来搭服务,源码、部署文档和讲解都配齐了。这篇文章就来复盘一下整个项目的设计、训练、开发和部署过程,里面有很多踩坑后的经验总结,适合做电力视觉相关项目的同学参考,也适合想了解目标检测+Web服务完整链路的朋友阅读。

1. 项目整体设计与技术选型思路

1.1 核心需求拆解:为什么需要绝缘子检测系统

绝缘子通常挂在输电铁塔上,长期暴露在野外,经历风吹日晒、雨雪雷电,表面很容易出现裂纹、自爆甚至污闪。这些缺陷如果不及时发现,轻则造成线路损耗,重则导致大面积停电。传统的人工巡检方式要爬塔或者靠望远镜,效率低、风险高,而且对肉眼难以分辨的细裂纹经常漏检。后来无人机巡检普及了,每天能拍成千上万张照片,但这么多图片如果还是靠人来看,眼睛很快会疲劳,漏检率反而更高。

所以这个系统的核心需求就变得很明确:能接收巡检拍回来的图像,自动识别出图像里的绝缘子,并判断是否存在缺陷,最后把检测结果在网页上展示,方便运维人员复核。进一步细化,系统需要满足三个层面:第一,算法层面要有足够高的准确率和召回率,尤其是不能漏掉细小破损;第二,平台层面要能支持用户上传图片、查看结果、保留历史记录,不然就只是个孤立模型;第三,部署层面要能方便装到服务器上,且不需要太高的硬件成本。基于这三点,我确定了“深度学习检测模型 + Web服务框架 + 数据库”的经典组合。

1.2 模型选型:YOLOv5/v8/v11/v12之间的取舍

为什么这个项目选了YOLO系列而不是其他目标检测算法?核心原因就是速度和精度的平衡。像Faster R-CNN这类两阶段检测器,精度不错,但推理速度较慢,在无人机巡检场景里,动辄几千张图片等着处理,时间成本太高。YOLO系列是单阶段检测器,一次前向传播就能同时得到类别和位置,速度快得多,而且在近几年的迭代中,小目标检测能力也追了上来。

那么YOLOv5、v8、v11、v12这四个版本怎么选?我逐一做了对比和分析:

  • YOLOv5:最经典、最稳定,训练资料多,部署方案非常成熟,对新手最友好。在网络结构上使用CSPDarknet骨干,模型容量适中,但早期YOLOv5的Anchor设置对细长物体(比如绝缘子串)不是最优。
  • YOLOv8:在v5基础上全面改版,采用Anchor-Free方式,去掉了预置锚框的麻烦,检测头解耦,分类和回归分支独立,收敛速度和精度都有提升。而且支持在移动端和边缘端部署,灵活性很高。
  • YOLOv11:进一步优化了骨干网络的C3K2模块和SPPF结构,加入了更高效的跨阶段局部连接,在保持精度的同时把参数量降了下来,推理速度更快。
  • YOLOv12:作为较新的版本,引入了注意力机制增强特征表达,对遮挡和小目标有更好的鲁棒性,但模型复杂度也相应增加,需要更好的显卡才能跑出速度优势。

我在项目里四个版本都训练过,最终的模型选择并不是追求最高精度,而是找一个在真实巡检图片上“既准又稳”的方案。下面的表格是我整理的不同版本的特性对比,方便你快速理解:

模型版本核心特点精度表现推理速度适用场景
YOLOv5成熟稳定,部署方案多中上快快速原型,有限算力
YOLOv8Anchor-Free,解耦头较高较快精度与速度均衡
YOLOv11优化C3K2,轻量高效高很快大规模批量检测
YOLOv12引入注意力,强特征融合最高中等小目标、遮挡较多

为什么提供四个版本而不是只保留一个?因为不同用户的硬件环境差异很大。有人只有CPU电脑,跑YOLOv12会卡得不行;有人需要量产实时检测,那YOLOv11更合适。系统设计成模型可配置的方式,用户可以在后台切换不同权重,这个思路也方便后续迭代升级。

1.3 后端选型:为什么用Django做Web服务

目标检测模型训练好以后,不可能每次检测都写Python脚本在命令行里调用,那样既不直观也无法给业务方使用。必须有一个Web服务把模型“包”起来,对外提供接口和界面。后端框架我在Flask和Django之间纠结过,最后选了Django。

原因有三点:

第一,Django自带ORM和数据库迁移功能。检测记录、用户信息、模型配置都需要存储,Flask需要再额外装SQLAlchemy,Django直接内置,省事。

第二,Django自带Admin后台。我可以很快地为检测记录建一个管理页面,方便查看所有上传图片和结果,甚至导出统计报表,这个对于毕业设计演示和实际项目交付都很加分。

第三,Django的MTV结构适合这种业务不复杂但需要扩展的项目。它把请求处理、模板渲染、业务逻辑分离开,代码维护起来很清晰,后续如果想把系统接入小程序或移动端,只要用Django REST Framework(DRF)写一套API就行,不必动现有页面。

当然Flask更轻量,但对我来说,Django的“基础设施齐全”能省下不少重复开发时间,尤其是用户认证和文件管理这部分。最终虽然模型推理本身只占系统一小部分,但Django让整个系统看起来像产品,而不是一个玩具。

1.4 系统架构总览

整个系统的架构可以用一条链路讲清楚:用户在前端页面上传一张绝缘子图片,Django后台接收请求,把图片保存到本地,随后调用封装好的YOLO模型进行推理,得到检测框、置信度和类别,再把检测结果画到原图上,返回给前端展示。同时,每次检测记录(原始图、标注图、检测信息、时间戳)都会写入数据库,方便用户随时在“历史记录”页面查看。

从模块划分来看,系统分成了三层:

  • 前端层:用HTML + JavaScript + CSS实现图片上传和结果展示,不需要复杂框架,重点是交互简单、响应快。
  • 业务层:Django的view处理上传请求、调用推理模块、做文件管理、读写数据库。
  • 模型层:封装YOLO模型,提供detect(image)方法,内部完成预处理、推理、后处理,不直接依赖Django,这样以后换框架也能复用。

这套架构最核心的设计思路就是“模型与业务解耦”。我把模型推理写在一个独立的detector.py里,Django只负责携带图片数据来调用它。这样即使以后不用Django,或者想换成FastAPI,模型代码不用动一行。

2. 数据集准备与预处理细节

2.1 绝缘子数据集的采集与标注

深度学习模型的成败,一半取决于数据。绝缘子数据集和通用物体数据集不太一样,主要难点在于:图像多是在复杂背景(山体、树木、天空、电网)下采集,绝缘子形态多样,有单串、双串、V型,而缺陷种类也多。

我起初用了一个公开的绝缘子数据集,里面包含正常绝缘子、破损绝缘子、自爆绝缘子和闪络绝缘子等类别,图片数大概几千张。但实际训练时发现,有些图片分辨率很低、目标很小,模型很难学。后来我又补充了一部分巡检图片,做数据清洗,把模糊的、目标过小的、重复的图片去掉,最后保留了大约5000张有效图片。

标注格式上,我统一用YOLO格式。这种格式用一个txt文件记录每张图中的所有目标,每一行是“类别ID 中心点x 中心点y 宽度 高度”,其中坐标都是相对于原图尺寸归一化到0-1之间的浮点数。标注工具我用了LabelImg,多年老牌工具,操作简单,快捷键多。在标注的时候要特别注意一点:对于一串绝缘子,是每片绝缘子单独框一个框,还是把整串框成一个框?这取决于检测目标定义。如果目的是“统计整串缺陷”,建议把整串当一个目标框;如果目的是“找到具体哪一片破损”,那么要单独框每个绝缘子。我采用的是后者,因为实际检修时需要精确到具体的绝缘子片。

标注完成后的目录结构是这样的:

dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/

每张图片对应一个同名txt标注文件,内容类似:

0 0.453 0.617 0.112 0.084 1 0.521 0.683 0.120 0.091

这里类别0代表正常绝缘子,类别1代表破损绝缘子。

2.2 数据增强与样本平衡策略

绝缘子数据集的典型问题是类别不平衡。正常样本很多,但破损和自爆样本相对稀少。如果直接用原始数据训练,模型会倾向于预测“正常”,从而漏掉真正的缺陷。我在训练前做了三类处理:

  • 针对缺陷样本过少,采用复制增强。对破损、自爆类图片做随机复制并融合到存在缺陷的样本集里,让缺陷类别占比达到总样本的30%左右,但不是简单复制,而是每次复制时随机改变亮度、对比度、添加噪声。
  • 使用Mosaic增强。把4张图片随机拼成一张,增加目标上下文多样性,同时丰富了小目标的数量。YOLOv5和v8本身内置了Mosaic,我在训练时开启了增强开关。
  • 做几何和颜色扰动。包括随机旋转(±10度)、随机水平翻转、HSV颜色调整、随机仿射变换、随机模糊等。这些增强能模拟无人机不同角度、不同光照条件下的拍摄情况,有效提升模型的泛化能力。

分享一个经验:增强不是越多越好。我一开始开了很大的随机旋转角度,导致绝缘子图像扭曲变形,反而让模型学出了错误的特征。后来把角度限制在±10度以内,效果明显改善。对于绝缘子这种细长结构,过度的旋转会破坏语义,需要谨慎。

2.3 数据集划分与格式转换

划分比例我按照7:2:1:70%训练集、20%验证集、10%测试集。训练时用验证集来监控模型是否过拟合,测试集只在最后评估一次,绝不参与调参。为了保证类别分布一致,我没有用随机划分,而是采用分层抽样:先按类别把样本分组,再在每个组内按比例划分,这样确保每个集合里缺陷样本比例相近。

用YOLOv8训练时,还需要一个描述数据集的yaml文件。内容如下:

path: /data/insulator train: images/train val: images/val test: images/test nc: 2 names: ['normal', 'broken']

这里的nc代表类别数,names是类别名称列表。YOLOv5也支持同样的格式,所以四个模型共用同一个数据集文件,训练时只需要修改模型权重和配置文件即可,非常方便。

3. 模型训练的过程与关键参数调优

3.1 环境配置与依赖安装

训练环境我用的是Linux服务器,显卡是单卡24G显存(这里不指定具体型号,避免广告嫌疑),系统Ubuntu 22.04,Python 3.10,CUDA 12.1。

安装深度学习框架这一部分,我习惯为每个模型单独建一个conda环境,防止依赖冲突。比如YOLOv5需要PyTorch 1.8以上,YOLOv8/11/12则需要PyTorch 1.8+且最好2.0以上。基础命令如下:

conda create -n yolo python=3.10 conda activate yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics

这里注意,YOLOv8及以上版本统一由一套ultralytics库支持,而YOLOv5是独立的仓库。我分别拉取了YOLOv5的官方仓库,并安装其requirements.txt。如果在国内网络环境下,pip要换国内源,否则下载速度很慢。

3.2 训练脚本与超参数配置(以YOLOv5为例)

YOLOv5的训练命令比较经典,我以它在四个版本中最稳定的特点来讲解。基本命令如下:

python train.py --data insulator.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --device 0

参数含义:

  • --data指定数据集配置文件。
  • --weights指定预训练权重。使用在COCO上预训练的模型作为初始权重,可以加快收敛,提升最终精度。如果你的类别和COCO差异很大,只冻结前几层,让深层参数充分训练。
  • --img是输入图片大小。我训练时先用640分辨率,后期如果想提升小目标检测,微调阶段再用960分辨率,但训练时间会显著增加。
  • --batch是批大小,受显存限制。我用16刚刚好,如果你显存不够,可以用8并通过梯度累积弥补。
  • --epochs是训练轮数。100轮是中等水平,实际训练过程中会出现验证集mAP不再上升的情况,说明已经收敛,可以提前停止。
  • --device指定GPU编号,多卡时代可以继续扩展。

YOLOv8及以上版本的训练更简单,一条命令:

yolo detect train data=insulator.yaml model=yolov8s.pt epochs=100 imgsz=640 batch=16 device=0

官方文档统一了命令行结构,yolo命令可以直接使用。训练日志中每轮会输出Train/Box、Valid/Box等指标,最终会把best.pt和last.pt保存到runs/detect/exp/目录下。

3.3 多版本模型训练与性能对比

我在同样的数据集上分别训练了YOLOv5s、YOLOv8s、YOLOv11s和YOLOv12s(都是s小规格,保证可比性),初始权重都是各自在COCO上的预训练模型,统一使用640分辨率,100轮,batch 16。训练耗时如下:

  • YOLOv5s:约3小时
  • YOLOv8s:约3.5小时
  • YOLOv11s:约4小时
  • YOLOv12s:约5小时

实际测试结果我整理成了表格,这里的mAP指验证集上的结果:

模型mAP@0.5mAP@0.5:0.95单张推理速度(GPU)模型大小
YOLOv5s0.8230.6028ms14.2MB
YOLOv8s0.8610.6457ms21.0MB
YOLOv11s0.8720.6686ms19.3MB
YOLOv12s0.8790.6849ms25.6MB

从数据看,YOLOv12精度最高,但速度和模型大小不占优;YOLOv11在精度与速度之间取得了非常好的平衡;YOLOv5虽然精度最低,但在CPU或低端设备上更容易部署。经过权衡,我在Django系统中默认使用YOLOv8s,因为它训练时间不算长,精度可以接受,而且生态最完善、问题最少。如果你只是做简单的故障分类,YOLOv5s也完全够用。

3.4 评估指标解析与最佳模型选择

很多人看训练日志时容易被各种loss数值绕晕,我的经验是重点看mAP@0.5、mAP@0.5:0.95和Recall这三个指标。

  • mAP@0.5:交并比0.5时各类别平均精度。它衡量模型的“定位好不好”。
  • mAP@0.5:0.95:在不同IoU阈值下的平均,更严格,对大目标回归框的准确性更敏感。
  • Recall:所有真实目标中,被正确检测出来的比例。对于绝缘子缺陷检测,宁可误检也要少漏检,所以Recall很低时模型基本不能用。

在最终选择时,我把重点放在mAP@0.5:0.95上,因为这个指标更贴近绝缘子小目标检测的难度。但也要考虑速度。实际线上测试时,我用测试集里的1000张图片跑了一遍,统计漏检率。最终选择YOLOv8s作为默认模型的另一个原因是它的踩坑成本最低——网上资料多,遇到问题容易查,部署到Django时也稳。

4. Django后端集成与API设计

4.1 将训练好的模型封装为推理类

模型训练完成后,最关键的一步是把模型封装成一个独立的Python类,方便Django调用。我在utils/detector.py里写了这样一个类:

class YoloDetector: def __init__(self, weights_path, device='cpu'): self.model = YOLO(weights_path) self.device = device self.model.to(device) self.conf_thres = 0.25 self.iou_thres = 0.45 def detect(self, image): results = self.model.predict(image, conf=self.conf_thres, iou=self.iou_thres, device=self.device) boxes = [] labels = [] confidences = [] for r in results: for box in r.boxes: x1, y1, x2, y2 = box.xyxy[0].tolist() labels.append(int(box.cls[0])) confidences.append(float(box.conf[0])) boxes.append([x1, y1, x2, y2]) return boxes, labels, confidences

这里有几个小技巧:第一,model.to(device)要把模型放到对应计算设备上。如果服务器有GPU,推测时就调用GPU;如果没有,会自动fall back到CPU。第二,在Django的settings中配置一个全局变量MODEL_SINGLETON = YoloDetector(weights_path),因为加载模型非常耗时,如果每次请求都加载一次,系统会卡死。第三,模型推理不是线程安全的,实际部署时最好加一个锁,或者用进程池。我简化处理为只用一个Django进程,配合Gunicorn多worker,这样每个worker独立加载模型,互不干扰,内存消耗会高一点但可控。

4.2 设计RESTful API接口

为了让前端和系统其他部分解耦,我使用Django REST Framework来设计API。主要提供两个接口:

  • POST /api/detect/:接收上传图片,返回检测结果和标注图片URL。
  • GET /api/records/:获取历史检测记录。

序列化器(serializers)用于把数据库模型转换成JSON。核心关系如下:

class DetectionRecordSerializer(serializers.ModelSerializer): image = serializers.ImageField() result_image = serializers.ImageField() class Meta: model = DetectionRecord fields = ['id', 'image', 'result_image', 'labels', 'confidences', 'created_at']

Django的view里处理上传和推理请求,大致框架:

class DetectView(APIView): def post(self, request): file = request.FILES.get('image') if not file: return Response({'error': '没有上传图片'}, status=400) record = DetectionRecord.objects.create(image=file) result_image, labels, confidences = run_detection(record.image.path) record.result_image = result_image record.labels = labels record.confidences = confidences record.save() return Response(DetectionRecordSerializer(record).data)

这样设计的好处是:推理过程并不直接写业务逻辑,而是封装在run_detection函数里,未来换成别的检测模型也只改这一处。

4.3 图像上传与结果返回的实现细节

前端页面上我用一个表单接收图片,JavaScript用FormData方式发送到后端。接收时需要注意文件大小限制。因为无人机巡检的照片可能达到十几MB,而Django默认的DATA_UPLOAD_MAX_MEMORY_SIZE只有2.5MB,如果不修改,超过限制会报错。我在settings里做了调整:

DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880

同时在后端设置允许上传的图片格式:png、jpg、jpeg、bmp。然后使用Pillow库打开图像,进行必要的EXIF方向校正。这里有个容易被忽略的点:有些手机或无人机拍的图片带有旋转信息,直接用OpenCV读取可能方向不对,导致检测框错位。我的做法是:

from PIL import Image img = Image.open(path) img = ImageOps.exif_transpose(img).convert('RGB') img.save(path)

之后把图片转成numpy数组,传给检测器。检测完成后,用Pillow把框画上去,再保存成新的图片。标注框的颜色我用了绿色(正常)和红色(缺陷),并在图上写上类别和置信度,方便人工检查。

4.4 数据库设计与历史记录管理

Django自带ORM,我定义了一个DetectionRecord模型:

字段类型说明
imageImageField上传的原始图片
result_imageImageField检测后画框的图片
labelsTextField检测到的类别列表,JSON格式
confidencesTextField置信度列表,JSON格式
boxesTextField检测框坐标列表,JSON格式
created_atDateTimeField检测时间
remarkCharField用户备注,可选

在Admin后台注册这个模型,就能直接看到所有检测记录,还支持按时间筛选。如果业务需要,可以在列表页增加一个“导出”按钮,把记录导出成Excel,方便汇报。Django自带的用户认证系统也派上了用场:没有登录的用户无法查看记录,防止敏感图片外泄。

5. 系统部署与使用实践

5.1 本地运行与调试

本地开发时,我用的是Django自带的runserver。先把conda环境激活,安装依赖,再启动服务:

conda activate yolo python manage.py makemigrations python manage.py migrate python manage.py runserver 127.0.0.1:8000

打开浏览器访问http://127.0.0.1:8000,上传一张测试图片,看能否返回结果。调试时遇到最多的问题是图片路径问题:Django的ImageField默认会把文件保存到MEDIA_ROOT指定的目录,如果你在部署时修改了MEDIA_ROOT,会导致历史记录的图片无法访问。设置如下:

MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

同时在主路由中加上:

from django.conf import settings from django.conf.urls.static import static urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

这样开发时才能直接访问上传的图片。

5.2 服务器部署要点

把系统部署到公网服务器的时候,不能再用runserver了。我采用Gunicorn + Nginx的组合。Gunicorn是Python WSGI服务器,比自带服务器更稳定、性能更好。启动命令:

gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 2 --timeout 120

需要注意的地方:

  • --workers的数量不是越大越好。因为每个worker都会加载一次模型,模型占显存或内存,worker过多会导致OOM。我用的GPU服务器只有一块,所以设成2个,CPU服务器可以设4个左右。
  • --timeout要设置得大一点。因为模型推理首次加载或突发并发请求时可能超过默认30秒的worker空闲超时,Gunicorn会杀掉worker。我设成120秒。
  • Nginx负责静态文件和反向代理。其中重要的配置是设置上传文件大小:
client_max_body_size 20m; location /media/ { alias /path/to/project/media/; } location /static/ { alias /path/to/project/static/; } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }

如果服务器内存不够,可以再加swap,否则模型加载时可能会卡死。

5.3 模型转换与推理加速

Django调用通常是一次性返回结果,如果只是图片检测,8-10ms左右的GPU推理时间足以接受。但如果想把系统用于实时监控,或者部署在没有NVIDIA显卡的机器上,就需要做模型优化。最简单的方式是把YOLO模型导出为ONNX格式:

from ultralytics import YOLO model = YOLO('best.pt') model.export(format='onnx', dynamic=True)

导出后得到一个.onnx文件,可以直接用ONNX Runtime推理。没有GPU时,ONNX Runtime的CPU推理速度比PyTorch快很多,因为TRT优化和算子融合。如果还需要进一步加速,就导出TensorRT engine,但TensorRT版本必须与显卡驱动匹配,踩坑概率较高。

我在项目中实际部署就是先把模型导出为ONNX,然后在Django调用ONNX Runtime,这样即使服务器没有GPU也能稳定运行。代码改造也不复杂,还是封装在detector.py里,换一个推理后端即可。

6. 常见问题与排查技巧实录

6.1 训练时显存不足怎么办

这应该是所有训练者遇到最多的问题。显存不足的直接表现是CUDA out of memory。我的解决思路按优先级排序:

  • 减小batch size。这是最直接的方法,从16减到8或4。
  • 降低输入图像尺寸。从640降到512,模型感受野变化不大,但显存占用能减少近一半。
  • 开启混合精度训练。YOLOv5加--amp,YOLOv8默认开启,能有效减少显存占用。
  • 使用梯度累积。如果batch=8还爆显存,就保持batch=8,但每步累积两次梯度,等效于batch=16,代价是训练时间变长。

还有一个隐藏技巧:不要在多线程加载数据时使用过多的预读进程。YOLO系列默认workers=8,但每增加一个worker都会占用内存,24G显存的机器有时还不够优化,硬生生被数据加载撑爆。我一般设置--workers 4,配合--prefetch-batch调小,就能明显缓解。

6.2 检测结果不佳?先做这5步

训练完后发现测试图片上有漏检或误检,先不要急着换模型。我每次都会按以下顺序排查:

  1. 查看训练日志:确认训练损失最终收敛,没有发散。
  2. 检查验证集的mAP曲线:如果mAP在某个epoch后不再上升,说明模型学不动了,可能是数据量不足或增强过度。
  3. 用几张训练图片重新推理:如果训练图片都检测不出来,那一定是代码或路径出了问题;如果训练集效果好但测试集差,那就是过拟合或泛化能力不足。
  4. 调整推理阈值:训练时用的conf阈值是0.25,但实际业务中为了减少漏检,可以把阈值降低到0.1,同时接受少量误检。
  5. 检查图片输入分辨率:如果原图是4K,模型输入只有640x640,很多小目标直接被缩小丢了。此时有两种做法,一是切成小块检测,二是将训练输入分辨率提高到960或1280再微调。

6.3 Django部署中的坑

部署Django系统时有很多超出开发环境的小坑,我记录几个印象深刻的:

  • 静态文件404:如果没有执行python manage.py collectstatic,Nginx找不到CSS和JS文件,页面看起来是“裸奔”的。需要在settings里配置STATIC_ROOT,部署时执行该命令。
  • 上传图片后历史记录里显示图片裂开:多半是MEDIA_ROOT路径配置不对,或者MEDIA_URL没有在Nginx中正确映射。
  • 请求超时:模型加载到内存需要几十秒,第一次请求会因为Gunicorn的worker超时被杀死。解决办法是把模型预加载到全局变量,或用--preload参数提前加载应用代码。
  • GPU内存不释放:PyTorch默认会在第一次推理后缓存显存,进程不退出,显存就不会释放。这不是内存泄漏,是框架特性。通过torch.cuda.empty_cache()也无法彻底解决,最好的方案是保持模型常驻单个worker,不要频繁创建和销毁进程。

6.4 前端展示与模型推理的异步处理

如果检测一张图需要几秒,用户会在前端等得很焦虑。我的第一个版本就是同步请求,用户在页面转圈等了很久才拿到结果,印象很差。后来我把处理改成异步:上传图片后立即返回一个“处理中”的任务ID,前端通过轮询或WebSocket获取结果。

实现方式比较轻量:在Django里用一个后台线程池,把图片路径放入队列,检测完成后更新数据库里的状态字段。前端每隔2秒请求一次任务状态。这个方案比引入Celery要简单,适合并发量不大的场景。需要注意的是,Django默认的ORM连接在子线程中要小心使用,尽量在任务开始前取数据库连接,并在任务结束后清理。

如果你要处理的是无人机拍摄的视频流,就不能再走HTTP请求了。更合理的方案是使用WebSocket,常见实现是Django Channels,不过配置比较复杂。但这样做的好处是真正的实时检测,每帧图像推送到前端显示结果,体验会好很多。

7. 项目扩展与优化方向

7.1 增加多类别检测

当前系统只区分normal和broken两类,但在实际业务里,绝缘子的缺陷种类很多,比如自爆、裂纹、闪络、污秽。你可以扩充标注集,将其变成多分类问题。相应的修改非常简单:在数据集的yaml文件里把nc改成实际类别数,重新标注和维护类别列表即可。模型输出层会自动适应。

多分类训练的核心难点还是类别不平衡。建议给稀有类别更大的损失权重,YOLOv8的训练参数里可以通过cls字段调整。如果仍不够,采用二次分类策略:先用原模型检测所有绝缘子,再对每个切片用另一个分类模型判断缺陷种类。这相当于两级级联,通常能取得比单模型更高的准确率。

7.2 引入注意力机制与轻量化网络

YOLOv12已经内置了注意力机制,但如果你用的是YOLOv8,还可以在骨干网络的末尾加一个SE模块或CBAM模块,让网络更关注绝缘子区域,减少背景干扰。这种改动并不复杂,在ultralytics/nn/modules/conv.py里自定义一个模块,然后在模型yaml中引用即可。当然,动手改之前一定要熟悉模块注册机制,否则跑不通。

如果目标设备是边缘计算盒子,可以考虑把骨干替换为MobileNetV3或ShuffleNet,它们参数量更小、推理更快,代价是精度略有下降。换骨干需要在yaml模型文件中整体替换backbone部分,工作量不小,但这是工程落地时很实际的优化方向。

7.3 实时视频流检测的实现

系统现在只能处理单张图片,如果要做无人机实时视频巡检,可以单独写一个脚本读取摄像头或RTSP流,调用训练好的模型逐帧检测。前端显示可以通过Django的StreamingHttpResponse实现,但更好的方式是搭一个WebSocket服务器,将检测结果帧推送到浏览器。由于是视频流,不能用高分辨率大模型,要适当降低输入帧尺寸或隔帧检测,否则容易掉帧。

有一点经验很重要:实时检测时,模型推理资源要独占,不能和图片检测共用同一个GPU进程,否则视频会卡顿。我在项目中是把视频检测单独部署成一个进程,通过消息队列与主系统通信,这个方案在真正的生产环境中也更稳定。


最后分享一点自己的体会。这套系统最花时间的不是模型训练,而是数据整理和前后端集成。YOLO本身很成熟,网上资料一搜一大把,真正需要打磨的是数据质量、部署可靠性和细节体验。如果你正准备做类似的电力视觉项目,我建议先跑通一条最简链路:用一个轻量模型跑通Django的上传、推理、展示,再逐步迭代数据集和模型。这样哪怕中途遇到问题,也能很快定位到底哪一环出了错。我的很多坑,都是因为一开始就把四个模型、复杂后台全部铺开,结果调试时花了大把时间。希望这些经验能帮你少走一些弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询