“真男人就應該用 C 編程”!用 1000 行 C 代碼手搓了一個大模型,Mac 即可運行,特斯拉前 AI 總監爆火科普 LLM

來自公衆號:InfoQ

編譯 | 核子可樂、Tina

徒手用 1000 行 C 語言實現,不依賴龐大的外部庫,Mac 即可運行。   

如今這年頭,徒手寫神經網絡代碼已經不算事兒了,現在流行手搓大模型訓練代碼了!這不,今天,特斯拉前 AI 總監、OpenAI 創始團隊成員 Andrej Karpathy 僅用 1000 行簡潔的 C 代碼,就完成了 GPT-2 大模型訓練過程。

幾個小時前,Andrej Karpathy 推出了一個名爲 llm.c 的項目,旨在用純 C 語言訓練 LLM,這種方法的主要優勢在於它顯著減少了依賴庫的體積——不再需要 245MB 的 PyTorch 和 107MB 的 cPython,這樣可以使得模型訓練過程更爲輕量化和高效。該項目還可以立即編譯和運行,並且可以與 PyTorch 的參考實現媲美。

Karpathy 表示他之所以選擇 GPT-2 作爲首個工作示例,是因爲它大語言模型鼻祖的定位,亦屬現代 AI 堆棧的首次組合。因此,選擇 GPT-2 作爲起點,可以讓我們更容易地理解和實踐大型語言模型訓練。

徒手實現 GPT-2 後,Karpathy 將這份代碼放到了 GitHub 上,以 MIT 協議開源。短短几個小時,就超過了 2500 顆星,並且數據還在不斷持續上漲......

將大模型原理拆解得無比簡單

Andrej Karpathy 是全球人工智能領域的知名科學家,也是 OpenAI 的創始成員和研究科學家。

他於 2009 年本科畢業於多倫多大學,獲得計算機科學和物理學學士學位。2011 年碩士畢業於不列顛哥倫比亞大學,隨後前往斯坦福大學 AI Lab(SAIL)讀博,師從著名學者李飛飛,是全球最早將深度學習應用於計算機視覺研究的學者之一。

在求學期間,Andrej Karpathy 曾在谷歌和 DeepMind 實習,後來在 OpenAI 剛剛成立時加入並擔任研究科學家。直到 2017 年 6 月,他被馬斯克挖去,擔任特斯拉人工智能部門主管,直接向馬斯克彙報。在特斯拉工作的五年裏,他主導了特斯拉自動輔助駕駛系統 Autopilot 的開發。這項技術對於特斯拉的完全自動駕駛系統 FSD 至關重要,也是馬斯克針對 Model S、Cybertruck 等車型推銷的主要賣點。在各大新聞中,他被譽爲 “特斯拉的祕密武器”。

去年 Karpathy 曾短暫回到 OpenAI,然後又在 OpenAI 衆人忙於內鬥時抽空錄製了一個長達一小時的教學視頻《大型語言模型入門》。

Karpathy 在視頻中首先介紹了一些 LLM 入門知識,然後以 Meta 推出的開源大模型 Llama 2-70b 爲例進行了講解。該模型有 700 億參數,主要包含兩個文件,分別是參數文件,文件大小爲 140GB,以及運行這些參數的代碼,以 C 語言爲例需要約 500 行代碼。

Karpathy 表示只要有這兩個文件再加上一臺 MacBook,我們就可以構建一個獨立的系統,無需聯網或其他設施。

大模型訓練,可以理解爲是對互聯網數據進行有損壓縮,一般需要一個巨大的 GPU 集羣來完成。以 Llama 2-70b 爲例的話,就是使用了類似網絡爬取的約 10TB 的文本,用 6000 個 GPU ,耗資 200 萬美元,訓練約 12 天,最後獲得基礎模型。

基礎模型即上圖裏 140GB 的 “壓縮文件”(壓縮率約 100 倍),就等於靠這些數據對世界形成了理解,那它就可以進行“預測” 工作了。

Karpathy 之前還分享過他的學習經驗,就是開始時要嘗試從 0 開始,寫一些原生代碼,幫助理解消化知識點。 也就是說,徒手實現代碼纔是最有效的學習方式。

兩年前,Karpathy 就曾基於 PyTorch,僅用 300 行左右的代碼就寫出了一個小型 GPT 訓練庫,並將其命名爲 minGPT,用這份代碼揭開了 GPT 神祕的面紗。

截圖來源:https://github.com/karpathy/minGPT

因爲大多數 GPT 模型的實現都過於龐大,而 minGPT 做到了小、乾淨、可解釋和具有教育意義,所以 Karpathy 的這 300 行代碼是學習 GPT 的最佳資源之一,可以用來深入理解 GPT 是如何工作的。

用 C 語言實現 LLM

這次,Andrej Karpathy 單純通過 C/CUDA 實現大語言模型訓練,且無需 245 MB PyTorch 或 107 MB cPython。例如,訓練 GPT-2(CPU,fp32 單精度)需要在單個文件中使用約 1000 行簡潔代碼,可立即編譯並運行、且與 PyTOrch 參考實現完全匹配。

從某種意義上說,Karpathy 確實在嘗試重新設計 LLM 的架構。他通過 llm.c 項目探索一種更簡單、更高效的訓練 LLM 方法。與現有 LLM 架構相比,這種新架構的主要亮點包括:

  1. 代碼簡潔性:僅使用約 1000 行代碼就能完成 GPT-2 模型的訓練,相比之下顯著降低了複雜度。

  2. 獨立性:不依賴龐大的外部庫如 PyTorch 或 cPython,使得部署和運行更加輕便快捷。

  3. 高效性:直接使用 C/CUDA 進行編程有望提高計算效率和訓練速度。

