神经网络训练的基本tricks

在上一篇文章中,介绍了如何使用优化函数更新权重参数,不断逼近损失函数的最小值,从而达到学习的目的。优化函数的基本思想是梯度下降法,而权重参数更新,需要计算所有权重相对于损失函数的梯度。而从之前神经网络介绍那篇文章我们可以知道,影响权重的梯度因素包括损失函数的导数、激活函数的导数、节点的输入值、权重值

接下来,本文将介绍梯度消失和梯度爆炸的概念,以及神经网络训练过程中防止梯度消失和梯度爆炸问题的一些tricks。

梯度消失和梯度爆炸

神经网络训练时,特别是深层神经网络所面临的一个大问题就是梯度消失或梯度爆炸,也就权重对损失函数的导数变得非常大,或者非常小。梯度消失或爆炸问题一般随着网络层数的增加会变得越来越明显。

模拟梯度消失

如下图所示,假设每层都只有一个神经元,且每一层都可以用如下的公式表示,其中 σ \sigma σ为激活函数,在这里以sigmoid为例。
a i = σ ( z i ) = σ ( w i ∗ x i ) , 其中 x i = a i − 1 a_i = \sigma{(z_i)} = \sigma{(w_i * x_i)}, 其中x_i = a_{i-1} ai=σ(zi)=σ(wixi),其中xi=ai1
image.png
那么可以推导出如下公式:
α L α w 1 = α L α a 4 ∗ α a 4 α z 4 ∗ α z 4 α a 3 ∗ α a 3 α z 3 ∗ α z 3 α a 2 ∗ α a 2 α z 2 ∗ α z 2 α a 1 ∗ α a 1 α z 1 ∗ α z 1 α w 1 \frac{\alpha{L}}{\alpha{w_1}} = \frac{\alpha{L}}{\alpha{a_4}}*\frac{\alpha{a_4}}{\alpha{z_4}}*\frac{\alpha{z_4}}{\alpha{a_3}}*\frac{\alpha{a_3}}{\alpha{z_3}}*\frac{\alpha{z_3}}{\alpha{a_2}}*\frac{\alpha{a_2}}{\alpha{z_2}}*\frac{\alpha{z_2}}{\alpha{a_1}}*\frac{\alpha{a_1}}{\alpha{z_1}}*\frac{\alpha{z_1}}{\alpha{w_1}} αw1αL=αa4αLαz4αa4αa3αz4αz3αa3αa2αz3αz2αa2αa1αz2αz1αa1αw1αz1
= α L α a 4 ∗ σ ′ z 4 ∗ w 4 ∗ σ ′ z 3 ∗ w 3 ∗ σ ′ z 2 ∗ w 2 ∗ σ ′ z 1 ∗ x 1 =\frac{\alpha{L}}{\alpha{a_4}}*{\sigma'{z_4}}*w_4*{\sigma'{z_3}}*w_3*{\sigma'{z_2}}*w2*{\sigma'{z_1}}*x_1 =αa4αLσz4w4σz3w3σz2w2σz1x1
而sigmoid函数的导数如下图所示:
image.png
可见, σ ′ ( x ) \sigma'(x) σ(x)的最大值为 1 4 \frac{1}{4} 41,而一般网络训练时,会使用一个均值为0标准差为1的高斯分布来初始化网络权重,即初始化的权重值通常都是小于1的,从而 σ ′ ( x ) ∗ w ≤ 1 4 \sigma'(x)*w ≤ \frac{1}{4} σ(x)w41。因此,对于上式中的链式求导,当层数越多,求导结果越小,最终导致梯度消失的情况出现。

梯度爆炸

σ ′ ( x ) ∗ w > 1 \sigma'(x)*w > 1 σ(x)w>1时,也即 w w w比较大的情况。则靠近输入层的隐藏层梯度变化巨大,从而引起梯度爆炸的问题。

归一化输入

