激活函数是神经网络中引入的非线性函数,用于捕获数据中的复杂关系。它来自动物界的灵感,动物的神经元会接受来自对它有作用的其他神经元的信号,当然这些信号对该神经元的作用大小不同(即具有不同的权重)。那么该神经元的信号值就是其他神经元信号加权求和后的值。如果该信号值大于指定阈值,则会激活,否则不会激活,抽象的数学模型为:
这里的激活函数就是阶跃函数,但在0处跃变且不可导。
进一步抽象出神经网络模型中神经元模型为:
其中为激活函数
没有激活函数,可能简单的二分类问题都不能被优雅解决
现在有一个二分类问题,将三角形和圆点进行正确分类。这是一个线性不可分的问题(在这个平面里,找不到一条直线可以把图中的三角形和圆点完全分开),我们试着用神经网络解决这个问题。
可能的解决思路:
首先我们想到利用最简单的单层感知机来解决,单层感知机可以画出一条直线,把平面分开。
左图是没有激活函数的单层感知机结构,其中w1,w2是权重值,b是偏置值,它的工作原理是:输入一个样本(有两个特征x1,x2),如果y>0说明该样本是正类;如果y<0,说明该样本是负类。我们这里不讨论y=0的特殊情况。根据单层感知机的工作原理,我们画出右边的坐标图。
结论是:不带激活函数的单层感知机是一个线性分类器,不能解决线性不可分的问题。 不能解决二分类问题。
不带激活函数的单层感知机解决不了问题,那我们就会想到用多个感知机进行组合,获得更强的分类能力,看看能不能解决我们的线性不可分问题。
上图中,虽说模型变得复杂,表达能力更强一点,但y还是一个关于x1,x2的线性表达式。
结论是:合并后的多个感知器本质上还是一个线性分类器,还是解决不了非线性的问题。
进一步分析总结:不管是单层感知机还是多个感知器,只要不带激活函数,都只能解决线性可分的问题,解决不了我们的线性不可分问题。
在上面的线性方程的组合过程中,我们其实类似的在做三条直线的线性组合,如图5所示。图5描述了,当我们直接用没有激活函数的分类器时,其实我们还是线性组合,最多也就是更复杂的线性组合罢了。
因此就需要来引入激活函数了。
我们再设计一个神经网络,在所有的隐层和输出层加一个激活函数,这里激活函数我们就用Sigmoid函数,如下图所示,这样y出的就是一个非线性函数了,y的输出更复杂,有了这样的非线性激活函数以后,神经网络的表达能力更加强大了。能不能解决我们一开始提出的线性不可分问题呢?
我们把上图中的带有激活函数的单层感知机扩展到带有激活函数的多个神经元的情况。那么神经网络的表达能力更强,具体如下图所示。
和之前相对应的非线性组合是图8所示的样子。这样看起来,似乎已经能解决我们线性不可分的问题了。最后,我们通过最优化损失函数的做法,通过不断的学习,能够学到正确分类三角形和圆点的曲线。
总结:激活函数是用来加入非线性因素的,提高神经网络对模型的表达能力,解决线性模型所不能解决的问题。要知道大部分问题是非线性问题,因此激活函数是必不可少的。
示例代码
import numpy as np
import matplotlib.pyplot as plt
sigmoid = lambda x: 1 / (1 + np.exp(-x))
x = np.linspace(-10, 10, 10)
y = np.linspace(-10, 10, 10)
fig = plt.figure()
plt.plot(y, sigmoid(y))
plt.grid(linestyle='--')
plt.xlabel('X Axis')
plt.ylabel('Y Axis')
plt.title('Sogmoid Function')
plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-2, -1, 0, 1, 2])
plt.xlim(-4,4)
plt.ylim(-2,2)
plt.show()
运行代码显示
Sigmoid函数优点:
Sigmoid函数缺点:
示例代码:
import numpy as np
import matplotlib.pyplot as plt
sigmoid = lambda x: 1 / (1 + np.exp(-x))
tanh = lambda x: 2*sigmoid(2*x)-1
x = np.linspace(-10, 10, 10)
y = np.linspace(-10, 10, 10)
plt.plot(y, tanh(y), 'b', label='linspace(-10, 10, 100)')
plt.grid(linestyle='--')
plt.xlabel('X Axis')
plt.ylabel('Y Axis')
plt.title('Tanh Function')
plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.xlim(-4,4)
plt.ylim(-4,4)
plt.show()
代码运行结果:
tanh 函数优点:
tanh 函数缺点:
示例代码:
import numpy as np
import matplotlib.pyplot as plt
relu = lambda x: np.where(x>=0, x, 0)
x = np.linspace(-10, 10, 10)
y = np.linspace(-10, 10, 1000)
plt.plot(y, relu(y), 'b', label='linspace(-10, 10, 100)')
plt.grid(linestyle='--')
plt.xlabel('X Axis')
plt.ylabel('Y Axis')
plt.title('RuLU')
plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.xlim(-4,4)
plt.ylim(-4,4)
plt.show()
代码运行结果:
Relu优点:
Relu缺点:
示例代码:
import numpy as np
import matplotlib.pyplot as plt
leakyrelu = lambda x: np.where(x>=0, x, 0.1*x)
x = np.linspace(-10, 10, 10)
y = np.linspace(-10, 10, 1000)
plt.plot(y, leakyrelu(y), 'b', label='linspace(-10, 10, 100)')
plt.grid(linestyle='--')
plt.xlabel('X Axis')
plt.ylabel('Y Axis')
plt.title('Leaky ReLU')
plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.xlim(-4, 4)
plt.ylim(-4, 4)
plt.show()
代码运行结果:
leaky_relu优点:
leaky_relu缺点: