【2】激活函数与Loss函数求导

本文涉及的产品
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 【2】激活函数与Loss函数求导

影响找到全局极小值点的几个主要的影响因素:


1)初始点的设置


2)学习率的设置,可能会影响收敛的精度与速度


ps : 处于一个全局极小值或者是鞍点的状态时,往往会影响实验效果


import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
# Jupyter notebook 中的魔法命令
%matplotlib inline                            # 在下面的代码模块里面都可以不用写 plt.show()
%config InlineBackend.figure_format = "png"   # 设置矢量图的方式来提高图片显示质量
# 常用的设置图片分辨率的有以下几个:
# %config InlineBackend.figure_format = “png"
# %config InlineBackend.figure_format = “svg"
# %config InlineBackend.figure_format = “retina"


1.常见的激活函数与梯度


Sign函数

image.png

# 使用函数的运行速度较慢
# def Single_layer(x):
#     if x <= 0:  return 0
#     else:       return 1
X = torch.linspace(-10,10,100)
Y = torch.tensor([0 if x<=0 else 1 for x in X])
plt.plot(X,Y),plt.xlabel('X_value'),plt.ylabel('Y_value'),plt.title('$sign$')
([<matplotlib.lines.Line2D at 0x296e3813c88>],
 Text(0.5, 0, 'X_value'),
 Text(0, 0.5, 'Y_value'),
 Text(0.5, 1.0, '$sign$'))

image.png


Sigmoid函数

image.png

X = torch.linspace(-3,3,100)
Y = F.sigmoid(X)
plt.plot(X,Y),plt.xlabel('X_value'),plt.ylabel('Y_value'),plt.title('$sigmoid$')
([<matplotlib.lines.Line2D at 0x296e1e1d1c8>],
 Text(0.5, 0, 'X_value'),
 Text(0, 0.5, 'Y_value'),
 Text(0.5, 1.0, '$sigmoid$'))

image.png


由此可见,sigmoid函数的特性,可以根据现有的值相乘以下便可以完成导数的求解情况。而且其是连续光滑的,解决了sign函数不能求导的情况。但是,在正无穷或者是负无穷的情况中,导数接近为0。而根据梯度下降法,这会导致梯度长时间得不到更新,这种情况称为梯度弥散现象


Tanh函数

image.png

X = torch.linspace(-3,3,100)
Y = F.tanh(X)
plt.plot(X,Y),plt.xlabel('X_value'),plt.ylabel('Y_value'),plt.title('$tanh$')
([<matplotlib.lines.Line2D at 0x296e3903688>],
 Text(0.5, 0, 'X_value'),
 Text(0, 0.5, 'Y_value'),
 Text(0.5, 1.0, '$tanh$'))

image.png


ReLU函数

image.png

优点,导数计算起来十分的简单,不会放大也不会缩小,梯度会保持变,所以很大情况下会减小出现梯度弥散或者是梯度爆炸的情况


X = torch.linspace(-3,3,100)
Y = F.relu(X)
plt.plot(X,Y),plt.xlabel('X_value'),plt.ylabel('Y_value'),plt.title('$ReLU$')
([<matplotlib.lines.Line2D at 0x296e3f2e6c8>],
 Text(0.5, 0, 'X_value'),
 Text(0, 0.5, 'Y_value'),
 Text(0.5, 1.0, '$ReLU$'))

image.png

Softmax函数

image.png


Leaky ReLU函数

Leaky ReLU函数是在ReLU函数上面做出一个改进,用于对于ReLU函数函数来说,当x<0的时候,其梯度是为0的,而这种情况也可能会导致梯度长时间得不到更新,所以Leaky ReLU函数会在x<0的时候做一个小小的偏移,让其有一个比较小的梯度


