首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >工业质检的“四座大山”:样本少、不平衡、拍不全、导入慢——YOLO+无监督组合拳,漏检率直降96%

工业质检的“四座大山”:样本少、不平衡、拍不全、导入慢——YOLO+无监督组合拳,漏检率直降96%

原创
作者头像
AI小怪兽
修改2026-04-01 12:33:47
修改2026-04-01 12:33:47
3570
举报
文章被收录于专栏:毕业设计毕业设计YOLO大作战

工业缺陷检测实战:一套组合拳,让漏检率直降96%,导入周期缩短80%

有监督+无监督双引擎驱动,误漏判双降,年省成本超400万

大家好,我是AI小怪兽

深耕计算机视觉与深度学习领域多年,我始终专注于视觉检测前沿技术的探索与突破,长期致力于YOLO系列算法的结构性创新、性能极限优化与工业级落地实践。今天想和大家分享一个我主导的工业缺陷检测项目,聊聊我们如何打通从学术研究到产业应用的“最后一公里”。

本文伪代码如下:

代码语言:py
复制
"""
工业缺陷检测双引擎方案
作者:AI小怪兽
技术栈:YOLOv8 (有监督) + PatchCore (无监督) + 模拟光学成像数据增强
功能:1. 仅用良品图像训练无监督模型(快速冷启动)
      2. 利用模拟光学成像增强少量缺陷样本,训练YOLO模型
      3. 双引擎协同推理,输出最终检测结果
依赖:pip install ultralytics albumentations anomalib opencv-python torch
"""

import cv2
import numpy as np
import albumentations as A
from albumentations.pytorch import ToTensorV2
import torch
from ultralytics import YOLO
from anomalib.models import Patchcore
from anomalib.data import Folder
from anomalib.engine import Engine
from pathlib import Path

# ======================== 配置参数 ========================
GOOD_IMG_DIR = "./datasets/good"           # 良品图像目录
DEFECT_DIR = "./datasets/defect"           # 缺陷图像目录(按类别分文件夹,如 defect/scratch/)
YOLO_DATA_YAML = "dataset.yaml"            # YOLO数据集配置文件
PATCHCORE_CKPT = "patchcore_model.ckpt"    # 无监督模型保存路径
YOLO_MODEL_PATH = "yolov8n_custom.pt"      # 训练后的YOLO模型路径
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
IMG_SIZE = 640

# ======================== 1. 模拟光学成像数据增强 ========================
def get_optical_augmentation():
    """返回模拟光学成像的增强流水线(仅训练时使用)"""
    return A.Compose([
        # 光照变化
        A.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, p=0.5),
        A.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=20, val_shift_limit=10, p=0.5),
        # 镜头畸变(透视变换)
        A.Perspective(scale=(0.05, 0.1), p=0.3),
        # 材质反光(模拟高光)
        A.RandomSunFlare(flare_roi=(0, 0, 1, 0.5), src_radius=100, p=0.3),
        # 成像噪声
        A.GaussNoise(var_limit=(10.0, 50.0), p=0.4),
        A.MotionBlur(blur_limit=5, p=0.3),
        # 保证输出尺寸一致
        A.Resize(IMG_SIZE, IMG_SIZE),
    ])

# ======================== 2. 无监督异常检测模型训练(PatchCore) ========================
def train_unsupervised():
    """仅使用良品图像训练无监督模型,实现零缺陷样本冷启动"""
    print(">> 开始训练无监督模型(PatchCore)...")
    # 数据模块:只读取良品图像
    datamodule = Folder(
        name="industrial_good",
        root="./datasets",
        normal_dir="good",
        task="segmentation",           # 输出像素级异常图
        image_size=(IMG_SIZE, IMG_SIZE),
    )
    model = Patchcore(
        backbone="resnet50",
        pre_trained=True,
        coreset_sampling_ratio=0.1,
    )
    engine = Engine(device=DEVICE)
    engine.fit(datamodule=datamodule, model=model)
    engine.save_checkpoint(PATCHCORE_CKPT)
    print(f"无监督模型已保存至 {PATCHCORE_CKPT}")

