【论文复现】ReLU、Leaky ReLU、PReLU、RReLU实验对比(2015)

在这里插入图片描述

前言

论文地址: https://arxiv.org/pdf/1505.00853.pdf.

论文贡献:

这篇论文并没有提出什么新的激活函数,而是对现有的非常火的几个非饱和激活函数作了一个系统性的介绍以及对他们的性能进行了对比。最后发现,在较小的数据集中(大数据集未必),Leaky ReLU及其变体(PReLU、RReLU)的性能都要优于ReLU激活函数;而RReLU由于具有良好的训练随机性,可以很好的防止过拟合。

一、背景

我们在设计神经网络时候,在选择激活函数方面,大家都有一个常识:使用非饱和激活函数取代替饱和激活函数。主要原因有两个:1)非饱和激活函数可以解决梯度爆炸问题;2)非饱和激活函数可以加快模型收敛速度。

而在非饱和激活函数中,最成功的使用范围最广的当属ReLU激活函数,在上一篇博客: ReLU Activation(2011).中我们就系统性的讨论了ReLU激活函数的由来,以及它的优缺点。我们可以知道,ReLU激活函数成功的最大秘籍在于它具有稀疏性(Sparsity)特征。

但是在最新的Leaky ReLU家族中,却打破了这个秘籍,在 x<0 部分主动的使用一些非零梯度来代替原先全为0(稀疏性)。原因也可以从前一篇博客中知道:因为 x<0,太绝对了,很容易在训练的时候产生神经元坏死现象:某些神经元可能永远不会被激活,导致相应参数永远不会被更新(在负数部分,梯度为0)。

人们先后又提出了Leaky ReLU及其变体函数来解决这个问题。4个函数图像如下图:
在这里插入图片描述

一、ReLU

R e L U = m a x ( 0 , x ) = { 0 , if x<0 x , if x ≥ 0 ReLU = max(0, x) = \begin{cases} 0, & \text {if x<0} \\ x, & \text{if x$\geq$0} \end{cases} ReLU=max(0,x)={0,x,if x<0if x0

函数图像和导函数图像如下:
在这里插入图片描述

二、Leaky ReLU

函数公式:
f ( x ) = m a x ( a x , x ) = { a x , if x<0 x , if x ≥ 0 f(x)=max(ax,x) = \begin{cases} ax, & \text {if x<0} \\ x, & \text{if x$\geq$0} \end{cases} f(x)=max(ax,x)={ax,x,if x<0if x0
原论文中建议a最好小于0.01,但我们在设计的时候a通常会设为0.01。

函数图像:
在这里插入图片描述
理论上Leaky ReLU可以解决上述的dead ReLU现象。

三、PReLU(parametric ReLU)

函数公式:

f ( x ) = { x i x i > 0 α i x i 其 他 f(x)=\begin{cases} x_i & x_i > 0 \\ \alpha_ix_i & 其他 \end{cases} f(x)={xiαixixi>0

注意:

  • α i \alpha_i αi是可通过反向传播学习到的参数

函数图像:
在这里插入图片描述
理论上也可以避免dead ReLU现象;

四、RReLU(Randomized ReLU)

函数公式:
f ( x ) = m a x ( a x , x ) = { a x , if x<0 x , if x ≥ 0 f(x)=max(ax,x) = \begin{cases} ax, & \text {if x<0} \\ x, & \text{if x$\geq$0} \end{cases} f(x)=max(ax,x)={ax,x,if x<0if x0

注意:

  • 训练时,a服从均匀分布 U ( l , u ) , l < u U(l, u), l<u U(l,u),l<u and l , u ∈ [ 0 , 1 ) l, u \in[0, 1) l,u[0,1)
  • 测试时,将训练的所有的a取平均值(有点像BN)

函数图像:
在这里插入图片描述
理论上也可以避免dead ReLU现象;

五、实验结果

CIFAR-10:
在这里插入图片描述
CIFAR-100:
在这里插入图片描述
NDSB:
在这里插入图片描述

可以看到在三个数据上Leaky ReLU、PReLU、RReLU的表现都要优于当前使用最多的激活函数ReLU。但这仅仅是在小数据集上的表现,更大的数据集更复杂的任务的情况下,还需要更多的实验。

六、PyTorch实现

自己代码实现

class ActivateFunc():
    def __init__(self, x, b=None, lamb=None, alpha=None, a=None):
        super(ActivateFunc, self).__init__()
        self.x = x
        self.b = b
        self.lamb = lamb
        self.alpha = alpha
        self.a = a
        
    def ReLU(self):
        y = np.where(self.x < 0, 0, self.x)
        y_grad = np.where(self.x < 0, 0, 1)
        return [y, y_grad]
        
    def LeakyReLU(self):   # a大于1,指定a
        y = np.where(self.x < 0, self.x / self.a, self.x)
        y_grad = np.where(self.x < 0, 1 / self.a, 1)
        return [y, y_grad]

    def PReLU(self):    # a大于1,指定a
        y = np.where(self.x < 0, self.x / self.a, self.x)
        y_grad = np.where(self.x < 0, 1 / self.a, 1)
        return [y, y_grad]

class RReLU(Module):
    __constants__ = ['lower', 'upper', 'inplace']

    lower: float
    upper: float
    inplace: bool

    def __init__(
        self,
        lower: float = 1. / 8,
        upper: float = 1. / 3,
        inplace: bool = False
    ):
        super(RReLU, self).__init__()
        self.lower = lower
        self.upper = upper
        self.inplace = inplace

    def forward(self, input: Tensor) -> Tensor:
        return F.rrelu(input, self.lower, self.upper, self.training, self.inplace)

    def extra_repr(self):
        inplace_str = ', inplace=True' if self.inplace else ''
        return 'lower={}, upper={}{}'.format(self.lower, self.upper, inplace_str)

调包实现:

import torch.nn as nn

activation_cfg = {
    # layer_abbreviation: module
    'ReLU': nn.ReLU,
    'LeakyReLU': nn.LeakyReLU,
    'PReLU': nn.PReLU,
    'RReLU': nn.RReLU,
    # 'ReLU6': nn.ReLU6,
    # 'SELU': nn.SELU,
    # 'CELU': nn.CELU
}


def build_activation_layer(cfg):
    """ Build activation layer
    Args:
        cfg (dict): cfg should contain:
            type (str): Identify activation layer type.
            layer args: args needed to instantiate a activation layer.
    Returns:
        layer (nn.Module): Created activation layer
    """
    assert isinstance(cfg, dict) and 'type' in cfg
    cfg_ = cfg.copy()

    layer_type = cfg_.pop('type')
    if layer_type not in activation_cfg:
        raise KeyError('Unrecognized activation type {}'.format(layer_type))
    else:
        activation = activation_cfg[layer_type]
        if activation is None:
            raise NotImplementedError

    layer = activation(**cfg_)
    return layer
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值