一、前言
最近 DeepSeek-R1 比较火,让本地部署大模型成为一个瞩目的话题。DeepSeek-R1 提供了 1.5B 到 671B 的模型,而大多数人电脑只能支持到 7-32B 模型的部署,而实际上 7-32B 的模型是基于 llama、Qwen 等模型蒸馏出来的,并非 DeepSeek 官网的 R1 模型。今天我们要做的就是本地部署 DeepSeek-R1 671B模型,挑战硬件极限。
二、模型精度
在深度学习早期,我们通常使用双精度浮点数(FP32)来表示模型参数,而双精度浮点数占用 4 个字节, 对于一个 100M 参数的模型其大小为:
推理的显存占用计算则比较复杂,我们假定和模型大小一致。而现在一个 1B 的模型其大小约为3.7GB,而 7B 的则大约为 26GB,而 70B 的则到了恐怖的 260G。
为了节省内存,出现了单精度(FP16)的方案,单精度浮点数占用 2 个字节,按照上述计算,7B 在 FP16 下大约为 13GB。13G 显存对游戏佬来说已经是一个可接受的范围了。
在 Bert时代,300M 参数的模型已经是大模型了,而进入 GPT 时代后,大模型开始以 B 为单位,此时 FP16 精度对个人电脑来说,也是无法承受的。由此模型量化技术成为了标配。
三、模型量化
通过将 FP16 的浮点数映射到8为的整型或 4 位的整型,将模型参数的大小再次缩小。以 8bit 量化为例,单个参数大小降到了 1 个字节,此时 7B 的模型大小为 6.5G 左右。而 4bit 量化单个参数大小降到了 0.5 个字节,此时 7B 的模型大小为 3.25G,已经到了个人电脑可以流畅运行的程度了。
但是如果使用 ollama,会发现 7B 的模型 4bit 量化大小并非 3.25G,而是 4.7G:
这是因为量化技术其实是对模型的线性层进行量化,因此实际大小要大约计算大小。
现在我们的目标是部署 671B 的模型,其大小为 404GB。目前要在单张 4090 部署还是比较困难的。
为了进一步量化,可以使用到 BitNet,这是微软开源的一个项目,可以将模型 动态量化到 1.58bit,此时 671B 的模型大小为 131GB。关于 BitNet 更详细的内容可以参考:arxiv.org/abs/2402.17…
四、逐层加载
DeepSeek-R1是一个 61 层的MoE 架构,在 1.58bit 量化的情况下,160G 显存才能完整加载所有层。目前为止量化可以说是走到头了,由此又出现了逐层加载技术。
我们可以把模型的层分为 layer1-layer61,在推理时,假设输入为 X,推理过程可以简化为:
x = ...
for layer in layers:
x = layer(x)
print(x)
现在我们使用 GPU 来加速上面的推理:
x = x.cuda()
for layer in layers:
layer = layer.cuda()
x = layer(x)
layer.cpu()
此时只需要显存能够加载一个 layer 就可以使用 GPU 加速推理。但是频繁的在 CPU 和 GPU 之间通信会让推理速度下降,因此可以一次性选择加载多层,比如一张 4090可以加载 7 层,因此我们修改为:
# 将 x 和前 7 个 layers 一起加载到 GPU
x = x.cuda()
# 假设 layers 是一个包含多个层的列表
layers_to_move = layers[:7]
# 将前 7 个 layer 加载到 GPU
layers_to_move = [layer.cuda() for layer in layers_to_move]
# 执行这些层
for layer in layers_to_move:
x = layer(x)
# 如果剩下的 layers 需要处理,也可以继续使用原来代码中的方式处理
for layer in layers[7:]:
x = layer(x)
此时 CPU 和 GPU 通信次数减少了,因此推理也更快了。现在只需要我们设置每次加载 7 层,就可以在 4090 上运行 DeepSeek-R1 的 681B 模型了。
五、实践
首先需要下载编译 llama.cpp 项目。llamacpp 是一个大模型推理项目,该项目使用 C++重写了大模型推理的代码,可以让我们在纯 CPU 模式下推理大模型,同时还可以使用 GPU 加速、逐层加载、提供 api 服务等,ollama 底层使用的就是 llamacpp。
这里以 Linux 环境为例,首先安装 llamacpp:
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 llama-gguf-split
cp llama.cpp/build/bin/llama-* llama.cpp
然后下载量化后的模型,可以使用 huggingface-cli 下载:
huggingface-cli download unsloth/DeepSeek-R1-GGUF --include *UD-IQ1_S*
也可以手动下载:huggingface.co/unsloth/Dee…
下载 DeepSeek-R1-UD-IQ1_S 目录下的文件。下载完成后直接运行 llamacpp 即可:
./llama.cpp/llama-cli \
--model DeepSeek-R1-GGUF/DeepSeek-R1-UD-IQ1_S/DeepSeek-R1-UD-IQ1_S-00001-of-00003.gguf \
--cache-type-k q4_0 \
--threads 16 \
--prio 2 \
--temp 0.6 \
--ctx-size 8192 \
--seed 3407 \
--n-gpu-layers 7 \
-no-cnv \
--prompt "<|User|>Create a Flappy Bird game in Python.<|Assistant|>"
这里需要指定--model、--n-gpu-layers、--prompt 三个参数,其中--n-gpu-layers 根据显卡显存指定,这里使用 4090 则设置为 7。