文章目录
- 第 1 章 神经网络简介
- 第 2 章 PyTorch 入门
- 总结
第 1 章 神经网络简介
神经网络的学习,并不是灌输规则,也不是理解概念,而是通过反复调整参数,让函数逐步逼近我们期望的映射关系。
具体来说,神经网络的学习过程可以分为 5 个步骤:
- 初始化参数:训练开始前,给参数θ \thetaθ赋予一组随机值,此时模型的输出是粗糙、甚至无意义的;
- 模型预测:将输入x xx输入模型,根据当前的参数,得到输出y yy;
- 计算偏差:对比模型输出y yy和真实目标值,判断模型做得好不好(这一步会用到后续要学的损失函数);
- 调整参数:根据偏差的大小和方向,调整参数θ \thetaθ的取值,让模型的输出更接近目标;
- 重复迭代:重复步骤 2-4,直到模型的输出足够准确,参数不再需要大幅调整。 那神经网络真正学到的是什么?
一组最优的参数配置,以及由这组参数所决定的函数行为。
神经网络的学习,本质上是在参数空间中寻找一组更好的参数,使损失函数不断下降。
回归任务的目标通常是预测一个连续数值。比如根据历史气温预测明天气温,对于这类问题,一个常见的损失函数是均方误差(Mean Squared Error, MSE)。
计算每一个样本预测误差的平方,然后取平均。预测越准确,MSE 就越小。
神经网络训练基本流程:
- 前向传播负责用当前参数产生预测;
- 损失函数负责衡量当前预测有多差;
- 反向传播负责计算每个参数对应的梯度;
- 优化算法负责根据梯度真正修改参数。最基本的参数更新方法就是梯度下降(Gradient Descent):
。
梯度指向局部上升最快的方向,因此负梯度指向局部下降最快的方向。
第 2 章 PyTorch 入门
前向传播负责计算数值,同时记录依赖关系;梯度要等到反向传播时才会真正出现。
x.grad和y.grad此时都是None,而不是0。这是因为梯度是一种反向回溯的产物,只有当你明确发起回溯(比如调用backward())时,PyTorch 才会沿着刚才记录的依赖关系,把梯度算出来并写回到叶子节点上。如果不调用,PyTorch 就不会去计算梯度。
requires_grad是张量的属性,表示这个张量是否有资格被 Autograd 追踪;no_grad()是上下文状态,表示当前这段计算是否需要被记录。no_grad()只是暂时关闭记录,离开这个代码块之后,梯度记录会恢复。如果需要重新加入自动微分系统的话,可以在之后设置requires_grad=True;enable_grad():局部恢复梯度记录;inference_mode():纯推理,不要再为反向传播保留任何可能性。
- 虽然
x.requires_grad=True,但y的计算发生在torch.no_grad()上下文中,因此这次计算不会被 Autograd 记录,得到的y也不会继续跟踪梯度。 - 因为训练阶段需要反向传播计算模型参数的梯度,因此前向计算需要记录相应的计算图;而验证和推理阶段通常只需要得到模型的前向计算结果,并不会进行反向传播或更新参数,因此可以关闭梯度记录。这样可以避免保存反向传播所需的中间信息,减少额外的内存占用和计算开销。
- 第一个在
no_grad里所以是False,第二个在enable_grad里面所以是True。
Dataset 负责定义一个样本长什么样,以及如何取出一个样本。如果只是普通张量数据,用TensorDataset就够了。但是,一旦数据稍微复杂一点,比如图片分类数据集,或者文本分类数据集,我们就需要自己写一个 Dataset,在__getitem__()里实现读取文件、做预处理、返回标签的逻辑。-no_grad()是上下文状态,表示当前这段计算是否需要被记录。no_grad()只是暂时关闭记录,离开这个代码块之后,梯度记录会恢复。如果需要重新加入自动微分系统的话,可以在之后设置requires_grad=True;
enable_grad():局部恢复梯度记录;inference_mode():纯推理,不要再为反向传播保留任何可能性。
- 虽然
x.requires_grad=True,但y的计算发生在torch.no_grad()上下文中,因此这次计算不会被 Autograd 记录,得到的y也不会继续跟踪梯度。 - 因为训练阶段需要反向传播计算模型参数的梯度,因此前向计算需要记录相应的计算图;而验证和推理阶段通常只需要得到模型的前向计算结果,并不会进行反向传播或更新参数,因此可以关闭梯度记录。这样可以避免保存反向传播所需的中间信息,减少额外的内存占用和计算开销。
- 第一个在
no_grad里所以是False,第二个在enable_grad里面所以是True。
classSimpleTensorDataset(utils.Dataset):"""Simple dataset that wraps training data and targets."""def__init__(self,X:Tensor,y:Tensor):ifX.size(0)!=y.size(0):raiseAssertionError('X and y must have the same length.')self.X=X self.y=ydef__len__(self)->int:returnlen(self.X)def__getitem__(self,idx:int)->tuple[Tensor,Tensor]:X=self.X[idx]y=self.y[idx]returnX,yDataLoader 负责把很多样本组织成 mini-batch,并处理打乱、多进程加载、拼接 batch、pin memory 等训练时常见细节。
dataloader=utils.DataLoader(dataset,batch_size=32,shuffle=True,)X,y=next(iter(dataloader))print('Input batch shape:',X.shape)print('Target batch shape:',y.shape)从 Dataset 中取出若干个样本(由 batch_size 指定);
把这些样本拼成一个 batch;
如果 shuffle=True,每个 epoch 会打乱样本顺序;
返回可以直接用于模型训练的张量。
Dataset: index -> sample
DataLoader: samples -> batch
如果每个样本的形状不一样,默认拼接就会失败。最常见的例子是自然语言处理中的变长序列,需要自定义 collate_fn,把这些样本整理成模型可以接收的 batch。例如,我们可以把变长序列填充到当前 batch 中的最大长度:
在实际任务中,collate_fn 很常用。比如:
文本任务中对变长句子做 padding;
目标检测中,每张图的目标框数量不同,不能简单 stack;
多模态任务中,把图像、文本、mask、metadata 组织成字典;
对一个 batch 内的数据做额外整理。
num_workers:让 DataLoader 启动多个子进程来提前加载数据。
num_workers=0:所有数据加载都发生在主进程里;num_workers > 0:PyTorch 会启动多个 worker 进程,它们负责提前从 dataset 里取样本、执行 collate_fn,并把准备好的 batch 放到队列里。主进程训练时,就可以从队列中取已经准备好的 batch,这样数据加载和模型计算可以重叠;persistent_workers:控制这些子进程要不要跨 epoch 保留下来。
总结
本文从神经网络的基本原理出发,梳理了其学习过程的 5 个核心步骤:初始化参数、模型预测、计算偏差、调整参数与重复迭代。神经网络学习的本质,是在参数空间中不断寻找一组更优的参数,使损失函数持续下降;而前向传播、损失函数、反向传播与优化算法四者共同构成了训练的基本流程。
随后,我们进入 PyTorch 的实践环节,重点理解了 Autograd 自动微分机制:requires_grad决定张量是否被追踪,no_grad()与enable_grad()控制梯度记录的开关,inference_mode()则用于纯推理场景。在数据加载方面,Dataset负责定义样本的读取方式,DataLoader负责将样本组织成 mini-batch,并通过collate_fn处理变长序列等复杂情况,num_workers与persistent_workers则进一步优化了数据加载的效率。
掌握这些基础概念后,具备了搭建并训练一个简单神经网络模型的能力。下一步可以尝试用 PyTorch 实现一个完整的分类任务,在实践中加深对自动微分与数据流水线的理解。