PyTorch 与视觉检测:从张量到 YOLO 实战的学习笔记

本文整理自课程《PyTorch 与视觉检测》的学习内容,涵盖 PyTorch 核心概念、CNN 卷积神经网络、YOLO 目标检测算法(v1 到 v13),以及一个完整的实战项目——钢铁表面缺陷检测。适合想入门深度学习视觉方向的同学阅读。

一、PyTorch 是什么

1.1 PyTorch = NumPy + GPU

痛点:NumPy 很好用,但只能用 CPU,在大数据面前太慢。

PyTorch 解法:Tensor(张量)用法和 NumPy 几乎一样(ones、zeros、add),唯一的区别是它可以被搬运到显卡(GPU)上跑,速度快几十倍。

import torch

x = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(x)
# tensor([[1., 2., 3.],
#         [4., 5., 6.],
#         [7., 8., 9.]])

x = torch.zeros(3)
print(x)  # tensor([0., 0., 0.])

# 与 NumPy 互转
import numpy as np
a = np.ones(3)
x = torch.from_numpy(a)
print(x)  # tensor([1., 1., 1.], dtype=torch.float64)

1.2 Tensor 常用运算

import torch
x = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 求幂运算
print(x.pow(-1.0))
# tensor([[1.0000, 0.5000, 0.3333],
#         [0.2500, 0.2000, 0.1667],
#         [0.1429, 0.1250, 0.1111]])
print(x.pow(2.0))

# 按列求和
print(x.sum(dim=0))       # tensor([12., 15., 18.])
print(torch.sum(x, 0))    # 等价写法

# 按行求和
print(x.sum(dim=1))       # tensor([ 6., 15., 24.])

# 链式操作 + 对角矩阵
temp = x.sum(dim=1).pow(-1.0)
print(temp)               # tensor([0.1667, 0.0667, 0.0417])
print(temp.diag_embed())
# tensor([[0.1667, 0.0000, 0.0000],
#         [0.0000, 0.0667, 0.0000],
#         [0.0000, 0.0000, 0.0417]])

1.3 torch 内置功能函数

PyTorch 内置了大量函数(torch.nn.functional,通常记作 F):

  • F.conv1d / F.conv2d:对输入信号应用一维/二维卷积
  • F.max_pool1d / F.max_pool2d:1D/2D 最大池化
  • F.relu(input, inplace=False):ReLU 激活函数
  • F.dropout(input, p=0.5, training=True, inplace=False):训练中按概率 p 随机将元素归零,防止过拟合

为什么要用内置函数?

  1. 数学太难:卷积、反向传播的导数公式很难推导,PyTorch 帮我们内置好了。
  2. 性能优化:Python 写循环很慢,这些内置函数底层是 C++ 和 CUDA 写的,速度快几百倍。

1.4 自动求导(Autograd)

痛点:神经网络需要通过"反向传播"更新参数,也就是求梯度,手算微积分太难了。

PyTorch 解法:你只管写前向计算公式(如 y = wx + b),PyTorch 会记录你的操作。调用 .backward(),它自动把所有导数算好。

x = torch.tensor(2.0, requires_grad=True)
y = x ** 2
y.backward()      # 梯度 dy/dx = 2x = 4
print(x.grad)     # tensor(4.)

1.5 动态图(Dynamic Graph)

与静态图框架(如 TensorFlow 1.x,写完要"编译"才能跑,报错看不懂)不同,PyTorch 的计算图是动态的:每次前向传播都会实时构建新图。这使得:

  • 调试更直观,可以逐行执行、单步 Debug
  • 支持灵活的网络结构(循环、条件分支 if/else)
  • 所见即所得,代码中间随便插 print(x) 查看变量

1.6 用 PyTorch 自定义神经网络的步骤

以 Boston 房价预测(数据集:housing.csv)为例:

  1. Step 1:定义网络结构
  2. Step 2:初始化模型参数
  3. Step 3:循环训练:
    • 3.1 执行前向传播
    • 3.2 计算损失函数
    • 3.3 执行反向传播
    • 3.4 权值更新

1.7 多 GPU 与分布式训练

DataParallel(单机多 GPU)——最简单的方式,只需包装模型,数据自动拆分到不同 GPU:

model = nn.DataParallel(model, device_ids=[0, 1])

缺点:主 GPU 负载不均衡,效率较低。

DistributedDataParallel(DDP,多机多 GPU)——更高效的方案,每个 GPU 独立计算梯度再同步聚合:

torch.distributed.init_process_group(backend='nccl')
model = DDP(model, device_ids=[local_rank])

PyTorch Lightning 简化训练:封装了分布式训练的复杂细节,只需一行配置:

trainer = Trainer(accelerator="gpu", devices=4, strategy="ddp")
trainer.fit(model)

1.8 PyTorch vs TensorFlow

维度 TensorFlow (Keras) PyTorch 一句话总结
上手体验 高度封装,model.fit() 一行搞定 逻辑透明,需要手写训练循环 TF 是自动挡车,PyTorch 是手动挡赛车
代码风格 静态图为主(TF2.0 虽支持动态,历史包袱重) 动态图,符合 Python 直觉 TF 像写公文,PyTorch 像写日记
调试难度 报错晦涩,常是巨大报错栈 报错直观,可单步调试
适用场景 工业界落地,TFLite/TF.js 生态强 学术界与大模型,90% 顶会论文、ChatGPT 都用它 进工厂用 TF,进实验室用 PyTorch

二、图像识别与缺陷检测概述

2.1 传统图像识别模型

传统流程:数据获取 → 预处理 → 特征提取 → 决策分类

  • 预处理:滤波、平滑、增强、复原、提取边缘、图像分割等
  • 特征提取:幅度特征、统计特征、几何特征、变换系数特征等,典型如 SIFT 特征

2.2 神经网络时代

  • 视觉是最重要的感知系统,人类大脑皮层中几乎一半神经元与视觉有关
  • ImageNet 数据集超过 1500 万张图像、约 22000 类;ILSVRC 竞赛(2010–2017)使用其 1000 类子集
  • 自 2012 年 AlexNet 取得里程碑式突破后,VGG、GoogLeNet、ResNet、DenseNet、ResNeXt 等网络不断刷新 ImageNet 分类准确率

2.3 视觉检测的两条路线

传统视觉检测:依靠特征工程,制定一系列规则判断检测目标是否符合标准。代表软件:Halcon、VisionPro、OpenCV。

  • 容易提取、好量化的特征:颜色、面积、圆度、角度、长度、宽度、长宽比、形状等
  • 不足:检测对象一变,所有规则和算法都要重新设计;即使同一产品,不同批次也会带来变化

深度学习视觉检测:采用深度神经网络(CNN 是最广泛的模型)。

  • 优势:能应对传统方法难以处理的变量,如照明、颜色变化、曲面、视野变化
  • 不足:数据量要求大,工业数据收集成本高 → 对策:数据增强、无监督学习、自动数据标注

三、缺陷检测方案:一个软硬件结合的系统工程

制定缺陷检测方案需要考虑:

3.1 算法层面

  1. 数据量:能获取多少数据,尤其是缺陷数据
  2. 人工是如何判断的:把人工判异的方法写下来,思考是否有量化指标辅助判断
  3. 是否有类似公开图片:数据不足时可用相似数据做迁移学习

案例:早期新冠病毒肺部 CT 缺陷样本仅 349 张(train 425 / val 118 / test 203),通过使用其他肺部 CT 检测模型做迁移学习,搭建出高准确率模型。

3.2 硬件相关

相机、镜头、光源(安装位置、角度、数量)。

Q:工业相机用黑白还是彩色?
推荐黑白相机:算法基于灰度值处理;相同分辨率下黑白相机精度高许多,对边缘检测及细节瑕疵检测更好。除非以颜色为特征,才用彩色相机。

Q:手机像素高,用手机不行吗?
不行。手机传感器芯片只有小拇指指甲盖大小,而工业相机即使是几百万像素,传感器也有邮票大小。更大的传感器能接受更多光线,同样亮度下工业相机能高速拍照,且在低光照下仍能成像(手机此时已拍不出有效图像)。对比:海康 2000 万像素黑白相机(约 5800 元)vs Redmi Note 9 一亿像素(1499 元)。

