Path: blob/master/site/zh-cn/guide/keras/masking_and_padding.ipynb
25118 views
Copyright 2020 The TensorFlow Authors.
Keras 中的遮盖和填充
设置
简介
遮盖的作用是告知序列处理层输入中有某些时间步骤丢失,因此在处理数据时应将其跳过。
填充是遮盖的一种特殊形式,其中被遮盖的步骤位于序列的起点或开头。填充是出于将序列数据编码成连续批次的需要:为了使批次中的所有序列适合给定的标准长度,有必要填充或截断某些序列。
让我们仔细看看。
填充序列数据
在处理序列数据时,各个样本常常具有不同长度。请考虑以下示例(文本被切分为单词):
进行词汇查询后,数据可能会被向量化为整数,例如:
此数据是一个嵌套列表,其中各个样本的长度分别为 3、5 和 6。由于深度学习模型的输入数据必须为单一张量(例如在此例中形状为 (batch_size, 6, vocab_size)
),短于最长条目的样本需要用占位符值进行填充(或者,也可以在填充短样本前截断长样本)。
Keras 提供了一个效用函数来截断和填充 Python 列表,使其具有相同长度:tf.keras.preprocessing.sequence.pad_sequences
。
遮盖
既然所有样本现在都具有了统一长度,那就必须告知模型,数据的某些部分实际上是填充,应该忽略。这种机制就是遮盖。
在 Keras 模型中引入输入掩码有三种方式:
添加一个
keras.layers.Masking
层。使用
mask_zero=True
配置一个keras.layers.Embedding
层。在调用支持
mask
参数的层(如 RNN 层)时,手动传递此参数。
掩码生成层:Embedding
和 Masking
这些层将在后台创建一个掩码张量(形状为 (batch, sequence_length)
的二维张量),并将其附加到由 Masking
或 Embedding
层返回的张量输出上。
您可以在输出结果中看到,该掩码是一个形状为 (batch_size, sequence_length)
的二维布尔张量,其中每个 False
条目表示对应的时间步骤应在处理时忽略。
函数式 API 和序列式 API 中的掩码传播
在使用函数式 API 或序列式 API 时,由 Embedding
或 Masking
层生成的掩码将通过网络传播给任何能够使用它们的层(如 RNN 层)。Keras 将自动提取与输入相对应的掩码,并将其传递给任何知道该掩码使用方法的层。
例如,在下面的序贯模型中,LSTM
层将自动接收掩码,这意味着它将忽略填充的值:
对以下函数式 API 的情况也是如此:
将掩码张量直接传递给层
能够处理掩码的层(如 LSTM
层)在其 __call__
方法中有一个 mask
参数。
同时,生成掩码的层(如 Embedding
)会公开一个 compute_mask(input, previous_mask)
方法,供您调用。
因此,您可以将掩码生成层的 compute_mask()
方法的输出传递给掩码使用层的 __call__
方法,如下所示:
在自定义层中支持遮盖
有时,您可能需要编写生成掩码的层(如 Embedding
),或者需要修改当前掩码的层。
例如,任何生成与其输入具有不同时间维度的张量的层(如在时间维度上进行连接的 Concatenate
层)都需要修改当前掩码,这样下游层才能正确顾及被遮盖的时间步骤。
为此,您的层应实现 layer.compute_mask()
方法,该方法会根据输入和当前掩码生成新的掩码。
以下是需要修改当前掩码的 TemporalSplit
层的示例。
下面是关于 CustomEmbedding
层的另一个示例,该层能够根据输入值生成掩码:
在兼容层上选择启用掩码传播
大多数层都不会修改时间维度,因此无需修改当前掩码。但是,这些层可能仍希望能够将当前掩码不加更改地传播到下一层。**这是一种可以选择启用的行为。**默认情况下,自定义层将破坏当前掩码(因为框架无法确定传播该掩码是否安全)。
如果您有一个不会修改时间维度的自定义层,且您希望它能够传播当前的输入掩码,您应该在层构造函数中设置 self.supports_masking = True
。在这种情况下,compute_mask()
的默认行为是仅传递当前掩码。
下面是被列入掩码传播白名单的层的示例:
现在,您可以在掩码生成层(如 Embedding
)和掩码使用层(如 LSTM
)之间使用此自定义层,它会将掩码一路传递到掩码使用层。
编写需要掩码信息的层
有些层是掩码使用者:他们会在 call
中接受 mask
参数,并使用该参数来决定是否跳过某些时间步骤。
要编写这样的层,您只需在 call
签名中添加一个 mask=None
参数。与输入关联的掩码只要可用就会被传递到您的层。
下面是一个简单示例:示例中的层在输入序列的时间维度(轴 1)上计算 Softmax,同时丢弃遮盖的时间步骤。
总结
以上是您需要了解的关于 Keras 中填充和遮盖的所有信息。回顾一下:
“遮盖”是层得知何时应该跳过/忽略序列输入中的某些时间步骤的方式。
有些层是掩码生成者:
Embedding
可以通过输入值来生成掩码(如果mask_zero=True
),Masking
层也可以。有些层是掩码使用者:它们会在其
__call__
方法中公开mask
参数。RNN 层就是如此。在函数式 API 和序列式 API 中,掩码信息会自动传播。
单独使用层时,您可以将
mask
参数手动传递给层。您可以轻松编写会修改当前掩码的层、生成新掩码的层,或使用与输入关联的掩码的层。