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 随机将元素归零,防止过拟合
为什么要用内置函数?
- 数学太难:卷积、反向传播的导数公式很难推导,PyTorch 帮我们内置好了。
- 性能优化: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)为例:
- Step 1:定义网络结构
- Step 2:初始化模型参数
- 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 算法层面
- 数据量:能获取多少数据,尤其是缺陷数据
- 人工是如何判断的:把人工判异的方法写下来,思考是否有量化指标辅助判断
- 是否有类似公开图片:数据不足时可用相似数据做迁移学习
案例:早期新冠病毒肺部 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 团队协作
缺陷检测通常由三类人合作完成:
- 硬件/打光工程师
- 算法工程师
- 自动化/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 目标检测两大流派
- Two-stage(基于 Region Proposal):R-CNN、Fast R-CNN、Faster R-CNN。先用启发式方法(selective search)或 RPN 网络产生候选区域,再做分类与回归。准确度高,但速度慢。
- 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 仍达其他实时检测算法的两倍
核心机制:
- 将图片分割为 S×S 个等大的 grid
- 只要求物体的中心点落在某个 grid 内,该 grid 就负责检测它
- 每个 grid 预测 B 个 bounding box,每个 box 含 5 个量:中心位置 (x, y)、宽高 (w, h)、置信度 confidence
- 虽然一个 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。
算法步骤:
- 选取 scores 最大的 box,记为 box_best
- 计算 box_best 与其余 box 的 IOU
- 若 IOU > 0.5,舍弃该 box(很可能表示同一目标,保留分数高的)
- 从剩余 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 |
演进脉络:
- 从回归到 Anchor 机制:v1 简单网格回归 → v2 引入 Anchor Boxes
- 从浅层到深层残差网络:Darknet-19 → Darknet-53 → CSPDarknet53 → 融合 Transformer
- 多尺度与注意力融合:v3 多尺度预测,v4 大量 Bag of Freebies/Specials,v9–v12 探索注意力模块
- 工业化与易用性:v5–v8 在工程化上下功夫,开发者可快速上手部署
- 高精度与实时性并重:始终保持高 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 尝试提交,注意每天只有一次提交机会,谨慎提交。
七、总结
- PyTorch:核心是 Tensor,支持 GPU 加速与自动求导(autograd);动态计算图便于调试;
torch.nn+torch.optim可快速搭建网络;支持 DataParallel / DDP 分布式训练,配合 PyTorch Lightning 进一步简化。 - CNN:模仿人类视觉皮层的 S/C 细胞机制,卷积找碎片、池化抗抖动、层层叠加拼出整体。
- YOLO:把检测变成回归问题,one-stage 端到端,速度极快;从 v1 到 v13 沿着 Anchor 机制、深层骨干、多尺度、注意力、工程化方向不断演进。
- 工业缺陷检测是系统工程:算法只是其中一环,相机、光源、PLC 打通同样关键——很多时候"换个灯"比"调模型"提升更大。

浙公网安备 33010602011771号