深度学习原理学习2:神经网络与激活函数
本文是深度学习原理的学习笔记,是作者学习斋藤康毅的《深度学习入门-基于Python的理论与实现》中产生的感悟和笔记。
神经网络示例
用图来表示神经网络的话,我们将输入称为输入层,输出称为输出层,中间的所有部分均成为中间层或隐藏层,就可以得到神经网络的基本例子。
仅看上图,神经网络的形状类似上一篇的多层感知机,就神经元的连接方式而言,全连接的神经网络与上一篇的朴素感知机并没有任何差异。而细节在于神经网络中信号的传递方式。要看清这个细节,我们需要更详细的表示朴素感知机,如下图所示:
如果我们将偏置设为一个特殊的输入,它的输入恒为1,且权重为b。则输出部分其实经过了一个加和计算和一个特殊的函数计算
h
(
)
h()
h(),若称加和计算的结果为a,则
h
(
x
)
h(x)
h(x)的数学表示如下:
h
(
a
)
=
{
0
(
a
≤
0
)
1
(
a
>
0
)
h(a)= \left\{ \begin{array}{lr} 0\ \ \ (a\leq0) \\ 1\ \ \ (a>0) \end{array} \right.
h(a)={0 (a≤0)1 (a>0)
这种函数也被称为阶跃函数,其函数图形如下:
h ( x ) h(x) h(x)会将输入信号的总和转换为输出信号,这种函数一般称为激活函数 (activation function)。如“激活”一词所示,激活函数的作用在于决定如何来激活输入信号的总和。
激活函数
参考激活函数(Activation Function)的资料,激活函数(Activation Function)是一种添加到人工神经网络中的函数,旨在帮助网络学习数据中的复杂模式。类似于人类大脑中基于神经元的模型,激活函数最终决定了要发射给下一个神经元的内容。不使用激活函数的话,神经网络的每层都只是做线性变换,多层输入叠加后也还是在用复杂的线性组合来试图逼近曲线。因为线性模型的表达能力通常不够,所以这时候就体现了激活函数的作用了,激活函数可以引入非线性因素,神经网络就有可能学习到平滑的曲线来分割平面,能够更好的拟合目标函数。
h
(
x
)
h(x)
h(x)表示的激活函数以阈值为界,一旦输入超过阈值,就切换输出。这样的函数称为“阶跃函数”。因此,可以说感知机中使用了阶跃函数作为激活函数。也就是说,在激活函数的众多候选函数中,感知机使用了阶跃函数。如果将激活函数从阶跃函数换成其他函数,就可以进入神经网络的世界了。sigmoid 函数就是神经网络经常使用的一个激活函数。式子如下所示:
h
(
x
)
=
1
1
+
e
−
x
h(x)=\frac{1}{1+e^{-x}}
h(x)=1+e−x1
其函数图像如下所示:
对比sigmoid 函数和阶跃函数,sigmoid 函数是一条平滑的曲线,输出随着输入发生连续性的变化。而阶跃函数以 0 为界,输出发
生急剧性的变化。sigmoid 函数的平滑性对神经网络的学习具有重要意义。并且相对于阶跃函数只能返回 0 或 1,sigmoid 函数可以返回 0.731 . . .、0.880 . . . 等实数(这一点和刚才的平滑性有关)。也就是说,感知机中神经元之间流动的是 0 或 1 的二元信号,而神经网络中流动的是连续的实数值信号。
二者也有不少共同性质,从宏观视角看,可以发现它们具有相似的形状。实际上,两者的结构均是“输入小时,输出接近 0 (为 0);随着输入增大,输出向 1 靠近(变成 1)”。也就是说,当输入信号为重要信息时,阶跃函数和 sigmoid 函数都会输出较大的值;当输入信号为不重要的信息时,两者都输出较小的值。还有一个共同点是,不管输入信号有多小,或者有多大,输出信号的值都在 0 到 1 之间。但最重要的是,这两个函数都是非线性函数。
线性激活函数的讨论
假设线性函数 h ( x ) = c x h(x)=cx h(x)=cx,3层带激活函数的神经网络可以抽象为 y ( x ) = h ( h ( h ( x ) ) ) y(x)=h(h(h(x))) y(x)=h(h(h(x)))。化简可得到 y ( x ) = c 3 x y(x)=c^3x y(x)=c3x,本质上是额外添加了一层偏置为0的网络层,不能起到激活函数应有的作用。
无论是阶跃函数还是sigmoid 函数,都是很早的较原始的激活函数了。据书中介绍,作为sigmoid 函数的替代品,人们使用了效果更好的ReLU 函数、PReLU函数。ReLu函数的公式和曲线如下所示:
h
(
x
)
=
{
x
(
x
>
0
)
0
(
x
≤
0
)
h(x)=\left\{ \begin{array}{lr} x\ \ \ (x>0) \\ 0\ \ \ (x\leq0) \end{array} \right.
h(x)={x (x>0)0 (x≤0)
在分类问题等特殊问题上,我们也要使用特殊的激活函数,如softmax函数,其数学公式如下所示:
y
k
=
e
a
k
∑
i
=
1
n
e
a
i
y_k=\frac{e^{a_k}}{\displaystyle\sum^n_{i=1}e^{a_i}}
yk=i=1∑neaieak
其中,softmax的作用层共有n个神经元, y k y_k yk计算了第k个神经元的输出。作为一种特殊的激活函数,softmax函数从作用层的所有神经元接受输入,并针对每个神经元产生单独的输出。
同时,为了避免在运算过程中产生溢出错误。我们往往要在函数中
e
e
e的指数上减去输入信号所能表示的最大值,经数学推导可以发现改进后的式子不影响softmax的最终值。
y
k
=
e
a
k
∑
i
=
1
n
e
a
i
=
C
e
a
k
C
∑
i
=
1
n
e
a
i
=
e
a
k
+
log
C
∑
i
=
1
n
e
a
i
+
log
C
=
e
a
k
+
C
′
∑
i
=
1
n
e
a
i
+
C
′
\begin{align} y_k=\frac{e^{a_k}}{\displaystyle\sum^n_{i=1}e^{a_i}}\ &= \frac{Ce^{a_k}}{C\displaystyle\sum^n_{i=1}e^{a_i}} \\ &= \frac{e^{a_k+\log C}}{\displaystyle\sum^n_{i=1}e^{a_i+\log C}} \\ &= \frac{e^{a_k+C'}}{\displaystyle\sum^n_{i=1}e^{a_i+C'}} \end{align}
yk=i=1∑neaieak =Ci=1∑neaiCeak=i=1∑neai+logCeak+logC=i=1∑neai+C′eak+C′
softmax 函数的输出是 0.0 到 1.0 之间的实数。并且,softmax函数的输出值的总和是 1。输出总和为 1 是 softmax 函数的一个重要性质。正因为有了这个性质,我们才可以把 softmax 函数的输出解释为“概率”。也就是说,通过使用 softmax 函数,我们可以用概率的(统计的)方法处理问题。并且在使用了softmax函数后,各个元素之间的大小关系也不会改变。
softmax函数的运算需要一定的时间,因此在实际预测时softmax函数可以省略,输出层的最大值就是预测结果。之所以在训练时使用softmax,是因为softmax可以让模型进行更好的学习。详情见下一篇。
原书中本章节还涉及到神经网络的矩阵运算、正则化和归一化内容。其中矩阵运算部分介绍的是神经网络如何使用线性代数加快运算速度,简化运算方式。这些内容将在后文专门提及。本篇仅涉及神经网络与激活函数部分。