X = torch.arange(-10,10,0.1)
Y = F.leaky_relu(X)
plt.xticks(range(-10,10,1))
plt.plot(X,Y),plt.xlabel('X_value'),plt.ylabel('Y_value'),plt.title('$Leaky ReLU$')
([<matplotlib.lines.Line2D at 0x1c1caaff9c8>],
 Text(0.5, 0, 'X_value'),
 Text(0, 0.5, 'Y_value'),
 Text(0.5, 1.0, '$Leaky ReLU$'))

image.png


SELU函数

image.png

同样的,SeLU函数也是ReLU函数的改进,对于x<0的情况,SELU函数是一个指数函数,也就是相当于是两个函数的拼接


X = torch.arange(-10,10,0.1)
Y = F.selu(X)
#cplt.xticks(range(-10,10,1))
plt.plot(X,Y),plt.xlabel('X_value'),plt.ylabel('Y_value'),plt.title('$SeLU$')
([<matplotlib.lines.Line2D at 0x1c1cacac2c8>],
 Text(0.5, 0, 'X_value'),
 Text(0, 0.5, 'Y_value'),
 Text(0.5, 1.0, '$SeLU$'))

image.png


Softplus函数

Softplus函数的表达式为

image.png

其也是在ReLU函数上面作了一个改进,使得在x=0的时候使得函数比较的平滑一些,如下图所示:


X = torch.arange(-10,10,0.1)
Y = F.softplus(X)
plt.plot(X,Y),plt.xlabel('X_value'),plt.ylabel('Y_value'),plt.title('$Softplus$')
([<matplotlib.lines.Line2D at 0x1c1cabedc48>],
 Text(0.5, 0, 'X_value'),
 Text(0, 0.5, 'Y_value'),
 Text(0.5, 1.0, '$Softplus$'))

image.png


2.常见的Loss与梯度


Mean Squared Error均方误差

image.png

# 代码表示为
torch.norm(y-pred,2).pow(2)


1)torch.autograd.grad的使用

# 现在使用torch.autograd.grad实现求导的过程
# torch.autograd.grad的使用方法
# 现在假设需要解决的任务方程是简单的一元函数:y = xw + b
# 所以其loss function为 loss = ∑[(xw + b) - y]**2
# 第一个例子:
x = torch.tensor(5)     # 设置x为5
w = torch.full([1],10.)  # 设置斜率w为10
b = torch.tensor(2)     # 设置bios为2
y = torch.rand(1)+50    # 设置真实值为50附近的随机数,输出为50.6296
loss = F.mse_loss(x*w+b,y)  
# 输出结果为:  tensor([1.8779]))
# 现在进行验证一下:(5*10+2-50.6296)**2=1.8779
# 对此时的w进行求导,但是出出现一个报错
## torch.autograd.grad(loss,[w])  
# RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
# 表示w此时是不需要求导,错误原因是一开始的w没有设置好导数信息,所以pytorch自动标注了w不需要求导
# 修改的方法是,可以使用requires_grad_函数更正标注
w.requires_grad_()
# RuntimeError: only Tensors of floating point dtype can require gradients
# 又出现了一个错误,表示w需要是浮点数值,现在重新将w修改为w = torch.full([1],10.)
# 此时想再来求导,但是还是出现了错误
# torch.autograd.grad(loss,[w])
# RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
# 出现错误的原因是:前一步已经更新了w,但pytorch的这个动态图还是没有更新,所以需要重新更新一个图
loss = F.mse_loss(x*w+b,y) 
# 此时输出下数值:w,y,loss
# (tensor([10.], requires_grad=True),
#  tensor([50.5761]),
#  tensor(1.8779, grad_fn=<MseLossBackward>),
# 完成这个过程之后,就可以对w进行求导了
torch.autograd.grad(loss,[w])
# 输出为(tensor([13.7037]),)
# 验证一下
# 2*5*(5*10+2-50.6296)=13.7037 与输出结果一致
# 补充:
# 以上过程进行中出现的问题,也就是w不能丘梯度的问题,其实可以从开始初始化的时候直接进行解决
w = torch.full([1],10.).requires_grad_()
w = torch.tensor(10.,requires_grad=True)  
# 以上的两个写法是等价的
# 第二个例子:
# 同时可以对多个未知量进行求导
x = torch.tensor(5)     # 设置x为5
w = torch.full([1],10.).requires_grad_()   # 设置斜率w为10
b = torch.tensor(2.).requires_grad_()      # 设置bios为2
y = torch.rand(1)+50    # 设置真实值为50附近的随机数,输出为50.6296
loss = F.mse_loss(x*w+b,y) 
# autograd.grad的函数中如果对多个未知量进行求导,需要设置参数retain_graph=True,否则相关的结果内存会被释放
dw = torch.autograd.grad(loss,[w],retain_graph=True)
db = torch.autograd.grad(loss,[b])
print(y,x*w+b-y,loss)
# 输出为:tensor([50.6393]) tensor([1.3607], grad_fn=<SubBackward0>) tensor(1.8514, grad_fn=<MseLossBackward>)
dw,db
# 输出为:((tensor([13.6066]),), (tensor(2.7213),))  验证结果是正确的
(tensor([13.7037]),)


