本文涉及到的详细测试代码和测试步骤放置于:
https://github.com/xinyuwei-david/david-share.git下的:Deep-LearningsGGUF-LoRA
本文中不再赘述代码实现。欢迎给repo点亮Star,您的点赞是作者持续创作的动力。
近年来,大型语言模型(LLM)在自然语言处理领域取得了巨大进展。然而,这些模型通常拥有数以亿计甚至数以千亿计的参数,导致它们在训练和推理时对计算资源的需求非常高。这对于许多资源有限的开发者来说,是一个巨大的挑战。
为了解决这个问题,研究者们提出了多种方法来降低模型的计算和存储成本。其中,模型量化和参数高效微调(如LoRA)是两种非常有用的技术。在本文中,我们将详细介绍如何在CPU上使用GGUF格式的LoRA适配器,以实现对大型语言模型的高效推理。
一、背景知识
1. GGUF格式是什么?
GGUF是一种用于存储量化大型语言模型的二进制文件格式,旨在高效存储模型并加速加载过程。它将模型推理所需的一切内容(包括模型权重、分词器、配置文件等)打包到一个文件中。这对于在**资源受限的环境(如CPU)**上进行快速推理非常有帮助。
2. 什么是LoRA?
LoRA(Low-Rank Adaptation)是一种参数高效的微调方法。传统的模型微调需要更新和存储模型的全部参数,这对大型模型来说非常耗费资源。LoRA通过引入低秩矩阵来更新模型的权重,大大减少了需要训练和存储的参数数量。这使得在普通硬件上微调大型模型成为可能。
3. 为什么要在CPU上使用GGUF格式的LoRA适配器?
将LoRA适配器转换为GGUF格式并与基础模型一起加载,有以下几个优点:
高效存储:GGUF格式经过优化,可以更紧凑地存储模型。
快速加载:在推理时,GGUF格式的模型可以更快速地加载,减少启动时间。
资源节约:在CPU上进行推理,无需高端GPU,降低了硬件成本。
推理速度快:GGUF格式对推理进行了优化,即使在CPU上也能获得较快的推理速度。
二、GGUF格式如何加速推理?
在深入实践之前,让我们先了解一下为什么GGUF格式能够显著提高推理速度。
1. 高效的二进制格式
GGUF采用了优化的二进制存储方式,能够快速读取和解析模型权重。这减少了模型加载的开销,加快了推理启动的速度。
2. 一体化的模型文件
GGUF格式将模型所需的所有组件(包括模型权重、分词器、配置文件等)打包在一个文件中。这避免了加载多个文件带来的I/O开销,进一步提升了加载速度。
3. 支持模型量化
GGUF格式支持多种量化精度(如FP16、INT8、INT4等)。通过量化,可以大幅减少模型权重的尺寸,降低内存占用和计算复杂度,从而加速推理过程。
4. 优化的内存访问
在推理过程中,GGUF格式的数据排列方式优化了内存访问模式,减少了缓存未命中和内存带宽的瓶颈,提高了CPU的计算效率。
5. 专为CPU推理设计
GGUF格式特别适合在CPU上运行模型,例如搭配llama.cpp
。它利用了CPU架构的特性,避免了一些GPU特有的优化,从而在CPU上获得更好的性能表现。
实际效果:
使用GGUF格式的模型时,模型加载速度更快,推理延迟更低。
在没有高性能GPU的情况下,GGUF格式可以让我们在普通计算机上运行大型语言模型,获得可接受的响应速度。
许多开发者报告称,在使用GGUF格式的量化模型(如INT4量化)时,能够在CPU上实现接近实时的推理。
三、传统方法:合并LoRA适配器并转换为GGUF格式
在实践中,最初使用LoRA适配器的流程通常是:
训练LoRA适配器:在基础模型上进行微调,得到LoRA适配器。
合并适配器和基础模型:使用工具将LoRA适配器的权重与基础模型的权重合并。
转换为GGUF格式:将合并后的模型转换为GGUF格式,供推理使用。
问题
这种方法的问题在于:
不灵活:每当有新的LoRA适配器时,都需要重新进行合并和转换,耗时耗力。
占用更多存储空间:每个合并后的模型都是完整的模型,占用大量磁盘空间。
操作复杂:对于每个新任务,都需要重复类似的步骤,不利于快速迭代。
四、新方法:分别转换基础模型和LoRA适配器为GGUF格式
为了克服上述问题,我们可以采用一种更灵活的方法:
转换基础模型为GGUF格式:将基础模型转换为GGUF格式。
转换LoRA适配器为GGUF格式:单独将LoRA适配器转换为GGUF格式。
在推理时一起加载:在推理时,同时加载基础模型和LoRA适配器。
优点
灵活性:可以在推理时自由切换不同的LoRA适配器,无需重新合并模型。
节省存储空间:LoRA适配器通常很小,占用的存储空间可以忽略不计。
操作简便:减少了合并模型的步骤,降低了操作复杂度。
推理速度快:利用GGUF格式的优势,即使在CPU上也能获得较好的推理速度。
操作步骤详解
以下,我们将详细介绍如何在实践中实现上述流程。
1. 将基础模型转换为GGUF格式
步骤:
下载基础模型:从Hugging Face或其他平台下载预训练的基础模型。
使用转换脚本:使用
llama.cpp
提供的convert_hf_to_gguf.py
脚本。
示例代码:
python convert_hf_to_gguf.py /path/to/your/base_model \
--outfile /path/to/output/base_model.gguf \
--outtype f16
/path/to/your/base_model
:您的基础模型的目录路径。/path/to/output/base_model.gguf
:转换后GGUF模型的保存路径。--outtype f16
:指定模型的精度为FP16。
2. 将LoRA适配器转换为GGUF格式
步骤:
训练LoRA适配器:使用PyTorch等深度学习框架,在基础模型上进行LoRA微调。
使用转换脚本:使用
llama.cpp
提供的convert_lora_to_gguf.py
脚本。
示例代码:
# 转换LoRA适配器为GGUF格式
python convert_lora_to_gguf.py \
--outfile /path/to/output/lora_adapter.gguf \
--outtype f16 \
/path/to/your/lora_adapter
/path/to/your/lora_adapter
:您的LoRA适配器的目录路径。/path/to/output/lora_adapter.gguf
:转换后GGUF LoRA适配器的保存路径。
注意事项:确保LoRA适配器和基础模型是兼容的,即基于同一架构和版本。
当前的转换脚本不支持包含词嵌入和语言模型头的LoRA适配器。
3. 在推理时一起加载基础模型和LoRA适配器
步骤:
使用llama.cpp进行推理:llama.cpp支持同时加载基础模型和LoRA适配器。
示例代码:
# 使用llama.cpp的推理程序
./main \
-m /path/to/output/base_model.gguf \
--lora /path/to/output/lora_adapter.gguf
解释:
-m
指定基础模型的路径。--lora
指定LoRA适配器的路径。
当使用 GGUF 格式的基础模型和 LoRA 适配器时,二者的数据类型(例如精度或量化级别)最好保持一致。
五、两种方法的对比
1. 灵活性
分别转换并加载:可以随时更换LoRA适配器,适用于需要频繁切换任务的场景。
合并后转换:每次更换适配器都需要重新合并,不够灵活。
2. 存储空间
分别转换并加载:只需存储一个基础模型和多个小的LoRA适配器文件。
合并后转换:每个合并后的模型都是完整的模型,占用大量存储空间。
3. 操作复杂度
分别转换并加载:减少了合并模型的步骤,操作更简便。
合并后转换:需要更多的步骤,操作复杂度更高。
4. 推理速度
两种方法在推理速度和性能上基本一致。由于GGUF格式优化了推理速度,无论是否合并,加载到内存后的计算都是高效的。
5. 适用场景
分别转换并加载:适用于不包含词嵌入和语言模型头的LoRA适配器,以及需要经常更换适配器的场景。
合并后转换:适用于包含额外模块的LoRA适配器,或只针对特定任务的场景。
六、注意事项和建议
1. LoRA适配器的限制
当前的convert_lora_to_gguf.py
脚本不支持包含embed_tokens
和lm_head
模块的LoRA适配器。如果您的适配器包含这些模块,建议使用合并后转换的方法。
2. 关于QLoRA适配器
如果您的LoRA适配器是使用QLoRA方法微调的(即在量化的基础模型上进行微调),直接将适配器转换为GGUF并与不同量化配置的基础模型一起加载,可能会导致性能下降。建议在与微调时相同的量化配置下进行操作。
3. 模型和适配器的兼容性
确保您的基础模型和LoRA适配器基于相同的模型架构和版本。如果不兼容,可能会导致推理失败或结果不准确。
4. 量化和精度选择
基础模型:可以选择适当的量化方案(如
q4_0
、q5_1
等)以减少内存占用。LoRA适配器:由于体积较小,通常使用FP16精度,无需进一步量化。
5. GGUF的优势
正如前文提到的,GGUF格式在推理速度方面具有显著的优势。通过优化的存储方式和对量化的支持,GGUF能够让大型语言模型在CPU上实现快速、高效的推理。这使得在资源受限的环境中运行复杂的模型成为可能。
七、实践案例
假设您有一个基础模型和多个LoRA适配器,希望在CPU上高效地进行不同任务的推理。
步骤:
将基础模型转换为GGUF格式,并存储在固定位置。
将所有的LoRA适配器分别转换为GGUF格式。
在需要进行推理时,根据任务加载对应的LoRA适配器,无需重新合并模型。
优势:
您只需要保存一个基础模型,节省了存储空间。
可以快速切换任务,提升了开发和部署的效率。
由于GGUF格式的优化,即使在CPU上,推理速度也能满足需求。