در این بخش نگاهی نزدیکتر به ساخت و استفاده از مدلها میاندازیم. کلاس AutoModel
را به کار خواهیم گرفت که برای ساختن مدلها از نقطههای تعلیم مشخص، بسیار پرکاربرد است.
کلاس AutoModel
و تمامی کلاسهای شبیه آن، در واقع پوستهای ساده روی انواع مختلف مدلهای موجود در کتابخانه هستند. پوستهای هوشمند که میتواند به صورت خودکار معماری مدل استفاده شده در نقطههای تعلیم را تشخیص دهد و سپس مدلی با آن معماری بسازد.
با این وجود، اگر نوع مدلی که میخواهید استفاده کنید را میدانید، میتوانید مستقیماً کلاسی که معماری خاص آن مدل را تعریف میکند به کار ببرید. نگاهی به چگونگی انجام این عملیات با مدل BERT میاندازیم.
ساخت ترنسفورمر
اولین کار برای ساخت نمونهای از مدل BERT، بارگذاری شیء تنظیمات است:
from transformers import BertConfig, BertModel
# Building the config
config = BertConfig()
# Building the model from the config
model = BertModel(config)
شیء تنظیمات ویژگیهای بسیاری دارد که برای ساختن مدل به کار میروند.
print(config)
BertConfig {
[...]
"hidden_size": 768,
"intermediate_size": 3072,
"max_position_embeddings": 512,
"num_attention_heads": 12,
"num_hidden_layers": 12,
[...]
}
با وجود اینکه هنوز ندیدهاید تک تک این ویژگیها چه تاثیری دارند، بعضی از آنها برای شما آشنا هستند: ویژگی hidden_size
اندازه بردار hidden_states
را مشخص میکند و ویژگی num_hidden_layers
مشخص کننده تعداد لایههای مدل ترنسفورمر است.
روشهای مختلف بارگذاری
ساختن مدل با تنظیمات پیشفرض، باعث مقداردهی اولیه وزنهای آن با اعداد تصادفی میشود.
from transformers import BertConfig, BertModel
config = BertConfig()
model = BertModel(config)
# Model is randomly initialized!
میتوان از مدل در این وضعیت استفاده کرد ولی خروجی آن بیمعنی خواهد بود؛ ابتدا باید مدل را تعلیم دهیم. میتوانیم مدل را از صفر برای مسئله مورد نظرمان تعلیم دهیم ولی همان گونه که در فصل اول دیدیم، برای این کار نیاز به زمان طولانی و داده بسیار داریم. این عملیات تاثیرات منفی غیر قابل چشمپوشیای بر محیطزیست دارد. برای جلوگیری از دوبارهکاری باید بتوانیم مدلهای از پیش تعلیم دیده را به اشتراک گذاشته و به کار ببریم.
بارگذاری مدل از پیش تعلیم دیده ترنسفورمر، ساده است. برای این کار از تابع from_pretrained()
استفاده میکنیم.
from transformers import BertModel
model = BertModel.from_pretrained("bert-base-cased")
همان طور که قبلا دیدید، میتوانیم کلاس BertModel
را با کلاس معادل AutoModel
جایگزین کنیم. از این پس همین کار را خواهیم کرد چون به این صورت کد وابسته به نقطه تعلیم خاصی نخواهد بود. اگر کد شما با یک نقطه تعلیم اجرا میشود، بدون تغییر با نقاط تعلیم دیگر هم اجرا خواهد شد. این حتی در مورد معماریهای متفاوت هم صدق میکند، البته در صورتی که نقطه تعلیم متعلق به مسئله مشابهی(برای مثال تحلیل احساسات) باشد.
در کد نمونه بالا، کلاس BertConfig
را به کار نبرده و در عوض از مدلی از پیش تعلیم دیده با شناسه bert-base-cased
استفاده کردیم؛ نقطه تعلیم مدلی که توسط خود مؤلفان مدل BERT تعلیم دیده است. اطلاعات بیشتر در مورد این نقطه تعلیم را میتوانید در صفحه توضیحات آن ببینید.
این مدل اکنون با وزنهای نقطه تعلیم پر شده است و میتوان آن را مستقیماً برای مسائلی که برای آن تعلیم دیده به کار برد یا برای مسئله جدیدی کوک کرد. با تعلیم روی وزنهای از پیش تعلیم دیده، به جای تعلیم از صفر، میتوانیم به سرعت به نتایج خوبی دست پیدا کنیم.
این وزنها دانلود و در پوشهای مخصوص انبار شدهاند، تا اجرای تابع from_pretrained()
در آینده مسبب دانلود دوبارهاشان نباشد. این پوشه به صورت پیشفرض در آدرس ~/.cache/huggingface/transformers قرار دارد. شما میتوانید با تخصیص مقدار به متغیر محیطی HF_HOME
مکان این پوشه را تغییر دهید.
شناسه هر مدلی در هاب مدلها را میتوانید برای بارگذاری استفاده کنید. البته در صورتی که آن مدل با معماری BERT سازگاری داشته باشد. فهرست کامل تمام نقاط تعلیم سازگار با BERT را اینجا مشاهده کنید.
روشهای ذخیرهسازی
ذخیرهسازی مدل به سادگی بارگذاری آن است. از تابع save_pretrained()
استفاده میکنیم که متناظر با تابع from_pretrained()
است:
model.save_pretrained("directory_on_my_computer")
اجرای این تابع باعث ذخیره شدن دو فایل در سیستم شما میشود:
ls directory_on_my_computer
config.json pytorch_model.bin
اگر نگاهی به فایل config.json بیاندازید، با ویژگیهای آشنای مورد نیاز برای ساختن معماری مدل روبرو خواهید شد. این فایل حاوی مقادیری متادیتا، مانند نقطه مادر این نقطه تعلیم و نسخه کتابخانه ترنسفورمرهای هاگینگفِیس که آخرین بار برای ذخیرهسازی این نقطه به کار رفته است، میباشد.
فایل pytorch_model.bin در واقع دیکشنری وضعیتها است و حاوی تمام وزنهای مدل شماست. این دو فایل به همراه هم کاربرد دارند؛ فایل تنظیمات برای دانستن معماری به کار رفته در مدل ضروری است و پارامترهای مدل هم که همان وزنهای داخل فایل دوم هستند.
اجرای یک مدل ترنسفورمر
حالا که میدانید چگونه مدلها را ذخیرهسازی و بارگذاری کنید، میتوانیم آنها را برای پیشبینی به کار بگیریم. مدلهای ترنسفورمر فقط میتوانند اعداد را پردازش کنند؛ اعدادی که توکِنایزر تولید نموده است. ولی پیش از آن که سراغ بحث توکِنایزرها برویم، ورودیهای قابل قبول برای مدلها را بررسی میکنیم.
توکِنایزرها میتوانند ورودیها را به تِنسورهای مخصوص هر فریمورک تبدیل کنند ولی برای آنکه درست متوجه آنچه اتفاق میافتد شویم، نگاهی کوتاه به کارهایی که باید قبل از فرستادن ورودیها به مدل انجام شود میاندازیم.
تصور کنید چند جمله به این صورت داریم:
sequences = ["Hello!", "Cool.", "Nice!"]
توکِنایزر این جملات را به اندیسهای مخصوص کلمات که معمولا به آنها شناسههای ورودی میگوییم، تبدیل میکند. هر رشته اکنون لیستی از اعداد است! نتیجه خروجی از این قرار است:
encoded_sequences = [
[101, 7592, 999, 102],
[101, 4658, 1012, 102],
[101, 3835, 999, 102],
]
این خروجی لیستی از رشتههای کد شده شده است: لیستی از لیستها. تِنسورها تنها مقادیر به شکل مستطیل(همان ماتریس) را میپذیرند. این «آرایه» خود شکل مستطیلی دارد پس تبدیل آن به تِنسور ساده است:
import torch
model_inputs = torch.tensor(encoded_sequences)
استفاده از تِنسورها به عنوان ورودی مدل
به کار بردن تِنسورها به عنوان ورودی مدل بسیار ساده است؛ تنها آرگومان تِنسور ورودی را به صورت زیر به مدل پاس میدهیم:
output = model(model_inputs)
این تابع آرگومانهای بسیاری را میپذیرد ولی تنها شناسههای ورودی ضروری هستند. کاربرد آرگومانهای دیگر و شرایط ضرورت آنها را بعد توضیح خواهیم داد. ولی ابتدا باید نگاهی نزدیکتر به توکِنایزرهایی که ورودیهای قابل فهم مدلهای ترنسفورمر را میسازند، بیاندازیم.