gpt4 book ai didi

time-series - 如何使用 Pytorch 优化 LSTM 中的梯度流?

转载 作者:行者123 更新时间:2023-12-04 15:45:42 29 4
gpt4 key购买 nike

我在 lstm 中使用时间序列数据,我发现我的网络梯度存在问题。我有一层 121 个 lstm 单元。对于每个单元格,我有一个输入值,我得到一个输出值。我使用 121 个值的批量大小,并使用 batch_first = True 定义 lstm 单元格,因此我的输出是 [batch,timestep,features]。

获得输出(大小为 [121,121,1] 的张量)后,我使用 MSELoss() 计算损失,然后对其进行反向传播。这里出现了问题。查看每个单元格的梯度,我注意到前 100 个单元格(或多或少)的梯度为空。

理论上,如果我没记错的话,当我反向传播错误时,我会为每个输出计算一个梯度,所以我每个单元格都有一个梯度。如果这是真的,我不明白为什么在第一个单元格中它们为零。

有人知道发生了什么吗?

谢谢!

PS.:我给你看最后一个细胞的梯度流:
enter image description here

更新:
正如我之前尝试过的那样,我仍然有一个关于 LSTM 反向传播的问题。从下图可以看出,在一个单元格中,除了来自其他单元格的渐变之外,我认为还有另一种渐变形式本身。
enter image description here

例如,让我们看看单元格 1。我得到输出 y1 并计算损失 E1。我对其他细胞也这样做。所以,当我在单元格 1 中反向传播时,我得到 dE2/dy2 * dy2/dh1 * dh1/dw1 + ...正如@kmario23 和@DavidNg 所解释的,这是与网络中的后续单元格(BPTT)相关的梯度。而且我还有与 E1 相关的梯度( dE1/dy1 * dy1/dw1 )。第一个梯度可以在流动过程中消失,但这个梯度不会。

所以,总而言之,虽然有很长的 lstm 单元层,但据我所知,我的梯度仅与每个单元格相关,因此我不明白为什么我的梯度为零。与 E1 相关的错误会发生什么?为什么只计算bptt?

最佳答案

我已经多次处理这些问题。这是我的建议:

Use smaller number of timesteps



前一个时间步的隐藏输出传递到当前步并乘以权重。当你多次相乘时,梯度会随着时间步数的增加而呈指数爆炸或消失。
让我们说:

# it's exploding
1.01^121 = 101979 # imagine how large it is when the weight is not 1.01

# or it's vanishing
0.9^121 = 2.9063214161987074e-06 # ~ 0.0 when we init the weight smaller than 1.0

为了减少困惑,我举了一个简单的 RNNCell 的例子 - 权重 W_ihW_hh没有偏见。在你的情况下, W_hh只是一个数字,但这种情况可能适用于任何矩阵 W_hh .我们使用 indentity激活也是如此。

如果我们沿着所有时间步长展开 RNN K=3 ,我们得到:

h_1 = W_ih * x_0 + W_hh * h_0 (1)
h_2 = W_ih * x_1 + W_hh * h_1 (2)
h_3 = W_ih * x_2 + W_hh * h_2 (3)

因此,当我们需要更新权重时 W_hh ,我们必须累加步骤(1),(2),(3)中的所有梯度。

grad(W_hh) = grad(W_hh at step 1) + grad(W_hh at step 2) + grad(W_hh at step 3)

# step 3
grad(W_hh at step3) = d_loss/d(h_3) * d(h_3)/d(W_hh)
grad(W_hh at step3) = d_loss/d(h_3) * h_2


# step 2
grad(W_hh at step2) = d_loss/d(h_2) * d(h_2)/d(W_hh)
grad(W_hh at step2) = d_loss/d(h_3) * d_(h_3)/d(h_2) * d(h_2)/d(W_hh)
grad(W_hh at step2) = d_loss/d(h_3) * d_(h_3)/d(h_2) * h_1

# step 1
grad(W_hh at step1) = d_loss/d(h_1) * d(h_1)/d(W_hh)
grad(W_hh at step1) = d_loss/d(h_3) * d(h_3)/d(h_2) * d(h_2)/d(h_1) * d(h_1)/d(W_hh)
grad(W_hh at step1) = d_loss/d(h_3) * d(h_3)/d(h_2) * d(h_2)/d(h_1) * h_0

# As we also:
d(h_i)/d(h_i-1) = W_hh

# Then:
grad(W_hh at step3) = d_loss/d(h_3) * h_2
grad(W_hh at step2) = d_loss/d(h_3) * W_hh * h_1
grad(W_hh at step1) = d_loss/d(h_3) * W_hh * W_hh * h_0
Let d_loss/d(h_3) = v

# We accumulate all gradients for W_hh
grad(W_hh) = v * h_2 + v * W_hh * h_1 + v * W_hh * W_hh * h_0

# If W_hh is initialized too big >> 1.0, grad(W_hh) explode quickly (-> infinity).
# If W_hh is initialized too small << 1.0, grad(W_hh) vanishes quickly (-> 0), since h_2, h_1 are vanishing after each forward step (exponentially)

虽然 LSTM 单元有不同的门(比如忘记门减少了时间步长无关的冗长依赖)来缓解这些问题,但它会受到长时间步长的影响。关于如何设计用于学习长依赖的网络架构,对于序列数据来说仍然是一个大问题。

为避免这些问题,只需将时间步数 ( seq_len ) 减少到子序列中即可。
bs = 121
seq_len = 121
new_seq_len = seq_len // k # k = 2, 2.5 or anything to experiment

X (of [bs,seq_len, 1]) -> [ X1[bs, new_seq_len, 1], X2[bs, new_seq_len, 1],...]

然后,您通过每个小批量 Xi进入模型,使得初始隐藏为 h_(i-1)这是前一批`X(i-1)的隐藏输出
h_i = model(Xi, h_(i-1))

所以它会帮助模型学习一些长依赖作为 121 的模型。时间步长。

关于time-series - 如何使用 Pytorch 优化 LSTM 中的梯度流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55883197/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com