CPU 混合推理,非常见大模型量化方案:“二三五六” 位量化

本篇文章聊聊网上聊的比较少的具体量化操作,非常见整型位数的量化,来自让各种开源模型能够在 CPU 环境、CPU & GPU 环境混合推理的技术方案:llama.cpp 。

写在前面

接下来,有计划分享一些关于各种开源模型的实践内容。为了能让更多的同学能够玩起来,降低入门的硬件门槛还是很有必要的。模型量化技术就是这样一个“神奇、有效”的方案。

看过前两篇文章《零一万物模型折腾笔记:官方 Yi-34B 模型基础使用》、《本地运行“李开复”的零一万物 34B 大模型》的同学知道,类似 34B 的模型,如果想不怎么量化直接跑起来,大概需要 76~85GB 的显存。如果我们进行效果损失比较小的 8 位量化,那么也需要 46GB 左右,如果是 4 位量化模型,那么也需要 21GB 左右的显存。

虽然模型能跑了,但是有可能模型效果“打了骨折”

是的,模型的量化其实就是这样的一个,把类似我们相机拍摄照片(RAW),转换成“PNG”,再转换成“JPG”,最后甚至转换成“GIF”的过程。我们追求的是尽量省钱,在我们的设备上保持最好效果的将模型跑起来。尽量整个接近 “PNG” 的 “JPG”,而不是一定要折腾个 “GIF” 。

尤其是一般情况下,许多同学会使用八位(INT8)或者 四位(INT4)位量化,但是我们很容易会遇到两个尴尬的情况:

  • 有的模型量化成四位(INT4)效果变的不是很好,但是量化成八位(INT8)效果还行。可是八位(INT8)尺寸又太大,运行不太方便,希望模型尺寸能够小一些。
  • 有的模型量化成四位(INT4),模型还是太大,硬件跑不起来或者跑起来太费力,希望模型变的更小巧一些。

在今年早些时候的几篇文章和对外分享里,我曾经多次提到了几种不同的模型量化方案,包括 Transformers、GGML 等,感兴趣的同学可以自行翻阅,就不多赘述了。

本篇文章,我们主要来聊聊非常见整型位数的模型量化方案。用自己制作的量化程序,将原本在本地用游戏显卡跑不起来的 YI 34B 模型跑起来。

准备材料

关于模型量化需要准备两个素材,一个是模型,另外一个是量化使用的计算设备。

模型程序文件

任意参数量的模型,可以是 7B、13B、14B、20B、33B、34B、68B、70B …的模型,也可以是更小参数量的小尺寸的模型。

我这里使用的是零一万物开源的 YI-34B 的社区 finetune 微调训练的版本,通常情况下,社区可能有热门模型的量化版本,经常看到一些同学说“等个量化版本”。

但其实自己动手,丰衣足食。况且,即使是从社区下载量化版本,模型体积也很大,需要来来回回测试模型是否合适,重复下载也非常消耗时间和宽带成本,远不如自己量化来的方便。

关于模型程序下载,方法很多。如果你想要从 HuggingFace 相对快速下载模型,可以参考这篇文章中的 “模型程序下载” 来解决问题。

量化使用的硬件

而量化模型使用的硬件,需要 CPU 计算能力相对强一些的机器,如果你有 GPU,那么将会极大的提升模型量化速度,如果没有也没有关系。

至于量化后的产物,则是各种设备通用的,你可以在 Windows 量化后给 Linux 或者 macOS 设备使用。你也可以使用有 CPU 和 GPU 的设备,量化后给只有 CPU 的设备使用。

唯一有一些差异的,只有运行这个通用模型格式程序的启动程序,是需要和你当前的运行环境和操作系统有些关联的,比如需要构建,或者安装时需要一些初始化。

相比较模型,程序这个真的就是小意思啦。

模型的 GGUF (GGML Universal File)格式量化准备

