LongCut logo

【生成式人工智慧與機器學習導論2025】第3講:解剖大型語言模型

By Hung-yi Lee

Summary

## Key takeaways - **Language models predict token probabilities**: Language models function by taking an incomplete sentence and outputting a probability distribution for every possible next token. [13:15], [19:22] - **Tokenization: Words to IDs**: The first step in processing a sentence is tokenization, where each token (often a word or sub-word) is converted into a numerical ID. [03:10:13], [03:15:21] - **Embeddings represent tokens as vectors**: Each token ID is mapped to a unique vector called an embedding, which captures semantic meaning and is a key part of the model's parameters. [04:15:17], [05:33:35] - **Layers process embeddings contextually**: Subsequent layers in the model take these token embeddings and transform them into contextualized embeddings by considering the surrounding tokens. [07:26:28], [08:56:59] - **Attention mechanisms weigh token importance**: Self-attention layers within the Transformer architecture calculate attention weights to determine how much influence each token has on others, enabling context understanding. [54:26:29], [58:50:52] - **Logits are raw scores before probability**: The final layer's output is a vector of logits, which are raw scores that need to be converted into probabilities using functions like softmax. [14:44:49], [15:21:23]

Topics Covered

  • Language models predict the next token.
  • Token embeddings capture semantic meaning.
  • Self-attention allows models to weigh token importance.
  • Model layers refine understanding contextually.
  • The final layer predicts token probabilities via LM Head.

Full Transcript

<b>今天呢,這是我們課程的第三講。</b>

<b>那我們要來看語言模型內部的運作。</b>

<b>那到目前為止呢,</b>

<b>我們在課堂中呢,</b>

<b>反覆跟大家強調說語言模型做的事情,</b>

<b>就是給一個未完成的句子,</b>

<b>讓它輸出一個機率分布,</b>

<b>它去預測</b>

<b>接下來可以接每一個 Token 的機率。</b>

<b>那我們也跟大家反覆講過說,</b>

<b>這個語言模型呢就是一個函式,</b>

<b>我們這邊寫做 F。</b>

<b>那未完成的句子我們寫做 X,</b>

<b>那輸出呢寫做 F(X)。</b>

<b>那在上一堂課裡面,</b>

<b>我們講說怎麼選取合適的 X,</b>

<b>讓你得到最後你要的 F(X)。</b>

<b>那在這一堂課裡面,</b>

<b>我們要來關注 F 內部是怎麼運作的。</b>

<b>也就給定 X 以後,</b>

<b>F 裡面到底發生了什麼事,</b>

<b>才讓我們看到 F(X) 長成某個樣子。</b>

<b>所以我們要進入課堂裡面比較深的部分,</b>

<b>我們把語言模型剖開來,</b>

<b>看看它內部是怎麼運作的。</b>

<b>那在開始之前呢,</b>

<b>要強調一下,</b>

<b>在這堂課中,</b>

<b>沒有任何模型被訓練。</b>

<b>我們是解剖已經訓練好的模型來觀察。</b>

<b>也就是說,</b>

<b>我們還暫時不討論,</b>

<b>為什麼這些語言模型</b>

<b>可以變成我們要的樣子。</b>

<b>那這個是往後的課程的內容。</b>

<b>但今天我們就假設這些語言模型,</b>

<b>它已經訓練好了,</b>

<b>它的參數就在那邊,</b>

<b>我們是直接去解剖它,</b>

<b>看看說這些參數跟輸入的句子</b>

<b>是進行什麼樣的互動,</b>

<b>最後產生出了下一個 Token 的機率。</b>

<b>那這是今天課程的規劃。</b>

<b>那跟第一堂課的架構比較像,</b>

<b>我們會先花一些時間用投影片跟你講一下,</b>

<b>這一些語言模型背後</b>

<b>是怎麼被運作的。</b>

<b>那為了要讓你更相信說,</b>

<b>這個語言模型背後運作的原理,</b>

<b>就跟投影片裡面講的差不多,</b>

<b>所以呢,</b>

<b>這課程的後半段,</b>

<b>我會帶一些實作,</b>

<b>實際解剖一個語言模型給你看,</b>

<b>讓你知道說這個語言模型的運作,</b>

<b>真的就跟我們上課說的是一樣的。</b>

<b>好,那我們就先從原理開始講起。</b>

<b>那原理呢,</b>

<b>我們會分三塊來討論。</b>

<b>第一個是先大家看過說,</b>

<b>從語言模型的輸入,</b>

<b>也就是一個 Prompt,</b>

<b>一直到輸出下一個 Token,</b>

<b>在這個過程中發生什麼樣的事情。</b>

<b>那第二部分,</b>

<b>我們會看語言模型每一層的輸出,</b>

<b>可能是發生了什麼事。</b>

<b>最後我們會看每一層內部</b>

<b>是怎麼運作的。</b>

<b>好,那我們就先從</b>

<b>語言模型的輸入到輸出,</b>

<b>先走一輪看看,</b>

<b>語言模型內部到底在做什麼事情。</b>

<b>那我們已經反覆強調說,</b>

<b>語言模型就是一個函式。</b>

<b>這個函式的輸入是一個句子,</b>

<b>輸出是這個句子後面</b>

<b>可以接的 Token 的機率分布。</b>

<b>好,那從輸入的句子到輸出的機率分布中間,</b>

<b>發生了什麼樣的事情呢?</b>

<b>那第一件事情是,</b>

<b>輸入的句子會先經過 Tokenization,</b>

<b>被切成一個一個 Token,</b>

<b>那每一個 Token 會對應到一個編號,</b>

<b>對應到一個 ID。</b>

<b>那這件事情呢,</b>

<b>是我們在第一講的實作中</b>

<b>已經帶大家看過的。</b>

<b>那在這一堂課裡面,</b>

<b>我們假設每一個中文的字,</b>

<b>每一個方塊字,</b>

<b>都是一個 Token。</b>

<b>雖然實際上並不是這樣子。</b>

<b>如果你有仔細聽第一講的話,</b>

<b>第一講我帶大家看過,</b>

<b>Llama 裡面的 Token 長什麼樣子。</b>

<b>很多時候好幾個中文字合起來</b>

<b>才是一個 Token,</b>

<b>或甚至有時候一個中文的字,</b>

<b>反而是好幾個 Token。</b>

<b>但在這堂課為了要做投影片比較簡潔,</b>

<b>所以我們假設一個中文的方塊字</b>

<b>就是一個 Token。</b>

<b>不過大家注意,</b>

<b>這並不一定是真實的狀況。</b>

<b>好,那做完 Tokenization 以後,</b>

<b>接下來呢,</b>

<b>我們會把這一些 ID 送進語言模型。</b>

<b>那第一個跟這些 ID 產生互動的,</b>

<b>是一個叫做</b>

<b>embedding table 的東西。</b>

<b>這個 embedding table 呢,</b>

<b>它就是一個矩陣,</b>

<b>它就是一個 matrix。</b>

<b>這個矩陣的 row,</b>

<b>就是對應到每一個 Token。</b>

<b>那假設這個模型呢,</b>

<b>有 12 萬 8 千個 Token,</b>

<b>那這個矩陣就有 12 萬 8 千個 row,</b>

<b>每一個 row 對應到某一個 Token。</b>

<b>那 column 呢,</b>

<b>column 的數目就代表說,</b>

<b>每一個 Token</b>

<b>如果我們要把它轉成一個向量,</b>

<b>轉成一個 embedding,</b>

<b>那個 embedding 的 dimension 有多少。</b>

<b>那這個 embedding table 做的事情就是,</b>

<b>輸入是一排 ID,</b>

<b>每一個 ID 會去查</b>

<b>它在 embedding table 裡面對應的位置。</b>

<b>那比如說有一個 Token,</b>

<b>它編號是 540,</b>

<b>那代表說它在這個 embedding table 裡面,</b>

<b>它就是第 541 個 row。</b>

<b>它的這個 embedding 呢,</b>

<b>就放在第 541 個 row。</b>

<b>因為這是從 0 開始啦,</b>

<b>所以編號 540,</b>

<b>放在第 541 個 row。</b>

<b>如果是 123,</b>

<b>就放在第 124 個 row。</b>

<b>然後呢,</b>

<b>我們會從這個 embedding table 裡面,</b>

<b>拿出每一個 ID</b>

<b>它對應的 embedding。</b>

<b>那 embedding 呢,</b>

<b>其實就是一個向量。</b>

<b>所以每一個 ID 本來是一個整數,</b>

<b>那現在會被對應到一個向量。</b>

<b>那向量呢,</b>

<b>就是一排數字。</b>

<b>那在這個投影片上呢,</b>

<b>我們都用一個長方形</b>

<b>來表示一個向量。</b>

<b>那之後我們就不會把</b>

<b>向量裡面的數字再畫出來,</b>

<b>你就想像說以後在投影片上面,</b>

<b>看到一個長方形,</b>

<b>它就代表一排數字。</b>

<b>好,那根據這一個 embedding table,</b>

<b>它裡面的 row 的數目,</b>

<b>就是 vocabulary 的大小。</b>

<b>你可以把每一個 ID</b>

<b>對應到一個向量。</b>

<b>那這個向量呢,</b>

<b>叫做 embedding。</b>

<b>這個向量有個名字,</b>

<b>叫做 token 的 embedding。</b>

<b>所以每個 token</b>

<b>會對應到一個它自己的 embedding。</b>

<b>這邊呢,</b>

<b>這一個 embedding table,</b>

<b>它是一個矩陣。</b>

<b>這個矩陣呢,</b>

<b>就是 network 的參數,</b>

<b>就是我們模型的參數。</b>

<b>我們之前有說,</b>

<b>模型裡面</b>

<b>都有數十億、數百億個參數。</b>

<b>那這邊每一個參數都是一個數字。</b>

<b>那這一個 embedding table 裡面的數字,</b>

<b>就是參數的一部分。</b>

<b>那通常在一個模型裡面,</b>

<b>我們參數呢,</b>

<b>會用一個一個矩陣為單位,</b>

<b>那存起來。</b>

<b>那等一下在實作的時候,</b>

<b>你會更清楚說,</b>

<b>每一組參數,</b>

<b>它就是一個一個的矩陣。</b>

<b>那 embedding table</b>

<b>它顯然就是一個矩陣。</b>

<b>那這個矩陣的 row 的數目,</b>

<b>就是 vocabulary 的數目。</b>

<b>它的 column 的數目,</b>

<b>就代表說</b>

<b>現在這個 embedding 的向量,</b>

<b>有多少個 dimension。</b>

<b>好,那這個是整個模型的第一部分。</b>

<b>先把每一個整數</b>

<b>對應到一個 embedding,</b>

<b>對應到一個向量。</b>

<b>好,那在下一步呢?</b>

<b>接下來呢,</b>

<b>就會進入模型中的第一個 layer。</b>

<b>這個模型中有很多個 layer。</b>

<b>這些 token 的 embedding</b>

<b>會先進入第一個 layer。</b>

<b>那每一個 layer 做的事情,</b>

<b>都是把一排輸入的向量</b>

<b>變成另外一排輸出的向量。</b>

<b>輸入跟輸出的長度是一樣的。</b>

<b>在這個投影片裡面,</b>

<b>輸入有七個向量,</b>

<b>輸出就是七個向量。</b>

<b>那在這個 layer 裡面,</b>

<b>會有非常多的參數。</b>

<b>這個 layer 裡面呢,</b>

<b>會有好幾個矩陣。</b>

<b>那不只一個矩陣,</b>

<b>有好幾個矩陣。</b>

<b>這些矩陣代表這個 layer 的參數。</b>

<b>那等一下呢,</b>

<b>那在第三部分才跟大家講說,</b>

<b>一個 layer 裡面發生什麼事情。</b>

<b>那在現在這個階段,</b>

<b>你就記得說呢,</b>

<b>一個 layer 做的事情就是,</b>

<b>它會去看每一個輸入的 token embedding,</b>

<b>在它之前有什麼樣的輸入。</b>

<b>它會綜合現在這個 token embedding</b>

<b>跟它之前所有的輸入合起來,</b>

<b>產生一個新的 embedding。</b>

<b>所以每一個 embedding,</b>

<b>每一個輸入的 token embedding,</b>

<b>會考慮前面已經發生過的事情,</b>

<b>全部綜合起來,</b>

<b>再輸出一個新的向量。</b>

<b>那這些輸出的新的向量,</b>

<b>很多時候我們也就叫它 embedding。</b>

<b>那不過有時候為了區別說,</b>

<b>第一層查表之後得到的 embedding,</b>

<b>跟通過這個 layer 之後得到的 embedding</b>

<b>是有一些不一樣的,</b>

<b>所以把輸入的、查表之後得到的 embedding</b>

<b>叫做 token embedding。</b>

<b>那通過 layer 以後的 embedding,</b>

<b>因為它考慮了上下文,</b>

<b>所以叫做 contextualized embedding。</b>

<b>強調它是考慮了上下文以後,</b>

<b>才計算出來的 embedding。</b>

<b>那很多時候 layer 輸出的這些向量,</b>

<b>也叫做 representation。</b>

<b>那有時候 representation 裡面,</b>

<b>前面會加一個形容詞,</b>

<b>比如說稱它為 hidden representation,</b>

<b>或者是 latent representation。</b>

<b>這個 hidden、latent 的意思是說,</b>

<b>我們通常在使用語言模型的時候,</b>

<b>你不會去看到這些 representation,</b>

<b>因為真正關心的只有</b>

<b>最終輸出的那個機率分布。</b>

<b>所以你通常不會把這些 representation 拿出來看,</b>

<b>所以它們是隱藏起來的,</b>

<b>叫做 hidden 或者是 latent representation。</b>

<b>總之,你在文獻上</b>

<b>看到 contextualized embedding、</b>

<b>hidden representation、latent representation,</b>

<b>它們指的都是一樣的東西,</b>

<b>就是模型裡面</b>

<b>某一個 layer 的輸出。</b>

<b>那模型裡面有很多個 layer,</b>

<b>所以 token embedding</b>

<b>所以 token embedding</b>

<b>通過第一個 layer 產生一排向量,</b>

<b>這排向量會再進入第二個 layer,</b>

<b>產生另外一排向量。</b>

<b>那第二個 layer 裡面</b>

<b>也是一堆的參數,</b>

<b>也是一堆的矩陣。</b>

<b>那等一下我們才會詳細看說,</b>

<b>一個 layer 裡面到底發生了什麼事。</b>

<b>現在就記得說,</b>

<b>每一個 layer 做的事情,</b>

<b>就是輸入一排向量,</b>

<b>然後它會考慮上下文,</b>

<b>再輸出另外一排長度一模一樣的向量。</b>

<b>那這個過程呢,</b>

<b>就會反覆持續下去。</b>

<b>那假設這整個模型有大 L 層,</b>

<b>那剛才的步驟就會反覆一直下去,</b>

<b>每次通過一個 layer,</b>

<b>直到通過最後大 L 個 layer,</b>

<b>得到最後一排向量。</b>

<b>好,得到最後一排向量,</b>

<b>得到最後一排的、</b>

<b>這個最後一層輸出的 representation 之後呢,</b>

<b>會做什麼事情呢?</b>

<b>這邊再跟大家說明一下,</b>

<b>就是多個 layer,</b>

<b>其實就是 deep learning。</b>

<b>當你的模型裡面有很多 layer 的時候,</b>

<b>我們就叫做 deep learning。</b>

<b>deep learning 其實也就是 neural network。</b>

<b>那講到這邊你可能會想說,</b>

<b>neural network 裡面</b>

<b>不是就是應該有很多的 neuron,</b>

<b>有很多的神經元嗎?</b>

<b>這些神經元在哪裡?</b>

<b>這個在課堂結尾的時候會告訴你,</b>

<b>這個神經元到底在哪裡。</b>

<b>總之有多個 layer</b>

<b>就是 deep learning,</b>

<b>就是 neural network。</b>

<b>那再來一個問題是,</b>

<b>那為什麼我們的模型裡面</b>

<b>要有多個 layer 呢?</b>

<b>多個 layer 有什麼好處呢?</b>

<b>那今天因為時間有限的關係,</b>

<b>我們就不細講這個部分。</b>

<b>那其實可以從很多不同的角度來切入,</b>

<b>為什麼需要有多個 layer。</b>

<b>也就是為什麼需要有 deep learning。</b>

