# التكميم

تمثل الكمية (Quantization) البيانات بعدد أقل من البتات، مما يجعلها تقنية مفيدة لتقليل استهلاك الذاكرة وتسريع الاستدلال (Inference)، لا سيما عند التعامل مع نماذج اللغة الكبيرة (LLMs). هناك عدة طرق لكمّية النموذج، بما في ذلك:

* تحسين الأوزان النموذجية التي يتم تكميمها باستخدام خوارزمية [AWQ](https://hf.co/papers/2306.00978)
* كمّ كل صف من مصفوفة الأوزان بشكل مستقل باستخدام خوارزمية [GPTQ](https://hf.co/papers/2210.17323)
* الكمّ إلى دقة 8 بت و4 بت باستخدام مكتبة [bitsandbytes](https://github.com/TimDettmers/bitsandbytes)
* تكميم الدقة حتى 2 بت باستخدام خوارزمية [AQLM](https://huggingface.co/papers/2401.06118)

ومع ذلك، بعد تكميم النموذج، لا يتم تدريبه عادةً بشكل إضافي على المهام التالية، لأن التدريب قد يكون غير مستقر بسبب الدقة المنخفضة للأوزان والتفعيلات. لكن نظرًا لأن طرق PEFT تضيف فقط *معلمات قابلة للتدريب إضافية*، فإن هذا يتيح لك تدريب نموذج مكمّم مع مُكيّف PEFT فوقه! يمكن أن يكون دمج التكميم مع PEFT استراتيجية جيدة لتدريب حتى أكبر النماذج على وحدة معالجة رسومية واحدة. على سبيل المثال، [QLoRA](https://hf.co/papers/2305.14314) هي طريقة تكمّم النموذج إلى 4 بتات ثم تدربه باستخدام LoRA. تتيح لك هذه الطريقة ضبط نموذج يحتوي على 65 مليار معلمة على وحدة معالجة رسومية واحدة بسعة 48 جيجابايت!

في هذا الدليل، ستتعلم كيفية تكميم نموذج إلى 4 بتات وتدريبه باستخدام LoRA.

## تكميم نموذج

[bitsandbytes](https://github.com/TimDettmers/bitsandbytes) هو مكتبة للكمّية (Quantization) تتضمن تكاملاً مع Transformers. من خلال هذا التكامل، يمكنك كمّية النموذج إلى 8 أو 4 بتات، وتمكين العديد من الخيارات الأخرى عن طريق تكوين فئة [BitsAndBytesConfig](https://huggingface.co/docs/transformers/main/en/main_classes/quantization#transformers.BitsAndBytesConfig). على سبيل المثال، يمكنك:

* اضبط `load_in_4bit=True` لتكميم النموذج إلى 4 بتات عند تحميله
* اضبط `bnb_4bit_quant_type="nf4"` لاستخدام نوع بيانات رباعي البت خاص للأوزان المُهيّأة من توزيع طبيعي
* اضبط `bnb_4bit_use_double_quant=True` لاستخدام مخطط تكميم متداخل لتكميم الأوزان المُكمَّمة مسبقًا
* اضبط `bnb_4bit_compute_dtype=torch.bfloat16` لاستخدام bfloat16 لحساب أسرع

```py
import torch
from transformers import BitsAndBytesConfig

config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
)
```

مرّر `config` إلى طريقة [from_pretrained](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoModelForCausalLM.from_pretrained).

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", quantization_config=config)
```

في الخطوة التالية، يجب عليك استدعاء دالة [prepare_model_for_kbit_training()](/docs/peft/main/ar/package_reference/peft_model#peft.prepare_model_for_kbit_training) لمعالجة النموذج المُكمَّم مسبقاً قبل التدريب.

```py
from peft import prepare_model_for_kbit_training

model = prepare_model_for_kbit_training(model)
```

الآن، بما أن النموذج المُكمَّم جاهز، فلنقم بإعداد تكوين.

## LoraConfig

أنشئ [LoraConfig](/docs/peft/main/ar/package_reference/lora#peft.LoraConfig) بالباراميترات التالية (أو اختر ما يناسبك):

```py
from peft import LoraConfig

config = LoraConfig(
    r=16,
    lora_alpha=8,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)
```

ثم استخدم دالة [get_peft_model()](/docs/peft/main/ar/package_reference/peft_model#peft.get_peft_model) لإنشاء [PeftModel](/docs/peft/main/ar/package_reference/peft_model#peft.PeftModel) من النموذج المُكمَّم والإعدادات.

```py
from peft import get_peft_model

model = get_peft_model(model, config)
```

لقد أصبحتَ مستعدًا تمامًا للتدريب باستخدام أي طريقة تدريب تفضلها!

### تهيئة LoftQ

يُهيّئ [LoftQ](https://hf.co/papers/2310.08659) أوزان LoRA بحيث يتم تقليل خطأ التكميم، ويمكنه تحسين الأداء عند تدريب النماذج المكمّمة. للبدء، اتبع [هذه التعليمات](https://github.com/huggingface/peft/tree/main/examples/loftq_finetuning).

يُطبَّق LoftQ على طبقات الخطية فقط، بما في ذلك تلك المستهدفة عبر `target_parameters`. لا تُدعَم طبقات التضمين والطبقات التلافيفية، بل تُستخدم بدلاً من ذلك تهيئة LoRA الافتراضية. كما لا تُدعَم طبقات `nn.MultiheadAttention` وتُطلق خطأً.

بشكل عام، للحصول على أفضل أداء لـ LoftQ، يُوصى باستهداف أكبر عدد ممكن من الطبقات باستخدام LoRA، حيث لا يمكن تطبيق LoftQ على الطبقات غير المستهدفة. وهذا يعني أن تمرير `LoraConfig(..., target_modules="all-linear")` سيُحقق على الأرجح أفضل النتائج. كما ينبغي استخدام `nf4` كنوع للتكميم في إعدادات التكميم الخاصة بك عند استخدام تكميم 4 بت، أي `BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")`.

بشكل عام، للحصول على أفضل أداء لـ LoftQ، يُوصى باستهداف أكبر عدد ممكن من الطبقات باستخدام LoRA، حيث لا يمكن تطبيق LoftQ على الطبقات غير المستهدفة. وهذا يعني أن تمرير `LoraConfig(..., target_modules="all-linear")` سيُحقق على الأرجح أفضل النتائج. كما ينبغي استخدام `nf4` كنوع للتكميم في إعدادات التكميم الخاصة بك عند استخدام تكميم 4 بت، أي `BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")`.

هناك طريقتان مقصودتان حاليًا لتطبيق LoftQ:

1. حمّل النموذج الأساسي غير المُكمَّم، وطبّق LoftQ بمستوى الكمّات المقصود (مثلًا `bits=4` لـ nf4) ثم احفظ المُكيّف الناتج. بعد ذلك، قم بكمّ النموذج الأساسي باستخدام، على سبيل المثال، `BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")` ثم حمّل المُكيّف المُهيّأ بواسطة LoftQ فوقه
2. تحميل النموذج الأساسي المُكمَّم، ثم تهيئة نموذج PEFT باستخدام LoRA (بدون loftq)، واستخدام `replace_lora_weights_loftq` لتطبيق تهيئة LoftQ عبر بث أوزان المرجع الخاصة بالنموذج الأساسي غير المُكمَّم من ملف الأوزان (يُشرح ذلك بالتفصيل في القسم التالي)

#### استخدام `replace_lora_weights_loftq` لتطبيق LoftQ أثناء التشغيل

طريقة أسهل لكنها أكثر محدودية لتطبيق تهيئة LoftQ هي استخدام الدالة الميسّرة `replace_lora_weights_loftq`. تستقبل هذه الدالة نموذج PEFT المُكمَّم كمدخل، وتستبدل أوزان LoRA في مكانها بنظيراتها المُهيّأة بواسطة LoftQ.

```python
from peft import replace_lora_weights_loftq
from transformers import BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(load_in_4bit=True, ...)
base_model = AutoModelForCausalLM.from_pretrained(..., quantization_config=bnb_config)
# note: don't pass init_lora_weights="loftq" or loftq_config!
lora_config = LoraConfig(task_type="CAUSAL_LM")
peft_model = get_peft_model(base_model, lora_config)
replace_lora_weights_loftq(peft_model)
```

`replace_lora_weights_loftq` يتيح لك أيضًا تمرير معامل `callback` لمنحك مزيدًا من التحكم في الطبقات التي يجب تعديلها أو عدم تعديلها، وهو ما يمكن أن يحسّن النتائج بشكل كبير عمليًا. للاطلاع على مثال أكثر تفصيلًا حول ذلك، راجع [هذا الدفتر](https://github.com/huggingface/peft/blob/main/examples/loftq_finetuning/LoftQ_weight_replacement.ipynb).

`replace_lora_weights_loftq` ينفّذ خطوة تكرار واحدة فقط من LoftQ. وهذا يعني أن أوزان LoRA هي التي تُحدَّث فقط، بدلاً من التحديث التكراري لأوزان LoRA وأوزان النموذج الأساسي المُكمَّم. قد يؤدي ذلك إلى أداء أدنى، لكنه يحمل ميزة وهي إمكانية استخدام الأوزان المُكمَّمة الأصلية المشتقة من النموذج الأساسي، بدلاً من الحاجة إلى الاحتفاظ بنسخة إضافية من الأوزان المُكمَّمة المعدَّلة. يعتمد ما إذا كان هذا التنازل يستحق أم لا على حالة الاستخدام.

في الوقت الحالي، `replace_lora_weights_loftq` لديها هذه القيود الإضافية:

- يجب تخزين ملفات النموذج كملف `safetensors`.
- يُؤمَّن فقط تكميم 4 بت من قِبل مكتبة bitsandbytes.

### التدريب بأسلوب QLoRA

تضيف QLoRA أوزانًا قابلة للتدريب إلى جميع الطبقات الخطية في بنية الترانسفورمر. نظرًا لأن أسماء الخصائص لهذه الطبقات الخطية قد تختلف بين البنى المعمارية، اضبط `target_modules` على `"all-linear"` لإضافة LoRA إلى جميع الطبقات الخطية:

```py
config = LoraConfig(target_modules="all-linear", ...)
```

## كمّية GPTQ

يمكنك معرفة المزيد حول التكميم بعدد بتات `[2, 3, 4, 8]` القائم على GPTQ في [GPT-QModel](https://github.com/ModelCloud/GPTQModel) وفي وثائق [GPTQ](https://huggingface.co/docs/transformers/quantization/gptq) الخاصة بـ Transformers. يدعم PEFT التدريب اللاحق باستخدام GPTQ من خلال GPT-QModel.

```bash
# GPT-QModel install
pip install "gptqmodel>=7.0.0"
```

```py
from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig

model_id = "facebook/opt-125m"
tokenizer = AutoTokenizer.from_pretrained(model_id)

gptq_config = GPTQConfig(bits=4, group_size=128, dataset="wikitext2", tokenizer=tokenizer)

quantized_model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", quantization_config=gptq_config)

# save quantized model
quantized_model.save_pretrained("./opt-125m-gptq")
tokenizer.save_pretrained("./opt-125m-gptq")
```

بمجرد إجراء التكميم، يمكنك تدريب نماذج GPTQ ما بعد التدريب باستخدام واجهات PEFT البرمجية.

## كمّية AQLM

تُعدّ الكمية الإضافية لنماذج اللغة ([AQLM](https://huggingface.co/papers/2401.06118)) طريقة لضغط نماذج اللغة الكبيرة. فهي تُكمّم أوزانًا متعددة معًا وتستفيد من التبعيات المتبادلة بينها. يُمثّل AQLM مجموعات من 8 إلى 16 وزنًا كمجموع لرموز متجهات متعددة. وهذا يتيح له ضغط النماذج حتى مستوى منخفض يبلغ 2 بت مع خسائر دقة منخفضة بشكل ملحوظ.

نظرًا لأن عملية تكميم AQLM مكلفة من الناحية الحسابية، يُوصى باستخدام النماذج المُكمَّمة مسبقًا. يمكن العثور على قائمة جزئية بالنماذج المتاحة في مستودع aqlm الرسمي [repository](https://github.com/Vahe1994/AQLM).

تدعم النماذج ضبط مُكيّفات LoRA. لضبط النموذج المُكمَّم، ستحتاج إلى تثبيت مكتبة الاستدلال `aqlm`: `pip install aqlm>=1.0.2`. يجب حفظ مُكيّفات LoRA المُحسَّنة بشكل منفصل، إذ لا يمكن دمجها مع الأوزان المُكمَّمة بواسطة AQLM.

```py
quantized_model = AutoModelForCausalLM.from_pretrained(
    "BlackSamorez/Mixtral-8x7b-AQLM-2Bit-1x16-hf-test-dispatch",
    dtype="auto", device_map="auto", low_cpu_mem_usage=True,
)

peft_config = LoraConfig(...)

quantized_model = get_peft_model(quantized_model, peft_config)
```

يمكنك الرجوع إلى مثال [Google Colab](https://colab.research.google.com/drive/12GTp1FCj5_0SnnNQH18h_2XFh9vS_guX?usp=sharing) للحصول على نظرة عامة على ضبط النموذج باستخدام AQLM+LoRA.

## كمّية EETQ

يمكنك أيضًا إجراء الضبط الدقيق باستخدام LoRA على النماذج المُكمّاة بتقنية EETQ. يوفر حزمة [EETQ](https://github.com/NetEase-FuXi/EETQ) طريقة بسيطة وفعّالة لإجراء التكميم بدقة 8 بت، ويُزعم أنها أسرع من خوارزمية `LLM.int8()`. أولاً، تأكد من أنك تستخدم إصدارًا من transformers متوافقًا مع EETQ (مثلًا عن طريق تثبيته من أحدث إصدار على pypi أو من المصدر).

```py
import torch
from transformers import EetqConfig

config = EetqConfig("int8")
```

مرّر `config` إلى طريقة [from_pretrained](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoModelForCausalLM.from_pretrained).

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", quantization_config=config)
```

وانشئ `LoraConfig` وقم بتمريره إلى `get_peft_model`:

```py
from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16,
    lora_alpha=8,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, config)
```

## كمّية HQQ

تدعم النماذج المُكمّمة باستخدام كمّية نصف تربيعية لنماذج التعلم الآلي الكبيرة ([HQQ](https://mobiusml.github.io/hqq_blog/)) ضبط مُكيّفات LoRA. لضبط النموذج المُكمّم، ستحتاج إلى تثبيت مكتبة `hqq` باستخدام الأمر: `pip install hqq`.

```python
from hqq.engine.hf import HQQModelForCausalLM

device = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"

quantized_model = HQQModelForCausalLM.from_quantized(save_dir_or_hfhub, device=device)
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)
```

أو باستخدام إصدار من transformers متوافق مع HQQ (على سبيل المثال، عن طريق تثبيته من أحدث إصدار على pypi أو من المصدر).

```python
from transformers import HqqConfig, AutoModelForCausalLM

quant_config = HqqConfig(nbits=4, group_size=64)
quantized_model = AutoModelForCausalLM.from_pretrained(save_dir_or_hfhub, device_map=device_map, quantization_config=quant_config)
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)
```

## torchao (تحسين بنية PyTorch)

يدعم PEFT النماذج المُكمّمة باستخدام [torchao](https://github.com/pytorch/ao) ("ao") لتكميم int8.

```python
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, TorchAoConfig
from torchao.quantization import Int8WeightOnlyConfig

model_id = ...
quantization_config = TorchAoConfig(quant_type=Int8WeightOnlyConfig())
base_model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config)
peft_config = LoraConfig(...)
model = get_peft_model(base_model, peft_config)
```

### ملاحظات:

- استخدم أحدث إصدارات من torchao (>= v0.4.0) و transformers (> 4.42).
- يتم حاليًا دعم الطبقات الخطية فقط.
- `quant_type = "int4_weight_only"` غير مدعوم حاليًا.
- لم يتم تنفيذ `NF4` في مكتبة transformers بعد، وبالتالي لا يُدعَم.
- يعمل DoRA حاليًا فقط مع `quant_type = "int8_weight_only"`.
- يوجد دعم صريح لـ torchao عند استخدامه مع LoRA. ومع ذلك، عندما يقوم torchao بتكميم طبقة، فإن فئتها لا تتغير، بل يتغير فقط نوع المصفوفة الأساسية. لهذا السبب، ستعمل بشكل عام طرق PEFT الأخرى غير LoRA مع torchao، حتى لو لم يكن هناك دعم صريح لها. لكن انتبه إلى أن **الدمج يعمل بشكل صحيح فقط مع LoRA ومع `quant_type = "int8_weight_only"`**. إذا استخدمت طريقة PEFT مختلفة أو نوع بيانات مختلف، فمن المرجح أن يؤدي الدمج إلى خطأ، وحتى لو لم يحدث خطأ، فستظل النتائج غير صحيحة.

## تكميم INC

يتيح Intel Neural Compressor ([INC](https://github.com/intel/neural-compressor)) تكميم النماذج لأجهزة متنوعة، بما في ذلك معجلات Intel Gaudi (المعروفة أيضًا بأجهزة HPU). يمكنك إجراء ضبط دقيق باستخدام LoRA على النماذج التي تم تكميمها باستخدام INC. لاستخدام INC مع نماذج PyTorch، قم بتثبيت المكتبة عبر الأمر: `pip install neural-compressor[pt]`. يمكن تكميم النموذج بدقة FP8 لأجهزة HPU من خلال سير عمل التكميم بخطوة واحدة التالي:

```python
import torch
from neural_compressor.torch.quantization import FP8Config, convert, finalize_calibration, prepare
quant_configs = {
    ...
}
config = FP8Config(**quant_configs)
```

مرّر الإعداد إلى طريقة `prepare`، ثم نفّذ الاستدلال لجمع إحصاءات المعايرة، واستدعِ طريقتي `finalize_calibration` و`convert` لتكميم النموذج بدقة FP8:

```python
model = prepare(model, config)
# Run inference to collect calibration statistics
...
# Finalize calibration and convert the model to FP8 precision
finalize_calibration(model)
model = convert(model)
# Load PEFT LoRA adapter as usual
...
```

يُقدَّم مثال يُظهر كيفية تحميل مُكيّف PEFT LoRA في نموذج FLUX لتوليد الصور من النص المُكمَّم بتقنية INC لأجهزة HPU [هنا](https://github.com/huggingface/peft/blob/main/examples/stable_diffusion/inc_flux_lora_hpu.py).

### ملاحظات:

- لا يتم دعم طريقتي `merge()` و`unmerge()` حاليًا للنماذج المُكمّاة بطريقة INC.
- حاليًا، يتم دعم طبقات **Linear** المُكمّاة بطريقة INC فقط عند تحميل محولات PEFT.

## طرق PEFT المدعومة الأخرى

بالإضافة إلى LoRA، تدعم طرق PEFT التالية التكميم:

- **VeRA** (يدعم تكميم bitsandbytes)
- **AdaLoRA** (يدعم كلًا من كميّات bitsandbytes وGPTQ)
- **(IA)³** (يدعم تكميم bitsandbytes)

## لورا لمحرك الترانسفورمر

يدعم PEFT مُكيّفات LoRA فوق طبقات [NVIDIA Transformer Engine](https://docs.nvidia.com/deeplearning/transformer-engine/) (`te.pytorch.Linear`، `te.pytorch.LayerNormLinear`، و`te.pytorch.LayerNormMLP`). تستخدم طبقات TE تنسيق FP8 والأنوية المدمجة لتسريع تدريب نماذج التحويل، وتتيح إرفاق مُكيّفات LoRA ضبطًا دقيقًا فعّالًا من حيث المعاملات للنماذج المُسرَّعة بواسطة TE.

```python
from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=8,
    lora_alpha=16,
    target_modules=["q_proj", "v_proj"],
    task_type="TOKEN_CLS",
)
model = get_peft_model(te_model, config)
```

عند تثبيت Transformer Engine، يقوم PEFT تلقائيًا بتوجيه الطبقات المطابقة إلى مُكيّف `TeLinear` — دون الحاجة إلى أي إعداد إضافي.

### ملاحظات

- `merge()` و`unmerge()` غير مدعومين بعدًا لطبقات TE.
- لا يُدعم DoRA مع طبقات TE.

يتوفر مثال كامل لتصنيف الرموز لـ ESM2 تحت `examples/lora_finetuning_transformer_engine/`.

## دمج المُكيِّفات في الأوزان المُكمَّمة

بالنسبة لأي طريقة تكميم تدعم ذلك، يقوم [merge_adapter()](/docs/peft/main/ar/package_reference/tuners#peft.tuners.tuners_utils.BaseTuner.merge_adapter) بإلغاء تكميم الوزن الأساسي، وإضافة أوزان المُكيّف، ثم إعادة تكميم النتيجة. يقوم [unmerge_adapter()](/docs/peft/main/ar/package_reference/tuners#peft.tuners.tuners_utils.BaseTuner.unmerge_adapter) بالشيء نفسه في الاتجاه المعاكس، لذا فهو لا يستعيد الأوزان المكمّمة الأصلية، كما أن تكرار دورات الدمج وإلغاء الدمج يمكن أن يؤدي إلى تراكم خطأ التقريب. لاستعادة الأوزان الأصلية، أعد تحميل النموذج الأساسي. للتبديل بين النموذج الأساسي والمُكيّف دون دمج، استخدم مدير السياق [disable_adapter()](/docs/peft/main/ar/package_reference/peft_model#peft.PeftModel.disable_adapter).

## الخطوات التالية

إذا كنت مهتمًا بمعرفة المزيد حول التكميم، فقد تكون العناصر التالية مفيدة:

* تعرّف على مزيد من التفاصيل حول QLoRA واستعرض بعض المعايير المرجعية لتأثيره في منشور المدونة [Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA](https://huggingface.co/blog/4bit-transformers-bitsandbytes).
* اقرأ المزيد حول مخططات التكميم المختلفة في دليل [Quantization](https://hf.co/docs/transformers/main/quantization) الخاص بـ Transformers.