# ======================== 3. YOLOv8 训练(自定义数据集,嵌入模拟光学成像增强) ========================
# 3.1 自定义YOLO数据集类,覆盖数据增强方法
from ultralytics.yolo.data.dataset import YOLODataset

class OpticalAugYOLODataset(YOLODataset):
    """在YOLO数据集基础上增加模拟光学成像增强"""
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.optical_aug = get_optical_augmentation()

    def load_image(self, i, rect_mode=True):
        """加载图像并应用模拟光学成像增强(仅训练阶段)"""
        img, (h0, w0), (h, w) = super().load_image(i, rect_mode)
        if self.augment:
            # 应用我们的光学模拟增强
            augmented = self.optical_aug(image=img)
            img = augmented["image"]
        return img, (h0, w0), (h, w)

def train_yolo():
    """使用少量缺陷样本 + 模拟光学成像增强训练YOLOv8"""
    print(">> 开始训练YOLOv8(有监督)...")
    # 替换默认的数据集类
    from ultralytics.yolo.data import build_dataset
    build_dataset.YOLODataset = OpticalAugYOLODataset

    model = YOLO("yolov8n.pt")
    model.train(
        data=YOLO_DATA_YAML,
        epochs=100,
        imgsz=IMG_SIZE,
        batch=16,
        device=DEVICE,
        augment=True,                  # 启用增强(会调用我们的custom dataset)
        patience=10,
        save=True,
        project="runs/train",
        name="yolo_optical_aug",
    )
    # 保存最终模型
    model.save(YOLO_MODEL_PATH)
    print(f"YOLO模型已保存至 {YOLO_MODEL_PATH}")

# ======================== 4. 双引擎协同推理 ========================
class DualEngineInference:
    """加载两个模型,协同进行缺陷检测"""
    def __init__(self, yolo_path, patchcore_ckpt):
        self.device = DEVICE
        self.yolo = YOLO(yolo_path)
        # 加载无监督模型
        self.anomaly_model = Patchcore.load_from_checkpoint(patchcore_ckpt)
        self.anomaly_model.eval()
        self.anomaly_model.to(self.device)

    def predict(self, image_path):
        """对单张图像进行检测,返回 (缺陷类别, 置信度, 异常区域mask)"""
        img = cv2.imread(image_path)
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        orig_h, orig_w = img.shape[:2]

        # 步骤1:YOLO检测已知缺陷
        yolo_results = self.yolo(img_rgb, imgsz=IMG_SIZE, conf=0.25, device=self.device)[0]
        yolo_defects = []   # 存储 (bbox, cls_name, conf)
        for box in yolo_results.boxes:
            cls_id = int(box.cls[0])
            conf = float(box.conf[0])
            cls_name = self.yolo.names[cls_id]
            bbox = box.xyxy[0].cpu().numpy().astype(int)
            yolo_defects.append((bbox, cls_name, conf))

        # 步骤2:无监督异常检测(像素级)
        # 需要将图像调整为模型输入尺寸
        input_tensor = self._preprocess_for_anomaly(img_rgb)
        with torch.no_grad():
            predictions = self.anomaly_model(input_tensor)
        anomaly_map = predictions["anomaly_map"].squeeze().cpu().numpy()  # (H, W)
        # 阈值判断是否有未知异常(可根据实际调整)
        unknown_anomaly = np.any(anomaly_map > 0.5)   # 0.5为经验阈值
        if unknown_anomaly:
            # 生成二值mask用于定位
            mask = (anomaly_map > 0.5).astype(np.uint8) * 255
            # 可以再根据mask寻找轮廓等,这里简化为整体标记
            unknown_defect = ("unknown", 1.0, mask)
        else:
            unknown_defect = None

        return {
            "yolo_defects": yolo_defects,
            "unknown_defect": unknown_defect,
            "anomaly_map": anomaly_map
        }

    def _preprocess_for_anomaly(self, img_rgb):
        """将图像转换为模型输入格式(归一化、tensor等)"""
        # 假设无监督模型输入尺寸与训练时一致(这里是IMG_SIZE)
        img = cv2.resize(img_rgb, (IMG_SIZE, IMG_SIZE))
        img = img.astype(np.float32) / 255.0
        img = torch.from_numpy(img).permute(2, 0, 1).unsqueeze(0)
        return img.to(self.device)