有網友問 Karpathy 爲何不用 Rust,Karpathy 回覆說,“我完全理解 Rust 的吸引力。然而,我仍然覺得 C 語言非常棒。它簡單、乾淨、可移植,在審美上也十分優美。使用 C 語言就像直接與機器交流一樣。”

這種語言選擇也讓網友們紛紛感嘆:

“我們正在掀起一場 C 語言復興!”

“真男人就應該用 C 語言編程。”

Karpathy 以更簡單、更原始的 C/CUDA 架構來做 LLM 的訓練,其中還涉及算法優化、計算資源管理等多個方面。

你會看到,項目在開始時一次性分配所有所需的內存,這些內存是一大塊 1D 內存。然後在訓練過程中,不會創建或銷燬任何內存,因此內存佔用量保持不變,並且只是動態的,將數據批次流過。這裏的關鍵在於手動實現所有單個層的前向和後向傳遞,然後將它們串聯在一起。

例如,這裏是 layernorm 前向和後向傳遞。除了 layernorm 之外,我們還需要編碼器、matmul、自注意力、gelu、殘差、softmax 和交叉熵損失。

“一旦你擁有了所有的層,接下來的工作只是將它們串在一起。講道理,寫起來相當乏味和自虐,因爲你必須確保所有指針和張量偏移都正確排列,”Karpathy 表示。

另外 Karpathy 還在 doc/layernorm/layernorm.md 中附上了短小的使用教程。裏面是一份簡單的分步指南,用於實現 GPT-2 模型中的單一層,即 layernorm 層,希望能成爲大家理解在 C 中實現大語言模型各層的理想起點。

更重要的是,他還用自己的 MacBook Pro(蘋果 M3 Max 芯片)演示了整個訓練過程,對照他之前的大模型入門教程,就可以輕鬆瞭解如今炙手可熱的 LLM 是怎麼一回事兒了。

 訓練過程:

首先下載數據集並 token 化。

python prepro_tinyshakespeare.py

輸出結果爲:

Saved 32768 tokens to 
data/tiny_shakespeare_val.bin
Saved 305260 tokens to 
data/tiny_shakespeare_train.bin

其中各. bin 文件爲 int32 數字的原始字節流,用於指示 GPT-2 token 化器的 token id。或者也可以使用 prepro_tinystories.py 對 TinyStories 數據集進行標註。

原則上,到這裏就已經可以開始訓練模型。爲提高效率,可以使用 OpenAI 發佈的 GPT-2 權重進行初始化,而後加以微調。爲此需要下載 GPT-2 權重並將其保存爲可在 C 中加載的檢查點:

python train_gpt2.py

該腳本會下載 GPT-2(124M)模型,對單批數據進行 10 次過擬合迭代,運行多個生成步驟,最重要的是保存兩個文件:1)gpt2_124M.bin 文件,包含用於在 C 中加載的模型權重;2)以及 gpt2_124M_debug_state.bin,包含包括 input、target、logits 及 loss 等更多調試狀態,對於調試 C 代碼、單元測試及確保能夠與 PyTorch 參考實現完全匹配非常重要。現在我們可以使用這些權重進行初始化並在原始 C 代碼中進行訓練。首先編譯代碼:

make train_gpt2

在 train_gpt2 編譯完成後即可運行:

OMP_NUM_THREADS=8 ./train_gpt2

大家應根據 CPU 的核心數量來調整線程數量。該程序將加載模型權重、tokens,並使用 Adam lr 1e-4 運行數次迭代的微調循環,而後由模型生成樣本。簡單來講,所有層都具有前向及後向傳遞實現,串聯在一起形成統一的大型、手動前向 / 後向 / 更新循環。在 MacBook Pro(蘋果 M3 Max 芯片)上的輸出結果如下所示:

[GPT-2]
max_seq_len: 1024
vocab_size: 50257
num_layers: 12
num_heads: 12
channels: 768
num_parameters: 124439808
train dataset num_batches: 1192
val dataset num_batches: 128
num_activations: 73323776
val loss 5.252026
step 0: train loss 5.356189 (took 1452.121000 ms)
step 1: train loss 4.301069 (took 1288.673000 ms)
step 2: train loss 4.623322 (took 1369.394000 ms)
step 3: train loss 4.600470 (took 1290.761000 ms)
... (trunctated) ...
step 39: train loss 3.970751 (took 1323.779000 ms)
val loss 4.107781
generated: 50256 16773 18162 21986 11 198 13681 263 23875 198 3152 262 11773 2910 198 1169 6002 6386 2583 286 262 11858 198 20424 428 3135 7596 995 3675 13 198 40 481 407 736 17903 11 329 703 6029 706 4082 198 42826 1028 1128 633 263 11 198 10594 407 198 2704 454 680 1028 262 1027 28860 286 198 3237 323
step 40: train loss 4.377757 (took 1366.368000 ms)

現在的生成結果僅給出 token ids,需要將其解碼迴文本形式:

<|endoftext|>Come Running Away,
Greater conquer
With the Imperial blood
the heaviest host of the gods
into this wondrous world beyond.
I will not back thee, for how sweet after birth
Netflix against repounder,
will not
flourish against the earlocks of
Allay

參考鏈接:

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

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

https://www.youtube.com/watch?v=zjkBMFhNj_g

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Tz__zz1NC18ue1jsIe-CZA