在大語言模型(LLM)中,位置編碼(Positional Encoding)是用于表示輸入序列中詞匯或標(biāo)記相對位置的技術(shù)。由于Transformer架構(gòu)本身并沒有內(nèi)建順序信息,位置編碼是為了讓模型能夠理解詞與詞之間的順序關(guān)系。以下是一些常用的位置編碼方法:
一、常用位置編碼
1. 固定位置編碼(Sinusoidal Position Encoding)
由Vaswani等人在《Attention is All You Need》論文中提出,是Transformer模型中的經(jīng)典位置編碼方法。
使用正弦(sine)和余弦(cosine)函數(shù)生成不同頻率的編碼:

其中,pos是位置,i是維度索引,d是嵌入的維度大?。╡mbedding的shape)。
- 優(yōu)點(diǎn):
- 可外推能力強(qiáng):即使輸入序列長度大于訓(xùn)練長度,編碼依然有效。
- 無需學(xué)習(xí)參數(shù):位置編碼是由公式生成,不增加模型參數(shù)量。
- 可解釋性強(qiáng):具有周期性和規(guī)律性,在數(shù)學(xué)上可以分析和理解
- 缺點(diǎn):
- 缺乏靈活性:無法針對特定任務(wù)或數(shù)據(jù)學(xué)習(xí)更有效的位置表示。
- 固定模式可能不適配任務(wù)需求:對某些結(jié)構(gòu)信息復(fù)雜的任務(wù)可能表達(dá)力不足。
- 與詞嵌入無耦合學(xué)習(xí):與 token embedding 是分離的,無法共同優(yōu)化。
2. 學(xué)習(xí)型位置編碼(Learnable Position Encoding)
在這種方法中,位置編碼作為模型的可訓(xùn)練參數(shù)來學(xué)習(xí),而不是使用固定的公式生成。
每個位置有一個對應(yīng)的嵌入向量,訓(xùn)練過程中這些向量與其他詞嵌入一起進(jìn)行優(yōu)化。
- 優(yōu)點(diǎn):
- 可任務(wù)自適應(yīng)學(xué)習(xí):模型可以根據(jù)任務(wù)自動調(diào)整位置編碼,提高性能。
- 表達(dá)能力更強(qiáng):位置表示可嵌入特定語言模式,適合結(jié)構(gòu)復(fù)雜的語言任務(wù)。
- 與詞嵌入一起學(xué)習(xí)優(yōu)化:能與 token embedding 一起訓(xùn)練,形成更合理的上下文表示。
- 缺點(diǎn):
- 無法外推:訓(xùn)練時(shí)只學(xué)習(xí)固定長度(如 512、1024)的位置信息,超長序列無法處理。
- 增加參數(shù)量:每一個位置都要存儲一個向量,位置越多,參數(shù)越多。
- 不具備可解釋性:學(xué)習(xí)結(jié)果較難解讀,缺乏數(shù)學(xué)解釋性。
3. 相對位置編碼(Relative Position Encoding)
這種方法不直接編碼絕對位置,而是編碼詞語間的相對距離。通過這種方式,模型能夠?qū)W⒂诓蹲皆~之間的相對關(guān)系,而不僅僅是其絕對位置。
一種流行的實(shí)現(xiàn)方法是通過 相對位置注意力(Relative Attention),例如 T5 和 Transformer-XL 中的實(shí)現(xiàn)。
- 優(yōu)點(diǎn):
- 能夠更好地處理變長輸入序列。
- 相對位置使得模型能更好地捕捉詞語間的關(guān)系,而不僅僅是位置。
- 缺點(diǎn):
- 可能需要額外的計(jì)算和復(fù)雜的模型設(shè)計(jì)。
4. 旋轉(zhuǎn)位置編碼(Rotary Position Encoding, RoPE)
旋轉(zhuǎn)位置編碼是一種創(chuàng)新的相對位置編碼方法,通過旋轉(zhuǎn)嵌入向量來傳遞位置信息。這種方法在 GPT-3 和一些最新的大型預(yù)訓(xùn)練模型中得到了應(yīng)用。
- 優(yōu)點(diǎn):
- 更加有效地表示位置間的相對關(guān)系,尤其是在長序列中。
- 在長文本任務(wù)中表現(xiàn)更好。
- 缺點(diǎn):
可能需要更復(fù)雜的數(shù)學(xué)理解和實(shí)現(xiàn)。
5. 絕對+相對位置編碼混合(Absolute and Relative Position Encoding Mix)
一些最新的研究提出將絕對位置編碼與相對位置編碼結(jié)合使用。例如,DeBERTa(Decoding-enhanced BERT with disentangled attention)模型采用了這種混合方法。
- 優(yōu)點(diǎn):
- 結(jié)合了兩種編碼的優(yōu)勢,能兼顧序列的絕對和相對結(jié)構(gòu)信息。
- 缺點(diǎn):
- 需要更多的參數(shù)和計(jì)算資源。
6. 全局位置編碼(Global Contextual Position Encoding)
這是一種嘗試捕捉全局上下文信息的編碼方法,例如通過全局注意力機(jī)制來編碼位置信息。這種方法能夠處理長文本并保留文本的全局結(jié)構(gòu)。
- 優(yōu)點(diǎn):
- 可以更好地處理長文本和全局依賴關(guān)系。
- 缺點(diǎn):
- 實(shí)現(xiàn)復(fù)雜且需要更多計(jì)算資源。
7. 結(jié)構(gòu)化位置編碼(Structural Position Encoding)
該方法通過編碼更為復(fù)雜的結(jié)構(gòu)信息,如句法結(jié)構(gòu)、樹形結(jié)構(gòu)等,以增強(qiáng)模型對句法結(jié)構(gòu)的理解。
這種方法更多應(yīng)用于圖神經(jīng)網(wǎng)絡(luò)(GNN)與自然語言處理結(jié)合的模型中。
- 優(yōu)點(diǎn):
- 能更好地捕捉句法或語義關(guān)系。
- 缺點(diǎn):
- 對輸入結(jié)構(gòu)的要求更高,且模型更復(fù)雜。
8. 稀疏位置編碼(Sparse Position Encoding)
為了應(yīng)對長文本序列中的位置編碼問題,稀疏位置編碼只為特定位置編碼,而不為每個位置都提供編碼,從而減少計(jì)算量。
這種方法在某些長文本模型中得到了應(yīng)用,比如Sparse Transformer。
- 優(yōu)點(diǎn):
- 降低了計(jì)算復(fù)雜度,特別是在長序列處理中。
- 缺點(diǎn):
- 可能喪失某些細(xì)粒度的位置信息。
總結(jié)
固定位置編碼(Sinusoidal)和學(xué)習(xí)型位置編碼是最常見的基礎(chǔ)方法,廣泛應(yīng)用于多種任務(wù)。
相對位置編碼和旋轉(zhuǎn)位置編碼則主要應(yīng)用于長序列處理和模型優(yōu)化中,尤其是對于GPT等模型。
更高級的技術(shù)如全局位置編碼和稀疏位置編碼等在特定任務(wù)中能提供更強(qiáng)的性能,尤其是在長序列的處理上。
選擇哪種位置編碼方法,通常取決于任務(wù)的需求、序列長度以及計(jì)算資源的限制。
二、用python實(shí)現(xiàn)
1. 固定位置編碼
import numpy as np
import matplotlib.pyplot as plt
def positional_encoding(seq_len, d_model):
"""
生成固定位置編碼(Sinusoidal Position Encoding)
Parameters:
seq_len (int): 輸入序列的長度
d_model (int): 嵌入的維度大小
Returns:
np.ndarray: 形狀為 (seq_len, d_model) 的位置編碼矩陣
"""
# 創(chuàng)建位置編碼矩陣,seq_len是序列長度,d_model是每個位置的編碼維度
pe = np.zeros((seq_len, d_model))
# 計(jì)算位置編碼
position = np.arange(0, seq_len)[:, np.newaxis] # 位置索引
div_term = np.exp(np.arange(0, d_model, 2) * -(np.log(10000.0) / d_model)) # 用于縮放的除數(shù)
# 填充偶數(shù)維度(sin)和奇數(shù)維度(cos)
pe[:, 0::2] = np.sin(position * div_term) # 偶數(shù)列使用正弦
pe[:, 1::2] = np.cos(position * div_term) # 奇數(shù)列使用余弦
return pe
# 示例
seq_len = 10 # 輸入序列長度
d_model = 16 # 嵌入維度
# 生成位置編碼
pe = positional_encoding(seq_len, d_model)
# 打印位置編碼
print("Position Encoding Matrix (shape: {}, {}):".format(pe.shape[0], pe.shape[1]))
print(pe)
# 可視化位置編碼
plt.imshow(pe, cmap='viridis', aspect='auto')
plt.colorbar()
plt.title('Sinusoidal Positional Encoding')
plt.xlabel('Embedding Dimensions')
plt.ylabel('Sequence Position')
plt.show()

