Appearance
閱讀心得
從 Python 到 C:一個 LLM 的逆向旅程
閱讀 llama2.c 最震撼的感受是:一個現代 LLM 的核心推理,竟然可以用不到一千行的 C 程式碼完整實作。這顛覆了我對「大型語言模型必須依賴龐大框架」的認知。
對 Karpathy 風格的觀察
Karpathy 的程式碼有一種 signature style:極簡但不簡陋。
run.c沒有使用任何第三方庫,連#include都只有標準 C 標頭檔- 註解恰到好處,解釋「為什麼」而非「是什麼」
- 變數命名直觀(
wq= weights for queries,xb= residual branch buffer) - 錯誤處理簡單直接(失敗就
exit(),不搞複雜的錯誤回傳)
對 C 語言實作 LLM 的反思
記憶體管理
C 語言要求開發者手動管理每個 byte。run.c 使用 calloc 分配緩衝區,使用 mmap 映射權重檔。這種底層控制讓權重佈局一目了然——你可以確切知道每個權重陣列在記憶體中的位置和大小。
效能
沒有 Python 的 interpreter overhead、沒有 PyTorch 的 tensor dispatch 開銷,純粹的 for 迴圈矩陣乘法。加上 OpenMP 平行化後,即使是 CPU 也能達到可用的推理速度。
可讀性
原始碼本身就是文件。forward() 函數的結構完全對應 Transformer 的數學定義,閱讀程式碼的同時就在學習架構。
學到的重要概念
Weight Tying 的實務意義:
model.py中tok_embeddings.weight = output.weight這一行,在 C 中對應wcls = shared_weights ? token_embedding_table : ptr——真正理解了「共享權重」在記憶體中的呈現方式。GQA 的實作巧妙:在 C 中,GQA 透過
kv_dim = (dim * n_kv_heads) / n_heads和kv_mul = n_heads / n_kv_heads來實作,比 PyTorch 版的repeat_kv()更加直覺。RoPE 的 On-the-fly 計算:C 版不像 PyTorch 版預先計算 cos/sin 表格,而是在 forward 時即時計算。這是空間 vs 時間的權衡。
改進空間
- CUDA 支援仍在 todo list 中(
run.cu) - 13B+ 模型的指標運算溢位問題尚未完全解決
- Chat 模式的實作被標註為「proof of concept」,不夠穩健