本文适用对象:高级水平
目标:编译HuggingFace的SafeTensor模型为Ollama可用模型
自从麦金叔写微信公众号以来得到很多朋友的鼓励和支持,那麦金叔也不能辜负网友粉丝的热情,后续会不定期出一些粉丝关心的问题进行答复。一定别忘了关注,以免错过精彩内容。
最近有网友问,同样的模型为什么使用官方API和本地Ollama出来的效果差距这么大?
要搞清楚这一点,就需要了解一下大模型基础的知识点。
01.
参数与量化
刚接触大语言模型的人,通常都比较关注参数量的大小。比如deepseek-r1-7b,就是指的70亿参数;qwen2.5vl:72b,则表示720亿参数。
人通常容易做数字大小的比较,所以直觉就知道参数越大,肯定表达的信息越多,那对应的模型理论上就越好。这没错,所以当DeepSeek出来之后,市场上所谓满血版一体机,才有人追捧。
但是,不是所有人都玩得起,那无疑就有点曲高和寡了。在应用的时候,为了性价比,就不能不关注另外一个指标:量化(Quantization)。
量化主要目的是节约显存、提升计算效率以及加快通信。
以deepseek-r1-7b模型为例,我们来看看不同的量化下对应模型文件大小和所需的显存。
_
|
FP32
| FP16 | Int8 |
Int4
| |
显存
|
28G
| 14G | 7G |
3.5G
|
所以使用更小量化的模型,就具备了如下的优势:
-
减少了模型的存储空间和显存的占用。
-
减少了显存和Tensorcore之间的数据传输量,从而加快模型推理时间。
-
加快了运算速度,从而缩短了模型推理时间。
但是,所有的好处不可能全占,有得必有失。带来的缺点就是精度损失,随着精度的降低,模型输出的准确度和精确度可能会下降,导致性能表现也不同程度下降。
02.
选择与应对
当你也遇到网友的困惑时,结合上面的基础概念,聪明的你大致已经知道问题的答案了。
当事情由多个因素共同决定时,就需要平衡利弊。
我们先看看Ollama的模型上的描述。
可以看到Ollama的deepseek-r1:32b使用的量化值为Q4\_K\_M,也就是4位量化类型,并结合了K/M参数策略。
Q4\_K\_M的核心特点:
-
4位量化:模型权重被压缩为4位表示,从而显著降低内存占用。相比于传统的16位浮点数(FP16),Q4_K_M的存储需求更低。
-
K参数:表示量化块的大小,例如将 128 个参数分组处理。这种分组优化可以减少量化误差。
-
M参数:采用混合精度策略(Mixed-precision),对重要的参数保留更高的位宽,以在压缩的同时尽量保留模型性能。
那如何解决既使用Ollama提供模型服务,又需要一个精度比较高的模型呢?麦金叔今天就给大家详细的讲一讲一定可行的方法。
首先需要一个工具,https://github.com/ggml-org/llama.cpp,下载项目之后,安装一下python库依赖,这个过程时间会比较长,需要耐心一点。在更新期间,可以开始第二步。
第二步,去https://hf-mirror.com/找到需要处理的模型(国内直接访问HuggingFace下载即使可以,也非常慢,所以需要通过镜像站),如https://hf-mirror.com/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B。 点进到Files and versions这里,将下方所有的文件都下载到本地电脑。注意.safetensors的文件会比较大,需要下载完整。
所有文件下载完毕后,放到一个目录下,备用。
第三步,llama.cpp的库更新完了之后,执行转换
python3 convert\_hf\_to\_gguf.py /path/to/local/safetensors-model --outtype f16
成功之后,会生成一个.gguf文件。
第四步,加载gguf进Ollama。先创建一个ModelFile,内容如下:
FROM /path/to/local/R1-Qwen-33B-F16.gguf
PARAMETER temperature 0.9
PARAMETER num_ctx 32768
SYSTEM You are Qwen, created by Alibaba Cloud. You are a helpful assistant.
TEMPLATE """
{{- if .System }}{{ .System }}{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1}}
{{- if eq .Role "user" }}<|User|>{{ .Content }}
{{- else if eq .Role "assistant" }}<|Assistant|>
{{- if and $.IsThinkSet (and $last .Thinking) -}}
<think>
{{ .Thinking }}
</think>
{{- end }}{{ .Content }}{{- if not $last }}<|end▁of▁sentence|>{{- end }}
{{- end }}
{{- if and $last (ne .Role "assistant") }}<|Assistant|>
{{- if and $.IsThinkSet (not $.Think) -}}
<think>
</think>
{{ end }}
{{- end -}}
{{- end }}
"""
PARAMETER stop "<|begin▁of▁sentence|>"
PARAMETER stop "<|end▁of▁sentence|>"
PARAMETER stop "<|User|>"
PARAMETER stop "<|Assistant|>"
接着执行:
ollama create my\_name\_model:32b -f ModelFile
现在可以通过ollama list查看或者ollama run来跑这个模型了。
网上的文章有说用ollama build的,直接就划走吧,早就不支持了。另外ModelFile中,必须有TEMPLATE和PARAMETER定义,否则不是加载出错,就是即使没错,实际运行也不正常。
上述的方法仅供参考,具体的量化参数和模型的参数模板需要自己根据项目的需要进行设置。
总结
今天的答疑来自网友的问题,虽然还没有彻底解决了大模型回答的精度问题,但是已经比ollama直接拉取的模型有了很大的改善。另外关于上下文长度的问题,也是在实际AI应用落地中常见的,如果输入内容特别长,比如40K,那给输出的空间就几乎没有了。需要对输入做拆分,来达到可用的目的。
麦金叔当初写这一些列的文章的时候,就没想着要搞知识付费,真心希望粉丝们,能都踏上AI应用的东风,为自己提高职场竞争力。当然,能顺手点个赞,收藏,转发一下,麦金叔也是非常高兴的。
往期回顾
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
如果你对AI的发展感兴趣,欢迎一键三连。有任何问题可以扫码添加好友,我们共同探讨。
