الدرس 23 من 24

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

النشر على Ollama

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

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

نظرة عامة على خط أنابيب التصدير

النموذج المضبوط (صيغة HF)
    دمج أوزان LoRA
    تحويل إلى GGUF
    إنشاء Modelfile لـ Ollama
    استيراد إلى Ollama
    تشغيل محلياً!

الخطوة 1: دمج أوزان LoRA

أولاً، ادمج محولات LoRA مع النموذج الأساسي:

from unsloth import FastLanguageModel

# حمّل نموذجك المضبوط
model, tokenizer = FastLanguageModel.from_pretrained(
    "./outputs/fine-tuned",
    max_seq_length=2048,
    load_in_4bit=False,  # حمّل بدقة كاملة للدمج
)

# ادمج أوزان LoRA في النموذج الأساسي
model.save_pretrained_merged(
    "./outputs/merged",
    tokenizer,
    save_method="merged_16bit",  # أوزان مدموجة بدقة كاملة
)

print("النموذج المدموج حُفظ في ./outputs/merged")

الخطوة 2: التحويل إلى GGUF

GGUF هي صيغة Ollama الأصلية. Unsloth يستطيع التصدير مباشرة:

from unsloth import FastLanguageModel

model, tokenizer = FastLanguageModel.from_pretrained(
    "./outputs/fine-tuned",
    max_seq_length=2048,
    load_in_4bit=False,
)

# صدّر إلى GGUF مع التكميم
model.save_pretrained_gguf(
    "./outputs/gguf",
    tokenizer,
    quantization_method="q4_k_m",  # توازن جيد بين الجودة/الحجم
)

خيارات التكميم

الطريقة الحجم الجودة السرعة حالة الاستخدام
q4_k_m صغير جيدة سريع استخدام عام
q5_k_m متوسط أفضل متوسط التركيز على الجودة
q8_0 كبير الأفضل أبطأ أقصى جودة
f16 الأكبر مثالية الأبطأ مرجعي
# لمستويات تكميم مختلفة
for quant in ["q4_k_m", "q5_k_m", "q8_0"]:
    model.save_pretrained_gguf(
        f"./outputs/gguf-{quant}",
        tokenizer,
        quantization_method=quant,
    )

الخطوة 3: إنشاء Modelfile

أنشئ Modelfile لـ Ollama لتكوين نموذجك:

# أنشئ Modelfile
cat > Modelfile << 'EOF'
# النموذج الأساسي من ملف GGUF
FROM ./outputs/gguf/unsloth.Q4_K_M.gguf

# معاملات النموذج
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER top_k 40
PARAMETER num_ctx 2048

# محث النظام (خصصه لحالة استخدامك)
SYSTEM """أنت مساعد مفيد متخصص في [مجالك].
تقدم استجابات دقيقة وموجزة ومفيدة."""

# قالب المحادثة (طابق صيغة تدريبك)
TEMPLATE """{{ if .System }}<|start_header_id|>system<|end_header_id|>

{{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|>

{{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|>

{{ .Response }}<|eot_id|>"""

# رموز التوقف
PARAMETER stop "<|eot_id|>"
PARAMETER stop "<|end_of_text|>"
EOF

الخطوة 4: الاستيراد إلى Ollama

# أنشئ النموذج في Ollama
ollama create my-fine-tuned -f Modelfile

# تحقق من إنشائه
ollama list

# اختبر النموذج
ollama run my-fine-tuned "محثك الاختباري هنا"

سكريبت النشر الكامل

إليك سكريبت كامل يجمع كل الخطوات:

from unsloth import FastLanguageModel
import subprocess
import os

def deploy_to_ollama(
    model_path: str,
    model_name: str,
    quantization: str = "q4_k_m",
    system_prompt: str = "أنت مساعد مفيد."
):
    """انشر نموذجاً مضبوطاً إلى Ollama"""

    print(f"تحميل النموذج من {model_path}...")
    model, tokenizer = FastLanguageModel.from_pretrained(
        model_path,
        max_seq_length=2048,
        load_in_4bit=False,
    )

    # صدّر إلى GGUF
    gguf_dir = f"./outputs/{model_name}-gguf"
    print(f"تصدير إلى GGUF ({quantization})...")
    model.save_pretrained_gguf(
        gguf_dir,
        tokenizer,
        quantization_method=quantization,
    )

    # ابحث عن ملف GGUF
    gguf_file = None
    for f in os.listdir(gguf_dir):
        if f.endswith(".gguf"):
            gguf_file = os.path.join(gguf_dir, f)
            break

    if not gguf_file:
        raise FileNotFoundError("ملف GGUF لم يُنشأ")

    # أنشئ Modelfile
    modelfile_content = f'''FROM {gguf_file}

PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER num_ctx 2048

SYSTEM """{system_prompt}"""

TEMPLATE """{{{{ if .System }}}}<|start_header_id|>system<|end_header_id|>

{{{{ .System }}}}<|eot_id|>{{{{ end }}}}{{{{ if .Prompt }}}}<|start_header_id|>user<|end_header_id|>

{{{{ .Prompt }}}}<|eot_id|>{{{{ end }}}}<|start_header_id|>assistant<|end_header_id|>

{{{{ .Response }}}}<|eot_id|>"""

PARAMETER stop "<|eot_id|>"
'''

    modelfile_path = os.path.join(gguf_dir, "Modelfile")
    with open(modelfile_path, "w") as f:
        f.write(modelfile_content)

    # أنشئ نموذج Ollama
    print(f"إنشاء نموذج Ollama '{model_name}'...")
    subprocess.run(["ollama", "create", model_name, "-f", modelfile_path], check=True)

    print(f"النموذج '{model_name}' جاهز! شغّل بـ: ollama run {model_name}")
    return model_name

# الاستخدام
deploy_to_ollama(
    model_path="./outputs/fine-tuned",
    model_name="my-domain-expert",
    quantization="q4_k_m",
    system_prompt="أنت خبير في [مجالك]. قدم استجابات مفصلة ودقيقة."
)

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

الاختبار التفاعلي

# ابدأ محادثة تفاعلية
ollama run my-fine-tuned

# اختبر محثات محددة
echo "سؤالك الاختباري" | ollama run my-fine-tuned

اختبار API

import requests

def query_ollama(prompt: str, model: str = "my-fine-tuned"):
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={
            "model": model,
            "prompt": prompt,
            "stream": False
        }
    )
    return response.json()["response"]

# اختبار
response = query_ollama("ما هو تخصصك؟")
print(response)

قياس الأداء

import time

def benchmark_model(model: str, prompts: list, num_runs: int = 3):
    """قياس سرعة الاستنتاج"""
    times = []

    for prompt in prompts:
        for _ in range(num_runs):
            start = time.time()
            query_ollama(prompt, model)
            times.append(time.time() - start)

    avg_time = sum(times) / len(times)
    print(f"متوسط وقت الاستجابة: {avg_time:.2f}ث")
    print(f"الإنتاجية: {1/avg_time:.2f} استجابة/ثانية")

test_prompts = [
    "سؤال قصير؟",
    "سؤال متوسط الطول يتطلب المزيد من التفكير والتفصيل في الاستجابة.",
    "سؤال أطول وأكثر تعقيداً يختبر قدرة النموذج على التعامل مع الاستفسارات المفصلة ذات الأجزاء المتعددة."
]

benchmark_model("my-fine-tuned", test_prompts)

إدارة نماذج Ollama

# اعرض كل النماذج
ollama list

# أظهر معلومات النموذج
ollama show my-fine-tuned

# احذف نموذجاً
ollama rm my-fine-tuned

# انسخ/أعد تسمية نموذج
ollama cp my-fine-tuned my-fine-tuned-backup

# ادفع إلى سجل Ollama (يتطلب حساب)
ollama push username/my-fine-tuned

استكشاف أخطاء النشر

المشكلة الحل
فشل تحويل GGUF تأكد من تثبيت llama.cpp، جرب تكميماً مختلفاً
صيغة محادثة خاطئة حدّث TEMPLATE في Modelfile ليطابق صيغة التدريب
النموذج بطيء جداً استخدم تكميماً أصغر (q4_k_m) أو قلل السياق
النموذج كبير جداً استخدم تكميماً أكثر عدوانية
Ollama لا يجد النموذج تحقق أن مسار FROM في Modelfile صحيح

نصيحة: اختبر GGUF مع llama.cpp مباشرة قبل إنشاء نموذج Ollama. هذا يساعد على عزل ما إذا كانت المشاكل في التصدير أو تكوين Modelfile.

بعد ذلك، لنستكشف ما هو التالي في رحلة تعلمك. :::

اختبار

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

خذ الاختبار