آموزش پردازش زبان طبیعی با اکوسیستم هاگینگ فیس ؛ تنظیم دقیق مدل با Keras (فصل سوم؛قسمت دوم)
این قسمت از دوره آموزش پردازش زبان طبیعی با اکوسیستم هاگینگ فیس به تنظیم دقیق مدل با Keras خواهد پرداخت. همچنین شما میتوانید در انتهای مطلب به لینک سایر قسمتها دسترسی داشته باشید.
به محض اِتمام کلیهی کارهای پیشپردازش در بخش پیشین، فقط چند مرحله دیگر برای آموزش مدل در پیش دارید. اما توجه داشته باشید که دستور model.fit عملکرد بسیار کُندی در CPU خواهد داشت. اگر سیستمتان را به GPU مناسب مجهز نکردهاید، میتوانید به GPU یا TPU رایگان در Google Colab دسترسی داشته باشید. در کدهای زیر، فرض بر این است که نمونهها را در بخش پیشین اجرا کردهاید. در بخش زیر، اقدامات مورد نیاز به طور خلاصه ذکر شده است:
from datasets import load_dataset from transformers import AutoTokenizer import numpy as np raw_datasets = load_dataset("glue", "mrpc") checkpoint = "bert-base-uncased" tokenizer = AutoTokenizer.from_pretrained(checkpoint) def tokenize_dataset(dataset): encoded = tokenizer( dataset["sentence1"], dataset["sentence2"], padding=True, truncation=True, return_tensors='np', ) return encoded.data tokenized_datasets = { split: tokenize_dataset(raw_datasets[split]) for split in raw_datasets.keys() }
آموزش
مدلهای تنسورفلوی وارد شده از transformers نوعی مدل Keras به حساب میآیند. در این بخش، مقدمهی کوتاهی برای Keras تهیه کردهایم.
پس از اینکه دادهها در دسترس قرار گرفت، کار اندکی برای آغاز فرایند آموزش بر روی آن نداریم. همانطور که در فصل قبل ملاحظه کردید، دستهی TFAutoModelForSequenceClassification با دو برچسب مورد استفاده قرار خواهد گرفت:
from transformers import TFAutoModelForSequenceClassification model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
برخلاف آنچه در فصل 2 ذکر شد، پس از راهاندازی این مدلِ از پیش آموزشدیده یک هشدار ارسال میشود زیرا برت با جفت جملات آموزش ندیده است. از این رو، هدِ مدل کنار گذاشته نشده و هد تازهای به جای آن برای طبقهبندی توالی جایگذاری شده است. هشدارها نشان میدهند که بعضی از وزنها استفاده نشدهاند (وزنهای مربوط به هد پیشآموزش) و بعضی نیز به طور تصادفی به کار برده شدهاند (وزنهای مربوط به هد جدید). کار با ترغیب شما برای آموزش مدل به پایان میرسد. اینک، دقیقاً قصد انجام همین کار را داریم.
تنظیم دقیق مدل با توجه به دیتاست موجود مستلزم این است که مدل را کامپایل (compile()) کرده و سپس دادهها را در اختیار روش fit قرار دهیم. به این ترتیب، فرایند تنظیم دقیق آغاز میشود (که معمولاً با GPU چند دقیقه به طول میانجامد). در وهله بعدی، لاس در زمان آموزش و لاس در زمان اعتبارسنجی در پایان هر دوره گزارش داده میشود.
تفسیر این کار آسانی نیست. چه اطلاعاتی درباره دقت حقیقیِ مدل در دسترس میباشد؟ افزودن متریک accuracy الزامی است زیرا بینشمان را درباره عملکرد مدل ارتقاء میبخشد:
حال، ممکن است با یک مشکل روبرو شوید. فقط این امکان را دارید که نام تابع لاس را در قالب رشتهای به Keras منتقل کنید، اما Keras این پیشفرض را با خود دارد که از تابع سافتمکس در خروجیهایتان استفاده کردهاید. با این حال، بسیاری از مدلها پیش از بهکارگیری تابع سافتمکس از مقادیر خروجی میگیرند که با عنوان لاجیت نیز شناخته میشوند. باید این اطلاعات را در اختیار تابع loss قرار داد که مدلمان این کار را انجام میدهد و تنها راه برای انجامش این است که به طور مستقیم فراخوانی شود (نَه اینکه با یک رشته نامگذاری شود).
from tensorflow.keras.losses import SparseCategoricalCrossentropy model.compile( optimizer='adam', loss=SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'], ) model.fit( tokenized_datasets['train'], np.array(raw_datasets['train']['label']), validation_data=( tokenized_datasets['validation'], np.array(raw_datasets['validation']['label']), ), batch_size=8 )
ارتقای عملکرد آمورشی
اگر کد بالا را امتحان کنید، قطعاً اجرا میشود، اما خواهید دید که لاس به آهستگی یا به طور پراکنده کاهش مییابد. نرخ یادگیری، عامل اصلیِ این اتفاق است. همانطور که در لاس مشاهده کردید، اگر نام بهینهسازی را به عنوان یک رشته در اختیار Keras قرار دهید، آن بهینهساز در همه پارامترها با مقادیر پیشفرض اجرا میشود (از جمله نرخ یادگیری). تجربه نشان میدهد که فایدهای که نرخ یادگیری پایین برای مدلهای ترنسفورمر دارد، بیشتر از مقادیر پیشفرض Adam است (1e-3). این مقادیر به صورت نیز نوشته میشوند. Adam ده برابر سرعت کمتری دارد، اما نقطه شروع بهتری محسوب میشود.
علاوه بر پایین آوردن نرخ یادگیری، باید ترفند دیگری را نیز به کار برد. این امکان وجود دارد که نرخ یادگیری را در طی فرایند آموزش کاهش دهید. در پژوهشهای پیشین از این اقدام با عنوان تجزیهی نرخ یادگیری نیز یاد میکنند. بهترین راه در Keras استفاده از ابزار زمانبندی نرخ یادگیری است. ما PolynomialDecay را توصیه میکنیم؛ علیرغم نامش، نرخ یادگیری را در طی فرایند آموزش به طور خطی از مقدار اولیه به مقدار نهایی تقلیل میدهد. این کار یکی از اهداف مد نظر ماست. اما برای اینکه به درستی از ابزار زمانبندی استفاده کنید، باید مدت زمان آموزش را مشخص نمائید. num_train_steps طبق شرایط زیر مورد محاسبه قرار میگیرد.
from tensorflow.keras.optimizers.schedules import PolynomialDecay batch_size = 8 num_epochs = 3 # The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied # by the total number of epochs num_train_steps = (len(tokenized_datasets['train']['input_ids']) // batch_size) * num_epochs lr_scheduler = PolynomialDecay( initial_learning_rate=5e-5, end_learning_rate=0., decay_steps=num_train_steps ) from tensorflow.keras.optimizers import Adam opt = Adam(learning_rate=lr_scheduler)
اینک، یک بهینهساز جدید در اختیار دارید که امکان آموزش را مهیا میسازد. در ابتدا، مدل را مجدداً بارگذاری کنید تا تغییرات اِعمال شده بر روی وزنها در مرحله آموزش به حالت قبل بازگردد. سپس، مدل را با بهینهساز جدید کامپایل نمائید.
import tensorflow as tf model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) model.compile(optimizer=opt, loss=loss)
حال، شرایط مثل قبل شده است. اگر مدل کامپایل شود، کلیه تغییرات پیادهسازی میشوند. بنابراین، دستور fit کارکرد یکسانی دارد.
پیشبینی مدل
آموزش و مشاهدهی روند کاهش زیان بسیار لذتبخش است، اما اگر میخواهید خروجیها را از مدل آموزش دیده به دست آورید، محاسبهی برخی متریکها یا استفاده از مدل میتواند موثر باشد؟ برای انجام این کار، میتوانید به استفاده از روش predict() بسنده کنید. بنابراین، لاگیتها از هد خروجی مدل به دست خواهند آمد (در ازای هر دسته).
preds = model.predict(tokenized_datasets['validation'])['logits']
میتوانید این لاجیتها را با استفاده از argmax به پیشبینی دستهی مدل تبدیل کنید تا بالاترین لاجیت به دست آید.
class_preds = np.argmax(preds, axis=1) print(preds.shape, class_preds.shape)
(408, 2) (408,)
اکنون، باید از preds برای محاسبهی برخی متریکها استفاده کنید. به همان شیوهای که دیتاست را بارگذاری کردید، میتوانید متریکهای مرتبط با دیتاست MRPC را بارگذاری کنید، اما این بار با تابع load_metric . شیء خروجی شده یک روش compute دارد که میتواند برای محاسبه متریک مورد استفاده قرار گیرد:
from datasets import load_metric metric = load_metric("glue", "mrpc") metric.compute(predictions=class_preds, references=raw_datasets['validation']['label'])
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}
نتایجی که به دست میآورید، میتواند متغیر باشد زیرا راهاندازیِ تصادفیِ هد مدل ممکن است متریکهای به دست آمده را تغییر دهد. همانطور که میبینید، مدل در مجموعه اعتبارسنجی به دقت 0.8578 درصدی رسیده است و مقدار F1 آن برابر با 0.8997 میباشد. این دو متریک در ارزیابی نتایج دیتاست MRPC در بنچمارک GLUE کاربرد دارند. جدول این مقالهی برت، مقدار 0.889 را برای F1 گزارش کرده است. این مدل uncased بود، اما در حال حاضر از مدل cased استفاده میشود. اگر به صورت دستی این روش را فراخوانی کنید، شاید قدری اذیت شوید.
آیا این امکان وجود دارد که وظیفهی محاسبات به عهدهی Keras سپرده شود؟ انجام این کار میتواند فرصتی برای رصدِ متریکها در طی فرایند آموزش ارائه کند. Keras به طور پیشفرض از چند متریک پشتیبانی میکند و با نوشتن نامشان در یک رشته انتقال داده میشوند. عملکرد آن شبیه بهینهسازها و توابع زیان است. متاسفانه، مقدار F1 در این دسته جای نمیگیرد. اگر تعریف مقدار F1 را جستجو کنید، میبینید که صرفاً میانگین هامونیکِ دقت و فراخوانی است؛ متریک Keras از هر دوی آنها پشتیبانی میکند. آیا میتوان از آن برای نوشتن یک متریک F1 ساده استفاده کرد؟
class F1_metric(tf.keras.metrics.Metric): def __init__(self, name='f1_score', **kwargs): super().__init__(name=name, **kwargs) # Initialize our metric by initializing the two metrics it's based on: # Precision and Recall self.precision = tf.keras.metrics.Precision() self.recall = tf.keras.metrics.Recall() def update_state(self, y_true, y_pred, sample_weight=None): # Update our metric by updating the two metrics it's based on self.precision.update_state(y_true, y_pred, sample_weight) self.recall.update_state(y_true, y_pred, sample_weight) def reset_state(self): self.precision.reset_state() self.recall.reset_state() def result(self): # To get the F1 result, we compute the harmonic mean of the current # precision and recall return 2 / ((1 / self.precision.result()) + (1 / self.recall.result()))
شاید کدهای بالا موجب ترس و اضطرابتان میشود، اما نگران نباشید. ساخت دسته با عملِ subclassing در این کدها توضیح داده شده است. این روش قدرتمند در کدهای بسیار پیشرفتهی پایتون کاربرد دارد. اکنون لازم نیست همه جزئیات این کدها را درک کنید. ما سعی کردیم متریک Metric جدیدی با استفاده از دستهی tf.keras.metrics.Metric بسازیم. به تعبیری، فقط باید به تصریح مواردی پرداخت که Metric به صورت منحصربفرد انجام میدهد. دستهی base (پایه) میتواند سایر کدهای بویلرپلیتِ دستههای Metric را مدیریت کند. دوباره تکرار میکنیم که اجازه ندهید این فرایند موجب ترس و اضطرابتان شود. اکنون نوبت به بارگذاری و آموزش مجدد مدل رسیده است. توجه داشته باشید که متریکها میتوانند با هم ترکیب شوند.
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) lr_scheduler = PolynomialDecay( initial_learning_rate=5e-5, end_learning_rate=0., decay_steps=num_train_steps ) opt = Adam(learning_rate=lr_scheduler) model.compile(optimizer=opt, loss=loss, metrics=['accuracy', F1_metric()]) model.fit( tokenized_datasets['train'], np.array(raw_datasets['train']['label']), validation_data=(tokenized_datasets['validation'], np.array(raw_datasets['validation']['label'])), batch_size=8, epochs=3 )
این بار، تابع زیان و متریکهای موجود در بالای زیان آموزش گزارش میشوند. دوباره، مقدار دقیق F1 ممکن است قدری با محاسبات ما فرق داشته باشد و دلیل آن را میتوان به راهاندازی هد تصادفیِ مدل نسبت داد. بنابراین، مقدمهی تنظیم دقیق با استفاده از Keras API به پایان میرسد. در فصل 7، نمونهای از آن برای متداولترین کارهای NLP ارائه خواهد شد. اگر قصد دارید مهارتهایتان را در Keras API تقویت کنید، مد را با دیتاست GLUE SST-2 تنظیم کنید. میتوانید از فرایند پردازش داده در بخش 2 استفاده کنید.
از طریق لینک زیر میتوانید به سایر فصلها و قسمتهای دوره آموزش پردازش زبان طبیعی دسترسی داشته باشید:
[button href=”https://hooshio.com/%D8%B1%D8%B3%D8%A7%D9%86%D9%87-%D9%87%D8%A7/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D8%B4-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B7%D8%A8%DB%8C%D8%B9%DB%8C/” type=”btn-default” size=”btn-lg”]آموزش پردازش زبان طبیعی[/button]