训练神经网络,其中一个加速训练的方法就是归一化输入。归一化输入包含如下两个步骤:

  • 零均值:计算所有样本的均值 μ = 1 m ∑ i = 1 m x i \mu=\frac{1}{m}\sum_{i=1}^m{x^{i}} μ=m1i=1mxi,然后每个样本减去均值 x i = x i − μ x^i = x^i - \mu xi=xiμ
  • 归一化方差:计算方差 σ 2 = 1 m ∑ i = 1 m ( x i ) 2 \sigma^2 = \frac{1}{m}\sum_{i=1}^m(x^i)^2 σ2=m1i=1m(xi)2,然后每个样本都除以均值 x i = x i σ 2 + ϵ x^i = \frac{x^i}{\sqrt{\sigma^2 + \epsilon}} xi=σ2+ϵ xi

image.png

权重初始化

为什么要初始化权重

从之前权重梯度计算中,可以知道权重值也参与了梯度计算,即权重初始化的目的是为了防止深度神经网络在前向传播过程中,由于权重过大或者过小导致输出无效,反向传播过程中出现梯度消失或爆炸

前向传播

以一个简单没有激活函数的100层神经网络为例,使用torch.randn生成标准正态分布数据初始化输入x和权重矩阵a,进行前向传播:
x = x 1 ∗ w 1 + x 2 ∗ w 2 + . . . + x 100 ∗ w 100 x = x_1*w_1 + x_2*w_2 + ... + x_{100}*w_{100} x=x1w1+x2w2+...+x100w100

>>> x = torch.randn(512)
>>> for i in range(100):
...     a = torch.randn(512, 512)
...     x = a @ x
...
>>> x.mean()
tensor(nan)
>>> x.std()
tensor(nan)

可以看到,经过100次矩阵乘法,在某次运算中,层输出变得非常大,导致计算机都无法识别其标准差和均值。也就是出现了梯度爆炸的情况。
当使用均值为0,方差为0.01的正态分布初始化权重时,进行前向传播:

>>> x = torch.randn(512)
>>> for i in range(100):
...     a = torch.randn(512, 512) * 0.01
...     x = a @ x
...
>>> x.mean()
tensor(0.)
>>> x.std()
tensor(0.)

可以看到,此时层输出值无限趋近于0。也即,权重初始值太大或太小,模型都不能好好学习。

权重初始化的方法

常见的权重初始化方法有三种:Xavier初始化、Kaimming He初始化、初始化为0.

Xavier初始化

Xavier初始化是一种经典的权重初始化方法,根据输入和输出的维度自适应地设置权重参数地初始值,将每层的权重设置在有界的随机均匀分布上,表达式如下所示:
W ∼ U [ − 6 n i + n i + 1 , 6 n i + n i + 1 ] W\sim{U[-\frac{\sqrt{6}}{\sqrt{n_i + n_{i+1}}}, \frac{\sqrt{6}}{\sqrt{n_i + n_{i+1}}}]} WU[ni+ni+1 6 ,ni+ni+1 6 ]
其中 n i n_i ni表示该神经元的输入连接数, n i + 1 n_{i+1} ni+1表示输出连接数。Xavier权重初始化能保证激活函数和反向传播梯度的方差,一直向上或向下传播到神经网络的每一层。

Kaimming He初始化

与Xavier初始化类似,He初始化也是根据输入和输出地维度自适应地设置权重参数的初始值。不同的是,He初始化方法是为了更好地适应ReLU激活函数而设计的。Xavier激活函数适用于:关于0对称,线性的激活函数,而ReLU激活函数并不满足这些条件。

初始化为0

以下图的简单两层神经网络为例,模拟权重初始化为0的前向传播和反向传播过程。

