چرا Unsloth؟
تا الان ابزارهای مختلفی برای Fine-tuning دیدیم — Hugging Face Transformers، PEFT، TRL. همهشون خوبن ولی Unsloth یه چیز خاص داره: سرعت و مصرف حافظه فوقالعاده بهینه.
- ۲ برابر سریعتر از Hugging Face + PEFT
- ۶۰ درصد حافظه کمتر مصرف میکنه
- بدون تغییر کیفیت — نتیجه دقیقاً یکیه
- نصب ساده و API شبیه Hugging Face
Unsloth این بهینهسازی رو با بازنویسی kernelهای CUDA و حذف عملیات غیرضروری انجام میده. یعنی همون محاسبات رو انجام میده ولی خیلی بهینهتر.
نصب Unsloth
# نصب در Google Colab یا محیط محلی
# pip install unsloth
# یا نسخه شبانه (nightly) برای آخرین ویژگیها
# pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
# بررسی نصب
import unsloth
print(f"Unsloth version: {unsloth.__version__}")
import torch
print(f"CUDA: {torch.cuda.is_available()}")
print(f"GPU: {torch.cuda.get_device_name(0)}")
قدم ۱: لود مدل
from unsloth import FastLanguageModel
import torch
# تنظیمات
max_seq_length = 2048
dtype = None # auto-detect (بهترین dtype برای GPU)
load_in_4bit = True # QLoRA
# لود مدل با Unsloth
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Llama-3.1-8B-Instruct", # مدل از Hugging Face
max_seq_length=max_seq_length,
dtype=dtype,
load_in_4bit=load_in_4bit,
)
print("مدل با موفقیت لود شد!")
print(f"حافظه مصرفی: {torch.cuda.memory_allocated() / 1e9:.2f} GB")
unsloth/). این مدلها سریعتر لود میشن ولی میتونی از هر مدل Hugging Face هم استفاده کنی.
قدم ۲: تنظیم LoRA
# اضافه کردن LoRA adapters
model = FastLanguageModel.get_peft_model(
model,
r=16, # LoRA rank
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
lora_alpha=16,
lora_dropout=0, # Unsloth توصیه میکنه 0
bias="none",
use_gradient_checkpointing="unsloth", # بهینهسازی حافظه Unsloth
random_state=3407,
use_rslora=False,
loftq_config=None,
)
# بررسی پارامترهای قابل آموزش
model.print_trainable_parameters()
# خروجی مثلاً: trainable params: 41,943,040 (0.92%)
قدم ۳: آمادهسازی دیتاست
from datasets import load_dataset
# لود دیتاست — مثال با یه دیتاست آماده
dataset = load_dataset("json", data_files="my_dataset.jsonl", split="train")
# تعریف قالب مکالمه
chat_template = """{{ bos_token }}
{% for message in messages %}
{% if message['role'] == 'system' %}
<|start_header_id|>system<|end_header_id|>
{{ message['content'] }}<|eot_id|>
{% elif message['role'] == 'user' %}
<|start_header_id|>user<|end_header_id|>
{{ message['content'] }}<|eot_id|>
{% elif message['role'] == 'assistant' %}
<|start_header_id|>assistant<|end_header_id|>
{{ message['content'] }}<|eot_id|>
{% endif %}
{% endfor %}"""
# یا سادهتر — از chat template خود مدل استفاده کن
def format_prompts(examples):
texts = []
for messages in examples["messages"]:
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=False
)
texts.append(text)
return {"text": texts}
dataset = dataset.map(format_prompts, batched=True)
# بررسی یه نمونه
print(dataset[0]["text"][:500])
اگه دیتاستت فرمت instruction داره:
# تبدیل فرمت instruction به messages
def convert_to_messages(examples):
all_messages = []
for instruction, output in zip(examples["instruction"], examples["output"]):
messages = [
{"role": "system", "content": "تو یه دستیار هوشمند و دقیق هستی."},
{"role": "user", "content": instruction},
{"role": "assistant", "content": output},
]
all_messages.append(messages)
return {"messages": all_messages}
dataset = dataset.map(convert_to_messages, batched=True)
dataset = dataset.map(format_prompts, batched=True)
قدم ۴: تنظیمات آموزش
from trl import SFTTrainer
from transformers import TrainingArguments
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset,
dataset_text_field="text",
max_seq_length=max_seq_length,
dataset_num_proc=2,
packing=False, # True برای نمونههای کوتاه (صرفهجویی زمان)
args=TrainingArguments(
# تنظیمات اصلی
output_dir="outputs",
num_train_epochs=3,
# Batch size
per_device_train_batch_size=2,
gradient_accumulation_steps=4, # effective batch = 8
# Learning rate
learning_rate=2e-4,
warmup_steps=5,
# بهینهسازی حافظه
fp16=not torch.cuda.is_bf16_supported(),
bf16=torch.cuda.is_bf16_supported(),
optim="adamw_8bit",
# Logging
logging_steps=10,
save_strategy="epoch",
# سرعت
weight_decay=0.01,
lr_scheduler_type="linear",
seed=3407,
),
)
# بررسی حافظه قبل از شروع
gpu_stats = torch.cuda.get_device_properties(0)
used_memory = round(torch.cuda.memory_allocated() / 1024**3, 2)
total_memory = round(gpu_stats.total_mem / 1024**3, 2)
print(f"GPU: {gpu_stats.name}")
print(f"حافظه مصرفی: {used_memory} GB / {total_memory} GB")
قدم ۵: شروع آموزش
# شروع آموزش!
trainer_stats = trainer.train()
# نمایش آمار آموزش
print(f"زمان آموزش: {trainer_stats.metrics['train_runtime']:.0f} ثانیه")
print(f"نمونه در ثانیه: {trainer_stats.metrics['train_samples_per_second']:.1f}")
# حافظه مصرفی نهایی
used_memory = round(torch.cuda.max_memory_allocated() / 1024**3, 2)
print(f"حداکثر حافظه مصرفی: {used_memory} GB")
قدم ۶: تست مدل
# تست سریع مدل Fine-tune شده
FastLanguageModel.for_inference(model) # سوئیچ به حالت inference
messages = [
{"role": "system", "content": "تو یه دستیار هوشمند هستی."},
{"role": "user", "content": "فرق بین LoRA و QLoRA رو توضیح بده."},
]
inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_tensors="pt",
).to("cuda")
outputs = model.generate(
input_ids=inputs,
max_new_tokens=512,
temperature=0.7,
use_cache=True,
)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(response)
قدم ۷: ذخیره مدل
# روش ۱: ذخیره فقط adapter (کمحجم)
model.save_pretrained("lora_model")
tokenizer.save_pretrained("lora_model")
# حجم: ~50-100 MB
# روش ۲: ذخیره مدل merge شده (کامل)
model.save_pretrained_merged(
"merged_model",
tokenizer,
save_method="merged_16bit", # یا "merged_4bit"
)
# حجم: ~16 GB (برای 8B model)
# روش ۳: ذخیره به فرمت GGUF (برای llama.cpp)
model.save_pretrained_gguf(
"gguf_model",
tokenizer,
quantization_method="q4_k_m", # یا q8_0, f16, ...
)
# حجم: ~4-8 GB
# روش ۴: آپلود به Hugging Face
model.push_to_hub_merged(
"your-username/my-fine-tuned-model",
tokenizer,
save_method="merged_16bit",
token="hf_your_token",
)
print("مدل آپلود شد!")
کد کامل از صفر تا صد
"""
Fine-tuning کامل با Unsloth
از لود مدل تا ذخیره نهایی
"""
from unsloth import FastLanguageModel
from trl import SFTTrainer
from transformers import TrainingArguments
from datasets import load_dataset
import torch
# ===== تنظیمات =====
MODEL_NAME = "unsloth/Llama-3.1-8B-Instruct"
DATASET_PATH = "my_dataset.jsonl"
OUTPUT_DIR = "outputs"
MAX_SEQ_LENGTH = 2048
EPOCHS = 3
BATCH_SIZE = 2
GRAD_ACCUM = 4
LEARNING_RATE = 2e-4
LORA_RANK = 16
# ===== لود مدل =====
model, tokenizer = FastLanguageModel.from_pretrained(
model_name=MODEL_NAME,
max_seq_length=MAX_SEQ_LENGTH,
load_in_4bit=True,
)
# ===== LoRA =====
model = FastLanguageModel.get_peft_model(
model, r=LORA_RANK, lora_alpha=LORA_RANK,
target_modules=["q_proj","k_proj","v_proj","o_proj",
"gate_proj","up_proj","down_proj"],
lora_dropout=0, bias="none",
use_gradient_checkpointing="unsloth",
)
# ===== دیتاست =====
dataset = load_dataset("json", data_files=DATASET_PATH, split="train")
def format_fn(examples):
texts = []
for msgs in examples["messages"]:
texts.append(tokenizer.apply_chat_template(
msgs, tokenize=False, add_generation_prompt=False
))
return {"text": texts}
dataset = dataset.map(format_fn, batched=True)
# ===== آموزش =====
trainer = SFTTrainer(
model=model, tokenizer=tokenizer,
train_dataset=dataset,
dataset_text_field="text",
max_seq_length=MAX_SEQ_LENGTH,
args=TrainingArguments(
output_dir=OUTPUT_DIR,
num_train_epochs=EPOCHS,
per_device_train_batch_size=BATCH_SIZE,
gradient_accumulation_steps=GRAD_ACCUM,
learning_rate=LEARNING_RATE,
warmup_steps=5,
bf16=torch.cuda.is_bf16_supported(),
fp16=not torch.cuda.is_bf16_supported(),
optim="adamw_8bit",
logging_steps=10,
save_strategy="epoch",
seed=3407,
),
)
stats = trainer.train()
print(f"آموزش تمام شد! زمان: {stats.metrics['train_runtime']:.0f}s")
# ===== ذخیره =====
model.save_pretrained("lora_model")
tokenizer.save_pretrained("lora_model")
print("مدل ذخیره شد!")
نکات و ترفندها
- Packing: اگه نمونههات کوتاهن (زیر ۵۱۲ توکن)،
packing=Trueبذار تا چند نمونه توی یه sequence جا بشن - gradient_checkpointing: حتماً از
"unsloth"استفاده کن — ۳۰٪ سریعتر از معمولیه - lora_dropout=0: Unsloth توصیه میکنه dropout رو ۰ بذاری
- مدلهای Unsloth: مدلهای با پیشوند
unsloth/سریعتر لود میشن - Multi-GPU: Unsloth فعلاً فقط روی یه GPU کار میکنه
Unsloth بهترین انتخاب برای Fine-tuning روی یه GPU هست. اگه چند GPU داری، از Hugging Face Accelerate یا DeepSpeed استفاده کن.
جمعبندی
Unsloth Fine-tuning رو ساده و سریع کرده. با چند خط کد میتونی مدل رو لود کنی، LoRA اضافه کنی، آموزش بدی و ذخیره کنی. مهمترین مزیتش سرعت و مصرف حافظه پایینه — یعنی میتونی روی GPUهای ارزونتر کار کنی.
ولی یه سوال مهم باقی میمونه: از کجا بفهمی مدل Fine-tune شدهات خوب شده؟ توی اپیزود بعدی، روشهای ارزیابی مدل رو بررسی میکنیم.
نظرات
هنوز نظری ثبت نشده. اولین نفر باشید!
نظر خود را بنویسید