You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用单隐藏层前馈神经网络拟合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

错误原因分析

  1. 未初始化vec_wght1和vec_wght2:这两个变量在第一次循环时是None,执行vec_wght1 -= lrng_rate * wght1.grad时,None无法与数值进行运算,直接触发类型错误。
  2. 权重更新方式不符合PyTorch规范:直接对张量重新赋值(如wght1 = vec_wght1)会破坏原有的计算图关联,且未清零梯度会导致后续反向传播时梯度累加,影响训练效果。

修正方案

  1. 直接在原权重张量上执行更新操作,无需额外临时变量。
  2. 使用with torch.no_grad():上下文管理器执行权重更新,避免追踪更新操作的梯度。
  3. 每次更新后手动清零梯度,防止梯度累加。
  4. 将输入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:45:33