來源:token的技術分享
DeepSeek-R1 最近在完全開源的情況下與 OpenAI 的 O1 推理模型競爭,掀起了波瀾。我們探索了如何讓更多的本地用戶運行它,并設法將 DeepSeek 的 R1 671B 參數模型量化為 131GB,比原來的 720GB 減少了 80%,同時功能強大。
通過研究 DeepSeek R1 的架構,我們設法選擇性地將某些層量化為更高的位(如 4 位),并將大多數 MoE 層(如 GPT-4 中使用的層)保留為 1.5 位(參見Unsloth 動態 4 位).天真地量化所有層會完全破壞模型,導致無限循環和亂碼輸出。我們的動態量化解決了這個問題。
1.58 位量化應該適合 160GB 的 VRAM 以進行快速推理(2x H100 80GB),每秒達到大約 140 個令牌。您不需要 VRAM (GPU) 來運行 1.58 位 R1,只需 20GB 的 RAM (CPU) 就可以工作,但可能會很慢。為了獲得最佳性能,我們建議 VRAM + RAM 的總和至少為 80GB+。
我們上傳了大小從 131GB 到 212GB 不等的動態量化版本,以:huggingface.co/unsloth/DeepSeek-R1-GGUF
P.S. 如果您喜歡我們的工作,請隨時給我們?加星標:github.com/unslothai/unsloth或在 X 上關注我們@UnslothAi
1.動態量化版本
我們提供 4 個動態量化版本。前 3 個使用重要性矩陣來校準量化過程(通過 llama.cpp 的 imatrix)以允許較低位的表示。最后一個 212GB 版本是通用的 2 位量化,無需校準。
MoE Bits
Disk Size
Type
Quality
Link
Down_proj
1.58-bit
131GB
IQ1_S
Fair
Link
2.06/1.56bit
1.73-bit
158GB
IQ1_M
Good
Link
2.06bit
2.22-bit
183GB
IQ2_XXS
Better
Link
2.5/2.06bit
2.51-bit
212GB
Q2_K_XL
Best
Link
3.5/2.5bit
這些指令適用于R1蒸餾版和非蒸餾版模型,但請注意,它們對硬件的要求不同。有關R1的具體要求,請參見下文。
2. 基準和消融
為了測試所有量化模型,我們沒有依賴通用基準,而是讓DeepSeek r1創建一個有3次嘗試機會的Flappy Bird游戲(pass@3),并根據10項標準對其進行評分(例如使用隨機顏色、隨機形狀、是否能在Python解釋器中運行等)。我們使用了種子3407、3408和3409,并采用了建議的溫度值0.6。
左側是chat.deepseek.com生成的一個示例,右側則是1.58位版本的結果。
DeepSeek原創 1.58位版本
我們驚訝地發現,我們的動態1.58位版本似乎仍然能夠生成有效的輸出! 然而,如果你不使用我們的動態1.58位版本,而是簡單地量化所有層,你將會得到無限重復的內容,比如在種子3407中:“Colours with dark Colours with dark Colours with dark Colours with dark Colours with dark”,或者在種子3408中:“Set up the Pygame's Pygame display with a Pygame's Pygame's Pygame's Pygame's Pygame's Pygame's Pygame's Pygame's Pygame's”。 同樣地,如果你不使用我們的動態版本,而是將所有層量化為1.75比特(149GB),無限重復會停止,但結果完全錯誤。所有輸出都會產生全黑的屏幕。如果你將所有層量化為2.06比特(175GB),結果甚至比1.58比特(131GB)的動態量化還要差。你最好使用2.22比特(183GB)版本,它在性能上更優越。
1.58比特的動態量化有時會每8000個token產生1個錯誤的token,我們需要將其注釋掉。使用min_p = 0.1
或0.05
應該可以緩解1.58比特版本生成單個錯誤token的問題。
總結一下,滿分10分和Pass@3的得分如下:
Model Size
Dynamic Quant
Model Size
Basic Quant
131GB
6.92
133GB
0
158GB
9.08
149GB
1.67
183GB
9.17
175GB
6.17
我們在博客文章末尾提供了更詳細的結果。
3.利用DeepSeek R1的架構
在我們之前對DeepSeek V3模型的分析中,該模型使用DeepSeek r1進行合成數據生成,我們注意到DeepSeek的前3層是完全密集的,而不是MoE(混合專家)。作為回顧,MoE(混合專家)層允許我們增加模型中的參數數量,而不會增加使用的FLOPs(浮點運算次數),因為我們動態地將大多數條目屏蔽為0,因此我們基本上跳過了對零化條目進行矩陣乘法運算。
MoEs(混合專家模型)的目標是“繞過”擴展定律,因為我們在不改變計算成本的情況下增加了參數數量。有關MoEs的更多筆記以及一種名為Memory Layers的新方法(旨在比MoEs做得更好),請參見這條推文:x.com/danielhanchen/status/1868748998783517093
通過結合以下四種方法,包括: 我們的4位動態量化方法 1.58位LLMs論文 Llama.cpp的1.5位量化 超級權重論文 我們成功應用了以下見解:
前三個密集層使用了所有權重的0.5%。我們將這些保持為4位或6位。
MoE層使用共享專家,使用了1.5%的權重。我們將使用6位。
我們可以將所有MLA注意力模塊保持為4位或6位,使用不到5%的權重。我們應該量化注意力輸出(3%),但最好保持其較高精度。
down_proj對量化最為敏感,尤其是在前幾層。我們通過超級權重論文、我們的動態量化方法和llama.cpp的GGUF量化方法驗證了我們的發現。因此,我們將前3到6個MoE down_proj矩陣保持較高精度。例如,在超級權重論文中,我們看到幾乎所有不應被量化的權重都在down_proj中。

