天天看點

李沐動手學深度學習V2-自注意力機制之位置編碼一. 自注意力機制之位置編碼

一. 自注意力機制之位置編碼

1. 位置編碼

在處理詞元序列時,循環神經網絡是逐個的重複地處理詞元的,而自注意力則因為并行計算而放棄了順序操作。為了使用序列的順序資訊,我們通過在輸入表示中添加位置編碼(positional encoding)來注入絕對的或相對的位置資訊。位置編碼可以通過學習得到也可以直接固定得到。下面使用基于正弦函數和餘弦函數的固定位置編碼:

假設輸入表示 X ∈ R n × d \mathbf{X} \in \mathbb{R}^{n \times d} X∈Rn×d包含一個序列中 n n n個詞元的 d d d維嵌入表示。位置編碼使用相同形狀的位置嵌入矩陣 P ∈ R n × d \mathbf{P} \in \mathbb{R}^{n \times d} P∈Rn×d輸出 X + P \mathbf{X} + \mathbf{P} X+P,矩陣第 i i i行、第 2 j 2j 2j列和 2 j + 1 2j+1 2j+1列上的元素為:

p i , 2 j = sin ⁡ ( i 1000 0 2 j / d ) , p i , 2 j + 1 = cos ⁡ ( i 1000 0 2 j / d ) . \begin{aligned} p_{i, 2j} &= \sin\left(\frac{i}{10000^{2j/d}}\right),\\p_{i, 2j+1} &= \cos\left(\frac{i}{10000^{2j/d}}\right).\end{aligned} pi,2j​pi,2j+1​​=sin(100002j/di​),=cos(100002j/di​).​

2. 位置編碼實作

import torch
import d2l.torch
from torch import nn
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(size=(1,max_len,num_hiddens))
        X = torch.arange(max_len,dtype=torch.float32).reshape(-1,1)/torch.pow(1000,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)
           

在位置嵌入矩陣 𝐏 中, 行代表詞元在序列中的位置,列代表不同次元的位置編碼。 如下面圖所示我們可以看到位置嵌入矩陣的第 6 列和第 7 列的頻率高于第 8 列和第 9 列。 第 6 列和第 7 列之間的偏移量(第 8 列和第 9 列相同)是由于正弦函數和餘弦函數的交替。

encoding_dim,num_steps = 32,60
pos_encoding = PositionalEncoding(encoding_dim,0)
pos_encoding.eval()
X = pos_encoding(torch.zeros(size=(1,num_steps,encoding_dim)))
P = pos_encoding.P[:,:X.shape[1],:]
d2l.torch.plot(torch.arange(num_steps),Y=P[0,:,6:10].T,xlabel='Row (position)',figsize=(6,2.5),legend=['Column %d' %d for d in torch.arange(6,10)])
           
李沐動手學深度學習V2-自注意力機制之位置編碼一. 自注意力機制之位置編碼

使用熱力圖顯示每一個樣本序列的位置編碼:

P = P[0,:,:].unsqueeze(0).unsqueeze(0)
d2l.torch.show_heatmaps(P,xlabel='Column(encoding dimension)',ylabel='Row (position)',figsize=(3.5,4),cmap='Blues')
           
李沐動手學深度學習V2-自注意力機制之位置編碼一. 自注意力機制之位置編碼

3. 相對位置資訊

除了捕獲絕對位置資訊之外,上述的位置編碼還允許模型學習得到輸入序列中相對位置資訊。這是因為對于任何确定的位置偏移 δ \delta δ,位置 i + δ i + \delta i+δ處的位置編碼可以線性投影位置 i i i處的位置編碼來表示。這種投影的數學解釋是,令 ω j = 1 / 1000 0 2 j / d \omega_j = 1/10000^{2j/d} ωj​=1/100002j/d,對于任何确定的位置偏移 δ \delta δ,任何一對 ( p i , 2 j , p i , 2 j + 1 ) (p_{i, 2j}, p_{i, 2j+1}) (pi,2j​,pi,2j+1​)都可以線性投影到 ( p i + δ , 2 j , p i + δ , 2 j + 1 ) (p_{i+\delta, 2j}, p_{i+\delta, 2j+1}) (pi+δ,2j​,pi+δ,2j+1​):

