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

PyTorch LSTM输出对输入的自动导数错误、输入子集输出不匹配问题

PyTorch LSTM相同输入值输出不一致、自动导数与数值导数存在偏差问题

我正在使用LSTM(长短期记忆神经网络)进行特定时间序列学习,其具体应用场景此处不做展开。
在计算PyTorch LSTM输出相对于输入的自动导数时,我发现部分输入区间的结果与数值导数相比存在偏差。
此外,输入原始输入的子集时,得到的输出与原输入对应的输出不一致。我刚接触循环神经网络,对这类异常行为的成因不了解,希望有人可以帮忙解释。
该问题可通过以下单输入单输出的简单LSTM最小复现代码复现:

import torch
from torch import nn
from torch import autograd
import matplotlib.pyplot as plt

### USER INPUT
input_dim = 1
hidden_dim = 20
num_layers = 1
output_dim = 1

# PyTorch随机数生成器种子固定
torch.manual_seed(1234)


### 模型定义
class Lstm(nn.Module):
    """简易长短期记忆神经网络"""
    def __init__(self, input_dim: int, hidden_dim: int, num_layers: int, output_dim: int):
        """初始化简易LSTM

        参数
        ----------
        input_dim : int
            神经网络输入维度
        hidden_dim : int
            神经网络隐藏层维度
        num_layers : int
            神经网络隐藏层数
        output_dim : int
            神经网络输出维度
        """
        # 调用父类初始化方法
        super().__init__()

        # 存储参数
        self.input_dim = input_dim
        self.hidden_dim = hidden_dim
        self.num_layers = num_layers

        # 循环神经网络层
        self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers, batch_first=True)

        # 全连接层
        self.fc = nn.Linear(hidden_dim, output_dim)

    def forward(self, input: torch.Tensor) -> torch.Tensor:
        """LSTM前向传播

        参数
        ----------
        input : torch.Tensor
            神经网络输入
        Returns
        -------
        torch.Tensor
            神经网络输出
        """

        t = input.float().unsqueeze(0)

        # 初始化隐藏层与细胞状态
        batch_size = 1  # 简化起见仅使用单batch
        hidden = torch.zeros(self.num_layers, batch_size, self.hidden_dim)
        cell = torch.zeros(self.num_layers, batch_size, self.hidden_dim)

        # 输入与隐藏状态传入模型得到输出
        out, hidden = self.lstm(t, (hidden, cell))

        # 调整输出维度适配全连接层
        out = out.squeeze()
        out = self.fc(out)

        return out


### 计算逻辑
# 创建单输入单输出维度的LSTM
my_lstm = Lstm(input_dim, hidden_dim, num_layers, output_dim)

# 构造两组重叠的时间序列输入
times1 = torch.linspace(0.0, 1.0, 100).unsqueeze(1)
times2 = torch.linspace(0.2, 1.0, 80).unsqueeze(1)
times1.requires_grad = True
times2.requires_grad = True

# 神经网络前向计算
outputs1 = my_lstm.forward(times1)
outputs2 = my_lstm.forward(times2)

# 计算第一组时间序列的自动导数
auto_deriv1 = autograd.grad(outputs1,
                            times1,
                            torch.ones(times1.shape),
                            retain_graph=True,
                            create_graph=True)[0]

# 计算第一组时间序列的数值导数
numeric_deriv1 = (outputs1[1:-1] - outputs1[0:-2]) / (times1[1:-1] - times1[0:-2])

# 绘制输出对比图
plt.figure()
plt.plot(times1.detach().numpy(), outputs1.detach().numpy(), 'b')
plt.plot(times2.detach().numpy(), outputs2.detach().numpy(), 'r')
plt.grid("on")
plt.xlabel("LSTM输入")
plt.ylabel("LSTM输出")
plt.legend(["完整时间序列", "后半段时间序列"])
plt.savefig("lstm_output.png")

# 绘制第一组时间序列的导数对比图
plt.figure()
plt.plot(times1.detach().numpy(), auto_deriv1.detach().numpy(), 'b')
plt.plot(times1.detach().numpy()[0:-2], numeric_deriv1.detach().numpy(), 'b--')
plt.grid("on")
plt.xlabel("LSTM输入")
plt.ylabel("LSTM输出导数")
plt.legend(["自动导数", "数值导数"])
plt.savefig("lstm_derivatives.png")

我得到的结果图如下:

  1. 两个时间序列的LSTM输出,我原本预期两条曲线应该完全重合。
    两个时间序列的LSTM输出
  2. LSTM输出相对于输入的自动导数与数值导数对比,我原本预期两条曲线应该完全一致。
    LSTM输出对输入的自动导数与数值导数对比
    由于偏差主要出现在时间序列的起始段,我猜测这和所用神经网络的循环特性有关,但我无法理解为什么相同的输入值没有得到相同的输出,也不清楚自动导数错误的原因,恳请各位解答。

问题解答

两个异常表现本质上都是LSTM的固有特性,不存在框架bug或代码逻辑错误:

  1. 相同输入输出不一致的原因
    LSTM当前时刻的输出不止取决于当前输入,还取决于之前所有时刻输入累积更新得到的隐藏状态、细胞状态。你两次前向传播时都将状态初始化为全0:
    • 完整序列times1输入时,0.2对应第20个时间步的输入,此时的状态已经经过前19个时间步的更新,不是初始全0值
    • 后半段序列times2输入时,0.2对应第一个时间步的输入,此时的状态为初始全0值
      输入相同但状态不同,输出自然存在差异,偏差会随着时间步推移逐渐缩小,和你观察到的曲线后半段几乎重合的现象完全吻合。
  2. 自动导数与数值导数不一致的原因
    你计算的数值导数是相邻时刻输出差除以输入差,本质上包含了当前输出对历史所有输入的梯度贡献,属于全导数近似;而autograd.grad计算的自动导数是当前时刻输出对当前时刻输入的偏导数,不包含历史输入的梯度影响,两者物理意义本身就不同,自然不会完全匹配。

内容的提问来源于stack exchange,提问作者Waldemar Martens

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 16:45:00