当先锋百科网

首页 1 2 3 4 5 6 7

03

BP算法推导

3.1 公式1

如下图所示,有个精灵跑到了网络中,假设位于第L层,第 j 个神经元的门口处,它引起了一点扰动,

638118ea70613fd643db51376035b95d.png

49e92c03322bbd7b7528af4a2af504ad.png

z的含义是加权输入项,容易得出这个扰动项对成本函数造成的损失可以定义为:

b71b11f759165f124833a1eb5c78aa41.png

那么,类推的,可以看出在输出层 L, 误差项的定义表达为如下,第一个公式

9341dbf0323b9619459afe1c33c60fe4.png

上式是根据链式规则可以推导得出,成本函数的改变首先是有第L层第j个神经元的输出项影响的,然后第 j 个神经元的输出又受到第 L层第 j 个神经元的干扰 z 影响,因此得到上式。这个式子的意义是定义了第 L层第 j个神经元的误差项怎么求,注意这里L可是输出层哦,那么如何求出第 L-1层中某个神经元的损失项(误差项)呢?

3.2 公式2

这就用到第二个公式,它给出了怎么由第 L层的误差推导出第L-1层的误差,先给出第二个公式:

516cc48a9b18cf1cd28dabaf27b4992c.png

那么,这个公式,是如何得出的呢?这里面,这个公式是相对最难想的,推导过程如下:

还是从损失项的定义入手,

c492e4527fb6cc906acdf8867ab84b13.png

c546c577d78fd7bf974356b268b4a527.png

0c451f6f3056410647aabd76d30f7c05.png

7e4f3b41849af3e50358aa2c80efb5fa.png

由以上这几个式子,就可以得出公式2 。

3.3 公式3

那么有了以上的分析,我们便能求解处任意层的损失项了,可以得出成本函数对某层某个神经元的梯度为,这是第三个公式:

3c4ff05ccd92c10f9d3e2a2993138cbf.png

还是可以由链式规则得出吧,如下推导过程:

9645e439ff19872f255d6c505d4b9c4d.png

3.4 公式4

成本函数对权重参数的梯度为,这是第四个公式:

51e4e73df24ea8110fb1e406f487bcbe.png

那么这个公式还是可以由链式规则得出,对其推导如下:

b9f8ddccab9ba27ad27f49b91c3196a9.png

推导第三,四个公式,都用到了以下这个基本知识:

d9dcd8f237f3ac618df084921e20d0e0.png

3.5 反向传播代码

根据这四个公式,可以得出BP算法的代码,每个步骤将公式放到上面,方便查看。

def backprop(self, x, y):

01 占位

nabla_b = [np.zeros(b.shape) for b in self.biases]

nabla_w = [np.zeros(w.shape) for w in self.weights]

02前向传播求出每个神经元的输出项

activation = x

activations = [x] # 分层存储每层的输出项(对应上文中的 a)

zs = [] # 分层存储每层的 z 向量(对应上文中的 z)

for b, w in zip(self.biases, self.weights):

z = np.dot(w, activation)+b

zs.append(z)

activation = sigmoid(z)

activations.append(activation)

89bfbb531b11b5f6962d80dd987c0e49.png#activations[-1] 必须是最后一层

delta = self.cost_derivative(activations[-1], y) *sigmoid_prime(zs[-1])

03 求偏置量的梯度

04f2785e7fbf1dc66db5bf86ccdfb7e5.png

nabla_b[-1] = delta

04 求权重参数的梯度

2027a3c458dee7ab62f53288bc8e2edd.png

nabla_w[-1] = np.dot(delta, activations[-2].transpose())

05 反向传播,依次更新每层的每个神经元的权重和偏移量

# L = 1 表示最后一层神经元, L = 2 倒数第二层神经元

for layer in range(2, self.num_layers):

z = zs[-layer]

sp = sigmoid_prime(z) #sigmoid函数的导数

e83c979ab0a0fa141190eefde19fea76.png

delta = np.dot(self.weights[-layer+1].transpose(), delta) * sp

nabla_b[-layer] = delta

nabla_w[-layer] = np.dot(delta, activations[-layer-1].transpose())

return (nabla_b, nabla_w)

def cost_derivative(self, output_activations, y):

"""

b71b11f759165f124833a1eb5c78aa41.png

"""

return (output_activations-y)