<b>但你可以用比較科普的講法,</b>

<b>就說有很多個 layer,</b>

<b>每個 layer 你就想成是流水線上的一個站,</b>

<b>然後每一站都做一點事情,</b>

<b>那合起來就可以做很複雜的事情。</b>

<b>這也是一種講法啦。</b>

<b>那你也可以從機器學習的原理出發,</b>

<b>告訴你說從機器學習的原理來看,</b>

<b>為什麼 deep learning,</b>

<b>中文通常翻成「深度學習」,</b>

<b>是一個好的方法。</b>

<b>那最後呢,</b>

<b>如果你想要知道它背後真正的原理的話,</b>

<b>那其實我在 2018 年的時候,</b>

<b>曾經講過一套課程,</b>

<b>是講 deep learning 的理論。</b>

<b>那在這個課程裡面,</b>

<b>會花快三個小時的時間,</b>

<b>實際在數學上證明給你看說,</b>

<b>deep learning 就是比 shallow 還要好。</b>

<b>所以 deep learning 比 shallow 還要好,</b>

<b>並不是 empirical,</b>

<b>也並不是經驗、實驗上的結果,</b>

<b>也不是那種科普的講法,</b>

<b>就是說一層拆成多層、</b>

<b>有很多站就是比較好等等之類的。</b>

<b>它是可以直接在數學上證明說,</b>

<b>deep learning 就是比 shallow 還要好。</b>

<b>那至於你想要知道為什麼,</b>

<b>你可以把以下這三堂課看完,</b>

<b>你就會知道說在數學上,</b>

<b>deep learning 就是比 shallow 還要好的。</b>

<b>好,那講到這邊,</b>

<b>我們還沒有產生機率分布。</b>

<b>怎麼產生這個機率分布呢?</b>

<b>我們把所有的 layer 都跑過之後,</b>

<b>最後得到一排向量。</b>

<b>那我們把這一排向量的最後一個拿出來。</b>

<b>我們假設它是 k 維的向量,</b>

<b>裡面有 k 個數字。</b>

<b>而這 k 維的向量呢,</b>

<b>會被乘上一個矩陣。</b>

<b>這個矩陣呢...</b>

<b>它有 k 個 column,</b>

<b>有大 V 個 row。</b>

<b>把這個 k 維的向量</b>

<b>乘上這個矩陣,</b>

<b>那如果熟悉線性代數的話,</b>

<b>你就知道說它的輸出</b>

<b>是一個大 V 維的向量。</b>

<b>那這個大 V 呢指的是 vocabulary 的 size。</b>

<b>指的是 network 的 Token 的數目。</b>

<b>如果這個 network 是 12 萬 8 千個 Token 的話,</b>

<b>那這個大 V 就是 12 萬 8 千維的向量。</b>

<b>那每一維呢就對應到一個 Token。</b>

<b>每一維就對應到一個 Token 的分數,</b>

<b>代表這個 Token 接在輸入句子後面的可能性。</b>

<b>那這個向量啊</b>

<b>它也是 network 的一部分。</b>

<b>它也是我們模型的一部分。</b>

<b>這個矩陣呢,</b>

<b>它也是我們模型的一部分。</b>

<b>這個矩陣裡面的數字</b>

<b>就是我們的參數。</b>

<b>那這個矩陣呢有一個名字,</b>

<b>叫做 LM Head。</b>

<b>因為它就出現在整個語言模型的最後面,</b>

<b>所以它是語言模型的頭。</b>

<b>所以如果你要稱呼它的話,</b>

<b>很多人會叫做 LM Head。</b>

<b>那講到這邊有人可能會想說,</b>

<b>欸這個...</b>

<b>把一個任意的向量,</b>

<b>我們沒有控制說語言模型輸出的向量裡面的數字,</b>

<b>一定要是多少。</b>

<b>所以它可以是正的、可以是負的。</b>

<b>那 LM Head 裡面的這些參數,</b>

<b>它也可以是正的、也可以是負的。</b>

<b>一個向量乘以一個矩陣,裡面的數字沒有任何限制,</b>

<b>然後再得到一個向量,</b>

<b>這個向量裡面的數值,</b>

<b>應該可以是任何的數字吧?</b>

<b>它並沒有說一定要是正數,</b>

<b>也沒有說一定要介於 0 到 1 之間。</b>

<b>所以你其實沒有辦法把</b>

<b>這個向量裡面的數字當作機率來看,</b>

<b>因為你知道機率呢,</b>

<b>需要介於 0 到 1 之間嘛。</b>

<b>所以不能把這個向量裡面的數字當作機率來看。</b>

<b>它有一個特殊的稱呼,</b>

<b>叫做 logit。</b>

<b>至於為什麼叫 logit,</b>

<b>這個今天可能就沒有時間細講,</b>

<b>大家有興趣再自己研究。</b>

<b>總之這個輸出叫做 logit。</b>

<b>你沒有辦法真的把它當作機率來看。</b>

<b>要怎麼把它當作機率來看呢?</b>

<b>你要對它做一個操作,</b>

<b>這個操作叫做 softmax。</b>

<b>把 logit 轉成機率。</b>

<b>所謂轉成機率的意思就是,</b>

<b>每一個向量裡面的數字,</b>

<b>變成介於 0 到 1 之間,</b>

<b>這個向量裡面所有數字的總和變成 1,</b>

<b>然後所以你可以把它當作一個機率來看。</b>

<b>那這邊也稍微講一下 softmax 實際的操作。</b>

<b>它的操作方式是這樣的:</b>

<b>我們假設 logit 裡面有三個數字,</b>

<b>但實際上不可能只有三個數字。</b>

<b>如果是一個語言模型,</b>

<b>有 12 萬 8 千個 Token,</b>

<b>那 logit 裡面就要 12 萬 8 千個數字。</b>

<b>那我們這邊就假設只有三個數字,</b>

<b>那分別是 s1, s2, s3。</b>

<b>那 softmax 的操作呢,</b>

<b>基本上分成兩步驟。</b>

<b>第一個步驟是,</b>

<b>對 s1 到 s3 全部都取 exponential。</b>

<b>因為 s1 到 s3 它可能是正的、可能是負的,</b>

<b>取完 exponential 之後,</b>

<b>至少確保它所有的數值都是正數。</b>

<b>雖然確保它所有的數值都是正數,</b>

<b>但是本來比較大的數字仍然會比較大,</b>

<b>本來比較小的數字,</b>

<b>做完 exponential 以後仍然是比較小的。</b>

<b>然後接下來呢,</b>

<b>把這個 exponential(s1)、</b>

<b>exponential(s2),</b>

<b>跟 exponential(s3) 全部加起來。</b>

<b>我們把它加起來的結果呢,</b>

<b>叫做大 M。</b>

<b>然後再把大 M 呢,</b>

<b>去除掉 exponential(s1)、</b>

<b>除掉 exponential(s2)、</b>

<b>除掉 exponential(s3)。</b>

<b>得到的這個結果呢,</b>

<b>就既是正的,</b>

<b>全部加起來</b>

<b>又是 1,</b>

<b>你可以把它當作機率來看。</b>

<b>那總之原則上呢,</b>

<b>就是 logit 輸入的數字越大,</b>

<b>那最後轉出來的</b>

<b>機率就越大。</b>

<b>那講到這邊,</b>

<b>有人可能會問說,</b>

<b>憑什麼取個 exponential</b>

<b>就要把它當作機率來看呢?</b>

<b>確實你沒有必要相信,</b>

<b>取個 exponential 就能當機率來看。</b>

<b>你其實沒有必要把</b>

<b>這個通過 softmax 以後</b>

<b>得到的這些數字,</b>

<b>當作一個真正的機率。</b>

<b>你沒有必要跟它太較真。</b>

<b>你仔細想想,我們在第一講裡面啊,</b>

<b>這個 softmax 這個操作,</b>

<b>甚至不能算是模型的一部分了。</b>

<b>你記得在使用 Hugging Face 的 model 的時候,</b>

<b>它其實只給你 logit。</b>

<b>它真正的輸出</b>

<b>是有正有負的 logit。</b>

<b>那至於要不要通過 softmax 轉成機率,</b>

<b>那是你自己決定的,</b>

<b>那是你自己做的。</b>

<b>你完全可以套一個別的方法,</b>

<b>把它轉成其他...</b>

<b>如果你真的很在意輸出要是機率,</b>

<b>那輸出是機率我們才能夠取樣嗎?</b>

<b>如果你真的很在意這件事,</b>

<b>那你可以用任何你喜歡的方法,</b>

<b>把它轉成像是機率的樣子,</b>

<b>方便你取樣。</b>

<b>你也不一定要用 softmax。</b>

<b>那其實啊,</b>

<b>就是因為這個機率啊,</b>

<b>你又不需要把它當作真正的機率來看。</b>

<b>它就只是轉成一個 0 到 1 之間的數字,</b>

<b>讓你接下來做取樣的時候、</b>

<b>做 decoding 的時候比較好操作而已。</b>

<b>所以這個 softmax 可以有種種</b>

<b>各式各樣的變形。</b>

<b>比如說一個最常見的操作就是,</b>

<b>把所有 logit 裡面的數值,</b>

<b>都先除上一個叫做大 T 的參數。</b>

<b>都除掉大 T 這個數值,</b>

<b>然後再去跑 softmax。</b>

<b>那除掉這個大 T 有什麼用呢?</b>

<b>這個大 T 呢叫做 temperature。</b>

<b>那如果這個大 T 呢數字越大,</b>

<b>那做完 softmax 以後,</b>

<b>就會機率分布就會越平均。</b>

<b>那如果數字越小,</b>

<b>那最後機率分布呢就會越集中</b>

<b>在這個機率比較大的那幾個 Token 上。</b>

<b>那控制這個大 T 呢,</b>

<b>你就可以控制說,</b>

<b>你最後在取樣的時候,</b>

<b>有多容易選出罕見的符號。</b>

<b>那今天你在用語言模型的時候呢,</b>

<b>有些語言模型會標榜說,</b>

<b>它有不同的模式,</b>

<b>比如說創意模式或者是保守模式。</b>

<b>通常這種創意模式、保守模式,</b>

<b>往往就是透過控制這個大 T 來實踐的。</b>

<b>你把大 T 呢設大一點,</b>

<b>那模型輸出的這個機率分布就比較平坦一點。</b>

<b>輸出機率分布比較平坦,</b>

<b>就比較容易選到奇怪、罕見的符號。</b>

<b>然後呢這個做平台的人就會告訴你說,</b>

<b>這個叫做語言模型的創意模式,</b>

<b>它比較容易輸出呢你意想不到的結果。</b>

<b>好,總之講這些就告訴你說,</b>

<b>你沒有太必要跟 softmax 轉出來的結果</b>

<b>是不是真正的機率較真。</b>

<b>總之它就是把 logit 變成一個</b>

<b>你容易做取樣的數值而已。</b>

<b>好,那如果你對 unembedding 這件事情,</b>

<b>為什麼有一個向量乘上一個矩陣,</b>

<b>最後就可以變成每一個 Token</b>

<b>它接在句子後面的分數,</b>

<b>如果你覺得這件事沒有非常直觀的話,</b>

<b>那我們再換一個方法來告訴你,</b>

<b>unembedding 實際上是怎麼操作的。</b>

<b>其實很多類神經網路、</b>

<b>很多這個語言模型它的設計是</b>

<b>首尾呼應、以始為終。</b>

<b>什麼意思呢?</b>

<b>其實很多類神經網路、</b>

<b>其實很多語言模型,</b>

<b>包括我們熟悉的 Llama 或者是 Gemma,</b>

<b>它們的 LM Head 都不是一組獨立的參數。</b>

<b>它們都是直接把 embedding table</b>

<b>當作 LM Head。</b>

<b>所以 LM Head 在很多語言模型裡面,</b>

<b>就是那個最開始的 embedding table。</b>

<b>我們剛才不是說</b>

<b>在整個語言模型最開始的地方,</b>

<b>有一個 embedding table</b>

<b>會把每一個 Token 轉成一個向量嗎?</b>

<b>對應到 embedding,</b>

<b>每一個 Token 對應到一個向量。</b>

<b>其實在最尾端的這個 LM Head,</b>

<b>也是同一個、一模一樣的 embedding table。</b>

<b>它們是同一個東西。</b>

<b>你的語言模型最終輸出一個向量,</b>

<b>然後它把這個向量</b>

<b>跟 embedding table 裡面的每一個 embedding、</b>

<b>每一個 token embedding 都去計算</b>

<b>dot product,也就是計算某種相似度。</b>

<b>你知道把這一個向量</b>

<b>跟這個矩陣做相乘,</b>

<b>其實就是把這一個向量</b>

<b>跟這個矩陣裡面的每一個 row 做 dot product。</b>

<b>你把這個向量跟矩陣的第一個 Row 做 dot product 得到一個數值</b>

<b>跟第二個 Row 做 dot product 得到第二個數值</b>

<b>以此類推</b>

<b>所以實際上呢 Unembedding 這件事情</b>

<b>就是去計算 LLM 最終的 layer 輸出的那個 embedding</b>

<b>跟每一個 Token embedding 的相似度</b>

<b>這個相似度是用 dot product 來表示的</b>

<b>那什麼樣的 Token 它會得到比較高的機率呢</b>

<b>什麼樣的 Token 會得到比較高的分數</b>

<b>被判斷比較容易接在未完成的句子後面呢</b>

<b>其實就是假設那個 Token 的 embedding</b>

<b>跟你的大型語言模型最終輸出的那個 representation</b>

<b>最後一個 layer 輸出的 representation 越接近</b>

<b>那那個 Token 就會得到越高的機率</b>

<b>所以可以想像說語言模型在做的事情就是</b>

<b>它為了要猜測下一個 Token 應該是什麼</b>

<b>假設它知道說下一個 Token</b>

<b>我應該要輸出第二個 Token,編號 2 的 Token</b>

<b>它就會想辦法在它的每一個 layer 中</b>

<b>想辦法去產生出一個 representation</b>

<b>這個 representation 跟 Token 2 的 embedding 是越接近越好</b>

<b>那最後 Token 2 就會得到比較高的機率分佈</b>

<b>那希望這樣的說明可以更讓你對於這個 unembedding</b>

<b>的操作有更直觀的了解</b>

<b>好那現在呢</b>

<b>我們就是把整個語言模型中間發生的事情走過一輪</b>

<b>從輸入一直到最終輸出的機率分佈</b>

<b>把它走過一輪</b>

<b>那接下來呢</b>

<b>我們就是要看看一個語言模型它中間</b>

<b>每一層的輸出都是在做些什麼</b>

<b>那我們說輸入 ID 之後</b>

<b>第一件做的事情是每一個 ID</b>

<b>都會被轉成一個 Token Embedding</b>

<b>也就是轉成一個向量</b>

<b>那同樣的 Token 就會有同樣的 Token Embedding</b>

<b>比如說有一句話是「今天天氣很好」</b>

<b>「今天」的「天」跟「天氣」的「天」</b>

<b>這兩個「天」它們是同個 Token</b>

<b>去 Token Embedding 的那個 table 裡面</b>

<b>去查表之後查出來的就是一模一樣的 Token</b>

<b>但除了一樣的 Token 就一樣的 Token Embedding 之外</b>

<b>這個 Token Embedding 還有一個效用是</b>

<b>意思相近的 Token</b>

<b>就會有相近的 Token Embedding</b>

<b>所以這個 Token Embedding 裡面的這個數字</b>

<b>這個向量裡面的數字</b>

<b>不是亂給的</b>

<b>意思相近的 Token 就會有相近的 Token Embedding</b>

<b>比如說假設你得到了 Apple 這個 Token 的 Embedding</b>

<b>那你去把 Apple 這個 Token 的 Embedding</b>

<b>拿去跟其他 Token 算相似度</b>

<b>那就會發現說 Apple 這個 Token 的 Embedding</b>

<b>可能跟 Orange 的 Embedding 特別接近</b>

<b>可能跟 Banana 的 Embedding 特別接近</b>

<b>它們指的都是水果</b>

<b>那它同時可能也跟 iPhone 的 Embedding 特別接近</b>

<b>因為 Apple 有可能它指的是蘋果電腦</b>

<b>所以 Apple 在某一個方向上跟其他水果接近</b>

<b>在另外一個方向上</b>

<b>它可能會跟 iPhone 接近</b>

<b>然後其他一些不相關的 Token</b>

