التقييم والنشر
تقييم النماذج المضبوطة
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 محث تغطي جميع حالات استخدامك. شغّل هذا التقييم بعد كل تشغيل تدريب لتتبع التحسينات.
بعد ذلك، لنتعلم كيفية تشخيص وإصلاح مشاكل التدريب الشائعة. :::