基于YOLOv5的焊缝缺陷检测:从数据集训练到PyQt5部署
简介YOLOv5焊缝质量检测资源面向工业视觉质检、目标检测入门与实战人群内容覆盖从数据标注、模型训练到界面演示的完整流程。训练好的模型已包含在内并附带PR曲线、loss曲线等评估文件可据此分析检测精度与收敛情况配套数据集中含1134张jpg焊缝图像使用LabelImg完成标注xmlVOC格式与txtYOLO格式两套标签分别存储方便接入不同训练框架文件总数2000个压缩包约222.96MB组织清晰、便于直接解压使用。同时提供PyQt图形界面支持图片检测、视频检测和摄像头实时检测三种模式操作选项直观适合快速验证模型效果并在此基础上开发定制化检测工具。目前该资源已有986人学习尤其适合希望获得“权重数据集界面”一体化方案、缩短项目开发周期的工程师、科研人员及学生参考使用。1. 焊缝质量检测为什么选中YOLOv5从车间需求到落地方案焊缝质检是焊接产线上最耗人的环节之一。YOLOv5焊缝质量好坏检测这个方案核心就是三样东西一份标注好的焊缝缺陷数据集、一个训练好的权重文件、一个用PyQt5封装的桌面界面。数据集决定模型认识什么样的缺陷权重决定它检得准不准、跑得快不快PyQt界面负责把算法变成车间工人能点的按钮。适合谁做手头有GPU、能拍到几百张真实焊缝图的工艺或视觉工程师。这里先泼盆冷水别在网上找“焊缝权重”直接拿去用焊接工艺一变缺陷形态全变通用模型在现场基本翻车自己训练才是正路。2. 准备焊缝数据集采集、标注与划分的三个关键点数据集是这套方案里最花时间的部分一般占整个工期的一半以上。很多人先跑通代码再补数据结果训练时发现要么漏检要么误检回头再补拍返工成本更高。我习惯把数据当作一个独立交付物来规划按采集、标注、划分三步走。2.1 焊缝缺陷样本怎么拍才能让模型学得会先说成像配置。焊缝表面缺陷检测常见的是工业面阵相机加白色条形光或同轴光垂直或小角度俯拍焊缝表面。三个要点第一固定工作距离和角度。焊接件表面金属反光强角度偏一点同一个缺陷的亮度差很大模型容易去学光照而不是学缺陷本身。我一般把相机固定在支架上距离工件表面200300mm光源用低角度条形光让咬边和气孔产生清晰的阴影轮廓。第二分辨率必须覆盖最小缺陷。假设现场要检出0.5mm的咬边而画面宽度是100mm这个缺陷在640×640输入下只占3个像素左右模型不可能认得出来。我的经验是让最小缺陷在输入图上至少占10×10像素。换算方法不复杂先量出相机视野宽度W毫米再看图像像素宽度P如果最小缺陷是d毫米那么它在图像上的像素数是d / W * P这个值小于10就调整拍摄距离或换更高分辨率的相机。第三合格与不合格样本必须都有。很多团队只拍了一堆缺陷件没拍够合格焊缝结果模型学成了“看到焊缝纹理就报警”误检率高得离谱。我一般按合格:不合格3:7到4:6来配比检测模型反而更稳因为它能学到“哪些纹理变异不算缺陷”。训练前检查样本量单类缺陷少于150个实例模型基本学不稳四类缺陷起步至少600800个标注框。拍的时候多变换工件型号、焊接参数、光照条件同一个缺陷的不同形态比数量更重要。2.2 LabelImg标注VOC格式转YOLO格式标注工具我图省事用LabelImg虽然停止维护了但胜在简单稳定。标注前先在predefined_classes.txt里写死类别标注时框完直接按快捷键切下一张。保存格式建议直接选YOLO格式省一步转换。但不少团队习惯用VOC格式的xml存档所以转换脚本也是刚需。类别怎么定按现场工艺文件走。我见过把表面缺陷分成四类的porosity气孔、undercut咬边、overlap焊瘤、spatter飞溅。类别宁少勿多能合并的先合并。比如气孔包括单个气孔和链状气孔形态差异大但都属于气孔先归一类等基础模型能稳定检出这个大类了再考虑细分。注意标注框小于10×10像素的目标建议直接删除或重拍。小标注框在训练时会被当成噪声处理反而拖累对同类型大目标的检测效果。下面是VOC格式转YOLO格式的脚本import xml.etree.ElementTree as ET import os def voc2yolo(xml_path, out_dir, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size).find(width).text) img_h int(root.find(size).find(height).text) yolo_lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_names: continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 归一化中心点坐标和宽高 cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h yolo_lines.append(f{class_names.index(name)} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_file os.path.join(out_dir, os.path.basename(xml_path).replace(.xml, .txt)) with open(out_file, w) as f: f.write(\n.join(yolo_lines)) class_names [porosity, undercut, overlap, spatter] os.makedirs(labels, exist_okTrue) for xml in os.listdir(annotations): if xml.endswith(.xml): voc2yolo(os.path.join(annotations, xml), labels, class_names)逻辑说明脚本读取xml里的图片宽高和每个目标框的左上、右下坐标换算成YOLO格式的归一化中心坐标和宽高按“类别索引 cx cy w h”的格式写入txt。两个容易出错的地方一是类别索引必须和class_names顺序严格一致顺序一变模型训练时读到的就是另一类二是宽高必须除以img_w和img_h做归一化漏了这一步框的坐标会整体偏移mAP直接崩。标注质量检查也是必要环节。转完格式后跑一遍脚本检查每个txt是否为空、坐标是否超出[0,1]范围、类别索引是否越界。yolov5训练自己的数据集时如果报“Label shape”错误多半就是标签文件里混了空行或异常坐标。2.3 数据划分与增强别让train和val穿帮划分数据集有一条红线同一道焊缝在不同角度下的多张照片不能同时出现在train和val里。YOLOv5如果没有自定义划分默认随机分配很容易把同一工件不同帧分到两边。结果模型在val上看到的都是“见过的场景”mAP虚高一到产线就打回原形。我一般按“工件/焊缝”维度手动划分先列一个工件清单按8:1:1的比例分成train/val/test然后按清单把图片和标签拷贝到对应目录。目录结构按YOLOv5约定dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/下面这段脚本按文件名前缀假设前缀就是工件编号做分组划分import os, random, shutil random.seed(42) imgs_dir raw_images train_dir dataset/images/train val_dir dataset/images/val test_dir dataset/images/test os.makedirs(train_dir, exist_okTrue) os.makedirs(val_dir, exist_okTrue) os.makedirs(test_dir, exist_okTrue) images os.listdir(imgs_dir) groups {} for img in images: key img.split(_)[0] # 假设文件名是 工件号_序号.jpg groups.setdefault(key, []).append(img) keys list(groups.keys()) random.shuffle(keys) n len(keys) for k in keys[:int(n*0.8)]: for img in groups[k]: shutil.copy(os.path.join(imgs_dir, img), os.path.join(train_dir, img)) for k in keys[int(n*0.8):int(n*0.9)]: for img in groups[k]: shutil.copy(os.path.join(imgs_dir, img), os.path.join(val_dir, img)) for k in keys[int(n*0.9):]: for img in groups[k]: shutil.copy(os.path.join(imgs_dir, img), os.path.join(test_dir, img)) print(划分完成:, len(os.listdir(train_dir)), len(os.listdir(val_dir)), len(os.listdir(test_dir)))参数说明random.seed(42)保证每次运行划分结果一致分组键是文件名第一个下划线前的部分如果你的命名规则不同需要改成对应的逻辑。这里用按工件分组而不是按图片随机为的是避免数据泄露。labels目录要按同样逻辑拷贝一份拷完检查同名对应import os for split in [train, val, test]: imgs set(f.split(.)[0] for f in os.listdir(fdataset/images/{split})) labels set(f.split(.)[0] for f in os.listdir(fdataset/labels/{split})) print(split, 缺标签:, imgs - labels, 缺图:, labels - imgs)数据增强方面YOLOv5训练时自带mosaic、翻转、HSV色彩扰动等增强一般情况下不用提前手动增强。需要留意的是fliplr这个参数对方向性缺陷有影响咬边沿焊缝方向延伸水平翻转后形态还是咬边但如果你把图片旋转90度咬边可能变成类似裂纹的形态模型会混乱。所以在hyp.yaml里fliplr保持0.5没问题但不要开rotate。3. 训练焊缝检测模型预训练权重、超参数与收敛判断数据集就绪后进入训练环节。建议直接用YOLOv5官方仓库的v6.0或v7.0版本安装依赖时注意PyTorch版本和CUDA版本匹配。训练阶段最大的变量是权重选择和超参数配置下面逐个说。3.1 预训练权重怎么选yolov5s.pt起步而不是从零训练先给结论除非你有上万张焊缝图否则用yolov5s.pt做预训练权重比从零训练收敛更快、精度也更高。焊缝缺陷在纹理和边缘特征上与COCO里的物体有共通之处预训练权重已经把底层特征提取器训练好了迁移到焊缝场景只需要微调。三个常见档位权重文件模型体积推理速度参考适用场景yolov5s.pt14MB左右最快产线实时检测、CPU推理yolov5m.pt40MB左右中等精度要求更高、有GPUyolov5l.pt90MB左右较慢离线检测、追求极致精度焊缝表面缺陷通常不算超小目标s或m就够用。如果你用s训练后mAP_0.5不到0.9换m往往有25个点的提升代价是推理速度下降约一半。先跑s不够再换m别一上来就l调试周期太长。权重下载注意版本匹配YOLOv5的v6.0权重不能用在v5.0的代码上v7.0同理。下载后放到weights目录训练时通过--weights指定路径。离线环境需要手动下载pt文件传到服务器可以用下面这段快速验证权重没损坏import torch ckpt torch.load(yolov5s.pt, map_locationcpu) print(ckpt[model].type)能打印出模型类型说明文件完整。如果报错KeyError多半是下到了不完整文件或版本不对。3.2 训练命令与关键超参数调优数据集准备好后在YOLOv5根目录下创建一个dataset.yamltrain: dataset/images/train val: dataset/images/val test: dataset/images/test nc: 4 names: [porosity, undercut, overlap, spatter]训练命令如下python train.py \ --data dataset.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 200 \ --workers 4 \ --device 0 \ --project runs/train_weld \ --name weld_s_640命令参数说明data指向刚建的yamlweights是预训练权重路径从零训练改成--weights img是输入分辨率640是平衡点缺陷偏小可以上1280但显存和训练时间翻倍batch由显存决定RTX 3060 12G跑s640batch 16可以显存不够先降到8epochs给200是基准值配合--patience 30自动早停workers在Windows下超过4容易触发DataLoader卡死Linux下可以设8device 0表示第一张GPUCPU训练设cpu但会很慢。第一次训练建议加--cache ram把图片预加载到内存能明显缩短数据读取时间内存只有8G就别开。超参数调整主要动data/hyps/hyp.scratch-low.yaml我一般只改三处lr0: 0.01 # 初始学习率预训练权重下保持默认 mosaic: 1.0 # mosaic增强概率小目标场景保持1.0 fliplr: 0.5 # 水平翻转缺陷有方向性就改成0焊缝缺陷如果有明确方向性比如咬边沿焊缝延伸、裂纹有走向fliplr设为0。否则模型把左右镜像的缺陷当新形态学反而干扰特征。mosaic在目标偏小时效果明显但缺陷只占图像很小区域时mosaic拼接可能把缺陷切成两半这时候可以把mosaic降到0.5试试。3.3 训练过程监控从loss和mAP判断是否收敛训练时开tensorboardpython -m tensorboard.main --logdir runs/train_weld浏览器打开后看三条主线train/box_loss和train/cls_loss应当稳步下降没有剧烈震荡val/box_loss和val/cls_loss不能显著反弹反弹往往意味着过拟合metrics/mAP_0.5:0.95在val上稳步上升后趋于平缓。如果val的loss到后期不降反升原因大概率是样本量不够或类别不均衡。解决顺序先降epochs一半跑一遍看val损失是否稳住仍然过拟合就加合格样本或者把数据增强开大一点比如把mosaic概率从1.0调到1.5YOLOv5支持大于1让模型见过的形态更多。这里有个经验epochs开太大不一定是好事200轮之后val mAP可能不再上升甚至掉点配合早停能省一堆时间。训练结束后runs/train_weld/weld_s_640/weights/下会有best.pt和last.pt两个文件。best.pt是训练过程中val mAP最高的一轮权重后面测试、部署都用它。如果训练中途崩了不要从头跑把last.pt当作--weights传回去续训python train.py --data dataset.yaml \ --weights runs/train_weld/weld_s_640/weights/last.pt \ --epochs 300 --resume注意resume参数会自动接续训练状态不用重新指定batch和name。如果训练平台不支持resume就把last.pt当普通权重加载重新训100轮左右效果差别不大。4. 用PyQt5搭焊缝检测界面把权重文件变成工人能点的按钮模型训练好只是第一步产线上的工人不可能去敲命令行。PyQt5界面在这个方案里承担人机交互层打开图片、选视频、接摄像头、点检测、看结果。4.1 界面结构设计输入区、显示区、结果区我一般把界面分成三块左侧控制区放三个输入按钮“打开图片、打开视频、打开摄像头”和一个“开始检测”按钮右侧显示区用QLabel显示原图和检测结果图底部结果区用QTextEdit显示检测到的缺陷类别、置信度、数量以及综合判定结果合格/不合格。界面骨架代码import sys from PyQt5.QtWidgets import (QWidget, QPushButton, QLabel, QVBoxLayout, QHBoxLayout, QFileDialog, QTextEdit) class WeldDetectorUI(QWidget): def __init__(self): super().__init__() self.setWindowTitle(焊缝质量检测系统) self.setGeometry(200, 200, 900, 600) self.btn_img QPushButton(打开图片) self.btn_video QPushButton(打开视频) self.btn_cam QPushButton(打开摄像头) self.btn_detect QPushButton(开始检测) self.image_label QLabel(显示区域) self.image_label.setMinimumSize(640, 480) self.result_text QTextEdit() self.result_text.setReadOnly(True) left QVBoxLayout() left.addWidget(self.btn_img) left.addWidget(self.btn_video) left.addWidget(self.btn_cam) left.addWidget(self.btn_detect) left.addStretch() right QVBoxLayout() right.addWidget(self.image_label) right.addWidget(self.result_text) layout QHBoxLayout(self) layout.addLayout(left) layout.addLayout(right) self.btn_img.clicked.connect(self.open_image) def open_image(self): path, _ QFileDialog.getOpenFileName( self, 选择图片, , Image Files (*.jpg *.png *.bmp)) if path: self.image_path path self.result_text.append(f已加载图片: {path}) if __name__ __main__: app QApplication(sys.argv) ui WeldDetectorUI() ui.show() sys.exit(app.exec_())逻辑说明这个骨架先搭出左右分区左侧是按钮右侧是显示和结果区。open_image方法只是选图还没接推理。完整的界面里选图后要触发一个推理线程把模型输出画在图上再setPixmap到image_label。QTextEdit作为结果输出框运行状态和检测信息都append进去方便现场查日志。PyQt5环境安装pip install pyqt5 pyqt5-tools如果是在没有显示器的Linux服务器上做界面调试会报“could not connect to display”需要加xvfb或者直接在Windows开发机上做界面。4.2 推理线程设计别让界面卡成“未响应”YOLOv5推理是CPU/GPU密集操作如果直接在按钮的槽函数里同步跑界面会卡住。常见现象是点了“开始检测”窗口立刻无响应过几秒才弹出结果。正确做法是把推理放到QThread里主线程只负责刷新UI。import torch import cv2 from PyQt5.QtCore import QThread, pyqtSignal class DetectThread(QThread): frame_ready pyqtSignal(object, object) # (原图, 结果图) log_msg pyqtSignal(str) def __init__(self, source, parentNone): super().__init__(parent) self.model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, force_reloadFalse) self.model.conf 0.25 self.model.iou 0.45 self.source source def run(self): cap cv2.VideoCapture(self.source) while not self.isInterruptionRequested(): ret, frame cap.read() if not ret: break results self.model(frame) plotted results.render()[0] # 画好框的BGR图 self.frame_ready.emit(frame, plotted) self.log_msg.emit(f检测到 {len(results.pandas().xyxy[0])} 个目标) cap.release()逻辑说明DetectThread在run里循环读视频帧、执行推理、发信号。frame_ready信号把原图和画好框的结果图传回主线程主线程负责把结果转成QPixmap显示。关键参数是model.conf和model.iou分别控制置信度阈值和NMS的IoU阈值现场调参主要就是动这两个值第6章会细说。提示torch.hub.load第一次运行时会克隆YOLOv5仓库到本地缓存。离线部署环境建议直接把YOLOv5源码目录拷贝到现场用sys.path.insert把仓库路径加进去或者干脆cd到仓库目录再执行。每次new线程都重新load模型太慢更稳的做法是把模型做成全局单例多个线程共用model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, force_reloadFalse) class DetectThread(QThread): def run(self): # 直接用全局model不再load results model(frame)4.3 结果显示与综合判定不只看框还要给结论检测框画出来后界面还要能回答“这工件合格吗”。判定逻辑我一般写在界面层或一个独立的判断函数里def judge_weld(results, threshold_qty3): df results.pandas().xyxy[0] if df.empty: return 合格, 0 counts df[name].value_counts().to_dict() total len(df) # 简单规则缺陷总数超过阈值或者存在裂纹类判不合格 if total threshold_qty or counts.get(crack, 0) 0: return 不合格, total return 合格, total参数说明threshold_qty是可配置的产量判定阈值不同工艺标准不同。比如某个工位的标准是“表面气孔不超过2个且不允许有裂纹”那缺陷总数大于2或出现裂纹就直接判不合格。这个规则需要和工艺工程师对齐不要让算法工程师自己拍脑袋。界面显示时给“不合格”三字加红色背景“合格”加绿色背景工人扫一眼就能知道结果。如果现场要求统计每天的合格率可以把检测结果写进SQLite或CSV界面加一个“导出报表”按钮。PyQt里写文件用QFile或Python的open都行关键是把时间、工件编号、检测结果关联起来方便追溯到具体批次。5. 焊缝检测部署避坑指南5个高频问题与排查方法进入这个章节说明你已经跑通流程了。但现场部署和实验室跑通是两个世界以下5个问题是大多数焊接场景都会遇到的坑每一条按现象-原因-解决来写。5.1 显存溢出训练到一半OOM现象train.py跑了几十步报CUDA out of memory进程直接崩。原因显存被一次性占用过大常见于batch_size过大、输入分辨率太高或开着太多其他程序。焊缝图如果现场是用500万像素工业相机拍的训练时不resize到640直接按原图尺寸训练几轮就爆。解决先把batch降到8img降到640。如果还爆把数据集里的图片统一压缩成短边不超过1280再训练。另外确认训练时没有其他程序占用GPUnvidia-smi如果显存还剩很多却报OOM再查PyTorch和CUDA版本是否匹配。常见组合是PyTorch 1.13 CUDA 11.7换成PyTorch 2.0后需要重新安装匹配的CUDA运行时。5.2 训练正常但val的mAP特别低现象loss曲线正常下降val mAP_0.5却不到0.5远低于预期。原因大概率是数据集划分穿帮或标注错误。比如标注时框的类别标反了或val里混进大量“合格”样本模型在val上看到的都是没缺陷的图检出的框都被算成误检。解决先用脚本抽检标注质量把标注框画回原图人工核对import cv2, os label_dir dataset/labels/train img_dir dataset/images/train os.makedirs(check, exist_okTrue) for f in sorted(os.listdir(label_dir))[:20]: txt_path os.path.join(label_dir, f) img_path os.path.join(img_dir, f.replace(.txt, .jpg)) img cv2.imread(img_path) if img is None: continue for line in open(txt_path): cls, cx, cy, w, h map(float, line.split()) x1 int((cx - w / 2) * img.shape[1]) y1 int((cy - h / 2) * img.shape[0]) x2 int((cx w / 2) * img.shape[1]) y2 int((cy h / 2) * img.shape[0]) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(fcheck/{f.replace(.txt, .jpg)}, img) print(已输出20张抽检图到check目录)把抽检图和原图对比看框是否贴合目标、类别是否标反。修正标注后重新划分并训练。5.3 PyQt界面点击按钮后卡死现象界面点了“打开视频”窗口变成白色或显示“未响应”等几秒才恢复。原因推理在UI主线程同步执行cv2.VideoCapture.read()和model(frame)阻塞了事件循环。视频源如果是网络摄像头或RTSP流阻塞更明显。解决把推理逻辑挪进QThread参考4.2节。另外注意VideoCapture读取RTSP流时要设置超时否则断流时cap.read()会一直阻塞cap cv2.VideoCapture(rtsp_url) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 只保留最新帧 cap.set(cv2.CAP_PROP_OPEN_TIMEOUT_MSEC, 2000) cap.set(cv2.CAP_PROP_READ_TIMEOUT_MSEC, 2000)线程里加一个stop_flag界面关闭时主动停止线程不然程序退出时线程还在跑会导致QApplication崩溃。5.4 小缺陷漏检焊缝上细小气孔检不出来现象大块咬边、焊瘤都能检测到但直径1mm以下的气孔经常漏检有时还出现时有时无的情况。原因缺陷在640×640输入下占的像素数太少特征经过下采样后基本丢失。另外NMS阈值设置过高也可能把相邻的低置信度框滤掉。解决分两步。第一步把输入分辨率从640提到1280训练和推理都改mAP一般有515个点的提升第二步在推理时把conf阈值调低到0.150.25配合“小目标放大”逻辑检测前先把焊缝区域裁剪出来放大两倍再送进模型。这个技巧在生产线上很常用代价是推理时间稍长对PC端来说完全可接受。如果还漏检回到数据集把标注时小于10×10像素的框删掉重标。标注框太小意味着框的位置本身也不准模型学的是噪声而不是特征。5.5 环境问题torch.hub.load加载老权重报错现象用torch.hub.load加载别人给的best.pt报错KeyError或RuntimeError。原因权重文件是用不同YOLOv5版本训练出来的代码和权重的key不匹配。最常见的是v5.0和v6.0混用。解决训练和推理用同一份YOLOv5源码目录把权重放到训练时的仓库里推理而不是换一个最新版仓库。如果必须用新代码加载旧权重先跑官方提供的迁移脚本或者重新导出# 在训练时的仓库里重新导出ONNX import torch model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt) model.export(formatonnx)导出后的onnx文件可以用onnxruntime加载不依赖YOLOv5仓库部署更轻。不过这属于新工程统一版本始终是更省事的方案。6. 现场验证与阈值调优把模型装到工位前的最后一步6.1 用回放测试确定conf阈值模型在现场的表现和val集上往往有差距主要因为现场光照、工件批次不同。我习惯在正式上线前做一轮回放测试找一台现场电脑把采集的工件图批量跑一遍统计不同conf阈值下的误检和漏检数量画一张简表conf漏检数误检数总耗时0.102154.3s0.25554.1s0.401114.0s选一个误检和漏检的平衡点一般取0.20.3之间。如果有把握通过后处理规则排除部分误检conf可以再调低。这个测试回归通常半天以内能完成。6.2 把判定规则和界面结果联动界面不能只显示“检测到3个目标”要能把“3个气孔、1处咬边”这样的信息对应到工艺判定规则。我在4.3节的judge_weld函数基础上把阈值做成界面可配置项。工艺人员调整标准时不用改代码直接在界面里输入“气孔2”或“裂纹出现”这种规则就行。我自己的习惯是模型只负责“看见”缺陷规则负责“判断”好坏。把这两个逻辑分开模型换权重不影响规则规则改标准不需要重训模型边界清晰。现场参数调好后及时把best.pt、推理脚本、依赖版本和训练数据打包归档。焊缝检测的痛点是不同批次工件差异大隔几个月工艺一改还得翻出老数据集重新训练没有备份就只能从头拍。做完这一步这套方案才算真正闭环希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →