NLP Course documentation

کوک کردن مدل‌ها با استفاده از API Trainer

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

کوک کردن مدل‌ها با استفاده از API Trainer

Open In Colab Open In Studio Lab

ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام Trainer دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف Trainer دارید. سخت ترین قسمت، احتمالا آماده‌سازی محیط جهت اجراي Trainer.train() می‌باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود. اگر GPU ندارید، می‌توانید از GPU یا TPUهای مجانی روی گوگل کولَب استفاده کنید.

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

from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPadding

raw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)


def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)


tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

تعلیم

قبل از این که بتوانیم Trainer مان را تعریف کنیم اولین مرحله تعریف کلاس TrainingArguments می‌باشد که شامل همه پارامترهای سطح بالایی است که Trainer برای Training و Evaluation استفاده خواهد کرد. تنها آرگومانی که شما باید ارائه کنید آدرسی است که مدل تعلیم دیده به همراه نقاط تعلیم در آن ذخیره خواهند شد. بقیه پارامترها را می‌توانید به حالت پیش‌فرض رها کنید، که برای کوک کردن پایه به خوبی کار خواهد کرد.

from transformers import TrainingArguments

training_args = TrainingArguments("test-trainer")

💡 اگر مایلید مدل‌تان را به صورت خودکار در حین تعلیم در هاب بارگذاری کنید، پارامتر push_to_hub=True را در TrainingArguments ارسال کنید. در فصل ۴ در این باره بیشتر خواهیم آموخت.

مرحله دوم تعریف مدل‌مان می‌باشد. مانند فصل قبل، از کلاس AutoModelForSequenceClassification با دو برچسب کلاس استفاده خواهیم کرد:

from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)

شما متوجه خواهید شد که برخلاف فصل ۲، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان کاری است که می‌خواهیم اکنون انجام دهیم.

به محض اینکه مدل‌مان مشخص شد می‌توانیم Trainer را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - model، training_args، دیتاسِت‌های training و validation، data_collator و tokenizer به داخل آن تعریف کنیم:

from transformers import Trainer

trainer = Trainer(
    model,
    training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
)

توجه داشته باشید زمانی که tokenizer را ارسال می‌کنید، مثل کاری که ما در اینجا انجام دادیم، data_collator پیش‌فرض مورد استفاده Trainer، همانطور که قبلا تعریف کردیم، DataCollatorWithPadding خواهد بود، در تنیجه شما می‌توانید خط data_collator=data_collator را در این فراخوانی نادیده بگیرید. این هنوز مهم بود که این بخش از پردازش را در بخش ۲ به شما نشان دهیم!

برای کوک کردن مدل روی دیتاسِت‌مان ما فقط باید تابع train() از Trainerمان را صدا بزنیم:

trainer.train()

این کار، کوک کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و هزینه تعلیم را هر ۵۰۰ مرحله یک‌بار گزارش می‌کند. با این حال به شما نمی‌گوید که مدل‌تان چقدر خوب (یا بد) عمل می‌کند. این به این خاطر است که:

۱. ما به Trainer نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با مقداردهی پارامتر evaluation_strategy به "steps" (برای ارزیابی در هر eval_steps) یا به "epoch" (برای ارزیابی در انتهای هر epoch) انجام دهیم.

۲. ما تابع compute_metrics() را برای Trainer فراهم نکردیم تا بتواند معیارها را در حین اصطلاحا ارزیابی محاسبه کند (که در غیر این صورت، ارزیابی فقط هزینه را چاپ می‌کند که عدد چندان گویایی هم نیست) .

ارزیابی

اجازه دهید ببینیم چگونه می‌توانیم تابع compute_metrics() مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء EvalPrediction دریافت کند (که تاپلی است شامل فیلدهای predictions و label_ids) و یک دیکشنری باز گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آن‌ها می باشند). برای استخراج چند پیش‌بینی‌ از مدل‌مان، می‌توانیم از دستور Trainer.predict() استفاده کنیم:

predictions = trainer.predict(tokenized_datasets["validation"])
print(predictions.predictions.shape, predictions.label_ids.shape)
(408, 2) (408,)

