自2017年發表的「Attention Is All You Need」論文以來,Transformer架構一直是自然語言處理(NLP)領域的基石。它的設計多年來基本上沒有變化,隨著旋轉位置編碼(RoPE)的引入,2022年標誌著該領域的重大發展。
旋轉位置嵌入是最先進的 NLP 位置嵌入技術。大多數流行的大型語言模型(如 Llama、Llama2、PaLM 和 CodeGen)已經在使用它。在本文中,我們將深入探討什麼是旋轉位置編碼,以及它們如何巧妙地整合絕對位置嵌入和相對位置嵌入的優點。
為了理解RoPE 的重要性,我們先回顧為什麼位置編碼至關重要。 Transformer 模型根據其固有的設計,不會考慮輸入標記的順序。
例如,像「the dog chases the pig 」和「the pig chases the dogs」這樣的短語雖然含義不同,但由於它們被視為一組無序的標記,因此被視為無法區分。為了維護序列資訊及其意義,需要一個表示來將位置資訊整合到模型中。
為了對句子中的位置進行編碼,需要使用具有相同維度的向量的另一個工具,其中每個向量代表句子中的一個位置。例如,在句子中的第二個單字指定特定向量。因此,每個句子位置都有其獨特的向量。然後透過將單字嵌入與其對應位置的嵌入結合起來,來形成Transformer層的輸入。
有兩種主要方法來產生這些嵌入:
#儘管使用廣泛但絕對位置嵌入也並非沒有缺點:
相對位置不是專注於句子中記的絕對位置,而是專注於記對之間的距離。此方法不會直接在詞向量中加入位置向量。而是改變了注意力機制以納入相對位置資訊。
T5(Text-to-Text Transfer Transformer)是利用相對位置嵌入的著名模型。 T5 引入了一種處理位置資訊的微妙方式:
儘管它們在理論上很有吸引力,但相對位置編碼得問題很嚴重
由於這些工程複雜性,位置編碼未被廣泛採用,特別是在較大的語言模型中。
RoPE 代表了一種編碼位置資訊的新方法。傳統方法中無論是絕對方法或相對方法,都有其限制。絕對位置編碼為每個位置分配一個唯一的向量,雖然簡單但不能很好地擴展並且無法有效捕獲相對位置;相對位置編碼關注標記之間的距離,增強模型對標記關係的理解,但使模型架構複雜化。
RoPE巧妙地結合了兩者的優點。允許模型理解標記的絕對位置及其相對距離的方式對位置資訊進行編碼。這是透過旋轉機制實現的,其中序列中的每個位置都由嵌入空間中的旋轉表示。 RoPE 的優雅之處在於其簡單性和高效性,這使得模型能夠更好地掌握語言語法和語義的細微差別。
旋轉矩陣源自於我們在高中學到的正弦和餘弦的三角性質,使用二維矩陣應該足以獲得旋轉矩陣的理論,如下所示!
我們看到旋轉矩陣保留了原始向量的大小(或長度),如上圖中的「r」所示,唯一改變的是與x軸的角度。
RoPE 引進了一個新穎的概念。它不是添加位置向量,而是對詞向量應用旋轉。旋轉角度 (θ) 與單字在句子中的位置成正比。第一個位置的向量旋轉 θ,第二個位置的向量旋轉 2θ,依此類推。這個方法有幾個好處:
RoPE的技術實作涉及旋轉矩陣。在 2D 情況下,論文中的方程式包含一個旋轉矩陣,該矩陣將向量旋轉 Mθ 角度,其中 M 是句子中的絕對位置。這種旋轉應用於 Transformer 自註意力機制中的查詢向量和鍵向量。
對於更高維度,向量被分成 2D 區塊,並且每對獨立旋轉。這可以被想像成一個在空間中旋轉的 n 維。聽著這個方法好好像實作是複雜,其實不然,這在 PyTorch 等函式庫只需要大約十行程式碼就可以有效率的實作。
import torch import torch.nn as nn class RotaryPositionalEmbedding(nn.Module): def __init__(self, d_model, max_seq_len): super(RotaryPositionalEmbedding, self).__init__() # Create a rotation matrix. self.rotation_matrix = torch.zeros(d_model, d_model, device=torch.device("cuda")) for i in range(d_model): for j in range(d_model): self.rotation_matrix[i, j] = torch.cos(i * j * 0.01) # Create a positional embedding matrix. self.positional_embedding = torch.zeros(max_seq_len, d_model, device=torch.device("cuda")) for i in range(max_seq_len): for j in range(d_model): self.positional_embedding[i, j] = torch.cos(i * j * 0.01) def forward(self, x): """Args:x: A tensor of shape (batch_size, seq_len, d_model). Returns:A tensor of shape (batch_size, seq_len, d_model).""" # Add the positional embedding to the input tensor. x += self.positional_embedding # Apply the rotation matrix to the input tensor. x = torch.matmul(x, self.rotation_matrix) return x
为了旋转是通过简单的向量运算而不是矩阵乘法来执行。距离较近的单词更有可能具有较高的点积,而距离较远的单词则具有较低的点积,这反映了它们在给定上下文中的相对相关性。
使用 RoPE 对 RoBERTa 和 Performer 等模型进行的实验表明,与正弦嵌入相比,它的训练时间更快。并且该方法在各种架构和训练设置中都很稳健。
最主要的是RoPE是可以外推的,也就是说可以直接处理任意长的问题。在最早的llamacpp项目中就有人通过线性插值RoPE扩张,在推理的时候直接通过线性插值将LLAMA的context由2k拓展到4k,并且性能没有下降,所以这也可以证明RoPE的有效性。
代码如下:
import transformers old_init = transformers.models.llama.modeling_llama.LlamaRotaryEmbedding.__init__ def ntk_scaled_init(self, dim, max_position_embeddings=2048, base=10000, device=None): #The method is just these three linesmax_position_embeddings = 16384a = 8 #Alpha valuebase = base * a ** (dim / (dim-2)) #Base change formula old_init(self, dim, max_position_embeddings, base, device) transformers.models.llama.modeling_llama.LlamaRotaryEmbedding.__init__ = ntk_scaled_init
旋转位置嵌入代表了 Transformer 架构的范式转变,提供了一种更稳健、直观和可扩展的位置信息编码方式。
RoPE不仅解决了LLM context过长之后引起的上下文无法关联问题,并且还提高了训练和推理的速度。这一进步不仅增强了当前的语言模型,还为 NLP 的未来创新奠定了基础。随着我们不断解开语言和人工智能的复杂性,像 RoPE 这样的方法将有助于构建更先进、更准确、更类人的语言处理系统。
以上是大語言模型中常用的旋轉位置編碼RoPE詳解:為什麼它比絕對或相對位置編碼更好?的詳細內容。更多資訊請關注PHP中文網其他相關文章!