【深度学习项目实战·23】图像异常检测:用自编码器重建误差识别类别外样本

文章目录

01 本篇要解决什么问题

前面的监督任务通常给每个训练样本标明类别。如果手头主要有"正常样本",能否先学习正常图像,再把不熟悉的输入找出来?

本篇以Fashion-MNIST的一类服装为正常,其他类别为异常,用卷积自编码器学习重建正常图,再把每张图的重建误差作为异常分数。

  • 本篇关键词:自编码器、瓶颈表示、正常类训练、异常分数、验证阈值、AUROC。
  • 完成标志:只用正常类更新参数,完成验证选模型、阈值校准和固定阈值测试。
  • 场景边界:这是类别外识别练习,不是带像素缺陷标注的工业异常检测基准。

02 背景:异常标签的含义由任务定义决定

Fashion-MNIST作者项目提供28×28灰度服装图,官方训练60000张、测试10000张。这里默认类别0,即T-shirt/top,作为正常;其余九类记为异常。

原始服装标签与新任务标签不同:原始类别用于查数据,新的异常标签固定为正常0、异常1。模型不再输出十类概率,而是先重建输入,再计算一个分数。

从官方训练集按类别划出10%验证数据,默认得到5400张正常训练图、6000张混合验证图;官方10000张测试图保留,其中正常1000、异常9000。混合验证集用于阈值校准,因此完整流程并不是完全不使用异常标签。

03 实操:把训练、选模型与定阈值分开

(1)只让正常图参与反向传播

powershell 复制代码
python examples/download_data.py --dataset fashion

下载使用作者维护的HTTPS资源,Torchvision检查资源MD5。若前面第13篇的数据已经存在,可把--data指向相同根目录。

训练集合先从原始训练数据中划出,再筛出正常类;测试图不会被放回训练。完整的源索引与正常类别会保存在split_manifest.json,便于检查是否存在集合交叉。

(2)瓶颈结构让模型学习受限重建

编码器把28×28图像压到低维向量,解码器把它还原到原尺寸。默认通道16、潜变量32,输出Sigmoid限定到0~1。

python 复制代码
import torch
from torch import nn
from torch.nn import functional as F

class Autoencoder(nn.Module):
    def __init__(self,width=16,latent=32):
        super().__init__()
        self.encoder=nn.Sequential(nn.Conv2d(1,width,3,2,1),nn.ReLU(),
                                   nn.Conv2d(width,width*2,3,2,1),nn.ReLU(),nn.Flatten(),
                                   nn.Linear(width*2*7*7,latent))
        self.fc=nn.Linear(latent,width*2*7*7)
        self.decoder=nn.Sequential(nn.ConvTranspose2d(width*2,width,4,2,1),nn.ReLU(),
                                   nn.ConvTranspose2d(width,1,4,2,1),nn.Sigmoid())
        self.width=width

    def forward(self,x):
        z=self.fc(self.encoder(x)).reshape(-1,self.width*2,7,7)
        return self.decoder(z)

这里没有从输入直接跨到输出的长跳跃连接,避免轻易复制全部输入。瓶颈只是建模选择,并不保证"只会重建正常图":网络仍可能把某些类别外样本重建得很好。

(3)重建损失与样本分数的归约不同

训练时:

python 复制代码
reconstruction = model(normal_images)
loss = torch.nn.functional.mse_loss(reconstruction, normal_images)

推理时,需要为每个样本单独计算平均误差:

python 复制代码
scores = (reconstruction - images).square().mean(dim=(1, 2, 3))

第二种写法保留batch维,输出[N]。如果直接对全部维度求平均,会把一批图压成一个数字,无法再逐图排序或判断。

分数越大越倾向异常。这个方向必须与AUROC、阈值判断和日志保持一致,不能一处取相反数,另一处仍按原方向解释。

(4)选模型只看正常验证重建误差

每轮在验证集推理,取其中正常样本的平均MSE,越低越好,保存为best.pt。这一步不以测试AUROC挑轮次,也不让异常验证图参与参数更新。

读取最优权重后,才在混合验证集上选择异常判别阈值。本版遍历验证分数对应的候选阈值,使异常类别F1最大;并列保留更大的阈值。

阈值规则固定为score >= threshold判异常,并写入检查点。测试阶段直接读取,不重新寻找一个使测试结果更漂亮的阈值。

(5)AUROC与固定阈值指标各有作用

AUROC接口说明对应的是连续分数的排序评价。本工程用平均秩处理相同分数,自行实现二分类AUROC;标签只有一类时返回null。

