DeepSeek R1 671b 满血版部署笔记

前言

DeepSeek R1 是最近大火的大语言模型,主要是可以比肩 o1 的性能以及完全开源。之前一篇文章所说,我手里有两台 1T 内存的 EPYC 机器,因此正好可以用来部署 R1。本文主要记录一下利用 llama.cpp 部署过程中的经验。

TL;DR: 对于 llama.cpp 以及衍生的 ollama 部署方案,推理速度基本和内存带宽成线性,符合 Roofline 模型。

模型下载

llama.cpp 支持 GGUF 类型的模型,所以直接下载 unsloth 做好的模型

注意 R1 是 FP8 训练的,也就是说其中的 Q8 就是满血版,也是我们这次要用的版本。

编译选项

如果是纯 CPU 推理,考虑到我希望有 -march=native 来达到最大运算速度采用了本地编译:

1
2
3
4
5
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j install

这里 llama.cpp 会帮我们加上 -march=native

如果是需要 GPU 推理,编译选项改为

1
2
cmake .. -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON
make -j install

运行

运行比较简单,我比较喜欢 llama-server 的方法:

1
2
3
llama-server -t 48 -m ./DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00001-of-00015.gguf \
-c 4096 --no-mmap \
--host 0.0.0.0 --port 9090
  • --no-mmap 的话会直接把模型拉到内存里
  • -t 48 使用 48 个线程
  • -c 4096 context 设置为 4k

占用合计在700G左右,增大 context 会显著提高内存占用。

推理速度

内存带宽

我自己的服务器上推理速度有 2.5-3.5 token/s,这个数值基本上和内存带宽是绑定的,可以用 mbw 测试

1
mbw -n 128 256

这个测出来的数值乘以通道数量就是最大内存带宽,我这里有大概 19926 * 16 = 318G/s考虑 R1 是 memory bound,基本上推理速度会和最大内存带宽成线性。比如根据这里的汇报,使用 DDR5 和 24 通道拥有接近 1T/s 的带宽,因此推理速度来到了 6-8 token/s,提升几乎是线性的。顺带一提,这已经比很多纯 GPU 推理还快了。

CPU 加速?

上文中我只使用了 48 个核心,一个想法是更多的核心会不会更快?可惜的是,R1 是完完全全的 memory bound,我尝试过 48,64,96,128 四种配置,推理速度的偏差基本都在实验误差范围内,因此选择 48 是完全足够了。

GPU 加速?

一个非常直观的想法是利用 GPU 加速,不过在实际操作前仍然要强调 R1 是完全的 memory bound,也就是说如果不能把模型完全加载进入 VRAM 的话至少还要把数据多来回拷贝两次。虽然理论上来说利用了闲置的 PCIE 带宽,但是会抢 CPU 的内存带宽,所以未必能加速。下面实验基于一台双路 epyc 7763 + 4xA100 的服务器测试 llama.cpp 的 GPU offload 效果。

  • 纯CPU推理:1.8 token/s (~700G RAM)

这里更加印证了之前说的内存带宽问题,因为在多路 EPYC 上存在非常严重的 NUMA 问题(在2代上更加严重),因此他的等效内存带宽会很低。所以即使这台服务器的内存带宽有我自己服务器的2倍,推理速度直接打了对折。

  • CPU + 8 layer GPU:3.0 token/s (~600G RAM + ~110G VRAM)

推理速度获得了近一倍的提升,根据观察推理过程中 CPU/GPU 的变化,可以看到加速的来源主要是 A100 运算速度远快于 CPU,但是最后 text generation 的过程中 A100 是完全闲着的,所以整体上仍然受制于内存带宽。

  • CPU + 16 layer GPU:2.4 token/s (~510G RAM + ~206G VRAM)

随着把更多的 layer 放到 GPU 上,推理速度反而下降了。不难猜测是更多的数据交换浪费了CPU的内存带宽所导致。

总的来说 GPU 应该是可以加速 R1 的推理速度的,但是:

  • 推理速度大部分还是由内存带宽决定的
  • 不是越多计算放到 GPU 越好,计算性能看起来也并不重要

因为 R1 是 MoE 模型,也就是说每次不是全量权重参与计算,我猜测会有一个比较甜点的 GPU VRAM 大小,可能接近 90G 能达到最高的加速效果。

总结

对于 llama.cpp 这种 CPU + GPU 的方案,内存带宽越高,R1 的推理速度会越快。

参考

  • https://www.anandtech.com/show/16529/amd-epyc-milan-review/4
  • https://x.com/carrigmat/status/1884244369907278106
  • https://snowkylin.github.io/blogs/a-note-on-deepseek-r1.html
  • https://digitalspaceport.com/how-to-run-deepseek-r1-671b-fully-locally-on-2000-epyc-rig/