nndl学习笔记(一)反向传播公式总结

本文介绍了反向传播算法的基本概念,包括定义、公式及其在神经网络中的应用。详细解释了四个基本方程,并提供了Python实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

nndl是什么?

《神经网络与深度学习》(《Neural Network and Deep Learning》)是机器学习大神
Michael Nielsen介绍神经网络入门的一本教材,英文地址:http://neuralnetworksanddeeplearning.com/在此感谢译者Xiaohu ZhuFreeman Zhang。有对机器学习和神经网络有关内容感兴趣的读者,点这里获取相关资源。
P.S.: 本文仅对该书第二章进行总结,其中的描述会不全面,想详细了解请点击链接下载学习。
1

反向传播算法简介

反向传播算法(Backpropagation Algorithm),最初在二十世纪70年代被提出,但真正得到重视是在1986年。反向传播被应用于计算损失函数(代价函数)的梯度,具有稳定、速度快等特点。

定义&公式

权重(Weight) w j k l : w_{jk}^{l}: wjkl: 代表从 ( l − 1 ) t h (l-1)^{th} (l1)th层的第 k t h k^{th} kth 个神经元到 l t h l^{th} lth 层的第 j t h j^{th} jth 个神经元的连接上的权重(注意 j j j k k k 代表的意义从位置上看是反过来的,这样做是为了方便矩阵乘积直接计算而不用进行转置操作,一开始不太好理解;还有上面的层数 l l l 指的是到达层的位置,故前一层 ( l − 1 ) t h (l-1)^{th} (l1)th 需要减去 1 1 1)。

偏置(Bias) b j l : b_{j}^{l} : bjl: 表示在第 l t h l^{th} lth 层第 j t h j^{th} jth 个神经元的偏置(有种把坐标系的x,y竖起来的感觉)。

带权输入 z j l z_j^l zjl:中间变量,表示 l l l层第 j j j个神经元的带权输入,即:
z j l = ∑ k w j k l a k l − 1 + b j l . z_j^l=\sum_kw_{jk}^la_k^{l-1}+b_j^l. zjl=kwjklakl1+bjl.

误差(Error) δ j l : \delta_j^l: δjl:中间量,表示 l t h l^{th} lth层第 j t h j^{th} jth个神经元上的误差。

Hadamard 乘积 s ⊙ t : s \odot t : st: 矩阵或向量的对应元素相乘,即 ( s ⊙ t ) j = s j t j (s \odot t)_j=s_jt_j (st)j=sjtj

激活函数(Activation Function) Sigmoid函数 : : : σ ( z ) = 1 1 + exp ⁡ ( − z ) , \sigma(z)=\frac{1}{1+\exp(-z)}, σ(z)=1+exp(z)1,其导数可表示为: σ ′ ( z ) = σ ( z ) ( 1 − σ ( z ) ) \sigma'(z)=\sigma(z)(1-\sigma(z)) σ(z)=σ(z)(1σ(z))

激活值(Activation) a j l : a_{j}^{l} : ajl: 表示第 l t h l^{th} lth 层第 j t h j^{th} jth 个神经元的激活值,由激活函数定义可记为: a j l = σ ( z j l ) a_j^l=\sigma(z_j^l) ajl=σ(zjl)

l t h l^{th} lth 层的第 j t h j^{th} jth 个神经元的激活值 a j l a_j^l ajl l t h l^{th} lth 层的激活值之间的联系:

a j l = σ ( z j l ) = σ ( ∑ k w j k l a k l − 1 + b j l ) . a^l_j = \sigma(z_j^l)= \sigma\left(\sum_kw^l_{jk}a^{l−1}_k+b^l_j\right). ajl=σ(zjl)=σ(kwjklakl1+bjl).

a l = σ ( w l a l − 1 + b l ) . a^l = \sigma(w^la^{l-1}+b^ l). al=σ(wlal1+bl).

二次代价函数(Cost Function) :

C = 1 2 n ∑ x ∣ ∣ y ( x ) − a L ( x ) ∣ ∣ 2 . C=\frac{1}{2n}\sum_x{||y(x)-a^L(x)||^2}. C=2n1xy(x)aL(x)2.

基本思想

反向传播的目标是计算代价函数 C C C分别关于权重 w w w和偏置 b b b的偏导 ∂ C / ∂ w \partial C/\partial w C/w ∂ C / ∂ b \partial C/\partial b C/b 。为了使反向传播算法可以正常工作,我们需要做两个主要假设如下。

  • 第一个假设:代价函数可以被写成一个在每个训练样本 x x x上的代价函数 C x C_x Cx的均值 C = 1 n ∑ x C x = 1 n ∑ x 1 2 ∣ ∣ y − a L ∣ ∣ 2 C=\frac1n\sum_x{C_x}=\frac1n\sum_x{\frac12||y-a^L||^2} C=n1xCx=n1x21yaL2。其原因是反向传播实际上是对一个独立的训练样本计算 ∂ C x / ∂ w \partial C_x/\partial w Cx/w ∂ C x / ∂ b \partial C_x/\partial b Cx/b ,然后我们通过在所有训练样本上进行平均化获得 ∂ C / ∂ w \partial C/\partial w C/w ∂ C / ∂ b \partial C/\partial b C/b
  • 第二个假设:代价函数可以写成神经网络输出的函数,例如:
    C = 1 2 n ∑ x ∣ ∣ y ( x ) − a L ( x ) ∣ ∣ 2 = 1 2 ∑ j ( y j − a j L ) 2 C=\frac{1}{2n}\sum_x{||y(x)-a^L(x)||^2}=\frac12\sum_j{(y_j-a^L_j)^2} C=2n1xy(x)aL(x)2=21j(yjajL)2