# ======================== 5. 主流程示例 ========================
if __name__ == "__main__":
    # 第一步:训练无监督模型(仅需良品图像,若已存在可跳过)
    # train_unsupervised()

    # 第二步:训练YOLO模型(需要少量缺陷样本+标注)
    # train_yolo()

    # 第三步:加载双引擎进行推理演示
    detector = DualEngineInference(YOLO_MODEL_PATH, PATCHCORE_CKPT)
    test_image = "./test_images/sample.jpg"
    result = detector.predict(test_image)

    print("YOLO检测到的已知缺陷:")
    for bbox, cls, conf in result["yolo_defects"]:
        print(f"  - {cls}: confidence={conf:.2f}, bbox={bbox}")

    if result["unknown_defect"]:
        cls, conf, mask = result["unknown_defect"]
        print(f"无监督模型发现未知缺陷: {cls}, confidence={conf:.2f}, mask区域已定位")
    else:
        print("无监督模型未发现异常")

# ======================== 说明 ========================
"""
关键点:
1. 模拟光学成像增强:通过albumentations模拟光照、畸变、反光、噪声,使YOLO模型对“拍不全”问题鲁棒。
2. 无监督模型仅用良品图像训练,快速上线,自动积累未知缺陷样本。
3. 双引擎协同:YOLO负责已知缺陷分类,无监督负责兜底未知缺陷,形成闭环。
4. 通过自定义YOLO数据集类,完美嵌入光学增强,无需修改ultralytics内核。
"""

一、缺陷检测的四大“拦路虎”

在深入项目之前,先说说工业缺陷检测普遍面临的四个核心痛点:

1. 缺陷样本稀缺——巧妇难为无米之炊

产线良品率往往在99%以上,缺陷样本可遇不可求。以某电子元器件产线为例,每天产出10万件产品,真正有缺陷的可能不到50件。有些缺陷几个月才出现一次,等收集到足够样本,黄花菜都凉了。这种样本稀缺性,是工业缺陷检测面临的首要挑战。

2. 样本分布失衡——数据的天平严重倾斜

即便收集到了一些缺陷样本,各类缺陷的数量也极不均衡:

  • 划痕缺陷:100个样本
  • 脏污缺陷:30个样本
  • 裂纹缺陷:仅5个样本
  • 毛刺缺陷:仅2个样本

传统分类模型在这种极度不平衡的数据上训练,往往会“无视”样本量少的缺陷类别,导致漏检率居高不下。

3. 缺陷成像不全——视角的局限性

工业相机拍摄时,受限于光照条件、拍摄角度、产品摆放位置等因素,同一个缺陷在不同图像中可能呈现完全不同的形态。金属表面的高反光、镜头畸变、运动模糊……这些光学干扰让缺陷“拍不全”甚至“拍不到”,模型难以学到稳定的特征。

4. 导入周期长——从立项到上线的漫长征途

这是很多企业容易忽视但实际非常痛的一点。传统AI质检项目从启动到上线,往往需要经历:缺陷样本收集(数月)→ 数据标注(数周)→ 模型训练调优(数周)→ 现场调试(数周)→ 产线验证(数周)。一套流程走下来,少则3-6个月,多则一年以上。等到模型上线,产品可能已经迭代,产线工艺已经变化,之前的缺陷样本又“过期”了。这种长周期严重制约了企业的敏捷响应能力。

