🐋DeepSeek-R1:如何在本地运行

关于如何使用 llama.cpp 运行我们为 DeepSeek-R1 提供的 1.58 位动态量化的指南。

circle-check

使用 llama.cpp(推荐)

  1. 别忘了 <|User|><|Assistant|> 标记!- 或使用聊天模板格式化器

  2. 获取最新的 llama.cpp 在: github.com/ggerganov/llama.cpparrow-up-right。你也可以按照下面的构建说明:

apt-get update
apt-get install pciutils 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=ON -DGGML_CUDA=ON -DLLAMA_CURL=ON
cmake --build llama.cpp/build --config Release -j --clean-first --target llama-quantize llama-cli llama-gguf-split
cp llama.cpp/build/bin/llama-* llama.cpp
  1. 最好使用 --min-p 0.05 来对抗非常罕见的标记预测——我发现这对 1.58bit 模型尤其有效。

  2. 通过以下方式下载模型:

# pip install huggingface_hub hf_transfer
# import os # 可选用于更快下载
# os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"

from huggingface_hub import snapshot_download
snapshot_download(
  repo_id = "unsloth/DeepSeek-R1-GGUF",
  local_dir = "DeepSeek-R1-GGUF",
  allow_patterns = ["*UD-IQ1_S*"], # 为 1.58bit 选择量化类型 UD-IQ1_S
)
  1. 使用 Q4_0 K 量化缓存的示例 注意 -no-cnv 会禁用自动对话模式

示例输出:

  1. 如果你有一个 GPU(例如 RTX 4090)且具有 24GB,你可以将多个层卸载到 GPU 以加快处理速度。如果你有多个 GPU,可能可以卸载更多层。

  1. 要测试我们在博客中提到的 Flappy Bird 示例,可参见: https://unsloth.ai/blog/deepseekr1-dynamicarrow-up-right,我们可以使用我们的 1.58bit 动态量化生成下面的第二个示例:

Cover

原始 DeepSeek R1

Cover

1.58bit 动态量化

使用的提示如下:

要使用此示例调用 llama.cpp,我们这样做:

  1. 另外,如果你想将权重合并以便在例如 Ollama 中使用,请使用此脚本:

  1. DeepSeek R1 有 61 层。例如在 24GB 或 80GB GPU 上,向下取整后你可以预计卸载的层数(如果出现内存不足则减 1):

量化
文件大小
24GB GPU
80GB GPU
2x80GB GPU

1.58bit

131GB

7

33

全部 61 层

1.73bit

158GB

5

26

57

2.22bit

183GB

4

22

49

2.51bit

212GB

2

19

32

在 Mac / Apple 设备上运行

对于 Apple Metal 设备,请注意 --n-gpu-layers。如果发现机器内存不足,请减少该值。对于 128GB 统一内存的机器,你应该能够卸载大约 59 层。

在 Ollama/Open WebUI 中运行

Open WebUI 提供了关于如何运行 R1 的逐步教程,见: docs.openwebui.com/tutorials/integrations/deepseekr1-dynamic/arrow-up-right 如果你想在 Ollama 上对 GGUF 进行推理,你需要先将 3 个 GGUF 拆分文件合并为 1 个,如下面代码所示。然后需要在本地运行模型。

DeepSeek 聊天模板

所有蒸馏版本和主 671B R1 模型使用相同的聊天模板:

<|begin▁of▁sentence|><|User|>What is 1+1?<|Assistant|>It's 2.<|end▁of▁sentence|><|User|>Explain more!<|Assistant|>

会强制添加一个 BOS,并且 EOS 用于分隔每次交互。为避免推理时出现双重 BOS 标记,你应该仅调用 tokenizer.encode(..., add_special_tokens = False) 因为聊天模板也会自动添加一个 BOS 标记。 对于 llama.cpp / GGUF 推理,你应该跳过 BOS,因为它会自动添加。

<|User|>What is 1+1?<|Assistant|>

<think> 和 </think> 标记有它们各自的专用标记。在为 Qwen 和 Llama 的蒸馏版本中,有些标记被重新映射,而例如 Qwen 没有 BOS 标记,所以不得不改用 <|object_ref_start|>。 分词器 ID 映射:

标记
R1
蒸馏 Qwen
蒸馏 Llama

<think>

128798

151648

128013

</think>

128799

151649

128014

<|begin_of_sentence|>

0

151646

128000

<|end_of_sentence|>

1

151643

128001

<|User|>

128803

151644

128011

<|Assistant|>

128804

151645

128012

填充标记

2

151654

128004

模型中的原始标记:

标记
Qwen 2.5 32B 基础版
Llama 3.3 70B 指令版

<think>

<|box_start|>

<|reserved_special_token_5|>

</think>

<|box_end|>

<|reserved_special_token_6|>

<|begin▁of▁sentence|>

<|object_ref_start|>

<|begin_of_text|>

<|end▁of▁sentence|>

<|endoftext|>

<|end_of_text|>

<|User|>

<|im_start|>

<|reserved_special_token_3|>

<|Assistant|>

<|im_end|>

<|reserved_special_token_4|>

填充标记

<|vision_pad|>

<|finetune_right_pad_id|>

所有蒸馏版本和原始 R1 版本似乎意外将填充标记分配为 <|end▁of▁sentence|>,这通常不是一个好主意,尤其是当你想在这些推理模型上继续进行微调时。这会导致无尽的无限生成,因为大多数框架会将 EOS 标记掩蔽为 -100。 我们已修正所有蒸馏版本和原始 R1 版本的正确填充标记(Qwen 使用 <|vision_pad|>,Llama 使用 <|finetune_right_pad_id|>,R1 使用 <|▁pad▁|> 或我们自己添加的 <|PAD▁TOKEN|>)。

GGUF R1 表格

MoE 比特数
类型
磁盘大小
准确性
链接
详情

1.58bit

UD-IQ1_S

131GB

一般

MoE 全部 1.56bit。 down_proj 在 MoE 中为 2.06/1.56bit 的混合

1.73bit

UD-IQ1_M

158GB

良好

MoE 全部 1.56bit。 down_proj 在 MoE 中保持为 2.06bit

2.22bit

UD-IQ2_XXS

183GB

更好

MoE 全部 2.06bit。 down_proj 在 MoE 中为 2.5/2.06bit 的混合

2.51bit

UD-Q2_K_XL

212GB

最佳

MoE 全部 2.5bit。 down_proj 在 MoE 中为 3.5/2.5bit 的混合

最后更新于

这有帮助吗?