fused_multi_head_attention¶
- paddle.incubate.nn.functional. fused_multi_head_attention ( x, qkv_weight, linear_weight, pre_layer_norm=False, pre_ln_scale=None, pre_ln_bias=None, ln_scale=None, ln_bias=None, pre_ln_epsilon=1e-05, qkv_bias=None, linear_bias=None, cache_kv=None, attn_mask=None, dropout_rate=0.5, attn_dropout_rate=0.5, ln_epsilon=1e-05, training=True, mode='upscale_in_train', ring_id=- 1, add_residual=True, num_heads=- 1, transpose_qkv_wb=False, name=None ) [源代码] ¶
多头注意力机制
注意力机制可以将查询(Query)与一组键值对(Key-Value)映射到输出。而多头注意力机制是将注意力机制的计算过程计算多次,以便模型提取不同子空间的信息。
细节可参考论文 Attention is all you need 。
fused_multi_head_attention 算子目前只支持在 GPU 下运行,其包含的计算功能如下:
# pseudocode
if pre_layer_norm:
out = layer_norm(x)
out = linear(out) + qkv) + bias
else:
out = linear(x) + bias
out = transpose(out, perm=[2, 0, 3, 1, 4])
# extract q, k and v from out.
q = out[0:1,::]
k = out[1:2,::]
v = out[2:3,::]
out = q * k^t
out = attn_mask + out
out = softmax(out)
out = dropout(out)
out = out * v
out = transpose(out, perm=[0, 2, 1, 3])
out = out_linear(out)
if pre_layer_norm:
out = x + dropout(linear_bias + out)
else:
out = layer_norm(x + dropout(linear_bias + out))
值得注意的是,该 API 中,q, k, v 的 weight 被统一存储在一个权重 Tensor 中,形状为 [3, num_heads, head_dim, embed_dim] , 如果想得到单独的 q, k 或 v 的 weight,可以通过转置和切分得到。
参数¶
linear_weight (Tensor) - 代表 linear 的权重,二维 tensor,形状为
[embed_dim, embed_dim]
。pre_layer_norm (bool,可选) - 代表是采用 pre_layer_norm 的结构(True)还是 post_layer_norm 的结构(False)。若为 True,则为 pre_layer_norm 结构,代表在 multi-head attention 和 ffn 之前各执行一次
layer_norm
。若为 False,则为 post_layer_norm 结构,代表在 multi-head attention 和 ffn 之后各执行一次layer_norm
。默认值:False
。pre_ln_scale (Tensor,可选) - 代表 normalize_before 为 True 时,multi-head attention 中第一个
layer_norm
的权重,一维 tensor,形状为[embed_dim]
。pre_ln_bias (Tensor,可选) - 代表 normalize_before 为 True 时,multi_head attention 中第一个
layer_norm
的偏置,一维 tensor,形状为[embed_dim]
。ln_scale (Tensor,可选) - 代表 normalize_before 为 True 时,multi-head attention 中第二个 (False 时的第一个)
layer_norm
的权重,一维 tensor,形状为[embed_dim]
。ln_bias (Tensor,可选) - 代表 normalize_before 为 True 时,multi-head attention 中第二个 (False 时的第一个)
layer_norm
的偏置,一维 tensor,形状为[embed_dim]
。pre_ln_epsilon (float,可选) - 代表 normalize_before 为 True 时,multi-head attention 中第一个
layer_norm
为了数值稳定加在分母上的值。默认值为 1e-05 。qkv_bias (Tensor,可选) - 代表 Attention 中计算 q, k, v 时的偏置,是一个三维 tensor,当
transpose_qkv_wb
为 False 时形状为[3, num_heads, head_dim]
。当transpose_qkv_wb
为 True 时形状为[3 * embed_dim]
。linear_bias (Tensor,可选) - 代表
linear
的偏置,一维 tensor,形状为[embed_dim]
。cache_kv (Tensor,可选) - 代表自回归生成模型中 cache 结构的部分,五维 tensor,形状为
[2, bsz, num_head, seq_len, head_dim]
。默认值为 None。attn_mask (Tensor,可选)- 用于限制 multi-head attention 中对当前词产生影响的其他词的范围。形状会被广播为
[batch_size, num_heads, sequence_length, sequence_length ]
。dropout_rate (float,可选) - 代表 multi-head attention 之后的 dropout 算子的 dropout 比例,默认为 0.5。
attn_dropout_rate (float,可选) - 代表 multi-head attention 中的 dropout 算子的 dropout 比例,默认为 0.5。
ln_epsilon (float,可选) - 代表 normalize_before 为 True 时,multi-head attention 中第二个 (False 时的第一个)
layer_norm
为了数值稳定加在分母上的值。默认值为 1e-05 。training (bool):标记是否为训练阶段。默认:True。
mode (str):丢弃单元的方式,有两种'upscale_in_train'和'downscale_in_infer',默认:'upscale_in_train'。计算方法如下:
upscale_in_train,在训练时增大输出结果。
train: out = input * mask / ( 1.0 - p )
inference: out = input
downscale_in_infer,在预测时减小输出结果
train: out = input * mask
inference: out = input * (1.0 - p)
ring_id (int,可选) - 分布式 tensor parallel 运行下通讯所使用的 NCCL id。默认值为 -1 。
add_residual (bool,可选) - 是否在计算最后对结果进行残差计算。默认值为 True。
num_heads (int,可选) - 在
transpose_qkv_wb
设置为 True 的时候,必须提供该值,表示 Multi-Head Attention 的 head 的维度。默认值为 -1。transpose_qkv_wb (bool,可选) - 是否在底层算子中对 Attention 中计算 q, k, v 时的权重与偏置进行 transpose 操作。默认值为 False。
name (str,可选) - 具体用法请参见 Name,一般无需设置,默认值为 None。
返回¶
Tensor
,数据类型和形状同x
一致。
代码示例¶
# required: gpu
import paddle
import paddle.incubate.nn.functional as F
# input: [batch_size, seq_len, embed_dim]
x = paddle.rand(shape=(2, 4, 128), dtype="float32")
# qkv_weight: [3, num_head, head_dim, embed_dim]
qkv_weight = paddle.rand(shape=(3, 4, 32, 128), dtype="float32")
# qkv_bias: [3, num_head, head_dim]
qkv_bias = paddle.rand(shape=(3, 4, 32), dtype="float32")
# linear_weight: [embed_dim, embed_dim]
linear_weight = paddle.rand(shape=(128, 128), dtype="float32")
# linear_bias: [embed_dim]
linear_bias = paddle.rand(shape=[128], dtype="float32")
# self attention mask: [batch_size, num_heads, seq_len, seq_len]
attn_mask = paddle.rand(shape=(2, 4, 4, 4), dtype="float32")
# output: [batch_size, seq_len, embed_dim]
output = F.fused_multi_head_attention(
x, qkv_weight, linear_weight, False,
None, None, None, None, 1e-5, qkv_bias,
linear_bias, None, attn_mask)
# [2, 4, 128]
print(output.shape)