الدرس 12 من 24

LoRA و QLoRA عملياً

أول ضبط دقيق لك

3 دقيقة للقراءة

دعنا نجمع كل شيء معاً ونشغّل مهمة ضبط دقيق كاملة باستخدام SFTTrainer من مكتبة TRL.

سكريبت التدريب الكامل

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

# ============================================
# 1. التكوين
# ============================================
model_name = "meta-llama/Llama-3.2-3B-Instruct"
output_dir = "./outputs/my-first-finetune"
max_seq_length = 2048

# ============================================
# 2. تحميل وإعداد مجموعة البيانات
# ============================================
dataset = load_dataset("tatsu-lab/alpaca", split="train")

# اختياري: خذ مجموعة فرعية للاختبار
dataset = dataset.select(range(1000))

def format_instruction(example):
    """نسّق مجموعة البيانات لصيغة التعليمات."""
    if example.get("input", ""):
        text = f"""### التعليمة:
{example['instruction']}

### المدخل:
{example['input']}

### الاستجابة:
{example['output']}"""
    else:
        text = f"""### التعليمة:
{example['instruction']}

### الاستجابة:
{example['output']}"""
    return {"text": text}

dataset = dataset.map(format_instruction)

# قسّم إلى تدريب/تحقق
dataset = dataset.train_test_split(test_size=0.1)
train_dataset = dataset["train"]
eval_dataset = dataset["test"]

print(f"حجم التدريب: {len(train_dataset)}")
print(f"حجم التقييم: {len(eval_dataset)}")

# ============================================
# 3. تحميل النموذج مع QLoRA
# ============================================
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",
    trust_remote_code=True
)

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)
model.print_trainable_parameters()

# ============================================
# 5. تحميل المُرمّز
# ============================================
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# ============================================
# 6. معاملات التدريب
# ============================================
training_args = TrainingArguments(
    output_dir=output_dir,
    num_train_epochs=3,
    per_device_train_batch_size=4,
    per_device_eval_batch_size=4,
    gradient_accumulation_steps=4,
    gradient_checkpointing=True,
    learning_rate=2e-4,
    weight_decay=0.01,
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
    logging_steps=10,
    save_steps=100,
    eval_strategy="steps",
    eval_steps=100,
    save_total_limit=3,
    bf16=True,
    max_grad_norm=0.3,
    group_by_length=True,
    report_to="none",  # أو "wandb" لتتبع التجارب
)

# ============================================
# 7. تهيئة المدرّب
# ============================================
trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    processing_class=tokenizer,
    max_seq_length=max_seq_length,
    dataset_text_field="text",
    packing=False,
)

# ============================================
# 8. درّب!
# ============================================
print("بدء التدريب...")
trainer.train()

# ============================================
# 9. احفظ النموذج
# ============================================
trainer.save_model(f"{output_dir}/final")
tokenizer.save_pretrained(f"{output_dir}/final")

print(f"اكتمل التدريب! النموذج حُفظ في {output_dir}/final")

فهم معاملات التدريب

حجم الدفعة والتراكم

# حجم الدفعة الفعال = per_device * devices * accumulation
# مثال: 4 * 1 * 4 = 16 حجم دفعة فعال
per_device_train_batch_size=4,
gradient_accumulation_steps=4,

جدولة معدل التعلم

learning_rate=2e-4,           # معدل التعلم الذروة
warmup_ratio=0.03,            # 3% من الخطوات للإحماء
lr_scheduler_type="cosine",   # تناقص جيب تمام بعد الإحماء

تحسين الذاكرة

gradient_checkpointing=True,  # استبدل الحساب بالذاكرة
bf16=True,                    # استخدم دقة BFloat16
max_grad_norm=0.3,            # قص التدرج

اختبار نموذجك المضبوط

from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# حمّل النموذج الأساسي والمحول
base_model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-3B-Instruct",
    torch_dtype=torch.bfloat16,
    device_map="auto"
)

model = PeftModel.from_pretrained(
    base_model,
    "./outputs/my-first-finetune/final"
)

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct")

# اختبر التوليد
prompt = """### التعليمة:
اكتب قصيدة قصيرة عن التعلم الآلي.

### الاستجابة:
"""

inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

outputs = model.generate(
    **inputs,
    max_new_tokens=200,
    temperature=0.7,
    do_sample=True
)

response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(response)

دمج المحولات (اختياري)

للنشر، يمكنك دمج محولات LoRA في النموذج الأساسي:

from peft import PeftModel
from transformers import AutoModelForCausalLM
import torch

# حمّل النموذج الأساسي (دقة كاملة للدمج)
base_model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-3B-Instruct",
    torch_dtype=torch.float16,
    device_map="auto"
)

# حمّل وادمج المحول
model = PeftModel.from_pretrained(base_model, "./outputs/my-first-finetune/final")
merged_model = model.merge_and_unload()

# احفظ النموذج المدمج
merged_model.save_pretrained("./outputs/merged-model")

نصائح التدريب

راقب منحنيات الخسارة

التدريب الجيد يُظهر:

  • خسارة تدريب متناقصة
  • خسارة تحقق تستقر (لا تزيد)
  • لا قفزات مفاجئة

نقاط الحفظ

# احفظ نقاط الحفظ بشكل متكرر
save_steps=100,
save_total_limit=3,  # احتفظ بآخر 3 نقاط حفظ فقط

استئناف التدريب

# استأنف من نقطة حفظ
trainer.train(resume_from_checkpoint="./outputs/checkpoint-500")

النتائج المتوقعة

لضبط دقيق بـ 1000 مثال على Llama 3.2 3B:

المقياس المتوقع
وقت التدريب 30-60 دقيقة (A100)
الخسارة النهائية 0.5-1.5
استخدام VRAM 8-12 GB
حجم نقطة الحفظ ~100 MB (LoRA فقط)

نصيحة: ابدأ بمجموعة بيانات صغيرة (100-1000 مثال) للتحقق أن كل شيء يعمل، ثم كبّر.

في الوحدة التالية، سنتعلم كيف يمكن لـ Unsloth جعل هذا أسرع مرتين مع 70% أقل ذاكرة. :::

اختبار

الوحدة 3: LoRA و QLoRA عملياً

خذ الاختبار