BP算法推导过程

从研究生时期就接触了神经网络算法,其中的反向传播BP算法是目前应用神经网络算法里使用最为广泛的算法,包括最近非常火爆的深度学习算法中都用到了这个算法。但是一直以来,自己对BP算法都没有做过仔细的数学推导,只是做到大概了解原理,不能深刻记忆,每次再看的时候又需要重新理解一遍。
        最近把Andrew Ng在Coursera上的机器学习课程又重新听了一遍,第一遍由于着急赶时间拿证书做完了编程练习很多细节都没推敲。这次看到神经网络这块的时候又有一种似曾相识又不得甚解的感觉,于是利用下班后两个晚上花了几个小时搜集网上的资料把推导过程整理下来。

推导过程遇到的几个问题

1. 不同的Cost函数开始的时候看到的网上有贴出来Ufldl里面的BP推导过程,虽然都是Ng的课程,但是这两个课程里面BP算法用到的Cost函数不一样

Ufldl课程里的Cost函数,用了最常规的最小二乘法代价函数

BP算法推导过程
Coursera上机器学习课程的Cost代价函数,与逻辑回归算法保持一致,通过极大似然估计导出的代价函数

BP算法推导过程

上面第二个J函数参数变量θ等价于第一个的W,b,但是上面两个函数形式完全不一样,网上的很多推导都是基于第一个Cost函数的形式,而实际上BP算法的cost函数是可以不同的,不利于对整个过程的理解,因此推导过程应该是基于函数范式而不是特定的函数表达式;

2. 链式法则。其实BP算法推导最主要用到的就是微积分里的偏导数链式法则,虽然数学系毕业,基本上也忘得也差不多,索性把找到的证明过程也贴出来,有兴趣的同学可以看一下

链式法则:
一元复合的情况
 (f \circ g)'(x) = f'(g(x)) g'(x).
多元复合的情况

考虑函数z f(xy),其中x g(t),y h(t),g(t)和h(t)是可微函数,那么:

{\ dz \over dt}={\partial z \over \partial x}{dx \over dt}+{\partial z \over \partial y}{dy \over dt}.
对一元复合情况的证明

fg为函数,x为常数,使得fg(x)可导,且gx可导。根据可导的定义,

 g(x+\delta)-g(x)= \delta g'(x) + \epsilon(\delta)\delta \,,其中当\delta\to 0时, \epsilon(\delta) \to 0 \,

同理,

 f(g(x)+\alpha) - f(g(x)) = \alpha f'(g(x)) + \eta(\alpha)\alpha \,,其中当\alpha\to 0. \,时,\eta(\alpha) \to 0 \,