Back Propagation四个基本方程

  1. 输出层的误差(注意输出层使用大写L记号) δ j L = ∂ C ∂ a j L σ ′ ( z j L ) \delta_j^L=\frac{\partial C}{\partial a_j^L}\sigma'(z_j^L) δjL=ajLCσ(zjL)矩阵表示:
    δ L = ∇ a C ⊙ σ ′ ( z L ) \delta^L=\nabla_aC\odot\sigma'(z^L) δL=aCσ(zL)

  2. 使用下一层的误差 δ l + 1 \delta^{l+1} δl+1来表示当前层的误差 δ l \delta^l δl
    δ j l = ∑ k w j k l + 1 δ k l + 1 σ ′ ( z j l ) \delta_j^l=\sum_k{w_{jk}^{l+1}\delta_{k}^{l+1}\sigma'(z_j^l)} δjl=kwjkl+1δkl+1σ(zjl)

δ l = ( ( w l + 1 ) T δ l + 1 ) ⊙ σ ′ ( z l ) \delta^l=((w^{l+1})^T\delta^{l+1})\odot \sigma'(z^l) δl=((wl+1)Tδl+1)σ(zl)

  1. 代价函数关于网络中任意偏置的改变率 ∂ C ∂ b j l = δ j l \frac{\partial C}{\partial b_j^l}=\delta_j^l bjlC=δjl

  2. 代价函数关于任何一个权重的改变率 ∂ C ∂ w j k l = a k l − 1 δ j l \frac{\partial C}{\partial w_{jk}^l}=a_k^{l-1}\delta_j^l wjklC=akl1δjl矩阵形式:
    ∂ C ∂ w = a i n δ o u t \frac{\partial C}{\partial w}=a_{in}\delta_{out} wC=ainδout

算法表示

  1. 输入 x x x:为输入层设置激活值 a 1 a^1 a1
  2. 前向传播:对每个 l = 2 , 3 , ⋯   , L l=2,3,\cdots,L l=2,3,,L计算相应的 z l = w l a l − 1 + b l z^l=w^la^{l-1}+b^l zl=wlal1+bl a l = σ ( z l ) a^l=\sigma(z^l) al=σ(zl)
  3. 输出层误差 δ l \delta^l δl:计算向量 δ l = ∇ a C ⊙ σ ′ ( z l ) \delta^l=\nabla_aC\odot\sigma'(z^l) δl=aCσ(zl)
  4. 反向传播误差:对每一个 l = L − 1 , L − 2 , ⋯   , 2 , l=L-1,L-2,\cdots,2, l=L1,L2,,2, 计算 δ l = ( ( w l + 1 ) T δ l + 1 ) ⊙ σ ′ ( z l ) \delta_l=((w^{l+1})^T\delta^{l+1})\odot\sigma'(z^l) δl=((wl+1)Tδl+1)σ(zl)
  5. 输出:代价函数的梯度 ∂ C ∂ w j k l = a k l − 1 δ j l \frac{\partial C}{\partial w_{jk}^l}=a_k^{l-1}\delta_j^l wjklC=akl1δjl ∂ C ∂ b j l = δ j l \frac{\partial C}{\partial b_j^l}=\delta_j^l bjlC=δjl

Python实现

仅反向传播部分的代码,完整代码请见该书第二章。

import numpy as np

def sigmoid(z):
	return 1. / (1. + np.exp(-z))
def sigmoid_prime(z):
	return sigmoid(z) * (1 - sigmoid(z))
	
class Network(object):
"""
省略其余方法的实现
"""
	def backprop(self, x, y):
		# 初始化权重向量和偏置向量,一般为零矩阵
		nabla_b = [np.zeros(b.shape) for b in self.biases]
		nabla_w = [np.zeros(w.shape) for w in self.weights]
		
		# 初始化激活值以及z向量(神经元的值z组成的向量)
		activation = x
		activations = [x]
		z_vectors = []
		
		# 开始循环计算z向量及激活向量
		for b, w in zip(self.biases, self.weights):
			z = np.dot(w, activation) + b
			z_vectors.append(z)
			activation = sigmoid(z)
			activations.append(activation)
			
		# 开始计算输出层的误差,应用第一个方程
		delta = self.cost_derivative(activations[-1], y) * sigmoid_prime(z_vectors[-1])
		nabla_b[-1] = delta
		nabla_w[-1] = np.dot(delta, activations[-2].T)
		
		# 开始向前计算误差并存入梯度b及梯度w,应用第二个方程
		for l in range(2, self.num_layers):
			z = z_vectors[-l]
			delta = np.dot(self.weights[-l + 1].T, delta) * sigmoid_prime(z)
			nabla_b[-l] = delta
			nabla_w[-l] = np.dot(delta, activations[-l-1].T)
	return nabla_b, nabla_w

	def cost_derivative(self, output_activations, y):
		# 定义代价函数的导数(梯度),本例中使用二次代价函数,故其导数为(输出层激活向量-y)
		return output_activations - y


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zorchp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值