Fine-Tuning چیست؟ آموزش کامل فاین‌تیون مدل‌های زبانی با LoRA و QLoRA

در این راهنمای فنی، Fine-Tuning مدل‌های زبانی را از طراحی دیتاست و SFT تا LoRA، QLoRA، تنظیم Hyperparameter، ارزیابی، جلوگیری از Overfitting و استقرار مدل آموزش می‌دهیم.

Share
Fine-Tuning چیست؟ آموزش کامل فاین‌تیون مدل‌های زبانی با LoRA و QLoRA

Fine-Tuning یا فاین‌تیون، فرایند ادامه‌دادن آموزش یک مدل ازپیش‌آموزش‌دیده برای سازگارکردن رفتار آن با یک وظیفه، دامنه، سبک پاسخ یا الگوی خروجی مشخص است.

به‌جای آموزش یک مدل زبانی بزرگ یا Large Language Model از صفر، یک مدل پایه انتخاب می‌کنیم و آن را با مجموعه‌ای از نمونه‌های باکیفیت آموزش می‌دهیم. نتیجه می‌تواند مدلی باشد که:

  • دستورهای تخصصی را بهتر دنبال می‌کند
  • لحن و قالب خروجی ثابتی دارد
  • داده ساختاریافته دقیق‌تری تولید می‌کند
  • روی یک وظیفه مشخص بهتر عمل می‌کند
  • اصطلاحات یک حوزه را بهتر می‌شناسد
  • پاسخ‌های کوتاه‌تر یا تخصصی‌تری می‌دهد
  • Tool Calling را با الگوی موردنظر انجام می‌دهد
  • زبان یا سبک نگارشی مشخصی را بهتر تولید می‌کند

اما Fine-Tuning راه‌حل همه مشکلات نیست. اگر هدف شما اضافه‌کردن اطلاعات جدید، خصوصی یا دائماً در حال تغییر به مدل باشد، احتمالاً RAG انتخاب مناسب‌تری است. اگر فقط می‌خواهید لحن یا ساختار پاسخ را کنترل کنید، ممکن است Prompt Engineering کافی باشد.

در این مقاله، Fine-Tuning را از دید یک مهندس هوش مصنوعی بررسی می‌کنیم و یک جریان عملی برای فاین‌تیون مدل‌های زبانی با Supervised Fine-Tuning، LoRA و QLoRA می‌سازیم.

Fine-Tuning چیست؟

یک مدل پایه پس از Pretraining، الگوهای عمومی زبان، کدنویسی، استدلال و دانش موجود در داده آموزشی خود را یاد گرفته است. Fine-Tuning این مدل را با داده‌های محدودتر و هدفمندتر سازگار می‌کند.

اگر پارامترهای مدل پایه را با (\theta) نمایش دهیم، هدف آموزش می‌تواند کمینه‌کردن خطای پیش‌بینی توکن بعدی روی دیتاست تخصصی باشد:

[
\mathcal{L}(\theta) =
-\sum_{i=1}^{N}
\sum_{t=1}^{T_i}
\log P_\theta(y_{i,t} \mid x_i, y_{i,<t})
]

در این رابطه:

  • (x_i) ورودی یا Prompt نمونه است
  • (y_i) پاسخ هدف است
  • (T_i) تعداد Tokenهای پاسخ است
  • (P_\theta) احتمال پیش‌بینی‌شده توسط مدل است
  • (\mathcal{L}) تابع Loss یا خطاست

در Full Fine-Tuning تمام یا بخش بزرگی از پارامترهای مدل به‌روزرسانی می‌شوند. در روش‌های Parameter-Efficient Fine-Tuning یا PEFT، بیشتر وزن‌های مدل ثابت می‌مانند و فقط تعداد محدودی پارامتر اضافه‌شده آموزش داده می‌شوند.

تفاوت Pretraining و Fine-Tuning

Pretraining

در Pretraining، مدل روی حجم بسیار بزرگی از داده آموزش می‌بیند تا ساختار عمومی زبان و الگوهای جهان را یاد بگیرد.

ویژگی‌های Pretraining:

  • دیتاست بسیار بزرگ
  • هزینه محاسباتی سنگین
  • زمان آموزش طولانی
  • نیاز به زیرساخت توزیع‌شده
  • هدف عمومی
  • تولید یک Base Model

Fine-Tuning

در Fine-Tuning، یک مدل آماده روی داده محدودتر و هدفمندتر آموزش داده می‌شود.

ویژگی‌های Fine-Tuning:

  • دیتاست کوچک‌تر
  • هزینه کمتر
  • هدف مشخص
  • قابل‌اجرا با زیرساخت محدودتر
  • امکان استفاده از LoRA و QLoRA
  • تولید مدل یا Adapter تخصصی

به زبان ساده:

Pretraining:
یادگیری عمومی زبان و جهان

Fine-Tuning:
سازگارکردن رفتار مدل با نیاز مشخص

انواع Fine-Tuning مدل‌های زبانی

Fine-Tuning فقط یک روش ندارد. براساس هدف و نوع داده می‌توان از روش‌های مختلف استفاده کرد.

Supervised Fine-Tuning یا SFT

Supervised Fine-Tuning رایج‌ترین شکل تنظیم دقیق مدل‌های زبانی است. در SFT، دیتاست شامل ورودی و پاسخ مطلوب است.

نمونه:

{
  "messages": [
    {
      "role": "system",
      "content": "شما دستیار پشتیبانی یک فروشگاه اینترنتی هستید."
    },
    {
      "role": "user",
      "content": "چگونه سفارش خود را پیگیری کنم؟"
    },
    {
      "role": "assistant",
      "content": "از بخش سفارش‌های من، سفارش موردنظر را باز کنید و وضعیت ارسال را ببینید."
    }
  ]
}

مدل یاد می‌گیرد وقتی ورودی مشابهی دریافت کرد، پاسخی نزدیک به نمونه هدف تولید کند.

SFT برای این موارد مناسب است:

  • آموزش قالب پاسخ
  • سازگارکردن لحن
  • طبقه‌بندی با خروجی متنی
  • استخراج اطلاعات
  • تبدیل متن به JSON
  • خلاصه‌سازی تخصصی
  • آموزش Tool Calling
  • پاسخ‌گویی در یک حوزه محدود
  • بهبود زبان یا گویش مشخص

کتابخانه TRL از Hugging Face، کلاس SFTTrainer را برای اجرای Supervised Fine-Tuning ارائه می‌کند. مستندات رسمی SFTTrainer

Instruction Tuning

Instruction Tuning نوعی SFT است که مدل را روی مجموعه متنوعی از دستورها و پاسخ‌ها آموزش می‌دهد. هدف این است که مدل توانایی دنبال‌کردن Instructionهای جدید را بهتر یاد بگیرد.

نمونه وظایف در یک دیتاست Instruction Tuning:

  • خلاصه‌کردن متن
  • طبقه‌بندی
  • بازنویسی
  • پاسخ به سؤال
  • تولید JSON
  • استخراج Entity
  • ترجمه
  • تحلیل احساسات
  • تولید کد

تنوع وظایف اهمیت دارد. اگر همه نمونه‌ها فقط یک ساختار محدود داشته باشند، مدل ممکن است روی همان الگو Overfit شود.

Continued Pretraining

Continued Pretraining یا Domain-Adaptive Pretraining برای ادامه آموزش مدل روی حجم بزرگی از متن خام یک حوزه استفاده می‌شود.

برای مثال:

  • مقالات پزشکی
  • متون حقوقی
  • اسناد مالی
  • کد یک زبان برنامه‌نویسی
  • متون فارسی تخصصی
  • مستندات صنعتی

