正向传播和反向传播

张开发
2026/4/13 11:32:20 15 分钟阅读

分享文章

正向传播和反向传播
正向传播和反向传播这是神经网络训练的两个核心过程就像呼吸一样缺一不可。1. 直观理解想象你在射箭正向传播你拉弓、瞄准、射箭 从输入到输出计算损失看箭离靶心有多远 反向传播分析原因调整姿势 从输出往回调整2. 正向传播Forward Propagation信息从输入流向输出的过程。importtorchimporttorch.nnasnn# 创建一个简单的网络classSimpleNet(nn.Module):def__init__(self):super().__init__()self.fc1nn.Linear(2,4)# 输入2维 → 隐藏层4维self.fc2nn.Linear(4,1)# 隐藏层4维 → 输出1维self.relunn.ReLU()defforward(self,x):print(f输入层:{x.shape})h1self.fc1(x)print(f线性变换后:{h1.shape})a1self.relu(h1)print(f激活后:{a1.shape})outputself.fc2(a1)print(f输出层:{output.shape})returnoutput# 正向传播演示modelSimpleNet()xtorch.tensor([[1.0,2.0]])# 输入ymodel(x)# 正向传播正向传播的步骤输入 x ↓ 线性变换: h W₁x b₁ ↓ 激活函数: a ReLU(h) ↓ 线性变换: output W₂a b₂ ↓ 输出 y_pred3. 反向传播Backward Propagation从损失函数开始逆向计算梯度的过程。# 完整的正向反向传播示例modelSimpleNet()xtorch.tensor([[1.0,2.0]])y_truetorch.tensor([[3.0]])# 真实值# 正向传播y_predmodel(x)print(f预测值:{y_pred.item():.4f})# 计算损失loss_fnnn.MSELoss()lossloss_fn(y_pred,y_true)print(f损失:{loss.item():.4f})# 反向传播计算梯度loss.backward()print(f\n梯度信息:)print(ffc1.weight 梯度:{model.fc1.weight.grad.shape})print(ffc1.bias 梯度:{model.fc1.bias.grad.shape})print(ffc2.weight 梯度:{model.fc2.weight.grad.shape})print(ffc2.bias 梯度:{model.fc2.bias.grad.shape})4. 详细过程可视化importtorchimporttorch.nnasnnimporttorch.nn.functionalasF# 更详细的示例展示每一步的数值classDetailedNet(nn.Module):def__init__(self):super().__init__()# 固定权重以便理解self.w1nn.Parameter(torch.tensor([[0.5,-0.2],[0.3,0.8],[-0.1,0.4],[0.6,-0.3]]))self.b1nn.Parameter(torch.tensor([0.1,-0.1,0.2,-0.2]))self.w2nn.Parameter(torch.tensor([[0.4,-0.5,0.3,0.7]]))self.b2nn.Parameter(torch.tensor([0.1]))defforward(self,x):# 第1层z1x self.w1.Tself.b1 a1F.relu(z1)# 第2层z2a1 self.w2.Tself.b2 a2z2# 线性输出returnz1,a1,z2,a2# 数据xtorch.tensor([[1.0,2.0]])y_truetorch.tensor([[5.0]])modelDetailedNet()print(*50)print(正向传播详细过程)print(*50)# 正向传播z1,a1,z2,y_predmodel(x)print(f输入 x:{x.numpy()})print(f\n第1层线性变换 z1 x·W1 b1:)print(fz1 {z1.detach().numpy()})print(f\n第1层激活 a1 ReLU(z1):)print(fa1 {a1.detach().numpy()})print(f\n第2层线性变换 y_pred a1·W2 b2:)print(fy_pred {y_pred.item():.4f})# 计算损失lossF.mse_loss(y_pred,y_true)print(f\n损失 Loss MSE(y_pred, y_true) {loss.item():.4f})print(\n*50)print(反向传播过程链式法则)print(*50)# 反向传播loss.backward()print(f\n梯度 ∂Loss/∂y_pred {2*(y_pred-y_true).item():.4f})print(f\n第2层权重梯度:)print(f∂Loss/∂W2 {model.w2.grad.numpy()})print(f\n第2层偏置梯度:)print(f∂Loss/∂b2 {model.b2.grad.item():.4f})print(f\n第1层权重梯度:)print(f∂Loss/∂W1 {model.w1.grad.numpy()})print(f\n第1层偏置梯度:)print(f∂Loss/∂b1 {model.b1.grad.numpy()})5. 链式法则反向传播的核心反向传播基于微积分中的链式法则# 数学原理# 损失 L 依赖于参数 W1, W2# L f(g(h(W1, W2)))# 链式法则# ∂L/∂W1 ∂L/∂y_pred × ∂y_pred/∂a1 × ∂a1/∂z1 × ∂z1/∂W1# (∂L/∂y_pred) × (W2) × (激活函数导数) × (x)# 数值示例defchain_rule_demo():# 假设我们在某个中间点grad_from_above2.0# 来自上层的梯度w20.5# 权重relu_grad1.0# ReLU导数正区间x3.0# 输入# 计算对 w1 的梯度grad_w1grad_from_above*w2*relu_grad*xprint(f梯度 ∂L/∂w1 {grad_w1})chain_rule_demo()6. 完整训练循环importtorchimporttorch.nnasnnimportmatplotlib.pyplotasplt# 创建数据xtorch.linspace(-3,3,100).reshape(-1,1)y_truetorch.sin(x)torch.randn(100,1)*0.1# 简单网络modelnn.Sequential(nn.Linear(1,10),nn.ReLU(),nn.Linear(10,10),nn.ReLU(),nn.Linear(10,1))loss_fnnn.MSELoss()optimizertorch.optim.SGD(model.parameters(),lr0.01)# 存储损失值losses[]print(训练过程)print(*60)forepochinrange(200):# 正向传播 y_predmodel(x)lossloss_fn(y_pred,y_true)# 反向传播 optimizer.zero_grad()# 清空旧梯度loss.backward()# 计算新梯度optimizer.step()# 更新参数losses.append(loss.item())ifepoch%400:print(fEpoch{epoch:3d}| Loss {loss.item():.4f})# 可视化结果plt.figure(figsize(12,4))plt.subplot(1,2,1)plt.plot(losses)plt.xlabel(Epoch)plt.ylabel(Loss)plt.title(损失下降曲线)plt.subplot(1,2,2)plt.scatter(x,y_true,alpha0.5,label真实值)plt.scatter(x,model(x).detach(),alpha0.5,label预测值)plt.xlabel(x)plt.ylabel(y)plt.legend()plt.title(拟合效果)plt.show()7. 可视化反向传播流程# 手动实现反向传播展示每一步defmanual_backprop():print(反向传播的梯度流动)print(*50)# 假设我们有一个简单的计算图# x → (乘2) → y → (平方) → z → (求和) → lossxtorch.tensor([3.0],requires_gradTrue)# 正向传播yx*2# y 6zy**2# z 36lossz.sum()# loss 36print(f正向传播:)print(f x {x.item():.1f})print(f y x × 2 {y.item():.1f})print(f z y² {z.item():.1f})print(f loss z {loss.item():.1f})# 反向传播loss.backward()print(f\n反向传播梯度流动:)print(f ∂loss/∂z 1.0)print(f ∂loss/∂y ∂loss/∂z × ∂z/∂y 1 × 2y {2*y.item():.1f})print(f ∂loss/∂x ∂loss/∂y × ∂y/∂x {2*y.item()}× 2 {x.grad.item():.1f})print(f\n最终梯度: ∂loss/∂x {x.grad.item():.1f})manual_backprop()8. 关键概念对比方面正向传播反向传播方向输入 → 输出输出 → 输入目的计算预测值计算梯度数据流激活值梯度计算内容z Wx b, a f(z)∂L/∂W, ∂L/∂b频率每个样本都要每个样本都要依赖依赖输入和参数依赖损失和正向结果9. 为什么需要两者# 类比学习投篮classShootingExample:def__init__(self):self.arm_angle45# 参数1self.power50# 参数2defforward(self,distance):正向传播投篮# 根据当前参数投篮scoreself._shoot(distance,self.arm_angle,self.power)returnscoredefbackward(self,score,target):反向传播分析调整# 计算误差errortarget-score# 分析原因梯度iferror0:# 投短了angle_grad1# 增加角度power_grad1# 增加力量else:# 投过了angle_grad-1# 减少角度power_grad-1# 减少力量# 调整参数self.arm_angle0.1*angle_grad self.power0.1*power_gradreturnerror# 学习过程shooterShootingExample()forattemptinrange(10):scoreshooter.forward(distance10)errorshooter.backward(score,target100)print(f尝试{attempt1}: 分数{score:.1f}, 误差{error:.1f})10. 实际训练检查点definspect_gradients(model):检查梯度是否正常print(\n梯度检查:)forname,paraminmodel.named_parameters():ifparam.gradisnotNone:grad_normparam.grad.norm().item()grad_meanparam.grad.mean().item()print(f{name}:)print(f 范数 {grad_norm:.6f})print(f 均值 {grad_mean:.6f})# 检查梯度消失/爆炸ifgrad_norm1e-6:print(f ⚠️ 警告梯度消失)elifgrad_norm1e3:print(f ⚠️ 警告梯度爆炸)# 使用示例modelSimpleNet()xtorch.randn(1,2)y_truetorch.randn(1,1)y_predmodel(x)lossF.mse_loss(y_pred,y_true)loss.backward()inspect_gradients(model)总结神经网络训练 循环重复以下过程 ┌─────────────────────────────────────────┐ │ 正向传播 │ │ 输入 → 计算 → 输出 → 损失 │ │ 让我看看现在猜得怎么样 │ └─────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────┐ │ 反向传播 │ │ 损失 → 梯度 → 更新参数 │ │ 让我分析误差调整策略 │ └─────────────────────────────────────────┘ ↓ 重复直到收敛记住正向传播问问题得到答案反向传播分析错误改进方法缺一不可只有正向无法学习只有反向没有意义

更多文章