簡單、純 C/CUDA 的法學碩士,不需要 245MB 的 PyTorch 或 107MB 的 cPython。目前的重點是預訓練,特別是複製 GPT-2 和 GPT-3 迷你係列,以及 train_gpt2.py 中的平行 PyTorch 參考實現。您會將此文件視為稍微調整過的 nanoGPT,這是我的早期專案。目前,llm.c 比 PyTorch Nightly 快一點(大約快 7%)。除了 train_gpt2.cu 中的前沿主線程式碼之外,我們還在一個檔案 train_gpt2.c 中提供了一個簡單的參考 CPU fp32 實現,其中包含大約 1,000 行乾淨的程式碼。我希望這個儲存庫僅維護 C 和 CUDA 程式碼。非常歡迎移植到其他語言或儲存庫,但應該在單獨的儲存庫中完成,我很高興在下面的「值得注意的分叉」部分中連結到它們。開發者協調發生在討論區和 Discord 上,可以是 Zero to Hero 頻道上的#llmc
頻道,也可以是 GPU MODE Discord 上的#llmdotc
。
今天對 llm.c 儲存庫的最佳介紹是複製 GPT-2 (124M) 模型。討論 #481 詳細介紹了這一點。我們可以在 llm.c 和 PyTorch 的平行實作中重現 GPT-2 和 GPT-3 系列的其他模型。查看腳本自述文件。
偵錯提示:當您執行make
命令來建立二進位檔案時,請透過將-O3
替換為-g
來修改它,以便您可以在您最喜歡的 IDE(例如 vscode)中單步偵錯程式碼。
如果您不會在多個節點上進行訓練,對混合精度不感興趣,並且有興趣學習 CUDA,那麼您可能會對 fp32(舊版)檔案感興趣。這些文件是在 llm.c 歷史早期被「檢查點」並及時凍結的文件。它們更簡單、更便攜,而且可能更容易理解。運行 1 GPU、fp32 程式碼,如下所示:
chmod u+x ./dev/download_starter_pack.sh
./dev/download_starter_pack.sh
make train_gpt2fp32cu
./train_gpt2fp32cu
download_starter_pack.sh 腳本是一種快速簡單的入門方法,它會下載一堆 .bin 文件,幫助您開始工作。其中包含:1)保存在fp32 和bfloat16 中的GPT-2 124M 模型,2)單元測試中使用的“測試狀態”(一小批數據以及目標激活和梯度),3)GPT-2 分詞器,以及 3) 標記化的tinyshakespeare 資料集。或者,您可以手動重新建立這些工件,而不是執行 .sh 腳本,如下所示:
pip install -r requirements.txt
python dev/data/tinyshakespeare.py
python train_gpt2.py
「我的 GPU 太差了,我甚至沒有一個 GPU」部分。您仍然可以欣賞 llm.c 火車!但你不會走太遠。就像上面的 fp32 版本一樣,CPU 版本是 llm.c 歷史上更早的檢查點,當時它只是 C 中的一個簡單參考實作。 )來輸出類似莎士比亞的文本,例如:
chmod u+x ./dev/download_starter_pack.sh
./dev/download_starter_pack.sh
make train_gpt2
OMP_NUM_THREADS=8 ./train_gpt2
如果您不想執行入門套件腳本,那麼如上一節所述,您可以透過執行python dev/data/tinyshakespeare.py
然後執行python train_gpt2.py
來重現完全相同的 .bin 檔案和工件。
上面的行(1) 下載已經標記化的tinyshakespeare資料集並下載GPT-2 (124M) 權重,(3) 在C 中對其進行初始化,並使用AdamW 在tineshakespeare上訓練40 個步驟(使用批量大小4 ,上下文長度僅64) ),評估驗證損失,並對一些文字進行取樣。老實說,除非您有強大的 CPU(並且可以在啟動命令中增加 OMP 線程的數量),否則您不會在 CPU 培訓 LLM 上取得那麼大的成果,但這可能是一個很好的演示/參考。在我的 MacBook Pro (Apple Silicon 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
generating:
---
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
---
/dev/data/(dataset).py
中的資料檔案負責下載、標記並將標記儲存到 .bin 檔案中,可以輕鬆地從 C 讀取。
python dev/data/tinyshakespeare.py
我們下載並標記tinyshakespeare 資料集。其輸出如下圖所示:
writing 32,768 tokens to ./dev/data/tinyshakespeare/tiny_shakespeare_val.bin
writing 305,260 tokens to ./dev/data/tinyshakespeare/tiny_shakespeare_train.bin
.bin 檔案包含一個短標頭(1024 位元組),然後是 uint16 格式的令牌流,使用 GPT-2 令牌產生器指示令牌 ID。 /dev/data
中提供了更多資料集。
我還附上了一個簡單的單元測試,以確保我們的 C 程式碼與 PyTorch 程式碼一致。以CPU為例,編譯並執行:
make test_gpt2
./test_gpt2
現在載入由 train_gpt2.py 編寫的gpt2_124M_debug_state.bin
文件,運行前向傳遞,將 logits 和損失與 PyTorch 參考實作進行比較,然後使用 Adam 進行 10 次迭代訓練,並確保損失與 PyTorch 匹配。為了測試 GPU 版本,我們運行:
# fp32 test (cudnn not supported)
make test_gpt2cu PRECISION=FP32 && ./test_gpt2cu
# mixed precision cudnn test
make test_gpt2cu USE_CUDNN=1 && ./test_gpt2cu
這將測試 fp32 路徑和混合精度路徑。測試應該通過並列印overall okay: 1
。
我在 doc/layernorm/layernorm.md 中附上了一個非常小的教學。這是一個簡單的逐步指南,用於實現 GPT-2 模型的單層(layernorm 層)。這是理解如何在 C 中實現層的一個很好的起點。
閃關注。自 2024 年 5 月 1 日起,我們使用 cuDNN 的 Flash Attention。由於 cuDNN 將編譯時間從幾秒鐘延長到大約分鐘,並且此程式碼路徑現在非常新,因此預設會停用此功能。您可以透過如下編譯來啟用它:
make train_gpt2cu USE_CUDNN=1
這將嘗試使用 cudnn 進行編譯並運行它。您必須在系統上安裝 cuDNN。使用 apt-get 的 cuDNN 安裝說明將取得預設的 cuDNN 軟體包集。對於最小設置,cuDNN 開發套件就足夠了,例如在 Ubuntu 22.04 上用於 CUDA 12.x:
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt-get -y install libcudnn9-dev-cuda-12
除此之外,您還需要 cuDNN 前端,但這只是頭檔。只需將存儲庫克隆到您的磁碟即可。 Makefile 目前在您的主目錄或目前目錄中尋找它。如果您已將其放在其他位置,請將CUDNN_FRONTEND_PATH=/path/to/your/cudnn-frontend/include
新增至make
命令列。
確保安裝 MPI 和 NCCL,例如在 Linux 上:
sudo apt install openmpi-bin openmpi-doc libopenmpi-dev
對於 NCCL,請遵循官方網站的說明(例如網路安裝程式)
進而:
make train_gpt2cu
mpirun -np < number of GPUs > ./train_gpt2cu
或只需在./scripts/
下運行我們的腳本之一。
確保您已按照多 GPU 部分的說明安裝了NCCL
。
我們目前支援 3 種方式可讓您執行多節點訓練:
./scripts/multi_node/run_gpt2_124M_mpi.sh
腳本。./scripts/multi_node/run_gpt2_124M_fs.sbatch
腳本。./scripts/multi_node/run_gpt2_124M_tcp.sbatch
腳本。筆記:
slurm-wlm
放棄了 PMIx 支持,我們假設這將是一種常見情況),您將必須使用 FS (2) 或 TCP (3) 方法。若要測試您的 slurm 是否支援 PMIx,請執行: srun --mpi=list
並查看輸出是否包含pmix
。mpirun
- MPI (1) 啟動多節點運行。這 3 種方法都沒有優越性,我們只是為您提供選項,以便您可以在您的特定環境中運行。
就像在 TinyStories 上使用 4 個 GPU 的機器上掃描學習率的範例過程一樣。執行 shell 腳本sweep.sh
(當然在chmod u+x sweep.sh
之後):
#! /bin/bash
learning_rates=(3e-5 1e-4 3e-4 1e-3)
for i in {0..3} ; do
export CUDA_VISIBLE_DEVICES= $i
screen -dmS " tr $i " bash -c " ./train_gpt2cu -i data/TinyStories -v 250 -s 250 -g 144 -l ${learning_rates[$i]} -o stories $i .log "
done
# you can bring these down with
# screen -ls | grep -E "tr[0-3]" | cut -d. -f1 | xargs -I {} screen -X -S {} quit
此範例開啟 4 個螢幕會話並使用不同的 LR 執行四個命令。這會將所有損失寫入日誌檔案stories$i.log
,您可以根據需要在 Python 中繪製它們。有關如何解析和繪製這些日誌檔案的簡單範例位於 dev/vislog.ipynb 中。
關於我想要這個存儲庫的更多內容:
首先,我希望llm.c
成為一個教育場所。例如,我們的dev/cuda
資料夾是一個包含所有層的核心庫的地方,這些層都是手動編寫的並且有很好的文檔記錄,從非常簡單的核心一直到更複雜/更快的核心。如果您有一個具有各種不同權衡的新內核,請隨時在此處貢獻它。
也就是說,我也希望llm.c
也非常快,甚至對於訓練網路來說實際上很有用。例如,首先,我們應該能夠重現大型 GPT-2 (1.6B) 訓練運行。這要求我們合併最快的內核,包括使用 cuBLAS、cuBLASLt、CUTLASS、cuDNN 等庫。速度的80%,等等。
然而,作為一個限制,我想保持根資料夾中的主線llm.c
簡單且可讀。如果有一個 PR 可以將效能提高 2%,但它「花費」了 500 行複雜的 C 程式碼,並且可能是一個奇異的第 3 方依賴項,我可能會拒絕該 PR,因為其複雜性不值得。舉一個具體的例子 - 將 cuBLAS for matmuls 設定為根訓練循環中的預設值是理所當然的:它使主線程式碼更快,它是單行可解釋程式碼,並且是非常常見的依賴項。另一方面,我們可以手動實現,可以與dev/cuda
中的 cuBLAS 競爭。
最後,我將對專案根資料夾中的複雜性更加敏感,其中包含專案的主/預設檔案。相比之下, dev/
資料夾對我們來說更像是一個臨時空間,用於開發核心或類別庫並共享有用或相關或教育程式碼,其中一些程式碼可能(本地)複雜。
AMD 支援
C#
CUDA C++
C++/CUDA
WebGPU C++
C++
去
爪哇
金屬
莫喬
OpenCL
鏽
迅速
之字形
哈瓦那高第2
尼姆
組織發展方式:
#llmc
頻道。 麻省理工學院