- 多模態大模型:算法、應用與微調
- 劉兆峰
- 2761字
- 2024-09-11 17:37:21
1.1.1 分詞器
在正式介紹Seq2Seq結構的模型之前,我們需要先了解“分詞器”。人類之間的有效溝通完全依賴自然語言,這種語言包含無數復雜的詞匯,而這些詞匯對計算機而言卻是完全陌生的。計算機是無法直接處理一個單詞或者一個漢字的,因此在進行模型訓練前,需要把人類能夠理解的元素轉化成計算機可以計算的向量。分詞器正是為模型準備輸入內容的,它可以將語料數據集預處理為模型可以接收的輸入格式。對于文本格式的數據來說,分詞器的作用就是將文本轉換為詞元序列,一個詞元可以是一個字母、一個單詞、一個標點符號或者一個其他符號,而這個過程也被稱為分詞(tokenization)。
1.什么是分詞
詞元(token)可以理解為最小的語義單元,分詞的目的是將輸入文本轉換為一系列的詞元,并且還要保證每個詞元擁有相對完整的獨立語義。舉個簡單的例子,比如“Hello World!”這句話,可以將其分為4個詞元,即["Hello", " ", "World", "!"],然后把每個詞元轉換成一個數字,后續我們就用這個數字來表示這個詞元,這個數字就被稱為詞元ID,也叫token ID。例如,我們可以用表1-1來表示上面那句話的詞元以及對應的ID,而最終“Hello World!”這句話就可以轉換為“1 2 3 4”的數字序列。
表1-1 “Hello World!”的分詞示例

那么,分詞應該分到什么粒度呢?對于英文來說,分詞的粒度從細到粗依次是character、subword、word。其中character表示的是單個字符,例如a、b、c、d。而word表示的是整個單詞,例如water表示水的意思。而subword相當于英文中的詞根、前綴、后綴等,例如unfortunately中的un、fortun(e)、ly等就是subword,它們都是有含義的。
對于中文來說,分詞算法也經歷了按詞語分、按字分和按子詞分三個階段。按詞語分和按字分比較好理解,也有一些工具包可以使用,例如jieba分詞。如果是按照子詞分,那么詞元就可以是偏旁部首,當然對于比較簡單的字,一個詞元也可以是一個完整的字。例如,“江”“河”“湖”“海”這四個字都跟水有關,并且它們都是三點水旁,那么在分詞的時候,“氵”很可能會作為一個詞元,“工”“可”“胡”“每”是另外的詞元。假如“氵”的詞元ID為1,“工”“可”“胡”“每”的詞元ID分別是2、3、4、5,那么“江”“河”“湖”“海”的詞元序列就可以表示為1 2、13、1 4、1 5。這樣做的好處是,只要字中帶有三點水旁,或者詞元序列中含有詞元ID為1的元素,那么我們就可以認為這個字或者這個詞元序列跟水有關。即使是沙漠的“沙”字,是由“氵”和“少”組成的,也可以理解為水很少的地方。
2.BPE分詞算法
使用單個字母或單詞作為詞元會帶來一些問題。首先,不同語言的詞匯量不同,如果每個單詞都需要分配唯一的詞元ID,那么會占用大量內存空間。其次,一些單詞可能很少出現或是新造詞,如專有名詞、縮寫、網絡用語等,如果要讓模型一直能夠處理這些單詞,就需要不斷更新詞元ID表格并重新訓練模型。
為了解決這些問題,GPT模型使用了BPE(Byte Pair Encoding,字節對編碼)方法來分割文本。BPE是一種數據壓縮技術,將文本分割為更小的子單元(subword),它們可以是單個字母、字母組合、部分單詞或完整單詞。BPE基于統計頻率合并最常見的字母對或子單元對,這種方法能夠更有效地處理不同語言的詞匯量和新出現的單詞。
接下來我們舉一個例子來介紹BPE分詞算法。首先我們需要知道,基于子詞的分詞算法有一個基本原則:常用字詞盡量表示為單個詞元,罕見詞分解為多個詞元。如果我們有一個語料庫,要從頭開始通過分詞構建詞表,首先要統計所有語料的詞頻,也就是計算每個單詞在語料庫中出現的頻率,假如得到如下結果:{"class</w>": 1, "classified</w>": 2, "classification</w>": 3, "create</w>": 4, "created</w>": 5, "creation</w>": 6}。其中“</w>”是為了讓算法知道每個單詞的結束位置而在末尾添加的一個特殊符號。接下來將每個單詞拆分成字符并再次統計其出現次數,特殊符號也被看作一個字符,可以得到如表1-2所示的詞元頻次表。
表1-2 詞元頻次表1

