为什么Pytorch Transformer模块中MultiheadAttention的输入大小是1536?

Why is the input size of the MultiheadAttention in Pytorch Transformer module 1536?

使用torch.nn.modules.transformer.Transformermodule/object时,第一层是encoder.layers.0.self_attn层,即MultiheadAttention层,即

from torch.nn.modules.transformer import Transformer
bumblebee = Transformer()

bumblee.parameters

[输出]:

<bound method Module.parameters of Transformer(
  (encoder): TransformerEncoder(
    (layers): ModuleList(
      (0): TransformerEncoderLayer(
        (self_attn): MultiheadAttention(
          (out_proj): Linear(in_features=512, out_features=512, bias=True)
        )
        (linear1): Linear(in_features=512, out_features=2048, bias=True)
        (dropout): Dropout(p=0.1, inplace=False)
        (linear2): Linear(in_features=2048, out_features=512, bias=True)
        (norm1): LayerNorm((512,), eps=1e-05, elementwise_affine=True)
        (norm2): LayerNorm((512,), eps=1e-05, elementwise_affine=True)
        (dropout1): Dropout(p=0.1, inplace=False)
        (dropout2): Dropout(p=0.1, inplace=False)
      )

如果我们打印出图层的大小,我们会看到:

for name in bumblebee.encoder.state_dict():
    print(name, '\t', bumblebee.encoder.state_dict()[name].shape)

[输出]:

layers.0.self_attn.in_proj_weight    torch.Size([1536, 512])
layers.0.self_attn.in_proj_bias      torch.Size([1536])
layers.0.self_attn.out_proj.weight   torch.Size([512, 512])
layers.0.self_attn.out_proj.bias     torch.Size([512])
layers.0.linear1.weight      torch.Size([2048, 512])
layers.0.linear1.bias    torch.Size([2048])
layers.0.linear2.weight      torch.Size([512, 2048])
layers.0.linear2.bias    torch.Size([512])
layers.0.norm1.weight    torch.Size([512])
layers.0.norm1.bias      torch.Size([512])
layers.0.norm2.weight    torch.Size([512])
layers.0.norm2.bias      torch.Size([512])

似乎 1536 是 512 * 3 并且 layers.0.self_attn.in_proj_weight 参数可能以某种方式将变压器架构中的所有三个 QKV 张量存储在一个矩阵中。

来自 https://github.com/pytorch/pytorch/blob/master/torch/nn/modules/activation.py#L649

class MultiheadAttention(Module):
    def __init__(self, embed_dim, num_heads, dropout=0., bias=True, add_bias_kv=False, add_zero_attn=False, kdim=None, vdim=None):
        super(MultiheadAttention, self).__init__()
        self.embed_dim = embed_dim
        self.kdim = kdim if kdim is not None else embed_dim
        self.vdim = vdim if vdim is not None else embed_dim
        self._qkv_same_embed_dim = self.kdim == embed_dim and self.vdim == embed_dim

        self.num_heads = num_heads
        self.dropout = dropout
        self.head_dim = embed_dim // num_heads
        assert self.head_dim * num_heads == self.embed_dim, "embed_dim must be divisible by num_heads"

        if self._qkv_same_embed_dim is False:
            self.q_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim))
            self.k_proj_weight = Parameter(torch.Tensor(embed_dim, self.kdim))
            self.v_proj_weight = Parameter(torch.Tensor(embed_dim, self.vdim))
        else:
            self.in_proj_weight = Parameter(torch.empty(3 * embed_dim, embed_dim))

MultiheadAttention 的文档字符串中的注释说:

Note: if kdim and vdim are None, they will be set to embed_dim such that query, key, and value have the same number of features.

对吗?

nn.Transformer definition with the default values, EncoderLayer实例化为d_model=512, nhead=8

MultiheadAttention is instantiated with d_model, nhead equal to those values and k_dim, v_dim are left to the default value of None.

如果他们是 Noneself._qkv_same_embed_dimthis line evaluates to True. When that happens, as you correctly pointed out self.in_proj_weight is defined as a Tensor of shape (3 x embed_dim, embed_dim)

简而言之:是的,没错。