深度学习之激活函数及python实现

激活函数

如果没有激活函数引入非线性,多层神经网络就相当于单层神经网络,非线性激活函数可以使得神经网络逼近任意复杂的函数。

1. Sigmoid函数
1.1 Sigmoid函数解析式

Sigmoid函数:

f ( x ) = 1 1 + e − x f(x) = \frac {1} {1 + e^{-x}} f(x)=1+ex1

Sigmoid函数一阶导数:

f ′ ( x ) = ( 1 1 + e − x ) ′ = − 1 ( 1 + e − x ) 2 ( 1 + e − x ) ′ = 1 1 + e − x e − x 1 + e − x = f ∗ ( 1 − f ) \begin{aligned} f'(x) &= (\frac{1}{1 + e^{-x}})'\\ &=- \frac{1}{{(1+e^{-x}})^2} (1+e^{-x})'\\ &=\frac{1}{1+e^{-x}} \frac{e^{-x}}{1+e^{-x}} \\ &=f*(1-f) \end{aligned} f(x)=(1+ex1)=(1+ex)21(1+ex)=1+ex11+exex=f(1f)

1.2 Sigmoid函数代码实现以及图像展示
import numpy as np


class Sigmoid(object):
    """
    Sigmoid 激活函数
    """
    def __str__(self):
        return 'Sigmoid'

    def __call__(self, x):
        """
        调用此类是,可直接执行函数
        :param x: 输入序列
        """
        return self.fn(x)

    def fn(self, x):
        """
        $$f(x) =  \frac {1} {1 + e^{-x}}$$
        """
        x = np.array(x)
        return 1 / (1 + np.exp(-1 * x))

    def grad(self, x):
        """
        Sigmoid 一阶导数: f'(x) = f(x) * (1 - f(x))
        """
        return self.fn(x) * (1 - self.fn(x))


def plot(fn):
    # 画图
    import matplotlib.pyplot as plt
    x = np.linspace(-6, 6, 100)

    fig, ax = plt.subplots()
    ax.plot(x, fn(x), c='red', label=r"$f(x)$")
    ax.plot(x, fn.grad(x), label=r"$\partial f(x) / \partial x$")
    ax.set_title("{}".format(fn))
    ax.grid()
    ax.legend()
    plt.show()


plot(fn=Sigmoid())

在这里插入图片描述

1.3 Sigmoid函数的分析

如上图所示,Sigmoid的函数输出值在0-1之间,可以表示概率值。
Sigmoid函数有如下几个缺点:

  1. 梯度消失。当x在0附近时,函数的导数比较大,也就是在更新的时候可以得到较大的调整,但是,当x远离0时,结果就会在0和1附近,梯度也基本上为0,神经元无法进行权值更新。此外,与这些神经元连接的神经元权值更新也会很小。这个问题称为梯度消失。
  2. 计量量比较大,尤其是指数函数计算。
2. Tanh激活函数
2.1 Tanh函数解析式

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

其一阶导数:

t a n h ′ ( x ) = [ e x − e − x e x + e − x ] ′ = − ( e x + e − x ) ′ ( e x + e − x ) 2 ( e x − e − x ) + ( e x − e − x ) ′ e x + e − x = − ( e x − e − x ) ( e x + e − x ) 2 ( e x − e − x ) + ( e x + e − x ) e x + e − x = 1 − t a n h 2 ( x ) \begin{aligned} tanh'(x) &= [\frac {e^x - e^{-x}} {e^x + e^{-x}}]' \\ &= - \frac {(e^x + e^{-x})'} {(e^x + e^{-x})^2} (e^x - e^{-x}) + \frac {(e^x - e^{-x})'} {e^x + e^{-x}} \\ & = - \frac {(e^x - e^{-x})} {(e^x + e^{-x})^2} (e^x - e^{-x}) + \frac {(e^x + e^{-x})} {e^x + e^{-x}} \\ &= 1 - tanh^2(x) \end{aligned} tanh(x)=[ex+exexex]=(ex+ex)2(ex+ex)(exex)+ex+ex(exex)=(ex+ex)2(exex)(exex)+ex+ex(ex+ex)=1tanh2(x)

2.2 Tanh函数的代码实现
class Tanh(object):
    """
    tanh 激活函数
    """
    def __str__(self):
        return 'Tanh'

    def __call__(self, x):
        return self.fn(x)

    def fn(self, x):
        """$$tanh(x) = \frac {e^x - e^{-x}} {e^x + e^{-x}}$$"""
        x = np.array(x)
        return np.tanh(x)

    def grad(self, x):
        """一阶导数: tanh'(x) = 1 - tanh ** 2"""
        return 1 - self.fn(x) ** 2

在这里插入图片描述

2.3 Tanh函数的分析

tanh和sigmoid不同之处在于,sigmoid处在[0,1]之间,tanh处在[-1,1]之间。但是它们都没有解决梯度爆炸的问题。

3. ReLu-线性整流函数
3.1 ReLu函数解析式

f ( x ) = max ⁡ ( 0 , x ) f(x) = \max(0, x) f(x)=max(0,x)

其一阶导数:

f ′ ( x ) { 1 , i f   x > 0 0 , e l s e f'(x) \begin{cases} 1, &if\ x > 0\\ 0, &else \end{cases} f(x){1,0,if x>0else

3.2 ReLu函数的代码实现
class ReLu(object):
    """
    ReLu 激活函数
    """
    def __str__(self):
        return "ReLu"

    def __call__(self, x):
        return self.fn(x)

    def fn(self, x):
        """f(x) = max (0, x)"""
        x = np.array(x)
        return np.clip(x, 0, np.inf)

    def grad(self, x):
        """f'(x) = 1 if x > 0 else f'(x) = 0"""
        x = np.array(x)
        return (x > 0).astype(int)

在这里插入图片描述

3.3 ReLu函数的分析

优点:

  1. ReLu在x>0的时候,输出值也为x,所以在正数范围内对梯度消失有抵抗力;
  2. 在x<0的时候,输出为0,反向传播的过程中,结果也都会是0,计算效率高,并且使得网络稀疏,减少参数之间的相互依存关系,缓解过拟合问题的发生。

缺点:因为x<0时,输出为0,可以能导致神经元死亡, dying ReLu problem

4. Leaky ReLu - 泄漏Relu激活函数
4.1 Leaky ReLu 函数解析式

f ( x ) = max ⁡ ( α x , x ) , α ∈ ( 0 , 1 ) f(x) = \max(\alpha x, x), \alpha \in (0, 1) f(x)=max(αx,x),α(0,1)

一阶导数:

f ′ ( x ) { 1 , i f   x > 0 − α , e l s e f'(x) \begin{cases} 1, &if\ x > 0\\ -\alpha, &else \end{cases} f(x){1,α,if x>0else

4.2 Leaky ReLu 函数代码实现
class LeakyReLu(object):
    def __init__(self, alpha=0.1):
        self.alpha = alpha

    def __str__(self):
        return "LeakyReLu"

    def __call__(self, x):
        return self.fn(x)

    def fn(self,x):
        """
        f(x) = x, if x > 0
             = alpha * x , if  x <= 0
        """
        x = np.array(x).astype(float)
        x[x < 0]= x[x < 0] * self.alpha
        return x

    def grad(self, x):
        """
        f'(x) = 1, if x > 0
              = alpha, else
        """
        x = np.array(x)
        y = np.ones_like(x)
        y[x < 0] *= self.alpha
        return y

在这里插入图片描述

4.3 Leaky ReLu函数分析

Leaky relu就是为了解决ReLu会导致神经元思维而设计的,即便是在x<0的情况下,也给一个很小的斜率进行激活。

5. ELU
5.1 ELU函数解析式

f ( x ) = { x , i f   x > 0 α ( e x − 1 ) , e l s e f(x) = \begin{cases} x, &if\ x > 0\\ \alpha(e^x - 1), &else \end{cases} f(x)={x,α(ex1),if x>0else

一阶导数:

f ′ ( x ) = { 1 , i f   x > 0 α e x , e l s e f'(x) = \begin{cases} 1, &if\ x > 0\\ \alpha e^x , &else \end{cases} f(x)={1,αex,if x>0else

5.2 ELU函数代码实现
class ELU(object):
    def __init__(self, alpha=1.0):
        self.alpha = alpha

    def __str__(self):
        return 'ELU'

    def __call__(self, x):
        return self.fn(x)

    def fn(self, x):
        """
        f(x) = x,                       if x > 0
             = alpha * (np.exp(x) - 1), else
        """
        x = np.array(x).astype(float)
        return np.where(x > 0, x, self.alpha * (np.exp(x) - 1))

    def grad(self, x):
        """
        f'(x) = 1,                 if x > 0
              = alpha * np.exp(x)  else
        """
        x = np.array(x).astype(float)
        return np.where(x > 0, np.ones_like(x), self.alpha * np.exp(x))


在这里插入图片描述

5.3 ELU函数分析

ELU也是针对RELU会导致神经元死亡的问题设计的,在x<0时有输出。不过ELU有指数运算问题。

6. SELU
6.1 SELU函数解析式

f ( x ) = λ { x , i f   x > 0 α ( e x − 1 ) , e l s e f(x) = \lambda \begin{cases} x, &if\ x > 0\\ \alpha(e^x - 1), &else \end{cases} f(x)=λ{x,α(ex1),if x>0else

一阶导数:

f ′ ( x ) = λ { 1 , i f   x > 0 α e x , e l s e f'(x) = \lambda \begin{cases} 1, &if\ x > 0\\ \alpha e^x, &else \end{cases} f(x)=λ{1,αex,if x>0else

6.2 SELU函数代码实现
class SELU(object):
    def __init__(self):
        self.alpha = 1.6732632423543772848170429916717
        self.beta = 1.0507009873554804934193349852946

    def __str__(self):
        return "SELU"

    def __call__(self, x):
        return self.fn(x)

    def fn(self, x):
        """
                f(x) = beta * x,                       if x > 0
                     = beta * alpha * (np.exp(x) - 1), else
                """
        x = np.array(x).astype(float)
        return np.where(x > 0, x, self.alpha * (np.exp(x) - 1)) * self.beta

    def grad(self, x):
        """
        f'(x) = beta,                 if x > 0
              = beta * alpha * np.exp(x)  else
        """
        x = np.array(x).astype(float)
        return np.where(x > 0, np.ones_like(x), self.alpha * np.exp(x)) * self.beta


在这里插入图片描述

6.3 SELU函数分析

SELU就是在ELU前面乘了一个lambda,并且lambda>1, 可以通过调节lamda,调整参数更新的快慢,就可以调节输出的方差和均值。

参考资料:
https://blog.csdn.net/qq_30815237/article/details/86700680
https://github.com/ddbourgin/numpy-ml/tree/master/numpy_ml/neural_nets/activations

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值