误差反向传播算法是否存在过拟合问题,如何解决

问题描述:误差反向传播算法是否存在过拟合问题,如何解决这个问题?

介绍

误差反向传播算法是用于训练神经网络的一种重要算法。在训练过程中,我们通过计算网络输出与真实值的差异(即误差),并将误差反向传播到网络的各个层,从而更新网络的参数。然而,这种算法存在一个常见问题,即过拟合。过拟合指的是模型在训练数据上表现良好,但是在未见过的测试数据上表现较差的现象。

算法原理

误差反向传播算法主要通过链式法则计算梯度以更新模型参数。在每一次迭代训练中,通过计算模型对训练样本的预测值与真实值之间的误差(损失函数),可以得到一个代表误差大小的值。然后,通过计算损失函数对网络参数的偏导数,即梯度,我们可以通过优化算法(如梯度下降法)来更新网络参数,以尽可能减少误差。

公式推导

让我们以一个简单的例子来推导误差反向传播算法的公式。假设我们有一个单隐藏层的前馈神经网络,输入为x,隐藏层神经元个数为h,输出层神经元个数为o。网络的输入层到隐藏层的权重为W1,隐藏层到输出层的权重为W2,隐藏层的偏置为b1,输出层的偏置为b2。我们使用平方损失函数,即$L(y, \hat{y}) = \frac{1}{2}(y – \hat{y})^2$。其中,y为真实值,$\hat{y}$为网络的预测值。

Step 1: 前向传播
首先,我们根据输入x计算隐藏层的激活值$a_1$:
$$a_1 = \sigma(W_1 \cdot x + b_1)$$
其中,$\sigma$为激活函数,通常使用ReLU或Sigmoid函数。

然后,我们使用隐藏层的激活值计算输出层的激活值$a_2$:
$$a_2 = \sigma(W_2 \cdot a_1 + b_2)$$

Step 2: 计算损失函数
接下来,我们计算损失函数对输出层激活值的偏导数$\frac{\partial L}{\partial a_2}$:
$$\frac{\partial L}{\partial a_2} = \frac{\partial}{\partial a_2} \frac{1}{2}(y – a_2)^2 = (a_2 – y)$$

Step 3: 反向传播
现在,我们使用链式法则计算损失函数对隐藏层到输出层权重W2的偏导数$\frac{\partial L}{\partial W_2}$:
$$\frac{\partial L}{\partial W_2} = \frac{\partial L}{\partial a_2} \cdot \frac{\partial a_2}{\partial (W_2 \cdot a_1 + b_2)} = (a_2 – y) \cdot \sigma'(W_2 \cdot a_1 + b_2) \cdot a_1^T$$
其中,$\sigma’$为激活函数的导数。

接着,我们计算损失函数对隐藏层偏置b2的偏导数$\frac{\partial L}{\partial b_2}$:
$$\frac{\partial L}{\partial b_2} = \frac{\partial L}{\partial a_2} \cdot \frac{\partial a_2}{\partial (W_2 \cdot a_1 + b_2)} = (a_2 – y) \cdot \sigma'(W_2 \cdot a_1 + b_2)$$

类似地,我们计算损失函数对输入层到隐藏层权重W1的偏导数$\frac{\partial L}{\partial W_1}$:
$$\frac{\partial L}{\partial W_1} = \frac{\partial L}{\partial a_2} \cdot \frac{\partial a_2}{\partial a_1} \cdot \frac{\partial a_1}{\partial (W_1 \cdot x + b_1)} \cdot x^T$$

最后,我们计算损失函数对隐藏层偏置b1的偏导数$\frac{\partial L}{\partial b_1}$:
$$\frac{\partial L}{\partial b_1} = \frac{\partial L}{\partial a_2} \cdot \frac{\partial a_2}{\partial a_1} \cdot \frac{\partial a_1}{\partial (W_1 \cdot x + b_1)}$$

Step 4: 参数更新
通过梯度下降法等优化算法,我们可以更新模型参数。假设学习率为$\alpha$,参数更新的具体公式如下:
$$W_2 = W_2 – \alpha \cdot \frac{\partial L}{\partial W_2}$$
$$b_2 = b_2 – \alpha \cdot \frac{\partial L}{\partial b_2}$$
$$W_1 = W_1 – \alpha \cdot \frac{\partial L}{\partial W_1}$$
$$b_1 = b_1 – \alpha \cdot \frac{\partial L}{\partial b_1}$$