GGUF 是 GGML 的全新替代型,被称为 GGML 通用文件格式。

GGUF 支持的模型量化格式非常多,刨除“几种跨开源生态模型转换的场景外”,主要依赖两个程序:convert.pyquantize 程序。前者以 Python 脚本的形态存在于 llama.cpp 项目的目录中,后者需要我们进行项目的构建。

下载 llama.cpp 的代码,然后就能够进行构建操作啦:

# 下载代码
git clone https://github.com/ggerganov/llama.cpp.git
# 切换工作目录到项目文件夹内
cd llama.cpp
# 构建项目可执行文件(有显卡)
make -j LLAMA_CUBLAS=1
# 构建项目执行文件 (没有显卡)
make -j

等待程序构建完毕,所有的准备工作就都完成啦。

预转换:Convert.py 转换脚本

这个脚本能够将非 GGML 格式的文件转换为 GGML,以 GGUF 后缀进行保存。程序默认支持转换下面几类格式的模型:*.pth*.pt*.bin*.safetensors

是我们进行后续非常见整型模型量化的基础操作步骤。

如果我们只追求使用 8 位量化的,可以使用 CPU 和 GPU 混合推理的模型,那么我们可以参考这篇文章中的“尝试对模型进行几种不同的量化操作”的方法中的命令行参数,将模型转换为 GGML 的 q8_0 模型。

但如果,我们希望制作更多其他的不同的类型的模型,比如 2 位量化~ 6 位量化,那么我非常建议大家使用 convert.py 脚本制作和转换一个 f16 类型的 GGML 模型。

虽然程序的命令行参数看起来很麻烦,但是我们需要使用到的转换命令其实非常简单,使用 Python 调用程序,命令中携带“模型路径”和“输出的模型类型”即可:

python ./convert.py 【模型的路径】 --outtype f16

我这里以 YI-34B 的社区 finetune 模型 brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties 为例子,调整为我自己的模型存放路径:

python ./convert.py ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ --outtype f16

执行命令后,机器将会火力全开的进行程序编译,输出大量日志:

Loading model file ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/model-00001-of-00008.safetensors
Loading model file ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/model-00001-of-00008.safetensors
Loading model file ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/model-00002-of-00008.safetensors
...params = Params(n_vocab=64000, n_embd=7168, n_layer=60, n_ctx=200000, n_ff=20480, n_head=56, n_head_kv=8, f_norm_eps=1e-05, rope_scaling_type=None, f_rope_freq_base=5000000.0, f_rope_scale=None, n_orig_ctx=None, rope_finetuned=None, ftype=<GGMLFileType.MostlyF16: 1>, path_model=PosixPath('../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties'))
Loading vocab file '../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/tokenizer.model', type 'spm'
Permuting layer 0
Permuting layer 1
Permuting layer 2
...model.embed_tokens.weight                        -> token_embd.weight                        | BF16   | [64000, 7168]
model.layers.0.input_layernorm.weight            -> blk.0.attn_norm.weight                   | BF16   | [7168]
...Writing ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf, format 1
gguf: This GGUF file is for Little Endian only
gguf: Setting special token type bos to 1
gguf: Setting special token type eos to 2
gguf: Setting special token type unk to 0
gguf: Setting special token type pad to 0
[  1/543] Writing tensor token_embd.weight                      | size  64000 x   7168  | type F16  | T+   1
[  2/543] Writing tensor blk.0.attn_norm.weight                 | size   7168           | type F32  | T+   2
[  3/543] Writing tensor blk.0.ffn_down.weight                  | size   7168 x  20480  | type F16  | T+   2
...Wrote ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf

当一切都结束后,我们能够看到类似上面日志的最后一行提示,告诉我们转换好的模型名字和存放到机器的什么位置了。默认会存放于你指定要转换模型的目录,并以 .gguf 后缀保存文件。

最终转换:quantize 量化程序

