GGUF_INSTALL_AND_TUNING.md 5.57 KB

Qwen3 GGUF 安装与调优手册

本文档只覆盖 qwen3_gguf 后端,目标机器为当前项目实测环境:

  • GPU: Tesla T4 16GB
  • CUDA: 12.8
  • 模型: DevQuasar/Qwen.Qwen3-Reranker-4B-GGUF
  • 量化: Q8_0

1. 结论先看

当前这套代码里,GGUF 后端的主要瓶颈不是“显存没吃满”,而是 llama.cpp 按 doc 顺序逐条打分。因此最有效的优化策略是:

  • 让模型层尽可能全部 offload 到 GPU
  • 打开 flash_attn / offload_kqv
  • n_ctx / n_batch / n_ubatch 调到一个对短标题重排更合适的高效点

本轮在当前机器上的推荐配置是:

qwen3_gguf:
  n_ctx: 512
  n_batch: 512
  n_ubatch: 512
  n_gpu_layers: 999
  n_threads: 2
  n_threads_batch: 4
  flash_attn: true
  offload_kqv: true
  infer_batch_size: 8
  sort_by_doc_length: true
  length_sort_mode: "char"

说明:

  • n_gpu_layers: 999 在 llama.cpp 中等价于“尽可能全部层都 offload”
  • 这台 T4 上,即使全量 offload,当前模型也只占到约 4.5 GiB GPU 显存
  • 所以“允许 8G 显存”并不会自动带来更高速度;这个模型/后端在当前工作负载下已经接近“该用到的权重都上 GPU 了”

2. 独立环境

qwen3_gguf 必须使用自己的独立 venv:

  • qwen3_vllm -> .venv-reranker
  • qwen3_gguf -> .venv-reranker-gguf

安装命令:

./scripts/setup_reranker_venv.sh qwen3_gguf

脚本现在会自动做两件事:

  1. 安装 GGUF 后端所需 Python 依赖
  2. 在检测到 /usr/local/cuda/bin/nvcc 时,把 llama-cpp-python 重编译成 CUDA 版

3. GPU 版验证

必须验证不是 CPU-only 版:

./.venv-reranker-gguf/bin/python - <<'PY'
import llama_cpp
print("supports_gpu_offload =", llama_cpp.llama_supports_gpu_offload())
PY

正确结果应为:

supports_gpu_offload = True

还可以看动态库:

ldd .venv-reranker-gguf/lib/python3.12/site-packages/llama_cpp/lib/libllama.so | rg 'cuda|cublas|ggml-cuda'

应能看到:

  • libggml-cuda.so
  • libcudart.so
  • libcublas.so

4. 模型下载

当前使用本地文件优先策略,模型放在:

models/reranker/qwen3-reranker-4b-gguf/Qwen.Qwen3-Reranker-4B.Q8_0.gguf

若本地文件存在,后端会直接加载本地 GGUF,不再依赖启动时在线下载。

为了避免当前机器上 Hugging Face Xet 下载的 416 Range Not Satisfiable 问题,start_reranker.sh 已对 qwen3_gguf 默认设置:

HF_HUB_DISABLE_XET=1

5. 本地调优脚本

新增本地基准脚本:

PYTHONPATH=/data/saas-search ./.venv-reranker-gguf/bin/python \
  scripts/benchmark_reranker_gguf_local.py --docs 64 --repeat 1

它会直接实例化 GGUF backend,输出:

  • 模型加载耗时
  • 当前进程 GPU 显存占用
  • 单次 rerank 延迟

6. 本轮实测结果

测试条件:

  • Query: 白色oversized T-shirt
  • Docs: 64 条商品标题
  • 本地脚本:scripts/benchmark_reranker_gguf_local.py
  • 每组 1 次,重点比较相对趋势

结果:

6.1 保守配置

n_ctx=384
n_batch=384
n_ubatch=128
n_gpu_layers=24
  • GPU 显存:2984 MiB
  • 64 docs 延迟:74347.91 ms

6.2 全量 offload

n_ctx=384
n_batch=384
n_ubatch=128
n_gpu_layers=999
  • GPU 显存:4338 MiB
  • 64 docs 延迟:51401.77 ms

6.3 最优配置

n_ctx=512
n_batch=512
n_ubatch=512
n_gpu_layers=999
  • GPU 显存:4564 MiB
  • 64 docs 延迟:49116.10 ms

6.4 其它尝试

n_threads=4 / n_threads_batch=8

  • GPU 显存:4564 MiB
  • 64 docs 延迟:49895.88 ms
  • 比推荐值略慢

infer_batch_size=64

  • GPU 显存:4564 MiB
  • 64 docs 延迟:50723.36 ms
  • 也略慢

6.5 API 级验证

在把推荐配置写入 config/config.yaml 并重启服务后,使用:

RERANK_BASE=http://127.0.0.1:6007 \
  ./.venv/bin/python scripts/benchmark_reranker_random_titles.py 64 --repeat 1 --query '白色oversized T-shirt'

得到:

  • 64 docs50177.22 ms

再用:

RERANK_BASE=http://127.0.0.1:6007 \
  ./.venv/bin/python scripts/benchmark_reranker_random_titles.py 153 --repeat 1 --query '白色oversized T-shirt'

得到:

  • 153 docs115328.60 ms

对比旧日志中的保守配置:

  • 旧配置 153 docs153435.37 ms
  • 新配置 153 docs115328.60 ms

改善幅度约:

  • 24.8%

7. 为什么没有吃到 8G

结论很重要:

  • 当前最优配置已经是“尽可能全量层 offload”
  • Q8_0 模型在这套 llama.cpp / T4 / 短文本重排场景下,实测只需要约 4.5 GiB GPU 显存
  • 继续为了“吃满 8G”去增大 n_ctx,不会明显提升吞吐,反而可能带来额外开销

所以本轮不是“显存太保守”,而是:

  • 可 offload 的权重已经基本 offload 完了
  • 真正拖慢响应的是 逐 doc 顺序推理 这一后端实现路径

8. 生产建议

8.1 当前建议

保留以下参数:

n_ctx: 512
n_batch: 512
n_ubatch: 512
n_gpu_layers: 999
n_threads: 2
n_threads_batch: 4
flash_attn: true
offload_kqv: true

8.2 如果还嫌慢

优先级建议:

  1. 缩小 rerank_window
  2. 减少传入 doc 数
  3. 若业务允许,切换到更适合高吞吐的后端

原因:

  • 当前 GGUF 后端是本地单进程、逐 doc 打分
  • 对长列表重排,它天然不如 vLLM / 云端 rerank API 擅长吞吐

9. 本轮落地文件

  • config/config.yaml
  • scripts/setup_reranker_venv.sh
  • scripts/start_reranker.sh
  • scripts/benchmark_reranker_gguf_local.py
  • reranker/GGUF_INSTALL_AND_TUNING.md