同时报告固定阈值下的Precision、Recall、F1与TP/FP/FN/TN。AUROC不能告诉我们某个阈值下会误报多少,F1又会受异常比例影响,二者应该结合使用。

小规模检查会让验证、测试的正常和异常各占一半,以保留两类;完整数据是1:9。因此小规模F1不能直接外推到完整数据或现实业务异常比例。

图:原创示意。正常训练、正常验证选权重、混合验证定阈值分别承担不同作用。

04 一个具体例子:把一张新图变成异常判断

小规模运行:

powershell 复制代码
python examples/train_anomaly.py --epochs 2 --width 4 --latent 8 --limit-train 64 --limit-val 40 --limit-test 40
python examples/visualize_run.py --run artifacts/23_anomaly

完整教学配置的起点:

powershell 复制代码
python examples/train_anomaly.py --epochs 20 --normal-class 0 --output artifacts/23_anomaly_full

数据不大,可以先用CPU;有GPU可追加--device cuda。主入口如下,阈值与评价实现全文见公共代码附录。

python 复制代码
"""Chapter23: normal-only AE training, mixed-validation threshold calibration."""
from vision_train import parser_for,train_project

if __name__=='__main__':
    train_project('anomaly',parser_for('anomaly','artifacts/23_anomaly').parse_args())

准备一张与Fashion-MNIST显示约定相近的服装图后:

powershell 复制代码
python examples/predict_image.py --checkpoint artifacts/23_anomaly/best.pt --image data/my_fashion.png --output artifacts/23_predict

脚本转为灰度28×28,输出重建图、误差数组、score、threshold和is_anomaly。误差图可帮助查看重建差异,但这里没有像素级缺陷监督,不能把高误差区域自动解释为真实缺陷定位。

出现高误差时,还应检查背景、尺度、亮度与预处理是否偏离训练分布;它们同样会造成模型不熟悉的输入。改变正常类、图像范围或模型权重后,应重新在验证集校准阈值。

05 常见问题与自测

问题1:异常图片可以混进训练一起重建吗?

本篇的假设是正常类训练,混入异常会改变任务设置,需要另行说明。

问题2:MSE很大就一定有工业缺陷吗?

不能这样解释。这里的异常按服装类别定义,重建误差也可能受输入分布变化影响。

问题3:为什么不能在测试集上选阈值?

测试就参与了决策调节,结果不再反映固定模型与规则的独立评价。

问题4:AUROC高,固定阈值F1为什么可能低?

排序能力、阈值位置和类别比例是不同因素,需要分别分析。

问题5:这套流程完全没有用异常标签吗?

训练参数只用正常图,但混合验证阈值校准使用异常标签,应如实说明。

06 本篇回顾与下一步

异常检测不仅是"训练一个自编码器",还包括分数方向、阈值来源和集合边界。将三者写清楚,结果才有可解释的使用条件。

中文 常见英文或写法
自编码器 Autoencoder / AE
瓶颈表示 Bottleneck Representation
异常分数 Anomaly Score
阈值校准 Threshold Calibration

下一篇从重建已有输入,转向从随机潜变量生成新数字图像。

相关推荐
小和尚同志10 分钟前
阿里大佬做的一款轻量化 Token 监控工具—知度 Tokei
人工智能·aigc·监控
墨林陌11 分钟前
AI 热点日报(2026-11-11):OpenAI季度营收破百亿美元,Anthropic双模型+IPO齐发,英伟达遭集体诉讼
人工智能
风巽·剑染春水14 分钟前
【Generative AI综述】生成式人工智能在医学影像中的应用(ACME-2026)
人工智能·transformer·gan·vae·生成模型·扩散模型·医学影像
数字孪生视频孪生1 小时前
在线重构,实时同步:视频动态三维重建打造 “常更常新” 的数字底座
大数据·人工智能·重构·架构·空间计算
CyrusYiVPP1 小时前
手写 MCP Server:给问答机器人接上本地文件工具,Python 实战第 13 期
人工智能·python
狂师1 小时前
Agent评测工具链大全:Promptfoo、DeepEval 与 LangSmith
人工智能·agent·测试
kaixin_啊啊1 小时前
【零基础学AI】第 28 章——大语言模型怎样训练出来
人工智能·语言模型·自然语言处理
Aloudata1 小时前
Claude 做数据分析的这两年:一份复盘与发展线索
大数据·数据库·人工智能·数据挖掘·数据分析·dataagent
前进的李工1 小时前
Agent 学习笔记 12:Agent 的工具应该怎么设计
人工智能·笔记·学习·agent·工具调用·skill·工具设计