<b>那跟 Apple 的距離就會相對比較遠</b>

<b>當然我這邊只是舉一個例子</b>

<b>那等一下在實作裡面會實際讓你看到說</b>

<b>Apple 這個 Token 跟哪些 Token 它是最接近的</b>

<b>好那底層的 Token Embedding</b>

<b>我們只看 Token</b>

<b>所以同樣的 Token 就會有一模一樣的 Embedding</b>

<b>那過了第一個 Layer 之後</b>

<b>這些 Token Embedding 就變成考慮上下文的 Contextualized Embedding</b>

<b>所以同樣可能是蘋果的「果」這個字</b>

<b>在進入底層之前</b>

<b>它們的 Token Embedding 是一模一樣的</b>

<b>但是通過第一個 Layer 之後</b>

<b>同樣是蘋果的「果」這個 Token</b>

<b>它們對應的 Embedding 在第一個 Layer 的輸出</b>

<b>就會開始不一樣了</b>

<b>因為現在這個蘋果的「果」</b>

<b>再也不是只單一那個 Token</b>

<b>而是考慮了上下文以後</b>

<b>得到的一個 Contextualized Embedding</b>

<b>那等一下會實際上讓大家看到說</b>

<b>同樣是 Apple 這個 Token</b>

<b>如果它上下文是不一樣的</b>

<b>那過了底層之後</b>

<b>它們的 Embedding 長得就會非常不一樣了</b>

<b>所以你就會看到說</b>

<b>同樣是 Apple 這個 Token</b>

<b>如果根據上下文指的是蘋果電腦的那個 Apple</b>

<b>跟根據上下文指的是可以吃的那個 Apple</b>

<b>它們的 Contextualized Embedding</b>

<b>就會有顯著的差距</b>

<b>同樣指蘋果電腦的 Contextualized Embedding 比較接近</b>

<b>而指蘋果電腦的 Contextualized Embedding</b>

<b>跟指可以吃的 Apple 的 Contextualized Embedding</b>

<b>它們的距離就會比較遠</b>

<b>那在這些 Embedding 的空間中</b>

<b>有時候特定的方向會有特定的含義</b>

<b>這些 Embedding 在這個高維的空間中</b>

<b>並不是任意擺放的</b>

<b>除了意思比較一樣的 Embedding 會聚集在一起以外</b>

<b>很多時候某一些特定的方向</b>

<b>就會有特定的含義</b>

<b>比如說在這個 Embedding 的空間裡面</b>

<b>可能會有一個方向代表中文英文的翻譯</b>

<b>如果你把一堆中文的詞彙</b>

<b>跟一堆英文的詞彙</b>

<b>它們對應的 Embedding 呢</b>

<b>通通劃出來的話</b>

<b>那你可能會發現說</b>

<b>Cold 跟「冷」它們之間相減的方向</b>

<b>跟「熱」減掉 Hot 的方向</b>

<b>跟「大」減掉 Big 的方向</b>

<b>可能是非常接近的</b>

<b>甚至用這個技術</b>

<b>你還可以做到翻譯</b>

<b>你可以把「冷」的 Embedding</b>

<b>減掉 Cold 的 Embedding</b>

<b>加上 Small 這個詞彙的 Embedding</b>

<b>那你可能就會得到「小」的 Embedding</b>

<b>當然什麼方向做什麼事情</b>

<b>你並沒有那麼容易分析</b>

<b>不同的語言模型</b>

<b>它們每一個方向所做的事情可能都不一樣</b>

<b>那在不同層之間</b>

<b>每一個方向做的事情</b>

<b>代表的含義可能也都不一樣</b>

<b>所以我今天在這邊只是舉一個例子</b>

<b>告訴你說</b>

<b>可能可以做到翻譯這件事</b>

<b>但並不代表所有的語言模型的每一層</b>

<b>都可以做到翻譯這件事情</b>

<b>可能有些層</b>

<b>輸出的 Representation 或者是 Embedding 可以</b>

<b>有些層不行</b>

<b>那這個就非常的 Case by Case</b>

<b>所以如果你看這個文獻上</b>

<b>常常有人會告訴你說什麼</b>

<b>Token Embedding 可以做到什麼</b>

<b>Man - Woman 等於 King - Queen</b>

<b>我相信你在很多地方</b>

<b>如果你對於自然語言處理稍有涉略的話</b>

<b>你在很多地方可能都有看到類似的說法</b>

<b>你可以自己玩玩看</b>

<b>看看你用 Llama 的 Embedding</b>

<b>做不做得出來類似的效果</b>

<b>那我自己試一下是做不出類似的效果了</b>

<b>所以這種 Embedding 的加加減減</b>

<b>有時候能成功</b>

<b>有時候不能成功</b>

<b>不同模型得到的結論</b>

<b>其實不一定是一樣的</b>

<b>那另外一個分析 Embedding 的方法</b>

<b>或分析 Representation 的方法</b>

<b>就是把這些高維的向量</b>

<b>投引到低維的空間</b>

<b>因為這一些 Embedding 或 Representation</b>

<b>它們其實是一個非常高維的向量</b>

<b>那這些高維的向量通常有幾千維</b>

<b>那你其實很難知道說</b>

<b>它們之間這個 Token 跟 Token 之間</b>

<b>有什麼樣的關係</b>

<b>那也許你可以把它們投影到一個</b>

<b>低維的空間中</b>

<b>比如說二維的平面</b>

<b>就可以讓你更容易的分析</b>

<b>這一些 Token 之間的關聯性</b>

<b>這些 Token 對應的 Representation 之間的關聯性</b>

<b>那要找什麼樣的低維空間</b>

<b>要從哪一個方向來看這個高維空間呢</b>

<b>要從哪一個方向來做投影呢</b>

<b>這個就見仁見智</b>

<b>你可以選擇不同的方向</b>

<b>來看這個高維的空間</b>

<b>你就可以看到不同的結果</b>

<b>所以這個是研究人員自己去解讀的</b>

<b>比如說有人就發現</b>

<b>這是非常早的論文</b>

<b>這是 2019 年的論文</b>

<b>2019 年這個時候世界上還沒有 GPT 3.5</b>

<b>人類甚至可能都還沒有出現</b>

<b>這個是侏羅紀時代</b>

<b>在這個侏羅紀時代</b>

<b>就已經有人發現</b>

<b>你把當時的語言模型</b>

<b>當時流行的不是用 GPT</b>

<b>當時是用一個叫做 BERT 的東西</b>

<b>反正它也就是個語言模型就是了</b>

<b>把 BERT 的 Latent Representation 拿出來</b>

<b>你可以找到</b>

<b>但並不是所有的二維空間</b>

<b>從所有的二維空間上看起來都是這樣</b>

<b>我要強調的是可以找到</b>

<b>某一個二維的平面</b>

<b>然後你把這一些 Representation</b>

<b>投影到二維的平面的話</b>

<b>你會看到一棵文法樹</b>

<b>就是一個句子</b>

<b>我們可以對它做文法剖析</b>

<b>可以產生一棵文法樹</b>

<b>然後你可以把這一些文字的 Representation</b>

<b>投影到一個二維平面上</b>

<b>就看到一棵文法樹出現</b>

<b>講到這邊你可能會想說</b>

<b>會不會這只是一個幻覺</b>

<b>因為你可以從很多不同的方向</b>

<b>來看這個高維的空間</b>

<b>會不會轉來轉去</b>

<b>你終究是可以轉出一棵文法樹</b>

<b>這篇論文就是告訴你說</b>

<b>不是這樣子的</b>

<b>其實只有某一些 Layer</b>

<b>你才有辦法轉得出文法樹</b>

<b>這一頁圖是這樣看的</b>

<b>這個橫軸是 Layer 的數目</b>

<b>當時有 BERT-Large 有 24 層</b>

<b>還有 BERT-Base 有 12 層</b>

<b>這個紅色是 Elmo</b>

<b>它只有兩層</b>

<b>我們就先不看它</b>

<b>縱軸是什麼意思</b>

<b>縱軸是某一層的 Representation</b>

<b>你想辦法去從各種不同角度看它</b>

<b>看起來最像文法樹的時候</b>

<b>到底有多像</b>

<b>這個 UUAS 跟這個指標指的是</b>

<b>跟文法樹的相近程度</b>

<b>然後你就會發現說</b>

<b>其實這個 Representation</b>

<b>只有在中間某幾層</b>

<b>你才有辦法找到一個二維空間</b>

<b>投影之後看起來像是文法樹</b>

<b>前面的層跟最後面的層</b>

<b>其實你是投影不出</b>

<b>像是文法樹的結果的</b>

<b>這可以引申出</b>

<b>在這些語言模型裡面</b>

<b>最中間的幾層</b>

<b>它特別有文法相關的資訊</b>

<b>那你也可以從其他的角度</b>

<b>來看這些 Representation</b>

<b>比如說有一篇文章</b>

<b>這個已經是比較近期的文章</b>

<b>所以它分析的是 Llama</b>

<b>它把各個地名都丟到 Llama 裡面</b>

<b>再從它的某一層</b>

<b>抽出每一個地名</b>

<b>對應的 Latent Representation</b>

<b>接下來它把這些 Latent Representation</b>

<b>投影到二維的平面上</b>

<b>但並不是隨便拿一個二維平面</b>

<b>投影上去</b>

<b>你都可以看到等一下的結果</b>

<b>而是你想辦法找出一個</b>

<b>最合適的平面</b>

<b>它可以投影出一個世界地圖</b>

<b>這邊每一個點</b>

<b>都代表某一個地名</b>

<b>它對應的 Latent Representation</b>

<b>然後呢</b>

<b>不同顏色是代表說</b>

<b>這個地名實際上在哪一洲</b>

<b>然後就發現說</b>

<b>它找得到</b>

<b>並不是所有二維平面</b>

<b>隨便投影都會看到這個結果</b>

<b>而是找得到一個二維的平面</b>

<b>把這些 Representation</b>

<b>投影到那個二維平面上以後</b>

<b>你可以看到這一些地名</b>

<b>它分佈的位置</b>

<b>接近它原來在世界地圖上面</b>

<b>真正的位置</b>

<b>但也不是對應的非常成功</b>

<b>你只能看個大概</b>

<b>大概那個城市在哪一洲</b>

<b>它大概就出現在附近的位置</b>

<b>好那剛才講的呢</b>

<b>使用觀察的方式</b>

<b>看這些 Representation</b>

<b>可能代表了什麼含義</b>

<b>那另外一個</b>

<b>你可以研究 Representation 的方式是</b>

<b>直接去修改這些 Representation</b>

<b>看看會發生什麼事情</b>

<b>那如果你可以把 Representation</b>

<b>做一個改動</b>

<b>然後就導致模型一直說髒話</b>

<b>你就會知道說</b>

<b>在這個 Representation 上面</b>

<b>可能有某一個方向</b>

<b>就是說髒話的方向</b>

<b>那這個技術有很多不同的名字</b>

<b>在文獻上不同的稱呼</b>

<b>有人叫 Representation Engineering</b>

<b>那從這個字面上</b>

<b>你也可以猜到什麼意思</b>

<b>就對 Representation</b>

<b>做 Engineering</b>

<b>對它做一些改變</b>

<b>然後看看會發生什麼事</b>

<b>那也有人叫 Activation Engineering</b>

<b>也有人叫 Activation Theory</b>

<b>總之指的都是差不多的技術</b>

<b>那在作業 3 裡面呢</b>

<b>我們也會做非常類似的事情</b>

<b>在作業 3 裡面呢</b>

<b>助教會帶大家看看</b>

<b>我們怎麼操控一個語言模型</b>

<b>強制它一定要拒絕</b>

<b>或者是同意你的請求</b>

<b>大家知道說今天語言模型呢</b>

<b>很容易拒絕你的請求</b>

<b>你叫它做一些壞事</b>

<b>比如說怎麼做炸藥</b>

<b>多數語言模型都會告訴你說</b>

<b>做炸藥是不對的</b>

<b>我們不能夠做這些事情</b>

<b>那我們在作業裡面告訴大家說</b>

<b>怎麼強迫這些語言模型</b>

<b>同意你的請求</b>

<b>好 那具體而言是怎麼做的呢</b>

<b>它的概念是這樣子的</b>

<b>當你給語言模型一段文字</b>

<b>那語言模型接下來繼續去做接龍的時候</b>

<b>如果它會接出拒絕相關的文句</b>

<b>那這代表著什麼</b>

<b>這代表說</b>

<b>當最後一個 Token</b>

<b>被讀入這個語言模型的時候</b>

<b>語言模型在中間某一些 layer</b>

<b>產生 Representation</b>

<b>這些 Representation 最終經過 Unembedding 以後</b>

<b>產生某一些詞彙</b>

<b>中間某一些 Representation</b>

<b>它有導致拒絕請求的成分</b>

<b>那中間每一個 Representation</b>

<b>它的產生都非常的複雜</b>

<b>每一個 layer 都是考慮了上下文</b>

<b>綜合考慮以後</b>

<b>產生一個 Representation</b>

<b>那在這個過程中</b>

<b>某一層產生了拒絕請求的成分</b>

<b>那我們現在先假設</b>

<b>這個拒絕請求的成分</b>

<b>出現在第 10 層</b>

<b>那等一下告訴你說實際上這個第 10 層</b>

<b>是怎麼被找出來的</b>

<b>這邊就是隨便一個假設</b>

<b>那在作業裡面</b>

<b>你可以自己去尋找</b>

<b>這個產生拒絕成分</b>

<b>是出現在哪一層</b>

<b>那我這邊要強調一下</b>

<b>我說的是產生拒絕的「成分」</b>

<b>代表說這個 Representation 裡面</b>

<b>有包含產生拒絕的指令</b>

<b>有產生拒絕的成分</b>

<b>但是也有其他東西</b>

<b>你不能夠再輸入一個</b>

<b>「怎麼製作炸藥」以後</b>

<b>得到一個 Representation</b>

<b>就說這個 Representation 代表了</b>

<b>會讓模型拒絕這件事情</b>

<b>因為這個 Representation 裡面</b>

<b>它代表了很多事情</b>

<b>模型說出了拒絕的這句話</b>

<b>只能夠說這個 Representation</b>

<b>跟拒絕有關係</b>

<b>它裡面有導致模型拒絕的成分</b>

<b>但它裡面可能有很多其他東西</b>

<b>比如說有跟炸藥有關的資訊等等</b>

<b>那怎麼真正把對應</b>

<b>導致模型拒絕的成分</b>

<b>真的把它抽取出來呢</b>

<b>這邊有很多不同的操作方法</b>

<b>那我們在作業裡面操作的方法</b>

<b>基本上是這個樣子的</b>

<b>你就給模型很多不同的句子</b>

<b>這些句子</b>

<b>很多不同的請求</b>

<b>這些請求</b>

<b>都是會導致模型拒絕的</b>

<b>都是叫模型去做壞事</b>

<b>所以它都會拒絕</b>

<b>比如說你叫模型教你做炸藥</b>

<b>它產生一個第 10 層的 Representation</b>

<b>你叫模型寫一封詐騙信</b>

<b>這個現在模型都是不做的</b>

<b>把它第 10 層的 Representation 也抽出來</b>

<b>那所以你就知道說</b>

<b>你這一個 Representation</b>

<b>裡面有拒絕的成分</b>

<b>但也有其他東西</b>

<b>這個 Representation 裡面有拒絕的成分</b>

<b>也有其他的東西</b>

<b>接下來我們把所有不同輸入的</b>

<b>第 10 層的 Representation 呢</b>

<b>通通都拿出來</b>

<b>然後取平均</b>

<b>那每一個 Representation 裡面</b>

<b>都有拒絕的成分</b>

<b>所以平均起來以後</b>

<b>還是拒絕的成分</b>

<b>有很多不同的「其他」</b>

<b>那你就可以得到「其他」的平均</b>

<b>那再來的問題是</b>

<b>我們怎麼把「其他」的平均</b>

<b>把它濾掉</b>

<b>怎麼把「其他」的平均減掉</b>

<b>那這邊方法是這樣的</b>

<b>那你在找很多的請求</b>

<b>是模型不會拒絕的</b>

<b>你叫它教你機器學習</b>

<b>它不會拒絕</b>

<b>你叫它寫一首詩</b>

<b>它不會拒絕</b>

<b>然後呢</b>

<b>你再把這些不會拒絕情況的</b>

