机器学习入门(03)— 激活函数分类(阶跃函数和 sigmoid 函数的理论、实现、显示以及区别、非线性函数、ReLU 函数、tanh 函数)

各种激活函数介绍,请参考下面链接:
https://en.wikipedia.org/wiki/Activation_function

1. 阶跃函数

1.1 理论

式(3.3)表示的激活函数以阈值为界,一旦输入超过阈值,就切换输出。这样的函数称为“阶跃函数”
阶跃函数
因此,可以说感知机中使用了阶跃函数作为激活函数。也就是说,在激活函数的众多候选函数中,感知机使用了阶跃函数。

那么,如果感知机使用其他函数作为激活函数的话会怎么样呢?实际上,如果将激活函数从阶跃函数换成其他函数,就可以进入神经网络的世界了。

1.2 实现

阶跃函数如式(3.3)所示,当输入超过0 时,输出1,否则输出0。代码实现如下:

def step_function(x):
    if x <= 0:
        return 0
    else:
        return 1

要想上面函数接受 Numpy 数组,即 step_function(np.array([1.0, 2.0])) 需要做如下改写:

def step_function(x):
    y = x > 0
    return y.astype(np.int)

对上述函数进行分解:

In [1]: import numpy as np

In [2]: x = np.array([-1.0, 1.0, 2.0])

In [3]: x
Out[3]: array([-1.,  1.,  2.])

In [4]: y = x > 0

In [5]: y
Out[5]: array([False,  True,  True])

In [6]: 

NumPy 数组进行不等号运算后,数组的各个元素都会进行不等号运算,生成一个布尔型数组。这里,数组 x 中大于 0 的元素被转换为 True ,小于等于 0 的元素被转换为 False ,从而生成一个新的数组 y

数组 y 是一个布尔型数组,但是我们想要的阶跃函数是会输出 int 型的 0 或 1 的函数。因此,需要把数组 y 的元素类型从布尔型转换为 int 型。

In [6]: y.astype(np.int)
Out[6]: array([0, 1, 1])

In [7]: 

如上所示,可以用 astype() 方法转换 Numpy 数组的类型。 astype() 方法通过参数指定期望的类型,这个例子中是 np.int 型。 Python 中将布尔型转换为 int 型后, True 会转换为 1, False 会转换为 0。

1.3 图形

图形化代码如下:

import numpy as np
import matplotlib.pylab as plt

def step_function(x):
    return np.array(x > 0, dtype=np.int)

x = np.arange(-5.0, 5.0, 0.1)
y = step_function(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)     # 指定y轴的范围
plt.show()
  • np.arange(-5.0, 5.0, 0.1) 在 −5.0 到 5.0 的范围内,以 0.1 为单位,生成 Numpy 数组([-5.0, -4.9, …, 4.9])。
  • step_function() 以该 Numpy 数组为参数,对数组的各个元素执行阶跃函数运算,并以数组形式返回运算结果。

对数组x、y进行绘图,显示如下:
阶跃函数

2. sigmoid 函数

2.1 理论

神经网络中经常使用的一个激活函数就是式(3.6)表示的 sigmoid 函数( sigmoid function )。

sigmoid函数
式(3.6)中的 exp(−x) 表示 e−x 的意思。e 是纳皮尔常数2.7182 . . .。

神经网络中用 sigmoid 函数作为激活函数,进行信号的转换,转换后的信号被传送给下一个神经元。实际上,上一章介绍的感知机和接下来要介绍的神经网络的主要区别就在于这个激活函数。其他方面,比如神经元的多层连接的构造、信号的传递方法等,基本上和感知机是一样的。

2.2 实现

sigmoid 函数的 Python 代码如下:

In [7]: def sigmoid(x):
   ...:     return 1/(1+np.exp(-x))

这里, np.exp(-x) 对应 e−x,当参数 xNumpy 数组时,结果也能被正确计算。

In [8]: x = np.array([-1, 1, 2])

In [9]: sigmoid(x)
Out[9]: array([0.26894142, 0.73105858, 0.88079708])

In [10]: 

之所以 sigmoid 函数的实现能支持 Numpy 数组,秘密就在于 Numpy 的广播功能, 即如果在标量和 Numpy 数组之间进行运算,则标量会和 Numpy 数组的各个元素进行运算。如下:

In [10]: a = np.array([-1, 1, 2])