در این روش الزاماً مجموعه‌ای از سؤال و پاسخ نداریم. مدل مانند مرحله Pretraining، پیش‌بینی توکن بعدی را روی متن خام ادامه می‌دهد.

Continued Pretraining بیشتر برای یادگیری زبان و اصطلاحات حوزه مناسب است، درحالی‌که SFT برای آموزش رفتار مطلوب استفاده می‌شود.

یک جریان حرفه‌ای می‌تواند به این صورت باشد:

Base Model
   ↓
Continued Pretraining روی متن تخصصی
   ↓
Supervised Fine-Tuning روی دستور و پاسخ
   ↓
Preference Optimization
   ↓
Evaluation

Preference Fine-Tuning

در Preference Fine-Tuning، دیتاست مشخص می‌کند کدام پاسخ نسبت به پاسخ دیگر بهتر است.

نمونه:

{
  "prompt": "تفاوت Cache و Database چیست؟",
  "chosen": "پاسخ دقیق، ساختاریافته و دارای مثال",
  "rejected": "پاسخ مبهم یا نادرست"
}

روش‌هایی مانند DPO یا Direct Preference Optimization از چنین داده‌ای برای سازگارکردن مدل با ترجیحات انسانی استفاده می‌کنند.

Preference Tuning معمولاً پس از SFT انجام می‌شود و برای بهبود موارد زیر کاربرد دارد:

  • لحن
  • میزان اختصار
  • مفیدبودن پاسخ
  • رعایت دستور
  • ایمنی
  • انتخاب پاسخ بهتر
  • کاهش رفتارهای نامطلوب

Full Fine-Tuning چیست؟

در Full Fine-Tuning همه پارامترهای مدل یا بخش بزرگی از آن‌ها آموزش داده می‌شوند.

مزایا:

  • بیشترین آزادی برای تغییر مدل
  • مناسب Domain Adaptation عمیق
  • امکان کسب بهترین کیفیت در بعضی وظایف
  • کنترل کامل روی فرایند آموزش

معایب:

  • مصرف زیاد VRAM
  • نیاز به GPUهای قدرتمند
  • هزینه ذخیره Optimizer State
  • زمان آموزش بیشتر
  • تولید Checkpoint بزرگ
  • دشواری نگهداری چند نسخه تخصصی
  • ریسک بیشتر Catastrophic Forgetting

برای مدل‌های بزرگ، Full Fine-Tuning همیشه اقتصادی یا ضروری نیست.

PEFT چیست؟

PEFT مخفف Parameter-Efficient Fine-Tuning است. در این روش‌ها فقط بخش کوچکی از پارامترها آموزش داده می‌شوند و وزن‌های اصلی مدل ثابت می‌مانند.

روش‌های PEFT شامل مواردی مانند:

  • LoRA
  • Prefix Tuning
  • Prompt Tuning
  • Adapters
  • IA3
  • AdaLoRA

استفاده از PEFT باعث کاهش موارد زیر می‌شود:

  • مصرف حافظه
  • زمان آموزش
  • اندازه Checkpoint
  • هزینه نگهداری چند مدل تخصصی

کتابخانه PEFT از Hugging Face برای اعمال این روش‌ها روی مدل‌های Transformers، Diffusers و سایر معماری‌ها طراحی شده است. مستندات رسمی Hugging Face PEFT

LoRA چیست؟

LoRA مخفف Low-Rank Adaptation است. در LoRA وزن‌های مدل پایه ثابت می‌مانند و به‌جای به‌روزرسانی مستقیم ماتریس بزرگ وزن، دو ماتریس کوچک آموزش داده می‌شوند.

فرض کنید یک لایه دارای ماتریس وزن زیر باشد:

[
W_0 \in \mathbb{R}^{d \times k}
]

در Fine-Tuning کامل، تغییر وزن (\Delta W) هم‌اندازه (W_0) خواهد بود. LoRA این تغییر را با ضرب دو ماتریس کم‌رتبه تقریب می‌زند:

[
W = W_0 + \Delta W
]

[
\Delta W = BA
]

که در آن:

[
B \in \mathbb{R}^{d \times r}
]

[
A \in \mathbb{R}^{r \times k}
]

و:

[
r \ll \min(d,k)
]

بنابراین به‌جای آموزش (d \times k) پارامتر، تقریباً (r(d+k)) پارامتر آموزش داده می‌شود.

در Forward Pass:

[
h = W_0x + \frac{\alpha}{r}BAx
]

پارامتر (\alpha) شدت اثر Adapter را کنترل می‌کند و (r) رتبه LoRA است.

مقاله اصلی LoRA نشان داد که ثابت نگه‌داشتن وزن‌های مدل و آموزش ماتریس‌های کم‌رتبه می‌تواند تعداد پارامترهای قابل‌آموزش و مصرف حافظه را به‌شدت کاهش دهد، بدون اینکه الزاماً افت کیفیت بزرگی ایجاد شود. مقاله اصلی LoRA

مزایای LoRA

  • نیاز کمتر به VRAM
  • آموزش سریع‌تر
  • Checkpoint کوچک‌تر
  • امکان نگهداری چند Adapter
  • تعویض Adapter براساس وظیفه
  • قابلیت Merge با مدل پایه
  • مناسب برای Personalization
  • کاهش هزینه آزمایش
  • پشتیبانی گسترده ابزارها

برای مثال، به‌جای ذخیره چند نسخه کامل از یک مدل ۸ میلیارد پارامتری، می‌توان یک Base Model و چند Adapter کوچک نگهداری کرد:

Base Model
├── Persian Support Adapter
├── SQL Generation Adapter
├── Customer Support Adapter
└── Medical Summarization Adapter

محدودیت‌های LoRA

LoRA بدون محدودیت نیست:

  • Rank نامناسب می‌تواند ظرفیت یادگیری را محدود کند.
  • انتخاب Target Module روی نتیجه اثر دارد.
  • Learning Rate نامناسب موجب ناپایداری می‌شود.
  • Adapter ممکن است روی داده ضعیف Overfit شود.
  • چند Adapter ناسازگار را نمی‌توان همیشه ساده ترکیب کرد.
  • کیفیت به مدل پایه وابسته است.
  • LoRA نمی‌تواند ضعف بنیادی مدل را همیشه جبران کند.
  • آموزش دانش جدید از چند نمونه محدود قابل‌اعتماد نیست.

QLoRA چیست؟

QLoRA ترکیبی از Quantization و LoRA است. در این روش، مدل پایه به‌صورت Quantized، معمولاً ۴ بیتی، در حافظه بارگذاری می‌شود و وزن‌های آن ثابت می‌مانند. Gradientها از مدل Quantized عبور می‌کنند، اما فقط Adapterهای LoRA آموزش می‌بینند.

ساختار کلی:

Frozen 4-bit Base Model
          +
Trainable LoRA Adapters
          ↓
Efficient Fine-Tuning

مقاله QLoRA سه ایده مهم را معرفی کرد:

  • 4-bit NormalFloat یا NF4
  • Double Quantization
  • Paged Optimizers

نویسندگان مقاله نشان دادند که می‌توان مدل ۶۵ میلیارد پارامتری را روی یک GPU با حافظه ۴۸ گیگابایت فاین‌تیون کرد، درحالی‌که عملکرد نزدیک به Fine-Tuning شانزده‌بیتی حفظ شود. مقاله اصلی QLoRA

تفاوت LoRA و QLoRA

معیارLoRAQLoRA
وزن مدل پایهمعمولاً FP16 یا BF16معمولاً 4-bit
پارامترهای قابل‌آموزشAdapterهای LoRAAdapterهای LoRA
مصرف VRAMپایینبسیار پایین‌تر
سرعتوابسته به سخت‌افزارQuantization سربار دارد
کیفیتمعمولاً مناسبدر بسیاری از وظایف نزدیک به LoRA
پیچیدگیکمتربیشتر
مناسب GPU محدودبلهبسیار مناسب
کتابخانه رایجPEFTPEFT + bitsandbytes

