网站所有分类中 点击箭头不出现下拉菜单,中小企业网站的建设实践报告,网站设计师薪资参考,网站应具有的功能模块神经网络基础
1 神经网络
深度学习神经网络就是大脑仿生#xff0c;数据从输入到输出经过一层一层的神经元产生预测值的过程就是前向传播#xff08;也叫正向传播#xff09;。
前向传播涉及到人工神经元是如何工作的#xff08;也就是神经元的初始化、激活函数#xf…神经网络基础
1 神经网络
深度学习神经网络就是大脑仿生数据从输入到输出经过一层一层的神经元产生预测值的过程就是前向传播也叫正向传播。
前向传播涉及到人工神经元是如何工作的也就是神经元的初始化、激活函数神经网络如何搭建权重参数计算、数据形如何状变化。千里之行始于足下我们一起进入深度学习的知识海洋吧。
1.1 神经网络概念
1.1.1 什么是神经网络
人工神经网络Artificial Neural Network 简写为ANN也简称为神经网络NN是一种模仿生物神经网络结构和功能的计算模型。它由多个互相连接的人工神经元也称为节点构成可以用于处理和学习复杂的数据模式尤其适合解决非线性问题。人工神经网络是机器学习中的一个重要模型尤其在深度学习领域中得到了广泛应用。
人脑可以看做是一个生物神经网络由众多的神经元连接而成。各个神经元传递复杂的电信号树突接收到输入信号然后对信号进行处理通过轴突输出信号。下图是生物神经元示意图 当电信号通过树突进入到细胞核时会逐渐聚集电荷。达到一定的电位后细胞就会被激活通过轴突发出电信号。
1.1.2 如何构建神经网络
神经网络是由多个神经元组成构建神经网络就是在构建神经元。以下是神经网络中神经元的构建说明 这个流程就像来源不同树突(树突都会有不同的权重)的信息, 进行的加权计算, 输入到细胞中做加和再通过激活函数输出细胞值。
同一层的多个神经元可以看作是通过并行计算来处理相同的输入数据学习输入数据的不同特征。每个神经元可能会关注输入数据中的不同部分从而捕捉到数据的不同属性。
接下来我们使用多个神经元来构建神经网络相邻层之间的神经元相互连接并给每一个连接分配一个强度如下图所示 神经网络中信息只向一个方向移动即从输入节点向前移动通过隐藏节点再向输出节点移动。其中的基本部分是:
输入层Input Layer: 即输入x的那一层如图像、文本、声音等。每个输入特征对应一个神经元。输入层将数据传递给下一层的神经元。输出层Output Layer: 即输出y的那一层。输出层的神经元根据网络的任务回归、分类等生成最终的预测结果。隐藏层Hidden Layers: 输入层和输出层之间都是隐藏层神经网络的“深度”通常由隐藏层的数量决定。隐藏层的神经元通过加权和激活函数处理输入并将结果传递到下一层。
特点是
同一层的神经元之间没有连接第N层的每个神经元和第N-1层的所有神经元相连这就是Fully Connected的含义)这就是全连接神经网络FCNN全连接神经网络接收的样本数据是二维的数据在每一层之间需要以二维的形式传递第N-1层神经元的输出就是第N层神经元的输入每个连接都有一个权重值w系数和b系数
1.1.3 神经网络内部状态值和激活值 每一个神经元工作时前向传播会产生两个值内部状态值加权求和值和激活值反向传播时会产生激活值梯度和内部状态值梯度。 内部状态值 神经元或隐藏单元的内部存储值它反映了当前神经元接收到的输入、历史信息以及网络内部的权重计算结果。每个输入 x i x_i xi都有一个与之相乘的权重 w i w_i wi表示每个输入信号的重要性。zw⋅xb w权重矩阵x输入值b偏置 激活值 通过激活函数如 ReLU、Sigmoid、Tanh对内部状态值进行非线性变换后得到的结果。激活值决定了当前神经元的输出。af(z) f激活函数z内部状态值
通过控制每个神经元的内部状态值、激活值的大小每一层的内部状态值的方差、每一层的激活值的方差可让整个神经网络工作的更好。
所以下面两个小结我们将要学习神经元的激活函数神经元的权重初始化。
1.2 激活函数
1.2.1 网络非线性因素理解 没有引入非线性因素的网络等价于使用一个线性模型来拟合 通过给网络输出增加激活函数, 实现引入非线性因素, 使得网络模型可以逼近任意函数, 提升网络对复杂问题的拟合能力 激活函数用于对每层的输出数据进行变换, 进而为整个网络注入了非线性因素。此时, 神经网络就可以拟合各种曲线。如果不使用激活函数整个网络虽然看起来复杂其本质还相当于一种线性模型如下公式所示: 另外通过图像可视化的形式理解
神经网络可视化 我们发现增加激活函数之后, 对于线性不可分的场景神经网络的拟合能力更强。
1.2.2 常见激活函数 激活函数主要用来向神经网络中加入非线性因素以解决线性模型表达能力不足的问题它对神经网络有着极其重要的作用。我们的网络参数在更新时使用的反向传播算法BP这就要求我们的激活函数必须可微。 1.2.2.1 Sigmoid 激活函数
激活函数公式 激活函数求导公式 sigmoid 激活函数的函数图像如下: 从sigmoid函数图像可以得到sigmoid 函数可以将任意的输入映射到 (0, 1) 之间当输入的值大致在**-6或者6**时意味着输入任何值得到的激活值都是差不多的这样会丢失部分的信息。比如输入100和输入10000经过 sigmoid的激活值几乎都是等于1的但是输入的数据之间相差100倍的信息就丢失了。 对于sigmoid函数而言输入值在**[-6, 6]之间输出值才会有明显差异**输入值在**[-3, 3]之间才会有比较好的效果** 通过上述导数图像我们发现导数数值范围是 (0, 0.25)当输入的值**-6或者6时sigmoid激活函数图像的导数接近为 0**此时网络参数将更新极其缓慢或者无法更新。 一般来说sigmoid网络在5层之内就会产生梯度消失现象。而且该激活函数的激活值并不是以0为中心的激活值总是偏向正数导致梯度更新时只会对某些特征产生相同方向的影响所以在实践中这种激活函数使用的很少。sigmoid函数一般只用于二分类的输出层。
在 PyTorch中使用sigmoid函数的示例代码如下:
import torch
import matplotlib.pyplot as pltplt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签
plt.rcParams[axes.unicode_minus] False # 用来正常显示负号
绘制激活函数图像时出现以下提示需要将anaconda3/Lib/site-packages/torch/lib目录下的libiomp5md.dll文件删除
OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.
# 创建画布和坐标轴
_, axes plt.subplots(1, 2)# 函数图像
x torch.linspace(-20, 20, 1000)
# 输入值x通过sigmoid函数转换成激活值y
y torch.sigmoid(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title(Sigmoid 函数图像)# 导数图像
x torch.linspace(-20, 20, 1000, requires_gradTrue)
torch.sigmoid(x).sum().backward()# x.detach():输入值x的ndarray数组
# x.grad:计算梯度求导
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title(Sigmoid 导数图像)plt.show()1.2.2.2 Tanh 激活函数
Tanh叫做双曲正切函数其公式如下 激活函数求导公式: Tanh的函数图像、导数图像如下 由上面的函数图像可以看到Tanh函数将输入映射到(-1, 1)之间图像以0为中心激活值在0点对称当输入的值大概**-3或者3** 时将被映射为-1或者1。其导数值范围 (0, 1)当输入的值大概**-3或者3**时其导数近似0。 与Sigmoid相比它是以0为中心的使得其收敛速度要比Sigmoid快减少迭代次数。然而从图中可以看出Tanh两侧的导数也为0同样会造成梯度消失。 若使用时可在隐藏层使用tanh函数在输出层使用sigmoid函数。
在 PyTorch 中使用tanh函数的示例代码如下:
import torch
import matplotlib.pyplot as pltplt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签
plt.rcParams[axes.unicode_minus] False # 用来正常显示负号_, axes plt.subplots(1, 2)# 函数图像
x torch.linspace(-20, 20, 1000)
y torch.tanh(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title(Tanh 函数图像)# 导数图像
x torch.linspace(-20, 20, 1000, requires_gradTrue)
torch.tanh(x).sum().backward()axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title(Tanh 导数图像)plt.show()1.2.2.3 ReLU 激活函数
ReLU 激活函数公式如下 激活函数求导公式: ReLU 的函数图像、导数图像如下 ReLU 激活函数将小于0的值映射为0而大于0的值则保持不变它更加重视正信号而忽略负信号这种激活函数运算更为简单能够提高模型的训练效率。当x0时ReLU导数为0而当x0时则不存在饱和问题。所以ReLU 能够在x0时保持梯度不衰减从而缓解梯度消失问题。然而随着训练的推进部分输入会落入小于0区域导致对应权重无法更新。这种现象被称为“神经元死亡”。ReLU是目前最常用的激活函数。与sigmoid相比RELU的优势是 采用sigmoid函数计算量大指数运算反向传播求误差梯度时计算量相对大而采用Relu激活函数整个过程的计算量节省很多sigmoid函数反向传播时很容易就会出现梯度消失的情况从而无法完成深层网络的训练而采用relu激活函数当输入的值0时梯度为1不会出现梯度消失的情况Relu会使一部分神经元的输出为0这样就造成了网络的稀疏性并且减少了参数的相互依存关系缓解了过拟合问题的发生
在 PyTorch 中使用ReLU函数的示例代码如下:
import torch
import matplotlib.pyplot as pltplt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签
plt.rcParams[axes.unicode_minus] False # 用来正常显示负号_, axes plt.subplots(1, 2)# 函数图像
x torch.linspace(-20, 20, 1000)
y torch.relu(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title(Tanh 函数图像)# 导数图像
x torch.linspace(-20, 20, 1000, requires_gradTrue)
torch.relu(x).sum().backward()axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title(Tanh 导数图像)plt.show()1.2.2.4 SoftMax激活函数
softmax用于多分类过程中它是二分类函数sigmoid在多分类上的推广目的是将多分类的结果以概率的形式展现出来。
计算方法如下图所示 SoftMax就是将网络输出的logits通过softmax函数映射成为(0,1)的值而这些值的累和为1满足概率的性质那么我们将它理解成概率选取概率最大也就是值对应最大的节点作为我们的预测目标类别。
在 PyTorch 中使用SoftMax函数的示例代码如下:
import torchscores torch.tensor([0.2, 0.02, 0.15, 0.15, 1.3, 0.5, 0.06, 1.1, 0.05, 3.75])
# dim0, 按行计算
probabilities torch.softmax(scores, dim0)
print(probabilities)程序输出结果:
tensor([0.0212, 0.0177, 0.0202, 0.0202, 0.0638, 0.0287, 0.0185, 0.0522, 0.0183,0.7392])1.2.3 如何选择激活函数 除了上述的激活函数还存在很多其他的激活函数如下图所示: 对于隐藏层:
优先选择ReLU激活函数如果ReLu效果不好那么尝试其他激活如Leaky ReLu等。如果你使用了ReLU 需要注意一下Dead ReLU问题避免出现0梯度从而导致过多的神经元死亡。少使用sigmoid激活函数可以尝试使用tanh激活函数
对于输出层:
二分类问题选择sigmoid激活函数多分类问题选择softmax激活函数回归问题选择identity激活函数
1.3 参数初始化
我们在构建网络之后网络中的参数是需要初始化的。我们需要初始化的参数主要有权重和偏置偏置一般初始化为0即可而对权重的初始化则会更加重要。
参数初始化的作用
防止梯度消失或爆炸初始权重值过大或过小会导致梯度在反向传播中指数级增大或缩小。提高收敛速度合理的初始化使得网络的激活值分布适中有助于梯度高效更新。保持对称性破除权重的初始化需要打破对称性否则网络的学习能力会受到限制。
1.3.1 常见参数初始化方法 随机初始化 均匀分布初始化权重参数初始化从区间均匀随机取值默认区间为01。可以设置为在(- 1 d 1\over\sqrt{d} d 1, 1 d 1\over\sqrt{d} d 1)均匀分布中生成当前神经元的权重其中d为神经元的输入数量。 正态分布初始化随机初始化从均值为0标准差是1的高斯分布中取样使用一些很小的值对参数W进行初始化 优点能有效打破对称性 缺点随机选择范围不当可能导致梯度问题 适用场景浅层网络或低复杂度模型。隐藏层1-3层总层数不超过5层。 全0初始化将神经网络中的所有权重参数初始化为0 优点实现简单缺点无法打破对称性所有神经元更新方向相同无法有效训练适用场景几乎不使用仅用于偏置项的初始化 全1初始化将神经网络中的所有权重参数初始化为1 优点实现简单缺点 无法打破对称性所有神经元更新方向相同无法有效训练会导致激活值在网络中呈指数增长容易出现梯度爆炸 适用场景 测试或调试比如验证神经网络是否能正常前向传播和反向传播特殊模型结构某些稀疏网络或特定的自定义网络中可能需要手动设置部分参数为1偏置初始化偶尔可以将偏置初始化为小的正值如 0.1但很少用1作为偏置的初始值 固定值初始化将神经网络中的所有权重参数初始化为某个固定值 优点实现简单缺点 无法打破对称性所有神经元更新方向相同无法有效训练初始权重过大或过小可能导致梯度爆炸或梯度消失 适用场景 测试或调试 kaiming初始化也叫做HE初始化专为ReLU和其变体设计考虑到ReLU激活函数的特性对输入维度进行缩放 HE初始化分为正态分布的HE初始化、均匀分布的HE初始化 正态分布的he初始化 w权重值从均值为0, 标准差为std中随机采样std sqrt(2 / fan_in)std值越大w权重值离均值0分布相对较广计算得到的内部状态值有较大的正值或负值 均匀分布的he初始化 它从[-limitlimit] 中的均匀分布中抽取样本, limit 是 sqrt(6 / fan_in) fan_in 输入神经元的个数当前层接受的来自上一层的神经元的数量。简单来说就是当前层接收多少个输入 优点适合 ReLU能保持梯度稳定缺点对非 ReLU 激活函数效果一般适用场景深度网络(10层及以上)使用 ReLU、Leaky ReLU 激活函数 xavier初始化也叫做Glorot初始化根据网络输入和输出的维度自动选择权重范围使输入和输出的方差相同 xavier初始化分为正态分布的xavier初始化、均匀分布的xavier初始化 正态化的Xavier初始化 w权重值从均值为0, 标准差为std中随机采样std sqrt(2 / (fan_in fan_out))std值越小w权重值离均值0分布相对集中计算得到的内部状态值有较小的正值或负值 均匀分布的Xavier初始化 [-limitlimit] 中的均匀分布中抽取样本, limit 是 sqrt(6 / (fan_in fan_out)) fan_in 是输入神经元个数当前层接受的来自上一层的神经元的数量。简单来说就是当前层接收多少个输入fan_out 是输出神经元个数当前层输出的神经元的数量也就是当前层会传递给下一层的神经元的数量。简单来说就是当前层会产生多少个输出。 优点适用于Sigmoid、Tanh 等激活函数解决梯度消失问题 缺点对 ReLU 等激活函数表现欠佳 适用场景深度网络(10层及以上)使用 Sigmoid 或 Tanh 激活函数
import torch.nn as nn# 1. 均匀分布随机初始化
def test01():linear nn.Linear(5, 3)# 从0-1均匀分布产生参数nn.init.uniform_(linear.weight)nn.init.uniform_(linear.bias)print(linear.weight.data)# 2. 固定初始化
def test02():linear nn.Linear(5, 3)nn.init.constant_(linear.weight, 5)print(linear.weight.data)# 3. 全0初始化
def test03():linear nn.Linear(5, 3)nn.init.zeros_(linear.weight)print(linear.weight.data)# 4. 全1初始化
def test04():linear nn.Linear(5, 3)nn.init.ones_(linear.weight)print(linear.weight.data)# 5. 正态分布随机初始化
def test05():linear nn.Linear(5, 3)nn.init.normal_(linear.weight, mean0, std1)print(linear.weight.data)# 6. kaiming 初始化
def test06():# kaiming 正态分布初始化linear nn.Linear(5, 3)nn.init.kaiming_normal_(linear.weight)print(linear.weight.data)# kaiming 均匀分布初始化linear nn.Linear(5, 3)nn.init.kaiming_uniform_(linear.weight)print(linear.weight.data)# 7. xavier 初始化
def test07():# xavier 正态分布初始化linear nn.Linear(5, 3)nn.init.xavier_normal_(linear.weight)print(linear.weight.data)# xavier 均匀分布初始化linear nn.Linear(5, 3)nn.init.xavier_uniform_(linear.weight)print(linear.weight.data)1.3.2 如何选择参数初始化 激活函数的选择根据激活函数的类型选择对应的初始化方法 Sigmoid/Tanhxavier 初始化ReLU/Leaky ReLUkaiming 初始化 神经网络模型的深度 浅层网络随机初始化即可深层网络需要考虑方差平衡如 xavier 或 kaiming 初始化
1.4 神经网络搭建和参数计算
1.4.1 构建神经网络
在pytorch中定义深度神经网络其实就是层堆叠的过程继承自nn.Module实现两个方法
__init__方法中定义网络中的层结构主要是全连接层并进行初始化forward方法在实例化模型的时候底层会自动调用该函数。该函数中为初始化定义的layer传入数据进行前向传播等。
接下来我们来构建如下图所示的神经网络模型 编码设计如下
第1个隐藏层权重初始化采用标准化的xavier初始化 激活函数使用sigmoid第2个隐藏层权重初始化采用标准化的He初始化 激活函数采用reluout输出层线性层 假若多分类采用softmax做数据归一化
构造神经网络模型代码:
import torch
import torch.nn as nn
from torchsummary import summary # 计算模型参数,查看模型结构, pip install torchsummary -i https://mirrors.aliyun.com/pypi/simple/# 创建神经网络模型类
class Model(nn.Module):# 初始化属性值def __init__(self):# 调用父类的初始化属性值super(Model, self).__init__()# 创建第一个隐藏层模型, 3个输入特征,3个输出特征self.linear1 nn.Linear(3, 3)# 初始化权重nn.init.xavier_normal_(self.linear1.weight)nn.init.zeros_(self.linear1.bias)# 创建第二个隐藏层模型, 3个输入特征(上一层的输出特征),2个输出特征self.linear2 nn.Linear(3, 2)# 初始化权重nn.init.kaiming_normal_(self.linear2.weight, nonlinearityrelu)nn.init.zeros_(self.linear2.bias)# 创建输出层模型self.out nn.Linear(2, 2)# 创建前向传播方法,自动执行forward()方法def forward(self, x):# 数据经过第一个线性层x self.linear1(x)# 使用sigmoid激活函数x torch.sigmoid(x)# 数据经过第二个线性层x self.linear2(x)# 使用relu激活函数x torch.relu(x)# 数据经过输出层x self.out(x)# 使用softmax激活函数# dim-1:每一维度行数据相加为1x torch.softmax(x, dim-1)return x训练神经网络模型代码:
# 创建构造模型函数
def train():# 实例化model对象my_model Model()# 随机产生数据my_data torch.randn(5, 3)print(my_data--, my_data)print(my_data shape, my_data.shape)# 数据经过神经网络模型训练output my_model(my_data)print(output--, output)print(output shape--, output.shape)# 计算模型参数# 计算每层每个神经元的w和b个数总和print(计算模型参数)summary(my_model, input_size(3,), batch_size5)# 查看模型参数print(查看模型参数w和b)for name, parameter in my_model.named_parameters():print(name, parameter)if __name__ __main__:train()1.4.2 观察数据形状变化 观察程序输入和输出的数据形状变化 输入5行数据输出也是5行数据输入5行数据3个特征经过第一个隐藏层是3个特征经过第二个隐藏层是2个特征经过输出层是2个特征模型最终预测结果是5行2列数据 mydata.shape--- torch.Size([5, 3])
output.shape--- torch.Size([5, 2])
mydata---tensor([[-0.3714, -0.8578, -1.6988],[ 0.3149, 0.0142, -1.0432],[ 0.5374, -0.1479, -2.0006],[ 0.4327, -0.3214, 1.0928],[ 2.2156, -1.1640, 1.0289]])
output---tensor([[0.5095, 0.4905],[0.5218, 0.4782],[0.5419, 0.4581],[0.5163, 0.4837],[0.6030, 0.3970]], grad_fnSoftmaxBackward)1.4.3 模型参数计算 模型参数的计算 以第一个隐层为例该隐层有3个神经元每个神经元的参数为4个w1,w2,w3,b1所以一共用3x412个参数。 输入数据和网络权重是两个不同的事儿对于初学者理解这一点十分重要要分得清。 ----------------------------------------------------------------Layer (type) Output Shape Param #
Linear-1 [5, 3] 12Linear-2 [5, 2] 8Linear-3 [5, 2] 6Total params: 26
Trainable params: 26
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 0.00
Params size (MB): 0.00
Estimated Total Size (MB): 0.00
----------------------------------------------------------------1.4.4 查看模型参数 通常继承nn.Module撰写自己的网络层。它强大的封装不需要我们定义可学习的参数比如卷积核的权重和偏置参数。 如何才能查看封装好的可学习的网络参数哪 模块实例名.name_parameters,会分别返回name和parameter # 实例化model对象
mymodel Model()# 查看网络参数
for name, parameter in mymodel.named_parameters():# print(name---, name)# print(parameter---, parameter)print(name, parameter)结果显示 linear1.weight Parameter containing:
tensor([[ 0.1715, -0.3711, 0.1692],[-0.2497, -0.6156, -0.4235],[-0.7090, -0.0380, 0.4790]], requires_gradTrue)
linear1.bias Parameter containing:
tensor([-0.2320, 0.3431, 0.2771], requires_gradTrue)
linear2.weight Parameter containing:
tensor([[-0.5044, -0.7435, -0.6736],[ 0.6908, -0.1466, -0.0019]], requires_gradTrue)
linear2.bias Parameter containing:
tensor([0.2340, 0.4730], requires_gradTrue)
out.weight Parameter containing:
tensor([[ 0.5185, 0.4019],[-0.4313, -0.3438]], requires_gradTrue)
out.bias Parameter containing:
tensor([ 0.4521, -0.6339], requires_gradTrue)2 损失函数
2.1 损失函数概念
在深度学习中, 损失函数是用来衡量模型参数质量的函数, 衡量的方式是比较网络输出预测值和真实输出真实值的差异。
模型通过最小化损失函数的值来调整参数使其输出更接近真实值。 损失函数在不同的文献中名称是不一样的主要有以下几种命名方式 损失函数作用
评估性能反映模型预测结果与目标值的匹配程度。指导优化通过梯度下降等算法最小化损失函数优化模型参数。
2.2 分类任务损失函数 在深度学习的分类任务中使用最多的是交叉熵损失函数所以在这里我们着重介绍这种损失函数。 2.2.1 多分类任务损失函数
在多分类任务通常使用softmax将logits转换为概率的形式所以多分类的交叉熵损失也叫做softmax损失它的计算方法是 其中:
yi是样本x属于某一个类别的真实概率而f(x)是样本属于某一类别的预测分数S是softmax激活函数,将属于某一类别的预测分数转换成概率L用来衡量真实值y和预测值f(x)之间差异性的损失结果
例子 上图中的交叉熵损失为 从概率角度理解我们的目的是最小化正确类别所对应的预测概率的对数的负值(损失值最小)如下图所示 在PyTorch中使用nn.CrossEntropyLoss()实现如下所示
import torch
from torch import nn# 分类损失函数交叉熵损失使用nn.CrossEntropyLoss()实现。nn.CrossEntropyLoss()softmax 损失计算
def test01():# 设置真实值: 可以是热编码后的结果也可以不进行热编码# y_true torch.tensor([[0, 1, 0], [0, 0, 1]], dtypetorch.float32)# 注意的类型必须是64位整型数据y_true torch.tensor([1, 2], dtypetorch.int64)y_pred torch.tensor([[0.2, 0.6, 0.2], [0.1, 0.8, 0.1]], requires_gradTrue, dtypetorch.float32)# 实例化交叉熵损失默认求平均损失# reductionsum总损失loss nn.CrossEntropyLoss()# 计算损失结果my_loss loss(y_pred, y_true).detach().numpy()print(loss:, my_loss)2.2.2 二分类任务损失函数
在处理二分类任务时我们不再使用softmax激活函数而是使用sigmoid激活函数那损失函数也相应的进行调整使用二分类的交叉熵损失函数
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
其中: y是样本x属于某一个类别的真实概率 而y^是样本属于某一类别的预测概率 L用来衡量真实值y与预测值y^之间差异性的损失结果。
在PyTorch中实现时使用nn.BCELoss() 实现如下所示
import torch
from torch import nndef test02():# 1 设置真实值和预测值# 预测值是sigmoid输出的结果y_pred torch.tensor([0.6901, 0.5459, 0.2469], requires_gradTrue)y_true torch.tensor([0, 1, 0], dtypetorch.float32)# 2 实例化二分类交叉熵损失loss nn.BCELoss()# 3 计算损失my_loss loss(y_pred, y_true).detach().numpy()print(loss, my_loss)2.3 回归任务损失函数
2.3.1 MAE损失函数
**Mean absolute loss(MAE)**也被称为L1 Loss是以绝对误差作为距离
损失函数公式: 曲线如下图所示
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
特点是
由于L1 loss具有稀疏性为了惩罚较大的值因此常常将其作为正则项添加到其他loss中作为约束。((0点不可导, 产生稀疏矩阵))L1 loss的最大问题是梯度在零点不平滑导致会跳过极小值适用于回归问题中存在异常值或噪声数据时可以减少对离群点的敏感性
在PyTorch中使用nn.L1Loss()实现如下所示
import torch
from torch import nn# 计算inputs与target之差的绝对值
def test03():# 1 设置真实值和预测值y_pred torch.tensor([1.0, 1.0, 1.9], requires_gradTrue)y_true torch.tensor([2.0, 2.0, 2.0], dtypetorch.float32)# 2 实例MAE损失对象loss nn.L1Loss()# 3 计算损失my_loss loss(y_pred, y_true).detach().numpy()print(loss:, my_loss)2.3.2 MSE损失函数
**Mean Squared Loss/ Quadratic Loss(MSE loss)**也被称为L2 loss或欧氏距离它以误差的平方和的均值作为距离
损失函数公式: 曲线如下图所示 特点是 L2 loss也常常作为正则项对于离群点outliers敏感因为平方项会放大大误差 当预测值与目标值相差很大时, 梯度容易爆炸 梯度爆炸:网络层之间的梯度值大于 1.0重复相乘导致的指数级增长会产生梯度爆炸 适用于大多数标准回归问题如房价预测、温度预测等
在PyTorch中通过nn.MSELoss()实现
import torch
from torch import nndef test04():# 1 设置真实值和预测值y_pred torch.tensor([1.0, 1.0, 1.9], requires_gradTrue)y_true torch.tensor([2.0, 2.0, 2.0], dtypetorch.float32)# 2 实例MSE损失对象loss nn.MSELoss()# 3 计算损失my_loss loss(y_pred, y_true).detach().numpy()print(myloss:, my_loss)2.3.3 Smooth L1损失函数 smooth L1说的是光滑之后的L1是一种结合了均方误差MSE和平均绝对误差MAE优点的损失函数。它在误差较小时表现得像 MSE在误差较大时则更像 MAE。 Smooth L1损失函数如下式所示 其中f(x)−y 为真实值和预测值的差值。 从上图中可以看出该函数实际上就是一个分段函数
在[-1,1]之间实际上就是L2损失这样解决了L1的不光滑问题在[-1,1]区间外实际上就是L1损失这样就解决了离群点梯度爆炸的问题
特点是 对离群点更加鲁棒当误差较大时损失函数会线性增加而不是像MSE那样平方增加因此它对离群点的惩罚更小避免了MSE对离群点过度敏感的问题 计算梯度时更加平滑与MAE相比Smooth L1在小误差时表现得像MSE避免了在训练过程中因使用绝对误差而导致的梯度不连续问题
在PyTorch中使用nn.SmoothL1Loss()计算该损失如下所示
import torch
from torch import nndef test05():# 1 设置真实值和预测值y_true torch.tensor([0, 3])y_pred torch.tensor([0.6, 0.4], requires_gradTrue)# 2 实例smmothL1损失对象loss nn.SmoothL1Loss()# 3 计算损失my_loss loss(y_pred, y_true).detach().numpy()print(loss:, my_loss)