مقدمه
فرض کن یه مدل زبانی بزرگ رو برداشتی، یه سوال تخصصی حقوقی یا پزشکی فارسی ازش پرسیدی، و جوابی بهت داده که نه فقط به درد نمیخوره، بلکه حسابی اعصابت رو خرد کرده. چرا این اتفاق میافته؟ چون این مدلهای بزرگ با کلی محتوای عمومی و اکثراً انگلیسی آموزش دیدن و خبری از دادههای کیفی فارسی توی مخزنشون نیست. اینجا دقیقاً همون جاییست که فاینتیونینگ وارد میشه تا به مدل یاد بده بهجای حرفهای کلیشهای و بیربط، مثل یه متخصص فارسیزبان باهات حرف بزنه. تنظیم دقیق، مدل رو با ظرافتهای دستوری، اصطلاحات تخصصی و بافت فرهنگی-اجتماعی زبان فارسی آشنا میکنه. این کار نهتنها دقت پاسخها رو چند برابر میکنه، بلکه اعتماد کاربر رو برای استفاده از هوش مصنوعی تو سناریوهای حساس جلب میکنه. توی این مقاله، بدون حاشیه و با یه چارچوب عملی، بهت میگیم چطور بین روشهای Full، LoRA و QLoRA یکی رو انتخاب کنی، چطور حافظهات رو دقیق محاسبه کنی، و نهایتاً با یه پروژهی کدنویسی گامبهگام، مدل خودت رو برای فارسی تنظیم کنی. پس کمربندها رو ببند، میریم تو دل ماجرا!
چرا باید فاینتیونینگ کنی؟ (واسه فارسیزبانا)
بیا یه مثال واقعی بزنیم: فرض کن یه وکیل دادگستری از مدل میپرسه "مادهی ۲۳۶ قانون مجازات اسلامی در مورد مجازات چی میگه؟" و مدل پایه بهش یه پاسخ کلیشهای و غیرمستند میده که نه استناد حقوقی داره و نه قابل قبوله. حالا با فاینتیونینگ روی یه دیتاست حقوقی فارسی که شامل آرای محاکم و متون قانونی هست، همون مدل میتونه دقیقاً ماده رو بیاره، تفسیر کنه، و حتی به پروندههای مشابه ارجاع بده.
تو حوزهی پزشکی هم به همین شکل: مدل پایه ممکنه علائم یه بیماری رو اشتباه تشخیص بده، ولی بعد از تنظیم روی پروندههای پزشکی فارسی و مقالات علمی، میتونه توصیههای اولیهی درستی بده. پس فاینتیونینگ مثل یه پل میمونه بین دانش عمومی مدل و تخصص مورد نظر تو. اگه میخوای بدونبینی این مدلها از چه ساختاری استفاده میکنن، مقالهی معماری ترنسفورمر و نحوه عملکرد آن در پردازش زبان فارسی رو چک کن.
جدول مقایسهی روشها: Full، LoRA و QLoRA (کدوم مال توئه؟)
خب، انتخاب روش فاینتیونینگ مثل انتخاب ماشین میمونه؛ بستگی به بودجهات همون (VRAM)، حجم دیتاست و این داره که چقدر دقت میخوای. هر روش یه تعادل خاصی بین این سه تا برقرار میکنه. بیا تو این جدول، مقایسه فاین تیونینگ کامل و کمپارامتر رو به همراه روش LoRA در فاین تیونینگ و نسخهی کمحافظهش یعنی QLoRA، از زوایای مختلف ببینیم:
| روش | چقدر وزن رو تغییر میده؟ | سرعت آموزش | حافظهی مصرفی (VRAM) | کیفیت نهایی روی فارسی |
| Full Fine-Tuning | همهی وزنهای مدل (میلیاردها پارامتر) | خیلی کند (به چندین کارت گرافیک سنگین نیازه) | بسیار بالا؛ حدودا ۴۰ تا ۸۰ گیگ (بسته به تنظیمات optimizer و دقت محاسباتی)[1] | بالاترین کیفیت ممکن، ولی خطر فراموشی دانش عمومی |
| LoRA | فقط ماتریسهای کوچیک کمرتبه (کمتر از ۱٪ پارامترها) | سریع (حدود ۴ برابر Full) | متوسط (حدود ۲۰ تا ۴۰ درصد حافظهی Full) | قابل رقابت با Full؛ حدودا ۹۰ تا ۹۵٪ کیفیت[2] |
| QLoRA | همون LoRA + مدل پایه رو ۴ بیتی میکنه | متوسط (کمی از LoRA کندتره به خاطر کوانتیزاسیون) | خیلی پایین (تا ۷۵٪ کمتر از LoRA) | نزدیک به LoRA؛ حدودا ۸۰ تا ۹۰٪ کیفیتFull را دارد [3] |
یه سناریوی عملی: اگه کارت گرافیک ۸ گیگ داری و دیتاست کوچیک؟
فرض کن کارت گرافیکت ۸ گیگابایت VRAM داره و یه دیتاست کوچیک (چند هزار تا نمونه) توی اختیار داری. کدوم روش رو باید انتخاب کنی؟
جواب قاطع: QLoRA. با ۸ گیگ حافظه، روش Full رو فراموش کن؛ حتی روش LoRA هم ممکنه به خاطر بارگذاری کامل مدل پایه (که حدود ۱۴ گیگابایت حافظه میخواد[4]) به مشکل بخوره. اما QLoRA با کوانتیزاسیون ۴ بیتی، حافظهی مورد نیاز مدل پایه رو به حدود ۳.۵ گیگابایت میرسونه[5] و فضای کافی برای LoRA adapters و دادههای میانی باقی میذاره. از طرفی، چون دیتاست کوچیکه، خطر Overfitting (بیشبرازش) وجود داره که QLoRA با استفاده از Dropout (نرخ ۰.۰۵ یا ۵ درصد برای مدلهای ۷ تا ۱۳ میلیاردی، طبق تنظیمات پیشنهادی خودِ مقالهی QLoRA[3]) میتونه جلوش رو بگیره. خلاصه، QLoRA بهترین تعادل رو بین محدودیت سختافزاری، کیفیت قابلقبول و هزینهی آموزش برای پروژههای فارسیزبان با بودجهی محدود فراهم میکنه.
قبل از کد زدن: محاسبهی دقیق VRAM (که جلوی OOM رو بگیره)
قبل از اینکه دست به کد بزنی، بیا یه محاسبهی سرانگشتی انجام بدیم تا وسط کار با خطای Out of Memory غافلگیر نشی. نیازمندی سختافزاری فاین تیونینگ به سه تا چیز اصلی بستگی داره: تعداد پارامترهای مدل، روش آموزشی که انتخاب میکنی، و طول دنباله (Sequence Length). یه فرمول تقریبی و کاربردی برای تخمین حافظهی VRAM اینه:
فاکتور روش برای Full Fine-Tuning حدود ۶ تا ۸ هست (چون باید وزنها، گرادیانها و وضعیت بهینهساز رو هم نگه داری)، برای LoRA حدود ۲ تا ۳ (با فرض دقت ۱۶ بیتی)، و برای QLoRA با کوانتیزاسیون ۴ بیتی حدود ۱ تا ۲. اما طول دنباله و Batch Size هم تأثیر جدی روی مصرف نهایی دارن. جدول زیر تخمینی از حافظهی مورد نیاز برای مدلهای ۳B، ۷B و ۱۳B رو با سه روش مختلف و دو طول دنبالهی ۵۱۲ و ۲۰۴۸ بهت میده (ارقام بر حسب گیگابایت و برای Batch Size برابر ۱ هستن):
| مدل | روش | طول دنباله 512 | طول دنباله 2048 |
| 3b | Full Fine-Tuning-LoRA-QLoRA | 32GB-10GB-5GB | 40GB-13GB-7GB |
| 7b | Full Fine-Tuning-LoRA-QLoRA | 70GB-20GB-12GB | 85GB-26GB-15GB |
| 13b | Full Fine-Tuning-LoRA-QLoRA | 130GB-38GB-20GB | 155GB-46GB-25GB |
منبع : [6]
نکتهی مهم: این اعداد برای Batch Size=۱ تخمین زده شدن و با افزایش طول دنباله، مصرف حافظه به صورت غیرخطی رشد میکنه.
تأثیر Batch Size و Gradient Checkpointing روی حافظه
بیا با یه مثال واقعی این قضیه رو باز کنیم. فرض کن میخوای یه مدل ۷ میلیارد پارامتری رو با روش LoRA و طول دنبالهی ۱۰۲۴ آموزش بدی. اگه Batch Size رو از ۴ به ۱ کاهش بدی، حجم دادهای که همزمان توی حافظه پردازش میشه به یکچهارم میرسه و مصرف VRAM تقریباً نصف میشه (چون گرادیانهای مربوط به هر نمونه هم حذف میشن). از طرف دیگه، اگه Gradient Checkpointing رو فعال کنی (یعنی به جای نگهداری همهی فعالسازیهای میانی، اونها رو دوباره محاسبه کنی)، مصرف حافظه تا ۶۰ تا ۸۰ درصد پایین میاد، ولی سرعت آموزش تا ۲۰ تا ۳۰ درصد کاهش پیدا میکنه [7]. ترکیب این دو تکنیک، یعنی کاهش Batch Size به همراه Gradient Checkpointing، اغلب بهت اجازه میده که مدلهای ۱۳ میلیارد پارامتری رو روی کارتهایی با حافظهی محدود (مثلاً حدود ۲۴ گیگابایت) هم فاینتیون کنی.
پیادهسازی گامبهگام: از دیتاست خام فارسی تا مدل آموزشدیده
حالا میرسیم به بخش شیرین و عملی ماجرا: کدنویسی! توی این بخش، قدمبهقدم آموزش فاین تیونینگ مدل زبانی رو با یه دیتاست فارسی برای تنظیم دقیق پیش میبریم. فرض میکنیم دیتاستات شامل جفتهای (پرسش، پاسخ) در یه حوزهی تخصصی مثل حقوق یا پزشکی هست. کل فرایند رو به ۴ مرحلهی اصلی تقسیم میکنیم و در انتها یه کد عملی کامل (حدود ۲۰ خط) بهت میدیم که با کمترین تغییرات توی اکثر کتابخانههای روز مثل transformers، peft و datasets قابل اجراست.
مرحله ۱: آمادهسازی دیتاست به فرمت JSONL
دیتاست رو به شکل یه فایل data.jsonl ذخیره کن؛ هر خط شامل دو کلید prompt (سوال یا دستور کاربر) و completion (پاسخ مطلوب) باشه. یه نمونه:
مرحله ۲: توکنایز کردن با توکنایزر فارسی
توکنایزر مدل پایه (مثلاً از خانوادهی Arian یا سایر مدلهای متنباز فارسی) رو بارگذاری کن. برای هر نمونه، ورودی رو با یه قالب ثابت ترکیب کن (مثلاً <|user|>\n{prompt}\n<|assistant|>\n{completion}<|end|>) و بعد توکنایز کن. حتماً padding و truncation رو با طول دنبالهی مد نظرت (مثلاً ۵۱۲) تنظیم کن.
مرحله ۳: پیکربندی LoRA با کتابخانهی PEFT
از LoraConfig استفاده کن. پارامترهای اصلی شامل r (رتبهی ماتریسها، معمولاً ۸ یا ۱۶)، lora_alpha (ضریب مقیاس)، target_modules (لایههای توجهی مثل q_proj و v_proj) و dropout (برای جلوگیری از Overfitting) هستن.
مرحله ۴: تنظیم TrainingArguments و اجرای Trainer
با TrainingArguments از transformers، ابرپارامترهایی مثل learning_rate، num_train_epochs، per_device_train_batch_size و gradient_accumulation_steps رو تعیین کن. بعد Trainer رو راهاندازی کن و حلقهی آموزش رو شروع کن.
کد عملی کامل (با کامنتهای فارسی)
نکته: target_modules رو باید با معماری مدل پایه هماهنگ کنی؛ برای مدلهای Llama معمولاً ["q_proj", "v_proj"] و برای معماری Arian ممکنه فرق کنه. اگه با خطای OOM روبرو شدی، per_device_train_batch_size رو کم کن و gradient_accumulation_steps رو زیاد کن.
سنجش کیفیت: ارزیابی مدل فاینتیون شده با معیارهای بومی
فقط اینکه Loss توی آموزش کم شده، کافی نیست؛ باید ببینی مدل توی دنیای واقعی چطور عمل میکنه. برای ارزیابی فاین تیونینگ روی زبان فارسی، باید از معیارهای بومی مثل ParsiEval استفاده کنی که شامل این شاخصهاست:
- دقت (Accuracy): درصد پاسخهای کاملاً درست در وظایف طبقهبندی یا پرسشپاسخ.
- F1-Score: هارمونیک بین Precision و Recall، مخصوصاً برای دادههای نامتوازن.
- BLEU: شباهت متن تولید شده با پاسخ مرجع، که برای متون حقوقی و پزشکی با جملات طولانی خیلی مهمه.
یه سناریوی فرضی: یه مجموعهتست با ۱۰۰۰ جفت (پرسش، پاسخ) از حوزهی حقوقی فارسی تهیه کردی. جدول زیر عملکرد مدل پایه و مدل فاینتیون شده رو روی این مجموعه نشون میده:
| معیار ارزیابی | مدل پایه (قبل از فاینتیون) | مدل فاینتیونشده (پس از تنظیم) |
| دقت | ۵۸٪ | ۸۲٪ |
| F1-Score | ۰.۵۵ | ۰.۸۰ |
| BLEU (متون حقوقی) | ۱۸.۳ | ۴۱.۶ |
این اختلاف نشون میده که فاینتیونینگ نهتنها دقت رو بالا برده، بلکه انسجام و صحت استنادات رو هم حسابی بهبود داده. برای دسترسی به دیتاستهای محک فارسی و نحوهی محاسبهی این معیارها، مقالهی معرفی دیتاستهای محک فارسی برای ارزیابی عملکرد مدلهای زبانی رو بخون.
۵ خطای مرگبار و راهکارهای سریع (از OOM تا Overfitting)
توی مسیر خطاهای رایج فاین تیونینگ، اگه از قبل بدونیشون، میتونی راحت ازشون عبور کنی. بیا ۵ تای اصلی رو با پیام خطا و راهکارش ببینیم:
۱) خطای Out of Memory (OOM)
- پیام خطا: CUDA out of memory. Tried to allocate ...
- راهکار: این خطا یعنی حافظهی کارت گرافیکت تموم شده. دو تا کار میتونی بکنی: اول، per_device_train_batch_size رو کم کن (مثلاً از ۴ به ۱ برسون). دوم، Gradient Checkpointing رو فعال کن تا مصرف حافظه تا ۶۰ تا ۸۰ درصد کاهش پیدا کنه، هرچند سرعت آموزش یهکم پایین میاد.
۲) Loss نوسانی و واگرا
- پیام خطا: نوسان شدید Loss اوایل آموزش یا افزایش ناگهانیاش.
- راهکار: نرخ یادگیری (Learning Rate) زیاد، شایعترین علته. نرخ رو کم کن (مثلاً یکدهم) و از Warmup استفاده کن تا نرخ یادگیری بهتدریج از صفر به مقدار نهایی برسه.
۳) Overfitting (بیشبرازش) روی دیتاست کوچک
- پیام خطا: Loss آموزش کم میشه ولی Loss اعتبارسنجی بالا میره.
- راهکار: مدل داره دادهها رو حفظ میکنه. دو راهکار: اول، Dropout رو توی پیکربندی LoRA زیاد کن (مثلاً از ۰.۱ به ۰.۳). دوم، Data Augmentation (افزایش داده) مثل بازنویسی جملات با ابزارهای تولید متن که دیتاست رو غنیتر میکنه.
۴) مشکل توکنایز کردن یونیکد فارسی
- پیام خطا: کاراکترهای � یا \u توی خروجی، یا خطای UnicodeDecodeError.
- راهکار: توکنایزرهای عمومی معمولاً حروف خاص فارسی مثل «ی» و «ک» رو درست نمیشناسن. حتماً از توکنایزر مخصوص مدل فارسیساز استفاده کن و فایلهای دیتاست رو با encoding utf-8 ذخیره کن.
۵) عدم تطابق قالب پرامپت در مرحلهی استنتاج
- پیام خطا: خروجیهای بیربط، پاسخهای خیلی کوتاه یا طولانی.
- راهکار: مدل توی آموزش یه قالب خاص (مثل <|user|>...) رو یاد گرفته. اگر توی استنتاج از قالب دیگهای استفاده کنی، سردرگم میشه. دقیقاً همون قالبی رو که توی توکنایز کردن استفاده کردی، توی استنتاج هم بهکار ببر.
جمعبندی
خب، از انتخاب روش و محاسبهی حافظه گرفته تا کدنویسی، ارزیابی و عیبیابی رو با هم رفتیم. حالا با این چارچوب عملی، میتونی بر اساس بودجهات و حجم دیتاست، بهترین تصمیم رو برای فاین تیونینگ مدل خودت بگیری و روی دیتاست فارسی پیادهاش کنی. دیگه وقتشه که دست به کار بشی و مدل خودت رو برای حوزهی تخصصی فارسی راهاندازی کنی!