前言
转行到现在已经三周了,前两周都是在做opencv相关的图像处理的内容,后面有幸参与神经网络的一些具体实现。在这个过程中使用了面向向量编程,正好之前这里还留了一坑,今天给补上。顺带再加点mini-batch小批量梯度下降的知识。
上篇DL算法学习之3中已经实现了传统版本的全联接神经网络,当然了,反向传播那里现在发现顺序没有采用倒序,这个没看到的童鞋留意下,而且那个实现是随机梯度下降,跟这里有所不同。
对于一个数学问题来讲,一般都是有多种解法。一种是常用的模拟法,比如从1加到10000,可以用1+2+3+…+10000。上一篇中就是模拟法,模拟神经网络中的神经元,连接,数据传输过程。另外一种就是公式法,1加到10000,有个快速公式(1+10000)*10000/2。很明显,第二种方式快得多,而且简单高效。
作者提出了一种面向向量编程就是第二种啦,可以对网络进行优化,提升运算速度,来尝试一下。
正文内容
1 面向向量编程
回顾一下上一篇的神经网络,其实对于它而言,无非就是两步:
一个前向传播得到各层输出y和最后的误差E
一个反向传播更新各层权重w和偏置项b
最终使得误差E最小。
如果采用向量编程,一次对一层进行计算,很显然前一节的神经元节点就没了,模仿一下tensorflow的做法,抽象一个层出来:
如上图所示,该网络由layer0(input=3,output=6),layer1(input=6,output=4) (input=4,output=1),layer2三个全连接层实现。为了解耦,这里不在层里实现激活,激活将由单独的激活层实现。
2 全连接层的正向传播
接下来就简单了,对于layer1而言:
正向传播就是将上一层layer0的输出作为本层的输入,如果是随机梯度下降,就只计算一个样本,它的维度是(6,1),而在本层内部进行全连接6个输入,最终产生4个输出,输出的维度是(4,1) , 这个过程中会产生 6x4 = 24条权重,为了计算方便,令其维度为(4,6)
当然我们现在讨论的不是单个样本了,而是小批量梯度下降算法。假设一次批量计算m个样本,那么对于layer1而言,它的输入维度将会由(6,1)扩展为(6,m) ,输出维度扩展为(4,m) , 因为m个样本计算过程中共享权重,其维度不变,为(4,6),如下图所示:
用X代表input,
S
i
S_i
Si代表input的维度,它是一个(
S
i
S_i
Si , m)的张量,如下所示
用Y代表output,
S
o
S_o
So代表output的维度,它是一个(
S
o
S_o
So , m)的张量,如下所示
用W代表所有权重,为了方便计算,用
w
j
w_j
wj
i
_i
i表示第j个输出和第i个输入间的权重
(j=1,2,…,
S
o
S_o
So ; i=1,2,…,
S
i
S_i
Si ),它是一个(
S
o
S_o
So ,
S
i
S_i
Si )的张量
对于第j个输出的第k个样本是所有输入的第k个样本的加权和
即W的行向量与X的列向量做内积
当然考虑偏置项的话在后面再加个b向量就好了。这个过程如果用python里面的numpy做运算,将会异常简单。
3 全连接层的反向传播
当抽象出这个全连接层的时候,发现对于神经网络一下子就清晰了:
1)正向过程就是通过上一层的拿到的X,求出本层Y,然后Y将传给下一层做为输入
2)反向过程也异常简单:
2-1 通过下一层反向拿到
d
J
d
Y
\frac {dJ}{dY}
dYdJ
2-2 计算出
d
J
d
X
\frac {dJ}{dX}
dXdJ反向传给上一层作为
d
J
d
Y
\frac {dJ}{dY}
dYdJ
2-3 如果还需要其他变量计算就计算一下,比如全连接层需要更新W,就需要计算
d
J
d
W
\frac {dJ}{dW}
dWdJ
完毕,是不是 so easy ,其他乱七八糟的符号通通走开,看的我头晕。
下面进行推导:
2-1 损失对输出的偏导
d
J
d
Y
\frac {dJ}{dY}
dYdJ,由下一层反向传播过来
Y是(
S
o
S_o
So , m)维度的张量,J是标量,所以
d
J
d
Y
\frac {dJ}{dY}
dYdJ 是(
S
o
S_o
So , m)的张量,这个大家可以查下标量对矩阵求导公式
2-2 损失对输入的偏导
d
J
d
X
\frac {dJ}{dX}
dXdJ
同理,
d
J
d
X
\frac {dJ}{dX}
dXdJ是(
S
i
S_i
Si , m)维度的张量
对于第i个输入的第k个样本会对所有输出的第k个样本 (j=1,2,…, )产生影响。
所以标量
这个结果太规则了,可能可以用矩阵求导公式来解决,这里先不讨论
2-3 计算其他变量
由于需要更新权重,还得求这个
小结
实践出真知这话完全有道理,想要理解透彻还得动手去算。至于代码就不贴了,照着公式算一遍就over了,这个简单。这个过程中还研究了batch-normalization,这真是个神器,对于加速收敛和防止梯度弥散或爆炸有神效,有兴趣的可以研究一下。