深度学习中的向前传播和向后传播

深度学习中的向前传播和向后传播


深度学习

在深度学习中,向前传播(Forward Propagation)和向后传播(Back Propagation)是训练神经网络的两个重要过程。

向前传播(Forward Propagation)

想象在一个迷宫中走路,目标是找到出口。在走迷宫的时候,从起点开始,每一步都根据当前的路径选择方向,直到到达终点(出口)。

  • 输入数据: 进入迷宫(给定一组输入数据)。
  • 经过各层: 每走一步都要做出一个决定(通过网络的每一层),这些决定是基于目前所看到的信息。
  • 输出结果: 走到迷宫的出口(输出一个预测结果)。

在向前传播中,我们将输入数据通过网络的每一层,逐层计算输出,直到得到最终的输出结果。

向后传播(Back Propagation)

现在发现并没有找到正确的出口,需要纠正路线。这时回头查看每一步走错的地方,重新调整你的决策,以便下一次能更接近正确的出口。

  • 计算误差: 检查到达的出口是否正确(计算预测结果和真实结果之间的误差)。
  • 传播误差: 从出口开始,沿着走过的路径,逐步回溯每一步(将误差逐层传递回去)。
  • 调整权重: 根据误差的大小,调整每一步的决策(调整网络的参数),以便下次更可能找到正确的出口。

在向后传播中,我们从输出层开始,将误差向后传递到每一层,计算每个参数的梯度,然后根据这些梯度来调整参数,使得下次向前传播时能更准确地进行预测。

梯度下降 (Gradient Descent)

在训练神经网络时,对于每一个训练批次,首先会进行一次向前传播计算输出值,然后立即进行一次向后传播来计算误差并更新权重。这种方式称为批量梯度下降(Batch Gradient Descent)。

批量梯度下降(Batch Gradient Descent):

使用整个训练集进行一次向前传播和向后传播,然后更新权重。

  • 优点: 收敛稳定,适合处理小型数据集。
  • 缺点: 计算量大,内存占用高,尤其在处理大型数据集时。

小批量梯度下降(Mini-Batch Gradient Descent):

将训练数据分成多个小批次(mini-batches),对每个小批次进行向前传播和向后传播,然后更新权重。

  • 优点: 平衡了全批次和单样本的优点,效率较高,适合大型数据集。
  • 缺点: 需要选择合适的批次大小。

随机梯度下降(Stochastic Gradient Descent, SGD):

每次使用一个样本进行向前传播和向后传播,然后更新权重。

  • 优点: 计算效率高,内存占用低,适合大型数据集。
  • 缺点: 收敛不稳定,可能会出现较大的波动。

示例代码

import numpy as np

# 定义激活函数及其导数(这里使用Sigmoid函数)
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_derivative(x):
    return x * (1 - x)

# 输入数据(假设有两个输入特征)
X = np.array([[0, 0],
              [0, 1],
              [1, 0],
              [1, 1]])

# 真实的输出(这里是一个逻辑与的例子)
y = np.array([[0], [1], [1], [0]])

# 设置随机种子(便于结果复现)
np.random.seed(42)

# 初始化权重(这里初始化为随机值)
weights = np.random.rand(2, 1)
bias = np.random.rand(1)

# 学习率
learning_rate = 0.1

# 训练次数
epochs = 10000

# 批次大小
batch_size = 2

for epoch in range(epochs):
    # 随机打乱数据
    indices = np.arange(X.shape[0])
    np.random.shuffle(indices)
    X = X[indices]
    y = y[indices]
    
    for i in range(0, X.shape[0], batch_size):
        # 获取当前批次数据
        X_batch = X[i:i + batch_size]
        y_batch = y[i:i + batch_size]

        # 向前传播
        inputs = X_batch
        z = np.dot(inputs, weights) + bias
        outputs = sigmoid(z)
        
        # 计算误差
        error = y_batch - outputs
        
        # 向后传播
        d_error = error * sigmoid_derivative(outputs)
        
        # 更新权重和偏置
        weights += np.dot(inputs.T, d_error) * learning_rate
        bias += np.sum(d_error) * learning_rate

# 打印训练后的权重和偏置
print("Weights after training:")
print(weights)
print("Bias after training:")
print(bias)

# 测试模型
test_inputs = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
test_outputs = sigmoid(np.dot(test_inputs, weights) + bias)
print("Test outputs after training:")
print(test_outputs)

每个训练周期(epoch)开始时,打乱数据顺序以确保模型不会偏向于特定的数据顺序。 将数据分成小批次,每个批次大小为 batch_size。 对每个小批次进行一次向前传播和向后传播,然后更新权重和偏置。 这种方法通过在每个小批次上更新权重,既能充分利用批量处理的优势,又能提高计算效率。