Transformers documentation
المساهمة
المساهمة
يدعم Transformers العديد من طرق التكميم مثل QLoRA وGPTQ وLLM.int8 وAWQ. ومع ذلك، لا تزال هناك العديد من أساليب التكميم الأخرى التي لم يتم دمجها بعد. لتسهيل إضافة هذه طرق التكميم واستخدامها مع Transformers، استخدم فئة HfQuantizer. صُممت فئة HfQuantizer لتكون فئة مساعدة داخلية لإضافة طريقة تكميم، بدلاً من أن تكون شيئاً يُطبَّق على كل وحدة PyTorch.
ستُظهر لك هذه الدليل كيفية دمج طريقة تكميم جديدة مع HfQuantizer.
المتطلبات
قبل دمج طريقة تكميم جديدة في Transformers، تأكد من أن الطريقة تستوفي المتطلبات التالية. يتم دعم طرق التكميم التي يمكن تشغيلها باستخدام وحدات PyTorch فقط.
يتوفر أسلوب التكميم عبر حزمة Python يمكن تثبيتها باستخدام pip (ولا بأس إذا كان بإمكانك تثبيت الحزمة من المصدر فقط). في المثالي، تتضمن حزمة pip نوى مُجمّعة مسبقًا.
يمكن تشغيل الطريقة على الأجهزة الشائعة الاستخدام (وحدة المعالجة المركزية، وحدة معالجة الرسوميات، إلخ).
يُغلَّف الأسلوب داخل nn.Module (
~bitsandbytes.nn.Linear8bitLt،~bitsandbytes.nn.Linear4bit)، وينبغي أن يكون للخطية المُكمَّمة التعريف التالي.class Linear4bit(nn.Module): def __init__(self, ...): ... def forward(self, x): return my_4bit_kernel(x, self.weight, self.bias)بهذه الطريقة، يمكن تكميم نماذج Transformers بسهولة عن طريق استبدال حالات nn.Linear بفئة مستهدفة.
يجب أن تكون طريقة التكميم قابلة للتسلسل. يمكنك حفظ الأوزان المكمّمة محليًا أو رفعها إلى Hub.
تأكد من أن الحزمة التي تحتوي على نواة/الأساسيات (primitives) للكمّ (quantization) مستقرة (لا تتضمن تغييرات متكررة تكسر التوافق).
قد تتطلب بعض طرق التكميم "تكميمًا مسبقًا" للنموذج من خلال معايرة البيانات (AWQ). في هذه الحالة، نفضّل دعم الاستدلال فقط في Transformers، ونترك لمكتبة الطرف الثالث التي تُدار من قبل مجتمع تعلم الآلة مهمة معالجة تكميم النموذج ذاتها.
إنشاء فئة HFQuantizer جديدة
أفضل نقطة انطلاق هي الاطلاع على طريقة تكميم أخرى مثل Finegrained Fp8. ستحتاج إلى تحديث أو إنشاء ثلاثة ملفات إجمالاً: ملف الإعدادات، وملف التكامل، وملف مُكمِّم.
أنشئ فئة إعدادات تكميم جديدة داخل src/transformers/utils/quantization_config.py. أضف فئة إعدادات التكميم الجديدة إلى _import_structure داخل ملف src/transformers/__init__.py الخاص بـ Transformers.
أنشئ ملفًا جديدًا داخل src/transformers/quantizers/ باسم
quantizer_your_method.py، واجعله يرث من [`~quantizers.HfQuantizer`]. تأكد من إضافة مُكمِّم (quantizer) جديد وإعدادات الكمّ (quantization config) في خرائط الكمّ التلقائية (quantization auto-mapping) الموجودة في src/transformers/quantizers/auto.py.حدّد سمات الفئة التالية وطرق الخاصية لطريقة التكميم الخاصة بك:
requires_calibration: ما إذا كانت طريقة التكميم تتطلب عملية معايرة للبيانات. إذا تم ضبطها علىTrue، يمكنك فقط دعم الاستدلال (بأوزان مُكمَّمة) وليس الاستدلال والتكميم معاً.is_serializable: طريقة خاصية لتحديد ما إذا كانت الطريقة قابلة للتسلسل أم لا.is_trainable: طريقة خاصية لتحديد ما إذا كان بإمكانك ضبط النماذج الدقيقة فوق طريقة التكميم (مع أو بدون أساليب PEFT).
اكتب طريقتي
validate_environmentوupdate_dtype. تُستدعى هاتان الطريقتان قبل إنشاء النموذج المُكمَّم للتأكد من استخدام المستخدمين الإعداد الصحيح. راجع مُكمِّمات أخرى كمثال على كيفية تنفيذها.اكتب طريقة
_process_model_before_weight_loading. في Transformers، يتم تهيئة النماذج المُكمّاة أولاً على جهاز"meta"قبل تحميل الأوزان. وهذا يعني أن طريقة_process_model_before_weight_loadingتتولى تعديل هيكل النموذج لاستبدال بعض الوحدات (nn.Linear) بالوحدات المستهدفة (وحدات الكمّ).
يمكنك تعريف منطق استبدال الوحدات أو أي طريقة مساعدة أخرى من خلال إنشاء ملف جديد في transformers/src/integrations/ وعرض الطرق ذات الصلة في ملف __init__.py الخاص بذلك المجلد.
أضف طريقة
get_quantize_opsإلى فئة المُكمِّم إذا كان التكميم يدعم التكميم أثناء التشغيل. في transformers، نُجسِّد كل متجه (tensor) ونطبّق سلسلة من العمليات المختلفة عليه. في حالتنا، يحدث عملية التكميم في النهاية. عليك إنشاءXXXQuantize، وهي فئة فرعية منConversionOps، وإضافة طريقةconvert. في طريقةconvert، عليك تكميم الأوزان وإرجاع قاموس (dictionary) بالمعاملات المُكمَّمة.أضِف طريقة
get_weight_conversionsإلى فئة المُكمِّم إذا كان التكميم يدعم تحميل الأوزان المُكمَّمة مسبقًا. في transformers، يمكننا جمع عدة متجهات وتطبيق عمليات عليها. وهذا مفيد بشكل خاص عندما يكون لدينا متجهات في نقطة الفحص (checkpoint) تتطلب إعادة تجميعها لإعادة إنشاء المتجهات المُكمَّمة.اكتب طريقة
_process_model_after_weight_loadingعند الحاجة. تتيح هذه الطريقة تنفيذ ميزات إضافية تتطلب التلاعب بالنموذج بعد تحميل الأوزان.وثّق كل شيء! تأكد من توثيق طريقة التكميم الخاصة بك عن طريق إضافة ملف جديد تحت
docs/source/en/quantization.يجب عليك إضافة الاختبارات عن طريق إضافة الحزمة إلى ملف Dockerfile الخاص بنا في
docker/transformers-quantization-latest-gpuثم إضافة ملف اختبار جديد فيtests/quantization/xxx. يمكنك الاطلاع على طرق التكميم الحالية لرؤية كيفية تنفيذها.
نظرة عامة على الملفات
| ملف | الغرض |
|---|---|
utils/quantization_config.py | حدّد YourMethodConfig بحيث يرث من QuantizationConfigMixin |
quantizers/quantizer_your_method.py | نفّذ YourMethodHfQuantizer بحيث يرث من HfQuantizer |
integrations/your_method.py | تنفيذ فئات فرعية من ConversionOps والدوال المساعدة |
quantizers/auto.py | سجّل مُكمِّم الإعدادات في AUTO_QUANTIZER_MAPPING وAUTO_QUANTIZATION_CONFIG_MAPPING |
docs/source/en/quantization/your_method.md | استخدام المستند للمستخدمين |
tests/quantization/your_method/ | إضافة اختبارات التكامل |
فهم get_quantize_ops مقابل get_weight_conversions
تعتمد هاتان الطريقتان على سيناريوهات مختلفة لتحميل الأوزان. ومن الضروري فهم متى يُستخدم كلٌّ منهما.
get_quantize_ops — تكميم أثناء التشغيل
استخدم هذا عند تحميل نقطة تحقق غير مُكمّاة (مثل أوزان float16/bfloat16) وإجراء التكميم أثناء التحميل.
Checkpoint: model.safetensors (float16 weights for example)
↓
get_quantize_ops → YourQuantize.convert()
↓
Result: Quantized weights in memoryيستقبل أسلوب convert متجهًا واحدًا في كل مرة، ويقوم بتكميمه، ويمكنه إرجاع قاموس للمعاملات المكمّمة، على سبيل المثال:
class YourQuantize(ConversionOps):
def convert(self, input_dict, model, full_layer_name, missing_keys, **kwargs):
# input_dict = {"layer.weight": <float16 tensor>}
value = list(input_dict.values())[0]
module, tensor_name = get_module_from_name(model, full_layer_name)
# Quantize and assign
quantized, scale, zero_point = your_quantize_fn(value)
return {full_layer_name: quantized, full_layer_name + ".scale": scale, full_layer_name + ".zero_point": zero_point}get_weight_conversions — تحميل نقاط التفتيش المُكمّاة مسبقًا
استخدم هذا عند تحميل نقطة تحقق مُكمّاة مسبقًا حيث تُحفظ الأوزان المكمّاة كمكوّنات منفصلة متعددة (مثل البيانات، والمقياس، ونقطة الصفر)، ويتطلب الأمر دمجها في متجه واحد أثناء التحميل. لا تتطلب جميع طرق التكميم هذه الخطوة لإعادة البناء؛ فبعض الطرق مثل FP8 تقوم ببساطة بتحميل الأوزان والمقاييس كما هي دون دمجها. بينما تتطلب طرق أخرى، مثل torchao، إعادة تجميع المتجه المكمّ من مكوّناته المحفوظة المتعددة.
Checkpoint: model.safetensors (quantized components)
- layer._weight_qdata
- layer._weight_scale
- layer._weight_zero_point
↓
get_weight_conversions → WeightConverter + YourDeserialize.convert()
↓
Result: Reconstructed quantized tensor → layer.weightيجمع WeightConverter المتجهات ذات الصلة بناءً على source_patterns، ثم يمررها إلى طريقة convert الخاصة بك:
def get_weight_conversions(self):
if self.pre_quantized:
return [
WeightConverter(
source_patterns=["_weight_qdata", "_weight_scale", "_weight_zero_point"],
target_patterns="weight",
operations=[YourDeserialize(self)],
),
]
return []
class YourDeserialize(ConversionOps):
def convert(self, input_dict, model, full_layer_name, **kwargs):
# input_dict contains all collected tensors
# Reconstruct the quantized tensor from components
reconstructed_tensor = reconstruct_from_components(input_dict)
return {full_layer_name: reconstructed_tensor}