淘客网站怎么做排名,寓意好的公司名字大全,免费网络推广渠道,求职文章目录ReLu公式求导过程优点#xff1a;缺点#xff1a;自定义ReLu与Torch定义的比较可视化Leaky ReLu PReLu公式求导过程优点#xff1a;缺点#xff1a;自定义LeakyReLu与Torch定义的比较可视化自定义PReLuELU公式求导过程优点缺点自定义LeakyReLu与Torch定义的比较可视…
文章目录ReLu公式求导过程优点缺点自定义ReLu与Torch定义的比较可视化Leaky ReLu PReLu公式求导过程优点缺点自定义LeakyReLu与Torch定义的比较可视化自定义PReLuELU公式求导过程优点缺点自定义LeakyReLu与Torch定义的比较可视化import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F%matplotlib inlineplt.rcParams[figure.figsize] (7, 3.5)
plt.rcParams[figure.dpi] 150
plt.rcParams[axes.unicode_minus] False #解决坐标轴负数的铅显示问题ReLu
线性整流函数 (rectified linear unit)
公式
relumax(0,x){x,x00,x≤0\text{relu} \max(0, x) \begin{cases} x, x0 \\ 0, x\leq 0 \end{cases}relumax(0,x){x,0,x0x≤0
求导过程
f(x)是连续的f(x)是连续的f(x)是连续的
f′(x)limh→0f(0)f(0h)−f(0)hmax(0,h)−0hf(x)\lim_{h\to 0}f(0) \frac{f(0 h)-f(0)}{h}\frac{\max(0, h) - 0}{h}f′(x)limh→0f(0)hf(0h)−f(0)hmax(0,h)−0 limh→0−0h0\lim_{h\to0^-}\frac{0}{h} 0limh→0−h00 limh→0hh1\lim_{h\to0^}\frac{h}{h} 1limh→0hh1 所以f′(0)f(0)f′(0)处不可导
所以f′(x){1,x00,x0f(x) \begin{cases} 1, x 0 \\ 0, x 0 \end{cases}f′(x){1,0,x0x0
优点
ReLU激活函数是一个简单的计算如果输入大于0直接返回作为输入提供的值如果输入是0或更小返回值0。
相较于sigmoid函数以及Tanh函数来看在输入为正时Relu函数不存在饱和问题即解决了gradient vanishing问题使得深层网络可训练Relu输出会使一部分神经元为0值在带来网络稀疏性的同时也减少了参数之间的关联性一定程度上缓解了过拟合的问题计算速度非常快收敛速度远快于sigmoid以及Tanh函数
缺点
输出不是zero-centered存在Dead Relu Problem即某些神经元可能永远不会被激活进而导致相应参数一直得不到更新产生该问题主要原因包括参数初始化问题以及学习率设置过大问题ReLU不会对数据做幅度压缩所以数据的幅度会随着模型层数的增加不断扩张当输入为正值导数为1在“链式反应”中不会出现梯度消失但梯度下降的强度则完全取决于权值的乘积如此可能会导致梯度爆炸问题
自定义ReLu
class SelfDefinedRelu(torch.autograd.Function):staticmethoddef forward(ctx, inp):ctx.save_for_backward(inp)return torch.where(inp 0., torch.zeros_like(inp), inp)staticmethoddef backward(ctx, grad_output):inp, ctx.saved_tensorsreturn grad_output * torch.where(inp 0., torch.zeros_like(inp),torch.ones_like(inp))class Relu(nn.Module):def __init__(self):super().__init__()def forward(self, x):out SelfDefinedRelu.apply(x)return out与Torch定义的比较
# self defined
torch.manual_seed(0)relu Relu() # SelfDefinedRelu
inp torch.randn(5, requires_gradTrue)
out relu((inp).pow(3))print(fOut is\n{out})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nFirst call\n{inp.grad})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nSecond call\n{inp.grad})inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nCall after zeroing gradients\n{inp.grad})Out is
tensor([3.6594, 0.0000, 0.0000, 0.1837, 0.0000],grad_fnSelfDefinedReluBackward)First call
tensor([7.1240, 0.0000, 0.0000, 0.9693, 0.0000])Second call
tensor([14.2480, 0.0000, 0.0000, 1.9387, 0.0000])Call after zeroing gradients
tensor([7.1240, 0.0000, 0.0000, 0.9693, 0.0000])# torch defined
torch.manual_seed(0)
inp torch.randn(5, requires_gradTrue)
out torch.relu((inp).pow(3))print(fOut is\n{out})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nFirst call\n{inp.grad})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nSecond call\n{inp.grad})inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nCall after zeroing gradients\n{inp.grad})Out is
tensor([3.6594, 0.0000, 0.0000, 0.1837, 0.0000], grad_fnReluBackward0)First call
tensor([7.1240, 0.0000, 0.0000, 0.9693, 0.0000])Second call
tensor([14.2480, 0.0000, 0.0000, 1.9387, 0.0000])Call after zeroing gradients
tensor([7.1240, 0.0000, 0.0000, 0.9693, 0.0000])可视化
# visualization
inp torch.arange(-8, 8, 0.05, requires_gradTrue)
out relu(inp)
out.sum().backward()inp_grad inp.gradplt.plot(inp.detach().numpy(),out.detach().numpy(),labelr$relu(x)$,alpha0.7)
plt.plot(inp.detach().numpy(),inp_grad.numpy(),labelr$relu(x)$,alpha0.5)
plt.scatter(0, 0, colorNone, markero, edgecolorsr, s50)
plt.grid()
plt.legend()
plt.show()Leaky ReLu PReLu
公式
leaky_relumax(αx,x){x,x≥0α,x0,α∈[0,∞)\text{leaky\_relu} \max(\alpha x, x) \begin{cases} x, x \ge 0 \\ \alpha, x 0 \end{cases} \quad, \alpha \in [0, \infty)leaky_relumax(αx,x){x,α,x≥0x0,α∈[0,∞)
whileα0,leaky_relurelu\text{while} \quad \alpha 0, \text{leaky\_relu} \text{relu}whileα0,leaky_relurelu
求导过程
所以f′(x){1,x≥0α,x0f(x) \begin{cases} 1, x \ge 0 \\ \alpha, x 0 \end{cases}f′(x){1,α,x≥0x0
优点
避免梯度消失的问题计算简单针对Relu函数中存在的Dead Relu ProblemLeaky Relu函数在输入为负值时给予输入值一个很小的斜率在解决了负输入情况下的0梯度问题的基础上也很好的缓解了Dead Relu问题
缺点
输出不是zero-centeredReLU不会对数据做幅度压缩所以数据的幅度会随着模型层数的增加不断扩张理论上来说该函数具有比Relu函数更好的效果但是大量的实践证明其效果不稳定故实际中该函数的应用并不多。由于在不同区间应用的不同的函数所带来的不一致结果将导致无法为正负输入值提供一致的关系预测。
超参数 α\alphaα 的取值也已经被很多实验研究过有一种取值方法是对 α\alphaα 随机取值 α\alphaα 的分布满足均值为0标准差为1的正态分布该方法叫做随机LeakyReLU(Randomized LeakyReLU)。原论文指出随机LeakyReLU相比LeakyReLU能得更好的结果且给出了参数 α\alphaα 的经验值1/5.5(好于0.01)。至于为什么随机LeakyReLU能取得更好的结果解释之一就是随机LeakyReLU小于0部分的随机梯度为优化方法引入了随机性这些随机噪声可以帮助参数取值跳出局部最优和鞍点这部分内容可能需要一整篇文章来阐述。正是由于 α\alphaα 的取值至关重要人们不满足与随机取样 α\alphaα 有论文将 α\alphaα 作为了需要学习的参数该激活函数为 PReLU(Parametrized ReLU)
自定义LeakyReLu
class SelfDefinedLeakyRelu(torch.autograd.Function):staticmethoddef forward(ctx, inp, alpha):ctx.constant alphactx.save_for_backward(inp)return torch.where(inp 0., alpha * inp, inp)staticmethoddef backward(ctx, grad_output):inp, ctx.saved_tensorsones_like_inp torch.ones_like(inp)return torch.where(inp 0., ones_like_inp * ctx.constant,ones_like_inp), Noneclass LeakyRelu(nn.Module):def __init__(self, alpha1):super().__init__()self.alpha alphadef forward(self, x):out SelfDefinedLeakyRelu.apply(x, self.alpha)return out与Torch定义的比较
# self defined
torch.manual_seed(0)alpha 0.1 # greater so could have bettrer visualization
leaky_relu LeakyRelu(alphaalpha) # SelfDefinedLeakyRelu
inp torch.randn(5, requires_gradTrue)
out leaky_relu((inp).pow(3))print(fOut is\n{out})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nFirst call\n{inp.grad})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nSecond call\n{inp.grad})inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nCall after zeroing gradients\n{inp.grad})Out is
tensor([ 3.6594e00, -2.5264e-03, -1.0343e00, 1.8367e-01, -1.2756e-01],grad_fnSelfDefinedLeakyReluBackward)First call
tensor([7.1240, 0.0258, 1.4241, 0.9693, 0.3529])Second call
tensor([14.2480, 0.0517, 2.8483, 1.9387, 0.7057])Call after zeroing gradients
tensor([7.1240, 0.0258, 1.4241, 0.9693, 0.3529])# torch defined
torch.manual_seed(0)
inp torch.randn(5, requires_gradTrue)
out F.leaky_relu((inp).pow(3), negative_slopealpha)print(fOut is\n{out})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nFirst call\n{inp.grad})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nSecond call\n{inp.grad})inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nCall after zeroing gradients\n{inp.grad})Out is
tensor([ 3.6594e00, -2.5264e-03, -1.0343e00, 1.8367e-01, -1.2756e-01],grad_fnLeakyReluBackward0)First call
tensor([7.1240, 0.0258, 1.4241, 0.9693, 0.3529])Second call
tensor([14.2480, 0.0517, 2.8483, 1.9387, 0.7057])Call after zeroing gradients
tensor([7.1240, 0.0258, 1.4241, 0.9693, 0.3529])可视化
# visualization
inp torch.arange(-8, 8, 0.05, requires_gradTrue)
out leaky_relu(inp)
out.sum().backward()inp_grad inp.gradplt.plot(inp.detach().numpy(),out.detach().numpy(),labelr$leakyrelu(x)$,alpha0.7)
plt.plot(inp.detach().numpy(),inp_grad.numpy(),labelr$leakyrelu(x)$,alpha0.5)
plt.scatter(0, 0, colorNone, markero, edgecolorsr, s50)
plt.grid()
plt.legend()
plt.show()自定义PReLu
class SelfDefinedPRelu(torch.autograd.Function):staticmethoddef forward(ctx, inp, alpha):ctx.constant alphactx.save_for_backward(inp)return torch.where(inp 0., alpha * inp, inp)staticmethoddef backward(ctx, grad_output):inp, ctx.saved_tensorsones_like_inp torch.ones_like(inp)return torch.where(inp 0., ones_like_inp * ctx.constant,ones_like_inp), Noneclass PRelu(nn.Module):def __init__(self):super().__init__()self.alpha torch.randn(1, dtypetorch.float32, requires_gradTrue)def forward(self, x):out SelfDefinedLeakyRelu.apply(x, self.alpha)return outELU
指数线性单元 (Exponential Linear Unit)
公式
elu(x){x,x≥0α(ex−1),x0\text{elu}(x) \begin{cases} x, x \ge 0 \\ \alpha(e^x - 1), x 0 \end{cases}elu(x){x,α(ex−1),x≥0x0
求导过程
f′(x)limh→0f(0)f(0h)−f(0)hf(x)\lim_{h\to 0}f(0) \frac{f(0h)-f(0)}{h}f′(x)limh→0f(0)hf(0h)−f(0) limh→0−α(eh−1)−0h0\lim_{h\to0^-}\frac{\alpha (e^h - 1) - 0}{h} 0limh→0−hα(eh−1)−00 limh→0hh1\lim_{h\to0^}\frac{h}{h} 1limh→0hh1 所以f′(0)f(0)f′(0)处不可导 所以f′(x){1,x≥0αex,x0f(x) \begin{cases} 1, x \ge 0 \\ \alpha e^x, x 0 \end{cases}f′(x){1,αex,x≥0x0
理想的激活函数应满足两个条件
输出的分布是零均值的可以加快训练速度。激活函数是单侧饱和的可以更好的收敛。
LeakyReLU和PReLU满足第1个条件不满足第2个条件而ReLU满足第2个条件不满足第1个条件。两个条件都满足的激活函数为ELU(Exponential Linear Unit)。ELU虽然也不是零均值的但在以0为中心一个较小的范围内均值是趋向于0当然也与α\alphaα的取值也是相关的。
优点
ELU具有Relu的大多数优点不存在Dead Relu问题输出的均值也接近为0值该函数通过减少偏置偏移的影响使正常梯度更接近于单位自然梯度从而使均值向0加速学习该函数在负数域存在饱和区域从而对噪声具有一定的鲁棒性
缺点
计算强度较高含有幂运算在实践中同样没有较Relu更突出的效果故应用不多
自定义LeakyReLu
class SelfDefinedElu(torch.autograd.Function):staticmethoddef forward(ctx, inp, alpha):ctx.constant alpha * inp.exp()ctx.save_for_backward(inp)return torch.where(inp 0., ctx.constant - alpha, inp)staticmethoddef backward(ctx, grad_output):inp, ctx.saved_tensorsones_like_inp torch.ones_like(inp)return torch.where(inp 0., ones_like_inp * ctx.constant,ones_like_inp), Noneclass Elu(nn.Module):def __init__(self, alpha1):super().__init__()self.alpha alphadef forward(self, x):out SelfDefinedElu.apply(x, self.alpha)return out与Torch定义的比较
# self defined
torch.manual_seed(0)alpha 0.5 # greater so could have bettrer visualization
elu Elu(alphaalpha) # SelfDefinedLeakyRelu
inp torch.randn(5, requires_gradTrue)
out elu((inp 1).pow(3))print(fOut is\n{out})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nFirst call\n{inp.grad})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nSecond call\n{inp.grad})inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nCall after zeroing gradients\n{inp.grad})Out is
tensor([ 1.6406e01, 3.5275e-01, -4.0281e-01, 3.8583e00, -3.0184e-04],grad_fnSelfDefinedEluBackward)First call
tensor([1.9370e01, 1.4977e00, 4.0513e-01, 7.3799e00, 1.0710e-02])Second call
tensor([3.8740e01, 2.9955e00, 8.1027e-01, 1.4760e01, 2.1419e-02])Call after zeroing gradients
tensor([1.9370e01, 1.4977e00, 4.0513e-01, 7.3799e00, 1.0710e-02])# torch defined
torch.manual_seed(0)
inp torch.randn(5, requires_gradTrue)
out F.elu((inp 1).pow(3), alphaalpha)print(fOut is\n{out})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nFirst call\n{inp.grad})out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nSecond call\n{inp.grad})inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graphTrue)
print(f\nCall after zeroing gradients\n{inp.grad})Out is
tensor([ 1.6406e01, 3.5275e-01, -4.0281e-01, 3.8583e00, -3.0184e-04],grad_fnEluBackward)First call
tensor([1.9370e01, 1.4977e00, 4.0513e-01, 7.3799e00, 1.0710e-02])Second call
tensor([3.8740e01, 2.9955e00, 8.1027e-01, 1.4760e01, 2.1419e-02])Call after zeroing gradients
tensor([1.9370e01, 1.4977e00, 4.0513e-01, 7.3799e00, 1.0710e-02])可视化
inp torch.arange(-1, 1, 0.05, requires_gradTrue)
out F.elu(inp, alpha1.2)
# out F.relu(inp)
out.mean(), out.std()(tensor(0.0074, grad_fnMeanBackward0),tensor(0.5384, grad_fnStdBackward0))inp torch.arange(-1, 1, 0.05, requires_gradTrue)
# out F.elu(inp, alpha1)
out F.relu(inp)
out.mean(), out.std()(tensor(0.2375, grad_fnMeanBackward0),tensor(0.3170, grad_fnStdBackward0))# visualization
inp torch.arange(-8, 8, 0.05, requires_gradTrue)
out elu(inp)
out.sum().backward()inp_grad inp.gradplt.plot(inp.detach().numpy(),out.detach().numpy(),labelr$elu(x)$,alpha0.7)
plt.plot(inp.detach().numpy(),inp_grad.numpy(),labelr$elu(x)$,alpha0.5)
plt.scatter(0, 0, colorNone, markero, edgecolorsr, s50)
plt.grid()
plt.legend()
plt.show()