Main Reference
The Illustrated GPT-2 (Visualizing Transformer Language Models) – Jay Alammar – Visualizing machine learning one concept at a time. (jalammar.github.io) by Jay Alammar, excellent
[@alammarIllustratedGPT2] and [@alammarIllustratedGPT22022a]
Introduction
今年湧現出了許多機器學習的精彩應用,令人目不暇接,OpenAI 的 GPT-2 就是其中之一。它在文字生成上有著驚豔的表現,其生成的文字在上下文連貫性和情感表達上都超過了人們對目前階段語言模型的預期。僅從模型架構而言,GPT-2 並沒有特別新穎的架構,它和只帶有解碼器的 transformer 模型很像。
然而,GPT-2 有著超大的規模,它是一個在海量資料集上訓練的基於 transformer 的巨大模型。GPT-2 成功的背後究竟隱藏著什麼祕密?本文將帶你一起探索取得優異效能的 GPT-2 模型架構,重點闡釋其中關鍵的自注意力(self-attention)層,並且看一看 GPT-2 採用的只有解碼器的 transformer 架構在語言建模之外的應用。
作者之前寫過一篇相關的介紹性文章「The Illustrated Transformer」,本文將在其基礎上加入更多關於 transformer 模型內部工作原理的視覺化解釋,以及這段時間以來關於 transformer 模型的新進展。基於 transformer 的模型在持續演進,我們希望本文使用的這一套視覺化表達方法可以使此類模型更容易解釋。
Part 1: GPT-2和語言模型
什麼是語言模型?
何為語言模型
簡單說來,語言模型的作用就是根據已有句子的一部分,來預測下一個單詞會是什麼。最著名的語言模型你一定見過,就是我們手機上的輸入法,它可以根據當前輸入的內容智慧推薦下一個詞。
從這個意義上說,我們可以說 GPT-2 基本上相當於輸入法的單詞聯想功能,但它比你手機上安裝的此類應用大得多,也更加複雜。OpenAI 的研究人員使用了一個從網路上爬取的 40GB 超大資料集「WebText」訓練 GPT-2,該資料集也是他們的工作成果的一部分。
如果從佔用儲存大小的角度進行比較,我現在用的手機輸入法「SwiftKey」也就佔用了 78MB 的空間,而 GPT-2 的最小版本也需要至少 500MB 的空間來儲存它的全部引數,最大版本的 GPT-2 甚至需要超過 6.5GB 的儲存空間。
讀者可以用「AllenAI GPT-2 Explorer」(https://gpt2.apps.allenai.org/?text=Joel%20is)來體驗 GPT-2 模型。它可以給出可能性排名前十的下一個單詞及其對應概率,你可以選擇其中一個單詞,然後看到下一個可能單詞的列表,如此往復,最終完成一篇文章。
使用 Transformers 進行語言建模
正如本文作者在「The Illustrated Transformer 」這篇文章中所述,原始的 transformer 模型由編碼器(encoder)和解碼器(decoder)組成,二者都是由被我們稱為「transformer 模組」的部分堆疊而成。這種架構在機器翻譯任務中取得的成功證實了它的有效性,值得一提的是,這個任務之前效果最好的方法也是基於編碼器-解碼器架構的。
Transformer 的許多後續工作嘗試去掉編碼器 (e.g. GPT : Decoder Only) 或解碼器 (e.g. BERT : Encoder Only),也就是隻使用一套堆疊得儘可能多的 transformer 模組,然後使用海量文字、耗費大量的算力進行訓練(研究者往往要投入數百甚至數千美元來訓練這些語言模型,而在 AlphaStar 專案中則可能要花費數百萬美元)。
那麼我們究竟能將這些模組堆疊到多深呢?事實上,這個問題的答案也就是區別不同 GPT-2 模型的主要因素之一,如下圖所示。「小號」的 GPT-2 模型堆疊了 12 層,「中號」24 層,「大號」36 層,還有一個「特大號」堆疊了整整 48 層。
與 BERT 的區別
機器人第一法則
機器人不得傷害人類,或者目睹人類將遭受危險而袖手旁觀。
GPT-2 是使用「transformer 解碼器」構建的,而 BERT 則是通過「transformer 編碼器」構建的。我們將在下一節中詳述二者的區別,但這裡需要指出的是,二者一個很關鍵的不同之處在於:GPT-2 就像傳統的語言模型一樣,一次只輸出一個單詞(token)。下面是引導訓練好的模型「背誦」機器人第一法則的例子:
這種模型之所以效果好是因為在每個新單詞產生後,該單詞就被新增在之前生成的單詞序列後面,這個序列會成為模型下一步的新輸入。這種機制叫做自迴歸(auto-regression),同時也是令 RNN 模型效果拔群的重要因素之一。
GPT-2,以及一些諸如 TransformerXL 和 XLNet 等後續出現的模型,本質上都是自迴歸模型,而 BERT 則不然。這就是一個權衡的問題了。雖然沒有使用自迴歸機制,但 BERT 獲得了結合單詞前後的上下文資訊的能力,從而取得了更好的效果。XLNet 使用了自迴歸,並且引入了一種能夠同時兼顧前後的上下文資訊的方法。
Transformer 模組的演進
原始的 transformer 論文引入了兩種型別的 transformer 模組,分別是:編碼器和解碼器。
編碼器模組 (Encoder Block)
首先是編碼器模組:
原始 transformer 論文中的編碼器模組可以接受長度不超過最大序列長度(如 512 個單詞)的輸入。如果序列長度小於該限制,我們就在其後填入預先定義的空白單詞(如上圖中的
解碼器模組 (Decoder Block)
其次是解碼器模組,它與編碼器模組在架構上有一點小差異 - 加入了一層使得它可以重點關注編碼器輸出的某一片段,也就是下圖中的編碼器-解碼器自注意力(encoder-decoder self-attention)層。
解碼器在自注意力(self-attention)層上還有一個關鍵的差異:它將後面的單詞掩蓋掉了。但並不像 BERT 一樣將它們替換成特殊定義的單詞
舉個例子,如果我們重點關注 4 號位置單詞及其前續路徑,我們可以模型只允許注意當前計算的單詞以及之前的單詞:
能夠清楚地區分 BERT 使用的自注意力(self-attention)模組和 GPT-2 使用的帶掩模的自注意力(masked self-attention)模組很重要。普通的自注意力模組允許一個位置看到它右側單詞的資訊(如下左圖),而帶掩模的自注意力模組則不允許這麼做(如下右圖)。
只包含解碼器的模組 (Decoder-Only Block)
在 transformer 原始論文發表之後,一篇名為「Generating Wikipedia by Summarizing Long Sequences」的論文提出用另一種 transformer 模組的排列方式來進行語言建模——它直接扔掉了所有的 transformer 編碼器模組……我們姑且就管它叫做「Transformer-Decoder」模型吧。這個早期的基於 transformer 的模型由 6 個 transformer 解碼器模組堆疊而成:
圖中所有的解碼器模組都是一樣的,因此本文只展開了第一個解碼器的內部結構。可以看見,它使用了帶掩模的自注意力層。請注意,該模型在某個片段中可以支援最長 4000 個單詞的序列,相較於 transformer 原始論文中最長 512 單詞的限制有了很大的提升。
這些解碼器模組和 transformer 原始論文中的解碼器模組相比,除了去除了第二個自注意力層之外,並無很大不同。一個相似的架構在 Google 另一篇論文 “Character-Level Language Modeling with Deeper Self-Attention” 也就是在字母級 (a, b, c, d, …, “?”, “,”) 的語言建模中也被驗證有效,它使用更深的自注意力層構建語言模型,一次預測一個字母。
OpenAI 的 GPT-2 模型就用了這種只包含編碼器(decoder-only)的模組。
GPT-2 內部機制速成
在我內心,字字如刀;電閃雷鳴,使我瘋癲。——Budgie
接下來,我們將深入剖析 GPT-2 的內部結構,看看它是如何工作的。
GPT-2 可以處理最長 1024 個單詞的序列。每個單詞都會和它的前續路徑一起「流過」所有的解碼器模組。
想要執行一個訓練好的 GPT-2 模型,最簡單的方法就是讓它自己隨機工作(從技術上說,叫做生成無條件樣本)。或者我們也可以給它一點提示,讓它說一些關於特定主題的話(即生成互動式條件樣本)。在隨機情況下,我們只簡單地提供一個預先定義好的起始單詞 (訓練好的模型使用「endoftext」作為它的起始單詞,不妨將其稱為 <s> ),然後讓它自己生成文字。
此時,模型的輸入只有一個單詞,所以只有這個單詞的路徑是活躍的。單詞經過層層處理,最終得到一個向量。向量可以對於詞彙表的每個單詞計算一個概率(詞彙表是模型能「說出」的所有單詞,GPT-2 的詞彙表中有 50000 個單詞)。在本例中,我們選擇概率最高的單詞「The」作為下一個單詞。
但有時這樣會出問題——就像如果我們持續點選輸入法推薦單詞的第一個,它可能會陷入推薦同一個詞的迴圈中,只有你點選第二或第三個推薦詞,才能跳出這種迴圈。同樣的,GPT-2 也有一個叫做「top-k」的引數,模型會從概率前 k 大的單詞中抽樣選取下一個單詞。顯然,在之前的情況下,top-k = 1。
接下來,我們將輸出的單詞新增在輸入序列的尾部構建新的輸入序列,讓模型進行下一步的預測:
請注意,第二個單詞的路徑是當前唯一活躍的路徑了。GPT-2 的每一層都保留了它們對第一個單詞的解釋,並且將運用這些資訊處理第二個單詞(具體將在下面一節對自注意力機制的講解中詳述),GPT-2 不會根據第二個單詞重新解釋第一個單詞。
更加深入瞭解內部原理
輸入編碼
讓我們更加深入地瞭解一下模型的內部細節。首先,讓我們從模型的輸入開始。正如我們之前討論過的其它自然語言處理模型一樣,GPT-2 同樣從嵌入矩陣中查詢單詞對應的嵌入向量,該矩陣也是模型訓練結果的一部分。
每一行都是一個詞嵌入向量:一個能夠表徵某個單詞,並捕獲其意義的數字列表。嵌入向量的長度和 GPT-2 模型的大小有關,最小的模型使用了長度為 768 的嵌入向量 (embedding vector) 來表徵一個單詞。
所以在一開始,我們需要在嵌入矩陣中查詢起始單詞<s>對應的嵌入向量。但在將其輸入給模型之前,我們還需要引入位置編碼— 告訴 transformer 序列中的單詞順序的訊號。1024 個輸入序列位置中的每一個都對應一個位置編碼,這些編碼組成的矩陣也是訓練模型的一部分。
至此,輸入單詞在進入模型第一個 transformer 模組之前所有的處理步驟就結束了。如上文所述,訓練後的 GPT-2 模型包含兩個權值矩陣:嵌入矩陣和位置編碼矩陣。
將單詞輸入第一個 transformer 模組之前需要查到它對應的嵌入向量,再加上 1 號位置位置對應的位置向量。
堆疊之旅
第一個 transformer 模組處理單詞的步驟如下:首先通過自注意力層處理,接著將其傳遞給神經網路層。第一個 transformer 模組處理完但此後,會將結果向量被傳入堆疊中的下一個 transformer 模組,繼續進行計算。每一個 transformer 模組的處理方式都是一樣的,但每個模組都會維護自己的自注意力層和神經網路層中的權重。
回顧自注意力機制
語言的含義是極度依賴上下文的,比如下面這個機器人第二法則:
機器人第二法則
機器人必須遵守人類給它的命令,除非該命令違背了第一法則。
Second Law of Robotics A robot must obey the orders given it by human beings except where such orders would conflict with the First Law.
我在這句話中高亮表示了三個地方,這三處單詞指代的是其它單詞。除非我們知道這些詞指代的上下文聯絡起來,否則根本不可能理解或處理這些詞語的意思。當模型處理這句話的時候,它必須知道:
- 「它」指代機器人
- 「命令」指代前半句話中人類給機器人下的命令,即「人類給它的命令」
- 「第一法則」指機器人第一法則的完整內容
這就是自注意力機制所做的工作,它在處理每個單詞(將其傳入神經網路)之前,融入了模型對於用來解釋某個單詞的上下文的相關單詞的理解。具體做法是,給序列中每一個單詞都賦予一個相關度得分,之後對他們的向量表徵求和。
舉個例子,最上層的 transformer 模組在處理單詞「it」的時候會關注「a robot」,所以「a」、「robot」、「it」這三個單詞與其得分相乘加權求和後的特徵向量會被送入之後的神經網路層。
自注意力機制
自注意力機制沿著序列中每一個單詞的路徑進行處理,主要由 3 個向量組成:
- 查詢向量(Query 向量):當前單詞的查詢向量被用來和其它單詞的鍵向量相乘,從而得到其它詞相對於當前詞的注意力得分。我們只關心目前正在處理的單詞的查詢向量。
- 鍵向量(Key 向量):鍵向量就像是序列中每個單詞的標籤,它使我們搜尋相關單詞時用來匹配的物件。
- 值向量(Value 向量):值向量是單詞真正的表徵,當我們算出注意力得分後,使用值向量進行加權求和得到能代表當前位置上下文的向量。
一個簡單粗暴的比喻是在檔案櫃中找檔案。 Query 向量就像一張便利貼,上面寫著你正在研究的課題。 Key 向量像是檔案櫃中資料夾上貼的標籤。當你找到和便利貼上所寫相匹配的資料夾時,拿出它,資料夾裡的東西便是 Value 向量。只不過我們最後找的並不是單一的值向量,而是很多資料夾值向量的混合。
將單詞的查詢向量分別乘以每個資料夾的鍵向量,得到各個資料夾對應的注意力得分(這裡的乘指的是向量點乘,乘積會通過 softmax 函式處理)。
我們將每個資料夾的值向量乘以其對應的注意力得分,然後求和,得到最終自注意力層的輸出。
這樣將值向量加權混合得到的結果是一個向量,它將其 50% 的「注意力」放在了單詞「robot」上,30% 的注意力放在了「a」上,還有 19% 的注意力放在「it」 上。我們之後還會更詳細地講解自注意力機制,讓我們先繼續向前探索 transformer 堆疊,看看模型的輸出。
模型輸出
當最後一個 transformer 模組產生輸出之後(即經過了它自注意力層和神經網路層的處理),模型會將輸出的向量乘上嵌入矩陣。
我們知道,嵌入矩陣的每一行都對應模型的詞彙表中一個單詞的嵌入向量。所以這個乘法操作得到的結果就是詞彙表中每個單詞對應的注意力得分。
我們簡單地選取得分最高的單詞作為輸出結果(即 top-k = 1)。但其實如果模型考慮其他候選單詞的話,效果通常會更好。所以,一個更好的策略是對於詞彙表中得分較高的一部分單詞,將它們的得分作為概率從整個單詞列表中進行抽樣(得分越高的單詞越容易被選中)。通常一個折中的方法是,將 top-k 設為 40,這樣模型會考慮注意力得分排名前 40 位的單詞。
這樣,模型就完成了一輪迭代,輸出了一個單詞。模型會接著不斷迭代,直到生成一個完整的序列——序列達到 1024 的長度上限或序列中產生了一個終止符。
第一部分結語:這就是 GPT-2
本文是 GPT-2 模型工作原理的一個概覽。如果你還是對自注意力層內部深層的細節很好奇。我們將引入更多視覺化語言來試著解釋自注意力層的工作原理,同時也是為了能夠更好地描述之後基於 transformer 的模型(說的就是你們,TransformerXL 還有 XLNet)。
這篇文章中有一些過分簡化的地方:
- 混用了 words 和 tokens 這兩個概念。但事實上,GPT-2 使用位元組對編碼(Byte Pair Encoding)方式來建立詞彙表中的 tokens ,也就是說 tokens 其實通常只是 words 的一部分。
- 舉的例子其實是 GPT-2 在 inference / evaluation 模式下執行的流程,所以一次只處理一個 word。在訓練過程中,模型會在更長的文字序列上進行訓練,並且一次處理多個 tokens。訓練過程的 batch size 也更大(512),而 inference 時的 batch size 只有 1。
- 為了更好地組織空間中的影象,作者畫圖時隨意轉置了向量,但在實現時需要更精確。
- Transformer 模組使用了很多歸一化(normalization)層,這在訓練中是很關鍵的。我們在「The Illustrated Transformer」(https://jalammar.github.io/illustrated-transformer/)譯文中提到了其中一些,但本文更關注自注意力層。
- 有時文章需要用更多的小方塊來代表一個向量,我把這些情況叫做「放大」,如下圖所示。
Part 2: 圖解自注意力機制
Beyond Language Modeling
只有decoder的transformer不斷顯示出超越語言模型(LM)的前景。它在許多應用場景中都取得了很好的效果,也可以簡單圖解一下。接下來我們就介紹幾個應用場景來結束我們這篇文章。
3.1 機器翻譯 machine translation 翻譯任務不需要編碼器,只用解碼器就可以進行翻譯了。
3.2 摘要 Summarization 這是只有編碼器的transformer訓練的第一個任務,訓練它閲讀維基百科的文章(不包括目錄前邊的開頭部分),前邊的開頭部分作為訓練數據的標籤。
GPT-2就是使用wikipedia的文章進行訓練的,因此訓練好的模型可以直接拿來做摘要。
3.3 遷移學習 Transfer Learning 在《Sample Efficient Text Summarization Using a Single Pre-Trained Transformer》,只有解碼器的transformer結構首先在語言模型上進行預訓練,然後微調做摘要任務,結果證明,在有限的數據設置中,它比預先訓練的編碼器-解碼器變壓器取得更好的結果。
GPT-2的論文原文也展示了在語言建模上對模型進行預訓練後做摘要任務的結果。
3.4 音樂生成 Music Generation 音樂Transformer使用的是只有解碼器的Transformer結構來生成具有表現力的音樂。“音樂建模”就像語言建模一樣,讓模型以一種無監督的方式學習音樂,然後讓它對輸出進行採樣(我們之前稱之為“rambling”)。
你可能會好奇音樂是如何表示的。語言建模可以通過字(characters)、詞(words)或token作為某個單詞(word)的表示,並將其轉化為向量表示。在音樂演奏中(比如鋼琴),我們除了要表示音符,還要表示速度——衡量鋼琴鍵按得有多用力。
一個表演只是一組one-hot向量而已。一個mini檔案可以轉化為下圖的格式。
論文中輸入序列的示例如下圖:
這個輸入序列的 one-hot 向量表示如下: 我很喜歡這篇論文中的音樂transformer的自注意力圖象。在這裡我添加了一些註釋:
這個音樂中有明顯的三角形循環。query在最後一個三角形的峰值上,它會注意到之前所有的三角形的高音峰值(包括樂曲最開始的峰值)。圖中的綫表示query都關注到了哪些位置,螢光綠色的條條代表的是attention分數,綠條條越長代表在這個位置投入的注意力越多。
如果你不懂圖中黑色條條塊塊的音符表示方法可以看一下這個視頻:d小調托卡塔與賦格
4 總結 GPT-2到這裡就介紹完了。本文對GPT-2以及它的父模型(只有解碼器的Transformer結構)的探索。我希望你在讀完這篇文章後,對自關注力機制有了更深入的理解,並且對Transformer的呢哦不工作機制有了更多的瞭解。