简介:这份资源是PyTorch深度学习入门实战视频教程的配套源代码与PPT合集,面向具备Python基础、希望系统掌握深度学习框架的初学者与进阶开发者,覆盖卷积神经网络、循环神经网络、生成对抗网络及图卷积网络等主流模型方向。压缩包共142个文件,约85.9MB,其中39个py脚本对应各章节实战代码,55个pdf与PPT讲义梳理理论要点,另有ipynb笔记本、png图示、xml配置及csv数据集等辅助材料,便于边看边练、对照复现。内容涉及Cifar10与ResNet18实战、LSTM序列建模、GCN图卷积等典型项目,并附有PyTorch安装与国内源配置说明,可帮助读者快速搭建环境、理解模型实现细节与调参思路。目前已有2678人学习下载,适合作为课程配套练习与项目复现的参考素材。
1. 从一份 PyTorch 配套源码说起:为什么我建议你先把环境跑通再谈模型
如果你手头正好有一份深度学习与 PyTorch 入门实战的配套源代码和 PPT,先别急着翻到 CNN 那一章。我见过太多人拿到资源包后第一件事是打开train.py从头读到尾,结果卡在torchvision版本不匹配上,连第一个 epoch 都没跑起来。这份资源的核心价值不在于代码写得多精妙,而在于它把 machine-learning tutorial 里那些抽象概念——张量、自动求导、卷积核、循环单元——全部落成了可执行的 Python 文件。它适合两类人:一是刚学完 Python 基础、想用 PyTorch 跑通第一个深度学习项目的学生;二是从 TensorFlow 转过来、需要快速对齐 PyTorch 写法差异的从业者。配套 PPT 的作用被很多人低估了,它其实是代码的“设计文档”,先看 PPT 理清模块划分,再对照源码看实现,比直接啃代码效率高得多。这一篇我会按“环境配置 → 核心模块拆解 → 训练流程复现 → 避坑排查 → 进阶技巧”的顺序,把这份资源拆成能直接抄作业的实战笔记。
2. 环境配置与资源结构:把依赖锁死再动手
2.1 先看清资源包里有什么
拿到资源后别急着pip install,先花五分钟把目录结构过一遍。典型的 PyTorch 教程配套包一般包含这几类文件:按章节编号的 Jupyter Notebook 或.py脚本、requirements.txt或environment.yml、PPT 文件、以及可能的数据集说明或下载脚本。我一般会先执行tree -L 2或find . -maxdepth 2 -type d看整体布局,重点关注有没有data/、checkpoints/、utils/这类目录。如果资源包里没有显式的依赖清单,那就需要从代码的 import 语句反推。常见做法是搜索所有import torch、import torchvision、import numpy的行,记录下大致版本范围。这一步偷懒的代价是后面可能花两小时排查一个 API 变更导致的报错。
2.2 用 conda 建独立环境并锁定版本
PyTorch 的版本兼容性是出了名的玄学,CUDA 驱动、cuDNN、PyTorch 三者版本必须对齐。我习惯用 conda 而不是 pip 来管理基础环境,因为 conda 能同时处理 Python 版本和二进制依赖。下面这套命令是我在多个项目里验证过的流程:
# 创建独立环境,Python 版本根据资源包要求调整,一般 3.8-3.10 较稳 conda create -n pytorch_tutorial python=3.9 -y conda activate pytorch_tutorial # 安装 PyTorch,注意 cu113 对应 CUDA 11.3,需根据本机驱动调整 # 如果只用 CPU,把 cu113 换成 cpu 即可 pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 -f https://download.pytorch.org/whl/torch_stable.html # 安装其余依赖,建议逐条装而不是一把梭 pip install numpy matplotlib jupyter tqdm tensorboard这里的关键参数是torch==1.12.1+cu113中的+cu113,它表示编译时链接的 CUDA 版本。如果你本机nvidia-smi显示的 CUDA Version 是 11.6,装 cu113 通常也能跑,因为 CUDA 有向前兼容的小版本机制,但大版本跨了就必须换。装完后务必验证:
import torch print(torch.__version__) # 应输出 1.12.1+cu113 print(torch.cuda.is_available()) # 期望 True,若 False 则检查驱动 print(torch.cuda.get_device_name(0)) # 确认显卡被识别如果cuda.is_available()返回 False,先别怀疑代码,九成是驱动版本低于 PyTorch 要求。这时候要么升级驱动,要么退回 CPU 版本先跑通逻辑。
2.3 数据集准备与路径约定
教程类资源的数据集通常有三种来源:内置的torchvision.datasets(如 MNIST、CIFAR-10)、随包附带的.npz或.csv文件、以及需要自行下载的较大数据集。对于内置数据集,第一次运行会自动下载到./data目录,国内网络环境下可能较慢,可以手动下载后放到对应路径。我一般会在项目根目录建一个data/文件夹,然后在代码里统一用相对路径引用。如果资源包里代码写的是绝对路径(比如/home/user/data),记得全局替换成自己的路径,否则一运行就报FileNotFoundError。这一步没有技术含量,但漏掉就是跑不通。
3. 核心模块拆解:从张量到 CNN/RNN/GAN 的代码映射
3.1 张量与自动求导:所有模型的底座
PyTorch 教程的前几章一定在讲torch.Tensor和autograd。这部分代码看起来简单,但藏着两个容易翻车的点。第一是requires_grad的传递性:如果你手动创建了一个张量并设置requires_grad=True,后续所有基于它的运算都会被追踪,显存占用会持续累积。第二是.detach()和with torch.no_grad()的区别:前者返回一个脱离计算图的新张量,后者是上下文管理器,在推理阶段必须用后者包住整个前向过程,否则验证集跑着跑着就 OOM。我一般会在训练脚本里这样写:
# 训练循环中的标准写法 for inputs, labels in train_loader: inputs, labels = inputs.to(device), labels.to(device) optimizer.zero_grad() # 清空上一轮梯度,漏掉这步梯度会累加 outputs = model(inputs) # 前向传播,计算图自动构建 loss = criterion(outputs, labels) # 计算损失 loss.backward() # 反向传播,计算梯度 optimizer.step() # 更新参数 # 验证阶段必须关闭梯度追踪 model.eval() with torch.no_grad(): for inputs, labels in val_loader: outputs = model(inputs) # 只做指标统计,不反向传播optimizer.zero_grad()的位置很讲究:放在loss.backward()之前、前向传播之后是标准做法。如果放在loss.backward()之后,这一轮的梯度还没用就被清掉了,模型永远不更新。这个坑我见过至少三个人踩过,现象是 loss 完全不下降。
3.2 CNN 模块:卷积核尺寸与特征图计算
卷积神经网络部分的代码通常包含nn.Conv2d、nn.MaxPool2d、nn.BatchNorm2d和全连接层的组合。看源码时不要只盯着层数,要算特征图尺寸的变化。公式是output_size = (input_size - kernel_size + 2*padding) / stride + 1。教程里常用kernel_size=3, padding=1, stride=1,这样特征图尺寸不变,只有池化层才降维。如果你把 padding 设成 0,经过几层卷积后特征图会缩得很快,最后 flatten 后的维度对不上全连接层,报RuntimeError: mat1 and mat2 shapes cannot be multiplied。解决办法有两个:一是用nn.AdaptiveAvgPool2d((1,1))把任意尺寸压成 1x1,二是手动算好每层输出尺寸再写全连接输入维度。我一般推荐前者,省心且对输入尺寸不敏感。
class SimpleCNN(nn.Module): def __init__(self, num_classes=10): super().__init__() self.features = nn.Sequential( nn.Conv2d(3, 32, kernel_size=3, padding=1), # 尺寸不变 nn.BatchNorm2d(32), nn.ReLU(inplace=True), nn.MaxPool2d(2), # 尺寸减半 nn.Conv2d(32, 64, kernel_size=3, padding=1), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(2), ) self.classifier = nn.Sequential( nn.AdaptiveAvgPool2d((1, 1)), # 自适应池化,避免手动计算 nn.Flatten(), nn.Linear(64, num_classes), ) def forward(self, x): x = self.features(x) x = self.classifier(x) return xBatchNorm2d的参数是通道数,必须和前一层的输出通道一致。inplace=True的 ReLU 能省一点显存,但在某些需要保留原始输入的场景下会出问题,新手可以先不管这个参数。
3.3 RNN 与 LSTM:序列维度的 batch_first
循环神经网络部分的代码是很多人第一次接触序列建模的地方。PyTorch 的nn.RNN、nn.LSTM、nn.GRU默认输入形状是(seq_len, batch, input_size),但教程里为了直观,通常会把batch_first=True设上,这样输入就变成(batch, seq_len, input_size)。如果你忘了设这个参数,模型不会报错,但会把 batch 和 seq_len 搞反,训练出来的结果完全不对。这个坑极其隐蔽,因为 loss 可能还在缓慢下降,只是效果差。我一般会在数据加载后打印一次inputs.shape确认维度顺序。
# LSTM 使用示例,batch_first=True 让输入为 (batch, seq, feature) lstm = nn.LSTM(input_size=128, hidden_size=256, num_layers=2, batch_first=True, dropout=0.3) # 输入 x: (32, 50, 128) 表示 batch=32, 序列长度=50, 特征维度=128 x = torch.randn(32, 50, 128) output, (hidden, cell) = lstm(x) # output: (32, 50, 256),hidden: (2, 32, 256),cell 同 hiddennum_layers=2表示堆叠两层 LSTM,dropout=0.3只在层与层之间生效,最后一层输出不 dropout。如果你在单层 LSTM 上设 dropout,PyTorch 会给出警告但不报错,实际没有任何效果。
3.4 GAN 模块:生成器与判别器的交替训练
生成对抗网络部分的代码结构和其他模型不同,它有两个网络、两个优化器,训练循环里要手动交替更新。教程里的 GAN 通常是 DCGAN 结构,生成器用转置卷积上采样,判别器用卷积下采样。关键点是:训练判别器时要把生成器的梯度冻结,训练生成器时要把判别器的梯度冻结。如果忘了冻结,两个网络会互相干扰,loss 震荡不收敛。常见做法是用requires_grad_(False)切换,或者用两个独立的优化器分别只传对应网络的参数。
# 判别器更新:只优化 D,不更新 G optimizer_D.zero_grad() real_loss = criterion(D(real_imgs), torch.ones(batch_size, 1).to(device)) fake_imgs = G(z).detach() # detach 切断生成器梯度 fake_loss = criterion(D(fake_imgs), torch.zeros(batch_size, 1).to(device)) loss_D = (real_loss + fake_loss) / 2 loss_D.backward() optimizer_D.step() # 生成器更新:只优化 G,不更新 D optimizer_G.zero_grad() fake_imgs = G(z) loss_G = criterion(D(fake_imgs), torch.ones(batch_size, 1).to(device)) loss_G.backward() optimizer_G.step()detach()在这里是必须的,否则loss_D.backward()会把梯度传到生成器,下一轮optimizer_G.step()时生成器已经被污染了。GAN 的训练稳定性是另一个话题,教程里一般用 Adam 优化器、学习率 0.0002、beta1=0.5,这套参数在 DCGAN 论文里被验证过,直接抄就行。
4. 训练流程复现:从单机脚本到 TensorBoard 监控
4.1 数据加载与增强的工程细节
torchvision.transforms是数据增强的主力工具,但顺序很重要。标准流程是:Resize→RandomCrop→RandomHorizontalFlip→ToTensor→Normalize。ToTensor必须放在Normalize之前,因为Normalize只接受张量。如果你把Normalize写在ToTensor前面,会报类型错误。另外,Normalize的均值和标准差通常用 ImageNet 的[0.485, 0.456, 0.406]和[0.229, 0.224, 0.225],即使你的数据集不是 ImageNet,这套参数也能用,只是不是最优。我一般会在训练集上用增强,验证集上只做Resize和ToTensor,保证评估结果可复现。
from torchvision import transforms train_transform = transforms.Compose([ transforms.Resize(256), transforms.RandomCrop(224), transforms.RandomHorizontalFlip(p=0.5), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) val_transform = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ])RandomHorizontalFlip(p=0.5)表示一半概率翻转,对于分类任务通常有益,但对于文字识别或医学图像可能不适用,需要根据任务判断。
4.2 训练循环与学习率调度
训练循环的骨架在 3.1 节已经给过,这里补充学习率调度和 checkpoint 保存。torch.optim.lr_scheduler提供了多种调度器,教程里常用StepLR或CosineAnnealingLR。StepLR每隔固定 epoch 把学习率乘以一个因子,适合传统 CNN 训练;CosineAnnealingLR按余弦曲线下降,适合较长的训练周期。我一般会在每个 epoch 结束后调用scheduler.step(),并记录当前学习率到 TensorBoard。
from torch.optim.lr_scheduler import CosineAnnealingLR from torch.utils.tensorboard import SummaryWriter writer = SummaryWriter('runs/exp1') scheduler = CosineAnnealingLR(optimizer, T_max=50, eta_min=1e-6) for epoch in range(50): model.train() for inputs, labels in train_loader: # ... 训练步骤 ... pass scheduler.step() writer.add_scalar('lr', optimizer.param_groups[0]['lr'], epoch) writer.add_scalar('train_loss', avg_loss, epoch) # 保存 checkpoint,包含模型、优化器、epoch,方便断点续训 if (epoch + 1) % 10 == 0: torch.save({ 'epoch': epoch, 'model_state': model.state_dict(), 'optimizer_state': optimizer.state_dict(), }, f'checkpoints/epoch_{epoch+1}.pth')T_max=50表示半个余弦周期为 50 个 epoch,eta_min=1e-6是学习率下限。保存 checkpoint 时把优化器状态也存上,续训时才能恢复动量等信息,否则相当于重新开始。
4.3 用 TensorBoard 看 loss 曲线和计算图
TensorBoard 是 PyTorch 训练监控的标配。除了记录 loss 和 lr,还可以用add_graph把模型结构画出来,检查层与层的连接是否符合预期。启动命令是tensorboard --logdir=runs,然后在浏览器打开对应端口。如果 loss 曲线出现剧烈震荡,先看学习率是不是太大;如果 loss 一直不降,检查数据标签有没有对错、zero_grad有没有漏掉。这些排查思路在下一章会展开。
5. 避坑与排查:那些让训练崩掉的细节
5.1 现象:loss 变成 NaN
原因:学习率过大导致梯度爆炸,或者数据里有 NaN 值,或者用了log(0)这类数学运算。解决:先把学习率降到 1e-4 或更低试一轮;然后在数据加载后加一句assert not torch.isnan(inputs).any()定位问题样本;如果是自定义 loss 里有 log,给输入加一个极小值1e-8。
5.2 现象:CUDA out of memory
原因:batch size 太大、模型参数量超过显存、或者验证阶段没加torch.no_grad()导致计算图累积。解决:先把 batch size 减半;然后用torch.cuda.empty_cache()清理缓存;确认验证循环包在with torch.no_grad()里;如果还不够,用梯度累积模拟大 batch。
5.3 现象:模型在训练集上准确率很高,验证集上很差
原因:过拟合,或者训练集和验证集的数据分布不一致。解决:加数据增强、加 Dropout 或 Weight Decay、早停;检查验证集的 transform 是否和训练集差太多,比如训练集做了 RandomCrop 而验证集没做 CenterCrop,导致输入尺寸不一致。
5.4 现象:RNN 训练时 loss 不降反升
原因:序列长度太长导致梯度爆炸,或者batch_first没设导致维度错乱。解决:加梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5);确认batch_first=True;如果序列极长,考虑用截断的 BPTT。
5.5 现象:GAN 的判别器 loss 迅速降到 0
原因:判别器太强,生成器梯度消失。解决:降低判别器的学习率或层数;给判别器的输入加噪声;把判别器的更新频率降到生成器的一半。GAN 的训练平衡是经验活,没有万能公式,但以上三条能救回大部分情况。
6. 进阶技巧:用 PPT 反推设计意图与迁移到自己的数据
6.1 把 PPT 当架构图用
很多人把配套 PPT 当讲义翻一遍就扔了,其实它是代码的“设计文档”。我一般会对照 PPT 里的模型结构图,在代码里找到对应的nn.Sequential或forward函数,逐层核对。比如 PPT 上画了“卷积 → BN → ReLU → 池化”四件套,代码里如果少了 BN,那可能是作者为了简化故意省略的,你在自己的项目里补上就行。PPT 里如果有超参数表格,直接抄到代码的config字典里,比在代码里到处找硬编码的数字高效得多。
6.2 迁移到自定义数据集的三步走
教程代码跑通后,下一步是用自己的数据替换。第一步,把数据整理成ImageFolder要求的格式:每个类别一个文件夹,文件夹名就是标签。第二步,改num_classes为你的类别数,如果是预训练模型,还要改最后一层全连接。第三步,调整数据增强策略:如果你的数据集很小,增强可以激进一些;如果图像尺寸和教程差异大,改Resize和RandomCrop的参数。下面是一个迁移时的检查清单:
| 检查项 | 教程默认值 | 自定义时需确认 |
|---|---|---|
| 类别数 | 10 或 1000 | 改为实际类别数 |
| 输入尺寸 | 224x224 | 根据数据调整,保持模型可接受 |
| 归一化参数 | ImageNet 均值方差 | 可沿用,也可算自己的 |
| batch size | 32 或 64 | 根据显存调整 |
| 学习率 | 0.001 或 0.0002 | 预训练微调时降到 1e-4 |
6.3 一个我常用的验证习惯
每次改完代码,我不会直接跑完整训练,而是先用一个极小的子集(比如 100 张图)跑 2 个 epoch,确认 loss 能下降、维度不报错、checkpoint 能保存。这个习惯帮我省下了大量“跑了三小时才发现标签对错”的时间。从那以后我每次动数据管道或模型结构,都强制走一遍这个小闭环,确认无误再上全量数据。希望帮到你。
本文还有配套的精品资源,点击获取