اگر GPU کافی دارید، LoRA با BF16 ساده‌تر است. اگر حافظه محدود است، QLoRA معمولاً گزینه عملی‌تری خواهد بود.

Fine-Tuning چه زمانی مناسب است؟

فاین‌تیون زمانی ارزشمند است که یک الگوی رفتاری پایدار و تکرارشونده دارید.

نمونه کاربردهای مناسب:

  • مدل همیشه JSON با Schema مشخص تولید کند.
  • پاسخ‌ها لحن و ساختار سازمانی ثابتی داشته باشند.
  • مدل یک طبقه‌بندی تخصصی انجام دهد.
  • SQL را براساس الگوی دیتابیس مشخص تولید کند.
  • Tool Calling را با ابزارهای محدود یاد بگیرد.
  • متن فارسی را با سبک نگارشی مشخص تولید کند.
  • گزارش‌ها را در قالب ثابت بنویسد.
  • داده‌ها را به ساختار استاندارد تبدیل کند.
  • نوع خاصی از کد را تولید کند.
  • پاسخ کوتاه و بدون توضیح اضافی ارائه دهد.

Fine-Tuning چه زمانی مناسب نیست؟

فاین‌تیون انتخاب خوبی نیست اگر:

  • اطلاعات دائماً تغییر می‌کنند.
  • پاسخ باید از اسناد جدید استخراج شود.
  • مشکل با Prompt بهتر حل می‌شود.
  • دیتاست باکیفیت ندارید.
  • مدل پایه قابلیت اصلی را ندارد.
  • فقط چند نمونه محدود دارید.
  • صحت factual بسیار مهم است.
  • منابع پاسخ باید قابل استناد باشند.
  • زیرساخت ارزیابی ندارید.
  • مسئله هنوز دقیق تعریف نشده است.

تفاوت Fine-Tuning، RAG و Prompt Engineering

معیارPrompt EngineeringRAGFine-Tuning
هدف اصلیهدایت مدلاضافه‌کردن Contextتغییر رفتار مدل
تغییر وزن مدلخیرخیربله یا Adapter
داده به‌روزدستی در Promptمناسبنامناسب برای تغییر مداوم
استناد به منبعمحدودمناسبذاتی نیست
هزینه پیاده‌سازیکممتوسطمتوسط تا زیاد
نیاز به دیتاست آموزشیخیراسنادنمونه‌های آموزشی
مناسب لحن ثابتتا حدیخیربله
مناسب دانش خصوصیContext محدودبسیار مناسببا ملاحظات زیاد
مناسب خروجی ساختاریافتهتا حدیتا حدیبله
سرعت Iterationبالامتوسطپایین‌تر

قانون عملی:

اگر مشکل با Prompt حل می‌شود:
Prompt Engineering

اگر مدل باید اطلاعات جدید را بازیابی کند:
RAG

اگر مدل باید رفتار جدید و پایدار یاد بگیرد:
Fine-Tuning

گاهی ترکیب هر سه بهترین نتیجه را می‌دهد:

Fine-Tuned Model
      +
RAG Context
      +
Runtime Prompt

طراحی پروژه Fine-Tuning

پیش از نوشتن کد باید مسئله را دقیق تعریف کنید.

هدف نامناسب

می‌خواهیم مدل بهتر شود.

هدف مناسب

می‌خواهیم مدل تیکت‌های پشتیبانی فارسی را در یکی از ۱۲ دسته
طبقه‌بندی کند و خروجی JSON معتبر با دقت Macro F1 حداقل 0.88 بدهد.

یا:

می‌خواهیم مدل براساس متن ورودی، سه فیلد product_name،
issue_type و urgency را استخراج کند و Schema را در حداقل
98 درصد نمونه‌ها رعایت کند.

هدف باید قابل‌اندازه‌گیری باشد.

ابتدا Baseline بسازید

پیش از Fine-Tuning، همان وظیفه را با یک مدل پایه و Prompt مناسب اجرا کنید.

مواردی که باید ثبت شوند:

  • کیفیت پاسخ
  • دقت
  • نرخ JSON معتبر
  • Latency
  • تعداد Token
  • هزینه
  • نرخ خطا
  • درصد نیاز به اصلاح انسانی

اگر Baseline به هدف می‌رسد، Fine-Tuning ممکن است ارزش اقتصادی نداشته باشد.

برای مقایسه مدل‌های پایه می‌توانید مدل‌های موجود در پنل درواره را با یک API استاندارد آزمایش کنید و نتیجه آن‌ها را روی یک Evaluation Set ثابت بسنجید.

Base URL درواره:

https://api.darvareh.ir/v1

طراحی دیتاست Fine-Tuning

کیفیت داده معمولاً از اندازه دیتاست مهم‌تر است. هزاران نمونه ضعیف می‌توانند مدل را بدتر کنند، درحالی‌که مجموعه کوچک‌تر و دقیق‌تر ممکن است نتیجه بهتری بدهد.

یک دیتاست مناسب باید:

  • با هدف پروژه مرتبط باشد
  • پاسخ‌های درست داشته باشد
  • تنوع ورودی را پوشش دهد
  • نمونه‌های مرزی داشته باشد
  • قالب یکسان و معتبر داشته باشد
  • داده تکراری نداشته باشد
  • اطلاعات حساس نداشته باشد
  • مجوز استفاده داشته باشد
  • با داده ارزیابی هم‌پوشانی نداشته باشد
  • رفتار مطلوب را نشان دهد

فرمت Conversational Dataset

برای Chat Model می‌توانید از ساختار messages استفاده کنید:

{
  "messages": [
    {
      "role": "system",
      "content": "شما یک دستیار فنی فارسی هستید."
    },
    {
      "role": "user",
      "content": "تفاوت Timeout و Retry چیست؟"
    },
    {
      "role": "assistant",
      "content": "Timeout حداکثر زمان انتظار برای یک عملیات را تعیین می‌کند، اما Retry اجرای مجدد عملیات شکست‌خورده است."
    }
  ]
}

فایل JSONL شامل یک نمونه در هر خط است:

{"messages":[{"role":"system","content":"شما یک دستیار فنی هستید."},{"role":"user","content":"Cache چیست؟"},{"role":"assistant","content":"Cache یک لایه ذخیره‌سازی سریع برای کاهش زمان دسترسی و بار سیستم است."}]}
{"messages":[{"role":"system","content":"شما یک دستیار فنی هستید."},{"role":"user","content":"Retry چیست؟"},{"role":"assistant","content":"Retry اجرای دوباره یک عملیات شکست‌خورده براساس سیاست کنترل‌شده است."}]}

فرمت Instruction Dataset

{
  "instruction": "متن را در یکی از دسته‌های پرداخت، ارسال یا حساب کاربری قرار بده.",
  "input": "پرداخت انجام دادم اما سفارش ثبت نشده است.",
  "output": "{\"category\":\"payment\"}"
}

در مرحله Formatting، این فیلدها باید به Chat Template مدل تبدیل شوند.

استفاده از Chat Template

مدل‌های مختلف قالب مکالمه متفاوتی دارند. برای مثال، نحوه نمایش Roleها و Special Tokenها ممکن است فرق کند.

استفاده دستی از قالب اشتباه می‌تواند عملکرد مدل را کاهش دهد. بهتر است از tokenizer.apply_chat_template استفاده کنید:

formatted = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=False,
)

برای Inference معمولاً:

prompt = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
)

قالب آموزش و Inference باید با یکدیگر سازگار باشند.

