我正在努力为MultiHeadAttention Layer屏蔽我的输入。我正在使用Keras文档中的Transformer Block,注意力集中。到目前为止,我在网上找不到任何示例代码,如果有人能给我给予一个代码片段,我将不胜感激。
this页面中的Transformer块:
class TransformerBlock(layers.Layer):
def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1):
super(TransformerBlock, self).__init__()
self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim)
self.ffn = keras.Sequential(
[layers.Dense(ff_dim, activation="relu"), layers.Dense(embed_dim),]
)
self.layernorm1 = layers.LayerNormalization(epsilon=1e-6)
self.layernorm2 = layers.LayerNormalization(epsilon=1e-6)
self.dropout1 = layers.Dropout(rate)
self.dropout2 = layers.Dropout(rate)
def call(self, inputs, training):
attn_output = self.att(inputs, inputs)
attn_output = self.dropout1(attn_output, training=training)
out1 = self.layernorm1(inputs + attn_output)
ffn_output = self.ffn(out1)
ffn_output = self.dropout2(ffn_output, training=training)
return self.layernorm2(out1 + ffn_output)
屏蔽的文档可以在this链接下找到:
attention_mask:形状为[B,T,S]的布尔掩码,防止注意某些位置。布尔掩码指定哪些查询元素可以关注哪些关键元素,1表示关注,0表示不关注。对于缺失的批次维度和标头维度,可能会发生广播。
我唯一可以运行的是在层类外部创建一个掩码,作为numpy数组:
mask = np.ones((observations, sequence_length, sequence_length))
mask[X[:observations,:,0]==0]=0
然后在调用层时输入,Transformer块中唯一的变化是:
def call(self, inputs, mask, training):
attn_output = self.att(inputs, inputs, attention_mask=mask)
然而,当在拟合时给定batch_size时,这当然不起作用,并且只对我的记忆中的5个观察值起作用,所以它没有任何意义。除此之外,我不认为这是屏蔽输入正确-一般来说,我很困惑如何屏蔽,给定的形状的注意力_掩码(观察,序列长度,序列长度)。我输入的形状是(observation,sequence_length,features)。这个输入被零填充,但是,当它到达Transformer块时,它已经通过了嵌入层和CNN。我尝试了各种方法来编写一个函数,该函数在使用不同的Tensor或Keras对象进行训练时创建遮罩。但我每次都犯错误。
我希望Tensorflow/Keras更流利的人能够提供一个例子。或者有人告诉我,考虑到我的架构,掩蔽是无用的。该模型运行良好。然而,我希望屏蔽可以帮助加快计算速度。我就是不明白。
1条答案
按热度按时间bvjveswy1#
也许有点晚了,但对于任何最终在这篇文章上寻找解决方案的人来说,这可能会有所帮助。
使用Transformer的一个典型场景是在NLP问题中,其中您有一批句子(为了简单起见,让我们假设它们已经被标记化)。请考虑以下示例:
正如你所看到的,我们有两个不同长度的句子。为了在tensorflow模型中学习它们,我们可以用一个特殊的token填充最短的token,比如说
'[PAD]'
,然后将它们馈送到Transformer模型中,就像你提议的那样。因此:同样假设我们已经有了从某个语料库中提取的标记词汇表,例如
1000
标记词汇表,我们可以定义一个StringLookup
层,将我们的一批句子转换为给定词汇表的数字投影。我们可以指定哪个token用于masking。我们可以看到
[PAD]
标记Map到词汇表中的0值。典型的下一步是将此Tensor馈送到
Embedding
层中,类似于以下内容:这里的关键是参数
mask_zero
。根据documentation,这个参数意味着:布尔值,输入值0是否是一个特殊的“填充”值,应该屏蔽掉.
这允许
embedding
层为后续层生成掩码,以指示哪些位置应该关注,哪些不应该关注。该掩码可以通过以下方式访问:嵌入的Tensor具有以下形式:
为了在
MultiHeadAttention
层中使用mask
,必须重新塑造掩膜以满足形状要求,根据文档,形状要求为[B, T, S]
,其中B
表示 * 批量大小 *T
表示查询大小(在我们的示例中为7),S
表示键大小(如果我们使用self attention,则仍然为7)。同样,在多头注意层中,我们必须注意头的数量H
。使用此输入创建兼容掩码的最简单方法是通过广播:最后我们可以像下面这样填充
MultiHeadAttention
层:因此,为了使用带有掩码的
TransformerBlock
层,您应该向call
方法添加mask
参数,如下所示:在调用
MultiHeadAttention
层的层/模型中,必须传递/传播Embedding
层生成的掩码。