计算步骤

  1. 初始化输入层到隐藏层的权重W1、隐藏层到输出层的权重W2、隐藏层的偏置b1、输出层的偏置b2。
  2. 根据输入x,进行前向传播,计算网络的预测值。
  3. 根据网络的预测值和真实值,计算损失函数。
  4. 根据损失函数,进行反向传播,计算梯度。
  5. 使用优化算法,根据梯度更新模型参数。
  6. 重复步骤2-5,直至达到收敛条件或达到最大迭代次数。

Python代码示例

下面是一个使用Python实现的简单的误差反向传播算法的例子。我们使用一个虚拟数据集,并使用Numpy库来进行矩阵运算。

首先,我们需要导入必要的库:

import numpy as np
import matplotlib.pyplot as plt

然后,我们定义激活函数和其导数:

def sigmoid(x):
 return 1 / (1 + np.exp(-x))

def sigmoid_derivative(x):
 return sigmoid(x) artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls (1 - sigmoid(x))

接下来,我们初始化输入、隐藏层、输出层的维度和学习率等参数:

input_dim = 1
hidden_dim = 3
output_dim = 1
learning_rate = 0.01

然后,我们生成虚拟数据集:

X = np.array([[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]])
y = np.array([[0], [1], [4], [9], [16], [25], [36], [49], [64], [81]])

接着,我们随机初始化参数权重W1、W2以及偏置b1、b2:

np.random.seed(1)
W1 = np.random.randn(hidden_dim, input_dim)
b1 = np.zeros((hidden_dim, 1))
W2 = np.random.randn(output_dim, hidden_dim)
b2 = np.zeros((output_dim, 1))

然后,我们开始迭代训练模型:

losses = []
for i in range(10000):
 # 前向传播
 hidden_layer_output = sigmoid(np.dot(W1, X) + b1)
 y_pred = sigmoid(np.dot(W2, hidden_layer_output) + b2)

 # 计算损失函数
 loss = 0.5 artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls np.mean((y_pred - y) artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls 2)
 losses.append(loss)

 # 反向传播
 dL_dypred = y_pred - y
 dypred_dz2 = sigmoid_derivative(np.dot(W2, hidden_layer_output) + b2)
 dz2_dW2 = hidden_layer_output
 dL_dW2 = np.dot((dL_dypred artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dypred_dz2), dz2_dW2.T)
 dL_db2 = np.sum(dL_dypred artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dypred_dz2, axis=1, keepdims=True)

 dz2_dhidden_layer = W2
 dhidden_layer_dz1 = sigmoid_derivative(np.dot(W1, X) + b1)
 dz1_dW1 = X
 dL_dW1 = np.dot((np.dot(dz2_dhidden_layer.T, (dL_dypred artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dypred_dz2)) artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dhidden_layer_dz1), dz1_dW1.T)
 dL_db1 = np.sum(np.dot(dz2_dhidden_layer.T, (dL_dypred artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dypred_dz2)) artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dhidden_layer_dz1, axis=1, keepdims=True)

 # 更新参数
 W2 -= learning_rate artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dL_dW2
 b2 -= learning_rate artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dL_db2
 W1 -= learning_rate artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dL_dW1
 b1 -= learning_rate artical cgpt2md_gpt.sh cgpt2md_johngo.log cgpt2md_johngo.sh cgpt2md.sh _content1.txt _content.txt current_url.txt history_url history_urls log nohup.out online pic.txt seo test.py topic_gpt.txt topic_johngo.txt topic.txt upload-markdown-to-wordpress.py urls dL_db1

最后,我们绘制损失函数的变化曲线来观察模型的训练情况:

plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()

代码细节解释

  1. 计算隐藏层和输出层的激活值时,使用了sigmoid激活函数。
  2. 计算损失函数时,使用了平方损失函数。
  3. 实现了参数的随机初始化,以防止所有参数具有相同的初始值,陷入局部最优点。
  4. 反向传播过程中,需要使用激活函数的导数来计算偏导数,这里使用了sigmoid函数的导数。
  5. 在更新参数时,需要乘以学习率。
  6. 每次迭代都记录下损失函数的值,便于之后绘制损失函数曲线进行分析。

通过运行以上代码,我们可以观察到损失函数逐渐减小,模型通过误差反向传播算法不断进行参数更新,逐渐优化模型。

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/823879/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球