Skip to content

llamacpp_zh

ymcui edited this page Jan 23, 2024 · 16 revisions

使用llama.cpp量化部署

llama.cpp工具为例,介绍模型量化并在本地部署的详细步骤。Windows则可能需要cmake等编译工具的安装。本地快速部署体验推荐使用经过指令精调的Alpaca-2模型,有条件的推荐使用6-bit或者8-bit模型,效果更佳。 下面以中文Alpaca-2-7B模型为例介绍,运行前请确保:

  1. 系统应有make(MacOS/Linux自带)或cmake(Windows需自行安装)编译工具
  2. 建议使用Python 3.10以上编译和运行该工具

Step 1: 克隆和编译llama.cpp

  1. (可选)如果已下载旧版仓库,建议git pull拉取最新代码,并执行make clean进行清理
  2. 拉取最新版llama.cpp仓库代码
$ git clone https://github.com/ggerganov/llama.cpp
  1. 对llama.cpp项目进行编译,生成./main(用于推理)和./quantize(用于量化)二进制文件。
$ make

Windows/Linux用户如需启用GPU推理,则推荐与BLAS(或cuBLAS如果有GPU)一起编译,可以提高prompt处理速度。以下是和cuBLAS一起编译的命令,适用于NVIDIA相关GPU。参考:llama.cpp#blas-build

$ make LLAMA_CUBLAS=1

macOS用户无需额外操作,llama.cpp已对ARM NEON做优化,并且已自动启用BLAS。M系列芯片推荐使用Metal启用GPU推理,显著提升速度。只需将编译命令改为:LLAMA_METAL=1 make,参考llama.cpp#metal-build

$ LLAMA_METAL=1 make

Step 2: 生成量化版本模型