二、破解之道:双引擎驱动方案

针对这四大痛点,我们设计了一套“有监督+无监督”的双引擎方案,核心思路是:用无监督快速冷启动,用有监督持续精进,将导入周期从数月压缩至数周

引擎一:YOLO + 模拟光学成像

有监督部分我们采用YOLO系列算法,但关键在于数据增强的创新模型结构的深度优化

在本次项目中,我们重点应用了以下策略:

模拟光学成像数据增强——传统数据增强只是简单旋转、缩放,我们则引入了更贴近工业场景的增强策略:

  • 模拟光照变化:调整亮度、对比度、色温,模拟不同工位的光照条件
  • 模拟镜头畸变:添加径向畸变、透视变换,还原不同相机的成像差异
  • 模拟材质反光:针对金属、塑料等材质,模拟高光、漫反射等光学特性
  • 模拟成像噪声:添加高斯噪声、运动模糊,覆盖实际产线的成像质量波动

这套策略让有限的小样本缺陷,能够“生成”出多种光学条件下的变体,模型学到的特征更加鲁棒,大幅提升对“拍不全”问题的适应能力。

同时配合迁移学习Focal Loss,进一步缓解样本失衡问题,让模型更加关注难分类的缺陷样本。

引擎二:HiAD + BGAD 无监督检测

有监督能解决已知缺陷,但未知缺陷才是真正的“暗雷”。更重要的是,无监督检测成为缩短导入周期的关键突破口——因为它仅需良品图像训练,无需等待缺陷样本积累。

我们引入两个前沿的无监督异常检测算法:

  • HiAD(Hierarchical Anomaly Detection):构建多层次特征比对体系,同时捕捉全局结构异常和局部纹理异常,特别适合精密零部件检测场景。
  • BGAD(Boundary-Guided Anomaly Detection):利用边界引导机制精准定位缺陷区域,对缺陷边缘特征极为敏感,解决传统方法“找不准、定不到位”的痛点。

核心优势:

  • 仅需良品图像训练,彻底解决缺陷样本稀缺问题,项目启动即可采集数据,无需等待缺陷出现
  • 发现未知缺陷,能检测出训练集中从未出现过的新型缺陷
  • 像素级定位,为后续工艺改进提供精准依据

双引擎协同:导入周期缩短80%的秘密

实际部署中,两套引擎各司其职,更重要的是我们重构了项目导入流程:

传统模式(3-6个月): 收集缺陷样本 → 标注 → 训练 → 调优 → 上线

双引擎模式(4-6周):

  1. 第1-2周:采集良品图像,训练HiAD/BGAD无监督模型,快速上线“初版”系统(无需缺陷样本)
  2. 第3-4周:无监督模型在生产中积累未知缺陷样本,经人工确认后形成标注数据集
  3. 第5-6周:训练YOLO有监督模型,与无监督模型双轨运行
  4. 持续迭代:无监督持续发现新缺陷 → 回流至YOLO训练集 → 两模型同步进化

这套流程的核心优势在于:无监督模型让系统在“零缺陷样本”的情况下就能上线运行,边生产边学习,彻底打破了“先收集缺陷再上线”的传统路径依赖

在具体运行时:

  • 第一道防线(YOLO):快速识别已知缺陷,给出具体缺陷类别
  • 第二道防线(HiAD/BGAD):对YOLO判良的产品深度筛查,捕捉未知异常
  • 反馈闭环:无监督发现的未知缺陷,经人工确认后回流到YOLO训练集,持续进化

这套方案既保证了常见缺陷的精准识别,又弥补了对未知缺陷的漏检风险,真正实现了“已知缺陷分得清,未知缺陷抓得住,项目导入跑得快”。

三、实战案例:笔记本外壳缺陷检测

项目背景

