神经网络与深度学习小结 (二)

神经网络与深度学习

Posted by sunlianglong on March 5, 2018

(BP)反向传播算法

  我感觉,神经网络中的反向传播算法(BP)在整个神经网络的学习过程中是很重要的内容,是基础中基础。学过一段时间后,再回过头来重新总结,希望自己能有意外的收获。

  反向传播是通过递归应用链式规则来计算表达式的梯度的一种方式,它可以非常容易地泛化到任意一个有向图的计算上去。其实也就是因为在计算梯度时,由于每个隐层节点与输出层多个节点之间均有关联,所以会对其上一层所有的Error作累加处理。反向传播的另一个优势是计算同层节点的梯度和权重更新时可以并行进行,因为它们之间不存在关联关系。

  但是根据梯度函数,反向传播会存在全局最小和局部极小的问题。在大多数情况下BP神经网络给出的只是一个局部的最优解,而不是全局的最优解。详细内容可以查看《机器学习》(周志华)P106页。

  如何计算复杂函数的梯度,计算图提供了一个比较直观的展示方法,下面是一个比较简单的反向传播计算图的例子。

  假设:f(x,y,z) = (x + y) z , [初值x=-2,y=5,z=-4,以绿色字体表示],设q = x + y,则 f = q*z,那么f对于其他各个变量的梯度计算方法如下。

# set some inputs
x = -2; y = 5; z = -4

# perform the forward pass
q = x + y # q becomes 3
f = q * z # f becomes -12

# perform the backward pass (backpropagation) in reverse order:
# first backprop through f = q * z
dfdz = q # df/dz = q, so gradient on z becomes 3
dfdq = z # df/dq = z, so gradient on q becomes -4
# now backprop through q = x + y
dfdx = 1.0 * dfdq # dq/dx = 1. And the multiplication here is the chain rule!
dfdy = 1.0 * dfdq # dq/dy = 1

  用计算图(也可以说是电路图)表示如下。前向传播(绿色)完成以后,执行反向传播,各个点的梯度值勇红色表示,梯度可以被认为是通过电路的回流。

-2-4x5-4y-43z3-4q+-121f*

  在反向传播中,当我们到达每一个节点时,这个节点都会得到一个从上游返回的梯度,这个梯度是对这个节点的输出的求导,也就是上游梯度值*本地梯度值。来得到该节点的输入梯度值。例如对于节点x的梯度为:

$$ \frac{\partial f}{\partial x} = \frac{\partial f}{\partial q} \frac{\partial q}{\partial x} $$

  另一个计算图的例子如下:

  我们使用计算图时,我们可以以我们想要的任意间隔尺寸来定义/计算节点。还有,神经网络中有最常用的三个门(add,mul,max),在反向传播过程中它们的行为方式都有非常简单的解释。

  • Add gate:gradient distributor (分发器)Add gate始终把它输出的梯度,同样将其分配给它的所有输入。
  • Max gate:gradient router (路由器)
  • Mul gate:gradient switcher (转换器)

如果是发散式的计算图,那就可以采用多元链式法则来计算梯度,如多元Add gate:

当将输入值转化成向量时,计算反向传播推导公式如下:

模块接口举例

1.Foeward/acckword API
class ComputationalGraph(object):
	def forward(inputs):
		#1.[pass inputs to input gates]
		#2.forward the computational graph:
		for gate in self.graph_nodes_topolpgically_sorted():
			gate.forward()
		return loss #the final gate in the graph outputs the loss
	def backward():
		for gate in reversed(graph_nodes_topolpgically_sorted()):
			gate.backward() #little piece of backprop(chain rule applied)
		return inputs_gradients
2.Mul Gate API
class MultiplyGate(object):
	def forward(x,y):
		z = x * y
		self.x = x #must keep these around
		self.y = y
	def backward(dz):
		dx = self.y * dz
		dy = self.x *dz
		return [dx,dy]