前向传播:
z 1 [ 1 ] = w 11 [ 1 ] ∗ x 1 + w 21 [ 1 ] ∗ x 2 = 0 ; a 1 [ 1 ] = σ ( z 1 [ 1 ] ) = 0.5 z_1^{[1]} = w_{11}^{[1]} * x_1 + w_{21}^{[1]} * x_2 = 0;a_1^{[1]}=\sigma(z_1^{[1]})=0.5 z1[1]=w11[1]x1+w21[1]x2=0;a1[1]=σ(z1[1])=0.5
z 2 [ 1 ] = 0 ; a 2 [ 1 ] = 0.5 z_2^{[1]}=0;a_2^{[1]}=0.5 z2[1]=0;a2[1]=0.5
z 3 [ 1 ] = 0 ; a 3 [ 1 ] = 0.5 z_3^{[1]}=0;a_3^{[1]}=0.5 z3[1]=0;a3[1]=0.5
z 1 [ 2 ] = 0 ; a 1 [ 2 ] = 0.5 z_1^{[2]}=0;a_1^{[2]}=0.5 z1[2]=0;a1[2]=0.5
当权重全初始化为0时,神经元的输出值全部相同。接下来模拟反向传播:
α L α w 11 [ 2 ] = α L α a 1 [ 2 ] ∗ α a 1 [ 2 ] α z 1 [ 2 ] ∗ a 1 [ 1 ] = α L α a 1 [ 2 ] ∗ σ ( z 1 [ 2 ] ) ( 1 − σ ( z 1 [ 2 ] ) ) ∗ 0.5 = α L α a 1 [ 2 ] ∗ ( 0.5 ) 3 \frac{\alpha{L}}{\alpha{w_{11}^{[2]}}}=\frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*\frac{\alpha{a_1^{[2]}}}{\alpha{z_{1}^{[2]}}}*a_1^{[1]}=\frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*\sigma(z_1^{[2])}(1-\sigma(z_1^{[2])})*0.5 = \frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*(0.5)^3 αw11[2]αL=αa1[2]αLαz1[2]αa1[2]a1[1]=αa1[2]αLσ(z1[2])(1σ(z1[2]))0.5=αa1[2]αL(0.5)3
α L α w 21 [ 2 ] = α L α a 1 [ 2 ] ∗ ( 0.5 ) 3 \frac{\alpha{L}}{\alpha{w_{21}^{[2]}}}=\frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*(0.5)^3 αw21[2]αL=αa1[2]αL(0.5)3
α L α w 31 [ 2 ] = α L α a 1 [ 2 ] ∗ ( 0.5 ) 3 \frac{\alpha{L}}{\alpha{w_{31}^{[2]}}}=\frac{\alpha{L}}{\alpha{a_{1}^{[2]}}}*(0.5)^3 αw31[2]αL=αa1[2]αL(0.5)3
而对于 w 11 [ 1 ] , w 21 [ 1 ] , w 31 [ 1 ] w_{11}^{[1]},w_{21}^{[1]},w_{31}^{[1]} w11[1],w21[1],w31[1]的偏导,由于相乘的数值中包含权重值,因此全为0.
综上,当权重全部初始化为0时,每层神经元在第一次前向传播时具有相同的输出值,而在反向传播更新权重时,只有最后一层权重得到更新,从而导致网络无法学习。

学习率衰减

在Mini-Batch梯度下降法中,由于损失函数的梯度计算取决于一小部分样本,样本的随机性可能导致梯度波动方差较大,可以通过不断减少学习率,慢慢收敛到极小值

学习率衰减方法

常见的学习率衰减方法共有四种:指数衰减、固定步长衰减、多步衰减、余弦退火衰减。变化规则如下图所示:
image.png

指数衰减

学习率按照指数的形式衰减是比较常用的策略。pytorch中的使用方法如下:

ExpLR = torch.optim.lr_scheduler.ExponentialLR(optimizer_ExpLR, gamma=0.98)

其中参数gamma表示衰减的底数,选择不同的gamma值可以获得幅度不同的衰减曲线,如下:
image.png
可以看到gamma值越小学习率衰减的越快。

固定步长衰减

即学习率每个一定的步数(或者epoch)就减少为原来的gamma分之一。

StepLR = torch.optim.lr_scheduler.StepLR(optimizer_StepLR, step_size=step_size, gamma=0.65)

其中gamma参数表示衰减的程度,step_size参数表示每隔多少个step进行一次学习率调整。
image.png

多步长衰减

固定步长的衰减虽然能够按照固定的区间长度进行学习率更新,但是优势我们希望不同的区间采用不同的更新频率。

torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[200, 300, 320, 340, 200], gamma=0.8)

其中milestones参数便是学习率更新的起止区间,上述表示在区间[0, 200]之间学习率不更新,其后区间都进行一次更新。
image.png

余弦退火

严格来说,余弦退火策略不应该是学习率衰减策略,因为它使得学习率成周期性变化。

CosineLR = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer_CosineLR, T_max=150, eta_min=0)

其中T_max表示余弦函数周期;eta_min表示学习率的最小值。
image.png

BatchNorm

