【剑指offer】反向传播

系列文章目录

BN层详解
梯度消失和梯度爆炸
交叉熵损失函数
1*1卷积的作用


文章目录

  • 系列文章目录
  • 什么是反向传播
  • 反向传播的过程
  • 部分过程详解
    • (1)前向传播
    • (2)计算梯度和更新参数
  • 代码理解


什么是反向传播

深度学习中的反向传播(Backpropagation)是一种基于梯度下降法的优化方法,用于计算神经网络中每个参数的梯度值,以便利用梯度下降法或其他优化方法来更新参数,从而最小化损失函数。

反向传播的基本思想是通过链式法则计算整个神经网络中每个参数对损失函数的贡献,以便利用梯度下降法来更新参数。具体来说,反向传播算法从输出层开始,将输出误差反向传播到隐藏层和输入层,计算每个神经元的误差和梯度,并使用梯度下降法来更新参数。反向传播算法的关键在于计算每个神经元的误差和梯度,这可以通过链式法则来实现。

在深度学习中,反向传播是一种非常重要的优化方法,可以用于训练各种类型的神经网络,包括卷积神经网络、循环神经网络和自编码器等。反向传播算法的优化和改进也一直是深度学习研究的热点之一。

反向传播的过程

反向传播是深度学习中最基本的优化方法之一,用于计算神经网络中每个参数的梯度值,以便利用梯度下降法或其他优化方法来更新参数,从而最小化损失函数。反向传播的过程可以分为以下几个步骤:

假设我们有一个多层前馈神经网络,其中包含输入层、若干个隐藏层和输出层,每个神经元都有权重和偏差。我们的目标是最小化损失函数。

  1. 前向传播:将输入数据输入到网络中,通过神经网络的前向传播计算出每个神经元的输出结果,直到输出层输出最终的结果。
  2. 计算损失函数:将神经网络输出的结果与真实标签进行比较,计算出损失函数的值。
  3. 反向传播误差:从输出层开始,计算每个神经元的误差,然后向前计算每个神经元的误差,直到计算出输入层每个神经元的误差。具体来说,我们首先计算输出层的误差,然后反向传播到前一层隐藏层,计算隐藏层的误差,并将误差反向传播到更早的层,直到计算出输入层的误差。这个过程可以使用链式法则来计算。
  4. 计算梯度:根据误差计算每个神经元的梯度,即损失函数对每个神经元权重和偏差的偏导数。
  5. 更新参数:使用梯度下降法或其他优化方法来更新每个神经元的权重和偏差,使得损失函数的值最小化。

重复上述步骤,直到达到收敛条件或达到预设的训练次数。通过反向传播算法,神经网络可以根据给定的输入和输出数据进行训练,并逐步优化网络参数,从而得到更准确的预测结果。

部分过程详解

(1)前向传播

前向传播是计算神经网络输出的过程。在前向传播中,输入信号通过神经网络的所有层,最终得到输出信号。这个过程可以看作是一个函数的计算过程,函数的输入是神经网络的输入数据,输出是神经网络的输出数据。在计算神经网络的输出时,需要使用神经元的权重和偏置值进行计算。
具体来说,前向传播的过程如下:

  1. 将输入数据传递给输入层的神经元。
  2. 计算输入层神经元的输出,即将输入数据乘以神经元的权重,再加上神经元的偏置值,最后使用激活函数进行非线性变换。这样可以得到输入层的输出信号。
  3. 将输入层的输出信号传递给下一层的神经元。
  4. 重复步骤2和3,直到所有层的神经元都计算完毕,得到神经网络的输出信号。
  5. 将输出信号与真实的标签进行比较,计算损失函数的值。

将损失函数的值作为反向传播的起点,使用链式法则计算每个神经元的梯度,以便进一步更新神经元的权重和偏置值。
在前向传播中,每个神经元都扮演着一个函数的角色,将输入信号转换为输出信号。这些函数的参数是神经元的权重和偏置值。因此,在反向传播中,需要计算每个神经元函数的梯度,以便更新神经元的参数,以最小化损失函数。

(2)计算梯度和更新参数

反向传播算法中的计算梯度和更新参数部分是整个算法的核心。在前向传播过程中,神经元的输出由输入和参数共同决定。在反向传播过程中,需要计算损失函数对每个参数的偏导数,以确定梯度方向。然后,使用梯度下降法或其他优化方法来更新参数,以最小化损失函数。