2. 旋轉(zhuǎn)位置編碼
旋轉(zhuǎn)位置編碼(Rotary Positional Encoding, RoPE)是一種在Transformer模型中用于表示位置信息的技術(shù),其核心思想是通過對詞向量進(jìn)行旋轉(zhuǎn)操作來表示位置信息,而不是像傳統(tǒng)的正弦余弦位置編碼那樣通過直接加和位置向量。
RoPE 主要用于 增強(qiáng) Transformer 模型對相對位置的敏感性,特別是在處理長序列時(shí),它避免了傳統(tǒng)位置編碼的限制。RoPE 的一個關(guān)鍵特性是使用旋轉(zhuǎn)變換來計(jì)算每個位置的編碼,因此具有更好的擴(kuò)展性。
RoPE 的公式
對于每個位置 pos 和維度 i,RoPE 會計(jì)算一個旋轉(zhuǎn)矩陣并應(yīng)用于輸入的詞嵌入。這種旋轉(zhuǎn)通常在頻域上進(jìn)行,在不同維度上應(yīng)用不同的旋轉(zhuǎn)角度。
具體公式如下:

其中,θ_i 是用于旋轉(zhuǎn)的角度。
import numpy as np
def rotary_position_encoding(seq_len, dim, base=10000.0):
"""
生成 RoPE (Rotary Position Encoding) 編碼。
參數(shù):
- seq_len: 序列的最大長度(位置數(shù))
- dim: 詞嵌入的維度
- base: 頻率基準(zhǔn)(默認(rèn)10000)
返回:
- position_encoding: shape (seq_len, dim),位置編碼矩陣
"""
# 創(chuàng)建位置(從0到seq_len-1)
positions = np.arange(seq_len)
# 計(jì)算每個維度的頻率
freqs = np.arange(0, dim, 2)
div_term = np.exp(-np.log(base) * freqs / dim)
# 創(chuàng)建 RoPE 編碼矩陣
position_encoding = np.zeros((seq_len, dim))
for i in range(0, dim, 2):
# 使用sin和cos函數(shù)來計(jì)算旋轉(zhuǎn)位置編碼
pos = positions * div_term[i//2]
position_encoding[:, i] = np.cos(pos) # 偶數(shù)維度
position_encoding[:, i+1] = np.sin(pos) # 奇數(shù)維度
return position_encoding
# 示例
seq_len = 10 # 序列長度
dim = 16 # 嵌入維度
position_encoding = rotary_position_encoding(seq_len, dim)
print(position_encoding)
QA
Q1. 位置編碼的shape需要和embedding的shape相同嗎
A: 是的,位置編碼的形狀(shape)需要與詞嵌入的形狀一致。這是因?yàn)槲恢镁幋a是加到詞嵌入上的,它需要與每個單詞的詞嵌入(即詞向量)在維度上匹配,從而確保它們能夠按元素相加。
Q2. 學(xué)習(xí)型位置編碼 在推理的時(shí)候可以擴(kuò)展嗎?
A: 在Transformer模型中,位置編碼的作用是提供每個詞在序列中的位置信息。傳統(tǒng)的固定位置編碼(如正弦/余弦位置編碼)具有固定的形狀,它在訓(xùn)練期間是預(yù)先計(jì)算好的,并且可以在推理時(shí)直接使用。然而,學(xué)習(xí)型位置編碼(Learnable Positional Encoding)是通過訓(xùn)練學(xué)習(xí)到的,它可以根據(jù)訓(xùn)練數(shù)據(jù)自適應(yīng)地調(diào)整,而不是依賴固定的公式。
關(guān)于學(xué)習(xí)型位置編碼在推理時(shí)是否可以擴(kuò)展,主要取決于兩方面:
位置編碼的學(xué)習(xí)方式:
學(xué)習(xí)型位置編碼是通過優(yōu)化目標(biāo)函數(shù)(例如,損失函數(shù))在訓(xùn)練過程中學(xué)習(xí)得到的。這些位置編碼通常是一個可學(xué)習(xí)的矩陣,其維度通常是 (seq_len, d_model),其中seq_len是序列的長度,d_model是嵌入的維度。在訓(xùn)練時(shí),模型會將這些位置編碼與詞嵌入相加,幫助模型學(xué)習(xí)每個詞的順序信息。
推理時(shí)的擴(kuò)展:通常,學(xué)習(xí)型位置編碼會在訓(xùn)練時(shí)有一個固定的最大序列長度。因?yàn)槟P偷妮斎胪ǔJ且粋€有限長度的序列,在訓(xùn)練時(shí)位置編碼矩陣的大小是固定的(比如max_seq_len x d_model)。在推理時(shí),如果輸入序列長度超過了訓(xùn)練時(shí)的最大序列長度,就會遇到問題。
推理時(shí)的擴(kuò)展策略:
直接擴(kuò)展:如果模型在推理時(shí)的輸入序列長度超過了訓(xùn)練時(shí)的最大序列長度,簡單的擴(kuò)展學(xué)習(xí)型位置編碼是不可行的,因?yàn)閷W(xué)習(xí)型位置編碼是依賴于訓(xùn)練時(shí)的序列長度的,無法直接通過線性插值或重復(fù)來擴(kuò)展。
可能的解決方法:
使用相同的編碼:一種簡單的策略是,將學(xué)習(xí)型位置編碼中的最后一個位置編碼重復(fù)或復(fù)制到超出訓(xùn)練時(shí)最大長度的位置,直到達(dá)到推理時(shí)的最大序列長度。雖然這種方式較為粗糙,但在一些任務(wù)中可能能接受。
插值(Interpolation):另一種方法是對學(xué)習(xí)型位置編碼進(jìn)行插值。比如在推理時(shí),當(dāng)輸入序列長度超過訓(xùn)練時(shí)的最大長度時(shí),可以根據(jù)現(xiàn)有的學(xué)習(xí)型位置編碼,使用插值(如線性插值)生成新的位置編碼,這樣可以在一定程度上避免丟失位置信息。不過,這種方法會增加計(jì)算復(fù)雜度,并且可能會導(dǎo)致性能下降,因?yàn)橥评頃r(shí)的編碼和訓(xùn)練時(shí)的編碼可能會存在不一致性。
訓(xùn)練時(shí)使用更大的序列長度:一種更直接的方法是在訓(xùn)練時(shí)使用足夠大的序列長度,以保證在推理時(shí)輸入序列不會超過最大序列長度。這種方法可以避免推理時(shí)的擴(kuò)展問題,但會增加訓(xùn)練時(shí)的計(jì)算和內(nèi)存開銷。
學(xué)到的“通用”位置編碼:有些研究者嘗試學(xué)習(xí)一個更“通用”的位置編碼,能夠適應(yīng)不同長度的序列,而不僅僅是固定長度。這種方法需要在訓(xùn)練過程中使用更大范圍的序列長度,或者通過特別的技術(shù)來確保模型能應(yīng)對不同長度的序列。
總結(jié):
學(xué)習(xí)型位置編碼在推理時(shí)的擴(kuò)展不是直接支持的,因?yàn)樗鼈冊谟?xùn)練期間是學(xué)習(xí)得到的,并且通常是為訓(xùn)練時(shí)的最大序列長度而設(shè)計(jì)的。
如果在推理時(shí)輸入的序列長度超出了訓(xùn)練時(shí)的最大序列長度,可以考慮以下幾種擴(kuò)展策略:
- 重復(fù)最后一個位置編碼:直接擴(kuò)展編碼。
- 插值生成新的位置編碼:對原位置編碼進(jìn)行插值。
- 訓(xùn)練時(shí)使用更長的序列:增加訓(xùn)練時(shí)的序列長度。
- 學(xué)習(xí)更通用的位置編碼:使位置編碼能夠適應(yīng)不同長度的序列。
在選擇具體的擴(kuò)展方法時(shí),應(yīng)該考慮任務(wù)的特性和性能需求。