当前位置: 首页 > article >正文

使用弹性方法的 BP 网络学习改进算法详解

使用弹性方法的 BP 网络学习改进算法详解

一、引言

BP(Back Propagation)神经网络在机器学习和人工智能领域有着广泛的应用。然而,传统的 BP 算法在训练过程中存在一些问题,例如对学习率的敏感度过高,容易导致训练过程不稳定或收敛速度慢等。为了克服这些问题,研究人员提出了多种改进算法,其中使用弹性方法的 BP 网络学习改进算法表现出了良好的性能。本文将详细介绍这种改进算法的原理、实现步骤,并通过代码示例来深入理解其工作方式。

二、传统 BP 网络学习算法的局限性

(一)学习率问题

  1. 收敛速度与学习率的关系
    在传统 BP 算法中,学习率是一个关键参数。如果学习率设置得过大,在训练过程中可能会导致权重更新幅度过大,使得网络在误差曲面上跳过最小值点,甚至可能导致训练过程无法收敛。相反,若学习率设置得过小,权重更新缓慢,会导致收敛速度极慢,尤其是在处理复杂的、高维的数据集时,这种情况会更加明显。
  2. 对不同训练阶段的不适应性
    在训练的不同阶段,网络对学习率的需求是不同的。在训练初期,误差曲面通常较为平坦,较大的学习率有助于快速接近最优解所在的区域。但随着训练的进行,在接近最优解时,误差曲面变得更加复杂,需要较小的学习率来精确调整权重,以避免越过最小值点。然而,传统 BP 算法中的固定学习率无法满足这种动态变化的需求。

(二)局部最优问题

由于传统 BP 算法基于梯度下降法,它在训练过程中容易陷入局部最优解。在复杂的误差曲面中,局部最优解周围的梯度可能非常小,导致算法无法继续朝着全局最优解的方向更新权重。

三、弹性方法的原理

(一)基本思想

弹性方法(Resilient Backpropagation,RPROP)的核心思想是根据权重更新过程中的梯度信息来动态调整每个权重的更新步长(即学习率),而不是使用一个固定的全局学习率。这种自适应的学习率调整机制可以有效地克服传统 BP 算法中学习率固定所带来的问题。

(二)梯度相关的更新规则

  1. 符号判断
    对于每个权重 w i j w_{ij} wij,在每次迭代中,观察其梯度的符号。如果当前梯度的符号与上一次梯度的符号相同,说明权重更新的方向是正确的,可以增加该权重的更新步长;如果梯度符号发生改变,说明上一次的更新可能已经越过了局部最优解或者走在错误的方向上,此时应该减小该权重的更新步长。
  2. 更新步长调整公式
    设权重 w i j w_{ij} wij 的当前更新步长为 Δ i j ( t ) \Delta_{ij}(t) Δij(t)(其中 t t t 表示训练迭代次数),根据梯度符号变化情况,更新步长的调整公式如下:

如果 ∂ E ∂ w i j ( t ) × ∂ E ∂ w i j ( t − 1 ) > 0 \frac{\partial E}{\partial w_{ij}}(t)\times\frac{\partial E}{\partial w_{ij}}(t - 1)>0 wijE(t)×wijE(t1)>0(梯度符号相同),则 Δ i j ( t + 1 ) = min ⁡ ( Δ i j ( t ) × η + , Δ m a x ) \Delta_{ij}(t + 1)=\min(\Delta_{ij}(t)\times\eta^{+},\Delta_{max}) Δij(t+1)=min(Δij(t)×η+,Δmax),其中 η + > 1 \eta^{+}>1 η+>1 是增加因子, Δ m a x \Delta_{max} Δmax 是最大更新步长限制。

如果 ∂ E ∂ w i j ( t ) × ∂ E ∂ w i j ( t − 1 ) < 0 \frac{\partial E}{\partial w_{ij}}(t)\times\frac{\partial E}{\partial w_{ij}}(t - 1)<0 wijE(t)×wijE(t1)<0(梯度符号改变),则 Δ i j ( t + 1 ) = max ⁡ ( Δ i j ( t ) × η − , Δ m i n ) \Delta_{ij}(t + 1)=\max(\Delta_{ij}(t)\times\eta^{-},\Delta_{min}) Δij(t+1)=max(Δij(t)×η,Δmin),其中 η − < 1 \eta^{-}<1 η<1 是减小因子, Δ m i n \Delta_{min} Δmin 是最小更新步长限制。

