Buckets:
| # Course | |
| ## Docs | |
| - [مقدمه](https://huggingface.co/learn/course/fa/chapter3/1.md) | |
| - [پردازش داده](https://huggingface.co/learn/course/fa/chapter3/2.md) | |
| - [کوک کردن مدلها با استفاده از API `Trainer`](https://huggingface.co/learn/course/fa/chapter3/3.md) | |
| - [کوک کردن مدلها با استفاده از کِراس](https://huggingface.co/learn/course/fa/chapter3/3_tf.md) | |
| - [مقدمه](https://huggingface.co/learn/course/fa/chapter0/1.md) | |
| - [هاب هاگینگفِیس](https://huggingface.co/learn/course/fa/chapter4/1.md) | |
| - [بکارگیری مدلهای از پیش تعلیم دیده](https://huggingface.co/learn/course/fa/chapter4/2.md) | |
| - [مقدمه](https://huggingface.co/learn/course/fa/chapter1/1.md) | |
| - [پردازش زبان طبیعی](https://huggingface.co/learn/course/fa/chapter1/2.md) | |
| - [واژهنامه](https://huggingface.co/learn/course/fa/glossary/1.md) | |
| - [مقدمه](https://huggingface.co/learn/course/fa/chapter2/1.md) | |
| - [پشت صحنه خط تولید](https://huggingface.co/learn/course/fa/chapter2/2.md) | |
| - [مدلها](https://huggingface.co/learn/course/fa/chapter2/3.md) | |
| ### مقدمه | |
| https://huggingface.co/learn/course/fa/chapter3/1.md | |
| # مقدمه | |
| در [فصل ۲](/course/chapter2) نحوه استفاده از توکِنایزرها و مدلهای از پیش تعلیم دیده را جهت انجام پیشبینیهای جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش تعلیم دیده را خودتان کوک کنید؟ | |
| {#if fw === 'pt'} | |
| * چگونه دیتاسِتهای بزرگ را از هاب تهیه کنید | |
| * چگونه از `API` سطح بالای `Trainer` برای کوک کردن مدل استفاده کنید | |
| * چگونه یک چرخه تعلیم دلخواه درست کنید | |
| * چگونه از کتابخانه `Accelerate` هاگینگفِیس برای اجرای چرخه تعلیم دلخواه در هر نوع تنظیمات توزیع شدهای استفاده کنید | |
| {:else} | |
| * چگونه دیتاسِتهای بزرگ را از هاب تهیه کنید | |
| * چگونه از کِراس برای کوک کردن مدل استفاده کنید | |
| * چگونه از کِراس برای استخراج پیشبینیها استفاده کنید | |
| * چگونه از مِتریک دلخواه استفاده کنید | |
| {/if} | |
| جهت آپلود نقطه تعلیم خود در هاب هاگینگفِیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) | |
| ### پردازش داده | |
| https://huggingface.co/learn/course/fa/chapter3/2.md | |
| # پردازش داده | |
| {#if fw === 'pt'} | |
| {:else} | |
| {/if} | |
| {#if fw === 'pt'} | |
| در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدلهای دستهبندی کننده رشتهها را در یک بَتچ با استفاده از پایتورچ شرح میدهیم: | |
| ```python | |
| import torch | |
| from torch.optim import AdamW | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification | |
| # Same as before | |
| checkpoint = "bert-base-uncased" | |
| tokenizer = AutoTokenizer.from_pretrained(checkpoint) | |
| model = AutoModelForSequenceClassification.from_pretrained(checkpoint) | |
| sequences = [ | |
| "I've been waiting for a HuggingFace course my whole life.", | |
| "This course is amazing!", | |
| ] | |
| batch = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") | |
| # This is new | |
| batch["labels"] = torch.tensor([1, 1]) | |
| optimizer = AdamW(model.parameters()) | |
| loss = model(**batch).loss | |
| loss.backward() | |
| optimizer.step() | |
| ``` | |
| {:else} | |
| در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدلهای دستهبندی کننده رشتهها را در یک بَتچ با استفاده از تِنسورفلو شرح میدهیم: | |
| ```python | |
| import tensorflow as tf | |
| import numpy as np | |
| from transformers import AutoTokenizer, TFAutoModelForSequenceClassification | |
| # Same as before | |
| checkpoint = "bert-base-uncased" | |
| tokenizer = AutoTokenizer.from_pretrained(checkpoint) | |
| model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) | |
| sequences = [ | |
| "I've been waiting for a HuggingFace course my whole life.", | |
| "This course is amazing!", | |
| ] | |
| batch = dict(tokenizer(sequences, padding=True, truncation=True, return_tensors="tf")) | |
| # This is new | |
| model.compile(optimizer="adam", loss="sparse_categorical_crossentropy") | |
| labels = tf.convert_to_tensor([1, 1]) | |
| model.train_on_batch(batch, labels) | |
| ``` | |
| {/if} | |
| البته تعلیم با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آمادهسازی دیتاسِت بزرگتری خواهید داشت. | |
| در این بخش ما از دیتاسِت MRPC[^1] که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشتهی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب میباشد که برچسب نشان دهنده متناظر بودن جملات میباشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. | |
| ### بارگذاری دیتاسِتها از هاب | |
| {#if fw === 'pt'} | |
| {:else} | |
| {/if} | |
| هاب تنها شامل مدلها نمیباشد؛ بلکه شامل دیتاسِتهای متعدد در بسیاری از زبانهای مختلف میباشد. شما میتوانید دیتاسِتها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد میکنیم پس از اتمام این بخش یک دیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading) مشاهده کنید). اما اجازه بدهید اکنون روی دیتاسِت MRPC تمرکز کنیم! این یکی از ۱۰ دیتاسِت [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دستهبندی متن مختلف میباشد. | |
| کتابخانه دیتاسِت هاگینگفِیس یک دستور بسیار ساده جهت دانلود و انبار کردن یک دیتاسِت در هاب ارائه میکند. ما میتوانیم دیتاسِت MRPC را به روش زیر دانلود کنیم: | |
| > [!TIP] | |
| > ⚠️ **هشدار** مطمئن شوید که `datasets` نصب شده است. برای اطمینان، دستور `pip install datasets` را اجرا کنید. سپس، مجموعه داده MRPC را بارگذاری کنید و آن را چاپ کنید تا ببینید چه چیزی در آن وجود دارد. | |
| ```py | |
| from datasets import load_dataset | |
| raw_datasets = load_dataset("glue", "mrpc") | |
| raw_datasets | |
| ``` | |
| ```python out | |
| DatasetDict({ | |
| train: Dataset({ | |
| features: ['sentence1', 'sentence2', 'label', 'idx'], | |
| num_rows: 3668 | |
| }) | |
| validation: Dataset({ | |
| features: ['sentence1', 'sentence2', 'label', 'idx'], | |
| num_rows: 408 | |
| }) | |
| test: Dataset({ | |
| features: ['sentence1', 'sentence2', 'label', 'idx'], | |
| num_rows: 1725 | |
| }) | |
| }) | |
| ``` | |
| همانطور که میبینید یک شیء `DatasetDict` بدست میآوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` میباشد. هر یک از اینها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل میدهند میباشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). | |
| این دستور دیتاسِت را دانلود و به صورت پیشفرض در پوشه *~/.cache/huggingface/dataset* انبار میکند. از فصل ۲ به یاد داشته باشید که میتوانید پوشه انبار کردنتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. | |
| ما میتوانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس, مانند یک دیکشنری دسترسی پیدا کنیم: | |
| ```py | |
| raw_train_dataset = raw_datasets["train"] | |
| raw_train_dataset[0] | |
| ``` | |
| ```python out | |
| {'idx': 0, | |
| 'label': 1, | |
| 'sentence1': 'Amrozi accused his brother , whom he called " the witness " , of deliberately distorting his evidence .', | |
| 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} | |
| ``` | |
| میبینیم که برچسبها از پیش اعداد صحیح هستند، بنابراین لازم نیست هیچ پیشپردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط میشود، میتوانیم `features` از `raw_train_dataset`مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت. | |
| ```py | |
| raw_train_dataset.features | |
| ``` | |
| ```python out | |
| {'sentence1': Value(dtype='string', id=None), | |
| 'sentence2': Value(dtype='string', id=None), | |
| 'label': ClassLabel(num_classes=2, names=['not_equivalent', 'equivalent'], names_file=None, id=None), | |
| 'idx': Value(dtype='int32', id=None)} | |
| ``` | |
| در پشت صحنه، `label` از نوع `ClassLabel` میباشد، و نگاشت اعداد صحیح به نام برچسب در پوشه *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` میباشد. | |
| > [!TIP] | |
| > ✏️ **امتحان کنید!** عنصر شماره ۱۵ از مجموعه `training` و عنصر شماره ۸۷ از مجموعه `validation` را مشاهده کنید. برچسبهای آنها چیست؟ | |
| ### پیشپردازش دیتاسِتها | |
| {#if fw === 'pt'} | |
| {:else} | |
| {/if} | |
| به منظور پیشپردازش دیتاسِت، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام میشود. ما میتوانیم یک یا چند جمله را به توکِنایزر بدهیم، در نتیجه میتوانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِن کنیم: | |
| ```py | |
| from transformers import AutoTokenizer | |
| checkpoint = "bert-base-uncased" | |
| tokenizer = AutoTokenizer.from_pretrained(checkpoint) | |
| tokenized_sentences_1 = tokenizer(raw_datasets["train"]["sentence1"]) | |
| tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"]) | |
| ``` | |
| با این حال، نمیتوانیم دو جمله را به مدل ارسال کنیم تا پیشبینی کند که متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم و پیشپردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکِنایزر میتواند یک جفت رشته را دریافت کند و آنرا به گونهای که مدل BERT ما انتظار دارد آمادهسازی کند: | |
| ```py | |
| inputs = tokenizer("This is the first sentence.", "This is the second one.") | |
| inputs | |
| ``` | |
| ```python out | |
| { | |
| 'input_ids': [101, 2023, 2003, 1996, 2034, 6251, 1012, 102, 2023, 2003, 1996, 2117, 2028, 1012, 102], | |
| 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], | |
| 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] | |
| } | |
| ``` | |
| در [فصل ۲](/course/chapter2) در مورد کلیدهای `input_ids` و `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل میگوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. | |
| > [!TIP] | |
| > ✏️ **امتحان کنید!** عنصر شماره ۱۵ از مجموعه `training` را بردارید و دو جمله را به صورت جداگانه و جفت توکِن کنید. تفاوت دو نتیجه چیست؟ | |
| اگر شناسههای داخل `input_ids` را به کلمات کدگشایی کنیم: | |
| ```py | |
| tokenizer.convert_ids_to_tokens(inputs["input_ids"]) | |
| ``` | |
| خواهیم داشت: | |
| ```python out | |
| ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] | |
| ``` | |
| بنابراین میبینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودیها به صورت `[CLS] sentence1 [SEP] sentence2 [SEP]` باشند. | |
| ```python out | |
| ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] | |
| [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] | |
| ``` | |
| همانطور که میبینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` هستند اندیس نشان دهنده نوع توکِن آنها `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند اندیس نشان دهنده نوع توکِنشان `1` میباشد. | |
| توجه داشته باشید که اگر نقطه تعلیم متفاوتی را انتخاب کنید، در ورودیها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده میشوند که مدل میداند با آنها چکار کند، به این خاطر که آنها را در زمان پیشتعلیم دیده است. | |
| در اینجا، مدل BERT با شناسههایی که نشان دهنده نوع توکِن هستند از پیش تعلیم دیده و علاوه بر هدف تکمیل جاهای خالی متن که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه دیگری تحت عنوان _پیشبینی جمله بعدی_ بر عهده دارد. هدف از این وظیفه مدل کردن رابطه بین جملات جفتی میباشد. | |
| در پیشبینی جمله بعدی، لیستی از جملههای جفت شده (با کلماتی که به طور تصادفی پنهان شدهاند) به مدل داده میشوند و از مدل خواسته میشود پیشبینی کند که آیا جمله دوم در ادامه جمله اول قرار دارد یا خیر. برای سختتر کردن مسئله، در نیمی از حالتها دو جمله در متن اصلی به دنبال هم آمده، و در نیمی دیگر از دو متن متفاوت میآیند. | |
| در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودیهای توکِن شده خود باشید: مادامی که از نقطه تعلیم یکسان برای توکِنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکِنایزر میداند چه چیزی برای مدل فراهم کند. | |
| اکنون که مشاهده کردیم چگونه توکِن کننده ما میتواند با دو جمله برخورد کند، میتوانیم آن را برای توکِن کردن کل دیتاسِتمان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما میتوانیم توکِنایزر را با لیستی از جفت جملهها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینههای `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیشپردازش دیتاسِت `training` اینگونه میباشد: | |
| ```py | |
| tokenized_dataset = tokenizer( | |
| raw_datasets["train"]["sentence1"], | |
| raw_datasets["train"]["sentence2"], | |
| padding=True, | |
| truncation=True, | |
| ) | |
| ``` | |
| این روش به خوبی کار میکند، اما مشکلاش این است که دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids` و مقادیر آنها که لیستهایی از لیستها هستند) برمیگرداند. همچنین این روش فقط زمانی کار میکند که حافظه موقت کافی جهت ذخیرهسازی کل دیتاسِت در حین توکِن کردن داشته باشید (در حالی که دیتاسِتهای موجود در کتابخانه `Datatasets` از هاگینگفِیس فایلهایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شدهاند، بنابراین شما فقط نمونههایی را که جهت ذخیره در حافظه درخواست کردهاید نگه میدارید). | |
| به منظور نگه داشتن داده به صورت یک دیتاسِت، از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیشپردازشهای بیشتری علاوه بر توکِن کردن نیاز داشته باشیم این روش انعطافپذیری لازم را به ما میدهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودیها را توکِن کند: | |
| ```py | |
| def tokenize_function(example): | |
| return tokenizer(example["sentence1"], example["sentence2"], truncation=True) | |
| ``` | |
| این تابع دیکشنری (مثل اقلام داخل دیتاسِت) دریافت میکند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمیگرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیستهایی از دو جملهها کار میکند، همانطور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان لیستی از جملهها) باشد کار میکند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکِنایزر را به میزان زیادی سریعتر خواهد کرد. این `tokenizer` با توکِنایزری در کتابخانه [Tokenizers](https://github.com/huggingface/tokenizers) از هاگینگفِیس که به زبان برنامهنویسی Rust نوشته شده پشتیبانی میشود. این توکِنایزر میتواند بسیار سریع باشد، اما فقط به شرطی که ورودیهای زیادی را به صورت یک جا به آن بدهیم. | |
| توجه داشته باشید که ما آرگومان همطولسازی را در تابع توکِن کنندهمان نادیده گرفتهایم. این به این خاطر است که همطولسازی روی همه نمونهها برای بیشترین طول به صرفه نیست: بهتر است که نمونهها را زمانی که در حال ساختن بَتچ هستیم همطول کنیم، در این صورت فقط نیاز داریم نمونهها را به اندازه بزرگترین طول همان بَتچ و نه بیشترین طول در سرتاسر دیتاسِت همطول کنیم. این روش زمانی که ورودیها دارای طولهای بسیار متغیری هستند وقت و انرژی زیادی را صرفهجویی خواهد کرد. | |
| در اینجا نشان میدهیم چگونه تابع تولید توکِن را روی کل دیتاسِت به یکباره اعمال میکنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده میکنیم بنابر این تابع ما به جای اینکه روی هر عنصر به صورت جداگانه عمل کند روی چندین عنصر از دیتاسِت به یکباره عمل میکند. این کار اجازه میدهد که پیشپردازش سریعتر انجام گیرد: | |
| ```py | |
| tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) | |
| tokenized_datasets | |
| ``` | |
| کتابخانه `Datasets` از هاگینگفِیس این پیشپردازش را با افزودن -فیلدهای- جدید به دیتاسِتها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیشپردازش بازگردانده میشوند، اعمال میکند: | |
| ```python out | |
| DatasetDict({ | |
| train: Dataset({ | |
| features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'], | |
| num_rows: 3668 | |
| }) | |
| validation: Dataset({ | |
| features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'], | |
| num_rows: 408 | |
| }) | |
| test: Dataset({ | |
| features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'], | |
| num_rows: 1725 | |
| }) | |
| }) | |
| ``` | |
| شما حتی میتوانید زمانی که تابع پیشپردازش خود را اعمال میکنید، با ارسال آرگومان `num_proc` در تابع `map()` از چندپردازشی استفاده کنید. در اینجا ما این کار را انجام ندادیم چرا که کتابخانه `Tokenizers` هاگینگفِیس از پیش، از چندین رشته پردازشی برای توکِن کردن سریعتر نمونههای ما استفاده میکند، اما اگر شما از یک توکِنایزر سریع که با این کتابخانه پشتیبانی شود استفاده نمیکنید، این روش میتواند پیشپردازش شما را سریعتر کند. | |
| تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمیگرداند به گونهای که این کلیدها به صورت سه فیلد جدید به همه بخشهای دیتاسِت افزوده گردند. توجه داشته باشید اگر تابع پیشپردازش ما برای یک کلید موجود در دیتاسِت مقدار جدیدی بازمیگرداند ما میتوانستیم فیلدهای موجود در دیتاسِتی که تابع `map()` به آن اعمال میشود را نیز تغییر دهیم. | |
| آخرین کاری که باید انجام دهیم این است که هنگامی که عناصر را با هم در یک بَتچ قرار میدهیم، طول همه عناصر را به اندازه بلندترین عنصر برسانیم - تکنیکی که ما به آن *همطولسازی پویا* میگوییم. | |
| ### همطولسازی پویا | |
| {#if fw === 'pt'} | |
| تابعی که مسئول کنار هم گذاشتن نمونهها در یک بَتچ میباشد *تابع ترکیب کننده* خوانده میشود. شما میتوانید این تابع را که در حالت پیش فرض نمونههای شما را به تِنسور پایتورچ تبدیل کرده و به هم الحاق میکند (اگر عناصر شما لیست، تاپِل یا دیکشنری باشند این کار به صورت بازگشتی انجام میگیرد) هنگام ساختن `DataLoader` به داخل آن ارسال کنید. از آنجایی که ورودیهای ما همطول نخواهند بود استفاده از این تابع برای ما امکانپذیر نیست. ناهمطولی ورودیها به این خاطر است که ما فرایند همطولسازی را عمدا به تعویق انداختیم تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودیهای بیش از اندازه طولانی با مقدار زیادی همطولسازی پیشگیری کنیم. این روش، فرایند تعلیم را تا اندازهای سرعت میبخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار میتواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح میدهد، حتی اگر نیاز به همطولسازی اضافه داشته باشد. | |
| {:else} | |
| تابعی که مسئول کنار هم گذاشتن نمونهها در یک بَتچ میباشد *تابع ترکیب کننده* خوانده میشود. تابع ترکیب کننده پیشفرض تابعی است که فقط نمونههای شما را به `tf.Tensor` تبدیل کرده و آنها را به هم الحاق میکند (اگر عناصر شما لیست، تاپِل یا دیکشنری باشند این کار به صورت بازگشتی انجام میگیرد). از آنجایی که ورودیهای ما همطول نخواهند بود استفاده از این تابع برای ما امکان پذیر نیست. ناهمطولی ورودیها به این خاطر است که ما فرایند همطولسازی را عمدا به تعویق انداختیم تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودیهای بیش از اندازه طولانی با مقدار زیادی همطولسازی پیشگیری کنیم. این روش، فرایند تعلیم را تا اندازهای سرعت میبخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار میتواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح میدهد، حتی اگر نیاز به همطولسازی اضافه داشته باشد. | |
| {/if} | |
| برای انجام این کار در عمل، ما باید یک تابع ترکیب کننده تعریف کنیم که میزان درستی از همطولسازی را به آیتمهای دیتاسِتهایی که ما میخواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگفِیس چنین قابلیتی را توسط کلاس `DataCollatorWithPadding` به ما میدهد. به محض این که شیءای از این کلاس را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای همطولسازی استفاده کند و مدل انتظار همطولسازی از سمت چپ یا راست ورودیها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام میدهد: | |
| {#if fw === 'pt'} | |
| ```py | |
| from transformers import DataCollatorWithPadding | |
| data_collator = DataCollatorWithPadding(tokenizer=tokenizer) | |
| ``` | |
| {:else} | |
| ```py | |
| from transformers import DataCollatorWithPadding | |
| data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf") | |
| ``` | |
| {/if} | |
| اجازه دهید چند نمونه از مجموعه `training` را که میخواهیم باهم در یک بَتچ قرار دهیم برداریم تا این ابزار جدید را امتحان کنیم. در اینجا ستونهای `idx`، `sentence1` و `sentence2` را حذف میکنیم چرا که احتیاج نخواهند شد و شامل رشتههای متنی میشوند (که ما نمیتوانیم تنسورهایی از رشتههای متنی ایجاد کنیم) و سپس نگاهی میاندازیم به طول هر ورودی در هر بَتچ: | |
| ```py | |
| samples = tokenized_datasets["train"][:8] | |
| samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "sentence2"]} | |
| [len(x) for x in samples["input_ids"]] | |
| ``` | |
| ```python out | |
| [50, 59, 47, 67, 59, 50, 62, 32] | |
| ``` | |
| تعجبی ندارد که نمونههایی با طولهای متغییر، از ۳۲ تا ۶۷ بدست میآوریم. همطولسازی پویا به این معنی است که نمونههای موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ میباشد، همطول شده باشند. بدون همطولسازی پویا، همه نمونهها در کل دیتاسِت باید به اندازه بزرگترین طول یا بزرگترین طول قابل پذیرش برای مدل، همطول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی همطول میکند: | |
| ```py | |
| batch = data_collator(samples) | |
| {k: v.shape for k, v in batch.items()} | |
| ``` | |
| {#if fw === 'tf'} | |
| ```python out | |
| {'attention_mask': TensorShape([8, 67]), | |
| 'input_ids': TensorShape([8, 67]), | |
| 'token_type_ids': TensorShape([8, 67]), | |
| 'labels': TensorShape([8])} | |
| ``` | |
| {:else} | |
| ```python out | |
| {'attention_mask': torch.Size([8, 67]), | |
| 'input_ids': torch.Size([8, 67]), | |
| 'token_type_ids': torch.Size([8, 67]), | |
| 'labels': torch.Size([8])} | |
| ``` | |
| به نظر خوب میآید! اکنون که از متن خالص به بَتچهایی رسیدهایم که مدلمان میتواند با آنها کار کند، آماده کوک کردن مدل هستیم: | |
| {/if} | |
| > [!TIP] | |
| > ✏️ **امتحان کنید!** پروسه پیشپردازش را روی دیتاسِت GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای دو جملهها شامل تک جملهها میباشد این کار کمی متفاوت است، اما بقیه کارهایی که انجام دادهایم باید یکسان به نظر برسند. برای یک چالش مشکلتر، سعی کنید تابع پیشپردازشی بنویسید که برای همه مسئلههای GLUE کار کند. | |
| {#if fw === 'tf'} | |
| اکنون که دیتاسِتمان و یک `collator` داده در اختیار داریم، نیاز داریم که آنها را باهم بکار ببریم. ما میتوانستیم بَتچها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی میبرد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، تابعی ساده وجود دارد که راه حل بهینهای برای این مسئله ارائه میکند: `to_tf_dataset()`. این تابع یک `tf.data.Dataset` شامل پارامتری اختیاری برای تابع `collation` را دور دیتاسِتتان میپیچد. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس میتواند برای `model.fit()` استفاده کند، در نتیجه همین یک تابع میتواند یک دیتاسِت هاگینگفِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دیتاسِتمان مشاهده کنیم! | |
| ```py | |
| tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( | |
| columns=["attention_mask", "input_ids", "token_type_ids"], | |
| label_cols=["labels"], | |
| shuffle=True, | |
| collate_fn=data_collator, | |
| batch_size=8, | |
| ) | |
| tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( | |
| columns=["attention_mask", "input_ids", "token_type_ids"], | |
| label_cols=["labels"], | |
| shuffle=False, | |
| collate_fn=data_collator, | |
| batch_size=8, | |
| ) | |
| ``` | |
| این هم از این! حالا میتوانیم این دیتاسِتها را به درس بعدی ببریم، جایی که تعلیم پس از همه سختیهای پیشپردازش به طرز خوشایندی سرراست خواهد بود. | |
| {/if} | |
| [^1]: Microsoft Research Paraphrase Corpus | |
| ### کوک کردن مدلها با استفاده از API `Trainer` | |
| https://huggingface.co/learn/course/fa/chapter3/3.md | |
| # کوک کردن مدلها با استفاده از API `Trainer` | |
| ترنسفورمرهای هاگینگفِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیدهای که روی داده شما ارائه میدهد به کار میرود. به محض اینکه همه کارهای پیشپردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقیمانده تا تعریف `Trainer` دارید. سخت ترین قسمت، احتمالا آمادهسازی محیط جهت اجراي `Trainer.train()` میباشد، چرا که این تابع روی CPU بسیار کند اجرا میشود. اگر GPU ندارید، میتوانید از GPU یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. | |
| نمونه کدهای زیر فرض میکنند که شما مثالهای بخش قبل را از پیش اجرا کردهاید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: | |
| ```py | |
| 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` استفاده خواهد کرد. تنها آرگومانی که شما باید ارائه کنید آدرسی است که مدل تعلیم دیده به همراه نقاط تعلیم در آن ذخیره خواهند شد. بقیه پارامترها را میتوانید به حالت پیشفرض رها کنید، که برای کوک کردن پایه به خوبی کار خواهد کرد. | |
| ```py | |
| from transformers import TrainingArguments | |
| training_args = TrainingArguments("test-trainer") | |
| ``` | |
| > [!TIP] | |
| > 💡 اگر مایلید مدلتان را به صورت خودکار در حین تعلیم در هاب بارگذاری کنید، پارامتر `push_to_hub=True` را در `TrainingArguments` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این باره بیشتر خواهیم آموخت. | |
| مرحله دوم تعریف مدلمان میباشد. مانند [فصل قبل](/course/chapter2)، از کلاس `AutoModelForSequenceClassification` با دو برچسب کلاس استفاده خواهیم کرد: | |
| ```py | |
| from transformers import AutoModelForSequenceClassification | |
| model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) | |
| ``` | |
| شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش تعلیم دیده یک هشدار دریافت میکنید. این به این خاطر است که BERT برای دستهبندی دو جملهها از پیش تعلیم ندیده است، بنابراین لایه سَر مدل از پیش تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشتهها به جای آن قرار گرفته است. هشدارها نشان میدهند که برخی از وزنهای مدل استفاده نشدهاند (آنهایی که مربوط به لایه سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار دهی شدهاند (آنهایی که مربوط به لایه سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل میکند، که دقیقا همان کاری است که میخواهیم اکنون انجام دهیم. | |
| به محض اینکه مدلمان مشخص شد میتوانیم `Trainer` را با ارسال همه اشیائی که تا کنون ساخته شدهاند - `model`، `training_args`، دیتاسِتهای `training` و `validation`، `data_collator` و `tokenizer` به داخل آن تعریف کنیم: | |
| ```py | |
| 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`مان را صدا بزنیم: | |
| ```py | |
| trainer.train() | |
| ``` | |
| این کار، کوک کردن را شروع میکند (که باید چند دقیقه روی GPU طول بکشد) و هزینه تعلیم را هر ۵۰۰ مرحله یکبار گزارش میکند. با این حال به شما نمیگوید که مدلتان چقدر خوب (یا بد) عمل میکند. این به این خاطر است که: | |
| ۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازهگیری کند. کاری که میتوانستیم با مقداردهی پارامتر `evaluation_strategy` به `"steps"` (برای ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر epoch) انجام دهیم. | |
| ۲. ما تابع `compute_metrics()` را برای `Trainer` فراهم نکردیم تا بتواند معیارها را در حین اصطلاحا ارزیابی محاسبه کند (که در غیر این صورت، ارزیابی فقط هزینه را چاپ میکند که عدد چندان گویایی هم نیست) . | |
| ### ارزیابی | |
| اجازه دهید ببینیم چگونه میتوانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids`) و یک دیکشنری باز گرداند که رشتههای متنی را به اعداد حقیقی تبدیل میکند (رشتههای متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). برای استخراج چند پیشبینی از مدلمان، میتوانیم از دستور `Trainer.predict()` استفاده کنیم: | |
| ```py | |
| predictions = trainer.predict(tokenized_datasets["validation"]) | |
| print(predictions.predictions.shape, predictions.label_ids.shape) | |
| ``` | |
| ```python out | |
| (408, 2) (408,) | |
| ``` | |
| خروجی تابع `predict()` تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` میباشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (پیشبینی، در مجموع و به طور میانگین، چقدر طول کشیده) میباشد. به محض این که تابع `compute_metrics()` را کامل کرده و آن را به `Trainer` ارسال کنیم، آن فیلد متریکهای بازگشتی از `compute_metrics()` را نیز در بر خواهد داشت. | |
| همانطور که میبینید، `predictions` آرایهای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده ما میباشد). این ها logits مربوط به هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدلهای ترَنسفورمِر logits را باز میگردانند). برای تبدیل logits به پیشبینیهایی که بتوانیم با برچسبهایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی بعد دوم را برداریم: | |
| ```py | |
| import numpy as np | |
| preds = np.argmax(predictions.predictions, axis=-1) | |
| ``` | |
| اکنون میتوانیم `preds` را با برچسبها مقایسه کنیم. برای ساختن تابع `compute_metric()`، به متریکهای کتابخانه دادههای هاگینگفِیس تکیه خواهیم کرد. ما میتوانیم متریکهای وابسته به دیتاسِت MRPC را به راحتی خود دیتاسِت، اما این بار با استفاده از تابع `load_metric()`، بارگذاری کنیم. شیء بازگردانده شده تابعی به نام `compute()` دارد که میتوانیم برای محاسبه متریک از آن استفاده کنیم: | |
| ```py | |
| from datasets import load_metric | |
| metric = load_metric("glue", "mrpc") | |
| metric.compute(predictions=preds, references=predictions.label_ids) | |
| ``` | |
| ```python out | |
| {'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} | |
| ``` | |
| از آنجایی که مقداردهی تصادفی اولیه مدل میتواند متریکهای نهایی را تغییر دهد، نتایج دقیقی که شما بدست میآورید ممکن است متفاوت باشد. در اینجا میتوانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست میآورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، برای مدل پایه، `F1 Score` معادل ۸۸.۹ را گزارش میکند. توجه داشته باشید که آن مدل `uncased` بود، حال آن که در اینجا ما از مدل `cased` استفاده میکنیم، که دستیابی به نتایج بهتر را توضیح میدهد. | |
| اکنون با قرار دادن همه چیز کنارهم تابع `compute_metrics()` را بدست خواهیم آورد: | |
| ```py | |
| 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 مشاهده کنیم: | |
| ```py | |
| 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 میباشد. در [فصل ۷](/course/chapter7) مثالی برای نشان دادن چگونگی انجام این کار برای معمولترین مسئلههای NLP ارائه خواهیم کرد، اما اکنون اجازه دهید ببینیم چگونه همین کار را صرفا با استفاده از PyTorch انجام دهیم. | |
| > [!TIP] | |
| > ✏️ **اتحان کنید!** با استفاده از پردازش دادهای که در بخش ۲ انجام دادید، مدلی را روی دیتاسِت GLUE SST-2 کوک کنید. | |
| ### کوک کردن مدلها با استفاده از کِراس | |
| https://huggingface.co/learn/course/fa/chapter3/3_tf.md | |
| # کوک کردن مدلها با استفاده از کِراس | |
| زمانی که همه کارهای پیشپردازش در بخش قبل را انجام دادید، فقط چند مرحله باقیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، میتوانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. | |
| نمونه کدهای زیر فرض میکنند که شما مثالهای بخش قبل را از پیش اجرا کردهاید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: | |
| ```py | |
| from datasets import load_dataset | |
| from transformers import AutoTokenizer, DataCollatorWithPadding | |
| import numpy as np | |
| 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, return_tensors="tf") | |
| tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( | |
| columns=["attention_mask", "input_ids", "token_type_ids"], | |
| label_cols=["labels"], | |
| shuffle=True, | |
| collate_fn=data_collator, | |
| batch_size=8, | |
| ) | |
| tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( | |
| columns=["attention_mask", "input_ids", "token_type_ids"], | |
| label_cols=["labels"], | |
| shuffle=False, | |
| collate_fn=data_collator, | |
| batch_size=8, | |
| ) | |
| ``` | |
| ### تعلیم | |
| مدلهای تِنسورفِلو که از ترَنسفورمِرهای هاگینگفِیس وارد شدهاند از پیش مدلهای کِراس هستند. این هم مقدمهای کوتاه به کِراس. | |
| این به این معنی است که به محض اینکه دادهمان را در اختیار بگیریم، کار بسیار کمی لازم است تا تعلیم را روی آن شروع کنیم. | |
| مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب دسته استفاده خواهیم کرد: | |
| ```py | |
| from transformers import TFAutoModelForSequenceClassification | |
| model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) | |
| ``` | |
| شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش تعلیم دیده یک هشدار دریافت میکنید. این به این خاطر است که BERT برای دستهبندی دو جملهها از پیش تعلیم ندیده است، بنابراین لایه سَر مدل از پیش تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشتهها به جای آن قرار گرفته است. هشدارها نشان میدهند که برخی از وزنهای مدل استفاده نشدهاند (آنهایی که مربوط به لایه سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار دهی شدهاند (آنهایی که مربوط به لایه سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل میکند، که دقیقا همان کاری است که میخواهیم اکنون انجام دهیم. | |
| برای کوک کردن مدل روی دِیتاسِتمان، ما فقط باید مدل را `compile()` کنیم و سپس دادهمان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک کردن را شروع میکند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه `training` و هزینه `validation` را در انتهای هر epoch گزارش میدهد. | |
| > [!TIP] | |
| > توجه داشته باشید که مدلهای ترَنسفورمِر هاگینگفِیس قابلیت ویژهای دارند که بسیاری از مدلهای کِراس ندارند - آنها میتوانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه میکنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیشفرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب دستههای خودتان را به عنوان بخشی از ورودی، نه به صورت یک برچسب دسته مجزا که روش معمول استفاده از برچسب دستهها در مدلهای کِراس میباشد، ارسال کنید. شما مثالهایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینهی درست میتواند تا اندازهای پیچیده باشد. به هر حال، برای دستهبندی رشتهها، یک تابع هزینه استانداد کِراس به خوبی کار میکند، چیزی که ما در اینجا استفاده خواهیم کرد. | |
| ```py | |
| from tensorflow.keras.losses import SparseCategoricalCrossentropy | |
| model.compile( | |
| optimizer="adam", | |
| loss=SparseCategoricalCrossentropy(from_logits=True), | |
| metrics=["accuracy"], | |
| ) | |
| model.fit( | |
| tf_train_dataset, | |
| validation_data=tf_validation_dataset, | |
| ) | |
| ``` | |
| > [!WARNING] | |
| > در اینجا توجه شما را به یک مسئله عام جلب میکنیم - شما *میتوانید* فقط نام تابع هزینه را به صورت یک متغیر متنی برای کِراس ارسال کنید، اما کِراس به صورت پیشفرض فکر میکند شما یک لایه softmax از پیش به خروجیتان اعمال کردهاید. با این حال، بسیاری از مدلها مقادیر را درست قبل از اینکه softmax به آنها اعمال شود به خروجی میدهند، که همچنین به عنوان *logits* شناخته میشوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدلمان انجام میدهد و تنها راه گفتن آن این است که به جای ارسال نام تابع هزینه به صورت متغیر متنی، آن را به صورت مستقیم صدا بزنیم. | |
| ### بهبود کارایی تعلیم | |
| اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش مییابد. علت اصلی این امر *نرخ یادگیری* میباشد. مانند تابع هزینه، وقتی که ما نام بهینهساز را به صورت یک متغیر متنی به کِراس ارسال میکنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیشفرض مقداردهی اولیه میکند. به تجربه طولانی، ما میدانیم که مدلهای ترَنسفورمِر از نرخهای یادگیری بسیار کوچکتر بهره بیشتری میبرند تا مقدار پیشفرض برای بهینهساز Adam، که ۱e-۳ میباشد و به صورت ۱۰ به توان -۳ یا ۰،۰۰۱ نیز نوشته میشود. | |
| علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما میتوانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپُختی* یاد میشود. بهترین روش برای انجام این کار در کِراس استفاده از زمانبند نرخ یادگیری است. یک زمانبند خوب برای استفاده، زمانبند `PolynomialDecay` میباشد - این زمانبند برخلاف نامش نرخ یادگیری را در حالت پیشفرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش میدهد که دقیقا همان چیزی است که ما میخواهیم. به منظور استفاده درست از زمانبند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه میکنیم. | |
| ```py | |
| 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. Note that the tf_train_dataset here is a batched tf.data.Dataset, | |
| # not the original Hugging Face Dataset, so its len() is already num_samples // batch_size. | |
| num_train_steps = len(tf_train_dataset) * num_epochs | |
| lr_scheduler = PolynomialDecay( | |
| initial_learning_rate=5e-5, end_learning_rate=0.0, decay_steps=num_train_steps | |
| ) | |
| from tensorflow.keras.optimizers import Adam | |
| opt = Adam(learning_rate=lr_scheduler) | |
| ``` | |
| > [!TIP] | |
| > کتابخانه ترنسفورمرهای هاگینگفِیس همچنین یک تابع `create_optimizer()` دارد که بهینهسازی از نوع `AdamW`، دارای میزان کاهش نرخ یادگیری میسازد. این یک میانبر مناسب است که آن را با جزئیات در بخشهای بعدی این آموزش خواهید دید. | |
| اکنون بهینهساز کاملا جدیدمان را در اختیار داریم و میتوانیم آن را تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شدهاند را به حالت اولیه بازگردانیم، سپس میتوانیم مدل را با بهینه ساز جدید تدوین کنیم: | |
| ```py | |
| 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, metrics=["accuracy"]) | |
| ``` | |
| حالا دوباره مدل را فیت میکنیم: | |
| ```py | |
| model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) | |
| ``` | |
| > [!TIP] | |
| > 💡 اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، میتوانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. | |
| ### پیشبینیهای مدل | |
| تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیدهمان، چه برای محاسبه برخی معیارها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ برای این منظور میتوانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر کلاس یک *logits* از لایه سَر خروجی مدل باز میگرداند. | |
| ```py | |
| preds = model.predict(tf_validation_dataset)["logits"] | |
| ``` | |
| سپس میتوانیم `logits` را با استفاده از `argmax` برای یافتن بزرگترین `logit`، که نماینده محتملترین دسته میباشد، به پیشبینیهای دسته مدل تبدیل کنیم: | |
| ```py | |
| class_preds = np.argmax(preds, axis=1) | |
| print(preds.shape, class_preds.shape) | |
| ``` | |
| ```python out | |
| (408, 2) (408,) | |
| ``` | |
| اکنون، اجازه دهید از `preds` برای محاسبه برخی معیارها استفاده کنیم! ما میتوانیم معیارهای مرتبط با دیتاسِت MRPC را، به همان آسانی که دیتاسِت را بارگذاری کردیم، بارگذاری کنیم اما این بار با استفاده از تابع `load_metric()`. شیء باز گردانده شده تابعی به نام `compute()` دارد که میتوانیم برای محاسبه معیارها از آن استفاده کنیم: | |
| ```py | |
| from datasets import load_metric | |
| metric = load_metric("glue", "mrpc") | |
| metric.compute(predictions=class_preds, references=raw_datasets["validation"]["label"]) | |
| ``` | |
| ```python out | |
| {'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} | |
| ``` | |
| از آنجایی که مقداردهی اولیه تصادفی در لایه سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما میتوانند متفاوت باشند. در اینجا میبینیم که مدل ما دقتی معادل ۸۵.۷۸٪ و F1 score معادل ۸۹.۹۷٪ روی مجموعه `validation` دارد. اینها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفتهاند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با ۸۸.۹ برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده میکنیم، که نتایج بهتر را توجیح میکند. | |
| به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان میرسد. در فصل ۷ یک مثال از انجام این کار برای معمولترین مسئلههای `NLP` ارائه خواهد شد. اگر مایلید مهارتهای خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`، با استفاده از روش پردازش داده که در بخش ۲ انجام دادید، کوک کنید. | |
| ### مقدمه | |
| https://huggingface.co/learn/course/fa/chapter0/1.md | |
| # مقدمه | |
| به دورهی آموزشی هاگینگفیس خوش آمدید! این مقدمه شما را در طی مراحل راهاندازی محیط کار راهنمایی میکند. اگر تازه این دوره را شروع کردهاید، پیشنهاد میکنیم ابتدا نگاهی به [فصل اول](/course/chapter1) بیاندازید و سپس به این بخش بازگشته تا محیط کاری را راهاندازی کنید و بتوانید خودتان کد را اجرا کنید. | |
| همه کتابخانههایی که در این دورهی آموزشی استفاده خواهیم کرد، پکیجهای پایتون هستند. در این بخش میبینیم که چگونه باید محیط کار پایتون را راهاندازی نموده و کتابخانههای مورد نیاز را نصب کنید. | |
| ما دو شیوه راهاندازی محیط کار، یکی استفاده از نوتبوک کولَب و دیگری استفاده از محیط مجازی پایتون را نشان خواهیم داد. میتوانید هرکدام را که میخواهید انتخاب کنید. اگر تازهکارها هستید، توصیه مؤکد داریم که از نوتبوک کولَب استفاده کنید. | |
| توجه کنید که به محیط ویندوز نخواهیم پرداخت. اگر از ویندوز استفاده میکنید توصیه میکنیم از نوتبوکهای کولَب استفاده کنید. اگر از سیستمعامل مک یا یکی از توزیعهای لینوکس استفاده میکنید میتوانید هرکدام از روشهایی که در اینجا ارائه میکنیم را دنبال کنید. | |
| برای طی بخش زیادی از این دوره نیاز به حساب کاربری هاگینگفیس دارید. پیشنهاد میکنیم همین الان [حساب خود را بسازید](https://huggingface.co/join). | |
| استفاده از نوتبوک کولَب گوگل | |
| استفاده از نوتبوک کولَب سادهترین راه شروع است. در مرورگر خود نوتبوکی جدید باز کرده و بلافاصله شروع به کد زدن کنید! | |
| اگر با کولَب آشنایی ندارید پیشنهاد میکنیم از این [راهنما](https://colab.research.google.com/notebooks/intro.ipynb) استفاده کنید. کولَب به شما امکان استفاده از سختافزارهای شتابدهنده مانند GPU یا TPU میدهد و استفاده از آن برای محاسبات سبک رایگان است. | |
| وقتی که با محیط کاربری کولَب آشنا شدید، نوتبوکی جدید بسازید و مراحل راهاندازی را شروع کنید. | |
| قدم اول نصب کتابخانههایی است که در این دوره استفاده خواهیم کرد. برای نصب کتابخانهها از `pip` استفاده میکنیم که پکیجمنیجر پایتون است. در فضای نوتبوک، برای اجرای دستورهای سیستمی، کافی است علامت `!` را به ابتدای خط اضافه کنید. برای نصب کتابخانه ترنسفورمرهای هاگینگفیس این دستور را اجرا کنید: | |
| ``` | |
| !pip install transformers | |
| ``` | |
| برای اطمینان از نصب صحیح این پکیج، آن را ایمپورت کنید: | |
| ``` | |
| import transformers | |
| ``` | |
| این دستور نسخهای بسیار کم حجم از ترنسفورمرهای هاگینگفیس را نصب میکند بدون آنکه فریمورک یادگیری ماشین مشخصی مانند پایتورچ یا تنسورفلو را اضافه کند. با توجه به اینکه ما از بسیاری از قابلیتهای مختلف این کتابخانه استفاده خواهیم کرد، پیشنهاد میکنیم نسخه توسعهی این کتابخانه، که حاوی تمام پکیجهای وابسته برای تقریبا همه مسائل قابل تصور است، را نصب کنید: | |
| ``` | |
| !pip install transformers[sentencepiece] | |
| ``` | |
| اجرای این فرمان کمی بیشتر طول میکشد ولی برای طی بقیه دوره نیازی به نصب پکیج دیگری نخواهید داشت! | |
| استفاده از محیط مجازی پایتون | |
| اگر ترجیح میدهید از یکی از محیطهای مجازی پایتون استفاده کنید، اولین مرحله نصب پایتون روی سیستمتان است. پیشنهاد میکنیم از این [راهنما](https://realpython.com/installing-python/) استفاده کنید. | |
| اگر پایتون را نصب کردید، میتوانید فرمانهای پایتون را در ترمینال اجرا کنید. قبل از اینکه به سراغ مراحل بعدی بروید، با اجرای دستور `python --version` از نصب صحیح پایتون مطمئن شوید. این دستور، نسخهی پایتون نصب شده روی سیستمتان را نمایش میدهد. | |
| زمانی که فرمانهای پایتون را در ترمینال اجرا می کنید، نسخه "اصلی” پایتون روی سیستم خود را درگیر می کنید. توصیه می کنیم این نسخه را تمیز نگه دارید و هیچ پکیج اضافهای روی آن نصب نکنید، بلکه از آن صرفا برای ایجاد محیطهای مجازی دیگر و برای پروژههای مختلف استفاده کنید. با این روش هر پروژه میتواند وابستگیهای مخصوص به خود را داشتهباشد و دیگر نیازی نیست نگران ناسازگاریهای احتمالی میان پکیجهای نصب شده برای پروژههای مختلف باشید. | |
| این کار در پایتون با استفاده از [محیطهای مجازی](https://docs.python.org/3/tutorial/venv.html) انجام میشود. محیط مجازی، پوشه ای قائم به خود روی فایلسیستم است که محتوی نسخهای مشخص از پایتون به همراه تمام پکیجهای مورد استفاده در پروژهای خاص است. ساخت این پوشه با ابزارهای مختلفی امکانپذیر است. ما در اینجا از ابزار رسمی پایتون به نام [`venv`](https://docs.python.org/3/library/venv.html#module-venv) استفاده میکنیم. | |
| ابتدا پوشهای جدید برای پروژه خود ایجاد کنید. برای مثال پوشهای به نام transformers-course زیر پوشهی خانه خودتان در فایلسیستم بسازید: | |
| ``` | |
| mkdir ~/transformers-course | |
| cd ~/transformers-course | |
| ``` | |
| درون این پوشه، با استفاده از ماژول `venv` پایتون، محیط مجازی خود را بسازید: | |
| ``` | |
| python -m venv .env | |
| ``` | |
| حالا میبایست زیر پوشه پروژه شما تنها یک پوشه دیگر به نام .env وجود داشته باشد. | |
| ``` | |
| ls -a | |
| . .. .env | |
| ``` | |
| برای ورود و خروج از محیط مجازی پروژه خود از اسکریپتهای activate و deactivate استفاده کنید: | |
| ``` | |
| \# Activate the virtual environment | |
| source .env/bin/activate | |
| \# Deactivate the virtual environment | |
| deactivate | |
| ``` | |
| با اجرای دستور `which python` از فعال شدن محیط مجازی خود اطمینان حاصل کنید. اگر این دستور به آدرس محیط مجازی جدید اشاره کند، با موفقیت این محیط را فعال کردهاید. | |
| ``` | |
| which python | |
| /home/<user>/transformers-course/.env/bin/python | |
| ``` | |
| نصب وابستگیها | |
| مانند آنچه در بخش استفاده از گوگل کولَب گفتیم، اکنون باید پکیجهای موردنیاز برای ادامه دوره را نصب کنید. میتوانید نسخه توسعهی پکیج ترنسفورمرهای هاگینگفیس را با استفاده از پکیجمنیجر `pip` نصب کنید: | |
| ``` | |
| pip install "transformers[sentencepiece]" | |
| ``` | |
| شما تمام مراحل راهاندازی را طی کرده و آماده شروع دوره هستید! | |
| ### هاب هاگینگفِیس | |
| https://huggingface.co/learn/course/fa/chapter4/1.md | |
| # هاب هاگینگفِیس | |
| [هاب هاگینگفِیس](https://huggingface.co/) –- وبسایت اصلی ما –- پلتفرمی مرکزی است که به همه امکان مشارکت، کشف و استفاده از جدیدترین و بهترین مدلها و دیتاسِتها را میدهد. این هاب طیف گستردهای از مدلها را در خود جای داده، که بالغ بر ۱۰ هزار مورد از آنها در دسترس عموم قرار دارد. در این فصل بر روی مدلها متمرکز شده و در فصل ۵ نیز نگاهی به دیتاسِتها خواهیم داشت. | |
| مدلهای موجود در هاب، محدود به ترنسفورمرهای هاگینگفِیس یا حتی NLP نیستند. از جمله آنها میتوان مدلهایی از قبیل [Flair](https://github.com/flairNLP/flair) و [AllenNLP](https://github.com/allenai/allennlp) برای پردازش زبان طبیعی، [Asteroid](https://github.com/asteroid-team/asteroid) و [pyannote](https://github.com/pyannote/pyannote-audio) برای پردازش گفتار، و [timm](https://github.com/rwightman/pytorch-image-models) را برای پردازش تصویر برشمرد. | |
| هر یک از این مدلها به عنوان مخزن گیت میزبانی میشود که این امر، امکان نسخهبندی و قابلیت تکرارپذیری را فراهم مینماید. به اشتراک گذاشتن مدل در هاب، به معنای باز کردن آن به روی جامعه کاربران و در دسترس قرار دادن آن برای افرادی است که میخواهند به راحتی از آن استفاده کنند؛ در نتیجه، ضرورت اینکه افراد مدل را خودشان به تنهایی تعلیم دهند، برطرف شده و همرسانی و استفاده از آن تسهیل میگردد. | |
| علاوه بر این، اشتراکگذاری مدل روی هاب، به طور خودکار باعث استقرار API برای اجرای آن مدل میشود. از این رو، هر کسی در جامعه کاربران خواهد توانست آزادانه آن را مستقیما در صفحه اختصاصی مدل، با ورودیهای سفارشی خود و ویجتهای مناسب آزمایش نماید. | |
| خبر خوش اینکه به اشتراکگذاری و استفاده از هر مدل با دسترسی عمومی در هاب، کاملا رایگان است! در صورتی هم که تمایل دارید مدلهایی را به صورت خصوصی به اشتراک بگذارید، [طرحهای پرداختی](https://huggingface.co/pricing) موجود هستند. | |
| ویدئوی زیر نحوه گشت و گذار در هاب مدلها را نمایش میدهد. | |
| داشتن حساب کاربری huggingface.co برای پیگیری این بخش ضروریست، زیرا در ادامه مخازن جدیدی را در هاب هاگینگفِیس ایجاد نموده و مدیریت خواهیم کرد: [حساب کاربری خود را بسازید](https://huggingface.co/join). | |
| ### بکارگیری مدلهای از پیش تعلیم دیده | |
| https://huggingface.co/learn/course/fa/chapter4/2.md | |
| # بکارگیری مدلهای از پیش تعلیم دیده | |
| {#if fw === 'pt'} | |
| {:else} | |
| {/if} | |
| هاب مدلها، انتخاب مدل مناسب را ساده میکند؛ به طوری که میتوان با چند خط کد، آن را در هر کتابخانه پاییندستی وابسته استفاده نمود. بیایید نگاهی به نحوه عملی بکارگیری یکی از این مدلها انداخته و ببینیم چگونه میتوانیم در جامعه کاربران مشارکت داشته باشیم. | |
| فرض کنید به دنبال مدلی مبتنی بر زبان فرانسوی هستیم که قادر به پر کردن جاهای خالی متن است. | |
| نقطه تعلیم `camembert-base` را انتخاب میکنیم تا مدل را با آن آزمایش نماییم. برای شروع استفاده از آن، تمام آنچه نیاز داریم شناسه `camembert-base` است! همان گونه که در فصلهای پیشین دیدید، میتوانیم با استفاده از تابع `pipeline()` نمونهای از آن بسازیم: | |
| ```py | |
| from transformers import pipeline | |
| camembert_fill_mask = pipeline("fill-mask", model="camembert-base") | |
| results = camembert_fill_mask("Le camembert est :)") | |
| ``` | |
| ```python out | |
| [ | |
| {'sequence': 'Le camembert est délicieux :)', 'score': 0.49091005325317383, 'token': 7200, 'token_str': 'délicieux'}, | |
| {'sequence': 'Le camembert est excellent :)', 'score': 0.1055697426199913, 'token': 2183, 'token_str': 'excellent'}, | |
| {'sequence': 'Le camembert est succulent :)', 'score': 0.03453313186764717, 'token': 26202, 'token_str': 'succulent'}, | |
| {'sequence': 'Le camembert est meilleur :)', 'score': 0.0330314114689827, 'token': 528, 'token_str': 'meilleur'}, | |
| {'sequence': 'Le camembert est parfait :)', 'score': 0.03007650189101696, 'token': 1654, 'token_str': 'parfait'} | |
| ] | |
| ``` | |
| همان طور که میبینید، بارگذاری مدل در داخل خط تولید بسیار ساده است. تنها چیزی که باید مراقبش باشید این است که نقطه تعلیم انتخاب شده، مناسب مسئلهای باشد که برای حل آن به کار گرفته خواهد شد. برای مثال، در اینجا نقطه تعلیم `camembert-base` را در خط تولید `fill-mask` استفاده میکنیم، که انتخابی کاملا معقول است. اما اگر ما این نقطه تعلیم را در خط تولید `text-classification` به کار بگیریم، نتایج هیچ معنایی نخواهند داشت؛ زیرا سَر مربوط به `camembert-base` برای این نوع مسئله مناسب نیست. توصیه میکنیم برای گزینش نقاط تعلیم مناسب، از قسمت انتخاب مسئله در رابط کاربری هاب هاگینگفِیس استفاده نمایید: | |
| همچنین میتوانید ایجاد نمونه از نقطه تعلیم مد نظر را مستقیما با استفاده از معماری مدل انجام دهید: | |
| {#if fw === 'pt'} | |
| ```py | |
| from transformers import CamembertTokenizer, CamembertForMaskedLM | |
| tokenizer = CamembertTokenizer.from_pretrained("camembert-base") | |
| model = CamembertForMaskedLM.from_pretrained("camembert-base") | |
| ``` | |
| با این حال توصیه میکنیم به جای این کار، از کلاسهایی استفاده کنید که نام آنها با [`Auto*`](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) شروع میشود؛ چرا که طراحی این کلاسهای خودکار به گونهایست که فارغ از هرگونه وابستگی به معماری به کار رفته هستند. در حالی که نمونه کد قبلی، کاربران را محدود به نقاط تعلیم قابل بارگذاری در معماری CamemBERT میکند، استفاده از کلاسهای `Auto*`، تعویض نقاط تعلیم را سادهتر مینماید: | |
| ```py | |
| from transformers import AutoTokenizer, AutoModelForMaskedLM | |
| tokenizer = AutoTokenizer.from_pretrained("camembert-base") | |
| model = AutoModelForMaskedLM.from_pretrained("camembert-base") | |
| ``` | |
| {:else} | |
| ```py | |
| from transformers import CamembertTokenizer, TFCamembertForMaskedLM | |
| tokenizer = CamembertTokenizer.from_pretrained("camembert-base") | |
| model = TFCamembertForMaskedLM.from_pretrained("camembert-base") | |
| ``` | |
| با این حال توصیه میکنیم به جای این کار، از کلاسهایی استفاده کنید که نام آنها با [`TFAuto*`](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) شروع میشود؛ چرا که طراحی این کلاسهای خودکار به گونهایست که فارغ از هرگونه وابستگی به معماری به کار رفته هستند. در حالی که نمونه کد قبلی، کاربران را محدود به نقاط تعلیم قابل بارگذاری در معماری CamemBERT میکند، استفاده از کلاسهای `TFAuto*`، تعویض نقاط تعلیم را سادهتر مینماید: | |
| ```py | |
| from transformers import AutoTokenizer, TFAutoModelForMaskedLM | |
| tokenizer = AutoTokenizer.from_pretrained("camembert-base") | |
| model = TFAutoModelForMaskedLM.from_pretrained("camembert-base") | |
| ``` | |
| {/if} | |
| > [!TIP] | |
| > هنگامی که مدلی از پیش تعلیم دیده را استفاده میکنید، حتما بررسی کنید که این تعلیم چگونه و روی چه دیتاسِتهایی صورت پذیرفته و چه محدودیتها و سوگیریهایی را شامل میشود. تمامی این اطلاعات میبایست در صفحه توضیحات مدل نشان داده شوند. | |
| ### مقدمه | |
| https://huggingface.co/learn/course/fa/chapter1/1.md | |
| # مقدمه | |
| ## به دوره آموزشی هاگینگفِیس خوش آمدید | |
| در این دوره آموزشی، پردازش زبان طبیعی[^1] را با استفاده از کتابخانههای اکوسیستم [هاگینگفِیس](https://huggingface.co/) یعنی [Transformers](https://github.com/huggingface/transformers), [Datasets](https://github.com/huggingface/datasets), [Tokenizers](https://github.com/huggingface/tokenizers), [Accelerate](https://github.com/huggingface/accelerate) و همچنین [هاب هاگینگفِیس](https://huggingface.co/models) میآموزید. این دوره کاملا رایگان و بدون تبلیغات است. | |
| ## در این دوره چه چیزهایی را میآموزیم؟ | |
| دید کلی کوتاه از مباحث این دوره آموزشی: | |
| - از فصل ۱ تا ۴ مقدمهای از مباحث پایهای کتابخانهی ترنسفورمرز هاگینگفِیس ارائه میشود. در پایان این فصل، شما با شیوهی عملکرد مدلهای ترنسفومر آشنا میشوید و میآموزید که چگونه از یک مدل در [هاب هاگینگفِیس](https://huggingface.co/models) استفاده کنید، آن را برای مجموعه داده خود کوک کنید و نتایج خود را در هاب به اشتراک بگذارید. | |
| - در فصلهای ۵ تا ۸، اصول پایهی کتابخانههای Datasets و Tokenizers، پیش از آن که وارد مسائل کلاسیک NLP شویم، آموزش داده میشوند. در پایان این فصول، قادر خواهید بود مسائل متداول NLP را به تنهایی حل کنید. | |
| - فصلهای ۹ تا ۱۲ به مباحث فراتر از NLP و استفاده از مدلهای ترنسفورمر برای حل مسائل پردازش گفتار و بینایی ماشین میپردازند. در طی این مسیر، فرا میگیرید که چگونه مدلی جدید ساخته، نمونه اولیه از آن را عرضه کرده و برای محیط استقرار نرمافزار بهینهاش کنید. در پایان این فصل، آمادهی استفاده از ترنسفورمرهای هاگینگفِیس برای (تقریبا) همه مسائل یادگیری ماشین خواهید بود. | |
| این دوره آموزشی: | |
| - به سطح خوبی از دانش پایتون نیاز دارد. | |
| - بهتر است پس از یک دوره آموزشی آشنایی با یادگیری عمیق، مانند دوره آموزشی یادگیری عمیق عملی برای برنامهنویسها از [fast.ai](https://www.fast.ai/) و یا یکی از دورههای ارائه شده توسط [DeepLearning.AI](https://www.deeplearning.ai/)، دنبال شود. | |
| - نیازمند دانش پیشین [پایتورچ](https://pytorch.org/) یا [تِنسورفِلو](https://www.tensorflow.org/) نیست، با این حال آشنایی با هر کدام از آنها میتواند کمککننده باشد. | |
| پس از اینکه این دوره آموزشی را به پایان رساندید، توصیه میکنیم نگاهی به [دوره آموزشی تخصصی پردازش زبان طبیعی](https://www.coursera.org/specializations/natural-language-processing) که توسط [DeepLearning.AI](https://www.deeplearning.ai/) ارائه شده است، بیاندازید. این دوره، بخش اعظمی از مدلهای سنتی NLP مانند دستهبندیکننده بیز ساده و LSTMها را شامل میشود که شناخت آنها ارزشمند است. | |
| ## ما چه کسانی هستیم؟ | |
| درباره نویسندگان: | |
| **متیو کاریگن**[^2] مهندس یادگیری ماشین در هاگینگفِیس است. او در دوبلین ایرلند زندگی میکند و پیشتر بعنوان مهندس یادگیری ماشین در [Parse.ly](https://www.parse.ly/) مشغول به کار بوده است. او دورهی تحقیقات پسادکترای خود را در کالج ترینیتی دوبلین به پایان رسانده است. به عقیدهی وی هوش جامع مصنوعی[^3] با افزایش مقیاس معماریهای فعلی حاصل نخواهد شد، با این حال او امید بسیاری به جاودانگی انسان در قالب رباتی دارد. | |
| **لیسندره دبوت**[^4] مهندس یادگیری ماشین در هاگینگفِیس است و از ابتدا، بر روی کتابخانهی ترنفسورمرهای هاگینگفِیس کار کرده است. هدف او دسترسپذیر کردن NLP برای همگان با توسعه ابزارهایی با API بسیار ساده است. | |
| **سیلوین گوجر**[^5] مهندس محقق در هاگینگفِیس است و از هستهی تیم مدیریتکنندگان کتابخانهی ترنفسورمرهای هاگینگفِیس محسوب میشود. او قبلتر مهندس محقق در fast.ai بود و [کتاب یادگیری عمیق عملی برای برنامهنویسها](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/) با استفاده از [fast.ai](https://www.fast.ai/) و پایتورچ را با همکاری جرمی هاوارد[^6] نگاشته است. تمرکز اصلی تحقیقات وی بر دسترسپذیرتر کردن یادگیری عمیق است. او برای این کار از طراحی و پیشبرد شیوههایی استفاده میکند که امکان یادگیری سریع با منابع محدود را برای مدلها پدید میآورد. | |
| **مروه نویان**[^7] توسعهی دهنده در هاگینگفِیس است و بر روی توسعهی ابزارها و تولید محتوا برای آنها کار میکند. هدف او دسترسپذیر کردن یادگیری ماشین برای همگان است. | |
| **لوسیله ساولنیر**[^8] مهندس یادگیری ماشین در هاگینگفِیس است و بر روی توسعه و پشتیبانی از ابزارهای متنباز تمرکز دارد. وی همچنین بصورت فعالانهای در بسیاری از پروژهای تحقیقاتی در حوزه پردازش زبان طبیعی، مانند یادگیری مشارکتی و بیگساینس مشارکت دارد. | |
| **لویس تونستال**[^9] مهندس یادگیری ماشین در هاگینگفِیس است. تمرکز اصلی او توسعهی ابزارهای متن باز و دسترسپذیر کردن آنها برای جامعهی گستردهتری از کاربران است. او همچنین از نویسندگان [کتاب انتشارات اُریلی[^10] دربارهی ترنسفورمرها](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/) است. | |
| **لئاندرو ون ورا**[^11] مهندس یادگیری ماشین در تیم متنباز هاگینگفِیس و از نویسندگان [کتاب انتشارات اُریلی دربارهی ترنسفورمرها](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/) است. وی تجربهی چندین سال کار در صنعت را دارد. او با کار در تمام جنبههای یادگیری ماشین، پروژههای متنباز را از مرحلهی تحقیق به استقرار در صنایع میرساند. | |
| آمادهی ورود به این دوره هستید؟ در این فصل شما میآموزید که: | |
| - چگونه میتوان از تابع pipeline() برای حل مسائل NLP مانند تولید متن و دستهبندی استفاده کرد. | |
| - معماری ترنسفورمرها چگونه است. | |
| - چگونه معماریهای مختلف انکودر، دیکودر و انکودر-دیکودر را از یکدیگر تشخصی داد و کاربردهای آنها در چیست. | |
| [^1]: Natural Language Processing (NLP) | |
| [^2]: Matthew Carrigan | |
| [^3]: Artificial General Intelligence (AGI) | |
| [^4]: Lysandre Debut | |
| [^5]: Sylvain Gugger | |
| [^6]: Jeremy Howard | |
| [^7]: Merve Noyan | |
| [^8]: Lucile Saulnier | |
| [^9]: Lewis Tunstall | |
| [^10]: O'Reilly | |
| [^11]: Leandro von Werra | |
| ### پردازش زبان طبیعی | |
| https://huggingface.co/learn/course/fa/chapter1/2.md | |
| # پردازش زبان طبیعی | |
| قبل از اینکه به سراغ مدلهای ترنسفومر برویم، بیایید نگاهی سریع بیاندازیم به اینکه پردازش زبان طبیعی[^1] چیست و چرا برای ما حائز اهمیت است. | |
| ## NLP چیست؟ | |
| NLP زیرشاخهای از زبانشناسی و یادگیری ماشین است که تمرکز آن بر درک همهی جوانب زبان انسانها است. هدف مسائل صرفا درک کلمات بصورت مجزا نیست، بلکه جمله، متن و در مجموع زمینهای است که آن کلمه در آن به کار رفته است. | |
| مسائل متداول NLP بهمراه برخی مثالهای آن را در این لیست میبینید: | |
| - **دستهبندی جملات**: دریافت احساس نظر، تشخیص هرزنامه بودن یک ایمیل، تشخیص اینکه آیا یک جمله از لحاظ دستور زبانی صحیح است یا نه و اینکه آیا دو جمله منطقا به یکدیگر مرتبط هستند یا نه. | |
| - **دستهبندی هر کلمه داخل یک جمله**: تشخیص اجزای مختلف دستور زبان در یک جمله (اسم، فعل، صفت) و یا موجودیتهای نامدار (شخص، موقعیت، سازمان). | |
| - **تولید محتوای متنی**: تکمیل یک پیام با متن تولید شده به صورت خودکار و یا تکمیل متنی که جاهای خالی دارد. | |
| - **استخراج پاسخ از یک متن**: پاسخ به سوالات با استفاده از اطلاعاتی که در متن زمینه ارائه شده است. | |
| - **تولید متن جدید از یک متن ارائه شده**: ترجمهی متون به دیگر زبانها، خلاصهسازی متون. | |
| با این حال NLP صرفا به متون نوشتاری محدود نمیشود و برای چالشهای پیچیدهی بسیاری در مسائل تشخیص گفتار و بینایی ماشین راهحل ارائه میکند. برای نمونه میتوان از تولید متن از یک فایل صوتی و یا تشریح یک تصویر، نام برد. | |
| ## چرا این مبحث چالشبرانگیز است؟ | |
| کامپیوترها اطلاعات را مانند انسان پردازش نمیکنند. برای مثال زمانی که ما جملهای مانند من گرسنه هستم را میخوانیم، به سادگی معنای آن را متوجه میشویم. همچنین زمانی که دو جمله مانند من گرسنه هستم و من ناراحت هستم را میخوانیم، بسادگی میتوانیم تشخیص دهیم که به چه میزان این دو جمله با یکدیگر تشابه دارند. برای مدلهای یادگیری ماشین، چنین مسائلی به مراتب سختتر است. متن باید به شیوهای پردازش شود که به مدل امکان یادگیری از آن را بدهد. و با توجه به اینکه زبان پیچیده است، باید در پیادهسازی این مدلها بسیار دقت کنیم. تحقیقات بسیاری انجام شده است تا نشان دهند چگونه میتوان متن را در کامپیوترها مدل کرد. در فصل بعدی به برخی از این شیوهها نگاهی میاندازیم. | |
| [^1]: Natural Language Processing (NLP) | |
| ### واژهنامه | |
| https://huggingface.co/learn/course/fa/glossary/1.md | |
| # واژهنامه | |
| | معادل در منبع | معادل در ترجمه | | |
| |-----------------------|------------------| | |
| | Transformer | ترنسفورمر | | |
| | PyTorch | پایتورچ | | |
| | TensorFlow | تِنسورفِلو | | |
| | Keras | کِراس | | |
| | Chapter | فصل | | |
| | Section | بخش | | |
| | Model | مدل | | |
| | Pretrained Model(s) | مدل(های) از پیش تعلیم دیده | | |
| | Dataset | دیتاسِت | | |
| | Parameter | پارامتر | | |
| | Train | تعلیم | | |
| | Deploy | مستقر کردن | | |
| | Deployment | استقرار | | |
| | 🤗 | هاگینگفِیس | | |
| | Hugging Face | هاگینگفِیس | | |
| | Hugging Face Hub | هاب هاگینگفِیس | | |
| | Load | بارگذاری | | |
| | Save | ذخیرهسازی | | |
| | Share | به اشتراکگذاری / همرسانی | | |
| | Library | کتابخانه | | |
| | Downstream Library | کتابخانه پاییندستی وابسته | | |
| | Download | دانلود | | |
| | Inference | اجرا؟ | | |
| | Interface | رابط، واسط | | |
| | Class | کلاس | | |
| | Module | ماژول | | |
| | Abstraction | انتزاع انتزاعات | | |
| | Forward Pass | اجرای روی به جلو | | |
| | Tokenizer | توکِنایزر | | |
| | Function | تابع | | |
| | Configuration | تنظیمات | | |
| | Batch | بتچ | | |
| | Model Hub | هاب مدلها | | |
| | Platform | پلتفرم | | |
| | Task | مسئله | | |
| | User Interface | رابط (یا واسط) کاربری | | |
| | Course | دوره آموزشی | | |
| | Community | جامعه کاربران | | |
| | Account | حساب کاربری | | |
| | Working Environment | محیط کار | | |
| | Workspace | فضای کار | | |
| | Setup | راهاندازی | | |
| | Create | ایجاد یا ساختن | | |
| | Code | کد | | |
| | Package | پکیج | | |
| | Python | پایتون | | |
| | Colab Notebook | نوتبوک کولَب | | |
| | Google | گوگل | | |
| | Windows | ویندوز | | |
| | macOS | سیستمعامل مک | | |
| | Distribution | توزیع | | |
| | Linux | لینوکس | | |
| | Workload | محاسبه، محاسبات | | |
| | Package Manager | پکیجمنیجر | | |
| | Command | دستور یا فرمان | | |
| | Feature, as for an app | قابلیت | | |
| | Development | توسعه | | |
| | Versioning | نسخهبندی | | |
| | Reproducibility | قابلیت تکرارپذیری | | |
| | Git | گیت | | |
| | GitHub | گیتهاب | | |
| | Repository | مخزن | | |
| | Dependency | وابسته، وابستگی | | |
| | Website | وبسایت | | |
| | Virtual Environment | محیط مجازی | | |
| | Terminal | ترمینال | | |
| | Incompatibility | ناسازگاری | | |
| | Self-Contained | خودکفا | | |
| | Script | اسکریپت | | |
| | Folder | پوشه | | |
| | Neural Network | شبکه عصبی | | |
| | Text | نوشته | | |
| | Pipeline | خط تولید | | |
| | Word | کلمه | | |
| | Subword | زیرکلمه | | |
| | Punctuation | علائم نگارشی | | |
| | Symbol | علامت، علامتها | | |
| | Token | توکِن | | |
| | Preprocess | پیشپردازش | | |
| | Postprocess | پسپردازش | | |
| | Method, as in code | تابع | | |
| | Checkpoint | نقطه تعلیم | | |
| | Model Card | صفحه توضیحات مدل | | |
| | Sentiment Analysis | تحلیل احساسات | | |
| | Dictionary, as in Python | دیکشنری | | |
| | List, as in code | لیست | | |
| | Tensor | تِنسور | | |
| | Framework | فریمورک | | |
| | Flax | فلَکس | | |
| | NumPy | NumPy | | |
| | Scalar | عددی | | |
| | Vector, as in math | برداری | | |
| | Matrix | ماتریس | | |
| | Instantiate | ساختن (یا ایجاد) نمونه | | |
| | Argument, as in code | آرگومان | | |
| | Key, as in Python dictionary | کلید | | |
| | Row | ردیف | | |
| | Integer | عدد صحیح | | |
| | ID | شناسه | | |
| | Unique ID | شناسه منحصر به فرد | | |
| | Code Snippet | قطعه کد | | |
| | Widget | ویجت | | |
| | Hidden State | وضعیت پنهان | | |
| | Feature, as in model | فیچر | | |
| | High-Dimensional | بُعد بالا | | |
| | Multi-Dimensional | چند بُعدی | | |
| | Vector, as in Python | وِکتور | | |
| | Sequence | رشته | | |
| | Index, as in an array or list | اندیس | | |
| | Project, as in math | بردن | | |
| | Embedding | embedding? | | |
| | Tokenized | توکِنشده | | |
| | Mask Filling | پر کردن جاهای خالی متن | | |
| | Attention Mechanism | مکانیزم توجه | | |
| | Classification | دستهبندی | | |
| | Attribute, as for a class in code | ویژگی | | |
| | Label, as in classification | برچسب دسته | | |
| | Prediction, as in nn model | پیشبینی | | |
| | Bias | سوگیری | | |
| | Logit, as in math and also in Pytorch | لوجیت | | |
| | SoftMax | سافتمکس | | |
| | Loss Function | تابع هزینه | | |
| | Activation Layer | لایه فعالسازی | | |
| | Cross Entropy | آنتروپی متقابل | | |
| | Head, as in model | سَر | | |
| | Weight, as in model | وزن | | |
| | Weights, as in model | وزنها | | |
| | Set, as for variable | تخصیص مقدار | | |
| | Environment Variable | متغیر محیطی | | |
| | Metadata | متادیتا | | |
| | Encode, as in assign numbers to | کد شده، کد گذاری | | |
| | Decode, as in same | کد گشایی | | |
| | Encoder, as in ML | اِنکودر | | |
| | Decoder, as in ML | دیکودر | | |
| | Encrypt | رمزگذاری | | |
| | Decrypt | رمزگشایی | | |
| | Cache | انبار کردن | | |
| | Production Environment | محیط استقرار | | |
| | Classifier | دستهبندیکننده | | |
| | Naive Bayes | بیز ساده | | |
| | Collaborative learning | یادگیری مشارکتی | | |
| | Demo | نمونه اولیه | | |
| | collate | ترکیب کردن | | |
| | mapping | نگاشت | | |
| | element | عنصر | | |
| | tuple | تاپِل | | |
| | object | شیء | | |
| | paraphrases | جملات متناظر | | |
| | benchmark | محک | | |
| | items | اقلام | | |
| | padding | همطولسازی | | |
| | documentation | مستندات | | |
| معادلهایی که استفاده نمیکنیم: | |
| | معادل در منبع | معادل اشتباه در ترجمه | | |
| |-----------------------|------------------| | |
| | Application, as in an app and not as in apply | کاربرد | | |
| | املای مورد استفاده کلمات فارسی | | |
| |-------------------------------| | |
| | ارائه | | |
| کلمات مخفف: | |
| | معادل در منبع | معادل در ترجمه | | |
| |-----------------------|------------------| | |
| | NLP | NLP | | |
| | API | API | | |
| | GPU | GPU | | |
| | TPU | TPU | | |
| | BERT | BERT | | |
| | ML | یادگیری ماشین | | |
| | AGI | هوش جامع مصنوعی | | |
| ### مقدمه | |
| https://huggingface.co/learn/course/fa/chapter2/1.md | |
| # مقدمه | |
| همان طور که در [فصل اول](/course/chapter1) دیدید، مدلهای ترنسفورمر معمولا بسیار بزرگ هستند. با داشتن میلیونها یا حتی دهها میلیارد پارامتر، تعلیم و بکارگیری این مدلها کار بسیار پیچیدهای است. علاوه بر این، تقریبا هر روز مدلهای جدیدی عرضه میشوند که هرکدام شیوه پیادهسازی خود را دارند و امتحان کردن تمام آنها کار آسانی نیست. | |
| کتابخانه ترنسفومرهای هاگینگفِیس برای حل این مشکل تولید شده است. هدف آن، ارائه یک API واحد برای بارگذاری، تعلیم و ذخیرهسازی مدلهای ترنسفورمر است. ویژگی های اصلی این کتابخانه از این قرار است: | |
| - **سهولت استفاده**: دانلود، بارگذاری و استفاده از مدلهای NLP روز دنیا برای تولید نتیجه عملیاتی، فقط با دو خط کد امکانپذیر است. | |
| - **انعطاف**: تمام مدلها در واقع کلاسهای معمولی پایتورچ مانند nn.Module یا کلاسهای تنسورفلو مانند tf.keras.Model هستند و مانند هر مدل دیگری در فریمورک خود در دسترسی قرار دارند. | |
| - **سادگی**: در طراحی کتابخانه انتزاعات بسیار کمی به کار رفته است. اصل خودکفا بودن مدلها بسیار مهم است. اجرای رو به جلوی مدل تماماً در یک فایل تعریف میشود و به این شیوه، کد به سادگی قابل فهم و تغییر است. | |
| این ویژگی آخر باعث میشود ترنسفورمرهای هاگینگفِیس بسیار متفاوت با نمونههای مشابه در کتابخانههای یادگیری ماشین دیگر باشند. مدلها روی ماژولهای متفاوتی که در فایلهای مختلف قرار دارند بنا نشدهاند؛ بلکه هر مدل محتوی لایههای خود است. علاوه بر سادهتر و قابل فهمتر کردن مدلها، این ویژگی به شما اجازه میدهد به راحتی مدل را دستکاری کنید بدون این که بر مدلهای دیگر تاثیر بگذارید. | |
| این فصل با مثالی کامل شروع میشود که در آن مدل و توکِنایزر را با هم استفاده میکنیم تا تابع pipeline() که در فصل اول معرفی کردیم را شبیهسازی کنیم. سپس API مربوط به مدلها را بررسی میکنیم و وارد پیچیدگیهای کلاسهای مدل و کلاسهای تنظیمات میشویم تا نشان دهیم چگونه میتوان مدلها را بارگذاری نمود و این مدلها چطور ورودیهای عددی را پردازش میکنند تا در خروجی پیشبینیها را تولید کنند. | |
| سپس نگاهی به API مربوط به توکِنایزر خواهیم داشت که بخش دیگر پیادهسازی تابع pipeline() است. توکِنایزرها مرحله اول و مرحله آخر پردازش را انجام میدهند که در طی آنها دادههای نوشتاری را به ورودیهای عددی برای شبکه عصبی تبدیل نموده و هنگام نیاز باز دادههای عددی را به نوشتار تبدیل میکنند. در انتها، به شما نشان خواهیم داد چگونه چندین جمله را همزمان در یک بتچ از پیش آماده شده از مدل عبور دهید و سپس فصل را با نگاهی نزدیکتر به تابع بالادستی tokenizer() به اتمام خواهیم برد. | |
| > [!TIP] | |
| > ⚠️ برای بهره بردن از تمامی ویژگیهای موجود در هاب مدلها و همچنین ترنسفورمرهای هاگینگفِیس پیشنهاد میکنیم که حساب کاربری بسازید. | |
| ### پشت صحنه خط تولید | |
| https://huggingface.co/learn/course/fa/chapter2/2.md | |
| # پشت صحنه خط تولید | |
| {#if fw === 'pt'} | |
| {:else} | |
| {/if} | |
| > [!TIP] | |
| > این اولین بخشی است که محتوای آن بسته به اینکه از پایتورچ یا تِنسورفِلو استفاده میکنید کمی متفاوت است. از سویچ بالای صفحه برای انتخاب پلتفرمی که ترجیح میدهید استفاده کنید! | |
| {#if fw === 'pt'} | |
| {:else} | |
| {/if} | |
| بگذارید با یک مثال کامل شروع کنیم. نگاهی میاندازیم به آنچه در پشت صحنه در اثر اجرای این قطعه کد در [فصل اول](/course/chapter1) رخ داد: | |
| ```python | |
| from transformers import pipeline | |
| classifier = pipeline("sentiment-analysis") | |
| classifier( | |
| [ | |
| "I've been waiting for a HuggingFace course my whole life.", | |
| "I hate this so much!", | |
| ] | |
| ) | |
| ``` | |
| این خروجی را دریافت کردیم: | |
| ```python out | |
| [{'label': 'POSITIVE', 'score': 0.9598047137260437}, | |
| {'label': 'NEGATIVE', 'score': 0.9994558095932007}] | |
| ``` | |
| همان طور که در در فصل اول دیدیم، این خط تولید از سه مرحله تشکیل شده است: پیشپردازش، پردازش ورودیها در مدل و پسپردازش. | |
| به صورت خلاصه هرکدام از این مراحل را بررسی میکنیم. | |
| ## پیشپردازش با توکِنایزر | |
| مثل شبکههای عصبی دیگر، مدلهای ترنسفورمر هم نمیتوانند نوشته خام را پردازش کنند. پس اولین قدم در خط تولید ما، تبدیل نوشته خام ورودی به اعدادی است که مدل قادر به فهم آنها باشد. برای این کار از یک *توکِنایزر* استفاده میکنیم، که مسئولیتهای زیر را بر عهده دارد: | |
| - شکستن نوشته به کلمات، زیرکلمات و علامتها (مانند علائم نگارشی) که به آنها *توکِن* میگوییم. | |
| - انتخاب عدد صحیح معادل برای هر توکِن. | |
| - اضافهکردن ورودیهای دیگری که ممکن است برای مدل مفید باشند. | |
| همه مراحل این پیشپردازش باید دقیقا همان طور که قبلا هنگام تعلیم مدل انجام شده، دنبال شوند. این اطلاعات در [هاب مدلها](https://huggingface.co/models) موجود است و توسط تابع `from_pretrained()` از کلاس `AutoTokenizer` دانلود میشود. با استفاده از نام کامل مدل که شامل نقطه تعلیم است، این تابع به صورت خودکار دادههای توکِنایزر مدل را دریافت نموده و در سیستم شما ذخیره میکند. به این ترتیب این دادهها فقط بار اولی که کد زیر را اجرا میکنید دانلود میشوند. | |
| خط تولید `تحلیل احساسات` نقطه تعلیم پیشفرضی به نام `distilbert-base-uncased-finetuned-sst-2-english` دارد. صفحه توضیحات این مدل را میتوانید در [اینجا مشاهده کنید](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english). با اجرای کد زیر آن را دانلود میکنیم: | |
| ```python | |
| from transformers import AutoTokenizer | |
| checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" | |
| tokenizer = AutoTokenizer.from_pretrained(checkpoint) | |
| ``` | |
| پس از دریافت توکِنایزر، میتوانیم جملات خود را مستقیماً وارد آن کنیم و دیکشنری خروجی را دریافت کنیم که آماده است تا به عنوان ورودی مدل مورد استفاده قرار گیرد! تنها کار باقی مانده، تبدیل لیست شناسههای ورودی به تِنسور است. | |
| شما میتوانید از ترنسفورمرهای هاگینگفِیس بدون اطلاع از اینکه کدام فریمورک یادگیری ماشین در پشت صحنه درگیر میشود استفاده کنید. ممکن است از پایتورچ، تِنسورفِلو یا حتی فلَکس برای بعضی مدلها استفاده شده باشد. با این وجود، مدلهای ترسفورمر فقط *تِنسور*ها را به عنوان ورودی قبول میکنند. اگر این بار اولی است که کلمه تِنسور را میشنوید، تصور کنید مانند آرایههای NumPy هستند. این آرایهها میتوانند عددی (تک بُعدی)، برداری (یک بُعدی)، ماتریس (دو بُعدی) یا با ابعاد بیشتر باشند. آنها در واقع تِنسور هستند و تِنسورها در فریمورکهای یادگیری ماشین رفتاری شبیه به آرایههای NumPy دارند و به همان سادگی هم ساخته میشوند. | |
| برای مشخص کردن نوع تِنسوری که میخواهیم به عنوان خروجی دریافت کنیم (پایتورچ، تِنسورفِلو یا NumPy ساده)، از آرگومان `return_tensors` استفاده میکنیم: | |
| {#if fw === 'pt'} | |
| ```python | |
| raw_inputs = [ | |
| "I've been waiting for a HuggingFace course my whole life.", | |
| "I hate this so much!", | |
| ] | |
| inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt") | |
| print(inputs) | |
| ``` | |
| {:else} | |
| ```python | |
| raw_inputs = [ | |
| "I've been waiting for a HuggingFace course my whole life.", | |
| "I hate this so much!", | |
| ] | |
| inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf") | |
| print(inputs) | |
| ``` | |
| {/if} | |
| هنوز لازم نیست نگران آرگومانهای `padding` و `truncation` باشید؛ زیرا بعدتر به آنها خواهیم پرداخت. مسئله اصلی که باید به به خاطر بسپارید، امکان دادن جمله یا آرایهای از جملهها به عنوان ورودی و مشخص کردن نوع تِنسورهای خروجی است. اگر نوع خروجی را مشخص نکنید، لیستی از لیستها را دریافت خواهید کرد. | |
| {#if fw === 'pt'} | |
| خروجی تِنسورهای پایتورچ به این شکل است: | |
| ```python out | |
| { | |
| 'input_ids': tensor([ | |
| [ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102], | |
| [ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0] | |
| ]), | |
| 'attention_mask': tensor([ | |
| [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
| [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
| ]) | |
| } | |
| ``` | |
| {:else} | |
| خروجی تِنسورهای تِنسورفِلو به این شکل است: | |
| ```python out | |
| { | |
| 'input_ids': , | |
| 'attention_mask': | |
| } | |
| ``` | |
| {/if} | |
| خروجی یک دیکشنری با دو کلید `input_ids` و `attention_mask` است. `input_ids` دو ردیف عدد صحیح (یک ردیف برای هر جمله) است که شناسههای منحصر به فرد توکِنهای هر جمله هستند. `attention_mask` را بعدتر در همین فصل توضیح خواهیم داد. | |
| ## گذر از مدل | |
| {#if fw === 'pt'} | |
| میتوانیم مدل از پیش تعلیم دیده را، همانند آن چه در مورد توکِنایزر انجام شد، دانلود کنیم. ترنسوفورمرهای هاگینگفِیس کلاس `AutoModel` را ارائه میدهد که آن هم تابعی به نام `from_pretrained()` دارد: | |
| ```python | |
| from transformers import AutoModel | |
| checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" | |
| model = AutoModel.from_pretrained(checkpoint) | |
| ``` | |
| {:else} | |
| میتوانیم مدل از پیش تعلیم دیده را، همانند آنچه در مورد توکِنایزر انجام شد، دانلود کنیم. ترنسوفورمرهای هاگینگفِیس کلاس `TFAutoModel` را ارائه میدهد که آن هم تابعی به نام `from_pretrained()` دارد: | |
| ```python | |
| from transformers import TFAutoModel | |
| checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" | |
| model = TFAutoModel.from_pretrained(checkpoint) | |
| ``` | |
| {/if} | |
| در این قطعه کد، همان نقطه تعلیمی که قبلا در خط تولید استفاده کردیم را دانلود کرده و مدلی جدید بر اساس آن میسازیم. این نقطه تعلیم احتمالا قبلا دانلود شده و در سیستم شما موجود است؛ پس نیازی به دانلود مجدد ندارد. | |
| این معماری تنها شامل ماژول پایهٔ ترنسفورمر است: با دریافت ورودی، تنها *وضعیت پنهان* را در خروجی تحویل میدهد. به این وضعیتهای پنهان، *فیچر* هم میگوییم. برای هر ورودی مدل، برداری با بُعد بالا دریافت میکنیم که معادل «درک کلی مدل ترنسفورمر از آن ورودی» است. | |
| نگران نباشید اگر درک این مفاهیم سخت است. همه آنها را بعدتر توضیح خواهیم داد. | |
| با وجود آنکه وضعیتهای پنهان به خودی خود هم مفید هستند، آنها معمولا ورودی بخش دیگری از مدل به نام *سَر مدل* هستند. در [فصل اول](/course/chapter1)، میتوانستیم همه مسائل مختلف را توسط تنها یک معماری حل کنیم، و سپس خروجی را به سر متفاوتی در ادامه مدل پاس بدهیم. | |
| ### بردارهای با بُعد بالا؟ | |
| خروجی ماژول `Transformer` معمولا تِنسوری بزرگ است که اکثراً سه بُعد دارد: | |
| - **اندازه بتچ**: تعداد رشتههای مورد پردازش در یک دسته، که در مثال ما دو عدد است. | |
| - **طول رشته**: تعداد بردارهای عددی معادل هر رشته، که در مثال ما ۱۶ است. | |
| - **اندازه پنهان**: ابعاد بردار نماینده هر ورودی مدل. | |
| به خاطر همین مقدار آخر به این تِنسور «بُعد بالا» میگوییم. اندازه پنهان میتواند بسیار بزرگ باشد (معمولا ۷۶۸ برای مدلهای کوچکتر، و در مدلهای بزرگتر این عدد به ۳۰۷۲ یا بیشتر هم میرسد). | |
| با پاس دادن ورودیهای پیشپردازش شده به مدل خود میتوانیم این تِنسور را ببینیم: | |
| {#if fw === 'pt'} | |
| ```python | |
| outputs = model(**inputs) | |
| print(outputs.last_hidden_state.shape) | |
| ``` | |
| ```python out | |
| torch.Size([2, 16, 768]) | |
| ``` | |
| {:else} | |
| ```py | |
| outputs = model(inputs) | |
| print(outputs.last_hidden_state.shape) | |
| ``` | |
| ```python out | |
| (2, 16, 768) | |
| ``` | |
| {/if} | |
| توجه کنید که خروجیهای ترنسفورمرهای هاگینگفِیس، رفتاری شبیه `namedtuple` یا دیکشنری دارند. شما میتوانید به هر عضو، با استفاده از نامش (مانند آنچه ما انجام دادیم) یا با کلیدش (`outputs["last_hidden_state"]`) یا حتی اگر دقیقاً از مکان آن اطلاع دارید با اندیساش (`outputs[0]`) دسترسی پیدا کنید. | |
| ### سَر مدل: درک اعداد درون مدل | |
| قسمت سَر، بردارهای بُعد بالای وضعیت پنهان را به عنوان ورودی میپذیرد و آنها را به بُعدی دیگر میبرد. سَرها معمولا از یک یا چند لایه خطی تشکیل شدهاند. | |
| خروجی مدل ترنسفورمر، مستقیماً به سَر مدل برای پردازش پاس داده میشود. در این نمودار، مدل ترنسفورمر به لایه embeddings و لایههای بعدی آن تقسیم شده است. لایه embeddings هر شناسه ورودی در ورودی توکِنشده را به یک بردار که نماینده آن توکِن است تبدیل میکند. لایههای بعدی با دستکاری در این بردارها توسط مکانیزم توجه، شکل پایانی بردار نماینده جملات را تولید میکنند. | |
| تعداد زیادی از معماریهای مختلف در ترنسفورمرهای هاگینگفِیس موجود است و هرکدام برای حل یک مسئله خاص طراحی شدهاند. در اینجا فهرست کوتاهی از آنها را میآوریم: | |
| - `*Model` (برای دسترسی به وضعیتهای پنهان) | |
| - `*ForCausalLM` | |
| - `*ForMaskedLM` | |
| - `*ForMultipleChoice` | |
| - `*ForQuestionAnswering` | |
| - `*ForSequenceClassification` | |
| - `*ForTokenClassification` | |
| - و نمونههای دیگر در هاگینگفِیس | |
| {#if fw === 'pt'} | |
| برای این مثال، نیازمند مدلی با سَر مخصوص دستهبندی رشتهها (برای تشخیص منفی یا مثبت بودن جملات) هستیم. پس به جای کلاس `AutoModel` از کلاس `AutoModelForSequenceClassification` استفاده میکنیم: | |
| ```python | |
| from transformers import AutoModelForSequenceClassification | |
| checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" | |
| model = AutoModelForSequenceClassification.from_pretrained(checkpoint) | |
| outputs = model(**inputs) | |
| ``` | |
| {:else} | |
| برای این مثال، نیازمند مدلی با سَر مخصوص دستهبندی رشتهها (برای تشخیص منفی یا مثبت بودن جملات) هستیم. پس به جای کلاس `TFAutoModel` از کلاس `TFAutoModelForSequenceClassification` استفاده میکنیم: | |
| ```python | |
| from transformers import TFAutoModelForSequenceClassification | |
| checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" | |
| model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) | |
| outputs = model(inputs) | |
| ``` | |
| {/if} | |
| اگر نگاهی به شکل ورودیها بیاندازیم، خواهیم دید که حالا تعداد ابعاد آنها بسیار کمتر است: قسمت سَر مدل، بردارهای بُعد بالایی که قبلا دیدیم را به عنوان ورودی دریافت کرده و در خروجی خود، بردارهایی با دو عضو (یکی به ازای هر برچسب دستهبندی) تولید میکند. | |
| ```python | |
| print(outputs.logits.shape) | |
| ``` | |
| {#if fw === 'pt'} | |
| ```python out | |
| torch.Size([2, 2]) | |
| ``` | |
| {:else} | |
| ```python out | |
| (2, 2) | |
| ``` | |
| {/if} | |
| از آنجا که ما تنها دو جمله و دو برچسب ممکن داشتیم، خروجی مدل ما شکل ۲ در ۲ دارد. | |
| ## پسپردازش خروجی | |
| مقادیری که به عنوان خروجی از مدل دریافت میکنیم به خودی خود قابل درک نیستند. بگذارید نگاهی به آنها بیندازیم: | |
| ```python | |
| print(outputs.logits) | |
| ``` | |
| {#if fw === 'pt'} | |
| ```python out | |
| tensor([[-1.5607, 1.6123], | |
| [ 4.1692, -3.3464]], grad_fn=) | |
| ``` | |
| {:else} | |
| ```python out | |
| ``` | |
| {/if} | |
| پیشبینی مدل ما برای جمله اول `[-1.5607, 1.6123]` و برای جمله دوم `[4.1692, -3.3464]` است. این خروجیها مقادیر آماری نیستند. به این مقادیر *لوجیت* میگوییم. مقادیری خام و نرمالنشده که خروجی آخرین لایه مدل هستند. برای تبدیل به مقادیر آماری باید این مقادیر را از یک لایه [سافتمکس](https://en.wikipedia.org/wiki/Softmax_function) بگذرانیم. تمام ترنسفورمرهای هاگینگفِیس در خروجی لوجیت تولید میکنند زیرا معمولا تابع هزینه مورد استفاده در تعلیم مدل، آخرین تابع فعالسازی (مانند سافتمکس) را با تابع هزینه مدل (مانند آنتروپی متقابل) ترکیب میکند. | |
| {#if fw === 'pt'} | |
| ```py | |
| import torch | |
| predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) | |
| print(predictions) | |
| ``` | |
| {:else} | |
| ```py | |
| import tensorflow as tf | |
| predictions = tf.math.softmax(outputs.logits, axis=-1) | |
| print(predictions) | |
| ``` | |
| {/if} | |
| {#if fw === 'pt'} | |
| ```python out | |
| tensor([[4.0195e-02, 9.5980e-01], | |
| [9.9946e-01, 5.4418e-04]], grad_fn=) | |
| ``` | |
| {:else} | |
| ```python out | |
| tf.Tensor( | |
| [[4.01951671e-02 9.59804833e-01] | |
| [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32) | |
| ``` | |
| {/if} | |
| حالا میببینیم که پیشبینی مدل برای جمله اول `[0.0402, 0.9598]` و برای جمله دوم `[0.9995, 0.0005]` است. اینها مقادیر آشنای آماری (به فرم احتمال) هستند. | |
| برای تبدیل این مقادیر به برچسب دسته تشخیص داده شده میتوانیم از ویژگی `id2label` تنظیمات مدل استفاده کنیم (در بخش بعدی بیشتر در این مورد صحبت خواهیم کرد): | |
| ```python | |
| model.config.id2label | |
| ``` | |
| ```python out | |
| {0: 'NEGATIVE', 1: 'POSITIVE'} | |
| ``` | |
| اکنون مشخص است که پیشبینیهای مدل از این قرار هستند: | |
| - جمله اول: NEGATIVE: 0.0402, POSITIVE: 0.9598 | |
| - جمله دوم: NEGATIVE: 0.9995, POSITIVE: 0.0005 | |
| ما با موفقیت سه مرحله خط تولید را در اینجا نشان دادیم: پیشپردازش توسط توکِنایزرها، گذر ورودیها از مدل و پسپردازش! اکنون زمان آن فرا رسیده که به شکلی عمیقتر وارد هر یک از این مراحل شویم. | |
| > [!TIP] | |
| > ✏️ **خودتان امتحان کنید!** دو نوشته از خودتان (یا حتی بیشتر) را از خط تولید `sentiment-analysis` بگذرانید. سپس مراحلی که در اینجا دیدیم را تکرار کنید و بررسی کنید که نتایج همان هستند! | |
| ### مدلها | |
| https://huggingface.co/learn/course/fa/chapter2/3.md | |
| # مدلها | |
| {#if fw === 'pt'} | |
| {:else} | |
| {/if} | |
| {#if fw === 'pt'} | |
| {:else} | |
| {/if} | |
| {#if fw === 'pt'} | |
| در این بخش نگاهی نزدیکتر به ساخت و استفاده از مدلها میاندازیم. کلاس `AutoModel` را به کار خواهیم گرفت که برای ساختن مدلها از نقطههای تعلیم مشخص، بسیار پرکاربرد است. | |
| کلاس `AutoModel` و تمامی کلاسهای شبیه آن، در واقع پوستهای ساده روی انواع مختلف مدلهای موجود در کتابخانه هستند. پوستهای هوشمند که میتواند به صورت خودکار معماری مدل استفاده شده در نقطههای تعلیم را تشخیص دهد و سپس مدلی با آن معماری بسازد. | |
| {:else} | |
| در این بخش نگاهی نزدیکتر به ساخت و استفاده از مدلها میاندازیم. کلاس `TFAutoModel` را به کار خواهیم گرفت که برای ساختن مدلها از نقطههای تعلیم مشخص، بسیار پرکاربرد است. | |
| کلاس `TFAutoModel` و تمامی کلاسهای شبیه آن، در واقع پوستهای ساده روی انواع مختلف مدلهای موجود در کتابخانه هستند. پوستهای هوشمند که میتواند به صورت خودکار معماری مدل استفاده شده در نقطههای تعلیم را تشخیص دهد و سپس مدلی با آن معماری بسازد. | |
| {/if} | |
| با این وجود، اگر نوع مدلی که میخواهید استفاده کنید را میدانید، میتوانید مستقیماً کلاسی که معماری خاص آن مدل را تعریف میکند به کار ببرید. نگاهی به چگونگی انجام این عملیات با مدل BERT میاندازیم. | |
| ## ساخت ترنسفورمر | |
| اولین کار برای ساخت نمونهای از مدل BERT، بارگذاری شیء تنظیمات است: | |
| {#if fw === 'pt'} | |
| ```py | |
| from transformers import BertConfig, BertModel | |
| # Building the config | |
| config = BertConfig() | |
| # Building the model from the config | |
| model = BertModel(config) | |
| ``` | |
| {:else} | |
| ```py | |
| from transformers import BertConfig, TFBertModel | |
| # Building the config | |
| config = BertConfig() | |
| # Building the model from the config | |
| model = TFBertModel(config) | |
| ``` | |
| {/if} | |
| شیء تنظیمات ویژگیهای بسیاری دارد که برای ساختن مدل به کار میروند. | |
| ```py | |
| print(config) | |
| ``` | |
| ```python out | |
| 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` مشخص کننده تعداد لایههای مدل ترنسفورمر است. | |
| ### روشهای مختلف بارگذاری | |
| ساختن مدل با تنظیمات پیشفرض، باعث مقداردهی اولیه وزنهای آن با اعداد تصادفی میشود. | |
| {#if fw === 'pt'} | |
| ```py | |
| from transformers import BertConfig, BertModel | |
| config = BertConfig() | |
| model = BertModel(config) | |
| # Model is randomly initialized! | |
| ``` | |
| {:else} | |
| ```py | |
| from transformers import BertConfig, TFBertModel | |
| config = BertConfig() | |
| model = TFBertModel(config) | |
| # Model is randomly initialized! | |
| ``` | |
| {/if} | |
| میتوان از مدل در این وضعیت استفاده کرد ولی خروجی آن بیمعنی خواهد بود؛ ابتدا باید مدل را تعلیم دهیم. میتوانیم مدل را از صفر برای مسئله مورد نظرمان تعلیم دهیم ولی همان گونه که در [فصل اول](/course/chapter1) دیدیم، برای این کار نیاز به زمان طولانی و داده بسیار داریم. این عملیات تاثیرات منفی غیر قابل چشمپوشیای بر محیطزیست دارد. برای جلوگیری از دوبارهکاری باید بتوانیم مدلهای از پیش تعلیم دیده را به اشتراک گذاشته و به کار ببریم. | |
| بارگذاری مدل از پیش تعلیم دیده ترنسفورمر، ساده است. برای این کار از تابع `from_pretrained()` استفاده میکنیم. | |
| {#if fw === 'pt'} | |
| ```py | |
| from transformers import BertModel | |
| model = BertModel.from_pretrained("bert-base-cased") | |
| ``` | |
| همان طور که قبلا دیدید، میتوانیم کلاس `BertModel` را با کلاس معادل `AutoModel` جایگزین کنیم. از این پس همین کار را خواهیم کرد چون به این صورت کد وابسته به نقطه تعلیم خاصی نخواهد بود. اگر کد شما با یک نقطه تعلیم اجرا میشود، بدون تغییر با نقاط تعلیم دیگر هم اجرا خواهد شد. این حتی در مورد معماریهای متفاوت هم صدق میکند، البته در صورتی که نقطه تعلیم متعلق به مسئله مشابهی(برای مثال تحلیل احساسات) باشد. | |
| {:else} | |
| ```py | |
| from transformers import TFBertModel | |
| model = TFBertModel.from_pretrained("bert-base-cased") | |
| ``` | |
| همان طور که قبلا دیدید، میتوانیم کلاس `TFBertModel` را با کلاس معادل `TFAutoModel` جایگزین کنیم. از این پس همین کار را خواهیم کرد چون به این صورت کد وابسته به نقطه تعلیم خاصی نخواهد بود. اگر کد شما با یک نقطه تعلیم اجرا میشود، بدون تغییر با نقاط تعلیم دیگر هم اجرا خواهد شد. این حتی در مورد معماریهای متفاوت هم صدق میکند، البته در صورتی که نقطه تعلیم متعلق به مسئله مشابهی(برای مثال تحلیل احساسات) باشد. | |
| {/if} | |
| در کد نمونه بالا، کلاس `BertConfig` را به کار نبرده و در عوض از مدلی از پیش تعلیم دیده با شناسه `bert-base-cased` استفاده کردیم؛ نقطه تعلیم مدلی که توسط خود مؤلفان مدل BERT تعلیم دیده است. اطلاعات بیشتر در مورد این نقطه تعلیم را میتوانید در [صفحه توضیحات](https://huggingface.co/bert-base-cased) آن ببینید. | |
| این مدل اکنون با وزنهای نقطه تعلیم پر شده است و میتوان آن را مستقیماً برای مسائلی که برای آن تعلیم دیده به کار برد یا برای مسئله جدیدی کوک کرد. با تعلیم روی وزنهای از پیش تعلیم دیده، به جای تعلیم از صفر، میتوانیم به سرعت به نتایج خوبی دست پیدا کنیم. | |
| این وزنها دانلود و در پوشهای مخصوص انبار شدهاند، تا اجرای تابع `from_pretrained()` در آینده مسبب دانلود دوبارهاشان نباشد. این پوشه به صورت پیشفرض در آدرس *~/.cache/huggingface/transformers* قرار دارد. شما میتوانید با تخصیص مقدار به متغیر محیطی `HF_HOME` مکان این پوشه را تغییر دهید. | |
| شناسه هر مدلی در هاب مدلها را میتوانید برای بارگذاری استفاده کنید. البته در صورتی که آن مدل با معماری BERT سازگاری داشته باشد. فهرست کامل تمام نقاط تعلیم سازگار با BERT را [اینجا مشاهده کنید](https://huggingface.co/models?filter=bert). | |
| ### روشهای ذخیرهسازی | |
| ذخیرهسازی مدل به سادگی بارگذاری آن است. از تابع `save_pretrained()` استفاده میکنیم که متناظر با تابع `from_pretrained()` است: | |
| ```py | |
| model.save_pretrained("directory_on_my_computer") | |
| ``` | |
| اجرای این تابع باعث ذخیره شدن دو فایل در سیستم شما میشود: | |
| {#if fw === 'pt'} | |
| ``` | |
| ls directory_on_my_computer | |
| config.json model.safetensors | |
| ``` | |
| {:else} | |
| ``` | |
| ls directory_on_my_computer | |
| config.json tf_model.h5 | |
| ``` | |
| {/if} | |
| اگر نگاهی به فایل *config.json* بیاندازید، با ویژگیهای آشنای مورد نیاز برای ساختن معماری مدل روبرو خواهید شد. این فایل حاوی مقادیری متادیتا، مانند نقطه مادر این نقطه تعلیم و نسخه کتابخانه ترنسفورمرهای هاگینگفِیس که آخرین بار برای ذخیرهسازی این نقطه به کار رفته است، میباشد. | |
| {#if fw === 'pt'} | |
| فایل *model.safetensors* در واقع *دیکشنری وضعیتها* است و حاوی تمام وزنهای مدل شماست. این دو فایل به همراه هم کاربرد دارند؛ فایل تنظیمات برای دانستن معماری به کار رفته در مدل ضروری است و پارامترهای مدل هم که همان وزنهای داخل فایل دوم هستند. | |
| {:else} | |
| فایل *tf_model.h5* در واقع *دیکشنری وضعیتها* است و حاوی تمام وزنهای مدل شماست. این دو فایل به همراه هم کاربرد دارند؛ فایل تنظیمات برای دانستن معماری به کار رفته در مدل ضروری است و پارامترهای مدل هم که همان وزنهای داخل فایل دوم هستند. | |
| {/if} | |
| ## اجرای یک مدل ترنسفورمر | |
| حالا که میدانید چگونه مدلها را ذخیرهسازی و بارگذاری کنید، میتوانیم آنها را برای پیشبینی به کار بگیریم. مدلهای ترنسفورمر فقط میتوانند اعداد را پردازش کنند؛ اعدادی که توکِنایزر تولید نموده است. ولی پیش از آن که سراغ بحث توکِنایزرها برویم، ورودیهای قابل قبول برای مدلها را بررسی میکنیم. | |
| توکِنایزرها میتوانند ورودیها را به تِنسورهای مخصوص هر فریمورک تبدیل کنند ولی برای آنکه درست متوجه آنچه اتفاق میافتد شویم، نگاهی کوتاه به کارهایی که باید قبل از فرستادن ورودیها به مدل انجام شود میاندازیم. | |
| تصور کنید چند جمله به این صورت داریم: | |
| ```py | |
| sequences = ["Hello!", "Cool.", "Nice!"] | |
| ``` | |
| توکِنایزر این جملات را به اندیسهای مخصوص کلمات که معمولا به آنها *شناسههای ورودی* میگوییم، تبدیل میکند. هر رشته اکنون لیستی از اعداد است! نتیجه خروجی از این قرار است: | |
| ```py no-format | |
| encoded_sequences = [ | |
| [101, 7592, 999, 102], | |
| [101, 4658, 1012, 102], | |
| [101, 3835, 999, 102], | |
| ] | |
| ``` | |
| این خروجی لیستی از رشتههای کد شده شده است: لیستی از لیستها. تِنسورها تنها مقادیر به شکل مستطیل(همان ماتریس) را میپذیرند. این «آرایه» خود شکل مستطیلی دارد پس تبدیل آن به تِنسور ساده است: | |
| {#if fw === 'pt'} | |
| ```py | |
| import torch | |
| model_inputs = torch.tensor(encoded_sequences) | |
| ``` | |
| {:else} | |
| ```py | |
| import tensorflow as tf | |
| model_inputs = tf.constant(encoded_sequences) | |
| ``` | |
| {/if} | |
| ### استفاده از تِنسورها به عنوان ورودی مدل | |
| به کار بردن تِنسورها به عنوان ورودی مدل بسیار ساده است؛ تنها آرگومان تِنسور ورودی را به صورت زیر به مدل پاس میدهیم: | |
| ```py | |
| output = model(model_inputs) | |
| ``` | |
| این تابع آرگومانهای بسیاری را میپذیرد ولی تنها شناسههای ورودی ضروری هستند. کاربرد آرگومانهای دیگر و شرایط ضرورت آنها را بعد توضیح خواهیم داد. ولی ابتدا باید نگاهی نزدیکتر به توکِنایزرهایی که ورودیهای قابل فهم مدلهای ترنسفورمر را میسازند، بیاندازیم. | |
Xet Storage Details
- Size:
- 137 kB
- Xet hash:
- bb208f669fe17954520a15bc57cca216e5e9dcfc98738b25fdd677dbdd17fa78
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.