Torch.nn.Transformer示例代码抛出张量形状错误

时间:2020-03-20 05:43:30

标签: python pytorch transformer

我试图用Pytorch实现Transformer模型,并尝试了this GitHub repo中的示例,该示例与here in the documentation链接,并在模型中的PositionalEncoding类中遇到了问题。 py。

该类的__init__()函数的代码如下:

def __init__(self, d_model, dropout=0.1, max_len=5000):
    super(PositionalEncoding, self).__init__()
    self.dropout = nn.Dropout(p=dropout)

    pe = torch.zeros(max_len, d_model)
    position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
    div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
    pe[:, 0::2] = torch.sin(position * div_term)
    pe[:, 1::2] = torch.cos(position * div_term)
    pe = pe.unsqueeze(0).transpose(0, 1)
    self.register_buffer('pe', pe)

以d_model = 103运行的这段代码在最后一行(pe[:, 0::2] = ...)上引发了以下错误:

RuntimeError:张量(52)的扩展大小必须与非单维度1上的现有大小(51)相匹配。目标大小:[5000,52]。张量大小:[5000,51]

我发现此错误相当难以理解,并且编写自己的类似有效实现并没有取得太大的成功。 我的第一个猜测是,这是Python / PyTorch中版本更改的问题,但当然可能是我所缺少的其他东西。

3 个答案:

答案 0 :(得分:1)

尝试

0:51:2 instead of 0::2

0 :: 2将生成-> [0,2,4,...,直到元素末尾]

答案 1 :(得分:0)

你可以这样做:

class PositionalEncoding(nn.Module):

  def __init__(self, d_model, max_len=1000):
    super().__init__()
    self.d_model = d_model
    self.max_len = max_len
  
  def forward(self):
    pos = torch.arange(self.max_len).view(-1, 1).float()
    pe = torch.arange(self.d_model).repeat(self.max_len, 1).float()
    pe[:, 0::2] = torch.sin(pos / (10000 ** (2 * pe[:, 0::2] / self.d_model)))
    pe[:, 1::2] = torch.cos(pos / (10000 ** (2 * pe[:, 1::2] / self.d_model)))
    return pe.unsqueeze(0)

当用切片求和时:

x + pe[:, :x.size(1)])

答案 2 :(得分:0)

此错误是因为您的 d_model 是一个奇数。您可以看到 div_term 的形状取决于 torch.arange(0, d_model, 2),在您的情况下,形状为 51。

然而,pe[:, 0::2] 的形状是 52。

这通常不会发生,因为在 Transformer 模型中,在将张量放入 PositionalEncoding 之前,它会被放入嵌入层以嵌入成通常为 的形状>偶数(512、128 等)。当 d_model 为偶数时,pe[:, 0::2] 的形状和 div_term 的形状将相等。

所以在你的情况下,你可以通过

  • 使您的 d_model 成为偶数(通过将您的输入嵌入到偶数维度中);
  • 或通过修改 div_term
  • 的形状使您的 pe[:, 0::2] 等于 div_term
def __init__(self, d_model, dropout=0.1, max_len=5000):
    super(PositionalEncoding, self).__init__()
    self.dropout = nn.Dropout(p=dropout)

    pe = torch.zeros(max_len, d_model)
    position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
    div_term = torch.exp(torch.arange(0, d_model-1, 2).float() * (-math.log(10000.0) / d_model))
    pe[:, 0::2] = torch.sin(position * div_term)
    div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
    pe[:, 1::2] = torch.cos(position * div_term)
    pe = pe.unsqueeze(0).transpose(0, 1)
    self.register_buffer('pe', pe)

PS:如果你把pe[:, 0::2]修改成pe[:, 0:d_model-1:2],当然可以,因为你把它变成了51,就像div_term一样。但这也意味着 pe 的最后一个维度不会被赋值,它仍然为零。这意味着输入的最后一个维度不会进行位置编码。