现在

 f(g(x+\delta))-f(g(x))\, = f(g(x) + \delta g'(x)+\epsilon(\delta)\delta) - f(g(x)) \,

 = \alpha_\delta f'(g(x)) + \eta(\alpha_\delta)\alpha_\delta \,

其中\alpha_\delta = \delta g'(x) + \epsilon(\delta)\delta \,. 注意到当\delta\to 0时,\frac{\alpha_\delta}{\delta}\to g'(x)\alpha_\delta \to 0,因此 \eta(\alpha_\delta)\to 0。因此

 \frac{f(g(x+\delta))-f(g(x))}{\delta} \to g'(x)f'(g(x)).

下面正式进入推导过程

其实BP算法推导的关键点就是找到层之间的传递关系,即
BP算法推导过程BP算法推导过程

BP算法推导过程BP算法推导过程

第一步、先定义变量

BP算法推导过程

第二步、使用链式法则推导BP算法推导过程BP算法推导过程之间的关系,注意原文中第二步替换w的公式里y的下标应该是i而不是j,应该是笔误


BP算法推导过程
第三步、继续用链式法则推导BP算法推导过程BP算法推导过程的关系

BP算法推导过程

第四步、得到和课程里相同的等式
BP算法推导过程

最后,关于不同的cost函数,coursera上的课程和Ufldl课程在输出层的BP算法推导过程是不一样的,这个是可以直接对cost函数求导的出来的。写完了之后发现自己想明白和写明白还是不一样的,关键还是需要花时间理解和推导,希望整理的这些东西能对和我遇到一样问题的同学们有帮助。
反向传播(Backpropagation, BP算法神经网络训练中的核心机制之一,其本质是通过链式求导法则计算损失函数对网络参数的梯度,并利用这些梯度更新模型参数以最小化损失函数。 在神经网络中,前向传播负责从输入层到输出层依次计算每一层的激活值。假设某一层的输入为 $ z^{(l)} $,权重矩阵为 $ W^{(l)} $,偏置为 $ b^{(l)} $,激活函数为 $ \sigma(\cdot) $,则该层的输出表示为: $$ a^{(l)} = \sigma(z^{(l)}) = \sigma(W^{(l)} a^{(l-1)} + b^{(l)}) $$ 损失函数 $ L $ 是衡量预测输出与真实标签之间误差的指标。为了优化参数,需要计算损失函数对每一层参数 $ W^{(l)} $ 和 $ b^{(l)} $ 的偏导数。反向传播的核心在于利用链式法则逐层回传误差信号,从而高效地计算这些梯度。 具体而言,对于输出层 $ l = L $,定义误差项 $ \delta^{(L)} $ 为损失函数对加权输入 $ z^{(L)} $ 的导数: $$ \delta^{(L)} = \frac{\partial L}{\partial z^{(L)}} $$ 随后,对于隐藏层 $ l = L-1, L-2, \dots, 1 $,误差项通过以下递归公式进行传递: $$ \delta^{(l)} = \left( (W^{(l+1)})^T \delta^{(l+1)} \right) \odot \sigma'(z^{(l)}) $$ 其中 $ \odot $ 表示逐元素乘法,$ \sigma'(\cdot) $ 是激活函数的导数。最终,参数的梯度可通过以下公式计算: $$ \frac{\partial L}{\partial W^{(l)}} = \delta^{(l)} (a^{(l-1)})^T $$ $$ \frac{\partial L}{\partial b^{(l)}} = \delta^{(l)} $$ 通过上述过程,可以将误差信号从输出层逐步反向传播至输入层,并完成所有参数的梯度计算。由于反向传播避免了重复计算,显著提高了训练效率[^2]。 ### 卷积神经网络中的反向传播 在卷积神经网络(CNN)中,反向传播不仅适用于全连接层,也适用于卷积层和池化层。对于卷积层,误差项的传播需考虑卷积操作的特性。设输入特征图 $ X $ 经过卷积核 $ K $ 得到输出特征图 $ Y $,则误差项 $ \delta_Y $ 在反向传播时会与卷积核 $ K $ 进行翻转后的卷积操作,得到输入特征图的误差项 $ \delta_X $。这一过程可以形式化为: $$ \delta_X = \text{conv}(\delta_Y, \text{rot180}(K)) $$ 其中,$\text{rot180}(K)$ 表示将卷积核旋转180度的操作。这种设计确保了卷积运算的局部感受野特性在反向传播中得以保留[^3]。 ### 示例代码:全连接网络的反向传播实现 以下是一个简单的Python代码片段,演示如何实现全连接神经网络中的反向传播过程: ```python import numpy as np def sigmoid(x): return 1 / (1 + np.exp(-x)) def sigmoid_derivative(x): return x * (1 - x) # 初始化参数 input_size = 2 hidden_size = 3 output_size = 1 W1 = np.random.randn(hidden_size, input_size) b1 = np.random.randn(hidden_size, 1) W2 = np.random.randn(output_size, hidden_size) b2 = np.random.randn(output_size, 1) # 前向传播 def forward(X): z1 = np.dot(W1, X) + b1 a1 = sigmoid(z1) z2 = np.dot(W2, a1) + b2 a2 = sigmoid(z2) return z1, a1, z2, a2 # 反向传播 def backward(X, y, z1, a1, z2, a2, learning_rate=0.1): m = X.shape[1] # 输出层误差 delta2 = (a2 - y) * sigmoid_derivative(a2) dW2 = np.dot(delta2, a1.T) / m db2 = np.sum(delta2, axis=1, keepdims=True) / m # 隐藏层误差 delta1 = np.dot(W2.T, delta2) * sigmoid_derivative(a1) dW1 = np.dot(delta1, X.T) / m db1 = np.sum(delta1, axis=1, keepdims=True) / m # 参数更新 W2 -= learning_rate * dW2 b2 -= learning_rate * db2 W1 -= learning_rate * dW1 b1 -= learning_rate * db1 # 示例数据 X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]).T y = np.array([[0, 1, 1, 0]]) # 训练循环 for epoch in range(10000): z1, a1, z2, a2 = forward(X) backward(X, y, z1, a1, z2, a2) # 最终预测结果 _, _, _, prediction = forward(X) print("预测输出:", prediction) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值