使用拟牛顿法的 BP 网络学习改进算法详解
使用拟牛顿法的 BP 网络学习改进算法详解
一、引言
BP(Back Propagation)神经网络是一种广泛应用于机器学习和非线性系统建模的工具。然而,传统的 BP 算法存在一些局限性,例如收敛速度慢、对复杂函数逼近效果不佳等。拟牛顿法作为一种优化算法,被引入到 BP 网络学习中,能够有效地克服这些问题。本文将详细阐述使用拟牛顿法的 BP 网络学习改进算法,包括其原理、实现步骤以及相应的代码示例。
二、传统 BP 网络学习算法回顾
(一)网络结构与前向传播
BP 神经网络一般由输入层、隐藏层和输出层组成。设输入层有 n n n 个神经元,输入向量为 x = ( x 1 , x 2 , ⋯ , x n ) \mathbf{x}=(x_1,x_2,\cdots,x_n) x=(x1,x2,⋯,xn);隐藏层有 m m m 个神经元,其输出向量为 h = ( h 1 , h 2 , ⋯ , h m ) \mathbf{h}=(h_1,h_2,\cdots,h_m) h=(h1,h2,⋯,hm);输出层有 l l l 个神经元,输出向量为 y = ( y 1 , y 2 , ⋯ , y l ) \mathbf{y}=(y_1,y_2,\cdots,y_l) y=(y1,y2,⋯,yl)。
在前向传播过程中,从输入层到隐藏层,隐藏层神经元的输入为:
z j = ∑ i = 1 n w i j 1 x i + b j 1 z_{j}=\sum_{i = 1}^{n}w_{ij}^{1}x_{i}+b_{j}^{1} zj=∑i=1nwij1xi+bj1
其中, w i j 1 w_{ij}^{1} wij1 是输入层到隐藏层的连接权重, b j 1 b_{j}^{1} bj1 是隐藏层的偏置。隐藏层神经元的输出通常经过激活函数处理,例如使用 Sigmoid 函数 h j = 1 1 + e − z j h_{j}=\frac{1}{1 + e^{-z_{j}}} hj=1+e−zj1。
从隐藏层到输出层,输出层神经元的输入为:
u k = ∑ j = 1 m w j k 2 h j + b k 2 u_{k}=\sum_{j = 1}^{m}w_{jk}^{2}h_{j}+b_{k}^{2} uk=∑j=1mwjk2hj+bk2
输出层神经元的输出 y k = 1 1 + e − u k y_{k}=\frac{1}{1 + e^{-u_{k}}} yk=1+e−uk1(这里以 Sigmoid 函数为例)。
(二)误差计算与反向传播
对于训练样本集 { ( x ( μ ) , t ( μ ) ) } μ = 1 N \{(\mathbf{x}^{(\mu)},\mathbf{t}^{(\mu)})\}_{\mu = 1}^{N} {(x(μ),t(μ))}μ=1N,其中 x ( μ ) \mathbf{x}^{(\mu)} x(μ) 是第 μ \mu μ 个输入样本, t ( μ ) \mathbf{t}^{(\mu)} t(μ) 是对应的目标输出。常用的误差函数是均方误差:
E = 1 2 ∑ μ = 1 N ∑ k = 1 l ( y k ( μ ) − t k ( μ ) ) 2 E=\frac{1}{2}\sum_{\mu = 1}^{N}\sum_{k = 1}^{l}(y_{k}^{(\mu)}-t_{k}^{(\mu)})^{2} E=21∑μ=1N∑k=1l(yk(μ)−tk(μ))2
在反向传播过程中,根据误差函数对权重的梯度来更新权重。以输出层到隐藏层的权重 w j k 2 w_{jk}^{2} wjk2 为例,其梯度计算为:
∂ E ∂ w j k 2 = ∑ μ = 1 N ( y k ( μ ) − t k ( μ ) ) y k ( μ ) ( 1 − y k ( μ ) ) h j ( μ ) \frac{\partial E}{\partial w_{jk}^{2}}=\sum_{\mu = 1}^{N}(y_{k}^{(\mu)}-t_{k}^{(\mu)})y_{k}^{(\mu)}(1 - y_{k}^{(\mu)})h_{j}^{(\mu)} ∂wjk2∂E=∑μ=1N(yk(μ)−tk(μ))yk(μ)(1−yk(μ))hj(μ)
然后根据梯度下降法更新权重:
w j k 2 ( t + 1 ) = w j k 2 ( t ) − η ∂ E ∂ w j k 2 w_{jk}^{2}(t + 1)=w_{jk}^{2}(t)-\eta\frac{\partial E}{\partial w_{jk}^{2}} wjk2(t+1)=wjk2(t)−η∂wjk2∂E
其中, η \eta η 是学习率, t t t 表示训练次数。类似地,可以计算输入层到隐藏层的权重更新公式。
三、传统 BP 算法的问题分析
(一)收敛速度问题
- 固定学习率的限制
传统 BP 算法中学习率是固定的,若学习率选择不当,会导致收敛速度慢。如果学习率过大,可能会使权重更新过度,跳过误差曲面的最小值点,导致训练过程震荡;若学习率过小,则权重更新缓慢,需要大量的训练迭代才能收敛。 - 梯度信息利用不足
在每次权重更新时,仅使用当前梯度信息,没有充分利用之前的梯度信息来调整更新方向和步长,使得在复杂的误差曲面中,收敛效率低下。
(二)局部最优问题
由于传统 BP 算法基于梯度下降法,容易陷入局部最优解。在误差曲面中,局部最优解周围的梯度接近零,导致权重更新停滞,无法找到全局最优解。
四、拟牛顿法原理
(一)牛顿法基本思想
牛顿法是一种基于二阶导数(Hessian 矩阵)的优化方法。对于目标函数 E ( w ) E(\mathbf{w}) E(w)(这里 w \mathbf{w} w 表示网络的所有权重和偏置组成的向量),其迭代公式为:
w t + 1 = w t − [ ∇ 2 E ( w t ) ] − 1 ∇ E ( w t ) \mathbf{w}^{t + 1}=\mathbf{w}^{t}-[\nabla^{2}E(\mathbf{w}^{t})]^{-1}\nabla E(\mathbf{w}^{t}) wt+1=wt−[∇2E(wt)]−1∇E(wt)
其中, ∇ E ( w t ) \nabla E(\mathbf{w}^{t}) ∇E(wt) 是目标函数在 w t \mathbf{w}^{t} wt 处的梯度向量, ∇ 2 E ( w t ) \nabla^{2}E(\mathbf{w}^{t}) ∇2E(wt) 是目标函数在 w t \mathbf{w}^{t} wt 处的 Hessian 矩阵。牛顿法利用了函数的二阶导数信息来更准确地确定搜索方向,在合适的条件下具有二次收敛性,收敛速度快。
(二)拟牛顿法的改进
计算 Hessian 矩阵及其逆矩阵在实际应用中计算量非常大,尤其是对于神经网络这种具有大量参数的模型。拟牛顿法的核心思想是通过近似计算 Hessian 矩阵或其逆矩阵来避免直接计算。常用的拟牛顿法有 BFGS(Broyden - Fletcher - Goldfarb - Shanno)算法和 DFP(Davidon - Fletcher - Powell)算法等。
这些算法通过构造一系列正定矩阵来逼近 Hessian 矩阵的逆矩阵,在每次迭代中,根据当前梯度信息和上一次迭代的信息来更新这个近似矩阵。以 BFGS 算法为例,它通过以下方式更新近似逆 Hessian 矩阵 H k \mathbf{H}_{k} Hk:
H k + 1 = H k + s k s k T s k T y k − H k y k y k T H k y k T H k y k \mathbf{H}_{k + 1}=\mathbf{H}_{k}+\frac{\mathbf{s}_{k}\mathbf{s}_{k}^{T}}{\mathbf{s}_{k}^{T}\mathbf{y}_{k}}-\frac{\mathbf{H}_{k}\mathbf{y}_{k}\mathbf{y}_{k}^{T}\mathbf{H}_{k}}{\mathbf{y}_{k}^{T}\mathbf{H}_{k}\mathbf{y}_{k}} Hk+1=Hk+skTykskskT−ykTHkykHkykykTHk
其中, s k = w k + 1 − w k \mathbf{s}_{k}=\mathbf{w}_{k + 1}-\mathbf{w}_{k} sk=wk+1−wk, y k = ∇ E ( w k + 1 ) − ∇ E ( w k ) \mathbf{y}_{k}=\nabla E(\mathbf{w}_{k + 1})-\nabla E(\mathbf{w}_{k}) yk=∇E(wk+1)−∇E(wk)。
然后,权重更新公式为:
w k + 1 = w k − α k H k ∇ E ( w k ) \mathbf{w}_{k + 1}=\mathbf{w}_{k}-\alpha_{k}\mathbf{H}_{k}\nabla E(\mathbf{w}_{k}) wk+1=wk−αkHk∇E(wk)
其中, α k \alpha_{k} αk 是通过线搜索确定的步长。
五、使用拟牛顿法的 BP 网络学习改进算法步骤
(一)初始化
- 网络参数初始化
初始化 BP 网络的权重和偏置,与传统 BP 算法类似,可以随机初始化权重在一个较小的范围内,例如 [ − 0.5 , 0.5 ] [-0.5,0.5] [−0.5,0.5]。 - 拟牛顿相关初始化
对于拟牛顿法,初始化近似逆 Hessian 矩阵。如果使用 BFGS 算法,可以将初始的 H 0 \mathbf{H}_{0} H0 设置为单位矩阵。同时,设置线搜索的相关参数,如初始步长等。
(二)训练过程
- 前向传播
与传统 BP 算法相同,对于每个训练样本,计算网络的前向传播,得到输出层的输出。 - 误差计算与梯度计算
计算当前样本的误差,并通过反向传播计算误差对权重的梯度,得到梯度向量 ∇ E ( w ) \nabla E(\mathbf{w}) ∇E(w)。 - 拟牛顿更新
根据当前梯度和上一次迭代的信息,使用拟牛顿算法(如 BFGS)更新近似逆 Hessian 矩阵 H \mathbf{H} H。 - 权重更新
根据更新后的近似逆 Hessian 矩阵和当前梯度,计算权重更新量,并更新网络的权重和偏置。 - 重复训练
对所有训练样本重复上述步骤,完成一次训练迭代(epoch)。持续进行多个训练迭代,直到满足训练停止条件,如达到预定的训练次数、误差小于某个阈值或者验证集误差不再下降等。
六、代码示例
以下是使用 Python 实现的基于 BFGS 拟牛顿法的 BP 网络学习改进算法的代码示例:
import numpy as np
# Sigmoid 激活函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# Sigmoid 函数的导数
def sigmoid_derivative(x):
return x * (1 - x)
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
self.input_size = input_size
self.hidden_size = hidden_size
self.output_size = output_size
# 随机初始化权重
self.W1 = np.random.rand(self.input_size, self.hidden_size)
self.b1 = np.zeros((1, self.hidden_size))
self.W2 = np.random.rand(self.hidden_size, self.output_size)
self.b2 = np.zeros((1, self.output_size))
# 初始化近似逆Hessian矩阵(BFGS)
self.H1 = np.eye(self.input_size * self.hidden_size + self.hidden_size + self.hidden_size * self.output_size + self.output_size)
self.H2 = np.eye(self.input_size * self.hidden_size + self.hidden_size + self.hidden_size * self.output_size + self.output_size)
def forward_propagation(self, X):
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = sigmoid(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = sigmoid(self.z2)
return self.a2
def back_propagation(self, X, y):
m = X.shape[0]
dZ2 = (self.a2 - y) * sigmoid_derivative(self.z2)
dW2 = np.dot(self.a1.T, dZ2)
db2 = np.sum(dZ2, axis=0, keepdims=True)
dZ1 = np.dot(dZ2, self.W2.T) * sigmoid_derivative(self.z1)
dW1 = np.dot(X.T, dZ1)
db1 = np.sum(dZ1, axis=0, keepdims=True)
return np.concatenate((dW1.flat, db1.flat, dW2.flat, db2.flat))
def update_weights_BFGS(self, X, y, gradient):
old_weights = np.concatenate((self.W1.flat, self.b1.flat, self.W2.flat, self.b2.flat))
new_weights = old_weights - np.dot(self.H1, gradient)
s = new_weights - old_weights
new_gradient = self.back_propagation(X, y)
y_ = new_gradient - gradient
rho = 1.0 / np.dot(y_, s)
self.H1 = (np.eye(len(self.H1)) - rho * np.outer(s, y_)).dot(self.H1).dot(np.eye(len(self.H1)) - rho * np.outer(y_, s)) + rho * np.outer(s, s)
self.W1 = new_weights[:self.input_size * self.hidden_size].reshape(self.input_size, self.hidden_size)
self.b1 = new_weights[self.input_size * self.hidden_size:self.input_size * self.hidden_size + self.hidden_size].reshape(1, self.hidden_size)
self.W2 = new_weights[self.input_size * self.hidden_size + self.hidden_size:self.input_size * self.hidden_size + self.hidden_size + self.hidden_size * self.output_size].reshape(self.hidden_size, self.output_size)
self.b2 = new_weights[self.input_size * self.hidden_size + self.hidden_size + self.hidden_size * self.output_size:].reshape(1, self.output_size)
def train(self, X, y, epochs):
for epoch in range(epochs):
output = self.forward_propagation(X)
gradient = self.back_propagation(X, y)
self.update_weights_BFGS(X, y, gradient)
if epoch % 100 == 0:
error = np.mean((output - y) ** 2)
print(f'Epoch {epoch}: Error = {error}')
以下是一个简单的测试示例:
# 示例用法
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])
neural_network = NeuralNetwork(2, 3, 1)
neural_network.train(X, y, 1000)
七、总结
使用拟牛顿法的 BP 网络学习改进算法通过更有效地利用梯度信息和近似计算二阶导数信息,克服了传统 BP 算法的一些局限性。它在收敛速度和避免局部最优解方面表现出更好的性能。代码示例展示了如何在 BP 网络中实现 BFGS 拟牛顿法,在实际应用中,可以根据具体的问题和数据集进一步优化算法,如调整线搜索策略、改进拟牛顿近似方法等,以提高网络的训练效果和泛化能力。
原文地址:https://blog.csdn.net/ashyyyy/article/details/143845708
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!