反向传播算法是如何计算神经网络中的误差梯度的

问题介绍

在神经网络中,反向传播算法是一种用于训练模型的常用方法。它通过计算神经网络中的误差梯度来更新模型的权重,从而实现模型的优化。本文将详细介绍反向传播算法的原理、公式推导、计算步骤,并提供一个复杂的Python代码示例来解释代码细节。

算法原理

反向传播算法通过使用链式法则将神经网络的误差梯度从输出层向输入层进行传播。它使用了一种称为“反向计算”的方法,从最后一层开始计算梯度,然后逐层向前计算,直到达到输入层。

公式推导

我们假设我们有一个包含多个层的神经网络,其中包括输入层、输出层和中间层。我们用$W_{ij}^{(l)}$表示第$l$层的第$i$个神经元到第$l+1$层的第$j$个神经元之间的连接权重,$a_i^{(l)}$表示第$l$层的第$i$个神经元的输入,$z_i^{(l)}$表示第$l$层的第$i$个神经元的输出。对于输出层的第$j$个神经元,我们用$y_j$表示期望的输出值。

误差梯度表示为$\delta_i^{(l)}$,表示第$l$层的第$i$个神经元的误差梯度。我们使用平方误差作为损失函数,定义为$E = \frac{1}{2}\sum_j (y_j – z_j^{(L)})^2$,其中$L$表示输出层的索引。

根据链式法则,我们可以计算每个神经元的误差梯度$\delta_i^{(l)}$,并使用它们来更新权重$W_{ij}^{(l)}$。具体推导如下:

对于输出层($l = L$)的第$j$个神经元,误差梯度为:
$$\delta_j^{(L)} = -(y_j – z_j^{(L)}) \cdot f'(a_j^{(L)})$$

其中$f'(a_j^{(L)})$表示激活函数$f$对输入$a_j^{(L)}$的导数。

对于中间层($l = L-1, L-2, …, 2$)的第$i$个神经元,误差梯度为:
$$\delta_i^{(l)} = f'(a_i^{(l)}) \cdot \sum_j (\delta_j^{(l+1)} \cdot W_{ij}^{(l)})$$

根据上述公式,我们可以从输出层向输入层逐层计算误差梯度,然后使用梯度下降法来更新权重。

计算步骤

反向传播算法的计算步骤包括:

  1. 初始化权重。使用适当的方法(如随机初始化)为每个连接的权重赋初始值。

  2. 前向传播。对于每个训练样本,计算每个神经元的输入和输出。开始时,将输入值作为第一层的输出,然后通过每一层应用加权和激活函数来计算下一层的输出。

  3. 计算输出层的误差梯度。根据上述公式计算输出层每个神经元的误差梯度。

  4. 反向传播误差。从输出层开始,使用上述公式计算中间层每个神经元的误差梯度。

  5. 更新权重。使用梯度下降法根据误差梯度更新每个连接的权重。

  6. 重复步骤2-5,直到满足停止条件(如达到最大迭代次数或误差下降到一定程度)。

复杂Python代码示例

下面是一个复杂的Python代码示例,展示了如何使用反向传播算法训练一个神经网络。代码示例使用Python的numpy库实现了神经网络的前向传播和反向传播过程,并使用随机梯度下降法更新权重。

import numpy as np

class NeuralNetwork:
 def __init__(self, layers):
 self.layers = layers
 self.weights = [np.random.randn(y, x) for x, y in zip(layers[:-1], layers[1:])]
 self.biases = [np.random.randn(y, 1) for y in layers[1:]]

 def forward_propagation(self, a):
 for w, b in zip(self.weights, self.biases):
 a = self.activation(np.dot(w, a) + b)
 return a

 def back_propagation(self, x, y):
 activations = [x]
 zs = []
 for w, b in zip(self.weights, self.biases):
 z = np.dot(w, activations[-1]) + b
 zs.append(z)
 activation = self.activation(z)
 activations.append(activation)

 delta = self.cost_derivative(activations[-1], 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 self.activation_derivative(zs[-1])
 nabla_b = [delta]
 nabla_w = [np.dot(delta, activations[-2].T)]

 for l in range(2, self.num_layers):
 z = zs[-l]
 delta = np.dot(self.weights[-l+1].T, delta) 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 self.activation_derivative(z)
 nabla_b.append(delta)
 nabla_w.append(np.dot(delta, activations[-l-1].T))

 nabla_b = [np.mean(b, axis=1, keepdims=True) for b in reversed(nabla_b)]
 nabla_w = [np.mean(w, axis=1, keepdims=True) for w in reversed(nabla_w)]

 return nabla_b, nabla_w

 def update_weights(self, nabla_b, nabla_w, learning_rate):
 self.weights = [w - 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 nw for w, nw in zip(self.weights, nabla_w)]
 self.biases = [b - 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 nb for b, nb in zip(self.biases, nabla_b)]

 def train(self, training_data, epochs, mini_batch_size, learning_rate):
 n = len(training_data)
 for epoch in range(epochs):
 np.random.shuffle(training_data)
 mini_batches = [training_data[k:k+mini_batch_size] for k in range(0, n, mini_batch_size)]
 for mini_batch in mini_batches:
 nabla_b = [np.zeros(b.shape) for b in self.biases]
 nabla_w = [np.zeros(w.shape) for w in self.weights]
 for x, y in mini_batch:
 delta_nabla_b, delta_nabla_w = self.back_propagation(x, y)
 nabla_b = [nb + dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
 nabla_w = [nw + dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
 self.update_weights(nabla_b, nabla_w, learning_rate)

 def activation(self, z):
 return 1.0 / (1.0 + np.exp(-z))

 def activation_derivative(self, z):
 return self.activation(z) 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 - self.activation(z))

 def cost_derivative(self, output_activations, y):
 return output_activations - y

# 创建一个神经网络
network = NeuralNetwork([2, 4, 1])

# 设置训练数据
training_data = [(np.array([[0], [0]]), np.array([[0]])),
 (np.array([[0], [1]]), np.array([[1]])),
 (np.array([[1], [0]]), np.array([[1]])),
 (np.array([[1], [1]]), np.array([[0]]))]

# 训练神经网络
network.train(training_data, epochs=1000, mini_batch_size=4, learning_rate=0.1)

# 测试神经网络
for x, y in training_data:
 prediction = network.forward_propagation(x)
 print('Input:', x.T, 'Expected:', y.T, 'Prediction:', prediction.T)

代码细节解释

该代码示例中的NeuralNetwork类实现了一个简单的三层神经网络。forward_propagation方法用于计算给定输入的输出,back_propagation方法用于计算误差梯度,update_weights方法用于更新权重。train方法用于训练神经网络。

在计算误差梯度时,代码利用前向传播过程中计算的激活值和线性组合值来计算误差梯度。在更新权重时,代码使用随机梯度下降法将权重沿着梯度方向进行更新。

代码示例使用了一个简单的训练数据集,其中包含4个训练样本。通过训练神经网络,并对训练数据进行预测,可以看到神经网络经过训练后能够正确预测输入样本的输出。

希望通过以上的详细阐述,您对反向传播算法如何计算神经网络中的误差梯度有更清晰的理解。

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

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

(0)

大家都在看

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