چرا داده مهمترین بخشه؟
یه ضربالمثل توی دنیای یادگیری ماشین هست: “Garbage in, garbage out.” اگه دادههات بد باشن، مدلت هم بد میشه — مهم نیست چقدر GPU قوی داری یا از چه تکنیکی استفاده میکنی.
Fine-tuning مثل آموزش یه شاگرد باهوشه. اگه بهش کتابهای بد بدی، بد یاد میگیره. اگه کتابهای خوب ولی کم بدی، بهتره از اینکه کلی کتاب بد بدی.
فرمتهای رایج دیتاست
۱. فرمت Instruction
سادهترین فرمت. یه دستورالعمل (instruction) و یه خروجی (output):
# فرمت Instruction — هر خط یه JSON
{"instruction": "فرق بین list و tuple رو توضیح بده.",
"output": "list تغییرپذیره (mutable) یعنی بعد از ساختنش میتونی عناصرش رو تغییر بدی. tuple تغییرناپذیره (immutable) و بعد از ساختن قابل تغییر نیست."}
{"instruction": "یه تابع بنویس که فاکتوریل محاسبه کنه.",
"output": "def factorial(n):\n if n <= 1:\n return 1\n return n * factorial(n - 1)"}
# با ورودی اختیاری
{"instruction": "متن زیر رو خلاصه کن.",
"input": "هوش مصنوعی شاخهای از علوم کامپیوتر است که...",
"output": "هوش مصنوعی حوزهای در علوم کامپیوتر برای..."}
۲. فرمت Conversation (مکالمهای)
برای مدلهای چت. هر نمونه یه مکالمه کامله:
# فرمت Chat/Conversation
{
"messages": [
{"role": "system", "content": "تو یه دستیار برنامهنویسی پایتون هستی."},
{"role": "user", "content": "چطور فایل CSV بخونم؟"},
{"role": "assistant", "content": "برای خوندن فایل CSV در پایتون از کتابخانه pandas استفاده کن:\n\nimport pandas as pd\ndf = pd.read_csv('data.csv')\nprint(df.head())"},
{"role": "user", "content": "اگه فایل با جداکننده tab باشه چی؟"},
{"role": "assistant", "content": "فقط پارامتر sep رو تغییر بده:\n\ndf = pd.read_csv('data.tsv', sep='\\t')"}
]
}
۳. فرمت Completion
سادهترین فرمت — فقط متن خام:
# فرمت Completion — برای ادامه متن
{"text": "### سوال: فرق HTTP و HTTPS چیه?\n\n### جواب: HTTPS نسخه امن HTTP هست..."}
# یا بدون ساختار خاص
{"text": "در برنامهنویسی پایتون، decorator یه تابعه که تابع دیگهای رو..."}
چقدر داده لازمه؟
جواب کوتاه: بستگی داره. ولی یه راهنمای کلی:
- تغییر سبک/لحن: ۵۰۰-۱۰۰۰ نمونه
- Task جدید ساده: ۱۰۰۰-۳۰۰۰ نمونه
- Task پیچیده: ۳۰۰۰-۱۰,۰۰۰ نمونه
- دانش جدید تخصصی: ۵۰۰۰-۲۰,۰۰۰ نمونه
- زبان جدید: ۱۰,۰۰۰+ نمونه
# اسکریپت بررسی کیفیت دیتاست
import json
from collections import Counter
def analyze_dataset(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
data = [json.loads(line) for line in f]
print(f"تعداد نمونهها: {len(data)}")
# بررسی طولها
lengths = []
for item in data:
if "messages" in item:
total_len = sum(len(m["content"]) for m in item["messages"])
elif "instruction" in item:
total_len = len(item["instruction"]) + len(item.get("output", ""))
else:
total_len = len(item.get("text", ""))
lengths.append(total_len)
print(f"میانگین طول: {sum(lengths)/len(lengths):.0f} کاراکتر")
print(f"کوتاهترین: {min(lengths)} کاراکتر")
print(f"بلندترین: {max(lengths)} کاراکتر")
# بررسی تکراریها
if "instruction" in data[0]:
instructions = [d["instruction"] for d in data]
duplicates = len(instructions) - len(set(instructions))
print(f"تکراریها: {duplicates}")
return data
data = analyze_dataset("my_dataset.jsonl")
تمیزکاری داده
۱. حذف نمونههای بد
def clean_dataset(data):
cleaned = []
removed = {"empty": 0, "too_short": 0, "too_long": 0, "duplicate": 0}
seen = set()
for item in data:
instruction = item.get("instruction", "")
output = item.get("output", "")
# حذف خالیها
if not instruction.strip() or not output.strip():
removed["empty"] += 1
continue
# حذف خیلی کوتاهها
if len(output) < 20:
removed["too_short"] += 1
continue
# حذف خیلی بلندها
if len(instruction) + len(output) > 8000:
removed["too_long"] += 1
continue
# حذف تکراریها
key = instruction.strip().lower()
if key in seen:
removed["duplicate"] += 1
continue
seen.add(key)
cleaned.append(item)
print(f"قبل از تمیزکاری: {len(data)}")
print(f"بعد از تمیزکاری: {len(cleaned)}")
print(f"حذف شدهها: {removed}")
return cleaned
۲. نرمالسازی متن فارسی
import re
def normalize_persian(text):
"""نرمالسازی متن فارسی"""
# یکسانسازی کاراکترهای عربی و فارسی
text = text.replace('ك', 'ک')
text = text.replace('ي', 'ی')
text = text.replace('٤', '۴')
text = text.replace('٥', '۵')
text = text.replace('٦', '۶')
# حذف فاصلههای اضافی
text = re.sub(r'\s+', ' ', text)
# حذف نیمفاصلههای اضافی
text = re.sub(r'{2,}', '', text)
# اصلاح نیمفاصله
text = re.sub(r' (می|نمی) ', r' \1', text)
text = re.sub(r' (ها|های|هایی) ', r'\1 ', text)
return text.strip()
# اعمال روی دیتاست
for item in data:
item["instruction"] = normalize_persian(item["instruction"])
item["output"] = normalize_persian(item["output"])
Deduplication: حذف تکراریها
داده تکراری یکی از بدترین مشکلاته. باعث میشه مدل overfit کنه و فقط اون نمونهها رو حفظ کنه.
from datasketch import MinHash, MinHashLSH
def remove_near_duplicates(data, threshold=0.8):
"""حذف نمونههای تقریباً مشابه با MinHash LSH"""
lsh = MinHashLSH(threshold=threshold, num_perm=128)
unique_data = []
for i, item in enumerate(data):
text = item.get("instruction", "") + " " + item.get("output", "")
# ساخت MinHash
mh = MinHash(num_perm=128)
for word in text.split():
mh.update(word.encode('utf-8'))
# بررسی تکراری بودن
result = lsh.query(mh)
if not result:
lsh.insert(str(i), mh)
unique_data.append(item)
print(f"قبل: {len(data)} → بعد: {len(unique_data)}")
return unique_data
Data Augmentation: زیاد کردن داده
اگه داده کم داری، میتونی با تکنیکهای مختلف داده بیشتری بسازی:
# روش ۱: بازنویسی سوال (Paraphrasing)
def augment_with_llm(instruction, model="gpt-4"):
"""ساخت نسخههای مختلف سوال با LLM"""
prompt = f"""سوال زیر رو به ۳ شکل مختلف بازنویسی کن.
معنی رو تغییر نده، فقط نحوه بیان رو عوض کن.
سوال اصلی: {instruction}
۳ بازنویسی:"""
# فراخوانی API
response = call_llm(prompt, model=model)
return parse_paraphrases(response)
# روش ۲: ساخت داده مصنوعی
def generate_synthetic_data(topic, num_samples=100):
"""ساخت جفت سوال-جواب مصنوعی"""
prompt = f"""برای موضوع "{topic}" تعداد {num_samples} جفت سوال و جواب
آموزشی بساز. جوابها باید دقیق و کامل باشن.
فرمت خروجی:
Q: سوال
A: جواب
---"""
response = call_llm(prompt)
return parse_qa_pairs(response)
# روش ۳: تغییر فرمت
def change_format(item):
"""تبدیل فرمت نمونه"""
variations = []
# تبدیل به سوال بله/خیر
variations.append({
"instruction": f"آیا جمله زیر درسته؟ {item['output'][:50]}...",
"output": "بله، این جمله درست است."
})
# تبدیل به تکمیل جمله
variations.append({
"instruction": f"جمله زیر رو کامل کن: {item['output'][:30]}...",
"output": item['output']
})
return variations
ابزار Argilla برای مدیریت دیتاست
Argilla یه ابزار open-source برای مدیریت، برچسبگذاری و بررسی دیتاسته:
# نصب Argilla
# pip install argilla
import argilla as rg
# اتصال به سرور Argilla
rg.init(api_url="http://localhost:6900", api_key="your_key")
# ساخت دیتاست برای بررسی کیفیت
dataset = rg.FeedbackDataset(
fields=[
rg.TextField(name="instruction", title="سوال"),
rg.TextField(name="output", title="جواب"),
],
questions=[
rg.RatingQuestion(
name="quality",
title="کیفیت جواب",
values=[1, 2, 3, 4, 5]
),
rg.TextQuestion(
name="corrected_output",
title="جواب اصلاحشده (اگه لازمه)",
required=False
),
],
)
# آپلود نمونهها
records = [
rg.FeedbackRecord(
fields={"instruction": item["instruction"], "output": item["output"]}
)
for item in data
]
dataset.add_records(records)
dataset.push_to_argilla(name="fine-tuning-review")
تبدیل به فرمت نهایی
import json
def convert_to_chat_format(data, system_prompt=""):
"""تبدیل دیتاست به فرمت مکالمهای"""
converted = []
for item in data:
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.append({"role": "user", "content": item["instruction"]})
messages.append({"role": "assistant", "content": item["output"]})
converted.append({"messages": messages})
return converted
# تبدیل و ذخیره
chat_data = convert_to_chat_format(
cleaned_data,
system_prompt="تو یه دستیار متخصص برنامهنویسی پایتون هستی."
)
# تقسیم به train و validation
from sklearn.model_selection import train_test_split
train_data, val_data = train_test_split(chat_data, test_size=0.1, random_state=42)
# ذخیره
def save_jsonl(data, path):
with open(path, 'w', encoding='utf-8') as f:
for item in data:
f.write(json.dumps(item, ensure_ascii=False) + '\n')
save_jsonl(train_data, "train.jsonl")
save_jsonl(val_data, "val.jsonl")
print(f"Train: {len(train_data)} نمونه")
print(f"Validation: {len(val_data)} نمونه")
چکلیست کیفیت دیتاست
قبل از شروع Fine-tuning، این چکلیست رو بررسی کن:
- آیا نمونهها تکراری نیستن؟
- آیا جوابها دقیق و بدون خطان؟
- آیا سبک جوابها یکدسته؟
- آیا تنوع کافی توی سوالات هست؟
- آیا نمونههای خیلی کوتاه یا خیلی بلند حذف شدن؟
- آیا فرمت همه نمونهها یکسانه؟
- آیا validation set جدا شده؟
- آیا متن فارسی نرمالسازی شده؟
یادت باشه: ۸۰٪ وقت Fine-tuning باید صرف آمادهسازی داده بشه. اگه دادهات خوب باشه، بقیه کار نسبتاً سادهست.
جمعبندی
آمادهسازی دیتاست مهمترین و زمانبرترین بخش Fine-tuning هست. روی کیفیت تمرکز کن نه کمیت. دادهها رو تمیز، نرمالسازی و deduplicate کن. از ابزارهایی مثل Argilla برای بررسی کیفیت استفاده کن.
حالا که دیتاست آمادهست، توی اپیزود بعدی Unsloth رو بررسی میکنیم — ابزاری که Fine-tuning رو ۲ برابر سریعتر و با ۶۰ درصد حافظه کمتر انجام میده.
نظرات
هنوز نظری ثبت نشده. اولین نفر باشید!
نظر خود را بنویسید