2)loss.backward的使用

# 还是以这个例子为例,其实backward函数会自动的对所有的参数进行求导,但是不会输出结果而是将结果保存在每一个未知量x.grad中
x = torch.tensor(5)     # 设置x为5
w = torch.full([1],10.).requires_grad_()   # 设置斜率w为10
b = torch.tensor(2.).requires_grad_()      # 设置bios为2
y = torch.rand(1)+50    # 设置真实值为50附近的随机数,输出为50.6296
loss = F.mse_loss(x*w+b,y) 
print("loss:",loss,"[(x*w+b)-y]**2:",((x*w+b)-y)**2)
# 输出为:loss: tensor(3.1575, grad_fn=<MseLossBackward>) [(x*w+b)-y]**2: tensor([3.1575], grad_fn=<PowBackward0>)
# 使用backward自动求导函数
loss.backward()
w.grad,b.grad
# 输出为:(tensor([17.7694]), tensor(3.5539))
# 验证一下
loss = F.mse_loss(x*w+b,y) 
dw = torch.autograd.grad(loss,[w],retain_graph=True)
db = torch.autograd.grad(loss,[b],retain_graph=True)
dw,db
# ((tensor([17.7694]),), (tensor(3.5539),))
# 可见,两种方法的输出结果一样
loss: tensor(3.1575, grad_fn=<MseLossBackward>) [(x*w+b)-y]**2: tensor([3.1575], grad_fn=<PowBackward0>)


3)Softmax的使用

a = torch.rand(3,requires_grad=True)
# 输出为:tensor([0.2001, 0.6048, 0.0787], requires_grad=True)
p = F.softmax(a,dim=0)
# 输出为:tensor([0.2954, 0.4429, 0.2617], grad_fn=<SoftmaxBackward>)
# 预测值:
# tensor([0.2954, 0.4429, 0.2617], grad_fn=<SoftmaxBackward>)
# (-0.13083266, 0.24673958999999998, -0.11590693)
torch.autograd.grad(p[1],[a])
# 输出为:(tensor([-0.1308,  0.2467, -0.1159]),),符合预测值
tensor([0.2001, 0.6048, 0.0787], requires_grad=True)


Cross Entropy Loss交叉熵损失

相对熵(relative entropy)就是KL散度(Kullback–Leibler divergence),用于衡量两个概率分布之间的差异。

对于两个概率分布p(x)和q(x) ,其相对熵的计算公式为:

image.png

需要注意:p(x)和q(x)在公式中的地位不是相等的,所以:

相对熵的特点,是只有p(x)=q(x)时,其值为0。若p(x)和q(x)略有差异,其值就会大于0。其证明利用了负对数函数(-lnx)是严格凸函数(strictly convex function)的性质。

