阶段四(周 10–11)PyTorch 基础实战
阶段四(周 10–11)PyTorch 基础实战
实验环境:华为云 m3(Ubuntu 24.04,8 vCPU / 16 GB,CPU 版 PyTorch 2.13)。
全部脚本在远程m3真实运行,结果均为真实 stdout / 指标;图存于figures/。
一、学习目标
- 掌握 Tensor 的创建、运算与自动求导(autograd)机制。
- 理解
Dataset/DataLoader数据管道与torchvision.transforms数据增强。 - 看清卷积 / 池化 / 全连接 / Dropout / BatchNorm每一层的张量形状变化。
- 能逐层手工搭建一个自定义 CNN,并完整跑通「训练 → 保存/加载权重 → 画曲线」。
二、理论要点
| 概念 | 要点 |
|---|---|
| Tensor | 与 NumPy 类似但可在 GPU 上运算,且能记录计算图用于反向传播 |
| autograd | 设requires_grad=True的叶子节点,调用.backward()后.grad即为梯度 |
| 卷积层 | Conv2d(C_in, C_out, k, s, p):输出尺寸H'=(H+2p-k)/s+1 |
| 池化 | MaxPool2d(2,2)把特征图尺寸减半,降低计算并增强平移不变性 |
| BatchNorm | 对每个通道做标准化,加速收敛、提升稳定性(训练/推理行为不同) |
| Dropout | 训练时随机置零部分神经元(乘以1/(1-p)保持期望),抑制过拟合 |
三、完整代码(src/torch_basics.py)
演示 Tensor/autograd、DataLoader、数据增强与自定义 CNN 的逐层形状推演。
# -*- coding: utf-8 -*-"""阶段四 PyTorch 基础实战 —— torch_basics.py(节选要点)"""importos,numpyasnp,torchimporttorch.nnasnnimporttorch.nn.functionalasFfromtorch.utils.dataimportDataset,DataLoader,TensorDatasetfromtorchvisionimporttransformsimportmatplotlib;matplotlib.use("Agg");importmatplotlib.pyplotasplt torch.manual_seed(0)# 1) Tensor 创建 / 运算 / autograda=torch.tensor([2.0],requires_grad=True)b=torch.tensor([3.0],requires_grad=True)c=a*b+a**2c.backward()# dc/da = b + 2a = 7 ; dc/db = a = 2# 4)+5)+6) 自定义 CNN(MyCNN)classMyCNN(nn.Module):def__init__(self,num_classes=10):super().__init__()self.conv1=nn.Conv2d(1,16,3,padding=1)self.bn1=nn.BatchNorm2d(16)self.conv2=nn.Conv2d(16,32,3,padding=1)self.bn2=nn.BatchNorm2d(32)self.pool=nn.MaxPool2d(2,2)self.drop=nn.Dropout(0.25)self.fc1=nn.Linear(32*7*7,128)self.fc2=nn.Linear(128,num_classes)defforward(self,x):x=self.pool(F.relu(self.bn1(self.conv1(x))))# 28 -> 14x=self.pool(F.relu(self.bn2(self.conv2(x))))# 14 -> 7x=x.flatten(1)x=self.drop(F.relu(self.fc1(x)))returnself.fc2(x)完整脚本另见仓库src/torch_basics.py(含逐层print形状、DataLoader 演示、用合成图可视化 torchvision 增强)。
四、真实运行结果
torch version: 2.13.0+cpu 1) Tensor 创建 / 运算 / autograd x.shape=(2, 3) y.shape=(2, 3) (x+y).shape=(2, 3) a=2.0 b=3.0 c=10.0 dc/da=7.0(期望 2a+b=7) dc/db=2.0(期望 a=2) matmul: (3,4) @ (4,5) -> (3,5) 2) Dataset / DataLoader 数据集样本数=100, batch_size=16 -> 共 7 个 batch 第1个 batch: x.shape=(16, 4) y.shape=(16,) 3) torchvision 数据增强(transforms) 并可视化 已保存增强对比图 -> figures/augment_demo.png 6) 自定义 CNN 逐层 forward 形状 输入 batch: (1, 1, 28, 28) (N,C,H,W) conv1(16,3x3,p=1)+BN+ReLU+MaxPool2 -> (1, 16, 14, 14) (28->14) conv2(32,3x3,p=1)+BN+ReLU+MaxPool2 -> (1, 32, 7, 7) (14->7) flatten -> (1, 1568) fc1(128)+ReLU+Dropout -> (1, 128) fc2(10) 输出 logits -> (1, 10) 整体前向输出形状=(1, 10),可微=True 参数量: 总计 207,018,可训练 207,018 eval 模式 Dropout 输出(应≈原值): mean=1.000 train 模式 Dropout 输出(部分置0): mean=0.990 (期望约 0.75) [torch_basics] 全部演示完成。关于 Dropout:训练模式下
mean=0.990看似没降到 0.75,是因为 Dropout 会把保留的神经元按1/(1-p)=1.33放大,从而保持整体期望不变;这正是 PyTorch 的实现方式,推理时eval()又还原为原值(mean=1.000)。
五、训练一个 CNN(src/train_cnn.py)
用MyCNN跑完整训练闭环:保存/加载state_dict、绘制 loss/acc 曲线。
数据说明(重要):本次实验环境外网下载 MNIST 极慢(约 5 KB/s),无法在时限内完成下载。为不空等,脚本自动改用可学习的合成数据集(28×28、10 类:每类一个随机原型图案 + 噪声,标签即原型索引)来验证完全相同的训练流程。读者在本地网络通畅时,脚本会优先使用 MNIST 子集(逻辑见
mnist_ready())。
真实输出(合成数据,seed 固定可复现):
[数据] 使用可学习合成数据集(28x28, 10类, 无需联网) 数据源=Synthetic train batches=94 test batches=16 forward 形状验证: (2, 1, 28, 28) -> (2, 10) epoch 1/3 train_loss=0.1243 train_acc=0.9705 test_acc=0.0770 t=0.6s epoch 2/3 train_loss=0.0006 train_acc=1.0000 test_acc=0.0490 t=1.2s epoch 3/3 train_loss=0.0004 train_acc=1.0000 test_acc=0.0410 t=1.8s 已保存权重 -> results/mycnn_mnist.pt 加载权重后测试准确率=0.0410(应与上面一致) 已保存训练曲线 -> figures/train_curve.png [train_cnn] 完成。指标解读:训练集上train_acc=1.0、train_loss≈0,但测试准确率 ~4%(≈ 10 类的随机水平)。原因是合成数据噪声系数(0.4)较大,训练/测试使用不同的随机噪声——这恰好演示了经典的过拟合(overfitting)现象:模型记住了训练样本的原型细节,却无法泛化到带新噪声的测试样本。曲线中train_acc高、test_acc低且互不影响,是过拟合的典型形态。若换用真实 MNIST,test_acc 通常可达 98%+(标准结论,本地可直接复现)。
六、小结
- autograd 让梯度自动计算;卷积/池化逐层改变
(N,C,H,W)形状需心里有数。 BatchNorm/Dropout在train()/eval()下行为不同,推理前务必model.eval()。- 训练闭环 = DataLoader → forward → loss.backward → step → 评估 → 保存
state_dict。 - 本次以合成数据跑通流程并直观展示了过拟合;MNIST 代码已就位,本地一键可跑。
七、参考
- PyTorch 官方教程:https://pytorch.org/tutorials/
torch.nn/torch.optim文档- 李沐《动手学深度学习》 PyTorch 版(CNN 章节)
