损失函数的爆炸式增长,LSTM 自动编码器

Posted

技术标签:

【中文标题】损失函数的爆炸式增长,LSTM 自动编码器【英文标题】:Explosion in loss function, LSTM autoencoder 【发布时间】:2020-07-01 17:53:16 【问题描述】:

我正在训练一个 LSTM 自动编码器,但损失函数会随机上升,如下图所示: 我尝试了多种方法来防止这种情况,调整批量大小,调整层中的神经元数量,但似乎没有任何帮助。我检查了我的输入数据以查看它是否包含 null / infinity 值,但它没有,它也被标准化。这是我的参考代码:

model = Sequential()
model.add(Masking(mask_value=0, input_shape=(430, 3)))
model.add(LSTM(100, dropout=0.2, recurrent_dropout=0.2, activation='relu'))
model.add(RepeatVector(430))
model.add(LSTM(100, dropout=0.2, recurrent_dropout=0.2, activation='relu', return_sequences=True))
model.add(TimeDistributed(Dense(3)))
model.compile(optimizer='adam', loss='mean_squared_error', metrics=['accuracy'])

context_paths = loadFile()
X_train, X_test = train_test_split(context_paths, test_size=0.20)

history = model.fit(X_train, X_train, epochs=1, batch_size=4, verbose=1, validation_data=(X_test, X_test))

损失函数在随机时间点爆炸,有时更快,有时更晚。我阅读了this 线程中可能存在的问题,但是在尝试了多种方法之后,我不知道该怎么做才能防止损失函数随机飙升。任何建议表示赞赏。除此之外,我可以看到我的准确性并没有提高很多,所以问题可能是相互关联的。

【问题讨论】:

今天同样的问题!我不知道为什么!我正在使用 Adam 作为基础优化器构建 LSTM 自动编码器。 【参考方案1】:

两个要点:

第 1 点正如 Daniel Möller 所强调的: 不要对 LSTM 使用“relu”,保留标准激活“tanh”。

第二点:修复爆炸梯度的一种方法是使用 clipnormclipvalue 作为优化器

在最后两行尝试这样的操作

对于clipnorm

opt = tf.keras.optimizers.Adam(clipnorm=1.0)

对于剪辑值

opt = tf.keras.optimizers.Adam(clipvalue=0.5)

请参阅此帖子以获取帮助(TF 的先前版本): How to apply gradient clipping in TensorFlow?

这个帖子的一般解释: https://machinelearningmastery.com/how-to-avoid-exploding-gradients-in-neural-networks-with-gradient-clipping/

【讨论】:

谢谢你的建议,损失函数的爆炸性是通过去除ReLUs解决的,所以我没有尝试过clipnorm和clipvalue。 那你就好了,不用玩那些了!如果您计划在几个不同的数据集上进行训练,那么无论如何包含安全网参数可能会很有用。 @Dr.H.Lecter。非常感谢医生!它的工作原理是我在第一个时代得到 inf ,然后在以后的时代得到 nan 。我用 tanh 替换了 relu 并且还使用了 clipnorm,它现在工作正常,但我仍然得到高损失:Epoch 1/10 1/1 - 8s - loss: 91188.7188 Epoch 2/10 1/1 - 0s - loss: 91179.7031 Epoch 3/10 1/1 - 0s - loss: 91169.9688 Epoch 4/10 1/1 - 0s - loss: 91157.8672 请知道为什么会这样吗?顺便说一句,我的原始数据有很多 0 和 1 以及正值和负值的混合。我也确实对我的数据进行了规范化。 我删除了0和1,现在我的损失是0.9!但是,这些删除的值很重要,因为它们意味着关闭和打开变电站。请问这是个好主意吗!【参考方案2】:

两个主要问题:

不要将'relu' 用于LSTM,保留标准激活,即'tanh'。因为 LSTM 是“循环的”,所以它们很容易将值的增长或减少累积到使数字无用的程度。 检查您的数据范围X_trainX_test。确保它们不是太大。 -4和+4之间的东西有点好。如果数据尚未标准化,您应该考虑对其进行标准化。

请注意,“准确性”对于非分类问题没有任何意义。 (我注意到你的最终激活是“线性的”,所以你没有做分类,对吧?)


最后,如果上面的两个提示不起作用。检查您是否有一个全为零的示例,这可能是在创建“全掩码”序列,而这个“可能”(我不知道)会导致错误。

(X_train == 0).all(axis=[1,2]).any() #should be false

【讨论】:

现在我只是想使用自动编码器来学习我的数据的表示。稍后当我达到足够准确的断点时,我想将编码器部分与自定义聚类层结合使用,以便(希望)将我的数据划分为清晰的聚类。所以从某种意义上说,它是没有预先设计的类的分类。我的最终操作是线性的,因为我的数据在 [-2, 2] 范围内,并且我没有找到任何具有这样范围的激活函数,tanh 只是 [-1,1]。 好吧,-2到2是合理的,但是LSTM中的“relu”确实很麻烦。不要使用它,保留默认值。 --- 如果您的模型的初始预测与此范围相差太远,您可能希望在最后一个 Dense 之前或之后进行 BatchNormalization(不是真正必要的)。 非常感谢。我做了你提到的关于tanh和clipvalue的事情,但我仍然有很高的损失。可能是因为我每行有一半由 0 和 1 组成?但是删除它们可能会产生错误的结果?如果我错了,请纠正我? 1/10 1/1 - 9s - 损失:91187.0781 2/10 1/1 - 0s - 损失:91178.6875 3/10 1/1 - 0s - 损失:91168.4688 这是我用 tanh 替换 relu 后前 3 个 epoch 得到的结果(高损失!):Epoch 1/10 1/1 - 9s - loss: 91189.1953 Epoch 2/10 1/1 - 0s - loss: 91176.1953 Epoch 3/10 1/1 - 0s - loss: 91164.1172 ...当我从我的每一行中删除 0s 和 1s 时,结果得到更好的 loss 大约为 0.9。但是删除这些值并不是一个好主意,因为这些值意味着开关的关闭和打开。请问有什么想法吗? @DanielMöller 谢谢;这有帮助! --- 我得到了 NaN,用于预测 3 年天气数据集中 7 个变量的输入的一个输出,使用以下方法:model = Sequential() model.add(LSTM(64, activation='relu', input_shape=(trainX.shape [1], trainX.shape[2]), return_sequences=True)) model.add(LSTM(32, activation='relu', return_sequences=False)) model.add(Dropout(0.1)) model.add(Dense (14, activation='relu')) model.compile(optimizer= Adam(learning_rate = 0.0001), loss="mean_squared_error")......还有什么其他的改进建议吗??

以上是关于损失函数的爆炸式增长,LSTM 自动编码器的主要内容,如果未能解决你的问题,请参考以下文章

变分自动编码器损失函数(keras)

如何为 LSTM 实现 Keras 自定义损失函数

PyTorch 中自定义后向函数的损失 - 简单 MSE 示例中的爆炸损失

输出keras中的损失/成本函数

忽略 keras 中 R 的缺失目标值的损失函数

LSTM 模型中 epoch 图中的损失跳跃 - keras