压缩张量¶
compressed-tensors 库提供了一种灵活且高效的方法来存储和管理压缩的模型检查点。该库支持多种量化和稀疏性方案,使其成为处理不同模型优化(如 GPTQ、AWQ、SmoothQuant、INT8、FP8、SparseGPT 等)的统一格式。
支持的一些格式包括:
denseint-quantized(示例):INT8 量化模型float-quantized(示例):FP8 量化模型;目前支持 E4M3pack-quantized(示例):INT4 或 INT8 权重量化模型,打包成 INT32。对于 INT4,权重有 INT4 的范围,但以 INT8 存储并打包成 INT32。
压缩模型可以使用 llm-compressor 轻松创建。或者,也可以独立创建模型,并使用压缩张量配置进行序列化。
要在 Hugging Face Model Hub 上查找现有模型,请搜索带有 compressed-tensors 标签的模型。
特性:¶
- 权重和激活精度:FP8、INT4、INT8(对于 Q/DQ,INT 允许任意精度)
- 量化尺度和零点策略:张量、通道、组、块、令牌
- 动态按令牌激活量化(或任何静态策略)
- 权重中的稀疏性(无结构或半结构化如 2:4)可以与量化组合以实现极端压缩
- 支持任意模块的量化,而不仅仅是线性模块
- 按名称或类目标定位或忽略模块
安装¶
建议从 PyPI 安装 compressed-tensors 的稳定版本:
pip install compressed-tensors
希望尝试最新功能的开发者可以从源代码安装该包:
git clone https://github.com/neuralmagic/compressed-tensors
cd compressed-tensors
pip install -e .
快速开始:加载模型¶
以下示例展示了如何轻松加载量化模型以进行推理。目前只能加载已量化的模型。要将模型量化解压成 compressed-tensors 格式,请参阅 llm-compressor。
from transformers import AutoModelForCausalLM
# 以压缩张量格式加载模型
ct_model = AutoModelForCausalLM.from_pretrained("nm-testing/Meta-Llama-3.1-8B-Instruct-FP8-hf")
# 测量内存使用情况
mem_params = sum([param.nelement() * param.element_size() for param in ct_model.parameters()])
print(f"{mem_params / 2**30:.4f} GB")
# 8.4575 GB
从上面可以看出,压缩张量 FP8 检查点的 Llama 3.1 8B 可以在推理时使用未量化参考检查点一半的内存。
示例用例:加载和运行 FP8 模型¶
from transformers import AutoModelForCausalLM, AutoTokenizer
prompt = [
"Hello, my name is",
"The capital of France is",
"The future of AI is"
]
model_name = "nm-testing/Meta-Llama-3-8B-Instruct-fp8-hf_compat"
quantized_model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)
inputs = tokenizer(prompt, return_tensors="pt")
generated_ids = quantized_model.generate(**inputs, max_length=50, do_sample=False)
outputs = tokenizer.batch_decode(generated_ids)
print(outputs)
"""
['<|begin_of_text|>Hello, my name is [Name]. I am a [Your Profession/Student] and I am here to learn about the [Course/Program] at [University/Institution]. I am excited to be here and I am looking forward to', '<|begin_of_text|>The capital of France is Paris, which is located in the north-central part of the country. Paris is the most populous city in France and is known for its stunning architecture, art museums, fashion, and romantic atmosphere. The city is home to', "<|begin_of_text|>The future of AI is here, and it's already changing the way we live and work. From virtual assistants to self-driving cars, AI is transforming industries and revolutionizing the way we interact with technology. But what does the future of AI hold"]
"""
上述示例展示了如何使用 compressed-tensors 模型进行生成。目前,一旦加载模型后,无法保存。
深入了解压缩张量模型检查点¶
在这个示例中,我们将通过模型配置条目来查看 compressed-tensors 模型 nm-testing/Meta-Llama-3.1-8B-Instruct-FP8-hf 如何定义,并了解这如何转换为加载后的模型表示。
首先,让我们来看看模型的 quantization_config 配置。虽然看起来条目很多,但这是因为 compressed-tensors 是一种允许在模型压缩期间和之后灵活表达的格式。
为了简化配置以便更专注于实际的压缩表示,我们可以删除所有默认或空的条目。
从上述配置中可以看出,它指定了一个配置组,其中包括权重和激活的 FP8 量化,采用静态每张量策略。值得注意的是,在 ignore 列表中有一个条目用于跳过 lm_head 模块的量化,因此该模块在检查点中应保持不变。
为了在实践中看到配置的结果,我们可以使用 safetensors 查看器 查看模型卡上的量化权重、输入比例和权重比例,例如第一个模型层中的所有 Linear 模块(其余层也是如此)。
| 张量 | 形状 | 精度 |
|---|---|---|
| model.layers.0.input_layernorm.weight | [4096] | BF16 |
| model.layers.0.mlp.down_proj.input_scale | [1] | BF16 |
| model.layers.0.mlp.down_proj.weight | [4096, 14336] | F8_E4M3 |
| model.layers.0.mlp.down_proj.weight_scale | [1] | BF16 |
| model.layers.0.mlp.gate_proj.input_scale | [1] | BF16 |
| model.layers.0.mlp.gate_proj.weight | [14336, 4096] | F8_E4M3 |
| model.layers.0.mlp.gate_proj.weight_scale | [1] | BF16 |
| model.layers.0.mlp.up_proj.input_scale | [1] | BF16 |
| model.layers.0.mlp.up_proj.weight | [14336, 4096] | F8_E4M3 |
| model.layers.0.mlp.up_proj.weight_scale | [1] | BF16 |
| model.layers.0.post_attention_layernorm.weight | [4096] | BF16 |
| model.layers.0.self_attn.k_proj.input_scale | [1] | BF16 |
| model.layers.0.self_attn.k_proj.weight | [1024, 4096] | F8_E4M3 |
| model.layers.0.self_attn.k_proj.weight_scale | [1] | BF16 |
| model.layers.0.self_attn.o_proj.input_scale | [1] | BF16 |
| model.layers.0.self_attn.o_proj.weight | [4096, 4096] | F8_E4M3 |
| model.layers.0.self_attn.o_proj.weight_scale | [1] | BF16 |
| model.layers.0.self_attn.q_proj.input_scale | [1] | BF16 |
| model.layers.0.self_attn.q_proj.weight | [4096, 4096] | F8_E4M3 |
| model.layers.0.self_attn.q_proj.weight_scale | [1] | BF16 |
| model.layers.0.self_attn.v_proj.input_scale | [1] | BF16 |
| model.layers.0.self_attn.v_proj.weight | [1024, 4096] | F8_E4M3 |
| model.layers.0.self_attn.v_proj.weight_scale | [1] | BF16 |
当我们使用压缩张量 HFQuantizer 集成加载模型时,可以看到 quantization_config 中指定的所有 Linear 模块都被替换为 CompressedLinear 模块,这些模块管理压缩权重和前向传递以进行推理。注意之前在 ignore 列表中提到的 lm_head 仍然保留为未量化的 Linear 模块。
from transformers import AutoModelForCausalLM
ct_model = AutoModelForCausalLM.from_pretrained("nm-testing/Meta-Llama-3.1-8B-Instruct-FP8-hf")
print(ct_model)
"""
LlamaForCausalLM(
(model): LlamaModel(
(embed_tokens): Embedding(128256, 4096)
(layers): ModuleList(
(0-31): 32 x LlamaDecoderLayer(
(self_attn): LlamaSdpaAttention(
(q_proj): CompressedLinear(
in_features=4096, out_features=4096, bias=False
(input_observer): MovingAverageMinMaxObserver()
(weight_observer): MovingAverageMinMaxObserver()
)
(k_proj): CompressedLinear(
in_features=4096, out_features=1024, bias=False
(input_observer): MovingAverageMinMaxObserver()
(weight_observer): MovingAverageMinMaxObserver()
)
(v_proj): CompressedLinear(
in_features=4096, out_features=1024, bias=False
(input_observer): MovingAverageMinMaxObserver()
(weight_observer): MovingAverageMinMaxObserver()
)
(o_proj): CompressedLinear(
in_features=4096, out_features=4096, bias=False
(input_observer): MovingAverageMinMaxObserver()
(weight_observer): MovingAverageMinMaxObserver()
)
(rotary_emb): LlamaRotaryEmbedding()
)
(mlp): LlamaMLP(
(gate_proj): CompressedLinear(
in_features=4096, out_features=14336, bias=False
(input_observer): MovingAverageMinMaxObserver()
(weight_observer): MovingAverageMinMaxObserver()
)
(up_proj): CompressedLinear(
in_features=4096, out_features=14336, bias=False
(input_observer): MovingAverageMinMaxObserver()
(weight_observer): MovingAverageMinMaxObserver()
)
(down_proj): CompressedLinear(
in_features=14336, out_features=4096, bias=False
(input_observer): MovingAverageMinMaxObserver()
(weight_observer): MovingAverageMinMaxObserver()
)
(act_fn): SiLU()
)
(input_layernorm): LlamaRMSNorm((4096,), eps=1e-05)
(post_attention_layernorm): LlamaRMSNorm((4096,), eps=1e-05)
)
)
(norm): LlamaRMSNorm((4096,), eps=1e-05)
(rotary_emb): LlamaRotaryEmbedding()
)
(lm_head): Linear(in_features=4096, out_features=128256, bias=False)
)
"""