關于為什么所有的“超級權重”或最重要的權重都在down_proj
中的主要見解是因為 SwiGLU 的操作:
[ [f(XW_{gate}) * (XW_{up})]W_{down} ] 這意味著up
和gate
投影本質上會相乘形成較大的數值,而down_proj
必須將它們縮小——這意味著量化down_proj
可能不是一個好主意,尤其是在 Transformer 的早期層中。
我們應該將
embedding
和lm_head
分別保留為 4 位和 6 位。MoE 路由器和所有層歸一化保留為 32 位。這使得約 88% 的權重成為 MoE 權重!通過將它們量化為 1.58 位,我們可以大幅縮小模型!
我們提供了動態量化代碼作為 llama.cpp 的一個分支:github.com/unslothai/llama.cpp
我們利用了 Bartowski 的重要性矩陣來進行低位量化。
所有蒸餾版本和主要的67IB R1模型使用相同的聊天模板:
< begin_of_sentence > < 用戶 > 1+1等于多少?
< 助手 > 等于2。< end_of_sentence >
| 用戶 | > 再解釋一下!< 助手 |
在推理過程中,強制添加了BOS(開始符),并且每個交互之間用EOS(結束符)分隔。為了避免在推理過程中出現雙BOS標記,你應該只調用tokenizer.encode(..., add_special_tokens = False)
,因為聊天模板會自動添加BOS標記。對于llama.cpp / GGUF推理,你應該跳過BOS,因為它會自動添加。
< 用戶 > 1+1等于多少?< 助手 >
和 標記有自己指定的標記。對于Qwen和Llama的蒸餾版本,一些標記被重新映射,例如Qwen沒有BOS標記,所以必須使用<\object_ref_start>代替。
Tokenizer ID 映射表:
Token
R1
Distill Gwen
Distill Llama
begin_of_sentence
0
end_of_sentence
1
User
Assistant
Padding token
2
原始模型中的標記:
標記
Gwen 2.5 32B 基礎版
Llama 3.3 70B 指導版
begin_of_sentence
end_of_sentence
User
Assistant
填充標記
所有蒸餾版和原始 R1 版本似乎意外地將填充標記分配給了< | end_of_sentence | >
,這通常不是一個好主意,特別是如果你想在這些推理模型的基礎上進一步微調。這將導致無限生成,因為大多數框架會將 EOS 標記屏蔽為 -100。 我們修復了所有蒸餾版本和原始R1版本,使用了正確的填充標記(Qwen使用<|vision_pad|>
,Llama使用<|finetune_right_pad_id|>
,而R1使用<|PAD▁TOKEN|>
或我們自己添加的填充標記)。
Running Dynamic Quants
你不需要使用新版本的 llama.cpp——任何能夠運行 GGUF 文件的系統(如 Ollama、OpenWebUI、Transformers,甚至 vLLM)都應該能夠運行動態量化(dynamic quants)。如果你的 VRAM 或 RAM 不足,可能會比較慢,但它是可以運行的。
如果你想直接使用 llama.cpp,請按照這里的 llama.cpp 構建說明操作——別忘了啟用 GPU 支持!我通常使用以下命令:
apt-get update apt-get install build-essential cmake curl libcurl4-openssl-dev -y git clone https://github.com/ggerganov/llama.cpp cmake llama.cpp -B llama.cpp/build \ -DBUILD_SHARED_LIBS=OFF -DGGML_CUDA=ON -DLLAMA_CURL=ON cmake --build llama.cpp/build --config Release -j --clean-first --target llama-quantize llama-cli cp llama.cpp/build/bin/llama-* llama.cpp
然后通過huggingface.co/unsloth/DeepSeek-R1-GGUF下載模型。您可以使用Hugging Face進行此操作。要下載1.58bit版本,請執行以下操作:
# pip install huggingface_hub from huggingface_hub import snapshot_download snapshot_download( repo_id = "unsloth/DeepSeek-R1-GGUF", local_dir = "DeepSeek-R1-GGUF", allow_patterns = [“*UD-IQ1_S*”], )
這將下載3個GGUF文件到DeepSeek-R1-GGUF/DeepSeek-R1-UD-IQ1_S。然后,使用以下公式決定可以將多少層卸載到GPU。如果沒有GPU,請將卸載設置為0:[n_{\text{offload}} = \frac{\text{VRAM}(GB)}{\text{文件大小}(GB)} \times n_{\text{層數}} - 4]
DeepSeek R1有61層。例如,使用24GB GPU或80GB GPU時,您可以預期在向下取整后卸載(如果內存不足,減少11):
量化
文件大小
24GB GPU
80GB GPU
2x80GB GPU
1.58bit
131GB
7
33
所有層 61
1.75bit
158GB
5
26
57
2.22bit
183GB
4
22
49
2.51bit
212GB
2
19
32
要運行模型,我們將K緩存量化為4bit。量化V緩存需要為llama.cpp編譯flash attention內核。我們使用機器上的所有線程,并使用DeepSeek推薦的溫度0.6。上下文大小是您希望模型生成的令牌數量。
./llama.cpp/llama-cli \ --model DeepSeek-R1-UD-IQ1_S/DeepSeek-R1-UD-IQ1_S-00001-of-00003.gguf \ --cache-type-k q4_0 \ --threads 12 -no-cnv --n-gpu-layers 61 --prio 2 \ --temp 0.6 \ --ctx-size 8192 \ --seed 3407 \ --prompt "<|User|>Create a Flappy Bird game in Python.<|Assistant|>”
在Ollama/vLLM 運行如果你想使用Ollama或vLLM對GGUF文件進行推理,你需要先將3個GGUF分片文件合并成1個,如下面的代碼所示。然后你需要在本地運行該模型。
./llama.cpp/llama-gguf-split --merge \ DeepSeek-R1-UD-IQ1_S/DeepSeek-R1-UD-IQ1_S-00001-of-00003.gguf \ merged_file.gguf
提示和結果使用的完整提示如下:用Python創建Flappy Bird游戲。您必須包括以下內容:
You must use pygame. The background color should be randomly chosen and is a light shade. Start with a light blue color. Pressing SPACE multiple times will accelerate the bird. The bird's shape should be randomly chosen as a square, circle or triangle. The color should be randomly chosen as a dark color. Place on the bottom some land colored as dark brown or yellow chosen randomly. Make a score shown on the top right side. Increment if you pass pipes and don't hit them. Make randomly spaced pipes with enough space. Color them randomly as dark green or light brown or a dark gray shade. When you lose, show the best score. Make the text inside the screen. Pressing q or Esc will quit the game. Restarting is pressing SPACE again.
最終的游戲應該在Python的markdown部分。檢查代碼中的錯誤,并在最后的markdown部分之前修復它們。 完整的表格和結果位于:docs.unsloth.ai/basics/deptheek-r1-dynamic-1.58-bit所有18個輸出和Python生成的代碼也上傳到那里!
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.