الدرس 21 من 24

التقييم والنشر

تقييم النماذج المضبوطة

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

بعد الضبط الدقيق، تحتاج لقياس إذا تحسن نموذجك فعلاً. دعنا نستكشف استراتيجيات ومقاييس التقييم.

لماذا التقييم مهم

الضبط الدقيق يمكن أن يفشل بطرق كثيرة:

المشكلة النتيجة
الإفراط في التدريب ممتاز على بيانات التدريب، سيء على البيانات الجديدة
نقص التدريب لا تحسن على الإطلاق
النسيان الكارثي فقد المعرفة العامة
انهيار الأسلوب مخرجات متكررة أو عامة

المقاييس التلقائية

الخسارة والحيرة

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model = AutoModelForCausalLM.from_pretrained("./outputs/fine-tuned")
tokenizer = AutoTokenizer.from_pretrained("./outputs/fine-tuned")

def calculate_perplexity(text):
    inputs = tokenizer(text, return_tensors="pt")
    with torch.no_grad():
        outputs = model(**inputs, labels=inputs["input_ids"])
        loss = outputs.loss
        perplexity = torch.exp(loss)
    return perplexity.item()

# الحيرة الأقل = أفضل
test_texts = [
    "نصك الاختباري الخاص بالمجال هنا",
    "مثال اختبار آخر"
]

for text in test_texts:
    ppl = calculate_perplexity(text)
    print(f"الحيرة: {ppl:.2f}")

مقاييس خاصة بالمهمة

from datasets import load_metric

# لمهام التصنيف
accuracy = load_metric("accuracy")
f1 = load_metric("f1")

# لمهام التوليد
bleu = load_metric("bleu")
rouge = load_metric("rouge")

# مثال: Rouge للتلخيص
predictions = ["النموذج ولّد هذا الملخص"]
references = ["الملخص المرجعي"]

rouge_scores = rouge.compute(
    predictions=predictions,
    references=references
)
print(rouge_scores)

مقارنة الأساسي مقابل المضبوط

دائماً قارن بالنموذج الأساسي:

from unsloth import FastLanguageModel

# حمّل كلا النموذجين
base_model, tokenizer = FastLanguageModel.from_pretrained(
    "unsloth/Llama-3.2-3B-Instruct",
    max_seq_length=2048,
    load_in_4bit=True,
)

fine_tuned_model, _ = FastLanguageModel.from_pretrained(
    "./outputs/fine-tuned",
    max_seq_length=2048,
    load_in_4bit=True,
)

# جهّز للاستنتاج
FastLanguageModel.for_inference(base_model)
FastLanguageModel.for_inference(fine_tuned_model)

# محث الاختبار
test_prompt = "سؤالك الخاص بالمجال هنا"

def generate(model, prompt):
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    outputs = model.generate(
        **inputs,
        max_new_tokens=200,
        temperature=0.7,
    )
    return tokenizer.decode(outputs[0], skip_special_tokens=True)

print("=== النموذج الأساسي ===")
print(generate(base_model, test_prompt))

print("\n=== النموذج المضبوط ===")
print(generate(fine_tuned_model, test_prompt))

إطار التقييم

أنشئ تقييماً منهجياً:

import json
from datetime import datetime

class ModelEvaluator:
    def __init__(self, model, tokenizer, model_name):
        self.model = model
        self.tokenizer = tokenizer
        self.model_name = model_name
        self.results = []

    def evaluate_prompt(self, prompt, expected_keywords=None):
        """قيّم محث واحد"""
        response = self.generate(prompt)

        result = {
            "prompt": prompt,
            "response": response,
            "response_length": len(response),
            "timestamp": datetime.now().isoformat()
        }

        # تحقق من الكلمات المفتاحية المتوقعة
        if expected_keywords:
            found = sum(1 for kw in expected_keywords if kw.lower() in response.lower())
            result["keyword_match"] = found / len(expected_keywords)

        self.results.append(result)
        return result

    def generate(self, prompt):
        inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
        outputs = self.model.generate(**inputs, max_new_tokens=200)
        return self.tokenizer.decode(outputs[0], skip_special_tokens=True)

    def save_results(self, filename):
        with open(filename, "w") as f:
            json.dump(self.results, f, indent=2)

# الاستخدام
evaluator = ModelEvaluator(fine_tuned_model, tokenizer, "my-fine-tuned")

test_cases = [
    {"prompt": "السؤال 1", "expected_keywords": ["كلمة1", "كلمة2"]},
    {"prompt": "السؤال 2", "expected_keywords": ["كلمة3"]},
]

for test in test_cases:
    evaluator.evaluate_prompt(test["prompt"], test["expected_keywords"])

evaluator.save_results("evaluation_results.json")

التقييم البشري

للجودة الذاتية، التقييم البشري ضروري:

معايير التقييم

المعيار الدرجة 1-5 الوصف
الصلة هل يجيب على السؤال؟
الدقة هل المعلومات صحيحة؟
الطلاقة هل هو مكتوب جيداً؟
الفائدة هل هو مفيد؟
الأمان هل هو مناسب؟

اختبار A/B

import random

def blind_comparison(prompt, model_a, model_b, tokenizer):
    """ولّد استجابات من كلا النموذجين بترتيب عشوائي"""
    response_a = generate(model_a, prompt, tokenizer)
    response_b = generate(model_b, prompt, tokenizer)

    # عشوائية الترتيب
    if random.random() > 0.5:
        return [
            {"label": "A", "response": response_a, "model": "fine-tuned"},
            {"label": "B", "response": response_b, "model": "base"}
        ]
    else:
        return [
            {"label": "A", "response": response_b, "model": "base"},
            {"label": "B", "response": response_a, "model": "fine-tuned"}
        ]

# المقيّم البشري يرى استجابات معنونة A و B
# يسجل أيهما يفضل دون معرفة أي نموذج أنتج كل استجابة

قائمة فحص التقييم

قبل النشر، تحقق من:

  • الخسارة تناقصت أثناء التدريب
  • خسارة التحقق لم تتباعد (لا إفراط في التدريب)
  • النموذج يستجيب صحيحاً للمحثات الخاصة بالمجال
  • النموذج لا يزال يتعامل مع المحثات العامة (لا نسيان كارثي)
  • أسلوب الاستجابة يطابق التوقعات
  • لا مخرجات ضارة أو غير مناسبة
  • سرعة الاستنتاج مقبولة

نصيحة: أنشئ مجموعة اختبار معيارية من 20-50 محث تغطي جميع حالات استخدامك. شغّل هذا التقييم بعد كل تشغيل تدريب لتتبع التحسينات.

بعد ذلك، لنتعلم كيفية تشخيص وإصلاح مشاكل التدريب الشائعة. :::

اختبار

الوحدة 6: التقييم والنشر

خذ الاختبار