You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keras/TensorFlow中MultiHeadAttention层attention_mask使用示例求助

问题解决方案

1. 掩码形状说明

自注意力场景下query和key来自同一个输入序列,因此T=S=sequence_length,最终掩码形状为(batch_size, sequence_length, sequence_length),含义是:对于单个样本的第i个query位置,掩码第i行的第j位为0时,该query在计算注意力时不会关注第j个key位置。

2. 动态掩码实现方案

不需要提前用numpy生成全局掩码,直接在层内部用TF算子动态生成,可适配任意batch size,不会占用额外内存。修改后的完整TransformerBlock代码如下:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

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):
        # 动态生成padding掩码:取每个时间步的第0个特征判断是否为padding位
        # 得到形状 (batch_size, sequence_length) 的padding掩码,True为有效位置,False为padding
        padding_mask = tf.not_equal(inputs[..., 0], 0)
        # 扩展为自注意力需要的 (batch_size, sequence_length, sequence_length) 形状
        # 相当于每个query位置都使用相同的padding掩码过滤key位置
        attention_mask = padding_mask[:, tf.newaxis, :] & padding_mask[:, :, tf.newaxis]
        
        attn_output = self.att(inputs, inputs, attention_mask=attention_mask)
        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)

如果输入经过嵌入层、CNN处理后padding位置的特征不再为0,可修改call方法支持接收前置层传递的掩码,Keras中嵌入层设置mask_zero=True后会自动传递掩码到后续层:

def call(self, inputs, training, mask=None):
    if mask is not None:
        attention_mask = mask[:, tf.newaxis, :] & mask[:, :, tf.newaxis]
        attn_output = self.att(inputs, inputs, attention_mask=attention_mask)
    else:
        attn_output = self.att(inputs, inputs)
    # 后续逻辑和原有代码一致

3. 掩码的必要性说明

  • 精度层面:如果当前是序列级分类任务,padding位的信息不会对最终全局池化/平均结果产生明显影响,所以未加掩码时模型表现尚可;如果是token级任务(比如序列标注、翻译),不加掩码会直接导致结果错误。
  • 效率层面:加掩码后MultiHeadAttention会跳过掩码为0的位置的注意力计算,确实可以减少计算量,序列padding比例越高加速效果越明显。

内容的提问来源于stack exchange,提问作者R. Giskard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 18:06:07