深度神经网络(DNN)模型与前向传播算法

深度神经网络(DNN)模型与前向传播算法

微信公众号:幼儿园的学霸
个人的学习笔记,关于OpenCV,关于机器学习, …。问题或建议,请公众号留言;

目录

神经网络的预备知识

神经元

神经元和感知器(感知机)本质上是一样的,只不过我们说感知器的时候,它的激活函数是阶跃函数;
感知机的激活函数是阶跃函数:
s i g n ( x ) = { 1 , i f    x < 0 1 , i f    x 0 sign(x) = \begin{cases} -1,& \quad if \; x<0\\ 1 ,& \quad if \; x \geq 0 \end{cases}
阶跃函数图像
感知器通过阶跃函数可以得到我们想要的输出结果1或者-1.

而当我们说神经元时,激活函数往往选择为sigmoid函数或双曲正切函数-tanh函数。计算一个神经元的输出的方法和计算一个感知器的输出是一样的。如下图所示:

sigmoid函数定义如下:
σ ( x ) = 1 1 + e x \sigma(x) = \frac{1}{1+e^{-x}}
sigmoid函数是一个非线性函数,值域是(0,1)。函数图像如下图所示:
sigmoid函数图像
sigmoid函数的导数是:
y = σ ( x ) = 1 1 + e x y = y ( 1 y ) y=\sigma(x) = \frac{1}{1+e^{-x}} \\ y^{'}=y(1-y)
可以看到,sigmoid函数的导数非常有趣,它可以用sigmoid函数自身来表示。这样,一旦计算出sigmoid函数的值,计算它的导数的值就非常方便。

感知机到神经网络

由于感知机的输出结果是1或者-1,该模型只能用于二元分类,且无法学习比较复杂的非线性模型,因此在工业界无法使用。
而神经网络则在感知机的模型上做了扩展,总结下主要有三点:
1)加入了隐藏层
隐藏层可以有多层,增强模型的表达能力,如下图所示。当然增加了隐藏层之后神经网络模型的复杂度也相应的增加了很多。

2)输出层的神经元可以不止一个输出,可以有多个输出
这样模型可以灵活的应用于分类回归,以及其他的机器学习领域,比如:降维或者聚类等。如下所示的神经网络具有4个输出神经元。

3)对激活函数的扩展
在神经元部分已经描述的那样,感知机的激活函数为阶跃函数,虽然简单但是处理能力有限,而在神经网络中一般采用其他激活函数,如sigmoid函数,双曲正切函数,softmax,ReLU(修正线性单元)等。通过采用不同的激活函数,神经网络的表达能力进一步增强。

什么是神经网络


神经网络其实就是按照一定规则连接起来的多个神经元。上图展示了一个全连接(full connected, FC)神经网络,通过观察上面的图,我们可以发现它的规则包括:

  • 神经元按照层来布局。最左边的层叫做输入层,负责接收输入数据;最右边的层叫输出层,我们可以从这层获取神经网络输出数据。输入层和输出层之间的层叫做隐藏层,因为它们对于外部来说是不可见的。
  • 同一层的神经元之间没有连接。
  • 层与层之间是全连接的。第N层的每个神经元和第N-1层的所有神经元相连(这就是full connected的含义),第N-1层神经元的输出就是第N层神经元的输入。
  • 每个连接都有一个权值。

上面这些规则定义了全连接神经网络的结构。事实上还存在很多其它结构的神经网络,比如卷积神经网络(CNN)、循环神经网络(RNN),他们都具有不同的连接规则。

对于隐藏层比较多(大于2)的神经网络叫做深度神经网络(Deep Neural Networks, 简称DNN)。而深度学习,就是使用深层架构(比如,深度神经网络)的机器学习方法。
那么深层网络和浅层网络相比有什么优势呢?简单来说深层网络能够表达力更强。事实上,一个仅有一个隐藏层的神经网络就能拟合任何一个函数,但是它需要很多很多的神经元。而深层网络用少得多的神经元就能拟合同样的函数。也就是为了拟合一个函数,要么使用一个浅而宽(DNN) 的网络,要么使用一个深而窄 的网络。而后者往往更节约资源。
深层网络也有劣势,就是它不太容易训练。简单的说,你需要大量的数据,很多的技巧才能训练好一个深层网络。这是个手艺活。

DNN的基本结构

