当前位置: 首页 > 面试题库 >

Keras LSTM带屏蔽层的可变长度输入

郜琦
2023-03-14
问题内容

我知道这是一个有很多问题的主题,但是我找不到解决问题的办法。

我正在使用遮罩层在可变长度输入上训练LSTM网络,但似乎没有任何效果。

输入形状(100、362、24),其中362为最大序列长度,特征为24,特征数为100,样本数为100(划分为75列/有效值为25)。

输出形状(100,362,1)随后转换为(100,362-N,1)。

这是我的网络的代码:

from keras import Sequential
from keras.layers import Embedding, Masking, LSTM, Lambda
import keras.backend as K


#                          O O O
#   example for N:3        | | |
#                    O O O O O O
#                    | | | | | | 
#                    O O O O O O

N = 5
y= y[:,N:,:]

x_train = x[:75]
x_test = x[75:]
y_train = y[:75]
y_test = y[75:]

model = Sequential()
model.add(Masking(mask_value=0., input_shape=(timesteps, features)))
model.add(LSTM(128, return_sequences=True))
model.add(LSTM(64, return_sequences=True))
model.add(LSTM(1, return_sequences=True))
model.add(Lambda(lambda x: x[:, N:, :]))

model.compile('adam', 'mae')

print(model.summary())
history = model.fit(x_train, y_train, 
                    epochs=3, 
                    batch_size=15, 
                    validation_data=[x_test, y_test])

我的数据最后被填充。例:

>> x_test[10,350]
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
   0., 0., 0., 0., 0., 0., 0.], dtype=float32)

问题在于掩模层似乎没有作用。我可以看到训练过程中打印出的损耗值,它等于我计算出的没有遮罩的损耗值:

Layer (type)                 Output Shape              Param #   
=================================================================
masking_1 (Masking)          (None, 362, 24)           0         
_________________________________________________________________
lstm_1 (LSTM)                (None, 362, 128)          78336     
_________________________________________________________________
lstm_2 (LSTM)                (None, 362, 64)           49408     
_________________________________________________________________
lstm_3 (LSTM)                (None, 362, 1)            264       
_________________________________________________________________
lambda_1 (Lambda)            (None, 357, 1)            0         
=================================================================
Total params: 128,008
Trainable params: 128,008
Non-trainable params: 0
_________________________________________________________________
None
Train on 75 samples, validate on 25 samples
Epoch 1/3
75/75 [==============================] - 8s 113ms/step - loss: 0.1711 - val_loss: 0.1814
Epoch 2/3
75/75 [==============================] - 5s 64ms/step - loss: 0.1591 - val_loss: 0.1307
Epoch 3/3
75/75 [==============================] - 5s 63ms/step - loss: 0.1057 - val_loss: 0.1034

>> from sklearn.metrics import mean_absolute_error
>> out = model.predict(x_test, batch_size=1)
>> print('wo mask', mean_absolute_error(y_test.ravel(), out.ravel()))
>> print('w mask', mean_absolute_error(y_test[~(x_test[:,N:] == 0).all(axis=2)].ravel(), out[~(x_test[:,N:] == 0).all(axis=2)].ravel()))
wo mask 0.10343371
w mask 0.16236152

此外,如果我将nan值用作屏蔽的输出值,则可以看到nan在训练过程中传播(损耗等于nan)。

使遮罩层按预期工作时我缺少什么?


问题答案:

Lambda默认情况下,该层不传播掩码。换句话说,由该Masking层计算的掩码张量被该层丢弃Lambda,因此该Masking层对输出损耗没有影响。

如果要使图层的compute_mask方法Lambda传播先前的蒙版,mask则在创建图层时必须提供参数。从Lambda层的源代码可以看出,

def __init__(self, function, output_shape=None,
             mask=None, arguments=None, **kwargs):
    # ...
    if mask is not None:
        self.supports_masking = True
    self.mask = mask

# ...

