给定神经网络的反向传播Python实现及与前向传播关联问题咨询

1 反向传播导数计算的Python实现
反向传播的导数计算本质是链式求导的工程化实现,核心逻辑是从损失函数出发,从网络输出端向输入端逐层计算损失对每一层参数、每一层输出的梯度,Python实现时直接用numpy的矩阵运算完成向量化的梯度计算即可,不需要逐样本循环,计算效率更高。实现前需要提前定义好所用损失函数、激活函数的局部导数计算规则。
2 反向传播对前向传播的反馈逻辑
反向传播的核心输出是损失函数对所有前向传播用到的权重(W0/W1/W2)、偏置(B0/B1/B2)的梯度,梯度的正负和大小直接指示了参数调整的方向和幅度:如果损失对某参数的梯度为正,说明调大该参数会让损失升高,因此我们会用参数值减去学习率乘以梯度的结果完成参数更新。更新后的参数会直接用于下一次前向传播的计算,让前向输出的预测值逐步逼近真实标签,降低预测误差。
3 对应给定网络结构的反向传播Python实现
以下实现默认使用均方误差作为损失函数,输入维度为(特征数, 批量大小),和你给出的前向传播矩阵乘法逻辑匹配,如果你的输入维度是(批量大小, 特征数),对应调整矩阵乘法的转置位置即可:
import numpy as np # 自定义unit激活的导数,示例为ReLU的导数,可根据实际使用的激活函数替换 def unit_activation_deriv(G): return np.where(G > 0, 1, 0) # 反向传播函数,需要传入前向传播时保存的所有中间变量、真实标签和学习率lr def back_propagation(X, W0, B0, G0, H0, W1, B1, G1, H1, W2, B2, G2, H2, Y_true, lr): batch_size = X.shape[1] # 损失层梯度:均方误差对网络输出Yhat的导数 dLoss_dYhat = 2 * (H2 - Y_true) / batch_size # 输出层tanh激活梯度 dLoss_dG2 = dLoss_dYhat * (1 - H2 ** 2) # W2、B2梯度计算 dLoss_dW2 = np.matmul(dLoss_dG2, H1.T) dLoss_dB2 = np.sum(dLoss_dG2, axis=1, keepdims=True) # 往回传递的梯度 dLoss_dH1 = np.matmul(W2.T, dLoss_dG2) # 第一层unit激活梯度 dLoss_dG1 = dLoss_dH1 * unit_activation_deriv(G1) # W1、B1梯度计算 dLoss_dW1 = np.matmul(dLoss_dG1, H0.T) dLoss_dB1 = np.sum(dLoss_dG1, axis=1, keepdims=True) # 往回传递的梯度 dLoss_dH0 = np.matmul(W1.T, dLoss_dG1) # 输入层unit激活梯度 dLoss_dG0 = dLoss_dH0 * unit_activation_deriv(G0) # W0、B0梯度计算 dLoss_dW0 = np.matmul(dLoss_dG0, X.T) dLoss_dB0 = np.sum(dLoss_dG0, axis=1, keepdims=True) # 参数更新,更新后的参数直接用于下一次前向传播 W0 -= lr * dLoss_dW0 B0 -= lr * dLoss_dB0 W1 -= lr * dLoss_dW1 B1 -= lr * dLoss_dB1 W2 -= lr * dLoss_dW2 B2 -= lr * dLoss_dB2 return W0, B0, W1, B1, W2, B2
使用时只需要在每次前向传播计算完所有中间变量后,调用该函数即可完成参数更新。如果使用交叉熵等其他损失函数,只需要替换dLoss_dYhat的计算逻辑即可。
内容的提问来源于stack exchange,提问作者Bogdan
相关产品推荐
相关产品推荐