相对熵公式的前半部分就是交叉熵(cross entropy)。既


  • 相对熵

image.png


  • 交叉熵

image.png

若p(x) 是数据的真实概率分布,q(x)是由数据计算得到的概率分布。机器学习的目的就是希望p(x)尽可能地逼近甚至等于p(x),从而使得相对熵接近最小值0. 由于真实的概率分布是固定的,相对熵公式的后半部分就成了一个常数。其后半部分为:

image.png

那么相对熵达到最小值的时候,也意味着交叉熵达到了最小值。对q(x)的优化就等效于求交叉熵的最小值。另外,对交叉熵求最小值,也等效于求最大似然估计(maximum likelihood estimation)。


1)cross_entropy的使用

x = torch.randn(1,28*28)
w = torch.randn(10,28*28)
# 矩阵相乘
logit = x@w.t()
# logit.shape为:torch.Size([1, 10])
# 直接求出交叉熵
F.cross_entropy(logit,torch.tensor([3]))
# 输出为:tensor(17.2760)


2)nll_loss的使用

nll_loss函数其实就是最大似然函数


x = torch.randn(1,28*28)
w = torch.randn(10,28*28)
# 矩阵相乘
logit = x@w.t()
# softmax 处理,即将 input 转换成概率分布的形式
pred = F.softmax(logit , dim=1)
# softmax 处理处理后取对数
pred = torch.log(pred)
# 最大似然计算,其中pred是预测值,torch.tensor([3])是真是值也就是label值,这位置是不能换的
F.nll_loss(pred,torch.tensor([3]))


输出结果同上面一样,所以实际上,可以认为:


CrossEntropyLoss = log_sofrmax + NLLLoss


实际意义为:

在对图片进行分类时,通常会一次性输入n张图片,最后得出一个n*c的tensor,c是此次分类的类别数:比如:n=10,c=2,表示一共10张图片,类别为2类;接下来对每一行使用softmax函数,得到每张图片每个类别的概率分布:结果如下:可以看出来,每一行的值加起来和为1

image.png

然后再对给概率分布取对数:输出如下:

image.png

最后,CrossEntropyLoss的结果就是将这10个图像输出中与label对应值拿出来,累加再对结果取负值。先假设label如下所示:

image.png

则最后结果为:

loss = -(-0.0178 + -0.3859 + -0.8744 + /
-1.3443 + -0.3392 + -2.7229 + -0.2614 + /
-0.2736 + -1.3477 + -2.0514) / 10 = 0.96186


使用代码来计算可以表示为:


