LoRA و QLoRA عملياً
QLoRA: الضبط الدقيق 4-bit
3 دقيقة للقراءة
QLoRA يجمع LoRA مع تكميم 4-bit، مما يتيح ضبط النماذج الكبيرة على GPUs المستهلك. دعنا نفهم كيف يعمل وكيف نُعده.
كيف يعمل QLoRA
QLoRA لديه ثلاثة ابتكارات رئيسية:
- 4-bit NormalFloat (NF4) - صيغة تكميم محسّنة لأوزان الشبكات العصبية
- التكميم المزدوج - يُكمّم ثوابت التكميم لتوفير ذاكرة إضافي
- المحسّنات المُرقّمة - تستخدم ذاكرة CPU لحالات المحسّن عندما تنفد GPU
نموذج 7B قياسي: ~14GB VRAM (fp16)
مع QLoRA: ~4-6GB VRAM
التوفير: 60-70% أقل VRAM
BitsAndBytesConfig
التكوين الأساسي لتكميم 4-bit:
from transformers import BitsAndBytesConfig
import torch
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # فعّل تحميل 4-bit
bnb_4bit_quant_type="nf4", # تكميم NormalFloat4
bnb_4bit_compute_dtype=torch.bfloat16, # دقة الحساب
bnb_4bit_use_double_quant=True # التكميم المزدوج
)
تعمّق في المعاملات
load_in_4bit
يفعّل تكميم 4-bit. أوزان النموذج تُخزن في 4-bit لكن تُحسب بدقة أعلى.
bnb_4bit_quant_type
| النوع | الوصف | الأفضل لـ |
|---|---|---|
| "nf4" | NormalFloat4 - محسّن للأوزان الموزعة طبيعياً | معظم الحالات |
| "fp4" | float 4-bit قياسي | التوافق |
# NF4 (موصى)
bnb_config = BitsAndBytesConfig(bnb_4bit_quant_type="nf4")
bnb_4bit_compute_dtype
نوع البيانات المستخدم للحساب أثناء التمرير الأمامي/الخلفي:
# BFloat16 (موصى لـ GPUs الحديثة)
bnb_config = BitsAndBytesConfig(bnb_4bit_compute_dtype=torch.bfloat16)
# Float16 (لـ GPUs الأقدم أو التوافق)
bnb_config = BitsAndBytesConfig(bnb_4bit_compute_dtype=torch.float16)
bnb_4bit_use_double_quant
يُكمّم ثوابت التكميم، يوفر ~0.4 bit لكل معامل:
# فعّل التكميم المزدوج (موصى)
bnb_config = BitsAndBytesConfig(bnb_4bit_use_double_quant=True)
تحميل نموذج مع QLoRA
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
import torch
# 1. كوّن التكميم
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True
)
# 2. حمّل النموذج المُكمّم
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.2-8B-Instruct",
quantization_config=bnb_config,
device_map="auto",
torch_dtype=torch.bfloat16
)
# 3. جهّز للتدريب
model = prepare_model_for_kbit_training(model)
# 4. أضف محولات LoRA
lora_config = LoraConfig(
r=16,
lora_alpha=16,
target_modules="all-linear",
lora_dropout=0.0,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
# 5. حمّل المُرمّز
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-8B-Instruct")
tokenizer.pad_token = tokenizer.eos_token
مقارنة الذاكرة
| النموذج | ضبط كامل | LoRA (fp16) | QLoRA (4-bit) |
|---|---|---|---|
| Llama 3.2 1B | 8GB | 4GB | 2GB |
| Llama 3.2 3B | 24GB | 12GB | 4GB |
| Llama 3.2 8B | 64GB | 18GB | 6GB |
| Mistral 7B | 56GB | 16GB | 5GB |
| Llama 3.3 70B | 560GB | 160GB | 24GB |
Gradient Checkpointing
قلل الذاكرة أكثر بإعادة حساب التنشيطات أثناء التمرير الخلفي:
# فعّل gradient checkpointing
model.gradient_checkpointing_enable()
model.enable_input_require_grads()
# أو عبر معاملات التدريب
training_args = TrainingArguments(
gradient_checkpointing=True,
...
)
إعداد QLoRA الكامل
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from trl import SFTTrainer
from datasets import load_dataset
# تكوين النموذج
model_name = "meta-llama/Llama-3.2-3B-Instruct"
# تكوين التكميم
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True
)
# حمّل النموذج
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto"
)
# جهّز لتدريب k-bit
model = prepare_model_for_kbit_training(model)
model.gradient_checkpointing_enable()
# تكوين LoRA
lora_config = LoraConfig(
r=16,
lora_alpha=16,
target_modules="all-linear",
lora_dropout=0.0,
bias="none",
task_type="CAUSAL_LM"
)
# طبّق LoRA
model = get_peft_model(model, lora_config)
# تحقق من المعاملات القابلة للتدريب
model.print_trainable_parameters()
# حمّل المُرمّز
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
المشاكل الشائعة والحلول
خسارة NaN
# استخدم قص التدرج
training_args = TrainingArguments(
max_grad_norm=0.3, # أقل من الافتراضي 1.0
...
)
تدريب بطيء
# فعّل Flash Attention 2
model = AutoModelForCausalLM.from_pretrained(
model_name,
attn_implementation="flash_attention_2",
...
)
نفاد الذاكرة
# قلل حجم الدفعة واستخدم تراكم التدرج
training_args = TrainingArguments(
per_device_train_batch_size=1,
gradient_accumulation_steps=8,
...
)
نصيحة: QLoRA هو الخيار الأمثل لـ GPUs المستهلك. ابدأ هنا، وانتقل لـ LoRA الكامل فقط إذا كان لديك VRAM واحتجت تحسين الجودة الطفيف.
بعد ذلك، سنجمع كل شيء معاً ونشغّل مهمة ضبط دقيق كاملة. :::