تقسیم Train، Validation و Test

داده را حداقل به سه بخش تقسیم کنید:

  • Train برای به‌روزرسانی وزن‌ها
  • Validation برای انتخاب Hyperparameter و Early Stopping
  • Test برای ارزیابی نهایی

نمونه تقسیم:

Train: 80%
Validation: 10%
Test: 10%

اگر داده کم است، می‌توان از Cross Validation یا Bootstrap استفاده کرد؛ اما Test Set نهایی نباید در فرایند تنظیم Hyperparameter مصرف شود.

باید مطمئن شوید نمونه‌های بسیار مشابه در Splitهای مختلف قرار نگرفته‌اند. در غیر این صورت Data Leakage ایجاد می‌شود و معیارها بیش‌ازحد خوش‌بینانه خواهند بود.

پاک‌سازی دیتاست

موارد زیر را بررسی کنید:

  • نمونه‌های تکراری
  • پاسخ‌های متناقض
  • Encoding خراب
  • متن ناقص
  • JSON نامعتبر
  • زبان اشتباه
  • اطلاعات شخصی
  • Secret و API Key
  • محتوای بدون مجوز
  • پاسخ‌های بیش‌ازحد طولانی
  • نمونه‌های خارج از دامنه
  • برچسب اشتباه
  • Prompt Injection موجود در داده

نمونه بررسی JSONL:

import json
from pathlib import Path

path = Path("train.jsonl")

valid_rows = []
errors = []

with path.open("r", encoding="utf-8") as file:
    for line_number, line in enumerate(file, start=1):
        try:
            row = json.loads(line)
            messages = row["messages"]

            if not isinstance(messages, list) or not messages:
                raise ValueError("messages must be a non-empty list")

            roles = [message.get("role") for message in messages]

            if "user" not in roles or "assistant" not in roles:
                raise ValueError("missing user or assistant message")

            for message in messages:
                content = message.get("content")

                if not isinstance(content, str) or not content.strip():
                    raise ValueError("empty message content")

            valid_rows.append(row)

        except Exception as error:
            errors.append({
                "line": line_number,
                "error": str(error),
            })

print({
    "valid": len(valid_rows),
    "errors": len(errors),
})

for error in errors[:20]:
    print(error)

داده مصنوعی یا Synthetic Data

می‌توان از یک مدل قوی‌تر برای تولید پیش‌نویس داده آموزشی استفاده کرد، اما داده مصنوعی نباید بدون کنترل انسانی وارد Train Set شود.

ریسک‌ها:

  • انتقال خطاهای مدل Teacher
  • کاهش تنوع زبانی
  • تکرار ساختار پاسخ
  • ایجاد داده‌های غیرواقعی
  • Reinforcement خطا
  • نشت اطلاعات حساس
  • ایجاد پاسخ‌های بیش‌ازحد تمیز و غیرواقعی

فرایند بهتر:

داده واقعی و مجاز
   ↓
تولید پیش‌نویس با مدل Teacher
   ↓
Validation خودکار
   ↓
بازبینی انسانی
   ↓
Deduplication
   ↓
Train Dataset

برای تولید پیش‌نویس داده می‌توانید از API مدل‌های موجود در درواره استفاده کنید، اما باید داده حساس را حذف و نمونه‌ها را انسانی اعتبارسنجی کنید.

انتخاب Base Model

انتخاب مدل پایه مهم‌تر از بسیاری از Hyperparameterهاست.

معیارها:

  • مجوز یا License
  • پشتیبانی از زبان فارسی
  • کیفیت Instruction Following
  • اندازه مدل
  • Context Window
  • معماری
  • Chat Template
  • سازگاری با PEFT
  • سازگاری با Quantization
  • نیاز سخت‌افزاری
  • سرعت Inference
  • امکان استفاده تجاری
  • کیفیت Baseline
  • پشتیبانی Tool Calling
  • جامعه و مستندات

مدلی را انتخاب نکنید که فقط در Benchmark عمومی رتبه خوبی دارد. آن را روی Evaluation Set واقعی خود آزمایش کنید.

محاسبه تقریبی حافظه

فقط وزن‌های یک مدل با (N) پارامتر در دقت (b) بیتی، تقریباً به حافظه زیر نیاز دارند:

[
Memory \approx \frac{N \times b}{8}
]

برای مدل ۸ میلیارد پارامتری:

FP16

[
8B \times 16 / 8 \approx 16GB
]

INT8

[
8B \times 8 / 8 \approx 8GB
]

INT4

[
8B \times 4 / 8 \approx 4GB
]

این اعداد فقط وزن خام هستند. در عمل حافظه بیشتری برای موارد زیر نیاز است:

  • Quantization Metadata
  • Activations
  • Gradientها
  • Optimizer State
  • CUDA Context
  • KV Cache
  • Temporary Buffers

QLoRA مصرف حافظه وزن‌های مدل را کاهش می‌دهد، اما طول Sequence و Batch Size همچنان می‌توانند VRAM زیادی مصرف کنند.

نصب ابزارهای Fine-Tuning

یک محیط Python جداگانه ایجاد کنید:

python -m venv .venv
source .venv/bin/activate

نصب کتابخانه‌ها:

pip install torch transformers datasets accelerate peft trl bitsandbytes

برای تکرارپذیری، نسخه‌ها را در پروژه واقعی Pin کنید:

torch==YOUR_TESTED_VERSION
transformers==YOUR_TESTED_VERSION
datasets==YOUR_TESTED_VERSION
accelerate==YOUR_TESTED_VERSION
peft==YOUR_TESTED_VERSION
trl==YOUR_TESTED_VERSION
bitsandbytes==YOUR_TESTED_VERSION

نسخه CUDA، Driver، PyTorch و bitsandbytes باید با یکدیگر سازگار باشند.

بررسی GPU:

import torch

print("CUDA available:", torch.cuda.is_available())

if torch.cuda.is_available():
    print("GPU:", torch.cuda.get_device_name(0))
    print(
        "BF16 supported:",
        torch.cuda.is_bf16_supported(),
    )

ساختار پیشنهادی پروژه

fine-tuning-project/
├── data/
│   ├── raw/
│   ├── processed/
│   ├── train.jsonl
│   ├── validation.jsonl
│   └── test.jsonl
├── configs/
│   └── qlora.yaml
├── scripts/
│   ├── validate_data.py
│   ├── train.py
│   ├── evaluate.py
│   └── inference.py
├── outputs/
├── tests/
├── requirements.txt
└── README.md

دیتاست خصوصی و Checkpointهای بزرگ را بدون بررسی وارد Git نکنید.

آموزش QLoRA با Hugging Face

نمونه زیر یک الگوی عمومی است. باید BASE_MODEL_ID، Target Moduleها و Chat Template را براساس مدل انتخابی تنظیم کنید.

import os
import torch

from datasets import load_dataset
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
)
from peft import LoraConfig
from trl import SFTConfig, SFTTrainer


BASE_MODEL_ID = os.environ["BASE_MODEL_ID"]
OUTPUT_DIR = "./outputs/qlora-adapter"


compute_dtype = (
    torch.bfloat16
    if torch.cuda.is_bf16_supported()
    else torch.float16
)


quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
    bnb_4bit_compute_dtype=compute_dtype,
)


tokenizer = AutoTokenizer.from_pretrained(
    BASE_MODEL_ID,
    use_fast=True,
)

if tokenizer.pad_token is None:
    tokenizer.pad_token = tokenizer.eos_token


model = AutoModelForCausalLM.from_pretrained(
    BASE_MODEL_ID,
    quantization_config=quantization_config,
    device_map="auto",
    torch_dtype=compute_dtype,
)

model.config.use_cache = False


