Transformers documentation
compressed-tensors
compressed-tensors
يمدّد compressed-tensors ملفات safetensors بأنواع بيانات المصفوفات المضغوطة، ليوفّر صيغة نقطة تفتيش موحّدة لتخزين وتحميل صيغ التكميم المختلفة، مثل: الكثيف (dense)، والمكمّم بالأعداد الصحيحة (int8)، والمكمّم بالأعداد العشرية (fp8)، والمكمّم المُجمّع (int4 أو int8 مكمّم الأوزان ومُجمّع داخل int32).
يدعم compressed-tensors الضبط الدقيق باستخدام PEFT، كما يتضمن الميزات التالية.
- دقة الأوزان والتفعيلات fp8 وint4 وint8.
- استراتيجيات مقاييس التكميم ونقاط الصفر لـ المصفوفة، القناة، المجموعة، الكتلة، الرمز.
- كمّية تنشيط ديناميكية لكل رمز (أو أي استراتيجية ثابتة).
- كمّية وحدات اختيارية، وليس فقط وحدات nn.Linear.
- دعم مخصص لوحدات محددة بالاسم أو بالفئة.
قم بتثبيت compressed-tensors من PyPI للحصول على أحدث إصدار مستقر (موصى به)، أو ثبّته من المصدر للحصول على أحدث الميزات.
pip install compressed-tensors
git clone https://github.com/neuralmagic/compressed-tensors
cd compressed-tensors
pip install -e .ابحث باستخدام وسم compressed-tensors للعثور على نموذج متوافق على Hugging Face Hub.
يمكن تحميل النماذج المُكمّاة مسبقًا مباشرةً. ولتكميم نموذج إلى صيغة compressed-tensors، راجع llm-compressor. وبديلًا عن ذلك، يمكن إنشاء النماذج بشكل مستقل ثم تسلسلها مع إعداد compressed-tensors.
from transformers import AutoModelForCausalLM
ct_model = AutoModelForCausalLM.from_pretrained("nm-testing/Meta-Llama-3.1-8B-Instruct-FP8-hf", device_map="auto")
# measure memory usage
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أوضاع التحميل
تُخزّن نقطة تفتيش compressed-tensors أوزانها مضغوطة (fp8، أو int4/int8 مُجمّعة). أما كيفية تنفيذها فتعتمد على حجّتين من CompressedTensorsConfig.
| الإعداد | الأوزان بعد التحميل | التنفيذ |
|---|---|---|
| افتراضي | مضغوط على اليسار | يملك compressed-tensors الطبقات ويفك ضغط النموذج في أول تمريرة أمامية |
dequantize=True | تُفكّك إلى نوع البيانات الخاص بالنموذج (مثل BF16) | عمليات ضرب المصفوفات الكثيفة العادية، ويمكن ضبط النموذج أو حفظه في ذلك النوع |
use_optimized_inference=True | بقي مُكمّط | الطبقات التي يمرّ نواة (kernel) عبر مخططها، وهي حالياً W8A8 fp8؛ للاستدلال فقط |
تسريع نواة FP8
مرّر use_optimized_inference=True للحفاظ على نموذج compressed-tensors المضغوط بصيغة FP8 في صيغة FP8، وتنفيذ عمليات ضرب المصفوفات (matmuls) الخاصة به عبر نوى FP8 المعززة بالعتاد (torch.nn.functional.scaled_mm، والتي تُوجَّه إلى torch._scaled_mm_v2؛ بينما تعود إصدارات torch الأقدم إلى torch._scaled_mm)، بدلاً من إلغاء تكميم الأوزان وإعادتها إلى BF16. إن إبقاء الأوزان بصيغة FP8 طوال عملية الاستدلال يقلل من استهلاك الذاكرة ويسرّع الحسابات. هذا الخيار مخصص للاستدلال فقط، لذا اتركه معطلاً عند إجراء الضبط الدقيق (fine-tuning).
| الجهاز | النواة | ملاحظات |
|---|---|---|
| Intel XPU | torch.nn.functional.scaled_mm | جميع أجهزة XPU التي تدعم FP8 |
| NVIDIA CUDA (SM89+) | torch.nn.functional.scaled_mm | آدا لوفليس (L4، L40)، هوبر (H100)، بلاكويل والأحدث |
| شريحة Apple (MPS) | torch.nn.functional.scaled_mm | يتطلب torch >= 2.15 |
| CPU / CUDA SM80 (A100) / MPS مع torch < 2.15 | بديل | يتم تجاهل use_optimized_inference=True، ويعمل النموذج دون فك التكميم |
يدعم مسار نواة FP8 تخطيطات التكميم التالية.
| الاستراتيجية | نموذج مثال |
|---|---|
| ديناميكي لكل قناة | RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8-dynamic |
| ثابت لكل مشغّل | RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8 |
تحميل نموذج FP8 مُكمَّم مسبقًا
نوى FP8 اختيارية: اطلبها باستخدام use_optimized_inference=True، وتُستخدم عندما يحدد تكوين النموذج تكميم FP8 ويتوفر معالج رسومي مدعوم.
from transformers import AutoModelForCausalLM, AutoTokenizer, CompressedTensorsConfig
model = AutoModelForCausalLM.from_pretrained(
"RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8-dynamic",
quantization_config=CompressedTensorsConfig(use_optimized_inference=True),
device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained("RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8-dynamic")
inputs = tokenizer("Hello, how are you?", return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=20)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))إلغاء التكميم عند التحميل
بدون use_optimized_inference=True، يتبع النموذج المسار المعتاد لـ compressed-tensors: تبقى الأوزان مضغوطة، ثم يقوم compressed-tensors بفك ضغطها في أول تمريرة أمامية. مرّر dequantize=True لفك تكميمها أثناء التحميل بدلاً من ذلك، وهو ما تحتاجه إذا كنت تريد ضبط النموذج بدقة أو حفظه بدقة الأصلية (مثل BF16).
from transformers import AutoModelForCausalLM, CompressedTensorsConfig
model = AutoModelForCausalLM.from_pretrained(
"RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8-dynamic",
quantization_config=CompressedTensorsConfig(dequantize=True),
device_map="auto",
)نقطة تفتيش النموذج
تُعرَّف نماذج compressed-tensor عبر مدخلات إعداداتها. المثال التالي مأخوذ من ملف config.json الخاص بـ nm-testing/Meta-Llama-3.1-8B-Instruct-FP8-hf.
توجد العديد من الإدخالات للسماح بالتعبير المرن أثناء الضغط وبعده، لكن يمكن تبسيط الإدخالات الخاصة بالتحميل والاستدلال للتركيز على عدد قليل من الإدخالات الرئيسية فقط.
"quantization_config": {
"config_groups": {
"group_0": {
"input_activations": {
"num_bits": 8,
"strategy": "tensor",
"type": "float"
},
"targets": ["Linear"],
"weights": {
"num_bits": 8,
"strategy": "tensor",
"type": "float"
}
}
},
"format": "naive-quantized",
"ignore": ["lm_head"],
"quant_method": "compressed-tensors",
"quantization_status": "frozen"
},يحدد ملف الإعدادات التكميم لمجموعة الإعدادات (group_0)، والتي تتضمن تكميم الأوزان والتفعيلات إلى fp8 باستخدام استراتيجية ثابتة لكل متجه. كما أن وحدة lm_head غير مُكمَّمة كما هو موضح في المفتاح ignore.
للنظر في أوزان النموذج بشكل أكثر تفصيلاً، استخدم safetensors viewer في بطاقة النموذج لعرض الأوزان المُكمّمة، ومقياس الإدخال، ومقياس الوزن لجميع وحدات nn.Linear.
| المصفوفات | الشكل | الدقة |
|---|---|---|
| model.layers.0.input_layernorm.weight | [4 096] | BF16 |
| model.layers.0.mlp.down_proj.input_scale | [1] | BF16 |
| model.layers.0.mlp.down_proj.weight | [4 096, 14 336] | 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 | [14 336, 4 096] | 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 | [14 336, 4 096] | F8_E4M3 |
| model.layers.0.mlp.up_proj.weight_scale | [1] | BF16 |
| model.layers.0.post_attention_layernorm.weight | [4 096] | BF16 |
| model.layers.0.self_attn.k_proj.input_scale | [1] | BF16 |
| model.layers.0.self_attn.k_proj.weight | [1 024, 4 096] | 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 | [4 096, 4 096] | 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 | [4 096, 4 096] | 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 | [1 024, 4 096] | F8_E4M3 |
| model.layers.0.self_attn.v_proj.weight_scale | [1] | BF16 |
عند تحميل نموذج compressed-tensors باستخدام تكامل ~quantizers.HFQuantizer، تُسلَّم الوحدات المستهدفة إلى compressed-tensors: حيث يربط مخطط التكميم المُحلَّلة quantization_scheme، ويضبط quantization_status، ويسجّل المعاملات التي يخزّنها نقطة التفتيش (weight بصيغة fp8، بالإضافة إلى weight_scale و، في حالة استخدام استراتيجية ثابتة، input_scale)، ويثبّت مسارًا أماميًا خاصًا به فوقها. تبقى هذه الوحدات كائنات من nn.Linear، لذا هذا ما يعرضه print — فإصدارات compressed-tensors الحديثة لم تعد تغلّفها في فئة فرعية من CompressedLinear. أما الوحدات المدرجة تحت ignore، مثل lm_head، فتُترك دون أي تعديل.
عند استخدام dequantize=False (القيمة الافتراضية)، تبقى الأوزان مضغوطة بعد اكتمال التحميل، ويقوم compressed-tensors بفك ضغط النموذج بالكامل في أول تمريرة أمامية. أما dequantize=True فيقوم بذلك أثناء التحميل، فلا تكون هناك حاجة إلى تمريرة أمامية للحصول على أوزان كثيفة.
import torch
from transformers import AutoModelForCausalLM, CompressedTensorsConfig
model_id = "nm-testing/Meta-Llama-3.1-8B-Instruct-FP8-hf"
ct_model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=CompressedTensorsConfig(dequantize=False),
device_map="auto",
)
q_proj = ct_model.model.layers[0].self_attn.q_proj
print(q_proj, q_proj.quantization_status)
# Linear(in_features=4096, out_features=4096, bias=False) QuantizationStatus.COMPRESSED
# ^ compressed-tensors module: fp8 weight, weight_scale, and its own forward
ct_model(input_ids=torch.tensor([[0, 1, 2]], device=ct_model.device))
print(q_proj, q_proj.quantization_status)
# Linear(in_features=4096, out_features=4096, bias=False) QuantizationStatus.DECOMPRESSED
# ^ weight is BF16 now, decompressed by that forward pass
ct_model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=CompressedTensorsConfig(dequantize=True),
device_map="auto",
)
print(ct_model.model.layers[0].self_attn.q_proj)
# Linear(in_features=4096, out_features=4096, bias=False) weight: BF16عند استخدام use_optimized_inference=True، تُستبدل الطبقات المشمولة بمجموعة إعدادات fp8 بـ CompressedTensorsFP8Linear، الذي يحتفظ بوزن fp8 ومقياسه في الترتيب الذي يتوقعه نواة ضرب المصفوفات الصفية. وتبقى هذه الأوزان في fp8، بما في ذلك عمليات المرور الأمامي.
from transformers import AutoModelForCausalLM, CompressedTensorsConfig
ct_model = AutoModelForCausalLM.from_pretrained(
"nm-testing/Meta-Llama-3.1-8B-Instruct-FP8-hf",
quantization_config=CompressedTensorsConfig(use_optimized_inference=True),
device_map="auto",
)
print(ct_model.model.layers[0].self_attn.q_proj)
# CompressedTensorsFP8Linear(in_features=4096, out_features=4096, bias=False) weight: F8_E4M3