上一节了解到神经网络基于感知机的扩展,而DNN可以理解为有很多隐藏层的神经网络。这个很多其实也没有什么度量标准, 多层神经网络和深度神经网络DNN其实也是指的一个东西,当然,DNN有时也叫做多层感知机(Multi-Layer perceptron,MLP), 名字实在是多。后面我们讲到的神经网络都默认为DNN。
DNN的基本结构在上一节的神经网络部分已经介绍过了。虽然DNN看起来很复杂,但是从小的局部模型来说,每一个神经元的输出还是和感知机一样,即一个线性关系 z = i ( w i x i + b ) z=\sum_{i}(w_i*xi+b) 然后加上激活函数 σ ( z ) \sigma(z)
由于DNN层数比较多,则权重w(weight)和偏置b(bias)的数量也就是很多了。
首先来看权重w的定义。我们使用 w j k l w^{l}_{jk} 表示从 ( l 1 ) t h (l-1)^{th} 层的第 k t h k^{th} 个神经元到其后面一层 l t h l^{th} 层的第 j t h j^{th} 个神经元的连接上的权重。比如,下图给出了网络中第2层的第4个神经元到第3层的第2个神经元的连接权重 w 24 3 w^3_{24}
权重上下标含义示例
你也许会问,为什么不是 w 42 3 w^3_{42} 呢:这主要是为了便于模型用矩阵形式进行表示运算,在后面展示的例子中你可以看到这种形式的下表和矩阵的行列下标表示是完美的一致的。NOTE:输入层的神经元由于没有对应的输入节点(神经元),因此输入层是没有权重w参数的
我们对神经网络的偏置和激活值(输出值)使用类似的表示。显式地,使用 b j l b^l_j 表示在第 l t h l^{th} 层的第 j t h j^{th} 个神经元的偏置;使用 a j l a^l_j 表示该神经元的激活值。如下图所示:
偏置和激活值的下标表示示例
有了上面的表示方法, l t h l^{th} 层的第 j t h j^{th} 个神经元的激活值 a j l a^l_j 就和 ( l 1 ) t h (l-1)^{th} 层的激活这通过方程联系起来了,这样可以从层的角度考虑输入输出而不仅仅是从神经元的角度考虑。

a j l = σ ( k w j k l a k l 1 + b j l ) ( 1 ) a^l_j = \sigma(\sum_k w^l_{jk}*a^{l-1}_k+b^l_j) \quad \text(1)
其中求和是在 ( l 1 ) t h (l-1)^{th} 的所有 k k 个神经元上进行的。

DNN前向传播算法数学原理

上一节中的公式(1)展示了神经网络前向传播的公式,接下来以实例进行演示。
(3,3,1)神经网络示例
对于第2层各神经元的输出 a 1 2 , a 2 2 , a 3 2 a^2_1,a^2_2,a^2_3 ,有:
a 1 2 = σ ( z 1 2 ) = σ ( w 11 2 x 1 + w 12 2 x 2 + w 13 2 x 3 + b 1 2 ) a 2 2 = σ ( z 2 2 ) = σ ( w 21 2 x 1 + w 22 2 x 2 + w 23 2 x 3 + b 2 2 ) a 3 2 = σ ( z 3 2 ) = σ ( w 31 2 x 1 + w 32 2 x 2 + w 33 2 x 3 + b 3 2 ) a^2_1 = \sigma(z^2_1) = \sigma(w^2_{11}x_1+w^2_{12}x_2+w^2_{13}x_3+b^2_1) \\ a^2_2 = \sigma(z^2_2) = \sigma(w^2_{21}x_1+w^2_{22}x_2+w^2_{23}x_3+b^2_2) \\ a^2_3 = \sigma(z^2_3) = \sigma(w^2_{31}x_1+w^2_{32}x_2+w^2_{33}x_3+b^2_3)
对于第3层的输出有:
a 1 3 = σ ( z 1 3 ) = σ ( w 11 3 a 1 2 + w 12 3 a 2 2 + w 13 3 a 3 2 + b 1 3 ) a^3_1 = \sigma(z^3_1) = \sigma(w^3_{11}a^2_1+w^3_{12}a^2_2+w^3_{13}a^2_3+b^3_1)

