损失函数,又叫目标函数,用于计算真实值和预测值之间差异的函数,和优化器是编译一个神经网络模型的重要要素。本篇文章主要对 pytorch 中的 损失函数和优化器进行讲解。
神经网络进行前向传播阶段,依次调用每个Layer的Forward函数,得到逐层的输出,最后一层与目标数值比较得到损失函数,计算误差更新值,通过反向传播逐层到达第一层,所有权值在反向传播结束时一起更新。
也就是说损失函数主要有两大作用,
- 计算实际输出和目标输出的差距;
- 为我们的更新输出提供一定的依据;
下面我们通过 查阅 pytorch 的官方文档来介绍一下 pytorch 中的损失函数:
进入 的官方帮助文档,找到损失函数 Loss function 这一项。我们主要介绍 损失函数中的 nn.L1Loss、nn.MSELoss、nn.CrossEntropyLoss这三种。
查看官方帮助文档:
设置三个 reduction 参数进行使用:
结果也是非常的好理解,如下所示:
查看MSELoss 官方文档
代码演示:
CrossEntropyLoss,翻译过来就是交叉熵损失。首先,我们来介绍一下什么是交叉熵。
给定输入向量 x,x[i] 表明类别是 i 的可能性强度,那么 对于输入 x,他对于类别 class 的交叉熵如上图所示,
经过化简之后为:
其中表示为种类的数量,class 为某一个特定的类别。
不难得知 \(loss(x, class)\) 肯定是大于 0 的,而且我们可以分析一下这个函数的合法性:
- 倘若 x[class] 比重越大,那么损失函数计算的数值将越接近于0,也就说是他越为合理
- 倘若其他 j 比重越大, 即 x[j] 越大,损失函数计算数值 也会变大,说明也比较合理
也就是说,该损失函数,可以将提高识别为目标类的概率,降低识别为其他类的概率。
下面,我们来看一下官方的帮助文档(pytorch的该帮助文档有些恐怖!!!):
有能力的看一下官方文档,我翻译的可能不是很准确,但也是尽力的标注和翻译了。
因为二分类交叉熵可以用作分类问题的求解,我们将其用到 我们 CIFAR10 写过的网络中去。
在 cross_entropy_loss.backward() 后面打入断点,可以看到 backward 的效果:
查看 my_model -> model -> Protected Attributes -> _modules -> 任选其中一个,这里我们选择 0,
查看他的 bias 和 weight ,下面的 grad 梯度属性都是 None
断点接着往下执行,一走到 后面,可以看到
数值有所更新,backward 起到了相应的效果。
我们知道,神经网络的学习的目的就是寻找合适的参数,使得损失函数的值尽可能小。解决这个问题的过程为称为最优化。解决这个问题使用的算法叫做优化器。
还是老规矩,我们首先查看 pytorch 优化器的官网
相比于之前 torch.nn 中的帮助文档,torch.optim 显得更为工程化,直接就是教你使用 优化器的步骤。
小建议
lr: learning rate 学习速率,不可太大,也不可太小,太大的话或导致算法的不稳定,太小的话又导致学习的速度太慢。推荐,一开始的时候 ,我们采取比较大的学习速率来进行学习,学习到后面,采用比较小的学习速率来进行学习
使用优化器的步骤
1、先定义一个优化器
2、对优化器的参数进行清零 optim.zero_grad()
3、调用损失函数的 backward,反向传播,求出每一个节点的梯度情况 result_lose.backward()
4、优化器.step 对每个参数进行调优 optim.step()
SGD : 梯度下降法(stochastic gradient descent,SGD)
根据梯度进行控制输出,每一个需要调整的参数,对于神经网络来说,或者是对于卷积层来说,其中的每一个卷积核都是需要进行调整的,通过设置grad 梯度,采用反向传播,每一个节点、或者说是每一个需要更新的参数,他都要求出一个对应的梯度,然后在优化的过程中根据梯度尽心进行优化,最终将整个loss进行降低。
下面我们以 SGD 优化器为例写一个小代码,跑一下我们之前的 CIFAR10 model 搭建的网络。
首先,还是瞄一眼 SGD 优化器的文档:
将 优化器加入到代码中
运行结果:
下面,让我们打一个断点查看一下优化器的具体优化内容,主要是参看 `weight`` 也就是我们卷积核的变化:
从下面的两个图片可以看到确实是发生了变化!
接着查看 optim_SGD.zero_grad() 作用,请看函数执行前 module grad 参数的数值
参考博客:Pytorch 的损失函数Loss function
Date:2021/11/12