BatchNorm是一种常用的神经网络正则化技术,旨在加速训练并提高模型性能。

为什么要使用BatchNorm

BatchNorm的作用是,在深度神经网络训练过程中使每一层神经网络的输入变得更加稳定,从而提高网络的训练速度。

Internal Covariate Shift问题

在深度神经网络中,每一层的输入数据分布通常会随着训练的进行而发生变化,即每一层的输入分布总是变化,使得网络很难稳定学的规律。在训练过程中,由于各层参数在不停变化,导致隐藏层的输入分布老是变来变去,就所谓的"Internal Covariate Shift"问题。
BatchNorm的基本思想:让每个隐藏节点的激活输入 z z z分布固定下来,从而避免"Internal Covariate Shift"问题。由于深度神经网络在做非线性变换前的激活输入值在训练过程中,其分布逐渐发生偏移或者变动,使得整体分布逐渐往非线性函数(sigmoid为例)的取值区间的上下两端靠近,导致反向传播时低层神经网络的梯度消失,神经网络收敛越来越慢。
BN就是通过规范化手段,将每个神经元的输入值的分布强行拉回到均值为0方差为1的标准正态分布,使得激活输入值 z z z落在非线性激活函数变化率较大的区域,输入小的变换能够引起损失函数较大的变化,避免梯度消失问题产生,同时非线性激活函数的敏感区域能引起梯度较大变化,即能加快训练速度
同时,当所有分布都被拉回到标准正态分布后,多层神经网络每一层都成了一个固定的表达式,即网络的表达能力下降了,深度的意义不存在。为了解决该问题,BN对变换后的标准正态分布又进行了scale和shift操作,这两个参数scale和shift是通过训练学习得到的。

什么是BatchNorm

对于mini-batch训练来说,一次训练过程包含m个训练实例,BN的具体操作流程如下:

首先,将神经元的输入激活值拉到均值为0,方差为1的标准分布,为了防止网络表达能力下降,为每个神经元增加两个调节参数(scale和shift),使得网络的拟合能力增强。

训练阶段

在训练阶段,BN会对每个输入值(样本)进行标准化,并使用指数加权移动平均法将均值和方差保存下来,近似得到整个样本集的均值和方差。在整个样本集上,会产生(样本总数/BatchSize)组 γ \gamma γ β \beta β

def bn_simple_for_train(x, gamma, beta, bn_params):
    '''
    X : 输入数据
    gamma:缩放因子
    beta:平移因子
    bn_params: batch norm所需要的一些参数
    running_mean: 滑动平均的方式计算新的均值,训练时计算,为测试数据做准备
    running_var: 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备
    '''
    running_mean = bn_params["running_mean"]       # shape = [B]
    running_var = bn_params["running_var"]
    
    x_mean = x.mean(axis=0)
    x_var = x.var(axis=0)
    # 归一化
    x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
    # bn
    res = gamma * x_normalized + beta
    
    # 滑动平移方式
    running_mean = momentum * running_mean + (1- momentum) * x_mean
    running_var = momentum * running_var + (1 - momentum) * x_var
    
    # 记录新的参数值
    bn_params["running_mean"] = running_mean
    bn_params["running_var"] = running_var
    
    return res, bn_params

推理阶段

由于测试的时候,输入样本只有一个,没法计算均值和方差,即使用训练阶段求得的全局统计量来预测。

def bn_simple_for_test(x, gamma, beta, bn_params):
    '''
    X : 输入数据
    gamma:缩放因子
    beta:平移因子
    bn_params: batch norm所需要的一些参数
    running_mean: 滑动平均的方式计算新的均值,训练时计算,为测试数据做准备
    running_var: 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备
    '''
    running_mean = bn_params["running_mean"]      
    running_var = bn_params["running_var"]

    # 归一化
    x_normalized = (x - running_mean) / np.sqrt(running_var + eps)
    # bn
    res = gamma * x_normalized + beta

    return res, bn_params

激活函数

在机器学习和深度学习中,激活函数通常用来为神经网络引入非线性因素,使得网络能在输入和输出数据中构建复杂和非线性关系。激活函数应该需要具有如下特性:

  1. 非线性:激活函数必须具有非线性,使得输入和输出数据之间具有非线性关系;
  2. 连续性:激活函数应该是连续且可微的,因为在进行梯度更新时,需要计算激活函数的导数;
  3. 计算效率高:计算量大的激活函数会显著减慢训练过程;