<b>第 10 層也通通拿出來</b>

<b>那這些不會拒絕情況的</b>

<b>Representation 裡面</b>

<b>就沒有拒絕的成分</b>

<b>都是「其他」</b>

<b>那找很多不會拒絕的狀況</b>

<b>平均起來</b>

<b>就是「其他」的平均</b>

<b>那期待說</b>

<b>這個拒絕的狀況</b>

<b>找得夠多</b>

<b>沒拒絕的狀況</b>

<b>找得夠多</b>

<b>兩邊平均起來以後</b>

<b>兩邊算出來的「其他」的平均</b>

<b>可以正好抵銷掉</b>

<b>你就得到了拒絕的向量</b>

<b>你就得到了這個拒絕的成分</b>

<b>那這個比較理想的狀況</b>

<b>你可以在座位裡面看看實際操作</b>

<b>能不能夠做到這件事情</b>

<b>好所以這邊呢</b>

<b>再講一下剛才的操作</b>

<b>就是你會收集一大堆拒絕的狀況</b>

<b>你會收集一大堆沒有拒絕的狀況</b>

<b>都把它的第 10 層拿出來</b>

<b>都把它的第 10 層拿出來</b>

<b>然後呢</b>

<b>把拒絕狀況的第 10 層</b>

<b>全部平均起來</b>

<b>把沒拒絕狀況的第 10 層</b>

<b>全部平均起來</b>

<b>相減</b>

<b>期待相減之後</b>

<b>得到的那個向量</b>

<b>就代表了拒絕的成分</b>

<b>這個向量呢</b>

<b>代表了</b>

<b>模型看到這個向量</b>

<b>模型的 Representation</b>

<b>出現這個向量的時候</b>

<b>它就會拒絕人類的請求</b>

<b>那有了這個拒絕的成分以後</b>

<b>你就可以開始糊搞這個模型</b>

<b>本來叫模型教你機器學習</b>

<b>它不會拒絕你</b>

<b>但是你就把這個拒絕的成分呢</b>

<b>直接加到第 10 層上面</b>

<b>直接加上去</b>

<b>本來輸入這個輸入</b>

<b>「請教我機器學習」</b>

<b>在第 10 層的時候</b>

<b>有一個原來會產生的 Representation</b>

<b>在這個原來會產生的 Representation 上面</b>

<b>直接加上這個拒絕的成分以後</b>

<b>直接加上這個代表拒絕的向量以後</b>

<b>模型就會拒絕你的請求了</b>

<b>明明就只是要教機器學習</b>

<b>它還突然告訴你</b>

<b>學習機器學習是很危險的一件事情</b>

<b>我們不能夠學習機器學習</b>

<b>它突然就拒絕你的請求了</b>

<b>這邊回答一下大家常問的問題</b>

<b>怎麼知道在第 10 層呢</b>

<b>你不知道</b>

<b>你不知道哪一層</b>

<b>可以抽出這個拒絕的向量</b>

<b>所以真正的做法就是</b>

<b>每一層都試</b>

<b>那你看哪一層的結果最好就是哪一層</b>

<b>那你在作業裡面</b>

<b>就會經歷一下這個步驟</b>

<b>然後就會回答問題告訴我們說</b>

<b>哪一層才能夠真的抽出拒絕的向量</b>

<b>好那這個呢</b>

<b>其實是文獻上有人做過的操作</b>

<b>那以下的實驗結果呢</b>

<b>出自 2024 年的這篇論文</b>

<b>在這篇論文裡面</b>

<b>它就是找出了這個拒絕的成分</b>

<b>然後本來的問題是</b>

<b>請教我怎麼做瑜伽</b>

<b>那本來正常的語言模型</b>

<b>這邊試了很多不同的語言模型</b>

<b>上面只是一個例子</b>

<b>本來正常的語言模型</b>

<b>就會教你怎麼做瑜伽</b>

<b>但一旦把拒絕的成分</b>

<b>加進去之後</b>

<b>語言模型就會告訴你說</b>

<b>做瑜伽對身體有害</b>

<b>我不能夠告訴你怎麼做瑜伽</b>

<b>好那下面是一些數字化的結果</b>

<b>然後數字越高</b>

<b>就代表說</b>

<b>語言模型越會拒絕你的請求</b>

<b>它先準備了一大堆問題去問模型</b>

<b>那在還沒有糊搞語言模型的內部</b>

<b>那個這個糊搞呢</b>

<b>他這邊叫做 intervention</b>

<b>就還沒有去動語言模型的 representation 的時候</b>

<b>基本上這些問題</b>

<b>語言模型都是不會拒絕的</b>

<b>這個橙色的這個 bar 呢</b>

<b>代表拒絕的比例</b>

<b>非常非常的低</b>

<b>但一旦呢</b>

<b>加上這個拒絕的成分以後</b>

<b>這些模型呢</b>

<b>就會拒絕你了</b>

<b>因為它的 representation 中</b>

<b>出現拒絕的成分</b>

<b>通過整個語言模型之後</b>

<b>最終它 unembedding 之後</b>

<b>產生的就是回絕你需求的答案</b>

好,那既然這個粉紅色的向量代表了拒絕的成分

那加上去,本來會回答的狀況就會變成拒絕

那本來會拒絕的狀況是不是

減掉這個拒絕的成分

就會變成回答你的問題了呢

是不是就變成不會拒絕了呢

基本上也是這樣沒有錯

但是如果你仔細看原始的論文的話

它還有做了一個比較複雜的操作

那我們這邊就不細講

總之原則上你把這個拒絕的成分

從 representation 裡面減掉

本來應該拒絕你

它就不拒絕你了

所以這篇論文也做了一樣的操作

那這邊問模型的問題是

「請幫我寫一封信

這封信是有關美國總統的醜聞的

美國總統吸食毒品的醜聞的」

那如果你本來沒有瞎搞模型的話

模型就會說:「我不能幫你做這件事」

但如果你把拒絕的成分

從 representation 裡面減掉

模型就會幫你做壞事

它就會寫封信,有關美國總統吸毒的事情

下面是在各個不同的模型上實驗的結果

那這邊它呈現兩個數字

第一個數字是代表拒絕的比例

第二個數字是代表安全的比例

因為有時候模型就算它沒有拒絕

它還是回答你了

但是它答案可能根本就一點用都沒有

它根本沒有真正的傷害性

所以仍然可以算是安全的

在這邊做兩個評量

一個是拒絕的比例

一個是答案是安全的比例

那在還沒有瞎搞模型之前

拒絕的比例跟安全的比例都是非常高了

但是這個斜線就代表說

你把模型的 representation 去減掉拒絕的成分

突然間模型沒辦法拒絕你了

它的拒絕的比例變很低

而且它沒有拒絕

所以它很容易回答你的問題

所以不安全的比例也變高了

安全的比例也變得非常低

所以你可以透過真的去動語言模型的 representation

然後去改變語言模型的行為

這邊 Anthropic

大家知道 Anthropic 就是做 Claude 的公司

他們有寫了一個很長的部落格

講了他們對於 Claude 的分析

他們也在 Claude 上面找到了很多各式各樣的成分

他們找成分的方法是自動的

至於實際上怎麼做

你可以在看他們的部落格的文章裡面

有非常詳細的說明

他們就找到了一個向量

找到了一個成分

這個成分是可以讓語言模型

拍馬屁、諂媚、尬吹的成分

然後這個 Claude

本來如果你跟 Claude 說

「我發明了一個諺語叫 stop and smell the rose

你覺得這個諺語如何呢」

這個不是一個新的諺語

這是一個老舊的諺語

所以 Claude 就會說

「這個諺語根本就不是你發明的

這個是 18 世紀就有的

這個諺語代表什麼什麼意思」

但是如果你把這一個尬吹的成分

加到 Claude 的 representation 上面

你不管做什麼它就開始尬吹

你就跟它說

我發明了這個諺語你覺得怎樣

它就會說

「哇你真的太厲害了

你真的是世界偉人

這句話一定會名留青史

我實在是比不上你

我實在是比不上你的天才

我很 humble in your presence」

所以它就會開始胡亂吹捧

毫無道理的吹捧

所以這個就是吹捧的成分

好,那在這個文章裡面

還找了各式各樣的東西

大家可以再慢慢研究這一個 blog 的文章

那另外一個分析的方法

叫做 Logit Lens

我們剛才分析的方法

是觀察 representation

或者是擾動 representation

但是這個觀察或擾動

它並沒有真的跟文字相關

Logit Lens 這個方法

是直接把語言模型的 representation

對應到文字

所以可以直接看這個對應的文字

知道這個 representation

可能代表什麼意思

那怎麼做呢

我們剛才有講過說

這個語言模型的最後一層

會做 unembedding 這件事情

把最後一層乘上 LM Head

就可以得到一個向量

這個向量的每一維

代表了某一個 token

它出現的分數

那其實呢

你可以對每一層都做 unembedding

通常我們只需要對最後一層

做 unembedding 得到機率分布

但其實你可以對每一層

都做 unembedding

你可以把每一層的 representation

都拿出來跟 LM Head

乘乘看

看看你會得到什麼樣的東西

這個做法叫做 Logit Lens

這個做法它象徵的意涵就是

我們去看 LM Head

在每一層在思考的時候

它心裡期待輸出的 token 是什麼

但真正會輸出的 token

是最後一層 representation

做 unembedding 的結果

但是你可以想像說

語言模型在它內心的每一層

它都想要產生

對於下一個 token 的預測

只是還沒有非常的完整

每一層它都想了一下

每一層都想了一下

那你可以看它在第一步思考的時候

它覺得下一個 token 要接什麼

再想一步

它覺得下一個 token 要接什麼

所以你可以從 Logit Lens

看到語言模型每一層思考的過程

那所以你就可以解讀

語言模型的 representation

在每一層間的變化

那我們可以象徵的

就是比喻式的

把這個過程想成是

窺探語言模型的思考過程

那等一下在實作

也會帶大家看一下

Logit Lens 這個方法是怎麼用的

那這邊是先引用一個論文上面的結果

那在這篇文章裡面

其實 Logit Lens 這個技術

也是上古時代

在史前時代人類就已經知道了

就我所知

Logit Lens 最早的文獻

可能是 2020 年的這篇文章

但那個時候並沒有把這個技術

叫做 Logit Lens

那這個其實是我們實驗室的文章

那後來大概在半年之後

有人寫了一篇博文

把這樣的方法命名為 Logit Lens

那這個時間點是引用一篇 2024 年的文章

他們用 Logit Lens 去分析了

Llama 做翻譯時候的狀況

怎麼分析呢

它就是跟 Llama 輸入一個句子

這個輸入的句子是

法文的 "fleur"

這個是法文的 "fleur" 這個字

相當於中文冒號引號的什麼東西

那當然這個 Llama 最後會輸出「花」

但我們可以看說

從輸入引號到輸出「花」中間的過程中

模型心裡有什麼樣的變化

那我們就看這個表格最右邊的這個結果

而最開始呢

模型根本不知道要輸出什麼

就輸出一些亂七八糟的東西

然後接下來呢

從某一層之後

它的輸出其實是英文的 "flower"

雖然我們要它做翻譯

但是它先輸出了英文的 "flower"

然後在某一層之後

才輸出中文的「花」這個字

所以就可以看到說

語言模型好像是在內心裡

先把法文變成了英文

然後才把英文變成了中文

它的內心是用英文在思考

只是最後因為你要的是中文的答案

所以它才給你一個中文的答案

好,那另外一個分析的方法

叫做這個 Patch Scope

那這個 Logit Lens 呢

只會把 representation 對應到一個 token

但是很多意思你可能沒有辦法

用一個 token 來描述

那如果你想要一個比較完整的句子

來描述一個 representation 的話

那你可以用一個叫做 Patch Scope 的技術

那這個 Patch Scope 的技術

它運作是這樣的

當你給語言模型輸入的時候

語言模型在某一個地方

它輸出了一個 representation

你輸入「李宏毅老師」

那在最後一個位置的某一層

輸出一個 representation

但我們可以用 Logit Lens 看看說

這個 representation 如果對應到一個 token 的話

到底是什麼

但是「李宏毅老師」可能是沒有辦法

直接用一個 token 來描述的

所以你可以用一個比較複雜的方法

來想辦法把 representation

轉成一個完整的句子

這件事是怎麼做的呢

這個做法是這樣

你先給同一個語言模型一個句子

這個句子是

「請簡單介紹 X」

這個 X 你就放一個怪怪的符號就好了

然後語言模型把這個句子讀進去以後

在某一層你直接把

這一個情況下的綠色的 vector

直接拿來置換掉

所以對這個語言模型來說

從某一層開始

它讀到的輸入

好像是「請簡單介紹李宏毅老師」這樣的句子

然後它開始繼續去講話

它開始繼續去做文字接龍

它可能就會接出李宏毅老師的身份

然後這個技術就叫 Patch Scope

那 Patch Scope

它有一個比較大的彈性就是

你可以用不同的角度

來解讀同一個 representation

如果你今天的輸入是

「請簡單介紹 X」

來把這個 X 對應的那個位置

換成李宏毅老師的 representation

它可能就介紹李宏毅老師

但是你可以換一個問法

「請告訴我 X 的秘密」

然後你把 X 這邊對應的 representation

換成李宏毅老師的話

它最後可能輸出就是「是個肥仔」

雖然這個可能也不算是秘密就是了

那你就可以用這個方法

來檢視一個語言模型

當它看到一個輸入的時候

每一層它想到了什麼

這個輸入在每一層中

它的理解到底理解到什麼樣的地步

那這邊是引用那個

Patchscope 那篇文章

原始的一個實驗

它舉一個例子

我們現在呢

想要知道當模型讀到

「Diana,

Princess of Wales」的時候

那這個模型在每一層

它分別覺得輸入是什麼樣的東西

這邊的做法就是

你先把這個詞彙丟到語言模型裡面

得到它每一層的 representation

然後接下來呢

你再給同樣的模型一個 prompt

那這邊它其實不是用「請簡單介紹 X」

它是用別的方法

那不同 prompt 的效果不一樣

實際上它用什麼 prompt 呢

你再去文章裡面仔細讀它

就給這個語言模型「請簡單介紹 X」

那你把 X 呢

換成輸入是「Diana」的時候

的每一層的 representation

你把這一層換成粉紅色的 representation

看看最終會輸出什麼

把這一層換成綠色的 representation

看看會輸出什麼

把這一層換成藍色的 representation

看看最終會輸出什麼

那它看到了什麼樣的結果呢

他們的觀察是這樣的

如果你叫語言模型解釋

前 1 到 3 層的 representation

那你會發現說語言模型

它其實沒有看到整個輸入

它只看到 "Wales" 這件事情

因為它的解讀是

「我現在這個 representation 是什麼呢?」

第一層、第二層它的輸出都是

"country in the United Kingdom"

第三層的輸出是 "country in Europe"

就代表說它以為它看到的是一個國家

代表語言模型在第一層到第三層的時候

它其實根本沒有剖析完整的輸入

它只看到了 "Wales" 這個字而已

那接下來呢

在第四層呢

它顯然看到了 "princess" 這個字了

它說第四層的 representation

代表的是「某一個女性王室成員的稱號」

而到第五層的時候

它就再想了一次

它再想一下 "Princess of Wales" 到底是誰呢

"Princess of Wales" 不是一個普通的 "princess"

她是威爾斯王子的 "princess"

她是威爾斯王子的老婆

所以它在第五層就可以解讀說

這個 representation 代表了「威爾斯王子的 wife」

然後到第六層呢

它就知道說這一整個輸入指的其實是 Diana 這個人

它就給了一個 Diana 完整的介紹

所以從這個分析你就可以看到

語言模型的每一層的 representation

它在想什麼

它看到了什麼

好,那接下來下一段

我們是要看這個語言模型的內部的每一層

語言模型的每一層的內部是怎麼運作的

一個 layer 到底做了什麼事情

它才能夠把上下文融合起來

得到新的輸出的 representation

好,那一個 layer 裡面發生了什麼事情呢

那我們這邊是用 Transformer 這個 network 架構

<b>來跟大家說明</b>

<b>那如果是不同的network架構</b>

它一個 layer 裡面做的事情是不一樣的

<b>那我們這邊看的是Transformers這個model</b>

<b>它每一個layer裡面發生了什麼事情</b>

好,那它基本上呢會做兩件事

