一、概述
上一集结束之后,学到了score function
,可以用SVM
或者Softmax
计算loss
,可以在loss
中增加regularization
来获取更加合理的W
,并且最后可以用Analytic Gradient
(微积分)的方式计算loss function
相对于W
的gradient
来更新W
。如下图。
这一集讲了如何使用链式法则
来反向传播gradients
,来更新W
和b
,这个gradients
反向传播的过程叫做Backpropagation
。
Backpropagation
之后,进入了Neural Network
的介绍。
二、Backpropagation
- Computational Graph 在计算
gradient
并进行backpropagate(bp)
的时候,借助computational graphs(cg)
可以让整个过程更加清晰(对于新手来说更是这样)。在学习的起步阶段,可以借助它来理解bp
的原理。但是当神经网络复杂了之后,再转换成cg
看起来就很头疼了。就像这样。tensorboard
是cg
可视化的一个很强大的工具。 一个computational graph
是对整个神经网络的直观图形表述。 上图中,每一个矩形代表着input x
和W
;每一个圆代表着一个操作;箭头指明了元素在这个神经网络中的流向,从输入开始,一直到最终的loss
输出。 其中,圆被称为一个门gate
。数据每流经一个门,都会经过相应的数学变换。 bp
如何实现 上图已经完成了forward pass
的过程,输入从左到右,经过+
,*
,得到结果f
。 上图中有三个输入,x,y,z
;一个+ gate q
;一个* gate f
;最后得到输出f = 12
。 红色框中,是+
这个操作相对于x
,y
的求导; 蓝色框中,是*
这个操作相对于+
,z
的求导;bp
的过程,就是将运算顺序倒过来,从cg
的最右端开始,利用链式法则(Chain Rule),依次将所有前面已经计算的到的导数,和当前元素的导数相乘,就是当前元素的gradient
。 从最右端开始,f
相对于自身的导数是1
。如下图: 继续往左运算,遇到了* gate
;这个门的算式就是f = qz
,蓝色框中的算式。 要求出z
的gradient
,就是将之前已经计算出的gradient df / df = 1
,与z
本身的gradient
相乘,即(df / df) * (df / dz)
。 先求f
相对于z
的导数,df / dz = q
; 由于q = 3
,因此,z
的gradient df / dz = (df / df) * q = 3
。 这个3
意味着,z
的变化对于f
是正向的。如果z
增加任意H
个单位,那么f
相应增加3H
个单位。 计算结果如图。 下面计算q
的gradient df / dq
。 蓝色框中已经写了,df / dq = z
,并且z = -4
。 因此,df / dq = (df / df) * z = -4
。如图。 接下来计算x
的gradient
。 根据Chain Rule
,x
的gradient df / dx = (df / dq) * (dq / dx)
。 因此,df / dx = -4 * 1 = -4
。如图。 点击去看Khan Academy
对于Chain Rule
的讲解。 以此类推,y
的gradient
也就能计算出来了。 下图展示了bp
的一个简易流程。 图中,x
,y
,f
,z
各是一个节点,称之为node
,每个node
在python中是一个class
。当x
和y
流经f
的时候,f
这个node
已经知道自身相对于x
的gradient
了,这个gradient
叫做local gradient
。在这个简单的网络作forward propagate
的时候,node f
就再已经保存了df / dx
的信息,比如,存放在变量self.local_gradient
中,便于之后back propagate
的时候取出来使用。 而bp
的整个过程,就是最右边开始,把每个节点的local gradient
拿出来,与处于该节点右边的所有节点的local gradient
相乘,就是该节点的最终gradient
。z
节点右边没有节点了,因此z
节点的local gradient
就是dz / dz = 1
,存在self.local_gradient
中。x
节点的gradient
就可以根据f.local_gradient * z.local_gradient
来得到。 问题:如果一个节点被多个节点使用,这个节点的gradient
如何计算?如下图,如果一个节点被多个节点使用,这个节点的gradient = local gradient + sum(all_previous_gradients)
左边的节点作为输入被之后的两个节点使用,那么在back propagate
的时候,右边两个节点的gradient
要加起来,再乘以左边节点的local gradient
才能得到左边节点最终的gardient
。 下图是forward pass
和back propagate
的一个简单python实现。 在实践中,在数学允许的情况下,多个gate
可以被合并成一个gate
,那么之前多个gate
的gradient
的计算,可以合并到这一个gate
中进行计算。如下面两张图。 上图中,所有的gradient
都是一个一个依次计算的。但那是其中4
个gate
可以合并。 上图中,蓝色框中的多个gate
,可以组合成一个sigmoid gate
,那么其中4
个单独gate
的gradient
计算可以合并成一个sigmoid gate
的gradient
计算,其结果不变。- 乐高积木 上图看的不是很清楚,大意就是,
Torch
的Git repo
中可以看到,这个框架就是一大堆神经网络的layer
集合。所以,玩深度学习,玩神经网络,就像是玩乐高积木一样,把自己需要的积木块(layer
)拿出来,拼接在一起,最后组成一个能完成任务的结构。 同样的情况在Caffe
框架中也能看到。 - Gradients for vectorized code以及Vectorized operations 这一小节关于
Jcobian matrix
以及Vectorized operations
不是很懂,还需要再查资料体会一下。 视频中说到了Jacobian matrix
会是一个维度很高的matrix,实践中是不会去算出整个Jacobian matrix
的。Jacobian matrix
在max()
作为activation function
的时候,又有一种特殊的结构,就是只有左上到右下对角线上才有值,可能是0,可能是非0,而其他值都是0。 不是很明白为什么说Vectorized operations
效率很高,同时提到这个Jacobian matrix
是为了什么…
三、神经网络(Neural Network)
这里讨论的神经网络和大脑的神经网络有一些联系,就是计算机神经网络借鉴了一些大脑神经元的工作原理。但是其复杂度是无法相提并论的,大脑神经元的复杂度远高于计算机神经网络。
- 更加复杂的神经网络 所有之前涉及的内容,是一个最简单的一层神经网络
f = Wx
。如下图。 下面,就可以再进一步,增加复杂度,构造一个2层神经网络
。 上图中,2层神经网络
将max activation function
变成了一个hidden layer
。在这个hidden layer
之后,再和W2
作运算,得到一个Output
。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HjMwMTIK-1587400552234)(http://img.blog.csdn.net/20170518181228612?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVpc2VqaXVodWNoZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)] 上图中,hidden layer
有100
个神经元neuron
,这会使这个神经网络比起之前简单的版本要强大很多。比如说在下图中: 记得对之前简单的Linear Classification
进行训练之后得到的这些模板,汽车和马的模板会出现不同的朝向和颜色问题。因为一层的神经网络不能处理不同的颜色,不同的朝向。这个问题在增加hidden layer
和大量的神经元之后就能得到进一步的解决。 每个神经元neuron
的作用就是细分前面输入的数据。比如说,一个神经元可以专门检测红色的,朝向前的汽车;一个神经元可以专门检测黄色的,朝向右边的汽车;以此类推。那么这个神经网络有具备了分类各种颜色和朝向汽车的能力。 在hidden layer
中的每个神经元,可以看作是一个简单的Linear Classifier
。多个神经元组合在一起,就可以学习很复杂的模型。 只需要通过扩展下图中的公式,就能构造层数更多,更加复杂的神经网络。 合理的数学编排,可以解决现实生活中很复杂的问题。 - 2层神经网络的简单Python实现 上图是Andrew Trask对2层神经网络的实现,其中用的是
logistic loss
,没有使用SVM
或者Softmax
,但是原理是一样的。 - 编排神经网络 经过编排的神经网络看起来是这样的,中间的
hidden layer
和最后的output layer
被称作fully-connected layers
。 问题:为什么要将神经网络编排成这个样子?像这样将神经网络组织成层是为了更高效率的计算(Vectorized operation
),输入只需要按照编排好的顺序一层一层流过所有的层即可,不需要额外考虑任何的顺序等因素。 - 不同的neuron数量和regularization时lambda的值
hidden layer
中的neuron数量,差不多就像regularization function
中的lambda
的值一样,被当作hyper parameter
来调整。 一般来说,neuron的数量越多越好。neuron越多,这个神经网络越强大。如下图。 上图中,neuron数量越多,分类的效果越好。 但是考虑到时间成本等因素(越多的neuron训练时间相应就越长),找到一个平衡点上的neuron数量才是最好的。 另外,可以看到regularization
时的lambda
的值,也影响着最后的分类效果。如下图。 在当前情况下,lambda
的值越小,分来效果也就越好。 点击这里去玩Andrej写的神经网络分类的Demo。
四、总结
到这里,已经知道如何进行反响传播backpropagation
。
知道能将神经网络编排成层。
这些层的编排,可以让vectorized operation
很方便的进行。
知道了神经网络并不是大脑中的神经网络。
通常情况下,神经网络越复杂,越强大。但是复杂的神经网络意味着更长的训练时间和更小心的规范化(regularization
)。