3.3 光源的选择

光源类型 特点 比喻 适用缺陷检测类型
环形光(Ring Light) 360 度照射,光照均匀,安装方便,最通用;分高角度(亮视野)和低角度(暗视野) 无影灯 通用外观检测、PCB 板检测、标签字符识别、划痕(低角度)
条形光(Bar Light) 自由度最高,可单条或 2–4 条组合成矩形,自由调整角度(侧打、俯打) 乐高积木 表面不平整检测、大面积划痕、金属表面裂纹
背光(Backlight) 光源在物体背面,相机拍到黑色剪影 皮影戏 尺寸测量、边缘崩缺、孔洞堵塞、引脚缺失
线光(Line Light) 光呈一条极亮的线,配合线阵相机,亮度极高 扫描仪 连续生产的钢板、布匹、玻璃检测,高速滚动圆柱体表面

光照角度:直射光会形成黑色剪影;反射光分镜面反射和漫反射。不仅要选好光源,还要选好放置的距离和角度(调试过程很重要)。

3.4 团队协作

缺陷检测通常由三类人合作完成:

  1. 硬件/打光工程师
  2. 算法工程师
  3. 自动化/PLC 工程师

一个经典经验:图片里缺陷看不清、准确率上不去时——

  • 死磕模型、疯狂调参、加深网络层数 → 结果提升 0.1%
  • 现场换个灯(成本几百块)→ 图片质量提升 50%,代码都不用改,准确率提升 10%

打光往往比调模型性价比高得多。

四、理解 CNN 卷积神经网络

4.1 CNN 的由来

CNN 源于生物学研究。Hubel 和 Wiesel 对猫视觉皮层的研究发现:

  • 视觉皮层细胞对外界输入的局部区域敏感,称为感受野(Receptive Field)
  • S 细胞(Simple Cell):在自身感受野内对边缘模式刺激做出响应
  • C 细胞(Complex Cell):感受野更大,能对刺激模式的空间位置进行定位

CNN 的本质是多层拼图游戏:先用 S 细胞(卷积)找到小碎片(横线、竖线、圆弧),再用 C 细胞(池化)忽略无关紧要的位置抖动,最后层层叠加,把线条拼成眼睛,把眼睛拼成脸。从局部到整体,从简单到复杂——这就是 CNN 打败传统神经网络的秘诀。

4.2 卷积的核心概念

  • 卷积神经网络就是让权重在不同位置共享的神经网络
  • 卷积核称为 kernel / filter / feature detector,其范围叫 filter size(如 2×2)
  • filter 扫描到不同位置计算输出时,权重 w₁~w₄ 和偏置 b₀ 是共用的
  • 卷积计算得到的输出叫 Convolved Feature / Activation Map / Feature Map

PyTorch 中的二维卷积:

nn.Conv2d(in_channels, out_channels, kernel_size,
          stride=1, padding=0, dilation=1, groups=1, bias=True)
# in_channels: 输入通道数,RGB 图片为 3
# out_channels: 输出通道数,根据模型调整
# kernel_size: 卷积核大小,int 或 tuple,如 (2, 3)

手动计算 Feature Map 练习:

image = np.array([[1,1,1,0,0],
                  [0,1,1,1,0],
                  [0,0,1,1,1],
                  [0,0,1,1,0],
                  [0,1,1,0,0]])
filter_1 = np.array([[1, 0, 1],
                     [0, 1, 0],
                     [1, 0, 1]])
# 用 filter_1 在 image 上滑动做内积,即得 3x3 的 Feature Map

4.3 卷积网络可视化实验

定义 4 组滤波器并观察卷积、激活、池化的输出:

filter_vals = np.array([
    [-1, -1, 1, 1],
    [-1, -1, 1, 1],
    [-1, -1, 1, 1],
    [-1, -1, 1, 1]
])
filter_1 = filter_vals
filter_2 = -filter_1
filter_3 = filter_1.T
filter_4 = -filter_3
filters = np.array([filter_1, filter_2, filter_3, filter_4])