خروجی تابع predict() تاپل نام گذاری شده دیگری شامل سه فیلد: predictions، label_ids و metrics می‌باشد. فیلد metrics فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (پیش‌بینی‌، در مجموع و به طور میانگین، چقدر طول کشیده) می‌باشد. به محض این که تابع compute_metrics() را کامل کرده و آن را به Trainer ارسال کنیم، آن فیلد متریک‌های بازگشتی از compute_metrics() را نیز در بر خواهد داشت.

همانطور که می‌بینید، predictions آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها logits مربوط به هریک از عناصر دیتاسِتی هستند که ما به تابع predict() ارسال کردیم (همانطور که در فصل قبل دیدید، همه مدل‌های ترَنسفورمِر logits را باز می‌گردانند). برای تبدیل logits به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی بعد دوم را برداریم:

import numpy as np

preds = np.argmax(predictions.predictions, axis=-1)

اکنون می‌توانیم preds را با برچسب‌ها مقایسه کنیم. برای ساختن تابع compute_metric()، به متریک‌های کتابخانه داده‌های هاگینگ‌فِیس تکیه خواهیم کرد. ما می‌توانیم متریک‌های وابسته به دیتاسِت MRPC را به راحتی خود دیتاسِت، اما این بار با استفاده از تابع load_metric()، بارگذاری کنیم. شیء بازگردانده شده تابعی به نام compute() دارد که می‌توانیم برای محاسبه متریک از آن استفاده کنیم:

from datasets import load_metric

metric = load_metric("glue", "mrpc")
metric.compute(predictions=preds, references=predictions.label_ids)
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}

از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما accuracy معادل ۸۵.۷۸٪ و F1 Score معادل ۸۹.۹۷٪ روی مجموعه validation بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله BERT، برای مدل پایه، F1 Score معادل ۸۸.۹ را گزارش می‌کند. توجه داشته باشید که آن مدل uncased بود، حال آن که در اینجا ما از مدل cased استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد.

اکنون با قرار دادن همه چیز کنارهم تابع compute_metrics() را بدست خواهیم آورد:

def compute_metrics(eval_preds):
    metric = load_metric("glue", "mrpc")
    logits, labels = eval_preds
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)

و در اینجا نشان می‌دهیم که چگونه یک Trainer جدید با استفاده از تابع compute_metrics() تعریف می‌کنیم، تا بتوانیم عملکرد آن را در حین گزارش متریک‌ها در پایان هر epoch مشاهده کنیم:

training_args = TrainingArguments("test-trainer", evaluation_strategy="epoch")
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)

trainer = Trainer(
    model,
    training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
    compute_metrics=compute_metrics,
)

توجه داشته باشید که ما مدلی جدید و TrainingArguments جدیدی که evaluation_strategy آن "epoch" است می‌سازیم - در غیر این صورت فقط تعلیم مدلی که از پیش تعلیم دیده بود را ادامه می‌دادیم. برای راه‌اندازی دور جدید تعلیم، دستور زیر را اجرا می‌کنیم:

trainer.train()

این بار هزینه validation و متریک‌ها را در پایان هر epoch و در بالای هزینه تعلیم گزارش می‌کنیم. دوباره، به خاطر مقدار دهی تصادفی اولیه لایه سر مدل، مقادیر دقیق accuracy/F1 score که شما بدست می‌آورید ممکن است کمی متفاوت از آنچه ما بدست آورده‌ایم باشد، اما این مقادیر باید در محدوده تخمینی یکسانی باشند.

به صورت پیش فرض، Trainer روی چندین GPU یا TPU کار خواهد کرد و گزینه‌های فراوانی، مثل تعلیم mixed-precision (از مقدار fp16 = True در آرگومان‌های تعلیم استفاده کنید) فراهم می‌کند. در فصل ۱۰ همه حالت‌هایی که پشتیبانی می‌کند را مرور خواهیم کرد.

این پایان مقدمه‌ای بر کوک کردن با استفاده از Trainer API می‌باشد. در فصل ۷ مثالی برای نشان دادن چگونگی انجام این کار برای معمول‌ترین مسئله‌های NLP ارائه خواهیم کرد، اما اکنون اجازه دهید ببینیم چگونه همین کار را صرفا با استفاده از PyTorch انجام دهیم.

✏️ اتحان کنید! با استفاده از پردازش داده‌ای که در بخش ۲ انجام دادید، مدلی را روی دیتاسِت GLUE SST-2 کوک کنید.