【动手学习pytorch笔记】35.自注意力和位置编码

自注意力机制和位置编码

理论

自注意力的自不是自己和自己做Attention,之前理解的有问题,是query,key,value都是自己。

在这里插入图片描述

y i = f ( x i , ( x 1 , x 1 ) , . . . , ( x n , x n ) ) ∈ R d y_i=f(x_i,(x_1,x_1),...,(x_n,x_n))\in\mathbb{R}^d yi=f(xi,(x1,x1),...,(xn,xn))Rd

CNN,RNN,Attention比较

在这里插入图片描述

但和CNN,RNN不一样,Attention有一个问题是它并没有包含序列的位置信息,比如机器翻译任务,把句子打乱了,翻译出来的每个词的内容也一样。注意不是对整个结果没影响,I love you->我爱你,love I you->爱我你,顺序是有影响的,但对于把love翻译成爱是没影响的。

所以为了加入词的位置信息,所以提出了位置编码。

位置编码直接将信息注入到输入里

  • 假设长度为n的序列是 X ∈ R n × d X\in\mathbb{R}^{n\times d} XRn×d,那么使用位置编码矩阵 P ∈ R n × d P\in\mathbb{R}^{n\times d} PRn×d来输出 X + P X+P X+P作为自编码的输入

  • P的元素计算如下

    p i , 2 j = s i n ( i 1000 0 2 j / d ) p_{i,2j}=sin(\frac{i}{10000^{2j/d}}) pi,2j=sin(100002j/di) p i , 2 j + 1 = c o s ( i 1000 0 2 j / d ) p_{i,2j+1}=cos(\frac{i}{10000^{2j/d}}) pi,2j+1=cos(100002j/di)

    在这里插入图片描述

个人理解:横轴是每个词,不同的线是每个词的列也就是特征,纵轴是这些特征所加的值的。

竖着切一刀,能看到每个词所有特征的位置编码P,沿着每条线是不同的词的第j个特征的P,能发现越往后的特征周期越长。

这就像计算机的二进制编码,越小的位频率越高。

在这里插入图片描述

热图表示

在这里插入图片描述

纵轴是每个词,横轴是它的各个特征,颜色是位置编码值。现在终于理解transformer那个黄绿色的位置编码图是啥意思了。

相对位置信息

最后一个问题,为什么我们要用sin,cos函数表示这个位置信息呢,用别的呢?

  • 位置于 i + δ i+\delta i+δ处的位置编码可以线性投影位置 i i i处的位置编码来表示

    简单来说,举个例子,第三个词和第五个词,可以通过一个矩阵找到他们的映射关系,且这个矩阵不受这两个词绝对位置的影响,即把他两移到第一个词和第三个词,依然可以通过这个矩阵映射出来。

    [ c o s ( δ w j ) s i n ( δ w j ) − s i n ( δ w j ) c o s ( δ w j ) ] [ p i + δ , 2 j p i + δ , 2 j + 1 ] = [ p i + δ , 2 j p i + δ , 2 j + 1 ] \begin{bmatrix} cos(\delta w_j) & sin(\delta w_j)\\ -sin(\delta w_j) & cos(\delta w_j) \end{bmatrix}\begin{bmatrix} p_{i+\delta,2j} \\ p_{i+\delta,2j+1} \end{bmatrix}=\begin{bmatrix} p_{i+\delta,2j} \\ p_{i+\delta,2j+1} \end{bmatrix} [cos(δwj)sin(δwj)sin(δwj)cos(δwj)][pi+δ,2jpi+δ,2j+1]=[pi+δ,2jpi+δ,2j+1]

代码

import math
import torch
from torch import nn
from d2l import torch as d2l
num_hiddens, num_heads = 100, 5
attention = d2l.MultiHeadAttention(num_hiddens, num_hiddens, num_hiddens,
                                   num_hiddens, num_heads, 0.5)
attention.eval()
MultiHeadAttention(
  (attention): DotProductAttention(
    (dropout): Dropout(p=0.5, inplace=False)
  )
  (W_q): Linear(in_features=100, out_features=100, bias=False)
  (W_k): Linear(in_features=100, out_features=100, bias=False)
  (W_v): Linear(in_features=100, out_features=100, bias=False)
  (W_o): Linear(in_features=100, out_features=100, bias=False)
)
batch_size, num_queries, valid_lens = 2, 4, torch.tensor([3, 2])
X = torch.ones((batch_size, num_queries, num_hiddens))
attention(X, X, X, valid_lens).shape
torch.Size([2, 4, 100])
#@save
class PositionalEncoding(nn.Module):
    """位置编码"""
    def __init__(self, num_hiddens, dropout, max_len=1000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(dropout)
        # 创建一个足够长的P
        self.P = torch.zeros((1, max_len, num_hiddens))
        X = torch.arange(max_len, dtype=torch.float32).reshape(
            -1, 1) / torch.pow(10000, torch.arange(
            0, num_hiddens, 2, dtype=torch.float32) / num_hiddens)
        self.P[:, :, 0::2] = torch.sin(X)
        self.P[:, :, 1::2] = torch.cos(X)

    def forward(self, X):
        X = X + self.P[:, :X.shape[1], :].to(X.device)
        return self.dropout(X)

self.P = torch.zeros((1, max_len, num_hiddens))

max_len:序列长度

num_hiddens:特征维度

套公式

dropout是为了防止对位置编码太敏感

encoding_dim, num_steps = 32, 60
pos_encoding = PositionalEncoding(encoding_dim, 0)
pos_encoding.eval()
X = pos_encoding(torch.zeros((1, num_steps, encoding_dim)))
P = pos_encoding.P[:, :X.shape[1], :]
d2l.plot(torch.arange(num_steps), P[0, :, 6:10].T, xlabel='Row (position)',
         figsize=(6, 2.5), legend=["Col %d" % d for d in torch.arange(6, 10)])


在这里插入图片描述

for i in range(8):
    print(f'{i}的二进制是:{i:>03b}')
0的二进制是:000
1的二进制是:001
2的二进制是:010
3的二进制是:011
4的二进制是:100
5的二进制是:101
6的二进制是:110
7的二进制是:111
P = P[0, :, :].unsqueeze(0).unsqueeze(0)
d2l.show_heatmaps(P, xlabel='Column (encoding dimension)',
                  ylabel='Row (position)', figsize=(3.5, 4), cmap='Blues')

在这里插入图片描述

下一节就是激动人心的Transformer了。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值