print(torch.nn.CrossEntropyLosss(output, label)))
相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
Python 机器学习/深度学习
Cross Entropy Loss 交叉熵损失函数公式推导
表达式 输出标签表示为{0,1}时,损失函数表达式为: $L = -[y log \hat{y} + (1-y)log(1- \hat{y})]$ 二分类 二分类问题,假设 y∈{0,1} 正例:$P(y = 1| x) = \hat{y}$ 反例:$P(y=0|x) = 1-\hat{y}$ 取似然函数 似然函数就是所有样本在参数θ下发生概率最大的那种情况,由于样本独立同分布,因此概率最大的情况就是每个样本发生概率的连乘。
15974 0
|
4月前
|
机器学习/深度学习 编解码
深度学习笔记(三):神经网络之九种激活函数Sigmoid、tanh、ReLU、ReLU6、Leaky Relu、ELU、Swish、Mish、Softmax详解
本文介绍了九种常用的神经网络激活函数:Sigmoid、tanh、ReLU、ReLU6、Leaky ReLU、ELU、Swish、Mish和Softmax,包括它们的定义、图像、优缺点以及在深度学习中的应用和代码实现。
338 0
深度学习笔记(三):神经网络之九种激活函数Sigmoid、tanh、ReLU、ReLU6、Leaky Relu、ELU、Swish、Mish、Softmax详解
|
4月前
|
机器学习/深度学习 资源调度 自然语言处理
Softmax激活函数介绍
【10月更文挑战第2天】
191 0
|
4月前
|
机器学习/深度学习 数据可视化 算法
激活函数与神经网络------带你迅速了解sigmoid,tanh,ReLU等激活函数!!!
激活函数与神经网络------带你迅速了解sigmoid,tanh,ReLU等激活函数!!!
WK
|
5月前
|
机器学习/深度学习 算法
为什么Sigmoid函数比Tanh函数更好
在神经网络中,Sigmoid和Tanh函数各有优劣,选择取决于具体应用场景。Sigmoid函数输出范围为(0,1),适合二分类问题,但存在梯度消失和非零中心化的问题;Tanh函数输出范围为(-1,1),以0为中心,有利于加速收敛,但同样涉及较大的计算复杂度。两者均存在梯度消失风险,但在多数情况下,Tanh梯度问题较轻。随着技术发展,ReLU等新型激活函数因能有效缓解梯度消失并提高计算效率,已成为许多任务的首选。因此,不能简单地说Sigmoid比Tanh更好,需依据任务需求和网络结构进行选择。
WK
216 1
WK
|
5月前
|
机器学习/深度学习
实际应用场景下Tanh和Sigmoid哪个更常用
在实际应用中,Tanh和Sigmoid函数的选择受多种因素影响。Sigmoid函数常用于二分类问题的输出层,因其输出范围在(0, 1)内,适合表示概率;但在隐藏层中较少使用,因为它会导致梯度消失和非零中心化问题。Tanh函数输出范围在(-1, 1),以0为中心,适用于隐藏层,有助于加快收敛速度,但也存在梯度消失问题。随着深度学习技术的发展,ReLU及其变体因计算效率高和梯度消失问题较轻而逐渐成为主流选择。因此,选择激活函数需综合考虑任务需求和网络结构特点。
WK
138 2
WK
|
5月前
|
机器学习/深度学习 算法
什么是Sigmoid函数
Sigmoid函数是在机器学习及统计学中广泛应用的一种数学模型,尤其适用于逻辑回归与神经网络中的激活场景。该函数能将任意实数映射至(0,1)区间,象征概率或事件发生可能性。其S型曲线特性使其在二分类问题中表现出色,同时具备连续平滑与中心对称的特点,利于采用如梯度下降等优化算法。然而,Sigmoid函数在极端输入值下会出现梯度消失的问题,影响模型训练效果。尽管有此局限性,它在特定应用场景中依然重要,例如需要输出概率值的情况。
WK
183 0
WK
|
5月前
|
机器学习/深度学习
在神经网络的反向传播中,Tanh和Sigmoid哪个更快
在神经网络反向传播中,Tanh与Sigmoid函数的速度差异并无定论,受网络结构、数据特性及参数设置影响。Sigmoid在远离零时易导致梯度消失,而Tanh因输出范围为(-1, 1)且以0为中心,能更好地缓解此问题,理论上训练速度更快。两者计算复杂度相近,现代硬件优化使这一差距不明显。实际应用中,Sigmoid常用于二分类输出层,Tanh则适用于隐藏层以加速收敛并减少权重更新偏向。随着深度学习发展,ReLU等新激活函数因高效性和轻度梯度消失问题成为主流选择。综合来看,Tanh可能比Sigmoid稍快,但需根据具体任务和网络结构选择。
WK
111 0
|
6月前
|
机器学习/深度学习
Softmax 和 ReLU 函数的效用
【8月更文挑战第23天】
373 0
|
8月前
|
机器学习/深度学习 Python
tanh函数
本文探讨了高等数学中的tanh函数,即双曲正切函数,其定义为 $\tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}$,导数为 $1 - \tanh^2(x)$。tanh函数广泛适用于各类场景,并在神经网络中有重要应用。提供的Python代码绘制了tanh函数及其导数的图像。
272 1