Transformer系列:快速通俗理解Transformer的位置編碼

關(guān)鍵詞:Transformer因妇,位置編碼

內(nèi)容提要

  • 位置編碼的目的
  • 位置編碼的多種方式
  • 從代碼理解sin-cos位置編碼特性
  • sin-cos位置編碼如何表達(dá)相對位置信息

位置編碼的目的

注意力Attention這種操作具有排列不變性伐债,輸入元素位置的變動不會對注意力結(jié)果產(chǎn)生影響,從而模型無法感知位置信息,而在自然語言處理場景,字/詞的順序位置關(guān)系信息尤為重要,同樣的字詞不同的順序可能導(dǎo)致句子的語言完全不一樣。
Transformer中采用Self-Attention羽资,每個詞和整個句子所有詞兩兩一對計算相似度權(quán)重,詞與詞的位置隨意變動一下不會導(dǎo)致最終計算該對詞的注意力權(quán)重產(chǎn)生變化瓮栗,進(jìn)一步導(dǎo)致注意力層的整個結(jié)果不變削罩,嚴(yán)格來說是結(jié)果中每一個詞向量計算完全一致,僅僅是詞向量在輸出矩陣的排列隨著詞和詞位置互換而對應(yīng)調(diào)整了一下费奸,舉個例子

                                         [ [0.3, 0.2, 0.1, 0.5]
[我弥激,愛,你]  => self attention layers =>    [0.1, -0.1, -0.2, 0.3], 
                                           [0.5, 0.5, 0.1, -0.1] ]
                                         [  [0.5, 0.5, 0.1, -0.1]
[你愿阐,愛微服,我]  => self attention layers =>    [0.1, -0.1, -0.2, 0.3], 
                                           [0.3, 0.2, 0.1, 0.5] ]

將[我,愛缨历,你]輸入一組Q以蕴,K,V組成的Self-Attention產(chǎn)出的向量辛孵,和[你丛肮,愛,我] 輸入同一組Q魄缚,K宝与,V組成的Self-Attention產(chǎn)出的向量焚廊,兩者的結(jié)果每個詞/字的embedding輸出一致,僅僅是在矩陣的位置調(diào)換了一下(1和3對調(diào))习劫。
而此時如果下游網(wǎng)絡(luò)是聚合池化操作咆瘟,則池化后的結(jié)果完全一致,徹底失去位置信息诽里,比如transformer之后使用均值池化去做文本分類袒餐,如果不做池化做flatten輸出,也僅僅是特征列和特征列交換位置谤狡,對下游是全連接Dense結(jié)構(gòu)而言是一致的效果灸眼。
因此需要引入位置編碼表達(dá)出每個句子中字/詞的位置信息,配合字/詞本身的embedding一起加入模型進(jìn)行訓(xùn)練豌汇。


位置編碼的多種方式

位置編碼是需要設(shè)計的幢炸,主要有絕對位置編碼和相對位置編碼

  • 絕對位置編碼:在輸入層做文章泄隔,為每個輸入的字/詞增加一個對應(yīng)位置編碼拒贱,該位置編碼只與位置k相關(guān),每個字/詞的輸入是自身編碼和位置編碼的融合佛嬉。絕對位置編碼包括可學(xué)習(xí)式逻澳,固定式等方法,比如BERT暖呕、GPT采用可學(xué)習(xí)式將位置編碼當(dāng)作可訓(xùn)練參數(shù)斜做,本文的Transformer采用的是無參數(shù)的固定式三角函數(shù)計算。
  • 相對位置編碼:在模型網(wǎng)絡(luò)層做文章湾揽,使得模型的Self-Attention能夠考慮詞和詞之間的相對距離瓤逼,而非每個詞都單獨(dú)標(biāo)注位置和距離,讓模型通過數(shù)據(jù)自己學(xué)習(xí)位置信息库物。

本文主要介紹Transformer中的sin-cos位置編碼


從代碼理解sin-cos位置編碼

先給到Transformer的sin-cos位置編碼公式

位置編碼公式

其中pos代表句子中詞的位置霸旗,2i或者2i+1代表位置編碼向量的一個分量,2i代表偶數(shù)戚揭,2i+1代表奇數(shù)诱告,由此可見某個詞的位置編碼是一個向量不是一個值,它由詞的位置民晒,以及分量位置兩個共同決定的精居。
進(jìn)一步看代碼實現(xiàn),從結(jié)果看sin-cos位置編碼在做什么