如果 ∂ E ∂ w i j ( t ) × ∂ E ∂ w i j ( t − 1 ) = 0 \frac{\partial E}{\partial w_{ij}}(t)\times\frac{\partial E}{\partial w_{ij}}(t - 1)=0 wijE(t)×wijE(t1)=0(梯度为零或变化很小),则 Δ i j ( t + 1 ) = Δ i j ( t ) \Delta_{ij}(t + 1)=\Delta_{ij}(t) Δij(t+1)=Δij(t),即保持更新步长不变。

(三)权重更新

权重的实际更新公式为:

w i j ( t + 1 ) = w i j ( t ) − sgn ( ∂ E ∂ w i j ( t ) ) × Δ i j ( t + 1 ) w_{ij}(t + 1)=w_{ij}(t)-\text{sgn}(\frac{\partial E}{\partial w_{ij}}(t))\times\Delta_{ij}(t + 1) wij(t+1)=wij(t)sgn(wijE(t))×Δij(t+1)

其中, sgn ( ⋅ ) \text{sgn}(\cdot) sgn() 是符号函数,根据梯度的正负确定权重更新的方向。

四、使用弹性方法的 BP 网络学习改进算法实现步骤

(一)初始化

  1. 网络结构初始化
    确定 BP 网络的输入层节点数 n n n、隐藏层节点数(可以有多个隐藏层,这里假设为 h h h)和输出层节点数 m m m。随机初始化网络的权重矩阵 W i j \mathbf{W}_{ij} Wij(包括输入层到隐藏层、隐藏层到输出层的权重)和偏置向量 b j \mathbf{b}_{j} bj(隐藏层和输出层的偏置)。
  2. 更新步长初始化
    为每个权重 w i j w_{ij} wij 初始化一个更新步长 Δ i j ( 0 ) \Delta_{ij}(0) Δij(0),通常设置为一个较小的正值,如 Δ i j ( 0 ) = 0.1 \Delta_{ij}(0)=0.1 Δij(0)=0.1。同时,设置最大更新步长 Δ m a x \Delta_{max} Δmax、最小更新步长 Δ m i n \Delta_{min} Δmin、增加因子 η + \eta^{+} η+ 和减小因子 η − \eta^{-} η,例如, Δ m a x = 50 \Delta_{max}=50 Δmax=50 Δ m i n = 1 e − 6 \Delta_{min}=1e - 6 Δmin=1e6 η + = 1.2 \eta^{+}=1.2 η+=1.2 η − = 0.5 \eta^{-}=0.5 η=0.5

(二)训练过程

  1. 前向传播
    对于输入样本向量 x = ( x 1 , x 2 , ⋯   , x n ) \mathbf{x}=(x_1,x_2,\cdots,x_n) x=(x1,x2,,xn),通过网络进行前向传播计算。从输入层到隐藏层,计算隐藏层神经元的输入和输出:

n e t j h = ∑ i = 1 n w i j i h x i + b j h net_{j}^{h}=\sum_{i = 1}^{n}w_{ij}^{ih}x_{i}+b_{j}^{h} netjh=i=1nwijihxi+bjh

h j = f ( n e t j h ) h_{j}=f(net_{j}^{h}) hj=f(netjh)

其中, w i j i h w_{ij}^{ih} wijih 是输入层到隐藏层的权重, b j h b_{j}^{h} bjh 是隐藏层的偏置, f ( ⋅ ) f(\cdot) f() 是激活函数(如 Sigmoid 函数)。类似地,从隐藏层到输出层计算输出层神经元的输出。

  1. 误差计算
    根据网络输出和目标输出计算误差。常用的误差函数是均方误差(MSE),对于训练样本集 { ( x ( p ) , t ( p ) ) } p = 1 P \{(\mathbf{x}^{(p)},\mathbf{t}^{(p)})\}_{p = 1}^{P} {(x(p),t(p))}p=1P,均方误差为:

