深度学习之网络与计算
1 网络操作与计算
1.1 前向传播与反向传播?
神经网络的计算主要有两种:前向传播(foward propagation, FP)作用于每一层的输入,通过逐层计算得到输出结果;反向传播(backward propagation, BP)作用于网络的输出,通过计算梯度由深到浅更新网络参数。
前向传播
假设上一层结点 $ i,j,k,… $ 等一些结点与本层的结点 $ w $ 有连接,那么结点 $ w $ 的值怎么算呢?就是通过上一层的 $ i,j,k,… $ 等结点以及对应的连接权值进行加权和运算,最终结果再加上一个偏置项(图中为了简单省略了),最后在通过一个非线性函数(即激活函数),如 R e L u ReLu ReLu, s i g m o i d sigmoid sigmoid 等函数,最后得到的结果就是本层结点 $ w $ 的输出。
最终不断的通过这种方法一层层的运算,得到输出层结果。
反向传播
由于我们前向传播最终得到的结果,以分类为例,最终总是有误差的,那么怎么减少误差呢,当前应用广泛的一个算法就是梯度下降算法,但是求梯度就要求偏导数,下面以图中字母为例讲解一下:
设最终误差为 $ E $且输出层的激活函数为线性激活函数,对于输出那么 $ E $ 对于输出节点 $ y_l $ 的偏导数是 $ y_l - t_l $,其中 $ t_l $ 是真实值,$ \frac{\partial y_l}{\partial z_l} $ 是指上面提到的激活函数,$ z_l $ 是上面提到的加权和,那么这一层的 $ E $ 对于 $ z_l $ 的偏导数为 $ \frac{\partial E}{\partial z_l} = \frac{\partial E}{\partial y_l} \frac{\partial y_l}{\partial z_l} $。同理,下一层也是这么计算,只不过 $ \frac{\partial E}{\partial y_k} $ 计算方法变了,一直反向传播到输入层,最后有 $ \frac{\partial E}{\partial x_i} = \frac{\partial E}{\partial y_j} \frac{\partial y_j}{\partial z_j} $,且 $ \frac{\partial z_j}{\partial x_i} = w_i j $。然后调整这些过程中的权值,再不断进行前向传播和反向传播的过程,最终得到一个比较好的结果。
1.2 如何计算神经网络的输出?
如上图,输入层有三个节点,我们将其依次编号为 1、2、3;隐藏层的 4 个节点,编号依次为 4、5、6、7;最后输出层的两个节点编号为 8、9。比如,隐藏层的节点 4,它和输入层的三个节点 1、2、3 之间都有连接,其连接上的权重分别为是 $ w_{41}, w_{42}, w_{43} $。
为了计算节点 4 的输出值,我们必须先得到其所有上游节点(也就是节点 1、2、3)的输出值。节点 1、2、3 是输入层的节点,所以,他们的输出值就是输入向量本身。按照上图画出的对应关系,可以看到节点 1、2、3 的输出值分别是 $ x_1, x_2, x_3 $。
a 4 = σ ( w T ⋅ a ) = σ ( w 41 x 4 + w 42 x 2 + w 43 a 3 + w 4 b ) a_4 = \sigma(w^T \cdot a) = \sigma(w_{41}x_4 + w_{42}x_2 + w_{43}a_3 + w_{4b}) a4=σ(wT⋅a)=σ(w41x4+w42x2+w43a3+w4b)
其中 $ w_{4b} $ 是节点 4 的偏置项。
同样,我们可以继续计算出节点 5、6、7 的输出值 $ a_5, a_6, a_7 $。
计算输出层的节点 8 的输出值 $ y_1 $:
y 1 = σ ( w T ⋅ a ) = σ ( w 84 a 4 + w 85 a 5 + w 86 a 6 + w 87 a 7 + w 8 b ) y_1 = \sigma(w^T \cdot a) = \sigma(w_{84}a_4 + w_{85}a_5 + w_{86}a_6 + w_{87}a_7 + w_{8b}) y1=σ(wT⋅a)=σ(w84a4+w85a5+w86a6+w87a7+w8b)
其中 $ w_{8b} $ 是节点 8 的偏置项。
同理,我们还可以计算出 $ y_2 $。这样输出层所有节点的输出值计算完毕,我们就得到了在输入向量 $ x_1, x_2, x_3, x_4 $ 时,神经网络的输出向量 $ y_1, y_2 $ 。这里我们也看到,输出向量的维度和输出层神经元个数相同。
1.3 如何计算卷积神经网络输出值?
假设有一个 5*5 的图像,使用一个 3*3 的 filter 进行卷积,想得到一个 3*3 的 Feature Map,如下所示:
$ x_{i,j} $ 表示图像第 $ i $ 行第 $ j $ 列元素。$ w_{m,n} $ 表示 filter 第 $ m $ 行第 $ n $ 列权重。 $ w_b $ 表示 f i l t e r filter filter 的偏置项。 表 a i , j a_i,_j ai,j示 feature map 第 $ i$ 行第 $ j $ 列元素。 f f f 表示激活函数,这里以$ ReLU$ 函数为例。
卷积计算公式如下:
a i , j = f ( ∑ m = 0 2 ∑ n = 0 2 w m , n x i + m , j + n + w b ) a_{i,j} = f(\sum_{m=0}^2 \sum_{n=0}^2 w_{m,n} x_{i+m, j+n} + w_b ) ai,j=f(m=0∑2n=0∑2wm,nxi+m,j+n+wb)
当步长为 1 1 1 时,计算 feature map 元素 $ a_{0,0} $ 如下:
$$
a_{0,0} = f(\sum_{m=0}^2 \sum_{n=0}^2 w_{m,n} x_{0+m, 0+n} + w_b )
= relu(w_{0,0} x_{0,0} + w_{0,1} x_{0,1} + w_{0,2} x_{0,2} + w_{1,0} x_{1,0} + \w_{1,1} x_{1,1} + w_{1,2} x_{1,2} + w_{2,0} x_{2,0} + w_{2,1} x_{2,1} + w_{2,2} x_{2,2}) \
= 1 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 1 \
= 4
$$
其计算过程图示如下:
以此类推,计算出全部的Feature Map。
当步幅为 2 时,Feature Map计算如下
注:图像大小、步幅和卷积后的Feature Map大小是有关系的。它们满足下面的关系:
W 2 = ( W 1 − F + 2 P ) / S + 1 H 2 = ( H 1 − F + 2 P ) / S + 1 W_2 = (W_1 - F + 2P)/S + 1\\ H_2 = (H_1 - F + 2P)/S + 1 W2=(W1−F+2P)/S+1H2=(H1−F+2P)/S+1
其中 $ W_2 ,是卷积后 F e a t u r e M a p 的宽度; , 是卷积后 Feature Map 的宽度; ,是卷积后FeatureMap的宽度; W_1 $ 是卷积前图像的宽度;$ F $ 是 filter 的宽度;$ P $ 是 Zero Padding 数量,Zero Padding 是指在原始图像周围补几圈 0 0 0,如果 P P P 的值是 1 1 1,那么就补 1 1 1 圈 0 0 0; S S S 是步幅;$ H_2 $ 卷积后 Feature Map 的高度;$ H_1 $ 是卷积前图像的宽度。
举例:假设图像宽度 $ W_1 = 5 $,filter 宽度 $ F=3 $,Zero Padding $ P=0 $,步幅 $ S=2 , , , Z $ 则
$$
W_2 = (W_1 - F + 2P)/S + 1
= (5-3+0)/2 + 1
= 2
$$
说明 Feature Map 宽度是2。同样,我们也可以计算出 Feature Map 高度也是 2。
如果卷积前的图像深度为 $ D $,那么相应的 filter 的深度也必须为 $ D $。深度大于 1 的卷积计算公式:
a i , j = f ( ∑ d = 0 D − 1 ∑ m = 0 F − 1 ∑ n = 0 F − 1 w d , m , n x d , i + m , j + n + w b ) a_{i,j} = f(\sum_{d=0}^{D-1} \sum_{m=0}^{F-1} \sum_{n=0}^{F-1} w_{d,m,n} x_{d,i+m,j+n} + w_b) ai,j=f(d=0∑D−1m=0∑F−1n=0∑F−1wd,m,nxd,i+m,j+n+wb)
其中,$ D $ 是深度;$ F $ 是 filter 的大小;$ w_{d,m,n} $ 表示 filter 的第 $ d $ 层第 $ m $ 行第 $ n $ 列权重;$ a_{d,i,j} $ 表示 feature map 的第 $ d $ 层第 $ i $ 行第 $ j $ 列像素;其它的符号含义前面相同,不再赘述。
每个卷积层可以有多个 filter。每个 filter 和原始图像进行卷积后,都可以得到一个 Feature Map。卷积后 Feature Map 的深度(个数)和卷积层的 filter 个数相同。下面的图示显示了包含两个 filter 的卷积层的计算。 7 ∗ 7 ∗ 3 7*7*3 7∗7∗3 输入,经过两个 3 ∗ 3 ∗ 3 3*3*3 3∗3∗3 filter 的卷积(步幅为 2 2 2),得到了 3 ∗ 3 ∗ 2 3*3*2 3∗3∗2 的输出。图中的 Zero padding 是 1 1 1,也就是在输入元素的周围补了一圈 0 0 0。
以上就是卷积层的计算方法。这里面体现了局部连接和权值共享:每层神经元只和上一层部分神经元相连(卷积计算规则),且 filter 的权值对于上一层所有神经元都是一样的。对于包含两个 $ 3 * 3 * 3 $ 的 fitler 的卷积层来说,其参数数量仅有 $ (3 * 3 * 3+1) * 2 = 56 $ 个,且参数数量与上一层神经元个数无关。与全连接神经网络相比,其参数数量大大减少了。
1.4 如何计算 Pooling 层输出值输出值?
Pooling 层主要的作用是下采样,通过去掉 Feature Map 中不重要的样本,进一步减少参数数量。Pooling 的方法很多,最常用的是 Max Pooling。Max Pooling 实际上就是在 n*n 的样本中取最大值,作为采样后的样本值。下图是 2*2 max pooling:
除了 Max Pooing 之外,常用的还有 Average Pooling ——取各样本的平均值。
对于深度为 $ D $ 的 Feature Map,各层独立做 Pooling,因此 Pooling 后的深度仍然为 $ D $。
1.5 实例理解反向传播
一个典型的三层神经网络如下所示:
其中 Layer $ L_1 $ 是输入层,Layer $ L_2 $ 是隐含层,Layer $ L_3 $ 是输出层。
假设输入数据集为 $ D={x_1, x_2, …, x_n} $,输出数据集为 $ y_1, y_2, …, y_n $。
如果输入和输出是一样,即为自编码模型。如果原始数据经过映射,会得到不同于输入的输出。
假设有如下的网络层:
输入层包含神经元 $ i_1, i_2 $,偏置 $ b_1 $;隐含层包含神经元 $ h_1, h_2 $,偏置 $ b_2 $,输出层为 $ o_1, o_2 , , , w_i $ 为层与层之间连接的权重,激活函数为 s i g m o i d sigmoid sigmoid 函数。对以上参数取初始值,如下图所示:
其中:
- 输入数据 $ i1=0.05, i2 = 0.10 $
- 输出数据 $ o1=0.01, o2=0.99 $;
- 初始权重 $ w1=0.15, w2=0.20, w3=0.25,w4=0.30, w5=0.40, w6=0.45, w7=0.50, w8=0.55 $
- 目标:给出输入数据 $ i1,i2 $ ( 0.05 0.05 0.05和 0.10 0.10 0.10 ),使输出尽可能与原始输出 $ o1,o2 $,( 0.01 0.01 0.01和 0.99 0.99 0.99)接近。
前向传播
- 输入层 --> 输出层
计算神经元 $ h1 $ 的输入加权和:
$$
net_{h1} = w_1 * i_1 + w_2 * i_2 + b_1 * 1\
net_{h1} = 0.15 * 0.05 + 0.2 * 0.1 + 0.35 * 1 = 0.3775
$$
神经元 $ h1 $ 的输出 $ o1 $ :(此处用到激活函数为 sigmoid 函数):
o u t h 1 = 1 1 + e − n e t h 1 = 1 1 + e − 0.3775 = 0.593269992 out_{h1} = \frac{1}{1 + e^{-net_{h1}}} = \frac{1}{1 + e^{-0.3775}} = 0.593269992 outh1=1+e−neth11=1+e−0.37751=0.593269992
同理,可计算出神经元 $ h2 $ 的输出 $ o1 $:
o u t h 2 = 0.596884378 out_{h2} = 0.596884378 outh2=0.596884378
- 隐含层–>输出层:
计算输出层神经元 $ o1 $ 和 $ o2 $ 的值:
n e t o 1 = w 5 ∗ o u t h 1 + w 6 ∗ o u t h 2 + b 2 ∗ 1 net_{o1} = w_5 * out_{h1} + w_6 * out_{h2} + b_2 * 1 neto1=w5∗outh1+w6∗outh2+b2∗1
n e t o 1 = 0.4 ∗ 0.593269992 + 0.45 ∗ 0.596884378 + 0.6 ∗ 1 = 1.105905967 net_{o1} = 0.4 * 0.593269992 + 0.45 * 0.596884378 + 0.6 * 1 = 1.105905967 neto1=0.4∗0.593269992+0.45∗0.596884378+0.6∗1=1.105905967
o u t o 1 = 1 1 + e − n e t o 1 = 1 1 + e 1.105905967 = 0.75136079 out_{o1} = \frac{1}{1 + e^{-net_{o1}}} = \frac{1}{1 + e^{1.105905967}} = 0.75136079 outo1=1+e−neto11=1+e1.1059059671=0.75136079
这样前向传播的过程就结束了,我们得到输出值为 $ [0.75136079 , 0.772928465] $,与实际值 $ [0.01 , 0.99] $ 相差还很远,现在我们对误差进行反向传播,更新权值,重新计算输出。
** 反向传播 **
1.计算总误差
总误差:(这里使用Square Error)
E t o t a l = ∑ 1 2 ( t a r g e t − o u t p u t ) 2 E_{total} = \sum \frac{1}{2}(target - output)^2 Etotal=∑21(target−output)2
但是有两个输出,所以分别计算 $ o1 $ 和 $ o2 $ 的误差,总误差为两者之和:
E o 1 = 1 2 ( t a r g e t o 1 − o u t o 1 ) 2 = 1 2 ( 0.01 − 0.75136507 ) 2 = 0.274811083 E_{o1} = \frac{1}{2}(target_{o1} - out_{o1})^2 = \frac{1}{2}(0.01 - 0.75136507)^2 = 0.274811083 Eo1=21(targeto1−outo1)2=21(0.01−0.75136507)2=0.274811083.
E o 2 = 0.023560026 E_{o2} = 0.023560026 Eo2=0.023560026.
E t o t a l = E o 1 + E o 2 = 0.274811083 + 0.023560026 = 0.298371109 E_{total} = E_{o1} + E_{o2} = 0.274811083 + 0.023560026 = 0.298371109 Etotal=Eo1+Eo2=0.274811083+0.023560026=0.298371109.
2.隐含层 --> 输出层的权值更新:
以权重参数 $ w5 $ 为例,如果我们想知道 $ w5 $ 对整体误差产生了多少影响,可以用整体误差对 $ w5 $ 求偏导求出:(链式法则)
∂ E t o t a l ∂ w 5 = ∂ E t o t a l ∂ o u t o 1 ∗ ∂ o u t o 1 ∂ n e t o 1 ∗ ∂ n e t o 1 ∂ w 5 \frac{\partial E_{total}}{\partial w5} = \frac{\partial E_{total}}{\partial out_{o1}} * \frac{\partial out_{o1}}{\partial net_{o1}} * \frac{\partial net_{o1}}{\partial w5} ∂w5∂Etotal=∂outo1∂Etotal∗∂neto1∂outo1∗∂w5∂neto1
下面的图可以更直观的看清楚误差是怎样反向传播的:
1.6 神经网络更“深”有什么意义?
前提:在一定范围内。
- 在神经元数量相同的情况下,深层网络结构具有更大容量,分层组合带来的是指数级的表达空间,能够组合成更多不同类型的子结构,这样可以更容易地学习和表示各种特征。
- 隐藏层增加则意味着由激活函数带来的非线性变换的嵌套层数更多,就能构造更复杂的映射关系。