为什么需要激活函数

如果不使用激活函数,即激活函数为 f ( x ) = x f(x)=x f(x)=x,此时,每一次节点的输入都是上层输出的线性函数,那么,无论神经网络有多少层,输出都是输入的线性组合,无法处理非线性关系,网络表达能力有限。通过引入激活函数,增加网络的非线性特性,使得网络的表达能力更加强大,可以拟合任意函数。此外,激活函数还可以使神经网络具有一定的抗噪性,能够处理噪声数据。

不同激活函数的区别和特点

常见的激活函数包括sigmoid函数、tanh函数、ReLU函数等。

  1. sigmoid函数

sigmoid是常用的非线性激活函数,数学形式如下:
f ( x ) = 1 1 + e − z f(x)=\frac{1}{1 + e^{-z}} f(x)=1+ez1
几何图像如下:
sigmoid.png
其导数的表达式如下:
f ′ ( x ) = σ ( x ) ( 1 − σ ( x ) ) f'(x) = \sigma(x)(1-\sigma(x)) f(x)=σ(x)(1σ(x))
几何图像如下:
sigmoid.png
优点:

  • sigmoid函数的输出范围在[0,1]之间,可以将输出限制在一个特定的范围内;
  • sigmoid函数的导数可以用它自己表示,方便计算;
  • sigmoid函数具有平滑的连续性,可以保证神经网络的连续性;

缺点:

  • sigmoid函数的梯度在较大或较小的输入值处接近于0,会导致梯度消失的问题,使得神经网络无法继续学习;
  • sigmoid函数的输出不是以0为中心zero-centered,那么在反向传播时,梯度的方向会偏向某一侧,而不是均匀地分布在两侧,这可能倒是训练过程出现不稳定的现象。
  • sigmoid函数的计算比ReLU和tanh函数慢,因为需要进行指数运算;
  1. tanh函数

tanh是一种常用的激活函数,其输出范围为[-1,1]。与sigmoid函数类似,tanh函数也是一种S型函数,但是 它的输出范围更广。其数学表达式如下:
t a n h ( x ) = e x − e − x e x + e − x tanh(x) = \frac{e^x- e^{-x}}{e^x+e^{-x}} tanh(x)=ex+exexex
几何图像如下所示:
sigmoid.png
tanh函数的导数为:
d d x t a n h ( x ) = 1 − ( t a n h ( x ) ) 2 \frac{d}{dx}tanh(x) = 1- {(tanh(x))}^2 dxdtanh(x)=1(tanh(x))2
几何图像如下所示:
sigmoid.png
优点:

  • 输出范围为[-1, 1],可以将数据规范化到一个较少的范围,有助于模型的稳定性和收敛速度;
  • 具有zero-centered特性,有组于模型的训练和优化;

缺点:

  • 容易出现梯度消失问题;
  • 计算量较大,tanh函数的计算量比sigmoid函数大两倍,影响模型的训练速度;
  • 对于输入较大或较少的数据,tanh函数会出现饱和现象,也存在梯度饱和问题,影响模型的训练效率;
  1. ReLU函数

ReLU激活函数是一种常用的非线性激活函数,其表达式如下:
r e l u ( x ) = m a x ( 0 , x ) relu(x) = max(0, x) relu(x)=max(0,x)
其几何图像如下所示:
sigmoid.png
优点:

  • 计算速度快;
  • 解决了梯度消失问题;
  • 收敛速度快,因为ReLU激活函数的导数为0或1,不存在平滑的过渡区域,因此在训练时更容易收敛;

缺点:

  • 部分神经元可能“死亡”,即输出一直为0,导致这些神经元无法参与模型的训练;
  • 需要进行数据预处理,将输入的数据进行归一化或标准化,以避免出现负数输入;
  1. leaky ReLU(2013)

Leaky ReLU激活函数的函数定义为:
l e a k y r e l u ( x ) = m a x ( x , α x ) leaky_relu(x) = max(x, \alpha{x}) leakyrelu(x)=max(x,αx)
其中α是一个非常小的正数常量,通常设置为0.01。其几何图像如下图所示:
sigmoid.png
优点:

  • 解决了神经元可能“死亡”问题;
  • 计算效率高;
  1. Softplus(2010)

