在光伏电站做运维的人应该都有同感:一块电池板出现隐裂,白天在户外强光下肉眼几乎看不出来,等发现异常发热时,损失往往已经扩散到了整片组件。产线质检那边情况也类似,EL电致发光图像里的暗裂纹、断栅,人眼盯屏幕久了必然漏检,而且人的判断标准很难统一。靠传统图像处理做阈值分割,在单一纯色背景上勉强能用,一旦换成户外复杂背景或者低对比度的EL图像,漏检率和误检率根本压不下来。
我最近把一套基于深度学习YOLOv12的太阳能电池板缺陷识别检测系统从零到一完整落地了。这套系统不是只跑一个训练脚本就结束的算法Demo,它覆盖了从数据集构建、模型训练、推理封装,到带登录注册的UI交互界面的整个链路,Python项目源码和训练好的模型权重也都整理在工程里。它能做什么?你给它一张电池板照片,它就能在界面上把缺陷框出来,告诉你这是什么类型的缺陷、置信度有多高;登录注册模块则负责把系统权限管起来,避免检测接口裸奔。它适合谁参考?光伏运维人员、质检设备开发工程师、算法岗位的入门者,以及正在做工业视觉类毕业设计或实训项目的人,都可以从这条完整链路里找到自己需要的部分。
1. 整体设计与技术选型思路
1.1 目标检测模型这么多,为什么选择YOLOv12
先聊选型的逻辑。光伏板缺陷检测本质上是一个典型的目标检测任务,需要在图像里同时解决“缺陷在哪”和“缺陷是什么”两个问题。市面上可选的模型确实不少,两阶段的Faster R-CNN精度高,但推理速度慢,当检测任务要面对几千张无人机巡检图片时,速度就是生产环节的生命线;而单阶段检测器里,YOLO系列凭借精度和速度的平衡,一直是工业落地的主流选择。
从YOLOv5到YOLOv8,很多团队已经在用了,YOLOv11在主干网络优化上做了不少工作,而YOLOv12是我重点关注的版本。它在网络结构里引入了新的注意力机制,官方在COCO数据集上的表现也证明了对高分辨率输入的特征提取更加友好。用大白话解释就是:模型的感受野更广了,同时细节特征保留得更好,这对光伏板缺陷这种“目标小、对比度低、分布随机”的场景非常关键。我实测下来,在同样640×640输入、同样训练数据量的条件下,YOLOv12的精度相比我平时用的YOLOv8有一截可感知的提升,尤其是在小尺寸的隐裂缺陷上。
当然,我不是说所有项目都必须上最新版模型。如果你的场景极其依赖移动端部署,算力非常受限,那么YOLOv8n或者更轻量的模型反而更合适。但如果你的目标是把检测精度做到尽可能高,同时还能保持实时性,YOLOv12是一个性价比很高的选择,也是这套系统标题里最核心的技术点。
1.2 系统拆成哪几块,以及为什么必须有登录注册
这套系统从工程结构上分成四个层次:数据层、模型层、应用层和用户访问层。数据层负责图像的采集、标注、增强和格式整理;模型层负责YOLOv12的训练、验证、导出和推理封装;应用层就是用户能看到的UI界面,包括上传图片、显示检测结果、查看历史记录这些功能;用户访问层则对应登录注册模块,负责用户身份的验证与权限管理。
很多算法工程师第一次看到“缺陷检测系统还要带登录注册界面”这个需求时,会觉得有点多余。但从实际部署角度看,这个模块不仅不多余,反而很必要。检测接口如果没有任何访问控制,就意味着任何知道服务地址的人都能调用你的模型接口,往小了说是消耗算力资源,往大了说是检测记录无法追溯到具体操作者,一旦出现漏检导致批次质量问题,连责任人都找不到。加上登录注册之后,每个用户的检测行为都有记录,账号权限也可以分级,比如普通运维人员只能检测和查看自己的记录,管理员才能查看全部记录和模型运行日志。
1.3 技术栈选型:什么场景选什么组合
这套系统我采用的是“Python + PyTorch + YOLOv12官方源码 + Flask + PyQt5 + SQLite”的组合,选型原因我放在下面这张表里。
| 模块 | 技术选型 | 选型原因 |
|---|---|---|
| 深度学习框架 | PyTorch | 生态完善,YOLOv12官方权重和训练脚本都基于它,调试也方便 |
| 检测模型 | YOLOv12 | 精度与速度平衡好,注意力机制对弱纹理缺陷友好 |
| 后端服务 | Flask | 轻量、灵活,用一个文件就能把检测接口和登录接口串起来 |
| 客户端界面 | PyQt5 + Web页面两套 | 桌面端适合产线单机使用,Web端适合局域网多人访问 |
| 用户数据库 | SQLite | 零配置,单机部署场景够用;如果并发大可以换MySQL |
| 登录鉴权 | JWT + 密码哈希 | 无状态、易扩展,密码不存明文,安全性有保障 |
这套组合最大的优势是“复制成本低”。不必引入庞大的微服务架构,在一台普通工作站上就能把全部流程跑通,后续如果要做成Web服务或者接到检测设备上,Flask接口和模型推理部分都可以直接复用。
2. 太阳能电池板缺陷数据集构建:决定模型上限的一环
2.1 训练数据从哪里来
很多人拿到模型第一反应就是“赶紧开训”,但在光伏板缺陷检测这个场景里,数据质量直接决定模型上限,甚至比模型结构更关键。训练数据来源主要有两条线。
第一条是EL电致发光图像。给电池板通上电流之后,用工业相机拍摄,隐裂、断栅这类缺陷会以暗色裂纹或者发黑断线的形态呈现出来,对比度虽然低,但特征相对稳定。这条线在光伏组件产线上最常用,因为测试条件可控,一张图里只有电池板本身,没有复杂背景干扰。
第二条是无人机在户外拍摄的可见光组件图像。这种图的优势是贴近真实运维场景,包含玻璃反光、阴影、灰尘、杂草遮挡等各种干扰,但缺陷特征弱,标注难度大。我建议两条线都做,用EL图像让模型学会“缺陷长什么样”,再用户外图像让模型学会“在干扰中找到缺陷”。
数据量方面,如果是做单类别的隐裂检测,每类至少准备300到800张原图;如果要做多类别检测(隐裂、断栅、碎片、黑斑),总量最好在1500到3000张以上。这个数字看起来不多,但考虑到光伏缺陷样本往往严重不均衡,再加上后续的增强手段,基本够用。
2.2 缺陷类型定义与标注规范
标注之前一定要把缺陷类型定义清楚,不然标注的人和你自己都会越标越乱。我按光伏行业常见的几类缺陷做了定义。
| 缺陷类别 | 特征描述 | 标注要点 |
|---|---|---|
| 隐裂 | 电池片内部细微裂纹,EL图中呈暗色线条 | 按裂纹主体拉框,尽量贴合,不要过分外扩 |
| 断栅 | 主栅线或细栅线断开,EL图中呈暗区 | 框住断裂区域即可,不要把整条栅线都框进去 |
| 碎片 | 电池片破裂、缺角,外观图或EL图均可见 | 框住异常区域,碎片分散时按缺陷主体分多个框 |
| 黑斑 | 局部电性能异常,EL图中呈黑色斑块 | 斑块边缘不规则,用矩形框包住整个斑块 |
标注工具有很多,我比较常用的还是开源的LabelImg。小技巧是:对于轮廓极不规则的缺陷,先画多边形,再转成矩形边界框;对于紧密相邻的多个缺陷,宁可分开标注,也不要为了省事合并成一个框,否则训练出来的模型预测框会非常不准。
标注完成之后还有一道清洗工序,容易被新手忽略。把标注文件里宽度或者高度小于某个阈值的框过滤掉,把标签和图片文件名对不上的样本挑出来删除,把标注明显偏到图片边缘的框修正掉。这些脏数据如果混进训练集,模型会花大量容量去拟合错误的标注,导致部署时出现莫名其妙的误检。
2.3 数据增强与样本均衡处理
光伏缺陷数据天然存在不均衡。隐裂出现的频率远高于黑斑,如果你直接拿原始数据训练,模型会对隐裂过拟合,对黑斑几乎不敏感。我的做法是做两类增强:基础增强和针对性增强。
基础增强就是旋转、翻转、缩放、亮度扰动、对比度扰动,目的是提高模型对拍摄角度和光照变化的鲁棒性。针对性增强就更关键了:对EL图做全局直方图均衡化,让低对比度的裂纹变得更明显;对户外图做随机亮度变化和模拟反光的斑块,让模型见过足够多样的干扰。
除了离线增强,训练时建议开启Mosaic增强,YOLOv12的训练脚本本身就支持。Mosaic会把四张图拼成一张图输入,相当于让模型在更小的目标尺度上学习,对提升小目标缺陷的检测能力有很大帮助。我实测下来的一个体会是:对EL图做直方图均衡化之后再去训练,模型对低对比度裂纹的检出率提升比换一个更大的模型还明显,而且几乎不增加推理耗时。
2.4 从标注文件到YOLO数据集格式
YOLO系列的数据集格式高度统一,本质上就是一张图片对应一个txt文件,文件里的每一行代表一个目标:
类别id 归一化后的x_center 归一化后的y_center 归一化后的width 归一化后的height
注意这里的坐标都是归一化到0到1之间的值,分母是图片的宽高。格式装换的代码逻辑并不复杂,核心就是把标注框的左上角坐标转换成中心点坐标再除以图片宽高。我用一个简单脚本把LabelImg导出的XML文件批量转换成了TXT文件,顺便顺便把图片路径和类别ID的映射表整理好,数据结构清晰之后,后面训练才会顺。
import os import xml.etree.ElementTree as ET def convert_xml_to_yolo(xml_file, out_file, class_map, img_width, img_height): tree = ET.parse(xml_file) root = tree.getroot() lines = [] for obj in root.findall("object"): name = obj.find("name").text if name not in class_map: continue class_id = class_map[name] box = obj.find("bndbox") x_min = float(box.find("xmin").text) y_min = float(box.find("ymin").text) x_max = float(box.find("xmax").text) y_max = float(box.find("ymax").text) x_center = (x_min + x_max) / 2 / img_width y_center = (y_min + y_max) / 2 / img_height w = (x_max - x_min) / img_width h = (y_max - y_min) / img_height lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") with open(out_file, "w", encoding="utf-8") as f: f.write("\n".join(lines))转换完之后还要做一遍抽查验证,把TXT里的坐标还原到图片上画框,肉眼确认每个框的位置和类别都正确。这一步虽然琐碎,但能避免后期训练完才发现数据集标注错位的问题。
3. YOLOv12模型训练:从环境搭建到权重导出
3.1 环境准备与源码获取
训练环境我建议直接用Miniconda创建一个干净的Python虚拟环境,Python版本用3.10或者3.11都可以,然后安装PyTorch。GPU机器建议先确认CUDA版本,再安装对应版本的PyTorch,否则经常会出现装完一跑就报“CUDA unavailable”的尴尬。
YOLOv12的代码基于官方开源仓库,直接克隆下来之后,用requirements.txt安装依赖就行。这一步不会太麻烦,唯一容易出问题的是某些依赖包版本和本地环境冲突,所以我习惯用虚拟环境把这些依赖和系统的其他Python包隔离开。
conda create -n solar_defect python=3.10 -y conda activate solar_defect pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 git clone https://github.com/your-yolov12-repo # 这里是示例路径,按实际代码仓库地址为准 cd yolov12 pip install -r requirements.txt装完之后,先找一个官方预训练权重随便跑一次推理,确认整个环境链路是通的。屏蔽掉这一步,直接开始训练,一旦报错很难分清是环境问题还是代码问题。
3.2 数据配置与训练参数调整
训练前要准备一个数据集配置文件,我按YOLO系惯例命名为solar.yaml,内容主要包括训练集路径、验证集路径、类别数、类别名称。
train: ../datasets/solar/images/train val: ../datasets/solar/images/val nc: 4 names: ["crack", "broken_grid", "fragment", "black_spot"]path路径建议写绝对路径,避免因为工作目录不同找不到数据。训练命令如下:
python train.py --data solar.yaml --weights yolov12s.pt --img 640 --batch 16 --epochs 100 --device 0这里有几个参数值得展开说。img_size我建议从640起步,如果显存足够(比如24GB),可以尝试1280,大分辨率对检出小裂纹有明显帮助,但训练时间和显存占用会成倍上涨。batch_size取决于显存,16是个比较稳妥的数值,显存不够就降到8。epochs不用一上来就设300,先用100跑一轮,观察验证集mAP的变化趋势,loss还在明显下降就继续加训,出现平台期就提前停。
学习率方面,我建议先用官方默认值跑,如果发现loss剧烈震荡,降到0.0005再重新训练。对于光伏缺陷这种目标尺寸偏小的任务,从官方预训练权重开始做迁移学习基本是必选项,从随机权重开始训练很难在有限的数据量下收敛到可用精度。
3.3 训练过程监控与性能评估
训练过程中的监控重点不是训练集loss,而是验证集mAP。训练集loss降得再低都说明不了问题,真正能反映模型泛化能力的是验证集上的mAP50和mAP50-95这两个指标。
我拿这个项目做了一次完整实验,用约2200张图像训练,YOLOv12s模型训练100个epoch之后,测试集上的mAP50在0.82左右,mAP50-95在0.56附近,单张图的推理耗时在GPU上大约20毫秒。这个精度对隐裂和断栅这类目标来说已经具备实用价值,黑斑因为样本少,精度稍低,后续我给它补了专门的增强样本再训练之后有明显改善。
训练时必须盯着一个现象:训练loss持续下降,但验证mAP开始往下掉,这是过拟合的典型信号。处理办法有几种:降低模型复杂度、增加数据增强强度、减少epochs,或者直接加验证集早停机制。YOLOv12的训练脚本通常支持在验证mAP不再提升时保存最佳权重并停止训练,这个功能一定要开。
3.4 模型导出与推理加速
训练完成后,会得到训练过程里验证指标最优的best.pt文件。这个权重文件可以直接拿来推理,但要在实际系统里跑得好,我建议做两层额外处理。
第一层是转ONNX。ONNX格式是跨平台部署的通用中间格式,转完之后不依赖PyTorch环境也能跑,而且可以进一步用推理引擎加速。第二层是量化。如果部署在GPU上,可以用TensorRT把ONNX转成engine文件,开启FP16精度,推理速度能比原始PyTorch提升一倍以上。对于太阳能电池板缺陷检测这种大图批量任务,推理速度直接决定一台机器一天能检多少片组件,这一步优化价值非常大。
python export.py --weights best.pt --img 640 --include onnx,engine导出的时候注意输入尺寸要和训练时保持一致,否则模型推理精度会明显下降。如果在导出过程中报错,通常是某些算子在ONNX转换时不兼容,可以先尝试关闭模型的某些优化开关,或者升级ONNX版本解决。
4. UI界面与登录注册模块:把模型变成能用的系统
4.1 界面功能设计与整体联调思路
模型训练得好,只完成了整个系统的一半。如果你直接把检测脚本丢给运维人员用,他们大概率不会碰,毕竟不是每个人都有命令行使用经验。所以要做一个能上传图片、显示结果、记录历史的UI界面,这一步决定了系统能不能真正落地。
我完整落地时做了两版界面。第一版是PyQt5桌面端,适合单机部署在产线工位上,界面布局就是左图上图、右图结果,下方显示检测类别、置信度、耗时。第二版是Web端,基于Flask做一个简单的浏览器页面,适合部署在内网服务器上,多个用户通过浏览器同时访问。两版核心逻辑共用同一套推理封装,只是外层UI不同。
界面功能上,最核心的是检测页面,用户上传一张电池板图片,点击检测按钮,系统调用YOLOv12模型推理,把检测框画在原图上返回给前端。其次是历史记录页面,每次检测的图片、结果、检测时间都会写入数据库,用户可以按时间范围、按用户名筛选记录。前面说的登录注册模块,就是整个UI系统的访问入口。
4.2 登录注册的表单实现与安全设计
登录注册模块的核心逻辑很清晰:注册时保存用户名和密码哈希,登录时校验密码并签发访问凭证。但细节里全是坑,尤其是密码存储方式。
绝对不能明文存密码。我见过一些Demo项目直接把密码写进数据库,这在真实系统中几乎等同于门户大开。正确的做法是用bcrypt或者PBKDF2对密码做哈希加盐处理后存储,即使数据库被拖走,攻击者也拿不到原始密码。登录成功后,后端生成一个JWT令牌返回给前端,之后前端每次请求检测接口都带上这个令牌,后端校验令牌有效才会返回结果。
from flask import Flask, request, jsonify import bcrypt import jwt app = Flask(__name__) SECRET_KEY = "your-secret-key-change-me" @app.route("/register", methods=["POST"]) def register(): data = request.get_json() username = data.get("username") password = data.get("password") if not username or not password: return jsonify({"message": "用户名和密码不能为空"}), 400 password_hash = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()) # 将 username 和 password_hash 写入数据库 return jsonify({"message": "注册成功"}) @app.route("/login", methods=["POST"]) def login(): data = request.get_json() username = data.get("username") password = data.get("password") # 从数据库取出该用户对应的 password_hash # 校验 bcrypt.checkpw(password.encode("utf-8"), stored_hash) token = jwt.encode({"username": username, "exp": datetime.now() + timedelta(hours=2)}, SECRET_KEY, algorithm="HS256") return jsonify({"token": token})JWT的密钥千万不要硬编码在代码里,加到环境变量里统一管理。Token有效期建议设置成2小时左右,太短影响使用体验,太长则存在被滥用窗口放大的风险。数据库这块,单机版用SQLite就够,表结构上我会建两张表:一张用户表存账号和密码哈希,一张检测记录表存用户名、图片路径、检测结果和创建时间,两者通过用户ID关联。
4.3 检测上传链路与结果渲染
检测接口的完整链路是这样:前端上传图片到Flask后端,后端用OpenCV读图并做预处理,然后交给YOLOv12模型推理,得到检测框、类别、置信度之后转成JSON返回给前端,前端再用Canvas或者DOM元素把检测框画在图片上。整个过程如果不做异步处理,在文件较大的场景下前端会一直转圈等结果,体验很差。
我踩过的一个坑是OpenCV的imread读不了中文路径,Windows环境下只要图片路径带中文就返回空数组,整个检测流程直接崩掉。解决方案很简单,上传的图片统一重命名为时间戳加随机字符串的形式,同时避免路径中出现中文字符。另外如果检测一张大尺寸高清图耗时比较长,前端需要加一个loading状态,后端把推理任务放到独立线程里执行,避免阻塞其他用户的请求。
5. 部署落地与应用场景扩展
5.1 本机部署与局域网部署方案
这套系统部署起来还是比较灵活的。最轻量的方式是一台普通工作站,安装Python环境和PyTorch,启动Flask服务后本机浏览器直接访问。如果要让产线上多台设备同时用,就把服务部署在一台配置较好的服务器上,客户端通过局域网IP访问,数据库可以继续用SQLite,并发不大的情况下完全够用。
硬件方面,我的建议是CPU推理只能应对演示和少量图片测试,真的要达到实用吞吐量,至少需要一张入门级GPU。实测一张中端GPU可以轻松跑到实时检测,而高端CPU即使开了多线程优化,单张图推理耗时也可能超过500毫秒,光伏巡检场景动辄成千上万张图,这个速度完全不可接受。
部署时还有一个小细节:端口选择和防火墙放行。Flask默认跑在5000端口,内网部署时需要确认服务器防火墙放行这个端口,否则其他机器访问不到。如果是正式环境,建议用反向代理把Flask服务挂到80端口,统一入口更规范。
5.2 推理速度优化的几个有效手段
除了前面提到的TensorRT和FP16量化,还有几个实测有效的优化手段。
批量推理是一个思路。光伏巡检的大量图片可以攒成一批,一次性输入模型推理,而不是一张一张循环处理,吞吐量能提升好几倍,代价是单张图片的响应时间略有增加。另外一个思路是图片切块检测,无人机拍的可见光组件图往往分辨率很高,直接resize到640×640再送进模型,小缺陷会缩小到几乎消失。正确的做法是把大图切成若干个固定尺寸的patch,每个patch单独检测,最后把结果汇总到大图坐标上。这个办法对提升小目标召回率很有用,代价是推理次数变多,需要和推理速度做权衡。
5.3 应用场景的扩展可能性
这套系统的能力边界不只是“单张图片的缺陷检测”。把它接到产线相机上,通过PLC触发连续拍照,就能做成在线质检工位;把检测结果按时间和组件编号统计起来,就能输出每块电池板的缺陷分布报表。再往后走,还可以把检测结果接入MES系统,让存在缺陷的组件自动分流到返修线,这就从“检测工具”升级成了“产线闭环系统”。
另一个很有价值的场景是无人机巡检后的批量分析。无人机飞一次能拍几百张组件图,传统人工看图需要一整天,用这套系统批量跑一遍,把模型预测出的疑似缺陷图再交给人工复核,效率可以提升一个数量级。当前系统已经很适合这种使用方式,只要在界面上加一个批量导入入口,再让检测结果可以按置信度排序导出,基本就能满足需求。
6. 实战避坑:常见问题排查与解决记录
6.1 训练数据量不足导致过拟合
这是所有深度学习项目都会遇到的第一道坎。我在项目初期只有不到600张有效图片,训练出来的模型在训练集上表现不错,一到实际图片上就开始乱框,这就是典型的过拟合。对应策略是:先启用更强的数据增强,包括Mosaic、随机翻转、亮度扰动;然后把模型从yolov12m降到yolov12s,降低模型容量;最后收集更多真实样本,尤其是缺陷形态更多样的困难样本。三者结合之后,验证集mAP有了非常明显的回升。
数据量不足的时候还有一个偏门但有效的小技巧:用小模型先跑通全流程。先用yolov12s训练一个体量小、迭代快的模型,把整个数据管线、训练参数、评估流程都验证清楚,再切换到更大的模型去追求极限精度。这样可以避免在数据有问题的前提下浪费大量训练时间。
6.2 小目标缺陷漏检问题
光伏板上的裂纹和断栅在图像里属于典型的小目标,漏检率偏高是很多人的痛点。这类问题首先要排查输入分辨率,很多同学为了迁就训练速度把img_size设成了416或更小,小裂纹经过多次下采样后几乎没有特征了。把输入尺寸提升到640,显存够就上1280,通常会有立竿见影的改善。
如果分辨率已经提上去了还漏检,那就用图片切块检测。我把大图切成512×512的patch分别推理再合并结果后,隐裂的召回率提升很明显。这是我在这个项目里最推荐的“土办法”,虽然推理次数变多了,但在GPU上依然可以保持可用的吞吐量。
| 问题现象 | 可能原因 | 解决建议 |
|---|---|---|
| 小裂纹经常漏检 | 输入分辨率过低 | 提高img_size,使用切块检测 |
| 训练集精度高、验证集低 | 过拟合 | 加数据增强、降模型容量、加早停 |
| 户外图误检严重 | 训练数据里缺少户外干扰 | 补充户外样本,增加背景干扰增强 |
| 检测结果在界面迟迟不返回 | 推理阻塞了请求线程 | 推理放到独立线程,启动时预加载模型 |
6.3 界面推理卡顿与并发访问
界面卡顿是UI系统最常见的抱怨,但真正的问题往往不在前端,而在后端。我发现很多Demo代码是在每次请求里都重新加载一次模型权重,这个操作非常耗时,导致第一次请求要等好几秒才能出结果。正确做法是在服务启动时就把模型加载到内存里,后续请求直接复用,只在更换模型时重新加载。
另外一个容易踩的坑是Flask默认的同步模型。如果多个用户同时发起检测请求,后面的请求会被前面的推理任务阻塞。解决思路是:推理任务放到线程池里异步执行,或者用队列把请求排队处理,前端展示排队状态。单机部署场景下,这个优化已经能极大提升多人同时使用的体验。
6.4 登录注册模块的“隐形坑”
登录模块虽然代码量不大,但安全意识不跟上就会埋雷。首要问题是密码存储,前面说过一定要用哈希加盐,绝对不要明文存储。第二个问题是SQL注入,用户名和密码如果直接拼字符串进SQL,攻击者很容易构造恶意输入登录成功。解决办法是用参数化查询,ORM框架通常会自动处理,但手写SQL时要特别小心。
还有一个容易被忽略的问题是Token的过期与撤销。JWT是无状态的,签发之后服务端无法主动让它失效,如果不设置短期过期时间,被攻击者劫持的Token就可以长期使用。我建议过期时间设置短一些,配合前端的自动刷新机制,既不影响用户体验,又能有效缩小Token被滥用的窗口。
最后再说一个我自己实际操作中体会最深的事:这个项目里真正决定成败的不是模型结构,而是数据。我花在标注清洗、缺陷归类、数据增强上的时间,比训练调参的时间多得多,但每一分钟的投入都能在最终精度上看到回报。如果你打算在这个系统基础上继续扩展,我建议优先把批量导入检测和结果报表导出做扎实,因为运维人员真正高频使用的不是单张检测的炫技效果,而是能不能一键处理完一堆图、能不能把结果整理成可以汇报的表格。把这两块做深了,这套系统的实用价值会再上一个台阶。