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

使用torch.nn.utils.clip_grad_norm_()遇RuntimeError:stack期望非空TensorList

问题分析与解决方案

这个问题我之前调试模型时也碰到过,核心是你的代码执行顺序完全搞反了,导致梯度还没生成就调用了梯度裁剪函数!

报错的直接原因

看你的代码流程:

for epoch in progress_bar(range(num_epochs)):
    lstm.train()
    outputs = lstm(trainX.to(device))
    optimizer.zero_grad()
    torch.nn.utils.clip_grad_norm_(lstm.parameters(), 1)

这里存在两个关键缺失:

  1. 没有计算损失(Loss):你只执行了前向传播得到输出,但没有和训练标签计算损失值;
  2. 没有执行反向传播:损失值是触发梯度计算的核心,只有调用loss.backward()后,模型参数的grad属性才会被赋值。

在这种情况下,所有参数的grad都是None,当clip_grad_norm_尝试把这些空的梯度张量堆叠起来计算范数时,就会抛出RuntimeError: stack expects a non-empty TensorList——因为根本没有有效的梯度张量可以处理。

关于Parameter和Tensor的疑问

你提到lstm.parameters()返回的是Parameter列表而非Tensor列表,其实这完全没问题:torch.nn.Parameter是torch.Tensor的子类,它本质上就是带requires_grad=True属性的特殊Tensor,完全符合clip_grad_norm_对输入参数的要求,这不是报错的原因。

正确的代码流程

调整顺序,确保梯度生成后再执行裁剪,完整流程如下:

for epoch in progress_bar(range(num_epochs)):
    lstm.train()
    optimizer.zero_grad()  # 先清空上一轮残留的梯度
    outputs = lstm(trainX.to(device))  # 前向传播得到输出
    # 关键步骤1:计算损失(需要替换成你实际使用的损失函数)
    loss = torch.nn.functional.mse_loss(outputs, trainY.to(device))  
    # 关键步骤2:反向传播,生成参数梯度
    loss.backward()
    # 现在梯度已存在,可以执行裁剪
    torch.nn.utils.clip_grad_norm_(lstm.parameters(), 1)
    # 最后更新模型参数
    optimizer.step()

额外提示

如果你的模型有部分参数被冻结(设置了requires_grad=False),这些参数的grad会是None,但clip_grad_norm_会自动忽略它们,只要至少有一个参数有有效梯度,就不会触发这个报错。

内容的提问来源于stack exchange,提问作者Brian Feeny

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 09:02:43