使用单隐藏层前馈神经网络拟合f(x)=x²时反向传播权重更新报错
问题:前馈神经网络反向传播权重更新报错"unsupported operand type(s) for *: 'float' and 'NoneType'"
尝试用含1个隐藏层(2个神经元)的前馈神经网络拟合函数f(x)=x²,但反向传播阶段无法更新权重,执行代码第19行时触发错误:
unsupported operand type(s) for *: 'float' and 'NoneType'
原代码如下:
import numpy as np import matplotlib.pyplot as plt import torch f = lambda x: x**2 x = np.linspace(-2,2,40) wght1 = torch.rand(2,1,requires_grad = True) wght2 = torch.rand(1,2,requires_grad = True) def sigmoid(val): return(1/(1+torch.exp(-val))) for loop in range(200): loss = 0 lrng_rate = 0.001 for i in range(len(x)): y_pred = torch.mm(wght2, sigmoid(wght1 * x[i])) loss = loss + (f(x[i])-y_pred)**2 loss = torch.mean(loss) loss.backward() #weights update vec_wght1 -= lrng_rate * wght1.grad #line 19 wght1 = vec_wght1 #line 20 vec_wght2 -= lrng_rate * wght2.grad #line 21 wght2 = vec_wght2 #line 22
错误原因分析
- 未初始化
vec_wght1和vec_wght2:这两个变量在第一次循环时是None,执行vec_wght1 -= lrng_rate * wght1.grad时,None无法与数值进行运算,直接触发类型错误。 - 权重更新方式不符合PyTorch规范:直接对张量重新赋值(如
wght1 = vec_wght1)会破坏原有的计算图关联,且未清零梯度会导致后续反向传播时梯度累加,影响训练效果。
修正方案
- 直接在原权重张量上执行更新操作,无需额外临时变量。
- 使用
with torch.no_grad():上下文管理器执行权重更新,避免追踪更新操作的梯度。 - 每次更新后手动清零梯度,防止梯度累加。
- 将输入
x转为PyTorch张量,统一计算流程。
修正后的代码:
import numpy as np import matplotlib.pyplot as plt import torch f = lambda x: x**2 # 将输入转为PyTorch张量并增加维度,适配矩阵运算 x = torch.tensor(np.linspace(-2, 2, 40), dtype=torch.float32).unsqueeze(1) # 初始化可训练权重 wght1 = torch.rand(2, 1, requires_grad=True) wght2 = torch.rand(1, 2, requires_grad=True) def sigmoid(val): return 1 / (1 + torch.exp(-val)) lrng_rate = 0.01 # 调大学习率,提升收敛速度 for loop in range(200): loss = 0.0 for xi in x: # 前向传播:隐藏层计算 -> 输出层预测 hidden_out = sigmoid(torch.matmul(wght1, xi)) y_pred = torch.matmul(wght2, hidden_out) loss += (f(xi) - y_pred) ** 2 loss = torch.mean(loss) loss.backward() # 权重更新:在no_grad上下文下操作,避免追踪梯度 with torch.no_grad(): wght1 -= lrng_rate * wght1.grad wght2 -= lrng_rate * wght2.grad # 清零梯度,防止下一次反向传播时梯度累加 wght1.grad.zero_() wght2.grad.zero_() # 打印训练进度(可选) if (loop + 1) % 20 == 0: print(f"Epoch {loop+1}, Loss: {loss.item():.4f}") # 可视化拟合结果 with torch.no_grad(): y_preds = [] for xi in x: hidden_out = sigmoid(torch.matmul(wght1, xi)) y_pred = torch.matmul(wght2, hidden_out) y_preds.append(y_pred.item()) plt.scatter(x.numpy(), f(x).numpy(), label='True f(x)=x²') plt.plot(x.numpy(), y_preds, color='red', label='NN Prediction') plt.legend() plt.show()
额外说明
- 调大学习率是因为原学习率过小,会导致训练收敛极慢。
- 使用
torch.matmul替代torch.mm,兼容性更强,支持更多维度的张量运算。 - 加入可视化代码,方便直观查看神经网络的拟合效果。
内容的提问来源于stack exchange,提问作者Tan
相关产品推荐
相关产品推荐