接下來我們要尋找出現得最頻繁的字符對,然后進行合并操作。我們從出現次數最多的字符開始,即“e”。通過計數可以發現,“ea”出現的次數最多,出現了4+5+6=15次,因此我們將“e”和“a”合并為“ea”,之后更新詞元頻次表,得到表1-3。
表1-3 詞元頻次表2

繼續合并,此時出現次數最多的是字符“c”,可以發現合并字符“cr”出現的次數最多,因此將這兩個字符合并,更新詞元頻率表,得到表1-4。
表1-4 詞元頻次表3

再進一步合并,就能發現BPE編碼的奇妙之處。接下來我們將“cr”和“ea”合并為“crea”,并且刪除表中出現次數為0的詞元,更新詞元頻次表,得到表1-5。
表1-5 詞元頻次表4

一直重復以上步驟,單個詞元會被逐漸合并,這也是BPE算法的主要目標——數據壓縮。我們可以在開始時設置一個閾值,每次更新后詞元的總數可能會發生變化,當詞元總數達到設定的閾值之后,就停止合并,此時的詞元頻次表中所有的詞元就是我們最終要用的詞表。
可以發現,當我們合并詞元并更新詞表的時候,總的詞元數可能增加,可能減少,也可能保持不變。一般來說,當迭代次數較小時,大部分詞元還是字母,基本上沒有什么實質含義,但是當迭代次數增大時,常用詞開始慢慢合并到一起。如圖1-2所示,這是我們在一次實驗中統計的詞元總數的變化,通常來說,隨著合并次數的增加,詞元總數是先增大后減小的,最終停止變化的條件就是達到我們設置的詞元總數的閾值,因此,合適的停止標準是需要調整的一個參數。

圖1-2 BPE分詞算法的詞元總數隨著迭代次數的增大而先增大后減小
詞表建立了一個從詞元到ID的對應關系。在模型處理輸入時,將輸入序列中的每一個元素的詞元都映射為ID,然后根據ID找到詞元對應的特征向量。模型最終的輸出結果也是詞元ID,再根據對應關系,將ID映射為詞元進行輸出。
BPE在分詞時具有一些顯著的優勢。首先,BPE能夠通過減少詞元的數量,節省內存以及計算資源。其次,BPE能有效地處理未遇見或罕見的詞匯,它會將這些詞匯分解為已知的子單元。此外,它能捕獲詞語的形態變化,例如復數、時態和派生形式,這使模型能夠學習詞語之間的關聯。然而,BPE也有一些缺點。例如,BPE可能會分割一些有語義意義的子單元,使完整的詞匯被拆分為多個部分。再者,BPE可能會影響對特定符號或標記的處理,如HTML標簽、URL、電子郵件地址等,這可能導致原始含義或格式的喪失。因此,BPE并不是一種完美無缺的方法,而是一種在減少詞元數量與保留詞元含義之間達成平衡的折中策略。
BPE是一種比較常用的分詞算法,GPT-2、BART和Llama模型都采用了BPE分詞算法。除此之外,還有其他一些分詞算法。WordPiece的核心思想與BPE分詞算法類似,但在子詞合并的選擇上并不是直接選擇出現頻率最高的相鄰子詞合并,而是選擇能夠提升語言模型概率的相鄰子詞進行合并。BERT模型采用的就是WordPiece算法。SentencePiece是另外一種分詞算法,它將空格視作一種特殊字符進行處理,然后再用BPE算法來進行分詞。ChatGLM、BLOOM和PaLM模型采用了SentencePiece分詞算法。
另外,在數據集的處理過程中,加入StartToken、PadToken、EndToken等詞元,可以幫助模型更好地理解數據,或者幫助下游應用進行編碼。以Vicuna模型為例,將對話結束標記</s>加入微調數據集中,能使模型更有效地預測何時停止生成字符。