bitsandbytes
bitsandbytes 是将模型量化为 8 位和 4 位的最简单选项。8 位量化将 fp16 中的异常值与 int8 中的非异常值相乘,将非异常值转换回 fp16,然后将它们加在一起以返回 fp16 中的权重。这减少了异常值对模型性能的降级影响。4 位量化进一步压缩模型,它通常与 QLoRA 一起用于微调量化的 LLMs。
要使用 bitsandbytes,请确保已安装以下库
pip install transformers accelerate bitsandbytes>0.37.0
bitsandbytes 正在重构以支持除 CUDA 之外的多个后端。目前,ROCm(AMD GPU)和 Intel CPU 实现已经成熟,Intel XPU 正在开发中,预计 Apple Silicon 支持将在 Q4/Q1 提供。有关安装说明和最新的后端更新,请访问 此链接。
我们非常重视您的反馈,以便在正式发布前识别出错误!查看这些文档以获取更多详细信息和反馈链接。
现在,您可以通过将BitsAndBytesConfig
传递给from_pretrained()方法来量化模型。这适用于任何模态的任何模型,只要它支持使用Accelerate加载并包含torch.nn.Linear
层。
将模型量化为8位可以将内存使用量减少一半,对于大型模型,设置device_map="auto"
可以有效地利用可用的GPU。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model_8bit = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-1b7",
quantization_config=quantization_config
)
默认情况下,所有其他模块(例如torch.nn.LayerNorm
)都转换为torch.float16
。如果需要,您可以使用torch_dtype
参数更改这些模块的数据类型。
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model_8bit = AutoModelForCausalLM.from_pretrained(
"facebook/opt-350m",
quantization_config=quantization_config,
torch_dtype=torch.float32
)
model_8bit.model.decoder.layers[-1].final_layer_norm.weight.dtype
将模型量化为8位后,除非您使用最新版本的Transformers和bitsandbytes,否则无法将量化权重推送到Hub。如果您拥有最新版本,则可以使用push_to_hub()方法将8位模型推送到Hub。首先推送量化配置文件config.json,然后推送量化模型权重。
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-560m",
quantization_config=quantization_config
)
tokenizer = AutoTokenizer.from_pretrained("bigscience/bloom-560m")
model.push_to_hub("bloom-560m-8bit")
仅支持使用8位和4位权重训练额外的参数。
您可以使用get_memory_footprint
方法检查内存占用。
print(model.get_memory_footprint())
量化模型可以从from_pretrained()方法加载,无需指定load_in_8bit
或load_in_4bit
参数。
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("{your_username}/bloom-560m-8bit", device_map="auto")
8位 (LLM.int8() 算法)
在此博文中了解有关8位量化详细信息的更多信息!
本节探讨了8位模型的一些特定功能,例如卸载、异常值阈值、跳过模块转换和微调。
卸载
8位模型可以在CPU和GPU之间卸载权重,以支持将非常大的模型放入内存中。分配到CPU的权重实际上存储在float32中,并且不会转换为8位。例如,要为bigscience/bloom-1b7模型启用卸载,首先创建一个BitsAndBytesConfig
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(llm_int8_enable_fp32_cpu_offload=True)
设计一个自定义设备映射,以将所有内容都放入您的GPU中,除了lm_head
,您将将其分配到CPU。
device_map = {
"transformer.word_embeddings": 0,
"transformer.word_embeddings_layernorm": 0,
"lm_head": "cpu",
"transformer.h": 0,
"transformer.ln_f": 0,
}
现在使用自定义device_map
和quantization_config
加载您的模型。
model_8bit = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-1b7",
device_map=device_map,
quantization_config=quantization_config,
)
异常值阈值
“异常值”是指大于某个阈值的隐藏状态值,这些值以fp16计算。虽然这些值通常是正态分布的([-3.5, 3.5]),但对于大型模型,这种分布可能会有很大差异([-60, 6] 或 [6, 60])。8位量化对于约为5的值效果很好,但超出此范围,性能会显著下降。一个好的默认阈值是6,但对于更不稳定的模型(小型模型或微调),可能需要更低的阈值。
要找到模型的最佳阈值,我们建议您尝试BitsAndBytesConfig中的llm_int8_threshold
参数。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
model_id = "bigscience/bloom-1b7"
quantization_config = BitsAndBytesConfig(
llm_int8_threshold=10,
)
model_8bit = AutoModelForCausalLM.from_pretrained(
model_id,
device_map=device_map,
quantization_config=quantization_config,
)
跳过模块转换
对于某些模型,例如Jukebox,您不需要将每个模块都量化为8位,这实际上会导致不稳定。对于Jukebox,有一些lm_head
模块应该使用BitsAndBytesConfig中的llm_int8_skip_modules
参数跳过。
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
model_id = "bigscience/bloom-1b7"
quantization_config = BitsAndBytesConfig(
llm_int8_skip_modules=["lm_head"],
)
model_8bit = AutoModelForCausalLM.from_pretrained(
model_id,
device_map="auto",
quantization_config=quantization_config,
)
微调
使用PEFT库,您可以使用8位量化来微调大型模型,例如flan-t5-large和facebook/opt-6.7b。您不需要为训练传递device_map
参数,因为它会自动将模型加载到GPU上。但是,如果需要,您仍然可以使用device_map
参数自定义设备映射(device_map="auto"
仅应用于推理)。
4位 (QLoRA 算法)
本节探讨了4位模型的一些特定功能,例如更改计算数据类型、使用Normal Float 4 (NF4)数据类型以及使用嵌套量化。
计算数据类型
为了加快计算速度,您可以使用BitsAndBytesConfig中的bnb_4bit_compute_dtype
参数将数据类型从float32(默认值)更改为bf16。
import torch
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)
Normal Float 4 (NF4)
NF4是QLoRA论文中的一种4位数据类型,适用于从正态分布初始化的权重。您应该将NF4用于训练4位基础模型。这可以通过BitsAndBytesConfig中的bnb_4bit_quant_type
参数进行配置。
from transformers import BitsAndBytesConfig
nf4_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
)
model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=nf4_config)
对于推理,bnb_4bit_quant_type
对性能的影响并不大。但是,为了与模型权重保持一致,您应该使用bnb_4bit_compute_dtype
和torch_dtype
值。
嵌套量化
嵌套量化是一种可以在不增加性能成本的情况下节省额外内存的技术。此功能对已量化的权重执行第二次量化,以额外节省 0.4 位/参数。例如,使用嵌套量化,您可以在 16GB NVIDIA T4 GPU 上对 Llama-13b 模型进行微调,序列长度为 1024,批大小为 1,并启用 4 步梯度累积。
from transformers import BitsAndBytesConfig
double_quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
)
model_double_quant = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-13b", quantization_config=double_quant_config)
反量化 bitsandbytes 模型
量化后,您可以将模型反量化到原始精度,但这可能会导致模型质量略有下降。请确保您有足够的 GPU RAM 来容纳反量化后的模型。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig, AutoTokenizer
model_id = "facebook/opt-125m"
model = AutoModelForCausalLM.from_pretrained(model_id, BitsAndBytesConfig(load_in_4bit=True))
tokenizer = AutoTokenizer.from_pretrained(model_id)
model.dequantize()
text = tokenizer("Hello my name is", return_tensors="pt").to(0)
out = model.generate(**text)
print(tokenizer.decode(out[0]))