1000行C語言搓出GPT-2!AI大神Karpathy新項目剛上線就狂攬2.5k星

新智元報道

編輯:桃子 好睏

【新智元導讀】訓大模型的方法可能要被革新了!AI大神Karpathy發佈的新項目僅用1000行的C語言訓完GPT-2,而不再依賴龐大的GPT-2庫。他本人預告,即將上線新課。

斷更近一個月,Karpathy終於上線了。

這次不是AI大課,而是帶來一個新項目。

這一項目剛剛發佈幾個小時,已經獲得了2.5k星。

項目地址:https://github.com/karpathy/llm.c

有網友表示,初創公司正在等着Karpathy挖掘新的點子。

很少有人知道,SUNO一開始是nanoGPT的一個分支。(Suno創業團隊首款產品Bark受到了nanoGPT的啓發)

或許Karpathy正在嘗試的是重新設計LLM架構,通過llm.c項目去探索一種更簡單、高效的模型訓練方法。

「我無法創造的,我就無法理解」。

Karpathy完全讓AI走向大衆化。

那麼,僅用C語言如何訓出LLM?

千行C代碼訓完GPT-2

項目開篇介紹中,Karpathy還提到了自己目前正在進行的研究:

- 直接使用CUDA實現,速度會快得多,可能接近PyTorch。

- 使用SIMD指令加速CPU版本,x86上的AVX2/ARM上的NEON(比如蘋果芯片)。

- 採用更現代的架構,如Llama2、Gema等。

對於repo,Karpathy希望同時維護乾淨、簡單的參考實現以及更優化的版本,這些版本可以接近PyTorch,但只需很少的代碼和依賴項。

快速入門

下載數據集,並將其進行分詞。Tinyshakepeare數據集下載和分詞速度最快:

打印內容如下:

其中,.bin文件包含有int32的原始數據流,這些整數代表了通過GPT-2分詞器定義的Token ID。

當然,也可以通過運行prepro_tinystories.py來對TinyStories數據集進行分詞處理。

理論上講,現在已經能夠開始訓練模型了。但是,目前基於CPU和FP32的參考代碼運行效率極低,無法從零開始訓練這些模型。

因此,我們選擇先用OpenAI發佈的GPT-2模型權重進行初始化,再對模型進行微調。

爲了這個目的,我們需要下載GPT-2模型的權重文件,並把它們作爲檢查點保存下來,這樣就可以在C語言環境中進行加載了:

這個腳本的作用是下載GPT-2(124M)模型,並對單個數據batch進行10次迭代訓練實現過擬合。

接着,腳本將執行幾步生成任務,並且最重要的是,保存兩個文件:

gpt2_124M.bin,其中包含了可用於在C語言環境中加載模型的原始權重;

gpt2_124M_debug_state.bin,其中包含了額外的調試信息,如輸入數據、目標、logits和損失。

這些信息對於調試、單元測試以及確保與PyTorch的參考實現完全一致很有幫助。

目前,主要關注的是gpt2_124M.bin文件中的模型權重。有了它們,就可以在C語言環境中初始化模型並開始訓練了。

首先,我們需要編譯代碼:

你可以打開Makefile文件,並閱讀裡面的註釋。

它會自動檢查你的電腦是否支持OpenMP,這對於以非常低的複雜度來加速代碼運行很有幫助。

當完成train_gpt2的編譯之後,就可以開始運行了:

現在,你需要根據電腦的CPU核心數來設置程序運行的線程數。

然後,程序會加載模型的權重和Token,接着進行幾次迭代的微調過程,這個過程使用了Adam優化算法,學習率設置爲0.0001。

最後,程序會根據模型生成一個樣本。

總結來說,代碼實現了模型每一層的數據處理流程,包括前向傳播、反向傳播和參數更新等,並且被組織成了一個完整的循環。

在搭載M3 Max芯片的MacBook Pro上運行時,輸出結果如下:

目前,程序生成的結果只是Token ID,我們需要把這些編號轉換成可讀的文本。

這個過程在C語言中實現起來相當簡單,因爲涉及到的主要是對應字符串片段的查找和輸出。

現在,我們可以利用一個叫做tiktoken的工具來完成這個任務:

打印內容如下:

Karpathy表示,他對Netflix在模型生成結果中的呈現方式非常滿意,因爲這顯示出模型仍然保留了其訓練過程中的一些特徵。

此外,他也沒有去調整微調的超參數,因此如果能夠優化這些設置,特別是通過延長訓練時間,模型的性能應該會有很大的提升空間。

測試

這裡提供一個簡單的單元測試程序,用來驗證我們編寫的C語言代碼是否與PyTorch框架中的代碼實現相匹配。

通過以下命令即可編譯並執行:

這段代碼首先會加載gpt2_124M_debug_state.bin文件,然後執行一次前向計算。

這個過程會生成模型的預測結果(logits)和損失(loss),並將其與PyTorch的標準實現進行比較。

接下來,它會利用Adam優化算法對模型進行10輪訓練,從而確保訓練的損失與PyTorch的結果一致。

教程

項目最後,Karpathy還附上了一個非常小的教程——

項目地址:https://github.com/karpathy/llm.c/blob/master/doc/layernorm/layernorm.md

它是實現GPT-2模型的單層,即LayerNorm的一個簡單的分步指南。

這是瞭解如何用C語言實現層的一個很好的起點。

純CUDA也可訓

在訓練開始時,先一次性預分配一大塊一維內存,用於存儲訓練過程中所需的所有數據。

這樣做的好處是,在整個訓練過程中,我們無需再次分配或釋放內存。如此一來,不僅簡化了內存管理,還確保了內存使用量保持不變,優化了數據處理效率。

接下來的核心任務是——手動編寫代碼,實現模型中每一層的數據前向傳播和後向傳播過程,並將這些層按順序連接起來。

此外,爲了構建完整的模型,我們還需要實現多個關鍵組件,包括編碼器(encoder)、矩陣乘法(matmul)、自注意力機制(self-attention)、GELU激活函數、殘差連接(residual)、softmax函數和交叉熵損失計算。

Karpathy繼續解釋道,一旦你有了所有的層,你就可以把所有的層串聯起來。

不瞞你說,寫這個過程相當乏味,也很受虐,因爲你必須確保所有的指針和張量偏移向量都正確排列。

左圖:在內存中分配一個一維數組,然後將所有模型的權重和激活指向它

右圖:小心地進行所有指針運算

在完成了模型的前向傳播和反向傳播之後,接下來的工作,比如設置數據加載器和調整Adam優化算法,就比較簡單了。

隨後,Karpathy還介紹了自己下一步進行工作是:

一步步地將這個過程遷移到CUDA上,從而大幅提升運算效率,甚至達到接近PyTorch的水平,而且不需要依賴那些複雜的庫。

目前,他已經完成了其中的幾層。

接下來的工作包括減少計算精度——從FP32降到FP16甚至更低,以及添加一些新的層(如RoPE),從而支持更先進的模型架構,例如Llama 2、Mistral、Gemma等。

當然了,等着這一切完成之後,另一期「從頭開始構建」的視頻也會上線。

參考資料:

https://github.com/karpathy/llm.c

https://twitter.com/karpathy/status/1777427944971083809