干貨滿(mǎn)滿(mǎn)!大神Karpathy兩小時(shí)AI大課文字版第一彈,全新工作流自動(dòng)把視頻轉(zhuǎn)成文章
前段時(shí)間,AI大神Karpathy上線(xiàn)的AI大課,已經(jīng)收獲了全網(wǎng)15萬(wàn)次播放量。
當(dāng)時(shí)還有網(wǎng)友表示,這2小時(shí)課程的含金量,相當(dāng)于大學(xué)4年。
就在這幾天,Karpathy又萌生了一個(gè)新的想法:
那便是,將2小時(shí)13分鐘的「從頭開(kāi)始構(gòu)建GPT分詞器」的視頻,轉(zhuǎn)換為一本書(shū)的章節(jié)(或者博客文章)形式,專(zhuān)門(mén)討論「分詞」。
具體步驟如下:
- 為視頻添加字幕或解說(shuō)文字。
- 將視頻切割成若干帶有配套圖片和文字的段落。
- 利用大語(yǔ)言模型的提示工程技術(shù),逐段進(jìn)行翻譯。
- 將結(jié)果輸出為網(wǎng)頁(yè)形式,其中包含指向原始視頻各部分的鏈接。
更廣泛地說(shuō),這樣的工作流程可以應(yīng)用于任何視頻輸入,自動(dòng)生成各種教程的「配套指南」,使其格式更加便于閱讀、瀏覽和搜索。
這聽(tīng)起來(lái)是可行的,但也頗具挑戰(zhàn)。
他在GitHub項(xiàng)目minbpe下,寫(xiě)了一個(gè)例子來(lái)闡述自己的想象。
地址:https://github.com/karpathy/minbpe/blob/master/lecture.md
Karpathy表示,這是自己手動(dòng)完成的任務(wù),即觀看視頻并將其翻譯成markdown格式的文章。
「我只看了大約4分鐘的視頻(即完成了3%),而這已經(jīng)用了大約30分鐘來(lái)寫(xiě),所以如果能自動(dòng)完成這樣的工作就太好了」。
接下來(lái),就是上課時(shí)間了!
「LLM分詞」課程文字版
大家好,今天我們將探討LLM中的「分詞」問(wèn)題。
遺憾的是,「分詞」是目前最領(lǐng)先的大模型中,一個(gè)相對(duì)復(fù)雜和棘手的組成部分,但我們有必要對(duì)其進(jìn)行詳細(xì)了解。
因?yàn)長(zhǎng)LM的許多缺陷可能歸咎于神經(jīng)網(wǎng)絡(luò),或其他看似神秘的因素,而這些缺陷實(shí)際上都可以追溯到「分詞」。
字符級(jí)分詞
那么,什么是分詞呢?
事實(shí)上,在之前的視頻《讓我們從零開(kāi)始構(gòu)建 GPT》中,我已經(jīng)介紹過(guò)分詞,但那只是一個(gè)非常簡(jiǎn)單的字符級(jí)版本。
如果你去Google colab查看那個(gè)視頻,你會(huì)發(fā)現(xiàn)我們從訓(xùn)練數(shù)據(jù)(莎士比亞)開(kāi)始,它只是Python中的一個(gè)大字符串:
First Citizen: Before we proceed any further, hear me speak.
All: Speak, speak.
First Citizen: You are all resolved rather to die than to famish?
All: Resolved. resolved.
First Citizen: First, you know Caius Marcius is chief enemy to the people.
All: We know't, we know't.
但是,我們?nèi)绾螌⒆址斎隠LM呢?
我們可以看到,我們首先要為整個(gè)訓(xùn)練集中的所有可能字符,構(gòu)建一個(gè)詞匯表:
# here are all the unique characters that occur in this text
chars = sorted(list(set(text)))
vocab_size = len(chars)
print(''.join(chars))
print(vocab_size)
# !$&',-.3:;?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
# 65
然后根據(jù)上面的詞匯表,創(chuàng)建用于在單個(gè)字符和整數(shù)之間進(jìn)行轉(zhuǎn)換的查找表。此查找表只是一個(gè)Python字典:
stoi = { ch:i for i,ch in enumerate(chars) }
itos = { i:ch for i,ch in enumerate(chars) }
# encoder: take a string, output a list of integers
encode = lambda s: [stoi[c] for c in s]
# decoder: take a list of integers, output a string
decode = lambda l: ''.join([itos[i] for i in l])
print(encode("hii there"))
print(decode(encode("hii there")))
# [46, 47, 47, 1, 58, 46, 43, 56, 43]
# hii there
一旦我們將一個(gè)字符串轉(zhuǎn)換成一個(gè)整數(shù)序列,我們就會(huì)看到每個(gè)整數(shù),都被用作可訓(xùn)練參數(shù)的二維嵌入的索引。
因?yàn)槲覀兊脑~匯表大小為 vocab_size=65 ,所以該嵌入表也將有65行:
class BigramLanguageModel(nn.Module):
def __init__(self, vocab_size):
super().__init__()
self.token_embedding_table = nn.Embedding(vocab_size, n_embd)
def forward(self, idx, targets=None):
tok_emb = self.token_embedding_table(idx) # (B,T,C)
在這里,整數(shù)從嵌入表中「提取」出一行,這一行就是代表該分詞的向量。然后,該向量將作為相應(yīng)時(shí)間步長(zhǎng)的輸入輸入到Transformer。
使用BPE算法進(jìn)行「字符塊」分詞
對(duì)于「字符級(jí)」語(yǔ)言模型的天真設(shè)置來(lái)說(shuō),這一切都很好。
但在實(shí)踐中,在最先進(jìn)的語(yǔ)言模型中,人們使用更復(fù)雜的方案來(lái)構(gòu)建這些表征詞匯。
具體地說(shuō),這些方案不是在字符級(jí)別上工作,而是在「字符塊」級(jí)別上工作。構(gòu)建這些塊詞匯表的方式是使用字節(jié)對(duì)編碼(BPE)等算法,我們將在下面詳細(xì)介紹該算法。
暫時(shí)回顧一下這種方法的歷史發(fā)展,將字節(jié)級(jí)BPE算法用于語(yǔ)言模型分詞的論文,是2019年OpenAI發(fā)表的GPT-2論文Language Models are Unsupervised Multitask Learners。
論文地址:https://d4mucfpksywv.cloudfront.net/better-language-models/language_models_are_unsupervised_multitask_learners.pdf
向下翻到第2.2節(jié)「輸入表示」,在那里他們描述并激勵(lì)這個(gè)算法。在這一節(jié)的末尾,你會(huì)看到他們說(shuō):
詞匯量擴(kuò)大到50257個(gè)。我們還將上下文大小從512增加到1024個(gè)token,并使用512更大batchsize。
回想一下,在Transformer的注意力層中,每個(gè)token都與序列中之前的有限token列表相關(guān)聯(lián)。
本文指出,GPT-2模型的上下文長(zhǎng)度從GPT-1的512個(gè)token,增加到1024個(gè)token。
換句話(huà)說(shuō),token是 LLM 輸入端的基本「原子」。
「分詞」是將Python中的原始字符串,轉(zhuǎn)換為token列表的過(guò)程,反之亦然。
還有一個(gè)流行的例子可以證明這種抽象的普遍性,如果你也去Llama 2的論文中搜索「token」,你將得到63個(gè)匹配結(jié)果。
比如,該論文聲稱(chēng)他們?cè)?萬(wàn)億個(gè)token上進(jìn)行了訓(xùn)練,等等。
論文地址:https://arxiv.org/pdf/2307.09288.pdf
淺談分詞的復(fù)雜性
在我們深入探討實(shí)現(xiàn)的細(xì)節(jié)之前,讓我們簡(jiǎn)要地說(shuō)明一下,需要詳細(xì)了解「分詞」過(guò)程的必要性。
分詞是LLM中許多許多怪異問(wèn)題的核心,我建議你不要忽略它。
很多看似神經(jīng)網(wǎng)絡(luò)架構(gòu)的問(wèn)題,實(shí)際上都與分詞有關(guān)。這里只是幾個(gè)例子:
- 為什么LLM不會(huì)拼寫(xiě)單詞?——分詞
- 為什么LLM不能執(zhí)行超簡(jiǎn)單的字符串處理任務(wù),比如反轉(zhuǎn)字符串?——分詞
- 為什么LLM在非英語(yǔ)語(yǔ)言(比如日語(yǔ))任務(wù)中更差?——分詞
- 為什么LLM不擅長(zhǎng)簡(jiǎn)單的算術(shù)?——分詞
- 為什么GPT-2在用Python編碼時(shí)遇到了更多的問(wèn)題?——分詞
- 為什么我的LLM在看到字符串<|endoftext|>時(shí)突然停止?——分詞
- 我收到的關(guān)于「trailing whitespace」的奇怪警告是什么?——分詞
- 如果我問(wèn)LLM關(guān)于「SolidGoldMagikarp」的問(wèn)題,為什么它會(huì)崩潰?——分詞
- 為什么我應(yīng)該使用帶有LLM的YAML而不是JSON?——分詞
- 為什么LLM不是真正的端到端語(yǔ)言建模?——分詞
我們將在視頻的末尾,再回到這些問(wèn)題上。
分詞的可視化預(yù)覽
接下來(lái),讓我們加載這個(gè)分詞WebApp。
地址:https://tiktokenizer.vercel.app/
這個(gè)Web應(yīng)用程序的優(yōu)點(diǎn)是,分詞在網(wǎng)絡(luò)瀏覽器中實(shí)時(shí)運(yùn)行,允許你輕松地在輸入端輸入一些文本字符串,并在右側(cè)看到分詞結(jié)果。
在頂部,你可以看到我們當(dāng)前正在使用 gpt2 分詞器,并且可以看到,這個(gè)示例中粘貼的字符串目前正在分詞為 300個(gè)token。
在這里,它們用顏色明確顯示出來(lái):
比如,字符串「Tokenization」編碼到token30642,其后是token是1634。
token「is」(注意,這是三個(gè)字符,包括前面的空格,這很重要?。┦?18。
注意使用空格,因?yàn)樗谧址惺墙^對(duì)存在的,必須與所有其他字符一起分詞。但為了清晰可見(jiàn),在可視化時(shí)通常會(huì)省略。
你可以在應(yīng)用程序底部打開(kāi)和關(guān)閉它的可視化功能。同樣,token「at」是379,「the」是262,依此類(lèi)推。
接下來(lái),我們有一個(gè)簡(jiǎn)單的算術(shù)例子。
在這里,我們看到,分詞器對(duì)數(shù)字的分解可能不一致。比如,數(shù)字127是由3個(gè)字符組成的token,但數(shù)字677是因?yàn)橛?個(gè)token:6(同樣,請(qǐng)注意前面的空格)和77。
我們依靠LLM來(lái)解釋這種任意性。
它必須在其參數(shù)內(nèi)部和訓(xùn)練過(guò)程中,了解這兩個(gè)token(6和77實(shí)際上組合成了數(shù)字677)。
同樣,我們可以看到,如果LLM想要預(yù)測(cè)這個(gè)總和的結(jié)果是數(shù)字804,它必須在兩個(gè)時(shí)間步長(zhǎng)內(nèi)輸出:
首先,它必須發(fā)出token「8」,然后是token「04」。
請(qǐng)注意,所有這些拆分看起來(lái)都是完全任意的。在下面的例子中,我們可以看到1275是「12」,然后「75」,6773實(shí)際上是三個(gè)token「6」、「77」、「3」,而8041是「8」、「041」。
(未完待續(xù)...)
(TODO:若想繼續(xù)文字版的內(nèi)容,除非我們想出如何從視頻中自動(dòng)生成)
網(wǎng)友在線(xiàn),出謀劃策
網(wǎng)友表示,太好了,實(shí)際上我更喜歡閱讀這些帖子,而不是看視頻,更容易把握自己的節(jié)奏。
還有網(wǎng)友為Karpathy出謀劃策:
「感覺(jué)很棘手,但使用LangChain可能是可行的。我在想是否可以使用whisper轉(zhuǎn)錄,產(chǎn)生有清晰章節(jié)的高級(jí)大綱,然后對(duì)這些章節(jié)塊并行處理,在整體提綱的上下文中,專(zhuān)注于各自章節(jié)塊的具體內(nèi)容(也為每個(gè)并行處理的章節(jié)生成配圖)。然后再通過(guò)LLM把所有生成的參考標(biāo)記,匯編到文章末尾」。
有人為此還寫(xiě)了一個(gè)pipeline,而且很快便會(huì)開(kāi)源。