Transformers documentation

المساهمة

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

المساهمة

يدعم 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 جديدة

  1. أفضل نقطة انطلاق هي الاطلاع على طريقة تكميم أخرى مثل Finegrained Fp8. ستحتاج إلى تحديث أو إنشاء ثلاثة ملفات إجمالاً: ملف الإعدادات، وملف التكامل، وملف مُكمِّم.

  2. أنشئ فئة إعدادات تكميم جديدة داخل src/transformers/utils/quantization_config.py. أضف فئة إعدادات التكميم الجديدة إلى _import_structure داخل ملف src/transformers/__init__.py الخاص بـ Transformers.

  3. أنشئ ملفًا جديدًا داخل src/transformers/quantizers/ باسم quantizer_your_method.py، واجعله يرث من [`~quantizers.HfQuantizer`]. تأكد من إضافة مُكمِّم (quantizer) جديد وإعدادات الكمّ (quantization config) في خرائط الكمّ التلقائية (quantization auto-mapping) الموجودة في src/transformers/quantizers/auto.py.

  4. حدّد سمات الفئة التالية وطرق الخاصية لطريقة التكميم الخاصة بك:

    • requires_calibration: ما إذا كانت طريقة التكميم تتطلب عملية معايرة للبيانات. إذا تم ضبطها على True، يمكنك فقط دعم الاستدلال (بأوزان مُكمَّمة) وليس الاستدلال والتكميم معاً.
    • is_serializable: طريقة خاصية لتحديد ما إذا كانت الطريقة قابلة للتسلسل أم لا.
    • is_trainable: طريقة خاصية لتحديد ما إذا كان بإمكانك ضبط النماذج الدقيقة فوق طريقة التكميم (مع أو بدون أساليب PEFT).
  5. اكتب طريقتي validate_environment وupdate_dtype. تُستدعى هاتان الطريقتان قبل إنشاء النموذج المُكمَّم للتأكد من استخدام المستخدمين الإعداد الصحيح. راجع مُكمِّمات أخرى كمثال على كيفية تنفيذها.

  6. اكتب طريقة _process_model_before_weight_loading. في Transformers، يتم تهيئة النماذج المُكمّاة أولاً على جهاز "meta" قبل تحميل الأوزان. وهذا يعني أن طريقة _process_model_before_weight_loading تتولى تعديل هيكل النموذج لاستبدال بعض الوحدات (nn.Linear) بالوحدات المستهدفة (وحدات الكمّ).

يمكنك تعريف منطق استبدال الوحدات أو أي طريقة مساعدة أخرى من خلال إنشاء ملف جديد في transformers/src/integrations/ وعرض الطرق ذات الصلة في ملف __init__.py الخاص بذلك المجلد.

  1. أضف طريقة get_quantize_ops إلى فئة المُكمِّم إذا كان التكميم يدعم التكميم أثناء التشغيل. في transformers، نُجسِّد كل متجه (tensor) ونطبّق سلسلة من العمليات المختلفة عليه. في حالتنا، يحدث عملية التكميم في النهاية. عليك إنشاء XXXQuantize، وهي فئة فرعية من ConversionOps، وإضافة طريقة convert. في طريقة convert، عليك تكميم الأوزان وإرجاع قاموس (dictionary) بالمعاملات المُكمَّمة.

  2. أضِف طريقة get_weight_conversions إلى فئة المُكمِّم إذا كان التكميم يدعم تحميل الأوزان المُكمَّمة مسبقًا. في transformers، يمكننا جمع عدة متجهات وتطبيق عمليات عليها. وهذا مفيد بشكل خاص عندما يكون لدينا متجهات في نقطة الفحص (checkpoint) تتطلب إعادة تجميعها لإعادة إنشاء المتجهات المُكمَّمة.

  3. اكتب طريقة _process_model_after_weight_loading عند الحاجة. تتيح هذه الطريقة تنفيذ ميزات إضافية تتطلب التلاعب بالنموذج بعد تحميل الأوزان.

  4. وثّق كل شيء! تأكد من توثيق طريقة التكميم الخاصة بك عن طريق إضافة ملف جديد تحت docs/source/en/quantization.

  5. يجب عليك إضافة الاختبارات عن طريق إضافة الحزمة إلى ملف 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}
Update on GitHub