dataset = load_dataset(
    "json",
    data_files={
        "train": "data/train.jsonl",
        "validation": "data/validation.jsonl",
    },
)


peft_config = LoraConfig(
    r=16,
    lora_alpha=32,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
    target_modules=[
        "q_proj",
        "k_proj",
        "v_proj",
        "o_proj",
        "gate_proj",
        "up_proj",
        "down_proj",
    ],
)


training_args = SFTConfig(
    output_dir=OUTPUT_DIR,
    num_train_epochs=3,
    per_device_train_batch_size=2,
    per_device_eval_batch_size=2,
    gradient_accumulation_steps=8,
    learning_rate=2e-4,
    warmup_ratio=0.03,
    weight_decay=0.01,
    logging_steps=10,
    eval_strategy="steps",
    eval_steps=100,
    save_strategy="steps",
    save_steps=100,
    save_total_limit=3,
    load_best_model_at_end=True,
    metric_for_best_model="eval_loss",
    greater_is_better=False,
    bf16=compute_dtype == torch.bfloat16,
    fp16=compute_dtype == torch.float16,
    gradient_checkpointing=True,
    max_length=2048,
    packing=False,
    report_to="none",
    seed=42,
)


trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=dataset["train"],
    eval_dataset=dataset["validation"],
    processing_class=tokenizer,
    peft_config=peft_config,
)


trainer.train()

trainer.save_model(OUTPUT_DIR)
tokenizer.save_pretrained(OUTPUT_DIR)

API کتابخانه‌های Hugging Face در طول زمان تغییر می‌کند. کد را با نسخه‌های Pinشده پروژه و مستندات همان نسخه تطبیق دهید.

Target Modules در LoRA

Target Moduleها لایه‌هایی هستند که Adapter به آن‌ها اضافه می‌شود.

در مدل‌های Transformer رایج ممکن است شامل این موارد باشند:

q_proj
k_proj
v_proj
o_proj
gate_proj
up_proj
down_proj

اما نام لایه‌ها در همه مدل‌ها یکسان نیست. برای بررسی:

for name, module in model.named_modules():
    if "proj" in name:
        print(name, type(module).__name__)

انتخاب فقط Attention Projectionها حافظه کمتری مصرف می‌کند. اضافه‌کردن MLP Projectionها ظرفیت یادگیری را افزایش می‌دهد، اما Adapter بزرگ‌تر و آموزش سنگین‌تر می‌شود.

Hyperparameterهای مهم LoRA

Rank یا r

Rank ظرفیت Adapter را تعیین می‌کند.

مقادیر رایج برای شروع:

8
16
32
64

Rank بالاتر:

  • پارامتر بیشتر
  • حافظه بیشتر
  • ظرفیت یادگیری بیشتر
  • ریسک بیشتر Overfitting

همیشه Rank بالاتر بهتر نیست. آن را با Validation Set انتخاب کنید.

lora_alpha

اثر LoRA معمولاً با نسبت (\alpha/r) مقیاس می‌شود.

نمونه:

r=16
lora_alpha=32

هیچ مقدار جهانی مناسبی وجود ندارد. ترکیب‌های مختلف را روی یک آزمایش کوچک مقایسه کنید.

lora_dropout

Dropout می‌تواند Overfitting را کاهش دهد:

lora_dropout=0.05

برای دیتاست کوچک، مقادیر ۰٫۰۵ یا ۰٫۱ قابل‌آزمایش هستند. برای دیتاست بزرگ ممکن است Dropout صفر یا کمتر بهتر باشد.

Learning Rate

Learning Rate در LoRA معمولاً می‌تواند از Full Fine-Tuning بیشتر باشد.

نقطه شروع احتمالی:

1e-5 تا 3e-4

اما مقدار مناسب به مدل، Batch Size، دیتاست و Target Module بستگی دارد.

نشانه Learning Rate زیاد:

  • Loss ناپایدار
  • NaN
  • افت کیفیت سریع
  • فراموشی رفتار پایه
  • پاسخ‌های تکراری

نشانه Learning Rate کم:

  • کاهش بسیار کند Loss
  • نبود بهبود در Validation
  • Underfitting

Batch Size

Effective Batch Size:

[
EffectiveBatch =
BatchPerDevice
\times
GradientAccumulation
\times
GPUCount
]

مثال:

2 × 8 × 1 = 16

Gradient Accumulation امکان شبیه‌سازی Batch بزرگ‌تر با حافظه محدود را فراهم می‌کند.

Sequence Length

افزایش Sequence Length مصرف حافظه Activation را به‌شدت بالا می‌برد.

اگر بیشتر نمونه‌ها زیر ۱۰۰۰ Token هستند، تنظیم ۸۱۹۲ ممکن است فقط منابع را هدر دهد. توزیع طول داده را بررسی کنید:

lengths = []

for row in dataset["train"]:
    text = tokenizer.apply_chat_template(
        row["messages"],
        tokenize=False,
        add_generation_prompt=False,
    )

    token_count = len(
        tokenizer(
            text,
            add_special_tokens=False,
        )["input_ids"]
    )

    lengths.append(token_count)

lengths.sort()

print("min:", lengths[0])
print("p50:", lengths[len(lengths) // 2])
print("p95:", lengths[int(len(lengths) * 0.95)])
print("max:", lengths[-1])

سپس max_length را براساس P95، نیاز واقعی و بودجه حافظه تعیین کنید.

Packing چیست؟

Packing چند نمونه کوتاه را در یک Sequence قرار می‌دهد تا Padding کمتری مصرف شود.

مزایا:

  • استفاده بهتر از GPU
  • کاهش Padding
  • افزایش Throughput

ریسک‌ها:

  • نیاز به کنترل مرز نمونه‌ها
  • پیچیدگی بیشتر در Masking
  • احتمال اثر متقابل اگر پیاده‌سازی اشتباه باشد

برای دیتاست دارای نمونه‌های بسیار کوتاه، Packing مفید است. ابتدا Pipeline را بدون Packing اعتبارسنجی و سپس آن را فعال کنید.

Loss Masking

در Chat Fine-Tuning باید مشخص کنید Loss روی کدام Tokenها محاسبه شود.

دو حالت رایج:

Loss روی کل مکالمه

مدل روی System، User و Assistant Tokenها آموزش می‌بیند.

Assistant-Only Loss

Loss فقط روی پاسخ Assistant محاسبه می‌شود. این حالت معمولاً برای یادگیری پاسخ مطلوب مناسب‌تر است.

پشتیبانی از Assistant-Only Loss به Trainer، Data Collator و Chat Template وابسته است. باید بررسی کنید Template بتواند مرز Tokenهای Assistant را به‌درستی مشخص کند.

در غیر این صورت ممکن است مدل به‌جای پاسخ‌دادن، متن User یا System را نیز تولید کند.

اجرای Inference با Adapter

import os
import torch

from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
)
from peft import PeftModel


BASE_MODEL_ID = os.environ["BASE_MODEL_ID"]
ADAPTER_PATH = "./outputs/qlora-adapter"


quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
)


tokenizer = AutoTokenizer.from_pretrained(
    ADAPTER_PATH,
    use_fast=True,
)


base_model = AutoModelForCausalLM.from_pretrained(
    BASE_MODEL_ID,
    quantization_config=quantization_config,
    device_map="auto",
)


model = PeftModel.from_pretrained(
    base_model,
    ADAPTER_PATH,
)

model.eval()


messages = [
    {
        "role": "system",
        "content": "پاسخ را دقیق، کوتاه و به زبان فارسی بنویس.",
    },
    {
        "role": "user",
        "content": "Circuit Breaker چیست؟",
    },
]


inputs = tokenizer.apply_chat_template(
    messages,
    tokenize=True,
    add_generation_prompt=True,
    return_tensors="pt",
).to(model.device)


