Deep Learning - 2 反向传播
Created at 2018-05-03 Updated at 2018-05-06 Category Deep Learning
深度神经网络的学习基于两个关键技术:
- Stochastic Gradient Descent
- Backpropagation
利用 SGD 算法学习 Weights 和 Biases,利用 Backpropagation 算法来快速计算 Cost Function 的 Gradient 。
反向传播是一种快速的学习算法,能够让我们深入地了解改变 Weights 和 Biases 的值,是如何改变整个网络的行为的。
Weights
- $W_{jk}^{l}$表示从第 $l-1$ 层的第 k 个神经元,到第 $l$ 层的第 $j$ 个神经元的连接的权重。
Biases and Activations
- $b_j^l$ 表示第 $l$ 层第 $j$ 个神经元的 Biases
- $a_j^l$ 表示第 $l$ 层第 $j$ 个神经元的 Activations(激活值)
神经元的视角
每个神经元的激活值可以这样表示:
$$
a_j^l = \sigma \left(\sum_k w_{jk}^{l} a_{k}^{l-1}+b_{j}^{l}\right)
$$
层视角
通过使用矩阵:
- 每一层 $l$ 定义一个权重矩阵 $w^l$ ,$w^l$ 中的第 $j$ 行第 $k$ 列的元素就是 $w_{jk}^{l}$ 。
- $b^l$ 代表第 $l$ 层的 Biases 向量。
- 将 $\sigma$ 函数向量化,即对向量 $v$ 中的每一项,都单独地应用 $\sigma$ 函数,记为 $\sigma(v)$ 。
- $a^l$代表第 $l$ 层的神经元的激活值向量。
每层的激活值可以这样表示:
$$
a^l = \sigma ( w^l a^{l-1} + b^l )
$$
- 将权值矩阵作用于上一层的激活值
- 然后加上偏置向量
- 最后用 $\sigma$ 函数作用于这个结果
- 就得到了本层的激活值
Weighted Input
$z^l \equiv w^l a^{l-1} + b^l$ ,$z^l$ 成为对第 $l$ 层神经元激活函数的加权输入。
$$
a^l = \sigma (z^l)
$$
Cost Function 的两个假设
MSE代价函数:
$$
C = \frac{1}{2n} \sum_x ||y(x)-a^L(x)||^2
$$
- n是训练样本数量
- $\sum_x$是对每个独立训练样本 $x$ 求和
- $y=y(x)$ 是每个独立训练样本 $x$ 的预期输出结果
- $L$ 是神经网络的层数
- $a^L = a^L (x)$是输入为 $x$ 时网络的激活函数的输出向量
为了能够使用反向传播,我们需要对代价函数C进行两个假设。
假设一
假设代价函数能够写成这样的形式
$$
C = \frac{1}{n} \sum_x C_x
$$
- $C_x$ 是每个独立训练样本 $x$ 的代价函数。
当代价函数是MSE时,$C_x = \frac{1}{2} ||y-a||^2$ 。
假设二
假设代价函数可以写成关于神经网络输出结果的函数。
MSE代价函数满足这个要求,因为单一训练样本x的二次代价可以表示为:
$$
C = \frac{1}{2} ||y-a^L||^2 = \frac{1}{2} \sum_j ( y_j - a_j^L )^2
$$
因为输入的训练样本 x 是固定的,所以期望的输出 y 也是固定的。x 和 y 不是神经网络所学习的东西,我们不能通过改变 Weights 和 Biases 来修改它。
所以这里可以把 C 视为是只关于输出 $a^L$ 的函数。
Hadamard Product
反向传播会用到 Hadamard Product ,假设 s 和 t 两个向量有相同的维数
$$
( s \odot t )_j = s_j t_j
$$
其中,$s \odot t$ 表示两个向量的对应元素相乘
反向传播背后的四个基本等式
$$
\delta^L = \nabla a C \odot \sigma’(z^L) \
\delta^l = ((w^{l+1})^T \delta^{l+1}) \odot \sigma’ (z^l) \
\frac{\partial C}{\partial b_j^l} = \delta_j^l \
\frac{\partial C}{\partial w_{jk}^l} = a_{k}^{l-1} \delta_j^l
$$
反向传播算法
输入一组训练数据
对于训练数据中的每个样本 x
计算输入层的激活函数值 $a^{x,1}$,并执行下面的步骤:
Feedforward(正向传播)
计算样本x在每一层的激活函数值 $a^{x,l}$
$$
l=2,3,\dots ,L \
z^{x,l} = w^l a^{x,l-1} + b^l \
a^{x,l} = \sigma ( z^{x,l} )
$$
输出层的误差
计算样本x在输出层的误差向量
$$
\delta^{x,L} = \nabla_a C_x \odot \sigma’ ( z^{x,L} )
$$
将误差反向传播
使用输出层的误差,计算样本x在之前每一层的误差
$$
l = L-1,L-2,\dots ,2 \
\delta^{x,l} = (( w^{l+1} )^T \delta^{x,l+1} ) \odot \sigma’( z^{x,l} )
$$
Gradient Descent
使用样本x在每一层的误差,更新 Weights 和 Biases
$$
l = L,L-1,\dots,2 \
w^l \rightarrow w^l - \frac{\eta}{m} \sum_x \delta^{x,l} (a^{x,l-1})^T\
b^l \rightarrow b^l - \frac{\eta}{m} \sum_x \delta^{x,l}
$$
反向传播算法的实现
初始化网络
1 | self.num_layers = len(sizes) |
对于5层的神经网络,初始化后 Weights 和 Biases 的结构如下
1 | size = [748, 40, 30, 20, 10] |
随机梯度下降
随机
1 | def SGD(self, training_data, epochs, mini_batch_size, eta, |
梯度下降
1 | def update_mini_batch(self, mini_batch, eta): |
反向传播
1 | def backprop(self, x, y): |
反向传播算法为什么更高效
待更新
反向传播整体描述
我们对 $w_{jk}^{l}$ 作出一个小的改变$\triangle w_{jk}^l$
这个改变量会导致与它相连的神经元的输出激活值改变
然后,这个激活着会影响下一层的所有激活值
这样一层一层地,最终引起代价函数的改变,并且这个改变我们可以算出。