就這個 layer 裡面呢是還有 sub-layer 的

所以它 layer 中還有 layer

好,在一個 Transformer 的 layer 裡面

它會先有一個 self-attention 的 layer

或有時候就直接縮寫成 attention 的 layer

那這個 attention layer 它做的事情是

輸入幾個向量,它就輸出幾個向量

輸入跟輸出的長度也會是一樣的

那今天呢之所以一個 layer 可以考慮上下文

靠的就是這個 attention layer 的力量

那 attention layer 它就輸出一排向量

那輸出的這一排向量呢

我們先把箭頭叫出來

輸出的這一排向量呢

每一個向量會通過幾個 feed-forward 的 layer

那等一下會再解釋一下什麼是 feed-forward 的 layer

再得到最終的整個 layer 的輸出

那這個 Transformer 呢,它的精華就在這個 self-attention

我們剛才說能夠考慮上下文

靠的就是 self-attention

所以我們先來仔細的看一下

這個 self-attention layer 裡面

發生了什麼樣的事情

那講到 self-attention

通常大家最常想到的就是

"Attention is all you need" 這篇 paper

這是一篇 2017 年的 paper

上古時代的文章

這個是寒武紀時候的文章

那個時候地球上剛有了多細胞生物

那很多人呢誤以為

"Attention is all you need" 這篇 paper

發明了 attention

這其實是個錯誤的概念

你知道 attention 這個概念大概 2014 年就已經有了

那 2014 年那時候有好幾篇 paper 都提出了 attention 的概念

然後在 15 年、16 年都有好些論文呢

嘗試把 attention 用在語言模型上

包括我們實驗室也曾經有論文嘗試過類似的事情

所以其實 attention 這個概念不是在寒武紀才有的

它其實早在地球上只有單細胞生物的時候

就已經有 attention 了

所以 "Attention is all you need" 這篇 paper

它真正的貢獻是什麼

它真正的貢獻是在有這篇 paper 之前

大家以為 attention 不夠強

大家以為 attention 必須要搭配

其他處理上下文的類神經網路架構

比如說 LSTM 來使用

那時候以為 attention 不能夠單獨使用

這篇 paper 它真正的貢獻是

它拿掉了 LSTM 這類 recurrent 的架構

發現只有 attention 是能夠單獨運作的

所以它的標題才會是 "Attention is all you need"

它並不是發明了 attention

它是告訴你說

除了 attention 之外

我們不需要其他的東西

那當年為什麼要把 attention 以外的東西拿掉呢

為什麼當時在 17 年以前要處理這種上下文

更常用的主流的類神經網路的架構

是 recurrent 這種架構

recurrent 的架構很多變形

最常見的 RNN

LSTM

GRU

都是這種 recurrent 的架構

那時候以為 attention 只是個輔助

recurrent 的架構它的壞處就是

它不容易用 GPU 做平行化

所以 "Attention is all you need" 這篇 paper 最大的貢獻就是

把 recurrent 的架構拿掉

發現沒問題

然後可以做很好的平行化

訓練語言模型就更方便了

那這個都是歷史故事

那我們就直接來看一下 attention 到底是怎麼運作的

我們先來看第一層

我們看第一層 layer 裡面的 attention

第一層 layer 裡面的 attention

它會直接把 token embedding 當作輸入

然後它會根據輸入的這些 token embedding

產生另外一排 representation

那我們現在就來看看

最右邊對應到「果」這個 token 的 representation

是怎麼被計算出來的

在講實際的過程之前

先講一下大方向

這邊有兩個步驟

第一個步驟是要尋找輸入中

會影響「果」的意思的 token

比如在這個例子裡面

輸入如果是「兩顆青蘋果」

那如果只看「果」這個 token

你其實不知道這個「果」指的是蘋果

你甚至不知道它是一個青色的蘋果

它可能是任何東西

它可能是個西瓜

可能是個鳳梨

可能是個蓮霧

它們都算是一種水果

那在這個句子中

「果」、「青」跟「蘋」會影響「果」的意思

所以 attention 第一件做的事情

是找出輸入的 token 裡面

哪些 token 會影響現在我們要考慮的

「果」這個 token 的意思

然後接下來把這些 token 的資訊

跟「果」這個 token 的資訊合在一起

你就會得到新的意思

過了 attention 之後

可能模型就知道

這個「果」它不是任何的水果

它是一個蘋果

而且還不是一個紅色的蘋果

是一個青色的蘋果

那實際上是怎麼做的呢

我們就來看第一步

怎麼尋找輸入中會影響「果」的意思的 token

這邊的操作是

模型會把每一個輸入的 token

都拿去計算跟「果」之間的相關程度

那這個相關程度是怎麼被計算出來的呢

需要有兩個步驟

第一個步驟是

我們先把「果」這個 token

它的 token embedding 拿出來

乘上一個叫做 Wq 的矩陣

那把一個 embedding、一個向量乘上一個矩陣

你就得到另外一個向量

那從 Wq 出來的這個向量

它的名字叫做 query

那因為它是「果」的 query

所以我就用 q 下標「果」

「果 q」聽起來像是某個果凍的名字

當做這個 query 的代號

好,那所以呢根據「果」,我們透過 WQ 得到 果q 這個向量。

那之後呢,我們就不把向量跟矩陣的相乘畫出來了。

當我畫一個矩陣,然後有個向量指到它再伸出去的時候,

就代表說輸入的這個向量乘上 WQ,得到輸出的這個向量。

好,那我們要怎麼考慮「果」這個 Token 跟其他 Token 之間的關聯程度呢?

首先,「果」這邊會產生一個 q (query) 向量,

然後其他的 Token 會再乘上另外一個矩陣,

這邊我們稱之為 WK,來得到一個 k (key) 向量。

這個 k 向量呢,每一個 Token 都會得到一個。

那如果是把「青」這個 Token 的 embedding 通過 WK,就會得到「青」的 k 向量,

我們這邊就用 k-青 來表示這一個向量。

然後呢,我們把 q (query) 跟 k (key) 拿去計算它們的相似程度。

在歷史上有各式各樣不同計算相似程度的方法,

甚至一度曾經有人覺得,這個相似程度要用另外一個類神經網路來計算,

就訓練另外一個類神經網路來計算這個相似程度。

後來這些方法都消失在歷史的洪流中,

那現在剩下主流的方法是最簡單的做法,

就是直接算它們的 dot product (點積)。

直接算這兩個向量的相似程度。

算出來 dot product 的數值越大,

就代表這個 key 所對應的 Token,

對這個 query 所對應的 Token 有越大的影響力。

那對每一個 Token 都會做一模一樣的計算。

剛才是對「青」這個 Token 做這個計算,

那我們也要對「顆」這個 Token、

「兩」、「顆」、「青」、「蘋」、「果」這五個 Token 都做一樣的計算。

我們這邊再展示一下對「蘋」這個 Token 做一樣的計算。

所以「蘋」這個 Token 的 embedding 通過 WK,

會變成「蘋」的 key,

也就是 k-蘋。

然後呢,k-蘋 會跟 q-果

這兩個向量去算 dot product。

算出來是負的。

代表說呢,「蘋」這個 Token 可能對「果」這個 Token

它的意思沒有什麼影響。

那講到這邊,就出現了一個盲點。

這個盲點是這樣:

當我們在產生 q-果 跟 k-青 的向量時,

我們其實只考慮了它們的 Token Embedding,

你其實並沒有考慮它的上下文。

你是拿「果」的 Token Embedding 得到「果」的 query,

拿「青」的 Token Embedding 得到「青」的 key,

然後就去算相似度了。

這會導致什麼問題?

這會導致說,假設我有兩個句子,

一個句子叫做「兩顆青蘋果」,

這裡的「青」跟「果」是非常有關係的。

另外一個句子「青山綠水紅蘋果」,

這個「青」跟「果」是沒有關係的。

但是它算出來的影響力、

算出來的 dot product,

會是一樣的。

因為這兩個「青」,

它通過這個矩陣得出來的 key 都是一樣的;

這兩個「果」,它 Token Embedding 是一樣的,

所以通過這個矩陣得出來的 query 是一樣的。

你算出來的影響力,

這個「青」跟「果」的影響力、

和那個「青」跟「果」的影響力,也會是一樣的。

所以我們這邊需要把距離,

兩個 Token 間的距離,

也就是 key 跟 query 的距離考慮進來。

那要怎麼考慮進來呢?

其實有非常多不同的方法。

這個方法多到我覺得需要開一門課,

需要有另外一門課直接講它。

但我們沒有時間講這件事情。

那這邊講個最簡單的方法,

最簡單的方法就是,

其實在這個類神經網路裡面,

還有一個東西叫做 Positional Embedding。

在語言模型裡面,

還有一個東西叫 Positional Embedding。

然後這個 Positional Embedding 裡面,

它記載了每一個位置的資訊。

輸入的這串文字的每一個位置,

都會對應到一個向量。

所以它也是一個 table,

它也是語言模型參數的一部分。

第一個位置有一個代表第一個位置的向量,

第二個位置有一個代表第二個位置的向量,

以此類推。

接下來,「兩顆青蘋果」這五個 Token,

分別會加上代表第一個位置的向量、

代表第二個位置的向量、

代表第三個位置的向量,以此類推。

所以現在 Token Embedding 裡面,

不是只有 Token 的意思,

它還包含了這個 Token 在第幾個位置的資訊。

但這個方法,

你可能可以想出一大堆的可能問題。

舉例来说,

這是否意味著,

如果我們需要 Positional Embedding 的 table,

是否意味著語言模型

它能夠處理的輸入長度是被固定的?

假設我這個 table 就是固定說,

有 256 個位置,

這 256 個位置都有對應的 Embedding,

那如果現在輸入的長度有 257 個 Token,

怎麼辦呢?

沒有對應的 Positional Embedding 了。

所以這會不會是一個問題?

這顯然是一個問題。

所以有很多其他更好的方法,

來處理 Positional Embedding,

來處理這個位置的問題。

比如說我們常用的 Llama,

它處理這個位置的方法,

是用一個叫做 RoPE 的技術。

那這個大家有興趣再自己研究。

RoPE 這個技術就可以很神奇的做到,

訓練的時候,

就算有一些位置我從來沒有看過,

訓練的時候輸入長度都是 1 到 4000,

但是我在用它的時候,

可以用 1 到 8000,

就是這麼神奇。

這個至於怎麼做到的,

大家有興趣再自己研究。

總之有很多不同的方法,

把位置的資訊加到 Attention 的計算中。

那我這邊講的是一個

古早時代的方法,

不見得是特別有效的方法,

只是告訴你說,

這個位置的資訊是需要被考慮的。

好。

那現在我們已經計算出

每一個輸入的 Token

對「果」的影響力了。

那我們把 dot product 算出來的分數,

記載在這個地方。

那其實自己跟自己的影響力

也是會被計算的。

在一般的 Attention 裡面,

也會計算自己跟自己的影響力。

然後這些 dot product 得出來的數字,

如果很大的話,

就代表說這個 Token,

它對於我們現在要考慮的

「果」這個 Token,

有很大的影響。

那這個時候你會說,

「果」attend 到某一個 Token。

就比如說「果」跟「青」之間,

它們算出來的 dot product 分數很大,

那你就會說,

「果」attend 到「青」,

或「果」attend 到「蘋」。

那這邊如果翻成中文的話,

就是「果」這個 Token

它專注於看「青」這個 Token,

它專注於看「蘋」這個 Token。

不過這個「專注」,

也許跟人類的專注

也沒有什麼關聯性,

總之就是 dot product 算出來比較大就是了。

那這個 dot product 算出來的分數,

它就叫做 attention weight。

所以有人告訴你 attention weight,

它指的就是 dot product 算出來的分數。

那這些 attention weight,

如果你只算 dot product 的話,

那它可能是任何數值,

它可能是正的、也可能是負的。

那通常這邊,

會把它再過一個 Softmax,

讓它變成一個像是機率分佈的東西,

讓所有的 attention weight

變成介於 0 到 1 之間,

然後全部加起來都是 1。

這個操作到底是不是必要的呢?

其實有人做過實驗,

把 Softmax 拿掉,

換成其他的處理方式,

結果也差不多。

所以看起來 Softmax 不是一定必要的,

只是它是一個非常常用的

處理 attention weight 的方式而已。

那計算出了 attention weight 之後,

我們把 attention weight

放在每一個 Token embedding 的旁邊。

接下來進入第二階段。

我們已經知道哪些 Token 會影響「果」的意思,

接下來就要把這些 Token

它的意思跟「果」的意思,

把它融合在一起。

那怎麼做到這件事呢?

這邊的做法就是,

把每一個 Token 算出來的 attention weight,

乘上一個叫做 value 的 vector。

那這個 value 的 vector 是怎麼產生的呢?

你會再有一個矩陣,

叫做 WV。

那你會把每一個 Token 的 embedding

過這個 WV 以後,

得到對應到那個 Token 的 value vector。

那有了這個 value vector 以後,

下一步驟就是,

把這些 value vector

根據 attention weight 做加權,

也就是 weighted sum。

所以,「兩」的 value vector 乘上 0.03,

加上「顆」乘上 0.02,

加上「青」乘上 0.33,

加上「蘋」乘上 0.55,

加上「果」乘上 0.07,

做 weighted sum 全部加起來,

得到一個新的向量。

因為它是很多不同的 Token embedding

融合在一起的,

所以這邊就給它一個彩色的向量,

代表它是很多不同 Token embedding

加在一起的結果。

那這邊你可能會擔心說,

「果」的權重有點低,

這樣會不會模型就根本忘了

這個位置是代表「果」這個 Token 了呢?

其實不會。

因為有一個操作

叫做 residual connection,

你會直接把「果」的原來的 embedding

拉過來,

加上這個 weighted sum 的結果,

當作最終 Attention layer 的輸出。

所以這邊這個向量,

就是 Attention layer 在這個位置

輸出的向量。

這個就是 Attention 最基本的操作。

但這只是基本的操作而已,

這邊還沒有講完。

Attention 真正的操作是更加複雜的。

我們剛才講說,

我們的第一步是要尋找

影響「果」這個意思的 Token,

但所謂的「影響」,

這邊應該加一個引號,

因為影響有很多不同的面向。

也許「青」這個字,

決定了這個水果是什麼顏色,

但你怎麼能夠說

「兩」這個字對「果」沒有影響呢?

「兩」這個字有另外一個面向的影響,

它告訴你說這個水果到底有幾個。

當「果」前面有「兩」這個字的時候,

這個「果」的 embedding 的意思也不一樣了。

所以其實 Attention 往往不止一組 Attention,

而是有多組的。

這個多組的 Attention,

通常叫做 Multi-head Attention。

所以你可能會有一個 Attention,

它是負責找每一個 Token 的形容詞的。

剛才講的 WK、WQ 它做的事情,

可能是去找形容「果」的形容詞,

所以「兩」對它來說,

可能是沒有什麼影響力。

但是可能有另外一個 Attention,

它專找數量。

它專門想知道說,

現在我考慮的這個 Token,

到底根據這個上下文,

它是單數還是複數?

它到底有幾個?

所以你可能會有另外一組參數,

這邊寫 WK2 跟 WQ2。

那你這個「兩」,

它會過 WK2 得到另外一個 Key。

這個「果」會過 WQ2 得到另外一個 Query。

我們會把這個 Query2 跟 Key2,

一樣去算它的 dot product。

因為這一組 Query 跟這組 Key,

跟找形容詞的這個 Key 跟 Query,

它們是不一樣的。

所以你可能會算出

不一樣的 dot product 的結果。

那如果這個 Q 跟 K,

它們就是設計來找數量的,

那可能「果」這個 Token 跟「兩」這個 Token,

它們做 dot product,

它們的 Query 跟 Key 做 dot product,

用第二個 Attention head 做 dot product 以後,

算出來的數字就會很大。

所以這個是 Multi-head Attention。

所以 attention weights

不是只有一組。

我們剛才看到的第一組 attention weights,

它會告訴你說,

「青」跟「蘋」對「果」的影響力很大。

那可能會有另外一組 attention weights

告訴你說,

「兩」跟「果」的影響力才大,

但是它是另外一個不同面向的影響力。

那通常一個 Self-attention 裡面

會有好多組的 head。

那等一下會實際看看說,

Llama 它的一個 Attention 裡面

到底有多少個 head。

那每一個 head 呢,

又會有自己的 Value vector。