with torch.inference_mode():
    outputs = model.generate(
        inputs,
        max_new_tokens=256,
        do_sample=False,
        temperature=None,
        top_p=None,
        pad_token_id=tokenizer.eos_token_id,
    )


generated_tokens = outputs[0][inputs.shape[-1]:]

answer = tokenizer.decode(
    generated_tokens,
    skip_special_tokens=True,
)

print(answer)

برای Evaluationهای قطعی، Sampling را غیرفعال کنید تا مقایسه مدل‌ها پایدارتر باشد.

Merge کردن LoRA با مدل پایه

برای استقرار می‌توان Adapter را جدا نگه داشت یا آن را با مدل پایه Merge کرد.

نمونه Merge:

from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
)
from peft import PeftModel


BASE_MODEL_ID = "YOUR_BASE_MODEL_ID"
ADAPTER_PATH = "./outputs/qlora-adapter"
MERGED_PATH = "./outputs/merged-model"


base_model = AutoModelForCausalLM.from_pretrained(
    BASE_MODEL_ID,
    torch_dtype="auto",
    device_map="cpu",
)


model = PeftModel.from_pretrained(
    base_model,
    ADAPTER_PATH,
)


merged_model = model.merge_and_unload()

merged_model.save_pretrained(
    MERGED_PATH,
    safe_serialization=True,
)


tokenizer = AutoTokenizer.from_pretrained(
    ADAPTER_PATH,
)

tokenizer.save_pretrained(MERGED_PATH)

نکات:

  • Merge معمولاً به حافظه CPU یا GPU بیشتری نیاز دارد.
  • مدل پایه Quantized را همیشه نمی‌توان مستقیم با همان دقت Merge کرد.
  • خروجی Mergeشده را دوباره ارزیابی کنید.
  • License مدل پایه همچنان اعمال می‌شود.
  • Merge می‌تواند حجم استقرار را افزایش دهد.

Adapter جدا یا مدل Mergeشده؟

Adapter جدا

مزایا:

  • حجم کمتر
  • تعویض سریع وظیفه
  • نگهداری چند نسخه
  • Rollback آسان‌تر

معایب:

  • پیچیدگی Serving
  • نیاز به بارگذاری Base Model و Adapter
  • سازگاری محدود بعضی Runtimeها

مدل Mergeشده

مزایا:

  • استقرار ساده‌تر
  • سازگاری بهتر با بعضی Engineها
  • عدم نیاز به مدیریت Adapter در Runtime

معایب:

  • حجم بیشتر
  • یک نسخه کامل برای هر وظیفه
  • Rollback و مدیریت نسخه سنگین‌تر

برای Multi-Tenant Serving، Adapter جدا معمولاً جذاب‌تر است.

ارزیابی مدل Fine-Tuned

کاهش Training Loss به معنی بهترشدن محصول نیست. باید مدل را روی Test Set و داده واقعی ارزیابی کنید.

معیارهای وظیفه‌ای

براساس کاربرد:

  • Accuracy
  • Precision
  • Recall
  • Macro F1
  • ROUGE
  • BLEU
  • Exact Match
  • JSON Validity
  • Schema Compliance
  • Tool Call Accuracy
  • SQL Execution Accuracy
  • Code Test Pass Rate

معیارهای عملیاتی

  • Latency
  • Throughput
  • VRAM
  • Token per Second
  • Error Rate
  • Cost per Request
  • GPU Utilization

معیارهای کیفی

  • رعایت دستور
  • وضوح
  • صحت
  • لحن
  • اختصار
  • ایمنی
  • عدم ساخت اطلاعات
  • عملکرد روی ورودی خارج از دامنه

نمونه ارزیابی JSON

import json
from jsonschema import validate, ValidationError


schema = {
    "type": "object",
    "properties": {
        "category": {
            "type": "string",
            "enum": [
                "payment",
                "shipping",
                "account",
                "other",
            ],
        },
        "urgency": {
            "type": "string",
            "enum": [
                "low",
                "medium",
                "high",
            ],
        },
    },
    "required": [
        "category",
        "urgency",
    ],
    "additionalProperties": False,
}


def is_valid_output(text: str) -> bool:
    try:
        data = json.loads(text)
        validate(instance=data, schema=schema)
        return True
    except (
        json.JSONDecodeError,
        ValidationError,
    ):
        return False

گزارش کنید:

JSON parse rate
Schema validity rate
Field accuracy
Exact match
Latency p50
Latency p95

مقایسه Baseline و Fine-Tuned Model

یک جدول استاندارد بسازید:

معیارBase ModelPrompted BaseFine-Tuned
Accuracy72%84%91%
JSON Validity81%94%99%
متوسط Output Token18011068
Latency p952.1s2.0s1.7s
نرخ اصلاح انسانی31%14%6%

اعداد بالا صرفاً نمونه‌اند. معیارهای واقعی باید از Evaluation پروژه به دست بیایند.

Fine-Tuning زمانی موفق است که بهبود آن نسبت به هزینه آموزش، Serving و نگهداری ارزش داشته باشد.

جلوگیری از Overfitting

نشانه‌های Overfitting:

  • Train Loss کاهش می‌یابد اما Validation Loss بالا می‌رود.
  • پاسخ‌ها جملات دیتاست را تکرار می‌کنند.
  • مدل روی سؤال‌های جدید ضعیف است.
  • خروجی بیش‌ازحد قالبی می‌شود.
  • مدل انعطاف عمومی خود را از دست می‌دهد.

راهکارها:

  • داده متنوع‌تر
  • حذف نمونه‌های تکراری
  • کاهش Epoch
  • Early Stopping
  • کاهش Rank
  • افزایش LoRA Dropout
  • کاهش Learning Rate
  • افزایش Validation Set
  • استفاده از Hard Example
  • توقف براساس معیار وظیفه‌ای

همیشه بهترین Checkpoint را براساس Validation انتخاب کنید، نه آخرین Checkpoint را.

Catastrophic Forgetting

Catastrophic Forgetting زمانی رخ می‌دهد که مدل در حین یادگیری وظیفه جدید، بخشی از توانایی‌های قبلی خود را از دست بدهد.

راهکارها:

  • Learning Rate کمتر
  • Epoch کمتر
  • PEFT به‌جای Full Fine-Tuning
  • ترکیب داده عمومی و تخصصی
  • حفظ نمونه‌های General Capability
  • ارزیابی Regression
  • محدودکردن Target Moduleها
  • استفاده از Adapter جدا

یک Regression Suite شامل وظایف عمومی مدل نگه دارید:

  • پاسخ‌گویی عمومی
  • فارسی
  • انگلیسی
  • خلاصه‌سازی
  • استدلال ساده
  • رعایت دستور
  • ایمنی
  • قالب‌بندی

مشکلات رایج آموزش

CUDA Out of Memory

راهکارها:

  • کاهش Batch Size
  • افزایش Gradient Accumulation
  • کاهش Sequence Length
  • فعال‌کردن Gradient Checkpointing
  • استفاده از QLoRA
  • کاهش Rank
  • استفاده از Flash Attention سازگار
  • فعال‌کردن Packing برای داده کوتاه
  • بررسی Memory Leak

Loss برابر NaN

دلایل احتمالی:

  • Learning Rate زیاد
  • ناسازگاری FP16
  • داده خراب
  • Tokenizer نامناسب
  • Gradient Explosion
  • تنظیم اشتباه Quantization

راهکارها:

  • استفاده از BF16 در سخت‌افزار سازگار
  • کاهش Learning Rate
  • Gradient Clipping
  • بررسی داده
  • لاگ‌کردن Gradient Norm
  • اجرای آزمایش روی Dataset کوچک