def GetPosEncodingMatrix(max_len, d_emb):
    # 位置編碼
    pos_enc = np.array([
        [pos / np.power(10000, 2 * (j // 2) / d_emb) for j in range(d_emb)]
        if pos != 0 else np.zeros(d_emb)
        for pos in range(max_len)
    ])
    pos_enc[1:, 0::2] = np.sin(pos_enc[1:, 0::2])  # dim 2i
    pos_enc[1:, 1::2] = np.cos(pos_enc[1:, 1::2])  # dim 2i+1
    return pos_enc

設(shè)置max_len為每個句子的最大長度為50潜必,d_emb為每個詞的embedding的維度為256靴姿,最終得到一個[50, 256]的位置編碼矩陣,每一行代表一個位置的位置編碼結(jié)果磁滚,每一列代表某個詞在某個位置編碼分量上的值佛吓。所有句子共享這個位置編碼矩陣,也就是說所有句子相同位置的字/詞的位置編碼結(jié)果是一致的,位置編碼矩陣?yán)锩婷總€值用熱力圖畫出來如下

位置編碼矩陣熱力圖

進(jìn)一步深入代碼辈毯,我們重新設(shè)置參數(shù)max_len=6坝疼,d_emb=4把計算結(jié)果全部列出來觀察

一個6*4的位置矩陣計算過程

其中矩陣第一行是全0向量,當(dāng)輸入序列的元素id是0時直接映射為這個全0向量來表示位置谆沃,我們進(jìn)一步結(jié)合源碼看下原始序列id映射為位置矩陣的代碼

class PosEncodingLayer:
    def __init__(self, max_len, d_emb):
        # 位置編碼不跟隨訓(xùn)練
        self.pos_emb_matrix = Embedding(max_len, d_emb, trainable=False, weights=[GetPosEncodingMatrix(max_len, d_emb)])

    def get_pos_seq(self, x):
        mask = K.cast(K.not_equal(x, 0), 'int32')
        # 這個cumsum在拿pos位置
        pos = K.cumsum(K.ones_like(x, 'int32'), 1)
        return pos * mask

    def __call__(self, seq, pos_input=False):
        x = seq
        if not pos_input:
            # 排除掉padding的钝凶,padding的置為0
            x = Lambda(self.get_pos_seq)(x)
        return self.pos_emb_matrix(x)

其中K.cumsum在將所有序列元素從1開始自增轉(zhuǎn)化為數(shù)字id,同時mask判斷得到padding為0的位置唁影,將K.cumsum的結(jié)果改為0耕陷,因此輸入序列id中所有padding位置都以全0向量作為位置編碼
除了第一行以外据沈,位置矩陣的所有值都是三角函數(shù)sin哟沫,cos的結(jié)果,因此所有位置和各分量上的結(jié)果都是介于-1到1之間的锌介,使得位置編碼值固定在一個區(qū)間內(nèi)不會太大或者太小嗜诀,從而使得位置編碼和詞原始embedding相加存在可行性。
進(jìn)一步橫向觀察表格孔祸,每個分量上是sin隆敢,cos輪流交替的,一對相鄰的偶數(shù)和奇數(shù)分量形成一對崔慧,該對的三角函數(shù)輸入相同拂蝎,每一行的POS相同,因此三角函數(shù)輸入的分母相同惶室,差異在分母温自。
再從縱向看,每個分量位置相同皇钞,因此差異在三角函數(shù)的輸入分子悼泌,此時POS不同,POS不斷自增加1鹅士。

總結(jié)

  • 位置編碼將詞的位置信息表征為向量券躁,該向量由詞位置和分量位置共同確定
  • 位置編碼矩陣所有句子共享,因此不同句子第n個詞的位置編碼結(jié)果相同
  • 對輸入padding的位置采用全0向量作為位置編碼
  • 采用sin-cos位置編碼保證了位置向量值在-1~1之間掉盅,穩(wěn)定可控
  • 在單個詞的位置向量上也拜,sin和cos形成一對交替出現(xiàn)
  • 所有POS相同分量上的三角函數(shù)相同(偶數(shù)都是sin,奇數(shù)都是cos)趾痘,差別僅是POS值不同

sin-cos位置編碼如何表達(dá)相對位置距離

從上一節(jié)僅能看出sin-cos位置編碼能夠?qū)ξ恢貌煌M(jìn)行差異化刻畫慢哈,同時輸出結(jié)果穩(wěn)定在-1到1之間,使得和原始embedding相加存在可行性永票,并沒有什么了不起的地方卵贱,實際上由于三角函數(shù)公式的特性滥沫,sin-cos位置編碼具有表達(dá)相對位置的能力,給定距離键俱,任意位置的位置編碼都可以表達(dá)為一個已知位置的位置編碼的關(guān)于距離的線性組合兰绣。
三角函數(shù)具有如下特性

三角函數(shù)公式

令一個已知位置pos,要表達(dá)距離該pos距離為k的另一個pos的位置編碼编振,套用三角函數(shù)公式如下


已知pos和距離

求解這組權(quán)重u缀辩,v即可通過已知pos的位置編碼計算出距離k的位置編碼

u and v

下面舉例進(jìn)行說明

1.通過位置2計算出位置3的位置編碼
通過位置2計算位置3(1)

根據(jù)公式,POS=3位置的第i=0的分量可以由POS=2位置的第i=0和i=1兩個結(jié)果的線性組合而計算得到

>>> # 線性組合的結(jié)果
>>> np.cos(1) * np.sin(2 / np.power(10000, 0 / 4)) + np.sin(1) * np.cos(2 / np.power(10000, 0 / 4))
0.1411200080598673
>>> # 直接生成的結(jié)果
>>> np.sin(3 / np.power(10000, 0 / 4))
0.1411200080598672

其中u=cos(1)踪央,v=sin(1)臀玄,線性組合的結(jié)果和直接生成的結(jié)果相同。
同理看一下POS=3的第2個位置分量

通過位置2計算位置3(2)
>>> np.cos(1 / 10000 ** (2 / 4)) * np.sin(2 / np.power(10000, 2 / 4)) + np.sin(1 / 10000 ** (2 / 4)) * np.cos(2 / np.power(10000, 2 / 4))
0.02999550020249566
>>> np.sin(3 / np.power(10000, 2 / 4))
0.02999550020249566
2.通過位置2計算出位置4的位置編碼
通過位置2計算位置4
>>> np.cos(1 / 10000 ** (2 / 4) * 2) * np.sin(2 / np.power(10000, 2 / 4)) + np.sin(1 / 10000 ** (2 / 4) * 2) * np.cos(2 / np.power(10000, 2 / 4))
0.03998933418663416
>>> np.sin(4 / np.power(10000, 2 / 4))
0.03998933418663416

計算結(jié)果一致畅蹂,結(jié)論是sin-cos這種位置編碼方式健无,任意位置的位置編碼都可以表達(dá)為一個已知位置的位置編碼的關(guān)于距離的線性組合。也是因為有這個特質(zhì)采用三角函數(shù)表征位置信息液斜,同時由于padding的詞不需要存在這種相對位置表達(dá)性質(zhì)累贤,因此對padding的位置向量做了全0處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旗唁,一起剝皮案震驚了整個濱河市畦浓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌检疫,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祷嘶,死亡現(xiàn)場離奇詭異屎媳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)论巍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門烛谊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嘉汰,你說我怎么就攤上這事丹禀。” “怎么了鞋怀?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵双泪,是天一觀的道長。 經(jīng)常有香客問我密似,道長焙矛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任残腌,我火速辦了婚禮村斟,結(jié)果婚禮上贫导,老公的妹妹穿的比我還像新娘。我一直安慰自己蟆盹,他們只是感情好孩灯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逾滥,像睡著了一般钱反。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匣距,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天面哥,我揣著相機(jī)與錄音,去河邊找鬼毅待。 笑死尚卫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尸红。 我是一名探鬼主播吱涉,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼外里!你這毒婦竟也來了怎爵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤盅蝗,失蹤者是張志新(化名)和其女友劉穎鳖链,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體墩莫,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芙委,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了狂秦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灌侣。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖裂问,靈堂內(nèi)的尸體忽然破棺而出侧啼,到底是詐尸還是另有隱情,我是刑警寧澤堪簿,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布痊乾,位于F島的核電站,受9級特大地震影響戴甩,放射性物質(zhì)發(fā)生泄漏符喝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一甜孤、第九天 我趴在偏房一處隱蔽的房頂上張望协饲。 院中可真熱鬧畏腕,春花似錦、人聲如沸茉稠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽而线。三九已至铭污,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間膀篮,已是汗流浹背嘹狞。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留誓竿,地道東北人磅网。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像筷屡,于是被迫代替她去往敵國和親涧偷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容