class Net(nn.Module):
    def __init__(self, weight):
        super(Net, self).__init__()
        k_height, k_width = weight.shape[2:]  # 4, 4
        # 4 个灰度滤波器初始化卷积层权重
        self.conv = nn.Conv2d(1, 4, kernel_size=(k_height, k_width), bias=False)
        self.conv.weight = torch.nn.Parameter(weight)
        self.pool = nn.MaxPool2d(2, 2)  # 池化层

    def forward(self, x):
        conv_x = self.conv(x)
        activated_x = F.relu(conv_x)
        pooled_x = self.pool(activated_x)
        return conv_x, activated_x, pooled_x

4.4 CNN 各层学到什么

CNN 层数越多,学到的特征越高阶:

  • Layer 1、2:颜色、边缘等低层特征
  • Layer 3:纹理特征,如网格纹理
  • Layer 4:有区别性的部件特征,如狗头
  • Layer 5:完整的、具有辨别性的关键特征

CNN 的训练过程:过滤器初始是随机的,先做前向传播逐层卷积,再用误差函数计算每层过滤器的梯度(反向传播),最后用随机梯度下降更新过滤器。这正如人类识别:第一次见面记住小细节→局部→全局印象→打上标签,第二次见面用记忆中的信息进行匹配。

五、YOLO 目标检测

5.1 CNN 与 YOLO 的关系

  • CNN 是技术组件,功能只有一个:看图,从图片里提取特征
  • YOLO(You Only Look Once)是解决方案/架构,把一堆 CNN 按特定顺序组装起来,不仅看懂图,还要算出物体在哪个位置(坐标)

一句话:CNN 是砖块,YOLO 是用砖块盖起来的摩天大楼。

5.2 目标检测两大流派

  1. Two-stage(基于 Region Proposal):R-CNN、Fast R-CNN、Faster R-CNN。先用启发式方法(selective search)或 RPN 网络产生候选区域,再做分类与回归。准确度高,但速度慢。
  2. One-stage(Region-free):YOLO、SSD。只用一个 CNN 网络直接预测目标的类别与位置。速度快,但精度略低。

5.3 YOLOv1 算法解析

论文:You Only Look Once: Unified, Real-Time Object Detection(CVPR 2016)

  • You Only Look Once:只需一次 CNN 运算
  • Unified:统一框架,端到端预测。YOLO 将检测变成回归问题——输入整张图,经过一个神经网络,直接得到 bounding box 及其类别概率
  • Real-Time:标准版每秒处理 45 帧;Fast YOLO 每秒 155 帧,mAP 仍达其他实时检测算法的两倍

核心机制:

  1. 将图片分割为 S×S 个等大的 grid
  2. 只要求物体的中心点落在某个 grid 内,该 grid 就负责检测它
  3. 每个 grid 预测 B 个 bounding box,每个 box 含 5 个量:中心位置 (x, y)、宽高 (w, h)、置信度 confidence
  4. 虽然一个 grid 有多个 box,但只能识别一个物体,所以类别由 grid 预测,box 不需要

输出张量计算(PASCAL VOC,20 类,S=7,B=2):

输出张量大小 = S × S × (5×B + C) = 7 × 7 × (5×2 + 20) = 7 × 7 × 30

30 维向量的含义:前 20 个是类别概率,后 2 个是边界框置信度(两者相乘得类别置信度),最后 8 个是两个边界框的 (x, y, w, h)。

  • 每个 grid 产生 2 个预测框,但只能预测 1 个物体(选置信度大的框输出)
  • 7×7 的 grid 最多可预测 49 个物体

网络设计:参考 GoogLeNet,含 24 个卷积层和 2 个全连接层;用 1×1 卷积做 channel reduction 紧跟 3×3 卷积;激活函数用 Leaky ReLU,最后一层线性激活。输入 448×448,输出 7×7×30。Fast YOLO 用 9 个卷积层替代 24 个。

损失函数:不能等值加权,需区分三部分:

误差 = 定位误差 + 置信度误差 + 分类误差
其中置信度误差 = 包含目标的框置信度误差 + 不包含目标的框置信度误差