[ cos ⁡ ( δ ω j ) sin ⁡ ( δ ω j ) − sin ⁡ ( δ ω j ) cos ⁡ ( δ ω j ) ] [ p i , 2 j p i , 2 j + 1 ] = [ cos ⁡ ( δ ω j ) sin ⁡ ( i ω j ) + sin ⁡ ( δ ω j ) cos ⁡ ( i ω j ) − sin ⁡ ( δ ω j ) sin ⁡ ( i ω j ) + cos ⁡ ( δ ω j ) cos ⁡ ( i ω j ) ] = [ sin ⁡ ( ( i + δ ) ω j ) cos ⁡ ( ( i + δ ) ω j ) ] = [ p i + δ , 2 j p i + δ , 2 j + 1 ] , \begin{aligned} &\begin{bmatrix} \cos(\delta \omega_j) & \sin(\delta \omega_j) \\ -\sin(\delta \omega_j) & \cos(\delta \omega_j) \\ \end{bmatrix} \begin{bmatrix} p_{i, 2j} \\ p_{i, 2j+1} \\ \end{bmatrix}\\ =&\begin{bmatrix} \cos(\delta \omega_j) \sin(i \omega_j) + \sin(\delta \omega_j) \cos(i \omega_j) \\ -\sin(\delta \omega_j) \sin(i \omega_j) + \cos(\delta \omega_j) \cos(i \omega_j) \\ \end{bmatrix}\\ =&\begin{bmatrix} \sin\left((i+\delta) \omega_j\right) \\ \cos\left((i+\delta) \omega_j\right) \\ \end{bmatrix}\\ =& \begin{bmatrix} p_{i+\delta, 2j} \\ p_{i+\delta, 2j+1} \\ \end{bmatrix}, \end{aligned} ===​[cos(δωj​)−sin(δωj​)​sin(δωj​)cos(δωj​)​][pi,2j​pi,2j+1​​][cos(δωj​)sin(iωj​)+sin(δωj​)cos(iωj​)−sin(δωj​)sin(iωj​)+cos(δωj​)cos(iωj​)​][sin((i+δ)ωj​)cos((i+δ)ωj​)​][pi+δ,2j​pi+δ,2j+1​​],​

2 × 2 2\times 2 2×2投影矩陣不依賴于任何位置的索引 i i i。

4. 小結

  • 為了使用序列的順序資訊,可以通過在輸入表示中添加位置編碼,來注入絕對的或相對的位置資訊。

5. 全部代碼

import torch
import d2l.torch
from torch import nn


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(size=(1, max_len, num_hiddens))
        X = torch.arange(max_len, dtype=torch.float32).reshape(-1, 1) / torch.pow(1000, 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)


encoding_dim, num_steps = 32, 60
pos_encoding = PositionalEncoding(encoding_dim, 0)
pos_encoding.eval()
X = pos_encoding(torch.zeros(size=(1, num_steps, encoding_dim)))
P = pos_encoding.P[:, :X.shape[1], :]
d2l.torch.plot(torch.arange(num_steps), Y=P[0, :, 6:10].T, xlabel='Row (position)', figsize=(6, 2.5),
               legend=['Column %d' % d for d in torch.arange(6, 10)])
P = P[0, :, :].unsqueeze(0).unsqueeze(0)
d2l.torch.show_heatmaps(P, xlabel='Column(encoding dimension)', ylabel='Row (position)', figsize=(3.5, 4), cmap='Blues')
           

6. 相關連結

注意力機制第一篇:李沐動手學深度學習V2-注意力機制

注意力機制第二篇:李沐動手學深度學習V2-注意力評分函數

注意力機制第三篇:李沐動手學深度學習V2-基于注意力機制的seq2seq

注意力機制第四篇:李沐動手學深度學習V2-自注意力機制之位置編碼

注意力機制第五篇:李沐動手學深度學習V2-自注意力機制

注意力機制第六篇:李沐動手學深度學習V2-多頭注意力機制和代碼實作

注意力機制第七篇:李沐動手學深度學習V2-transformer和代碼實作

繼續閱讀