def compute_mask(self, inputs, mask=None):
    if callable(self.mask):
        return self.mask(inputs, mask)
    return self.mask

因为默认值maskNonecompute_mask收益None和损失是不是在所有的屏蔽。

要解决此问题,由于您的Lambda图层本身未引入任何其他遮罩,因此该compute_mask方法应仅返回上一层的遮罩(并进行适当的切片以匹配该图层的输出形状)。

masking_func = lambda inputs, previous_mask: previous_mask[:, N:]
model = Sequential()
model.add(Masking(mask_value=0., input_shape=(timesteps, features)))
model.add(LSTM(128, return_sequences=True))
model.add(LSTM(64, return_sequences=True))
model.add(LSTM(1, return_sequences=True))
model.add(Lambda(lambda x: x[:, N:, :], mask=masking_func))

现在您应该能够看到正确的损失值。

>> model.evaluate(x_test, y_test, verbose=0)
0.2660679519176483
>> out = model.predict(x_test)
>> print('wo mask', mean_absolute_error(y_test.ravel(), out.ravel()))
wo mask 0.26519736809498456
>> print('w mask', mean_absolute_error(y_test[~(x_test[:,N:] == 0).all(axis=2)].ravel(), out[~(x_test[:,N:] == 0).all(axis=2)].ravel()))
w mask 0.2660679670482195

使用NaN值进行填充不起作用,因为通过将损耗张量乘以二进制掩码(0 * nanis nan,所以平均值为nan)来完成掩码。



 类似资料:
  • 本文向大家介绍javascript实现网页屏蔽Backspace事件,输入框不屏蔽,包括了javascript实现网页屏蔽Backspace事件,输入框不屏蔽的使用技巧和注意事项,需要的朋友参考一下 下面通过javascript代码实现网页屏蔽Backspace事件,输入框不屏蔽,具体代码如下: 希望能够帮助到大家。

  • 问题内容: 我有一个带有列的表,其中包含如下所示的字符串。 我需要从第二次出现到字符串结尾获取子字符串,并且您可以看到子字符串的长度不是固定的。第一部分并不总是固定的,它可以改变。到目前为止,我正在使用以下代码来实现它。 如您所见,我采用一个任意大的值作为长度来处理可变长度。有更好的方法吗? 问题答案: 您可以与函数结合使用,找到的最后一次出现,还可以使用从字符串末尾获取指定数量的字符。 SQLF

  • 我使用的是javafx文本字段。我需要输入与格式##########匹配的数字和小数### 小数不可编辑,数字可以是任意数字;不允许其他输入。并非所有数字占位符都需要填写,例如,它可能是1.2或2.22.1,甚至是1.222.222.0 我尝试使用模式匹配与正则表达式来验证更改的文本,但仅此而已;它验证输入,它不会使十进制字段成为不可编辑的字段,并且工具提示不是一个选项。我不确定还能尝试什么。 我

  • 问题内容: 所以我需要屏蔽一个SSN#输入字段,假设ssn是,我需要显示(他们输入每个数字时都是实时的),但是我仍然需要保留原始值以提交。 如果用户严格输入值,我可以做到这一点,但是如果用户执行其他任何操作(如删除或将光标移动到随机位置并添加/删除数字,复制粘贴/删除等),它就会中断如果可能的话,我真的不想听一堆事件来完成这项工作。 我还尝试过在输入字段的顶部放置一个div来显示被屏蔽的ssn,而

  • 屏蔽IP 可以在此设置屏蔽蜘蛛爬的IP,点击右上角添加需要屏蔽的IP即可

  • 问题内容: 如何从控制台输入中屏蔽密码?我正在使用Java 6。 我尝试使用,但无法使用。一个完整的例子可能实际上对我有帮助。 这是我的代码: 我收到 问题答案: 一个完整的例子?运行以下代码:(注意:此示例最好在控制台中运行,而不是从IDE内部运行,因为在这种情况下System.console()方法可能返回null。)