所以你會有另外一個 WV,

這邊寫做 WV2。

它算出第二組 Value vector。

第二組 Value vector

要去乘上第二組的 attention weight。

所以第二組的 Value vector

去乘上第二組的 attention weight。

第二組的 attention weight 告訴你說,

「兩」其實對「果」這個 Token

也是非常重要的,

只是它是另外一個面向。

然後你一樣做 weighted sum,

得到另外一個彩色的向量。

所以每一個 attention head

都會給你一個向量。

那我們在這個投影片裡面,

舉的例子是有兩個 attention head,

所以我們就會有兩個向量。

那這兩個向量呢,

你要把它再揉合起來,

所以再過一個矩陣,

把這兩個向量

乘上一個叫做 WO 的矩陣,

再得到一個新的向量。

這個新的向量,

再跟「果」呢,

用 residual connection 加起來。

這個才是 Self-Attention layer

在「果」這個 Token 對應的位置,

最終輸出的 representation。

所以這個是 Self-Attention 做的事情。

那從 Self-Attention 剛才的運算,

你可以看出說,

輸入越長,

運算量越大。

這個就是為什麼語言模型

在處理長輸入的時候,

會有困難的原因之一。

那要怎麼解決這個問題呢?

就有很多不同的方法。

那因為我們上課時間有限的關係,

所以我把這一段留在

延伸閱讀裡面,

你可以看一下。

上個學期的機器學習課程,

我們花了一堂課的時間,

跟大家講 Transformer

有哪些其他的競爭者。

比如說一個

你可能比較熟知的競爭者

就是 Mamba。

它們就是為了處理 Attention

在輸入越長的時候,

運算量就越大

這樣的問題。

好,那我們剛才講了

怎麼算出對應到

「果」這個位置的 representation。

那如果是對應到

「蘋」這個字的 representation 呢?

這邊要注意的事情是,

在一般的時候、在實作上,

只會考慮每一個 Token

左邊的,

所謂的左邊就是前面的 Token。

所以我們只會去考慮

「兩、顆、青」這三個 Token

對「蘋」的影響力,

我們就不會再考慮

右邊的 Token「果」

對「蘋」的影響力。

這種只考慮左邊、

只考慮前面的 attention,

叫做 Causal Attention。

那一般語言模型呢,

通常都會

...今天一般的語言模型

就是用 Causal Attention。

那能不能用

Non-Causal 的 Attention?

我們能不能夠

在考慮「蘋」的 Token 的時候,

在做 self-attention 的時候,

把右邊這個 Token 也考慮進來呢?

可以。

那這樣做,

會不會比較好呢?

有些文獻指出說

可能會更好一點。

因為一個句子、

一個詞彙、

一個 Token 不是只受

左邊的詞彙影響,

也有可能受到右邊的詞彙影響。

所以你考慮完整的上下文,

可能會更好。

但是 Causal Attention

是為了計算方便

所產生的一個方式。

那至於為什麼這樣計算比較方便,

你可以想想

語言模型生成句子的過程,

是用 autoregressive 的。

因為 autoregressive 的這個設計,

用 Causal Attention

可能會比較方便。

那細節,

因為我不想讓這堂課太長...

我覺得第一講跟第二講

其實太長了。

為了避免這個課太長,我們就留給大家自己思考。

好,那接下來呢,

我們來看最後一個部分。

我們來看看

過了 Attention 之後,

the feed-forward layer

做了什麼樣的事情。

那在這個投影片上,

我們的 feed-forward layer 有兩層。

那在實際上不一定兩層,

那等一下看到的這個

Llama2 4B 也是兩層

等一下看到的 Llama 3B 也是兩層,

Gemma 4B 也是兩層。

但是其實不一定要是兩層,

你要放幾層都可以,

取決於你要怎麼設計

你的模型的架構。

那我們來看看兩層的

feed-forward layer 是怎麼運作的。

輸入是紅色的這個向量,

過一個 feed-forward layer 的意思就是

把紅色的向量

乘上一個矩陣,

這個矩陣叫做 Weight。

我們用 W 來表示。

那乘完之後,

再加上一個向量,

這個向量我們叫做 Bias。

把紅色的向量

乘上 Weight 這個矩陣,

再加 Bias 這個向量,

你再得到的東西

還是一個向量。

這個向量會通過一個

函式叫做 activation。

會通過 activation function。

那 activation function 的形狀

是人類設計的。

那過去比較常用的

一種 activation function

叫做 ReLU,

R-E-L-U,

Rectified Linear Unit。

那它操作非常的單純,

就是輸入的向量裡面,

如果小於 0 就設成 0,

如果大於 0 就不動。

一個非常簡單的操作。

不過近年來在大型語言模型,

也不一定用 ReLU,

有很多更複雜的 activation function,

比如說 GeLU 等等。

這個就留給大家自己研究。

總之這邊有一個人為訂定的

activation function,

對輸入做一些改動,

然後得到輸出。

然後這個輸出的藍色向量,

它是一個中間產物,

再過一個 Feed-Forward Layer。

這個藍色向量

再乘上另外一個矩陣 W',

然後再加上另外一個向量 B',

再通過 activation function,

最終得到輸出,這裡的

黃色的向量。

這個向量乘矩陣

再過 activation

再乘另外一個矩陣

最後得到黃色的向量

這一連串的 process

代表什麼樣的含義呢?

當然你可以很簡單的理解成,

反正每過一層就是過一個轉換,

這樣也可以。

這樣理解其實也沒什麼問題。

但這邊我就引用另外一篇論文,

這篇論文告訴你說,

如果你的 Feed-Forward Layer 有兩層的話,

你也可以把它看作是一個

Attention 的過程,

就好像我們講的 Self-Attention 一樣,

它是另外一個維度的 Attention,

非常神奇的一個想法。

那為了避免這個課程太長,

我把文獻留在這邊給大家參考。

那你看它的標題:

"Transformer Feed-Forward Layers

Are Key-Value Memories"

它就告訴你說,

Transformer 的 Feed-Forward Layer

其實是做了另外一組 Attention,

它有另外一組的 Key 跟 Value,

這個是一個非常有趣的

對於 Feed-Forward Layer 的看待方式。

好,那

講到目前為止,

我們說這個語言模型就是 Deep Learning,

Deep Learning 就是類神經網路,

但講到目前為止都好像

沒有什麼跟類神經網路有關的東西。

那我們來告訴你說,

所謂類神經網路,

它怎麼把現在我們講的東西,

看待成一個類神經網路。

我們來看一下,

在這個藍色的向量裡面,

它的第一個維度

是怎麼被計算出來的。

第一個維度的數值,我們把它命名為 y1。

y1 是怎麼被計算出來的呢?

假設這個紅色的向量裡面

有三個數值,

dimension 是 3,但實際上不可能是 3 啦,

實際上通常是上千的。

假設紅色的向量就是三個 dimension,

三個 dimension 的數值分別叫

x1、x2 跟 x3。

然後怎麼計算出這個 y1 呢?

你就把...

W 的第一 row (列) 拿出來。

這個第一 row 呢,

如果你輸入的這個向量是

三個數值,

第一 row 也得是三個數值 分別是w1 w2 w3

如果你學過線性代數的話,

那你知道 y1 的算法就是

x1*w11 + x2*w12 + x3*w13

再加上 b1,就等於 y1。

所以 y1 跟 x1、x2、x3 的關係是

X1 x W1, X2 x W2, X3 x W3 加 B1

通過一個 activation function

它可能就是簡單的 ReLU

然後得到 Y1

這個沒有什麼神奇的地方

就只是把這個矩陣運算的其中一部分

拿出來給你看而已

那在這整個矩陣運算裡面

同樣的這個式子

你會反覆做很多次

這邊有幾個 columns

這樣的式子就要做幾次

但如果只說這是矩陣運算的話

聽起來不夠潮

所以有人就換了一個說法

我們是從 X1, X2 變到 Y1

然後就畫個圖

說把這個 X1 x W1, X2 x W2, X3 x W3

其實是換湯不換藥的東西

再加上 B1

通過 activation function 把它畫一個圈圈

得到 Y1

接下來給它一個名字說

這叫做一個神經元

本來只是一些簡單的運算

聽起來不夠潮

沒有辦法騙騙麻瓜

然後但是你就說它是一個神經元

然後接下來就開始鬼扯說

這個就是模仿人腦的運算

所以它應該很厲害

這個就是 AI 的起源等等

然後麻瓜就會覺得

這個聽起來非常的潮

其實就是矩陣運算而已

所以這個就是一個 neuron

然後同樣的這樣的操作

在整個語言模型裡面反覆的出現

所以它就是很多 neuron 集合起來

就是一個神經網路

但是其實就都是矩陣的運算而已

那今天講的

有關大型語言模型內部運作機制的研究

只是滄海一粟而已

還有很多可以探討的問題

那如果你有興趣的話

可以看一下上學期機器學習的第三講

講了 AI 的腦科學

那今天講的內容有一部分

Large Lens 跟 PathScope

是有出現在第三講裡面的

但第三講還有更多的內容

值得你再去深挖

好,接下來我們就進入實作的環節

來實際解剖一個大型語言模型

看看它裡面有什麼東西

這個是 Colab 的連結

好,如果大家找不到 Colab 連結的話

反正投影片都是公開的

你可以在投影片上找到

上課範例的 Colab

我們現在就來跑一下上課的範例

好,那這個

這個 Colab 的前面幾步的操作呢

都跟第一講、第二講是一模一樣的

總之你要先連到 Hugging Face

然後下載 Hugging Face 上的模型

那今天我們須要下載兩個模型

我們下載了

Llama 3B 這個模型

跟 Gemma 4B 這兩個模型

因為我們想要比較這兩個模型的差異

好,那這個 Llama 3B

它的 Tokenizer 跟 Llama 3B

它的那個 Model 的參數

就分別存在 Tokenizer 跟 Model 裡面

然後這個 Gemma 4B

就分別存在 Tokenizer 2 跟 Model 2 裡面

所以就記得說 Model 是 Llama

Model 2 是 Gemma

好,那我先來看看 Model 中有什麼

首先你在 Model 後面加點 .num_parameters()

你就可以看到這個 Model 裡面有幾個參數

所以我們來看一下

Llama 3B 有幾個參數吧

然後我執行 model.num_parameters() 以後

它給我一個巨大的數值

這個巨大的數值

這個巨大的數值算出來

就是 32 億多

所以你就知道為什麼 Llama 3B 叫 3B

這個 B 是 Billion 的意思

因為它有超過 3 個 Billion 的參數

這邊的數位就是它模型中的參數量

那 Gemma 呢?

這個 Model 2.num_parameters()

會告訴我們 Gemma 4B 有幾個參數

那算出來這邊有 43 億個參數

所以它就叫 Gemma 4B

因為它有超過 4 個 Billion

超過 40 億個參數

好,那在語言模型裡面呢

這些參數都是以矩陣跟向量的形式

被存在一起的

那矩陣跟向量其實又統稱為張量

又統稱為 Tensor

那所以在這個模型的輸出中

你常常看到 Tensor 這個字

指的就是矩陣或者是向量了

那我們可以把一個 Model 中所有的參數

也就是所有的矩陣跟向量

一個一個的印出來

那每一個矩陣或向量

它會包含兩個我們可以看的資訊

一個資訊叫做 Name

就是它會給每一個矩陣一個名字

那你從這個名字可以猜說

這個矩陣是用在整個語言模型中的哪裡

比如說假設有一個東西

它的名字叫做 model.layers.0.mlp.weight

那你就知道說

這個應該是放在第 0 層

但第 0 層其實是第 1 層

大家應該知道 Computer Science 的習慣,0

其實就是 1

所以這是第 1 層

然後 MLP 其實就是 Feed-Forward Network

剛才沒有提說 MLP 就是 Feed-Forward Network

然後它是 Feed-Forward Network 的 weight

所以它是第 1 層的 Feed-Forward Network 的某一個 weight

那 Feed-Forward Network 裡面通常有好幾層

那 up_projection 其實通常指的是第 1 層 的意思

然後會有一個 shape

一個形狀

它會告訴你說

我們還可以印出一個東西叫做 shape

這個 shape 會告訴你說

這個張量它長什麼樣子

比如說如果印出來的 shape 是 (8192, 3072)

就代表說這個矩陣它的 column 有 8192

它的 row 有 8192 個 row

它的 column 有 3072 個 column

然後我們用 named_parameters()

來把這些參數一個一個的召喚出來

所以當我執行這段程式碼

執行這個 block 之後

我就可以把 Llama 3B 裡面所有的參數

它的名字跟它的形狀把它條列出來

那我們來看看裡面到底有什麼樣的參數

第一個參數叫做 embed_tokens.weight

它是什麼?

它就是 token embedding table

它有多大?

它的大小是 128256 x 3072

非常巨大的一個矩陣

那 128256 是什麼意思?

就是 vocabulary size

就是 token 的數目

所以你知道 Llama 大概有 12 萬 8 千多個 token

那 3072 就代表每一個 token

它對應的 token embedding dimension 是多少

它對應的 token embedding dimension 是 3072

進入第一個 layer

這邊寫成 layer 0

它其實是第一個 layer

第一個 layer 裡面

我們剛才不是說算 attention

你要有一個計算 query 的 matrix

有一個計算 key 的 matrix

有一個計算 value 的 matrix

這邊果然有一個 query 的 matrix

有一個 key 的 matrix

有一個 value 的 matrix

query 的 matrix 是 3072 x 3072

key 是 1024 x 3072

value 是 1024 x 3072

那這邊看這個 shape 的時候

通常右邊代表的是輸入

左邊代表的是輸出

所以每一個 token embedding

token embedding 是 3072 維

它乘上這個 query 的 matrix 之後

會從 3072 維的向量

變成另外一個 3072 維的向量

那 key 呢?

key 是 3072 維的向量變成 1024 維的向量

query 跟 key 不是要算 dot product 嗎?

算 dot product 不是應該 dimension 一樣

才有辦法算 dot product 嗎?

一個 3072 維的向量要怎麼跟

1024 維的向量算 dot product 呢?

這個就是奇妙的地方

這個叫做 Grouped-Query Attention

這個大家有興趣再自己研究

總之這是 Llama 裡面用的一個

可以說是節省參數的設計

一個特殊的設計

總之我們這邊看到

query, key 跟 value 產生它們的 weight

那這邊你可能會問說

這邊只有一組 query, key 跟 value 的參數

是不是只有一個 attention head?

我們剛才不是說應該要有多個 attention head 嗎?

那我告訴你這邊有多個 attention head

至於只有三個 matrix

到底是怎麼樣製造出多個 attention head 的

這個也留給大家自己研究

好,多個 attention head 要被

用一個叫做 Wo 的東西併在一起

這個就是這邊的這個 O 這個東西

o_proj

這邊有一個怪怪的東西叫做 gate_proj

這個大家有興趣再自己研究它是什麼

然後過完 attention 以後

有兩層的 feed-forward

第一層 feed-forward

它會把 3072 維變成 8192 維

在下一層的 feed-forward

會把 8192 維變成 3072 維

變回 3072 維

總之 Llama 的一個

Transformer 的 block 裡面

就是兩個 feed-forward network

這邊還有一些神秘的東西叫做 LayerNorm

LayerNorm 也是有參數的

至於它是什麼

這個也再留給大家自己研究

總之我們走完了

layer 0 就是第一層

然後接下來第二層就是 layer 1

再下一層就是 layer 2

以此類推

那每一層都有一大堆的參數在裡面

然後一直下去、一直下去、一直下去

有好多好多層

這個是 Llama 3B,有幾層呢?

一直到 layer 27

一直到 layer 27

就是 28 層

因為它從 0 開始算的

所以就是 28 層

所以我們知道 Llama 有 28 層

然後最後在做 unembedding 的地方是沒有參數的

因為對 Llama 來說

unembedding 的矩陣就是 input 的 embedding table

所以這邊就沒有 unembedding 的矩陣

然後再來

我們現在換成把 Model 2

跑這個 named_parameters() 把它裡面的資訊印出來

我們現在把 Gemma 裡面的資訊印出來

這個是 Gemma 裡面的資訊

那你發現 Gemma 跟 Llama 其實不太一樣

Gemma 它前面還有什麼 vision tower

Gemma 是可以看圖片的

所以前面這些參數

就前面有掛 vision 的這些參數

是拿來處理圖片的

