PyTorch深度学习入门:从张量到CNN/RNN/GAN实战
简介:面向深度学习初学者、转行开发者与课程学员的 PyTorch 入门实战配套材料,围绕神经网络基础、卷积网络、循环网络、生成对抗网络及图卷积等主题,提供可对照视频教程运行的源代码、课件与实验素材,帮助读者从环境安装逐步过渡到模型训练、项目复现与结果分析。压缩包共 142 个文件、约 85.9MB,以 55 个 PDF 课件/讲义和 39 个 Python 脚本为核心,并含 PNG 图示、XML 配置、TXT 说明、Notebook 等辅助文件,便于按章节查阅代码、理解实验流程、整理排错思路。已有 2679 人学习下载。内容覆盖 CIFAR-10 与 ResNet18 实战、LSTM、图卷积网络等案例,并配合数据加载、模型搭建、训练评估与可视化等环节,代码与课件相互对应,既适合边看教程边动手实践,也可作为课程配套练习、阶段复习与项目复现的参考资料,帮助读者建立从理论理解到工程实现的完整学习路径。
1. 先破除一个误解:深度学习并不神秘,它只是“让程序自己调整参数”
很多人第一次听到深度学习,脑子里浮现出来的是一堆看不懂的公式和满屏大写字母。换个说法就好懂了:传统编程是你把规则写清楚,让程序照着做;深度学习是你给它一堆例子,让它自己把规则“猜”出来。猜得不准怎么办?答案会被判错、扣分,它据此微调自己内部的参数,再来一次,反复几万遍,参数就慢慢逼近那个“对的规则”。
这份 PyTorch 深度学习教程配套的源代码和课件,做的事就是把上面这个“猜—扣分—微调”的循环,从你看不懂的内部过程,变成你能亲手调整的几个参数。它覆盖了从基础网络到卷积神经网络、循环神经网络、生成对抗网络的一条完整线索。零基础也能跟着做,前提只有一条:你写过一点点 Python,知道变量、循环、函数是怎么回事。
2. 先搞清楚 PyTorch 是什么:四块基础组件,撑起整套深度学习
在动手之前,得先知道自己要学的东西长什么样。PyTorch 不是一门新语言,它是一个 Python 的第三方库,专门用来搭神经网络、跑训练。你可以把它想象成一套“深度学习积木”:它不会替你想模型结构,但它把最脏最累的活,比如求导、把数据搬到显卡上算、按批次送数据,全都包了。
2.1 深度学习到底在做什么:把“手写规则”换成“用数据找参数”
举个最常见的例子:判断一张图里是不是猫。
用传统写法,你得手写规则:有尖耳朵算一条、有胡须算一条、眼睛是竖瞳算一条。写着写着就发现不对:侧着脸的猫没耳朵形状、糊掉的图没有胡须、玩偶猫全都符合。规则永远写不完,这就是传统方法最尴尬的地方。
深度学习的做法完全反过来。你准备一万张标好“猫”和“不是猫”的图,丢给一个初始参数全是随机数的网络。它先乱猜,猜错了就计算“错得有多离谱”,然后按让错误变小的方向,把内部几百万个参数各自微调一点点。重复几万次之后,这些参数组合出来的效果,就是一种人类写不出来、但确实好用的“判断规则”。
所以学习深度学习,重点并不在背公式,而在搞懂三件事:数据怎么喂进去、参数怎么被调整、结果怎么判断好不好。这三件事,正好对应下面四块组件。
2.2 PyTorch 的四块组件:张量、自动求导、模型、数据管道
新手最容易迷糊的地方是:教程里一会儿 tensor,一会儿 nn.Module,一会儿 DataLoader,不知道哪个是主哪个是次。其实它们的分工很清楚:
| 基础组件 | 一句话作用 | 你什么时候会用到 |
|---|---|---|
| 张量(tensor) | 能放到显卡上算的多维数组 | 从第一个例子开始,天天用 |
| 自动求导(autograd) | 自动帮你把梯度算出来 | 每次调用backward()的时候 |
| 模型(nn.Module) | 装网络层的容器,管参数、管前向计算 | 定义任何网络结构时 |
| 数据管道(Dataset / DataLoader) | 按批次把数据送进模型 | 数据量一大就必须用 |
张量你可以直接理解成“升级版的 NumPy 数组”,区别在于它能在显卡上算,而且记得住自己参与过哪些运算。自动求导就是那个记账的:你对张量做了哪些操作,它一笔一笔记下来,等你说“开始反向传播”,它顺着账本把每个参数的梯度算好。梯度是什么?简单说就是“这个参数往哪个方向调、调多少,损失会变小”。
nn.Module像一块乐高底板。你把卷积层、全连接层、激活函数按顺序插上去,它就自动帮你把所有可训练参数登记在册,你用model.parameters()一句话就能全拿出来交给优化器。DataLoader 则是传送带:它负责把几万张图切成一批一批,每批几十张,边训练边读盘,不会一次性把内存塞满。
这四块组件,就是整套 machine-learning tutorial 反复在用的东西。课件 PPT 里通常会有一两页专门画它们的关系图,看代码之前先翻一遍那几页,后面会顺很多。
2.3 为什么新手先学它:报错看得懂,调试像写普通 Python
框架不止一个,为什么入门建议从它开始?最关键的一点是:它按“写一行、跑一行”的方式工作。
你在脚本里定义完网络,下一行就能直接print(model)把结构打出来;中间想看看某一层的输出长什么样,插一句 print 就行。出错的时候,报错信息会直接指到你写的那一行,Python 的调试器也能照常用。对零基础的人来说,这个体验太重要了。另一种思路是“先把整张计算图定义好,再统一编译执行”,跑得快,但调试时你很难知道中间到底发生了什么,错误信息也经常绕着弯说。
我第一次学的时候踩过的坑就是:贪图“看起来更专业”,选了一个静态图风格的写法,结果一个维度对不上,报错信息只有一句类型不匹配,我对着代码看了整整一晚上,最后发现是把 batch 维度和特征维度写反了。换成动态执行的写法之后,同样的错误,print 一下 shape 就抓出来了。
所以入门阶段,优先选“能让你看见中间结果”的工具,这比性能重要得多。等你把整套流程跑顺了,再考虑性能优化的事完全不迟。
2.4 学之前要不要先补数学:只掌握够用的最低配置
这是问得最多、也最容易把人劝退的问题。直接给结论:不用先把数学补完再开始,边做边补就够了。
入门真正用得上的只有三样。第一是矩阵乘法,你要知道两个矩阵相乘时形状怎么变,因为维度对不上是新手最常见的报错。第二是导数与梯度的直觉,你不需要手算,但要知道“梯度指向上坡方向,所以更新参数时要往反方向走”。第三是一点点概率,比如输出为什么要过 softmax 变成概率分布、交叉熵在衡量什么。
其余的东西,比如链式法则的严格推导、各种优化的收敛性证明,入门阶段完全可以先跳过。你可以在跑通几个例子、对流程有感觉之后,再回头看课件里那些公式,那时候它们就不再是天书,而是“哦,原来是在解释我刚才做的那件事”。
3. 第一步怎么迈:装好环境,跑通两个能出结果的例子
概念说再多,不如让屏幕上出现一行数字。这一章的目标很明确:从零把环境装起来,跑通两个例子,第一个让你看懂张量,第二个让你亲手完成一次“训练”。整个过程不需要显卡,普通笔记本的 CPU 就够。
3.1 装环境:三步走,别一上来就折腾显卡
新手装环境翻车的概率极高,绝大多数是因为把包装进了系统自带的 Python 里,和别的项目打架。所以第一步不是装框架,是建一个独立的环境。
# 第一步:建一个专用虚拟环境,名字随便取,这里叫 dl_env python -m venv dl_env # 第二步:激活它。Windows 用这一行 dl_env\Scripts\activate # 第三步:激活它。macOS / Linux 用这一行 source dl_env/bin/activate激活成功的标志是命令行前面多了一对括号,里面写着dl_env。看到它,说明后面装的任何包都只会落在这个环境里,删掉文件夹就等于彻底卸载,不会留垃圾。
接着装框架和配套的图像库:
# 在已激活的虚拟环境里执行 pip install torch torchvisiontorch是框架本体,torchvision是配套的视觉工具包,后面处理图片数据集、做数据增强都要用它。安装完成后,验证一下:
import torch print(torch.__version__) # 能打印出版本号就说明装好了 print(torch.cuda.is_available()) # 没有显卡的话,输出 False 完全正常第二行输出False不用慌,入门阶段的例子在 CPU 上跑,几秒钟就出结果。有显卡的同学可以之后再研究怎么把张量搬到显卡上,那是加速手段,不是入门门槛。
提示:如果
pip install卡住不动或者报网络错误,先换成国内的镜像源再试,不要一直重试同一条命令。装完之后建议把pip install torch torchvision写进一个requirements.txt,以后换电脑一行命令就能复现环境。
3.2 第一个例子:十分钟看懂张量在干什么
环境好了,先别急着上神经网络,从最小的东西开始。新建一个step1_tensor.py:
import torch # 造两个 2x2 的张量,可以理解成"能上显卡算的多维数组" a = torch.tensor([[1.0, 2.0], [3.0, 4.0]]) b = torch.tensor([[5.0, 6.0], [7.0, 8.0]]) print(a + b) # 逐元素相加:对应位置直接加 print(a * b) # 逐元素相乘:不是矩阵乘法 print(a @ b) # 矩阵乘法,@ 是矩阵乘的专用运算符 print(a.shape) # 形状,输出 torch.Size([2, 2])跑一下,你会看到四组输出。这里最关键的是搞清楚*和@的区别:*是位置上的一一对应相乘,@才是数学课上的矩阵乘法。这两个符号搞混,是后面维度报错的重灾区。
再往下走一步,看看自动求导长什么样:
import torch # requires_grad=True 表示"这个数需要求梯度",框架会自动记账 x = torch.tensor(2.0, requires_grad=True) # 定义一个关于 x 的表达式 y = x ** 2 + 3 * x + 1 y.backward() # 反向传播,把梯度算出来 print(x.grad) # dy/dx = 2x + 3,在 x = 2 处等于 7输出是tensor(7.)。你可能想问:我明明没写求导公式,它怎么算出来的?这就是自动求导在做的事:y是由x一步步算出来的,每一步都被记了下来,backward()一调用,它就顺着记录反着走一遍,把导数算好放进x.grad。
参数说明一下:requires_grad=True是开关,只有打开了,这个张量才会被跟踪;.grad是存放结果的属性,在调用backward()之前它是None。真实训练里,模型的所有参数默认就是这个开关打开的,所以你不必手动设置。
3.3 第二个例子:一个完整训练循环,让机器自己把参数猜出来
现在上正餐。我们造一批假数据,真实关系是y = 3x + 2,然后让模型从完全随机开始,自己把 3 和 2 猜出来。新建step2_train.py:
import torch torch.manual_seed(0) # 固定随机种子,保证你和我跑出来的结果一致 # 1. 造数据:真实关系 y = 3x + 2,故意加一点噪声,模拟真实世界的脏数据 x = torch.rand(100, 1) * 10 y = 3 * x + 2 + torch.randn(100, 1) * 0.5 # 2. 定义模型:一个线性层,输入 1 维、输出 1 维,内部就两个参数 w 和 b model = torch.nn.Linear(1, 1) # 3. 损失函数与优化器 loss_fn = torch.nn.MSELoss() # 均方误差,越小说明猜得越准 optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # 随机梯度下降,lr 是学习率 # 4. 训练循环:前向 → 算损失 → 清零 → 反向 → 更新 for epoch in range(200): pred = model(x) # 前向:拿当前参数去猜 loss = loss_fn(pred, y) # 算一下错得多离谱 optimizer.zero_grad() # 梯度清零,不清会累加到上一轮的结果上 loss.backward() # 反向:算出每个参数的梯度 optimizer.step() # 更新:按梯度把参数往"损失变小"的方向挪一点 if (epoch + 1) % 50 == 0: print(f"第 {epoch + 1} 轮,损失 {loss.item():.4f}") print("学到的权重 w =", model.weight.item()) print("学到的偏置 b =", model.bias.item())跑完你会看到损失从几十一路降到零点几,最后打印出来的w接近 3、b接近 2。这就是整件事的全貌:没有任何人告诉程序答案,它靠“猜错—扣分—微调”,把参数猜到了正确值附近。
几个参数必须解释清楚。lr=0.01是学习率,控制每次挪多大一步:调太大会来回震荡、损失不降反升,调太小则两百轮下来还没走到位,一般从 0.01 或 0.001 试起。MSELoss是均方误差,把每个样本的偏差平方后取平均,回归问题默认用它。SGD是最基础的优化器,你只要记住它是“按梯度反方向挪参数”的那个执行者。
这五行循环的顺序,是全篇最该背下来的东西:前向、算损失、清零、反向、更新。后面无论换成多复杂的网络,卷积也好、循环网络也好,这五步一步都不会变,变的只是模型内部长什么样。
3.4 跑通之后:怎么判断自己是真的懂了
代码能跑不等于懂了。检验方法很简单,做四个小改动,每改一个就先猜结果再看结果:
第一个,把lr改成 1.0,看损失会怎样。大概率你会看到损失先是暴涨然后变成nan,这就是学习率太大导致训练发散的典型症状,以后遇到nan,第一反应就应该是调小学习率。
第二个,把循环里的optimizer.zero_grad()注释掉,再跑一次。损失会变得很奇怪,因为梯度被一轮轮累加起来了。这个实验做一遍,你就永远不会忘记为什么必须清零。
第三个,把噪声* 0.5改成* 5.0,看学出来的w和b还准不准。数据越脏,学出来的参数越偏,这是“垃圾进垃圾出”的最直观演示。
第四个,把轮数从 200 改成 20,看损失停在哪。你会直观感受到“训练不够”是什么样子,这比看十篇讲欠拟合的文章都管用。
做完这四个实验,你手上就已经有了调试模型的直觉。后面课件里那些看起来复杂的例子,本质上都是这个循环加料。
4. 三条主线怎么排:卷积网络、循环网络、生成对抗网络
这份教程的配套代码覆盖了三类经典网络。新手最容易犯的错误,是拿到就按文件夹顺序一个一个硬啃,结果卡在某个看不懂的地方,前面学的也忘了。这一章讲清楚它们各自解决什么问题、适合什么数据,以及该按什么顺序学。
4.1 卷积神经网络:处理图片的主力
卷积神经网络(convolutional neural networks,常写作 CNN)是图像任务的标准解法。它和全连接层最大的区别在于:全连接层把图片拉成一长条,相邻像素的空间关系就丢了;卷积层用一个小的窗口在图上滑动,每次只看局部,因此能捕捉“边缘”“纹理”这类局部特征,而且同一套窗口参数在全图复用,参数少了很多。
搭一个能跑的最小 CNN 长这样:
import torch from torch import nn class SmallCNN(nn.Module): def __init__(self, num_classes=10): super().__init__() # 特征提取:卷积 + 激活 + 池化,重复两次 self.features = nn.Sequential( nn.Conv2d(1, 16, kernel_size=3, padding=1), # 1 通道进,16 通道出,卷积核 3x3 nn.ReLU(), # 激活函数,给网络加非线性 nn.MaxPool2d(2), # 池化,长宽各减半 nn.Conv2d(16, 32, kernel_size=3, padding=1), nn.ReLU(), nn.MaxPool2d(2), ) # 分类头:把特征图拉平,接到全连接层输出类别分数 self.classifier = nn.Sequential( nn.Flatten(), nn.Linear(32 * 7 * 7, num_classes), ) def forward(self, x): return self.classifier(self.features(x)) model = SmallCNN() print(model)先看参数。Conv2d(1, 16, kernel_size=3, padding=1)里,第一个 1 是输入通道数(灰度图是 1,彩色图是 3),16 是输出通道数,也就是用 16 个不同的卷积核去看同一张图,得到 16 张特征图;kernel_size=3是那个滑动窗口的边长;padding=1是在图像四周补一圈 0,保证卷完尺寸不变。MaxPool2d(2)是每 2x2 的区域只留最大值,图的长宽直接减半,作用是压缩信息、扩大感受野。
再看结构。nn.Sequential就是一个按顺序执行的容器,把层像积木一样串起来,forward里一行调用就够了。Flatten()负责把多维的特征图拉成一维向量,因为全连接层只认一维。32 * 7 * 7这个数字不是随便写的:输入 28x28 的图,经过两次减半变成 7x7 又因为第二个卷积输出 32 通道,所以是 32 乘 7 乘 7。这个数字写错,报错信息会直接告诉你实际是多少,照着实到的值改就行。
入门时的顺序建议是:先跑通一个手写数字分类的例子,看清楚数据是怎么从 28x28 的图变成 10 个类别分数的;再回头改通道数、加一层卷积,观察参数量和准确率的变化。
4.2 循环神经网络:处理有先后顺序的数据
卷积网络处理的是“空间”,循环神经网络(recurrent neural networks,常写作 RNN)处理的是“时间”。文本、语音、股票价格这类数据,前后顺序一变意思就变了,“我打他”和“他打我”用词一样,顺序不同。RNN 的做法是:每读一个词就更新一次内部状态,把这个状态往后传,于是后面的判断能带上前面看过的信息。
一个最小的写法:
import torch from torch import nn # 输入特征 8 维,隐藏状态 16 维,batch_first=True 表示第 0 维是批次 rnn = nn.RNN(input_size=8, hidden_size=16, batch_first=True) # 模拟一批数据:4 个样本,每个样本是长度 10 的序列,每步 8 个特征 x = torch.randn(4, 10, 8) out, h_n = rnn(x) print(out.shape) # [4, 10, 16]:每一步都有一个输出 print(h_n.shape) # [1, 4, 16]:最后一步的隐藏状态input_size是每一步输入几个数,hidden_size是内部记忆有多少维,batch_first=True是个很实用的开关,打开之后数据形状是“批次在前”,和绝大多数教程、绝大多数其他层的习惯一致,能省掉大量转置操作。返回两个值:out是每一步的输出,做序列标注、词性判断时用它;h_n是最后一步的记忆,做整句分类时用它。
新手用 RNN 最容易忽略的是它的“记忆衰减”:序列太长时,前面的信息传到后面已经淡得差不多了。所以真实场景里,一般会直接上它的改进版,也就是带门控的结构。入门阶段先把上面这七行跑通、搞清两个返回值的形状,再去理解门控怎么工作,会顺畅得多。
4.3 生成对抗网络:两个网络互相较劲
生成对抗网络(generative adversarial network,常写作 GAN)的思路和前两个完全不同,它不是做分类,而是做生成:画出一张不存在的图、造出一段不存在的人脸。
它的结构里有两个网络,一攻一守。生成器负责造假,从一堆随机数里变出一张图;判别器负责鉴定,看一张图是真货还是假货。训练时两边轮流进步:判别器越来越会挑刺,生成器就被逼着造得越来越像。这个过程有点像造假币的和验钞的互相较劲,最后造假的那位手艺高到验钞的都分不出来。
| 角色 | 输入 | 输出 | 训练目标 |
|---|---|---|---|
| 生成器 | 一串随机数 | 一张假图 | 骗过判别器 |
| 判别器 | 一张图 | 真/假分数 | 分清真假 |
新手看 GAN 的代码,最容易困惑的是“为什么有两个优化器、为什么判别器的标签要一会儿是 1 一会儿是 0”。记住这个原则就行:训练判别器时,把真图标 1、假图标 0,让它学会区分;训练生成器时,把假图标成 1,让它朝“被判成真”的方向优化。两组参数交替更新,所以要有两个优化器。
GAN 的训练是三者里最不稳定的,损失曲线经常上下乱跳,甚至两个网络一起崩掉,这属于这门技术的固有特点,并不是你的代码写错了。入门阶段的目标不是训出惊艳的效果,而是看懂两个网络的参数是怎么交替更新的。看懂这一点,就已经跨过门槛了。
4.4 三条线的学习顺序:先卷积、再循环、最后生成
顺序不是随便定的,它跟难度和复用度直接挂钩。
先学卷积,因为它把“数据怎么组织成批次、模型怎么定义、训练循环怎么写、准确率怎么看”这一整套流程跑得最完整,而且图像任务的结果很直观,对错一眼能看出来。把这条线走通,你就有了一个可以反复套用的模板。
再学循环,因为它引入了新的数据形状:多出来一个“序列长度”维度。这个维度对新手来说很容易搞混,有卷积的基础打底,你会更容易分清哪个维度是批次、哪个是特征。
最后看生成对抗网络,它需要你先熟悉前两种网络,因为生成器和判别器本身通常就是卷积网络堆出来的。前面两条线扎实了,GAN 的结构对你来说只是“两个熟悉的模型拼在一起,加一个交替训练的流程”。
课件 PPT 里的顺序一般也是这么排的,如果你拿到手发现某一节看不懂,先退回去看上一节,八成是前一节的概念没吃透,而不是这一节太难。
5. 新手最容易踩的五个坑:现象、原因、解决
这一章单独拿出来讲,是因为下面这几条我几乎每次带新人都要重复一遍。它们的共同特征是:报错信息看起来吓人,但原因往往只有一行代码那么小。
5.1 环境和安装类的坑
现象一:命令行里import torch报ModuleNotFoundError,但明明装过了。原因基本只有一个:装包和跑代码用的不是同一个 Python。电脑里往往同时存在系统自带的 Python、其他工具装的 Python,以及你刚建的虚拟环境,pip装进哪个、python用的是哪个,两者对不上就找不到包。 解决方法是先确认当前环境。看命令行前面有没有(dl_env)这样的括号,没有就先激活;然后统一用python -m pip install xxx这种写法,让 pip 和 python 绑定在同一个解释器上,能避开绝大多数“装了却找不到”的问题。
现象二:代码跑到一半提示显存不足。原因是你一次性把太多数据塞进去了,或者上一个模型的显存没释放。 解决方法是先把批次大小减半试试,也就是batch_size从 64 降到 32、再降到 16;如果还不行,就先老老实实用 CPU 跑小规模数据。入门阶段的数据集,CPU 完全跑得动,没必要在环境上跟自己较劲。
5.2 训练过程类的坑
现象三:损失一动不动,或者第一轮就变成nan。损失的字母全是 n 的时候,原因通常是学习率太大,参数一步迈太远直接飞出去了;也可能是数据没做归一化,几万的数值进网络,梯度自然爆掉。 解决方法是把lr缩小十倍再跑一次,比如从 0.01 降到 0.001;同时检查输入数据有没有做标准化。这两步能解决绝大部分nan。
现象四:训练集准确率很高,换一批数据就崩。原因一般是过拟合,模型把训练数据的噪声也背下来了;也可能是训练集和测试集的数据处理方式不一致,比如一边做了归一化一边没做。 解决方法是先看数据划分有没有问题,确认测试集从来没有参与训练;再考虑加数据增强、加正则、减少模型参数。第一步永远是检查数据,而不是改模型。
现象五:改了模型结构之后,报形状不匹配。原因几乎都出在维度上:最常见的是卷积层输出尺寸算错,接了全连接层时数字对不上;或者忘了把图拉平。 解决方法是养成习惯,在forward里打印一次中间张量的形状:print(x.shape)。报错信息里其实已经写了期望值和实际值,对着看一眼就知道差在哪。这个习惯能帮你省掉无数个小时。
5.3 看教程和读代码类的坑
现象六:跟着视频一行行抄,抄完能跑,但一关掉视频就写不出来。原因是你抄的是字符,不是逻辑。视频里每一行代码为什么出现、删掉会怎样,你没想过。 解决方法是改一个参数看变化。抄完之后立刻做实验:把轮数改成原来的十分之一、把学习率乘十、把某一层注释掉,看输出怎么变。做三个这样的对比实验,比再抄一遍有用得多。配套源代码的价值也在这里:它有注释、可以随便改,改坏了重下一份就行,这种“敢乱动”的安全感才是学得快的真正原因。
6. 下一步学什么:一条能自己走下去的路线
把上面两个例子跑通之后,很多人会陷入新的迷茫:接下来该干什么?我的建议是不要横向铺开去看各种新模型,而是纵向把一个完整的项目做穿。
具体分三个阶段,你可以照着表里的顺序推:
| 阶段 | 目标 | 具体做什么 | 大概花多久 |
|---|---|---|---|
| 第一阶段 | 流程形成肌肉记忆 | 把训练循环那五行自己默写三遍,不看代码 | 两三天 |
| 第二阶段 | 跑通一个真实数据集 | 图像分类走一遍,把数据加载、训练、评估、保存模型串起来 | 一到两周 |
| 第三阶段 | 换一个方向复用同一套流程 | 挑循环网络或生成对抗网络里的一个,改自己的数据 | 两到三周 |
第一阶段的判断标准很朴素:关掉所有参考,新建一个空文件,从import torch开始,把“前向、算损失、清零、反向、更新”这五步写出来并且能跑通。写不出来就回去看第 3.3 节的例子,直到能默写为止。这一步看起来笨,但它是后面所有内容的地基,地基不牢,后面每学一个新模型都要重新查一遍怎么写循环。
第二阶段重点是补上“工程化”的部分。前面的例子只教了训练,真实项目里还有几件事必须会:把数据集写成Dataset子类、用DataLoader按批次送数据、把训练好的权重存下来再加载、在测试集上算准确率而不是看损失。这几件事课件里通常都有现成的代码段,别只看,自己敲一遍,改几个参数看会怎样。
第三阶段是检验你到底有没有真的掌握。找一个自己感兴趣的小数据集,套用第二阶段的整套代码,只改数据加载部分和网络结构,其他不动。能顺利跑起来并出结果,说明你已经具备独立往前走的能力了。这时候再回头看那些讲原理的章节,会突然顺畅很多,因为那些公式原来是在解释你已经亲眼见过的现象。
最后说个我自己的习惯。从那以后我每次跑通一个新模型,都会强制走一遍“三个实验”:把学习率改大十倍、把数据增强关掉、把批次大小减半,各跑一轮,把结果记在代码注释里。刚开始是逼自己做的,后来发现这三次对比给我的信息量,比继续看十篇教程都多。血泪经验是:那些你以为已经懂了的参数,只有在你亲手把它调坏一次之后,才算真的懂了。
希望帮到你,从第一个张量开始,别急着看懂全部。
本文还有配套的精品资源,点击获取