【问题标题】:How do I mask multi-output in Tensorflow 2 LSTM training?如何在 Tensorflow 2 LSTM 训练中屏蔽多输出?
【发布时间】:2020-06-28 22:01:51
【问题描述】:

我正在 Tensorflow 2 中训练一个 LSTM 模型来预测两个输出,即水流和水温。

  • 对于某些时间步,有一个流标签一个温度标签,
  • 对于某些只有水流标签温度标签,
  • 对于某些人来说,两者都没有

所以损失函数需要在没有标签的情况下忽略温度和流量损失。我在 TF 文档中做了很多阅读,但我正在努力弄清楚如何最好地做到这一点。

到目前为止我已经尝试过

  • 在编译模型时指定sample_weight_mode='temporal',然后在调用fit 时包含sample_weight numpy 数组

当我这样做时,我收到一个错误,要求我传递一个二维数组。但这让我感到困惑,因为有 3 个维度:n_samplessequence_lengthn_outputs

这是我基本上想要做的一些代码:

import tensorflow as tf
import numpy as np

# set up the model
simple_lstm_model = tf.keras.models.Sequential([
    tf.keras.layers.LSTM(8, return_sequences=True),
    tf.keras.layers.Dense(2)
])

simple_lstm_model.compile(optimizer='adam', loss='mae',
                          sample_weight_mode='temporal')

n_sample = 2
seq_len = 10
n_feat = 5
n_out = 2

# random in/out
x = np.random.randn(n_sample, seq_len, n_feat)
y_true = np.random.randn(n_sample, seq_len, n_out)

# set the initial mask as all ones (everything counts equally)
mask = np.ones([n_sample, seq_len, n_out])
# set the mask so that in the 0th sample, in the 3-8th time step
# the 1th variable is not counted in the loss function
mask[0, 3:8, 1] = 0

simple_lstm_model.fit(x, y_true, sample_weight=mask)

错误:

ValueError: Found a sample_weight array with shape (2, 10, 2). In order to use timestep-wise sample weighting, you should
pass a 2D sample_weight array.

有什么想法吗?我一定不明白sample_weights 做了什么,因为对我来说,只有sample_weight 数组与输出具有相同的维度才有意义。我可以编写一个自定义损失函数并手动处理屏蔽,但似乎应该有一个更通用或内置的解决方案。

【问题讨论】:

    标签: python numpy tensorflow keras lstm


    【解决方案1】:

    1。 sample_weights

    是的,你理解错了。在这种情况下,您有 2 样本,10 时间步长,每个都有 5 特征。您可以像这样传递 2D 张量,因此每个样本的每个时间步对总损失的贡献不同,所有特征的权重相同(通常是这种情况)。

    这根本不是你想要的。您想在计算后掩盖某些损失值,这样它们就不会产生影响。

    2。自定义损失

    一种可能的解决方案是实现您自己的损失函数,在采用meansum 之前将损失张量乘以掩码。

    基本上,您将masktensor 以某种方式连接在一起,然后将其拆分到函数中以供使用。这就足够了:

    def my_loss_function(y_true_mask, y_pred):
        # Recover y and mask
        y_true, mask = tf.split(y_true_mask, 2)
        # You could user reduce_sum or other combinations
        return tf.math.reduce_mean(tf.math.abs(y_true - y_pred) * mask)
    

    现在您的代码(不需要加权,因为它不需要):

    simple_lstm_model = tf.keras.models.Sequential(
        [tf.keras.layers.LSTM(8, return_sequences=True), tf.keras.layers.Dense(2)]
    )
    
    simple_lstm_model.compile(optimizer="adam", loss=my_loss_function)
    
    n_sample = 2
    seq_len = 10
    n_feat = 5
    n_out = 2
    
    x = np.random.randn(n_sample, seq_len, n_feat)
    y_true = np.random.randn(n_sample, seq_len, n_out)
    
    mask = np.ones([n_sample, seq_len, n_out])
    mask[0, 3:8, 1] = 0
    
    # Stack y and mask together
    y_true_mask = np.stack([y_true, mask])
    
    simple_lstm_model.fit(x, y_true_mask)
    

    所以它起作用了。您也可以通过其他方式堆叠这些值,但我希望您能了解如何做到这一点。

    3。屏蔽输出

    请注意上面介绍了一些问题。如果你有很多零并取mean,你可能会得到一个非常小的损失值并抑制学习。另一方面,如果你选择sum,它可能会爆炸。

    【讨论】:

      猜你喜欢
      • 2019-02-15
      • 2017-06-17
      • 1970-01-01
      • 2018-09-04
      • 2017-12-30
      • 2018-03-21
      • 2020-02-03
      • 2017-11-30
      • 2018-01-10
      相关资源
      最近更新 更多