当我们使用上面的方法,将模型转换为了相对高精度的模型文件后,我们就可以进行下一步量化了。

执行 ./quantize --help,除了程序的执行命令格式参考外,我们还能够看到量化程序支持的所有类型:

Allowed quantization types:2  or  Q4_0   :  3.56G, +0.2166 ppl @ LLaMA-v1-7B3  or  Q4_1   :  3.90G, +0.1585 ppl @ LLaMA-v1-7B8  or  Q5_0   :  4.33G, +0.0683 ppl @ LLaMA-v1-7B9  or  Q5_1   :  4.70G, +0.0349 ppl @ LLaMA-v1-7B10  or  Q2_K   :  2.63G, +0.6717 ppl @ LLaMA-v1-7B12  or  Q3_K   : alias for Q3_K_M11  or  Q3_K_S :  2.75G, +0.5551 ppl @ LLaMA-v1-7B12  or  Q3_K_M :  3.07G, +0.2496 ppl @ LLaMA-v1-7B13  or  Q3_K_L :  3.35G, +0.1764 ppl @ LLaMA-v1-7B15  or  Q4_K   : alias for Q4_K_M14  or  Q4_K_S :  3.59G, +0.0992 ppl @ LLaMA-v1-7B15  or  Q4_K_M :  3.80G, +0.0532 ppl @ LLaMA-v1-7B17  or  Q5_K   : alias for Q5_K_M16  or  Q5_K_S :  4.33G, +0.0400 ppl @ LLaMA-v1-7B17  or  Q5_K_M :  4.45G, +0.0122 ppl @ LLaMA-v1-7B18  or  Q6_K   :  5.15G, -0.0008 ppl @ LLaMA-v1-7B7  or  Q8_0   :  6.70G, +0.0004 ppl @ LLaMA-v1-7B1  or  F16    : 13.00G              @ 7B0  or  F32    : 26.00G              @ 7BCOPY   : only copy tensors, no quantizing

这里,我建议始终使用 Q4_KQ5_K 这类代指名称来进行模型转换,并且在进行转换之前,偶尔执行 ./quantize --help 看看有没有新的、更适合你的量化方案。名称中的 Q数字 中的数字就是对应的量化的位数啦。

一般来说,位数越高,需要的内存和显存就越多,运行起来越慢,但是效果和精度就越接近原始版本。反之,我们虽然得到了省资源的版本,但是效果会有明显的降低。不过,如果你模型跑不起来,效果是零,这种情况下能够量化跑起来的模型,总归是比没有强,某种程度来说,也是不得已而为之。

帮助信息中展示的如何使用命令行的演示信息,同样是内容比较多比较复杂的。但是同样的,我们实际只需要非常简单的使用方法,记住下面的调用方式就足够了:

./quantize 【模型地址】【模型类型名称】

如果我们将命令中的“变量”进行替换,改成本文中我使用的模型和我选择的量化方案,命令行如下:

./quantize ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf Q5_K_M

命令执行过程中,我们将看到滚动的日志:

