Pytorch 3 :Model & Training
神经网络的训练
框架
过程大致可以分为以下几步:
- 初始化:对神经网络的权重和偏差进行随机的初始化赋值,将这些初始值作为学习过程的起点;
- 前向传播:输入数据被注入到神经网络中,并通过一系列乘加运算和激活函数,计算每层神经元的激活值,最终产生神经网络的预测输出;
- 损失计算:使用损失函数计算预测输出与实际目标输出之间的差异,量化预测值与真实值的偏差;
- 反向传播:计算损失函数相对于模型参数的梯度,其数值表明损失如何随着这些参数的微小变化而变化;这一步涉及到的数据除了网络中的所有参数外,还需要用到前向传播中计算出来的所有层神经元的激活值;
- 梯度下降:反向传播过程中计算出的梯度表示损失值上升最陡峭的方向,为了最小化损失,网络沿梯度的反方向来更新其参数,更新幅度由学习率控制;
- 迭代:对每一批训练数据(batch)重复步骤2到5多次(epoch),直到神经网络在训练数据上的性能达到令人满意的水平或收敛到一个解决方案。

定义网络
一个简单的前馈神经网络,它接收输入,让输入一个接着一个的通过一些层,最后给出输出。
通过 torch.nn 包来构建。一个 nn.Module 包括层和一个方法 forward(input) 它会返回输出(output)。
1 | import torch |
一个模型可训练的参数可以通过调用 net.parameters() 返回:
1 | params = list(net.parameters()) |
运行一次网络
1 | input = torch.randn(1, 1, 32, 32) |
反向传播计算各个位置梯度
把所有参数梯度缓存器置零,用随机的梯度来反向传播
1 | net.zero_grad() |
损失函数
一个损失函数需要一对输入:模型输出和目标,然后计算一个值来评估输出距离目标有多远。
有一些不同的损失函数在 nn 包中。一个简单的损失函数就是 nn.MSELoss ,这计算了均方误差。
可以调用包,也可以自己设计。
1 | output = net(input) |
使用loss反向传播更新梯度
查看梯度记录的地方
1 | input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d |
当我们调用 loss.backward(),整个图都会微分,而且所有的在图中的requires_grad=True 的张量将会让他们的 grad 张量累计梯度。
为了实现反向传播损失,我们所有需要做的事情仅仅是使用 loss.backward()。你需要清空现存的梯度,要不然将会和现存(上一轮)的梯度累计到一起。
1 | net.zero_grad() # zeroes the gradient buffers of all parameters |
查看某处梯度
1 | print(net.conv1.bias.grad) |
使用梯度和各种方法优化器更新参数
最简单的更新规则就是随机梯度下降。
1 | weight = weight - learning_rate * gradient |
我们可以使用 python 来实现这个规则:
1 | learning_rate = 0.01 |
尽管如此,如果你是用神经网络,你想使用不同的更新规则,类似于 SGD, Nesterov-SGD, Adam, RMSProp, 等。为了让这可行,我们建立了一个小包:torch.optim 实现了所有的方法。使用它非常的简单。
1 | import torch.optim as optim |
上面是一次训练
一般是按照一次多少batch训练,训练10次等.
或者考虑loss 稳定后结束,一般不使用loss小于某个值(因为不知道loss阈值是多少)
或许可以考虑K折交叉检验法(k-fold cross validation)
1 | for epoch in range(2): # loop over the dataset multiple times |
测试单个任务
分类任务,取最高的
1 | outputs = net(images) |
测试总误差
1 | correct = 0 |
各种不同的Loss
交叉熵和加权交叉熵
多用于多分类任务,预测值是每一类各自的概率。label为特定的类别
torch.nn.NLLLOSS通常不被独立当作损失函数,而需要和softmax、log等运算组合当作损失函数。
torch.nn.CrossEntropyLoss相当于softmax + log + nllloss。