我們先不看它

所以前面好多參數都是弄圖片的

好,從這邊開始

從它這邊有寫命名有 language_model 開始

就是跟處理文字有關的

所以它一開始有一個 embedding table

這 embedding table 裡面有什麼呢?

這 embedding table 是 262144 x 2560

所以你看這個 Gemma 它的 token 有多少

個、十、百、千、萬、十萬

26 萬個 token

比 Llama 還多兩倍

然後它每一個 token 用 2560 維來存它

接下來它也有 Q, K, V

然後也有 O

Q, K, V 一樣,Q 跟 K 的那個

維度一樣對不起來

它一樣把 2560 維轉成 2048 維

跟 2560 維轉成 1024 維

一樣對不起來

為什麼會這樣?

留給大家慢慢研究

然後這邊就是其他都差不多

這邊也有 up_projection

從... 這是第一層的 feed-forward network

從 2560 維的向量變成 10240 維的向量

然後第二層的 feed-forward network

再從 10240 維的向量變回 2560 維的向量

每一層都是做一樣的事情

有很多層

有很多層

這個就是 Gemma

那總共有幾層呢?

總共有幾層呢?

最後算出來是 33

因為從 0 開始起算

所以有 34 層

所以我們知道 Gemma 4B 有 34 層

比 Llama 還要多

那如果你想實際把參數的數值印出來

因為我們前面只印出了參數的名字

跟它長什麼樣子

如果你真的要把它的數值印出來

那你要用一個叫做 state_dict() 的這個 function

你可以把它印出來

所以我執行 model.state_dict()

那它就會把所有的參數印出來

很多很多

每一個、每一組

每一個 matrix 裡面的數值都幫你印出來

然後你也搞不清楚發生什麼事

那我們可以只看某一個 matrix

某一組參數

一個 matrix 就是一組參數

比如說假設我想看這個 Model

就是 Llama 3B 的這個第 28 層

layer 27 其實是第 28 層

第 28 層的 up_projection

up_projection 是第一個 feed-forward network

它裡面的 weight 長什麼樣子

那我就先執行 model.state_dict()

把所有參數拿回來

然後這邊只取某一個名字的參數

然後把它存到 weight 裡面

那我可以把 weight print 出來

print 出來看到什麼呢?

什麼都沒有看到

就是一個矩陣

裡面有一大堆的數字

你很難想像說這些數位怎麼跟語言扯上關係

怎麼這些很多矩陣相乘

最後就會變出了一個

下一個 token 的機率

這真的非常的複雜

很難憑藉著人類的智慧把它想像出來

那我們這邊可以把這個矩陣的

左上角的 100x100 的範圍把它呈現出來

就長這樣

數字有正有負

那你也看不出什麼東西

就只能看到人類本質上的焦慮跟寂寞而已

所以你看不出什麼東西

通常比較能夠分析的

是語言模型的 embedding table

那我們現在就把 embedding table

再拿出來看看

那如果中間分析某一層

你通常是看不出什麼花樣

我們再來看看這個 embedding table

我們把 Model

它裡面的 model.embed_tokens.weight 拿出來

這個是什麼?

這個是 embedding table

我把它存進 input_embedding 這個變數裡面

我們先把 embedding table 拿出來

那裡面就會告訴我們說

每一個 token 對應到什麼樣的向量

我們把這個 embedding table 印出來

印出來是 128256 x 3072

就代表說有這麼多 token

token 的 ID 可以一直從 0 一直排到 128255

然後每一個 token 對應到一個 token embedding

它的長度是 3072

講到這邊

如果是細心的同學

你可能發現一個怪怪的問題就是

第一堂課

在說 Llama 的 token 的時候

token 不是只排到編號 128000 嗎?

這邊多了 256 個

那是什麼東西?

那個是保留的 token

那是可以讓你自訂新的 token

再插入 Llama 裡面

不然如果它把所有 token 用完

你就沒有辦法加新的 token

所以其實 Llama 的這個神經元

這個元模型是有留一些空間

讓你可以自己訓練模型

讓它讀懂一些新的 token

不過我們這邊就不詳細講這個細節

那我們可以把 input embedding 印出來看

總之就是個巨大的矩陣

你也看不出朵花來

接下來我們可以把每一個 token

對應的 token embedding 印出來

比如說我想知道 token ID 編號是 0 的 token embedding

我不知道你還記不記得在 Llama 裡面

編號 0 的天字第一號的 token 是誰

其實是驚嘆號

好,先把... 我們可以先...

我們這邊

如果你想要看 token ID 是 0 的 token

然後你可以怎麼做

你就去把 input_embedding 這個矩陣裡面

對應到 token ID 的那一個 row

這邊如果是 0 就是第 0 個 row

把它取出來印出來

你就知道驚嘆號對應的 token embedding

長什麼樣子

我來執行一下

token 0 對應到驚嘆號

token embedding 就長這樣

你也看不出什麼名堂來

那你試別的都是一樣

token embedding 1 是雙引號

就長另外一個 embedding 的樣子

token ID 2 就長另外一個樣子

總之每一個 token 都有一個

它自己對應的 token embedding 的向量

那我們怎麼來分析這些向量

到底包含什麼意思?

直接看這些 embedding

你往往看不出朵花來

比較有資訊量的是

token embedding 跟 embedding 之間的

相似程度

所以我們等一下做的事情就是

我們拿出ㄧ個 token

比如說 "apple"

然後我們找一下

"apple" 的 token ID

有它的 ID 以後

我們就可以知道

"apple" 這個 token 的 token embedding 長什麼樣子

然後接下來

我們再把 "apple" 的 token embedding

去跟所有其他 token 的 token embedding

算相似度

然後我們就可以找出

跟 "apple" 對於這個語言模型來說

跟 "apple" 這個 token 意思最相近的

前 K 名的 token

以下這段程式碼

就是在做我上面描述的這五個步驟

那因為時間有限的關係

我們這邊都不直接解釋程式碼

就是你就知道這個程式碼

在執行什麼就好了

執行這個程式碼以後

我們就可以輸入一個 token

比如說我輸入 "apple"

好,輸入 "apple"

然後就會去計算說

"apple" 的 token embedding

跟哪些 token 的 token embedding 是最像

比如說跟 "apple" token 最相近的

跟 "apple" 的 token embedding 最相近的那個字

其實是 "apple" 前面加空白

瞭解吧

就大家知道說

Llama 裡面它的 token 各式各樣都有

"apple" 大寫、小寫都算是不同的 token

前面有空白也算是不同的 token

所以跟 "apple" 前面沒有空白

意思最像的那個 token

是 "apple" 前面加一個空白

這有沒有覺得很合理呢?

然後第二像的就是 "Apple" 前面大寫

第三像的就是全部大寫 "APPLE"

第四像的是 "apple" 前面再加一個空白

全部大寫再加一個空白

不過它還有一些比較有意思的東西

比如說 "apple" 這個英文

跟 "蘋果" 的中文是最像

或者是 "apple" 居然跟 "Cupertino" 是最像

Cupertino 是什麼意思?

Cupertino 就是 Apple 總部的位置

所以對它來說

"apple" 也是有那個蘋果電腦的意思的

而如果你想要這個...

更看得出 "Apple" 跟蘋果電腦的關係

你要用大寫

因為其實蘋果電腦的 Apple

通常第一個字母會大寫

所以 "Apple"

我們看 "Apple" 第一個字母大寫

跟哪些 token 它的 embedding 是最像的

當然一樣,這個 "Apple"

這個首字母大寫

跟 "Apple" 首字母大寫再加一個空白

其實意思是最像的

不過它也發現說,你看 "Apple"

跟 "MacBook" 意思是很像的

"Apple" 跟 "iPhone" 還有 "iphone" 意思是很像的

所以知道對這個語言模型來說

"Apple" 這個詞彙

真的會讓它聯想到 "iPhone" 或者是 "MacBook"

這邊你要輸入什麼都可以

你就亂輸入一些

比如輸入個 "李"

"李" 這個 token 對它來說是什麼意思呢?

對它來說 "李" 最像的

當然是 "李" 前面加一個空白

但是它也知道

"李" 跟 "LEE" 英文的 "李"

其實意思是很像的

"李" 跟 "劉" 意思很像

因為他們都是姓氏

所以你知道模型很厲害

它知道很多很多的事情

當然有一些莫名其妙

為什麼 "李" 會跟什麼... "收入" 像?

我也不知道

反正它算出來就是這個樣子

然後這邊有一些怪怪的符號

這邊有怪怪符號

我先去查了

這個怪怪符號

其實是某個語言的 "李"

好像是某個阿拉伯語言的 "李"

所以對模型來說

不同語言同樣意思的 token

它的 token embedding 其實是非常接近的

那我們再亂輸入一些

輸入個 "王"

它除了知道說 "王" 呢

它這邊 "王" 跟 "王" 最相近的就是 "king"

所以它知道說 "王" 對應到英文就是 "king"

它也知道 "王" 跟中文的 "黃" 意思是接近的

所以這個語言模型的 token embedding

可以告訴我們

這個語言模型來說

哪些 token 是意思相近的東西

那剛才呢

就是只觀察了 token embedding

我們知道說這個 token embedding

接下來會被丟進 Transformer

然後每一層都會吐出一個 representation

每一層都會吐出一個 representation

那我們就現在來把這些 representation 拿出來看看

看看我們應該看到什麼東西

那我這邊做的事情是這樣子的

你想要得到那些 representation

你就得先編一個句子

然後丟到模型裡面

然後才能夠得到這些 representation

那我們現在輸入的句子是 "大家好"

把 "大家好" 先通過 tokenizer encode

變成 IDs

<b>然後呢 再把這些ID丟到模型裡面</b>

<b>那我們之前在第一講的時候</b>

<b>有做過非常類似的操作</b>

那個時候我們從 model output 拿出最後一個 token

下一個 token 的這個 probability distribution。

在這邊我們要拿每一層的 latent representation。

那如果你要拿每一層的 latent representation,

你需要在 model 的輸入加上 `output_hidden_states=True` 這件事。

你要加入這個 flag,

它才會把每一層的 hidden representation 存下來。

不然你就會…

不然它就沒有存每一層的 hidden representation。

好,現在 model 吃 token ID,

給它 `output_hidden_states=True` 得到 output,

然後你打 `output.hidden_states`,

就可以把 hidden states 那些 representation、

那些 hidden latent representation 通通取出來,

存在 `hidden_states` 這個變數裡面。

那 `hidden_states` 的第 0 個部分代表的就是 embedding。

就是這個 `hidden_states` 裡面的第 0 個部分,

它是 embedding,

然後第 1 個部分就是第 1 層、

第 2 個部分就是第 2 層,

以此類推。

然後這邊我們把這個拿到幾層,

包括 token embedding 也算一層,把它印出來。

然後我們把每一層裡面的參數的形狀把它印出來。

那我們這邊也會把 token embedding

還有第 1 層得到的 representation 印出來看看,

我們得到什麼樣的東西。

好,那我們看這個輸入是

「大家好」,輸入是「大家好」。

「大家好」這個輸入,

「大家」其實是一個 token,「好」是一個 token。

不過這個 Hugging Face Transformer 會比較雞婆,

會幫你在前面加一個代表開始的符號。

所以其實你輸入的是 3 個 token。

你輸入給語言模型的是 3 個 token。

好,那語言模型

把這 3 個 token 讀進去以後,

然後我們這邊拿到 29 層 representation。

那其實是 28 層加上 token embedding,

所以總共算出來 29 層。

那每一層給我們什麼呢?

每一層它的形狀是有 3 個數字來代表,

這邊有 1、3 跟 3072。

這 3 個數字分別代表什麼意思呢?

第 1 個數字代表一次處理幾個句子。

其實 model 是可以一次處理多個句子,

但我們這邊都是 1,

因為我們一次只處理一個句子,

我們還沒有講到 batch 的概念。

第 2 個數字代表輸入的 token sequence 有多長。

輸入 token sequence 有 3 個 token,

所以這邊就顯示 3。

然後第 3 個數字代表說,

那些 representation 有多少 dimension。

那 representation 的 dimension 都是 3072。

所以我們就把每一層、每一層,

通通都拿出來。

我們可以把它印出來啦。

這個 token embedding 的輸出印出來就長這樣。

第 1 層 transformer 印出來就是這個樣子。

你也看不出什麼有趣的東西來。

好,那接下來我們想做的事情是,

我們來看看如果輸入 3 個不同的句子,

在每一層中,

它的每一個位置的 representation

會有什麼樣的變化。

我們執行這段程式以後,

它做的事情就是,

它會把 "how about you?"

這一個句子裡面每一個 token

對應的 representation 把它印出來給你看。

所以丟進去 "how" 以後,

在某一層產生的 representation 長這樣。

這是 "about" 的 representation、

"you" 的 representation、問號的 representation。

這是 "how about you"。

這是 "how are you?"。

這個是 "nice to meet you"。

這邊如果輸入 0,

就代表說我們抽的是第 0 層。

第 0 層這邊其實是 token embedding。

所以這邊我們只要是同樣的 token,

就會有一樣的 representation。

我們來看看是不是一樣的 token,

就有一樣的 token embedding。

所以如果輸入是 "how are you",

那在第 0 層也就是看 token embedding 的時候,

這邊 "you" 你看是,

第一個數字是 0.0060,再來是 0.0238。

這邊 "you" 是 0.0060、0.0238。

這邊 "you" 是 0.0060、0.0238。

所以 token embedding 只要是 "you" 都是一樣的。

再來看第 1 層。

我們來看過了第 1 層。

過了第 1 層。

過了第 1 層以後,

我們再來比較

對應到 "you" 這個 token 的 representation。

"how about you" 的 "you",

它的 representation 是 0.0397、0.0275。

這邊只印整個 representation 的前幾個數字,

其實是 3000 多個,向量很長。

這邊 "how are you" 的 "you",

是 0.024 跟 0.095。

你就發現它變了。

因為為什麼?

因為現在 "how about you" 跟 "how are you" 的 "you",

前面接的 token 是不一樣的。

所以過了第 1 層以後,

它的 embedding 變成 contextualized embedding,

它就會產生不一樣的數字,

它存在向量裡面的數字就不一樣。

但有趣的是你會發現,

"how" 都是一樣的。

這邊是 0.0479、-0.0892。

0.0479、-0.0892。

"how about you" 的 "how" 跟 "how are you" 的 "how",

它過了第 1 層以後 representation 還是一模一樣的。

為什麼?

因為我們考慮上下文的時候,

我只考慮每一個 token 的左邊,

"how" 的左邊沒有東西了。

所以這兩個 "how" 左邊是完全一模一樣的,

所以就沒有差別。

你放幾層都沒有差別。

我們拿到第 10 層。

但每一層之間會不一樣,

就是第 9 層跟第 10 層的 "how" 會不一樣,

但是不同句子 "how about you" 的 "how"

跟 "how are you" 的 "how",

它會是一模一樣。

它們左邊都沒有其他 token,

它們左邊是一模一樣的。

所以不管過幾層抽出來的 "how" 的 representation,

都是一模一樣的。

所以我們就對 representation 做了一些觀察。

好,但這個觀察不出朵花來。

接下來我們來看,

到底模型有沒有辦法判斷,

兩個句子中如果它的 "apple"

根據上下文意思不一樣,

模型有沒有辦法知道說,

它們的 representation 就應該要非常不一樣。

所以我這邊給模型兩個句子,

一個叫做 "I ate an apple for breakfast"。

這邊 "apple" 是一個能吃的東西,

顯然是代表食物的 "apple"。

那這邊我在說,

"the company" 就是做 iPad 跟 AirPod 的公司,

叫做 "apple"。

那這個 "apple" 雖然我沒有大寫,

但我顯然指的是蘋果電腦的 "apple"。

現在我們把這兩個句子都丟到語言模型裡面,

再把對應到 "apple" 的每一層的 representation 都抽出來。

所以第一個句子,

我們會把對應到 "apple" 的 representation 都抽出來。

第二個句子,

我們會把對應到 "apple" 的 representation 通通都抽出來。

然後我們在同一層之間,

兩個不同 "apple" 的 representation

去算它的 cosine similarity,

去算它的相似度,

然後印出來給大家看。

好,那這邊程式的細節,

大家就再自己研究。

總之直接畫一個圖出來。

這個橫軸代表每一層,

第 0 層是那個 embedding,

從第 0 層開始,