ggml_init_cublas: GGML_CUDA_FORCE_MMQ:   no
ggml_init_cublas: CUDA_USE_TENSOR_CORES: yes
ggml_init_cublas: found 1 CUDA devices:Device 0: NVIDIA GeForce RTX 4090, compute capability 8.9
main: build = 1622 (8a7b2fa)
main: built with cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 for x86_64-linux-gnu
main: quantizing '../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf' to '../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-Q5_K_M.gguf' as Q5_K_M
llama_model_loader: loaded meta data with 20 key-value pairs and 543 tensors from ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf (version GGUF V3 (latest))
llama_model_loader: - tensor    0:                token_embd.weight f16      [  7168, 64000,     1,     1 ]
llama_model_loader: - tensor    1:           blk.0.attn_norm.weight f32      [  7168,     1,     1,     1 ]
...
llama_model_loader: - tensor  542:               output_norm.weight f32      [  7168,     1,     1,     1 ]
llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output.
llama_model_loader: - kv   0:                       general.architecture str              = llama
llama_model_loader: - kv   1:                               general.name str              = brucethemoose
llama_model_loader: - kv   2:                       llama.context_length u32              = 200000
llama_model_loader: - kv   3:                     llama.embedding_length u32              = 7168
...
[ 541/ 543]               blk.59.ffn_down.weight - [20480,  7168,     1,     1], type =    f16, quantizing to q6_K .. size =   280.00 MiB ->   114.84 MiB | hist: 
[ 542/ 543]               blk.59.ffn_norm.weight - [ 7168,     1,     1,     1], type =    f32, size =    0.027 MB
[ 543/ 543]                   output_norm.weight - [ 7168,     1,     1,     1], type =    f32, size =    0.027 MB
llama_model_quantize_internal: model size  = 65593.31 MB
llama_model_quantize_internal: quant size  = 23193.68 MBmain: quantize time = 99803.07 ms
main:    total time = 99803.07 ms

转换完毕,我们前往模型的目录,查看文件大小,能够看到非常明显的尺寸缩减:

# du -hs *
23G	ggml-model-Q5_K_M.gguf
65G	ggml-model-f16.gguf

至于模型的使用,就太简单啦。

我们可以使用 llama.cpp 项目中的 mainserver 来运行模型,前者会在命令行中启动一个交互式的终端,后者则会启动一个简洁的 Web UI,我们在浏览器中就可以轻松的调节模型的调用参数。

在前两篇相关的文章中有提到过,这里我们再聊一次,顺便聊聊不同的参数的选择和调整策略。

我一般的“起手式”是这样:

./server --ctx-size 2048 --host 0.0.0.0 --n-gpu-layers 50 --model ../playground/01-ai/Yi-34B/ggml-model-q8_0.gguf

上面的命令中,分别包含了:

  • --ctx-size” 指定模型会话窗口大小,所能容纳和使用的 Token 数量,这里如果想省点显存和内存,就设置小一些,能够满足你的任务需要就好。如果资源比较多,可以开到模型的上限,比如最近的默认模型都是 4k 的,就设置 4096,8K 就设置 8192,200K 就设置个 200000,以此类推。
  • --host” 默认其实可以不添加,但是如果你在局域网,或者你的服务运行在容器里,那么你需要分享或者在容器外访问,设置 --host 0.0.0.0 就很有必要啦。
  • --n-gpu-layers” 这个参数需要配合显卡一起使用,如果你有显卡,但是显卡装不下模型,或者装下模型后快满了,可以考虑适当调整下数值,根据自己的需求,将合适的模型层数扔到显卡里,稍微给显卡留点富余量。扔到显卡里的模型层数越多,推理速度越快。
  • --model” 这个参数没有什么特别的,指定我们下载或者转换好的 GGML 模型文件就好。

好啦,当这个命令执行后,我们就能够快乐的和模型一起玩耍啦。

使用量化后的 Yi-34B 进行角色扮演游戏

是不是很有趣,后面有机会我们聊聊上面这个交互体验是如何实现的。

最后

这篇内容就先写到这里,接下来的相关文章,我们来聊聊社区里不同优化方向和模型的模型们。

希望大家玩模型,都能玩的开心。感谢所有为开源模型辛苦工作的模型创作者团队,和所有为开源社区摇旗呐喊,将好的东西分享给更多的人的朋友们。

–EOF


本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2023年12月12日
统计字数: 8528字
阅读时间: 18分钟阅读
本文链接: https://soulteary.com/2023/12/12/cpu-hybrid-inference-unusual-large-language-model-quantization-2-3-5-6-bit-quantization.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/215294.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装ThingBox Eclipse Plugin