Softplus激活函数的定义如下:
s o f t p l u s ( x ) = l n ( 1 + e x ) softplus(x)=ln(1+e^x) softplus(x)=ln(1+ex)
其几何图像如下图所示:
sigmoid.png
softplus激活函数可以近似堪称ReLU函数的平滑,连续且处处可导。相对于ReLU函数具有如下特点。
优点:

  • 连续性:softplus函数是一个具有连续一阶导数的函数,有利于梯度更新;
  • 非零的:不同于ReLU函数产生的输出值要么为0,要么为正,softplus函数产生正输出值;
  • 非零梯度:softplus函数对负输入值有一个非零梯度,可以防止dying ReLU问题;

缺点:

  • softplus输出值不是以0为中心;
  • 其导数常常小于1,可能存在梯度消失问题;
  1. Swish(2017)

Swish激活函数的定义如下:
S w i s h ( x ) = x ∗ σ ( β ∗ x ) Swish(x)=x*\sigma(\beta*x) Swish(x)=xσ(βx)
其中 β \beta β是一个可学习参数, σ \sigma σ是sigmoid函数。

  1. SiLU(2017)

SiLU(Sigmoid Linear Unit)激活函数融合了sigmoid和线性激活函数元素,其定义如下:
S i L U ( x ) = x 1 + e − x SiLU(x)=\frac{x}{1+e^{-x}} SiLU(x)=1+exx
其几何图像如下所示:

sigmoid.png
优点:

  • smooth gradients:SiLU函数具有平滑导数,可以避免出现梯度消失问题;
  • 非单调性:SiLU函数是非单调的,既有正值也有负值,使得SiLU函数可以捕获输入数据中的复杂模式;
  • 计算效率高;
  1. HardSwish(2019)

HardSwish激活函数是一种分段线性激活函数,是Swish函数的简化版本,其定义如下:
h a r d s w i s h ( x ) = { 0 , i f ( x ≤ − 3 ) x , i f ( x ≥ 3 ) x ( x + 3 ) 6 , o t h e r v i s e hard_swish(x) = \begin{cases} 0, \quad if(x\le-3) \\x, \quad if(x\ge3) \\ \frac{x(x+3)}{6}, \quad othervise \end{cases} hardswish(x)= 0,if(x3)x,if(x3)6x(x+3),othervise
其几何图像如下所示:
sigmoid.png
hardswish激活函数是对swish激活函数的改进,swish激活函数能在一定程度上提高神经网络的准确性,但是不适合在嵌入式移动设备上使用,因为”S“型函数在嵌入式移动设备上的计算成本高,求导较为复杂。
优点:

  • 计算速度快;
  • 相对于ReLU,能够有效地缓解梯度消失问题;

缺点:

  • 非线性程度较低:与Swish和Mish激活函数相比,HardSwish的非线性程度相对较低,可能无法充分挖掘数据中的非线性特征;
  1. Mish(2019)

Mish激活函数拥有** 无上界、有下界、平滑导数和非单调**四个优点,其数学表达形式如下:
f ( x ) = x ∗ t a n h ( s o f t p l u s ( x ) ) = x ∗ t a n h ( l n ( 1 + e x p ( x ) ) ) f(x)=x*tanh(softplus(x)) = x * tanh(ln(1+exp(x))) f(x)=xtanh(softplus(x))=xtanh(ln(1+exp(x)))
几何图形如下:
sigmoid.png
特点:

  • 非单调性(非线性):通过导数可以得到Mish函数在不同区间上可能单调递增或递减,可以捕获输入数据中的复杂模式;
  • 连续性:Mish激活函数具有较好的连续性,且处处可微,能够更好地更新模型;
  • 无上界有下界:无上界可以避免饱和问题,有下界有助于实现强正则化效果;

如何选择合适的激活函数

选择合适的激活函数可以考虑如下几点:

  • 尽量选择使用zero-centered特点的激活函数来加快模型的收敛速度;
  • 考虑梯度消失问题,选择不容易出现梯度消失问题的激活函数,如ReLU、Leaky ReLU等;
  • 考虑计算效率;

参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值