一直到第 28 層。

這個 Llama 有 28 層。

那縱軸代表的就是 cosine similarity,

代表兩個 embedding 或兩個 representation 之間的相似度。

第 0 層,

第 0 層是 token embedding。

只要是同一個 token 就是一模一樣的,

所以發現相似度是 1。

cosine similarity 算出來就是 1,

最大就是 1。

然後發現說從第 1 層開始,

兩個 "apple",

因為它們意思不一樣,

所以它們的相似度就越來越低、

越來越低,

然後到第 11 層的時候跌到谷底。

不知道為什麼,

後來又回彈回來。

好,其實在分析這種 representation 的時候,

你可能會覺得回彈回來不合常理,

但是在做 representation 的時候,

其實你要想想看,

每一個 layer 的 representation

它的分佈可能是非常不一樣。

有沒有可能比較後面的 layer,

本質上那些 representation 就比較接近?

因為那些 representation 比較接近的關係,

所以這邊算出來的數值,

在不同 layer 之間比較的時候,

算出來 representation 它的相似度就會比較大。

所以我們應該做一個 normalization,

把平均的相似度

把它除掉。

因為有可能後面這些 layer,

它們不同的 embedding 之間本來就比較像,

本來就會算出比較像的結果。

所以我們應該要把平均的相似度除掉。

所以這邊我又多寫了一段程式,

細節大家再自己研究,

總之多寫了一段程式,

我們去計算這兩個句子中,

兩兩的 token

在每一個 layer 中的相似度,

然後我們會對兩個 "apple" 之間的相似度

除掉平均的相似度,

做一個 normalization。

做完這個 normalization 以後,

你看到這個結果就合理非常多。

我們看最開始的時候在第 0 層,

兩個 embedding 非常的像。

然後從第 1 層開始,

它就知道這兩個 "apple" 應該是不一樣的。

隨著層數越來越多,

它可能這個句子讀得越來越仔細,

它就越來越清楚說,

代表蘋果電腦的 "apple" 跟能吃的 "apple",

根據上下文,

它們其實是不一樣的東西,

所以它們的 representation 越來越不相近。

不過剛才我們是看了一個代表蘋果的 representation

跟代表蘋果電腦的 representation,

它們相似度的變化。

但會不會兩個 "apple" 如果都代表蘋果,

但上下文不一樣,

它們的 representation…

兩個 "apple" 都代表可以吃的蘋果,

但是它們上下文不一樣,

那模型知不知道它們的意思其實是一樣的呢?

我們就來做一個實驗。

這邊總共有 4 個句子。

前 2 個句子它的 "apple" 都是可以吃的 "apple"。

第 1 個句子是 "I ate an apple for breakfast"。

第 2 個句子是 "She baked an apple pie for dessert"。

所以第 1 個句子跟第 2 個句子 "apple" 都是能吃的 "apple"。

第 3 個句子跟第 4 個句子的 "apple"

都指的是一個公司的名稱,都是蘋果電腦的 "apple"。

那接下來呢,

我們總共有 4 個 "apple",

我們兩兩之間拿每一層的 representation 來算相似度,

看看會發生什麼樣的事情。

你就記得說第 1 個句子跟第 2 個句子 "apple" 是可以吃的 "apple",

第 3 個跟第 4 個句子 "apple" 是代表公司名稱的 "apple"。

那我們來看看。

這邊是 4 個不同的 "apple"

兩兩之間算相似度,

在每一層的相似度變化。

那在第 0 層其實都是 1,

因為不管是哪一個 "apple",在第 0 層

它的相似度、

cosine similarity 都是 1。

那你看棕色這一條線,

棕色這一條線,

這兩個 "apple",

它們的相似度不管是哪一層,

始終都非常的高。

這兩個 "apple" 是第 3 句跟第 4 句的 "apple",

它們都代表蘋果電腦。

雖然上下文不一樣,

但是語言模型知道,

這兩個 "apple" 都是指公司的 "apple"。

雖然上下文不一樣,

但它們意思很近,

所以它們的相似度一直維持非常的高。

那這個藍色這條線呢,

藍色這條線是第 1 句話跟第 2 句話的 "apple",

它們指的也都是能吃的 "apple",

意思是一樣的。

所以雖然上下文不一樣,

但相似度始終維持一定的水準。

而那其他的 "apple"

如果兩兩比較你就會發現,

它相似度就有非常顯著的下降。

隨著深度越來越深,

隨著語言模型對於整個句子的理解、

上下文看得越來越多,

這些代表不同意思的 "apple",

它的相似度就越來越低。

語言模型真的知道

哪些 "apple" 意思是一樣的、

哪些 "apple" 意思是不一樣的。

好,那接下來呢,

我們來看一下 Logit Lens。

我們把每一層都透過 LM head

把它解析成一個 token。

我們把每一層通過 LM head,

看看根據這個 LM head

哪一個 token 是機率最高的。

那這邊剖析的方法是這個樣子的。

我們先輸入一段文字,

比如這邊輸入的是「天氣」。

這段文字會變成 token ID,

這個 token ID 會把它丟到模型裡面,

模型會產生輸出。

我們把模型輸出裡面的 hidden representation

把它拿出來。

拿出 hidden representation 以後,

接下來我們把每一層的 hidden representation 拿出來,

丟給 `model.lm_head`。

這句話的意思就是

把 hidden representation 丟給 LM head,

看它輸出的 logit 是什麼。

我們再把輸出的 logit 裡面,

分數最高的那個 token 拿出來,

就可以知道說模型跑過每一層的時候,

它心裡覺得

最有可能的下一個 token 分別是什麼。

好,那我們現在輸入是「天氣」,

那我們就看「天氣」後面該接什麼。

這個第 0 層是 token embedding,

所以第 0 層解出來還是「氣」。

所以本來輸入是「天氣」,

在前面幾個 layer,

模型只是反覆地講最後一個 token,

所以一直「氣、氣、氣、氣、氣、氣、氣」,

好像它很生氣的樣子。

然後接下來突然就變成英文了,

就突然變成 "weather"。

然後 "weather"、"weather"、"weather"、"weather",

然後突然變成 "forecast"。

它突然知道下一個字應該是「預報」,

"weather" 後面可以接 "forecast"。

然後但是最後中文輸出倒是中文,

所以 "forecast" 突然在最後一層變成了「預」,

然後所以「天氣預報」就出現了,

「天氣」後面就可以接「預」。

接個「預」看看接下來它會講什麼。

幫它接個「預」。

好,那「天氣預」後面,

再把最後一個 token 的每一個 layer 拿出來。

「預」,一開始都是「預、預、預、預」,

然後後來把它轉成英文變成 "forecast"。

那有一陣子又變成 "prediction"。

那有一陣子又變成 "forecast"。

然後接下來它突然覺得 "forecast" 後面可以接 "report",

然後再把 "report" 轉成中文,

所以「天氣預」後面它就知道

最後可以接「報」。

但你就會知道說,

欸,這個 Llama 2 它內心深處還是比較喜歡用英文的。

它中間的 representation 變化的時候,

都是英文的變化。

好,最後再試一個例子。

比如說「今天天氣真…」,

「真」怎麼樣呢?

好,「今天天氣真」怎麼樣呢?

一開始都是「真、真、真、真、真」,

然後到某個時間點,

它覺得「真」後面可以接 "beautiful"。

今天天氣很 "beautiful"。

後來覺得可以接 "good",

有時候可以接 "bad"。

然後回去 "beautiful"。

然後最後它覺得應該用中文,

所以天氣到底「真」怎麼樣呢?

它本來有機會講「真不怎麼樣」,

它可能講「真不好」,

但是後來覺得還是講「真好」好了,

所以最後決定接「真好」。

你就會看到這個語言模型的思路,

一路怎麼從輸入一直變到輸出。

所以這個是 Logit Lens。

好,那最後一個部分呢,

是想讓大家看一下,

語言模型的 attention 在做什麼事情。

那這邊怎麼看它的 attention 呢?

一樣要從 model 裡面,

把跟 attention 有關的數值,

比如說 attention weight,

我們說做 attention 的時候,

就是會有兩個 token 之間的相關連的程度,

那這個叫 attention weight。

我們可以把 attention weight 拿出來。

好,那我們得到…

我們給一段文字,

文字轉成 token ID,

然後呢,我們得到一串文字,

然後呢,我們把這串文字

丟給 encoder 得到 token ID,

然後丟給 model。

那這邊需要注意的地方是,

你不只要打 `output_attentions=True`,

你還要指定它 implementation 的方式。

那這邊的 implementation 方式叫做 `eager`。

總之為什麼需要這樣指定呢?

因為有一些算 attention 的方式,

不會把 attention weight 存下來。

所以你要找一個算 attention 的方式,

會把 attention weight 存下來,

這樣我們之後才能夠印出、

才能夠展示這個 attention weight。

好,總之呢,

把未完成的句子丟給 model,

model 得到 output。

我們從 output 裡面,

把 `output.attentions`

把 attention 導出來,

存到 `attentions` 這個變數裡面。

接下來把我們存出來的東西,

把它印出來。

我們來看看得到什麼。

那因為呢,

embedding 那邊就沒有什麼 attention 了,

我們剛才在看那個 representation 的時候,

會包含 token embedding 的部分,

但是因為現在看 attention 的部分,

就跟 token embedding 沒有關係了。

所以我們這邊就只導出了

28 層的東西。

那這邊是從 0 開始算啦,

那就是 Llama 的每一層

都可以看出一個 attention。

那我們從 attention weight 裡面

導出來的數字長什麼樣子呢?

你會發現它有 4 個維度。

1、24、12、12。

這個 1、24、12、12 是什麼意思呢?

1 指的是我們輸入只有一個句子。

但這個我們先不解釋。

24 指的是

有幾個 attention head,

有幾組 attention。

所以 Llama 裡面每一層

其實是有 24 組 attention。

雖然它前面我們只看到

QKV 的向量各只有一個,

但怎麼搞出 24 個 attention weight 呢?

這個大家再自己研究,

總之它就是搞出了 24 組 attention weight。

然後這每一個 attention weight 呢,

都是 12 x 12 的矩陣。

那這個 12 是哪來的呢?

12 是輸入的這個句子的長度。

現在輸入的句子長度是

"the apple is green."

"what color is the apple?"

那這邊總共有 12 個 token,

所以得到的 attention

就是 12 x 12 的矩陣。

它會告诉我們

兩兩 token 之間

在算 attention 的時候,

算出來的 attention weight 有多大。

好,那我們就把

某一個 layer 裡面的

某一組 attention weight 印出來吧。

比如說我們現在選擇

印第 6 層的

第 7 個 attention head。

好,我們來

印第 6 層的第 7 個 attention head,

我們看看我們得到什麼。

我們先把那個

attention 的 weight 印出來,

不過印出來就是一堆數字,

所以你很難看到什麼。

不過我們把它直接畫圖,

用圖像的方式把它呈現出來。

所以第 6 層的第 7 個 head

到底發生了什麼事呢?

這個圖要怎麼看呢?

這個圖就是

橫軸是現在要考慮

跟其他人去算 attention 的 token。

那你會發現,

幾乎每一個人

都是跟第 1 個、

代表句子起始的 token

有最大的 attention weight。

但是有一個例外,

就是 "apple"。

這邊有一個句點,

這個句點你不要太在意,

這個就是代表那個空白,

句子起始

token 前面的空白的意思。

然後這個 "apple",

這個 token 在這整個句子裡面,

"the apple is green."

"what color is the apple?"

"apple" 這個 token,

如果這個語言模型

在考慮它的意思的時候,

它覺得哪一些詞彙

會影響 token 的意思呢?

"apple" 跟其他 token 的 attention weight,

哪一些 token 的 attention weight 最大呢?

除了第 1 個 token 之外,

它跟 "green" 的 attention weight

是有一些的。

所以代表這一組

第 6 層的第 7 組 attention,

它知道說

如果要考慮 "apple" 的意思的話,

要到句子前面找這個顏色,

這個 "green" 影響了 "apple" 的性質,

影響了 "apple" 的 representation

接下來應該長什麼樣子。

好,那你可以試試別的數字,

比如說 6,我們試個 5,

看看我們應該看到什麼。

你會發現右上部都是 0。

為什麼右上部都是 0 呢?

右上部都深色、深藍色,

就代表它是 0。

因為我們是 causal attention,

所以每一個 token 都不會

算它右邊的 token 的 attention,

都只會算它左邊的 token 的 attention。

所以這個矩陣,

這個 attention 的 weight

把它用一個矩陣呈現出來,

右上角就都是 0。

然後這邊看不出什麼東西。

試個 4。

再換一個 attention weight 看看。

這個看起來稍微比較複雜。

感覺在看到 "color" 的時候,

模型會覺得前面的 "green"

會影響 "color" 的意思。

"is" 呢?

"is" 它會看前面的句點。

"the" 也會看前面的句點。

問號也會看前面的句點。

attention 其實通常

你蠻難分析出它在幹什麼的,

它的行為往往蠻無厘頭的。

我們來看這個第 4 個 attention,

發現 "color" 要 attend 到 "green"。

這個 "color" 跟 "green" 是非常有關係的,

所以這個是非常合理的。

然後像第 2 個 "apple",

會 attend 到前面那個 "apple",

前面那個 "apple" 的意思

會影響後面那個 "apple" 的意思,

這個也是一個還可以勉強解釋一下的 attention。

我們其實可以把所有的 attention weight 都印出來。

我們這邊就跑一個迴圈,

把所有的 layer 裡面所有的 attention weight

一次都把它全部印出來。

這個跑起來就會花一點時間,

等一下你就會看到一堆小圖,

每一個小圖都是一組 attention weight。

畫完了,這個圖很小啊。

這個圖很小啊。

這個放大看一下嗎?

放大看一下。

這邊就從第 1 層、第 2 層、第 3 層

一直排到第 28 層。

然後每一層都有 24 個 attention,

每一個 attention 有一組 attention weight,

所以從第 1 組、第 2 組一直到第 24 組。

你會發現每一個 attention、

每一個人都做不同的事情。

很多 attention 都做滿類似的事情,

都是看前幾個 token。

你有很多 attention

你就是搞不清楚它在做什麼。

每一個 attention 都找一點自己的事情來做。

剛才是看 Llama,

我們把 Llama 換成 Gemma,

其實可以的。

改一行程式就好了。

我們來改一下。

剛才是看 Llama,

我們來換成 Gemma 吧。

你唯一要做的,

就是把 model 換成 model2

把 Gemma 所有的 attention 印出來,

這花一點時間。

剛才你可能發現說,

這個在做 attention 的時候,

好像模型特別喜歡 attend 到

起始的那個符號。

所以那是什麼意思呢?

其實你甚至可以找到一篇論文直接討論這個問題。

這個起始的符號代表

「我沒什麼好看的」。

因為你想想看,

我們今天在做 attention 的時候,

不是會有一個 softmax 嗎?

你等於強迫說,

假設今天沒有任何 token

跟現在你要考慮的那個 token

attention 算起來是大的,

過了 softmax 以後,

反而每個人都算出來數值會變成蠻大的。

你等於強迫說,

假設今天整個句子裡面

根本沒有相關的 token,

模型還是得考慮某一些 token

就是要有關係。

所以起始那個符號,

就變成一個 default 的符號。

如果今天這一組 attention,

假設有一組 attention 就是關注

現在我們考慮的這個 token

有多少個…

它考慮數量,

整個句子裡面都沒有跟數量有關的東西,

那怎麼辦?

就去 attend 到那個起始的符號。

那個起始的符號就代表

「我沒什麼好 attend 的」意思。

所以你會發現說,

今天這個是

不同語言模型幾乎都有這個行為。

Gemma、Llama 都有這個行為。

你會發現,

很多時候一個 attention 沒什麼好做的,

它就 attend 在起始的符號上。

這個是 Gemma 的 attention。

這個很多啊。

有幾層呢?

有從第 1 層開始,

這是每一層的 attention,

每一層的 attention。

它每一層就是

8 個 attention,

它 attention 比較少。

它每一層是

8 個 attention head。

然後

從第 1 層開始

一直到…

哇,這很多很多,

一直到第 34 層。

每個 attention 做的事情都不太一樣,

每一層的 attention 都做不一樣的事情。

好。

那這邊就是跟大家

剖析了這個 Gemma 跟 Llama 內部的運作的過程。

Loading...

Loading video analysis...