In [11]: 10 + a
Out[11]: array([ 9, 11, 12])

In [12]: 

2.3 图形

实现代码:

import numpy as np
import matplotlib.pylab as plt

def sigmoid(x):
   return 1/(1+np.exp(-x))

x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)     # 指定y轴的范围
plt.show()

图形化展示如下:
sigmoid函数图形

3. sigmoid 函数和阶跃函数的比较

图形比较代码:

import numpy as np
import matplotlib.pylab as plt

def step_function(x):
    return np.array(x > 0, dtype=np.int)

def sigmoid(x):
    return 1/(1+np.exp(-x))

x = np.arange(-5.0, 5.0, 0.1)
y1 = step_function(x)
y2 = sigmoid(x)


plt.plot(x, y1, label="step_function")
plt.plot(x, y2, linestyle="--", label="sigmoid") # 用虚线绘制
plt.xlabel("x") # x轴标签
plt.ylabel("y") # y轴标签
plt.title('step_function & sigmoid') # 标题
plt.legend()
plt.show()

两者之间的图形化展示如下:

比较对比

差异点:

  • sigmoid 函数是一条平滑的曲线,输出随着输入发生连续性的变化。而阶跃函数以 0 为界,输出发生急剧性的变化;

  • 相对于阶跃函数只能返回 0 或1, sigmoid 函数可以返回 0.731 . . .、0.880 . . . 等实数,也就是说,感知机中神经元之间流动的是 0 或 1 的二元信号,而神经网络中流动的是连续的实数值信号;

共同点:

  • 输入较小时,输出接近 0(为 0),随着输入增大,输出向 1 靠近(变成 1),也就是说,当输入信号为重要信息时,阶跃函数和 sigmoid 函数都会输出较大的值,当输入信号为不重要的信息时,两者都输出较小的值;
  • 不管输入信号有多小,或者有多大,输出信号的值都在 0 到 1 之间;
  • 两者均为非线性函数。 sigmoid 函数是一条曲线,阶跃函数是一条像阶梯一样的折线;

4. 非线性函数

在介绍激活函数时,经常会看到“非线性函数”和“线性函数”等术语。函数本来是输入某个值后会返回一个值的转换器。向这个转换器输入某个值后,输出值是输入值的常数倍的函数称为线性函数(用数学式表示为 h(x) = cxc 为常数)。

因此,线性函数是一条笔直的直线。而非线性函数,顾名思义,指的是不像线性函数那样呈现出一条直线的函数。

神经网络的激活函数必须使用非线性函数。换句话说,激活函数不能使用线性函数。为什么不能使用线性函数呢?因为使用线性函数的话,加深神经网络的层数就没有意义了。

线性函数的问题在于,不管如何加深层数,总是存在与之等效的“无隐藏层的神经网络”。为了具体地(稍微直观地)理解这一点,我们来思考下面这个简单的例子。

这里我们考虑把线性函数 h(x) = cx 作为激活函数,把 y(x) = h(h(h(x))) 的运算对应 3 层神经网络 A。这个运算会进行 y(x) = c × c × c × x 的乘法运算,但是同样的处理可以由 y(x) = ax (注意,a = c 3 )这一次乘法运算(即没有隐藏层的神经网络)来表示。

如本例所示,使用线性函数时,无法发挥多层网络带来的优势。因此,为了发挥叠加层所带来的优势,激活函数必须使用非线性函数

5. ReLU 函数

在神经网络发展的历史上, sigmoid 函数很早就开始被使用了,而最近则主要使用 ReLU 线性整流函数 ( Rectified Linear Unit )函数。

ReLU 函数在输入大于 0 时,直接输出该值;在输入小于等于 0 时,输出 0 (图 3-9)。
ReLU函数公式
ReLU 函 数 是 一 个 非 常 简 单 的 函 数。因 此, ReLU 函数的实现也很简单,可以写成如下形式。

def relu(x):
	return np.maximum(0, x)

maximum 函数会从输入的数值中选择较大的那个值进行输出。

ReLU 函数

6. tanh 函数

激活函数 tanh 的数学表达式如下:
公式
图像显示如下:
tanh函数图形化显示
tanh 函数的输出结果是零中心数据,所以解决了激活函数在模型优化过程中收敛速度变慢的问题。

参考:《深度学习入门:基于Python的理论与实现》

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值