E = 1 2 P ∑ p = 1 P ∑ k = 1 m ( y k ( p ) − t k ( p ) ) 2 E=\frac{1}{2P}\sum_{p = 1}^{P}\sum_{k = 1}^{m}(y_{k}^{(p)}-t_{k}^{(p)})^{2} E=2P1p=1Pk=1m(yk(p)tk(p))2

其中, y k ( p ) y_{k}^{(p)} yk(p) 是网络对第 p p p 个样本的第 k k k 个输出, t k ( p ) t_{k}^{(p)} tk(p) 是第 p p p 个样本的第 k k k 个目标输出。

  1. 反向传播与权重更新步长调整
    通过反向传播计算误差对权重的梯度。对于输出层到隐藏层的权重梯度计算:

∂ E ∂ w j k h o = ∑ p = 1 P ( y k ( p ) − t k ( p ) ) f ′ ( n e t k o ) h j h \frac{\partial E}{\partial w_{jk}^{ho}}=\sum_{p = 1}^{P}(y_{k}^{(p)}-t_{k}^{(p)})f^{\prime}(net_{k}^{o})h_{j}^{h} wjkhoE=p=1P(yk(p)tk(p))f(netko)hjh

其中, w j k h o w_{jk}^{ho} wjkho 是隐藏层到输出层的权重, n e t k o net_{k}^{o} netko 是输出层神经元 k k k 的输入, f ′ ( ⋅ ) f^{\prime}(\cdot) f() 是激活函数的导数。类似地,可以计算输入层到隐藏层的权重梯度。

根据梯度信息和当前的更新步长,按照前面提到的更新步长调整公式调整每个权重的更新步长 Δ i j ( t + 1 ) \Delta_{ij}(t + 1) Δij(t+1)

  1. 权重更新
    根据调整后的更新步长,使用权重更新公式更新权重:

w i j ( t + 1 ) = w i j ( t ) − sgn ( ∂ E ∂ w i j ( t ) ) × Δ i j ( t + 1 ) w_{ij}(t + 1)=w_{ij}(t)-\text{sgn}(\frac{\partial E}{\partial w_{ij}}(t))\times\Delta_{ij}(t + 1) wij(t+1)=wij(t)sgn(wijE(t))×Δij(t+1)

  1. 重复训练
    对所有训练样本重复上述步骤,完成一次训练迭代(epoch)。持续进行多个训练迭代,直到满足训练停止条件,如达到预定的训练次数、误差小于某个阈值或者验证集误差不再下降等。

五、代码示例