5.4 非极大值抑制(NMS)

一个物体可能被多个边界框检测到(如产生 40 个预测框),需要 NMS 筛选最佳框(最终只保留 5 个)。

重叠度 IOU:IOU = (A ∩ B) / (A ∪ B),一般设阈值 nms_threshold = 0.5。

算法步骤:

  1. 选取 scores 最大的 box,记为 box_best
  2. 计算 box_best 与其余 box 的 IOU
  3. 若 IOU > 0.5,舍弃该 box(很可能表示同一目标,保留分数高的)
  4. 从剩余 boxes 中再找 score 最大的,循环往复

5.5 YOLOv3 的改进

  • 多尺度预测:13×13、26×26、52×52 三种网格,小网格负责大目标,大网格负责小目标
  • 先验框(anchor)大小可基于数据集用 k-means 聚类适配,例如 COCO 上的:
    • 52×52 层:40,30 / 60,42 / 89,69
    • 26×26 层:93,276 / 127,94 / 148,53
    • 13×13 层:223,114 / 339,172 / 418,329
  • 每个单元格预测 3 × (4 + 1 + B) 个值,每层输出 S×S×3×(4+1+B) 大小的张量(B 为类别数)

5.6 YOLO 发展总结(v1 → v13)

版本 论文/特点 链接
YOLOv1 You Only Look Once: Unified, Real-Time Object Detection CVPR 2016
YOLOv2 / YOLO9000 Better, Faster, Stronger arXiv
YOLOv3 An Incremental Improvement arXiv
YOLOv4 Optimal Speed and Accuracy arXiv / darknet
YOLOv5 无论文,工程化 ultralytics/yolov5
YOLOv6 美团,面向工业应用 arXiv / GitHub
YOLOv7 Trainable bag-of-freebies CVPR 2023
YOLOv8 无论文 ultralytics
YOLOv9 Programmable Gradient Information arXiv
YOLOv10 Real-Time End-to-End(清华) arXiv
YOLOv11 无论文 ultralytics
YOLOv12 Attention-Centric Real-Time Object Detectors GitHub
YOLOv13 Hypergraph-Enhanced Adaptive Visual Perception GitHub

演进脉络:

  1. 从回归到 Anchor 机制:v1 简单网格回归 → v2 引入 Anchor Boxes
  2. 从浅层到深层残差网络:Darknet-19 → Darknet-53 → CSPDarknet53 → 融合 Transformer
  3. 多尺度与注意力融合:v3 多尺度预测,v4 大量 Bag of Freebies/Specials,v9–v12 探索注意力模块
  4. 工业化与易用性:v5–v8 在工程化上下功夫,开发者可快速上手部署
  5. 高精度与实时性并重:始终保持高 FPS 的同时缩小与双阶段检测器的精度差距

应用场景:自动驾驶(车辆、行人、交通标志)、安防监控、机器人视觉、智能交通等。

六、实战:基于 YOLOv12 的钢铁表面缺陷检测

6.1 任务说明

识别钢铁表面缺陷位置,给出锚点框坐标并分类。数据集收集了 6 种典型热轧带钢表面缺陷:

  • 氧化铁皮压入(rolled-in_scale, RS)
  • 斑块(patches, Pa)
  • 开裂(crazing, Cr)
  • 点蚀(pitted_surface, PS)
  • 夹杂(inclusion, In)
  • 划痕(scratches, Sc)

每幅图像分辨率 200×200。Train 含 1400 个标注文件(xml)+ 图片(jpg),Test 含 400 张图片。比赛地址:百度 AI Studio 钢铁缺陷检测。

提交格式 submission.csv:image_id, bbox, category_id, confidence,其中类别字典为:

{'crazing': 0, 'inclusion': 1, 'pitted_surface': 2,
 'scratches': 3, 'patches': 4, 'rolled-in_scale': 5}

每行记录 1 个检测框;同张图片的多个检测框分行记录。

6.2 YOLOv12 快速上手(ultralytics)

预测:

from ultralytics import YOLO