1. ChatGPT问 The latest version of the ThingBox Eclipse Plugin requires Eclipse IDE 2021-06 or later. 2. PTC官网下载 MED-61378-CD-092_F000_Eclipse-Plugin-9-0-1.zip文件, 和 MED-61098-CD-085_F000_ThingWorx-Extension-SDK-8-5-0&#xff08;需要账号&#xff09…

虚拟化逻辑架构:KVM虚拟机通过OVS端口组实现网络连接

目录 一、实验 1.CentOS 7 安装 OpenVSwitch(构建RPM安装包&#xff09; 2.KVM虚拟机通过OVS端口组实现网络连接 二、问题 1.安装openvswitch-2.5.10报错 2.virt-install未找到命令 3.如何删除自定义网络 一、实验 1.CentOS 7 安装 OpenVSwitch(构建RPM安装包&#xff…

创建一个有阴影的threejs三维几何体

import * as THREE from "three" import { OrbitControls } from three/examples/jsm/controls/OrbitControlsconst width window.innerWidth; const height window.innerHeight;//创建场景 const scene new THREE.Scene(); scene.background new THREE.Color(#6…

LinuxBasicsForHackers笔记 --Python 脚本基础

添加Python模块 Python 有一个专门用于安装和管理 Python 包的包管理器&#xff0c;称为 pip&#xff08;Pip Installs Packages&#xff09;。由于我们在这里使用 Python 3&#xff0c;因此您将需要 Python 3 的 pip 来下载和安装软件包。默认情况下应包含 Pip&#xff0c;但…

vue前端访问Django channels WebSocket失败

现象 前端报错&#xff1a;SSH.vue:51 WebSocket connection to ‘ws://127.0.0.1:8000/server/terminal/120.59.88.26/22/1/’ failed: 后端报错&#xff1a;Not Found: /server/terminal/120.79.83.26/22/1/ 原因 django的版本与channels的版本不匹配&#xff08;django…

关于个人职业选择

职业选择&#xff0c;一直是个老生常谈的话题。这并不是一个容易做的决定。 让我们来看看AI怎么说。 首先是方向性的回答&#xff1a; 然后是一些具体的回答 我个人比较倾向于深耕网络安全。这是一个很有趣也是一个持续发展着的领域。 不知道关于这个事情你怎么看&#xff0…

在线学习平台-课程分页、用户管理、教师查询

在线学习平台------手把手教程&#x1f448; 用户管理 添加功能增强 新增属性 若依里的用户模块(SysUser)是没有课程这一属性的,要实现我们自己的课程分页查询功能 这个位置传入的实体类SysUser要加上classId,记得加上get、set方法 更改sql语句 ctrl 鼠标左键不断点进去…

DS二叉排序树之删除

Description 给出一个数据序列&#xff0c;建立二叉排序树&#xff0c;并实现删除功能 对二叉排序树进行中序遍历&#xff0c;可以得到有序的数据序列 Input 第一行输入t&#xff0c;表示有t个数据序列 第二行输入n&#xff0c;表示首个序列包含n个数据 第三行输入n个数据…

蓝桥杯周赛 第 1 场 强者挑战赛 6. 小球碰撞【算法赛】(思维题/最长上升子序列LIS)

题目 https://www.lanqiao.cn/problems/9494/learning/?contest_id153 思路来源 Aging代码 题解 二分时间t&#xff0c;第i个小球对应一个起点pi、终点pit*vi的区间&#xff0c;问题转化为&#xff0c; 选最多的区间&#xff0c;使得不存在区间包含&#xff08;即li<l…

微信小程序过滤器之计算当前时间差

微信小程序过滤器之计算当前时间差 前言一、wxs简介二、使用步骤1.定义2.使用 前言 最近遇到了一个需求&#xff0c;将小程序里面的具体时间2023-12-11 09:41:06转为当前时间差10小时前&#xff0c;这块可以使用js逻辑函数对数据进行处理&#xff0c;但这里我们采用微信小程序…

Error: Failed to resolve vue/compiler-sfc——vite项目启动报错——npm run serve

运行项目时&#xff0c;报错如下&#xff1a; Error: Failed to resolve vue/compiler-sfc 根据报错信息的提示&#xff1a;vue的版本必须大于3.2.25&#xff0c;经过查看package.json文件&#xff0c;可以看到vue的版本为3.2.36&#xff0c;是满足条件的。 因此考虑缓存问题&…

【OPNEGIS】Geoserver原地升级jetty,解决Apache HTTP/2拒绝服务漏洞 (CVE-2023-44487)

Geoserver是我们常用的地图服务器&#xff0c;在开源系统中的应用比较广泛。在实际环境中&#xff0c;我们可能会选用官方的二进制安装包进行部署&#xff0c;这样只要服务器上有java环境就可以运行&#xff0c;方便在现场进行部署。 1.问题来源 这次由于甲方一月一次的漏洞扫…

智能优化算法应用:基于阴阳对算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于阴阳对算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于阴阳对算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.阴阳对算法4.实验参数设定5.算法结果6.参考文…

Java - Mybatis的缓存机制、集成SpringBoot后缓存相关问题

mybaits提供一级缓存&#xff0c;和二级缓存 一级缓存&#xff08;默认开启&#xff09; 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象&#xff0c;在对象中有一个(内存区域)数据结构&#xff08;HashMap&#xff09;用于存储缓存数据。不同的sqlSe…

STM32F407-14.3.1-01 时基单元

时基单元 可编程高级控制定时器的主要模块是一个 16 位计数器及其相关的自动重载寄存器。计数器可递增计数、递减计数或交替进行递增和递减计数。计数器的时钟可通过预分频器进行分频。 计数器、自动重载寄存器和预分频器寄存器可通过软件进行读写。即使在计数器运行时也可执行…

Python:核心知识点整理大全14-笔记

目录 ​编辑 7.2.2 让用户选择何时退出 parrot.py 7.2.3 使用标志 7.2.4 使用 break 退出循环 cities.py 7.2.5 在循环中使用 continue counting.py 7.2.6 避免无限循环 counting.py 7.3 使用 while 循环来处理列表和字典 7.3.1 在列表之间移动元素 confirmed_user…

数字图像处理(实践篇)二十二 使用opencv进行人脸、眼睛、嘴的检测

目录 1 xml文件 2 涉及的函数 3 实践 使用opencv进行人脸、眼睛、嘴的检测。 1 xml文件 方法① 下载 地址&#xff1a;https://github.com/opencv/opencv/tree/master/data/haarcascades 点击haarcascade_frontalface_default.xml文件 对着Raw右键&#xff0c;选择“链接…

【JVM从入门到实战】(二)字节码文件的组成

一、Java虚拟机的组成 二、字节码文件的组成 字节码文件的组成 – 应用场景 字节码文件的组成部分-Magic魔数 什么是魔数&#xff1f; Java字节码文件中的魔数 文件是无法通过文件扩展名来确定文件类型的&#xff0c;文件扩展名可以随意修改&#xff0c;不影响文件的内容。…

UE引擎 LandscapeGrass 实现机制分析(UE5.2)

前言 随着电脑和手机硬件性能越来越高&#xff0c;游戏越来越追求大世界&#xff0c;而大世界非常核心的一环是植被&#xff0c;目前UE5引擎提供给植被生成的主流两种方式为 手刷植被和LandscapeGrass(WeightMap程序化植被)。当然UE5.3推出新一代PCGFramework 节点程序化生成框…

MyBatis:缓存

MyBatis 缓存一级缓存二级缓存注 缓存 缓存&#xff0c;是数据交换的缓冲区&#xff08;临时保存数据的地方&#xff09;。即将数据&#xff08;数据一般为频繁查询且不易改变&#xff09;保存在计算机内存中&#xff0c;下次读取数据时直接从内存中获取&#xff0c;以避免频繁…