某精密制造企业生产笔记本电脑金属外壳,需检测划痕、变形、凹陷等细微缺陷。传统人工质检痛点突出:

  • 金属表面高反光,缺陷“拍不全”问题严重
  • 缺陷样本稀少,部分缺陷类型从未见过
  • 人员疲劳导致误判漏判频发,不良品流出风险高
  • 传统AI方案评估周期需4个月,企业无法接受

实施过程

第一阶段:成像系统设计(1周) 设计偏振光调控+多光谱融合方案,彻底消除金属反光干扰,确保缺陷“拍得全、拍得清”。

第二阶段:无监督快速冷启动(1周) 采集10万+良品图像,训练HiAD、BGAD双无监督检测体系。仅用1周时间,系统即上线试运行,开始辅助人工质检并积累缺陷样本。

第三阶段:有监督同步训练(第2-4周) 无监督系统运行过程中,持续收集未知缺陷样本,经快速标注后训练YOLO模型。采用模拟光学成像策略扩充有限缺陷样本,专栏中分享的YOLO优化技巧(包括模块改进、损失函数调优等),训练出高精度的YOLO模型。

第四阶段:双引擎协同上线(第5周) 双模型并行部署,设置人机协同机制:高置信度结果自动判定,低置信度及异常报警送人工复核。从项目启动到双引擎正式上线,仅用5周时间,较传统模式缩短80%。

成果展示

核心指标对比:

指标

优化前(人工)

优化后(AI双引擎)

提升幅度

缺陷检出率

92.5%

99.7%

↑7.2%

漏检率

7.5%

0.3%

↓96%

误判率(过杀)

5.8%

1.2%

↓79%

单台设备日均检测量

2,000件

12,000件

↑5倍

质检人力

36人/天

6人/天

减少83%

项目导入周期

4个月

5周

缩短80%

经济收益:

  • 年节约人力成本:原质检团队三班倒共计36人,优化后仅需6人,年节约人力成本约216万元
  • 降低客诉损失:漏检率从7.5%降至0.3%,不良品流出大幅减少,年降低客诉赔偿及返工成本约85万元
  • 提升产线产出:检测速度提升5倍,不再因质检瓶颈限制产能,年增加产出价值约120万元
  • 综合年收益超420万元

业务价值:

  • 产品良率提升3.8%,后端组装质量显著改善
  • HiAD与BGAD双算法并行验证,将未知缺陷漏检风险降至最低
  • 质检数据全流程数字化,为工艺改进提供数据支撑
  • 新产线复制时,导入周期进一步缩短至3周

写在最后

工业缺陷检测的本质是“长尾问题”——20%的常见缺陷加上80%的偶发未知缺陷。单纯依赖有监督学习,永远无法穷尽所有缺陷类型;单纯依赖无监督学习,又难以对已知缺陷精准分类。而传统项目导入的长周期,又让许多企业对AI质检望而却步。

“有监督+无监督”的组合方案,正是破解这一系列困局的关键。 它既保持了YOLO对已知缺陷的精准识别能力,又借助HiAD、BGAD等先进算法构建起未知缺陷的“安全网”,更通过无监督快速冷启动将导入周期从数月压缩至数周,形成一个可持续进化的智能质检系统。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 工业缺陷检测实战:一套组合拳,让漏检率直降96%,导入周期缩短80%
    • 一、缺陷检测的四大“拦路虎”
      • 1. 缺陷样本稀缺——巧妇难为无米之炊
      • 2. 样本分布失衡——数据的天平严重倾斜
      • 3. 缺陷成像不全——视角的局限性
      • 4. 导入周期长——从立项到上线的漫长征途
    • 二、破解之道:双引擎驱动方案
      • 引擎一:YOLO + 模拟光学成像
      • 引擎二:HiAD + BGAD 无监督检测
      • 双引擎协同:导入周期缩短80%的秘密
    • 三、实战案例:笔记本外壳缺陷检测
      • 项目背景
      • 实施过程
      • 成果展示
    • 写在最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档