model = YOLO('./yolov12n.pt')
results = model("./000000000139.jpg")
results[0].show()
# 输出示例:448x640 2 persons, 3 chairs, 2 potted plants...

验证:

metrics = model.val(data='./coco.yaml', save_json=True)
print(metrics.box.map)  # mAP 指标,如 0.503

训练:

from ultralytics import YOLO

model = YOLO("yolov12.yaml")   # 从配置初始化;有预训练权重可用 YOLO("yolov12n.pt")
model.info()
# YOLOv12 summary: 497 layers, 2,553,904 parameters, 6.2 GFLOPs

results = model.train(
    data='coco.yaml',
    epochs=1,
    batch=256,
    imgsz=640,
    scale=0.5,        # 图像缩放比例
    mosaic=1.0,       # 马赛克数据增强概率
    mixup=0.0,        # 混合增强概率
    copy_paste=0.1,   # 复制粘贴增强概率
    device="0",
)

6.3 数据集配置 dataset.yaml

path: /root/autodl-tmp/vl_model_cases/yolo-cases/steel_data
train: train/train.txt   # 训练图像列表
val: train/val.txt       # 验证图像列表
test: train/test.txt     # 测试图像列表(可选)

names:
  0: crazing
  1: inclusion
  2: pitted_surface
  3: scratches
  4: patches
  5: rolled-in_scale

说明:dataset.yaml 支持文件夹和 .txt 两种配置方式。文件夹方式(如 train/images)会自动取该文件夹所有文件,并在 train/labels 下找同名标注文件;.txt 方式可自行指定参与训练的文件(txt 中每行写一个图片路径,如 ./images/1.jpg,程序自动在 ./labels/1.txt 找标注),更灵活。

6.4 训练脚本

from ultralytics import YOLO

model = YOLO('yolov12.yaml')      # 从配置文件新建模型
# model = YOLO('yolov12n.pt')    # 或加载预训练模型(可选)
model.info()

results = model.train(
    data='./steel_data/dataset.yaml',
    epochs=100,
    batch=16,
    imgsz=640,
    patience=50,          # 早停轮数
    save=True,
    device='0',           # GPU 设备号,用 CPU 则设为 'cpu'
    workers=8,
    pretrained=True,
    optimizer='auto',
    verbose=True,
    # 数据增强参数
    scale=0.5,
    mosaic=1.0,
    mixup=0.1,
    copy_paste=0.1,
)

results = model.val()  # 在验证集上评估

6.5 预测与生成提交文件

from ultralytics import YOLO
import os

model2 = YOLO('./runs/detect/train28/weights/best.pt')

test_image_dir = './steel_data/test/images'
if os.path.exists(test_image_dir):
    for image_name in os.listdir(test_image_dir)[:5]:  # 先测试前 5 张
        image_path = os.path.join(test_image_dir, image_name)
        results = model2(image_path)
        results[0].save(os.path.join('./runs/detect/predict', image_name))

最后将 test 结果整理为 submission.csv(字段:image_id, bbox, category_id, confidence,bbox 为绝对坐标 (XMin, YMin, XMax, YMax))提交即可。小技巧:可以先把 confidence 统一改成 1 尝试提交,注意每天只有一次提交机会,谨慎提交。

七、总结

  1. PyTorch:核心是 Tensor,支持 GPU 加速与自动求导(autograd);动态计算图便于调试;torch.nn + torch.optim 可快速搭建网络;支持 DataParallel / DDP 分布式训练,配合 PyTorch Lightning 进一步简化。
  2. CNN:模仿人类视觉皮层的 S/C 细胞机制,卷积找碎片、池化抗抖动、层层叠加拼出整体。
  3. YOLO:把检测变成回归问题,one-stage 端到端,速度极快;从 v1 到 v13 沿着 Anchor 机制、深层骨干、多尺度、注意力、工程化方向不断演进。
  4. 工业缺陷检测是系统工程:算法只是其中一环,相机、光源、PLC 打通同样关键——很多时候"换个灯"比"调模型"提升更大。
posted @ 2026-08-15 11:53  coderliu_cn  阅读(49)  评论(0)    收藏  举报