خروجی مدل تکراری است

دلایل:

  • داده تکراری
  • Overfitting
  • Epoch زیاد
  • پاسخ‌های آموزشی مشابه
  • Generation Configuration نامناسب
  • Chat Template اشتباه

مدل Prompt را تکرار می‌کند

دلایل احتمالی:

  • Loss Masking اشتباه
  • نبود Generation Prompt
  • Chat Template ناسازگار
  • Decode کردن کل ورودی و خروجی با هم
  • داده آموزشی بدفرمت

Adapter اثری ندارد

بررسی کنید:

  • Adapter واقعاً بارگذاری شده است.
  • Target Moduleها درست هستند.
  • پارامترهای Trainable صفر نیستند.
  • Checkpoint صحیح انتخاب شده است.
  • Base Model همان مدل زمان آموزش است.
model.print_trainable_parameters()

ثبت آزمایش‌ها

برای هر Run این موارد را ذخیره کنید:

{
  "run_id": "qlora-r16-lr2e4-v3",
  "base_model": "BASE_MODEL_ID",
  "dataset_version": "support-fa-v3",
  "dataset_hash": "sha256:...",
  "seed": 42,
  "rank": 16,
  "lora_alpha": 32,
  "lora_dropout": 0.05,
  "learning_rate": 0.0002,
  "epochs": 3,
  "effective_batch_size": 16,
  "max_length": 2048,
  "best_eval_loss": 0.0,
  "git_commit": "COMMIT_SHA"
}

بدون Dataset Version، Code Version و Seed، بازتولید نتیجه دشوار می‌شود.

امنیت و حریم خصوصی دیتاست

دیتاست Fine-Tuning ممکن است اطلاعات حساس را در رفتار مدل تثبیت کند.

قبل از آموزش:

  • PII را حذف کنید.
  • API Key و Password را جست‌وجو کنید.
  • Email و شماره تلفن را Mask کنید.
  • مجوز استفاده از داده را بررسی کنید.
  • سیاست Retention تعریف کنید.
  • دسترسی به Dataset را محدود کنید.
  • فایل‌ها را Encrypt کنید.
  • Artifactهای آموزش را بررسی کنید.
  • Logها را پاک‌سازی کنید.
  • فرایند حذف داده تعریف کنید.

Regex ساده کافی نیست. ترکیبی از Rule-based Detection، Named Entity Recognition و بازبینی انسانی لازم است.

Data Poisoning

اگر داده از کاربران یا منابع خارجی جمع‌آوری می‌شود، ممکن است شامل نمونه‌های مخرب باشد.

ریسک‌ها:

  • Backdoor
  • رفتار مخفی وابسته به Trigger
  • Prompt Injection
  • پاسخ‌های آلوده
  • تغییر سیاست مدل
  • نشت داده
  • آموزش رفتار نامطلوب

راهکارها:

  • منبع داده قابل‌اعتماد
  • Provenance
  • امضای Dataset Version
  • بررسی Outlier
  • Deduplication
  • نمونه‌گیری انسانی
  • Red Teaming
  • تست Triggerهای مشکوک
  • محدودکردن دسترسی Pipeline

استقرار مدل Fine-Tuned

گزینه‌های Serving:

  • Transformers
  • vLLM
  • Text Generation Inference
  • llama.cpp برای مدل‌های سازگار
  • TensorRT-LLM
  • Runtimeهای مبتنی بر ONNX
  • سرویس مدیریت‌شده GPU

معیار انتخاب:

  • پشتیبانی از معماری مدل
  • LoRA Serving
  • Continuous Batching
  • Quantization
  • Streaming
  • Tensor Parallelism
  • Throughput
  • Latency
  • OpenAI-compatible API
  • Observability
  • مدیریت چند Adapter

معماری Production:

Client
   ↓
API Gateway
   ↓
Authentication
   ↓
Rate Limiting
   ↓
Request Validation
   ↓
Model Router
   ↓
Inference Server
   ↓
Base Model + LoRA Adapter
   ↓
Response Validation
   ↓
Logging, Metrics and Tracing

نسخه‌بندی مدل

هر نسخه باید شامل این اطلاعات باشد:

  • Base Model
  • Base Model Revision
  • Adapter Version
  • Dataset Version
  • Tokenizer Version
  • Chat Template
  • Training Config
  • Evaluation Report
  • License
  • Deployment Config
  • Known Limitations

نام‌گذاری پیشنهادی:

support-fa-qlora-v1.2.0

تغییر عمده دیتاست یا رفتار:

Major Version

اصلاح Adapter:

Minor Version

رفع مشکل بسته‌بندی:

Patch Version

Rollout امن

مدل جدید را مستقیماً برای همه کاربران فعال نکنید.

فرایند پیشنهادی:

  1. Offline Evaluation
  2. Red Teaming
  3. Shadow Traffic
  4. Canary Deployment
  5. A/B Test
  6. افزایش تدریجی ترافیک
  7. پایش کیفیت و خطا
  8. Rollback در صورت Regression

معیارهای Rollback:

  • افزایش Error Rate
  • افت کیفیت
  • افزایش Latency
  • رشد خروجی نامعتبر
  • رفتار ایمنی نامناسب
  • افزایش هزینه
  • افت رضایت کاربر

هزینه واقعی Fine-Tuning

هزینه فقط GPU Training نیست.

هزینه‌های پنهان:

  • جمع‌آوری داده
  • پاک‌سازی
  • برچسب‌گذاری
  • بازبینی متخصص
  • آزمایش Hyperparameter
  • ذخیره Checkpoint
  • Evaluation
  • Serving
  • Monitoring
  • نگهداری نسخه‌ها
  • رفع Regression
  • بازآموزی
  • امنیت و Compliance

در بسیاری از پروژه‌ها، هزینه آماده‌سازی و کنترل کیفیت داده بیشتر از هزینه یک Run آموزشی است.

چه زمانی Fine-Tuning از نظر اقتصادی منطقی است؟

Fine-Tuning می‌تواند اقتصادی باشد اگر:

  • حجم درخواست زیاد باشد.
  • Prompt فعلی بسیار طولانی باشد.
  • پاسخ کوتاه‌تر هزینه Token را کم کند.
  • نرخ اصلاح انسانی کاهش یابد.
  • یک مدل کوچک Fine-Tuned جای مدل بزرگ‌تر را بگیرد.
  • Schema Compliance افزایش یابد.
  • وظیفه پایدار و تکرارشونده باشد.

فرمول ساده:

[
ROI =
SavingsFromInference
+
SavingsFromHumanReview

TrainingAndMaintenanceCost
]

فقط کاهش هزینه Token را اندازه‌گیری نکنید؛ هزینه خطا و بازبینی انسانی نیز مهم است.

Fine-Tuning مدل فارسی

برای فاین‌تیون فارسی باید به موارد زیر توجه کنید:

  • کیفیت Tokenizer روی فارسی
  • نیم‌فاصله
  • ترکیب فارسی و انگلیسی
  • اعداد فارسی و لاتین
  • RTL
  • علائم نگارشی
  • زبان محاوره و رسمی
  • Encoding
  • تنوع گویش
  • متن ترجمه‌شده ماشینی
  • استفاده بیش‌ازحد از عبارت‌های مصنوعی

پیش از انتخاب مدل، تعداد Token چند نمونه فارسی را مقایسه کنید:

samples = [
    "آموزش استفاده از API هوش مصنوعی",
    "نحوه مدیریت خطا در برنامه‌های توزیع‌شده",
    "Prompt Engineering یا مهندسی پرامپت چیست؟",
]