预测的概率大于1明显不符合预期,可以使用softmax归一,取log后是交叉熵,取负号是为了符合loss越小,预测概率越大。
1 | # 4类权重是 1, 10, 100, 100 一般是与样本占比成反比 |
- size_average(该参数不建议使用,后续版本可能被废弃),该参数指定loss是否在一个Batch内平均,即是否除以N。默认为True
- reduce (该参数不建议使用,后续版本可能会废弃),首先说明该参数与size_average冲突,当该参数指定为False时size_average不生效,该参数默认为True。reduce为False时,对batch内的每个样本单独计算loss,loss的返回值Shape为[N],每一个数对应一个样本的loss。reduce为True时,根据size_average决定对N个样本的loss进行求和还是平均,此时返回的loss是一个数。
- reduction 该参数在新版本中是为了取代size_average和reduce参数的。
- 它共有三种选项’mean’,’sum’和’none’。
- ‘mean’为默认情况,表明对N个样本的loss进行求平均之后返回(相当于reduce=True,size_average=True);
- ‘sum’指对n个样本的loss求和(相当于reduce=True,size_average=False);
- ‘none’表示直接返回n分样本的loss(相当于reduce=False)
Focal Loss
相对于加权交叉熵不仅权重不需要计算,自动通过概率算,而且gamma=2按照平方缩小了,大样本的影响。

“蓝”线代表交叉熵损失。X轴即“预测为真实标签的概率”(为简单起见,将其称为pt)。举例来说,假设模型预测某物是自行车的概率为0.6,而它确实是自行车, 在这种情况下的pt为0.6。
Y轴是给定pt后Focal loss和CE的loss的值。
从图像中可以看出,当模型预测为真实标签的概率为0.6左右时,交叉熵损失仍在0.5左右。因此,为了在训练过程中减少损失,我们的模型将必须以更高的概率来预测到真实标签。换句话说,交叉熵损失要求模型对自己的预测非常有信心。但这也同样会给模型表现带来负面影响。
深度学习模型会变得过度自信, 因此模型的泛化能力会下降.
当使用γ> 1的Focal Loss可以减少“分类得好的样本”或者说“模型预测正确概率大”的样本的训练损失,而对于“难以分类的示例”,比如预测概率小于0.5的,则不会减小太多损失。因此,在数据类别不平衡的情况下,会让模型的注意力放在稀少的类别上,因为这些类别的样本见过的少,比较难分。
https://cloud.tencent.com/developer/article/1669261
https://blog.csdn.net/qq_34914551/article/details/105393989
https://ptorch.com/news/253.html
Pytorch.nn常用函数
torch.nn.Linear
$$
y=x*A^T+b
$$
设置网络中的全连接层的,需要注意在二维图像处理的任务中,全连接层的输入与输出一般都设置为二维张量,形状通常为[batch_size, size],不同于卷积层要求输入输出是四维张量。
in_features指的是输入的二维张量的大小,即输入的[batch_size, size]中的size。
out_features指的是输出的二维张量的大小,即输出的二维张量的形状为[batch_size,output_size],当然,它也代表了该全连接层的神经元个数。
torch.nn.ReLU()
$$
ReLU(x)=(x)^+=max(0,x)
$$
torch.nn.Sigmoid
$$
Sigmoid(x)=σ(x)= \frac{1}{1+exp(−x)}
$$
- torch.nn.Sigmoid()
- 是一个类。在定义模型的初始化方法中使用,需要在_init__中定义,然后再使用。
- torch.nn.functional.sigmoid():
- 可以直接在forward()里使用。eg.
A=F.sigmoid(x)
- 可以直接在forward()里使用。eg.
torch.cat
cat是concatnate的意思:拼接,联系在一起。
1 | C = torch.cat( (A,B),0 ) #按维数0拼接(竖着拼) |
torch.nn.BatchNorm2d
num_features – C from an expected input of size (N, C, H, W)
torch.nn.BatchNorm1d
Input: (N, C) or (N, C, L), where NN is the batch size, C is the number of features or channels, and L is the sequence length
Output: (N, C) or (N, C, L) (same shape as input)
Softmax函数和Sigmoid函数的区别
https://zhuanlan.zhihu.com/p/356976844
钩子函数
EmptyInitOnDevice 类通过重写 torch_function 方法,可以在特定设备上执行某些 PyTorch 操作时修改其行为。具体来说,它可以跳过初始化操作或将新创建的张量放置在指定设备上。torch_function 方法会在每次调用 PyTorch 操作时被触发,从而允许对这些操作进行细粒度的控制。
1 | class EmptyInitOnDevice(torch.overrides.TorchFunctionMode): |