以下是使用 Python 实现的使用弹性方法的 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))
        # 初始化权重更新步长
        self.delta_W1 = np.ones_like(self.W1) * 0.1
        self.delta_b1 = np.ones_like(self.b1) * 0.1
        self.delta_W2 = np.ones_like(self.W2) * 0.1
        self.delta_b2 = np.ones_like(self.b2) * 0.1
        self.eta_plus = 1.2  # 增加因子
        self.eta_minus = 0.5  # 减小因子
        self.delta_max = 50
        self.delta_min = 1e - 6

    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) / m
        db2 = np.sum(dZ2, axis=0, keepdims=True) / m
        dZ1 = np.dot(dZ2, self.W2.T) * sigmoid_derivative(self.z1)
        dW1 = np.dot(X.T, dZ1) / m
        db1 = np.sum(dZ1, axis=0, keepdims=True) / m
        return dW1, db1, dW2, db2

    def update_weights_and_deltas(self, dW1, db1, dW2, db2):
        for i in range(self.W1.shape[0]):
            for j in range(self.W1.shape[1]):
                if dW1[i][j] * self.prev_dW1[i][j] > 0:
                    self.delta_W1[i][j] = min(self.delta_W1[i][j] * self.eta_plus, self.delta_max)
                elif dW1[i][j] * self.prev_dW1[i][j] < 0:
                    self.delta_W1[i][j] = max(self.delta_W1[i][j] * self.eta_minus, self.delta_min)
                self.W1[i][j] -= np.sign(dW1[i][j]) * self.delta_W1[i][j]
        for j in range(self.b1.shape[1]):
            if db1[0][j] * self.prev_db1[0][j] > 0:
                self.delta_b1[0][j] = min(self.delta_b1[0][j] * self.eta_plus, self.delta_max)
            elif db1[0][j] * self.prev_db1[0][j] < 0:
                self.delta_b1[0][j] = max(self.delta_b1[0][j] * self.eta_minus, self.delta_min)
            self.b1[0][j] -= np.sign(db1[0][j]) * self.delta_b1[0][j]

        for i in range(self.W2.shape[0]):
            for j in range(self.W2.shape[1]):
                if dW2[i][j] * self.prev_dW2[i][j] > 0:
                    self.delta_W2[i][j] = min(self.delta_W2[i][j] * self.eta_plus, self.delta_max)
                elif dW2[i][j] * self.prev_dW2[i][j] < 0:
                    self.delta_W2[i][j] = max(self.delta_W2[i][j] * self.eta_minus, self.delta_min)
                self.W2[i][j] -= np.sign(dW2[i][j]) * self.delta_W2[i][j]
        for j in range(self.b2.shape[1]):
            if db2[0][j] * self.prev_db2[0][j] > 0:
                self.delta_b2[0][j] = min(self.delta_b2[0][j] * self.eta_plus, self.delta_max)
            elif db2[0][j] * self.prev_db2[0][j] < 0:
                self.delta_b2[0][j] = max(self.delta_b2[0][j] * self.eta_minus, self.delta_min)
            self.b2[0][j] -= np.sign(db2[0][j]) * self.delta_b2[0][j]

        self.prev_dW1 = dW1.copy()
        self.prev_db1 = db1.copy()
        self.prev_dW2 = dW2.copy()
        self.prev_db2 = db2.copy()

    def train(self, X, y, epochs):
        self.prev_dW1 = np.zeros_like(self.W1)
        self.prev_db1 = np.zeros_like(self.b1)
        self.prev_dW2 = np.zeros_like(self.W2)
        self.prev_db2 = np.zeros_like(self.b2)
        for epoch in range(epochs):
            output = self.forward_propagation(X)
            dW1, db1, dW2, db2 = self.back_propagation(X, y)
            self.update_weights_and_deltas(dW1, db1, dW2, db2)
            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 算法中对固定学习率敏感的问题。这种算法在训练过程中能够根据梯度信息动态调整学习率,提高了训练的稳定性和收敛速度,并且在一定程度上减少了陷入局部最优解的可能性。代码示例详细展示了该算法的实现过程,通过实际运行可以观察到其在训练神经网络时的优势。在实际应用中,可以根据具体的数据集和问题进一步优化算法参数,以获得更好的性能。


http://www.kler.cn/a/400444.html

相关文章:

  • mysql 的乐观锁和 mvcc 是一回事吗
  • 【AI图像生成网站Golang】项目架构
  • 初识Linux · 信号处理 · 续
  • 刘艳兵-DBA036-Oracle数据库中的触发器(Trigger)可以在以下哪种情况下自动执行?
  • 华为ensp实验二--mux vlan的应用
  • 5. langgraph中的react agent使用 (从零构建一个react agent)
  • 【操作系统】Linux之线程同步二(头歌作业)
  • Git 常用命令大全与详解
  • 请求响应入门
  • element ui table进行相同数据合并单元格
  • Web搭建入门教程:基于ssh向服务器推送文件
  • 了解存储过程
  • c#————委托Action使用例子
  • 【泛型 Plus】Kotlin 的加强版类型推断:@BuilderInference
  • LM2 : A Simple Society of Language Models Solves Complex Reasoning
  • MyBatis XML一个方法执行插入或更新操做(PostgreSQL)
  • Java Collection的使用
  • Jaskson处理复杂的泛型对象
  • (Linux 入门) 基本指令、基本权限
  • 动态规划 之 子序列系列 算法专题
  • 脚手架vue-cli,webpack模板
  • 资源管理功能拆解——如何高效配置和管理项目资源?
  • 高斯数据库Postgresql死锁和锁表解决方法
  • MATLAB深度学习(三)——LeNet卷积神经网络
  • 独立站干货:WordPress主机推荐
  • Python高级编程模式和设计模式