(💡 也可直接下载已量化好的gguf模型:gguf模型

目前llama.cpp已支持.pth文件以及huggingface格式.bin的转换。将完整模型权重转换为GGML的FP16格式,生成文件路径为zh-models/7B/ggml-model-f16.gguf。进一步对FP16模型进行4-bit量化,生成量化模型文件路径为zh-models/7B/ggml-model-q4_0.gguf。不同量化方法的性能对比见本Wiki最后部分。

$ python convert.py zh-models/7B/
$ ./quantize ./zh-models/7B/ggml-model-f16.gguf ./zh-models/7B/ggml-model-q4_0.gguf q4_0

Step 3: 加载并启动模型

由于本项目推出的Alpaca-2使用了Llama-2-chat的指令模板,请首先将本项目的scripts/llama-cpp/chat.sh拷贝至llama.cpp的根目录。chat.sh文件的内容形如,内部嵌套了聊天模板和一些默认参数,可根据实际情况进行修改。最新版llama.cpp已在转换模型时考虑了长上下文训练时的参数,因此加载长上下文版模型时无需手动设置--rope-scale参数。

  • GPU推理:cuBLAS/Metal编译需要指定offload层数,在./main中指定例如-ngl 40表示offload 40层模型参数到GPU
#!/bin/bash

# temporary script to chat with Chinese Alpaca-2 model
# usage: ./chat.sh alpaca2-ggml-model-path your-first-instruction

SYSTEM='You are a helpful assistant. 你是一个乐于助人的助手。'
FIRST_INSTRUCTION=$2

./main -m $1 \
--color -i -c 4096 -t 8 --temp 0.5 --top_k 40 --top_p 0.9 --repeat_penalty 1.1 \
--in-prefix-bos --in-prefix ' [INST] ' --in-suffix ' [/INST]' -p \
"[INST] <<SYS>>
$SYSTEM
<</SYS>>

$FIRST_INSTRUCTION [/INST]"

使用以下命令启动聊天。

$ chmod +x chat.sh
$ ./chat.sh zh-models/7B/ggml-model-q4_0.gguf '请列举5条文明乘车的建议'

在提示符 > 之后输入你的prompt,cmd/ctrl+c中断输出,多行信息以\作为行尾。如需查看帮助和参数说明,请执行./main -h命令。下面介绍一些常用的参数:

-c 控制上下文的长度,值越大越能参考更长的对话历史(默认:512)
-f 指定prompt模板,alpaca模型请加载prompts/alpaca.txt
-n 控制回复生成的最大长度(默认:128)
-b 控制batch size(默认:512)
-t 控制线程数量(默认:8),可适当增加
--repeat_penalty 控制生成回复中对重复文本的惩罚力度
--temp 温度系数,值越低回复的随机性越小,反之越大
--top_p, top_k 控制解码采样的相关参数

更详细的官方说明请参考:https://github.com/ggerganov/llama.cpp/tree/master/examples/main

关于量化方法选择及推理速度

下表给出了不同量化方法的相关统计数据供参考。推理模型为Chinese-LLaMA-2-7B,测试设备为M1 Max芯片(8x性能核心,2x能效核心),分别汇报CPU速度(8线程)和GPU速度,单位为ms/tok。速度方面报告的是eval time,即模型回复生成的速度。更多关于量化参数的介绍可参考llama.cpp量化统计表

相关结论:

  • 默认的量化方法为q4_0,虽然速度最快但损失也较大,推荐使用Q4_K作为替代
  • 线程数-t与物理核心数一致时速度最快,超过之后速度反而变慢(M1 Max上从8改到10之后耗时变为3倍)
  • 机器资源够用且对速度要求不是那么苛刻的情况下可以使用q8_0或Q6_K,非常接近F16模型的效果

测试命令:

$ ./perplexity -m zh-models/7B/ggml-model-q4_0.gguf -f test.txt -c 4096 -ngl 999

Chinese-LLaMA-2-7B

F16 Q2_K Q3_K Q4_0 Q4_1 Q4_K Q5_0 Q5_1 Q5_K Q6_K Q8_0
PPL 9.128 11.107 9.576 9.476 9.576 9.240 9.156 9.213 9.168 9.132 9.129
Size 12.91G 2.41G 3.18G 3.69G 4.08G 3.92G 4.47G 4.86G 4.59G 5.30G 6.81G
CPU Speed 117 42 51 39 44 43 48 51 50 54 65
GPU Speed 53 19 21 17 18 20 x x 25 26 x

Chinese-LLaMA-2-13B

F16 Q2_K Q3_K Q4_0 Q4_1 Q4_K Q5_0 Q5_1 Q5_K Q6_K Q8_0
PPL 8.810 12.804 9.738 9.371 9.549 8.952 8.988 8.924 8.858 8.820 8.811
Size 24.69G 5.26G 6.02G 7.01G 7.77G 7.48G 8.52G 9.28G 8.76G 10.13G 13.05G
CPU Speed - 75 90 76 80 80 91 99 92 104 125
GPU Speed - 31 37 30 32 36 x x 47 51 x

延伸用途:架设server

llama.cpp还提供架设server的功能,用于API调用、架设简易demo等用途。

运行以下命令启动server,二进制文件./server在llama.cpp根目录,服务默认监听127.0.0.1:8080。这里指定模型路径、上下文窗口大小。如果需要使用GPU解码,也可指定-ngl参数。

$ ./server -m ./zh-models/7B/ggml-model-q4_0.gguf -c 4096 -ngl 999

服务启动后,即可通过多种方式进行调用,例如利用curl命令。以下是一个示例脚本(同时存放在scripts/llamacpp/server_curl_example.sh),将Alpaca-2的模板进行包装并利用curl命令进行API访问。

# server_curl_example.sh

SYSTEM_PROMPT='You are a helpful assistant. 你是一个乐于助人的助手。'
# SYSTEM_PROMPT='You are a helpful assistant. 你是一个乐于助人的助手。请你提供专业、有逻辑、内容真实、有价值的详细回复。' # Try this one, if you prefer longer response.
INSTRUCTION=$1
ALL_PROMPT="[INST] <<SYS>>\n$SYSTEM_PROMPT\n<</SYS>>\n\n$INSTRUCTION [/INST]"
CURL_DATA="{\"prompt\": \"$ALL_PROMPT\",\"n_predict\": 128}"

curl --request POST \
    --url http://localhost:8080/completion \
    --header "Content-Type: application/json" \
    --data "$CURL_DATA"

例如,我们给出一个示例指令。

$ bash server_curl_example.sh '请列举5条文明乘车的建议'

稍后返回响应结果。

{
	"content": " 以下是五个文明乘车的建议:1)注意礼貌待人,不要大声喧哗或使用不雅用语;2)保持车厢整洁卫生,丢弃垃圾时要及时处理;3)不影响他人休息和正常工作时间,避免在车厢内做剧烈运动、吃零食等有异味的行为;4)遵守乘车纪律,尊重公共交通工具的规则和制度;5)若遇到突发状况或紧急情况,请保持冷静并配合相关部门的工作。这些建议旨在提高公民道德水平和社会文明程度,共同营造一个和谐、舒适的乘坐环境。",
	"generation_settings": {
		"frequency_penalty": 0.0,
		"ignore_eos": false,
		"logit_bias": [],
		"mirostat": 0,
		"mirostat_eta": 0.10000000149011612,
		"mirostat_tau": 5.0,
		"model": "zh-alpaca2-models/7b/ggml-model-q6_k.gguf",
		"n_ctx": 4096,
		"n_keep": 0,
		"n_predict": 128,
		"n_probs": 0,
		"penalize_nl": true,
		"presence_penalty": 0.0,
		"repeat_last_n": 64,
		"repeat_penalty": 1.100000023841858,
		"seed": 4294967295,
		"stop": [],
		"stream": false,
		"temp": 0.800000011920929,
		"tfs_z": 1.0,
		"top_k": 40,
		"top_p": 0.949999988079071,
		"typical_p": 1.0
	},
	"model": "zh-alpaca2-models/7b/ggml-model-q6_k.gguf",
	"prompt": " [INST] <<SYS>>\nYou are a helpful assistant. 你是一个乐于助人的助手。\n<</SYS>>\n\n请列举5条文明乘车的建议 [/INST]",
	"stop": true,
	"stopped_eos": true,
	"stopped_limit": false,
	"stopped_word": false,
	"stopping_word": "",
	"timings": {
		"predicted_ms": 3386.748,
		"predicted_n": 120,
		"predicted_per_second": 35.432219934875576,
		"predicted_per_token_ms": 28.2229,
		"prompt_ms": 0.0,
		"prompt_n": 120,
		"prompt_per_second": null,
		"prompt_per_token_ms": 0.0
	},
	"tokens_cached": 162,
	"tokens_evaluated": 43,
	"tokens_predicted": 120,
	"truncated": false
}

更详细的使用教程请访问:https://github.com/ggerganov/llama.cpp/tree/master/examples/server

Clone this wiki locally