for sample in samples:
    tokens = tokenizer.encode(
        sample,
        add_special_tokens=False,
    )

    print({
        "text": sample,
        "characters": len(sample),
        "tokens": len(tokens),
        "ratio": len(tokens) / len(sample),
    })

Tokenizer نامناسب می‌تواند هزینه آموزش و Inference فارسی را افزایش دهد.

چک‌لیست Fine-Tuning

پیش از آموزش:

  • هدف قابل‌اندازه‌گیری است؟
  • Baseline ساخته شده است؟
  • Fine-Tuning از RAG مناسب‌تر است؟
  • License مدل بررسی شده است؟
  • دیتاست مجوز استفاده دارد؟
  • PII و Secret حذف شده‌اند؟
  • Split بدون Leakage است؟
  • Test Set واقعی وجود دارد؟
  • Chat Template درست است؟
  • سخت‌افزار کافی است؟
  • معیار موفقیت مشخص است؟
  • Rollback Plan دارید؟

پس از آموزش:

  • بهترین Checkpoint انتخاب شده است؟
  • مدل با Baseline مقایسه شده است؟
  • Regression Test اجرا شده است؟
  • خروجی‌های حساس بررسی شده‌اند؟
  • Adapter و Base Model نسخه‌بندی شده‌اند؟
  • Inference Config ثبت شده است؟
  • Latency و هزینه سنجیده شده‌اند؟
  • Canary Deployment انجام شده است؟
  • Monitoring فعال است؟
  • مستندات Known Limitations نوشته شده‌اند؟

سؤالات متداول Fine-Tuning

Fine-Tuning چیست؟

Fine-Tuning ادامه آموزش یک مدل ازپیش‌آموزش‌دیده روی دیتاست هدفمند برای تغییر رفتار، سبک یا عملکرد آن در یک وظیفه مشخص است.

SFT چیست؟

SFT یا Supervised Fine-Tuning آموزش مدل با نمونه‌های ورودی و پاسخ مطلوب است.

LoRA چیست؟

LoRA روشی برای Fine-Tuning کم‌هزینه است که وزن‌های مدل پایه را ثابت نگه می‌دارد و فقط ماتریس‌های کم‌رتبه کوچکی را آموزش می‌دهد.

QLoRA چیست؟

QLoRA مدل پایه را به‌صورت Quantized چهار بیتی بارگذاری و Adapterهای LoRA را آموزش می‌دهد تا مصرف VRAM کاهش یابد.

تفاوت LoRA و QLoRA چیست؟

در LoRA مدل پایه معمولاً با FP16 یا BF16 بارگذاری می‌شود؛ اما QLoRA از مدل پایه Quantized، معمولاً ۴ بیتی، استفاده می‌کند.

Fine-Tuning بهتر است یا RAG؟

برای تغییر رفتار پایدار، Fine-Tuning مناسب‌تر است. برای اضافه‌کردن اطلاعات جدید، خصوصی و قابل استناد، RAG معمولاً انتخاب بهتری است.

چند نمونه برای Fine-Tuning لازم است؟

عدد ثابتی وجود ندارد. پیچیدگی وظیفه، تنوع داده، کیفیت نمونه‌ها و توانایی مدل پایه تعیین‌کننده‌اند. ابتدا با چندصد نمونه باکیفیت آزمایش کوچک انجام دهید و Learning Curve بسازید.

آیا با یک GPU می‌توان LLM را Fine-Tune کرد؟

بسته به اندازه مدل، VRAM، طول Sequence و روش آموزش، بله. QLoRA فاین‌تیون مدل‌های بزرگ‌تر را روی GPU محدود امکان‌پذیرتر می‌کند.

آیا Fine-Tuning دانش جدید به مدل اضافه می‌کند؟

ممکن است بعضی الگوها و اطلاعات در وزن‌ها یاد گرفته شوند، اما برای اطلاعات دقیق، قابل‌به‌روزرسانی و منبع‌دار، Fine-Tuning جایگزین قابل‌اعتماد RAG یا Database نیست.

آیا LoRA کیفیت Full Fine-Tuning را دارد؟

در بسیاری از وظایف می‌تواند کیفیت نزدیک یا حتی بهتر ایجاد کند، اما نتیجه به مدل، دیتاست و تنظیمات وابسته است.

Rank مناسب LoRA چقدر است؟

مقدار جهانی وجود ندارد. مقادیر ۸، ۱۶ و ۳۲ نقاط شروع رایجی هستند و باید با Validation انتخاب شوند.

آیا Adapter را می‌توان با مدل Merge کرد؟

بله. در بسیاری از معماری‌ها می‌توان وزن LoRA را با مدل پایه Merge و یک Checkpoint مستقل ایجاد کرد.

آیا می‌توان چند LoRA را هم‌زمان استفاده کرد؟

بعضی Runtimeها امکان بارگذاری، تعویض یا ترکیب چند Adapter را دارند، اما ترکیب آن‌ها همیشه رفتار قابل‌پیش‌بینی ایجاد نمی‌کند و باید ارزیابی شود.

آیا درواره سرویس Fine-Tuning ارائه می‌کند؟

درواره در حال حاضر سرویس API دسترسی به مدل‌های هوش مصنوعی ارائه می‌کند. می‌توانید از API درواره برای ساخت Baseline، مقایسه مدل‌ها و تولید کنترل‌شده پیش‌نویس داده استفاده کنید؛ اما مراحل Fine-Tuning باید براساس زیرساخت و مدل انتخابی خودتان انجام شود.

جمع‌بندی

Fine-Tuning زمانی ارزشمند است که بخواهید رفتار یک مدل زبانی را برای وظیفه‌ای پایدار، تکرارشونده و قابل‌اندازه‌گیری تغییر دهید. برای بیشتر تیم‌ها، شروع با SFT و روش‌های PEFT مانند LoRA یا QLoRA عملی‌تر از Full Fine-Tuning است.

موفقیت Fine-Tuning فقط به اجرای اسکریپت آموزش وابسته نیست. مهم‌ترین بخش‌های پروژه عبارت‌اند از:

  • تعریف مسئله
  • ساخت Baseline
  • انتخاب مدل پایه
  • طراحی دیتاست باکیفیت
  • جلوگیری از Leakage
  • انتخاب Hyperparameter
  • ارزیابی وظیفه‌ای
  • Regression Testing
  • نسخه‌بندی
  • Rollout تدریجی
  • Monitoring

قبل از Fine-Tuning، مسئله را با Prompt Engineering و RAG مقایسه کنید. اگر مدل باید اطلاعات جدید را بازیابی کند، RAG مناسب‌تر است. اگر فقط چند قانون ساده دارید، Prompt کافی است. Fine-Tuning را زمانی انتخاب کنید که به رفتار تخصصی و پایدار نیاز دارید و بتوانید بهبود آن را اندازه‌گیری کنید.

برای آزمایش مدل‌های مختلف و ساخت Baseline از طریق یک API استاندارد می‌توانید در درواره ثبت‌نام کنید و مدل‌های موجود در پنل را با Base URL زیر فراخوانی کنید:

https://api.darvareh.ir/v1

مقالات مرتبط

Read more

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی با ترکیب گردش‌کارهای خودکار و مدل‌های هوش مصنوعی، پردازش متن، دسته‌بندی، استخراج اطلاعات و تصمیم‌های پیشنهادی را خودکار می‌کند. در این راهنما، معماری و ساخت نمونه عملی آن با API درواره را می‌آموزید.

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce شیوه‌ای جدید برای خرید اینترنتی است که در آن ایجنت هوش مصنوعی می‌تواند نیاز کاربر را بفهمد، محصولات را جست‌وجو و مقایسه کند و فرایند خرید را پیش ببرد. در این راهنما با معماری، UCP، ACP و پیاده‌سازی آن با API درواره آشنا می‌شوید.