隨著人工智能技術(shù)的飛速發(fā)展,大型語言模型(LLMs)已成為深度學(xué)習(xí)領(lǐng)域的前沿技術(shù),推動了自然語言處理(NLP)向更高水平的發(fā)展。從了解人工智能的未來,深入淺出地理解“Embedding”,到初識Transformer架構(gòu),我們逐步揭開了大型語言模型的神秘面紗。今天,我們將進入一個至關(guān)重要的環(huán)節(jié)——數(shù)據(jù)準(zhǔn)備,這一步驟是構(gòu)建高效、功能強大的語言模型不可或缺的基石。
在本篇文章中,我們?yōu)槔斫獯笳Z言模型(LLMs)奠定了基礎(chǔ)。在本系列的剩余部分中,我們將從零開始編碼一個LLM。我們將采用GPT背后的基本理念作為藍圖,并按照下圖中概述的三個階段來解決這個問題。
上圖涵蓋的構(gòu)建大語言模型(LLMs)的階段包括實現(xiàn)大語言模型架構(gòu)和數(shù)據(jù)準(zhǔn)備過程,預(yù)訓(xùn)練一個大語言模型以創(chuàng)建一個基礎(chǔ)模型,以及微調(diào)這個基礎(chǔ)模型,使其成為個人助理或文本分類器。
在預(yù)訓(xùn)練階段,LLMs 逐字處理文本。通過對擁有從百萬到十億數(shù)量級參數(shù)的LLMs進行下一個詞預(yù)測的訓(xùn)練任務(wù),可以培養(yǎng)出具備卓越能力的模型。這些模型隨后可以針對特定目標(biāo)任務(wù)進行進一步的微調(diào),以便執(zhí)行一般性指令或處理特定任務(wù)。但是,在我們即將在后續(xù)篇章中部署和訓(xùn)練 LLMs 之前,我們首先需要準(zhǔn)備好訓(xùn)練數(shù)據(jù)集,這正是本文的討論重點。
你將掌握如何為訓(xùn)練大型語言模型(Large Language Models, LLMs)準(zhǔn)備輸入文本。這個過程涉及到把文本拆分為單詞和子詞級別的令牌,進而將這些令牌轉(zhuǎn)換成 LLMs 可以理解的向量形式。你還將了解到像字節(jié)對編碼(Byte Pair Encoding)這樣的高級分詞技術(shù),它在GPT 等知名 LLMs 中得到廣泛應(yīng)用。最終,我們將介紹一種抽樣和數(shù)據(jù)加載的策略,用于生成在隨后章節(jié)中訓(xùn)練 LLMs 所需的輸入和輸出配對數(shù)據(jù)。
進一步理解 Embedding
包括大語言模型(LLMs)在內(nèi)的所有深度神經(jīng)網(wǎng)絡(luò)模型無法直接處理原始文本數(shù)據(jù)。這是因為文本本質(zhì)上屬于分類數(shù)據(jù)類型,與神經(jīng)網(wǎng)絡(luò)實施和訓(xùn)練所需的數(shù)學(xué)運算不相兼容。因此,我們必須找到一種方式,以將單詞轉(zhuǎn)化為連續(xù)數(shù)值向量的形式來表示。
數(shù)據(jù)轉(zhuǎn)化為向量格式的過程,通常被稱作“Embedding”。在《大型模型語言入門:深入淺出地理解“Embedding”》中有介紹過相關(guān)概念,通過利用特定的神經(jīng)網(wǎng)絡(luò)層或預(yù)先訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)模型,我們能夠?qū)崿F(xiàn)將各種類型的數(shù)據(jù)——如視頻、音頻及文本——轉(zhuǎn)換為向量格式,正如下圖所示。這不僅使得深度學(xué)習(xí)模型能夠理解和處理這些信息,也為各類數(shù)據(jù)提供了一種統(tǒng)一且高效的表示方式。
本質(zhì)上,嵌入技術(shù)是將如單詞、圖像甚至整篇文檔等離散對象映射到連續(xù)向量空間中點的過程。其主要目的是把那些原本無法直接被神經(jīng)網(wǎng)絡(luò)處理的非數(shù)值數(shù)據(jù)轉(zhuǎn)換成可處理的格式。
盡管詞嵌入是文本嵌入中最常見的類型,但對于句子、段落或整個文檔的嵌入也同樣存在。對于那些結(jié)合了文本生成和檢索外部知識以豐富內(nèi)容的檢索增強生成技術(shù)來說,句子或段落嵌入(Embedding)尤為重要。考慮到我們旨在訓(xùn)練能夠逐詞生成文本的 GPT 風(fēng)格的大型語言模型,我們將重點討論詞嵌入的概念和應(yīng)用。
為了生成這些詞嵌入,研究人員開發(fā)了多種算法和框架。Word2Vec是其中最早和最知名的方法之一,它通過預(yù)測詞的上下文或從上下文預(yù)測詞來訓(xùn)練神經(jīng)網(wǎng)絡(luò)生成詞嵌入(Word Embedding)。Word2Vec的核心思想是:在相似上下文中出現(xiàn)的詞意義也相近。因此,當(dāng)我們將這些詞嵌入為了可視化目的而投影到二維空間時,可以看到意義相近的詞會聚集在一起,正如下圖所示。
在上圖這個向量空間里,各種鳥類相較于國家和城市的詞向量,彼此的距離更近,直觀展現(xiàn)了它們概念上的相似性。這種特性使得我們能夠通過詞嵌入技術(shù)探索和理解詞語之間的語義聯(lián)系。
詞嵌入的維度范圍廣泛,從一維到數(shù)千維都有。正如上圖展示的那樣,我們?yōu)榱丝梢暬康?,可以選擇二維詞嵌入(Word Embedding)。雖然較高的維度能揭示更微妙的詞義關(guān)系,但這同時也會增加計算的復(fù)雜度和成本。
盡管我們可以借助 Word2Vec 這類預(yù)訓(xùn)練模型來生成機器學(xué)習(xí)模型所需的詞嵌入,大型語言模型(LLMs)卻通常生成它們自身的嵌入,這些嵌入作為輸入層的一部分,并在訓(xùn)練過程中得到更新。與使用 Word2Vec 相比,直接在LLM訓(xùn)練過程中優(yōu)化嵌入的優(yōu)點在于,這些嵌入能夠針對當(dāng)前任務(wù)和數(shù)據(jù)進行特定優(yōu)化。后續(xù)部分會介紹如何實現(xiàn)這樣的嵌入層。進一步地,在未來的篇章中我們還將探討 LLMs 如何創(chuàng)建能夠體現(xiàn)上下文信息的輸出嵌入。
不幸的是,高維嵌入對于可視化來說是一個挑戰(zhàn),因為我們的感官感知和常見的圖形表示本質(zhì)上限于三維或更少維度,這就是為什么上圖展示了二維嵌入在一個二維散點圖中的原因。然而,在處理大型語言模型(LLMs)時,我們通常使用的嵌入維度遠高于上圖所示的維度。對于 GPT-2 和 GPT-3,嵌入大?。ㄍǔV改P碗[藏狀態(tài)的維度)基于特定的模型變體和大小而變化。這是性能和效率之間的權(quán)衡。最小的 GPT-2(117M參數(shù))和 GPT-2(125M參數(shù))模型使用 768 維度。最大的GPT-3模型(175B參數(shù))使用 12,288 維度。
接下來的部分將介紹為LLM準(zhǔn)備嵌入所需的步驟,包括將文本拆分成單詞,將單詞轉(zhuǎn)換成令牌,以及將令牌轉(zhuǎn)換成嵌入向量。
Tokenizing Text(文本分詞處理)
本節(jié)將探討我們?nèi)绾螌⑤斎氲奈谋炯?xì)分為單個令牌,這是為LLM生成嵌入前必須進行的預(yù)處理步驟。這些令牌可能是獨立的單詞或者特殊字符,包括各種標(biāo)點符號(如下圖)。通過這一過程,我們能夠確保文本以一種結(jié)構(gòu)化的形式被模型理解和處理,為后續(xù)的嵌入生成奠定基礎(chǔ)。
在本節(jié)中,我們將展示如何在大型語言模型(LLM)處理文本的上下文中進行文本處理的各個步驟。具體來說,我們會將輸入的文本細(xì)分為單獨的令牌,這包括單詞及特殊字符,例如標(biāo)點符號。隨后的章節(jié)將詳細(xì)介紹如何將這些文本轉(zhuǎn)換為令牌 ID,以及如何基于這些 ID 創(chuàng)建對應(yīng)的令牌嵌入。這一系列步驟是理解和實現(xiàn) LLM 的基礎(chǔ),不僅涵蓋了數(shù)據(jù)預(yù)處理的重要環(huán)節(jié),也為后續(xù)模型的訓(xùn)練和應(yīng)用奠定了基礎(chǔ)。
我們用于 LLM 訓(xùn)練分詞的文本是一篇由埃迪斯·華頓所著的短篇故事《The Verdict》,這篇故事已經(jīng)公開發(fā)布,因此允許用于 LLM 訓(xùn)練任務(wù)。
// Listing 2.1 Reading in a short story as text sample into Python
with open('the-verdict.txt', 'r', encoding='utf-8') as f:
raw_text = f.read()
print('Total number of character:', len(raw_text))
print(raw_text[:99])可以在 GitHub 倉庫中找到'the-verdict.txt'文件,上述 print命令用于打印文件的總字符數(shù),隨后為了示例目的,打印該文件的前100個字符:
Total number of character: 20479
I HAD always thought Jack Gisburn rather a cheap genius--though a good fellow enough--so it was no 我們的目標(biāo)是將這篇包含 20,479 個字符的短篇故事分詞成單獨的單詞和特殊字符,以便在接下來的篇章中將其轉(zhuǎn)換成 Embedding,用于 LLM 的訓(xùn)練。
文本樣本大?。?/p>
注意,在處理大型語言模型(LLM)時,處理數(shù)百萬篇文章和數(shù)十萬本書——許多千兆字節(jié)的文本是很常見的。然而,出于教育目的,使用較小的文本樣本,如一本書,就足以說明文本處理步驟背后的主要思想,并使其能夠在合理的時間內(nèi)在消費者硬件上運行。
如何能夠最有效地將一段文本分割成一個個的詞元(Token)呢?為了解釋這個過程,我們會簡單介紹一下如何利用Python中的正則表達式庫(re)來實現(xiàn)這一目標(biāo)。(不過別擔(dān)心,你無需專門去學(xué)習(xí)或記憶正則表達式的具體語法,因為我們在本章后面會介紹一種更加簡便的預(yù)制分詞工具。)
舉個簡單的例子,我們可以使用 re.split 命令和特定的語法規(guī)則,來根據(jù)空白字符將文本分割開:
import re
text = 'Hello, world. This, is a test.'
result = re.split(r'(\s)', text)
print(result)得到的結(jié)果是一個列表,包括了獨立的單詞、空格以及標(biāo)點符號:這樣,文本就被我們細(xì)致地拆分開來,每個元素都清晰地展現(xiàn)出來。
['Hello,', ' ', 'world.', ' ', 'This,', ' ', 'is', ' ', 'a', ' ', 'test.']注意到,雖然上述簡單的分詞方法在很大程度上可以實現(xiàn)將文本拆分成獨立單詞的目的,但某些單詞依舊和標(biāo)點符號粘連在一起,這不是我們想要的結(jié)果。我們期望標(biāo)點符號也能作為獨立的元素出現(xiàn)在列表中。
為了達到這一目的,我們需要調(diào)整我們的正則表達式規(guī)則,使其不僅僅是在空格(這里指的是所有的空白字符,如空格、制表符等,用 \s 表示)上分割,還要在逗號和句點(即,和.,使用[,.]來匹配)上分割,這樣可以更準(zhǔn)確地將文本中的單詞和標(biāo)點符號分離開來:
result = re.split(r'([,.]|\s)', text)
print(result)現(xiàn)在,我們可以觀察到,單詞與標(biāo)點符號正如我們所期望的那樣,被成功分割成了獨立的列表元素。這意味著每一個單詞和標(biāo)點都能被單獨識別和處理,這對于文本分析和處理來說是非常重要的一步。
['Hello', ',', '', ' ', 'world.', ' ', 'This', ',', '', ' ', 'is', ' ', 'a', ' ', 'test.']盡管我們已經(jīng)成功地將單詞和標(biāo)點符號分開,但列表中還殘留了一些不必要的空白字符。如果需要,我們可以通過一些簡單的步驟來清理這些字符,確保列表中只包含有實際意義的元素,下面就是實現(xiàn)這一目的的方法:
result = [item.strip() for item in result if item.strip()]
print(result)經(jīng)過去除空白字符的處理,我們得到了一個更加整潔的輸出,現(xiàn)在的列表僅包含有實際意義的單詞和標(biāo)點符號,沒有任何多余的空白。這樣的輸出更適合后續(xù)的文本處理和分析工作。
['Hello', ',', 'world.', 'This', ',', 'is', 'a', 'test.']是否移除空格字符
在我們構(gòu)建一個簡單的分詞器過程中,關(guān)于是否將空格字符當(dāng)作獨立的元素處理或是直接去除它們,這個決定需要根據(jù)我們的應(yīng)用場景和具體需求來定。去除空格字符能夠幫助我們節(jié)省內(nèi)存使用量和計算資源。但是,在一些特定場景下,比如我們訓(xùn)練的模型需要對文本的具體格式(如Python代碼中對縮進和空格的敏感性)有精確的識別能力時,保留空格就顯得尤為重要。在這里,為了讓分詞結(jié)果更加簡潔明了,我們選擇去除空格。不過,在后續(xù)的過程中,我們將采用一個能夠識別空格的分詞策略。
我們之前設(shè)計的分詞策略已經(jīng)能夠很好地處理簡單的文本樣本了。現(xiàn)在,讓我們對它進行一些調(diào)整,使其能夠識別和處理更多種類的標(biāo)點符號,包括問號、引號,以及我們在埃迪斯·華頓(Edith Wharton)的短篇故事開頭 100 個字符中見到的雙破折號等,同時還包括其他一些特殊字符。這樣的改進將使我們的分詞器更加全面,能夠應(yīng)對更復(fù)雜的文本場景。
text = 'Hello, world. Is this-- a test?'
result = re.split(r'([,.?_!'()\']|--|\s)', text)
result = [item.strip() for item in result if item.strip()]
print(result)現(xiàn)在,我們得到的輸出結(jié)果如下所示:
['Hello', ',', 'world', '.', 'Is', 'this', '--', 'a', 'test', '?']從下圖中的結(jié)果概覽可以看出,我們調(diào)整后的分詞策略現(xiàn)在能夠成功識別和分割文本中的各種特殊字符了。這意味著無論是標(biāo)點符號、引號還是其他特殊格式的字符,我們的分詞工具都能夠準(zhǔn)確地將它們從文本中分離出來,為后續(xù)的文本分析和處理提供了更為精確和全面的數(shù)據(jù)基礎(chǔ)。
現(xiàn)在我們已經(jīng)成功開發(fā)出一個基本的文本分詞工具,接下來,讓我們嘗試將這個工具運用到埃迪斯·華頓(Edith Wharton)的完整短篇故事中。通過這個實踐,我們不僅可以檢驗分詞工具的實際效果,還能深入理解如何處理和分析更長篇幅的文本內(nèi)容。
preprocessed = re.split(r'([,.?_!'()\']|--|\s)', raw_text)
preprocessed = [item.strip() for item in preprocessed if item.strip()]
print(len(preprocessed))上述打印操作顯示,該文本共包含4649個詞元(Token),這一統(tǒng)計不包括任何空白字符。接下來,為了直觀地了解分詞結(jié)果,我們將展示文本開頭的前30個詞元:
print(preprocessed[:30])結(jié)果表明,我們的分詞工具表現(xiàn)出色,能夠有效地將文本中的單詞和特殊字符分離開。每一個元素都被準(zhǔn)確地識別并獨立出來,這為進一步的文本分析和處理打下了良好的基礎(chǔ)。
['I', 'HAD', 'always', 'thought', 'Jack', 'Gisburn', 'rather', 'a', 'cheap', 'genius', '--', 'though', 'a', 'good', 'fellow', 'enough', '--', 'so', 'it', 'was', 'no', 'great', 'surprise', 'to', 'me', 'to', 'hear', 'that', ',', 'in']在本篇的分享中,我們已經(jīng)涉及了文本處理的基礎(chǔ)步驟,為構(gòu)建高效的大型語言模型打下了堅實的基礎(chǔ)。但我們的探索之旅遠未結(jié)束,更多深入和高級的技術(shù)等待著我們在接下來的系列文章中探討。
接下來,在《構(gòu)建大模型之?dāng)?shù)據(jù)準(zhǔn)備(中)》和《構(gòu)建大模型之?dāng)?shù)據(jù)準(zhǔn)備(下)》中,我們將進一步深化我們的知識,包括如何更有效地處理和準(zhǔn)備數(shù)據(jù),以提升大型模型的性能。具體來說,我們將討論:
- 轉(zhuǎn)換令牌為唯一標(biāo)識符:理解令牌如何被轉(zhuǎn)換為模型可以理解的數(shù)字標(biāo)識符,這是理解文本的第一步。
- 引入特定場景的特殊令牌:如何使用特殊令牌來增強模型對特定上下文的理解能力。
- 字節(jié)對編碼(BPE)技術(shù):一種高效的編碼方法,可減少模型的復(fù)雜性同時保留語義信息。
- 利用滑動窗口技術(shù)進行數(shù)據(jù)樣本提?。阂环N處理長文本的技術(shù),確保模型能夠有效學(xué)習(xí)。
- 構(gòu)建令牌的嵌入表示:如何將令牌轉(zhuǎn)換為密集的向量,以捕捉更深層的語義關(guān)系。
- 對單詞在文本中的位置進行編碼:理解模型如何識別文本中詞匯的相對和絕對位置。
希望你能在接下來的文章中繼續(xù)與我們同行,深入探索大型模型的構(gòu)建過程。如果你對這些內(nèi)容感興趣,記得點贊、關(guān)注并收藏,這樣你就不會錯過我們的最新分享。感謝你的閱讀,期待在后續(xù)文章中再次與你相遇!



