简介:这份资源面向希望系统入门深度学习与 PyTorch 框架的学习者,配套《深度学习与PyTorch入门实战》视频课程使用,覆盖机器学习基础、卷积神经网络、循环神经网络、生成对抗网络、图卷积等主题,适合具备一定 Python 基础、想从理论走向代码实践的高校学生与算法初学者,帮助解决环境配置繁琐、示例代码零散、缺少可复现实验材料的问题。压缩包共 142 个文件,约 85.9MB,以 55 个 pdf 讲义与课件、39 个 py 示例脚本为主,另含 ipynb 交互式笔记本、png 示意图、xml 与 cfg 配置文件及少量数据集说明文档,可对照课程按章节阅读与运行。已有 2679 人学习下载,说明内容经过较多读者检验。资源中还包含 PyTorch 安装与环境配置说明,涵盖 Anaconda、CUDA 10.0 及国内镜像源设置,并给出 LSTM、Cifar10 与 ResNet18 实战、图卷积网络等案例的代码骨架,便于读者搭建环境后逐课复现模型训练流程,理解网络结构与调参思路,形成从安装到实战的完整学习路径。
1. 先破除一个误会:深度学习入门不是先啃完数学再动手
很多人一想到深度学习,脑子里先冒出来的是满黑板的偏导数和矩阵乘法,于是把 PyTorch 入门这件事一拖再拖,教材买了三本,环境一个没装。真相是,新手最该先做的,是把一个能跑的最小例子跑通:装好框架、造一个张量、让它自己学着拟合一条直线。这一步不需要你会推导公式,只需要你会写几行 Python。这份配套视频教程的源码和 PPT,走的就是这条路——先让你看见结果,再回头补原理。它适合三类人:会一点 Python 想转方向的学生、工作中要接触模型但没系统学过的开发者、以及被数学吓退过好几次的自学者。接下来的内容按「这是什么、为什么值得学、第一步怎么迈」的顺序,把这条路铺平。
2. 搞懂 PyTorch 到底在做什么:把「张量」和「自动求导」两个词拆开看
2.1 为什么第一站该选它,而不是先纠结框架选型
新手最爱问的问题之一是「我该学哪个框架」。这个问题其实问早了。框架之间九成的概念是共通的:数据怎么装、模型怎么搭、损失怎么算、梯度怎么回传,换个框架只是写法变了。真正决定你能不能入门的是「有没有把一次训练从头到尾跑完」,而不是「站队站得对不对」。
那为什么这份教程从 PyTorch 切入?三个很实际的原因。第一,它写起来像普通 Python,你定义模型就是定义一个类,前向计算就是写一个函数,没有额外的心智负担。第二,它的报错信息相对友好,出错时通常能定位到具体某一行,这对新手极其重要——血泪经验告诉我们,入门阶段最劝退的不是概念难,而是报错看不懂。第三,它可以在任何一行代码处打断点,像调试普通脚本一样调试模型,这对理解「数据在每一步变成了什么形状」帮助巨大。
所以别在选型上纠结太久。学透一个,再看别的,通常两周就能迁移过去。你现在需要的是一个能把概念落地的最小环境,而不是一份完美的技术选型报告。
2.2 张量:把数据装进一个带形状的盒子
PyTorch 里所有数据都是张量(Tensor)。你可以把它理解成「带形状信息的多维数组」,或者更生活化一点——一张 Excel 表,可以往上叠。
零维张量就是一个光秃秃的数,比如3.14。一维张量是一行数,比如一条长度为 10 的向量。二维张量就是一张表格,有行有列。三维张量是好几张表摞在一起。四维就是「一摞一摞的表再打包成一批」。新手最容易卡住的地方,是搞不清什么时候该用几维。这里给一个能直接套用的经验:图片数据在 PyTorch 里通常是四维的,顺序是[批大小, 通道数, 高, 宽];一段文本数据通常是三维的,顺序是[批大小, 序列长度, 每个词的向量长度]。
张量有三个你必须随时能说出来的属性。shape是形状,比如torch.Size([32, 3, 224, 224])表示一次喂进去 32 张彩色图,每张 224×224。dtype是数据类型,神经网络里绝大多数计算用float32,整数标签用int64。device是它待在哪儿,在内存里还是在显卡上。
这三个属性里,新手九成的报错都和shape有关。所以从今天起养成一个习惯:每写完一步运算,就打印一次print(x.shape)。这个动作看起来笨,但它能让你在半小时内建立对维度的直觉,比看十页教材都快。
2.3 自动求导:训练为什么不用你手推公式
深度学习的「学习」过程,说穿了就是不断调参数让误差变小。要调参数,就得知道「参数往哪个方向调能让误差变小」,这个东西就是梯度。手推梯度是入门阶段最大的心理障碍,而 PyTorch 把这件事打包了。
机制不复杂。你给一个张量加上requires_grad=True,相当于给它开了一本账本:从此以后,凡是用到它的运算,都会被记进账本里,形成一条计算链。等你算完损失,调用一次.backward(),框架就沿着这条链倒着走一遍,把每个参数的梯度算出来,存进.grad里。这个过程叫自动求导。
举个例子。你写y = w * x + b,再写loss = (y - target) ** 2,然后loss.backward()。跑完之后,w.grad和b.grad里就已经是梯度值了,你什么都不用推。这就像记账本帮你把每笔开销都记好了,你只需要在月底翻一下总额。
提示:
.grad里的值是累加的,不会自动清零。每次更新完参数要手动清零,否则梯度会越滚越大。这是新手最经典的翻车点之一,后面第 5 章还会专门说。
2.4 一次训练循环,永远是这五个动作
把训练拆开看,不管模型多复杂,一轮循环永远由五个动作组成,顺序固定:
- 前向计算:把数据喂进模型,得到预测值。
- 算损失:拿预测值和真实值比,得到一个表示「错得多离谱」的数。
- 反向传播:调用
.backward(),算出每个参数的梯度。 - 更新参数:拿梯度乘上学习率,把参数往反方向挪一点。
- 梯度清零:把上一轮的梯度清掉,为下一轮做准备。
记住这五步,后面你看 CNN、RNN、GAN 的代码时会发现,模型内部千变万化,这五步一步都没变。变化的只有两样东西:模型长什么样,损失函数怎么定义。
3. 第一个能跑的例子:从装环境到拟出一条直线
3.1 装环境:先跑通再说,别一上来就折腾显卡
新手装环境最容易犯的错,是想一步到位配好显卡加速,结果在驱动和版本匹配上耗掉一整天,热情直接磨没。入门阶段的建议是:先装 CPU 版本,把代码跑通,等你有把握了再去折腾显卡。CPU 版本跑小数据和线性回归完全够用。
用 conda 建一个独立环境,避免和你电脑里其它 Python 项目打架:
# 建一个专门用于深度学习的独立环境,Python 版本选 3.10 比较稳 conda create -n dl-start python=3.10 -y # 激活这个环境,之后所有安装和运行都在这个环境里进行 conda activate dl-start # 先装 CPU 版本,包体小、装得快,入门阶段够用 pip install torch torchvision三条命令的含义分别是:创建隔离环境、切换进去、安装框架本体和配套的视觉工具库。隔离环境这一步别省,它相当于给你的实验单独开了一间房,弄乱了直接删掉重建,不会波及你系统里其它东西。
装完之后一定要验证,别靠「没报错就是装好了」这种玄学判断:
import torch # 打印版本号,确认装上了 print(torch.__version__) # 打印显卡是否可用,CPU 版本这里会是 False,属于正常现象 print(torch.cuda.is_available()) # 造一个小张量,确认能正常运算 x = torch.ones(2, 3) print(x)如果第一行能打出类似2.x.x的版本号,第三行能打出两行三列的全 1 矩阵,说明环境通了。第二行是False也不用慌,说明你装的是 CPU 版本,第 3.3 节的例子照样能跑。
3.2 第一段代码:认识张量的形状和运算
在跑模型之前,先花十分钟和张量混个脸熟。下面这段代码覆盖了新手最常用的几个操作:
import torch # 从 Python 列表造张量,形状是两行两列 a = torch.tensor([[1.0, 2.0], [3.0, 4.0]]) print("a 的形状:", a.shape) # torch.Size([2, 2]) # 全零、全一、随机初始化,这三种在搭模型时天天用 z = torch.zeros(3, 4) # 三行四列,全 0 o = torch.ones(2, 2) # 两行两列,全 1 r = torch.randn(2, 3) # 两行三列,标准正态分布随机数 # 改变形状:把两行两列拍平成一行四个 flat = a.reshape(1, 4) print("拍平后:", flat.shape) # torch.Size([1, 4]) # 矩阵乘法用 @,注意左矩阵的列数要等于右矩阵的行数 b = torch.randn(2, 3) c = a @ b print("相乘后:", c.shape) # torch.Size([2, 3])逐条解释几个关键点。torch.tensor是从现成数据造张量,torch.zeros、torch.ones、torch.randn是按形状造张量,后三个在初始化权重时用得最多。reshape只改形状不改数据,但改完的元素总数必须和原来一致,两行两列四个数,只能变成一行四列或四行一列,变成三行三列就会直接报错。
@是矩阵乘法运算符。这条规则是新手前期最容易翻车的地方:左矩阵的列数必须等于右矩阵的行数。上面的例子里a是 2×2,b是 2×3,所以能乘,结果形状是 2×3。如果你把b改成 3×2,那a @ b就会报错。
提示:报错信息里出现
mat1 and mat2 shapes cannot be multiplied,九成是矩阵乘法两边的形状不匹配。看到这句先别慌,把两边的shape打印出来对着看。
3.3 第二段代码:跑通一次完整训练
现在跑一个真家伙:让程序自己找出「y 等于 3 乘 x 加 2」这条直线的两个参数。数据是我们自己造的,所以我们知道正确答案是 3 和 2,最后可以对照着看模型学得准不准。
import torch # 固定随机种子,保证每次运行结果一致,方便你对照 torch.manual_seed(0) # 造 100 个样本:y = 3x + 2,再掺一点噪声,模拟真实数据的抖动 x = torch.randn(100, 1) y = 3 * x + 2 + 0.1 * torch.randn(100, 1) # 需要学习的两个参数,随机给初值,requires_grad 打开账本 w = torch.randn(1, 1, requires_grad=True) b = torch.zeros(1, 1, requires_grad=True) lr = 0.1 # 学习率:每次参数挪动的幅度 for step in range(200): # 训练 200 轮 pred = x @ w + b # 第一步:前向计算 loss = ((pred - y) ** 2).mean() # 第二步:均方误差 loss.backward() # 第三步:反向传播,算梯度 with torch.no_grad(): # 更新参数时不记录梯度 w -= lr * w.grad # 第四步:沿梯度反方向挪一小步 b -= lr * b.grad w.grad.zero_() # 第五步:梯度清零,防止累加 b.grad.zero_() if step % 50 == 0: print(f"第 {step} 轮,损失 {loss.item():.4f}") print(f"学到的 w = {w.item():.3f},b = {b.item():.3f}")跑完你会看到损失从几下降到接近 0.01,最后打印出来的w和b会非常接近 3 和 2。这就是一次完整的训练。
几个参数值得说清楚。lr是学习率,它决定每次参数挪多大一步。设太大会来回震荡甚至越训越差,设太小则收敛慢得像爬。0.1 对这个小例子合适,换成真实模型通常要小得多。range(200)是训练轮数,轮数不够损失降不下去,轮数太多又可能过拟合。with torch.no_grad()的作用是告诉框架「这段别记账」,因为更新参数这个动作本身不需要求导,不加这层会导致计算图越堆越大。
把这段代码和 2.4 节那五个动作对照着看一遍,你会发现顺序完全对得上。这就是为什么前面要专门讲那五步——它是所有 PyTorch 代码的骨架。
3.4 配套源码和 PPT 怎么配合着用
拿到一套教程,最笨的用法是从第一个文件按顺序看到最后一个。更有效的顺序是:先用 PPT 建立整体地图,知道这门课要带你走哪几站;再挑一个最短的源码文件跑通,拿到「我能跑起来」的信心;最后才回头按章节补细节。
具体到操作上,跑源码之前先做三件事:读一遍文件开头的注释和导入部分,看它依赖了什么;找到数据加载的那几行,搞清数据长什么样;找到训练循环,对照 2.4 节的五步看它有没有缺。这三件事做完,一个陌生的训练脚本你就能大致读懂了。
跑通之后别急着看下一个,先把参数改一改再跑一遍。把学习率改成 1 和 0.001 各试一次,看看损失曲线有什么变化;把训练轮数改成 10 和 1000 各试一次;把网络层数加一层试试。这种「改一改看结果」的过程,比被动看十段代码学到的东西多。
4. 顺着配套源码往上走:CNN、RNN、GAN 各自解决什么问题
4.1 卷积神经网络:为什么图片不能直接拍平
如果你把一张图的所有像素拍成一条长长的向量,再喂给普通全连接层,会发生两件事:参数量爆炸,以及图像的空间结构被彻底打乱——原本相邻的两个像素被打散到向量两端,模型学不到「边上有什么」。
卷积神经网络(CNN)解决的就是这个问题。它的核心动作是「用小窗口在图上滑动」,每次只看局部一小块,然后把结果汇总。这带来两个好处:参数共享,同一个窗口滑遍全图,参数量比全连接少几个数量级;平移不变性,猫出现在左上角还是右下角,识别结果都该一样。
用 PyTorch 写一个最小卷积块,其实只有三行:
import torch.nn as nn # 输入 3 通道彩色图,输出 16 个特征图 # kernel_size=3 表示用 3×3 的小窗口滑动 conv = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1) # 激活函数,把负值压成 0,给网络引入非线性 act = nn.ReLU() # 每次取窗口内最大值,把长宽各缩小一半 pool = nn.MaxPool2d(kernel_size=2)in_channels=3对应 RGB 三通道,灰度图就是 1。out_channels=16表示这一层会生成 16 张特征图,每一张关注一种局部模式,比如某一张专门对横线敏感,另一张对直角敏感。padding=1是在四周补一圈零,目的是让输出尺寸和输入保持一致,不补的话每卷一次边缘都会被削掉一点。
一层卷积之后通常接激活函数再接池化。池化把长宽各砍一半,作用是压缩信息、扩大感受野,同时降低计算量。这三样东西堆几层,最后接一个全连接层输出分类结果,就是一个标准的图像分类网络。
新手学到这里最容易陷入的误区,是钻进去研究卷积的数学定义。入门阶段你只需要记住三件事:它用局部窗口提取特征、参数在全图共享、堆叠层数越多看到的范围越大。够用了。
4.2 循环神经网络:处理有先后顺序的数据
图片没有先后顺序,但文本、语音、时间序列有。一句话里「不」和「好」的位置调换,意思完全相反。普通网络把每个输入当独立个体处理,天然抓不到这个顺序信息。
循环神经网络(RNN)的做法是引入「记忆」:处理当前这一步时,除了看当前输入,还把上一步的输出一起拿来看。用代码表达非常短:
import torch.nn as nn # 输入向量长度 128,隐藏状态长度 256,堆两层 rnn = nn.RNN(input_size=128, hidden_size=256, num_layers=2, batch_first=True)input_size是每一步输入的向量长度,hidden_size是那个「记忆」的宽度,num_layers是堆几层。batch_first=True表示输入张量的第一个维度是批大小,这是新手最容易搞混的一个开关,不设的话默认把序列长度放第一位,后面形状对不上就要查半天。
朴素 RNN 有个经典毛病:序列一长,早期的信息就传不到后面,梯度在回传时越乘越小,最后接近于零,也就是常说的梯度消失。所以实际工程里更多用它的两个改进版本,一个加了门控机制来决定记什么忘什么,另一个用类似思路但结构更简洁。入门阶段先把「记忆」这个直觉建立起来,至于用哪个变体,跟着教程源码走就行。
4.3 生成对抗网络:两个网络互相较劲
前面两类模型都是「输入什么判断什么」,生成对抗网络(GAN)干的是另一件事:造出以假乱真的数据。
它的结构很有意思,由两个网络组成。一个叫生成器,负责从随机噪声里造样本;一个叫判别器,负责判断一个样本是真的还是造的。训练时两者交替上场:判别器努力分辨真假,生成器努力骗过判别器。两边互相促进,造出来的东西越来越像真的。
写出来就是个博弈过程:
for step in range(总共轮数): # 第一轮:固定生成器,训练判别器,让它学会分辨真假 fake = 生成器(随机噪声) 判别器损失 = 判别器(真样本, 标签真) + 判别器(fake.detach(), 标签假) 更新判别器() # 第二轮:固定判别器,训练生成器,让它学会骗人 fake = 生成器(随机噪声) 生成器损失 = 判别器(fake, 标签真) # 注意这里目标是让判别器判成真 更新生成器()这段伪代码里有两个新手必须注意的细节。fake.detach()的作用是把生成器造出来的样本从计算图里摘出来,训练判别器时不能让它顺手把生成器的梯度也更新了。生成器损失那里把标签写成「真」,是因为生成器的目标就是骗判别器,这个「反着标」的写法是 GAN 最反直觉的地方。
GAN 的训练是出了名的不稳定,两边实力失衡就容易崩:判别器太强,生成器学不到东西;生成器太强,判别器给不出有效信号。这不是你代码写错了,是这个结构本身的脾气。入门阶段跑通一个能出模糊结果的小例子就够了,别一上来就追求高质量生成。
4.4 一套陌生源码怎么读才不迷路
配套源码通常按模型类型分目录。拿到之后,按这个顺序读会顺很多:
先看数据部分,找到数据是怎么加载、怎么划分、怎么变成张量的。数据决定了一切,看不懂数据就看不懂后面的模型。再看模型定义,找到那个继承自nn.Module的类,看它的__init__里定义了哪些层,forward里这些层按什么顺序串起来。然后把训练循环找出来,对照 2.4 节的五步逐个对上。最后看评估部分,看它用什么指标判断好坏。
读的过程中有个笨办法特别有效:在每个关键的张量后面打印形状。模型定义得再花哨,形状对不上就是跑不了,而形状对了,逻辑通常也就顺了。
5. 新手避坑排查清单:五个最常见的翻车现场
5.1 环境与安装阶段的坑
坑一:装完之后发现用不了显卡,或者装到一半卡住不动。
现象是torch.cuda.is_available()一直返回False,或者pip install卡在下载阶段十几分钟没反应。
原因通常有两个:装的是默认的 CPU 版本,本来就不带显卡支持;或者网络到软件源的速度慢,包体又大,卡在下载很正常。
解决办法是先确认自己装的是哪个版本,去官方安装页面对着自己的系统和显卡情况选对应命令重新装一遍。如果只是下载慢,换个时间段或者配置国内镜像源通常能缓解。入门阶段其实建议就用 CPU 版本,等真需要跑大模型了再折腾,能省掉一整天的折腾。
坑二:在错的环境里装包,跑代码时提示找不到模块。
现象是明明刚pip install过,一运行就报ModuleNotFoundError: No module named 'torch'。
原因是你的终端里激活的环境和编辑器里选用的解释器不是同一个。命令行装进了 A 环境,编辑器用的是 B 环境。
解决办法是两步核对:在终端里执行conda activate 环境名后跑which python看路径,在编辑器里找到解释器设置,把路径选成同一个。这个坑我踩过不止一次,养成「装包前先确认环境,装完立刻验证」的习惯能省很多事。
5.2 数据与形状阶段的坑
坑三:模型跑到一半报形状不匹配。
现象是报错里出现size mismatch或者shapes cannot be multiplied,程序在某一行直接中断。
原因基本是张量维度对不上。常见的有三种:图片数据忘了从[高, 宽, 通道]转成[通道, 高, 宽];卷积层输出接全连接层时忘了先把特征图拍平;批大小那一维忘了加,或者加错了位置。
解决办法是在报错那一行前面把参与运算的所有张量的shape都打印出来,逐个核对。特别记住两件事:PyTorch 图片张量的通道维在前面,矩阵乘法要求左列等于右行,拍平用reshape(x.size(0), -1),第一个参数保留批大小。
坑四:标签的数据类型不对,损失函数直接报错。
现象是跑分类任务时,交叉熵损失函数抛出类型相关的异常。
原因是分类任务的标签必须是 64 位整数,而很多人从 numpy 转过来的时候默认是浮点。
解决办法是在构造数据集时显式转换:labels = labels.long()。这一行看起来无关紧要,但它能省掉你半小时的排查时间。
5.3 训练过程的坑
坑五:损失不降、来回震荡,甚至变成 nan。
现象是训练跑了几十轮,损失值在某个数附近反复横跳,或者突然变成nan,模型彻底废掉。
原因按出现频率排:学习率设得太大,每步迈过头,参数在两极之间来回弹;忘了梯度清零,梯度一轮轮累加,越滚越大最后溢出;数据没有归一化,数值范围差太多,梯度被大数值主导;模型太深而初始化又不合适。
解决办法按顺序试:先把学习率调小十倍,这是最快见效的一招;再检查训练循环里有没有zero_grad();然后把输入数据归一化到 0 到 1 或者标准化到均值 0 方差 1;最后再考虑换初始化方式。如果损失变成nan了,从后往前找,通常是某一步除零或者对零取了对数。
还有一个不报错但很常见的坑:训练时忘了切换模式。带批归一化或者随机失活的模型,在训练和推理时的行为是不一样的。预测前要调.eval(),训练前要调.train(),不切换的话你会看到「训练集准确率很高,测试集一塌糊涂」的诡异现象,然后怀疑人生。
注意:新手排查问题的顺序建议固定成「先形状、再数值、后结构」。形状问题会直接报错,最好查;数值问题表现成损失异常,次之;结构问题最隐蔽,放到最后查。
6. 下一步学什么:一条不绕路的三个月路线
跑通上面的例子之后,很多人会问:然后呢?我给一条自己带新人时用过的路线,按周推进,每一步都有明确的产出物,不至于学着学着不知道自己在哪儿。
| 阶段 | 时间 | 主要任务 | 产出物 |
|---|---|---|---|
| 打地基 | 第 1 到 2 周 | 张量操作、自动求导、一次完整训练循环 | 能手写线性回归和逻辑回归 |
| 上手视觉 | 第 3 到 5 周 | 卷积层、池化、数据增强、分类任务全流程 | 跑通一个手写数字识别 |
| 上手序列 | 第 6 到 8 周 | 循环结构、序列建模、文本分类 | 跑通一个文本情感分类 |
| 拓展 | 第 9 到 12 周 | 生成模型、迁移学习、模型保存与加载 | 能用现成模型改造成自己的任务 |
第 1 到 2 周的重点不是学多少东西,而是把「五步训练循环」变成肌肉记忆。你合上教程,能凭记忆写出一个能跑的线性回归,这两周就算过关。
第 3 到 5 周进入视觉。这个阶段最容易贪多,看到各种网络结构都想跑一遍。建议是挑一个最简单的分类任务,从数据加载、模型定义、训练、评估到保存模型,完完整整走一遍。跑通一次完整流程,比稀里糊涂跑十个 demo 有用得多。配套源码在这一段的价值最大,你可以对着它改数据增强、改层数、改学习率,看每一步的变化。
第 6 到 8 周进入序列。这一段的核心是理解「记忆」是怎么在时间步之间传递的。刚开始容易被各种张量的维度绕晕,一个实用的办法是拿一个极小的例子,比如只处理长度 5 的句子、批大小为 2,手动打印每一步的形状,看着数据在时间维上流动。
第 9 到 12 周是拓展期。到这个时候你已经不缺概念了,缺的是把模型用到自己数据上的经验。找一个你真正关心的小问题,哪怕只是给几百张图片分类,从头做一遍,你会遇到一堆教程里不会讲的问题:数据脏、类别不平衡、样本太少。这些问题解决掉,才算真入门。
最后说一个我自己踩过的坑。我刚开始学的时候,总想着先把理论看透再动手,结果书看了两章,代码一行没写,两周后连环境都懒得开了。后来改成「先跑通、再回头补」,进度反而快得多。从那以后我每次学新东西,都强制自己在第一天结束前跑出一个能打印结果的最小例子,哪怕它只有十行。这个习惯救了我很多次。
希望帮到你。
本文还有配套的精品资源,点击获取