基于矩阵的反向传播

xgxyxs 2018-07-25

反向传播是神经网络训练中常用的一种方法,它是通过对每一层的权值进行调优来实现输出误差的反向传播,从而使损失函数最小化。

在本文中,我将用小批量表示反向传播的矩阵方法,以及它如何加强神经网络的学习;我还将把这种方法与在小批上循环进行比较,然后解释小批处理大小如何影响学习速度和准确性。

简介:

实际上,小批量梯度下降是梯度下降的一种变体,它在处理(feed-forwarding/back- propagation)一系列训练数据后更新权重。所处理的示例数量称为“mini-batch size”,是需要优化的神经网络的超参数之一,因为我们将看到,这个大小的值会影响学习的速度和准确性。

给定一个具有多个示例(n)的mini-batch,循环方法包括循环该小批量,通过feed-forwarding然后一次back propagating 一个示例。因此,我们需要(n)次迭代来处理mini-batch的所有示例。

对于矩阵方法,我们将同时对所有示例进行 feed-forward/back-propagate。因此,只有一次迭代就足以处理所有的小批处理示例。

基于矩阵的反向传播

符号:

在进一步讨论之前,我们将指定一个符号来帮助我们引用神经网络的组件。我们以这个包含4个神经元的隐藏层、3个神经元的输入层和2个神经元的输出层的网络为例:

基于矩阵的反向传播

我们通过以下方式表示权重,偏差和激活:

基于矩阵的反向传播

因此,属于层(1)的神经元(j)的激活可以用以下方式写入(其中σ是激活函数):

基于矩阵的反向传播

方程-1

基于矩阵的Feed-Forwarding:

如果我们指定每层的权重矩阵(W l ),则等式-1可以以矩阵形式重写,其中(w jk )是矩阵的行号(j)和列号(k)上的元素。给定层(l)的权重矩阵乘以前一层(l-1)的激活的向量(A),乘法的结果被加到属于该层的偏差(B)的向量中。(l)最后,激活函数应用于结果向量的每个元素。通过在我们的神经网络上应用这个等式(1)等于3的等式,我们得到:

基于矩阵的反向传播

方程-2

为了简化方程式,我将插入向量(B)作为权重矩阵的第一列,并将(1)作为向量(A)的第一个元素插入,就像偏差正在扮演权重的角色一样相应的激活总是等于1:

基于矩阵的反向传播

方程-3

实际上,我所展示的是前馈传播,但一次只有一个例子。我们想要做的是同时提供大量的例子,以加快学习速度。为此,不是将权重矩阵乘以一个激活矢量,而是将其乘以矩阵(X),其中每列表示对应于一个示例的激活矢量。后一个矩阵的列数是我们想要一次输入的示例数,换句话说,就是mini-batch size。如果我们选择一个等于4的小批量大小作为示例,该方程-3成为:

基于矩阵的反向传播

基于矩阵的反向传播:

现在我们已经了解矩阵方法如何用于前馈传播,我们可以以相同的方式攻击反向传播:我们通过乘以权重矩阵一次前馈多个示例,然后返回 - 传播误差,始终遵循矩阵方法。为此,我们必须以矩阵形式重写反向传播的四个基本方程(见下图):

基于矩阵的反向传播

对于所表示的输出层(L) ,我们写出方程BP1中,如下图,其中该矩阵的每个元素(G)是成本函数的导数(C)相对于所述激活(a)中,在这里我们正利用二次代价函数,因此导数等于(aji-yji),其中(yji)是对应于输出神经元(j)和示例(i)的标签。

对于矩阵(S),每个元素是相对于(Zij)的激活函数的导数。

得到的矩阵(D)的每个元素对应于 输出神经元(j)和示例(i)的Δ 。

基于矩阵的反向传播

BP1:矩阵形式

现在,对于表示为(l)的隐藏层,我们将来自于层(l + 1)的加权矩阵的转数乘以来自相同层的矩阵(D),得到的结果是使用Hadamard乘积乘以层(l)的矩阵(S)。BP2的方程是

基于矩阵的反向传播

BP2

考虑到所有这些,方程式BP3和BP4很容易导出

Matrix VS Loop方法:

为了测试循环方法,我将运行数字识别程序,并 计算程序完成每个epoch所经过的秒数,以及测试的准确性数据。至于矩阵方法,我将运行相同代码的修改版本,其中我已经实现了矩阵形式(https://github.com/hindkls/Matrix-Based-Backpropagation/blob/master/Network1.py)。

神经网络从MNIST的训练数据中学习,它有784个输入神经元,10个输出神经元和30个神经元的隐藏层。通过将我们的程序设置为运行超过30个epochs,学习率为η= 3.0且小批量大小为10,我们得到以下结果:

循环方法:

Looping over a mini-batch of size 10

--- 34.2879998684 seconds elapsed ---

Epoch 0: 9114 / 10000

--- 27.7209999561 seconds elapsed ---

Epoch 1: 9192 / 10000

--- 33.2569999695 seconds elapsed ---

Epoch 2: 9289 / 10000

...

--- 36.6579999924 seconds elapsed ---

Epoch 28: 9496 / 10000

--- 34.5559999943 seconds elapsed ---

Epoch 29: 9486 / 10000

矩阵方法:

Matrix approach with a mini-batch of size 10

--- 11.6560001373 seconds elapsed---

Epoch 0: 9090 / 10000

--- 11.375 seconds elapsed---

Epoch 1: 9273 / 10000

--- 11.4839999676 seconds elapsed---

Epoch 2: 9322 / 10000

...

--- 12.0789999962 seconds elapsed---

Epoch 28: 9486 / 10000

--- 11.3129999638 seconds elapsed---

Epoch 29: 9503 / 10000

通过比较结果,我们可以看到,使用矩阵方法处理每个epoch所经过的平均秒数远小于使用循环方法所花费的时间。这是因为矩阵方法利用CPU和GPU中的并行性来加速计算。实现神经网络的库使用相同的方法,因为线性代数库现在针对快速硬件进行了优化。

Mini-batch size

在本节中,我们将使用不同的Mini-batch size的值来看一下,看看它如何影响学习。为此,我们运行我们的程序(具有矩阵形式的程序)进行两次试验,第一次使用Mini-batch size等于1,第二次使用Mini-batch size等于600。

第一次:

Mini-Batch size = 1

--- 78.3759999275 seconds elapsed---

Epoch 0: 7669 / 10000

--- 81.4859998226 seconds elapsed---

Epoch 1: 8382 / 10000

--- 85.0969998837 seconds elapsed---

Epoch 2: 8311 / 10000

...

第二次:

Mini-Batch size = 600

--- 63.4069998264 seconds elapsed---

Epoch 0: 4206 / 10000

--- 67.6930000782 seconds elapsed---

Epoch 1: 5712 / 10000

--- 68.2200000286 seconds elapsed---

Epoch 2: 6570 / 10000

...

正如我们在这里看到的,当我们运行一个小批量大小为600的程序时,学习速度要比当大小为1时快一些,但是准确度较低。这种行为背后的原因是,在第一次试验中,权重的更新比第二次试验要频繁得多,因为它们是在处理完每个例子之后更新的,而在第二个试验中,直到所有600个例子都被处理后,权重才会更新。那么我们该怎么做呢?我们是否应该选择一个小的小批量尺寸并赢得准确性?还是用一个大的小批量生产,赢得速度却失去精度?

我们需要做的,是找到一个速度和精度之间的折中的mini-batch size值,太小,我们不利用快速矩阵乘法,太大,我们不经常更新我们的权重。

现在,您可能认为学习速度与准确性并不重要,因为最终我们将达到良好的准确度,但请看一下我们运行的程序的结果是mini-batch size为10,你可以看到只要在第一个epoch,精度达到了90%,即权重没有比大小等于1时更新很多。这与我们早先得出的结论并不矛盾。原因在于,当我们选择一个小型批次大小等于1时,由于它对每个示例的影响都作出了响应,因此这种学习是最不明显的。这就是为什么选择一个优化良好的mini-batch size,一方面可以帮助我们快速地收敛到一个好的最小值,因为我们确信权重是经常更新的,但是是以一种合理的方式更新的,另一方面可以利用快速矩阵库。

相关推荐