反向传播算法的计算梯度和更新参数部分可以分为以下步骤:

  1. 计算输出层神经元的梯度。输出层神经元的梯度可以通过损失函数的导数和激活函数的导数来计算。具体来说,输出层神经元的梯度等于损失函数对神经元输出的偏导数乘以激活函数对神经元加权和的偏导数。
  2. 计算隐藏层神经元的梯度。隐藏层神经元的梯度可以通过链式法则来计算。具体来说,隐藏层神经元的梯度等于该神经元输出对下一层神经元加权和的偏导数乘以下一层神经元梯度对该神经元输出的偏导数。
  3. 计算参数的梯度。对于每个参数,需要计算损失函数对该参数的偏导数。具体来说,对于权重矩阵中的每个元素,需要计算损失函数对该元素的偏导数。对于偏置向量中的每个元素,需要计算损失函数对该元素的偏导数。
  4. 更新参数。使用梯度下降法或其他优化方法来更新参数。具体来说,对于权重矩阵中的每个元素,需要将该元素减去学习率乘以该元素的梯度。对于偏置向量中的每个元素,需要将该元素减去学习率乘以该元素的梯度。
    (具体地,可以使用随机梯度下降法(SGD)等优化算法来更新参数,公式如下: w = w - learning_rate * dw b = b - learning_rate * db 其中,w和b分别表示神经元的权重和偏置,dw和db分别表示相应的梯度,learning_rate表示学习率,用于控制参数更新的步长。)
  5. 重复步骤1到4,直到达到停止条件。

在实现反向传播算法时,需要注意梯度消失和梯度爆炸的问题。梯度消失和梯度爆炸可能会导致算法无法更新参数,从而影响模型的训练效果。为了解决这个问题,可以使用一些技巧,例如梯度裁剪、权重初始化和正则化等方法。其中,梯度裁剪可以防止梯度爆炸,即限制梯度的最大值,以避免梯度过大。权重初始化可以使神经元的输出均匀分布,从而避免梯度消失。正则化可以通过限制参数的大小来避免过拟合,从而提高模型的泛化能力。也可以参考系列文章:梯度消失和梯度爆炸

总之,在反向传播算法中,计算梯度和更新参数是非常重要的步骤。通过计算参数的梯度,并使用梯度下降法或其他优化方法来更新参数,可以最小化损失函数,从而提高模型的准确性。而为了处理梯度消失和梯度爆炸的问题,需要使用一些技巧来优化算法。

代码理解

以下是一个简单的Python代码示例,用于说明反向传播过程的实现:

假设我们有一个三层神经网络,包含一个输入层、一个隐藏层和一个输出层,其中输入层有两个神经元,隐藏层有三个神经元,输出层有一个神经元。我们使用sigmoid作为激活函数,并使用均方误差作为损失函数。

import numpy as np


# 激活函数sigmoid
def sigmoid(x):
	return 1 / (1 + np.exp(-x))


# 损失函数均方误差
def mse_loss(y_true, y_pred):
	return np.mean(np.square(y_true - y_pred))


# 前向传播
def forward_propagation(X, W1, b1, W2, b2):
	hidden_layer_output = sigmoid(np.dot(X, W1) + b1)
	y_pred = sigmoid(np.dot(hidden_layer_output, W2) + b2)
	return hidden_layer_output, y_pred


# 反向传播
def backward_propagation(X, y_true, hidden_layer_output, y_pred, W1, b1, W2, b2):
	# 计算输出层误差
	output_error = y_pred - y_true
	output_delta = output_error * y_pred * (1 - y_pred)

	# 计算隐藏层误差
	hidden_error = np.dot(output_delta, W2.T)
	hidden_delta = hidden_error * hidden_layer_output * (1 - hidden_layer_output)

	# 计算梯度
	dW2 = np.dot(hidden_layer_output.T, output_delta)
	db2 = np.sum(output_delta, axis=0, keepdims=True)
	dW1 = np.dot(X.T, hidden_delta)
	db1 = np.sum(hidden_delta, axis=0, keepdims=True)

	return dW1, db1, dW2, db2


# 训练模型
def train(X, y_true, hidden_units, epochs, learning_rate):
	# 初始化参数
	input_units = X.shape[1]
	output_units = y_true.shape[1]
	W1 = np.random.randn(input_units, hidden_units)
	b1 = np.zeros((1, hidden_units))
	W2 = np.random.randn(hidden_units, output_units)
	b2 = np.zeros((1, output_units))

	# 迭代训练
	for i in range(epochs):
		# 前向传播
		hidden_layer_output, y_pred = forward_propagation(X, W1, b1, W2, b2)

		# 计算损失函数
		loss = mse_loss(y_true, y_pred)

		# 反向传播
		dW1, db1, dW2, db2 = backward_propagation(X, y_true, hidden_layer_output, y_pred, W1, b1, W2, b2)

		# 更新参数
		W1 -= learning_rate * dW1
		b1 -= learning_rate * db1
		W2 -= learning_rate * dW2
		b2 -= learning_rate * db2

		# 打印损失函数
		if i % 1000 == 0:
			print("Epoch %d: loss = %f" % (i, loss))

	# 返回训练好的模型参数
	return W1, b1, W2, b2


X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y_true = np.array([[0], [1], [1], [0]])
W1, b1, W2, b2 = train(X, y_true, hidden_units=3, epochs=10000, learning_rate=0.1)
_, y_pred = forward_propagation(X, W1, b1, W2, b2)
print("Predictions: \n", y_pred)

你可能感兴趣的:(剑指offer,深度学习,神经网络,cnn)