1.前言
一個月前,Meta 發布了開源大模型 llama3 系列,在多個關鍵基準測試中優于業界 SOTA 模型,并在代碼生成任務上全面領先。
此后,開發者們便開始了本地部署和實現,比如 llama3 的中文實現、llama3 的純 NumPy 實現等。
幾天前,有位名為「Nishant Aklecha」的開發者發布了一個從零開始實現 llama3 的存儲庫,包括跨多個頭的注意力矩陣乘法、位置編碼和每個層在內都有非常詳細的解釋,幫助我們理解大語言模型是如果構建和工作的。
該項目得到了大神 Karpathy 的稱贊,他表示項目看起來不錯,完全展開后,通過模塊嵌套和相互調用,可以更容易看到實際的情況。
項目地址:https://github.com/naklecha/llama3-from-scratch
2.從零實現Llama3中文版
詳細實現見倉庫地址:wdndev/llama3-from-scratch-zh: 從零實現一個 llama3 中文版
項目主要翻譯「Nishant Aklecha」的 llama3-from-scratch 倉庫,并對中文版做了特殊的適配,使該項目能在一臺 16G RAM 的筆記本電腦上運行:
- 將英文翻譯為中文,文中的 Youtube 視頻也替換為 Bilibili鏈接,方便查看;
- 將原版 Llama3-8B模型上傳至Modescope社區,方便國內下載;
- 因原版 Llama3-8B 模型采用32層 Transformers,且大佬「Nishant Aklecha」使用CPU加載,如果加載全部的參數,16G內存機器加載失敗,故選取原版 Llama3-8B 模型權重的前2層,重新保存,大小約占為2.7G,此教程也可以直接加載,實際測試內存占用約4~5G,唯一缺點是后續推理結果不對,但不影響學習矩陣變換等其他知識;
- Jupyter文件,可直接在 16G RAM 筆記本電腦運行;
2.1 實現細節
- 分詞器(Tokenizer):
- 使用
tiktoken
庫進行文本分詞。 - 定義了一些特殊標記,如文本開始
<|begin_of_text|>
、文本結束<|end_of_text|>
等。 - 通過
tokenizer.encode
將文本轉換為標記序列,通過tokenizer.decode
將標記序列轉換回文本。
- 使用
- 模型權重和配置:
- 加載Llama3-8B模型Pytorch格式權重。
- 加載Llama3-8B模型配置,包括:
- 維度
dim
: 4096 - 層數
n_layers
: 32 - 注意力頭數
n_heads
: 32 - 鍵值頭數
n_kv_heads
: 8 - 詞匯表大小
vocab_size
: 128256 - 其他參數如
multiple_of
、ffn_dim_multiplier
、norm_eps
、rope_theta
等。
- 維度
- 文本到標記(Tokenization):
- 使用分詞器將輸入文本轉換為標記序列。
- 將標記轉換為對應的標記ID。
- 標記嵌入(Embeddings):
- 使用
torch.nn.Embedding
層將標記ID轉換為詞嵌入向量。 - 將詞嵌入向量進行歸一化處理。
- 使用
- Transformer層:
- 實現了Transformer模型的一個層,包括:
- 歸一化: 使用RMS歸一化對輸入進行歸一化。
- 注意力機制:
- 使用模型權重初始化查詢(Query)、鍵(Key)、值(Value)矩陣。
- 對查詢矩陣進行拆分,得到每個注意力頭的查詢向量。
- 通過點積計算查詢向量與鍵向量的關系,得到注意力分數矩陣。
- 對注意力分數應用掩碼,防止未來信息的泄露。
- 使用Softmax函數對注意力分數進行歸一化。
- 將歸一化的注意力分數與值向量相乘,得到加權的值向量。
- 多頭注意力: 對每個注意力頭重復上述過程,并將結果合并。
- 輸出權重: 使用模型權重將注意力輸出映射到最終的輸出向量。
- 實現了Transformer模型的一個層,包括:
- 前饋網絡(Feed-Forward Network):
- 使用SwiGLU網絡架構,增加模型的非線性表達能力。
- 通過矩陣乘法實現前饋網絡的計算。
- 多層堆疊:
- 將上述Transformer層和前饋網絡堆疊32層。
- 每一層都會對輸入進行更復雜的變換和抽象。
- 輸出解碼:
- 使用模型的輸出層權重將最終的嵌入向量映射到詞匯表上。
- 通過取最大值獲取預測的下一個標記ID。
- 使用分詞器將標記ID解碼回文本。
2.2 總結
- 詳細展示了從頭開始構建大型語言模型的一個層的完整過程。
- 通過分步實現文本分詞、標記嵌入、注意力機制、多頭注意力、前饋網絡等關鍵組件,讓讀者能夠深入理解模型的工作原理。