从上面可以看出,使用代数法一个个的表示输出比较复杂,我们可以使用矩阵的形式重写表达式(1)。
假设第l-1层共有m个神经元,而第l层共有n个神经元,则第l层各神经元的权重组成了一个n×M的矩阵 w l \bm w^l ,权重矩阵中的元素正是连接到 l t h l^{th} 层神经元的权重,更确切地说,在第 j t h j^{th} 行第 k t h k^{th} 列的元素是 w j k l w^l_{jk} ,类似的,每一层的偏置b组成了一个n×1的列向量 b l \bm b^l ,每个元素对应于 l t h l^{th} 层的每个神经元。最后,定义激活向量 a l \bm a^l ,其元素是那些激活值 a j l a^l_j

最后,需要引入向量化函数(如σ),其含义就是将函数(如σ)作用到向量 v \bm v 中的每个元素。我们使用 σ ( v ) \sigma({\bm v}) 表示这种按元素进行的函数作用。所以, σ ( v ) \sigma({\bm v}) 中的每个元素其实满足 σ ( v ) j = σ ( v j ) \sigma({\bm v})_j = \sigma(v_j) 。给个例子,如果我们的函数是 f ( x ) = x 2 f(x) = x^2 ,那么向量化的f的函数作用就起到下面的效果:
v = [ 2 3 ] f ( v ) = f ( [ 2 3 ] ) = [ f ( 2 ) f ( 3 ) ] = [ 4 9 ] {\bm v} = \left[ \begin{matrix} 2 \\ 3 \end{matrix} \right] \\ f({\bm v}) = f(\left[ \begin{matrix} 2 \\ 3 \end{matrix} \right]) = \left[ \begin{matrix} f(2) \\ f(3) \end{matrix} \right]= \left[ \begin{matrix} 4 \\ 9 \end{matrix} \right]
也就是说,向量化的f仅仅是对向量中的每个元素分别进行了平方运算。

有了上面的知识,那么方程(1)就可以写成下面这种美妙而简洁的向量(矩阵)形式:
a l = σ ( w l a l 1 + b l ) \bm a^l = \sigma(\bm {w^l \cdot a^{l-1}+b^l})
这个表达式给出了一种更加全局的思考每层的激活值和前一层激活值的关联方式:我们仅仅用权重矩阵作用在激活值(对输入层来说可以理解为输入值)上,然后加上一个偏置向量,最后作用于激活函数。这种全局的观点相比神经元层面的观点常常更加简明,和代数形式相比也没有更多的索引下标了。

我们在使用方程(2)计算 a l \bm a^l 的过程中,计算了中间量 z l = w l a l 1 + b l \bm z^l = \bm {w^l \cdot a^{l-1}+b^l} 。这个向量在后面反向传播过程中非常有用的,我们称之为l层神经元的带权输入。那么方程(2)有时候会以带权输入的形式写作 a l = σ ( z l ) \bm a^l = \sigma(\bm z^l) 。同样需要指出的是 z l \bm z^l 中的每个元素是 z j l = k w j k l a k l 1 + b j l z^l_j = \sum_k w^l_{jk}a^{l-1}_k+b^l_j .

DNN 前向传播算法实现

有了上面的铺垫,实现前向传播算法也就不难了。也就是利用每一层的权重矩阵和偏置矩阵以及激活向量进行一系列的线性运算+激活运算,从输入层开始,从上一层的结果计算下一层的结果,一层层的向后计算,一直运算到输出层,得到输出结果为止。
算法描述如下:
输入:总层数L,每一隐藏层和最后输出层所对应的权重矩 w l \bm w^l 、偏置矩阵 b l \bm b^l ,以及输入矩阵(输入向量) x \bm x

输出:输出层的输出矩阵 a l \bm a^l

实现
1)初始化输入层的激活值 a 1 = x \bm {a^1=x}
2)for l in [2,L],计算
a l = σ ( z l ) = σ ( w l a l 1 + b l ) \bm a^l = \sigma(\bm z^l)=\sigma(\bm{w^l \cdot a^{l-1}+b^l})
3)输出:2)中循环结束后的输出值即为前向传播算法最终的结果。

总结

单独看DNN前向传播算法,似乎没有什么大用处,而且这一大堆权重矩阵,偏置矩阵对应的参数怎么获得呢?怎么得到最优的矩阵W,偏置向量b呢?这个在DNN的反向传播算法时将会有说明。而理解反向传播算法的前提就是理解DNN的模型与前向传播算法。

参考链接

1. Neural Networks and Deep Learning,开源,有中文版,值得一看。
2.深度神经网络(DNN)模型与前向传播算法,比较详细,贴合我们的理解思维



下面的是我的公众号二维码图片,欢迎关注。
图注:幼儿园的学霸