From 52b21586130d13e8cff7b7b47878877807ac265f Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 10:04:37 +0200 Subject: [PATCH 001/502] chapter3 - added introduction --- chapters/fa/chapter3/1.mdx | 1 + 1 file changed, 1 insertion(+) create mode 100644 chapters/fa/chapter3/1.mdx diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/chapters/fa/chapter3/1.mdx @@ -0,0 +1 @@ + From 33915ea32f7af0443eea873f3a0f92f68a045c89 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 10:22:54 +0200 Subject: [PATCH 002/502] ch3 - intro - title --- chapters/fa/chapter3/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 8b1378917..0cef3bdd6 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1 +1 @@ - +### مقدمه From 6bd93263e69a2442a2fc00519a0e9c63c984f785 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 10:30:21 +0200 Subject: [PATCH 003/502] intro some text added --- chapters/fa/chapter3/1.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 0cef3bdd6..a2f9138f5 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1 +1,3 @@ -### مقدمه +# مقدمه + +در فصل ۲ نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. From 7eae7bbecd0b3dc2424b0e64d1758b3c0d18311a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 21:53:01 +0200 Subject: [PATCH 004/502] url added --- chapters/fa/chapter3/1.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index a2f9138f5..fc77c3c56 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,3 +1,6 @@ # مقدمه -در فصل ۲ نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. +در (/course/chapter2)[فصل ۲] ۲ نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش آموزش داده شده را خودتان فاین تیون کنید؟ + +* چگونه یک داده بزرگ را از هاب تهیه کنید +* From cb090d1bf229796fc91786b6a0a4fa4447e22fe9 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 21:55:06 +0200 Subject: [PATCH 005/502] url added --- chapters/fa/chapter3/1.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index fc77c3c56..869494168 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -4,3 +4,5 @@ * چگونه یک داده بزرگ را از هاب تهیه کنید * + +[url](www.google.com) \ No newline at end of file From b7aee3a6ec8fc72ff03ca59a700fee35047986d8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 21:55:44 +0200 Subject: [PATCH 006/502] url added --- chapters/fa/chapter3/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 869494168..30f4a99cd 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -2,7 +2,7 @@ در (/course/chapter2)[فصل ۲] ۲ نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش آموزش داده شده را خودتان فاین تیون کنید؟ -* چگونه یک داده بزرگ را از هاب تهیه کنید +* چگونه [url](www.google.com) یک داده بزرگ را از هاب تهیه کنید * [url](www.google.com) \ No newline at end of file From 8e1e264c7c9ea71ba780d9e6ee1cf8fe866b3555 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 21:56:23 +0200 Subject: [PATCH 007/502] url added --- chapters/fa/chapter3/1.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 30f4a99cd..41dd60266 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -2,7 +2,9 @@ در (/course/chapter2)[فصل ۲] ۲ نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش آموزش داده شده را خودتان فاین تیون کنید؟ -* چگونه [url](www.google.com) یک داده بزرگ را از هاب تهیه کنید +* چگونه [لینک](www.google.com) یک داده بزرگ را از هاب تهیه کنید * -[url](www.google.com) \ No newline at end of file +[url](www.google.com) + + From 0c472b689ed91f029c9199431f9ca72fe06b81fc Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 21:57:39 +0200 Subject: [PATCH 008/502] url added --- chapters/fa/chapter3/1.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 41dd60266..9f9d52fbb 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,6 +1,6 @@ # مقدمه -در (/course/chapter2)[فصل ۲] ۲ نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش آموزش داده شده را خودتان فاین تیون کنید؟ +در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش آموزش داده شده را خودتان فاین تیون کنید؟ * چگونه [لینک](www.google.com) یک داده بزرگ را از هاب تهیه کنید * @@ -8,3 +8,4 @@ [url](www.google.com) +/course/chapter2 \ No newline at end of file From ccac309a6dfa8c02bf686fca254711722de65ebc Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 22:05:43 +0200 Subject: [PATCH 009/502] bullets added --- chapters/fa/chapter3/1.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 9f9d52fbb..e37bdd7ac 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -2,10 +2,12 @@ در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش آموزش داده شده را خودتان فاین تیون کنید؟ -* چگونه [لینک](www.google.com) یک داده بزرگ را از هاب تهیه کنید -* +{#if fw === 'pt'} -[url](www.google.com) +* چگونه یک داده بزرگ را از هاب تهیه کنید +* چگونه از ای پی ای آموزش دهنده سطح بالا برای فاین تیون کردن مدل استفاده کنید +* چطور یک لوپ آموزش دهنده شخصی درست کنیم +* چگونه از کتابخانه شتابدهنده استفاده کنیم برای اینکه لوپ آموزش دهنده شخصی را در هر گونه تنظیمات پراکنده اجرا کنیم +{:else} -/course/chapter2 \ No newline at end of file From 9f01f8263cf3a3ea1d0ae24ad71bacad5e0ee0b9 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 19 Apr 2022 22:17:44 +0200 Subject: [PATCH 010/502] bullets added --- chapters/fa/chapter3/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index e37bdd7ac..18e7580dd 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -7,7 +7,7 @@ * چگونه یک داده بزرگ را از هاب تهیه کنید * چگونه از ای پی ای آموزش دهنده سطح بالا برای فاین تیون کردن مدل استفاده کنید * چطور یک لوپ آموزش دهنده شخصی درست کنیم -* چگونه از کتابخانه شتابدهنده استفاده کنیم برای اینکه لوپ آموزش دهنده شخصی را در هر گونه تنظیمات پراکنده اجرا کنیم +* چگونه از کتابخانه شتابدهنده 🤗 استفاده کنیم برای اینکه لوپ آموزش دهنده شخصی را در هر گونه تنظیمات پراکنده اجرا کنیم {:else} From 8011d3728b5ae2e517d83e3e2667696cda2126fd Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 08:52:47 +0200 Subject: [PATCH 011/502] introduction - first draft --- chapters/fa/chapter3/1.mdx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 18e7580dd..fca5f8e49 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,13 +1,21 @@ # مقدمه -در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزر ها و مدلهای از پیش آموزش داده شده را جهت انجام پیش بینی جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش آموزش داده شده را خودتان فاین تیون کنید؟ +در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدلهای پیش تعلیم را جهت انجام پیش بینی های جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش تعلیم را خودتان بازتنظیم کنید؟ {#if fw === 'pt'} * چگونه یک داده بزرگ را از هاب تهیه کنید -* چگونه از ای پی ای آموزش دهنده سطح بالا برای فاین تیون کردن مدل استفاده کنید -* چطور یک لوپ آموزش دهنده شخصی درست کنیم -* چگونه از کتابخانه شتابدهنده 🤗 استفاده کنیم برای اینکه لوپ آموزش دهنده شخصی را در هر گونه تنظیمات پراکنده اجرا کنیم +* چگونه از API سطح بالای "Trainer" آموزش دهنده برای بازتنظیم مدل استفاده کنید +* چگونه یک چرخه تعلیم دلخواه درست کنید +* چگونه از کتابخانه Accelerate 🤗 برای اجرای چرخه تعلیم دلخواه را در هر تنظیمات غیر متمرکزی استفاده کنید {:else} +* چگونه یک داده بزرگ را از هاب تهیه کنید +* چگونه از کراس برای بازتنظیم مدل استفاده کنید +* چگونه از کراس برای استخراج پیش بینی ها استفاده کنید +* چگونه از یک متریک دلخواه استفاده کنید + +{/if} + +جهت بارگذاری چک پوینت تعلیم دیده خود در هاب هاگینک فیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) \ No newline at end of file From 96a3dc08f3ca648e6647bc923c3e62c964470593 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 08:54:10 +0200 Subject: [PATCH 012/502] fixed minor typo --- chapters/fa/chapter3/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index fca5f8e49..8ef01b751 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,6 +1,6 @@ # مقدمه -در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدلهای پیش تعلیم را جهت انجام پیش بینی های جدید بررسی کردیم. اما چگونه میتوانید یک مدل از پیش تعلیم را خودتان بازتنظیم کنید؟ +در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدلهای پیش تعلیم را جهت انجام پیش بینی های جدید بررسی کردیم. اما چگونه میتوانید یک مدل پیش تعلیم را خودتان بازتنظیم کنید؟ {#if fw === 'pt'} From 7321d7202add8061d348be9014ea69a1969bf12f Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 08:55:55 +0200 Subject: [PATCH 013/502] fixed minor typo --- chapters/fa/chapter3/1.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 8ef01b751..ccb01c2e9 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -5,9 +5,9 @@ {#if fw === 'pt'} * چگونه یک داده بزرگ را از هاب تهیه کنید -* چگونه از API سطح بالای "Trainer" آموزش دهنده برای بازتنظیم مدل استفاده کنید +* چگونه از API سطح بالای "Trainer" برای بازتنظیم مدل استفاده کنید * چگونه یک چرخه تعلیم دلخواه درست کنید -* چگونه از کتابخانه Accelerate 🤗 برای اجرای چرخه تعلیم دلخواه را در هر تنظیمات غیر متمرکزی استفاده کنید +* چگونه از کتابخانه Accelerate 🤗 برای اجرای چرخه تعلیم دلخواه در هر تنظیمات غیر متمرکزی استفاده کنید {:else} From 34eeeda61e79b6473aa4c91f3e58482fe4512229 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 13:39:56 +0200 Subject: [PATCH 014/502] section 2 - process data - file added. --- chapters/fa/chapter3/1.mdx | 2 + chapters/fa/chapter3/2.mdx | 383 +++++++++++++++++++++++++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 chapters/fa/chapter3/2.mdx diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index ccb01c2e9..b960c3886 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,3 +1,5 @@ + + # مقدمه در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدلهای پیش تعلیم را جهت انجام پیش بینی های جدید بررسی کردیم. اما چگونه میتوانید یک مدل پیش تعلیم را خودتان بازتنظیم کنید؟ diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx new file mode 100644 index 000000000..4611e8469 --- /dev/null +++ b/chapters/fa/chapter3/2.mdx @@ -0,0 +1,383 @@ + + +#پردازش داده +# Processing the data + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} +ادامه از مثال [فصل قبل](/course/chapter2) نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch به شرح زیر میباش: +Continuing with the example from the [previous chapter](/course/chapter2), here is how we would train a sequence classifier on one batch in PyTorch: + +```python +import torch +from transformers import AdamW, 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} +Continuing with the example from the [previous chapter](/course/chapter2), here is how we would train a sequence classifier on one batch in TensorFlow: + +```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} + +Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. + +In this section we will use as an example the MRPC (Microsoft Research Paraphrase Corpus) dataset, introduced in a [paper](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. The dataset consists of 5,801 pairs of sentences, with a label indicating if they are paraphrases or not (i.e., if both sentences mean the same thing). We've selected it for this chapter because it's a small dataset, so it's easy to experiment with training on it. + +### Loading a dataset from the Hub + +{#if fw === 'pt'} + +{:else} + +{/if} + +The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. + +The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: + +```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 + }) +}) +``` + +As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). + +This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. + +We can access each pair of sentences in our `raw_datasets` object by indexing, like with a dictionary: + +```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 .'} +``` + +We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: + +```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)} +``` + +Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers to label name is stored in the *names* folder. `0` corresponds to `not_equivalent`, and `1` corresponds to `equivalent`. + + + +✏️ **Try it out!** Look at element 15 of the training set and element 87 of the validation set. What are their labels? + + + +### Preprocessing a dataset + +{#if fw === 'pt'} + +{:else} + +{/if} + +To preprocess the dataset, we need to convert the text to numbers the model can make sense of. As you saw in the [previous chapter](/course/chapter2), this is done with a tokenizer. We can feed the tokenizer one sentence or a list of sentences, so we can directly tokenize all the first sentences and all the second sentences of each pair like this: + +```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"]) +``` + +However, we can't just pass two sequences to the model and get a prediction of whether the two sentences are paraphrases or not. We need to handle the two sequences as a pair, and apply the appropriate preprocessing. Fortunately, the tokenizer can also take a pair of sequences and prepare it the way our BERT model expects: + +```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] +} +``` + +We discussed the `input_ids` and `attention_mask` keys in [Chapter 2](/course/chapter2), but we put off talking about `token_type_ids`. In this example, this is what tells the model which part of the input is the first sentence and which is the second sentence. + + + +✏️ **Try it out!** Take element 15 of the training set and tokenize the two sentences separately and as a pair. What's the difference between the two results? + + + +If we decode the IDs inside `input_ids` back to words: + +```py +tokenizer.convert_ids_to_tokens(inputs["input_ids"]) +``` + +we will get: + +```python out +['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] +``` + +So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] sentence2 [SEP]` when there are two sentences. Aligning this with the `token_type_ids` gives us: + +```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] +``` + +As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` all have a token type ID of `0`, while the other parts, corresponding to `sentence2 [SEP]`, all have a token type ID of `1`. + +Note that if you select a different checkpoint, you won't necessarily have the `token_type_ids` in your tokenized inputs (for instance, they're not returned if you use a DistilBERT model). They are only returned when the model will know what to do with them, because it has seen them during its pretraining. + +Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. + +With next sentence prediction, the model is provided pairs of sentences (with randomly masked tokens) and asked to predict whether the second sentence follows the first. To make the task non-trivial, half of the time the sentences follow each other in the original document they were extracted from, and the other half of the time the two sentences come from two different documents. + +In general, you don't need to worry about whether or not there are `token_type_ids` in your tokenized inputs: as long as you use the same checkpoint for the tokenizer and the model, everything will be fine as the tokenizer knows what to provide to its model. + +Now that we have seen how our tokenizer can deal with one pair of sentences, we can use it to tokenize our whole dataset: like in the [previous chapter](/course/chapter2), we can feed the tokenizer a list of pairs of sentences by giving it the list of first sentences, then the list of second sentences. This is also compatible with the padding and truncation options we saw in [Chapter 2](/course/chapter2). So, one way to preprocess the training dataset is: + +```py +tokenized_dataset = tokenizer( + raw_datasets["train"]["sentence1"], + raw_datasets["train"]["sentence2"], + padding=True, + truncation=True, +) +``` + +This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). + +To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: + +```py +def tokenize_function(example): + return tokenizer(example["sentence1"], example["sentence2"], truncation=True) +``` + +This function takes a dictionary (like the items of our dataset) and returns a new dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`. Note that it also works if the `example` dictionary contains several samples (each key as a list of sentences) since the `tokenizer` works on lists of pairs of sentences, as seen before. This will allow us to use the option `batched=True` in our call to `map()`, which will greatly speed up the tokenization. The `tokenizer` is backed by a tokenizer written in Rust from the [🤗 Tokenizers](https://github.com/huggingface/tokenizers) library. This tokenizer can be very fast, but only if we give it lots of inputs at once. + +Note that we've left the `padding` argument out in our tokenization function for now. This is because padding all the samples to the maximum length is not efficient: it's better to pad the samples when we're building a batch, as then we only need to pad to the maximum length in that batch, and not the maximum length in the entire dataset. This can save a lot of time and processing power when the inputs have very variable lengths! + +Here is how we apply the tokenization function on all our datasets at once. We're using `batched=True` in our call to `map` so the function is applied to multiple elements of our dataset at once, and not on each element separately. This allows for faster preprocessing. + +```py +tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) +tokenized_datasets +``` + +The way the 🤗 Datasets library applies this processing is by adding new fields to the datasets, one for each key in the dictionary returned by the preprocessing function: + +```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 + }) +}) +``` + +You can even use multiprocessing when applying your preprocessing function with `map()` by passing along a `num_proc` argument. We didn't do this here because the 🤗 Tokenizers library already uses multiple threads to tokenize our samples faster, but if you are not using a fast tokenizer backed by this library, this could speed up your preprocessing. + +Our `tokenize_function` returns a dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`, so those three fields are added to all splits of our dataset. Note that we could also have changed existing fields if our preprocessing function returned a new value for an existing key in the dataset to which we applied `map()`. + +The last thing we will need to do is pad all the examples to the length of the longest element when we batch elements together — a technique we refer to as *dynamic padding*. + +### Dynamic padding + + + +{#if fw === 'pt'} +The function that is responsible for putting together samples inside a batch is called a *collate function*. It's an argument you can pass when you build a `DataLoader`, the default being a function that will just convert your samples to PyTorch tensors and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. + +{:else} + +The function that is responsible for putting together samples inside a batch is called a *collate function*. The default collator is a function that will just convert your samples to tf.Tensor and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. + +{/if} + +To do this in practice, we have to define a collate function that will apply the correct amount of padding to the items of the dataset we want to batch together. Fortunately, the 🤗 Transformers library provides us with such a function via `DataCollatorWithPadding`. It takes a tokenizer when you instantiate it (to know which padding token to use, and whether the model expects padding to be on the left or on the right of the inputs) and will do everything you need: + +{#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} + +To test this new toy, let's grab a few samples from our training set that we would like to batch together. Here, we remove the columns `idx`, `sentence1`, and `sentence2` as they won't be needed and contain strings (and we can't create tensors with strings) and have a look at the lengths of each entry in the batch: + +```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] +``` + +No surprise, we get samples of varying length, from 32 to 67. Dynamic padding means the samples in this batch should all be padded to a length of 67, the maximum length inside the batch. Without dynamic padding, all of the samples would have to be padded to the maximum length in the whole dataset, or the maximum length the model can accept. Let's double-check that our `data_collator` is dynamically padding the batch properly: + +```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])} +``` + +Looking good! Now that we've gone from raw text to batches our model can deal with, we're ready to fine-tune it! + +{/if} + + + +✏️ **Try it out!** Replicate the preprocessing on the GLUE SST-2 dataset. It's a little bit different since it's composed of single sentences instead of pairs, but the rest of what we did should look the same. For a harder challenge, try to write a preprocessing function that works on any of the GLUE tasks. + + + +{#if fw === 'tf'} + +Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! + +```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, +) +``` + +And that's it! We can take those datasets forward into the next lecture, where training will be pleasantly straightforward after all the hard work of data preprocessing. + +{/if} From 4abbc2a52c44cab2fce0fe339cc5912f253efa09 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 13:40:44 +0200 Subject: [PATCH 015/502] minor fix --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 4611e8469..507f255f4 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -1,6 +1,6 @@ -#پردازش داده +# پردازش داده # Processing the data {#if fw === 'pt'} From 2217041e8b682e894775bccbcd4866c3be575d29 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 13:45:56 +0200 Subject: [PATCH 016/502] minor fix --- chapters/fa/chapter3/2.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 507f255f4..7efd875be 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -24,7 +24,9 @@ {/if} {#if fw === 'pt'} -ادامه از مثال [فصل قبل](/course/chapter2) نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch به شرح زیر میباش: + + در این بخش در ادامه مثال [فصل قبل](/course/chapter2) نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می دهیم: + Continuing with the example from the [previous chapter](/course/chapter2), here is how we would train a sequence classifier on one batch in PyTorch: ```python From 7b4590533776df7fc9e3c03ed6cb6995b02cec7c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 13:46:48 +0200 Subject: [PATCH 017/502] minor fix --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 7efd875be..fc88d8348 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -25,7 +25,7 @@ {#if fw === 'pt'} - در این بخش در ادامه مثال [فصل قبل](/course/chapter2) نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می دهیم: + در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می دهیم: Continuing with the example from the [previous chapter](/course/chapter2), here is how we would train a sequence classifier on one batch in PyTorch: From bf53804b3a176cf46035589d160a7e55a64a28a7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 13:56:52 +0200 Subject: [PATCH 018/502] added new paragraph --- chapters/fa/chapter3/2.mdx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index fc88d8348..c5444dce9 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -27,8 +27,6 @@ در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می دهیم: -Continuing with the example from the [previous chapter](/course/chapter2), here is how we would train a sequence classifier on one batch in PyTorch: - ```python import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -52,7 +50,8 @@ loss.backward() optimizer.step() ``` {:else} -Continuing with the example from the [previous chapter](/course/chapter2), here is how we would train a sequence classifier on one batch in TensorFlow: + +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می دهیم: ```python import tensorflow as tf @@ -74,8 +73,13 @@ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy") labels = tf.convert_to_tensor([1, 1]) model.train_on_batch(batch, labels) ``` + {/if} +البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی داده بزرگتر خواهید داشت. + +در این بخش ما از داده -- که در مقاله -- معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب میباشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. ما این داده را به این دلیل انتخاب کردیم که داده کوچکیست و تجربه آموزش دادن روی آن آسان است. + Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. In this section we will use as an example the MRPC (Microsoft Research Paraphrase Corpus) dataset, introduced in a [paper](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. The dataset consists of 5,801 pairs of sentences, with a label indicating if they are paraphrases or not (i.e., if both sentences mean the same thing). We've selected it for this chapter because it's a small dataset, so it's easy to experiment with training on it. From 5b85ac44680b0e94e6dcd86bc85c427a06b6a523 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 18:19:57 +0200 Subject: [PATCH 019/502] urls added --- chapters/fa/chapter3/2.mdx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c5444dce9..c3127e372 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,12 +78,15 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی داده بزرگتر خواهید داشت. -در این بخش ما از داده -- که در مقاله -- معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب میباشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. ما این داده را به این دلیل انتخاب کردیم که داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از داده MRPC (Microsoft Research Paraphrase Corpus) که در [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب میباشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. ما این داده را به این دلیل انتخاب کردیم که داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. In this section we will use as an example the MRPC (Microsoft Research Paraphrase Corpus) dataset, introduced in a [paper](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. The dataset consists of 5,801 pairs of sentences, with a label indicating if they are paraphrases or not (i.e., if both sentences mean the same thing). We've selected it for this chapter because it's a small dataset, so it's easy to experiment with training on it. + +### بارگذاری داده از هاب + ### Loading a dataset from the Hub {#if fw === 'pt'} @@ -92,6 +95,8 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} +هاب تنها شامل مدلها نمیشود؛ بلکه شامل داده های متعدد در بسیاری زبانهای مختلف می باشد. در اینجا شما میتوانید + The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: From 18ed2b6c79b034131316e462dd0829dc5ae33d50 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 18:45:33 +0200 Subject: [PATCH 020/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c3127e372..2332412f9 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -95,7 +95,7 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} -هاب تنها شامل مدلها نمیشود؛ بلکه شامل داده های متعدد در بسیاری زبانهای مختلف می باشد. در اینجا شما میتوانید +هاب تنها شامل مدلها نمیشود؛ بلکه شامل داده های متعدد در بسیاری زبانهای مختلف می باشد. شما میتوانید داده ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می کنیم پس از اتمام این این بخش یک داده جدید را بارگذاری و پردازش کنید (بخش داکیومنتهای عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) ببنید). اما اجازه بدید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده GLUE benchmark](https://gluebenchmark.com/) است که یک بنچمارک اکادمی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ وظیفه دسته بندی متن مختلف میباشد. The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. From 53af6411071aa8b0cb3da7d908ab55797d4178b7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 18:47:14 +0200 Subject: [PATCH 021/502] typos fixed --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 2332412f9..6ab0537f4 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -95,7 +95,7 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} -هاب تنها شامل مدلها نمیشود؛ بلکه شامل داده های متعدد در بسیاری زبانهای مختلف می باشد. شما میتوانید داده ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می کنیم پس از اتمام این این بخش یک داده جدید را بارگذاری و پردازش کنید (بخش داکیومنتهای عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) ببنید). اما اجازه بدید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده GLUE benchmark](https://gluebenchmark.com/) است که یک بنچمارک اکادمی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ وظیفه دسته بندی متن مختلف میباشد. +هاب تنها شامل مدلها نمیشود؛ بلکه شامل داده های متعدد در بسیاری زبانهای مختلف می باشد. شما میتوانید داده ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می کنیم پس از اتمام این بخش یک داده جدید را بارگذاری و پردازش کنید (بخش داکیومنتهای عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) ببنید). اما اجازه بدید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک بنچمارک اکادمی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ وظیفه دسته بندی متن مختلف میباشد. The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. From 8d386faa31f2cf8b53fbcf47d0a82de46b9efd3a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 18:48:44 +0200 Subject: [PATCH 022/502] writing improved --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 6ab0537f4..33b9a4462 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -95,7 +95,7 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} -هاب تنها شامل مدلها نمیشود؛ بلکه شامل داده های متعدد در بسیاری زبانهای مختلف می باشد. شما میتوانید داده ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می کنیم پس از اتمام این بخش یک داده جدید را بارگذاری و پردازش کنید (بخش داکیومنتهای عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) ببنید). اما اجازه بدید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک بنچمارک اکادمی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ وظیفه دسته بندی متن مختلف میباشد. +هاب تنها شامل مدلها نمیشود؛ بلکه شامل داده های متعدد در بسیاری زبانهای مختلف می باشد. شما میتوانید داده ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می کنیم پس از اتمام این بخش یک داده جدید را بارگذاری و پردازش کنید (بخش متون عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک بنچمارک اکادمی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ وظیفه دسته بندی متن مختلف میباشد. The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. From 991055c0471f15148c8dd1299b1cd6346e0bac2a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 18:56:11 +0200 Subject: [PATCH 023/502] synch with glossary --- chapters/fa/chapter3/2.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 33b9a4462..e207d93ce 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -99,6 +99,8 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. +کتابخانه داده 🤗 یک دستور بسیار ساده جهت دانلود و بارگذاری یک داده در هاب ارائه میکند. ما میتوانیم داده MRPC را به صورت زیر دانلود کنیم. + The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: ```py From 9a6023e81ac6dfad278a3c8e672e06ee71690206 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 19:05:51 +0200 Subject: [PATCH 024/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index e207d93ce..6ad194308 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -99,7 +99,7 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. -کتابخانه داده 🤗 یک دستور بسیار ساده جهت دانلود و بارگذاری یک داده در هاب ارائه میکند. ما میتوانیم داده MRPC را به صورت زیر دانلود کنیم. +کتابخانه داده 🤗 یک دستور بسیار ساده جهت دانلود و بارگذاری یک داده در هاب ارائه میکند. ما میتوانیم داده MRPC را به روش زیر دانلود کنیم. The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: @@ -127,8 +127,12 @@ DatasetDict({ }) ``` +همانطور که می بینید یک ابجکت "DatasetDict" بدست می آوریم که شامل مجموعه داده های Train, Test, و Validation میباشد. هریک از اینها شامل چندین سطون (`sentence1`, `sentence2`, `label`, and `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می دهند میباشد. + As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). +این دستور داده را به صورت پیش فرض در *~/.cache/huggingface/dataset* دانلود و کش میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید دایرکتوری کشتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. We can access each pair of sentences in our `raw_datasets` object by indexing, like with a dictionary: From 4f1d096cfead622d9c9097b653cc0bcc79d30fd6 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 19:08:40 +0200 Subject: [PATCH 025/502] polished sentences --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 6ad194308..3f4372212 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,7 +78,7 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی داده بزرگتر خواهید داشت. -در این بخش ما از داده MRPC (Microsoft Research Paraphrase Corpus) که در [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب میباشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. ما این داده را به این دلیل انتخاب کردیم که داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از داده MRPC (Microsoft Research Paraphrase Corpus) که در [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب میباشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این داده این است که داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. From 3544c2903a69622ae9309a9d5d99948d14e54f16 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 20 Apr 2022 19:13:24 +0200 Subject: [PATCH 026/502] new sentence added --- chapters/fa/chapter3/2.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 3f4372212..aeca47bff 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک ابجکت "DatasetDict" بدست می آوریم که شامل مجموعه داده های Train, Test, و Validation میباشد. هریک از اینها شامل چندین سطون (`sentence1`, `sentence2`, `label`, and `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می دهند میباشد. +همانطور که می بینید یک ابجکت "DatasetDict" بدست می آوریم که شامل مجموعه داده های Train Test, و Validation میباشد. هریک از اینها شامل چندین سطون (`sentence1`, `sentence2`, `label`, and `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می دهند میباشد. As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). @@ -135,6 +135,8 @@ As you can see, we get a `DatasetDict` object which contains the training set, t This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. +ما می توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از indexing درست مانند یک dictionary دسترسی پیدا کنیم: + We can access each pair of sentences in our `raw_datasets` object by indexing, like with a dictionary: ```py From e297990bbe2c6304d4b006905b9929d4b2abf570 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 08:43:15 +0200 Subject: [PATCH 027/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index aeca47bff..5b6c40429 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -135,7 +135,7 @@ As you can see, we get a `DatasetDict` object which contains the training set, t This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. -ما می توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از indexing درست مانند یک dictionary دسترسی پیدا کنیم: +ما می توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از indexing, مانند یک dictionary دسترسی پیدا کنیم: We can access each pair of sentences in our `raw_datasets` object by indexing, like with a dictionary: @@ -151,6 +151,8 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` +ما می‌توانیم ببینم که برچسبها از پیش مقادیر عددی صحیح هستند، بنابراین نیازی به پیش پردازش آنها نداریم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، ما می‌توانیم ویژگی‌های `raw_train_dataset`‌مان را بررسی کنیم. + We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: ```py From d279e146735c9d338d3adb2b8e3a8fdf43dcdb8b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 09:03:01 +0200 Subject: [PATCH 028/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 5b6c40429..e2247f80d 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -151,7 +151,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -ما می‌توانیم ببینم که برچسبها از پیش مقادیر عددی صحیح هستند، بنابراین نیازی به پیش پردازش آنها نداریم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، ما می‌توانیم ویژگی‌های `raw_train_dataset`‌مان را بررسی کنیم. +می‌توانیم از پیش ببینم که برچسبها مقادیر عددی صحیح هستند، بنابراین نیازی به پیش پردازش آنها نداریم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، ما می‌توانیم ویژگی‌های `raw_train_dataset`‌مان را بررسی کنیم. We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: @@ -166,6 +166,8 @@ raw_train_dataset.features 'idx': Value(dtype='int32', id=None)} ``` +در پیش صحنه، `برچسب` از نوع `برچسب کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. + Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers to label name is stored in the *names* folder. `0` corresponds to `not_equivalent`, and `1` corresponds to `equivalent`. From 104acb966821eb857141dd801717c4b5ebc0c9c2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 18:15:46 +0200 Subject: [PATCH 029/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index e2247f80d..e8590aa97 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -166,12 +166,14 @@ raw_train_dataset.features 'idx': Value(dtype='int32', id=None)} ``` -در پیش صحنه، `برچسب` از نوع `برچسب کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. +در پشت صحنه، `برچسب` از نوع `برچسب کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers to label name is stored in the *names* folder. `0` corresponds to `not_equivalent`, and `1` corresponds to `equivalent`. +✏️ **خودتان امتحان کنید!** عنصر شماره ۱۵ از داده --- و عنصر شماره ۸۷ از داده --- را مشاهده کنید. برچسبهای آنها چیست؟ + ✏️ **Try it out!** Look at element 15 of the training set and element 87 of the validation set. What are their labels? From cc15095fb9df63d99e82687b75b8a6f09d851bb2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 18:22:21 +0200 Subject: [PATCH 030/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index e8590aa97..3301a3a9f 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -174,6 +174,12 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers ✏️ **خودتان امتحان کنید!** عنصر شماره ۱۵ از داده --- و عنصر شماره ۸۷ از داده --- را مشاهده کنید. برچسبهای آنها چیست؟ + + + + +✏️ **خودتان امتحان کنید!** عنصر شماره ۱۵ از داده --- و عنصر شماره ۸۷ از داده --- را مشاهده کنید. برچسبهای آنها چیست؟ + ✏️ **Try it out!** Look at element 15 of the training set and element 87 of the validation set. What are their labels? From e9e9250b63f884ec319ce34388e6bbe3244d759e Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 18:23:12 +0200 Subject: [PATCH 031/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 3301a3a9f..ad80ef599 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -172,14 +172,12 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers -✏️ **خودتان امتحان کنید!** عنصر شماره ۱۵ از داده --- و عنصر شماره ۸۷ از داده --- را مشاهده کنید. برچسبهای آنها چیست؟ +✏️ **خودتان امتحان کنید!** عنصر شماره ۱۵ از داده training و عنصر شماره ۸۷ از داده validation را مشاهده کنید. برچسبهای آنها چیست؟ -✏️ **خودتان امتحان کنید!** عنصر شماره ۱۵ از داده --- و عنصر شماره ۸۷ از داده --- را مشاهده کنید. برچسبهای آنها چیست؟ - ✏️ **Try it out!** Look at element 15 of the training set and element 87 of the validation set. What are their labels? From a98899d93f7ce919764dd91c9ad0b87654901927 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 18:29:19 +0200 Subject: [PATCH 032/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index ad80ef599..0e763c406 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -182,6 +182,8 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers +### پیش پردازشِ یک داده + ### Preprocessing a dataset {#if fw === 'pt'} @@ -190,6 +192,8 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers {/if} +به منظور پیش بردازش داد، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در فصل قبل مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم را به صورت زیر توکنایز کنیم: + To preprocess the dataset, we need to convert the text to numbers the model can make sense of. As you saw in the [previous chapter](/course/chapter2), this is done with a tokenizer. We can feed the tokenizer one sentence or a list of sentences, so we can directly tokenize all the first sentences and all the second sentences of each pair like this: ```py From 3c7526d27cb365d2c09fa4e4e7eb400b580cd146 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 18:39:46 +0200 Subject: [PATCH 033/502] new paragraph added --- chapters/fa/chapter3/2.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 0e763c406..fa5c5b229 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -192,7 +192,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers {/if} -به منظور پیش بردازش داد، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در فصل قبل مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم را به صورت زیر توکنایز کنیم: +به منظور پیش بردازش داد، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2), مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: To preprocess the dataset, we need to convert the text to numbers the model can make sense of. As you saw in the [previous chapter](/course/chapter2), this is done with a tokenizer. We can feed the tokenizer one sentence or a list of sentences, so we can directly tokenize all the first sentences and all the second sentences of each pair like this: @@ -205,6 +205,8 @@ tokenized_sentences_1 = tokenizer(raw_datasets["train"]["sentence1"]) tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"]) ``` +با این حال، نمی‌توانیم دو جمله را به مدل ارسال کنیم تا پیشبینی کند متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم، و پیش پردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکنایز می‌تواند یک جفت رشته را دریافت کند و آنرا به گونه‌ای که مدل BERT ما انتظار دارد آماده سازی کند: + However, we can't just pass two sequences to the model and get a prediction of whether the two sentences are paraphrases or not. We need to handle the two sequences as a pair, and apply the appropriate preprocessing. Fortunately, the tokenizer can also take a pair of sequences and prepare it the way our BERT model expects: ```py From f1ed412a35c288766bd4d5bfbb31119ed2fb007a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 18:40:59 +0200 Subject: [PATCH 034/502] fixed typo --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index fa5c5b229..a3be1e26d 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -192,7 +192,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers {/if} -به منظور پیش بردازش داد، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2), مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: +به منظور پیش بردازش داد، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: To preprocess the dataset, we need to convert the text to numbers the model can make sense of. As you saw in the [previous chapter](/course/chapter2), this is done with a tokenizer. We can feed the tokenizer one sentence or a list of sentences, so we can directly tokenize all the first sentences and all the second sentences of each pair like this: From 7b758748e3a0f5b075130912d066569cd300ac26 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 19:28:48 +0200 Subject: [PATCH 035/502] multiple paragraphs first draft added --- chapters/fa/chapter3/2.mdx | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index a3be1e26d..399588ba2 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -172,7 +172,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers -✏️ **خودتان امتحان کنید!** عنصر شماره ۱۵ از داده training و عنصر شماره ۸۷ از داده validation را مشاهده کنید. برچسبهای آنها چیست؟ +✏️ **امتحان کنید!** عنصر شماره ۱۵ از داده training و عنصر شماره ۸۷ از داده validation را مشاهده کنید. برچسبهای آنها چیست؟ @@ -222,26 +222,36 @@ inputs } ``` +در فصل ۲ ما در مورد `input_ids` شری `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. + We discussed the `input_ids` and `attention_mask` keys in [Chapter 2](/course/chapter2), but we put off talking about `token_type_ids`. In this example, this is what tells the model which part of the input is the first sentence and which is the second sentence. +✏️ **امتحان کنید!** عنصر شماره ۱۵ داده را بردارید و دو جمله را به صورت جداگانه و جفت توکنایز کنید. تفاوت دو نتیجه چیست؟ + ✏️ **Try it out!** Take element 15 of the training set and tokenize the two sentences separately and as a pair. What's the difference between the two results? +اگر آیدی های داخل `input_ids` را رمزگشایی کنیم: + If we decode the IDs inside `input_ids` back to words: ```py tokenizer.convert_ids_to_tokens(inputs["input_ids"]) ``` +خواهیم داشت: + we will get: ```python out ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] ``` +بنابر این می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `[CLS] sentence1 [SEP] sentence2 [SEP]` باشند. + So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] sentence2 [SEP]` when there are two sentences. Aligning this with the `token_type_ids` gives us: ```python out @@ -249,16 +259,28 @@ So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] ``` +همانطور که می‌بینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` میباشند همگی دارای آیدی نوع توکن `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند همگی دارای آیدی نوع توکن `1` میباشند. + As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` all have a token type ID of `0`, while the other parts, corresponding to `sentence2 [SEP]`, all have a token type ID of `1`. +توجه داشته باشید که اگر چکپوینت دیگری را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل میداند با آنها چکار کند، به این خاطر که آنها را در زمان پیش تعلیم دیده است. + Note that if you select a different checkpoint, you won't necessarily have the `token_type_ids` in your tokenized inputs (for instance, they're not returned if you use a DistilBERT model). They are only returned when the model will know what to do with them, because it has seen them during its pretraining. +در اینجا، --- با آیدی های نوع توکن پیش‌تعلیم شده، و در بالای هدف مدل زبانی ماسکی که در فصل --- در مورد آن صحبت کردیم، این مدل یک وظیفه دیگ تحت عنوان ---- دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد،. + Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. + در روش پیش بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده اند) به مدل داده می‌شود و از آن خواسته می‌شود که پیش بینی کند که آیا جمله دوم در ادامه جمله اول قرار دارد یا خیر.برای خارج کردن وظیفه از حالت بدیهی، در نیمی از حالتها جمله‌ها در متن اصلی به دنبال هم آمده‌اند، و در نیمی دیگر دو جمله از دو متن متفاوت می‌آیند. + With next sentence prediction, the model is provided pairs of sentences (with randomly masked tokens) and asked to predict whether the second sentence follows the first. To make the task non-trivial, half of the time the sentences follow each other in the original document they were extracted from, and the other half of the time the two sentences come from two different documents. +در مجموع، نیازی نیست نگران وجود یا عدم وجود --- در ورودی های توکنیزه شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چراکه توکنایزر میداند چه چیزی برای مدل تهیه کند. + In general, you don't need to worry about whether or not there are `token_type_ids` in your tokenized inputs: as long as you use the same checkpoint for the tokenizer and the model, everything will be fine as the tokenizer knows what to provide to its model. +اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت از جملات برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک راه برای پیش پردازشِ داده training اینگونه می‌باشد: + Now that we have seen how our tokenizer can deal with one pair of sentences, we can use it to tokenize our whole dataset: like in the [previous chapter](/course/chapter2), we can feed the tokenizer a list of pairs of sentences by giving it the list of first sentences, then the list of second sentences. This is also compatible with the padding and truncation options we saw in [Chapter 2](/course/chapter2). So, one way to preprocess the training dataset is: ```py From 5f09dc4ecdff84c1f2dfaf435032cbb21a58da33 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 21 Apr 2022 22:05:36 +0200 Subject: [PATCH 036/502] polish --- chapters/fa/chapter3/2.mdx | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 399588ba2..f79bafe58 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -25,7 +25,7 @@ {#if fw === 'pt'} - در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می دهیم: + در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می‌دهیم: ```python import torch @@ -51,7 +51,7 @@ optimizer.step() ``` {:else} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می‌دهیم: ```python import tensorflow as tf @@ -76,9 +76,9 @@ model.train_on_batch(batch, labels) {/if} -البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی داده بزرگتر خواهید داشت. +البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از داده MRPC (Microsoft Research Paraphrase Corpus) که در [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب میباشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این داده این است که داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf) نوشته William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. @@ -95,11 +95,11 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} -هاب تنها شامل مدلها نمیشود؛ بلکه شامل داده های متعدد در بسیاری زبانهای مختلف می باشد. شما میتوانید داده ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می کنیم پس از اتمام این بخش یک داده جدید را بارگذاری و پردازش کنید (بخش متون عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک بنچمارک اکادمی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ وظیفه دسته بندی متن مختلف میباشد. +هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه داده های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می کنیم پس از اتمام این بخش یک مجموعه داده جدید را دریافت و پردازش کنید (بخش متون عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. -کتابخانه داده 🤗 یک دستور بسیار ساده جهت دانلود و بارگذاری یک داده در هاب ارائه میکند. ما میتوانیم داده MRPC را به روش زیر دانلود کنیم. +کتابخانه مجموعه داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه داده در هاب ارائه میکند. ما میتوانیم مجموعه داده MRPC را به روش زیر دانلود کنیم. The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). -این دستور داده را به صورت پیش فرض در *~/.cache/huggingface/dataset* دانلود و کش میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید دایرکتوری کشتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* دانلود و ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. @@ -182,7 +182,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers -### پیش پردازشِ یک داده +### پیش پردازشِ یک مجموعه داده ### Preprocessing a dataset @@ -192,7 +192,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers {/if} -به منظور پیش بردازش داد، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: +به منظور پیش بردازش مجموعه داده، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: To preprocess the dataset, we need to convert the text to numbers the model can make sense of. As you saw in the [previous chapter](/course/chapter2), this is done with a tokenizer. We can feed the tokenizer one sentence or a list of sentences, so we can directly tokenize all the first sentences and all the second sentences of each pair like this: @@ -222,7 +222,7 @@ inputs } ``` -در فصل ۲ ما در مورد `input_ids` شری `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. +در [فصل ۲](/course/chapter2) در مورد کلیدهای `input_ids` و `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. We discussed the `input_ids` and `attention_mask` keys in [Chapter 2](/course/chapter2), but we put off talking about `token_type_ids`. In this example, this is what tells the model which part of the input is the first sentence and which is the second sentence. @@ -259,27 +259,27 @@ So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] ``` -همانطور که می‌بینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` میباشند همگی دارای آیدی نوع توکن `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند همگی دارای آیدی نوع توکن `1` میباشند. +همانطور که می‌بینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` می‌باشند همگی دارای آیدی نوع توکن `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند همگی دارای آیدی نوع توکن `1` می‌باشند. As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` all have a token type ID of `0`, while the other parts, corresponding to `sentence2 [SEP]`, all have a token type ID of `1`. -توجه داشته باشید که اگر چکپوینت دیگری را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل میداند با آنها چکار کند، به این خاطر که آنها را در زمان پیش تعلیم دیده است. +توجه داشته باشید که اگر چکپوینت دیگری را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. Note that if you select a different checkpoint, you won't necessarily have the `token_type_ids` in your tokenized inputs (for instance, they're not returned if you use a DistilBERT model). They are only returned when the model will know what to do with them, because it has seen them during its pretraining. -در اینجا، --- با آیدی های نوع توکن پیش‌تعلیم شده، و در بالای هدف مدل زبانی ماسکی که در فصل --- در مورد آن صحبت کردیم، این مدل یک وظیفه دیگ تحت عنوان ---- دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد،. +در اینجا، BERT با آیدی های نوع توکن پیش‌تعلیم شده، و در بالای هدف مدل زبانی ماسکی که در فصل --- در مورد آن صحبت کردیم، این مدل یک وظیفه دیگر تحت عنوان _next sentence prediction_ دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. - در روش پیش بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده اند) به مدل داده می‌شود و از آن خواسته می‌شود که پیش بینی کند که آیا جمله دوم در ادامه جمله اول قرار دارد یا خیر.برای خارج کردن وظیفه از حالت بدیهی، در نیمی از حالتها جمله‌ها در متن اصلی به دنبال هم آمده‌اند، و در نیمی دیگر دو جمله از دو متن متفاوت می‌آیند. + در روش پیش‌ بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شود و از آن خواسته می‌شود که پیش بینی کند آیا جمله دوم در ادامه جمله اول قرار دارد یا خیر.برای خارج کردن وظیفه از حالت بدیهی، در نیمی از حالتها جمله‌ها در متن اصلی به دنبال هم آمده‌اند، و در نیمی دیگر دو جمله از دو متن متفاوت می‌آیند. With next sentence prediction, the model is provided pairs of sentences (with randomly masked tokens) and asked to predict whether the second sentence follows the first. To make the task non-trivial, half of the time the sentences follow each other in the original document they were extracted from, and the other half of the time the two sentences come from two different documents. -در مجموع، نیازی نیست نگران وجود یا عدم وجود --- در ورودی های توکنیزه شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چراکه توکنایزر میداند چه چیزی برای مدل تهیه کند. +در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی های توکنیزه شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چراکه توکنایزر میداند چه چیزی برای مدل تهیه کند. In general, you don't need to worry about whether or not there are `token_type_ids` in your tokenized inputs: as long as you use the same checkpoint for the tokenizer and the model, everything will be fine as the tokenizer knows what to provide to its model. -اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت از جملات برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک راه برای پیش پردازشِ داده training اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل مجموعه داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک راه برای پیش پردازشِ مجموعه داده training اینگونه می‌باشد: Now that we have seen how our tokenizer can deal with one pair of sentences, we can use it to tokenize our whole dataset: like in the [previous chapter](/course/chapter2), we can feed the tokenizer a list of pairs of sentences by giving it the list of first sentences, then the list of second sentences. This is also compatible with the padding and truncation options we saw in [Chapter 2](/course/chapter2). So, one way to preprocess the training dataset is: @@ -291,9 +291,12 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` +این به خوبی کار میکند، اما مشکلش این است که یک dictionary برمیگرداند (شامل کلیدها، `input_ids`, `attention_mask`, and `token_type_ids`, و مقادیری که مجموعه ای از مجموعه ها هستند). همچنین این روش فقط زمانی کار میکند که حافظه موقت کافی جهت ذخیره سازی کل مجموعه داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه داده‌های موجود در پایگاه مجموعه داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره سازی در حافظه درخواست کردید نگه میدارید. ) This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). + + To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: ```py From cb38ccb54b3073bd4ade7167434528e5d0ab01d7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 22 Apr 2022 08:49:51 +0200 Subject: [PATCH 037/502] new paragraphs added --- chapters/fa/chapter3/2.mdx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index f79bafe58..8e48007c1 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -291,11 +291,11 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` -این به خوبی کار میکند، اما مشکلش این است که یک dictionary برمیگرداند (شامل کلیدها، `input_ids`, `attention_mask`, and `token_type_ids`, و مقادیری که مجموعه ای از مجموعه ها هستند). همچنین این روش فقط زمانی کار میکند که حافظه موقت کافی جهت ذخیره سازی کل مجموعه داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه داده‌های موجود در پایگاه مجموعه داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره سازی در حافظه درخواست کردید نگه میدارید. ) +این به خوبی کار میکند، اما مشکلش این است که یک dictionary برمیگرداند (شامل کلیدها، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیری که مجموعه ای از مجموعه ها هستند). همچنین این روش فقط زمانی کار میکند که حافظه موقت کافی جهت ذخیره سازی کل مجموعه داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه داده‌های موجود در پایگاه مجموعه داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره سازی در حافظه درخواست کردید نگه میدارید. ) This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). - +به منظور نگه داشتن داده به صورت یک مجموعه داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. این روش همچنین به ما انعطافپذیری می‌دهد چنانچه به پیش پردازشهای بیشتری نیاز داشته باشیم. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: @@ -304,8 +304,12 @@ def tokenize_function(example): return tokenizer(example["sentence1"], example["sentence2"], truncation=True) ``` +این تابع یک دیکشنری (مثل اقلام داخل مجموعه داده) دریافت میکند و دیکشنری دیگری بازمی‌گرداند با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`. توجه داشته باشید از انجایی که توکنایزر بر روی لیستهایی از جفت جمله ها کار میکند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار میکند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. + This function takes a dictionary (like the items of our dataset) and returns a new dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`. Note that it also works if the `example` dictionary contains several samples (each key as a list of sentences) since the `tokenizer` works on lists of pairs of sentences, as seen before. This will allow us to use the option `batched=True` in our call to `map()`, which will greatly speed up the tokenization. The `tokenizer` is backed by a tokenizer written in Rust from the [🤗 Tokenizers](https://github.com/huggingface/tokenizers) library. This tokenizer can be very fast, but only if we give it lots of inputs at once. + + Note that we've left the `padding` argument out in our tokenization function for now. This is because padding all the samples to the maximum length is not efficient: it's better to pad the samples when we're building a batch, as then we only need to pad to the maximum length in that batch, and not the maximum length in the entire dataset. This can save a lot of time and processing power when the inputs have very variable lengths! Here is how we apply the tokenization function on all our datasets at once. We're using `batched=True` in our call to `map` so the function is applied to multiple elements of our dataset at once, and not on each element separately. This allows for faster preprocessing. From ec10da95c14601b7fafefa2cb1ad73dfd3054f20 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 22 Apr 2022 09:16:09 +0200 Subject: [PATCH 038/502] new paragraphs added --- chapters/fa/chapter3/2.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 8e48007c1..af458dce3 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -308,16 +308,19 @@ def tokenize_function(example): This function takes a dictionary (like the items of our dataset) and returns a new dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`. Note that it also works if the `example` dictionary contains several samples (each key as a list of sentences) since the `tokenizer` works on lists of pairs of sentences, as seen before. This will allow us to use the option `batched=True` in our call to `map()`, which will greatly speed up the tokenization. The `tokenizer` is backed by a tokenizer written in Rust from the [🤗 Tokenizers](https://github.com/huggingface/tokenizers) library. This tokenizer can be very fast, but only if we give it lots of inputs at once. - +توجه داشته باشید ما مبحث `padding` را در حال حاضر کنار گذاشته ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` روی نمونه‌ها را زمانی که در حال ساختن بتچ هستیم انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بتچ انجام دهیم، و نه بیشترین طول در سرتاسر مجموعه داده. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متقیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. Note that we've left the `padding` argument out in our tokenization function for now. This is because padding all the samples to the maximum length is not efficient: it's better to pad the samples when we're building a batch, as then we only need to pad to the maximum length in that batch, and not the maximum length in the entire dataset. This can save a lot of time and processing power when the inputs have very variable lengths! +در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل مجموعه داده به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابر این تابع بر روی چندین عنصر از مجموعه داده ما به یکباره عمل می‌کند، نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش پردازش سریعتر انجام گیرد: + Here is how we apply the tokenization function on all our datasets at once. We're using `batched=True` in our call to `map` so the function is applied to multiple elements of our dataset at once, and not on each element separately. This allows for faster preprocessing. ```py tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` +کتابخانه مجموعه داده 🤗 این پیش پردازش را با افزودن -فیلدهای- جدید به مجموعه داده‌ها، یکی به ازای هر کلید در -دیکشنری- که توسط تابع پیش پردازش باز گردانده می‌شود اعمال می‌کند، The way the 🤗 Datasets library applies this processing is by adding new fields to the datasets, one for each key in the dictionary returned by the preprocessing function: From 06fc68f5b608cec259c02e6a1689fb6708cdf899 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 22 Apr 2022 10:56:35 +0200 Subject: [PATCH 039/502] new paragraphs added --- chapters/fa/chapter3/2.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index af458dce3..c7fe4f65e 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -341,10 +341,16 @@ DatasetDict({ }) ``` +شما حتی می‌توانید زمانی که تابع پیش پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایز سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش پردازش شما را سریعتر کند. + You can even use multiprocessing when applying your preprocessing function with `map()` by passing along a `num_proc` argument. We didn't do this here because the 🤗 Tokenizers library already uses multiple threads to tokenize our samples faster, but if you are not using a fast tokenizer backed by this library, this could speed up your preprocessing. +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخشهای مجموعه داده افزوده گردند. توجه داشته باشید که اگر تابع پیش پردازش ما برای یک کلید موجود در مجموعه داده که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گرداند همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. + Our `tokenize_function` returns a dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`, so those three fields are added to all splits of our dataset. Note that we could also have changed existing fields if our preprocessing function returned a new value for an existing key in the dataset to which we applied `map()`. +آخرین چیزی که نیاز داریم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر پَد کنیم - تکنیکی که ما به آن *dynamic padding* می‌گوییم. + The last thing we will need to do is pad all the examples to the length of the longest element when we batch elements together — a technique we refer to as *dynamic padding*. ### Dynamic padding From f61f8b7cf6b565fbfc08f2b481667a808c9a6829 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 22 Apr 2022 16:05:06 +0200 Subject: [PATCH 040/502] new paragraphs added --- chapters/fa/chapter3/2.mdx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c7fe4f65e..8524392aa 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -349,19 +349,26 @@ You can even use multiprocessing when applying your preprocessing function with Our `tokenize_function` returns a dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`, so those three fields are added to all splits of our dataset. Note that we could also have changed existing fields if our preprocessing function returned a new value for an existing key in the dataset to which we applied `map()`. -آخرین چیزی که نیاز داریم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر پَد کنیم - تکنیکی که ما به آن *dynamic padding* می‌گوییم. +آخرین چیزی که نیاز داریم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر پَد کنیم - تکنیکی که ما به آن *dynamic padding* (هم طول کردن پویا) می‌گوییم. The last thing we will need to do is pad all the examples to the length of the longest element when we batch elements together — a technique we refer to as *dynamic padding*. +### هم طول کردن پویا + ### Dynamic padding {#if fw === 'pt'} + +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم طول سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم طول سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم طول سازی اضافه داشته باشد. + The function that is responsible for putting together samples inside a batch is called a *collate function*. It's an argument you can pass when you build a `DataLoader`, the default being a function that will just convert your samples to PyTorch tensors and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. {:else} +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم طول سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم طول سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم طول سازی اضافه داشته باشد. + The function that is responsible for putting together samples inside a batch is called a *collate function*. The default collator is a function that will just convert your samples to tf.Tensor and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. {/if} From 7f2a8bbb24659506a89f01e6989c73d8aef56ffc Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 22 Apr 2022 17:14:41 +0200 Subject: [PATCH 041/502] first draft done. --- chapters/fa/chapter3/2.mdx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 8524392aa..51c2598f2 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -349,7 +349,7 @@ You can even use multiprocessing when applying your preprocessing function with Our `tokenize_function` returns a dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`, so those three fields are added to all splits of our dataset. Note that we could also have changed existing fields if our preprocessing function returned a new value for an existing key in the dataset to which we applied `map()`. -آخرین چیزی که نیاز داریم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر پَد کنیم - تکنیکی که ما به آن *dynamic padding* (هم طول کردن پویا) می‌گوییم. +آخرین چیزی که نیاز داریم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر پَد کنیم - تکنیکی که ما به آن *dynamic padding* (همطول سازی پویا) می‌گوییم. The last thing we will need to do is pad all the examples to the length of the longest element when we batch elements together — a technique we refer to as *dynamic padding*. @@ -373,6 +373,8 @@ The function that is responsible for putting together samples inside a batch is {/if} +برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم طول سازی را به آیتمهای مجموعه داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا معرفی کنید (که چه توکنی برای همطول سازی استفاده کند، و اینکه مدل انتظار همطول سازی از سمت چپ ورودی‌ها را دارد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: + To do this in practice, we have to define a collate function that will apply the correct amount of padding to the items of the dataset we want to batch together. Fortunately, the 🤗 Transformers library provides us with such a function via `DataCollatorWithPadding`. It takes a tokenizer when you instantiate it (to know which padding token to use, and whether the model expects padding to be on the left or on the right of the inputs) and will do everything you need: {#if fw === 'pt'} @@ -389,6 +391,8 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf" ``` {/if} +اجازه دهید چند نمونه از مجموعه training مان، که می‌خواهیم باهم بَتچ کنیم، برداریم تا این ابزار جدید را امتحان کنیم. در اینجا سطون‌های -، --، و --- را خذف می‌کنیم چراکه احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (و ما نمی‌توانیم تنسورهایی با رشته های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: + To test this new toy, let's grab a few samples from our training set that we would like to batch together. Here, we remove the columns `idx`, `sentence1`, and `sentence2` as they won't be needed and contain strings (and we can't create tensors with strings) and have a look at the lengths of each entry in the batch: ```py @@ -401,6 +405,8 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se [50, 59, 47, 67, 59, 50, 62, 32] ``` +تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. همطول سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، همطول شده باشند. بدون همطول سازی پویا، همه نمونه‌ها در کل مجموعه داده باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، همطول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی همطول می‌کند: + No surprise, we get samples of varying length, from 32 to 67. Dynamic padding means the samples in this batch should all be padded to a length of 67, the maximum length inside the batch. Without dynamic padding, all of the samples would have to be padded to the maximum length in the whole dataset, or the maximum length the model can accept. Let's double-check that our `data_collator` is dynamically padding the batch properly: ```py @@ -426,18 +432,24 @@ batch = data_collator(samples) 'labels': torch.Size([8])} ``` +به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل مان می‌تواند با آنها کار کند، آماده هستیم برای انجام بازتنظیم مدل: + Looking good! Now that we've gone from raw text to batches our model can deal with, we're ready to fine-tune it! {/if} +✏️ **امتحان کنید!** پروسه پیش بردازش را روی مجموعه داده GLUE SST-2 باز تکرار کنید. این یک مقدار متفاوت است از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد، اما بقیه کارهایی که انجام دادیم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. + ✏️ **Try it out!** Replicate the preprocessing on the GLUE SST-2 dataset. It's a little bit different since it's composed of single sentences instead of pairs, but the rest of what we did should look the same. For a harder challenge, try to write a preprocessing function that works on any of the GLUE tasks. {#if fw === 'tf'} +توجه داشته باشید که ما مجموعه‌ داده مان و یک collator داریم، حال نیاز داریم که آنها را بهم وصل کنیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این کار زیادی می‌برد و احتمالا خیلی بهینه هم نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور مجموعه داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه داده‌مان مشاهده کنیم! + Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! ```py @@ -458,6 +470,8 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` +این هم از این! ما می‌توانی آن مجموعه داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختیهای پروسه پیش پردازش به طرز خوشایندی سرراست خواهد بود. + And that's it! We can take those datasets forward into the next lecture, where training will be pleasantly straightforward after all the hard work of data preprocessing. {/if} From f5aa7689d0c6f25d0ccfc49c6f32f1a31c47362d Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 09:56:44 +0200 Subject: [PATCH 042/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 51c2598f2..07112d48c 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -25,7 +25,7 @@ {#if fw === 'pt'} - در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بَتچ توسط pytorch را شرح می‌دهیم: ```python import torch @@ -78,7 +78,7 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf) نوشته William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، MRPC نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. From a93d7a20555992a33cfb9228a6ea85bd3f53ee8c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 09:57:52 +0200 Subject: [PATCH 043/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 07112d48c..ee1fb467c 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,7 +78,7 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، MRPC نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده (Microsoft Research Paraphrase Corpus) MRPC که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. From ede676eeff9ef15dd011c1b572ea9132e01de84f Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 09:58:49 +0200 Subject: [PATCH 044/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index ee1fb467c..5252a0ea9 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,7 +78,7 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده (Microsoft Research Paraphrase Corpus) MRPC که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. From 113d77aa2d118ee72a17716059df2731bf7a0ae9 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 09:59:48 +0200 Subject: [PATCH 045/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 5252a0ea9..ee1fb467c 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,7 +78,7 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده (Microsoft Research Paraphrase Corpus) MRPC که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. From 2f4a662264bfd44bcaeab89546ac96d1f7341a76 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:00:58 +0200 Subject: [PATCH 046/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index ee1fb467c..c22ac970a 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,7 +78,7 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده (Microsoft Research Paraphrase Corpus) MRPC که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده MRPC یا (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. From 4dd8c5def92ab4a50326f259c45f0c4bfa872887 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:01:46 +0200 Subject: [PATCH 047/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c22ac970a..5252a0ea9 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,7 +78,7 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده MRPC یا (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. From 33c8b39612aa7960d903ad0c2be854d1b6f45739 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:02:26 +0200 Subject: [PATCH 048/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 5252a0ea9..bd9e9d859 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,7 +78,7 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett. معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. From 54a7614bd287cf60c7c3f2c6bfd63eb8cd12927c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:15:46 +0200 Subject: [PATCH 049/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index bd9e9d859..d90da1c68 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -78,14 +78,14 @@ model.train_on_batch(batch, labels) البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) است. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. In this section we will use as an example the MRPC (Microsoft Research Paraphrase Corpus) dataset, introduced in a [paper](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. The dataset consists of 5,801 pairs of sentences, with a label indicating if they are paraphrases or not (i.e., if both sentences mean the same thing). We've selected it for this chapter because it's a small dataset, so it's easy to experiment with training on it. -### بارگذاری داده از هاب +### بارگذاری یک داده از هاب ### Loading a dataset from the Hub @@ -95,11 +95,11 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} -هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه داده های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می کنیم پس از اتمام این بخش یک مجموعه داده جدید را دریافت و پردازش کنید (بخش متون عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. +هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه داده‌های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. -کتابخانه مجموعه داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه داده در هاب ارائه میکند. ما میتوانیم مجموعه داده MRPC را به روش زیر دانلود کنیم. +کتابخانه مجموعه داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه داده در هاب ارائه میکند. ما میتوانیم مجموعه داده MRPC را به روش زیر دانلود کنیم: The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک ابجکت "DatasetDict" بدست می آوریم که شامل مجموعه داده های Train Test, و Validation میباشد. هریک از اینها شامل چندین سطون (`sentence1`, `sentence2`, `label`, and `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می دهند میباشد. +همانطور که می بینید یک شیء "DatasetDict" بدست می آوریم که شامل مجموعه داده‌های Train، Test، و Validation می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، `sentence2`، `label`، and `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From 56ed2ea801feb76650b7616583993cad49879cb2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:18:21 +0200 Subject: [PATCH 050/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index d90da1c68..72cabfe2f 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می آوریم که شامل مجموعه داده‌های Train، Test، و Validation می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، `sentence2`، `label`، and `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). +همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه داده‌های Train، Test، و Validation می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، `sentence2`، `label`، و `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From e342854b21f64b794d5f83369727947eedb86db7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:21:33 +0200 Subject: [PATCH 051/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 72cabfe2f..f131ded76 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه داده‌های Train، Test، و Validation می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، `sentence2`، `label`، و `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). +همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، `sentence2`، `label`، و `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From c28091e7ba787e8307c02536bb7dc37fa5a82d45 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:24:44 +0200 Subject: [PATCH 052/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index f131ded76..717195c66 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، `sentence2`، `label`، و `idx`) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). +همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (-، --، ---، و ----) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From da86f2a9f47b51d6732939789692aec946ebb7a0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:25:54 +0200 Subject: [PATCH 053/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 717195c66..428486c49 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (-، --، ---، و ----) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). +همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، --، ---، و ----) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From c9680ebe411ca411459e676d85bba820ebdbef5b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:26:34 +0200 Subject: [PATCH 054/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 428486c49..5d225f4ad 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، --، ---، و ----) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). +همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، `sentence2`، ---، و ----) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From a27f1ba4737e88263b14007a1faa4c2314ad7a6b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:28:59 +0200 Subject: [PATCH 055/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 5d225f4ad..45f0c1efe 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`sentence1`، `sentence2`، ---، و ----) و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). +همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`label`، `sentence2`، `sentence1`، و `idx` و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From 66efcf3ae8c8ebb5bd40aac2eaa128c02afc8d18 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 24 Apr 2022 10:30:42 +0200 Subject: [PATCH 056/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 45f0c1efe..51f17ed03 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`label`، `sentence2`، `sentence1`، و `idx` و تعداد متغیری ردیف داده که تعداد عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test وجود دارند.). +همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`label`، `sentence2`، `sentence1`، و `idx`) و تعداد متغیری ردیف داده که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training وجود دارد، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test.). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From 2b0e4a600fc82bae81e6a0cafb511c0d2ea30819 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:33:08 +0200 Subject: [PATCH 057/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 51f17ed03..cc3984948 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -127,7 +127,7 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`label`، `sentence2`، `sentence1`، و `idx`) و تعداد متغیری ردیف داده که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training وجود دارد، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test.). +همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`label`، `sentence2`، `sentence1`، و `idx`) و تعداد متغیری ردیف داده که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training وجود دارد، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test). As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). From af4de38f6010f2b9190cec718bc2a6ec05a2bd82 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:40:27 +0200 Subject: [PATCH 058/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index cc3984948..21fd54fd6 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* دانلود و ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. From 9c1276fa0be704d32dd9cb42df26a88a9f33df0b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:42:07 +0200 Subject: [PATCH 059/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 21fd54fd6..d5a4a7694 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. From 5b79da9a816b76515ed150550c4a1b3e1b79d16c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:43:26 +0200 Subject: [PATCH 060/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index d5a4a7694..cf18eba9f 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *dataset/huggingface/.cache/~* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. From b0fd16396b9c73cac21335c6f31d5b54cea24c3e Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:45:00 +0200 Subject: [PATCH 061/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index cf18eba9f..1b0f22ed1 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *dataset/huggingface/.cache/~* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. From 217073a21d55f37b286bf5fd1a09d68e99788ddb Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:46:11 +0200 Subject: [PATCH 062/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 1b0f22ed1..294372d99 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی */.cache/huggingface/dataset~* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. From 1a6bd700a16e245a09fe66eff10c6c97c0f64f22 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:49:20 +0200 Subject: [PATCH 063/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 294372d99..0e46cdf29 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی */.cache/huggingface/dataset~* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *`~/.cache/huggingface/dataset`* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. From 15f7f953fbdd9688edccb9b6ed0f64eb90736ddf Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:50:51 +0200 Subject: [PATCH 064/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 0e46cdf29..1b0f22ed1 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *`~/.cache/huggingface/dataset`* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. From a4c9c1782fdaace56b71588b18f6747d6e3fd4a6 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 08:58:33 +0200 Subject: [PATCH 065/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 1b0f22ed1..b588825e3 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -131,11 +131,11 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که شما میتوانید زیرشاخه‌ی ذخیره سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. -ما می توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از indexing, مانند یک dictionary دسترسی پیدا کنیم: +ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از شماره‌گذاری, مانند یک dictionary دسترسی پیدا کنیم: We can access each pair of sentences in our `raw_datasets` object by indexing, like with a dictionary: From 868402c2e1f6f3604eed056903b00e1c196b26b1 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 09:06:12 +0200 Subject: [PATCH 066/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index b588825e3..494bc9957 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -99,7 +99,7 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. -کتابخانه مجموعه داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه داده در هاب ارائه میکند. ما میتوانیم مجموعه داده MRPC را به روش زیر دانلود کنیم: +کتابخانه مجموعه داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه داده در هاب ارائه می‌کند. ما می‌توانیم مجموعه داده MRPC را به روش زیر دانلود کنیم: The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: @@ -151,7 +151,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌توانیم از پیش ببینم که برچسبها مقادیر عددی صحیح هستند، بنابراین نیازی به پیش پردازش آنها نداریم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، ما می‌توانیم ویژگی‌های `raw_train_dataset`‌مان را بررسی کنیم. +می‌توانیم از پیش ببینم که برچسبها مقادیر عددی صحیح هستند، بنابراین نیازی به پیش پردازش آنها نداریم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: From 4598b69bf80829b16e14702303024b55798d29a7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 09:12:19 +0200 Subject: [PATCH 067/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 494bc9957..a26f3c77c 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -151,7 +151,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌توانیم از پیش ببینم که برچسبها مقادیر عددی صحیح هستند، بنابراین نیازی به پیش پردازش آنها نداریم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. +می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی در آنجا انجام دهیم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: From 87942d6c092ffbf519b13637fffcc63f7b3b7242 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 09:18:30 +0200 Subject: [PATCH 068/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index a26f3c77c..50f50c9fc 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -234,7 +234,7 @@ We discussed the `input_ids` and `attention_mask` keys in [Chapter 2](/course/ch -اگر آیدی های داخل `input_ids` را رمزگشایی کنیم: +اگر آیدی های داخل `input_ids` را به کلمات رمزگشایی کنیم: If we decode the IDs inside `input_ids` back to words: @@ -250,7 +250,7 @@ we will get: ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] ``` -بنابر این می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `[CLS] sentence1 [SEP] sentence2 [SEP]` باشند. +بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `sentence1 [SEP] sentence2 [SEP] [CLS]` باشند. So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] sentence2 [SEP]` when there are two sentences. Aligning this with the `token_type_ids` gives us: From 1971f779f972ac80b3cb47ffcbfe7e5dd2ed4609 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 09:19:24 +0200 Subject: [PATCH 069/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 50f50c9fc..bbbff15b5 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -250,7 +250,7 @@ we will get: ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] ``` -بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `sentence1 [SEP] sentence2 [SEP] [CLS]` باشند. +بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `[CLS] sentence1 [SEP] sentence2 [SEP]` باشند. So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] sentence2 [SEP]` when there are two sentences. Aligning this with the `token_type_ids` gives us: From a1d8859afcb8ad6b8aace09b3f611521e1306333 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 09:20:54 +0200 Subject: [PATCH 070/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index bbbff15b5..50f50c9fc 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -250,7 +250,7 @@ we will get: ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] ``` -بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `[CLS] sentence1 [SEP] sentence2 [SEP]` باشند. +بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `sentence1 [SEP] sentence2 [SEP] [CLS]` باشند. So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] sentence2 [SEP]` when there are two sentences. Aligning this with the `token_type_ids` gives us: From b5ebbc96095b4336c2551e58e041c76ae6c0ea2d Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 09:23:12 +0200 Subject: [PATCH 071/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 50f50c9fc..b622527cb 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -250,7 +250,7 @@ we will get: ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] ``` -بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `sentence1 [SEP] sentence2 [SEP] [CLS]` باشند. +بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `a [CLS] sentence1 [SEP] sentence2 [SEP]` باشند. So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] sentence2 [SEP]` when there are two sentences. Aligning this with the `token_type_ids` gives us: From 4811b944bf166d551c229ae33c2a2f022d243dc5 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 11:30:20 +0200 Subject: [PATCH 072/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index b622527cb..c606aa67f 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -250,7 +250,7 @@ we will get: ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] ``` -بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `a [CLS] sentence1 [SEP] sentence2 [SEP]` باشند. +بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `[CLS] sentence1 [SEP] sentence2 [SEP]` باشند. So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] sentence2 [SEP]` when there are two sentences. Aligning this with the `token_type_ids` gives us: @@ -259,7 +259,7 @@ So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] ``` -همانطور که می‌بینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` می‌باشند همگی دارای آیدی نوع توکن `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند همگی دارای آیدی نوع توکن `1` می‌باشند. +همانطور که می‌بینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` می‌باشند آیدی نشاندهنده نوع توکِن آنها `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند آیدی نشاندهنده نوع توکِن آنها `1` می‌باشند. As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` all have a token type ID of `0`, while the other parts, corresponding to `sentence2 [SEP]`, all have a token type ID of `1`. @@ -267,7 +267,7 @@ As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` Note that if you select a different checkpoint, you won't necessarily have the `token_type_ids` in your tokenized inputs (for instance, they're not returned if you use a DistilBERT model). They are only returned when the model will know what to do with them, because it has seen them during its pretraining. -در اینجا، BERT با آیدی های نوع توکن پیش‌تعلیم شده، و در بالای هدف مدل زبانی ماسکی که در فصل --- در مورد آن صحبت کردیم، این مدل یک وظیفه دیگر تحت عنوان _next sentence prediction_ دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. +در اینجا، BERT با آیدی های نوع توکن پیش‌تعلیم شده، و در بالای هدف مدل زبانی ماسکی که در [فصل 1](/course/chapter1) در مورد آن صحبت کردیم، این مدل یک وظیفه دیگر تحت عنوان _next sentence prediction_ دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. From cc392b970a97ae8e9cd6555d570e4163a766654a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 11:31:39 +0200 Subject: [PATCH 073/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c606aa67f..bb6406e07 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -151,7 +151,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی در آنجا انجام دهیم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. +می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: From a6b5e07ffcf274cefd28384864298a3a4bc97683 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 11:52:39 +0200 Subject: [PATCH 074/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index bb6406e07..e154869c3 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -151,7 +151,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. +می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: @@ -166,7 +166,7 @@ raw_train_dataset.features 'idx': Value(dtype='int32', id=None)} ``` -در پشت صحنه، `برچسب` از نوع `برچسب کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. +در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers to label name is stored in the *names* folder. `0` corresponds to `not_equivalent`, and `1` corresponds to `equivalent`. @@ -182,7 +182,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers -### پیش پردازشِ یک مجموعه داده +### پیش‌پردازشِ یک مجموعه داده ### Preprocessing a dataset @@ -192,7 +192,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers {/if} -به منظور پیش بردازش مجموعه داده، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: +به منظور پیش‌پردازش مجموعه داده، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: To preprocess the dataset, we need to convert the text to numbers the model can make sense of. As you saw in the [previous chapter](/course/chapter2), this is done with a tokenizer. We can feed the tokenizer one sentence or a list of sentences, so we can directly tokenize all the first sentences and all the second sentences of each pair like this: @@ -205,7 +205,7 @@ tokenized_sentences_1 = tokenizer(raw_datasets["train"]["sentence1"]) tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"]) ``` -با این حال، نمی‌توانیم دو جمله را به مدل ارسال کنیم تا پیشبینی کند متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم، و پیش پردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکنایز می‌تواند یک جفت رشته را دریافت کند و آنرا به گونه‌ای که مدل BERT ما انتظار دارد آماده سازی کند: +با این حال، نمی‌توانیم دو جمله را به مدل ارسال کنیم تا پیش‌بینی کند متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم، و پیش‌پردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکنایزر می‌تواند یک جفت رشته را دریافت کند و آنرا به گونه‌ای که مدل BERT ما انتظار دارد آماده سازی کند: However, we can't just pass two sequences to the model and get a prediction of whether the two sentences are paraphrases or not. We need to handle the two sequences as a pair, and apply the appropriate preprocessing. Fortunately, the tokenizer can also take a pair of sequences and prepare it the way our BERT model expects: @@ -222,7 +222,7 @@ inputs } ``` -در [فصل ۲](/course/chapter2) در مورد کلیدهای `input_ids` و `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. +در [فصل ۲](/course/chapter2) در مورد کلیدهای `input_ids` و `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی، جمله اول و کدام بخش جمله دوم است. We discussed the `input_ids` and `attention_mask` keys in [Chapter 2](/course/chapter2), but we put off talking about `token_type_ids`. In this example, this is what tells the model which part of the input is the first sentence and which is the second sentence. @@ -259,15 +259,15 @@ So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] ``` -همانطور که می‌بینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` می‌باشند آیدی نشاندهنده نوع توکِن آنها `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند آیدی نشاندهنده نوع توکِن آنها `1` می‌باشند. +همانطور که می‌بینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` هستند آیدی نشاندهنده نوع توکِن آنها `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند آیدی نشاندهنده نوع توکِن‌شان `1` می‌باشد. As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` all have a token type ID of `0`, while the other parts, corresponding to `sentence2 [SEP]`, all have a token type ID of `1`. -توجه داشته باشید که اگر چکپوینت دیگری را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. +توجه داشته باشید که اگر چکپوینت متفاوتی را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. Note that if you select a different checkpoint, you won't necessarily have the `token_type_ids` in your tokenized inputs (for instance, they're not returned if you use a DistilBERT model). They are only returned when the model will know what to do with them, because it has seen them during its pretraining. -در اینجا، BERT با آیدی های نوع توکن پیش‌تعلیم شده، و در بالای هدف مدل زبانی ماسکی که در [فصل 1](/course/chapter1) در مورد آن صحبت کردیم، این مدل یک وظیفه دیگر تحت عنوان _next sentence prediction_ دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. +در اینجا، مدل BERT با آیدی‌هایی که نشاندهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف masked language modeling که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنان _next sentence prediction_ برعهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. From 0bcc2f6c0ef3c3a39113053b2792aa8fc7819c36 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:01:57 +0200 Subject: [PATCH 075/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index e154869c3..0378e831d 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -267,11 +267,11 @@ As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` Note that if you select a different checkpoint, you won't necessarily have the `token_type_ids` in your tokenized inputs (for instance, they're not returned if you use a DistilBERT model). They are only returned when the model will know what to do with them, because it has seen them during its pretraining. -در اینجا، مدل BERT با آیدی‌هایی که نشاندهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف masked language modeling که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنان _next sentence prediction_ برعهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. +در اینجا، مدل BERT با آیدی‌هایی که نشاندهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبان ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ برعهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. - در روش پیش‌ بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شود و از آن خواسته می‌شود که پیش بینی کند آیا جمله دوم در ادامه جمله اول قرار دارد یا خیر.برای خارج کردن وظیفه از حالت بدیهی، در نیمی از حالتها جمله‌ها در متن اصلی به دنبال هم آمده‌اند، و در نیمی دیگر دو جمله از دو متن متفاوت می‌آیند. + در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ی جمله‌ی اول قرار دارد یا خیر. برای خارج کردن وظیفه از حالت بدیهی، در نیمی از حالتها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. With next sentence prediction, the model is provided pairs of sentences (with randomly masked tokens) and asked to predict whether the second sentence follows the first. To make the task non-trivial, half of the time the sentences follow each other in the original document they were extracted from, and the other half of the time the two sentences come from two different documents. From edc0f359608a8bb02567624d6a9d2dc2cbf43077 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:08:51 +0200 Subject: [PATCH 076/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 0378e831d..786a5355f 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -271,15 +271,15 @@ Note that if you select a different checkpoint, you won't necessarily have the ` Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. - در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ی جمله‌ی اول قرار دارد یا خیر. برای خارج کردن وظیفه از حالت بدیهی، در نیمی از حالتها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. + در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ی جمله‌ی اول قرار دارد یا خیر. برای خارج کردن مسئله از حالت بدیهی، در نیمی از حالتها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. With next sentence prediction, the model is provided pairs of sentences (with randomly masked tokens) and asked to predict whether the second sentence follows the first. To make the task non-trivial, half of the time the sentences follow each other in the original document they were extracted from, and the other half of the time the two sentences come from two different documents. -در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی های توکنیزه شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چراکه توکنایزر میداند چه چیزی برای مدل تهیه کند. +در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی های توکنیزه شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکنایزر می‌داند چه چیزی برای مدل فراهم کند. In general, you don't need to worry about whether or not there are `token_type_ids` in your tokenized inputs: as long as you use the same checkpoint for the tokenizer and the model, everything will be fine as the tokenizer knows what to provide to its model. -اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل مجموعه داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک راه برای پیش پردازشِ مجموعه داده training اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل مجموعه داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک راه برای پیش پردازشِ مجموعه داده‌ی training اینگونه می‌باشد: Now that we have seen how our tokenizer can deal with one pair of sentences, we can use it to tokenize our whole dataset: like in the [previous chapter](/course/chapter2), we can feed the tokenizer a list of pairs of sentences by giving it the list of first sentences, then the list of second sentences. This is also compatible with the padding and truncation options we saw in [Chapter 2](/course/chapter2). So, one way to preprocess the training dataset is: @@ -291,7 +291,7 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` -این به خوبی کار میکند، اما مشکلش این است که یک dictionary برمیگرداند (شامل کلیدها، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیری که مجموعه ای از مجموعه ها هستند). همچنین این روش فقط زمانی کار میکند که حافظه موقت کافی جهت ذخیره سازی کل مجموعه داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه داده‌های موجود در پایگاه مجموعه داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره سازی در حافظه درخواست کردید نگه میدارید. ) +این به خوبی کار میکند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقدار‌ها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل مجموعه داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه داده‌های موجود در پایگاه مجموعه داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره سازی در حافظه درخواست کرده‌اید نگه می‌دارید. ) This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). From c3cf4e79cc853446d35a1ffe327139ac7ca9ddd2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:16:08 +0200 Subject: [PATCH 077/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 786a5355f..bf35fb0e9 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -95,7 +95,7 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} -هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه داده‌های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. +هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. @@ -151,7 +151,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. +می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه‌داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: @@ -267,19 +267,19 @@ As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` Note that if you select a different checkpoint, you won't necessarily have the `token_type_ids` in your tokenized inputs (for instance, they're not returned if you use a DistilBERT model). They are only returned when the model will know what to do with them, because it has seen them during its pretraining. -در اینجا، مدل BERT با آیدی‌هایی که نشاندهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبان ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ برعهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. +در اینجا، مدل BERT با آیدی‌هایی که نشاندهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبانِ ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ برعهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. - در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ی جمله‌ی اول قرار دارد یا خیر. برای خارج کردن مسئله از حالت بدیهی، در نیمی از حالتها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. + در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ جمله‌ اول قرار دارد یا خیر. برای خارج کردن مسئله از حالت بدیهی، در نیمی از حالتها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. With next sentence prediction, the model is provided pairs of sentences (with randomly masked tokens) and asked to predict whether the second sentence follows the first. To make the task non-trivial, half of the time the sentences follow each other in the original document they were extracted from, and the other half of the time the two sentences come from two different documents. -در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی های توکنیزه شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکنایزر می‌داند چه چیزی برای مدل فراهم کند. +در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکنایز شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکنایزر می‌داند چه چیزی برای مدل فراهم کند. In general, you don't need to worry about whether or not there are `token_type_ids` in your tokenized inputs: as long as you use the same checkpoint for the tokenizer and the model, everything will be fine as the tokenizer knows what to provide to its model. -اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل مجموعه داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک راه برای پیش پردازشِ مجموعه داده‌ی training اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل مجموعه‌داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ مجموعه‌داده‌ی training اینگونه می‌باشد: Now that we have seen how our tokenizer can deal with one pair of sentences, we can use it to tokenize our whole dataset: like in the [previous chapter](/course/chapter2), we can feed the tokenizer a list of pairs of sentences by giving it the list of first sentences, then the list of second sentences. This is also compatible with the padding and truncation options we saw in [Chapter 2](/course/chapter2). So, one way to preprocess the training dataset is: @@ -291,7 +291,7 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` -این به خوبی کار میکند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقدار‌ها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل مجموعه داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه داده‌های موجود در پایگاه مجموعه داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره سازی در حافظه درخواست کرده‌اید نگه می‌دارید. ) +این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل مجموعه‌داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه‌داده‌های موجود در پایگاه مجموعه‌داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره سازی در حافظه درخواست کرده‌اید نگه می‌دارید. ) This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). @@ -320,7 +320,7 @@ Here is how we apply the tokenization function on all our datasets at once. We'r tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -کتابخانه مجموعه داده 🤗 این پیش پردازش را با افزودن -فیلدهای- جدید به مجموعه داده‌ها، یکی به ازای هر کلید در -دیکشنری- که توسط تابع پیش پردازش باز گردانده می‌شود اعمال می‌کند، +کتابخانه مجموعه داده 🤗 این پیش پردازش را با افزودن -فیلدهای- جدید به مجموعه‌داده‌ها، یکی به ازای هر کلید در -دیکشنری- که توسط تابع پیش پردازش باز گردانده می‌شود اعمال می‌کند، The way the 🤗 Datasets library applies this processing is by adding new fields to the datasets, one for each key in the dictionary returned by the preprocessing function: @@ -373,7 +373,7 @@ The function that is responsible for putting together samples inside a batch is {/if} -برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم طول سازی را به آیتمهای مجموعه داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا معرفی کنید (که چه توکنی برای همطول سازی استفاده کند، و اینکه مدل انتظار همطول سازی از سمت چپ ورودی‌ها را دارد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم طول سازی را به آیتمهای مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا معرفی کنید (که چه توکنی برای همطول سازی استفاده کند، و اینکه مدل انتظار همطول سازی از سمت چپ ورودی‌ها را دارد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: To do this in practice, we have to define a collate function that will apply the correct amount of padding to the items of the dataset we want to batch together. Fortunately, the 🤗 Transformers library provides us with such a function via `DataCollatorWithPadding`. It takes a tokenizer when you instantiate it (to know which padding token to use, and whether the model expects padding to be on the left or on the right of the inputs) and will do everything you need: @@ -448,7 +448,7 @@ Looking good! Now that we've gone from raw text to batches our model can deal wi {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌ داده مان و یک collator داریم، حال نیاز داریم که آنها را بهم وصل کنیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این کار زیادی می‌برد و احتمالا خیلی بهینه هم نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور مجموعه داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه داده‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌ داده مان و یک collator داریم، حال نیاز داریم که آنها را بهم وصل کنیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این کار زیادی می‌برد و احتمالا خیلی بهینه هم نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! @@ -470,7 +470,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -این هم از این! ما می‌توانی آن مجموعه داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختیهای پروسه پیش پردازش به طرز خوشایندی سرراست خواهد بود. +این هم از این! ما می‌توانی آن مجموعه‌داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختیهای پروسه پیش پردازش به طرز خوشایندی سرراست خواهد بود. And that's it! We can take those datasets forward into the next lecture, where training will be pleasantly straightforward after all the hard work of data preprocessing. From c0a6bd929e47d601032d6a7afdf5a7d208b2c8a0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:19:50 +0200 Subject: [PATCH 078/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index bf35fb0e9..cd3792401 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -295,7 +295,7 @@ tokenized_dataset = tokenizer( This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). -به منظور نگه داشتن داده به صورت یک مجموعه داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. این روش همچنین به ما انعطافپذیری می‌دهد چنانچه به پیش پردازشهای بیشتری نیاز داشته باشیم. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازشهای بیشتری علاوه‌بر توکنیزشن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: From 234ef87bd387f687a0e48d968ac12acc4bf01df4 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:22:25 +0200 Subject: [PATCH 079/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index cd3792401..715f933c7 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -295,7 +295,7 @@ tokenized_dataset = tokenizer( This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). -به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازشهای بیشتری علاوه‌بر توکنیزشن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map()` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: From 1e5ecfe24511502343e7ff09b0c7376f88b0db66 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:22:55 +0200 Subject: [PATCH 080/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 715f933c7..32c6a4a73 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -295,7 +295,7 @@ tokenized_dataset = tokenizer( This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). -به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map()` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.()map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: From b9080795c3ebcbdb4ecd71c79fa3d4e956922fd2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:23:20 +0200 Subject: [PATCH 081/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 32c6a4a73..06bfbc9e2 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -295,7 +295,7 @@ tokenized_dataset = tokenizer( This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). -به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.()map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: From 28e160db630268daa2f918b29325edfdaa483fc0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:24:13 +0200 Subject: [PATCH 082/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 06bfbc9e2..587078b0f 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -295,7 +295,7 @@ tokenized_dataset = tokenizer( This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). -به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: From d6aa6d632878da889deed1d3156bfb4da10027e8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:25:04 +0200 Subject: [PATCH 083/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 587078b0f..c600f9f8d 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -295,7 +295,7 @@ tokenized_dataset = tokenizer( This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). -به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: @@ -304,7 +304,7 @@ def tokenize_function(example): return tokenizer(example["sentence1"], example["sentence2"], truncation=True) ``` -این تابع یک دیکشنری (مثل اقلام داخل مجموعه داده) دریافت میکند و دیکشنری دیگری بازمی‌گرداند با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`. توجه داشته باشید از انجایی که توکنایزر بر روی لیستهایی از جفت جمله ها کار میکند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار میکند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. +این تابع یک دیکشنری (مثل اقلام داخل مجموعه داده) دریافت میکند و دیکشنری دیگری بازمی‌گرداند با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`. توجه داشته باشید از انجایی که توکنایزر بر روی لیستهایی از جفت جمله ها کار میکند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار میکند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `()map` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. This function takes a dictionary (like the items of our dataset) and returns a new dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`. Note that it also works if the `example` dictionary contains several samples (each key as a list of sentences) since the `tokenizer` works on lists of pairs of sentences, as seen before. This will allow us to use the option `batched=True` in our call to `map()`, which will greatly speed up the tokenization. The `tokenizer` is backed by a tokenizer written in Rust from the [🤗 Tokenizers](https://github.com/huggingface/tokenizers) library. This tokenizer can be very fast, but only if we give it lots of inputs at once. From 5b852113c6e97784f61206ad13a15c942aba74a7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:37:26 +0200 Subject: [PATCH 084/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c600f9f8d..cf5e0cdb5 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -76,9 +76,9 @@ model.train_on_batch(batch, labels) {/if} -البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه داده بزرگتر خواهید داشت. +البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه‌داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه داده این است که مجموعه داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه‌داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه‌داده این است که مجموعه‌داده کوچکیست و تجربه آموزش دادن روی آن آسان است. Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. @@ -95,11 +95,11 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} -هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. +هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه‌داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. -کتابخانه مجموعه داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه داده در هاب ارائه می‌کند. ما می‌توانیم مجموعه داده MRPC را به روش زیر دانلود کنیم: +کتابخانه مجموعه‌داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه‌داده در هاب ارائه می‌کند. ما می‌توانیم مجموعه‌داده MRPC را به روش زیر دانلود کنیم: The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: @@ -131,7 +131,7 @@ DatasetDict({ As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور مجموعه‌داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. @@ -182,7 +182,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers -### پیش‌پردازشِ یک مجموعه داده +### پیش‌پردازشِ یک مجموعه‌داده ### Preprocessing a dataset @@ -192,7 +192,7 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers {/if} -به منظور پیش‌پردازش مجموعه داده، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: +به منظور پیش‌پردازش مجموعه‌داده، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: To preprocess the dataset, we need to convert the text to numbers the model can make sense of. As you saw in the [previous chapter](/course/chapter2), this is done with a tokenizer. We can feed the tokenizer one sentence or a list of sentences, so we can directly tokenize all the first sentences and all the second sentences of each pair like this: @@ -295,7 +295,7 @@ tokenized_dataset = tokenizer( This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). -به منظور نگه داشتن داده به صورت یک مجموعه‌داده از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه داده عمل میکند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک مجموعه‌داده، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه‌داده عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکنایز کند: To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: @@ -304,15 +304,15 @@ def tokenize_function(example): return tokenizer(example["sentence1"], example["sentence2"], truncation=True) ``` -این تابع یک دیکشنری (مثل اقلام داخل مجموعه داده) دریافت میکند و دیکشنری دیگری بازمی‌گرداند با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`. توجه داشته باشید از انجایی که توکنایزر بر روی لیستهایی از جفت جمله ها کار میکند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار میکند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `()map` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. +این تابع یک دیکشنری (مثل اقلام داخل مجموعه‌داده) دریافت میکند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids` بازمی‌گرداند. توجه داشته باشید از آنجایی که توکنایزر روی لیستهایی از جفت جمله‌ها کار می‌کند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `()map` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. This function takes a dictionary (like the items of our dataset) and returns a new dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`. Note that it also works if the `example` dictionary contains several samples (each key as a list of sentences) since the `tokenizer` works on lists of pairs of sentences, as seen before. This will allow us to use the option `batched=True` in our call to `map()`, which will greatly speed up the tokenization. The `tokenizer` is backed by a tokenizer written in Rust from the [🤗 Tokenizers](https://github.com/huggingface/tokenizers) library. This tokenizer can be very fast, but only if we give it lots of inputs at once. -توجه داشته باشید ما مبحث `padding` را در حال حاضر کنار گذاشته ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` روی نمونه‌ها را زمانی که در حال ساختن بتچ هستیم انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بتچ انجام دهیم، و نه بیشترین طول در سرتاسر مجموعه داده. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متقیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. +توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر مجموعه‌داده. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. Note that we've left the `padding` argument out in our tokenization function for now. This is because padding all the samples to the maximum length is not efficient: it's better to pad the samples when we're building a batch, as then we only need to pad to the maximum length in that batch, and not the maximum length in the entire dataset. This can save a lot of time and processing power when the inputs have very variable lengths! -در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل مجموعه داده به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابر این تابع بر روی چندین عنصر از مجموعه داده ما به یکباره عمل می‌کند، نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش پردازش سریعتر انجام گیرد: +در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل مجموعه‌داده به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از مجموعه‌داده ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: Here is how we apply the tokenization function on all our datasets at once. We're using `batched=True` in our call to `map` so the function is applied to multiple elements of our dataset at once, and not on each element separately. This allows for faster preprocessing. @@ -320,7 +320,7 @@ Here is how we apply the tokenization function on all our datasets at once. We'r tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -کتابخانه مجموعه داده 🤗 این پیش پردازش را با افزودن -فیلدهای- جدید به مجموعه‌داده‌ها، یکی به ازای هر کلید در -دیکشنری- که توسط تابع پیش پردازش باز گردانده می‌شود اعمال می‌کند، +کتابخانه مجموعه‌داده 🤗 این پیش‌پردازش را با افزودن -فیلدهای- جدید به مجموعه‌داده‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شود اعمال می‌کند، The way the 🤗 Datasets library applies this processing is by adding new fields to the datasets, one for each key in the dictionary returned by the preprocessing function: @@ -341,11 +341,11 @@ DatasetDict({ }) ``` -شما حتی می‌توانید زمانی که تابع پیش پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایز سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش پردازش شما را سریعتر کند. +شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایز سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. You can even use multiprocessing when applying your preprocessing function with `map()` by passing along a `num_proc` argument. We didn't do this here because the 🤗 Tokenizers library already uses multiple threads to tokenize our samples faster, but if you are not using a fast tokenizer backed by this library, this could speed up your preprocessing. -تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخشهای مجموعه داده افزوده گردند. توجه داشته باشید که اگر تابع پیش پردازش ما برای یک کلید موجود در مجموعه داده که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گرداند همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخشهای مجموعه‌داده افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در مجموعه‌داده که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گرداند همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. Our `tokenize_function` returns a dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`, so those three fields are added to all splits of our dataset. Note that we could also have changed existing fields if our preprocessing function returned a new value for an existing key in the dataset to which we applied `map()`. @@ -405,7 +405,7 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se [50, 59, 47, 67, 59, 50, 62, 32] ``` -تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. همطول سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، همطول شده باشند. بدون همطول سازی پویا، همه نمونه‌ها در کل مجموعه داده باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، همطول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی همطول می‌کند: +تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. همطول سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، همطول شده باشند. بدون همطول سازی پویا، همه نمونه‌ها در کل مجموعه‌داده باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، همطول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی همطول می‌کند: No surprise, we get samples of varying length, from 32 to 67. Dynamic padding means the samples in this batch should all be padded to a length of 67, the maximum length inside the batch. Without dynamic padding, all of the samples would have to be padded to the maximum length in the whole dataset, or the maximum length the model can accept. Let's double-check that our `data_collator` is dynamically padding the batch properly: @@ -440,7 +440,7 @@ Looking good! Now that we've gone from raw text to batches our model can deal wi -✏️ **امتحان کنید!** پروسه پیش بردازش را روی مجموعه داده GLUE SST-2 باز تکرار کنید. این یک مقدار متفاوت است از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد، اما بقیه کارهایی که انجام دادیم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. +✏️ **امتحان کنید!** پروسه پیش بردازش را روی مجموعه‌داده GLUE SST-2 باز تکرار کنید. این یک مقدار متفاوت است از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد، اما بقیه کارهایی که انجام دادیم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. ✏️ **Try it out!** Replicate the preprocessing on the GLUE SST-2 dataset. It's a little bit different since it's composed of single sentences instead of pairs, but the rest of what we did should look the same. For a harder challenge, try to write a preprocessing function that works on any of the GLUE tasks. @@ -448,7 +448,7 @@ Looking good! Now that we've gone from raw text to batches our model can deal wi {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌ داده مان و یک collator داریم، حال نیاز داریم که آنها را بهم وصل کنیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این کار زیادی می‌برد و احتمالا خیلی بهینه هم نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌ داده مان و یک collator داریم، حال نیاز داریم که آنها را بهم وصل کنیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این کار زیادی می‌برد و احتمالا خیلی بهینه هم نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه‌داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! @@ -470,7 +470,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -این هم از این! ما می‌توانی آن مجموعه‌داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختیهای پروسه پیش پردازش به طرز خوشایندی سرراست خواهد بود. +این هم از این! ما می‌توانی آن مجموعه‌داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختیهای پروسه پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. And that's it! We can take those datasets forward into the next lecture, where training will be pleasantly straightforward after all the hard work of data preprocessing. From 4848b6126eec9489613d4887bf2551d3111ba559 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 12:48:07 +0200 Subject: [PATCH 085/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index cf5e0cdb5..f94b59f58 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -320,7 +320,7 @@ Here is how we apply the tokenization function on all our datasets at once. We'r tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -کتابخانه مجموعه‌داده 🤗 این پیش‌پردازش را با افزودن -فیلدهای- جدید به مجموعه‌داده‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شود اعمال می‌کند، +روشی که کتابخانه مجموعه‌داده 🤗 این پیش‌پردازش را اعمال می‌کند، با افزودن -فیلدهای- جدید به مجموعه‌داده‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، می‌باشد:، The way the 🤗 Datasets library applies this processing is by adding new fields to the datasets, one for each key in the dictionary returned by the preprocessing function: @@ -341,19 +341,19 @@ DatasetDict({ }) ``` -شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایز سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. +شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `()map` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایزر سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. You can even use multiprocessing when applying your preprocessing function with `map()` by passing along a `num_proc` argument. We didn't do this here because the 🤗 Tokenizers library already uses multiple threads to tokenize our samples faster, but if you are not using a fast tokenizer backed by this library, this could speed up your preprocessing. -تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخشهای مجموعه‌داده افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در مجموعه‌داده که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گرداند همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های مجموعه‌داده افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در مجموعه‌داده که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. Our `tokenize_function` returns a dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`, so those three fields are added to all splits of our dataset. Note that we could also have changed existing fields if our preprocessing function returned a new value for an existing key in the dataset to which we applied `map()`. -آخرین چیزی که نیاز داریم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر پَد کنیم - تکنیکی که ما به آن *dynamic padding* (همطول سازی پویا) می‌گوییم. +آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر همطول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. The last thing we will need to do is pad all the examples to the length of the longest element when we batch elements together — a technique we refer to as *dynamic padding*. -### هم طول کردن پویا +### هم‌طول‌سازی پویا ### Dynamic padding @@ -361,19 +361,19 @@ The last thing we will need to do is pad all the examples to the length of the l {#if fw === 'pt'} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم طول سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم طول سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم طول سازی اضافه داشته باشد. +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. The function that is responsible for putting together samples inside a batch is called a *collate function*. It's an argument you can pass when you build a `DataLoader`, the default being a function that will just convert your samples to PyTorch tensors and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. {:else} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم طول سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم طول سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم طول سازی اضافه داشته باشد. +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. The function that is responsible for putting together samples inside a batch is called a *collate function*. The default collator is a function that will just convert your samples to tf.Tensor and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. {/if} -برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم طول سازی را به آیتمهای مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا معرفی کنید (که چه توکنی برای همطول سازی استفاده کند، و اینکه مدل انتظار همطول سازی از سمت چپ ورودی‌ها را دارد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتمهای مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا معرفی کنید (که چه توکنی برای همطول سازی استفاده کند، و اینکه مدل انتظار همطول سازی از سمت چپ ورودی‌ها را دارد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: To do this in practice, we have to define a collate function that will apply the correct amount of padding to the items of the dataset we want to batch together. Fortunately, the 🤗 Transformers library provides us with such a function via `DataCollatorWithPadding`. It takes a tokenizer when you instantiate it (to know which padding token to use, and whether the model expects padding to be on the left or on the right of the inputs) and will do everything you need: From d4eb913cbff9d286396d5bc61f14a42cff94df15 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:01:06 +0200 Subject: [PATCH 086/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index f94b59f58..c9887c2e5 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -349,7 +349,7 @@ You can even use multiprocessing when applying your preprocessing function with Our `tokenize_function` returns a dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`, so those three fields are added to all splits of our dataset. Note that we could also have changed existing fields if our preprocessing function returned a new value for an existing key in the dataset to which we applied `map()`. -آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر همطول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. +آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. The last thing we will need to do is pad all the examples to the length of the longest element when we batch elements together — a technique we refer to as *dynamic padding*. @@ -361,7 +361,7 @@ The last thing we will need to do is pad all the examples to the length of the l {#if fw === 'pt'} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU ها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. The function that is responsible for putting together samples inside a batch is called a *collate function*. It's an argument you can pass when you build a `DataLoader`, the default being a function that will just convert your samples to PyTorch tensors and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. @@ -373,7 +373,7 @@ The function that is responsible for putting together samples inside a batch is {/if} -برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتمهای مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا معرفی کنید (که چه توکنی برای همطول سازی استفاده کند، و اینکه مدل انتظار همطول سازی از سمت چپ ورودی‌ها را دارد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند، و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: To do this in practice, we have to define a collate function that will apply the correct amount of padding to the items of the dataset we want to batch together. Fortunately, the 🤗 Transformers library provides us with such a function via `DataCollatorWithPadding`. It takes a tokenizer when you instantiate it (to know which padding token to use, and whether the model expects padding to be on the left or on the right of the inputs) and will do everything you need: @@ -391,7 +391,7 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf" ``` {/if} -اجازه دهید چند نمونه از مجموعه training مان، که می‌خواهیم باهم بَتچ کنیم، برداریم تا این ابزار جدید را امتحان کنیم. در اینجا سطون‌های -، --، و --- را خذف می‌کنیم چراکه احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (و ما نمی‌توانیم تنسورهایی با رشته های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: +اجازه دهید چند نمونه از مجموعه training مان، که می‌خواهیم باهم بَتچ کنیم، برداریم تا این ابزار جدید را امتحان کنیم. در اینجا سطون‌های `idx`، `sentence1`، و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: To test this new toy, let's grab a few samples from our training set that we would like to batch together. Here, we remove the columns `idx`, `sentence1`, and `sentence2` as they won't be needed and contain strings (and we can't create tensors with strings) and have a look at the lengths of each entry in the batch: @@ -405,7 +405,7 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se [50, 59, 47, 67, 59, 50, 62, 32] ``` -تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. همطول سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، همطول شده باشند. بدون همطول سازی پویا، همه نمونه‌ها در کل مجموعه‌داده باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، همطول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی همطول می‌کند: +تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل مجموعه‌داده باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: No surprise, we get samples of varying length, from 32 to 67. Dynamic padding means the samples in this batch should all be padded to a length of 67, the maximum length inside the batch. Without dynamic padding, all of the samples would have to be padded to the maximum length in the whole dataset, or the maximum length the model can accept. Let's double-check that our `data_collator` is dynamically padding the batch properly: From ddf951a3121defedc202fbbf056cc3e8e339c532 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:08:39 +0200 Subject: [PATCH 087/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c9887c2e5..cd0a19be3 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -440,7 +440,7 @@ Looking good! Now that we've gone from raw text to batches our model can deal wi -✏️ **امتحان کنید!** پروسه پیش بردازش را روی مجموعه‌داده GLUE SST-2 باز تکرار کنید. این یک مقدار متفاوت است از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد، اما بقیه کارهایی که انجام دادیم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. +✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی مجموعه‌داده GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. ✏️ **Try it out!** Replicate the preprocessing on the GLUE SST-2 dataset. It's a little bit different since it's composed of single sentences instead of pairs, but the rest of what we did should look the same. For a harder challenge, try to write a preprocessing function that works on any of the GLUE tasks. @@ -448,7 +448,7 @@ Looking good! Now that we've gone from raw text to batches our model can deal wi {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌ داده مان و یک collator داریم، حال نیاز داریم که آنها را بهم وصل کنیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این کار زیادی می‌برد و احتمالا خیلی بهینه هم نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه‌داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه‌داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! From f65bf3e03409cdc40b8caedf52c4c09fd2f62d30 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:10:31 +0200 Subject: [PATCH 088/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index cd0a19be3..604af7b95 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -448,7 +448,7 @@ Looking good! Now that we've gone from raw text to batches our model can deal wi {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه‌داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `()model.fit` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه‌داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! From 3253b83e187dd435fd928d7769598b9d2decab39 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:11:23 +0200 Subject: [PATCH 089/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 604af7b95..8e2ef1c79 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -448,7 +448,7 @@ Looking good! Now that we've gone from raw text to batches our model can deal wi {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `()model.fit` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `tf.data.Dataset` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه‌داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه‌داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! From b9e4251a81fa4758e9d345f6b991bef981c6c9ad Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:13:48 +0200 Subject: [PATCH 090/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 8e2ef1c79..8027786c4 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -448,7 +448,7 @@ Looking good! Now that we've gone from raw text to batches our model can deal wi {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه این یک تابع به سرعت یک مجموعه‌داده 🤗 را به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک مجموعه‌داده 🤗 را به سرعت به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! @@ -470,7 +470,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -این هم از این! ما می‌توانی آن مجموعه‌داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختیهای پروسه پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. +این هم از این! حالا می‌توانیم این مجموعه‌داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. And that's it! We can take those datasets forward into the next lecture, where training will be pleasantly straightforward after all the hard work of data preprocessing. From 21a79479c5a0c7c1fa9f670cc30e234d7e0eb777 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:23:37 +0200 Subject: [PATCH 091/502] minor fixes and polish --- chapters/fa/chapter3/2.mdx | 93 ++------------------------------------ 1 file changed, 3 insertions(+), 90 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 8027786c4..486aefcda 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -80,11 +80,6 @@ model.train_on_batch(batch, labels) در این بخش ما از مجموعه‌داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه‌داده این است که مجموعه‌داده کوچکیست و تجربه آموزش دادن روی آن آسان است. -Of course, just training the model on two sentences is not going to yield very good results. To get better results, you will need to prepare a bigger dataset. - -In this section we will use as an example the MRPC (Microsoft Research Paraphrase Corpus) dataset, introduced in a [paper](https://www.aclweb.org/anthology/I05-5002.pdf) by William B. Dolan and Chris Brockett. The dataset consists of 5,801 pairs of sentences, with a label indicating if they are paraphrases or not (i.e., if both sentences mean the same thing). We've selected it for this chapter because it's a small dataset, so it's easy to experiment with training on it. - - ### بارگذاری یک داده از هاب ### Loading a dataset from the Hub @@ -97,12 +92,8 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه‌داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. -The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. - کتابخانه مجموعه‌داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه‌داده در هاب ارائه می‌کند. ما می‌توانیم مجموعه‌داده MRPC را به روش زیر دانلود کنیم: -The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: - ```py from datasets import load_dataset @@ -129,16 +120,10 @@ DatasetDict({ همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`label`، `sentence2`، `sentence1`، و `idx`) و تعداد متغیری ردیف داده که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training وجود دارد، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test). -As you can see, we get a `DatasetDict` object which contains the training set, the validation set, and the test set. Each of those contains several columns (`sentence1`, `sentence2`, `label`, and `idx`) and a variable number of rows, which are the number of elements in each set (so, there are 3,668 pairs of sentences in the training set, 408 in the validation set, and 1,725 in the test set). - این دستور مجموعه‌داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. -This command downloads and caches the dataset, by default in *~/.cache/huggingface/dataset*. Recall from Chapter 2 that you can customize your cache folder by setting the `HF_HOME` environment variable. - ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از شماره‌گذاری, مانند یک dictionary دسترسی پیدا کنیم: -We can access each pair of sentences in our `raw_datasets` object by indexing, like with a dictionary: - ```py raw_train_dataset = raw_datasets["train"] raw_train_dataset[0] @@ -153,8 +138,6 @@ raw_train_dataset[0] می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه‌داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. -We can see the labels are already integers, so we won't have to do any preprocessing there. To know which integer corresponds to which label, we can inspect the `features` of our `raw_train_dataset`. This will tell us the type of each column: - ```py raw_train_dataset.features ``` @@ -168,24 +151,12 @@ raw_train_dataset.features در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. -Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers to label name is stored in the *names* folder. `0` corresponds to `not_equivalent`, and `1` corresponds to `equivalent`. - - ✏️ **امتحان کنید!** عنصر شماره ۱۵ از داده training و عنصر شماره ۸۷ از داده validation را مشاهده کنید. برچسبهای آنها چیست؟ - - - - - -✏️ **Try it out!** Look at element 15 of the training set and element 87 of the validation set. What are their labels? - ### پیش‌پردازشِ یک مجموعه‌داده -### Preprocessing a dataset - {#if fw === 'pt'} {:else} @@ -194,8 +165,6 @@ Behind the scenes, `label` is of type `ClassLabel`, and the mapping of integers به منظور پیش‌پردازش مجموعه‌داده، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: -To preprocess the dataset, we need to convert the text to numbers the model can make sense of. As you saw in the [previous chapter](/course/chapter2), this is done with a tokenizer. We can feed the tokenizer one sentence or a list of sentences, so we can directly tokenize all the first sentences and all the second sentences of each pair like this: - ```py from transformers import AutoTokenizer @@ -207,8 +176,6 @@ tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"]) با این حال، نمی‌توانیم دو جمله را به مدل ارسال کنیم تا پیش‌بینی کند متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم، و پیش‌پردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکنایزر می‌تواند یک جفت رشته را دریافت کند و آنرا به گونه‌ای که مدل BERT ما انتظار دارد آماده سازی کند: -However, we can't just pass two sequences to the model and get a prediction of whether the two sentences are paraphrases or not. We need to handle the two sequences as a pair, and apply the appropriate preprocessing. Fortunately, the tokenizer can also take a pair of sequences and prepare it the way our BERT model expects: - ```py inputs = tokenizer("This is the first sentence.", "This is the second one.") inputs @@ -224,19 +191,13 @@ inputs در [فصل ۲](/course/chapter2) در مورد کلیدهای `input_ids` و `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی، جمله اول و کدام بخش جمله دوم است. -We discussed the `input_ids` and `attention_mask` keys in [Chapter 2](/course/chapter2), but we put off talking about `token_type_ids`. In this example, this is what tells the model which part of the input is the first sentence and which is the second sentence. - ✏️ **امتحان کنید!** عنصر شماره ۱۵ داده را بردارید و دو جمله را به صورت جداگانه و جفت توکنایز کنید. تفاوت دو نتیجه چیست؟ -✏️ **Try it out!** Take element 15 of the training set and tokenize the two sentences separately and as a pair. What's the difference between the two results? - -اگر آیدی های داخل `input_ids` را به کلمات رمزگشایی کنیم: - -If we decode the IDs inside `input_ids` back to words: +اگر آیدی‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: ```py tokenizer.convert_ids_to_tokens(inputs["input_ids"]) @@ -252,8 +213,6 @@ we will get: بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `[CLS] sentence1 [SEP] sentence2 [SEP]` باشند. -So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] sentence2 [SEP]` when there are two sentences. Aligning this with the `token_type_ids` gives us: - ```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] @@ -261,28 +220,16 @@ So we see the model expects the inputs to be of the form `[CLS] sentence1 [SEP] همانطور که می‌بینید، بخشهایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` هستند آیدی نشاندهنده نوع توکِن آنها `0` و بخشهایی که مربوط به `sentence2 [SEP]` هستند آیدی نشاندهنده نوع توکِن‌شان `1` می‌باشد. -As you can see, the parts of the input corresponding to `[CLS] sentence1 [SEP]` all have a token type ID of `0`, while the other parts, corresponding to `sentence2 [SEP]`, all have a token type ID of `1`. - توجه داشته باشید که اگر چکپوینت متفاوتی را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. -Note that if you select a different checkpoint, you won't necessarily have the `token_type_ids` in your tokenized inputs (for instance, they're not returned if you use a DistilBERT model). They are only returned when the model will know what to do with them, because it has seen them during its pretraining. - در اینجا، مدل BERT با آیدی‌هایی که نشاندهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبانِ ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ برعهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. -Here, BERT is pretrained with token type IDs, and on top of the masked language modeling objective we talked about in [Chapter 1](/course/chapter1), it has an additional objective called _next sentence prediction_. The goal with this task is to model the relationship between pairs of sentences. - در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ جمله‌ اول قرار دارد یا خیر. برای خارج کردن مسئله از حالت بدیهی، در نیمی از حالتها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. -With next sentence prediction, the model is provided pairs of sentences (with randomly masked tokens) and asked to predict whether the second sentence follows the first. To make the task non-trivial, half of the time the sentences follow each other in the original document they were extracted from, and the other half of the time the two sentences come from two different documents. - در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکنایز شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکنایزر می‌داند چه چیزی برای مدل فراهم کند. -In general, you don't need to worry about whether or not there are `token_type_ids` in your tokenized inputs: as long as you use the same checkpoint for the tokenizer and the model, everything will be fine as the tokenizer knows what to provide to its model. - اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل مجموعه‌داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ مجموعه‌داده‌ی training اینگونه می‌باشد: -Now that we have seen how our tokenizer can deal with one pair of sentences, we can use it to tokenize our whole dataset: like in the [previous chapter](/course/chapter2), we can feed the tokenizer a list of pairs of sentences by giving it the list of first sentences, then the list of second sentences. This is also compatible with the padding and truncation options we saw in [Chapter 2](/course/chapter2). So, one way to preprocess the training dataset is: - ```py tokenized_dataset = tokenizer( raw_datasets["train"]["sentence1"], @@ -291,39 +238,27 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` -این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل مجموعه‌داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه‌داده‌های موجود در پایگاه مجموعه‌داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره سازی در حافظه درخواست کرده‌اید نگه می‌دارید. ) - -This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). +این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل مجموعه‌داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه‌داده‌های موجود در پایگاه مجموعه‌داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه می‌دارید). به منظور نگه داشتن داده به صورت یک مجموعه‌داده، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه‌داده عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکنایز کند: -To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: - ```py def tokenize_function(example): return tokenizer(example["sentence1"], example["sentence2"], truncation=True) ``` -این تابع یک دیکشنری (مثل اقلام داخل مجموعه‌داده) دریافت میکند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids` بازمی‌گرداند. توجه داشته باشید از آنجایی که توکنایزر روی لیستهایی از جفت جمله‌ها کار می‌کند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `()map` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. - -This function takes a dictionary (like the items of our dataset) and returns a new dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`. Note that it also works if the `example` dictionary contains several samples (each key as a list of sentences) since the `tokenizer` works on lists of pairs of sentences, as seen before. This will allow us to use the option `batched=True` in our call to `map()`, which will greatly speed up the tokenization. The `tokenizer` is backed by a tokenizer written in Rust from the [🤗 Tokenizers](https://github.com/huggingface/tokenizers) library. This tokenizer can be very fast, but only if we give it lots of inputs at once. +این تابع یک دیکشنری (مثل اقلام داخل مجموعه‌داده) دریافت میکند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids` بازمی‌گرداند. توجه داشته باشید از آنجایی که توکنایزر روی لیستهایی از جفت جمله‌ها کار می‌کند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `()map` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. این توکنایزر با توکنایزری در کتابخانه [🤗 Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر مجموعه‌داده. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. -Note that we've left the `padding` argument out in our tokenization function for now. This is because padding all the samples to the maximum length is not efficient: it's better to pad the samples when we're building a batch, as then we only need to pad to the maximum length in that batch, and not the maximum length in the entire dataset. This can save a lot of time and processing power when the inputs have very variable lengths! - در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل مجموعه‌داده به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از مجموعه‌داده ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: -Here is how we apply the tokenization function on all our datasets at once. We're using `batched=True` in our call to `map` so the function is applied to multiple elements of our dataset at once, and not on each element separately. This allows for faster preprocessing. - ```py tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` روشی که کتابخانه مجموعه‌داده 🤗 این پیش‌پردازش را اعمال می‌کند، با افزودن -فیلدهای- جدید به مجموعه‌داده‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، می‌باشد:، -The way the 🤗 Datasets library applies this processing is by adding new fields to the datasets, one for each key in the dictionary returned by the preprocessing function: - ```python out DatasetDict({ train: Dataset({ @@ -343,15 +278,11 @@ DatasetDict({ شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `()map` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایزر سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. -You can even use multiprocessing when applying your preprocessing function with `map()` by passing along a `num_proc` argument. We didn't do this here because the 🤗 Tokenizers library already uses multiple threads to tokenize our samples faster, but if you are not using a fast tokenizer backed by this library, this could speed up your preprocessing. تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های مجموعه‌داده افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در مجموعه‌داده که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. -Our `tokenize_function` returns a dictionary with the keys `input_ids`, `attention_mask`, and `token_type_ids`, so those three fields are added to all splits of our dataset. Note that we could also have changed existing fields if our preprocessing function returned a new value for an existing key in the dataset to which we applied `map()`. - آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. -The last thing we will need to do is pad all the examples to the length of the longest element when we batch elements together — a technique we refer to as *dynamic padding*. ### هم‌طول‌سازی پویا @@ -363,20 +294,14 @@ The last thing we will need to do is pad all the examples to the length of the l تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU ها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. -The function that is responsible for putting together samples inside a batch is called a *collate function*. It's an argument you can pass when you build a `DataLoader`, the default being a function that will just convert your samples to PyTorch tensors and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. - {:else} تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. -The function that is responsible for putting together samples inside a batch is called a *collate function*. The default collator is a function that will just convert your samples to tf.Tensor and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. - {/if} برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند، و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: -To do this in practice, we have to define a collate function that will apply the correct amount of padding to the items of the dataset we want to batch together. Fortunately, the 🤗 Transformers library provides us with such a function via `DataCollatorWithPadding`. It takes a tokenizer when you instantiate it (to know which padding token to use, and whether the model expects padding to be on the left or on the right of the inputs) and will do everything you need: - {#if fw === 'pt'} ```py from transformers import DataCollatorWithPadding @@ -393,8 +318,6 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf" اجازه دهید چند نمونه از مجموعه training مان، که می‌خواهیم باهم بَتچ کنیم، برداریم تا این ابزار جدید را امتحان کنیم. در اینجا سطون‌های `idx`، `sentence1`، و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: -To test this new toy, let's grab a few samples from our training set that we would like to batch together. Here, we remove the columns `idx`, `sentence1`, and `sentence2` as they won't be needed and contain strings (and we can't create tensors with strings) and have a look at the lengths of each entry in the batch: - ```py samples = tokenized_datasets["train"][:8] samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "sentence2"]} @@ -407,8 +330,6 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل مجموعه‌داده باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: -No surprise, we get samples of varying length, from 32 to 67. Dynamic padding means the samples in this batch should all be padded to a length of 67, the maximum length inside the batch. Without dynamic padding, all of the samples would have to be padded to the maximum length in the whole dataset, or the maximum length the model can accept. Let's double-check that our `data_collator` is dynamically padding the batch properly: - ```py batch = data_collator(samples) {k: v.shape for k, v in batch.items()} @@ -434,24 +355,18 @@ batch = data_collator(samples) به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل مان می‌تواند با آنها کار کند، آماده هستیم برای انجام بازتنظیم مدل: -Looking good! Now that we've gone from raw text to batches our model can deal with, we're ready to fine-tune it! - {/if} ✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی مجموعه‌داده GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. -✏️ **Try it out!** Replicate the preprocessing on the GLUE SST-2 dataset. It's a little bit different since it's composed of single sentences instead of pairs, but the rest of what we did should look the same. For a harder challenge, try to write a preprocessing function that works on any of the GLUE tasks. - {#if fw === 'tf'} توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک مجموعه‌داده 🤗 را به سرعت به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! -Now that we have our dataset and a data collator, we need to put them together. We could manually load batches and collate them, but that's a lot of work, and probably not very performant either. Instead, there's a simple method that offers a performant solution to this problem: `to_tf_dataset()`. This will wrap a `tf.data.Dataset` around your dataset, with an optional collation function. `tf.data.Dataset` is a native TensorFlow format that Keras can use for `model.fit()`, so this one method immediately converts a 🤗 Dataset to a format that's ready for training. Let's see it in action with our dataset! - ```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( columns=["attention_mask", "input_ids", "token_type_ids"], @@ -472,6 +387,4 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( این هم از این! حالا می‌توانیم این مجموعه‌داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. -And that's it! We can take those datasets forward into the next lecture, where training will be pleasantly straightforward after all the hard work of data preprocessing. - {/if} From 1dd88fe6373dc3406b5c276048fc43b6cf1945a0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:24:26 +0200 Subject: [PATCH 092/502] minor fix --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 486aefcda..e1cef18a8 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -51,7 +51,7 @@ optimizer.step() ``` {:else} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بتچ توسط pytorch را شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بَتچ توسط pytorch را شرح می‌دهیم: ```python import tensorflow as tf From 1ab29f4e3bee3c5914b8692ce8fc315b9abf61ff Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:28:28 +0200 Subject: [PATCH 093/502] Ch3 - 1 and 2 funal draft. --- chapters/fa/chapter3/1.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index b960c3886..6cfa5d3ee 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -2,22 +2,22 @@ # مقدمه -در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدلهای پیش تعلیم را جهت انجام پیش بینی های جدید بررسی کردیم. اما چگونه میتوانید یک مدل پیش تعلیم را خودتان بازتنظیم کنید؟ +در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدل‌های پیش‌تعلیم را جهت انجام پیش‌بینی‌های جدید بررسی کردیم. اما چگونه می‌توانید یک مدل پیش‌تعلیم را خودتان بازتنظیم کنید؟ {#if fw === 'pt'} -* چگونه یک داده بزرگ را از هاب تهیه کنید +* چگونه یک مجموعه‌داده بزرگ را از هاب تهیه کنید * چگونه از API سطح بالای "Trainer" برای بازتنظیم مدل استفاده کنید -* چگونه یک چرخه تعلیم دلخواه درست کنید -* چگونه از کتابخانه Accelerate 🤗 برای اجرای چرخه تعلیم دلخواه در هر تنظیمات غیر متمرکزی استفاده کنید +* چگونه یک چرخه‌تعلیم دلخواه درست کنید +* چگونه از کتابخانه Accelerate 🤗 برای اجرای چرخه‌تعلیم دلخواه در هر تنظیمات غیر متمرکزی استفاده کنید {:else} -* چگونه یک داده بزرگ را از هاب تهیه کنید -* چگونه از کراس برای بازتنظیم مدل استفاده کنید -* چگونه از کراس برای استخراج پیش بینی ها استفاده کنید +* چگونه یک مجموعه‌داده بزرگ را از هاب تهیه کنید +* چگونه از کِراس برای بازتنظیم مدل استفاده کنید +* چگونه از کِراس برای استخراج پیش بینی‌ها استفاده کنید * چگونه از یک متریک دلخواه استفاده کنید {/if} -جهت بارگذاری چک پوینت تعلیم دیده خود در هاب هاگینک فیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) \ No newline at end of file +جهت بارگذاری چکپوینت تعلیم دیده خود در هاب هاگینگ‌فیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) \ No newline at end of file From e1fdabc51fdfb206d67ac67da5c41d6242a4986f Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 13:34:47 +0200 Subject: [PATCH 094/502] Ch3 - 1 and 2 funal draft. --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index e1cef18a8..2a683ac84 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -90,7 +90,7 @@ model.train_on_batch(batch, labels) {/if} -هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبانهای مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه‌داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. +هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبان‌های مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه‌داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. کتابخانه مجموعه‌داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه‌داده در هاب ارائه می‌کند. ما می‌توانیم مجموعه‌داده MRPC را به روش زیر دانلود کنیم: From cfc8ba62688a8b5536f228185ab477e80a53eae9 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 25 Apr 2022 21:40:50 +0200 Subject: [PATCH 095/502] Ch3 - 1 and 2 final draft. --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 2a683ac84..5be25d104 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -365,7 +365,7 @@ batch = data_collator(samples) {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک مجموعه‌داده 🤗 را به سرعت به فرمت آماده برای آموزش تبدیل می‌کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک مجموعه‌داده 🤗 را به سرعت به فرمت آماده برای آموزش تبدیل کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! ```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( From fe1fdd20dbd35bce042a60e34de90e992a8fd526 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 27 Apr 2022 10:57:37 +0200 Subject: [PATCH 096/502] Ch3-P3 - first push --- chapters/fa/chapter3/3.mdx | 172 ++++++++++++++++ chapters/fa/chapter3/3_tf.mdx | 203 +++++++++++++++++++ chapters/fa/chapter3/4.mdx | 359 ++++++++++++++++++++++++++++++++++ chapters/fa/chapter3/5.mdx | 20 ++ chapters/fa/chapter3/6.mdx | 296 ++++++++++++++++++++++++++++ 5 files changed, 1050 insertions(+) create mode 100644 chapters/fa/chapter3/3.mdx create mode 100644 chapters/fa/chapter3/3_tf.mdx create mode 100644 chapters/fa/chapter3/4.mdx create mode 100644 chapters/fa/chapter3/5.mdx create mode 100644 chapters/fa/chapter3/6.mdx diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx new file mode 100644 index 000000000..749cfd511 --- /dev/null +++ b/chapters/fa/chapter3/3.mdx @@ -0,0 +1,172 @@ + + +# Fine-tuning a model with the Trainer API + + + + + +🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). + +The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: + +```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) +``` + +### Training + +The first step before we can define our `Trainer` is to define a `TrainingArguments` class that will contain all the hyperparameters the `Trainer` will use for training and evaluation. The only argument you have to provide is a directory where the trained model will be saved, as well as the checkpoints along the way. For all the rest, you can leave the defaults, which should work pretty well for a basic fine-tuning. + +```py +from transformers import TrainingArguments + +training_args = TrainingArguments("test-trainer") +``` + + + +💡 If you want to automatically upload your model to the Hub during training, pass along `push_to_hub=True` in the `TrainingArguments`. We will learn more about this in [Chapter 4](/course/chapter4/3) + + + +The second step is to define our model. As in the [previous chapter](/course/chapter2), we will use the `AutoModelForSequenceClassification` class, with two labels: + +```py +from transformers import AutoModelForSequenceClassification + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. + +Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `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, +) +``` + +Note that when you pass the `tokenizer` as we did here, the default `data_collator` used by the `Trainer` will be a `DataCollatorWithPadding` as defined previously, so you can skip the line `data_collator=data_collator` in this call. It was still important to show you this part of the processing in section 2! + +To fine-tune the model on our dataset, we just have to call the `train()` method of our `Trainer`: + +```py +trainer.train() +``` + +This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: + +1. We didn't tell the `Trainer` to evaluate during training by setting `evaluation_strategy` to either `"steps"` (evaluate every `eval_steps`) or `"epoch"` (evaluate at the end of each epoch). +2. We didn't provide the `Trainer` with a `compute_metrics()` function to calculate a metric during said evaluation (otherwise the evaluation would just have printed the loss, which is not a very intuitive number). + + +### Evaluation + +Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: + +```py +predictions = trainer.predict(tokenized_datasets["validation"]) +print(predictions.predictions.shape, predictions.label_ids.shape) +``` + +```python out +(408, 2) (408,) +``` + +The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. + +As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: + +```py +import numpy as np + +preds = np.argmax(predictions.predictions, axis=-1) +``` + +We can now compare those `preds` to the labels. To build our `compute_metric()` function, we will rely on the metrics from the 🤗 Datasets library. We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: + +```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} +``` + +The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. + +Wrapping everything together, we get our `compute_metrics()` function: + +```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) +``` + +And to see it used in action to report metrics at the end of each epoch, here is how we define a new `Trainer` with this `compute_metrics()` function: + +```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, +) +``` + +Note that we create a new `TrainingArguments` with its `evaluation_strategy` set to `"epoch"` and a new model — otherwise, we would just be continuing the training of the model we have already trained. To launch a new training run, we execute: + +``` +trainer.train() +``` + +This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. + +The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. + +This concludes the introduction to fine-tuning using the `Trainer` API. An example of doing this for most common NLP tasks will be given in Chapter 7, but for now let's look at how to do the same thing in pure PyTorch. + + + +✏️ **Try it out!** Fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. + + + diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx new file mode 100644 index 000000000..85a4626dd --- /dev/null +++ b/chapters/fa/chapter3/3_tf.mdx @@ -0,0 +1,203 @@ + + +# باز‌تنظیم یک مدل با استفاده از کِراس + +# Fine-tuning a model with Keras + + + +وقتی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا آموزشِ مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر تنظیمات GPU را انجام نداده‌اید، می‌توانید به GPUها یا TPUها مجانی روی [Google Colab](https://colab.research.google.com/) دسترسی داشته باشید. + +Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). + +The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: + +```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, +) +``` + +### Training + +TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. + + + +That means that once we have our data, very little work is required to begin training on it. + + + +As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: + +```py +from transformers import TFAutoModelForSequenceClassification + +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. + +To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. + + + +Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. + + + +```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, +) +``` + + + +Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. + + + + +### Improving training performance + + + +If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause +is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes +that optimizer with default values for all parameters, including learning rate. From long experience, though, we know +that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written +as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. + +In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate +over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* +the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is +`PolynomialDecay` — despite the name, with default settings it simply linearly decays the learning rate from the initial +value to the final value over the course of training, which is exactly what we want. In order to use a scheduler correctly, +though, we need to tell it how long training is going to be. We compute that as `num_train_steps` below. + +```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) +``` + + + +The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. + + + +Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: + +```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"]) +``` + +Now, we fit again: + +```py +model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) +``` + + + +💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) + + + +### Model predictions + + + + +Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. + +```py +preds = model.predict(tf_validation_dataset)["logits"] +``` + +We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: + +```py +class_preds = np.argmax(preds, axis=1) +print(preds.shape, class_preds.shape) +``` + +```python out +(408, 2) (408,) +``` + +Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: + +```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} +``` + +The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. + +This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. diff --git a/chapters/fa/chapter3/4.mdx b/chapters/fa/chapter3/4.mdx new file mode 100644 index 000000000..54563ea7c --- /dev/null +++ b/chapters/fa/chapter3/4.mdx @@ -0,0 +1,359 @@ +# A full training + + + + + +Now we'll see how to achieve the same results as we did in the last section without using the `Trainer` class. Again, we assume you have done the data processing in section 2. Here is a short summary covering everything you will need: + +```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) +``` + +### Prepare for training + +Before actually writing our training loop, we will need to define a few objects. The first ones are the dataloaders we will use to iterate over batches. But before we can define those dataloaders, we need to apply a bit of postprocessing to our `tokenized_datasets`, to take care of some things that the `Trainer` did for us automatically. Specifically, we need to: + +- Remove the columns corresponding to values the model does not expect (like the `sentence1` and `sentence2` columns). +- Rename the column `label` to `labels` (because the model expects the argument to be named `labels`). +- Set the format of the datasets so they return PyTorch tensors instead of lists. + +Our `tokenized_datasets` has one method for each of those steps: + +```py +tokenized_datasets = tokenized_datasets.remove_columns(["sentence1", "sentence2", "idx"]) +tokenized_datasets = tokenized_datasets.rename_column("label", "labels") +tokenized_datasets.set_format("torch") +tokenized_datasets["train"].column_names +``` + +We can then check that the result only has columns that our model will accept: + +```python +["attention_mask", "input_ids", "labels", "token_type_ids"] +``` + +Now that this is done, we can easily define our dataloaders: + +```py +from torch.utils.data import DataLoader + +train_dataloader = DataLoader( + tokenized_datasets["train"], shuffle=True, batch_size=8, collate_fn=data_collator +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], batch_size=8, collate_fn=data_collator +) +``` + +To quickly check there is no mistake in the data processing, we can inspect a batch like this: + +```py +for batch in train_dataloader: + break +{k: v.shape for k, v in batch.items()} +``` + +```python out +{'attention_mask': torch.Size([8, 65]), + 'input_ids': torch.Size([8, 65]), + 'labels': torch.Size([8]), + 'token_type_ids': torch.Size([8, 65])} +``` + +Note that the actual shapes will probably be slightly different for you since we set `shuffle=True` for the training dataloader and we are padding to the maximum length inside the batch. + +Now that we're completely finished with data preprocessing (a satisfying yet elusive goal for any ML practitioner), let's turn to the model. We instantiate it exactly as we did in the previous section: + +```py +from transformers import AutoModelForSequenceClassification + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +To make sure that everything will go smoothly during training, we pass our batch to this model: + +```py +outputs = model(**batch) +print(outputs.loss, outputs.logits.shape) +``` + +```python out +tensor(0.5441, grad_fn=) torch.Size([8, 2]) +``` + +All 🤗 Transformers models will return the loss when `labels` are provided, and we also get the logits (two for each input in our batch, so a tensor of size 8 x 2). + +We're almost ready to write our training loop! We're just missing two things: an optimizer and a learning rate scheduler. Since we are trying to replicate what the `Trainer` was doing by hand, we will use the same defaults. The optimizer used by the `Trainer` is `AdamW`, which is the same as Adam, but with a twist for weight decay regularization (see ["Decoupled Weight Decay Regularization"](https://arxiv.org/abs/1711.05101) by Ilya Loshchilov and Frank Hutter): + +```py +from transformers import AdamW + +optimizer = AdamW(model.parameters(), lr=5e-5) +``` + +Finally, the learning rate scheduler used by default is just a linear decay from the maximum value (5e-5) to 0. To properly define it, we need to know the number of training steps we will take, which is the number of epochs we want to run multiplied by the number of training batches (which is the length of our training dataloader). The `Trainer` uses three epochs by default, so we will follow that: + +```py +from transformers import get_scheduler + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dataloader) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +print(num_training_steps) +``` + +```python out +1377 +``` + +### The training loop + +One last thing: we will want to use the GPU if we have access to one (on a CPU, training might take several hours instead of a couple of minutes). To do this, we define a `device` we will put our model and our batches on: + +```py +import torch + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +model.to(device) +device +``` + +```python out +device(type='cuda') +``` + +We are now ready to train! To get some sense of when training will be finished, we add a progress bar over our number of training steps, using the `tqdm` library: + +```py +from tqdm.auto import tqdm + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dataloader: + batch = {k: v.to(device) for k, v in batch.items()} + outputs = model(**batch) + loss = outputs.loss + loss.backward() + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +You can see that the core of the training loop looks a lot like the one in the introduction. We didn't ask for any reporting, so this training loop will not tell us anything about how the model fares. We need to add an evaluation loop for that. + + +### The evaluation loop + +As we did earlier, we will use a metric provided by the 🤗 Datasets library. We've already seen the `metric.compute()` method, but metrics can actually accumulate batches for us as we go over the prediction loop with the method `add_batch()`. Once we have accumulated all the batches, we can get the final result with `metric.compute()`. Here's how to implement all of this in an evaluation loop: + +```py +from datasets import load_metric + +metric = load_metric("glue", "mrpc") +model.eval() +for batch in eval_dataloader: + batch = {k: v.to(device) for k, v in batch.items()} + with torch.no_grad(): + outputs = model(**batch) + + logits = outputs.logits + predictions = torch.argmax(logits, dim=-1) + metric.add_batch(predictions=predictions, references=batch["labels"]) + +metric.compute() +``` + +```python out +{'accuracy': 0.8431372549019608, 'f1': 0.8907849829351535} +``` + +Again, your results will be slightly different because of the randomness in the model head initialization and the data shuffling, but they should be in the same ballpark. + + + +✏️ **Try it out!** Modify the previous training loop to fine-tune your model on the SST-2 dataset. + + + +### Supercharge your training loop with 🤗 Accelerate + + + +The training loop we defined earlier works fine on a single CPU or GPU. But using the [🤗 Accelerate](https://github.com/huggingface/accelerate) library, with just a few adjustments we can enable distributed training on multiple GPUs or TPUs. Starting from the creation of the training and validation dataloaders, here is what our manual training loop looks like: + +```py +from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +optimizer = AdamW(model.parameters(), lr=3e-5) + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +model.to(device) + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dataloader) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dataloader: + batch = {k: v.to(device) for k, v in batch.items()} + outputs = model(**batch) + loss = outputs.loss + loss.backward() + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +And here are the changes: + +```diff ++ from accelerate import Accelerator + from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler + ++ accelerator = Accelerator() + + model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) + optimizer = AdamW(model.parameters(), lr=3e-5) + +- device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +- model.to(device) + ++ train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare( ++ train_dataloader, eval_dataloader, model, optimizer ++ ) + + num_epochs = 3 + num_training_steps = num_epochs * len(train_dataloader) + lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps + ) + + progress_bar = tqdm(range(num_training_steps)) + + model.train() + for epoch in range(num_epochs): + for batch in train_dataloader: +- batch = {k: v.to(device) for k, v in batch.items()} + outputs = model(**batch) + loss = outputs.loss +- loss.backward() ++ accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +The first line to add is the import line. The second line instantiates an `Accelerator` object that will look at the environment and initialize the proper distributed setup. 🤗 Accelerate handles the device placement for you, so you can remove the lines that put the model on the device (or, if you prefer, change them to use `accelerator.device` instead of `device`). + +Then the main bulk of the work is done in the line that sends the dataloaders, the model, and the optimizer to `accelerator.prepare()`. This will wrap those objects in the proper container to make sure your distributed training works as intended. The remaining changes to make are removing the line that puts the batch on the `device` (again, if you want to keep this you can just change it to use `accelerator.device`) and replacing `loss.backward()` with `accelerator.backward(loss)`. + + +⚠️ In order to benefit from the speed-up offered by Cloud TPUs, we recommend padding your samples to a fixed length with the `padding="max_length"` and `max_length` arguments of the tokenizer. + + +If you'd like to copy and paste it to play around, here's what the complete training loop looks like with 🤗 Accelerate: + +```py +from accelerate import Accelerator +from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler + +accelerator = Accelerator() + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +optimizer = AdamW(model.parameters(), lr=3e-5) + +train_dl, eval_dl, model, optimizer = accelerator.prepare( + train_dataloader, eval_dataloader, model, optimizer +) + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dl) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dl: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +Putting this in a `train.py` script will make that script runnable on any kind of distributed setup. To try it out in your distributed setup, run the command: + +```bash +accelerate config +``` + +which will prompt you to answer a few questions and dump your answers in a configuration file used by this command: + +``` +accelerate launch train.py +``` + +which will launch the distributed training. + +If you want to try this in a Notebook (for instance, to test it with TPUs on Colab), just paste the code in a `training_function()` and run a last cell with: + +```python +from accelerate import notebook_launcher + +notebook_launcher(training_function) +``` + +You can find more examples in the [🤗 Accelerate repo](https://github.com/huggingface/accelerate/tree/main/examples). diff --git a/chapters/fa/chapter3/5.mdx b/chapters/fa/chapter3/5.mdx new file mode 100644 index 000000000..dda8cb7fe --- /dev/null +++ b/chapters/fa/chapter3/5.mdx @@ -0,0 +1,20 @@ + + +# Fine-tuning, Check! + +That was fun! In the first two chapters you learned about models and tokenizers, and now you know how to fine-tune them for your own data. To recap, in this chapter you: + +{#if fw === 'pt'} +* Learned about datasets in the [Hub](https://huggingface.co/datasets) +* Learned how to load and preprocess datasets, including using dynamic padding and collators +* Implemented your own fine-tuning and evaluation of a model +* Implemented a lower-level training loop +* Used 🤗 Accelerate to easily adapt your training loop so it works for multiple GPUs or TPUs + +{:else} +* Learned about datasets in the [Hub](https://huggingface.co/datasets) +* Learned how to load and preprocess datasets +* Learned how to fine-tune and evaluate a model with Keras +* Implemented a custom metric + +{/if} diff --git a/chapters/fa/chapter3/6.mdx b/chapters/fa/chapter3/6.mdx new file mode 100644 index 000000000..94d02da24 --- /dev/null +++ b/chapters/fa/chapter3/6.mdx @@ -0,0 +1,296 @@ + + + + +# End-of-chapter quiz + +Test what you learned in this chapter! + +### 1. The `emotion` dataset contains Twitter messages labeled with emotions. Search for it in the [Hub](https://huggingface.co/datasets), and read the dataset card. Which of these is not one of its basic emotions? + + + +### 2. Search for the `ar_sarcasm` dataset in the [Hub](https://huggingface.co/datasets). Which task does it support? + +dataset card!" + }, + { + text: "Named entity recognition", + explain: "That's not it — take another look at the dataset card!" + }, + { + text: "Question answering", + explain: "Alas, this question was not answered correctly. Try again!" + } + ]} +/> + +### 3. How does the BERT model expect a pair of sentences to be processed? + +[SEP] special token is needed to separate the two sentences, but that's not the only thing!" + }, + { + text: "[CLS] Tokens_of_sentence_1 Tokens_of_sentence_2", + explain: "A [CLS] special token is required at the beginning, but that's not the only thing!" + }, + { + text: "[CLS] Tokens_of_sentence_1 [SEP] Tokens_of_sentence_2 [SEP]", + explain: "That's correct!", + correct: true + }, + { + text: "[CLS] Tokens_of_sentence_1 [SEP] Tokens_of_sentence_2", + explain: "A [CLS] special token is needed at the beginning as well as a [SEP] special token to separate the two sentences, but that's not all!" + } + ]} +/> + +{#if fw === 'pt'} +### 4. What are the benefits of the `Dataset.map()` method? + + + +### 5. What does dynamic padding mean? + + + +### 6. What is the purpose of a collate function? + +DataCollatorWithPadding specifically." + }, + { + text: "It puts together all the samples in a batch.", + explain: "Correct! You can pass the collate function as an argument of a DataLoader. We used the DataCollatorWithPadding function, which pads all items in a batch so they have the same length.", + correct: true + }, + { + text: "It preprocesses the whole dataset.", + explain: "That would be a preprocessing function, not a collate function." + }, + { + text: "It truncates the sequences in the dataset.", + explain: "A collate function is involved in handling individual batches, not the whole dataset. If you're interested in truncating, you can use the truncate argument of tokenizer." + } + ]} +/> + +### 7. What happens when you instantiate one of the `AutoModelForXxx` classes with a pretrained language model (such as `bert-base-uncased`) that corresponds to a different task than the one for which it was trained? + +AutoModelForSequenceClassification with bert-base-uncased, we got warnings when instantiating the model. The pretrained head is not used for the sequence classification task, so it's discarded and a new head is instantiated with random weights.", + correct: true + }, + { + text: "The head of the pretrained model is discarded.", + explain: "Something else needs to happen. Try again!" + }, + { + text: "Nothing, since the model can still be fine-tuned for the different task.", + explain: "The head of the pretrained model was not trained to solve this task, so we should discard the head!" + } + ]} +/> + +### 8. What's the purpose of `TrainingArguments`? + +Trainer.", + explain: "Correct!", + correct: true + }, + { + text: "It specifies the size of the model.", + explain: "The model size is defined by the model configuration, not the class TrainingArguments." + }, + { + text: "It just contains the hyperparameters used for evaluation.", + explain: "In the example, we specified where the model and its checkpoints will be saved. Try again!" + }, + { + text: "It just contains the hyperparameters used for training.", + explain: "In the example, we used an evaluation_strategy as well, so this impacts evaluation. Try again!" + } + ]} +/> + +### 9. Why should you use the 🤗 Accelerate library? + +Trainer, not the 🤗 Accelerate library. Try again!" + }, + { + text: "It makes our training loops work on distributed strategies", + explain: "Correct! With 🤗 Accelerate, your training loops will work for multiple GPUs and TPUs.", + correct: true + }, + { + text: "It provides more optimization functions.", + explain: "No, the 🤗 Accelerate library does not provide any optimization functions." + } + ]} +/> + +{:else} +### 4. What happens when you instantiate one of the `TFAutoModelForXxx` classes with a pretrained language model (such as `bert-base-uncased`) that corresponds to a different task than the one for which it was trained? + +TFAutoModelForSequenceClassification with bert-base-uncased, we got warnings when instantiating the model. The pretrained head is not used for the sequence classification task, so it's discarded and a new head is instantiated with random weights.", + correct: true + }, + { + text: "The head of the pretrained model is discarded.", + explain: "Something else needs to happen. Try again!" + }, + { + text: "Nothing, since the model can still be fine-tuned for the different task.", + explain: "The head of the pretrained model was not trained to solve this task, so we should discard the head!" + } + ]} +/> + +### 5. The TensorFlow models from `transformers` are already Keras models. What benefit does this offer? + +TPUStrategy scope, including the initialization of the model." + }, + { + text: "You can leverage existing methods such as compile(), fit(), and predict().", + explain: "Correct! Once you have the data, training on it requires very little work.", + correct: true + }, + { + text: "You get to learn Keras as well as transformers.", + explain: "Correct, but we're looking for something else :)", + correct: true + }, + { + text: "You can easily compute metrics related to the dataset.", + explain: "Keras helps us with training and evaluating the model, not computing dataset-related metrics." + } + ]} +/> + +### 6. How can you define your own custom metric? + +tf.keras.metrics.Metric.", + explain: "Great!", + correct: true + }, + { + text: "Using the Keras functional API.", + explain: "Try again!" + }, + { + text: "By using a callable with signature metric_fn(y_true, y_pred).", + explain: "Correct!", + correct: true + }, + { + text: "By Googling it.", + explain: "That's not the answer we're looking for, but it should help you find it.", + correct: true + } + ]} +/> + +{/if} \ No newline at end of file From f38ca66c13074f325e241c133dd3e803b55b6675 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sat, 30 Apr 2022 08:48:35 +0200 Subject: [PATCH 097/502] file removed --- chapters/fa/chapter3/2.mdx | 390 ---------------------------------- chapters/fa/chapter3/3.mdx | 172 --------------- chapters/fa/chapter3/3_tf.mdx | 203 ------------------ 3 files changed, 765 deletions(-) delete mode 100644 chapters/fa/chapter3/2.mdx delete mode 100644 chapters/fa/chapter3/3.mdx delete mode 100644 chapters/fa/chapter3/3_tf.mdx diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx deleted file mode 100644 index 5be25d104..000000000 --- a/chapters/fa/chapter3/2.mdx +++ /dev/null @@ -1,390 +0,0 @@ - - -# پردازش داده -# Processing the data - -{#if fw === 'pt'} - - - -{:else} - - - -{/if} - -{#if fw === 'pt'} - -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بَتچ توسط pytorch را شرح می‌دهیم: - -```python -import torch -from transformers import AdamW, 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)، نحوه آموزش یک مدل ترتیبی در یک بَتچ توسط pytorch را شرح می‌دهیم: - -```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 (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه‌داده این است که مجموعه‌داده کوچکیست و تجربه آموزش دادن روی آن آسان است. - -### بارگذاری یک داده از هاب - -### Loading a dataset from the Hub - -{#if fw === 'pt'} - -{:else} - -{/if} - -هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبان‌های مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه‌داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. - -کتابخانه مجموعه‌داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه‌داده در هاب ارائه می‌کند. ما می‌توانیم مجموعه‌داده 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` با استفاده از شماره‌گذاری, مانند یک dictionary دسترسی پیدا کنیم: - -```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)} -``` - -در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. - - -✏️ **امتحان کنید!** عنصر شماره ۱۵ از داده 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` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی، جمله اول و کدام بخش جمله دوم است. - - - -✏️ **امتحان کنید!** عنصر شماره ۱۵ داده را بردارید و دو جمله را به صورت جداگانه و جفت توکنایز کنید. تفاوت دو نتیجه چیست؟ - - - -اگر آیدی‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: - -```py -tokenizer.convert_ids_to_tokens(inputs["input_ids"]) -``` - -خواهیم داشت: - -we will get: - -```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, -) -``` -این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل مجموعه‌داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه‌داده‌های موجود در پایگاه مجموعه‌داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه می‌دارید). - -به منظور نگه داشتن داده به صورت یک مجموعه‌داده، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#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` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. این توکنایزر با توکنایزری در کتابخانه [🤗 Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. - -توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر مجموعه‌داده. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. - -در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل مجموعه‌داده به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از مجموعه‌داده ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: - -```py -tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) -tokenized_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` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایزر سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. - - -تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های مجموعه‌داده افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در مجموعه‌داده که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. - -آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. - - -### هم‌طول‌سازی پویا - -### Dynamic padding - - - -{#if fw === 'pt'} - -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU ها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. - -{:else} - -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. - -{/if} - -برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `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} - - - -✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی مجموعه‌داده 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} diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx deleted file mode 100644 index 749cfd511..000000000 --- a/chapters/fa/chapter3/3.mdx +++ /dev/null @@ -1,172 +0,0 @@ - - -# Fine-tuning a model with the Trainer API - - - - - -🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). - -The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: - -```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) -``` - -### Training - -The first step before we can define our `Trainer` is to define a `TrainingArguments` class that will contain all the hyperparameters the `Trainer` will use for training and evaluation. The only argument you have to provide is a directory where the trained model will be saved, as well as the checkpoints along the way. For all the rest, you can leave the defaults, which should work pretty well for a basic fine-tuning. - -```py -from transformers import TrainingArguments - -training_args = TrainingArguments("test-trainer") -``` - - - -💡 If you want to automatically upload your model to the Hub during training, pass along `push_to_hub=True` in the `TrainingArguments`. We will learn more about this in [Chapter 4](/course/chapter4/3) - - - -The second step is to define our model. As in the [previous chapter](/course/chapter2), we will use the `AutoModelForSequenceClassification` class, with two labels: - -```py -from transformers import AutoModelForSequenceClassification - -model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) -``` - -You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. - -Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `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, -) -``` - -Note that when you pass the `tokenizer` as we did here, the default `data_collator` used by the `Trainer` will be a `DataCollatorWithPadding` as defined previously, so you can skip the line `data_collator=data_collator` in this call. It was still important to show you this part of the processing in section 2! - -To fine-tune the model on our dataset, we just have to call the `train()` method of our `Trainer`: - -```py -trainer.train() -``` - -This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: - -1. We didn't tell the `Trainer` to evaluate during training by setting `evaluation_strategy` to either `"steps"` (evaluate every `eval_steps`) or `"epoch"` (evaluate at the end of each epoch). -2. We didn't provide the `Trainer` with a `compute_metrics()` function to calculate a metric during said evaluation (otherwise the evaluation would just have printed the loss, which is not a very intuitive number). - - -### Evaluation - -Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: - -```py -predictions = trainer.predict(tokenized_datasets["validation"]) -print(predictions.predictions.shape, predictions.label_ids.shape) -``` - -```python out -(408, 2) (408,) -``` - -The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. - -As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: - -```py -import numpy as np - -preds = np.argmax(predictions.predictions, axis=-1) -``` - -We can now compare those `preds` to the labels. To build our `compute_metric()` function, we will rely on the metrics from the 🤗 Datasets library. We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: - -```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} -``` - -The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. - -Wrapping everything together, we get our `compute_metrics()` function: - -```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) -``` - -And to see it used in action to report metrics at the end of each epoch, here is how we define a new `Trainer` with this `compute_metrics()` function: - -```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, -) -``` - -Note that we create a new `TrainingArguments` with its `evaluation_strategy` set to `"epoch"` and a new model — otherwise, we would just be continuing the training of the model we have already trained. To launch a new training run, we execute: - -``` -trainer.train() -``` - -This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. - -The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. - -This concludes the introduction to fine-tuning using the `Trainer` API. An example of doing this for most common NLP tasks will be given in Chapter 7, but for now let's look at how to do the same thing in pure PyTorch. - - - -✏️ **Try it out!** Fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. - - - diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx deleted file mode 100644 index 85a4626dd..000000000 --- a/chapters/fa/chapter3/3_tf.mdx +++ /dev/null @@ -1,203 +0,0 @@ - - -# باز‌تنظیم یک مدل با استفاده از کِراس - -# Fine-tuning a model with Keras - - - -وقتی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا آموزشِ مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر تنظیمات GPU را انجام نداده‌اید، می‌توانید به GPUها یا TPUها مجانی روی [Google Colab](https://colab.research.google.com/) دسترسی داشته باشید. - -Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). - -The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: - -```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, -) -``` - -### Training - -TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. - - - -That means that once we have our data, very little work is required to begin training on it. - - - -As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: - -```py -from transformers import TFAutoModelForSequenceClassification - -model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) -``` - -You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. - -To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. - - - -Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. - - - -```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, -) -``` - - - -Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. - - - - -### Improving training performance - - - -If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause -is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes -that optimizer with default values for all parameters, including learning rate. From long experience, though, we know -that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written -as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. - -In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate -over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* -the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is -`PolynomialDecay` — despite the name, with default settings it simply linearly decays the learning rate from the initial -value to the final value over the course of training, which is exactly what we want. In order to use a scheduler correctly, -though, we need to tell it how long training is going to be. We compute that as `num_train_steps` below. - -```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) -``` - - - -The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. - - - -Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: - -```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"]) -``` - -Now, we fit again: - -```py -model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -``` - - - -💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) - - - -### Model predictions - - - - -Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. - -```py -preds = model.predict(tf_validation_dataset)["logits"] -``` - -We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: - -```py -class_preds = np.argmax(preds, axis=1) -print(preds.shape, class_preds.shape) -``` - -```python out -(408, 2) (408,) -``` - -Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: - -```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} -``` - -The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. - -This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. From bf5bf0f4c43b5374bded2ef20296d425f51214e2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sat, 30 Apr 2022 08:51:38 +0200 Subject: [PATCH 098/502] mistake fixed --- chapters/fa/chapter3/2.mdx | 390 +++++++++++++++++++++++++++++++++++++ chapters/fa/chapter3/4.mdx | 359 ---------------------------------- chapters/fa/chapter3/5.mdx | 20 -- chapters/fa/chapter3/6.mdx | 296 ---------------------------- 4 files changed, 390 insertions(+), 675 deletions(-) create mode 100644 chapters/fa/chapter3/2.mdx delete mode 100644 chapters/fa/chapter3/4.mdx delete mode 100644 chapters/fa/chapter3/5.mdx delete mode 100644 chapters/fa/chapter3/6.mdx diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx new file mode 100644 index 000000000..5be25d104 --- /dev/null +++ b/chapters/fa/chapter3/2.mdx @@ -0,0 +1,390 @@ + + +# پردازش داده +# Processing the data + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بَتچ توسط pytorch را شرح می‌دهیم: + +```python +import torch +from transformers import AdamW, 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)، نحوه آموزش یک مدل ترتیبی در یک بَتچ توسط pytorch را شرح می‌دهیم: + +```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 (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه‌داده این است که مجموعه‌داده کوچکیست و تجربه آموزش دادن روی آن آسان است. + +### بارگذاری یک داده از هاب + +### Loading a dataset from the Hub + +{#if fw === 'pt'} + +{:else} + +{/if} + +هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبان‌های مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه‌داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. + +کتابخانه مجموعه‌داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه‌داده در هاب ارائه می‌کند. ما می‌توانیم مجموعه‌داده 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` با استفاده از شماره‌گذاری, مانند یک dictionary دسترسی پیدا کنیم: + +```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)} +``` + +در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. + + +✏️ **امتحان کنید!** عنصر شماره ۱۵ از داده 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` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی، جمله اول و کدام بخش جمله دوم است. + + + +✏️ **امتحان کنید!** عنصر شماره ۱۵ داده را بردارید و دو جمله را به صورت جداگانه و جفت توکنایز کنید. تفاوت دو نتیجه چیست؟ + + + +اگر آیدی‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: + +```py +tokenizer.convert_ids_to_tokens(inputs["input_ids"]) +``` + +خواهیم داشت: + +we will get: + +```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, +) +``` +این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل مجموعه‌داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه‌داده‌های موجود در پایگاه مجموعه‌داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه می‌دارید). + +به منظور نگه داشتن داده به صورت یک مجموعه‌داده، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#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` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. این توکنایزر با توکنایزری در کتابخانه [🤗 Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. + +توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر مجموعه‌داده. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. + +در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل مجموعه‌داده به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از مجموعه‌داده ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: + +```py +tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) +tokenized_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` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایزر سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. + + +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های مجموعه‌داده افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در مجموعه‌داده که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. + +آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. + + +### هم‌طول‌سازی پویا + +### Dynamic padding + + + +{#if fw === 'pt'} + +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU ها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. + +{:else} + +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. + +{/if} + +برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `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} + + + +✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی مجموعه‌داده 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} diff --git a/chapters/fa/chapter3/4.mdx b/chapters/fa/chapter3/4.mdx deleted file mode 100644 index 54563ea7c..000000000 --- a/chapters/fa/chapter3/4.mdx +++ /dev/null @@ -1,359 +0,0 @@ -# A full training - - - - - -Now we'll see how to achieve the same results as we did in the last section without using the `Trainer` class. Again, we assume you have done the data processing in section 2. Here is a short summary covering everything you will need: - -```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) -``` - -### Prepare for training - -Before actually writing our training loop, we will need to define a few objects. The first ones are the dataloaders we will use to iterate over batches. But before we can define those dataloaders, we need to apply a bit of postprocessing to our `tokenized_datasets`, to take care of some things that the `Trainer` did for us automatically. Specifically, we need to: - -- Remove the columns corresponding to values the model does not expect (like the `sentence1` and `sentence2` columns). -- Rename the column `label` to `labels` (because the model expects the argument to be named `labels`). -- Set the format of the datasets so they return PyTorch tensors instead of lists. - -Our `tokenized_datasets` has one method for each of those steps: - -```py -tokenized_datasets = tokenized_datasets.remove_columns(["sentence1", "sentence2", "idx"]) -tokenized_datasets = tokenized_datasets.rename_column("label", "labels") -tokenized_datasets.set_format("torch") -tokenized_datasets["train"].column_names -``` - -We can then check that the result only has columns that our model will accept: - -```python -["attention_mask", "input_ids", "labels", "token_type_ids"] -``` - -Now that this is done, we can easily define our dataloaders: - -```py -from torch.utils.data import DataLoader - -train_dataloader = DataLoader( - tokenized_datasets["train"], shuffle=True, batch_size=8, collate_fn=data_collator -) -eval_dataloader = DataLoader( - tokenized_datasets["validation"], batch_size=8, collate_fn=data_collator -) -``` - -To quickly check there is no mistake in the data processing, we can inspect a batch like this: - -```py -for batch in train_dataloader: - break -{k: v.shape for k, v in batch.items()} -``` - -```python out -{'attention_mask': torch.Size([8, 65]), - 'input_ids': torch.Size([8, 65]), - 'labels': torch.Size([8]), - 'token_type_ids': torch.Size([8, 65])} -``` - -Note that the actual shapes will probably be slightly different for you since we set `shuffle=True` for the training dataloader and we are padding to the maximum length inside the batch. - -Now that we're completely finished with data preprocessing (a satisfying yet elusive goal for any ML practitioner), let's turn to the model. We instantiate it exactly as we did in the previous section: - -```py -from transformers import AutoModelForSequenceClassification - -model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) -``` - -To make sure that everything will go smoothly during training, we pass our batch to this model: - -```py -outputs = model(**batch) -print(outputs.loss, outputs.logits.shape) -``` - -```python out -tensor(0.5441, grad_fn=) torch.Size([8, 2]) -``` - -All 🤗 Transformers models will return the loss when `labels` are provided, and we also get the logits (two for each input in our batch, so a tensor of size 8 x 2). - -We're almost ready to write our training loop! We're just missing two things: an optimizer and a learning rate scheduler. Since we are trying to replicate what the `Trainer` was doing by hand, we will use the same defaults. The optimizer used by the `Trainer` is `AdamW`, which is the same as Adam, but with a twist for weight decay regularization (see ["Decoupled Weight Decay Regularization"](https://arxiv.org/abs/1711.05101) by Ilya Loshchilov and Frank Hutter): - -```py -from transformers import AdamW - -optimizer = AdamW(model.parameters(), lr=5e-5) -``` - -Finally, the learning rate scheduler used by default is just a linear decay from the maximum value (5e-5) to 0. To properly define it, we need to know the number of training steps we will take, which is the number of epochs we want to run multiplied by the number of training batches (which is the length of our training dataloader). The `Trainer` uses three epochs by default, so we will follow that: - -```py -from transformers import get_scheduler - -num_epochs = 3 -num_training_steps = num_epochs * len(train_dataloader) -lr_scheduler = get_scheduler( - "linear", - optimizer=optimizer, - num_warmup_steps=0, - num_training_steps=num_training_steps, -) -print(num_training_steps) -``` - -```python out -1377 -``` - -### The training loop - -One last thing: we will want to use the GPU if we have access to one (on a CPU, training might take several hours instead of a couple of minutes). To do this, we define a `device` we will put our model and our batches on: - -```py -import torch - -device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") -model.to(device) -device -``` - -```python out -device(type='cuda') -``` - -We are now ready to train! To get some sense of when training will be finished, we add a progress bar over our number of training steps, using the `tqdm` library: - -```py -from tqdm.auto import tqdm - -progress_bar = tqdm(range(num_training_steps)) - -model.train() -for epoch in range(num_epochs): - for batch in train_dataloader: - batch = {k: v.to(device) for k, v in batch.items()} - outputs = model(**batch) - loss = outputs.loss - loss.backward() - - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - progress_bar.update(1) -``` - -You can see that the core of the training loop looks a lot like the one in the introduction. We didn't ask for any reporting, so this training loop will not tell us anything about how the model fares. We need to add an evaluation loop for that. - - -### The evaluation loop - -As we did earlier, we will use a metric provided by the 🤗 Datasets library. We've already seen the `metric.compute()` method, but metrics can actually accumulate batches for us as we go over the prediction loop with the method `add_batch()`. Once we have accumulated all the batches, we can get the final result with `metric.compute()`. Here's how to implement all of this in an evaluation loop: - -```py -from datasets import load_metric - -metric = load_metric("glue", "mrpc") -model.eval() -for batch in eval_dataloader: - batch = {k: v.to(device) for k, v in batch.items()} - with torch.no_grad(): - outputs = model(**batch) - - logits = outputs.logits - predictions = torch.argmax(logits, dim=-1) - metric.add_batch(predictions=predictions, references=batch["labels"]) - -metric.compute() -``` - -```python out -{'accuracy': 0.8431372549019608, 'f1': 0.8907849829351535} -``` - -Again, your results will be slightly different because of the randomness in the model head initialization and the data shuffling, but they should be in the same ballpark. - - - -✏️ **Try it out!** Modify the previous training loop to fine-tune your model on the SST-2 dataset. - - - -### Supercharge your training loop with 🤗 Accelerate - - - -The training loop we defined earlier works fine on a single CPU or GPU. But using the [🤗 Accelerate](https://github.com/huggingface/accelerate) library, with just a few adjustments we can enable distributed training on multiple GPUs or TPUs. Starting from the creation of the training and validation dataloaders, here is what our manual training loop looks like: - -```py -from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler - -model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) -optimizer = AdamW(model.parameters(), lr=3e-5) - -device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") -model.to(device) - -num_epochs = 3 -num_training_steps = num_epochs * len(train_dataloader) -lr_scheduler = get_scheduler( - "linear", - optimizer=optimizer, - num_warmup_steps=0, - num_training_steps=num_training_steps, -) - -progress_bar = tqdm(range(num_training_steps)) - -model.train() -for epoch in range(num_epochs): - for batch in train_dataloader: - batch = {k: v.to(device) for k, v in batch.items()} - outputs = model(**batch) - loss = outputs.loss - loss.backward() - - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - progress_bar.update(1) -``` - -And here are the changes: - -```diff -+ from accelerate import Accelerator - from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler - -+ accelerator = Accelerator() - - model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) - optimizer = AdamW(model.parameters(), lr=3e-5) - -- device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") -- model.to(device) - -+ train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare( -+ train_dataloader, eval_dataloader, model, optimizer -+ ) - - num_epochs = 3 - num_training_steps = num_epochs * len(train_dataloader) - lr_scheduler = get_scheduler( - "linear", - optimizer=optimizer, - num_warmup_steps=0, - num_training_steps=num_training_steps - ) - - progress_bar = tqdm(range(num_training_steps)) - - model.train() - for epoch in range(num_epochs): - for batch in train_dataloader: -- batch = {k: v.to(device) for k, v in batch.items()} - outputs = model(**batch) - loss = outputs.loss -- loss.backward() -+ accelerator.backward(loss) - - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - progress_bar.update(1) -``` - -The first line to add is the import line. The second line instantiates an `Accelerator` object that will look at the environment and initialize the proper distributed setup. 🤗 Accelerate handles the device placement for you, so you can remove the lines that put the model on the device (or, if you prefer, change them to use `accelerator.device` instead of `device`). - -Then the main bulk of the work is done in the line that sends the dataloaders, the model, and the optimizer to `accelerator.prepare()`. This will wrap those objects in the proper container to make sure your distributed training works as intended. The remaining changes to make are removing the line that puts the batch on the `device` (again, if you want to keep this you can just change it to use `accelerator.device`) and replacing `loss.backward()` with `accelerator.backward(loss)`. - - -⚠️ In order to benefit from the speed-up offered by Cloud TPUs, we recommend padding your samples to a fixed length with the `padding="max_length"` and `max_length` arguments of the tokenizer. - - -If you'd like to copy and paste it to play around, here's what the complete training loop looks like with 🤗 Accelerate: - -```py -from accelerate import Accelerator -from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler - -accelerator = Accelerator() - -model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) -optimizer = AdamW(model.parameters(), lr=3e-5) - -train_dl, eval_dl, model, optimizer = accelerator.prepare( - train_dataloader, eval_dataloader, model, optimizer -) - -num_epochs = 3 -num_training_steps = num_epochs * len(train_dl) -lr_scheduler = get_scheduler( - "linear", - optimizer=optimizer, - num_warmup_steps=0, - num_training_steps=num_training_steps, -) - -progress_bar = tqdm(range(num_training_steps)) - -model.train() -for epoch in range(num_epochs): - for batch in train_dl: - outputs = model(**batch) - loss = outputs.loss - accelerator.backward(loss) - - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - progress_bar.update(1) -``` - -Putting this in a `train.py` script will make that script runnable on any kind of distributed setup. To try it out in your distributed setup, run the command: - -```bash -accelerate config -``` - -which will prompt you to answer a few questions and dump your answers in a configuration file used by this command: - -``` -accelerate launch train.py -``` - -which will launch the distributed training. - -If you want to try this in a Notebook (for instance, to test it with TPUs on Colab), just paste the code in a `training_function()` and run a last cell with: - -```python -from accelerate import notebook_launcher - -notebook_launcher(training_function) -``` - -You can find more examples in the [🤗 Accelerate repo](https://github.com/huggingface/accelerate/tree/main/examples). diff --git a/chapters/fa/chapter3/5.mdx b/chapters/fa/chapter3/5.mdx deleted file mode 100644 index dda8cb7fe..000000000 --- a/chapters/fa/chapter3/5.mdx +++ /dev/null @@ -1,20 +0,0 @@ - - -# Fine-tuning, Check! - -That was fun! In the first two chapters you learned about models and tokenizers, and now you know how to fine-tune them for your own data. To recap, in this chapter you: - -{#if fw === 'pt'} -* Learned about datasets in the [Hub](https://huggingface.co/datasets) -* Learned how to load and preprocess datasets, including using dynamic padding and collators -* Implemented your own fine-tuning and evaluation of a model -* Implemented a lower-level training loop -* Used 🤗 Accelerate to easily adapt your training loop so it works for multiple GPUs or TPUs - -{:else} -* Learned about datasets in the [Hub](https://huggingface.co/datasets) -* Learned how to load and preprocess datasets -* Learned how to fine-tune and evaluate a model with Keras -* Implemented a custom metric - -{/if} diff --git a/chapters/fa/chapter3/6.mdx b/chapters/fa/chapter3/6.mdx deleted file mode 100644 index 94d02da24..000000000 --- a/chapters/fa/chapter3/6.mdx +++ /dev/null @@ -1,296 +0,0 @@ - - - - -# End-of-chapter quiz - -Test what you learned in this chapter! - -### 1. The `emotion` dataset contains Twitter messages labeled with emotions. Search for it in the [Hub](https://huggingface.co/datasets), and read the dataset card. Which of these is not one of its basic emotions? - - - -### 2. Search for the `ar_sarcasm` dataset in the [Hub](https://huggingface.co/datasets). Which task does it support? - -dataset card!" - }, - { - text: "Named entity recognition", - explain: "That's not it — take another look at the dataset card!" - }, - { - text: "Question answering", - explain: "Alas, this question was not answered correctly. Try again!" - } - ]} -/> - -### 3. How does the BERT model expect a pair of sentences to be processed? - -[SEP] special token is needed to separate the two sentences, but that's not the only thing!" - }, - { - text: "[CLS] Tokens_of_sentence_1 Tokens_of_sentence_2", - explain: "A [CLS] special token is required at the beginning, but that's not the only thing!" - }, - { - text: "[CLS] Tokens_of_sentence_1 [SEP] Tokens_of_sentence_2 [SEP]", - explain: "That's correct!", - correct: true - }, - { - text: "[CLS] Tokens_of_sentence_1 [SEP] Tokens_of_sentence_2", - explain: "A [CLS] special token is needed at the beginning as well as a [SEP] special token to separate the two sentences, but that's not all!" - } - ]} -/> - -{#if fw === 'pt'} -### 4. What are the benefits of the `Dataset.map()` method? - - - -### 5. What does dynamic padding mean? - - - -### 6. What is the purpose of a collate function? - -DataCollatorWithPadding specifically." - }, - { - text: "It puts together all the samples in a batch.", - explain: "Correct! You can pass the collate function as an argument of a DataLoader. We used the DataCollatorWithPadding function, which pads all items in a batch so they have the same length.", - correct: true - }, - { - text: "It preprocesses the whole dataset.", - explain: "That would be a preprocessing function, not a collate function." - }, - { - text: "It truncates the sequences in the dataset.", - explain: "A collate function is involved in handling individual batches, not the whole dataset. If you're interested in truncating, you can use the truncate argument of tokenizer." - } - ]} -/> - -### 7. What happens when you instantiate one of the `AutoModelForXxx` classes with a pretrained language model (such as `bert-base-uncased`) that corresponds to a different task than the one for which it was trained? - -AutoModelForSequenceClassification with bert-base-uncased, we got warnings when instantiating the model. The pretrained head is not used for the sequence classification task, so it's discarded and a new head is instantiated with random weights.", - correct: true - }, - { - text: "The head of the pretrained model is discarded.", - explain: "Something else needs to happen. Try again!" - }, - { - text: "Nothing, since the model can still be fine-tuned for the different task.", - explain: "The head of the pretrained model was not trained to solve this task, so we should discard the head!" - } - ]} -/> - -### 8. What's the purpose of `TrainingArguments`? - -Trainer.", - explain: "Correct!", - correct: true - }, - { - text: "It specifies the size of the model.", - explain: "The model size is defined by the model configuration, not the class TrainingArguments." - }, - { - text: "It just contains the hyperparameters used for evaluation.", - explain: "In the example, we specified where the model and its checkpoints will be saved. Try again!" - }, - { - text: "It just contains the hyperparameters used for training.", - explain: "In the example, we used an evaluation_strategy as well, so this impacts evaluation. Try again!" - } - ]} -/> - -### 9. Why should you use the 🤗 Accelerate library? - -Trainer, not the 🤗 Accelerate library. Try again!" - }, - { - text: "It makes our training loops work on distributed strategies", - explain: "Correct! With 🤗 Accelerate, your training loops will work for multiple GPUs and TPUs.", - correct: true - }, - { - text: "It provides more optimization functions.", - explain: "No, the 🤗 Accelerate library does not provide any optimization functions." - } - ]} -/> - -{:else} -### 4. What happens when you instantiate one of the `TFAutoModelForXxx` classes with a pretrained language model (such as `bert-base-uncased`) that corresponds to a different task than the one for which it was trained? - -TFAutoModelForSequenceClassification with bert-base-uncased, we got warnings when instantiating the model. The pretrained head is not used for the sequence classification task, so it's discarded and a new head is instantiated with random weights.", - correct: true - }, - { - text: "The head of the pretrained model is discarded.", - explain: "Something else needs to happen. Try again!" - }, - { - text: "Nothing, since the model can still be fine-tuned for the different task.", - explain: "The head of the pretrained model was not trained to solve this task, so we should discard the head!" - } - ]} -/> - -### 5. The TensorFlow models from `transformers` are already Keras models. What benefit does this offer? - -TPUStrategy scope, including the initialization of the model." - }, - { - text: "You can leverage existing methods such as compile(), fit(), and predict().", - explain: "Correct! Once you have the data, training on it requires very little work.", - correct: true - }, - { - text: "You get to learn Keras as well as transformers.", - explain: "Correct, but we're looking for something else :)", - correct: true - }, - { - text: "You can easily compute metrics related to the dataset.", - explain: "Keras helps us with training and evaluating the model, not computing dataset-related metrics." - } - ]} -/> - -### 6. How can you define your own custom metric? - -tf.keras.metrics.Metric.", - explain: "Great!", - correct: true - }, - { - text: "Using the Keras functional API.", - explain: "Try again!" - }, - { - text: "By using a callable with signature metric_fn(y_true, y_pred).", - explain: "Correct!", - correct: true - }, - { - text: "By Googling it.", - explain: "That's not the answer we're looking for, but it should help you find it.", - correct: true - } - ]} -/> - -{/if} \ No newline at end of file From 2847e0c39fd9e8973e77d030eba210393052ecf2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 1 May 2022 07:51:39 +0200 Subject: [PATCH 099/502] new file added --- chapters/fa/chapter3/3_tf.mdx | 205 ++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 chapters/fa/chapter3/3_tf.mdx diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx new file mode 100644 index 000000000..a6d0f70bb --- /dev/null +++ b/chapters/fa/chapter3/3_tf.mdx @@ -0,0 +1,205 @@ + + +# باز‌تنظیم یک مدل با استفاده از کِراس + +# Fine-tuning a model with Keras + + + +وقتی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا آموزشِ مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر تنظیمات GPU ندارید، می‌توانید به GPUها یا TPUها مجانی روی [Google Colab](https://colab.research.google.com/) دسترسی داشته باشید. + +Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). + +نمونه کدِ‌های زیر فرض می‌کنند شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه جهت یادآوری آنچه نیاز دارید: + +The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: + +```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, +) +``` + +### Training + +TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. + + + +That means that once we have our data, very little work is required to begin training on it. + + + +As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: + +```py +from transformers import TFAutoModelForSequenceClassification + +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. + +To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. + + + +Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. + + + +```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, +) +``` + + + +Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. + + + + +### Improving training performance + + + +If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause +is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes +that optimizer with default values for all parameters, including learning rate. From long experience, though, we know +that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written +as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. + +In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate +over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* +the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is +`PolynomialDecay` — despite the name, with default settings it simply linearly decays the learning rate from the initial +value to the final value over the course of training, which is exactly what we want. In order to use a scheduler correctly, +though, we need to tell it how long training is going to be. We compute that as `num_train_steps` below. + +```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) +``` + + + +The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. + + + +Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: + +```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"]) +``` + +Now, we fit again: + +```py +model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) +``` + + + +💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) + + + +### Model predictions + + + + +Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. + +```py +preds = model.predict(tf_validation_dataset)["logits"] +``` + +We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: + +```py +class_preds = np.argmax(preds, axis=1) +print(preds.shape, class_preds.shape) +``` + +```python out +(408, 2) (408,) +``` + +Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: + +```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} +``` + +The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. + +This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. From 86af017ce8e3a97a2499ce87ac167e3024c2edc8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 1 May 2022 08:10:39 +0200 Subject: [PATCH 100/502] multiple new paragraph added to the translation --- chapters/fa/chapter3/3_tf.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index a6d0f70bb..bd943fd2e 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -54,16 +54,24 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` +### آموزش + ### Training +مدل‌های تِنسورفلو که از ترَنسفورمِرهای 🤗 وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. + TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. +آن به این معنی است که به محض اینکه در اختیار داشته باشیم، کار خیلی کمی لازم است تا آموزش را روی آن شروع کنیم. + That means that once we have our data, very little work is required to begin training on it. +مانند [previous chapter](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب استفاده خواهیم کرد: + As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: ```py From e01d74c356516b1a0c0b102e3b419a7114f16dcc Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 1 May 2022 08:14:47 +0200 Subject: [PATCH 101/502] minor update --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index bd943fd2e..df60da40a 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -64,7 +64,7 @@ TensorFlow models imported from 🤗 Transformers are already Keras models. Here -آن به این معنی است که به محض اینکه در اختیار داشته باشیم، کار خیلی کمی لازم است تا آموزش را روی آن شروع کنیم. +آن به این معنی است که به محض اینکه داده‌مان در اختیار بگیریم، کار خیلی کمی لازم است تا آموزش را روی آن شروع کنیم. That means that once we have our data, very little work is required to begin training on it. From e8cbf4a2cbec6a8576df46ccb2ee9e6eca5c2efd Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 3 May 2022 10:04:37 +0200 Subject: [PATCH 102/502] new paragraphs added. --- chapters/fa/chapter3/3_tf.mdx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index df60da40a..e85917338 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -64,13 +64,13 @@ TensorFlow models imported from 🤗 Transformers are already Keras models. Here -آن به این معنی است که به محض اینکه داده‌مان در اختیار بگیریم، کار خیلی کمی لازم است تا آموزش را روی آن شروع کنیم. +آن به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار خیلی کمی لازم است تا آموزش را روی آن شروع کنیم. That means that once we have our data, very little work is required to begin training on it. -مانند [previous chapter](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب استفاده خواهیم کرد: +مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب استفاده خواهیم کرد: As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: @@ -80,12 +80,18 @@ from transformers import TFAutoModelForSequenceClassification model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` +شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از نمونه‌سازیِ این مدل پیش‌تعلیم شما یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی جفت جمله‌ها پیش‌تعلیم نشده، بنابراین لایه-سر مدل پیش‌تعلیم حذف شده و یک لایه-سر مناسب جهت دسته بندی رشته‌‌ای به جای آن اضافه شده. هشدارها نشان می‌دهند که برخی از وزنها استفاده نشده‌اند (آنهایی که مربوط به لایه-سر جدید هستند) و برخی دیگر به صورت تصادفی مقدار‌دهی شده‌ند. (آنهایی که مربوط به لایه-سر پیش‌تعلیم حذف شده هستند). در نتیجه این شما را تشویق به آموزش مدل می‌کند، که دقیقا همان چیزی است که می‌خواهیم اکنون انجام دهیم. + You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. +برای باز‌تنظیم مدل روی مجموعه‌داده مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند باز‌تنظیم را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای آموزش را گزارش دهد، بعلاوه‌ی خطای تایید در انتهای هر epoch. + To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. +توجه داشته باشید که مدل‌های ترَنسفورمِر 🤗 قابلیت ویژه‌ای دارند که بسیاری از مدل‌های Keras ندارند - آنها به صورت خودکار یک تابع خطای مناسب استفاده می‌کنند که آنرا به صورت داخلی محاسبه می‌کنند. اگر آرگومانی برای تابع خطا در زمان `compile()` تعیین نکنید آنها از این تابع خطا به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع خطای داخلی شما نیاز خواهید داشت که برچسب‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب مجزا، که روش معمول استفاده از برچسب‌ها در مدل‌های Keras می‌باشد. شما مثال‌هایی از این را در بخش ۲ این آموزش خواهید دید، جایی که تعیین تابع خطای درست می‌تواند تا اندازه‌ای گول‌زننده باشد. به هر حال، برای دسته‌بندی رشته‌‌ای، یک تابع خطای استانداد Keras به خوبی کار می‌کند، بنابراین آن چیزی است که ما در اینجا استفاده خواهیم کرد. + Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. From bc24213a642611042a3ed191d622201638eb3f33 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 4 May 2022 16:48:54 +0200 Subject: [PATCH 103/502] toc_tree updated --- chapters/fa/_toctree.yml | 10 ++++++++++ chapters/fa/chapter3/3_tf.mdx | 1 - 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index 179c9d87a..6a1b81a92 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -13,6 +13,16 @@ - local: chapter2/1 title: مقدمه +- title: 3. بازتنظیمِ یک مدل از پیش‌تعلیم دیده # Translate this! + sections: + - local: chapter3/1 + title: مقدمه # Translate this! + - local: chapter3/2 + title: پردازش داده # Translate this! + - local: chapter3/3 + title: باز‌تنظیم یک مدل با استفاده از Trainer-API یا کِراس # Translate this! + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - title: واژه‌نامه sections: - local: glossary/1 diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index e85917338..f13f71740 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -116,7 +116,6 @@ Note a very common pitfall here — you *can* just pass the name of the loss as - ### Improving training performance From cca41c13ac6f7d2ed64c6555451c4b8d34e00055 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 15:10:49 +0200 Subject: [PATCH 104/502] rtl div added --- chapters/fa/chapter3/1.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 6cfa5d3ee..3869ae26f 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,3 +1,4 @@ +
# مقدمه @@ -20,4 +21,6 @@ {/if} -جهت بارگذاری چکپوینت تعلیم دیده خود در هاب هاگینگ‌فیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) \ No newline at end of file +جهت بارگذاری چکپوینت تعلیم دیده خود در هاب هاگینگ‌فیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) + +
\ No newline at end of file From 7d0e787d13a71761dc79b3149eb8dd9332a9df96 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 15:12:22 +0200 Subject: [PATCH 105/502] rtl div added --- chapters/fa/chapter3/2.mdx | 3 +++ chapters/fa/chapter3/3_tf.mdx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 5be25d104..f8d35c49a 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -1,3 +1,5 @@ +
+ # پردازش داده @@ -388,3 +390,4 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( این هم از این! حالا می‌توانیم این مجموعه‌داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. {/if} +
\ No newline at end of file diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index f13f71740..77df31ef0 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -1,3 +1,4 @@ +
# باز‌تنظیم یک مدل با استفاده از کِراس @@ -216,3 +217,5 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. + +
\ No newline at end of file From b94b45719caa3013d5f5cb30ee124ec24cea4119 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 15:29:05 +0200 Subject: [PATCH 106/502] Applied reviews to chapters part 1 and 2. New phrases added to G --- chapters/fa/chapter3/1.mdx | 10 +++++----- chapters/fa/chapter3/2.mdx | 32 ++++++++++++++++---------------- chapters/fa/chapter3/3_tf.mdx | 2 +- chapters/fa/glossary/1.mdx | 2 ++ 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 3869ae26f..ce767c60b 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -3,18 +3,18 @@ # مقدمه -در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدل‌های پیش‌تعلیم را جهت انجام پیش‌بینی‌های جدید بررسی کردیم. اما چگونه می‌توانید یک مدل پیش‌تعلیم را خودتان بازتنظیم کنید؟ +در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدل‌های پیش‌تعلیم را جهت انجام پیش‌بینی‌های جدید بررسی کردیم. اما چگونه می‌توانید یک مدل از پیش‌ تعلیم دیده را خودتان بازتنظیم کنید؟ {#if fw === 'pt'} -* چگونه یک مجموعه‌داده بزرگ را از هاب تهیه کنید -* چگونه از API سطح بالای "Trainer" برای بازتنظیم مدل استفاده کنید +* چگونه یک دیتاسِت بزرگ را از هاب تهیه کنید +* چگونه از `API` سطح بالای `Trainer` برای کوک کردن مدل استفاده کنید * چگونه یک چرخه‌تعلیم دلخواه درست کنید -* چگونه از کتابخانه Accelerate 🤗 برای اجرای چرخه‌تعلیم دلخواه در هر تنظیمات غیر متمرکزی استفاده کنید +* چگونه از کتابخانه `Accelerate` 🤗 برای اجرای چرخه‌تعلیم دلخواه در هر تنظیمات غیر متمرکزی استفاده کنید {:else} -* چگونه یک مجموعه‌داده بزرگ را از هاب تهیه کنید +* چگونه یک دیتاسِت بزرگ را از هاب تهیه کنید * چگونه از کِراس برای بازتنظیم مدل استفاده کنید * چگونه از کِراس برای استخراج پیش بینی‌ها استفاده کنید * چگونه از یک متریک دلخواه استفاده کنید diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index f8d35c49a..e9b393752 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -138,7 +138,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` مجموعه‌داده‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. +می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` دیتاسِت‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. ```py raw_train_dataset.features @@ -157,7 +157,7 @@ raw_train_dataset.features ✏️ **امتحان کنید!** عنصر شماره ۱۵ از داده training و عنصر شماره ۸۷ از داده validation را مشاهده کنید. برچسبهای آنها چیست؟
-### پیش‌پردازشِ یک مجموعه‌داده +### پیش‌پردازشِ یک دیتاسِت {#if fw === 'pt'} @@ -165,7 +165,7 @@ raw_train_dataset.features {/if} -به منظور پیش‌پردازش مجموعه‌داده، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: +به منظور پیش‌پردازش دیتاسِت، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: ```py from transformers import AutoTokenizer @@ -230,7 +230,7 @@ we will get: در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکنایز شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکنایزر می‌داند چه چیزی برای مدل فراهم کند. -اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل مجموعه‌داده‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ مجموعه‌داده‌ی training اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل دیتاسِتمان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دیتاسِت training اینگونه می‌باشد: ```py tokenized_dataset = tokenizer( @@ -240,26 +240,26 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` -این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل مجموعه‌داده در حین توکنایز کردن داشته باشید (در حالی که مجموعه‌داده‌های موجود در پایگاه مجموعه‌داده‌‌ی 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه می‌دارید). +این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل دیتاسِت در حین توکنایز کردن داشته باشید (در حالی که دیتاسِت‌های موجود در پایگاه دیتاسِت 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه می‌دارید). -به منظور نگه داشتن داده به صورت یک مجموعه‌داده، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر مجموعه‌داده عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک دیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#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` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. این توکنایزر با توکنایزری در کتابخانه [🤗 Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. +این تابع یک دیکشنری (مثل اقلام داخل دیتاسِت) دریافت میکند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids` بازمی‌گرداند. توجه داشته باشید از آنجایی که توکنایزر روی لیستهایی از جفت جمله‌ها کار می‌کند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `()map` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. این توکنایزر با توکنایزری در کتابخانه [🤗 Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. -توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر مجموعه‌داده. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. +توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. -در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل مجموعه‌داده به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از مجموعه‌داده ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: +در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: ```py tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -روشی که کتابخانه مجموعه‌داده 🤗 این پیش‌پردازش را اعمال می‌کند، با افزودن -فیلدهای- جدید به مجموعه‌داده‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، می‌باشد:، +روشی که کتابخانه دیتاسِت 🤗 این پیش‌پردازش را اعمال می‌کند، با افزودن -فیلدهای- جدید به دیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، می‌باشد:، ```python out DatasetDict({ @@ -281,7 +281,7 @@ DatasetDict({ شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `()map` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایزر سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. -تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های مجموعه‌داده افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در مجموعه‌داده که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. @@ -302,7 +302,7 @@ DatasetDict({ {/if} -برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های مجموعه‌داده‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند، و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند، و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} ```py @@ -330,7 +330,7 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se [50, 59, 47, 67, 59, 50, 62, 32] ``` -تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل مجموعه‌داده باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: +تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دیتاسِت باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: ```py batch = data_collator(samples) @@ -361,13 +361,13 @@ batch = data_collator(samples) -✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی مجموعه‌داده GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. +✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی دیتاسِت GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور مجموعه‌داده‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک مجموعه‌داده 🤗 را به سرعت به فرمت آماده برای آموزش تبدیل کند. اجازه دهید آنرا در عمل با مجموعه‌داده‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور دیتاسِت‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دیتاسِت 🤗 را به سرعت به فرمت آماده برای آموزش تبدیل کند. اجازه دهید آنرا در عمل با دیتاسِت‌مان مشاهده کنیم! ```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( @@ -387,7 +387,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -این هم از این! حالا می‌توانیم این مجموعه‌داده‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. +این هم از این! حالا می‌توانیم این دیتاسِت‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. {/if} \ No newline at end of file diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 77df31ef0..0db366978 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -85,7 +85,7 @@ model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_lab You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -برای باز‌تنظیم مدل روی مجموعه‌داده مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند باز‌تنظیم را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای آموزش را گزارش دهد، بعلاوه‌ی خطای تایید در انتهای هر epoch. +برای کوک‌ کردن مدل روی دیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای آموزش را گزارش دهد، بعلاوه‌ی خطای تایید در انتهای هر epoch. To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index 8587b671b..81979861d 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -54,6 +54,8 @@ | Script | اسکریپت‌ | | Feature | قابلیت | | Folder | پوشه | +|fine-tune|کوک کردن| +|dataset|دیتاسِت| معادل‌هایی که استفاده نمی‌کنیم: From d764628ee96bcf9eca1a5428aeba396407a2ab5b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 15:30:28 +0200 Subject: [PATCH 107/502] test remove rtl div --- chapters/fa/chapter3/1.mdx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index ce767c60b..340b8de5b 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,9 +1,9 @@ -
+ # مقدمه -در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدل‌های پیش‌تعلیم را جهت انجام پیش‌بینی‌های جدید بررسی کردیم. اما چگونه می‌توانید یک مدل از پیش‌ تعلیم دیده را خودتان بازتنظیم کنید؟ +در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدل‌های پیش‌تعلیم را جهت انجام پیش‌بینی‌های جدید بررسی کردیم. اما چگونه می‌توانید یک مدل از پیش‌ تعلیم دیده را خودتان کوک‌ کردن کنید؟ {#if fw === 'pt'} @@ -15,7 +15,7 @@ {:else} * چگونه یک دیتاسِت بزرگ را از هاب تهیه کنید -* چگونه از کِراس برای بازتنظیم مدل استفاده کنید +* چگونه از کِراس برای کوک‌ کردن مدل استفاده کنید * چگونه از کِراس برای استخراج پیش بینی‌ها استفاده کنید * چگونه از یک متریک دلخواه استفاده کنید @@ -23,4 +23,3 @@ جهت بارگذاری چکپوینت تعلیم دیده خود در هاب هاگینگ‌فیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) -
\ No newline at end of file From 59a6274313947db36af6ec314d64be128a56c4aa Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 15:31:27 +0200 Subject: [PATCH 108/502] test remove rtl div --- chapters/fa/chapter3/1.mdx | 3 ++- chapters/fa/chapter3/2.mdx | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 340b8de5b..55406ebd7 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,4 +1,4 @@ - +
# مقدمه @@ -23,3 +23,4 @@ جهت بارگذاری چکپوینت تعلیم دیده خود در هاب هاگینگ‌فیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) +
\ No newline at end of file diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index e9b393752..614c54dd9 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -1,4 +1,4 @@ -
+ @@ -355,7 +355,7 @@ batch = data_collator(samples) 'labels': torch.Size([8])} ``` -به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل مان می‌تواند با آنها کار کند، آماده هستیم برای انجام بازتنظیم مدل: +به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل مان می‌تواند با آنها کار کند، آماده هستیم برای انجام کوک‌ کردن مدل: {/if} @@ -390,4 +390,3 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( این هم از این! حالا می‌توانیم این دیتاسِت‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. {/if} -
\ No newline at end of file From 0349df6e50521bb1d8fb57aff8b41945cee655b2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 15:42:30 +0200 Subject: [PATCH 109/502] comment applies --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 614c54dd9..844654825 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -124,7 +124,7 @@ DatasetDict({ این دستور مجموعه‌داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. -ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از شماره‌گذاری, مانند یک dictionary دسترسی پیدا کنیم: +ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک dictionary دسترسی پیدا کنیم: ```py raw_train_dataset = raw_datasets["train"] @@ -138,7 +138,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌بینم که برچسبها از پیش مقادیر صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم تابع `features` دیتاسِت‌مان `raw_train_dataset`‌ را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. +می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. ```py raw_train_dataset.features From 8bdfb66d9c19b3974c8e79b9aa325563ed94a3f0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 15:55:36 +0200 Subject: [PATCH 110/502] all comment applied --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 844654825..efe4edc0e 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -138,7 +138,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این تابع نوع هر سطون را به ما خواهد گفت. +می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر سطون را به ما خواهد گفت. ```py raw_train_dataset.features From f651342d62f98414c7c15d11803a05369757772b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 19:46:18 +0200 Subject: [PATCH 111/502] comments applies --- chapters/fa/chapter3/1.mdx | 12 ++++++------ chapters/fa/chapter3/3_tf.mdx | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 55406ebd7..140a34482 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -3,24 +3,24 @@ # مقدمه -در [فصل ۲](/course/chapter2) نحوه استفاده از توکنایزرها و مدل‌های پیش‌تعلیم را جهت انجام پیش‌بینی‌های جدید بررسی کردیم. اما چگونه می‌توانید یک مدل از پیش‌ تعلیم دیده را خودتان کوک‌ کردن کنید؟ +در [فصل ۲](/course/chapter2) نحوه استفاده از توکِنایزرها و مدل‌های از پیش تعلیم دیده را جهت انجام پیش‌بینی‌های جدید بررسی کردیم. اما چگونه می‌توانید یک مدل از پیش‌ تعلیم دیده را خودتان کوک‌ کنید؟ {#if fw === 'pt'} * چگونه یک دیتاسِت بزرگ را از هاب تهیه کنید * چگونه از `API` سطح بالای `Trainer` برای کوک کردن مدل استفاده کنید -* چگونه یک چرخه‌تعلیم دلخواه درست کنید -* چگونه از کتابخانه `Accelerate` 🤗 برای اجرای چرخه‌تعلیم دلخواه در هر تنظیمات غیر متمرکزی استفاده کنید +* چگونه یک چرخه‌ تعلیم دلخواه درست کنید +* چگونه از کتابخانه `Accelerate` هاگینگ‌فِیس برای اجرای چرخه‌ تعلیم دلخواه در هر نوع تنظیمات غیر متمرکزی استفاده کنید {:else} * چگونه یک دیتاسِت بزرگ را از هاب تهیه کنید * چگونه از کِراس برای کوک‌ کردن مدل استفاده کنید -* چگونه از کِراس برای استخراج پیش بینی‌ها استفاده کنید -* چگونه از یک متریک دلخواه استفاده کنید +* چگونه از کِراس برای استخراج پیش‌بینی‌ها استفاده کنید +* چگونه از یک مِتریک دلخواه استفاده کنید {/if} -جهت بارگذاری چکپوینت تعلیم دیده خود در هاب هاگینگ‌فیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) +جهت بارگذاری چکپوینت تعلیم دیده خود در هاب هاگینگ‌فِیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) \ No newline at end of file diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 0db366978..5adede6a0 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -59,7 +59,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ### Training -مدل‌های تِنسورفلو که از ترَنسفورمِرهای 🤗 وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. +مدل‌های تِنسورفلو که از ترَنسفورمِرهای هاگینگ‌فِیس وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. @@ -91,7 +91,7 @@ To fine-tune the model on our dataset, we just have to `compile()` our model and -توجه داشته باشید که مدل‌های ترَنسفورمِر 🤗 قابلیت ویژه‌ای دارند که بسیاری از مدل‌های Keras ندارند - آنها به صورت خودکار یک تابع خطای مناسب استفاده می‌کنند که آنرا به صورت داخلی محاسبه می‌کنند. اگر آرگومانی برای تابع خطا در زمان `compile()` تعیین نکنید آنها از این تابع خطا به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع خطای داخلی شما نیاز خواهید داشت که برچسب‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب مجزا، که روش معمول استفاده از برچسب‌ها در مدل‌های Keras می‌باشد. شما مثال‌هایی از این را در بخش ۲ این آموزش خواهید دید، جایی که تعیین تابع خطای درست می‌تواند تا اندازه‌ای گول‌زننده باشد. به هر حال، برای دسته‌بندی رشته‌‌ای، یک تابع خطای استانداد Keras به خوبی کار می‌کند، بنابراین آن چیزی است که ما در اینجا استفاده خواهیم کرد. +توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های Keras ندارند - آنها به صورت خودکار یک تابع خطای مناسب استفاده می‌کنند که آنرا به صورت داخلی محاسبه می‌کنند. اگر آرگومانی برای تابع خطا در زمان `compile()` تعیین نکنید آنها از این تابع خطا به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع خطای داخلی شما نیاز خواهید داشت که برچسب‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب مجزا، که روش معمول استفاده از برچسب‌ها در مدل‌های Keras می‌باشد. شما مثال‌هایی از این را در بخش ۲ این آموزش خواهید دید، جایی که تعیین تابع خطای درست می‌تواند تا اندازه‌ای گول‌زننده باشد. به هر حال، برای دسته‌بندی رشته‌‌ای، یک تابع خطای استانداد Keras به خوبی کار می‌کند، بنابراین آن چیزی است که ما در اینجا استفاده خواهیم کرد. Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. From 1c9dbd52b1c7e7e2eeb1567b6bb3d63d5fb951d0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 20:01:32 +0200 Subject: [PATCH 112/502] some comments applied --- chapters/fa/chapter3/1.mdx | 8 ++++---- chapters/fa/glossary/1.mdx | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 140a34482..e3c8ac49d 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -7,17 +7,17 @@ {#if fw === 'pt'} -* چگونه یک دیتاسِت بزرگ را از هاب تهیه کنید +* چگونه دیتاسِت‌های بزرگ را از هاب تهیه کنید * چگونه از `API` سطح بالای `Trainer` برای کوک کردن مدل استفاده کنید * چگونه یک چرخه‌ تعلیم دلخواه درست کنید -* چگونه از کتابخانه `Accelerate` هاگینگ‌فِیس برای اجرای چرخه‌ تعلیم دلخواه در هر نوع تنظیمات غیر متمرکزی استفاده کنید +* چگونه از کتابخانه `Accelerate` هاگینگ‌فِیس برای اجرای چرخه‌ تعلیم دلخواه در هر نوع تنظیمات توزیع شده‌ای استفاده کنید {:else} -* چگونه یک دیتاسِت بزرگ را از هاب تهیه کنید +* چگونه دیتاسِت‌های بزرگ را از هاب تهیه کنید * چگونه از کِراس برای کوک‌ کردن مدل استفاده کنید * چگونه از کِراس برای استخراج پیش‌بینی‌ها استفاده کنید -* چگونه از یک مِتریک دلخواه استفاده کنید +* چگونه از مِتریک دلخواه استفاده کنید {/if} diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index 81979861d..a5ba8475e 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -40,6 +40,7 @@ | Windows | ویندوز | | macOS | سیستم‌عامل مک | | Distribution | توزیع | +| Distributed | توزیع شده | | Linux | لینوکس | | Workload | محاسبه، محاسبات | | Package Manager | پکیج‌منیجر | From 7bb86f1f52d6287ae3b3be4b1e58d2b714323116 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 20:18:24 +0200 Subject: [PATCH 113/502] comments applied --- chapters/fa/chapter3/1.mdx | 6 +++--- chapters/fa/chapter3/2.mdx | 32 ++++++++++++++++---------------- chapters/fa/chapter3/3_tf.mdx | 2 +- chapters/fa/glossary/1.mdx | 6 +++--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index e3c8ac49d..6b3879845 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -7,20 +7,20 @@ {#if fw === 'pt'} -* چگونه دیتاسِت‌های بزرگ را از هاب تهیه کنید +* چگونه دِیتاسِت‌های بزرگ را از هاب تهیه کنید * چگونه از `API` سطح بالای `Trainer` برای کوک کردن مدل استفاده کنید * چگونه یک چرخه‌ تعلیم دلخواه درست کنید * چگونه از کتابخانه `Accelerate` هاگینگ‌فِیس برای اجرای چرخه‌ تعلیم دلخواه در هر نوع تنظیمات توزیع شده‌ای استفاده کنید {:else} -* چگونه دیتاسِت‌های بزرگ را از هاب تهیه کنید +* چگونه دِیتاسِت‌های بزرگ را از هاب تهیه کنید * چگونه از کِراس برای کوک‌ کردن مدل استفاده کنید * چگونه از کِراس برای استخراج پیش‌بینی‌ها استفاده کنید * چگونه از مِتریک دلخواه استفاده کنید {/if} -جهت بارگذاری چکپوینت تعلیم دیده خود در هاب هاگینگ‌فِیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) +جهت آپلود نقطه تعلیم خود در هاب هاگینگ‌فِیس، احتیاج به یک حساب کاربری در huggingface.co خواهید داشت: [ایجاد حساب کاربری](https://huggingface.co/join) \ No newline at end of file diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index efe4edc0e..3fc081e0e 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -157,7 +157,7 @@ raw_train_dataset.features ✏️ **امتحان کنید!** عنصر شماره ۱۵ از داده training و عنصر شماره ۸۷ از داده validation را مشاهده کنید. برچسبهای آنها چیست؟ -### پیش‌پردازشِ یک دیتاسِت +### پیش‌پردازشِ یک دِیتاسِت‌ {#if fw === 'pt'} @@ -165,7 +165,7 @@ raw_train_dataset.features {/if} -به منظور پیش‌پردازش دیتاسِت، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: +به منظور پیش‌پردازش دِیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: ```py from transformers import AutoTokenizer @@ -230,7 +230,7 @@ we will get: در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکنایز شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکنایزر می‌داند چه چیزی برای مدل فراهم کند. -اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل دیتاسِتمان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دیتاسِت training اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل دِیتاسِتمان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دِیتاسِت training اینگونه می‌باشد: ```py tokenized_dataset = tokenizer( @@ -240,26 +240,26 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` -این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل دیتاسِت در حین توکنایز کردن داشته باشید (در حالی که دیتاسِت‌های موجود در پایگاه دیتاسِت 🤗 فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه می‌دارید). +این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل دِیتاسِت در حین توکنایز کردن داشته باشید (در حالی که دِیتاسِت‌های موجود در پایگاه دِیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه می‌دارید). -به منظور نگه داشتن داده به صورت یک دیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکنایز کند: +به منظور نگه داشتن داده به صورت یک دِیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#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` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. این توکنایزر با توکنایزری در کتابخانه [🤗 Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. +این تابع یک دیکشنری (مثل اقلام داخل دِیتاسِت) دریافت میکند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask`، و `token_type_ids` بازمی‌گرداند. توجه داشته باشید از آنجایی که توکنایزر روی لیستهایی از جفت جمله‌ها کار می‌کند، همانطور که قبلا مشاهده کردیم، این تابع نیز درصورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `()map` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. این توکنایزر با توکنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. -توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. +توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دِیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. -در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: +در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل دِیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دِیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: ```py tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -روشی که کتابخانه دیتاسِت 🤗 این پیش‌پردازش را اعمال می‌کند، با افزودن -فیلدهای- جدید به دیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، می‌باشد:، +روشی که کتابخانه دِیتاسِت هاگینگ‌فِیس این پیش‌پردازش را اعمال می‌کند، با افزودن -فیلدهای- جدید به دِیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، می‌باشد:، ```python out DatasetDict({ @@ -278,10 +278,10 @@ DatasetDict({ }) ``` -شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `()map` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر 🤗 از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایزر سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. +شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `()map` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایزر سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. -تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های دِیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دِیتاسِت که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. @@ -302,7 +302,7 @@ DatasetDict({ {/if} -برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای 🤗 چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند، و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دِیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند، و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} ```py @@ -330,7 +330,7 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se [50, 59, 47, 67, 59, 50, 62, 32] ``` -تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دیتاسِت باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: +تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دِیتاسِت باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: ```py batch = data_collator(samples) @@ -361,13 +361,13 @@ batch = data_collator(samples) -✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی دیتاسِت GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. +✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی دِیتاسِت GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور دیتاسِت‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دیتاسِت 🤗 را به سرعت به فرمت آماده برای آموزش تبدیل کند. اجازه دهید آنرا در عمل با دیتاسِت‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور دِیتاسِت‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دِیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای آموزش تبدیل کند. اجازه دهید آنرا در عمل با دِیتاسِت‌مان مشاهده کنیم! ```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( @@ -387,6 +387,6 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -این هم از این! حالا می‌توانیم این دیتاسِت‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. +این هم از این! حالا می‌توانیم این دِیتاسِت‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. {/if} diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 5adede6a0..ca62b27ca 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -85,7 +85,7 @@ model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_lab You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -برای کوک‌ کردن مدل روی دیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای آموزش را گزارش دهد، بعلاوه‌ی خطای تایید در انتهای هر epoch. +برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای آموزش را گزارش دهد، بعلاوه‌ی خطای تایید در انتهای هر epoch. To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index a5ba8475e..e8642a8bc 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -55,9 +55,9 @@ | Script | اسکریپت‌ | | Feature | قابلیت | | Folder | پوشه | -|fine-tune|کوک کردن| -|dataset|دیتاسِت| - +| Fine-tune | کوک کردن | +| Dataset | دِیتاسِت | +| Upload | آپلود | معادل‌هایی که استفاده نمی‌کنیم: From 6551eb89262ba181baae56b0c2b250725808b1da Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 21:01:21 +0200 Subject: [PATCH 114/502] new fixes applied --- chapters/fa/chapter3/2.mdx | 9 ++++----- chapters/fa/glossary/1.mdx | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 3fc081e0e..0e656dc9b 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -2,15 +2,14 @@ -# پردازش داده -# Processing the data +# پردازش داده {#if fw === 'pt'} @@ -19,7 +18,7 @@ @@ -27,7 +26,7 @@ {#if fw === 'pt'} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بَتچ توسط pytorch را شرح می‌دهیم: +در ادامه مثال [فصل قبل](/course/chapter2)،نشان می‌دهیم چگونه مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ در PyTorch آموزش می‌دهیم: ```python import torch diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index e8642a8bc..b6ef6e20a 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -58,6 +58,8 @@ | Fine-tune | کوک کردن | | Dataset | دِیتاسِت | | Upload | آپلود | +| Batch | بَتچ | + معادل‌هایی که استفاده نمی‌کنیم: From e9664af0de71095986f5b828255b4c8deb93db40 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 21:09:13 +0200 Subject: [PATCH 115/502] new fixes applied --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 0e656dc9b..ce08a8254 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -26,7 +26,7 @@ {#if fw === 'pt'} -در ادامه مثال [فصل قبل](/course/chapter2)،نشان می‌دهیم چگونه مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ در PyTorch آموزش می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط pytorch شرح می‌دهیم: ```python import torch @@ -52,7 +52,7 @@ optimizer.step() ``` {:else} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش یک مدل ترتیبی در یک بَتچ توسط pytorch را شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط pytorch شرح می‌دهیم: ```python import tensorflow as tf From a4311f544a95904185a3b81908fefcf3cdd5930c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 21:09:53 +0200 Subject: [PATCH 116/502] new fixes applied --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index ce08a8254..00b5e9807 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -26,7 +26,7 @@ {#if fw === 'pt'} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط pytorch شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط PyTorch شرح می‌دهیم: ```python import torch @@ -52,7 +52,7 @@ optimizer.step() ``` {:else} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط pytorch شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط PyTorch شرح می‌دهیم: ```python import tensorflow as tf From 1474c43ecb28a9ccf682af0f2225d125bd3c3268 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 21:17:07 +0200 Subject: [PATCH 117/502] new fixes applied --- chapters/fa/chapter3/2.mdx | 16 ++++++++-------- chapters/fa/chapter3/3_tf.mdx | 14 ++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 00b5e9807..e083ba8ff 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -26,7 +26,7 @@ {#if fw === 'pt'} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط PyTorch شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط پایتورچ شرح می‌دهیم: ```python import torch @@ -52,7 +52,7 @@ optimizer.step() ``` {:else} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه آموزش مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط PyTorch شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط پایتورچ شرح می‌دهیم: ```python import tensorflow as tf @@ -77,9 +77,9 @@ model.train_on_batch(batch, labels) {/if} -البته آموزش با استفاده از دو جمله به نتایج چشمگیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه‌داده بزرگتر خواهید داشت. +البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه‌داده بزرگتر خواهید داشت. -در این بخش ما از مجموعه‌داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه‌داده این است که مجموعه‌داده کوچکیست و تجربه آموزش دادن روی آن آسان است. +در این بخش ما از مجموعه‌داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه‌داده این است که مجموعه‌داده کوچکیست و تجربه تعلیم روی آن آسان است. ### بارگذاری یک داده از هاب @@ -293,11 +293,11 @@ DatasetDict({ {#if fw === 'pt'} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU ها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPU ها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. {:else} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه آموزش را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال آموزش روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. {/if} @@ -366,7 +366,7 @@ batch = data_collator(samples) {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور دِیتاسِت‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دِیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای آموزش تبدیل کند. اجازه دهید آنرا در عمل با دِیتاسِت‌مان مشاهده کنیم! +توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور دِیتاسِت‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دِیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دِیتاسِت‌مان مشاهده کنیم! ```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( @@ -386,6 +386,6 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -این هم از این! حالا می‌توانیم این دِیتاسِت‌ها را به درس بعدی ببریم، جایی که آموزش پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. +این هم از این! حالا می‌توانیم این دِیتاسِت‌ها را به درس بعدی ببریم، جایی که تعلیم پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. {/if} diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index ca62b27ca..9f0da034b 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -12,7 +12,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter3/section3_tf.ipynb"}, ]} /> -وقتی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا آموزشِ مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر تنظیمات GPU ندارید، می‌توانید به GPUها یا TPUها مجانی روی [Google Colab](https://colab.research.google.com/) دسترسی داشته باشید. +وقتی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر تنظیمات GPU ندارید، می‌توانید به GPUها یا TPUها مجانی روی [Google Colab](https://colab.research.google.com/) دسترسی داشته باشید. Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). @@ -55,9 +55,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -### آموزش - -### Training +### تعلیم مدل‌های تِنسورفلو که از ترَنسفورمِرهای هاگینگ‌فِیس وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. @@ -65,7 +63,7 @@ TensorFlow models imported from 🤗 Transformers are already Keras models. Here -آن به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار خیلی کمی لازم است تا آموزش را روی آن شروع کنیم. +آن به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار خیلی کمی لازم است تا تعلیم را روی آن شروع کنیم. That means that once we have our data, very little work is required to begin training on it. @@ -81,17 +79,17 @@ from transformers import TFAutoModelForSequenceClassification model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` -شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از نمونه‌سازیِ این مدل پیش‌تعلیم شما یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی جفت جمله‌ها پیش‌تعلیم نشده، بنابراین لایه-سر مدل پیش‌تعلیم حذف شده و یک لایه-سر مناسب جهت دسته بندی رشته‌‌ای به جای آن اضافه شده. هشدارها نشان می‌دهند که برخی از وزنها استفاده نشده‌اند (آنهایی که مربوط به لایه-سر جدید هستند) و برخی دیگر به صورت تصادفی مقدار‌دهی شده‌ند. (آنهایی که مربوط به لایه-سر پیش‌تعلیم حذف شده هستند). در نتیجه این شما را تشویق به آموزش مدل می‌کند، که دقیقا همان چیزی است که می‌خواهیم اکنون انجام دهیم. +شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از نمونه‌سازیِ این مدل پیش‌تعلیم شما یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی جفت جمله‌ها پیش‌تعلیم نشده، بنابراین لایه-سر مدل پیش‌تعلیم حذف شده و یک لایه-سر مناسب جهت دسته بندی رشته‌‌ای به جای آن اضافه شده. هشدارها نشان می‌دهند که برخی از وزنها استفاده نشده‌اند (آنهایی که مربوط به لایه-سر جدید هستند) و برخی دیگر به صورت تصادفی مقدار‌دهی شده‌ند. (آنهایی که مربوط به لایه-سر پیش‌تعلیم حذف شده هستند). در نتیجه این شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان چیزی است که می‌خواهیم اکنون انجام دهیم. You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای آموزش را گزارش دهد، بعلاوه‌ی خطای تایید در انتهای هر epoch. +برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای تعلیم را گزارش دهد، بعلاوه‌ی خطای تایید در انتهای هر epoch. To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. -توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های Keras ندارند - آنها به صورت خودکار یک تابع خطای مناسب استفاده می‌کنند که آنرا به صورت داخلی محاسبه می‌کنند. اگر آرگومانی برای تابع خطا در زمان `compile()` تعیین نکنید آنها از این تابع خطا به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع خطای داخلی شما نیاز خواهید داشت که برچسب‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب مجزا، که روش معمول استفاده از برچسب‌ها در مدل‌های Keras می‌باشد. شما مثال‌هایی از این را در بخش ۲ این آموزش خواهید دید، جایی که تعیین تابع خطای درست می‌تواند تا اندازه‌ای گول‌زننده باشد. به هر حال، برای دسته‌بندی رشته‌‌ای، یک تابع خطای استانداد Keras به خوبی کار می‌کند، بنابراین آن چیزی است که ما در اینجا استفاده خواهیم کرد. +توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های Keras ندارند - آنها به صورت خودکار یک تابع خطای مناسب استفاده می‌کنند که آنرا به صورت داخلی محاسبه می‌کنند. اگر آرگومانی برای تابع خطا در زمان `compile()` تعیین نکنید آنها از این تابع خطا به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع خطای داخلی شما نیاز خواهید داشت که برچسب‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب مجزا، که روش معمول استفاده از برچسب‌ها در مدل‌های Keras می‌باشد. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع خطای درست می‌تواند تا اندازه‌ای گول‌زننده باشد. به هر حال، برای دسته‌بندی رشته‌‌ای، یک تابع خطای استانداد Keras به خوبی کار می‌کند، بنابراین آن چیزی است که ما در اینجا استفاده خواهیم کرد. Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. From 42c55ff31a9f4846ea25a5740df3a79579259832 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 21:52:02 +0200 Subject: [PATCH 118/502] new fixes applied --- chapters/fa/chapter3/2.mdx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index e083ba8ff..54940b668 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -26,7 +26,7 @@ {#if fw === 'pt'} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط پایتورچ شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از پایتورچ شرح می‌دهیم: ```python import torch @@ -52,7 +52,7 @@ optimizer.step() ``` {:else} -در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ توسط پایتورچ شرح می‌دهیم: +در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از تِنسورفلو شرح می‌دهیم: ```python import tensorflow as tf @@ -77,23 +77,21 @@ model.train_on_batch(batch, labels) {/if} -البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای بدست آوردن نتایج بهتر نیاز به آماده سازی مجموعه‌داده بزرگتر خواهید داشت. +البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دِیتاسِت بزرگتری خواهید داشت. -در این بخش ما از مجموعه‌داده MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی William B. Dolan و Chris Brockett.، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این مجموعه‌داده این است که مجموعه‌داده کوچکیست و تجربه تعلیم روی آن آسان است. +در این بخش ما از دِیتاسِت MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این دِیتاسِت این است که دِیتاسِت کوچکیست و تجربه تعلیم روی آن آسان است. ### بارگذاری یک داده از هاب -### Loading a dataset from the Hub - {#if fw === 'pt'} {:else} {/if} -هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل مجموعه‌داده‌های متعدد در بسیاری زبان‌های مختلف می‌باشد. شما می‌توانید مجموعه‌داده‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک مجموعه‌داده جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. +هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل دِیتاسِت‌های متعدد در بسیاری زبان‌های مختلف می‌باشد. شما می‌توانید دِیتاسِت‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک دِیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. -کتابخانه مجموعه‌داده 🤗 یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک مجموعه‌داده در هاب ارائه می‌کند. ما می‌توانیم مجموعه‌داده MRPC را به روش زیر دانلود کنیم: +کتابخانه دِیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک دِیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دِیتاسِت MRPC را به روش زیر دانلود کنیم: ```py from datasets import load_dataset @@ -121,7 +119,7 @@ DatasetDict({ همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`label`، `sentence2`، `sentence1`، و `idx`) و تعداد متغیری ردیف داده که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training وجود دارد، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test). - این دستور مجموعه‌داده را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور دِیتاسِت را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک dictionary دسترسی پیدا کنیم: From 258b9828883c60df8d681dba89e4e9b81619605d Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 22:37:06 +0200 Subject: [PATCH 119/502] new fixes applied --- chapters/fa/chapter3/2.mdx | 18 +++++++++--------- chapters/fa/glossary/1.mdx | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 54940b668..d33ba0c76 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -79,9 +79,9 @@ model.train_on_batch(batch, labels) البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دِیتاسِت بزرگتری خواهید داشت. -در این بخش ما از دِیتاسِت MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این داده شامل ۵،۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشاندهنده متناظر بودن جملات (به عنوان مثال، آیا دو جمله معنی یکسانی دارند یا خیر) می‌باشد. علت انتخاب این دِیتاسِت این است که دِیتاسِت کوچکیست و تجربه تعلیم روی آن آسان است. +در این بخش ما از دِیتاسِت MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دِیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دِیتاسِت این است که دِیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. -### بارگذاری یک داده از هاب +### بارگذاری دِیتاسِت‌ها از هاب {#if fw === 'pt'} @@ -89,9 +89,9 @@ model.train_on_batch(batch, labels) {/if} -هاب تنها شامل مدلها نمی‌باشد؛ بلکه شامل دِیتاسِت‌های متعدد در بسیاری زبان‌های مختلف می‌باشد. شما می‌توانید دِیتاسِت‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک دِیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی داده MRPC تمرکز کنیم! این داده یکی از ۱۰ داده [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدلهای یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. +هاب تنها شامل مدل‌ها نمی‌باشد؛ بلکه شامل دِیتاسِت‌های متعدد در بسیاری از زبان‌های مختلف می‌باشد. شما می‌توانید دِیتاسِت‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک دِیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی دِیتاسِت MRPC تمرکز کنیم! این یکی از ۱۰ دِیتاسِت [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدل‌های یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. -کتابخانه دِیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره سازی یک دِیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دِیتاسِت MRPC را به روش زیر دانلود کنیم: +کتابخانه دِیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره‌سازی یک دِیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دِیتاسِت MRPC را به روش زیر دانلود کنیم: ```py from datasets import load_dataset @@ -117,11 +117,11 @@ DatasetDict({ }) ``` -همانطور که می بینید یک شیء "DatasetDict" بدست می‌آوریم که شامل مجموعه training، مجموعه validation، و مجموعه test می‌باشد. هریک از اینها شامل چندین سطون (`label`، `sentence2`، `sentence1`، و `idx`) و تعداد متغیری ردیف داده که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳،۶۶۸ جفت جمله در مجموعه training وجود دارد، ۴۰۸ تا در مجموعه validation، و ۱،۷۲۵ تا در مجموعه test). +همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). - این دستور دِیتاسِت را دانلود و به صورت پیش فرض در زیرشاخه‌ی *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازیتان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور دِیتاسِت را دانلود و به صورت پیش فرض در پوشه‌ي
*~/.cache/huggingface/dataset*
ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. -ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک dictionary دسترسی پیدا کنیم: +ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک `dictionary` دسترسی پیدا کنیم: ```py raw_train_dataset = raw_datasets["train"] @@ -135,7 +135,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر سطون را به ما خواهد گفت. +می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت. ```py raw_train_dataset.features @@ -315,7 +315,7 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf" ``` {/if} -اجازه دهید چند نمونه از مجموعه training مان، که می‌خواهیم باهم بَتچ کنیم، برداریم تا این ابزار جدید را امتحان کنیم. در اینجا سطون‌های `idx`، `sentence1`، و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: +اجازه دهید چند نمونه از مجموعه training مان، که می‌خواهیم باهم بَتچ کنیم، برداریم تا این ابزار جدید را امتحان کنیم. در اینجا ستون‌های `idx`، `sentence1`، و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: ```py samples = tokenized_datasets["train"][:8] diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index b6ef6e20a..4950f5558 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -59,7 +59,7 @@ | Dataset | دِیتاسِت | | Upload | آپلود | | Batch | بَتچ | - +| Label | برچسب | معادل‌هایی که استفاده نمی‌کنیم: From c93fe7e7e006d11c781b1f17512b67acec5c77d8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 22:51:29 +0200 Subject: [PATCH 120/502] new fixes applied --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index d33ba0c76..5511c7c7f 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -119,7 +119,7 @@ DatasetDict({ همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). - این دستور دِیتاسِت را دانلود و به صورت پیش فرض در پوشه‌ي
*~/.cache/huggingface/dataset*
ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور دِیتاسِت را دانلود و به صورت پیش فرض در پوشه‌ي *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک `dictionary` دسترسی پیدا کنیم: From e08e7cd52399475e786b003040225a2789a37f31 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 5 May 2022 23:01:32 +0200 Subject: [PATCH 121/502] Finally, all fixes applied --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 5511c7c7f..eb0df5e0f 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -119,9 +119,9 @@ DatasetDict({ همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). - این دستور دِیتاسِت را دانلود و به صورت پیش فرض در پوشه‌ي *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید زیرشاخه‌ی ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور دِیتاسِت را دانلود و به صورت پیش فرض در پوشه‌ي *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید پوشه‌ي ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. -ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک `dictionary` دسترسی پیدا کنیم: +ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک دیکشنری دسترسی پیدا کنیم: ```py raw_train_dataset = raw_datasets["train"] From 46f1fca796690d27fb130e5d6ecb312792840017 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:14:00 +0200 Subject: [PATCH 122/502] additional fixes made following the comments in the review --- chapters/fa/chapter3/2.mdx | 64 +++++++++++++++++++------------------- chapters/fa/glossary/1.mdx | 3 ++ 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index eb0df5e0f..9dde9a11e 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -119,7 +119,7 @@ DatasetDict({ همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). - این دستور دِیتاسِت را دانلود و به صورت پیش فرض در پوشه‌ي *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید پوشه‌ي ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور دِیتاسِت را دانلود و به صورت پیش‌فرض در پوشه‌ي *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید پوشه‌ي ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک دیکشنری دسترسی پیدا کنیم: @@ -135,7 +135,7 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` -می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای اینکه بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت. +می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت. ```py raw_train_dataset.features @@ -148,13 +148,13 @@ raw_train_dataset.features 'idx': Value(dtype='int32', id=None)} ``` -در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent`، و `1` مربوط به `equivalent` می‌باشد،. +در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` می‌باشد. -✏️ **امتحان کنید!** عنصر شماره ۱۵ از داده training و عنصر شماره ۸۷ از داده validation را مشاهده کنید. برچسبهای آنها چیست؟ +✏️ **امتحان کنید!** عنصر شماره ۱۵ از مجموعه `training` و عنصر شماره ۸۷ از مجموعه `validation` را مشاهده کنید. برچسب‌های آنها چیست؟ -### پیش‌پردازشِ یک دِیتاسِت‌ +### پیش‌پردازشِ دِیتاسِت‌‌ها {#if fw === 'pt'} @@ -162,7 +162,7 @@ raw_train_dataset.features {/if} -به منظور پیش‌پردازش دِیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنایزر بدهیم، در نتیجه می‌توانیم مستقیما تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکنایز کنیم: +به منظور پیش‌پردازش دِیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنِایزر بدهیم، در نتیجه می‌توانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِنایز کنیم: ```py from transformers import AutoTokenizer @@ -173,7 +173,7 @@ tokenized_sentences_1 = tokenizer(raw_datasets["train"]["sentence1"]) tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"]) ``` -با این حال، نمی‌توانیم دو جمله را به مدل ارسال کنیم تا پیش‌بینی کند متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم، و پیش‌پردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکنایزر می‌تواند یک جفت رشته را دریافت کند و آنرا به گونه‌ای که مدل BERT ما انتظار دارد آماده سازی کند: +با این حال، نمی‌توانیم دو جمله را به مدل ارسال کنیم تا پیش‌بینی کند که متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم، و پیش‌پردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکِنایزر می‌تواند یک جفت رشته را دریافت کند و آنرا به گونه‌ای که مدل BERT ما انتظار دارد آماده‌سازی کند: ```py inputs = tokenizer("This is the first sentence.", "This is the second one.") @@ -188,15 +188,15 @@ inputs } ``` -در [فصل ۲](/course/chapter2) در مورد کلیدهای `input_ids` و `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی، جمله اول و کدام بخش جمله دوم است. +در [فصل ۲](/course/chapter2) در مورد کلیدهای `input_ids` و `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. -✏️ **امتحان کنید!** عنصر شماره ۱۵ داده را بردارید و دو جمله را به صورت جداگانه و جفت توکنایز کنید. تفاوت دو نتیجه چیست؟ +✏️ **امتحان کنید!** عنصر شماره ۱۵ از مجموعه `training` را بردارید و دو جمله را به صورت جداگانه و جفت توکِنایز کنید. تفاوت دو نتیجه چیست؟ -اگر آیدی‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: +اگر شناسه‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: ```py tokenizer.convert_ids_to_tokens(inputs["input_ids"]) @@ -210,24 +210,24 @@ we will get: ['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] ``` -بنابراین می‌بینیم که مدل انتظار دارد وقتی که دو جمله داریم ورودی‌ها به صورت `[CLS] sentence1 [SEP] sentence2 [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` می‌باشد. +همانطور که می‌بینید، بخش‌هایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` هستند اندیسِ نشان دهنده نوع توکِن آنها `0` و بخش‌هایی که مربوط به `sentence2 [SEP]` هستند اندیس نشان دهنده نوع توکِن‌شان `1` می‌باشد. -توجه داشته باشید که اگر چکپوینت متفاوتی را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. +توجه داشته باشید که اگر نقطه تعلیمِ متفاوتی را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. -در اینجا، مدل BERT با آیدی‌هایی که نشاندهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبانِ ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ برعهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. +در اینجا، مدل BERT با آیدی‌هایی که نشان دهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبانِ ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ بر عهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. - در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ جمله‌ اول قرار دارد یا خیر. برای خارج کردن مسئله از حالت بدیهی، در نیمی از حالتها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. + در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ جمله‌ اول قرار دارد یا خیر. برای خارج کردن مسئله از حالت بدیهی، در نیمی از حالت‌ها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. -در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکنایز شده خود باشید: مادامی که از چکپوینت یکسان برای توکنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکنایزر می‌داند چه چیزی برای مدل فراهم کند. +در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکِنایز شده خود باشید: مادامی که از نقطه تعلیم یکسان برای توکِنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکِنایزر می‌داند چه چیزی برای مدل فراهم کند. -اکنون که مشاهده کردیم چگونه توکنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکنایز کردن کل دِیتاسِتمان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم نوکنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های padding و truncation که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دِیتاسِت training اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کلِ دِیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دِیتاسِت `training` اینگونه می‌باشد: ```py tokenized_dataset = tokenizer( @@ -237,26 +237,26 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` -این روش به خوبی کار می‌کند، اما مشکلش این است که یک dictionary برمیگرداند (از کلیدهای ما شامل، `input_ids`, `attention_mask`, و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند). همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل دِیتاسِت در حین توکنایز کردن داشته باشید (در حالی که دِیتاسِت‌های موجود در پایگاه دِیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه می‌دارید). +این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کلِ دِیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دِیتاسِت‌های موجود در پایگاه دِیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). -به منظور نگه داشتن داده به صورت یک دِیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده میکنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `()map` با اعمال کردن یک عملیات روی هر عنصر دِیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکنایز کند: +به منظور نگهداشتن داده به صورت یک دِیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#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` استفاده کنیم که توکنایزر را به میزان زیادی سریعتر خواهد کرد. این توکنایزر با توکنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. +این تابع یک دیکشنری (مثل اقلام داخل دِیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از جفت جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. -توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دِیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه جویی خواهد کرد. +توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` را زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دِیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. -در اینجا نشان می‌دهیم چگونه تابع توکنایزیشن را روی کل دِیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دِیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریعتر انجام گیرد: +در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دِیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دِیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: ```py tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -روشی که کتابخانه دِیتاسِت هاگینگ‌فِیس این پیش‌پردازش را اعمال می‌کند، با افزودن -فیلدهای- جدید به دِیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، می‌باشد:، +کتابخانه دِیتاسِت هاگینگ‌فِیس این پیش‌پردازش را با افزودن -فیلدهای- جدید به دِیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، اعمال می‌کند: ```python out DatasetDict({ @@ -275,10 +275,10 @@ DatasetDict({ }) ``` -شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `()map` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکنایز کردن سریعتر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکنایزر سریع که با این کتابخانه پشتیبانی میشود استفاده نمی‌کنید، این روش میتواند پیش‌پردازش شما را سریعتر کند. +شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکِنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکِنایز کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. -تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask`، و `token_type_ids`، برمیگرداند به گونه‌ای که این سه فیلد به همه بخش‌های دِیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دِیتاسِت که تابع `()map` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids`، برمی‌گرداند به گونه‌ای که این سه فیلد به همه بخش‌های دِیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دِیتاسِت که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. @@ -291,15 +291,15 @@ DatasetDict({ {#if fw === 'pt'} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش فرض تابعی است که نمونه‌های شما را به ماتریس PyTorch تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPU ها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش‌ فرض تابعی است که نمونه‌های شما را به ماتریس پایتورچ تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان‌پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPUها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. {:else} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. collator پیش فرض تابعی است که فقط نمونه‌های شما را به tf.Tensor تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل، یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیشگیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPU اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. `collator` پیش‌فرض تابعی است که فقط نمونه‌های شما را به `tf.Tensor` تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPUها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. {/if} -برای انجام اینکار در عمل، ما باید یک تابع collate تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دِیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند، و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام این کار در عمل، ما باید یک تابع `collate` تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دِیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهند. این تابع به محض اینکه آنرا تعریف کنیم (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} ```py @@ -315,7 +315,7 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf" ``` {/if} -اجازه دهید چند نمونه از مجموعه training مان، که می‌خواهیم باهم بَتچ کنیم، برداریم تا این ابزار جدید را امتحان کنیم. در اینجا ستون‌های `idx`، `sentence1`، و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: +اجازه دهید چند نمونه از مجموعه `training`مان را که می‌خواهیم باهم بَتچ کنیم برداریم تا این ابزار جدید را امتحان کنیم. در اینجا ستون‌های `idx`، `sentence1` و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: ```py samples = tokenized_datasets["train"][:8] @@ -327,7 +327,7 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se [50, 59, 47, 67, 59, 50, 62, 32] ``` -تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دِیتاسِت باید به اندازه بزرگترین طول یا بزرگترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: +تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دِیتاسِت باید به اندازه بزرگ‌ترین طول یا بزرگ‌ترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: ```py batch = data_collator(samples) @@ -352,7 +352,7 @@ batch = data_collator(samples) 'labels': torch.Size([8])} ``` -به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل مان می‌تواند با آنها کار کند، آماده هستیم برای انجام کوک‌ کردن مدل: +به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل‌مان می‌تواند با آنها کار کند، آماده هستیم برای کوک‌ کردن مدل: {/if} @@ -364,7 +364,7 @@ batch = data_collator(samples) {#if fw === 'tf'} -توجه داشته باشید که ما مجموعه‌‌داده مان و یک collator داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را collate کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه میکند: `()to_tf_dataset`. این روش یک `tf.data.Dataset` را دور دِیتاسِت‌تان می‌پیچد، با یک تابع collation دلخواه. `tf.data.Dataset` یک فرمت بومی تنسورفلو است که کِراس می‌تواند برای `()model.fit` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دِیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دِیتاسِت‌مان مشاهده کنیم! +توجه داشته باشید که ما دِیتاسِت‌مان و یک `collator` داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه می‌کند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور دِیتاسِت‌تان می‌پیچد، با یک تابع `collation` دلخواه. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس می‌تواند برای `model.fit()` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دِیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دِیتاسِت‌مان مشاهده کنیم! ```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index 4950f5558..bde5aae82 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -60,6 +60,9 @@ | Upload | آپلود | | Batch | بَتچ | | Label | برچسب | +| Padding | هم‌طول‌سازی | +| Dynamic padding | هم‌طول‌سازی پویا | + معادل‌هایی که استفاده نمی‌کنیم: From cb33b96fce6d091a09386b709a2aa92b72852c68 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:24:30 +0200 Subject: [PATCH 123/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 66 +++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 9dde9a11e..f68698102 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -1,5 +1,4 @@ - - +
# پردازش داده @@ -28,6 +27,7 @@ در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از پایتورچ شرح می‌دهیم: +
```python import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -50,10 +50,13 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` +
+ {:else} در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از تِنسورفلو شرح می‌دهیم: +
```python import tensorflow as tf import numpy as np @@ -74,6 +77,7 @@ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy") labels = tf.convert_to_tensor([1, 1]) model.train_on_batch(batch, labels) ``` +
{/if} @@ -93,13 +97,16 @@ model.train_on_batch(batch, labels) کتابخانه دِیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره‌سازی یک دِیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دِیتاسِت MRPC را به روش زیر دانلود کنیم: +
```py from datasets import load_dataset raw_datasets = load_dataset("glue", "mrpc") raw_datasets ``` +
+
```python out DatasetDict({ train: Dataset({ @@ -116,6 +123,7 @@ DatasetDict({ }) }) ``` +
همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). @@ -123,30 +131,38 @@ DatasetDict({ ما می‌توانیم به هر جفت از جملات در شئ `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 .'} ``` +
می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`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)} ``` +
در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` می‌باشد. @@ -164,6 +180,7 @@ raw_train_dataset.features به منظور پیش‌پردازش دِیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنِایزر بدهیم، در نتیجه می‌توانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِنایز کنیم: +
```py from transformers import AutoTokenizer @@ -172,14 +189,18 @@ 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], @@ -187,6 +208,7 @@ inputs '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` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. @@ -198,24 +220,30 @@ inputs اگر شناسه‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: +
```py tokenizer.convert_ids_to_tokens(inputs["input_ids"]) ``` +
خواهیم داشت: we will get: +
```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` می‌باشد. @@ -229,6 +257,7 @@ we will get: اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کلِ دِیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دِیتاسِت `training` اینگونه می‌باشد: +
```py tokenized_dataset = tokenizer( raw_datasets["train"]["sentence1"], @@ -237,14 +266,18 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` +
+ این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کلِ دِیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دِیتاسِت‌های موجود در پایگاه دِیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). به منظور نگهداشتن داده به صورت یک دِیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#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()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. @@ -252,12 +285,16 @@ def tokenize_function(example): در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دِیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دِیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: +
```py tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` +
+ کتابخانه دِیتاسِت هاگینگ‌فِیس این پیش‌پردازش را با افزودن -فیلدهای- جدید به دِیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، اعمال می‌کند: +
```python out DatasetDict({ train: Dataset({ @@ -274,6 +311,7 @@ DatasetDict({ }) }) ``` +
شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکِنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکِنایز کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. @@ -285,8 +323,6 @@ DatasetDict({ ### هم‌طول‌سازی پویا -### Dynamic padding - {#if fw === 'pt'} @@ -302,55 +338,73 @@ DatasetDict({ برای انجام این کار در عمل، ما باید یک تابع `collate` تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دِیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `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])} ``` +
به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل‌مان می‌تواند با آنها کار کند، آماده هستیم برای کوک‌ کردن مدل: @@ -366,6 +420,7 @@ batch = data_collator(samples) توجه داشته باشید که ما دِیتاسِت‌مان و یک `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"], @@ -383,7 +438,10 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( batch_size=8, ) ``` +
این هم از این! حالا می‌توانیم این دِیتاسِت‌ها را به درس بعدی ببریم، جایی که تعلیم پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. {/if} + +
\ No newline at end of file From cf3fcc2b7ee9c0cb6dd09a6722dbfd8413d1b3f8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:27:24 +0200 Subject: [PATCH 124/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index f68698102..f0e93879e 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -27,7 +27,7 @@ در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از پایتورچ شرح می‌دهیم: -
+ ```python import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -50,7 +50,7 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` -
+<\span> {:else} From 67bf22ad6c4007914b9b12e06e502f185c821cc2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:28:03 +0200 Subject: [PATCH 125/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index f0e93879e..6bbdc795a 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -27,7 +27,7 @@ در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از پایتورچ شرح می‌دهیم: - + ```python import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -50,7 +50,7 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` -<\span> + {:else} From 52a06715f01a771a810ba548adaf24640e8d2db2 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:31:48 +0200 Subject: [PATCH 126/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 6bbdc795a..bca43a80b 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -1,6 +1,6 @@ -
+
# پردازش داده {#if fw === 'pt'} @@ -27,7 +27,7 @@ در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از پایتورچ شرح می‌دهیم: - +
```python import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -50,7 +50,7 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` - +
{:else} From 59313b6f8bda471206c96e9e38660a29dd995d72 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:35:25 +0200 Subject: [PATCH 127/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 88 ++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 52 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index bca43a80b..af3e07f89 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -27,7 +27,7 @@ در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از پایتورچ شرح می‌دهیم: -
+ ```python import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -50,13 +50,12 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` -
{:else} در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از تِنسورفلو شرح می‌دهیم: -
+ ```python import tensorflow as tf import numpy as np @@ -77,7 +76,6 @@ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy") labels = tf.convert_to_tensor([1, 1]) model.train_on_batch(batch, labels) ``` -
{/if} @@ -97,16 +95,14 @@ model.train_on_batch(batch, labels) کتابخانه دِیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره‌سازی یک دِیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دِیتاسِت MRPC را به روش زیر دانلود کنیم: -
+ ```py from datasets import load_dataset raw_datasets = load_dataset("glue", "mrpc") raw_datasets ``` -
-
```python out DatasetDict({ train: Dataset({ @@ -123,7 +119,6 @@ DatasetDict({ }) }) ``` -
همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). @@ -131,38 +126,34 @@ DatasetDict({ ما می‌توانیم به هر جفت از جملات در شئ `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 .'} ``` -
+ می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`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)} ``` -
+ در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` می‌باشد. @@ -180,7 +171,7 @@ raw_train_dataset.features به منظور پیش‌پردازش دِیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنِایزر بدهیم، در نتیجه می‌توانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِنایز کنیم: -
+ ```py from transformers import AutoTokenizer @@ -189,18 +180,15 @@ 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], @@ -208,7 +196,7 @@ inputs '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` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. @@ -220,30 +208,29 @@ inputs اگر شناسه‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: -
+ ```py tokenizer.convert_ids_to_tokens(inputs["input_ids"]) ``` -
+ خواهیم داشت: we will get: -
+ ```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` می‌باشد. @@ -257,7 +244,7 @@ we will get: اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کلِ دِیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دِیتاسِت `training` اینگونه می‌باشد: -
+ ```py tokenized_dataset = tokenizer( raw_datasets["train"]["sentence1"], @@ -266,18 +253,18 @@ tokenized_dataset = tokenizer( truncation=True, ) ``` -
+ این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کلِ دِیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دِیتاسِت‌های موجود در پایگاه دِیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). به منظور نگهداشتن داده به صورت یک دِیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#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()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. @@ -285,16 +272,16 @@ def tokenize_function(example): در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دِیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دِیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: -
+ ```py tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -
+ کتابخانه دِیتاسِت هاگینگ‌فِیس این پیش‌پردازش را با افزودن -فیلدهای- جدید به دِیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، اعمال می‌کند: -
+ ```python out DatasetDict({ train: Dataset({ @@ -311,7 +298,6 @@ DatasetDict({ }) }) ``` -
شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکِنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکِنایز کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. @@ -339,72 +325,70 @@ DatasetDict({ {#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])} ``` -
+ به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل‌مان می‌تواند با آنها کار کند، آماده هستیم برای کوک‌ کردن مدل: @@ -420,7 +404,7 @@ batch = data_collator(samples) توجه داشته باشید که ما دِیتاسِت‌مان و یک `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"], @@ -438,7 +422,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( batch_size=8, ) ``` -
+ این هم از این! حالا می‌توانیم این دِیتاسِت‌ها را به درس بعدی ببریم، جایی که تعلیم پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. From 2a3502c398ab1f2b84f2f6f91627e84f50be62f8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:37:48 +0200 Subject: [PATCH 128/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index af3e07f89..bfacbb3f9 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -27,7 +27,7 @@ در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از پایتورچ شرح می‌دهیم: - +
```python import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -50,6 +50,7 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` +<\div> {:else} From 39696feab64cef2a3ae5e80c23e7bdbee31e137e Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:39:02 +0200 Subject: [PATCH 129/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index bfacbb3f9..23d71cb34 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -27,7 +27,24 @@ در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از پایتورچ شرح می‌دهیم: +
+ +```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 import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -50,7 +67,7 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` -<\div> + {:else} From 62dedb1bf74f52650263ca63a5a995ef54ded25b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:39:39 +0200 Subject: [PATCH 130/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 23d71cb34..0fc1ae1fa 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -30,21 +30,6 @@
-```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 import torch from transformers import AdamW, AutoTokenizer, AutoModelForSequenceClassification @@ -68,6 +53,7 @@ loss.backward() optimizer.step() ``` +<\div> {:else} From f588f85c9843c2ecc10d213f2b9266a3ba12c9e8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:40:51 +0200 Subject: [PATCH 131/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 0fc1ae1fa..3b80ceb7e 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -53,12 +53,13 @@ loss.backward() optimizer.step() ``` -<\div> +
{:else} در این بخش در ادامه مثال [فصل قبل](/course/chapter2)، نحوه تعلیم مدل‌های دسته‌بندی کننده رشته‌ها را در یک بَتچ با استفاده از تِنسورفلو شرح می‌دهیم: +
```python import tensorflow as tf @@ -81,6 +82,8 @@ labels = tf.convert_to_tensor([1, 1]) model.train_on_batch(batch, labels) ``` +
+ {/if} البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دِیتاسِت بزرگتری خواهید داشت. From de26443cfb5c2f6200706294a29c962c191be720 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 00:45:54 +0200 Subject: [PATCH 132/502] lrt and rtl divisions added --- chapters/fa/chapter3/2.mdx | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 3b80ceb7e..2d97fbcdf 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -102,6 +102,7 @@ model.train_on_batch(batch, labels) کتابخانه دِیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره‌سازی یک دِیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دِیتاسِت MRPC را به روش زیر دانلود کنیم: +
```py from datasets import load_dataset @@ -110,6 +111,10 @@ raw_datasets = load_dataset("glue", "mrpc") raw_datasets ``` +
+ +
+ ```python out DatasetDict({ train: Dataset({ @@ -127,18 +132,25 @@ DatasetDict({ }) ``` +
+ همانطور که می بینید یک شیء `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, @@ -146,14 +158,20 @@ raw_train_dataset[0] 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} ``` +
می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت. +
```py raw_train_dataset.features ``` +
+ +
+ ```python out {'sentence1': Value(dtype='string', id=None), 'sentence2': Value(dtype='string', id=None), @@ -161,6 +179,7 @@ raw_train_dataset.features 'idx': Value(dtype='int32', id=None)} ``` +
در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` می‌باشد. @@ -178,6 +197,7 @@ raw_train_dataset.features به منظور پیش‌پردازش دِیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنِایزر بدهیم، در نتیجه می‌توانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِنایز کنیم: +
```py from transformers import AutoTokenizer @@ -188,14 +208,21 @@ 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], @@ -204,6 +231,7 @@ inputs } ``` +
در [فصل ۲](/course/chapter2) در مورد کلیدهای `input_ids` و `attention_mask` بحث کردیم، اما از گفتگو در مورد `token_type_ids` اجتناب کردیم. در این مثال این همان چیزی است که به مدل می‌گوید کدام بخش از ورودی جمله اول و کدام بخش جمله دوم است. @@ -215,29 +243,37 @@ inputs اگر شناسه‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: +
```py tokenizer.convert_ids_to_tokens(inputs["input_ids"]) ``` +
خواهیم داشت: we will get: +
+ ```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` می‌باشد. @@ -251,6 +287,7 @@ we will get: اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کلِ دِیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دِیتاسِت `training` اینگونه می‌باشد: +
```py tokenized_dataset = tokenizer( @@ -261,17 +298,20 @@ tokenized_dataset = tokenizer( ) ``` +
این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کلِ دِیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دِیتاسِت‌های موجود در پایگاه دِیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). به منظور نگهداشتن داده به صورت یک دِیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#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()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. @@ -279,15 +319,18 @@ def tokenize_function(example): در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دِیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دِیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: +
```py tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` +
کتابخانه دِیتاسِت هاگینگ‌فِیس این پیش‌پردازش را با افزودن -فیلدهای- جدید به دِیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، اعمال می‌کند: +
```python out DatasetDict({ @@ -306,6 +349,8 @@ DatasetDict({ }) ``` +
+ شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکِنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکِنایز کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. @@ -332,6 +377,7 @@ DatasetDict({ {#if fw === 'pt'} +
```py from transformers import DataCollatorWithPadding @@ -339,9 +385,11 @@ from transformers import DataCollatorWithPadding data_collator = DataCollatorWithPadding(tokenizer=tokenizer) ``` +
{:else} +
```py from transformers import DataCollatorWithPadding @@ -349,11 +397,13 @@ from transformers import DataCollatorWithPadding data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf") ``` +
{/if} اجازه دهید چند نمونه از مجموعه `training`مان را که می‌خواهیم باهم بَتچ کنیم برداریم تا این ابزار جدید را امتحان کنیم. در اینجا ستون‌های `idx`، `sentence1` و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: +
```py samples = tokenized_datasets["train"][:8] @@ -361,22 +411,30 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se [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]), @@ -385,9 +443,11 @@ batch = data_collator(samples) 'labels': TensorShape([8])} ``` +
{:else} +
```python out {'attention_mask': torch.Size([8, 67]), @@ -396,6 +456,7 @@ batch = data_collator(samples) 'labels': torch.Size([8])} ``` +
به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل‌مان می‌تواند با آنها کار کند، آماده هستیم برای کوک‌ کردن مدل: @@ -411,6 +472,7 @@ batch = data_collator(samples) توجه داشته باشید که ما دِیتاسِت‌مان و یک `collator` داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه می‌کند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور دِیتاسِت‌تان می‌پیچد، با یک تابع `collation` دلخواه. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس می‌تواند برای `model.fit()` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دِیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دِیتاسِت‌مان مشاهده کنیم! +
```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( @@ -430,6 +492,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` +
این هم از این! حالا می‌توانیم این دِیتاسِت‌ها را به درس بعدی ببریم، جایی که تعلیم پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. From 5753b150e81f824edf863d53cbc8baf21cc05ad7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 6 May 2022 13:20:34 +0200 Subject: [PATCH 133/502] remove unfinished translation from merge --- chapters/fa/chapter3/3_tf.mdx | 219 ---------------------------------- 1 file changed, 219 deletions(-) delete mode 100644 chapters/fa/chapter3/3_tf.mdx diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx deleted file mode 100644 index 9f0da034b..000000000 --- a/chapters/fa/chapter3/3_tf.mdx +++ /dev/null @@ -1,219 +0,0 @@ -
- - -# باز‌تنظیم یک مدل با استفاده از کِراس - -# Fine-tuning a model with Keras - - - -وقتی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر تنظیمات GPU ندارید، می‌توانید به GPUها یا TPUها مجانی روی [Google Colab](https://colab.research.google.com/) دسترسی داشته باشید. - -Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). - -نمونه کدِ‌های زیر فرض می‌کنند شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه جهت یادآوری آنچه نیاز دارید: - -The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: - -```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, -) -``` - -### تعلیم - -مدل‌های تِنسورفلو که از ترَنسفورمِرهای هاگینگ‌فِیس وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. - -TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. - - - -آن به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار خیلی کمی لازم است تا تعلیم را روی آن شروع کنیم. - -That means that once we have our data, very little work is required to begin training on it. - - - -مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب استفاده خواهیم کرد: - -As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: - -```py -from transformers import TFAutoModelForSequenceClassification - -model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) -``` - -شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از نمونه‌سازیِ این مدل پیش‌تعلیم شما یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی جفت جمله‌ها پیش‌تعلیم نشده، بنابراین لایه-سر مدل پیش‌تعلیم حذف شده و یک لایه-سر مناسب جهت دسته بندی رشته‌‌ای به جای آن اضافه شده. هشدارها نشان می‌دهند که برخی از وزنها استفاده نشده‌اند (آنهایی که مربوط به لایه-سر جدید هستند) و برخی دیگر به صورت تصادفی مقدار‌دهی شده‌ند. (آنهایی که مربوط به لایه-سر پیش‌تعلیم حذف شده هستند). در نتیجه این شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان چیزی است که می‌خواهیم اکنون انجام دهیم. - -You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. - -برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای تعلیم را گزارش دهد، بعلاوه‌ی خطای تایید در انتهای هر epoch. - -To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. - - - -توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های Keras ندارند - آنها به صورت خودکار یک تابع خطای مناسب استفاده می‌کنند که آنرا به صورت داخلی محاسبه می‌کنند. اگر آرگومانی برای تابع خطا در زمان `compile()` تعیین نکنید آنها از این تابع خطا به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع خطای داخلی شما نیاز خواهید داشت که برچسب‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب مجزا، که روش معمول استفاده از برچسب‌ها در مدل‌های Keras می‌باشد. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع خطای درست می‌تواند تا اندازه‌ای گول‌زننده باشد. به هر حال، برای دسته‌بندی رشته‌‌ای، یک تابع خطای استانداد Keras به خوبی کار می‌کند، بنابراین آن چیزی است که ما در اینجا استفاده خواهیم کرد. - -Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. - - - -```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, -) -``` - - - -Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. - - - -### Improving training performance - - - -If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause -is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes -that optimizer with default values for all parameters, including learning rate. From long experience, though, we know -that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written -as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. - -In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate -over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* -the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is -`PolynomialDecay` — despite the name, with default settings it simply linearly decays the learning rate from the initial -value to the final value over the course of training, which is exactly what we want. In order to use a scheduler correctly, -though, we need to tell it how long training is going to be. We compute that as `num_train_steps` below. - -```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) -``` - - - -The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. - - - -Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: - -```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"]) -``` - -Now, we fit again: - -```py -model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -``` - - - -💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) - - - -### Model predictions - - - - -Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. - -```py -preds = model.predict(tf_validation_dataset)["logits"] -``` - -We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: - -```py -class_preds = np.argmax(preds, axis=1) -print(preds.shape, class_preds.shape) -``` - -```python out -(408, 2) (408,) -``` - -Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: - -```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} -``` - -The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. - -This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. - -
\ No newline at end of file From 42b81a4fec56db0d1579485b1b67325c3267b0c0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 8 May 2022 22:26:43 +0200 Subject: [PATCH 134/502] pulled G from upstream. --- chapters/fa/glossary/1.mdx | 63 +++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index d2a216617..fe42e4885 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -54,7 +54,6 @@ | Windows | ویندوز | | macOS | سیستم‌عامل مک | | Distribution | توزیع | -| Distributed | توزیع شده | | Linux | لینوکس | | Workload | محاسبه، محاسبات | | Package Manager | پکیج‌منیجر | @@ -74,6 +73,68 @@ | 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, not as in cypher | کد شده؟، کد گذاری؟ | +| Cache | انبار کردن | معادل‌هایی که استفاده نمی‌کنیم: From db01f41ee41f14b45cf6bcb8677f3b67e7ef96f0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 9 May 2022 08:19:05 +0200 Subject: [PATCH 135/502] some comments applied --- chapters/fa/_toctree.yml | 4 +-- chapters/fa/chapter3/1.mdx | 7 +++--- chapters/fa/chapter3/2.mdx | 50 ++++++++++++++++++++------------------ 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index 454df675c..f785fe42c 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -24,14 +24,12 @@ - local: chapter4/2 title: بکارگیری مدل‌های از پیش تعلیم دیده -- title: 3. بازتنظیمِ یک مدل از پیش‌تعلیم دیده # Translate this! +- title: 3. کوک کردن یک مدل از پیش تعلیم دیده # Translate this! sections: - local: chapter3/1 title: مقدمه # Translate this! - local: chapter3/2 title: پردازش داده # Translate this! - - local: chapter3/3 - title: باز‌تنظیم یک مدل با استفاده از Trainer-API یا کِراس # Translate this! local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - title: واژه‌نامه diff --git a/chapters/fa/chapter3/1.mdx b/chapters/fa/chapter3/1.mdx index 6b3879845..b3f520423 100644 --- a/chapters/fa/chapter3/1.mdx +++ b/chapters/fa/chapter3/1.mdx @@ -1,20 +1,21 @@ -
+
+ # مقدمه در [فصل ۲](/course/chapter2) نحوه استفاده از توکِنایزرها و مدل‌های از پیش تعلیم دیده را جهت انجام پیش‌بینی‌های جدید بررسی کردیم. اما چگونه می‌توانید یک مدل از پیش‌ تعلیم دیده را خودتان کوک‌ کنید؟ {#if fw === 'pt'} -* چگونه دِیتاسِت‌های بزرگ را از هاب تهیه کنید +* چگونه دیتاسِت‌های بزرگ را از هاب تهیه کنید * چگونه از `API` سطح بالای `Trainer` برای کوک کردن مدل استفاده کنید * چگونه یک چرخه‌ تعلیم دلخواه درست کنید * چگونه از کتابخانه `Accelerate` هاگینگ‌فِیس برای اجرای چرخه‌ تعلیم دلخواه در هر نوع تنظیمات توزیع شده‌ای استفاده کنید {:else} -* چگونه دِیتاسِت‌های بزرگ را از هاب تهیه کنید +* چگونه دیتاسِت‌های بزرگ را از هاب تهیه کنید * چگونه از کِراس برای کوک‌ کردن مدل استفاده کنید * چگونه از کِراس برای استخراج پیش‌بینی‌ها استفاده کنید * چگونه از مِتریک دلخواه استفاده کنید diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 2d97fbcdf..d0fec0593 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -86,11 +86,11 @@ model.train_on_batch(batch, labels) {/if} -البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دِیتاسِت بزرگتری خواهید داشت. +البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دیتاسِت بزرگتری خواهید داشت. -در این بخش ما از دِیتاسِت MRPC (Microsoft Research Paraphrase Corpus) که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دِیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دِیتاسِت این است که دِیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. +در این بخش ما از دیتاسِت MRPC[1^] که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. -### بارگذاری دِیتاسِت‌ها از هاب +### بارگذاری دیتاسِت‌ها از هاب {#if fw === 'pt'} @@ -98,9 +98,9 @@ model.train_on_batch(batch, labels) {/if} -هاب تنها شامل مدل‌ها نمی‌باشد؛ بلکه شامل دِیتاسِت‌های متعدد در بسیاری از زبان‌های مختلف می‌باشد. شما می‌توانید دِیتاسِت‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک دِیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی دِیتاسِت MRPC تمرکز کنیم! این یکی از ۱۰ دِیتاسِت [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدل‌های یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. +هاب تنها شامل مدل‌ها نمی‌باشد؛ بلکه شامل دیتاسِت‌های متعدد در بسیاری از زبان‌های مختلف می‌باشد. شما می‌توانید دیتاسِت‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک دیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی دیتاسِت MRPC تمرکز کنیم! این یکی از ۱۰ دیتاسِت [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدل‌های یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. -کتابخانه دِیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره‌سازی یک دِیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دِیتاسِت MRPC را به روش زیر دانلود کنیم: +کتابخانه دیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره‌سازی یک دیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دیتاسِت MRPC را به روش زیر دانلود کنیم:
@@ -136,9 +136,9 @@ DatasetDict({ همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). - این دستور دِیتاسِت را دانلود و به صورت پیش‌فرض در پوشه‌ي *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید پوشه‌ي ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور دیتاسِت را دانلود و به صورت پیش‌فرض در پوشه‌ *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید پوشه‌ ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. -ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس گذاری, مانند یک دیکشنری دسترسی پیدا کنیم: +ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس, مانند یک دیکشنری دسترسی پیدا کنیم:
@@ -160,7 +160,7 @@ raw_train_dataset[0]
-می‌بینم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت. +می‌بینیم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت.
@@ -181,13 +181,13 @@ raw_train_dataset.features
-در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ي *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` می‌باشد. +در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` می‌باشد. ✏️ **امتحان کنید!** عنصر شماره ۱۵ از مجموعه `training` و عنصر شماره ۸۷ از مجموعه `validation` را مشاهده کنید. برچسب‌های آنها چیست؟ -### پیش‌پردازشِ دِیتاسِت‌‌ها +### پیش‌پردازشِ دیتاسِت‌‌ها {#if fw === 'pt'} @@ -195,7 +195,7 @@ raw_train_dataset.features {/if} -به منظور پیش‌پردازش دِیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنِایزر بدهیم، در نتیجه می‌توانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِنایز کنیم: +به منظور پیش‌پردازش دیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنِایزر بدهیم، در نتیجه می‌توانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِنایز کنیم:
@@ -285,7 +285,7 @@ we will get: در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکِنایز شده خود باشید: مادامی که از نقطه تعلیم یکسان برای توکِنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکِنایزر می‌داند چه چیزی برای مدل فراهم کند. -اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کلِ دِیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دِیتاسِت `training` اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کلِ دیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دیتاسِت `training` اینگونه می‌باشد:
@@ -300,9 +300,9 @@ tokenized_dataset = tokenizer(
-این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کلِ دِیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دِیتاسِت‌های موجود در پایگاه دِیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). +این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کلِ دیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دیتاسِت‌های موجود در پایگاه دیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). -به منظور نگهداشتن داده به صورت یک دِیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیش‌تری علاوه‌بر توکِنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دِیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِنایز کند: +به منظور نگهداشتن داده به صورت یک دیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیش‌تری علاوه‌بر توکِنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِنایز کند:
@@ -313,11 +313,11 @@ def tokenize_function(example):
-این تابع یک دیکشنری (مثل اقلام داخل دِیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از جفت جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. +این تابع یک دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از جفت جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. -توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` را زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دِیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. +توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` را زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. -در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دِیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دِیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: +در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد:
@@ -328,7 +328,7 @@ tokenized_datasets
-کتابخانه دِیتاسِت هاگینگ‌فِیس این پیش‌پردازش را با افزودن -فیلدهای- جدید به دِیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، اعمال می‌کند: +کتابخانه دیتاسِت هاگینگ‌فِیس این پیش‌پردازش را با افزودن -فیلدهای- جدید به دیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، اعمال می‌کند:
@@ -354,7 +354,7 @@ DatasetDict({ شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکِنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکِنایز کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. -تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids`، برمی‌گرداند به گونه‌ای که این سه فیلد به همه بخش‌های دِیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دِیتاسِت که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids`، برمی‌گرداند به گونه‌ای که این سه فیلد به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. @@ -373,7 +373,7 @@ DatasetDict({ {/if} -برای انجام این کار در عمل، ما باید یک تابع `collate` تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دِیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهند. این تابع به محض اینکه آنرا تعریف کنیم (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام این کار در عمل، ما باید یک تابع `collate` تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهند. این تابع به محض اینکه آنرا تعریف کنیم (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} @@ -421,7 +421,7 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se
-تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دِیتاسِت باید به اندازه بزرگ‌ترین طول یا بزرگ‌ترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: +تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دیتاسِت باید به اندازه بزرگ‌ترین طول یا بزرگ‌ترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند:
@@ -464,13 +464,13 @@ batch = data_collator(samples) -✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی دِیتاسِت GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. +✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی دیتاسِت GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. {#if fw === 'tf'} -توجه داشته باشید که ما دِیتاسِت‌مان و یک `collator` داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه می‌کند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور دِیتاسِت‌تان می‌پیچد، با یک تابع `collation` دلخواه. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس می‌تواند برای `model.fit()` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دِیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دِیتاسِت‌مان مشاهده کنیم! +توجه داشته باشید که ما دیتاسِت‌مان و یک `collator` داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه می‌کند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور دیتاسِت‌تان می‌پیچد، با یک تابع `collation` دلخواه. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس می‌تواند برای `model.fit()` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دیتاسِت‌مان مشاهده کنیم!
@@ -494,8 +494,10 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset(
-این هم از این! حالا می‌توانیم این دِیتاسِت‌ها را به درس بعدی ببریم، جایی که تعلیم پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. +این هم از این! حالا می‌توانیم این دیتاسِت‌ها را به درس بعدی ببریم، جایی که تعلیم پس از همه سختی‌های پیش‌پردازش به طرز خوشایندی سرراست خواهد بود. {/if} +[^1]: Microsoft Research Paraphrase Corpus +
\ No newline at end of file From 888da94645609a100afc212947367022ffa69c22 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 9 May 2022 08:23:39 +0200 Subject: [PATCH 136/502] some comments applied --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index d0fec0593..3b1102fe1 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -88,7 +88,7 @@ model.train_on_batch(batch, labels) البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دیتاسِت بزرگتری خواهید داشت. -در این بخش ما از دیتاسِت MRPC[1^] که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. +در این بخش ما از دیتاسِت MRPC[^1] که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. ### بارگذاری دیتاسِت‌ها از هاب From f405cff611cb0b02a5ed73c0c553903e26664d63 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 9 May 2022 08:24:42 +0200 Subject: [PATCH 137/502] some comments applied --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 3b1102fe1..dd49018e0 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -88,7 +88,7 @@ model.train_on_batch(batch, labels) البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دیتاسِت بزرگتری خواهید داشت. -در این بخش ما از دیتاسِت MRPC[^1] که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. +در این بخش ما از دیتاسِت [^1]MRPC که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. ### بارگذاری دیتاسِت‌ها از هاب From 7c0eee286262358c38540b4f51e7e270ed776a13 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 9 May 2022 08:25:38 +0200 Subject: [PATCH 138/502] some comments applied --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index dd49018e0..d98c3646c 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -88,7 +88,7 @@ model.train_on_batch(batch, labels) البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دیتاسِت بزرگتری خواهید داشت. -در این بخش ما از دیتاسِت [^1]MRPC که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. +در این بخش ما از دیتاسِت MRPC [^1]که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. ### بارگذاری دیتاسِت‌ها از هاب From 5189d1aa03f4f58f93ec40b78e179e2147530a6f Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 9 May 2022 08:26:01 +0200 Subject: [PATCH 139/502] some comments applied --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index d98c3646c..3b1102fe1 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -88,7 +88,7 @@ model.train_on_batch(batch, labels) البته تعلیم با استفاده از دو جمله به نتایج چشم‌گیری منتهی نخواهد شد. برای به دست آوردن نتایج بهتر نیاز به آماده‌سازی دیتاسِت بزرگتری خواهید داشت. -در این بخش ما از دیتاسِت MRPC [^1]که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. +در این بخش ما از دیتاسِت MRPC[^1] که در یک [مقاله](https://www.aclweb.org/anthology/I05-5002.pdf)، نوشته‌ی ویلیام بی دالن و کریس براکت، معرفی شده به عنوان یک مثال استفاده خواهیم کرد. این دیتاسِت شامل ۵۸۰۱ جفت جمله و یک برچسب می‌باشد که برچسب نشان دهنده متناظر بودن جملات می‌باشد (به عنوان مثال اینکه آیا دو جمله معنی یکسانی دارند یا خیر). علت انتخاب این دیتاسِت این است که دیتاسِت کوچکی است و تجربه تعلیم روی آن آسان است. ### بارگذاری دیتاسِت‌ها از هاب From 73c5ddee04e059a89023c61c3a135912a22c469e Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 9 May 2022 12:39:51 +0200 Subject: [PATCH 140/502] multiple comments applied --- chapters/fa/chapter3/2.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 3b1102fe1..69b7e6b3e 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -160,7 +160,7 @@ raw_train_dataset[0]
-می‌بینیم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین مجبور نیستیم هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدارِ عددیِ صحیح به کدام برچسب مربوط می‌شود، می‌توانیم ویژگی‌های ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت. +می‌بینیم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین لازم نیست هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم قابلیت‌های ‌`raw_train_dataset`‌ را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت.
@@ -181,13 +181,13 @@ raw_train_dataset.features
-در پشت صحنه، `برچسب` از نوع `برچسبِ کلاس` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` می‌باشد. +در پشت صحنه، `label` از نوع `ClassLabel` می‌باشد، و نگاشت اعداد صحیح به نام برچسب در پوشه‌ *names* ذخیره شده است. `0` مربوط به `not_equivalent` و `1` مربوط به `equivalent` می‌باشد. ✏️ **امتحان کنید!** عنصر شماره ۱۵ از مجموعه `training` و عنصر شماره ۸۷ از مجموعه `validation` را مشاهده کنید. برچسب‌های آنها چیست؟ -### پیش‌پردازشِ دیتاسِت‌‌ها +### پیش‌پردازش دیتاسِت‌‌ها {#if fw === 'pt'} @@ -275,17 +275,17 @@ we will get:
-همانطور که می‌بینید، بخش‌هایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` هستند اندیسِ نشان دهنده نوع توکِن آنها `0` و بخش‌هایی که مربوط به `sentence2 [SEP]` هستند اندیس نشان دهنده نوع توکِن‌شان `1` می‌باشد. +همانطور که می‌بینید، بخش‌هایی از ورودی که مربوط به `[CLS] sentence1 [SEP]` هستند اندیس نشان دهنده نوع توکِن آنها `0` و بخش‌هایی که مربوط به `sentence2 [SEP]` هستند اندیس نشان دهنده نوع توکِن‌شان `1` می‌باشد. -توجه داشته باشید که اگر نقطه تعلیمِ متفاوتی را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. +توجه داشته باشید که اگر نقطه تعلیم متفاوتی را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. -در اینجا، مدل BERT با آیدی‌هایی که نشان دهنده نوعِ توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبانِ ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ بر عهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. +در اینجا، مدل BERT با آیدی‌هایی که نشان دهنده نوع توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبان ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ بر عهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ جمله‌ اول قرار دارد یا خیر. برای خارج کردن مسئله از حالت بدیهی، در نیمی از حالت‌ها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکِنایز شده خود باشید: مادامی که از نقطه تعلیم یکسان برای توکِنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکِنایزر می‌داند چه چیزی برای مدل فراهم کند. -اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کلِ دیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازشِ دیتاسِت `training` اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کل دیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازش دیتاسِت `training` اینگونه می‌باشد:
@@ -300,7 +300,7 @@ tokenized_dataset = tokenizer(
-این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کلِ دیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دیتاسِت‌های موجود در پایگاه دیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). +این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل دیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دیتاسِت‌های موجود در پایگاه دیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). به منظور نگهداشتن داده به صورت یک دیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیش‌تری علاوه‌بر توکِنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِنایز کند: @@ -421,7 +421,7 @@ samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "se
-تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دیتاسِت باید به اندازه بزرگ‌ترین طول یا بزرگ‌ترین طولِ قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند: +تعجبی ندارد که نمونه‌هایی با طول‌های متغییر، از ۳۲ تا ۶۷ بدست می‌آوریم. هم‌طول‌سازی پویا به این معنی است که نمونه‌های موجود در این بَتچ باید همگی با طول ۶۷، که بزرگترین طول داخل بَتچ می‌باشد، هم‌طول شده باشند. بدون هم‌طول‌سازی پویا، همه نمونه‌ها در کل دیتاسِت باید به اندازه بزرگ‌ترین طول یا بزرگ‌ترین طول قابل پذیرش برای مدل، هم‌طول شوند. اجازه دهید بررسی کنیم آیا `data_collator` ما بَتچ را به درستی هم‌طول می‌کند:
From 840c8e43760b7d187e8783aa5b3ae149267bc787 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 12 May 2022 23:33:49 +0200 Subject: [PATCH 141/502] multiple review comments applied --- chapters/fa/chapter3/2.mdx | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 69b7e6b3e..fd134ebe6 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -195,7 +195,7 @@ raw_train_dataset.features {/if} -به منظور پیش‌پردازش دیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکنِایزر بدهیم، در نتیجه می‌توانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِنایز کنیم: +به منظور پیش‌پردازش دیتاسِت‌، لازم است متن را به اعدادی قابل پردازش برای مدل تبدیل کنیم. همانطور که در[فصل قبل](/course/chapter2) مشاهده کردید، این کار با استفاده از یک توکِنایزر انجام می‌شود. ما می‌توانیم یک یا چند جمله را به توکِنایزر بدهیم، در نتیجه می‌توانیم به طور مستقیم تمام جملات اول و دوم هر جفت جمله را به صورت زیر توکِن کنیم:
@@ -210,7 +210,7 @@ tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"])
-با این حال، نمی‌توانیم دو جمله را به مدل ارسال کنیم تا پیش‌بینی کند که متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم، و پیش‌پردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکِنایزر می‌تواند یک جفت رشته را دریافت کند و آنرا به گونه‌ای که مدل BERT ما انتظار دارد آماده‌سازی کند: +با این حال، نمی‌توانیم دو جمله را به مدل ارسال کنیم تا پیش‌بینی کند که متناظر هستند یا خیر. ما نیاز داریم با دو رشته به صورت یک جفت برخورد کنیم و پیش‌پردازش مناسب را به آن اعمال کنیم. خوشبختانه، توکِنایزر می‌تواند یک جفت رشته را دریافت کند و آنرا به گونه‌ای که مدل BERT ما انتظار دارد آماده‌سازی کند:
@@ -237,11 +237,11 @@ inputs -✏️ **امتحان کنید!** عنصر شماره ۱۵ از مجموعه `training` را بردارید و دو جمله را به صورت جداگانه و جفت توکِنایز کنید. تفاوت دو نتیجه چیست؟ +✏️ **امتحان کنید!** عنصر شماره ۱۵ از مجموعه `training` را بردارید و دو جمله را به صورت جداگانه و جفت توکِن کنید. تفاوت دو نتیجه چیست؟ -اگر شناسه‌های داخل `input_ids` را به کلمات رمزگشایی کنیم: +اگر شناسه‌های داخل `input_ids` را به کلمات کدگشایی کنیم:
@@ -253,9 +253,6 @@ tokenizer.convert_ids_to_tokens(inputs["input_ids"]) خواهیم داشت: -we will get: - -
```python out @@ -279,13 +276,13 @@ we will get: توجه داشته باشید که اگر نقطه تعلیم متفاوتی را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. -در اینجا، مدل BERT با آیدی‌هایی که نشان دهنده نوع توکن هستند پیش‌تعلیم شده، و علاوه بر هدف مدل سازی زبان ماسکی که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ی دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ بر عهده دارد. هدف از این وظیفه مدل کردن رابطه بین جفت جمله‌ها می‌باشد. +در اینجا، مدل BERT با شناسه‌هایی که نشان دهنده نوع توکِن هستند از پیش‌ تعلیم دیده و علاوه بر هدف تکمیل جاهای خالی متن که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ بر عهده دارد. هدف از این وظیفه مدل کردن رابطه بین دو جمله می‌باشد. - در روش پیش‌بینی جمله بعدی، جفت جملاتی (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ جمله‌ اول قرار دارد یا خیر. برای خارج کردن مسئله از حالت بدیهی، در نیمی از حالت‌ها دوجمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. + در پیش‌بینی جمله بعدی، لیستی از جمله‌های جفت شده (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ جمله‌ اول قرار دارد یا خیر. برای سخت‌تر کردن مسئله، در نیمی از حالت‌ها دو جمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. -در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکِنایز شده خود باشید: مادامی که از نقطه تعلیم یکسان برای توکِنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکِنایزر می‌داند چه چیزی برای مدل فراهم کند. +در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکِن شده خود باشید: مادامی که از نقطه تعلیم یکسان برای توکِنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکِنایزر می‌داند چه چیزی برای مدل فراهم کند. -اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با یک جفت جمله برخورد کند، می‌توانیم آنرا برای توکِنایز کردن کل دیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازش دیتاسِت `training` اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با دو جمله برخورد کند، می‌توانیم آن را برای توکِن کردن کل دیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازش دیتاسِت `training` اینگونه می‌باشد:
@@ -300,9 +297,9 @@ tokenized_dataset = tokenizer(
-این روش به خوبی کار می‌کند، اما مشکل‌اش این است که یک دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids`, و مقادیر آنها که مجموعه‌ای از مجموعه‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل دیتاسِت در حین توکِنایز کردن داشته باشید (در حالی که دیتاسِت‌های موجود در پایگاه دیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌می‌دارید). +این روش به خوبی کار می‌کند، اما مشکل‌اش این است که دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids` و مقادیر آنها که لیست‌هایی از لیست‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل دیتاسِت در حین توکِن کردن داشته باشید (در حالی که دیتاسِت‌های موجود در پایگاه دیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌ می‌دارید). -به منظور نگهداشتن داده به صورت یک دیتاسِت، از تابع [`()Dataset.map`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیش‌تری علاوه‌بر توکِنایز کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِنایز کند: +به منظور نگه داشتن داده به صورت یک دیتاسِت، از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکِن کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِن کند:
@@ -313,9 +310,9 @@ def tokenize_function(example):
-این تابع یک دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از جفت جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان مجموعه‌ای از جملات) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [هاگینگ‌فِیس Tokenizers](https://github.com/huggingface/tokenizers) که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. +این تابع دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از دو جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان لیستی از جمله‌ها) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [Tokenizers](https://github.com/huggingface/tokenizers) از هاگینگ‌فِیس که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. -توجه داشته باشید که ما مبحث `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام `padding` روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که `padding` را زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. +توجه داشته باشید که ما آرگومان `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام padding روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که padding را زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: @@ -351,7 +348,7 @@ DatasetDict({
-شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکِنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکِنایز کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. +شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکِنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکِن کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids`، برمی‌گرداند به گونه‌ای که این سه فیلد به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. From a1e7c0804d78a176314004984eaf9108f3afcade Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 17 May 2022 08:58:49 +0200 Subject: [PATCH 142/502] review changes applied --- chapters/fa/chapter3/2.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index fd134ebe6..564fff30d 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -312,7 +312,7 @@ def tokenize_function(example): این تابع دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از دو جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان لیستی از جمله‌ها) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [Tokenizers](https://github.com/huggingface/tokenizers) از هاگینگ‌فِیس که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. -توجه داشته باشید که ما آرگومان `padding` را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که انجام padding روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که padding را زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم که `padding` را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. +توجه داشته باشید که ما آرگومان هم‌طول‌سازی را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که هم‌طول‌سازی روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که آن را زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم هم‌طول‌سازی را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: @@ -362,7 +362,7 @@ DatasetDict({ {#if fw === 'pt'} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش‌ فرض تابعی است که نمونه‌های شما را به ماتریس پایتورچ تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان‌پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPUها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش‌ فرض تابعی است که نمونه‌های شما را به ماتریس پایتورچ تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان‌پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPUها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. {:else} @@ -370,7 +370,7 @@ DatasetDict({ {/if} -برای انجام این کار در عمل، ما باید یک تابع `collate` تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهند. این تابع به محض اینکه آنرا تعریف کنیم (یعنی تعیین کنیم چه توکنی برای هم‌طول‌سازی استفاده کند و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام این کار در عمل، ما باید یک تابع `collate` تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} @@ -467,7 +467,7 @@ batch = data_collator(samples) {#if fw === 'tf'} -توجه داشته باشید که ما دیتاسِت‌مان و یک `collator` داده در اختیار داریم، حال نیاز داریم که آنها را کنار هم قرار دهیم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، یک روش ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه می‌کند: `to_tf_dataset()`. این روش یک `tf.data.Dataset` را دور دیتاسِت‌تان می‌پیچد، با یک تابع `collation` دلخواه. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس می‌تواند برای `model.fit()` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دیتاسِت‌مان مشاهده کنیم! +اکنون که دیتاسِت‌مان و یک `collator` داده در اختیار داریم، حال نیاز داریم که آنها را باهم بکار ببریم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، تابعی ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه می‌کند: `to_tf_dataset()`. این تابع یک `tf.data.Dataset` شامل پارامتری اختیاری برای تابع `collation` را دور دیتاسِت‌تان می‌پیچد. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس می‌تواند برای `model.fit()` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دیتاسِت‌مان مشاهده کنیم!
From e9d680915fb35607f8e2fa951354badfcfe595cc Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 18 May 2022 08:21:35 +0200 Subject: [PATCH 143/502] review coments applied --- chapters/fa/chapter3/2.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 564fff30d..b0746be86 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -312,9 +312,9 @@ def tokenize_function(example): این تابع دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از دو جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان لیستی از جمله‌ها) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [Tokenizers](https://github.com/huggingface/tokenizers) از هاگینگ‌فِیس که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. -توجه داشته باشید که ما آرگومان هم‌طول‌سازی را در حال حاضر کنار گذاشته‌ایم. این به این خاطر است که هم‌طول‌سازی روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که آن را زمانی که در حال ساختن بَتچ هستیم روی نمونه‌ها انجام دهیم، چرا که آنوقت فقط نیاز داریم هم‌طول‌سازی را روی همان بَتچ انجام دهیم، و نه بیشترین طول در سرتاسر دیتاسِت. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. +توجه داشته باشید که ما آرگومان هم‌طول‌سازی را در تابع توکِن کننده‌مان نادیده گرفته‌ایم. این به این خاطر است که هم‌طول‌سازی روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که نمونه‌ها را زمانی که در حال ساختن بَتچ هستیم هم‌طول کنیم، در این صورت فقط نیاز داریم نمونه‌ها را به اندازه بزرگترین طول همان بَتچ و نه بیشترین طول در سرتاسر دیتاسِت‌ هم‌طول کنیم. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. -در اینجا نشان می‌دهیم چگونه تابع توکِنایزیشن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: +در اینجا نشان می‌دهیم چگونه تابع تولید توکِن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد:
@@ -353,7 +353,7 @@ DatasetDict({ تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids`، برمی‌گرداند به گونه‌ای که این سه فیلد به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. -آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را باهم بَتچ می‌کنیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. +آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را با هم در یک بَتچ قرار می‌دهیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. ### هم‌طول‌سازی پویا @@ -366,11 +366,11 @@ DatasetDict({ {:else} -تابعی که مسئول کنارهم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. `collator` پیش‌فرض تابعی است که فقط نمونه‌های شما را به `tf.Tensor` تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌ها ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPUها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. `collator` پیش‌فرض تابعی است که فقط نمونه‌های شما را به `tf.Tensor` تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما فرایند هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش، فرایند تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار می‌تواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح می‌دهد، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. {/if} -برای انجام این کار در عمل، ما باید یک تابع `collate` تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم بَتچ کنیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار میدهد. این تابع به محض اینکه آنرا تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و اینکه مدل انتظار هم‌طول‌سازی از سمت چپ ورودی‌ها را داشته باشد یا از سمت راست آنها) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام این کار در عمل، ما باید یک تابع مرتب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار می‌دهد. این تابع به محض این که آن را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} @@ -398,7 +398,7 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf" {/if} -اجازه دهید چند نمونه از مجموعه `training`مان را که می‌خواهیم باهم بَتچ کنیم برداریم تا این ابزار جدید را امتحان کنیم. در اینجا ستون‌های `idx`، `sentence1` و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ: +اجازه دهید چند نمونه از مجموعه `training` را که می‌خواهیم باهم در یک بَتچ قرار دهیم برداریم تا این ابزار جدید را امتحان کنیم. در اینجا ستون‌های `idx`، `sentence1` و `sentence2` را حذف می‌کنیم چرا که احتیاج نخواهند شد و شامل رشته‌های متنی می‌شوند (که ما نمی‌توانیم تنسورهایی از رشته‌های متنی ایجاد کنیم) و سپس نگاهی می‌اندازیم به طول هر ورودی در هر بَتچ:
From 58f52079c6decb876235700b638620a09c827222 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 19 May 2022 09:22:01 +0200 Subject: [PATCH 144/502] review coments applied --- chapters/fa/chapter3/2.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index b0746be86..c9601b3e1 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -276,13 +276,13 @@ tokenizer.convert_ids_to_tokens(inputs["input_ids"]) توجه داشته باشید که اگر نقطه تعلیم متفاوتی را انتخاب کنید، در ورودی‌ها لزوما `token_type_ids` نخواهید داشت (به عنوان مثال، اگر از یک DistilBERT استفاده کنید آنها بازگردانده نخواهند شد). آنها فقط زمانی بازگردانده می‌شوند که مدل می‌داند با آنها چکار کند، به این خاطر که آنها را در زمان پیش‌تعلیم دیده است. -در اینجا، مدل BERT با شناسه‌هایی که نشان دهنده نوع توکِن هستند از پیش‌ تعلیم دیده و علاوه بر هدف تکمیل جاهای خالی متن که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ دیگری تحت عنوان _پیش‌بینی جمله‌ی بعدی_ بر عهده دارد. هدف از این وظیفه مدل کردن رابطه بین دو جمله می‌باشد. +در اینجا، مدل BERT با شناسه‌هایی که نشان دهنده نوع توکِن هستند از پیش‌ تعلیم دیده و علاوه بر هدف تکمیل جاهای خالی متن که در [فصل ۱](/course/chapter1) در مورد آن صحبت کردیم وظیفه‌ دیگری تحت عنوان _پیش‌بینی جمله‌ بعدی_ بر عهده دارد. هدف از این وظیفه مدل کردن رابطه بین جملات جفتی می‌باشد. در پیش‌بینی جمله بعدی، لیستی از جمله‌های جفت شده (با کلماتی که به طور تصادفی پنهان شده‌اند) به مدل داده می‌شوند و از مدل خواسته می‌شود پیش‌بینی کند که آیا جمله دوم در ادامه‌ جمله‌ اول قرار دارد یا خیر. برای سخت‌تر کردن مسئله، در نیمی از حالت‌ها دو جمله در متن اصلی به دنبال هم آمده‌، و در نیمی دیگر از دو متن متفاوت می‌آیند. در مجموع، نیازی نیست نگران وجود یا عدم وجود `token_type_ids` در ورودی‌های توکِن شده خود باشید: مادامی که از نقطه تعلیم یکسان برای توکِنایزر و مدل استفاده کنید، همه چیز خوب پیش خواهد رفت چرا که توکِنایزر می‌داند چه چیزی برای مدل فراهم کند. -اکنون که مشاهده کردیم چگونه توکِنایزر ما می‌تواند با دو جمله برخورد کند، می‌توانیم آن را برای توکِن کردن کل دیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازش دیتاسِت `training` اینگونه می‌باشد: +اکنون که مشاهده کردیم چگونه توکِن کننده ما می‌تواند با دو جمله برخورد کند، می‌توانیم آن را برای توکِن کردن کل دیتاسِت‌مان به کار ببریم: مانند [فصل قبل](/course/chapter2)، ما می‌توانیم توکِنایزر را با لیستی از جفت جمله‌ها، با دادن لیست جملات اول و سپس لیست جملات دوم، تغذیه کنیم. این روش همچنین با گزینه‌های `padding` و `truncation` که در [فصل ۲](/course/chapter2) مشاهده کردیم سازگاری دارد. بنابراین، یک روش برای پیش‌پردازش دیتاسِت `training` اینگونه می‌باشد:
@@ -310,11 +310,11 @@ def tokenize_function(example):
-این تابع دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از دو جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان لیستی از جمله‌ها) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این توکِنایزر با توکِنایزری در کتابخانه [Tokenizers](https://github.com/huggingface/tokenizers) از هاگینگ‌فِیس که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. +این تابع دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از دو جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان لیستی از جمله‌ها) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این `tokenizer` با توکِنایزری در کتابخانه [Tokenizers](https://github.com/huggingface/tokenizers) از هاگینگ‌فِیس که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. توجه داشته باشید که ما آرگومان هم‌طول‌سازی را در تابع توکِن کننده‌مان نادیده گرفته‌ایم. این به این خاطر است که هم‌طول‌سازی روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که نمونه‌ها را زمانی که در حال ساختن بَتچ هستیم هم‌طول کنیم، در این صورت فقط نیاز داریم نمونه‌ها را به اندازه بزرگترین طول همان بَتچ و نه بیشترین طول در سرتاسر دیتاسِت‌ هم‌طول کنیم. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. -در اینجا نشان می‌دهیم چگونه تابع تولید توکِن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابراین تابع روی چندین عنصر از دیتاسِت ما به یکباره عمل می‌کند نه روی هر عنصر به صورت جداگانه. این اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد: +در اینجا نشان می‌دهیم چگونه تابع تولید توکِن را روی کل دیتاسِت به یکباره اعمال می‌کنیم. ما از `batched=True` در فراخوانی تابع `map` استفاده می‌کنیم بنابر این تابع ما به جای اینکه روی هر عنصر به صورت جداگانه عمل کند روی چندین عنصر از دیتاسِت به یکباره عمل می‌کند. این کار اجازه می‌دهد که پیش‌پردازش سریع‌تر انجام گیرد:
From c90ad2a08d25570d9d4bbb52f359c707ad9dbfb0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 19 May 2022 13:40:09 +0200 Subject: [PATCH 145/502] review coments applied --- chapters/fa/chapter3/2.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c9601b3e1..872792503 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -297,7 +297,7 @@ tokenized_dataset = tokenizer(
-این روش به خوبی کار می‌کند، اما مشکل‌اش این است که دیکشنری (از کلیدهای ما شامل، `input_ids`, `attention_mask` و `token_type_ids` و مقادیر آنها که لیست‌هایی از لیست‌ها هستند) برمی‌گرداند. همچنین این روش فقط زمانی کار می‌کند که حافظه موقت کافی جهت ذخیره‌سازی کل دیتاسِت در حین توکِن کردن داشته باشید (در حالی که دیتاسِت‌های موجود در پایگاه دیتاسِت هاگینگ‌فِیس فایل‌هایی از نوع [Apache Arrow](https://arrow.apache.org/) هستند که روی دیسک ذخیره شده‌اند، بنابراین شما فقط نمونه‌هایی را که جهت ذخیره در حافظه درخواست کرده‌اید نگه‌ می‌دارید). +این روش به خوبی کار می‌کند، اما مشکل‌اش این است که دیکشنری (از کلیدهای ما شامل، `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.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکِن کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِن کند: @@ -325,7 +325,7 @@ tokenized_datasets
-کتابخانه دیتاسِت هاگینگ‌فِیس این پیش‌پردازش را با افزودن -فیلدهای- جدید به دیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، اعمال می‌کند: +کتابخانه `Datasets` از هاگینگ‌فِیس این پیش‌پردازش را با افزودن -فیلدهای- جدید به دیتاسِت‌ها، یکی به اِزای هر کلید در -دیکشنری- که توسط تابع پیش‌پردازش بازگردانده می‌شوند، اعمال می‌کند:
@@ -348,7 +348,7 @@ DatasetDict({
-شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه توکِنایزر هاگینگ‌فِیس از پیش از چندین رشته پردازنده برای توکِن کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. +شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه `Tokenizers` هاگینگ‌فِیس از پیش، از چندین رشته پردازنده برای توکِن کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids`، برمی‌گرداند به گونه‌ای که این سه فیلد به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. From 0423a4229a447e88ca219577d19dd9367d82fb5c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 20 May 2022 09:08:39 +0200 Subject: [PATCH 146/502] review changes applied --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 872792503..c82b29e72 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -348,7 +348,7 @@ DatasetDict({
-شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از پردازش موازی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه `Tokenizers` هاگینگ‌فِیس از پیش، از چندین رشته پردازنده برای توکِن کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. +شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از چندپردازشی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه `Tokenizers` هاگینگ‌فِیس از پیش، از چندین رشته پردازشی برای توکِن کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids`، برمی‌گرداند به گونه‌ای که این سه فیلد به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. From fe3df6d824a3b16dc4fdd4199f47ff70c694714b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 20 May 2022 12:56:09 +0200 Subject: [PATCH 147/502] finish applying review comments --- chapters/fa/chapter3/2.mdx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index c82b29e72..6759d50c9 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -348,12 +348,12 @@ DatasetDict({
-شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از چندپردازشی استفاده کنید. ما آن را در اینجا استفاده نکردیم به این خاطر که کتابخانه `Tokenizers` هاگینگ‌فِیس از پیش، از چندین رشته پردازشی برای توکِن کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما در صورتی که از یک توکِنایزر سریع که با این کتابخانه پشتیبانی می‌شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. +شما حتی می‌توانید زمانی که تابع پیش‌پردازش خود را اعمال می‌کنید، با ارسال آرگومان `num_proc` در تابع `map()` از چندپردازشی استفاده کنید. در اینجا ما این کار را انجام ندادیم چرا که کتابخانه `Tokenizers` هاگینگ‌فِیس از پیش، از چندین رشته پردازشی برای توکِن کردن سریع‌تر نمونه‌های ما استفاده می‌کند، اما اگر شما از یک توکِنایزر سریع که با این کتابخانه پشتیبانی شود استفاده نمی‌کنید، این روش می‌تواند پیش‌پردازش شما را سریع‌تر کند. -تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids`، برمی‌گرداند به گونه‌ای که این سه فیلد به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید که اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت که تابع `map()` به آن اعمال شده یک مقدار جدید بازمی‌گردانید همچنین می‌توانستیم فیلدهای موجود را تغییر دهیم. +تابع `tokenize_function` ما یک دیکشنری شامل کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند به گونه‌ای که این کلیدها به صورت سه فیلد جدید به همه بخش‌های دیتاسِت افزوده گردند. توجه داشته باشید اگر تابع پیش‌پردازش ما برای یک کلید موجود در دیتاسِت مقدار جدیدی بازمی‌گرداند ما می‌توانستیم فیلدهای موجود در دیتاسِتی که تابع `map()` به آن اعمال می‌شود را نیز تغییر دهیم. -آخرین چیزی که نیاز داریم انجام دهیم این است که هنگامی که عناصر را با هم در یک بَتچ قرار می‌دهیم، همه نمونه‌ها را به اندازه طول بلندترین عنصر هم‌طول کنیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. +آخرین کاری که باید انجام دهیم این است که هنگامی که عناصر را با هم در یک بَتچ قرار می‌دهیم، طول همه عناصر را به اندازه بلندترین عنصر برسانیم - تکنیکی که ما به آن *هم‌طول‌سازی پویا* می‌گوییم. ### هم‌طول‌سازی پویا @@ -362,11 +362,14 @@ DatasetDict({ {#if fw === 'pt'} -تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. این تابع آرگومانی است که شما می‌توانید هنگام ساختن یک `DataLoader` به داخل آن ارسال کنید، که در حالت پیش‌ فرض تابعی است که نمونه‌های شما را به ماتریس پایتورچ تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان‌پذیر نیست. ما پروسه هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آنرا روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش پروسه تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید می‌تواند مشکل ساز باشد - TPUها اشکال معین را ترجیح می‌دهند، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *تابع مرتب کننده* خوانده می‌شود. شما می‌توانید این تابع را که در حالت پیش‌ فرض نمونه‌های شما را به تِنسور پایتورچ تبدیل کرده و به هم الحاق می‌کند (اگر عناصر شما لیست، تاپِل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد) هنگام ساختن `DataLoader` به داخل آن ارسال کنید. از آنجایی که ورودی‌های ما هم‌طول نخواهند بود استفاده از این تابع برای ما امکان‌پذیر نیست. ناهم‌طولی ورودی‌ها به این خاطر است که ما فرایند هم‌طول‌سازی را عمدا به تعویق انداختیم تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با مقدار زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش، فرایند تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار می‌تواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح می‌دهد، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. + {:else} -تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *collate function* خوانده می‌شود. `collator` پیش‌فرض تابعی است که فقط نمونه‌های شما را به `tf.Tensor` تبدیل کرده و آنها را بهم الحاق می‌کند (اگر عناصر شما لیست، تاپل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما همه به یک اندازه نیستند این کار برای ما امکان پذیر نیست. ما فرایند هم‌طول‌سازی را عمدا به تعویق انداختیم، تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با تعداد زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش، فرایند تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار می‌تواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح می‌دهد، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. +تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *تابع مرتب کننده* خوانده می‌شود. تابع مرتب کننده پیش‌فرض تابعی است که فقط نمونه‌های شما را به `tf.Tensor` تبدیل کرده و آنها را به هم الحاق می‌کند (اگر عناصر شما لیست، تاپِل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما هم‌طول نخواهند بود استفاده از این تابع برای ما امکان پذیر نیست. ناهم‌طولی ورودی‌ها به این خاطر است که ما فرایند هم‌طول‌سازی را عمدا به تعویق انداختیم تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با مقدار زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش، فرایند تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار می‌تواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح می‌دهد، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. + +The function that is responsible for putting together samples inside a batch is called a *collate function*. The default collator is a function that will just convert your samples to tf.Tensor and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. {/if} From b748da27d9dc94215549ca5260d9327cba7776eb Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 20 May 2022 13:21:26 +0200 Subject: [PATCH 148/502] PR failure resolved --- chapters/fa/_toctree.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index 9853f9d85..d45d23d0e 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -32,7 +32,6 @@ title: مقدمه # Translate this! - local: chapter3/2 title: پردازش داده # Translate this! - local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - title: واژه‌نامه sections: From dc51a8cf322330d4a4dbcb9636d2ce7cea121ed3 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sat, 21 May 2022 18:40:37 +0200 Subject: [PATCH 149/502] minot typo --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 6759d50c9..92dc1c469 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -1,7 +1,7 @@
-# پردازش داده +#پردازش داده {#if fw === 'pt'} From 9708bc9c6df532b812562f148ecbd98a5144a973 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sat, 21 May 2022 18:41:41 +0200 Subject: [PATCH 150/502] minot typo --- chapters/fa/chapter3/2.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 92dc1c469..cf9a9e1de 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -1,7 +1,8 @@
-#پردازش داده + +# پردازش داده {#if fw === 'pt'} From 8a5894fc0695cf47ca8ca691c6911dbef6ec3c1e Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 22 May 2022 13:00:03 +0200 Subject: [PATCH 151/502] new phrases added to G --- chapters/fa/glossary/1.mdx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index 6e0ef2dba..4813de422 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -145,6 +145,17 @@ | Naive Bayes | بیز ساده | | Collaborative learning | یادگیری مشارکتی | | Demo | نمونه اولیه | +| collate | مرتب کردن | +| mapping | نگاشت | +| element | عنصر | +| tuple | تاپِل | +| object | شیء | +| paraphrases | جملات متناظر | +| benchmark | محک | +| items | اقلام | +| padding | هم‌طول‌سازی | +| sequential model | مدل ترتیبی | +| documentation | مستندات | معادل‌هایی که استفاده نمی‌کنیم: From 8d6f07345ca5ff1c7a38fedd2214c6c24f9061e8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 23 May 2022 08:29:02 +0200 Subject: [PATCH 152/502] a few changes applied --- chapters/fa/chapter3/2.mdx | 13 +++++-------- chapters/fa/glossary/1.mdx | 3 +-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index cf9a9e1de..cfe504239 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -101,7 +101,7 @@ model.train_on_batch(batch, labels) هاب تنها شامل مدل‌ها نمی‌باشد؛ بلکه شامل دیتاسِت‌های متعدد در بسیاری از زبان‌های مختلف می‌باشد. شما می‌توانید دیتاسِت‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک دیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی دیتاسِت MRPC تمرکز کنیم! این یکی از ۱۰ دیتاسِت [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدل‌های یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. -کتابخانه دیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و ذخیره‌سازی یک دیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دیتاسِت MRPC را به روش زیر دانلود کنیم: +کتابخانه دیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و انبار کردن یک دیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دیتاسِت MRPC را به روش زیر دانلود کنیم:
@@ -137,7 +137,7 @@ DatasetDict({ همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). - این دستور دیتاسِت را دانلود و به صورت پیش‌فرض در پوشه‌ *~/.cache/huggingface/dataset* ذخیره میکند. از فصل ۲ به یاد داشته باشید که می‌توانید پوشه‌ ذخیره‌سازی‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. + این دستور دیتاسِت را دانلود و به صورت پیش‌فرض در پوشه‌ *~/.cache/huggingface/dataset* انبار می‌کند. از فصل ۲ به یاد داشته باشید که می‌توانید پوشه‌ انبار کردن‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. ما می‌توانیم به هر جفت از جملات در شئ `raw_datasets` با استفاده از اندیس, مانند یک دیکشنری دسترسی پیدا کنیم: @@ -363,18 +363,15 @@ DatasetDict({ {#if fw === 'pt'} -تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *تابع مرتب کننده* خوانده می‌شود. شما می‌توانید این تابع را که در حالت پیش‌ فرض نمونه‌های شما را به تِنسور پایتورچ تبدیل کرده و به هم الحاق می‌کند (اگر عناصر شما لیست، تاپِل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد) هنگام ساختن `DataLoader` به داخل آن ارسال کنید. از آنجایی که ورودی‌های ما هم‌طول نخواهند بود استفاده از این تابع برای ما امکان‌پذیر نیست. ناهم‌طولی ورودی‌ها به این خاطر است که ما فرایند هم‌طول‌سازی را عمدا به تعویق انداختیم تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با مقدار زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش، فرایند تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار می‌تواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح می‌دهد، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. - +تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *تابع ترکیب کننده* خوانده می‌شود. شما می‌توانید این تابع را که در حالت پیش‌ فرض نمونه‌های شما را به تِنسور پایتورچ تبدیل کرده و به هم الحاق می‌کند (اگر عناصر شما لیست، تاپِل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد) هنگام ساختن `DataLoader` به داخل آن ارسال کنید. از آنجایی که ورودی‌های ما هم‌طول نخواهند بود استفاده از این تابع برای ما امکان‌پذیر نیست. ناهم‌طولی ورودی‌ها به این خاطر است که ما فرایند هم‌طول‌سازی را عمدا به تعویق انداختیم تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با مقدار زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش، فرایند تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار می‌تواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح می‌دهد، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. {:else} -تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *تابع مرتب کننده* خوانده می‌شود. تابع مرتب کننده پیش‌فرض تابعی است که فقط نمونه‌های شما را به `tf.Tensor` تبدیل کرده و آنها را به هم الحاق می‌کند (اگر عناصر شما لیست، تاپِل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما هم‌طول نخواهند بود استفاده از این تابع برای ما امکان پذیر نیست. ناهم‌طولی ورودی‌ها به این خاطر است که ما فرایند هم‌طول‌سازی را عمدا به تعویق انداختیم تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با مقدار زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش، فرایند تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار می‌تواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح می‌دهد، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. - -The function that is responsible for putting together samples inside a batch is called a *collate function*. The default collator is a function that will just convert your samples to tf.Tensor and concatenate them (recursively if your elements are lists, tuples, or dictionaries). This won't be possible in our case since the inputs we have won't all be of the same size. We have deliberately postponed the padding, to only apply it as necessary on each batch and avoid having over-long inputs with a lot of padding. This will speed up training by quite a bit, but note that if you're training on a TPU it can cause problems — TPUs prefer fixed shapes, even when that requires extra padding. +تابعی که مسئول کنار هم گذاشتن نمونه‌ها در یک بَتچ می‌باشد *تابع ترکیب کننده* خوانده می‌شود. تابع ترکیب کننده پیش‌فرض تابعی است که فقط نمونه‌های شما را به `tf.Tensor` تبدیل کرده و آنها را به هم الحاق می‌کند (اگر عناصر شما لیست، تاپِل یا دیکشنری باشند این کار به صورت بازگشتی انجام می‌گیرد). از آنجایی که ورودی‌های ما هم‌طول نخواهند بود استفاده از این تابع برای ما امکان پذیر نیست. ناهم‌طولی ورودی‌ها به این خاطر است که ما فرایند هم‌طول‌سازی را عمدا به تعویق انداختیم تا فقط در زمان نیاز آن را روی هر بَتچ اجرا کنیم و از داشتن ورودی‌های بیش از اندازه طولانی با مقدار زیادی هم‌طول‌سازی پیش‌گیری کنیم. این روش، فرایند تعلیم را تا اندازه‌ای سرعت می‌بخشد، اما توجه داشته باشید که اگر شما در حال تعلیم روی TPU هستید این کار می‌تواند مشکل ساز باشد چرا که TPU اشکال معین را ترجیح می‌دهد، حتی اگر نیاز به هم‌طول‌سازی اضافه داشته باشد. {/if} -برای انجام این کار در عمل، ما باید یک تابع مرتب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین تابعی را تحت عنوان `DataCollatorWithPadding` در اختیار ما قرار می‌دهد. این تابع به محض این که آن را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام این کار در عمل، ما باید یک تابع ترکیب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین قابلیتی را توسط شیء `DataCollatorWithPadding` به ما می‌دهد. این تابع به محض این که آن را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index 4813de422..d3fedc968 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -145,7 +145,7 @@ | Naive Bayes | بیز ساده | | Collaborative learning | یادگیری مشارکتی | | Demo | نمونه اولیه | -| collate | مرتب کردن | +| collate | ترکیب کردن | | mapping | نگاشت | | element | عنصر | | tuple | تاپِل | @@ -154,7 +154,6 @@ | benchmark | محک | | items | اقلام | | padding | هم‌طول‌سازی | -| sequential model | مدل ترتیبی | | documentation | مستندات | معادل‌هایی که استفاده نمی‌کنیم: From 494af448ff3e61884de48d6df83d06d4c31c7447 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 23 May 2022 08:53:18 +0200 Subject: [PATCH 153/502] minor updates applied --- chapters/fa/chapter3/2.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index cfe504239..1468d8a9e 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -135,7 +135,7 @@ DatasetDict({
-همانطور که می بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). +همانطور که می‌بینید یک شیء `DatasetDict` بدست می‌آوریم که شامل مجموعه `training`، مجموعه `validation` و مجموعه `test` می‌باشد. هر یک از این‌ها شامل چندین ستون (`label`، `sentence2`، `sentence1` و `idx`) و تعداد متغیری سطر که عناصر هر مجموعه را تشکیل می‌دهند می‌باشد. (بنابراین، ۳۶۶۸ جفت جمله در مجموعه `training` وجود دارد، ۴۰۸ تا در مجموعه `validation` و ۱۷۲۵ تا در مجموعه `test`). این دستور دیتاسِت را دانلود و به صورت پیش‌فرض در پوشه‌ *~/.cache/huggingface/dataset* انبار می‌کند. از فصل ۲ به یاد داشته باشید که می‌توانید پوشه‌ انبار کردن‌تان را با تنظیم متغیر محیطی `HF_HOME` به دلخواه تغییر دهید. @@ -300,7 +300,7 @@ tokenized_dataset = tokenizer( این روش به خوبی کار می‌کند، اما مشکل‌اش این است که دیکشنری (از کلیدهای ما شامل، `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.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌بر توکِن کردن نیاز داشته باشیم این روش انعطاف‌پذری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِن کند: +به منظور نگه داشتن داده به صورت یک دیتاسِت، از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌ بر توکِن کردن نیاز داشته باشیم این روش انعطاف‌پذیری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِن کند:
@@ -311,7 +311,7 @@ def tokenize_function(example):
-این تابع دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از دو جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان لیستی از جمله‌ها) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکٍنایزر را به میزان زیادی سریع‌تر خواهد کرد. این `tokenizer` با توکِنایزری در کتابخانه [Tokenizers](https://github.com/huggingface/tokenizers) از هاگینگ‌فِیس که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکٍنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یکجا به آن بدهیم. +این تابع دیکشنری (مثل اقلام داخل دیتاسِت) دریافت می‌کند و دیکشنری دیگری با کلیدهای `input_ids`، `attention_mask` و `token_type_ids` برمی‌گرداند. توجه داشته باشید از آنجایی که توکِنایزر روی لیست‌هایی از دو جمله‌ها کار می‌کند، همان‌طور که قبلا مشاهده کردیم، این تابع نیز در صورتی که دیکشنری `example` شامل چندین نمونه (هر کلید به عنوان لیستی از جمله‌ها) باشد کار می‌کند. این به ما این امکان را خواهد داد که از گزینه `batched=True` در فراخوانی تابع `map()` استفاده کنیم که توکِنایزر را به میزان زیادی سریع‌تر خواهد کرد. این `tokenizer` با توکِنایزری در کتابخانه [Tokenizers](https://github.com/huggingface/tokenizers) از هاگینگ‌فِیس که به زبان برنامه‌‌نویسی Rust نوشته شده پشتیبانی می‌شود. این توکِنایزر می‌تواند بسیار سریع باشد، اما فقط به شرطی که ورودی‌های زیادی را به صورت یک جا به آن بدهیم. توجه داشته باشید که ما آرگومان هم‌طول‌سازی را در تابع توکِن کننده‌مان نادیده گرفته‌ایم. این به این خاطر است که هم‌طول‌سازی روی همه نمونه‌ها برای بیشترین طول به صرفه نیست: بهتر است که نمونه‌ها را زمانی که در حال ساختن بَتچ هستیم هم‌طول کنیم، در این صورت فقط نیاز داریم نمونه‌ها را به اندازه بزرگترین طول همان بَتچ و نه بیشترین طول در سرتاسر دیتاسِت‌ هم‌طول کنیم. این روش زمانی که ورودی‌ها دارای طول‌های بسیار متغیری هستند وقت و انرژی زیادی را صرفه‌جویی خواهد کرد. @@ -371,7 +371,7 @@ DatasetDict({ {/if} -برای انجام این کار در عمل، ما باید یک تابع ترکیب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین قابلیتی را توسط شیء `DataCollatorWithPadding` به ما می‌دهد. این تابع به محض این که آن را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام این کار در عمل، ما باید یک تابع ترکیب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین قابلیتی را توسط شیء `DataCollatorWithPadding` به ما می‌دهد. این شئ به محض این که آن را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} @@ -456,19 +456,19 @@ batch = data_collator(samples)
-به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل‌مان می‌تواند با آنها کار کند، آماده هستیم برای کوک‌ کردن مدل: +به نظر خوب می‌آید! اکنون که از متن خالص به بَتچ‌هایی رسیده‌ایم که مدل‌مان می‌تواند با آنها کار کند، آماده کوک‌ کردن مدل هستیم: {/if} -✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی دیتاسِت GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای جفت شامل تک جمله‌ها می‌باشد این کار یک مقدار متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. +✏️ **امتحان کنید!** پروسه پیش‌پردازش را روی دیتاسِت GLUE SST-2 باز تکرار کنید. از آنجایی که این مجموعه به جای دو جمله‌ها شامل تک جمله‌ها می‌باشد این کار کمی متفاوت است، اما بقیه کارهایی که انجام داده‌ایم باید یکسان به نظر برسند. برای یک چالش مشکل‌تر، سعی کنید تابع پیش‌پردازشی بنویسید که برای همه مسئله‌های GLUE کار کند. {#if fw === 'tf'} -اکنون که دیتاسِت‌مان و یک `collator` داده در اختیار داریم، حال نیاز داریم که آنها را باهم بکار ببریم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، تابعی ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه می‌کند: `to_tf_dataset()`. این تابع یک `tf.data.Dataset` شامل پارامتری اختیاری برای تابع `collation` را دور دیتاسِت‌تان می‌پیچد. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس می‌تواند برای `model.fit()` استفاده کند، در تنیجه همین یک تابع می‌تواند یک دیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دیتاسِت‌مان مشاهده کنیم! +اکنون که دیتاسِت‌مان و یک `collator` داده در اختیار داریم، نیاز داریم که آنها را باهم بکار ببریم. ما می‌توانستیم بَتچ‌ها را دستی لود کرده و آنها را `collate` کنیم، اما این روش کار زیادی می‌برد و احتمالا خیلی هم بهینه نخواهد بود. در عوض، تابعی ساده وجود دارد که راه حل بهینه‌ای برای این مسئله ارائه می‌کند: `to_tf_dataset()`. این تابع یک `tf.data.Dataset` شامل پارامتری اختیاری برای تابع `collation` را دور دیتاسِت‌تان می‌پیچد. `tf.data.Dataset` یک فرمت بومی تِنسورفلو است که کِراس می‌تواند برای `model.fit()` استفاده کند، در نتیجه همین یک تابع می‌تواند یک دیتاسِت هاگینگ‌فِیس را به سرعت به فرمت آماده برای تعلیم تبدیل کند. اجازه دهید آنرا در عمل با دیتاسِت‌مان مشاهده کنیم!
From 703d1d138069bc0ac6083bee018a7849eed55234 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 23 May 2022 14:21:27 +0200 Subject: [PATCH 154/502] comments applied --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 1468d8a9e..54dc5dedc 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -161,7 +161,7 @@ raw_train_dataset[0]
-می‌بینیم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین لازم نیست هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم قابلیت‌های ‌`raw_train_dataset`‌ را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت. +می‌بینیم که برچسب‌ها از پیش اعداد صحیح هستند، بنابراین لازم نیست هیچ پیش‌پردازشی روی آنها انجام دهیم. برای این که بدانیم کدام مقدار عددی صحیح به کدام برچسب مربوط می‌شود، می‌توانیم `features` از ‌`raw_train_dataset`‌مان را بررسی کنیم. این کار نوع هر ستون را به ما خواهد گفت.
@@ -371,7 +371,7 @@ DatasetDict({ {/if} -برای انجام این کار در عمل، ما باید یک تابع ترکیب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین قابلیتی را توسط شیء `DataCollatorWithPadding` به ما می‌دهد. این شئ به محض این که آن را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام این کار در عمل، ما باید یک تابع ترکیب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین قابلیتی را توسط کلاس `DataCollatorWithPadding` به ما می‌دهد. به محض این که این کلاس را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} From 31b55cd9fd543405d0258b5aab511c3044b0a3a8 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 24 May 2022 09:12:13 +0200 Subject: [PATCH 155/502] one last fix --- chapters/fa/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 54dc5dedc..092a92b30 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -371,7 +371,7 @@ DatasetDict({ {/if} -برای انجام این کار در عمل، ما باید یک تابع ترکیب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین قابلیتی را توسط کلاس `DataCollatorWithPadding` به ما می‌دهد. به محض این که این کلاس را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: +برای انجام این کار در عمل، ما باید یک تابع ترکیب کننده تعریف کنیم که میزان درستی از هم‌طول‌سازی را به آیتم‌های دیتاسِت‌هایی که ما می‌خواهیم باهم در یک بَتچ قرار دهیم اعمال کند. خوشبختانه، کتابخانه ترنسفورمرهای هاگینگ‌فِیس چنین قابلیتی را توسط کلاس `DataCollatorWithPadding` به ما می‌دهد. به محض این که شیء‌ای از این کلاس را تعریف کنیم (یعنی تعیین کنیم چه توکِنی برای هم‌طول‌سازی استفاده کند و مدل انتظار هم‌طول‌سازی از سمت چپ یا راست ورودی‌ها را داشته باشد) یک توکِنایزر را برداشته و هر کاری را که لازم دارید انجام می‌دهد: {#if fw === 'pt'} From 7cead81c2472d881b73265859c51a3ae4ea5dc32 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 30 May 2022 16:06:31 +0200 Subject: [PATCH 156/502] chapter title fixed --- chapters/fa/_toctree.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index d45d23d0e..4884167eb 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -19,6 +19,13 @@ - local: chapter2/3 title: مدل‌ها +- title: ۳. کوک کردن یک مدل از پیش تعلیم دیده # Translate this! + sections: + - local: chapter3/1 + title: مقدمه # Translate this! + - local: chapter3/2 + title: پردازش داده # Translate this! + - title: ۴- به اشتراک‌گذاری مدل‌ها و توکِنایزرها sections: - local: chapter4/1 @@ -26,13 +33,6 @@ - local: chapter4/2 title: بکارگیری مدل‌های از پیش تعلیم دیده -- title: 3. کوک کردن یک مدل از پیش تعلیم دیده # Translate this! - sections: - - local: chapter3/1 - title: مقدمه # Translate this! - - local: chapter3/2 - title: پردازش داده # Translate this! - - title: واژه‌نامه sections: - local: glossary/1 From 4fd7475da184dd87dbcf1140a5b73ff32025e17b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 30 May 2022 16:09:30 +0200 Subject: [PATCH 157/502] minor fix - chapter title --- chapters/fa/_toctree.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index 5dcfcc83c..021a2c1eb 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -19,7 +19,7 @@ - local: chapter2/3 title: مدل‌ها -- title: ۳. کوک کردن یک مدل از پیش تعلیم دیده # Translate this! +- title: ۳- کوک کردن یک مدل از پیش تعلیم دیده # Translate this! sections: - local: chapter3/1 title: مقدمه # Translate this! From 25c3b71b9c7b235435d14cb7216bc29b2650a34a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 30 May 2022 16:12:01 +0200 Subject: [PATCH 158/502] fixe typos the title of chapter 3 --- chapters/fa/_toctree.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index 021a2c1eb..7336e1e93 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -19,12 +19,12 @@ - local: chapter2/3 title: مدل‌ها -- title: ۳- کوک کردن یک مدل از پیش تعلیم دیده # Translate this! +- title: ۳- کوک کردن یک مدل از پیش تعلیم دیده sections: - local: chapter3/1 - title: مقدمه # Translate this! + title: مقدمه - local: chapter3/2 - title: پردازش داده # Translate this! + title: پردازش داده - title: ۴- به اشتراک‌گذاری مدل‌ها و توکِنایزرها sections: From b66cdef68759f6fab0a08c2e37e5586c489c93df Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 1 Jun 2022 10:04:27 +0200 Subject: [PATCH 159/502] new file added --- chapters/fa/chapter3/3_tf.mdx | 263 ++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 chapters/fa/chapter3/3_tf.mdx diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx new file mode 100644 index 000000000..6e5d2c746 --- /dev/null +++ b/chapters/fa/chapter3/3_tf.mdx @@ -0,0 +1,263 @@ + + +
+ +# کوک کردن مدل‌ها با استفاده از کِراس + +# Fine-tuning a model with Keras + + + +وقتی که شما همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPUها یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. + +Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). + +نمونه کدهای زیر فرض می‌کنند شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: + +The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: + +
+ +```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, +) +``` + +
+ +### تعلیم + +مدل‌های تِنسورفِلو که از ترَنسفورمِرهای هاگینگ‌فِیس وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. + +TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. + + + +جمله بالا به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار بسیار کمی لازم است تا تعلیم را روی آن شروع کنیم. + +That means that once we have our data, very little work is required to begin training on it. + + + +مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب دسته استفاده خواهیم کرد: + +As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: + +
+ +```py +from transformers import TFAutoModelForSequenceClassification + +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +
+ +شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه-سر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه-سر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه-سر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه-سر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان چیزی است که می‌خواهیم اکنون انجام دهیم. + +You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. + +برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای تعلیم و خطای تایید را در انتهای هر epoch گزارش می‌دهد. + +To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. + + + +توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع خطای مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع خطا در زمان `compile()` تعیین نکنید آنها از این تابع خطا به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع خطای داخلی شما نیاز خواهید داشت برچسب‌ دسته‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب دسته مجزا، که روش معمول استفاده از برچسب‌ دسته‌ها در مدل‌های کِراس می‌باشد. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع خطای درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع خطای استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. + +Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. + + + +
+ +```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, +) +``` + +
+ + + +Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. + + + +### Improving training performance + + + +If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause +is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes +that optimizer with default values for all parameters, including learning rate. From long experience, though, we know +that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written +as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. + +In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate +over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* +the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is +`PolynomialDecay` — despite the name, with default settings it simply linearly decays the learning rate from the initial +value to the final value over the course of training, which is exactly what we want. In order to use a scheduler correctly, +though, we need to tell it how long training is going to be. We compute that as `num_train_steps` below. + +
+ +```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) +``` + +
+ + + +The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. + + + +Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: + +
+ +```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"]) +``` + +
+ +Now, we fit again: + +
+ +```py +model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) +``` + +
+ + + +💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) + + + +### Model predictions + + + + +Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. + +
+ +```py +preds = model.predict(tf_validation_dataset)["logits"] +``` + +
+ +We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: + +
+ +```py +class_preds = np.argmax(preds, axis=1) +print(preds.shape, class_preds.shape) +``` + +
+ +
+ +```python out +(408, 2) (408,) +``` + +
+ +Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: + +
+ +```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} +``` + +
+ +The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. + +This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. + +
\ No newline at end of file From d1feca3c9b8548953f79f24dd968956f7b53aaad Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 1 Jun 2022 15:29:18 +0200 Subject: [PATCH 160/502] new paragraphs added --- chapters/fa/chapter3/3_tf.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 6e5d2c746..4a351f66b 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -73,7 +73,7 @@ That means that once we have our data, very little work is required to begin tra -مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب دسته استفاده خواهیم کرد: +مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب‌دسته استفاده خواهیم کرد: As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: @@ -91,13 +91,13 @@ model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_lab You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین خطای تعلیم و خطای تایید را در انتهای هر epoch گزارش می‌دهد. +برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه تعلیم و هزینه تایید را در انتهای هر epoch گزارش می‌دهد. To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. -توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع خطای مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع خطا در زمان `compile()` تعیین نکنید آنها از این تابع خطا به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع خطای داخلی شما نیاز خواهید داشت برچسب‌ دسته‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب دسته مجزا، که روش معمول استفاده از برچسب‌ دسته‌ها در مدل‌های کِراس می‌باشد. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع خطای درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع خطای استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. +توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب‌دسته‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب‌دسته مجزا، که روش معمول استفاده از برچسب‌دسته‌ها در مدل‌های کِراس می‌باشد. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینه درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع هزینه استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. @@ -123,6 +123,8 @@ model.fit( +در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغییر رشته‌ای برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فرض می‌کند که شما از پیش یک لایه softmax به خروجی خودتان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax اعمال شود خروجی می‌دهند، که تحت عنوان *logits* نیز شناخته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم که این چیزی است که مدل ما انجام می‌دهد و تنها راه انجام این کار این است که آن را به صورت مستقیم صدا بزنیم، به جای استفاده از یک نام به صورت یک متغییر رشته‌ای. + Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. From 644599a629f6af92e8b722e7ce7bcb0a7d52fbaa Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 1 Jun 2022 15:42:27 +0200 Subject: [PATCH 161/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 4a351f66b..22587d302 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -91,13 +91,13 @@ model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_lab You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه تعلیم و هزینه تایید را در انتهای هر epoch گزارش می‌دهد. +برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه تعلیم و هزینه تایید را در انتهای هر epoch گزارش می‌دهد. To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. -توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب‌دسته‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب‌دسته مجزا، که روش معمول استفاده از برچسب‌دسته‌ها در مدل‌های کِراس می‌باشد. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینه درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع هزینه استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. +توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب‌دسته‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب‌دسته مجزا، که روش معمول استفاده از برچسب‌دسته‌ها در مدل‌های کِراس می‌باشد. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینه درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع هزینه استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. @@ -129,6 +129,8 @@ Note a very common pitfall here — you *can* just pass the name of the loss as +### بهبود کارایی آموزش + ### Improving training performance From 531f9634c197e8511fcfc1dae26dc7078f5610c4 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 1 Jun 2022 15:48:25 +0200 Subject: [PATCH 162/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 22587d302..db2229019 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -123,7 +123,7 @@ model.fit( -در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغییر رشته‌ای برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فرض می‌کند که شما از پیش یک لایه softmax به خروجی خودتان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax اعمال شود خروجی می‌دهند، که تحت عنوان *logits* نیز شناخته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم که این چیزی است که مدل ما انجام می‌دهد و تنها راه انجام این کار این است که آن را به صورت مستقیم صدا بزنیم، به جای استفاده از یک نام به صورت یک متغییر رشته‌ای. +در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغییر رشته‌ای برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softma از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax اعمال شود خروجی می‌دهند، که تحت عنوان *logits* نیز شناخته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم که این چیزی است که مدل ما انجام می‌دهد و تنها راه انجام این کار این است که آن را به صورت مستقیم صدا بزنیم، به جای استفاده از یک نام به صورت یک متغییر رشته‌ای. Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. From 99b95027dcaa7490e32083caed5f0e784dce955b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 1 Jun 2022 15:54:06 +0200 Subject: [PATCH 163/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index db2229019..b31484642 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -123,7 +123,7 @@ model.fit( -در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغییر رشته‌ای برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softma از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax اعمال شود خروجی می‌دهند، که تحت عنوان *logits* نیز شناخته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم که این چیزی است که مدل ما انجام می‌دهد و تنها راه انجام این کار این است که آن را به صورت مستقیم صدا بزنیم، به جای استفاده از یک نام به صورت یک متغییر رشته‌ای. +در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغییر رشته‌ای برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softmax از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax اعمال شود به خروجی می‌دهند، که به آنها *logits* نیز گفته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدل‌مان انجام می‌دهد و تنها راه گفتن آن این است که به جای استفاده از یک نام به صورت یک متغییر رشته‌ای، آن را به صورت مستقیم صدا بزنیم. Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. From 2f9e9b5c43025d1cb07397a55ec3da77f4fd66b0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 1 Jun 2022 16:17:02 +0200 Subject: [PATCH 164/502] new paragraph added --- chapters/fa/chapter3/3_tf.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index b31484642..3998f4427 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -123,7 +123,7 @@ model.fit( -در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغییر رشته‌ای برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softmax از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax اعمال شود به خروجی می‌دهند، که به آنها *logits* نیز گفته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدل‌مان انجام می‌دهد و تنها راه گفتن آن این است که به جای استفاده از یک نام به صورت یک متغییر رشته‌ای، آن را به صورت مستقیم صدا بزنیم. +در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغیر متنی برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softmax از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax اعمال شود به خروجی می‌دهند، که به آنها *logits* نیز گفته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدل‌مان انجام می‌دهد و تنها راه گفتن آن این است که به جای ارسال نام تابع هزینه به صورت متغیر متنی، آن را به صورت مستقیم صدا بزنیم. Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. @@ -135,6 +135,8 @@ Note a very common pitfall here — you *can* just pass the name of the loss as +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن بهینه‌ساز، شامل نرخ تعلیم، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3، یا 0.001 نیز نوشته میشود. + If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes that optimizer with default values for all parameters, including learning rate. From long experience, though, we know From 9d89e11ac0de394437a4d3aba853ce7b87a03047 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 1 Jun 2022 16:17:59 +0200 Subject: [PATCH 165/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 3998f4427..259835477 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -135,7 +135,7 @@ Note a very common pitfall here — you *can* just pass the name of the loss as -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن بهینه‌ساز، شامل نرخ تعلیم، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3، یا 0.001 نیز نوشته میشود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ تعلیم، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3، یا 0.001 نیز نوشته میشود. If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes From 9cdff871f5996a7faa2160a9136e1902a096b56b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Wed, 1 Jun 2022 16:42:48 +0200 Subject: [PATCH 166/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 259835477..1984ee463 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -135,7 +135,7 @@ Note a very common pitfall here — you *can* just pass the name of the loss as -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ تعلیم، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3، یا 0.001 نیز نوشته میشود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ تعلیم، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3، یا 0.001 نیز نوشته میشود. If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes From 2ab6994b8b2f9125f2f692428eaa051bec2146eb Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 08:18:36 +0200 Subject: [PATCH 167/502] new paragraph added --- chapters/fa/chapter3/3_tf.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 1984ee463..999746a06 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -135,7 +135,7 @@ Note a very common pitfall here — you *can* just pass the name of the loss as -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ تعلیم، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3، یا 0.001 نیز نوشته میشود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3، یا 0.001 نیز نوشته میشود. If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes @@ -143,6 +143,8 @@ that optimizer with default values for all parameters, including learning rate. that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. +علاوه بر کم کردن نرخ یادگیری، ما ترفند دیگری در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. در متون مشابه گاها خواهید دید که از این روش با عنوان نرخ یادگیری *محو شونده* یا *باز پختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمانبند نرخ یادگیری* است.* یک زمانبند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمانبند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمانبند ما نیاز داریم که به آن بگوییم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. + In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is From 5b7ca84e56ffb53eb032246b711a11a07685df7d Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 11:25:54 +0200 Subject: [PATCH 168/502] all paragraphs added --- chapters/fa/chapter3/3_tf.mdx | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 999746a06..05e540c15 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -143,7 +143,7 @@ that optimizer with default values for all parameters, including learning rate. that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. -علاوه بر کم کردن نرخ یادگیری، ما ترفند دیگری در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. در متون مشابه گاها خواهید دید که از این روش با عنوان نرخ یادگیری *محو شونده* یا *باز پختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمانبند نرخ یادگیری* است.* یک زمانبند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمانبند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمانبند ما نیاز داریم که به آن بگوییم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. +علاوه بر کم کردن نرخ یادگیری، ما ترفند دیگری در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. در متون مشابه گاها خواهید دید که از این روش با عنوان نرخ یادگیری *محو شونده* یا *بازپختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمانبند نرخ یادگیری* است.* یک زمانبند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمانبند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمانبند ما نیاز داریم که به آن بگوییم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* @@ -175,10 +175,14 @@ opt = Adam(learning_rate=lr_scheduler) +کتابخانه ترنسفورمرهای هاگینگ‌فِیس همچنین یک تابع `create_optimizer()` دارد که یک بهینه‌ساز `AdamW` دارای اندازه کاهش نرخ یادگیری می‌سازد. این یک میانبر مناسب است که آنرا با جزئیات در بخش‌های بعدی این آموزش خواهید دید. + The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. +اکنون بهینه ساز کاملا جدیدمان را در اختار داریم و می‌توانیم آنرا تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شده‌اند را به حالت اولیه بازگردانیم، سپس می‌توانیم مدل را با بهینه ساز جدید تدوین کنیم: + Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer:
@@ -205,14 +209,20 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) +اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در این‌باره در [Chapter 4](/course/chapter4/3) بیشتر خواهیم آموخت. + 💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) +# پیش‌بینی‌های مدل + ### Model predictions +تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما چه کار کنیم اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها یا چه برای استفاده در خط تولید، خروجی دریافت کنیم؟ برای انجام این کار می‌توانیم از تابع `predict()` استفاده کنیم. این کار *logits* را از لایه سر خروجی مدل، یکی به ازای هر کلاس، باز می‌گرداند. + Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. @@ -224,6 +234,8 @@ preds = model.predict(tf_validation_dataset)["logits"]
+ما می‌توانیم logitها را با استفاده از `argmax` برای یافتن بزرگترین لاجیت، که نماینده محتمل ترین دسته می‌باشد به پیش‌بینی‌های دسته مدل تبدیل کنیم، + We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class:
@@ -243,6 +255,8 @@ print(preds.shape, class_preds.shape)
+اکنون، اجازه دهید از `preds` برای محاسبه برخی معیارها استفاده کنیم! ما می‌توانیم معیارهای مرتبط با دیتاسِت MRPC را، به همان آسانی که دیتاسِت را بارگذاری کردیم، بارگذاری کنیم اما این بار با استفاده از تابع `load_metric()`. شیء باز گردانده شده تابعی به نام `compute()` دارد که می‌توانیم برای محاسبه معیارها از آن استفاده کنیم: + Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation:
@@ -264,8 +278,12 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l
+از آنجایی که مقداردهی اولیه تصادفی در لایه‌سر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه آزمون دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT paper](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح میکند. + The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. +به این ترتیب مقدمه بازتعلیم با استفاده از `API` کِراس به پایان می‌رسد. یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` در فصل ۷ ارائه خواهد شد. اگر مایلید خود را روی `API` کِراس کار آزموده کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, بازتعلیم دهید + This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2.
\ No newline at end of file From e4a6674103b4536d5e30c21a2dab9dfcf02badd1 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 11:53:49 +0200 Subject: [PATCH 169/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 05e540c15..934502c11 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -282,7 +282,7 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. -به این ترتیب مقدمه بازتعلیم با استفاده از `API` کِراس به پایان می‌رسد. یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` در فصل ۷ ارائه خواهد شد. اگر مایلید خود را روی `API` کِراس کار آزموده کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, بازتعلیم دهید +به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` در فصل ۷ ارائه خواهد شد. اگر مایلید خود را روی `API` کِراس کار آزموده کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, کوک کنید. This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. From 0e1e56f0e7458140b987496e83b34adb2be8a5bd Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 11:55:09 +0200 Subject: [PATCH 170/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 934502c11..183b5ff4b 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -278,7 +278,7 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l
-از آنجایی که مقداردهی اولیه تصادفی در لایه‌سر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه آزمون دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT paper](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح میکند. +از آنجایی که مقداردهی اولیه تصادفی در لایه‌سر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه آزمون دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح میکند. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. From ecdec2a248b52d7d83d9b97ef46f42a874b4322d Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:00:46 +0200 Subject: [PATCH 171/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 183b5ff4b..7b576b0e9 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -91,7 +91,7 @@ model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_lab You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه تعلیم و هزینه تایید را در انتهای هر epoch گزارش می‌دهد. +برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه `training` و هزینه `validation` را در انتهای هر epoch گزارش می‌دهد. To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. @@ -278,7 +278,7 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l
-از آنجایی که مقداردهی اولیه تصادفی در لایه‌سر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه آزمون دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح میکند. +از آنجایی که مقداردهی اولیه تصادفی در لایه‌سر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح میکند. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. From 28bc80663b79d67fcf11c21008e21e30ec1a8973 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:09:02 +0200 Subject: [PATCH 172/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 7b576b0e9..0d2d224a3 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -234,7 +234,7 @@ preds = model.predict(tf_validation_dataset)["logits"]
-ما می‌توانیم logitها را با استفاده از `argmax` برای یافتن بزرگترین لاجیت، که نماینده محتمل ترین دسته می‌باشد به پیش‌بینی‌های دسته مدل تبدیل کنیم، +سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگترین `logit`، که نماینده محتمل ترین دسته می‌باشد به پیش‌بینی‌های دسته مدل تبدیل کنیم، We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: @@ -278,7 +278,7 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l
-از آنجایی که مقداردهی اولیه تصادفی در لایه‌سر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح میکند. +از آنجایی که مقداردهی اولیه تصادفی در لایه‌سر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. From 6b361fd2a4e1fd97681b89c6c62b239e14494d08 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:16:38 +0200 Subject: [PATCH 173/502] minor paragraph fixes applied --- chapters/fa/chapter3/3_tf.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 0d2d224a3..ddb8b064a 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -135,7 +135,7 @@ Note a very common pitfall here — you *can* just pass the name of the loss as -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3، یا 0.001 نیز نوشته میشود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3 یا 0.001 نیز نوشته می‌شود. If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes @@ -143,7 +143,7 @@ that optimizer with default values for all parameters, including learning rate. that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. -علاوه بر کم کردن نرخ یادگیری، ما ترفند دیگری در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. در متون مشابه گاها خواهید دید که از این روش با عنوان نرخ یادگیری *محو شونده* یا *بازپختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمانبند نرخ یادگیری* است.* یک زمانبند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمانبند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمانبند ما نیاز داریم که به آن بگوییم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. +علاوه بر کم کردن یکباره نرخ یادگیری ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمانب‌ند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* From 9ee05b2af30c7f7b20e402cd0ec320191f6501e6 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:18:52 +0200 Subject: [PATCH 174/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index ddb8b064a..a6ca0d872 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -129,7 +129,9 @@ Note a very common pitfall here — you *can* just pass the name of the loss as -### بهبود کارایی آموزش + +### بهبود کارایی تعلیم + ### Improving training performance @@ -143,7 +145,7 @@ that optimizer with default values for all parameters, including learning rate. that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. -علاوه بر کم کردن یکباره نرخ یادگیری ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمانب‌ند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. +علاوه بر کم کردن یکباره نرخ یادگیری ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* @@ -215,7 +217,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -# پیش‌بینی‌های مدل +### پیش‌بینی‌های مدل ### Model predictions From cfcda0ae5c77ee0d8727bcea8446292ccb065fcc Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:22:45 +0200 Subject: [PATCH 175/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index a6ca0d872..9990d1f61 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -87,7 +87,7 @@ model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_lab
-شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه-سر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه-سر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه-سر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه-سر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان چیزی است که می‌خواهیم اکنون انجام دهیم. +شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان چیزی است که می‌خواهیم اکنون انجام دهیم. You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. @@ -223,7 +223,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما چه کار کنیم اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها یا چه برای استفاده در خط تولید، خروجی دریافت کنیم؟ برای انجام این کار می‌توانیم از تابع `predict()` استفاده کنیم. این کار *logits* را از لایه سر خروجی مدل، یکی به ازای هر کلاس، باز می‌گرداند. +تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما چه کار کنیم اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها یا چه برای استفاده در خط تولید، خروجی دریافت کنیم؟ برای انجام این کار می‌توانیم از تابع `predict()` استفاده کنیم. این کار *logits* را از لایه‌ سَر خروجی مدل، یکی به ازای هر کلاس، باز می‌گرداند. Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. @@ -280,7 +280,7 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l
-از آنجایی که مقداردهی اولیه تصادفی در لایه‌سر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. +از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. From 17b37be11f6f7c7b4aabb26ffe8ba6d77f5c05aa Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:38:08 +0200 Subject: [PATCH 176/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 9990d1f61..ddaca838b 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -17,7 +17,7 @@ Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). -نمونه کدهای زیر فرض می‌کنند شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: +نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: @@ -73,7 +73,7 @@ That means that once we have our data, very little work is required to begin tra -مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب‌دسته استفاده خواهیم کرد: +مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب دسته استفاده خواهیم کرد: As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: @@ -87,7 +87,7 @@ model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_lab
-شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان چیزی است که می‌خواهیم اکنون انجام دهیم. +شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان کاری است که می‌خواهیم اکنون انجام دهیم. You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. @@ -97,7 +97,7 @@ To fine-tune the model on our dataset, we just have to `compile()` our model and -توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب‌دسته‌های خودتان را به عنوان بخشی از ورودی ارسال کنید، نه به صورت یک برچسب‌دسته مجزا، که روش معمول استفاده از برچسب‌دسته‌ها در مدل‌های کِراس می‌باشد. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینه درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع هزینه استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. +توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب دسته‌های خودتان را به عنوان بخشی از ورودی، نه به صورت یک برچسب دسته مجزا که روش معمول استفاده از برچسب دسته‌ها در مدل‌های کِراس می‌باشد، ارسال کنید. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینه‌ی درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع هزینه استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. @@ -123,7 +123,7 @@ model.fit( -در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغیر متنی برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softmax از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax اعمال شود به خروجی می‌دهند، که به آنها *logits* نیز گفته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدل‌مان انجام می‌دهد و تنها راه گفتن آن این است که به جای ارسال نام تابع هزینه به صورت متغیر متنی، آن را به صورت مستقیم صدا بزنیم. +در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغیر متنی برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softmax از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax به آنها اعمال شود به خروجی می‌دهند، که همچنین به عنوان *logits* شناخته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدل‌مان انجام می‌دهد و تنها راه گفتن آن این است که به جای ارسال نام تابع هزینه به صورت متغیر متنی، آن را به صورت مستقیم صدا بزنیم. Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. From a34fb6d344cc2d322619e013882ddd516cbce2b1 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:45:14 +0200 Subject: [PATCH 177/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index ddaca838b..aed8bec16 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -137,7 +137,7 @@ Note a very common pitfall here — you *can* just pass the name of the loss as -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و همچنین به صورت 10 به توان -3 یا 0.001 نیز نوشته می‌شود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد که به صورت‌های 10 به توان -3 یا 0.001 نیز نوشته می‌شود. If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes @@ -145,7 +145,7 @@ that optimizer with default values for all parameters, including learning rate. that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. -علاوه بر کم کردن یکباره نرخ یادگیری ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. +علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* @@ -177,13 +177,13 @@ opt = Adam(learning_rate=lr_scheduler) -کتابخانه ترنسفورمرهای هاگینگ‌فِیس همچنین یک تابع `create_optimizer()` دارد که یک بهینه‌ساز `AdamW` دارای اندازه کاهش نرخ یادگیری می‌سازد. این یک میانبر مناسب است که آنرا با جزئیات در بخش‌های بعدی این آموزش خواهید دید. +کتابخانه ترنسفورمرهای هاگینگ‌فِیس همچنین یک تابع `create_optimizer()` دارد که بهینه‌سازی از نوع `AdamW` دارای میزان کاهش نرخ یادگیری می‌سازد. این یک میان‌بر مناسب است که آن‌ را با جزئیات در بخش‌های بعدی این آموزش خواهید دید. The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. -اکنون بهینه ساز کاملا جدیدمان را در اختار داریم و می‌توانیم آنرا تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شده‌اند را به حالت اولیه بازگردانیم، سپس می‌توانیم مدل را با بهینه ساز جدید تدوین کنیم: +اکنون بهینه ساز کاملا جدیدمان را در اختار داریم و می‌توانیم آن را تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شده‌اند را به حالت اولیه بازگردانیم، سپس می‌توانیم مدل را با بهینه ساز جدید تدوین کنیم: Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: From 268f7211876abf8faecae948161a91b4e70c2462 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:58:09 +0200 Subject: [PATCH 178/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index aed8bec16..980dbeaf7 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -137,7 +137,7 @@ Note a very common pitfall here — you *can* just pass the name of the loss as -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچکتر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد که به صورت‌های 10 به توان -3 یا 0.001 نیز نوشته می‌شود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد که و صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes @@ -145,7 +145,7 @@ that optimizer with default values for all parameters, including learning rate. that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. -علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی نیز یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. +علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* @@ -177,13 +177,13 @@ opt = Adam(learning_rate=lr_scheduler) -کتابخانه ترنسفورمرهای هاگینگ‌فِیس همچنین یک تابع `create_optimizer()` دارد که بهینه‌سازی از نوع `AdamW` دارای میزان کاهش نرخ یادگیری می‌سازد. این یک میان‌بر مناسب است که آن‌ را با جزئیات در بخش‌های بعدی این آموزش خواهید دید. +کتابخانه ترنسفورمرهای هاگینگ‌فِیس همچنین یک تابع `create_optimizer()` دارد که بهینه‌سازی از نوع `AdamW`، دارای میزان کاهش نرخ یادگیری می‌سازد. این یک میان‌بر مناسب است که آن‌ را با جزئیات در بخش‌های بعدی این آموزش خواهید دید. The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. -اکنون بهینه ساز کاملا جدیدمان را در اختار داریم و می‌توانیم آن را تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شده‌اند را به حالت اولیه بازگردانیم، سپس می‌توانیم مدل را با بهینه ساز جدید تدوین کنیم: +اکنون بهینه‌ساز کاملا جدیدمان را در اختیار داریم و می‌توانیم آن را تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شده‌اند را به حالت اولیه بازگردانیم، سپس می‌توانیم مدل را با بهینه ساز جدید تدوین کنیم: Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: @@ -199,6 +199,8 @@ model.compile(optimizer=opt, loss=loss, metrics=["accuracy"]) +حالا دوباره مدل را تعلیم می‌دهیم: + Now, we fit again:
@@ -211,7 +213,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در این‌باره در [Chapter 4](/course/chapter4/3) بیشتر خواهیم آموخت. +اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [Chapter 4](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. 💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) @@ -223,7 +225,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما چه کار کنیم اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها یا چه برای استفاده در خط تولید، خروجی دریافت کنیم؟ برای انجام این کار می‌توانیم از تابع `predict()` استفاده کنیم. این کار *logits* را از لایه‌ سَر خروجی مدل، یکی به ازای هر کلاس، باز می‌گرداند. +تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ به برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر دسته یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. From 56bf11959795e896fe66e982d085b4751a3987f7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 12:59:41 +0200 Subject: [PATCH 179/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 980dbeaf7..0ab11ef6c 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -225,7 +225,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ به برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر دسته یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. +تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ به برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار ازای هر کلاس یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. From b1c8c1d4e9320daa7842e06b8860476966331457 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:00:09 +0200 Subject: [PATCH 180/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 0ab11ef6c..ac74e527e 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -225,7 +225,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ به برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار ازای هر کلاس یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. +تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ به برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر کلاس یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. From 4f974d5a1ea14cd5c8276f74cd455564b9b79f49 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:01:16 +0200 Subject: [PATCH 181/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index ac74e527e..e3d60b658 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -238,7 +238,7 @@ preds = model.predict(tf_validation_dataset)["logits"]
-سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگترین `logit`، که نماینده محتمل ترین دسته می‌باشد به پیش‌بینی‌های دسته مدل تبدیل کنیم، +سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگ‌ترین `logit`، که نماینده محتمل ترین دسته می‌باشد، به پیش‌بینی‌های دسته مدل تبدیل کنیم، We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: From 64303ef6c2e96b5d20968680e6c5881b1bbbf938 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:01:59 +0200 Subject: [PATCH 182/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index e3d60b658..cafd7f59e 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -238,7 +238,7 @@ preds = model.predict(tf_validation_dataset)["logits"] -سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگ‌ترین `logit`، که نماینده محتمل ترین دسته می‌باشد، به پیش‌بینی‌های دسته مدل تبدیل کنیم، +سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگ‌ترین `logit`، که نماینده محتمل‌ترین دسته می‌باشد، به پیش‌بینی‌های دسته مدل تبدیل کنیم، We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: From 67f1b0bb8836a85eaad785c7a22e99a337201583 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:04:43 +0200 Subject: [PATCH 183/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index cafd7f59e..91420a328 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -238,7 +238,7 @@ preds = model.predict(tf_validation_dataset)["logits"] -سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگ‌ترین `logit`، که نماینده محتمل‌ترین دسته می‌باشد، به پیش‌بینی‌های دسته مدل تبدیل کنیم، +سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگ‌ترین `logit`، که نماینده محتمل‌ترین دسته می‌باشد، به پیش‌بینی‌های دسته مدل تبدیل کنیم: We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: @@ -282,7 +282,7 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l -از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. +از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. From c0940eaae50098cdec49fc505b1f298fcbf91ddb Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:13:36 +0200 Subject: [PATCH 184/502] prune original text --- chapters/fa/chapter3/3_tf.mdx | 58 ++--------------------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 91420a328..0d7aea252 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -4,7 +4,6 @@ # کوک کردن مدل‌ها با استفاده از کِراس -# Fine-tuning a model with Keras `model.fit()`
روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPUها یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. -Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). - نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: -The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: -
```py @@ -63,20 +58,15 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( مدل‌های تِنسورفِلو که از ترَنسفورمِرهای هاگینگ‌فِیس وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. -TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. جمله بالا به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار بسیار کمی لازم است تا تعلیم را روی آن شروع کنیم. -That means that once we have our data, very little work is required to begin training on it. - مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب دسته استفاده خواهیم کرد: -As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: -
```py @@ -89,18 +79,12 @@ model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_lab شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان کاری است که می‌خواهیم اکنون انجام دهیم. -You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. - برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه `training` و هزینه `validation` را در انتهای هر epoch گزارش می‌دهد. -To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. - توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب دسته‌های خودتان را به عنوان بخشی از ورودی، نه به صورت یک برچسب دسته مجزا که روش معمول استفاده از برچسب دسته‌ها در مدل‌های کِراس می‌باشد، ارسال کنید. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینه‌ی درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع هزینه استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. -Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. -
@@ -125,35 +109,17 @@ model.fit( در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغیر متنی برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softmax از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax به آنها اعمال شود به خروجی می‌دهند، که همچنین به عنوان *logits* شناخته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدل‌مان انجام می‌دهد و تنها راه گفتن آن این است که به جای ارسال نام تابع هزینه به صورت متغیر متنی، آن را به صورت مستقیم صدا بزنیم. -Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. - ### بهبود کارایی تعلیم - -### Improving training performance - اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد که و صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. -If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause -is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes -that optimizer with default values for all parameters, including learning rate. From long experience, though, we know -that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written -as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. - علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. -In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate -over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* -the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is -`PolynomialDecay` — despite the name, with default settings it simply linearly decays the learning rate from the initial -value to the final value over the course of training, which is exactly what we want. In order to use a scheduler correctly, -though, we need to tell it how long training is going to be. We compute that as `num_train_steps` below. -
```py @@ -179,14 +145,10 @@ opt = Adam(learning_rate=lr_scheduler) کتابخانه ترنسفورمرهای هاگینگ‌فِیس همچنین یک تابع `create_optimizer()` دارد که بهینه‌سازی از نوع `AdamW`، دارای میزان کاهش نرخ یادگیری می‌سازد. این یک میان‌بر مناسب است که آن‌ را با جزئیات در بخش‌های بعدی این آموزش خواهید دید. -The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. - اکنون بهینه‌ساز کاملا جدیدمان را در اختیار داریم و می‌توانیم آن را تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شده‌اند را به حالت اولیه بازگردانیم، سپس می‌توانیم مدل را با بهینه ساز جدید تدوین کنیم: -Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: -
```py @@ -199,9 +161,7 @@ model.compile(optimizer=opt, loss=loss, metrics=["accuracy"])
-حالا دوباره مدل را تعلیم می‌دهیم: - -Now, we fit again: +حالا دوباره مدل را فیت می‌کنیم:
@@ -213,23 +173,17 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [Chapter 4](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. - -💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) +💡 اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [Chapter 4](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. ### پیش‌بینی‌های مدل -### Model predictions - تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ به برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر کلاس یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. -Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. -
```py @@ -240,8 +194,6 @@ preds = model.predict(tf_validation_dataset)["logits"] سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگ‌ترین `logit`، که نماینده محتمل‌ترین دسته می‌باشد، به پیش‌بینی‌های دسته مدل تبدیل کنیم: -We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: -
```py @@ -261,8 +213,6 @@ print(preds.shape, class_preds.shape) اکنون، اجازه دهید از `preds` برای محاسبه برخی معیارها استفاده کنیم! ما می‌توانیم معیارهای مرتبط با دیتاسِت MRPC را، به همان آسانی که دیتاسِت را بارگذاری کردیم، بارگذاری کنیم اما این بار با استفاده از تابع `load_metric()`. شیء باز گردانده شده تابعی به نام `compute()` دارد که می‌توانیم برای محاسبه معیارها از آن استفاده کنیم: -Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: -
```py @@ -284,10 +234,6 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. -The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. - به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` در فصل ۷ ارائه خواهد شد. اگر مایلید خود را روی `API` کِراس کار آزموده کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, کوک کنید. -This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. -
\ No newline at end of file From 350986fb7a5a1130145aedfcb61c0aad7cf9c85a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:15:07 +0200 Subject: [PATCH 185/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 0d7aea252..bc7a4c0bb 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -234,6 +234,6 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. -به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` در فصل ۷ ارائه خواهد شد. اگر مایلید خود را روی `API` کِراس کار آزموده کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, کوک کنید. +به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` در فصل ۷ ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, کوک کنید.
\ No newline at end of file From 898295e6915c71b8e269bb497d34082ecf64b83c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:15:53 +0200 Subject: [PATCH 186/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index bc7a4c0bb..f5e1f706f 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -234,6 +234,6 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. -به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` در فصل ۷ ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, کوک کنید. +به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, کوک کنید.
\ No newline at end of file From e2ee265bb828907ab889b9477417ccb3d1949a7b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:16:34 +0200 Subject: [PATCH 187/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index f5e1f706f..fe457123c 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -234,6 +234,6 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. -به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ای که در بخش ۲ انجام دادید, کوک کنید. +به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ که در بخش ۲ انجام دادید, کوک کنید.
\ No newline at end of file From 4fd6112ffb354db51667bea7d965a89537bf53ee Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:17:09 +0200 Subject: [PATCH 188/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index fe457123c..71d76fc47 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -234,6 +234,6 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. -به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`, با استفاده از روش پردازش داده‌ که در بخش ۲ انجام دادید, کوک کنید. +به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`، با استفاده از روش پردازش داده‌ که در بخش ۲ انجام دادید، کوک کنید.
\ No newline at end of file From 611b3ca428a4087d7d9361bbf169ac5a75535f17 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:20:03 +0200 Subject: [PATCH 189/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 71d76fc47..c6e573ba7 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -12,7 +12,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter3/section3_tf.ipynb"}, ]} /> -وقتی که شما همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPUها یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. +زمانی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPUها یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: From e7c671de7e02e3c9cd41055010a6dae390ac7af7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:21:19 +0200 Subject: [PATCH 190/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index c6e573ba7..982679336 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -12,7 +12,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter3/section3_tf.ipynb"}, ]} /> -زمانی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPUها یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. +زمانی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: From 541e0fdbb220b8fc780bf8200c7105f83a00cd84 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:23:02 +0200 Subject: [PATCH 191/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 982679336..0e2fafec3 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -61,7 +61,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( -جمله بالا به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار بسیار کمی لازم است تا تعلیم را روی آن شروع کنیم. +این به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار بسیار کمی لازم است تا تعلیم را روی آن شروع کنیم. From 42d214ad8335351514e9c9ed78f8829ab6f35b9a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:27:07 +0200 Subject: [PATCH 192/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 0e2fafec3..5a5a9f45f 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -116,7 +116,7 @@ model.fit( -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد که و صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد که به صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. From 49985766291d8dd03f8c3aceeaa0e0c725344cc5 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:27:56 +0200 Subject: [PATCH 193/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 5a5a9f45f..5cd98f554 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -116,7 +116,7 @@ model.fit( -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد که به صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و به صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. From 41ecfb1c0e439c639b6605042d7cf7857cf31bfd Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:28:55 +0200 Subject: [PATCH 194/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 5cd98f554..76b0fe996 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -118,7 +118,7 @@ model.fit( اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و به صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. -علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. +علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپُختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم.
From 10c311684e0cca9c042f1f2fc8fd5911344ba493 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Fri, 3 Jun 2022 13:31:33 +0200 Subject: [PATCH 195/502] minor fix --- chapters/fa/chapter3/3_tf.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 76b0fe996..9e1b2be95 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -181,7 +181,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ به برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر کلاس یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. +تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر کلاس یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند.
From ab1f91c50ee65531c6b57c887edd4b01a042f4f0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sat, 11 Jun 2022 18:16:20 +0200 Subject: [PATCH 196/502] new file added --- chapters/fa/chapter3/3.mdx | 176 +++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 chapters/fa/chapter3/3.mdx diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx new file mode 100644 index 000000000..5265697e2 --- /dev/null +++ b/chapters/fa/chapter3/3.mdx @@ -0,0 +1,176 @@ + + +
+ +# کوک کردن مدل‌ها با استفاده API تعلیم + +# Fine-tuning a model with the Trainer API + + + + + +🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). + +The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: + +```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) +``` + +### Training + +The first step before we can define our `Trainer` is to define a `TrainingArguments` class that will contain all the hyperparameters the `Trainer` will use for training and evaluation. The only argument you have to provide is a directory where the trained model will be saved, as well as the checkpoints along the way. For all the rest, you can leave the defaults, which should work pretty well for a basic fine-tuning. + +```py +from transformers import TrainingArguments + +training_args = TrainingArguments("test-trainer") +``` + + + +💡 If you want to automatically upload your model to the Hub during training, pass along `push_to_hub=True` in the `TrainingArguments`. We will learn more about this in [Chapter 4](/course/chapter4/3) + + + +The second step is to define our model. As in the [previous chapter](/course/chapter2), we will use the `AutoModelForSequenceClassification` class, with two labels: + +```py +from transformers import AutoModelForSequenceClassification + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. + +Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `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, +) +``` + +Note that when you pass the `tokenizer` as we did here, the default `data_collator` used by the `Trainer` will be a `DataCollatorWithPadding` as defined previously, so you can skip the line `data_collator=data_collator` in this call. It was still important to show you this part of the processing in section 2! + +To fine-tune the model on our dataset, we just have to call the `train()` method of our `Trainer`: + +```py +trainer.train() +``` + +This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: + +1. We didn't tell the `Trainer` to evaluate during training by setting `evaluation_strategy` to either `"steps"` (evaluate every `eval_steps`) or `"epoch"` (evaluate at the end of each epoch). +2. We didn't provide the `Trainer` with a `compute_metrics()` function to calculate a metric during said evaluation (otherwise the evaluation would just have printed the loss, which is not a very intuitive number). + + +### Evaluation + +Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: + +```py +predictions = trainer.predict(tokenized_datasets["validation"]) +print(predictions.predictions.shape, predictions.label_ids.shape) +``` + +```python out +(408, 2) (408,) +``` + +The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. + +As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: + +```py +import numpy as np + +preds = np.argmax(predictions.predictions, axis=-1) +``` + +We can now compare those `preds` to the labels. To build our `compute_metric()` function, we will rely on the metrics from the 🤗 Datasets library. We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: + +```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} +``` + +The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. + +Wrapping everything together, we get our `compute_metrics()` function: + +```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) +``` + +And to see it used in action to report metrics at the end of each epoch, here is how we define a new `Trainer` with this `compute_metrics()` function: + +```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, +) +``` + +Note that we create a new `TrainingArguments` with its `evaluation_strategy` set to `"epoch"` and a new model — otherwise, we would just be continuing the training of the model we have already trained. To launch a new training run, we execute: + +``` +trainer.train() +``` + +This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. + +The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. + +This concludes the introduction to fine-tuning using the `Trainer` API. An example of doing this for most common NLP tasks will be given in [Chapter 7](/course/chapter7), but for now let's look at how to do the same thing in pure PyTorch. + + + +✏️ **Try it out!** Fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. + + + From 76da5dc8221c7d6f7d0b3fb4c0d9b5dba392805f Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 13 Jun 2022 10:39:20 +0200 Subject: [PATCH 197/502] new paragraph added --- chapters/fa/chapter3/3.mdx | 6 +++++- chapters/fa/chapter3/3_tf.mdx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 5265697e2..4ece6177a 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -2,7 +2,7 @@
-# کوک کردن مدل‌ها با استفاده API تعلیم +# کوک کردن مدل‌ها با استفاده از API تعلیم دهنده # Fine-tuning a model with the Trainer API @@ -15,8 +15,12 @@ +ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت آماده‌سازی محیط جهت اجراي `Trainer.train()` می‌تواند باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود.اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. + 🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). +نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: + The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: ```py diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 9e1b2be95..d631cc545 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -12,7 +12,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter3/section3_tf.ipynb"}, ]} /> -زمانی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قیمانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. +زمانی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قی‌مانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: From c34e358c7acad82238e8f6045a48516ae4c643ed Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 13 Jun 2022 10:41:10 +0200 Subject: [PATCH 198/502] right to left span --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 4ece6177a..f372f8b14 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -15,7 +15,7 @@ -ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت آماده‌سازی محیط جهت اجراي `Trainer.train()` می‌تواند باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود.اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. +ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت آماده‌سازی محیط جهت اجراي `Trainer.train()` می‌تواند باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود.اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. 🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). From 8112c47f3955eb42f2db2217a049318ddd15fcb7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 13 Jun 2022 11:10:21 +0200 Subject: [PATCH 199/502] new paragraph added --- chapters/fa/chapter3/3.mdx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index f372f8b14..c6dcecd1d 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -15,7 +15,7 @@ -ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت آماده‌سازی محیط جهت اجراي `Trainer.train()` می‌تواند باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود.اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. +ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت آماده‌سازی محیط جهت اجراي `Trainer.train()` می‌تواند باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود. اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. 🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). @@ -40,8 +40,12 @@ tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) data_collator = DataCollatorWithPadding(tokenizer=tokenizer) ``` +### تعلیم + ### Training +قبل از این که بتوانیم `Trainer` مان را تعریف کنیم اولین مرحله تعریف کلاس `TrainingArguments` می‌باشد که شامل همه پارامترهای سطح بالایی است که `Trainer` برای `Training` و `Evaluation` استفاده خواهد کرد. تنها آرگومانی که شما باید ارائه کنید آدرسی است که مدل تعلیم دیده به همراه نفاط تعلیم در آن ذخیره خواهند شد. بقیه پارامترها را می‌توانید به حالت پیش‌فرض رها کنید، که برای کوک کردن پایه به خوبی کار خواهد کرد. + The first step before we can define our `Trainer` is to define a `TrainingArguments` class that will contain all the hyperparameters the `Trainer` will use for training and evaluation. The only argument you have to provide is a directory where the trained model will be saved, as well as the checkpoints along the way. For all the rest, you can leave the defaults, which should work pretty well for a basic fine-tuning. ```py @@ -52,10 +56,14 @@ training_args = TrainingArguments("test-trainer") +اگر مایلید مدل‌تان را در حین تعلیم در هاب بارگذاری کنید، پارامتر `push_to_hub=True` را در `TrainingArguments` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این باره بیشتر خواهیم آموخت. + 💡 If you want to automatically upload your model to the Hub during training, pass along `push_to_hub=True` in the `TrainingArguments`. We will learn more about this in [Chapter 4](/course/chapter4/3) +مرحله دوم تعریف مدل‌مان می‌باشد. مانند [فصل قبل](/course/chapter2)، از کلاس `AutoModelForSequenceClassification` با دو برچسب کلاس استفاده خواهیم کرد: + The second step is to define our model. As in the [previous chapter](/course/chapter2), we will use the `AutoModelForSequenceClassification` class, with two labels: ```py From 6e5541763b98650bc1d48baa6a20e36fa47a3e36 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 13 Jun 2022 11:16:44 +0200 Subject: [PATCH 200/502] left to right code sections fixed --- chapters/fa/chapter3/3.mdx | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index c6dcecd1d..af01f33c3 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -23,6 +23,8 @@ The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: +
+ ```py from datasets import load_dataset from transformers import AutoTokenizer, DataCollatorWithPadding @@ -40,6 +42,8 @@ tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) data_collator = DataCollatorWithPadding(tokenizer=tokenizer) ``` +
+ ### تعلیم ### Training @@ -48,12 +52,16 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer) The first step before we can define our `Trainer` is to define a `TrainingArguments` class that will contain all the hyperparameters the `Trainer` will use for training and evaluation. The only argument you have to provide is a directory where the trained model will be saved, as well as the checkpoints along the way. For all the rest, you can leave the defaults, which should work pretty well for a basic fine-tuning. +
+ ```py from transformers import TrainingArguments training_args = TrainingArguments("test-trainer") ``` +
+ اگر مایلید مدل‌تان را در حین تعلیم در هاب بارگذاری کنید، پارامتر `push_to_hub=True` را در `TrainingArguments` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این باره بیشتر خواهیم آموخت. @@ -66,16 +74,22 @@ training_args = TrainingArguments("test-trainer") The second step is to define our model. As in the [previous chapter](/course/chapter2), we will use the `AutoModelForSequenceClassification` class, with two labels: +
+ ```py from transformers import AutoModelForSequenceClassification model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` +
+ You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: +
+ ```py from transformers import Trainer @@ -89,14 +103,20 @@ trainer = Trainer( ) ``` +
+ Note that when you pass the `tokenizer` as we did here, the default `data_collator` used by the `Trainer` will be a `DataCollatorWithPadding` as defined previously, so you can skip the line `data_collator=data_collator` in this call. It was still important to show you this part of the processing in section 2! To fine-tune the model on our dataset, we just have to call the `train()` method of our `Trainer`: +
+ ```py trainer.train() ``` +
+ This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: 1. We didn't tell the `Trainer` to evaluate during training by setting `evaluation_strategy` to either `"steps"` (evaluate every `eval_steps`) or `"epoch"` (evaluate at the end of each epoch). @@ -107,6 +127,8 @@ This will start the fine-tuning (which should take a couple of minutes on a GPU) Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: +
+ ```py predictions = trainer.predict(tokenized_datasets["validation"]) print(predictions.predictions.shape, predictions.label_ids.shape) @@ -116,18 +138,26 @@ print(predictions.predictions.shape, predictions.label_ids.shape) (408, 2) (408,) ``` +
+ The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: +
+ ```py import numpy as np preds = np.argmax(predictions.predictions, axis=-1) ``` +
+ We can now compare those `preds` to the labels. To build our `compute_metric()` function, we will rely on the metrics from the 🤗 Datasets library. We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: +
+ ```py from datasets import load_metric @@ -139,10 +169,14 @@ metric.compute(predictions=preds, references=predictions.label_ids) {'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} ``` +
+ The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. Wrapping everything together, we get our `compute_metrics()` function: +
+ ```py def compute_metrics(eval_preds): metric = load_metric("glue", "mrpc") @@ -151,8 +185,12 @@ def compute_metrics(eval_preds): return metric.compute(predictions=predictions, references=labels) ``` +
+ And to see it used in action to report metrics at the end of each epoch, here is how we define a new `Trainer` with this `compute_metrics()` function: +
+ ```py training_args = TrainingArguments("test-trainer", evaluation_strategy="epoch") model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) @@ -168,12 +206,18 @@ trainer = Trainer( ) ``` +
+ Note that we create a new `TrainingArguments` with its `evaluation_strategy` set to `"epoch"` and a new model — otherwise, we would just be continuing the training of the model we have already trained. To launch a new training run, we execute: +
+ ``` trainer.train() ``` +
+ This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. From b5f9674376ccee15f33e9bdf7955fd58ac0703e0 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 13 Jun 2022 17:39:32 +0200 Subject: [PATCH 201/502] two new paragraphs added --- chapters/fa/chapter3/3.mdx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index af01f33c3..9e85d59ed 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -84,8 +84,13 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label
+ +شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان کاری است که می‌خواهیم اکنون انجام دهیم. + You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `model`، training دیتاسِت‌های validation و `data_collator`مان `training_args` و توکِنایزرمان به آن تعریف کنیم: + Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`:
From 33e599477184054277b282d790bf694a6478f2b3 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 13 Jun 2022 17:44:33 +0200 Subject: [PATCH 202/502] minor sentence structure fixed --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 9e85d59ed..65cd3843e 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `model`، training دیتاسِت‌های validation و `data_collator`مان `training_args` و توکِنایزرمان به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator و توکِنایزرمان به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 6480710ca8c4d7286454ec736c2efbc627835e2c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 13 Jun 2022 17:46:17 +0200 Subject: [PATCH 203/502] minor sentence structure fixed --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 65cd3843e..56cc6ca10 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator و توکِنایزرمان به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator` و توکِنایزرمان به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 631312fe19e30b136edab38ed7b26bb8ee929f35 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Mon, 13 Jun 2022 19:44:05 +0200 Subject: [PATCH 204/502] new paragraphs added --- chapters/fa/chapter3/3.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 56cc6ca10..f585ef1ca 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -110,8 +110,12 @@ trainer = Trainer(
+توجه داشته باشید زمانی که `tokenizer` را ارسال می‌کنید، همانطور که ما در اینجا انجام دادیم، `data_collator` پیش‌فرض مورد استفاده `Trainer` `DataCollatorWithPadding` خواهد بود، همانطور که قبلا تعریف کردیم، پس شما می‌توانید خط `data_collator=data_collator` را در این صدا کردن نادیده بگیرید. + Note that when you pass the `tokenizer` as we did here, the default `data_collator` used by the `Trainer` will be a `DataCollatorWithPadding` as defined previously, so you can skip the line `data_collator=data_collator` in this call. It was still important to show you this part of the processing in section 2! +برای کوک کردن مدل روی دیتاسِت‌مان ما فقط باید تابع `train()` از `Trainer`مان را صدا بزنیم: + To fine-tune the model on our dataset, we just have to call the `train()` method of our `Trainer`:
From 04eac7793aff1aa07e52d829f3835275f1e0e66b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 14 Jun 2022 19:16:07 +0200 Subject: [PATCH 205/502] new paragraph added --- chapters/fa/chapter3/3.mdx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index f585ef1ca..97263239a 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -126,8 +126,13 @@ trainer.train()
+این کار کوک کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و خطای تعلیم را هر ۵۰۰ مرحله یکبار گزارش می‌کند. با این حال به شما نمی‌گوید که مدل‌تان چقدر خوب (یا بد) عمل می‌کند. این به این خاطر است که: + This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: +۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با تنظیم پارامتر `evaluation_strategy` به `"steps"` (جهت ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر ایپاک) +۲. ما تابع `compute_metrics()` را جهت محاسبه معیارها در حین اصطلاحا ارزیابی (که در غیر این صورت فقط هزینه، که عدد چندان گویایی هم نیست، را چاپ می‌کرد) برای `Trainer` فراهم نکردیم. + 1. We didn't tell the `Trainer` to evaluate during training by setting `evaluation_strategy` to either `"steps"` (evaluate every `eval_steps`) or `"epoch"` (evaluate at the end of each epoch). 2. We didn't provide the `Trainer` with a `compute_metrics()` function to calculate a metric during said evaluation (otherwise the evaluation would just have printed the loss, which is not a very intuitive number). From 0cd3a2f1dbb98fd9b7b81b743d0a6ff5559a1458 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 14 Jun 2022 19:19:42 +0200 Subject: [PATCH 206/502] fixed typose --- chapters/fa/chapter3/3.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 97263239a..3960428f6 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -126,11 +126,12 @@ trainer.train()
-این کار کوک کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و خطای تعلیم را هر ۵۰۰ مرحله یکبار گزارش می‌کند. با این حال به شما نمی‌گوید که مدل‌تان چقدر خوب (یا بد) عمل می‌کند. این به این خاطر است که: +این کار کوک کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و هزینه تعلیم را هر ۵۰۰ مرحله یکبار گزارش می‌کند. با این حال به شما نمی‌گوید که مدل‌تان چقدر خوب (یا بد) عمل می‌کند. این به این خاطر است که: This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: -۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با تنظیم پارامتر `evaluation_strategy` به `"steps"` (جهت ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر ایپاک) +۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با تنظیم پارامتر `evaluation_strategy` به `"steps"` (جهت ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر ایپاک) انجام دهیم. + ۲. ما تابع `compute_metrics()` را جهت محاسبه معیارها در حین اصطلاحا ارزیابی (که در غیر این صورت فقط هزینه، که عدد چندان گویایی هم نیست، را چاپ می‌کرد) برای `Trainer` فراهم نکردیم. 1. We didn't tell the `Trainer` to evaluate during training by setting `evaluation_strategy` to either `"steps"` (evaluate every `eval_steps`) or `"epoch"` (evaluate at the end of each epoch). From 2e60166a86da6c665d50eec44ec4764566c09435 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 14 Jun 2022 19:28:52 +0200 Subject: [PATCH 207/502] new paragraph added --- chapters/fa/chapter3/3.mdx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 3960428f6..7ad5ca092 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -130,7 +130,7 @@ trainer.train() This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: -۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با تنظیم پارامتر `evaluation_strategy` به `"steps"` (جهت ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر ایپاک) انجام دهیم. +۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با مقداردهی پارامتر `evaluation_strategy` به `"steps"` (جهت ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر ایپاک) انجام دهیم. ۲. ما تابع `compute_metrics()` را جهت محاسبه معیارها در حین اصطلاحا ارزیابی (که در غیر این صورت فقط هزینه، که عدد چندان گویایی هم نیست، را چاپ می‌کرد) برای `Trainer` فراهم نکردیم. @@ -138,8 +138,12 @@ This will start the fine-tuning (which should take a couple of minutes on a GPU) 2. We didn't provide the `Trainer` with a `compute_metrics()` function to calculate a metric during said evaluation (otherwise the evaluation would just have printed the loss, which is not a very intuitive number). +### ارزیابی + ### Evaluation +اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids` و دیکشنری باز می‌گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (که رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). + Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command:
From 272dcccda470cf7119720831cc804883f4cff0db Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 14 Jun 2022 19:29:37 +0200 Subject: [PATCH 208/502] fixed typose --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 7ad5ca092..2fe856fd3 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -142,7 +142,7 @@ This will start the fine-tuning (which should take a couple of minutes on a GPU) ### Evaluation -اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids` و دیکشنری باز می‌گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (که رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). +اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids` و دیکشنری باز می‌گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (که رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: From e5389cc183b00ff3336dbe1eed50f9b1d161e684 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 14 Jun 2022 19:31:02 +0200 Subject: [PATCH 209/502] fixed typose --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 2fe856fd3..e4b979802 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -142,7 +142,7 @@ This will start the fine-tuning (which should take a couple of minutes on a GPU) ### Evaluation -اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids` و دیکشنری باز می‌گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (که رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). +اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids`) و دیکشنری باز گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (که رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: From cfe895878adaa2b7ed2afb69dd19a2b925535084 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 14 Jun 2022 19:33:45 +0200 Subject: [PATCH 210/502] fixed typose --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index e4b979802..1f12e86c2 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -142,7 +142,7 @@ This will start the fine-tuning (which should take a couple of minutes on a GPU) ### Evaluation -اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids`) و دیکشنری باز گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (که رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). +اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids`) و دیکشنری باز گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (که رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). برای استخراج چند پیش‌بینی‌ از مدل‌مان، می‌توانیم از دستور `Trainer.predict()` استفاده کنیم: Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: From 0e614ca0258a04e633f3bdf4e4f14ff4b8833633 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 14 Jun 2022 19:40:28 +0200 Subject: [PATCH 211/502] new paragraph added --- chapters/fa/chapter3/3.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 1f12e86c2..aaf335232 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -159,6 +159,8 @@ print(predictions.predictions.shape, predictions.label_ids.shape)
+خروجی تابع --- تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (در مجموع و به طور میانگین پیش‌بینی‌ چقدر طول کشید) می‌باشد. + The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: From b4dad8abb49b1b00c22afe36da9d47a592319de7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 19 Jun 2022 12:48:41 +0200 Subject: [PATCH 212/502] new paragraphs added --- chapters/fa/chapter3/3.mdx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index aaf335232..dc5ce898e 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -159,10 +159,12 @@ print(predictions.predictions.shape, predictions.label_ids.shape)
-خروجی تابع --- تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (در مجموع و به طور میانگین پیش‌بینی‌ چقدر طول کشید) می‌باشد. +خروجی تابع `predict()` تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (در مجموع و به طور میانگین پیش‌بینی‌ چقدر طول کشیده) می‌باشد. به محض این که تابع `compute_metrics()` را کامل کرده و آنرا به `Trainer` ارسال کردیم، آن فیلد متریک‌های بازگشتی از `compute_metrics()` را نیز در بر خواهد داشت. The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. +همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مرود استفاده‌مان می‌باشد). این ها لاجیت‌های هر عنصر دیتاسِتی هستند که به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌ها که بتوانیم با برچسب‌هایمان مقایسه کنیم، ما لازم داریم که اندیس مقدار بیشینه رود محور دوم را برداریم: + As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis:
@@ -175,6 +177,8 @@ preds = np.argmax(predictions.predictions, axis=-1)
+اکنون می‌توانیم آن `preds`ها را با برچسب‌ها مقایسه کنیم. برای ساختن تابع `compute_metric()`مان، به متریک‌های کتابخانه داده‌های هاگینگ‌فِیس تکیه خواهیم کرد. ما می‌توانیم متریک های وابسته به دیتاسِت MRPC را به همان راحتی خود دیتاسِت بارگذاری کنیم، این بار با استفاده از تابع `load_metric()`. شیء بازگردانده شده تابعی به نام `compute()` دارد که می‌توانیم برای محاسبه متریک از آن استفاده کنیم: + We can now compare those `preds` to the labels. To build our `compute_metric()` function, we will rely on the metrics from the 🤗 Datasets library. We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation:
From 8ff8d2d82fc4ad9039eccd08787752abba4d2f45 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 19 Jun 2022 12:56:43 +0200 Subject: [PATCH 213/502] fixed typose --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index dc5ce898e..dc9c1086f 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -177,7 +177,7 @@ preds = np.argmax(predictions.predictions, axis=-1)
-اکنون می‌توانیم آن `preds`ها را با برچسب‌ها مقایسه کنیم. برای ساختن تابع `compute_metric()`مان، به متریک‌های کتابخانه داده‌های هاگینگ‌فِیس تکیه خواهیم کرد. ما می‌توانیم متریک های وابسته به دیتاسِت MRPC را به همان راحتی خود دیتاسِت بارگذاری کنیم، این بار با استفاده از تابع `load_metric()`. شیء بازگردانده شده تابعی به نام `compute()` دارد که می‌توانیم برای محاسبه متریک از آن استفاده کنیم: +اکنون می‌توانیم `preds` را با برچسب‌ها مقایسه کنیم. برای ساختن تابع `compute_metric()`، به متریک‌های کتابخانه داده‌های هاگینگ‌فِیس تکیه خواهیم کرد. ما می‌توانیم متریک‌های وابسته به دیتاسِت MRPC را به راحتی خود دیتاسِت، اما این بار با استفاده از تابع `load_metric()`، بارگذاری کنیم. شیء بازگردانده شده تابعی به نام `compute()` دارد که می‌توانیم برای محاسبه متریک از آن استفاده کنیم: We can now compare those `preds` to the labels. To build our `compute_metric()` function, we will rely on the metrics from the 🤗 Datasets library. We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: From 832d5c554d0ef3554311f9de814fba50b7766029 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 19 Jun 2022 13:01:16 +0200 Subject: [PATCH 214/502] fixed typose --- chapters/fa/chapter3/3.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index dc9c1086f..91957bc35 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -159,11 +159,11 @@ print(predictions.predictions.shape, predictions.label_ids.shape)
-خروجی تابع `predict()` تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (در مجموع و به طور میانگین پیش‌بینی‌ چقدر طول کشیده) می‌باشد. به محض این که تابع `compute_metrics()` را کامل کرده و آنرا به `Trainer` ارسال کردیم، آن فیلد متریک‌های بازگشتی از `compute_metrics()` را نیز در بر خواهد داشت. +خروجی تابع `predict()` تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (در مجموع و به طور میانگین پیش‌بینی‌ چقدر طول کشیده) می‌باشد. به محض این که تابع `compute_metrics()` را کامل کرده و آنرا به `Trainer` ارسال کنیم، آن فیلد متریک‌های بازگشتی از `compute_metrics()` را نیز در بر خواهد داشت. The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. -همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مرود استفاده‌مان می‌باشد). این ها لاجیت‌های هر عنصر دیتاسِتی هستند که به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌ها که بتوانیم با برچسب‌هایمان مقایسه کنیم، ما لازم داریم که اندیس مقدار بیشینه رود محور دوم را برداریم: +همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مرود استفاده‌مان می‌باشد). این ها لاجیت‌های هر عنصر دیتاسِتی هستند که به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌ها که بتوانیم با برچسب‌هایمان مقایسه کنیم، ما لازم داریم که اندیس مقدار بیشینه رود محور دوم را برداریم: As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: From f4883d80e47a8a2f9966165584037c9c5c211f04 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 19 Jun 2022 13:04:14 +0200 Subject: [PATCH 215/502] fixed typose --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 91957bc35..523d62968 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -163,7 +163,7 @@ print(predictions.predictions.shape, predictions.label_ids.shape) The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. -همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مرود استفاده‌مان می‌باشد). این ها لاجیت‌های هر عنصر دیتاسِتی هستند که به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌ها که بتوانیم با برچسب‌هایمان مقایسه کنیم، ما لازم داریم که اندیس مقدار بیشینه رود محور دوم را برداریم: +همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هر عنصر دیتاسِتی هستند که به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌ها که بتوانیم با برچسب‌هایمان مقایسه کنیم، ما لازم داریم که اندیس مقدار بیشینه رود محور دوم را برداریم: As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: From c38c6296aa7ec7f98bfff355a5bcc4844012e008 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 19 Jun 2022 13:05:06 +0200 Subject: [PATCH 216/502] fixed typose --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 523d62968..c0f513cb8 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -163,7 +163,7 @@ print(predictions.predictions.shape, predictions.label_ids.shape) The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. -همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هر عنصر دیتاسِتی هستند که به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌ها که بتوانیم با برچسب‌هایمان مقایسه کنیم، ما لازم داریم که اندیس مقدار بیشینه رود محور دوم را برداریم: +همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌ها که بتوانیم با برچسب‌هایمان مقایسه کنیم، ما لازم داریم که اندیس مقدار بیشینه رود محور دوم را برداریم: As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: From c43a5c12987ae64338dd67818d65790ea70ccc29 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 19 Jun 2022 13:06:40 +0200 Subject: [PATCH 217/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index c0f513cb8..b3c26e49c 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -163,7 +163,7 @@ print(predictions.predictions.shape, predictions.label_ids.shape) The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. -همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌ها که بتوانیم با برچسب‌هایمان مقایسه کنیم، ما لازم داریم که اندیس مقدار بیشینه رود محور دوم را برداریم: +همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی محور دوم را برداریم: As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: From 08fa6b8d6e4a8d998dcc1545706219e1ab6b9b26 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Sun, 19 Jun 2022 13:07:50 +0200 Subject: [PATCH 218/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index b3c26e49c..7b943d1ed 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -163,7 +163,7 @@ print(predictions.predictions.shape, predictions.label_ids.shape) The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. -همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی محور دوم را برداریم: +همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی بعد دوم را برداریم: As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: From 66ef657d196f1286f1d367b92dace840bcc4baad Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 21 Jun 2022 13:05:18 +0200 Subject: [PATCH 219/502] new paragraphs added --- chapters/fa/chapter3/3.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 7b943d1ed..99a67cba0 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -196,8 +196,12 @@ metric.compute(predictions=preds, references=predictions.label_ids)
+از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا میتوانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` دارد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در [مقاله BERT](https://arxiv.org/pdf/1810.04805.pdf) `F1 Score` معادل ۸۸.۹ را برای مدل پایه گزارش می‌کند. آن مدل `uncased` بود، حال اینکه ما در اینجا از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. + The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. +با قرار دادن همه چیز کنارهم تابع `compute_metrics()` را بدست خواهیم آورد: + Wrapping everything together, we get our `compute_metrics()` function:
@@ -212,6 +216,8 @@ def compute_metrics(eval_preds):
+و در اینجا نشان می‌دهیم که چگونه یک `Trainer` جدید با استفاده از تابع `compute_metrics()` تعریف می‌کنیم، که ببینیم چگونه در عمل برای گزارش متریک‌های در پایان هر epoch مورد استفاده قرار می‌گیرد: + And to see it used in action to report metrics at the end of each epoch, here is how we define a new `Trainer` with this `compute_metrics()` function:
From 5fa39b32d1a7184e7fe3b1534154671f5ce90c16 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 21 Jun 2022 13:11:42 +0200 Subject: [PATCH 220/502] fixed wording --- chapters/fa/chapter3/3.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 99a67cba0..f39c7d3a5 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -196,11 +196,11 @@ metric.compute(predictions=preds, references=predictions.label_ids)
-از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا میتوانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` دارد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در [مقاله BERT](https://arxiv.org/pdf/1810.04805.pdf) `F1 Score` معادل ۸۸.۹ را برای مدل پایه گزارش می‌کند. آن مدل `uncased` بود، حال اینکه ما در اینجا از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. +از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf) `F1 Score` معادل ۸۸.۹ را برای مدل پایه گزارش می‌کند. توجه داشته باشید که آن مدل `uncased` بود، حال این که در اینجا ما از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. -با قرار دادن همه چیز کنارهم تابع `compute_metrics()` را بدست خواهیم آورد: +اکنون با قرار دادن همه چیز کنارهم تابع `compute_metrics()` را بدست خواهیم آورد: Wrapping everything together, we get our `compute_metrics()` function: @@ -216,7 +216,7 @@ def compute_metrics(eval_preds):
-و در اینجا نشان می‌دهیم که چگونه یک `Trainer` جدید با استفاده از تابع `compute_metrics()` تعریف می‌کنیم، که ببینیم چگونه در عمل برای گزارش متریک‌های در پایان هر epoch مورد استفاده قرار می‌گیرد: +و در اینجا نشان می‌دهیم که چگونه یک `Trainer` جدید با استفاده از تابع `compute_metrics()` تعریف می‌کنیم تا عملکرد آنرا در حین گزارش متریک‌ها در پایان هر epoch مشاهده کنیم: And to see it used in action to report metrics at the end of each epoch, here is how we define a new `Trainer` with this `compute_metrics()` function: From 6a432e4383061e8cc027cc1f696aacf11b780d3f Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Tue, 21 Jun 2022 13:15:23 +0200 Subject: [PATCH 221/502] fixed ltr --- chapters/fa/chapter3/3.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index f39c7d3a5..f6147f94e 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -196,7 +196,7 @@ metric.compute(predictions=preds, references=predictions.label_ids)
-از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf) `F1 Score` معادل ۸۸.۹ را برای مدل پایه گزارش می‌کند. توجه داشته باشید که آن مدل `uncased` بود، حال این که در اینجا ما از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. +از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، برای مدل پایه `F1 Score` معادل ۸۸.۹ را گزارش می‌کند. توجه داشته باشید که آن مدل `uncased` بود، حال این که در اینجا ما از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. @@ -216,7 +216,7 @@ def compute_metrics(eval_preds): -و در اینجا نشان می‌دهیم که چگونه یک `Trainer` جدید با استفاده از تابع `compute_metrics()` تعریف می‌کنیم تا عملکرد آنرا در حین گزارش متریک‌ها در پایان هر epoch مشاهده کنیم: +و در اینجا نشان می‌دهیم که چگونه یک `Trainer` جدید با استفاده از تابع `compute_metrics()` تعریف می‌کنیم، تا بتوانیم عملکرد آن را در حین گزارش متریک‌ها در پایان هر epoch مشاهده کنیم: And to see it used in action to report metrics at the end of each epoch, here is how we define a new `Trainer` with this `compute_metrics()` function: From df6e86f318eb75b7c0ad3807e4591ee1cf7ee893 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 09:41:18 +0200 Subject: [PATCH 222/502] new paragraphs added --- chapters/fa/chapter3/3.mdx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index f6147f94e..694d64762 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -2,7 +2,7 @@
-# کوک کردن مدل‌ها با استفاده از API تعلیم دهنده +# کوک کردن مدل‌ها با استفاده از API `Trainer` # Fine-tuning a model with the Trainer API @@ -239,6 +239,8 @@ trainer = Trainer(
+توجه داشته باشید که ما مدلی جدید و `TrainingArguments` جدیدی که `evaluation_strategy` آن `"epoch"` ست شده است می‌سازیم - در غیر این صورت فقط تعلیم مدلی را ادامه می‌دادیم که از تعلیم دیده بود. دستور زیر را برای راه‌اندازی دور جدید تعلیم اجرا می‌کنیم: + Note that we create a new `TrainingArguments` with its `evaluation_strategy` set to `"epoch"` and a new model — otherwise, we would just be continuing the training of the model we have already trained. To launch a new training run, we execute:
@@ -249,14 +251,22 @@ trainer.train()
+این بار هزینه validation و متریک‌ها را در پایان هر epoch و در بالای هزینه تعلیم گزارش می‌کنیم. دوباره، به خاطر مقدار دهی تصادفی اولیه لایه سر مدل، مقادیر دقیق accuracy/F1 score که شما بدست می‌آورید ممکن است کمی متفاوت از آنچه ما بدست آورده‌ایم باشد، اما این مقادیر باید در محدوده تخمینی یکسانی باشند. + This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. +`Trainer` به صورت پیش فرض روی چندین GPU یا TPU کار خواهد کرد و گزینه‌های فراوانی، مثل تعلیم mixed-precision (از مقدار `fp16 = True` در آرگومان‌های تعلیم استفاده کنید) فراهم می‌کند. در فصل ۱۰ همه حالت‌هایی که پشتیبانی می‌کند را مرور خواهیم کرد. + The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. +این پایان مقدمه‌ای بر کوک کردن با استفاده از `Trainer` API می‌باشد. در [فصل ۷](/course/chapter7) مثالی برای نشان دادن چگونگی انجام این کار برای معمول‌ترین مسئله‌های NLP ارائه خواهیم کرد، اما اکنون اجازه دهید ببینیم چگونه همین کار را صرفا با استفاده از PyTorch انجام دهیم. + This concludes the introduction to fine-tuning using the `Trainer` API. An example of doing this for most common NLP tasks will be given in [Chapter 7](/course/chapter7), but for now let's look at how to do the same thing in pure PyTorch. +✏️ **اتحان کنید!** با استفاده از پردازش داده‌ای که در بخش ۲ انجام دادی، مدلی را روی دیتاسِت GLUE SST-2 کوک کنید، + ✏️ **Try it out!** Fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. From 83bb189100dbaebd405037fe8a4a597e31d1c139 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 09:45:05 +0200 Subject: [PATCH 223/502] fixed sentece wording and structure --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 694d64762..ad6f7747d 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -15,7 +15,7 @@ -ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت آماده‌سازی محیط جهت اجراي `Trainer.train()` می‌تواند باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود. اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. +ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت، احتمالا آماده‌سازی محیط جهت اجراي `Trainer.train()` باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود. اگر GPU ندارید، می‌توانید از GPU یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. 🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). From b0d38c0aaaad0969d7c3a7980bfdc30e279b610d Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 09:51:54 +0200 Subject: [PATCH 224/502] fixed sentece wording and structure --- chapters/fa/chapter3/3.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index ad6f7747d..926521fd3 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -15,7 +15,7 @@ -ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت، احتمالا آماده‌سازی محیط جهت اجراي `Trainer.train()` باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود. اگر GPU ندارید، می‌توانید از GPU یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. +ترنسفورمرهای هاگینگ‌فِیس کلاسی به نام `Trainer` دارند که برای کمک به کوک کردن هر مدل از پیش تعلیم دیده‌ای که روی داده شما ارائه می‌دهد به کار می‌رود. به محض اینکه همه کارهای پیش‌پردازش داده در بخش آخر را انجام دادید، فقط چند مرحله باقی‌مانده تا تعریف `Trainer` دارید. سخت ترین قسمت، احتمالا آماده‌سازی محیط جهت اجراي `Trainer.train()` می‌باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود. اگر GPU ندارید، می‌توانید از GPU یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. 🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). @@ -48,7 +48,7 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer) ### Training -قبل از این که بتوانیم `Trainer` مان را تعریف کنیم اولین مرحله تعریف کلاس `TrainingArguments` می‌باشد که شامل همه پارامترهای سطح بالایی است که `Trainer` برای `Training` و `Evaluation` استفاده خواهد کرد. تنها آرگومانی که شما باید ارائه کنید آدرسی است که مدل تعلیم دیده به همراه نفاط تعلیم در آن ذخیره خواهند شد. بقیه پارامترها را می‌توانید به حالت پیش‌فرض رها کنید، که برای کوک کردن پایه به خوبی کار خواهد کرد. +قبل از این که بتوانیم `Trainer` مان را تعریف کنیم اولین مرحله تعریف کلاس `TrainingArguments` می‌باشد که شامل همه پارامترهای سطح بالایی است که `Trainer` برای `Training` و `Evaluation` استفاده خواهد کرد. تنها آرگومانی که شما باید ارائه کنید آدرسی است که مدل تعلیم دیده به همراه نقاط تعلیم در آن ذخیره خواهند شد. بقیه پارامترها را می‌توانید به حالت پیش‌فرض رها کنید، که برای کوک کردن پایه به خوبی کار خواهد کرد. The first step before we can define our `Trainer` is to define a `TrainingArguments` class that will contain all the hyperparameters the `Trainer` will use for training and evaluation. The only argument you have to provide is a directory where the trained model will be saved, as well as the checkpoints along the way. For all the rest, you can leave the defaults, which should work pretty well for a basic fine-tuning. @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator` و توکِنایزرمان به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `training_args`، `model`، دیتاسِت‌های `training` و `validation`، `data_collator` و توکِنایزرمان به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 92e0e5ccdba5050474ed1621c999336a6a630b00 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 09:53:44 +0200 Subject: [PATCH 225/502] fixed sentece wording and structure --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 926521fd3..3de86e7d0 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `training_args`، `model`، دیتاسِت‌های `training` و `validation`، `data_collator` و توکِنایزرمان به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `training_args`، `model`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From e130d699017107cb250d5a49ad2f5b50f77a54c9 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 09:55:17 +0200 Subject: [PATCH 226/502] fixed sentece wording and structure --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 3de86e7d0..4fc57e4ef 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `training_args`، `model`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `training_args`، `model`، دیتاسِت‌های `training` و `validation`, `data_collator` و `tokenizer` به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 4fa5e7e6cdfd92a5cf0b921e1a2a7bb8fb164d0d Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 09:58:02 +0200 Subject: [PATCH 227/502] fixed ltr --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 4fc57e4ef..63725cf2b 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `training_args`، `model`، دیتاسِت‌های `training` و `validation`, `data_collator` و `tokenizer` به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `training_args`، `model`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 410c43dd2c058eb934aafdd6916223e8f5e7f050 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:00:31 +0200 Subject: [PATCH 228/502] fixed ltr --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 63725cf2b..b016309f8 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند شامل `training_args`، `model`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `training_args`، `model`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From fef307f91f10f789080dfbabc4d5ec2ff45c1d05 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:03:39 +0200 Subject: [PATCH 229/502] fixed ltr --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index b016309f8..857851566 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `training_args`، `model`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 8ff9f08469ca5827d03b3aa44746ba9f5a375365 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:04:43 +0200 Subject: [PATCH 230/502] fixed ltr --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 857851566..a0513d9eb 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به آن تعریف کنیم: +با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `validation` و `training`، `data_collator` و `tokenizer` به آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 4ca6047aeb55a3c37147546b285da85826d2369b Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:07:28 +0200 Subject: [PATCH 231/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index a0513d9eb..8c2504aaf 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -با داشتن مدل، ما می‌توانیم `Trainer`ای را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `validation` و `training`، `data_collator` و `tokenizer` به آن تعریف کنیم: +به محض اینکه مدل‌مان مشخص شد می‌توانیم `Trainer` را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `validation` و `training`، `data_collator` و `tokenizer` به داخل آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 860ed2800d74b085d0f67a8836db40d434442f42 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:09:00 +0200 Subject: [PATCH 232/502] fixed ltr --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 8c2504aaf..5f16244ef 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -89,7 +89,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -به محض اینکه مدل‌مان مشخص شد می‌توانیم `Trainer` را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `validation` و `training`، `data_collator` و `tokenizer` به داخل آن تعریف کنیم: +به محض اینکه مدل‌مان مشخص شد می‌توانیم `Trainer` را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به داخل آن تعریف کنیم: Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: From 87ec5754c044362d79baad9bd8c1bbd93bba8bd9 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:11:40 +0200 Subject: [PATCH 233/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 5f16244ef..c5e878c4a 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -110,7 +110,7 @@ trainer = Trainer( -توجه داشته باشید زمانی که `tokenizer` را ارسال می‌کنید، همانطور که ما در اینجا انجام دادیم، `data_collator` پیش‌فرض مورد استفاده `Trainer` `DataCollatorWithPadding` خواهد بود، همانطور که قبلا تعریف کردیم، پس شما می‌توانید خط `data_collator=data_collator` را در این صدا کردن نادیده بگیرید. +توجه داشته باشید زمانی که `tokenizer` را ارسال می‌کنید، همانطور که ما در اینجا انجام دادیم، `data_collator` پیش‌فرض مورد استفاده `Trainer` `DataCollatorWithPadding` خواهد بود، همانطور که قبلا تعریف کردیم، در تنیجه شما می‌توانید خط `data_collator=data_collator` را در این فراخوانی نادیده بگیرید. Note that when you pass the `tokenizer` as we did here, the default `data_collator` used by the `Trainer` will be a `DataCollatorWithPadding` as defined previously, so you can skip the line `data_collator=data_collator` in this call. It was still important to show you this part of the processing in section 2! From a5729aa3c9fdef6376dbcdbecfd5c51986d3b3c7 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:16:12 +0200 Subject: [PATCH 234/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index c5e878c4a..7800043d0 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -110,7 +110,7 @@ trainer = Trainer( -توجه داشته باشید زمانی که `tokenizer` را ارسال می‌کنید، همانطور که ما در اینجا انجام دادیم، `data_collator` پیش‌فرض مورد استفاده `Trainer` `DataCollatorWithPadding` خواهد بود، همانطور که قبلا تعریف کردیم، در تنیجه شما می‌توانید خط `data_collator=data_collator` را در این فراخوانی نادیده بگیرید. +توجه داشته باشید زمانی که `tokenizer` را ارسال می‌کنید، مثل کاری که ما در اینجا انجام دادیم، `data_collator` پیش‌فرض مورد استفاده `Trainer`، همانطور که قبلا تعریف کردیم، `DataCollatorWithPadding` خواهد بود، در تنیجه شما می‌توانید خط `data_collator=data_collator` را در این فراخوانی نادیده بگیرید. Note that when you pass the `tokenizer` as we did here, the default `data_collator` used by the `Trainer` will be a `DataCollatorWithPadding` as defined previously, so you can skip the line `data_collator=data_collator` in this call. It was still important to show you this part of the processing in section 2! From dfe8a8d19a3b641e802a1c402936919842a41e90 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:18:49 +0200 Subject: [PATCH 235/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 7800043d0..9000da2bf 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -130,7 +130,7 @@ trainer.train() This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: -۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با مقداردهی پارامتر `evaluation_strategy` به `"steps"` (جهت ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر ایپاک) انجام دهیم. +۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با مقداردهی پارامتر `evaluation_strategy` به `"steps"` (جهت ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر epoch) انجام دهیم. ۲. ما تابع `compute_metrics()` را جهت محاسبه معیارها در حین اصطلاحا ارزیابی (که در غیر این صورت فقط هزینه، که عدد چندان گویایی هم نیست، را چاپ می‌کرد) برای `Trainer` فراهم نکردیم. From 9ab029ba4e75333a624e8ec8bd2fa17d97f54366 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:44:17 +0200 Subject: [PATCH 236/502] fixed wording --- chapters/fa/chapter3/3.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 9000da2bf..e4f4067ad 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -126,13 +126,13 @@ trainer.train() -این کار کوک کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و هزینه تعلیم را هر ۵۰۰ مرحله یکبار گزارش می‌کند. با این حال به شما نمی‌گوید که مدل‌تان چقدر خوب (یا بد) عمل می‌کند. این به این خاطر است که: +این کار، کوک کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و هزینه تعلیم را هر ۵۰۰ مرحله یک‌بار گزارش می‌کند. با این حال به شما نمی‌گوید که مدل‌تان چقدر خوب (یا بد) عمل می‌کند. این به این خاطر است که: This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: -۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با مقداردهی پارامتر `evaluation_strategy` به `"steps"` (جهت ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر epoch) انجام دهیم. +۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با مقداردهی پارامتر `evaluation_strategy` به `"steps"` (برای ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر epoch) انجام دهیم. -۲. ما تابع `compute_metrics()` را جهت محاسبه معیارها در حین اصطلاحا ارزیابی (که در غیر این صورت فقط هزینه، که عدد چندان گویایی هم نیست، را چاپ می‌کرد) برای `Trainer` فراهم نکردیم. +۲. ما تابع `compute_metrics()` را برای `Trainer` فراهم نکردیم تا بتواند معیارها را در حین اصطلاحا ارزیابی محاسبه کند (که در غیر این صورت، ارزیابی فقط هزینه را چاپ می‌کند که عدد چندان گویایی هم نیست) . 1. We didn't tell the `Trainer` to evaluate during training by setting `evaluation_strategy` to either `"steps"` (evaluate every `eval_steps`) or `"epoch"` (evaluate at the end of each epoch). 2. We didn't provide the `Trainer` with a `compute_metrics()` function to calculate a metric during said evaluation (otherwise the evaluation would just have printed the loss, which is not a very intuitive number). From 372d8c5e774d3d6d000eb55a4ce8b1efd981dd49 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:48:03 +0200 Subject: [PATCH 237/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index e4f4067ad..34483b46f 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -142,7 +142,7 @@ This will start the fine-tuning (which should take a couple of minutes on a GPU) ### Evaluation -اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids`) و دیکشنری باز گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (که رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آنها می باشند). برای استخراج چند پیش‌بینی‌ از مدل‌مان، می‌توانیم از دستور `Trainer.predict()` استفاده کنیم: +اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids`) و یک دیکشنری باز گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آن‌ها می باشند). برای استخراج چند پیش‌بینی‌ از مدل‌مان، می‌توانیم از دستور `Trainer.predict()` استفاده کنیم: Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: From 9fafe844a7b71d2202a30ba018d859b49406392a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:55:19 +0200 Subject: [PATCH 238/502] fixed typo --- chapters/fa/chapter3/3.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 34483b46f..c41b896e3 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -159,11 +159,11 @@ print(predictions.predictions.shape, predictions.label_ids.shape) -خروجی تابع `predict()` تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (در مجموع و به طور میانگین پیش‌بینی‌ چقدر طول کشیده) می‌باشد. به محض این که تابع `compute_metrics()` را کامل کرده و آنرا به `Trainer` ارسال کنیم، آن فیلد متریک‌های بازگشتی از `compute_metrics()` را نیز در بر خواهد داشت. +خروجی تابع `predict()` تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (پیش‌بینی‌، در مجموع و به طور میانگین، چقدر طول کشیده) می‌باشد. به محض این که تابع `compute_metrics()` را کامل کرده و آن را به `Trainer` ارسال کنیم، آن فیلد متریک‌های بازگشتی از `compute_metrics()` را نیز در بر خواهد داشت. The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. -همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل آنها به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی بعد دوم را برداریم: +همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل لاجیت‌ها به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی بعد دوم را برداریم: As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: @@ -196,7 +196,7 @@ metric.compute(predictions=preds, references=predictions.label_ids) -از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، برای مدل پایه `F1 Score` معادل ۸۸.۹ را گزارش می‌کند. توجه داشته باشید که آن مدل `uncased` بود، حال این که در اینجا ما از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. +از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، برای مدل پایه، `F1 Score` معادل ۸۸.۹ را گزارش می‌کند. توجه داشته باشید که آن مدل `uncased` بود، حال این که در اینجا ما از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. From dec3de9b6ad95f4c573090fb431cb787f1b1fc20 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:56:11 +0200 Subject: [PATCH 239/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index c41b896e3..a361bd759 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -196,7 +196,7 @@ metric.compute(predictions=preds, references=predictions.label_ids) -از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، برای مدل پایه، `F1 Score` معادل ۸۸.۹ را گزارش می‌کند. توجه داشته باشید که آن مدل `uncased` بود، حال این که در اینجا ما از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. +از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، برای مدل پایه، `F1 Score` معادل ۸۸.۹ را گزارش می‌کند. توجه داشته باشید که آن مدل `uncased` بود، حال آن که در اینجا ما از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. From 119853cd7831e5d6f17c2da56148a598e39b4a38 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:58:18 +0200 Subject: [PATCH 240/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index a361bd759..4434b9aa7 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -239,7 +239,7 @@ trainer = Trainer( -توجه داشته باشید که ما مدلی جدید و `TrainingArguments` جدیدی که `evaluation_strategy` آن `"epoch"` ست شده است می‌سازیم - در غیر این صورت فقط تعلیم مدلی را ادامه می‌دادیم که از تعلیم دیده بود. دستور زیر را برای راه‌اندازی دور جدید تعلیم اجرا می‌کنیم: +توجه داشته باشید که ما مدلی جدید و `TrainingArguments` جدیدی که `evaluation_strategy` آن `"epoch"` است می‌سازیم - در غیر این صورت فقط تعلیم مدلی که از پیش تعلیم دیده بود را ادامه می‌دادیم. دستور زیر را برای راه‌اندازی دور جدید تعلیم اجرا می‌کنیم: Note that we create a new `TrainingArguments` with its `evaluation_strategy` set to `"epoch"` and a new model — otherwise, we would just be continuing the training of the model we have already trained. To launch a new training run, we execute: From f4a5b552150846dac0291dabdef69c2f3725a02e Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 10:59:07 +0200 Subject: [PATCH 241/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 4434b9aa7..2f26edd24 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -239,7 +239,7 @@ trainer = Trainer( -توجه داشته باشید که ما مدلی جدید و `TrainingArguments` جدیدی که `evaluation_strategy` آن `"epoch"` است می‌سازیم - در غیر این صورت فقط تعلیم مدلی که از پیش تعلیم دیده بود را ادامه می‌دادیم. دستور زیر را برای راه‌اندازی دور جدید تعلیم اجرا می‌کنیم: +توجه داشته باشید که ما مدلی جدید و `TrainingArguments` جدیدی که `evaluation_strategy` آن `"epoch"` است می‌سازیم - در غیر این صورت فقط تعلیم مدلی که از پیش تعلیم دیده بود را ادامه می‌دادیم. برای راه‌اندازی دور جدید تعلیم، دستور زیر را اجرا می‌کنیم: Note that we create a new `TrainingArguments` with its `evaluation_strategy` set to `"epoch"` and a new model — otherwise, we would just be continuing the training of the model we have already trained. To launch a new training run, we execute: From f45102967290bd18252ab382519fdcaaeb278c6d Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 11:00:42 +0200 Subject: [PATCH 242/502] fixed ltr --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 2f26edd24..2b6ffcb9f 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -251,7 +251,7 @@ trainer.train() -این بار هزینه validation و متریک‌ها را در پایان هر epoch و در بالای هزینه تعلیم گزارش می‌کنیم. دوباره، به خاطر مقدار دهی تصادفی اولیه لایه سر مدل، مقادیر دقیق accuracy/F1 score که شما بدست می‌آورید ممکن است کمی متفاوت از آنچه ما بدست آورده‌ایم باشد، اما این مقادیر باید در محدوده تخمینی یکسانی باشند. +این بار هزینه validation و متریک‌ها را در پایان هر epoch و در بالای هزینه تعلیم گزارش می‌کنیم. دوباره، به خاطر مقدار دهی تصادفی اولیه لایه سر مدل، مقادیر دقیق accuracy/F1 score که شما بدست می‌آورید ممکن است کمی متفاوت از آنچه ما بدست آورده‌ایم باشد، اما این مقادیر باید در محدوده تخمینی یکسانی باشند. This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. From 1b611d8f80bb05c35feb38a4f3f690bedf062f4c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 11:02:30 +0200 Subject: [PATCH 243/502] fixed ltr --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 2b6ffcb9f..0108d519a 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -255,7 +255,7 @@ trainer.train() This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. -`Trainer` به صورت پیش فرض روی چندین GPU یا TPU کار خواهد کرد و گزینه‌های فراوانی، مثل تعلیم mixed-precision (از مقدار `fp16 = True` در آرگومان‌های تعلیم استفاده کنید) فراهم می‌کند. در فصل ۱۰ همه حالت‌هایی که پشتیبانی می‌کند را مرور خواهیم کرد. +به صورت پیش فرض `Trainer` روی چندین GPU یا TPU کار خواهد کرد و گزینه‌های فراوانی، مثل تعلیم mixed-precision (از مقدار `fp16 = True` در آرگومان‌های تعلیم استفاده کنید) فراهم می‌کند. در فصل ۱۰ همه حالت‌هایی که پشتیبانی می‌کند را مرور خواهیم کرد. The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. From b79139bb40f77878585095becd9fe0ac1c014964 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 11:02:58 +0200 Subject: [PATCH 244/502] fixed wording --- chapters/fa/chapter3/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 0108d519a..a59d19b09 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -255,7 +255,7 @@ trainer.train() This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. -به صورت پیش فرض `Trainer` روی چندین GPU یا TPU کار خواهد کرد و گزینه‌های فراوانی، مثل تعلیم mixed-precision (از مقدار `fp16 = True` در آرگومان‌های تعلیم استفاده کنید) فراهم می‌کند. در فصل ۱۰ همه حالت‌هایی که پشتیبانی می‌کند را مرور خواهیم کرد. +به صورت پیش فرض، `Trainer` روی چندین GPU یا TPU کار خواهد کرد و گزینه‌های فراوانی، مثل تعلیم mixed-precision (از مقدار `fp16 = True` در آرگومان‌های تعلیم استفاده کنید) فراهم می‌کند. در فصل ۱۰ همه حالت‌هایی که پشتیبانی می‌کند را مرور خواهیم کرد. The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. From d8eba670bc648e9c4e1b3e0a12e86f397efecaac Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 11:08:14 +0200 Subject: [PATCH 245/502] missing icon added --- chapters/fa/chapter3/3.mdx | 47 +++----------------------------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index a59d19b09..296c18bf5 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -64,7 +64,7 @@ training_args = TrainingArguments("test-trainer") -اگر مایلید مدل‌تان را در حین تعلیم در هاب بارگذاری کنید، پارامتر `push_to_hub=True` را در `TrainingArguments` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این باره بیشتر خواهیم آموخت. +💡 اگر مایلید مدل‌تان را در حین تعلیم در هاب بارگذاری کنید، پارامتر `push_to_hub=True` را در `TrainingArguments` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این باره بیشتر خواهیم آموخت. 💡 If you want to automatically upload your model to the Hub during training, pass along `push_to_hub=True` in the `TrainingArguments`. We will learn more about this in [Chapter 4](/course/chapter4/3) @@ -72,7 +72,6 @@ training_args = TrainingArguments("test-trainer") مرحله دوم تعریف مدل‌مان می‌باشد. مانند [فصل قبل](/course/chapter2)، از کلاس `AutoModelForSequenceClassification` با دو برچسب کلاس استفاده خواهیم کرد: -The second step is to define our model. As in the [previous chapter](/course/chapter2), we will use the `AutoModelForSequenceClassification` class, with two labels:
@@ -87,12 +86,8 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان کاری است که می‌خواهیم اکنون انجام دهیم. -You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been added instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. - به محض اینکه مدل‌مان مشخص شد می‌توانیم `Trainer` را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به داخل آن تعریف کنیم: -Once we have our model, we can define a `Trainer` by passing it all the objects constructed up to now — the `model`, the `training_args`, the training and validation datasets, our `data_collator`, and our `tokenizer`: -
```py @@ -110,14 +105,10 @@ trainer = Trainer(
-توجه داشته باشید زمانی که `tokenizer` را ارسال می‌کنید، مثل کاری که ما در اینجا انجام دادیم، `data_collator` پیش‌فرض مورد استفاده `Trainer`، همانطور که قبلا تعریف کردیم، `DataCollatorWithPadding` خواهد بود، در تنیجه شما می‌توانید خط `data_collator=data_collator` را در این فراخوانی نادیده بگیرید. - -Note that when you pass the `tokenizer` as we did here, the default `data_collator` used by the `Trainer` will be a `DataCollatorWithPadding` as defined previously, so you can skip the line `data_collator=data_collator` in this call. It was still important to show you this part of the processing in section 2! +توجه داشته باشید زمانی که `tokenizer` را ارسال می‌کنید، مثل کاری که ما در اینجا انجام دادیم، `data_collator` پیش‌فرض مورد استفاده `Trainer`، همانطور که قبلا تعریف کردیم، `DataCollatorWithPadding` خواهد بود، در تنیجه شما می‌توانید خط `data_collator=data_collator` را در این فراخوانی نادیده بگیرید. این هنوز مهم بود که این بخش از پردازش را در بخش ۲ به شما نشان دهیم! برای کوک کردن مدل روی دیتاسِت‌مان ما فقط باید تابع `train()` از `Trainer`مان را صدا بزنیم: -To fine-tune the model on our dataset, we just have to call the `train()` method of our `Trainer`: -
```py @@ -128,24 +119,14 @@ trainer.train() این کار، کوک کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و هزینه تعلیم را هر ۵۰۰ مرحله یک‌بار گزارش می‌کند. با این حال به شما نمی‌گوید که مدل‌تان چقدر خوب (یا بد) عمل می‌کند. این به این خاطر است که: -This will start the fine-tuning (which should take a couple of minutes on a GPU) and report the training loss every 500 steps. It won't, however, tell you how well (or badly) your model is performing. This is because: - ۱. ما به `Trainer` نگفتیم که در حین تعلیم کیفیت مدل را اندازه‌گیری کند. کاری که می‌توانستیم با مقداردهی پارامتر `evaluation_strategy` به `"steps"` (برای ارزیابی در هر `eval_steps`) یا به `"epoch"` (برای ارزیابی در انتهای هر epoch) انجام دهیم. ۲. ما تابع `compute_metrics()` را برای `Trainer` فراهم نکردیم تا بتواند معیارها را در حین اصطلاحا ارزیابی محاسبه کند (که در غیر این صورت، ارزیابی فقط هزینه را چاپ می‌کند که عدد چندان گویایی هم نیست) . -1. We didn't tell the `Trainer` to evaluate during training by setting `evaluation_strategy` to either `"steps"` (evaluate every `eval_steps`) or `"epoch"` (evaluate at the end of each epoch). -2. We didn't provide the `Trainer` with a `compute_metrics()` function to calculate a metric during said evaluation (otherwise the evaluation would just have printed the loss, which is not a very intuitive number). - - ### ارزیابی -### Evaluation - اجازه دهید ببینیم چگونه می‌توانیم تابع `compute_metrics()` مفیدی بسازیم و در تعلیم بعدی از آن استفاده کنیم. تابع باید یک شیء `EvalPrediction` دریافت کند (که تاپلی است شامل فیلدهای `predictions` و `label_ids`) و یک دیکشنری باز گرداند که رشته‌های متنی را به اعداد حقیقی تبدیل می‌کند (رشته‌های متنی نام معیارهای بازگردانده شونده و اعداد حقیقی مقادیر آن‌ها می باشند). برای استخراج چند پیش‌بینی‌ از مدل‌مان، می‌توانیم از دستور `Trainer.predict()` استفاده کنیم: -Let's see how we can build a useful `compute_metrics()` function and use it the next time we train. The function must take an `EvalPrediction` object (which is a named tuple with a `predictions` field and a `label_ids` field) and will return a dictionary mapping strings to floats (the strings being the names of the metrics returned, and the floats their values). To get some predictions from our model, we can use the `Trainer.predict()` command: -
```py @@ -161,12 +142,8 @@ print(predictions.predictions.shape, predictions.label_ids.shape) خروجی تابع `predict()` تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (پیش‌بینی‌، در مجموع و به طور میانگین، چقدر طول کشیده) می‌باشد. به محض این که تابع `compute_metrics()` را کامل کرده و آن را به `Trainer` ارسال کنیم، آن فیلد متریک‌های بازگشتی از `compute_metrics()` را نیز در بر خواهد داشت. -The output of the `predict()` method is another named tuple with three fields: `predictions`, `label_ids`, and `metrics`. The `metrics` field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average). Once we complete our `compute_metrics()` function and pass it to the `Trainer`, that field will also contain the metrics returned by `compute_metrics()`. - همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل لاجیت‌ها به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی بعد دوم را برداریم: -As you can see, `predictions` is a two-dimensional array with shape 408 x 2 (408 being the number of elements in the dataset we used). Those are the logits for each element of the dataset we passed to `predict()` (as you saw in the [previous chapter](/course/chapter2), all Transformer models return logits). To transform them into predictions that we can compare to our labels, we need to take the index with the maximum value on the second axis: -
```py @@ -179,8 +156,6 @@ preds = np.argmax(predictions.predictions, axis=-1) اکنون می‌توانیم `preds` را با برچسب‌ها مقایسه کنیم. برای ساختن تابع `compute_metric()`، به متریک‌های کتابخانه داده‌های هاگینگ‌فِیس تکیه خواهیم کرد. ما می‌توانیم متریک‌های وابسته به دیتاسِت MRPC را به راحتی خود دیتاسِت، اما این بار با استفاده از تابع `load_metric()`، بارگذاری کنیم. شیء بازگردانده شده تابعی به نام `compute()` دارد که می‌توانیم برای محاسبه متریک از آن استفاده کنیم: -We can now compare those `preds` to the labels. To build our `compute_metric()` function, we will rely on the metrics from the 🤗 Datasets library. We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: -
```py @@ -198,12 +173,8 @@ metric.compute(predictions=preds, references=predictions.label_ids) از آنجایی که مقداردهی تصادفی اولیه مدل می‌تواند متریک‌های نهایی را تغییر دهد، نتایج دقیقی که شما بدست می‌آورید ممکن است متفاوت باشد. در اینجا می‌توانیم ببینیم که مدل ما `accuracy` معادل ۸۵.۷۸٪ و `F1 Score` معادل ۸۹.۹۷٪ روی مجموعه `validation` بدست می‌آورد. آنها دو متریک برای ارزیابی نتایج محک GLUE روی دیتاسِت MRPC هستند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، برای مدل پایه، `F1 Score` معادل ۸۸.۹ را گزارش می‌کند. توجه داشته باشید که آن مدل `uncased` بود، حال آن که در اینجا ما از مدل `cased` استفاده می‌کنیم، که دستیابی به نتایج بهتر را توضیح می‌دهد. -The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. - اکنون با قرار دادن همه چیز کنارهم تابع `compute_metrics()` را بدست خواهیم آورد: -Wrapping everything together, we get our `compute_metrics()` function: -
```py @@ -218,8 +189,6 @@ def compute_metrics(eval_preds): و در اینجا نشان می‌دهیم که چگونه یک `Trainer` جدید با استفاده از تابع `compute_metrics()` تعریف می‌کنیم، تا بتوانیم عملکرد آن را در حین گزارش متریک‌ها در پایان هر epoch مشاهده کنیم: -And to see it used in action to report metrics at the end of each epoch, here is how we define a new `Trainer` with this `compute_metrics()` function: -
```py @@ -241,8 +210,6 @@ trainer = Trainer( توجه داشته باشید که ما مدلی جدید و `TrainingArguments` جدیدی که `evaluation_strategy` آن `"epoch"` است می‌سازیم - در غیر این صورت فقط تعلیم مدلی که از پیش تعلیم دیده بود را ادامه می‌دادیم. برای راه‌اندازی دور جدید تعلیم، دستور زیر را اجرا می‌کنیم: -Note that we create a new `TrainingArguments` with its `evaluation_strategy` set to `"epoch"` and a new model — otherwise, we would just be continuing the training of the model we have already trained. To launch a new training run, we execute: -
``` @@ -253,21 +220,13 @@ trainer.train() این بار هزینه validation و متریک‌ها را در پایان هر epoch و در بالای هزینه تعلیم گزارش می‌کنیم. دوباره، به خاطر مقدار دهی تصادفی اولیه لایه سر مدل، مقادیر دقیق accuracy/F1 score که شما بدست می‌آورید ممکن است کمی متفاوت از آنچه ما بدست آورده‌ایم باشد، اما این مقادیر باید در محدوده تخمینی یکسانی باشند. -This time, it will report the validation loss and metrics at the end of each epoch on top of the training loss. Again, the exact accuracy/F1 score you reach might be a bit different from what we found, because of the random head initialization of the model, but it should be in the same ballpark. - به صورت پیش فرض، `Trainer` روی چندین GPU یا TPU کار خواهد کرد و گزینه‌های فراوانی، مثل تعلیم mixed-precision (از مقدار `fp16 = True` در آرگومان‌های تعلیم استفاده کنید) فراهم می‌کند. در فصل ۱۰ همه حالت‌هایی که پشتیبانی می‌کند را مرور خواهیم کرد. -The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. - این پایان مقدمه‌ای بر کوک کردن با استفاده از `Trainer` API می‌باشد. در [فصل ۷](/course/chapter7) مثالی برای نشان دادن چگونگی انجام این کار برای معمول‌ترین مسئله‌های NLP ارائه خواهیم کرد، اما اکنون اجازه دهید ببینیم چگونه همین کار را صرفا با استفاده از PyTorch انجام دهیم. -This concludes the introduction to fine-tuning using the `Trainer` API. An example of doing this for most common NLP tasks will be given in [Chapter 7](/course/chapter7), but for now let's look at how to do the same thing in pure PyTorch. - -✏️ **اتحان کنید!** با استفاده از پردازش داده‌ای که در بخش ۲ انجام دادی، مدلی را روی دیتاسِت GLUE SST-2 کوک کنید، - -✏️ **Try it out!** Fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. +✏️ **اتحان کنید!** با استفاده از پردازش داده‌ای که در بخش ۲ انجام دادید، مدلی را روی دیتاسِت GLUE SST-2 کوک کنید. From 8858f2c77361ffc55f0f3b4ca2ee4f08238c8867 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 11:10:15 +0200 Subject: [PATCH 246/502] remove original english text --- chapters/fa/chapter3/3.mdx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 296c18bf5..0e2b50626 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -4,8 +4,6 @@ # کوک کردن مدل‌ها با استفاده از API `Trainer` -# Fine-tuning a model with the Trainer API - `Trainer.train()` می‌باشد، چرا که این تابع روی CPU بسیار کند اجرا می‌شود. اگر GPU ندارید، می‌توانید از GPU یا TPUهای مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. -🤗 Transformers provides a `Trainer` class to help you fine-tune any of the pretrained models it provides on your dataset. Once you've done all the data preprocessing work in the last section, you have just a few steps left to define the `Trainer`. The hardest part is likely to be preparing the environment to run `Trainer.train()`, as it will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). - نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: -The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need:
@@ -46,11 +41,8 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer) ### تعلیم -### Training - قبل از این که بتوانیم `Trainer` مان را تعریف کنیم اولین مرحله تعریف کلاس `TrainingArguments` می‌باشد که شامل همه پارامترهای سطح بالایی است که `Trainer` برای `Training` و `Evaluation` استفاده خواهد کرد. تنها آرگومانی که شما باید ارائه کنید آدرسی است که مدل تعلیم دیده به همراه نقاط تعلیم در آن ذخیره خواهند شد. بقیه پارامترها را می‌توانید به حالت پیش‌فرض رها کنید، که برای کوک کردن پایه به خوبی کار خواهد کرد. -The first step before we can define our `Trainer` is to define a `TrainingArguments` class that will contain all the hyperparameters the `Trainer` will use for training and evaluation. The only argument you have to provide is a directory where the trained model will be saved, as well as the checkpoints along the way. For all the rest, you can leave the defaults, which should work pretty well for a basic fine-tuning.
@@ -64,9 +56,7 @@ training_args = TrainingArguments("test-trainer") -💡 اگر مایلید مدل‌تان را در حین تعلیم در هاب بارگذاری کنید، پارامتر `push_to_hub=True` را در `TrainingArguments` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این باره بیشتر خواهیم آموخت. - -💡 If you want to automatically upload your model to the Hub during training, pass along `push_to_hub=True` in the `TrainingArguments`. We will learn more about this in [Chapter 4](/course/chapter4/3) +💡 اگر مایلید مدل‌تان را به صورت خودکار در حین تعلیم در هاب بارگذاری کنید، پارامتر `push_to_hub=True` را در `TrainingArguments` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این باره بیشتر خواهیم آموخت. From 9b9a72cebc0ef0b2ca294c0b0afdca7ddac0495c Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 11:16:59 +0200 Subject: [PATCH 247/502] final commit CH3 P3 --- chapters/fa/_toctree.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index 7336e1e93..5b7f5151f 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -25,6 +25,9 @@ title: مقدمه - local: chapter3/2 title: پردازش داده + - local: chapter3/3 + title: کوک کردن مدل‌ها با استفاده از Trainer API یا کِراس + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - title: ۴- به اشتراک‌گذاری مدل‌ها و توکِنایزرها sections: @@ -33,13 +36,6 @@ - local: chapter4/2 title: بکارگیری مدل‌های از پیش تعلیم دیده -- title: 3. کوک کردن یک مدل از پیش تعلیم دیده - sections: - - local: chapter3/1 - title: مقدمه - - local: chapter3/2 - title: پردازش داده - - title: واژه‌نامه sections: - local: glossary/1 From f92b070aefb559b55327cfc1d924bb39903d1fa4 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 12:40:35 +0200 Subject: [PATCH 248/502] formatting fixed - section ending was missing --- chapters/fa/chapter3/3.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 0e2b50626..aa3928b75 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -220,3 +220,4 @@ trainer.train() +
\ No newline at end of file From 00e876ee7032dca06c0d921b2bf705224195d81a Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 12:47:06 +0200 Subject: [PATCH 249/502] fixed formatting --- chapters/fa/chapter3/3.mdx | 2 -- chapters/fa/chapter3/3_tf.mdx | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index aa3928b75..7880d346a 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -62,7 +62,6 @@ training_args = TrainingArguments("test-trainer") مرحله دوم تعریف مدل‌مان می‌باشد. مانند [فصل قبل](/course/chapter2)، از کلاس `AutoModelForSequenceClassification` با دو برچسب کلاس استفاده خواهیم کرد: -
```py @@ -73,7 +72,6 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_label
- شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان کاری است که می‌خواهیم اکنون انجام دهیم. به محض اینکه مدل‌مان مشخص شد می‌توانیم `Trainer` را با ارسال همه اشیائی که تا کنون ساخته شده‌اند - `model`، `training_args`، دیتاسِت‌های `training` و `validation`، `data_collator` و `tokenizer` به داخل آن تعریف کنیم: diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index d631cc545..1bed20661 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -4,7 +4,6 @@ # کوک کردن مدل‌ها با استفاده از کِراس - این به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار بسیار کمی لازم است تا تعلیم را روی آن شروع کنیم. @@ -111,7 +109,6 @@ model.fit( - ### بهبود کارایی تعلیم @@ -171,6 +168,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3)
+ 💡 اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [Chapter 4](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. From 8d30cdd97a9c4af9ffcb331d914405f1cd6c9387 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 12:58:42 +0200 Subject: [PATCH 250/502] test 3_tf for formatting --- chapters/fa/chapter3/3_tf.mdx | 108 +++++++++++----------------------- 1 file changed, 35 insertions(+), 73 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 1bed20661..2252a9613 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -1,8 +1,6 @@ -
- -# کوک کردن مدل‌ها با استفاده از کِراس +# Fine-tuning a model with Keras -زمانی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قی‌مانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. - -نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: +Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). -
+The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: ```py from datasets import load_dataset @@ -30,6 +26,7 @@ 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") @@ -51,21 +48,17 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -
- -### تعلیم +### Training -مدل‌های تِنسورفِلو که از ترَنسفورمِرهای هاگینگ‌فِیس وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. +TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. -این به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار بسیار کمی لازم است تا تعلیم را روی آن شروع کنیم. +That means that once we have our data, very little work is required to begin training on it. -مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب دسته استفاده خواهیم کرد: - -
+As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: ```py from transformers import TFAutoModelForSequenceClassification @@ -73,20 +66,16 @@ from transformers import TFAutoModelForSequenceClassification model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` -
- -شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان کاری است که می‌خواهیم اکنون انجام دهیم. +You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. -برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه `training` و هزینه `validation` را در انتهای هر epoch گزارش می‌دهد. +To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. -توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب دسته‌های خودتان را به عنوان بخشی از ورودی، نه به صورت یک برچسب دسته مجزا که روش معمول استفاده از برچسب دسته‌ها در مدل‌های کِراس می‌باشد، ارسال کنید. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینه‌ی درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع هزینه استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. +Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. -
- ```py from tensorflow.keras.losses import SparseCategoricalCrossentropy @@ -101,23 +90,29 @@ model.fit( ) ``` -
- -در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغیر متنی برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softmax از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax به آنها اعمال شود به خروجی می‌دهند، که همچنین به عنوان *logits* شناخته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدل‌مان انجام می‌دهد و تنها راه گفتن آن این است که به جای ارسال نام تابع هزینه به صورت متغیر متنی، آن را به صورت مستقیم صدا بزنیم. +Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. -### بهبود کارایی تعلیم - +### Improving training performance -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و به صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. + -علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپُختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. +If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause +is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes +that optimizer with default values for all parameters, including learning rate. From long experience, though, we know +that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written +as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. -
+In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate +over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* +the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is +`PolynomialDecay` — despite the name, with default settings it simply linearly decays the learning rate from the initial +value to the final value over the course of training, which is exactly what we want. In order to use a scheduler correctly, +though, we need to tell it how long training is going to be. We compute that as `num_train_steps` below. ```py from tensorflow.keras.optimizers.schedules import PolynomialDecay @@ -136,17 +131,13 @@ from tensorflow.keras.optimizers import Adam opt = Adam(learning_rate=lr_scheduler) ``` -
- -کتابخانه ترنسفورمرهای هاگینگ‌فِیس همچنین یک تابع `create_optimizer()` دارد که بهینه‌سازی از نوع `AdamW`، دارای میزان کاهش نرخ یادگیری می‌سازد. این یک میان‌بر مناسب است که آن‌ را با جزئیات در بخش‌های بعدی این آموزش خواهید دید. +The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. -اکنون بهینه‌ساز کاملا جدیدمان را در اختیار داریم و می‌توانیم آن را تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شده‌اند را به حالت اولیه بازگردانیم، سپس می‌توانیم مدل را با بهینه ساز جدید تدوین کنیم: - -
+Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: ```py import tensorflow as tf @@ -156,62 +147,41 @@ loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) model.compile(optimizer=opt, loss=loss, metrics=["accuracy"]) ``` -
- -حالا دوباره مدل را فیت می‌کنیم: - -
+Now, we fit again: ```py model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) ``` -
- - -💡 اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [Chapter 4](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. +💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) -### پیش‌بینی‌های مدل +### Model predictions -تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر کلاس یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. - -
+Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. ```py preds = model.predict(tf_validation_dataset)["logits"] ``` -
- -سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگ‌ترین `logit`، که نماینده محتمل‌ترین دسته می‌باشد، به پیش‌بینی‌های دسته مدل تبدیل کنیم: - -
+We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: ```py class_preds = np.argmax(preds, axis=1) print(preds.shape, class_preds.shape) ``` -
- -
- ```python out (408, 2) (408,) ``` -
- -اکنون، اجازه دهید از `preds` برای محاسبه برخی معیارها استفاده کنیم! ما می‌توانیم معیارهای مرتبط با دیتاسِت MRPC را، به همان آسانی که دیتاسِت را بارگذاری کردیم، بارگذاری کنیم اما این بار با استفاده از تابع `load_metric()`. شیء باز گردانده شده تابعی به نام `compute()` دارد که می‌توانیم برای محاسبه معیارها از آن استفاده کنیم: - -
+Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: ```py from datasets import load_metric @@ -220,18 +190,10 @@ metric = load_metric("glue", "mrpc") metric.compute(predictions=class_preds, references=raw_datasets["validation"]["label"]) ``` -
- -
- ```python out {'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} ``` -
- -از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. - -به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`، با استفاده از روش پردازش داده‌ که در بخش ۲ انجام دادید، کوک کنید. +The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. -
\ No newline at end of file +This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in [Chapter 7](/course/chapter7). If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. From 14f0b6cc15f2a6c78eb7954013a04fa839838db1 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 13:02:48 +0200 Subject: [PATCH 251/502] test 3_tf for formatting - put back --- chapters/fa/chapter3/3_tf.mdx | 108 +++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 35 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 2252a9613..1bed20661 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -1,6 +1,8 @@ -# Fine-tuning a model with Keras +
+ +# کوک کردن مدل‌ها با استفاده از کِراس -Once you've done all the data preprocessing work in the last section, you have just a few steps left to train the model. Note, however, that the `model.fit()` command will run very slowly on a CPU. If you don't have a GPU set up, you can get access to free GPUs or TPUs on [Google Colab](https://colab.research.google.com/). +زمانی که همه کارهای پیش‌پردازش در بخش قبل را انجام دادید، فقط چند مرحله با‌قی‌مانده تا تعلیم مدل دارید. با این حال، توجه داشته باشید که دستور `model.fit()` روی CPU بسیار آهسته اجرا خواهد شد. اگر GPU ندارید، می‌توانید از GPU یا TPU مجانی روی [گوگل کولَب](https://colab.research.google.com/) استفاده کنید. + +نمونه کدهای زیر فرض می‌کنند که شما مثال‌های بخش قبل را از پیش اجرا کرده‌اید. این یک خلاصه کوتاه است جهت یادآوری آنچه نیاز دارید: -The code examples below assume you have already executed the examples in the previous section. Here is a short summary recapping what you need: +
```py from datasets import load_dataset @@ -26,7 +30,6 @@ 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") @@ -48,17 +51,21 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -### Training +
+ +### تعلیم -TensorFlow models imported from 🤗 Transformers are already Keras models. Here is a short introduction to Keras. +مدل‌های تِنسورفِلو که از ترَنسفورمِرهای هاگینگ‌فِیس وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. -That means that once we have our data, very little work is required to begin training on it. +این به این معنی است که به محض اینکه داده‌مان را در اختیار بگیریم، کار بسیار کمی لازم است تا تعلیم را روی آن شروع کنیم. -As in the [previous chapter](/course/chapter2), we will use the `TFAutoModelForSequenceClassification` class, with two labels: +مانند [فصل قبل](/course/chapter2)، ما از کلاس `TFAutoModelForSequenceClassification` با دو برچسب دسته استفاده خواهیم کرد: + +
```py from transformers import TFAutoModelForSequenceClassification @@ -66,16 +73,20 @@ from transformers import TFAutoModelForSequenceClassification model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` -You will notice that unlike in [Chapter 2](/course/chapter2), you get a warning after instantiating this pretrained model. This is because BERT has not been pretrained on classifying pairs of sentences, so the head of the pretrained model has been discarded and a new head suitable for sequence classification has been inserted instead. The warnings indicate that some weights were not used (the ones corresponding to the dropped pretraining head) and that some others were randomly initialized (the ones for the new head). It concludes by encouraging you to train the model, which is exactly what we are going to do now. +
+ +شما متوجه خواهید شد که برخلاف [فصل ۲](/course/chapter2)، بعد از ساختن این مدل از پیش‌ تعلیم دیده یک هشدار دریافت می‌کنید. این به این خاطر است که BERT برای دسته‌بندی دو جمله‌ها از پیش‌ تعلیم ندیده است، بنابراین لایه سَر مدل از پیش‌ تعلیم دیده حذف شده و یک لایه سَر مناسب جهت دسته بندی رشته‌‌‌ها به جای آن قرار گرفته است. هشدارها نشان می‌دهند که برخی از وزن‌های مدل استفاده نشده‌اند (آنهایی که مربوط به لایه‌ سَر حذف شده مدل از پیش تعلیم دیده هستند) و برخی دیگر به صورت تصادفی مقدار‌ دهی شده‌‌اند (آنهایی که مربوط به لایه‌ سَر جدید هستند). در نتیجه این امر شما را تشویق به تعلیم مدل می‌کند، که دقیقا همان کاری است که می‌خواهیم اکنون انجام دهیم. -To fine-tune the model on our dataset, we just have to `compile()` our model and then pass our data to the `fit()` method. This will start the fine-tuning process (which should take a couple of minutes on a GPU) and report training loss as it goes, plus the validation loss at the end of each epoch. +برای کوک‌ کردن مدل روی دِیتاسِت‌مان، ما فقط باید مدل را `compile()` کنیم و سپس داده‌مان را به تابع `fit()` ارسال کنیم. این کار فرایند کوک‌ کردن را شروع می‌کند (که باید چند دقیقه روی GPU طول بکشد) و در همین حین هزینه `training` و هزینه `validation` را در انتهای هر epoch گزارش می‌دهد. -Note that 🤗 Transformers models have a special ability that most Keras models don't - they can automatically use an appropriate loss which they compute internally. They will use this loss by default if you don't set a loss argument in `compile()`. Note that to use the internal loss you'll need to pass your labels as part of the input, not as a separate label, which is the normal way to use labels with Keras models. You'll see examples of this in Part 2 of the course, where defining the correct loss function can be tricky. For sequence classification, however, a standard Keras loss function works fine, so that's what we'll use here. +توجه داشته باشید که مدل‌های ترَنسفورمِر هاگینگ‌فِیس قابلیت ویژه‌ای دارند که بسیاری از مدل‌های کِراس ندارند - آنها می‌توانند به صورت خودکار از یک تابع هزینه مناسب که به صورت داخلی محاسبه می‌کنند استفاده کنند. در صورتی که شما آرگومانی برای تابع هزینه در زمان `compile()` تعیین نکنید آنها از این تابع هزینه به صورت پیش‌فرض استفاده خواهند کرد. توجه داشته باشید که جهت استفاده از تابع هزینه داخلی شما نیاز خواهید داشت برچسب دسته‌های خودتان را به عنوان بخشی از ورودی، نه به صورت یک برچسب دسته مجزا که روش معمول استفاده از برچسب دسته‌ها در مدل‌های کِراس می‌باشد، ارسال کنید. شما مثال‌هایی از این را در بخش ۲ این درس خواهید دید، جایی که تعیین تابع هزینه‌ی درست می‌تواند تا اندازه‌ای پیچیده باشد. به هر حال، برای دسته‌بندی رشته‌‌‌ها، یک تابع هزینه استانداد کِراس به خوبی کار می‌کند، چیزی که ما در اینجا استفاده خواهیم کرد. +
+ ```py from tensorflow.keras.losses import SparseCategoricalCrossentropy @@ -90,29 +101,23 @@ model.fit( ) ``` +
+ -Note a very common pitfall here — you *can* just pass the name of the loss as a string to Keras, but by default Keras will assume that you have already applied a softmax to your outputs. Many models, however, output the values right before the softmax is applied, which are also known as the *logits*. We need to tell the loss function that that's what our model does, and the only way to do that is to call it directly, rather than by name with a string. +در اینجا توجه شما را به یک مسئله عام جلب می‌کنیم - شما *می‌توانید* فقط نام تابع هزینه را به صورت یک متغیر متنی برای کِراس ارسال کنید، اما کِراس به صورت پیش‌فرض فکر می‌کند شما یک لایه softmax از پیش به خروجی‌تان اعمال کرده‌اید. با این حال، بسیاری از مدل‌ها مقادیر را درست قبل از اینکه softmax به آنها اعمال شود به خروجی می‌دهند، که همچنین به عنوان *logits* شناخته می‌شوند. ما نیاز داریم که به تابع هزینه بگوییم، این کاری است که مدل‌مان انجام می‌دهد و تنها راه گفتن آن این است که به جای ارسال نام تابع هزینه به صورت متغیر متنی، آن را به صورت مستقیم صدا بزنیم. - -### Improving training performance +### بهبود کارایی تعلیم -If you try the above code, it certainly runs, but you'll find that the loss declines only slowly or sporadically. The primary cause -is the *learning rate*. As with the loss, when we pass Keras the name of an optimizer as a string, Keras initializes -that optimizer with default values for all parameters, including learning rate. From long experience, though, we know -that transformer models benefit from a much lower learning rate than the default for Adam, which is 1e-3, also written -as 10 to the power of -3, or 0.001. 5e-5 (0.00005), which is some twenty times lower, is a much better starting point. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و به صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. -In addition to lowering the learning rate, we have a second trick up our sleeve: We can slowly reduce the learning rate -over the course of training. In the literature, you will sometimes see this referred to as *decaying* or *annealing* -the learning rate. In Keras, the best way to do this is to use a *learning rate scheduler*. A good one to use is -`PolynomialDecay` — despite the name, with default settings it simply linearly decays the learning rate from the initial -value to the final value over the course of training, which is exactly what we want. In order to use a scheduler correctly, -though, we need to tell it how long training is going to be. We compute that as `num_train_steps` below. +علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپُختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. + +
```py from tensorflow.keras.optimizers.schedules import PolynomialDecay @@ -131,13 +136,17 @@ from tensorflow.keras.optimizers import Adam opt = Adam(learning_rate=lr_scheduler) ``` +
+ -The 🤗 Transformers library also has a `create_optimizer()` function that will create an `AdamW` optimizer with learning rate decay. This is a convenient shortcut that you'll see in detail in future sections of the course. +کتابخانه ترنسفورمرهای هاگینگ‌فِیس همچنین یک تابع `create_optimizer()` دارد که بهینه‌سازی از نوع `AdamW`، دارای میزان کاهش نرخ یادگیری می‌سازد. این یک میان‌بر مناسب است که آن‌ را با جزئیات در بخش‌های بعدی این آموزش خواهید دید. -Now we have our all-new optimizer, and we can try training with it. First, let's reload the model, to reset the changes to the weights from the training run we just did, and then we can compile it with the new optimizer: +اکنون بهینه‌ساز کاملا جدیدمان را در اختیار داریم و می‌توانیم آن را تعلیم دهیم. ابتدا، اجازه دهید مدل را مجددا بارگذاری کنیم تا تغییرات ایجاد شده بر وزنها که در تعلیم قبلی اعمال شده‌اند را به حالت اولیه بازگردانیم، سپس می‌توانیم مدل را با بهینه ساز جدید تدوین کنیم: + +
```py import tensorflow as tf @@ -147,41 +156,62 @@ loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) model.compile(optimizer=opt, loss=loss, metrics=["accuracy"]) ``` -Now, we fit again: +
+ +حالا دوباره مدل را فیت می‌کنیم: + +
```py model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) ``` +
+ + -💡 If you want to automatically upload your model to the Hub during training, you can pass along a `PushToHubCallback` in the `model.fit()` method. We will learn more about this in [Chapter 4](/course/chapter4/3) +💡 اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [Chapter 4](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. -### Model predictions +### پیش‌بینی‌های مدل +تعلیم و تماشای پایین رفتن هزینه خیلی خوب است، اما اگر واقعا بخواهیم از مدل تعلیم دیده‌مان، چه برای محاسبه برخی معیار‌ها و چه برای استفاده در خط تولید، خروجی دریافت کنیم باید چه کار کنیم؟ برای این منظور می‌توانیم از تابع `predict()` استفاده کنیم. این کار به ازای هر کلاس یک *logits* از لایه‌ سَر خروجی مدل باز می‌گرداند. -Training and watching the loss go down is all very nice, but what if we want to actually get outputs from the trained model, either to compute some metrics, or to use the model in production? To do that, we can just use the `predict()` method. This will return the *logits* from the output head of the model, one per class. + +
```py preds = model.predict(tf_validation_dataset)["logits"] ``` -We can convert these logits into the model's class predictions by using `argmax` to find the highest logit, which corresponds to the most likely class: +
+ +سپس می‌توانیم `logits` را با استفاده از `argmax` برای یافتن بزرگ‌ترین `logit`، که نماینده محتمل‌ترین دسته می‌باشد، به پیش‌بینی‌های دسته مدل تبدیل کنیم: + +
```py class_preds = np.argmax(preds, axis=1) print(preds.shape, class_preds.shape) ``` +
+ +
+ ```python out (408, 2) (408,) ``` -Now, let's use those `preds` to compute some metrics! We can load the metrics associated with the MRPC dataset as easily as we loaded the dataset, this time with the `load_metric()` function. The object returned has a `compute()` method we can use to do the metric calculation: +
+ +اکنون، اجازه دهید از `preds` برای محاسبه برخی معیارها استفاده کنیم! ما می‌توانیم معیارهای مرتبط با دیتاسِت MRPC را، به همان آسانی که دیتاسِت را بارگذاری کردیم، بارگذاری کنیم اما این بار با استفاده از تابع `load_metric()`. شیء باز گردانده شده تابعی به نام `compute()` دارد که می‌توانیم برای محاسبه معیارها از آن استفاده کنیم: + +
```py from datasets import load_metric @@ -190,10 +220,18 @@ metric = load_metric("glue", "mrpc") metric.compute(predictions=class_preds, references=raw_datasets["validation"]["label"]) ``` +
+ +
+ ```python out {'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} ``` -The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. +
+ +از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. + +به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`، با استفاده از روش پردازش داده‌ که در بخش ۲ انجام دادید، کوک کنید. -This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in [Chapter 7](/course/chapter7). If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. +
\ No newline at end of file From bda0cc13628432f54ef5410e60133c572b70cc02 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 13:09:14 +0200 Subject: [PATCH 252/502] text formatting --- chapters/fa/chapter3/3_tf.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 1bed20661..1b5806d69 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -30,6 +30,7 @@ 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") @@ -53,6 +54,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset(
+ ### تعلیم مدل‌های تِنسورفِلو که از ترَنسفورمِرهای هاگینگ‌فِیس وارد شده‌اند از پیش مدل‌های کِراس هستند. این هم مقدمه‌ای کوتاه به کِراس. @@ -113,7 +115,7 @@ model.fit( -اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که 1e-3 می‌باشد و به صورت‌ 10 به توان -3 یا 0.001 نیز نوشته می‌شود. +اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که ۱e-۳ می‌باشد و به صورت‌ ۱۰ به توان یا ۰،۰۰۱ نیز نوشته می‌شود. علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپُختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. From 7e9ef4f019d4f2217ce6ee75af81d54baac03158 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 13:15:18 +0200 Subject: [PATCH 253/502] text formatting --- chapters/fa/chapter3/3.mdx | 2 +- chapters/fa/chapter3/3_tf.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/3.mdx b/chapters/fa/chapter3/3.mdx index 7880d346a..aa64dc157 100644 --- a/chapters/fa/chapter3/3.mdx +++ b/chapters/fa/chapter3/3.mdx @@ -130,7 +130,7 @@ print(predictions.predictions.shape, predictions.label_ids.shape) خروجی تابع `predict()` تاپل نام گذاری شده دیگری شامل سه فیلد: `predictions`، `label_ids` و `metrics` می‌باشد. فیلد `metrics` فقط شامل هزینه داده عبور کرده و برخی معیارهای زمان (پیش‌بینی‌، در مجموع و به طور میانگین، چقدر طول کشیده) می‌باشد. به محض این که تابع `compute_metrics()` را کامل کرده و آن را به `Trainer` ارسال کنیم، آن فیلد متریک‌های بازگشتی از `compute_metrics()` را نیز در بر خواهد داشت. -همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها لاجیت‌های هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر لاجیت‌ها را باز می‌گردانند). برای تبدیل لاجیت‌ها به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی بعد دوم را برداریم: +همانطور که می‌بینید، `predictions` آرایه‌ای دو بعدی است با شکل ۴۰۸ x ۲ (که ۴۰۸ تعداد عناصر در دیتاسِت مورد استفاده‌ ما می‌باشد). این ها logits مربوط به هریک از عناصر دیتاسِتی هستند که ما به تابع `predict()` ارسال کردیم (همانطور که در [فصل قبل](/course/chapter2) دیدید، همه مدل‌های ترَنسفورمِر logits را باز می‌گردانند). برای تبدیل logits به پیش‌بینی‌‌هایی که بتوانیم با برچسب‌هایمان مقایسه کنیم، نیاز داریم اندیس مقدار بیشینه روی بعد دوم را برداریم:
diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index 1b5806d69..ecb3d4b08 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -173,7 +173,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -💡 اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [Chapter 4](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. +💡 اگر مایلید مدلتان را در حین تعلیم به صورت خودکار در هاب بارگذاری کنید، می‌توانید پارامتر `PushToHubCallback` را در تابع `model.fit()` ارسال کنید. در [فصل ۴](/course/chapter4/3) در این مورد بیشتر خواهیم آموخت. From 985fd5f9261d3e0ba38d68f63c39f3ba07d81345 Mon Sep 17 00:00:00 2001 From: gitkamyah Date: Thu, 23 Jun 2022 13:26:48 +0200 Subject: [PATCH 254/502] text formatting error fixe --- chapters/fa/chapter3/3_tf.mdx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/chapters/fa/chapter3/3_tf.mdx b/chapters/fa/chapter3/3_tf.mdx index ecb3d4b08..fb49d492f 100644 --- a/chapters/fa/chapter3/3_tf.mdx +++ b/chapters/fa/chapter3/3_tf.mdx @@ -117,7 +117,7 @@ model.fit( اگر کد بالا را امتحان کنید، قطعا اجرا خواهد شد، اما متوجه خواهید شد که هزینه بسیار آهسته یا به صورت گاه و بیگاه کاهش می‌یابد. علت اصلی این امر *نرخ یادگیری* می‌باشد. مانند تابع هزینه، وقتی که ما نام بهینه‌ساز را به صورت یک متغیر متنی به کِراس ارسال می‌کنیم، کِراس همه پارامترهای آن، شامل نرخ یادگیری، را با مقادیر پیش‌فرض مقداردهی اولیه می‌کند. به تجربه طولانی، ما می‌دانیم که مدل‌های ترَنسفورمِر از نرخ‌های یادگیری بسیار کوچک‌تر بهره بیشتری می‌برند تا مقدار پیش‌فرض برای بهینه‌ساز Adam، که ۱e-۳ می‌باشد و به صورت‌ ۱۰ به توان یا ۰،۰۰۱ نیز نوشته می‌شود. -علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپُختی یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از *زمان‌بند نرخ یادگیری* است.* یک زمان‌بند خوب برای استفاده زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم. +علاوه بر کم کردن یکباره نرخ یادگیری، ترفند دیگری نیز در آستین داریم: ما می‌توانیم نرخ یادگیری را به آهستگی در طول دوره تعلیم کاهش دهیم. گاها خواهید دید که از این روش در متون مشابه با عنوان نرخ یادگیری *محو شونده* یا *بازپُختی* یاد می‌شود. بهترین روش برای انجام این کار در کِراس استفاده از زمان‌بند نرخ یادگیری است. یک زمان‌بند خوب برای استفاده، زمان‌بند `PolynomialDecay` می‌باشد - این زمان‌بند برخلاف نامش نرخ یادگیری را در حالت پیش‌فرض به صورت خطی از مقدار اولیه تا مقدار نهایی در طول دوره تعلیم کاهش می‌دهد که دقیقا همان چیزی است که ما می‌خواهیم. به منظور استفاده درست از زمان‌بند ما نیاز داریم که به آن بگویم طول زمان تعلیم چقدر خواهد بود. در زیر ما آن را به عنوان `num_train_steps` محاسبه می‌کنیم.
@@ -232,8 +232,9 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l
-از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل 85.78% و F1 score معادل 89.97 روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با 88.9 برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. +از آنجایی که مقداردهی اولیه تصادفی در لایه‌ سَر مدل ممکن است مقادیر معیارهای حاصل را تغییر دهد، نتایج دریافتی شما می‌توانند متفاوت باشند. در اینجا می‌بینیم که مدل ما دقتی معادل ۸۵.۷۸٪ و F1 score معادل ۸۹.۹۷٪ روی مجموعه `validation` دارد. این‌‌ها دو معیاری هستند که جهت سنجش نتایج روی داده MRPC در محک GLUE به کار رفته‌اند. جدول نتایج در مقاله [BERT](https://arxiv.org/pdf/1810.04805.pdf)، F1 score برابر با ۸۸.۹ برای مدل پایه گزارش کرده است. توجه داشته باشید که آن مدل `uncased` بود در حالی که اکنون ما از مدل `cased` استفاده می‌کنیم، که نتایج بهتر را توجیح می‌کند. + +به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`، با استفاده از روش پردازش داده‌ که در بخش ۲ انجام دادید، کوک کنید. -به این ترتیب مقدمه کوک کردن با استفاده از `API` کِراس به پایان می‌رسد. در فصل ۷ یک مثال از انجام این کار برای معمول‌ترین مسئله‌های `NLP` ارائه خواهد شد. اگر مایلید مهارت‌های خود را روی `API` کِراس تقویت کنید، سعی کنید مدلی را روی مسئله `GLUE SST-2`، با استفاده از روش پردازش داده‌ که در بخش ۲ انجام دادید، کوک کنید.
\ No newline at end of file From 2ca3e7824f391ed161ff6b20b69385604d3c4f59 Mon Sep 17 00:00:00 2001 From: Fabrizio Damicelli Date: Wed, 5 Oct 2022 14:55:14 +0200 Subject: [PATCH 255/502] translate de-ch-4.4 --- chapters/de/chapter4/4.mdx | 90 +++++++++++++++ chapters/de/chapter4/5.mdx | 12 ++ chapters/de/chapter4/6.mdx | 228 +++++++++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+) create mode 100644 chapters/de/chapter4/4.mdx create mode 100644 chapters/de/chapter4/5.mdx create mode 100644 chapters/de/chapter4/6.mdx diff --git a/chapters/de/chapter4/4.mdx b/chapters/de/chapter4/4.mdx new file mode 100644 index 000000000..2c978d53c --- /dev/null +++ b/chapters/de/chapter4/4.mdx @@ -0,0 +1,90 @@ +# Erstellung eines Modellkarte ("model card") + + + +Die Modellkarte (Steckbrief) ist eine Datei, die wahrscheinlich genauso wichtig wie das Modell und der Tokenizer in dem Modell-Repository ist. +Da liegt die zentrale Definition vom Modell und sie trägt dazu bei, dass andere Menschen der Community das wiederverwenden und die Ergebnisse reproduzieren können – also das ist die Basis, auf der Andere ihre Artifakte bauen können. + +Die Dokumentation zum Modell- Training und Evaluierung hilft anderen Nutzer:innen zu verstehen, was sie vom Modell erwarten sollten. +Ausreichende Information zu der Vor- und Nachaufarbeitung der Daten dient auch dazu, dass man die Einschränkungen, Biases und den Kontext identifizieren kann, wann das Modell nützlich ist und wann nicht. + +Deswegen ist die Erstellung einer klar definierten Modellkarte ein sehr wichtiger Schritt. Hier geben wir ein Paar Hinweise, die dir dabei helfen könnten. Die Modellkarte wird durch eine *README.md* Datei (eine Markdown Datei) kreiert, die du schonmal gesehen hast. + +#TODO +The "model card" concept originates from a research direction from Google, first shared in the paper ["Model Cards for Model Reporting"](https://arxiv.org/abs/1810.03993) by Margaret Mitchell et al. A lot of information contained here is based on that paper, and we recommend you take a look at it to understand why model cards are so important in a world that values reproducibility, reusability, and fairness. + +The model card usually starts with a very brief, high-level overview of what the model is for, followed by additional details in the following sections: + +- Model description +- Intended uses & limitations +- How to use +- Limitations and bias +- Training data +- Training procedure +- Evaluation results + +Let's take a look at what each of these sections should contain. + +### Model description + +The model description provides basic details about the model. This includes the architecture, version, if it was introduced in a paper, if an original implementation is available, the author, and general information about the model. Any copyright should be attributed here. General information about training procedures, parameters, and important disclaimers can also be mentioned in this section. + +### Intended uses & limitations + +Here you describe the use cases the model is intended for, including the languages, fields, and domains where it can be applied. This section of the model card can also document areas that are known to be out of scope for the model, or where it is likely to perform suboptimally. + +### How to use + +This section should include some examples of how to use the model. This can showcase usage of the `pipeline()` function, usage of the model and tokenizer classes, and any other code you think might be helpful. + +### Training data + +This part should indicate which dataset(s) the model was trained on. A brief description of the dataset(s) is also welcome. + +### Training procedure + +In this section you should describe all the relevant aspects of training that are useful from a reproducibility perspective. This includes any preprocessing and postprocessing that were done on the data, as well as details such as the number of epochs the model was trained for, the batch size, the learning rate, and so on. + +### Variable and metrics + +Here you should describe the metrics you use for evaluation, and the different factors you are mesuring. Mentioning which metric(s) were used, on which dataset and which dataset split, makes it easy to compare you model's performance compared to that of other models. These should be informed by the previous sections, such as the intended users and use cases. + +### Evaluation results + +Finally, provide an indication of how well the model performs on the evaluation dataset. If the model uses a decision threshold, either provide the decision threshold used in the evaluation, or provide details on evaluation at different thresholds for the intended uses. + +## Example + +Check out the following for a few examples of well-crafted model cards: + +- [`bert-base-cased`](https://huggingface.co/bert-base-cased) +- [`gpt2`](https://huggingface.co/gpt2) +- [`distilbert`](https://huggingface.co/distilbert-base-uncased) + +More examples from different organizations and companies are available [here](https://github.com/huggingface/model_card/blob/master/examples.md). + +## Note + +Model cards are not a requirement when publishing models, and you don't need to include all of the sections described above when you make one. However, explicit documentation of the model can only benefit future users, so we recommend that you fill in as many of the sections as possible to the best of your knowledge and ability. + +## Model card metadata + +If you have done a little exploring of the Hugging Face Hub, you should have seen that some models belong to certain categories: you can filter them by tasks, languages, libraries, and more. The categories a model belongs to are identified according to the metadata you add in the model card header. + +For example, if you take a look at the [`camembert-base` model card](https://huggingface.co/camembert-base/blob/main/README.md), you should see the following lines in the model card header: + +``` +--- +language: fr +license: mit +datasets: +- oscar +--- +``` + +This metadata is parsed by the Hugging Face Hub, which then identifies this model as being a French model, with an MIT license, trained on the Oscar dataset. + +The [full model card specification](https://github.com/huggingface/hub-docs/blame/main/modelcard.md) allows specifying languages, licenses, tags, datasets, metrics, as well as the evaluation results the model obtained when training. diff --git a/chapters/de/chapter4/5.mdx b/chapters/de/chapter4/5.mdx new file mode 100644 index 000000000..341f9f348 --- /dev/null +++ b/chapters/de/chapter4/5.mdx @@ -0,0 +1,12 @@ +# Part 1 completed! + + + +This is the end of the first part of the course! Part 2 will be released on November 15th with a big community event, see more information [here](https://huggingface.co/blog/course-launch-event). + +You should now be able to fine-tune a pretrained model on a text classification problem (single or pairs of sentences) and upload the result to the Model Hub. To make sure you mastered this first section, you should do exactly that on a problem that interests you (and not necessarily in English if you speak another language)! You can find help in the [Hugging Face forums](https://discuss.huggingface.co/) and share your project in [this topic](https://discuss.huggingface.co/t/share-your-projects/6803) once you're finished. + +We can't wait to see what you will build with this! diff --git a/chapters/de/chapter4/6.mdx b/chapters/de/chapter4/6.mdx new file mode 100644 index 000000000..4317fdb4f --- /dev/null +++ b/chapters/de/chapter4/6.mdx @@ -0,0 +1,228 @@ + + + + +# End-of-chapter quiz + + + +Let's test what you learned in this chapter! + +### 1. What are models on the Hub limited to? + + + +### 2. How can you manage models on the Hub? + +git-lfs for large files.", + correct: true + } + ]} +/> + +### 3. What can you do using the Hugging Face Hub web interface? + + + +### 4. What is a model card? + + + +### 5. Which of these objects of the 🤗 Transformers library can be directly shared on the Hub with `push_to_hub()`? + +{#if fw === 'pt'} +push_to_hub method, and using it will push all the tokenizer files (vocabulary, architecture of the tokenizer, etc.) to a given repo. That's not the only right answer, though!", + correct: true + }, + { + text: "A model configuration", + explain: "Right! All model configurations have the push_to_hub method, and using it will push them to a given repo. What else can you share?", + correct: true + }, + { + text: "A model", + explain: "Correct! All models have the push_to_hub method, and using it will push them and their configuration files to a given repo. That's not all you can share, though.", + correct: true + }, + { + text: "A Trainer", + explain: "That's right — the Trainer also implements the push_to_hub method, and using it will upload the model, its configuration, the tokenizer, and a model card draft to a given repo. Try another answer!", + correct: true + } + ]} +/> +{:else} +push_to_hub method, and using it will push all the tokenizer files (vocabulary, architecture of the tokenizer, etc.) to a given repo. That's not the only right answer, though!", + correct: true + }, + { + text: "A model configuration", + explain: "Right! All model configurations have the push_to_hub method, and using it will push them to a given repo. What else can you share?", + correct: true + }, + { + text: "A model", + explain: "Correct! All models have the push_to_hub method, and using it will push them and their configuration files to a given repo. That's not all you can share, though.", + correct: true + }, + { + text: "All of the above with a dedicated callback", + explain: "That's right — the PushToHubCallback will regularly send all of those objects to a repo during training.", + correct: true + } + ]} +/> +{/if} + +### 6. What is the first step when using the `push_to_hub()` method or the CLI tools? + + + +### 7. You're using a model and a tokenizer — how can you upload them to the Hub? + +huggingface_hub utility.", + explain: "Models and tokenizers already benefit from huggingface_hub utilities: no need for additional wrapping!" + }, + { + text: "By saving them to disk and calling transformers-cli upload-model", + explain: "The command upload-model does not exist." + } + ]} +/> + +### 8. Which git operations can you do with the `Repository` class? + +git_commit() method is there for that.", + correct: true + }, + { + text: "A pull", + explain: "That is the purpose of the git_pull() method.", + correct: true + }, + { + text: "A push", + explain: "The method git_push() does this.", + correct: true + }, + { + text: "A merge", + explain: "No, that operation will never be possible with this API." + } + ]} +/> From 0c66281b37df36b1488eeebad040c16f1d39b2f4 Mon Sep 17 00:00:00 2001 From: Fabrizio Damicelli Date: Sat, 12 Nov 2022 15:23:37 +0100 Subject: [PATCH 256/502] translate de-ch4-part2 --- chapters/de/chapter4/4.mdx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/chapters/de/chapter4/4.mdx b/chapters/de/chapter4/4.mdx index 2c978d53c..42c0488ff 100644 --- a/chapters/de/chapter4/4.mdx +++ b/chapters/de/chapter4/4.mdx @@ -13,21 +13,22 @@ Ausreichende Information zu der Vor- und Nachaufarbeitung der Daten dient auch d Deswegen ist die Erstellung einer klar definierten Modellkarte ein sehr wichtiger Schritt. Hier geben wir ein Paar Hinweise, die dir dabei helfen könnten. Die Modellkarte wird durch eine *README.md* Datei (eine Markdown Datei) kreiert, die du schonmal gesehen hast. -#TODO -The "model card" concept originates from a research direction from Google, first shared in the paper ["Model Cards for Model Reporting"](https://arxiv.org/abs/1810.03993) by Margaret Mitchell et al. A lot of information contained here is based on that paper, and we recommend you take a look at it to understand why model cards are so important in a world that values reproducibility, reusability, and fairness. +Das Konzept von Modellkarte ("model card") stammt aus einer Forschungsrichtung bei Google, die zuerst in dem Paper ["Model Cards for Model Reporting"](https://arxiv.org/abs/1810.03993) von Margaret Mitchell et al erschien. Vieles von dem, was hier steht, basiert auf dem Paper und wir empfehlen dir, das Paper zu lesen, um besser zu verstehen, warum Modellkarten so wichtig sind, wenn man Wert auf Reproduzierbarkeit, Wiederverwendbarkeit und Fairness legt. The model card usually starts with a very brief, high-level overview of what the model is for, followed by additional details in the following sections: +Eine Modellkarte fängt mit einer kurzen, große Übersicht davon, was das Modell kann plus einige Details in den folgenden Abschnitte: -- Model description -- Intended uses & limitations -- How to use -- Limitations and bias -- Training data -- Training procedure -- Evaluation results +- Modell Beschreibung +- Beabsichtigte Nutzung und Einschränkungen +- Modell-Bedienung +- Einschränkungen und Bias +- Trainingsdaten +- Trainingsverfahren +- Evaluierungsergebnisse -Let's take a look at what each of these sections should contain. +Lass uns anschauen, was genau in jedem Abschnitt stehen sollte. +#TODO ### Model description The model description provides basic details about the model. This includes the architecture, version, if it was introduced in a paper, if an original implementation is available, the author, and general information about the model. Any copyright should be attributed here. General information about training procedures, parameters, and important disclaimers can also be mentioned in this section. From bfb85a33679e009584043fb8af65e08eef932d0f Mon Sep 17 00:00:00 2001 From: Nate Voorhies Date: Thu, 23 Feb 2023 21:46:44 -0700 Subject: [PATCH 257/502] Removing errant double quote. Just a typo correction, no changes to code or semantics of course lessons. --- chapters/en/chapter2/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter2/5.mdx b/chapters/en/chapter2/5.mdx index 81d496fef..e1b54c66e 100644 --- a/chapters/en/chapter2/5.mdx +++ b/chapters/en/chapter2/5.mdx @@ -85,7 +85,7 @@ InvalidArgumentError: Input to reshape is a tensor with 14 values, but the reque ``` {/if} -Oh no! Why did this fail? "We followed the steps from the pipeline in section 2. +Oh no! Why did this fail? We followed the steps from the pipeline in section 2. The problem is that we sent a single sequence to the model, whereas 🤗 Transformers models expect multiple sentences by default. Here we tried to do everything the tokenizer did behind the scenes when we applied it to a `sequence`. But if you look closely, you'll see that the tokenizer didn't just convert the list of input IDs into a tensor, it added a dimension on top of it: From 2a5c9706ba0ac865d68e3c8a12037290da4667d3 Mon Sep 17 00:00:00 2001 From: askfor Date: Sun, 19 Mar 2023 09:55:16 +0800 Subject: [PATCH 258/502] typo fix: _toctree.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix typo: A full training 一个完整的训练过程 --- chapters/zh-CN/_toctree.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/zh-CN/_toctree.yml b/chapters/zh-CN/_toctree.yml index ff3aaaa6d..c8a84781d 100644 --- a/chapters/zh-CN/_toctree.yml +++ b/chapters/zh-CN/_toctree.yml @@ -57,7 +57,7 @@ title: 使用 Trainer API 或者 Keras 微调一个模型 local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - local: chapter3/4 - title: 一个完成的训练过程 + title: 一个完整的训练过程 - local: chapter3/5 title: 微调,章节回顾! - local: chapter3/6 From cfc456b85dce4a7d9b81b31094754482a9aae4ff Mon Sep 17 00:00:00 2001 From: sj Date: Tue, 28 Mar 2023 19:43:02 +0900 Subject: [PATCH 259/502] Fix typo --- chapters/en/chapter6/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter6/5.mdx b/chapters/en/chapter6/5.mdx index 291518720..e877653ef 100644 --- a/chapters/en/chapter6/5.mdx +++ b/chapters/en/chapter6/5.mdx @@ -97,7 +97,7 @@ Let's take the example we used during training, with the three merge rules learn ("h", "ug") -> "hug" ``` -The word `"bug"` will be tokenized as `["b", "ug"]`. `"mug"`, however, will be tokenized as `["[UNK]", "ug"]` since the letter `"m"` was not in the base vocabulary. Likewise, the word `"thug"` will be tokenized as `["[UNK]", "hug"]`: the letter `"t"` is not in the base vocabulary, and applying the merge rules results first in `"u"` and `"g"` being merged and then `"hu"` and `"g"` being merged. +The word `"bug"` will be tokenized as `["b", "ug"]`. `"mug"`, however, will be tokenized as `["[UNK]", "ug"]` since the letter `"m"` was not in the base vocabulary. Likewise, the word `"thug"` will be tokenized as `["[UNK]", "hug"]`: the letter `"t"` is not in the base vocabulary, and applying the merge rules results first in `"u"` and `"g"` being merged and then `"h"` and `"ug"` being merged. From 21e6e6b7579905db6a53feb02f5cc8fce555c83a Mon Sep 17 00:00:00 2001 From: Sureshkumar Thangavel <108256+tsureshkumar@users.noreply.github.com> Date: Mon, 3 Apr 2023 21:51:15 +0530 Subject: [PATCH 260/502] The GPT2 link is broken The link `/course/en/chapter7/section6` does not exist in the course. Corrected to `/course/en/chapter7/6`. --- chapters/en/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter7/3.mdx b/chapters/en/chapter7/3.mdx index 9a9d1b8ff..629fc704d 100644 --- a/chapters/en/chapter7/3.mdx +++ b/chapters/en/chapter7/3.mdx @@ -1035,7 +1035,7 @@ Neat -- our model has clearly adapted its weights to predict words that are more -This wraps up our first experiment with training a language model. In [section 6](/course/en/chapter7/section6) you'll learn how to train an auto-regressive model like GPT-2 from scratch; head over there if you'd like to see how you can pretrain your very own Transformer model! +This wraps up our first experiment with training a language model. In [section 6](/course/en/chapter7/6) you'll learn how to train an auto-regressive model like GPT-2 from scratch; head over there if you'd like to see how you can pretrain your very own Transformer model! From 14067bb9a7d590133b4e9984498c63520001d435 Mon Sep 17 00:00:00 2001 From: Andrei Shirobokov Date: Tue, 4 Apr 2023 15:10:23 +0300 Subject: [PATCH 261/502] typo in `Now your turn!` section Duplicated `the` was removed --- chapters/en/chapter6/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter6/7.mdx b/chapters/en/chapter6/7.mdx index 505cf7588..b0067ecc5 100644 --- a/chapters/en/chapter6/7.mdx +++ b/chapters/en/chapter6/7.mdx @@ -58,7 +58,7 @@ So, the sum of all frequencies is 210, and the probability of the subword `"ug"` -✏️ **Now your turn!** Write the code to compute the the frequencies above and double-check that the results shown are correct, as well as the total sum. +✏️ **Now your turn!** Write the code to compute the frequencies above and double-check that the results shown are correct, as well as the total sum. From 1d5471a019b28736a876e39b90adffc8d39808b4 Mon Sep 17 00:00:00 2001 From: Andrei Shirobokov Date: Sun, 9 Apr 2023 19:37:20 +0300 Subject: [PATCH 262/502] `chunk_size` should be instead of `block_size` `chunk_size` should be instead of `block_size` (`block_size` was never mentioned before) --- chapters/en/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter7/3.mdx b/chapters/en/chapter7/3.mdx index 9a9d1b8ff..116ff6d82 100644 --- a/chapters/en/chapter7/3.mdx +++ b/chapters/en/chapter7/3.mdx @@ -347,7 +347,7 @@ print(f"'>>> Concatenated reviews length: {total_length}'") '>>> Concatenated reviews length: 951' ``` -Great, the total length checks out -- so now let's split the concatenated reviews into chunks of the size given by `block_size`. To do so, we iterate over the features in `concatenated_examples` and use a list comprehension to create slices of each feature. The result is a dictionary of chunks for each feature: +Great, the total length checks out -- so now let's split the concatenated reviews into chunks of the size given by `chunk_size`. To do so, we iterate over the features in `concatenated_examples` and use a list comprehension to create slices of each feature. The result is a dictionary of chunks for each feature: ```python chunks = { From de2cb2778bdbbff772a05e5e4021d320eb61af44 Mon Sep 17 00:00:00 2001 From: Pranav <66965591+Pranav-Bobde@users.noreply.github.com> Date: Mon, 24 Apr 2023 08:49:40 +0530 Subject: [PATCH 263/502] refactor: rephrase text to improve clarity and specificity In context to "training with a dataset specific to your task" and "train directly for the final task", I was not able to infer easily that "directly" here implies training from scratch. --- chapters/en/chapter1/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter1/4.mdx b/chapters/en/chapter1/4.mdx index 80f692852..3fcff99af 100644 --- a/chapters/en/chapter1/4.mdx +++ b/chapters/en/chapter1/4.mdx @@ -97,7 +97,7 @@ By the way, you can evaluate the carbon footprint of your models' training throu This pretraining is usually done on very large amounts of data. Therefore, it requires a very large corpus of data, and training can take up to several weeks. -*Fine-tuning*, on the other hand, is the training done **after** a model has been pretrained. To perform fine-tuning, you first acquire a pretrained language model, then perform additional training with a dataset specific to your task. Wait -- why not simply train directly for the final task? There are a couple of reasons: +*Fine-tuning*, on the other hand, is the training done **after** a model has been pretrained. To perform fine-tuning, you first acquire a pretrained language model, then perform additional training with a dataset specific to your task. Wait -- why not simply train the model for your final use case from the start (**scratch**)? There are a couple of reasons: * The pretrained model was already trained on a dataset that has some similarities with the fine-tuning dataset. The fine-tuning process is thus able to take advantage of knowledge acquired by the initial model during pretraining (for instance, with NLP problems, the pretrained model will have some kind of statistical understanding of the language you are using for your task). * Since the pretrained model was already trained on lots of data, the fine-tuning requires way less data to get decent results. From e5a8fcfd8a1f8d7d9c4ec12273c22dcf6beb3172 Mon Sep 17 00:00:00 2001 From: Maria Khalusova Date: Wed, 10 May 2023 11:19:37 -0400 Subject: [PATCH 264/502] Demo link fixes (#562) * demo link fixes * minor demo fix --- chapters/en/chapter7/3.mdx | 2 +- chapters/en/chapter9/5.mdx | 8 +------- chapters/en/chapter9/7.mdx | 2 +- chapters/en/events/3.mdx | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/chapters/en/chapter7/3.mdx b/chapters/en/chapter7/3.mdx index 9a9d1b8ff..dc12fb8bc 100644 --- a/chapters/en/chapter7/3.mdx +++ b/chapters/en/chapter7/3.mdx @@ -35,7 +35,7 @@ This process of fine-tuning a pretrained language model on in-domain data is usu By the end of this section you'll have a [masked language model](https://huggingface.co/huggingface-course/distilbert-base-uncased-finetuned-imdb?text=This+is+a+great+%5BMASK%5D.) on the Hub that can autocomplete sentences as shown below: - + Let's dive in! diff --git a/chapters/en/chapter9/5.mdx b/chapters/en/chapter9/5.mdx index b32056e33..4e1797c7a 100644 --- a/chapters/en/chapter9/5.mdx +++ b/chapters/en/chapter9/5.mdx @@ -23,19 +23,13 @@ import gradio as gr title = "GPT-J-6B" description = "Gradio Demo for GPT-J 6B, a transformer model trained using Ben Wang's Mesh Transformer JAX. 'GPT-J' refers to the class of model, while '6B' represents the number of trainable parameters. To use it, simply add your text, or click one of the examples to load them. Read more at the links below." article = "

GPT-J-6B: A 6 Billion Parameter Autoregressive Language Model

" -examples = [ - ["The tower is 324 metres (1,063 ft) tall,"], - ["The Moon's orbit around Earth has"], - ["The smooth Borealis basin in the Northern Hemisphere covers 40%"], -] + gr.Interface.load( "huggingface/EleutherAI/gpt-j-6B", inputs=gr.Textbox(lines=5, label="Input Text"), title=title, description=description, article=article, - examples=examples, - enable_queue=True, ).launch() ``` diff --git a/chapters/en/chapter9/7.mdx b/chapters/en/chapter9/7.mdx index 3c74d8452..fce4f80fb 100644 --- a/chapters/en/chapter9/7.mdx +++ b/chapters/en/chapter9/7.mdx @@ -231,6 +231,6 @@ with gr.Blocks() as block: block.launch() ``` - + We just explored all the core concepts of `Blocks`! Just like with `Interfaces`, you can create cool demos that can be shared by using `share=True` in the `launch()` method or deployed on [Hugging Face Spaces](https://huggingface.co/spaces). \ No newline at end of file diff --git a/chapters/en/events/3.mdx b/chapters/en/events/3.mdx index b0770d38d..d74b9c206 100644 --- a/chapters/en/events/3.mdx +++ b/chapters/en/events/3.mdx @@ -6,4 +6,4 @@ You can find all the demos that the community created under the [`Gradio-Blocks` **Natural language to SQL** - + From cccc2c91ac8e702e5e14bbb0419dbf0490c7aaaf Mon Sep 17 00:00:00 2001 From: lewtun Date: Wed, 10 May 2023 21:02:16 +0200 Subject: [PATCH 265/502] Bump release (#566) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add note about `remove_unused_columns` for whole word masking * Merge pull request #24 from huggingface/fix-typo Fix typo * Merge pull request #26 from huggingface/fix-qa-offsets Fix inequalities in answer spans for QA chapter * Merge pull request #30 from huggingface/fix-modelcard-url Update model card URL * Merge pull request #69 from yulonglin/patch-1 Correct typo mixing up space and newline symbols * Bump release (#99) * Bump release * Update author list Co-authored-by: DOOHAE JUNG Co-authored-by: m_khandaker Co-authored-by: Md. Al-Amin Khandaker Co-authored-by: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Co-authored-by: Doohae Jung <80743307+Doohae@users.noreply.github.com> Co-authored-by: melaniedrevet * Bump release (#115) * ko-chapter1/1 * ko _toctree.yml created * Fix the issue #80 * Single expression changed * ko/chapter1 finished * ko/chapter0 finished * ko/chapter0 finished * reviewed by @bzantium ko/chapter0 * reviewed by @bzantium chapter0 & fixed typo * reviewed by @rainmaker712 * maximize Korean expressions * [Chapter 1] bangla traslation initial commit * Update 1.mdx update and fix formating * Fix formating and typos * translate _toctree.yml 0-1 chapter * Add Korean to CI * [tr] Translated chapter1/2.mdx * remove translation from sec titles not yet translated * Add authors [th ru] * [FIX] _toctree.yml * Update chapters/bn/chapter0/1.mdx [FIX] syntax formatting Co-authored-by: lewtun * tag typos & indentation & unnatural expressions * modified toctree.yml for chapter1/2 * modified toctree.yml for chapter1/2 & fix typo * French Translation - Chapter 5 * Add Bengali to CI * Update author list * Adding translations for 2/4 and 2/5 🚀 (#74) * Adding translations for 2/4 and 2/5 🚀 * Remove English content Co-authored-by: lewtun * Translation to Russian (#97) * translation of chapter 2/section 1 * add section 1 / chapter 2 to _toctree.yml * Translation of Chapter0 to Hindi (#86) * Hindi?Chapter0-Part_1 * Hindi/Chapter0-Part_2 * Chapter 0 Persian Translation First Draft (#95) * merged branch0 into main. no toctree yet. * updated toctree. * Updated the glossary with terms from chapter0. * Second draft in collab w/ @schoobani. Added empty chapter1 for preview. * Glossary typo fix. * Translation of Chapter0 (setup) to Arabic (#104) * Add AR translation for `introduction` * Fix alignment & format * Add Arabic to CI build * Russian - Chapter 1 finished (#98) * 01/4 start * 1/4 finished * 1/5 finished * 1/5 update toc * 1/6 finished * 1/7 finished * 1/8 finished * 1/9 finished * 1/4 fix * toc update * Chinese - Chapter 1 finished (#113) * Chinese - Chapter 1 finished * Add zh to the languages field Co-authored-by: petrichor1122 <87262598+petrichor1122@users.noreply.github.com> Co-authored-by: zhlhyx <95976146+zhlhyx@users.noreply.github.com> * [PT] Translation of chapter 2 (#107) * add PT translate to 2.1 * add PT translate to 2.2 * add portuguese translation to 2.3 * WIP portuguese translation to 2.4 * add portuguese translation to 2.4 * add portuguese translation to 2.5 * add portuguese translation to 2.6 * add _toctree infos Co-authored-by: lewtun * [FR] Translation of chapter 2 & event + Review of chapters 0 & 5 (#106) * Update _toctree.yml Add chapter 2 + little fix of chapter 5 * Update 1.mdx Review of chapter 0 * Create 1.mdx * Create 2.mdx * Create 3.mdx * Create 4.mdx * Create 5.mdx * Create 6.mdx * Create 7.mdx * Create 8.mdx * Update 8.mdx Since AutoNLP has recently been renamed to AutoTrain, let me make the correction on the English file * Update 1.mdx Review of chapter 5/1 * Update 2.mdx Review of chapter 5/2 * Update 3.mdx Review of chapter 5/3 * Update 4.mdx Review of chapter 5/4 * Update 5.mdx Review of chapter 5/5 * Update 6.mdx Review of chapter 5/6 * Update 7.mdx Review of chapter 5/7 * Update 8.mdx Review of chapter 5/8 * Create 1.mdx event's translation * Update _toctree.yml add event to the tree * Update _toctree.yml deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * Delete 1.mdx deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * make style correction * Update _toctree.yml the - * Fix spacing Co-authored-by: Lewis Tunstall * [th] Translated Chapter2/1 (#83) * Finish chapter2/1 * Update _toctree.yml * ko-chapter1/1 * ko _toctree.yml created * Fix the issue #80 * Single expression changed * ko/chapter1 finished * ko/chapter0 finished * ko/chapter0 finished * reviewed by @bzantium ko/chapter0 * reviewed by @bzantium chapter0 & fixed typo * reviewed by @rainmaker712 * maximize Korean expressions * [Chapter 1] bangla traslation initial commit * Update 1.mdx update and fix formating * Fix formating and typos * translate _toctree.yml 0-1 chapter * Add Korean to CI * remove translation from sec titles not yet translated * Add authors [th ru] * [FIX] _toctree.yml * Update chapters/bn/chapter0/1.mdx [FIX] syntax formatting Co-authored-by: lewtun * tag typos & indentation & unnatural expressions * modified toctree.yml for chapter1/2 * modified toctree.yml for chapter1/2 & fix typo * Add Bengali to CI * Update author list * Adding translations for 2/4 and 2/5 🚀 (#74) * Adding translations for 2/4 and 2/5 🚀 * Remove English content Co-authored-by: lewtun * Translation to Russian (#97) * translation of chapter 2/section 1 * add section 1 / chapter 2 to _toctree.yml * Translation of Chapter0 to Hindi (#86) * Hindi?Chapter0-Part_1 * Hindi/Chapter0-Part_2 * Chapter 0 Persian Translation First Draft (#95) * merged branch0 into main. no toctree yet. * updated toctree. * Updated the glossary with terms from chapter0. * Second draft in collab w/ @schoobani. Added empty chapter1 for preview. * Glossary typo fix. * Translation of Chapter0 (setup) to Arabic (#104) * Add AR translation for `introduction` * Fix alignment & format * Add Arabic to CI build * Russian - Chapter 1 finished (#98) * 01/4 start * 1/4 finished * 1/5 finished * 1/5 update toc * 1/6 finished * 1/7 finished * 1/8 finished * 1/9 finished * 1/4 fix * toc update * Chinese - Chapter 1 finished (#113) * Chinese - Chapter 1 finished * Add zh to the languages field Co-authored-by: petrichor1122 <87262598+petrichor1122@users.noreply.github.com> Co-authored-by: zhlhyx <95976146+zhlhyx@users.noreply.github.com> * [PT] Translation of chapter 2 (#107) * add PT translate to 2.1 * add PT translate to 2.2 * add portuguese translation to 2.3 * WIP portuguese translation to 2.4 * add portuguese translation to 2.4 * add portuguese translation to 2.5 * add portuguese translation to 2.6 * add _toctree infos Co-authored-by: lewtun * [FR] Translation of chapter 2 & event + Review of chapters 0 & 5 (#106) * Update _toctree.yml Add chapter 2 + little fix of chapter 5 * Update 1.mdx Review of chapter 0 * Create 1.mdx * Create 2.mdx * Create 3.mdx * Create 4.mdx * Create 5.mdx * Create 6.mdx * Create 7.mdx * Create 8.mdx * Update 8.mdx Since AutoNLP has recently been renamed to AutoTrain, let me make the correction on the English file * Update 1.mdx Review of chapter 5/1 * Update 2.mdx Review of chapter 5/2 * Update 3.mdx Review of chapter 5/3 * Update 4.mdx Review of chapter 5/4 * Update 5.mdx Review of chapter 5/5 * Update 6.mdx Review of chapter 5/6 * Update 7.mdx Review of chapter 5/7 * Update 8.mdx Review of chapter 5/8 * Create 1.mdx event's translation * Update _toctree.yml add event to the tree * Update _toctree.yml deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * Delete 1.mdx deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * make style correction * Update _toctree.yml the - * Fix spacing Co-authored-by: Lewis Tunstall * [th] Translated Chapter2/1 (#83) * Finish chapter2/1 * Update _toctree.yml * Add Hindi to CI (#116) Co-authored-by: DOOHAE JUNG Co-authored-by: m_khandaker Co-authored-by: Md. Al-Amin Khandaker Co-authored-by: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Co-authored-by: Doohae Jung <80743307+Doohae@users.noreply.github.com> Co-authored-by: melaniedrevet Co-authored-by: Jose M Munoz Co-authored-by: svv73 <88366711+svv73@users.noreply.github.com> Co-authored-by: Vedant Pandya Co-authored-by: Bahram Shamshiri Co-authored-by: Giyaseddin Bayrak <34009210+giyaseddin@users.noreply.github.com> Co-authored-by: Pavel <60391448+pdumin@users.noreply.github.com> Co-authored-by: 1375626371 <40328311+1375626371@users.noreply.github.com> Co-authored-by: petrichor1122 <87262598+petrichor1122@users.noreply.github.com> Co-authored-by: zhlhyx <95976146+zhlhyx@users.noreply.github.com> Co-authored-by: João Gustavo A. Amorim Co-authored-by: lbourdois <58078086+lbourdois@users.noreply.github.com> Co-authored-by: Cherdsak Kingkan * Bump release 4 (#133) * Bump release (#138) * ko-chapter1/1 * ko _toctree.yml created * Fix the issue #80 * Single expression changed * ko/chapter1 finished * ko/chapter0 finished * ko/chapter0 finished * reviewed by @bzantium ko/chapter0 * reviewed by @bzantium chapter0 & fixed typo * reviewed by @rainmaker712 * maximize Korean expressions * [Chapter 1] bangla traslation initial commit * Update 1.mdx update and fix formating * Fix formating and typos * translate _toctree.yml 0-1 chapter * Add Korean to CI * [tr] Translated chapter1/2.mdx * remove translation from sec titles not yet translated * Add authors [th ru] * [FIX] _toctree.yml * Update chapters/bn/chapter0/1.mdx [FIX] syntax formatting Co-authored-by: lewtun * tag typos & indentation & unnatural expressions * modified toctree.yml for chapter1/2 * modified toctree.yml for chapter1/2 & fix typo * French Translation - Chapter 5 * Add Bengali to CI * Update author list * Adding translations for 2/4 and 2/5 🚀 (#74) * Adding translations for 2/4 and 2/5 🚀 * Remove English content Co-authored-by: lewtun * Translation to Russian (#97) * translation of chapter 2/section 1 * add section 1 / chapter 2 to _toctree.yml * Translation of Chapter0 to Hindi (#86) * Hindi?Chapter0-Part_1 * Hindi/Chapter0-Part_2 * Chapter 0 Persian Translation First Draft (#95) * merged branch0 into main. no toctree yet. * updated toctree. * Updated the glossary with terms from chapter0. * Second draft in collab w/ @schoobani. Added empty chapter1 for preview. * Glossary typo fix. * Translation of Chapter0 (setup) to Arabic (#104) * Add AR translation for `introduction` * Fix alignment & format * Add Arabic to CI build * Russian - Chapter 1 finished (#98) * 01/4 start * 1/4 finished * 1/5 finished * 1/5 update toc * 1/6 finished * 1/7 finished * 1/8 finished * 1/9 finished * 1/4 fix * toc update * Chinese - Chapter 1 finished (#113) * Chinese - Chapter 1 finished * Add zh to the languages field Co-authored-by: petrichor1122 <87262598+petrichor1122@users.noreply.github.com> Co-authored-by: zhlhyx <95976146+zhlhyx@users.noreply.github.com> * [PT] Translation of chapter 2 (#107) * add PT translate to 2.1 * add PT translate to 2.2 * add portuguese translation to 2.3 * WIP portuguese translation to 2.4 * add portuguese translation to 2.4 * add portuguese translation to 2.5 * add portuguese translation to 2.6 * add _toctree infos Co-authored-by: lewtun * [FR] Translation of chapter 2 & event + Review of chapters 0 & 5 (#106) * Update _toctree.yml Add chapter 2 + little fix of chapter 5 * Update 1.mdx Review of chapter 0 * Create 1.mdx * Create 2.mdx * Create 3.mdx * Create 4.mdx * Create 5.mdx * Create 6.mdx * Create 7.mdx * Create 8.mdx * Update 8.mdx Since AutoNLP has recently been renamed to AutoTrain, let me make the correction on the English file * Update 1.mdx Review of chapter 5/1 * Update 2.mdx Review of chapter 5/2 * Update 3.mdx Review of chapter 5/3 * Update 4.mdx Review of chapter 5/4 * Update 5.mdx Review of chapter 5/5 * Update 6.mdx Review of chapter 5/6 * Update 7.mdx Review of chapter 5/7 * Update 8.mdx Review of chapter 5/8 * Create 1.mdx event's translation * Update _toctree.yml add event to the tree * Update _toctree.yml deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * Delete 1.mdx deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * make style correction * Update _toctree.yml the - * Fix spacing Co-authored-by: Lewis Tunstall * [th] Translated Chapter2/1 (#83) * Finish chapter2/1 * Update _toctree.yml * Add Hindi to CI (#116) * Update README.md (#87) * Update authors on README (#120) * Update authors * French translation `Chapter1` full (#56) * traduction 1st part of chapter1 * fix typo * fix job titles and encoder-decoder translation * add part 2 for 1st chapter * fix some typo part2 * fix Transformer -> Transformers * add part 3 not totally ended * end of part3 of chapter1 * part9 chapter 1 * add part7 chapter 1 * add part5 chapter 1 * part 6 chapter 1 * add part8 chapter 1 * end quizz of chapter * add last part of chapter 1 Co-authored-by: ChainYo * Translate to Japanese Chapter0 (#123) * start working * translate chapter0/1.mdx * [FA] First draft of Chapter2/Page2 (#129) * merged branch0 into main. no toctree yet. * updated toctree. * Updated the glossary with terms from chapter0. * Second draft in collab w/ @schoobani. Added empty chapter1 for preview. * Glossary typo fix. * Added missing backticks. * Removed a couple of bad indefinite articles I forgot. * First draft of ch2/p2. Adds to glossary. Trans. guidelines moved out. * Fixed missing diacritics, fixed the py/tf switch placing. Other fixes. * Changed the equivalent for prediction per @kambizG 's direction. * Redid ambiguous passage in translation per @lewtun 's direction. * [th] Finished whole Chapter 2 translation (#127) * Finish chapter2/1 * delete untranslated files * chapter2/2 WIP * Delete WIP files * WIP chapter2/2 * Fixed conflict * Update _toctree.yml * Update _toctree.yml * Finished Chapter2/2 * Finish all chapter2/n * Finish all chapter2/n * Fixed Ch2/8 as PR run failed * [de] Translation Chapter 0 (#130) * Copy files to newly created german dir (de) * Add translation for chapter 0 * Clean up english files for chapter 1 * Change _toctree.yml for chapter 0 * Fix whitespaces * Fix whitespaces again * Adjust _toctree.yml - leave only chaper 0 * Add German language (de) to workflow yaml files * [de] German Translation Guide (#132) * German Translation Guide * Add German Glossary to TOC * Chapter 1, Section 1 Bengali translation (#124) * [ADD] Chapter 1, Section 1 benglai tranlation * [FIX] toc * [FIX] commit mistakes * [FIX] remove the Eng duplicates Co-authored-by: m_khandaker * [FR] Review of chapters 0, 2 & 5 + add chapters 6, 7, 8 & event (#125) * Create 1.mdx Event translation * Create 1.mdx * Chapter 6 in French * Update 1.mdx fix italic * Update 9.mdx fix italic * Update 3.mdx fix italic * Update 4.mdx fix italic * Update 4.mdx * Update 1.mdx little fix * Update 2.mdx little fix * Update 4.mdx fix italic * Update 8.mdx fix italic * Update 1.mdx little fix * Update 2.mdx little fix * Update 3.mdx little fix * Update 5.mdx little fix * Update 7.mdx little fix * Update 8.mdx little fix * add chapter8 * Update 6.mdx fix italic * Update 3.mdx fix, fix everywhere * Update 2.mdx fix, fix everywhere * Update 4.mdx fix, fix everywhere * Update 4_tf.mdx fix, fix everywhere * Add files via upload add chapter 7 * Update 1.mdx fix links * Update 2.mdx fix, fix everywhere * Update 3.mdx fix, fix everywhere * Update 4.mdx fix, fix everywhere * Update 5.mdx * Update 6.mdx fix, fix everywhere * Update 7.mdx fix, fix everywhere * Update 3.mdx fix link * Update 8.mdx fix link * Update 2.mdx fix link * Update 4.mdx little fix * Update 6.mdx * Update 7.mdx * Update 8.mdx fix * Update 2.mdx little fix * Update 3.mdx little fix * Update 5.mdx * Update 4_tf.mdx little fix * Update _toctree.yml Forgot the toctree * Update _toctree.yml fix local fields * Update _toctree.yml My bad, I forgot some 🙃 * Update 7.mdx I don't know why it was there... * Update 1.mdx * [de] Chapter 3 translation (#128) * chapter 3 part 1 DE * [DE] Chapter 3 - Part 2 * Prepare TOC-Tree * Fein-tuning * Initial translation * Glossary additions for C3P3 * C3P2 style * [de] Chapter 3 P3-TF initial translation * [de] Chapter 3 P4 initial translation * [de] Chapter 3 Part 5 initial translation * [de] Chapter 3 P6 Initial translation * Missing commas * fixing quotes * Mark third option on chapter 8, question 8 as correct (#135) * doc_change(translation): translating course from english to gujarati (#126) * change(translation): chapter0 to gujarati content translated: Chapter0/1.mdx - Introduction commit-by: menonashwathi4@gmail.com * Revert "change(translation): chapter0 to gujarati" This reverts commit c27e06992af8892687f343a19368ce322d69e8b2. * doc_change(translation): translation to gj translated content: chapters/gj/chapter0.mdx - introduction * doc_change(translation): translation to gj translated content: chapters/gj/chapter0.mdx - introduction * Delete _toctree.yml * change: adding gj to github workflow * nit: fix heading * Update authors (#136) * [FA] First draft of Chapter4/Page1 (#134) * added chapter4 title and it's first section * added first draft of Chapter4/Page1 * minor fix * updated the title according to convention * applied some updates according to convention * added footnotes, minor improvements * applied tweaks according to review points * the new draft of glossary according to PR #134 * fixed an inconsistant title * minor fix for better compatibility with T points * applied final touches for this round of G updates * [FR] End of chapter 3 + chapter 4 (#137) * add chapters 3 & 4 * Update 2.mdx fix links * Update 3.mdx some fix * Update 6.mdx fix tag * Update 3.mdx add link to chapter 7 * Update 3_tf.mdx add link to chapter 7 * Update _toctree.yml Co-authored-by: DOOHAE JUNG Co-authored-by: m_khandaker Co-authored-by: Md. Al-Amin Khandaker Co-authored-by: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Co-authored-by: Doohae Jung <80743307+Doohae@users.noreply.github.com> Co-authored-by: melaniedrevet Co-authored-by: Jose M Munoz Co-authored-by: svv73 <88366711+svv73@users.noreply.github.com> Co-authored-by: Vedant Pandya Co-authored-by: Bahram Shamshiri Co-authored-by: Giyaseddin Bayrak <34009210+giyaseddin@users.noreply.github.com> Co-authored-by: Pavel <60391448+pdumin@users.noreply.github.com> Co-authored-by: 1375626371 <40328311+1375626371@users.noreply.github.com> Co-authored-by: petrichor1122 <87262598+petrichor1122@users.noreply.github.com> Co-authored-by: zhlhyx <95976146+zhlhyx@users.noreply.github.com> Co-authored-by: João Gustavo A. Amorim Co-authored-by: lbourdois <58078086+lbourdois@users.noreply.github.com> Co-authored-by: Cherdsak Kingkan Co-authored-by: Thomas Chaigneau <50595514+ChainYo@users.noreply.github.com> Co-authored-by: ChainYo Co-authored-by: hiromu <45531573+hiromu166@users.noreply.github.com> Co-authored-by: Cherdsak Kingkan Co-authored-by: Marcus Fraaß Co-authored-by: Jesper Dramsch Co-authored-by: amyeroberts Co-authored-by: Ash <103081562+ashwathim@users.noreply.github.com> Co-authored-by: Hamed Homaei Rad * Bump release (#147) * Bump release (#161) * Fix typos in chapter 9 (#176) (#180) Co-authored-by: regisss <15324346+regisss@users.noreply.github.com> * Bump release (#187) * Chapter 2 Section 1 Bengali Translation (huggingface#72) (#168) * [TH] Chapter 6 Section 1 and 2 (#171) Co-authored-by: Suteera * [FA] CH1 / P1-2 (#142) * Spanish Chapter 3: sections 1 & 2 (#162) * fix typos in bpe, wordpiece, unigram (#166) * [FR] French Review (#186) * Part 7: Training a causal... fixes (#179) * typo & error mitigation * consistency * Trainer.predict() returns 3 fields * ran make style * [TR] Translated Chapter 1.6 🤗 (#185) * added chapter 1/6 to _toctree.yml * [TR] Translated Chapter 1.6 🤗 Co-authored-by: Avishek Das Co-authored-by: Suteera Seeha <33692408+meanna@users.noreply.github.com> Co-authored-by: Suteera Co-authored-by: Saeed Choobani Co-authored-by: Fermin Ordaz Co-authored-by: Kerem Turgutlu Co-authored-by: lbourdois <58078086+lbourdois@users.noreply.github.com> Co-authored-by: Sebastian Sosa <37946988+CakeCrusher@users.noreply.github.com> Co-authored-by: tanersekmen <56790802+tanersekmen@users.noreply.github.com> * Bump release 10 (#194) * Bump release (#195) * Bump release 12 (#209) * Bump release (#224) * Bump release (#229) * Bump release (#236) * Bump release (#258) * Bump release (#270) * Bump release (#274) * Bump release (#286) * Bump release (#288) * Chapter 2 Section 1 Bengali Translation (huggingface#72) (#168) * [TH] Chapter 6 Section 1 and 2 (#171) Co-authored-by: Suteera * [FA] CH1 / P1-2 (#142) * Spanish Chapter 3: sections 1 & 2 (#162) * fix typos in bpe, wordpiece, unigram (#166) * [FR] French Review (#186) * Part 7: Training a causal... fixes (#179) * typo & error mitigation * consistency * Trainer.predict() returns 3 fields * ran make style * [TR] Translated Chapter 1.6 🤗 (#185) * added chapter 1/6 to _toctree.yml * [TR] Translated Chapter 1.6 🤗 * [PT][Chapter 01 - 2.mdx] - issue #51 (#170) * Fix Gradio ToC (#193) * Add Gradio authors and Blocks event (#189) * Update 6.mdx (#188) Correct link to Transformer XL doc * Add translating notes and glossary to Spanish (#192) * Add translating notes and glosary to Spanish * Adding glossary to the toc * add pt 4.3 (#191) * [FR] Visual corrections (#190) * [PT] add chapter 4.4 and 4.5 (#196) * fix invite discord link (#197) * [FA] Second draft of CH2/P1-2 (#139) * added chapter3 in hindi (#198) * [TR] Chapter 3/1 (#165) * [RU] Ch3-1/2/3 (#200) * [PT] add 5.1 and 5.2 (#204) * [FA] - Ch3 - P1 and P2 (#199) * [PT] add `end-of-chapter quiz` for chapter 4 (4.6) (#201) Co-authored-by: lewtun * Chapter1: 2.mdx Translated. (#206) * Remove comments from Persian ToC (#210) * Fix CI URL for PRs (#211) * code fragment & english syntax and meaning (#203) * Updated Ch1/1 with Emoji (#214) * Add missing numpy import (#217) * [ES] translate sections 8.1 and 8.2 (#215) * Fix path to datasets (#216) * [PT] add 5.3 (#218) * fix 4.3 (#223) * Fix notebook generation (#227) * Add Gradio nb links * add 5.4 (#226) * add pt wip (#225) * Added Gujarati List. (#221) * Add Gradio nbs links to fr (#228) * Chinese - Chapter 3finished (#219) * add ch7 at _toctree and translate 7.1 (#222) * add 5.5 (#235) * [FR] Review of chapter 7 (#233) * Italian translation - chapter 4 (#230) * Added Thai translation of chapters 3 (#231) * [Ru] Add part 2, chapter 2 (#234) * Update 8.mdx (#237) - Remove Gradio Blocks Party - Add, Where to next? section * Created HI/Chapter1/5.mdx (#232) * Add Spanish chaper3/section4, update toc and glossary (#238) * [RU] Chapter 3 finished (#239) * [PT] add 5.6 and 5.7 (#240) * [EN] Visual corrections (#245) * Translation for 1/4, 1/5 and 1/6. (#247) * add event in PT (#250) * Pin version of black (#252) * Translate ja event (#241) * [PT] add quiz chapter 5 (#243) * Update 5.mdx (#253) inconsistent naming with line 327 * Translation for Traditional Chinese (zh-tw) chapter0 (#251) Co-authored-by: Lewis Tunstall * Translated the whole Chapter 3 to Thai (#255) * Japanese chapter 4 (#244) * Translation of 1/7, 1/8, and 1/9. (#263) * [PT] add chapter 8.1 and 8.2 (#265) * [RU] Chapter 4 (#269) * Add Thai translation for chapter 6.3b to 6.10 (#268) * add 8.3 (#266) * 3.mdx of chapter 01 (#260) Co-authored-by: Lewis Tunstall * Fix typo (#271) * [PT] add chapter 6.1 (#273) * add Japanese chapter7 (#267) * replace `load_metric` with `evaluate.load` (#285) * update `load_metric` refs to `evaluate.load` Co-authored-by: lewtun * [GJ] Translation to Gujarati - Ch0 Setup (#287) * [PT] add chapter 6.2 and 6.3 (#279) * zh-CN - Chapter 4,5finished (#281) Co-authored-by: Lewis Tunstall * Chapter 01 - Done [PT] #51 (#280) Co-authored-by: Lewis Tunstall Co-authored-by: Avishek Das Co-authored-by: Suteera Seeha <33692408+meanna@users.noreply.github.com> Co-authored-by: Suteera Co-authored-by: Saeed Choobani Co-authored-by: Fermin Ordaz Co-authored-by: Kerem Turgutlu Co-authored-by: lbourdois <58078086+lbourdois@users.noreply.github.com> Co-authored-by: Sebastian Sosa <37946988+CakeCrusher@users.noreply.github.com> Co-authored-by: tanersekmen <56790802+tanersekmen@users.noreply.github.com> Co-authored-by: Victor Costa <54755870+victorescosta@users.noreply.github.com> Co-authored-by: Camille Couturier Co-authored-by: João Gustavo A. Amorim Co-authored-by: Bahram Shamshiri Co-authored-by: Kavya <36916536+robotjellyzone@users.noreply.github.com> Co-authored-by: Batuhan Ayhan Co-authored-by: Pavel <60391448+pdumin@users.noreply.github.com> Co-authored-by: Kambiz Ghoorchian Co-authored-by: Vedant Pandya Co-authored-by: Diego Vargas <91356068+dzarkV@users.noreply.github.com> Co-authored-by: Thomas O'Brien Co-authored-by: Lincoln V Schreiber Co-authored-by: 1375626371 <40328311+1375626371@users.noreply.github.com> Co-authored-by: Giorgio Severi Co-authored-by: svv73 <88366711+svv73@users.noreply.github.com> Co-authored-by: Ömer Faruk Özdemir Co-authored-by: Caterina Bonan <97481648+CaterinaBi@users.noreply.github.com> Co-authored-by: Hiromu Hota Co-authored-by: trtd56 <5toda6@gmail.com> Co-authored-by: Mehrdad Nezamdoost Co-authored-by: Wolvz Co-authored-by: a-krirk <56425947+a-krirk@users.noreply.github.com> Co-authored-by: atgctg <105969161+atgctg@users.noreply.github.com> Co-authored-by: Thiago Medeiros Co-authored-by: webbigdata-jp <87654083+webbigdata-jp@users.noreply.github.com> Co-authored-by: Leandro von Werra Co-authored-by: Bhadresh Savani * Bump release (#295) * Bump release (#296) * Bump release (#299) * Bump release (#305) * Chinese - Chapter 1 finished * Add zh to the languages field Add zh to the languages field in the build_documentation.yml and build_pr_documentation.yml files * Remove untranslated chapters in _toctree.yml Remove all these sections that haven't been translated yet Remove Chapter 0 from the table of contents since it hasn't been translated yet * Fixed an error in the translation format Fixed an error in the translation format of Chapter 1, Section 3 * Added a small part of the missing content * Fix style * Complete the translation of Chapters 0 and 2 * Fixed some bugs ·Fixed some formatting errors ·Moved Chapters 0 and 2 to Simplified Chinese * Add files via upload Formatting revisions and some translation corrections * run make style to format chapter1 session3 * run make style to format code * run make style to format code * Fix style * Chapter 2 Section 1 Bengali Translation (huggingface#72) (#168) * [TH] Chapter 6 Section 1 and 2 (#171) Co-authored-by: Suteera * [FA] CH1 / P1-2 (#142) * Spanish Chapter 3: sections 1 & 2 (#162) * fix typos in bpe, wordpiece, unigram (#166) * [FR] French Review (#186) * Part 7: Training a causal... fixes (#179) * typo & error mitigation * consistency * Trainer.predict() returns 3 fields * ran make style * [TR] Translated Chapter 1.6 🤗 (#185) * added chapter 1/6 to _toctree.yml * [TR] Translated Chapter 1.6 🤗 * [PT][Chapter 01 - 2.mdx] - issue #51 (#170) * Fix Gradio ToC (#193) * Add Gradio authors and Blocks event (#189) * Update 6.mdx (#188) Correct link to Transformer XL doc * Add translating notes and glossary to Spanish (#192) * Add translating notes and glosary to Spanish * Adding glossary to the toc * add pt 4.3 (#191) * [FR] Visual corrections (#190) * [PT] add chapter 4.4 and 4.5 (#196) * fix invite discord link (#197) * [FA] Second draft of CH2/P1-2 (#139) * added chapter3 in hindi (#198) * [TR] Chapter 3/1 (#165) * [RU] Ch3-1/2/3 (#200) * [PT] add 5.1 and 5.2 (#204) * Add placeholders for audio chapters (#208) * [FA] - Ch3 - P1 and P2 (#199) * [PT] add `end-of-chapter quiz` for chapter 4 (4.6) (#201) Co-authored-by: lewtun * Chapter1: 2.mdx Translated. (#206) * Remove comments from Persian ToC (#210) * Fix CI URL for PRs (#211) * code fragment & english syntax and meaning (#203) * Updated Ch1/1 with Emoji (#214) * Add missing numpy import (#217) * Updata chapter3 * Code format for chapter3 * Updata yml file of chapter3 * Uptata yml file of chapter3 * Fix yml file bug * [ES] translate sections 8.1 and 8.2 (#215) * Fix path to datasets (#216) * [PT] add 5.3 (#218) * fix 4.3 (#223) * Run make style * Fix notebook generation (#227) * Add Gradio nb links * add 5.4 (#226) * add pt wip (#225) * Added Gujarati List. (#221) * Fix quality * Add Gradio nbs links to fr (#228) * Fix ToC tree * Remove audio templates * Fix fr section * Fix fr chapter * Chinese - Chapter 3finished (#219) * add ch7 at _toctree and translate 7.1 (#222) * add 5.5 (#235) * [FR] Review of chapter 7 (#233) * Italian translation - chapter 4 (#230) * Added Thai translation of chapters 3 (#231) * [Ru] Add part 2, chapter 2 (#234) * Update 8.mdx (#237) - Remove Gradio Blocks Party - Add, Where to next? section * Created HI/Chapter1/5.mdx (#232) * Add Spanish chaper3/section4, update toc and glossary (#238) * [RU] Chapter 3 finished (#239) * [PT] add 5.6 and 5.7 (#240) * [EN] Visual corrections (#245) * Translation for 1/4, 1/5 and 1/6. (#247) * add event in PT (#250) * Pin version of black (#252) * Translate ja event (#241) * [PT] add quiz chapter 5 (#243) * Update 5.mdx (#253) inconsistent naming with line 327 * Translation for Traditional Chinese (zh-tw) chapter0 (#251) Co-authored-by: Lewis Tunstall * Translated the whole Chapter 3 to Thai (#255) * Japanese chapter 4 (#244) * Translation of 1/7, 1/8, and 1/9. (#263) * [PT] add chapter 8.1 and 8.2 (#265) * [RU] Chapter 4 (#269) * Add Thai translation for chapter 6.3b to 6.10 (#268) * add 8.3 (#266) * 3.mdx of chapter 01 (#260) Co-authored-by: Lewis Tunstall * Fix typo (#271) * [PT] add chapter 6.1 (#273) * add Japanese chapter7 (#267) * zh-CN - Chapter 4,5finished * replace `load_metric` with `evaluate.load` (#285) * update `load_metric` refs to `evaluate.load` Co-authored-by: lewtun * [GJ] Translation to Gujarati - Ch0 Setup (#287) * [PT] add chapter 6.2 and 6.3 (#279) * Fix formatting * Debug formatting * Debug FR formatting * zh-CN - Chapter 4,5finished (#281) Co-authored-by: Lewis Tunstall * Chapter 01 - Done [PT] #51 (#280) Co-authored-by: Lewis Tunstall * tf_default_data_collator seems to have moved * zh-CN - Chapter 6finished * Revert "Merge branch 'huggingface:main' into main" This reverts commit aebb46e12f9f87a4303f8bb4f0f2cf545eb83b21, reversing changes made to 69187a3789e8d3d2d0de821ebe495f111d1cc73d. * Revert "zh-CN - Chapter 6finished" This reverts commit e69fce28d3a7b35b76c4f768a6cedf295b37d8c9. * zh-CN - Chapter 6finished * fix style * undo bad commit * Chapter5it (#278) * added the italian translation for unit 1 chapter5 Co-authored-by: Leandro von Werra * Vietnamese translation (#293) * Update .github/workflows/build_pr_documentation.yml Co-authored-by: lewtun * Translate JP chapter 8 (#249) * Italian translation - Chapter 8 (#272) * Translation to Vietnamese - chapter 5 (#297) * Add course contributors (#298) * Add CourseFloatingBanner component * DocNotebookDropdown -> CourseFloatingBanner * Italian translation Ch 2/1, 2/2 (#300) * Add contributors (#304) * Add forum button (#306) Co-authored-by: 1375626371 <40328311+1375626371@users.noreply.github.com> Co-authored-by: 1375626371 <1375626371@qq.com> Co-authored-by: Avishek Das Co-authored-by: Suteera Seeha <33692408+meanna@users.noreply.github.com> Co-authored-by: Suteera Co-authored-by: Saeed Choobani Co-authored-by: Fermin Ordaz Co-authored-by: Kerem Turgutlu Co-authored-by: lbourdois <58078086+lbourdois@users.noreply.github.com> Co-authored-by: Sebastian Sosa <37946988+CakeCrusher@users.noreply.github.com> Co-authored-by: tanersekmen <56790802+tanersekmen@users.noreply.github.com> Co-authored-by: Victor Costa <54755870+victorescosta@users.noreply.github.com> Co-authored-by: Camille Couturier Co-authored-by: João Gustavo A. Amorim Co-authored-by: Bahram Shamshiri Co-authored-by: Kavya <36916536+robotjellyzone@users.noreply.github.com> Co-authored-by: Batuhan Ayhan Co-authored-by: Pavel <60391448+pdumin@users.noreply.github.com> Co-authored-by: Kambiz Ghoorchian Co-authored-by: Vedant Pandya Co-authored-by: Diego Vargas <91356068+dzarkV@users.noreply.github.com> Co-authored-by: Thomas O'Brien Co-authored-by: Lincoln V Schreiber Co-authored-by: Giorgio Severi Co-authored-by: svv73 <88366711+svv73@users.noreply.github.com> Co-authored-by: Ömer Faruk Özdemir Co-authored-by: Caterina Bonan <97481648+CaterinaBi@users.noreply.github.com> Co-authored-by: Hiromu Hota Co-authored-by: trtd56 <5toda6@gmail.com> Co-authored-by: Mehrdad Nezamdoost Co-authored-by: Wolvz Co-authored-by: a-krirk <56425947+a-krirk@users.noreply.github.com> Co-authored-by: atgctg <105969161+atgctg@users.noreply.github.com> Co-authored-by: Thiago Medeiros Co-authored-by: webbigdata-jp <87654083+webbigdata-jp@users.noreply.github.com> Co-authored-by: Leandro von Werra Co-authored-by: Bhadresh Savani Co-authored-by: Andreas Ehrencrona Co-authored-by: leandro Co-authored-by: Matt Co-authored-by: Nolanogenn <52080100+Nolanogenn@users.noreply.github.com> Co-authored-by: Hồng Hạnh Co-authored-by: Younes Belkada <49240599+younesbelkada@users.noreply.github.com> Co-authored-by: Edoardo Abati <29585319+EdAbati@users.noreply.github.com> Co-authored-by: Mishig Davaadorj Co-authored-by: Acciaro Gennaro Daniele * Bump release (#307) * Bump release (#308) * Bump release (#314) * Bump release (#320) * Bump release (#328) * Bump release (#333) * Bump release (#335) * Bump release (#343) * Bump release (#355) * Bump release (#358) * Bump release (#371) * Bump release (#381) * Bump release (#387) * Bump release (#404) * Bump release (#413) * Bump release (#426) * Bump release (#463) --------- Co-authored-by: DOOHAE JUNG Co-authored-by: m_khandaker Co-authored-by: Md. Al-Amin Khandaker Co-authored-by: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Co-authored-by: Doohae Jung <80743307+Doohae@users.noreply.github.com> Co-authored-by: melaniedrevet Co-authored-by: Jose M Munoz Co-authored-by: svv73 <88366711+svv73@users.noreply.github.com> Co-authored-by: Vedant Pandya Co-authored-by: Bahram Shamshiri Co-authored-by: Giyaseddin Bayrak <34009210+giyaseddin@users.noreply.github.com> Co-authored-by: Pavel <60391448+pdumin@users.noreply.github.com> Co-authored-by: 1375626371 <40328311+1375626371@users.noreply.github.com> Co-authored-by: petrichor1122 <87262598+petrichor1122@users.noreply.github.com> Co-authored-by: zhlhyx <95976146+zhlhyx@users.noreply.github.com> Co-authored-by: João Gustavo A. Amorim Co-authored-by: lbourdois <58078086+lbourdois@users.noreply.github.com> Co-authored-by: Cherdsak Kingkan Co-authored-by: Thomas Chaigneau <50595514+ChainYo@users.noreply.github.com> Co-authored-by: ChainYo Co-authored-by: hiromu <45531573+hiromu166@users.noreply.github.com> Co-authored-by: Cherdsak Kingkan Co-authored-by: Marcus Fraaß Co-authored-by: Jesper Dramsch Co-authored-by: amyeroberts Co-authored-by: Ash <103081562+ashwathim@users.noreply.github.com> Co-authored-by: Hamed Homaei Rad Co-authored-by: Dawood Khan Co-authored-by: regisss <15324346+regisss@users.noreply.github.com> Co-authored-by: Avishek Das Co-authored-by: Suteera Seeha <33692408+meanna@users.noreply.github.com> Co-authored-by: Suteera Co-authored-by: Saeed Choobani Co-authored-by: Fermin Ordaz Co-authored-by: Kerem Turgutlu Co-authored-by: Sebastian Sosa <37946988+CakeCrusher@users.noreply.github.com> Co-authored-by: tanersekmen <56790802+tanersekmen@users.noreply.github.com> Co-authored-by: Victor Costa <54755870+victorescosta@users.noreply.github.com> Co-authored-by: Camille Couturier Co-authored-by: Kavya <36916536+robotjellyzone@users.noreply.github.com> Co-authored-by: Batuhan Ayhan Co-authored-by: Kambiz Ghoorchian Co-authored-by: Diego Vargas <91356068+dzarkV@users.noreply.github.com> Co-authored-by: Thomas O'Brien Co-authored-by: Lincoln V Schreiber Co-authored-by: Giorgio Severi Co-authored-by: Ömer Faruk Özdemir Co-authored-by: Caterina Bonan <97481648+CaterinaBi@users.noreply.github.com> Co-authored-by: Hiromu Hota Co-authored-by: trtd56 <5toda6@gmail.com> Co-authored-by: Mehrdad Nezamdoost Co-authored-by: Wolvz Co-authored-by: a-krirk <56425947+a-krirk@users.noreply.github.com> Co-authored-by: atgctg <105969161+atgctg@users.noreply.github.com> Co-authored-by: Thiago Medeiros Co-authored-by: webbigdata-jp <87654083+webbigdata-jp@users.noreply.github.com> Co-authored-by: Leandro von Werra Co-authored-by: Bhadresh Savani Co-authored-by: 1375626371 <1375626371@qq.com> Co-authored-by: Andreas Ehrencrona Co-authored-by: leandro Co-authored-by: Matt Co-authored-by: Nolanogenn <52080100+Nolanogenn@users.noreply.github.com> Co-authored-by: Hồng Hạnh Co-authored-by: Younes Belkada <49240599+younesbelkada@users.noreply.github.com> Co-authored-by: Edoardo Abati <29585319+EdAbati@users.noreply.github.com> Co-authored-by: Mishig Davaadorj Co-authored-by: Acciaro Gennaro Daniele --- utils/generate_subtitles.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/generate_subtitles.py b/utils/generate_subtitles.py index 68592830f..7de26249e 100644 --- a/utils/generate_subtitles.py +++ b/utils/generate_subtitles.py @@ -75,6 +75,7 @@ def generate_subtitles(language: str, youtube_language_code: str = None, is_task + if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--language", type=str, help="Language to generate subtitles for") From 9c44804ab7a97f80040d117117da004fe2c6e9dc Mon Sep 17 00:00:00 2001 From: lewtun Date: Wed, 10 May 2023 21:06:50 +0200 Subject: [PATCH 266/502] Revert "Bump release (#566)" (#567) This reverts commit cccc2c91ac8e702e5e14bbb0419dbf0490c7aaaf. --- utils/generate_subtitles.py | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/generate_subtitles.py b/utils/generate_subtitles.py index 7de26249e..68592830f 100644 --- a/utils/generate_subtitles.py +++ b/utils/generate_subtitles.py @@ -75,7 +75,6 @@ def generate_subtitles(language: str, youtube_language_code: str = None, is_task - if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--language", type=str, help="Language to generate subtitles for") From 86f439601936919f65a6c1f9e792d625844b9a3a Mon Sep 17 00:00:00 2001 From: nnoboa Date: Sun, 4 Jun 2023 13:18:41 -0400 Subject: [PATCH 267/502] updated documentation links --- chapters/en/chapter1/5.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chapters/en/chapter1/5.mdx b/chapters/en/chapter1/5.mdx index 477dd128f..89694ee83 100644 --- a/chapters/en/chapter1/5.mdx +++ b/chapters/en/chapter1/5.mdx @@ -15,8 +15,8 @@ Encoder models are best suited for tasks requiring an understanding of the full Representatives of this family of models include: -- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html) -- [BERT](https://huggingface.co/transformers/model_doc/bert.html) -- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) -- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) -- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) +- [ALBERT](https://huggingface.co/docs/transformers/model_doc/albert) +- [BERT](https://huggingface.co/docs/transformers/model_doc/bert) +- [DistilBERT](https://huggingface.co/docs/transformers/model_doc/distilbert) +- [ELECTRA](https://huggingface.co/docs/transformers/model_doc/electra) +- [RoBERTa](https://huggingface.co/docs/transformers/model_doc/roberta) From 0018bb434204d9750a03592cb0d4e846093218d8 Mon Sep 17 00:00:00 2001 From: Mishig Date: Fri, 9 Jun 2023 11:23:45 +0200 Subject: [PATCH 268/502] [doc build] Use secrets (#581) --- .github/workflows/build_documentation.yml | 1 + .github/workflows/build_pr_documentation.yml | 1 - .github/workflows/delete_doc_comment.yml | 14 +++++++------- .../workflows/delete_doc_comment_trigger.yml | 12 ++++++++++++ .github/workflows/upload_pr_documentation.yml | 17 +++++++++++++++++ 5 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/delete_doc_comment_trigger.yml create mode 100644 .github/workflows/upload_pr_documentation.yml diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index b09b32f58..fc3c24562 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -17,3 +17,4 @@ jobs: languages: ar bn de en es fa fr gj he hi id it ja ko pt ru th tr vi zh-CN zh-TW secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} + hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }} diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index 45e3b3e09..a568b16f4 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -17,4 +17,3 @@ jobs: path_to_docs: course/chapters/ additional_args: --not_python_module languages: ar bn de en es fa fr gj he hi id it ja ko pt ru th tr vi zh-CN zh-TW - hub_base_path: https://moon-ci-docs.huggingface.co diff --git a/.github/workflows/delete_doc_comment.yml b/.github/workflows/delete_doc_comment.yml index 9ec2aaf44..72801c856 100644 --- a/.github/workflows/delete_doc_comment.yml +++ b/.github/workflows/delete_doc_comment.yml @@ -1,13 +1,13 @@ -name: Delete dev documentation +name: Delete doc comment on: - pull_request: - types: [ closed ] - + workflow_run: + workflows: ["Delete doc comment trigger"] + types: + - completed jobs: delete: uses: huggingface/doc-builder/.github/workflows/delete_doc_comment.yml@main - with: - pr_number: ${{ github.event.number }} - package: course \ No newline at end of file + secrets: + comment_bot_token: ${{ secrets.COMMENT_BOT_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/delete_doc_comment_trigger.yml b/.github/workflows/delete_doc_comment_trigger.yml new file mode 100644 index 000000000..5e39e2539 --- /dev/null +++ b/.github/workflows/delete_doc_comment_trigger.yml @@ -0,0 +1,12 @@ +name: Delete doc comment trigger + +on: + pull_request: + types: [ closed ] + + +jobs: + delete: + uses: huggingface/doc-builder/.github/workflows/delete_doc_comment_trigger.yml@main + with: + pr_number: ${{ github.event.number }} \ No newline at end of file diff --git a/.github/workflows/upload_pr_documentation.yml b/.github/workflows/upload_pr_documentation.yml new file mode 100644 index 000000000..446433459 --- /dev/null +++ b/.github/workflows/upload_pr_documentation.yml @@ -0,0 +1,17 @@ +name: Upload PR Documentation + +on: + workflow_run: + workflows: ["Build PR Documentation"] + types: + - completed + +jobs: + build: + uses: huggingface/doc-builder/.github/workflows/upload_pr_documentation.yml@main + with: + package_name: course + hub_base_path: https://moon-ci-docs.huggingface.co + secrets: + hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }} + comment_bot_token: ${{ secrets.COMMENT_BOT_TOKEN }} \ No newline at end of file From ceef93d457bb11ac864da184b33a37070be76de7 Mon Sep 17 00:00:00 2001 From: Vipula Sandaruwan Dissanayake Date: Thu, 15 Jun 2023 15:04:23 +1200 Subject: [PATCH 269/502] docs: fix broken links --- chapters/en/chapter2/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter2/5.mdx b/chapters/en/chapter2/5.mdx index 81d496fef..199877efb 100644 --- a/chapters/en/chapter2/5.mdx +++ b/chapters/en/chapter2/5.mdx @@ -329,7 +329,7 @@ With Transformer models, there is a limit to the lengths of the sequences we can - Use a model with a longer supported sequence length. - Truncate your sequences. -Models have different supported sequence lengths, and some specialize in handling very long sequences. [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) is one example, and another is [LED](https://huggingface.co/transformers/model_doc/led.html). If you're working on a task that requires very long sequences, we recommend you take a look at those models. +Models have different supported sequence lengths, and some specialize in handling very long sequences. [Longformer](https://huggingface.co/docs/transformers/model_doc/longformer) is one example, and another is [LED](https://huggingface.co/docs/transformers/model_doc/led). If you're working on a task that requires very long sequences, we recommend you take a look at those models. Otherwise, we recommend you truncate your sequences by specifying the `max_sequence_length` parameter: From f6ded40ec200b1a524f3f03f79934d12e98ac24c Mon Sep 17 00:00:00 2001 From: Alex Bzdel Date: Thu, 22 Jun 2023 16:36:05 -0400 Subject: [PATCH 270/502] changed 'perspires' to 'persists' in chapter 1 quiz solves issue #585 --- chapters/en/chapter1/10.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter1/10.mdx b/chapters/en/chapter1/10.mdx index cb0ca145c..1e14a5c95 100644 --- a/chapters/en/chapter1/10.mdx +++ b/chapters/en/chapter1/10.mdx @@ -241,7 +241,7 @@ result = classifier("This is a course about the Transformers library") choices={[ { text: "The model is a fine-tuned version of a pretrained model and it picked up its bias from it.", - explain: "When applying Transfer Learning, the bias in the pretrained model used perspires in the fine-tuned model.", + explain: "When applying Transfer Learning, the bias in the pretrained model used persists in the fine-tuned model.", correct: true }, { From 333d7fe7539c0f9627191d12681ddc2fb0140092 Mon Sep 17 00:00:00 2001 From: JieShen <49408146+JieShenAI@users.noreply.github.com> Date: Sat, 24 Jun 2023 19:32:39 +0800 Subject: [PATCH 271/502] Update 4.mdx You forgot to write a return for this function. --- chapters/zh-CN/chapter7/4.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/chapters/zh-CN/chapter7/4.mdx b/chapters/zh-CN/chapter7/4.mdx index a88dc2777..bb15ba4c7 100644 --- a/chapters/zh-CN/chapter7/4.mdx +++ b/chapters/zh-CN/chapter7/4.mdx @@ -225,6 +225,7 @@ def preprocess_function(examples): model_inputs = tokenizer( inputs, text_target=targets, max_length=max_length, truncation=True ) + return model_inputs ``` 请注意,我们为输入和输出设置了相同的最大长度。由于我们处理的文本看起来很短,我们使用 128。 From 773e88a34eb8cd9725c684bb8a786fa7ec063472 Mon Sep 17 00:00:00 2001 From: Heo GeonYeong Date: Tue, 27 Jun 2023 09:47:28 +0900 Subject: [PATCH 272/502] Fix Typo (huggingface#588) --- chapters/ko/chapter1/9.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ko/chapter1/9.mdx b/chapters/ko/chapter1/9.mdx index 9fee845cc..1eff01f0d 100644 --- a/chapters/ko/chapter1/9.mdx +++ b/chapters/ko/chapter1/9.mdx @@ -13,4 +13,4 @@ | --- | --- | --- | | 인코더 | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa | 문장 분류, 개체명 인식, 추출 질의 응답 | | 디코더 | CTRL, GPT, GPT-2, Transformer XL | 텍스트 생성 | -| 인코더-디코더 | BART, T5, Marian, mBART | 오약, 번역, 생성 질의 응답 | \ No newline at end of file +| 인코더-디코더 | BART, T5, Marian, mBART | 요약, 번역, 생성 질의 응답 | From b3cfa9c3e1b6b56195a2e1bdef85182c92dfb10a Mon Sep 17 00:00:00 2001 From: Hardik Bhadani Date: Sat, 5 Aug 2023 16:11:34 +0530 Subject: [PATCH 273/502] Update 4.mdx : Fix Typo Should be "course" --- chapters/en/chapter1/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter1/4.mdx b/chapters/en/chapter1/4.mdx index 80f692852..918af3016 100644 --- a/chapters/en/chapter1/4.mdx +++ b/chapters/en/chapter1/4.mdx @@ -144,7 +144,7 @@ We will dive into those architectures independently in later sections. A key feature of Transformer models is that they are built with special layers called *attention layers*. In fact, the title of the paper introducing the Transformer architecture was ["Attention Is All You Need"](https://arxiv.org/abs/1706.03762)! We will explore the details of attention layers later in the course; for now, all you need to know is that this layer will tell the model to pay specific attention to certain words in the sentence you passed it (and more or less ignore the others) when dealing with the representation of each word. -To put this into context, consider the task of translating text from English to French. Given the input "You like this course", a translation model will need to also attend to the adjacent word "You" to get the proper translation for the word "like", because in French the verb "like" is conjugated differently depending on the subject. The rest of the sentence, however, is not useful for the translation of that word. In the same vein, when translating "this" the model will also need to pay attention to the word "course", because "this" translates differently depending on whether the associated noun is masculine or feminine. Again, the other words in the sentence will not matter for the translation of "this". With more complex sentences (and more complex grammar rules), the model would need to pay special attention to words that might appear farther away in the sentence to properly translate each word. +To put this into context, consider the task of translating text from English to French. Given the input "You like this course", a translation model will need to also attend to the adjacent word "You" to get the proper translation for the word "like", because in French the verb "like" is conjugated differently depending on the subject. The rest of the sentence, however, is not useful for the translation of that word. In the same vein, when translating "this" the model will also need to pay attention to the word "course", because "this" translates differently depending on whether the associated noun is masculine or feminine. Again, the other words in the sentence will not matter for the translation of "course". With more complex sentences (and more complex grammar rules), the model would need to pay special attention to words that might appear farther away in the sentence to properly translate each word. The same concept applies to any task associated with natural language: a word by itself has a meaning, but that meaning is deeply affected by the context, which can be any other word (or words) before or after the word being studied. From 77df7287ec187848ac04dce0e2ed97ddacafacfa Mon Sep 17 00:00:00 2001 From: Dawood Date: Tue, 19 Sep 2023 10:48:40 -0400 Subject: [PATCH 274/502] fix link --- chapters/en/events/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/events/3.mdx b/chapters/en/events/3.mdx index d74b9c206..2f7e69063 100644 --- a/chapters/en/events/3.mdx +++ b/chapters/en/events/3.mdx @@ -6,4 +6,4 @@ You can find all the demos that the community created under the [`Gradio-Blocks` **Natural language to SQL** - + From 2af483123fe87a390ac7c4c22cbdfd8a5057234a Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:44:53 +0530 Subject: [PATCH 275/502] Update 2.mdx updated loading datasets link --- chapters/de/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/de/chapter3/2.mdx b/chapters/de/chapter3/2.mdx index 49a025c1a..50a183761 100644 --- a/chapters/de/chapter3/2.mdx +++ b/chapters/de/chapter3/2.mdx @@ -84,7 +84,7 @@ In diesem Abschnitt verwenden wir den MRPC-Datensatz (Microsoft Research Paraphr {/if} -Das Hub enthält nicht nur Modelle; Es hat auch mehrere Datensätze in vielen verschiedenen Sprachen. Du kannst die Datensätze [hier](https://huggingface.co/datasets) durchsuchen, und wir empfehlen, einen weiteren Datensatz zu laden und zu verarbeiten, sobald Sie diesen Abschnitt abgeschlossen haben (die Dokumentation befindet sich [hier](https: //huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). Aber jetzt konzentrieren wir uns auf den MRPC-Datensatz! Dies ist einer der 10 Datensätze, aus denen sich das [GLUE-Benchmark](https://gluebenchmark.com/) zusammensetzt. Dies ist ein akademisches Benchmark, das verwendet wird, um die Performance von ML-Modellen in 10 verschiedenen Textklassifizierungsaufgaben zu messen. +Das Hub enthält nicht nur Modelle; Es hat auch mehrere Datensätze in vielen verschiedenen Sprachen. Du kannst die Datensätze [hier](https://huggingface.co/datasets) durchsuchen, und wir empfehlen, einen weiteren Datensatz zu laden und zu verarbeiten, sobald Sie diesen Abschnitt abgeschlossen haben (die Dokumentation befindet sich [hier](https://huggingface.co/docs/datasets/loading)). Aber jetzt konzentrieren wir uns auf den MRPC-Datensatz! Dies ist einer der 10 Datensätze, aus denen sich das [GLUE-Benchmark](https://gluebenchmark.com/) zusammensetzt. Dies ist ein akademisches Benchmark, das verwendet wird, um die Performance von ML-Modellen in 10 verschiedenen Textklassifizierungsaufgaben zu messen. Die Bibliothek 🤗 Datasets bietet einen leichten Befehl zum Herunterladen und Caching eines Datensatzes aus dem Hub. Wir können den MRPC-Datensatz wie folgt herunterladen: From b88cae11a5743880a201e72eadabd54d44267f70 Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:45:28 +0530 Subject: [PATCH 276/502] Update 2.mdx updated loading datasets link --- chapters/en/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter3/2.mdx b/chapters/en/chapter3/2.mdx index 22852fb0c..f64747dac 100644 --- a/chapters/en/chapter3/2.mdx +++ b/chapters/en/chapter3/2.mdx @@ -84,7 +84,7 @@ In this section we will use as an example the MRPC (Microsoft Research Paraphras {/if} -The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. +The Hub doesn't just contain models; it also has multiple datasets in lots of different languages. You can browse the datasets [here](https://huggingface.co/datasets), and we recommend you try to load and process a new dataset once you have gone through this section (see the general documentation [here](https://huggingface.co/docs/datasets/loading)). But for now, let's focus on the MRPC dataset! This is one of the 10 datasets composing the [GLUE benchmark](https://gluebenchmark.com/), which is an academic benchmark that is used to measure the performance of ML models across 10 different text classification tasks. The 🤗 Datasets library provides a very simple command to download and cache a dataset on the Hub. We can download the MRPC dataset like this: From 52ec6a93bc4a7e8ff740ed00535d3b6d4c578d6b Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:45:59 +0530 Subject: [PATCH 277/502] Update 2.mdx updated loading datasets link --- chapters/es/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/es/chapter3/2.mdx b/chapters/es/chapter3/2.mdx index eded26291..9be89bb79 100644 --- a/chapters/es/chapter3/2.mdx +++ b/chapters/es/chapter3/2.mdx @@ -84,7 +84,7 @@ En esta sección usaremos como ejemplo el conjunto de datos MRPC (Cuerpo de par {/if} -El Hub no solo contiene modelos; sino que también tiene múltiples conjunto de datos en diferentes idiomas. Puedes explorar los conjuntos de datos [aquí](https://huggingface.co/datasets), y recomendamos que trates de cargar y procesar un nuevo conjunto de datos una vez que hayas revisado esta sección (mira la documentación general [aquí](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). Por ahora, enfoquémonos en el conjunto de datos MRPC! Este es uno de los 10 conjuntos de datos que comprende el [punto de referencia GLUE](https://gluebenchmark.com/), el cual es un punto de referencia académico que se usa para medir el desempeño de modelos ML sobre 10 tareas de clasificación de texto. +El Hub no solo contiene modelos; sino que también tiene múltiples conjunto de datos en diferentes idiomas. Puedes explorar los conjuntos de datos [aquí](https://huggingface.co/datasets), y recomendamos que trates de cargar y procesar un nuevo conjunto de datos una vez que hayas revisado esta sección (mira la documentación general [aquí](https://huggingface.co/docs/datasets/loading)). Por ahora, enfoquémonos en el conjunto de datos MRPC! Este es uno de los 10 conjuntos de datos que comprende el [punto de referencia GLUE](https://gluebenchmark.com/), el cual es un punto de referencia académico que se usa para medir el desempeño de modelos ML sobre 10 tareas de clasificación de texto. La Libreria Datasets 🤗 provee un comando muy simple para descargar y memorizar un conjunto de datos en el Hub. Podemos descargar el conjunto de datos de la siguiente manera: From 812f00abe88af0f54b2779f3ed341ff50b79f1a1 Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:46:43 +0530 Subject: [PATCH 278/502] Update 2.mdx updated loading datasets link --- chapters/fa/chapter3/2.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index d553572ad..07d933cc6 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -99,7 +99,7 @@ model.train_on_batch(batch, labels) {/if} -هاب تنها شامل مدل‌ها نمی‌باشد؛ بلکه شامل دیتاسِت‌های متعدد در بسیاری از زبان‌های مختلف می‌باشد. شما می‌توانید دیتاسِت‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک دیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) مشاهده کنید). اما اجازه بدهید اکنون روی دیتاسِت MRPC تمرکز کنیم! این یکی از ۱۰ دیتاسِت [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدل‌های یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. +هاب تنها شامل مدل‌ها نمی‌باشد؛ بلکه شامل دیتاسِت‌های متعدد در بسیاری از زبان‌های مختلف می‌باشد. شما می‌توانید دیتاسِت‌ها را در این [لینک](https://huggingface.co/datasets) جستجو کنید و پیشنهاد می‌کنیم پس از اتمام این بخش یک دیتاسِت جدید را دریافت و پردازش کنید (بخش مستندات عمومی را در [اینجا](https://huggingface.co/docs/datasets/loading) مشاهده کنید). اما اجازه بدهید اکنون روی دیتاسِت MRPC تمرکز کنیم! این یکی از ۱۰ دیتاسِت [GLUE benchmark](https://gluebenchmark.com/) است که یک محک تهیه شده در محیط دانشگاهی جهت اندازه گیری کارکرد مدل‌های یادگیری ماشینی در ۱۰ مسئله دسته‌بندی متن مختلف می‌باشد. کتابخانه دیتاسِت هاگینگ‌فِیس یک دستور بسیار ساده جهت دانلود و انبار کردن یک دیتاسِت در هاب ارائه می‌کند. ما می‌توانیم دیتاسِت MRPC را به روش زیر دانلود کنیم: @@ -498,4 +498,4 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( [^1]: Microsoft Research Paraphrase Corpus -
\ No newline at end of file +
From 5a99fa24f2568b0771611f0708828ee1520178dc Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:47:13 +0530 Subject: [PATCH 279/502] Update 2.mdx updated loading datasets link --- chapters/fr/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fr/chapter3/2.mdx b/chapters/fr/chapter3/2.mdx index 6e36b38df..70b529f7b 100644 --- a/chapters/fr/chapter3/2.mdx +++ b/chapters/fr/chapter3/2.mdx @@ -92,7 +92,7 @@ Dans cette section, nous allons utiliser comme exemple le jeu de données MRPC ( {/if} -Le *Hub* ne contient pas seulement des modèles mais aussi plusieurs jeux de données dans un tas de langues différentes. Vous pouvez explorer les jeux de données [ici](https://huggingface.co/datasets) et nous vous conseillons d'essayer de charger un nouveau jeu de données une fois que vous avez étudié cette section (voir la documentation générale [ici](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). Mais pour l'instant, concentrons-nous sur le jeu de données MRPC ! Il s'agit de l'un des 10 jeux de données qui constituent le [*benchmark* GLUE](https://gluebenchmark.com/) qui est un *benchmark* académique utilisé pour mesurer les performances des modèles d'apprentissage automatique sur 10 différentes tâches de classification de textes. +Le *Hub* ne contient pas seulement des modèles mais aussi plusieurs jeux de données dans un tas de langues différentes. Vous pouvez explorer les jeux de données [ici](https://huggingface.co/datasets) et nous vous conseillons d'essayer de charger un nouveau jeu de données une fois que vous avez étudié cette section (voir la documentation générale [ici](https://huggingface.co/docs/datasets/loading)). Mais pour l'instant, concentrons-nous sur le jeu de données MRPC ! Il s'agit de l'un des 10 jeux de données qui constituent le [*benchmark* GLUE](https://gluebenchmark.com/) qui est un *benchmark* académique utilisé pour mesurer les performances des modèles d'apprentissage automatique sur 10 différentes tâches de classification de textes. La bibliothèque 🤗 *Datasets* propose une commande très simple pour télécharger et mettre en cache un jeu de données à partir du *Hub*. On peut télécharger le jeu de données MRPC comme ceci : From 0e84926f25c8911bc16dec146354827c506c5f2a Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:47:49 +0530 Subject: [PATCH 280/502] Update 2.mdx updated loading datasets link --- chapters/hi/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/hi/chapter3/2.mdx b/chapters/hi/chapter3/2.mdx index eb45b962d..481fc824f 100644 --- a/chapters/hi/chapter3/2.mdx +++ b/chapters/hi/chapter3/2.mdx @@ -84,7 +84,7 @@ model.train_on_batch(batch, labels) {/if} -हब में केवल मॉडल ही नहीं हैं; इसमें कई अलग-अलग भाषाओं में कई डेटासेट भी हैं। आप [यहां](https://huggingface.co/datasets) डेटासेट ब्राउज़ कर सकते हैं, और हम अनुशंसा करते हैं कि आप इस अनुभाग को पढ़ने के बाद एक नए डेटासेट को लोड और संसाधित करने का प्रयास करें ([यहां](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub) सामान्य दस्तावेज देखें)। लेकिन अभी के लिए, आइए MRPC डेटासेट पर ध्यान दें! यह [GLUE बेंचमार्क](https://gluebenchmark.com/) की रचना करने वाले 10 डेटासेट में से एक है, जो एक अकादमिक बेंचमार्क है जिसका उपयोग 10 अलग-अलग पाठ वर्गीकरण कार्यों में ML मॉडल के प्रदर्शन को मापने के लिए किया जाता है। +हब में केवल मॉडल ही नहीं हैं; इसमें कई अलग-अलग भाषाओं में कई डेटासेट भी हैं। आप [यहां](https://huggingface.co/datasets) डेटासेट ब्राउज़ कर सकते हैं, और हम अनुशंसा करते हैं कि आप इस अनुभाग को पढ़ने के बाद एक नए डेटासेट को लोड और संसाधित करने का प्रयास करें ([यहां](https://huggingface.co/docs/datasets/loading) सामान्य दस्तावेज देखें)। लेकिन अभी के लिए, आइए MRPC डेटासेट पर ध्यान दें! यह [GLUE बेंचमार्क](https://gluebenchmark.com/) की रचना करने वाले 10 डेटासेट में से एक है, जो एक अकादमिक बेंचमार्क है जिसका उपयोग 10 अलग-अलग पाठ वर्गीकरण कार्यों में ML मॉडल के प्रदर्शन को मापने के लिए किया जाता है। 🤗 डेटासेट लाइब्रेरी एक बहुत ही सरल कमांड प्रदान करती है हब पर डेटासेट को डाउनलोड और कैश करने के लिए। हम MRPC डेटासेट को इस तरह डाउनलोड कर सकते हैं: From 82e991b6463de3620582e7d0a099718d8276bb76 Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:48:18 +0530 Subject: [PATCH 281/502] Update 2.mdx updated loading datasets link --- chapters/it/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/it/chapter3/2.mdx b/chapters/it/chapter3/2.mdx index 9de949110..5ebea52a6 100644 --- a/chapters/it/chapter3/2.mdx +++ b/chapters/it/chapter3/2.mdx @@ -84,7 +84,7 @@ In questa sezione verrà usato come esempio il dataset MRPC (Microsoft Research {/if} -L'Hub non contiene solo modelli; contiene anche molti dataset in tante lingue diverse. I dataset possono essere esplorati [qui](https://huggingface.co/datasets), ed è consigliato tentare di caricare e processare un nuovo dataset dopo aver completato questa sezione (cfr. la [documentazione](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). Per ora, focalizziamoci sul dataset MRPC! Questo è uno dei 10 dataset che fanno parte del [GLUE benchmark](https://gluebenchmark.com/), che è un benchmark accademico usato per misurare la performance di modelli ML su 10 compiti di classificazione del testo. +L'Hub non contiene solo modelli; contiene anche molti dataset in tante lingue diverse. I dataset possono essere esplorati [qui](https://huggingface.co/datasets), ed è consigliato tentare di caricare e processare un nuovo dataset dopo aver completato questa sezione (cfr. la [documentazione](https://huggingface.co/docs/datasets/loading). Per ora, focalizziamoci sul dataset MRPC! Questo è uno dei 10 dataset che fanno parte del [GLUE benchmark](https://gluebenchmark.com/), che è un benchmark accademico usato per misurare la performance di modelli ML su 10 compiti di classificazione del testo. La libreria 🤗 Datasets fornisce un comando molto semplice per scaricare e mettere nella cache un dataset sull'Hub. Il dataset MRPC può essere scaricato così: From 7c0ee67372bbf08932a82f60a7c5a11e8171a17c Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:50:20 +0530 Subject: [PATCH 282/502] Update 2.mdx updated loading datasets link --- chapters/ru/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter3/2.mdx b/chapters/ru/chapter3/2.mdx index 250e553b1..dc8c83f24 100644 --- a/chapters/ru/chapter3/2.mdx +++ b/chapters/ru/chapter3/2.mdx @@ -84,7 +84,7 @@ model.train_on_batch(batch, labels) {/if} -Hub содержит не только модели, там также расположено множество датасетов на различных языках. Вы можете посмотреть на них [тут](https://huggingface.co/datasets), а также мы рекомендуем попровать загрузить новый датасет после того, как вы изучите текущий раздел (см. документацию [здесь](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). Но сейчас вернемся к датасету MRPC! Это один из 10 датасетов из состава [GLUE](https://gluebenchmark.com/), который является тестом для производительности моделей машинного обучения в задачах классификации текста. +Hub содержит не только модели, там также расположено множество датасетов на различных языках. Вы можете посмотреть на них [тут](https://huggingface.co/datasets), а также мы рекомендуем попровать загрузить новый датасет после того, как вы изучите текущий раздел (см. документацию [здесь](https://huggingface.co/docs/datasets/loading)). Но сейчас вернемся к датасету MRPC! Это один из 10 датасетов из состава [GLUE](https://gluebenchmark.com/), который является тестом для производительности моделей машинного обучения в задачах классификации текста. Библиотека 🤗 Datasets предоставляет возможность использовать очень простую команду для загрузки и кэширования датасета с Hub. Мы можем загрузить датасет следующим образом: From 5cb46d9c8b99d0ad58db6939864d2f919e143c5e Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:51:27 +0530 Subject: [PATCH 283/502] Update 2.mdx updated loading datasets link --- chapters/th/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/th/chapter3/2.mdx b/chapters/th/chapter3/2.mdx index 79444c44c..73f8ec8cf 100644 --- a/chapters/th/chapter3/2.mdx +++ b/chapters/th/chapter3/2.mdx @@ -84,7 +84,7 @@ model.train_on_batch(batch, labels) {/if} -Hub นั้นไม่ได้เก็บเพียงแค่โมเดล แต่ยังเก็บชุดข้อมูลในหลากหลายภาษาไว้เป็นจำนวนมาก คุณสามารถเลือกดูชุดข้อมูลต่าง ๆ ได้ที่ [here](https://huggingface.co/datasets) และเราขอแนะนำให้คุณลองโหลดและประมวลผลชุดข้อมูลชุดใหม่หลังจากที่คุณเรียน section นี้จบแล้ว (ดูเอกสารข้อมูลทั่วไปได้ที่ [here](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)) แต่ตอนนี้เรามาสนใจกับชุดข้อมูล MRPC กันก่อนนะ! ชุดข้อมูลนี้เป็นหนึ่งในสิบของชุดข้อมูลที่ใช้วัดผลใน [GLUE benchmark](https://gluebenchmark.com/) ซึ่งเป็นตัววัดผลทางวิชาการ (academic benchmark) ที่ใช้วัดประสิทธิภาพของโมเดล ML โดยให้โมเดลทำงานจำแนกข้อความแบบต่าง ๆ กัน รวม 10 งาน +Hub นั้นไม่ได้เก็บเพียงแค่โมเดล แต่ยังเก็บชุดข้อมูลในหลากหลายภาษาไว้เป็นจำนวนมาก คุณสามารถเลือกดูชุดข้อมูลต่าง ๆ ได้ที่ [here](https://huggingface.co/datasets) และเราขอแนะนำให้คุณลองโหลดและประมวลผลชุดข้อมูลชุดใหม่หลังจากที่คุณเรียน section นี้จบแล้ว (ดูเอกสารข้อมูลทั่วไปได้ที่ [here](https://huggingface.co/docs/datasets/loading)) แต่ตอนนี้เรามาสนใจกับชุดข้อมูล MRPC กันก่อนนะ! ชุดข้อมูลนี้เป็นหนึ่งในสิบของชุดข้อมูลที่ใช้วัดผลใน [GLUE benchmark](https://gluebenchmark.com/) ซึ่งเป็นตัววัดผลทางวิชาการ (academic benchmark) ที่ใช้วัดประสิทธิภาพของโมเดล ML โดยให้โมเดลทำงานจำแนกข้อความแบบต่าง ๆ กัน รวม 10 งาน ไลบรารี่ 🤗 Datasets library มีคำสั่งที่ใช้งานได้ง่ายมากในการดาวโหลดและ cache ชุดข้อมูลที่อยู่บน Hub เราสามารถดาวโหลดชุดข้อมูล MRPC ได้ดังนี้: From 90931311cbd3c1228df132bab136cdccfaaf04a6 Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:52:17 +0530 Subject: [PATCH 284/502] Update 2.mdx updated loading datasets link --- chapters/vi/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/vi/chapter3/2.mdx b/chapters/vi/chapter3/2.mdx index af766f084..e04c61e6d 100644 --- a/chapters/vi/chapter3/2.mdx +++ b/chapters/vi/chapter3/2.mdx @@ -84,7 +84,7 @@ Trong phần này, chúng tôi sẽ sử dụng tập dữ liệu MRPC (Microsof {/if} -Hub không chỉ chứa các mô hình; nó cũng có nhiều bộ dữ liệu nhiều ngôn ngữ khác nhau. Bạn có thể xem qua tập dữ liệu [tại đây](https://huggingface.co/datasets) và chúng tôi khuyên bạn nên thử tải và xử lý bộ dữ liệu mới khi bạn đã xem qua phần này (xem tài liệu chung [tại đây](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). Nhưng hiện tại, hãy tập trung vào bộ dữ liệu MRPC! Đây là một trong 10 bộ dữ liệu tạo nên [bộ chuẩn GLUE](https://gluebenchmark.com/), là một điểm chuẩn học thuật được sử dụng để đo hiệu suất của các mô hình ML trên 10 tác vụ phân loại văn bản khác nhau. +Hub không chỉ chứa các mô hình; nó cũng có nhiều bộ dữ liệu nhiều ngôn ngữ khác nhau. Bạn có thể xem qua tập dữ liệu [tại đây](https://huggingface.co/datasets) và chúng tôi khuyên bạn nên thử tải và xử lý bộ dữ liệu mới khi bạn đã xem qua phần này (xem tài liệu chung [tại đây](https://huggingface.co/docs/datasets/loading)). Nhưng hiện tại, hãy tập trung vào bộ dữ liệu MRPC! Đây là một trong 10 bộ dữ liệu tạo nên [bộ chuẩn GLUE](https://gluebenchmark.com/), là một điểm chuẩn học thuật được sử dụng để đo hiệu suất của các mô hình ML trên 10 tác vụ phân loại văn bản khác nhau. Thư viện 🤗 Datasets cung cấp một lệnh rất đơn giản để tải xuống và lưu vào bộ nhớ cache một tập dữ liệu trên Hub. Chúng ta có thể tải xuống bộ dữ liệu MRPC như sau: From e003d5239fb4a66cb43bfc06a3ff8ec6fd271edd Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:52:47 +0530 Subject: [PATCH 285/502] Update 2.mdx updated loading datasets link --- chapters/zh-CN/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/zh-CN/chapter3/2.mdx b/chapters/zh-CN/chapter3/2.mdx index 94fd5d1eb..57e649e65 100644 --- a/chapters/zh-CN/chapter3/2.mdx +++ b/chapters/zh-CN/chapter3/2.mdx @@ -84,7 +84,7 @@ model.train_on_batch(batch, labels) {/if} -模型中心(hub)不只是包含模型;它也有许多不同语言的多个数据集。点击[数据集](https://huggingface.co/datasets)的链接即可进行浏览。我们建议您在阅读本节后阅读一下[加载和处理新的数据集](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)这篇文章,这会让您对huggingface的darasets更加清晰。但现在,让我们使用MRPC数据集中的[GLUE 基准测试数据集](https://gluebenchmark.com/),它是构成MRPC数据集的10个数据集之一,这是一个学术基准,用于衡量机器学习模型在10个不同文本分类任务中的性能。 +模型中心(hub)不只是包含模型;它也有许多不同语言的多个数据集。点击[数据集](https://huggingface.co/datasets)的链接即可进行浏览。我们建议您在阅读本节后阅读一下[加载和处理新的数据集](https://huggingface.co/docs/datasets/loading)这篇文章,这会让您对huggingface的darasets更加清晰。但现在,让我们使用MRPC数据集中的[GLUE 基准测试数据集](https://gluebenchmark.com/),它是构成MRPC数据集的10个数据集之一,这是一个学术基准,用于衡量机器学习模型在10个不同文本分类任务中的性能。 🤗 Datasets库提供了一个非常便捷的命令,可以在模型中心(hub)上下载和缓存数据集。我们可以通过以下的代码下载MRPC数据集: From b2993769fbce6f0de313b54788c4e57b2cf86eeb Mon Sep 17 00:00:00 2001 From: Suket Kamboj <82956207+Sookeyy-12@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:53:21 +0530 Subject: [PATCH 286/502] Update 2.mdx updated loading datasets link --- chapters/zh-TW/chapter3/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/zh-TW/chapter3/2.mdx b/chapters/zh-TW/chapter3/2.mdx index 1b9045aab..4970fb9eb 100644 --- a/chapters/zh-TW/chapter3/2.mdx +++ b/chapters/zh-TW/chapter3/2.mdx @@ -84,7 +84,7 @@ model.train_on_batch(batch, labels) {/if} -模型中心(hub)不只是包含模型;它也有許多不同語言的多個數據集。點擊[數據集](https://huggingface.co/datasets)的鏈接即可進行瀏覽。我們建議您在閱讀本節後閱讀一下[加載和處理新的數據集](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)這篇文章,這會讓您對huggingface的darasets更加清晰。但現在,讓我們使用MRPC數據集中的[GLUE 基準測試數據集](https://gluebenchmark.com/),它是構成MRPC數據集的10個數據集之一,這是一個學術基準,用於衡量機器學習模型在10個不同文本分類任務中的性能。 +模型中心(hub)不只是包含模型;它也有許多不同語言的多個數據集。點擊[數據集](https://huggingface.co/datasets)的鏈接即可進行瀏覽。我們建議您在閱讀本節後閱讀一下[加載和處理新的數據集](https://huggingface.co/docs/datasets/loading)這篇文章,這會讓您對huggingface的darasets更加清晰。但現在,讓我們使用MRPC數據集中的[GLUE 基準測試數據集](https://gluebenchmark.com/),它是構成MRPC數據集的10個數據集之一,這是一個學術基準,用於衡量機器學習模型在10個不同文本分類任務中的性能。 🤗 Datasets庫提供了一個非常便捷的命令,可以在模型中心(hub)上下載和緩存數據集。我們可以通過以下的代碼下載MRPC數據集: From 02e815959d959a2d55d64818719ab351ed5c210c Mon Sep 17 00:00:00 2001 From: Mishig Date: Sun, 24 Sep 2023 13:59:41 +0200 Subject: [PATCH 287/502] Fix syntax in vi/chapter7/7.mdx There was an unnecessary `` --- chapters/vi/chapter7/7.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/chapters/vi/chapter7/7.mdx b/chapters/vi/chapter7/7.mdx index b183ef44b..516daa7a9 100644 --- a/chapters/vi/chapter7/7.mdx +++ b/chapters/vi/chapter7/7.mdx @@ -355,8 +355,6 @@ print(f"Theoretical answer: {answer}, decoded example: {decoded_example}") 'Theoretical answer: a Marian place of prayer and reflection, decoded example: [CLS] What is the Grotto at Notre Dame? [SEP] Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grot [SEP]' ``` - - Bây giờ chúng ta đã thấy từng bước cách tiền xử lý dữ liệu huấn luyện của mình, chúng ta có thể nhóm nó trong một hàm mà ta sẽ áp dụng trên toàn bộ tập dữ liệu huấn luyện. Chúng ta sẽ đệm mọi đặc trưng đến độ dài tối đa mà ta đã đặt, vì hầu hết các ngữ cảnh sẽ dài (và các mẫu tương ứng sẽ được chia thành nhiều đặc trưng), vì vậy không có lợi ích thực sự nào khi áp dụng đệm động ở đây: Thật vậy, chúng ta không thấy câu trả lời bên trong ngữ cảnh. From adf9b1a88983bd065b7c0dbfd25f0b313bbaf2ba Mon Sep 17 00:00:00 2001 From: Brad Windsor Date: Tue, 3 Oct 2023 13:59:58 -0400 Subject: [PATCH 288/502] Remove `get_lr()` from logs which refers to nonexistent function `get_lr()` is called as part of this function, but the function is not declared anywhere in the script. This change removes this portion of the code since it is non-necessary. --- chapters/en/chapter7/6.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chapters/en/chapter7/6.mdx b/chapters/en/chapter7/6.mdx index 7a498a863..6c6418c75 100644 --- a/chapters/en/chapter7/6.mdx +++ b/chapters/en/chapter7/6.mdx @@ -870,7 +870,6 @@ for epoch in range(num_train_epochs): if step % 100 == 0: accelerator.print( { - "lr": get_lr(), "samples": step * samples_per_step, "steps": completed_steps, "loss/train": loss.item() * gradient_accumulation_steps, @@ -912,4 +911,4 @@ And that's it -- you now have your own custom training loop for causal language -{/if} \ No newline at end of file +{/if} From e7d45fbdc2e4180c1221159c03ddf7fa7a7f43f8 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre SCHEMBRI Date: Sun, 15 Oct 2023 14:02:20 +0200 Subject: [PATCH 289/502] Update 4.mdx removed judgmental argument --- chapters/fr/chapter7/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fr/chapter7/4.mdx b/chapters/fr/chapter7/4.mdx index 6f62da3f5..d778c8479 100644 --- a/chapters/fr/chapter7/4.mdx +++ b/chapters/fr/chapter7/4.mdx @@ -119,7 +119,7 @@ split_datasets["train"][1]["translation"] ``` Nous obtenons un dictionnaire contenant deux phrases dans la paire de langues qui nous intéresse. -Une particularité de ce jeu de données rempli de termes techniques informatiques est qu'ils sont tous entièrement traduits en français. Cependant, les ingénieurs français sont souvent paresseux et laissent la plupart des mots spécifiques à l'informatique en anglais lorsqu'ils parlent. Ici, par exemple, le mot « *threads* » pourrait très bien apparaître dans une phrase française, surtout dans une conversation technique. Mais dans ce jeu de données, il a été traduit en « fils de discussion ». Le modèle pré-entraîné que nous utilisons (qui a été pré-entraîné sur un plus grand corpus de phrases françaises et anglaises) prend l'option de laisser le mot tel quel : +Une particularité de ce jeu de données rempli de termes techniques informatiques est qu'ils sont tous entièrement traduits en français. Cependant, les ingénieurs français laissent la plupart des mots spécifiques à l'informatique en anglais lorsqu'ils parlent. Ici, par exemple, le mot « *threads* » pourrait très bien apparaître dans une phrase française, surtout dans une conversation technique. Mais dans ce jeu de données, il a été traduit en « fils de discussion ». Le modèle pré-entraîné que nous utilisons (qui a été pré-entraîné sur un plus grand corpus de phrases françaises et anglaises) prend l'option de laisser le mot tel quel : ```py from transformers import pipeline From 5c0b7bbe0fc2b13f04f419fbd0fe4c565b23dc32 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre SCHEMBRI Date: Sun, 15 Oct 2023 14:04:12 +0200 Subject: [PATCH 290/502] Update en-version --- chapters/en/chapter7/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/en/chapter7/4.mdx b/chapters/en/chapter7/4.mdx index bc957c37b..cdae18d5b 100644 --- a/chapters/en/chapter7/4.mdx +++ b/chapters/en/chapter7/4.mdx @@ -114,7 +114,7 @@ split_datasets["train"][1]["translation"] 'fr': 'Par défaut, développer les fils de discussion'} ``` -We get a dictionary with two sentences in the pair of languages we requested. One particularity of this dataset full of technical computer science terms is that they are all fully translated in French. However, French engineers are often lazy and leave most computer science-specific words in English when they talk. Here, for instance, the word "threads" might well appear in a French sentence, especially in a technical conversation; but in this dataset it has been translated into the more correct "fils de discussion." The pretrained model we use, which has been pretrained on a larger corpus of French and English sentences, takes the easier option of leaving the word as is: +We get a dictionary with two sentences in the pair of languages we requested. One particularity of this dataset full of technical computer science terms is that they are all fully translated in French. However, French engineers leave most computer science-specific words in English when they talk. Here, for instance, the word "threads" might well appear in a French sentence, especially in a technical conversation; but in this dataset it has been translated into the more correct "fils de discussion." The pretrained model we use, which has been pretrained on a larger corpus of French and English sentences, takes the easier option of leaving the word as is: ```py from transformers import pipeline From 12558d7ccd61db35c7933eb2e1ff7fb66c389607 Mon Sep 17 00:00:00 2001 From: Remy Date: Thu, 19 Oct 2023 14:09:12 +0200 Subject: [PATCH 291/502] fix: remove useless token --- .github/workflows/build_documentation.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index fc3c24562..bd7ce48d9 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -16,5 +16,4 @@ jobs: additional_args: --not_python_module languages: ar bn de en es fa fr gj he hi id it ja ko pt ru th tr vi zh-CN zh-TW secrets: - token: ${{ secrets.HUGGINGFACE_PUSH }} hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }} From 342328173a126839dfbb245a22554c9fb2d66508 Mon Sep 17 00:00:00 2001 From: Remy Date: Thu, 19 Oct 2023 14:32:29 +0200 Subject: [PATCH 292/502] fix: remove useless token (#635) From 5828ea13ff912b1b6e62e97613976ee48e6f9cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Grandury?= <57645283+mariagrandury@users.noreply.github.com> Date: Mon, 23 Oct 2023 10:56:22 +0200 Subject: [PATCH 293/502] Translate Chapter 3 to Spanish (#510) * translate Chapter 3 to Spanish * translate code comments to Spanish and fix typos --- chapters/es/_toctree.yml | 12 +- chapters/es/chapter0/1.mdx | 4 +- chapters/es/chapter1/10.mdx | 8 +- chapters/es/chapter2/4.mdx | 17 +- chapters/es/chapter2/6.mdx | 26 +-- chapters/es/chapter3/1.mdx | 20 +- chapters/es/chapter3/2.mdx | 44 +++-- chapters/es/chapter3/3.mdx | 180 ++++++++++++++++++ chapters/es/chapter3/3_tf.mdx | 203 +++++++++++++++++++++ chapters/es/chapter3/4.mdx | 31 ++-- chapters/es/chapter3/5.mdx | 24 +++ chapters/es/chapter3/6.mdx | 333 ++++++++++++++++++++++++++++++++++ chapters/es/chapter5/4.mdx | 7 +- chapters/es/glossary/1.mdx | 12 +- 14 files changed, 843 insertions(+), 78 deletions(-) create mode 100644 chapters/es/chapter3/3.mdx create mode 100644 chapters/es/chapter3/3_tf.mdx create mode 100644 chapters/es/chapter3/5.mdx create mode 100644 chapters/es/chapter3/6.mdx diff --git a/chapters/es/_toctree.yml b/chapters/es/_toctree.yml index 80ab8accd..a87ddf0f1 100644 --- a/chapters/es/_toctree.yml +++ b/chapters/es/_toctree.yml @@ -39,6 +39,7 @@ title: ¡Haz completado el uso básico! - local: chapter2/8 title: Quiz de final de capítulo + quiz: 2 - title: 3. Ajuste (fine-tuning) de un modelo preentrenado sections: @@ -46,8 +47,17 @@ title: Introducción - local: chapter3/2 title: Procesamiento de los datos + - local: chapter3/3 + title: Ajuste de un modelo con la API Trainer + - local: chapter3/3_tf + title: Ajuste de un modelo con Keras - local: chapter3/4 title: Entrenamiento completo + - local: chapter3/5 + title: Ajuste de modelos, ¡hecho! + - local: chapter3/6 + title: Quiz de final de capítulo + quiz: 3 - title: 5. La librería 🤗 Datasets sections: @@ -66,7 +76,7 @@ - local: chapter5/7 title: 🤗 Datasets, ¡listo! - local: chapter5/8 - title: Quiz + title: Quiz de final de capítulo quiz: 5 - title: 8. ¿Cómo solicitar ayuda? diff --git a/chapters/es/chapter0/1.mdx b/chapters/es/chapter0/1.mdx index 41a65887b..efa9ef346 100644 --- a/chapters/es/chapter0/1.mdx +++ b/chapters/es/chapter0/1.mdx @@ -82,10 +82,10 @@ ls -a Puedes entrar y salir de tu entorno virtual con los scripts `activate` y `deactivate`: ``` -# Activate the virtual environment +# Activa el entorno virtual source .env/bin/activate -# Deactivate the virtual environment +# Desactiva el entorno virtual source .env/bin/deactivate ``` diff --git a/chapters/es/chapter1/10.mdx b/chapters/es/chapter1/10.mdx index 6749eeee5..6bad89a0d 100644 --- a/chapters/es/chapter1/10.mdx +++ b/chapters/es/chapter1/10.mdx @@ -80,7 +80,7 @@ result = filler("...") }, { text: "This man has been waiting for you.", - explain: "Incorrecto. Esrte pipeline llena palabras ocultas, por lo que necesita un mask token en algún lugar." + explain: "Incorrecto. Este pipeline llena palabras ocultas, por lo que necesita un mask token en algún lugar." } ]} /> @@ -154,8 +154,6 @@ result = classifier("This is a course about the Transformers library") ### 7. Selecciona la oración que describe mejor los términos "modelo", "arquitectura" y "pesos". -Select the sentence that best describes the terms "model," "architecture," and "weights." - ### 11. ¿Cuál puede ser una posible fuente del sesgo observado en un modelo? -What possible source can the bias observed in a model have? - El primer tokenizador que nos ocurre es el _word-based_ (_basado-en-palabras_). Es generalmente sencillo, con pocas normas, y generalmente da buenos resultados. Por ejemplo, en la imagen a continuación separamos el texto en palabras y buscamos una representación numérica. +
Un ejemplo de tokenizador _word-based_. @@ -55,6 +57,7 @@ print(tokenized_text) ```python out ['Jim', 'Henson', 'era', 'un', 'titiritero'] ``` + También hay variaciones de tokenizadores de palabras que tienen reglas adicionales para la puntuación. Con este tipo de tokenizador, podemos acabar con unos "vocabularios" bastante grandes, donde un vocabulario se define por el número total de tokens independientes que tenemos en nuestro corpus. A cada palabra se le asigna un ID, empezando por 0 y subiendo hasta el tamaño del vocabulario. El modelo utiliza estos ID para identificar cada palabra. @@ -69,13 +72,12 @@ Una forma de reducir la cantidad de tokens desconocidos es ir un poco más allá -Character-based tokenizers split the text into characters, rather than words. This has two primary benefits: -Un tokenizador _character-based_ separa el texto en caracteres, y no en palabras. Conllevando dos beneficios principales: +Un tokenizador _character-based_ separa el texto en caracteres, y no en palabras. Esto conlleva dos beneficios principales: - Obtenemos un vocabulario mucho más corto. -- Habrá muchos menos tokens por fuera del vocabulatio conocido. +- Habrá muchos menos tokens por fuera del vocabulario conocido. -No obstante, pueden surgir incovenientes por los espacios en blanco y signos de puntuación. +No obstante, pueden surgir inconvenientes por los espacios en blanco y signos de puntuación.
Ejemplo de tokenizador basado en palabras. @@ -105,7 +107,7 @@ Este es un ejemplo que muestra cómo un algoritmo de tokenización de subpalabra Estas subpalabras terminan aportando mucho significado semántico: por ejemplo, en el ejemplo anterior, "tokenización" se dividió en "token" y "ización", dos tokens que tienen un significado semántico y a la vez son eficientes en cuanto al espacio (sólo se necesitan dos tokens para representar una palabra larga). Esto nos permite tener una cobertura relativamente buena con vocabularios pequeños y casi sin tokens desconocidos. -Este enfoque es especialmente útil en algunos idimas como el turco, donde se pueden formar palabras complejas (casi) arbitrariamente largas encadenando subpalabras. +Este enfoque es especialmente útil en algunos idiomas como el turco, donde se pueden formar palabras complejas (casi) arbitrariamente largas encadenando subpalabras. ### Y más! @@ -154,6 +156,7 @@ tokenizer("Using a Transformer network is simple") 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} ``` + Guardar un tokenizador es idéntico a guardar un modelo: ```py @@ -200,6 +203,7 @@ Este tokenizador es un tokenizador de subpalabras: divide las palabras hasta obt ### De tokens a IDs de entrada La conversión a IDs de entrada se hace con el método del tokenizador `convert_tokens_to_ids()`: + ```py ids = tokenizer.convert_tokens_to_ids(tokens) @@ -230,6 +234,7 @@ print(decoded_string) ```python out 'Using a Transformer network is simple' ``` + Notemos que el método `decode` no sólo convierte los índices de nuevo en tokens, sino que también agrupa los tokens que formaban parte de las mismas palabras para producir una frase legible. Este comportamiento será extremadamente útil cuando utilicemos modelos que predigan texto nuevo (ya sea texto generado a partir de una indicación, o para problemas de secuencia a secuencia como la traducción o el resumen). -A estas alturas deberías entender las operaciones atómicas que un tokenizador puede manejar: tokenización, conversión a IDs, y conversión de IDs de vuelta a una cadena. Sin embargo, sólo hemos rozado la punta del iceberg. En la siguiente sección, llevaremos nuestro enfoque a sus límites y echaremos un vistazo a cómo superarlos. \ No newline at end of file +A estas alturas deberías entender las operaciones atómicas que un tokenizador puede manejar: tokenización, conversión a IDs, y conversión de IDs de vuelta a una cadena. Sin embargo, sólo hemos rozado la punta del iceberg. En la siguiente sección, llevaremos nuestro enfoque a sus límites y echaremos un vistazo a cómo superarlos. diff --git a/chapters/es/chapter2/6.mdx b/chapters/es/chapter2/6.mdx index 443ee3ee2..de2e84e13 100644 --- a/chapters/es/chapter2/6.mdx +++ b/chapters/es/chapter2/6.mdx @@ -58,14 +58,14 @@ model_inputs = tokenizer(sequences) Puede rellenar de acuerdo a varios objetivos: ```py -# Will pad the sequences up to the maximum sequence length +# Rellenar las secuencias hasta la mayor longitud de secuencia model_inputs = tokenizer(sequences, padding="longest") -# Will pad the sequences up to the model max length -# (512 for BERT or DistilBERT) +# Rellenar las secuencias hasta la máxima longitud del modelo +# (512 para BERT o DistilBERT) model_inputs = tokenizer(sequences, padding="max_length") -# Will pad the sequences up to the specified max length +# Rellenar las secuencias hasta la máxima longitud especificada model_inputs = tokenizer(sequences, padding="max_length", max_length=8) ``` @@ -74,11 +74,11 @@ También puede truncar secuencias: ```py sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] -# Will truncate the sequences that are longer than the model max length -# (512 for BERT or DistilBERT) +# Truncar las secuencias más largas que la máxima longitud del modelo +# (512 para BERT o DistilBERT) model_inputs = tokenizer(sequences, truncation=True) -# Will truncate the sequences that are longer than the specified max length +# Truncar las secuencias más largas que la longitud especificada model_inputs = tokenizer(sequences, max_length=8, truncation=True) ``` @@ -87,13 +87,13 @@ El objeto `tokenizer` puede manejar la conversión a tensores de frameworks espe ```py sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] -# Returns PyTorch tensors +# Devuelve tensores PyTorch model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") -# Returns TensorFlow tensors +# Devuelve tensores TensorFlow model_inputs = tokenizer(sequences, padding=True, return_tensors="tf") -# Returns NumPy arrays +# Devuelve arrays Numpy model_inputs = tokenizer(sequences, padding=True, return_tensors="np") ``` @@ -129,13 +129,14 @@ print(tokenizer.decode(ids)) "i've been waiting for a huggingface course my whole life." ``` -El tokenizador agregó la palabra especial `[CLS]` al principio y la palabra especial `[SEP]` al final. Esto se debe a que el modelo fue preentrenado con esos, así para obtener los mismos resultados por inferencia necesitamos agregarlos también. Nota que algunos modelos no agregan palabras especiales, o agregan unas distintas; los modelos también pueden agregar estas palabras especiales sólo al principio, o sólo al final. En cualquier caso, el tokenizador sabe cuáles son las esperadas y se encargará de ello por tí. +El tokenizador agregó la palabra especial `[CLS]` al principio y la palabra especial `[SEP]` al final. Esto se debe a que el modelo fue preentrenado con esos, así para obtener los mismos resultados por inferencia necesitamos agregarlos también. Nota que algunos modelos no agregan palabras especiales, o agregan unas distintas; los modelos también pueden agregar estas palabras especiales sólo al principio, o sólo al final. En cualquier caso, el tokenizador sabe cuáles son las esperadas y se encargará de ello por tí. ## Conclusión: Del tokenizador al moelo Ahora que hemos visto todos los pasos individuales que el objeto `tokenizer` usa cuando se aplica a textos, veamos una última vez cómo maneja varias secuencias (¡relleno!), secuencias muy largas (¡truncado!), y múltiples tipos de tensores con su API principal: {#if fw === 'pt'} + ```py import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification @@ -148,7 +149,9 @@ sequences = ["I've been waiting for a HuggingFace course my whole life.", "So ha tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") output = model(**tokens) ``` + {:else} + ```py import tensorflow as tf from transformers import AutoTokenizer, TFAutoModelForSequenceClassification @@ -161,4 +164,5 @@ sequences = ["I've been waiting for a HuggingFace course my whole life.", "So ha tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="tf") output = model(**tokens) ``` + {/if} diff --git a/chapters/es/chapter3/1.mdx b/chapters/es/chapter3/1.mdx index 2f0398087..f37308113 100644 --- a/chapters/es/chapter3/1.mdx +++ b/chapters/es/chapter3/1.mdx @@ -7,19 +7,21 @@ classNames="absolute z-10 right-0 top-0" /> -En el [Capítulo 2](/course/chapter2) exploramos como usar los tokenizadores y modelos preentrenados para realizar predicciones. Pero qué tal si deseas ajustar un modelo preentrenado con tu propio conjunto de datos ? +En el [Capítulo 2](/course/chapter2) exploramos cómo usar los tokenizadores y modelos preentrenados para realizar predicciones. Pero, ¿qué pasa si deseas ajustar un modelo preentrenado con tu propio conjunto de datos? {#if fw === 'pt'} -* Como preparar un conjunto de datos grande desde el Hub. -* Como usar la API de alto nivel del entrenador para ajustar un modelo. -* Como usar un bucle personalizado de entrenamiento. -* Como aprovechar la Accelerate library 🤗 para fácilmente ejecutar el bucle personalizado de entrenamiento en cualquier configuración distribuida. + +* Cómo preparar un conjunto de datos grande desde el Hub. +* Cómo usar la API de alto nivel del entrenador para ajustar un modelo. +* Cómo usar un bucle personalizado de entrenamiento. +* Cómo aprovechar la librería 🤗 Accelerate para fácilmente ejecutar el bucle personalizado de entrenamiento en cualquier configuración distribuida. {:else} -* Como preparar un conjunto de datos grande desde el Hub. -* Como usar Keras para ajustar un modelo. -* Como usar Keras para obtener predicciones. -* Como usar una métrica personalizada. + +* Cómo preparar un conjunto de datos grande desde el Hub. +* Cómo usar Keras para ajustar un modelo. +* Cómo usar Keras para obtener predicciones. +* Cómo usar una métrica personalizada. {/if} diff --git a/chapters/es/chapter3/2.mdx b/chapters/es/chapter3/2.mdx index 9be89bb79..9ca011823 100644 --- a/chapters/es/chapter3/2.mdx +++ b/chapters/es/chapter3/2.mdx @@ -47,6 +47,7 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` + {:else} Continuando con el ejemplo del [capítulo anterior](/course/chapter2), aquí mostraremos como podríamos entrenar un clasificador de oraciones/sentencias en TensorFlow: @@ -70,6 +71,7 @@ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy") labels = tf.convert_to_tensor([1, 1]) model.train_on_batch(batch, labels) ``` + {/if} Por supuesto, entrenando el modelo con solo dos oraciones no va a producir muy buenos resultados. Para obtener mejores resultados, debes preparar un conjunto de datos más grande. @@ -79,6 +81,7 @@ En esta sección usaremos como ejemplo el conjunto de datos MRPC (Cuerpo de par ### Cargando un conjunto de datos desde el Hub {#if fw === 'pt'} + {:else} @@ -86,7 +89,7 @@ En esta sección usaremos como ejemplo el conjunto de datos MRPC (Cuerpo de par El Hub no solo contiene modelos; sino que también tiene múltiples conjunto de datos en diferentes idiomas. Puedes explorar los conjuntos de datos [aquí](https://huggingface.co/datasets), y recomendamos que trates de cargar y procesar un nuevo conjunto de datos una vez que hayas revisado esta sección (mira la documentación general [aquí](https://huggingface.co/docs/datasets/loading)). Por ahora, enfoquémonos en el conjunto de datos MRPC! Este es uno de los 10 conjuntos de datos que comprende el [punto de referencia GLUE](https://gluebenchmark.com/), el cual es un punto de referencia académico que se usa para medir el desempeño de modelos ML sobre 10 tareas de clasificación de texto. -La Libreria Datasets 🤗 provee un comando muy simple para descargar y memorizar un conjunto de datos en el Hub. Podemos descargar el conjunto de datos de la siguiente manera: +La librería 🤗 Datasets provee un comando muy simple para descargar y memorizar un conjunto de datos en el Hub. Podemos descargar el conjunto de datos de la siguiente manera: ```py from datasets import load_dataset @@ -154,6 +157,7 @@ Internamente, `label` es del tipo de dato `ClassLabel`, y la asociación de valo ### Preprocesando un conjunto de datos {#if fw === 'pt'} + {:else} @@ -179,7 +183,7 @@ 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] @@ -192,7 +196,6 @@ Nosotros consideramos las llaves `input_ids` y `attention_mask` en el [Capítulo ✏️ **Inténtalo!** Toma el elemento 15 del conjunto de datos de entrenamiento y tokeniza las dos oraciones independientemente y como un par. Cuál es la diferencia entre los dos resultados? - Si convertimos los IDs dentro de `input_ids` en palabras: @@ -216,15 +219,15 @@ De esta manera vemos que el modelo espera las entradas de la siguiente forma `[C Como puedes observar, las partes de la entrada que corresponden a `[CLS] sentence1 [SEP]` todas tienen un tipo de token ID `0`, mientras que las otras partes que corresponden a `sentence2 [SEP]`, todas tienen tipo ID `1`. -Nótese que si seleccionas un punto de control diferente, no necesariamente tendrás el `token_type_ids` en tus entradas tonenizadas (por ejemplo, ellas no aparecen si usas un modelo DistilBERT). Estas aparecen cuando el modelo sabe que hacer con ellas, porque las ha visto durante su etapa de preentrenamiento. +Nótese que si seleccionas un punto de control diferente, no necesariamente tendrás el `token_type_ids` en tus entradas tokenizadas (por ejemplo, ellas no aparecen si usas un modelo DistilBERT). Estas aparecen cuando el modelo sabe que hacer con ellas, porque las ha visto durante su etapa de preentrenamiento. -Aquí, BERT esta preentrenado con tokens de tipo ID, y además del objetivo de modelado de lenguaje oculto que mencionamos en el [Capítulo 1](/course/chapter1), también tiene el objetivo llamado _predicción de la siguiente oración_. El objectivo con esta tarea es modelar la relación entre pares de oraciones. +Aquí, BERT está preentrenado con tokens de tipo ID, y además del objetivo de modelado de lenguaje oculto que mencionamos en el [Capítulo 1](/course/chapter1), también tiene el objetivo llamado _predicción de la siguiente oración_. El objetivo con esta tarea es modelar la relación entre pares de oraciones. -Para predecir la siguiente oración, el modelo recibe pares de oraciones (con tokens ocultados aleatoriamente) y se le pide que prediga si la segunda secuencia sigue a la primera. Para que la tarea no sea tan simple, la mitad de las veces las oraciones estan seguidas en el texto original de donde se obtuvieron, y la otra mitad las oraciones vienen de dos documentos distintos. +Para predecir la siguiente oración, el modelo recibe pares de oraciones (con tokens ocultados aleatoriamente) y se le pide que prediga si la segunda secuencia sigue a la primera. Para que la tarea no sea tan simple, la mitad de las veces las oraciones están seguidas en el texto original de donde se obtuvieron, y la otra mitad las oraciones vienen de dos documentos distintos. -En general, no debes preocuparte si los `token_type_ids` estan o no en las entradas tokenizadas: con tal que uses el mismo punto de control para el tokenizador y el modelo, todo estará bien porque el tokenizador sabe que pasarle a su modelo. +En general, no debes preocuparte si los `token_type_ids` están o no en las entradas tokenizadas: con tal de que uses el mismo punto de control para el tokenizador y el modelo, todo estará bien porque el tokenizador sabe qué pasarle a su modelo. -Ahora que hemos visto como nuestro tokenizador puede trabajar con un par de oraciones, podemos usarlo para tokenizar todo el conjunto de datos: como en el [capítulo anterior](/course/chapter2), podemos darle al tokenizador una lista de pares de oraciones, dándole la lista de las primeras oraciones, y luego la lista de las segundas oraciones. Esto también es compatible con las opciones de relleno y truncamiento que vimos en el [Capítulo 2](/course/chapter2). Por lo tanto, una manera de preprocessar el conjunto de datos de entrenamiento sería: +Ahora que hemos visto como nuestro tokenizador puede trabajar con un par de oraciones, podemos usarlo para tokenizar todo el conjunto de datos: como en el [capítulo anterior](/course/es/chapter2), podemos darle al tokenizador una lista de pares de oraciones, dándole la lista de las primeras oraciones, y luego la lista de las segundas oraciones. Esto también es compatible con las opciones de relleno y truncamiento que vimos en el [Capítulo 2](/course/chapter2). Por lo tanto, una manera de preprocesar el conjunto de datos de entrenamiento sería: ```py tokenized_dataset = tokenizer( @@ -235,7 +238,7 @@ tokenized_dataset = tokenizer( ) ``` -Esto funciona bien, pero tiene la desventaja de que devuelve un diccionario (con nuestras llaves, `input_ids`, `attention_mask`, and `token_type_ids`, y valores que son listas de listas). Además va a trabajar solo si tienes suficiente memoria principal para almacenar todo el conjunto de datos durante la tokenización (mientras que los conjuntos de datos de la librería Datasets 🤗 son archivos [Apache Arrow](https://arrow.apache.org/) almacenados en disco, y así solo mantienes en memoria las muestras que necesitas). +Esto funciona bien, pero tiene la desventaja de que devuelve un diccionario (con nuestras llaves, `input_ids`, `attention_mask`, and `token_type_ids`, y valores que son listas de listas). Además va a trabajar solo si tienes suficiente memoria principal para almacenar todo el conjunto de datos durante la tokenización (mientras que los conjuntos de datos de la librería 🤗 Datasets son archivos [Apache Arrow](https://arrow.apache.org/) almacenados en disco, y así solo mantienes en memoria las muestras que necesitas). Para mantener los datos como un conjunto de datos, usaremos el método [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map). Este también nos ofrece una flexibilidad adicional en caso de que necesitemos preprocesamiento mas allá de la tokenización. El método `map()` trabaja aplicando una función sobre cada elemento del conjunto de datos, así que definamos una función para tokenizar nuestras entradas: @@ -244,9 +247,9 @@ def tokenize_function(example): return tokenizer(example["sentence1"], example["sentence2"], truncation=True) ``` -Esta función recibe un diccionario (como los elementos de nuestro conjunto de datos) y devuelve un nuevo diccionario con las llaves `input_ids`, `attention_mask`, y `token_type_ids`. Nótese que también funciona si el diccionario `example` contiene múltiples elementos (cada llave con una lista de oraciones) debido a que el `tokenizador` funciona con listas de pares de oraciones, como se vio anteriormente. Esto nos va a permitir usar la opción `batched=True` en nuestra llamada a `map()`, lo que acelera la tokenización significativamente. El `tokenizador` es respaldado por un tokenizador escrito en Rust que viene de la libreria [Tokenizadores 🤗](https://github.com/huggingface/tokenizers). Este tokenizador puede ser muy rápido, pero solo si le da muchas entradas al mismo tiempo. +Esta función recibe un diccionario (como los elementos de nuestro conjunto de datos) y devuelve un nuevo diccionario con las llaves `input_ids`, `attention_mask`, y `token_type_ids`. Nótese que también funciona si el diccionario `example` contiene múltiples elementos (cada llave con una lista de oraciones) debido a que el `tokenizador` funciona con listas de pares de oraciones, como se vio anteriormente. Esto nos va a permitir usar la opción `batched=True` en nuestra llamada a `map()`, lo que acelera la tokenización significativamente. El `tokenizador` es respaldado por un tokenizador escrito en Rust que viene de la librería [🤗 Tokenizers](https://github.com/huggingface/tokenizers). Este tokenizador puede ser muy rápido, pero solo si le da muchas entradas al mismo tiempo. -Nótese que por ahora hemos dejado el argumento `padding` fuera de nuestra función de tokenización. Esto es porque rellenar todos los elementos hasta su máxima longitud no es eficiente: es mejor rellenar los elememtos cuando se esta construyendo el lote, debido a que solo debemos rellenar hasta la máxima longitud en el lote, pero no en todo el conjunto de datos. Esto puede ahorrar mucho tiempo y poder de processamiento cuando las entradas tienen longitudes variables. +Nótese que por ahora hemos dejado el argumento `padding` fuera de nuestra función de tokenización. Esto es porque rellenar todos los elementos hasta su máxima longitud no es eficiente: es mejor rellenar los elementos cuando se esta construyendo el lote, debido a que solo debemos rellenar hasta la máxima longitud en el lote, pero no en todo el conjunto de datos. Esto puede ahorrar mucho tiempo y poder de procesamiento cuando las entradas tienen longitudes variables. Aquí se muestra como se aplica la función de tokenización a todo el conjunto de datos en un solo paso. Estamos usando `batched=True` en nuestra llamada a `map` para que la función sea aplicada a múltiples elementos de nuestro conjunto de datos al mismo tiempo, y no a cada elemento por separado. Esto permite un preprocesamiento más rápido. @@ -255,7 +258,7 @@ tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -La manera en que la libreria 🤗 aplica este procesamiento es a través de campos añadidos al conjunto de datos, uno por cada diccionario devuelto por la función de preprocesamiento. +La manera en que la librería 🤗 Datasets aplica este procesamiento es a través de campos añadidos al conjunto de datos, uno por cada diccionario devuelto por la función de preprocesamiento. ```python out DatasetDict({ @@ -274,7 +277,7 @@ DatasetDict({ }) ``` -Hasta puedes usar multiprocesamiento cuando aplicas la función de preprocesamiento con `map()` pasando el argumento `num_proc`. Nosotros no usamos esta opción porque los Tokenizadores de la libreria 🤗 usa múltiples hilos de procesamiento para tokenizar rápidamente nuestros elementos, pero sino estas usando un tokenizador rápido respaldado por esta libreria, esta opción puede acelerar tu preprocesamiento. +Hasta puedes usar multiprocesamiento cuando aplicas la función de preprocesamiento con `map()` pasando el argumento `num_proc`. Nosotros no usamos esta opción porque los tokenizadores de la librería 🤗 Tokenizers usa múltiples hilos de procesamiento para tokenizar rápidamente nuestros elementos, pero sino estas usando un tokenizador rápido respaldado por esta librería, esta opción puede acelerar tu preprocesamiento. Nuestra función `tokenize_function` devuelve un diccionario con las llaves `input_ids`, `attention_mask`, y `token_type_ids`, así que esos tres campos son adicionados a todas las divisiones de nuestro conjunto de datos. Nótese que pudimos haber cambiado los campos existentes si nuestra función de preprocesamiento hubiese devuelto un valor nuevo para cualquiera de las llaves en el conjunto de datos al que le aplicamos `map()`. @@ -293,20 +296,24 @@ La función responsable de juntar los elementos dentro de un lote es llamada *fu {/if} -Para poner esto en práctica, tenemos que definir una función de cotejo que aplique la cantidad correcta de relleno a los elementos del conjunto de datos que queremos agrupar. Afortundamente, la libreria Transformers de 🤗 nos provee esta función mediante `DataCollatorWithPadding`. Esta recibe un tokenizador cuando la creas (para saber cual token de relleno se debe usar, y si el modelo espera el relleno a la izquierda o la derecha en las entradas) y hace todo lo que necesitas: +Para poner esto en práctica, tenemos que definir una función de cotejo que aplique la cantidad correcta de relleno a los elementos del conjunto de datos que queremos agrupar. Afortunadamente, la librería 🤗 Transformers nos provee esta función mediante `DataCollatorWithPadding`. Esta recibe un tokenizador cuando la creas (para saber cual token de relleno se debe usar, y si el modelo espera el relleno a la izquierda o la derecha en las entradas) y hace todo lo que necesitas: {#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} Para probar este nuevo juguete, tomemos algunos elementos de nuestro conjunto de datos de entrenamiento para agruparlos. Aquí, removemos las columnas `idx`, `sentence1`, and `sentence2` ya que éstas no se necesitan y contienen cadenas (y no podemos crear tensores con cadenas), miremos las longitudes de cada elemento en el lote. @@ -346,20 +353,19 @@ batch = data_collator(samples) 'labels': torch.Size([8])} ``` -Luce bién! Ahora que hemos convertido el texto crudo a lotes que nuestro modelo puede aceptar, estamos listos para ajustarlo! +¡Luce bien! Ahora que hemos convertido el texto crudo a lotes que nuestro modelo puede aceptar, estamos listos para ajustarlo! {/if} -✏️ **Inténtalo!** Reproduce el preprocesamiento en el conjunto de datos GLUE SST-2. Es un poco diferente ya que esta compuesto de oraciones individuales en lugar de pares, pero el resto de lo que hicimos deberia ser igual. Para un reto mayor, intenta escribir una función de preprocesamiento que trabaje con cualquiera de las tareas GLUE. +✏️ **¡Inténtalo!** Reproduce el preprocesamiento en el conjunto de datos GLUE SST-2. Es un poco diferente ya que esta compuesto de oraciones individuales en lugar de pares, pero el resto de lo que hicimos debería ser igual. Para un reto mayor, intenta escribir una función de preprocesamiento que trabaje con cualquiera de las tareas GLUE. {#if fw === 'tf'} -Ahora que tenemos nuestro conjunto de datos y el cotejador de datos, necesitamos juntarlos. Nosotros podriamos cargar lotes de datos y cotejarlos, pero eso sería mucho trabajo, y probablemente no muy eficiente. En cambio, existe un método que ofrece una solución eficiente para este problema: `to_tf_dataset()`. Este envuelve un `tf.data.Dataset` alrededor de tu conjunto de datos, con una función opcional de cotejo. `tf.data.Dataset` es un formato nativo de TensorFlow que Keras puede usar con el `model.fit()`, así este método convierte inmediatamente un conjunto de datos 🤗 a un formato que viene listo para entrenamiento. Veámoslo en acción con nuestro conjunto de datos. - +Ahora que tenemos nuestro conjunto de datos y el cotejador de datos, necesitamos juntarlos. Nosotros podríamos cargar lotes de datos y cotejarlos, pero eso sería mucho trabajo, y probablemente no muy eficiente. En cambio, existe un método que ofrece una solución eficiente para este problema: `to_tf_dataset()`. Este envuelve un `tf.data.Dataset` alrededor de tu conjunto de datos, con una función opcional de cotejo. `tf.data.Dataset` es un formato nativo de TensorFlow que Keras puede usar con el `model.fit()`, así este método convierte inmediatamente un conjunto de datos 🤗 a un formato que viene listo para entrenamiento. Veámoslo en acción con nuestro conjunto de datos. ```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( @@ -379,6 +385,6 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -Y eso es todo! Ahora podemos usar esos conjuntos de datos en nuestra próxima clase, donde el entrenamiento será mas sencillo después de todo el trabajo de preprocesamiento de datos. +¡Y eso es todo! Ahora podemos usar esos conjuntos de datos en nuestra próxima clase, donde el entrenamiento será mas sencillo después de todo el trabajo de preprocesamiento de datos. {/if} diff --git a/chapters/es/chapter3/3.mdx b/chapters/es/chapter3/3.mdx new file mode 100644 index 000000000..72a76691e --- /dev/null +++ b/chapters/es/chapter3/3.mdx @@ -0,0 +1,180 @@ + + +# Ajuste de un modelo con la API Trainer + + + + + +🤗 Transformers incluye una clase `Trainer` para ayudarte a ajustar cualquiera de los modelos preentrenados proporcionados en tu dataset. Una vez que hayas hecho todo el trabajo de preprocesamiento de datos de la última sección, sólo te quedan unos pocos pasos para definir el `Trainer`. La parte más difícil será preparar el entorno para ejecutar `Trainer.train()`, ya que se ejecutará muy lentamente en una CPU. Si no tienes una GPU preparada, puedes acceder a GPUs o TPUs gratuitas en [Google Colab](https://colab.research.google.com/). + +Los siguientes ejemplos de código suponen que ya has ejecutado los ejemplos de la sección anterior. Aquí tienes un breve resumen de lo que necesitas: + +```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) +``` + +### Entrenamiento + +El primer paso antes de que podamos definir nuestro `Trainer` es definir una clase `TrainingArguments` que contendrá todos los hiperparámetros que el `Trainer` utilizará para el entrenamiento y la evaluación del modelo. El único argumento que tienes que proporcionar es el directorio donde se guardarán tanto el modelo entrenado como los puntos de control (checkpoints). Para los demás parámetros puedes dejar los valores por defecto, deberían funcionar bastante bien para un ajuste básico. + +```py +from transformers import TrainingArguments + +training_args = TrainingArguments("test-trainer") +``` + + + +💡 Si quieres subir automáticamente tu modelo al Hub durante el entrenamiento, incluye `push_to_hub=True` en `TrainingArguments`. Aprenderemos más sobre esto en el [Capítulo 4](/course/chapter4/3). + + + +El segundo paso es definir nuestro modelo. Como en el [capítulo anterior](/course/chapter2), utilizaremos la clase `AutoModelForSequenceClassification`, con dos etiquetas: + +```py +from transformers import AutoModelForSequenceClassification + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +Observarás que, a diferencia del [Capítulo 2](/course/chapter2), aparece una advertencia después de instanciar este modelo preentrenado. Esto se debe a que BERT no ha sido preentrenado para la clasificación de pares de frases, por lo que la cabeza del modelo preentrenado se ha eliminado y en su lugar se ha añadido una nueva cabeza adecuada para la clasificación de secuencias. Las advertencias indican que algunos pesos no se han utilizado (los correspondientes a la cabeza de preentrenamiento eliminada) y que otros se han inicializado aleatoriamente (los correspondientes a la nueva cabeza). La advertencia concluye animándote a entrenar el modelo, que es exactamente lo que vamos a hacer ahora. + +Una vez que tenemos nuestro modelo, podemos definir un `Trainer` pasándole todos los objetos construidos hasta ahora: el `model`, los `training_args`, los datasets de entrenamiento y validación, nuestro `data_collator`, y nuestro `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, +) +``` + +Ten en cuenta que cuando pasas el `tokenizer` como hicimos aquí, el `data_collator` por defecto utilizado por el `Trainer` será un `DataCollatorWithPadding` como definimos anteriormente, por lo que puedes omitir la línea `data_collator=data_collator`. De todas formas, era importante mostrarte esta parte del proceso en la sección 2. + +Para ajustar el modelo en nuestro dataset, sólo tenemos que llamar al método `train()` de nuestro `Trainer`: + +```py +trainer.train() +``` + +Esto iniciará el ajuste (que debería tardar un par de minutos en una GPU) e informará de la training loss cada 500 pasos. Sin embargo, no te dirá lo bien (o mal) que está rindiendo tu modelo. Esto se debe a que: + +1. No le hemos dicho al `Trainer` que evalúe el modelo durante el entrenamiento especificando un valor para `evaluation_strategy`: `steps` (evaluar cada `eval_steps`) o `epoch` (evaluar al final de cada época). +2. No hemos proporcionado al `Trainer` una función `compute_metrics()` para calcular una métrica durante dicha evaluación (de lo contrario, la evaluación sólo habría impreso la pérdida, que no es un número muy intuitivo). + +### Evaluación + +Veamos cómo podemos construir una buena función `compute_metrics()` para utilizarla la próxima vez que entrenemos. La función debe tomar un objeto `EvalPrediction` (que es una tupla nombrada con un campo `predictions` y un campo `label_ids`) y devolverá un diccionario que asigna cadenas a flotantes (las cadenas son los nombres de las métricas devueltas, y los flotantes sus valores). Para obtener algunas predicciones de nuestro modelo, podemos utilizar el comando `Trainer.predict()`: + +```py +predictions = trainer.predict(tokenized_datasets["validation"]) +print(predictions.predictions.shape, predictions.label_ids.shape) +``` + +```python out +(408, 2) (408,) +``` + +La salida del método `predict()` es otra tupla con tres campos: `predictions`, `label_ids`, y `metrics`. El campo `metrics` sólo contendrá la pérdida en el dataset proporcionado, así como algunas métricas de tiempo (cuánto se tardó en predecir, en total y de media). Una vez que completemos nuestra función `compute_metrics()` y la pasemos al `Trainer`, ese campo también contendrá las métricas devueltas por `compute_metrics()`. + +Como puedes ver, `predictions` es una matriz bidimensional con forma 408 x 2 (408 es el número de elementos del dataset que hemos utilizado). Esos son los logits de cada elemento del dataset que proporcionamos a `predict()` (como viste en el [capítulo anterior](/curso/capítulo2), todos los modelos Transformer devuelven logits). Para convertirlos en predicciones que podamos comparar con nuestras etiquetas, necesitamos tomar el índice con el valor máximo en el segundo eje: + +```py +import numpy as np + +preds = np.argmax(predictions.predictions, axis=-1) +``` + +Ahora podemos comparar esas predicciones `preds` con las etiquetas. Para construir nuestra función `compute_metric()`, nos basaremos en las métricas de la biblioteca 🤗 [Evaluate](https://github.com/huggingface/evaluate/). Podemos cargar las métricas asociadas al dataset MRPC tan fácilmente como cargamos el dataset, esta vez con la función `evaluate.load()`. El objeto devuelto tiene un método `compute()` que podemos utilizar para calcular de la métrica: + +```py +import evaluate + +metric = evaluate.load("glue", "mrpc") +metric.compute(predictions=preds, references=predictions.label_ids) +``` + +```python out +{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} +``` + +Los resultados exactos que obtengas pueden variar, ya que la inicialización aleatoria de la cabeza del modelo podría cambiar las métricas obtenidas. Aquí, podemos ver que nuestro modelo tiene una precisión del 85,78% en el conjunto de validación y una puntuación F1 de 89,97. Estas son las dos métricas utilizadas para evaluar los resultados en el dataset MRPC para la prueba GLUE. La tabla del [paper de BERT](https://arxiv.org/pdf/1810.04805.pdf) recoge una puntuación F1 de 88,9 para el modelo base. Se trataba del modelo "uncased" (el texto se reescribe en minúsculas antes de la tokenización), mientras que nosotros hemos utilizado el modelo "cased" (el texto se tokeniza sin reescribir), lo que explica el mejor resultado. + +Juntándolo todo obtenemos nuestra función `compute_metrics()`: + +```py +def compute_metrics(eval_preds): + metric = evaluate.load("glue", "mrpc") + logits, labels = eval_preds + predictions = np.argmax(logits, axis=-1) + return metric.compute(predictions=predictions, references=labels) +``` + +Y para ver cómo se utiliza para informar de las métricas al final de cada época, así es como definimos un nuevo `Trainer` con nuestra función `compute_metrics()`: + +```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, +) +``` + +Ten en cuenta que hemos creado un nuevo `TrainingArguments` con su `evaluation_strategy` configurado como `"epoch"` y un nuevo modelo. De lo contrario sólo estaríamos continuando el entrenamiento del modelo que ya habíamos entrenado. Para lanzar una nueva ejecución de entrenamiento, ejecutamos: + +```py +trainer.train() +``` + +Esta vez, nos informará de la pérdida de validación y las métricas al final de cada época, además de la pérdida de entrenamiento. De nuevo, la puntuación exacta de precisión/F1 que alcances puede ser un poco diferente de la que encontramos nosotros, debido a la inicialización aleatoria del modelo, pero debería estar en el mismo rango. + +El `Trainer` funciona en múltiples GPUs o TPUs y proporciona muchas opciones, como el entrenamiento de precisión mixta (usa `fp16 = True` en tus argumentos de entrenamiento). Repasaremos todo lo que ofrece en el capítulo 10. + +Con esto concluye la introducción al ajuste utilizando la API de `Trainer`. En el [Capítulo 7](/course/chapter7) se dará un ejemplo de cómo hacer esto para las tareas más comunes de PLN, pero ahora veamos cómo hacer lo mismo en PyTorch puro. + + + +✏️ **¡Inténtalo!** Ajusta un modelo sobre el dataset GLUE SST-2 utilizando el procesamiento de datos que has implementado en la sección 2. + + diff --git a/chapters/es/chapter3/3_tf.mdx b/chapters/es/chapter3/3_tf.mdx new file mode 100644 index 000000000..34f5dcb69 --- /dev/null +++ b/chapters/es/chapter3/3_tf.mdx @@ -0,0 +1,203 @@ + + +# Ajuste de un modelo con Keras + + + +Una vez que hayas realizado todo el trabajo de preprocesamiento de datos de la última sección, sólo te quedan unos pocos pasos para entrenar el modelo. Sin embargo, ten en cuenta que el comando `model.fit()` se ejecutará muy lentamente en una CPU. Si no dispones de una GPU, puedes acceder a GPUs o TPUs gratuitas en [Google Colab](https://colab.research.google.com/). + +Los siguientes ejemplos de código suponen que ya has ejecutado los ejemplos de la sección anterior. Aquí tienes un breve resumen de lo que necesitas: + +```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, +) +``` + +### Entrenamiento + +Los modelos TensorFlow importados de 🤗 Transformers ya son modelos Keras. A continuación, una breve introducción a Keras. + + + +Eso significa que, una vez que tenemos nuestros datos, se requiere muy poco trabajo para empezar a entrenar con ellos. + + + +Como en el [capítulo anterior](/course/chapter2), utilizaremos la clase `TFAutoModelForSequenceClassification`, con dos etiquetas: + +```py +from transformers import TFAutoModelForSequenceClassification + +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +Observarás que, a diferencia del [Capítulo 2](/course/es/chapter2), aparece una advertencia después de instanciar este modelo preentrenado. Esto se debe a que BERT no ha sido preentrenado para la clasificación de pares de frases, por lo que la cabeza del modelo preentrenado se ha eliminado y en su lugar se ha añadido una nueva cabeza adecuada para la clasificación de secuencias. Las advertencias indican que algunos pesos no se han utilizado (los correspondientes a la cabeza de preentrenamiento eliminada) y que otros se han inicializado aleatoriamente (los correspondientes a la nueva cabeza). La advertencia concluye animándote a entrenar el modelo, que es exactamente lo que vamos a hacer ahora. + +Para afinar el modelo en nuestro dataset, sólo tenemos que compilar nuestro modelo con `compile()` y luego pasar nuestros datos al método `fit()`. Esto iniciará el proceso de ajuste (que debería tardar un par de minutos en una GPU) e informará de la pérdida de entrenamiento a medida que avanza, además de la pérdida de validación al final de cada época. + + + +Ten en cuenta que los modelos 🤗 Transformers tienen una característica especial que la mayoría de los modelos Keras no tienen - pueden usar automáticamente una pérdida apropiada que calculan internamente. Usarán esta pérdida por defecto si no estableces un argumento de pérdida en `compile()`. Tea en cuenta que para utilizar la pérdida interna tendrás que pasar las etiquetas como parte de la entrada, en vez de como una etiqueta separada como es habitual en los modelos Keras. Veremos ejemplos de esto en la Parte 2 del curso, donde definir la función de pérdida correcta puede ser complicado. Para la clasificación de secuencias, sin embargo, una función de pérdida estándar de Keras funciona bien, así que eso es lo que usaremos aquí. + + + +```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, +) +``` + + + +Ten en cuenta un fallo muy común aquí: por poder, _puedes_ pasar simplemente el nombre de la función de pérdida como una cadena a Keras, pero por defecto Keras asumirá que ya has aplicado una función softmax a tus salidas. Sin embargo, muchos modelos devuelven los valores justo antes de que se aplique la función softmax, también conocidos como _logits_. Tenemos que decirle a la función de pérdida que eso es lo que hace nuestro modelo, y la única manera de hacerlo es llamándola directamente, en lugar de pasar su nombre con una cadena. + + + +### Mejorar el rendimiento del entrenamiento + + + +Si ejecutas el código anterior seguro que funciona, pero comprobarás que la pérdida sólo disminuye lenta o esporádicamente. La causa principal es la _tasa de aprendizaje_ (learning rate en inglés). Al igual que con la pérdida, cuando pasamos a Keras el nombre de un optimizador como una cadena, Keras inicializa ese optimizador con valores por defecto para todos los parámetros, incluyendo la tasa de aprendizaje. Sin embargo, por experiencia sabemos que los transformadores se benefician de una tasa de aprendizaje mucho menor que la predeterminada para Adam, que es 1e-3, también escrito +como 10 a la potencia de -3, o 0,001. 5e-5 (0,00005), que es unas veinte veces menor, es un punto de partida mucho mejor. + +Además de reducir la tasa de aprendizaje, tenemos un segundo truco en la manga: podemos reducir lentamente la tasa de aprendizaje a lo largo del entrenamiento. En la literatura, a veces se habla de _decrecimiento_ o _reducción_ de la tasa de aprendizaje. En Keras, la mejor manera de hacer esto es utilizar un _programador de tasa de aprendizaje_. Una buena opción es `PolynomialDecay` que, a pesar del nombre, con la configuración por defecto simplemente hace que la tasa de aprendizaje decaiga decae linealmente desde el valor inicial hasta el valor final durante el transcurso del entrenamiento, que es exactamente lo que queremos. Con el fin de utilizar un programador correctamente, necesitamos decirle cuánto tiempo va a durar el entrenamiento. Especificamos esto a continuación como el número de pasos de entrenamiento: `num_train_steps`. + +```py +from tensorflow.keras.optimizers.schedules import PolynomialDecay + +batch_size = 8 +num_epochs = 3 + +# El número de pasos de entrenamiento es el número de muestras del conjunto de datos +# dividido por el tamaño del lote y multiplicado por el número total de épocas. +# Ten en cuenta que el conjunto de datos tf_train_dataset es un conjunto de datos +# tf.data.Dataset por lotes, no el conjunto de datos original de Hugging Face +# por lo que su len() ya es 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) +``` + + + +La librería 🤗 Transformers también tiene una función `create_optimizer()` que creará un optimizador `AdamW` con descenso de tasa de aprendizaje. Verás en detalle este útil atajo en próximas secciones del curso. + + + +Ahora tenemos nuestro nuevo optimizador, y podemos intentar entrenar con él. En primer lugar, vamos a recargar el modelo, para restablecer los cambios en los pesos del entrenamiento que acabamos de hacer, y luego podemos compilarlo con el nuevo optimizador: + +```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"]) +``` + +Ahora, ajustamos de nuevo: + +```py +model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) +``` + + + +💡 Si quieres subir automáticamente tu modelo a Hub durante el entrenamiento, puedes pasar un `PushToHubCallback` en el método `model.fit()`. Aprenderemos más sobre esto en el [Capítulo 4](/course/es/chapter4/3) + + + +### Predicciones del Modelo[[model-predictions]] + + + +Entrenar y ver cómo disminuye la pérdida está muy bien, pero ¿qué pasa si queremos obtener la salida del modelo entrenado, ya sea para calcular algunas métricas o para utilizar el modelo en producción? Para ello, podemos utilizar el método `predict()`. Este devuelve los _logits_ de la cabeza de salida del modelo, uno por clase. + +```py +preds = model.predict(tf_validation_dataset)["logits"] +``` + +Podemos convertir estos logits en predicciones de clases del modelo utilizando `argmax` para encontrar el logit más alto, que corresponde a la clase más probable: + +```py +class_preds = np.argmax(preds, axis=1) +print(preds.shape, class_preds.shape) +``` + +```python out +(408, 2) (408,) +``` + +Ahora, ¡utilicemos esos `preds` (predicciones) para calcular métricas! Podemos cargar las métricas asociadas al conjunto de datos MRPC tan fácilmente como cargamos el conjunto de datos, esta vez con la función `evaluate.load()`. El objeto devuelto tiene un método `compute()` que podemos utilizar para calcular las métricas: + +```py +import evaluate + +metric = evaluate.load("glue", "mrpc") +metric.compute(predictions=class_preds, references=raw_datasets["validation"]["label"]) +``` + +```python out +{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} +``` + +Los resultados exactos que obtengas pueden variar, ya que la inicialización aleatoria de la cabeza del modelo podría cambiar los valores resultantes de las métricas. Aquí, podemos ver que nuestro modelo tiene una precisión del 85,78% en el conjunto de validación y una puntuación F1 de 89,97. Estas son las dos métricas utilizadas para evaluar los resultados del conjunto de datos MRPC del benchmark GLUE. La tabla del [paper de BERT](https://arxiv.org/pdf/1810.04805.pdf) muestra una puntuación F1 de 88,9 para el modelo base. Se trataba del modelo `uncased` ("no encasillado"), mientras que nosotros utilizamos el modelo `cased` ("encasillado"), lo que explica el mejor resultado. + +Con esto concluye la introducción al ajuste de modelos utilizando la API de Keras. En el [Capítulo 7](/course/es/chapter7) se dará un ejemplo de cómo hacer esto para las tareas de PLN más comunes. Si quieres perfeccionar tus habilidades con la API Keras, intenta ajustar un modelo con el conjunto de datos GLUE SST-2, utilizando el procesamiento de datos que hiciste en la sección 2. diff --git a/chapters/es/chapter3/4.mdx b/chapters/es/chapter3/4.mdx index 8d4e84e8d..696722e45 100644 --- a/chapters/es/chapter3/4.mdx +++ b/chapters/es/chapter3/4.mdx @@ -30,7 +30,7 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer) ### Prepárate para el entrenamiento -Antes de escribir nuestro bucle de entrenamiento, necesitaremos definir algunos objetos. Los primeros son los dataloaders que usaremos para iterar sobre lotes. Pero antes de que podamos definir esos dataloaders, necesitamos aplicar un poquito de preprocesamiento a nuestro `tokenized_datasets`, para encargarnos de algunas cosas que el `Trainer` hizo por nosotros de manera automática. Específicamente, necesitamos: +Antes de escribir nuestro bucle de entrenamiento, necesitaremos definir algunos objetos. Los primeros son los `dataloaders` (literalmente, "cargadores de datos") que usaremos para iterar sobre lotes. Pero antes de que podamos definir esos `dataloaders`, necesitamos aplicar un poquito de preprocesamiento a nuestro `tokenized_datasets`, para encargarnos de algunas cosas que el `Trainer` hizo por nosotros de manera automática. Específicamente, necesitamos: - Remover las columnas correspondientes a valores que el model no espera (como las columnas `sentence1` y `sentence2`). - Renombrar la columna `label` con `labels` (porque el modelo espera el argumento llamado `labels`). @@ -51,7 +51,7 @@ Ahora podemos verificar que el resultado solo tiene columnas que nuestro modelo ["attention_mask", "input_ids", "labels", "token_type_ids"] ``` -Ahora que esto esta hecho, es fácil definir nuestros dataloaders: +Ahora que esto esta hecho, es fácil definir nuestros `dataloaders`: ```py from torch.utils.data import DataLoader @@ -100,9 +100,9 @@ print(outputs.loss, outputs.logits.shape) tensor(0.5441, grad_fn=) torch.Size([8, 2]) ``` -Todos los modelos Transformers 🤗 van a retornar la pérdida cuando se pasan los `labels`, y también obtenemos los logits (dos por cada entrada en nuestro lote, asi que es un tensor de tamaño 8 x 2). +Todos los modelos 🤗 Transformers van a retornar la pérdida cuando se pasan los `labels`, y también obtenemos los logits (dos por cada entrada en nuestro lote, asi que es un tensor de tamaño 8 x 2). -Estamos casi listos para escribir nuestro bucle de entrenamiento! Nos están faltando dos cosas: un optimizador y un programador de la rata de aprendizaje. Ya que estamos tratando de replicar a mano lo que el `Trainer` estaba haciendo, usaremos los mismos valores por defecto. El optimizador usado por el `Trainer` es `AdamW`, que es el mismo que Adam, pero con un cambio para la regularización de decremento de los pesos (ver ["Decoupled Weight Decay Regularization"](https://arxiv.org/abs/1711.05101) por Ilya Loshchilov y Frank Hutter): +Estamos casi listos para escribir nuestro bucle de entrenamiento! Nos están faltando dos cosas: un optimizador y un programador de la tasa de aprendizaje. Ya que estamos tratando de replicar a mano lo que el `Trainer` estaba haciendo, usaremos los mismos valores por defecto. El optimizador usado por el `Trainer` es `AdamW`, que es el mismo que Adam, pero con un cambio para la regularización de decremento de los pesos (ver ["Decoupled Weight Decay Regularization"](https://arxiv.org/abs/1711.05101) por Ilya Loshchilov y Frank Hutter): ```py from transformers import AdamW @@ -110,7 +110,7 @@ from transformers import AdamW optimizer = AdamW(model.parameters(), lr=5e-5) ``` -Finalmente, el programador por defecto de la rata de aprendizaje es un decremento lineal desde al valor máximo (5e-5) hasta 0. Para definirlo apropiadamente, necesitamos saber el número de pasos de entrenamiento que vamos a tener, el cual viene dado por el número de épocas que deseamos correr multiplicado por el número de lotes de entrenamiento (que es el largo de nuestro dataloader de entrenamiento). El `Trainer` usa tres épocas por defecto, asi que usaremos eso: +Finalmente, el programador por defecto de la tasa de aprendizaje es un decremento lineal desde al valor máximo (5e-5) hasta 0. Para definirlo apropiadamente, necesitamos saber el número de pasos de entrenamiento que vamos a tener, el cual viene dado por el número de épocas que deseamos correr multiplicado por el número de lotes de entrenamiento (que es el largo de nuestro dataloader de entrenamiento). El `Trainer` usa tres épocas por defecto, asi que usaremos eso: ```py from transformers import get_scheduler @@ -146,7 +146,7 @@ device device(type='cuda') ``` -Ya estamos listos para entrenar! Para tener una idea de cuando el entrenamiento va a terminar, adicionamos una barra de progreso sobre el número de pasos de entrenamiento, usando la libreria `tqdm`: +Ya estamos listos para entrenar! Para tener una idea de cuando el entrenamiento va a terminar, adicionamos una barra de progreso sobre el número de pasos de entrenamiento, usando la librería `tqdm`: ```py from tqdm.auto import tqdm @@ -171,7 +171,7 @@ Puedes ver que la parte central del bucle de entrenamiento luce bastante como el ### El bucle de evaluación -Como lo hicimos anteriormente, usaremos una métrica ofrecida por la libreria 🤗 Evaluate. Ya hemos visto el método `metric.compute()`, pero de hecho las métricas se pueden acumular sobre los lotes a medida que avanzamos en el bucle de predicción con el método `add_batch()`. Una vez que hemos acumulado todos los lotes, podemos obtener el resultado final con `metric.compute()`. Aquí se muestra como se puede implementar en un bucle de evaluación: +Como lo hicimos anteriormente, usaremos una métrica ofrecida por la librería 🤗 Evaluate. Ya hemos visto el método `metric.compute()`, pero de hecho las métricas se pueden acumular sobre los lotes a medida que avanzamos en el bucle de predicción con el método `add_batch()`. Una vez que hemos acumulado todos los lotes, podemos obtener el resultado final con `metric.compute()`. Aquí se muestra como se puede implementar en un bucle de evaluación: ```py import evaluate @@ -206,7 +206,7 @@ De nuevo, tus resultados serán un tanto diferente debido a la inicialización a -El bucle de entrenamiento que definimos anteriormente trabaja bien en un solo CPU o GPU. Pero usando la libreria [Accelerate 🤗](https://github.com/huggingface/accelerate), con solo pocos ajustes podemos habilitar el entrenamiento distribuido en múltiples GPUs o CPUs. Comenzando con la creación de los dataloaders de entrenamiento y validación, aquí se muestra como luce nuestro bucle de entrenamiento: +El bucle de entrenamiento que definimos anteriormente trabaja bien en un solo CPU o GPU. Pero usando la librería [Accelerate 🤗](https://github.com/huggingface/accelerate), con solo pocos ajustes podemos habilitar el entrenamiento distribuido en múltiples GPUs o CPUs. Comenzando con la creación de los `dataloaders` de entrenamiento y validación, aquí se muestra como luce nuestro bucle de entrenamiento: ```py from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler @@ -242,7 +242,7 @@ for epoch in range(num_epochs): progress_bar.update(1) ``` -Y aqui están los cambios: +Y aquí están los cambios: ```diff + from accelerate import Accelerator @@ -286,15 +286,17 @@ Y aqui están los cambios: progress_bar.update(1) ``` -La primera línea a agregarse es la línea del import. La segunda línea crea un objeto `Accelerator` que revisa el ambiente e inicializa la configuración distribuida apropiada. La libreria Accelerate 🤗 se encarga de asignarte el dispositivo, para que puedas remover las líneas que ponen el modelo en el dispositivo (o si prefieres, cámbialas para usar el `accelerator.device` en lugar de `device`). +La primera línea a agregarse es la línea del import. La segunda línea crea un objeto `Accelerator` que revisa el ambiente e inicializa la configuración distribuida apropiada. La librería Accelerate 🤗 se encarga de asignarte el dispositivo, para que puedas remover las líneas que ponen el modelo en el dispositivo (o si prefieres, cámbialas para usar el `accelerator.device` en lugar de `device`). -Ahora la mayor parte del trabajo se hace en la línea que envia los dataloaders, el modelo y el optimizador al `accelerator.prepare()`. Este va a envolver esos objetos en el contenedor apropiado para asegurarse que tu entrenamiento distribuido funcione como se espera. Los cambios que quedan son remover la línea que coloca el lote en el `device` (de nuevo, si deseas dejarlo asi bastaría con cambiarlo para que use el `accelerator.device`) y reemplazar `loss.backward()` con `accelerator.backward(loss)`. +Ahora la mayor parte del trabajo se hace en la línea que envía los `dataloaders`, el modelo y el optimizador al `accelerator.prepare()`. Este va a envolver esos objetos en el contenedor apropiado para asegurarse que tu entrenamiento distribuido funcione como se espera. Los cambios que quedan son remover la línea que coloca el lote en el `device` (de nuevo, si deseas dejarlo asi bastaría con cambiarlo para que use el `accelerator.device`) y reemplazar `loss.backward()` con `accelerator.backward(loss)`. -⚠️ Para obtener el beneficio de la aceleración ofrecida por los TPUs de la nube, recomendamos rellenar las muestras hasta una longitud fija con los argumentos `padding="max_length"` y `max_length` del tokenizador. + ⚠️ Para obtener el beneficio de la aceleración ofrecida por los TPUs de la + nube, recomendamos rellenar las muestras hasta una longitud fija con los + argumentos `padding="max_length"` y `max_length` del tokenizador. -Si deseas copiarlo y pegarlo para probar, así es como luce el bucle completo de entrenamiento con Accelerate 🤗: +Si deseas copiarlo y pegarlo para probar, así es como luce el bucle completo de entrenamiento con 🤗 Accelerate: ```py from accelerate import Accelerator @@ -334,6 +336,7 @@ for epoch in range(num_epochs): ``` Colocando esto en un script `train.py` permitirá que el mismo sea ejecutable en cualquier configuración distribuida. Para probarlo en tu configuración distribuida, ejecuta el siguiente comando: + ```bash accelerate config ``` @@ -354,4 +357,4 @@ from accelerate import notebook_launcher notebook_launcher(training_function) ``` -Puedes encontrar más ejemplos en el [repositorio Accelerate 🤗](https://github.com/huggingface/accelerate/tree/main/examples). +Puedes encontrar más ejemplos en el [repositorio 🤗 Accelerate](https://github.com/huggingface/accelerate/tree/main/examples). diff --git a/chapters/es/chapter3/5.mdx b/chapters/es/chapter3/5.mdx new file mode 100644 index 000000000..0fba0735b --- /dev/null +++ b/chapters/es/chapter3/5.mdx @@ -0,0 +1,24 @@ + + +# Ajuste de modelos, ¡hecho! + + + +¡Qué divertido! En los dos primeros capítulos aprendiste sobre modelos y tokenizadores, y ahora sabes cómo ajustarlos a tus propios datos. Para recapitular, en este capítulo: + +{#if fw === 'pt'} + +- Aprendiste sobre los conjuntos de datos del [Hub](https://huggingface.co/datasets) +- Aprendiste a cargar y preprocesar conjuntos de datos, incluyendo el uso de padding dinámico y los "collators" +- Implementaste tu propio ajuste (fine-tuning) y cómo evaluar un modelo +- Implementaste un bucle de entrenamiento de bajo nivel +- Utilizaste 🤗 Accelerate para adaptar fácilmente tu bucle de entrenamiento para que funcione en múltiples GPUs o TPUs + +{:else} + +- Aprendiste sobre los conjuntos de datos en [Hub](https://huggingface.co/datasets) +- Aprendiste a cargar y preprocesar conjuntos de datos +- Aprendiste a ajustar (fine-tuning) y evaluar un modelo con Keras +- Implementaste una métrica personalizada + +{/if} diff --git a/chapters/es/chapter3/6.mdx b/chapters/es/chapter3/6.mdx new file mode 100644 index 000000000..6a5104392 --- /dev/null +++ b/chapters/es/chapter3/6.mdx @@ -0,0 +1,333 @@ + + + + +# Quiz de final de capítulo + + + +A ver qué has aprendido en este capítulo: + +### 1. El dataset `emotion` contiene mensajes de Twitter etiquetados con emociones. Búscalo en el [Hub](https://huggingface.co/datasets), y lee la tarjeta del dataset. ¿Cuál de estas no es una de sus emociones básicas? + + + +### 2. Busca el dataset `ar_sarcasm` en el [Hub](https://huggingface.co/datasets). ¿Con qué tarea es compatible? + +tarjeta del dataset.", + }, + { + text: "Reconocimiento de entidades nombradas", + explain: + "No es correcto, echa otro vistazo a la tarjeta del dataset.", + }, + { + text: "Responder preguntas", + explain: + "No es correcto, echa otro vistazo a la tarjeta del dataset.", + }, + ]} +/> + +### 3. ¿Cómo se procesan un par de frases según el modelo BERT? + +[SEP] para separar las dos frases, ¡pero falta algo más!", + }, + { + text: "[CLS] tokens_frase_1 tokens_frase_2", + explain: + "Se necesita un token especial [CLS] al principio, ¡pero falta algo más!", + }, + { + text: "[CLS] tokens_frase_1 [SEP] tokens_frase_2 [SEP]", + explain: "¡Correcto!", + correct: true, + }, + { + text: "[CLS] tokens_frase_1 [SEP] tokens_frase_2", + explain: + "Se necesita un token especial [CLS] al principio y un token especial [SEP] para separar las dos frases, ¡pero falta algo más!", + }, + ]} +/> + +{#if fw === 'pt'} + +### 4. ¿Cuáles son las ventajas del método `Dataset.map()`? + + + +### 5. ¿Qué significa padding dinámico? + + + +### 6. ¿Cuál es el objetivo de la función "collate"? + +DataCollatorWithPadding en especial.', + }, + { + text: "Combina todas las muestras del conjunto de datos en un lote.", + explain: + '¡Correcto! Puedes pasar una función "collate" como argumento a un DataLoader. Nosotros usamos la función DataCollatorWithPadding, que rellena todos los elementos de un lote para que tengan la misma longitud.', + correct: true, + }, + { + text: "Preprocesa todo el conjunto de datos.", + explain: + 'Eso sería una función de preprocesamiento, no una función "collate".', + }, + { + text: "Trunca las secuencias del conjunto de datos.", + explain: + 'Una función "collate" está relacionada con el procesamiento de lotes individuales, no del conjunto de datos completo. Si quieres truncar, puedes utilizar el argumento truncate del tokenizer.', + }, + ]} +/> + +### 7. ¿Qué ocurre cuando instancias una de las clases `AutoModelForXxx` con un modelo del lenguaje preentrenado (como `bert-base-uncased`) que corresponde a una tarea distinta de aquella para la que fue entrenado? + +AutoModelForSequenceClassification con bert-base-uncased, recibimos una advertencia al instanciar el modelo. La cabeza preentrenada no se puede utilizar para la tarea de clasificación de secuencias, por lo que es eliminada y se instancia una nueva cabeza con pesos aleatorios.", + correct: true, + }, + { + text: "La cabeza del modelo preentrenado es eliminada.", + explain: "Se necesita hacer algo más, inténtalo de nuevo.", + }, + { + text: "Nada, ya que el modelo se puede seguir ajustando para la otra tarea.", + explain: + "La cabeza del modelo preentrenado no fue entrenada para resolver esta tarea, ¡así que deberíamos eliminarla!", + }, + ]} +/> + +### 8. ¿Para qué sirve `TrainingArguments`? + +Trainer.", + explain: "¡Correcto!", + correct: true, + }, + { + text: "Especifica el tamaño del modelo.", + explain: + "El tamaño del modelo viene definido por la configuración del modelo, no por la clase TrainingArguments.", + }, + { + text: "Solo contiene los hiperparámetros utilizados para la evaluación.", + explain: + "En el ejemplo especificamos dónde se guardarán el modelo y sus checkpoints. ¡Inténtalo de nuevo!", + }, + { + text: "Solo contiene los hiperparámetros utilizados para el entrenamiento.", + explain: + "En el ejemplo también utilizamos evaluation_strategy, que afecta a la evaluación. ¡Inténtalo de nuevo!", + }, + ]} +/> + +### 9. ¿Por qué deberías utilizar la biblioteca 🤗 Accelerate? + +Trainer, no con la librería 🤗 Accelerate. ¡Vuelve a intentarlo!", + }, + { + text: "Hace que nuestros bucles de entrenamiento funcionen con estrategias distribuidas.", + explain: + "¡Correcto! Con 🤗 Accelerate, tus bucles de entrenamiento funcionarán para múltiples GPUs y TPUs.", + correct: true, + }, + { + text: "Ofrece más funciones de optimización.", + explain: + "No, la biblioteca 🤗 Accelerate no proporciona ninguna función de optimización.", + }, + ]} +/> + +{:else} + +### 4. ¿Qué ocurre cuando instancias una de las clases `TFAutoModelForXxx` con un modelo del lenguaje preentrenado (como `bert-base-uncased`) que corresponde a una tarea distinta de aquella para la que fue entrenado? + +TFAutoModelForSequenceClassification con bert-base-uncased, recibimos una advertencia al instanciar el modelo. La cabeza preentrenada no se puede utilizar para la tarea de clasificación de secuencias, por lo que es eliminada y se instancia una nueva cabeza con pesos aleatorios.", + correct: true, + }, + { + text: "La cabeza del modelo preentrenado es eliminada", + explain: "Se necesita hacer algo más, inténtalo de nuevo.", + }, + { + text: "Nada, ya que el modelo se puede seguir ajustando para la otra tarea.", + explain: + "La cabeza del modelo preentrenado no fue entrenada para resolver esta tarea, ¡así que deberíamos eliminarla!", + }, + ]} +/> + +### 5. Los modelos TensorFlow de `transformers` ya son modelos Keras. ¿Qué ventajas ofrece esto? + +TPUStrategy, incluyendo la inicialización del modelo.", + }, + { + text: "Puede aprovechar los métodos existentes, como compile(), fit() y predict().", + explain: + "¡Correcto! Una vez que tienes los datos, entrenar el modelo requiere muy poco esfuerzo.", + correct: true, + }, + { + text: "Tienes la oportunidad de aprender Keras a la vez que transformadores.", + explain: "Correcto, pero estamos buscando otra respuesta :)", + correct: true, + }, + { + text: "Puede calcular fácilmente las métricas relacionadas con el dataset.", + explain: + "Keras nos ayuda con el entrenamiento y la evaluación del modelo, no con el cálculo de métricas relacionadas con el dataset.", + }, + ]} +/> + +### 6. ¿Cómo puedes definir tu propia métrica personalizada? + +tf.keras.metrics.Metric.", + explain: "¡Genial!", + correct: true, + }, + { + text: "Utilizando la API funcional de Keras.", + explain: "¡Inténtalo de nuevo!", + }, + { + text: "Utilizando una función cuya firma sea metric_fn(y_true, y_pred).", + explain: "¡Correcto!", + correct: true, + }, + { + text: "Buscándolo en Google.", + explain: + "Esta no es la respuesta que estamos buscando, pero te podría ayudar a encontrarla.", + correct: true, + }, + ]} +/> + +{/if} diff --git a/chapters/es/chapter5/4.mdx b/chapters/es/chapter5/4.mdx index 344fb0545..6e4024694 100644 --- a/chapters/es/chapter5/4.mdx +++ b/chapters/es/chapter5/4.mdx @@ -7,7 +7,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter5/section4.ipynb"}, ]} /> -Hoy en día es común que tengas que trabajar con dataset de varios GB, especialmente si planeas pre-entrenar un transformador como BERT o GPT-2 desde ceros. En estos casos, _solamente cargar_ los datos puede ser un desafío. Por ejemplo, el corpus de WebText utilizado para preentrenar GPT-2 consiste de más de 8 millones de documentos y 40 GB de texto. ¡Cargarlo en la RAM de tu computador portatil le va a causar un paro cardiaco! +Hoy en día es común que tengas que trabajar con dataset de varios GB, especialmente si planeas pre-entrenar un transformador como BERT o GPT-2 desde ceros. En estos casos, _solamente cargar_ los datos puede ser un desafío. Por ejemplo, el corpus de WebText utilizado para preentrenar GPT-2 consiste de más de 8 millones de documentos y 40 GB de texto. ¡Cargarlo en la RAM de tu computador portátil le va a causar un paro cardíaco! Afortunadamente, 🤗 Datasets está diseñado para superar estas limitaciones: te libera de problemas de manejo de memoria al tratar los datasets como archivos _proyectados en memoria_ (_memory-mapped_) y de límites de almacenamiento al hacer _streaming_ de las entradas en un corpus. @@ -212,9 +212,9 @@ list(dataset_head) También podemos usar la función `IterableDataset.skip()` para crear conjuntos de entrenamiento y validación de un dataset ordenado aleatóriamente así: ```py -# Skip the first 1,000 examples and include the rest in the training set +# Salta las primeras 1000 muestras e incluye el resto en el conjunto de entrenamiento train_dataset = shuffled_dataset.skip(1000) -# Take the first 1,000 examples for the validation set +# Toma las primeras 1000 muestras para el conjunto de validación validation_dataset = shuffled_dataset.take(1000) ``` @@ -283,4 +283,3 @@ next(iter(pile_dataset["train"])) Ya tienes todas las herramientas para cargar y procesar datasets de todas las formas y tamaños, pero a menos que seas muy afortunado, llegará un punto en tu camino de PLN en el que tendrás que crear el dataset tu mismo para resolver tu problema particular. De esto hablaremos en la siguiente sección. - diff --git a/chapters/es/glossary/1.mdx b/chapters/es/glossary/1.mdx index 562cf2fe9..153b35f6a 100644 --- a/chapters/es/glossary/1.mdx +++ b/chapters/es/glossary/1.mdx @@ -36,8 +36,8 @@ | Incompatibility | Incompatibilidad | | Inference | Inferencia | | Key (in a dictionary) | Llave | -| Learning rate | Rata de aprendizaje | -| Library | Libreria | +| Learning rate | Tasa de aprendizaje | +| Library | Librería | | Linux | Linux | | Load | Cargar | | Loss | Pérdida | @@ -53,14 +53,14 @@ | Padding | Relleno | | Parameter | Parámetro | | Python | Python | -| Pytorch | Pytorch | +| PyTorch | PyTorch | | Samples | Muestras | | Save | Guardar | | Scheduler | Programador | | Script | Script | | Self-Contained | Auto-contenido | | Setup | Instalación | -| TensorFlow | Tensorflow | +| TensorFlow | TensorFlow | | Terminal | Terminal | | Tokenizer | Tokenizador | | Train | Entrenar | @@ -90,10 +90,10 @@ Please refer to [TRANSLATING.txt](/chapters/es/TRANSLATING.txt) for a translatio - Refer and contribute to the glossary frequently to stay on top of the latest choices we make. This minimizes the amount of editing that is required. Add new terms alphabetically sorted. -- In certain cases is better to accept an Enlish word. Check for the correct usage of terms in computer science and commonly used terms in other publications. +- In certain cases is better to accept an English word. Check for the correct usage of terms in computer science and commonly used terms in other publications. - Don't translate industry-accepted acronyms. e.g. TPU or GPU. - If translating a technical word, keep the choice of Spanish translation consistent. This does not apply for non-technical choices, as in those cases variety actually helps keep the text engaging. -- Be exact when choosing equivalents for technical words. Package is Paquete. Library is Libreria. Don't mix and match. +- Be exact when choosing equivalents for technical words. Package is Paquete. Library is Librería. Don't mix and match. From 198345755d4e2b1e61a394c6df03c36319258fda Mon Sep 17 00:00:00 2001 From: Alfonso Tobar-Arancibia <48638337+datacubeR@users.noreply.github.com> Date: Mon, 23 Oct 2023 05:57:06 -0300 Subject: [PATCH 294/502] Translating Chapter 6 to Spanish (#523) * Translating sections 1 and 2 to spanish * Translating sections 3 to spanish * Translating sections 3b to spanish * Translating sections 4 to spanish * Translating section 5 to spanish * Translating section 6 to spanish * Translating section 7 to spanish * Translating section 8 to spanish * Translating section 9 to spanish * Translating section 10 to spanish * Adding Sections to _toctree.yml * Fixing Typos after second review --------- Co-authored-by: datacubeR --- chapters/es/_toctree.yml | 27 ++ chapters/es/chapter6/1.mdx | 20 ++ chapters/es/chapter6/10.mdx | 283 ++++++++++++++++ chapters/es/chapter6/2.mdx | 250 ++++++++++++++ chapters/es/chapter6/3.mdx | 478 +++++++++++++++++++++++++++ chapters/es/chapter6/3b.mdx | 643 ++++++++++++++++++++++++++++++++++++ chapters/es/chapter6/4.mdx | 123 +++++++ chapters/es/chapter6/5.mdx | 360 ++++++++++++++++++++ chapters/es/chapter6/6.mdx | 373 +++++++++++++++++++++ chapters/es/chapter6/7.mdx | 382 +++++++++++++++++++++ chapters/es/chapter6/8.mdx | 566 +++++++++++++++++++++++++++++++ chapters/es/chapter6/9.mdx | 16 + 12 files changed, 3521 insertions(+) create mode 100644 chapters/es/chapter6/1.mdx create mode 100644 chapters/es/chapter6/10.mdx create mode 100644 chapters/es/chapter6/2.mdx create mode 100644 chapters/es/chapter6/3.mdx create mode 100644 chapters/es/chapter6/3b.mdx create mode 100644 chapters/es/chapter6/4.mdx create mode 100644 chapters/es/chapter6/5.mdx create mode 100644 chapters/es/chapter6/6.mdx create mode 100644 chapters/es/chapter6/7.mdx create mode 100644 chapters/es/chapter6/8.mdx create mode 100644 chapters/es/chapter6/9.mdx diff --git a/chapters/es/_toctree.yml b/chapters/es/_toctree.yml index a87ddf0f1..cf10f9b60 100644 --- a/chapters/es/_toctree.yml +++ b/chapters/es/_toctree.yml @@ -79,6 +79,33 @@ title: Quiz de final de capítulo quiz: 5 + +- title: 6. La librería 🤗 Tokenizers + sections: + - local: chapter6/1 + title: Introducción + - local: chapter6/2 + title: Entrenar un nuevo tokenizador a partir de uno existente + - local: chapter6/3 + title: Los poderes especiales de los Tokenizadores Rápidos (Fast tokenizers) + - local: chapter6/3b + title: Tokenizadores Rápidos en un Pipeline de Question-Answering + - local: chapter6/4 + title: Normalización y pre-tokenización + - local: chapter6/5 + title: Tokenización por Codificación Byte-Pair + - local: chapter6/6 + title: Tokenización WordPiece + - local: chapter6/7 + title: Tokenización Unigram + - local: chapter6/8 + title: Construir un tokenizador, bloque por bloque + - local: chapter6/9 + title: Tokenizadores, listo! + - local: chapter6/10 + title: Quiz de final de capítulo + quiz: 1 + - title: 8. ¿Cómo solicitar ayuda? sections: - local: chapter8/1 diff --git a/chapters/es/chapter6/1.mdx b/chapters/es/chapter6/1.mdx new file mode 100644 index 000000000..d92567df9 --- /dev/null +++ b/chapters/es/chapter6/1.mdx @@ -0,0 +1,20 @@ +# Introducción[[introduction]] + + + +En el [Capítulo 3](/course/chapter3), revisamos como hacer fine-tuning a un modelo para una tarea dada. Cuando hacemos eso, usamos el mismo tokenizador con el que el modelo fue entrenado -- pero, ¿Qué hacemos cuando queremos entrenar un modelo desde cero? En estos casos, usar un tokenizador que fue entrenado en un corpus con otro dominio u otro lenguaje típicamente no es lo más óptimo. Por ejemplo un tokenizador que es entrenado en un corpus en Inglés tendrá un desempeño pobre en un corpus de textos en Japonés porque el uso de los espacios y de la puntuación es muy diferente entre los dos lenguajes. + + +En este capítulo, aprenderás como entrenar un tokenizador completamente nuevo en un corpus, para que luego pueda ser usado para pre-entrenar un modelo de lenguaje. Todo esto será hecho con la ayuda de la librería [🤗 Tokenizers](https://github.com/huggingface/tokenizers), la cual provee tokenizadores rápidos (_fast tokenizers_) en la librería [🤗 Transformers](https://github.com/huggingface/transformers). Miraremos de cerca todas las características que la provee la librería, y explorar cómo los tokenizadores rápidos (fast tokenizers) difieren de las versiones "lentas". + +Los temas a cubrir incluyen: + +* Cómo entrenar un tokenizador nuevo similar a los usados por un checkpoint dado en un nuevo corpus de texto. +* Las características especiales de los tokenizador rápidos ("fast tokenizers"). +* Las diferencias entre los tres principales algoritmos de tokenización usados en PLN hoy. +* Como construir un tokenizador desde cero con la librería 🤗 Tokenizers y entrenarlo en datos. + +Las técnicas presentadas en este capítulo te prepararán para la sección en el [Capítulo 7](/course/chapter7/6) donde estudiaremos cómo crear un modelo de lenguaje para Código Fuente en Python. Comenzaremos en primer lugar revisando qué significa "entrenar" un tokenizador. \ No newline at end of file diff --git a/chapters/es/chapter6/10.mdx b/chapters/es/chapter6/10.mdx new file mode 100644 index 000000000..0b9f89193 --- /dev/null +++ b/chapters/es/chapter6/10.mdx @@ -0,0 +1,283 @@ + + +# Quiz de Final de Capítulo[[end-of-chapter-quiz]] + + + +Probemos lo que aprendimos en este capítulo! + +### 1. Cuando debería entrenar un nuevo tokenizador? + + + +### 2. Cuál es la ventaja de usar un generador de listas de textos comparado con una lista de listas de textos al usar `train_new_from_iterator()`? + +train_new_from_iterator() acepta.", + explain: "Una lista de listas de textos es un tipo particular de generador de listas de textos, por lo que el método aceptará esto también. Intenta de nuevo!" + }, + { + text: "Evitarás cargar todo el conjunto de datos en memoria de una sóla vez.", + explain: "Correcto! Cada lote de textos será liberado de la memoria al ir iterando, y la ganancia será especialmente visible si usas la librería 🤗 Datasets para almacenar tus textos.", + correct: true + }, + { + text: "Esto permite que la librería 🤗 Tokenizers library use multiprocesamiento.", + explain: "No, usará multiprocesamiento en ambos casos." + }, + { + text: "El tokenizador que entrenarás generará mejores textos.", + explain: "El tokenizador no genera texto -- estás confundiéndolo con un modelo de lenguaje?" + } + ]} +/> + +### 3. Cuáles son las ventajas de utilizar un tokenizador "rápido"? + + + +### 4. Como hace el pipeline `token-classification` para manejar entidades que se extienden a varios tokens? + + + +### 5. Cómo hace el pipeline de `question-answering` para manejar contextos largos? + + + +### 6. Qué es la normalización? + + + +### 7. Qué es la pre-tokenización para un tokenizador de subpalabra? + + + +### 8. Selecciona las afirmaciones que aplican para el modelo de tokenización BPE. + + + +### 9. Selecciona las afirmaciones que aplican para el modelo de tokenizacion WordPiece. + + + +### 10. Selecciona las afirmaciones que aplican para el modelo de tokenización Unigram. + + diff --git a/chapters/es/chapter6/2.mdx b/chapters/es/chapter6/2.mdx new file mode 100644 index 000000000..d4e629374 --- /dev/null +++ b/chapters/es/chapter6/2.mdx @@ -0,0 +1,250 @@ +# Entrenar un nuevo tokenizador a partir de uno existente[[training-a-new-tokenizer-from-an-old-one]] + + + +Si un modelo de lenguaje no está disponible en el lenguaje en el que estás interesado, o si el corpus es muy diferente del lenguaje original en el que el modelo de lenguaje fue entrenado, es muy probable que quieras reentrenar el modelo desde cero utilizando un tokenizador adaptado a tus datos. Eso requerirá entrenar un tokenizador nuevo en tu conjunto de datos. Pero, ¿Qué significa eso exactamente? Cuando revisamos los tokenizadores por primera vez en el [Capítulo 2](/course/chapter2), vimos que la mayoría de los modelos basados en Transformers usan un algoritmo de _tokenización basado en subpalabras_. Para identificar qué subpalabras son de interés y ocurren más frecuentemente en el corpus deseado, el tokenizador necesita mirar de manera profunda todo el texto en el corpus -- un proceso al que llamamos *entrenamiento*. Las reglas exactas que gobiernan este entrenamiento dependen en el tipo de tokenizador usado, y revisaremos los 3 algoritmos principales más tarde en el capítulo. + + + + + + +⚠️ ¡Entrenar un tokenizador no es lo mismo que entrenar un modelo! Entrenar un modelo utiliza `stochastic gradient descent` para minimizar la pérdida (`loss`) en cada lote (`batch`). Es un proceso aleatorio por naturaleza (lo que signifiva que hay que fijar semillas para poder obterner los mismos resultados cuando se realiza el mismo entrenamiento dos veces). Entrenar un tokenizador es un proceso estadístico que intenta identificar cuales son las mejores subpalabras para un corpus dado, y las reglas exactas para elegir estas subpalabras dependen del algoritmo de tokenización. Es un proceso deterministico, lo que significa que siempre se obtienen los mismos resultados al entrenar el mismo algoritmo en el mismo corpus. + + + +## Ensamblando un Corpus[[assembling-a-corpus]] + +Hay una API muy simple en 🤗 Transformers que se puede usar para entrenar un nuevo tokenizador con las mismas características que uno existente: `AutoTokenizer.train_new_from_iterator()`. Para verlo en acción, digamos que queremos entrenar GPT-2 desde cero, pero en lenguaje distinto al Inglés. Nuestra primera tarea será reunir muchos datos en ese lenguaje en un corpus de entrenamiento. Para proveer ejemplos que todos serán capaces de entender no usaremos un lenguaje como el Ruso o el Chino, sino uno versión del inglés más especializado: Código en Python. + +La librería [🤗 Datasets](https://github.com/huggingface/datasets) nos puede ayudar a ensamblar un corpus de código fuente en Python. Usaremos la típica función `load_dataset()` para descargar y cachear el conjunto de datos [CodeSearchNet](https://huggingface.co/datasets/code_search_net). Este conjunto de datos fue creado para el [CodeSearchNet challenge](https://wandb.ai/github/CodeSearchNet/benchmark) y contiene millones de funciones de librerías open source en GitHub en varios lenguajes de programación. Aquí cargaremos la parte del conjunto de datos que está en Python: + +```py +from datasets import load_dataset + +# Esto puede tomar varios minutos para cargarse, así que ¡Agarra un té o un café mientras esperas! +raw_datasets = load_dataset("code_search_net", "python") +``` +Podemos echar un vistazo a la porción de entrenamiento para ver a qué columnas tenemos acceso: + +```py +raw_datasets["train"] +``` + +```python out +Dataset({ + features: ['repository_name', 'func_path_in_repository', 'func_name', 'whole_func_string', 'language', + 'func_code_string', 'func_code_tokens', 'func_documentation_string', 'func_documentation_tokens', 'split_name', + 'func_code_url' + ], + num_rows: 412178 +}) +``` + +Podemos ver que el conjunto de datos separa los docstrings del código y sugiere una tokenización de ambos. Acá, sólo utilizaremos la columna `whole_func_string` para entrenar nuestro tokenizador. Podemos mirar un ejemplo de estas funciones utilizando algún índice en la porción de "train". + +```py +print(raw_datasets["train"][123456]["whole_func_string"]) +``` +lo cual debería imprimir lo siguiente: + +```out +def handle_simple_responses( + self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): + """Accepts normal responses from the device. + + Args: + timeout_ms: Timeout in milliseconds to wait for each response. + info_cb: Optional callback for text sent from the bootloader. + + Returns: + OKAY packet's message. + """ + return self._accept_responses('OKAY', info_cb, timeout_ms=timeout_ms) +``` + +Lo primero que necesitamos hacer es transformar el dataset en un _iterador_ de listas de textos -- por ejemplo, una lista de listas de textos. utilizar listas de textos permitirá que nuestro tokenizador vaya más rápido (entrenar en batches de textos en vez de procesar textos de manera individual uno por uno), y debería ser un iterador si queremos evitar tener cargar todo en memoria de una sola vez. Si tu corpus es gigante, querrás tomar ventaja del hecho que 🤗 Datasets no carga todo en RAM sino que almacena los elementos del conjunto de datos en disco. +Hacer lo siguiente debería crear una lista de listas de 1000 textos cada una, pero cargando todo en memoria: + +```py +# Don't uncomment the following line unless your dataset is small! +# training_corpus = [raw_datasets["train"][i: i + 1000]["whole_func_string"] for i in range(0, len(raw_datasets["train"]), 1000)] +``` + +Al usar un generador de Python, podemos evitar que Python cargue todo en memoria hasta que sea realmente necesario. Para crear dicho generador, solo necesitas reemplazar los corchetes con paréntesis: + +```py +training_corpus = ( + raw_datasets["train"][i : i + 1000]["whole_func_string"] + for i in range(0, len(raw_datasets["train"]), 1000) +) +``` +Esta línea de código no trae ningún elemento del conjunto de datos; sólo crea un objeto que se puede usar en Python con un ciclo `for`. Los textos sólo serán cargados cuando los necesites (es decir, cuando estás un paso del ciclo `for` que los requiera), y sólo 1000 textos a la vez serán cargados. De eso forma no agotarás toda tu memoria incluso si procesas un conjunto de datos gigante. + +El problema con un objeto generador es que sólo se puede usar una vez. Entonces en vea que el siguiente código nos entregue una lista de los primeros 10 dígitos dos veces: + +```py +gen = (i for i in range(10)) +print(list(gen)) +print(list(gen)) +``` +Nos lo entrega una vez, y luego una lista vacía: + +```python out +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +[] +``` + +Es por eso que definimos una función que retorne un generador: + +```py +def get_training_corpus(): + return ( + raw_datasets["train"][i : i + 1000]["whole_func_string"] + for i in range(0, len(raw_datasets["train"]), 1000) + ) + + +training_corpus = get_training_corpus() +``` +También puedes definir un generador dentro de un ciclo `for`utilizando el comando `yield`: + +```py +def get_training_corpus(): + dataset = raw_datasets["train"] + for start_idx in range(0, len(dataset), 1000): + samples = dataset[start_idx : start_idx + 1000] + yield samples["whole_func_string"] +``` + +el cual producirá el mismo generador anterior, pero también permitiendo usar lógicas más complejas de las que se puede hacer en un `list comprehension`. + +## Entrenar un nuevo Tokenizador[[training-a-new-tokenizer]] + +Ahora que tenemos nuestro corpus en la forma de un iterador de lotes de textos, estamos listos para entrenar un nuevo tokenizador. Para hacer esto, primero tenemos que cargar el tokenizador que queremos utilizar con nuestro modelo (en este caso, GPT-2): + +```py +from transformers import AutoTokenizer + +old_tokenizer = AutoTokenizer.from_pretrained("gpt2") +``` +Aunque vamos a entrenar un nuevo tokenizador, es una buena idea hacer esto para evitar comenzar de cero completamente. De esta manera, no tendremos que especificar nada acerca del algoritmo de tokenización o de los tokens especiales que queremos usar; nuestro tokenizador será exactamente el mismo que GPT-2, y lo único que cambiará será el vocabulario, el cuál será determinado por el entrenamiento en nuestro corpus. + +Primero, echemos un vistazo a cómo este tokenizador tratará una función de ejemplo: + +```py +example = '''def add_numbers(a, b): + """Add the two numbers `a` and `b`.""" + return a + b''' + +tokens = old_tokenizer.tokenize(example) +tokens +``` + +```python out +['def', 'Ġadd', '_', 'n', 'umbers', '(', 'a', ',', 'Ġb', '):', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', + 'Ġnumbers', 'Ġ`', 'a', '`', 'Ġand', 'Ġ`', 'b', '`', '."', '""', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] +``` + +Este tokenizador tiene algunos símbolos especiales como `Ġ` y `Ċ`, lo cual denota espacios y nuevas líneas (saltos de líneas) respectivamente. Como podemos ver, esto no es muy eficiente: el tokenizador retorna tokens individuales para cada espacio, cuando debería agrupar los niveles de indentación (dado que tener grupos de cuatro u ocho espacios va a ser muy común en el uso de código). Además separa el nombre de la función de manera un poco extraña al no estar acostumbrado a ver palabras separadas con el caracter `_`. + +Entrenemos nuestro nuevo tokenizador y veamos si resuelve nuestros problemas. Para esto usaremos el método `train_new_from_iterator()`: + +```py +tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) +``` +Este comando puede tomar tiempo si tu corpus es muy largo, pero para este conjunto de datos de 1.6 GB de textos es muy rápido (1 minuto 16 segundos en un AMD Ryzen 9 3900X CPU con 12 núcleos). + +Nota que `AutoTokenizer.train_new_from_iterator()` sólo funciona si el tokenizador que estás usando es un tokenizador rápido (_fast tokenizer_). Cómo verás en la siguiente sección, la librería 🤗 Transformers contiene 2 tipos de tokenizadores: algunos están escritos puramente en Python y otros (los rápidos) están respaldados por la librería 🤗 Tokenizers, los cuales están escritos en lenguaje de programación [Rust](https://www.rust-lang.org). Python es el lenguaje mayormente usado en ciencia de datos y aplicaciones de deep learning, pero cuando algo necesita ser paralelizado para ser rápido, tiene que ser escrito en otro lenguaje. Por ejemplo, las multiplicaciones matriciales que están en el corazón de los cómputos de un modelo están escritos en CUDA, una librería optimizada en C para GPUs. del computation are written in CUDA, an optimized C library for GPUs. + +Entrenar un nuevo tokenizador en Python puro sería insoportablemente lento, razón pr la cual desarrollamos la librería 🤗 Tokenizers. Notar que de la misma manera que no tuviste que aprender el lenguaje CUDA para ser capaz de ejecutar tu modelo en un barch de inputs en una GPU, no necesitarás aprender Rust para usar los tokenizadores rápidos (_fast tokenizers_). La librería 🤗 Tokenizers provee bindings en Python para muchos métodos que internamente llaman trozos de código en Rust; por ejemplo, para paralelizar el entrenamiento de un nuevo tokenizador o, como vimos en el [Capítulo 3](/course/chapter3), la tokenización de un batch de inputs. + +La mayoría de los modelos Transformers tienen un tokenizador rápido (_Fast Tokenizer_) disponible (hay algunas excepciones que se pueden revisar [acá](https://huggingface.co/transformers/#supported-frameworks)), y la API `AutoTokenizer` siempre seleccionar un tokenizador rápido para ti en caso de estar disponible. En la siguiente sección echaremos un vistazo a algunas de las características especiales que tienen los tokenizadores rápidos, los cuales serán realmente útiles para tareas como clasificación de tokens y question answering. Antes de sumergirnos en eso, probemos nuestro tokenizador recién entrenado en nuestro ejemplo previo: + +```py +tokens = tokenizer.tokenize(example) +tokens +``` + +```python out +['def', 'Ġadd', '_', 'numbers', '(', 'a', ',', 'Ġb', '):', 'ĊĠĠĠ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', 'Ġnumbers', 'Ġ`', + 'a', '`', 'Ġand', 'Ġ`', 'b', '`."""', 'ĊĠĠĠ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] +``` + +Acá nuevamente vemos los símbolos especiales `Ġ` y `Ċ` que denotan espacios y nuevas líneas (saltos de líneas), pero también podemos ver que nuestro tokenizador aprendió algunos tokens que son altamente específicos para el corpus de funciones en Python: por ejemplo, está el token `ĊĠĠĠ` que representa una indentación y un token `Ġ"""` que representan la triple comilla para comenzar un docstring. El tokenizador también divide correctamente los nombres de funciones usando `_`. Esta es una representación más compacta ya que utilizar un tokenizador común y corriente en inglés en el mismo ejemplo nos dara una oración más larga: + + + +```py +print(len(tokens)) +print(len(old_tokenizer.tokenize(example))) +``` + +```python out +27 +36 +``` +Echemos un vistazo al siguiente ejemplo: + +```python +example = """class LinearLayer(): + def __init__(self, input_size, output_size): + self.weight = torch.randn(input_size, output_size) + self.bias = torch.zeros(output_size) + + def __call__(self, x): + return x @ self.weights + self.bias + """ +tokenizer.tokenize(example) +``` + +```python out +['class', 'ĠLinear', 'Layer', '():', 'ĊĠĠĠ', 'Ġdef', 'Ġ__', 'init', '__(', 'self', ',', 'Ġinput', '_', 'size', ',', + 'Ġoutput', '_', 'size', '):', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'weight', 'Ġ=', 'Ġtorch', '.', 'randn', '(', 'input', '_', + 'size', ',', 'Ġoutput', '_', 'size', ')', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'bias', 'Ġ=', 'Ġtorch', '.', 'zeros', '(', + 'output', '_', 'size', ')', 'ĊĊĠĠĠ', 'Ġdef', 'Ġ__', 'call', '__(', 'self', ',', 'Ġx', '):', 'ĊĠĠĠĠĠĠĠ', + 'Ġreturn', 'Ġx', 'Ġ@', 'Ġself', '.', 'weights', 'Ġ+', 'Ġself', '.', 'bias', 'ĊĠĠĠĠ'] +``` + +En adición al token correspondiente a la indentación, también podemos ver un token para la doble indentación: `ĊĠĠĠĠĠĠĠ`. Palabras espaciales del lenguaje Python como `class`, `init`, `call`, `self`, and `return` son tokenizadas como un sólo token y podemos ver que además de dividir en `_` y `.`, el tokenizador correctamente divide incluso en nombres que usan camel-case: `LinearLayer` es tokenizado como `["ĠLinear", "Layer"]`. + +## Guardar el Tokenizador[[saving-the-tokenizer]] + + +Para asegurarnos que podemos usar el tokenizador más tarde, necesitamos guardar nuestro nuevo tokenizador. Al igual que los modelos, esto se hace con el método `save_pretrained()`. + +```py +tokenizer.save_pretrained("code-search-net-tokenizer") +``` + +Esto creará una nueva carpeta llamada *code-search-net-tokenizer*, la cual contendrá todos los archivos que el tokenizador necesita para ser cargado. Si quieres compartir el tokenizador con tus colegas y amigos, puedes subirlo al Hub logeando en tu cuenta. Si estás trabajando en notebooks, hay una función conveniente para ayudarte a hacer esto: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +Esto mostrará un widget donde puedes ingresar tus credenciales de Hugging Face. En caso de no estar usando un notebook, puedes escribir la siguiente línea en tu terminal: + +```bash +huggingface-cli login +``` + +Una vez logueado puedes enviar tu tokenizador al Hub ejecutando el siguiente comando:: + +```py +tokenizer.push_to_hub("code-search-net-tokenizer") +``` +Esto creará un nuevo repositorio en tu namespace con el nombre `code-search-net-tokenizer`, conteniendo el archivo del tokenizador. Luego puedes cargar tu tokenizador desde donde quieras utilizando método `from_pretrained()`. + +```py +# Replace "huggingface-course" below with your actual namespace to use your own tokenizer +tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") +``` +Ya estás listo para entrenar un modelo de lenguaje desde cero y hacer fine-tuning en la tarea que desees. Llegaremos a eso en el [Capítulo 7](/course/chapter7), pero primero en el resto del capítulo miraremos más de cerca los tokenizadores rápidos (_Fast Tokenizers_) y explorar en detalle lo que pasa en realidad pasa cuando llamamos al método `train_new_from_iterator()`. diff --git a/chapters/es/chapter6/3.mdx b/chapters/es/chapter6/3.mdx new file mode 100644 index 000000000..65392631a --- /dev/null +++ b/chapters/es/chapter6/3.mdx @@ -0,0 +1,478 @@ + + +# Los poderes especiales de los Tokenizadores Rápidos (Fast tokenizers)[[fast-tokenizers-special-powers]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + + + +En esta sección miraremos más de cerca las capacidades de los tokenizadores en 🤗 Transformers. Hasta ahora sólo los hemos utilizado para tokenizar las entradas o decodificar los IDs en texto, pero los tokenizadores -- especialmente los que están respaldados en la librería 🤗 Tokenizers -- pueden hacer mucho más. Para ilustrar estas características adicionales, exploraremos cómo reproducir los resultados de los pipelines de `clasificación de tokens` (al que llamamos ner) y `question-answering` que nos encontramos en el [Capítulo 1](/course/chapter1). + + + +En la siguiente discusión, a menudo haremos la diferencia entre un tokenizador "lento" y uno "rápido". Los tokenizadores lentos son aquellos escritos en Python dentro de la librería Transformers, mientras que las versiones provistas por la librería 🤗 Tokenizers, son los que están escritos en Rust. Si recuerdas la tabla del [Capítulo 5](/course/chapter5/3) en la que se reportaron cuanto tomó a un tokenizador rápido y uno lento tokenizar el Drug Review Dataset, ya deberías tener una idea de por qué los llamamos rápidos y lentos: + + +| | Tokenizador Rápido | Tokenizador Lento +:--------------:|:--------------:|:-------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s + + + +⚠️ Al tokenizar una sóla oración, no siempre verás una diferencia de velocidad entre la versión lenta y la rápida del mismo tokenizador. De hecho, las versión rápida podría incluso ser más lenta! Es sólo cuando se tokenizan montones de textos en paralelos al mismo tiempo que serás capaz de ver claramente la diferencia. + + + +## Codificación en Lotes (Batch Encoding)[[batch-encoding]] + + + +La salida de un tokenizador no siempre un simple diccionario; lo que se obtiene en realidad es un objeto especial `BatchEncoding`. Es una subclase de un diccionario (razón por la cual pudimos indexar el resultado sin ningún problema anteriormente), pero con métodos adicionales que son mayormente usados por los tokenizadores rápidos (_Fast Tokenizers_). + +Además de sus capacidad en paralelización, la funcionalidad clave de un tokenizador rápido es que siempre llevan registro de la porción de texto de la cual los tokens finales provienen -- una característica llamada *offset mapping*. Esto permite la capacidad de mapear cada palabra con el token generado o mapear cada caracter del texto original con el token respectivo y viceversa. + +Echemos un vistazo a un ejemplo: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +encoding = tokenizer(example) +print(type(encoding)) +``` +Como se mencionó previamente, obtenemos un objeto de tipo `BatchEncoding` como salida del tokenizador: + +```python out + +``` + +Dado que la clase `AutoTokenizer` escoge un tokenizador rápido por defecto, podemos usar los métodos adicionales que este objeto `BatchEncoding` provee. Tenemos dos manera de chequear si el tokenizador es rápido o lento. Podemos chequear el atributo `is_fast` del tokenizador: + +```python +tokenizer.is_fast +``` + +```python out +True +``` +o chequear el mismo atributo de nuestro `encoding`: + +```python +encoding.is_fast +``` + +```python out +True +``` + +Veamos lo que un tokenizador rápido nos permite hacer. Primero podemos acceder a los tokens sin tener que convertir los IDs a tokens: + +```py +encoding.tokens() +``` + +```python out +['[CLS]', 'My', 'name', 'is', 'S', '##yl', '##va', '##in', 'and', 'I', 'work', 'at', 'Hu', '##gging', 'Face', 'in', + 'Brooklyn', '.', '[SEP]'] +``` + +En este caso el token con índice 5 is `##yl`, el cual es parte de la palabra "Sylvain" en la oración original. Podemos también utilizar el método `word_ids()` para obtener el índice de la palabra de la que cada token proviene: + +```py +encoding.word_ids() +``` + +```python out +[None, 0, 1, 2, 3, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, None] +``` + +Podemos ver que los tokens especiales del tokenizador `[CLS]` y `[SEP]` están mapeados a `None`, y que cada token está mapeado a la palabra de la cual se origina. Esto es especialmente útil para determinar si el token está al inicio de la palabra o si dos tokens están en la misma palabra. POdríamos confiar en el prefijo `[CLS]` and `[SEP]` para eso, pero eso sólo funciona para tokenizadores tipo BERT; este método funciona para cualquier tipo de tokenizador mientras sea de tipo rápido. En el próximo capítulo, veremos como podemos usar esta capacidad para aplicar etiquetas para cada palabra de manera apropiada en tareas como Reconocimiento de Entidades (Named Entity Recognition NER), y etiquetado de partes de discurso (part-of-speech POS tagging). También podemos usarlo para enmascarar todos los tokens que provienen de la misma palabra en masked language modeling (una técnica llamada _whole word masking_). + + + +La noción de qué es una palabra es complicada. Por ejemplo "I'll" (la contracción de "I will" en inglés) ¿cuenta como una o dos palabras? De hecho depende del tokenizador y la operación de pretokenización que aplica. Algunos tokenizadores sólo separan en espacios, por lo que considerarán esto como una sóla palabra. Otros utilizan puntuación por sobre los espacios, por lo que lo considerarán como dos palabras. + +✏️ **Inténtalo!** Crea un tokenizador a partir de los checkpoints `bert-base-cased` y `roberta-base` y tokeniza con ellos "81s". ¿Qué observas? Cuál son los IDs de la palabra? + + + +De manera similar está el método `sentence_ids()` que podemos utilizar para mapear un token a la oración de la cuál proviene (aunque en este caso el `token_type_ids` retornado por el tokenizador puede darnos la misma información). + +Finalmente, podemos mapear cualquier palabra o token a los caracteres originales del texto, y viceversa, utilizando los métodos `word_to_chars()` o `token_to_chars()` y los métodos `char_to_word()` o `char_to_token()`. Por ejemplo el método `word_ids()` nos dijo que `##yl` es parte de la palabra con índice 3, pero qué palabra es en la oración? Podemos averiguarlo así: + +```py +start, end = encoding.word_to_chars(3) +example[start:end] +``` + +```python out +Sylvain +``` + +Como mencionamos previamente, todo esto funciona gracias al hecho de que los tokenizadores rápidos llevan registro de la porción de texto del que cada token proviene en una lista de *offsets*. Para ilustrar sus usos, a continuación mostraremos como replicar los resultados del pipeline de `clasificación de tokens` de manera manual. + + + +✏️ **Inténtalo!** Crea tu propio texto de ejemplo y ve si puedes entender qué tokens están asociados con el ID de palabra, y también cómo extraer los caracteres para una palabra. Como bonus, intenta usar dos oraciones como entrada/input y ve si los IDs de oraciones te hacen sentido. + + + +## Dentro del Pipeline de `clasificación de tokens`[[inside-the-token-classification-pipeline]] + +En el [Capítulo 1](/course/chapter1) tuvimos nuestra primera probada aplicando NER -- donde la tarea es identificar qué partes del texto corresponden a entidades como personas, locaciones, u organizaciones -- con la función `pipeline()` de la librería 🤗 Transformers. Luego en el [Capítulo 2](/course/chapter2), vimos como un pipeline agrupa las tres etapas necesarias para obtener predicciones desde un texto crudo: tokenización, pasar los inputs a través del modelo, y post-procesamiento. Las primeras dos etapas en el pipeline de `clasificación de tokens` son las mismas que en otros pipelines, pero el post-procesamiento es un poco más complejo -- ×+/¡veamos cómo! + + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +### Obteniendo los resultados base con el pipeline[[getting-the-base-results-with-the-pipeline]] + +Primero, agarremos un pipeline de clasificación de tokens para poder tener resultados que podemos comparar manualmente. El usado por defecto es [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english); el que realiza NER en oraciones: + +```py +from transformers import pipeline + +token_classifier = pipeline("token-classification") +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +El modelo indentificó apropiadamente cada token generado por "Sylvain" como una persona, cada token generado por "Hugging Face" como una organización y el token "Brooklyn" como una locación. Podemos pedirle también al pipeline que agrupe los tokens que corresponden a la misma identidad: + +```py +from transformers import pipeline + +token_classifier = pipeline("token-classification", aggregation_strategy="simple") +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +La estrategia de agregación (`aggregation_strategy`) elegida cambiará los puntajes calculados para cada entidad agrupada. Con `"simple"` el puntaje es la media los puntajes de cada token en la entidad dada: por ejemplo, el puntaje de "Sylvain" es la media de los puntajes que vimos en el ejemplo previo para los tokens `S`, `##yl`, `##va`, y `##in`. Otras estrategias disponibles son: + +- `"first"`, donde el puntaje de cada entidad es el puntaje del primer token de la entidad (para el caso de "Sylvain" sería 0.9923828, el puntaje del token `S`) +- `"max"`, donde el puntaje de cada entidad es el puntaje máximo de los tokens en esa entidad (para el caso de "Hugging Face" sería 0.98879766, el puntaje de "Face") +- `"average"`, donde el puntaje de cada entidad es el promedio de los puntajes de las palabras que componen la entidad (para el caso de "Sylvain" no habría diferencia con la estrategia "simple", pero "Hugging Face" tendría un puntaje de 0.9819, el promedio de los puntajes para "Hugging", 0.975, y "Face", 0.98879) + +Ahora veamos como obtener estos resultados sin utilizar la función `pipeline()`! + +### De los inputs a las predicciones[[from-inputs-to-predictions]] + +{#if fw === 'pt'} + +Primero necesitamos tokenizar nuestro input y pasarlo a través del modelo. Esto es exactamente lo que se hace en el [Capítulo 2](/course/chapter2); instanciamos el tokenizador y el modelo usando las clases `AutoXxx` y luego los usamos en nuestro ejemplo: + + +```py +from transformers import AutoTokenizer, AutoModelForTokenClassification + +model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModelForTokenClassification.from_pretrained(model_checkpoint) + +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +inputs = tokenizer(example, return_tensors="pt") +outputs = model(**inputs) +``` + +Dado que estamos usando acá `AutoModelForTokenClassification`, obtenemos un conjunto de logits para cada token en la secuencia de entrada: + +```py +print(inputs["input_ids"].shape) +print(outputs.logits.shape) +``` + +```python out +torch.Size([1, 19]) +torch.Size([1, 19, 9]) +``` + +{:else} + +Primero necesitamos tokenizar nuestro input y pasarlo por nuestro modelo. Esto es exactamente lo que se hace en el [Capítulo 2](/course/chapter2); instanciamos el tokenizador y el modelo usando las clases `TFAutoXxx` y luego los usamos en nuestro ejemplo: + +```py +from transformers import AutoTokenizer, TFAutoModelForTokenClassification + +model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = TFAutoModelForTokenClassification.from_pretrained(model_checkpoint) + +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +inputs = tokenizer(example, return_tensors="tf") +outputs = model(**inputs) +``` +Dado que estamos usando acá `TFAutoModelForTokenClassification`, obtenemos un conjunto de logits para cada token en la secuencia de entrada: + +```py +print(inputs["input_ids"].shape) +print(outputs.logits.shape) +``` + +```python out +(1, 19) +(1, 19, 9) +``` + +{/if} + +Tenemos un lote de 1 secuencia con 19 tokens y el modelo tiene 9 etiquetas diferentes, por lo que la salida del modelo tiene dimensiones 1 x 19 x 9. Al igual que el pipeline de clasificación de texto, usamos la función softmax para convertir esos logits en probabilidades, y tomamos el argmax para obtener las predicciones (notar que podemos tomar el argmax de los logits directamente porque el softmax no cambia el orden): + +{#if fw === 'pt'} + +```py +import torch + +probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)[0].tolist() +predictions = outputs.logits.argmax(dim=-1)[0].tolist() +print(predictions) +``` + +{:else} + +```py +import tensorflow as tf + +probabilities = tf.math.softmax(outputs.logits, axis=-1)[0] +probabilities = probabilities.numpy().tolist() +predictions = tf.math.argmax(outputs.logits, axis=-1)[0] +predictions = predictions.numpy().tolist() +print(predictions) +``` + +{/if} + +```python out +[0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 6, 6, 6, 0, 8, 0, 0] +``` + +El atributo `model.config.id2label` contiene el mapeo de los índices con las etiquetas para que podemos hacer sentido de las predicciones: + +```py +model.config.id2label +``` + +```python out +{0: 'O', + 1: 'B-MISC', + 2: 'I-MISC', + 3: 'B-PER', + 4: 'I-PER', + 5: 'B-ORG', + 6: 'I-ORG', + 7: 'B-LOC', + 8: 'I-LOC'} +``` + +Como vimos antes, hay 9 etiquetas: `0` es la etiqueta para los tokens que no tienen ningúna entidad (proviene del inglés "outside"), y luego tenemos dos etiquetas para cada tipo de entidad (misceláneo, persona, organización, y locación). La etiqueta `B-XXX` indica que el token is el inicio de la entidad `XXX` y la etiqueta `I-XXX` indica que el token está dentro de la entidad `XXX`. For ejemplo, en el ejemplo actual esperaríamos que nuestro modelo clasificará el token `S` como `B-PER` (inicio de la entidad persona), y los tokens `##yl`, `##va` y `##in` como `I-PER` (dentro de la entidad persona). + +Podrías pensar que el modelo está equivocado en este caso ya que entregó la etiqueta `I-PER` a los 4 tokens, pero eso no es completamente cierto. En realidad hay 4 formatos par esas etiquetas `B-` y `I-`: *I0B1* y *I0B2*. El formato I0B2 (abajo en rosado), es el que presentamos, mientras que en el formato I0B1 (en azul), las etiquetas de comenzando con `B-` son sólo utilizadas para separar dos entidades adyacentes del mismo tipo. Al modelo que estamos usando se le hizo fine-tune en un conjunto de datos utilizando ese formato, lo cual explica por qué asigna la etiqueta `I-PER` al token `S`. + +
+IOB1 vs IOB2 format + +
+ +Con este mapa, estamos listos para reproducir (de manera casi completa) los resultados del primer pipeline -- basta con tomar los puntajes y etiquetas de cada token que no fue clasificado como `0`: + +```py +results = [] +tokens = inputs.tokens() + +for idx, pred in enumerate(predictions): + label = model.config.id2label[pred] + if label != "O": + results.append( + {"entity": label, "score": probabilities[idx][pred], "word": tokens[idx]} + ) + +print(results) +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S'}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl'}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va'}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in'}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu'}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging'}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face'}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn'}] +``` + +Esto es muy similar a lo que teníamos antes, con una excepción: el pipeline también nos dió información acerca del `inicio` y el `final` de cada entidad en la oración original. Aquí es donde nuestro mapeo de offsets entrarán en juego. Para obtener los offsets, sólo tenemos que fijar la opción `return_offsets_mapping=True` cuando apliquemos el tokenizador a nuestros inputs: + +```py +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +inputs_with_offsets["offset_mapping"] +``` + +```python out +[(0, 0), (0, 2), (3, 7), (8, 10), (11, 12), (12, 14), (14, 16), (16, 18), (19, 22), (23, 24), (25, 29), (30, 32), + (33, 35), (35, 40), (41, 45), (46, 48), (49, 57), (57, 58), (0, 0)] +``` + +Cada tupla es la porción de texto correspondiente a cada token, donde `(0, 0)` está reservado para los tokens especiales. Vimos antes que el token con índice 5 is `##yl`, el cual tiene como offsets `(12, 14)`, Si tomamos los trozos correspondientes en nuestro ejemplo: + + +```py +example[12:14] +``` + +obtenemos la porción apropiada sin los `##`: + + +```python out +yl +``` + +Usando esto, ahora podemos completar los resultados previos: + +```py +results = [] +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +tokens = inputs_with_offsets.tokens() +offsets = inputs_with_offsets["offset_mapping"] + +for idx, pred in enumerate(predictions): + label = model.config.id2label[pred] + if label != "O": + start, end = offsets[idx] + results.append( + { + "entity": label, + "score": probabilities[idx][pred], + "word": tokens[idx], + "start": start, + "end": end, + } + ) + +print(results) +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +Esto es lo mismo que obtuvimos en el primer pipeline! + +### Agrupando Entidades[[grouping-entities]] + +Usar los offsets para determinar las llaves de inicio y fin para cada entidad is útil, pero esa información no es estrictamente necesaria. Cuando queremos agrupar las entidades, sin embargo, los offsets nos ahorarán un montón de código engorroso. Por ejemplo, si queremos agrupar los tokens `Hu`, `##gging`, y `Face`, podemos hacer reglas especiales que digan que los dos primeros se tienen que unir eliminando los `##`, y `Face` debería añadirse con el espacio ya que no comienza con `##` -- pero eso sólo funcionaría para este tipo particular de tokenizador. Tendríamos que escribir otro grupo de reglas para un tokenizador tipo SentencePiece (trozo de oración) tipo Byte-Pair-Encoding (codificación por par de bytes) (los que se discutirán más adelante en este capítulo). + +Con estos offsets, todo ese código hecho a medida no se necesita: basta tomar la porción del texto original que comienza con el primer token y termina con el último token. En el caso de los tokens `Hu`, `##gging`, and `Face`, deberíamos empezar en el character 33 (el inicio de `Hu`) y termianr antes del caracter 45 (al final de `Face`): + +```py +example[33:45] +``` + +```python out +Hugging Face +``` + +Para escribir el código encargado del post-procesamiento de las prediciones que agrupan entidades, agruparemos la entidades que son consecutivas y etiquetadas con `I-XXX`, excepto la primera, la cual puedes estar etiquetada como `B-XXX` o `I-XXX` (por lo que, dejamos de agrupar una entidad cuando nos encontramos un `0`, un nuevo tipo de entidad, o un `B-XXX` que nos dice que una entidad del mismo tipo está empezando): + +```py +import numpy as np + +results = [] +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +tokens = inputs_with_offsets.tokens() +offsets = inputs_with_offsets["offset_mapping"] + +idx = 0 +while idx < len(predictions): + pred = predictions[idx] + label = model.config.id2label[pred] + if label != "O": + # Remove the B- or I- + label = label[2:] + start, _ = offsets[idx] + + # Toma todos los tokens etiquetados con la etiqueta I + all_scores = [] + while ( + idx < len(predictions) + and model.config.id2label[predictions[idx]] == f"I-{label}" + ): + all_scores.append(probabilities[idx][pred]) + _, end = offsets[idx] + idx += 1 + + # El puntaje es la media de todos los puntajes de los tokens en la entidad agrupada + score = np.mean(all_scores).item() + word = example[start:end] + results.append( + { + "entity_group": label, + "score": score, + "word": word, + "start": start, + "end": end, + } + ) + idx += 1 + +print(results) +``` + +Y obtenemos los mismos resultados de nuestro segundo pipeline! + +```python out +[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +Otro ejemplo de una tarea donde estos offsets son extremadamente útiles es question answering. Sumergirnos en ese pipeline, lo cual haremos en la siguiente sección, también nos permitirá echar un vistazo a una última característica de los tokenizadores en la librería 🤗 Transformers: lidiar con tokens desbordados (overflowing tokens) cuando truncamos una entrada/input a un largo dado. diff --git a/chapters/es/chapter6/3b.mdx b/chapters/es/chapter6/3b.mdx new file mode 100644 index 000000000..df6d509fd --- /dev/null +++ b/chapters/es/chapter6/3b.mdx @@ -0,0 +1,643 @@ + + +# Tokenizadores Rápidos en un Pipeline de Question-Answering[[fast-tokenizers-in-the-qa-pipeline]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Ahora nos sumergiremos en el pipeline de `question-answering` (preguntas y respuestas) y veremos como hacer uso de los offsets para tomar la respuesta de la pregunta desde el contexto, un poco como lo que hicimos para las entidades agrupadas en la sección previa. Luego veremos como lidiar con contextos muy largos que terminan siendo truncados. Puedes saltar esta sección si no estás interesado en la tarea de pregunta y respuesta (_question answering_). + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +## Usando el pipeline de `question-answering`[[using-the-question-answering-pipeline]] + +Como vimos en el [Capítulo 1](/course/chapter1), podemos usar el pipeline de `question-answering` para obtener la respuesta a una pregunta de la siguiente manera: + +```py +from transformers import pipeline + +question_answerer = pipeline("question-answering") +context = """ +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch, and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question = "Which deep learning libraries back 🤗 Transformers?" +question_answerer(question=question, context=context) +``` + +```python out +{'score': 0.97773, + 'start': 78, + 'end': 105, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +A diferencia de otros pipelines, los cuales no pueden truncar y dividir textos que son más largos que el largo máximo aceptado por el modelo (y por lo tanto perder información al final de un documento), este pipeline puede lidiar con contextos muy largos y retornará una respuesta a la pregunta incluso si está al final. + +```py +long_context = """ +🤗 Transformers: State of the Art NLP + +🤗 Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, +question answering, summarization, translation, text generation and more in over 100 languages. +Its aim is to make cutting-edge NLP easier to use for everyone. + +🤗 Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and +then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and +can be modified to enable quick research experiments. + +Why should I use transformers? + +1. Easy-to-use state-of-the-art models: + - High performance on NLU and NLG tasks. + - Low barrier to entry for educators and practitioners. + - Few user-facing abstractions with just three classes to learn. + - A unified API for using all our pretrained models. + - Lower compute costs, smaller carbon footprint: + +2. Researchers can share trained models instead of always retraining. + - Practitioners can reduce compute time and production costs. + - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. + +3. Choose the right framework for every part of a model's lifetime: + - Train state-of-the-art models in 3 lines of code. + - Move a single model between TF2.0/PyTorch frameworks at will. + - Seamlessly pick the right framework for training, evaluation and production. + +4. Easily customize a model or an example to your needs: + - We provide examples for each architecture to reproduce the results published by its original authors. + - Model internals are exposed as consistently as possible. + - Model files can be used independently of the library for quick experiments. + +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question_answerer(question=question, context=long_context) +``` + +```python out +{'score': 0.97149, + 'start': 1892, + 'end': 1919, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +¡Veamos cómo hace todo esto! + +## Usando un modelo para question answering[[using-a-model-for-question-answering]] + +Como para cualquier otro pipeline, empezamos tokenizando nuestro input y lo envíamos a través del modelo. El punto de control (`checkpoint`) usado por defecto para el pipeline de `question-answering` es [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) (el "squad" en el nombre viene del conjunto de datos en el cual se le hizo fine-tune; hablaremos más acerca del conjunto de datos SQuAD en el [Capítulo 7](/course/chapter7/7)) + +{#if fw === 'pt'} + +```py +from transformers import AutoTokenizer, AutoModelForQuestionAnswering + +model_checkpoint = "distilbert-base-cased-distilled-squad" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) + +inputs = tokenizer(question, context, return_tensors="pt") +outputs = model(**inputs) +``` + +{:else} + +```py +from transformers import AutoTokenizer, TFAutoModelForQuestionAnswering + +model_checkpoint = "distilbert-base-cased-distilled-squad" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint) + +inputs = tokenizer(question, context, return_tensors="tf") +outputs = model(**inputs) +``` + +{/if} + +Notar que tokenizamos nuestra y el contexto como un par, con la pregunta primero. + +
+An example of tokenization of question and context + +
+ +Los modelos para question answering funcionan de manera un poco distinta de los modelos que hemos visto hasta ahora. Usando la imagen de arriba como ejemplo, el modelo ha sido entrenado para predecir el índice de los tokens al inicio de la respuesta (en este caso el 21) y el índice del token donde la respuesta termina (en este caso el 24). Esto porque estos modelos no retornar un tensor de logits sino dos: uno para los logits correspondientes al token de inicio de la respuesta, y uno para los logits correspondientes al token de término de la respuesta. Dado que en este caso tenemos un input conteniendo 66 tokens, obtenemos: + +```py +start_logits = outputs.start_logits +end_logits = outputs.end_logits +print(start_logits.shape, end_logits.shape) +``` + +{#if fw === 'pt'} + +```python out +torch.Size([1, 66]) torch.Size([1, 66]) +``` + +{:else} + +```python out +(1, 66) (1, 66) +``` + +{/if} + +Para convertir estos logits en probabilidades, aplicaremos la función softmax -- pero antes de eso, necesitamos asegurarnos que enmascaramos los índices que no son parte del contexto. Nuestro input es `[CLS] pregunta [SEP] contexto [SEP]`, por lo que necesitamos enmascarar los tokens de la pregunta como también el token `[SEP]`. Mantredemos el token `[CLS]`, ya que algunos modelos lo usan para indicar que la respuesta no está en el contexto. + +Dado que aplicaremos una softmax después, sólo necesitamos reemplazar los logits que queremos enmascarar con un número negativo muy grande. En este caso, usamos el `-10000`: + +{#if fw === 'pt'} + +```py +import torch + +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +mask = torch.tensor(mask)[None] + +start_logits[mask] = -10000 +end_logits[mask] = -10000 +``` + +{:else} + +```py +import tensorflow as tf + +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +mask = tf.constant(mask)[None] + +start_logits = tf.where(mask, -10000, start_logits) +end_logits = tf.where(mask, -10000, end_logits) +``` + +{/if} + +Ahora que tenemos enmascarados los logits de manera apropiada correspondientes a los tokens que no queremos predecir. Podemos aplicar la softmax: + +{#if fw === 'pt'} + +```py +start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1)[0] +end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1)[0] +``` + +{:else} + +```py +start_probabilities = tf.math.softmax(start_logits, axis=-1)[0].numpy() +end_probabilities = tf.math.softmax(end_logits, axis=-1)[0].numpy() +``` + +{/if} + +En esta punto, podemos tomar el argmax de las probabilidades de inicio y fin -- pero podríamos terminar con un índice de inicio que es mayot que índice de término, por lo que necesitamos tomar unas pocas precauciones más. Calcularemos la probabilidad de cada posible `start_index` and `end_index` (índice de inicio y final respectivamente) donde `start_index <= end_index`, luego tomamos la tupla `(start_index, end_index)` con la probabilidad más alta. + +Asumiendo que los eventos "La respuesta comienzda en `start_index`" y "La respuesta termina en `end_index`" son independientes, la probabilidad de que la respuesta inicie en `start_index` y termine en `end_index` es: + +$$\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]$$ + +Así que para calcular todos los puntajes, necesitamos calcular todos los productos \\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\) donde `start_index <= end_index`. + +Primero calculemos todos los posibles productos: + +```py +scores = start_probabilities[:, None] * end_probabilities[None, :] +``` + +{#if fw === 'pt'} + +Luego enmascararemos los valores donde `start_index > end_index` reemplazándolos como 0 (las otras probabilidades son todos números positivos). La función `torch.triu()` retorna la parte triangular superior de el tensor 2D pasado como argumento, por lo que hará el enmascaramiento por nosotros. + +```py +scores = torch.triu(scores) +``` + +{:else} + + +Luego enmascararemos los valores donde `start_index > end_index` reemplazándolos como 0 (las otras probabilidades son todos números positivos). La función `np.triu()` retorna la parte triangular superior de el tensor 2D pasado como argumento, por lo que hará el enmascaramiento por nosotros. + +```py +import numpy as np + +scores = np.triu(scores) +``` + +{/if} + +Ahora basta con obtener el índice el máximo. Dado que Pytorch retornará el índice en el tensor aplanado, necesitamos usar las operaciones división entera `//` y módulo `%` para obtener el `start_index` y el `end_index`: + +```py +max_index = scores.argmax().item() +start_index = max_index // scores.shape[1] +end_index = max_index % scores.shape[1] +print(scores[start_index, end_index]) +``` + +No estamos listos aún, pero al menos ya tenemos el puntaje correcto para la respuesta (puedes chequear esto comparándolo con el primer resultado en la sección previa): + +```python out +0.97773 +``` + + + +✏️ **Inténtalo!** Calcula los índices de inicio y término para las cinco respuestas más probables. + + + +Tenemos el `start_index` y el `end_index` de la respuesta en términos de tokens, así que ahora sólo necesitamos convertirlos en los índices de caracteres en el contexto. Aquí es donde los offsets serán sumamente útiles. Podemos tomarlos y usarlos como lo hicimos en la tarea de clasificación de tokens: + +```py +inputs_with_offsets = tokenizer(question, context, return_offsets_mapping=True) +offsets = inputs_with_offsets["offset_mapping"] + +start_char, _ = offsets[start_index] +_, end_char = offsets[end_index] +answer = context[start_char:end_char] +``` + +Ahora sólo tenemos que dar formato a todo para tener nuestros resultados: + +```py +result = { + "answer": answer, + "start": start_char, + "end": end_char, + "score": scores[start_index, end_index], +} +print(result) +``` + +```python out +{'answer': 'Jax, PyTorch and TensorFlow', + 'start': 78, + 'end': 105, + 'score': 0.97773} +``` + +Genial! Obtuvimos lo mismo que en nuestro primer ejemplo! + + + +✏️ **Inténtalo!** Usaremos los mejores puntajes calculados anteriormente para mostrar las cinco respuestas más probables. Para revisar nuestros resultados regresa al primer pipeline y agrega `top_k=5` al llamarlo. + + + +## Manejando contextos largos[[handling-long-contexts]] + +Si tratamos de tokenizar la pregunta en un contexto largo que usamos en el ejemplo previamente, tendremos un número de tokens que es más alto que el largo máximo usado en el pipeline de `question-answering` (que es 384): + +```py +inputs = tokenizer(question, long_context) +print(len(inputs["input_ids"])) +``` + +```python out +461 +``` + +Entonces, necesitaremos truncar nuestras entradas/inputs al largo máximo. Hay varias maneras de hacer esto, pero no queremos truncar la pregunta, sólo el contexto. Dado que el contexto es la segunda oración, usaremos la estrategia de truncamiento `"only_second"`. El problema que aparece es que la respuesta a la pregunta podría no estar en el contexto truncado. En este caso, por ejemplo, elegimos una pregunta donde la respuesta está hacia el final del contexto, y cuando truncamos la respuesta no está presente: + +```py +inputs = tokenizer(question, long_context, max_length=384, truncation="only_second") +print(tokenizer.decode(inputs["input_ids"])) +``` + +```python out +""" +[CLS] Which deep learning libraries back [UNK] Transformers? [SEP] [UNK] Transformers : State of the Art NLP + +[UNK] Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, +question answering, summarization, translation, text generation and more in over 100 languages. +Its aim is to make cutting-edge NLP easier to use for everyone. + +[UNK] Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and +then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and +can be modified to enable quick research experiments. + +Why should I use transformers? + +1. Easy-to-use state-of-the-art models: + - High performance on NLU and NLG tasks. + - Low barrier to entry for educators and practitioners. + - Few user-facing abstractions with just three classes to learn. + - A unified API for using all our pretrained models. + - Lower compute costs, smaller carbon footprint: + +2. Researchers can share trained models instead of always retraining. + - Practitioners can reduce compute time and production costs. + - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. + +3. Choose the right framework for every part of a model's lifetime: + - Train state-of-the-art models in 3 lines of code. + - Move a single model between TF2.0/PyTorch frameworks at will. + - Seamlessly pick the right framework for training, evaluation and production. + +4. Easily customize a model or an example to your needs: + - We provide examples for each architecture to reproduce the results published by its original authors. + - Model internal [SEP] +""" +``` + +Esto significa que el modelo le costará bastante elegir la respuesta correcta. Para corregir eso, el pipeline de `question-answering` permite separar el contexto en trozos pequeños, especificando el largo máximo. Para asegurarnos que no separemos el contexto exactamente en un lugar incorrecto donde podríamos encontrar la respuesta, también incluye algunos traslapes (overlaps) entre los trozos. + +Podemos hacer que el tokenizador (rápido o lento) haga esto por nosotros agregando `return_overflowing_tokens=True`, y podemos especificar el traslape (overlap) que queremos con el argumento `stride`. Acá un ejemplo, usando una oración corta: + +```py +sentence = "This sentence is not too long but we are going to split it anyway." +inputs = tokenizer( + sentence, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 +) + +for ids in inputs["input_ids"]: + print(tokenizer.decode(ids)) +``` + +```python out +'[CLS] This sentence is not [SEP]' +'[CLS] is not too long [SEP]' +'[CLS] too long but we [SEP]' +'[CLS] but we are going [SEP]' +'[CLS] are going to split [SEP]' +'[CLS] to split it anyway [SEP]' +'[CLS] it anyway. [SEP]' +``` + +Como podemos ver, la oración ha sido dividida en trozos de tal manera que cada entrada en `inputs["input_ids"] tiene a lo más 6 tokens (tendríamos que agregar relleno (`padding`) en el último trozo para tener el mismo largo que los otros) y hay traslape (overlap) de 2 tokens entre cada uno de los trozos. + +Miremos de cerca el resultado de la tokenización: + +```py +print(inputs.keys()) +``` + +```python out +dict_keys(['input_ids', 'attention_mask', 'overflow_to_sample_mapping']) +``` + +Como se esperaba, obtenemos los IDs de entrada y una máscara de atención (attention mask). La última clave, `overflow_to_sample_mapping`, es un mapa que nos dice a qué oraciones corresponde cada resultado -- en este caso tenemos 7 resultados, todos provenientes de la (única) oración que le pasamos al tokenizador: + +```py +print(inputs["overflow_to_sample_mapping"]) +``` + +```python out +[0, 0, 0, 0, 0, 0, 0] +``` + +Esto es más útil cuando tokenizamos varias oraciones juntas. Por ejemplo así: + +```py +sentences = [ + "This sentence is not too long but we are going to split it anyway.", + "This sentence is shorter but will still get split.", +] +inputs = tokenizer( + sentences, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 +) + +print(inputs["overflow_to_sample_mapping"]) +``` + +obtenemos: + +```python out +[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] +``` + +lo que significa que la primera oración está dividida en 7 trozos igual que antes, y los siguientes 4 trozos vienen de la segunda oración. + +Ahora volvamos a nuestro contexto largo. Por defecto el pipeline de `question-answering` usa un largo máximo de 384, como mencionamos antes, y un stride de 128, lo que corresponde a la manera en la que al modelo se le hizo fine-tuning (puedes ajustar esos parámetros pasando los argumentos `max_seq_len` y `stride` al llamar el pipeline). Por lo tanto, usaremos esos parámetros al tokenizar. También agregaremos relleno (`padding`) (para tener muestras del mismo largo, para que podamos construir los tensores) como también pedir los offsets: + +```py +inputs = tokenizer( + question, + long_context, + stride=128, + max_length=384, + padding="longest", + truncation="only_second", + return_overflowing_tokens=True, + return_offsets_mapping=True, +) +``` + +Esos `inputs` contendrán los IDs de entrada y las máscaras de atención (attention masks) que el modelo espera, así como los offsets y el `overflow_to_sample_mapping` que hablamos antes. Dado que esos dos no son parámetros usados por el modelo, los sacaremos de los `inputs` (y no guardaremos el mapa, ya que no es útil acá) antes de convertirlo en un tensor: + +{#if fw === 'pt'} + +```py +_ = inputs.pop("overflow_to_sample_mapping") +offsets = inputs.pop("offset_mapping") + +inputs = inputs.convert_to_tensors("pt") +print(inputs["input_ids"].shape) +``` + +```python out +torch.Size([2, 384]) +``` + +{:else} + +```py +_ = inputs.pop("overflow_to_sample_mapping") +offsets = inputs.pop("offset_mapping") + +inputs = inputs.convert_to_tensors("tf") +print(inputs["input_ids"].shape) +``` + +```python out +(2, 384) +``` + +{/if} + +Nuestro contexto largo fue dividido en dos, lo que significa que después de pasar por nuestro modelo, tendremos 2 sets de logits de inicio y término: + +```py +outputs = model(**inputs) + +start_logits = outputs.start_logits +end_logits = outputs.end_logits +print(start_logits.shape, end_logits.shape) +``` + +{#if fw === 'pt'} + +```python out +torch.Size([2, 384]) torch.Size([2, 384]) +``` + +{:else} + +```python out +(2, 384) (2, 384) +``` + +{/if} + +Al igual que antes, primero enmascaramos los tokens que no son parte del contexto antes de aplicar softmax. También enmascaramos todos los tokens de de relleno (`padding`) (de acuerdo a la máscara de atención (attention masks)): + +{#if fw === 'pt'} + +```py +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +# Mask all the [PAD] tokens +mask = torch.logical_or(torch.tensor(mask)[None], (inputs["attention_mask"] == 0)) + +start_logits[mask] = -10000 +end_logits[mask] = -10000 +``` + +{:else} + +```py +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +# Mask all the [PAD] tokens +mask = tf.math.logical_or(tf.constant(mask)[None], inputs["attention_mask"] == 0) + +start_logits = tf.where(mask, -10000, start_logits) +end_logits = tf.where(mask, -10000, end_logits) +``` + +{/if} + +Luego podemos usar la función softmax para convertir nuestros logits en probabilidades: + +{#if fw === 'pt'} + +```py +start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1) +end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1) +``` + +{:else} + +```py +start_probabilities = tf.math.softmax(start_logits, axis=-1).numpy() +end_probabilities = tf.math.softmax(end_logits, axis=-1).numpy() +``` + +{/if} + +El siguiente paso es similar a lo que hicimos para el contexto pequeño, pero lo repetimos para cada uno de nuestros dos trozos. Le atribuímos un puntaje a todas las posibles respuestas, para luego tomar la respuesta con el mejor puntaje: + +{#if fw === 'pt'} + +```py +candidates = [] +for start_probs, end_probs in zip(start_probabilities, end_probabilities): + scores = start_probs[:, None] * end_probs[None, :] + idx = torch.triu(scores).argmax().item() + + start_idx = idx // scores.shape[1] + end_idx = idx % scores.shape[1] + score = scores[start_idx, end_idx].item() + candidates.append((start_idx, end_idx, score)) + +print(candidates) +``` + +{:else} + +```py +candidates = [] +for start_probs, end_probs in zip(start_probabilities, end_probabilities): + scores = start_probs[:, None] * end_probs[None, :] + idx = np.triu(scores).argmax().item() + + start_idx = idx // scores.shape[1] + end_idx = idx % scores.shape[1] + score = scores[start_idx, end_idx].item() + candidates.append((start_idx, end_idx, score)) + +print(candidates) +``` + +{/if} + +```python out +[(0, 18, 0.33867), (173, 184, 0.97149)] +``` + +Estos dos candidatos corresponden a las mejores respuestas que el modelo fue capaz de encontrar en cada trozo. El modelo está mucho más confiado de que la respuesta correcta está en la segunda parte (¡lo que es una buena señal!). Ahora sólo tenemos que mapear dichos tokens a los caracteres en el contexto (sólo necesitamos mapear la segunda para obtener nuestra respuesta, pero es interesante ver que el modelo ha elegido en el primer trozo). + + + +✏️ **Inténtalo!** Adapta el código de arriba pra retornar los puntajes de las 5 respuestas más probables (en total, no por trozo). + + + +Los `offsets` que tomamos antes es en realidad una lista de offsets, con una lista por trozo de texto: + +```py +for candidate, offset in zip(candidates, offsets): + start_token, end_token, score = candidate + start_char, _ = offset[start_token] + _, end_char = offset[end_token] + answer = long_context[start_char:end_char] + result = {"answer": answer, "start": start_char, "end": end_char, "score": score} + print(result) +``` + +```python out +{'answer': '\n🤗 Transformers: State of the Art NLP', 'start': 0, 'end': 37, 'score': 0.33867} +{'answer': 'Jax, PyTorch and TensorFlow', 'start': 1892, 'end': 1919, 'score': 0.97149} +``` + +Si ignoramos el primer resultado, obtenemos el mismo resultado que nuestro pipeline para el contexto largo -- bien! + + + +✏️ **Inténtalo!** Usa los mejores puntajes que calculaste antes para mostrar las 5 respuestas más probables. Para revisar tus resultados, regresa al primer pipeline y agrega `top_k=5` al llamarlo. + + + +Esto concluye nuestra profundización en las capacidades de los tokenizadores. Pondremos todo esto en práctica de nuevo en el siguiente capítulo, cuando te mostremos cómo hacer fine-tuning a un modelo en una variedad de tareas comunes de PLN. diff --git a/chapters/es/chapter6/4.mdx b/chapters/es/chapter6/4.mdx new file mode 100644 index 000000000..c020896f7 --- /dev/null +++ b/chapters/es/chapter6/4.mdx @@ -0,0 +1,123 @@ +# Normalización y pre-tokenización[[normalization-and-pre-tokenization]] + + + +Antes de sumergirnos más profundamente en los tres algoritmos más comunes de tokenización usados con los modelos transformers (Byte-Pair Encoding [BPE], WordPiece, and Unigram), primero miraremos el preprocesamiento que cada tokenizador aplica al texto. Acá una descripción general de los pasos en el pipeline de tokenización: + +
+The tokenization pipeline. + +
+ +Antes de dividir un texto en subtokens (de acuerdo a su modelo), el tokenizador realiza dos pasos: _normalización_ y _pre-tokenización_. + +## Normalización[[normalization]] + + + +El paso de normalización involucra una limpieza general, como la remoción de espacios en blanco innecesario, transformar a minúsculas, y/o remoción de acentos. Si estás familiarizado con [Normalización Unicode](http://www.unicode.org/reports/tr15/) (como NFC o NFKC), esto es algo que el tokenizador también puede aplicar. + +Los tokenizadores de la librería 🤗 Transformers tienen un atributo llamado `backend_tokenizer` que provee acceso al tokenizador subyacente de la librería 🤗 Tokenizers: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") +print(type(tokenizer.backend_tokenizer)) +``` + +```python out + +``` + +El atributo `normalizer` del objeto `tokenizer` tiene un método `normalize_str()` que puede puedes usar para ver cómo la normalización se realiza: + +```py +print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +'hello how are u?' +``` + +En este ejemplo, dado que elegimos el punto de control (checkpoint) `bert-base-uncased`, la normalización aplicó transformación a minúsculas y remoción de acentos. + + + +✏️ **Inténtalo!** Carga un tokenizador desde el punto de control (checkpoint)`bert-base-cased` y pásale el mismo ejemplo. Cuáles son las principales diferencias que puedes ver entre las versiones cased y uncased de los tokenizadores? + + + +## Pre-tokenización[[pre-tokenization]] + + + +Como veremos en las siguientes secciones, un tokenizador no puede ser entrenado en un texto tal como viene así nada más. En vez de eso, primero necesitamos separar los textos en entidades más pequeñas, como palabras. Ahí es donde el paso de pre-tokenización entra en juego. Como vimos en el [Capítulo 2](/course/chapter2), un tokenizador basado en palabras (word-based) puede dividir el texto en palabras separando en espacios en blanco y puntuación. Esas palabras serán las fronteras de los subtokens que el tokenizador aprende durante su entrenamiento. + +Para ver qué tan rápido un tokenizador rápido (fast tokenizer) realiza la pre-tokenización, podemos usar el método `pre_tokenize_str()` del atributo `pre_tokenizer` del objeto `tokenizer`: + +```py +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +```python out +[('Hello', (0, 5)), (',', (5, 6)), ('how', (7, 10)), ('are', (11, 14)), ('you', (16, 19)), ('?', (19, 20))] +``` + +Notar como el tokenizador ya lleva registro de los offsets, el cual nos entrega el mapeo de offsets que usamos en la sección anterior. Acá el tokenizador ignora los dos espacios y los reemplaza con uno sólo, pero el offset salta entre `are` y `you` para tomar eso en cuenta. + +Dado que estamos usando un tokenizador BERT, la pre-tokenización involucra separar en espacios en blanco y puntuación. Otros tokenizadores pueden tener distintas reglas para esta etapa. Por ejemplo, si usamor el tokenizador de GPT-2: + +```py +tokenizer = AutoTokenizer.from_pretrained("gpt2") +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +dividirá en espacios en blanco y puntuación también, pero mantendrá los espacios y los reemplazará con el símbolo `Ġ`, permitiendo recobrar los espacios originales en el caso de decodificar los tokens: + +```python out +[('Hello', (0, 5)), (',', (5, 6)), ('Ġhow', (6, 10)), ('Ġare', (10, 14)), ('Ġ', (14, 15)), ('Ġyou', (15, 19)), + ('?', (19, 20))] +``` + +También notar que a diferencia del tokenizador BERT, este tokenizador no ignora los espacios dobles. + +Para el último ejemplo, tenemos que mirar el tokenizador T5, el cuál está basado en el algoritmo SentencePiece: + +```py +tokenizer = AutoTokenizer.from_pretrained("t5-small") +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +```python out +[('▁Hello,', (0, 6)), ('▁how', (7, 10)), ('▁are', (11, 14)), ('▁you?', (16, 20))] +``` + +Al igual que el tokenizador GPT-2, este mantiene los espacios y los reemplaza con un token específico (`_`), pero el tokenizador T5 sólo divide en espacios en blanco, no en puntuación. También notar que agrego un espacio por defecto al inicio de la oración (antes de `Hello`) e ignoró el doble espacio entre `are` y `you`. + +Ahora que hemos visto un poco de cómo los diferentes tokenizadores procesan texto, podemos empezar a explorar los algoritmos subyacentes propiamente tal. Comenzaremos con una mirada rápida al ampliamente aplicable SentencePiece; luego, a lo largo de las 3 secciones siguientes examinaremos cómo los tres principales algoritmos usados para el trabajo de tokenización por subpalabra (subword tokenization). + +## SentencePiece[[sentencepiece]] + +[SentencePiece](https://github.com/google/sentencepiece) es un algoritmo para el preprocesamiento de texto que puedes usar con cualquiera de los modelos que veremos en las siguientes tres secciones. Éste considere el texto como una secuencia de caractéres Unicode, y reemplaza los especios con un caracter especial, `_`. Usado en conjunto con el algoritmo Unigram (ver [Sección 7](/course/chapter7/7)), ni siquiera requiere un paso de pre-tokenización, lo cual es muy útil para lenguajes donde el caracter de espacio no es usado (como el Chino o el Japonés). + +La otra característica principal de SentencePiece es la *tokenización reversible* (tokenización reversible): dado que no hay tratamiento especial de los espacios, decodificar los tokens se hace simplemente concatenandolos y reemplazando los `_`s con espacios -- esto resulta en el texto normalizado. Como vimos antes, el tokenizador BERT remueve los espacios repetidos, por lo que su tokenización no es reversible. + +## Descripción General del Algoritmo[[algorithm-overview]] + +En las siguientes secciones, profundizaremos en los tres principales algoritmos de tokenización por subpalabra (subword tokenization): BPE (usado por GPT-2 y otros), WordPiece (usado por ejemplo por BERT), y Unigram (usado por T5 y otros). Antes de comenzar, aquí una rápida descripción general de cómo funciona cada uno de ellos. No dudes en regresar a esta tabla luego de leer cada una de las siguientes secciones si no te hace sentido aún. + + +Model | BPE | WordPiece | Unigram +:----:|:---:|:---------:|:------: +Entrenamiento | Comienza a partir de un pequeño vocabulario y aprende reglas para fusionar tokens | Comienza a partir de un pequeño vocabulario y aprende reglas para fusionar tokens | Comienza de un gran vocabulario y aprende reglas para remover tokens +Etapa de Entrenamiento | Fusiona los tokens correspondiente a los pares más comunes | Fusiona los tokens correspondientes al par con el mejor puntaje basado en la frecuencia del par, privilegiando pares donde cada token individual es menos frecuente | Remueve todos los tokens en el vocabulario que minimizarán la función de pérdida (loss) calculado en el corpus completo. +Aprende | Reglas de fusión y un vocabulario | Sólo un vocabulario | Un vocabulario con puntaje para cada token +Codificación | Separa una palabra en caracteres y aplica las fusiones aprendidas durante el entrenamiento | Encuentra la subpalabra más larga comenzando del inicio que está en el vocabulario, luego hace lo mismo para el resto de las palabras | Encuentra la separación en tokens más probable, usando los puntajes aprendidos durante el entrenamiento + +Ahora profundicemos en BPE! \ No newline at end of file diff --git a/chapters/es/chapter6/5.mdx b/chapters/es/chapter6/5.mdx new file mode 100644 index 000000000..c8bd82898 --- /dev/null +++ b/chapters/es/chapter6/5.mdx @@ -0,0 +1,360 @@ +# Tokenización por Codificación Byte-Pair[[byte-pair-encoding-tokenization]] + + + +La codificación por pares de byte (Byte-Pair Encoding (BPE)) fue inicialmente desarrollado como un algoritmo para comprimir textos, y luego fue usado por OpenAI para la tokenización al momento de pre-entrenar el modelo GPT. Es usado por un montón de modelos Transformers, incluyendo GPT, GPT-2, RoBERTa, BART, y DeBERTa. + + + + + +💡 Esta sección cubre BPE en produndidad, yendo tan lejos como para mostrar una implementación completa. Puedes saltarte hasta el final si sólo quieres una descripción general del algoritmo de tokenización. + + + +## Algoritmo de Entrenamiento[[training-algorithm]] + +El entrenamiento de BPE comienza calculando el conjunto de palabras únicas usada en el corpus (después de completar las etapas de normalización y pre-tokenización), para luego contruir el vocabulario tomando todos los símbolos usados para escribir esas palabras. Como un ejemplo muy simple, digamos que nuestros corpus usa estas cinco palabras: + + +``` +"hug", "pug", "pun", "bun", "hugs" +``` + +El vocabulario vase entonces será `["b", "g", "h", "n", "p", "s", "u"]`. Para casos reales, el vocabulario base contendrá todos los caracteres ASCII, al menos, y probablemente algunos caracteres Unicode también. Si un ejemplo que estás tokenizando usa un caracter que no está en el corpus de entrenamiento, ese caracter será convertido al token "desconocido". Esa es una razón por la cual muchos modelos de NLP son muy malos analizando contenido con emojis. + + + +Los tokenizadores de GPT-2 y RoBERTa (que son bastante similares) tienen una manera bien inteligente de lidiar con esto: ellos no miran a las palabras como si estuvieran escritas con caracteres Unicode, sino con bytes. De esa manera el vocabulario base tiene un tamaño pequeño (256), pero cada caracter que te puedas imaginar estará incluido y no terminará convertido en el token "desconocido". Este truco se llama *byte-level BPE*. + + + +Luego de obtener el vocabulario base, agregamos nuevos tokens hasta que el tamaño deseado del vocabulario se alcance por medio de aprender *fusiones* (merges), las cuales son reglas para fusionar dos elementos del vocabulario existente en uno nuevo. Por lo que al inicio de estas fusiones crearemos tokens con dos caracteres, y luego, a medida que el entrenamiento avance, subpalabras más largas. + +En cualquier etapa durante el entrenamiento del tokenizador, el algoritmo BPE buscará pos los pares más frecuentes de los tokens existentes (por "par", acá nos referimos a dos tokens consecutivos en una palabra). El par más frecuente es el que será fusionado, y enjuagamos y repetimos para la siguiente etapa. + +Volviedo a nuestro ejemplo previo, asumamos que las palabras tenían las siguientes frecuencias: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +lo que significa que `"hug"` estuvo presente 10 veces en el corpus, `"pug"` 5 veces, `"pun"` 12 veces, `"bun"` 4 veces, and `"hugs"` 5 veces. Empezamos el entrenamiento separando cada palabra en caracteres (los que formaron nuestro vocabulario inicial) para que podamos ver cada palabra como una lista de tokens: + +``` +("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5) +``` + +Luego miramos los pares. El par `("h", "u")` está presente en las palabras `"hug"` y `"hugs"`, 15 veces en el total del corpus. No es el par más frecuente: ese honor le corresponde a `("u", "g")`, el cual está presente en `"hug"`, `"pug"`, y `"hugs"`, para un gran total de 20 veces en el vocabulario. + +Por lo tanto, la primera regla de fusión aprendida por el tokenizador es `("u", "g") -> "ug"`, lo que significa que `"ug"` será agregado al vocabulario, y el par debería ser fusionado en todas las palabras del corpus. Al final de esta etapa, el vocabulario se ve así: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug"] +Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5) +``` + +Ahora tenemos algunos pares que resultan en un token más largo de dos caracteres: por ejemplo el par `("h", "ug")` (presente 15 veces en el corpus). Sin embargo, el par más frecuente en este punto is `("u", "n")`, presente 16 veces en el corpus, por lo que la segunda regla de fusión aprendida es `("u", "n") -> "un"`. Agregando esto y fusionando todas las ocurrencias existentes nos lleva a: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un"] +Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("h" "ug" "s", 5) +``` + +Ahora el par más frecuente es `("h", "ug")`, por lo que aprendemos que la regla de fusión es `("h", "ug") -> "hug"`, lo cual nos da tuestro primer token de tres letras. Luego de la fusión el corpus se ve así: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"] +Corpus: ("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5) +``` + +Y continuamos así hasta que alcancemos el tamaño deseado del vocabulario. + + + +✏️ **Ahora es tu turno!** Cuál crees que será la siguiente regla de fusión? + + + +## Algoritmo de Tokenización[[tokenization-algorithm]] + +La tokenización sigue el proceso de entrenamiento de cerca, en el sentido que nuevos inputs son tokenizados aplicando los siguientes pasos: + +1. Normalización +2. Pre-tokenización +3. Separar las palabras en caracteres individuales +4. Aplicar las reglas de fusión aprendidas en orden en dichas separaciones. + +Tomemos el ejemplo que usamos durante el entrenamiento, con las tres reglas de fusión aprendidas: + +``` +("u", "g") -> "ug" +("u", "n") -> "un" +("h", "ug") -> "hug" +``` +La palabra `"bug"` será tokenizada como `["b", "ug"]`. En cambio, `"mug"`, será tokenizado como `["[UNK]", "ug"]` dado que la letra `"m"` no fue parte del vocabulario base. De la misma manera, la palabra `"thug"` será tokenizada como `["[UNK]", "hug"]`: la letra `"t"` no está en el vocabulario base, y aplicando las reglas de fusión resulta primero la fusión de `"u"` y `"g"` y luego de `"hu"` and `"g"`. + + + +✏️ **Ahora es tu turno!** ¿Cómo crees será tokenizada la palabra `"unhug"`? + + + +## Implementando BPE[[implementing-bpe]] + +Ahora echemos un vistazo a una implementación el algoritmo BPE. Esta no será una versión optimizada que puedes usar en corpus grande; sólo queremos mostrar el código para que puedas entender el algoritmo un poquito mejor. + +Primero necesitamos un corpus, así que creemos uno simple con algunas oraciones: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +A continuación, necesitamos pre-tokenizar el corpus en palabras. Dado que estamos replicando un tokenizador BPE (como GPT-2), usaremos el tokenizdor `gpt2` para la pre-tokenización: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("gpt2") +``` + +Luego calculamos las frecuencias de cada palabra en el corpues mientras hacemos la pre-tokenización: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) + +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +print(word_freqs) +``` + +```python out +defaultdict(int, {'This': 3, 'Ġis': 2, 'Ġthe': 1, 'ĠHugging': 1, 'ĠFace': 1, 'ĠCourse': 1, '.': 4, 'Ġchapter': 1, + 'Ġabout': 1, 'Ġtokenization': 1, 'Ġsection': 1, 'Ġshows': 1, 'Ġseveral': 1, 'Ġtokenizer': 1, 'Ġalgorithms': 1, + 'Hopefully': 1, ',': 1, 'Ġyou': 1, 'Ġwill': 1, 'Ġbe': 1, 'Ġable': 1, 'Ġto': 1, 'Ġunderstand': 1, 'Ġhow': 1, + 'Ġthey': 1, 'Ġare': 1, 'Ġtrained': 1, 'Ġand': 1, 'Ġgenerate': 1, 'Ġtokens': 1}) +``` + +El siguiente paso es calcualar el vocabulario base, formado por todos los caracteres usados en el corpus: + +```python +alphabet = [] + +for word in word_freqs.keys(): + for letter in word: + if letter not in alphabet: + alphabet.append(letter) +alphabet.sort() + +print(alphabet) +``` + +```python out +[ ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', + 't', 'u', 'v', 'w', 'y', 'z', 'Ġ'] +``` + +También agregamos el token especial usado por el modelo al inicio de ese vocabulario. En el caso de GPT-2, el único token especial es `"<|endoftext|>"`: + +```python +vocab = ["<|endoftext|>"] + alphabet.copy() +``` + +Ahora necesitamos separar cada palabra en caracteres individuales, para poder comenzar el entrenamiento: + +```python +splits = {word: [c for c in word] for word in word_freqs.keys()} +``` + +Ahora estamos listos para el entrenamiento, escribamos una función que calcule la frecuencia de cada par. Necesitaremos usar esto en cada paso del entrenamiento: + +```python +def compute_pair_freqs(splits): + pair_freqs = defaultdict(int) + for word, freq in word_freqs.items(): + split = splits[word] + if len(split) == 1: + continue + for i in range(len(split) - 1): + pair = (split[i], split[i + 1]) + pair_freqs[pair] += freq + return pair_freqs +``` + +Ahora miremos una parte de ese diccionario después de las separaciones iniciales: + +```python +pair_freqs = compute_pair_freqs(splits) + +for i, key in enumerate(pair_freqs.keys()): + print(f"{key}: {pair_freqs[key]}") + if i >= 5: + break +``` + +```python out +('T', 'h'): 3 +('h', 'i'): 3 +('i', 's'): 5 +('Ġ', 'i'): 2 +('Ġ', 't'): 7 +('t', 'h'): 3 +``` + +Ahora, encontrar el par más frecuenta sólo toma un rápido ciclo: + +```python +best_pair = "" +max_freq = None + +for pair, freq in pair_freqs.items(): + if max_freq is None or max_freq < freq: + best_pair = pair + max_freq = freq + +print(best_pair, max_freq) +``` + +```python out +('Ġ', 't') 7 +``` + +Por lo que la primera fusión a aprender es `('Ġ', 't') -> 'Ġt'`, y luego agregamos `'Ġt'` al vocabulario: + +```python +merges = {("Ġ", "t"): "Ġt"} +vocab.append("Ġt") +``` + +Para continuar, necesitamos aplicar la fusión en nuestro diccionario de divisiones (`splits` dictionary). Escribamos otra función para esto: + +```python +def merge_pair(a, b, splits): + for word in word_freqs: + split = splits[word] + if len(split) == 1: + continue + + i = 0 + while i < len(split) - 1: + if split[i] == a and split[i + 1] == b: + split = split[:i] + [a + b] + split[i + 2 :] + else: + i += 1 + splits[word] = split + return splits +``` + +Y podemos echar un vistazo al resultado de nuestra primera fusión: + +```py +splits = merge_pair("Ġ", "t", splits) +print(splits["Ġtrained"]) +``` + +```python out +['Ġt', 'r', 'a', 'i', 'n', 'e', 'd'] +``` + +Ahora tenemos todo lo que necesitamos para iterar hasta que aprendamos todas las fusiones que queramos. Apuntemos a un tamaño de vocabulario de 50: + +```python +vocab_size = 50 + +while len(vocab) < vocab_size: + pair_freqs = compute_pair_freqs(splits) + best_pair = "" + max_freq = None + for pair, freq in pair_freqs.items(): + if max_freq is None or max_freq < freq: + best_pair = pair + max_freq = freq + splits = merge_pair(*best_pair, splits) + merges[best_pair] = best_pair[0] + best_pair[1] + vocab.append(best_pair[0] + best_pair[1]) +``` + +Como resultado, hemos aprendido 19 reglas de fusión (el vocabulario inicial tenía un tamaño de 31 -- 30 caracteres del alfabeto, más el token especial): + +```py +print(merges) +``` + +```python out +{('Ġ', 't'): 'Ġt', ('i', 's'): 'is', ('e', 'r'): 'er', ('Ġ', 'a'): 'Ġa', ('Ġt', 'o'): 'Ġto', ('e', 'n'): 'en', + ('T', 'h'): 'Th', ('Th', 'is'): 'This', ('o', 'u'): 'ou', ('s', 'e'): 'se', ('Ġto', 'k'): 'Ġtok', + ('Ġtok', 'en'): 'Ġtoken', ('n', 'd'): 'nd', ('Ġ', 'is'): 'Ġis', ('Ġt', 'h'): 'Ġth', ('Ġth', 'e'): 'Ġthe', + ('i', 'n'): 'in', ('Ġa', 'b'): 'Ġab', ('Ġtoken', 'i'): 'Ġtokeni'} +``` + +And the vocabulary is composed of the special token, the initial alphabet, and all the results of the merges: + +```py +print(vocab) +``` + +```python out +['<|endoftext|>', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', + 'p', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z', 'Ġ', 'Ġt', 'is', 'er', 'Ġa', 'Ġto', 'en', 'Th', 'This', 'ou', 'se', + 'Ġtok', 'Ġtoken', 'nd', 'Ġis', 'Ġth', 'Ġthe', 'in', 'Ġab', 'Ġtokeni'] +``` + + + +💡 Usar `train_new_from_iterator()` en el mismo corpus no resultará en exactament el mismo vocabulario. Esto es porque cuando hay una elección del par más frecuente, seleccionamos el primero encontrado, mientras que la librería 🤗 Tokenizers selecciona el primero basado en sus IDs internos. + + + +Para tokenizar un nuevo texto lo pre-tokenizamos, lo separamos, luego aplicamos todas las reglas de fusión aprendidas: + +```python +def tokenize(text): + pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in pre_tokenize_result] + splits = [[l for l in word] for word in pre_tokenized_text] + for pair, merge in merges.items(): + for idx, split in enumerate(splits): + i = 0 + while i < len(split) - 1: + if split[i] == pair[0] and split[i + 1] == pair[1]: + split = split[:i] + [merge] + split[i + 2 :] + else: + i += 1 + splits[idx] = split + + return sum(splits, []) +``` + +Podemos intentar esto con cualquier texto compuesto de de caracteres del alfabeto: + +```py +tokenize("This is not a token.") +``` + +```python out +['This', 'Ġis', 'Ġ', 'n', 'o', 't', 'Ġa', 'Ġtoken', '.'] +``` + + + +⚠️ Nuestra implementación arrojará un error si hay un caracter desconocido dado que no hicimos nada para manejarlos. GPT-2 en realidad no tiene un token desconocido (es imposible obtener un caracter desconocido cuando se usa byte-level BPE), pero esto podría ocurrir acá porque no incluímos todos los posibles bytes en el vocabulario inicial. Este aspectode BPE va más allá del alcance de está sección, por lo que dejaremos los detalles fuera. + + + +Eso es todo para el algoritmo BPE! A continuación echaremos un vistazo a WordPiece. \ No newline at end of file diff --git a/chapters/es/chapter6/6.mdx b/chapters/es/chapter6/6.mdx new file mode 100644 index 000000000..bb5dd62e5 --- /dev/null +++ b/chapters/es/chapter6/6.mdx @@ -0,0 +1,373 @@ +# Tokenización WordPiece[[wordpiece-tokenization]] + + + +WordPiece es el algoritmo de tokenización que Google desarrolló para pre-entrenar BERT. Ha sido reutilizado un varios modelos Transformers basados en BERT, tales como DistilBERT, MobileBERT, Funnel Transformers, y MPNET. Es muy similar a BPE en términos del entrenamiento, pero la tokenización se hace de distinta manera. + + + + + +💡 Esta sección cubre WordPiece en profundidad, yendo tan lejos como para mostrar una implementación completa. Puedes saltarte hasta el final si sólo quieres una descripción general del algoritmo de tokenización. + + + +## Algoritmo de Entrenamiento[[training-algorithm]] + + + +⚠️ Google nunca liberó el código (open-sourced) su implementación del algoritmo de entrenamiento de WordPiece, por tanto lo que sigue es nuestra mejor suposición badado en la literatura publicada. Puede no ser 100% preciso. + + + +Al igual que BPE, WordPiece comienza a partir de un pequeño vocabulario incluyendo los tokens especiales utilizados por el modelo y el alfabeto inicial. Dado que identifica subpalabras (subwords) agregando un prefijo (como `##` para el caso de BERT), cada palabra está inicialmente separada agregando dicho prefijo a todos los caracteres dentro de la palabra. Por lo que por ejemplo la palabra `"word"` queda separada así: + +``` +w ##o ##r ##d +``` +Por lo tanto, el alfabeto inicial contiene todos los caracteres presentes al comienzo de una palabra y los caracteres presente dentro de una palabra precedida por el prefijo de WordPiece. + +Luego, de nuevo al igual que BPE, WordPiece aprende reglas de fusión. La principal diferencia es la forma que el par fusionado es seleccionado. Envex de seleccionar el par más frecuente, WordPiece calcula un puntaje para cada par, utilizando la siguiente formula: + +$$\mathrm{score} = (\mathrm{freq\_of\_pair}) / (\mathrm{freq\_of\_first\_element} \times \mathrm{freq\_of\_second\_element})$$ + +Dividiendo por la frecuencia del par por el producto de las frecuencias de cada una de sus partes, el algoritmo prioriza la fusión de pares donde las partes individuales son menos frecuentes en el vocabulario. Por ejemplo, no fusionará necesariamente `("un", "##able")` incluso si ese par ocurre de manera muy frecuente en el vocabulario, porque los dos pares `"un"` y `"##able"` muy probablemente aparecerán en un montón de otras palabras y tendrán una alta frecuencia. En contraste con un par como `("hu", "##gging")` los cuales son probablemente menos frecuentes individualmente. + +Miremos el mismo vocabulario que usamos en el ejemplo de entrenamiento de BPE: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +Las separaciones acá serán: + +``` +("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##g" "##s", 5) +``` + +por lo que el vocabulario inicial será `["b", "h", "p", "##g", "##n", "##s", "##u"]` (si nos olvidamos de los tokens especiales por ahora). El par más frecuente es `("##u", "##g")` (presente 20 veces), pero la frecuencia individual de `"##u"` es muy alta, por lo que el puntaje no es el más alto (es 1 / 36). Todos los pares con `"##u"` en realidad tienen el mismo puntaje (1 / 36), por lo que el mejor puntaje va para el par `("##g", "##s")` -- el único sin `"##u"` -- 1 / 20, y la primera fusión aprendida es `("##g", "##s") -> ("##gs")`. + +Notar que cuando fusionamos, removemos el `##` entre los dos tokens, por que agregamos `"##gs"` al vocabulario y aplicamos la fusión en las palabras del corpus: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"] +Corpus: ("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##gs", 5) +``` + +En este punto, `"##u"` está en todos los posibles pares, por lo que todos terminan con el mismo puntaje. Digamos que en este caso, el primer par se fusiona, `("h", "##u") -> "hu"`. Esto nos lleva a: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu"] +Corpus: ("hu" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) +``` + +Luego el siguiente mejor puntaje está compartido por `("hu", "##g")` y `("hu", "##gs")` (con 1/15, comparado con 1/21 para todos los otros pares), por lo que el primer par con el puntaje más alto se fusiona: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu", "hug"] +Corpus: ("hug", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) +``` + +y continuamos como esto hasta que alcancemos el tamaño de vocabulario deseado. + + + +✏️ **Ahora es tu turno!** Cuál será la siguiente regla de fusioń? + + + +## Algoritmo de Tokenización[[tokenization-algorithm]] + +La tokenización difiere en WordPiece y BPE en que WordPiece sólo guarda el vocabulario final, no las reglas de fusión aprendidas. Comenzando a partir de la palabra a tokenizar, WordPiece encuentra la subpalabra más larga que está en el vocabulario, luego la separa. Por ejemplo, su usamos el vocabulario aprendido en el ejemplo anterior, para la palabra `"hugs"` la subpalabra más larga comenzando desde el inicio que está dentro del vocabulario es `"hug"`, por lo que separamos ahí y obtenemos `["hug", "##s"]`. Luego continuamos con `"##s"`, el cuál está en el vocabulario, por lo que la tokenización de `"hugs"` es `["hug", "##s"]`. + +Con BPE, habríamos aplicado las fusiones aprendidas en orden y tokenizado esto como `["hu", "##gs"]`, por lo que la codificación es diferente. + +Como otro ejemplo, veamos como la palabra `"bugs"` sería tokenizado. `"b"` es la subpalabra más larga comenzando del inicio de la palabra que está en el vocabulario, por lo que separamos ahí y obtenemos `["b", "##ugs"]`. Luego `"##u"` es la subpalabra más larga somenzando desde el inicio de `"##ugs"` que está en el vocabulario, por lo que separamos ahí y obtenemos `["b", "##u, "##gs"]`. Finalmente, `"##gs"` está en el vocabulario, por lo que esta última lista es la tokenización de `"bugs"`. + +Cuando la tokenización llega a la etapa donde ya no es posible encontrar una subpalabra en el vocabulario, la palabra entera es tokenizada como desconocida -- Por ejemplo, `"mug"` sería tokenizada como `["[UNK]"]`, al igual que `"bum"` (incluso si podemos comenzar con `"b"` y `"##u"`, `"##m"` no está en el vocabulario, y la tokenización resultante será sólo `["[UNK]"]`, y no `["b", "##u", "[UNK]"]`). Este es otra diferencia con respecto a BPE, el cual sólo clasificaría los caracteres individuales que no están en el vocabulario como desconocido. + + + +✏️ **Ahora es tu turno!** ¿Cómo se tokenizaría la palabra `"pugs"`? + + + +## Implementando WordPiece[[implementing-wordpiece]] + +Ahora echemos un vistazo a una implementación del algoritmo WordPiece. Al igual que BPE, este es sólo pedagócico y no podrás aplicar esto en corpus grande. + +Usaremos el mismo corpus que en el ejemplo de BPE: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +Primero, necesitamos pre-tokenizar el corpus en palabras. Dado que estamos replicando el tokenizador WordPiece (como BERT), usaremos el tokenizador `bert-base-cased` para la pre-tokenización: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Luego calculamos las frecuencias de cada palabra en el corpus mientras hacemos la pre-tokenización: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +word_freqs +``` + +```python out +defaultdict( + int, {'This': 3, 'is': 2, 'the': 1, 'Hugging': 1, 'Face': 1, 'Course': 1, '.': 4, 'chapter': 1, 'about': 1, + 'tokenization': 1, 'section': 1, 'shows': 1, 'several': 1, 'tokenizer': 1, 'algorithms': 1, 'Hopefully': 1, + ',': 1, 'you': 1, 'will': 1, 'be': 1, 'able': 1, 'to': 1, 'understand': 1, 'how': 1, 'they': 1, 'are': 1, + 'trained': 1, 'and': 1, 'generate': 1, 'tokens': 1}) +``` + +Como vimos antes, el alfabeto es el único conjunto compuesto de todas las primeras letras de las palabras, y todas las otras letras que aparecen con el prefijo `##`: + +```python +alphabet = [] +for word in word_freqs.keys(): + if word[0] not in alphabet: + alphabet.append(word[0]) + for letter in word[1:]: + if f"##{letter}" not in alphabet: + alphabet.append(f"##{letter}") + +alphabet.sort() +alphabet + +print(alphabet) +``` + +```python out +['##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', '##l', '##m', '##n', '##o', '##p', '##r', '##s', + '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', + 'w', 'y'] +``` + +También agregamos los tokens especiales usados por el modelo al inicio de ese vocabulario. En el caso de BERT, es la lista `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]`: + +```python +vocab = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] + alphabet.copy() +``` + +A continuación necesitamos separar cada palabra, con todas las letras que no tienen el prefijo `##`: + +```python +splits = { + word: [c if i == 0 else f"##{c}" for i, c in enumerate(word)] + for word in word_freqs.keys() +} +``` + +Ahora que estamos listos para el entrenamiento, escribamos una función que calcule el puntaje para cada par. Usaremos esto en cada etapa del entrenamiento: + +```python +def compute_pair_scores(splits): + letter_freqs = defaultdict(int) + pair_freqs = defaultdict(int) + for word, freq in word_freqs.items(): + split = splits[word] + if len(split) == 1: + letter_freqs[split[0]] += freq + continue + for i in range(len(split) - 1): + pair = (split[i], split[i + 1]) + letter_freqs[split[i]] += freq + pair_freqs[pair] += freq + letter_freqs[split[-1]] += freq + + scores = { + pair: freq / (letter_freqs[pair[0]] * letter_freqs[pair[1]]) + for pair, freq in pair_freqs.items() + } + return scores +``` + +Echemos un vistazo a parte de este diccionario luego de las separaciones iniciales: + +```python +pair_scores = compute_pair_scores(splits) +for i, key in enumerate(pair_scores.keys()): + print(f"{key}: {pair_scores[key]}") + if i >= 5: + break +``` + +```python out +('T', '##h'): 0.125 +('##h', '##i'): 0.03409090909090909 +('##i', '##s'): 0.02727272727272727 +('i', '##s'): 0.1 +('t', '##h'): 0.03571428571428571 +('##h', '##e'): 0.011904761904761904 +``` + +Ahora, encontrar el par con el mejor puntaje sólo toma un rápido ciclo: + +```python +best_pair = "" +max_score = None +for pair, score in pair_scores.items(): + if max_score is None or max_score < score: + best_pair = pair + max_score = score + +print(best_pair, max_score) +``` + +```python out +('a', '##b') 0.2 +``` + +Por lo que la primera fusión a aprender es `('a', '##b') -> 'ab'`, y agregamos `'ab'` al vocabulario: + +```python +vocab.append("ab") +``` + +Para continuar, necesitamos aplicar esa fusión en nuestro diccionario de separaciones (`splits` dictionary). Escribamos otra función para esto: + +```python +def merge_pair(a, b, splits): + for word in word_freqs: + split = splits[word] + if len(split) == 1: + continue + i = 0 + while i < len(split) - 1: + if split[i] == a and split[i + 1] == b: + merge = a + b[2:] if b.startswith("##") else a + b + split = split[:i] + [merge] + split[i + 2 :] + else: + i += 1 + splits[word] = split + return splits +``` + +Y podemos mirar el resultado de la primera fusión: + +```py +splits = merge_pair("a", "##b", splits) +splits["about"] +``` + +```python out +['ab', '##o', '##u', '##t'] +``` + +Ahora tenemos todos los que necesitamos para iterar hasta haber aprendido todas las fusiones que queramos. Apuntemos a un tamaño de vocabulario de 70: + +```python +vocab_size = 70 +while len(vocab) < vocab_size: + scores = compute_pair_scores(splits) + best_pair, max_score = "", None + for pair, score in scores.items(): + if max_score is None or max_score < score: + best_pair = pair + max_score = score + splits = merge_pair(*best_pair, splits) + new_token = ( + best_pair[0] + best_pair[1][2:] + if best_pair[1].startswith("##") + else best_pair[0] + best_pair[1] + ) + vocab.append(new_token) +``` + +Luego podemos ver el vocabulario generado: + +```py +print(vocab) +``` + +```python out +['[PAD]', '[UNK]', '[CLS]', '[SEP]', '[MASK]', '##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', + '##l', '##m', '##n', '##o', '##p', '##r', '##s', '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', + 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', 'w', 'y', 'ab', '##fu', 'Fa', 'Fac', '##ct', '##ful', '##full', '##fully', + 'Th', 'ch', '##hm', 'cha', 'chap', 'chapt', '##thm', 'Hu', 'Hug', 'Hugg', 'sh', 'th', 'is', '##thms', '##za', '##zat', + '##ut'] +``` + +Como podemos ver, comparado con BPE, este tokenizador aprende partes de palabras como tokens un poco más rápido. + + + +💡 Usar `train_new_from_iterator()` en el mismo corpus no resultará en exactamente el mismo vocabulario. Esto porque la librería 🤗 Tokenizers no implementa WordPiece para el entrenamiento (dado que no estamos completamente seguros de su funcionamiento interno), en vez de eso utiliza BPE. + + + +Para tokenizar un nuevo texto, lo pre-tokenizamos, lo separamos, y luego aplicamos el algoritmo de tokenización para cada palabra. Es decir, miramos la subpalabra más grande comenzando al inicio de la primera palabra y la separamos, luego repetimos el proceso en la segunda parte, y así pará el resto de dicha palabra y de las siguientes palabras en el texto: + +```python +def encode_word(word): + tokens = [] + while len(word) > 0: + i = len(word) + while i > 0 and word[:i] not in vocab: + i -= 1 + if i == 0: + return ["[UNK]"] + tokens.append(word[:i]) + word = word[i:] + if len(word) > 0: + word = f"##{word}" + return tokens +``` + +Probémoslo en una palabra que esté en el vocabulario, y en otra que no esté: + +```python +print(encode_word("Hugging")) +print(encode_word("HOgging")) +``` + +```python out +['Hugg', '##i', '##n', '##g'] +['[UNK]'] +``` + +Ahora, escribamos una función que tokenize un texto: + +```python +def tokenize(text): + pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in pre_tokenize_result] + encoded_words = [encode_word(word) for word in pre_tokenized_text] + return sum(encoded_words, []) +``` + +Podemos probar en cualquier texto: + +```python +tokenize("This is the Hugging Face course!") +``` + +```python out +['Th', '##i', '##s', 'is', 'th', '##e', 'Hugg', '##i', '##n', '##g', 'Fac', '##e', 'c', '##o', '##u', '##r', '##s', + '##e', '[UNK]'] +``` + +Eso es todo para el algoritmo WordPiece! Ahora echemos un visto a Unigram. diff --git a/chapters/es/chapter6/7.mdx b/chapters/es/chapter6/7.mdx new file mode 100644 index 000000000..325e86c7c --- /dev/null +++ b/chapters/es/chapter6/7.mdx @@ -0,0 +1,382 @@ +# Tokenización Unigram[[unigram-tokenization]] + + + +El algoritmo de Unigram es a menudo utilizado en SetencePiece, el cual es el algoritmo de tokenización usado por modelos como AlBERT, T5, mBART, Big Bird y XLNet. + + + + + +💡 Esta sección cubre Unigram en profundidad, yendo tan lejos como para mostrar una implementación completa. Puedes saltarte hasta el final si sólo quieres una descripción general del algoritmo de tokenización. + + + +## Algoritmo de Entrenamiento[[training-algorithm]] + +Comparado con BPE y WordPiece, Unigram funciona en la otra dirección: comienza desde un gran vocabulario y remueve tokens hasta que alcanza el tamaño deseado del vocabulario.. Hay varias opciones para construir el vocabulario base: podemos tomar los substrings más comunes en palabras pre-tokenizadas, por ejemplo, o aplicar BPE en el corpus inicial con un tamaño de vocabulario grande. + +En cada paso del entrenamiento, el algoritmo de Unigram calcula la pérdida (`loss`)sobre el corpus dado el vocabulario actual. Entonces para cada símbolo en el vocabulario, el algoritmo calcula cuánto incremetaría el la pérdida (`loss`) total si el símbolo se remueve, y busca por los símbolos que lo incrementarían lo menos posible. Esos símbolos tienen un efecto más bajo en la pérdida sobre el corpus, por lo que en un sentido son "menos necesarios" y son los mejores candidatos para ser removidos. + +Esto es una operación bastante costosa, por lo que no removemos un sólo símbolo asociato con el incremento en la pérdida (`loss`) más baja, sino que \\(p\\) (\\(p\\) es un parámetro que puedes controlar, usualmente 10 o 20) porciento de los símbolos asociados con el incremento más bajo de la pérdida. Este proceso es repetido hasta que el vocabulario ha alcanzado el tamaño deseado. + +Nota que nunca removemos los caracteres base, para asegurarnos que cada palabra pueda ser tokenizada. + +Hora, esto es todavía un poco vago: la parte principal del algoritmo es calcular una pérdida (`loss`) sobre el corpus, y ver como cambia cuando removemos algunos tokens desde el vocabulario, pero no hemos explicado como hacer esto aún. Este paso se basa en el algoritmo de tokenización de un modelo Unigram, por lo que profundizaremos en esto a continuación. + +Usaremos el corpus de los ejemplos previos: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +y para este ejemplo, tomaremos todos los substrings strictos para el vocabulario inicial. + +``` +["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"] +``` + +## Algoritmo de Tokenización[[tokenization-algorithm]] + +Un modelo Unigram es un tipo de modelo de lenguaje que considera cada token como independiente de los tokens antes que él. Es el modelo de lenguaje más simple, en el sentido de que la probabilidad de que el token X dado el contexto previo es sólo la probabilidad del token X. Por lo que, si usamos un modelo de Lenguaje Unigram para generar texto, siempre predeciríamos el token más común. + +La probabilidad de un token dado es su frecuencia (el número de veces en el cual lo encontramos) en el corpus original, dividido por la suma de todas las frecuencias de todos los tokens en el vocabulario (para asegurarnos que las probabilidad sumen 1). Por ejemplo, `"ug"` está presente en `"hug"`, `"pug"`, y `"hugs"`, por lo que tiene una frecuencia de 20 en nuestro corpus. + +Acá están las frecuencias de todas las posibles subpalabras en el vocabulario: + +``` +("h", 15) ("u", 36) ("g", 20) ("hu", 15) ("ug", 20) ("p", 17) ("pu", 17) ("n", 16) +("un", 16) ("b", 4) ("bu", 4) ("s", 5) ("hug", 15) ("gs", 5) ("ugs", 5) +``` + +Por lo que, la suma de todas las frecuencias es 210, y la probabilidad de la subpalabra `"ug"` es por lo tanto 20/210. + + + +✏️ **Ahora es tu turno!** Escribe el código para calcular las frecuencias de arriba y chequea que los resultados mostrados son correctos, como también la suma total. + + + +Ahora, para tokenizar una palabra dada, miramos todas las posibles segmentaciones en tokens y calculamos la probabilidad de cada uno de acuerdo al modelo Unigram. Dado que todos los tokens se consideran como independientes, esta probabilidad es sólo el producto de la probabilidad de cada token. Por ejemplo, la tokenización `["p", "u", "g"]` de `"pug"` tiene como probabilidad: + +$$P([``p", ``u", ``g"]) = P(``p") \times P(``u") \times P(``g") = \frac{5}{210} \times \frac{36}{210} \times \frac{20}{210} = 0.000389$$ + +Comparativamente, la tokenización `["pu", "g"]` tiene como probabilidad: + +$$P([``pu", ``g"]) = P(``pu") \times P(``g") = \frac{5}{210} \times \frac{20}{210} = 0.0022676$$ + +por lo que es un poco más probable. En general, las tokenizaciones con el menor número de tokens posibles tendrán la probabilidad más alta (debido a la división por 210 repetida para cada token), lo cual corresponde a lo que queremos intuitivamente: separar una palabra en el menor número de tokens posibles. + +La tokenización de una palabra con el modelo Unigram es entonces la tokenización con la probabilidad más alta. Acá están las probabilidades para el ejemplo de `"pug"` que obtendríamos para cada posible segmentación: + +``` +["p", "u", "g"] : 0.000389 +["p", "ug"] : 0.0022676 +["pu", "g"] : 0.0022676 +``` + +Por lo que, `"pug"` sería tokenizado como `["p", "ug"]` o `["pu", "g"]`, dependiendo de cual de esas segmentaciones e encuentre primero (notar que en un corpus grande, casos equivalentes como este serán raros). + +En este caso, fue fácil encontrar todas las posibles segmentaciones y calcular sus probabilidades, pero en general, va a ser un poco más difícil. Hay un algoritmo clásico usado para esto, llamado el *Algoritmo de Viterbi* (*Viterbi algorithm*). Esencialmente, podemos construir un grafo para detectar las posibles segmentaciones de una palabra dada diciendo que existe una rama que va desde el caracter _a_ hasta el caracter _b_ si la subpalabra de _a_ hasta _b_ está en el vocabulario, y se atribuye a esa rama la probabilidad de la subpalabra. + +Para encontrar el camino en dicho grafo que va a tener el mejor puntaje el Algoritmo de Viterbi determina, por cada posición en la palabra, la segmentacion con el mejor puntaje que termina en esa posición. Dado que vamos desde el inicio al final, el mejor puntaje puede ser encontrado iterando a través de todas las subpalabras que terminan en la posición actual y luego usando el mejor puntaje de tokenización desde la posición en que esta palabra comienza. Luego sólo tenemos que desenrollar el camino tomado para llegar al final. + +Echemos un vistazo a un ejemplo usando nuestro vocabulario y la palabra `"unhug"`. Para cada posición, las subpalabras con el mejor puntaje terminando ahí son las siguientes: + +``` +Character 0 (u): "u" (score 0.171429) +Character 1 (n): "un" (score 0.076191) +Character 2 (h): "un" "h" (score 0.005442) +Character 3 (u): "un" "hu" (score 0.005442) +Character 4 (g): "un" "hug" (score 0.005442) +``` + +Por lo tanto, `"unhug"` se tokenizaría como `["un", "hug"]`. + + + +✏️ **Ahora es tu turno!** Determina la tokenización de la palabra `"huggun"`, y su puntaje + + + + +## De vuelta al entrenamiento[[back-to-training]] + +Ahora que hemos visto cómo funciona la tokenización, podemos ir un poco más profundo en la pérdida (`loss`) usada durante el entrenamiento. En cualquier etapa, esta pérdida (`loss`) es calculada tokenizando cualquier palabra en el corpus, usando el vocabulario actual y el modelo Unigram determinado por las frecuencias de cada token en el corpus (como se vió antes). + +Cada palabra en el corpus tiene un puntaje, y la pérdida (`loss`) es la log verosimilitud negativa (negative log likelihood) de estos puntajes -- es decir, la suma por todas las palabras en el corpus de todos los `-log(P(word))`. + +Volvamos a nuestro ejemplo con el siguiente corpus: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +La tokenización de cada palabra con sus respectivos puntajes es: + +``` +"hug": ["hug"] (score 0.071428) +"pug": ["pu", "g"] (score 0.007710) +"pun": ["pu", "n"] (score 0.006168) +"bun": ["bu", "n"] (score 0.001451) +"hugs": ["hug", "s"] (score 0.001701) +``` + +Por lo que la loss es: + +``` +10 * (-log(0.071428)) + 5 * (-log(0.007710)) + 12 * (-log(0.006168)) + 4 * (-log(0.001451)) + 5 * (-log(0.001701)) = 169.8 +``` + +Ahora necesitamos calcular cómo remover cada token afecta a la pérdida (`loss`). Esto es bastante tedioso, por lo que lo haremos sólo para dos tokens avá y nos ahorraremos el proceso entero para cuando tengamos código que nos ayude. En este (muy) particular caso, teníamos dos tokenizaciones equivalentes de todas las palabras: como vimos antes, por ejemplo, `"pug"` podría ser tokenizado como `["p", "ug"]` con el mismo puntaje. Por lo tanto, removiendo el token `"pu"` del vocabulario nos dará la misma pérdida. + +Por otro lado, remover, `"hug"` hará nuestra pérdida peor, porque la tokenización de `"hug"` y `"hugs"` se convertirá en: + +``` +"hug": ["hu", "g"] (score 0.006802) +"hugs": ["hu", "gs"] (score 0.001701) +``` + +Estos cambios causarán que la pérdida aumenta en: + +``` +- 10 * (-log(0.071428)) + 10 * (-log(0.006802)) = 23.5 +``` + +Por lo tanto, el token `"pu"` será probablemente removido del vocabulario, pero `"hug"`. + +## Implementando Unigram[[implementing-unigram]] + +Ahora, implementemos todo lo que hemos visto hasta ahora en código. Al igual que BPE y WordPiece, esta es una implementación no tan eficiente del algoritmo Unigram (de hecho, todo lo contrario), pero debería ayudar a entenderla un poco mejor. + +Usaremos el mismo corpus que antes como nuestro ejemplo: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +Esta vez, usaremos `xlnet-base-cased` como nuestro modelo: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased") +``` + +Al igual que BPE y WordPiece, comenzamos contando el número de ocurrencias para cada palabra en el corpus: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +word_freqs +``` + +Luego, necesitamos inicializar nuestro vocabulario a algo más grande que el tamaño de vocabulario que querremos al final. Tenemos que incluir, todos los caracteres básicos (de otra manera no seremos capaces de tokenizar cada palabra), pero para los substrings más grandes mantendremos sólos los más comunes, de manera que los ordenemos por frecuencia: + +```python +char_freqs = defaultdict(int) +subwords_freqs = defaultdict(int) +for word, freq in word_freqs.items(): + for i in range(len(word)): + char_freqs[word[i]] += freq + # Loop through the subwords of length at least 2 + for j in range(i + 2, len(word) + 1): + subwords_freqs[word[i:j]] += freq + +# Sort subwords by frequency +sorted_subwords = sorted(subwords_freqs.items(), key=lambda x: x[1], reverse=True) +sorted_subwords[:10] +``` + +```python out +[('▁t', 7), ('is', 5), ('er', 5), ('▁a', 5), ('▁to', 4), ('to', 4), ('en', 4), ('▁T', 3), ('▁Th', 3), ('▁Thi', 3)] +``` + +Agrupamos los caracteres con las mejores subpalabras para llegar a un vocabulario inicial de 300: + +```python +token_freqs = list(char_freqs.items()) + sorted_subwords[: 300 - len(char_freqs)] +token_freqs = {token: freq for token, freq in token_freqs} +``` + + + +💡 SentencePiece usa un algoritmo más eficiente llamado Enhanced Suffix Array (ESA) para crear el vocabulario inicial. + + + +A continuación, calculamos la suma de todas las frecuencias, para convertir las frecuencias en probabilidades. Para nuestro modelo, almacenaremos los logaritmos de las probabilidades, porque es numericamente más estable sumar logaritmos que multiplicar números pequeños, y esto simplificará el cálculo de la pérdida (`loss`) del modelo: + +```python +from math import log + +total_sum = sum([freq for token, freq in token_freqs.items()]) +model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} +``` + +Ahora, la función es la que tokeniza palabras usando el algoritmo de Viterbi. Como vimos antes, el algoritmo calcula la mejor segmentación de cada substring de la palabra, la cual almacenará en una variable llamada `best_segmentations`. Almacenaremos un diccionario por posición en la palabra (desde 0 hasta su largo total), con dos claves: el índice de inicio del último token en la mejor segmentación, y el puntaje de la mejor segmentación. Con el índice del inicio del último token, seremos capaces de recuperar la segmentación total una vez que la lista esté completamente poblada. + +Poblar la lista se hace con dos ciclos: el ciclo principal recorre cada posición de inicio, y el segundo loop, prueba todos los substrings comenaando en esa posición. Si el substring está en el vocabulario, tenemos una nueva segmentación de la palabra hasta esa posición final, la cual comparamos con lo que está en `best_segmentations`. + +Una vez que el ciclo principal se termina, empezamos desde el final y saltamos de una posición de inicio hasta la siguiente, guardando los tokens a medida que avanzamos, hasta alcanzar el inicio de la palabra: + +```python +def encode_word(word, model): + best_segmentations = [{"start": 0, "score": 1}] + [ + {"start": None, "score": None} for _ in range(len(word)) + ] + for start_idx in range(len(word)): + # This should be properly filled by the previous steps of the loop + best_score_at_start = best_segmentations[start_idx]["score"] + for end_idx in range(start_idx + 1, len(word) + 1): + token = word[start_idx:end_idx] + if token in model and best_score_at_start is not None: + score = model[token] + best_score_at_start + # If we have found a better segmentation ending at end_idx, we update + if ( + best_segmentations[end_idx]["score"] is None + or best_segmentations[end_idx]["score"] > score + ): + best_segmentations[end_idx] = {"start": start_idx, "score": score} + + segmentation = best_segmentations[-1] + if segmentation["score"] is None: + # We did not find a tokenization of the word -> unknown + return [""], None + + score = segmentation["score"] + start = segmentation["start"] + end = len(word) + tokens = [] + while start != 0: + tokens.insert(0, word[start:end]) + next_start = best_segmentations[start]["start"] + end = start + start = next_start + tokens.insert(0, word[start:end]) + return tokens, score +``` + +Ya podemos probar nuestro modelo inicial en algunas palabras: + +```python +print(encode_word("Hopefully", model)) +print(encode_word("This", model)) +``` + +```python out +(['H', 'o', 'p', 'e', 'f', 'u', 'll', 'y'], 41.5157494601402) +(['This'], 6.288267030694535) +``` + +Ahora es fácil calcular la pérdida (`loss`) del modelo en el corpus! + +```python +def compute_loss(model): + loss = 0 + for word, freq in word_freqs.items(): + _, word_loss = encode_word(word, model) + loss += freq * word_loss + return loss +``` + +Podemos chequear que funciona en el modelo que tenemos: + +```python +compute_loss(model) +``` + +```python out +413.10377642940875 +``` + +Calcular los puntajes para cada token no es tan difícil tampoco; sólo tenemos que calcular la pérdida para los modelos obtenidos al eliminar cada token: + +```python +import copy + + +def compute_scores(model): + scores = {} + model_loss = compute_loss(model) + for token, score in model.items(): + # We always keep tokens of length 1 + if len(token) == 1: + continue + model_without_token = copy.deepcopy(model) + _ = model_without_token.pop(token) + scores[token] = compute_loss(model_without_token) - model_loss + return scores +``` + +Podemos probarlo en token dado: + +```python +scores = compute_scores(model) +print(scores["ll"]) +print(scores["his"]) +``` + +Dado que `"ll"` se usa en la tokenización de `"Hopefully"`, y removerlo nos hará probablemente usar el token `"l"` dos veces, esperamos que tendrá una pérdida positiva. `"his"` es sólo usado dentro de la palabra `"This"`, lo cuál es tokenizado como sí mismo, por lo que esperamos que tenga pérdida cero. Acá están los resultados: + +```python out +6.376412403623874 +0.0 +``` + + + +💡 Este acercamiento es muy ineficiente, por lo que SentencePiece usa una aproximación de la pérdida del modelo sin el token X: en vez de comenzar desde cero, sólo reemplaza el token X por su segmentación en el vocabulario que queda. De esta manera, todos los puntajes se pueden calcular de una sóla vez al mismo tiempo que la pérdida del modelo. + + + +Con todo esto en su lugar, lo último que necesitamos hacer es agregar los tokens especiales usados por el modelo al vocabulario, e iterar hasta haber podado suficientes tokens de nuestro vocabulario hasta alcanzar el tamaño deseado: + +```python +percent_to_remove = 0.1 +while len(model) > 100: + scores = compute_scores(model) + sorted_scores = sorted(scores.items(), key=lambda x: x[1]) + # Remove percent_to_remove tokens with the lowest scores. + for i in range(int(len(model) * percent_to_remove)): + _ = token_freqs.pop(sorted_scores[i][0]) + + total_sum = sum([freq for token, freq in token_freqs.items()]) + model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} +``` + +Luego, para tokenizar algo de texto, sólo necesitamos aplicar la pre-tokenización y luego usar nuestra función `encode_word()`: + +```python +def tokenize(text, model): + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in words_with_offsets] + encoded_words = [encode_word(word, model)[0] for word in pre_tokenized_text] + return sum(encoded_words, []) + + +tokenize("This is the Hugging Face course.", model) +``` + +```python out +['▁This', '▁is', '▁the', '▁Hugging', '▁Face', '▁', 'c', 'ou', 'r', 's', 'e', '.'] +``` + +Eso es todo para Unigram! Ojalá a esta altura te sientas como un experto en todos los aspectos de los tokenizadores. En la siguiente sección, ahondaremos en las unidades básicas de la librería 🤗 Tokenizers, y te mostraremos cómo puedes usarlo para construir tu propio tokenizador. \ No newline at end of file diff --git a/chapters/es/chapter6/8.mdx b/chapters/es/chapter6/8.mdx new file mode 100644 index 000000000..795be36aa --- /dev/null +++ b/chapters/es/chapter6/8.mdx @@ -0,0 +1,566 @@ +# Construir un tokenizador, bloque por bloque[[building-a-tokenizer-block-by-block]] + + + +Como hemos visto en las secciones previas, la tokenización está compuesta de varias etapas: + +- Normalización (cualquier limpieza del texto que se considere necesaria, tales como remover espacios o acentos, normalización Unicode, etc.) +- Pre-tokenización (separar la entrada en palabras) +- Pasar las entradas (inputs) por el modelo (usar las palabras pre-tokenizadas para producir una secuencia de tokens) +- Post-procesamiento (agregar tokens especiales del tokenizador, generando la máscara de atención (attention mask) y los IDs de tipo de token) + +Como recordatorio, acá hay otro vistazo al proceso en totalidad: + +
+The tokenization pipeline. + +
+ +La librería 🤗 Tokenizers ha sido construida para proveer varias opciones para cada una de esas etapas, las cuales se pueden mezclar y combinar. En esta sección veremos cómo podemos construir un tokenizador desde cero, opuesto al entrenamiento de un nuevo tokenizador a partir de uno existente como hicimos en la [Sección 2](/course/chapter6/2). Después de esto, serás capaz de construir cualquier tipo de tokenizador que puedas imaginar! + + + +De manera más precisa, la librería está construida a partir de una clase central `Tokenizer` con las unidades más básica reagrupadas en susbmódulos: + +- `normalizers` contiene todos los posibles tipos de `Normalizer` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). +- `pre_tokenizers` contiene todos los posibles tipos de `PreTokenizer` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). +- `models` contiene los distintos tipos de `Model` que puedes usar, como `BPE`, `WordPiece`, and `Unigram` (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). +- `trainers` contiene todos los distintos tipos de `Trainer` que puedes usar para entrenar tu modelo en un corpus (uno por cada tipo de modelo; la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). +- `post_processors` contiene varios tipos de `PostProcessor` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). +- `decoders` contiene varios tipos de `Decoder` que puedes usar para decodificar las salidas de la tokenización (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). + +Puedes encontrar la lista completas de las unidades más básicas [aquí](https://huggingface.co/docs/tokenizers/python/latest/components.html). + +## Adquirir un corpus[[acquiring-a-corpus]] + +Para entrenar nuestro nuevo tokenizador, usaremos un pequeño corpus de texto (para que los ejemplos se ejecuten rápido). Los pasos para adquirir el corpus son similares a los que tomamos al [beginning of this chapter](/course/chapter6/2), pero esta vez usaremos el conjunto de datos [WikiText-2](https://huggingface.co/datasets/wikitext): + +```python +from datasets import load_dataset + +dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train") + + +def get_training_corpus(): + for i in range(0, len(dataset), 1000): + yield dataset[i : i + 1000]["text"] +``` + +La función `get_training_corpus()` es un generador que entregará lotes de 1.000 textos, los cuales usaremos para entrenar el tokenizador. + +🤗 Tokenizers puedes también ser entrenada en archivos de textos directamente. Así es como podemos generar un archivo de texto conteniendo todos los textos/entradas de WikiText-2 que podemos usar localmente: + +```python +with open("wikitext-2.txt", "w", encoding="utf-8") as f: + for i in range(len(dataset)): + f.write(dataset[i]["text"] + "\n") +``` + +A continuación mostraremos como construir tu propios propios tokenizadores BERT, GPT-2 y XLNet, bloque por bloque. Esto nos dará un ejemplo de cada una de los tres principales algoritmos de tokenización: WordPiece, BPE y Unigram. Empecemos con BERT! + +## Construyendo un tokenizador WordPiece desde cero[[building-a-wordpiece-tokenizer-from-scratch]] + +Para construir un tokenizador con la librería 🤗 Tokenizers, empezamos instanciando un objeto `Tokenizer` con un `model`, luego fijamos sus atributos `normalizer`, `pre_tokenizer`, `post_processor`, y `decoder` a los valores que queremos. + +Para este ejemplo, crearemos un `Tokenizer` con modelo WordPiece: + +```python +from tokenizers import ( + decoders, + models, + normalizers, + pre_tokenizers, + processors, + trainers, + Tokenizer, +) + +tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) +``` + +Tenemos que especificar el `unk_token` para que el modelo sepa que retornar si encuentra caracteres que no ha visto antes. Otros argumentos que podemos fijar acá incluyen el `vocab` de nuestro modelo (vamos a entrenar el modelo, por lo que no necesitamos fijar esto) y `max_input_chars_per_word`, el cual especifica el largo máximo para cada palabra (palabras más largas que el valor pasado se serpararán). + +El primer paso de la tokenización es la normalizacion, así que empecemos con eso. Dado que BERT es ampliamente usado, hay un `BertNormalizer` con opciones clásicas que podemos fijar para BERT: `lowercase` (transformar a minúsculas) y `strip_accents` (eliminar acentos); `clean_text` para remover todos los caracteres de control y reemplazar espacios repetidos en uno solo; y `handle_chinese_chars` el cual coloca espacios alrededor de los caracteres en Chino. Para replicar el tokenizador `bert-base-uncased`, basta con fijar este normalizador: + +```python +tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) +``` + +Sin embargo, en términos generales, cuando se construye un nuevo tokenizador no tendrás acceso a tan útil normalizador ya implementado en la librería 🤗 Tokenizers -- por lo que veamos como crear el normalizador BERT a mano. La librería provee un normalizador `Lowercase` y un normalizador `StripAccents`, y puedes componer varios normalizadores usando un `Sequence` (secuencia): + +```python +tokenizer.normalizer = normalizers.Sequence( + [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()] +) +``` + +También estamos usando un normalizador Unicode `NFD`, ya que de otra manera el normalizador `StripAccents` no reconocerá apropiadamente los caracteres acentuados y por lo tanto, no los eliminará. + +Como hemos visto antes, podemos usar el método `normalize_str()` del `normalizer` para chequear los efectos que tiene en un texto dado: + +```python +# print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +hello how are u? +``` + + + +**Para ir más allá** Si pruebas las dos versiones de los normalizadores previos en un string conteniendo un caracter unicode `u"\u0085"` +de seguro notarás que los dos normalizadores no son exactamente equivalentes. +Para no sobre-complicar demasiado la version con `normalizers.Sequence`, no hemos incluido los reemplazos usando Expresiones Regulares (Regex) que el `BertNormalizer` requiere cuando el argumento `clean_text` se fija como `True` - lo cual es el comportamiento por defecto. Pero no te preocupes, es posible obtener la misma normalización sin usar el útil `BertNormalizer` agregando dos `normalizers.Replace` a la secuencia de normalizadores. + + + +A continuación está la etapa de pre-tokenización. De nuevo, hay un `BertPreTokenizer` pre-hecho que podemos usar: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() +``` + +O podemos constuirlo desde cero: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() +``` + +Nota que el pre-tokenizador `Whitespace` separa en espacios en blando y todos los caracteres que no son letras, dígitos o el guión bajo/guión al piso (_), por lo que técnicamente separa en espacios en blanco y puntuación: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +Si sólo quieres separar en espacios en blanco, deberías usar el pre-tokenizador `WhitespaceSplit`: + +```python +pre_tokenizer = pre_tokenizers.WhitespaceSplit() +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] +``` + +Al igual que con los normalizadores, puedes un `Sequence` para componer varios pre-tokenizadores: + +```python +pre_tokenizer = pre_tokenizers.Sequence( + [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()] +) +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +El siguiente paso en el pipeline de tokenización es pasar las entradas a través del modelo. Ya especificamos nuestro modelo en la inicialización, pero todavía necesitamos entrenarlo, lo cual requerirá un `WordPieceTrainer`. El aspecto principal a recordar cuando se instancia un entrenador (trainer) en 🤗 Tokenizers es que necesitas pasarle todos los tokens especiales que tiene la intención de usar -- de otra manera no los agregará al vocabulario, dado que que no están en el corpus de entrenamiento: + +```python +special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] +trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) +``` + +Al igual que especificar `vocab_size` y `special_tokens`, podemos fijar `min_frequency` (el número de veces que un token debe aparecer para ser incluido en el vocabulario) o cambiar `continuing_subword_prefix` (si queremos usar algo diferente a `##`). + +Para entrenar nuestro modelo usando el iterador que definimos antes, tenemos que ejecutar el siguiente comando: + +```python +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +También podemos usar archivos de texto para entrenar nuestro tokenizador, lo cual se vería así (reinicializamos el modelo con un `WordPiece` vacío de antemano): + +```python +tokenizer.model = models.WordPiece(unk_token="[UNK]") +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +En ambos casos, podemos probar el tokenizador en un texto llamando al método `encode: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +# print(encoding.tokens) +``` + +```python out +['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] +``` + +El `encoding` (codificación) obtenido es un objeto `Encoding`, el cual contiene todas las salidas necesarias del tokenizador y sus distintos atributos: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask`, y `overflowing`. + +El último paso en el pipeline de tokenización es el post-procesamiento. Necesitamos agregar el token `[CLS]` al inicio y el token `[SEP]` al final (o después de cada oración, si tenemos un par de oraciones). Usaremos un `TemplateProcessor` para esto, pero primero necesitamos conocer los IDs de los tokens `[CLS]` y `[SEP]` en el vocabulario: + +```python +cls_token_id = tokenizer.token_to_id("[CLS]") +sep_token_id = tokenizer.token_to_id("[SEP]") +# print(cls_token_id, sep_token_id) +``` + +```python out +(2, 3) +``` + +Para escribir la plantilla (template) para un `TemplateProcessor`, tenemos que especificar como tratar una sóla oración y un par de oraciones. Para ambos, escribimos los tokens especiales que queremos usar; la primera oración se representa por `$A`, mientras que la segunda oración (si se está codificando un par) se representa por `$B`. Para cada uno de estos (tokens especiales y oraciones), también especificamos el ID del tipo de token correspondiente después de un dos puntos (:). + +La clásica plantilla para BERT se define como sigue: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single=f"[CLS]:0 $A:0 [SEP]:0", + pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1", + special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)], +) +``` + +Nota que necesitamos pasar los IDs de los tokens especiales, para que el tokenizador pueda convertirlos apropiadamente a sus IDs. + +Una vez que se agrega esto, volviendo a nuestro ejemplo anterior nos dará: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +# print(encoding.tokens) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] +``` + +Y en un par de oraciones, obtenemos el resultado apropiado: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") +# print(encoding.tokens) +# print(encoding.type_ids) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]'] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] +``` + +Ya casi finalizamos de construir este tokenizador desde cero -- el último paso es incluir un decodificador: + +```python +tokenizer.decoder = decoders.WordPiece(prefix="##") +``` + +Probemoslo en nuestro `encoding` previo: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"let's test this tokenizer... on a pair of sentences." +``` + +Genial! Ahora podemos guardar nuestro tokenizador en un archivo JSON así: + +```python +tokenizer.save("tokenizer.json") +``` + +Podemos cargar ese archivo en un objeto `Tokenizer` con el método `from_file()`: + +```python +new_tokenizer = Tokenizer.from_file("tokenizer.json") +``` + +Para usar este tokenizador en 🤗 Transformers, tenemos que envolverlo en un `PreTrainedTokenizerFast`. Podemos usar una clase generica o, si nuestro tokenizador corresponde un modelo existente, usar esa clase (en este caso, `BertTokenizerFast`). Si aplicas esta lección para construir un tokenizador nuevo de paquete, tendrás que usar la primera opción. + +Para envolver el tokenizador en un `PreTrainedTokenizerFast`, podemos pasar el tokenizador que construimos como un `tokenizer_object` o pasar el archivo del tokenizador que guardarmos como `tokenizer_file`. El aspecto clave a recordar es que tenemos que manualmente fijar los tokens especiales, dado que la clase no puede inferir del objeto `tokenizer` qué token es el el token de enmascaramiento (mask token), el token `[CLS]`, etc.: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + # tokenizer_file="tokenizer.json", # You can load from the tokenizer file, alternatively + unk_token="[UNK]", + pad_token="[PAD]", + cls_token="[CLS]", + sep_token="[SEP]", + mask_token="[MASK]", +) +``` + +Si estás usando una clase de tokenizador específico (como `BertTokenizerFast`), sólo necesitarás especificar los tokens especiales diferentes a los que están por defecto (en este caso, ninguno): + +```python +from transformers import BertTokenizerFast + +wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) +``` + +Luego puedes usar este tokenizador como cualquier otro tokenizador de 🤗 Transformers. Puedes guardarlo con el método `save_pretrained()`, o subirlo al Hub con el método `push_to_hub()`. + +Ahora que hemos visto como construir el tokenizador WordPiece, hagamos lo mismo para un tokenizador BPE. Iremos un poco más rápido dato que conoces todos los pasos, y sólo destacaremos las diferencias. + +## Construyendo un tokenizador BPE desde cero[[building-a-bpe-tokenizer-from-scratch]] + +Ahora construyamos un tokenizador GPT-2. Al igual que el tokenizador BERT, empezamos inicializando un `Tokenizer` con un modelo BPE: + +```python +tokenizer = Tokenizer(models.BPE()) +``` + +También al igual que BERT, podríamos inicializar este modelo con un vocabulario si tuviéramos uno (necesitaríamos pasar el `vocab` y `merges`, en este caso), pero dado que entrenaremos desde cero, no necesitaremos hacer eso. Tampoco necesitamos especificar `unk_token` porque GPT-2 utiliza un byte-level BPE, que no lo requiere. + +GPT-2 no usa un normalizador, por lo que nos saltamos este paso y vamos directo a la pre-tokenización: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) +``` + +La opción que agregada acá `ByteLevel` es para no agregar un espacio al inicio de una oración (el cuál es el valor por defecto). Podemos echar un vistazo a la pre-tokenización de un texto de ejemplo como antes: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") +``` + +```python out +[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)), + ('tokenization', (15, 27)), ('!', (27, 28))] +``` + +A continuación está el modelo, el cual necesita entrenamiento. Para GPT-2, el único token especial es el token de final de texto (end-of-text): + +```python +trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +Al igual que con el `WordPieceTrainer`, junto con `vocab_size` y `special_tokens`, podemos especificar el `min_frequency` si queremos, o si tenemos un sufijo de fín de palabra (end-of-word suffix) (como ``), podemos fijarlo con `end_of_word_suffix`. + +Este tokenizador también se puede entrenar en archivos de textos: + +```python +tokenizer.model = models.BPE() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +Echemos un vistazo a la tokenización de un texto de muestra: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +# print(encoding.tokens) +``` + +```python out +['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] +``` + +Aplicaremos el post-procesamiento byte-level para el tokenizador GPT-2 como sigue: + +```python +tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) +``` + +La opción `trim_offsets = False` indica al post-procesador que deberíamos dejar los offsets de los tokens que comiencen con 'Ġ' sin modificar: De esta manera el inicio de los offsets apuntarán al espacio antes de la palabra, no el primer caracter de la palabra (dado que el espacio es técnicamente parte del token). Miremos el resultado con el texto que acabamos de codificar, donde `'Ġtest'` el token en el índice 4: + +```python +sentence = "Let's test this tokenizer." +encoding = tokenizer.encode(sentence) +start, end = encoding.offsets[4] +sentence[start:end] +``` + +```python out +' test' +``` + +Finalmente, agregamos un decodificador byte-level: + +```python +tokenizer.decoder = decoders.ByteLevel() +``` + +y podemos chequear si funciona de manera apropiada: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"Let's test this tokenizer." +``` + +Genial! Ahora que estamos listos, podemos guardar el tokenizador como antes, y envolverlo en un `PreTrainedTokenizerFast` o `GPT2TokenizerFast` si queremos usarlo en 🤗 Transformers: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="<|endoftext|>", + eos_token="<|endoftext|>", +) +``` + +o: + +```python +from transformers import GPT2TokenizerFast + +wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) +``` + +Como en el último ejemplo, mostraremos cómo construir un tokenizador Unigram desde cero. + +## Construyendo un tokenizador Unigran desde cero[[building-a-unigram-tokenizer-from-scratch]] + +Construyamos un tokenizador XLNet. Al igual que los tokenizadores previos, empezamos inicializando un `Tokenizer` con un modelo Unigram: + +```python +tokenizer = Tokenizer(models.Unigram()) +``` + +De nuevo, podríamos inicializar este modelo con un vocabulario si tuvieramos uno. + +Para la normalización, XLNet utiliza unos pocos reemplazos (los cuales vienen de SentencePiece): + +```python +from tokenizers import Regex + +tokenizer.normalizer = normalizers.Sequence( + [ + normalizers.Replace("``", '"'), + normalizers.Replace("''", '"'), + normalizers.NFKD(), + normalizers.StripAccents(), + normalizers.Replace(Regex(" {2,}"), " "), + ] +) +``` + +Esto reemplaza `` y '' con " y cualquier secuencia de dos o más espacios con un espacio simple, además remueve los acentos en el texto a tokenizar. + +El pre-tokenizador a usar para cualquier tokenizador SentencePiece es `Metaspace`: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() +``` + +Podemos echar un vistazo a la pre-tokenización de un texto de ejemplo como antes: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") +``` + +```python out +[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] +``` + +A continuación está el modelo, el cuál necesita entrenamiento. XLNet tiene varios tokens especiales: + +```python +special_tokens = ["", "", "", "", "", "", ""] +trainer = trainers.UnigramTrainer( + vocab_size=25000, special_tokens=special_tokens, unk_token="" +) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +Un argumento muy importante a no olvidar para el `UnigramTrainer` es el `unk_token`. También podemos pasarle otros argumentos específicos al algoritmo Unigram, tales como el `shrinking_factor` para cada paso donde removemos tokens (su valor por defecto es 0.75) o el `max_piece_length` para especificar el largo máximo de un token dado (su valor por defecto es 16). + +Este tokenizador también se puede entrenar en archivos de texto: + +```python +tokenizer.model = models.Unigram() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +Ahora miremos la tokenización de un texto de muestra: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +# print(encoding.tokens) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] +``` + +Una peculiariodad de XLNet es que coloca el token `` al final de la oración, con un ID de tipo de 2 (para distinguirlo de los otros tokens). Como el resultado el resultado se rellena a la izquierda (left padding). Podemos lidiar con todos los tokens especiales y el token de ID de tipo con una plantilla, al igual que BERT, pero primero tenemos que obtener los IDs de los tokens `` y ``: + +```python +cls_token_id = tokenizer.token_to_id("") +sep_token_id = tokenizer.token_to_id("") +# print(cls_token_id, sep_token_id) +``` + +```python out +0 1 +``` + +La plantilla se ve así: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single="$A:0 :0 :2", + pair="$A:0 :0 $B:1 :1 :2", + special_tokens=[("", sep_token_id), ("", cls_token_id)], +) +``` + +Y podemos probar si funciona codificando un par de oraciones: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") +# print(encoding.tokens) +# print(encoding.type_ids) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '', '▁', 'on', '▁', 'a', '▁pair', + '▁of', '▁sentence', 's', '!', '', ''] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] +``` + +Finalmente, agregamos el decodificador `Metaspace`: + +```python +tokenizer.decoder = decoders.Metaspace() +``` + +y estamos listos con este tokenizador! Podemos guardar el tokenizador como antes, y envolverlo en un `PreTrainedTokenizerFast` o `XLNetTokenizerFast` si queremos usarlo en 🤗 Transformers. Una cosa a notar al usar `PreTrainedTokenizerFast` es que además de los tokens especiales, necesitamos decirle a la librería 🤗 Transformers que rellene a la izquierda (agregar left padding): + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="", + eos_token="", + unk_token="", + pad_token="", + cls_token="", + sep_token="", + mask_token="", + padding_side="left", +) +``` + +O de manera alternativa: + +```python +from transformers import XLNetTokenizerFast + +wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) +``` + +Ahora que has visto como varias de nuestras unidades más básicas se usan para construir tokenizadores existentes, deberías ser capaz de escribir cualquier tokenizador que quieras con la librería 🤗 Tokenizers y ser capaz de usarlo en la librería 🤗 Transformers. \ No newline at end of file diff --git a/chapters/es/chapter6/9.mdx b/chapters/es/chapter6/9.mdx new file mode 100644 index 000000000..37efd29b3 --- /dev/null +++ b/chapters/es/chapter6/9.mdx @@ -0,0 +1,16 @@ +# Tokenizadores, listo![[tokenizers-check]] + + + +Gran trabajo terminando este capítulo! + +Luego de esta profundizacion en los tokenizadores, deberías: + +- Ser capaz de entrenar un nuevo tokenizador usando un existente como plantilla +- Entender como usar los offsets para mapear las posiciones de los tokens a sus trozos de texto original +- Conocer las diferencias entre BPE, WordPiece y Unigram +- Ser capaz de mezclar y combinar los bloques provistos por la librería 🤗 Tokenizers para construir tu propio tokenizador +- Ser capaz de usar el tokenizador dentro de la librería 🤗 Transformers. From 0916d0a8885d0124437efdc33485baca69882cd6 Mon Sep 17 00:00:00 2001 From: Alysson <50303964+k3ybladewielder@users.noreply.github.com> Date: Tue, 24 Oct 2023 20:12:48 -0300 Subject: [PATCH 295/502] Update 5.mdx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajuste na tradução de "encoders". São "codificadores", não "decodificadores". Decoders são "decodificadores". --- chapters/pt/chapter1/5.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/pt/chapter1/5.mdx b/chapters/pt/chapter1/5.mdx index f14bb0ac2..1b8846e0a 100644 --- a/chapters/pt/chapter1/5.mdx +++ b/chapters/pt/chapter1/5.mdx @@ -1,4 +1,4 @@ -# Modelos decodificadores +# Modelos codificadores -Os modelos de encoder (decodificadores) usam apenas o encoder de um modelo Transformer. Em cada estágio, as camadas de atenção podem acessar todas as palavras da frase inicial. Esses modelos geralmente são caracterizados como tendo atenção "bidirecional" e são frequentemente chamados de *modelos de codificação automática*. +Os modelos de encoder (codificadores) usam apenas o encoder de um modelo Transformer. Em cada estágio, as camadas de atenção podem acessar todas as palavras da frase inicial. Esses modelos geralmente são caracterizados como tendo atenção "bidirecional" e são frequentemente chamados de *modelos de codificação automática*. O pré-treinamento desses modelos geralmente gira em torno de corromper de alguma forma uma determinada frase (por exemplo, mascarando palavras aleatórias nela) e encarregando o modelo de encontrar ou reconstruir a frase inicial. From 22986ccca28dc90b447e3609b31a6df103fb89ec Mon Sep 17 00:00:00 2001 From: Fabrizio Damicelli Date: Sat, 4 Nov 2023 18:46:41 +0100 Subject: [PATCH 296/502] finalize de_ch_4_part2 --- chapters/de/chapter4/4.mdx | 54 +++++++------- chapters/de/chapter4/5.mdx | 8 +- chapters/de/chapter4/6.mdx | 149 +++++++++++++++++++------------------ 3 files changed, 108 insertions(+), 103 deletions(-) diff --git a/chapters/de/chapter4/4.mdx b/chapters/de/chapter4/4.mdx index 42c0488ff..48b41c566 100644 --- a/chapters/de/chapter4/4.mdx +++ b/chapters/de/chapter4/4.mdx @@ -18,7 +18,7 @@ Das Konzept von Modellkarte ("model card") stammt aus einer Forschungsrichtung b The model card usually starts with a very brief, high-level overview of what the model is for, followed by additional details in the following sections: Eine Modellkarte fängt mit einer kurzen, große Übersicht davon, was das Modell kann plus einige Details in den folgenden Abschnitte: -- Modell Beschreibung +- Modell-Beschreibung - Beabsichtigte Nutzung und Einschränkungen - Modell-Bedienung - Einschränkungen und Bias @@ -28,54 +28,56 @@ Eine Modellkarte fängt mit einer kurzen, große Übersicht davon, was das Model Lass uns anschauen, was genau in jedem Abschnitt stehen sollte. -#TODO -### Model description +# TODO +### Modell-Beschreibung -The model description provides basic details about the model. This includes the architecture, version, if it was introduced in a paper, if an original implementation is available, the author, and general information about the model. Any copyright should be attributed here. General information about training procedures, parameters, and important disclaimers can also be mentioned in this section. +Die Modellbeschreibung enthält grundlegende Details zum Modell. Dazu gehören die Architektur, die Version, ob es in einem Paper vorgestellt wurde, ob eine Originalimplementierung verfügbar ist, der Autor und allgemeine Informationen über das Modell. Eventuelle Urheberrechte sind hier anzugeben. In diesem Abschnitt können auch allgemeine Informationen zu Trainingsverfahren, Parametern und wichtigen Haftungsausschlüssen erwähnt werden. -### Intended uses & limitations +### Verwendungszweck und Einschränkungen -Here you describe the use cases the model is intended for, including the languages, fields, and domains where it can be applied. This section of the model card can also document areas that are known to be out of scope for the model, or where it is likely to perform suboptimally. +Hier beschreibst du die angedachten Anwendungsfälle fürs Modell, einschließlich der Sprachen, Felder und Domänen, in denen es angewendet werden kann. In diesem Abschnitt der Modellkarte können auch Bereiche dokumentiert werden, die bekanntermaßen außerhalb des Anwendungsbereichs des Modells liegen oder in denen die Leistung wahrscheinlich nicht optimal ist. -### How to use +### Modell-Bedienung -This section should include some examples of how to use the model. This can showcase usage of the `pipeline()` function, usage of the model and tokenizer classes, and any other code you think might be helpful. +Dieser Abschnitt sollte einige Beispiele für die Verwendung des Modells enthalten. Dies kann die Verwendung der Funktion `pipeline()`, die Verwendung der Modell- und Tokenizer-Klassen und jeden anderen Code zeigen, der deiner Meinung nach hilfreich sein könnte. -### Training data -This part should indicate which dataset(s) the model was trained on. A brief description of the dataset(s) is also welcome. +### Trainingsdaten -### Training procedure +In diesem Teil sollte angegeben werden, auf welchen Datensatz bzw. Datensätze das Modell trainiert wurde. Eine kurze Beschreibung des Datensatzes/der Datensätze ist ebenfalls willkommen. -In this section you should describe all the relevant aspects of training that are useful from a reproducibility perspective. This includes any preprocessing and postprocessing that were done on the data, as well as details such as the number of epochs the model was trained for, the batch size, the learning rate, and so on. +### Trainingsverfahren -### Variable and metrics +In diesem Abschnitt solltest du alle relevanten Aspekte des Modelltrainingsverfahren beschreiben, die für die Reproduzierbarkeit nützlich sind. Dazu gehören alle Vor- und Nachbearbeitungen, die an den Daten durchgeführt wurden, sowie Details wie die Anzahl der Trainingsepochene, Batch-Größe, die Lernrate usw. -Here you should describe the metrics you use for evaluation, and the different factors you are mesuring. Mentioning which metric(s) were used, on which dataset and which dataset split, makes it easy to compare you model's performance compared to that of other models. These should be informed by the previous sections, such as the intended users and use cases. +### Variablen und Metriken -### Evaluation results +Hier solltest du die Bewertungsmetriken beschreiben und die verschiedenen Faktoren, die du dabei mit berücksichtigst. Durch die Angabe, welche Metrik(en) verwendet wurden, für welchen Datensatz und welche Datensatzaufteilung, kannst du die Leistung deines Modells leicht mit der anderer Modelle vergleichen. Diese sollten durch die vorherigen Abschnitte informiert werden, wie z. B. die beabsichtigten Benutzer und Anwendungsfälle. -Finally, provide an indication of how well the model performs on the evaluation dataset. If the model uses a decision threshold, either provide the decision threshold used in the evaluation, or provide details on evaluation at different thresholds for the intended uses. +### Evaluierungsergebnisse -## Example +Abschließend gibst du an, wie gut das Modell mit dem Bewertungsdatensatz abschneidet. Wenn das Modell einen Entscheidungsschwellenwert verwendet, gib entweder den in der Bewertung verwendeten Entscheidungsschwellenwert an oder mach Angaben zur Bewertung bei verschiedenen Schwellenwerten für die beabsichtigten Verwendungszwecke. -Check out the following for a few examples of well-crafted model cards: +## Beispiel + +Im Folgenden findest du einige Beispiele von guten Modellkarten: - [`bert-base-cased`](https://huggingface.co/bert-base-cased) - [`gpt2`](https://huggingface.co/gpt2) - [`distilbert`](https://huggingface.co/distilbert-base-uncased) -More examples from different organizations and companies are available [here](https://github.com/huggingface/model_card/blob/master/examples.md). -## Note +Mehr Beispiele von verschiedene Organisationen/Firmen sind hier verfügbar [here](https://github.com/huggingface/model_card/blob/master/examples.md). + +## Hinweis -Model cards are not a requirement when publishing models, and you don't need to include all of the sections described above when you make one. However, explicit documentation of the model can only benefit future users, so we recommend that you fill in as many of the sections as possible to the best of your knowledge and ability. +Modellkarten sind bei der Veröffentlichung von Modellen nicht erforderlich und du musst bei der Erstellung nicht alle oben beschriebenen Abschnitte einbeziehen. Allerdings kann eine explizite Dokumentation des Modells künftigen Nutzern nur nützen, daher empfehlen wir dir, so viele Abschnitte wie möglich nach bestem Wissen und Gewissen auszufüllen. -## Model card metadata +## Modellkarte-Metadaten -If you have done a little exploring of the Hugging Face Hub, you should have seen that some models belong to certain categories: you can filter them by tasks, languages, libraries, and more. The categories a model belongs to are identified according to the metadata you add in the model card header. +Wenn du den Hugging Face Hub ein wenig erkundet hast, solltest du gesehen haben, dass einige Modelle zu bestimmten Kategorien gehören: Du kannst sie nach Aufgaben, Sprachen, Bibliotheken und mehr filtern. Die Kategorien, zu denen ein Modell gehört, werden anhand der Metadaten identifiziert, die du im Kopf der Modellkarte hinzufügst. -For example, if you take a look at the [`camembert-base` model card](https://huggingface.co/camembert-base/blob/main/README.md), you should see the following lines in the model card header: +Zum Beispiel sieh dir dieses an [`camembert-base` model card](https://huggingface.co/camembert-base/blob/main/README.md). Du solltest folgende Zeilen auf der Modellkarte sehen: ``` --- @@ -86,6 +88,6 @@ datasets: --- ``` -This metadata is parsed by the Hugging Face Hub, which then identifies this model as being a French model, with an MIT license, trained on the Oscar dataset. +Diese Metadaten werden vom Hugging Face Hub analysiert, der dieses Modell dann als französisches Modell mit einer MIT-Lizenz identifiziert, das auf dem Oscar-Datensatz trainiert wurde. -The [full model card specification](https://github.com/huggingface/hub-docs/blame/main/modelcard.md) allows specifying languages, licenses, tags, datasets, metrics, as well as the evaluation results the model obtained when training. +Die vollständige [Modellkarte](https://github.com/huggingface/hub-docs/blame/main/modelcard.md) ermöglicht die Angabe von Sprachen, Lizenzen, Tags, Datensätzen, Metriken sowie den Bewertungsergebnissen, die das Modell wann erhalten hat Ausbildung. diff --git a/chapters/de/chapter4/5.mdx b/chapters/de/chapter4/5.mdx index 341f9f348..65eac0fa9 100644 --- a/chapters/de/chapter4/5.mdx +++ b/chapters/de/chapter4/5.mdx @@ -1,12 +1,12 @@ -# Part 1 completed! +# Teil 1 abgeschlossen! -This is the end of the first part of the course! Part 2 will be released on November 15th with a big community event, see more information [here](https://huggingface.co/blog/course-launch-event). +Dies ist das Ende des ersten Teils des Kurses! Teil 2 wird am 15. November mit einem großen Community-Event veröffentlicht, weitere Informationen findest du [hier](https://huggingface.co/blog/course-launch-event). -You should now be able to fine-tune a pretrained model on a text classification problem (single or pairs of sentences) and upload the result to the Model Hub. To make sure you mastered this first section, you should do exactly that on a problem that interests you (and not necessarily in English if you speak another language)! You can find help in the [Hugging Face forums](https://discuss.huggingface.co/) and share your project in [this topic](https://discuss.huggingface.co/t/share-your-projects/6803) once you're finished. +Du solltest nun in der Lage sein, ein vorab trainiertes Modell für ein Textklassifizierungsproblem (einzelne Sätze oder Satzpaare) zu optimieren und das Ergebnis in den Model Hub hochzuladen. Um sicherzustellen, dass du diesen ersten Abschnitt beherrschst, solltest du genau das an einem Problem verwenden, das dich interessiert (und nicht unbedingt auf Englisch, wenn Sie eine andere Sprache sprechen)! Hilfe findest du in den [Hugging Face-Foren](https://discuss.huggingface.co/) und du kannst dein Projekt in [diesem Thema](https://discuss.huggingface.co/t/share-your-projects) teilen /6803), sobald du damit fertig bist. -We can't wait to see what you will build with this! +Wir freuen uns darauf, zu sehen, was du alles damit baust! diff --git a/chapters/de/chapter4/6.mdx b/chapters/de/chapter4/6.mdx index 4317fdb4f..90f8dfe79 100644 --- a/chapters/de/chapter4/6.mdx +++ b/chapters/de/chapter4/6.mdx @@ -9,126 +9,127 @@ classNames="absolute z-10 right-0 top-0" /> -Let's test what you learned in this chapter! +Lass uns testen, was du im vorheringen Kapitel gelernt hast! -### 1. What are models on the Hub limited to? +### 1. Auf welche Modelle sind die Hub-Modelle beschränkt? -### 2. How can you manage models on the Hub? +### 2. Wie kannst du die Modelle auf dem Hub verwalten? git-lfs for large files.", + text: "Durch git und git-lfs.", + explain: "Korrekt! Modelle auf dem Hub sind einfach Git-Repositories, die für große Dateien git-lfs benutzen.", correct: true } ]} /> -### 3. What can you do using the Hugging Face Hub web interface? +### 3. Was kannst du mit der Hugging Face Hub-Weboberfläche tun? -### 4. What is a model card? +### 4. Was ist eine Modellkarte? -### 5. Which of these objects of the 🤗 Transformers library can be directly shared on the Hub with `push_to_hub()`? +### 5. Welche dieser Objekte der 🤗 Transformers-Bibliothek können mit `push_to_hub()` direkt auf dem Hub geteilt werden? {#if fw === 'pt'} push_to_hub method, and using it will push all the tokenizer files (vocabulary, architecture of the tokenizer, etc.) to a given repo. That's not the only right answer, though!", + text: "Ein Tokenizer", + explain: "Richtig! Alle Tokenizer verfügen über die Methode push_to_hub, und wenn su sie verwendest, werden alle Tokenizer-Dateien (Vokabular, Architektur des Tokenizers usw.) in ein bestimmtes Repo verschoben. Aber das ist nicht die einzig richtige Antwort!", correct: true }, { - text: "A model configuration", - explain: "Right! All model configurations have the push_to_hub method, and using it will push them to a given repo. What else can you share?", + text: "Eine Modell-Konfiguration", + explain: "Richtig! Alle Modellkonfigurationen verfügen über die Methode push_to_hub, und wenn Sie sie verwenden, werden sie an ein bestimmtes Repo gepusht. Was kannst du sonst noch teilen?", correct: true }, { - text: "A model", - explain: "Correct! All models have the push_to_hub method, and using it will push them and their configuration files to a given repo. That's not all you can share, though.", + text: "Ein Model", + explain: "Richtig! Alle Modelle verfügen über die Methode push_to_hub, und wenn du sie verwendest, werden sie und ihre Konfigurationsdateien in ein bestimmtes Repo gepusht. Das ist jedoch nicht alles, was du teilen kannst.", correct: true }, { - text: "A Trainer", - explain: "That's right — the Trainer also implements the push_to_hub method, and using it will upload the model, its configuration, the tokenizer, and a model card draft to a given repo. Try another answer!", + text: "Ein Trainer", + explain: "Das ist richtig – der Trainer implementiert auch die Methode push_to_hub und lädt mit dieser Methode das Modell, seine Konfiguration, den Tokenizer und einen Modellkartenentwurf auf einen gegebenen Server hoch repo. Versuch es auch mit einer anderen Antwort!", correct: true } ]} @@ -137,92 +138,94 @@ Let's test what you learned in this chapter! push_to_hub method, and using it will push all the tokenizer files (vocabulary, architecture of the tokenizer, etc.) to a given repo. That's not the only right answer, though!", + explain: "Richtig! Alle Tokenizer verfügen über die Methode push_to_hub, und wenn du sie verwendest, werden alle Tokenizer-Dateien (Vokabular, Architektur des Tokenizers usw.) in ein bestimmtes Repo verschoben. Das ist aber nicht die einzige richtige Antwort!", correct: true }, { - text: "A model configuration", + text: "Eine Modell-Konfiguration", explain: "Right! All model configurations have the push_to_hub method, and using it will push them to a given repo. What else can you share?", + explain: "Richtig! Alle Modellkonfigurationen verfügen über die Methode push_to_hub, und wenn du sie verwendest, werden sie an ein bestimmtes Repo gepusht. Was kannst du sonst noch teilen?", correct: true }, { - text: "A model", - explain: "Correct! All models have the push_to_hub method, and using it will push them and their configuration files to a given repo. That's not all you can share, though.", + text: "Ein Modell", + explain: "Richtig! Alle Modelle verfügen über die Methode push_to_hub, und wenn du sie verwendest, werden sie und ihre Konfigurationsdateien in ein bestimmtes Repo gepusht. Das ist jedoch nicht alles, was du teilen kannst.", correct: true }, { - text: "All of the above with a dedicated callback", - explain: "That's right — the PushToHubCallback will regularly send all of those objects to a repo during training.", + text: "Alles oben mit einem speziellen `Callback`", + explain: "Das ist richtig – der PushToHubCallback sendet während des Trainings regelmäßig alle diese Objekte an ein Repo.", correct: true } ]} /> {/if} -### 6. What is the first step when using the `push_to_hub()` method or the CLI tools? +### 6. Was ist der erste Schritt bei Verwendung der Methode `push_to_hub()` oder der CLI-Tools? -### 7. You're using a model and a tokenizer — how can you upload them to the Hub? +### 7. Du verwendest ein Modell und einen Tokenizer – wie kannst du diese auf den Hub hochladen? huggingface_hub utility.", - explain: "Models and tokenizers already benefit from huggingface_hub utilities: no need for additional wrapping!" + text: "Innerhalb der Python-Runtime, indem man sie in ein huggingface_hub-Dienstprogramm einschließt.", + explain: "Modelle und Tokenizer profitieren bereits von den Dienstprogrammen huggingface_hub: kein zusätzlicher Wrapping erforderlich!" }, { - text: "By saving them to disk and calling transformers-cli upload-model", - explain: "The command upload-model does not exist." + text: "Indem du sie auf der Festplatte speicherst und transformers-cli upload-model aufrufst", + explain: "Der Befehl upload-model existiert nicht." } ]} /> -### 8. Which git operations can you do with the `Repository` class? +### 8. Welche Git-Operationen kann man mit der Klasse „Repository“ ausführen? git_commit() method is there for that.", + text: "Ein Commit.", + explain: "Richtig, dafür ist die git_commit() Methode da.", correct: true }, { - text: "A pull", - explain: "That is the purpose of the git_pull() method.", + text: "Ein Pull", + explain: "Das ist der Zweck der git_pull() Methode.", correct: true }, { - text: "A push", - explain: "The method git_push() does this.", + text: "Ein Push", + explain: "Die Methode git_push() macht das.", correct: true }, { - text: "A merge", - explain: "No, that operation will never be possible with this API." + text: "Ein Merge", + explain: "Nein, die Operation wird mit dieser API nie möglich sein." } ]} /> From 7d86ff31c405ed3e72dd35c4dc2ad674733d9bc0 Mon Sep 17 00:00:00 2001 From: Fabrizio Damicelli Date: Sat, 4 Nov 2023 18:58:40 +0100 Subject: [PATCH 297/502] add ch 4 parts to table of contents --- chapters/de/_toctree.yml | 7 +++++++ chapters/de/chapter4/4.mdx | 3 +-- chapters/de/chapter4/6.mdx | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/chapters/de/_toctree.yml b/chapters/de/_toctree.yml index 7227717ef..1ef7de3d6 100644 --- a/chapters/de/_toctree.yml +++ b/chapters/de/_toctree.yml @@ -28,6 +28,13 @@ title: Verwendung vortrainierter Modelle - local: chapter4/3 title: Vortrainierte Modelle teilen + - local: chapter4/4 + title: Erstellung einer Modellkarte ("model card") + - local: chapter4/5 + title: Teil 1 abgeschlossen! + - local: chapter4/6 + title: Quiz am Ende des Kapitels + quiz: 4 - title: Wörterverzeichnis sections: diff --git a/chapters/de/chapter4/4.mdx b/chapters/de/chapter4/4.mdx index 48b41c566..b490b4be8 100644 --- a/chapters/de/chapter4/4.mdx +++ b/chapters/de/chapter4/4.mdx @@ -1,4 +1,4 @@ -# Erstellung eines Modellkarte ("model card") +# Erstellung einer Modellkarte ("model card") -# End-of-chapter quiz +# Quiz am Ende des Kapitels Date: Tue, 5 Dec 2023 12:31:21 +0100 Subject: [PATCH 298/502] Update doc CI (#643) --- .github/workflows/delete_doc_comment.yml | 13 ------------- .github/workflows/delete_doc_comment_trigger.yml | 12 ------------ 2 files changed, 25 deletions(-) delete mode 100644 .github/workflows/delete_doc_comment.yml delete mode 100644 .github/workflows/delete_doc_comment_trigger.yml diff --git a/.github/workflows/delete_doc_comment.yml b/.github/workflows/delete_doc_comment.yml deleted file mode 100644 index 72801c856..000000000 --- a/.github/workflows/delete_doc_comment.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Delete doc comment - -on: - workflow_run: - workflows: ["Delete doc comment trigger"] - types: - - completed - -jobs: - delete: - uses: huggingface/doc-builder/.github/workflows/delete_doc_comment.yml@main - secrets: - comment_bot_token: ${{ secrets.COMMENT_BOT_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/delete_doc_comment_trigger.yml b/.github/workflows/delete_doc_comment_trigger.yml deleted file mode 100644 index 5e39e2539..000000000 --- a/.github/workflows/delete_doc_comment_trigger.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Delete doc comment trigger - -on: - pull_request: - types: [ closed ] - - -jobs: - delete: - uses: huggingface/doc-builder/.github/workflows/delete_doc_comment_trigger.yml@main - with: - pr_number: ${{ github.event.number }} \ No newline at end of file From 3def036a672b3ca28fedef7ed4b7861c6bd34506 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Tue, 12 Dec 2023 17:59:47 +0300 Subject: [PATCH 299/502] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=82=D0=B5=D0=BA=D1=83=D1=89=D0=B8=D1=85=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82=D0=B0=D1=82=D0=BE?= =?UTF-8?q?=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_toctree-checkpoint.yml | 201 ++++++ .../.ipynb_checkpoints/1-checkpoint.mdx | 19 + .../.ipynb_checkpoints/2-checkpoint.mdx | 257 +++++++ .../TRANSLATING-checkpoint.txt | 47 ++ .../_toctree-checkpoint.yml | 114 ++++ chapters/ru/_toctree.yml | 32 +- .../.ipynb_checkpoints/1-checkpoint.mdx | 19 + .../.ipynb_checkpoints/2-checkpoint.mdx | 257 +++++++ chapters/ru/chapter6/1.mdx | 16 +- chapters/ru/chapter6/10.mdx | 283 ++++++++ chapters/ru/chapter6/2.mdx | 82 +-- chapters/ru/chapter6/3.mdx | 473 +++++++++++++ chapters/ru/chapter6/3b.mdx | 642 ++++++++++++++++++ chapters/ru/chapter6/4.mdx | 123 ++++ chapters/ru/chapter6/5.mdx | 360 ++++++++++ chapters/ru/chapter6/6.mdx | 374 ++++++++++ chapters/ru/chapter6/7.mdx | 381 +++++++++++ chapters/ru/chapter6/8.mdx | 565 +++++++++++++++ chapters/ru/chapter6/9.mdx | 16 + 19 files changed, 4205 insertions(+), 56 deletions(-) create mode 100644 chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml create mode 100644 chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx create mode 100644 chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx create mode 100644 chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt create mode 100644 chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/1-checkpoint.mdx create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/2-checkpoint.mdx create mode 100644 chapters/ru/chapter6/10.mdx create mode 100644 chapters/ru/chapter6/3.mdx create mode 100644 chapters/ru/chapter6/3b.mdx create mode 100644 chapters/ru/chapter6/4.mdx create mode 100644 chapters/ru/chapter6/5.mdx create mode 100644 chapters/ru/chapter6/6.mdx create mode 100644 chapters/ru/chapter6/7.mdx create mode 100644 chapters/ru/chapter6/8.mdx create mode 100644 chapters/ru/chapter6/9.mdx diff --git a/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml new file mode 100644 index 000000000..c8364cc6d --- /dev/null +++ b/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml @@ -0,0 +1,201 @@ +- title: 0. Setup + sections: + - local: chapter0/1 + title: Introduction + +- title: 1. Transformer models + sections: + - local: chapter1/1 + title: Introduction + - local: chapter1/2 + title: Natural Language Processing + - local: chapter1/3 + title: Transformers, what can they do? + - local: chapter1/4 + title: How do Transformers work? + - local: chapter1/5 + title: Encoder models + - local: chapter1/6 + title: Decoder models + - local: chapter1/7 + title: Sequence-to-sequence models + - local: chapter1/8 + title: Bias and limitations + - local: chapter1/9 + title: Summary + - local: chapter1/10 + title: End-of-chapter quiz + quiz: 1 + +- title: 2. Using 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Behind the pipeline + - local: chapter2/3 + title: Models + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Handling multiple sequences + - local: chapter2/6 + title: Putting it all together + - local: chapter2/7 + title: Basic usage completed! + - local: chapter2/8 + title: End-of-chapter quiz + quiz: 2 + +- title: 3. Fine-tuning a pretrained model + sections: + - local: chapter3/1 + title: Introduction + - local: chapter3/2 + title: Processing the data + - local: chapter3/3 + title: Fine-tuning a model with the Trainer API or Keras + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: A full training + - local: chapter3/5 + title: Fine-tuning, Check! + - local: chapter3/6 + title: End-of-chapter quiz + quiz: 3 + +- title: 4. Sharing models and tokenizers + sections: + - local: chapter4/1 + title: The Hugging Face Hub + - local: chapter4/2 + title: Using pretrained models + - local: chapter4/3 + title: Sharing pretrained models + - local: chapter4/4 + title: Building a model card + - local: chapter4/5 + title: Part 1 completed! + - local: chapter4/6 + title: End-of-chapter quiz + quiz: 4 + +- title: 5. The 🤗 Datasets library + sections: + - local: chapter5/1 + title: Introduction + - local: chapter5/2 + title: What if my dataset isn't on the Hub? + - local: chapter5/3 + title: Time to slice and dice + - local: chapter5/4 + title: Big data? 🤗 Datasets to the rescue! + - local: chapter5/5 + title: Creating your own dataset + - local: chapter5/6 + title: Semantic search with FAISS + - local: chapter5/7 + title: 🤗 Datasets, check! + - local: chapter5/8 + title: End-of-chapter quiz + quiz: 5 + +- title: 6. The 🤗 Tokenizers library + sections: + - local: chapter6/1 + title: Introduction + - local: chapter6/2 + title: Training a new tokenizer from an old one + - local: chapter6/3 + title: Fast tokenizers' special powers + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Normalization and pre-tokenization + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 + +- title: 7. Main NLP tasks + sections: + - local: chapter7/1 + title: Introduction + - local: chapter7/2 + title: Token classification + - local: chapter7/3 + title: Fine-tuning a masked language model + - local: chapter7/4 + title: Translation + - local: chapter7/5 + title: Summarization + - local: chapter7/6 + title: Training a causal language model from scratch + - local: chapter7/7 + title: Question answering + - local: chapter7/8 + title: Mastering NLP + - local: chapter7/9 + title: End-of-chapter quiz + quiz: 7 + +- title: 8. How to ask for help + sections: + - local: chapter8/1 + title: Introduction + - local: chapter8/2 + title: What to do when you get an error + - local: chapter8/3 + title: Asking for help on the forums + - local: chapter8/4 + title: Debugging the training pipeline + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: How to write a good issue + - local: chapter8/6 + title: Part 2 completed! + - local: chapter8/7 + title: End-of-chapter quiz + quiz: 8 + +- title: 9. Building and sharing demos + new: true + subtitle: I trained a model, but how can I show it off? + sections: + - local: chapter9/1 + title: Introduction to Gradio + - local: chapter9/2 + title: Building your first demo + - local: chapter9/3 + title: Understanding the Interface class + - local: chapter9/4 + title: Sharing demos with others + - local: chapter9/5 + title: Integrations with the Hugging Face Hub + - local: chapter9/6 + title: Advanced Interface features + - local: chapter9/7 + title: Introduction to Blocks + - local: chapter9/8 + title: Gradio, check! + - local: chapter9/9 + title: End-of-chapter quiz + quiz: 9 + +- title: Course Events + sections: + - local: events/1 + title: Live sessions and workshops + - local: events/2 + title: Part 2 release event + - local: events/3 + title: Gradio Blocks party diff --git a/chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx b/chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx new file mode 100644 index 000000000..ce50bfd4e --- /dev/null +++ b/chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx @@ -0,0 +1,19 @@ +# Introduction[[introduction]] + + + +In [Chapter 3](/course/chapter3), we looked at how to fine-tune a model on a given task. When we do that, we use the same tokenizer that the model was pretrained with -- but what do we do when we want to train a model from scratch? In these cases, using a tokenizer that was pretrained on a corpus from another domain or language is typically suboptimal. For example, a tokenizer that's trained on an English corpus will perform poorly on a corpus of Japanese texts because the use of spaces and punctuation is very different in the two languages. + +In this chapter, you will learn how to train a brand new tokenizer on a corpus of texts, so it can then be used to pretrain a language model. This will all be done with the help of the [🤗 Tokenizers](https://github.com/huggingface/tokenizers) library, which provides the "fast" tokenizers in the [🤗 Transformers](https://github.com/huggingface/transformers) library. We'll take a close look at the features that this library provides, and explore how the fast tokenizers differ from the "slow" versions. + +Topics we will cover include: + +* How to train a new tokenizer similar to the one used by a given checkpoint on a new corpus of texts +* The special features of fast tokenizers +* The differences between the three main subword tokenization algorithms used in NLP today +* How to build a tokenizer from scratch with the 🤗 Tokenizers library and train it on some data + +The techniques introduced in this chapter will prepare you for the section in [Chapter 7](/course/chapter7/6) where we look at creating a language model for Python source code. Let's start by looking at what it means to "train" a tokenizer in the first place. \ No newline at end of file diff --git a/chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx b/chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx new file mode 100644 index 000000000..e966c486e --- /dev/null +++ b/chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx @@ -0,0 +1,257 @@ +# Training a new tokenizer from an old one[[training-a-new-tokenizer-from-an-old-one]] + + + +If a language model is not available in the language you are interested in, or if your corpus is very different from the one your language model was trained on, you will most likely want to retrain the model from scratch using a tokenizer adapted to your data. That will require training a new tokenizer on your dataset. But what exactly does that mean? When we first looked at tokenizers in [Chapter 2](/course/chapter2), we saw that most Transformer models use a _subword tokenization algorithm_. To identify which subwords are of interest and occur most frequently in the corpus at hand, the tokenizer needs to take a hard look at all the texts in the corpus -- a process we call *training*. The exact rules that govern this training depend on the type of tokenizer used, and we'll go over the three main algorithms later in this chapter. + + + + + +⚠️ Training a tokenizer is not the same as training a model! Model training uses stochastic gradient descent to make the loss a little bit smaller for each batch. It's randomized by nature (meaning you have to set some seeds to get the same results when doing the same training twice). Training a tokenizer is a statistical process that tries to identify which subwords are the best to pick for a given corpus, and the exact rules used to pick them depend on the tokenization algorithm. It's deterministic, meaning you always get the same results when training with the same algorithm on the same corpus. + + + +## Assembling a corpus[[assembling-a-corpus]] + +There's a very simple API in 🤗 Transformers that you can use to train a new tokenizer with the same characteristics as an existing one: `AutoTokenizer.train_new_from_iterator()`. To see this in action, let’s say we want to train GPT-2 from scratch, but in a language other than English. Our first task will be to gather lots of data in that language in a training corpus. To provide examples everyone will be able to understand, we won't use a language like Russian or Chinese here, but rather a specialized English language: Python code. + +The [🤗 Datasets](https://github.com/huggingface/datasets) library can help us assemble a corpus of Python source code. We'll use the usual `load_dataset()` function to download and cache the [CodeSearchNet](https://huggingface.co/datasets/code_search_net) dataset. This dataset was created for the [CodeSearchNet challenge](https://wandb.ai/github/CodeSearchNet/benchmark) and contains millions of functions from open source libraries on GitHub in several programming languages. Here, we will load the Python part of this dataset: + +```py +from datasets import load_dataset + +# This can take a few minutes to load, so grab a coffee or tea while you wait! +raw_datasets = load_dataset("code_search_net", "python") +``` + +We can have a look at the training split to see which columns we have access to: + +```py +raw_datasets["train"] +``` + +```python out +Dataset({ + features: ['repository_name', 'func_path_in_repository', 'func_name', 'whole_func_string', 'language', + 'func_code_string', 'func_code_tokens', 'func_documentation_string', 'func_documentation_tokens', 'split_name', + 'func_code_url' + ], + num_rows: 412178 +}) +``` + +We can see the dataset separates docstrings from code and suggests a tokenization of both. Here. we'll just use the `whole_func_string` column to train our tokenizer. We can look at an example of one these functions by indexing into the `train` split: + +```py +print(raw_datasets["train"][123456]["whole_func_string"]) +``` + +which should print the following: + +```out +def handle_simple_responses( + self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): + """Accepts normal responses from the device. + + Args: + timeout_ms: Timeout in milliseconds to wait for each response. + info_cb: Optional callback for text sent from the bootloader. + + Returns: + OKAY packet's message. + """ + return self._accept_responses('OKAY', info_cb, timeout_ms=timeout_ms) +``` + +The first thing we need to do is transform the dataset into an _iterator_ of lists of texts -- for instance, a list of list of texts. Using lists of texts will enable our tokenizer to go faster (training on batches of texts instead of processing individual texts one by one), and it should be an iterator if we want to avoid having everything in memory at once. If your corpus is huge, you will want to take advantage of the fact that 🤗 Datasets does not load everything into RAM but stores the elements of the dataset on disk. + +Doing the following would create a list of lists of 1,000 texts each, but would load everything in memory: + +```py +# Don't uncomment the following line unless your dataset is small! +# training_corpus = [raw_datasets["train"][i: i + 1000]["whole_func_string"] for i in range(0, len(raw_datasets["train"]), 1000)] +``` + +Using a Python generator, we can avoid Python loading anything into memory until it's actually necessary. To create such a generator, you just to need to replace the brackets with parentheses: + +```py +training_corpus = ( + raw_datasets["train"][i : i + 1000]["whole_func_string"] + for i in range(0, len(raw_datasets["train"]), 1000) +) +``` + +This line of code doesn't fetch any elements of the dataset; it just creates an object you can use in a Python `for` loop. The texts will only be loaded when you need them (that is, when you're at the step of the `for` loop that requires them), and only 1,000 texts at a time will be loaded. This way you won't exhaust all your memory even if you are processing a huge dataset. + +The problem with a generator object is that it can only be used once. So, instead of this giving us the list of the first 10 digits twice: + +```py +gen = (i for i in range(10)) +print(list(gen)) +print(list(gen)) +``` + +we get them once and then an empty list: + +```python out +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +[] +``` + +That's why we define a function that returns a generator instead: + +```py +def get_training_corpus(): + return ( + raw_datasets["train"][i : i + 1000]["whole_func_string"] + for i in range(0, len(raw_datasets["train"]), 1000) + ) + + +training_corpus = get_training_corpus() +``` + +You can also define your generator inside a `for` loop by using the `yield` statement: + +```py +def get_training_corpus(): + dataset = raw_datasets["train"] + for start_idx in range(0, len(dataset), 1000): + samples = dataset[start_idx : start_idx + 1000] + yield samples["whole_func_string"] +``` + +which will produce the exact same generator as before, but allows you to use more complex logic than you can in a list comprehension. + +## Training a new tokenizer[[training-a-new-tokenizer]] + +Now that we have our corpus in the form of an iterator of batches of texts, we are ready to train a new tokenizer. To do this, we first need to load the tokenizer we want to pair with our model (here, GPT-2): + +```py +from transformers import AutoTokenizer + +old_tokenizer = AutoTokenizer.from_pretrained("gpt2") +``` + +Even though we are going to train a new tokenizer, it's a good idea to do this to avoid starting entirely from scratch. This way, we won't have to specify anything about the tokenization algorithm or the special tokens we want to use; our new tokenizer will be exactly the same as GPT-2, and the only thing that will change is the vocabulary, which will be determined by the training on our corpus. + +First let's have a look at how this tokenizer would treat an example function: + +```py +example = '''def add_numbers(a, b): + """Add the two numbers `a` and `b`.""" + return a + b''' + +tokens = old_tokenizer.tokenize(example) +tokens +``` + +```python out +['def', 'Ġadd', '_', 'n', 'umbers', '(', 'a', ',', 'Ġb', '):', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', + 'Ġnumbers', 'Ġ`', 'a', '`', 'Ġand', 'Ġ`', 'b', '`', '."', '""', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] +``` + +This tokenizer has a few special symbols, like `Ġ` and `Ċ`, which denote spaces and newlines, respectively. As we can see, this is not too efficient: the tokenizer returns individual tokens for each space, when it could group together indentation levels (since having sets of four or eight spaces is going to be very common in code). It also split the function name a bit weirdly, not being used to seeing words with the `_` character. + +Let's train a new tokenizer and see if it solves those issues. For this, we'll use the method `train_new_from_iterator()`: + +```py +tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) +``` + +This command might take a bit of time if your corpus is very large, but for this dataset of 1.6 GB of texts it's blazing fast (1 minute 16 seconds on an AMD Ryzen 9 3900X CPU with 12 cores). + +Note that `AutoTokenizer.train_new_from_iterator()` only works if the tokenizer you are using is a "fast" tokenizer. As you'll see in the next section, the 🤗 Transformers library contains two types of tokenizers: some are written purely in Python and others (the fast ones) are backed by the 🤗 Tokenizers library, which is written in the [Rust](https://www.rust-lang.org) programming language. Python is the language most often used for data science and deep learning applications, but when anything needs to be parallelized to be fast, it has to be written in another language. For instance, the matrix multiplications that are at the core of the model computation are written in CUDA, an optimized C library for GPUs. + +Training a brand new tokenizer in pure Python would be excruciatingly slow, which is why we developed the 🤗 Tokenizers library. Note that just as you didn't have to learn the CUDA language to be able to execute your model on a batch of inputs on a GPU, you won't need to learn Rust to use a fast tokenizer. The 🤗 Tokenizers library provides Python bindings for many methods that internally call some piece of code in Rust; for example, to parallelize the training of your new tokenizer or, as we saw in [Chapter 3](/course/chapter3), the tokenization of a batch of inputs. + +Most of the Transformer models have a fast tokenizer available (there are some exceptions that you can check [here](https://huggingface.co/transformers/#supported-frameworks)), and the `AutoTokenizer` API always selects the fast tokenizer for you if it's available. In the next section we'll take a look at some of the other special features fast tokenizers have, which will be really useful for tasks like token classification and question answering. Before diving into that, however, let's try our brand new tokenizer on the previous example: + +```py +tokens = tokenizer.tokenize(example) +tokens +``` + +```python out +['def', 'Ġadd', '_', 'numbers', '(', 'a', ',', 'Ġb', '):', 'ĊĠĠĠ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', 'Ġnumbers', 'Ġ`', + 'a', '`', 'Ġand', 'Ġ`', 'b', '`."""', 'ĊĠĠĠ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] +``` + +Here we again see the special symbols `Ġ` and `Ċ` that denote spaces and newlines, but we can also see that our tokenizer learned some tokens that are highly specific to a corpus of Python functions: for example, there is a `ĊĠĠĠ` token that represents an indentation, and a `Ġ"""` token that represents the three quotes that start a docstring. The tokenizer also correctly split the function name on `_`. This is quite a compact representation; comparatively, using the plain English tokenizer on the same example will give us a longer sentence: + +```py +print(len(tokens)) +print(len(old_tokenizer.tokenize(example))) +``` + +```python out +27 +36 +``` + +Let's look at another example: + +```python +example = """class LinearLayer(): + def __init__(self, input_size, output_size): + self.weight = torch.randn(input_size, output_size) + self.bias = torch.zeros(output_size) + + def __call__(self, x): + return x @ self.weights + self.bias + """ +tokenizer.tokenize(example) +``` + +```python out +['class', 'ĠLinear', 'Layer', '():', 'ĊĠĠĠ', 'Ġdef', 'Ġ__', 'init', '__(', 'self', ',', 'Ġinput', '_', 'size', ',', + 'Ġoutput', '_', 'size', '):', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'weight', 'Ġ=', 'Ġtorch', '.', 'randn', '(', 'input', '_', + 'size', ',', 'Ġoutput', '_', 'size', ')', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'bias', 'Ġ=', 'Ġtorch', '.', 'zeros', '(', + 'output', '_', 'size', ')', 'ĊĊĠĠĠ', 'Ġdef', 'Ġ__', 'call', '__(', 'self', ',', 'Ġx', '):', 'ĊĠĠĠĠĠĠĠ', + 'Ġreturn', 'Ġx', 'Ġ@', 'Ġself', '.', 'weights', 'Ġ+', 'Ġself', '.', 'bias', 'ĊĠĠĠĠ'] +``` + +In addition to the token corresponding to an indentation, here we can also see a token for a double indentation: `ĊĠĠĠĠĠĠĠ`. The special Python words like `class`, `init`, `call`, `self`, and `return` are each tokenized as one token, and we can see that as well as splitting on `_` and `.` the tokenizer correctly splits even camel-cased names: `LinearLayer` is tokenized as `["ĠLinear", "Layer"]`. + +## Saving the tokenizer[[saving-the-tokenizer]] + +To make sure we can use it later, we need to save our new tokenizer. Like for models, this is done with the `save_pretrained()` method: + +```py +tokenizer.save_pretrained("code-search-net-tokenizer") +``` + +This will create a new folder named *code-search-net-tokenizer*, which will contain all the files the tokenizer needs to be reloaded. If you want to share this tokenizer with your colleagues and friends, you can upload it to the Hub by logging into your account. If you're working in a notebook, there's a convenience function to help you with this: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +This will display a widget where you can enter your Hugging Face login credentials. If you aren't working in a notebook, just type the following line in your terminal: + +```bash +huggingface-cli login +``` + +Once you've logged in, you can push your tokenizer by executing the following command: + +```py +tokenizer.push_to_hub("code-search-net-tokenizer") +``` + +This will create a new repository in your namespace with the name `code-search-net-tokenizer`, containing the tokenizer file. You can then load the tokenizer from anywhere with the `from_pretrained()` method: + +```py +# Replace "huggingface-course" below with your actual namespace to use your own tokenizer +tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") +``` + +You're now all set for training a language model from scratch and fine-tuning it on your task at hand! We'll get to that in [Chapter 7](/course/chapter7), but first, in the rest of this chapter we'll take a closer look at fast tokenizers and explore in detail what actually happens when we call the method `train_new_from_iterator()`. diff --git a/chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt b/chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt new file mode 100644 index 000000000..77282cecc --- /dev/null +++ b/chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt @@ -0,0 +1,47 @@ +1. We use the formal "you" (i.e. "вы" instead of "ты") to keep the neutral tone. + However, don't make the text too formal to keep it more engaging. + +2. Don't translate industry-accepted acronyms. e.g. TPU or GPU. + +3. The Russian language accepts English words especially in modern contexts more than + many other languages (i.e. Anglicisms). Check for the correct usage of terms in + computer science and commonly used terms in other publications. + +4. Russian word order is often different from English. If after translating a sentence + it sounds unnatural try to change the word or clause order to make it more natural. + +5. Beware of "false friends" in Russian and English translations. Translators are trained + for years to specifically avoid false English friends and avoid anglicised translations. + e.g. "точность" is "accuracy", but "carefulness" is "аккуратность". For more examples refer to: + http://falsefriends.ru/ffslovar.htm + +6. Keep voice active and consistent. Don't overdo it but try to avoid a passive voice. + +7. Refer and contribute to the glossary frequently to stay on top of the latest + choices we make. This minimizes the amount of editing that is required. + +8. Keep POV consistent. + +9. Smaller sentences are better sentences. Apply with nuance. + +10. If translating a technical word, keep the choice of Russian translation consistent. + This does not apply for non-technical choices, as in those cases variety actually + helps keep the text engaging. + +11. This is merely a translation. Don't add any technical/contextual information + not present in the original text. Also don't leave stuff out. The creative + choices in composing this information were the original authors' to make. + Our creative choices are in doing a quality translation. + +12. Be exact when choosing equivalents for technical words. Package is package. + Library is library. Don't mix and match. Also, since both "batch" and "package" + can be translated as "пакет", use "батч" for "batch" and "пакет" for "package" to + avoid ambiguity. + +13. Library names are kept in the original forms, e.g. "🤗 Datasets", however, + the word dataset in a sentence gets a translation to "датасет". + +14. As a style choice prefer the imperative over constructions with auxiliary words + to avoid unnecessary verbosity and addressing of the reader, which seems + unnatural in Russian. e.g. "см. главу X" - "See chapter X" instead of + "Вы можете найти это в главе X" - "You can see this in chapter X". \ No newline at end of file diff --git a/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml new file mode 100644 index 000000000..7b1b88ea3 --- /dev/null +++ b/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml @@ -0,0 +1,114 @@ +- title: 0. Установка + sections: + - local: chapter0/1 + title: Введение + +- title: 1. Трансформеры + sections: + - local: chapter1/1 + title: Введение + - local: chapter1/2 + title: Обработка естественного языка + - local: chapter1/3 + title: "Трансформеры: на что они способны?" + - local: chapter1/4 + title: Как работают трансформеры? + - local: chapter1/5 + title: Модели-кодировщики + - local: chapter1/6 + title: Модели-декодировщики + - local: chapter1/7 + title: Модели "seq2seq" + - local: chapter1/8 + title: Предвзятости и ограничения + - local: chapter1/9 + title: Итоги + - local: chapter1/10 + title: Проверка знаний + +- title: 2. Использование библиотеки 🤗 Transformers + sections: + - local: chapter2/1 + title: Введение + - local: chapter2/2 + title: Внутри конвейера + - local: chapter2/3 + title: Модели + - local: chapter2/7 + title: Базовое использование завершено! + +- title: 3. Fine-tuning предобученной модели + sections: + - local: chapter3/1 + title: Введение + - local: chapter3/2 + title: Предобработка данных + - local: chapter3/3 + title: Fine-tuning модели с использованием Trainer API + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: Полное обучение модели + - local: chapter3/5 + title: Fine-tuning, итоги! + - local: chapter3/6 + title: Итоговый тест по главе + quiz: 3 + +- title: 4. Hugging Face Hub + sections: + - local: chapter4/1 + title: Hugging Face Hub + - local: chapter4/2 + title: Использование предобученных моделей + - local: chapter4/3 + title: Публикация предобученных моделей в общий доступ + - local: chapter4/4 + title: Создание карточки модели + - local: chapter4/5 + title: Первая часть завершена! + - local: chapter4/6 + title: Итоговый тест по главе + quiz: 4 + +- title: 5. Библиотека 🤗 Datasets + sections: + - local: chapter5/1 + title: Введение + - local: chapter5/2 + title: Что делать, если моего датасета на нет на Hub? + - local: chapter5/3 + title: Препарируем 🤗 Datasets + - local: chapter5/4 + title: Big data? 🤗 Datasets спешат на помощь! + - local: chapter5/6 + title: Семантический поиск с помощью FAISS + - local: chapter5/7 + title: 🤗 Datasets, итоги! + - local: chapter5/8 + title: Тест по главе 5 + +- title: 6. Бибилиотека 🤗 Tokenizers + sections: + - local: chapter6/1 + title: Введение + - local: chapter6/2 + title: Обучение нового токенизатора на основе старого + - local: chapter6/3 + title: Особые возможности быстрых токенизаторов + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Нормализация и предварительная токенизация + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index 8bc60860c..7b1b88ea3 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -53,6 +53,7 @@ - local: chapter3/6 title: Итоговый тест по главе quiz: 3 + - title: 4. Hugging Face Hub sections: - local: chapter4/1 @@ -68,6 +69,7 @@ - local: chapter4/6 title: Итоговый тест по главе quiz: 4 + - title: 5. Библиотека 🤗 Datasets sections: - local: chapter5/1 @@ -83,14 +85,30 @@ - local: chapter5/7 title: 🤗 Datasets, итоги! - local: chapter5/8 - title: Тест по главе 5 + title: Тест по главе 5 + - title: 6. Бибилиотека 🤗 Tokenizers - sections: + sections: - local: chapter6/1 title: Введение - local: chapter6/2 - title: Обучение токенизатора на основе существующего -- title: Глоссарий - sections: - - local: glossary/1 - title: Глоссарий \ No newline at end of file + title: Обучение нового токенизатора на основе старого + - local: chapter6/3 + title: Особые возможности быстрых токенизаторов + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Нормализация и предварительная токенизация + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/1-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/1-checkpoint.mdx new file mode 100644 index 000000000..93525db9d --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/1-checkpoint.mdx @@ -0,0 +1,19 @@ +# Введение[[introduction]] + + + +В [Главе 3](/course/chapter3) мы рассмотрели, как дообучить модель для конкретной задачи. При этом мы используем тот же токенизатор, на котором была предварительно обучена модель, но что делать, когда мы хотим обучить модель с нуля? В таких случаях использование токенизатора, который был предварительно обучен на корпусе из другой области или языка, как правило, является неоптимальным. Например, токенизатор, обученный на корпусе английских текстов, будет плохо работать на корпусе японских текстов, поскольку использование пробелов и знаков препинания в этих двух языках сильно отличается. + +В этой главе вы узнаете, как обучить совершенно новый токенизатор на корпусе текстов, чтобы затем использовать его для предварительного обучения языковой модели. Все это будет сделано с помощью библиотеки [🤗 Tokenizers](https://github.com/huggingface/tokenizers), которая предоставляет "быстрые" токенизаторы в библиотеке [🤗 Transformers](https://github.com/huggingface/transformers). Мы подробно рассмотрим возможности, которые предоставляет эта библиотека, и выясним, чем быстрые токенизаторы отличаются от "медленных" версий. + +Мы рассмотрим следующие темы: + +* Как обучить новый токенизатор, аналогичный тому, который используется в данной контрольной точке, на новом корпусе текстов +* Особенности быстрых токенизаторов +* Различия между тремя основными алгоритмами токенизации по подсловам, используемыми в NLP сегодня +* Как создать токенизатор с нуля с помощью библиотеки 🤗 Tokenizers и обучить его на некоторых данных + +Техники, представленные в этой главе, подготовят вас к разделу в [Главе 7](/course/chapter7/6), где мы рассмотрим создание языковой модели по исходному коду Python. Для начала давайте разберемся, что значит "обучить" токенизатор. \ No newline at end of file diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/2-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/2-checkpoint.mdx new file mode 100644 index 000000000..4dfd465bb --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/2-checkpoint.mdx @@ -0,0 +1,257 @@ +# Обучение нового токенизатора на основе старого[[training-a-new-tokenizer-from-an-old-one]] + + + +Если языковая модель не доступна на интересующем вас языке или ваш корпус сильно отличается от того, на котором обучалась языковая модель, вам, скорее всего, придется заново обучать модель с нуля, используя токенизатор, адаптированный к вашим данным. Для этого потребуется обучить новый токенизатор на вашем наборе данных. Но что именно это значит? Когда мы впервые рассматривали токенизаторы в [Главе 2](/course/chapter2), мы увидели, что большинство моделей трансформеров используют _алгоритм токенизации по подсловам_. Чтобы определить, какие подслова представляют интерес и наиболее часто встречаются в корпусе, токенизатор должен внимательно изучить все тексты в корпусе - этот процесс мы называем *обучением*. Точные правила обучения зависят от типа используемого токенизатора, далее в этой главе мы рассмотрим три основных алгоритма. + + + + + +⚠️ Обучение токенизатора - это не то же самое, что обучение модели! При обучении модели используется стохастический градиентный спуск, чтобы сделать потери немного меньше для каждого батча. Оно рандомизировано по своей природе (это означает, что вам нужно задать некоторое число seed, чтобы получить одинаковые результаты при повторном обучении). Обучение токенизатора - это статистический процесс, который пытается определить, какие подслова лучше всего выбрать для данного корпуса, а точные правила, используемые для их выбора, зависят от алгоритма токенизации. Это детерминированный процесс, то есть вы всегда получите одинаковые результаты при обучении одного и того же алгоритма на одном и том же корпусе. + + + +## Сбор корпуса слов[[assembling-a-corpus]] + +В 🤗 Transformers есть очень простой API, который можно использовать для обучения нового токенизатора с теми же характеристиками, что и у существующего: `AutoTokenizer.train_new_from_iterator()`. Чтобы увидеть это в действии, предположим, что мы хотим обучить GPT-2 с нуля, но на языке, отличном от английского. Нашей первой задачей будет собрать много данных на этом языке в обучающий корпус. Чтобы примеры были понятны всем, мы будем использовать не русский или китайский язык, а будем использовать специализированный английский: Python-код. + +Библиотека [🤗 Datasets](https://github.com/huggingface/datasets) может помочь нам собрать корпус исходного кода Python. Мы воспользуемся обычной функцией `load_dataset()` для загрузки и кэширования набора данных [CodeSearchNet](https://huggingface.co/datasets/code_search_net). Этот набор данных был создан для конкурса [CodeSearchNet challenge](https://wandb.ai/github/CodeSearchNet/benchmark) и содержит миллионы функций из библиотек с открытым исходным кодом с GitHub на нескольких языках программирования. Здесь мы загрузим Python-часть этого набора данных: + +```py +from datasets import load_dataset + +# Загрузка может занять несколько минут, так что выпейте кофе или чай, пока ждете! +raw_datasets = load_dataset("code_search_net", "python") +``` + +Мы можем взглянуть на тренировочную часть датасета, чтобы узнать, к каким столбцам у нас есть доступ: + +```py +raw_datasets["train"] +``` + +```python out +Dataset({ + features: ['repository_name', 'func_path_in_repository', 'func_name', 'whole_func_string', 'language', + 'func_code_string', 'func_code_tokens', 'func_documentation_string', 'func_documentation_tokens', 'split_name', + 'func_code_url' + ], + num_rows: 412178 +}) +``` + +Мы видим, что набор данных отделяет документацию от кода и предлагает токенизировать и то, и другое. Здесь мы просто используем колонку `whole_func_string` для обучения нашего токенизатора. Мы можем посмотреть пример одной из этих функций, обратившись к соответствующему индексу в части `train`: + +```py +print(raw_datasets["train"][123456]["whole_func_string"]) +``` + +который должен вывести следующее: + +```out +def handle_simple_responses( + self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): + """Accepts normal responses from the device. + + Args: + timeout_ms: Timeout in milliseconds to wait for each response. + info_cb: Optional callback for text sent from the bootloader. + + Returns: + OKAY packet's message. + """ + return self._accept_responses('OKAY', info_cb, timeout_ms=timeout_ms) +``` + +Первое, что нам нужно сделать, это преобразовать набор данных в _итератор_ списков текстов -- например, список списков текстов. Использование списков текстов позволит нашему токенизатору работать быстрее (обучение на батчах текстов вместо обработки отдельных текстов по одному), и это должен быть итератор, если мы хотим избежать необходимости держать в памяти все сразу. Если ваш корпус огромен, вы захотите воспользоваться тем, что 🤗 Datasets не загружает все в RAM, а хранит элементы набора данных на диске. + +Следующее действие создаст список списков по 1 000 текстов в каждом, но загрузит все в память: + +```py +# Не раскоментируйте следующую строку кода, если только ваш набор данных не маленький! +# training_corpus = [raw_datasets["train"][i: i + 1000]["whole_func_string"] for i in range(0, len(raw_datasets["train"]), 1000)] +``` + +Используя генератор Python, мы можем не загружать ничего в память Python до тех пор, пока это действительно не понадобится. Чтобы создать такой генератор, нужно просто заменить скобки на круглые скобки: + +```py +training_corpus = ( + raw_datasets["train"][i : i + 1000]["whole_func_string"] + for i in range(0, len(raw_datasets["train"]), 1000) +) +``` + +Эта строка кода не получает никаких элементов из набора данных; она просто создает объект, который можно использовать в цикле Python `for`. Тексты будут загружаться только тогда, когда они вам нужны (то есть когда вы находитесь на том шаге цикла `for`, где они требуются), и за один раз будет загружено только 1 000 текстов. Таким образом, вы не исчерпаете всю память, даже если обрабатываете огромный набор данных. + +Проблема с объектом-генератором заключается в том, что он может быть использован только один раз. Поэтому вместо того, чтобы выдать нам список первых 10 цифр дважды: + +```py +gen = (i for i in range(10)) +print(list(gen)) +print(list(gen)) +``` + +мы получаем его один раз, а затем пустой список: + +```python out +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +[] +``` + +Поэтому мы определяем функцию, которая возвращает генератор: + +```py +def get_training_corpus(): + return ( + raw_datasets["train"][i : i + 1000]["whole_func_string"] + for i in range(0, len(raw_datasets["train"]), 1000) + ) + + +training_corpus = get_training_corpus() +``` + +Вы также можете определить свой генератор внутри цикла `for`, используя оператор `yield`: + +```py +def get_training_corpus(): + dataset = raw_datasets["train"] + for start_idx in range(0, len(dataset), 1000): + samples = dataset[start_idx : start_idx + 1000] + yield samples["whole_func_string"] +``` + +который выдает точно такой же генератор, как и предыдущий, но позволяет использовать более сложную логику, чем при работе с list comprehension. + +## Обучение нового токенизатора[[training-a-new-tokenizer]] + +Теперь, когда у нас есть корпус в виде итератора батчей текстов, мы готовы обучить новый токенизатор. Для этого нам сначала нужно загрузить токенизатор, который мы хотим использовать в паре с нашей моделью (здесь GPT-2): + +```py +from transformers import AutoTokenizer + +old_tokenizer = AutoTokenizer.from_pretrained("gpt2") +``` + +Несмотря на то, что мы собираемся обучить новый токенизатор, это хорошая идея сделать это, не начиная все с нуля. Таким образом, нам не придется ничего уточнять об алгоритме токенизации или специальных токенах, которые мы хотим использовать; наш новый токенизатор будет точно таким же, как GPT-2, и единственное, что изменится, - это словарный запас, который будет определен в результате обучения на нашем корпусе. + +Сначала давайте посмотрим, как будет работать этот токенизатор с примером функции: + +```py +example = '''def add_numbers(a, b): + """Add the two numbers `a` and `b`.""" + return a + b''' + +tokens = old_tokenizer.tokenize(example) +tokens +``` + +```python out +['def', 'Ġadd', '_', 'n', 'umbers', '(', 'a', ',', 'Ġb', '):', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', + 'Ġnumbers', 'Ġ`', 'a', '`', 'Ġand', 'Ġ`', 'b', '`', '."', '""', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] +``` + +Этот токенизатор имеет несколько специальных символов, таких как `Ġ` и `Ċ`, которые обозначают пробелы и новые строки, соответственно. Как мы видим, это не слишком эффективно: токенизатор возвращает отдельные токены для каждого пробела, в то время как он мог бы группировать уровни отступов (поскольку наборы из четырех или восьми пробелов будут очень часто встречаться в коде). Он также немного странно разделил имя функции, не ожидая увидеть слова с символом `_`. + +Давайте обучим новый токенизатор и посмотрим, решит ли он эти проблемы. Для этого мы воспользуемся методом `train_new_from_iterator()`: + +```py +tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) +``` + +Выполнение этой команды может занять много времени, если ваш корпус очень большой, но для данного набора данных с 1,6 ГБ текстов она работает молниеносно (1 минута 16 секунд на процессоре AMD Ryzen 9 3900X с 12 ядрами). + +Обратите внимание, что `AutoTokenizer.train_new_from_iterator()` работает только в том случае, если используемый вами токенизатор является "быстрым" токенизатором. Как вы увидите в следующем разделе, библиотека 🤗 Transformers содержит два типа токенизаторов: одни написаны исключительно на Python, а другие (быстрые) опираются на библиотеку 🤗 Tokenizers, которая написана на языке программирования [Rust](https://www.rust-lang.org). Python - это язык, который чаще всего используется для приложений data science и deep learning, но когда что-то нужно распараллелить для быстроты, это приходится писать на другом языке. Например, матричные умножения, которые лежат в основе вычислений модели, написаны на CUDA, оптимизированной библиотеке языка C для GPU. + +Обучение совершенно нового токенизатора на чистом Python было бы мучительно медленным, поэтому мы разработали библиотеку 🤗 Tokenizers. Обратите внимание, что так же как вам не нужно было изучать язык CUDA, чтобы выполнить свою модель на батче входных данных на GPU, вам не понадобится изучать Rust, чтобы использовать быстрый токенизатор. Библиотека 🤗 Tokenizers предоставляет привязки к Python для многих методов, которые внутренне вызывают некоторые части кода на Rust; например, для распараллеливания обучения вашего нового токенизатора или, как мы видели в [Главе 3](/course/chapter3), токенизации батча входных данных. + +В большинстве моделей Transformer доступен быстрый токенизатор (есть некоторые исключения, о которых вы можете узнать [здесь](https://huggingface.co/transformers/#supported-frameworks)), а API `AutoTokenizer` всегда выбирает быстрый токенизатор, если он доступен. В следующем разделе мы рассмотрим некоторые другие особенности быстрых токенизаторов, которые будут очень полезны для таких задач, как классификация токенов и ответы на вопросы. Однако прежде чем погрузиться в эту тему, давайте попробуем наш новый токенизатор на предыдущем примере: + +```py +tokens = tokenizer.tokenize(example) +tokens +``` + +```python out +['def', 'Ġadd', '_', 'numbers', '(', 'a', ',', 'Ġb', '):', 'ĊĠĠĠ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', 'Ġnumbers', 'Ġ`', + 'a', '`', 'Ġand', 'Ġ`', 'b', '`."""', 'ĊĠĠĠ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] +``` + +Здесь мы снова видим специальные символы `Ġ` и `Ċ`, обозначающие пробелы и новые строки, но мы также видим, что наш токенизатор выучил некоторые токены, которые очень специфичны для корпуса функций Python: например, есть токен `ĊĠĠĠ`, который обозначает отступ, и токен `Ġ"""`, который обозначает три кавычки, с которых начинается doc-строка. Токенизатор также правильно разделил имя функции на `_`. Это довольно компактное представление; для сравнения, использование токенизатора простого английского языка для того же примера даст нам более длинное предложение: + +```py +print(len(tokens)) +print(len(old_tokenizer.tokenize(example))) +``` + +```python out +27 +36 +``` + +Давайте рассмотрим другой пример: + +```python +example = """class LinearLayer(): + def __init__(self, input_size, output_size): + self.weight = torch.randn(input_size, output_size) + self.bias = torch.zeros(output_size) + + def __call__(self, x): + return x @ self.weights + self.bias + """ +tokenizer.tokenize(example) +``` + +```python out +['class', 'ĠLinear', 'Layer', '():', 'ĊĠĠĠ', 'Ġdef', 'Ġ__', 'init', '__(', 'self', ',', 'Ġinput', '_', 'size', ',', + 'Ġoutput', '_', 'size', '):', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'weight', 'Ġ=', 'Ġtorch', '.', 'randn', '(', 'input', '_', + 'size', ',', 'Ġoutput', '_', 'size', ')', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'bias', 'Ġ=', 'Ġtorch', '.', 'zeros', '(', + 'output', '_', 'size', ')', 'ĊĊĠĠĠ', 'Ġdef', 'Ġ__', 'call', '__(', 'self', ',', 'Ġx', '):', 'ĊĠĠĠĠĠĠĠ', + 'Ġreturn', 'Ġx', 'Ġ@', 'Ġself', '.', 'weights', 'Ġ+', 'Ġself', '.', 'bias', 'ĊĠĠĠĠ'] +``` + +В дополнение к токену, соответствующему отступу, здесь мы также видим токен для двойного отступа: `ĊĠĠĠĠĠĠĠĠĠ`. Специальные слова Python, такие как `class`, `init`, `call`, `self` и `return`, обрабатываются как один токен, и мы видим, что наряду с разделением на `_` и `.` токенизатор правильно разделяет даже имена с camel-case: `LinearLayer` обрабатывается как `["ĠLinear", "Layer"]`. + +## Сохранение токенизатора[[saving-the-tokenizer]] + +Чтобы убедиться, что мы сможем использовать его позже, нам нужно сохранить наш новый токенизатор. Как и для моделей, это делается с помощью метода `save_pretrained()`: + +```py +tokenizer.save_pretrained("code-search-net-tokenizer") +``` + +В результате будет создана новая папка с именем *code-search-net-tokenizer*, в которой будут содержаться все файлы, необходимые токенизатору для загрузки. Если вы хотите поделиться этим токенизатором со своими коллегами и друзьями, вы можете загрузить его на Hub, войдя в свою учетную запись. Если вы работаете в блокноте, есть удобная функция, которая поможет вам в этом: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +Появится виджет, в котором вы можете ввести свои учетные данные для входа в Hugging Face. Если вы работаете не в блокноте, просто введите следующую строку в терминале: + +```bash +huggingface-cli login +``` + +После того как вы авторизовались, вы можете опубликовать свой токенизатор, выполнив следующую команду: + +```py +tokenizer.push_to_hub("code-search-net-tokenizer") +``` + +Это создаст новое хранилище в вашем пространстве имен с именем `code-search-net-tokenizer`, содержащее файл токенизатора. Затем вы можете загрузить токенизатор где угодно с помощью метода `from_pretrained()`: + +```py +# Замените "huggingface-course" ниже своим реальным пространством имен, чтобы использовать свой собственный токенизатор +tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") +``` + +Теперь вы готовы обучить языковую модель с нуля и дообучить ее в соответствии с поставленной задачей! Мы займемся этим в [Главе 7](/course/chapter7), но сначала в этой главе мы рассмотрим быстрые токенизаторы и подробно изучим, что происходит при вызове метода `train_new_from_iterator()`. diff --git a/chapters/ru/chapter6/1.mdx b/chapters/ru/chapter6/1.mdx index 50a260ae0..93525db9d 100644 --- a/chapters/ru/chapter6/1.mdx +++ b/chapters/ru/chapter6/1.mdx @@ -1,19 +1,19 @@ -# Введение +# Введение[[introduction]] -В [главе 3](/course/ru/chapter3), мы рассмотрели, как настроить модель под конкретную задачу. Когда мы это делаем, мы используем тот же токенизатор, с помощью которого была предварительно обучена модель, но что нам делать, когда мы хотим обучить модель с нуля? В этих случаях использование токенизатора, предварительно обученного на корпусе из другого домена или языка, обычно неоптимально. Например, токенизатор, обученный на английском корпусе, будет плохо работать с корпусом японских текстов, поскольку использование пробелов и пунктуации в этих двух языках сильно различается. +В [Главе 3](/course/chapter3) мы рассмотрели, как дообучить модель для конкретной задачи. При этом мы используем тот же токенизатор, на котором была предварительно обучена модель, но что делать, когда мы хотим обучить модель с нуля? В таких случаях использование токенизатора, который был предварительно обучен на корпусе из другой области или языка, как правило, является неоптимальным. Например, токенизатор, обученный на корпусе английских текстов, будет плохо работать на корпусе японских текстов, поскольку использование пробелов и знаков препинания в этих двух языках сильно отличается. -В этой главе вы узнаете, как обучить совершенно новый токенизатор на корпусе текстов, чтобы затем его можно было использовать для предобучения языковой модели. Все это будет сделано с помощью библиотеки [🤗 Tokenizers](https://github.com/huggingface/tokenizers), которая предоставляет «быстрые» токенизаторы в [🤗 Transformers](https://github.com/huggingface/transformers). Мы внимательно рассмотрим функции, предоставляемые этой библиотекой, и выясним, чем быстрые токенизаторы отличаются от «медленных» версий. +В этой главе вы узнаете, как обучить совершенно новый токенизатор на корпусе текстов, чтобы затем использовать его для предварительного обучения языковой модели. Все это будет сделано с помощью библиотеки [🤗 Tokenizers](https://github.com/huggingface/tokenizers), которая предоставляет "быстрые" токенизаторы в библиотеке [🤗 Transformers](https://github.com/huggingface/transformers). Мы подробно рассмотрим возможности, которые предоставляет эта библиотека, и выясним, чем быстрые токенизаторы отличаются от "медленных" версий. -Темы, которые мы рассмотрим: +Мы рассмотрим следующие темы: -* Как обучить новый токенизатор, аналогичный тому, который используется конкретной моделью, на новом корпусе текстов +* Как обучить новый токенизатор, аналогичный тому, который используется в данной контрольной точке, на новом корпусе текстов * Особенности быстрых токенизаторов -* Различия между тремя основными алгоритмами токенизации составных частей слов, используемыми сегодня в NLP. -* Как создать токенизатор с нуля с помощью библиотеки 🤗 Tokenizers и обучить его на собственных данных +* Различия между тремя основными алгоритмами токенизации по подсловам, используемыми в NLP сегодня +* Как создать токенизатор с нуля с помощью библиотеки 🤗 Tokenizers и обучить его на некоторых данных -Методы, представленные в этой главе, подготовят вас к разделу [главы 7](/course/ru/chapter7/6), где мы рассмотрим создание языковой модели для исходного кода Python. Давайте начнем с рассмотрения того, что значит «обучить» токенизатор. \ No newline at end of file +Техники, представленные в этой главе, подготовят вас к разделу в [Главе 7](/course/chapter7/6), где мы рассмотрим создание языковой модели по исходному коду Python. Для начала давайте разберемся, что значит "обучить" токенизатор. \ No newline at end of file diff --git a/chapters/ru/chapter6/10.mdx b/chapters/ru/chapter6/10.mdx new file mode 100644 index 000000000..e1d55634d --- /dev/null +++ b/chapters/ru/chapter6/10.mdx @@ -0,0 +1,283 @@ + + +# End-of-chapter quiz[[end-of-chapter-quiz]] + + + +Let's test what you learned in this chapter! + +### 1. When should you train a new tokenizer? + + + +### 2. What is the advantage of using a generator of lists of texts compared to a list of lists of texts when using `train_new_from_iterator()`? + +train_new_from_iterator() accepts.", + explain: "A list of lists of texts is a particular kind of generator of lists of texts, so the method will accept this too. Try again!" + }, + { + text: "You will avoid loading the whole dataset into memory at once.", + explain: "Right! Each batch of texts will be released from memory when you iterate, and the gain will be especially visible if you use 🤗 Datasets to store your texts.", + correct: true + }, + { + text: "This will allow the 🤗 Tokenizers library to use multiprocessing.", + explain: "No, it will use multiprocessing either way." + }, + { + text: "The tokenizer you train will generate better texts.", + explain: "The tokenizer does not generate text -- are you confusing it with a language model?" + } + ]} +/> + +### 3. What are the advantages of using a "fast" tokenizer? + + + +### 4. How does the `token-classification` pipeline handle entities that span over several tokens? + + + +### 5. How does the `question-answering` pipeline handle long contexts? + + + +### 6. What is normalization? + + + +### 7. What is pre-tokenization for a subword tokenizer? + + + +### 8. Select the sentences that apply to the BPE model of tokenization. + + + +### 9. Select the sentences that apply to the WordPiece model of tokenization. + + + +### 10. Select the sentences that apply to the Unigram model of tokenization. + + diff --git a/chapters/ru/chapter6/2.mdx b/chapters/ru/chapter6/2.mdx index 08c77aac3..4dfd465bb 100644 --- a/chapters/ru/chapter6/2.mdx +++ b/chapters/ru/chapter6/2.mdx @@ -1,4 +1,4 @@ -# Обучение нового токенизатора на основе существующего +# Обучение нового токенизатора на основе старого[[training-a-new-tokenizer-from-an-old-one]] -Если языковая модель недоступна на интересующем вас языке или если ваш корпус сильно отличается от того, на котором обучалась ваша языковая модель, вы, скорее всего, захотите переобучить модель с нуля, используя токенизатор, адаптированный к вашим данным. Это потребует обучения нового токенизатора на вашем наборе данных. Но что именно это означает? Когда мы впервые рассмотрели токенизаторы в [Главе 2](/course/chapter2), мы увидели, что большинство моделей Transformer используют _алгоритм токенизации составных частей слов_ (_subword tokenization algorithm_). Чтобы определить, какие подслова представляют интерес и чаще всего встречаются в имеющемся корпусе, токенизатору необходимо внимательно изучить все тексты в корпусе — процесс, который мы называем «обучением». Точные правила, управляющие этим обучением, зависят от типа используемого токенизатора, и мы рассмотрим три основных алгоритма позже в этой главе. +Если языковая модель не доступна на интересующем вас языке или ваш корпус сильно отличается от того, на котором обучалась языковая модель, вам, скорее всего, придется заново обучать модель с нуля, используя токенизатор, адаптированный к вашим данным. Для этого потребуется обучить новый токенизатор на вашем наборе данных. Но что именно это значит? Когда мы впервые рассматривали токенизаторы в [Главе 2](/course/chapter2), мы увидели, что большинство моделей трансформеров используют _алгоритм токенизации по подсловам_. Чтобы определить, какие подслова представляют интерес и наиболее часто встречаются в корпусе, токенизатор должен внимательно изучить все тексты в корпусе - этот процесс мы называем *обучением*. Точные правила обучения зависят от типа используемого токенизатора, далее в этой главе мы рассмотрим три основных алгоритма. -⚠️ Обучение токенизатора — это не то же самое, что обучение модели! Обучение модели использует стохастический градиентный спуск, чтобы уменьшить значение функции потерь для каждого батча данных. Он рандомизирован по своей природе (это означает, что вы должны зафиксировать несколько начальных значений, чтобы получить одинаковые результаты при выполнении одной и той же тренировки дважды). Обучение токенизатора — это статистический процесс, который пытается определить, какие подслова лучше всего выбирать для данного корпуса, а точные правила, используемые для их выбора, зависят от алгоритма токенизации. Он детерминирован, то есть вы всегда получаете одни и те же результаты при обучении с одним и тем же алгоритмом на одном и том же корпусе. +⚠️ Обучение токенизатора - это не то же самое, что обучение модели! При обучении модели используется стохастический градиентный спуск, чтобы сделать потери немного меньше для каждого батча. Оно рандомизировано по своей природе (это означает, что вам нужно задать некоторое число seed, чтобы получить одинаковые результаты при повторном обучении). Обучение токенизатора - это статистический процесс, который пытается определить, какие подслова лучше всего выбрать для данного корпуса, а точные правила, используемые для их выбора, зависят от алгоритма токенизации. Это детерминированный процесс, то есть вы всегда получите одинаковые результаты при обучении одного и того же алгоритма на одном и том же корпусе. -## Сбор корпуса слов +## Сбор корпуса слов[[assembling-a-corpus]] -В 🤗 Transformers есть очень простой API, который вы можете использовать для обучения нового токенизатора с теми же характеристиками, что и у существующего: `AutoTokenizer.train_new_from_iterator()`. Чтобы увидеть это в действии, предположим, что мы хотим обучить GPT-2 с нуля, но на языке, отличном от английского. Нашей первой задачей будет сбор большого количества данных на этом языке в обучающем корпусе. Чтобы предоставить примеры, понятные каждому, мы не будем использовать здесь язык, подобный русскому или китайскому, а скорее специализированный английский язык: код Python. +В 🤗 Transformers есть очень простой API, который можно использовать для обучения нового токенизатора с теми же характеристиками, что и у существующего: `AutoTokenizer.train_new_from_iterator()`. Чтобы увидеть это в действии, предположим, что мы хотим обучить GPT-2 с нуля, но на языке, отличном от английского. Нашей первой задачей будет собрать много данных на этом языке в обучающий корпус. Чтобы примеры были понятны всем, мы будем использовать не русский или китайский язык, а будем использовать специализированный английский: Python-код. -Библиотека [🤗 Datasets](https://github.com/huggingface/datasets) может помочь нам собрать корпус исходного кода Python. Мы будем использовать обычную функцию `load_dataset()` для загрузки и кэширования набора данных [CodeSearchNet](https://huggingface.co/datasets/code_search_net). Этот набор данных был создан для [соревнования CodeSearchNet](https://wandb.ai/github/CodeSearchNet/benchmark) и содержит миллионы функций из библиотек с открытым исходным кодом на GitHub на нескольких языках программирования. Здесь мы загрузим часть Python этого набора данных: +Библиотека [🤗 Datasets](https://github.com/huggingface/datasets) может помочь нам собрать корпус исходного кода Python. Мы воспользуемся обычной функцией `load_dataset()` для загрузки и кэширования набора данных [CodeSearchNet](https://huggingface.co/datasets/code_search_net). Этот набор данных был создан для конкурса [CodeSearchNet challenge](https://wandb.ai/github/CodeSearchNet/benchmark) и содержит миллионы функций из библиотек с открытым исходным кодом с GitHub на нескольких языках программирования. Здесь мы загрузим Python-часть этого набора данных: ```py from datasets import load_dataset -# Это может занять некоторое время – заварите себе чаю! +# Загрузка может занять несколько минут, так что выпейте кофе или чай, пока ждете! raw_datasets = load_dataset("code_search_net", "python") ``` -Мы можем взглянуть на обучающий сплит данных, чтобы увидеть, к каким столбцам у нас есть доступ: +Мы можем взглянуть на тренировочную часть датасета, чтобы узнать, к каким столбцам у нас есть доступ: ```py raw_datasets["train"] @@ -45,13 +45,14 @@ Dataset({ num_rows: 412178 }) ``` -Мы видим, что набор данных отделяет строки документации от кода и предлагает токенизацию обоих. Здесь мы просто будем использовать столбец `whole_func_string` для обучения нашего токенизатора. Мы можем посмотреть на пример одной из этих функций, проиндексировав раздел `train`: + +Мы видим, что набор данных отделяет документацию от кода и предлагает токенизировать и то, и другое. Здесь мы просто используем колонку `whole_func_string` для обучения нашего токенизатора. Мы можем посмотреть пример одной из этих функций, обратившись к соответствующему индексу в части `train`: ```py print(raw_datasets["train"][123456]["whole_func_string"]) ``` -должно быть распечатано следующее: +который должен вывести следующее: ```out def handle_simple_responses( @@ -68,16 +69,16 @@ def handle_simple_responses( return self._accept_responses('OKAY', info_cb, timeout_ms=timeout_ms) ``` -Первое, что нам нужно сделать, это преобразовать набор данных в _итератор_ списков текстов, например, в список списков текстов. Использование списков текстов позволит нашему токенизатору работать быстрее (обучение на пакетах текстов вместо обработки отдельных текстов по одному), и он должен быть итерируемым объектом, если мы хотим избежать хранения всего набора данных в памяти. Если ваш корпус огромен, вы захотите воспользоваться тем фактом, что 🤗 Datasets не загружают все в оперативную память, а сохраняют элементы набора данных на диске. +Первое, что нам нужно сделать, это преобразовать набор данных в _итератор_ списков текстов -- например, список списков текстов. Использование списков текстов позволит нашему токенизатору работать быстрее (обучение на батчах текстов вместо обработки отдельных текстов по одному), и это должен быть итератор, если мы хотим избежать необходимости держать в памяти все сразу. Если ваш корпус огромен, вы захотите воспользоваться тем, что 🤗 Datasets не загружает все в RAM, а хранит элементы набора данных на диске. -Следующее действие создаст список списков по 1000 текстов в каждом, но загрузит все в память: +Следующее действие создаст список списков по 1 000 текстов в каждом, но загрузит все в память: ```py -# Если ваш датасет маленький – оставьте эту строку закомментированной! +# Не раскоментируйте следующую строку кода, если только ваш набор данных не маленький! # training_corpus = [raw_datasets["train"][i: i + 1000]["whole_func_string"] for i in range(0, len(raw_datasets["train"]), 1000)] ``` -Используя генератор Python, мы можем избежать загрузки Python чего-либо в память до тех пор, пока это действительно необходимо. Чтобы создать такой генератор, вам нужно всего лишь заменить квадратные скобки круглыми: +Используя генератор Python, мы можем не загружать ничего в память Python до тех пор, пока это действительно не понадобится. Чтобы создать такой генератор, нужно просто заменить скобки на круглые скобки: ```py training_corpus = ( @@ -86,9 +87,9 @@ training_corpus = ( ) ``` -Эта строка кода не извлекает никаких элементов набора данных; он просто создает объект, который вы можете использовать в цикле for Python. Тексты будут загружаться только тогда, когда они вам нужны (то есть, когда вы находитесь на этапе цикла `for`, который их требует), и за один раз будет загружено только 1000 текстов. Таким образом, вы не исчерпаете всю свою память, даже если обрабатываете огромный набор данных. +Эта строка кода не получает никаких элементов из набора данных; она просто создает объект, который можно использовать в цикле Python `for`. Тексты будут загружаться только тогда, когда они вам нужны (то есть когда вы находитесь на том шаге цикла `for`, где они требуются), и за один раз будет загружено только 1 000 текстов. Таким образом, вы не исчерпаете всю память, даже если обрабатываете огромный набор данных. -Проблема с объектом-генератором заключается в том, что его можно использовать только один раз. Итак, вместо того, чтобы дважды давать нам список первых 10 цифр: +Проблема с объектом-генератором заключается в том, что он может быть использован только один раз. Поэтому вместо того, чтобы выдать нам список первых 10 цифр дважды: ```py gen = (i for i in range(10)) @@ -96,14 +97,14 @@ print(list(gen)) print(list(gen)) ``` -мы получим их только один раз, дальше список станет пустым: +мы получаем его один раз, а затем пустой список: ```python out [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [] ``` -Вот почему мы определяем функцию, которая вместо этого возвращает генератор: +Поэтому мы определяем функцию, которая возвращает генератор: ```py def get_training_corpus(): @@ -126,11 +127,11 @@ def get_training_corpus(): yield samples["whole_func_string"] ``` -который будет производить точно такой же генератор, как и раньше, но позволяет вам использовать более сложную логику, чем в обычном list comprehension. +который выдает точно такой же генератор, как и предыдущий, но позволяет использовать более сложную логику, чем при работе с list comprehension. -## Обучение нового токенизатора +## Обучение нового токенизатора[[training-a-new-tokenizer]] -Теперь, когда у нас есть корпус в виде итератора пакетов текстов, мы готовы обучить новый токенизатор. Для этого нам сначала нужно загрузить токенизатор, который мы хотим связать с нашей моделью (здесь, GPT-2): +Теперь, когда у нас есть корпус в виде итератора батчей текстов, мы готовы обучить новый токенизатор. Для этого нам сначала нужно загрузить токенизатор, который мы хотим использовать в паре с нашей моделью (здесь GPT-2): ```py from transformers import AutoTokenizer @@ -138,9 +139,9 @@ from transformers import AutoTokenizer old_tokenizer = AutoTokenizer.from_pretrained("gpt2") ``` -Несмотря на то, что мы собираемся обучить новый токенизатор, мы используем конкретный алгоритм (который был использован в GPT-2). Таким образом, нам не нужно будет указывать что-либо об алгоритме токенизации или специальных токенах, которые мы хотим использовать; наш новый токенизатор будет точно таким же, как GPT-2, и единственное, что изменится, — это словарный запас, который будет определен обучением на нашем корпусе. +Несмотря на то, что мы собираемся обучить новый токенизатор, это хорошая идея сделать это, не начиная все с нуля. Таким образом, нам не придется ничего уточнять об алгоритме токенизации или специальных токенах, которые мы хотим использовать; наш новый токенизатор будет точно таким же, как GPT-2, и единственное, что изменится, - это словарный запас, который будет определен в результате обучения на нашем корпусе. -Сначала давайте посмотрим, как этот токенизатор будет обрабатывать пример функции: +Сначала давайте посмотрим, как будет работать этот токенизатор с примером функции: ```py example = '''def add_numbers(a, b): @@ -156,21 +157,21 @@ tokens 'Ġnumbers', 'Ġ`', 'a', '`', 'Ġand', 'Ġ`', 'b', '`', '."', '""', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] ``` -Этот токенизатор имеет несколько специальных символов, таких как `Ġ` и `Ċ`, которые обозначают пробелы и символы новой строки соответственно. Как мы видим, это не слишком эффективно: токенизатор возвращает отдельные токены для каждого пробела, в то время как он мог бы сгруппировать уровни отступа (поскольку наборы из четырех или восьми пробелов будут очень распространены в коде). Он также немного странно разделял имя функции из-за используемого символа `_`. +Этот токенизатор имеет несколько специальных символов, таких как `Ġ` и `Ċ`, которые обозначают пробелы и новые строки, соответственно. Как мы видим, это не слишком эффективно: токенизатор возвращает отдельные токены для каждого пробела, в то время как он мог бы группировать уровни отступов (поскольку наборы из четырех или восьми пробелов будут очень часто встречаться в коде). Он также немного странно разделил имя функции, не ожидая увидеть слова с символом `_`. -Давайте обучим новый токенизатор и посмотрим, решит ли он эти проблемы. Для этого воспользуемся методом `train_new_from_iterator()`: +Давайте обучим новый токенизатор и посмотрим, решит ли он эти проблемы. Для этого мы воспользуемся методом `train_new_from_iterator()`: ```py tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) ``` -Этот процесс может занять некоторое время, если ваш корпус очень большой, но для этого набора данных из 1,6 ГБ текстов это невероятно быстро (1 минута 16 секунд на процессоре AMD Ryzen 9 3900X с 12 ядрами). +Выполнение этой команды может занять много времени, если ваш корпус очень большой, но для данного набора данных с 1,6 ГБ текстов она работает молниеносно (1 минута 16 секунд на процессоре AMD Ryzen 9 3900X с 12 ядрами). -Обратите внимание, что `AutoTokenizer.train_new_from_iterator()` работает только в том случае, если используемый вами токенизатор является «быстрым» токенизатором. Как вы увидите в следующем разделе, библиотека 🤗 Transformers содержит два типа токенизаторов: одни написаны исключительно на Python, а другие (более быстрые) поддерживаются библиотекой 🤗 Tokenizers, написанной на [Rust]( https://www.rust-lang.org). Python — это язык, который чаще всего используется для обработки данных и приложений глубокого обучения, но когда что-то нужно распараллелить, чтобы работать быстро, это приходится писать на другом языке. Например, умножение матриц, лежащее в основе вычисления модели, написано в CUDA, оптимизированной библиотеке C для графических процессоров. +Обратите внимание, что `AutoTokenizer.train_new_from_iterator()` работает только в том случае, если используемый вами токенизатор является "быстрым" токенизатором. Как вы увидите в следующем разделе, библиотека 🤗 Transformers содержит два типа токенизаторов: одни написаны исключительно на Python, а другие (быстрые) опираются на библиотеку 🤗 Tokenizers, которая написана на языке программирования [Rust](https://www.rust-lang.org). Python - это язык, который чаще всего используется для приложений data science и deep learning, но когда что-то нужно распараллелить для быстроты, это приходится писать на другом языке. Например, матричные умножения, которые лежат в основе вычислений модели, написаны на CUDA, оптимизированной библиотеке языка C для GPU. -Обучение нового токенизатора на чистом Python было бы мучительно медленным, поэтому мы разработали библиотеку 🤗 Tokenizers. Обратите внимание, что так же, как вам не нужно было изучать язык CUDA, чтобы иметь возможность выполнять свою модель на пакете входных данных на графическом процессоре, вам не нужно будет изучать Rust, чтобы использовать быстрый токенизатор. Библиотека 🤗 Tokenizers предоставляет привязки Python для многих методов, которые внутренне вызывают некоторый фрагмент кода в Rust; например, для распараллеливания обучения вашего нового токенизатора или, как мы видели в [Главе 3](/course/ru/chapter3), токенизации пакета батча данных. +Обучение совершенно нового токенизатора на чистом Python было бы мучительно медленным, поэтому мы разработали библиотеку 🤗 Tokenizers. Обратите внимание, что так же как вам не нужно было изучать язык CUDA, чтобы выполнить свою модель на батче входных данных на GPU, вам не понадобится изучать Rust, чтобы использовать быстрый токенизатор. Библиотека 🤗 Tokenizers предоставляет привязки к Python для многих методов, которые внутренне вызывают некоторые части кода на Rust; например, для распараллеливания обучения вашего нового токенизатора или, как мы видели в [Главе 3](/course/chapter3), токенизации батча входных данных. -Большинство моделей Transformer имеют быстрый токенизатор (есть некоторые исключения, которые вы можете проверить [здесь](https://huggingface.co/transformers/#supported-frameworks)), а API `AutoTokenizer` всегда выбирает быстрый токенизатор для вас, если он доступен. В следующем разделе мы рассмотрим некоторые другие специальные функции быстрых токенизаторов, которые будут действительно полезны для таких задач, как классификация токенов и ответы на вопросы. Однако, прежде чем углубляться в это, давайте попробуем наш новый токенизатор на предыдущем примере: +В большинстве моделей Transformer доступен быстрый токенизатор (есть некоторые исключения, о которых вы можете узнать [здесь](https://huggingface.co/transformers/#supported-frameworks)), а API `AutoTokenizer` всегда выбирает быстрый токенизатор, если он доступен. В следующем разделе мы рассмотрим некоторые другие особенности быстрых токенизаторов, которые будут очень полезны для таких задач, как классификация токенов и ответы на вопросы. Однако прежде чем погрузиться в эту тему, давайте попробуем наш новый токенизатор на предыдущем примере: ```py tokens = tokenizer.tokenize(example) @@ -182,8 +183,7 @@ tokens 'a', '`', 'Ġand', 'Ġ`', 'b', '`."""', 'ĊĠĠĠ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] ``` -Здесь мы снова видим специальные символы `Ġ` и `Ċ`, которые обозначают пробелы и символы новой строки, но мы также можем видеть, что наш токенизатор изучил некоторые токены, очень специфичные для корпуса функций Python: например, есть `ĊĠĠĠ ` токен, который представляет отступ, и токен `Ġ"""`, который представляет три кавычки, с которых начинается строка документации. Токенизатор также правильно разделяет имя функции по символу `_`. Это довольно компактное представление; для сравнения используем простой английский токенизатор на том же примере даст нам более длинное предложение: - +Здесь мы снова видим специальные символы `Ġ` и `Ċ`, обозначающие пробелы и новые строки, но мы также видим, что наш токенизатор выучил некоторые токены, которые очень специфичны для корпуса функций Python: например, есть токен `ĊĠĠĠ`, который обозначает отступ, и токен `Ġ"""`, который обозначает три кавычки, с которых начинается doc-строка. Токенизатор также правильно разделил имя функции на `_`. Это довольно компактное представление; для сравнения, использование токенизатора простого английского языка для того же примера даст нам более длинное предложение: ```py print(len(tokens)) @@ -195,7 +195,7 @@ print(len(old_tokenizer.tokenize(example))) 36 ``` -Давайте взглянем на еще один пример: +Давайте рассмотрим другой пример: ```python example = """class LinearLayer(): @@ -217,17 +217,17 @@ tokenizer.tokenize(example) 'Ġreturn', 'Ġx', 'Ġ@', 'Ġself', '.', 'weights', 'Ġ+', 'Ġself', '.', 'bias', 'ĊĠĠĠĠ'] ``` -В дополнение к токену, соответствующему отступу, здесь мы также можем видеть токен для двойного отступа: `ĊĠĠĠĠĠĠĠ`. Специальные слова Python, такие как `class`, `init`, `call`, `self` и `return` токенизатор корректно разбивает имена даже в верблюжьем регистре: `LinearLayer` токенизируется как `["ĠLinear", "Layer"]`. +В дополнение к токену, соответствующему отступу, здесь мы также видим токен для двойного отступа: `ĊĠĠĠĠĠĠĠĠĠ`. Специальные слова Python, такие как `class`, `init`, `call`, `self` и `return`, обрабатываются как один токен, и мы видим, что наряду с разделением на `_` и `.` токенизатор правильно разделяет даже имена с camel-case: `LinearLayer` обрабатывается как `["ĠLinear", "Layer"]`. -## Сохранение токенизатора +## Сохранение токенизатора[[saving-the-tokenizer]] -Чтобы убедиться, что мы сможем использовать его позже, нам нужно сохранить наш новый токенизатор. Как и в случае с моделями, это делается с помощью метода `save_pretrained()`: +Чтобы убедиться, что мы сможем использовать его позже, нам нужно сохранить наш новый токенизатор. Как и для моделей, это делается с помощью метода `save_pretrained()`: ```py tokenizer.save_pretrained("code-search-net-tokenizer") ``` -Будет создана новая папка с именем *code-search-net-tokenizer*, которая будет содержать все файлы, которые необходимо использовать токенизатору. Если вы хотите поделиться этим токенизатором со своими коллегами и друзьями, вы можете загрузить его в Hub, войдя в свою учетную запись. Если вы работаете в блокноте, есть удобная функция, которая поможет вам в этом: +В результате будет создана новая папка с именем *code-search-net-tokenizer*, в которой будут содержаться все файлы, необходимые токенизатору для загрузки. Если вы хотите поделиться этим токенизатором со своими коллегами и друзьями, вы можете загрузить его на Hub, войдя в свою учетную запись. Если вы работаете в блокноте, есть удобная функция, которая поможет вам в этом: ```python from huggingface_hub import notebook_login @@ -235,23 +235,23 @@ from huggingface_hub import notebook_login notebook_login() ``` -Это отобразит виджет, где вы можете ввести свои учетные данные для входа в Hugging Face. Если вы не работаете в блокноте, просто введите в терминале следующую строку: +Появится виджет, в котором вы можете ввести свои учетные данные для входа в Hugging Face. Если вы работаете не в блокноте, просто введите следующую строку в терминале: ```bash huggingface-cli login ``` -После входа в систему вы можете активировать свой токенизатор, выполнив следующую команду: +После того как вы авторизовались, вы можете опубликовать свой токенизатор, выполнив следующую команду: ```py tokenizer.push_to_hub("code-search-net-tokenizer") ``` -Это создаст новый репозиторий в вашем пространстве имен с именем `code-search-net-tokenizer`, содержащий файл токенизатора. Затем вы можете загрузить токенизатор из любого места с помощью метода `from_pretrained()`: +Это создаст новое хранилище в вашем пространстве имен с именем `code-search-net-tokenizer`, содержащее файл токенизатора. Затем вы можете загрузить токенизатор где угодно с помощью метода `from_pretrained()`: ```py -# Измените "huggingface-course" на ваше название пространства +# Замените "huggingface-course" ниже своим реальным пространством имен, чтобы использовать свой собственный токенизатор tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") ``` -Теперь у вас все готово для обучения языковой модели с нуля и ее точной настройки для вашей задачи! Мы вернемся к этому в [Главе 7](/course/ru/chapter7), но сначала в оставшейся части этой главы мы более подробно рассмотрим быстрые токенизаторы и подробно рассмотрим, что на самом деле происходит, когда мы вызываем метод ` train_new_from_iterator()`. +Теперь вы готовы обучить языковую модель с нуля и дообучить ее в соответствии с поставленной задачей! Мы займемся этим в [Главе 7](/course/chapter7), но сначала в этой главе мы рассмотрим быстрые токенизаторы и подробно изучим, что происходит при вызове метода `train_new_from_iterator()`. diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx new file mode 100644 index 000000000..88250f6df --- /dev/null +++ b/chapters/ru/chapter6/3.mdx @@ -0,0 +1,473 @@ + + +# Fast tokenizers' special powers[[fast-tokenizers-special-powers]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +In this section we will take a closer look at the capabilities of the tokenizers in 🤗 Transformers. Up to now we have only used them to tokenize inputs or decode IDs back into text, but tokenizers -- especially those backed by the 🤗 Tokenizers library -- can do a lot more. To illustrate these additional features, we will explore how to reproduce the results of the `token-classification` (that we called `ner`) and `question-answering` pipelines that we first encountered in [Chapter 1](/course/chapter1). + + + +In the following discussion, we will often make the distinction between "slow" and "fast" tokenizers. Slow tokenizers are those written in Python inside the 🤗 Transformers library, while the fast versions are the ones provided by 🤗 Tokenizers, which are written in Rust. If you remember the table from [Chapter 5](/course/chapter5/3) that reported how long it took a fast and a slow tokenizer to tokenize the Drug Review Dataset, you should have an idea of why we call them fast and slow: + +| | Fast tokenizer | Slow tokenizer +:--------------:|:--------------:|:-------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s + + + +⚠️ When tokenizing a single sentence, you won't always see a difference in speed between the slow and fast versions of the same tokenizer. In fact, the fast version might actually be slower! It's only when tokenizing lots of texts in parallel at the same time that you will be able to clearly see the difference. + + + +## Batch encoding[[batch-encoding]] + + + +The output of a tokenizer isn't a simple Python dictionary; what we get is actually a special `BatchEncoding` object. It's a subclass of a dictionary (which is why we were able to index into that result without any problem before), but with additional methods that are mostly used by fast tokenizers. + +Besides their parallelization capabilities, the key functionality of fast tokenizers is that they always keep track of the original span of texts the final tokens come from -- a feature we call *offset mapping*. This in turn unlocks features like mapping each word to the tokens it generated or mapping each character of the original text to the token it's inside, and vice versa. + +Let's take a look at an example: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +encoding = tokenizer(example) +print(type(encoding)) +``` + +As mentioned previously, we get a `BatchEncoding` object in the tokenizer's output: + +```python out + +``` + +Since the `AutoTokenizer` class picks a fast tokenizer by default, we can use the additional methods this `BatchEncoding` object provides. We have two ways to check if our tokenizer is a fast or a slow one. We can either check the attribute `is_fast` of the `tokenizer`: + +```python +tokenizer.is_fast +``` + +```python out +True +``` + +or check the same attribute of our `encoding`: + +```python +encoding.is_fast +``` + +```python out +True +``` + +Let's see what a fast tokenizer enables us to do. First, we can access the tokens without having to convert the IDs back to tokens: + +```py +encoding.tokens() +``` + +```python out +['[CLS]', 'My', 'name', 'is', 'S', '##yl', '##va', '##in', 'and', 'I', 'work', 'at', 'Hu', '##gging', 'Face', 'in', + 'Brooklyn', '.', '[SEP]'] +``` + +In this case the token at index 5 is `##yl`, which is part of the word "Sylvain" in the original sentence. We can also use the `word_ids()` method to get the index of the word each token comes from: + +```py +encoding.word_ids() +``` + +```python out +[None, 0, 1, 2, 3, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, None] +``` + +We can see that the tokenizer's special tokens `[CLS]` and `[SEP]` are mapped to `None`, and then each token is mapped to the word it originates from. This is especially useful to determine if a token is at the start of a word or if two tokens are in the same word. We could rely on the `##` prefix for that, but it only works for BERT-like tokenizers; this method works for any type of tokenizer as long as it's a fast one. In the next chapter, we'll see how we can use this capability to apply the labels we have for each word properly to the tokens in tasks like named entity recognition (NER) and part-of-speech (POS) tagging. We can also use it to mask all the tokens coming from the same word in masked language modeling (a technique called _whole word masking_). + + + +The notion of what a word is complicated. For instance, does "I'll" (a contraction of "I will") count as one or two words? It actually depends on the tokenizer and the pre-tokenization operation it applies. Some tokenizers just split on spaces, so they will consider this as one word. Others use punctuation on top of spaces, so will consider it two words. + +✏️ **Try it out!** Create a tokenizer from the `bert-base-cased` and `roberta-base` checkpoints and tokenize "81s" with them. What do you observe? What are the word IDs? + + + +Similarly, there is a `sentence_ids()` method that we can use to map a token to the sentence it came from (though in this case, the `token_type_ids` returned by the tokenizer can give us the same information). + +Lastly, we can map any word or token to characters in the original text, and vice versa, via the `word_to_chars()` or `token_to_chars()` and `char_to_word()` or `char_to_token()` methods. For instance, the `word_ids()` method told us that `##yl` is part of the word at index 3, but which word is it in the sentence? We can find out like this: + +```py +start, end = encoding.word_to_chars(3) +example[start:end] +``` + +```python out +Sylvain +``` + +As we mentioned previously, this is all powered by the fact the fast tokenizer keeps track of the span of text each token comes from in a list of *offsets*. To illustrate their use, next we'll show you how to replicate the results of the `token-classification` pipeline manually. + + + +✏️ **Try it out!** Create your own example text and see if you can understand which tokens are associated with word ID, and also how to extract the character spans for a single word. For bonus points, try using two sentences as input and see if the sentence IDs make sense to you. + + + +## Inside the `token-classification` pipeline[[inside-the-token-classification-pipeline]] + +In [Chapter 1](/course/chapter1) we got our first taste of applying NER -- where the task is to identify which parts of the text correspond to entities like persons, locations, or organizations -- with the 🤗 Transformers `pipeline()` function. Then, in [Chapter 2](/course/chapter2), we saw how a pipeline groups together the three stages necessary to get the predictions from a raw text: tokenization, passing the inputs through the model, and post-processing. The first two steps in the `token-classification` pipeline are the same as in any other pipeline, but the post-processing is a little more complex -- let's see how! + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +### Getting the base results with the pipeline[[getting-the-base-results-with-the-pipeline]] + +First, let's grab a token classification pipeline so we can get some results to compare manually. The model used by default is [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english); it performs NER on sentences: + +```py +from transformers import pipeline + +token_classifier = pipeline("token-classification") +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +The model properly identified each token generated by "Sylvain" as a person, each token generated by "Hugging Face" as an organization, and the token "Brooklyn" as a location. We can also ask the pipeline to group together the tokens that correspond to the same entity: + +```py +from transformers import pipeline + +token_classifier = pipeline("token-classification", aggregation_strategy="simple") +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +The `aggregation_strategy` picked will change the scores computed for each grouped entity. With `"simple"` the score is just the mean of the scores of each token in the given entity: for instance, the score of "Sylvain" is the mean of the scores we saw in the previous example for the tokens `S`, `##yl`, `##va`, and `##in`. Other strategies available are: + +- `"first"`, where the score of each entity is the score of the first token of that entity (so for "Sylvain" it would be 0.993828, the score of the token `S`) +- `"max"`, where the score of each entity is the maximum score of the tokens in that entity (so for "Hugging Face" it would be 0.98879766, the score of "Face") +- `"average"`, where the score of each entity is the average of the scores of the words composing that entity (so for "Sylvain" there would be no difference from the `"simple"` strategy, but "Hugging Face" would have a score of 0.9819, the average of the scores for "Hugging", 0.975, and "Face", 0.98879) + +Now let's see how to obtain these results without using the `pipeline()` function! + +### From inputs to predictions[[from-inputs-to-predictions]] + +{#if fw === 'pt'} + +First we need to tokenize our input and pass it through the model. This is done exactly as in [Chapter 2](/course/chapter2); we instantiate the tokenizer and the model using the `AutoXxx` classes and then use them on our example: + +```py +from transformers import AutoTokenizer, AutoModelForTokenClassification + +model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModelForTokenClassification.from_pretrained(model_checkpoint) + +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +inputs = tokenizer(example, return_tensors="pt") +outputs = model(**inputs) +``` + +Since we're using `AutoModelForTokenClassification` here, we get one set of logits for each token in the input sequence: + +```py +print(inputs["input_ids"].shape) +print(outputs.logits.shape) +``` + +```python out +torch.Size([1, 19]) +torch.Size([1, 19, 9]) +``` + +{:else} + +First we need to tokenize our input and pass it through the model. This is done exactly as in [Chapter 2](/course/chapter2); we instantiate the tokenizer and the model using the `TFAutoXxx` classes and then use them on our example: + +```py +from transformers import AutoTokenizer, TFAutoModelForTokenClassification + +model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = TFAutoModelForTokenClassification.from_pretrained(model_checkpoint) + +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +inputs = tokenizer(example, return_tensors="tf") +outputs = model(**inputs) +``` + +Since we're using `TFAutoModelForTokenClassification` here, we get one set of logits for each token in the input sequence: + +```py +print(inputs["input_ids"].shape) +print(outputs.logits.shape) +``` + +```python out +(1, 19) +(1, 19, 9) +``` + +{/if} + +We have a batch with 1 sequence of 19 tokens and the model has 9 different labels, so the output of the model has a shape of 1 x 19 x 9. Like for the text classification pipeline, we use a softmax function to convert those logits to probabilities, and we take the argmax to get predictions (note that we can take the argmax on the logits because the softmax does not change the order): + +{#if fw === 'pt'} + +```py +import torch + +probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)[0].tolist() +predictions = outputs.logits.argmax(dim=-1)[0].tolist() +print(predictions) +``` + +{:else} + +```py +import tensorflow as tf + +probabilities = tf.math.softmax(outputs.logits, axis=-1)[0] +probabilities = probabilities.numpy().tolist() +predictions = tf.math.argmax(outputs.logits, axis=-1)[0] +predictions = predictions.numpy().tolist() +print(predictions) +``` + +{/if} + +```python out +[0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 6, 6, 6, 0, 8, 0, 0] +``` + +The `model.config.id2label` attribute contains the mapping of indexes to labels that we can use to make sense of the predictions: + +```py +model.config.id2label +``` + +```python out +{0: 'O', + 1: 'B-MISC', + 2: 'I-MISC', + 3: 'B-PER', + 4: 'I-PER', + 5: 'B-ORG', + 6: 'I-ORG', + 7: 'B-LOC', + 8: 'I-LOC'} +``` + +As we saw earlier, there are 9 labels: `O` is the label for the tokens that are not in any named entity (it stands for "outside"), and we then have two labels for each type of entity (miscellaneous, person, organization, and location). The label `B-XXX` indicates the token is at the beginning of an entity `XXX` and the label `I-XXX` indicates the token is inside the entity `XXX`. For instance, in the current example we would expect our model to classify the token `S` as `B-PER` (beginning of a person entity) and the tokens `##yl`, `##va` and `##in` as `I-PER` (inside a person entity). + +You might think the model was wrong in this case as it gave the label `I-PER` to all four of these tokens, but that's not entirely true. There are actually two formats for those `B-` and `I-` labels: *IOB1* and *IOB2*. The IOB2 format (in pink below), is the one we introduced whereas in the IOB1 format (in blue), the labels beginning with `B-` are only ever used to separate two adjacent entities of the same type. The model we are using was fine-tuned on a dataset using that format, which is why it assigns the label `I-PER` to the `S` token. + +
+IOB1 vs IOB2 format + +
+ +With this map, we are ready to reproduce (almost entirely) the results of the first pipeline -- we can just grab the score and label of each token that was not classified as `O`: + +```py +results = [] +tokens = inputs.tokens() + +for idx, pred in enumerate(predictions): + label = model.config.id2label[pred] + if label != "O": + results.append( + {"entity": label, "score": probabilities[idx][pred], "word": tokens[idx]} + ) + +print(results) +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S'}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl'}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va'}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in'}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu'}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging'}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face'}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn'}] +``` + +This is very similar to what we had before, with one exception: the pipeline also gave us information about the `start` and `end` of each entity in the original sentence. This is where our offset mapping will come into play. To get the offsets, we just have to set `return_offsets_mapping=True` when we apply the tokenizer to our inputs: + +```py +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +inputs_with_offsets["offset_mapping"] +``` + +```python out +[(0, 0), (0, 2), (3, 7), (8, 10), (11, 12), (12, 14), (14, 16), (16, 18), (19, 22), (23, 24), (25, 29), (30, 32), + (33, 35), (35, 40), (41, 45), (46, 48), (49, 57), (57, 58), (0, 0)] +``` + +Each tuple is the span of text corresponding to each token, where `(0, 0)` is reserved for the special tokens. We saw before that the token at index 5 is `##yl`, which has `(12, 14)` as offsets here. If we grab the corresponding slice in our example: + + +```py +example[12:14] +``` + +we get the proper span of text without the `##`: + +```python out +yl +``` + +Using this, we can now complete the previous results: + +```py +results = [] +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +tokens = inputs_with_offsets.tokens() +offsets = inputs_with_offsets["offset_mapping"] + +for idx, pred in enumerate(predictions): + label = model.config.id2label[pred] + if label != "O": + start, end = offsets[idx] + results.append( + { + "entity": label, + "score": probabilities[idx][pred], + "word": tokens[idx], + "start": start, + "end": end, + } + ) + +print(results) +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +This is the same as what we got from the first pipeline! + +### Grouping entities[[grouping-entities]] + +Using the offsets to determine the start and end keys for each entity is handy, but that information isn't strictly necessary. When we want to group the entities together, however, the offsets will save us a lot of messy code. For example, if we wanted to group together the tokens `Hu`, `##gging`, and `Face`, we could make special rules that say the first two should be attached while removing the `##`, and the `Face` should be added with a space since it does not begin with `##` -- but that would only work for this particular type of tokenizer. We would have to write another set of rules for a SentencePiece or a Byte-Pair-Encoding tokenizer (discussed later in this chapter). + +With the offsets, all that custom code goes away: we just can take the span in the original text that begins with the first token and ends with the last token. So, in the case of the tokens `Hu`, `##gging`, and `Face`, we should start at character 33 (the beginning of `Hu`) and end before character 45 (the end of `Face`): + +```py +example[33:45] +``` + +```python out +Hugging Face +``` + +To write the code that post-processes the predictions while grouping entities, we will group together entities that are consecutive and labeled with `I-XXX`, except for the first one, which can be labeled as `B-XXX` or `I-XXX` (so, we stop grouping an entity when we get a `O`, a new type of entity, or a `B-XXX` that tells us an entity of the same type is starting): + +```py +import numpy as np + +results = [] +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +tokens = inputs_with_offsets.tokens() +offsets = inputs_with_offsets["offset_mapping"] + +idx = 0 +while idx < len(predictions): + pred = predictions[idx] + label = model.config.id2label[pred] + if label != "O": + # Remove the B- or I- + label = label[2:] + start, _ = offsets[idx] + + # Grab all the tokens labeled with I-label + all_scores = [] + while ( + idx < len(predictions) + and model.config.id2label[predictions[idx]] == f"I-{label}" + ): + all_scores.append(probabilities[idx][pred]) + _, end = offsets[idx] + idx += 1 + + # The score is the mean of all the scores of the tokens in that grouped entity + score = np.mean(all_scores).item() + word = example[start:end] + results.append( + { + "entity_group": label, + "score": score, + "word": word, + "start": start, + "end": end, + } + ) + idx += 1 + +print(results) +``` + +And we get the same results as with our second pipeline! + +```python out +[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +Another example of a task where these offsets are extremely useful is question answering. Diving into that pipeline, which we'll do in the next section, will also enable us to take a look at one last feature of the tokenizers in the 🤗 Transformers library: dealing with overflowing tokens when we truncate an input to a given length. diff --git a/chapters/ru/chapter6/3b.mdx b/chapters/ru/chapter6/3b.mdx new file mode 100644 index 000000000..d0affbcba --- /dev/null +++ b/chapters/ru/chapter6/3b.mdx @@ -0,0 +1,642 @@ + + +# Fast tokenizers in the QA pipeline[[fast-tokenizers-in-the-qa-pipeline]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +We will now dive into the `question-answering` pipeline and see how to leverage the offsets to grab the answer to the question at hand from the context, a bit like we did for the grouped entities in the previous section. Then we will see how we can deal with very long contexts that end up being truncated. You can skip this section if you're not interested in the question answering task. + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +## Using the `question-answering` pipeline[[using-the-question-answering-pipeline]] + +As we saw in [Chapter 1](/course/chapter1), we can use the `question-answering` pipeline like this to get the answer to a question: + +```py +from transformers import pipeline + +question_answerer = pipeline("question-answering") +context = """ +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch, and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question = "Which deep learning libraries back 🤗 Transformers?" +question_answerer(question=question, context=context) +``` + +```python out +{'score': 0.97773, + 'start': 78, + 'end': 105, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +Unlike the other pipelines, which can't truncate and split texts that are longer than the maximum length accepted by the model (and thus may miss information at the end of a document), this pipeline can deal with very long contexts and will return the answer to the question even if it's at the end: + +```py +long_context = """ +🤗 Transformers: State of the Art NLP + +🤗 Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, +question answering, summarization, translation, text generation and more in over 100 languages. +Its aim is to make cutting-edge NLP easier to use for everyone. + +🤗 Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and +then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and +can be modified to enable quick research experiments. + +Why should I use transformers? + +1. Easy-to-use state-of-the-art models: + - High performance on NLU and NLG tasks. + - Low barrier to entry for educators and practitioners. + - Few user-facing abstractions with just three classes to learn. + - A unified API for using all our pretrained models. + - Lower compute costs, smaller carbon footprint: + +2. Researchers can share trained models instead of always retraining. + - Practitioners can reduce compute time and production costs. + - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. + +3. Choose the right framework for every part of a model's lifetime: + - Train state-of-the-art models in 3 lines of code. + - Move a single model between TF2.0/PyTorch frameworks at will. + - Seamlessly pick the right framework for training, evaluation and production. + +4. Easily customize a model or an example to your needs: + - We provide examples for each architecture to reproduce the results published by its original authors. + - Model internals are exposed as consistently as possible. + - Model files can be used independently of the library for quick experiments. + +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question_answerer(question=question, context=long_context) +``` + +```python out +{'score': 0.97149, + 'start': 1892, + 'end': 1919, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +Let's see how it does all of this! + +## Using a model for question answering[[using-a-model-for-question-answering]] + +Like with any other pipeline, we start by tokenizing our input and then send it through the model. The checkpoint used by default for the `question-answering` pipeline is [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) (the "squad" in the name comes from the dataset on which the model was fine-tuned; we'll talk more about the SQuAD dataset in [Chapter 7](/course/chapter7/7)): + +{#if fw === 'pt'} + +```py +from transformers import AutoTokenizer, AutoModelForQuestionAnswering + +model_checkpoint = "distilbert-base-cased-distilled-squad" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) + +inputs = tokenizer(question, context, return_tensors="pt") +outputs = model(**inputs) +``` + +{:else} + +```py +from transformers import AutoTokenizer, TFAutoModelForQuestionAnswering + +model_checkpoint = "distilbert-base-cased-distilled-squad" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint) + +inputs = tokenizer(question, context, return_tensors="tf") +outputs = model(**inputs) +``` + +{/if} + +Note that we tokenize the question and the context as a pair, with the question first. + +
+An example of tokenization of question and context + +
+ +Models for question answering work a little differently from the models we've seen up to now. Using the picture above as an example, the model has been trained to predict the index of the token starting the answer (here 21) and the index of the token where the answer ends (here 24). This is why those models don't return one tensor of logits but two: one for the logits corresponding to the start token of the answer, and one for the logits corresponding to the end token of the answer. Since in this case we have only one input containing 66 tokens, we get: + +```py +start_logits = outputs.start_logits +end_logits = outputs.end_logits +print(start_logits.shape, end_logits.shape) +``` + +{#if fw === 'pt'} + +```python out +torch.Size([1, 66]) torch.Size([1, 66]) +``` + +{:else} + +```python out +(1, 66) (1, 66) +``` + +{/if} + +To convert those logits into probabilities, we will apply a softmax function -- but before that, we need to make sure we mask the indices that are not part of the context. Our input is `[CLS] question [SEP] context [SEP]`, so we need to mask the tokens of the question as well as the `[SEP]` token. We'll keep the `[CLS]` token, however, as some models use it to indicate that the answer is not in the context. + +Since we will apply a softmax afterward, we just need to replace the logits we want to mask with a large negative number. Here, we use `-10000`: + +{#if fw === 'pt'} + +```py +import torch + +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +mask = torch.tensor(mask)[None] + +start_logits[mask] = -10000 +end_logits[mask] = -10000 +``` + +{:else} + +```py +import tensorflow as tf + +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +mask = tf.constant(mask)[None] + +start_logits = tf.where(mask, -10000, start_logits) +end_logits = tf.where(mask, -10000, end_logits) +``` + +{/if} + +Now that we have properly masked the logits corresponding to positions we don't want to predict, we can apply the softmax: + +{#if fw === 'pt'} + +```py +start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1)[0] +end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1)[0] +``` + +{:else} + +```py +start_probabilities = tf.math.softmax(start_logits, axis=-1)[0].numpy() +end_probabilities = tf.math.softmax(end_logits, axis=-1)[0].numpy() +``` + +{/if} + +At this stage, we could take the argmax of the start and end probabilities -- but we might end up with a start index that is greater than the end index, so we need to take a few more precautions. We will compute the probabilities of each possible `start_index` and `end_index` where `start_index <= end_index`, then take the tuple `(start_index, end_index)` with the highest probability. + +Assuming the events "The answer starts at `start_index`" and "The answer ends at `end_index`" to be independent, the probability that the answer starts at `start_index` and ends at `end_index` is: + +$$\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]$$ + +So, to compute all the scores, we just need to compute all the products \\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\) where `start_index <= end_index`. + +First let's compute all the possible products: + +```py +scores = start_probabilities[:, None] * end_probabilities[None, :] +``` + +{#if fw === 'pt'} + +Then we'll mask the values where `start_index > end_index` by setting them to `0` (the other probabilities are all positive numbers). The `torch.triu()` function returns the upper triangular part of the 2D tensor passed as an argument, so it will do that masking for us: + +```py +scores = torch.triu(scores) +``` + +{:else} + +Then we'll mask the values where `start_index > end_index` by setting them to `0` (the other probabilities are all positive numbers). The `np.triu()` function returns the upper triangular part of the 2D tensor passed as an argument, so it will do that masking for us: + +```py +import numpy as np + +scores = np.triu(scores) +``` + +{/if} + +Now we just have to get the index of the maximum. Since PyTorch will return the index in the flattened tensor, we need to use the floor division `//` and modulus `%` operations to get the `start_index` and `end_index`: + +```py +max_index = scores.argmax().item() +start_index = max_index // scores.shape[1] +end_index = max_index % scores.shape[1] +print(scores[start_index, end_index]) +``` + +We're not quite done yet, but at least we already have the correct score for the answer (you can check this by comparing it to the first result in the previous section): + +```python out +0.97773 +``` + + + +✏️ **Try it out!** Compute the start and end indices for the five most likely answers. + + + +We have the `start_index` and `end_index` of the answer in terms of tokens, so now we just need to convert to the character indices in the context. This is where the offsets will be super useful. We can grab them and use them like we did in the token classification task: + +```py +inputs_with_offsets = tokenizer(question, context, return_offsets_mapping=True) +offsets = inputs_with_offsets["offset_mapping"] + +start_char, _ = offsets[start_index] +_, end_char = offsets[end_index] +answer = context[start_char:end_char] +``` + +Now we just have to format everything to get our result: + +```py +result = { + "answer": answer, + "start": start_char, + "end": end_char, + "score": scores[start_index, end_index], +} +print(result) +``` + +```python out +{'answer': 'Jax, PyTorch and TensorFlow', + 'start': 78, + 'end': 105, + 'score': 0.97773} +``` + +Great! That's the same as in our first example! + + + +✏️ **Try it out!** Use the best scores you computed earlier to show the five most likely answers. To check your results, go back to the first pipeline and pass in `top_k=5` when calling it. + + + +## Handling long contexts[[handling-long-contexts]] + +If we try to tokenize the question and long context we used as an example previously, we'll get a number of tokens higher than the maximum length used in the `question-answering` pipeline (which is 384): + +```py +inputs = tokenizer(question, long_context) +print(len(inputs["input_ids"])) +``` + +```python out +461 +``` + +So, we'll need to truncate our inputs at that maximum length. There are several ways we can do this, but we don't want to truncate the question, only the context. Since the context is the second sentence, we'll use the `"only_second"` truncation strategy. The problem that arises then is that the answer to the question may not be in the truncated context. Here, for instance, we picked a question where the answer is toward the end of the context, and when we truncate it that answer is not present: + +```py +inputs = tokenizer(question, long_context, max_length=384, truncation="only_second") +print(tokenizer.decode(inputs["input_ids"])) +``` + +```python out +""" +[CLS] Which deep learning libraries back [UNK] Transformers? [SEP] [UNK] Transformers : State of the Art NLP + +[UNK] Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, +question answering, summarization, translation, text generation and more in over 100 languages. +Its aim is to make cutting-edge NLP easier to use for everyone. + +[UNK] Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and +then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and +can be modified to enable quick research experiments. + +Why should I use transformers? + +1. Easy-to-use state-of-the-art models: + - High performance on NLU and NLG tasks. + - Low barrier to entry for educators and practitioners. + - Few user-facing abstractions with just three classes to learn. + - A unified API for using all our pretrained models. + - Lower compute costs, smaller carbon footprint: + +2. Researchers can share trained models instead of always retraining. + - Practitioners can reduce compute time and production costs. + - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. + +3. Choose the right framework for every part of a model's lifetime: + - Train state-of-the-art models in 3 lines of code. + - Move a single model between TF2.0/PyTorch frameworks at will. + - Seamlessly pick the right framework for training, evaluation and production. + +4. Easily customize a model or an example to your needs: + - We provide examples for each architecture to reproduce the results published by its original authors. + - Model internal [SEP] +""" +``` + +This means the model will have a hard time picking the correct answer. To fix this, the `question-answering` pipeline allows us to split the context into smaller chunks, specifying the maximum length. To make sure we don't split the context at exactly the wrong place to make it possible to find the answer, it also includes some overlap between the chunks. + +We can have the tokenizer (fast or slow) do this for us by adding `return_overflowing_tokens=True`, and we can specify the overlap we want with the `stride` argument. Here is an example, using a smaller sentence: + +```py +sentence = "This sentence is not too long but we are going to split it anyway." +inputs = tokenizer( + sentence, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 +) + +for ids in inputs["input_ids"]: + print(tokenizer.decode(ids)) +``` + +```python out +'[CLS] This sentence is not [SEP]' +'[CLS] is not too long [SEP]' +'[CLS] too long but we [SEP]' +'[CLS] but we are going [SEP]' +'[CLS] are going to split [SEP]' +'[CLS] to split it anyway [SEP]' +'[CLS] it anyway. [SEP]' +``` + +As we can see, the sentence has been split into chunks in such a way that each entry in `inputs["input_ids"]` has at most 6 tokens (we would need to add padding to have the last entry be the same size as the others) and there is an overlap of 2 tokens between each of the entries. + +Let's take a closer look at the result of the tokenization: + +```py +print(inputs.keys()) +``` + +```python out +dict_keys(['input_ids', 'attention_mask', 'overflow_to_sample_mapping']) +``` + +As expected, we get input IDs and an attention mask. The last key, `overflow_to_sample_mapping`, is a map that tells us which sentence each of the results corresponds to -- here we have 7 results that all come from the (only) sentence we passed the tokenizer: + +```py +print(inputs["overflow_to_sample_mapping"]) +``` + +```python out +[0, 0, 0, 0, 0, 0, 0] +``` + +This is more useful when we tokenize several sentences together. For instance, this: + +```py +sentences = [ + "This sentence is not too long but we are going to split it anyway.", + "This sentence is shorter but will still get split.", +] +inputs = tokenizer( + sentences, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 +) + +print(inputs["overflow_to_sample_mapping"]) +``` + +gets us: + +```python out +[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] +``` + +which means the first sentence is split into 7 chunks as before, and the next 4 chunks come from the second sentence. + +Now let's go back to our long context. By default the `question-answering` pipeline uses a maximum length of 384, as we mentioned earlier, and a stride of 128, which correspond to the way the model was fine-tuned (you can adjust those parameters by passing `max_seq_len` and `stride` arguments when calling the pipeline). We will thus use those parameters when tokenizing. We'll also add padding (to have samples of the same length, so we can build tensors) as well as ask for the offsets: + +```py +inputs = tokenizer( + question, + long_context, + stride=128, + max_length=384, + padding="longest", + truncation="only_second", + return_overflowing_tokens=True, + return_offsets_mapping=True, +) +``` + +Those `inputs` will contain the input IDs and attention masks the model expects, as well as the offsets and the `overflow_to_sample_mapping` we just talked about. Since those two are not parameters used by the model, we'll pop them out of the `inputs` (and we won't store the map, since it's not useful here) before converting it to a tensor: + +{#if fw === 'pt'} + +```py +_ = inputs.pop("overflow_to_sample_mapping") +offsets = inputs.pop("offset_mapping") + +inputs = inputs.convert_to_tensors("pt") +print(inputs["input_ids"].shape) +``` + +```python out +torch.Size([2, 384]) +``` + +{:else} + +```py +_ = inputs.pop("overflow_to_sample_mapping") +offsets = inputs.pop("offset_mapping") + +inputs = inputs.convert_to_tensors("tf") +print(inputs["input_ids"].shape) +``` + +```python out +(2, 384) +``` + +{/if} + +Our long context was split in two, which means that after it goes through our model, we will have two sets of start and end logits: + +```py +outputs = model(**inputs) + +start_logits = outputs.start_logits +end_logits = outputs.end_logits +print(start_logits.shape, end_logits.shape) +``` + +{#if fw === 'pt'} + +```python out +torch.Size([2, 384]) torch.Size([2, 384]) +``` + +{:else} + +```python out +(2, 384) (2, 384) +``` + +{/if} + +Like before, we first mask the tokens that are not part of the context before taking the softmax. We also mask all the padding tokens (as flagged by the attention mask): + +{#if fw === 'pt'} + +```py +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +# Mask all the [PAD] tokens +mask = torch.logical_or(torch.tensor(mask)[None], (inputs["attention_mask"] == 0)) + +start_logits[mask] = -10000 +end_logits[mask] = -10000 +``` + +{:else} + +```py +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +# Mask all the [PAD] tokens +mask = tf.math.logical_or(tf.constant(mask)[None], inputs["attention_mask"] == 0) + +start_logits = tf.where(mask, -10000, start_logits) +end_logits = tf.where(mask, -10000, end_logits) +``` + +{/if} + +Then we can use the softmax to convert our logits to probabilities: + +{#if fw === 'pt'} + +```py +start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1) +end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1) +``` + +{:else} + +```py +start_probabilities = tf.math.softmax(start_logits, axis=-1).numpy() +end_probabilities = tf.math.softmax(end_logits, axis=-1).numpy() +``` + +{/if} + +The next step is similar to what we did for the small context, but we repeat it for each of our two chunks. We attribute a score to all possible spans of answer, then take the span with the best score: + +{#if fw === 'pt'} + +```py +candidates = [] +for start_probs, end_probs in zip(start_probabilities, end_probabilities): + scores = start_probs[:, None] * end_probs[None, :] + idx = torch.triu(scores).argmax().item() + + start_idx = idx // scores.shape[1] + end_idx = idx % scores.shape[1] + score = scores[start_idx, end_idx].item() + candidates.append((start_idx, end_idx, score)) + +print(candidates) +``` + +{:else} + +```py +candidates = [] +for start_probs, end_probs in zip(start_probabilities, end_probabilities): + scores = start_probs[:, None] * end_probs[None, :] + idx = np.triu(scores).argmax().item() + + start_idx = idx // scores.shape[1] + end_idx = idx % scores.shape[1] + score = scores[start_idx, end_idx].item() + candidates.append((start_idx, end_idx, score)) + +print(candidates) +``` + +{/if} + +```python out +[(0, 18, 0.33867), (173, 184, 0.97149)] +``` + +Those two candidates correspond to the best answers the model was able to find in each chunk. The model is way more confident the right answer is in the second part (which is a good sign!). Now we just have to map those two token spans to spans of characters in the context (we only need to map the second one to have our answer, but it's interesting to see what the model has picked in the first chunk). + + + +✏️ **Try it out!** Adapt the code above to return the scores and spans for the five most likely answers (in total, not per chunk). + + + +The `offsets` we grabbed earlier is actually a list of offsets, with one list per chunk of text: + +```py +for candidate, offset in zip(candidates, offsets): + start_token, end_token, score = candidate + start_char, _ = offset[start_token] + _, end_char = offset[end_token] + answer = long_context[start_char:end_char] + result = {"answer": answer, "start": start_char, "end": end_char, "score": score} + print(result) +``` + +```python out +{'answer': '\n🤗 Transformers: State of the Art NLP', 'start': 0, 'end': 37, 'score': 0.33867} +{'answer': 'Jax, PyTorch and TensorFlow', 'start': 1892, 'end': 1919, 'score': 0.97149} +``` + +If we ignore the first result, we get the same result as our pipeline for this long context -- yay! + + + +✏️ **Try it out!** Use the best scores you computed before to show the five most likely answers (for the whole context, not each chunk). To check your results, go back to the first pipeline and pass in `top_k=5` when calling it. + + + +This concludes our deep dive into the tokenizer's capabilities. We will put all of this in practice again in the next chapter, when we show you how to fine-tune a model on a range of common NLP tasks. diff --git a/chapters/ru/chapter6/4.mdx b/chapters/ru/chapter6/4.mdx new file mode 100644 index 000000000..a53611a60 --- /dev/null +++ b/chapters/ru/chapter6/4.mdx @@ -0,0 +1,123 @@ +# Normalization and pre-tokenization[[normalization-and-pre-tokenization]] + + + +Before we dive more deeply into the three most common subword tokenization algorithms used with Transformer models (Byte-Pair Encoding [BPE], WordPiece, and Unigram), we'll first take a look at the preprocessing that each tokenizer applies to text. Here's a high-level overview of the steps in the tokenization pipeline: + +
+The tokenization pipeline. + +
+ +Before splitting a text into subtokens (according to its model), the tokenizer performs two steps: _normalization_ and _pre-tokenization_. + +## Normalization[[normalization]] + + + +The normalization step involves some general cleanup, such as removing needless whitespace, lowercasing, and/or removing accents. If you're familiar with [Unicode normalization](http://www.unicode.org/reports/tr15/) (such as NFC or NFKC), this is also something the tokenizer may apply. + +The 🤗 Transformers `tokenizer` has an attribute called `backend_tokenizer` that provides access to the underlying tokenizer from the 🤗 Tokenizers library: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") +print(type(tokenizer.backend_tokenizer)) +``` + +```python out + +``` + +The `normalizer` attribute of the `tokenizer` object has a `normalize_str()` method that we can use to see how the normalization is performed: + +```py +print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +'hello how are u?' +``` + +In this example, since we picked the `bert-base-uncased` checkpoint, the normalization applied lowercasing and removed the accents. + + + +✏️ **Try it out!** Load a tokenizer from the `bert-base-cased` checkpoint and pass the same example to it. What are the main differences you can see between the cased and uncased versions of the tokenizer? + + + +## Pre-tokenization[[pre-tokenization]] + + + +As we will see in the next sections, a tokenizer cannot be trained on raw text alone. Instead, we first need to split the texts into small entities, like words. That's where the pre-tokenization step comes in. As we saw in [Chapter 2](/course/chapter2), a word-based tokenizer can simply split a raw text into words on whitespace and punctuation. Those words will be the boundaries of the subtokens the tokenizer can learn during its training. + +To see how a fast tokenizer performs pre-tokenization, we can use the `pre_tokenize_str()` method of the `pre_tokenizer` attribute of the `tokenizer` object: + +```py +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +```python out +[('Hello', (0, 5)), (',', (5, 6)), ('how', (7, 10)), ('are', (11, 14)), ('you', (16, 19)), ('?', (19, 20))] +``` + +Notice how the tokenizer is already keeping track of the offsets, which is how it can give us the offset mapping we used in the previous section. Here the tokenizer ignores the two spaces and replaces them with just one, but the offset jumps between `are` and `you` to account for that. + +Since we're using a BERT tokenizer, the pre-tokenization involves splitting on whitespace and punctuation. Other tokenizers can have different rules for this step. For example, if we use the GPT-2 tokenizer: + +```py +tokenizer = AutoTokenizer.from_pretrained("gpt2") +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +it will split on whitespace and punctuation as well, but it will keep the spaces and replace them with a `Ġ` symbol, enabling it to recover the original spaces if we decode the tokens: + +```python out +[('Hello', (0, 5)), (',', (5, 6)), ('Ġhow', (6, 10)), ('Ġare', (10, 14)), ('Ġ', (14, 15)), ('Ġyou', (15, 19)), + ('?', (19, 20))] +``` + +Also note that unlike the BERT tokenizer, this tokenizer does not ignore the double space. + +For a last example, let's have a look at the T5 tokenizer, which is based on the SentencePiece algorithm: + +```py +tokenizer = AutoTokenizer.from_pretrained("t5-small") +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +```python out +[('▁Hello,', (0, 6)), ('▁how', (7, 10)), ('▁are', (11, 14)), ('▁you?', (16, 20))] +``` + +Like the GPT-2 tokenizer, this one keeps spaces and replaces them with a specific token (`_`), but the T5 tokenizer only splits on whitespace, not punctuation. Also note that it added a space by default at the beginning of the sentence (before `Hello`) and ignored the double space between `are` and `you`. + +Now that we've seen a little of how some different tokenizers process text, we can start to explore the underlying algorithms themselves. We'll begin with a quick look at the broadly widely applicable SentencePiece; then, over the next three sections, we'll examine how the three main algorithms used for subword tokenization work. + +## SentencePiece[[sentencepiece]] + +[SentencePiece](https://github.com/google/sentencepiece) is a tokenization algorithm for the preprocessing of text that you can use with any of the models we will see in the next three sections. It considers the text as a sequence of Unicode characters, and replaces spaces with a special character, `▁`. Used in conjunction with the Unigram algorithm (see [section 7](/course/chapter7/7)), it doesn't even require a pre-tokenization step, which is very useful for languages where the space character is not used (like Chinese or Japanese). + +The other main feature of SentencePiece is *reversible tokenization*: since there is no special treatment of spaces, decoding the tokens is done simply by concatenating them and replacing the `_`s with spaces -- this results in the normalized text. As we saw earlier, the BERT tokenizer removes repeating spaces, so its tokenization is not reversible. + +## Algorithm overview[[algorithm-overview]] + +In the following sections, we'll dive into the three main subword tokenization algorithms: BPE (used by GPT-2 and others), WordPiece (used for example by BERT), and Unigram (used by T5 and others). Before we get started, here's a quick overview of how they each work. Don't hesitate to come back to this table after reading each of the next sections if it doesn't make sense to you yet. + + +Model | BPE | WordPiece | Unigram +:----:|:---:|:---------:|:------: +Training | Starts from a small vocabulary and learns rules to merge tokens | Starts from a small vocabulary and learns rules to merge tokens | Starts from a large vocabulary and learns rules to remove tokens +Training step | Merges the tokens corresponding to the most common pair | Merges the tokens corresponding to the pair with the best score based on the frequency of the pair, privileging pairs where each individual token is less frequent | Removes all the tokens in the vocabulary that will minimize the loss computed on the whole corpus +Learns | Merge rules and a vocabulary | Just a vocabulary | A vocabulary with a score for each token +Encoding | Splits a word into characters and applies the merges learned during training | Finds the longest subword starting from the beginning that is in the vocabulary, then does the same for the rest of the word | Finds the most likely split into tokens, using the scores learned during training + +Now let's dive into BPE! \ No newline at end of file diff --git a/chapters/ru/chapter6/5.mdx b/chapters/ru/chapter6/5.mdx new file mode 100644 index 000000000..e877653ef --- /dev/null +++ b/chapters/ru/chapter6/5.mdx @@ -0,0 +1,360 @@ +# Byte-Pair Encoding tokenization[[byte-pair-encoding-tokenization]] + + + +Byte-Pair Encoding (BPE) was initially developed as an algorithm to compress texts, and then used by OpenAI for tokenization when pretraining the GPT model. It's used by a lot of Transformer models, including GPT, GPT-2, RoBERTa, BART, and DeBERTa. + + + + + +💡 This section covers BPE in depth, going as far as showing a full implementation. You can skip to the end if you just want a general overview of the tokenization algorithm. + + + +## Training algorithm[[training-algorithm]] + +BPE training starts by computing the unique set of words used in the corpus (after the normalization and pre-tokenization steps are completed), then building the vocabulary by taking all the symbols used to write those words. As a very simple example, let's say our corpus uses these five words: + +``` +"hug", "pug", "pun", "bun", "hugs" +``` + +The base vocabulary will then be `["b", "g", "h", "n", "p", "s", "u"]`. For real-world cases, that base vocabulary will contain all the ASCII characters, at the very least, and probably some Unicode characters as well. If an example you are tokenizing uses a character that is not in the training corpus, that character will be converted to the unknown token. That's one reason why lots of NLP models are very bad at analyzing content with emojis, for instance. + + + +The GPT-2 and RoBERTa tokenizers (which are pretty similar) have a clever way to deal with this: they don't look at words as being written with Unicode characters, but with bytes. This way the base vocabulary has a small size (256), but every character you can think of will still be included and not end up being converted to the unknown token. This trick is called *byte-level BPE*. + + + +After getting this base vocabulary, we add new tokens until the desired vocabulary size is reached by learning *merges*, which are rules to merge two elements of the existing vocabulary together into a new one. So, at the beginning these merges will create tokens with two characters, and then, as training progresses, longer subwords. + +At any step during the tokenizer training, the BPE algorithm will search for the most frequent pair of existing tokens (by "pair," here we mean two consecutive tokens in a word). That most frequent pair is the one that will be merged, and we rinse and repeat for the next step. + +Going back to our previous example, let's assume the words had the following frequencies: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +meaning `"hug"` was present 10 times in the corpus, `"pug"` 5 times, `"pun"` 12 times, `"bun"` 4 times, and `"hugs"` 5 times. We start the training by splitting each word into characters (the ones that form our initial vocabulary) so we can see each word as a list of tokens: + +``` +("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5) +``` + +Then we look at pairs. The pair `("h", "u")` is present in the words `"hug"` and `"hugs"`, so 15 times total in the corpus. It's not the most frequent pair, though: that honor belongs to `("u", "g")`, which is present in `"hug"`, `"pug"`, and `"hugs"`, for a grand total of 20 times in the vocabulary. + +Thus, the first merge rule learned by the tokenizer is `("u", "g") -> "ug"`, which means that `"ug"` will be added to the vocabulary, and the pair should be merged in all the words of the corpus. At the end of this stage, the vocabulary and corpus look like this: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug"] +Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5) +``` + +Now we have some pairs that result in a token longer than two characters: the pair `("h", "ug")`, for instance (present 15 times in the corpus). The most frequent pair at this stage is `("u", "n")`, however, present 16 times in the corpus, so the second merge rule learned is `("u", "n") -> "un"`. Adding that to the vocabulary and merging all existing occurrences leads us to: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un"] +Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("h" "ug" "s", 5) +``` + +Now the most frequent pair is `("h", "ug")`, so we learn the merge rule `("h", "ug") -> "hug"`, which gives us our first three-letter token. After the merge, the corpus looks like this: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"] +Corpus: ("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5) +``` + +And we continue like this until we reach the desired vocabulary size. + + + +✏️ **Now your turn!** What do you think the next merge rule will be? + + + +## Tokenization algorithm[[tokenization-algorithm]] + +Tokenization follows the training process closely, in the sense that new inputs are tokenized by applying the following steps: + +1. Normalization +2. Pre-tokenization +3. Splitting the words into individual characters +4. Applying the merge rules learned in order on those splits + +Let's take the example we used during training, with the three merge rules learned: + +``` +("u", "g") -> "ug" +("u", "n") -> "un" +("h", "ug") -> "hug" +``` + +The word `"bug"` will be tokenized as `["b", "ug"]`. `"mug"`, however, will be tokenized as `["[UNK]", "ug"]` since the letter `"m"` was not in the base vocabulary. Likewise, the word `"thug"` will be tokenized as `["[UNK]", "hug"]`: the letter `"t"` is not in the base vocabulary, and applying the merge rules results first in `"u"` and `"g"` being merged and then `"h"` and `"ug"` being merged. + + + +✏️ **Now your turn!** How do you think the word `"unhug"` will be tokenized? + + + +## Implementing BPE[[implementing-bpe]] + +Now let's take a look at an implementation of the BPE algorithm. This won't be an optimized version you can actually use on a big corpus; we just want to show you the code so you can understand the algorithm a little bit better. + +First we need a corpus, so let's create a simple one with a few sentences: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +Next, we need to pre-tokenize that corpus into words. Since we are replicating a BPE tokenizer (like GPT-2), we will use the `gpt2` tokenizer for the pre-tokenization: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("gpt2") +``` + +Then we compute the frequencies of each word in the corpus as we do the pre-tokenization: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) + +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +print(word_freqs) +``` + +```python out +defaultdict(int, {'This': 3, 'Ġis': 2, 'Ġthe': 1, 'ĠHugging': 1, 'ĠFace': 1, 'ĠCourse': 1, '.': 4, 'Ġchapter': 1, + 'Ġabout': 1, 'Ġtokenization': 1, 'Ġsection': 1, 'Ġshows': 1, 'Ġseveral': 1, 'Ġtokenizer': 1, 'Ġalgorithms': 1, + 'Hopefully': 1, ',': 1, 'Ġyou': 1, 'Ġwill': 1, 'Ġbe': 1, 'Ġable': 1, 'Ġto': 1, 'Ġunderstand': 1, 'Ġhow': 1, + 'Ġthey': 1, 'Ġare': 1, 'Ġtrained': 1, 'Ġand': 1, 'Ġgenerate': 1, 'Ġtokens': 1}) +``` + +The next step is to compute the base vocabulary, formed by all the characters used in the corpus: + +```python +alphabet = [] + +for word in word_freqs.keys(): + for letter in word: + if letter not in alphabet: + alphabet.append(letter) +alphabet.sort() + +print(alphabet) +``` + +```python out +[ ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', + 't', 'u', 'v', 'w', 'y', 'z', 'Ġ'] +``` + +We also add the special tokens used by the model at the beginning of that vocabulary. In the case of GPT-2, the only special token is `"<|endoftext|>"`: + +```python +vocab = ["<|endoftext|>"] + alphabet.copy() +``` + +We now need to split each word into individual characters, to be able to start training: + +```python +splits = {word: [c for c in word] for word in word_freqs.keys()} +``` + +Now that we are ready for training, let's write a function that computes the frequency of each pair. We'll need to use this at each step of the training: + +```python +def compute_pair_freqs(splits): + pair_freqs = defaultdict(int) + for word, freq in word_freqs.items(): + split = splits[word] + if len(split) == 1: + continue + for i in range(len(split) - 1): + pair = (split[i], split[i + 1]) + pair_freqs[pair] += freq + return pair_freqs +``` + +Let's have a look at a part of this dictionary after the initial splits: + +```python +pair_freqs = compute_pair_freqs(splits) + +for i, key in enumerate(pair_freqs.keys()): + print(f"{key}: {pair_freqs[key]}") + if i >= 5: + break +``` + +```python out +('T', 'h'): 3 +('h', 'i'): 3 +('i', 's'): 5 +('Ġ', 'i'): 2 +('Ġ', 't'): 7 +('t', 'h'): 3 +``` + +Now, finding the most frequent pair only takes a quick loop: + +```python +best_pair = "" +max_freq = None + +for pair, freq in pair_freqs.items(): + if max_freq is None or max_freq < freq: + best_pair = pair + max_freq = freq + +print(best_pair, max_freq) +``` + +```python out +('Ġ', 't') 7 +``` + +So the first merge to learn is `('Ġ', 't') -> 'Ġt'`, and we add `'Ġt'` to the vocabulary: + +```python +merges = {("Ġ", "t"): "Ġt"} +vocab.append("Ġt") +``` + +To continue, we need to apply that merge in our `splits` dictionary. Let's write another function for this: + +```python +def merge_pair(a, b, splits): + for word in word_freqs: + split = splits[word] + if len(split) == 1: + continue + + i = 0 + while i < len(split) - 1: + if split[i] == a and split[i + 1] == b: + split = split[:i] + [a + b] + split[i + 2 :] + else: + i += 1 + splits[word] = split + return splits +``` + +And we can have a look at the result of the first merge: + +```py +splits = merge_pair("Ġ", "t", splits) +print(splits["Ġtrained"]) +``` + +```python out +['Ġt', 'r', 'a', 'i', 'n', 'e', 'd'] +``` + +Now we have everything we need to loop until we have learned all the merges we want. Let's aim for a vocab size of 50: + +```python +vocab_size = 50 + +while len(vocab) < vocab_size: + pair_freqs = compute_pair_freqs(splits) + best_pair = "" + max_freq = None + for pair, freq in pair_freqs.items(): + if max_freq is None or max_freq < freq: + best_pair = pair + max_freq = freq + splits = merge_pair(*best_pair, splits) + merges[best_pair] = best_pair[0] + best_pair[1] + vocab.append(best_pair[0] + best_pair[1]) +``` + +As a result, we've learned 19 merge rules (the initial vocabulary had a size of 31 -- 30 characters in the alphabet, plus the special token): + +```py +print(merges) +``` + +```python out +{('Ġ', 't'): 'Ġt', ('i', 's'): 'is', ('e', 'r'): 'er', ('Ġ', 'a'): 'Ġa', ('Ġt', 'o'): 'Ġto', ('e', 'n'): 'en', + ('T', 'h'): 'Th', ('Th', 'is'): 'This', ('o', 'u'): 'ou', ('s', 'e'): 'se', ('Ġto', 'k'): 'Ġtok', + ('Ġtok', 'en'): 'Ġtoken', ('n', 'd'): 'nd', ('Ġ', 'is'): 'Ġis', ('Ġt', 'h'): 'Ġth', ('Ġth', 'e'): 'Ġthe', + ('i', 'n'): 'in', ('Ġa', 'b'): 'Ġab', ('Ġtoken', 'i'): 'Ġtokeni'} +``` + +And the vocabulary is composed of the special token, the initial alphabet, and all the results of the merges: + +```py +print(vocab) +``` + +```python out +['<|endoftext|>', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', + 'p', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z', 'Ġ', 'Ġt', 'is', 'er', 'Ġa', 'Ġto', 'en', 'Th', 'This', 'ou', 'se', + 'Ġtok', 'Ġtoken', 'nd', 'Ġis', 'Ġth', 'Ġthe', 'in', 'Ġab', 'Ġtokeni'] +``` + + + +💡 Using `train_new_from_iterator()` on the same corpus won't result in the exact same vocabulary. This is because when there is a choice of the most frequent pair, we selected the first one encountered, while the 🤗 Tokenizers library selects the first one based on its inner IDs. + + + +To tokenize a new text, we pre-tokenize it, split it, then apply all the merge rules learned: + +```python +def tokenize(text): + pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in pre_tokenize_result] + splits = [[l for l in word] for word in pre_tokenized_text] + for pair, merge in merges.items(): + for idx, split in enumerate(splits): + i = 0 + while i < len(split) - 1: + if split[i] == pair[0] and split[i + 1] == pair[1]: + split = split[:i] + [merge] + split[i + 2 :] + else: + i += 1 + splits[idx] = split + + return sum(splits, []) +``` + +We can try this on any text composed of characters in the alphabet: + +```py +tokenize("This is not a token.") +``` + +```python out +['This', 'Ġis', 'Ġ', 'n', 'o', 't', 'Ġa', 'Ġtoken', '.'] +``` + + + +⚠️ Our implementation will throw an error if there is an unknown character since we didn't do anything to handle them. GPT-2 doesn't actually have an unknown token (it's impossible to get an unknown character when using byte-level BPE), but this could happen here because we did not include all the possible bytes in the initial vocabulary. This aspect of BPE is beyond the scope of this section, so we've left the details out. + + + +That's it for the BPE algorithm! Next, we'll have a look at WordPiece. \ No newline at end of file diff --git a/chapters/ru/chapter6/6.mdx b/chapters/ru/chapter6/6.mdx new file mode 100644 index 000000000..eb0cbddeb --- /dev/null +++ b/chapters/ru/chapter6/6.mdx @@ -0,0 +1,374 @@ +# WordPiece tokenization[[wordpiece-tokenization]] + + + +WordPiece is the tokenization algorithm Google developed to pretrain BERT. It has since been reused in quite a few Transformer models based on BERT, such as DistilBERT, MobileBERT, Funnel Transformers, and MPNET. It's very similar to BPE in terms of the training, but the actual tokenization is done differently. + + + + + +💡 This section covers WordPiece in depth, going as far as showing a full implementation. You can skip to the end if you just want a general overview of the tokenization algorithm. + + + +## Training algorithm[[training-algorithm]] + + + +⚠️ Google never open-sourced its implementation of the training algorithm of WordPiece, so what follows is our best guess based on the published literature. It may not be 100% accurate. + + + +Like BPE, WordPiece starts from a small vocabulary including the special tokens used by the model and the initial alphabet. Since it identifies subwords by adding a prefix (like `##` for BERT), each word is initially split by adding that prefix to all the characters inside the word. So, for instance, `"word"` gets split like this: + +``` +w ##o ##r ##d +``` + +Thus, the initial alphabet contains all the characters present at the beginning of a word and the characters present inside a word preceded by the WordPiece prefix. + +Then, again like BPE, WordPiece learns merge rules. The main difference is the way the pair to be merged is selected. Instead of selecting the most frequent pair, WordPiece computes a score for each pair, using the following formula: + +$$\mathrm{score} = (\mathrm{freq\_of\_pair}) / (\mathrm{freq\_of\_first\_element} \times \mathrm{freq\_of\_second\_element})$$ + +By dividing the frequency of the pair by the product of the frequencies of each of its parts, the algorithm prioritizes the merging of pairs where the individual parts are less frequent in the vocabulary. For instance, it won't necessarily merge `("un", "##able")` even if that pair occurs very frequently in the vocabulary, because the two pairs `"un"` and `"##able"` will likely each appear in a lot of other words and have a high frequency. In contrast, a pair like `("hu", "##gging")` will probably be merged faster (assuming the word "hugging" appears often in the vocabulary) since `"hu"` and `"##gging"` are likely to be less frequent individually. + +Let's look at the same vocabulary we used in the BPE training example: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +The splits here will be: + +``` +("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##g" "##s", 5) +``` + +so the initial vocabulary will be `["b", "h", "p", "##g", "##n", "##s", "##u"]` (if we forget about special tokens for now). The most frequent pair is `("##u", "##g")` (present 20 times), but the individual frequency of `"##u"` is very high, so its score is not the highest (it's 1 / 36). All pairs with a `"##u"` actually have that same score (1 / 36), so the best score goes to the pair `("##g", "##s")` -- the only one without a `"##u"` -- at 1 / 20, and the first merge learned is `("##g", "##s") -> ("##gs")`. + +Note that when we merge, we remove the `##` between the two tokens, so we add `"##gs"` to the vocabulary and apply the merge in the words of the corpus: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"] +Corpus: ("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##gs", 5) +``` + +At this point, `"##u"` is in all the possible pairs, so they all end up with the same score. Let's say that in this case, the first pair is merged, so `("h", "##u") -> "hu"`. This takes us to: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu"] +Corpus: ("hu" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) +``` + +Then the next best score is shared by `("hu", "##g")` and `("hu", "##gs")` (with 1/15, compared to 1/21 for all the other pairs), so the first pair with the biggest score is merged: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu", "hug"] +Corpus: ("hug", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) +``` + +and we continue like this until we reach the desired vocabulary size. + + + +✏️ **Now your turn!** What will the next merge rule be? + + + +## Tokenization algorithm[[tokenization-algorithm]] + +Tokenization differs in WordPiece and BPE in that WordPiece only saves the final vocabulary, not the merge rules learned. Starting from the word to tokenize, WordPiece finds the longest subword that is in the vocabulary, then splits on it. For instance, if we use the vocabulary learned in the example above, for the word `"hugs"` the longest subword starting from the beginning that is inside the vocabulary is `"hug"`, so we split there and get `["hug", "##s"]`. We then continue with `"##s"`, which is in the vocabulary, so the tokenization of `"hugs"` is `["hug", "##s"]`. + +With BPE, we would have applied the merges learned in order and tokenized this as `["hu", "##gs"]`, so the encoding is different. + +As another example, let's see how the word `"bugs"` would be tokenized. `"b"` is the longest subword starting at the beginning of the word that is in the vocabulary, so we split there and get `["b", "##ugs"]`. Then `"##u"` is the longest subword starting at the beginning of `"##ugs"` that is in the vocabulary, so we split there and get `["b", "##u, "##gs"]`. Finally, `"##gs"` is in the vocabulary, so this last list is the tokenization of `"bugs"`. + +When the tokenization gets to a stage where it's not possible to find a subword in the vocabulary, the whole word is tokenized as unknown -- so, for instance, `"mug"` would be tokenized as `["[UNK]"]`, as would `"bum"` (even if we can begin with `"b"` and `"##u"`, `"##m"` is not the vocabulary, and the resulting tokenization will just be `["[UNK]"]`, not `["b", "##u", "[UNK]"]`). This is another difference from BPE, which would only classify the individual characters not in the vocabulary as unknown. + + + +✏️ **Now your turn!** How will the word `"pugs"` be tokenized? + + + +## Implementing WordPiece[[implementing-wordpiece]] + +Now let's take a look at an implementation of the WordPiece algorithm. Like with BPE, this is just pedagogical, and you won't able to use this on a big corpus. + +We will use the same corpus as in the BPE example: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +First, we need to pre-tokenize the corpus into words. Since we are replicating a WordPiece tokenizer (like BERT), we will use the `bert-base-cased` tokenizer for the pre-tokenization: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Then we compute the frequencies of each word in the corpus as we do the pre-tokenization: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +word_freqs +``` + +```python out +defaultdict( + int, {'This': 3, 'is': 2, 'the': 1, 'Hugging': 1, 'Face': 1, 'Course': 1, '.': 4, 'chapter': 1, 'about': 1, + 'tokenization': 1, 'section': 1, 'shows': 1, 'several': 1, 'tokenizer': 1, 'algorithms': 1, 'Hopefully': 1, + ',': 1, 'you': 1, 'will': 1, 'be': 1, 'able': 1, 'to': 1, 'understand': 1, 'how': 1, 'they': 1, 'are': 1, + 'trained': 1, 'and': 1, 'generate': 1, 'tokens': 1}) +``` + +As we saw before, the alphabet is the unique set composed of all the first letters of words, and all the other letters that appear in words prefixed by `##`: + +```python +alphabet = [] +for word in word_freqs.keys(): + if word[0] not in alphabet: + alphabet.append(word[0]) + for letter in word[1:]: + if f"##{letter}" not in alphabet: + alphabet.append(f"##{letter}") + +alphabet.sort() +alphabet + +print(alphabet) +``` + +```python out +['##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', '##l', '##m', '##n', '##o', '##p', '##r', '##s', + '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', + 'w', 'y'] +``` + +We also add the special tokens used by the model at the beginning of that vocabulary. In the case of BERT, it's the list `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]`: + +```python +vocab = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] + alphabet.copy() +``` + +Next we need to split each word, with all the letters that are not the first prefixed by `##`: + +```python +splits = { + word: [c if i == 0 else f"##{c}" for i, c in enumerate(word)] + for word in word_freqs.keys() +} +``` + +Now that we are ready for training, let's write a function that computes the score of each pair. We'll need to use this at each step of the training: + +```python +def compute_pair_scores(splits): + letter_freqs = defaultdict(int) + pair_freqs = defaultdict(int) + for word, freq in word_freqs.items(): + split = splits[word] + if len(split) == 1: + letter_freqs[split[0]] += freq + continue + for i in range(len(split) - 1): + pair = (split[i], split[i + 1]) + letter_freqs[split[i]] += freq + pair_freqs[pair] += freq + letter_freqs[split[-1]] += freq + + scores = { + pair: freq / (letter_freqs[pair[0]] * letter_freqs[pair[1]]) + for pair, freq in pair_freqs.items() + } + return scores +``` + +Let's have a look at a part of this dictionary after the initial splits: + +```python +pair_scores = compute_pair_scores(splits) +for i, key in enumerate(pair_scores.keys()): + print(f"{key}: {pair_scores[key]}") + if i >= 5: + break +``` + +```python out +('T', '##h'): 0.125 +('##h', '##i'): 0.03409090909090909 +('##i', '##s'): 0.02727272727272727 +('i', '##s'): 0.1 +('t', '##h'): 0.03571428571428571 +('##h', '##e'): 0.011904761904761904 +``` + +Now, finding the pair with the best score only takes a quick loop: + +```python +best_pair = "" +max_score = None +for pair, score in pair_scores.items(): + if max_score is None or max_score < score: + best_pair = pair + max_score = score + +print(best_pair, max_score) +``` + +```python out +('a', '##b') 0.2 +``` + +So the first merge to learn is `('a', '##b') -> 'ab'`, and we add `'ab'` to the vocabulary: + +```python +vocab.append("ab") +``` + +To continue, we need to apply that merge in our `splits` dictionary. Let's write another function for this: + +```python +def merge_pair(a, b, splits): + for word in word_freqs: + split = splits[word] + if len(split) == 1: + continue + i = 0 + while i < len(split) - 1: + if split[i] == a and split[i + 1] == b: + merge = a + b[2:] if b.startswith("##") else a + b + split = split[:i] + [merge] + split[i + 2 :] + else: + i += 1 + splits[word] = split + return splits +``` + +And we can have a look at the result of the first merge: + +```py +splits = merge_pair("a", "##b", splits) +splits["about"] +``` + +```python out +['ab', '##o', '##u', '##t'] +``` + +Now we have everything we need to loop until we have learned all the merges we want. Let's aim for a vocab size of 70: + +```python +vocab_size = 70 +while len(vocab) < vocab_size: + scores = compute_pair_scores(splits) + best_pair, max_score = "", None + for pair, score in scores.items(): + if max_score is None or max_score < score: + best_pair = pair + max_score = score + splits = merge_pair(*best_pair, splits) + new_token = ( + best_pair[0] + best_pair[1][2:] + if best_pair[1].startswith("##") + else best_pair[0] + best_pair[1] + ) + vocab.append(new_token) +``` + +We can then look at the generated vocabulary: + +```py +print(vocab) +``` + +```python out +['[PAD]', '[UNK]', '[CLS]', '[SEP]', '[MASK]', '##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', + '##l', '##m', '##n', '##o', '##p', '##r', '##s', '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', + 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', 'w', 'y', 'ab', '##fu', 'Fa', 'Fac', '##ct', '##ful', '##full', '##fully', + 'Th', 'ch', '##hm', 'cha', 'chap', 'chapt', '##thm', 'Hu', 'Hug', 'Hugg', 'sh', 'th', 'is', '##thms', '##za', '##zat', + '##ut'] +``` + +As we can see, compared to BPE, this tokenizer learns parts of words as tokens a bit faster. + + + +💡 Using `train_new_from_iterator()` on the same corpus won't result in the exact same vocabulary. This is because the 🤗 Tokenizers library does not implement WordPiece for the training (since we are not completely sure of its internals), but uses BPE instead. + + + +To tokenize a new text, we pre-tokenize it, split it, then apply the tokenization algorithm on each word. That is, we look for the biggest subword starting at the beginning of the first word and split it, then we repeat the process on the second part, and so on for the rest of that word and the following words in the text: + +```python +def encode_word(word): + tokens = [] + while len(word) > 0: + i = len(word) + while i > 0 and word[:i] not in vocab: + i -= 1 + if i == 0: + return ["[UNK]"] + tokens.append(word[:i]) + word = word[i:] + if len(word) > 0: + word = f"##{word}" + return tokens +``` + +Let's test it on one word that's in the vocabulary, and another that isn't: + +```python +print(encode_word("Hugging")) +print(encode_word("HOgging")) +``` + +```python out +['Hugg', '##i', '##n', '##g'] +['[UNK]'] +``` + +Now, let's write a function that tokenizes a text: + +```python +def tokenize(text): + pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in pre_tokenize_result] + encoded_words = [encode_word(word) for word in pre_tokenized_text] + return sum(encoded_words, []) +``` + +We can try it on any text: + +```python +tokenize("This is the Hugging Face course!") +``` + +```python out +['Th', '##i', '##s', 'is', 'th', '##e', 'Hugg', '##i', '##n', '##g', 'Fac', '##e', 'c', '##o', '##u', '##r', '##s', + '##e', '[UNK]'] +``` + +That's it for the WordPiece algorithm! Now let's take a look at Unigram. diff --git a/chapters/ru/chapter6/7.mdx b/chapters/ru/chapter6/7.mdx new file mode 100644 index 000000000..505cf7588 --- /dev/null +++ b/chapters/ru/chapter6/7.mdx @@ -0,0 +1,381 @@ +# Unigram tokenization[[unigram-tokenization]] + + + +The Unigram algorithm is often used in SentencePiece, which is the tokenization algorithm used by models like AlBERT, T5, mBART, Big Bird, and XLNet. + + + + + +💡 This section covers Unigram in depth, going as far as showing a full implementation. You can skip to the end if you just want a general overview of the tokenization algorithm. + + + +## Training algorithm[[training-algorithm]] + +Compared to BPE and WordPiece, Unigram works in the other direction: it starts from a big vocabulary and removes tokens from it until it reaches the desired vocabulary size. There are several options to use to build that base vocabulary: we can take the most common substrings in pre-tokenized words, for instance, or apply BPE on the initial corpus with a large vocabulary size. + +At each step of the training, the Unigram algorithm computes a loss over the corpus given the current vocabulary. Then, for each symbol in the vocabulary, the algorithm computes how much the overall loss would increase if the symbol was removed, and looks for the symbols that would increase it the least. Those symbols have a lower effect on the overall loss over the corpus, so in a sense they are "less needed" and are the best candidates for removal. + +This is all a very costly operation, so we don't just remove the single symbol associated with the lowest loss increase, but the \\(p\\) (\\(p\\) being a hyperparameter you can control, usually 10 or 20) percent of the symbols associated with the lowest loss increase. This process is then repeated until the vocabulary has reached the desired size. + +Note that we never remove the base characters, to make sure any word can be tokenized. + +Now, this is still a bit vague: the main part of the algorithm is to compute a loss over the corpus and see how it changes when we remove some tokens from the vocabulary, but we haven't explained how to do this yet. This step relies on the tokenization algorithm of a Unigram model, so we'll dive into this next. + +We'll reuse the corpus from the previous examples: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +and for this example, we will take all strict substrings for the initial vocabulary : + +``` +["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"] +``` + +## Tokenization algorithm[[tokenization-algorithm]] + +A Unigram model is a type of language model that considers each token to be independent of the tokens before it. It's the simplest language model, in the sense that the probability of token X given the previous context is just the probability of token X. So, if we used a Unigram language model to generate text, we would always predict the most common token. + +The probability of a given token is its frequency (the number of times we find it) in the original corpus, divided by the sum of all frequencies of all tokens in the vocabulary (to make sure the probabilities sum up to 1). For instance, `"ug"` is present in `"hug"`, `"pug"`, and `"hugs"`, so it has a frequency of 20 in our corpus. + +Here are the frequencies of all the possible subwords in the vocabulary: + +``` +("h", 15) ("u", 36) ("g", 20) ("hu", 15) ("ug", 20) ("p", 17) ("pu", 17) ("n", 16) +("un", 16) ("b", 4) ("bu", 4) ("s", 5) ("hug", 15) ("gs", 5) ("ugs", 5) +``` + +So, the sum of all frequencies is 210, and the probability of the subword `"ug"` is thus 20/210. + + + +✏️ **Now your turn!** Write the code to compute the the frequencies above and double-check that the results shown are correct, as well as the total sum. + + + +Now, to tokenize a given word, we look at all the possible segmentations into tokens and compute the probability of each according to the Unigram model. Since all tokens are considered independent, this probability is just the product of the probability of each token. For instance, the tokenization `["p", "u", "g"]` of `"pug"` has the probability: + +$$P([``p", ``u", ``g"]) = P(``p") \times P(``u") \times P(``g") = \frac{5}{210} \times \frac{36}{210} \times \frac{20}{210} = 0.000389$$ + +Comparatively, the tokenization `["pu", "g"]` has the probability: + +$$P([``pu", ``g"]) = P(``pu") \times P(``g") = \frac{5}{210} \times \frac{20}{210} = 0.0022676$$ + +so that one is way more likely. In general, tokenizations with the least tokens possible will have the highest probability (because of that division by 210 repeated for each token), which corresponds to what we want intuitively: to split a word into the least number of tokens possible. + +The tokenization of a word with the Unigram model is then the tokenization with the highest probability. In the example of `"pug"`, here are the probabilities we would get for each possible segmentation: + +``` +["p", "u", "g"] : 0.000389 +["p", "ug"] : 0.0022676 +["pu", "g"] : 0.0022676 +``` + +So, `"pug"` would be tokenized as `["p", "ug"]` or `["pu", "g"]`, depending on which of those segmentations is encountered first (note that in a larger corpus, equality cases like this will be rare). + +In this case, it was easy to find all the possible segmentations and compute their probabilities, but in general it's going to be a bit harder. There is a classic algorithm used for this, called the *Viterbi algorithm*. Essentially, we can build a graph to detect the possible segmentations of a given word by saying there is a branch from character _a_ to character _b_ if the subword from _a_ to _b_ is in the vocabulary, and attribute to that branch the probability of the subword. + +To find the path in that graph that is going to have the best score the Viterbi algorithm determines, for each position in the word, the segmentation with the best score that ends at that position. Since we go from the beginning to the end, that best score can be found by looping through all subwords ending at the current position and then using the best tokenization score from the position this subword begins at. Then, we just have to unroll the path taken to arrive at the end. + +Let's take a look at an example using our vocabulary and the word `"unhug"`. For each position, the subwords with the best scores ending there are the following: + +``` +Character 0 (u): "u" (score 0.171429) +Character 1 (n): "un" (score 0.076191) +Character 2 (h): "un" "h" (score 0.005442) +Character 3 (u): "un" "hu" (score 0.005442) +Character 4 (g): "un" "hug" (score 0.005442) +``` + +Thus `"unhug"` would be tokenized as `["un", "hug"]`. + + + +✏️ **Now your turn!** Determine the tokenization of the word `"huggun"`, and its score. + + + +## Back to training[[back-to-training]] + +Now that we have seen how the tokenization works, we can dive a little more deeply into the loss used during training. At any given stage, this loss is computed by tokenizing every word in the corpus, using the current vocabulary and the Unigram model determined by the frequencies of each token in the corpus (as seen before). + +Each word in the corpus has a score, and the loss is the negative log likelihood of those scores -- that is, the sum for all the words in the corpus of all the `-log(P(word))`. + +Let's go back to our example with the following corpus: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +The tokenization of each word with their respective scores is: + +``` +"hug": ["hug"] (score 0.071428) +"pug": ["pu", "g"] (score 0.007710) +"pun": ["pu", "n"] (score 0.006168) +"bun": ["bu", "n"] (score 0.001451) +"hugs": ["hug", "s"] (score 0.001701) +``` + +So the loss is: + +``` +10 * (-log(0.071428)) + 5 * (-log(0.007710)) + 12 * (-log(0.006168)) + 4 * (-log(0.001451)) + 5 * (-log(0.001701)) = 169.8 +``` + +Now we need to compute how removing each token affects the loss. This is rather tedious, so we'll just do it for two tokens here and save the whole process for when we have code to help us. In this (very) particular case, we had two equivalent tokenizations of all the words: as we saw earlier, for example, `"pug"` could be tokenized `["p", "ug"]` with the same score. Thus, removing the `"pu"` token from the vocabulary will give the exact same loss. + +On the other hand, removing `"hug"` will make the loss worse, because the tokenization of `"hug"` and `"hugs"` will become: + +``` +"hug": ["hu", "g"] (score 0.006802) +"hugs": ["hu", "gs"] (score 0.001701) +``` + +These changes will cause the loss to rise by: + +``` +- 10 * (-log(0.071428)) + 10 * (-log(0.006802)) = 23.5 +``` + +Therefore, the token `"pu"` will probably be removed from the vocabulary, but not `"hug"`. + +## Implementing Unigram[[implementing-unigram]] + +Now let's implement everything we've seen so far in code. Like with BPE and WordPiece, this is not an efficient implementation of the Unigram algorithm (quite the opposite), but it should help you understand it a bit better. + +We will use the same corpus as before as an example: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +This time, we will use `xlnet-base-cased` as our model: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased") +``` + +Like for BPE and WordPiece, we begin by counting the number of occurrences of each word in the corpus: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +word_freqs +``` + +Then, we need to initialize our vocabulary to something larger than the vocab size we will want at the end. We have to include all the basic characters (otherwise we won't be able to tokenize every word), but for the bigger substrings we'll only keep the most common ones, so we sort them by frequency: + +```python +char_freqs = defaultdict(int) +subwords_freqs = defaultdict(int) +for word, freq in word_freqs.items(): + for i in range(len(word)): + char_freqs[word[i]] += freq + # Loop through the subwords of length at least 2 + for j in range(i + 2, len(word) + 1): + subwords_freqs[word[i:j]] += freq + +# Sort subwords by frequency +sorted_subwords = sorted(subwords_freqs.items(), key=lambda x: x[1], reverse=True) +sorted_subwords[:10] +``` + +```python out +[('▁t', 7), ('is', 5), ('er', 5), ('▁a', 5), ('▁to', 4), ('to', 4), ('en', 4), ('▁T', 3), ('▁Th', 3), ('▁Thi', 3)] +``` + +We group the characters with the best subwords to arrive at an initial vocabulary of size 300: + +```python +token_freqs = list(char_freqs.items()) + sorted_subwords[: 300 - len(char_freqs)] +token_freqs = {token: freq for token, freq in token_freqs} +``` + + + +💡 SentencePiece uses a more efficient algorithm called Enhanced Suffix Array (ESA) to create the initial vocabulary. + + + +Next, we compute the sum of all frequencies, to convert the frequencies into probabilities. For our model we will store the logarithms of the probabilities, because it's more numerically stable to add logarithms than to multiply small numbers, and this will simplify the computation of the loss of the model: + +```python +from math import log + +total_sum = sum([freq for token, freq in token_freqs.items()]) +model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} +``` + +Now the main function is the one that tokenizes words using the Viterbi algorithm. As we saw before, that algorithm computes the best segmentation of each substring of the word, which we will store in a variable named `best_segmentations`. We will store one dictionary per position in the word (from 0 to its total length), with two keys: the index of the start of the last token in the best segmentation, and the score of the best segmentation. With the index of the start of the last token, we will be able to retrieve the full segmentation once the list is completely populated. + +Populating the list is done with just two loops: the main loop goes over each start position, and the second loop tries all substrings beginning at that start position. If the substring is in the vocabulary, we have a new segmentation of the word up until that end position, which we compare to what is in `best_segmentations`. + +Once the main loop is finished, we just start from the end and hop from one start position to the next, recording the tokens as we go, until we reach the start of the word: + +```python +def encode_word(word, model): + best_segmentations = [{"start": 0, "score": 1}] + [ + {"start": None, "score": None} for _ in range(len(word)) + ] + for start_idx in range(len(word)): + # This should be properly filled by the previous steps of the loop + best_score_at_start = best_segmentations[start_idx]["score"] + for end_idx in range(start_idx + 1, len(word) + 1): + token = word[start_idx:end_idx] + if token in model and best_score_at_start is not None: + score = model[token] + best_score_at_start + # If we have found a better segmentation ending at end_idx, we update + if ( + best_segmentations[end_idx]["score"] is None + or best_segmentations[end_idx]["score"] > score + ): + best_segmentations[end_idx] = {"start": start_idx, "score": score} + + segmentation = best_segmentations[-1] + if segmentation["score"] is None: + # We did not find a tokenization of the word -> unknown + return [""], None + + score = segmentation["score"] + start = segmentation["start"] + end = len(word) + tokens = [] + while start != 0: + tokens.insert(0, word[start:end]) + next_start = best_segmentations[start]["start"] + end = start + start = next_start + tokens.insert(0, word[start:end]) + return tokens, score +``` + +We can already try our initial model on some words: + +```python +print(encode_word("Hopefully", model)) +print(encode_word("This", model)) +``` + +```python out +(['H', 'o', 'p', 'e', 'f', 'u', 'll', 'y'], 41.5157494601402) +(['This'], 6.288267030694535) +``` + +Now it's easy to compute the loss of the model on the corpus! + +```python +def compute_loss(model): + loss = 0 + for word, freq in word_freqs.items(): + _, word_loss = encode_word(word, model) + loss += freq * word_loss + return loss +``` + +We can check it works on the model we have: + +```python +compute_loss(model) +``` + +```python out +413.10377642940875 +``` + +Computing the scores for each token is not very hard either; we just have to compute the loss for the models obtained by deleting each token: + +```python +import copy + + +def compute_scores(model): + scores = {} + model_loss = compute_loss(model) + for token, score in model.items(): + # We always keep tokens of length 1 + if len(token) == 1: + continue + model_without_token = copy.deepcopy(model) + _ = model_without_token.pop(token) + scores[token] = compute_loss(model_without_token) - model_loss + return scores +``` + +We can try it on a given token: + +```python +scores = compute_scores(model) +print(scores["ll"]) +print(scores["his"]) +``` + +Since `"ll"` is used in the tokenization of `"Hopefully"`, and removing it will probably make us use the token `"l"` twice instead, we expect it will have a positive loss. `"his"` is only used inside the word `"This"`, which is tokenized as itself, so we expect it to have a zero loss. Here are the results: + +```python out +6.376412403623874 +0.0 +``` + + + +💡 This approach is very inefficient, so SentencePiece uses an approximation of the loss of the model without token X: instead of starting from scratch, it just replaces token X by its segmentation in the vocabulary that is left. This way, all the scores can be computed at once at the same time as the model loss. + + + +With all of this in place, the last thing we need to do is add the special tokens used by the model to the vocabulary, then loop until we have pruned enough tokens from the vocabulary to reach our desired size: + +```python +percent_to_remove = 0.1 +while len(model) > 100: + scores = compute_scores(model) + sorted_scores = sorted(scores.items(), key=lambda x: x[1]) + # Remove percent_to_remove tokens with the lowest scores. + for i in range(int(len(model) * percent_to_remove)): + _ = token_freqs.pop(sorted_scores[i][0]) + + total_sum = sum([freq for token, freq in token_freqs.items()]) + model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} +``` + +Then, to tokenize some text, we just need to apply the pre-tokenization and then use our `encode_word()` function: + +```python +def tokenize(text, model): + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in words_with_offsets] + encoded_words = [encode_word(word, model)[0] for word in pre_tokenized_text] + return sum(encoded_words, []) + + +tokenize("This is the Hugging Face course.", model) +``` + +```python out +['▁This', '▁is', '▁the', '▁Hugging', '▁Face', '▁', 'c', 'ou', 'r', 's', 'e', '.'] +``` + +That's it for Unigram! Hopefully by now you're feeling like an expert in all things tokenizer. In the next section, we will delve into the building blocks of the 🤗 Tokenizers library, and show you how you can use them to build your own tokenizer. diff --git a/chapters/ru/chapter6/8.mdx b/chapters/ru/chapter6/8.mdx new file mode 100644 index 000000000..7caee98ed --- /dev/null +++ b/chapters/ru/chapter6/8.mdx @@ -0,0 +1,565 @@ +# Building a tokenizer, block by block[[building-a-tokenizer-block-by-block]] + + + +As we've seen in the previous sections, tokenization comprises several steps: + +- Normalization (any cleanup of the text that is deemed necessary, such as removing spaces or accents, Unicode normalization, etc.) +- Pre-tokenization (splitting the input into words) +- Running the input through the model (using the pre-tokenized words to produce a sequence of tokens) +- Post-processing (adding the special tokens of the tokenizer, generating the attention mask and token type IDs) + +As a reminder, here's another look at the overall process: + +
+The tokenization pipeline. + +
+ +The 🤗 Tokenizers library has been built to provide several options for each of those steps, which you can mix and match together. In this section we'll see how we can build a tokenizer from scratch, as opposed to training a new tokenizer from an old one as we did in [section 2](/course/chapter6/2). You'll then be able to build any kind of tokenizer you can think of! + + + +More precisely, the library is built around a central `Tokenizer` class with the building blocks regrouped in submodules: + +- `normalizers` contains all the possible types of `Normalizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). +- `pre_tokenizers` contains all the possible types of `PreTokenizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). +- `models` contains the various types of `Model` you can use, like `BPE`, `WordPiece`, and `Unigram` (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). +- `trainers` contains all the different types of `Trainer` you can use to train your model on a corpus (one per type of model; complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). +- `post_processors` contains the various types of `PostProcessor` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). +- `decoders` contains the various types of `Decoder` you can use to decode the outputs of tokenization (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). + +You can find the whole list of building blocks [here](https://huggingface.co/docs/tokenizers/python/latest/components.html). + +## Acquiring a corpus[[acquiring-a-corpus]] + +To train our new tokenizer, we will use a small corpus of text (so the examples run fast). The steps for acquiring the corpus are similar to the ones we took at the [beginning of this chapter](/course/chapter6/2), but this time we'll use the [WikiText-2](https://huggingface.co/datasets/wikitext) dataset: + +```python +from datasets import load_dataset + +dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train") + + +def get_training_corpus(): + for i in range(0, len(dataset), 1000): + yield dataset[i : i + 1000]["text"] +``` + +The function `get_training_corpus()` is a generator that will yield batches of 1,000 texts, which we will use to train the tokenizer. + +🤗 Tokenizers can also be trained on text files directly. Here's how we can generate a text file containing all the texts/inputs from WikiText-2 that we can use locally: + +```python +with open("wikitext-2.txt", "w", encoding="utf-8") as f: + for i in range(len(dataset)): + f.write(dataset[i]["text"] + "\n") +``` + +Next we'll show you how to build your own BERT, GPT-2, and XLNet tokenizers, block by block. That will give us an example of each of the three main tokenization algorithms: WordPiece, BPE, and Unigram. Let's start with BERT! + +## Building a WordPiece tokenizer from scratch[[building-a-wordpiece-tokenizer-from-scratch]] + +To build a tokenizer with the 🤗 Tokenizers library, we start by instantiating a `Tokenizer` object with a `model`, then set its `normalizer`, `pre_tokenizer`, `post_processor`, and `decoder` attributes to the values we want. + +For this example, we'll create a `Tokenizer` with a WordPiece model: + +```python +from tokenizers import ( + decoders, + models, + normalizers, + pre_tokenizers, + processors, + trainers, + Tokenizer, +) + +tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) +``` + +We have to specify the `unk_token` so the model knows what to return when it encounters characters it hasn't seen before. Other arguments we can set here include the `vocab` of our model (we're going to train the model, so we don't need to set this) and `max_input_chars_per_word`, which specifies a maximum length for each word (words longer than the value passed will be split). + +The first step of tokenization is normalization, so let's begin with that. Since BERT is widely used, there is a `BertNormalizer` with the classic options we can set for BERT: `lowercase` and `strip_accents`, which are self-explanatory; `clean_text` to remove all control characters and replace repeating spaces with a single one; and `handle_chinese_chars`, which places spaces around Chinese characters. To replicate the `bert-base-uncased` tokenizer, we can just set this normalizer: + +```python +tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) +``` + +Generally speaking, however, when building a new tokenizer you won't have access to such a handy normalizer already implemented in the 🤗 Tokenizers library -- so let's see how to create the BERT normalizer by hand. The library provides a `Lowercase` normalizer and a `StripAccents` normalizer, and you can compose several normalizers using a `Sequence`: + +```python +tokenizer.normalizer = normalizers.Sequence( + [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()] +) +``` + +We're also using an `NFD` Unicode normalizer, as otherwise the `StripAccents` normalizer won't properly recognize the accented characters and thus won't strip them out. + +As we've seen before, we can use the `normalize_str()` method of the `normalizer` to check out the effects it has on a given text: + +```python +print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +hello how are u? +``` + + + +**To go further** If you test the two versions of the previous normalizers on a string containing the unicode character `u"\u0085"` you will surely notice that these two normalizers are not exactly equivalent. +To not over-complicate the version with `normalizers.Sequence` too much , we haven't included the Regex replacements that the `BertNormalizer` requires when the `clean_text` argument is set to `True` - which is the default behavior. But don't worry: it is possible to get exactly the same normalization without using the handy `BertNormalizer` by adding two `normalizers.Replace`'s to the normalizers sequence. + + + +Next is the pre-tokenization step. Again, there is a prebuilt `BertPreTokenizer` that we can use: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() +``` + +Or we can build it from scratch: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() +``` + +Note that the `Whitespace` pre-tokenizer splits on whitespace and all characters that are not letters, digits, or the underscore character, so it technically splits on whitespace and punctuation: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +If you only want to split on whitespace, you should use the `WhitespaceSplit` pre-tokenizer instead: + +```python +pre_tokenizer = pre_tokenizers.WhitespaceSplit() +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] +``` + +Like with normalizers, you can use a `Sequence` to compose several pre-tokenizers: + +```python +pre_tokenizer = pre_tokenizers.Sequence( + [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()] +) +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +The next step in the tokenization pipeline is running the inputs through the model. We already specified our model in the initialization, but we still need to train it, which will require a `WordPieceTrainer`. The main thing to remember when instantiating a trainer in 🤗 Tokenizers is that you need to pass it all the special tokens you intend to use -- otherwise it won't add them to the vocabulary, since they are not in the training corpus: + +```python +special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] +trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) +``` + +As well as specifying the `vocab_size` and `special_tokens`, we can set the `min_frequency` (the number of times a token must appear to be included in the vocabulary) or change the `continuing_subword_prefix` (if we want to use something different from `##`). + +To train our model using the iterator we defined earlier, we just have to execute this command: + +```python +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +We can also use text files to train our tokenizer, which would look like this (we reinitialize the model with an empty `WordPiece` beforehand): + +```python +tokenizer.model = models.WordPiece(unk_token="[UNK]") +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +In both cases, we can then test the tokenizer on a text by calling the `encode()` method: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] +``` + +The `encoding` obtained is an `Encoding`, which contains all the necessary outputs of the tokenizer in its various attributes: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask`, and `overflowing`. + +The last step in the tokenization pipeline is post-processing. We need to add the `[CLS]` token at the beginning and the `[SEP]` token at the end (or after each sentence, if we have a pair of sentences). We will use a `TemplateProcessor` for this, but first we need to know the IDs of the `[CLS]` and `[SEP]` tokens in the vocabulary: + +```python +cls_token_id = tokenizer.token_to_id("[CLS]") +sep_token_id = tokenizer.token_to_id("[SEP]") +print(cls_token_id, sep_token_id) +``` + +```python out +(2, 3) +``` + +To write the template for the `TemplateProcessor`, we have to specify how to treat a single sentence and a pair of sentences. For both, we write the special tokens we want to use; the first (or single) sentence is represented by `$A`, while the second sentence (if encoding a pair) is represented by `$B`. For each of these (special tokens and sentences), we also specify the corresponding token type ID after a colon. + +The classic BERT template is thus defined as follows: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single=f"[CLS]:0 $A:0 [SEP]:0", + pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1", + special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)], +) +``` + +Note that we need to pass along the IDs of the special tokens, so the tokenizer can properly convert them to their IDs. + +Once this is added, going back to our previous example will give: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] +``` + +And on a pair of sentences, we get the proper result: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") +print(encoding.tokens) +print(encoding.type_ids) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]'] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] +``` + +We've almost finished building this tokenizer from scratch -- the last step is to include a decoder: + +```python +tokenizer.decoder = decoders.WordPiece(prefix="##") +``` + +Let's test it on our previous `encoding`: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"let's test this tokenizer... on a pair of sentences." +``` + +Great! We can save our tokenizer in a single JSON file like this: + +```python +tokenizer.save("tokenizer.json") +``` + +We can then reload that file in a `Tokenizer` object with the `from_file()` method: + +```python +new_tokenizer = Tokenizer.from_file("tokenizer.json") +``` + +To use this tokenizer in 🤗 Transformers, we have to wrap it in a `PreTrainedTokenizerFast`. We can either use the generic class or, if our tokenizer corresponds to an existing model, use that class (here, `BertTokenizerFast`). If you apply this lesson to build a brand new tokenizer, you will have to use the first option. + +To wrap the tokenizer in a `PreTrainedTokenizerFast`, we can either pass the tokenizer we built as a `tokenizer_object` or pass the tokenizer file we saved as `tokenizer_file`. The key thing to remember is that we have to manually set all the special tokens, since that class can't infer from the `tokenizer` object which token is the mask token, the `[CLS]` token, etc.: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + # tokenizer_file="tokenizer.json", # You can load from the tokenizer file, alternatively + unk_token="[UNK]", + pad_token="[PAD]", + cls_token="[CLS]", + sep_token="[SEP]", + mask_token="[MASK]", +) +``` + +If you are using a specific tokenizer class (like `BertTokenizerFast`), you will only need to specify the special tokens that are different from the default ones (here, none): + +```python +from transformers import BertTokenizerFast + +wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) +``` + +You can then use this tokenizer like any other 🤗 Transformers tokenizer. You can save it with the `save_pretrained()` method, or upload it to the Hub with the `push_to_hub()` method. + +Now that we've seen how to build a WordPiece tokenizer, let's do the same for a BPE tokenizer. We'll go a bit faster since you know all the steps, and only highlight the differences. + +## Building a BPE tokenizer from scratch[[building-a-bpe-tokenizer-from-scratch]] + +Let's now build a GPT-2 tokenizer. Like for the BERT tokenizer, we start by initializing a `Tokenizer` with a BPE model: + +```python +tokenizer = Tokenizer(models.BPE()) +``` + +Also like for BERT, we could initialize this model with a vocabulary if we had one (we would need to pass the `vocab` and `merges` in this case), but since we will train from scratch, we don't need to do that. We also don't need to specify an `unk_token` because GPT-2 uses byte-level BPE, which doesn't require it. + +GPT-2 does not use a normalizer, so we skip that step and go directly to the pre-tokenization: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) +``` + +The option we added to `ByteLevel` here is to not add a space at the beginning of a sentence (which is the default otherwise). We can have a look at the pre-tokenization of an example text like before: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") +``` + +```python out +[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)), + ('tokenization', (15, 27)), ('!', (27, 28))] +``` + +Next is the model, which needs training. For GPT-2, the only special token is the end-of-text token: + +```python +trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +Like with the `WordPieceTrainer`, as well as the `vocab_size` and `special_tokens`, we can specify the `min_frequency` if we want to, or if we have an end-of-word suffix (like ``), we can set it with `end_of_word_suffix`. + +This tokenizer can also be trained on text files: + +```python +tokenizer.model = models.BPE() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +Let's have a look at the tokenization of a sample text: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] +``` + +We apply the byte-level post-processing for the GPT-2 tokenizer as follows: + +```python +tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) +``` + +The `trim_offsets = False` option indicates to the post-processor that we should leave the offsets of tokens that begin with 'Ġ' as they are: this way the start of the offsets will point to the space before the word, not the first character of the word (since the space is technically part of the token). Let's have a look at the result with the text we just encoded, where `'Ġtest'` is the token at index 4: + +```python +sentence = "Let's test this tokenizer." +encoding = tokenizer.encode(sentence) +start, end = encoding.offsets[4] +sentence[start:end] +``` + +```python out +' test' +``` + +Finally, we add a byte-level decoder: + +```python +tokenizer.decoder = decoders.ByteLevel() +``` + +and we can double-check it works properly: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"Let's test this tokenizer." +``` + +Great! Now that we're done, we can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `GPT2TokenizerFast` if we want to use it in 🤗 Transformers: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="<|endoftext|>", + eos_token="<|endoftext|>", +) +``` + +or: + +```python +from transformers import GPT2TokenizerFast + +wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) +``` + +As the last example, we'll show you how to build a Unigram tokenizer from scratch. + +## Building a Unigram tokenizer from scratch[[building-a-unigram-tokenizer-from-scratch]] + +Let's now build an XLNet tokenizer. Like for the previous tokenizers, we start by initializing a `Tokenizer` with a Unigram model: + +```python +tokenizer = Tokenizer(models.Unigram()) +``` + +Again, we could initialize this model with a vocabulary if we had one. + +For the normalization, XLNet uses a few replacements (which come from SentencePiece): + +```python +from tokenizers import Regex + +tokenizer.normalizer = normalizers.Sequence( + [ + normalizers.Replace("``", '"'), + normalizers.Replace("''", '"'), + normalizers.NFKD(), + normalizers.StripAccents(), + normalizers.Replace(Regex(" {2,}"), " "), + ] +) +``` + +This replaces `` and '' with " and any sequence of two or more spaces with a single space, as well as removing the accents in the texts to tokenize. + +The pre-tokenizer to use for any SentencePiece tokenizer is `Metaspace`: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() +``` + +We can have a look at the pre-tokenization of an example text like before: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") +``` + +```python out +[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] +``` + +Next is the model, which needs training. XLNet has quite a few special tokens: + +```python +special_tokens = ["", "", "", "", "", "", ""] +trainer = trainers.UnigramTrainer( + vocab_size=25000, special_tokens=special_tokens, unk_token="" +) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +A very important argument not to forget for the `UnigramTrainer` is the `unk_token`. We can also pass along other arguments specific to the Unigram algorithm, such as the `shrinking_factor` for each step where we remove tokens (defaults to 0.75) or the `max_piece_length` to specify the maximum length of a given token (defaults to 16). + +This tokenizer can also be trained on text files: + +```python +tokenizer.model = models.Unigram() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +Let's have a look at the tokenization of a sample text: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] +``` + +A peculiarity of XLNet is that it puts the `` token at the end of the sentence, with a type ID of 2 (to distinguish it from the other tokens). It's padding on the left, as a result. We can deal with all the special tokens and token type IDs with a template, like for BERT, but first we have to get the IDs of the `` and `` tokens: + +```python +cls_token_id = tokenizer.token_to_id("") +sep_token_id = tokenizer.token_to_id("") +print(cls_token_id, sep_token_id) +``` + +```python out +0 1 +``` + +The template looks like this: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single="$A:0 :0 :2", + pair="$A:0 :0 $B:1 :1 :2", + special_tokens=[("", sep_token_id), ("", cls_token_id)], +) +``` + +And we can test it works by encoding a pair of sentences: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") +print(encoding.tokens) +print(encoding.type_ids) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '', '▁', 'on', '▁', 'a', '▁pair', + '▁of', '▁sentence', 's', '!', '', ''] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] +``` + +Finally, we add a `Metaspace` decoder: + +```python +tokenizer.decoder = decoders.Metaspace() +``` + +and we're done with this tokenizer! We can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `XLNetTokenizerFast` if we want to use it in 🤗 Transformers. One thing to note when using `PreTrainedTokenizerFast` is that on top of the special tokens, we need to tell the 🤗 Transformers library to pad on the left: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="", + eos_token="", + unk_token="", + pad_token="", + cls_token="", + sep_token="", + mask_token="", + padding_side="left", +) +``` + +Or alternatively: + +```python +from transformers import XLNetTokenizerFast + +wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) +``` + +Now that you have seen how the various building blocks are used to build existing tokenizers, you should be able to write any tokenizer you want with the 🤗 Tokenizers library and be able to use it in 🤗 Transformers. diff --git a/chapters/ru/chapter6/9.mdx b/chapters/ru/chapter6/9.mdx new file mode 100644 index 000000000..288c4864b --- /dev/null +++ b/chapters/ru/chapter6/9.mdx @@ -0,0 +1,16 @@ +# Tokenizers, check![[tokenizers-check]] + + + +Great job finishing this chapter! + +After this deep dive into tokenizers, you should: + +- Be able to train a new tokenizer using an old one as a template +- Understand how to use offsets to map tokens' positions to their original span of text +- Know the differences between BPE, WordPiece, and Unigram +- Be able to mix and match the blocks provided by the 🤗 Tokenizers library to build your own tokenizer +- Be able to use that tokenizer inside the 🤗 Transformers library From 5097c17c1f6b066dc0a0ada5ceb9b3b6b58f7f87 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Sat, 16 Dec 2023 21:38:43 +0300 Subject: [PATCH 300/502] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=D0=B8=D1=80?= =?UTF-8?q?=D1=83=D1=8E=20=D1=82=D0=B5=D0=BA=D1=83=D1=89=D0=B5=D0=B5=20?= =?UTF-8?q?=D1=81=D0=BE=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.ipynb_checkpoints/3-checkpoint.mdx | 473 ++++++++++++++++++ chapters/ru/chapter6/3.mdx | 2 +- 2 files changed, 474 insertions(+), 1 deletion(-) create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx new file mode 100644 index 000000000..c420e4dda --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx @@ -0,0 +1,473 @@ + + +# Особые возможности быстрых токенизаторов[[fast-tokenizers-special-powers]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +In this section we will take a closer look at the capabilities of the tokenizers in 🤗 Transformers. Up to now we have only used them to tokenize inputs or decode IDs back into text, but tokenizers -- especially those backed by the 🤗 Tokenizers library -- can do a lot more. To illustrate these additional features, we will explore how to reproduce the results of the `token-classification` (that we called `ner`) and `question-answering` pipelines that we first encountered in [Chapter 1](/course/chapter1). + + + +In the following discussion, we will often make the distinction between "slow" and "fast" tokenizers. Slow tokenizers are those written in Python inside the 🤗 Transformers library, while the fast versions are the ones provided by 🤗 Tokenizers, which are written in Rust. If you remember the table from [Chapter 5](/course/chapter5/3) that reported how long it took a fast and a slow tokenizer to tokenize the Drug Review Dataset, you should have an idea of why we call them fast and slow: + +| | Fast tokenizer | Slow tokenizer +:--------------:|:--------------:|:-------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s + + + +⚠️ When tokenizing a single sentence, you won't always see a difference in speed between the slow and fast versions of the same tokenizer. In fact, the fast version might actually be slower! It's only when tokenizing lots of texts in parallel at the same time that you will be able to clearly see the difference. + + + +## Batch encoding[[batch-encoding]] + + + +The output of a tokenizer isn't a simple Python dictionary; what we get is actually a special `BatchEncoding` object. It's a subclass of a dictionary (which is why we were able to index into that result without any problem before), but with additional methods that are mostly used by fast tokenizers. + +Besides their parallelization capabilities, the key functionality of fast tokenizers is that they always keep track of the original span of texts the final tokens come from -- a feature we call *offset mapping*. This in turn unlocks features like mapping each word to the tokens it generated or mapping each character of the original text to the token it's inside, and vice versa. + +Let's take a look at an example: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +encoding = tokenizer(example) +print(type(encoding)) +``` + +As mentioned previously, we get a `BatchEncoding` object in the tokenizer's output: + +```python out + +``` + +Since the `AutoTokenizer` class picks a fast tokenizer by default, we can use the additional methods this `BatchEncoding` object provides. We have two ways to check if our tokenizer is a fast or a slow one. We can either check the attribute `is_fast` of the `tokenizer`: + +```python +tokenizer.is_fast +``` + +```python out +True +``` + +or check the same attribute of our `encoding`: + +```python +encoding.is_fast +``` + +```python out +True +``` + +Let's see what a fast tokenizer enables us to do. First, we can access the tokens without having to convert the IDs back to tokens: + +```py +encoding.tokens() +``` + +```python out +['[CLS]', 'My', 'name', 'is', 'S', '##yl', '##va', '##in', 'and', 'I', 'work', 'at', 'Hu', '##gging', 'Face', 'in', + 'Brooklyn', '.', '[SEP]'] +``` + +In this case the token at index 5 is `##yl`, which is part of the word "Sylvain" in the original sentence. We can also use the `word_ids()` method to get the index of the word each token comes from: + +```py +encoding.word_ids() +``` + +```python out +[None, 0, 1, 2, 3, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, None] +``` + +We can see that the tokenizer's special tokens `[CLS]` and `[SEP]` are mapped to `None`, and then each token is mapped to the word it originates from. This is especially useful to determine if a token is at the start of a word or if two tokens are in the same word. We could rely on the `##` prefix for that, but it only works for BERT-like tokenizers; this method works for any type of tokenizer as long as it's a fast one. In the next chapter, we'll see how we can use this capability to apply the labels we have for each word properly to the tokens in tasks like named entity recognition (NER) and part-of-speech (POS) tagging. We can also use it to mask all the tokens coming from the same word in masked language modeling (a technique called _whole word masking_). + + + +The notion of what a word is complicated. For instance, does "I'll" (a contraction of "I will") count as one or two words? It actually depends on the tokenizer and the pre-tokenization operation it applies. Some tokenizers just split on spaces, so they will consider this as one word. Others use punctuation on top of spaces, so will consider it two words. + +✏️ **Try it out!** Create a tokenizer from the `bert-base-cased` and `roberta-base` checkpoints and tokenize "81s" with them. What do you observe? What are the word IDs? + + + +Similarly, there is a `sentence_ids()` method that we can use to map a token to the sentence it came from (though in this case, the `token_type_ids` returned by the tokenizer can give us the same information). + +Lastly, we can map any word or token to characters in the original text, and vice versa, via the `word_to_chars()` or `token_to_chars()` and `char_to_word()` or `char_to_token()` methods. For instance, the `word_ids()` method told us that `##yl` is part of the word at index 3, but which word is it in the sentence? We can find out like this: + +```py +start, end = encoding.word_to_chars(3) +example[start:end] +``` + +```python out +Sylvain +``` + +As we mentioned previously, this is all powered by the fact the fast tokenizer keeps track of the span of text each token comes from in a list of *offsets*. To illustrate their use, next we'll show you how to replicate the results of the `token-classification` pipeline manually. + + + +✏️ **Try it out!** Create your own example text and see if you can understand which tokens are associated with word ID, and also how to extract the character spans for a single word. For bonus points, try using two sentences as input and see if the sentence IDs make sense to you. + + + +## Inside the `token-classification` pipeline[[inside-the-token-classification-pipeline]] + +In [Chapter 1](/course/chapter1) we got our first taste of applying NER -- where the task is to identify which parts of the text correspond to entities like persons, locations, or organizations -- with the 🤗 Transformers `pipeline()` function. Then, in [Chapter 2](/course/chapter2), we saw how a pipeline groups together the three stages necessary to get the predictions from a raw text: tokenization, passing the inputs through the model, and post-processing. The first two steps in the `token-classification` pipeline are the same as in any other pipeline, but the post-processing is a little more complex -- let's see how! + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +### Getting the base results with the pipeline[[getting-the-base-results-with-the-pipeline]] + +First, let's grab a token classification pipeline so we can get some results to compare manually. The model used by default is [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english); it performs NER on sentences: + +```py +from transformers import pipeline + +token_classifier = pipeline("token-classification") +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +The model properly identified each token generated by "Sylvain" as a person, each token generated by "Hugging Face" as an organization, and the token "Brooklyn" as a location. We can also ask the pipeline to group together the tokens that correspond to the same entity: + +```py +from transformers import pipeline + +token_classifier = pipeline("token-classification", aggregation_strategy="simple") +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +The `aggregation_strategy` picked will change the scores computed for each grouped entity. With `"simple"` the score is just the mean of the scores of each token in the given entity: for instance, the score of "Sylvain" is the mean of the scores we saw in the previous example for the tokens `S`, `##yl`, `##va`, and `##in`. Other strategies available are: + +- `"first"`, where the score of each entity is the score of the first token of that entity (so for "Sylvain" it would be 0.993828, the score of the token `S`) +- `"max"`, where the score of each entity is the maximum score of the tokens in that entity (so for "Hugging Face" it would be 0.98879766, the score of "Face") +- `"average"`, where the score of each entity is the average of the scores of the words composing that entity (so for "Sylvain" there would be no difference from the `"simple"` strategy, but "Hugging Face" would have a score of 0.9819, the average of the scores for "Hugging", 0.975, and "Face", 0.98879) + +Now let's see how to obtain these results without using the `pipeline()` function! + +### From inputs to predictions[[from-inputs-to-predictions]] + +{#if fw === 'pt'} + +First we need to tokenize our input and pass it through the model. This is done exactly as in [Chapter 2](/course/chapter2); we instantiate the tokenizer and the model using the `AutoXxx` classes and then use them on our example: + +```py +from transformers import AutoTokenizer, AutoModelForTokenClassification + +model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModelForTokenClassification.from_pretrained(model_checkpoint) + +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +inputs = tokenizer(example, return_tensors="pt") +outputs = model(**inputs) +``` + +Since we're using `AutoModelForTokenClassification` here, we get one set of logits for each token in the input sequence: + +```py +print(inputs["input_ids"].shape) +print(outputs.logits.shape) +``` + +```python out +torch.Size([1, 19]) +torch.Size([1, 19, 9]) +``` + +{:else} + +First we need to tokenize our input and pass it through the model. This is done exactly as in [Chapter 2](/course/chapter2); we instantiate the tokenizer and the model using the `TFAutoXxx` classes and then use them on our example: + +```py +from transformers import AutoTokenizer, TFAutoModelForTokenClassification + +model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = TFAutoModelForTokenClassification.from_pretrained(model_checkpoint) + +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +inputs = tokenizer(example, return_tensors="tf") +outputs = model(**inputs) +``` + +Since we're using `TFAutoModelForTokenClassification` here, we get one set of logits for each token in the input sequence: + +```py +print(inputs["input_ids"].shape) +print(outputs.logits.shape) +``` + +```python out +(1, 19) +(1, 19, 9) +``` + +{/if} + +We have a batch with 1 sequence of 19 tokens and the model has 9 different labels, so the output of the model has a shape of 1 x 19 x 9. Like for the text classification pipeline, we use a softmax function to convert those logits to probabilities, and we take the argmax to get predictions (note that we can take the argmax on the logits because the softmax does not change the order): + +{#if fw === 'pt'} + +```py +import torch + +probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)[0].tolist() +predictions = outputs.logits.argmax(dim=-1)[0].tolist() +print(predictions) +``` + +{:else} + +```py +import tensorflow as tf + +probabilities = tf.math.softmax(outputs.logits, axis=-1)[0] +probabilities = probabilities.numpy().tolist() +predictions = tf.math.argmax(outputs.logits, axis=-1)[0] +predictions = predictions.numpy().tolist() +print(predictions) +``` + +{/if} + +```python out +[0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 6, 6, 6, 0, 8, 0, 0] +``` + +The `model.config.id2label` attribute contains the mapping of indexes to labels that we can use to make sense of the predictions: + +```py +model.config.id2label +``` + +```python out +{0: 'O', + 1: 'B-MISC', + 2: 'I-MISC', + 3: 'B-PER', + 4: 'I-PER', + 5: 'B-ORG', + 6: 'I-ORG', + 7: 'B-LOC', + 8: 'I-LOC'} +``` + +As we saw earlier, there are 9 labels: `O` is the label for the tokens that are not in any named entity (it stands for "outside"), and we then have two labels for each type of entity (miscellaneous, person, organization, and location). The label `B-XXX` indicates the token is at the beginning of an entity `XXX` and the label `I-XXX` indicates the token is inside the entity `XXX`. For instance, in the current example we would expect our model to classify the token `S` as `B-PER` (beginning of a person entity) and the tokens `##yl`, `##va` and `##in` as `I-PER` (inside a person entity). + +You might think the model was wrong in this case as it gave the label `I-PER` to all four of these tokens, but that's not entirely true. There are actually two formats for those `B-` and `I-` labels: *IOB1* and *IOB2*. The IOB2 format (in pink below), is the one we introduced whereas in the IOB1 format (in blue), the labels beginning with `B-` are only ever used to separate two adjacent entities of the same type. The model we are using was fine-tuned on a dataset using that format, which is why it assigns the label `I-PER` to the `S` token. + +
+IOB1 vs IOB2 format + +
+ +With this map, we are ready to reproduce (almost entirely) the results of the first pipeline -- we can just grab the score and label of each token that was not classified as `O`: + +```py +results = [] +tokens = inputs.tokens() + +for idx, pred in enumerate(predictions): + label = model.config.id2label[pred] + if label != "O": + results.append( + {"entity": label, "score": probabilities[idx][pred], "word": tokens[idx]} + ) + +print(results) +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S'}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl'}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va'}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in'}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu'}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging'}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face'}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn'}] +``` + +This is very similar to what we had before, with one exception: the pipeline also gave us information about the `start` and `end` of each entity in the original sentence. This is where our offset mapping will come into play. To get the offsets, we just have to set `return_offsets_mapping=True` when we apply the tokenizer to our inputs: + +```py +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +inputs_with_offsets["offset_mapping"] +``` + +```python out +[(0, 0), (0, 2), (3, 7), (8, 10), (11, 12), (12, 14), (14, 16), (16, 18), (19, 22), (23, 24), (25, 29), (30, 32), + (33, 35), (35, 40), (41, 45), (46, 48), (49, 57), (57, 58), (0, 0)] +``` + +Each tuple is the span of text corresponding to each token, where `(0, 0)` is reserved for the special tokens. We saw before that the token at index 5 is `##yl`, which has `(12, 14)` as offsets here. If we grab the corresponding slice in our example: + + +```py +example[12:14] +``` + +we get the proper span of text without the `##`: + +```python out +yl +``` + +Using this, we can now complete the previous results: + +```py +results = [] +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +tokens = inputs_with_offsets.tokens() +offsets = inputs_with_offsets["offset_mapping"] + +for idx, pred in enumerate(predictions): + label = model.config.id2label[pred] + if label != "O": + start, end = offsets[idx] + results.append( + { + "entity": label, + "score": probabilities[idx][pred], + "word": tokens[idx], + "start": start, + "end": end, + } + ) + +print(results) +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +This is the same as what we got from the first pipeline! + +### Grouping entities[[grouping-entities]] + +Using the offsets to determine the start and end keys for each entity is handy, but that information isn't strictly necessary. When we want to group the entities together, however, the offsets will save us a lot of messy code. For example, if we wanted to group together the tokens `Hu`, `##gging`, and `Face`, we could make special rules that say the first two should be attached while removing the `##`, and the `Face` should be added with a space since it does not begin with `##` -- but that would only work for this particular type of tokenizer. We would have to write another set of rules for a SentencePiece or a Byte-Pair-Encoding tokenizer (discussed later in this chapter). + +With the offsets, all that custom code goes away: we just can take the span in the original text that begins with the first token and ends with the last token. So, in the case of the tokens `Hu`, `##gging`, and `Face`, we should start at character 33 (the beginning of `Hu`) and end before character 45 (the end of `Face`): + +```py +example[33:45] +``` + +```python out +Hugging Face +``` + +To write the code that post-processes the predictions while grouping entities, we will group together entities that are consecutive and labeled with `I-XXX`, except for the first one, which can be labeled as `B-XXX` or `I-XXX` (so, we stop grouping an entity when we get a `O`, a new type of entity, or a `B-XXX` that tells us an entity of the same type is starting): + +```py +import numpy as np + +results = [] +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +tokens = inputs_with_offsets.tokens() +offsets = inputs_with_offsets["offset_mapping"] + +idx = 0 +while idx < len(predictions): + pred = predictions[idx] + label = model.config.id2label[pred] + if label != "O": + # Remove the B- or I- + label = label[2:] + start, _ = offsets[idx] + + # Grab all the tokens labeled with I-label + all_scores = [] + while ( + idx < len(predictions) + and model.config.id2label[predictions[idx]] == f"I-{label}" + ): + all_scores.append(probabilities[idx][pred]) + _, end = offsets[idx] + idx += 1 + + # The score is the mean of all the scores of the tokens in that grouped entity + score = np.mean(all_scores).item() + word = example[start:end] + results.append( + { + "entity_group": label, + "score": score, + "word": word, + "start": start, + "end": end, + } + ) + idx += 1 + +print(results) +``` + +And we get the same results as with our second pipeline! + +```python out +[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +Another example of a task where these offsets are extremely useful is question answering. Diving into that pipeline, which we'll do in the next section, will also enable us to take a look at one last feature of the tokenizers in the 🤗 Transformers library: dealing with overflowing tokens when we truncate an input to a given length. diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index 88250f6df..c420e4dda 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -1,6 +1,6 @@ -# Fast tokenizers' special powers[[fast-tokenizers-special-powers]] +# Особые возможности быстрых токенизаторов[[fast-tokenizers-special-powers]] {#if fw === 'pt'} From ab2a8b5985689700963b4b2153f13ff38a92bd80 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Sun, 17 Dec 2023 21:20:12 +0300 Subject: [PATCH 301/502] Fixing the transfer results for today. --- .../.ipynb_checkpoints/3-checkpoint.mdx | 104 +++++++++--------- chapters/ru/chapter6/3.mdx | 104 +++++++++--------- 2 files changed, 106 insertions(+), 102 deletions(-) diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx index c420e4dda..4829edf25 100644 --- a/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx +++ b/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx @@ -22,20 +22,20 @@ {/if} -In this section we will take a closer look at the capabilities of the tokenizers in 🤗 Transformers. Up to now we have only used them to tokenize inputs or decode IDs back into text, but tokenizers -- especially those backed by the 🤗 Tokenizers library -- can do a lot more. To illustrate these additional features, we will explore how to reproduce the results of the `token-classification` (that we called `ner`) and `question-answering` pipelines that we first encountered in [Chapter 1](/course/chapter1). +В этом разделе мы подробно рассмотрим возможности токенизаторов в 🤗 Transformers. До сих пор мы использовали их только для токенизации входных данных или декодирования идентификаторов обратно в текст, но токенизаторы -- особенно те, которые поддерживаются библиотекой 🤗 Tokenizers - могут делать гораздо больше. Чтобы проиллюстрировать эти дополнительные возможности, мы рассмотрим, как воспроизвести результаты конвейеров `token-classification` (которые мы назвали `ner`) и `question-answering`, с которыми мы впервые столкнулись в [Главе 1] (/course/chapter1). -In the following discussion, we will often make the distinction between "slow" and "fast" tokenizers. Slow tokenizers are those written in Python inside the 🤗 Transformers library, while the fast versions are the ones provided by 🤗 Tokenizers, which are written in Rust. If you remember the table from [Chapter 5](/course/chapter5/3) that reported how long it took a fast and a slow tokenizer to tokenize the Drug Review Dataset, you should have an idea of why we call them fast and slow: +В дальнейшем обсуждении мы будем часто проводить различие между "медленными" и "быстрыми" токенизаторами. Медленные токенизаторы - это те, что написаны на Python в библиотеке 🤗 Transformers, а быстрые версии - это те, что предоставляются в 🤗 Tokenizers, которые написаны на Rust. Если вы помните таблицу из [Главы 5](/course/chapter5/3), в которой приводилось, сколько времени потребовалось быстрому и медленному токенизаторам для токенизации датасета Drug Review Dataset, вы должны иметь представление о том, почему мы называем их быстрыми и медленными: -| | Fast tokenizer | Slow tokenizer -:--------------:|:--------------:|:-------------: -`batched=True` | 10.8s | 4min41s -`batched=False` | 59.2s | 5min3s +| | Быстрый токенизатор | Медленный токенизатор +:--------------:|:----------------------:|:----------------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s -⚠️ When tokenizing a single sentence, you won't always see a difference in speed between the slow and fast versions of the same tokenizer. In fact, the fast version might actually be slower! It's only when tokenizing lots of texts in parallel at the same time that you will be able to clearly see the difference. +⚠️ Когда вы токенизируете одно предложение, вы не всегда увидите разницу в скорости между медленной и быстрой версиями одного и того же токенизатора. Более того, быстрая версия может быть даже медленнее! Только при параллельной токенизации большого количества текстов вы сможете увидеть разницу. @@ -43,11 +43,11 @@ In the following discussion, we will often make the distinction between "slow" a -The output of a tokenizer isn't a simple Python dictionary; what we get is actually a special `BatchEncoding` object. It's a subclass of a dictionary (which is why we were able to index into that result without any problem before), but with additional methods that are mostly used by fast tokenizers. +Результат работы токенизатора - это не простой словарь Python; то, что мы получаем, - это специальный объект `BatchEncoding`. Это подкласс словаря (именно поэтому мы раньше могли без проблем индексировать результат), но с дополнительными методами, которые в основном используются быстрыми токенизаторами. -Besides their parallelization capabilities, the key functionality of fast tokenizers is that they always keep track of the original span of texts the final tokens come from -- a feature we call *offset mapping*. This in turn unlocks features like mapping each word to the tokens it generated or mapping each character of the original text to the token it's inside, and vice versa. +Помимо возможностей распараллеливания, ключевой функцией быстрых токенизаторов является то, что они всегда отслеживают исходный диапазон текстов, из которых взяты конечные токены, - эту функцию мы называем *сопоставление смещений (offset mapping)*. Это, в свою очередь, открывает такие возможности, как сопоставление каждого слова с порожденными им токенами или сопоставление каждого символа исходного текста с токеном, в котором он находится, и наоборот. -Let's take a look at an example: +Давайте посмотрим на пример: ```py from transformers import AutoTokenizer @@ -58,13 +58,13 @@ encoding = tokenizer(example) print(type(encoding)) ``` -As mentioned previously, we get a `BatchEncoding` object in the tokenizer's output: +Как уже говорилось, на выходе токенизатора мы получаем объект `BatchEncoding`: ```python out ``` -Since the `AutoTokenizer` class picks a fast tokenizer by default, we can use the additional methods this `BatchEncoding` object provides. We have two ways to check if our tokenizer is a fast or a slow one. We can either check the attribute `is_fast` of the `tokenizer`: +Поскольку класс `AutoTokenizer` по умолчанию выбирает быстрый токенизатор, мы можем использовать дополнительные методы, которые предоставляет объект `BatchEncoding`. У нас есть два способа проверить, является ли наш токенизатор быстрым или медленным. Мы можем проверить атрибут `is_fast` у `tokenizer`: ```python tokenizer.is_fast @@ -74,7 +74,7 @@ tokenizer.is_fast True ``` -or check the same attribute of our `encoding`: +или проверьте тот же атрибут нашего `encoding`: ```python encoding.is_fast @@ -84,7 +84,7 @@ encoding.is_fast True ``` -Let's see what a fast tokenizer enables us to do. First, we can access the tokens without having to convert the IDs back to tokens: +Давайте посмотрим, что позволяет нам сделать быстрый токенизатор. Во-первых, мы можем получить доступ к токенам без необходимости преобразовывать идентификаторы обратно в токены: ```py encoding.tokens() @@ -95,7 +95,7 @@ encoding.tokens() 'Brooklyn', '.', '[SEP]'] ``` -In this case the token at index 5 is `##yl`, which is part of the word "Sylvain" in the original sentence. We can also use the `word_ids()` method to get the index of the word each token comes from: +В данном случае токен с индексом 5 - это `##yl`, который является частью слова "Sylvain" в исходном предложении. Мы также можем использовать метод `word_ids()`, чтобы получить индекс слова, из которого происходит каждый токен: ```py encoding.word_ids() @@ -107,17 +107,19 @@ encoding.word_ids() We can see that the tokenizer's special tokens `[CLS]` and `[SEP]` are mapped to `None`, and then each token is mapped to the word it originates from. This is especially useful to determine if a token is at the start of a word or if two tokens are in the same word. We could rely on the `##` prefix for that, but it only works for BERT-like tokenizers; this method works for any type of tokenizer as long as it's a fast one. In the next chapter, we'll see how we can use this capability to apply the labels we have for each word properly to the tokens in tasks like named entity recognition (NER) and part-of-speech (POS) tagging. We can also use it to mask all the tokens coming from the same word in masked language modeling (a technique called _whole word masking_). +Мы можем видеть, что специальные токены токенизатора `[CLS]` и `[SEP]` сопоставляются с `None`, а затем каждый токен сопоставляется со словом, от которого он происходит. Это особенно полезно для определения того, находится ли токен в начале слова или два токена в одном и том же слове. Для этого мы могли бы использовать префикс `##`, но он работает только для токенизаторов типа BERT; этот метод работает для любого типа токенизаторов, лишь бы он был быстрым. В следующей главе мы увидим, как можно использовать эту возможность для применения меток, которые мы имеем для каждого слова, к токенам в таких задачах, как распознавание именованных сущностей (NER) и тегирование частей речи (part-of-speech - POS). Мы также можем использовать ее для маскирования всех токенов, происходящих от одного и того же слова, при моделировании языка по маске (masked language modeling) (эта техника называется _маскированием всего слова (whole word masking)_). + -The notion of what a word is complicated. For instance, does "I'll" (a contraction of "I will") count as one or two words? It actually depends on the tokenizer and the pre-tokenization operation it applies. Some tokenizers just split on spaces, so they will consider this as one word. Others use punctuation on top of spaces, so will consider it two words. +Понятие "слово" очень сложное. Например, "I'll" (сокращение от "I will") считается одним или двумя словами? На самом деле это зависит от токенизатора и применяемой им операции предварительной токенизации. Некоторые токенизаторы просто разделяют пробелы, поэтому они будут считать это одним словом. Другие используют пунктуацию поверх пробелов, поэтому будут считать это двумя словами. -✏️ **Try it out!** Create a tokenizer from the `bert-base-cased` and `roberta-base` checkpoints and tokenize "81s" with them. What do you observe? What are the word IDs? +✏️ **Попробуйте! ** Создайте токенизатор из контрольных точек `bert-base-cased` и `roberta-base` и токенизируйте с их помощью "81s". Что вы заметили? Каковы идентификаторы слов? -Similarly, there is a `sentence_ids()` method that we can use to map a token to the sentence it came from (though in this case, the `token_type_ids` returned by the tokenizer can give us the same information). +Аналогично, существует метод `sentence_ids()`, который мы можем использовать для сопоставления токена с предложением, из которого оно взято (хотя в этом случае ту же информацию может дать и `token_type_ids`, возвращаемый токенизатором). -Lastly, we can map any word or token to characters in the original text, and vice versa, via the `word_to_chars()` or `token_to_chars()` and `char_to_word()` or `char_to_token()` methods. For instance, the `word_ids()` method told us that `##yl` is part of the word at index 3, but which word is it in the sentence? We can find out like this: +Наконец, с помощью методов `word_to_chars()` или `token_to_chars()` и `char_to_word()` или `char_to_token()` мы можем сопоставить любое слово или токен с символами в оригинальном тексте и наоборот. Например, метод `word_ids()` сообщил нам, что `##yl` является частью слова с индексом 3, но какое это слово в предложении? Мы можем выяснить это следующим образом: ```py start, end = encoding.word_to_chars(3) @@ -128,17 +130,17 @@ example[start:end] Sylvain ``` -As we mentioned previously, this is all powered by the fact the fast tokenizer keeps track of the span of text each token comes from in a list of *offsets*. To illustrate their use, next we'll show you how to replicate the results of the `token-classification` pipeline manually. +Как мы уже говорили, все это происходит благодаря тому, что быстрый токенизатор отслеживает, из какого участка текста происходит каждый токен, в списке *смещений (offsets)*. Чтобы проиллюстрировать их использование, далее мы покажем, как воспроизвести результаты конвейера `token-classification` вручную. -✏️ **Try it out!** Create your own example text and see if you can understand which tokens are associated with word ID, and also how to extract the character spans for a single word. For bonus points, try using two sentences as input and see if the sentence IDs make sense to you. +✏️ **Попробуйте!** Создайте свой собственный пример текста и посмотрите, сможете ли вы понять, какие токены связаны с идентификаторами слов, а также как извлечь диапазоны символов для одного слова. Чтобы получить бонусные очки, попробуйте использовать два предложения в качестве входных данных и посмотрите, будут ли идентификаторы предложений иметь для вас смысл. -## Inside the `token-classification` pipeline[[inside-the-token-classification-pipeline]] +## Внутри конвейера `token-classification`[[inside-the-token-classification-pipeline]] -In [Chapter 1](/course/chapter1) we got our first taste of applying NER -- where the task is to identify which parts of the text correspond to entities like persons, locations, or organizations -- with the 🤗 Transformers `pipeline()` function. Then, in [Chapter 2](/course/chapter2), we saw how a pipeline groups together the three stages necessary to get the predictions from a raw text: tokenization, passing the inputs through the model, and post-processing. The first two steps in the `token-classification` pipeline are the same as in any other pipeline, but the post-processing is a little more complex -- let's see how! +В [Главе 1](/course/chapter1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2] (/course/chapter2), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! {#if fw === 'pt'} @@ -150,9 +152,9 @@ In [Chapter 1](/course/chapter1) we got our first taste of applying NER -- where {/if} -### Getting the base results with the pipeline[[getting-the-base-results-with-the-pipeline]] +### Получение базовых результатов с помощью конвейера[[getting-the-base-results-with-the-pipeline]] -First, let's grab a token classification pipeline so we can get some results to compare manually. The model used by default is [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english); it performs NER on sentences: +Для начала возьмем конвейер token classification, чтобы получить результаты для сравнения вручную. По умолчанию используется модель [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english); она выполняет NER на предложениях: ```py from transformers import pipeline @@ -172,7 +174,7 @@ token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] ``` -The model properly identified each token generated by "Sylvain" as a person, each token generated by "Hugging Face" as an organization, and the token "Brooklyn" as a location. We can also ask the pipeline to group together the tokens that correspond to the same entity: +Модель правильно идентифицировала каждый токен, сгенерировав "Sylvain", как человека, каждый токен, сгенерированный "Hugging Face", как организацию, а токен "Brooklyn" - как местоположение. Мы также можем попросить конвейер сгруппировать токены, которые соответствуют одной и той же сущности: ```py from transformers import pipeline @@ -187,19 +189,19 @@ token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] ``` -The `aggregation_strategy` picked will change the scores computed for each grouped entity. With `"simple"` the score is just the mean of the scores of each token in the given entity: for instance, the score of "Sylvain" is the mean of the scores we saw in the previous example for the tokens `S`, `##yl`, `##va`, and `##in`. Other strategies available are: +Выбранная `aggregation_strategy` изменит оценки, вычисляемые для каждой сгруппированной сущности. При использовании значения `"simple"` оценка является средним значением оценок каждого токена данной сущности: например, оценка "Sylvain" является средним значением оценок, которые мы видели в предыдущем примере для токенов `S`, `##yl`, `##va` и `##in`. Другие доступные стратегии: -- `"first"`, where the score of each entity is the score of the first token of that entity (so for "Sylvain" it would be 0.993828, the score of the token `S`) -- `"max"`, where the score of each entity is the maximum score of the tokens in that entity (so for "Hugging Face" it would be 0.98879766, the score of "Face") -- `"average"`, where the score of each entity is the average of the scores of the words composing that entity (so for "Sylvain" there would be no difference from the `"simple"` strategy, but "Hugging Face" would have a score of 0.9819, the average of the scores for "Hugging", 0.975, and "Face", 0.98879) +- `"first"`, где оценка каждой сущности - это оценка первого токена этой сущности (так, для "Sylvain" это будет 0,993828, оценки токена `S`) +- `"max"`, где оценка каждой сущности - это максимальная оценка токенов в этой сущности (так, для ""Hugging Face"" это будет 0.98879766, оценки "Face"). +- `"average"`, где оценка каждой сущности - это средняя оценка слов, составляющих эту сущность (таким образом, для слова ""Sylvain"" не будет никаких отличий от стратегии `"simple"`, но "Hugging Face" будет иметь оценку 0.9819, среднюю оценку для "Hugging", 0.975, и "Face", 0.98879) Now let's see how to obtain these results without using the `pipeline()` function! -### From inputs to predictions[[from-inputs-to-predictions]] +### От входных данных к прогнозам[[from-inputs-to-predictions]] {#if fw === 'pt'} -First we need to tokenize our input and pass it through the model. This is done exactly as in [Chapter 2](/course/chapter2); we instantiate the tokenizer and the model using the `AutoXxx` classes and then use them on our example: +Сначала нам нужно токенизировать наш ввод и пропустить его через модель. Это делается точно так же, как в [Главе 2](/course/chapter2); мы инстанцируем токенизатор и модель с помощью классов `AutoXxx`, а затем используем их в нашем примере: ```py from transformers import AutoTokenizer, AutoModelForTokenClassification @@ -213,7 +215,7 @@ inputs = tokenizer(example, return_tensors="pt") outputs = model(**inputs) ``` -Since we're using `AutoModelForTokenClassification` here, we get one set of logits for each token in the input sequence: +Поскольку мы используем `AutoModelForTokenClassification`, мы получаем один набор логитов для каждого токена во входной последовательности: ```py print(inputs["input_ids"].shape) @@ -227,7 +229,7 @@ torch.Size([1, 19, 9]) {:else} -First we need to tokenize our input and pass it through the model. This is done exactly as in [Chapter 2](/course/chapter2); we instantiate the tokenizer and the model using the `TFAutoXxx` classes and then use them on our example: +Сначала нам нужно токенизировать наши входные данные и пропустить их через модель. Это делается точно так же, как в [Главе 2](/course/chapter2); мы инстанцируем токенизатор и модель с помощью классов `TFAutoXxx`, а затем используем их в нашем примере: ```py from transformers import AutoTokenizer, TFAutoModelForTokenClassification @@ -241,7 +243,7 @@ inputs = tokenizer(example, return_tensors="tf") outputs = model(**inputs) ``` -Since we're using `TFAutoModelForTokenClassification` here, we get one set of logits for each token in the input sequence: +Поскольку мы используем `TFAutoModelForTokenClassification`, мы получаем один набор логитов для каждого токена во входной последовательности: ```py print(inputs["input_ids"].shape) @@ -255,7 +257,7 @@ print(outputs.logits.shape) {/if} -We have a batch with 1 sequence of 19 tokens and the model has 9 different labels, so the output of the model has a shape of 1 x 19 x 9. Like for the text classification pipeline, we use a softmax function to convert those logits to probabilities, and we take the argmax to get predictions (note that we can take the argmax on the logits because the softmax does not change the order): +У нас есть батч с 1 последовательностью из 19 токенов, и модель имеет 9 различных меток, поэтому выход модели имеет форму 1 x 19 x 9. Как и для конвейера классификации текста, мы используем функцию softmax для преобразования этих логитов в вероятности и берем argmax для получения прогнозов (обратите внимание, что мы можем взять argmax для логитов, потому что softmax не меняет порядок): {#if fw === 'pt'} @@ -285,7 +287,7 @@ print(predictions) [0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 6, 6, 6, 0, 8, 0, 0] ``` -The `model.config.id2label` attribute contains the mapping of indexes to labels that we can use to make sense of the predictions: +Атрибут `model.config.id2label` содержит отображение индексов в метки, которые мы можем использовать для осмысления прогнозов: ```py model.config.id2label @@ -303,16 +305,16 @@ model.config.id2label 8: 'I-LOC'} ``` -As we saw earlier, there are 9 labels: `O` is the label for the tokens that are not in any named entity (it stands for "outside"), and we then have two labels for each type of entity (miscellaneous, person, organization, and location). The label `B-XXX` indicates the token is at the beginning of an entity `XXX` and the label `I-XXX` indicates the token is inside the entity `XXX`. For instance, in the current example we would expect our model to classify the token `S` as `B-PER` (beginning of a person entity) and the tokens `##yl`, `##va` and `##in` as `I-PER` (inside a person entity). +Как мы видели ранее, существует 9 меток: `O` - это метка для токенов, которые не входят ни в одну именованную сущность (она означает "вне"), а затем у нас есть две метки для каждого типа сущности (miscellaneous, person, organization и location). Метка `B-XXX` указывает на то, что токен находится в начале сущности `XXX`, а метка `I-XXX` указывает на то, что токен находится внутри сущности `XXX`. Таким образом, в данном примере мы ожидаем, что наша модель классифицирует токен `S` как `B-PER` (начало сущности person), а токены `##yl`, `##va` и `##in` как `I-PER` (внутри сущности person). -You might think the model was wrong in this case as it gave the label `I-PER` to all four of these tokens, but that's not entirely true. There are actually two formats for those `B-` and `I-` labels: *IOB1* and *IOB2*. The IOB2 format (in pink below), is the one we introduced whereas in the IOB1 format (in blue), the labels beginning with `B-` are only ever used to separate two adjacent entities of the same type. The model we are using was fine-tuned on a dataset using that format, which is why it assigns the label `I-PER` to the `S` token. +Вы можете подумать, что модель в данном случае ошиблась, поскольку присвоила всем четырем токенам метку `I-PER`, но это не совсем так. На самом деле существует два формата для меток `B-` и `I-`: *IOB1* и *IOB2*. Формат IOB2 (розовый цвет ниже) - это тот, который мы представили, в то время как в формате IOB1 (синий цвет) метки, начинающиеся с `B-`, используются только для разделения двух соседних сущностей одного типа. Используемая нами модель была дообучена на наборе данных, использующем этот формат, поэтому она присваивает токену `S` метку `I-PER`.
IOB1 vs IOB2 format
-With this map, we are ready to reproduce (almost entirely) the results of the first pipeline -- we can just grab the score and label of each token that was not classified as `O`: +С помощью этой карты мы можем воспроизвести (почти полностью) результаты первого конвейера - мы можем просто получить оценку и метку каждого токена, который не был классифицирован как `O`: ```py results = [] @@ -339,7 +341,7 @@ print(results) {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn'}] ``` -This is very similar to what we had before, with one exception: the pipeline also gave us information about the `start` and `end` of each entity in the original sentence. This is where our offset mapping will come into play. To get the offsets, we just have to set `return_offsets_mapping=True` when we apply the tokenizer to our inputs: +Это очень похоже на то, что у нас было раньше, за одним исключением: конвейер также предоставил нам информацию о `start` и `end` каждой сущности в исходном предложении. Вот тут-то и пригодится наше сопоставление смещений. Чтобы получить смещения, нам нужно просто установить `return_offsets_mapping=True`, когда мы применяем токенизатор к нашим входным данным: ```py inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) @@ -351,20 +353,20 @@ inputs_with_offsets["offset_mapping"] (33, 35), (35, 40), (41, 45), (46, 48), (49, 57), (57, 58), (0, 0)] ``` -Each tuple is the span of text corresponding to each token, where `(0, 0)` is reserved for the special tokens. We saw before that the token at index 5 is `##yl`, which has `(12, 14)` as offsets here. If we grab the corresponding slice in our example: +Каждый кортеж - это участок текста, соответствующий каждому токену, где `(0, 0)` зарезервировано для специальных токенов. Мы уже видели, что токен с индексом 5 - это `##yl`, который имеет `(12, 14)` в качестве смещения. Если мы возьмем соответствующий фрагмент в нашем примере: ```py example[12:14] ``` -we get the proper span of text without the `##`: +мы получим нужный участок текста без использования `##`: ```python out yl ``` -Using this, we can now complete the previous results: +Используя это, мы можем дополнить предыдущие результаты: ```py results = [] @@ -400,13 +402,13 @@ print(results) {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] ``` -This is the same as what we got from the first pipeline! +Это то же самое, что мы получили от первого конвейера! -### Grouping entities[[grouping-entities]] +### Группировка сущностей[[grouping-entities]] -Using the offsets to determine the start and end keys for each entity is handy, but that information isn't strictly necessary. When we want to group the entities together, however, the offsets will save us a lot of messy code. For example, if we wanted to group together the tokens `Hu`, `##gging`, and `Face`, we could make special rules that say the first two should be attached while removing the `##`, and the `Face` should be added with a space since it does not begin with `##` -- but that would only work for this particular type of tokenizer. We would have to write another set of rules for a SentencePiece or a Byte-Pair-Encoding tokenizer (discussed later in this chapter). +Использование смещений для определения начального и конечного ключей для каждой сущности удобно, но эта информация не является строго необходимой. Однако когда мы захотим сгруппировать сущности вместе, смещения избавят нас от большого количества беспорядочного кода. Например, если бы мы хотели сгруппировать токены `Hu`, `##gging` и `Face`, мы могли бы создать специальные правила, согласно которым первые два должны быть присоединены, удалив `##`, а `Face` должен быть добавлен через пробел, поскольку он не начинается с `##` - но это будет работать только для данного конкретного типа токенизатора. Для токенизатора SentencePiece или Byte-Pair-Encoding нам придется написать другой набор правил (о них мы поговорим позже в этой главе). -With the offsets, all that custom code goes away: we just can take the span in the original text that begins with the first token and ends with the last token. So, in the case of the tokens `Hu`, `##gging`, and `Face`, we should start at character 33 (the beginning of `Hu`) and end before character 45 (the end of `Face`): +С помощью смещений весь этот пользовательский код отпадает: мы просто можем взять в исходном тексте промежуток, который начинается с первого токена и заканчивается последним. Так, в случае с токенами `Hu`, `##gging` и `Face` мы должны начать с символа 33 (начало `Hu`) и закончить символом 45 (конец `Face`): ```py example[33:45] @@ -416,7 +418,7 @@ example[33:45] Hugging Face ``` -To write the code that post-processes the predictions while grouping entities, we will group together entities that are consecutive and labeled with `I-XXX`, except for the first one, which can be labeled as `B-XXX` or `I-XXX` (so, we stop grouping an entity when we get a `O`, a new type of entity, or a `B-XXX` that tells us an entity of the same type is starting): +Чтобы написать код для постобработки прогнозов при группировке сущностей, мы будем группировать сущности, которые идут подряд и помечены `I-XXX`, за исключением первой, которая может быть помечена как `B-XXX` или `I-XXX` (таким образом, мы прекращаем группировать сущность, когда получаем `O`, новый тип сущности, или `B-XXX`, который говорит нам, что начинается сущность того же типа): ```py import numpy as np @@ -462,7 +464,7 @@ while idx < len(predictions): print(results) ``` -And we get the same results as with our second pipeline! +И мы получаем те же результаты, что и со вторым конвейером! ```python out [{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, @@ -470,4 +472,4 @@ And we get the same results as with our second pipeline! {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] ``` -Another example of a task where these offsets are extremely useful is question answering. Diving into that pipeline, which we'll do in the next section, will also enable us to take a look at one last feature of the tokenizers in the 🤗 Transformers library: dealing with overflowing tokens when we truncate an input to a given length. +Еще один пример задачи, в которой эти смещения чрезвычайно полезны, - question answering. Погружение в этот конвейер, которое мы сделаем в следующем разделе, также позволит нам взглянуть на последнюю особенность токенизаторов в библиотеке 🤗 Transformers: работа с переполненными токенами (overflowing tokens), когда мы усекаем входные данные до заданной длины. diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index c420e4dda..4829edf25 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -22,20 +22,20 @@ {/if} -In this section we will take a closer look at the capabilities of the tokenizers in 🤗 Transformers. Up to now we have only used them to tokenize inputs or decode IDs back into text, but tokenizers -- especially those backed by the 🤗 Tokenizers library -- can do a lot more. To illustrate these additional features, we will explore how to reproduce the results of the `token-classification` (that we called `ner`) and `question-answering` pipelines that we first encountered in [Chapter 1](/course/chapter1). +В этом разделе мы подробно рассмотрим возможности токенизаторов в 🤗 Transformers. До сих пор мы использовали их только для токенизации входных данных или декодирования идентификаторов обратно в текст, но токенизаторы -- особенно те, которые поддерживаются библиотекой 🤗 Tokenizers - могут делать гораздо больше. Чтобы проиллюстрировать эти дополнительные возможности, мы рассмотрим, как воспроизвести результаты конвейеров `token-classification` (которые мы назвали `ner`) и `question-answering`, с которыми мы впервые столкнулись в [Главе 1] (/course/chapter1). -In the following discussion, we will often make the distinction between "slow" and "fast" tokenizers. Slow tokenizers are those written in Python inside the 🤗 Transformers library, while the fast versions are the ones provided by 🤗 Tokenizers, which are written in Rust. If you remember the table from [Chapter 5](/course/chapter5/3) that reported how long it took a fast and a slow tokenizer to tokenize the Drug Review Dataset, you should have an idea of why we call them fast and slow: +В дальнейшем обсуждении мы будем часто проводить различие между "медленными" и "быстрыми" токенизаторами. Медленные токенизаторы - это те, что написаны на Python в библиотеке 🤗 Transformers, а быстрые версии - это те, что предоставляются в 🤗 Tokenizers, которые написаны на Rust. Если вы помните таблицу из [Главы 5](/course/chapter5/3), в которой приводилось, сколько времени потребовалось быстрому и медленному токенизаторам для токенизации датасета Drug Review Dataset, вы должны иметь представление о том, почему мы называем их быстрыми и медленными: -| | Fast tokenizer | Slow tokenizer -:--------------:|:--------------:|:-------------: -`batched=True` | 10.8s | 4min41s -`batched=False` | 59.2s | 5min3s +| | Быстрый токенизатор | Медленный токенизатор +:--------------:|:----------------------:|:----------------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s -⚠️ When tokenizing a single sentence, you won't always see a difference in speed between the slow and fast versions of the same tokenizer. In fact, the fast version might actually be slower! It's only when tokenizing lots of texts in parallel at the same time that you will be able to clearly see the difference. +⚠️ Когда вы токенизируете одно предложение, вы не всегда увидите разницу в скорости между медленной и быстрой версиями одного и того же токенизатора. Более того, быстрая версия может быть даже медленнее! Только при параллельной токенизации большого количества текстов вы сможете увидеть разницу. @@ -43,11 +43,11 @@ In the following discussion, we will often make the distinction between "slow" a -The output of a tokenizer isn't a simple Python dictionary; what we get is actually a special `BatchEncoding` object. It's a subclass of a dictionary (which is why we were able to index into that result without any problem before), but with additional methods that are mostly used by fast tokenizers. +Результат работы токенизатора - это не простой словарь Python; то, что мы получаем, - это специальный объект `BatchEncoding`. Это подкласс словаря (именно поэтому мы раньше могли без проблем индексировать результат), но с дополнительными методами, которые в основном используются быстрыми токенизаторами. -Besides their parallelization capabilities, the key functionality of fast tokenizers is that they always keep track of the original span of texts the final tokens come from -- a feature we call *offset mapping*. This in turn unlocks features like mapping each word to the tokens it generated or mapping each character of the original text to the token it's inside, and vice versa. +Помимо возможностей распараллеливания, ключевой функцией быстрых токенизаторов является то, что они всегда отслеживают исходный диапазон текстов, из которых взяты конечные токены, - эту функцию мы называем *сопоставление смещений (offset mapping)*. Это, в свою очередь, открывает такие возможности, как сопоставление каждого слова с порожденными им токенами или сопоставление каждого символа исходного текста с токеном, в котором он находится, и наоборот. -Let's take a look at an example: +Давайте посмотрим на пример: ```py from transformers import AutoTokenizer @@ -58,13 +58,13 @@ encoding = tokenizer(example) print(type(encoding)) ``` -As mentioned previously, we get a `BatchEncoding` object in the tokenizer's output: +Как уже говорилось, на выходе токенизатора мы получаем объект `BatchEncoding`: ```python out ``` -Since the `AutoTokenizer` class picks a fast tokenizer by default, we can use the additional methods this `BatchEncoding` object provides. We have two ways to check if our tokenizer is a fast or a slow one. We can either check the attribute `is_fast` of the `tokenizer`: +Поскольку класс `AutoTokenizer` по умолчанию выбирает быстрый токенизатор, мы можем использовать дополнительные методы, которые предоставляет объект `BatchEncoding`. У нас есть два способа проверить, является ли наш токенизатор быстрым или медленным. Мы можем проверить атрибут `is_fast` у `tokenizer`: ```python tokenizer.is_fast @@ -74,7 +74,7 @@ tokenizer.is_fast True ``` -or check the same attribute of our `encoding`: +или проверьте тот же атрибут нашего `encoding`: ```python encoding.is_fast @@ -84,7 +84,7 @@ encoding.is_fast True ``` -Let's see what a fast tokenizer enables us to do. First, we can access the tokens without having to convert the IDs back to tokens: +Давайте посмотрим, что позволяет нам сделать быстрый токенизатор. Во-первых, мы можем получить доступ к токенам без необходимости преобразовывать идентификаторы обратно в токены: ```py encoding.tokens() @@ -95,7 +95,7 @@ encoding.tokens() 'Brooklyn', '.', '[SEP]'] ``` -In this case the token at index 5 is `##yl`, which is part of the word "Sylvain" in the original sentence. We can also use the `word_ids()` method to get the index of the word each token comes from: +В данном случае токен с индексом 5 - это `##yl`, который является частью слова "Sylvain" в исходном предложении. Мы также можем использовать метод `word_ids()`, чтобы получить индекс слова, из которого происходит каждый токен: ```py encoding.word_ids() @@ -107,17 +107,19 @@ encoding.word_ids() We can see that the tokenizer's special tokens `[CLS]` and `[SEP]` are mapped to `None`, and then each token is mapped to the word it originates from. This is especially useful to determine if a token is at the start of a word or if two tokens are in the same word. We could rely on the `##` prefix for that, but it only works for BERT-like tokenizers; this method works for any type of tokenizer as long as it's a fast one. In the next chapter, we'll see how we can use this capability to apply the labels we have for each word properly to the tokens in tasks like named entity recognition (NER) and part-of-speech (POS) tagging. We can also use it to mask all the tokens coming from the same word in masked language modeling (a technique called _whole word masking_). +Мы можем видеть, что специальные токены токенизатора `[CLS]` и `[SEP]` сопоставляются с `None`, а затем каждый токен сопоставляется со словом, от которого он происходит. Это особенно полезно для определения того, находится ли токен в начале слова или два токена в одном и том же слове. Для этого мы могли бы использовать префикс `##`, но он работает только для токенизаторов типа BERT; этот метод работает для любого типа токенизаторов, лишь бы он был быстрым. В следующей главе мы увидим, как можно использовать эту возможность для применения меток, которые мы имеем для каждого слова, к токенам в таких задачах, как распознавание именованных сущностей (NER) и тегирование частей речи (part-of-speech - POS). Мы также можем использовать ее для маскирования всех токенов, происходящих от одного и того же слова, при моделировании языка по маске (masked language modeling) (эта техника называется _маскированием всего слова (whole word masking)_). + -The notion of what a word is complicated. For instance, does "I'll" (a contraction of "I will") count as one or two words? It actually depends on the tokenizer and the pre-tokenization operation it applies. Some tokenizers just split on spaces, so they will consider this as one word. Others use punctuation on top of spaces, so will consider it two words. +Понятие "слово" очень сложное. Например, "I'll" (сокращение от "I will") считается одним или двумя словами? На самом деле это зависит от токенизатора и применяемой им операции предварительной токенизации. Некоторые токенизаторы просто разделяют пробелы, поэтому они будут считать это одним словом. Другие используют пунктуацию поверх пробелов, поэтому будут считать это двумя словами. -✏️ **Try it out!** Create a tokenizer from the `bert-base-cased` and `roberta-base` checkpoints and tokenize "81s" with them. What do you observe? What are the word IDs? +✏️ **Попробуйте! ** Создайте токенизатор из контрольных точек `bert-base-cased` и `roberta-base` и токенизируйте с их помощью "81s". Что вы заметили? Каковы идентификаторы слов? -Similarly, there is a `sentence_ids()` method that we can use to map a token to the sentence it came from (though in this case, the `token_type_ids` returned by the tokenizer can give us the same information). +Аналогично, существует метод `sentence_ids()`, который мы можем использовать для сопоставления токена с предложением, из которого оно взято (хотя в этом случае ту же информацию может дать и `token_type_ids`, возвращаемый токенизатором). -Lastly, we can map any word or token to characters in the original text, and vice versa, via the `word_to_chars()` or `token_to_chars()` and `char_to_word()` or `char_to_token()` methods. For instance, the `word_ids()` method told us that `##yl` is part of the word at index 3, but which word is it in the sentence? We can find out like this: +Наконец, с помощью методов `word_to_chars()` или `token_to_chars()` и `char_to_word()` или `char_to_token()` мы можем сопоставить любое слово или токен с символами в оригинальном тексте и наоборот. Например, метод `word_ids()` сообщил нам, что `##yl` является частью слова с индексом 3, но какое это слово в предложении? Мы можем выяснить это следующим образом: ```py start, end = encoding.word_to_chars(3) @@ -128,17 +130,17 @@ example[start:end] Sylvain ``` -As we mentioned previously, this is all powered by the fact the fast tokenizer keeps track of the span of text each token comes from in a list of *offsets*. To illustrate their use, next we'll show you how to replicate the results of the `token-classification` pipeline manually. +Как мы уже говорили, все это происходит благодаря тому, что быстрый токенизатор отслеживает, из какого участка текста происходит каждый токен, в списке *смещений (offsets)*. Чтобы проиллюстрировать их использование, далее мы покажем, как воспроизвести результаты конвейера `token-classification` вручную. -✏️ **Try it out!** Create your own example text and see if you can understand which tokens are associated with word ID, and also how to extract the character spans for a single word. For bonus points, try using two sentences as input and see if the sentence IDs make sense to you. +✏️ **Попробуйте!** Создайте свой собственный пример текста и посмотрите, сможете ли вы понять, какие токены связаны с идентификаторами слов, а также как извлечь диапазоны символов для одного слова. Чтобы получить бонусные очки, попробуйте использовать два предложения в качестве входных данных и посмотрите, будут ли идентификаторы предложений иметь для вас смысл. -## Inside the `token-classification` pipeline[[inside-the-token-classification-pipeline]] +## Внутри конвейера `token-classification`[[inside-the-token-classification-pipeline]] -In [Chapter 1](/course/chapter1) we got our first taste of applying NER -- where the task is to identify which parts of the text correspond to entities like persons, locations, or organizations -- with the 🤗 Transformers `pipeline()` function. Then, in [Chapter 2](/course/chapter2), we saw how a pipeline groups together the three stages necessary to get the predictions from a raw text: tokenization, passing the inputs through the model, and post-processing. The first two steps in the `token-classification` pipeline are the same as in any other pipeline, but the post-processing is a little more complex -- let's see how! +В [Главе 1](/course/chapter1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2] (/course/chapter2), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! {#if fw === 'pt'} @@ -150,9 +152,9 @@ In [Chapter 1](/course/chapter1) we got our first taste of applying NER -- where {/if} -### Getting the base results with the pipeline[[getting-the-base-results-with-the-pipeline]] +### Получение базовых результатов с помощью конвейера[[getting-the-base-results-with-the-pipeline]] -First, let's grab a token classification pipeline so we can get some results to compare manually. The model used by default is [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english); it performs NER on sentences: +Для начала возьмем конвейер token classification, чтобы получить результаты для сравнения вручную. По умолчанию используется модель [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english); она выполняет NER на предложениях: ```py from transformers import pipeline @@ -172,7 +174,7 @@ token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] ``` -The model properly identified each token generated by "Sylvain" as a person, each token generated by "Hugging Face" as an organization, and the token "Brooklyn" as a location. We can also ask the pipeline to group together the tokens that correspond to the same entity: +Модель правильно идентифицировала каждый токен, сгенерировав "Sylvain", как человека, каждый токен, сгенерированный "Hugging Face", как организацию, а токен "Brooklyn" - как местоположение. Мы также можем попросить конвейер сгруппировать токены, которые соответствуют одной и той же сущности: ```py from transformers import pipeline @@ -187,19 +189,19 @@ token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] ``` -The `aggregation_strategy` picked will change the scores computed for each grouped entity. With `"simple"` the score is just the mean of the scores of each token in the given entity: for instance, the score of "Sylvain" is the mean of the scores we saw in the previous example for the tokens `S`, `##yl`, `##va`, and `##in`. Other strategies available are: +Выбранная `aggregation_strategy` изменит оценки, вычисляемые для каждой сгруппированной сущности. При использовании значения `"simple"` оценка является средним значением оценок каждого токена данной сущности: например, оценка "Sylvain" является средним значением оценок, которые мы видели в предыдущем примере для токенов `S`, `##yl`, `##va` и `##in`. Другие доступные стратегии: -- `"first"`, where the score of each entity is the score of the first token of that entity (so for "Sylvain" it would be 0.993828, the score of the token `S`) -- `"max"`, where the score of each entity is the maximum score of the tokens in that entity (so for "Hugging Face" it would be 0.98879766, the score of "Face") -- `"average"`, where the score of each entity is the average of the scores of the words composing that entity (so for "Sylvain" there would be no difference from the `"simple"` strategy, but "Hugging Face" would have a score of 0.9819, the average of the scores for "Hugging", 0.975, and "Face", 0.98879) +- `"first"`, где оценка каждой сущности - это оценка первого токена этой сущности (так, для "Sylvain" это будет 0,993828, оценки токена `S`) +- `"max"`, где оценка каждой сущности - это максимальная оценка токенов в этой сущности (так, для ""Hugging Face"" это будет 0.98879766, оценки "Face"). +- `"average"`, где оценка каждой сущности - это средняя оценка слов, составляющих эту сущность (таким образом, для слова ""Sylvain"" не будет никаких отличий от стратегии `"simple"`, но "Hugging Face" будет иметь оценку 0.9819, среднюю оценку для "Hugging", 0.975, и "Face", 0.98879) Now let's see how to obtain these results without using the `pipeline()` function! -### From inputs to predictions[[from-inputs-to-predictions]] +### От входных данных к прогнозам[[from-inputs-to-predictions]] {#if fw === 'pt'} -First we need to tokenize our input and pass it through the model. This is done exactly as in [Chapter 2](/course/chapter2); we instantiate the tokenizer and the model using the `AutoXxx` classes and then use them on our example: +Сначала нам нужно токенизировать наш ввод и пропустить его через модель. Это делается точно так же, как в [Главе 2](/course/chapter2); мы инстанцируем токенизатор и модель с помощью классов `AutoXxx`, а затем используем их в нашем примере: ```py from transformers import AutoTokenizer, AutoModelForTokenClassification @@ -213,7 +215,7 @@ inputs = tokenizer(example, return_tensors="pt") outputs = model(**inputs) ``` -Since we're using `AutoModelForTokenClassification` here, we get one set of logits for each token in the input sequence: +Поскольку мы используем `AutoModelForTokenClassification`, мы получаем один набор логитов для каждого токена во входной последовательности: ```py print(inputs["input_ids"].shape) @@ -227,7 +229,7 @@ torch.Size([1, 19, 9]) {:else} -First we need to tokenize our input and pass it through the model. This is done exactly as in [Chapter 2](/course/chapter2); we instantiate the tokenizer and the model using the `TFAutoXxx` classes and then use them on our example: +Сначала нам нужно токенизировать наши входные данные и пропустить их через модель. Это делается точно так же, как в [Главе 2](/course/chapter2); мы инстанцируем токенизатор и модель с помощью классов `TFAutoXxx`, а затем используем их в нашем примере: ```py from transformers import AutoTokenizer, TFAutoModelForTokenClassification @@ -241,7 +243,7 @@ inputs = tokenizer(example, return_tensors="tf") outputs = model(**inputs) ``` -Since we're using `TFAutoModelForTokenClassification` here, we get one set of logits for each token in the input sequence: +Поскольку мы используем `TFAutoModelForTokenClassification`, мы получаем один набор логитов для каждого токена во входной последовательности: ```py print(inputs["input_ids"].shape) @@ -255,7 +257,7 @@ print(outputs.logits.shape) {/if} -We have a batch with 1 sequence of 19 tokens and the model has 9 different labels, so the output of the model has a shape of 1 x 19 x 9. Like for the text classification pipeline, we use a softmax function to convert those logits to probabilities, and we take the argmax to get predictions (note that we can take the argmax on the logits because the softmax does not change the order): +У нас есть батч с 1 последовательностью из 19 токенов, и модель имеет 9 различных меток, поэтому выход модели имеет форму 1 x 19 x 9. Как и для конвейера классификации текста, мы используем функцию softmax для преобразования этих логитов в вероятности и берем argmax для получения прогнозов (обратите внимание, что мы можем взять argmax для логитов, потому что softmax не меняет порядок): {#if fw === 'pt'} @@ -285,7 +287,7 @@ print(predictions) [0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 6, 6, 6, 0, 8, 0, 0] ``` -The `model.config.id2label` attribute contains the mapping of indexes to labels that we can use to make sense of the predictions: +Атрибут `model.config.id2label` содержит отображение индексов в метки, которые мы можем использовать для осмысления прогнозов: ```py model.config.id2label @@ -303,16 +305,16 @@ model.config.id2label 8: 'I-LOC'} ``` -As we saw earlier, there are 9 labels: `O` is the label for the tokens that are not in any named entity (it stands for "outside"), and we then have two labels for each type of entity (miscellaneous, person, organization, and location). The label `B-XXX` indicates the token is at the beginning of an entity `XXX` and the label `I-XXX` indicates the token is inside the entity `XXX`. For instance, in the current example we would expect our model to classify the token `S` as `B-PER` (beginning of a person entity) and the tokens `##yl`, `##va` and `##in` as `I-PER` (inside a person entity). +Как мы видели ранее, существует 9 меток: `O` - это метка для токенов, которые не входят ни в одну именованную сущность (она означает "вне"), а затем у нас есть две метки для каждого типа сущности (miscellaneous, person, organization и location). Метка `B-XXX` указывает на то, что токен находится в начале сущности `XXX`, а метка `I-XXX` указывает на то, что токен находится внутри сущности `XXX`. Таким образом, в данном примере мы ожидаем, что наша модель классифицирует токен `S` как `B-PER` (начало сущности person), а токены `##yl`, `##va` и `##in` как `I-PER` (внутри сущности person). -You might think the model was wrong in this case as it gave the label `I-PER` to all four of these tokens, but that's not entirely true. There are actually two formats for those `B-` and `I-` labels: *IOB1* and *IOB2*. The IOB2 format (in pink below), is the one we introduced whereas in the IOB1 format (in blue), the labels beginning with `B-` are only ever used to separate two adjacent entities of the same type. The model we are using was fine-tuned on a dataset using that format, which is why it assigns the label `I-PER` to the `S` token. +Вы можете подумать, что модель в данном случае ошиблась, поскольку присвоила всем четырем токенам метку `I-PER`, но это не совсем так. На самом деле существует два формата для меток `B-` и `I-`: *IOB1* и *IOB2*. Формат IOB2 (розовый цвет ниже) - это тот, который мы представили, в то время как в формате IOB1 (синий цвет) метки, начинающиеся с `B-`, используются только для разделения двух соседних сущностей одного типа. Используемая нами модель была дообучена на наборе данных, использующем этот формат, поэтому она присваивает токену `S` метку `I-PER`.
IOB1 vs IOB2 format
-With this map, we are ready to reproduce (almost entirely) the results of the first pipeline -- we can just grab the score and label of each token that was not classified as `O`: +С помощью этой карты мы можем воспроизвести (почти полностью) результаты первого конвейера - мы можем просто получить оценку и метку каждого токена, который не был классифицирован как `O`: ```py results = [] @@ -339,7 +341,7 @@ print(results) {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn'}] ``` -This is very similar to what we had before, with one exception: the pipeline also gave us information about the `start` and `end` of each entity in the original sentence. This is where our offset mapping will come into play. To get the offsets, we just have to set `return_offsets_mapping=True` when we apply the tokenizer to our inputs: +Это очень похоже на то, что у нас было раньше, за одним исключением: конвейер также предоставил нам информацию о `start` и `end` каждой сущности в исходном предложении. Вот тут-то и пригодится наше сопоставление смещений. Чтобы получить смещения, нам нужно просто установить `return_offsets_mapping=True`, когда мы применяем токенизатор к нашим входным данным: ```py inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) @@ -351,20 +353,20 @@ inputs_with_offsets["offset_mapping"] (33, 35), (35, 40), (41, 45), (46, 48), (49, 57), (57, 58), (0, 0)] ``` -Each tuple is the span of text corresponding to each token, where `(0, 0)` is reserved for the special tokens. We saw before that the token at index 5 is `##yl`, which has `(12, 14)` as offsets here. If we grab the corresponding slice in our example: +Каждый кортеж - это участок текста, соответствующий каждому токену, где `(0, 0)` зарезервировано для специальных токенов. Мы уже видели, что токен с индексом 5 - это `##yl`, который имеет `(12, 14)` в качестве смещения. Если мы возьмем соответствующий фрагмент в нашем примере: ```py example[12:14] ``` -we get the proper span of text without the `##`: +мы получим нужный участок текста без использования `##`: ```python out yl ``` -Using this, we can now complete the previous results: +Используя это, мы можем дополнить предыдущие результаты: ```py results = [] @@ -400,13 +402,13 @@ print(results) {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] ``` -This is the same as what we got from the first pipeline! +Это то же самое, что мы получили от первого конвейера! -### Grouping entities[[grouping-entities]] +### Группировка сущностей[[grouping-entities]] -Using the offsets to determine the start and end keys for each entity is handy, but that information isn't strictly necessary. When we want to group the entities together, however, the offsets will save us a lot of messy code. For example, if we wanted to group together the tokens `Hu`, `##gging`, and `Face`, we could make special rules that say the first two should be attached while removing the `##`, and the `Face` should be added with a space since it does not begin with `##` -- but that would only work for this particular type of tokenizer. We would have to write another set of rules for a SentencePiece or a Byte-Pair-Encoding tokenizer (discussed later in this chapter). +Использование смещений для определения начального и конечного ключей для каждой сущности удобно, но эта информация не является строго необходимой. Однако когда мы захотим сгруппировать сущности вместе, смещения избавят нас от большого количества беспорядочного кода. Например, если бы мы хотели сгруппировать токены `Hu`, `##gging` и `Face`, мы могли бы создать специальные правила, согласно которым первые два должны быть присоединены, удалив `##`, а `Face` должен быть добавлен через пробел, поскольку он не начинается с `##` - но это будет работать только для данного конкретного типа токенизатора. Для токенизатора SentencePiece или Byte-Pair-Encoding нам придется написать другой набор правил (о них мы поговорим позже в этой главе). -With the offsets, all that custom code goes away: we just can take the span in the original text that begins with the first token and ends with the last token. So, in the case of the tokens `Hu`, `##gging`, and `Face`, we should start at character 33 (the beginning of `Hu`) and end before character 45 (the end of `Face`): +С помощью смещений весь этот пользовательский код отпадает: мы просто можем взять в исходном тексте промежуток, который начинается с первого токена и заканчивается последним. Так, в случае с токенами `Hu`, `##gging` и `Face` мы должны начать с символа 33 (начало `Hu`) и закончить символом 45 (конец `Face`): ```py example[33:45] @@ -416,7 +418,7 @@ example[33:45] Hugging Face ``` -To write the code that post-processes the predictions while grouping entities, we will group together entities that are consecutive and labeled with `I-XXX`, except for the first one, which can be labeled as `B-XXX` or `I-XXX` (so, we stop grouping an entity when we get a `O`, a new type of entity, or a `B-XXX` that tells us an entity of the same type is starting): +Чтобы написать код для постобработки прогнозов при группировке сущностей, мы будем группировать сущности, которые идут подряд и помечены `I-XXX`, за исключением первой, которая может быть помечена как `B-XXX` или `I-XXX` (таким образом, мы прекращаем группировать сущность, когда получаем `O`, новый тип сущности, или `B-XXX`, который говорит нам, что начинается сущность того же типа): ```py import numpy as np @@ -462,7 +464,7 @@ while idx < len(predictions): print(results) ``` -And we get the same results as with our second pipeline! +И мы получаем те же результаты, что и со вторым конвейером! ```python out [{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, @@ -470,4 +472,4 @@ And we get the same results as with our second pipeline! {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] ``` -Another example of a task where these offsets are extremely useful is question answering. Diving into that pipeline, which we'll do in the next section, will also enable us to take a look at one last feature of the tokenizers in the 🤗 Transformers library: dealing with overflowing tokens when we truncate an input to a given length. +Еще один пример задачи, в которой эти смещения чрезвычайно полезны, - question answering. Погружение в этот конвейер, которое мы сделаем в следующем разделе, также позволит нам взглянуть на последнюю особенность токенизаторов в библиотеке 🤗 Transformers: работа с переполненными токенами (overflowing tokens), когда мы усекаем входные данные до заданной длины. From 11f30d18cb32bf65d2d17bcd252fd68abc1cb9a3 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Mon, 18 Dec 2023 22:03:21 +0300 Subject: [PATCH 302/502] Translated files 3b and partially 4. Fixing the result. --- .../.ipynb_checkpoints/3b-checkpoint.mdx | 642 ++++++++++++++++++ .../.ipynb_checkpoints/4-checkpoint.mdx | 123 ++++ chapters/ru/chapter6/3b.mdx | 116 ++-- chapters/ru/chapter6/4.mdx | 38 +- 4 files changed, 842 insertions(+), 77 deletions(-) create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx new file mode 100644 index 000000000..555ea8fd4 --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx @@ -0,0 +1,642 @@ + + +# Быстрые токенизаторы в QA конвейере[[fast-tokenizers-in-the-qa-pipeline]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Теперь мы погрузимся в конвейер `question-answering` и посмотрим, как использовать смещения (offsets) для получения ответа на вопрос из контекста, подобно тому, как мы делали это для сгруппированных сущностей в предыдущем разделе. Затем мы посмотрим, как работать с очень длинными контекстами, которые в итоге будут обрезаны. Вы можете пропустить этот раздел, если вас не интересует задача ответа на вопрос. + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +## Использование конвейера `question-answering`[[using-the-question-answering-pipeline]] + +Как мы видели в [Главе 1](/course/chapter1), для получения ответа на вопрос мы можем использовать конвейер `question-answering` следующим образом: + +```py +from transformers import pipeline + +question_answerer = pipeline("question-answering") +context = """ +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch, and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question = "Which deep learning libraries back 🤗 Transformers?" +question_answerer(question=question, context=context) +``` + +```python out +{'score': 0.97773, + 'start': 78, + 'end': 105, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +В отличие от других конвейеров, которые не могут обрезать и разбивать на части тексты, длина которых превышает максимально допустимую моделью (и поэтому могут пропустить информацию в конце документа), этот конвейер может работать с очень длинными контекстами и вернет ответ на вопрос, даже если он находится в конце: + +```py +long_context = """ +🤗 Transformers: State of the Art NLP + +🤗 Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, +question answering, summarization, translation, text generation and more in over 100 languages. +Its aim is to make cutting-edge NLP easier to use for everyone. + +🤗 Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and +then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and +can be modified to enable quick research experiments. + +Why should I use transformers? + +1. Easy-to-use state-of-the-art models: + - High performance on NLU and NLG tasks. + - Low barrier to entry for educators and practitioners. + - Few user-facing abstractions with just three classes to learn. + - A unified API for using all our pretrained models. + - Lower compute costs, smaller carbon footprint: + +2. Researchers can share trained models instead of always retraining. + - Practitioners can reduce compute time and production costs. + - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. + +3. Choose the right framework for every part of a model's lifetime: + - Train state-of-the-art models in 3 lines of code. + - Move a single model between TF2.0/PyTorch frameworks at will. + - Seamlessly pick the right framework for training, evaluation and production. + +4. Easily customize a model or an example to your needs: + - We provide examples for each architecture to reproduce the results published by its original authors. + - Model internals are exposed as consistently as possible. + - Model files can be used independently of the library for quick experiments. + +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question_answerer(question=question, context=long_context) +``` + +```python out +{'score': 0.97149, + 'start': 1892, + 'end': 1919, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +Давайте посмотрим, как он справится со всем этим! + +## Использование модели для ответа на вопросы[[using-a-model-for-question-answering]] + +Как и в любом другом конвейере, мы начинаем с токенизации входных данных, а затем отправляем их через модель. По умолчанию для конвейера `question-answering` используется контрольная точка [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) (слово "squad" в названии происходит от набора данных, на котором дообучили модель; подробнее о наборе данных SQuAD мы поговорим в [главе 7](/course/chapter7/7)): + +{#if fw === 'pt'} + +```py +from transformers import AutoTokenizer, AutoModelForQuestionAnswering + +model_checkpoint = "distilbert-base-cased-distilled-squad" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) + +inputs = tokenizer(question, context, return_tensors="pt") +outputs = model(**inputs) +``` + +{:else} + +```py +from transformers import AutoTokenizer, TFAutoModelForQuestionAnswering + +model_checkpoint = "distilbert-base-cased-distilled-squad" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint) + +inputs = tokenizer(question, context, return_tensors="tf") +outputs = model(**inputs) +``` + +{/if} + +Обратите внимание, что мы токенизируем вопрос и контекст как пару, причем вопрос стоит первым. + +
+An example of tokenization of question and context + +
+ +Модели для ответов на вопросы работают немного иначе, чем модели, которые мы рассматривали до сих пор. На примере картинки выше модель была обучена предсказывать индекс токена, с которого начинается ответ (здесь 21), и индекс токена, на котором ответ заканчивается (здесь 24). Вот почему эти модели возвращают не один тензор логитов, а два: один для логитов, соответствующих начальному токену ответа, и один для логитов, соответствующих конечному токену ответа. Поскольку в данном случае у нас только один вход, содержащий 66 токенов, мы получаем: + +```py +start_logits = outputs.start_logits +end_logits = outputs.end_logits +print(start_logits.shape, end_logits.shape) +``` + +{#if fw === 'pt'} + +```python out +torch.Size([1, 66]) torch.Size([1, 66]) +``` + +{:else} + +```python out +(1, 66) (1, 66) +``` + +{/if} + +Чтобы преобразовать эти логиты в вероятности, мы применим функцию softmax, но перед этим нам нужно убедиться, что мы маскируем индексы, которые не являются частью контекста. Наш вход - `[CLS] вопрос [SEP] контекст [SEP]`, поэтому нам нужно замаскировать токены вопроса, а также токен `[SEP]`. Однако мы оставим токен `[CLS]`, поскольку некоторые модели используют его для указания на то, что ответ не находится в контексте. + +Поскольку впоследствии мы будем применять softmax, нам просто нужно заменить логиты, которые мы хотим замаскировать, на большое отрицательное число. Здесь мы используем `-10000`: + +{#if fw === 'pt'} + +```py +import torch + +sequence_ids = inputs.sequence_ids() +# Маскируем все, кроме токенов контекста +mask = [i != 1 for i in sequence_ids] +# Демаскируем токен [CLS] +mask[0] = False +mask = torch.tensor(mask)[None] + +start_logits[mask] = -10000 +end_logits[mask] = -10000 +``` + +{:else} + +```py +import tensorflow as tf + +sequence_ids = inputs.sequence_ids() +# Маскируем все, кроме токенов контекста +mask = [i != 1 for i in sequence_ids] +# Демаскируем токен [CLS] +mask[0] = False +mask = tf.constant(mask)[None] + +start_logits = tf.where(mask, -10000, start_logits) +end_logits = tf.where(mask, -10000, end_logits) +``` + +{/if} + +Теперь, когда мы правильно замаскировали логиты, соответствующие позициям, которые мы не хотим предсказывать, мы можем применить softmax: + +{#if fw === 'pt'} + +```py +start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1)[0] +end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1)[0] +``` + +{:else} + +```py +start_probabilities = tf.math.softmax(start_logits, axis=-1)[0].numpy() +end_probabilities = tf.math.softmax(end_logits, axis=-1)[0].numpy() +``` + +{/if} + +На этом этапе мы могли бы взять argmax вероятностей начала и конца - но в итоге мы можем получить начальный индекс, который больше конечного, поэтому нам нужно принять еще несколько мер предосторожности. Мы вычислим вероятности каждого возможного `start_index` и `end_index`, где `start_index <= end_index`, а затем возьмем кортеж `(start_index, end_index)` с наибольшей вероятностью. + +Если предположить, что события "Ответ начинается на `start_index`" и "Ответ заканчивается на `end_index`" независимы, то вероятность того, что ответ начинается на `start_index` и заканчивается на `end_index`, равна: + +$$\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]$$ + +Таким образом, чтобы вычислить все оценки, нам нужно просто вычислить все произведения \\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\) где `start_index <= end_index`. + +Сначала вычислим все возможные произведения: + +```py +scores = start_probabilities[:, None] * end_probabilities[None, :] +``` + +{#if fw === 'pt'} + +Затем мы замаскируем значения, где `start_index > end_index`, установив для них значение `0` (все остальные вероятности - положительные числа). Функция `torch.triu()` возвращает верхнюю треугольную часть двумерного тензора, переданного в качестве аргумента, поэтому она сделает эту маскировку за нас: + +```py +scores = torch.triu(scores) +``` + +{:else} + +Затем мы замаскируем значения, где `start_index > end_index`, установив для них значение `0` (все остальные вероятности - положительные числа). Функция `np.triu()` возвращает верхнюю треугольную часть двумерного тензора, переданного в качестве аргумента, поэтому она сделает эту маскировку за нас: + +```py +import numpy as np + +scores = np.triu(scores) +``` + +{/if} + +Теперь нам осталось получить индекс максимума. Поскольку PyTorch вернет индекс в плоском тензоре, для получения `start_index` и `end_index` нам нужно воспользоваться операциями получения целой части `//` и остатка `%` от деления: + +```py +max_index = scores.argmax().item() +start_index = max_index // scores.shape[1] +end_index = max_index % scores.shape[1] +print(scores[start_index, end_index]) +``` + +Мы еще не закончили, но, по крайней мере, у нас уже есть корректная оценка ответа (вы можете проверить это, сравнив ее с первым результатом в предыдущем разделе): + +```python out +0.97773 +``` + + + +✏️ **Попробуйте!** Вычислите начальный и конечный индексы для пяти наиболее вероятных ответов. + + + +У нас есть `start_index` и `end_index` ответа в терминах токенов, так что теперь нам просто нужно преобразовать их в индексы символов в контексте. Именно здесь смещения будут очень полезны. Мы можем захватить их и использовать, как мы это делали в задаче token classification: + +```py +inputs_with_offsets = tokenizer(question, context, return_offsets_mapping=True) +offsets = inputs_with_offsets["offset_mapping"] + +start_char, _ = offsets[start_index] +_, end_char = offsets[end_index] +answer = context[start_char:end_char] +``` + +Осталось только отформатировать все, чтобы получить результат: + +```py +result = { + "answer": answer, + "start": start_char, + "end": end_char, + "score": scores[start_index, end_index], +} +print(result) +``` + +```python out +{'answer': 'Jax, PyTorch and TensorFlow', + 'start': 78, + 'end': 105, + 'score': 0.97773} +``` + +Отлично! Это то же самое, что и в нашем первом примере! + + + +✏️ **Попробуйте! ** Используйте лучшие оценки, которые вы вычислили ранее, чтобы показать пять наиболее вероятных ответов. Чтобы проверить результаты, вернитесь к первому конвейеру и передайте `top_k=5` при его вызове. + + + +## Обработка длинных контекстов[[handling-long-contexts]] + +Если мы попытаемся токенизировать вопрос и длинный контекст, который мы использовали в качестве примера ранее, мы получим количество токенов, превышающее максимальную длину, используемую в конвейере `question-answering` (которая составляет 384): + +```py +inputs = tokenizer(question, long_context) +print(len(inputs["input_ids"])) +``` + +```python out +461 +``` + +Поэтому нам нужно обрезать входные данные до максимальной длины. Есть несколько способов сделать это, но мы не хотим усекать вопрос, а только контекст. Поскольку контекст - это второе предложение, мы используем стратегию усечения `" only_second"`. Проблема, которая возникает в этом случае, заключается в том, что ответ на вопрос может не находиться в усеченном контексте. Например, здесь мы выбрали вопрос, ответ на который находится в конце контекста, а когда мы его усекаем, то этого ответа в нём нет: + +```py +inputs = tokenizer(question, long_context, max_length=384, truncation="only_second") +print(tokenizer.decode(inputs["input_ids"])) +``` + +```python out +""" +[CLS] Which deep learning libraries back [UNK] Transformers? [SEP] [UNK] Transformers : State of the Art NLP + +[UNK] Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, +question answering, summarization, translation, text generation and more in over 100 languages. +Its aim is to make cutting-edge NLP easier to use for everyone. + +[UNK] Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and +then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and +can be modified to enable quick research experiments. + +Why should I use transformers? + +1. Easy-to-use state-of-the-art models: + - High performance on NLU and NLG tasks. + - Low barrier to entry for educators and practitioners. + - Few user-facing abstractions with just three classes to learn. + - A unified API for using all our pretrained models. + - Lower compute costs, smaller carbon footprint: + +2. Researchers can share trained models instead of always retraining. + - Practitioners can reduce compute time and production costs. + - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. + +3. Choose the right framework for every part of a model's lifetime: + - Train state-of-the-art models in 3 lines of code. + - Move a single model between TF2.0/PyTorch frameworks at will. + - Seamlessly pick the right framework for training, evaluation and production. + +4. Easily customize a model or an example to your needs: + - We provide examples for each architecture to reproduce the results published by its original authors. + - Model internal [SEP] +""" +``` + +Это означает, что модели будет сложно выбрать правильный ответ. Чтобы исправить это, конвейер `question-answering` позволяет нам разбить контекст на более мелкие фрагменты, указав максимальную длину. Чтобы убедиться, что мы не разбиваем контекст на фрагменты именно в том месте, которое не позволяет найти ответ, он также включает некоторое перекрытие между фрагментами. + +Мы можем заставить токенизатор (быстрый или медленный) сделать это за нас, добавив `return_overflowing_tokens=True`, и указать желаемое перекрытие с помощью аргумента `stride`. Вот пример, использующий небольшое предложение: + +```py +sentence = "This sentence is not too long but we are going to split it anyway." +inputs = tokenizer( + sentence, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 +) + +for ids in inputs["input_ids"]: + print(tokenizer.decode(ids)) +``` + +```python out +'[CLS] This sentence is not [SEP]' +'[CLS] is not too long [SEP]' +'[CLS] too long but we [SEP]' +'[CLS] but we are going [SEP]' +'[CLS] are going to split [SEP]' +'[CLS] to split it anyway [SEP]' +'[CLS] it anyway. [SEP]' +``` + +Как мы видим, предложение было разбито на части таким образом, что каждая запись в `inputs["input_ids"]` содержит не более 6 токенов (чтобы последняя запись была такого же размера, как и остальные, нам придется добавить padding), и между каждой частью есть перекрытие в 2 токена. + +Давайте посмотрим на результат токенизации: + +```py +print(inputs.keys()) +``` + +```python out +dict_keys(['input_ids', 'attention_mask', 'overflow_to_sample_mapping']) +``` + +Как и ожидалось, мы получаем идентификаторы входов и маску внимания. Последний ключ, `overflow_to_sample_mapping`, представляет собой карту, которая говорит нам, какому предложению соответствует каждый из результатов - здесь у нас есть 7 результатов, которые все происходят из (единственного) предложения, которое мы передали токенизатору: + +```py +print(inputs["overflow_to_sample_mapping"]) +``` + +```python out +[0, 0, 0, 0, 0, 0, 0] +``` + +Это более полезно, когда мы токенизируем несколько предложений вместе. Например, так: + +```py +sentences = [ + "This sentence is not too long but we are going to split it anyway.", + "This sentence is shorter but will still get split.", +] +inputs = tokenizer( + sentences, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 +) + +print(inputs["overflow_to_sample_mapping"]) +``` + +gets us: + +```python out +[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] +``` + +что означает, что первое предложение разбито на 7 частей, как и раньше, а следующие 4 части взяты из второго предложения. + +Теперь давайте вернемся к нашему длинному контексту. По умолчанию конвейер `question-answering` использует максимальную длину 384, как мы уже упоминали ранее, и stride 128, что соответствует тому, как была дообучена модель (вы можете настроить эти параметры, передав аргументы `max_seq_len` и `stride` при вызове конвейера). Таким образом, мы будем использовать эти параметры при токенизации. Мы также добавим padding (чтобы иметь образцы одинаковой длины, чтобы можно было строить тензоры), а также запросим смещения: + +```py +inputs = tokenizer( + question, + long_context, + stride=128, + max_length=384, + padding="longest", + truncation="only_second", + return_overflowing_tokens=True, + return_offsets_mapping=True, +) +``` + +Эти `inputs` будут содержать идентификаторы входов и маски внимания, которые ожидает модель, а также смещения и `overflow_to_sample_mapping`, о которых мы только что говорили. Поскольку эти два параметра не используются моделью, мы выкинем их из `inputs` (и не будем хранить карту, поскольку она здесь не нужна) перед преобразованием в тензор: + +{#if fw === 'pt'} + +```py +_ = inputs.pop("overflow_to_sample_mapping") +offsets = inputs.pop("offset_mapping") + +inputs = inputs.convert_to_tensors("pt") +print(inputs["input_ids"].shape) +``` + +```python out +torch.Size([2, 384]) +``` + +{:else} + +```py +_ = inputs.pop("overflow_to_sample_mapping") +offsets = inputs.pop("offset_mapping") + +inputs = inputs.convert_to_tensors("tf") +print(inputs["input_ids"].shape) +``` + +```python out +(2, 384) +``` + +{/if} + +Наш длинный контекст был разделен на две части, а это значит, что после того, как он пройдет через нашу модель, у нас будет два набора начальных и конечных логитов: + +```py +outputs = model(**inputs) + +start_logits = outputs.start_logits +end_logits = outputs.end_logits +print(start_logits.shape, end_logits.shape) +``` + +{#if fw === 'pt'} + +```python out +torch.Size([2, 384]) torch.Size([2, 384]) +``` + +{:else} + +```python out +(2, 384) (2, 384) +``` + +{/if} + +Как и раньше, мы сначала маскируем токены, которые не являются частью контекста, прежде чем использовать softmax. Мы также маскируем все padding токены (отмеченные маской внимания): + +{#if fw === 'pt'} + +```py +sequence_ids = inputs.sequence_ids() +# Маскируем все, кроме токенов контекста +mask = [i != 1 for i in sequence_ids] +# Демаскируем токен [CLS]. +mask[0] = False +# Маскируем все [PAD] токены +mask = torch.logical_or(torch.tensor(mask)[None], (inputs["attention_mask"] == 0)) + +start_logits[mask] = -10000 +end_logits[mask] = -10000 +``` + +{:else} + +```py +sequence_ids = inputs.sequence_ids() +# Маскируем все, кроме токенов контекста +mask = [i != 1 for i in sequence_ids] +# Демаскируем токен [CLS]. +mask[0] = False +# Маскируем все [PAD] токены +mask = tf.math.logical_or(tf.constant(mask)[None], inputs["attention_mask"] == 0) + +start_logits = tf.where(mask, -10000, start_logits) +end_logits = tf.where(mask, -10000, end_logits) +``` + +{/if} + +Затем мы можем использовать softmax для преобразования логитов в вероятности: + +{#if fw === 'pt'} + +```py +start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1) +end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1) +``` + +{:else} + +```py +start_probabilities = tf.math.softmax(start_logits, axis=-1).numpy() +end_probabilities = tf.math.softmax(end_logits, axis=-1).numpy() +``` + +{/if} + +Следующий шаг аналогичен тому, что мы делали для малого контекста, но мы повторяем его для каждого из наших двух фрагментов. Мы присваиваем оценку всем возможным фрагментам ответа, а затем выбираем фрагмент с наилучшей оценкой: + +{#if fw === 'pt'} + +```py +candidates = [] +for start_probs, end_probs in zip(start_probabilities, end_probabilities): + scores = start_probs[:, None] * end_probs[None, :] + idx = torch.triu(scores).argmax().item() + + start_idx = idx // scores.shape[1] + end_idx = idx % scores.shape[1] + score = scores[start_idx, end_idx].item() + candidates.append((start_idx, end_idx, score)) + +print(candidates) +``` + +{:else} + +```py +candidates = [] +for start_probs, end_probs in zip(start_probabilities, end_probabilities): + scores = start_probs[:, None] * end_probs[None, :] + idx = np.triu(scores).argmax().item() + + start_idx = idx // scores.shape[1] + end_idx = idx % scores.shape[1] + score = scores[start_idx, end_idx].item() + candidates.append((start_idx, end_idx, score)) + +print(candidates) +``` + +{/if} + +```python out +[(0, 18, 0.33867), (173, 184, 0.97149)] +``` + +Эти два кандидата соответствуют лучшим ответам, которые модель смогла найти в каждом фрагменте. Модель гораздо больше уверена в том, что правильный ответ находится во второй части (это хороший знак!). Теперь нам нужно сопоставить эти два диапазона токенов с диапазонами символов в контексте (для получения ответа нам нужно сопоставить только второй, но интересно посмотреть, что модель выбрала в первом фрагменте). + + + +✏️ **Попробуйте! ** Адаптируйте приведенный выше код, чтобы он возвращал оценки и промежутки для пяти наиболее вероятных ответов (в целом, а не по частям). + + + +`offsets`, которую мы взяли ранее, на самом деле является списком смещений, по одному списку на каждый фрагмент текста: + +```py +for candidate, offset in zip(candidates, offsets): + start_token, end_token, score = candidate + start_char, _ = offset[start_token] + _, end_char = offset[end_token] + answer = long_context[start_char:end_char] + result = {"answer": answer, "start": start_char, "end": end_char, "score": score} + print(result) +``` + +```python out +{'answer': '\n🤗 Transformers: State of the Art NLP', 'start': 0, 'end': 37, 'score': 0.33867} +{'answer': 'Jax, PyTorch and TensorFlow', 'start': 1892, 'end': 1919, 'score': 0.97149} +``` + +Если мы проигнорируем первый результат, то получим тот же результат, что и в нашем конвейере для этого длинного контекста - ура! + + + +✏️ **Попробуйте! ** Используйте лучшие оценки, которые вы вычислили ранее, чтобы показать пять наиболее вероятных ответов (для всего контекста, а не для каждого фрагмента). Чтобы проверить результаты, вернитесь к первому конвейеру и передайте `top_k=5` при его вызове. + + + +На этом мы завершаем наше глубокое погружение в возможности токенизатора. В следующей главе мы снова применим все это на практике, когда покажем, как дообучить модель для ряда распространенных задач NLP. diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx new file mode 100644 index 000000000..de4adfe30 --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx @@ -0,0 +1,123 @@ +# Нормализация и предварительная токенизация[[normalization-and-pre-tokenization]] + + + +Прежде чем мы более подробно рассмотрим три наиболее распространенных алгоритма токенизации подслов, используемых в моделях Transformer (Byte-Pair Encoding [BPE], WordPiece и Unigram), мы сначала рассмотрим предварительную обработку, которую каждый токенизатор применяет к тексту. Вот высокоуровневый обзор этапов конвейера токенизации: + +
+The tokenization pipeline. + +
+ +Перед тем как разбить текст на подтокены (в соответствии со выбранной моделью), токенизатор выполняет два шага: _нормализацию_ и _претокенизацию_. + +## Нормализация[[normalization]] + + + +Шаг нормализации включает в себя некоторую общую очистку, например, удаление ненужных пробельных символов, понижение регистра и/или удаление ударений. Если вы знакомы с [Unicode normalization](http://www.unicode.org/reports/tr15/) (например, NFC или NFKC), это также может быть применено токенизатором. + +У 🤗 Transformers `tokenizer` есть атрибут `backend_tokenizer`, который предоставляет доступ к базовому токенизатору из библиотеки 🤗 Tokenizers: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") +print(type(tokenizer.backend_tokenizer)) +``` + +```python out + +``` + +Атрибут `normalizer` объекта `tokenizer` имеет метод `normalize_str()`, который мы можем использовать, чтобы увидеть, как выполняется нормализация: + +```py +print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +'hello how are u?' +``` + +В этом примере, поскольку мы выбрали контрольную точку `bert-base-uncased`, нормализация применила нижний регистр и удалила ударения. + + + +✏️ **Попробуйте! ** Загрузите токенизатор из контрольной точки `bert-base-cased` и передайте ему тот же пример. Какие основные различия вы можете увидеть между версией токенизатора cased и uncased? + + + +## Предварительная токенизация[[pre-tokenization]] + + + +Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2] (/course/chapter2), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. + +Чтобы увидеть, как быстрый токенизатор выполняет предварительную токенизацию, мы можем воспользоваться методом `pre_tokenize_str()` атрибута `pre_tokenizer` объекта `tokenizer`: + +```py +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +```python out +[('Hello', (0, 5)), (',', (5, 6)), ('how', (7, 10)), ('are', (11, 14)), ('you', (16, 19)), ('?', (19, 20))] +``` + +Обратите внимание, что токенизатор уже следит за смещениями, и именно поэтому он может дать нам сопоставление смещений, которое мы использовали в предыдущем разделе. Здесь токенизатор игнорирует два пробела и заменяет их одним, но смещение перескакивает между `are` и `you`, чтобы учесть это. + +Поскольку мы используем токенизатор BERT, предварительная токенизация включает часть пробельных символов и пунктуацию. Другие токенизаторы могут иметь другие правила для этого шага. Например, если мы используем токенизатор GPT-2: + +```py +tokenizer = AutoTokenizer.from_pretrained("gpt2") +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +он также выполнит разбиение по пробельным символам и пунктуации, но сохранит пробелы и заменит их символом `Ġ`, что позволит ему восстановить исходные пробелы, если мы декодируем токены: + +```python out +[('Hello', (0, 5)), (',', (5, 6)), ('Ġhow', (6, 10)), ('Ġare', (10, 14)), ('Ġ', (14, 15)), ('Ġyou', (15, 19)), + ('?', (19, 20))] +``` + +Также обратите внимание, что в отличие от токенизатора BERT, этот токенизатор не игнорирует двойной пробел. + +В качестве последнего примера рассмотрим токенизатор T5, основанный на алгоритме SentencePiece: + +```py +tokenizer = AutoTokenizer.from_pretrained("t5-small") +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +```python out +[('▁Hello,', (0, 6)), ('▁how', (7, 10)), ('▁are', (11, 14)), ('▁you?', (16, 20))] +``` + +Как и токенизатор GPT-2, этот сохраняет пробелы и заменяет их специальным токеном (`_`), но токенизатор T5 делает разбиение только по пробелам, а не по знакам препинания. Также обратите внимание, что он по умолчанию добавляет пробел в начале предложения (перед `Hello`) и игнорирует двойной пробел между `are` и `you`. + +Теперь, когда мы немного познакомились с тем, как обрабатывают текст различные токенизаторы, можно приступить к изучению самих алгоритмов, лежащих в их основе. Мы начнем с краткого обзора широко применяемого SentencePiece; затем, в следующих трех разделах, мы рассмотрим, как работают три основных алгоритма, используемых для токенизации по подсловам. + +## SentencePiece[[sentencepiece]] + +[SentencePiece](https://github.com/google/sentencepiece) is a tokenization algorithm for the preprocessing of text that you can use with any of the models we will see in the next three sections. It considers the text as a sequence of Unicode characters, and replaces spaces with a special character, `▁`. Used in conjunction with the Unigram algorithm (see [section 7](/course/chapter7/7)), it doesn't even require a pre-tokenization step, which is very useful for languages where the space character is not used (like Chinese or Japanese). + +The other main feature of SentencePiece is *reversible tokenization*: since there is no special treatment of spaces, decoding the tokens is done simply by concatenating them and replacing the `_`s with spaces -- this results in the normalized text. As we saw earlier, the BERT tokenizer removes repeating spaces, so its tokenization is not reversible. + +## Algorithm overview[[algorithm-overview]] + +In the following sections, we'll dive into the three main subword tokenization algorithms: BPE (used by GPT-2 and others), WordPiece (used for example by BERT), and Unigram (used by T5 and others). Before we get started, here's a quick overview of how they each work. Don't hesitate to come back to this table after reading each of the next sections if it doesn't make sense to you yet. + + +Model | BPE | WordPiece | Unigram +:----:|:---:|:---------:|:------: +Training | Starts from a small vocabulary and learns rules to merge tokens | Starts from a small vocabulary and learns rules to merge tokens | Starts from a large vocabulary and learns rules to remove tokens +Training step | Merges the tokens corresponding to the most common pair | Merges the tokens corresponding to the pair with the best score based on the frequency of the pair, privileging pairs where each individual token is less frequent | Removes all the tokens in the vocabulary that will minimize the loss computed on the whole corpus +Learns | Merge rules and a vocabulary | Just a vocabulary | A vocabulary with a score for each token +Encoding | Splits a word into characters and applies the merges learned during training | Finds the longest subword starting from the beginning that is in the vocabulary, then does the same for the rest of the word | Finds the most likely split into tokens, using the scores learned during training + +Now let's dive into BPE! \ No newline at end of file diff --git a/chapters/ru/chapter6/3b.mdx b/chapters/ru/chapter6/3b.mdx index d0affbcba..555ea8fd4 100644 --- a/chapters/ru/chapter6/3b.mdx +++ b/chapters/ru/chapter6/3b.mdx @@ -1,6 +1,6 @@ -# Fast tokenizers in the QA pipeline[[fast-tokenizers-in-the-qa-pipeline]] +# Быстрые токенизаторы в QA конвейере[[fast-tokenizers-in-the-qa-pipeline]] {#if fw === 'pt'} @@ -22,7 +22,7 @@ {/if} -We will now dive into the `question-answering` pipeline and see how to leverage the offsets to grab the answer to the question at hand from the context, a bit like we did for the grouped entities in the previous section. Then we will see how we can deal with very long contexts that end up being truncated. You can skip this section if you're not interested in the question answering task. +Теперь мы погрузимся в конвейер `question-answering` и посмотрим, как использовать смещения (offsets) для получения ответа на вопрос из контекста, подобно тому, как мы делали это для сгруппированных сущностей в предыдущем разделе. Затем мы посмотрим, как работать с очень длинными контекстами, которые в итоге будут обрезаны. Вы можете пропустить этот раздел, если вас не интересует задача ответа на вопрос. {#if fw === 'pt'} @@ -34,9 +34,9 @@ We will now dive into the `question-answering` pipeline and see how to leverage {/if} -## Using the `question-answering` pipeline[[using-the-question-answering-pipeline]] +## Использование конвейера `question-answering`[[using-the-question-answering-pipeline]] -As we saw in [Chapter 1](/course/chapter1), we can use the `question-answering` pipeline like this to get the answer to a question: +Как мы видели в [Главе 1](/course/chapter1), для получения ответа на вопрос мы можем использовать конвейер `question-answering` следующим образом: ```py from transformers import pipeline @@ -57,7 +57,7 @@ question_answerer(question=question, context=context) 'answer': 'Jax, PyTorch and TensorFlow'} ``` -Unlike the other pipelines, which can't truncate and split texts that are longer than the maximum length accepted by the model (and thus may miss information at the end of a document), this pipeline can deal with very long contexts and will return the answer to the question even if it's at the end: +В отличие от других конвейеров, которые не могут обрезать и разбивать на части тексты, длина которых превышает максимально допустимую моделью (и поэтому могут пропустить информацию в конце документа), этот конвейер может работать с очень длинными контекстами и вернет ответ на вопрос, даже если он находится в конце: ```py long_context = """ @@ -107,11 +107,11 @@ question_answerer(question=question, context=long_context) 'answer': 'Jax, PyTorch and TensorFlow'} ``` -Let's see how it does all of this! +Давайте посмотрим, как он справится со всем этим! -## Using a model for question answering[[using-a-model-for-question-answering]] +## Использование модели для ответа на вопросы[[using-a-model-for-question-answering]] -Like with any other pipeline, we start by tokenizing our input and then send it through the model. The checkpoint used by default for the `question-answering` pipeline is [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) (the "squad" in the name comes from the dataset on which the model was fine-tuned; we'll talk more about the SQuAD dataset in [Chapter 7](/course/chapter7/7)): +Как и в любом другом конвейере, мы начинаем с токенизации входных данных, а затем отправляем их через модель. По умолчанию для конвейера `question-answering` используется контрольная точка [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) (слово "squad" в названии происходит от набора данных, на котором дообучили модель; подробнее о наборе данных SQuAD мы поговорим в [главе 7](/course/chapter7/7)): {#if fw === 'pt'} @@ -141,14 +141,14 @@ outputs = model(**inputs) {/if} -Note that we tokenize the question and the context as a pair, with the question first. +Обратите внимание, что мы токенизируем вопрос и контекст как пару, причем вопрос стоит первым.
An example of tokenization of question and context
-Models for question answering work a little differently from the models we've seen up to now. Using the picture above as an example, the model has been trained to predict the index of the token starting the answer (here 21) and the index of the token where the answer ends (here 24). This is why those models don't return one tensor of logits but two: one for the logits corresponding to the start token of the answer, and one for the logits corresponding to the end token of the answer. Since in this case we have only one input containing 66 tokens, we get: +Модели для ответов на вопросы работают немного иначе, чем модели, которые мы рассматривали до сих пор. На примере картинки выше модель была обучена предсказывать индекс токена, с которого начинается ответ (здесь 21), и индекс токена, на котором ответ заканчивается (здесь 24). Вот почему эти модели возвращают не один тензор логитов, а два: один для логитов, соответствующих начальному токену ответа, и один для логитов, соответствующих конечному токену ответа. Поскольку в данном случае у нас только один вход, содержащий 66 токенов, мы получаем: ```py start_logits = outputs.start_logits @@ -170,9 +170,9 @@ torch.Size([1, 66]) torch.Size([1, 66]) {/if} -To convert those logits into probabilities, we will apply a softmax function -- but before that, we need to make sure we mask the indices that are not part of the context. Our input is `[CLS] question [SEP] context [SEP]`, so we need to mask the tokens of the question as well as the `[SEP]` token. We'll keep the `[CLS]` token, however, as some models use it to indicate that the answer is not in the context. +Чтобы преобразовать эти логиты в вероятности, мы применим функцию softmax, но перед этим нам нужно убедиться, что мы маскируем индексы, которые не являются частью контекста. Наш вход - `[CLS] вопрос [SEP] контекст [SEP]`, поэтому нам нужно замаскировать токены вопроса, а также токен `[SEP]`. Однако мы оставим токен `[CLS]`, поскольку некоторые модели используют его для указания на то, что ответ не находится в контексте. -Since we will apply a softmax afterward, we just need to replace the logits we want to mask with a large negative number. Here, we use `-10000`: +Поскольку впоследствии мы будем применять softmax, нам просто нужно заменить логиты, которые мы хотим замаскировать, на большое отрицательное число. Здесь мы используем `-10000`: {#if fw === 'pt'} @@ -180,9 +180,9 @@ Since we will apply a softmax afterward, we just need to replace the logits we w import torch sequence_ids = inputs.sequence_ids() -# Mask everything apart from the tokens of the context +# Маскируем все, кроме токенов контекста mask = [i != 1 for i in sequence_ids] -# Unmask the [CLS] token +# Демаскируем токен [CLS] mask[0] = False mask = torch.tensor(mask)[None] @@ -196,9 +196,9 @@ end_logits[mask] = -10000 import tensorflow as tf sequence_ids = inputs.sequence_ids() -# Mask everything apart from the tokens of the context +# Маскируем все, кроме токенов контекста mask = [i != 1 for i in sequence_ids] -# Unmask the [CLS] token +# Демаскируем токен [CLS] mask[0] = False mask = tf.constant(mask)[None] @@ -208,7 +208,7 @@ end_logits = tf.where(mask, -10000, end_logits) {/if} -Now that we have properly masked the logits corresponding to positions we don't want to predict, we can apply the softmax: +Теперь, когда мы правильно замаскировали логиты, соответствующие позициям, которые мы не хотим предсказывать, мы можем применить softmax: {#if fw === 'pt'} @@ -226,15 +226,15 @@ end_probabilities = tf.math.softmax(end_logits, axis=-1)[0].numpy() {/if} -At this stage, we could take the argmax of the start and end probabilities -- but we might end up with a start index that is greater than the end index, so we need to take a few more precautions. We will compute the probabilities of each possible `start_index` and `end_index` where `start_index <= end_index`, then take the tuple `(start_index, end_index)` with the highest probability. +На этом этапе мы могли бы взять argmax вероятностей начала и конца - но в итоге мы можем получить начальный индекс, который больше конечного, поэтому нам нужно принять еще несколько мер предосторожности. Мы вычислим вероятности каждого возможного `start_index` и `end_index`, где `start_index <= end_index`, а затем возьмем кортеж `(start_index, end_index)` с наибольшей вероятностью. -Assuming the events "The answer starts at `start_index`" and "The answer ends at `end_index`" to be independent, the probability that the answer starts at `start_index` and ends at `end_index` is: +Если предположить, что события "Ответ начинается на `start_index`" и "Ответ заканчивается на `end_index`" независимы, то вероятность того, что ответ начинается на `start_index` и заканчивается на `end_index`, равна: $$\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]$$ -So, to compute all the scores, we just need to compute all the products \\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\) where `start_index <= end_index`. +Таким образом, чтобы вычислить все оценки, нам нужно просто вычислить все произведения \\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\) где `start_index <= end_index`. -First let's compute all the possible products: +Сначала вычислим все возможные произведения: ```py scores = start_probabilities[:, None] * end_probabilities[None, :] @@ -242,7 +242,7 @@ scores = start_probabilities[:, None] * end_probabilities[None, :] {#if fw === 'pt'} -Then we'll mask the values where `start_index > end_index` by setting them to `0` (the other probabilities are all positive numbers). The `torch.triu()` function returns the upper triangular part of the 2D tensor passed as an argument, so it will do that masking for us: +Затем мы замаскируем значения, где `start_index > end_index`, установив для них значение `0` (все остальные вероятности - положительные числа). Функция `torch.triu()` возвращает верхнюю треугольную часть двумерного тензора, переданного в качестве аргумента, поэтому она сделает эту маскировку за нас: ```py scores = torch.triu(scores) @@ -250,7 +250,7 @@ scores = torch.triu(scores) {:else} -Then we'll mask the values where `start_index > end_index` by setting them to `0` (the other probabilities are all positive numbers). The `np.triu()` function returns the upper triangular part of the 2D tensor passed as an argument, so it will do that masking for us: +Затем мы замаскируем значения, где `start_index > end_index`, установив для них значение `0` (все остальные вероятности - положительные числа). Функция `np.triu()` возвращает верхнюю треугольную часть двумерного тензора, переданного в качестве аргумента, поэтому она сделает эту маскировку за нас: ```py import numpy as np @@ -260,7 +260,7 @@ scores = np.triu(scores) {/if} -Now we just have to get the index of the maximum. Since PyTorch will return the index in the flattened tensor, we need to use the floor division `//` and modulus `%` operations to get the `start_index` and `end_index`: +Теперь нам осталось получить индекс максимума. Поскольку PyTorch вернет индекс в плоском тензоре, для получения `start_index` и `end_index` нам нужно воспользоваться операциями получения целой части `//` и остатка `%` от деления: ```py max_index = scores.argmax().item() @@ -269,7 +269,7 @@ end_index = max_index % scores.shape[1] print(scores[start_index, end_index]) ``` -We're not quite done yet, but at least we already have the correct score for the answer (you can check this by comparing it to the first result in the previous section): +Мы еще не закончили, но, по крайней мере, у нас уже есть корректная оценка ответа (вы можете проверить это, сравнив ее с первым результатом в предыдущем разделе): ```python out 0.97773 @@ -277,11 +277,11 @@ We're not quite done yet, but at least we already have the correct score for the -✏️ **Try it out!** Compute the start and end indices for the five most likely answers. +✏️ **Попробуйте!** Вычислите начальный и конечный индексы для пяти наиболее вероятных ответов. -We have the `start_index` and `end_index` of the answer in terms of tokens, so now we just need to convert to the character indices in the context. This is where the offsets will be super useful. We can grab them and use them like we did in the token classification task: +У нас есть `start_index` и `end_index` ответа в терминах токенов, так что теперь нам просто нужно преобразовать их в индексы символов в контексте. Именно здесь смещения будут очень полезны. Мы можем захватить их и использовать, как мы это делали в задаче token classification: ```py inputs_with_offsets = tokenizer(question, context, return_offsets_mapping=True) @@ -292,7 +292,7 @@ _, end_char = offsets[end_index] answer = context[start_char:end_char] ``` -Now we just have to format everything to get our result: +Осталось только отформатировать все, чтобы получить результат: ```py result = { @@ -311,17 +311,17 @@ print(result) 'score': 0.97773} ``` -Great! That's the same as in our first example! +Отлично! Это то же самое, что и в нашем первом примере! -✏️ **Try it out!** Use the best scores you computed earlier to show the five most likely answers. To check your results, go back to the first pipeline and pass in `top_k=5` when calling it. +✏️ **Попробуйте! ** Используйте лучшие оценки, которые вы вычислили ранее, чтобы показать пять наиболее вероятных ответов. Чтобы проверить результаты, вернитесь к первому конвейеру и передайте `top_k=5` при его вызове. -## Handling long contexts[[handling-long-contexts]] +## Обработка длинных контекстов[[handling-long-contexts]] -If we try to tokenize the question and long context we used as an example previously, we'll get a number of tokens higher than the maximum length used in the `question-answering` pipeline (which is 384): +Если мы попытаемся токенизировать вопрос и длинный контекст, который мы использовали в качестве примера ранее, мы получим количество токенов, превышающее максимальную длину, используемую в конвейере `question-answering` (которая составляет 384): ```py inputs = tokenizer(question, long_context) @@ -332,7 +332,7 @@ print(len(inputs["input_ids"])) 461 ``` -So, we'll need to truncate our inputs at that maximum length. There are several ways we can do this, but we don't want to truncate the question, only the context. Since the context is the second sentence, we'll use the `"only_second"` truncation strategy. The problem that arises then is that the answer to the question may not be in the truncated context. Here, for instance, we picked a question where the answer is toward the end of the context, and when we truncate it that answer is not present: +Поэтому нам нужно обрезать входные данные до максимальной длины. Есть несколько способов сделать это, но мы не хотим усекать вопрос, а только контекст. Поскольку контекст - это второе предложение, мы используем стратегию усечения `" only_second"`. Проблема, которая возникает в этом случае, заключается в том, что ответ на вопрос может не находиться в усеченном контексте. Например, здесь мы выбрали вопрос, ответ на который находится в конце контекста, а когда мы его усекаем, то этого ответа в нём нет: ```py inputs = tokenizer(question, long_context, max_length=384, truncation="only_second") @@ -375,9 +375,9 @@ Why should I use transformers? """ ``` -This means the model will have a hard time picking the correct answer. To fix this, the `question-answering` pipeline allows us to split the context into smaller chunks, specifying the maximum length. To make sure we don't split the context at exactly the wrong place to make it possible to find the answer, it also includes some overlap between the chunks. +Это означает, что модели будет сложно выбрать правильный ответ. Чтобы исправить это, конвейер `question-answering` позволяет нам разбить контекст на более мелкие фрагменты, указав максимальную длину. Чтобы убедиться, что мы не разбиваем контекст на фрагменты именно в том месте, которое не позволяет найти ответ, он также включает некоторое перекрытие между фрагментами. -We can have the tokenizer (fast or slow) do this for us by adding `return_overflowing_tokens=True`, and we can specify the overlap we want with the `stride` argument. Here is an example, using a smaller sentence: +Мы можем заставить токенизатор (быстрый или медленный) сделать это за нас, добавив `return_overflowing_tokens=True`, и указать желаемое перекрытие с помощью аргумента `stride`. Вот пример, использующий небольшое предложение: ```py sentence = "This sentence is not too long but we are going to split it anyway." @@ -399,9 +399,9 @@ for ids in inputs["input_ids"]: '[CLS] it anyway. [SEP]' ``` -As we can see, the sentence has been split into chunks in such a way that each entry in `inputs["input_ids"]` has at most 6 tokens (we would need to add padding to have the last entry be the same size as the others) and there is an overlap of 2 tokens between each of the entries. +Как мы видим, предложение было разбито на части таким образом, что каждая запись в `inputs["input_ids"]` содержит не более 6 токенов (чтобы последняя запись была такого же размера, как и остальные, нам придется добавить padding), и между каждой частью есть перекрытие в 2 токена. -Let's take a closer look at the result of the tokenization: +Давайте посмотрим на результат токенизации: ```py print(inputs.keys()) @@ -411,7 +411,7 @@ print(inputs.keys()) dict_keys(['input_ids', 'attention_mask', 'overflow_to_sample_mapping']) ``` -As expected, we get input IDs and an attention mask. The last key, `overflow_to_sample_mapping`, is a map that tells us which sentence each of the results corresponds to -- here we have 7 results that all come from the (only) sentence we passed the tokenizer: +Как и ожидалось, мы получаем идентификаторы входов и маску внимания. Последний ключ, `overflow_to_sample_mapping`, представляет собой карту, которая говорит нам, какому предложению соответствует каждый из результатов - здесь у нас есть 7 результатов, которые все происходят из (единственного) предложения, которое мы передали токенизатору: ```py print(inputs["overflow_to_sample_mapping"]) @@ -421,7 +421,7 @@ print(inputs["overflow_to_sample_mapping"]) [0, 0, 0, 0, 0, 0, 0] ``` -This is more useful when we tokenize several sentences together. For instance, this: +Это более полезно, когда мы токенизируем несколько предложений вместе. Например, так: ```py sentences = [ @@ -441,9 +441,9 @@ gets us: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] ``` -which means the first sentence is split into 7 chunks as before, and the next 4 chunks come from the second sentence. +что означает, что первое предложение разбито на 7 частей, как и раньше, а следующие 4 части взяты из второго предложения. -Now let's go back to our long context. By default the `question-answering` pipeline uses a maximum length of 384, as we mentioned earlier, and a stride of 128, which correspond to the way the model was fine-tuned (you can adjust those parameters by passing `max_seq_len` and `stride` arguments when calling the pipeline). We will thus use those parameters when tokenizing. We'll also add padding (to have samples of the same length, so we can build tensors) as well as ask for the offsets: +Теперь давайте вернемся к нашему длинному контексту. По умолчанию конвейер `question-answering` использует максимальную длину 384, как мы уже упоминали ранее, и stride 128, что соответствует тому, как была дообучена модель (вы можете настроить эти параметры, передав аргументы `max_seq_len` и `stride` при вызове конвейера). Таким образом, мы будем использовать эти параметры при токенизации. Мы также добавим padding (чтобы иметь образцы одинаковой длины, чтобы можно было строить тензоры), а также запросим смещения: ```py inputs = tokenizer( @@ -458,7 +458,7 @@ inputs = tokenizer( ) ``` -Those `inputs` will contain the input IDs and attention masks the model expects, as well as the offsets and the `overflow_to_sample_mapping` we just talked about. Since those two are not parameters used by the model, we'll pop them out of the `inputs` (and we won't store the map, since it's not useful here) before converting it to a tensor: +Эти `inputs` будут содержать идентификаторы входов и маски внимания, которые ожидает модель, а также смещения и `overflow_to_sample_mapping`, о которых мы только что говорили. Поскольку эти два параметра не используются моделью, мы выкинем их из `inputs` (и не будем хранить карту, поскольку она здесь не нужна) перед преобразованием в тензор: {#if fw === 'pt'} @@ -490,7 +490,7 @@ print(inputs["input_ids"].shape) {/if} -Our long context was split in two, which means that after it goes through our model, we will have two sets of start and end logits: +Наш длинный контекст был разделен на две части, а это значит, что после того, как он пройдет через нашу модель, у нас будет два набора начальных и конечных логитов: ```py outputs = model(**inputs) @@ -514,17 +514,17 @@ torch.Size([2, 384]) torch.Size([2, 384]) {/if} -Like before, we first mask the tokens that are not part of the context before taking the softmax. We also mask all the padding tokens (as flagged by the attention mask): +Как и раньше, мы сначала маскируем токены, которые не являются частью контекста, прежде чем использовать softmax. Мы также маскируем все padding токены (отмеченные маской внимания): {#if fw === 'pt'} ```py sequence_ids = inputs.sequence_ids() -# Mask everything apart from the tokens of the context +# Маскируем все, кроме токенов контекста mask = [i != 1 for i in sequence_ids] -# Unmask the [CLS] token +# Демаскируем токен [CLS]. mask[0] = False -# Mask all the [PAD] tokens +# Маскируем все [PAD] токены mask = torch.logical_or(torch.tensor(mask)[None], (inputs["attention_mask"] == 0)) start_logits[mask] = -10000 @@ -535,11 +535,11 @@ end_logits[mask] = -10000 ```py sequence_ids = inputs.sequence_ids() -# Mask everything apart from the tokens of the context +# Маскируем все, кроме токенов контекста mask = [i != 1 for i in sequence_ids] -# Unmask the [CLS] token +# Демаскируем токен [CLS]. mask[0] = False -# Mask all the [PAD] tokens +# Маскируем все [PAD] токены mask = tf.math.logical_or(tf.constant(mask)[None], inputs["attention_mask"] == 0) start_logits = tf.where(mask, -10000, start_logits) @@ -548,7 +548,7 @@ end_logits = tf.where(mask, -10000, end_logits) {/if} -Then we can use the softmax to convert our logits to probabilities: +Затем мы можем использовать softmax для преобразования логитов в вероятности: {#if fw === 'pt'} @@ -566,7 +566,7 @@ end_probabilities = tf.math.softmax(end_logits, axis=-1).numpy() {/if} -The next step is similar to what we did for the small context, but we repeat it for each of our two chunks. We attribute a score to all possible spans of answer, then take the span with the best score: +Следующий шаг аналогичен тому, что мы делали для малого контекста, но мы повторяем его для каждого из наших двух фрагментов. Мы присваиваем оценку всем возможным фрагментам ответа, а затем выбираем фрагмент с наилучшей оценкой: {#if fw === 'pt'} @@ -606,15 +606,15 @@ print(candidates) [(0, 18, 0.33867), (173, 184, 0.97149)] ``` -Those two candidates correspond to the best answers the model was able to find in each chunk. The model is way more confident the right answer is in the second part (which is a good sign!). Now we just have to map those two token spans to spans of characters in the context (we only need to map the second one to have our answer, but it's interesting to see what the model has picked in the first chunk). +Эти два кандидата соответствуют лучшим ответам, которые модель смогла найти в каждом фрагменте. Модель гораздо больше уверена в том, что правильный ответ находится во второй части (это хороший знак!). Теперь нам нужно сопоставить эти два диапазона токенов с диапазонами символов в контексте (для получения ответа нам нужно сопоставить только второй, но интересно посмотреть, что модель выбрала в первом фрагменте). -✏️ **Try it out!** Adapt the code above to return the scores and spans for the five most likely answers (in total, not per chunk). +✏️ **Попробуйте! ** Адаптируйте приведенный выше код, чтобы он возвращал оценки и промежутки для пяти наиболее вероятных ответов (в целом, а не по частям). -The `offsets` we grabbed earlier is actually a list of offsets, with one list per chunk of text: +`offsets`, которую мы взяли ранее, на самом деле является списком смещений, по одному списку на каждый фрагмент текста: ```py for candidate, offset in zip(candidates, offsets): @@ -631,12 +631,12 @@ for candidate, offset in zip(candidates, offsets): {'answer': 'Jax, PyTorch and TensorFlow', 'start': 1892, 'end': 1919, 'score': 0.97149} ``` -If we ignore the first result, we get the same result as our pipeline for this long context -- yay! +Если мы проигнорируем первый результат, то получим тот же результат, что и в нашем конвейере для этого длинного контекста - ура! -✏️ **Try it out!** Use the best scores you computed before to show the five most likely answers (for the whole context, not each chunk). To check your results, go back to the first pipeline and pass in `top_k=5` when calling it. +✏️ **Попробуйте! ** Используйте лучшие оценки, которые вы вычислили ранее, чтобы показать пять наиболее вероятных ответов (для всего контекста, а не для каждого фрагмента). Чтобы проверить результаты, вернитесь к первому конвейеру и передайте `top_k=5` при его вызове. -This concludes our deep dive into the tokenizer's capabilities. We will put all of this in practice again in the next chapter, when we show you how to fine-tune a model on a range of common NLP tasks. +На этом мы завершаем наше глубокое погружение в возможности токенизатора. В следующей главе мы снова применим все это на практике, когда покажем, как дообучить модель для ряда распространенных задач NLP. diff --git a/chapters/ru/chapter6/4.mdx b/chapters/ru/chapter6/4.mdx index a53611a60..de4adfe30 100644 --- a/chapters/ru/chapter6/4.mdx +++ b/chapters/ru/chapter6/4.mdx @@ -1,4 +1,4 @@ -# Normalization and pre-tokenization[[normalization-and-pre-tokenization]] +# Нормализация и предварительная токенизация[[normalization-and-pre-tokenization]] -Before we dive more deeply into the three most common subword tokenization algorithms used with Transformer models (Byte-Pair Encoding [BPE], WordPiece, and Unigram), we'll first take a look at the preprocessing that each tokenizer applies to text. Here's a high-level overview of the steps in the tokenization pipeline: +Прежде чем мы более подробно рассмотрим три наиболее распространенных алгоритма токенизации подслов, используемых в моделях Transformer (Byte-Pair Encoding [BPE], WordPiece и Unigram), мы сначала рассмотрим предварительную обработку, которую каждый токенизатор применяет к тексту. Вот высокоуровневый обзор этапов конвейера токенизации:
The tokenization pipeline.
-Before splitting a text into subtokens (according to its model), the tokenizer performs two steps: _normalization_ and _pre-tokenization_. +Перед тем как разбить текст на подтокены (в соответствии со выбранной моделью), токенизатор выполняет два шага: _нормализацию_ и _претокенизацию_. -## Normalization[[normalization]] +## Нормализация[[normalization]] -The normalization step involves some general cleanup, such as removing needless whitespace, lowercasing, and/or removing accents. If you're familiar with [Unicode normalization](http://www.unicode.org/reports/tr15/) (such as NFC or NFKC), this is also something the tokenizer may apply. +Шаг нормализации включает в себя некоторую общую очистку, например, удаление ненужных пробельных символов, понижение регистра и/или удаление ударений. Если вы знакомы с [Unicode normalization](http://www.unicode.org/reports/tr15/) (например, NFC или NFKC), это также может быть применено токенизатором. -The 🤗 Transformers `tokenizer` has an attribute called `backend_tokenizer` that provides access to the underlying tokenizer from the 🤗 Tokenizers library: +У 🤗 Transformers `tokenizer` есть атрибут `backend_tokenizer`, который предоставляет доступ к базовому токенизатору из библиотеки 🤗 Tokenizers: ```py from transformers import AutoTokenizer @@ -35,7 +35,7 @@ print(type(tokenizer.backend_tokenizer)) ``` -The `normalizer` attribute of the `tokenizer` object has a `normalize_str()` method that we can use to see how the normalization is performed: +Атрибут `normalizer` объекта `tokenizer` имеет метод `normalize_str()`, который мы можем использовать, чтобы увидеть, как выполняется нормализация: ```py print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) @@ -45,21 +45,21 @@ print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü? 'hello how are u?' ``` -In this example, since we picked the `bert-base-uncased` checkpoint, the normalization applied lowercasing and removed the accents. +В этом примере, поскольку мы выбрали контрольную точку `bert-base-uncased`, нормализация применила нижний регистр и удалила ударения. -✏️ **Try it out!** Load a tokenizer from the `bert-base-cased` checkpoint and pass the same example to it. What are the main differences you can see between the cased and uncased versions of the tokenizer? +✏️ **Попробуйте! ** Загрузите токенизатор из контрольной точки `bert-base-cased` и передайте ему тот же пример. Какие основные различия вы можете увидеть между версией токенизатора cased и uncased? -## Pre-tokenization[[pre-tokenization]] +## Предварительная токенизация[[pre-tokenization]] -As we will see in the next sections, a tokenizer cannot be trained on raw text alone. Instead, we first need to split the texts into small entities, like words. That's where the pre-tokenization step comes in. As we saw in [Chapter 2](/course/chapter2), a word-based tokenizer can simply split a raw text into words on whitespace and punctuation. Those words will be the boundaries of the subtokens the tokenizer can learn during its training. +Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2] (/course/chapter2), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. -To see how a fast tokenizer performs pre-tokenization, we can use the `pre_tokenize_str()` method of the `pre_tokenizer` attribute of the `tokenizer` object: +Чтобы увидеть, как быстрый токенизатор выполняет предварительную токенизацию, мы можем воспользоваться методом `pre_tokenize_str()` атрибута `pre_tokenizer` объекта `tokenizer`: ```py tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") @@ -69,25 +69,25 @@ tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you? [('Hello', (0, 5)), (',', (5, 6)), ('how', (7, 10)), ('are', (11, 14)), ('you', (16, 19)), ('?', (19, 20))] ``` -Notice how the tokenizer is already keeping track of the offsets, which is how it can give us the offset mapping we used in the previous section. Here the tokenizer ignores the two spaces and replaces them with just one, but the offset jumps between `are` and `you` to account for that. +Обратите внимание, что токенизатор уже следит за смещениями, и именно поэтому он может дать нам сопоставление смещений, которое мы использовали в предыдущем разделе. Здесь токенизатор игнорирует два пробела и заменяет их одним, но смещение перескакивает между `are` и `you`, чтобы учесть это. -Since we're using a BERT tokenizer, the pre-tokenization involves splitting on whitespace and punctuation. Other tokenizers can have different rules for this step. For example, if we use the GPT-2 tokenizer: +Поскольку мы используем токенизатор BERT, предварительная токенизация включает часть пробельных символов и пунктуацию. Другие токенизаторы могут иметь другие правила для этого шага. Например, если мы используем токенизатор GPT-2: ```py tokenizer = AutoTokenizer.from_pretrained("gpt2") tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") ``` -it will split on whitespace and punctuation as well, but it will keep the spaces and replace them with a `Ġ` symbol, enabling it to recover the original spaces if we decode the tokens: +он также выполнит разбиение по пробельным символам и пунктуации, но сохранит пробелы и заменит их символом `Ġ`, что позволит ему восстановить исходные пробелы, если мы декодируем токены: ```python out [('Hello', (0, 5)), (',', (5, 6)), ('Ġhow', (6, 10)), ('Ġare', (10, 14)), ('Ġ', (14, 15)), ('Ġyou', (15, 19)), ('?', (19, 20))] ``` -Also note that unlike the BERT tokenizer, this tokenizer does not ignore the double space. +Также обратите внимание, что в отличие от токенизатора BERT, этот токенизатор не игнорирует двойной пробел. -For a last example, let's have a look at the T5 tokenizer, which is based on the SentencePiece algorithm: +В качестве последнего примера рассмотрим токенизатор T5, основанный на алгоритме SentencePiece: ```py tokenizer = AutoTokenizer.from_pretrained("t5-small") @@ -98,9 +98,9 @@ tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you? [('▁Hello,', (0, 6)), ('▁how', (7, 10)), ('▁are', (11, 14)), ('▁you?', (16, 20))] ``` -Like the GPT-2 tokenizer, this one keeps spaces and replaces them with a specific token (`_`), but the T5 tokenizer only splits on whitespace, not punctuation. Also note that it added a space by default at the beginning of the sentence (before `Hello`) and ignored the double space between `are` and `you`. +Как и токенизатор GPT-2, этот сохраняет пробелы и заменяет их специальным токеном (`_`), но токенизатор T5 делает разбиение только по пробелам, а не по знакам препинания. Также обратите внимание, что он по умолчанию добавляет пробел в начале предложения (перед `Hello`) и игнорирует двойной пробел между `are` и `you`. -Now that we've seen a little of how some different tokenizers process text, we can start to explore the underlying algorithms themselves. We'll begin with a quick look at the broadly widely applicable SentencePiece; then, over the next three sections, we'll examine how the three main algorithms used for subword tokenization work. +Теперь, когда мы немного познакомились с тем, как обрабатывают текст различные токенизаторы, можно приступить к изучению самих алгоритмов, лежащих в их основе. Мы начнем с краткого обзора широко применяемого SentencePiece; затем, в следующих трех разделах, мы рассмотрим, как работают три основных алгоритма, используемых для токенизации по подсловам. ## SentencePiece[[sentencepiece]] From 6450802258c0d9098f123480be480cee36235415 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Tue, 19 Dec 2023 22:30:13 +0300 Subject: [PATCH 303/502] Fixing today's translation. --- .../.ipynb_checkpoints/3b-checkpoint.mdx | 6 +- .../.ipynb_checkpoints/4-checkpoint.mdx | 18 +- .../.ipynb_checkpoints/5-checkpoint.mdx | 360 +++++++++++++++++ .../.ipynb_checkpoints/6-checkpoint.mdx | 374 ++++++++++++++++++ chapters/ru/chapter6/3b.mdx | 6 +- chapters/ru/chapter6/4.mdx | 18 +- chapters/ru/chapter6/5.mdx | 96 ++--- chapters/ru/chapter6/6.mdx | 38 +- 8 files changed, 825 insertions(+), 91 deletions(-) create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/5-checkpoint.mdx create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx index 555ea8fd4..f7921fdb6 100644 --- a/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx +++ b/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx @@ -399,7 +399,7 @@ for ids in inputs["input_ids"]: '[CLS] it anyway. [SEP]' ``` -Как мы видим, предложение было разбито на части таким образом, что каждая запись в `inputs["input_ids"]` содержит не более 6 токенов (чтобы последняя запись была такого же размера, как и остальные, нам придется добавить padding), и между каждой частью есть перекрытие в 2 токена. +Как мы видим, предложение было разбито на части таким образом, что каждая запись в `inputs["input_ids"]` содержит не более 6 токенов (чтобы последняя запись была такого же размера, как и остальные, нам придется добавить дополняющие токены (padding tokens)), и между каждой частью есть перекрытие в 2 токена. Давайте посмотрим на результат токенизации: @@ -443,7 +443,7 @@ gets us: что означает, что первое предложение разбито на 7 частей, как и раньше, а следующие 4 части взяты из второго предложения. -Теперь давайте вернемся к нашему длинному контексту. По умолчанию конвейер `question-answering` использует максимальную длину 384, как мы уже упоминали ранее, и stride 128, что соответствует тому, как была дообучена модель (вы можете настроить эти параметры, передав аргументы `max_seq_len` и `stride` при вызове конвейера). Таким образом, мы будем использовать эти параметры при токенизации. Мы также добавим padding (чтобы иметь образцы одинаковой длины, чтобы можно было строить тензоры), а также запросим смещения: +Теперь давайте вернемся к нашему длинному контексту. По умолчанию конвейер `question-answering` использует максимальную длину 384, как мы уже упоминали ранее, и stride 128, что соответствует тому, как была дообучена модель (вы можете настроить эти параметры, передав аргументы `max_seq_len` и `stride` при вызове конвейера). Таким образом, мы будем использовать эти параметры при токенизации. Мы также добавим дополняющие токены (padding tokens) (чтобы иметь образцы одинаковой длины, чтобы можно было строить тензоры), а также запросим смещения: ```py inputs = tokenizer( @@ -514,7 +514,7 @@ torch.Size([2, 384]) torch.Size([2, 384]) {/if} -Как и раньше, мы сначала маскируем токены, которые не являются частью контекста, прежде чем использовать softmax. Мы также маскируем все padding токены (отмеченные маской внимания): +Как и раньше, мы сначала маскируем токены, которые не являются частью контекста, прежде чем использовать softmax. Мы также маскируем все дополняющие токены (padding tokens) (отмеченные маской внимания): {#if fw === 'pt'} diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx index de4adfe30..75706fdde 100644 --- a/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx +++ b/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx @@ -104,20 +104,20 @@ tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you? ## SentencePiece[[sentencepiece]] -[SentencePiece](https://github.com/google/sentencepiece) is a tokenization algorithm for the preprocessing of text that you can use with any of the models we will see in the next three sections. It considers the text as a sequence of Unicode characters, and replaces spaces with a special character, `▁`. Used in conjunction with the Unigram algorithm (see [section 7](/course/chapter7/7)), it doesn't even require a pre-tokenization step, which is very useful for languages where the space character is not used (like Chinese or Japanese). +[SentencePiece](https://github.com/google/sentencepiece) - это алгоритм токенизации для предварительной обработки текста, который можно использовать с любой из моделей, которые мы рассмотрим в следующих трех разделах. Он рассматривает текст как последовательность символов Unicode и заменяет пробелы специальным символом `▁`. При использовании в сочетании с алгоритмом Unigram (см. [раздел 7](/course/chapter7/7)) он даже не требует шага предварительной токенизации, что очень полезно для языков, где символ пробела не используется (например, китайского или японского). -The other main feature of SentencePiece is *reversible tokenization*: since there is no special treatment of spaces, decoding the tokens is done simply by concatenating them and replacing the `_`s with spaces -- this results in the normalized text. As we saw earlier, the BERT tokenizer removes repeating spaces, so its tokenization is not reversible. +Другой главной особенностью SentencePiece является *обратимая токенизация*: поскольку в нем нет специальной обработки пробелов, декодирование токенов осуществляется просто путем их конкатенации и замены `_` на пробелы - в результате получается нормализованный текст. Как мы видели ранее, токенизатор BERT удаляет повторяющиеся пробелы, поэтому его токенизация не является обратимой. -## Algorithm overview[[algorithm-overview]] +## Обзор алгоритма[[algorithm-overview]] -In the following sections, we'll dive into the three main subword tokenization algorithms: BPE (used by GPT-2 and others), WordPiece (used for example by BERT), and Unigram (used by T5 and others). Before we get started, here's a quick overview of how they each work. Don't hesitate to come back to this table after reading each of the next sections if it doesn't make sense to you yet. +В следующих разделах мы рассмотрим три основных алгоритма токенизации по подсловам: BPE (используется в GPT-2 и других моделях), WordPiece (используется, например, в BERT) и Unigram (используется в T5 и других моделях). Прежде чем мы приступим, вот краткий обзор того, как работает каждый из них. Не стесняйтесь возвращаться к этой таблице после прочтения каждого из следующих разделов, если вам еще не все понятно. Model | BPE | WordPiece | Unigram :----:|:---:|:---------:|:------: -Training | Starts from a small vocabulary and learns rules to merge tokens | Starts from a small vocabulary and learns rules to merge tokens | Starts from a large vocabulary and learns rules to remove tokens -Training step | Merges the tokens corresponding to the most common pair | Merges the tokens corresponding to the pair with the best score based on the frequency of the pair, privileging pairs where each individual token is less frequent | Removes all the tokens in the vocabulary that will minimize the loss computed on the whole corpus -Learns | Merge rules and a vocabulary | Just a vocabulary | A vocabulary with a score for each token -Encoding | Splits a word into characters and applies the merges learned during training | Finds the longest subword starting from the beginning that is in the vocabulary, then does the same for the rest of the word | Finds the most likely split into tokens, using the scores learned during training +Обучение | Начинается с маленького словаря и изучает правила слияния токенов | Начинается с маленького словаря и изучает правила слияния токенов | Начинается с большого словаря и изучает правила удаления токенов +Шаг обучения | Объединяет токены, соответствующие наиболее часто встречающейся паре | Объединяет токены, соответствующие паре с наилучшей оценкой, основанной на частоте пары, отдавая предпочтение парам, где каждый отдельный токен встречается реже | Удаляет все токены в словаре, что минимизирует потери, вычисленные для всего корпуса. +Обучение | Слияние правил и словаря | Только словарь | Словарь с оценкой каждого токена +Кодирование | Разбивает слово на символы и применяет слияния, полученные во время обучения | Находит самое длинное подслово, начиная с начала, которое есть в словаре, затем делает то же самое для остальной части слова | Находит наиболее вероятное разбиение на токены, используя оценки, полученные во время обучения -Now let's dive into BPE! \ No newline at end of file +А теперь давайте погрузимся в BPE! \ No newline at end of file diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/5-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/5-checkpoint.mdx new file mode 100644 index 000000000..f28641f59 --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/5-checkpoint.mdx @@ -0,0 +1,360 @@ +# Токенизация Byte-Pair Encoding[[byte-pair-encoding-tokenization]] + + + +Byte-Pair Encoding (BPE) изначально была разработана как алгоритм для сжатия текстов, а затем использовалась OpenAI для токенизации при предварительном обучении модели GPT. Она используется во многих моделях трансформеров, включая GPT, GPT-2, RoBERTa, BART и DeBERTa. + + + + + +💡 В этом разделе подробно рассматривается BPE, вплоть до демонстрации полной реализации. Вы можете пропустить этот раздел, если вам нужен только общий обзор алгоритма токенизации. + + + +## Алгоритм обучения[[training-algorithm]] + +Обучение BPE начинается с вычисления уникального набора слов, используемых в корпусе (после завершения этапов нормализации и предварительной токенизации), затем создается словарь, в который заносятся все символы, используемые для записи этих слов. В качестве очень простого примера предположим, что в нашем корпусе используются следующие пять слов: + +``` +"hug", "pug", "pun", "bun", "hugs" +``` + +Тогда базовым словарем будет `["b", "g", "h", "n", "p", "s", "u"]`. В реальном мире этот базовый словарь будет содержать, как минимум, все символы ASCII, а возможно, и некоторые символы Unicode. Если в примере, который вы обрабатываете, используется символ, которого нет в обучающем корпусе, этот символ будет преобразован в неизвестный токен. Это одна из причин, по которой многие модели NLP очень плохо анализируют контент с эмоджи, например. + + + +Токенизаторы GPT-2 и RoBERTa (которые довольно похожи) имеют умный способ решения этой проблемы: они рассматривают слова не как символы Unicode, а как байты. Таким образом, базовый словарь имеет небольшой размер (256), но все символы, которые вы можете придумать, все равно будут включены и не будут преобразованы в неизвестный токен. Этот трюк называется *byte-level BPE*. + + + +После получения базового словаря мы добавляем новые токены, пока не достигнем желаемого объема словаря, обучаясь *слияниям*, которые представляют собой правила слияния двух элементов существующего словаря в новый. Таким образом, в начале эти слияния будут создавать токены с двумя символами, а затем, по мере обучения, более длинные подслова. + +На любом шаге обучения токенизатора алгоритм BPE будет искать наиболее частую пару существующих токенов (под "парой" здесь понимаются два последовательных токена в слове). Эта наиболее часто встречающаяся пара и будет объединена, после чего все повторяется для следующего шага. + +Возвращаясь к нашему предыдущему примеру, предположим, что слова имеют следующую частоту: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +значение `" hug"` встречалось в корпусе 10 раз, `"pug"` - 5 раз, `"pun"` - 12 раз, `"bun"` - 4 раза, и `"hugs"` - 5 раз. Мы начинаем обучение с разбиения каждого слова на части символов (те, которые формируют наш начальный словарь), чтобы мы могли рассматривать каждое слово как список токенов: + +``` +("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5) +``` + +Затем мы посмотрим на пары. Пара `("h", "u")` присутствует в словах `"hug"` и `"hugs"`, всего 15 раз в корпусе. Однако это не самая частая пара: эта честь принадлежит `("u", "g")`, которая присутствует в словах `"hug"`, `"pug"` и `"hugs"`, в общей сложности 20 раз в словаре. + +Таким образом, первое правило слияния, выученное токенизатором, - `("u", "g") -> "ug"`, что означает, что `"ug"` будет добавлено в словарь, и эта пара должна быть объединена во всех словах корпуса. В конце этого этапа словарь и корпус выглядят следующим образом: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug"] +Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5) +``` + +Теперь у нас есть несколько пар, в результате которых получается токен длиннее двух символов: например, пара `("h", "ug")` (встречается в корпусе 15 раз). Самая частая пара на этом этапе - `("u", "n")`, однако она встречается в корпусе 16 раз, поэтому второе выученное правило слияния - `("u", "n") -> "un"`. Добавив это в словарь и объединив все существующие вхождения, мы получаем: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un"] +Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("h" "ug" "s", 5) +``` + +Теперь наиболее частой парой является `("h", "ug")`, поэтому мы изучаем правило слияния `("h", "ug") -> "hug"`, что дает нам первый трехбуквенный токен. После слияния корпус выглядит следующим образом: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"] +Corpus: ("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5) +``` + +И продолжаем в том же духе, пока не достигнем желаемого размера словаря. + + + +✏️ **Теперь ваша очередь!** Как вы думаете, каким будет следующее правило слияния? + + + +## Алгоритм токенизации[[tokenization-algorithm]] + +Токенизация следует за процессом обучения в том смысле, что новые входные данные подвергаются токенизации путем применения следующих шагов: + +1. Нормализация +2. Предварительная токенизация +3. Разделение слов на отдельные символы +4. Применение правил слияния, изученных по порядку, к этим частям + +Возьмем пример, который мы использовали во время обучения, с тремя выученными правилами слияния: + +``` +("u", "g") -> "ug" +("u", "n") -> "un" +("h", "ug") -> "hug" +``` + +Слово `"bug"` будет токенизировано как `["b", "ug"]`. Слово `"mug"`, однако, будет токенизировано как `["[UNK]", "ug"]`, поскольку буква `"m"` отсутствует в базовом словаре. Аналогично, слово `"thug" будет токенизировано как `["[UNK]", "hug"]`: буква `"t" отсутствует в базовом словаре, и применение правил слияния приводит сначала к слиянию `"u"` и `"g"`, а затем к слиянию `"h"` и `"ug"`. + + + +✏️ ** Теперь ваша очередь! ** Как вы думаете, как будет токенизировано слово `'unhug''? + + + +## Реализация BPE[[implementing-bpe]] + +Теперь давайте посмотрим на реализацию алгоритма BPE. Это не будет оптимизированная версия, которую вы сможете использовать на большом корпусе; мы просто хотим показать вам код, чтобы вы могли лучше понять алгоритм. + +Для начала нам нужен корпус текста, поэтому давайте создадим простой корпус с несколькими предложениями: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +Далее нам нужно предварительно токенизировать корпус в слова. Поскольку мы воспроизводим токенизатор BPE (например, GPT-2), для предварительной токенизации мы будем использовать токенизатор `gpt2`: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("gpt2") +``` + +Затем мы вычисляем частоту каждого слова в корпусе, как и при предварительной токенизации: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) + +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +print(word_freqs) +``` + +```python out +defaultdict(int, {'This': 3, 'Ġis': 2, 'Ġthe': 1, 'ĠHugging': 1, 'ĠFace': 1, 'ĠCourse': 1, '.': 4, 'Ġchapter': 1, + 'Ġabout': 1, 'Ġtokenization': 1, 'Ġsection': 1, 'Ġshows': 1, 'Ġseveral': 1, 'Ġtokenizer': 1, 'Ġalgorithms': 1, + 'Hopefully': 1, ',': 1, 'Ġyou': 1, 'Ġwill': 1, 'Ġbe': 1, 'Ġable': 1, 'Ġto': 1, 'Ġunderstand': 1, 'Ġhow': 1, + 'Ġthey': 1, 'Ġare': 1, 'Ġtrained': 1, 'Ġand': 1, 'Ġgenerate': 1, 'Ġtokens': 1}) +``` + +Следующий шаг - составление базового словаря, состоящего из всех символов, используемых в корпусе: + +```python +alphabet = [] + +for word in word_freqs.keys(): + for letter in word: + if letter not in alphabet: + alphabet.append(letter) +alphabet.sort() + +print(alphabet) +``` + +```python out +[ ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', + 't', 'u', 'v', 'w', 'y', 'z', 'Ġ'] +``` + +Мы также добавляем специальные токены, используемые моделью, в начало этого словаря. В случае GPT-2 единственным специальным токеном является `"<|endoftext|>"`: + +```python +vocab = ["<|endoftext|>"] + alphabet.copy() +``` + +Теперь нам нужно разделить каждое слово на отдельные символы, чтобы можно было начать обучение: + +```python +splits = {word: [c for c in word] for word in word_freqs.keys()} +``` + +Теперь, когда мы готовы к обучению, давайте напишем функцию, которая вычисляет частоту каждой пары. Нам нужно будет использовать ее на каждом шаге обучения: + +```python +def compute_pair_freqs(splits): + pair_freqs = defaultdict(int) + for word, freq in word_freqs.items(): + split = splits[word] + if len(split) == 1: + continue + for i in range(len(split) - 1): + pair = (split[i], split[i + 1]) + pair_freqs[pair] += freq + return pair_freqs +``` + +Давайте посмотрим на часть этого словаря после первых разделений: + +```python +pair_freqs = compute_pair_freqs(splits) + +for i, key in enumerate(pair_freqs.keys()): + print(f"{key}: {pair_freqs[key]}") + if i >= 5: + break +``` + +```python out +('T', 'h'): 3 +('h', 'i'): 3 +('i', 's'): 5 +('Ġ', 'i'): 2 +('Ġ', 't'): 7 +('t', 'h'): 3 +``` + +Теперь, чтобы найти наиболее часто встречающуюся пару, нужно всего лишь сделать быстрый цикл: + +```python +best_pair = "" +max_freq = None + +for pair, freq in pair_freqs.items(): + if max_freq is None or max_freq < freq: + best_pair = pair + max_freq = freq + +print(best_pair, max_freq) +``` + +```python out +('Ġ', 't') 7 +``` + +Итак, первое слияние, которое нужно выучить, это `('Ġ', 't') -> 'Ġt'`, и мы добавляем `'Ġt'` в словарь: + +```python +merges = {("Ġ", "t"): "Ġt"} +vocab.append("Ġt") +``` + +Чтобы продолжить, нам нужно применить это объединение в нашем экземпляре `splits` словаря. Давайте напишем для этого еще одну функцию: + +```python +def merge_pair(a, b, splits): + for word in word_freqs: + split = splits[word] + if len(split) == 1: + continue + + i = 0 + while i < len(split) - 1: + if split[i] == a and split[i + 1] == b: + split = split[:i] + [a + b] + split[i + 2 :] + else: + i += 1 + splits[word] = split + return splits +``` + +И мы можем посмотреть на результат первого слияния: + +```py +splits = merge_pair("Ġ", "t", splits) +print(splits["Ġtrained"]) +``` + +```python out +['Ġt', 'r', 'a', 'i', 'n', 'e', 'd'] +``` + +Теперь у нас есть все, что нужно, чтобы проитерироваться до тех пор, пока мы не выучим все слияния, которые нам нужны. Пусть размер словаря будет 50: + +```python +vocab_size = 50 + +while len(vocab) < vocab_size: + pair_freqs = compute_pair_freqs(splits) + best_pair = "" + max_freq = None + for pair, freq in pair_freqs.items(): + if max_freq is None or max_freq < freq: + best_pair = pair + max_freq = freq + splits = merge_pair(*best_pair, splits) + merges[best_pair] = best_pair[0] + best_pair[1] + vocab.append(best_pair[0] + best_pair[1]) +``` + +В результате мы выучили 19 правил слияния (исходный словарь имел размер 31 - 30 символов в алфавите плюс специальный токен): + +```py +print(merges) +``` + +```python out +{('Ġ', 't'): 'Ġt', ('i', 's'): 'is', ('e', 'r'): 'er', ('Ġ', 'a'): 'Ġa', ('Ġt', 'o'): 'Ġto', ('e', 'n'): 'en', + ('T', 'h'): 'Th', ('Th', 'is'): 'This', ('o', 'u'): 'ou', ('s', 'e'): 'se', ('Ġto', 'k'): 'Ġtok', + ('Ġtok', 'en'): 'Ġtoken', ('n', 'd'): 'nd', ('Ġ', 'is'): 'Ġis', ('Ġt', 'h'): 'Ġth', ('Ġth', 'e'): 'Ġthe', + ('i', 'n'): 'in', ('Ġa', 'b'): 'Ġab', ('Ġtoken', 'i'): 'Ġtokeni'} +``` + +А словарь состоит из специального токена, начального алфавита и всех результатов слияния: + +```py +print(vocab) +``` + +```python out +['<|endoftext|>', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', + 'p', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z', 'Ġ', 'Ġt', 'is', 'er', 'Ġa', 'Ġto', 'en', 'Th', 'This', 'ou', 'se', + 'Ġtok', 'Ġtoken', 'nd', 'Ġis', 'Ġth', 'Ġthe', 'in', 'Ġab', 'Ġtokeni'] +``` + + + +💡 Использование `train_new_from_iterator()` на том же корпусе не приведет к созданию точно такого же словаря. Это связано с тем, что при выборе наиболее частотной пары мы выбираем первую попавшуюся, в то время как библиотека 🤗 Tokenizers выбирает первую пару, основываясь на ее внутренних ID. + + + +Чтобы токенизировать новый текст, мы предварительно токенизируем его, разбиваем на части, а затем применяем все изученные правила слияния: + +```python +def tokenize(text): + pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in pre_tokenize_result] + splits = [[l for l in word] for word in pre_tokenized_text] + for pair, merge in merges.items(): + for idx, split in enumerate(splits): + i = 0 + while i < len(split) - 1: + if split[i] == pair[0] and split[i + 1] == pair[1]: + split = split[:i] + [merge] + split[i + 2 :] + else: + i += 1 + splits[idx] = split + + return sum(splits, []) +``` + +Мы можем попробовать это на любом тексте, состоящем из символов алфавита: + +```py +tokenize("This is not a token.") +``` + +```python out +['This', 'Ġis', 'Ġ', 'n', 'o', 't', 'Ġa', 'Ġtoken', '.'] +``` + + + +⚠️ Наша реализация будет выбрасывать ошибку при наличии неизвестного символа, поскольку мы ничего не сделали для их обработки. На самом деле в GPT-2 нет неизвестного токена (невозможно получить неизвестный символ при использовании BPE на уровне байтов), но здесь это может произойти, поскольку мы не включили все возможные байты в начальный словарь. Этот аспект BPE выходит за рамки данного раздела, поэтому мы опустили подробности. + + + +Вот и все об алгоритме BPE! Далее мы рассмотрим WordPiece. \ No newline at end of file diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx new file mode 100644 index 000000000..bc512fc73 --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx @@ -0,0 +1,374 @@ +# Токенизация WordPiece[[wordpiece-tokenization]] + + + +WordPiece - это алгоритм токенизации, разработанный Google для предварительного обучения BERT. Впоследствии он был повторно использован во многих моделях трансформеров, основанных на BERT, таких как DistilBERT, MobileBERT, Funnel Transformers и MPNET. Он очень похож на BPE в плане обучения, но фактическая токенизация выполняется по-другому. + + + + + +💡 В этом разделе подробно рассматривается WordPiece, вплоть до демонстрации полной реализации. Вы можете пропустить его, если вам нужен только общий обзор алгоритма токенизации. + + + +## Алгоритм обучения[[training-algorithm]] + + + +⚠️ Google никогда не предоставлял открытый доступ к своей реализации алгоритма обучения WordPiece, поэтому все вышесказанное - это наши предположения, основанные на опубликованных материалах. Возможно, они точны не на 100 %. + + + +Как и BPE, WordPiece начинает работу с небольшого словаря, включающего специальные токены, используемые моделью, и начальный алфавит. Поскольку модель идентифицирует подслова путем добавления префикса (как `##` для BERT), каждое слово первоначально разбивается на части путем добавления этого префикса ко всем символам внутри слова. Так, например, `"word"` разбивается на части следующим образом: + +``` +w ##o ##r ##d +``` + +Таким образом, начальный алфавит содержит все символы, присутствующие в начале слова, и символы, присутствующие внутри слова, которым предшествует префикс WordPiece. + +Затем, как и в случае с BPE, WordPiece изучает правила слияния. Основное отличие заключается в способе выбора пары для слияния. Вместо того чтобы выбирать наиболее частую пару, WordPiece рассчитывает оценку для каждой пары по следующей формуле: + +$$\mathrm{score} = (\mathrm{freq\_of\_pair}) / (\mathrm{freq\_of\_first\_element} \times \mathrm{freq\_of\_second\_element})$$ + +Деля частоту пары на произведение частот каждой из ее частей, алгоритм отдает предпочтение слиянию пар, отдельные части которых встречаются в словаре реже. Например, он не обязательно объединит `("un", "##able")`, даже если эта пара встречается в словаре очень часто, потому что две пары `"un"` и `"##able"`, скорее всего, встречаются в большом количестве других слов и имеют высокую частоту. Напротив, такая пара, как `("hu", "##gging")`, вероятно, будет объединена быстрее (при условии, что слово "hugging" часто встречается в словаре), поскольку `"hu"` и `"##gging"` по отдельности, скорее всего, встречаются реже. + +Давайте рассмотрим тот же словарь, который мы использовали в учебном примере BPE: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +Рабиение здесь будет следующим: + +``` +("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##g" "##s", 5) +``` + +поэтому исходный словарь будет иметь вид `["b", "h", "p", "##g", "##n", "##s", "##u"]` (если мы пока забудем о специальных токенах). Самая частая пара - `("##u", "##g")` (встречается 20 раз), но индивидуальная частота `"##u"` очень высока, поэтому ее оценка не самая высокая (она составляет 1/36). Все пары с `"##u"` фактически имеют такую же оценку (1/36), поэтому лучшую оценку получает пара `("##g", "##s")` - единственная, в которой нет `"##u"` - с оценкой 1/20, и первым выученным слиянием будет `("##g", "##s") -> ("##gs")`. + +Обратите внимание, что при слиянии мы удаляем `##` между двумя токенами, поэтому мы добавляем `"##gs"` в словарь и применяем слияние в словах корпуса: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"] +Corpus: ("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##gs", 5) +``` + +В этот момент `"##u"` находится во всех возможных парах, поэтому все они получают одинаковый балл. Допустим, в этом случае первая пара объединяется, так что `("h", "##u") -> "hu"`. Это приводит нас к: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu"] +Corpus: ("hu" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) +``` + +Затем следующую лучшую оценку разделяют `("hu", "##g")` и `("hu", "##gs")` (1/15, по сравнению с 1/21 для всех остальных пар), поэтому первая пара с наибольшей оценкой объединяется: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu", "hug"] +Corpus: ("hug", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) +``` + +и мы продолжаем так до тех пор, пока не достигнем необходимого размера словаря. + + + +✏️ ** Теперь ваша очередь! ** Каким будет следующее правило слияния? + + + +## Алгоритм токенизации[[tokenization-algorithm]] + +Tokenization differs in WordPiece and BPE in that WordPiece only saves the final vocabulary, not the merge rules learned. Starting from the word to tokenize, WordPiece finds the longest subword that is in the vocabulary, then splits on it. For instance, if we use the vocabulary learned in the example above, for the word `"hugs"` the longest subword starting from the beginning that is inside the vocabulary is `"hug"`, so we split there and get `["hug", "##s"]`. We then continue with `"##s"`, which is in the vocabulary, so the tokenization of `"hugs"` is `["hug", "##s"]`. + +With BPE, we would have applied the merges learned in order and tokenized this as `["hu", "##gs"]`, so the encoding is different. + +As another example, let's see how the word `"bugs"` would be tokenized. `"b"` is the longest subword starting at the beginning of the word that is in the vocabulary, so we split there and get `["b", "##ugs"]`. Then `"##u"` is the longest subword starting at the beginning of `"##ugs"` that is in the vocabulary, so we split there and get `["b", "##u, "##gs"]`. Finally, `"##gs"` is in the vocabulary, so this last list is the tokenization of `"bugs"`. + +When the tokenization gets to a stage where it's not possible to find a subword in the vocabulary, the whole word is tokenized as unknown -- so, for instance, `"mug"` would be tokenized as `["[UNK]"]`, as would `"bum"` (even if we can begin with `"b"` and `"##u"`, `"##m"` is not the vocabulary, and the resulting tokenization will just be `["[UNK]"]`, not `["b", "##u", "[UNK]"]`). This is another difference from BPE, which would only classify the individual characters not in the vocabulary as unknown. + + + +✏️ **Now your turn!** How will the word `"pugs"` be tokenized? + + + +## Реализация WordPiece[[implementing-wordpiece]] + +Now let's take a look at an implementation of the WordPiece algorithm. Like with BPE, this is just pedagogical, and you won't able to use this on a big corpus. + +We will use the same corpus as in the BPE example: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +First, we need to pre-tokenize the corpus into words. Since we are replicating a WordPiece tokenizer (like BERT), we will use the `bert-base-cased` tokenizer for the pre-tokenization: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Then we compute the frequencies of each word in the corpus as we do the pre-tokenization: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +word_freqs +``` + +```python out +defaultdict( + int, {'This': 3, 'is': 2, 'the': 1, 'Hugging': 1, 'Face': 1, 'Course': 1, '.': 4, 'chapter': 1, 'about': 1, + 'tokenization': 1, 'section': 1, 'shows': 1, 'several': 1, 'tokenizer': 1, 'algorithms': 1, 'Hopefully': 1, + ',': 1, 'you': 1, 'will': 1, 'be': 1, 'able': 1, 'to': 1, 'understand': 1, 'how': 1, 'they': 1, 'are': 1, + 'trained': 1, 'and': 1, 'generate': 1, 'tokens': 1}) +``` + +As we saw before, the alphabet is the unique set composed of all the first letters of words, and all the other letters that appear in words prefixed by `##`: + +```python +alphabet = [] +for word in word_freqs.keys(): + if word[0] not in alphabet: + alphabet.append(word[0]) + for letter in word[1:]: + if f"##{letter}" not in alphabet: + alphabet.append(f"##{letter}") + +alphabet.sort() +alphabet + +print(alphabet) +``` + +```python out +['##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', '##l', '##m', '##n', '##o', '##p', '##r', '##s', + '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', + 'w', 'y'] +``` + +We also add the special tokens used by the model at the beginning of that vocabulary. In the case of BERT, it's the list `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]`: + +```python +vocab = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] + alphabet.copy() +``` + +Next we need to split each word, with all the letters that are not the first prefixed by `##`: + +```python +splits = { + word: [c if i == 0 else f"##{c}" for i, c in enumerate(word)] + for word in word_freqs.keys() +} +``` + +Now that we are ready for training, let's write a function that computes the score of each pair. We'll need to use this at each step of the training: + +```python +def compute_pair_scores(splits): + letter_freqs = defaultdict(int) + pair_freqs = defaultdict(int) + for word, freq in word_freqs.items(): + split = splits[word] + if len(split) == 1: + letter_freqs[split[0]] += freq + continue + for i in range(len(split) - 1): + pair = (split[i], split[i + 1]) + letter_freqs[split[i]] += freq + pair_freqs[pair] += freq + letter_freqs[split[-1]] += freq + + scores = { + pair: freq / (letter_freqs[pair[0]] * letter_freqs[pair[1]]) + for pair, freq in pair_freqs.items() + } + return scores +``` + +Let's have a look at a part of this dictionary after the initial splits: + +```python +pair_scores = compute_pair_scores(splits) +for i, key in enumerate(pair_scores.keys()): + print(f"{key}: {pair_scores[key]}") + if i >= 5: + break +``` + +```python out +('T', '##h'): 0.125 +('##h', '##i'): 0.03409090909090909 +('##i', '##s'): 0.02727272727272727 +('i', '##s'): 0.1 +('t', '##h'): 0.03571428571428571 +('##h', '##e'): 0.011904761904761904 +``` + +Now, finding the pair with the best score only takes a quick loop: + +```python +best_pair = "" +max_score = None +for pair, score in pair_scores.items(): + if max_score is None or max_score < score: + best_pair = pair + max_score = score + +print(best_pair, max_score) +``` + +```python out +('a', '##b') 0.2 +``` + +So the first merge to learn is `('a', '##b') -> 'ab'`, and we add `'ab'` to the vocabulary: + +```python +vocab.append("ab") +``` + +To continue, we need to apply that merge in our `splits` dictionary. Let's write another function for this: + +```python +def merge_pair(a, b, splits): + for word in word_freqs: + split = splits[word] + if len(split) == 1: + continue + i = 0 + while i < len(split) - 1: + if split[i] == a and split[i + 1] == b: + merge = a + b[2:] if b.startswith("##") else a + b + split = split[:i] + [merge] + split[i + 2 :] + else: + i += 1 + splits[word] = split + return splits +``` + +And we can have a look at the result of the first merge: + +```py +splits = merge_pair("a", "##b", splits) +splits["about"] +``` + +```python out +['ab', '##o', '##u', '##t'] +``` + +Now we have everything we need to loop until we have learned all the merges we want. Let's aim for a vocab size of 70: + +```python +vocab_size = 70 +while len(vocab) < vocab_size: + scores = compute_pair_scores(splits) + best_pair, max_score = "", None + for pair, score in scores.items(): + if max_score is None or max_score < score: + best_pair = pair + max_score = score + splits = merge_pair(*best_pair, splits) + new_token = ( + best_pair[0] + best_pair[1][2:] + if best_pair[1].startswith("##") + else best_pair[0] + best_pair[1] + ) + vocab.append(new_token) +``` + +We can then look at the generated vocabulary: + +```py +print(vocab) +``` + +```python out +['[PAD]', '[UNK]', '[CLS]', '[SEP]', '[MASK]', '##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', + '##l', '##m', '##n', '##o', '##p', '##r', '##s', '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', + 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', 'w', 'y', 'ab', '##fu', 'Fa', 'Fac', '##ct', '##ful', '##full', '##fully', + 'Th', 'ch', '##hm', 'cha', 'chap', 'chapt', '##thm', 'Hu', 'Hug', 'Hugg', 'sh', 'th', 'is', '##thms', '##za', '##zat', + '##ut'] +``` + +As we can see, compared to BPE, this tokenizer learns parts of words as tokens a bit faster. + + + +💡 Using `train_new_from_iterator()` on the same corpus won't result in the exact same vocabulary. This is because the 🤗 Tokenizers library does not implement WordPiece for the training (since we are not completely sure of its internals), but uses BPE instead. + + + +To tokenize a new text, we pre-tokenize it, split it, then apply the tokenization algorithm on each word. That is, we look for the biggest subword starting at the beginning of the first word and split it, then we repeat the process on the second part, and so on for the rest of that word and the following words in the text: + +```python +def encode_word(word): + tokens = [] + while len(word) > 0: + i = len(word) + while i > 0 and word[:i] not in vocab: + i -= 1 + if i == 0: + return ["[UNK]"] + tokens.append(word[:i]) + word = word[i:] + if len(word) > 0: + word = f"##{word}" + return tokens +``` + +Let's test it on one word that's in the vocabulary, and another that isn't: + +```python +print(encode_word("Hugging")) +print(encode_word("HOgging")) +``` + +```python out +['Hugg', '##i', '##n', '##g'] +['[UNK]'] +``` + +Now, let's write a function that tokenizes a text: + +```python +def tokenize(text): + pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in pre_tokenize_result] + encoded_words = [encode_word(word) for word in pre_tokenized_text] + return sum(encoded_words, []) +``` + +We can try it on any text: + +```python +tokenize("This is the Hugging Face course!") +``` + +```python out +['Th', '##i', '##s', 'is', 'th', '##e', 'Hugg', '##i', '##n', '##g', 'Fac', '##e', 'c', '##o', '##u', '##r', '##s', + '##e', '[UNK]'] +``` + +That's it for the WordPiece algorithm! Now let's take a look at Unigram. diff --git a/chapters/ru/chapter6/3b.mdx b/chapters/ru/chapter6/3b.mdx index 555ea8fd4..f7921fdb6 100644 --- a/chapters/ru/chapter6/3b.mdx +++ b/chapters/ru/chapter6/3b.mdx @@ -399,7 +399,7 @@ for ids in inputs["input_ids"]: '[CLS] it anyway. [SEP]' ``` -Как мы видим, предложение было разбито на части таким образом, что каждая запись в `inputs["input_ids"]` содержит не более 6 токенов (чтобы последняя запись была такого же размера, как и остальные, нам придется добавить padding), и между каждой частью есть перекрытие в 2 токена. +Как мы видим, предложение было разбито на части таким образом, что каждая запись в `inputs["input_ids"]` содержит не более 6 токенов (чтобы последняя запись была такого же размера, как и остальные, нам придется добавить дополняющие токены (padding tokens)), и между каждой частью есть перекрытие в 2 токена. Давайте посмотрим на результат токенизации: @@ -443,7 +443,7 @@ gets us: что означает, что первое предложение разбито на 7 частей, как и раньше, а следующие 4 части взяты из второго предложения. -Теперь давайте вернемся к нашему длинному контексту. По умолчанию конвейер `question-answering` использует максимальную длину 384, как мы уже упоминали ранее, и stride 128, что соответствует тому, как была дообучена модель (вы можете настроить эти параметры, передав аргументы `max_seq_len` и `stride` при вызове конвейера). Таким образом, мы будем использовать эти параметры при токенизации. Мы также добавим padding (чтобы иметь образцы одинаковой длины, чтобы можно было строить тензоры), а также запросим смещения: +Теперь давайте вернемся к нашему длинному контексту. По умолчанию конвейер `question-answering` использует максимальную длину 384, как мы уже упоминали ранее, и stride 128, что соответствует тому, как была дообучена модель (вы можете настроить эти параметры, передав аргументы `max_seq_len` и `stride` при вызове конвейера). Таким образом, мы будем использовать эти параметры при токенизации. Мы также добавим дополняющие токены (padding tokens) (чтобы иметь образцы одинаковой длины, чтобы можно было строить тензоры), а также запросим смещения: ```py inputs = tokenizer( @@ -514,7 +514,7 @@ torch.Size([2, 384]) torch.Size([2, 384]) {/if} -Как и раньше, мы сначала маскируем токены, которые не являются частью контекста, прежде чем использовать softmax. Мы также маскируем все padding токены (отмеченные маской внимания): +Как и раньше, мы сначала маскируем токены, которые не являются частью контекста, прежде чем использовать softmax. Мы также маскируем все дополняющие токены (padding tokens) (отмеченные маской внимания): {#if fw === 'pt'} diff --git a/chapters/ru/chapter6/4.mdx b/chapters/ru/chapter6/4.mdx index de4adfe30..75706fdde 100644 --- a/chapters/ru/chapter6/4.mdx +++ b/chapters/ru/chapter6/4.mdx @@ -104,20 +104,20 @@ tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you? ## SentencePiece[[sentencepiece]] -[SentencePiece](https://github.com/google/sentencepiece) is a tokenization algorithm for the preprocessing of text that you can use with any of the models we will see in the next three sections. It considers the text as a sequence of Unicode characters, and replaces spaces with a special character, `▁`. Used in conjunction with the Unigram algorithm (see [section 7](/course/chapter7/7)), it doesn't even require a pre-tokenization step, which is very useful for languages where the space character is not used (like Chinese or Japanese). +[SentencePiece](https://github.com/google/sentencepiece) - это алгоритм токенизации для предварительной обработки текста, который можно использовать с любой из моделей, которые мы рассмотрим в следующих трех разделах. Он рассматривает текст как последовательность символов Unicode и заменяет пробелы специальным символом `▁`. При использовании в сочетании с алгоритмом Unigram (см. [раздел 7](/course/chapter7/7)) он даже не требует шага предварительной токенизации, что очень полезно для языков, где символ пробела не используется (например, китайского или японского). -The other main feature of SentencePiece is *reversible tokenization*: since there is no special treatment of spaces, decoding the tokens is done simply by concatenating them and replacing the `_`s with spaces -- this results in the normalized text. As we saw earlier, the BERT tokenizer removes repeating spaces, so its tokenization is not reversible. +Другой главной особенностью SentencePiece является *обратимая токенизация*: поскольку в нем нет специальной обработки пробелов, декодирование токенов осуществляется просто путем их конкатенации и замены `_` на пробелы - в результате получается нормализованный текст. Как мы видели ранее, токенизатор BERT удаляет повторяющиеся пробелы, поэтому его токенизация не является обратимой. -## Algorithm overview[[algorithm-overview]] +## Обзор алгоритма[[algorithm-overview]] -In the following sections, we'll dive into the three main subword tokenization algorithms: BPE (used by GPT-2 and others), WordPiece (used for example by BERT), and Unigram (used by T5 and others). Before we get started, here's a quick overview of how they each work. Don't hesitate to come back to this table after reading each of the next sections if it doesn't make sense to you yet. +В следующих разделах мы рассмотрим три основных алгоритма токенизации по подсловам: BPE (используется в GPT-2 и других моделях), WordPiece (используется, например, в BERT) и Unigram (используется в T5 и других моделях). Прежде чем мы приступим, вот краткий обзор того, как работает каждый из них. Не стесняйтесь возвращаться к этой таблице после прочтения каждого из следующих разделов, если вам еще не все понятно. Model | BPE | WordPiece | Unigram :----:|:---:|:---------:|:------: -Training | Starts from a small vocabulary and learns rules to merge tokens | Starts from a small vocabulary and learns rules to merge tokens | Starts from a large vocabulary and learns rules to remove tokens -Training step | Merges the tokens corresponding to the most common pair | Merges the tokens corresponding to the pair with the best score based on the frequency of the pair, privileging pairs where each individual token is less frequent | Removes all the tokens in the vocabulary that will minimize the loss computed on the whole corpus -Learns | Merge rules and a vocabulary | Just a vocabulary | A vocabulary with a score for each token -Encoding | Splits a word into characters and applies the merges learned during training | Finds the longest subword starting from the beginning that is in the vocabulary, then does the same for the rest of the word | Finds the most likely split into tokens, using the scores learned during training +Обучение | Начинается с маленького словаря и изучает правила слияния токенов | Начинается с маленького словаря и изучает правила слияния токенов | Начинается с большого словаря и изучает правила удаления токенов +Шаг обучения | Объединяет токены, соответствующие наиболее часто встречающейся паре | Объединяет токены, соответствующие паре с наилучшей оценкой, основанной на частоте пары, отдавая предпочтение парам, где каждый отдельный токен встречается реже | Удаляет все токены в словаре, что минимизирует потери, вычисленные для всего корпуса. +Обучение | Слияние правил и словаря | Только словарь | Словарь с оценкой каждого токена +Кодирование | Разбивает слово на символы и применяет слияния, полученные во время обучения | Находит самое длинное подслово, начиная с начала, которое есть в словаре, затем делает то же самое для остальной части слова | Находит наиболее вероятное разбиение на токены, используя оценки, полученные во время обучения -Now let's dive into BPE! \ No newline at end of file +А теперь давайте погрузимся в BPE! \ No newline at end of file diff --git a/chapters/ru/chapter6/5.mdx b/chapters/ru/chapter6/5.mdx index e877653ef..f28641f59 100644 --- a/chapters/ru/chapter6/5.mdx +++ b/chapters/ru/chapter6/5.mdx @@ -1,4 +1,4 @@ -# Byte-Pair Encoding tokenization[[byte-pair-encoding-tokenization]] +# Токенизация Byte-Pair Encoding[[byte-pair-encoding-tokenization]] -Byte-Pair Encoding (BPE) was initially developed as an algorithm to compress texts, and then used by OpenAI for tokenization when pretraining the GPT model. It's used by a lot of Transformer models, including GPT, GPT-2, RoBERTa, BART, and DeBERTa. +Byte-Pair Encoding (BPE) изначально была разработана как алгоритм для сжатия текстов, а затем использовалась OpenAI для токенизации при предварительном обучении модели GPT. Она используется во многих моделях трансформеров, включая GPT, GPT-2, RoBERTa, BART и DeBERTa. -💡 This section covers BPE in depth, going as far as showing a full implementation. You can skip to the end if you just want a general overview of the tokenization algorithm. +💡 В этом разделе подробно рассматривается BPE, вплоть до демонстрации полной реализации. Вы можете пропустить этот раздел, если вам нужен только общий обзор алгоритма токенизации. -## Training algorithm[[training-algorithm]] +## Алгоритм обучения[[training-algorithm]] -BPE training starts by computing the unique set of words used in the corpus (after the normalization and pre-tokenization steps are completed), then building the vocabulary by taking all the symbols used to write those words. As a very simple example, let's say our corpus uses these five words: +Обучение BPE начинается с вычисления уникального набора слов, используемых в корпусе (после завершения этапов нормализации и предварительной токенизации), затем создается словарь, в который заносятся все символы, используемые для записи этих слов. В качестве очень простого примера предположим, что в нашем корпусе используются следующие пять слов: ``` "hug", "pug", "pun", "bun", "hugs" ``` -The base vocabulary will then be `["b", "g", "h", "n", "p", "s", "u"]`. For real-world cases, that base vocabulary will contain all the ASCII characters, at the very least, and probably some Unicode characters as well. If an example you are tokenizing uses a character that is not in the training corpus, that character will be converted to the unknown token. That's one reason why lots of NLP models are very bad at analyzing content with emojis, for instance. +Тогда базовым словарем будет `["b", "g", "h", "n", "p", "s", "u"]`. В реальном мире этот базовый словарь будет содержать, как минимум, все символы ASCII, а возможно, и некоторые символы Unicode. Если в примере, который вы обрабатываете, используется символ, которого нет в обучающем корпусе, этот символ будет преобразован в неизвестный токен. Это одна из причин, по которой многие модели NLP очень плохо анализируют контент с эмоджи, например. -The GPT-2 and RoBERTa tokenizers (which are pretty similar) have a clever way to deal with this: they don't look at words as being written with Unicode characters, but with bytes. This way the base vocabulary has a small size (256), but every character you can think of will still be included and not end up being converted to the unknown token. This trick is called *byte-level BPE*. +Токенизаторы GPT-2 и RoBERTa (которые довольно похожи) имеют умный способ решения этой проблемы: они рассматривают слова не как символы Unicode, а как байты. Таким образом, базовый словарь имеет небольшой размер (256), но все символы, которые вы можете придумать, все равно будут включены и не будут преобразованы в неизвестный токен. Этот трюк называется *byte-level BPE*. -After getting this base vocabulary, we add new tokens until the desired vocabulary size is reached by learning *merges*, which are rules to merge two elements of the existing vocabulary together into a new one. So, at the beginning these merges will create tokens with two characters, and then, as training progresses, longer subwords. +После получения базового словаря мы добавляем новые токены, пока не достигнем желаемого объема словаря, обучаясь *слияниям*, которые представляют собой правила слияния двух элементов существующего словаря в новый. Таким образом, в начале эти слияния будут создавать токены с двумя символами, а затем, по мере обучения, более длинные подслова. -At any step during the tokenizer training, the BPE algorithm will search for the most frequent pair of existing tokens (by "pair," here we mean two consecutive tokens in a word). That most frequent pair is the one that will be merged, and we rinse and repeat for the next step. +На любом шаге обучения токенизатора алгоритм BPE будет искать наиболее частую пару существующих токенов (под "парой" здесь понимаются два последовательных токена в слове). Эта наиболее часто встречающаяся пара и будет объединена, после чего все повторяется для следующего шага. -Going back to our previous example, let's assume the words had the following frequencies: +Возвращаясь к нашему предыдущему примеру, предположим, что слова имеют следующую частоту: ``` ("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) ``` -meaning `"hug"` was present 10 times in the corpus, `"pug"` 5 times, `"pun"` 12 times, `"bun"` 4 times, and `"hugs"` 5 times. We start the training by splitting each word into characters (the ones that form our initial vocabulary) so we can see each word as a list of tokens: +значение `" hug"` встречалось в корпусе 10 раз, `"pug"` - 5 раз, `"pun"` - 12 раз, `"bun"` - 4 раза, и `"hugs"` - 5 раз. Мы начинаем обучение с разбиения каждого слова на части символов (те, которые формируют наш начальный словарь), чтобы мы могли рассматривать каждое слово как список токенов: ``` ("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5) ``` -Then we look at pairs. The pair `("h", "u")` is present in the words `"hug"` and `"hugs"`, so 15 times total in the corpus. It's not the most frequent pair, though: that honor belongs to `("u", "g")`, which is present in `"hug"`, `"pug"`, and `"hugs"`, for a grand total of 20 times in the vocabulary. +Затем мы посмотрим на пары. Пара `("h", "u")` присутствует в словах `"hug"` и `"hugs"`, всего 15 раз в корпусе. Однако это не самая частая пара: эта честь принадлежит `("u", "g")`, которая присутствует в словах `"hug"`, `"pug"` и `"hugs"`, в общей сложности 20 раз в словаре. -Thus, the first merge rule learned by the tokenizer is `("u", "g") -> "ug"`, which means that `"ug"` will be added to the vocabulary, and the pair should be merged in all the words of the corpus. At the end of this stage, the vocabulary and corpus look like this: +Таким образом, первое правило слияния, выученное токенизатором, - `("u", "g") -> "ug"`, что означает, что `"ug"` будет добавлено в словарь, и эта пара должна быть объединена во всех словах корпуса. В конце этого этапа словарь и корпус выглядят следующим образом: ``` Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug"] Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5) ``` -Now we have some pairs that result in a token longer than two characters: the pair `("h", "ug")`, for instance (present 15 times in the corpus). The most frequent pair at this stage is `("u", "n")`, however, present 16 times in the corpus, so the second merge rule learned is `("u", "n") -> "un"`. Adding that to the vocabulary and merging all existing occurrences leads us to: +Теперь у нас есть несколько пар, в результате которых получается токен длиннее двух символов: например, пара `("h", "ug")` (встречается в корпусе 15 раз). Самая частая пара на этом этапе - `("u", "n")`, однако она встречается в корпусе 16 раз, поэтому второе выученное правило слияния - `("u", "n") -> "un"`. Добавив это в словарь и объединив все существующие вхождения, мы получаем: ``` Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un"] Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("h" "ug" "s", 5) ``` -Now the most frequent pair is `("h", "ug")`, so we learn the merge rule `("h", "ug") -> "hug"`, which gives us our first three-letter token. After the merge, the corpus looks like this: +Теперь наиболее частой парой является `("h", "ug")`, поэтому мы изучаем правило слияния `("h", "ug") -> "hug"`, что дает нам первый трехбуквенный токен. После слияния корпус выглядит следующим образом: ``` Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"] Corpus: ("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5) ``` -And we continue like this until we reach the desired vocabulary size. +И продолжаем в том же духе, пока не достигнем желаемого размера словаря. -✏️ **Now your turn!** What do you think the next merge rule will be? +✏️ **Теперь ваша очередь!** Как вы думаете, каким будет следующее правило слияния? -## Tokenization algorithm[[tokenization-algorithm]] +## Алгоритм токенизации[[tokenization-algorithm]] -Tokenization follows the training process closely, in the sense that new inputs are tokenized by applying the following steps: +Токенизация следует за процессом обучения в том смысле, что новые входные данные подвергаются токенизации путем применения следующих шагов: -1. Normalization -2. Pre-tokenization -3. Splitting the words into individual characters -4. Applying the merge rules learned in order on those splits +1. Нормализация +2. Предварительная токенизация +3. Разделение слов на отдельные символы +4. Применение правил слияния, изученных по порядку, к этим частям -Let's take the example we used during training, with the three merge rules learned: +Возьмем пример, который мы использовали во время обучения, с тремя выученными правилами слияния: ``` ("u", "g") -> "ug" @@ -97,19 +97,19 @@ Let's take the example we used during training, with the three merge rules learn ("h", "ug") -> "hug" ``` -The word `"bug"` will be tokenized as `["b", "ug"]`. `"mug"`, however, will be tokenized as `["[UNK]", "ug"]` since the letter `"m"` was not in the base vocabulary. Likewise, the word `"thug"` will be tokenized as `["[UNK]", "hug"]`: the letter `"t"` is not in the base vocabulary, and applying the merge rules results first in `"u"` and `"g"` being merged and then `"h"` and `"ug"` being merged. +Слово `"bug"` будет токенизировано как `["b", "ug"]`. Слово `"mug"`, однако, будет токенизировано как `["[UNK]", "ug"]`, поскольку буква `"m"` отсутствует в базовом словаре. Аналогично, слово `"thug" будет токенизировано как `["[UNK]", "hug"]`: буква `"t" отсутствует в базовом словаре, и применение правил слияния приводит сначала к слиянию `"u"` и `"g"`, а затем к слиянию `"h"` и `"ug"`. -✏️ **Now your turn!** How do you think the word `"unhug"` will be tokenized? +✏️ ** Теперь ваша очередь! ** Как вы думаете, как будет токенизировано слово `'unhug''? -## Implementing BPE[[implementing-bpe]] +## Реализация BPE[[implementing-bpe]] -Now let's take a look at an implementation of the BPE algorithm. This won't be an optimized version you can actually use on a big corpus; we just want to show you the code so you can understand the algorithm a little bit better. +Теперь давайте посмотрим на реализацию алгоритма BPE. Это не будет оптимизированная версия, которую вы сможете использовать на большом корпусе; мы просто хотим показать вам код, чтобы вы могли лучше понять алгоритм. -First we need a corpus, so let's create a simple one with a few sentences: +Для начала нам нужен корпус текста, поэтому давайте создадим простой корпус с несколькими предложениями: ```python corpus = [ @@ -120,7 +120,7 @@ corpus = [ ] ``` -Next, we need to pre-tokenize that corpus into words. Since we are replicating a BPE tokenizer (like GPT-2), we will use the `gpt2` tokenizer for the pre-tokenization: +Далее нам нужно предварительно токенизировать корпус в слова. Поскольку мы воспроизводим токенизатор BPE (например, GPT-2), для предварительной токенизации мы будем использовать токенизатор `gpt2`: ```python from transformers import AutoTokenizer @@ -128,7 +128,7 @@ from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("gpt2") ``` -Then we compute the frequencies of each word in the corpus as we do the pre-tokenization: +Затем мы вычисляем частоту каждого слова в корпусе, как и при предварительной токенизации: ```python from collections import defaultdict @@ -151,7 +151,7 @@ defaultdict(int, {'This': 3, 'Ġis': 2, 'Ġthe': 1, 'ĠHugging': 1, 'ĠFace': 1, 'Ġthey': 1, 'Ġare': 1, 'Ġtrained': 1, 'Ġand': 1, 'Ġgenerate': 1, 'Ġtokens': 1}) ``` -The next step is to compute the base vocabulary, formed by all the characters used in the corpus: +Следующий шаг - составление базового словаря, состоящего из всех символов, используемых в корпусе: ```python alphabet = [] @@ -170,19 +170,19 @@ print(alphabet) 't', 'u', 'v', 'w', 'y', 'z', 'Ġ'] ``` -We also add the special tokens used by the model at the beginning of that vocabulary. In the case of GPT-2, the only special token is `"<|endoftext|>"`: +Мы также добавляем специальные токены, используемые моделью, в начало этого словаря. В случае GPT-2 единственным специальным токеном является `"<|endoftext|>"`: ```python vocab = ["<|endoftext|>"] + alphabet.copy() ``` -We now need to split each word into individual characters, to be able to start training: +Теперь нам нужно разделить каждое слово на отдельные символы, чтобы можно было начать обучение: ```python splits = {word: [c for c in word] for word in word_freqs.keys()} ``` -Now that we are ready for training, let's write a function that computes the frequency of each pair. We'll need to use this at each step of the training: +Теперь, когда мы готовы к обучению, давайте напишем функцию, которая вычисляет частоту каждой пары. Нам нужно будет использовать ее на каждом шаге обучения: ```python def compute_pair_freqs(splits): @@ -197,7 +197,7 @@ def compute_pair_freqs(splits): return pair_freqs ``` -Let's have a look at a part of this dictionary after the initial splits: +Давайте посмотрим на часть этого словаря после первых разделений: ```python pair_freqs = compute_pair_freqs(splits) @@ -217,7 +217,7 @@ for i, key in enumerate(pair_freqs.keys()): ('t', 'h'): 3 ``` -Now, finding the most frequent pair only takes a quick loop: +Теперь, чтобы найти наиболее часто встречающуюся пару, нужно всего лишь сделать быстрый цикл: ```python best_pair = "" @@ -235,14 +235,14 @@ print(best_pair, max_freq) ('Ġ', 't') 7 ``` -So the first merge to learn is `('Ġ', 't') -> 'Ġt'`, and we add `'Ġt'` to the vocabulary: +Итак, первое слияние, которое нужно выучить, это `('Ġ', 't') -> 'Ġt'`, и мы добавляем `'Ġt'` в словарь: ```python merges = {("Ġ", "t"): "Ġt"} vocab.append("Ġt") ``` -To continue, we need to apply that merge in our `splits` dictionary. Let's write another function for this: +Чтобы продолжить, нам нужно применить это объединение в нашем экземпляре `splits` словаря. Давайте напишем для этого еще одну функцию: ```python def merge_pair(a, b, splits): @@ -261,7 +261,7 @@ def merge_pair(a, b, splits): return splits ``` -And we can have a look at the result of the first merge: +И мы можем посмотреть на результат первого слияния: ```py splits = merge_pair("Ġ", "t", splits) @@ -272,7 +272,7 @@ print(splits["Ġtrained"]) ['Ġt', 'r', 'a', 'i', 'n', 'e', 'd'] ``` -Now we have everything we need to loop until we have learned all the merges we want. Let's aim for a vocab size of 50: +Теперь у нас есть все, что нужно, чтобы проитерироваться до тех пор, пока мы не выучим все слияния, которые нам нужны. Пусть размер словаря будет 50: ```python vocab_size = 50 @@ -290,7 +290,7 @@ while len(vocab) < vocab_size: vocab.append(best_pair[0] + best_pair[1]) ``` -As a result, we've learned 19 merge rules (the initial vocabulary had a size of 31 -- 30 characters in the alphabet, plus the special token): +В результате мы выучили 19 правил слияния (исходный словарь имел размер 31 - 30 символов в алфавите плюс специальный токен): ```py print(merges) @@ -303,7 +303,7 @@ print(merges) ('i', 'n'): 'in', ('Ġa', 'b'): 'Ġab', ('Ġtoken', 'i'): 'Ġtokeni'} ``` -And the vocabulary is composed of the special token, the initial alphabet, and all the results of the merges: +А словарь состоит из специального токена, начального алфавита и всех результатов слияния: ```py print(vocab) @@ -317,11 +317,11 @@ print(vocab) -💡 Using `train_new_from_iterator()` on the same corpus won't result in the exact same vocabulary. This is because when there is a choice of the most frequent pair, we selected the first one encountered, while the 🤗 Tokenizers library selects the first one based on its inner IDs. +💡 Использование `train_new_from_iterator()` на том же корпусе не приведет к созданию точно такого же словаря. Это связано с тем, что при выборе наиболее частотной пары мы выбираем первую попавшуюся, в то время как библиотека 🤗 Tokenizers выбирает первую пару, основываясь на ее внутренних ID. -To tokenize a new text, we pre-tokenize it, split it, then apply all the merge rules learned: +Чтобы токенизировать новый текст, мы предварительно токенизируем его, разбиваем на части, а затем применяем все изученные правила слияния: ```python def tokenize(text): @@ -341,7 +341,7 @@ def tokenize(text): return sum(splits, []) ``` -We can try this on any text composed of characters in the alphabet: +Мы можем попробовать это на любом тексте, состоящем из символов алфавита: ```py tokenize("This is not a token.") @@ -353,8 +353,8 @@ tokenize("This is not a token.") -⚠️ Our implementation will throw an error if there is an unknown character since we didn't do anything to handle them. GPT-2 doesn't actually have an unknown token (it's impossible to get an unknown character when using byte-level BPE), but this could happen here because we did not include all the possible bytes in the initial vocabulary. This aspect of BPE is beyond the scope of this section, so we've left the details out. +⚠️ Наша реализация будет выбрасывать ошибку при наличии неизвестного символа, поскольку мы ничего не сделали для их обработки. На самом деле в GPT-2 нет неизвестного токена (невозможно получить неизвестный символ при использовании BPE на уровне байтов), но здесь это может произойти, поскольку мы не включили все возможные байты в начальный словарь. Этот аспект BPE выходит за рамки данного раздела, поэтому мы опустили подробности. -That's it for the BPE algorithm! Next, we'll have a look at WordPiece. \ No newline at end of file +Вот и все об алгоритме BPE! Далее мы рассмотрим WordPiece. \ No newline at end of file diff --git a/chapters/ru/chapter6/6.mdx b/chapters/ru/chapter6/6.mdx index eb0cbddeb..bc512fc73 100644 --- a/chapters/ru/chapter6/6.mdx +++ b/chapters/ru/chapter6/6.mdx @@ -1,4 +1,4 @@ -# WordPiece tokenization[[wordpiece-tokenization]] +# Токенизация WordPiece[[wordpiece-tokenization]] -WordPiece is the tokenization algorithm Google developed to pretrain BERT. It has since been reused in quite a few Transformer models based on BERT, such as DistilBERT, MobileBERT, Funnel Transformers, and MPNET. It's very similar to BPE in terms of the training, but the actual tokenization is done differently. +WordPiece - это алгоритм токенизации, разработанный Google для предварительного обучения BERT. Впоследствии он был повторно использован во многих моделях трансформеров, основанных на BERT, таких как DistilBERT, MobileBERT, Funnel Transformers и MPNET. Он очень похож на BPE в плане обучения, но фактическая токенизация выполняется по-другому. -💡 This section covers WordPiece in depth, going as far as showing a full implementation. You can skip to the end if you just want a general overview of the tokenization algorithm. +💡 В этом разделе подробно рассматривается WordPiece, вплоть до демонстрации полной реализации. Вы можете пропустить его, если вам нужен только общий обзор алгоритма токенизации. -## Training algorithm[[training-algorithm]] +## Алгоритм обучения[[training-algorithm]] -⚠️ Google never open-sourced its implementation of the training algorithm of WordPiece, so what follows is our best guess based on the published literature. It may not be 100% accurate. +⚠️ Google никогда не предоставлял открытый доступ к своей реализации алгоритма обучения WordPiece, поэтому все вышесказанное - это наши предположения, основанные на опубликованных материалах. Возможно, они точны не на 100 %. -Like BPE, WordPiece starts from a small vocabulary including the special tokens used by the model and the initial alphabet. Since it identifies subwords by adding a prefix (like `##` for BERT), each word is initially split by adding that prefix to all the characters inside the word. So, for instance, `"word"` gets split like this: +Как и BPE, WordPiece начинает работу с небольшого словаря, включающего специальные токены, используемые моделью, и начальный алфавит. Поскольку модель идентифицирует подслова путем добавления префикса (как `##` для BERT), каждое слово первоначально разбивается на части путем добавления этого префикса ко всем символам внутри слова. Так, например, `"word"` разбивается на части следующим образом: ``` w ##o ##r ##d ``` -Thus, the initial alphabet contains all the characters present at the beginning of a word and the characters present inside a word preceded by the WordPiece prefix. +Таким образом, начальный алфавит содержит все символы, присутствующие в начале слова, и символы, присутствующие внутри слова, которым предшествует префикс WordPiece. -Then, again like BPE, WordPiece learns merge rules. The main difference is the way the pair to be merged is selected. Instead of selecting the most frequent pair, WordPiece computes a score for each pair, using the following formula: +Затем, как и в случае с BPE, WordPiece изучает правила слияния. Основное отличие заключается в способе выбора пары для слияния. Вместо того чтобы выбирать наиболее частую пару, WordPiece рассчитывает оценку для каждой пары по следующей формуле: $$\mathrm{score} = (\mathrm{freq\_of\_pair}) / (\mathrm{freq\_of\_first\_element} \times \mathrm{freq\_of\_second\_element})$$ -By dividing the frequency of the pair by the product of the frequencies of each of its parts, the algorithm prioritizes the merging of pairs where the individual parts are less frequent in the vocabulary. For instance, it won't necessarily merge `("un", "##able")` even if that pair occurs very frequently in the vocabulary, because the two pairs `"un"` and `"##able"` will likely each appear in a lot of other words and have a high frequency. In contrast, a pair like `("hu", "##gging")` will probably be merged faster (assuming the word "hugging" appears often in the vocabulary) since `"hu"` and `"##gging"` are likely to be less frequent individually. +Деля частоту пары на произведение частот каждой из ее частей, алгоритм отдает предпочтение слиянию пар, отдельные части которых встречаются в словаре реже. Например, он не обязательно объединит `("un", "##able")`, даже если эта пара встречается в словаре очень часто, потому что две пары `"un"` и `"##able"`, скорее всего, встречаются в большом количестве других слов и имеют высокую частоту. Напротив, такая пара, как `("hu", "##gging")`, вероятно, будет объединена быстрее (при условии, что слово "hugging" часто встречается в словаре), поскольку `"hu"` и `"##gging"` по отдельности, скорее всего, встречаются реже. -Let's look at the same vocabulary we used in the BPE training example: +Давайте рассмотрим тот же словарь, который мы использовали в учебном примере BPE: ``` ("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) ``` -The splits here will be: +Рабиение здесь будет следующим: ``` ("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##g" "##s", 5) ``` -so the initial vocabulary will be `["b", "h", "p", "##g", "##n", "##s", "##u"]` (if we forget about special tokens for now). The most frequent pair is `("##u", "##g")` (present 20 times), but the individual frequency of `"##u"` is very high, so its score is not the highest (it's 1 / 36). All pairs with a `"##u"` actually have that same score (1 / 36), so the best score goes to the pair `("##g", "##s")` -- the only one without a `"##u"` -- at 1 / 20, and the first merge learned is `("##g", "##s") -> ("##gs")`. +поэтому исходный словарь будет иметь вид `["b", "h", "p", "##g", "##n", "##s", "##u"]` (если мы пока забудем о специальных токенах). Самая частая пара - `("##u", "##g")` (встречается 20 раз), но индивидуальная частота `"##u"` очень высока, поэтому ее оценка не самая высокая (она составляет 1/36). Все пары с `"##u"` фактически имеют такую же оценку (1/36), поэтому лучшую оценку получает пара `("##g", "##s")` - единственная, в которой нет `"##u"` - с оценкой 1/20, и первым выученным слиянием будет `("##g", "##s") -> ("##gs")`. -Note that when we merge, we remove the `##` between the two tokens, so we add `"##gs"` to the vocabulary and apply the merge in the words of the corpus: +Обратите внимание, что при слиянии мы удаляем `##` между двумя токенами, поэтому мы добавляем `"##gs"` в словарь и применяем слияние в словах корпуса: ``` Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"] Corpus: ("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##gs", 5) ``` -At this point, `"##u"` is in all the possible pairs, so they all end up with the same score. Let's say that in this case, the first pair is merged, so `("h", "##u") -> "hu"`. This takes us to: +В этот момент `"##u"` находится во всех возможных парах, поэтому все они получают одинаковый балл. Допустим, в этом случае первая пара объединяется, так что `("h", "##u") -> "hu"`. Это приводит нас к: ``` Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu"] Corpus: ("hu" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) ``` -Then the next best score is shared by `("hu", "##g")` and `("hu", "##gs")` (with 1/15, compared to 1/21 for all the other pairs), so the first pair with the biggest score is merged: +Затем следующую лучшую оценку разделяют `("hu", "##g")` и `("hu", "##gs")` (1/15, по сравнению с 1/21 для всех остальных пар), поэтому первая пара с наибольшей оценкой объединяется: ``` Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu", "hug"] Corpus: ("hug", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) ``` -and we continue like this until we reach the desired vocabulary size. +и мы продолжаем так до тех пор, пока не достигнем необходимого размера словаря. -✏️ **Now your turn!** What will the next merge rule be? +✏️ ** Теперь ваша очередь! ** Каким будет следующее правило слияния? -## Tokenization algorithm[[tokenization-algorithm]] +## Алгоритм токенизации[[tokenization-algorithm]] Tokenization differs in WordPiece and BPE in that WordPiece only saves the final vocabulary, not the merge rules learned. Starting from the word to tokenize, WordPiece finds the longest subword that is in the vocabulary, then splits on it. For instance, if we use the vocabulary learned in the example above, for the word `"hugs"` the longest subword starting from the beginning that is inside the vocabulary is `"hug"`, so we split there and get `["hug", "##s"]`. We then continue with `"##s"`, which is in the vocabulary, so the tokenization of `"hugs"` is `["hug", "##s"]`. @@ -98,7 +98,7 @@ When the tokenization gets to a stage where it's not possible to find a subword -## Implementing WordPiece[[implementing-wordpiece]] +## Реализация WordPiece[[implementing-wordpiece]] Now let's take a look at an implementation of the WordPiece algorithm. Like with BPE, this is just pedagogical, and you won't able to use this on a big corpus. From be9d37616499cdf4305b8b883746887445c8416d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Grandury?= <57645283+mariagrandury@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:08:46 +0100 Subject: [PATCH 304/502] fix typos in Spanish translation (#511) --- chapters/en/chapter3/6.mdx | 2 +- chapters/es/chapter0/1.mdx | 4 ++-- chapters/es/chapter1/3.mdx | 4 ++-- chapters/es/chapter1/4.mdx | 16 ++++++++-------- chapters/es/chapter1/5.mdx | 2 +- chapters/es/chapter1/6.mdx | 2 +- chapters/es/chapter1/7.mdx | 4 ++-- chapters/es/chapter1/8.mdx | 2 +- chapters/es/chapter2/4.mdx | 10 +++++----- chapters/es/chapter2/6.mdx | 6 +++--- chapters/es/chapter2/7.mdx | 2 +- chapters/es/chapter2/8.mdx | 12 ++++++------ chapters/es/chapter3/2.mdx | 8 ++++---- chapters/es/chapter3/3.mdx | 2 +- chapters/es/chapter3/4.mdx | 10 +++++----- chapters/es/chapter3/6.mdx | 6 +++--- chapters/es/chapter5/1.mdx | 2 +- chapters/es/chapter5/2.mdx | 2 +- chapters/es/chapter5/3.mdx | 16 ++++++++-------- chapters/es/chapter5/4.mdx | 8 ++++---- chapters/es/chapter5/5.mdx | 10 +++++----- chapters/es/chapter5/6.mdx | 4 ++-- chapters/es/chapter5/8.mdx | 18 +++++++++--------- 23 files changed, 76 insertions(+), 76 deletions(-) diff --git a/chapters/en/chapter3/6.mdx b/chapters/en/chapter3/6.mdx index 8749edef8..89d131b58 100644 --- a/chapters/en/chapter3/6.mdx +++ b/chapters/en/chapter3/6.mdx @@ -211,7 +211,7 @@ Test what you learned in this chapter! explain: "This is what we did with Trainer, not the 🤗 Accelerate library. Try again!" }, { - text: "It makes our training loops work on distributed strategies", + text: "It makes our training loops work on distributed strategies.", explain: "Correct! With 🤗 Accelerate, your training loops will work for multiple GPUs and TPUs.", correct: true }, diff --git a/chapters/es/chapter0/1.mdx b/chapters/es/chapter0/1.mdx index efa9ef346..47b77485a 100644 --- a/chapters/es/chapter0/1.mdx +++ b/chapters/es/chapter0/1.mdx @@ -2,7 +2,7 @@ Bienvenido al curso de Hugging Face. Esta introducción te guiará en la configuración de un entorno de trabajo. Si acabas de empezar el curso, te recomendamos que primero eches un vistazo al [Capítulo 1](/course/chapter1), y luego vuelvas y configures tu entorno para poder probar el código por ti mismo. -Todas las bibliotecas que usaremos en este curso están disponibles como paquetes de Python, así que aquí te mostraremos cómo configurar un entorno de Python e instalar las bibliotecas específicas que necesitarás. +Todas las librerías que usaremos en este curso están disponibles como paquetes de Python, así que aquí te mostraremos cómo configurar un entorno de Python e instalar las librerías específicas que necesitarás. Cubriremos dos formas de configurar tu entorno de trabajo, utilizando un cuaderno Colab o un entorno virtual Python. Siéntete libre de elegir la que más te convenga. Para los principiantes, recomendamos encarecidamente que comiencen utilizando un cuaderno Colab. @@ -38,7 +38,7 @@ import transformers A gif showing the result of the two commands above: installation and import
-Esto instala una versión muy ligera de 🤗 Transformers. En particular, no se instalan frameworks específicos de deep learning (como PyTorch o TensorFlow). Dado que vamos a utilizar un montón de características diferentes de la biblioteca, se recomienda instalar la versión de desarrollo, que viene con todas las dependencias necesarias para casi cualquier caso de uso imaginable: +Esto instala una versión muy ligera de 🤗 Transformers. En particular, no se instalan frameworks específicos de deep learning (como PyTorch o TensorFlow). Dado que vamos a utilizar un montón de características diferentes de la librería, se recomienda instalar la versión de desarrollo, que viene con todas las dependencias necesarias para casi cualquier caso de uso imaginable: ``` !pip install transformers[sentencepiece] diff --git a/chapters/es/chapter1/3.mdx b/chapters/es/chapter1/3.mdx index b0b42ade6..07c6f9c46 100644 --- a/chapters/es/chapter1/3.mdx +++ b/chapters/es/chapter1/3.mdx @@ -116,7 +116,7 @@ Este pipeline se llama _zero-shot_ porque no necesitas ajustar el modelo con tus ## Generación de texto -Ahora veamos cómo usar un pipeline para generar texto. La idea es que proporciones una indicación (*prompt*) y el modelo la va a completar automáticamente al generar el texto restante. Esto es parecido a la función de texto predictivo que está presente en muchos teléfonos. La generación de texto involucra aleatóriedad, por lo que es normal que no obtengas el mismo resultado que se muestra abajo. +Ahora veamos cómo usar un pipeline para generar texto. La idea es que proporciones una indicación (*prompt*) y el modelo la va a completar automáticamente al generar el texto restante. Esto es parecido a la función de texto predictivo que está presente en muchos teléfonos. La generación de texto involucra aleatoriedad, por lo que es normal que no obtengas el mismo resultado que se muestra abajo. ```python from transformers import pipeline @@ -234,7 +234,7 @@ ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") En este caso el modelo identificó correctamente que Sylvain es una persona (PER), Hugging Face una organización (ORG) y Brooklyn una ubicación (LOC). -Pasamos la opción `grouped_entities=True` en la función de creación del pipeline para decirle que agrupe las partes de la oración que corresponden a la misma entidad: Aquí el modelo agrupó correctamente "Hugging" y "Face" como una sola organización, a pesar de que su nombre está compuesto de varias palabras. De hecho, como veremos en el siguente capítulo, el preprocesamiento puede incluso dividir palabras en partes más pequeñas. Por ejemplo, 'Sylvain' se separa en cuatro piezas: `S`, `##yl`, `##va` y`##in`. En el paso de prosprocesamiento, el pipeline reagrupa de manera exitosa dichas piezas. +Pasamos la opción `grouped_entities=True` en la función de creación del pipeline para decirle que agrupe las partes de la oración que corresponden a la misma entidad: Aquí el modelo agrupó correctamente "Hugging" y "Face" como una sola organización, a pesar de que su nombre está compuesto de varias palabras. De hecho, como veremos en el siguiente capítulo, el preprocesamiento puede incluso dividir palabras en partes más pequeñas. Por ejemplo, 'Sylvain' se separa en cuatro piezas: `S`, `##yl`, `##va` y`##in`. En el paso de prosprocesamiento, el pipeline reagrupa de manera exitosa dichas piezas. diff --git a/chapters/es/chapter1/4.mdx b/chapters/es/chapter1/4.mdx index 7d6b958b0..05bce22bc 100644 --- a/chapters/es/chapter1/4.mdx +++ b/chapters/es/chapter1/4.mdx @@ -16,7 +16,7 @@ Estos son algunos hitos en la (corta) historia de los Transformadores:
-La [arquitectura de los Transformadores](https://arxiv.org/abs/1706.03762) fue presentada por primera vez en junio de 2017. El trabajo original se enfocaba en tareas de traducción. A esto le siguó la introducción de numerosos modelos influyentes, que incluyen: +La [arquitectura de los Transformadores](https://arxiv.org/abs/1706.03762) fue presentada por primera vez en junio de 2017. El trabajo original se enfocaba en tareas de traducción. A esto le siguió la introducción de numerosos modelos influyentes, que incluyen: - **Junio de 2018**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), el primer modelo de Transformadores preentrenados, que fue usado para ajustar varias tareas de PLN y obtuvo resultados de vanguardia @@ -50,7 +50,7 @@ Un ejemplo de una tarea es predecir la palabra siguiente en una oración con bas
-Otro ejemplo es el *modelado de leguaje oculto*, en el que el modelo predice una palabra oculta en la oración. +Otro ejemplo es el *modelado de lenguaje oculto*, en el que el modelo predice una palabra oculta en la oración.
Example of masked language modeling in which a masked word from a sentence is predicted. @@ -84,7 +84,7 @@ Esta es la razón por la que compartir modelos de lenguaje es fundamental: compa -El *preentrenamiento* es el acto de entrenar un modelo desde cero: los pesos se inicializan de manera aleatória y el entrenamiento empieza sin un conocimiento previo. +El *preentrenamiento* es el acto de entrenar un modelo desde cero: los pesos se inicializan de manera aleatoria y el entrenamiento empieza sin un conocimiento previo.
The pretraining of a language model is costly in both time and money. @@ -121,7 +121,7 @@ En esta sección, revisaremos la arquitectura general del Transformador. No te p El modelo está compuesto por dos bloques: * **Codificador (izquierda)**: El codificador recibe una entrada y construye una representación de ésta (sus características). Esto significa que el modelo está optimizado para conseguir un entendimiento a partir de la entrada. -* **Decodificador (derecha)**: El decodificador usa la representacón del codificador (características) junto con otras entradas para generar una secuencia objetivo. Esto significa que el modelo está optimizado para generar salidas. +* **Decodificador (derecha)**: El decodificador usa la representación del codificador (características) junto con otras entradas para generar una secuencia objetivo. Esto significa que el modelo está optimizado para generar salidas.
Architecture of a Transformers models @@ -148,9 +148,9 @@ Ahora que tienes una idea de qué son las capas de atención, echemos un vistazo ## La arquitectura original -La arquitectura del Transformador fue diseñada originalmente para traducción. Durante el entrenamiento, el codificador recibe entradas (oraciones) en un idioma dado, mientras que el decodificador recibe las mismas oraciones en el idioma objetivo. En el codificador, las capas de atención pueden usar todas las palabras en una oración (dado que, como vimos, la traducción de una palabra dada puede ser dependiente de lo que está antes y después en la oración). Por su parte, el decodificador trabaja de manera secuencial y sólo le puede prestar atención a las palabras en la oración que ya ha traducido (es decir, sólo las palabras antes de que la palabra se ha generado). Por ejemplo, cuando hemos predecido las primeras tres palabras del objetivo de traducción se las damos al decodificador, que luego usa todas las entradas del codificador para intentar predecir la cuarta palabra. +La arquitectura del Transformador fue diseñada originalmente para traducción. Durante el entrenamiento, el codificador recibe entradas (oraciones) en un idioma dado, mientras que el decodificador recibe las mismas oraciones en el idioma objetivo. En el codificador, las capas de atención pueden usar todas las palabras en una oración (dado que, como vimos, la traducción de una palabra dada puede ser dependiente de lo que está antes y después en la oración). Por su parte, el decodificador trabaja de manera secuencial y sólo le puede prestar atención a las palabras en la oración que ya ha traducido (es decir, sólo las palabras antes de que la palabra se ha generado). Por ejemplo, cuando hemos predicho las primeras tres palabras del objetivo de traducción se las damos al decodificador, que luego usa todas las entradas del codificador para intentar predecir la cuarta palabra. -Para acelerar el entrenamiento (cuando el modelo tiene acceso a las oraciones objetivo), al decodificador se le alimenta el objetivo completo, pero no puede usar palabras futuras (si tuviera acceso a la palabra en la posición 2 cuando trata de predecir la palabra en la posición 2, ¡el problema no sería muy dificil!). Por ejemplo, al intentar predecir la cuarta palabra, la capa de atención sólo tendría acceso a las palabras en las posiciones 1 a 3. +Para acelerar el entrenamiento (cuando el modelo tiene acceso a las oraciones objetivo), al decodificador se le alimenta el objetivo completo, pero no puede usar palabras futuras (si tuviera acceso a la palabra en la posición 2 cuando trata de predecir la palabra en la posición 2, ¡el problema no sería muy difícil!). Por ejemplo, al intentar predecir la cuarta palabra, la capa de atención sólo tendría acceso a las palabras en las posiciones 1 a 3. La arquitectura original del Transformador se veía así, con el codificador a la izquierda y el decodificador a la derecha: @@ -159,13 +159,13 @@ La arquitectura original del Transformador se veía así, con el codificador a l
-Observa que la primera capa de atención en un bloque de decodificador presta atención a todas las entradas (pasadas) al decodificador, mientras que la segunda capa de atención usa la salida del codificador. De esta manera puede acceder a toda la oración de entrada para predecir de mejor manera la palabra actual. Esto es muy útil dado que diferentes idiomas pueden tener reglas gramaticales que ponen las palabras en órden distinto o algún contexto que se provee después puede ser útil para determinar la mejor traducción de una palabra dada. +Observa que la primera capa de atención en un bloque de decodificador presta atención a todas las entradas (pasadas) al decodificador, mientras que la segunda capa de atención usa la salida del codificador. De esta manera puede acceder a toda la oración de entrada para predecir de mejor manera la palabra actual. Esto es muy útil dado que diferentes idiomas pueden tener reglas gramaticales que ponen las palabras en orden distinto o algún contexto que se provee después puede ser útil para determinar la mejor traducción de una palabra dada. La *máscara de atención* también se puede usar en el codificador/decodificador para evitar que el modelo preste atención a algunas palabras especiales --por ejemplo, la palabra especial de relleno que hace que todas las entradas sean de la misma longitud cuando se agrupan oraciones. ## Arquitecturas vs. puntos de control -A medida que estudiemos a profundidad los Transformadores, verás menciones a *arquitecturas*, *puntos de control* (*checkpoints*) y *modelos*. Estos términos tienen significados ligeramentes diferentes: +A medida que estudiemos a profundidad los Transformadores, verás menciones a *arquitecturas*, *puntos de control* (*checkpoints*) y *modelos*. Estos términos tienen significados ligeramente diferentes: * **Arquitecturas**: Este es el esqueleto del modelo -- la definición de cada capa y cada operación que sucede al interior del modelo. * **Puntos de control**: Estos son los pesos que serán cargados en una arquitectura dada. diff --git a/chapters/es/chapter1/5.mdx b/chapters/es/chapter1/5.mdx index b06cb7b75..c39f00b73 100644 --- a/chapters/es/chapter1/5.mdx +++ b/chapters/es/chapter1/5.mdx @@ -9,7 +9,7 @@ Los modelos de codificadores usan únicamente el codificador del Transformador. En cada etapa, las capas de atención pueden acceder a todas las palabras de la oración inicial. Estos modelos se caracterizan generalmente por tener atención "bidireccional" y se suelen llamar modelos *auto-encoding*. -El preentrenamiento de estos modelos generalmente gira en torno a corromper de alguna manera una oración dada (por ejemplo, ocultando aleatóriamente palabras en ella) y pidiéndole al modelo que encuentre o reconstruya la oración inicial. +El preentrenamiento de estos modelos generalmente gira en torno a corromper de alguna manera una oración dada (por ejemplo, ocultando aleatoriamente palabras en ella) y pidiéndole al modelo que encuentre o reconstruya la oración inicial. Los modelos de codificadores son más adecuados para tareas que requieren un entendimiento de la oración completa, como la clasificación de oraciones, reconocimiento de entidades nombradas (y más generalmente clasificación de palabras) y respuesta extractiva a preguntas. diff --git a/chapters/es/chapter1/6.mdx b/chapters/es/chapter1/6.mdx index 3cc3f9afb..653531431 100644 --- a/chapters/es/chapter1/6.mdx +++ b/chapters/es/chapter1/6.mdx @@ -7,7 +7,7 @@ -Los modelos de decodificadores usan únicamente el decodificador del Transformador. En cada etapa, para una palabra dada las capas de atención pueden acceder sólamente a las palabras que se ubican antes en la oración. Estos modelos se suelen llamar modelos *auto-regressive*. +Los modelos de decodificadores usan únicamente el decodificador del Transformador. En cada etapa, para una palabra dada las capas de atención pueden acceder solamente a las palabras que se ubican antes en la oración. Estos modelos se suelen llamar modelos *auto-regressive*. El preentrenamiento de los modelos de decodificadores generalmente gira en torno a la predicción de la siguiente palabra en la oración. diff --git a/chapters/es/chapter1/7.mdx b/chapters/es/chapter1/7.mdx index 0d48876a1..265781853 100644 --- a/chapters/es/chapter1/7.mdx +++ b/chapters/es/chapter1/7.mdx @@ -2,9 +2,9 @@ -Los modelos codificador/decodificador (tambén llamados *modelos secuencia a secuencia*) usan ambas partes de la arquitectura del Transformador. En cada etapa, las capas de atención del codificador pueden acceder a todas las palabras de la sencuencia inicial, mientras que las capas de atención del decodificador sólo pueden acceder a las palabras que se ubican antes de una palabra dada en el texto de entrada. +Los modelos codificador/decodificador (también llamados *modelos secuencia a secuencia*) usan ambas partes de la arquitectura del Transformador. En cada etapa, las capas de atención del codificador pueden acceder a todas las palabras de la secuencia inicial, mientras que las capas de atención del decodificador sólo pueden acceder a las palabras que se ubican antes de una palabra dada en el texto de entrada. -El preentrenamiento de estos modelos se puede hacer usando los objetivos de los modelos de codificadores o decodificadores, pero usualmente implican algo más complejo. Por ejemplo, [T5](https://huggingface.co/t5-base) está preentrenado al reemplazar segmentos aleatórios de texto (que pueden contener varias palabras) con una palabra especial que las oculta, y el objetivo es predecir el texto que esta palabra reemplaza. +El preentrenamiento de estos modelos se puede hacer usando los objetivos de los modelos de codificadores o decodificadores, pero usualmente implican algo más complejo. Por ejemplo, [T5](https://huggingface.co/t5-base) está preentrenado al reemplazar segmentos aleatorios de texto (que pueden contener varias palabras) con una palabra especial que las oculta, y el objetivo es predecir el texto que esta palabra reemplaza. Los modelos secuencia a secuencia son más adecuados para tareas relacionadas con la generación de nuevas oraciones dependiendo de una entrada dada, como resumir, traducir o responder generativamente preguntas. diff --git a/chapters/es/chapter1/8.mdx b/chapters/es/chapter1/8.mdx index 818575337..607e95510 100644 --- a/chapters/es/chapter1/8.mdx +++ b/chapters/es/chapter1/8.mdx @@ -29,4 +29,4 @@ print([r["token_str"] for r in result]) Cuando se le pide llenar la palabra faltante en estas dos oraciones, el modelo devuelve solo una respuesta agnóstica de género (*waiter/waitress*). Las otras son ocupaciones que se suelen asociar con un género específico -- y si, prostituta es una de las primeras 5 posibilidades que el modelo asocia con "mujer" y "trabajo". Esto sucede a pesar de que BERT es uno de los pocos modelos de Transformadores que no se construyeron basados en datos *raspados* de todo el internet, pero usando datos aparentemente neutrales (está entrenado con los conjuntos de datos de [Wikipedia en Inglés](https://huggingface.co/datasets/wikipedia) y [BookCorpus](https://huggingface.co/datasets/bookcorpus)). -Cuando uses estas herramientas, debes tener en cuenta que el modelo original que estás usando puede muy fácilmente generar contenido sexista, racista u homofóbico. Ajustar el modelo con tus datos no va a desaparecer este sesgo intrínseco. +Cuando uses estas herramientas, debes tener en cuenta que el modelo original que estás usando puede muy fácilmente generar contenido sexista, racista u homófobo. Ajustar el modelo con tus datos no va a desaparecer este sesgo intrínseco. diff --git a/chapters/es/chapter2/4.mdx b/chapters/es/chapter2/4.mdx index 4f34065b1..e2b954efb 100644 --- a/chapters/es/chapter2/4.mdx +++ b/chapters/es/chapter2/4.mdx @@ -32,7 +32,7 @@ En las tareas de NLP, los datos generalmente ingresan como texto crudo. Por ejem Jim Henson era un titiritero ``` -Sin embargo, necesitamos una forma de convertir el texto crudo a valores numéricos para los modelos. Eso es precisamente lo que hacen los tokenizadores, y existe una variedad de formas en que puede hacerse. El objetivo final es obetener valores que sean cortos pero muy significativos para el modelo. +Sin embargo, necesitamos una forma de convertir el texto crudo a valores numéricos para los modelos. Eso es precisamente lo que hacen los tokenizadores, y existe una variedad de formas en que puede hacerse. El objetivo final es obtener valores que sean cortos pero muy significativos para el modelo. Veamos algunos algoritmos de tokenización, e intentemos atacar algunas preguntas que puedas tener. @@ -47,7 +47,7 @@ El primer tokenizador que nos ocurre es el _word-based_ (_basado-en-palabras_).
-Existen varias formas de separar el texto. Por ejempĺo, podríamos usar los espacios para tokenizar usando Python y la función `split()`. +Existen varias formas de separar el texto. Por ejemplo, podríamos usar los espacios para tokenizar usando Python y la función `split()`. ```py tokenized_text = "Jim Henson era un titiritero".split() @@ -115,7 +115,7 @@ Como es lógico, existen muchas más técnicas. Por nombrar algunas: - Byte-level BPE (a nivel de bytes), como usa GPT-2 - WordPiece, usado por BERT -- SentencePiece or Unigram (pedazo de sentencia o unigrama), como se usa en los modelos multilengua +- SentencePiece or Unigram (pedazo de sentencia o unigrama), como se usa en los modelos multilingües A este punto, deberías tener conocimientos suficientes sobre el funcionamiento de los tokenizadores para empezar a utilizar la API. @@ -132,10 +132,10 @@ tokenizer = BertTokenizer.from_pretrained("bert-base-cased") ``` {#if fw === 'pt'} -Al igual que `AutoModel`, la clase `AutoTokenizer` tomará la clase de tokenizador adecuada en la biblioteca basada en el nombre del punto de control, y se puede utilizar directamente con cualquier punto de control: +Al igual que `AutoModel`, la clase `AutoTokenizer` tomará la clase de tokenizador adecuada en la librería basada en el nombre del punto de control, y se puede utilizar directamente con cualquier punto de control: {:else} -Al igual que `TFAutoModel`, la clase `AutoTokenizer` tomará la clase de tokenizador adecuada en la biblioteca basada en el nombre del punto de control, y se puede utilizar directamente con cualquier punto de control: +Al igual que `TFAutoModel`, la clase `AutoTokenizer` tomará la clase de tokenizador adecuada en la librería basada en el nombre del punto de control, y se puede utilizar directamente con cualquier punto de control: {/if} diff --git a/chapters/es/chapter2/6.mdx b/chapters/es/chapter2/6.mdx index de2e84e13..489b35977 100644 --- a/chapters/es/chapter2/6.mdx +++ b/chapters/es/chapter2/6.mdx @@ -37,7 +37,7 @@ sequence = "I've been waiting for a HuggingFace course my whole life." model_inputs = tokenizer(sequence) ``` -Aquí la varibale `model_inputs` contiene todo lo necesario para que un modelo opere bien. Para DistilBERT, que incluye los IDs de entrada también como la máscara de atención. Otros modelos que aceptan entradas adicionales también tendrán las salidas del objeto `tokenizer`. +Aquí la variable `model_inputs` contiene todo lo necesario para que un modelo opere bien. Para DistilBERT, que incluye los IDs de entrada también como la máscara de atención. Otros modelos que aceptan entradas adicionales también tendrán las salidas del objeto `tokenizer`. Como veremos en los ejemplos de abajo, este método es muy poderoso. Primero, puede tokenizar una sola secuencia: @@ -82,7 +82,7 @@ model_inputs = tokenizer(sequences, truncation=True) model_inputs = tokenizer(sequences, max_length=8, truncation=True) ``` -El objeto `tokenizer` puede manejar la conversión a tensores de frameworks específicos, los cuales pueden ser enviados directametne al modelo. Por ejemplo, en el siguiente código de ejemplo estamos solicitando al tokenizer que regrese los tensores de los distintos frameworks — `"pt"` regresa tensores de PyTorch, `"tf"` regresa tensores de TensorFlow, y `"np"` regresa arreglos de NumPy: +El objeto `tokenizer` puede manejar la conversión a tensores de frameworks específicos, los cuales pueden ser enviados directamente al modelo. Por ejemplo, en el siguiente código de ejemplo estamos solicitando al tokenizer que regrese los tensores de los distintos frameworks — `"pt"` regresa tensores de PyTorch, `"tf"` regresa tensores de TensorFlow, y `"np"` regresa arreglos de NumPy: ```py sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] @@ -131,7 +131,7 @@ print(tokenizer.decode(ids)) El tokenizador agregó la palabra especial `[CLS]` al principio y la palabra especial `[SEP]` al final. Esto se debe a que el modelo fue preentrenado con esos, así para obtener los mismos resultados por inferencia necesitamos agregarlos también. Nota que algunos modelos no agregan palabras especiales, o agregan unas distintas; los modelos también pueden agregar estas palabras especiales sólo al principio, o sólo al final. En cualquier caso, el tokenizador sabe cuáles son las esperadas y se encargará de ello por tí. -## Conclusión: Del tokenizador al moelo +## Conclusión: Del tokenizador al modelo Ahora que hemos visto todos los pasos individuales que el objeto `tokenizer` usa cuando se aplica a textos, veamos una última vez cómo maneja varias secuencias (¡relleno!), secuencias muy largas (¡truncado!), y múltiples tipos de tensores con su API principal: diff --git a/chapters/es/chapter2/7.mdx b/chapters/es/chapter2/7.mdx index 6d7c470c3..d8a0ac53f 100644 --- a/chapters/es/chapter2/7.mdx +++ b/chapters/es/chapter2/7.mdx @@ -1,4 +1,4 @@ -# ¡Haz completado el uso básico! +# ¡Has completado el uso básico! Model Hub para encontrar el mejor punto de control para tu tarea!" + explain: "Incorrecto; aunque algunos puntos de control y modelos son capaces de manejar varios lenguajes, no hay herramientas integradas para la selección automática de punto de control de acuerdo al lenguaje. ¡Deberías dirigirte a Model Hub para encontrar el mejor punto de control para tu tarea!" } ]} /> @@ -140,7 +140,7 @@ }, { text: "Un modelo que detecta automáticamente el lenguaje usado por sus entradas para cargar los pesos correctos", - explain: "Incorrecto; auqneu algunos puntos de control y modelos son capaced de manejar varios lenguajes, no hay herramientas integradas para la selección automática de punto de control de acuerdo al lenguaje. ¡Deberías dirigirte a Model Hub para encontrar el mejor punto de control para tu tarea!" + explain: "Incorrecto; aunque algunos puntos de control y modelos son capaces de manejar varios lenguajes, no hay herramientas integradas para la selección automática de punto de control de acuerdo al lenguaje. ¡Deberías dirigirte a Model Hub para encontrar el mejor punto de control para tu tarea!" } ]} /> @@ -173,7 +173,7 @@ ]} /> -### 7. ¿Cuál es el punto de aplicar una funcion SoftMax a las salidas logits por un modelo de clasificación de secuencias? +### 7. ¿Cuál es el punto de aplicar una función SoftMax a las salidas logits por un modelo de clasificación de secuencias? -✏️ **Inténtalo!** Mira el elemento 15 del conjunto de datos de entrenamiento y el elemento 87 del conjunto de datos de validación. Cuáles son sus etiquetas? +✏️ **¡Inténtalo!** Mira el elemento 15 del conjunto de datos de entrenamiento y el elemento 87 del conjunto de datos de validación. Cuáles son sus etiquetas? @@ -194,7 +194,7 @@ Nosotros consideramos las llaves `input_ids` y `attention_mask` en el [Capítulo -✏️ **Inténtalo!** Toma el elemento 15 del conjunto de datos de entrenamiento y tokeniza las dos oraciones independientemente y como un par. Cuál es la diferencia entre los dos resultados? +✏️ **¡Inténtalo!** Toma el elemento 15 del conjunto de datos de entrenamiento y tokeniza las dos oraciones independientemente y como un par. Cuál es la diferencia entre los dos resultados? diff --git a/chapters/es/chapter3/3.mdx b/chapters/es/chapter3/3.mdx index 72a76691e..83bacfffd 100644 --- a/chapters/es/chapter3/3.mdx +++ b/chapters/es/chapter3/3.mdx @@ -119,7 +119,7 @@ import numpy as np preds = np.argmax(predictions.predictions, axis=-1) ``` -Ahora podemos comparar esas predicciones `preds` con las etiquetas. Para construir nuestra función `compute_metric()`, nos basaremos en las métricas de la biblioteca 🤗 [Evaluate](https://github.com/huggingface/evaluate/). Podemos cargar las métricas asociadas al dataset MRPC tan fácilmente como cargamos el dataset, esta vez con la función `evaluate.load()`. El objeto devuelto tiene un método `compute()` que podemos utilizar para calcular de la métrica: +Ahora podemos comparar esas predicciones `preds` con las etiquetas. Para construir nuestra función `compute_metric()`, nos basaremos en las métricas de la librería 🤗 [Evaluate](https://github.com/huggingface/evaluate/). Podemos cargar las métricas asociadas al dataset MRPC tan fácilmente como cargamos el dataset, esta vez con la función `evaluate.load()`. El objeto devuelto tiene un método `compute()` que podemos utilizar para calcular de la métrica: ```py import evaluate diff --git a/chapters/es/chapter3/4.mdx b/chapters/es/chapter3/4.mdx index 696722e45..054a25639 100644 --- a/chapters/es/chapter3/4.mdx +++ b/chapters/es/chapter3/4.mdx @@ -146,7 +146,7 @@ device device(type='cuda') ``` -Ya estamos listos para entrenar! Para tener una idea de cuando el entrenamiento va a terminar, adicionamos una barra de progreso sobre el número de pasos de entrenamiento, usando la librería `tqdm`: +¡Ya está todo listo para entrenar! Para tener una idea de cuándo va a terminar el entrenamiento, adicionamos una barra de progreso sobre el número de pasos de entrenamiento, usando la librería `tqdm`: ```py from tqdm.auto import tqdm @@ -171,7 +171,7 @@ Puedes ver que la parte central del bucle de entrenamiento luce bastante como el ### El bucle de evaluación -Como lo hicimos anteriormente, usaremos una métrica ofrecida por la librería 🤗 Evaluate. Ya hemos visto el método `metric.compute()`, pero de hecho las métricas se pueden acumular sobre los lotes a medida que avanzamos en el bucle de predicción con el método `add_batch()`. Una vez que hemos acumulado todos los lotes, podemos obtener el resultado final con `metric.compute()`. Aquí se muestra como se puede implementar en un bucle de evaluación: +Como lo hicimos anteriormente, usaremos una métrica ofrecida por la librería 🤗 Evaluate. Ya hemos visto el método `metric.compute()`, pero de hecho las métricas se pueden acumular sobre los lotes a medida que avanzamos en el bucle de predicción con el método `add_batch()`. Una vez que hemos acumulado todos los lotes, podemos obtener el resultado final con `metric.compute()`. Aquí se muestra cómo se puede implementar en un bucle de evaluación: ```py import evaluate @@ -206,7 +206,7 @@ De nuevo, tus resultados serán un tanto diferente debido a la inicialización a -El bucle de entrenamiento que definimos anteriormente trabaja bien en un solo CPU o GPU. Pero usando la librería [Accelerate 🤗](https://github.com/huggingface/accelerate), con solo pocos ajustes podemos habilitar el entrenamiento distribuido en múltiples GPUs o CPUs. Comenzando con la creación de los `dataloaders` de entrenamiento y validación, aquí se muestra como luce nuestro bucle de entrenamiento: +El bucle de entrenamiento que definimos anteriormente trabaja bien en una sola CPU o GPU. Pero usando la librería [Accelerate 🤗](https://github.com/huggingface/accelerate), con solo pocos ajustes podemos habilitar el entrenamiento distribuido en múltiples GPUs o CPUs. Comenzando con la creación de los dataloaders de entrenamiento y validación, aquí se muestra como luce nuestro bucle de entrenamiento: ```py from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler @@ -286,9 +286,9 @@ Y aquí están los cambios: progress_bar.update(1) ``` -La primera línea a agregarse es la línea del import. La segunda línea crea un objeto `Accelerator` que revisa el ambiente e inicializa la configuración distribuida apropiada. La librería Accelerate 🤗 se encarga de asignarte el dispositivo, para que puedas remover las líneas que ponen el modelo en el dispositivo (o si prefieres, cámbialas para usar el `accelerator.device` en lugar de `device`). +La primera línea a agregarse es la línea del `import`. La segunda línea crea un objeto `Accelerator` que revisa el ambiente e inicializa la configuración distribuida apropiada. La librería 🤗 Accelerate se encarga de asignarte el dispositivo, para que puedas remover las líneas que ponen el modelo en el dispositivo (o si prefieres, cámbialas para usar el `accelerator.device` en lugar de `device`). -Ahora la mayor parte del trabajo se hace en la línea que envía los `dataloaders`, el modelo y el optimizador al `accelerator.prepare()`. Este va a envolver esos objetos en el contenedor apropiado para asegurarse que tu entrenamiento distribuido funcione como se espera. Los cambios que quedan son remover la línea que coloca el lote en el `device` (de nuevo, si deseas dejarlo asi bastaría con cambiarlo para que use el `accelerator.device`) y reemplazar `loss.backward()` con `accelerator.backward(loss)`. +Ahora la mayor parte del trabajo se hace en la línea que envía los `dataloaders`, el modelo y el optimizador al `accelerator.prepare()`. Este va a envolver esos objetos en el contenedor apropiado para asegurarse que tu entrenamiento distribuido funcione como se espera. Los cambios que quedan son remover la línea que coloca el lote en el `device` (de nuevo, si deseas dejarlo así bastaría con cambiarlo para que use el `accelerator.device`) y reemplazar `loss.backward()` con `accelerator.backward(loss)`. ⚠️ Para obtener el beneficio de la aceleración ofrecida por los TPUs de la diff --git a/chapters/es/chapter3/6.mdx b/chapters/es/chapter3/6.mdx index 6a5104392..5e5a1ba9f 100644 --- a/chapters/es/chapter3/6.mdx +++ b/chapters/es/chapter3/6.mdx @@ -219,14 +219,14 @@ A ver qué has aprendido en este capítulo: ]} /> -### 9. ¿Por qué deberías utilizar la biblioteca 🤗 Accelerate? +### 9. ¿Por qué deberías utilizar la librería 🤗 Accelerate? diff --git a/chapters/es/chapter5/1.mdx b/chapters/es/chapter5/1.mdx index 31a9a4c07..07db42118 100644 --- a/chapters/es/chapter5/1.mdx +++ b/chapters/es/chapter5/1.mdx @@ -5,7 +5,7 @@ classNames="absolute z-10 right-0 top-0" /> -En el [Capítulo 3](/course/chapter3) tuviste tu primer acercamento a la librería 🤗 Datasets y viste que existían 3 pasos principales para ajustar un modelo: +En el [Capítulo 3](/course/chapter3) tuviste tu primer acercamiento a la librería 🤗 Datasets y viste que existían 3 pasos principales para ajustar un modelo: 1. Cargar un conjunto de datos del Hub de Hugging Face. 2. Preprocesar los datos con `Dataset.map()`. diff --git a/chapters/es/chapter5/2.mdx b/chapters/es/chapter5/2.mdx index a239ddf53..a0de6264a 100644 --- a/chapters/es/chapter5/2.mdx +++ b/chapters/es/chapter5/2.mdx @@ -50,7 +50,7 @@ De este modo, podemos ver que los archivos comprimidos son reemplazados por los -✎ Si te preguntas por qué hay un caracter de signo de admiración (`!`) en los comandos de shell, esto es porque los estamos ejecutando desde un cuaderno de Jupyter. Si quieres descargar y descomprimir el archivo directamente desde la terminal, elimina el signo de admiración. +✎ Si te preguntas por qué hay un carácter de signo de admiración (`!`) en los comandos de shell, esto es porque los estamos ejecutando desde un cuaderno de Jupyter. Si quieres descargar y descomprimir el archivo directamente desde la terminal, elimina el signo de admiración. diff --git a/chapters/es/chapter5/3.mdx b/chapters/es/chapter5/3.mdx index 241916c9d..f1cc5ab69 100644 --- a/chapters/es/chapter5/3.mdx +++ b/chapters/es/chapter5/3.mdx @@ -11,7 +11,7 @@ La mayor parte del tiempo tus datos no estarán perfectamente listos para entren -## Subdivdiendo nuestros datos +## Subdividiendo nuestros datos De manera similar a Pandas, 🤗 Datasets incluye varias funciones para manipular el contenido de los objetos `Dataset` y `DatasetDict`. Ya vimos el método `Dataset.map()` en el [Capítulo 3](/course/chapter3) y en esta sección vamos a explorar otras funciones que tenemos a nuestra disposición. @@ -30,7 +30,7 @@ Dado que TSV es una variación de CSV en la que se usan tabulaciones en vez de c from datasets import load_dataset data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"} -# \t es el caracter para tabulaciones en Python +# \t es el carácter para tabulaciones en Python drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t") ``` @@ -54,7 +54,7 @@ drug_sample[:3] 'usefulCount': [36, 13, 128]} ``` -Puedes ver que hemos fijado la semilla en `Dataset.shuffle()` por motivos de reproducibilidad. `Dataset.select()` espera un interable de índices, así que incluimos `range(1000)` para tomar los primeros 1.000 ejemplos del conjunto de datos aleatorizado. Ya podemos ver algunos detalles para esta muestra: +Puedes ver que hemos fijado la semilla en `Dataset.shuffle()` por motivos de reproducibilidad. `Dataset.select()` espera un iterable de índices, así que incluimos `range(1000)` para tomar los primeros 1.000 ejemplos del conjunto de datos aleatorizado. Ya podemos ver algunos detalles para esta muestra: * La columna `Unnamed: 0` se ve sospechosamente como un ID anonimizado para cada paciente. * La columna `condition` incluye una mezcla de niveles en mayúscula y minúscula. @@ -215,7 +215,7 @@ drug_dataset["train"].sort("review_length")[:3] 'review_length': [1, 1, 1]} ``` -Como lo discutimos anteriormente, algunas reseñas incluyen una sola palabra, que si bien puede ser útil para el análisis de sentimientos, no sería tan informativa si quisieramos predecir la condición. +Como lo discutimos anteriormente, algunas reseñas incluyen una sola palabra, que si bien puede ser útil para el análisis de sentimientos, no sería tan informativa si quisiéramos predecir la condición. @@ -312,7 +312,7 @@ Opciones | Tokenizador rápido | Tokenizador lento Esto significa que usar un tokenizador rápido con la opción `batched=True` es 30 veces más rápido que su contraparte lenta sin usar lotes. ¡Realmente impresionante! Esta es la razón principal por la que los tokenizadores rápidos son la opción por defecto al usar `AutoTokenizer` (y por qué se denominan "rápidos"). Estos logran tal rapidez gracias a que el código de los tokenizadores corre en Rust, que es un lenguaje que facilita la ejecución del código en paralelo. -La paralelización también es la razón para el incremento de 6x en la velocidad del tokenizador al ejecutarse por lotes: No puedes ejecutar una única operacón de tokenización en paralelo, pero cuando quieres tokenizar muchos textos al mismo tiempo puedes dividir la ejecución en diferentes procesos, cada uno responsable de sus propios textos. +La paralelización también es la razón para el incremento de 6x en la velocidad del tokenizador al ejecutarse por lotes: No puedes ejecutar una única operación de tokenización en paralelo, pero cuando quieres tokenizar muchos textos al mismo tiempo puedes dividir la ejecución en diferentes procesos, cada uno responsable de sus propios textos. `Dataset.map()` también tiene algunas capacidades de paralelización. Dado que no funcionan con Rust, no van a hacer que un tokenizador lento alcance el rendimiento de uno rápido, pero aún así pueden ser útiles (especialmente si estás usando un tokenizador que no tiene una versión rápida). Para habilitar el multiprocesamiento, usa el argumento `num_proc` y especifica el número de procesos para usar en `Dataset.map()`: @@ -329,7 +329,7 @@ tokenized_dataset = drug_dataset.map(slow_tokenize_function, batched=True, num_p También puedes medir el tiempo para determinar el número de procesos que vas a usar. En nuestro caso, usar 8 procesos produjo la mayor ganancia de velocidad. Aquí están algunos de los números que obtuvimos con y sin multiprocesamiento: -Opciones | Tokenizador rápido | Rokenizador lento +Opciones | Tokenizador rápido | Tokenizador lento :--------------:|:--------------:|:-------------: `batched=True` | 10.8s | 4min41s `batched=False` | 59.2s | 5min3s @@ -348,7 +348,7 @@ Que toda esta funcionalidad está incluida en un método es algo impresionante e -💡 Un _ejemplo_ en Machine Learning se suele definir como el conjunto de _features_ que le damos al modelo. En algunos contextos estos features serán el conjuto de columnas en un `Dataset`, mientras que en otros se pueden extraer mútiples features de un solo ejemplo que pertenecen a una columna –como aquí y en tareas de responder preguntas-. +💡 Un _ejemplo_ en Machine Learning se suele definir como el conjunto de _features_ que le damos al modelo. En algunos contextos estos features serán el conjunto de columnas en un `Dataset`, mientras que en otros se pueden extraer múltiples features de un solo ejemplo que pertenecen a una columna –como aquí y en tareas de responder preguntas-. @@ -385,7 +385,7 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -¿Por qué no funcionó? El mensaje de error nos da una pista: hay un desajuste en las longitudes de una de las columnas, siendo una de logitud 1.463 y otra de longitud 1.000. Si has revisado la [documentación de `Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), te habrás dado cuenta que estamos mapeando el número de muestras que le pasamos a la función: en este caso los 1.000 ejemplos nos devuelven 1.463 features, arrojando un error. +¿Por qué no funcionó? El mensaje de error nos da una pista: hay un desajuste en las longitudes de una de las columnas, siendo una de longitud 1.463 y otra de longitud 1.000. Si has revisado la [documentación de `Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), te habrás dado cuenta que estamos mapeando el número de muestras que le pasamos a la función: en este caso los 1.000 ejemplos nos devuelven 1.463 features, arrojando un error. El problema es que estamos tratando de mezclar dos datasets de tamaños diferentes: las columnas de `drug_dataset` tendrán un cierto número de ejemplos (los 1.000 en el error), pero el `tokenized_dataset` que estamos construyendo tendrá más (los 1.463 en el mensaje de error). Esto no funciona para un `Dataset`, así que tenemos que eliminar las columnas del anterior dataset o volverlas del mismo tamaño del nuevo. Podemos hacer la primera operación con el argumento `remove_columns`: diff --git a/chapters/es/chapter5/4.mdx b/chapters/es/chapter5/4.mdx index 6e4024694..38919187d 100644 --- a/chapters/es/chapter5/4.mdx +++ b/chapters/es/chapter5/4.mdx @@ -128,7 +128,7 @@ print( 'Iterated over 15518009 examples (about 19.5 GB) in 64.2s, i.e. 0.304 GB/s' ``` -Aquí usamos el módulo `timeit` de Python para medir el tiempo de ejecución que se toma `code_snippet`. Tipicamemente, puedes iterar a lo largo de un dataset a una velocidad de unas cuantas décimas de un GB por segundo. Esto funciona muy bien para la gran mayoría de aplicaciones, pero algunas veces tendrás que trabajar con un dataset que es tan grande para incluso almacenarse en el disco de tu computador. Por ejemplo, si quisieramos descargar el _Pile_ completo ¡necesitaríamos 825 GB de almacenamiento libre! Para trabajar con esos casos, 🤗 Datasets puede trabajar haciendo _streaming_, lo que permite la descarga y acceso a los elementos sobre la marcha, sin necesidad de descargar todo el dataset. Veamos cómo funciona: +Aquí usamos el módulo `timeit` de Python para medir el tiempo de ejecución que se toma `code_snippet`. Típicamemente, puedes iterar a lo largo de un dataset a una velocidad de unas cuantas décimas de un GB por segundo. Esto funciona muy bien para la gran mayoría de aplicaciones, pero algunas veces tendrás que trabajar con un dataset que es tan grande para incluso almacenarse en el disco de tu computador. Por ejemplo, si quisieramos descargar el _Pile_ completo ¡necesitaríamos 825 GB de almacenamiento libre! Para trabajar con esos casos, 🤗 Datasets puede trabajar haciendo _streaming_, lo que permite la descarga y acceso a los elementos sobre la marcha, sin necesidad de descargar todo el dataset. Veamos cómo funciona: @@ -173,7 +173,7 @@ next(iter(tokenized_dataset)) -💡 Para acelerar la tokenización con _streaming_ puedes definir `batched=True`, como lo vimos en la sección anterior. Esto va a procesar los ejemplos lote por lote. Recuerda que el tamaño por defecto de los lotes es 1.000 y puede ser expecificado con el argumento `batch_size`. +💡 Para acelerar la tokenización con _streaming_ puedes definir `batched=True`, como lo vimos en la sección anterior. Esto va a procesar los ejemplos lote por lote. Recuerda que el tamaño por defecto de los lotes es 1.000 y puede ser especificado con el argumento `batch_size`. @@ -189,7 +189,7 @@ next(iter(shuffled_dataset)) 'text': 'Randomized study of dose or schedule modification of granulocyte colony-stimulating factor in platinum-based chemotherapy for elderly patients with lung cancer ...'} ``` -En este ejemplo, seleccionamos un ejemplo aleatório de los primeros 10.000 ejemplos en el buffer. Apenas se accede a un ejemplo, su lugar en el buffer se llena con el siguiente ejemplo en el corpus (i.e., el ejemplo número 10.001). También peudes seleccionar elementos de un dataset _streamed_ usando las funciones `IterableDataset.take()` y `IterableDataset.skip()`, que funcionan de manera similar a `Dataset.select()`. Por ejemplo, para seleccionar los 5 primeros ejemplos en el dataset de abstracts de PubMed podemos hacer lo siguiente: +En este ejemplo, seleccionamos un ejemplo aleatorio de los primeros 10.000 ejemplos en el buffer. Apenas se accede a un ejemplo, su lugar en el buffer se llena con el siguiente ejemplo en el corpus (i.e., el ejemplo número 10.001). También puedes seleccionar elementos de un dataset _streamed_ usando las funciones `IterableDataset.take()` y `IterableDataset.skip()`, que funcionan de manera similar a `Dataset.select()`. Por ejemplo, para seleccionar los 5 primeros ejemplos en el dataset de abstracts de PubMed podemos hacer lo siguiente: ```py dataset_head = pubmed_dataset_streamed.take(5) @@ -209,7 +209,7 @@ list(dataset_head) 'text': 'Oxygen supply in rural africa: a personal experience ...'}] ``` -También podemos usar la función `IterableDataset.skip()` para crear conjuntos de entrenamiento y validación de un dataset ordenado aleatóriamente así: +También podemos usar la función `IterableDataset.skip()` para crear conjuntos de entrenamiento y validación de un dataset ordenado aleatoriamente así: ```py # Salta las primeras 1000 muestras e incluye el resto en el conjunto de entrenamiento diff --git a/chapters/es/chapter5/5.mdx b/chapters/es/chapter5/5.mdx index 113138fa5..e901c3717 100644 --- a/chapters/es/chapter5/5.mdx +++ b/chapters/es/chapter5/5.mdx @@ -13,7 +13,7 @@ Algunas veces el dataset que necesitas para crear una aplicación de procesamien * Entrenar un _clasificador de etiquetas múltiples_ que pueda etiquetar issues con metadados basado en la descripción del issue (e.g., "bug", "mejora" o "pregunta") * Crear un motor de búsqueda semántica para encontrar qué issues coinciden con la pregunta del usuario -En esta sección nos vamos a enfocar en la creación del corpus y en la siguiente vamos a abordar la aplicación de búsqueda semántica. Para que esto sea un meta-proyecto, vamos a usar los issues de Github asociados con un proyecto popular de código abierto: 🤗 Datasets! Veamos cómo obtener los datos y explorar la información contenida en estos issues. +En esta sección nos vamos a enfocar en la creación del corpus y en la siguiente vamos a abordar la aplicación de búsqueda semántica. Para que esto sea un meta-proyecto, vamos a usar los issues de GitHub asociados con un proyecto popular de código abierto: 🤗 Datasets! Veamos cómo obtener los datos y explorar la información contenida en estos issues. ## Obteniendo los datos @@ -255,7 +255,7 @@ Como se muestra en la siguiente captura de pantalla, los comentarios asociados c Comments associated with an issue about 🤗 Datasets.
-El API REST de GitHub tiene un [endpoint `Comments`](https://docs.github.com/en/rest/reference/issues#list-issue-comments) que devuelve todos los comentarios asociados con un número de issue. Probémos este endpoint para ver qué devuelve: +El API REST de GitHub tiene un [endpoint `Comments`](https://docs.github.com/en/rest/reference/issues#list-issue-comments) que devuelve todos los comentarios asociados con un número de issue. Probemos este endpoint para ver qué devuelve: ```py issue_number = 2792 @@ -378,7 +378,7 @@ En este ejemplo, hemos creado un repositorio vacío para el dataset llamado `git -✏️ **¡Inténtalo!** Usa tu nombre de usuario de Hugging Face Hub para obtener un token y crear un repositorio vacío llamado `girhub-issues`. Recuerda **nunca guardar tus credenciales** en Colab o cualquier otro repositorio, ya que esta información puede ser aprovechada por terceros. +✏️ **¡Inténtalo!** Usa tu nombre de usuario de Hugging Face Hub para obtener un token y crear un repositorio vacío llamado `github-issues`. Recuerda **nunca guardar tus credenciales** en Colab o cualquier otro repositorio, ya que esta información puede ser aprovechada por terceros. @@ -445,7 +445,7 @@ En el Hub de Hugging Face, esta información se almacena en el archivo *README.m 2. Lee la [guía de 🤗 Datasets](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) sobre cómo crear tarjetas informativas y usarlas como plantilla. -Puedes crear el archivo *README.md* drectamente desde el Hub y puedes encontrar una plantilla de tarjeta en el repositorio `lewtun/github-issues`. Así se ve una tarjeta de dataset diligenciada: +Puedes crear el archivo *README.md* directamente desde el Hub y puedes encontrar una plantilla de tarjeta en el repositorio `lewtun/github-issues`. Así se ve una tarjeta de dataset diligenciada:
A dataset card. @@ -457,7 +457,7 @@ Puedes crear el archivo *README.md* drectamente desde el Hub y puedes encontrar -¡Eso es todo! Hemos visto que crear un buen dataset requiere de mucho esfuerzo de tu parte, pero afortunadamente subirlo y compartirlo con la comunidad no. En la siguiente sección usaremos nuestro nuevo dataset para crear un motor de búsqueda semántica con 🤗 Datasets que pueda emparejar pregunras con los issues y comentarios más relevantes. +¡Eso es todo! Hemos visto que crear un buen dataset requiere de mucho esfuerzo de tu parte, pero afortunadamente subirlo y compartirlo con la comunidad no. En la siguiente sección usaremos nuestro nuevo dataset para crear un motor de búsqueda semántica con 🤗 Datasets que pueda emparejar preguntas con los issues y comentarios más relevantes. diff --git a/chapters/es/chapter5/6.mdx b/chapters/es/chapter5/6.mdx index 2c4cbd13f..1e635315b 100644 --- a/chapters/es/chapter5/6.mdx +++ b/chapters/es/chapter5/6.mdx @@ -22,7 +22,7 @@ {/if} -En la [sección 5](/course/chapter5/5) creamos un dataset de issues y comentarios del repositorio de Github de 🤗 Datasets. En esta sección usaremos esta información para construir un motor de búsqueda que nos ayude a responder nuestras preguntas más apremiantes sobre la librería. +En la [sección 5](/course/chapter5/5) creamos un dataset de issues y comentarios del repositorio de GitHub de 🤗 Datasets. En esta sección usaremos esta información para construir un motor de búsqueda que nos ayude a responder nuestras preguntas más apremiantes sobre la librería. @@ -266,7 +266,7 @@ tokenizer = AutoTokenizer.from_pretrained(model_ckpt) model = TFAutoModel.from_pretrained(model_ckpt, from_pt=True) ``` -Ten en cuenta que hemos definido `from_pt=True` como un argumento del método `from_pretrained()`. Esto es porque el punto de control `multi-qa-mpnet-base-dot-v1` sólo tiene pesos de PyTorch, asi que usar `from_pt=True` los va a covertir automáticamente al formato TensorFlow. Como puedes ver, ¡es múy fácil cambiar entre frameworks usando 🤗 Transformers! +Ten en cuenta que hemos definido `from_pt=True` como un argumento del método `from_pretrained()`. Esto es porque el punto de control `multi-qa-mpnet-base-dot-v1` sólo tiene pesos de PyTorch, asi que usar `from_pt=True` los va a convertir automáticamente al formato TensorFlow. Como puedes ver, ¡es múy fácil cambiar entre frameworks usando 🤗 Transformers! {/if} diff --git a/chapters/es/chapter5/8.mdx b/chapters/es/chapter5/8.mdx index 4718d8faf..99f5e0ffd 100644 --- a/chapters/es/chapter5/8.mdx +++ b/chapters/es/chapter5/8.mdx @@ -1,6 +1,6 @@ -# Quiz +# Quiz de final de capítulo data_files de la función load_dataset() psara cargar archivos remotos.", + explain: "¡Correcto! Puedes pasar URL al argumento data_files de la función load_dataset() para cargar archivos remotos.", correct: true }, ]} @@ -41,7 +41,7 @@ from datasets import load_dataset dataset = load_dataset("glue", "mrpc", split="train") ``` -¿Cuál de los sigientes comandos a a producir una muestra aleatoria de 50 elementos de `dataset`? +¿Cuál de los siguientes comandos a a producir una muestra aleatoria de 50 elementos de `dataset`? pets_dataset.filter(lambda x['name'].startswith('L'))", - explain: "Esto es incorrecrto. Una función lambda toma la forma general lambda *arguments* : *expression*, así que tienes que definir los argumentos en este caso." + explain: "Esto es incorrecto. Una función lambda toma la forma general lambda *arguments* : *expression*, así que tienes que definir los argumentos en este caso." }, { - text: "Crear una funcióin como def filter_names(x): return x['name'].startswith('L') y ejecutar pets_dataset.filter(filter_names).", + text: "Crear una función como def filter_names(x): return x['name'].startswith('L') y ejecutar pets_dataset.filter(filter_names).", explain: "¡Correcto! Justo como con Dataset.map(), puedes pasar funciones explícitas a Dataset.filter(). Esto es útil cuando tienes una lógica compleja que no es adecuada para una función lambda. ¿Cuál de las otras soluciones podría funcionar?", correct: true } @@ -150,7 +150,7 @@ dataset[0] ]} /> -### 7. ¿Cuáles son los principales beneficiones de crear una tarjeta para un dataset? +### 7. ¿Cuáles son los principales beneficios de crear una tarjeta para un dataset? Date: Wed, 20 Dec 2023 20:45:48 +0300 Subject: [PATCH 305/502] Fixing today's translation. Files: 6.mdx, 7.mdx and half of 8.mdx. --- .../.ipynb_checkpoints/6-checkpoint.mdx | 56 +- .../.ipynb_checkpoints/7-checkpoint.mdx | 381 ++++++++++++ .../.ipynb_checkpoints/8-checkpoint.mdx | 565 ++++++++++++++++++ chapters/ru/chapter6/6.mdx | 56 +- chapters/ru/chapter6/7.mdx | 128 ++-- chapters/ru/chapter6/8.mdx | 120 ++-- 6 files changed, 1126 insertions(+), 180 deletions(-) create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/7-checkpoint.mdx create mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/8-checkpoint.mdx diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx index bc512fc73..a462d82f2 100644 --- a/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx +++ b/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx @@ -78,31 +78,31 @@ Corpus: ("hug", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "## -✏️ ** Теперь ваша очередь! ** Каким будет следующее правило слияния? +✏️ **Теперь ваша очередь!** Каким будет следующее правило слияния? ## Алгоритм токенизации[[tokenization-algorithm]] -Tokenization differs in WordPiece and BPE in that WordPiece only saves the final vocabulary, not the merge rules learned. Starting from the word to tokenize, WordPiece finds the longest subword that is in the vocabulary, then splits on it. For instance, if we use the vocabulary learned in the example above, for the word `"hugs"` the longest subword starting from the beginning that is inside the vocabulary is `"hug"`, so we split there and get `["hug", "##s"]`. We then continue with `"##s"`, which is in the vocabulary, so the tokenization of `"hugs"` is `["hug", "##s"]`. +Токенизация в WordPiece и BPE отличается тем, что WordPiece сохраняет только конечный словарь, а не выученные правила слияния. Начиная со слова, которое нужно токенизировать, WordPiece находит самое длинное подслово, которое есть в словаре, а затем разбивает его на части. Например, если мы используем словарь, изученный в примере выше, для слова `" hugs"` самым длинным подсловом, начиная с начала, которое находится в словаре, является `"hug"`, поэтому мы делим его на части и получаем `["hug", "##s"]`. Затем мы продолжаем с `"##s"`, которое находится в словаре, поэтому токенизация `"hugs"` будет `["hug", "##s"]`. -With BPE, we would have applied the merges learned in order and tokenized this as `["hu", "##gs"]`, so the encoding is different. +В BPE мы бы применили слияния, выученные по порядку, и токенизировали это как `["hu", "##gs"]`, поэтому кодировка отличается. -As another example, let's see how the word `"bugs"` would be tokenized. `"b"` is the longest subword starting at the beginning of the word that is in the vocabulary, so we split there and get `["b", "##ugs"]`. Then `"##u"` is the longest subword starting at the beginning of `"##ugs"` that is in the vocabulary, so we split there and get `["b", "##u, "##gs"]`. Finally, `"##gs"` is in the vocabulary, so this last list is the tokenization of `"bugs"`. +В качестве другого примера посмотрим, как будет токенизировано слово `"bugs"`. `"b"` - самое длинное подслово, начинающееся с начала слова, которое есть в словаре, поэтому мы делим его на части и получаем `["b", "##ugs"]`. Затем `"##u"` - самое длинное подслово, начинающееся в начале `"##ugs"`, которое есть в словаре, поэтому мы делим его на части и получаем `["b", "##u", "##gs"]`. Наконец, `"##gs"` находится в словаре, так что этот последний список является токеном `"bugs"`. -When the tokenization gets to a stage where it's not possible to find a subword in the vocabulary, the whole word is tokenized as unknown -- so, for instance, `"mug"` would be tokenized as `["[UNK]"]`, as would `"bum"` (even if we can begin with `"b"` and `"##u"`, `"##m"` is not the vocabulary, and the resulting tokenization will just be `["[UNK]"]`, not `["b", "##u", "[UNK]"]`). This is another difference from BPE, which would only classify the individual characters not in the vocabulary as unknown. +Когда токенизация доходит до стадии, когда невозможно найти подслово в словаре, все слово токенизируется как неизвестное - так, например, `"mug"` будет токенизировано как `["[UNK]"]`, как и `"bum"` (даже если мы можем начать с `"b"` и `"##u"`, `"##m"` не входит в словарь, и результирующий токен будет просто `["[UNK]"]`, а не `["b", "##u", "[UNK]"]`). Это еще одно отличие от BPE, который классифицирует как неизвестные только отдельные символы, отсутствующие в словаре. -✏️ **Now your turn!** How will the word `"pugs"` be tokenized? +✏️ **Теперь ваша очередь!** Как будет токенизировано слово `"pugs"`? ## Реализация WordPiece[[implementing-wordpiece]] -Now let's take a look at an implementation of the WordPiece algorithm. Like with BPE, this is just pedagogical, and you won't able to use this on a big corpus. +Теперь давайте посмотрим на реализацию алгоритма WordPiece. Как и в случае с BPE, это всего лишь учебный пример, и вы не сможете использовать его на большом корпусе. -We will use the same corpus as in the BPE example: +Мы будем использовать тот же корпус, что и в примере с BPE: ```python corpus = [ @@ -113,7 +113,7 @@ corpus = [ ] ``` -First, we need to pre-tokenize the corpus into words. Since we are replicating a WordPiece tokenizer (like BERT), we will use the `bert-base-cased` tokenizer for the pre-tokenization: +Во-первых, нам нужно предварительно токенизировать корпус в слова. Поскольку мы воспроизводим токенизатор WordPiece (например, BERT), для предварительной токенизации мы будем использовать токенизатор `bert-base-cased`: ```python from transformers import AutoTokenizer @@ -121,7 +121,7 @@ from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") ``` -Then we compute the frequencies of each word in the corpus as we do the pre-tokenization: +Затем мы вычисляем частоту каждого слова в корпусе, как и при предварительной токенизации: ```python from collections import defaultdict @@ -144,7 +144,7 @@ defaultdict( 'trained': 1, 'and': 1, 'generate': 1, 'tokens': 1}) ``` -As we saw before, the alphabet is the unique set composed of all the first letters of words, and all the other letters that appear in words prefixed by `##`: +Как мы уже видели, алфавит - это уникальное множество, состоящее из всех первых букв слов и всех остальных букв, которые встречаются в словах с префиксом `##`: ```python alphabet = [] @@ -167,13 +167,13 @@ print(alphabet) 'w', 'y'] ``` -We also add the special tokens used by the model at the beginning of that vocabulary. In the case of BERT, it's the list `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]`: +Мы также добавляем специальные токены, используемые моделью, в начало этого словаря. В случае BERT это список `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]`: ```python vocab = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] + alphabet.copy() ``` -Next we need to split each word, with all the letters that are not the first prefixed by `##`: +Далее нам нужно разделить каждое слово на части, при этом все буквы, которые не являются первыми, должны иметь префикс `##`: ```python splits = { @@ -182,7 +182,7 @@ splits = { } ``` -Now that we are ready for training, let's write a function that computes the score of each pair. We'll need to use this at each step of the training: +Теперь, когда мы готовы к обучению, давайте напишем функцию, которая вычисляет оценку каждой пары. Нам нужно будет использовать ее на каждом шаге обучения: ```python def compute_pair_scores(splits): @@ -206,7 +206,7 @@ def compute_pair_scores(splits): return scores ``` -Let's have a look at a part of this dictionary after the initial splits: +Давайте посмотрим на часть этого словаря после первых разделений: ```python pair_scores = compute_pair_scores(splits) @@ -225,7 +225,7 @@ for i, key in enumerate(pair_scores.keys()): ('##h', '##e'): 0.011904761904761904 ``` -Now, finding the pair with the best score only takes a quick loop: +Теперь для того, чтобы найти пару с наилучшим результатом, нужно всего лишь сделать быстрый цикл: ```python best_pair = "" @@ -242,13 +242,13 @@ print(best_pair, max_score) ('a', '##b') 0.2 ``` -So the first merge to learn is `('a', '##b') -> 'ab'`, and we add `'ab'` to the vocabulary: +Итак, первое слияние, которое нужно выучить, это `('a', '##b') -> 'ab'`, и мы добавляем `'ab'` в словарь: ```python vocab.append("ab") ``` -To continue, we need to apply that merge in our `splits` dictionary. Let's write another function for this: +Чтобы продолжить, нам нужно применить это слияние в нашем словаре `splits`. Давайте напишем для этого еще одну функцию: ```python def merge_pair(a, b, splits): @@ -267,7 +267,7 @@ def merge_pair(a, b, splits): return splits ``` -And we can have a look at the result of the first merge: +И мы можем посмотреть на результат первого слияния: ```py splits = merge_pair("a", "##b", splits) @@ -278,7 +278,7 @@ splits["about"] ['ab', '##o', '##u', '##t'] ``` -Now we have everything we need to loop until we have learned all the merges we want. Let's aim for a vocab size of 70: +Теперь у нас есть все, что нужно, чтобы зацикливать процесс до тех пор, пока мы не выучим все слияния, которые нам нужны. Давайте нацелимся на размер словаря равный 70: ```python vocab_size = 70 @@ -298,7 +298,7 @@ while len(vocab) < vocab_size: vocab.append(new_token) ``` -We can then look at the generated vocabulary: +Затем мы можем просмотреть созданный словарь: ```py print(vocab) @@ -312,15 +312,15 @@ print(vocab) '##ut'] ``` -As we can see, compared to BPE, this tokenizer learns parts of words as tokens a bit faster. +Как мы видим, по сравнению с BPE этот токенизатор быстрее выучивает части слов как токены. -💡 Using `train_new_from_iterator()` on the same corpus won't result in the exact same vocabulary. This is because the 🤗 Tokenizers library does not implement WordPiece for the training (since we are not completely sure of its internals), but uses BPE instead. +💡 Использование `train_new_from_iterator()` на одном и том же корпусе не приведет к точно такому же словарю. Это происходит потому, что библиотека 🤗 Tokenizers не реализует WordPiece для обучения (поскольку мы не полностью уверены в его внутреннем устройстве), а использует вместо него BPE. -To tokenize a new text, we pre-tokenize it, split it, then apply the tokenization algorithm on each word. That is, we look for the biggest subword starting at the beginning of the first word and split it, then we repeat the process on the second part, and so on for the rest of that word and the following words in the text: +Чтобы токенизировать новый текст, мы предварительно токенизируем его, разбиваем на части, а затем применяем алгоритм токенизации к каждому слову. То есть начиная с первого слова мы ищем самое большое подслово и разбиваем его на части, затем мы повторяем процесс для второй части, и так далее для оставшейся части этого слова и следующих слов в тексте: ```python def encode_word(word): @@ -338,7 +338,7 @@ def encode_word(word): return tokens ``` -Let's test it on one word that's in the vocabulary, and another that isn't: +Давайте проверим алгоритм на одном слове, которое есть в словаре, и на другом, которого нет: ```python print(encode_word("Hugging")) @@ -350,7 +350,7 @@ print(encode_word("HOgging")) ['[UNK]'] ``` -Now, let's write a function that tokenizes a text: +Теперь давайте напишем функцию, которая токенизирует текст: ```python def tokenize(text): @@ -360,7 +360,7 @@ def tokenize(text): return sum(encoded_words, []) ``` -We can try it on any text: +Мы можем попробовать его на любом тексте: ```python tokenize("This is the Hugging Face course!") @@ -371,4 +371,4 @@ tokenize("This is the Hugging Face course!") '##e', '[UNK]'] ``` -That's it for the WordPiece algorithm! Now let's take a look at Unigram. +Вот и все об алгоритме WordPiece! Теперь давайте посмотрим на Unigram. diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/7-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/7-checkpoint.mdx new file mode 100644 index 000000000..032c92f79 --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/7-checkpoint.mdx @@ -0,0 +1,381 @@ +# Токенизация Unigram[[unigram-tokenization]] + + + +Алгоритм Unigram часто используется в SentencePiece, который является алгоритмом токенизации, применяемым в таких моделях, как AlBERT, T5, mBART, Big Bird и XLNet. + + + + + +💡 В этом разделе подробно рассматривается Unigram, вплоть до демонстрации полной реализации. Вы можете пропустить его, если вам нужен только общий обзор алгоритма токенизации. + + + +## Алгоритм обучения[[training-algorithm]] + +По сравнению с BPE и WordPiece, Unigram работает в другом направлении: он начинает с большого словарного запаса и удаляет из него токены, пока не достигнет желаемого размера словаря. Существует несколько вариантов создания базового словаря: например, мы можем взять наиболее часто встречающиеся подстроки в предварительно токенизированных словах или применить BPE к исходному корпусу с большим объемом словаря. + +На каждом шаге обучения алгоритм Unigram рассчитывает потери по корпусу с учетом текущего словарного запаса. Затем для каждого символа в словаре алгоритм вычисляет, насколько увеличится общая потеря, если этот символ будет удален, и ищет символы, которые увеличат ее меньше всего. Эти символы оказывают меньшее влияние на общую потерю по корпусу, поэтому в некотором смысле они "менее нужны" и являются лучшими кандидатами на удаление. + +Это очень дорогостоящая операция, поэтому мы удаляем не просто один символ, связанный с наименьшим увеличением потерь, а \\(p\\) (\\(p\\) - гиперпараметр, которым вы можете управлять, обычно 10 или 20) процентов символов, связанных с наименьшим увеличением потерь. Этот процесс повторяется до тех пор, пока словарь не достигнет желаемого размера. + +Обратите внимание, что мы никогда не удаляем базовые символы, чтобы убедиться, что любое слово может быть токенизировано. + +Итак, все еще немного туманно: основная часть алгоритма заключается в том, чтобы вычислить потери по корпусу и посмотреть, как они изменяются при удалении некоторых токенов из словаря, но мы еще не объяснили, как это сделать. Этот шаг зависит от алгоритма токенизации модели Unigram, поэтому мы рассмотрим его далее. + +Мы используем корпус текста из предыдущих примеров: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +и для этого примера мы возьмем все подстроки из исходного словаря: + +``` +["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"] +``` + +## Алгоритм токенизации[[tokenization-algorithm]] + +Модель Unigram - это тип языковой модели, в которой каждый токен рассматривается как независимый от предшествующих ему. Это самая простая языковая модель в том смысле, что вероятность появления токена X с учетом предыдущего контекста - это просто вероятность появления токена X. Таким образом, если бы мы использовали модель Unigram для генерации текста, мы бы всегда предсказывали наиболее часто встречающийся токен. + +Вероятность данного токена - это его частота (количество раз, когда мы его находим) в исходном корпусе, деленная на сумму частот всех токенов в словаре (чтобы убедиться, что суммы вероятностей равны 1). Например, `"ug"` присутствует в `"hug"`, `"pug"` и `"hugs"`, поэтому его частота в нашем корпусе равна 20. + +Здесь приведены частоты всех возможных подслов в словаре: + +``` +("h", 15) ("u", 36) ("g", 20) ("hu", 15) ("ug", 20) ("p", 17) ("pu", 17) ("n", 16) +("un", 16) ("b", 4) ("bu", 4) ("s", 5) ("hug", 15) ("gs", 5) ("ugs", 5) +``` + +Итак, сумма всех частот равна 210, а вероятность появления подслова `"ug"`, таким образом, составляет 20/210. + + + +✏️ **Теперь ваша очередь!** Напишите код для вычисления вышеуказанных частот и дважды проверьте правильность приведенных результатов, а также общую сумму. + + + +Теперь для токенизации данного слова мы рассматриваем все возможные сегментации на токены и вычисляем вероятность каждого из них в соответствии с моделью Unigram. Поскольку все токены считаются независимыми, эта вероятность равна произведению вероятностей появления каждого токена. Например, при токенизации `["p", "u", "g"]` слова `"pug"` вероятность составляет: + +$$P([``p", ``u", ``g"]) = P(``p") \times P(``u") \times P(``g") = \frac{5}{210} \times \frac{36}{210} \times \frac{20}{210} = 0.000389$$ + +Для сравнения, токен `["pu", "g"]` имеет вероятность: + +$$P([``pu", ``g"]) = P(``pu") \times P(``g") = \frac{5}{210} \times \frac{20}{210} = 0.0022676$$ + +так что один из них гораздо более вероятен. В целом, токенизации с наименьшим количеством токенов будут иметь наибольшую вероятность (из-за деления на 210, повторяющегося для каждого токена), что соответствует интуитивному желанию: разбить слово на наименьшее количество токенов. + +Токенизация слова с помощью модели Unigram - это токенизация с наибольшей вероятностью. В примере с `"pug"` приведены вероятности, которые мы получили бы для каждой возможной сегментации: + +``` +["p", "u", "g"] : 0.000389 +["p", "ug"] : 0.0022676 +["pu", "g"] : 0.0022676 +``` + +Так, `"pug"` будет токенизировано как `["p", "ug"]` или `["pu", "g"]`, в зависимости от того, какая из этих сегментаций встретится первой (отметим, что в большом корпусе подобные случаи равенства будут редки). + +В данном случае было легко найти все возможные сегментации и вычислить их вероятности, но в общем случае это будет немного сложнее. Для этого используется классический алгоритм, который называется *алгоритм Витерби (Viterbi algorithm)*. По сути, мы можем построить граф для выявления возможных сегментаций данного слова, сказав, что существует ветвь от символа _a_ до символа _b_, если подслово от _a_ до _b_ есть в словаре, и приписать этой ветви вероятность подслова. + +Чтобы найти путь в этом графе, который будет иметь наилучшую оценку, алгоритм Витерби определяет для каждой позиции в слове сегментацию с наилучшей оценкой, которая заканчивается на этой позиции. Поскольку мы идем от начала к концу, этот лучший результат можно найти, перебирая все подслова, заканчивающиеся на текущей позиции, а затем используя лучший результат токенизации с позиции, на которой начинается это подслово. Затем нужно просто развернуть путь, чтобы прийти к концу. + +Давайте рассмотрим пример с использованием нашего словаря и слова `"unhug"`. Для каждой позиции подслова с наилучшими оценками заканчиваются следующим образом: + +``` +Character 0 (u): "u" (score 0.171429) +Character 1 (n): "un" (score 0.076191) +Character 2 (h): "un" "h" (score 0.005442) +Character 3 (u): "un" "hu" (score 0.005442) +Character 4 (g): "un" "hug" (score 0.005442) +``` + +Таким образом, `"unhug"` будет токенизировано как `["un", "hug"]`. + + + +✏️ **Теперь ваша очередь!** Определите токенизацию слова `" huggun"` и его оценку. + + + +## Назад к обучению[[back-to-training]] + +Теперь, когда мы увидели, как работает токенизация, мы можем немного глубже изучить потери, используемые во время обучения. На любом этапе эта потеря вычисляется путем токенизации каждого слова в корпусе с использованием текущего словаря и модели Unigram, определяемой частотами каждого токена в корпусе (как было показано ранее). + +Каждое слово в корпусе имеет оценку, а потеря - это отрицательное логарифмическое правдоподобие этих оценок, то есть сумма для всех слов в корпусе всех `-log(P(word))`. + +Давайте вернемся к нашему примеру со следующим корпусом: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +Токенизация каждого слова с соответствующими оценками: + +``` +"hug": ["hug"] (score 0.071428) +"pug": ["pu", "g"] (score 0.007710) +"pun": ["pu", "n"] (score 0.006168) +"bun": ["bu", "n"] (score 0.001451) +"hugs": ["hug", "s"] (score 0.001701) +``` + +Таким образом, потери будут: + +``` +10 * (-log(0.071428)) + 5 * (-log(0.007710)) + 12 * (-log(0.006168)) + 4 * (-log(0.001451)) + 5 * (-log(0.001701)) = 169.8 +``` + +Теперь нам нужно вычислить, как удаление каждого токена влияет на потери. Это довольно утомительно, поэтому мы просто сделаем это для двух токенов и оставим весь процесс на потом, когда у нас будет код, чтобы помочь нам. В этом (очень) конкретном случае у нас есть две эквивалентные токенизации всех слов: как мы видели ранее, например, `"pug"` может быть токенизировано `["p", "ug"]` с тем же результатом. Таким образом, удаление токена `"pu"` из словаря приведет к точно таким же потерям. + +С другой стороны, удаление `" hug"` усугубит потери, потому что токенизация `"hug"` и `"hugs"` станет: + +``` +"hug": ["hu", "g"] (score 0.006802) +"hugs": ["hu", "gs"] (score 0.001701) +``` + +Эти изменения приведут к увеличению потерь: + +``` +- 10 * (-log(0.071428)) + 10 * (-log(0.006802)) = 23.5 +``` + +Поэтому токен `"pu"`, вероятно, будет удален из словаря, но не `"hug"`. + +## Реализация Unigram[[implementing-unigram]] + +Теперь давайте реализуем все, что мы видели до сих пор, в коде. Как и в случае с BPE и WordPiece, это не эффективная реализация алгоритма Unigram (совсем наоборот), но она должна помочь вам понять его немного лучше. + +В качестве примера мы будем использовать тот же корпус текста, что и раньше: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +На этот раз в качестве модели мы будем использовать `xlnet-base-cased`: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased") +``` + +Как и в случае с BPE и WordPiece, мы начинаем с подсчета количества вхождений каждого слова в корпус: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +word_freqs +``` + +Затем нам нужно инициализировать наш словарь чем-то большим, чем размер словаря, который мы захотим получить в конце. Мы должны включить все основные символы (иначе мы не сможем токенизировать каждое слово), но для больших подстрок мы сохраним только самые распространенные, поэтому мы отсортируем их по частоте: + +```python +char_freqs = defaultdict(int) +subwords_freqs = defaultdict(int) +for word, freq in word_freqs.items(): + for i in range(len(word)): + char_freqs[word[i]] += freq + # Перебираем подслова длиной не менее 2 + for j in range(i + 2, len(word) + 1): + subwords_freqs[word[i:j]] += freq + +# Сортировка подслов по частоте +sorted_subwords = sorted(subwords_freqs.items(), key=lambda x: x[1], reverse=True) +sorted_subwords[:10] +``` + +```python out +[('▁t', 7), ('is', 5), ('er', 5), ('▁a', 5), ('▁to', 4), ('to', 4), ('en', 4), ('▁T', 3), ('▁Th', 3), ('▁Thi', 3)] +``` + +Мы группируем символы с лучшими подсловами, чтобы получить начальный словарь размером 300: + +```python +token_freqs = list(char_freqs.items()) + sorted_subwords[: 300 - len(char_freqs)] +token_freqs = {token: freq for token, freq in token_freqs} +``` + + + +💡 SentencePiece использует более эффективный алгоритм под названием Enhanced Suffix Array (ESA) для создания начального словаря. + + + +Далее мы вычисляем сумму всех частот, чтобы преобразовать частоты в вероятности. Для нашей модели мы будем хранить логарифмы вероятностей, потому что численно стабильнее складывать логарифмы, чем перемножать маленькие числа, и это упростит вычисление потерь модели: + +```python +from math import log + +total_sum = sum([freq for token, freq in token_freqs.items()]) +model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} +``` + +Теперь основная функция - это функция токенизации слов с помощью алгоритма Витерби. Как мы уже видели, этот алгоритм вычисляет наилучшую сегментацию каждой подстроки слова, которую мы будем хранить в переменной с именем `best_segmentations`. Мы будем хранить по одному словарю на каждую позицию в слове (от 0 до его полной длины), с двумя ключами: индекс начала последнего токена в лучшей сегментации и оценка лучшей сегментации. По индексу начала последнего токена мы сможем получить полную сегментацию, когда список будет полностью заполнен. + +Пополнение списка осуществляется с помощью двух циклов: основной цикл просматривает каждую начальную позицию, а второй цикл перебирает все подстроки, начинающиеся с этой начальной позиции. Если подстрока есть в словаре, мы получаем новую сегментацию слова до этой конечной позиции, которую сравниваем с той, что хранится в `best_segmentations`. + +После завершения основного цикла мы просто начинаем с конца и переходим от одной начальной позиции к другой, записывая токены по мере продвижения, пока не достигнем начала слова: + +```python +def encode_word(word, model): + best_segmentations = [{"start": 0, "score": 1}] + [ + {"start": None, "score": None} for _ in range(len(word)) + ] + for start_idx in range(len(word)): + # Это должно быть правильно заполнено предыдущими шагами цикла + best_score_at_start = best_segmentations[start_idx]["score"] + for end_idx in range(start_idx + 1, len(word) + 1): + token = word[start_idx:end_idx] + if token in model and best_score_at_start is not None: + score = model[token] + best_score_at_start + # Если мы нашли лучшую сегментацию, заканчивающуюся на end_idx, мы обновляем + if ( + best_segmentations[end_idx]["score"] is None + or best_segmentations[end_idx]["score"] > score + ): + best_segmentations[end_idx] = {"start": start_idx, "score": score} + + segmentation = best_segmentations[-1] + if segmentation["score"] is None: + # Мы не нашли токенизацию слова -> возвращаем unknown + return [""], None + + score = segmentation["score"] + start = segmentation["start"] + end = len(word) + tokens = [] + while start != 0: + tokens.insert(0, word[start:end]) + next_start = best_segmentations[start]["start"] + end = start + start = next_start + tokens.insert(0, word[start:end]) + return tokens, score +``` + +Мы уже можем опробовать нашу первоначальную модель на некоторых словах: + +```python +print(encode_word("Hopefully", model)) +print(encode_word("This", model)) +``` + +```python out +(['H', 'o', 'p', 'e', 'f', 'u', 'll', 'y'], 41.5157494601402) +(['This'], 6.288267030694535) +``` + +Теперь легко вычислить потери модели на корпусе! + +```python +def compute_loss(model): + loss = 0 + for word, freq in word_freqs.items(): + _, word_loss = encode_word(word, model) + loss += freq * word_loss + return loss +``` + +Мы можем проверить его работу на имеющейся у нас модели: + +```python +compute_loss(model) +``` + +```python out +413.10377642940875 +``` + +Вычисление оценок для каждого токена также не представляет особой сложности; нам просто нужно вычислить потери для модели, полученные при удалении каждого токена: + +```python +import copy + + +def compute_scores(model): + scores = {} + model_loss = compute_loss(model) + for token, score in model.items(): + # We always keep tokens of length 1 + if len(token) == 1: + continue + model_without_token = copy.deepcopy(model) + _ = model_without_token.pop(token) + scores[token] = compute_loss(model_without_token) - model_loss + return scores +``` + +Мы можем попробовать это на заданном токене: + +```python +scores = compute_scores(model) +print(scores["ll"]) +print(scores["his"]) +``` + +Поскольку `"ll"` используется в токенизации слова `"Hopefully"`, и его удаление, вероятно, заставит нас дважды использовать токен `"l"` вместо этого, мы ожидаем, что он будет иметь положительную потерю. `"his"` используется только внутри слова `"This"`, которое токенизируется само по себе, поэтому мы ожидаем, что потери будут нулевыми. Вот результаты: + +```python out +6.376412403623874 +0.0 +``` + + + +💡 Такой подход очень неэффективен, поэтому SentencePiece использует приближенную оценку потерь модели без токена X: вместо того чтобы начинать с нуля, он просто заменяет токен X его сегментацией в оставшемся словаре. Таким образом, все оценки могут быть вычислены одновременно с потерями модели. + + + +Когда этот процесс завершиться, останется только добавить в словарь специальные токены, используемые моделью, а затем итерироваться, пока мы не вычеркнем из словаря достаточно токенов, чтобы достичь желаемого размера: + +```python +percent_to_remove = 0.1 +while len(model) > 100: + scores = compute_scores(model) + sorted_scores = sorted(scores.items(), key=lambda x: x[1]) + # Remove percent_to_remove tokens with the lowest scores. + for i in range(int(len(model) * percent_to_remove)): + _ = token_freqs.pop(sorted_scores[i][0]) + + total_sum = sum([freq for token, freq in token_freqs.items()]) + model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} +``` + +Затем, чтобы токенизировать некоторый текст, нам просто нужно применить предварительную токенизацию, а затем использовать нашу функцию `encode_word()`: + +```python +def tokenize(text, model): + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in words_with_offsets] + encoded_words = [encode_word(word, model)[0] for word in pre_tokenized_text] + return sum(encoded_words, []) + + +tokenize("This is the Hugging Face course.", model) +``` + +```python out +['▁This', '▁is', '▁the', '▁Hugging', '▁Face', '▁', 'c', 'ou', 'r', 's', 'e', '.'] +``` + +Вот и все об Unigram! Надеемся, теперь вы чувствуете себя экспертом во всем, что касается токенизаторов. В следующем разделе мы рассмотрим блоки библиотеки 🤗 Tokenizers и покажем, как их можно использовать для создания собственного токенизатора. diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/8-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/8-checkpoint.mdx new file mode 100644 index 000000000..9a7367458 --- /dev/null +++ b/chapters/ru/chapter6/.ipynb_checkpoints/8-checkpoint.mdx @@ -0,0 +1,565 @@ +# Создание токенизатора, блок за блоком[[building-a-tokenizer-block-by-block]] + + + +Как мы уже видели в предыдущих разделах, токенизация состоит из нескольких этапов: + +- Нормализация (любая необходимая очистка текста, например, удаление пробелов или подчеркиваний, нормализация Unicode и т. д.) +- Предварительная токенизация (разделение входного текста на слова). +- Прогон входных данных через модель (использование предварительно токенизированных слов для создания последовательности токенов) +- Постобработка (добавление специальных токенов токенизатора, генерация маски внимания и идентификаторов типов токенов) + +В качестве напоминания вот еще один взгляд на общий процесс: + +
+The tokenization pipeline. + +
+ +Библиотека 🤗 Tokenizers была создана для того, чтобы предоставить несколько вариантов каждого из этих шагов, которые вы можете смешивать и сочетать между собой. В этом разделе мы рассмотрим, как можно создать токенизатор с нуля, а не обучать новый токенизатор на основе старого, как мы делали в [разделе 2](/course/chapter6/2). После этого вы сможете создать любой токенизатор, который только сможете придумать! + + + +Точнее, библиотека построена вокруг центрального класса `Tokenizer`, а строительные блоки сгруппированы в подмодули: + +- `normalizers` содержит все возможные типы нормализаторов текста `Normalizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). +- `pre_tokenizers` содержит все возможные типы предварительных токенизаторов `PreTokenizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). +- `models` содержит различные типы моделей `Model`, которые вы можете использовать, такие как `BPE`, `WordPiece` и `Unigram` (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). +- `trainers` содержит все различные типы `Trainer`, которые вы можете использовать для обучения модели на корпусе (по одному на каждый тип модели; полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). +- `post_processors` содержит различные типы постпроцессоров `PostProcessor`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). +- `decoders` содержит различные типы декодеров `Decoder`, которые вы можете использовать для декодирования результатов токенизации (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). + +Весь список блоков вы можете найти [здесь](https://huggingface.co/docs/tokenizers/python/latest/components.html). + +## Получение корпуса текста[[acquiring-a-corpus]] + +Для обучения нашего нового токенизатора мы будем использовать небольшой корпус текстов (чтобы примеры выполнялись быстро). Шаги по сбору корпуса аналогичны тем, что мы делали в [начале этой главы](/course/chapter6/2), но на этот раз мы будем использовать набор данных [WikiText-2](https://huggingface.co/datasets/wikitext): + +```python +from datasets import load_dataset + +dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train") + + +def get_training_corpus(): + for i in range(0, len(dataset), 1000): + yield dataset[i : i + 1000]["text"] +``` + +Функция `get_training_corpus()` - это генератор, который выдает батч из 1000 текстов, которые мы будем использовать для обучения токенизатора. + +🤗 Токенизаторы также можно обучать непосредственно на текстовых файлах. Вот как мы можем сгенерировать текстовый файл, содержащий все тексты/входы из WikiText-2, который мы можем использовать локально: + +```python +with open("wikitext-2.txt", "w", encoding="utf-8") as f: + for i in range(len(dataset)): + f.write(dataset[i]["text"] + "\n") +``` + +Далее мы покажем вам, как блок за блоком построить собственные токенизаторы BERT, GPT-2 и XLNet. Это даст нам пример каждого из трех основных алгоритмов токенизации: WordPiece, BPE и Unigram. Начнем с BERT! + +## Создание токенизатора WordPiece с нуля[[building-a-wordpiece-tokenizer-from-scratch]] + +Чтобы создать токенизатор с помощью библиотеки 🤗 Tokenizers, мы начнем с инстанцирования объектов `Tokenizer` и `model`, затем установим для их атрибутов `normalizer`, `pre_tokenizer`, `post_processor` и `decoder` нужные нам значения. + +Для этого примера мы создадим `Tokenizer` с моделью WordPiece: + +```python +from tokenizers import ( + decoders, + models, + normalizers, + pre_tokenizers, + processors, + trainers, + Tokenizer, +) + +tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) +``` + +Мы должны указать `unk_token`, чтобы модель знала, что возвращать, когда она встречает символы, которых раньше не видела. Другие аргументы, которые мы можем задать здесь, включают `vocab` нашей модели (мы собираемся обучать модель, поэтому нам не нужно его задавать) и `max_input_chars_per_word`, который определяет максимальную длину для каждого слова (слова длиннее переданного значения будут разбиты на части). + +Первым шагом токенизации является нормализация, поэтому начнем с нее. Поскольку BERT широко используется, существует `BertNormalizer` с классическими параметрами, которые мы можем установить для BERT: `lowercase` и `strip_accents`, которые не требуют пояснений; `clean_text` для удаления всех управляющих символов и замены повторяющихся пробелов на один; и `handle_chinese_chars`, который расставляет пробелы вокруг китайских символов. Чтобы повторить токенизатор `bert-base-uncased`, мы можем просто установить этот нормализатор: + +```python +tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) +``` + +Однако, как правило, при создании нового токенизатора у вас не будет доступа к такому удобному нормализатору, уже реализованному в библиотеке 🤗 Tokenizers, поэтому давайте посмотрим, как создать нормализатор BERT вручную. Библиотека предоставляет нормализатор `Lowercase` и нормализатор `StripAccents`, и вы можете комбинировать несколько нормализаторов с помощью `Sequence`: + +```python +tokenizer.normalizer = normalizers.Sequence( + [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()] +) +``` + +Мы также используем нормализатор Unicode `NFD`, поскольку в противном случае нормализатор `StripAccents` не сможет правильно распознать акцентированные символы и, следовательно, не удалит их. + +Как мы уже видели ранее, мы можем использовать метод `normalize_str()` нормализатора, чтобы проверить, как он влияет на данный текст: + +```python +print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +hello how are u? +``` + + + +**Далее** если вы протестируете две версии предыдущих нормализаторов на строке, содержащей символ Unicode `u"\u0085"`, то наверняка заметите, что эти два нормализатора не совсем эквивалентны. +Чтобы не усложнять версию с `normalizers.Sequence`, мы не включили в нее Regex-замены, которые требует `BertNormalizer`, когда аргумент `clean_text` установлен в `True`, что является поведением по умолчанию. Но не волнуйтесь: можно получить точно такую же нормализацию без использования удобного `BertNormalizer`, добавив два `normalizers.Replace` в последовательность нормализаторов. + + + +Далее следует этап предварительной токенизации. Опять же, есть готовый `BertPreTokenizer`, который мы можем использовать: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() +``` + +Или мы можем создать его с нуля: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() +``` + +Обратите внимание, что токенизатор `Whitespace` разделяет пробельные символы и все символы, которые не являются буквами, цифрами или символом подчеркивания, поэтому технически он разделяет пробельные символы и знаки пунктуации: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +Если вы хотите выполнять разделение только по пробельным символам, то вместо этого следует использовать предварительный токенизатор `WhitespaceSplit`: + +```python +pre_tokenizer = pre_tokenizers.WhitespaceSplit() +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] +``` + +Как и в случае с нормализаторами, вы можете использовать `Sequence` для комбинирования нескольких предварительных токенизаторов: + +```python +pre_tokenizer = pre_tokenizers.Sequence( + [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()] +) +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +Следующий шаг в конвейере токенизации - обработка входных данных с помощью модели. Мы уже указали нашу модель в инициализации, но нам все еще нужно обучить ее, для чего потребуется `WordPieceTrainer`. Главное, что нужно помнить при инстанцировании тренера в 🤗 Tokenizers, это то, что вам нужно передать ему все специальные токены, которые вы собираетесь использовать - иначе он не добавит их в словарь, поскольку их нет в обучающем корпусе: + +```python +special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] +trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) +``` + +Помимо указания `vocab_size` и `special_tokens`, мы можем задать `min_frequency` (количество раз, которое должен встретиться токен, чтобы быть включенным в словарь) или изменить `continuing_subword_prefix` (если мы хотим использовать что-то отличное от `##`). + +Чтобы обучить нашу модель с помощью итератора, который мы определили ранее, достаточно выполнить эту команду: + +```python +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +Мы также можем использовать текстовые файлы для обучения нашего токенизатора, что будет выглядеть следующим образом (предварительно мы повторно инициализируем модель с пустым `WordPiece`): + +```python +tokenizer.model = models.WordPiece(unk_token="[UNK]") +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +В обоих случаях мы можем проверить работу токенизатора на тексте, вызвав метод `encode()`: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] +``` + +Полученное `encoding` представляет собой `Encoding`, которое содержит все необходимые результаты работы токенизатора в разных атрибутах: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask` и `overflowing`. + +Последний шаг в конвейере токенизации - постобработка. Нам нужно добавить токен `[CLS]` в начале и токен `[SEP]` в конце (или после каждого предложения, если у нас есть пара предложений). Для этого мы будем использовать `TemplateProcessor`, но сначала нам нужно узнать идентификаторы токенов `[CLS]` и `[SEP]` в словаре: + +```python +cls_token_id = tokenizer.token_to_id("[CLS]") +sep_token_id = tokenizer.token_to_id("[SEP]") +print(cls_token_id, sep_token_id) +``` + +```python out +(2, 3) +``` + +Чтобы написать шаблон для `TemplateProcessor`, мы должны указать, как обрабатывать одно предложение и пару предложений. Для обоих случаев мы указываем специальные токены, которые мы хотим использовать; первое (или одиночное) предложение представлено `$A`, а второе предложение (если кодируется пара) представлено `$B`. Для каждого из них (специальных токенов и предложений) мы также указываем соответствующий идентификатор типа токена (token type ID) после двоеточия. + +Таким образом, классический шаблон BERT определяется следующим образом: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single=f"[CLS]:0 $A:0 [SEP]:0", + pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1", + special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)], +) +``` + +Обратите внимание, что нам нужно передать идентификаторы специальных токенов, чтобы токенизатор мог правильно преобразовать их в их идентификаторы. + +Как только это будет добавлено, вернемся к нашему предыдущему примеру: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] +``` + +И на паре предложений мы получаем правильный результат: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") +print(encoding.tokens) +print(encoding.type_ids) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]'] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] +``` + +Мы почти закончили создание этого токенизатора с нуля - остался последний шаг - добавить декодер: + +```python +tokenizer.decoder = decoders.WordPiece(prefix="##") +``` + +Давайте проверим его на нашем предыдущем `encoding`: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"let's test this tokenizer... on a pair of sentences." +``` + +Отлично! Мы можем сохранить наш токенизатор в единственном JSON-файле следующим образом: + +```python +tokenizer.save("tokenizer.json") +``` + +Затем мы можем загрузить этот файл в объект `Tokenizer` с помощью метода `from_file()`: + +```python +new_tokenizer = Tokenizer.from_file("tokenizer.json") +``` + +Чтобы использовать этот токенизатор в 🤗 Transformers, мы должны обернуть его в `PreTrainedTokenizerFast`. Мы можем использовать либо общий класс, либо, если наш токенизатор соответствует существующей модели, использовать этот класс (здесь `BertTokenizerFast`). Если вы используете этот урок для создания нового токенизатора, вам придется использовать первый вариант. + +Чтобы обернуть токенизатор в `PreTrainedTokenizerFast`, мы можем либо передать собранный нами токенизатор как `tokenizer_object`, либо передать сохраненный файл токенизатора как `tokenizer_file`. Главное помнить, что нам придется вручную задавать все специальные токены, поскольку класс не может определить из объекта `tokenizer`, какой токен является токеном маски, токеном `[CLS]` и т. д.: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + # tokenizer_file="tokenizer.json", # В качестве альтернативы можно загрузить из файла токенизатора. + unk_token="[UNK]", + pad_token="[PAD]", + cls_token="[CLS]", + sep_token="[SEP]", + mask_token="[MASK]", +) +``` + +Если вы используете определенный класс токенизатора (например, `BertTokenizerFast`), вам нужно будет указать только специальные токены, которые отличаются от токенов по умолчанию (здесь их нет): + +```python +from transformers import BertTokenizerFast + +wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) +``` + +Затем вы можете использовать этот токенизатор, как и любой другой 🤗 токенизатор Transformers. Вы можете сохранить его с помощью метода `save_pretrained()` или загрузить на хаб с помощью метода `push_to_hub()`. + +Теперь, когда мы рассмотрели, как создать токенизатор WordPiece, давайте сделаем то же самое для токенизатора BPE. Мы будем двигаться немного быстрее, поскольку вы знаете все шаги, и подчеркнем только различия. + +## Создание токенизатора BPE с нуля[[building-a-bpe-tokenizer-from-scratch]] + +Теперь давайте создадим токенизатор GPT-2. Как и в случае с токенизатором BERT, мы начнем с инициализации `Tokenizer` с моделью BPE: + +```python +tokenizer = Tokenizer(models.BPE()) +``` + +Also like for BERT, we could initialize this model with a vocabulary if we had one (we would need to pass the `vocab` and `merges` in this case), but since we will train from scratch, we don't need to do that. We also don't need to specify an `unk_token` because GPT-2 uses byte-level BPE, which doesn't require it. + +GPT-2 does not use a normalizer, so we skip that step and go directly to the pre-tokenization: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) +``` + +The option we added to `ByteLevel` here is to not add a space at the beginning of a sentence (which is the default otherwise). We can have a look at the pre-tokenization of an example text like before: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") +``` + +```python out +[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)), + ('tokenization', (15, 27)), ('!', (27, 28))] +``` + +Next is the model, which needs training. For GPT-2, the only special token is the end-of-text token: + +```python +trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +Like with the `WordPieceTrainer`, as well as the `vocab_size` and `special_tokens`, we can specify the `min_frequency` if we want to, or if we have an end-of-word suffix (like ``), we can set it with `end_of_word_suffix`. + +This tokenizer can also be trained on text files: + +```python +tokenizer.model = models.BPE() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +Let's have a look at the tokenization of a sample text: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] +``` + +We apply the byte-level post-processing for the GPT-2 tokenizer as follows: + +```python +tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) +``` + +The `trim_offsets = False` option indicates to the post-processor that we should leave the offsets of tokens that begin with 'Ġ' as they are: this way the start of the offsets will point to the space before the word, not the first character of the word (since the space is technically part of the token). Let's have a look at the result with the text we just encoded, where `'Ġtest'` is the token at index 4: + +```python +sentence = "Let's test this tokenizer." +encoding = tokenizer.encode(sentence) +start, end = encoding.offsets[4] +sentence[start:end] +``` + +```python out +' test' +``` + +Finally, we add a byte-level decoder: + +```python +tokenizer.decoder = decoders.ByteLevel() +``` + +and we can double-check it works properly: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"Let's test this tokenizer." +``` + +Great! Now that we're done, we can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `GPT2TokenizerFast` if we want to use it in 🤗 Transformers: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="<|endoftext|>", + eos_token="<|endoftext|>", +) +``` + +or: + +```python +from transformers import GPT2TokenizerFast + +wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) +``` + +As the last example, we'll show you how to build a Unigram tokenizer from scratch. + +## Building a Unigram tokenizer from scratch[[building-a-unigram-tokenizer-from-scratch]] + +Let's now build an XLNet tokenizer. Like for the previous tokenizers, we start by initializing a `Tokenizer` with a Unigram model: + +```python +tokenizer = Tokenizer(models.Unigram()) +``` + +Again, we could initialize this model with a vocabulary if we had one. + +For the normalization, XLNet uses a few replacements (which come from SentencePiece): + +```python +from tokenizers import Regex + +tokenizer.normalizer = normalizers.Sequence( + [ + normalizers.Replace("``", '"'), + normalizers.Replace("''", '"'), + normalizers.NFKD(), + normalizers.StripAccents(), + normalizers.Replace(Regex(" {2,}"), " "), + ] +) +``` + +This replaces `` and '' with " and any sequence of two or more spaces with a single space, as well as removing the accents in the texts to tokenize. + +The pre-tokenizer to use for any SentencePiece tokenizer is `Metaspace`: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() +``` + +We can have a look at the pre-tokenization of an example text like before: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") +``` + +```python out +[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] +``` + +Next is the model, which needs training. XLNet has quite a few special tokens: + +```python +special_tokens = ["", "", "", "", "", "", ""] +trainer = trainers.UnigramTrainer( + vocab_size=25000, special_tokens=special_tokens, unk_token="" +) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +A very important argument not to forget for the `UnigramTrainer` is the `unk_token`. We can also pass along other arguments specific to the Unigram algorithm, such as the `shrinking_factor` for each step where we remove tokens (defaults to 0.75) or the `max_piece_length` to specify the maximum length of a given token (defaults to 16). + +This tokenizer can also be trained on text files: + +```python +tokenizer.model = models.Unigram() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +Let's have a look at the tokenization of a sample text: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] +``` + +A peculiarity of XLNet is that it puts the `` token at the end of the sentence, with a type ID of 2 (to distinguish it from the other tokens). It's padding on the left, as a result. We can deal with all the special tokens and token type IDs with a template, like for BERT, but first we have to get the IDs of the `` and `` tokens: + +```python +cls_token_id = tokenizer.token_to_id("") +sep_token_id = tokenizer.token_to_id("") +print(cls_token_id, sep_token_id) +``` + +```python out +0 1 +``` + +The template looks like this: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single="$A:0 :0 :2", + pair="$A:0 :0 $B:1 :1 :2", + special_tokens=[("", sep_token_id), ("", cls_token_id)], +) +``` + +And we can test it works by encoding a pair of sentences: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") +print(encoding.tokens) +print(encoding.type_ids) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '', '▁', 'on', '▁', 'a', '▁pair', + '▁of', '▁sentence', 's', '!', '', ''] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] +``` + +Finally, we add a `Metaspace` decoder: + +```python +tokenizer.decoder = decoders.Metaspace() +``` + +and we're done with this tokenizer! We can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `XLNetTokenizerFast` if we want to use it in 🤗 Transformers. One thing to note when using `PreTrainedTokenizerFast` is that on top of the special tokens, we need to tell the 🤗 Transformers library to pad on the left: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="", + eos_token="", + unk_token="", + pad_token="", + cls_token="", + sep_token="", + mask_token="", + padding_side="left", +) +``` + +Or alternatively: + +```python +from transformers import XLNetTokenizerFast + +wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) +``` + +Now that you have seen how the various building blocks are used to build existing tokenizers, you should be able to write any tokenizer you want with the 🤗 Tokenizers library and be able to use it in 🤗 Transformers. diff --git a/chapters/ru/chapter6/6.mdx b/chapters/ru/chapter6/6.mdx index bc512fc73..a462d82f2 100644 --- a/chapters/ru/chapter6/6.mdx +++ b/chapters/ru/chapter6/6.mdx @@ -78,31 +78,31 @@ Corpus: ("hug", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "## -✏️ ** Теперь ваша очередь! ** Каким будет следующее правило слияния? +✏️ **Теперь ваша очередь!** Каким будет следующее правило слияния? ## Алгоритм токенизации[[tokenization-algorithm]] -Tokenization differs in WordPiece and BPE in that WordPiece only saves the final vocabulary, not the merge rules learned. Starting from the word to tokenize, WordPiece finds the longest subword that is in the vocabulary, then splits on it. For instance, if we use the vocabulary learned in the example above, for the word `"hugs"` the longest subword starting from the beginning that is inside the vocabulary is `"hug"`, so we split there and get `["hug", "##s"]`. We then continue with `"##s"`, which is in the vocabulary, so the tokenization of `"hugs"` is `["hug", "##s"]`. +Токенизация в WordPiece и BPE отличается тем, что WordPiece сохраняет только конечный словарь, а не выученные правила слияния. Начиная со слова, которое нужно токенизировать, WordPiece находит самое длинное подслово, которое есть в словаре, а затем разбивает его на части. Например, если мы используем словарь, изученный в примере выше, для слова `" hugs"` самым длинным подсловом, начиная с начала, которое находится в словаре, является `"hug"`, поэтому мы делим его на части и получаем `["hug", "##s"]`. Затем мы продолжаем с `"##s"`, которое находится в словаре, поэтому токенизация `"hugs"` будет `["hug", "##s"]`. -With BPE, we would have applied the merges learned in order and tokenized this as `["hu", "##gs"]`, so the encoding is different. +В BPE мы бы применили слияния, выученные по порядку, и токенизировали это как `["hu", "##gs"]`, поэтому кодировка отличается. -As another example, let's see how the word `"bugs"` would be tokenized. `"b"` is the longest subword starting at the beginning of the word that is in the vocabulary, so we split there and get `["b", "##ugs"]`. Then `"##u"` is the longest subword starting at the beginning of `"##ugs"` that is in the vocabulary, so we split there and get `["b", "##u, "##gs"]`. Finally, `"##gs"` is in the vocabulary, so this last list is the tokenization of `"bugs"`. +В качестве другого примера посмотрим, как будет токенизировано слово `"bugs"`. `"b"` - самое длинное подслово, начинающееся с начала слова, которое есть в словаре, поэтому мы делим его на части и получаем `["b", "##ugs"]`. Затем `"##u"` - самое длинное подслово, начинающееся в начале `"##ugs"`, которое есть в словаре, поэтому мы делим его на части и получаем `["b", "##u", "##gs"]`. Наконец, `"##gs"` находится в словаре, так что этот последний список является токеном `"bugs"`. -When the tokenization gets to a stage where it's not possible to find a subword in the vocabulary, the whole word is tokenized as unknown -- so, for instance, `"mug"` would be tokenized as `["[UNK]"]`, as would `"bum"` (even if we can begin with `"b"` and `"##u"`, `"##m"` is not the vocabulary, and the resulting tokenization will just be `["[UNK]"]`, not `["b", "##u", "[UNK]"]`). This is another difference from BPE, which would only classify the individual characters not in the vocabulary as unknown. +Когда токенизация доходит до стадии, когда невозможно найти подслово в словаре, все слово токенизируется как неизвестное - так, например, `"mug"` будет токенизировано как `["[UNK]"]`, как и `"bum"` (даже если мы можем начать с `"b"` и `"##u"`, `"##m"` не входит в словарь, и результирующий токен будет просто `["[UNK]"]`, а не `["b", "##u", "[UNK]"]`). Это еще одно отличие от BPE, который классифицирует как неизвестные только отдельные символы, отсутствующие в словаре. -✏️ **Now your turn!** How will the word `"pugs"` be tokenized? +✏️ **Теперь ваша очередь!** Как будет токенизировано слово `"pugs"`? ## Реализация WordPiece[[implementing-wordpiece]] -Now let's take a look at an implementation of the WordPiece algorithm. Like with BPE, this is just pedagogical, and you won't able to use this on a big corpus. +Теперь давайте посмотрим на реализацию алгоритма WordPiece. Как и в случае с BPE, это всего лишь учебный пример, и вы не сможете использовать его на большом корпусе. -We will use the same corpus as in the BPE example: +Мы будем использовать тот же корпус, что и в примере с BPE: ```python corpus = [ @@ -113,7 +113,7 @@ corpus = [ ] ``` -First, we need to pre-tokenize the corpus into words. Since we are replicating a WordPiece tokenizer (like BERT), we will use the `bert-base-cased` tokenizer for the pre-tokenization: +Во-первых, нам нужно предварительно токенизировать корпус в слова. Поскольку мы воспроизводим токенизатор WordPiece (например, BERT), для предварительной токенизации мы будем использовать токенизатор `bert-base-cased`: ```python from transformers import AutoTokenizer @@ -121,7 +121,7 @@ from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") ``` -Then we compute the frequencies of each word in the corpus as we do the pre-tokenization: +Затем мы вычисляем частоту каждого слова в корпусе, как и при предварительной токенизации: ```python from collections import defaultdict @@ -144,7 +144,7 @@ defaultdict( 'trained': 1, 'and': 1, 'generate': 1, 'tokens': 1}) ``` -As we saw before, the alphabet is the unique set composed of all the first letters of words, and all the other letters that appear in words prefixed by `##`: +Как мы уже видели, алфавит - это уникальное множество, состоящее из всех первых букв слов и всех остальных букв, которые встречаются в словах с префиксом `##`: ```python alphabet = [] @@ -167,13 +167,13 @@ print(alphabet) 'w', 'y'] ``` -We also add the special tokens used by the model at the beginning of that vocabulary. In the case of BERT, it's the list `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]`: +Мы также добавляем специальные токены, используемые моделью, в начало этого словаря. В случае BERT это список `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]`: ```python vocab = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] + alphabet.copy() ``` -Next we need to split each word, with all the letters that are not the first prefixed by `##`: +Далее нам нужно разделить каждое слово на части, при этом все буквы, которые не являются первыми, должны иметь префикс `##`: ```python splits = { @@ -182,7 +182,7 @@ splits = { } ``` -Now that we are ready for training, let's write a function that computes the score of each pair. We'll need to use this at each step of the training: +Теперь, когда мы готовы к обучению, давайте напишем функцию, которая вычисляет оценку каждой пары. Нам нужно будет использовать ее на каждом шаге обучения: ```python def compute_pair_scores(splits): @@ -206,7 +206,7 @@ def compute_pair_scores(splits): return scores ``` -Let's have a look at a part of this dictionary after the initial splits: +Давайте посмотрим на часть этого словаря после первых разделений: ```python pair_scores = compute_pair_scores(splits) @@ -225,7 +225,7 @@ for i, key in enumerate(pair_scores.keys()): ('##h', '##e'): 0.011904761904761904 ``` -Now, finding the pair with the best score only takes a quick loop: +Теперь для того, чтобы найти пару с наилучшим результатом, нужно всего лишь сделать быстрый цикл: ```python best_pair = "" @@ -242,13 +242,13 @@ print(best_pair, max_score) ('a', '##b') 0.2 ``` -So the first merge to learn is `('a', '##b') -> 'ab'`, and we add `'ab'` to the vocabulary: +Итак, первое слияние, которое нужно выучить, это `('a', '##b') -> 'ab'`, и мы добавляем `'ab'` в словарь: ```python vocab.append("ab") ``` -To continue, we need to apply that merge in our `splits` dictionary. Let's write another function for this: +Чтобы продолжить, нам нужно применить это слияние в нашем словаре `splits`. Давайте напишем для этого еще одну функцию: ```python def merge_pair(a, b, splits): @@ -267,7 +267,7 @@ def merge_pair(a, b, splits): return splits ``` -And we can have a look at the result of the first merge: +И мы можем посмотреть на результат первого слияния: ```py splits = merge_pair("a", "##b", splits) @@ -278,7 +278,7 @@ splits["about"] ['ab', '##o', '##u', '##t'] ``` -Now we have everything we need to loop until we have learned all the merges we want. Let's aim for a vocab size of 70: +Теперь у нас есть все, что нужно, чтобы зацикливать процесс до тех пор, пока мы не выучим все слияния, которые нам нужны. Давайте нацелимся на размер словаря равный 70: ```python vocab_size = 70 @@ -298,7 +298,7 @@ while len(vocab) < vocab_size: vocab.append(new_token) ``` -We can then look at the generated vocabulary: +Затем мы можем просмотреть созданный словарь: ```py print(vocab) @@ -312,15 +312,15 @@ print(vocab) '##ut'] ``` -As we can see, compared to BPE, this tokenizer learns parts of words as tokens a bit faster. +Как мы видим, по сравнению с BPE этот токенизатор быстрее выучивает части слов как токены. -💡 Using `train_new_from_iterator()` on the same corpus won't result in the exact same vocabulary. This is because the 🤗 Tokenizers library does not implement WordPiece for the training (since we are not completely sure of its internals), but uses BPE instead. +💡 Использование `train_new_from_iterator()` на одном и том же корпусе не приведет к точно такому же словарю. Это происходит потому, что библиотека 🤗 Tokenizers не реализует WordPiece для обучения (поскольку мы не полностью уверены в его внутреннем устройстве), а использует вместо него BPE. -To tokenize a new text, we pre-tokenize it, split it, then apply the tokenization algorithm on each word. That is, we look for the biggest subword starting at the beginning of the first word and split it, then we repeat the process on the second part, and so on for the rest of that word and the following words in the text: +Чтобы токенизировать новый текст, мы предварительно токенизируем его, разбиваем на части, а затем применяем алгоритм токенизации к каждому слову. То есть начиная с первого слова мы ищем самое большое подслово и разбиваем его на части, затем мы повторяем процесс для второй части, и так далее для оставшейся части этого слова и следующих слов в тексте: ```python def encode_word(word): @@ -338,7 +338,7 @@ def encode_word(word): return tokens ``` -Let's test it on one word that's in the vocabulary, and another that isn't: +Давайте проверим алгоритм на одном слове, которое есть в словаре, и на другом, которого нет: ```python print(encode_word("Hugging")) @@ -350,7 +350,7 @@ print(encode_word("HOgging")) ['[UNK]'] ``` -Now, let's write a function that tokenizes a text: +Теперь давайте напишем функцию, которая токенизирует текст: ```python def tokenize(text): @@ -360,7 +360,7 @@ def tokenize(text): return sum(encoded_words, []) ``` -We can try it on any text: +Мы можем попробовать его на любом тексте: ```python tokenize("This is the Hugging Face course!") @@ -371,4 +371,4 @@ tokenize("This is the Hugging Face course!") '##e', '[UNK]'] ``` -That's it for the WordPiece algorithm! Now let's take a look at Unigram. +Вот и все об алгоритме WordPiece! Теперь давайте посмотрим на Unigram. diff --git a/chapters/ru/chapter6/7.mdx b/chapters/ru/chapter6/7.mdx index 505cf7588..032c92f79 100644 --- a/chapters/ru/chapter6/7.mdx +++ b/chapters/ru/chapter6/7.mdx @@ -1,4 +1,4 @@ -# Unigram tokenization[[unigram-tokenization]] +# Токенизация Unigram[[unigram-tokenization]] -The Unigram algorithm is often used in SentencePiece, which is the tokenization algorithm used by models like AlBERT, T5, mBART, Big Bird, and XLNet. +Алгоритм Unigram часто используется в SentencePiece, который является алгоритмом токенизации, применяемым в таких моделях, как AlBERT, T5, mBART, Big Bird и XLNet. -💡 This section covers Unigram in depth, going as far as showing a full implementation. You can skip to the end if you just want a general overview of the tokenization algorithm. +💡 В этом разделе подробно рассматривается Unigram, вплоть до демонстрации полной реализации. Вы можете пропустить его, если вам нужен только общий обзор алгоритма токенизации. -## Training algorithm[[training-algorithm]] +## Алгоритм обучения[[training-algorithm]] -Compared to BPE and WordPiece, Unigram works in the other direction: it starts from a big vocabulary and removes tokens from it until it reaches the desired vocabulary size. There are several options to use to build that base vocabulary: we can take the most common substrings in pre-tokenized words, for instance, or apply BPE on the initial corpus with a large vocabulary size. +По сравнению с BPE и WordPiece, Unigram работает в другом направлении: он начинает с большого словарного запаса и удаляет из него токены, пока не достигнет желаемого размера словаря. Существует несколько вариантов создания базового словаря: например, мы можем взять наиболее часто встречающиеся подстроки в предварительно токенизированных словах или применить BPE к исходному корпусу с большим объемом словаря. -At each step of the training, the Unigram algorithm computes a loss over the corpus given the current vocabulary. Then, for each symbol in the vocabulary, the algorithm computes how much the overall loss would increase if the symbol was removed, and looks for the symbols that would increase it the least. Those symbols have a lower effect on the overall loss over the corpus, so in a sense they are "less needed" and are the best candidates for removal. +На каждом шаге обучения алгоритм Unigram рассчитывает потери по корпусу с учетом текущего словарного запаса. Затем для каждого символа в словаре алгоритм вычисляет, насколько увеличится общая потеря, если этот символ будет удален, и ищет символы, которые увеличат ее меньше всего. Эти символы оказывают меньшее влияние на общую потерю по корпусу, поэтому в некотором смысле они "менее нужны" и являются лучшими кандидатами на удаление. -This is all a very costly operation, so we don't just remove the single symbol associated with the lowest loss increase, but the \\(p\\) (\\(p\\) being a hyperparameter you can control, usually 10 or 20) percent of the symbols associated with the lowest loss increase. This process is then repeated until the vocabulary has reached the desired size. +Это очень дорогостоящая операция, поэтому мы удаляем не просто один символ, связанный с наименьшим увеличением потерь, а \\(p\\) (\\(p\\) - гиперпараметр, которым вы можете управлять, обычно 10 или 20) процентов символов, связанных с наименьшим увеличением потерь. Этот процесс повторяется до тех пор, пока словарь не достигнет желаемого размера. -Note that we never remove the base characters, to make sure any word can be tokenized. +Обратите внимание, что мы никогда не удаляем базовые символы, чтобы убедиться, что любое слово может быть токенизировано. -Now, this is still a bit vague: the main part of the algorithm is to compute a loss over the corpus and see how it changes when we remove some tokens from the vocabulary, but we haven't explained how to do this yet. This step relies on the tokenization algorithm of a Unigram model, so we'll dive into this next. +Итак, все еще немного туманно: основная часть алгоритма заключается в том, чтобы вычислить потери по корпусу и посмотреть, как они изменяются при удалении некоторых токенов из словаря, но мы еще не объяснили, как это сделать. Этот шаг зависит от алгоритма токенизации модели Unigram, поэтому мы рассмотрим его далее. -We'll reuse the corpus from the previous examples: +Мы используем корпус текста из предыдущих примеров: ``` ("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) ``` -and for this example, we will take all strict substrings for the initial vocabulary : +и для этого примера мы возьмем все подстроки из исходного словаря: ``` ["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"] ``` -## Tokenization algorithm[[tokenization-algorithm]] +## Алгоритм токенизации[[tokenization-algorithm]] -A Unigram model is a type of language model that considers each token to be independent of the tokens before it. It's the simplest language model, in the sense that the probability of token X given the previous context is just the probability of token X. So, if we used a Unigram language model to generate text, we would always predict the most common token. +Модель Unigram - это тип языковой модели, в которой каждый токен рассматривается как независимый от предшествующих ему. Это самая простая языковая модель в том смысле, что вероятность появления токена X с учетом предыдущего контекста - это просто вероятность появления токена X. Таким образом, если бы мы использовали модель Unigram для генерации текста, мы бы всегда предсказывали наиболее часто встречающийся токен. -The probability of a given token is its frequency (the number of times we find it) in the original corpus, divided by the sum of all frequencies of all tokens in the vocabulary (to make sure the probabilities sum up to 1). For instance, `"ug"` is present in `"hug"`, `"pug"`, and `"hugs"`, so it has a frequency of 20 in our corpus. +Вероятность данного токена - это его частота (количество раз, когда мы его находим) в исходном корпусе, деленная на сумму частот всех токенов в словаре (чтобы убедиться, что суммы вероятностей равны 1). Например, `"ug"` присутствует в `"hug"`, `"pug"` и `"hugs"`, поэтому его частота в нашем корпусе равна 20. -Here are the frequencies of all the possible subwords in the vocabulary: +Здесь приведены частоты всех возможных подслов в словаре: ``` ("h", 15) ("u", 36) ("g", 20) ("hu", 15) ("ug", 20) ("p", 17) ("pu", 17) ("n", 16) ("un", 16) ("b", 4) ("bu", 4) ("s", 5) ("hug", 15) ("gs", 5) ("ugs", 5) ``` -So, the sum of all frequencies is 210, and the probability of the subword `"ug"` is thus 20/210. +Итак, сумма всех частот равна 210, а вероятность появления подслова `"ug"`, таким образом, составляет 20/210. -✏️ **Now your turn!** Write the code to compute the the frequencies above and double-check that the results shown are correct, as well as the total sum. +✏️ **Теперь ваша очередь!** Напишите код для вычисления вышеуказанных частот и дважды проверьте правильность приведенных результатов, а также общую сумму. -Now, to tokenize a given word, we look at all the possible segmentations into tokens and compute the probability of each according to the Unigram model. Since all tokens are considered independent, this probability is just the product of the probability of each token. For instance, the tokenization `["p", "u", "g"]` of `"pug"` has the probability: +Теперь для токенизации данного слова мы рассматриваем все возможные сегментации на токены и вычисляем вероятность каждого из них в соответствии с моделью Unigram. Поскольку все токены считаются независимыми, эта вероятность равна произведению вероятностей появления каждого токена. Например, при токенизации `["p", "u", "g"]` слова `"pug"` вероятность составляет: $$P([``p", ``u", ``g"]) = P(``p") \times P(``u") \times P(``g") = \frac{5}{210} \times \frac{36}{210} \times \frac{20}{210} = 0.000389$$ -Comparatively, the tokenization `["pu", "g"]` has the probability: +Для сравнения, токен `["pu", "g"]` имеет вероятность: $$P([``pu", ``g"]) = P(``pu") \times P(``g") = \frac{5}{210} \times \frac{20}{210} = 0.0022676$$ -so that one is way more likely. In general, tokenizations with the least tokens possible will have the highest probability (because of that division by 210 repeated for each token), which corresponds to what we want intuitively: to split a word into the least number of tokens possible. +так что один из них гораздо более вероятен. В целом, токенизации с наименьшим количеством токенов будут иметь наибольшую вероятность (из-за деления на 210, повторяющегося для каждого токена), что соответствует интуитивному желанию: разбить слово на наименьшее количество токенов. -The tokenization of a word with the Unigram model is then the tokenization with the highest probability. In the example of `"pug"`, here are the probabilities we would get for each possible segmentation: +Токенизация слова с помощью модели Unigram - это токенизация с наибольшей вероятностью. В примере с `"pug"` приведены вероятности, которые мы получили бы для каждой возможной сегментации: ``` ["p", "u", "g"] : 0.000389 @@ -80,13 +80,13 @@ The tokenization of a word with the Unigram model is then the tokenization with ["pu", "g"] : 0.0022676 ``` -So, `"pug"` would be tokenized as `["p", "ug"]` or `["pu", "g"]`, depending on which of those segmentations is encountered first (note that in a larger corpus, equality cases like this will be rare). +Так, `"pug"` будет токенизировано как `["p", "ug"]` или `["pu", "g"]`, в зависимости от того, какая из этих сегментаций встретится первой (отметим, что в большом корпусе подобные случаи равенства будут редки). -In this case, it was easy to find all the possible segmentations and compute their probabilities, but in general it's going to be a bit harder. There is a classic algorithm used for this, called the *Viterbi algorithm*. Essentially, we can build a graph to detect the possible segmentations of a given word by saying there is a branch from character _a_ to character _b_ if the subword from _a_ to _b_ is in the vocabulary, and attribute to that branch the probability of the subword. +В данном случае было легко найти все возможные сегментации и вычислить их вероятности, но в общем случае это будет немного сложнее. Для этого используется классический алгоритм, который называется *алгоритм Витерби (Viterbi algorithm)*. По сути, мы можем построить граф для выявления возможных сегментаций данного слова, сказав, что существует ветвь от символа _a_ до символа _b_, если подслово от _a_ до _b_ есть в словаре, и приписать этой ветви вероятность подслова. -To find the path in that graph that is going to have the best score the Viterbi algorithm determines, for each position in the word, the segmentation with the best score that ends at that position. Since we go from the beginning to the end, that best score can be found by looping through all subwords ending at the current position and then using the best tokenization score from the position this subword begins at. Then, we just have to unroll the path taken to arrive at the end. +Чтобы найти путь в этом графе, который будет иметь наилучшую оценку, алгоритм Витерби определяет для каждой позиции в слове сегментацию с наилучшей оценкой, которая заканчивается на этой позиции. Поскольку мы идем от начала к концу, этот лучший результат можно найти, перебирая все подслова, заканчивающиеся на текущей позиции, а затем используя лучший результат токенизации с позиции, на которой начинается это подслово. Затем нужно просто развернуть путь, чтобы прийти к концу. -Let's take a look at an example using our vocabulary and the word `"unhug"`. For each position, the subwords with the best scores ending there are the following: +Давайте рассмотрим пример с использованием нашего словаря и слова `"unhug"`. Для каждой позиции подслова с наилучшими оценками заканчиваются следующим образом: ``` Character 0 (u): "u" (score 0.171429) @@ -96,27 +96,27 @@ Character 3 (u): "un" "hu" (score 0.005442) Character 4 (g): "un" "hug" (score 0.005442) ``` -Thus `"unhug"` would be tokenized as `["un", "hug"]`. +Таким образом, `"unhug"` будет токенизировано как `["un", "hug"]`. -✏️ **Now your turn!** Determine the tokenization of the word `"huggun"`, and its score. +✏️ **Теперь ваша очередь!** Определите токенизацию слова `" huggun"` и его оценку. -## Back to training[[back-to-training]] +## Назад к обучению[[back-to-training]] -Now that we have seen how the tokenization works, we can dive a little more deeply into the loss used during training. At any given stage, this loss is computed by tokenizing every word in the corpus, using the current vocabulary and the Unigram model determined by the frequencies of each token in the corpus (as seen before). +Теперь, когда мы увидели, как работает токенизация, мы можем немного глубже изучить потери, используемые во время обучения. На любом этапе эта потеря вычисляется путем токенизации каждого слова в корпусе с использованием текущего словаря и модели Unigram, определяемой частотами каждого токена в корпусе (как было показано ранее). -Each word in the corpus has a score, and the loss is the negative log likelihood of those scores -- that is, the sum for all the words in the corpus of all the `-log(P(word))`. +Каждое слово в корпусе имеет оценку, а потеря - это отрицательное логарифмическое правдоподобие этих оценок, то есть сумма для всех слов в корпусе всех `-log(P(word))`. -Let's go back to our example with the following corpus: +Давайте вернемся к нашему примеру со следующим корпусом: ``` ("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) ``` -The tokenization of each word with their respective scores is: +Токенизация каждого слова с соответствующими оценками: ``` "hug": ["hug"] (score 0.071428) @@ -126,34 +126,34 @@ The tokenization of each word with their respective scores is: "hugs": ["hug", "s"] (score 0.001701) ``` -So the loss is: +Таким образом, потери будут: ``` 10 * (-log(0.071428)) + 5 * (-log(0.007710)) + 12 * (-log(0.006168)) + 4 * (-log(0.001451)) + 5 * (-log(0.001701)) = 169.8 ``` -Now we need to compute how removing each token affects the loss. This is rather tedious, so we'll just do it for two tokens here and save the whole process for when we have code to help us. In this (very) particular case, we had two equivalent tokenizations of all the words: as we saw earlier, for example, `"pug"` could be tokenized `["p", "ug"]` with the same score. Thus, removing the `"pu"` token from the vocabulary will give the exact same loss. +Теперь нам нужно вычислить, как удаление каждого токена влияет на потери. Это довольно утомительно, поэтому мы просто сделаем это для двух токенов и оставим весь процесс на потом, когда у нас будет код, чтобы помочь нам. В этом (очень) конкретном случае у нас есть две эквивалентные токенизации всех слов: как мы видели ранее, например, `"pug"` может быть токенизировано `["p", "ug"]` с тем же результатом. Таким образом, удаление токена `"pu"` из словаря приведет к точно таким же потерям. -On the other hand, removing `"hug"` will make the loss worse, because the tokenization of `"hug"` and `"hugs"` will become: +С другой стороны, удаление `" hug"` усугубит потери, потому что токенизация `"hug"` и `"hugs"` станет: ``` "hug": ["hu", "g"] (score 0.006802) "hugs": ["hu", "gs"] (score 0.001701) ``` -These changes will cause the loss to rise by: +Эти изменения приведут к увеличению потерь: ``` - 10 * (-log(0.071428)) + 10 * (-log(0.006802)) = 23.5 ``` -Therefore, the token `"pu"` will probably be removed from the vocabulary, but not `"hug"`. +Поэтому токен `"pu"`, вероятно, будет удален из словаря, но не `"hug"`. -## Implementing Unigram[[implementing-unigram]] +## Реализация Unigram[[implementing-unigram]] -Now let's implement everything we've seen so far in code. Like with BPE and WordPiece, this is not an efficient implementation of the Unigram algorithm (quite the opposite), but it should help you understand it a bit better. +Теперь давайте реализуем все, что мы видели до сих пор, в коде. Как и в случае с BPE и WordPiece, это не эффективная реализация алгоритма Unigram (совсем наоборот), но она должна помочь вам понять его немного лучше. -We will use the same corpus as before as an example: +В качестве примера мы будем использовать тот же корпус текста, что и раньше: ```python corpus = [ @@ -164,7 +164,7 @@ corpus = [ ] ``` -This time, we will use `xlnet-base-cased` as our model: +На этот раз в качестве модели мы будем использовать `xlnet-base-cased`: ```python from transformers import AutoTokenizer @@ -172,7 +172,7 @@ from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased") ``` -Like for BPE and WordPiece, we begin by counting the number of occurrences of each word in the corpus: +Как и в случае с BPE и WordPiece, мы начинаем с подсчета количества вхождений каждого слова в корпус: ```python from collections import defaultdict @@ -187,7 +187,7 @@ for text in corpus: word_freqs ``` -Then, we need to initialize our vocabulary to something larger than the vocab size we will want at the end. We have to include all the basic characters (otherwise we won't be able to tokenize every word), but for the bigger substrings we'll only keep the most common ones, so we sort them by frequency: +Затем нам нужно инициализировать наш словарь чем-то большим, чем размер словаря, который мы захотим получить в конце. Мы должны включить все основные символы (иначе мы не сможем токенизировать каждое слово), но для больших подстрок мы сохраним только самые распространенные, поэтому мы отсортируем их по частоте: ```python char_freqs = defaultdict(int) @@ -195,11 +195,11 @@ subwords_freqs = defaultdict(int) for word, freq in word_freqs.items(): for i in range(len(word)): char_freqs[word[i]] += freq - # Loop through the subwords of length at least 2 + # Перебираем подслова длиной не менее 2 for j in range(i + 2, len(word) + 1): subwords_freqs[word[i:j]] += freq -# Sort subwords by frequency +# Сортировка подслов по частоте sorted_subwords = sorted(subwords_freqs.items(), key=lambda x: x[1], reverse=True) sorted_subwords[:10] ``` @@ -208,7 +208,7 @@ sorted_subwords[:10] [('▁t', 7), ('is', 5), ('er', 5), ('▁a', 5), ('▁to', 4), ('to', 4), ('en', 4), ('▁T', 3), ('▁Th', 3), ('▁Thi', 3)] ``` -We group the characters with the best subwords to arrive at an initial vocabulary of size 300: +Мы группируем символы с лучшими подсловами, чтобы получить начальный словарь размером 300: ```python token_freqs = list(char_freqs.items()) + sorted_subwords[: 300 - len(char_freqs)] @@ -217,11 +217,11 @@ token_freqs = {token: freq for token, freq in token_freqs} -💡 SentencePiece uses a more efficient algorithm called Enhanced Suffix Array (ESA) to create the initial vocabulary. +💡 SentencePiece использует более эффективный алгоритм под названием Enhanced Suffix Array (ESA) для создания начального словаря. -Next, we compute the sum of all frequencies, to convert the frequencies into probabilities. For our model we will store the logarithms of the probabilities, because it's more numerically stable to add logarithms than to multiply small numbers, and this will simplify the computation of the loss of the model: +Далее мы вычисляем сумму всех частот, чтобы преобразовать частоты в вероятности. Для нашей модели мы будем хранить логарифмы вероятностей, потому что численно стабильнее складывать логарифмы, чем перемножать маленькие числа, и это упростит вычисление потерь модели: ```python from math import log @@ -230,11 +230,11 @@ total_sum = sum([freq for token, freq in token_freqs.items()]) model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} ``` -Now the main function is the one that tokenizes words using the Viterbi algorithm. As we saw before, that algorithm computes the best segmentation of each substring of the word, which we will store in a variable named `best_segmentations`. We will store one dictionary per position in the word (from 0 to its total length), with two keys: the index of the start of the last token in the best segmentation, and the score of the best segmentation. With the index of the start of the last token, we will be able to retrieve the full segmentation once the list is completely populated. +Теперь основная функция - это функция токенизации слов с помощью алгоритма Витерби. Как мы уже видели, этот алгоритм вычисляет наилучшую сегментацию каждой подстроки слова, которую мы будем хранить в переменной с именем `best_segmentations`. Мы будем хранить по одному словарю на каждую позицию в слове (от 0 до его полной длины), с двумя ключами: индекс начала последнего токена в лучшей сегментации и оценка лучшей сегментации. По индексу начала последнего токена мы сможем получить полную сегментацию, когда список будет полностью заполнен. -Populating the list is done with just two loops: the main loop goes over each start position, and the second loop tries all substrings beginning at that start position. If the substring is in the vocabulary, we have a new segmentation of the word up until that end position, which we compare to what is in `best_segmentations`. +Пополнение списка осуществляется с помощью двух циклов: основной цикл просматривает каждую начальную позицию, а второй цикл перебирает все подстроки, начинающиеся с этой начальной позиции. Если подстрока есть в словаре, мы получаем новую сегментацию слова до этой конечной позиции, которую сравниваем с той, что хранится в `best_segmentations`. -Once the main loop is finished, we just start from the end and hop from one start position to the next, recording the tokens as we go, until we reach the start of the word: +После завершения основного цикла мы просто начинаем с конца и переходим от одной начальной позиции к другой, записывая токены по мере продвижения, пока не достигнем начала слова: ```python def encode_word(word, model): @@ -242,13 +242,13 @@ def encode_word(word, model): {"start": None, "score": None} for _ in range(len(word)) ] for start_idx in range(len(word)): - # This should be properly filled by the previous steps of the loop + # Это должно быть правильно заполнено предыдущими шагами цикла best_score_at_start = best_segmentations[start_idx]["score"] for end_idx in range(start_idx + 1, len(word) + 1): token = word[start_idx:end_idx] if token in model and best_score_at_start is not None: score = model[token] + best_score_at_start - # If we have found a better segmentation ending at end_idx, we update + # Если мы нашли лучшую сегментацию, заканчивающуюся на end_idx, мы обновляем if ( best_segmentations[end_idx]["score"] is None or best_segmentations[end_idx]["score"] > score @@ -257,7 +257,7 @@ def encode_word(word, model): segmentation = best_segmentations[-1] if segmentation["score"] is None: - # We did not find a tokenization of the word -> unknown + # Мы не нашли токенизацию слова -> возвращаем unknown return [""], None score = segmentation["score"] @@ -273,7 +273,7 @@ def encode_word(word, model): return tokens, score ``` -We can already try our initial model on some words: +Мы уже можем опробовать нашу первоначальную модель на некоторых словах: ```python print(encode_word("Hopefully", model)) @@ -285,7 +285,7 @@ print(encode_word("This", model)) (['This'], 6.288267030694535) ``` -Now it's easy to compute the loss of the model on the corpus! +Теперь легко вычислить потери модели на корпусе! ```python def compute_loss(model): @@ -296,7 +296,7 @@ def compute_loss(model): return loss ``` -We can check it works on the model we have: +Мы можем проверить его работу на имеющейся у нас модели: ```python compute_loss(model) @@ -306,7 +306,7 @@ compute_loss(model) 413.10377642940875 ``` -Computing the scores for each token is not very hard either; we just have to compute the loss for the models obtained by deleting each token: +Вычисление оценок для каждого токена также не представляет особой сложности; нам просто нужно вычислить потери для модели, полученные при удалении каждого токена: ```python import copy @@ -325,7 +325,7 @@ def compute_scores(model): return scores ``` -We can try it on a given token: +Мы можем попробовать это на заданном токене: ```python scores = compute_scores(model) @@ -333,7 +333,7 @@ print(scores["ll"]) print(scores["his"]) ``` -Since `"ll"` is used in the tokenization of `"Hopefully"`, and removing it will probably make us use the token `"l"` twice instead, we expect it will have a positive loss. `"his"` is only used inside the word `"This"`, which is tokenized as itself, so we expect it to have a zero loss. Here are the results: +Поскольку `"ll"` используется в токенизации слова `"Hopefully"`, и его удаление, вероятно, заставит нас дважды использовать токен `"l"` вместо этого, мы ожидаем, что он будет иметь положительную потерю. `"his"` используется только внутри слова `"This"`, которое токенизируется само по себе, поэтому мы ожидаем, что потери будут нулевыми. Вот результаты: ```python out 6.376412403623874 @@ -342,11 +342,11 @@ Since `"ll"` is used in the tokenization of `"Hopefully"`, and removing it will -💡 This approach is very inefficient, so SentencePiece uses an approximation of the loss of the model without token X: instead of starting from scratch, it just replaces token X by its segmentation in the vocabulary that is left. This way, all the scores can be computed at once at the same time as the model loss. +💡 Такой подход очень неэффективен, поэтому SentencePiece использует приближенную оценку потерь модели без токена X: вместо того чтобы начинать с нуля, он просто заменяет токен X его сегментацией в оставшемся словаре. Таким образом, все оценки могут быть вычислены одновременно с потерями модели. -With all of this in place, the last thing we need to do is add the special tokens used by the model to the vocabulary, then loop until we have pruned enough tokens from the vocabulary to reach our desired size: +Когда этот процесс завершиться, останется только добавить в словарь специальные токены, используемые моделью, а затем итерироваться, пока мы не вычеркнем из словаря достаточно токенов, чтобы достичь желаемого размера: ```python percent_to_remove = 0.1 @@ -361,7 +361,7 @@ while len(model) > 100: model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} ``` -Then, to tokenize some text, we just need to apply the pre-tokenization and then use our `encode_word()` function: +Затем, чтобы токенизировать некоторый текст, нам просто нужно применить предварительную токенизацию, а затем использовать нашу функцию `encode_word()`: ```python def tokenize(text, model): @@ -378,4 +378,4 @@ tokenize("This is the Hugging Face course.", model) ['▁This', '▁is', '▁the', '▁Hugging', '▁Face', '▁', 'c', 'ou', 'r', 's', 'e', '.'] ``` -That's it for Unigram! Hopefully by now you're feeling like an expert in all things tokenizer. In the next section, we will delve into the building blocks of the 🤗 Tokenizers library, and show you how you can use them to build your own tokenizer. +Вот и все об Unigram! Надеемся, теперь вы чувствуете себя экспертом во всем, что касается токенизаторов. В следующем разделе мы рассмотрим блоки библиотеки 🤗 Tokenizers и покажем, как их можно использовать для создания собственного токенизатора. diff --git a/chapters/ru/chapter6/8.mdx b/chapters/ru/chapter6/8.mdx index 7caee98ed..9a7367458 100644 --- a/chapters/ru/chapter6/8.mdx +++ b/chapters/ru/chapter6/8.mdx @@ -1,4 +1,4 @@ -# Building a tokenizer, block by block[[building-a-tokenizer-block-by-block]] +# Создание токенизатора, блок за блоком[[building-a-tokenizer-block-by-block]] -As we've seen in the previous sections, tokenization comprises several steps: +Как мы уже видели в предыдущих разделах, токенизация состоит из нескольких этапов: -- Normalization (any cleanup of the text that is deemed necessary, such as removing spaces or accents, Unicode normalization, etc.) -- Pre-tokenization (splitting the input into words) -- Running the input through the model (using the pre-tokenized words to produce a sequence of tokens) -- Post-processing (adding the special tokens of the tokenizer, generating the attention mask and token type IDs) +- Нормализация (любая необходимая очистка текста, например, удаление пробелов или подчеркиваний, нормализация Unicode и т. д.) +- Предварительная токенизация (разделение входного текста на слова). +- Прогон входных данных через модель (использование предварительно токенизированных слов для создания последовательности токенов) +- Постобработка (добавление специальных токенов токенизатора, генерация маски внимания и идентификаторов типов токенов) -As a reminder, here's another look at the overall process: +В качестве напоминания вот еще один взгляд на общий процесс:
The tokenization pipeline.
-The 🤗 Tokenizers library has been built to provide several options for each of those steps, which you can mix and match together. In this section we'll see how we can build a tokenizer from scratch, as opposed to training a new tokenizer from an old one as we did in [section 2](/course/chapter6/2). You'll then be able to build any kind of tokenizer you can think of! +Библиотека 🤗 Tokenizers была создана для того, чтобы предоставить несколько вариантов каждого из этих шагов, которые вы можете смешивать и сочетать между собой. В этом разделе мы рассмотрим, как можно создать токенизатор с нуля, а не обучать новый токенизатор на основе старого, как мы делали в [разделе 2](/course/chapter6/2). После этого вы сможете создать любой токенизатор, который только сможете придумать! -More precisely, the library is built around a central `Tokenizer` class with the building blocks regrouped in submodules: +Точнее, библиотека построена вокруг центрального класса `Tokenizer`, а строительные блоки сгруппированы в подмодули: -- `normalizers` contains all the possible types of `Normalizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). -- `pre_tokenizers` contains all the possible types of `PreTokenizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). -- `models` contains the various types of `Model` you can use, like `BPE`, `WordPiece`, and `Unigram` (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). -- `trainers` contains all the different types of `Trainer` you can use to train your model on a corpus (one per type of model; complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). -- `post_processors` contains the various types of `PostProcessor` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). -- `decoders` contains the various types of `Decoder` you can use to decode the outputs of tokenization (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). +- `normalizers` содержит все возможные типы нормализаторов текста `Normalizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). +- `pre_tokenizers` содержит все возможные типы предварительных токенизаторов `PreTokenizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). +- `models` содержит различные типы моделей `Model`, которые вы можете использовать, такие как `BPE`, `WordPiece` и `Unigram` (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). +- `trainers` содержит все различные типы `Trainer`, которые вы можете использовать для обучения модели на корпусе (по одному на каждый тип модели; полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). +- `post_processors` содержит различные типы постпроцессоров `PostProcessor`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). +- `decoders` содержит различные типы декодеров `Decoder`, которые вы можете использовать для декодирования результатов токенизации (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). -You can find the whole list of building blocks [here](https://huggingface.co/docs/tokenizers/python/latest/components.html). +Весь список блоков вы можете найти [здесь](https://huggingface.co/docs/tokenizers/python/latest/components.html). -## Acquiring a corpus[[acquiring-a-corpus]] +## Получение корпуса текста[[acquiring-a-corpus]] -To train our new tokenizer, we will use a small corpus of text (so the examples run fast). The steps for acquiring the corpus are similar to the ones we took at the [beginning of this chapter](/course/chapter6/2), but this time we'll use the [WikiText-2](https://huggingface.co/datasets/wikitext) dataset: +Для обучения нашего нового токенизатора мы будем использовать небольшой корпус текстов (чтобы примеры выполнялись быстро). Шаги по сбору корпуса аналогичны тем, что мы делали в [начале этой главы](/course/chapter6/2), но на этот раз мы будем использовать набор данных [WikiText-2](https://huggingface.co/datasets/wikitext): ```python from datasets import load_dataset @@ -51,9 +51,9 @@ def get_training_corpus(): yield dataset[i : i + 1000]["text"] ``` -The function `get_training_corpus()` is a generator that will yield batches of 1,000 texts, which we will use to train the tokenizer. +Функция `get_training_corpus()` - это генератор, который выдает батч из 1000 текстов, которые мы будем использовать для обучения токенизатора. -🤗 Tokenizers can also be trained on text files directly. Here's how we can generate a text file containing all the texts/inputs from WikiText-2 that we can use locally: +🤗 Токенизаторы также можно обучать непосредственно на текстовых файлах. Вот как мы можем сгенерировать текстовый файл, содержащий все тексты/входы из WikiText-2, который мы можем использовать локально: ```python with open("wikitext-2.txt", "w", encoding="utf-8") as f: @@ -61,13 +61,13 @@ with open("wikitext-2.txt", "w", encoding="utf-8") as f: f.write(dataset[i]["text"] + "\n") ``` -Next we'll show you how to build your own BERT, GPT-2, and XLNet tokenizers, block by block. That will give us an example of each of the three main tokenization algorithms: WordPiece, BPE, and Unigram. Let's start with BERT! +Далее мы покажем вам, как блок за блоком построить собственные токенизаторы BERT, GPT-2 и XLNet. Это даст нам пример каждого из трех основных алгоритмов токенизации: WordPiece, BPE и Unigram. Начнем с BERT! -## Building a WordPiece tokenizer from scratch[[building-a-wordpiece-tokenizer-from-scratch]] +## Создание токенизатора WordPiece с нуля[[building-a-wordpiece-tokenizer-from-scratch]] -To build a tokenizer with the 🤗 Tokenizers library, we start by instantiating a `Tokenizer` object with a `model`, then set its `normalizer`, `pre_tokenizer`, `post_processor`, and `decoder` attributes to the values we want. +Чтобы создать токенизатор с помощью библиотеки 🤗 Tokenizers, мы начнем с инстанцирования объектов `Tokenizer` и `model`, затем установим для их атрибутов `normalizer`, `pre_tokenizer`, `post_processor` и `decoder` нужные нам значения. -For this example, we'll create a `Tokenizer` with a WordPiece model: +Для этого примера мы создадим `Tokenizer` с моделью WordPiece: ```python from tokenizers import ( @@ -83,15 +83,15 @@ from tokenizers import ( tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) ``` -We have to specify the `unk_token` so the model knows what to return when it encounters characters it hasn't seen before. Other arguments we can set here include the `vocab` of our model (we're going to train the model, so we don't need to set this) and `max_input_chars_per_word`, which specifies a maximum length for each word (words longer than the value passed will be split). +Мы должны указать `unk_token`, чтобы модель знала, что возвращать, когда она встречает символы, которых раньше не видела. Другие аргументы, которые мы можем задать здесь, включают `vocab` нашей модели (мы собираемся обучать модель, поэтому нам не нужно его задавать) и `max_input_chars_per_word`, который определяет максимальную длину для каждого слова (слова длиннее переданного значения будут разбиты на части). -The first step of tokenization is normalization, so let's begin with that. Since BERT is widely used, there is a `BertNormalizer` with the classic options we can set for BERT: `lowercase` and `strip_accents`, which are self-explanatory; `clean_text` to remove all control characters and replace repeating spaces with a single one; and `handle_chinese_chars`, which places spaces around Chinese characters. To replicate the `bert-base-uncased` tokenizer, we can just set this normalizer: +Первым шагом токенизации является нормализация, поэтому начнем с нее. Поскольку BERT широко используется, существует `BertNormalizer` с классическими параметрами, которые мы можем установить для BERT: `lowercase` и `strip_accents`, которые не требуют пояснений; `clean_text` для удаления всех управляющих символов и замены повторяющихся пробелов на один; и `handle_chinese_chars`, который расставляет пробелы вокруг китайских символов. Чтобы повторить токенизатор `bert-base-uncased`, мы можем просто установить этот нормализатор: ```python tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) ``` -Generally speaking, however, when building a new tokenizer you won't have access to such a handy normalizer already implemented in the 🤗 Tokenizers library -- so let's see how to create the BERT normalizer by hand. The library provides a `Lowercase` normalizer and a `StripAccents` normalizer, and you can compose several normalizers using a `Sequence`: +Однако, как правило, при создании нового токенизатора у вас не будет доступа к такому удобному нормализатору, уже реализованному в библиотеке 🤗 Tokenizers, поэтому давайте посмотрим, как создать нормализатор BERT вручную. Библиотека предоставляет нормализатор `Lowercase` и нормализатор `StripAccents`, и вы можете комбинировать несколько нормализаторов с помощью `Sequence`: ```python tokenizer.normalizer = normalizers.Sequence( @@ -99,9 +99,9 @@ tokenizer.normalizer = normalizers.Sequence( ) ``` -We're also using an `NFD` Unicode normalizer, as otherwise the `StripAccents` normalizer won't properly recognize the accented characters and thus won't strip them out. +Мы также используем нормализатор Unicode `NFD`, поскольку в противном случае нормализатор `StripAccents` не сможет правильно распознать акцентированные символы и, следовательно, не удалит их. -As we've seen before, we can use the `normalize_str()` method of the `normalizer` to check out the effects it has on a given text: +Как мы уже видели ранее, мы можем использовать метод `normalize_str()` нормализатора, чтобы проверить, как он влияет на данный текст: ```python print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) @@ -113,24 +113,24 @@ hello how are u? -**To go further** If you test the two versions of the previous normalizers on a string containing the unicode character `u"\u0085"` you will surely notice that these two normalizers are not exactly equivalent. -To not over-complicate the version with `normalizers.Sequence` too much , we haven't included the Regex replacements that the `BertNormalizer` requires when the `clean_text` argument is set to `True` - which is the default behavior. But don't worry: it is possible to get exactly the same normalization without using the handy `BertNormalizer` by adding two `normalizers.Replace`'s to the normalizers sequence. +**Далее** если вы протестируете две версии предыдущих нормализаторов на строке, содержащей символ Unicode `u"\u0085"`, то наверняка заметите, что эти два нормализатора не совсем эквивалентны. +Чтобы не усложнять версию с `normalizers.Sequence`, мы не включили в нее Regex-замены, которые требует `BertNormalizer`, когда аргумент `clean_text` установлен в `True`, что является поведением по умолчанию. Но не волнуйтесь: можно получить точно такую же нормализацию без использования удобного `BertNormalizer`, добавив два `normalizers.Replace` в последовательность нормализаторов. -Next is the pre-tokenization step. Again, there is a prebuilt `BertPreTokenizer` that we can use: +Далее следует этап предварительной токенизации. Опять же, есть готовый `BertPreTokenizer`, который мы можем использовать: ```python tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() ``` -Or we can build it from scratch: +Или мы можем создать его с нуля: ```python tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() ``` -Note that the `Whitespace` pre-tokenizer splits on whitespace and all characters that are not letters, digits, or the underscore character, so it technically splits on whitespace and punctuation: +Обратите внимание, что токенизатор `Whitespace` разделяет пробельные символы и все символы, которые не являются буквами, цифрами или символом подчеркивания, поэтому технически он разделяет пробельные символы и знаки пунктуации: ```python tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") @@ -141,7 +141,7 @@ tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] ``` -If you only want to split on whitespace, you should use the `WhitespaceSplit` pre-tokenizer instead: +Если вы хотите выполнять разделение только по пробельным символам, то вместо этого следует использовать предварительный токенизатор `WhitespaceSplit`: ```python pre_tokenizer = pre_tokenizers.WhitespaceSplit() @@ -152,7 +152,7 @@ pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") [("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] ``` -Like with normalizers, you can use a `Sequence` to compose several pre-tokenizers: +Как и в случае с нормализаторами, вы можете использовать `Sequence` для комбинирования нескольких предварительных токенизаторов: ```python pre_tokenizer = pre_tokenizers.Sequence( @@ -166,29 +166,29 @@ pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] ``` -The next step in the tokenization pipeline is running the inputs through the model. We already specified our model in the initialization, but we still need to train it, which will require a `WordPieceTrainer`. The main thing to remember when instantiating a trainer in 🤗 Tokenizers is that you need to pass it all the special tokens you intend to use -- otherwise it won't add them to the vocabulary, since they are not in the training corpus: +Следующий шаг в конвейере токенизации - обработка входных данных с помощью модели. Мы уже указали нашу модель в инициализации, но нам все еще нужно обучить ее, для чего потребуется `WordPieceTrainer`. Главное, что нужно помнить при инстанцировании тренера в 🤗 Tokenizers, это то, что вам нужно передать ему все специальные токены, которые вы собираетесь использовать - иначе он не добавит их в словарь, поскольку их нет в обучающем корпусе: ```python special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) ``` -As well as specifying the `vocab_size` and `special_tokens`, we can set the `min_frequency` (the number of times a token must appear to be included in the vocabulary) or change the `continuing_subword_prefix` (if we want to use something different from `##`). +Помимо указания `vocab_size` и `special_tokens`, мы можем задать `min_frequency` (количество раз, которое должен встретиться токен, чтобы быть включенным в словарь) или изменить `continuing_subword_prefix` (если мы хотим использовать что-то отличное от `##`). -To train our model using the iterator we defined earlier, we just have to execute this command: +Чтобы обучить нашу модель с помощью итератора, который мы определили ранее, достаточно выполнить эту команду: ```python tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) ``` -We can also use text files to train our tokenizer, which would look like this (we reinitialize the model with an empty `WordPiece` beforehand): +Мы также можем использовать текстовые файлы для обучения нашего токенизатора, что будет выглядеть следующим образом (предварительно мы повторно инициализируем модель с пустым `WordPiece`): ```python tokenizer.model = models.WordPiece(unk_token="[UNK]") tokenizer.train(["wikitext-2.txt"], trainer=trainer) ``` -In both cases, we can then test the tokenizer on a text by calling the `encode()` method: +В обоих случаях мы можем проверить работу токенизатора на тексте, вызвав метод `encode()`: ```python encoding = tokenizer.encode("Let's test this tokenizer.") @@ -199,9 +199,9 @@ print(encoding.tokens) ['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] ``` -The `encoding` obtained is an `Encoding`, which contains all the necessary outputs of the tokenizer in its various attributes: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask`, and `overflowing`. +Полученное `encoding` представляет собой `Encoding`, которое содержит все необходимые результаты работы токенизатора в разных атрибутах: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask` и `overflowing`. -The last step in the tokenization pipeline is post-processing. We need to add the `[CLS]` token at the beginning and the `[SEP]` token at the end (or after each sentence, if we have a pair of sentences). We will use a `TemplateProcessor` for this, but first we need to know the IDs of the `[CLS]` and `[SEP]` tokens in the vocabulary: +Последний шаг в конвейере токенизации - постобработка. Нам нужно добавить токен `[CLS]` в начале и токен `[SEP]` в конце (или после каждого предложения, если у нас есть пара предложений). Для этого мы будем использовать `TemplateProcessor`, но сначала нам нужно узнать идентификаторы токенов `[CLS]` и `[SEP]` в словаре: ```python cls_token_id = tokenizer.token_to_id("[CLS]") @@ -213,9 +213,9 @@ print(cls_token_id, sep_token_id) (2, 3) ``` -To write the template for the `TemplateProcessor`, we have to specify how to treat a single sentence and a pair of sentences. For both, we write the special tokens we want to use; the first (or single) sentence is represented by `$A`, while the second sentence (if encoding a pair) is represented by `$B`. For each of these (special tokens and sentences), we also specify the corresponding token type ID after a colon. +Чтобы написать шаблон для `TemplateProcessor`, мы должны указать, как обрабатывать одно предложение и пару предложений. Для обоих случаев мы указываем специальные токены, которые мы хотим использовать; первое (или одиночное) предложение представлено `$A`, а второе предложение (если кодируется пара) представлено `$B`. Для каждого из них (специальных токенов и предложений) мы также указываем соответствующий идентификатор типа токена (token type ID) после двоеточия. -The classic BERT template is thus defined as follows: +Таким образом, классический шаблон BERT определяется следующим образом: ```python tokenizer.post_processor = processors.TemplateProcessing( @@ -225,9 +225,9 @@ tokenizer.post_processor = processors.TemplateProcessing( ) ``` -Note that we need to pass along the IDs of the special tokens, so the tokenizer can properly convert them to their IDs. +Обратите внимание, что нам нужно передать идентификаторы специальных токенов, чтобы токенизатор мог правильно преобразовать их в их идентификаторы. -Once this is added, going back to our previous example will give: +Как только это будет добавлено, вернемся к нашему предыдущему примеру: ```python encoding = tokenizer.encode("Let's test this tokenizer.") @@ -238,7 +238,7 @@ print(encoding.tokens) ['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] ``` -And on a pair of sentences, we get the proper result: +И на паре предложений мы получаем правильный результат: ```python encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") @@ -251,13 +251,13 @@ print(encoding.type_ids) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] ``` -We've almost finished building this tokenizer from scratch -- the last step is to include a decoder: +Мы почти закончили создание этого токенизатора с нуля - остался последний шаг - добавить декодер: ```python tokenizer.decoder = decoders.WordPiece(prefix="##") ``` -Let's test it on our previous `encoding`: +Давайте проверим его на нашем предыдущем `encoding`: ```python tokenizer.decode(encoding.ids) @@ -267,28 +267,28 @@ tokenizer.decode(encoding.ids) "let's test this tokenizer... on a pair of sentences." ``` -Great! We can save our tokenizer in a single JSON file like this: +Отлично! Мы можем сохранить наш токенизатор в единственном JSON-файле следующим образом: ```python tokenizer.save("tokenizer.json") ``` -We can then reload that file in a `Tokenizer` object with the `from_file()` method: +Затем мы можем загрузить этот файл в объект `Tokenizer` с помощью метода `from_file()`: ```python new_tokenizer = Tokenizer.from_file("tokenizer.json") ``` -To use this tokenizer in 🤗 Transformers, we have to wrap it in a `PreTrainedTokenizerFast`. We can either use the generic class or, if our tokenizer corresponds to an existing model, use that class (here, `BertTokenizerFast`). If you apply this lesson to build a brand new tokenizer, you will have to use the first option. +Чтобы использовать этот токенизатор в 🤗 Transformers, мы должны обернуть его в `PreTrainedTokenizerFast`. Мы можем использовать либо общий класс, либо, если наш токенизатор соответствует существующей модели, использовать этот класс (здесь `BertTokenizerFast`). Если вы используете этот урок для создания нового токенизатора, вам придется использовать первый вариант. -To wrap the tokenizer in a `PreTrainedTokenizerFast`, we can either pass the tokenizer we built as a `tokenizer_object` or pass the tokenizer file we saved as `tokenizer_file`. The key thing to remember is that we have to manually set all the special tokens, since that class can't infer from the `tokenizer` object which token is the mask token, the `[CLS]` token, etc.: +Чтобы обернуть токенизатор в `PreTrainedTokenizerFast`, мы можем либо передать собранный нами токенизатор как `tokenizer_object`, либо передать сохраненный файл токенизатора как `tokenizer_file`. Главное помнить, что нам придется вручную задавать все специальные токены, поскольку класс не может определить из объекта `tokenizer`, какой токен является токеном маски, токеном `[CLS]` и т. д.: ```python from transformers import PreTrainedTokenizerFast wrapped_tokenizer = PreTrainedTokenizerFast( tokenizer_object=tokenizer, - # tokenizer_file="tokenizer.json", # You can load from the tokenizer file, alternatively + # tokenizer_file="tokenizer.json", # В качестве альтернативы можно загрузить из файла токенизатора. unk_token="[UNK]", pad_token="[PAD]", cls_token="[CLS]", @@ -297,7 +297,7 @@ wrapped_tokenizer = PreTrainedTokenizerFast( ) ``` -If you are using a specific tokenizer class (like `BertTokenizerFast`), you will only need to specify the special tokens that are different from the default ones (here, none): +Если вы используете определенный класс токенизатора (например, `BertTokenizerFast`), вам нужно будет указать только специальные токены, которые отличаются от токенов по умолчанию (здесь их нет): ```python from transformers import BertTokenizerFast @@ -305,13 +305,13 @@ from transformers import BertTokenizerFast wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) ``` -You can then use this tokenizer like any other 🤗 Transformers tokenizer. You can save it with the `save_pretrained()` method, or upload it to the Hub with the `push_to_hub()` method. +Затем вы можете использовать этот токенизатор, как и любой другой 🤗 токенизатор Transformers. Вы можете сохранить его с помощью метода `save_pretrained()` или загрузить на хаб с помощью метода `push_to_hub()`. -Now that we've seen how to build a WordPiece tokenizer, let's do the same for a BPE tokenizer. We'll go a bit faster since you know all the steps, and only highlight the differences. +Теперь, когда мы рассмотрели, как создать токенизатор WordPiece, давайте сделаем то же самое для токенизатора BPE. Мы будем двигаться немного быстрее, поскольку вы знаете все шаги, и подчеркнем только различия. -## Building a BPE tokenizer from scratch[[building-a-bpe-tokenizer-from-scratch]] +## Создание токенизатора BPE с нуля[[building-a-bpe-tokenizer-from-scratch]] -Let's now build a GPT-2 tokenizer. Like for the BERT tokenizer, we start by initializing a `Tokenizer` with a BPE model: +Теперь давайте создадим токенизатор GPT-2. Как и в случае с токенизатором BERT, мы начнем с инициализации `Tokenizer` с моделью BPE: ```python tokenizer = Tokenizer(models.BPE()) From 311371364a487299f4f6c4ff1926149dd17e8c7c Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:24:54 +0300 Subject: [PATCH 306/502] The translation of chapter 6 has been completed. --- .../.ipynb_checkpoints/8-checkpoint.mdx | 231 +++++++ .../.ipynb_checkpoints/8-checkpoint.mdx | 565 +++++++++++++++ .../.ipynb_checkpoints/9-checkpoint.mdx | 16 + .../_toctree-checkpoint.yml | 19 +- chapters/ru/_toctree.yml | 19 +- .../.ipynb_checkpoints/8-checkpoint.mdx | 230 +++++++ .../.ipynb_checkpoints/1-checkpoint.mdx | 19 - .../.ipynb_checkpoints/2-checkpoint.mdx | 257 ------- .../.ipynb_checkpoints/3-checkpoint.mdx | 475 ------------- .../.ipynb_checkpoints/3b-checkpoint.mdx | 642 ------------------ .../.ipynb_checkpoints/4-checkpoint.mdx | 123 ---- .../.ipynb_checkpoints/5-checkpoint.mdx | 360 ---------- .../.ipynb_checkpoints/6-checkpoint.mdx | 374 ---------- .../.ipynb_checkpoints/7-checkpoint.mdx | 381 ----------- .../.ipynb_checkpoints/8-checkpoint.mdx | 565 --------------- chapters/ru/chapter6/10.mdx | 209 +++--- chapters/ru/chapter6/8.mdx | 68 +- chapters/ru/chapter6/9.mdx | 16 +- 18 files changed, 1211 insertions(+), 3358 deletions(-) create mode 100644 chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx create mode 100644 chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx create mode 100644 chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx create mode 100644 chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/1-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/2-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/5-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/7-checkpoint.mdx delete mode 100644 chapters/ru/chapter6/.ipynb_checkpoints/8-checkpoint.mdx diff --git a/chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx b/chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx new file mode 100644 index 000000000..27addf6b6 --- /dev/null +++ b/chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx @@ -0,0 +1,231 @@ + + +# End-of-chapter quiz[[end-of-chapter-quiz]] + + + +This chapter covered a lot of ground! Don't worry if you didn't grasp all the details; the next chapters will help you understand how things work under the hood. + +Before moving on, though, let's test what you learned in this chapter. + +### 1. The `load_dataset()` function in 🤗 Datasets allows you to load a dataset from which of the following locations? + +data_files argument of load_dataset() to load local datasets.", + correct: true + }, + { + text: "The Hugging Face Hub", + explain: "Correct! You can load datasets on the Hub by providing the dataset ID, e.g. load_dataset('emotion').", + correct: true + }, + { + text: "A remote server", + explain: "Correct! You can pass URLs to the data_files argument of load_dataset() to load remote files.", + correct: true + }, + ]} +/> + +### 2. Suppose you load one of the GLUE tasks as follows: + +```py +from datasets import load_dataset + +dataset = load_dataset("glue", "mrpc", split="train") +``` + +Which of the following commands will produce a random sample of 50 elements from `dataset`? + +dataset.sample(50)", + explain: "This is incorrect -- there is no Dataset.sample() method." + }, + { + text: "dataset.shuffle().select(range(50))", + explain: "Correct! As you saw in this chapter, you first shuffle the dataset and then select the samples from it.", + correct: true + }, + { + text: "dataset.select(range(50)).shuffle()", + explain: "This is incorrect -- although the code will run, it will only shuffle the first 50 elements in the dataset." + } + ]} +/> + +### 3. Suppose you have a dataset about household pets called `pets_dataset`, which has a `name` column that denotes the name of each pet. Which of the following approaches would allow you to filter the dataset for all pets whose names start with the letter "L"? + +pets_dataset.filter(lambda x : x['name'].startswith('L'))", + explain: "Correct! Using a Python lambda function for these quick filters is a great idea. Can you think of another solution?", + correct: true + }, + { + text: "pets_dataset.filter(lambda x['name'].startswith('L'))", + explain: "This is incorrect -- a lambda function takes the general form lambda *arguments* : *expression*, so you need to provide arguments in this case." + }, + { + text: "Create a function like def filter_names(x): return x['name'].startswith('L') and run pets_dataset.filter(filter_names).", + explain: "Correct! Just like with Dataset.map(), you can pass explicit functions to Dataset.filter(). This is useful when you have some complex logic that isn't suitable for a short lambda function. Which of the other solutions would work?", + correct: true + } + ]} +/> + +### 4. What is memory mapping? + + + +### 5. Which of the following are the main benefits of memory mapping? + + + +### 6. Why does the following code fail? + +```py +from datasets import load_dataset + +dataset = load_dataset("allocine", streaming=True, split="train") +dataset[0] +``` + +IterableDataset.", + explain: "Correct! An IterableDataset is a generator, not a container, so you should access its elements using next(iter(dataset)).", + correct: true + }, + { + text: "The allocine dataset doesn't have a train split.", + explain: "This is incorrect -- check out the [allocine dataset card](https://huggingface.co/datasets/allocine) on the Hub to see which splits it contains." + } + ]} +/> + +### 7. Which of the following are the main benefits of creating a dataset card? + + + + +### 8. What is semantic search? + + + +### 9. For asymmetric semantic search, you usually have: + + + +### 10. Can I use 🤗 Datasets to load data for use in other domains, like speech processing? + +MNIST dataset on the Hub for a computer vision example." + }, + { + text: "Yes", + explain: "Correct! Check out the exciting developments with speech and vision in the 🤗 Transformers library to see how 🤗 Datasets is used in these domains.", + correct : true + }, + ]} +/> diff --git a/chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx b/chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx new file mode 100644 index 000000000..7caee98ed --- /dev/null +++ b/chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx @@ -0,0 +1,565 @@ +# Building a tokenizer, block by block[[building-a-tokenizer-block-by-block]] + + + +As we've seen in the previous sections, tokenization comprises several steps: + +- Normalization (any cleanup of the text that is deemed necessary, such as removing spaces or accents, Unicode normalization, etc.) +- Pre-tokenization (splitting the input into words) +- Running the input through the model (using the pre-tokenized words to produce a sequence of tokens) +- Post-processing (adding the special tokens of the tokenizer, generating the attention mask and token type IDs) + +As a reminder, here's another look at the overall process: + +
+The tokenization pipeline. + +
+ +The 🤗 Tokenizers library has been built to provide several options for each of those steps, which you can mix and match together. In this section we'll see how we can build a tokenizer from scratch, as opposed to training a new tokenizer from an old one as we did in [section 2](/course/chapter6/2). You'll then be able to build any kind of tokenizer you can think of! + + + +More precisely, the library is built around a central `Tokenizer` class with the building blocks regrouped in submodules: + +- `normalizers` contains all the possible types of `Normalizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). +- `pre_tokenizers` contains all the possible types of `PreTokenizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). +- `models` contains the various types of `Model` you can use, like `BPE`, `WordPiece`, and `Unigram` (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). +- `trainers` contains all the different types of `Trainer` you can use to train your model on a corpus (one per type of model; complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). +- `post_processors` contains the various types of `PostProcessor` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). +- `decoders` contains the various types of `Decoder` you can use to decode the outputs of tokenization (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). + +You can find the whole list of building blocks [here](https://huggingface.co/docs/tokenizers/python/latest/components.html). + +## Acquiring a corpus[[acquiring-a-corpus]] + +To train our new tokenizer, we will use a small corpus of text (so the examples run fast). The steps for acquiring the corpus are similar to the ones we took at the [beginning of this chapter](/course/chapter6/2), but this time we'll use the [WikiText-2](https://huggingface.co/datasets/wikitext) dataset: + +```python +from datasets import load_dataset + +dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train") + + +def get_training_corpus(): + for i in range(0, len(dataset), 1000): + yield dataset[i : i + 1000]["text"] +``` + +The function `get_training_corpus()` is a generator that will yield batches of 1,000 texts, which we will use to train the tokenizer. + +🤗 Tokenizers can also be trained on text files directly. Here's how we can generate a text file containing all the texts/inputs from WikiText-2 that we can use locally: + +```python +with open("wikitext-2.txt", "w", encoding="utf-8") as f: + for i in range(len(dataset)): + f.write(dataset[i]["text"] + "\n") +``` + +Next we'll show you how to build your own BERT, GPT-2, and XLNet tokenizers, block by block. That will give us an example of each of the three main tokenization algorithms: WordPiece, BPE, and Unigram. Let's start with BERT! + +## Building a WordPiece tokenizer from scratch[[building-a-wordpiece-tokenizer-from-scratch]] + +To build a tokenizer with the 🤗 Tokenizers library, we start by instantiating a `Tokenizer` object with a `model`, then set its `normalizer`, `pre_tokenizer`, `post_processor`, and `decoder` attributes to the values we want. + +For this example, we'll create a `Tokenizer` with a WordPiece model: + +```python +from tokenizers import ( + decoders, + models, + normalizers, + pre_tokenizers, + processors, + trainers, + Tokenizer, +) + +tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) +``` + +We have to specify the `unk_token` so the model knows what to return when it encounters characters it hasn't seen before. Other arguments we can set here include the `vocab` of our model (we're going to train the model, so we don't need to set this) and `max_input_chars_per_word`, which specifies a maximum length for each word (words longer than the value passed will be split). + +The first step of tokenization is normalization, so let's begin with that. Since BERT is widely used, there is a `BertNormalizer` with the classic options we can set for BERT: `lowercase` and `strip_accents`, which are self-explanatory; `clean_text` to remove all control characters and replace repeating spaces with a single one; and `handle_chinese_chars`, which places spaces around Chinese characters. To replicate the `bert-base-uncased` tokenizer, we can just set this normalizer: + +```python +tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) +``` + +Generally speaking, however, when building a new tokenizer you won't have access to such a handy normalizer already implemented in the 🤗 Tokenizers library -- so let's see how to create the BERT normalizer by hand. The library provides a `Lowercase` normalizer and a `StripAccents` normalizer, and you can compose several normalizers using a `Sequence`: + +```python +tokenizer.normalizer = normalizers.Sequence( + [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()] +) +``` + +We're also using an `NFD` Unicode normalizer, as otherwise the `StripAccents` normalizer won't properly recognize the accented characters and thus won't strip them out. + +As we've seen before, we can use the `normalize_str()` method of the `normalizer` to check out the effects it has on a given text: + +```python +print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +hello how are u? +``` + + + +**To go further** If you test the two versions of the previous normalizers on a string containing the unicode character `u"\u0085"` you will surely notice that these two normalizers are not exactly equivalent. +To not over-complicate the version with `normalizers.Sequence` too much , we haven't included the Regex replacements that the `BertNormalizer` requires when the `clean_text` argument is set to `True` - which is the default behavior. But don't worry: it is possible to get exactly the same normalization without using the handy `BertNormalizer` by adding two `normalizers.Replace`'s to the normalizers sequence. + + + +Next is the pre-tokenization step. Again, there is a prebuilt `BertPreTokenizer` that we can use: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() +``` + +Or we can build it from scratch: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() +``` + +Note that the `Whitespace` pre-tokenizer splits on whitespace and all characters that are not letters, digits, or the underscore character, so it technically splits on whitespace and punctuation: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +If you only want to split on whitespace, you should use the `WhitespaceSplit` pre-tokenizer instead: + +```python +pre_tokenizer = pre_tokenizers.WhitespaceSplit() +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] +``` + +Like with normalizers, you can use a `Sequence` to compose several pre-tokenizers: + +```python +pre_tokenizer = pre_tokenizers.Sequence( + [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()] +) +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +The next step in the tokenization pipeline is running the inputs through the model. We already specified our model in the initialization, but we still need to train it, which will require a `WordPieceTrainer`. The main thing to remember when instantiating a trainer in 🤗 Tokenizers is that you need to pass it all the special tokens you intend to use -- otherwise it won't add them to the vocabulary, since they are not in the training corpus: + +```python +special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] +trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) +``` + +As well as specifying the `vocab_size` and `special_tokens`, we can set the `min_frequency` (the number of times a token must appear to be included in the vocabulary) or change the `continuing_subword_prefix` (if we want to use something different from `##`). + +To train our model using the iterator we defined earlier, we just have to execute this command: + +```python +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +We can also use text files to train our tokenizer, which would look like this (we reinitialize the model with an empty `WordPiece` beforehand): + +```python +tokenizer.model = models.WordPiece(unk_token="[UNK]") +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +In both cases, we can then test the tokenizer on a text by calling the `encode()` method: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] +``` + +The `encoding` obtained is an `Encoding`, which contains all the necessary outputs of the tokenizer in its various attributes: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask`, and `overflowing`. + +The last step in the tokenization pipeline is post-processing. We need to add the `[CLS]` token at the beginning and the `[SEP]` token at the end (or after each sentence, if we have a pair of sentences). We will use a `TemplateProcessor` for this, but first we need to know the IDs of the `[CLS]` and `[SEP]` tokens in the vocabulary: + +```python +cls_token_id = tokenizer.token_to_id("[CLS]") +sep_token_id = tokenizer.token_to_id("[SEP]") +print(cls_token_id, sep_token_id) +``` + +```python out +(2, 3) +``` + +To write the template for the `TemplateProcessor`, we have to specify how to treat a single sentence and a pair of sentences. For both, we write the special tokens we want to use; the first (or single) sentence is represented by `$A`, while the second sentence (if encoding a pair) is represented by `$B`. For each of these (special tokens and sentences), we also specify the corresponding token type ID after a colon. + +The classic BERT template is thus defined as follows: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single=f"[CLS]:0 $A:0 [SEP]:0", + pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1", + special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)], +) +``` + +Note that we need to pass along the IDs of the special tokens, so the tokenizer can properly convert them to their IDs. + +Once this is added, going back to our previous example will give: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] +``` + +And on a pair of sentences, we get the proper result: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") +print(encoding.tokens) +print(encoding.type_ids) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]'] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] +``` + +We've almost finished building this tokenizer from scratch -- the last step is to include a decoder: + +```python +tokenizer.decoder = decoders.WordPiece(prefix="##") +``` + +Let's test it on our previous `encoding`: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"let's test this tokenizer... on a pair of sentences." +``` + +Great! We can save our tokenizer in a single JSON file like this: + +```python +tokenizer.save("tokenizer.json") +``` + +We can then reload that file in a `Tokenizer` object with the `from_file()` method: + +```python +new_tokenizer = Tokenizer.from_file("tokenizer.json") +``` + +To use this tokenizer in 🤗 Transformers, we have to wrap it in a `PreTrainedTokenizerFast`. We can either use the generic class or, if our tokenizer corresponds to an existing model, use that class (here, `BertTokenizerFast`). If you apply this lesson to build a brand new tokenizer, you will have to use the first option. + +To wrap the tokenizer in a `PreTrainedTokenizerFast`, we can either pass the tokenizer we built as a `tokenizer_object` or pass the tokenizer file we saved as `tokenizer_file`. The key thing to remember is that we have to manually set all the special tokens, since that class can't infer from the `tokenizer` object which token is the mask token, the `[CLS]` token, etc.: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + # tokenizer_file="tokenizer.json", # You can load from the tokenizer file, alternatively + unk_token="[UNK]", + pad_token="[PAD]", + cls_token="[CLS]", + sep_token="[SEP]", + mask_token="[MASK]", +) +``` + +If you are using a specific tokenizer class (like `BertTokenizerFast`), you will only need to specify the special tokens that are different from the default ones (here, none): + +```python +from transformers import BertTokenizerFast + +wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) +``` + +You can then use this tokenizer like any other 🤗 Transformers tokenizer. You can save it with the `save_pretrained()` method, or upload it to the Hub with the `push_to_hub()` method. + +Now that we've seen how to build a WordPiece tokenizer, let's do the same for a BPE tokenizer. We'll go a bit faster since you know all the steps, and only highlight the differences. + +## Building a BPE tokenizer from scratch[[building-a-bpe-tokenizer-from-scratch]] + +Let's now build a GPT-2 tokenizer. Like for the BERT tokenizer, we start by initializing a `Tokenizer` with a BPE model: + +```python +tokenizer = Tokenizer(models.BPE()) +``` + +Also like for BERT, we could initialize this model with a vocabulary if we had one (we would need to pass the `vocab` and `merges` in this case), but since we will train from scratch, we don't need to do that. We also don't need to specify an `unk_token` because GPT-2 uses byte-level BPE, which doesn't require it. + +GPT-2 does not use a normalizer, so we skip that step and go directly to the pre-tokenization: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) +``` + +The option we added to `ByteLevel` here is to not add a space at the beginning of a sentence (which is the default otherwise). We can have a look at the pre-tokenization of an example text like before: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") +``` + +```python out +[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)), + ('tokenization', (15, 27)), ('!', (27, 28))] +``` + +Next is the model, which needs training. For GPT-2, the only special token is the end-of-text token: + +```python +trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +Like with the `WordPieceTrainer`, as well as the `vocab_size` and `special_tokens`, we can specify the `min_frequency` if we want to, or if we have an end-of-word suffix (like ``), we can set it with `end_of_word_suffix`. + +This tokenizer can also be trained on text files: + +```python +tokenizer.model = models.BPE() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +Let's have a look at the tokenization of a sample text: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] +``` + +We apply the byte-level post-processing for the GPT-2 tokenizer as follows: + +```python +tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) +``` + +The `trim_offsets = False` option indicates to the post-processor that we should leave the offsets of tokens that begin with 'Ġ' as they are: this way the start of the offsets will point to the space before the word, not the first character of the word (since the space is technically part of the token). Let's have a look at the result with the text we just encoded, where `'Ġtest'` is the token at index 4: + +```python +sentence = "Let's test this tokenizer." +encoding = tokenizer.encode(sentence) +start, end = encoding.offsets[4] +sentence[start:end] +``` + +```python out +' test' +``` + +Finally, we add a byte-level decoder: + +```python +tokenizer.decoder = decoders.ByteLevel() +``` + +and we can double-check it works properly: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"Let's test this tokenizer." +``` + +Great! Now that we're done, we can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `GPT2TokenizerFast` if we want to use it in 🤗 Transformers: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="<|endoftext|>", + eos_token="<|endoftext|>", +) +``` + +or: + +```python +from transformers import GPT2TokenizerFast + +wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) +``` + +As the last example, we'll show you how to build a Unigram tokenizer from scratch. + +## Building a Unigram tokenizer from scratch[[building-a-unigram-tokenizer-from-scratch]] + +Let's now build an XLNet tokenizer. Like for the previous tokenizers, we start by initializing a `Tokenizer` with a Unigram model: + +```python +tokenizer = Tokenizer(models.Unigram()) +``` + +Again, we could initialize this model with a vocabulary if we had one. + +For the normalization, XLNet uses a few replacements (which come from SentencePiece): + +```python +from tokenizers import Regex + +tokenizer.normalizer = normalizers.Sequence( + [ + normalizers.Replace("``", '"'), + normalizers.Replace("''", '"'), + normalizers.NFKD(), + normalizers.StripAccents(), + normalizers.Replace(Regex(" {2,}"), " "), + ] +) +``` + +This replaces `` and '' with " and any sequence of two or more spaces with a single space, as well as removing the accents in the texts to tokenize. + +The pre-tokenizer to use for any SentencePiece tokenizer is `Metaspace`: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() +``` + +We can have a look at the pre-tokenization of an example text like before: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") +``` + +```python out +[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] +``` + +Next is the model, which needs training. XLNet has quite a few special tokens: + +```python +special_tokens = ["", "", "", "", "", "", ""] +trainer = trainers.UnigramTrainer( + vocab_size=25000, special_tokens=special_tokens, unk_token="" +) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +A very important argument not to forget for the `UnigramTrainer` is the `unk_token`. We can also pass along other arguments specific to the Unigram algorithm, such as the `shrinking_factor` for each step where we remove tokens (defaults to 0.75) or the `max_piece_length` to specify the maximum length of a given token (defaults to 16). + +This tokenizer can also be trained on text files: + +```python +tokenizer.model = models.Unigram() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +Let's have a look at the tokenization of a sample text: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] +``` + +A peculiarity of XLNet is that it puts the `` token at the end of the sentence, with a type ID of 2 (to distinguish it from the other tokens). It's padding on the left, as a result. We can deal with all the special tokens and token type IDs with a template, like for BERT, but first we have to get the IDs of the `` and `` tokens: + +```python +cls_token_id = tokenizer.token_to_id("") +sep_token_id = tokenizer.token_to_id("") +print(cls_token_id, sep_token_id) +``` + +```python out +0 1 +``` + +The template looks like this: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single="$A:0 :0 :2", + pair="$A:0 :0 $B:1 :1 :2", + special_tokens=[("", sep_token_id), ("", cls_token_id)], +) +``` + +And we can test it works by encoding a pair of sentences: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") +print(encoding.tokens) +print(encoding.type_ids) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '', '▁', 'on', '▁', 'a', '▁pair', + '▁of', '▁sentence', 's', '!', '', ''] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] +``` + +Finally, we add a `Metaspace` decoder: + +```python +tokenizer.decoder = decoders.Metaspace() +``` + +and we're done with this tokenizer! We can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `XLNetTokenizerFast` if we want to use it in 🤗 Transformers. One thing to note when using `PreTrainedTokenizerFast` is that on top of the special tokens, we need to tell the 🤗 Transformers library to pad on the left: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="", + eos_token="", + unk_token="", + pad_token="", + cls_token="", + sep_token="", + mask_token="", + padding_side="left", +) +``` + +Or alternatively: + +```python +from transformers import XLNetTokenizerFast + +wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) +``` + +Now that you have seen how the various building blocks are used to build existing tokenizers, you should be able to write any tokenizer you want with the 🤗 Tokenizers library and be able to use it in 🤗 Transformers. diff --git a/chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx b/chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx new file mode 100644 index 000000000..288c4864b --- /dev/null +++ b/chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx @@ -0,0 +1,16 @@ +# Tokenizers, check![[tokenizers-check]] + + + +Great job finishing this chapter! + +After this deep dive into tokenizers, you should: + +- Be able to train a new tokenizer using an old one as a template +- Understand how to use offsets to map tokens' positions to their original span of text +- Know the differences between BPE, WordPiece, and Unigram +- Be able to mix and match the blocks provided by the 🤗 Tokenizers library to build your own tokenizer +- Be able to use that tokenizer inside the 🤗 Transformers library diff --git a/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml index 7b1b88ea3..597730c46 100644 --- a/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml +++ b/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml @@ -96,19 +96,24 @@ - local: chapter6/3 title: Особые возможности быстрых токенизаторов - local: chapter6/3b - title: Fast tokenizers in the QA pipeline + title: Быстрые токенизаторы в QA конвейере - local: chapter6/4 title: Нормализация и предварительная токенизация - local: chapter6/5 - title: Byte-Pair Encoding tokenization + title: Токенизация Byte-Pair Encoding - local: chapter6/6 - title: WordPiece tokenization + title: Токенизация WordPiece - local: chapter6/7 - title: Unigram tokenization + title: Токенизация Unigram - local: chapter6/8 - title: Building a tokenizer, block by block + title: Создание токенизатора, блок за блоком - local: chapter6/9 - title: Tokenizers, check! + title: Токенизаторы, проверка! - local: chapter6/10 - title: End-of-chapter quiz + title: Тест в конце главы quiz: 6 + +- title: Глоссарий + sections: + - local: glossary/1 + title: Глоссарий diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index 7b1b88ea3..597730c46 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -96,19 +96,24 @@ - local: chapter6/3 title: Особые возможности быстрых токенизаторов - local: chapter6/3b - title: Fast tokenizers in the QA pipeline + title: Быстрые токенизаторы в QA конвейере - local: chapter6/4 title: Нормализация и предварительная токенизация - local: chapter6/5 - title: Byte-Pair Encoding tokenization + title: Токенизация Byte-Pair Encoding - local: chapter6/6 - title: WordPiece tokenization + title: Токенизация WordPiece - local: chapter6/7 - title: Unigram tokenization + title: Токенизация Unigram - local: chapter6/8 - title: Building a tokenizer, block by block + title: Создание токенизатора, блок за блоком - local: chapter6/9 - title: Tokenizers, check! + title: Токенизаторы, проверка! - local: chapter6/10 - title: End-of-chapter quiz + title: Тест в конце главы quiz: 6 + +- title: Глоссарий + sections: + - local: glossary/1 + title: Глоссарий diff --git a/chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx b/chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx new file mode 100644 index 000000000..717a1b959 --- /dev/null +++ b/chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx @@ -0,0 +1,230 @@ + + +# Тест по главе 5 + + + +Эта глава охватила много вопросов! Не волнуйтесь, если вы не поняли всех деталей; следующие главы помогут вам понять, как все работает внутри. + +Однако, прежде чем двигаться дальше, давайте проверим то, что вы узнали в этой главе. +### Из каких источников функция `load_dataset()` в 🤗 Datasets позволяет загружать наборы данных? + +data_files функции load_dataset() для загрузки локальных наборов данных.", + correct: true + }, + { + text: "Hugging Face Hub", + explain: "Правильно! Вы можете загружать наборы данных в Hub, указав идентификатор набора данных, например. load_dataset('emotion').", + correct: true + }, + { + text: "Удаленный сервер", + explain: "Правильно! Вы можете передать URLs в аргумент data_files фунции load_dataset(). ", + correct: true + }, + ]} +/> + +### 2. Предположим, вы загружаете одну из задач GLUE следующим образом: + +```py +from datasets import load_dataset + +dataset = load_dataset("glue", "mrpc", split="train") +``` + +Какая из следующих команд создаст случайную выборку из 50 элементов из `dataset`? + +dataset.sample(50)", + explain: "Это неверно — нет метода Dataset.sample()." + }, + { + text: "dataset.shuffle().select(range(50))", + explain: "Правильный! Как вы видели в этой главе, вы сначала перемешиваете набор данных, а затем выбираете из него подмножества.", + correct: true + }, + { + text: "dataset.select(range(50)).shuffle()", + explain: "Это неверно — хотя код запустится, он перемешает только первые 50 элементов в наборе данных." + } + ]} +/> + +### 3. Предположим, у вас есть набор данных о домашних питомцах под названием `pets_dataset`, в котором есть столбец `name`, обозначающий имя каждого питомца. Какой из следующих подходов позволит вам отфильтровать набор данных для всех домашних животных, имена которых начинаются с буквы «L»? + +pets_dataset.filter(lambda x : x['name'].startswith('L'))", + explain: "Правильно! Использование лямбда-функции Python для этих быстрых фильтров — отличная идея. Можете ли вы придумать другое решение?", + correct: true + }, + { + text: "pets_dataset.filter(lambda x['name'].startswith('L'))", + explain: "Это неверно — лямбда-функция принимает общую форму lambda *arguments* : *expression*, поэтому в этом случае вам необходимо предоставить аргументы." + }, + { + text: "Create a function like def filter_names(x): return x['name'].startswith('L') and run pets_dataset.filter(filter_names).", + explain: "Правильно! Как и в случае с Dataset.map(), вы можете передавать явные функции в Dataset.filter(). Это полезно, когда у вас есть сложная логика, которая не подходит для короткой лямбда-функции. Какое из других решений будет работать?", + correct: true + } + ]} +/> + +### 4. Что такое отображение в память? + + + +### 5. Что из перечисленного ниже является основным преимуществом отображения памяти? + + + +### 6. Почему следующий код не работает? + +```py +from datasets import load_dataset + +dataset = load_dataset("allocine", streaming=True, split="train") +dataset[0] +``` + +IterableDataset.", + explain: "Правильно! IterableDataset — это генератор, а не контейнер, поэтому вы должны получить доступ к его элементам, используя next(iter(dataset)).", + correct: true + }, + { + text: "Набор данных allocine не имеет разделения train.", + explain: "Это неверно — проверьте [allocine карточку набора данных](https://huggingface.co/datasets/allocine) в Hub, чтобы увидеть, какие разбиения он содержит." + } + ]} +/> + +### 7. Что из перечисленного является основными преимуществами создания карточки датасета? + + + + +### 8. Что такое семантический поиск? + + + +### 9. Для асимметричного семантического поиска можно использовать: + + + +### 10. Могу ли я использовать 🤗 Datasets для загрузки данных и решения задач в других областях, например для обработки речи? + +набором данных MNIST в Hub для примера компьютерного зрения." + }, + { + text: "Да", + explain: "Правильно! Ознакомьтесь с захватывающими разработками в области речи и зрения в библиотеке 🤗 Transformers, чтобы узнать, как 🤗 Datasets используются в этих областях.", + correct : true + }, + ]} +/> diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/1-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/1-checkpoint.mdx deleted file mode 100644 index 93525db9d..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/1-checkpoint.mdx +++ /dev/null @@ -1,19 +0,0 @@ -# Введение[[introduction]] - - - -В [Главе 3](/course/chapter3) мы рассмотрели, как дообучить модель для конкретной задачи. При этом мы используем тот же токенизатор, на котором была предварительно обучена модель, но что делать, когда мы хотим обучить модель с нуля? В таких случаях использование токенизатора, который был предварительно обучен на корпусе из другой области или языка, как правило, является неоптимальным. Например, токенизатор, обученный на корпусе английских текстов, будет плохо работать на корпусе японских текстов, поскольку использование пробелов и знаков препинания в этих двух языках сильно отличается. - -В этой главе вы узнаете, как обучить совершенно новый токенизатор на корпусе текстов, чтобы затем использовать его для предварительного обучения языковой модели. Все это будет сделано с помощью библиотеки [🤗 Tokenizers](https://github.com/huggingface/tokenizers), которая предоставляет "быстрые" токенизаторы в библиотеке [🤗 Transformers](https://github.com/huggingface/transformers). Мы подробно рассмотрим возможности, которые предоставляет эта библиотека, и выясним, чем быстрые токенизаторы отличаются от "медленных" версий. - -Мы рассмотрим следующие темы: - -* Как обучить новый токенизатор, аналогичный тому, который используется в данной контрольной точке, на новом корпусе текстов -* Особенности быстрых токенизаторов -* Различия между тремя основными алгоритмами токенизации по подсловам, используемыми в NLP сегодня -* Как создать токенизатор с нуля с помощью библиотеки 🤗 Tokenizers и обучить его на некоторых данных - -Техники, представленные в этой главе, подготовят вас к разделу в [Главе 7](/course/chapter7/6), где мы рассмотрим создание языковой модели по исходному коду Python. Для начала давайте разберемся, что значит "обучить" токенизатор. \ No newline at end of file diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/2-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/2-checkpoint.mdx deleted file mode 100644 index 4dfd465bb..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/2-checkpoint.mdx +++ /dev/null @@ -1,257 +0,0 @@ -# Обучение нового токенизатора на основе старого[[training-a-new-tokenizer-from-an-old-one]] - - - -Если языковая модель не доступна на интересующем вас языке или ваш корпус сильно отличается от того, на котором обучалась языковая модель, вам, скорее всего, придется заново обучать модель с нуля, используя токенизатор, адаптированный к вашим данным. Для этого потребуется обучить новый токенизатор на вашем наборе данных. Но что именно это значит? Когда мы впервые рассматривали токенизаторы в [Главе 2](/course/chapter2), мы увидели, что большинство моделей трансформеров используют _алгоритм токенизации по подсловам_. Чтобы определить, какие подслова представляют интерес и наиболее часто встречаются в корпусе, токенизатор должен внимательно изучить все тексты в корпусе - этот процесс мы называем *обучением*. Точные правила обучения зависят от типа используемого токенизатора, далее в этой главе мы рассмотрим три основных алгоритма. - - - - - -⚠️ Обучение токенизатора - это не то же самое, что обучение модели! При обучении модели используется стохастический градиентный спуск, чтобы сделать потери немного меньше для каждого батча. Оно рандомизировано по своей природе (это означает, что вам нужно задать некоторое число seed, чтобы получить одинаковые результаты при повторном обучении). Обучение токенизатора - это статистический процесс, который пытается определить, какие подслова лучше всего выбрать для данного корпуса, а точные правила, используемые для их выбора, зависят от алгоритма токенизации. Это детерминированный процесс, то есть вы всегда получите одинаковые результаты при обучении одного и того же алгоритма на одном и том же корпусе. - - - -## Сбор корпуса слов[[assembling-a-corpus]] - -В 🤗 Transformers есть очень простой API, который можно использовать для обучения нового токенизатора с теми же характеристиками, что и у существующего: `AutoTokenizer.train_new_from_iterator()`. Чтобы увидеть это в действии, предположим, что мы хотим обучить GPT-2 с нуля, но на языке, отличном от английского. Нашей первой задачей будет собрать много данных на этом языке в обучающий корпус. Чтобы примеры были понятны всем, мы будем использовать не русский или китайский язык, а будем использовать специализированный английский: Python-код. - -Библиотека [🤗 Datasets](https://github.com/huggingface/datasets) может помочь нам собрать корпус исходного кода Python. Мы воспользуемся обычной функцией `load_dataset()` для загрузки и кэширования набора данных [CodeSearchNet](https://huggingface.co/datasets/code_search_net). Этот набор данных был создан для конкурса [CodeSearchNet challenge](https://wandb.ai/github/CodeSearchNet/benchmark) и содержит миллионы функций из библиотек с открытым исходным кодом с GitHub на нескольких языках программирования. Здесь мы загрузим Python-часть этого набора данных: - -```py -from datasets import load_dataset - -# Загрузка может занять несколько минут, так что выпейте кофе или чай, пока ждете! -raw_datasets = load_dataset("code_search_net", "python") -``` - -Мы можем взглянуть на тренировочную часть датасета, чтобы узнать, к каким столбцам у нас есть доступ: - -```py -raw_datasets["train"] -``` - -```python out -Dataset({ - features: ['repository_name', 'func_path_in_repository', 'func_name', 'whole_func_string', 'language', - 'func_code_string', 'func_code_tokens', 'func_documentation_string', 'func_documentation_tokens', 'split_name', - 'func_code_url' - ], - num_rows: 412178 -}) -``` - -Мы видим, что набор данных отделяет документацию от кода и предлагает токенизировать и то, и другое. Здесь мы просто используем колонку `whole_func_string` для обучения нашего токенизатора. Мы можем посмотреть пример одной из этих функций, обратившись к соответствующему индексу в части `train`: - -```py -print(raw_datasets["train"][123456]["whole_func_string"]) -``` - -который должен вывести следующее: - -```out -def handle_simple_responses( - self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): - """Accepts normal responses from the device. - - Args: - timeout_ms: Timeout in milliseconds to wait for each response. - info_cb: Optional callback for text sent from the bootloader. - - Returns: - OKAY packet's message. - """ - return self._accept_responses('OKAY', info_cb, timeout_ms=timeout_ms) -``` - -Первое, что нам нужно сделать, это преобразовать набор данных в _итератор_ списков текстов -- например, список списков текстов. Использование списков текстов позволит нашему токенизатору работать быстрее (обучение на батчах текстов вместо обработки отдельных текстов по одному), и это должен быть итератор, если мы хотим избежать необходимости держать в памяти все сразу. Если ваш корпус огромен, вы захотите воспользоваться тем, что 🤗 Datasets не загружает все в RAM, а хранит элементы набора данных на диске. - -Следующее действие создаст список списков по 1 000 текстов в каждом, но загрузит все в память: - -```py -# Не раскоментируйте следующую строку кода, если только ваш набор данных не маленький! -# training_corpus = [raw_datasets["train"][i: i + 1000]["whole_func_string"] for i in range(0, len(raw_datasets["train"]), 1000)] -``` - -Используя генератор Python, мы можем не загружать ничего в память Python до тех пор, пока это действительно не понадобится. Чтобы создать такой генератор, нужно просто заменить скобки на круглые скобки: - -```py -training_corpus = ( - raw_datasets["train"][i : i + 1000]["whole_func_string"] - for i in range(0, len(raw_datasets["train"]), 1000) -) -``` - -Эта строка кода не получает никаких элементов из набора данных; она просто создает объект, который можно использовать в цикле Python `for`. Тексты будут загружаться только тогда, когда они вам нужны (то есть когда вы находитесь на том шаге цикла `for`, где они требуются), и за один раз будет загружено только 1 000 текстов. Таким образом, вы не исчерпаете всю память, даже если обрабатываете огромный набор данных. - -Проблема с объектом-генератором заключается в том, что он может быть использован только один раз. Поэтому вместо того, чтобы выдать нам список первых 10 цифр дважды: - -```py -gen = (i for i in range(10)) -print(list(gen)) -print(list(gen)) -``` - -мы получаем его один раз, а затем пустой список: - -```python out -[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] -[] -``` - -Поэтому мы определяем функцию, которая возвращает генератор: - -```py -def get_training_corpus(): - return ( - raw_datasets["train"][i : i + 1000]["whole_func_string"] - for i in range(0, len(raw_datasets["train"]), 1000) - ) - - -training_corpus = get_training_corpus() -``` - -Вы также можете определить свой генератор внутри цикла `for`, используя оператор `yield`: - -```py -def get_training_corpus(): - dataset = raw_datasets["train"] - for start_idx in range(0, len(dataset), 1000): - samples = dataset[start_idx : start_idx + 1000] - yield samples["whole_func_string"] -``` - -который выдает точно такой же генератор, как и предыдущий, но позволяет использовать более сложную логику, чем при работе с list comprehension. - -## Обучение нового токенизатора[[training-a-new-tokenizer]] - -Теперь, когда у нас есть корпус в виде итератора батчей текстов, мы готовы обучить новый токенизатор. Для этого нам сначала нужно загрузить токенизатор, который мы хотим использовать в паре с нашей моделью (здесь GPT-2): - -```py -from transformers import AutoTokenizer - -old_tokenizer = AutoTokenizer.from_pretrained("gpt2") -``` - -Несмотря на то, что мы собираемся обучить новый токенизатор, это хорошая идея сделать это, не начиная все с нуля. Таким образом, нам не придется ничего уточнять об алгоритме токенизации или специальных токенах, которые мы хотим использовать; наш новый токенизатор будет точно таким же, как GPT-2, и единственное, что изменится, - это словарный запас, который будет определен в результате обучения на нашем корпусе. - -Сначала давайте посмотрим, как будет работать этот токенизатор с примером функции: - -```py -example = '''def add_numbers(a, b): - """Add the two numbers `a` and `b`.""" - return a + b''' - -tokens = old_tokenizer.tokenize(example) -tokens -``` - -```python out -['def', 'Ġadd', '_', 'n', 'umbers', '(', 'a', ',', 'Ġb', '):', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', - 'Ġnumbers', 'Ġ`', 'a', '`', 'Ġand', 'Ġ`', 'b', '`', '."', '""', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] -``` - -Этот токенизатор имеет несколько специальных символов, таких как `Ġ` и `Ċ`, которые обозначают пробелы и новые строки, соответственно. Как мы видим, это не слишком эффективно: токенизатор возвращает отдельные токены для каждого пробела, в то время как он мог бы группировать уровни отступов (поскольку наборы из четырех или восьми пробелов будут очень часто встречаться в коде). Он также немного странно разделил имя функции, не ожидая увидеть слова с символом `_`. - -Давайте обучим новый токенизатор и посмотрим, решит ли он эти проблемы. Для этого мы воспользуемся методом `train_new_from_iterator()`: - -```py -tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) -``` - -Выполнение этой команды может занять много времени, если ваш корпус очень большой, но для данного набора данных с 1,6 ГБ текстов она работает молниеносно (1 минута 16 секунд на процессоре AMD Ryzen 9 3900X с 12 ядрами). - -Обратите внимание, что `AutoTokenizer.train_new_from_iterator()` работает только в том случае, если используемый вами токенизатор является "быстрым" токенизатором. Как вы увидите в следующем разделе, библиотека 🤗 Transformers содержит два типа токенизаторов: одни написаны исключительно на Python, а другие (быстрые) опираются на библиотеку 🤗 Tokenizers, которая написана на языке программирования [Rust](https://www.rust-lang.org). Python - это язык, который чаще всего используется для приложений data science и deep learning, но когда что-то нужно распараллелить для быстроты, это приходится писать на другом языке. Например, матричные умножения, которые лежат в основе вычислений модели, написаны на CUDA, оптимизированной библиотеке языка C для GPU. - -Обучение совершенно нового токенизатора на чистом Python было бы мучительно медленным, поэтому мы разработали библиотеку 🤗 Tokenizers. Обратите внимание, что так же как вам не нужно было изучать язык CUDA, чтобы выполнить свою модель на батче входных данных на GPU, вам не понадобится изучать Rust, чтобы использовать быстрый токенизатор. Библиотека 🤗 Tokenizers предоставляет привязки к Python для многих методов, которые внутренне вызывают некоторые части кода на Rust; например, для распараллеливания обучения вашего нового токенизатора или, как мы видели в [Главе 3](/course/chapter3), токенизации батча входных данных. - -В большинстве моделей Transformer доступен быстрый токенизатор (есть некоторые исключения, о которых вы можете узнать [здесь](https://huggingface.co/transformers/#supported-frameworks)), а API `AutoTokenizer` всегда выбирает быстрый токенизатор, если он доступен. В следующем разделе мы рассмотрим некоторые другие особенности быстрых токенизаторов, которые будут очень полезны для таких задач, как классификация токенов и ответы на вопросы. Однако прежде чем погрузиться в эту тему, давайте попробуем наш новый токенизатор на предыдущем примере: - -```py -tokens = tokenizer.tokenize(example) -tokens -``` - -```python out -['def', 'Ġadd', '_', 'numbers', '(', 'a', ',', 'Ġb', '):', 'ĊĠĠĠ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', 'Ġnumbers', 'Ġ`', - 'a', '`', 'Ġand', 'Ġ`', 'b', '`."""', 'ĊĠĠĠ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] -``` - -Здесь мы снова видим специальные символы `Ġ` и `Ċ`, обозначающие пробелы и новые строки, но мы также видим, что наш токенизатор выучил некоторые токены, которые очень специфичны для корпуса функций Python: например, есть токен `ĊĠĠĠ`, который обозначает отступ, и токен `Ġ"""`, который обозначает три кавычки, с которых начинается doc-строка. Токенизатор также правильно разделил имя функции на `_`. Это довольно компактное представление; для сравнения, использование токенизатора простого английского языка для того же примера даст нам более длинное предложение: - -```py -print(len(tokens)) -print(len(old_tokenizer.tokenize(example))) -``` - -```python out -27 -36 -``` - -Давайте рассмотрим другой пример: - -```python -example = """class LinearLayer(): - def __init__(self, input_size, output_size): - self.weight = torch.randn(input_size, output_size) - self.bias = torch.zeros(output_size) - - def __call__(self, x): - return x @ self.weights + self.bias - """ -tokenizer.tokenize(example) -``` - -```python out -['class', 'ĠLinear', 'Layer', '():', 'ĊĠĠĠ', 'Ġdef', 'Ġ__', 'init', '__(', 'self', ',', 'Ġinput', '_', 'size', ',', - 'Ġoutput', '_', 'size', '):', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'weight', 'Ġ=', 'Ġtorch', '.', 'randn', '(', 'input', '_', - 'size', ',', 'Ġoutput', '_', 'size', ')', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'bias', 'Ġ=', 'Ġtorch', '.', 'zeros', '(', - 'output', '_', 'size', ')', 'ĊĊĠĠĠ', 'Ġdef', 'Ġ__', 'call', '__(', 'self', ',', 'Ġx', '):', 'ĊĠĠĠĠĠĠĠ', - 'Ġreturn', 'Ġx', 'Ġ@', 'Ġself', '.', 'weights', 'Ġ+', 'Ġself', '.', 'bias', 'ĊĠĠĠĠ'] -``` - -В дополнение к токену, соответствующему отступу, здесь мы также видим токен для двойного отступа: `ĊĠĠĠĠĠĠĠĠĠ`. Специальные слова Python, такие как `class`, `init`, `call`, `self` и `return`, обрабатываются как один токен, и мы видим, что наряду с разделением на `_` и `.` токенизатор правильно разделяет даже имена с camel-case: `LinearLayer` обрабатывается как `["ĠLinear", "Layer"]`. - -## Сохранение токенизатора[[saving-the-tokenizer]] - -Чтобы убедиться, что мы сможем использовать его позже, нам нужно сохранить наш новый токенизатор. Как и для моделей, это делается с помощью метода `save_pretrained()`: - -```py -tokenizer.save_pretrained("code-search-net-tokenizer") -``` - -В результате будет создана новая папка с именем *code-search-net-tokenizer*, в которой будут содержаться все файлы, необходимые токенизатору для загрузки. Если вы хотите поделиться этим токенизатором со своими коллегами и друзьями, вы можете загрузить его на Hub, войдя в свою учетную запись. Если вы работаете в блокноте, есть удобная функция, которая поможет вам в этом: - -```python -from huggingface_hub import notebook_login - -notebook_login() -``` - -Появится виджет, в котором вы можете ввести свои учетные данные для входа в Hugging Face. Если вы работаете не в блокноте, просто введите следующую строку в терминале: - -```bash -huggingface-cli login -``` - -После того как вы авторизовались, вы можете опубликовать свой токенизатор, выполнив следующую команду: - -```py -tokenizer.push_to_hub("code-search-net-tokenizer") -``` - -Это создаст новое хранилище в вашем пространстве имен с именем `code-search-net-tokenizer`, содержащее файл токенизатора. Затем вы можете загрузить токенизатор где угодно с помощью метода `from_pretrained()`: - -```py -# Замените "huggingface-course" ниже своим реальным пространством имен, чтобы использовать свой собственный токенизатор -tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") -``` - -Теперь вы готовы обучить языковую модель с нуля и дообучить ее в соответствии с поставленной задачей! Мы займемся этим в [Главе 7](/course/chapter7), но сначала в этой главе мы рассмотрим быстрые токенизаторы и подробно изучим, что происходит при вызове метода `train_new_from_iterator()`. diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx deleted file mode 100644 index 4829edf25..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/3-checkpoint.mdx +++ /dev/null @@ -1,475 +0,0 @@ - - -# Особые возможности быстрых токенизаторов[[fast-tokenizers-special-powers]] - -{#if fw === 'pt'} - - - -{:else} - - - -{/if} - -В этом разделе мы подробно рассмотрим возможности токенизаторов в 🤗 Transformers. До сих пор мы использовали их только для токенизации входных данных или декодирования идентификаторов обратно в текст, но токенизаторы -- особенно те, которые поддерживаются библиотекой 🤗 Tokenizers - могут делать гораздо больше. Чтобы проиллюстрировать эти дополнительные возможности, мы рассмотрим, как воспроизвести результаты конвейеров `token-classification` (которые мы назвали `ner`) и `question-answering`, с которыми мы впервые столкнулись в [Главе 1] (/course/chapter1). - - - -В дальнейшем обсуждении мы будем часто проводить различие между "медленными" и "быстрыми" токенизаторами. Медленные токенизаторы - это те, что написаны на Python в библиотеке 🤗 Transformers, а быстрые версии - это те, что предоставляются в 🤗 Tokenizers, которые написаны на Rust. Если вы помните таблицу из [Главы 5](/course/chapter5/3), в которой приводилось, сколько времени потребовалось быстрому и медленному токенизаторам для токенизации датасета Drug Review Dataset, вы должны иметь представление о том, почему мы называем их быстрыми и медленными: - -| | Быстрый токенизатор | Медленный токенизатор -:--------------:|:----------------------:|:----------------------: -`batched=True` | 10.8s | 4min41s -`batched=False` | 59.2s | 5min3s - - - -⚠️ Когда вы токенизируете одно предложение, вы не всегда увидите разницу в скорости между медленной и быстрой версиями одного и того же токенизатора. Более того, быстрая версия может быть даже медленнее! Только при параллельной токенизации большого количества текстов вы сможете увидеть разницу. - - - -## Batch encoding[[batch-encoding]] - - - -Результат работы токенизатора - это не простой словарь Python; то, что мы получаем, - это специальный объект `BatchEncoding`. Это подкласс словаря (именно поэтому мы раньше могли без проблем индексировать результат), но с дополнительными методами, которые в основном используются быстрыми токенизаторами. - -Помимо возможностей распараллеливания, ключевой функцией быстрых токенизаторов является то, что они всегда отслеживают исходный диапазон текстов, из которых взяты конечные токены, - эту функцию мы называем *сопоставление смещений (offset mapping)*. Это, в свою очередь, открывает такие возможности, как сопоставление каждого слова с порожденными им токенами или сопоставление каждого символа исходного текста с токеном, в котором он находится, и наоборот. - -Давайте посмотрим на пример: - -```py -from transformers import AutoTokenizer - -tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") -example = "My name is Sylvain and I work at Hugging Face in Brooklyn." -encoding = tokenizer(example) -print(type(encoding)) -``` - -Как уже говорилось, на выходе токенизатора мы получаем объект `BatchEncoding`: - -```python out - -``` - -Поскольку класс `AutoTokenizer` по умолчанию выбирает быстрый токенизатор, мы можем использовать дополнительные методы, которые предоставляет объект `BatchEncoding`. У нас есть два способа проверить, является ли наш токенизатор быстрым или медленным. Мы можем проверить атрибут `is_fast` у `tokenizer`: - -```python -tokenizer.is_fast -``` - -```python out -True -``` - -или проверьте тот же атрибут нашего `encoding`: - -```python -encoding.is_fast -``` - -```python out -True -``` - -Давайте посмотрим, что позволяет нам сделать быстрый токенизатор. Во-первых, мы можем получить доступ к токенам без необходимости преобразовывать идентификаторы обратно в токены: - -```py -encoding.tokens() -``` - -```python out -['[CLS]', 'My', 'name', 'is', 'S', '##yl', '##va', '##in', 'and', 'I', 'work', 'at', 'Hu', '##gging', 'Face', 'in', - 'Brooklyn', '.', '[SEP]'] -``` - -В данном случае токен с индексом 5 - это `##yl`, который является частью слова "Sylvain" в исходном предложении. Мы также можем использовать метод `word_ids()`, чтобы получить индекс слова, из которого происходит каждый токен: - -```py -encoding.word_ids() -``` - -```python out -[None, 0, 1, 2, 3, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, None] -``` - -We can see that the tokenizer's special tokens `[CLS]` and `[SEP]` are mapped to `None`, and then each token is mapped to the word it originates from. This is especially useful to determine if a token is at the start of a word or if two tokens are in the same word. We could rely on the `##` prefix for that, but it only works for BERT-like tokenizers; this method works for any type of tokenizer as long as it's a fast one. In the next chapter, we'll see how we can use this capability to apply the labels we have for each word properly to the tokens in tasks like named entity recognition (NER) and part-of-speech (POS) tagging. We can also use it to mask all the tokens coming from the same word in masked language modeling (a technique called _whole word masking_). - -Мы можем видеть, что специальные токены токенизатора `[CLS]` и `[SEP]` сопоставляются с `None`, а затем каждый токен сопоставляется со словом, от которого он происходит. Это особенно полезно для определения того, находится ли токен в начале слова или два токена в одном и том же слове. Для этого мы могли бы использовать префикс `##`, но он работает только для токенизаторов типа BERT; этот метод работает для любого типа токенизаторов, лишь бы он был быстрым. В следующей главе мы увидим, как можно использовать эту возможность для применения меток, которые мы имеем для каждого слова, к токенам в таких задачах, как распознавание именованных сущностей (NER) и тегирование частей речи (part-of-speech - POS). Мы также можем использовать ее для маскирования всех токенов, происходящих от одного и того же слова, при моделировании языка по маске (masked language modeling) (эта техника называется _маскированием всего слова (whole word masking)_). - - - -Понятие "слово" очень сложное. Например, "I'll" (сокращение от "I will") считается одним или двумя словами? На самом деле это зависит от токенизатора и применяемой им операции предварительной токенизации. Некоторые токенизаторы просто разделяют пробелы, поэтому они будут считать это одним словом. Другие используют пунктуацию поверх пробелов, поэтому будут считать это двумя словами. - -✏️ **Попробуйте! ** Создайте токенизатор из контрольных точек `bert-base-cased` и `roberta-base` и токенизируйте с их помощью "81s". Что вы заметили? Каковы идентификаторы слов? - - - -Аналогично, существует метод `sentence_ids()`, который мы можем использовать для сопоставления токена с предложением, из которого оно взято (хотя в этом случае ту же информацию может дать и `token_type_ids`, возвращаемый токенизатором). - -Наконец, с помощью методов `word_to_chars()` или `token_to_chars()` и `char_to_word()` или `char_to_token()` мы можем сопоставить любое слово или токен с символами в оригинальном тексте и наоборот. Например, метод `word_ids()` сообщил нам, что `##yl` является частью слова с индексом 3, но какое это слово в предложении? Мы можем выяснить это следующим образом: - -```py -start, end = encoding.word_to_chars(3) -example[start:end] -``` - -```python out -Sylvain -``` - -Как мы уже говорили, все это происходит благодаря тому, что быстрый токенизатор отслеживает, из какого участка текста происходит каждый токен, в списке *смещений (offsets)*. Чтобы проиллюстрировать их использование, далее мы покажем, как воспроизвести результаты конвейера `token-classification` вручную. - - - -✏️ **Попробуйте!** Создайте свой собственный пример текста и посмотрите, сможете ли вы понять, какие токены связаны с идентификаторами слов, а также как извлечь диапазоны символов для одного слова. Чтобы получить бонусные очки, попробуйте использовать два предложения в качестве входных данных и посмотрите, будут ли идентификаторы предложений иметь для вас смысл. - - - -## Внутри конвейера `token-classification`[[inside-the-token-classification-pipeline]] - -В [Главе 1](/course/chapter1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2] (/course/chapter2), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! - -{#if fw === 'pt'} - - - -{:else} - - - -{/if} - -### Получение базовых результатов с помощью конвейера[[getting-the-base-results-with-the-pipeline]] - -Для начала возьмем конвейер token classification, чтобы получить результаты для сравнения вручную. По умолчанию используется модель [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english); она выполняет NER на предложениях: - -```py -from transformers import pipeline - -token_classifier = pipeline("token-classification") -token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") -``` - -```python out -[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, - {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, - {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, - {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, - {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, - {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, - {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, - {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] -``` - -Модель правильно идентифицировала каждый токен, сгенерировав "Sylvain", как человека, каждый токен, сгенерированный "Hugging Face", как организацию, а токен "Brooklyn" - как местоположение. Мы также можем попросить конвейер сгруппировать токены, которые соответствуют одной и той же сущности: - -```py -from transformers import pipeline - -token_classifier = pipeline("token-classification", aggregation_strategy="simple") -token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") -``` - -```python out -[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, - {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, - {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] -``` - -Выбранная `aggregation_strategy` изменит оценки, вычисляемые для каждой сгруппированной сущности. При использовании значения `"simple"` оценка является средним значением оценок каждого токена данной сущности: например, оценка "Sylvain" является средним значением оценок, которые мы видели в предыдущем примере для токенов `S`, `##yl`, `##va` и `##in`. Другие доступные стратегии: - -- `"first"`, где оценка каждой сущности - это оценка первого токена этой сущности (так, для "Sylvain" это будет 0,993828, оценки токена `S`) -- `"max"`, где оценка каждой сущности - это максимальная оценка токенов в этой сущности (так, для ""Hugging Face"" это будет 0.98879766, оценки "Face"). -- `"average"`, где оценка каждой сущности - это средняя оценка слов, составляющих эту сущность (таким образом, для слова ""Sylvain"" не будет никаких отличий от стратегии `"simple"`, но "Hugging Face" будет иметь оценку 0.9819, среднюю оценку для "Hugging", 0.975, и "Face", 0.98879) - -Now let's see how to obtain these results without using the `pipeline()` function! - -### От входных данных к прогнозам[[from-inputs-to-predictions]] - -{#if fw === 'pt'} - -Сначала нам нужно токенизировать наш ввод и пропустить его через модель. Это делается точно так же, как в [Главе 2](/course/chapter2); мы инстанцируем токенизатор и модель с помощью классов `AutoXxx`, а затем используем их в нашем примере: - -```py -from transformers import AutoTokenizer, AutoModelForTokenClassification - -model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" -tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) -model = AutoModelForTokenClassification.from_pretrained(model_checkpoint) - -example = "My name is Sylvain and I work at Hugging Face in Brooklyn." -inputs = tokenizer(example, return_tensors="pt") -outputs = model(**inputs) -``` - -Поскольку мы используем `AutoModelForTokenClassification`, мы получаем один набор логитов для каждого токена во входной последовательности: - -```py -print(inputs["input_ids"].shape) -print(outputs.logits.shape) -``` - -```python out -torch.Size([1, 19]) -torch.Size([1, 19, 9]) -``` - -{:else} - -Сначала нам нужно токенизировать наши входные данные и пропустить их через модель. Это делается точно так же, как в [Главе 2](/course/chapter2); мы инстанцируем токенизатор и модель с помощью классов `TFAutoXxx`, а затем используем их в нашем примере: - -```py -from transformers import AutoTokenizer, TFAutoModelForTokenClassification - -model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" -tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) -model = TFAutoModelForTokenClassification.from_pretrained(model_checkpoint) - -example = "My name is Sylvain and I work at Hugging Face in Brooklyn." -inputs = tokenizer(example, return_tensors="tf") -outputs = model(**inputs) -``` - -Поскольку мы используем `TFAutoModelForTokenClassification`, мы получаем один набор логитов для каждого токена во входной последовательности: - -```py -print(inputs["input_ids"].shape) -print(outputs.logits.shape) -``` - -```python out -(1, 19) -(1, 19, 9) -``` - -{/if} - -У нас есть батч с 1 последовательностью из 19 токенов, и модель имеет 9 различных меток, поэтому выход модели имеет форму 1 x 19 x 9. Как и для конвейера классификации текста, мы используем функцию softmax для преобразования этих логитов в вероятности и берем argmax для получения прогнозов (обратите внимание, что мы можем взять argmax для логитов, потому что softmax не меняет порядок): - -{#if fw === 'pt'} - -```py -import torch - -probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)[0].tolist() -predictions = outputs.logits.argmax(dim=-1)[0].tolist() -print(predictions) -``` - -{:else} - -```py -import tensorflow as tf - -probabilities = tf.math.softmax(outputs.logits, axis=-1)[0] -probabilities = probabilities.numpy().tolist() -predictions = tf.math.argmax(outputs.logits, axis=-1)[0] -predictions = predictions.numpy().tolist() -print(predictions) -``` - -{/if} - -```python out -[0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 6, 6, 6, 0, 8, 0, 0] -``` - -Атрибут `model.config.id2label` содержит отображение индексов в метки, которые мы можем использовать для осмысления прогнозов: - -```py -model.config.id2label -``` - -```python out -{0: 'O', - 1: 'B-MISC', - 2: 'I-MISC', - 3: 'B-PER', - 4: 'I-PER', - 5: 'B-ORG', - 6: 'I-ORG', - 7: 'B-LOC', - 8: 'I-LOC'} -``` - -Как мы видели ранее, существует 9 меток: `O` - это метка для токенов, которые не входят ни в одну именованную сущность (она означает "вне"), а затем у нас есть две метки для каждого типа сущности (miscellaneous, person, organization и location). Метка `B-XXX` указывает на то, что токен находится в начале сущности `XXX`, а метка `I-XXX` указывает на то, что токен находится внутри сущности `XXX`. Таким образом, в данном примере мы ожидаем, что наша модель классифицирует токен `S` как `B-PER` (начало сущности person), а токены `##yl`, `##va` и `##in` как `I-PER` (внутри сущности person). - -Вы можете подумать, что модель в данном случае ошиблась, поскольку присвоила всем четырем токенам метку `I-PER`, но это не совсем так. На самом деле существует два формата для меток `B-` и `I-`: *IOB1* и *IOB2*. Формат IOB2 (розовый цвет ниже) - это тот, который мы представили, в то время как в формате IOB1 (синий цвет) метки, начинающиеся с `B-`, используются только для разделения двух соседних сущностей одного типа. Используемая нами модель была дообучена на наборе данных, использующем этот формат, поэтому она присваивает токену `S` метку `I-PER`. - -
-IOB1 vs IOB2 format - -
- -С помощью этой карты мы можем воспроизвести (почти полностью) результаты первого конвейера - мы можем просто получить оценку и метку каждого токена, который не был классифицирован как `O`: - -```py -results = [] -tokens = inputs.tokens() - -for idx, pred in enumerate(predictions): - label = model.config.id2label[pred] - if label != "O": - results.append( - {"entity": label, "score": probabilities[idx][pred], "word": tokens[idx]} - ) - -print(results) -``` - -```python out -[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S'}, - {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl'}, - {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va'}, - {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in'}, - {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu'}, - {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging'}, - {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face'}, - {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn'}] -``` - -Это очень похоже на то, что у нас было раньше, за одним исключением: конвейер также предоставил нам информацию о `start` и `end` каждой сущности в исходном предложении. Вот тут-то и пригодится наше сопоставление смещений. Чтобы получить смещения, нам нужно просто установить `return_offsets_mapping=True`, когда мы применяем токенизатор к нашим входным данным: - -```py -inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) -inputs_with_offsets["offset_mapping"] -``` - -```python out -[(0, 0), (0, 2), (3, 7), (8, 10), (11, 12), (12, 14), (14, 16), (16, 18), (19, 22), (23, 24), (25, 29), (30, 32), - (33, 35), (35, 40), (41, 45), (46, 48), (49, 57), (57, 58), (0, 0)] -``` - -Каждый кортеж - это участок текста, соответствующий каждому токену, где `(0, 0)` зарезервировано для специальных токенов. Мы уже видели, что токен с индексом 5 - это `##yl`, который имеет `(12, 14)` в качестве смещения. Если мы возьмем соответствующий фрагмент в нашем примере: - - -```py -example[12:14] -``` - -мы получим нужный участок текста без использования `##`: - -```python out -yl -``` - -Используя это, мы можем дополнить предыдущие результаты: - -```py -results = [] -inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) -tokens = inputs_with_offsets.tokens() -offsets = inputs_with_offsets["offset_mapping"] - -for idx, pred in enumerate(predictions): - label = model.config.id2label[pred] - if label != "O": - start, end = offsets[idx] - results.append( - { - "entity": label, - "score": probabilities[idx][pred], - "word": tokens[idx], - "start": start, - "end": end, - } - ) - -print(results) -``` - -```python out -[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, - {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, - {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, - {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, - {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, - {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, - {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, - {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] -``` - -Это то же самое, что мы получили от первого конвейера! - -### Группировка сущностей[[grouping-entities]] - -Использование смещений для определения начального и конечного ключей для каждой сущности удобно, но эта информация не является строго необходимой. Однако когда мы захотим сгруппировать сущности вместе, смещения избавят нас от большого количества беспорядочного кода. Например, если бы мы хотели сгруппировать токены `Hu`, `##gging` и `Face`, мы могли бы создать специальные правила, согласно которым первые два должны быть присоединены, удалив `##`, а `Face` должен быть добавлен через пробел, поскольку он не начинается с `##` - но это будет работать только для данного конкретного типа токенизатора. Для токенизатора SentencePiece или Byte-Pair-Encoding нам придется написать другой набор правил (о них мы поговорим позже в этой главе). - -С помощью смещений весь этот пользовательский код отпадает: мы просто можем взять в исходном тексте промежуток, который начинается с первого токена и заканчивается последним. Так, в случае с токенами `Hu`, `##gging` и `Face` мы должны начать с символа 33 (начало `Hu`) и закончить символом 45 (конец `Face`): - -```py -example[33:45] -``` - -```python out -Hugging Face -``` - -Чтобы написать код для постобработки прогнозов при группировке сущностей, мы будем группировать сущности, которые идут подряд и помечены `I-XXX`, за исключением первой, которая может быть помечена как `B-XXX` или `I-XXX` (таким образом, мы прекращаем группировать сущность, когда получаем `O`, новый тип сущности, или `B-XXX`, который говорит нам, что начинается сущность того же типа): - -```py -import numpy as np - -results = [] -inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) -tokens = inputs_with_offsets.tokens() -offsets = inputs_with_offsets["offset_mapping"] - -idx = 0 -while idx < len(predictions): - pred = predictions[idx] - label = model.config.id2label[pred] - if label != "O": - # Remove the B- or I- - label = label[2:] - start, _ = offsets[idx] - - # Grab all the tokens labeled with I-label - all_scores = [] - while ( - idx < len(predictions) - and model.config.id2label[predictions[idx]] == f"I-{label}" - ): - all_scores.append(probabilities[idx][pred]) - _, end = offsets[idx] - idx += 1 - - # The score is the mean of all the scores of the tokens in that grouped entity - score = np.mean(all_scores).item() - word = example[start:end] - results.append( - { - "entity_group": label, - "score": score, - "word": word, - "start": start, - "end": end, - } - ) - idx += 1 - -print(results) -``` - -И мы получаем те же результаты, что и со вторым конвейером! - -```python out -[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, - {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, - {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] -``` - -Еще один пример задачи, в которой эти смещения чрезвычайно полезны, - question answering. Погружение в этот конвейер, которое мы сделаем в следующем разделе, также позволит нам взглянуть на последнюю особенность токенизаторов в библиотеке 🤗 Transformers: работа с переполненными токенами (overflowing tokens), когда мы усекаем входные данные до заданной длины. diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx deleted file mode 100644 index f7921fdb6..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/3b-checkpoint.mdx +++ /dev/null @@ -1,642 +0,0 @@ - - -# Быстрые токенизаторы в QA конвейере[[fast-tokenizers-in-the-qa-pipeline]] - -{#if fw === 'pt'} - - - -{:else} - - - -{/if} - -Теперь мы погрузимся в конвейер `question-answering` и посмотрим, как использовать смещения (offsets) для получения ответа на вопрос из контекста, подобно тому, как мы делали это для сгруппированных сущностей в предыдущем разделе. Затем мы посмотрим, как работать с очень длинными контекстами, которые в итоге будут обрезаны. Вы можете пропустить этот раздел, если вас не интересует задача ответа на вопрос. - -{#if fw === 'pt'} - - - -{:else} - - - -{/if} - -## Использование конвейера `question-answering`[[using-the-question-answering-pipeline]] - -Как мы видели в [Главе 1](/course/chapter1), для получения ответа на вопрос мы можем использовать конвейер `question-answering` следующим образом: - -```py -from transformers import pipeline - -question_answerer = pipeline("question-answering") -context = """ -🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch, and TensorFlow — with a seamless integration -between them. It's straightforward to train your models with one before loading them for inference with the other. -""" -question = "Which deep learning libraries back 🤗 Transformers?" -question_answerer(question=question, context=context) -``` - -```python out -{'score': 0.97773, - 'start': 78, - 'end': 105, - 'answer': 'Jax, PyTorch and TensorFlow'} -``` - -В отличие от других конвейеров, которые не могут обрезать и разбивать на части тексты, длина которых превышает максимально допустимую моделью (и поэтому могут пропустить информацию в конце документа), этот конвейер может работать с очень длинными контекстами и вернет ответ на вопрос, даже если он находится в конце: - -```py -long_context = """ -🤗 Transformers: State of the Art NLP - -🤗 Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, -question answering, summarization, translation, text generation and more in over 100 languages. -Its aim is to make cutting-edge NLP easier to use for everyone. - -🤗 Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and -then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and -can be modified to enable quick research experiments. - -Why should I use transformers? - -1. Easy-to-use state-of-the-art models: - - High performance on NLU and NLG tasks. - - Low barrier to entry for educators and practitioners. - - Few user-facing abstractions with just three classes to learn. - - A unified API for using all our pretrained models. - - Lower compute costs, smaller carbon footprint: - -2. Researchers can share trained models instead of always retraining. - - Practitioners can reduce compute time and production costs. - - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. - -3. Choose the right framework for every part of a model's lifetime: - - Train state-of-the-art models in 3 lines of code. - - Move a single model between TF2.0/PyTorch frameworks at will. - - Seamlessly pick the right framework for training, evaluation and production. - -4. Easily customize a model or an example to your needs: - - We provide examples for each architecture to reproduce the results published by its original authors. - - Model internals are exposed as consistently as possible. - - Model files can be used independently of the library for quick experiments. - -🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch and TensorFlow — with a seamless integration -between them. It's straightforward to train your models with one before loading them for inference with the other. -""" -question_answerer(question=question, context=long_context) -``` - -```python out -{'score': 0.97149, - 'start': 1892, - 'end': 1919, - 'answer': 'Jax, PyTorch and TensorFlow'} -``` - -Давайте посмотрим, как он справится со всем этим! - -## Использование модели для ответа на вопросы[[using-a-model-for-question-answering]] - -Как и в любом другом конвейере, мы начинаем с токенизации входных данных, а затем отправляем их через модель. По умолчанию для конвейера `question-answering` используется контрольная точка [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) (слово "squad" в названии происходит от набора данных, на котором дообучили модель; подробнее о наборе данных SQuAD мы поговорим в [главе 7](/course/chapter7/7)): - -{#if fw === 'pt'} - -```py -from transformers import AutoTokenizer, AutoModelForQuestionAnswering - -model_checkpoint = "distilbert-base-cased-distilled-squad" -tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) -model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) - -inputs = tokenizer(question, context, return_tensors="pt") -outputs = model(**inputs) -``` - -{:else} - -```py -from transformers import AutoTokenizer, TFAutoModelForQuestionAnswering - -model_checkpoint = "distilbert-base-cased-distilled-squad" -tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) -model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint) - -inputs = tokenizer(question, context, return_tensors="tf") -outputs = model(**inputs) -``` - -{/if} - -Обратите внимание, что мы токенизируем вопрос и контекст как пару, причем вопрос стоит первым. - -
-An example of tokenization of question and context - -
- -Модели для ответов на вопросы работают немного иначе, чем модели, которые мы рассматривали до сих пор. На примере картинки выше модель была обучена предсказывать индекс токена, с которого начинается ответ (здесь 21), и индекс токена, на котором ответ заканчивается (здесь 24). Вот почему эти модели возвращают не один тензор логитов, а два: один для логитов, соответствующих начальному токену ответа, и один для логитов, соответствующих конечному токену ответа. Поскольку в данном случае у нас только один вход, содержащий 66 токенов, мы получаем: - -```py -start_logits = outputs.start_logits -end_logits = outputs.end_logits -print(start_logits.shape, end_logits.shape) -``` - -{#if fw === 'pt'} - -```python out -torch.Size([1, 66]) torch.Size([1, 66]) -``` - -{:else} - -```python out -(1, 66) (1, 66) -``` - -{/if} - -Чтобы преобразовать эти логиты в вероятности, мы применим функцию softmax, но перед этим нам нужно убедиться, что мы маскируем индексы, которые не являются частью контекста. Наш вход - `[CLS] вопрос [SEP] контекст [SEP]`, поэтому нам нужно замаскировать токены вопроса, а также токен `[SEP]`. Однако мы оставим токен `[CLS]`, поскольку некоторые модели используют его для указания на то, что ответ не находится в контексте. - -Поскольку впоследствии мы будем применять softmax, нам просто нужно заменить логиты, которые мы хотим замаскировать, на большое отрицательное число. Здесь мы используем `-10000`: - -{#if fw === 'pt'} - -```py -import torch - -sequence_ids = inputs.sequence_ids() -# Маскируем все, кроме токенов контекста -mask = [i != 1 for i in sequence_ids] -# Демаскируем токен [CLS] -mask[0] = False -mask = torch.tensor(mask)[None] - -start_logits[mask] = -10000 -end_logits[mask] = -10000 -``` - -{:else} - -```py -import tensorflow as tf - -sequence_ids = inputs.sequence_ids() -# Маскируем все, кроме токенов контекста -mask = [i != 1 for i in sequence_ids] -# Демаскируем токен [CLS] -mask[0] = False -mask = tf.constant(mask)[None] - -start_logits = tf.where(mask, -10000, start_logits) -end_logits = tf.where(mask, -10000, end_logits) -``` - -{/if} - -Теперь, когда мы правильно замаскировали логиты, соответствующие позициям, которые мы не хотим предсказывать, мы можем применить softmax: - -{#if fw === 'pt'} - -```py -start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1)[0] -end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1)[0] -``` - -{:else} - -```py -start_probabilities = tf.math.softmax(start_logits, axis=-1)[0].numpy() -end_probabilities = tf.math.softmax(end_logits, axis=-1)[0].numpy() -``` - -{/if} - -На этом этапе мы могли бы взять argmax вероятностей начала и конца - но в итоге мы можем получить начальный индекс, который больше конечного, поэтому нам нужно принять еще несколько мер предосторожности. Мы вычислим вероятности каждого возможного `start_index` и `end_index`, где `start_index <= end_index`, а затем возьмем кортеж `(start_index, end_index)` с наибольшей вероятностью. - -Если предположить, что события "Ответ начинается на `start_index`" и "Ответ заканчивается на `end_index`" независимы, то вероятность того, что ответ начинается на `start_index` и заканчивается на `end_index`, равна: - -$$\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]$$ - -Таким образом, чтобы вычислить все оценки, нам нужно просто вычислить все произведения \\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\) где `start_index <= end_index`. - -Сначала вычислим все возможные произведения: - -```py -scores = start_probabilities[:, None] * end_probabilities[None, :] -``` - -{#if fw === 'pt'} - -Затем мы замаскируем значения, где `start_index > end_index`, установив для них значение `0` (все остальные вероятности - положительные числа). Функция `torch.triu()` возвращает верхнюю треугольную часть двумерного тензора, переданного в качестве аргумента, поэтому она сделает эту маскировку за нас: - -```py -scores = torch.triu(scores) -``` - -{:else} - -Затем мы замаскируем значения, где `start_index > end_index`, установив для них значение `0` (все остальные вероятности - положительные числа). Функция `np.triu()` возвращает верхнюю треугольную часть двумерного тензора, переданного в качестве аргумента, поэтому она сделает эту маскировку за нас: - -```py -import numpy as np - -scores = np.triu(scores) -``` - -{/if} - -Теперь нам осталось получить индекс максимума. Поскольку PyTorch вернет индекс в плоском тензоре, для получения `start_index` и `end_index` нам нужно воспользоваться операциями получения целой части `//` и остатка `%` от деления: - -```py -max_index = scores.argmax().item() -start_index = max_index // scores.shape[1] -end_index = max_index % scores.shape[1] -print(scores[start_index, end_index]) -``` - -Мы еще не закончили, но, по крайней мере, у нас уже есть корректная оценка ответа (вы можете проверить это, сравнив ее с первым результатом в предыдущем разделе): - -```python out -0.97773 -``` - - - -✏️ **Попробуйте!** Вычислите начальный и конечный индексы для пяти наиболее вероятных ответов. - - - -У нас есть `start_index` и `end_index` ответа в терминах токенов, так что теперь нам просто нужно преобразовать их в индексы символов в контексте. Именно здесь смещения будут очень полезны. Мы можем захватить их и использовать, как мы это делали в задаче token classification: - -```py -inputs_with_offsets = tokenizer(question, context, return_offsets_mapping=True) -offsets = inputs_with_offsets["offset_mapping"] - -start_char, _ = offsets[start_index] -_, end_char = offsets[end_index] -answer = context[start_char:end_char] -``` - -Осталось только отформатировать все, чтобы получить результат: - -```py -result = { - "answer": answer, - "start": start_char, - "end": end_char, - "score": scores[start_index, end_index], -} -print(result) -``` - -```python out -{'answer': 'Jax, PyTorch and TensorFlow', - 'start': 78, - 'end': 105, - 'score': 0.97773} -``` - -Отлично! Это то же самое, что и в нашем первом примере! - - - -✏️ **Попробуйте! ** Используйте лучшие оценки, которые вы вычислили ранее, чтобы показать пять наиболее вероятных ответов. Чтобы проверить результаты, вернитесь к первому конвейеру и передайте `top_k=5` при его вызове. - - - -## Обработка длинных контекстов[[handling-long-contexts]] - -Если мы попытаемся токенизировать вопрос и длинный контекст, который мы использовали в качестве примера ранее, мы получим количество токенов, превышающее максимальную длину, используемую в конвейере `question-answering` (которая составляет 384): - -```py -inputs = tokenizer(question, long_context) -print(len(inputs["input_ids"])) -``` - -```python out -461 -``` - -Поэтому нам нужно обрезать входные данные до максимальной длины. Есть несколько способов сделать это, но мы не хотим усекать вопрос, а только контекст. Поскольку контекст - это второе предложение, мы используем стратегию усечения `" only_second"`. Проблема, которая возникает в этом случае, заключается в том, что ответ на вопрос может не находиться в усеченном контексте. Например, здесь мы выбрали вопрос, ответ на который находится в конце контекста, а когда мы его усекаем, то этого ответа в нём нет: - -```py -inputs = tokenizer(question, long_context, max_length=384, truncation="only_second") -print(tokenizer.decode(inputs["input_ids"])) -``` - -```python out -""" -[CLS] Which deep learning libraries back [UNK] Transformers? [SEP] [UNK] Transformers : State of the Art NLP - -[UNK] Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, -question answering, summarization, translation, text generation and more in over 100 languages. -Its aim is to make cutting-edge NLP easier to use for everyone. - -[UNK] Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and -then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and -can be modified to enable quick research experiments. - -Why should I use transformers? - -1. Easy-to-use state-of-the-art models: - - High performance on NLU and NLG tasks. - - Low barrier to entry for educators and practitioners. - - Few user-facing abstractions with just three classes to learn. - - A unified API for using all our pretrained models. - - Lower compute costs, smaller carbon footprint: - -2. Researchers can share trained models instead of always retraining. - - Practitioners can reduce compute time and production costs. - - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. - -3. Choose the right framework for every part of a model's lifetime: - - Train state-of-the-art models in 3 lines of code. - - Move a single model between TF2.0/PyTorch frameworks at will. - - Seamlessly pick the right framework for training, evaluation and production. - -4. Easily customize a model or an example to your needs: - - We provide examples for each architecture to reproduce the results published by its original authors. - - Model internal [SEP] -""" -``` - -Это означает, что модели будет сложно выбрать правильный ответ. Чтобы исправить это, конвейер `question-answering` позволяет нам разбить контекст на более мелкие фрагменты, указав максимальную длину. Чтобы убедиться, что мы не разбиваем контекст на фрагменты именно в том месте, которое не позволяет найти ответ, он также включает некоторое перекрытие между фрагментами. - -Мы можем заставить токенизатор (быстрый или медленный) сделать это за нас, добавив `return_overflowing_tokens=True`, и указать желаемое перекрытие с помощью аргумента `stride`. Вот пример, использующий небольшое предложение: - -```py -sentence = "This sentence is not too long but we are going to split it anyway." -inputs = tokenizer( - sentence, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 -) - -for ids in inputs["input_ids"]: - print(tokenizer.decode(ids)) -``` - -```python out -'[CLS] This sentence is not [SEP]' -'[CLS] is not too long [SEP]' -'[CLS] too long but we [SEP]' -'[CLS] but we are going [SEP]' -'[CLS] are going to split [SEP]' -'[CLS] to split it anyway [SEP]' -'[CLS] it anyway. [SEP]' -``` - -Как мы видим, предложение было разбито на части таким образом, что каждая запись в `inputs["input_ids"]` содержит не более 6 токенов (чтобы последняя запись была такого же размера, как и остальные, нам придется добавить дополняющие токены (padding tokens)), и между каждой частью есть перекрытие в 2 токена. - -Давайте посмотрим на результат токенизации: - -```py -print(inputs.keys()) -``` - -```python out -dict_keys(['input_ids', 'attention_mask', 'overflow_to_sample_mapping']) -``` - -Как и ожидалось, мы получаем идентификаторы входов и маску внимания. Последний ключ, `overflow_to_sample_mapping`, представляет собой карту, которая говорит нам, какому предложению соответствует каждый из результатов - здесь у нас есть 7 результатов, которые все происходят из (единственного) предложения, которое мы передали токенизатору: - -```py -print(inputs["overflow_to_sample_mapping"]) -``` - -```python out -[0, 0, 0, 0, 0, 0, 0] -``` - -Это более полезно, когда мы токенизируем несколько предложений вместе. Например, так: - -```py -sentences = [ - "This sentence is not too long but we are going to split it anyway.", - "This sentence is shorter but will still get split.", -] -inputs = tokenizer( - sentences, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 -) - -print(inputs["overflow_to_sample_mapping"]) -``` - -gets us: - -```python out -[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] -``` - -что означает, что первое предложение разбито на 7 частей, как и раньше, а следующие 4 части взяты из второго предложения. - -Теперь давайте вернемся к нашему длинному контексту. По умолчанию конвейер `question-answering` использует максимальную длину 384, как мы уже упоминали ранее, и stride 128, что соответствует тому, как была дообучена модель (вы можете настроить эти параметры, передав аргументы `max_seq_len` и `stride` при вызове конвейера). Таким образом, мы будем использовать эти параметры при токенизации. Мы также добавим дополняющие токены (padding tokens) (чтобы иметь образцы одинаковой длины, чтобы можно было строить тензоры), а также запросим смещения: - -```py -inputs = tokenizer( - question, - long_context, - stride=128, - max_length=384, - padding="longest", - truncation="only_second", - return_overflowing_tokens=True, - return_offsets_mapping=True, -) -``` - -Эти `inputs` будут содержать идентификаторы входов и маски внимания, которые ожидает модель, а также смещения и `overflow_to_sample_mapping`, о которых мы только что говорили. Поскольку эти два параметра не используются моделью, мы выкинем их из `inputs` (и не будем хранить карту, поскольку она здесь не нужна) перед преобразованием в тензор: - -{#if fw === 'pt'} - -```py -_ = inputs.pop("overflow_to_sample_mapping") -offsets = inputs.pop("offset_mapping") - -inputs = inputs.convert_to_tensors("pt") -print(inputs["input_ids"].shape) -``` - -```python out -torch.Size([2, 384]) -``` - -{:else} - -```py -_ = inputs.pop("overflow_to_sample_mapping") -offsets = inputs.pop("offset_mapping") - -inputs = inputs.convert_to_tensors("tf") -print(inputs["input_ids"].shape) -``` - -```python out -(2, 384) -``` - -{/if} - -Наш длинный контекст был разделен на две части, а это значит, что после того, как он пройдет через нашу модель, у нас будет два набора начальных и конечных логитов: - -```py -outputs = model(**inputs) - -start_logits = outputs.start_logits -end_logits = outputs.end_logits -print(start_logits.shape, end_logits.shape) -``` - -{#if fw === 'pt'} - -```python out -torch.Size([2, 384]) torch.Size([2, 384]) -``` - -{:else} - -```python out -(2, 384) (2, 384) -``` - -{/if} - -Как и раньше, мы сначала маскируем токены, которые не являются частью контекста, прежде чем использовать softmax. Мы также маскируем все дополняющие токены (padding tokens) (отмеченные маской внимания): - -{#if fw === 'pt'} - -```py -sequence_ids = inputs.sequence_ids() -# Маскируем все, кроме токенов контекста -mask = [i != 1 for i in sequence_ids] -# Демаскируем токен [CLS]. -mask[0] = False -# Маскируем все [PAD] токены -mask = torch.logical_or(torch.tensor(mask)[None], (inputs["attention_mask"] == 0)) - -start_logits[mask] = -10000 -end_logits[mask] = -10000 -``` - -{:else} - -```py -sequence_ids = inputs.sequence_ids() -# Маскируем все, кроме токенов контекста -mask = [i != 1 for i in sequence_ids] -# Демаскируем токен [CLS]. -mask[0] = False -# Маскируем все [PAD] токены -mask = tf.math.logical_or(tf.constant(mask)[None], inputs["attention_mask"] == 0) - -start_logits = tf.where(mask, -10000, start_logits) -end_logits = tf.where(mask, -10000, end_logits) -``` - -{/if} - -Затем мы можем использовать softmax для преобразования логитов в вероятности: - -{#if fw === 'pt'} - -```py -start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1) -end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1) -``` - -{:else} - -```py -start_probabilities = tf.math.softmax(start_logits, axis=-1).numpy() -end_probabilities = tf.math.softmax(end_logits, axis=-1).numpy() -``` - -{/if} - -Следующий шаг аналогичен тому, что мы делали для малого контекста, но мы повторяем его для каждого из наших двух фрагментов. Мы присваиваем оценку всем возможным фрагментам ответа, а затем выбираем фрагмент с наилучшей оценкой: - -{#if fw === 'pt'} - -```py -candidates = [] -for start_probs, end_probs in zip(start_probabilities, end_probabilities): - scores = start_probs[:, None] * end_probs[None, :] - idx = torch.triu(scores).argmax().item() - - start_idx = idx // scores.shape[1] - end_idx = idx % scores.shape[1] - score = scores[start_idx, end_idx].item() - candidates.append((start_idx, end_idx, score)) - -print(candidates) -``` - -{:else} - -```py -candidates = [] -for start_probs, end_probs in zip(start_probabilities, end_probabilities): - scores = start_probs[:, None] * end_probs[None, :] - idx = np.triu(scores).argmax().item() - - start_idx = idx // scores.shape[1] - end_idx = idx % scores.shape[1] - score = scores[start_idx, end_idx].item() - candidates.append((start_idx, end_idx, score)) - -print(candidates) -``` - -{/if} - -```python out -[(0, 18, 0.33867), (173, 184, 0.97149)] -``` - -Эти два кандидата соответствуют лучшим ответам, которые модель смогла найти в каждом фрагменте. Модель гораздо больше уверена в том, что правильный ответ находится во второй части (это хороший знак!). Теперь нам нужно сопоставить эти два диапазона токенов с диапазонами символов в контексте (для получения ответа нам нужно сопоставить только второй, но интересно посмотреть, что модель выбрала в первом фрагменте). - - - -✏️ **Попробуйте! ** Адаптируйте приведенный выше код, чтобы он возвращал оценки и промежутки для пяти наиболее вероятных ответов (в целом, а не по частям). - - - -`offsets`, которую мы взяли ранее, на самом деле является списком смещений, по одному списку на каждый фрагмент текста: - -```py -for candidate, offset in zip(candidates, offsets): - start_token, end_token, score = candidate - start_char, _ = offset[start_token] - _, end_char = offset[end_token] - answer = long_context[start_char:end_char] - result = {"answer": answer, "start": start_char, "end": end_char, "score": score} - print(result) -``` - -```python out -{'answer': '\n🤗 Transformers: State of the Art NLP', 'start': 0, 'end': 37, 'score': 0.33867} -{'answer': 'Jax, PyTorch and TensorFlow', 'start': 1892, 'end': 1919, 'score': 0.97149} -``` - -Если мы проигнорируем первый результат, то получим тот же результат, что и в нашем конвейере для этого длинного контекста - ура! - - - -✏️ **Попробуйте! ** Используйте лучшие оценки, которые вы вычислили ранее, чтобы показать пять наиболее вероятных ответов (для всего контекста, а не для каждого фрагмента). Чтобы проверить результаты, вернитесь к первому конвейеру и передайте `top_k=5` при его вызове. - - - -На этом мы завершаем наше глубокое погружение в возможности токенизатора. В следующей главе мы снова применим все это на практике, когда покажем, как дообучить модель для ряда распространенных задач NLP. diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx deleted file mode 100644 index 75706fdde..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/4-checkpoint.mdx +++ /dev/null @@ -1,123 +0,0 @@ -# Нормализация и предварительная токенизация[[normalization-and-pre-tokenization]] - - - -Прежде чем мы более подробно рассмотрим три наиболее распространенных алгоритма токенизации подслов, используемых в моделях Transformer (Byte-Pair Encoding [BPE], WordPiece и Unigram), мы сначала рассмотрим предварительную обработку, которую каждый токенизатор применяет к тексту. Вот высокоуровневый обзор этапов конвейера токенизации: - -
-The tokenization pipeline. - -
- -Перед тем как разбить текст на подтокены (в соответствии со выбранной моделью), токенизатор выполняет два шага: _нормализацию_ и _претокенизацию_. - -## Нормализация[[normalization]] - - - -Шаг нормализации включает в себя некоторую общую очистку, например, удаление ненужных пробельных символов, понижение регистра и/или удаление ударений. Если вы знакомы с [Unicode normalization](http://www.unicode.org/reports/tr15/) (например, NFC или NFKC), это также может быть применено токенизатором. - -У 🤗 Transformers `tokenizer` есть атрибут `backend_tokenizer`, который предоставляет доступ к базовому токенизатору из библиотеки 🤗 Tokenizers: - -```py -from transformers import AutoTokenizer - -tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") -print(type(tokenizer.backend_tokenizer)) -``` - -```python out - -``` - -Атрибут `normalizer` объекта `tokenizer` имеет метод `normalize_str()`, который мы можем использовать, чтобы увидеть, как выполняется нормализация: - -```py -print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) -``` - -```python out -'hello how are u?' -``` - -В этом примере, поскольку мы выбрали контрольную точку `bert-base-uncased`, нормализация применила нижний регистр и удалила ударения. - - - -✏️ **Попробуйте! ** Загрузите токенизатор из контрольной точки `bert-base-cased` и передайте ему тот же пример. Какие основные различия вы можете увидеть между версией токенизатора cased и uncased? - - - -## Предварительная токенизация[[pre-tokenization]] - - - -Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2] (/course/chapter2), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. - -Чтобы увидеть, как быстрый токенизатор выполняет предварительную токенизацию, мы можем воспользоваться методом `pre_tokenize_str()` атрибута `pre_tokenizer` объекта `tokenizer`: - -```py -tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") -``` - -```python out -[('Hello', (0, 5)), (',', (5, 6)), ('how', (7, 10)), ('are', (11, 14)), ('you', (16, 19)), ('?', (19, 20))] -``` - -Обратите внимание, что токенизатор уже следит за смещениями, и именно поэтому он может дать нам сопоставление смещений, которое мы использовали в предыдущем разделе. Здесь токенизатор игнорирует два пробела и заменяет их одним, но смещение перескакивает между `are` и `you`, чтобы учесть это. - -Поскольку мы используем токенизатор BERT, предварительная токенизация включает часть пробельных символов и пунктуацию. Другие токенизаторы могут иметь другие правила для этого шага. Например, если мы используем токенизатор GPT-2: - -```py -tokenizer = AutoTokenizer.from_pretrained("gpt2") -tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") -``` - -он также выполнит разбиение по пробельным символам и пунктуации, но сохранит пробелы и заменит их символом `Ġ`, что позволит ему восстановить исходные пробелы, если мы декодируем токены: - -```python out -[('Hello', (0, 5)), (',', (5, 6)), ('Ġhow', (6, 10)), ('Ġare', (10, 14)), ('Ġ', (14, 15)), ('Ġyou', (15, 19)), - ('?', (19, 20))] -``` - -Также обратите внимание, что в отличие от токенизатора BERT, этот токенизатор не игнорирует двойной пробел. - -В качестве последнего примера рассмотрим токенизатор T5, основанный на алгоритме SentencePiece: - -```py -tokenizer = AutoTokenizer.from_pretrained("t5-small") -tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") -``` - -```python out -[('▁Hello,', (0, 6)), ('▁how', (7, 10)), ('▁are', (11, 14)), ('▁you?', (16, 20))] -``` - -Как и токенизатор GPT-2, этот сохраняет пробелы и заменяет их специальным токеном (`_`), но токенизатор T5 делает разбиение только по пробелам, а не по знакам препинания. Также обратите внимание, что он по умолчанию добавляет пробел в начале предложения (перед `Hello`) и игнорирует двойной пробел между `are` и `you`. - -Теперь, когда мы немного познакомились с тем, как обрабатывают текст различные токенизаторы, можно приступить к изучению самих алгоритмов, лежащих в их основе. Мы начнем с краткого обзора широко применяемого SentencePiece; затем, в следующих трех разделах, мы рассмотрим, как работают три основных алгоритма, используемых для токенизации по подсловам. - -## SentencePiece[[sentencepiece]] - -[SentencePiece](https://github.com/google/sentencepiece) - это алгоритм токенизации для предварительной обработки текста, который можно использовать с любой из моделей, которые мы рассмотрим в следующих трех разделах. Он рассматривает текст как последовательность символов Unicode и заменяет пробелы специальным символом `▁`. При использовании в сочетании с алгоритмом Unigram (см. [раздел 7](/course/chapter7/7)) он даже не требует шага предварительной токенизации, что очень полезно для языков, где символ пробела не используется (например, китайского или японского). - -Другой главной особенностью SentencePiece является *обратимая токенизация*: поскольку в нем нет специальной обработки пробелов, декодирование токенов осуществляется просто путем их конкатенации и замены `_` на пробелы - в результате получается нормализованный текст. Как мы видели ранее, токенизатор BERT удаляет повторяющиеся пробелы, поэтому его токенизация не является обратимой. - -## Обзор алгоритма[[algorithm-overview]] - -В следующих разделах мы рассмотрим три основных алгоритма токенизации по подсловам: BPE (используется в GPT-2 и других моделях), WordPiece (используется, например, в BERT) и Unigram (используется в T5 и других моделях). Прежде чем мы приступим, вот краткий обзор того, как работает каждый из них. Не стесняйтесь возвращаться к этой таблице после прочтения каждого из следующих разделов, если вам еще не все понятно. - - -Model | BPE | WordPiece | Unigram -:----:|:---:|:---------:|:------: -Обучение | Начинается с маленького словаря и изучает правила слияния токенов | Начинается с маленького словаря и изучает правила слияния токенов | Начинается с большого словаря и изучает правила удаления токенов -Шаг обучения | Объединяет токены, соответствующие наиболее часто встречающейся паре | Объединяет токены, соответствующие паре с наилучшей оценкой, основанной на частоте пары, отдавая предпочтение парам, где каждый отдельный токен встречается реже | Удаляет все токены в словаре, что минимизирует потери, вычисленные для всего корпуса. -Обучение | Слияние правил и словаря | Только словарь | Словарь с оценкой каждого токена -Кодирование | Разбивает слово на символы и применяет слияния, полученные во время обучения | Находит самое длинное подслово, начиная с начала, которое есть в словаре, затем делает то же самое для остальной части слова | Находит наиболее вероятное разбиение на токены, используя оценки, полученные во время обучения - -А теперь давайте погрузимся в BPE! \ No newline at end of file diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/5-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/5-checkpoint.mdx deleted file mode 100644 index f28641f59..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/5-checkpoint.mdx +++ /dev/null @@ -1,360 +0,0 @@ -# Токенизация Byte-Pair Encoding[[byte-pair-encoding-tokenization]] - - - -Byte-Pair Encoding (BPE) изначально была разработана как алгоритм для сжатия текстов, а затем использовалась OpenAI для токенизации при предварительном обучении модели GPT. Она используется во многих моделях трансформеров, включая GPT, GPT-2, RoBERTa, BART и DeBERTa. - - - - - -💡 В этом разделе подробно рассматривается BPE, вплоть до демонстрации полной реализации. Вы можете пропустить этот раздел, если вам нужен только общий обзор алгоритма токенизации. - - - -## Алгоритм обучения[[training-algorithm]] - -Обучение BPE начинается с вычисления уникального набора слов, используемых в корпусе (после завершения этапов нормализации и предварительной токенизации), затем создается словарь, в который заносятся все символы, используемые для записи этих слов. В качестве очень простого примера предположим, что в нашем корпусе используются следующие пять слов: - -``` -"hug", "pug", "pun", "bun", "hugs" -``` - -Тогда базовым словарем будет `["b", "g", "h", "n", "p", "s", "u"]`. В реальном мире этот базовый словарь будет содержать, как минимум, все символы ASCII, а возможно, и некоторые символы Unicode. Если в примере, который вы обрабатываете, используется символ, которого нет в обучающем корпусе, этот символ будет преобразован в неизвестный токен. Это одна из причин, по которой многие модели NLP очень плохо анализируют контент с эмоджи, например. - - - -Токенизаторы GPT-2 и RoBERTa (которые довольно похожи) имеют умный способ решения этой проблемы: они рассматривают слова не как символы Unicode, а как байты. Таким образом, базовый словарь имеет небольшой размер (256), но все символы, которые вы можете придумать, все равно будут включены и не будут преобразованы в неизвестный токен. Этот трюк называется *byte-level BPE*. - - - -После получения базового словаря мы добавляем новые токены, пока не достигнем желаемого объема словаря, обучаясь *слияниям*, которые представляют собой правила слияния двух элементов существующего словаря в новый. Таким образом, в начале эти слияния будут создавать токены с двумя символами, а затем, по мере обучения, более длинные подслова. - -На любом шаге обучения токенизатора алгоритм BPE будет искать наиболее частую пару существующих токенов (под "парой" здесь понимаются два последовательных токена в слове). Эта наиболее часто встречающаяся пара и будет объединена, после чего все повторяется для следующего шага. - -Возвращаясь к нашему предыдущему примеру, предположим, что слова имеют следующую частоту: - -``` -("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) -``` - -значение `" hug"` встречалось в корпусе 10 раз, `"pug"` - 5 раз, `"pun"` - 12 раз, `"bun"` - 4 раза, и `"hugs"` - 5 раз. Мы начинаем обучение с разбиения каждого слова на части символов (те, которые формируют наш начальный словарь), чтобы мы могли рассматривать каждое слово как список токенов: - -``` -("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5) -``` - -Затем мы посмотрим на пары. Пара `("h", "u")` присутствует в словах `"hug"` и `"hugs"`, всего 15 раз в корпусе. Однако это не самая частая пара: эта честь принадлежит `("u", "g")`, которая присутствует в словах `"hug"`, `"pug"` и `"hugs"`, в общей сложности 20 раз в словаре. - -Таким образом, первое правило слияния, выученное токенизатором, - `("u", "g") -> "ug"`, что означает, что `"ug"` будет добавлено в словарь, и эта пара должна быть объединена во всех словах корпуса. В конце этого этапа словарь и корпус выглядят следующим образом: - -``` -Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug"] -Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5) -``` - -Теперь у нас есть несколько пар, в результате которых получается токен длиннее двух символов: например, пара `("h", "ug")` (встречается в корпусе 15 раз). Самая частая пара на этом этапе - `("u", "n")`, однако она встречается в корпусе 16 раз, поэтому второе выученное правило слияния - `("u", "n") -> "un"`. Добавив это в словарь и объединив все существующие вхождения, мы получаем: - -``` -Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un"] -Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("h" "ug" "s", 5) -``` - -Теперь наиболее частой парой является `("h", "ug")`, поэтому мы изучаем правило слияния `("h", "ug") -> "hug"`, что дает нам первый трехбуквенный токен. После слияния корпус выглядит следующим образом: - -``` -Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"] -Corpus: ("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5) -``` - -И продолжаем в том же духе, пока не достигнем желаемого размера словаря. - - - -✏️ **Теперь ваша очередь!** Как вы думаете, каким будет следующее правило слияния? - - - -## Алгоритм токенизации[[tokenization-algorithm]] - -Токенизация следует за процессом обучения в том смысле, что новые входные данные подвергаются токенизации путем применения следующих шагов: - -1. Нормализация -2. Предварительная токенизация -3. Разделение слов на отдельные символы -4. Применение правил слияния, изученных по порядку, к этим частям - -Возьмем пример, который мы использовали во время обучения, с тремя выученными правилами слияния: - -``` -("u", "g") -> "ug" -("u", "n") -> "un" -("h", "ug") -> "hug" -``` - -Слово `"bug"` будет токенизировано как `["b", "ug"]`. Слово `"mug"`, однако, будет токенизировано как `["[UNK]", "ug"]`, поскольку буква `"m"` отсутствует в базовом словаре. Аналогично, слово `"thug" будет токенизировано как `["[UNK]", "hug"]`: буква `"t" отсутствует в базовом словаре, и применение правил слияния приводит сначала к слиянию `"u"` и `"g"`, а затем к слиянию `"h"` и `"ug"`. - - - -✏️ ** Теперь ваша очередь! ** Как вы думаете, как будет токенизировано слово `'unhug''? - - - -## Реализация BPE[[implementing-bpe]] - -Теперь давайте посмотрим на реализацию алгоритма BPE. Это не будет оптимизированная версия, которую вы сможете использовать на большом корпусе; мы просто хотим показать вам код, чтобы вы могли лучше понять алгоритм. - -Для начала нам нужен корпус текста, поэтому давайте создадим простой корпус с несколькими предложениями: - -```python -corpus = [ - "This is the Hugging Face Course.", - "This chapter is about tokenization.", - "This section shows several tokenizer algorithms.", - "Hopefully, you will be able to understand how they are trained and generate tokens.", -] -``` - -Далее нам нужно предварительно токенизировать корпус в слова. Поскольку мы воспроизводим токенизатор BPE (например, GPT-2), для предварительной токенизации мы будем использовать токенизатор `gpt2`: - -```python -from transformers import AutoTokenizer - -tokenizer = AutoTokenizer.from_pretrained("gpt2") -``` - -Затем мы вычисляем частоту каждого слова в корпусе, как и при предварительной токенизации: - -```python -from collections import defaultdict - -word_freqs = defaultdict(int) - -for text in corpus: - words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) - new_words = [word for word, offset in words_with_offsets] - for word in new_words: - word_freqs[word] += 1 - -print(word_freqs) -``` - -```python out -defaultdict(int, {'This': 3, 'Ġis': 2, 'Ġthe': 1, 'ĠHugging': 1, 'ĠFace': 1, 'ĠCourse': 1, '.': 4, 'Ġchapter': 1, - 'Ġabout': 1, 'Ġtokenization': 1, 'Ġsection': 1, 'Ġshows': 1, 'Ġseveral': 1, 'Ġtokenizer': 1, 'Ġalgorithms': 1, - 'Hopefully': 1, ',': 1, 'Ġyou': 1, 'Ġwill': 1, 'Ġbe': 1, 'Ġable': 1, 'Ġto': 1, 'Ġunderstand': 1, 'Ġhow': 1, - 'Ġthey': 1, 'Ġare': 1, 'Ġtrained': 1, 'Ġand': 1, 'Ġgenerate': 1, 'Ġtokens': 1}) -``` - -Следующий шаг - составление базового словаря, состоящего из всех символов, используемых в корпусе: - -```python -alphabet = [] - -for word in word_freqs.keys(): - for letter in word: - if letter not in alphabet: - alphabet.append(letter) -alphabet.sort() - -print(alphabet) -``` - -```python out -[ ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', - 't', 'u', 'v', 'w', 'y', 'z', 'Ġ'] -``` - -Мы также добавляем специальные токены, используемые моделью, в начало этого словаря. В случае GPT-2 единственным специальным токеном является `"<|endoftext|>"`: - -```python -vocab = ["<|endoftext|>"] + alphabet.copy() -``` - -Теперь нам нужно разделить каждое слово на отдельные символы, чтобы можно было начать обучение: - -```python -splits = {word: [c for c in word] for word in word_freqs.keys()} -``` - -Теперь, когда мы готовы к обучению, давайте напишем функцию, которая вычисляет частоту каждой пары. Нам нужно будет использовать ее на каждом шаге обучения: - -```python -def compute_pair_freqs(splits): - pair_freqs = defaultdict(int) - for word, freq in word_freqs.items(): - split = splits[word] - if len(split) == 1: - continue - for i in range(len(split) - 1): - pair = (split[i], split[i + 1]) - pair_freqs[pair] += freq - return pair_freqs -``` - -Давайте посмотрим на часть этого словаря после первых разделений: - -```python -pair_freqs = compute_pair_freqs(splits) - -for i, key in enumerate(pair_freqs.keys()): - print(f"{key}: {pair_freqs[key]}") - if i >= 5: - break -``` - -```python out -('T', 'h'): 3 -('h', 'i'): 3 -('i', 's'): 5 -('Ġ', 'i'): 2 -('Ġ', 't'): 7 -('t', 'h'): 3 -``` - -Теперь, чтобы найти наиболее часто встречающуюся пару, нужно всего лишь сделать быстрый цикл: - -```python -best_pair = "" -max_freq = None - -for pair, freq in pair_freqs.items(): - if max_freq is None or max_freq < freq: - best_pair = pair - max_freq = freq - -print(best_pair, max_freq) -``` - -```python out -('Ġ', 't') 7 -``` - -Итак, первое слияние, которое нужно выучить, это `('Ġ', 't') -> 'Ġt'`, и мы добавляем `'Ġt'` в словарь: - -```python -merges = {("Ġ", "t"): "Ġt"} -vocab.append("Ġt") -``` - -Чтобы продолжить, нам нужно применить это объединение в нашем экземпляре `splits` словаря. Давайте напишем для этого еще одну функцию: - -```python -def merge_pair(a, b, splits): - for word in word_freqs: - split = splits[word] - if len(split) == 1: - continue - - i = 0 - while i < len(split) - 1: - if split[i] == a and split[i + 1] == b: - split = split[:i] + [a + b] + split[i + 2 :] - else: - i += 1 - splits[word] = split - return splits -``` - -И мы можем посмотреть на результат первого слияния: - -```py -splits = merge_pair("Ġ", "t", splits) -print(splits["Ġtrained"]) -``` - -```python out -['Ġt', 'r', 'a', 'i', 'n', 'e', 'd'] -``` - -Теперь у нас есть все, что нужно, чтобы проитерироваться до тех пор, пока мы не выучим все слияния, которые нам нужны. Пусть размер словаря будет 50: - -```python -vocab_size = 50 - -while len(vocab) < vocab_size: - pair_freqs = compute_pair_freqs(splits) - best_pair = "" - max_freq = None - for pair, freq in pair_freqs.items(): - if max_freq is None or max_freq < freq: - best_pair = pair - max_freq = freq - splits = merge_pair(*best_pair, splits) - merges[best_pair] = best_pair[0] + best_pair[1] - vocab.append(best_pair[0] + best_pair[1]) -``` - -В результате мы выучили 19 правил слияния (исходный словарь имел размер 31 - 30 символов в алфавите плюс специальный токен): - -```py -print(merges) -``` - -```python out -{('Ġ', 't'): 'Ġt', ('i', 's'): 'is', ('e', 'r'): 'er', ('Ġ', 'a'): 'Ġa', ('Ġt', 'o'): 'Ġto', ('e', 'n'): 'en', - ('T', 'h'): 'Th', ('Th', 'is'): 'This', ('o', 'u'): 'ou', ('s', 'e'): 'se', ('Ġto', 'k'): 'Ġtok', - ('Ġtok', 'en'): 'Ġtoken', ('n', 'd'): 'nd', ('Ġ', 'is'): 'Ġis', ('Ġt', 'h'): 'Ġth', ('Ġth', 'e'): 'Ġthe', - ('i', 'n'): 'in', ('Ġa', 'b'): 'Ġab', ('Ġtoken', 'i'): 'Ġtokeni'} -``` - -А словарь состоит из специального токена, начального алфавита и всех результатов слияния: - -```py -print(vocab) -``` - -```python out -['<|endoftext|>', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', - 'p', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z', 'Ġ', 'Ġt', 'is', 'er', 'Ġa', 'Ġto', 'en', 'Th', 'This', 'ou', 'se', - 'Ġtok', 'Ġtoken', 'nd', 'Ġis', 'Ġth', 'Ġthe', 'in', 'Ġab', 'Ġtokeni'] -``` - - - -💡 Использование `train_new_from_iterator()` на том же корпусе не приведет к созданию точно такого же словаря. Это связано с тем, что при выборе наиболее частотной пары мы выбираем первую попавшуюся, в то время как библиотека 🤗 Tokenizers выбирает первую пару, основываясь на ее внутренних ID. - - - -Чтобы токенизировать новый текст, мы предварительно токенизируем его, разбиваем на части, а затем применяем все изученные правила слияния: - -```python -def tokenize(text): - pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) - pre_tokenized_text = [word for word, offset in pre_tokenize_result] - splits = [[l for l in word] for word in pre_tokenized_text] - for pair, merge in merges.items(): - for idx, split in enumerate(splits): - i = 0 - while i < len(split) - 1: - if split[i] == pair[0] and split[i + 1] == pair[1]: - split = split[:i] + [merge] + split[i + 2 :] - else: - i += 1 - splits[idx] = split - - return sum(splits, []) -``` - -Мы можем попробовать это на любом тексте, состоящем из символов алфавита: - -```py -tokenize("This is not a token.") -``` - -```python out -['This', 'Ġis', 'Ġ', 'n', 'o', 't', 'Ġa', 'Ġtoken', '.'] -``` - - - -⚠️ Наша реализация будет выбрасывать ошибку при наличии неизвестного символа, поскольку мы ничего не сделали для их обработки. На самом деле в GPT-2 нет неизвестного токена (невозможно получить неизвестный символ при использовании BPE на уровне байтов), но здесь это может произойти, поскольку мы не включили все возможные байты в начальный словарь. Этот аспект BPE выходит за рамки данного раздела, поэтому мы опустили подробности. - - - -Вот и все об алгоритме BPE! Далее мы рассмотрим WordPiece. \ No newline at end of file diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx deleted file mode 100644 index a462d82f2..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/6-checkpoint.mdx +++ /dev/null @@ -1,374 +0,0 @@ -# Токенизация WordPiece[[wordpiece-tokenization]] - - - -WordPiece - это алгоритм токенизации, разработанный Google для предварительного обучения BERT. Впоследствии он был повторно использован во многих моделях трансформеров, основанных на BERT, таких как DistilBERT, MobileBERT, Funnel Transformers и MPNET. Он очень похож на BPE в плане обучения, но фактическая токенизация выполняется по-другому. - - - - - -💡 В этом разделе подробно рассматривается WordPiece, вплоть до демонстрации полной реализации. Вы можете пропустить его, если вам нужен только общий обзор алгоритма токенизации. - - - -## Алгоритм обучения[[training-algorithm]] - - - -⚠️ Google никогда не предоставлял открытый доступ к своей реализации алгоритма обучения WordPiece, поэтому все вышесказанное - это наши предположения, основанные на опубликованных материалах. Возможно, они точны не на 100 %. - - - -Как и BPE, WordPiece начинает работу с небольшого словаря, включающего специальные токены, используемые моделью, и начальный алфавит. Поскольку модель идентифицирует подслова путем добавления префикса (как `##` для BERT), каждое слово первоначально разбивается на части путем добавления этого префикса ко всем символам внутри слова. Так, например, `"word"` разбивается на части следующим образом: - -``` -w ##o ##r ##d -``` - -Таким образом, начальный алфавит содержит все символы, присутствующие в начале слова, и символы, присутствующие внутри слова, которым предшествует префикс WordPiece. - -Затем, как и в случае с BPE, WordPiece изучает правила слияния. Основное отличие заключается в способе выбора пары для слияния. Вместо того чтобы выбирать наиболее частую пару, WordPiece рассчитывает оценку для каждой пары по следующей формуле: - -$$\mathrm{score} = (\mathrm{freq\_of\_pair}) / (\mathrm{freq\_of\_first\_element} \times \mathrm{freq\_of\_second\_element})$$ - -Деля частоту пары на произведение частот каждой из ее частей, алгоритм отдает предпочтение слиянию пар, отдельные части которых встречаются в словаре реже. Например, он не обязательно объединит `("un", "##able")`, даже если эта пара встречается в словаре очень часто, потому что две пары `"un"` и `"##able"`, скорее всего, встречаются в большом количестве других слов и имеют высокую частоту. Напротив, такая пара, как `("hu", "##gging")`, вероятно, будет объединена быстрее (при условии, что слово "hugging" часто встречается в словаре), поскольку `"hu"` и `"##gging"` по отдельности, скорее всего, встречаются реже. - -Давайте рассмотрим тот же словарь, который мы использовали в учебном примере BPE: - -``` -("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) -``` - -Рабиение здесь будет следующим: - -``` -("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##g" "##s", 5) -``` - -поэтому исходный словарь будет иметь вид `["b", "h", "p", "##g", "##n", "##s", "##u"]` (если мы пока забудем о специальных токенах). Самая частая пара - `("##u", "##g")` (встречается 20 раз), но индивидуальная частота `"##u"` очень высока, поэтому ее оценка не самая высокая (она составляет 1/36). Все пары с `"##u"` фактически имеют такую же оценку (1/36), поэтому лучшую оценку получает пара `("##g", "##s")` - единственная, в которой нет `"##u"` - с оценкой 1/20, и первым выученным слиянием будет `("##g", "##s") -> ("##gs")`. - -Обратите внимание, что при слиянии мы удаляем `##` между двумя токенами, поэтому мы добавляем `"##gs"` в словарь и применяем слияние в словах корпуса: - -``` -Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"] -Corpus: ("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##gs", 5) -``` - -В этот момент `"##u"` находится во всех возможных парах, поэтому все они получают одинаковый балл. Допустим, в этом случае первая пара объединяется, так что `("h", "##u") -> "hu"`. Это приводит нас к: - -``` -Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu"] -Corpus: ("hu" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) -``` - -Затем следующую лучшую оценку разделяют `("hu", "##g")` и `("hu", "##gs")` (1/15, по сравнению с 1/21 для всех остальных пар), поэтому первая пара с наибольшей оценкой объединяется: - -``` -Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu", "hug"] -Corpus: ("hug", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) -``` - -и мы продолжаем так до тех пор, пока не достигнем необходимого размера словаря. - - - -✏️ **Теперь ваша очередь!** Каким будет следующее правило слияния? - - - -## Алгоритм токенизации[[tokenization-algorithm]] - -Токенизация в WordPiece и BPE отличается тем, что WordPiece сохраняет только конечный словарь, а не выученные правила слияния. Начиная со слова, которое нужно токенизировать, WordPiece находит самое длинное подслово, которое есть в словаре, а затем разбивает его на части. Например, если мы используем словарь, изученный в примере выше, для слова `" hugs"` самым длинным подсловом, начиная с начала, которое находится в словаре, является `"hug"`, поэтому мы делим его на части и получаем `["hug", "##s"]`. Затем мы продолжаем с `"##s"`, которое находится в словаре, поэтому токенизация `"hugs"` будет `["hug", "##s"]`. - -В BPE мы бы применили слияния, выученные по порядку, и токенизировали это как `["hu", "##gs"]`, поэтому кодировка отличается. - -В качестве другого примера посмотрим, как будет токенизировано слово `"bugs"`. `"b"` - самое длинное подслово, начинающееся с начала слова, которое есть в словаре, поэтому мы делим его на части и получаем `["b", "##ugs"]`. Затем `"##u"` - самое длинное подслово, начинающееся в начале `"##ugs"`, которое есть в словаре, поэтому мы делим его на части и получаем `["b", "##u", "##gs"]`. Наконец, `"##gs"` находится в словаре, так что этот последний список является токеном `"bugs"`. - -Когда токенизация доходит до стадии, когда невозможно найти подслово в словаре, все слово токенизируется как неизвестное - так, например, `"mug"` будет токенизировано как `["[UNK]"]`, как и `"bum"` (даже если мы можем начать с `"b"` и `"##u"`, `"##m"` не входит в словарь, и результирующий токен будет просто `["[UNK]"]`, а не `["b", "##u", "[UNK]"]`). Это еще одно отличие от BPE, который классифицирует как неизвестные только отдельные символы, отсутствующие в словаре. - - - -✏️ **Теперь ваша очередь!** Как будет токенизировано слово `"pugs"`? - - - -## Реализация WordPiece[[implementing-wordpiece]] - -Теперь давайте посмотрим на реализацию алгоритма WordPiece. Как и в случае с BPE, это всего лишь учебный пример, и вы не сможете использовать его на большом корпусе. - -Мы будем использовать тот же корпус, что и в примере с BPE: - -```python -corpus = [ - "This is the Hugging Face Course.", - "This chapter is about tokenization.", - "This section shows several tokenizer algorithms.", - "Hopefully, you will be able to understand how they are trained and generate tokens.", -] -``` - -Во-первых, нам нужно предварительно токенизировать корпус в слова. Поскольку мы воспроизводим токенизатор WordPiece (например, BERT), для предварительной токенизации мы будем использовать токенизатор `bert-base-cased`: - -```python -from transformers import AutoTokenizer - -tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") -``` - -Затем мы вычисляем частоту каждого слова в корпусе, как и при предварительной токенизации: - -```python -from collections import defaultdict - -word_freqs = defaultdict(int) -for text in corpus: - words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) - new_words = [word for word, offset in words_with_offsets] - for word in new_words: - word_freqs[word] += 1 - -word_freqs -``` - -```python out -defaultdict( - int, {'This': 3, 'is': 2, 'the': 1, 'Hugging': 1, 'Face': 1, 'Course': 1, '.': 4, 'chapter': 1, 'about': 1, - 'tokenization': 1, 'section': 1, 'shows': 1, 'several': 1, 'tokenizer': 1, 'algorithms': 1, 'Hopefully': 1, - ',': 1, 'you': 1, 'will': 1, 'be': 1, 'able': 1, 'to': 1, 'understand': 1, 'how': 1, 'they': 1, 'are': 1, - 'trained': 1, 'and': 1, 'generate': 1, 'tokens': 1}) -``` - -Как мы уже видели, алфавит - это уникальное множество, состоящее из всех первых букв слов и всех остальных букв, которые встречаются в словах с префиксом `##`: - -```python -alphabet = [] -for word in word_freqs.keys(): - if word[0] not in alphabet: - alphabet.append(word[0]) - for letter in word[1:]: - if f"##{letter}" not in alphabet: - alphabet.append(f"##{letter}") - -alphabet.sort() -alphabet - -print(alphabet) -``` - -```python out -['##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', '##l', '##m', '##n', '##o', '##p', '##r', '##s', - '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', - 'w', 'y'] -``` - -Мы также добавляем специальные токены, используемые моделью, в начало этого словаря. В случае BERT это список `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]`: - -```python -vocab = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] + alphabet.copy() -``` - -Далее нам нужно разделить каждое слово на части, при этом все буквы, которые не являются первыми, должны иметь префикс `##`: - -```python -splits = { - word: [c if i == 0 else f"##{c}" for i, c in enumerate(word)] - for word in word_freqs.keys() -} -``` - -Теперь, когда мы готовы к обучению, давайте напишем функцию, которая вычисляет оценку каждой пары. Нам нужно будет использовать ее на каждом шаге обучения: - -```python -def compute_pair_scores(splits): - letter_freqs = defaultdict(int) - pair_freqs = defaultdict(int) - for word, freq in word_freqs.items(): - split = splits[word] - if len(split) == 1: - letter_freqs[split[0]] += freq - continue - for i in range(len(split) - 1): - pair = (split[i], split[i + 1]) - letter_freqs[split[i]] += freq - pair_freqs[pair] += freq - letter_freqs[split[-1]] += freq - - scores = { - pair: freq / (letter_freqs[pair[0]] * letter_freqs[pair[1]]) - for pair, freq in pair_freqs.items() - } - return scores -``` - -Давайте посмотрим на часть этого словаря после первых разделений: - -```python -pair_scores = compute_pair_scores(splits) -for i, key in enumerate(pair_scores.keys()): - print(f"{key}: {pair_scores[key]}") - if i >= 5: - break -``` - -```python out -('T', '##h'): 0.125 -('##h', '##i'): 0.03409090909090909 -('##i', '##s'): 0.02727272727272727 -('i', '##s'): 0.1 -('t', '##h'): 0.03571428571428571 -('##h', '##e'): 0.011904761904761904 -``` - -Теперь для того, чтобы найти пару с наилучшим результатом, нужно всего лишь сделать быстрый цикл: - -```python -best_pair = "" -max_score = None -for pair, score in pair_scores.items(): - if max_score is None or max_score < score: - best_pair = pair - max_score = score - -print(best_pair, max_score) -``` - -```python out -('a', '##b') 0.2 -``` - -Итак, первое слияние, которое нужно выучить, это `('a', '##b') -> 'ab'`, и мы добавляем `'ab'` в словарь: - -```python -vocab.append("ab") -``` - -Чтобы продолжить, нам нужно применить это слияние в нашем словаре `splits`. Давайте напишем для этого еще одну функцию: - -```python -def merge_pair(a, b, splits): - for word in word_freqs: - split = splits[word] - if len(split) == 1: - continue - i = 0 - while i < len(split) - 1: - if split[i] == a and split[i + 1] == b: - merge = a + b[2:] if b.startswith("##") else a + b - split = split[:i] + [merge] + split[i + 2 :] - else: - i += 1 - splits[word] = split - return splits -``` - -И мы можем посмотреть на результат первого слияния: - -```py -splits = merge_pair("a", "##b", splits) -splits["about"] -``` - -```python out -['ab', '##o', '##u', '##t'] -``` - -Теперь у нас есть все, что нужно, чтобы зацикливать процесс до тех пор, пока мы не выучим все слияния, которые нам нужны. Давайте нацелимся на размер словаря равный 70: - -```python -vocab_size = 70 -while len(vocab) < vocab_size: - scores = compute_pair_scores(splits) - best_pair, max_score = "", None - for pair, score in scores.items(): - if max_score is None or max_score < score: - best_pair = pair - max_score = score - splits = merge_pair(*best_pair, splits) - new_token = ( - best_pair[0] + best_pair[1][2:] - if best_pair[1].startswith("##") - else best_pair[0] + best_pair[1] - ) - vocab.append(new_token) -``` - -Затем мы можем просмотреть созданный словарь: - -```py -print(vocab) -``` - -```python out -['[PAD]', '[UNK]', '[CLS]', '[SEP]', '[MASK]', '##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', - '##l', '##m', '##n', '##o', '##p', '##r', '##s', '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', - 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', 'w', 'y', 'ab', '##fu', 'Fa', 'Fac', '##ct', '##ful', '##full', '##fully', - 'Th', 'ch', '##hm', 'cha', 'chap', 'chapt', '##thm', 'Hu', 'Hug', 'Hugg', 'sh', 'th', 'is', '##thms', '##za', '##zat', - '##ut'] -``` - -Как мы видим, по сравнению с BPE этот токенизатор быстрее выучивает части слов как токены. - - - -💡 Использование `train_new_from_iterator()` на одном и том же корпусе не приведет к точно такому же словарю. Это происходит потому, что библиотека 🤗 Tokenizers не реализует WordPiece для обучения (поскольку мы не полностью уверены в его внутреннем устройстве), а использует вместо него BPE. - - - -Чтобы токенизировать новый текст, мы предварительно токенизируем его, разбиваем на части, а затем применяем алгоритм токенизации к каждому слову. То есть начиная с первого слова мы ищем самое большое подслово и разбиваем его на части, затем мы повторяем процесс для второй части, и так далее для оставшейся части этого слова и следующих слов в тексте: - -```python -def encode_word(word): - tokens = [] - while len(word) > 0: - i = len(word) - while i > 0 and word[:i] not in vocab: - i -= 1 - if i == 0: - return ["[UNK]"] - tokens.append(word[:i]) - word = word[i:] - if len(word) > 0: - word = f"##{word}" - return tokens -``` - -Давайте проверим алгоритм на одном слове, которое есть в словаре, и на другом, которого нет: - -```python -print(encode_word("Hugging")) -print(encode_word("HOgging")) -``` - -```python out -['Hugg', '##i', '##n', '##g'] -['[UNK]'] -``` - -Теперь давайте напишем функцию, которая токенизирует текст: - -```python -def tokenize(text): - pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) - pre_tokenized_text = [word for word, offset in pre_tokenize_result] - encoded_words = [encode_word(word) for word in pre_tokenized_text] - return sum(encoded_words, []) -``` - -Мы можем попробовать его на любом тексте: - -```python -tokenize("This is the Hugging Face course!") -``` - -```python out -['Th', '##i', '##s', 'is', 'th', '##e', 'Hugg', '##i', '##n', '##g', 'Fac', '##e', 'c', '##o', '##u', '##r', '##s', - '##e', '[UNK]'] -``` - -Вот и все об алгоритме WordPiece! Теперь давайте посмотрим на Unigram. diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/7-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/7-checkpoint.mdx deleted file mode 100644 index 032c92f79..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/7-checkpoint.mdx +++ /dev/null @@ -1,381 +0,0 @@ -# Токенизация Unigram[[unigram-tokenization]] - - - -Алгоритм Unigram часто используется в SentencePiece, который является алгоритмом токенизации, применяемым в таких моделях, как AlBERT, T5, mBART, Big Bird и XLNet. - - - - - -💡 В этом разделе подробно рассматривается Unigram, вплоть до демонстрации полной реализации. Вы можете пропустить его, если вам нужен только общий обзор алгоритма токенизации. - - - -## Алгоритм обучения[[training-algorithm]] - -По сравнению с BPE и WordPiece, Unigram работает в другом направлении: он начинает с большого словарного запаса и удаляет из него токены, пока не достигнет желаемого размера словаря. Существует несколько вариантов создания базового словаря: например, мы можем взять наиболее часто встречающиеся подстроки в предварительно токенизированных словах или применить BPE к исходному корпусу с большим объемом словаря. - -На каждом шаге обучения алгоритм Unigram рассчитывает потери по корпусу с учетом текущего словарного запаса. Затем для каждого символа в словаре алгоритм вычисляет, насколько увеличится общая потеря, если этот символ будет удален, и ищет символы, которые увеличат ее меньше всего. Эти символы оказывают меньшее влияние на общую потерю по корпусу, поэтому в некотором смысле они "менее нужны" и являются лучшими кандидатами на удаление. - -Это очень дорогостоящая операция, поэтому мы удаляем не просто один символ, связанный с наименьшим увеличением потерь, а \\(p\\) (\\(p\\) - гиперпараметр, которым вы можете управлять, обычно 10 или 20) процентов символов, связанных с наименьшим увеличением потерь. Этот процесс повторяется до тех пор, пока словарь не достигнет желаемого размера. - -Обратите внимание, что мы никогда не удаляем базовые символы, чтобы убедиться, что любое слово может быть токенизировано. - -Итак, все еще немного туманно: основная часть алгоритма заключается в том, чтобы вычислить потери по корпусу и посмотреть, как они изменяются при удалении некоторых токенов из словаря, но мы еще не объяснили, как это сделать. Этот шаг зависит от алгоритма токенизации модели Unigram, поэтому мы рассмотрим его далее. - -Мы используем корпус текста из предыдущих примеров: - -``` -("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) -``` - -и для этого примера мы возьмем все подстроки из исходного словаря: - -``` -["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"] -``` - -## Алгоритм токенизации[[tokenization-algorithm]] - -Модель Unigram - это тип языковой модели, в которой каждый токен рассматривается как независимый от предшествующих ему. Это самая простая языковая модель в том смысле, что вероятность появления токена X с учетом предыдущего контекста - это просто вероятность появления токена X. Таким образом, если бы мы использовали модель Unigram для генерации текста, мы бы всегда предсказывали наиболее часто встречающийся токен. - -Вероятность данного токена - это его частота (количество раз, когда мы его находим) в исходном корпусе, деленная на сумму частот всех токенов в словаре (чтобы убедиться, что суммы вероятностей равны 1). Например, `"ug"` присутствует в `"hug"`, `"pug"` и `"hugs"`, поэтому его частота в нашем корпусе равна 20. - -Здесь приведены частоты всех возможных подслов в словаре: - -``` -("h", 15) ("u", 36) ("g", 20) ("hu", 15) ("ug", 20) ("p", 17) ("pu", 17) ("n", 16) -("un", 16) ("b", 4) ("bu", 4) ("s", 5) ("hug", 15) ("gs", 5) ("ugs", 5) -``` - -Итак, сумма всех частот равна 210, а вероятность появления подслова `"ug"`, таким образом, составляет 20/210. - - - -✏️ **Теперь ваша очередь!** Напишите код для вычисления вышеуказанных частот и дважды проверьте правильность приведенных результатов, а также общую сумму. - - - -Теперь для токенизации данного слова мы рассматриваем все возможные сегментации на токены и вычисляем вероятность каждого из них в соответствии с моделью Unigram. Поскольку все токены считаются независимыми, эта вероятность равна произведению вероятностей появления каждого токена. Например, при токенизации `["p", "u", "g"]` слова `"pug"` вероятность составляет: - -$$P([``p", ``u", ``g"]) = P(``p") \times P(``u") \times P(``g") = \frac{5}{210} \times \frac{36}{210} \times \frac{20}{210} = 0.000389$$ - -Для сравнения, токен `["pu", "g"]` имеет вероятность: - -$$P([``pu", ``g"]) = P(``pu") \times P(``g") = \frac{5}{210} \times \frac{20}{210} = 0.0022676$$ - -так что один из них гораздо более вероятен. В целом, токенизации с наименьшим количеством токенов будут иметь наибольшую вероятность (из-за деления на 210, повторяющегося для каждого токена), что соответствует интуитивному желанию: разбить слово на наименьшее количество токенов. - -Токенизация слова с помощью модели Unigram - это токенизация с наибольшей вероятностью. В примере с `"pug"` приведены вероятности, которые мы получили бы для каждой возможной сегментации: - -``` -["p", "u", "g"] : 0.000389 -["p", "ug"] : 0.0022676 -["pu", "g"] : 0.0022676 -``` - -Так, `"pug"` будет токенизировано как `["p", "ug"]` или `["pu", "g"]`, в зависимости от того, какая из этих сегментаций встретится первой (отметим, что в большом корпусе подобные случаи равенства будут редки). - -В данном случае было легко найти все возможные сегментации и вычислить их вероятности, но в общем случае это будет немного сложнее. Для этого используется классический алгоритм, который называется *алгоритм Витерби (Viterbi algorithm)*. По сути, мы можем построить граф для выявления возможных сегментаций данного слова, сказав, что существует ветвь от символа _a_ до символа _b_, если подслово от _a_ до _b_ есть в словаре, и приписать этой ветви вероятность подслова. - -Чтобы найти путь в этом графе, который будет иметь наилучшую оценку, алгоритм Витерби определяет для каждой позиции в слове сегментацию с наилучшей оценкой, которая заканчивается на этой позиции. Поскольку мы идем от начала к концу, этот лучший результат можно найти, перебирая все подслова, заканчивающиеся на текущей позиции, а затем используя лучший результат токенизации с позиции, на которой начинается это подслово. Затем нужно просто развернуть путь, чтобы прийти к концу. - -Давайте рассмотрим пример с использованием нашего словаря и слова `"unhug"`. Для каждой позиции подслова с наилучшими оценками заканчиваются следующим образом: - -``` -Character 0 (u): "u" (score 0.171429) -Character 1 (n): "un" (score 0.076191) -Character 2 (h): "un" "h" (score 0.005442) -Character 3 (u): "un" "hu" (score 0.005442) -Character 4 (g): "un" "hug" (score 0.005442) -``` - -Таким образом, `"unhug"` будет токенизировано как `["un", "hug"]`. - - - -✏️ **Теперь ваша очередь!** Определите токенизацию слова `" huggun"` и его оценку. - - - -## Назад к обучению[[back-to-training]] - -Теперь, когда мы увидели, как работает токенизация, мы можем немного глубже изучить потери, используемые во время обучения. На любом этапе эта потеря вычисляется путем токенизации каждого слова в корпусе с использованием текущего словаря и модели Unigram, определяемой частотами каждого токена в корпусе (как было показано ранее). - -Каждое слово в корпусе имеет оценку, а потеря - это отрицательное логарифмическое правдоподобие этих оценок, то есть сумма для всех слов в корпусе всех `-log(P(word))`. - -Давайте вернемся к нашему примеру со следующим корпусом: - -``` -("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) -``` - -Токенизация каждого слова с соответствующими оценками: - -``` -"hug": ["hug"] (score 0.071428) -"pug": ["pu", "g"] (score 0.007710) -"pun": ["pu", "n"] (score 0.006168) -"bun": ["bu", "n"] (score 0.001451) -"hugs": ["hug", "s"] (score 0.001701) -``` - -Таким образом, потери будут: - -``` -10 * (-log(0.071428)) + 5 * (-log(0.007710)) + 12 * (-log(0.006168)) + 4 * (-log(0.001451)) + 5 * (-log(0.001701)) = 169.8 -``` - -Теперь нам нужно вычислить, как удаление каждого токена влияет на потери. Это довольно утомительно, поэтому мы просто сделаем это для двух токенов и оставим весь процесс на потом, когда у нас будет код, чтобы помочь нам. В этом (очень) конкретном случае у нас есть две эквивалентные токенизации всех слов: как мы видели ранее, например, `"pug"` может быть токенизировано `["p", "ug"]` с тем же результатом. Таким образом, удаление токена `"pu"` из словаря приведет к точно таким же потерям. - -С другой стороны, удаление `" hug"` усугубит потери, потому что токенизация `"hug"` и `"hugs"` станет: - -``` -"hug": ["hu", "g"] (score 0.006802) -"hugs": ["hu", "gs"] (score 0.001701) -``` - -Эти изменения приведут к увеличению потерь: - -``` -- 10 * (-log(0.071428)) + 10 * (-log(0.006802)) = 23.5 -``` - -Поэтому токен `"pu"`, вероятно, будет удален из словаря, но не `"hug"`. - -## Реализация Unigram[[implementing-unigram]] - -Теперь давайте реализуем все, что мы видели до сих пор, в коде. Как и в случае с BPE и WordPiece, это не эффективная реализация алгоритма Unigram (совсем наоборот), но она должна помочь вам понять его немного лучше. - -В качестве примера мы будем использовать тот же корпус текста, что и раньше: - -```python -corpus = [ - "This is the Hugging Face Course.", - "This chapter is about tokenization.", - "This section shows several tokenizer algorithms.", - "Hopefully, you will be able to understand how they are trained and generate tokens.", -] -``` - -На этот раз в качестве модели мы будем использовать `xlnet-base-cased`: - -```python -from transformers import AutoTokenizer - -tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased") -``` - -Как и в случае с BPE и WordPiece, мы начинаем с подсчета количества вхождений каждого слова в корпус: - -```python -from collections import defaultdict - -word_freqs = defaultdict(int) -for text in corpus: - words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) - new_words = [word for word, offset in words_with_offsets] - for word in new_words: - word_freqs[word] += 1 - -word_freqs -``` - -Затем нам нужно инициализировать наш словарь чем-то большим, чем размер словаря, который мы захотим получить в конце. Мы должны включить все основные символы (иначе мы не сможем токенизировать каждое слово), но для больших подстрок мы сохраним только самые распространенные, поэтому мы отсортируем их по частоте: - -```python -char_freqs = defaultdict(int) -subwords_freqs = defaultdict(int) -for word, freq in word_freqs.items(): - for i in range(len(word)): - char_freqs[word[i]] += freq - # Перебираем подслова длиной не менее 2 - for j in range(i + 2, len(word) + 1): - subwords_freqs[word[i:j]] += freq - -# Сортировка подслов по частоте -sorted_subwords = sorted(subwords_freqs.items(), key=lambda x: x[1], reverse=True) -sorted_subwords[:10] -``` - -```python out -[('▁t', 7), ('is', 5), ('er', 5), ('▁a', 5), ('▁to', 4), ('to', 4), ('en', 4), ('▁T', 3), ('▁Th', 3), ('▁Thi', 3)] -``` - -Мы группируем символы с лучшими подсловами, чтобы получить начальный словарь размером 300: - -```python -token_freqs = list(char_freqs.items()) + sorted_subwords[: 300 - len(char_freqs)] -token_freqs = {token: freq for token, freq in token_freqs} -``` - - - -💡 SentencePiece использует более эффективный алгоритм под названием Enhanced Suffix Array (ESA) для создания начального словаря. - - - -Далее мы вычисляем сумму всех частот, чтобы преобразовать частоты в вероятности. Для нашей модели мы будем хранить логарифмы вероятностей, потому что численно стабильнее складывать логарифмы, чем перемножать маленькие числа, и это упростит вычисление потерь модели: - -```python -from math import log - -total_sum = sum([freq for token, freq in token_freqs.items()]) -model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} -``` - -Теперь основная функция - это функция токенизации слов с помощью алгоритма Витерби. Как мы уже видели, этот алгоритм вычисляет наилучшую сегментацию каждой подстроки слова, которую мы будем хранить в переменной с именем `best_segmentations`. Мы будем хранить по одному словарю на каждую позицию в слове (от 0 до его полной длины), с двумя ключами: индекс начала последнего токена в лучшей сегментации и оценка лучшей сегментации. По индексу начала последнего токена мы сможем получить полную сегментацию, когда список будет полностью заполнен. - -Пополнение списка осуществляется с помощью двух циклов: основной цикл просматривает каждую начальную позицию, а второй цикл перебирает все подстроки, начинающиеся с этой начальной позиции. Если подстрока есть в словаре, мы получаем новую сегментацию слова до этой конечной позиции, которую сравниваем с той, что хранится в `best_segmentations`. - -После завершения основного цикла мы просто начинаем с конца и переходим от одной начальной позиции к другой, записывая токены по мере продвижения, пока не достигнем начала слова: - -```python -def encode_word(word, model): - best_segmentations = [{"start": 0, "score": 1}] + [ - {"start": None, "score": None} for _ in range(len(word)) - ] - for start_idx in range(len(word)): - # Это должно быть правильно заполнено предыдущими шагами цикла - best_score_at_start = best_segmentations[start_idx]["score"] - for end_idx in range(start_idx + 1, len(word) + 1): - token = word[start_idx:end_idx] - if token in model and best_score_at_start is not None: - score = model[token] + best_score_at_start - # Если мы нашли лучшую сегментацию, заканчивающуюся на end_idx, мы обновляем - if ( - best_segmentations[end_idx]["score"] is None - or best_segmentations[end_idx]["score"] > score - ): - best_segmentations[end_idx] = {"start": start_idx, "score": score} - - segmentation = best_segmentations[-1] - if segmentation["score"] is None: - # Мы не нашли токенизацию слова -> возвращаем unknown - return [""], None - - score = segmentation["score"] - start = segmentation["start"] - end = len(word) - tokens = [] - while start != 0: - tokens.insert(0, word[start:end]) - next_start = best_segmentations[start]["start"] - end = start - start = next_start - tokens.insert(0, word[start:end]) - return tokens, score -``` - -Мы уже можем опробовать нашу первоначальную модель на некоторых словах: - -```python -print(encode_word("Hopefully", model)) -print(encode_word("This", model)) -``` - -```python out -(['H', 'o', 'p', 'e', 'f', 'u', 'll', 'y'], 41.5157494601402) -(['This'], 6.288267030694535) -``` - -Теперь легко вычислить потери модели на корпусе! - -```python -def compute_loss(model): - loss = 0 - for word, freq in word_freqs.items(): - _, word_loss = encode_word(word, model) - loss += freq * word_loss - return loss -``` - -Мы можем проверить его работу на имеющейся у нас модели: - -```python -compute_loss(model) -``` - -```python out -413.10377642940875 -``` - -Вычисление оценок для каждого токена также не представляет особой сложности; нам просто нужно вычислить потери для модели, полученные при удалении каждого токена: - -```python -import copy - - -def compute_scores(model): - scores = {} - model_loss = compute_loss(model) - for token, score in model.items(): - # We always keep tokens of length 1 - if len(token) == 1: - continue - model_without_token = copy.deepcopy(model) - _ = model_without_token.pop(token) - scores[token] = compute_loss(model_without_token) - model_loss - return scores -``` - -Мы можем попробовать это на заданном токене: - -```python -scores = compute_scores(model) -print(scores["ll"]) -print(scores["his"]) -``` - -Поскольку `"ll"` используется в токенизации слова `"Hopefully"`, и его удаление, вероятно, заставит нас дважды использовать токен `"l"` вместо этого, мы ожидаем, что он будет иметь положительную потерю. `"his"` используется только внутри слова `"This"`, которое токенизируется само по себе, поэтому мы ожидаем, что потери будут нулевыми. Вот результаты: - -```python out -6.376412403623874 -0.0 -``` - - - -💡 Такой подход очень неэффективен, поэтому SentencePiece использует приближенную оценку потерь модели без токена X: вместо того чтобы начинать с нуля, он просто заменяет токен X его сегментацией в оставшемся словаре. Таким образом, все оценки могут быть вычислены одновременно с потерями модели. - - - -Когда этот процесс завершиться, останется только добавить в словарь специальные токены, используемые моделью, а затем итерироваться, пока мы не вычеркнем из словаря достаточно токенов, чтобы достичь желаемого размера: - -```python -percent_to_remove = 0.1 -while len(model) > 100: - scores = compute_scores(model) - sorted_scores = sorted(scores.items(), key=lambda x: x[1]) - # Remove percent_to_remove tokens with the lowest scores. - for i in range(int(len(model) * percent_to_remove)): - _ = token_freqs.pop(sorted_scores[i][0]) - - total_sum = sum([freq for token, freq in token_freqs.items()]) - model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} -``` - -Затем, чтобы токенизировать некоторый текст, нам просто нужно применить предварительную токенизацию, а затем использовать нашу функцию `encode_word()`: - -```python -def tokenize(text, model): - words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) - pre_tokenized_text = [word for word, offset in words_with_offsets] - encoded_words = [encode_word(word, model)[0] for word in pre_tokenized_text] - return sum(encoded_words, []) - - -tokenize("This is the Hugging Face course.", model) -``` - -```python out -['▁This', '▁is', '▁the', '▁Hugging', '▁Face', '▁', 'c', 'ou', 'r', 's', 'e', '.'] -``` - -Вот и все об Unigram! Надеемся, теперь вы чувствуете себя экспертом во всем, что касается токенизаторов. В следующем разделе мы рассмотрим блоки библиотеки 🤗 Tokenizers и покажем, как их можно использовать для создания собственного токенизатора. diff --git a/chapters/ru/chapter6/.ipynb_checkpoints/8-checkpoint.mdx b/chapters/ru/chapter6/.ipynb_checkpoints/8-checkpoint.mdx deleted file mode 100644 index 9a7367458..000000000 --- a/chapters/ru/chapter6/.ipynb_checkpoints/8-checkpoint.mdx +++ /dev/null @@ -1,565 +0,0 @@ -# Создание токенизатора, блок за блоком[[building-a-tokenizer-block-by-block]] - - - -Как мы уже видели в предыдущих разделах, токенизация состоит из нескольких этапов: - -- Нормализация (любая необходимая очистка текста, например, удаление пробелов или подчеркиваний, нормализация Unicode и т. д.) -- Предварительная токенизация (разделение входного текста на слова). -- Прогон входных данных через модель (использование предварительно токенизированных слов для создания последовательности токенов) -- Постобработка (добавление специальных токенов токенизатора, генерация маски внимания и идентификаторов типов токенов) - -В качестве напоминания вот еще один взгляд на общий процесс: - -
-The tokenization pipeline. - -
- -Библиотека 🤗 Tokenizers была создана для того, чтобы предоставить несколько вариантов каждого из этих шагов, которые вы можете смешивать и сочетать между собой. В этом разделе мы рассмотрим, как можно создать токенизатор с нуля, а не обучать новый токенизатор на основе старого, как мы делали в [разделе 2](/course/chapter6/2). После этого вы сможете создать любой токенизатор, который только сможете придумать! - - - -Точнее, библиотека построена вокруг центрального класса `Tokenizer`, а строительные блоки сгруппированы в подмодули: - -- `normalizers` содержит все возможные типы нормализаторов текста `Normalizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). -- `pre_tokenizers` содержит все возможные типы предварительных токенизаторов `PreTokenizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). -- `models` содержит различные типы моделей `Model`, которые вы можете использовать, такие как `BPE`, `WordPiece` и `Unigram` (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). -- `trainers` содержит все различные типы `Trainer`, которые вы можете использовать для обучения модели на корпусе (по одному на каждый тип модели; полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). -- `post_processors` содержит различные типы постпроцессоров `PostProcessor`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). -- `decoders` содержит различные типы декодеров `Decoder`, которые вы можете использовать для декодирования результатов токенизации (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). - -Весь список блоков вы можете найти [здесь](https://huggingface.co/docs/tokenizers/python/latest/components.html). - -## Получение корпуса текста[[acquiring-a-corpus]] - -Для обучения нашего нового токенизатора мы будем использовать небольшой корпус текстов (чтобы примеры выполнялись быстро). Шаги по сбору корпуса аналогичны тем, что мы делали в [начале этой главы](/course/chapter6/2), но на этот раз мы будем использовать набор данных [WikiText-2](https://huggingface.co/datasets/wikitext): - -```python -from datasets import load_dataset - -dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train") - - -def get_training_corpus(): - for i in range(0, len(dataset), 1000): - yield dataset[i : i + 1000]["text"] -``` - -Функция `get_training_corpus()` - это генератор, который выдает батч из 1000 текстов, которые мы будем использовать для обучения токенизатора. - -🤗 Токенизаторы также можно обучать непосредственно на текстовых файлах. Вот как мы можем сгенерировать текстовый файл, содержащий все тексты/входы из WikiText-2, который мы можем использовать локально: - -```python -with open("wikitext-2.txt", "w", encoding="utf-8") as f: - for i in range(len(dataset)): - f.write(dataset[i]["text"] + "\n") -``` - -Далее мы покажем вам, как блок за блоком построить собственные токенизаторы BERT, GPT-2 и XLNet. Это даст нам пример каждого из трех основных алгоритмов токенизации: WordPiece, BPE и Unigram. Начнем с BERT! - -## Создание токенизатора WordPiece с нуля[[building-a-wordpiece-tokenizer-from-scratch]] - -Чтобы создать токенизатор с помощью библиотеки 🤗 Tokenizers, мы начнем с инстанцирования объектов `Tokenizer` и `model`, затем установим для их атрибутов `normalizer`, `pre_tokenizer`, `post_processor` и `decoder` нужные нам значения. - -Для этого примера мы создадим `Tokenizer` с моделью WordPiece: - -```python -from tokenizers import ( - decoders, - models, - normalizers, - pre_tokenizers, - processors, - trainers, - Tokenizer, -) - -tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) -``` - -Мы должны указать `unk_token`, чтобы модель знала, что возвращать, когда она встречает символы, которых раньше не видела. Другие аргументы, которые мы можем задать здесь, включают `vocab` нашей модели (мы собираемся обучать модель, поэтому нам не нужно его задавать) и `max_input_chars_per_word`, который определяет максимальную длину для каждого слова (слова длиннее переданного значения будут разбиты на части). - -Первым шагом токенизации является нормализация, поэтому начнем с нее. Поскольку BERT широко используется, существует `BertNormalizer` с классическими параметрами, которые мы можем установить для BERT: `lowercase` и `strip_accents`, которые не требуют пояснений; `clean_text` для удаления всех управляющих символов и замены повторяющихся пробелов на один; и `handle_chinese_chars`, который расставляет пробелы вокруг китайских символов. Чтобы повторить токенизатор `bert-base-uncased`, мы можем просто установить этот нормализатор: - -```python -tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) -``` - -Однако, как правило, при создании нового токенизатора у вас не будет доступа к такому удобному нормализатору, уже реализованному в библиотеке 🤗 Tokenizers, поэтому давайте посмотрим, как создать нормализатор BERT вручную. Библиотека предоставляет нормализатор `Lowercase` и нормализатор `StripAccents`, и вы можете комбинировать несколько нормализаторов с помощью `Sequence`: - -```python -tokenizer.normalizer = normalizers.Sequence( - [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()] -) -``` - -Мы также используем нормализатор Unicode `NFD`, поскольку в противном случае нормализатор `StripAccents` не сможет правильно распознать акцентированные символы и, следовательно, не удалит их. - -Как мы уже видели ранее, мы можем использовать метод `normalize_str()` нормализатора, чтобы проверить, как он влияет на данный текст: - -```python -print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) -``` - -```python out -hello how are u? -``` - - - -**Далее** если вы протестируете две версии предыдущих нормализаторов на строке, содержащей символ Unicode `u"\u0085"`, то наверняка заметите, что эти два нормализатора не совсем эквивалентны. -Чтобы не усложнять версию с `normalizers.Sequence`, мы не включили в нее Regex-замены, которые требует `BertNormalizer`, когда аргумент `clean_text` установлен в `True`, что является поведением по умолчанию. Но не волнуйтесь: можно получить точно такую же нормализацию без использования удобного `BertNormalizer`, добавив два `normalizers.Replace` в последовательность нормализаторов. - - - -Далее следует этап предварительной токенизации. Опять же, есть готовый `BertPreTokenizer`, который мы можем использовать: - -```python -tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() -``` - -Или мы можем создать его с нуля: - -```python -tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() -``` - -Обратите внимание, что токенизатор `Whitespace` разделяет пробельные символы и все символы, которые не являются буквами, цифрами или символом подчеркивания, поэтому технически он разделяет пробельные символы и знаки пунктуации: - -```python -tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") -``` - -```python out -[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), - ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] -``` - -Если вы хотите выполнять разделение только по пробельным символам, то вместо этого следует использовать предварительный токенизатор `WhitespaceSplit`: - -```python -pre_tokenizer = pre_tokenizers.WhitespaceSplit() -pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") -``` - -```python out -[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] -``` - -Как и в случае с нормализаторами, вы можете использовать `Sequence` для комбинирования нескольких предварительных токенизаторов: - -```python -pre_tokenizer = pre_tokenizers.Sequence( - [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()] -) -pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") -``` - -```python out -[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), - ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] -``` - -Следующий шаг в конвейере токенизации - обработка входных данных с помощью модели. Мы уже указали нашу модель в инициализации, но нам все еще нужно обучить ее, для чего потребуется `WordPieceTrainer`. Главное, что нужно помнить при инстанцировании тренера в 🤗 Tokenizers, это то, что вам нужно передать ему все специальные токены, которые вы собираетесь использовать - иначе он не добавит их в словарь, поскольку их нет в обучающем корпусе: - -```python -special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] -trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) -``` - -Помимо указания `vocab_size` и `special_tokens`, мы можем задать `min_frequency` (количество раз, которое должен встретиться токен, чтобы быть включенным в словарь) или изменить `continuing_subword_prefix` (если мы хотим использовать что-то отличное от `##`). - -Чтобы обучить нашу модель с помощью итератора, который мы определили ранее, достаточно выполнить эту команду: - -```python -tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) -``` - -Мы также можем использовать текстовые файлы для обучения нашего токенизатора, что будет выглядеть следующим образом (предварительно мы повторно инициализируем модель с пустым `WordPiece`): - -```python -tokenizer.model = models.WordPiece(unk_token="[UNK]") -tokenizer.train(["wikitext-2.txt"], trainer=trainer) -``` - -В обоих случаях мы можем проверить работу токенизатора на тексте, вызвав метод `encode()`: - -```python -encoding = tokenizer.encode("Let's test this tokenizer.") -print(encoding.tokens) -``` - -```python out -['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] -``` - -Полученное `encoding` представляет собой `Encoding`, которое содержит все необходимые результаты работы токенизатора в разных атрибутах: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask` и `overflowing`. - -Последний шаг в конвейере токенизации - постобработка. Нам нужно добавить токен `[CLS]` в начале и токен `[SEP]` в конце (или после каждого предложения, если у нас есть пара предложений). Для этого мы будем использовать `TemplateProcessor`, но сначала нам нужно узнать идентификаторы токенов `[CLS]` и `[SEP]` в словаре: - -```python -cls_token_id = tokenizer.token_to_id("[CLS]") -sep_token_id = tokenizer.token_to_id("[SEP]") -print(cls_token_id, sep_token_id) -``` - -```python out -(2, 3) -``` - -Чтобы написать шаблон для `TemplateProcessor`, мы должны указать, как обрабатывать одно предложение и пару предложений. Для обоих случаев мы указываем специальные токены, которые мы хотим использовать; первое (или одиночное) предложение представлено `$A`, а второе предложение (если кодируется пара) представлено `$B`. Для каждого из них (специальных токенов и предложений) мы также указываем соответствующий идентификатор типа токена (token type ID) после двоеточия. - -Таким образом, классический шаблон BERT определяется следующим образом: - -```python -tokenizer.post_processor = processors.TemplateProcessing( - single=f"[CLS]:0 $A:0 [SEP]:0", - pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1", - special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)], -) -``` - -Обратите внимание, что нам нужно передать идентификаторы специальных токенов, чтобы токенизатор мог правильно преобразовать их в их идентификаторы. - -Как только это будет добавлено, вернемся к нашему предыдущему примеру: - -```python -encoding = tokenizer.encode("Let's test this tokenizer.") -print(encoding.tokens) -``` - -```python out -['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] -``` - -И на паре предложений мы получаем правильный результат: - -```python -encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") -print(encoding.tokens) -print(encoding.type_ids) -``` - -```python out -['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]'] -[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] -``` - -Мы почти закончили создание этого токенизатора с нуля - остался последний шаг - добавить декодер: - -```python -tokenizer.decoder = decoders.WordPiece(prefix="##") -``` - -Давайте проверим его на нашем предыдущем `encoding`: - -```python -tokenizer.decode(encoding.ids) -``` - -```python out -"let's test this tokenizer... on a pair of sentences." -``` - -Отлично! Мы можем сохранить наш токенизатор в единственном JSON-файле следующим образом: - -```python -tokenizer.save("tokenizer.json") -``` - -Затем мы можем загрузить этот файл в объект `Tokenizer` с помощью метода `from_file()`: - -```python -new_tokenizer = Tokenizer.from_file("tokenizer.json") -``` - -Чтобы использовать этот токенизатор в 🤗 Transformers, мы должны обернуть его в `PreTrainedTokenizerFast`. Мы можем использовать либо общий класс, либо, если наш токенизатор соответствует существующей модели, использовать этот класс (здесь `BertTokenizerFast`). Если вы используете этот урок для создания нового токенизатора, вам придется использовать первый вариант. - -Чтобы обернуть токенизатор в `PreTrainedTokenizerFast`, мы можем либо передать собранный нами токенизатор как `tokenizer_object`, либо передать сохраненный файл токенизатора как `tokenizer_file`. Главное помнить, что нам придется вручную задавать все специальные токены, поскольку класс не может определить из объекта `tokenizer`, какой токен является токеном маски, токеном `[CLS]` и т. д.: - -```python -from transformers import PreTrainedTokenizerFast - -wrapped_tokenizer = PreTrainedTokenizerFast( - tokenizer_object=tokenizer, - # tokenizer_file="tokenizer.json", # В качестве альтернативы можно загрузить из файла токенизатора. - unk_token="[UNK]", - pad_token="[PAD]", - cls_token="[CLS]", - sep_token="[SEP]", - mask_token="[MASK]", -) -``` - -Если вы используете определенный класс токенизатора (например, `BertTokenizerFast`), вам нужно будет указать только специальные токены, которые отличаются от токенов по умолчанию (здесь их нет): - -```python -from transformers import BertTokenizerFast - -wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) -``` - -Затем вы можете использовать этот токенизатор, как и любой другой 🤗 токенизатор Transformers. Вы можете сохранить его с помощью метода `save_pretrained()` или загрузить на хаб с помощью метода `push_to_hub()`. - -Теперь, когда мы рассмотрели, как создать токенизатор WordPiece, давайте сделаем то же самое для токенизатора BPE. Мы будем двигаться немного быстрее, поскольку вы знаете все шаги, и подчеркнем только различия. - -## Создание токенизатора BPE с нуля[[building-a-bpe-tokenizer-from-scratch]] - -Теперь давайте создадим токенизатор GPT-2. Как и в случае с токенизатором BERT, мы начнем с инициализации `Tokenizer` с моделью BPE: - -```python -tokenizer = Tokenizer(models.BPE()) -``` - -Also like for BERT, we could initialize this model with a vocabulary if we had one (we would need to pass the `vocab` and `merges` in this case), but since we will train from scratch, we don't need to do that. We also don't need to specify an `unk_token` because GPT-2 uses byte-level BPE, which doesn't require it. - -GPT-2 does not use a normalizer, so we skip that step and go directly to the pre-tokenization: - -```python -tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) -``` - -The option we added to `ByteLevel` here is to not add a space at the beginning of a sentence (which is the default otherwise). We can have a look at the pre-tokenization of an example text like before: - -```python -tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") -``` - -```python out -[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)), - ('tokenization', (15, 27)), ('!', (27, 28))] -``` - -Next is the model, which needs training. For GPT-2, the only special token is the end-of-text token: - -```python -trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) -tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) -``` - -Like with the `WordPieceTrainer`, as well as the `vocab_size` and `special_tokens`, we can specify the `min_frequency` if we want to, or if we have an end-of-word suffix (like ``), we can set it with `end_of_word_suffix`. - -This tokenizer can also be trained on text files: - -```python -tokenizer.model = models.BPE() -tokenizer.train(["wikitext-2.txt"], trainer=trainer) -``` - -Let's have a look at the tokenization of a sample text: - -```python -encoding = tokenizer.encode("Let's test this tokenizer.") -print(encoding.tokens) -``` - -```python out -['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] -``` - -We apply the byte-level post-processing for the GPT-2 tokenizer as follows: - -```python -tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) -``` - -The `trim_offsets = False` option indicates to the post-processor that we should leave the offsets of tokens that begin with 'Ġ' as they are: this way the start of the offsets will point to the space before the word, not the first character of the word (since the space is technically part of the token). Let's have a look at the result with the text we just encoded, where `'Ġtest'` is the token at index 4: - -```python -sentence = "Let's test this tokenizer." -encoding = tokenizer.encode(sentence) -start, end = encoding.offsets[4] -sentence[start:end] -``` - -```python out -' test' -``` - -Finally, we add a byte-level decoder: - -```python -tokenizer.decoder = decoders.ByteLevel() -``` - -and we can double-check it works properly: - -```python -tokenizer.decode(encoding.ids) -``` - -```python out -"Let's test this tokenizer." -``` - -Great! Now that we're done, we can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `GPT2TokenizerFast` if we want to use it in 🤗 Transformers: - -```python -from transformers import PreTrainedTokenizerFast - -wrapped_tokenizer = PreTrainedTokenizerFast( - tokenizer_object=tokenizer, - bos_token="<|endoftext|>", - eos_token="<|endoftext|>", -) -``` - -or: - -```python -from transformers import GPT2TokenizerFast - -wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) -``` - -As the last example, we'll show you how to build a Unigram tokenizer from scratch. - -## Building a Unigram tokenizer from scratch[[building-a-unigram-tokenizer-from-scratch]] - -Let's now build an XLNet tokenizer. Like for the previous tokenizers, we start by initializing a `Tokenizer` with a Unigram model: - -```python -tokenizer = Tokenizer(models.Unigram()) -``` - -Again, we could initialize this model with a vocabulary if we had one. - -For the normalization, XLNet uses a few replacements (which come from SentencePiece): - -```python -from tokenizers import Regex - -tokenizer.normalizer = normalizers.Sequence( - [ - normalizers.Replace("``", '"'), - normalizers.Replace("''", '"'), - normalizers.NFKD(), - normalizers.StripAccents(), - normalizers.Replace(Regex(" {2,}"), " "), - ] -) -``` - -This replaces `` and '' with " and any sequence of two or more spaces with a single space, as well as removing the accents in the texts to tokenize. - -The pre-tokenizer to use for any SentencePiece tokenizer is `Metaspace`: - -```python -tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() -``` - -We can have a look at the pre-tokenization of an example text like before: - -```python -tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") -``` - -```python out -[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] -``` - -Next is the model, which needs training. XLNet has quite a few special tokens: - -```python -special_tokens = ["", "", "", "", "", "", ""] -trainer = trainers.UnigramTrainer( - vocab_size=25000, special_tokens=special_tokens, unk_token="" -) -tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) -``` - -A very important argument not to forget for the `UnigramTrainer` is the `unk_token`. We can also pass along other arguments specific to the Unigram algorithm, such as the `shrinking_factor` for each step where we remove tokens (defaults to 0.75) or the `max_piece_length` to specify the maximum length of a given token (defaults to 16). - -This tokenizer can also be trained on text files: - -```python -tokenizer.model = models.Unigram() -tokenizer.train(["wikitext-2.txt"], trainer=trainer) -``` - -Let's have a look at the tokenization of a sample text: - -```python -encoding = tokenizer.encode("Let's test this tokenizer.") -print(encoding.tokens) -``` - -```python out -['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] -``` - -A peculiarity of XLNet is that it puts the `` token at the end of the sentence, with a type ID of 2 (to distinguish it from the other tokens). It's padding on the left, as a result. We can deal with all the special tokens and token type IDs with a template, like for BERT, but first we have to get the IDs of the `` and `` tokens: - -```python -cls_token_id = tokenizer.token_to_id("") -sep_token_id = tokenizer.token_to_id("") -print(cls_token_id, sep_token_id) -``` - -```python out -0 1 -``` - -The template looks like this: - -```python -tokenizer.post_processor = processors.TemplateProcessing( - single="$A:0 :0 :2", - pair="$A:0 :0 $B:1 :1 :2", - special_tokens=[("", sep_token_id), ("", cls_token_id)], -) -``` - -And we can test it works by encoding a pair of sentences: - -```python -encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") -print(encoding.tokens) -print(encoding.type_ids) -``` - -```python out -['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '', '▁', 'on', '▁', 'a', '▁pair', - '▁of', '▁sentence', 's', '!', '', ''] -[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] -``` - -Finally, we add a `Metaspace` decoder: - -```python -tokenizer.decoder = decoders.Metaspace() -``` - -and we're done with this tokenizer! We can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `XLNetTokenizerFast` if we want to use it in 🤗 Transformers. One thing to note when using `PreTrainedTokenizerFast` is that on top of the special tokens, we need to tell the 🤗 Transformers library to pad on the left: - -```python -from transformers import PreTrainedTokenizerFast - -wrapped_tokenizer = PreTrainedTokenizerFast( - tokenizer_object=tokenizer, - bos_token="", - eos_token="", - unk_token="", - pad_token="", - cls_token="", - sep_token="", - mask_token="", - padding_side="left", -) -``` - -Or alternatively: - -```python -from transformers import XLNetTokenizerFast - -wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) -``` - -Now that you have seen how the various building blocks are used to build existing tokenizers, you should be able to write any tokenizer you want with the 🤗 Tokenizers library and be able to use it in 🤗 Transformers. diff --git a/chapters/ru/chapter6/10.mdx b/chapters/ru/chapter6/10.mdx index e1d55634d..5199cf774 100644 --- a/chapters/ru/chapter6/10.mdx +++ b/chapters/ru/chapter6/10.mdx @@ -1,283 +1,282 @@ -# End-of-chapter quiz[[end-of-chapter-quiz]] +# Тест в конце главы[[end-of-chapter-quiz]] -Let's test what you learned in this chapter! +Давайте проверим, чему вы научились в этой главе! -### 1. When should you train a new tokenizer? +### 1. Когда следует обучать новый токенизатор? -### 2. What is the advantage of using a generator of lists of texts compared to a list of lists of texts when using `train_new_from_iterator()`? +### 2. В чем преимущество использования генератора списков текстов по сравнению со списком списков текстов при использовании `train_new_from_iterator()`? train_new_from_iterator() accepts.", - explain: "A list of lists of texts is a particular kind of generator of lists of texts, so the method will accept this too. Try again!" + text: "Это единственный тип, который принимает метод train_new_from_iterator().", + explain: "Список списков текстов - это особый вид генератора списков текстов, поэтому метод примет и его. Попробуйте еще раз!" }, { - text: "You will avoid loading the whole dataset into memory at once.", - explain: "Right! Each batch of texts will be released from memory when you iterate, and the gain will be especially visible if you use 🤗 Datasets to store your texts.", + text: "Это позволит избежать загрузки в память сразу всего набора данных.", + explain: "Точно! Каждый батч текстов будет освобождаться из памяти при итерации, и выигрыш будет особенно заметен, если вы используете библиотеку 🤗 Datasets для хранения текстов.", correct: true }, { - text: "This will allow the 🤗 Tokenizers library to use multiprocessing.", - explain: "No, it will use multiprocessing either way." + text: "Это позволит библиотеке 🤗 Tokenizers использовать многопроцессорность (multiprocessing).", + explain: "Нет, она будет использовать многопроцессорность в любом случае." }, { - text: "The tokenizer you train will generate better texts.", - explain: "The tokenizer does not generate text -- are you confusing it with a language model?" + text: "Обученный вами токенизатор будет генерировать более качественные тексты.", + explain: "Токенизатор не генерирует текст - вы не путаете его с языковой моделью?" } ]} /> -### 3. What are the advantages of using a "fast" tokenizer? +### 3. Каковы преимущества использования "быстрого" токенизатора? -### 4. How does the `token-classification` pipeline handle entities that span over several tokens? +### 4. Как конвейер `token-classification` обрабатывает сущности, которые охватывают несколько токенов? -### 5. How does the `question-answering` pipeline handle long contexts? +### 5. Как конвейер `question-answering` обрабатывает длинные контексты? -### 6. What is normalization? +### 6. Что такое нормализация? -### 7. What is pre-tokenization for a subword tokenizer? +### 7. Что такое предварительная токенизация для токенизатора по подсловам? -### 8. Select the sentences that apply to the BPE model of tokenization. +### 8. Выберите предложения, которые относятся к модели токенизации BPE. -### 9. Select the sentences that apply to the WordPiece model of tokenization. +### 9. Выберите предложения, которые относятся к модели токенизации WordPiece. -### 10. Select the sentences that apply to the Unigram model of tokenization. +### 10. Выберите предложения, которые относятся к модели токенизации Unigram. diff --git a/chapters/ru/chapter6/8.mdx b/chapters/ru/chapter6/8.mdx index 9a7367458..191e1d2f4 100644 --- a/chapters/ru/chapter6/8.mdx +++ b/chapters/ru/chapter6/8.mdx @@ -305,7 +305,7 @@ from transformers import BertTokenizerFast wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) ``` -Затем вы можете использовать этот токенизатор, как и любой другой 🤗 токенизатор Transformers. Вы можете сохранить его с помощью метода `save_pretrained()` или загрузить на хаб с помощью метода `push_to_hub()`. +Затем вы можете использовать этот токенизатор, как и любой другой токенизатор 🤗 Transformers. Вы можете сохранить его с помощью метода `save_pretrained()` или загрузить на хаб с помощью метода `push_to_hub()`. Теперь, когда мы рассмотрели, как создать токенизатор WordPiece, давайте сделаем то же самое для токенизатора BPE. Мы будем двигаться немного быстрее, поскольку вы знаете все шаги, и подчеркнем только различия. @@ -317,15 +317,15 @@ wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) tokenizer = Tokenizer(models.BPE()) ``` -Also like for BERT, we could initialize this model with a vocabulary if we had one (we would need to pass the `vocab` and `merges` in this case), but since we will train from scratch, we don't need to do that. We also don't need to specify an `unk_token` because GPT-2 uses byte-level BPE, which doesn't require it. +Также, как и в случае с BERT, мы могли бы инициализировать эту модель словарем, если бы он у нас был (в этом случае нам нужно было бы передать `vocab` и `merges`), но поскольку мы будем обучать с нуля, нам не нужно этого делать. Нам также не нужно указывать `unk_token`, потому что GPT-2 использует byte-level BPE, который не требует этого. -GPT-2 does not use a normalizer, so we skip that step and go directly to the pre-tokenization: +GPT-2 не использует нормализатор, поэтому мы пропускаем этот шаг и переходим непосредственно к предварительной токенизации: ```python tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) ``` -The option we added to `ByteLevel` here is to not add a space at the beginning of a sentence (which is the default otherwise). We can have a look at the pre-tokenization of an example text like before: +Опция, которую мы добавили к `ByteLevel`, заключается в том, чтобы не добавлять пробел в начале предложения (в противном случае это происходит по умолчанию). Мы можем посмотреть на предварительную токенизацию примера текста, как было показано ранее: ```python tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") @@ -336,23 +336,23 @@ tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") ('tokenization', (15, 27)), ('!', (27, 28))] ``` -Next is the model, which needs training. For GPT-2, the only special token is the end-of-text token: +Далее следует модель, которую нужно обучить. Для GPT-2 единственным специальным токеном является токен конца текста: ```python trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) ``` -Like with the `WordPieceTrainer`, as well as the `vocab_size` and `special_tokens`, we can specify the `min_frequency` if we want to, or if we have an end-of-word suffix (like ``), we can set it with `end_of_word_suffix`. +Как и в случае с `WordPieceTrainer`, а также `vocab_size` и `special_tokens`, мы можем указать `min_frequency`, если хотим, или если у нас есть суффикс конца слова (например, ``), мы можем задать его с помощью `end_of_word_suffix`. -This tokenizer can also be trained on text files: +Этот токенизатор также может быть обучен на текстовых файлах: ```python tokenizer.model = models.BPE() tokenizer.train(["wikitext-2.txt"], trainer=trainer) ``` -Let's have a look at the tokenization of a sample text: +Давайте посмотрим на пример токенизации текста: ```python encoding = tokenizer.encode("Let's test this tokenizer.") @@ -363,13 +363,13 @@ print(encoding.tokens) ['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] ``` -We apply the byte-level post-processing for the GPT-2 tokenizer as follows: +Мы применяем постобработку на уровне байтов для токенизатора GPT-2 следующим образом: ```python tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) ``` -The `trim_offsets = False` option indicates to the post-processor that we should leave the offsets of tokens that begin with 'Ġ' as they are: this way the start of the offsets will point to the space before the word, not the first character of the word (since the space is technically part of the token). Let's have a look at the result with the text we just encoded, where `'Ġtest'` is the token at index 4: +Опция `trim_offsets = False` указывает постпроцессору, что мы должны оставить смещения токенов, начинающихся с 'Ġ', как есть: таким образом, начало смещения будет указывать на пробел перед словом, а не на первый символ слова (поскольку пробел технически является частью токена). Давайте посмотрим на результат с текстом, который мы только что закодировали, где `'Ġtest'` - это токен с индексом 4: ```python sentence = "Let's test this tokenizer." @@ -382,13 +382,13 @@ sentence[start:end] ' test' ``` -Finally, we add a byte-level decoder: +Наконец, мы добавляем декодер на уровне байтов: ```python tokenizer.decoder = decoders.ByteLevel() ``` -and we can double-check it works properly: +и мы сможем перепроверить, правильно ли он работает: ```python tokenizer.decode(encoding.ids) @@ -398,7 +398,7 @@ tokenizer.decode(encoding.ids) "Let's test this tokenizer." ``` -Great! Now that we're done, we can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `GPT2TokenizerFast` if we want to use it in 🤗 Transformers: +Отлично! Теперь, когда мы закончили, мы можем сохранить токенизатор, как раньше, и обернуть его в `PreTrainedTokenizerFast` или `GPT2TokenizerFast`, если мы хотим использовать его в 🤗 Transformers: ```python from transformers import PreTrainedTokenizerFast @@ -410,7 +410,7 @@ wrapped_tokenizer = PreTrainedTokenizerFast( ) ``` -or: +или: ```python from transformers import GPT2TokenizerFast @@ -418,19 +418,19 @@ from transformers import GPT2TokenizerFast wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) ``` -As the last example, we'll show you how to build a Unigram tokenizer from scratch. +В качестве последнего примера мы покажем вам, как создать токенизатор Unigram с нуля. -## Building a Unigram tokenizer from scratch[[building-a-unigram-tokenizer-from-scratch]] +## Создание токенизатора Unigram с нуля[[building-a-unigram-tokenizer-from-scratch]] -Let's now build an XLNet tokenizer. Like for the previous tokenizers, we start by initializing a `Tokenizer` with a Unigram model: +Теперь давайте построим токенизатор XLNet. Как и в предыдущих токенизаторах, мы начнем с инициализации `Tokenizer` с моделью Unigram: ```python tokenizer = Tokenizer(models.Unigram()) ``` -Again, we could initialize this model with a vocabulary if we had one. +Опять же, мы могли бы инициализировать эту модель словарем, если бы он у нас был. -For the normalization, XLNet uses a few replacements (which come from SentencePiece): +Для нормализации XLNet использует несколько замен (которые пришли из SentencePiece): ```python from tokenizers import Regex @@ -446,15 +446,15 @@ tokenizer.normalizer = normalizers.Sequence( ) ``` -This replaces `` and '' with " and any sequence of two or more spaces with a single space, as well as removing the accents in the texts to tokenize. +Он заменяет `` и '' with " и любую последовательность из двух или более пробелов на один пробел, а также удаляет ударения в токенезируемых текстах. -The pre-tokenizer to use for any SentencePiece tokenizer is `Metaspace`: +Предварительный токенизатор, который должен использоваться для любого токенизатора SentencePiece, - это `Metaspace`: ```python tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() ``` -We can have a look at the pre-tokenization of an example text like before: +Мы можем посмотреть на предварительную токенизацию примера текста, как было показано ранее: ```python tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") @@ -464,7 +464,7 @@ tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") [("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] ``` -Next is the model, which needs training. XLNet has quite a few special tokens: +Далее следует модель, которую нужно обучить. В XLNet довольно много специальных токенов: ```python special_tokens = ["", "", "", "", "", "", ""] @@ -473,17 +473,15 @@ trainer = trainers.UnigramTrainer( ) tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) ``` +Очень важный аргумент, который не стоит забывать для `UnigramTrainer` - это `unk_token`. Мы также можем передавать другие аргументы, специфичные для алгоритма Unigram, такие как `shrinking_factor` для каждого шага удаления токенов (по умолчанию 0.75) или `max_piece_length` для указания максимальной длины данного токена (по умолчанию 16). -A very important argument not to forget for the `UnigramTrainer` is the `unk_token`. We can also pass along other arguments specific to the Unigram algorithm, such as the `shrinking_factor` for each step where we remove tokens (defaults to 0.75) or the `max_piece_length` to specify the maximum length of a given token (defaults to 16). - -This tokenizer can also be trained on text files: +Этот токенизатор также может быть обучен на текстовых файлах: ```python tokenizer.model = models.Unigram() tokenizer.train(["wikitext-2.txt"], trainer=trainer) ``` - -Let's have a look at the tokenization of a sample text: +Давайте посмотрим на токенизацию примера текста: ```python encoding = tokenizer.encode("Let's test this tokenizer.") @@ -494,7 +492,7 @@ print(encoding.tokens) ['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] ``` -A peculiarity of XLNet is that it puts the `` token at the end of the sentence, with a type ID of 2 (to distinguish it from the other tokens). It's padding on the left, as a result. We can deal with all the special tokens and token type IDs with a template, like for BERT, but first we have to get the IDs of the `` and `` tokens: +Особенностью XLNet является то, что он помещает токен `` в конец предложения с идентификатором типа 2 (чтобы отличить его от других токенов). В результате он помещается слева. Мы можем разобраться со всеми специальными токенами и идентификаторами типов токенов с помощью шаблона, как в BERT, но сначала нам нужно получить идентификаторы токенов `` и ``: ```python cls_token_id = tokenizer.token_to_id("") @@ -506,7 +504,7 @@ print(cls_token_id, sep_token_id) 0 1 ``` -The template looks like this: +Шаблон выглядит следующим образом: ```python tokenizer.post_processor = processors.TemplateProcessing( @@ -516,7 +514,7 @@ tokenizer.post_processor = processors.TemplateProcessing( ) ``` -And we can test it works by encoding a pair of sentences: +И мы можем проверить, как это работает, закодировав пару предложений: ```python encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") @@ -530,13 +528,13 @@ print(encoding.type_ids) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] ``` -Finally, we add a `Metaspace` decoder: +Наконец, мы добавляем декодер `Metaspace`: ```python tokenizer.decoder = decoders.Metaspace() ``` -and we're done with this tokenizer! We can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `XLNetTokenizerFast` if we want to use it in 🤗 Transformers. One thing to note when using `PreTrainedTokenizerFast` is that on top of the special tokens, we need to tell the 🤗 Transformers library to pad on the left: +и мы закончили работу с этим токенизатором! Мы можем сохранить токенизатор, как и раньше, и обернуть его в `PreTrainedTokenizerFast` или `XLNetTokenizerFast`, если мы хотим использовать его в 🤗 Transformers. При использовании `PreTrainedTokenizerFast` следует обратить внимание на то, что помимо специальных токенов, нам нужно указать библиотеке 🤗 Transformers на то, чтобы они располагались слева: ```python from transformers import PreTrainedTokenizerFast @@ -554,7 +552,7 @@ wrapped_tokenizer = PreTrainedTokenizerFast( ) ``` -Or alternatively: +Или альтернативно: ```python from transformers import XLNetTokenizerFast @@ -562,4 +560,4 @@ from transformers import XLNetTokenizerFast wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) ``` -Now that you have seen how the various building blocks are used to build existing tokenizers, you should be able to write any tokenizer you want with the 🤗 Tokenizers library and be able to use it in 🤗 Transformers. +Теперь, когда вы увидели, как различные блоки используются для создания существующих токенизаторов, вы должны быть в состоянии написать любой токенизатор, который вы хотите, с помощью библиотеки 🤗 Tokenizers и использовать его в 🤗 Transformers. diff --git a/chapters/ru/chapter6/9.mdx b/chapters/ru/chapter6/9.mdx index 288c4864b..da0adfb0a 100644 --- a/chapters/ru/chapter6/9.mdx +++ b/chapters/ru/chapter6/9.mdx @@ -1,16 +1,16 @@ -# Tokenizers, check![[tokenizers-check]] +# Токенизаторы, проверка![[tokenizers-check]] -Great job finishing this chapter! +Отличная работа по завершению этой главы! -After this deep dive into tokenizers, you should: +После этого глубокого погружения в токенизаторы вы должны: -- Be able to train a new tokenizer using an old one as a template -- Understand how to use offsets to map tokens' positions to their original span of text -- Know the differences between BPE, WordPiece, and Unigram -- Be able to mix and match the blocks provided by the 🤗 Tokenizers library to build your own tokenizer -- Be able to use that tokenizer inside the 🤗 Transformers library +- Уметь обучать новый токенизатор, используя старый в качестве шаблона. +- Понимать, как использовать смещения для сопоставления позиций токенов с их исходным положением в тексте +- Знать различия между BPE, WordPiece и Unigram. +- Уметь комбинировать блоки, предоставляемые библиотекой 🤗 Tokenizers, для создания собственного токенизатора +- Уметь использовать собственный токенизатор в библиотеке 🤗 Transformers From 2be3db1252105d9ca2fcd9a32f3531fb7aa0546c Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:57:15 +0300 Subject: [PATCH 307/502] Delete chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml This is backup created by JupyterLab. --- .../_toctree-checkpoint.yml | 201 ------------------ 1 file changed, 201 deletions(-) delete mode 100644 chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml diff --git a/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml deleted file mode 100644 index c8364cc6d..000000000 --- a/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml +++ /dev/null @@ -1,201 +0,0 @@ -- title: 0. Setup - sections: - - local: chapter0/1 - title: Introduction - -- title: 1. Transformer models - sections: - - local: chapter1/1 - title: Introduction - - local: chapter1/2 - title: Natural Language Processing - - local: chapter1/3 - title: Transformers, what can they do? - - local: chapter1/4 - title: How do Transformers work? - - local: chapter1/5 - title: Encoder models - - local: chapter1/6 - title: Decoder models - - local: chapter1/7 - title: Sequence-to-sequence models - - local: chapter1/8 - title: Bias and limitations - - local: chapter1/9 - title: Summary - - local: chapter1/10 - title: End-of-chapter quiz - quiz: 1 - -- title: 2. Using 🤗 Transformers - sections: - - local: chapter2/1 - title: Introduction - - local: chapter2/2 - title: Behind the pipeline - - local: chapter2/3 - title: Models - - local: chapter2/4 - title: Tokenizers - - local: chapter2/5 - title: Handling multiple sequences - - local: chapter2/6 - title: Putting it all together - - local: chapter2/7 - title: Basic usage completed! - - local: chapter2/8 - title: End-of-chapter quiz - quiz: 2 - -- title: 3. Fine-tuning a pretrained model - sections: - - local: chapter3/1 - title: Introduction - - local: chapter3/2 - title: Processing the data - - local: chapter3/3 - title: Fine-tuning a model with the Trainer API or Keras - local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - - local: chapter3/4 - title: A full training - - local: chapter3/5 - title: Fine-tuning, Check! - - local: chapter3/6 - title: End-of-chapter quiz - quiz: 3 - -- title: 4. Sharing models and tokenizers - sections: - - local: chapter4/1 - title: The Hugging Face Hub - - local: chapter4/2 - title: Using pretrained models - - local: chapter4/3 - title: Sharing pretrained models - - local: chapter4/4 - title: Building a model card - - local: chapter4/5 - title: Part 1 completed! - - local: chapter4/6 - title: End-of-chapter quiz - quiz: 4 - -- title: 5. The 🤗 Datasets library - sections: - - local: chapter5/1 - title: Introduction - - local: chapter5/2 - title: What if my dataset isn't on the Hub? - - local: chapter5/3 - title: Time to slice and dice - - local: chapter5/4 - title: Big data? 🤗 Datasets to the rescue! - - local: chapter5/5 - title: Creating your own dataset - - local: chapter5/6 - title: Semantic search with FAISS - - local: chapter5/7 - title: 🤗 Datasets, check! - - local: chapter5/8 - title: End-of-chapter quiz - quiz: 5 - -- title: 6. The 🤗 Tokenizers library - sections: - - local: chapter6/1 - title: Introduction - - local: chapter6/2 - title: Training a new tokenizer from an old one - - local: chapter6/3 - title: Fast tokenizers' special powers - - local: chapter6/3b - title: Fast tokenizers in the QA pipeline - - local: chapter6/4 - title: Normalization and pre-tokenization - - local: chapter6/5 - title: Byte-Pair Encoding tokenization - - local: chapter6/6 - title: WordPiece tokenization - - local: chapter6/7 - title: Unigram tokenization - - local: chapter6/8 - title: Building a tokenizer, block by block - - local: chapter6/9 - title: Tokenizers, check! - - local: chapter6/10 - title: End-of-chapter quiz - quiz: 6 - -- title: 7. Main NLP tasks - sections: - - local: chapter7/1 - title: Introduction - - local: chapter7/2 - title: Token classification - - local: chapter7/3 - title: Fine-tuning a masked language model - - local: chapter7/4 - title: Translation - - local: chapter7/5 - title: Summarization - - local: chapter7/6 - title: Training a causal language model from scratch - - local: chapter7/7 - title: Question answering - - local: chapter7/8 - title: Mastering NLP - - local: chapter7/9 - title: End-of-chapter quiz - quiz: 7 - -- title: 8. How to ask for help - sections: - - local: chapter8/1 - title: Introduction - - local: chapter8/2 - title: What to do when you get an error - - local: chapter8/3 - title: Asking for help on the forums - - local: chapter8/4 - title: Debugging the training pipeline - local_fw: { pt: chapter8/4, tf: chapter8/4_tf } - - local: chapter8/5 - title: How to write a good issue - - local: chapter8/6 - title: Part 2 completed! - - local: chapter8/7 - title: End-of-chapter quiz - quiz: 8 - -- title: 9. Building and sharing demos - new: true - subtitle: I trained a model, but how can I show it off? - sections: - - local: chapter9/1 - title: Introduction to Gradio - - local: chapter9/2 - title: Building your first demo - - local: chapter9/3 - title: Understanding the Interface class - - local: chapter9/4 - title: Sharing demos with others - - local: chapter9/5 - title: Integrations with the Hugging Face Hub - - local: chapter9/6 - title: Advanced Interface features - - local: chapter9/7 - title: Introduction to Blocks - - local: chapter9/8 - title: Gradio, check! - - local: chapter9/9 - title: End-of-chapter quiz - quiz: 9 - -- title: Course Events - sections: - - local: events/1 - title: Live sessions and workshops - - local: events/2 - title: Part 2 release event - - local: events/3 - title: Gradio Blocks party From 32c9ad09bbed846f5dd31a880bb689c92b9c5d14 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:57:43 +0300 Subject: [PATCH 308/502] Delete chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx This is backup created by JupyterLab. --- .../.ipynb_checkpoints/8-checkpoint.mdx | 231 ------------------ 1 file changed, 231 deletions(-) delete mode 100644 chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx diff --git a/chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx b/chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx deleted file mode 100644 index 27addf6b6..000000000 --- a/chapters/en/chapter5/.ipynb_checkpoints/8-checkpoint.mdx +++ /dev/null @@ -1,231 +0,0 @@ - - -# End-of-chapter quiz[[end-of-chapter-quiz]] - - - -This chapter covered a lot of ground! Don't worry if you didn't grasp all the details; the next chapters will help you understand how things work under the hood. - -Before moving on, though, let's test what you learned in this chapter. - -### 1. The `load_dataset()` function in 🤗 Datasets allows you to load a dataset from which of the following locations? - -data_files argument of load_dataset() to load local datasets.", - correct: true - }, - { - text: "The Hugging Face Hub", - explain: "Correct! You can load datasets on the Hub by providing the dataset ID, e.g. load_dataset('emotion').", - correct: true - }, - { - text: "A remote server", - explain: "Correct! You can pass URLs to the data_files argument of load_dataset() to load remote files.", - correct: true - }, - ]} -/> - -### 2. Suppose you load one of the GLUE tasks as follows: - -```py -from datasets import load_dataset - -dataset = load_dataset("glue", "mrpc", split="train") -``` - -Which of the following commands will produce a random sample of 50 elements from `dataset`? - -dataset.sample(50)", - explain: "This is incorrect -- there is no Dataset.sample() method." - }, - { - text: "dataset.shuffle().select(range(50))", - explain: "Correct! As you saw in this chapter, you first shuffle the dataset and then select the samples from it.", - correct: true - }, - { - text: "dataset.select(range(50)).shuffle()", - explain: "This is incorrect -- although the code will run, it will only shuffle the first 50 elements in the dataset." - } - ]} -/> - -### 3. Suppose you have a dataset about household pets called `pets_dataset`, which has a `name` column that denotes the name of each pet. Which of the following approaches would allow you to filter the dataset for all pets whose names start with the letter "L"? - -pets_dataset.filter(lambda x : x['name'].startswith('L'))", - explain: "Correct! Using a Python lambda function for these quick filters is a great idea. Can you think of another solution?", - correct: true - }, - { - text: "pets_dataset.filter(lambda x['name'].startswith('L'))", - explain: "This is incorrect -- a lambda function takes the general form lambda *arguments* : *expression*, so you need to provide arguments in this case." - }, - { - text: "Create a function like def filter_names(x): return x['name'].startswith('L') and run pets_dataset.filter(filter_names).", - explain: "Correct! Just like with Dataset.map(), you can pass explicit functions to Dataset.filter(). This is useful when you have some complex logic that isn't suitable for a short lambda function. Which of the other solutions would work?", - correct: true - } - ]} -/> - -### 4. What is memory mapping? - - - -### 5. Which of the following are the main benefits of memory mapping? - - - -### 6. Why does the following code fail? - -```py -from datasets import load_dataset - -dataset = load_dataset("allocine", streaming=True, split="train") -dataset[0] -``` - -IterableDataset.", - explain: "Correct! An IterableDataset is a generator, not a container, so you should access its elements using next(iter(dataset)).", - correct: true - }, - { - text: "The allocine dataset doesn't have a train split.", - explain: "This is incorrect -- check out the [allocine dataset card](https://huggingface.co/datasets/allocine) on the Hub to see which splits it contains." - } - ]} -/> - -### 7. Which of the following are the main benefits of creating a dataset card? - - - - -### 8. What is semantic search? - - - -### 9. For asymmetric semantic search, you usually have: - - - -### 10. Can I use 🤗 Datasets to load data for use in other domains, like speech processing? - -MNIST dataset on the Hub for a computer vision example." - }, - { - text: "Yes", - explain: "Correct! Check out the exciting developments with speech and vision in the 🤗 Transformers library to see how 🤗 Datasets is used in these domains.", - correct : true - }, - ]} -/> From 72e67793b7596a1bdc84ae5753b3feff03b8a378 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:58:02 +0300 Subject: [PATCH 309/502] Delete chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx This is backup created by JupyterLab. --- .../.ipynb_checkpoints/1-checkpoint.mdx | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx diff --git a/chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx b/chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx deleted file mode 100644 index ce50bfd4e..000000000 --- a/chapters/en/chapter6/.ipynb_checkpoints/1-checkpoint.mdx +++ /dev/null @@ -1,19 +0,0 @@ -# Introduction[[introduction]] - - - -In [Chapter 3](/course/chapter3), we looked at how to fine-tune a model on a given task. When we do that, we use the same tokenizer that the model was pretrained with -- but what do we do when we want to train a model from scratch? In these cases, using a tokenizer that was pretrained on a corpus from another domain or language is typically suboptimal. For example, a tokenizer that's trained on an English corpus will perform poorly on a corpus of Japanese texts because the use of spaces and punctuation is very different in the two languages. - -In this chapter, you will learn how to train a brand new tokenizer on a corpus of texts, so it can then be used to pretrain a language model. This will all be done with the help of the [🤗 Tokenizers](https://github.com/huggingface/tokenizers) library, which provides the "fast" tokenizers in the [🤗 Transformers](https://github.com/huggingface/transformers) library. We'll take a close look at the features that this library provides, and explore how the fast tokenizers differ from the "slow" versions. - -Topics we will cover include: - -* How to train a new tokenizer similar to the one used by a given checkpoint on a new corpus of texts -* The special features of fast tokenizers -* The differences between the three main subword tokenization algorithms used in NLP today -* How to build a tokenizer from scratch with the 🤗 Tokenizers library and train it on some data - -The techniques introduced in this chapter will prepare you for the section in [Chapter 7](/course/chapter7/6) where we look at creating a language model for Python source code. Let's start by looking at what it means to "train" a tokenizer in the first place. \ No newline at end of file From c2f871bde41f90271445e5a55018ea8305798b00 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:58:21 +0300 Subject: [PATCH 310/502] Delete chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx This is backup created by JupyterLab. --- .../.ipynb_checkpoints/2-checkpoint.mdx | 257 ------------------ 1 file changed, 257 deletions(-) delete mode 100644 chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx diff --git a/chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx b/chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx deleted file mode 100644 index e966c486e..000000000 --- a/chapters/en/chapter6/.ipynb_checkpoints/2-checkpoint.mdx +++ /dev/null @@ -1,257 +0,0 @@ -# Training a new tokenizer from an old one[[training-a-new-tokenizer-from-an-old-one]] - - - -If a language model is not available in the language you are interested in, or if your corpus is very different from the one your language model was trained on, you will most likely want to retrain the model from scratch using a tokenizer adapted to your data. That will require training a new tokenizer on your dataset. But what exactly does that mean? When we first looked at tokenizers in [Chapter 2](/course/chapter2), we saw that most Transformer models use a _subword tokenization algorithm_. To identify which subwords are of interest and occur most frequently in the corpus at hand, the tokenizer needs to take a hard look at all the texts in the corpus -- a process we call *training*. The exact rules that govern this training depend on the type of tokenizer used, and we'll go over the three main algorithms later in this chapter. - - - - - -⚠️ Training a tokenizer is not the same as training a model! Model training uses stochastic gradient descent to make the loss a little bit smaller for each batch. It's randomized by nature (meaning you have to set some seeds to get the same results when doing the same training twice). Training a tokenizer is a statistical process that tries to identify which subwords are the best to pick for a given corpus, and the exact rules used to pick them depend on the tokenization algorithm. It's deterministic, meaning you always get the same results when training with the same algorithm on the same corpus. - - - -## Assembling a corpus[[assembling-a-corpus]] - -There's a very simple API in 🤗 Transformers that you can use to train a new tokenizer with the same characteristics as an existing one: `AutoTokenizer.train_new_from_iterator()`. To see this in action, let’s say we want to train GPT-2 from scratch, but in a language other than English. Our first task will be to gather lots of data in that language in a training corpus. To provide examples everyone will be able to understand, we won't use a language like Russian or Chinese here, but rather a specialized English language: Python code. - -The [🤗 Datasets](https://github.com/huggingface/datasets) library can help us assemble a corpus of Python source code. We'll use the usual `load_dataset()` function to download and cache the [CodeSearchNet](https://huggingface.co/datasets/code_search_net) dataset. This dataset was created for the [CodeSearchNet challenge](https://wandb.ai/github/CodeSearchNet/benchmark) and contains millions of functions from open source libraries on GitHub in several programming languages. Here, we will load the Python part of this dataset: - -```py -from datasets import load_dataset - -# This can take a few minutes to load, so grab a coffee or tea while you wait! -raw_datasets = load_dataset("code_search_net", "python") -``` - -We can have a look at the training split to see which columns we have access to: - -```py -raw_datasets["train"] -``` - -```python out -Dataset({ - features: ['repository_name', 'func_path_in_repository', 'func_name', 'whole_func_string', 'language', - 'func_code_string', 'func_code_tokens', 'func_documentation_string', 'func_documentation_tokens', 'split_name', - 'func_code_url' - ], - num_rows: 412178 -}) -``` - -We can see the dataset separates docstrings from code and suggests a tokenization of both. Here. we'll just use the `whole_func_string` column to train our tokenizer. We can look at an example of one these functions by indexing into the `train` split: - -```py -print(raw_datasets["train"][123456]["whole_func_string"]) -``` - -which should print the following: - -```out -def handle_simple_responses( - self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): - """Accepts normal responses from the device. - - Args: - timeout_ms: Timeout in milliseconds to wait for each response. - info_cb: Optional callback for text sent from the bootloader. - - Returns: - OKAY packet's message. - """ - return self._accept_responses('OKAY', info_cb, timeout_ms=timeout_ms) -``` - -The first thing we need to do is transform the dataset into an _iterator_ of lists of texts -- for instance, a list of list of texts. Using lists of texts will enable our tokenizer to go faster (training on batches of texts instead of processing individual texts one by one), and it should be an iterator if we want to avoid having everything in memory at once. If your corpus is huge, you will want to take advantage of the fact that 🤗 Datasets does not load everything into RAM but stores the elements of the dataset on disk. - -Doing the following would create a list of lists of 1,000 texts each, but would load everything in memory: - -```py -# Don't uncomment the following line unless your dataset is small! -# training_corpus = [raw_datasets["train"][i: i + 1000]["whole_func_string"] for i in range(0, len(raw_datasets["train"]), 1000)] -``` - -Using a Python generator, we can avoid Python loading anything into memory until it's actually necessary. To create such a generator, you just to need to replace the brackets with parentheses: - -```py -training_corpus = ( - raw_datasets["train"][i : i + 1000]["whole_func_string"] - for i in range(0, len(raw_datasets["train"]), 1000) -) -``` - -This line of code doesn't fetch any elements of the dataset; it just creates an object you can use in a Python `for` loop. The texts will only be loaded when you need them (that is, when you're at the step of the `for` loop that requires them), and only 1,000 texts at a time will be loaded. This way you won't exhaust all your memory even if you are processing a huge dataset. - -The problem with a generator object is that it can only be used once. So, instead of this giving us the list of the first 10 digits twice: - -```py -gen = (i for i in range(10)) -print(list(gen)) -print(list(gen)) -``` - -we get them once and then an empty list: - -```python out -[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] -[] -``` - -That's why we define a function that returns a generator instead: - -```py -def get_training_corpus(): - return ( - raw_datasets["train"][i : i + 1000]["whole_func_string"] - for i in range(0, len(raw_datasets["train"]), 1000) - ) - - -training_corpus = get_training_corpus() -``` - -You can also define your generator inside a `for` loop by using the `yield` statement: - -```py -def get_training_corpus(): - dataset = raw_datasets["train"] - for start_idx in range(0, len(dataset), 1000): - samples = dataset[start_idx : start_idx + 1000] - yield samples["whole_func_string"] -``` - -which will produce the exact same generator as before, but allows you to use more complex logic than you can in a list comprehension. - -## Training a new tokenizer[[training-a-new-tokenizer]] - -Now that we have our corpus in the form of an iterator of batches of texts, we are ready to train a new tokenizer. To do this, we first need to load the tokenizer we want to pair with our model (here, GPT-2): - -```py -from transformers import AutoTokenizer - -old_tokenizer = AutoTokenizer.from_pretrained("gpt2") -``` - -Even though we are going to train a new tokenizer, it's a good idea to do this to avoid starting entirely from scratch. This way, we won't have to specify anything about the tokenization algorithm or the special tokens we want to use; our new tokenizer will be exactly the same as GPT-2, and the only thing that will change is the vocabulary, which will be determined by the training on our corpus. - -First let's have a look at how this tokenizer would treat an example function: - -```py -example = '''def add_numbers(a, b): - """Add the two numbers `a` and `b`.""" - return a + b''' - -tokens = old_tokenizer.tokenize(example) -tokens -``` - -```python out -['def', 'Ġadd', '_', 'n', 'umbers', '(', 'a', ',', 'Ġb', '):', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', - 'Ġnumbers', 'Ġ`', 'a', '`', 'Ġand', 'Ġ`', 'b', '`', '."', '""', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] -``` - -This tokenizer has a few special symbols, like `Ġ` and `Ċ`, which denote spaces and newlines, respectively. As we can see, this is not too efficient: the tokenizer returns individual tokens for each space, when it could group together indentation levels (since having sets of four or eight spaces is going to be very common in code). It also split the function name a bit weirdly, not being used to seeing words with the `_` character. - -Let's train a new tokenizer and see if it solves those issues. For this, we'll use the method `train_new_from_iterator()`: - -```py -tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) -``` - -This command might take a bit of time if your corpus is very large, but for this dataset of 1.6 GB of texts it's blazing fast (1 minute 16 seconds on an AMD Ryzen 9 3900X CPU with 12 cores). - -Note that `AutoTokenizer.train_new_from_iterator()` only works if the tokenizer you are using is a "fast" tokenizer. As you'll see in the next section, the 🤗 Transformers library contains two types of tokenizers: some are written purely in Python and others (the fast ones) are backed by the 🤗 Tokenizers library, which is written in the [Rust](https://www.rust-lang.org) programming language. Python is the language most often used for data science and deep learning applications, but when anything needs to be parallelized to be fast, it has to be written in another language. For instance, the matrix multiplications that are at the core of the model computation are written in CUDA, an optimized C library for GPUs. - -Training a brand new tokenizer in pure Python would be excruciatingly slow, which is why we developed the 🤗 Tokenizers library. Note that just as you didn't have to learn the CUDA language to be able to execute your model on a batch of inputs on a GPU, you won't need to learn Rust to use a fast tokenizer. The 🤗 Tokenizers library provides Python bindings for many methods that internally call some piece of code in Rust; for example, to parallelize the training of your new tokenizer or, as we saw in [Chapter 3](/course/chapter3), the tokenization of a batch of inputs. - -Most of the Transformer models have a fast tokenizer available (there are some exceptions that you can check [here](https://huggingface.co/transformers/#supported-frameworks)), and the `AutoTokenizer` API always selects the fast tokenizer for you if it's available. In the next section we'll take a look at some of the other special features fast tokenizers have, which will be really useful for tasks like token classification and question answering. Before diving into that, however, let's try our brand new tokenizer on the previous example: - -```py -tokens = tokenizer.tokenize(example) -tokens -``` - -```python out -['def', 'Ġadd', '_', 'numbers', '(', 'a', ',', 'Ġb', '):', 'ĊĠĠĠ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', 'Ġnumbers', 'Ġ`', - 'a', '`', 'Ġand', 'Ġ`', 'b', '`."""', 'ĊĠĠĠ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] -``` - -Here we again see the special symbols `Ġ` and `Ċ` that denote spaces and newlines, but we can also see that our tokenizer learned some tokens that are highly specific to a corpus of Python functions: for example, there is a `ĊĠĠĠ` token that represents an indentation, and a `Ġ"""` token that represents the three quotes that start a docstring. The tokenizer also correctly split the function name on `_`. This is quite a compact representation; comparatively, using the plain English tokenizer on the same example will give us a longer sentence: - -```py -print(len(tokens)) -print(len(old_tokenizer.tokenize(example))) -``` - -```python out -27 -36 -``` - -Let's look at another example: - -```python -example = """class LinearLayer(): - def __init__(self, input_size, output_size): - self.weight = torch.randn(input_size, output_size) - self.bias = torch.zeros(output_size) - - def __call__(self, x): - return x @ self.weights + self.bias - """ -tokenizer.tokenize(example) -``` - -```python out -['class', 'ĠLinear', 'Layer', '():', 'ĊĠĠĠ', 'Ġdef', 'Ġ__', 'init', '__(', 'self', ',', 'Ġinput', '_', 'size', ',', - 'Ġoutput', '_', 'size', '):', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'weight', 'Ġ=', 'Ġtorch', '.', 'randn', '(', 'input', '_', - 'size', ',', 'Ġoutput', '_', 'size', ')', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'bias', 'Ġ=', 'Ġtorch', '.', 'zeros', '(', - 'output', '_', 'size', ')', 'ĊĊĠĠĠ', 'Ġdef', 'Ġ__', 'call', '__(', 'self', ',', 'Ġx', '):', 'ĊĠĠĠĠĠĠĠ', - 'Ġreturn', 'Ġx', 'Ġ@', 'Ġself', '.', 'weights', 'Ġ+', 'Ġself', '.', 'bias', 'ĊĠĠĠĠ'] -``` - -In addition to the token corresponding to an indentation, here we can also see a token for a double indentation: `ĊĠĠĠĠĠĠĠ`. The special Python words like `class`, `init`, `call`, `self`, and `return` are each tokenized as one token, and we can see that as well as splitting on `_` and `.` the tokenizer correctly splits even camel-cased names: `LinearLayer` is tokenized as `["ĠLinear", "Layer"]`. - -## Saving the tokenizer[[saving-the-tokenizer]] - -To make sure we can use it later, we need to save our new tokenizer. Like for models, this is done with the `save_pretrained()` method: - -```py -tokenizer.save_pretrained("code-search-net-tokenizer") -``` - -This will create a new folder named *code-search-net-tokenizer*, which will contain all the files the tokenizer needs to be reloaded. If you want to share this tokenizer with your colleagues and friends, you can upload it to the Hub by logging into your account. If you're working in a notebook, there's a convenience function to help you with this: - -```python -from huggingface_hub import notebook_login - -notebook_login() -``` - -This will display a widget where you can enter your Hugging Face login credentials. If you aren't working in a notebook, just type the following line in your terminal: - -```bash -huggingface-cli login -``` - -Once you've logged in, you can push your tokenizer by executing the following command: - -```py -tokenizer.push_to_hub("code-search-net-tokenizer") -``` - -This will create a new repository in your namespace with the name `code-search-net-tokenizer`, containing the tokenizer file. You can then load the tokenizer from anywhere with the `from_pretrained()` method: - -```py -# Replace "huggingface-course" below with your actual namespace to use your own tokenizer -tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") -``` - -You're now all set for training a language model from scratch and fine-tuning it on your task at hand! We'll get to that in [Chapter 7](/course/chapter7), but first, in the rest of this chapter we'll take a closer look at fast tokenizers and explore in detail what actually happens when we call the method `train_new_from_iterator()`. From ce3ac4d2ea5528f0ae97a54d9ef9754635da511d Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:58:40 +0300 Subject: [PATCH 311/502] Delete chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx This is backup created by JupyterLab. --- .../.ipynb_checkpoints/8-checkpoint.mdx | 565 ------------------ 1 file changed, 565 deletions(-) delete mode 100644 chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx diff --git a/chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx b/chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx deleted file mode 100644 index 7caee98ed..000000000 --- a/chapters/en/chapter6/.ipynb_checkpoints/8-checkpoint.mdx +++ /dev/null @@ -1,565 +0,0 @@ -# Building a tokenizer, block by block[[building-a-tokenizer-block-by-block]] - - - -As we've seen in the previous sections, tokenization comprises several steps: - -- Normalization (any cleanup of the text that is deemed necessary, such as removing spaces or accents, Unicode normalization, etc.) -- Pre-tokenization (splitting the input into words) -- Running the input through the model (using the pre-tokenized words to produce a sequence of tokens) -- Post-processing (adding the special tokens of the tokenizer, generating the attention mask and token type IDs) - -As a reminder, here's another look at the overall process: - -
-The tokenization pipeline. - -
- -The 🤗 Tokenizers library has been built to provide several options for each of those steps, which you can mix and match together. In this section we'll see how we can build a tokenizer from scratch, as opposed to training a new tokenizer from an old one as we did in [section 2](/course/chapter6/2). You'll then be able to build any kind of tokenizer you can think of! - - - -More precisely, the library is built around a central `Tokenizer` class with the building blocks regrouped in submodules: - -- `normalizers` contains all the possible types of `Normalizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). -- `pre_tokenizers` contains all the possible types of `PreTokenizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). -- `models` contains the various types of `Model` you can use, like `BPE`, `WordPiece`, and `Unigram` (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). -- `trainers` contains all the different types of `Trainer` you can use to train your model on a corpus (one per type of model; complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). -- `post_processors` contains the various types of `PostProcessor` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). -- `decoders` contains the various types of `Decoder` you can use to decode the outputs of tokenization (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). - -You can find the whole list of building blocks [here](https://huggingface.co/docs/tokenizers/python/latest/components.html). - -## Acquiring a corpus[[acquiring-a-corpus]] - -To train our new tokenizer, we will use a small corpus of text (so the examples run fast). The steps for acquiring the corpus are similar to the ones we took at the [beginning of this chapter](/course/chapter6/2), but this time we'll use the [WikiText-2](https://huggingface.co/datasets/wikitext) dataset: - -```python -from datasets import load_dataset - -dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train") - - -def get_training_corpus(): - for i in range(0, len(dataset), 1000): - yield dataset[i : i + 1000]["text"] -``` - -The function `get_training_corpus()` is a generator that will yield batches of 1,000 texts, which we will use to train the tokenizer. - -🤗 Tokenizers can also be trained on text files directly. Here's how we can generate a text file containing all the texts/inputs from WikiText-2 that we can use locally: - -```python -with open("wikitext-2.txt", "w", encoding="utf-8") as f: - for i in range(len(dataset)): - f.write(dataset[i]["text"] + "\n") -``` - -Next we'll show you how to build your own BERT, GPT-2, and XLNet tokenizers, block by block. That will give us an example of each of the three main tokenization algorithms: WordPiece, BPE, and Unigram. Let's start with BERT! - -## Building a WordPiece tokenizer from scratch[[building-a-wordpiece-tokenizer-from-scratch]] - -To build a tokenizer with the 🤗 Tokenizers library, we start by instantiating a `Tokenizer` object with a `model`, then set its `normalizer`, `pre_tokenizer`, `post_processor`, and `decoder` attributes to the values we want. - -For this example, we'll create a `Tokenizer` with a WordPiece model: - -```python -from tokenizers import ( - decoders, - models, - normalizers, - pre_tokenizers, - processors, - trainers, - Tokenizer, -) - -tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) -``` - -We have to specify the `unk_token` so the model knows what to return when it encounters characters it hasn't seen before. Other arguments we can set here include the `vocab` of our model (we're going to train the model, so we don't need to set this) and `max_input_chars_per_word`, which specifies a maximum length for each word (words longer than the value passed will be split). - -The first step of tokenization is normalization, so let's begin with that. Since BERT is widely used, there is a `BertNormalizer` with the classic options we can set for BERT: `lowercase` and `strip_accents`, which are self-explanatory; `clean_text` to remove all control characters and replace repeating spaces with a single one; and `handle_chinese_chars`, which places spaces around Chinese characters. To replicate the `bert-base-uncased` tokenizer, we can just set this normalizer: - -```python -tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) -``` - -Generally speaking, however, when building a new tokenizer you won't have access to such a handy normalizer already implemented in the 🤗 Tokenizers library -- so let's see how to create the BERT normalizer by hand. The library provides a `Lowercase` normalizer and a `StripAccents` normalizer, and you can compose several normalizers using a `Sequence`: - -```python -tokenizer.normalizer = normalizers.Sequence( - [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()] -) -``` - -We're also using an `NFD` Unicode normalizer, as otherwise the `StripAccents` normalizer won't properly recognize the accented characters and thus won't strip them out. - -As we've seen before, we can use the `normalize_str()` method of the `normalizer` to check out the effects it has on a given text: - -```python -print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) -``` - -```python out -hello how are u? -``` - - - -**To go further** If you test the two versions of the previous normalizers on a string containing the unicode character `u"\u0085"` you will surely notice that these two normalizers are not exactly equivalent. -To not over-complicate the version with `normalizers.Sequence` too much , we haven't included the Regex replacements that the `BertNormalizer` requires when the `clean_text` argument is set to `True` - which is the default behavior. But don't worry: it is possible to get exactly the same normalization without using the handy `BertNormalizer` by adding two `normalizers.Replace`'s to the normalizers sequence. - - - -Next is the pre-tokenization step. Again, there is a prebuilt `BertPreTokenizer` that we can use: - -```python -tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() -``` - -Or we can build it from scratch: - -```python -tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() -``` - -Note that the `Whitespace` pre-tokenizer splits on whitespace and all characters that are not letters, digits, or the underscore character, so it technically splits on whitespace and punctuation: - -```python -tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") -``` - -```python out -[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), - ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] -``` - -If you only want to split on whitespace, you should use the `WhitespaceSplit` pre-tokenizer instead: - -```python -pre_tokenizer = pre_tokenizers.WhitespaceSplit() -pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") -``` - -```python out -[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] -``` - -Like with normalizers, you can use a `Sequence` to compose several pre-tokenizers: - -```python -pre_tokenizer = pre_tokenizers.Sequence( - [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()] -) -pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") -``` - -```python out -[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), - ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] -``` - -The next step in the tokenization pipeline is running the inputs through the model. We already specified our model in the initialization, but we still need to train it, which will require a `WordPieceTrainer`. The main thing to remember when instantiating a trainer in 🤗 Tokenizers is that you need to pass it all the special tokens you intend to use -- otherwise it won't add them to the vocabulary, since they are not in the training corpus: - -```python -special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] -trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) -``` - -As well as specifying the `vocab_size` and `special_tokens`, we can set the `min_frequency` (the number of times a token must appear to be included in the vocabulary) or change the `continuing_subword_prefix` (if we want to use something different from `##`). - -To train our model using the iterator we defined earlier, we just have to execute this command: - -```python -tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) -``` - -We can also use text files to train our tokenizer, which would look like this (we reinitialize the model with an empty `WordPiece` beforehand): - -```python -tokenizer.model = models.WordPiece(unk_token="[UNK]") -tokenizer.train(["wikitext-2.txt"], trainer=trainer) -``` - -In both cases, we can then test the tokenizer on a text by calling the `encode()` method: - -```python -encoding = tokenizer.encode("Let's test this tokenizer.") -print(encoding.tokens) -``` - -```python out -['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] -``` - -The `encoding` obtained is an `Encoding`, which contains all the necessary outputs of the tokenizer in its various attributes: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask`, and `overflowing`. - -The last step in the tokenization pipeline is post-processing. We need to add the `[CLS]` token at the beginning and the `[SEP]` token at the end (or after each sentence, if we have a pair of sentences). We will use a `TemplateProcessor` for this, but first we need to know the IDs of the `[CLS]` and `[SEP]` tokens in the vocabulary: - -```python -cls_token_id = tokenizer.token_to_id("[CLS]") -sep_token_id = tokenizer.token_to_id("[SEP]") -print(cls_token_id, sep_token_id) -``` - -```python out -(2, 3) -``` - -To write the template for the `TemplateProcessor`, we have to specify how to treat a single sentence and a pair of sentences. For both, we write the special tokens we want to use; the first (or single) sentence is represented by `$A`, while the second sentence (if encoding a pair) is represented by `$B`. For each of these (special tokens and sentences), we also specify the corresponding token type ID after a colon. - -The classic BERT template is thus defined as follows: - -```python -tokenizer.post_processor = processors.TemplateProcessing( - single=f"[CLS]:0 $A:0 [SEP]:0", - pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1", - special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)], -) -``` - -Note that we need to pass along the IDs of the special tokens, so the tokenizer can properly convert them to their IDs. - -Once this is added, going back to our previous example will give: - -```python -encoding = tokenizer.encode("Let's test this tokenizer.") -print(encoding.tokens) -``` - -```python out -['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] -``` - -And on a pair of sentences, we get the proper result: - -```python -encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") -print(encoding.tokens) -print(encoding.type_ids) -``` - -```python out -['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]'] -[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] -``` - -We've almost finished building this tokenizer from scratch -- the last step is to include a decoder: - -```python -tokenizer.decoder = decoders.WordPiece(prefix="##") -``` - -Let's test it on our previous `encoding`: - -```python -tokenizer.decode(encoding.ids) -``` - -```python out -"let's test this tokenizer... on a pair of sentences." -``` - -Great! We can save our tokenizer in a single JSON file like this: - -```python -tokenizer.save("tokenizer.json") -``` - -We can then reload that file in a `Tokenizer` object with the `from_file()` method: - -```python -new_tokenizer = Tokenizer.from_file("tokenizer.json") -``` - -To use this tokenizer in 🤗 Transformers, we have to wrap it in a `PreTrainedTokenizerFast`. We can either use the generic class or, if our tokenizer corresponds to an existing model, use that class (here, `BertTokenizerFast`). If you apply this lesson to build a brand new tokenizer, you will have to use the first option. - -To wrap the tokenizer in a `PreTrainedTokenizerFast`, we can either pass the tokenizer we built as a `tokenizer_object` or pass the tokenizer file we saved as `tokenizer_file`. The key thing to remember is that we have to manually set all the special tokens, since that class can't infer from the `tokenizer` object which token is the mask token, the `[CLS]` token, etc.: - -```python -from transformers import PreTrainedTokenizerFast - -wrapped_tokenizer = PreTrainedTokenizerFast( - tokenizer_object=tokenizer, - # tokenizer_file="tokenizer.json", # You can load from the tokenizer file, alternatively - unk_token="[UNK]", - pad_token="[PAD]", - cls_token="[CLS]", - sep_token="[SEP]", - mask_token="[MASK]", -) -``` - -If you are using a specific tokenizer class (like `BertTokenizerFast`), you will only need to specify the special tokens that are different from the default ones (here, none): - -```python -from transformers import BertTokenizerFast - -wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) -``` - -You can then use this tokenizer like any other 🤗 Transformers tokenizer. You can save it with the `save_pretrained()` method, or upload it to the Hub with the `push_to_hub()` method. - -Now that we've seen how to build a WordPiece tokenizer, let's do the same for a BPE tokenizer. We'll go a bit faster since you know all the steps, and only highlight the differences. - -## Building a BPE tokenizer from scratch[[building-a-bpe-tokenizer-from-scratch]] - -Let's now build a GPT-2 tokenizer. Like for the BERT tokenizer, we start by initializing a `Tokenizer` with a BPE model: - -```python -tokenizer = Tokenizer(models.BPE()) -``` - -Also like for BERT, we could initialize this model with a vocabulary if we had one (we would need to pass the `vocab` and `merges` in this case), but since we will train from scratch, we don't need to do that. We also don't need to specify an `unk_token` because GPT-2 uses byte-level BPE, which doesn't require it. - -GPT-2 does not use a normalizer, so we skip that step and go directly to the pre-tokenization: - -```python -tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) -``` - -The option we added to `ByteLevel` here is to not add a space at the beginning of a sentence (which is the default otherwise). We can have a look at the pre-tokenization of an example text like before: - -```python -tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") -``` - -```python out -[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)), - ('tokenization', (15, 27)), ('!', (27, 28))] -``` - -Next is the model, which needs training. For GPT-2, the only special token is the end-of-text token: - -```python -trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) -tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) -``` - -Like with the `WordPieceTrainer`, as well as the `vocab_size` and `special_tokens`, we can specify the `min_frequency` if we want to, or if we have an end-of-word suffix (like ``), we can set it with `end_of_word_suffix`. - -This tokenizer can also be trained on text files: - -```python -tokenizer.model = models.BPE() -tokenizer.train(["wikitext-2.txt"], trainer=trainer) -``` - -Let's have a look at the tokenization of a sample text: - -```python -encoding = tokenizer.encode("Let's test this tokenizer.") -print(encoding.tokens) -``` - -```python out -['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] -``` - -We apply the byte-level post-processing for the GPT-2 tokenizer as follows: - -```python -tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) -``` - -The `trim_offsets = False` option indicates to the post-processor that we should leave the offsets of tokens that begin with 'Ġ' as they are: this way the start of the offsets will point to the space before the word, not the first character of the word (since the space is technically part of the token). Let's have a look at the result with the text we just encoded, where `'Ġtest'` is the token at index 4: - -```python -sentence = "Let's test this tokenizer." -encoding = tokenizer.encode(sentence) -start, end = encoding.offsets[4] -sentence[start:end] -``` - -```python out -' test' -``` - -Finally, we add a byte-level decoder: - -```python -tokenizer.decoder = decoders.ByteLevel() -``` - -and we can double-check it works properly: - -```python -tokenizer.decode(encoding.ids) -``` - -```python out -"Let's test this tokenizer." -``` - -Great! Now that we're done, we can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `GPT2TokenizerFast` if we want to use it in 🤗 Transformers: - -```python -from transformers import PreTrainedTokenizerFast - -wrapped_tokenizer = PreTrainedTokenizerFast( - tokenizer_object=tokenizer, - bos_token="<|endoftext|>", - eos_token="<|endoftext|>", -) -``` - -or: - -```python -from transformers import GPT2TokenizerFast - -wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) -``` - -As the last example, we'll show you how to build a Unigram tokenizer from scratch. - -## Building a Unigram tokenizer from scratch[[building-a-unigram-tokenizer-from-scratch]] - -Let's now build an XLNet tokenizer. Like for the previous tokenizers, we start by initializing a `Tokenizer` with a Unigram model: - -```python -tokenizer = Tokenizer(models.Unigram()) -``` - -Again, we could initialize this model with a vocabulary if we had one. - -For the normalization, XLNet uses a few replacements (which come from SentencePiece): - -```python -from tokenizers import Regex - -tokenizer.normalizer = normalizers.Sequence( - [ - normalizers.Replace("``", '"'), - normalizers.Replace("''", '"'), - normalizers.NFKD(), - normalizers.StripAccents(), - normalizers.Replace(Regex(" {2,}"), " "), - ] -) -``` - -This replaces `` and '' with " and any sequence of two or more spaces with a single space, as well as removing the accents in the texts to tokenize. - -The pre-tokenizer to use for any SentencePiece tokenizer is `Metaspace`: - -```python -tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() -``` - -We can have a look at the pre-tokenization of an example text like before: - -```python -tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") -``` - -```python out -[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] -``` - -Next is the model, which needs training. XLNet has quite a few special tokens: - -```python -special_tokens = ["", "", "", "", "", "", ""] -trainer = trainers.UnigramTrainer( - vocab_size=25000, special_tokens=special_tokens, unk_token="" -) -tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) -``` - -A very important argument not to forget for the `UnigramTrainer` is the `unk_token`. We can also pass along other arguments specific to the Unigram algorithm, such as the `shrinking_factor` for each step where we remove tokens (defaults to 0.75) or the `max_piece_length` to specify the maximum length of a given token (defaults to 16). - -This tokenizer can also be trained on text files: - -```python -tokenizer.model = models.Unigram() -tokenizer.train(["wikitext-2.txt"], trainer=trainer) -``` - -Let's have a look at the tokenization of a sample text: - -```python -encoding = tokenizer.encode("Let's test this tokenizer.") -print(encoding.tokens) -``` - -```python out -['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] -``` - -A peculiarity of XLNet is that it puts the `` token at the end of the sentence, with a type ID of 2 (to distinguish it from the other tokens). It's padding on the left, as a result. We can deal with all the special tokens and token type IDs with a template, like for BERT, but first we have to get the IDs of the `` and `` tokens: - -```python -cls_token_id = tokenizer.token_to_id("") -sep_token_id = tokenizer.token_to_id("") -print(cls_token_id, sep_token_id) -``` - -```python out -0 1 -``` - -The template looks like this: - -```python -tokenizer.post_processor = processors.TemplateProcessing( - single="$A:0 :0 :2", - pair="$A:0 :0 $B:1 :1 :2", - special_tokens=[("", sep_token_id), ("", cls_token_id)], -) -``` - -And we can test it works by encoding a pair of sentences: - -```python -encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") -print(encoding.tokens) -print(encoding.type_ids) -``` - -```python out -['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '', '▁', 'on', '▁', 'a', '▁pair', - '▁of', '▁sentence', 's', '!', '', ''] -[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] -``` - -Finally, we add a `Metaspace` decoder: - -```python -tokenizer.decoder = decoders.Metaspace() -``` - -and we're done with this tokenizer! We can save the tokenizer like before, and wrap it in a `PreTrainedTokenizerFast` or `XLNetTokenizerFast` if we want to use it in 🤗 Transformers. One thing to note when using `PreTrainedTokenizerFast` is that on top of the special tokens, we need to tell the 🤗 Transformers library to pad on the left: - -```python -from transformers import PreTrainedTokenizerFast - -wrapped_tokenizer = PreTrainedTokenizerFast( - tokenizer_object=tokenizer, - bos_token="", - eos_token="", - unk_token="", - pad_token="", - cls_token="", - sep_token="", - mask_token="", - padding_side="left", -) -``` - -Or alternatively: - -```python -from transformers import XLNetTokenizerFast - -wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) -``` - -Now that you have seen how the various building blocks are used to build existing tokenizers, you should be able to write any tokenizer you want with the 🤗 Tokenizers library and be able to use it in 🤗 Transformers. From 8f7520aecc61f28227b4b84c50140731267566fb Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:59:02 +0300 Subject: [PATCH 312/502] Delete chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx This is backup created by JupyterLab. --- .../chapter6/.ipynb_checkpoints/9-checkpoint.mdx | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx diff --git a/chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx b/chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx deleted file mode 100644 index 288c4864b..000000000 --- a/chapters/en/chapter6/.ipynb_checkpoints/9-checkpoint.mdx +++ /dev/null @@ -1,16 +0,0 @@ -# Tokenizers, check![[tokenizers-check]] - - - -Great job finishing this chapter! - -After this deep dive into tokenizers, you should: - -- Be able to train a new tokenizer using an old one as a template -- Understand how to use offsets to map tokens' positions to their original span of text -- Know the differences between BPE, WordPiece, and Unigram -- Be able to mix and match the blocks provided by the 🤗 Tokenizers library to build your own tokenizer -- Be able to use that tokenizer inside the 🤗 Transformers library From 73855b0862a4901d5b5199ca0d6301a429d962cd Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:59:24 +0300 Subject: [PATCH 313/502] Delete chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt This is backup created by JupyterLab. --- .../TRANSLATING-checkpoint.txt | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt diff --git a/chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt b/chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt deleted file mode 100644 index 77282cecc..000000000 --- a/chapters/ru/.ipynb_checkpoints/TRANSLATING-checkpoint.txt +++ /dev/null @@ -1,47 +0,0 @@ -1. We use the formal "you" (i.e. "вы" instead of "ты") to keep the neutral tone. - However, don't make the text too formal to keep it more engaging. - -2. Don't translate industry-accepted acronyms. e.g. TPU or GPU. - -3. The Russian language accepts English words especially in modern contexts more than - many other languages (i.e. Anglicisms). Check for the correct usage of terms in - computer science and commonly used terms in other publications. - -4. Russian word order is often different from English. If after translating a sentence - it sounds unnatural try to change the word or clause order to make it more natural. - -5. Beware of "false friends" in Russian and English translations. Translators are trained - for years to specifically avoid false English friends and avoid anglicised translations. - e.g. "точность" is "accuracy", but "carefulness" is "аккуратность". For more examples refer to: - http://falsefriends.ru/ffslovar.htm - -6. Keep voice active and consistent. Don't overdo it but try to avoid a passive voice. - -7. Refer and contribute to the glossary frequently to stay on top of the latest - choices we make. This minimizes the amount of editing that is required. - -8. Keep POV consistent. - -9. Smaller sentences are better sentences. Apply with nuance. - -10. If translating a technical word, keep the choice of Russian translation consistent. - This does not apply for non-technical choices, as in those cases variety actually - helps keep the text engaging. - -11. This is merely a translation. Don't add any technical/contextual information - not present in the original text. Also don't leave stuff out. The creative - choices in composing this information were the original authors' to make. - Our creative choices are in doing a quality translation. - -12. Be exact when choosing equivalents for technical words. Package is package. - Library is library. Don't mix and match. Also, since both "batch" and "package" - can be translated as "пакет", use "батч" for "batch" and "пакет" for "package" to - avoid ambiguity. - -13. Library names are kept in the original forms, e.g. "🤗 Datasets", however, - the word dataset in a sentence gets a translation to "датасет". - -14. As a style choice prefer the imperative over constructions with auxiliary words - to avoid unnecessary verbosity and addressing of the reader, which seems - unnatural in Russian. e.g. "см. главу X" - "See chapter X" instead of - "Вы можете найти это в главе X" - "You can see this in chapter X". \ No newline at end of file From 02395c1f52b6911591c6785e65ecbe82c8ede150 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 18:59:48 +0300 Subject: [PATCH 314/502] Delete chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml This is backup created by JupyterLab. --- .../_toctree-checkpoint.yml | 119 ------------------ 1 file changed, 119 deletions(-) delete mode 100644 chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml diff --git a/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml deleted file mode 100644 index 597730c46..000000000 --- a/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml +++ /dev/null @@ -1,119 +0,0 @@ -- title: 0. Установка - sections: - - local: chapter0/1 - title: Введение - -- title: 1. Трансформеры - sections: - - local: chapter1/1 - title: Введение - - local: chapter1/2 - title: Обработка естественного языка - - local: chapter1/3 - title: "Трансформеры: на что они способны?" - - local: chapter1/4 - title: Как работают трансформеры? - - local: chapter1/5 - title: Модели-кодировщики - - local: chapter1/6 - title: Модели-декодировщики - - local: chapter1/7 - title: Модели "seq2seq" - - local: chapter1/8 - title: Предвзятости и ограничения - - local: chapter1/9 - title: Итоги - - local: chapter1/10 - title: Проверка знаний - -- title: 2. Использование библиотеки 🤗 Transformers - sections: - - local: chapter2/1 - title: Введение - - local: chapter2/2 - title: Внутри конвейера - - local: chapter2/3 - title: Модели - - local: chapter2/7 - title: Базовое использование завершено! - -- title: 3. Fine-tuning предобученной модели - sections: - - local: chapter3/1 - title: Введение - - local: chapter3/2 - title: Предобработка данных - - local: chapter3/3 - title: Fine-tuning модели с использованием Trainer API - local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - - local: chapter3/4 - title: Полное обучение модели - - local: chapter3/5 - title: Fine-tuning, итоги! - - local: chapter3/6 - title: Итоговый тест по главе - quiz: 3 - -- title: 4. Hugging Face Hub - sections: - - local: chapter4/1 - title: Hugging Face Hub - - local: chapter4/2 - title: Использование предобученных моделей - - local: chapter4/3 - title: Публикация предобученных моделей в общий доступ - - local: chapter4/4 - title: Создание карточки модели - - local: chapter4/5 - title: Первая часть завершена! - - local: chapter4/6 - title: Итоговый тест по главе - quiz: 4 - -- title: 5. Библиотека 🤗 Datasets - sections: - - local: chapter5/1 - title: Введение - - local: chapter5/2 - title: Что делать, если моего датасета на нет на Hub? - - local: chapter5/3 - title: Препарируем 🤗 Datasets - - local: chapter5/4 - title: Big data? 🤗 Datasets спешат на помощь! - - local: chapter5/6 - title: Семантический поиск с помощью FAISS - - local: chapter5/7 - title: 🤗 Datasets, итоги! - - local: chapter5/8 - title: Тест по главе 5 - -- title: 6. Бибилиотека 🤗 Tokenizers - sections: - - local: chapter6/1 - title: Введение - - local: chapter6/2 - title: Обучение нового токенизатора на основе старого - - local: chapter6/3 - title: Особые возможности быстрых токенизаторов - - local: chapter6/3b - title: Быстрые токенизаторы в QA конвейере - - local: chapter6/4 - title: Нормализация и предварительная токенизация - - local: chapter6/5 - title: Токенизация Byte-Pair Encoding - - local: chapter6/6 - title: Токенизация WordPiece - - local: chapter6/7 - title: Токенизация Unigram - - local: chapter6/8 - title: Создание токенизатора, блок за блоком - - local: chapter6/9 - title: Токенизаторы, проверка! - - local: chapter6/10 - title: Тест в конце главы - quiz: 6 - -- title: Глоссарий - sections: - - local: glossary/1 - title: Глоссарий From 849d5dde3a16ecd6c40eacbed8874f14b0a61c03 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 19:01:26 +0300 Subject: [PATCH 315/502] Delete chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx This is backup created by JupyterLab. --- .../.ipynb_checkpoints/8-checkpoint.mdx | 230 ------------------ 1 file changed, 230 deletions(-) delete mode 100644 chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx diff --git a/chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx b/chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx deleted file mode 100644 index 717a1b959..000000000 --- a/chapters/ru/chapter5/.ipynb_checkpoints/8-checkpoint.mdx +++ /dev/null @@ -1,230 +0,0 @@ - - -# Тест по главе 5 - - - -Эта глава охватила много вопросов! Не волнуйтесь, если вы не поняли всех деталей; следующие главы помогут вам понять, как все работает внутри. - -Однако, прежде чем двигаться дальше, давайте проверим то, что вы узнали в этой главе. -### Из каких источников функция `load_dataset()` в 🤗 Datasets позволяет загружать наборы данных? - -data_files функции load_dataset() для загрузки локальных наборов данных.", - correct: true - }, - { - text: "Hugging Face Hub", - explain: "Правильно! Вы можете загружать наборы данных в Hub, указав идентификатор набора данных, например. load_dataset('emotion').", - correct: true - }, - { - text: "Удаленный сервер", - explain: "Правильно! Вы можете передать URLs в аргумент data_files фунции load_dataset(). ", - correct: true - }, - ]} -/> - -### 2. Предположим, вы загружаете одну из задач GLUE следующим образом: - -```py -from datasets import load_dataset - -dataset = load_dataset("glue", "mrpc", split="train") -``` - -Какая из следующих команд создаст случайную выборку из 50 элементов из `dataset`? - -dataset.sample(50)", - explain: "Это неверно — нет метода Dataset.sample()." - }, - { - text: "dataset.shuffle().select(range(50))", - explain: "Правильный! Как вы видели в этой главе, вы сначала перемешиваете набор данных, а затем выбираете из него подмножества.", - correct: true - }, - { - text: "dataset.select(range(50)).shuffle()", - explain: "Это неверно — хотя код запустится, он перемешает только первые 50 элементов в наборе данных." - } - ]} -/> - -### 3. Предположим, у вас есть набор данных о домашних питомцах под названием `pets_dataset`, в котором есть столбец `name`, обозначающий имя каждого питомца. Какой из следующих подходов позволит вам отфильтровать набор данных для всех домашних животных, имена которых начинаются с буквы «L»? - -pets_dataset.filter(lambda x : x['name'].startswith('L'))", - explain: "Правильно! Использование лямбда-функции Python для этих быстрых фильтров — отличная идея. Можете ли вы придумать другое решение?", - correct: true - }, - { - text: "pets_dataset.filter(lambda x['name'].startswith('L'))", - explain: "Это неверно — лямбда-функция принимает общую форму lambda *arguments* : *expression*, поэтому в этом случае вам необходимо предоставить аргументы." - }, - { - text: "Create a function like def filter_names(x): return x['name'].startswith('L') and run pets_dataset.filter(filter_names).", - explain: "Правильно! Как и в случае с Dataset.map(), вы можете передавать явные функции в Dataset.filter(). Это полезно, когда у вас есть сложная логика, которая не подходит для короткой лямбда-функции. Какое из других решений будет работать?", - correct: true - } - ]} -/> - -### 4. Что такое отображение в память? - - - -### 5. Что из перечисленного ниже является основным преимуществом отображения памяти? - - - -### 6. Почему следующий код не работает? - -```py -from datasets import load_dataset - -dataset = load_dataset("allocine", streaming=True, split="train") -dataset[0] -``` - -IterableDataset.", - explain: "Правильно! IterableDataset — это генератор, а не контейнер, поэтому вы должны получить доступ к его элементам, используя next(iter(dataset)).", - correct: true - }, - { - text: "Набор данных allocine не имеет разделения train.", - explain: "Это неверно — проверьте [allocine карточку набора данных](https://huggingface.co/datasets/allocine) в Hub, чтобы увидеть, какие разбиения он содержит." - } - ]} -/> - -### 7. Что из перечисленного является основными преимуществами создания карточки датасета? - - - - -### 8. Что такое семантический поиск? - - - -### 9. Для асимметричного семантического поиска можно использовать: - - - -### 10. Могу ли я использовать 🤗 Datasets для загрузки данных и решения задач в других областях, например для обработки речи? - -набором данных MNIST в Hub для примера компьютерного зрения." - }, - { - text: "Да", - explain: "Правильно! Ознакомьтесь с захватывающими разработками в области речи и зрения в библиотеке 🤗 Transformers, чтобы узнать, как 🤗 Datasets используются в этих областях.", - correct : true - }, - ]} -/> From be33220fc934818151c4be3c7898e58debe90691 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 19:21:55 +0300 Subject: [PATCH 316/502] Update 10.mdx Minor fix. From e9552b0128fd09fddc5235acd1f86f47cf4d4bc1 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 19:28:11 +0300 Subject: [PATCH 317/502] Update 10.mdx Trying to solve the markup problem. --- chapters/ru/chapter6/10.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/chapters/ru/chapter6/10.mdx b/chapters/ru/chapter6/10.mdx index 5199cf774..5593ee09b 100644 --- a/chapters/ru/chapter6/10.mdx +++ b/chapters/ru/chapter6/10.mdx @@ -74,7 +74,7 @@ text: "Он может применять дополнение (padding) и усечение (truncation).", explain: "Верно, но медленные токенизаторы тоже могут это делать." }, - { + { text: "Он обладает некоторыми дополнительными функциями, позволяющими сопоставлять токены с фрагментами текста, которые их сформировали.", explain: "Действительно, это так называемые смещенные отображения (offset mappings). Однако это не единственное преимущество.", correct: true @@ -100,7 +100,7 @@ explain: "Это одна из стратегий работы с сущностями. Какие еще ответы здесь применимы?", correct: true }, - { + { text: "Когда токен имеет метку данной сущности, любой другой следующий токен с такой же меткой считается частью той же сущности, если только он не помечен как начало новой сущности.", explain: "Это самый распространенный способ группировки сущностей - однако это не единственный правильный ответ.", correct: true @@ -125,7 +125,7 @@ explain: "Это правильный ответ!", correct: true }, - { + { text: "Он разбивает контекст на несколько частей (без перекрытия, для эффективности) и находит максимальную оценку для ответа в каждой части.", explain: "Нет, он включает в себя некоторое перекрытие частей, чтобы избежать ситуации, когда ответ будет разбит на две части." } @@ -149,7 +149,7 @@ text: "Это последний этап постобработки, на котором токенизатор добавляет специальные токены.", explain: "Этот этап называется просто постобработкой." }, - { + { text: "Это когда эмбеддинги создаются со среднеквадратичным отклонением 0 и стандартным отклонением 1, путем вычитания среднеквадратичного и деления на стандартное отклонение.", explain: "Этот процесс обычно называется нормализацией, когда применяется к значениям пикселей в компьютерном зрении, но это не то, что означает нормализация в NLP." } @@ -173,7 +173,7 @@ explain: "Это правильный ответ!", correct: true }, - { + { text: "Это шаг, предшествующий применению модели токенизатора для разделения входных данных на токены.", explain: "Нет, разбиение на части - это задача модели токенизатора." } @@ -210,7 +210,7 @@ { text: "BPE токенизирует слова в подслова, находя самое длинное подслово, которое есть в словаре, начиная с начала, а затем повторяя процесс для остальной части текста.", explain: "Нет, это способ работы другого алгоритма токенизации." - }, + } ]} /> @@ -243,7 +243,7 @@ text: "WordPiece токенизирует слова на подслова, находя самое длинное подслово, которое есть в словаре, начиная с начала, а затем повторяя процесс для остальной части текста.", explain: "Да, именно так работает WordPiece в процессе кодирования.", correct: true - }, + } ]} /> @@ -277,6 +277,6 @@ { text: "Unigram токенизирует слова на подслова, разбивая их на символы, а затем применяя правила слияния.", explain: "Нет, так работает другой алгоритм токенизации." - }, + } ]} /> From 5cffa31af67a30cdc586b8d46c4962ec27c0b184 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 21 Dec 2023 19:40:52 +0300 Subject: [PATCH 318/502] Update 10.mdx Correcting the syntax of some markup again) --- chapters/ru/chapter6/10.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/chapters/ru/chapter6/10.mdx b/chapters/ru/chapter6/10.mdx index 5593ee09b..45ff73711 100644 --- a/chapters/ru/chapter6/10.mdx +++ b/chapters/ru/chapter6/10.mdx @@ -230,6 +230,7 @@ { text: "Токенизаторы WordPiece учат правила слияния, объединяя пары токенов, которые встречаются чаще всего.", explain: "Нет, это стратегия, применяемая другим алгоритмом токенизации." + }, { text: "Токенизатор WordPiece изучает правило слияния, объединяя пары токенов, которые максимизируют оценку, отдающую предпочтение частым парам с менее частыми отдельными частями.", explain: "Правильно!", From d11fc346ad933eafbbda11b92d4462ba6fc334c2 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:15:35 +0300 Subject: [PATCH 319/502] Update chapters/ru/chapter6/4.mdx Yes, that space is redundant here. You're right about that. Co-authored-by: Maria Khalusova --- chapters/ru/chapter6/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter6/4.mdx b/chapters/ru/chapter6/4.mdx index 75706fdde..8127b26f8 100644 --- a/chapters/ru/chapter6/4.mdx +++ b/chapters/ru/chapter6/4.mdx @@ -49,7 +49,7 @@ print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü? -✏️ **Попробуйте! ** Загрузите токенизатор из контрольной точки `bert-base-cased` и передайте ему тот же пример. Какие основные различия вы можете увидеть между версией токенизатора cased и uncased? +✏️ **Попробуйте!** Загрузите токенизатор из контрольной точки `bert-base-cased` и передайте ему тот же пример. Какие основные различия вы можете увидеть между версией токенизатора cased и uncased? From ccbae71129c409c7b0c95200a91c150fbdfad1dd Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:16:19 +0300 Subject: [PATCH 320/502] Update chapters/ru/chapter6/4.mdx Extra space. I overlooked it. My mistake. Co-authored-by: Maria Khalusova --- chapters/ru/chapter6/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter6/4.mdx b/chapters/ru/chapter6/4.mdx index 8127b26f8..e3c04d37a 100644 --- a/chapters/ru/chapter6/4.mdx +++ b/chapters/ru/chapter6/4.mdx @@ -57,7 +57,7 @@ print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü? -Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2] (/course/chapter2), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. +Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2](/course/chapter2), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. Чтобы увидеть, как быстрый токенизатор выполняет предварительную токенизацию, мы можем воспользоваться методом `pre_tokenize_str()` атрибута `pre_tokenizer` объекта `tokenizer`: From 22bde78ceea15803105d62bb074820b3373cde1f Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:23:46 +0300 Subject: [PATCH 321/502] Update chapters/ru/chapter6/3.mdx There's an extra space here. You're right. Co-authored-by: Maria Khalusova --- chapters/ru/chapter6/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index 4829edf25..068076110 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -113,7 +113,7 @@ We can see that the tokenizer's special tokens `[CLS]` and `[SEP]` are mapped to Понятие "слово" очень сложное. Например, "I'll" (сокращение от "I will") считается одним или двумя словами? На самом деле это зависит от токенизатора и применяемой им операции предварительной токенизации. Некоторые токенизаторы просто разделяют пробелы, поэтому они будут считать это одним словом. Другие используют пунктуацию поверх пробелов, поэтому будут считать это двумя словами. -✏️ **Попробуйте! ** Создайте токенизатор из контрольных точек `bert-base-cased` и `roberta-base` и токенизируйте с их помощью "81s". Что вы заметили? Каковы идентификаторы слов? +✏️ **Попробуйте!** Создайте токенизатор из контрольных точек `bert-base-cased` и `roberta-base` и токенизируйте с их помощью "81s". Что вы заметили? Каковы идентификаторы слов?
From eaafdc531937a1621bb640208e32a2d07cddf17d Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:24:55 +0300 Subject: [PATCH 322/502] Update chapters/ru/chapter6/3.mdx There's an extra space here. You're right. Co-authored-by: Maria Khalusova --- chapters/ru/chapter6/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index 068076110..a6a7a204d 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -140,7 +140,7 @@ Sylvain ## Внутри конвейера `token-classification`[[inside-the-token-classification-pipeline]] -В [Главе 1](/course/chapter1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2] (/course/chapter2), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! +В [Главе 1](/course/chapter1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2](/course/chapter2), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! {#if fw === 'pt'} From ea57588762a397a8b4d6f678546eccf01f78ed96 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:29:01 +0300 Subject: [PATCH 323/502] Update chapters/ru/chapter6/3b.mdx Yeah, there's no need for a space here. Co-authored-by: Maria Khalusova --- chapters/ru/chapter6/3b.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter6/3b.mdx b/chapters/ru/chapter6/3b.mdx index f7921fdb6..73e78fce3 100644 --- a/chapters/ru/chapter6/3b.mdx +++ b/chapters/ru/chapter6/3b.mdx @@ -610,7 +610,7 @@ print(candidates) -✏️ **Попробуйте! ** Адаптируйте приведенный выше код, чтобы он возвращал оценки и промежутки для пяти наиболее вероятных ответов (в целом, а не по частям). +✏️ **Попробуйте!** Адаптируйте приведенный выше код, чтобы он возвращал оценки и промежутки для пяти наиболее вероятных ответов (в целом, а не по частям). From 0d340147496fdf549f4df5c29a4a6dda52375153 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:30:17 +0300 Subject: [PATCH 324/502] Update chapters/ru/chapter6/3.mdx Co-authored-by: Maria Khalusova --- chapters/ru/chapter6/3.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index a6a7a204d..d4353e1a1 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -105,7 +105,6 @@ encoding.word_ids() [None, 0, 1, 2, 3, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, None] ``` -We can see that the tokenizer's special tokens `[CLS]` and `[SEP]` are mapped to `None`, and then each token is mapped to the word it originates from. This is especially useful to determine if a token is at the start of a word or if two tokens are in the same word. We could rely on the `##` prefix for that, but it only works for BERT-like tokenizers; this method works for any type of tokenizer as long as it's a fast one. In the next chapter, we'll see how we can use this capability to apply the labels we have for each word properly to the tokens in tasks like named entity recognition (NER) and part-of-speech (POS) tagging. We can also use it to mask all the tokens coming from the same word in masked language modeling (a technique called _whole word masking_). Мы можем видеть, что специальные токены токенизатора `[CLS]` и `[SEP]` сопоставляются с `None`, а затем каждый токен сопоставляется со словом, от которого он происходит. Это особенно полезно для определения того, находится ли токен в начале слова или два токена в одном и том же слове. Для этого мы могли бы использовать префикс `##`, но он работает только для токенизаторов типа BERT; этот метод работает для любого типа токенизаторов, лишь бы он был быстрым. В следующей главе мы увидим, как можно использовать эту возможность для применения меток, которые мы имеем для каждого слова, к токенам в таких задачах, как распознавание именованных сущностей (NER) и тегирование частей речи (part-of-speech - POS). Мы также можем использовать ее для маскирования всех токенов, происходящих от одного и того же слова, при моделировании языка по маске (masked language modeling) (эта техника называется _маскированием всего слова (whole word masking)_). From 8a9bbbcb696bdfcd726d1550f1f0bb4bd3b1502b Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:32:45 +0300 Subject: [PATCH 325/502] Update 3.mdx --- chapters/ru/chapter6/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index d4353e1a1..0912e9d00 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -194,7 +194,7 @@ token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") - `"max"`, где оценка каждой сущности - это максимальная оценка токенов в этой сущности (так, для ""Hugging Face"" это будет 0.98879766, оценки "Face"). - `"average"`, где оценка каждой сущности - это средняя оценка слов, составляющих эту сущность (таким образом, для слова ""Sylvain"" не будет никаких отличий от стратегии `"simple"`, но "Hugging Face" будет иметь оценку 0.9819, среднюю оценку для "Hugging", 0.975, и "Face", 0.98879) -Now let's see how to obtain these results without using the `pipeline()` function! +Теперь давайте посмотрим, как получить эти результаты без использования функции `pipeline()`! ### От входных данных к прогнозам[[from-inputs-to-predictions]] From b5b2da8346237072fd1304840cc076c130397051 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:38:34 +0300 Subject: [PATCH 326/502] Update 7.mdx Translated the comments noted on the review. --- chapters/ru/chapter6/7.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/ru/chapter6/7.mdx b/chapters/ru/chapter6/7.mdx index 032c92f79..3b436be17 100644 --- a/chapters/ru/chapter6/7.mdx +++ b/chapters/ru/chapter6/7.mdx @@ -316,7 +316,7 @@ def compute_scores(model): scores = {} model_loss = compute_loss(model) for token, score in model.items(): - # We always keep tokens of length 1 + # Мы всегда храним токены длиной 1 if len(token) == 1: continue model_without_token = copy.deepcopy(model) @@ -353,7 +353,7 @@ percent_to_remove = 0.1 while len(model) > 100: scores = compute_scores(model) sorted_scores = sorted(scores.items(), key=lambda x: x[1]) - # Remove percent_to_remove tokens with the lowest scores. + # Удалите токены percent_to_remove с наименьшими оценками for i in range(int(len(model) * percent_to_remove)): _ = token_freqs.pop(sorted_scores[i][0]) From c67bdb033f709a29c6f1d501b7e85d307b0def06 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:42:10 +0300 Subject: [PATCH 327/502] Update 3.mdx Translated the missing comments in the code. --- chapters/ru/chapter6/3.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index 0912e9d00..25aa85b22 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -432,11 +432,11 @@ while idx < len(predictions): pred = predictions[idx] label = model.config.id2label[pred] if label != "O": - # Remove the B- or I- + # Удалим B- или I- label = label[2:] start, _ = offsets[idx] - # Grab all the tokens labeled with I-label + # Соберём все токены, помеченные I-меткой all_scores = [] while ( idx < len(predictions) @@ -446,7 +446,7 @@ while idx < len(predictions): _, end = offsets[idx] idx += 1 - # The score is the mean of all the scores of the tokens in that grouped entity + # Оценка является средним значением всех оценок токенов в этой сгруппированной сущности score = np.mean(all_scores).item() word = example[start:end] results.append( From 4b4f7111feca008cb1b0baf165549f1dfa283d68 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 22 Dec 2023 22:47:03 +0300 Subject: [PATCH 328/502] Update chapters/ru/chapter6/3b.mdx Yes, an extra space. Co-authored-by: Maria Khalusova --- chapters/ru/chapter6/3b.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter6/3b.mdx b/chapters/ru/chapter6/3b.mdx index 73e78fce3..7902ec2ff 100644 --- a/chapters/ru/chapter6/3b.mdx +++ b/chapters/ru/chapter6/3b.mdx @@ -635,7 +635,7 @@ for candidate, offset in zip(candidates, offsets): -✏️ **Попробуйте! ** Используйте лучшие оценки, которые вы вычислили ранее, чтобы показать пять наиболее вероятных ответов (для всего контекста, а не для каждого фрагмента). Чтобы проверить результаты, вернитесь к первому конвейеру и передайте `top_k=5` при его вызове. +✏️ **Попробуйте!** Используйте лучшие оценки, которые вы вычислили ранее, чтобы показать пять наиболее вероятных ответов (для всего контекста, а не для каждого фрагмента). Чтобы проверить результаты, вернитесь к первому конвейеру и передайте `top_k=5` при его вызове. From f00418f082a210baf92d70ab682ab0eab6b4f80d Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Mon, 25 Dec 2023 18:41:52 +0300 Subject: [PATCH 329/502] Update chapters/ru/chapter6/5.mdx Minor fix. Co-authored-by: Maria Khalusova --- chapters/ru/chapter6/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter6/5.mdx b/chapters/ru/chapter6/5.mdx index f28641f59..fa05c49ff 100644 --- a/chapters/ru/chapter6/5.mdx +++ b/chapters/ru/chapter6/5.mdx @@ -101,7 +101,7 @@ Corpus: ("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5 -✏️ ** Теперь ваша очередь! ** Как вы думаете, как будет токенизировано слово `'unhug''? +✏️ ** Теперь ваша очередь!** Как вы думаете, как будет токенизировано слово `'unhug'`? From 2bf5df968fc05f89768c0ec14401064d14c6741e Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Tue, 9 Jan 2024 20:30:43 +0300 Subject: [PATCH 330/502] Completed the translation of the first part of Chapter 7 into Russian. --- chapters/ru/_toctree.yml | 13 + chapters/ru/chapter7/1.mdx | 38 ++ chapters/ru/chapter7/2.mdx | 981 ++++++++++++++++++++++++++++++++ chapters/ru/chapter7/3.mdx | 1044 +++++++++++++++++++++++++++++++++++ chapters/ru/chapter7/4.mdx | 1002 +++++++++++++++++++++++++++++++++ chapters/ru/chapter7/5.mdx | 1073 ++++++++++++++++++++++++++++++++++++ 6 files changed, 4151 insertions(+) create mode 100644 chapters/ru/chapter7/1.mdx create mode 100644 chapters/ru/chapter7/2.mdx create mode 100644 chapters/ru/chapter7/3.mdx create mode 100644 chapters/ru/chapter7/4.mdx create mode 100644 chapters/ru/chapter7/5.mdx diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index 597730c46..fa28f0fca 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -113,6 +113,19 @@ title: Тест в конце главы quiz: 6 +- title: 7. Основные задачи NLP + sections: + - local: chapter7/1 + title: Введение + - local: chapter7/2 + title: Классификация токенов + - local: chapter7/3 + title: Дообучение модели маскированного языкового моделирования + - local: chapter7/4 + title: Перевод + - local: chapter7/5 + title: Суммаризация + - title: Глоссарий sections: - local: glossary/1 diff --git a/chapters/ru/chapter7/1.mdx b/chapters/ru/chapter7/1.mdx new file mode 100644 index 000000000..43df2873c --- /dev/null +++ b/chapters/ru/chapter7/1.mdx @@ -0,0 +1,38 @@ + + +# Введение[[introduction]] + + + +В [Главе 3] (/course/chapter3) вы узнали, как дообучить модель для классификации текстов. В этой главе мы рассмотрим следующие общие задачи NLP: + +- Классификация токенов (Token classification) +- Маскированное языковое моделирование (Masked language modeling, например, BERT) +- Резюмирование текста (Summarization) +- Перевод (Translation) +- Предварительное обучение каузального языкового моделирования (Causal language modeling, например, GPT-2) +- Ответы на вопросы (Question answering) + +{#if fw === 'pt'} + +Для этого вам понадобится использовать все, что вы узнали об API `Trainer` и библиотеке 🤗 Accelerate в [Главе 3](/course/chapter3), библиотеке 🤗 Datasets в [Главе 5](/course/chapter5) и библиотеке 🤗 Tokenizers в [Главе 6](/course/chapter6). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](/course/chapter4), так что это действительно глава,в которой все собирается воедино! + +Каждый раздел можно читать независимо друг от друга, и в нем вы узнаете, как обучить модель с помощью API `Trainer` или с помощью собственного цикла обучения, используя 🤗 Accelerate. Вы можете пропустить любую часть и сосредоточиться на той, которая вас больше всего интересует: API `Trainer` отлично подходит для того, чтобы дообучить или обучить вашу модель, не беспокоясь о том, что происходит за кулисами, а цикл обучения с `Accelerate` позволит вам легче настроить любую часть, которую вы хотите. + +{:else} + +Для этого вам понадобится использовать все, что вы узнали об обучении моделей с помощью Keras API в [Главе 3](/course/chapter3), библиотеке 🤗 Datasets в [Главе 5](/course/chapter5) и библиотеке 🤗 Tokenizers в [Главе 6](/course/chapter6). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](/course/chapter4), так что это действительно глава, в которой все собирается воедино! + +Каждый раздел можно читать самостоятельно. + +{/if} + + + + +Если вы будете читать разделы по порядку, то заметите, что в них довольно много общего в коде и тексте. Повторение сделано намеренно, чтобы вы могли погрузиться (или вернуться позже) в любую интересующую вас задачу и найти полный рабочий пример. + + diff --git a/chapters/ru/chapter7/2.mdx b/chapters/ru/chapter7/2.mdx new file mode 100644 index 000000000..7f7aa7b65 --- /dev/null +++ b/chapters/ru/chapter7/2.mdx @@ -0,0 +1,981 @@ + + +# Классификация токенов[[token-classification]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Первое приложение, которое мы рассмотрим, - это классификация токенов. Эта общая задача охватывает любую проблему, которую можно сформулировать как "присвоение метки каждому токену в предложении", например: + +- **Распознавание именованных сущностей (Named entity recognition - NER)**: Поиск сущностей (например, лиц, мест или организаций) в предложении. Это можно сформулировать как приписывание метки каждому токену, имея один класс для сущности и один класс для "нет сущности". +- **Морфологическая разметка (Part-of-speech tagging - POS)**: Пометить каждое слово в предложении как соответствующее определенной части речи (например, существительное, глагол, прилагательное и т. д.). +- **Выделение токенов (Chunking)**: Поиск токенов, принадлежащих одной и той же сущности. Эта задача (которая может быть объединена с POS или NER) может быть сформулирована как присвоение одной метки (обычно `B-`) всем токенам, которые находятся в начале фрагмента текста, другой метки (обычно `I-`) - токенам, которые находятся внутри фрагмента текста, и третьей метки (обычно `O`) - токенам, которые не принадлежат ни к одному фрагменту. + + + +Конечно, существует множество других типов задач классификации токенов; это лишь несколько показательных примеров. В этом разделе мы дообучим модель (BERT) для задачи NER, которая затем сможет вычислять прогнозы, подобные этому: + + + + +One-hot encoded labels for question answering. + + + +Вы можете найти модель, которую мы обучим и загрузим на хаб, и перепроверить ее предсказания [здесь](https://huggingface.co/huggingface-course/bert-finetuned-ner?text=My+name+is+Sylvain+and+I+work+at+Hugging+Face+in+Brooklyn). + +## Подготовка данных[[preparing-the-data]] + +Прежде всего, нам нужен набор данных, подходящий для классификации токенов. В этом разделе мы будем использовать [набор данных CoNLL-2003](https://huggingface.co/datasets/conll2003), который содержит новости от Reuters. + + + +💡 Если ваш набор данных состоит из текстов, часть которых состоит из слов с соответствующими метками, вы сможете адаптировать описанные здесь процедуры обработки данных к своему набору данных. Обратитесь к [Главе 5] (/course/chapter5), если вам нужно освежить в памяти то, как загружать собственные данные в `Dataset`. + + + +### Датасет CoNLL-2003[[the-conll-2003-dataset]] + +Для загрузки датасета CoNLL-2003 мы используем метод `load_dataset()` из библиотеки 🤗 Datasets: + +```py +from datasets import load_dataset + +raw_datasets = load_dataset("conll2003") +``` + +Это позволит загрузить и кэшировать датасет, как мы видели в [Главе 3](/course/chapter3) для датасета GLUE MRPC. Изучение этого объекта показывает нам присутствующие столбцы и части тренировочного, проверочного и тестового наборов: + +```py +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'], + num_rows: 14041 + }) + validation: Dataset({ + features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'], + num_rows: 3250 + }) + test: Dataset({ + features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'], + num_rows: 3453 + }) +}) +``` + +В частности, мы видим, что датасет содержит метки для трех задач, о которых мы говорили ранее: NER, POS и chunking. Существенным отличием от других датасетов является то, что входные тексты представлены не как предложения или документы, а как списки слов (последний столбец называется `tokens`, но он содержит слова в том смысле, что это предварительно токинизированные входные данные, которые еще должны пройти через токенизатор для токенизации по подсловам). + +Давайте посмотрим на первый элемент обучающего набора: + +```py +raw_datasets["train"][0]["tokens"] +``` + +```python out +['EU', 'rejects', 'German', 'call', 'to', 'boycott', 'British', 'lamb', '.'] +``` + +Поскольку мы хотим выполнить распознавание именованных сущностей, мы изучим теги NER: + +```py +raw_datasets["train"][0]["ner_tags"] +``` + +```python out +[3, 0, 7, 0, 0, 0, 7, 0, 0] +``` + +Это метки в виде целых чисел, готовые для обучения, но они не всегда полезны, когда мы хотим проанализировать данные. Как и в случае с классификацией текста, мы можем получить доступ к соответствию между этими целыми числами и названиями меток, посмотрев на атрибут `features` нашего датасета: + +```py +ner_feature = raw_datasets["train"].features["ner_tags"] +ner_feature +``` + +```python out +Sequence(feature=ClassLabel(num_classes=9, names=['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC', 'B-MISC', 'I-MISC'], names_file=None, id=None), length=-1, id=None) +``` + +Таким образом, этот столбец содержит элементы, которые являются последовательностями `ClassLabel`. Тип элементов последовательности указан в атрибуте `feature` этого `ner_feature`, и мы можем получить доступ к списку имен, посмотрев на атрибут `names` этого `feature`: + +```py +label_names = ner_feature.feature.names +label_names +``` + +```python out +['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC', 'B-MISC', 'I-MISC'] +``` + +Мы уже видели эти метки при изучении конвейера `token-classification` в [Главе 6] (/course/chapter6/3), но для краткости напомним: + +- `O` означает, что слово не соответствует какой-либо сущности. +- `B-PER`/`I-PER` означает, что слово соответствует началу/находится внутри сущности персоны *person*. +- `B-ORG`/`I-ORG` означает, что слово соответствует началу/находится внутри сущности *organization*. +- `B-LOC`/`I-LOC` означает, что слово соответствует началу/находится внутри сущности *location*. +- `B-MISC`/`I-MISC` означает, что слово соответствует началу/находится внутри сущности *miscellaneous*. + +Теперь декодирование меток, которые мы видели ранее, дает нам следующее: + +```python +words = raw_datasets["train"][0]["tokens"] +labels = raw_datasets["train"][0]["ner_tags"] +line1 = "" +line2 = "" +for word, label in zip(words, labels): + full_label = label_names[label] + max_length = max(len(word), len(full_label)) + line1 += word + " " * (max_length - len(word) + 1) + line2 += full_label + " " * (max_length - len(full_label) + 1) + +print(line1) +print(line2) +``` + +```python out +'EU rejects German call to boycott British lamb .' +'B-ORG O B-MISC O O O B-MISC O O' +``` + +В качестве примера смешивания меток `B-` и `I-`, вот что дает тот же код для элемента обучающего множества с индексом 4: + +```python out +'Germany \'s representative to the European Union \'s veterinary committee Werner Zwingmann said on Wednesday consumers should buy sheepmeat from countries other than Britain until the scientific advice was clearer .' +'B-LOC O O O O B-ORG I-ORG O O O B-PER I-PER O O O O O O O O O O O B-LOC O O O O O O O' +``` + +Как мы видим, сущностям, состоящим из двух слов, например "European Union" и "Werner Zwingmann", присваивается метка `B-` для первого слова и метка `I-` для второго. + + + +✏️ **Попробуйте!** Выведите те же два предложения с метками POS или chunking. + + + +### Обработка данных[[processing-the-data]] + + + +Как обычно, наши тексты должны быть преобразованы в идентификаторы токенов, прежде чем модель сможет понять их смысл. Как мы видели в [Главе 6](/course/chapter6/), существенным отличием задачи классификации токенов является то, что у нас есть предварительно токенизированные входные данные. К счастью, API токенизатора справляется с этим довольно легко; нам просто нужно предупредить `tokenizer` специальным флагом. + +Для начала давайте создадим объект `tokenizer`. Как мы уже говорили, мы будем использовать предварительно обученную модель BERT, поэтому начнем с загрузки и кэширования соответствующего токенизатора: + +```python +from transformers import AutoTokenizer + +model_checkpoint = "bert-base-cased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +Вы можете заменить `model_checkpoint` на любую другую модель из [Hub](https://huggingface.co/models) или на локальную папку, в которой вы сохранили предварительно обученную модель и токенизатор. Единственное ограничение - токенизатор должен быть создан с помощью библиотеки 🤗 Tokenizers, поэтому существует "быстрая" версия. Вы можете увидеть все архитектуры, которые поставляются с быстрой версией в [этой большой таблице](https://huggingface.co/transformers/#supported-frameworks), а чтобы проверить, что используемый вами объект `tokenizer` действительно поддерживается 🤗 Tokenizers, вы можете посмотреть на его атрибут `is_fast`: + +```py +tokenizer.is_fast +``` + +```python out +True +``` + +Для токенизации предварительно токинизированного ввода мы можем использовать наш `tokenizer`, как обычно, просто добавив `is_split_into_words=True`: + +```py +inputs = tokenizer(raw_datasets["train"][0]["tokens"], is_split_into_words=True) +inputs.tokens() +``` + +```python out +['[CLS]', 'EU', 'rejects', 'German', 'call', 'to', 'boycott', 'British', 'la', '##mb', '.', '[SEP]'] +``` + +Как мы видим, токенизатор добавил специальные токены, используемые моделью (`[CLS]` в начале и `[SEP]` в конце), и оставил большинство слов нетронутыми. Слово `lamb`, однако, было токенизировано на два подслова, `la` и `##mb`. Это вносит несоответствие между нашими входными данными и метками: список меток состоит всего из 9 элементов, в то время как наши входные данные теперь содержат 12 токенов. Учесть специальные токены легко (мы знаем, что они находятся в начале и в конце), но нам также нужно убедиться, что мы выровняли все метки с соответствующими словами. + +К счастью, поскольку мы используем быстрый токенизатор, у нас есть доступ к суперспособностям 🤗 Tokenizers, что означает, что мы можем легко сопоставить каждый токен с соответствующим словом (как показано в [Глава 6](/course/chapter6/3)): + +```py +inputs.word_ids() +``` + +```python out +[None, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, None] +``` + +Немного поработав, мы сможем расширить список меток, чтобы он соответствовал токенам. Первое правило, которое мы применим, заключается в том, что специальные токены получают метку `-100`. Это связано с тем, что по умолчанию `-100` - это индекс, который игнорируется в функции потерь, которую мы будем использовать (кросс-энтропия). Затем каждый токен получает ту же метку, что и токен, с которого началось слово, в котором он находится, поскольку они являются частью одной и той же сущности. Для токенов, находящихся внутри слова, но не в его начале, мы заменяем `B-` на `I-` (поскольку такие токены не являются началом сущности): + +```python +def align_labels_with_tokens(labels, word_ids): + new_labels = [] + current_word = None + for word_id in word_ids: + if word_id != current_word: + # Начало нового слова! + current_word = word_id + label = -100 if word_id is None else labels[word_id] + new_labels.append(label) + elif word_id is None: + # Специальный токен + new_labels.append(-100) + else: + # То же слово, что и предыдущий токен + label = labels[word_id] + # If the label is B-XXX we change it to I-XXX + if label % 2 == 1: + label += 1 + new_labels.append(label) + + return new_labels +``` + +Давайте опробуем это на нашем первом предложении: + +```py +labels = raw_datasets["train"][0]["ner_tags"] +word_ids = inputs.word_ids() +print(labels) +print(align_labels_with_tokens(labels, word_ids)) +``` + +```python out +[3, 0, 7, 0, 0, 0, 7, 0, 0] +[-100, 3, 0, 7, 0, 0, 0, 7, 0, 0, 0, -100] +``` + +Как мы видим, наша функция добавила `-100` для двух специальных токенов в начале и в конце и новый `0` для нашего слова, которое было разбито на две части. + + + +✏️ **Попробуйте!** Некоторые исследователи предпочитают назначать только одну метку на слово и присваивать `-100` другим подтокенам в данном слове. Это делается для того, чтобы длинные слова, часть которых состоит из множества субтокенов, не вносили значительный вклад в потери. + + + +Чтобы предварительно обработать весь наш датасет, нам нужно провести токенизацию всех входных данных и применить `align_labels_with_tokens()` ко всем меткам. Чтобы воспользоваться преимуществами скорости нашего быстрого токенизатора, лучше всего токенизировать много текстов одновременно, поэтому мы напишем функцию, которая обрабатывает список примеров и использует метод `Dataset.map()` с параметром `batched=True`. Единственное отличие от нашего предыдущего примера заключается в том, что функция `word_ids()` должна получить индекс примера, идентификаторы слов которого нам нужны, с учётом того что входными данными для токенизатора являются списки текстов (или, в нашем случае, списки слов), поэтому мы добавляем и это: + +```py +def tokenize_and_align_labels(examples): + tokenized_inputs = tokenizer( + examples["tokens"], truncation=True, is_split_into_words=True + ) + all_labels = examples["ner_tags"] + new_labels = [] + for i, labels in enumerate(all_labels): + word_ids = tokenized_inputs.word_ids(i) + new_labels.append(align_labels_with_tokens(labels, word_ids)) + + tokenized_inputs["labels"] = new_labels + return tokenized_inputs +``` + +Обратите внимание, что мы еще не добавляли во входные данные дополняющие токены; мы сделаем это позже, при создании батчей с помощью коллатора данных. + +Теперь мы можем применить всю эту предварительную обработку к другим частям нашего датасета: + +```py +tokenized_datasets = raw_datasets.map( + tokenize_and_align_labels, + batched=True, + remove_columns=raw_datasets["train"].column_names, +) +``` + +Мы сделали самую сложную часть! Теперь, когда данные прошли предварительную обработку, само обучение будет выглядеть примерно так, как мы делали это в [Главе 3](/course/chapter3). + +{#if fw === 'pt'} + +## Дообучение модели с помощью API `Trainer`[[fine-tuning-the-model-with-the-trainer-api]] + +Фактический код, использующий `Trainer`, будет таким же, как и раньше; единственные изменения - это способ объединения данных в батч и функция вычисления метрики. + +{:else} + +## Дообучение модели с помощью Keras[[fine-tuning-the-model-with-keras]] + +Фактический код, использующий Keras, будет очень похож на предыдущий; единственные изменения - это способ объединения данных в батч и функция вычисления метрики. + +{/if} + + +### Сопоставление данных[[data-collation]] + +Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](/course/chapter3), потому что в этом случае дополняются только входные данные (идентификаторы входов, маска внимания и идентификаторы типов токенов). Здесь наши метки должны быть дополнены точно так же, как и входы, чтобы они оставались одного размера, используя `-100` в качестве значения, чтобы соответствующие прогнозы игнорировались при вычислении потерь. + +Все это делает [`DataCollatorForTokenClassification`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorfortokenclassification). Как и `DataCollatorWithPadding`, он принимает `токенизатор`, используемый для предварительной обработки входных данных: + +{#if fw === 'pt'} + +```py +from transformers import DataCollatorForTokenClassification + +data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer) +``` + +{:else} + +```py +from transformers import DataCollatorForTokenClassification + +data_collator = DataCollatorForTokenClassification( + tokenizer=tokenizer, return_tensors="tf" +) +``` + +{/if} + +Чтобы проверить его на нескольких примерах, мы можем просто вызвать его на списке примеров из нашего токенизированного обучающего набора: + +```py +batch = data_collator([tokenized_datasets["train"][i] for i in range(2)]) +batch["labels"] +``` + +```python out +tensor([[-100, 3, 0, 7, 0, 0, 0, 7, 0, 0, 0, -100], + [-100, 1, 2, -100, -100, -100, -100, -100, -100, -100, -100, -100]]) +``` + +Давайте сравним это с метками для первого и второго элементов в нашем датасете: + +```py +for i in range(2): + print(tokenized_datasets["train"][i]["labels"]) +``` + +```python out +[-100, 3, 0, 7, 0, 0, 0, 7, 0, 0, 0, -100] +[-100, 1, 2, -100] +``` + +{#if fw === 'pt'} + +Как мы видим, второй набор меток был дополнен до длины первого с помощью значения `-100`. + +{:else} + +Наш коллатор данных готов к работе! Теперь давайте используем его для создания датасета `tf.data.Dataset` с помощью метода `to_tf_dataset()`. Вы также можете использовать `model.prepare_tf_dataset()`, чтобы сделать это с меньшим количеством кода - вы увидите это в некоторых других разделах этой главы. + +```py +tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( + columns=["attention_mask", "input_ids", "labels", "token_type_ids"], + collate_fn=data_collator, + shuffle=True, + batch_size=16, +) + +tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset( + columns=["attention_mask", "input_ids", "labels", "token_type_ids"], + collate_fn=data_collator, + shuffle=False, + batch_size=16, +) +``` + + + Next stop: the model itself. + +{/if} + +{#if fw === 'tf'} + +### Определение модели[[defining-the-model]] + +Поскольку мы работаем над проблемой классификации токенов, мы будем использовать класс `TFAutoModelForTokenClassification`. Главное, что нужно помнить при определении этой модели, - это передать информацию о количестве имеющихся у нас меток. Проще всего передать это число с помощью аргумента `num_labels`, но если мы хотим получить красивый виджет инференса, подобный тому, что мы видели в начале этого раздела, то лучше задать правильные соответствия меток. + +Они должны быть заданы двумя словарями, `id2label` и `label2id`, которые содержат отображение идентификатора в метку и наоборот: + +```py +id2label = {i: label for i, label in enumerate(label_names)} +label2id = {v: k for k, v in id2label.items()} +``` + +Теперь мы можем просто передать их в метод `TFAutoModelForTokenClassification.from_pretrained()`, и они будут заданы в конфигурации модели, затем правильно сохранены и загружены в Hub: + +```py +from transformers import TFAutoModelForTokenClassification + +model = TFAutoModelForTokenClassification.from_pretrained( + model_checkpoint, + id2label=id2label, + label2id=label2id, +) +``` + +Как и при определении `TFAutoModelForSequenceClassification` в [Главе 3](/course/chapter3), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (веса из предварительно обученной головы), а другие веса инициализированы случайно (веса из новой головы классификации токенов), и что эту модель нужно обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: + +```python +model.config.num_labels +``` + +```python out +9 +``` + + + +⚠️ Если у вас есть модель с неправильным количеством меток, то при последующем вызове `model.fit()` вы получите непонятную ошибку. Это может вызвать раздражение при отладке, поэтому обязательно выполните эту проверку, чтобы убедиться, что у вас есть ожидаемое количество меток. + + + +### Дообучение модели[[fine-tuning-the-model]] + +Теперь мы готовы к обучению нашей модели! Однако сначала нам нужно сделать еще немного работы: войти в Hugging Face и определить гиперпараметры обучения. Если вы работаете в блокноте, есть удобная функция, которая поможет вам в этом: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +Появится виджет, в котором вы можете ввести свои учетные данные для входа в Hugging Face. + +Если вы работаете не в блокноте, просто введите следующую строку в терминале: + +```bash +huggingface-cli login +``` + +После входа в аккаунт мы можем подготовить все необходимое для компиляции нашей модели. 🤗 Transformers предоставляет удобную функцию `create_optimizer()`, которая создаст вам оптимизатор `AdamW` с соответствующими настройками затухания весов и затухания скорости обучения, что позволит улучшить качество вашей модели по сравнению со встроенным оптимизатором `Adam`: + +```python +from transformers import create_optimizer +import tensorflow as tf + +# Обучение со смешанной точностью float16 +# Закомментируйте эту строку, если вы используете GPU, которому это не принесет никаких преимуществ +tf.keras.mixed_precision.set_global_policy("mixed_float16") + +# Количество шагов обучения - это количество примеров в датасете, разделенное на размер батча, затем умноженное +# на общее количество эпох. Обратите внимание, что tf_train_dataset здесь - это разбитое на батчи tf.data.Dataset, +# а не оригинальный датасет Hugging Face, поэтому его len() уже равен num_samples // batch_size. +num_epochs = 3 +num_train_steps = len(tf_train_dataset) * num_epochs + +optimizer, schedule = create_optimizer( + init_lr=2e-5, + num_warmup_steps=0, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) +``` + +Обратите внимание, что мы не указываем аргумент `loss` в `compile()`. Это связано с тем, что модели могут вычислять потери внутри себя - если вы компилируете без потерь и предоставляете свои метки во входном словаре (как мы делаем в наших датасетах), то модель будет обучаться, используя эти внутренние потери, которые будут соответствовать задаче и типу выбранной вами модели. + +Далее мы определяем `PushToHubCallback` для загрузки нашей модели в Hub во время обучения модели с помощью этого обратного вызова: + +```python +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback(output_dir="bert-finetuned-ner", tokenizer=tokenizer) + +model.fit( + tf_train_dataset, + validation_data=tf_eval_dataset, + callbacks=[callback], + epochs=num_epochs, +) +``` + +С помощью аргумента `hub_model_id` можно указать полное имя репозитория, в который вы хотите передать модель (в частности, этот аргумент нужно использовать, чтобы передать модель в организацию). Например, когда мы отправили модель в [организацию `huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/bert-finetuned-ner"`. По умолчанию используемое хранилище будет находиться в вашем пространстве имен и называться в соответствии с заданной вами выходной директорией, например `"cool_huggingface_user/bert-finetuned-ner"`. + + + +💡 Если выходной каталог, который вы используете, уже существует, он должен быть локальным клоном репозитория, в который вы хотите выполнить push. Если это не так, вы получите ошибку при вызове `model.fit()` и должны будете задать новое имя. + + + +Обратите внимание, что во время обучения каждый раз, когда модель сохраняется (здесь - каждую эпоху), она загружается на хаб в фоновом режиме. Таким образом, при необходимости вы сможете возобновить обучение на другой машине. + +На этом этапе вы можете использовать виджет инференса на Model Hub, чтобы протестировать свою модель и поделиться ею с друзьями. Вы успешно дообучили модель для задачи классификации токенов - поздравляем! Но насколько хороша наша модель на самом деле? Чтобы выяснить это, нам следует оценить некоторые метрики. + +{/if} + + +### Метрики[[metrics]] + +{#if fw === 'pt'} + +Чтобы `Trainer` вычислял метрику каждую эпоху, нам нужно определить функцию `compute_metrics()`, которая принимает массивы прогнозов и меток и возвращает словарь с именами и значениями метрик. + +Традиционно для оценки прогнозирования классификации токенов используется библиотека [*seqeval*](https://github.com/chakki-works/seqeval). Чтобы использовать эту метрику, сначала нужно установить библиотеку *seqeval*: + +```py +!pip install seqeval +``` + +Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](/course/chapter3): + +{:else} + +Традиционно для оценки прогнозирования классификации токенов используется библиотека [*seqeval*](https://github.com/chakki-works/seqeval). Чтобы использовать эту метрику, сначала нужно установить библиотеку *seqeval*: + +```py +!pip install seqeval +``` + +Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](/course/chapter3): + +{/if} + +```py +import evaluate + +metric = evaluate.load("seqeval") +``` + +Эта метрика ведет себя не так, как стандартная accuracy: на самом деле она принимает списки меток как строки, а не как целые числа, поэтому нам нужно полностью декодировать прогноз и метки перед передачей их в метрику. Давайте посмотрим, как это работает. Сначала мы получим метки для нашего первого обучающего примера: + +```py +labels = raw_datasets["train"][0]["ner_tags"] +labels = [label_names[i] for i in labels] +labels +``` + +```python out +['B-ORG', 'O', 'B-MISC', 'O', 'O', 'O', 'B-MISC', 'O', 'O'] +``` + +Затем мы можем создать фальшивые прогнозы для них, просто изменив значение в индексе 2: + +```py +predictions = labels.copy() +predictions[2] = "O" +metric.compute(predictions=[predictions], references=[labels]) +``` + +Обратите внимание, что метрика принимает список прогнозов (не только один) и список меток. Вот результат: + +```python out +{'MISC': {'precision': 1.0, 'recall': 0.5, 'f1': 0.67, 'number': 2}, + 'ORG': {'precision': 1.0, 'recall': 1.0, 'f1': 1.0, 'number': 1}, + 'overall_precision': 1.0, + 'overall_recall': 0.67, + 'overall_f1': 0.8, + 'overall_accuracy': 0.89} +``` + +{#if fw === 'pt'} + +Она возвращает огромное количество информации! Мы получаем оценки precision, recall и F1 для каждой отдельной сущности, а также в целом. Для расчета метрик мы сохраним только общую оценку, но вы можете настроить функцию `compute_metrics()` так, чтобы она возвращала все метрики, которые вы хотите получить. + +Эта функция `compute_metrics()` сначала берет argmax логитов, чтобы преобразовать их в прогнозы (как обычно, логиты и вероятности расположены в том же порядке, поэтому нам не нужно применять softmax). Затем нам нужно преобразовать метки и прогнозы из целых чисел в строки. Мы удаляем все значения, для которых метка равна `-100`, а затем передаем результаты в метод `metric.compute()`: + +```py +import numpy as np + + +def compute_metrics(eval_preds): + logits, labels = eval_preds + predictions = np.argmax(logits, axis=-1) + + # Удаляем игнорируемый индекс (специальные токены) и преобразуем в метки + true_labels = [[label_names[l] for l in label if l != -100] for label in labels] + true_predictions = [ + [label_names[p] for (p, l) in zip(prediction, label) if l != -100] + for prediction, label in zip(predictions, labels) + ] + all_metrics = metric.compute(predictions=true_predictions, references=true_labels) + return { + "precision": all_metrics["overall_precision"], + "recall": all_metrics["overall_recall"], + "f1": all_metrics["overall_f1"], + "accuracy": all_metrics["overall_accuracy"], + } +``` + +Теперь, когда это сделано, мы почти готовы к определению нашего `Trainer`. Нам просто нужна `model`, чтобы дообучить ее! + +{:else} + +Она возвращает огромное количество информации! Мы получаем оценки precision, recall и F1 для каждой отдельной сущности, а также в целом. Теперь давайте посмотрим, что произойдет, если мы попробуем использовать реальные прогнозы модели для вычисления реальных оценок. + +TensorFlow не любит конкатенировать наши прогнозы, поскольку они имеют переменную длину последовательности. Это означает, что мы не можем просто использовать `model.predict()` - но это нас не остановит. Мы будем получать прогнозы по батчу за раз и конкатенировать их в один большой длинный список по мере продвижения, отбрасывая токены `-100`, которые указывают на маскирование/дополнение, а затем вычислять метрики для списка в конце: + +```py +import numpy as np + +all_predictions = [] +all_labels = [] +for batch in tf_eval_dataset: + logits = model.predict_on_batch(batch)["logits"] + labels = batch["labels"] + predictions = np.argmax(logits, axis=-1) + for prediction, label in zip(predictions, labels): + for predicted_idx, label_idx in zip(prediction, label): + if label_idx == -100: + continue + all_predictions.append(label_names[predicted_idx]) + all_labels.append(label_names[label_idx]) +metric.compute(predictions=[all_predictions], references=[all_labels]) +``` + + +```python out +{'LOC': {'precision': 0.91, 'recall': 0.92, 'f1': 0.91, 'number': 1668}, + 'MISC': {'precision': 0.70, 'recall': 0.79, 'f1': 0.74, 'number': 702}, + 'ORG': {'precision': 0.85, 'recall': 0.90, 'f1': 0.88, 'number': 1661}, + 'PER': {'precision': 0.95, 'recall': 0.95, 'f1': 0.95, 'number': 1617}, + 'overall_precision': 0.87, + 'overall_recall': 0.91, + 'overall_f1': 0.89, + 'overall_accuracy': 0.97} +``` + +Как ваша модель показала себя по сравнению с нашей? Если вы получили похожие цифры, значит, ваше обучение прошло успешно! + +{/if} + +{#if fw === 'pt'} + +### Определение модели[[defining-the-model]] + +Поскольку мы работаем над проблемой классификации токенов, мы будем использовать класс `AutoModelForTokenClassification`. Главное, что нужно помнить при определении этой модели, - это передать информацию о количестве имеющихся у нас меток. Проще всего передать это число с помощью аргумента `num_labels`, но если мы хотим получить красивый виджет инференса, подобный тому, что мы видели в начале этого раздела, то лучше задать правильное сопоставление меток. + +Оно должно задаваться двумя словарями, `id2label` и `label2id`, которые содержат соответствие между идентификатором и меткой и наоборот: + +```py +id2label = {i: label for i, label in enumerate(label_names)} +label2id = {v: k for k, v in id2label.items()} +``` + +Теперь мы можем просто передать их в метод `AutoModelForTokenClassification.from_pretrained()`, и они будут заданы в конфигурации модели, а затем правильно сохранены и загружены в Hub: + +```py +from transformers import AutoModelForTokenClassification + +model = AutoModelForTokenClassification.from_pretrained( + model_checkpoint, + id2label=id2label, + label2id=label2id, +) +``` + +Как и в случае определения `AutoModelForSequenceClassification` в [Главе 3](/course/chapter3), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (те, что были получены из предварительно обученной головы), а другие инициализированы случайно (те, что были получены из новой головы классификации токенов), и что эту модель необходимо обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: + +```python +model.config.num_labels +``` + +```python out +9 +``` + + + +⚠️ Если у вас есть модель с неправильным количеством меток, то при последующем вызове метода `Trainer.train()` вы получите непонятную ошибку (что-то вроде "CUDA error: device-side assert triggered"). Это главная причина ошибок, о которых сообщают пользователи, поэтому обязательно выполните эту проверку, чтобы убедиться, что у вас есть ожидаемое количество меток. + + + +### Дообучение модели[[fine-tuning-the-model]] + +Теперь мы готовы к обучению нашей модели! Нам осталось сделать две последние вещи, прежде чем мы определим наш `Trainer`: войти в Hugging Face и определить наши аргументы для обучения. Если вы работаете в блокноте, есть удобная функция, которая поможет вам в этом: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +Появится виджет, в котором вы можете ввести свои учетные данные для входа в Hugging Face. + +Если вы работаете не в ноутбуке, просто введите следующую строку в терминале: + +```bash +huggingface-cli login +``` + +Как только это будет сделано, мы сможем определить наши `TrainingArguments`: + +```python +from transformers import TrainingArguments + +args = TrainingArguments( + "bert-finetuned-ner", + evaluation_strategy="epoch", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, + push_to_hub=True, +) +``` + +Большинство из них вы уже видели: мы задаем некоторые гиперпараметры (например, скорость обучения, количество эпох для обучения и затухание весов) и указываем `push_to_hub=True`, чтобы указать, что мы хотим сохранить модель и оценить ее в конце каждой эпохи, а также что мы хотим загрузить наши результаты в Model Hub. Обратите внимание, что с помощью аргумента `hub_model_id` можно указать имя репозитория, в который вы хотите передать модель (в частности, этот аргумент нужно использовать, чтобы передать модель в организацию). Например, когда мы передавали модель в [организацию`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/bert-finetuned-ner"` в `TrainingArguments`. По умолчанию используемый репозиторий будет находиться в вашем пространстве имен и называться в соответствии с заданным вами выходным каталогом, так что в нашем случае это будет `"sgugger/bert-finetuned-ner"`. + + + +💡 Если выходной каталог, который вы используете, уже существует, он должен быть локальным клоном репозитория, в который вы хотите передать модель. Если это не так, вы получите ошибку при определении вашего `Trainer` и должны будете задать новое имя. + + + +Наконец, мы просто передаем все в `Trainer` и запускаем обучение: + +```python +from transformers import Trainer + +trainer = Trainer( + model=model, + args=args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + compute_metrics=compute_metrics, + tokenizer=tokenizer, +) +trainer.train() +``` + +Обратите внимание, что во время обучения каждый раз, когда модель сохраняется (здесь - каждую эпоху), она загружается в Hub в фоновом режиме. Таким образом, при необходимости вы сможете возобновить обучение на другой машине. + +После завершения обучения мы используем метод `push_to_hub()`, чтобы убедиться, что загружена самая последняя версия модели: + +```py +trainer.push_to_hub(commit_message="Training complete") +``` + +Эта команда возвращает URL только что выполненного commit, если вы хотите его проверить: + +```python out +'https://huggingface.co/sgugger/bert-finetuned-ner/commit/26ab21e5b1568f9afeccdaed2d8715f571d786ed' +``` + + `Trainer` также создает черновик карточки модели со всеми результатами оценки и загружает его. На этом этапе вы можете использовать виджет инференса на Model Hub, чтобы протестировать свою модель и поделиться ею с друзьями. Вы успешно дообучили модель для задачи классификации токенов - поздравляем! + + Если вы хотите более глубоко погрузиться в цикл обучения, мы покажем вам, как сделать то же самое с помощью 🤗 Accelerate. + +## Индивидуальный цикл обучения[[a-custom-training-loop]] + +Теперь давайте рассмотрим полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет очень похож на тот, что мы делали в [Главе 3](/course/chapter3/4), с некоторыми изменениями для оценки. + +### Подготовка всего к обучению[[preparing-everything-for-training]] + +Сначала нам нужно создать `DataLoader` для наших датасетов. Мы используем наш `data_collator` в качестве `collate_fn` и перемешиваем обучающий набор, но не валидационный: + +```py +from torch.utils.data import DataLoader + +train_dataloader = DataLoader( + tokenized_datasets["train"], + shuffle=True, + collate_fn=data_collator, + batch_size=8, +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], collate_fn=data_collator, batch_size=8 +) +``` + +Затем мы повторно инстанцируем нашу модель, чтобы убедиться, что мы не продолжаем дообучать модель, а снова начинаем с предварительно обученной модели BERT: + +```py +model = AutoModelForTokenClassification.from_pretrained( + model_checkpoint, + id2label=id2label, + label2id=label2id, +) +``` + +Тогда нам понадобится оптимизатор. Мы будем использовать классический `AdamW`, который похож на `Adam`, но с исправлениями в способе применения затухания весов: + +```py +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=2e-5) +``` + +Когда у нас есть все эти объекты, мы можем отправить их в метод `accelerator.prepare()`: + +```py +from accelerate import Accelerator + +accelerator = Accelerator() +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + + + +🚨 Если вы обучаетесь на TPU, вам нужно будет перенести весь код, начиная с ячейки выше, в специальную функцию обучения. Подробнее смотрите [Главу 3](/course/chapter3). + + + +Теперь, когда мы отправили наш `train_dataloader` в `accelerator.prepare()`, мы можем использовать его длину для вычисления количества шагов обучения. Помните, что это всегда нужно делать после подготовки загрузчика данных, так как этот метод изменит его длину. Мы используем классический линейный планировшик скорости обучения до 0: + +```py +from transformers import get_scheduler + +num_train_epochs = 3 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +Наконец, чтобы передать нашу модель в Hub, нам нужно создать объект `Repository` в рабочей папке. Сначала авторизуйтесь в Hugging Face, если вы еще не авторизованы. Мы определим имя репозитория по идентификатору модели, который мы хотим присвоить нашей модели (не стесняйтесь заменить `repo_name` на свой собственный выбор; он просто должен содержать ваше имя пользователя, что и делает функция `get_full_repo_name()`): + +```py +from huggingface_hub import Repository, get_full_repo_name + +model_name = "bert-finetuned-ner-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'sgugger/bert-finetuned-ner-accelerate' +``` + +Затем мы можем клонировать этот репозиторий в локальную папку. Если она уже существует, эта локальная папка должна быть существующим клоном репозитория, с которым мы работаем: + +```py +output_dir = "bert-finetuned-ner-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +Теперь мы можем загрузить все, что сохранили в `output_dir`, вызвав метод `repo.push_to_hub()`. Это поможет нам загружать промежуточные модели в конце каждой эпохи. + +### Цикл обучения[[training-loop]] + +Теперь мы готовы написать полный цикл обучения. Чтобы упростить его оценочную часть, мы определяем функцию `postprocess()`, которая принимает прогнозы и метки и преобразует их в списки строк, как того ожидает наш объект `metric`: + +```py +def postprocess(predictions, labels): + predictions = predictions.detach().cpu().clone().numpy() + labels = labels.detach().cpu().clone().numpy() + + # Удаляем игнорируемый индекс (специальные токены) и преобразуем в метки + true_labels = [[label_names[l] for l in label if l != -100] for label in labels] + true_predictions = [ + [label_names[p] for (p, l) in zip(prediction, label) if l != -100] + for prediction, label in zip(predictions, labels) + ] + return true_labels, true_predictions +``` + +Затем мы можем написать цикл обучения. После определения прогресс-бара, чтобы следить за ходом обучения, цикл состоит из трех частей: + +- Само обучение представляет собой классическую итерацию по `train_dataloader`, прямой проход по модели, затем обратный проход и шаг оптимизатора. +- Оценка, в которой есть новшество после получения выходов нашей модели на батче: поскольку два процесса могли дополнять входы и метки до разных форм, нам нужно использовать `accelerator.pad_across_processes()`, чтобы сделать прогнозы и метки одинаковой формы перед вызовом метода `gather()`. Если мы этого не сделаем, оценка либо завершится с ошибкой, либо зависнет навсегда. Затем мы отправляем результаты в `metric.add_batch()` и вызываем `metric.compute()` после завершения цикла оценки. +- Сохранение и загрузка, где мы сначала сохраняем модель и токенизатор, а затем вызываем `repo.push_to_hub()`. Обратите внимание, что мы используем аргумент `blocking=False`, чтобы указать библиотеке 🤗 Hub на выполнение push в асинхронном процессе. Таким образом, обучение продолжается нормально, а эта (длинная) инструкция выполняется в фоновом режиме. + +Вот полный код цикла обучения: + +```py +from tqdm.auto import tqdm +import torch + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Обучение + model.train() + for batch in train_dataloader: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Оценка + model.eval() + for batch in eval_dataloader: + with torch.no_grad(): + outputs = model(**batch) + + predictions = outputs.logits.argmax(dim=-1) + labels = batch["labels"] + + # Необходимо добавить предсказания и метки для gather + predictions = accelerator.pad_across_processes(predictions, dim=1, pad_index=-100) + labels = accelerator.pad_across_processes(labels, dim=1, pad_index=-100) + + predictions_gathered = accelerator.gather(predictions) + labels_gathered = accelerator.gather(labels) + + true_predictions, true_labels = postprocess(predictions_gathered, labels_gathered) + metric.add_batch(predictions=true_predictions, references=true_labels) + + results = metric.compute() + print( + f"epoch {epoch}:", + { + key: results[f"overall_{key}"] + for key in ["precision", "recall", "f1", "accuracy"] + }, + ) + + # Сохранение и загрузка + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +Если вы впервые видите модель, сохраненную с помощью 🤗 Accelerate, давайте посмотрим на три строки кода, которые идут вместе с ним: + +```py +accelerator.wait_for_everyone() +unwrapped_model = accelerator.unwrap_model(model) +unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) +``` + +Первая строка не требует пояснений: она указывает всем процессам подождать, пока все не окажутся на этой стадии, прежде чем продолжить работу. Это нужно для того, чтобы убедиться, что у нас одна и та же модель в каждом процессе перед сохранением. Затем мы берем `unwrapped_model`, которая является базовой моделью, которую мы определили. Метод `accelerator.prepare()` изменяет модель для работы в распределенном обучении, поэтому у нее больше не будет метода `save_pretrained()`; метод `accelerator.unwrap_model()` отменяет этот шаг. Наконец, мы вызываем `save_pretrained()`, но указываем этому методу использовать `accelerator.save()` вместо `torch.save()`. + +После того как это будет сделано, у вас должна получиться модель, выдающая результаты, очень похожие на те, что были обучены с помощью `Trainer`. Вы можете посмотреть модель, которую мы обучили с помощью этого кода, на [*huggingface-course/bert-finetuned-ner-accelerate*](https://huggingface.co/huggingface-course/bert-finetuned-ner-accelerate). А если вы хотите протестировать какие-либо изменения в цикле обучения, вы можете напрямую реализовать их, отредактировав код, показанный выше! + +{/if} + +## Использование дообученной модели[[using-the-fine-tuned-model]] + +Мы уже показали вам, как можно использовать модель, которую мы дообучили на Model Hub, с помощью виджета инференса. Чтобы использовать ее локально в `pipeline`, нужно просто указать соответствующий идентификатор модели: + +```py +from transformers import pipeline + +# Замените это на свою собственную контрольную точку +model_checkpoint = "huggingface-course/bert-finetuned-ner" +token_classifier = pipeline( + "token-classification", model=model_checkpoint, aggregation_strategy="simple" +) +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity_group': 'PER', 'score': 0.9988506, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.9647625, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.9986118, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +Отлично! Наша модель работает так же хорошо, как и модель по умолчанию для этого конвейера! diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx new file mode 100644 index 000000000..934a38243 --- /dev/null +++ b/chapters/ru/chapter7/3.mdx @@ -0,0 +1,1044 @@ + + +# Дообучение модели маскированного языкового моделирования[[fine-tuning-a-masked-language-model]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Для многих приложений NLP, в которых используются модели-трансформеры, можно просто взять предварительно обученную модель из Hugging Face Hub и дообучить ее непосредственно на ваших данных для решения поставленной задачи. При условии, что корпус, использованный для предварительного обучения, не слишком отличается от корпуса, используемого для дообучения, трансферное обучение обычно дает хорошие результаты. + +Однако есть несколько случаев, когда перед обучением специфичной для конкретной задачи головы необходимо дообучить языковые модели на ваших данных. Например, если ваш датасет содержит юридические контракты или научные статьи, ванильная модель трансформер, такая как BERT, обычно рассматривает специфические для области слова в вашем корпусе как редкие токены, и результирующее качество может быть менее чем удовлетворительным. Дообучив языковую модель на данных из домена, вы сможете повысить качество работы во многих последующих задачах, а это значит, что обычно этот шаг нужно выполнить только один раз! + +Этот процесс дообучить предварительно обученную языковую модель на данных из домена обычно называют _доменной адаптацией (domain adaptation)_. Он был популяризирован в 2018 году благодаря [ULMFiT](https://arxiv.org/abs/1801.06146), которая стала одной из первых нейронных архитектур (основанных на LSTM), заставивших трансферное обучение действительно работать в NLP. Пример доменной адаптации с помощью ULMFiT показан на изображении ниже; в этом разделе мы сделаем нечто подобное, но с трансформером вместо LSTM! + +
+ULMFiT. + +
+ +К концу этого раздела у вас будет [модель маскированного языкового моделирования](https://huggingface.co/huggingface-course/distilbert-base-uncased-finetuned-imdb?text=This+is+a+great+%5BMASK%5D.) на Hub, которая позволяет автоматически дописывать предложения, как показано ниже: + + + +Давайте погрузимся в работу! + + + + + +🙋 Если термины "маскированное моделирование языка (masked language modeling)" и "предварительно обученная модель (pretrained model)" кажутся вам незнакомыми, загляните в [Главу 1](/course/chapter1), где мы объясняем все эти основные понятия, сопровождая их видеороликами! + + + +## Выбор предварительно обученной модели для маскированного моделирования языка[[picking-a-pretrained-model-for-masked-language-modeling]] + +Для начала давайте выберем подходящую предварительно обученную модель для маскированного языкового моделирования. Как показано на следующем скриншоте, вы можете найти список кандидатов, применив фильтр "Fill-Mask" на [Hugging Face Hub](https://huggingface.co/models?pipeline_tag=fill-mask&sort=downloads): + +
+Hub models. +
+ +Хотя модели семейства BERT и RoBERTa являются наиболее загружаемыми, мы будем использовать модель под названием [DistilBERT](https://huggingface.co/distilbert-base-uncased) +которая может быть обучена гораздо быстрее и практически без потерь в качестве. Эта модель была обучена с помощью специальной техники, называемой [_дистилляцией знаний (knowledge distillation)_](https://en.wikipedia.org/wiki/Knowledge_distillation), когда большая "модель-учитель", такая как BERT, используется для обучения "модели-ученика", имеющей гораздо меньше параметров. Объяснение деталей дистилляции знаний завело бы нас слишком далеко в этом разделе, но если вам интересно, вы можете прочитать об этом в [_Natural Language Processing with Transformers_](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/) (в просторечии известном как учебник по Трансформерам). + +{#if fw === 'pt'} + +Let's go ahead and download DistilBERT using the `AutoModelForMaskedLM` class: + +```python +from transformers import AutoModelForMaskedLM + +model_checkpoint = "distilbert-base-uncased" +model = AutoModelForMaskedLM.from_pretrained(model_checkpoint) +``` + +Мы можем узнать, сколько параметров имеет эта модель, вызвав метод `num_parameters()`: + +```python +distilbert_num_parameters = model.num_parameters() / 1_000_000 +print(f"'>>> DistilBERT number of parameters: {round(distilbert_num_parameters)}M'") +print(f"'>>> BERT number of parameters: 110M'") +``` + +```python out +'>>> DistilBERT number of parameters: 67M' +'>>> BERT number of parameters: 110M' +``` + +{:else} + +Давайте загрузим DistilBERT, используя класс `AutoModelForMaskedLM`: + +```python +from transformers import TFAutoModelForMaskedLM + +model_checkpoint = "distilbert-base-uncased" +model = TFAutoModelForMaskedLM.from_pretrained(model_checkpoint) +``` + +Мы можем узнать, сколько параметров имеет эта модель, вызвав метод `summary()`: + +```python +model.summary() +``` + +```python out +Model: "tf_distil_bert_for_masked_lm" +_________________________________________________________________ +Layer (type) Output Shape Param # +================================================================= +distilbert (TFDistilBertMain multiple 66362880 +_________________________________________________________________ +vocab_transform (Dense) multiple 590592 +_________________________________________________________________ +vocab_layer_norm (LayerNorma multiple 1536 +_________________________________________________________________ +vocab_projector (TFDistilBer multiple 23866170 +================================================================= +Total params: 66,985,530 +Trainable params: 66,985,530 +Non-trainable params: 0 +_________________________________________________________________ +``` + +{/if} + +Имея около 67 миллионов параметров, DistilBERT примерно в два раза меньше, чем базовая модель BERT, что примерно соответствует двукратному ускорению обучения - неплохо! Теперь посмотрим, какие виды токенов эта модель предсказывает как наиболее вероятные завершения небольшого образца текста: + +```python +text = "This is a great [MASK]." +``` + +Как люди, мы можем представить множество вариантов использования токена `[MASK]`, например "day (день)", "ride (поездка)" или "painting (картина)". Для предварительно обученных моделей прогнозы зависят от корпуса, на котором обучалась модель, поскольку она учится улавливать статистические закономерности, присутствующие в данных. Как и BERT, DistilBERT был предварительно обучен на датасетах [English Wikipedia](https://huggingface.co/datasets/wikipedia) и [BookCorpus](https://huggingface.co/datasets/bookcorpus), поэтому мы ожидаем, что прогнозы для `[MASK]` будут отражать эти домены. Для прогнозирования маски нам нужен токенизатор DistilBERT для создания входных данных для модели, поэтому давайте загрузим и его с хаба: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +Теперь, имея токенизатор и модель, мы можем передать наш текстовый пример в модель, извлечь логиты и вывести 5 лучших кандидатов: + +{#if fw === 'pt'} + +```python +import torch + +inputs = tokenizer(text, return_tensors="pt") +token_logits = model(**inputs).logits +# Определеним местоположения [MASK] и извлечем его логиты +mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1] +mask_token_logits = token_logits[0, mask_token_index, :] +# Выберем кандидатов [MASK] с наибольшими логитами +top_5_tokens = torch.topk(mask_token_logits, 5, dim=1).indices[0].tolist() + +for token in top_5_tokens: + print(f"'>>> {text.replace(tokenizer.mask_token, tokenizer.decode([token]))}'") +``` + +{:else} + +```python +import numpy as np +import tensorflow as tf + +inputs = tokenizer(text, return_tensors="np") +token_logits = model(**inputs).logits +# Определеним местоположения [MASK] и извлечем его логиты +mask_token_index = np.argwhere(inputs["input_ids"] == tokenizer.mask_token_id)[0, 1] +mask_token_logits = token_logits[0, mask_token_index, :] +# Выберем кандидатов [MASK] с наибольшими логитами +# Мы выполняем отрицание массива перед argsort, чтобы получить самые большие, а не самые маленькие логиты +top_5_tokens = np.argsort(-mask_token_logits)[:5].tolist() + +for token in top_5_tokens: + print(f">>> {text.replace(tokenizer.mask_token, tokenizer.decode([token]))}") +``` + +{/if} + +```python out +'>>> This is a great deal.' +'>>> This is a great success.' +'>>> This is a great adventure.' +'>>> This is a great idea.' +'>>> This is a great feat.' +``` + +Из результатов видно, что предсказания модели относятся к повседневным терминам, что, пожалуй, неудивительно, учитывая основу английской Википедии. Давайте посмотрим, как мы можем изменить эту область на что-то более нишевое - сильно поляризованные обзоры фильмов! + + +## Датасет[[the-dataset]] + +Для демонстрации адаптации к домену мы используем знаменитый [Large Movie Review Dataset](https://huggingface.co/datasets/imdb) (или сокращенно IMDb) - корпус кинорецензий, который часто используется для тестирования моделей анализа настроения. Дообучив DistilBERT на этом корпусе, мы ожидаем, что языковая модель адаптирует свой словарный запас от фактических данных Википедии, на которых она была предварительно обучена, к более субъективным элементам кинорецензий. Мы можем получить данные из Hugging Face Hub с помощью функции `load_dataset()` из 🤗 Datasets: + +```python +from datasets import load_dataset + +imdb_dataset = load_dataset("imdb") +imdb_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['text', 'label'], + num_rows: 25000 + }) + test: Dataset({ + features: ['text', 'label'], + num_rows: 25000 + }) + unsupervised: Dataset({ + features: ['text', 'label'], + num_rows: 50000 + }) +}) +``` + +Мы видим, что части `train` и `test` состоят из 25 000 отзывов каждая, а часть без меток, называемая `unsupervised`, содержит 50 000 отзывов. Давайте посмотрим на несколько примеров, чтобы получить представление о том, с каким текстом мы имеем дело. Как мы уже делали в предыдущих главах курса, мы используем функции `Dataset.shuffle()` и `Dataset.select()` для создания случайной выборки: + +```python +sample = imdb_dataset["train"].shuffle(seed=42).select(range(3)) + +for row in sample: + print(f"\n'>>> Review: {row['text']}'") + print(f"'>>> Label: {row['label']}'") +``` + +```python out + +'>>> Review: This is your typical Priyadarshan movie--a bunch of loony characters out on some silly mission. His signature climax has the entire cast of the film coming together and fighting each other in some crazy moshpit over hidden money. Whether it is a winning lottery ticket in Malamaal Weekly, black money in Hera Pheri, "kodokoo" in Phir Hera Pheri, etc., etc., the director is becoming ridiculously predictable. Don\'t get me wrong; as clichéd and preposterous his movies may be, I usually end up enjoying the comedy. However, in most his previous movies there has actually been some good humor, (Hungama and Hera Pheri being noteworthy ones). Now, the hilarity of his films is fading as he is using the same formula over and over again.

Songs are good. Tanushree Datta looks awesome. Rajpal Yadav is irritating, and Tusshar is not a whole lot better. Kunal Khemu is OK, and Sharman Joshi is the best.' +'>>> Label: 0' + +'>>> Review: Okay, the story makes no sense, the characters lack any dimensionally, the best dialogue is ad-libs about the low quality of movie, the cinematography is dismal, and only editing saves a bit of the muddle, but Sam" Peckinpah directed the film. Somehow, his direction is not enough. For those who appreciate Peckinpah and his great work, this movie is a disappointment. Even a great cast cannot redeem the time the viewer wastes with this minimal effort.

The proper response to the movie is the contempt that the director San Peckinpah, James Caan, Robert Duvall, Burt Young, Bo Hopkins, Arthur Hill, and even Gig Young bring to their work. Watch the great Peckinpah films. Skip this mess.' +'>>> Label: 0' + +'>>> Review: I saw this movie at the theaters when I was about 6 or 7 years old. I loved it then, and have recently come to own a VHS version.

My 4 and 6 year old children love this movie and have been asking again and again to watch it.

I have enjoyed watching it again too. Though I have to admit it is not as good on a little TV.

I do not have older children so I do not know what they would think of it.

The songs are very cute. My daughter keeps singing them over and over.

Hope this helps.' +'>>> Label: 1' +``` + +Да, это точно рецензии на фильмы, и если вы достаточно взрослый, то можете даже понять комментарий в последней рецензии о том, что у вас есть VHS-версия 😜! Хотя нам не понадобятся эти метки для языкового моделирования, мы уже видим, что `0` обозначает отрицательный отзыв, а `1` - положительный. + + + +✏️ **Попробуйте!** Создайте случайную выборку из части `unsupervised` и проверьте, что метки не являются ни `0`, ни `1`. В процессе работы вы также можете проверить, что метки в частях `train` и `test` действительно равны `0` или `1` - это полезная проверка здравомыслия, которую каждый практикующий NLP должен выполнять в начале нового проекта! + + + +Теперь, когда мы вкратце ознакомились с данными, давайте перейдем к их подготовке к моделированию языка по маске. Как мы увидим, есть несколько дополнительных шагов, которые необходимо сделать по сравнению с задачами классификации последовательностей, которые мы рассматривали в [Главе 3](/course/chapter3). Поехали! + +## Предварительная обработка данных[[preprocessing-the-data]] + + + +Как для авторегрессивного, так и для масочного моделирования языка общим шагом предварительной обработки является объединение всех примеров, а затем разбиение всего корпуса на части одинакового размера. Это сильно отличается от нашего обычного подхода, когда мы просто проводим токенизацию отдельных примеров. Зачем конкатенируем все вместе? Причина в том, что отдельные примеры могут быть обрезаны, если они слишком длинные, и это приведет к потере информации, которая может быть полезна для задачи языкового моделирования! + +Итак, для начала мы проведем обычную токенизацию нашего корпуса, но _без_ задания параметра `truncation=True` в нашем токенизаторе. Мы также возьмем идентификаторы слов, если они доступны ((а они будут доступны, если мы используем быстрый токенизатор, как описано в [Главе 6](/course/chapter6/3)), поскольку они понадобятся нам позже для маскирования целых слов. Мы обернем это в простую функцию, а пока удалим столбцы `text` и `label`, поскольку они нам больше не нужны: + +```python +def tokenize_function(examples): + result = tokenizer(examples["text"]) + if tokenizer.is_fast: + result["word_ids"] = [result.word_ids(i) for i in range(len(result["input_ids"]))] + return result + + +# Используйте batched=True для активации быстрой многопоточности! +tokenized_datasets = imdb_dataset.map( + tokenize_function, batched=True, remove_columns=["text", "label"] +) +tokenized_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'input_ids', 'word_ids'], + num_rows: 25000 + }) + test: Dataset({ + features: ['attention_mask', 'input_ids', 'word_ids'], + num_rows: 25000 + }) + unsupervised: Dataset({ + features: ['attention_mask', 'input_ids', 'word_ids'], + num_rows: 50000 + }) +}) +``` + +Поскольку DistilBERT - это BERT-подобная модель, мы видим, что закодированные тексты состоят из `input_ids` и `attention_mask`, которые мы уже видели в других главах, а также из `word_ids`, которые мы добавили. + +Теперь, когда мы провели токенизацию рецензий на фильмы, следующий шаг - сгруппировать их вместе и разбить результат на части. Но какого размера должны быть эти части? В конечном итоге это будет зависеть от объема доступной памяти GPU, но хорошей отправной точкой будет узнать, каков максимальный размер контекста модели. Это можно сделать путем проверки атрибута `model_max_length` токенизатора: + +```python +tokenizer.model_max_length +``` + +```python out +512 +``` + +Это значение берется из файла *tokenizer_config.json*, связанного с контрольной точкой; в данном случае мы видим, что размер контекста составляет 512 токенов, как и в случае с BERT. + + + +✏️ **Попробуйте!** Некоторые модели трансформеров, например [BigBird](https://huggingface.co/google/bigbird-roberta-base) и [Longformer](hf.co/allenai/longformer-base-4096), имеют гораздо большую длину контекста, чем BERT и другие ранние модели трансформеров. Инстанцируйте токенизатор для одной из этих контрольных точек и проверьте, что `model_max_length` согласуется с тем, что указано в карточке модели. + + + +Поэтому для проведения экспериментов на GPU, подобных тем, что стоят в Google Colab, мы выберем что-нибудь поменьше, что может поместиться в памяти: + +```python +chunk_size = 128 +``` + + + +Обратите внимание, что использование небольшого размера фрагмента может быть вредным в реальных сценариях, поэтому следует использовать размер, соответствующий сценарию использования, к которому вы будете применять вашу модель. + + + +Теперь наступает самое интересное. Чтобы показать, как работает конкатенация, давайте возьмем несколько отзывов из нашего обучающего набора с токенизацией и выведем количество токенов в отзыве: + +```python +# С помощью среза получаем список списков для каждого признака +tokenized_samples = tokenized_datasets["train"][:3] + +for idx, sample in enumerate(tokenized_samples["input_ids"]): + print(f"'>>> Review {idx} length: {len(sample)}'") +``` + +```python out +'>>> Review 0 length: 200' +'>>> Review 1 length: 559' +'>>> Review 2 length: 192' +``` + +Затем мы можем объединить все эти примеры с помощью простого dictionary comprehension, как показано ниже: + +```python +concatenated_examples = { + k: sum(tokenized_samples[k], []) for k in tokenized_samples.keys() +} +total_length = len(concatenated_examples["input_ids"]) +print(f"'>>> Concatenated reviews length: {total_length}'") +``` + +```python out +'>>> Concatenated reviews length: 951' +``` + +Отлично, общая длина подтвердилась - теперь давайте разобьем конкатенированные обзоры на части размером `chunk_size`. Для этого мы перебираем признаки в `concatenated_examples` и используем list comprehension для создания срезов каждого признака. В результате мы получаем словарь фрагментов для каждого признака: + +```python +chunks = { + k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)] + for k, t in concatenated_examples.items() +} + +for chunk in chunks["input_ids"]: + print(f"'>>> Chunk length: {len(chunk)}'") +``` + +```python out +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 55' +``` + +Как видно из этого примера, последний фрагмент, как правило, будет меньше максимального размера фрагмента. Существует две основные стратегии решения этой проблемы: + +* Отбросить последний фрагмент, если он меньше `chunk_size`. +* Дополнить последний фрагмент до длины, равной `chunk_size`. + +Мы воспользуемся первым подходом, поэтому обернем всю описанную выше логику в одну функцию, которую можно применить к нашим токенизированным датасетам: + +```python +def group_texts(examples): + # Конкатенируем все тексты + concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()} + # Вычисляем длину конкатенированных текстов + total_length = len(concatenated_examples[list(examples.keys())[0]]) + # Отбрасываем последний фрагмент, если он меньше chunk_size + total_length = (total_length // chunk_size) * chunk_size + # Разбиваем на фрагменты длиной max_len + result = { + k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)] + for k, t in concatenated_examples.items() + } + # Создаем новый столбец меток + result["labels"] = result["input_ids"].copy() + return result +``` + +Обратите внимание, что на последнем шаге `group_texts()` мы создаем новый столбец `labels`, который является копией столбца `input_ids`. Как мы вскоре увидим, это связано с тем, что при моделировании языка по маске цель состоит в прогнозировании случайно замаскированных токенов во входном батче, и, создавая столбец `labels`, мы предоставляем базовую истину для нашей языковой модели, на которой она будет учиться. + +Теперь давайте применим `group_texts()` к нашим токенизированным датасетам, используя нашу надежную функцию `Dataset.map()`: + +```python +lm_datasets = tokenized_datasets.map(group_texts, batched=True) +lm_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 61289 + }) + test: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 59905 + }) + unsupervised: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 122963 + }) +}) +``` + +Вы можете видеть, что группировка и последующее разбиение текстов на фрагменты позволили получить гораздо больше примеров, чем наши первоначальные 25 000 примеров для частей `train` и `test`. Это потому, что теперь у нас есть примеры с _непрерывными токенами (contiguous tokens)_, которые охватывают несколько примеров из исходного корпуса. В этом можно убедиться, поискав специальные токены `[SEP]` и `[CLS]` в одном из фрагментов: + +```python +tokenizer.decode(lm_datasets["train"][1]["input_ids"]) +``` + +```python out +".... at.......... high. a classic line : inspector : i'm here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn't! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless" +``` + +В этом примере вы можете увидеть два перекрывающихся обзора фильмов: один - о старшей школе, другой - о бездомности. Давайте также посмотрим, как выглядят метки при моделировании языка по маске: + +```python out +tokenizer.decode(lm_datasets["train"][1]["labels"]) +``` + +```python out +".... at.......... high. a classic line : inspector : i'm here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn't! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless" +``` + +Как и ожидалось от нашей функции `group_texts()` выше, это выглядит идентично декодированным `input_ids` - но как тогда наша модель может чему-то научиться? Нам не хватает ключевого шага: вставки токенов `[MASK]` в случайные позиции во входных данных! Давайте посмотрим, как это можно сделать на лету во время дообучения с помощью специального коллатора данных. + +## Дообучение DistilBERT с помощью API `Trainer`[[fine-tuning-distilbert-with-the-trainer-api]] + +Дообучить модель моделирования языка по маске почти то же самое, что и дообучить модель классификации последовательностей, как мы делали в [Главе 3] (/course/chapter3). Единственное отличие заключается в том, что нам нужен специальный коллатор данных, который может случайным образом маскировать некоторые токены в каждом батче текстов. К счастью, 🤗 Transformers поставляется со специальным `DataCollatorForLanguageModeling`, предназначенным именно для этой задачи. Нам нужно только передать ему токенизатор и аргумент `mlm_probability`, который указывает, какую долю токенов нужно маскировать. Мы выберем 15 % - это количество используется для BERT и является распространенным выбором в литературе: + +```python +from transformers import DataCollatorForLanguageModeling + +data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15) +``` + +Чтобы увидеть, как работает случайное маскирование, давайте отправим несколько примеров в коллатор данных. Поскольку он ожидает список `dict`, где каждый `dict` представляет собой один фрагмент непрерывного текста, мы сначала выполняем итерацию над датасетом, прежде чем отправить батч коллатору. Мы удаляем ключ `"word_ids"` для этого коллатора данных, поскольку он его не ожидает: + +```python +samples = [lm_datasets["train"][i] for i in range(2)] +for sample in samples: + _ = sample.pop("word_ids") + +for chunk in data_collator(samples)["input_ids"]: + print(f"\n'>>> {tokenizer.decode(chunk)}'") +``` + +```python output +'>>> [CLS] bromwell [MASK] is a cartoon comedy. it ran at the same [MASK] as some other [MASK] about school life, [MASK] as " teachers ". [MASK] [MASK] [MASK] in the teaching [MASK] lead [MASK] to believe that bromwell high\'[MASK] satire is much closer to reality than is " teachers ". the scramble [MASK] [MASK] financially, the [MASK]ful students whogn [MASK] right through [MASK] pathetic teachers\'pomp, the pettiness of the whole situation, distinction remind me of the schools i knew and their students. when i saw [MASK] episode in [MASK] a student repeatedly tried to burn down the school, [MASK] immediately recalled. [MASK]...' + +'>>> .... at.. [MASK]... [MASK]... high. a classic line plucked inspector : i\'[MASK] here to [MASK] one of your [MASK]. student : welcome to bromwell [MASK]. i expect that many adults of my age think that [MASK]mwell [MASK] is [MASK] fetched. what a pity that it isn\'t! [SEP] [CLS] [MASK]ness ( or [MASK]lessness as george 宇in stated )公 been an issue for years but never [MASK] plan to help those on the street that were once considered human [MASK] did everything from going to school, [MASK], [MASK] vote for the matter. most people think [MASK] the homeless' +``` + +Отлично, сработало! Мы видим, что токен `[MASK]` был случайным образом вставлен в различные места нашего текста. Это будут токены, которые наша модель должна будет предсказать в процессе обучения - и прелесть коллатора данных в том, что он будет случайным образом вставлять `[MASK]` в каждом батче! + + + +✏️ **Попробуйте!** Запустите приведенный выше фрагмент кода несколько раз, чтобы увидеть, как случайное маскирование происходит на ваших глазах! Также замените метод `tokenizer.decode()` на `tokenizer.convert_ids_to_tokens()`, чтобы увидеть, что иногда маскируется один токен из данного слова, а не все остальные. + + + +{#if fw === 'pt'} + +Одним из побочных эффектов случайного маскирования является то, что наши метрики оценки не будут детерминированными при использовании `Trainer`, поскольку мы используем один и тот же коллатор данных для обучающего и тестового наборов. Позже, когда мы рассмотрим дообучение с помощью 🤗 Accelerate, мы увидим, как можно использовать гибкость пользовательского цикла оценки, чтобы заморозить случайность. + +{/if} + +При обучении моделей для моделирования языка с маской можно использовать один из методов - маскировать целые слова, а не только отдельные токены. Такой подход называется _маскированием целых слов (whole word masking)_. Если мы хотим использовать маскирование целых слов, нам нужно будет самостоятельно создать коллатор данных. Коллатор данных - это просто функция, которая берет список примеров и преобразует их в батч, так что давайте сделаем это прямо сейчас! Мы будем использовать идентификаторы слов, вычисленные ранее, для создания карты между индексами слов и соответствующими токенами, затем случайным образом определим, какие слова нужно маскировать, и применим эту маску к входным данным. Обратите внимание, что все метки - `-100`, кроме тех, что соответствуют словам-маскам. + +{#if fw === 'pt'} + +```py +import collections +import numpy as np + +from transformers import default_data_collator + +wwm_probability = 0.2 + + +def whole_word_masking_data_collator(features): + for feature in features: + word_ids = feature.pop("word_ids") + + # Создаем отображение между словами и соответствующими индексами токенов + mapping = collections.defaultdict(list) + current_word_index = -1 + current_word = None + for idx, word_id in enumerate(word_ids): + if word_id is not None: + if word_id != current_word: + current_word = word_id + current_word_index += 1 + mapping[current_word_index].append(idx) + + # Случайно маскируем слова + mask = np.random.binomial(1, wwm_probability, (len(mapping),)) + input_ids = feature["input_ids"] + labels = feature["labels"] + new_labels = [-100] * len(labels) + for word_id in np.where(mask)[0]: + word_id = word_id.item() + for idx in mapping[word_id]: + new_labels[idx] = labels[idx] + input_ids[idx] = tokenizer.mask_token_id + feature["labels"] = new_labels + + return default_data_collator(features) +``` + +{:else} + +```py +import collections +import numpy as np + +from transformers.data.data_collator import tf_default_data_collator + +wwm_probability = 0.2 + + +def whole_word_masking_data_collator(features): + for feature in features: + word_ids = feature.pop("word_ids") + + # Создаем отображение между словами и соответствующими индексами токенов + mapping = collections.defaultdict(list) + current_word_index = -1 + current_word = None + for idx, word_id in enumerate(word_ids): + if word_id is not None: + if word_id != current_word: + current_word = word_id + current_word_index += 1 + mapping[current_word_index].append(idx) + + # Случайно маскируем слова + mask = np.random.binomial(1, wwm_probability, (len(mapping),)) + input_ids = feature["input_ids"] + labels = feature["labels"] + new_labels = [-100] * len(labels) + for word_id in np.where(mask)[0]: + word_id = word_id.item() + for idx in mapping[word_id]: + new_labels[idx] = labels[idx] + input_ids[idx] = tokenizer.mask_token_id + feature["labels"] = new_labels + + return tf_default_data_collator(features) +``` + +{/if} + +Далее мы можем опробовать ее на тех же примерах, что и раньше: + +```py +samples = [lm_datasets["train"][i] for i in range(2)] +batch = whole_word_masking_data_collator(samples) + +for chunk in batch["input_ids"]: + print(f"\n'>>> {tokenizer.decode(chunk)}'") +``` + +```python out +'>>> [CLS] bromwell high is a cartoon comedy [MASK] it ran at the same time as some other programs about school life, such as " teachers ". my 35 years in the teaching profession lead me to believe that bromwell high\'s satire is much closer to reality than is " teachers ". the scramble to survive financially, the insightful students who can see right through their pathetic teachers\'pomp, the pettiness of the whole situation, all remind me of the schools i knew and their students. when i saw the episode in which a student repeatedly tried to burn down the school, i immediately recalled.....' + +'>>> .... [MASK] [MASK] [MASK] [MASK]....... high. a classic line : inspector : i\'m here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn\'t! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless' +``` + + + +✏️ **Попробуйте!** Запустите приведенный выше фрагмент кода несколько раз, чтобы увидеть, как случайное маскирование происходит на ваших глазах! Также замените метод `tokenizer.decode()` на `tokenizer.convert_ids_to_tokens()`, чтобы увидеть, что токены из данного слова всегда маскируются вместе. + + + +Теперь, когда у нас есть два колатора данных, остальные шаги по дообучению стандартны. Обучение может занять много времени в Google Colab, если вам не посчастливилось получить мифический GPU P100 😭, поэтому мы сначала уменьшим размер обучающего набора до нескольких тысяч примеров. Не волнуйтесь, мы все равно получим довольно приличную языковую модель! Быстрый способ уменьшить размер датасета в 🤗 Datasets - это функция `Dataset.train_test_split()`, которую мы рассматривали в [Главе 5](/course/chapter5): + +```python +train_size = 10_000 +test_size = int(0.1 * train_size) + +downsampled_dataset = lm_datasets["train"].train_test_split( + train_size=train_size, test_size=test_size, seed=42 +) +downsampled_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 10000 + }) + test: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 1000 + }) +}) +``` + +Это автоматически создаст новые части `train` и `test`, с размером обучающего набора в 10 000 примеров и валидацией в 10 % от этого количества - не стесняйтесь увеличить это значение, если у вас мощный GPU! Следующее, что нам нужно сделать, это авторизоваться на Hugging Face Hub. Если вы выполняете этот код в блокноте, вы можете сделать это с помощью следующей служебной функции: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +которая отобразит виджет, где вы можете ввести свои учетные данные. В качестве альтернативы можно выполнить команду: + +``` +huggingface-cli login +``` + +в вашем любимом терминале и авторизуйтесь там. + +{#if fw === 'tf'} + +После того как мы авторизовались, мы можем создавать наши датасеты `tf.data`. Для этого мы воспользуемся методом `prepare_tf_dataset()`, который использует нашу модель для автоматического инференса того, какие столбцы должны войти в датасет. Если вы хотите контролировать, какие именно столбцы будут использоваться, вы можете использовать метод `Dataset.to_tf_dataset()` вместо этого. Для простоты мы будем использовать стандартный коллатор данных, но вы также можете попробовать коллатор для маскировки слов целиком и сравнить результаты в качестве упражнения: + +```python +tf_train_dataset = model.prepare_tf_dataset( + downsampled_dataset["train"], + collate_fn=data_collator, + shuffle=True, + batch_size=32, +) + +tf_eval_dataset = model.prepare_tf_dataset( + downsampled_dataset["test"], + collate_fn=data_collator, + shuffle=False, + batch_size=32, +) +``` + +Далее мы задаем гиперпараметры обучения и компилируем нашу модель. Мы используем функцию `create_optimizer()` из библиотеки 🤗 Transformers, которая возвращает нам оптимизатор `AdamW` с линейным затуханием скорости обучения. Мы также используем встроенные потери модели, которые используются по умолчанию, если в качестве аргумента `compile()` не указаны потери, и устанавливаем точность обучения на `"mixed_float16"`. Обратите внимание, что если вы используете Colab GPU или другой GPU, который не имеет поддержки ускорения float16, вам, вероятно, следует закомментировать эту строку. + +Кроме того, мы настроили `PushToHubCallback`, который будет сохранять модель в Hub после каждой эпохи. Вы можете указать имя репозитория, в который хотите отправить модель, с помощью аргумента `hub_model_id` (в частности, этот аргумент нужно использовать, чтобы отправить модель в организацию). Например, чтобы отправить модель в организацию [`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/distilbert-finetuned-imdb"`. По умолчанию используемый репозиторий будет находиться в вашем пространстве имен и называться в соответствии с заданным вами выходным каталогом, так что в нашем случае это будет `"lewtun/distilbert-finetuned-imdb"`. + +```python +from transformers import create_optimizer +from transformers.keras_callbacks import PushToHubCallback +import tensorflow as tf + +num_train_steps = len(tf_train_dataset) +optimizer, schedule = create_optimizer( + init_lr=2e-5, + num_warmup_steps=1_000, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) + +# Train in mixed-precision float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") + +model_name = model_checkpoint.split("/")[-1] +callback = PushToHubCallback( + output_dir=f"{model_name}-finetuned-imdb", tokenizer=tokenizer +) +``` + +Теперь мы готовы запустить `model.fit()`, но перед этим давайте вкратце рассмотрим _перплексию (perplexity)_, которая является общей метрикой для оценки качества работы языковых моделей. + +{:else} + +После того как мы авторизовались, мы можем указать аргументы для `Trainer`: + +```python +from transformers import TrainingArguments + +batch_size = 64 +# Показываем потери при обучении для каждой эпохи +logging_steps = len(downsampled_dataset["train"]) // batch_size +model_name = model_checkpoint.split("/")[-1] + +training_args = TrainingArguments( + output_dir=f"{model_name}-finetuned-imdb", + overwrite_output_dir=True, + evaluation_strategy="epoch", + learning_rate=2e-5, + weight_decay=0.01, + per_device_train_batch_size=batch_size, + per_device_eval_batch_size=batch_size, + push_to_hub=True, + fp16=True, + logging_steps=logging_steps, +) +``` + +Здесь мы изменили несколько параметров по умолчанию, включая `logging_steps`, чтобы обеспечить отслеживание потерь при обучении в каждой эпохе. Мы также использовали `fp16=True`, чтобы включить обучение со смешанной точностью, что дает нам еще большее улучшение скорости. По умолчанию `Trainer` удаляет все столбцы, которые не являются частью метода `forward()` модели. Это означает, что если вы используете коллатор для маскировки слов целиком, вам также нужно установить `remove_unused_columns=False`, чтобы не потерять колонку `word_ids` во время обучения. + +Обратите внимание, что с помощью аргумента `hub_model_id` можно указать имя репозитория, в который вы хотите отправить модель (в частности, этот аргумент нужно использовать, чтобы отправить модель в ырепозиторий организации). Например, когда мы отправили модель в репозиторий организации [`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/distilbert-finetuned-imdb"` в `TrainingArguments`. По умолчанию используемый репозиторий будет находиться в вашем пространстве имен и называться в соответствии с заданной вами выходной директорией, так что в нашем случае это будет `"lewtun/distilbert-finetuned-imdb"`. + +Теперь у нас есть все компоненты для создания `Trainer`. Здесь мы просто используем стандартный `data_collator`, но вы можете попробовать коллатор для маскирования слов целиком и сравнить результаты в качестве упражнения: + +```python +from transformers import Trainer + +trainer = Trainer( + model=model, + args=training_args, + train_dataset=downsampled_dataset["train"], + eval_dataset=downsampled_dataset["test"], + data_collator=data_collator, + tokenizer=tokenizer, +) +``` + +Теперь мы готовы запустить `trainer.train()`, но перед этим давайте вкратце рассмотрим _перплексию (perplexity), которая является общей метрикой для оценки качества языковых моделей. + +{/if} + +### Перплексия языковых моделей[[perplexity-for-language-models]] + + + +В отличие от других задач, таких как классификация текстов или ответов на вопросы, где для обучения нам дается помеченный корпус, при языковом моделировании у нас нет никаких явных меток. Как же определить, какая языковая модель является хорошей? Как и в случае с функцией автокоррекции в вашем телефоне, хорошая языковая модель - это та, которая присваивает высокую вероятность грамматически правильным предложениям и низкую вероятность бессмысленным предложениям. Чтобы лучше представить себе, как это выглядит, вы можете найти в Интернете целые подборки "неудач автокоррекции", где модель в телефоне человека выдает довольно забавные (и часто неуместные) завершения! + +{#if fw === 'pt'} + +Если предположить, что наш тестовый набор состоит в основном из грамматически правильных предложений, то одним из способов измерения качества нашей языковой модели является подсчет вероятностей, которые она присваивает следующему слову во всех предложениях тестового набора. Высокие вероятности указывают на то, что модель не "удивлена" и не "перплексирована" не виденными ранее примерами, и предполагают, что она усвоила основные грамматические закономерности языка. Существуют различные математические определения перплексии, но то, которое мы будем использовать, определяет ее как экспоненту потери перекрестной энтропии. Таким образом, мы можем вычислить перплексию нашей предварительно обученной модели, используя функцию `Trainer.evaluate()` для вычисления потерь кросс-энтропии на тестовом наборе, а затем взяв экспоненту результата: + +```python +import math + +eval_results = trainer.evaluate() +print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}") +``` + +{:else} + +Если предположить, что наш тестовый набор состоит в основном из грамматически правильных предложений, то одним из способов измерения качества нашей языковой модели является подсчет вероятностей, которые она присваивает следующему слову во всех предложениях тестового набора. Высокие вероятности указывают на то, что модель не "удивлена" или не "перплексирована" не виденными ранее примерами, и предполагают, что она выучила основные грамматические закономерности языка. Существуют различные математические определения перплексии, но то, которое мы будем использовать, определяет ее как экспоненту потери перекрестной энтропии. Таким образом, мы можем вычислить перплексию нашей предварительно обученной модели, используя метод `model.evaluate()` для вычисления потери кросс-энтропии на тестовом наборе, а затем взяв экспоненту результата: + +```python +import math + +eval_loss = model.evaluate(tf_eval_dataset) +print(f"Perplexity: {math.exp(eval_loss):.2f}") +``` + +{/if} + +```python out +>>> Perplexity: 21.75 +``` + +Более низкий показатель перплексии означает лучшую языковую модель, и мы видим, что наша начальная модель имеет несколько большое значение. Давайте посмотрим, сможем ли мы снизить его, дообучив модель! Для этого сначала запустим цикл обучения: + +{#if fw === 'pt'} + +```python +trainer.train() +``` + +{:else} + +```python +model.fit(tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback]) +``` + +{/if} + +и затем вычислить результирующую перплексию на тестовом наборе, как и раньше: + +{#if fw === 'pt'} + +```python +eval_results = trainer.evaluate() +print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}") +``` + +{:else} + +```python +eval_loss = model.evaluate(tf_eval_dataset) +print(f"Perplexity: {math.exp(eval_loss):.2f}") +``` + +{/if} + +```python out +>>> Perplexity: 11.32 +``` + +Неплохо - это довольно значительное уменьшение перплексии, что говорит о том, что модель узнала что-то новое об области рецензий на фильмы! + +{#if fw === 'pt'} + +После завершения обучения мы можем отправить карточку модели с информацией об обучении в Hub (контрольные точки сохраняются во время самого обучения): + +```python +trainer.push_to_hub() +``` + +{/if} + + + +✏️ **Попробуйте!** Запустите обучение, описанное выше, после замены коллатора данных на коллатор маскирующий все слово. Получили ли вы лучшие результаты? + + + +{#if fw === 'pt'} + +В нашем случае нам не нужно было делать ничего особенного с циклом обучения, но в некоторых случаях вам может понадобиться реализовать некоторую пользовательскую логику. Для таких случаев вы можете использовать 🤗 Accelerate - давайте посмотрим! + +## Дообучение DistilBERT с помощью 🤗 Accelerate[[fine-tuning-distilbert-with-accelerate]] + +Как мы видели на примере `Trainer`, дообучение модели маскированного языкового моделирования очень похоже на пример классификации текста из [Главы 3](/course/chapter3). Фактически, единственной особенностью является использование специального коллатора данных, о котором мы уже рассказывали ранее в этом разделе! + +Однако мы видели, что `DataCollatorForLanguageModeling` также применяет случайное маскирование при каждой оценке, поэтому мы увидим некоторые колебания в наших оценках перплексии при каждом цикле обучения. Один из способов устранить этот источник случайности - применить маскирование _один раз_ ко всему тестовому набору, а затем использовать стандартный коллатор данных в 🤗 Transformers для сбора батчей во время оценки. Чтобы увидеть, как это работает, давайте реализуем простую функцию, которая применяет маскирование к батчу, подобно нашей первой работе с `DataCollatorForLanguageModeling`: + +```python +def insert_random_mask(batch): + features = [dict(zip(batch, t)) for t in zip(*batch.values())] + masked_inputs = data_collator(features) + # Создаем новый "маскированный" столбец для каждого столбца в датасете + return {"masked_" + k: v.numpy() for k, v in masked_inputs.items()} +``` + +Далее мы применим эту функцию к нашему тестовому набору и удалим столбцы без маскирования, чтобы заменить их столбцами с маскированием. Вы можете использовать маскирование целых слов, заменив `data_collator` выше на соответствующий, в этом случае вам следует удалить первую строку здесь: + +```py +downsampled_dataset = downsampled_dataset.remove_columns(["word_ids"]) +eval_dataset = downsampled_dataset["test"].map( + insert_random_mask, + batched=True, + remove_columns=downsampled_dataset["test"].column_names, +) +eval_dataset = eval_dataset.rename_columns( + { + "masked_input_ids": "input_ids", + "masked_attention_mask": "attention_mask", + "masked_labels": "labels", + } +) +``` + +Затем мы можем настроить загрузчики данных как обычно, но для оценочного набора мы будем использовать `default_data_collator` из 🤗 Transformers: + +```python +from torch.utils.data import DataLoader +from transformers import default_data_collator + +batch_size = 64 +train_dataloader = DataLoader( + downsampled_dataset["train"], + shuffle=True, + batch_size=batch_size, + collate_fn=data_collator, +) +eval_dataloader = DataLoader( + eval_dataset, batch_size=batch_size, collate_fn=default_data_collator +) +``` + +Здесь мы следуем стандартным шагам 🤗 Accelerate. Первым делом загружаем свежую версию предварительно обученной модели: + +``` +model = AutoModelForMaskedLM.from_pretrained(model_checkpoint) +``` + +Затем нужно указать оптимизатор; мы будем использовать стандартный `AdamW`: + +```python +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=5e-5) +``` + +Теперь, имея эти объекты, мы можем подготовить все для обучения с помощью объекта `Accelerator`: + +```python +from accelerate import Accelerator + +accelerator = Accelerator() +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +Теперь, когда наша модель, оптимизатор и загрузчики данных настроены, мы можем задать планировщик скорости обучения следующим образом: + +```python +from transformers import get_scheduler + +num_train_epochs = 3 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +Осталось сделать еще одну последнюю вещь перед обучением: создать репозиторий модели на Hugging Face Hub! Мы можем использовать библиотеку 🤗 Hub, чтобы сначала сгенерировать полное имя нашего репозитория: + +```python +from huggingface_hub import get_full_repo_name + +model_name = "distilbert-base-uncased-finetuned-imdb-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'lewtun/distilbert-base-uncased-finetuned-imdb-accelerate' +``` + +затем создадим и клонируем репозиторий, используя класс `Repository` из 🤗 Hub: + +```python +from huggingface_hub import Repository + +output_dir = model_name +repo = Repository(output_dir, clone_from=repo_name) +``` + +После этого остается только написать полный цикл обучения и оценки: + +```python +from tqdm.auto import tqdm +import torch +import math + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Обучение + model.train() + for batch in train_dataloader: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Оценка + model.eval() + losses = [] + for step, batch in enumerate(eval_dataloader): + with torch.no_grad(): + outputs = model(**batch) + + loss = outputs.loss + losses.append(accelerator.gather(loss.repeat(batch_size))) + + losses = torch.cat(losses) + losses = losses[: len(eval_dataset)] + try: + perplexity = math.exp(torch.mean(losses)) + except OverflowError: + perplexity = float("inf") + + print(f">>> Epoch {epoch}: Perplexity: {perplexity}") + + # Сохранение и загрузка + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +```python out +>>> Epoch 0: Perplexity: 11.397545307900472 +>>> Epoch 1: Perplexity: 10.904909330983092 +>>> Epoch 2: Perplexity: 10.729503505340409 +``` + +Круто, мы смогли оценить перплексию для каждой эпохи и обеспечить воспроизводимость нескольких циклов обучения! + +{/if} + +## Использование нашей дообученной модели[[using-our-fine-tuned-model]] + +Вы можете взаимодействовать с дообученной моделью либо с помощью ее виджета на Hub, либо локально с помощью `pipeline` из 🤗 Transformers. Давайте воспользуемся последним вариантом, чтобы загрузить нашу модель с помощью конвейера `fill-mask`: + +```python +from transformers import pipeline + +mask_filler = pipeline( + "fill-mask", model="huggingface-course/distilbert-base-uncased-finetuned-imdb" +) +``` + +Затем мы можем передать конвейеру наш пример текста " This is a great [MASK]" и посмотреть, каковы 5 лучших прогнозов: + +```python +preds = mask_filler(text) + +for pred in preds: + print(f">>> {pred['sequence']}") +``` + +```python out +'>>> this is a great movie.' +'>>> this is a great film.' +'>>> this is a great story.' +'>>> this is a great movies.' +'>>> this is a great character.' +``` + +Отлично - наша модель явно адаптировала свои веса, чтобы прогнозировать слова, которые сильнее ассоциируются с фильмами! + + + +На этом мы завершаем наш первый эксперимент по обучению языковой модели. В [разделе 6](/course/en/chapter7/6) вы узнаете, как обучить авторегрессионную модель типа GPT-2 с нуля; загляните туда, если хотите посмотреть, как можно предварительно обучить свою собственную модель трансформера! + + + +✏️ **Попробуйте!** Чтобы оценить преимущества адаптации к домену, дообучите классификатор на метках IMDb как для предварительно обученных, так и для дообученных контрольных точек DistilBERT. Если вам нужно освежить в памяти классификацию текстов, ознакомьтесь с [Главой 3] (/course/chapter3). + + diff --git a/chapters/ru/chapter7/4.mdx b/chapters/ru/chapter7/4.mdx new file mode 100644 index 000000000..f1362724f --- /dev/null +++ b/chapters/ru/chapter7/4.mdx @@ -0,0 +1,1002 @@ + + +# Перевод[[translation]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Теперь давайте погрузимся в перевод. Это еще одна [задача преобразования последовательности в последовательность (sequence-to-sequence)](/course/chapter1/7), что означает, что это проблема, которую можно сформулировать как переход от одной последовательности к другой. В этом смысле задача очень близка к [резюмированию (summarization)](/course/chapter7/6), и вы можете приспособить то, что мы здесь рассмотрим, к другим задачам преобразования последовательности в последовательность, таким как: + +- **Перенос стиля (Style transfer)**: Создание модели, которая *переводит* тексты, написанные в определенном стиле, в другой (например, из формального в повседневный или из шекспировского английского в современный). +- **Генеративные ответы на вопросы (Generative question answering)**: Создание модели, которая генерирует ответы на вопросы, учитывая контекст + + + +Если у вас есть достаточно большой корпус текстов на двух (или более) языках, вы можете обучить новую модель перевода с нуля, как мы это сделаем в разделе по [казуальному языковому моделированию (causal language modeling)] (/course/chapter7/6). Однако быстрее будет дообучить существующую модель перевода, будь то многоязычная модель типа mT5 или mBART, которую нужно дообучить для конкретной пары языков, или даже модель, специализированная для перевода с одного языка на другой, которую нужно дообучить для конкретного корпуса. + +В этом разделе мы дообучим модель Marian, предварительно обученную переводу с английского на французский (поскольку многие сотрудники Hugging Face говорят на обоих этих языках), на датасете [KDE4](https://huggingface.co/datasets/kde4), который представляет собой набор локализованных файлов для приложений [KDE](https://apps.kde.org/). Модель, которую мы будем использовать, была предварительно обучена на большом корпусе французских и английских текстов, взятых из [Opus dataset](https://opus.nlpl.eu/), который фактически содержит датасет KDE4. Но даже если модель, которую мы используем, видела эти данные во время предварительного обучения, мы увидим, что после дообучения мы сможем получить ее лучшую версию. + +Когда мы закончим, у нас будет модель, способная делать прогнозы, подобные этому: + + + + +One-hot encoded labels for question answering. + + + +Как и в предыдущих разделах, вы можете найти актуальную модель, которую мы обучим и загрузим на Hub, используя приведенный ниже код, и перепроверить ее предсказания [здесь](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr?text=This+plugin+allows+you+to+automatically+translate+web+pages+between+several+languages.). + +## Подготовка данных[[preparing-the-data]] + +Чтобы дообучить или обучить модель перевода с нуля, нам понадобится датасет, подходящий для этой задачи. Как уже упоминалось, мы будем использовать [датасет KDE4](https://huggingface.co/datasets/kde4) , но вы можете легко адаптировать код для использования своих собственных данных, если у вас есть пары предложений на двух языках, с которых вы хотите переводить и на которые хотите переводить. Обратитесь к [Главе 5](/course/chapter5) если вам нужно вспомнить, как загружать пользовательские данные в `Dataset`. + +### Датасет KDE4[[the-kde4-dataset]] + +Как обычно, мы загружаем наш датасет с помощью функции `load_dataset()`: + +```py +from datasets import load_dataset + +raw_datasets = load_dataset("kde4", lang1="en", lang2="fr") +``` + +Если вы хотите работать с другой парой языков, вы можете указать их по кодам. Всего для этого датасета доступно 92 языка; вы можете увидеть их все, развернув языковые теги в его [карточке датасета](https://huggingface.co/datasets/kde4). + +Language available for the KDE4 dataset. + +Давайте посмотрим на датасет: + +```py +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['id', 'translation'], + num_rows: 210173 + }) +}) +``` + +У нас есть 210 173 пары предложений, но в одной части, поэтому нам нужно создать собственный проверочный набор. Как мы видели в [Главе 5] (/course/chapter5), у `Dataset` есть метод `train_test_split()`, который может нам помочь. Мы зададим seed для воспроизводимости: + +```py +split_datasets = raw_datasets["train"].train_test_split(train_size=0.9, seed=20) +split_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['id', 'translation'], + num_rows: 189155 + }) + test: Dataset({ + features: ['id', 'translation'], + num_rows: 21018 + }) +}) +``` + +Мы можем переименовать ключ `"test"` в `"validation"` следующим образом: + +```py +split_datasets["validation"] = split_datasets.pop("test") +``` + +Теперь давайте рассмотрим один элемент датасета: + +```py +split_datasets["train"][1]["translation"] +``` + +```python out +{'en': 'Default to expanded threads', + 'fr': 'Par défaut, développer les fils de discussion'} +``` + +Мы получаем словарь с двумя предложениями на запрошенной паре языков. Одна из особенностей этого датасета, наполненного техническими терминами в области компьютерных наук, заключается в том, что все они полностью переведены на французский язык. Однако французские инженеры при разговоре оставляют большинство специфических для компьютерных наук слов на английском. Например, слово "threads" вполне может встретиться во французском предложении, особенно в техническом разговоре; но в данном датасете оно переведено как более правильное "fils de discussion". Используемая нами модель, предварительно обученная на большем корпусе французских и английских предложений, выбирает более простой вариант - оставить слово как есть: + +```py +from transformers import pipeline + +model_checkpoint = "Helsinki-NLP/opus-mt-en-fr" +translator = pipeline("translation", model=model_checkpoint) +translator("Default to expanded threads") +``` + +```python out +[{'translation_text': 'Par défaut pour les threads élargis'}] +``` + +Другой пример такого поведения можно увидеть на примере слова "plugin", которое официально не является французским словом, но большинство носителей языка поймут его и не станут переводить. +В датасете KDE4 это слово было переведено на французский как более официальное "module d'extension": + +```py +split_datasets["train"][172]["translation"] +``` + +```python out +{'en': 'Unable to import %1 using the OFX importer plugin. This file is not the correct format.', + 'fr': "Impossible d'importer %1 en utilisant le module d'extension d'importation OFX. Ce fichier n'a pas un format correct."} +``` + +Однако наша предварительно обученная модель придерживается компактного и знакомого английского слова: + +```py +translator( + "Unable to import %1 using the OFX importer plugin. This file is not the correct format." +) +``` + +```python out +[{'translation_text': "Impossible d'importer %1 en utilisant le plugin d'importateur OFX. Ce fichier n'est pas le bon format."}] +``` + +Будет интересно посмотреть, сможет ли наша дообученная модель уловить эти особенности датасета (спойлер: сможет). + + + + + +✏️ **Попробуйте!** Еще одно английское слово, которое часто используется во французском языке, - "email". Найдите в обучающем датасете первый образец, в котором используется это слово. Как оно переводится? Как предварительно обученная модель переводит то же английское предложение? + + + +### Предварительная обработка данных[[processing-the-data]] + + + +Вы уже должны знать, как это делается: все тексты нужно преобразовать в наборы идентификаторов токенов, чтобы модель могла понять их смысл. Для этой задачи нам понадобится токенизация как входных данных, так и целевых. Наша первая задача - создать объект `tokenizer`. Как отмечалось ранее, мы будем использовать предварительно обученную модель Marian English to French. Если вы будете пробовать этот код с другой парой языков, обязательно адаптируйте контрольную точку модели. Организация [Helsinki-NLP](https://huggingface.co/Helsinki-NLP) предоставляет более тысячи моделей на разных языках. + +```python +from transformers import AutoTokenizer + +model_checkpoint = "Helsinki-NLP/opus-mt-en-fr" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, return_tensors="pt") +``` + +Вы также можете заменить `model_checkpoint` на любую другую модель из [Hub](https://huggingface.co/models) или локальной папки, в которой вы сохранили предварительно обученную модель и токенизатор. + + + +💡 Если вы используете многоязыковой токенизатор, такой как mBART, mBART-50 или M2M100, вам нужно задать языковые коды ваших входных и целевых данных в токенизаторе, задав правильные значения параметрам `tokenizer.src_lang` и `tokenizer.tgt_lang`. + + + +Подготовка наших данных довольно проста. Нужно помнить только об одном: необходимо убедиться, что токенизатор обрабатывает целевые значения на выходном языке (здесь - французском). Вы можете сделать это, передав целевые данные в аргумент `text_targets` метода `__call__` токенизатора. + +Чтобы увидеть, как это работает, давайте обработаем по одному примеру каждого языка из обучающего набора: + +```python +en_sentence = split_datasets["train"][1]["translation"]["en"] +fr_sentence = split_datasets["train"][1]["translation"]["fr"] + +inputs = tokenizer(en_sentence, text_target=fr_sentence) +inputs +``` + +```python out +{'input_ids': [47591, 12, 9842, 19634, 9, 0], 'attention_mask': [1, 1, 1, 1, 1, 1], 'labels': [577, 5891, 2, 3184, 16, 2542, 5, 1710, 0]} +``` + +Как мы видим, в выходных данных содержатся входные идентификаторы, связанные с английским предложением, а идентификаторы, связанные с французским, хранятся в поле `labels`. Если вы забудете указать, что выполняете токенизацию меток, они будут токенизированы входным токенизатором, что в случае с моделью Marian не приведет ни к чему хорошему: + +```python +wrong_targets = tokenizer(fr_sentence) +print(tokenizer.convert_ids_to_tokens(wrong_targets["input_ids"])) +print(tokenizer.convert_ids_to_tokens(inputs["labels"])) +``` + +```python out +['▁Par', '▁dé', 'f', 'aut', ',', '▁dé', 've', 'lop', 'per', '▁les', '▁fil', 's', '▁de', '▁discussion', ''] +['▁Par', '▁défaut', ',', '▁développer', '▁les', '▁fils', '▁de', '▁discussion', ''] +``` + +Как мы видим, при использовании английского токенизатора для предварительной обработки французского предложения получается гораздо больше токенов, поскольку токенизатор не знает ни одного французского слова (кроме тех, которые также встречаются в английском языке, например "discussion"). + +Поскольку `inputs` - это словарь с нашими обычными ключами (идентификаторы входных данных, маска внимания и т. д.), последним шагом будет определение функции предварительной обработки, которую мы будем применять к датасетам: + +```python +max_length = 128 + + +def preprocess_function(examples): + inputs = [ex["en"] for ex in examples["translation"]] + targets = [ex["fr"] for ex in examples["translation"]] + model_inputs = tokenizer( + inputs, text_target=targets, max_length=max_length, truncation=True + ) + return model_inputs +``` + +Обратите внимание, что мы установили одинаковую максимальную длину для наших входов и выходов. Поскольку тексты, с которыми мы имеем дело, довольно короткие, мы используем 128. + + + +💡 Если вы используете модель T5 (точнее, одну из контрольных точек `t5-xxx`), модель будет ожидать, что текстовые данные будут иметь префикс, указывающий на поставленную задачу, например `translate: English to French:`. + + + + + +⚠️ Мы не обращаем внимания на маску внимания целевых значений, так как модель не будет этого ожидать. Вместо этого метки, соответствующие токенам дополнения, должны быть заданы как `-100`, чтобы они игнорировались при вычислении потерь. Это будет сделано нашим коллатором данных позже, так как мы применяем динамическое дополнение (dynamic padding), но если вы используете дополнение (padding) здесь, вы должны адаптировать функцию предварительной обработки данных, чтобы установить все метки, соответствующие токену дополнения, в `-100`. + + + +Теперь мы можем применить эту функцию предварительной обработки ко всем частям нашего датасета за один раз: + +```py +tokenized_datasets = split_datasets.map( + preprocess_function, + batched=True, + remove_columns=split_datasets["train"].column_names, +) +``` + +Теперь, когда данные прошли предварительную обработку, мы готовы дообучить нашу предварительно обученную модель! + +{#if fw === 'pt'} + +## Дообучение модели с помощью API `Trainer`[[fine-tuning-the-model-with-the-trainer-api]] + +Фактический код, использующий `Trainer`, будет таким же, как и раньше, с одним лишь небольшим изменением: мы используем [`Seq2SeqTrainer`](https://huggingface.co/transformers/main_classes/trainer.html#seq2seqtrainer), который является подклассом `Trainer`, что позволит нам правильно работать с оценкой, используя метод `generate()` для предсказания выходов на основе входов. Мы рассмотрим это более подробно, когда будем говорить о вычислении метрик. + +Прежде всего, нам нужна реальная модель, которую нужно дообучить. Мы воспользуемся обычным API `AutoModel`: + +```py +from transformers import AutoModelForSeq2SeqLM + +model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +{:else} + +## Дообучение модели с Keras[[fine-tuning-the-model-with-keras]] + +Прежде всего, нам нужна актуальная модель, которую нужно дообучить. Мы воспользуемся обычным API `AutoModel`: + +```py +from transformers import TFAutoModelForSeq2SeqLM + +model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint, from_pt=True) +``` + + + +💡 Контрольная точка `Helsinki-NLP/opus-mt-en-fr` имеет только веса PyTorch, поэтому +вы получите ошибку, если попытаетесь загрузить модель без использования аргумента +`from_pt=True` в методе `from_pretrained()`. Когда вы указываете +`from_pt=True`, библиотека автоматически загрузит и преобразует +веса из PyTorch для вас. Как видите, очень просто переключаться между +фреймворками в 🤗 Transformers! + + + +{/if} + +Обратите внимание, что в этот раз мы используем модель, которая была обучена на задаче перевода и фактически уже может быть использована, поэтому нет предупреждения о пропущенных или новых инициализированных весах. + +### Сопоставление данных[[data-collation]] + +Для динамического батча нам понадобится коллатор данных для работы с дополнением (padding). Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](/course/chapter3), потому что в этом случае будут заполнены только входы (идентификаторы входов, маска внимания и идентификаторы типов токенов). Наши метки также должны быть дополнены до максимальной длины, встречающейся в метках. И, как уже говорилось, добовляемое значение, используемое для дополнения меток, должно быть `-100`, а не добавочный токен токенизатора, чтобы эти добавочные значения игнорировались при вычислении потерь. + +Все это делает [`DataCollatorForSeq2Seq`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorforseq2seq). Как и `DataCollatorWithPadding`, он принимает `tokenizer`, используемый для препроцессирования входных данных, а также `model`. Это связано с тем, что данный коллатор данных также будет отвечать за подготовку входных идентификаторов декодера, которые представляют собой сдвинутые версии меток со специальным токеном в начале. Поскольку для разных архитектур этот сдвиг выполняется по-разному, `DataCollatorForSeq2Seq` должен знать объект `model`: + +{#if fw === 'pt'} + +```py +from transformers import DataCollatorForSeq2Seq + +data_collator = DataCollatorForSeq2Seq(tokenizer, model=model) +``` + +{:else} + +```py +from transformers import DataCollatorForSeq2Seq + +data_collator = DataCollatorForSeq2Seq(tokenizer, model=model, return_tensors="tf") +``` + +{/if} + +Чтобы протестировать его на нескольких примерах, мы просто вызываем его на списке примеров из нашего токинезированного обучающего набора: + +```py +batch = data_collator([tokenized_datasets["train"][i] for i in range(1, 3)]) +batch.keys() +``` + +```python out +dict_keys(['attention_mask', 'input_ids', 'labels', 'decoder_input_ids']) +``` + +Мы можем проверить, что наши метки были дополнены до максимальной длины батча, с использованием `-100`: + +```py +batch["labels"] +``` + +```python out +tensor([[ 577, 5891, 2, 3184, 16, 2542, 5, 1710, 0, -100, + -100, -100, -100, -100, -100, -100], + [ 1211, 3, 49, 9409, 1211, 3, 29140, 817, 3124, 817, + 550, 7032, 5821, 7907, 12649, 0]]) +``` + +Также мы можем взглянуть на идентификаторы входов декодера и убедиться, что они являются сдвинутыми версиями меток: + +```py +batch["decoder_input_ids"] +``` + +```python out +tensor([[59513, 577, 5891, 2, 3184, 16, 2542, 5, 1710, 0, + 59513, 59513, 59513, 59513, 59513, 59513], + [59513, 1211, 3, 49, 9409, 1211, 3, 29140, 817, 3124, + 817, 550, 7032, 5821, 7907, 12649]]) +``` + +Вот метки для первого и второго элементов в нашем датасете: + +```py +for i in range(1, 3): + print(tokenized_datasets["train"][i]["labels"]) +``` + +```python out +[577, 5891, 2, 3184, 16, 2542, 5, 1710, 0] +[1211, 3, 49, 9409, 1211, 3, 29140, 817, 3124, 817, 550, 7032, 5821, 7907, 12649, 0] +``` + +{#if fw === 'pt'} + +Мы передадим этот `data_collator` в `Seq2SeqTrainer`. Далее давайте рассмотрим метрику. + +{:else} + +Теперь мы можем использовать этот `data_collator` для преобразования каждого из наших датасетов в `tf.data.Dataset`, готовый к обучению: + +```python +tf_train_dataset = model.prepare_tf_dataset( + tokenized_datasets["train"], + collate_fn=data_collator, + shuffle=True, + batch_size=32, +) +tf_eval_dataset = model.prepare_tf_dataset( + tokenized_datasets["validation"], + collate_fn=data_collator, + shuffle=False, + batch_size=16, +) +``` + +{/if} + + +### Метрики[[metrics]] + + + +{#if fw === 'pt'} + +Свойство, которое `Seq2SeqTrainer` добавляет к своему суперклассу `Trainer`, - это возможность использовать метод `generate()` во время оценки или предсказания. Во время обучения модель будет использовать `decoder_input_ids` с маской внимания, гарантирующей, что она не будет использовать токены после токена, который пытается предсказать, чтобы ускорить обучение. Во время инференса мы не сможем использовать эти данные, так как у нас не будет меток, поэтому было бы неплохо оценить нашу модель с аналогичной настройкой. + +Как мы видели в [Главе 1](/course/chapter1/6), декодер выполняет инференс, предсказывая токены один за другим - то, что за кулисами реализовано в 🤗 Transformers методом `generate()`. Тренер `Seq2SeqTrainer` позволит нам использовать этот метод для оценки, если мы установим `predict_with_generate=True`. + +{/if} + +Традиционной метрикой, используемой для перевода, является [BLEU score](https://en.wikipedia.org/wiki/BLEU), представленная в [статье 2002 года](https://aclanthology.org/P02-1040.pdf) Кишором Папинени и др. BLEU score оценивает, насколько близки переводы к своим меткам. Он не измеряет разборчивость или грамматическую правильность сгенерированных моделью результатов, но использует статистические правила, чтобы гарантировать, что все слова в сгенерированных результатах также встречаются в целевых. Кроме того, существуют правила, наказывающие повторы одних и тех же слов, если они не повторяются в целевых словах (чтобы модель не выводила предложения типа `"the the the the the the the"), и вывод предложений, которые короче, чем целевые (чтобы модель не выводила предложения типа `"the"`). + +Один из недостатков BLEU заключается в том, что она предполагает, что текст уже прошел токенизацию, что затрудняет сравнение оценок между моделями, использующими различные токенизаторы. Поэтому сегодня для сравнения моделей перевода чаще всего используется метрика [SacreBLEU](https://github.com/mjpost/sacrebleu), которая устраняет этот недостаток (и другие) путем стандартизации этапа токенизации. Чтобы использовать эту метрику, сначала нужно установить библиотеку SacreBLEU: + +```py +!pip install sacrebleu +``` + +Затем мы можем загрузить ее с помощью `evaluate.load()`, как мы это делали в [Главе 3](/course/chapter3): + +```py +import evaluate + +metric = evaluate.load("sacrebleu") +``` + +Эта метрика принимает тексты в качестве входных и целевых данных. Она рассчитана на использование нескольких приемлемых целей, так как часто существует несколько приемлемых переводов одного и того же предложения - в используемом нами датасете есть только один, но в NLP нередко встречаются датасеты, дающие несколько предложений в качестве меток. Таким образом, прогнозы должны представлять собой список предложений, а ссылки - список списков предложений. + +Попробуем рассмотреть пример: + +```py +predictions = [ + "This plugin lets you translate web pages between several languages automatically." +] +references = [ + [ + "This plugin allows you to automatically translate web pages between several languages." + ] +] +metric.compute(predictions=predictions, references=references) +``` + +```python out +{'score': 46.750469682990165, + 'counts': [11, 6, 4, 3], + 'totals': [12, 11, 10, 9], + 'precisions': [91.67, 54.54, 40.0, 33.33], + 'bp': 0.9200444146293233, + 'sys_len': 12, + 'ref_len': 13} +``` + +Это дает оценку BLEU 46,75, что довольно хорошо - для сравнения, оригинальная модель Transformer в статье ["Attention Is All You Need" paper](https://arxiv.org/pdf/1706.03762.pdf) достигла оценки BLEU 41,8 на аналогичной задаче перевода с английского на французский! (Более подробную информацию об отдельных метриках, таких как `counts` и `bp`, можно найти в репозитории [SacreBLEU](https://github.com/mjpost/sacrebleu/blob/078c440168c6adc89ba75fe6d63f0d922d42bcfe/sacrebleu/metrics/bleu.py#L74)). С другой стороны, если мы попробуем использовать два плохих типа предсказаний (много повторов или слишком короткие), которые часто получаются в моделях перевода, мы получим довольно плохие оценки BLEU: + +```py +predictions = ["This This This This"] +references = [ + [ + "This plugin allows you to automatically translate web pages between several languages." + ] +] +metric.compute(predictions=predictions, references=references) +``` + +```python out +{'score': 1.683602693167689, + 'counts': [1, 0, 0, 0], + 'totals': [4, 3, 2, 1], + 'precisions': [25.0, 16.67, 12.5, 12.5], + 'bp': 0.10539922456186433, + 'sys_len': 4, + 'ref_len': 13} +``` + +```py +predictions = ["This plugin"] +references = [ + [ + "This plugin allows you to automatically translate web pages between several languages." + ] +] +metric.compute(predictions=predictions, references=references) +``` + +```python out +{'score': 0.0, + 'counts': [2, 1, 0, 0], + 'totals': [2, 1, 0, 0], + 'precisions': [100.0, 100.0, 0.0, 0.0], + 'bp': 0.004086771438464067, + 'sys_len': 2, + 'ref_len': 13} +``` + +Оценка может варьироваться от 0 до 100, причем чем больше, тем лучше. + +{#if fw === 'tf'} + +Чтобы получить из результатов модели тексты, которые может использовать метрика, мы воспользуемся методом `tokenizer.batch_decode()`. Нам нужно только очистить все знаки `-100` в метках; токенизатор автоматически сделает то же самое для дополняющего токена. Определим функцию, которая берет нашу модель и датасет и вычисляет на нем метрики. Мы также используем трюк, который значительно повышает производительность, - компиляцию нашего кода генерации с помощью [XLA](https://www.tensorflow.org/xla), ускоренного компилятора линейной алгебры TensorFlow. XLA применяет различные оптимизации к графу вычислений модели, что приводит к значительному увеличению скорости и использования памяти. Как описано в блоге Hugging Face [blog](https://huggingface.co/blog/tf-xla-generate), XLA лучше всего работает, когда наши входные формы не слишком сильно варьируются. Чтобы справиться с этим, мы разделим наши входные данные на части, кратные 128, и создадим новый датасет с коллатором с дополнением, а затем применим декоратор `@tf.function(jit_compile=True)` к нашей функции генерации, который обозначит всю функцию для компиляции с помощью XLA. + +```py +import numpy as np +import tensorflow as tf +from tqdm import tqdm + +generation_data_collator = DataCollatorForSeq2Seq( + tokenizer, model=model, return_tensors="tf", pad_to_multiple_of=128 +) + +tf_generate_dataset = model.prepare_tf_dataset( + tokenized_datasets["validation"], + collate_fn=generation_data_collator, + shuffle=False, + batch_size=8, +) + + +@tf.function(jit_compile=True) +def generate_with_xla(batch): + return model.generate( + input_ids=batch["input_ids"], + attention_mask=batch["attention_mask"], + max_new_tokens=128, + ) + + +def compute_metrics(): + all_preds = [] + all_labels = [] + + for batch, labels in tqdm(tf_generate_dataset): + predictions = generate_with_xla(batch) + decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) + labels = labels.numpy() + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + decoded_preds = [pred.strip() for pred in decoded_preds] + decoded_labels = [[label.strip()] for label in decoded_labels] + all_preds.extend(decoded_preds) + all_labels.extend(decoded_labels) + + result = metric.compute(predictions=all_preds, references=all_labels) + return {"bleu": result["score"]} +``` + +{:else} + +Чтобы получить из результатов модели тексты, которые может использовать метрика, мы воспользуемся методом `tokenizer.batch_decode()`. Нам просто нужно очистить все значения `-100` в метках (токенизатор автоматически сделает то же самое для дополняющего токена): + +```py +import numpy as np + + +def compute_metrics(eval_preds): + preds, labels = eval_preds + # В случае, если модель возвращает больше, чем предсказанные логиты + if isinstance(preds, tuple): + preds = preds[0] + + decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True) + + # Заменяем -100 в метках, так как мы не можем их декодировать + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + + # Немного простой постобработки + decoded_preds = [pred.strip() for pred in decoded_preds] + decoded_labels = [[label.strip()] for label in decoded_labels] + + result = metric.compute(predictions=decoded_preds, references=decoded_labels) + return {"bleu": result["score"]} +``` + +{/if} + +Теперь, когда все готово, мы готовы дообучить нашу модель! + + +### Дообучение модели[[fine-tuning-the-model]] + +Первый шаг - войти в Hugging Face, чтобы загрузить результаты в Model Hub. В блокноте есть удобная функция, которая поможет вам в этом: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +Появится виджет, в котором вы можете ввести свои учетные данные для входа в Hugging Face. + +Если вы работаете не в блокноте, просто введите следующую строку в терминале: + +```bash +huggingface-cli login +``` + +{#if fw === 'tf'} + +Прежде чем начать, давайте посмотрим, какие результаты мы получим от нашей модели без какого-либо обучения: + +```py +print(compute_metrics()) +``` + +``` +{'bleu': 33.26983701454733} +``` + +Как только это будет сделано, мы сможем подготовить все необходимое для компиляции и обучения нашей модели. Обратите внимание на использование `tf.keras.mixed_precision.set_global_policy("mixed_float16")` - это укажет Keras обучать с использованием float16, что может дать значительное ускорение на GPU, поддерживающих эту функцию (Nvidia 20xx/V100 или новее). + +```python +from transformers import create_optimizer +from transformers.keras_callbacks import PushToHubCallback +import tensorflow as tf + +# Количество шагов обучения - это количество примеров в датасете, разделенное на размер батча, затем умноженное +# на общее количество эпох. Обратите внимание, что tf_train_dataset здесь - это батч tf.data.Dataset, +# а не оригинальный датасет Hugging Face, поэтому его len() уже равен num_samples // batch_size. +num_epochs = 3 +num_train_steps = len(tf_train_dataset) * num_epochs + +optimizer, schedule = create_optimizer( + init_lr=5e-5, + num_warmup_steps=0, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) + +# Train in mixed-precision float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") +``` + +Далее мы определяем обратный вызов `PushToHubCallback` для загрузки нашей модели в Hub во время обучения, как мы видели в [разделе 2]((/course/chapter7/2)), а затем мы просто подгоняем модель с помощью этого обратного вызова: + +```python +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback( + output_dir="marian-finetuned-kde4-en-to-fr", tokenizer=tokenizer +) + +model.fit( + tf_train_dataset, + validation_data=tf_eval_dataset, + callbacks=[callback], + epochs=num_epochs, +) +``` + +Обратите внимание, что с помощью аргумента `hub_model_id` можно указать имя репозитория, в который вы хотите отправить модель (в частности, этот аргумент нужно использовать, чтобы отправить модель в организацию). Например, когда мы отправили модель в организацию [`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` в `Seq2SeqTrainingArguments`. По умолчанию используемый репозиторий будет находиться в вашем пространстве имен и называться в соответствии с заданным вами выходным каталогом, поэтому здесь это будет `"sgugger/marian-finetuned-kde4-en-to-fr"` (это модель, на которую мы ссылались в начале этого раздела). + + + +💡 Если выходной каталог, который вы используете, уже существует, он должен быть локальным клоном репозитория, в который вы хотите выполнить push. Если это не так, вы получите ошибку при вызове `model.fit()` и должны будете задать новое имя. + + + +Наконец, давайте посмотрим, как выглядят наши метрики после завершения обучения: + +```py +print(compute_metrics()) +``` + +``` +{'bleu': 57.334066271545865} +``` + +На этом этапе вы можете использовать виджет инференса на Model Hub, чтобы протестировать свою модель и поделиться ею с друзьями. Вы успешно дообучили модель для задачи перевода - поздравляем! + +{:else} + +Когда это сделано, мы можем определить наши `Seq2SeqTrainingArguments`. Как и в случае с `Trainer`, мы используем подкласс `TrainingArguments`, который содержит еще несколько дополнительных полей: + +```python +from transformers import Seq2SeqTrainingArguments + +args = Seq2SeqTrainingArguments( + f"marian-finetuned-kde4-en-to-fr", + evaluation_strategy="no", + save_strategy="epoch", + learning_rate=2e-5, + per_device_train_batch_size=32, + per_device_eval_batch_size=64, + weight_decay=0.01, + save_total_limit=3, + num_train_epochs=3, + predict_with_generate=True, + fp16=True, + push_to_hub=True, +) +``` + +Помимо обычных гиперпараметров (таких как скорость обучения, количество эпох, размер батча и некоторое затухание веса), здесь есть несколько отличий по сравнению с тем, что мы видели в предыдущих разделах: + +- Мы не задаем никаких регулярных оценок, так как оценка занимает много времени; мы просто оценим нашу модель один раз до обучения и после. +- Мы установили `fp16=True`, что ускоряет обучение на современных GPU. +- Мы устанавливаем `predict_with_generate=True`, как обсуждалось выше. +- Мы используем `push_to_hub=True` для загрузки модели в Hub в конце каждой эпохи. + +Обратите внимание, что в аргументе `hub_model_id` можно указать полное имя розитория, в который вы хотите отправить модель (в частности, этот аргумент нужно использовать, чтобы отправить модель в организацию). Например, когда мы отправили модель в организацию [`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` в `Seq2SeqTrainingArguments`. По умолчанию используемый розиторий будет находиться в вашем пространстве имен и называться в соответствии с заданным вами выходным каталогом, поэтому в нашем случае это будет `"sgugger/marian-finetuned-kde4-en-to-fr"` (это модель, на которую мы ссылались в начале этого раздела). + + + +💡 Если выходной каталог, который вы используете, уже существует, он должен быть локальным клоном того розитория, в который вы хотите выполнить push. Если это не так, вы получите ошибку при определении вашего `Seq2SeqTrainer` и должны будете задать новое имя. + + + + +Наконец, мы просто передаем все в `Seq2SeqTrainer`: + +```python +from transformers import Seq2SeqTrainer + +trainer = Seq2SeqTrainer( + model, + args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + tokenizer=tokenizer, + compute_metrics=compute_metrics, +) +``` + +Перед обучением мы сначала посмотрим, какую оценку получила наша модель, чтобы проверить, не ухудшаем ли мы результаты, дообучив ее. Выполнение этой команды займет некоторое время, поэтому во время ее выполнения можно выпить кофе: + +```python +trainer.evaluate(max_length=max_length) +``` + +```python out +{'eval_loss': 1.6964408159255981, + 'eval_bleu': 39.26865061007616, + 'eval_runtime': 965.8884, + 'eval_samples_per_second': 21.76, + 'eval_steps_per_second': 0.341} +``` + +Оценка BLEU в 39 баллов не так уж плохо, что говорит о том, что наша модель уже хорошо справляется с переводом английских предложений на французский. + +Далее следует обучение, которое также займет некоторое время: + +```python +trainer.train() +``` + +Обратите внимание, что во время обучения каждый раз, когда модель сохраняется (здесь - каждую эпоху), она загружается на Hub в фоновом режиме. Таким образом, при необходимости вы сможете возобновить обучение на другой машине. + +После завершения обучения мы снова оцениваем нашу модель - надеемся, мы увидим некоторое улучшение в показателе BLEU! + +```py +trainer.evaluate(max_length=max_length) +``` + +```python out +{'eval_loss': 0.8558505773544312, + 'eval_bleu': 52.94161337775576, + 'eval_runtime': 714.2576, + 'eval_samples_per_second': 29.426, + 'eval_steps_per_second': 0.461, + 'epoch': 3.0} +``` + +Это улучшение почти на 14 пунктов, что очень хорошо. + +Наконец, мы используем метод `push_to_hub()`, чтобы убедиться, что загружена последняя версия модели. Тренер также создает карту модели со всеми результатами оценки и загружает ее. Эта карта модели содержит метаданные, которые помогают хабу моделей выбрать виджет для демонстрации инференса. Обычно ничего не нужно указывать, так как он сам определяет нужный виджет по классу модели, но в данном случае один и тот же класс модели может быть использован для всех видов задач, связанных с последовательностями, поэтому мы указываем, что это модель перевода: + +```py +trainer.push_to_hub(tags="translation", commit_message="Training complete") +``` + +Эта команда возвращает URL-адрес только что выполненного коммита, если вы хотите его просмотреть: + +```python out +'https://huggingface.co/sgugger/marian-finetuned-kde4-en-to-fr/commit/3601d621e3baae2bc63d3311452535f8f58f6ef3' +``` + +На этом этапе вы можете использовать виджет инференса на Model Hub, чтобы протестировать свою модель и поделиться ею с друзьями. Вы успешно дообучили модель для задачи перевода - поздравляем! + +Если вы хотите более глубоко погрузиться в цикл обучения, мы покажем вам, как сделать то же самое с помощью 🤗 Accelerate. + +{/if} + +{#if fw === 'pt'} + +## Индивидуальный цикл обучения[[a-custom-training-loop]] + +Теперь давайте рассмотрим полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет выглядеть примерно так же, как мы делали это в [Главе 2](/course/chapter7/2) и [Главе 3](/course/chapter3/4). + +### Подготовка всего к обучению[[preparing-everything-for-training]] + +Вы уже видели все это несколько раз, поэтому мы пройдемся по коду довольно быстро. Сначала мы создадим `DataLoader` из наших датасетов, после чего установим для датасетов формат `"torch"`, чтобы получить тензоры PyTorch: + +```py +from torch.utils.data import DataLoader + +tokenized_datasets.set_format("torch") +train_dataloader = DataLoader( + tokenized_datasets["train"], + shuffle=True, + collate_fn=data_collator, + batch_size=8, +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], collate_fn=data_collator, batch_size=8 +) +``` + +Затем мы повторно инстанцируем нашу модель, чтобы убедиться, что мы не продолжаем дообучение предыдущей модели, а начинаем с предварительно обученной модели: + +```py +model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +Тогда нам понадобится оптимизатор: + +```py +from transformers import AdamW + +optimizer = AdamW(model.parameters(), lr=2e-5) +``` + +Когда у нас есть все эти объекты, мы можем отправить их в метод `accelerator.prepare()`. Помните, что если вы хотите обучаться на TPU в блокноте Colab, вам нужно будет перенести весь этот код в функцию обучения, которая не должна выполнять ни одной ячейки, инстанцирующей `Accelerator`. + +```py +from accelerate import Accelerator + +accelerator = Accelerator() +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +Теперь, когда мы отправили наш `train_dataloader` в `accelerator.prepare()`, мы можем использовать его длину для вычисления количества шагов обучения. Помните, что это всегда нужно делать после подготовки загрузчика данных, так как этот метод изменит длину `DataLoader`. Мы используем классический линейный планировшик скорости обучения до 0: + +```py +from transformers import get_scheduler + +num_train_epochs = 3 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +Наконец, чтобы отправить нашу модель в Hub, нам нужно создать объект `Repository` в рабочей папке. Сначала войдите в Hub Hugging Face, если вы еще не авторизованы. Мы определим имя розитория по идентификатору модели, который мы хотим присвоить нашей модели (не стесняйтесь заменить `repo_name` на свой собственный выбор; оно просто должно содержать ваше имя пользователя, что и делает функция `get_full_repo_name()`): + +```py +from huggingface_hub import Repository, get_full_repo_name + +model_name = "marian-finetuned-kde4-en-to-fr-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'sgugger/marian-finetuned-kde4-en-to-fr-accelerate' +``` + +Затем мы можем клонировать этот розиторий в локальную папку. Если она уже существует, эта локальная папка должна быть клоном того розитория, с которым мы работаем: + +```py +output_dir = "marian-finetuned-kde4-en-to-fr-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +Теперь мы можем загрузить все, что сохранили в `output_dir`, вызвав метод `repo.push_to_hub()`. Это поможет нам загружать промежуточные модели в конце каждой эпохи. + +### Цикл обучения[[training-loop]] + +Теперь мы готовы написать полный цикл обучения. Чтобы упростить его оценочную часть, мы определяем эту функцию `postprocess()`, которая принимает прогнозы и метки и преобразует их в списки строк, которые будет ожидать наш объект `metric`: + +```py +def postprocess(predictions, labels): + predictions = predictions.cpu().numpy() + labels = labels.cpu().numpy() + + decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) + + # Заменим -100 в метках, так как мы не можем их декодировать. + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + + # Немного простой постобработки + decoded_preds = [pred.strip() for pred in decoded_preds] + decoded_labels = [[label.strip()] for label in decoded_labels] + return decoded_preds, decoded_labels +``` + +Цикл обучения очень похож на циклы в [разделе 2](/course/chapter7/2) и [главе 3](/course/chapter3), с некоторыми отличиями в части оценки - так что давайте сосредоточимся на этом! + +Первое, что следует отметить, это то, что мы используем метод `generate()` для вычисления прогнозов, но это метод нашей базовой модели, а не обернутой модели 🤗 Accelerate, созданной в методе `prepare()`. Поэтому мы сначала развернем модель, а затем вызовем этот метод. + +Второй момент заключается в том, что, как и в случае с [классификацией токенов](/course/chapter7/2), два процесса могут дополнить входы и метки до разных форм, поэтому мы используем `accelerator.pad_across_processes()`, чтобы сделать прогнозы и метки одинаковыми по форме перед вызовом метода `gather()`. Если мы этого не сделаем, оценка либо выдаст ошибку, либо зависнет навсегда. + +```py +from tqdm.auto import tqdm +import torch + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Обучение + model.train() + for batch in train_dataloader: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Оценка + model.eval() + for batch in tqdm(eval_dataloader): + with torch.no_grad(): + generated_tokens = accelerator.unwrap_model(model).generate( + batch["input_ids"], + attention_mask=batch["attention_mask"], + max_length=128, + ) + labels = batch["labels"] + + ## Необходимо дополнить прогнозы и метки + generated_tokens = accelerator.pad_across_processes( + generated_tokens, dim=1, pad_index=tokenizer.pad_token_id + ) + labels = accelerator.pad_across_processes(labels, dim=1, pad_index=-100) + + predictions_gathered = accelerator.gather(generated_tokens) + labels_gathered = accelerator.gather(labels) + + decoded_preds, decoded_labels = postprocess(predictions_gathered, labels_gathered) + metric.add_batch(predictions=decoded_preds, references=decoded_labels) + + results = metric.compute() + print(f"epoch {epoch}, BLEU score: {results['score']:.2f}") + + # Сохранение и загрузка + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +```python out +epoch 0, BLEU score: 53.47 +epoch 1, BLEU score: 54.24 +epoch 2, BLEU score: 54.44 +``` + +После этого у вас должна получиться модель, результаты которой будут очень похожи на модель, обученную с помощью `Seq2SeqTrainer`. Вы можете проверить модель, которую мы обучили с помощью этого кода, на [*huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate*](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate). А если вы хотите протестировать какие-либо изменения в цикле обучения, вы можете реализовать их напрямую, отредактировав код, показанный выше! + +{/if} + +## Использование дообученной модели[[using-the-fine-tuned-model]] + +Мы уже показали вам, как можно использовать модель, которую мы дообучили на Model Hub, с помощью виджета инференса. Чтобы использовать ее локально в `pipeline`, нам просто нужно указать соответствующий идентификатор модели: + +```py +from transformers import pipeline + +# Замените это на свою собственную контрольную точку +model_checkpoint = "huggingface-course/marian-finetuned-kde4-en-to-fr" +translator = pipeline("translation", model=model_checkpoint) +translator("Default to expanded threads") +``` + +```python out +[{'translation_text': 'Par défaut, développer les fils de discussion'}] +``` + +Как и ожидалось, наша предварительно обученная модель адаптировала свои знания к корпусу, на котором мы ее дообучили, и вместо того, чтобы оставить английское слово "threads" в покое, она теперь переводит его на официальный французский вариант. То же самое относится и к слову " plugin ": + +```py +translator( + "Unable to import %1 using the OFX importer plugin. This file is not the correct format." +) +``` + +```python out +[{'translation_text': "Impossible d'importer %1 en utilisant le module externe d'importation OFX. Ce fichier n'est pas le bon format."}] +``` + +Еще один отличный пример доменной адаптации! + + + +✏️ **Попробуйте!** Что возвращает модель для примера со словом "email", который вы определили ранее? + + diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx new file mode 100644 index 000000000..fbe935615 --- /dev/null +++ b/chapters/ru/chapter7/5.mdx @@ -0,0 +1,1073 @@ + + +# Суммаризация[[summarization]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +В этом разделе мы рассмотрим, как модели Transformer могут быть использованы для сжатия длинных документов в краткое изложение - задача, известная как _суммаризация текста (text summarization)_. Это одна из самых сложных задач NLP, поскольку она требует целого ряда способностей, таких как понимание длинных отрывков и генерация связного текста, отражающего основные темы документа. Однако при правильном подходе суммаризация текста - это мощный инструмент, который может ускорить различные бизнес-процессы, избавив экспертов домена от необходимости детального прочтения длинных документов. + + + +Хотя на [Hugging Face Hub](https://huggingface.co/models?pipeline_tag=summarization&sort=downloads) уже существуют различные дообученные модели для суммаризации, почти все они подходят только для англоязычных документов. Поэтому, чтобы добавить изюминку в этот раздел, мы обучим двухязыковую модель для английского и испанского языков. К концу этого раздела у вас будет [модель](https://huggingface.co/huggingface-course/mt5-small-finetuned-amazon-en-es), способная к суммаризации отзывов покупателей, как показано здесь: + + + +Как мы увидим, эти резюме кратки, поскольку они составляются на основе названий, которые покупатели указывают в своих отзывах о товаре. Для начала давайте соберем подходящий двуязыковой корпус для этой задачи. + +## Подготовка многоязыкового корпуса[[preparing-a-multilingual-corpus]] + +Для создания нашей двуязыковой суммаризации мы будем использовать [Multilingual Amazon Reviews Corpus](https://huggingface.co/datasets/amazon_reviews_multi). Этот корпус состоит из отзывов о товарах Amazon на шести языках и обычно используется для тестирования многоязыковых классификаторов. Однако, поскольку каждый отзыв сопровождается коротким заголовком, мы можем использовать заголовки в качестве целевых резюме для обучения нашей модели! Чтобы начать работу, давайте загрузим английские и испанские подмножества из Hugging Face Hub: + +```python +from datasets import load_dataset + +spanish_dataset = load_dataset("amazon_reviews_multi", "es") +english_dataset = load_dataset("amazon_reviews_multi", "en") +english_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'], + num_rows: 200000 + }) + validation: Dataset({ + features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'], + num_rows: 5000 + }) + test: Dataset({ + features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'], + num_rows: 5000 + }) +}) +``` + +Как видите, для каждого языка есть 200 000 отзывов в части `train` и по 5 000 отзывов в частях `validation` и `test`. Интересующая нас информация о рецензиях содержится в столбцах `review_body` и `review_title`. Давайте рассмотрим несколько примеров, создав простую функцию, которая берет случайную выборку из обучающего множества с помощью методов, изученных в [Главе 5](/course/chapter5): + +```python +def show_samples(dataset, num_samples=3, seed=42): + sample = dataset["train"].shuffle(seed=seed).select(range(num_samples)) + for example in sample: + print(f"\n'>> Title: {example['review_title']}'") + print(f"'>> Review: {example['review_body']}'") + + +show_samples(english_dataset) +``` + +```python out +'>> Title: Worked in front position, not rear' +'>> Review: 3 stars because these are not rear brakes as stated in the item description. At least the mount adapter only worked on the front fork of the bike that I got it for.' + +'>> Title: meh' +'>> Review: Does it’s job and it’s gorgeous but mine is falling apart, I had to basically put it together again with hot glue' + +'>> Title: Can\'t beat these for the money' +'>> Review: Bought this for handling miscellaneous aircraft parts and hanger "stuff" that I needed to organize; it really fit the bill. The unit arrived quickly, was well packaged and arrived intact (always a good sign). There are five wall mounts-- three on the top and two on the bottom. I wanted to mount it on the wall, so all I had to do was to remove the top two layers of plastic drawers, as well as the bottom corner drawers, place it when I wanted and mark it; I then used some of the new plastic screw in wall anchors (the 50 pound variety) and it easily mounted to the wall. Some have remarked that they wanted dividers for the drawers, and that they made those. Good idea. My application was that I needed something that I can see the contents at about eye level, so I wanted the fuller-sized drawers. I also like that these are the new plastic that doesn\'t get brittle and split like my older plastic drawers did. I like the all-plastic construction. It\'s heavy duty enough to hold metal parts, but being made of plastic it\'s not as heavy as a metal frame, so you can easily mount it to the wall and still load it up with heavy stuff, or light stuff. No problem there. For the money, you can\'t beat it. Best one of these I\'ve bought to date-- and I\'ve been using some version of these for over forty years.' +``` + + + +✏️ **Попробуйте!** Измените random seed в команде `Dataset.shuffle()`, чтобы изучить другие отзывы в корпусе. Если вы владеете испанским языком, посмотрите на некоторые отзывы в `spanish_dataset`, чтобы понять, похожи ли их названия на разумные резюме. + + + +Эта выборка демонстрирует разнообразие отзывов, которые обычно можно найти в сети, - от положительных до отрицательных (и все, что между ними!). Хотя пример с названием "meh" не очень информативен, остальные названия выглядят как достойные резюме самих отзывов. Обучение модели суммаризации всех 400 000 отзывов заняло бы слишком много времени на одном GPU, поэтому вместо этого мы сосредоточимся на создании резюме для одного домена продуктов. Чтобы получить представление о том, какие домены мы можем выбрать, давайте преобразуем `english_dataset` в `pandas.DataFrame` и вычислим количество отзывов по каждой категории товаров: + +```python +english_dataset.set_format("pandas") +english_df = english_dataset["train"][:] +# Show counts for top 20 products +english_df["product_category"].value_counts()[:20] +``` + +```python out +home 17679 +apparel 15951 +wireless 15717 +other 13418 +beauty 12091 +drugstore 11730 +kitchen 10382 +toy 8745 +sports 8277 +automotive 7506 +lawn_and_garden 7327 +home_improvement 7136 +pet_products 7082 +digital_ebook_purchase 6749 +pc 6401 +electronics 6186 +office_product 5521 +shoes 5197 +grocery 4730 +book 3756 +Name: product_category, dtype: int64 +``` + +Самые популярные товары в английском датасете - это бытовые товары, одежда и беспроводная электроника. Однако, чтобы поддержать тему Amazon, давайте сосредоточимся на суммаризации отзывов о книгах - в конце концов, именно для этого компания и была основана! Мы видим две категории товаров, которые подходят для этой цели (`book` и `digital_ebook_purchase`), поэтому давайте отфильтруем датасеты на обоих языках только для этих товаров. Как мы видели в [Главе 5](/course/chapter5), функция `Dataset.filter()` позволяет нам очень эффективно разделять датасет на части, поэтому мы можем определить простую функцию для этого: + +```python +def filter_books(example): + return ( + example["product_category"] == "book" + or example["product_category"] == "digital_ebook_purchase" + ) +``` + +Теперь, когда мы применим эту функцию к `english_dataset` и `spanish_dataset`, результат будет содержать только те строки, в которых присутствуют категории книг. Прежде чем применить фильтр, давайте изменим формат `english_dataset` с `"pandas"` обратно на `"arrow"`: + +```python +english_dataset.reset_format() +``` + +Затем мы можем применить функцию фильтрации, и в качестве проверки работоспособности давайте посмотрим на выборку отзывов, чтобы убедиться, что они действительно посвящены книгам: + +```python +spanish_books = spanish_dataset.filter(filter_books) +english_books = english_dataset.filter(filter_books) +show_samples(english_books) +``` + +```python out +'>> Title: I\'m dissapointed.' +'>> Review: I guess I had higher expectations for this book from the reviews. I really thought I\'d at least like it. The plot idea was great. I loved Ash but, it just didnt go anywhere. Most of the book was about their radio show and talking to callers. I wanted the author to dig deeper so we could really get to know the characters. All we know about Grace is that she is attractive looking, Latino and is kind of a brat. I\'m dissapointed.' + +'>> Title: Good art, good price, poor design' +'>> Review: I had gotten the DC Vintage calendar the past two years, but it was on backorder forever this year and I saw they had shrunk the dimensions for no good reason. This one has good art choices but the design has the fold going through the picture, so it\'s less aesthetically pleasing, especially if you want to keep a picture to hang. For the price, a good calendar' + +'>> Title: Helpful' +'>> Review: Nearly all the tips useful and. I consider myself an intermediate to advanced user of OneNote. I would highly recommend.' +``` + +Хорошо, мы видим, что отзывы не совсем о книгах и могут относиться к таким вещам, как календари и электронные приложения, например OneNote. Тем не менее, домен кажется подходящим для обучения модели суммаризации. Прежде чем мы рассмотрим различные модели, подходящие для этой задачи, нам осталось подготовить данные: объединить английские и испанские отзывы в один объект `DatasetDict`. 🤗Datasets предоставляет удобную функцию `concatenate_datasets()`, которая (как следует из названия) стекирует два объекта `Dataset` друг на друга. Таким образом, чтобы создать двуязыковой датасет, мы пройдемся по каждой части, объединим датасеты для этой части и перемешаем результат, чтобы наша модель не была слишком переобучена для одного языка: + +```python +from datasets import concatenate_datasets, DatasetDict + +books_dataset = DatasetDict() + +for split in english_books.keys(): + books_dataset[split] = concatenate_datasets( + [english_books[split], spanish_books[split]] + ) + books_dataset[split] = books_dataset[split].shuffle(seed=42) + +# Посмотрим на несколько примеров +show_samples(books_dataset) +``` + +```python out +'>> Title: Easy to follow!!!!' +'>> Review: I loved The dash diet weight loss Solution. Never hungry. I would recommend this diet. Also the menus are well rounded. Try it. Has lots of the information need thanks.' + +'>> Title: PARCIALMENTE DAÑADO' +'>> Review: Me llegó el día que tocaba, junto a otros libros que pedí, pero la caja llegó en mal estado lo cual dañó las esquinas de los libros porque venían sin protección (forro).' + +'>> Title: no lo he podido descargar' +'>> Review: igual que el anterior' +``` + +Это определенно похоже на смесь английских и испанских обзоров! Теперь, когда у нас есть тренировочный корпус, осталось проверить распределение слов в рецензиях и их заголовках. Это особенно важно для задач суммаризации, где короткие эталонные резюме в данных могут склонять модель в сторону вывода только одного или двух слов в сгенерированных резюме. На графиках ниже показаны распределения слов, и мы видим, что названия сильно перекошены в сторону 1-2 слов: + +
+Word count distributions for the review titles and texts. + +
+ +Чтобы справиться с этой проблемой, мы отфильтруем примеры с очень короткими заголовками, чтобы наша модель могла создавать более интересные резюме. Поскольку мы имеем дело с английскими и испанскими текстами, мы можем использовать грубую эвристику для разделения названий по символам пробела, а затем использовать наш надежный метод `Dataset.filter()` следующим образом: + +```python +books_dataset = books_dataset.filter(lambda x: len(x["review_title"].split()) > 2) +``` + +Теперь, когда мы подготовили корпус, давайте рассмотрим несколько возможных моделей Transformer, которые можно было бы дообучить на его основе! + +## Модели для суммаризации текста[[models-for-text-summarization]] + +Если задуматься, то суммаризация текста - это задача, похожая на машинный перевод: у нас есть текст, например рецензия, который мы хотели бы "перевести" в более короткую версию, передающую основные особенности исходного текста. Соответственно, большинство моделей Transformer для суммаризации используют архитектуру кодер-декодер, с которой мы впервые столкнулись в [Глава 1] (/course/chapter1), хотя есть и исключения, например семейство моделей GPT, которые также могут использоваться для суммаризации в условиях few-shot настроек. В следующей таблице перечислены некоторые популярные предварительно обученные модели, которые можно дообучить для суммаризации. + +| Модель Transformer | Описание | Многоязычная? | +| :---------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------: | +| [GPT-2](https://huggingface.co/gpt2-xl) | Хотя GPT-2 обучен как авторегрессивная языковая модель, вы можете заставить его генерировать резюме, добавляя "TL;DR" в конце входного текста. | ❌ | +| [PEGASUS](https://huggingface.co/google/pegasus-large) | Использует цель предварительного обучения для предсказания замаскированных предложений в текстах с несколькими предложениями. Эта задача предварительного обучения ближе к суммаризации, чем к классическому языковому моделированию демонстрирует высокие результаты в популярных бенчмарках. + | ❌ | +| [T5](https://huggingface.co/t5-base) | Универсальная трансформерная архитектура, которая формулирует все задачи в рамках преобразования текста в текст; например, входной формат модели для суммаризации документа - `summarize: ARTICLE`. | ❌ | +| [mT5](https://huggingface.co/google/mt5-base) | Многоязыковая версия T5, предварительно обученная на многоязыковом корпусе Common Crawl (mC4), охватывающем 101 язык. | ✅ | +| [BART](https://huggingface.co/facebook/bart-base) | Новая архитектура Transformer с кодером и стеком декодеров, обученных восстанавливать поврежденный входной сигнал, сочетает в себе схемы предварительного обучения BERT и GPT-2. | ❌ | +| [mBART-50](https://huggingface.co/facebook/mbart-large-50) | Многоязыковая версия BART, предварительно обученная на 50 языках. | ✅ | + +Как видно из этой таблицы, большинство моделей Transformer для суммаризации (и вообще для большинства задач NLP) являются монолингвистическими. Это хорошо, если ваша задача на "высокоресурсном" языке, таком как английский или немецкий, но не очень хорошо для тысяч других языков, используемых по всему миру. К счастью, существует класс многоязыковых моделей Transformer, таких как mT5 и mBART, которые приходят на помощь. Эти модели предварительно обучаются с помощью языкового моделирования, но с изюминкой: вместо обучения на корпусе одного языка они обучаются совместно на текстах более чем на 50 языках одновременно! + +Мы сосредоточимся на mT5, интересной архитектуре, основанной на T5, которая была предварительно обучена на фреймворке "текс-в-текст" (text-to-text). В T5 каждая задача NLP формулируется в терминах префикса подсказки, например `summarize:`, который определяет, что модель должна адаптировать сгенерированный текст к подсказке. Как показано на рисунке ниже, это делает T5 чрезвычайно универсальным, поскольку вы можете решать множество задач с помощью одной модели! + +
+Different tasks performed by the T5 architecture. + +
+ +В mT5 не используются префиксы, но она обладает многими универсальными возможностями T5 и имеет многоязыковое преимущество. Теперь, когда мы выбрали модель, давайте посмотрим, как подготовить данные для обучения. + + + + +✏️ **Попробуйте!** После того как вы проработаете этот раздел, посмотрите, насколько хорошо mT5 сравнится с mBART, дообучив его тем же методам. Чтобы получить бонусные очки, вы также можете попробовать дообучить T5 только на английских рецензиях. Поскольку в T5 есть специальный префикс запроса, вам нужно будет добавить `summarize:` к входным примерам на следующих шагах предварительной обработки. + + + +## Предварительная обработка данных[[preprocessing-the-data]] + + + +Наша следующая задача - токенизация и кодирование отзывов и их заголовков. Как обычно, мы начинаем с загрузки токенизатора, связанного с контрольной точкой предварительно обученной модели. В качестве контрольной точки мы будем использовать `mt5-small`, чтобы можно было дообучить модель за разумное время: + +```python +from transformers import AutoTokenizer + +model_checkpoint = "google/mt5-small" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + + + +💡 На ранних стадиях ваших NLP-проектов хорошей практикой является обучение класса "маленьких" моделей на небольшой выборке данных. Это позволит вам быстрее отлаживать и итерировать модели, чтобы создать сквозной рабочий процесс. Когда вы будете уверены в результатах, вы всегда сможете увеличить масштаб модели, просто изменив контрольную точку модели! + + + +Давайте протестируем токенизатор mT5 на небольшом примере: + +```python +inputs = tokenizer("I loved reading the Hunger Games!") +inputs +``` + +```python out +{'input_ids': [336, 259, 28387, 11807, 287, 62893, 295, 12507, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +Здесь мы видим знакомые нам `input_ids` и `attention_mask`, с которыми мы столкнулись в наших первых экспериментах по дообучению еще в [Главе 3] (/course/chapter3). Давайте декодируем эти входные идентификаторы с помощью функции токенизатора `convert_ids_to_tokens()`, чтобы понять, с каким токенизатором мы имеем дело: + +```python +tokenizer.convert_ids_to_tokens(inputs.input_ids) +``` + +```python out +['▁I', '▁', 'loved', '▁reading', '▁the', '▁Hung', 'er', '▁Games', ''] +``` + +Специальный символ Юникода `▁` и токен конца последовательности `` указывают на то, что мы имеем дело с токенизатором SentencePiece, который основан на алгоритме сегментации Unigram, рассмотренном в [Главе 6] (/course/chapter6). Unigram особенно полезен для многоязычных корпусов, поскольку он позволяет SentencePiece не зависеть от ударений, пунктуации и того факта, что во многих языках, например в японском, нет пробельных символов. + +Для токенизации нашего корпуса нам придется столкнуться с одной тонкостью, связанной с сумризацией: поскольку наши метки также являются текстом, возможно, что они превышают максимальный размер контекста модели. Это означает, что нам нужно применять усечение как к обзорам, так и к их заголовкам, чтобы не передавать в модель слишком длинные данные. Токенизаторы в 🤗 Transformers предоставляют интересный аргумент `text_target`, который позволяет вам токенизировать метки параллельно с входными данными. Вот пример того, как обрабатываются входные и целевые данные для mT5: + +```python +max_input_length = 512 +max_target_length = 30 + + +def preprocess_function(examples): + model_inputs = tokenizer( + examples["review_body"], + max_length=max_input_length, + truncation=True, + ) + labels = tokenizer( + examples["review_title"], max_length=max_target_length, truncation=True + ) + model_inputs["labels"] = labels["input_ids"] + return model_inputs +``` + +Давайте пройдемся по этому коду, чтобы понять, что происходит. Первое, что мы сделали, это определили значения `max_input_length` и `max_target_length`, которые устанавливают верхние границы длины наших обзоров и заголовков. Поскольку тело обзора обычно намного больше заголовка, мы соответственно изменили эти значения. + +С помощью `preprocess_function()` можно провести токенизацию всего корпуса с помощью удобной функции `Dataset.map()`, которую мы часто использовали на протяжении всего курса: + +```python +tokenized_datasets = books_dataset.map(preprocess_function, batched=True) +``` + +Теперь, когда корпус был предварительно обработан, давайте посмотрим на некоторые метрики, которые обычно используются для суммаризации. Как мы увидим, не существует серебряной пули, когда дело доходит до измерения качества сгенерированного машиной текста. + + + +💡 Возможно, вы заметили, что выше в функции `Dataset.map()` мы использовали `batched=True`. Это кодирует примеры в батчах по 1 000 (по умолчанию) и позволяет использовать возможности многопоточности быстрых токенизаторов в 🤗 Transformers. По возможности, попробуйте использовать `batched=True`, чтобы получить максимальную отдачу от препроцессинга! + + + + +## Метрики для суммаризации текста[[metrics-for-text-summarization]] + + + +По сравнению с большинством других задач, которые мы рассматривали в этом курсе, измерение качества работы задач по созданию текста, таких как суммаризация или перевод, не так просто. Например, для рецензии типа "I loved reading the Hunger Games" существует множество правильных резюме, таких как "I loved the Hunger Games" или "Hunger Games is a great read". Очевидно, что применение какого-то точного соответствия между сгенерированным резюме и меткой не является хорошим решением - даже люди не справятся с такой метрикой, потому что у каждого из нас свой стиль написания. + +Для суммаризации одной из наиболее часто используемых метрик является [оценка ROUGE](https://en.wikipedia.org/wiki/ROUGE_(metric)) (сокращение от Recall-Oriented Understudy for Gisting Evaluation). Основная идея этой метрики заключается в сравнении сгенерированного резюме с набором эталонных резюме, которые обычно создаются людьми. Чтобы сделать ее более точной, предположим, что мы хотим сравнить следующие два резюме: + +```python +generated_summary = "I absolutely loved reading the Hunger Games" +reference_summary = "I loved reading the Hunger Games" +``` + +Одним из способов их сравнения может быть подсчет количества перекрывающихся слов, которых в данном случае будет 6. Однако это несколько грубовато, поэтому вместо этого ROUGE основывается на вычислении оценок _precision_ и _recall_ для перекрытия. + + + +🙋 Не волнуйтесь, если вы впервые слышите о precision и recall - мы вместе разберем несколько наглядных примеров, чтобы все стало понятно. Эти метрики обычно встречаются в задачах классификации, поэтому, если вы хотите понять, как определяются precision и recall в этом контексте, мы рекомендуем ознакомиться с `scikit-learn` [руководством](https://scikit-learn.org/stable/auto_examples/model_selection/plot_precision_recall.html). + + + +Для ROUGE recall измеряет, насколько эталонное резюме соответствует сгенерированному. Если мы просто сравниваем слова, recall можно рассчитать по следующей формуле: + +$$ \mathrm{Recall} = \frac{\mathrm{Number\,of\,overlapping\, words}}{\mathrm{Total\, number\, of\, words\, in\, reference\, summary}} $$ + +Для нашего простого примера выше эта формула дает идеальный recall 6/6 = 1; то есть все слова в эталонном резюме были получены моделью. Это может показаться замечательным, но представьте, если бы сгенерированное нами резюме было "I really really loved reading the Hunger Games all night". Это тоже дало бы идеальный recall, но, возможно, было бы хуже, поскольку было бы многословным. Чтобы справиться с этими сценариями, мы также вычисляем precision, которая в контексте ROUGE измеряет, насколько сгенерированное резюме было релевантным: + +$$ \mathrm{Precision} = \frac{\mathrm{Number\,of\,overlapping\, words}}{\mathrm{Total\, number\, of\, words\, in\, generated\, summary}} $$ + +Если применить это к нашему подробному резюме, то precision составит 6/10 = 0,6, что значительно хуже, чем precision 6/7 = 0,86, полученная при использовании более короткого резюме. На практике обычно вычисляют и precision, и recall, а затем F1-score (среднее гармоническое из precision и recall). Мы можем легко это сделать с помощью 🤗 Datasets, предварительно установив пакет `rouge_score`: + +```py +!pip install rouge_score +``` + +а затем загрузить метрику ROUGE следующим образом: + +```python +import evaluate + +rouge_score = evaluate.load("rouge") +``` + +Затем мы можем использовать функцию `rouge_score.compute()`, чтобы рассчитать все метрики сразу: + +```python +scores = rouge_score.compute( + predictions=[generated_summary], references=[reference_summary] +) +scores +``` + +```python out +{'rouge1': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92)), + 'rouge2': AggregateScore(low=Score(precision=0.67, recall=0.8, fmeasure=0.73), mid=Score(precision=0.67, recall=0.8, fmeasure=0.73), high=Score(precision=0.67, recall=0.8, fmeasure=0.73)), + 'rougeL': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92)), + 'rougeLsum': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92))} +``` + +Ого, в этом выводе много информации - что же она означает? Во-первых, 🤗 Datasets действительно вычисляет доверительные интервалы для precision, recall и F1-score; это `low`, `mid`, и `high` атрибуты, которые вы можете здесь увидеть. Кроме того, 🤗 Dataset вычисляет различные оценки ROUGE, которые основаны на различных типах детализации текста при сравнении сгенерированных и эталонных резюме. Вариант `rouge1` представляет собой перекрытие униграмм - это просто модный способ сказать о перекрытии слов, и это именно та метрика, которую мы обсуждали выше. Чтобы убедиться в этом, давайте извлечем `среднее` значение наших оценок: + +```python +scores["rouge1"].mid +``` + +```python out +Score(precision=0.86, recall=1.0, fmeasure=0.92) +``` + +Отлично, показатели precision и recall совпадают! А как насчет других показателей ROUGE? `rouge2` измеряет перекрытие биграмм (считайте, что это перекрытие пар слов), а `rougeL` и `rougeLsum` измеряют самые длинные совпадающие последовательности слов, ища самые длинные общие подстроки в сгенерированных и эталонных резюме. Слово "sum" в `rougeLsum` означает, что эта метрика вычисляется для всего резюме, в то время как `rougeL` вычисляется как среднее по отдельным предложениям. + + + +✏️ **Попробуйте!** Создайте свой собственный пример сгенерированного и эталонного резюме и посмотрите, согласуются ли полученные оценки ROUGE с ручным расчетом по формулам precision и recall. Для получения бонусных очков разбейте текст на биграммы и сравните precision и recall для метрики `rouge2`. + + + +Мы будем использовать эту оценку ROUGE для отслеживания эффективности нашей модели, но перед этим давайте сделаем то, что должен сделать каждый хороший NLP-практик: создадим сильную, но простую базовую модель! + +### Создание сильного базового уровня[[creating-a-strong-baseline]] + +Для суммаризации текста обычно берут первые три предложения статьи, что часто называют базвым уровнем _lead-3_. Мы могли бы использовать символы полной остановки для отслеживания границ предложений, но это не поможет при использовании таких аббревиатур, как " U.S." или "U.N.". -- поэтому вместо этого мы воспользуемся библиотекой `nltk`, которая включает в себя лучший алгоритм для таких случаев. Вы можете установить пакет с помощью `pip` следующим образом: + +```python +!pip install nltk +``` + +а затем скачайте правила пунктуации: + +```python +import nltk + +nltk.download("punkt") +``` + +Далее мы импортируем токенизатор предложений из `nltk` и создадим простую функцию для извлечения первых трех предложений в обзоре. При суммаризации текста принято отделять каждое предложение новой строкой, поэтому давайте включим эту функцию и протестируем ее на обучающем примере: + +```python +from nltk.tokenize import sent_tokenize + + +def three_sentence_summary(text): + return "\n".join(sent_tokenize(text)[:3]) + + +print(three_sentence_summary(books_dataset["train"][1]["review_body"])) +``` + +```python out +'I grew up reading Koontz, and years ago, I stopped,convinced i had "outgrown" him.' +'Still,when a friend was looking for something suspenseful too read, I suggested Koontz.' +'She found Strangers.' +``` + +Похоже, что это работает, так что теперь давайте реализуем функцию, которая извлекает эти "резюме" из датасета и вычисляет оценку ROUGE для базового уровня: + +```python +def evaluate_baseline(dataset, metric): + summaries = [three_sentence_summary(text) for text in dataset["review_body"]] + return metric.compute(predictions=summaries, references=dataset["review_title"]) +``` + +Затем мы можем использовать эту функцию для вычисления оценок ROUGE на валидационном множестве и немного приукрасить их с помощью Pandas: + +```python +import pandas as pd + +score = evaluate_baseline(books_dataset["validation"], rouge_score) +rouge_names = ["rouge1", "rouge2", "rougeL", "rougeLsum"] +rouge_dict = dict((rn, round(score[rn].mid.fmeasure * 100, 2)) for rn in rouge_names) +rouge_dict +``` + +```python out +{'rouge1': 16.74, 'rouge2': 8.83, 'rougeL': 15.6, 'rougeLsum': 15.96} +``` + +Мы видим, что оценка `rouge2` значительно ниже, чем у остальных; скорее всего, это отражает тот факт, что заголовки рецензий обычно лаконичны, и поэтому базовый уровень lead-3 слишком многословен. Теперь, когда у нас есть хороший базовый уровень для работы, давайте дообучим mT5! + +{#if fw === 'pt'} + +## Дообучение mT5 с API `Trainer`[[fine-tuning-mt5-with-the-trainer-api]] + +Дообучение модели суммаризации очень похоже на другие задачи, которые мы рассмотрели в этой главе. Первое, что нам нужно сделать, это загрузить предварительно обученную модель из контрольной точки `mt5-small`. Поскольку суммаризация - это задача преобразования последовательности в последовательность, мы можем загрузить модель с помощью класса `AutoModelForSeq2SeqLM`, который автоматически загрузит и кэширует веса: + +```python +from transformers import AutoModelForSeq2SeqLM + +model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +{:else} + +## Дообучение mT5 с Keras[[fine-tuning-mt5-with-keras]] + +Дообучение модели суммаризации очень похоже на другие задачи, которые мы рассмотрели в этой главе. Первое, что нам нужно сделать, это загрузить предварительно обученную модель из контрольной точки `mt5-small`. Поскольку суммаризация - это задача преобразования последовательности в последовательность, мы можем загрузить модель с помощью класса `TFAutoModelForSeq2SeqLM`, который автоматически загрузит и кэширует веса: + +```python +from transformers import TFAutoModelForSeq2SeqLM + +model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +{/if} + + + +💡 Если вы задаетесь вопросом, почему вы не видите предупреждений о необходимости дообучить модель для последующей задачи, то это потому, что для задач "последовательность-в-последовательность" мы сохраняем все веса сети. Сравните это с нашей моделью классификации текста из [Главы 3](/course/chapter3), где голова предварительно обученной модели была заменена на случайно инициализированную сеть. + + + +Следующее, что нам нужно сделать, это войти в Hugging Face Hub. Если вы выполняете этот код в ноутбуке, вы можете сделать это с помощью следующей полезной функции: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +которая отобразит виджет, где вы можете ввести свои учетные данные. Также вы можете запустить эту команду в терминале и войти в систему там: + +``` +huggingface-cli login +``` + +{#if fw === 'pt'} + +Для вычисления оценки ROUGE в процессе обучения нам понадобится генерировать резюме. К счастью, 🤗 Transformers предоставляет специальные классы `Seq2SeqTrainingArguments` и `Seq2SeqTrainer`, которые могут сделать это за нас автоматически! Чтобы увидеть, как это работает, давайте сначала определим гиперпараметры и другие аргументы для наших экспериментов: + +```python +from transformers import Seq2SeqTrainingArguments + +batch_size = 8 +num_train_epochs = 8 +# Show the training loss with every epoch +logging_steps = len(tokenized_datasets["train"]) // batch_size +model_name = model_checkpoint.split("/")[-1] + +args = Seq2SeqTrainingArguments( + output_dir=f"{model_name}-finetuned-amazon-en-es", + evaluation_strategy="epoch", + learning_rate=5.6e-5, + per_device_train_batch_size=batch_size, + per_device_eval_batch_size=batch_size, + weight_decay=0.01, + save_total_limit=3, + num_train_epochs=num_train_epochs, + predict_with_generate=True, + logging_steps=logging_steps, + push_to_hub=True, +) +``` + +Здесь аргумент `predict_with_generate` был задан, чтобы указать, что мы должны генерировать резюме во время оценки, чтобы мы могли вычислить баллы ROUGE для каждой эпохи. Как обсуждалось в [Главе 1](/course/chapter1), декодер выполняет инференс, предсказывая токены по одному, и это реализуется методом модели `generate()`. Задание `predict_with_generate=True` указывает `Seq2SeqTrainer` на использование этого метода для оценки. Мы также скорректировали некоторые гиперпараметры по умолчанию, такие как скорость обучения, количество эпох и затухание весов, и задали параметр `save_total_limit`, чтобы сохранять только 3 контрольные точки во время обучения - это сделано потому, что даже "маленькая" версия mT5 использует около Гигабайта места на жестком диске, и мы можем сэкономить немного места, ограничив количество копий, которые мы сохраняем. + +Аргумент `push_to_hub=True` позволит нам отправить модель в Hub после обучения; вы найдете розиторий под своим профилем пользователя в месте, определенном `output_dir`. Обратите внимание, что вы можете указать имя розитория, в который хотите отправить модель, с помощью аргумента `hub_model_id` (в частности, вам нужно использовать этот аргумент, чтобы отправить модель в организацию). Например, когда мы отправили модель в организацию [`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/mt5-finetuned-amazon-en-es"` в `Seq2SeqTrainingArguments`. + +Следующее, что нам нужно сделать, это предоставить тренеру функцию `compute_metrics()`, чтобы мы могли оценить нашу модель во время обучения. Для суммаризации это немного сложнее, чем просто вызвать `rouge_score.compute()` для прогнозов модели, поскольку нам нужно _декодировать_ выводы и метки в текст, прежде чем мы сможем вычислить оценку ROUGE. Следующая функция делает именно это, а также использует функцию `sent_tokenize()` из `nltk` для разделения предложений резюме символом новой строки: + +```python +import numpy as np + + +def compute_metrics(eval_pred): + predictions, labels = eval_pred + # Декодируем сгенерированные резюме в текст + decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) + # Заменяем -100 в метках, поскольку мы не можем их декодировать + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + # Декодируем эталонные резюме в текст + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + # ROUGE ожидает символ новой строки после каждого предложения + decoded_preds = ["\n".join(sent_tokenize(pred.strip())) for pred in decoded_preds] + decoded_labels = ["\n".join(sent_tokenize(label.strip())) for label in decoded_labels] + # Вычисляем оценки ROUGE + result = rouge_score.compute( + predictions=decoded_preds, references=decoded_labels, use_stemmer=True + ) + # Извлекаем медианные оценки + result = {key: value.mid.fmeasure * 100 for key, value in result.items()} + return {k: round(v, 4) for k, v in result.items()} +``` + +{/if} + +Далее нам нужно определить коллатор данных для нашей задачи преобразования последовательности в последовательность. Поскольку mT5 является моделью трансформера кодер-декодер, одна из тонкостей подготовки наших батчей заключается в том, что во время декодирования нам нужно сдвинуть метки вправо на единицу. Это необходимо для того, чтобы декодер видел только предыдущие метки, а не текущие или будущие, которые модели было бы легко запомнить. Это похоже на то, как маскированное самовнимание применяется к входным данным в задаче типа [каузального языкового моделирования](/course/chapter7/6). + +К счастью, 🤗 Transformers предоставляет коллатор `DataCollatorForSeq2Seq`, который будет динамически дополнять входные данные и метки за нас. Чтобы инстанцировать этот коллатор, нам просто нужно предоставить `tokenizer` и `model`: + +{#if fw === 'pt'} + +```python +from transformers import DataCollatorForSeq2Seq + +data_collator = DataCollatorForSeq2Seq(tokenizer, model=model) +``` + +{:else} + +```python +from transformers import DataCollatorForSeq2Seq + +data_collator = DataCollatorForSeq2Seq(tokenizer, model=model, return_tensors="tf") +``` + +{/if} + +Давайте посмотрим, что выдает этот коллатор, когда ему передается небольшой батч примеров. Во-первых, нам нужно удалить столбцы со строками, потому что коллатор не будет знать, как вставлять эти элементы: + +```python +tokenized_datasets = tokenized_datasets.remove_columns( + books_dataset["train"].column_names +) +``` + +Давайте посмотрим, что выдает этот коллатор, когда ему передается небольшой батч примеров. Во-первых, нам нужно удалить столбцы со строками, потому что коллатор не будет знать, как вставлять эти элементы: + +```python +features = [tokenized_datasets["train"][i] for i in range(2)] +data_collator(features) +``` + +```python out +{'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, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]), 'input_ids': tensor([[ 1494, 259, 8622, 390, 259, 262, 2316, 3435, 955, + 772, 281, 772, 1617, 263, 305, 14701, 260, 1385, + 3031, 259, 24146, 332, 1037, 259, 43906, 305, 336, + 260, 1, 0, 0, 0, 0, 0, 0], + [ 259, 27531, 13483, 259, 7505, 260, 112240, 15192, 305, + 53198, 276, 259, 74060, 263, 260, 459, 25640, 776, + 2119, 336, 259, 2220, 259, 18896, 288, 4906, 288, + 1037, 3931, 260, 7083, 101476, 1143, 260, 1]]), 'labels': tensor([[ 7483, 259, 2364, 15695, 1, -100], + [ 259, 27531, 13483, 259, 7505, 1]]), 'decoder_input_ids': tensor([[ 0, 7483, 259, 2364, 15695, 1], + [ 0, 259, 27531, 13483, 259, 7505]])} +``` + +Главное, что здесь нужно заметить, - это то, что первый пример длиннее второго, поэтому `input_ids` и `attention_mask` второго примера были дополнены справа токеном `[PAD]` (чей идентификатор равен `0`). Аналогично, мы видим, что `labels` были дополнены значением `-100`, чтобы функция потерь игнорировала токены дополнения. И наконец, мы видим новый `decoder_input_ids`, в котором метки сдвинуты вправо за счет вставки токена `[PAD]` в первую запись. + +{#if fw === 'pt'} + +Наконец-то у нас есть все необходимые ингредиенты для обучения! Теперь нам нужно просто создать тренер со стандартными аргументами: + +```python +from transformers import Seq2SeqTrainer + +trainer = Seq2SeqTrainer( + model, + args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + tokenizer=tokenizer, + compute_metrics=compute_metrics, +) +``` + +и запустить наш цикл обучения: + +```python +trainer.train() +``` + +Во время обучения вы должны видеть, как потери при обучении уменьшаются, а оценка ROUGE увеличивается с каждой эпохой. После завершения обучения вы можете увидеть итоговую оценку ROUGE, выполнив команду `Trainer.evaluate()`: + +```python +trainer.evaluate() +``` + +```python out +{'eval_loss': 3.028524398803711, + 'eval_rouge1': 16.9728, + 'eval_rouge2': 8.2969, + 'eval_rougeL': 16.8366, + 'eval_rougeLsum': 16.851, + 'eval_gen_len': 10.1597, + 'eval_runtime': 6.1054, + 'eval_samples_per_second': 38.982, + 'eval_steps_per_second': 4.914} +``` + +Из оценок видно, что наша модель значительно превзошла базовый уровень lead-3 - отлично! Осталось отправить веса модели в Hub, как показано ниже: + +``` +trainer.push_to_hub(commit_message="Training complete", tags="summarization") +``` + +```python out +'https://huggingface.co/huggingface-course/mt5-finetuned-amazon-en-es/commit/aa0536b829b28e73e1e4b94b8a5aacec420d40e0' +``` + +Это позволит сохранить контрольную точку и файлы конфигурации в `output_dir`, а затем загрузить все файлы на Хаб. Указав аргумент `tags`, мы также гарантируем, что виджет на хабе будет предназначен для конвейера суммаризации, а не для конвейера генерации текста по умолчанию, связанного с архитектурой mT5 (более подробную информацию о тегах моделей можно найти в [🤗 документации по Hub](https://huggingface.co/docs/hub/main#how-is-a-models-type-of-inference-api-and-widget-determined)). Вывод `trainer.push_to_hub()` - это URL на хэш Git-коммита, так что вы можете легко увидеть изменения, которые были сделаны в розитории модели! + +В завершение этого раздела рассмотрим, как можно дообучить mT5 с помощью низкоуровневых функций, предоставляемых 🤗 Accelerate. + +{:else} + +Мы почти готовы к обучению! Нам нужно только преобразовать наши датасеты в `tf.data.Dataset` с помощью коллатора данных, который мы определили выше, а затем выолнить `compile()` и `fit()` модели. Сначала датасеты: + +```python +tf_train_dataset = model.prepare_tf_dataset( + tokenized_datasets["train"], + collate_fn=data_collator, + shuffle=True, + batch_size=8, +) +tf_eval_dataset = model.prepare_tf_dataset( + tokenized_datasets["validation"], + collate_fn=data_collator, + shuffle=False, + batch_size=8, +) +``` + +Теперь определяем гиперпараметры обучения и компилируем: + +```python +from transformers import create_optimizer +import tensorflow as tf + +# Количество шагов обучения - это количество примеров в датасете, разделенное на размер батча, затем умноженное +# на общее количество эпох. Обратите внимание, что tf_train_dataset здесь - это батч tf.data.Dataset, +# а не оригинальный датасет Hugging Face, поэтому его len() уже равен num_samples // batch_size. +num_train_epochs = 8 +num_train_steps = len(tf_train_dataset) * num_train_epochs +model_name = model_checkpoint.split("/")[-1] + +optimizer, schedule = create_optimizer( + init_lr=5.6e-5, + num_warmup_steps=0, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) + +model.compile(optimizer=optimizer) + +# Обучение со смешанной точностью float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") +``` + +И наконец, мы подгоняем модель. Мы используем `PushToHubCallback` для сохранения модели на Hub после каждой эпохи, что позволит нам использовать ее позже для инференса: + +```python +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback( + output_dir=f"{model_name}-finetuned-amazon-en-es", tokenizer=tokenizer +) + +model.fit( + tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback], epochs=8 +) +``` + +Мы получили некоторые значения потерь во время обучения, но на самом деле нам хотелось бы увидеть метрику ROUGE, которую мы вычисляли ранее. Чтобы получить эти метрики, нам нужно сгенерировать выходные данные модели и преобразовать их в строки. Давайте создадим несколько списков меток и прогнозов для сравнения с метрикой ROUGE (обратите внимание, что если вы получаете ошибки импорта в этом разделе, вам может понадобиться команда `!pip install tqdm`). Мы также используем трюк, который значительно повышает производительность, - компиляцию генерируемого кода с помощью [XLA](https://www.tensorflow.org/xla), ускоренного компилятора линейной алгебры TensorFlow. XLA применяет различные оптимизации к графу вычислений модели, что приводит к значительному увеличению скорости и использования памяти. Как описано в Hugging Face [блоге](https://huggingface.co/blog/tf-xla-generate), XLA работает лучше всего, когда формы наших входных данных не слишком сильно различаются. Чтобы справиться с этим, мы дополним наши входные данные до кратных 128 и создадим новый датасет с помощью дополняющего коллатора, а затем применим декоратор `@tf.function(jit_compile=True)` к нашей функции генерации, который помечает всю функцию для компиляции с помощью XLA. + +```python +from tqdm import tqdm +import numpy as np + +generation_data_collator = DataCollatorForSeq2Seq( + tokenizer, model=model, return_tensors="tf", pad_to_multiple_of=320 +) + +tf_generate_dataset = model.prepare_tf_dataset( + tokenized_datasets["validation"], + collate_fn=generation_data_collator, + shuffle=False, + batch_size=8, + drop_remainder=True, +) + + +@tf.function(jit_compile=True) +def generate_with_xla(batch): + return model.generate( + input_ids=batch["input_ids"], + attention_mask=batch["attention_mask"], + max_new_tokens=32, + ) + + +all_preds = [] +all_labels = [] +for batch, labels in tqdm(tf_generate_dataset): + predictions = generate_with_xla(batch) + decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) + labels = labels.numpy() + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + decoded_preds = ["\n".join(sent_tokenize(pred.strip())) for pred in decoded_preds] + decoded_labels = ["\n".join(sent_tokenize(label.strip())) for label in decoded_labels] + all_preds.extend(decoded_preds) + all_labels.extend(decoded_labels) +``` + +Когда у нас есть списки строк меток и прогнозов, вычислить оценку ROUGE очень просто: + +```python +result = rouge_score.compute( + predictions=decoded_preds, references=decoded_labels, use_stemmer=True +) +result = {key: value.mid.fmeasure * 100 for key, value in result.items()} +{k: round(v, 4) for k, v in result.items()} +``` + +``` +{'rouge1': 31.4815, 'rouge2': 25.4386, 'rougeL': 31.4815, 'rougeLsum': 31.4815} +``` + + +{/if} + +{#if fw === 'pt'} + +## Дообучение mT5 с 🤗 Accelerate[[fine-tuning-mt5-with-accelerate]] + +Дообучение нашей модели с помощью 🤗 Accelerate очень похоже на пример с классификацией текста, который мы рассматривали в [Главе 3] (/course/chapter3). Основные отличия заключаются в необходимости явной генерации резюме во время обучения и определении способа вычисления оценок ROUGE (напомним, что `Seq2SeqTrainer` позаботился о генерации за нас). Давайте посмотрим, как мы можем реализовать эти два требования в 🤗 Accelerate! + +### Подготовка всего к обучению[[preparing-everything-for-training]] + +Первое, что нам нужно сделать, это создать `DataLoader` для каждой из наших частей. Поскольку загрузчики данных PyTorch ожидают батч тензоров, нам нужно задать формат `"torch"` в наших датасетах: + +```python +tokenized_datasets.set_format("torch") +``` + +Теперь, когда у нас есть датасеты, состоящие только из тензоров, следующее, что нужно сделать, - это снова инстанцировать `DataCollatorForSeq2Seq`. Для этого нам нужно предоставить свежую версию модели, поэтому давайте снова загрузим ее из нашего кэша: + +```python +model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +Затем мы можем инстанцировать коллатор данных и использовать его для определения наших загрузчиков данных: + +```python +from torch.utils.data import DataLoader + +batch_size = 8 +train_dataloader = DataLoader( + tokenized_datasets["train"], + shuffle=True, + collate_fn=data_collator, + batch_size=batch_size, +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], collate_fn=data_collator, batch_size=batch_size +) +``` + +Следующее, что нужно сделать, это определить оптимизатор, который мы хотим использовать. Как и в других наших примерах, мы будем использовать `AdamW`, который хорошо работает для большинства задач: + +```python +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=2e-5) +``` + +Наконец, мы передаем нашу модель, оптимизатор и загрузчики данных в метод `accelerator.prepare()`: + +```python +from accelerate import Accelerator + +accelerator = Accelerator() +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + + + +🚨 Если вы обучаете на TPU, вам нужно будет перенести весь приведенный выше код в специальную функцию обучения. Подробнее смотрите в [Главе 3](/course/chapter3). + + + +Теперь, когда мы подготовили наши объекты, осталось сделать три вещи: + +* Определить график скорости обучения. +* Реализовать функцию для постобработки резюме для оценки. +* Создать розиторий на Hub, в который мы можем отправить нашу модель. + +В качестве графика скорости обучения мы будем использовать стандартный линейный график из предыдущих разделов: + +```python +from transformers import get_scheduler + +num_train_epochs = 10 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +Для постобработки нам нужна функция, которая разбивает сгенерированные резюме на предложения, разделенные символами новой строки. Именно такой формат ожидает метрика ROUGE, и мы можем достичь этого с помощью следующего фрагмента кода: + +```python +def postprocess_text(preds, labels): + preds = [pred.strip() for pred in preds] + labels = [label.strip() for label in labels] + + # ROUGE ожидает символ новой строки после каждого предложения + preds = ["\n".join(nltk.sent_tokenize(pred)) for pred in preds] + labels = ["\n".join(nltk.sent_tokenize(label)) for label in labels] + + return preds, labels +``` + +Это должно показаться вам знакомым, если вы помните, как мы определяли функцию `compute_metrics()` для `Seq2SeqTrainer`. + +Наконец, нам нужно создать розиторий модели на Hugging Face Hub. Для этого мы можем использовать библиотеку 🤗Hub с соответствующим заголовком. Нам нужно только задать имя нашего розитория, а в библиотеке есть служебная функция для объединения идентификатора розитория с профилем пользователя: + +```python +from huggingface_hub import get_full_repo_name + +model_name = "test-bert-finetuned-squad-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'lewtun/mt5-finetuned-amazon-en-es-accelerate' +``` + +Теперь мы можем использовать имя этого розитория для клонирования локальной версии в каталог результатов, в котором будут храниться результаты обучения: + +```python +from huggingface_hub import Repository + +output_dir = "results-mt5-finetuned-squad-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +Это позволит нам отправить результаты в Hub, вызвав метод `repo.push_to_hub()` во время обучения! Теперь давайте завершим наш анализ, написав цикл обучения. + +### Цикл обучения[[training-loop]] + +Цикл обучения суммаризации очень похож на другие примеры 🤗 Accelerate, с которыми мы сталкивались, и состоит из четырех основных этапов: + +1. Обучение модели путем итерации по всем примерам в `train_dataloader` на каждой эпохе. +2. Генерация резюме моделью в конце каждой эпохи, сначала генерируются токены, а затем они (и эталонные резюме) декодируются в текст. +3. Вычисление оценок ROUGE с помощью тех же приемов, которые мы рассмотрели ранее. +4. Сохранение контрольных точек и отправка всего в Hub. Здесь мы полагаемся на полезный аргумент `blocking=False` объекта `Repository`, чтобы мы могли отправить контрольные точки на каждой эпохе _асинхронно_. Это позволяет нам продолжать обучение, не дожидаясь медленной загрузки, связанной с моделью размером в гигабайт! + +Эти шаги можно увидеть в следующем блоке кода: + +```python +from tqdm.auto import tqdm +import torch +import numpy as np + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Обучение + model.train() + for step, batch in enumerate(train_dataloader): + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Оценка + model.eval() + for step, batch in enumerate(eval_dataloader): + with torch.no_grad(): + generated_tokens = accelerator.unwrap_model(model).generate( + batch["input_ids"], + attention_mask=batch["attention_mask"], + ) + + generated_tokens = accelerator.pad_across_processes( + generated_tokens, dim=1, pad_index=tokenizer.pad_token_id + ) + labels = batch["labels"] + + # Если мы не дополнили до максимальной длины, нам нужно дополнить и метки + labels = accelerator.pad_across_processes( + batch["labels"], dim=1, pad_index=tokenizer.pad_token_id + ) + + generated_tokens = accelerator.gather(generated_tokens).cpu().numpy() + labels = accelerator.gather(labels).cpu().numpy() + + # Заменяем -100 в метках, поскольку мы не можем их декодировать + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + if isinstance(generated_tokens, tuple): + generated_tokens = generated_tokens[0] + decoded_preds = tokenizer.batch_decode( + generated_tokens, skip_special_tokens=True + ) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + + decoded_preds, decoded_labels = postprocess_text( + decoded_preds, decoded_labels + ) + + rouge_score.add_batch(predictions=decoded_preds, references=decoded_labels) + + # Вычисляем метрики + result = rouge_score.compute() + # Извлекаем медианные оценки ROUGE + result = {key: value.mid.fmeasure * 100 for key, value in result.items()} + result = {k: round(v, 4) for k, v in result.items()} + print(f"Epoch {epoch}:", result) + + # Сохранение и загрузка + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +```python out +Epoch 0: {'rouge1': 5.6351, 'rouge2': 1.1625, 'rougeL': 5.4866, 'rougeLsum': 5.5005} +Epoch 1: {'rouge1': 9.8646, 'rouge2': 3.4106, 'rougeL': 9.9439, 'rougeLsum': 9.9306} +Epoch 2: {'rouge1': 11.0872, 'rouge2': 3.3273, 'rougeL': 11.0508, 'rougeLsum': 10.9468} +Epoch 3: {'rouge1': 11.8587, 'rouge2': 4.8167, 'rougeL': 11.7986, 'rougeLsum': 11.7518} +Epoch 4: {'rouge1': 12.9842, 'rouge2': 5.5887, 'rougeL': 12.7546, 'rougeLsum': 12.7029} +Epoch 5: {'rouge1': 13.4628, 'rouge2': 6.4598, 'rougeL': 13.312, 'rougeLsum': 13.2913} +Epoch 6: {'rouge1': 12.9131, 'rouge2': 5.8914, 'rougeL': 12.6896, 'rougeLsum': 12.5701} +Epoch 7: {'rouge1': 13.3079, 'rouge2': 6.2994, 'rougeL': 13.1536, 'rougeLsum': 13.1194} +Epoch 8: {'rouge1': 13.96, 'rouge2': 6.5998, 'rougeL': 13.9123, 'rougeLsum': 13.7744} +Epoch 9: {'rouge1': 14.1192, 'rouge2': 7.0059, 'rougeL': 14.1172, 'rougeLsum': 13.9509} +``` + +Вот и все! После запуска у вас будет модель и результаты, очень похожие на те, что мы получили с помощью `Trainer`. + +{/if} + +## Использование дообученной вами модели[[using-your-fine-tuned-model]] + +После того как вы отправили модель в Hub, вы можете работать с ней либо с помощью виджета инференса, либо с помощью объекта `pipeline`, как показано ниже: + +```python +from transformers import pipeline + +hub_model_id = "huggingface-course/mt5-small-finetuned-amazon-en-es" +summarizer = pipeline("summarization", model=hub_model_id) +``` + +Мы можем передать в наш конвейер несколько примеров из тестового набора (которые модель не видела), чтобы получить представление о качестве резюме. Для начала давайте реализуем простую функцию, которая будет показывать обзор, заголовок и сгенерированное резюме вместе: + +```python +def print_summary(idx): + review = books_dataset["test"][idx]["review_body"] + title = books_dataset["test"][idx]["review_title"] + summary = summarizer(books_dataset["test"][idx]["review_body"])[0]["summary_text"] + print(f"'>>> Review: {review}'") + print(f"\n'>>> Title: {title}'") + print(f"\n'>>> Summary: {summary}'") +``` + +Давайте посмотрим на один из английских примеров, которые мы получаем: + +```python +print_summary(100) +``` + +```python out +'>>> Review: Nothing special at all about this product... the book is too small and stiff and hard to write in. The huge sticker on the back doesn’t come off and looks super tacky. I would not purchase this again. I could have just bought a journal from the dollar store and it would be basically the same thing. It’s also really expensive for what it is.' + +'>>> Title: Not impressed at all... buy something else' + +'>>> Summary: Nothing special at all about this product' +``` + +Это не так уж плохо! Мы видим, что наша модель действительно способна выполнять _абстрактную_ суммуризацию, дополняя части обзора новыми словами. И, пожалуй, самый интересный аспект нашей модели - это то, что она билингвистическая, так что мы можем генерировать резюме и для испанских рецензий: + +```python +print_summary(0) +``` + +```python out +'>>> Review: Es una trilogia que se hace muy facil de leer. Me ha gustado, no me esperaba el final para nada' + +'>>> Title: Buena literatura para adolescentes' + +'>>> Summary: Muy facil de leer' +``` + +Резюме переводится как "Very easy to read" на английском языке, что, как мы видим, в данном случае было непосредственно взято из обзора. Тем не менее, это демонстрирует универсальность модели mT5 и дает вам представление о том, каково это - работать с многоязычным корпусом! + +Далее мы обратимся к несколько более сложной задаче: обучению языковой модели с нуля. From 3fda9eb09d60bd1adf7a538ade36c8a84522b8c8 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Tue, 9 Jan 2024 20:40:11 +0300 Subject: [PATCH 331/502] After run python utils/code_formatter.py --- chapters/ru/chapter7/3.mdx | 2 +- chapters/ru/chapter7/4.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index 934a38243..99b6014eb 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -383,7 +383,7 @@ def group_texts(examples): concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()} # Вычисляем длину конкатенированных текстов total_length = len(concatenated_examples[list(examples.keys())[0]]) - # Отбрасываем последний фрагмент, если он меньше chunk_size + # Отбрасываем последний фрагмент, если он меньше chunk_size total_length = (total_length // chunk_size) * chunk_size # Разбиваем на фрагменты длиной max_len result = { diff --git a/chapters/ru/chapter7/4.mdx b/chapters/ru/chapter7/4.mdx index f1362724f..870684687 100644 --- a/chapters/ru/chapter7/4.mdx +++ b/chapters/ru/chapter7/4.mdx @@ -552,7 +552,7 @@ import numpy as np def compute_metrics(eval_preds): preds, labels = eval_preds - # В случае, если модель возвращает больше, чем предсказанные логиты + # В случае, если модель возвращает больше, чем предсказанные логиты if isinstance(preds, tuple): preds = preds[0] From c6247014ff4d823ad8416bd24a71183398879594 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:02:15 +0300 Subject: [PATCH 332/502] Update chapters/ru/chapter7/1.mdx Extra space. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/1.mdx b/chapters/ru/chapter7/1.mdx index 43df2873c..b25a2e19c 100644 --- a/chapters/ru/chapter7/1.mdx +++ b/chapters/ru/chapter7/1.mdx @@ -7,7 +7,7 @@ classNames="absolute z-10 right-0 top-0" /> -В [Главе 3] (/course/chapter3) вы узнали, как дообучить модель для классификации текстов. В этой главе мы рассмотрим следующие общие задачи NLP: +В [Главе 3](/course/chapter3) вы узнали, как дообучить модель для классификации текстов. В этой главе мы рассмотрим следующие общие задачи NLP: - Классификация токенов (Token classification) - Маскированное языковое моделирование (Masked language modeling, например, BERT) From 37cd6129ce6dd570ff7ca7f760ef9dac682fced6 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:02:45 +0300 Subject: [PATCH 333/502] Update chapters/ru/chapter7/2.mdx Extra space. I didn't notice. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/2.mdx b/chapters/ru/chapter7/2.mdx index 7f7aa7b65..839259bdc 100644 --- a/chapters/ru/chapter7/2.mdx +++ b/chapters/ru/chapter7/2.mdx @@ -47,7 +47,7 @@ -💡 Если ваш набор данных состоит из текстов, часть которых состоит из слов с соответствующими метками, вы сможете адаптировать описанные здесь процедуры обработки данных к своему набору данных. Обратитесь к [Главе 5] (/course/chapter5), если вам нужно освежить в памяти то, как загружать собственные данные в `Dataset`. +💡 Если ваш набор данных состоит из текстов, часть которых состоит из слов с соответствующими метками, вы сможете адаптировать описанные здесь процедуры обработки данных к своему набору данных. Обратитесь к [Главе 5](/course/chapter5), если вам нужно освежить в памяти то, как загружать собственные данные в `Dataset`. From 7a8731112b487409b58cf0cb5ff737d8624e5f75 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:03:00 +0300 Subject: [PATCH 334/502] Update chapters/ru/chapter7/2.mdx Extra space. I didn't notice. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/2.mdx b/chapters/ru/chapter7/2.mdx index 839259bdc..489f48998 100644 --- a/chapters/ru/chapter7/2.mdx +++ b/chapters/ru/chapter7/2.mdx @@ -128,7 +128,7 @@ label_names ['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC', 'B-MISC', 'I-MISC'] ``` -Мы уже видели эти метки при изучении конвейера `token-classification` в [Главе 6] (/course/chapter6/3), но для краткости напомним: +Мы уже видели эти метки при изучении конвейера `token-classification` в [Главе 6](/course/chapter6/3), но для краткости напомним: - `O` означает, что слово не соответствует какой-либо сущности. - `B-PER`/`I-PER` означает, что слово соответствует началу/находится внутри сущности персоны *person*. From c4379456a53eb239a66ca762aacdd16162e4b50a Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:04:37 +0300 Subject: [PATCH 335/502] Update chapters/ru/chapter7/2.mdx Yes, indeed, I ate the space bar))))) Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/2.mdx b/chapters/ru/chapter7/2.mdx index 489f48998..c4036cbd0 100644 --- a/chapters/ru/chapter7/2.mdx +++ b/chapters/ru/chapter7/2.mdx @@ -719,7 +719,7 @@ args = TrainingArguments( ) ``` -Большинство из них вы уже видели: мы задаем некоторые гиперпараметры (например, скорость обучения, количество эпох для обучения и затухание весов) и указываем `push_to_hub=True`, чтобы указать, что мы хотим сохранить модель и оценить ее в конце каждой эпохи, а также что мы хотим загрузить наши результаты в Model Hub. Обратите внимание, что с помощью аргумента `hub_model_id` можно указать имя репозитория, в который вы хотите передать модель (в частности, этот аргумент нужно использовать, чтобы передать модель в организацию). Например, когда мы передавали модель в [организацию`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/bert-finetuned-ner"` в `TrainingArguments`. По умолчанию используемый репозиторий будет находиться в вашем пространстве имен и называться в соответствии с заданным вами выходным каталогом, так что в нашем случае это будет `"sgugger/bert-finetuned-ner"`. +Большинство из них вы уже видели: мы задаем некоторые гиперпараметры (например, скорость обучения, количество эпох для обучения и затухание весов) и указываем `push_to_hub=True`, чтобы указать, что мы хотим сохранить модель и оценить ее в конце каждой эпохи, а также что мы хотим загрузить наши результаты в Model Hub. Обратите внимание, что с помощью аргумента `hub_model_id` можно указать имя репозитория, в который вы хотите передать модель (в частности, этот аргумент нужно использовать, чтобы передать модель в организацию). Например, когда мы передавали модель в [организацию `huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/bert-finetuned-ner"` в `TrainingArguments`. По умолчанию используемый репозиторий будет находиться в вашем пространстве имен и называться в соответствии с заданным вами выходным каталогом, так что в нашем случае это будет `"sgugger/bert-finetuned-ner"`. From 2626bc500eeb22cd3ef5c04ea966259d1f7f8f59 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:05:12 +0300 Subject: [PATCH 336/502] Update chapters/ru/chapter7/5.mdx There's that extra space again. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx index fbe935615..294c8a8f5 100644 --- a/chapters/ru/chapter7/5.mdx +++ b/chapters/ru/chapter7/5.mdx @@ -265,7 +265,7 @@ inputs {'input_ids': [336, 259, 28387, 11807, 287, 62893, 295, 12507, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} ``` -Здесь мы видим знакомые нам `input_ids` и `attention_mask`, с которыми мы столкнулись в наших первых экспериментах по дообучению еще в [Главе 3] (/course/chapter3). Давайте декодируем эти входные идентификаторы с помощью функции токенизатора `convert_ids_to_tokens()`, чтобы понять, с каким токенизатором мы имеем дело: +Здесь мы видим знакомые нам `input_ids` и `attention_mask`, с которыми мы столкнулись в наших первых экспериментах по дообучению еще в [Главе 3](/course/chapter3). Давайте декодируем эти входные идентификаторы с помощью функции токенизатора `convert_ids_to_tokens()`, чтобы понять, с каким токенизатором мы имеем дело: ```python tokenizer.convert_ids_to_tokens(inputs.input_ids) From cb440a6d0e674e152a23b9e5618c743e9eddbdf9 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:05:42 +0300 Subject: [PATCH 337/502] Update chapters/ru/chapter7/5.mdx There's that extra space again that I didn't notice. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx index 294c8a8f5..4e71e1cb5 100644 --- a/chapters/ru/chapter7/5.mdx +++ b/chapters/ru/chapter7/5.mdx @@ -275,7 +275,7 @@ tokenizer.convert_ids_to_tokens(inputs.input_ids) ['▁I', '▁', 'loved', '▁reading', '▁the', '▁Hung', 'er', '▁Games', ''] ``` -Специальный символ Юникода `▁` и токен конца последовательности `` указывают на то, что мы имеем дело с токенизатором SentencePiece, который основан на алгоритме сегментации Unigram, рассмотренном в [Главе 6] (/course/chapter6). Unigram особенно полезен для многоязычных корпусов, поскольку он позволяет SentencePiece не зависеть от ударений, пунктуации и того факта, что во многих языках, например в японском, нет пробельных символов. +Специальный символ Юникода `▁` и токен конца последовательности `` указывают на то, что мы имеем дело с токенизатором SentencePiece, который основан на алгоритме сегментации Unigram, рассмотренном в [Главе 6](/course/chapter6). Unigram особенно полезен для многоязычных корпусов, поскольку он позволяет SentencePiece не зависеть от ударений, пунктуации и того факта, что во многих языках, например в японском, нет пробельных символов. Для токенизации нашего корпуса нам придется столкнуться с одной тонкостью, связанной с сумризацией: поскольку наши метки также являются текстом, возможно, что они превышают максимальный размер контекста модели. Это означает, что нам нужно применять усечение как к обзорам, так и к их заголовкам, чтобы не передавать в модель слишком длинные данные. Токенизаторы в 🤗 Transformers предоставляют интересный аргумент `text_target`, который позволяет вам токенизировать метки параллельно с входными данными. Вот пример того, как обрабатываются входные и целевые данные для mT5: From 068217e8d4b0db170f27e5306a570d0f6c0185dc Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:06:30 +0300 Subject: [PATCH 338/502] Update chapters/ru/chapter7/5.mdx Extra space. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx index 4e71e1cb5..e7b112701 100644 --- a/chapters/ru/chapter7/5.mdx +++ b/chapters/ru/chapter7/5.mdx @@ -792,7 +792,7 @@ result = {key: value.mid.fmeasure * 100 for key, value in result.items()} ## Дообучение mT5 с 🤗 Accelerate[[fine-tuning-mt5-with-accelerate]] -Дообучение нашей модели с помощью 🤗 Accelerate очень похоже на пример с классификацией текста, который мы рассматривали в [Главе 3] (/course/chapter3). Основные отличия заключаются в необходимости явной генерации резюме во время обучения и определении способа вычисления оценок ROUGE (напомним, что `Seq2SeqTrainer` позаботился о генерации за нас). Давайте посмотрим, как мы можем реализовать эти два требования в 🤗 Accelerate! +Дообучение нашей модели с помощью 🤗 Accelerate очень похоже на пример с классификацией текста, который мы рассматривали в [Главе 3](/course/chapter3). Основные отличия заключаются в необходимости явной генерации резюме во время обучения и определении способа вычисления оценок ROUGE (напомним, что `Seq2SeqTrainer` позаботился о генерации за нас). Давайте посмотрим, как мы можем реализовать эти два требования в 🤗 Accelerate! ### Подготовка всего к обучению[[preparing-everything-for-training]] From fa12024fe95a599b9148fd06cc932b48c337719a Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:12:13 +0300 Subject: [PATCH 339/502] Update 5.mdx Translated the missing comment. --- chapters/ru/chapter7/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx index e7b112701..a2930329b 100644 --- a/chapters/ru/chapter7/5.mdx +++ b/chapters/ru/chapter7/5.mdx @@ -508,7 +508,7 @@ from transformers import Seq2SeqTrainingArguments batch_size = 8 num_train_epochs = 8 -# Show the training loss with every epoch +# Выводим потери при обучении по каждой эпохе logging_steps = len(tokenized_datasets["train"]) // batch_size model_name = model_checkpoint.split("/")[-1] From 07373e64dcee1cd5d49b202ba245767e23abde9a Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:17:24 +0300 Subject: [PATCH 340/502] Update chapters/ru/chapter7/4.mdx Extra space. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/4.mdx b/chapters/ru/chapter7/4.mdx index 870684687..98843c395 100644 --- a/chapters/ru/chapter7/4.mdx +++ b/chapters/ru/chapter7/4.mdx @@ -29,7 +29,7 @@ -Если у вас есть достаточно большой корпус текстов на двух (или более) языках, вы можете обучить новую модель перевода с нуля, как мы это сделаем в разделе по [казуальному языковому моделированию (causal language modeling)] (/course/chapter7/6). Однако быстрее будет дообучить существующую модель перевода, будь то многоязычная модель типа mT5 или mBART, которую нужно дообучить для конкретной пары языков, или даже модель, специализированная для перевода с одного языка на другой, которую нужно дообучить для конкретного корпуса. +Если у вас есть достаточно большой корпус текстов на двух (или более) языках, вы можете обучить новую модель перевода с нуля, как мы это сделаем в разделе по [казуальному языковому моделированию (causal language modeling)](/course/chapter7/6). Однако быстрее будет дообучить существующую модель перевода, будь то многоязычная модель типа mT5 или mBART, которую нужно дообучить для конкретной пары языков, или даже модель, специализированная для перевода с одного языка на другой, которую нужно дообучить для конкретного корпуса. В этом разделе мы дообучим модель Marian, предварительно обученную переводу с английского на французский (поскольку многие сотрудники Hugging Face говорят на обоих этих языках), на датасете [KDE4](https://huggingface.co/datasets/kde4), который представляет собой набор локализованных файлов для приложений [KDE](https://apps.kde.org/). Модель, которую мы будем использовать, была предварительно обучена на большом корпусе французских и английских текстов, взятых из [Opus dataset](https://opus.nlpl.eu/), который фактически содержит датасет KDE4. Но даже если модель, которую мы используем, видела эти данные во время предварительного обучения, мы увидим, что после дообучения мы сможем получить ее лучшую версию. From 95bda7c413f0b98fa47e219a587706b677299cd8 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:20:28 +0300 Subject: [PATCH 341/502] Update 2.mdx Translated the missing comment in the code --- chapters/ru/chapter7/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/2.mdx b/chapters/ru/chapter7/2.mdx index c4036cbd0..1000eab4a 100644 --- a/chapters/ru/chapter7/2.mdx +++ b/chapters/ru/chapter7/2.mdx @@ -239,7 +239,7 @@ def align_labels_with_tokens(labels, word_ids): else: # То же слово, что и предыдущий токен label = labels[word_id] - # If the label is B-XXX we change it to I-XXX + # Если метка B-XXX, заменяем ее на I-XXX if label % 2 == 1: label += 1 new_labels.append(label) From 913a9b1efb91988fc374f6c525f4b6b5dc1b1ef5 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:29:39 +0300 Subject: [PATCH 342/502] Update 2.mdx Translated the missing sentence. --- chapters/ru/chapter7/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/2.mdx b/chapters/ru/chapter7/2.mdx index 1000eab4a..cae2eb4e6 100644 --- a/chapters/ru/chapter7/2.mdx +++ b/chapters/ru/chapter7/2.mdx @@ -390,7 +390,7 @@ tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset( ``` - Next stop: the model itself. + Следующая остановка: сама модель. {/if} From 5f5d4aaf7cc35aebfc1dcb7d80e21cfa1301113e Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:34:32 +0300 Subject: [PATCH 343/502] Update 3.mdx Translated the missing sentence. --- chapters/ru/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index 99b6014eb..a51860d0b 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -60,7 +60,7 @@ {#if fw === 'pt'} -Let's go ahead and download DistilBERT using the `AutoModelForMaskedLM` class: +Давайте перейдем к загрузке DistilBERT с помощью класса `AutoModelForMaskedLM`: ```python from transformers import AutoModelForMaskedLM From 30ca4467842d7f323ed1b038a24618234aabd4cf Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:51:18 +0300 Subject: [PATCH 344/502] Update 3.mdx I agree, it sounds more neutral that way. --- chapters/ru/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index a51860d0b..f6dd2eadb 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -235,7 +235,7 @@ for row in sample: '>>> Label: 1' ``` -Да, это точно рецензии на фильмы, и если вы достаточно взрослый, то можете даже понять комментарий в последней рецензии о том, что у вас есть VHS-версия 😜! Хотя нам не понадобятся эти метки для языкового моделирования, мы уже видим, что `0` обозначает отрицательный отзыв, а `1` - положительный. +Да, это точно рецензии на фильмы, и если вы родились до 1990х, вам будет лучше понятен комментарий в последней рецензии о VHS-версии. 😜! Хотя нам не понадобятся эти метки для языкового моделирования, мы уже видим, что `0` обозначает отрицательный отзыв, а `1` - положительный. From 8c57d55bb5a3e5a2e59e994ee6a9eb565a734cb5 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:54:08 +0300 Subject: [PATCH 345/502] Update chapters/ru/chapter7/3.mdx An unnecessary parenthesis. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index f6dd2eadb..7bcc9b94f 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -251,7 +251,7 @@ for row in sample: Как для авторегрессивного, так и для масочного моделирования языка общим шагом предварительной обработки является объединение всех примеров, а затем разбиение всего корпуса на части одинакового размера. Это сильно отличается от нашего обычного подхода, когда мы просто проводим токенизацию отдельных примеров. Зачем конкатенируем все вместе? Причина в том, что отдельные примеры могут быть обрезаны, если они слишком длинные, и это приведет к потере информации, которая может быть полезна для задачи языкового моделирования! -Итак, для начала мы проведем обычную токенизацию нашего корпуса, но _без_ задания параметра `truncation=True` в нашем токенизаторе. Мы также возьмем идентификаторы слов, если они доступны ((а они будут доступны, если мы используем быстрый токенизатор, как описано в [Главе 6](/course/chapter6/3)), поскольку они понадобятся нам позже для маскирования целых слов. Мы обернем это в простую функцию, а пока удалим столбцы `text` и `label`, поскольку они нам больше не нужны: +Итак, для начала мы проведем обычную токенизацию нашего корпуса, но _без_ задания параметра `truncation=True` в нашем токенизаторе. Мы также возьмем идентификаторы слов, если они доступны (а они будут доступны, если мы используем быстрый токенизатор, как описано в [Главе 6](/course/chapter6/3)), поскольку они понадобятся нам позже для маскирования целых слов. Мы обернем это в простую функцию, а пока удалим столбцы `text` и `label`, поскольку они нам больше не нужны: ```python def tokenize_function(examples): From e1993b521c67068ce8aa250a1b52959307405d3a Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:55:56 +0300 Subject: [PATCH 346/502] Update chapters/ru/chapter7/3.mdx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also an option, but we've translated it as "карточка модели" a lot of places. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index 7bcc9b94f..61a371b26 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -301,7 +301,7 @@ tokenizer.model_max_length -✏️ **Попробуйте!** Некоторые модели трансформеров, например [BigBird](https://huggingface.co/google/bigbird-roberta-base) и [Longformer](hf.co/allenai/longformer-base-4096), имеют гораздо большую длину контекста, чем BERT и другие ранние модели трансформеров. Инстанцируйте токенизатор для одной из этих контрольных точек и проверьте, что `model_max_length` согласуется с тем, что указано в карточке модели. +✏️ **Попробуйте!** Некоторые модели трансформеров, например [BigBird](https://huggingface.co/google/bigbird-roberta-base) и [Longformer](hf.co/allenai/longformer-base-4096), имеют гораздо большую длину контекста, чем BERT и другие ранние модели трансформеров. Инстанцируйте токенизатор для одной из этих контрольных точек и проверьте, что `model_max_length` согласуется с тем, что указано в описании модели. From c2ad2f64e159cc1d23d4cd0eb66880740ab812ef Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:56:36 +0300 Subject: [PATCH 347/502] Update chapters/ru/chapter7/3.mdx Extra space. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index 61a371b26..4017e6738 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -445,7 +445,7 @@ tokenizer.decode(lm_datasets["train"][1]["labels"]) ## Дообучение DistilBERT с помощью API `Trainer`[[fine-tuning-distilbert-with-the-trainer-api]] -Дообучить модель моделирования языка по маске почти то же самое, что и дообучить модель классификации последовательностей, как мы делали в [Главе 3] (/course/chapter3). Единственное отличие заключается в том, что нам нужен специальный коллатор данных, который может случайным образом маскировать некоторые токены в каждом батче текстов. К счастью, 🤗 Transformers поставляется со специальным `DataCollatorForLanguageModeling`, предназначенным именно для этой задачи. Нам нужно только передать ему токенизатор и аргумент `mlm_probability`, который указывает, какую долю токенов нужно маскировать. Мы выберем 15 % - это количество используется для BERT и является распространенным выбором в литературе: +Дообучить модель моделирования языка по маске почти то же самое, что и дообучить модель классификации последовательностей, как мы делали в [Главе 3](/course/chapter3). Единственное отличие заключается в том, что нам нужен специальный коллатор данных, который может случайным образом маскировать некоторые токены в каждом батче текстов. К счастью, 🤗 Transformers поставляется со специальным `DataCollatorForLanguageModeling`, предназначенным именно для этой задачи. Нам нужно только передать ему токенизатор и аргумент `mlm_probability`, который указывает, какую долю токенов нужно маскировать. Мы выберем 15 % - это количество используется для BERT и является распространенным выбором в литературе: ```python from transformers import DataCollatorForLanguageModeling From 1a195753968baef08a2bb1c42f6bb13f1dd696a5 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 20:58:46 +0300 Subject: [PATCH 348/502] Update 3.mdx Translated the missing comment in the code. --- chapters/ru/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index 4017e6738..9b50962f7 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -671,7 +671,7 @@ optimizer, schedule = create_optimizer( ) model.compile(optimizer=optimizer) -# Train in mixed-precision float16 +# Обучение со смешанной точностью float16 tf.keras.mixed_precision.set_global_policy("mixed_float16") model_name = model_checkpoint.split("/")[-1] From 743ea976232e43defb7da70029da8e85805fd0c7 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 21:00:51 +0300 Subject: [PATCH 349/502] Update chapters/ru/chapter7/3.mdx Extra sapce. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index 9b50962f7..0fcf0ff95 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -1039,6 +1039,6 @@ for pred in preds: -✏️ **Попробуйте!** Чтобы оценить преимущества адаптации к домену, дообучите классификатор на метках IMDb как для предварительно обученных, так и для дообученных контрольных точек DistilBERT. Если вам нужно освежить в памяти классификацию текстов, ознакомьтесь с [Главой 3] (/course/chapter3). +✏️ **Попробуйте!** Чтобы оценить преимущества адаптации к домену, дообучите классификатор на метках IMDb как для предварительно обученных, так и для дообученных контрольных точек DistilBERT. Если вам нужно освежить в памяти классификацию текстов, ознакомьтесь с [Главой 3](/course/chapter3). From 184cceb7f04717b9eb863b18857333babdb29fcd Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 21:01:40 +0300 Subject: [PATCH 350/502] Update chapters/ru/chapter7/4.mdx Extra space. Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/4.mdx b/chapters/ru/chapter7/4.mdx index 98843c395..1704d7051 100644 --- a/chapters/ru/chapter7/4.mdx +++ b/chapters/ru/chapter7/4.mdx @@ -77,7 +77,7 @@ DatasetDict({ }) ``` -У нас есть 210 173 пары предложений, но в одной части, поэтому нам нужно создать собственный проверочный набор. Как мы видели в [Главе 5] (/course/chapter5), у `Dataset` есть метод `train_test_split()`, который может нам помочь. Мы зададим seed для воспроизводимости: +У нас есть 210 173 пары предложений, но в одной части, поэтому нам нужно создать собственный проверочный набор. Как мы видели в [Главе 5](/course/chapter5), у `Dataset` есть метод `train_test_split()`, который может нам помочь. Мы зададим seed для воспроизводимости: ```py split_datasets = raw_datasets["train"].train_test_split(train_size=0.9, seed=20) From 5eb4f4be1320f29454758cc7def43e1bb2e4f1a0 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 21:02:46 +0300 Subject: [PATCH 351/502] Update 4.mdx Translated the missing comment in the code. --- chapters/ru/chapter7/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/4.mdx b/chapters/ru/chapter7/4.mdx index 1704d7051..51c3b6121 100644 --- a/chapters/ru/chapter7/4.mdx +++ b/chapters/ru/chapter7/4.mdx @@ -626,7 +626,7 @@ optimizer, schedule = create_optimizer( ) model.compile(optimizer=optimizer) -# Train in mixed-precision float16 +# Обучение со смешанной точностью float16 tf.keras.mixed_precision.set_global_policy("mixed_float16") ``` From e7c59a56dd985228fe3670799d9492e986fae319 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 10 Jan 2024 21:23:18 +0300 Subject: [PATCH 352/502] Update 5.mdx Added and translated the missing sentence: "Since the collator expects a list of dicts, where each dict represents a single example in the dataset, we also need to wrangle the data into the expected format before passing it to the data collator:" --- chapters/ru/chapter7/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx index a2930329b..0ca6b02d2 100644 --- a/chapters/ru/chapter7/5.mdx +++ b/chapters/ru/chapter7/5.mdx @@ -589,7 +589,7 @@ tokenized_datasets = tokenized_datasets.remove_columns( ) ``` -Давайте посмотрим, что выдает этот коллатор, когда ему передается небольшой батч примеров. Во-первых, нам нужно удалить столбцы со строками, потому что коллатор не будет знать, как вставлять эти элементы: +Поскольку коллатор ожидает список словарей `dict`, где каждый словарь `dict` представляет один пример в датасете, нам также необходимо привести данные к ожидаемому формату, прежде чем передавать их коллатору: ```python features = [tokenized_datasets["train"][i] for i in range(2)] From e09613a9e11bf67136672b707c984421b7b01cba Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 11 Jan 2024 20:39:15 +0300 Subject: [PATCH 353/502] Update 5.mdx Edit the display of the table on the course page. --- chapters/ru/chapter7/5.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx index 0ca6b02d2..21fc15dbe 100644 --- a/chapters/ru/chapter7/5.mdx +++ b/chapters/ru/chapter7/5.mdx @@ -210,8 +210,7 @@ books_dataset = books_dataset.filter(lambda x: len(x["review_title"].split()) > | Модель Transformer | Описание | Многоязычная? | | :---------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------: | | [GPT-2](https://huggingface.co/gpt2-xl) | Хотя GPT-2 обучен как авторегрессивная языковая модель, вы можете заставить его генерировать резюме, добавляя "TL;DR" в конце входного текста. | ❌ | -| [PEGASUS](https://huggingface.co/google/pegasus-large) | Использует цель предварительного обучения для предсказания замаскированных предложений в текстах с несколькими предложениями. Эта задача предварительного обучения ближе к суммаризации, чем к классическому языковому моделированию демонстрирует высокие результаты в популярных бенчмарках. - | ❌ | +| [PEGASUS](https://huggingface.co/google/pegasus-large) | Использует цель предварительного обучения для предсказания замаскированных предложений в текстах с несколькими предложениями. Эта задача предварительного обучения ближе к суммаризации, чем к классическому языковому моделированию демонстрирует высокие результаты в популярных бенчмарках.| ❌ | | [T5](https://huggingface.co/t5-base) | Универсальная трансформерная архитектура, которая формулирует все задачи в рамках преобразования текста в текст; например, входной формат модели для суммаризации документа - `summarize: ARTICLE`. | ❌ | | [mT5](https://huggingface.co/google/mt5-base) | Многоязыковая версия T5, предварительно обученная на многоязыковом корпусе Common Crawl (mC4), охватывающем 101 язык. | ✅ | | [BART](https://huggingface.co/facebook/bart-base) | Новая архитектура Transformer с кодером и стеком декодеров, обученных восстанавливать поврежденный входной сигнал, сочетает в себе схемы предварительного обучения BERT и GPT-2. | ❌ | From efbd59f691fa8aa4d108360cb06eab3bdd4955eb Mon Sep 17 00:00:00 2001 From: MKhalusova Date: Thu, 11 Jan 2024 15:38:59 -0500 Subject: [PATCH 354/502] fixed links to other chapters --- chapters/ru/chapter0/1.mdx | 2 +- chapters/ru/chapter2/1.mdx | 4 ++-- chapters/ru/chapter2/2.mdx | 6 +++--- chapters/ru/chapter2/3.mdx | 2 +- chapters/ru/chapter3/1.mdx | 2 +- chapters/ru/chapter3/2.mdx | 12 ++++++------ chapters/ru/chapter3/3.mdx | 8 ++++---- chapters/ru/chapter3/3_tf.mdx | 8 ++++---- chapters/ru/chapter4/3.mdx | 2 +- chapters/ru/chapter5/1.mdx | 4 ++-- chapters/ru/chapter5/3.mdx | 18 +++++++++--------- chapters/ru/chapter5/4.mdx | 4 ++-- chapters/ru/chapter5/6.mdx | 8 ++++---- chapters/ru/chapter5/7.mdx | 2 +- chapters/ru/chapter6/1.mdx | 4 ++-- chapters/ru/chapter6/2.mdx | 6 +++--- chapters/ru/chapter6/3.mdx | 10 +++++----- chapters/ru/chapter6/3b.mdx | 4 ++-- chapters/ru/chapter6/4.mdx | 4 ++-- chapters/ru/chapter6/8.mdx | 4 ++-- chapters/ru/chapter7/1.mdx | 6 +++--- chapters/ru/chapter7/2.mdx | 26 +++++++++++++------------- chapters/ru/chapter7/3.mdx | 16 ++++++++-------- chapters/ru/chapter7/4.mdx | 22 +++++++++++----------- chapters/ru/chapter7/5.mdx | 20 ++++++++++---------- 25 files changed, 102 insertions(+), 102 deletions(-) diff --git a/chapters/ru/chapter0/1.mdx b/chapters/ru/chapter0/1.mdx index 6e42a9fc7..ba7dd42c8 100644 --- a/chapters/ru/chapter0/1.mdx +++ b/chapters/ru/chapter0/1.mdx @@ -1,6 +1,6 @@ # Введение -Добро пожаловать на курс от Hugging Face! Это введение поможет настроить рабочее окружение. Если вы только начинаете курс, мы рекомендуем сначала заглянуть в [Главу 1](/course/ru/chapter1), затем вернуться и настроить среду, чтобы попробовать запустить код самостоятельно. +Добро пожаловать на курс от Hugging Face! Это введение поможет настроить рабочее окружение. Если вы только начинаете курс, мы рекомендуем сначала заглянуть в [Главу 1](../chapter1), затем вернуться и настроить среду, чтобы попробовать запустить код самостоятельно. Все библиотеки, которые мы будем использовать в этом курсе, доступны в качестве Python-пакетов. В этом уроке мы покажем, как установить окружение и необходимые библиотеки. diff --git a/chapters/ru/chapter2/1.mdx b/chapters/ru/chapter2/1.mdx index 47421460e..fa750f068 100644 --- a/chapters/ru/chapter2/1.mdx +++ b/chapters/ru/chapter2/1.mdx @@ -5,7 +5,7 @@ classNames="absolute z-10 right-0 top-0" /> -Как вы могли заметить в [Главе 1](/course/chapter1), модели трансформеров обычно бывают очень большие. Обучение и развертывание таких моделей с миллионами и даже десятками *миллиардов* параметров является сложной задачей. Кроме того, новые модели выпускаются почти ежедневно, и каждая из них имеет собственную реализацию, опробовать их все — непростая задача. +Как вы могли заметить в [Главе 1](../chapter1), модели трансформеров обычно бывают очень большие. Обучение и развертывание таких моделей с миллионами и даже десятками *миллиардов* параметров является сложной задачей. Кроме того, новые модели выпускаются почти ежедневно, и каждая из них имеет собственную реализацию, опробовать их все — непростая задача. Библиотека 🤗 Transformers была создана для решения этой проблемы. Её цель — предоставить единый API, с помощью которого можно загружать, обучать и сохранять любую модель трансформера. Основными функциями библиотеки являются: @@ -15,7 +15,7 @@ Последняя особенность сильно отличает библиотеку 🤗 Transformers от других библиотек машинного обучения. Модели не строятся на модулях, которые являются общими для всех файлов; вместо этого каждая модель имеет свои собственные слои. Это не только делает модели более доступными и понятными, но и позволяет легко экспериментировать с одной моделью, не затрагивая другие. -Эта глава начнается со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воспроизвести функцию `pipeline()` представленную в [Главе 1](/course/chapter1). Далее мы обсудим API модели: углубимся в классы модели и конфигурации и покажем, как загружать модель и как она обрабатывает числовые входные данные для получения прогнозов. +Эта глава начнается со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воспроизвести функцию `pipeline()` представленную в [Главе 1](../chapter1). Далее мы обсудим API модели: углубимся в классы модели и конфигурации и покажем, как загружать модель и как она обрабатывает числовые входные данные для получения прогнозов. Затем мы рассмотрим API токенизатора, который является другим основным компонентом функции `pipeline()`. Токенизаторы берут на себя первый и последний этапы обработки, обрабатывая преобразование текста в числовые входные данные для нейронной сети и обратное преобразование в текст, когда это необходимо. Наконец, мы покажем вам, как обработывается передача нескольких предложений в модель с помощью подготовленных пакетов, а затем завершим все это более детальным рассмотрением высокоуровневой функции `tokenizer()`. diff --git a/chapters/ru/chapter2/2.mdx b/chapters/ru/chapter2/2.mdx index ff5c6a630..53ae80016 100644 --- a/chapters/ru/chapter2/2.mdx +++ b/chapters/ru/chapter2/2.mdx @@ -32,7 +32,7 @@ {/if} -Давайте начнем с готового примера, взглянув на то, что происходило за кулисами, когда мы выполняли следующий код в [Главе 1](/course/chapter1): +Давайте начнем с готового примера, взглянув на то, что происходило за кулисами, когда мы выполняли следующий код в [Главе 1](../chapter1): ```python from transformers import pipeline @@ -53,7 +53,7 @@ classifier( {'label': 'NEGATIVE', 'score': 0.9994558095932007}] ``` -Как мы уже увидели в [Главе 1](/course/chapter1), данный конвейер включает в себя три шага: предварительная обработка, передача входных данных через модель и постобработка: +Как мы уже увидели в [Главе 1](../chapter1), данный конвейер включает в себя три шага: предварительная обработка, передача входных данных через модель и постобработка:
Полный конвейер NLP: токенизация текста, преобразование в идентификаторы и вывод с помощью модели Transformer и слоя 'head' модели. @@ -176,7 +176,7 @@ model = TFAutoModel.from_pretrained(checkpoint) Если вы пока не понимаете в чем смысл, не беспокойтесь об этом. Мы объясним все это позже. -Хотя эти скрытые состояния могут быть полезны сами по себе, они обычно являются входными данными для другой части модели, известной как слой *head*. В [Главе 1](/course/chapter1) разные задачи могли бы выполняться с одной и той же архитектурой, но с каждой из этих задач будет связан отдельный слой "head". +Хотя эти скрытые состояния могут быть полезны сами по себе, они обычно являются входными данными для другой части модели, известной как слой *head*. В [Главе 1](../chapter1) разные задачи могли бы выполняться с одной и той же архитектурой, но с каждой из этих задач будет связан отдельный слой "head". ### Многомерный вектор, что это? diff --git a/chapters/ru/chapter2/3.mdx b/chapters/ru/chapter2/3.mdx index 41d226813..d818897ce 100644 --- a/chapters/ru/chapter2/3.mdx +++ b/chapters/ru/chapter2/3.mdx @@ -112,7 +112,7 @@ model = TFBertModel(config) ``` {/if} -Модель можно использовать в этом состоянии, но она будет выводить тарабарщину; сначала ее нужно обучить. Мы могли бы обучить модель с нуля для решения поставленной задачи, но, как вы видели в [Главе 1](/course/chapter1), это потребовало бы много времени и большого количества данных, а также имело бы значительное воздействие на окружающую среду. Чтобы избежать ненужных и дублирующих усилий, крайне важно иметь возможность делиться и повторно использовать модели, которые уже были обучены. +Модель можно использовать в этом состоянии, но она будет выводить тарабарщину; сначала ее нужно обучить. Мы могли бы обучить модель с нуля для решения поставленной задачи, но, как вы видели в [Главе 1](../chapter1), это потребовало бы много времени и большого количества данных, а также имело бы значительное воздействие на окружающую среду. Чтобы избежать ненужных и дублирующих усилий, крайне важно иметь возможность делиться и повторно использовать модели, которые уже были обучены. Загрузить уже обученную модель Transformer очень просто — мы можем сделать это с помощью метода `from_pretrained()`: diff --git a/chapters/ru/chapter3/1.mdx b/chapters/ru/chapter3/1.mdx index 476152eb3..f17d754bd 100644 --- a/chapters/ru/chapter3/1.mdx +++ b/chapters/ru/chapter3/1.mdx @@ -7,7 +7,7 @@ classNames="absolute z-10 right-0 top-0" /> -В [главе 2](/course/ru/chapter2) мы увидели, как можно использовать токенизаторы и предобученные модели для построения предсказаний. Но что если мы хотим дообучить предобученную модель на собственном датасете? Это и есть тема данной главы! Мы изучим: +В [главе 2](../chapter2) мы увидели, как можно использовать токенизаторы и предобученные модели для построения предсказаний. Но что если мы хотим дообучить предобученную модель на собственном датасете? Это и есть тема данной главы! Мы изучим: {#if fw === 'pt'} * Как подготовить большой датасет из Model Hub diff --git a/chapters/ru/chapter3/2.mdx b/chapters/ru/chapter3/2.mdx index dc8c83f24..1613f54d6 100644 --- a/chapters/ru/chapter3/2.mdx +++ b/chapters/ru/chapter3/2.mdx @@ -23,7 +23,7 @@ {/if} {#if fw === 'pt'} -Продолжим с примером из [предыдущей главы](/course/ru/chapter2), вот как мы будем обучать классификатор последовательности на одном батче с помощью PyTorch: +Продолжим с примером из [предыдущей главы](../chapter2), вот как мы будем обучать классификатор последовательности на одном батче с помощью PyTorch: ```python import torch @@ -48,7 +48,7 @@ loss.backward() optimizer.step() ``` {:else} -Continuing with the example from the [previous chapter](/course/ru/chapter2), вот как мы будем обучать классификатор последовательности на одном батче с помощью TensorFlow: +Continuing with the example from the [previous chapter](../chapter2), вот как мы будем обучать классификатор последовательности на одном батче с помощью TensorFlow: ```python import tensorflow as tf @@ -159,7 +159,7 @@ raw_train_dataset.features {/if} -Чтобы предобработать датасет, нам необходимо конвертировать текст в числа, которые может обработать модель. Как вы видели в [предыдущей главе](/course/ru/chapter2), это делается с помощью токенайзера. Мы можем подать на вход токенайзеру одно или список предложений, т.е. можно токенизировать предложения попарно таким образом: +Чтобы предобработать датасет, нам необходимо конвертировать текст в числа, которые может обработать модель. Как вы видели в [предыдущей главе](../chapter2), это делается с помощью токенайзера. Мы можем подать на вход токенайзеру одно или список предложений, т.е. можно токенизировать предложения попарно таким образом: ```py from transformers import AutoTokenizer @@ -185,7 +185,7 @@ inputs } ``` -Мы уже обсуждали ключи `input_ids` и `attention_mask` в [главе 2](/course/ru/chapter2), но не упоминали о `token_type_ids`. В этом примере мы указываем модели какая часть входных данных является первым предложением, а какая вторым. +Мы уже обсуждали ключи `input_ids` и `attention_mask` в [главе 2](../chapter2), но не упоминали о `token_type_ids`. В этом примере мы указываем модели какая часть входных данных является первым предложением, а какая вторым. @@ -216,13 +216,13 @@ tokenizer.convert_ids_to_tokens(inputs["input_ids"]) Обратите внимание, что если вы выберете другой чекпоинт, `token_type_ids` необязательно будут присутствовать в ваших токенизированных входных данных (например, они не возвращаются, если вы используете модель DistilBERT). Они возвращаются только тогда, когда модель будет знать, что с ними делать, потому что она видела их во время предобучения. -В данном случае BERT был обучен с информацией о идентификаторах типов токенов, и помимо задачи маскированной языковой модели, о которой мы говорили в [главе 1](/course/ru/chapter1), он может решать еще одну задачу: предсказание следующего предложения (_next sentence prediction_). Суть этой задачи - смоделировать связь между предложениями. +В данном случае BERT был обучен с информацией о идентификаторах типов токенов, и помимо задачи маскированной языковой модели, о которой мы говорили в [главе 1](../chapter1), он может решать еще одну задачу: предсказание следующего предложения (_next sentence prediction_). Суть этой задачи - смоделировать связь между предложениями. В этой задаче модели на вход подаются пары предложений (со случайно замаскированными токенами), от модели требуется предсказать, является ли следующее предложение продолжением текущего. Чтобы задача не была слишком тривиальной, половина времени модель обучается на соседних предложениях из одного документа, другую половину на парах предложений, взятых из разных источников. В общем случае вам не нужно беспокоиться о наличии `token_type_ids` в ваших токенизированных данных: пока вы используете одинаковый чекпоинт и для токенизатора, и для модели – токенизатор будет знать, как нужно обработать данные. -Теперь мы знаем, что токенизатор может подготовить сразу пару предложений, а значит мы можем использовать его для целого датасета: так же как и в [предыдущей главе](/course/ru/chapter2) можно подать на вход токенизатору список первых предложений и список вторых предложений. Это также сработает и для механизмов дополнения (padding) и усечения до максимальной длины (truncation) - об этом мы говорили в [главе 2](/course/chapter2). Итак, один из способов предобработать обучающий датасет такой: +Теперь мы знаем, что токенизатор может подготовить сразу пару предложений, а значит мы можем использовать его для целого датасета: так же как и в [предыдущей главе](../chapter2) можно подать на вход токенизатору список первых предложений и список вторых предложений. Это также сработает и для механизмов дополнения (padding) и усечения до максимальной длины (truncation) - об этом мы говорили в [главе 2](../chapter2). Итак, один из способов предобработать обучающий датасет такой: ```py tokenized_dataset = tokenizer( diff --git a/chapters/ru/chapter3/3.mdx b/chapters/ru/chapter3/3.mdx index 8da9c30d1..787481517 100644 --- a/chapters/ru/chapter3/3.mdx +++ b/chapters/ru/chapter3/3.mdx @@ -45,11 +45,11 @@ training_args = TrainingArguments("test-trainer") -💡 Если вы хотите автоматически загружать модель на Hub во время обучения, передайте аргумент `push_to_hub=True` в `TrainingArguments`. Мы больше узнаем об этом в главе [Chapter 4](/course/chapter4/3). +💡 Если вы хотите автоматически загружать модель на Hub во время обучения, передайте аргумент `push_to_hub=True` в `TrainingArguments`. Мы больше узнаем об этом в [главе 4](../chapter4/3). -Второй шаг – задание модели. Так же, как и в [предыдущей главе](/course/chapter2), мы будем использовать класс `AutoModelForSequenceClassification` с двумя лейблами: +Второй шаг – задание модели. Так же, как и в [предыдущей главе](../chapter2), мы будем использовать класс `AutoModelForSequenceClassification` с двумя лейблами: ```py from transformers import AutoModelForSequenceClassification @@ -57,7 +57,7 @@ from transformers import AutoModelForSequenceClassification model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` -После создания экземпляра предобученной модели будет распечатано предупреждение (в [главе 2](/course/chapter2) мы с таким не сталкивались). Это происходит потому, что BERT не был предобучен для задачи классификации пар предложений, его последний слой не будет использован, вместо него будет добавлен слой, позволяющий работать с такой задачей. Предупреждения сообщают, что некоторые веса не будут использованы (как раз тех слоев, которые не будут использоваться) и для новых будут инициализированы случайные веса. В заключении предлагается обучить модель, что мы и сделаем прямо сейчас. +После создания экземпляра предобученной модели будет распечатано предупреждение (в [главе 2](../chapter2) мы с таким не сталкивались). Это происходит потому, что BERT не был предобучен для задачи классификации пар предложений, его последний слой не будет использован, вместо него будет добавлен слой, позволяющий работать с такой задачей. Предупреждения сообщают, что некоторые веса не будут использованы (как раз тех слоев, которые не будут использоваться) и для новых будут инициализированы случайные веса. В заключении предлагается обучить модель, что мы и сделаем прямо сейчас. После того, как мы загрузили модель, мы можем определить `Trainer` и передать туда нужные объекты: `model`, `training_args`, обучающую и валидационную выборки, `data_collator` и `tokenizer` @@ -105,7 +105,7 @@ print(predictions.predictions.shape, predictions.label_ids.shape) Результат функции `predict()` - другой именованный кортеж с полями `predictions`, `label_ids` и `metrics`. Поле `metrics` будет содержать значение лосса на нашем датасете и значения метрик. После реализации функции `compute_metrics()` и передачи ее в `Trainer` поле `metrics` также будет содержать результат функции `compute_metrics()`. -Как можно заметить, `predictions` - массив 408 х 2 (408 - число элементов в датасете, который мы использовали). Это логиты для каждого элемента нашего датасета, переданного в `predict()` (как вы видели в [предыдущей главе](/course/chapter2) все модели Трансформеров возвращают логиты). Чтобы превратить их в предсказания и сравнить с нашими лейблами, нам необходимо узнать индекс максимального элемента второй оси: +Как можно заметить, `predictions` - массив 408 х 2 (408 - число элементов в датасете, который мы использовали). Это логиты для каждого элемента нашего датасета, переданного в `predict()` (как вы видели в [предыдущей главе](../chapter2) все модели Трансформеров возвращают логиты). Чтобы превратить их в предсказания и сравнить с нашими лейблами, нам необходимо узнать индекс максимального элемента второй оси: ```py import numpy as np diff --git a/chapters/ru/chapter3/3_tf.mdx b/chapters/ru/chapter3/3_tf.mdx index 92b68b191..e4207f846 100644 --- a/chapters/ru/chapter3/3_tf.mdx +++ b/chapters/ru/chapter3/3_tf.mdx @@ -58,7 +58,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( -Как и в [предыдущей главе](/course/ru/chapter2), мы будем использовать класс `TFAutoModelForSequenceClassification` с двумя метками: +Как и в [предыдущей главе](../chapter2), мы будем использовать класс `TFAutoModelForSequenceClassification` с двумя метками: ```py from transformers import TFAutoModelForSequenceClassification @@ -66,7 +66,7 @@ from transformers import TFAutoModelForSequenceClassification model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` -Вы заметите, что в отличие от [Главы 2](/course/ru/chapter2), вы получаете предупреждение после создания экземпляра этой предварительно обученной модели. Это связано с тем, что BERT не был предварительно обучен классификации пар предложений, поэтому последний слой предварительно обученной модели был отброшен, а вместо него был вставлен новый слой, подходящий для классификации последовательностей. Предупреждения указывают на то, что некоторые веса не использовались (те, которые соответствуют удаленным слоям), а некоторые другие были инициализированы случайным образом (те, что для новых слоев). В заключение предлагается обучить модель, что мы и собираемся сделать сейчас. +Вы заметите, что в отличие от [Главы 2](../chapter2), вы получаете предупреждение после создания экземпляра этой предварительно обученной модели. Это связано с тем, что BERT не был предварительно обучен классификации пар предложений, поэтому последний слой предварительно обученной модели был отброшен, а вместо него был вставлен новый слой, подходящий для классификации последовательностей. Предупреждения указывают на то, что некоторые веса не использовались (те, которые соответствуют удаленным слоям), а некоторые другие были инициализированы случайным образом (те, что для новых слоев). В заключение предлагается обучить модель, что мы и собираемся сделать сейчас. Чтобы точно настроить модель в нашем наборе данных, нам просто нужно вызвать `compile()` у нашей модели, а затем передать наши данные в метод `fit()`. Это запустит процесс fine tuning (который должен занять пару минут на графическом процессоре) и сообщит о значениях функции потерь при обучении, а также о значениях функции потерь на валидации. @@ -147,7 +147,7 @@ model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) -💡 Если вы хотите автоматически загружать свою модель на Hub во время обучения, вы можете передать `PushToHubCallback` в метод `model.fit()`. Мы узнаем об этом больше в [Chapter 4](/course/chapter4/3). +💡 Если вы хотите автоматически загружать свою модель на Hub во время обучения, вы можете передать `PushToHubCallback` в метод `model.fit()`. Мы узнаем об этом больше в [Главе 4](../chapter4/3). @@ -188,4 +188,4 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l Точные результаты, которые вы получите, могут отличаться, так как случайная инициализация параметров выходных слоев модели может изменить показатели. Здесь мы видим, что наша модель имеет точность 85,78% на валидационном наборе и оценку F1 89,97. Это две метрики, используемые для оценки результатов датасета MRPC для теста GLUE. В таблице в [документации BERT] (https://arxiv.org/pdf/1810.04805.pdf) сообщается о балле F1 88,97% для базовой модели. Это была модель, которая не чувствительна к регистру текста, в то время как сейчас мы используем модель, учитывающую регистр, что и объясняет лучший результат. -На этом введение в fine tuning с помощью Keras API завершено. Пример выполнения этого для наиболее распространенных задач NLP будет дан в [Главе 7](/course/ru/chapter7). Если вы хотите отточить свои навыки работы с Keras API, попробуйте точно настроить модель в наборе данных GLUE SST-2, используя обработку данных, которую вы выполнили в разделе 2. +На этом введение в fine tuning с помощью Keras API завершено. Пример выполнения этого для наиболее распространенных задач NLP будет дан в [Главе 7](../chapter7). Если вы хотите отточить свои навыки работы с Keras API, попробуйте точно настроить модель в наборе данных GLUE SST-2, используя обработку данных, которую вы выполнили в разделе 2. diff --git a/chapters/ru/chapter4/3.mdx b/chapters/ru/chapter4/3.mdx index d737fd07a..3a7fbf507 100644 --- a/chapters/ru/chapter4/3.mdx +++ b/chapters/ru/chapter4/3.mdx @@ -50,7 +50,7 @@ Простейший путь загрузки файлов на Hub – `push_to_hub` API. -Перед тем, как пойдем дальше, необходимо сгенерировать токен аутентификации. Это необходимо сделать для того, чтобы `huggingface_hub` API «узнал» вас и предоставил вам необходимые права на запись. Убедитесь, что вы находитесь в окружении, в котором установлена библиотека `transformers` (см. [Установка](/course/ru/chapter0)). Если вы работаете в Jupyter'е, вы можете использовать следующую функцию для авторизации: +Перед тем, как пойдем дальше, необходимо сгенерировать токен аутентификации. Это необходимо сделать для того, чтобы `huggingface_hub` API «узнал» вас и предоставил вам необходимые права на запись. Убедитесь, что вы находитесь в окружении, в котором установлена библиотека `transformers` (см. [Установка](../chapter0)). Если вы работаете в Jupyter'е, вы можете использовать следующую функцию для авторизации: ```python from huggingface_hub import notebook_login diff --git a/chapters/ru/chapter5/1.mdx b/chapters/ru/chapter5/1.mdx index ff8429d6a..a5a7cbb4f 100644 --- a/chapters/ru/chapter5/1.mdx +++ b/chapters/ru/chapter5/1.mdx @@ -1,6 +1,6 @@ # Введение -В [главе 3](/course/ru/chapter3) вы поверхностно ознакомились с библиотекой 🤗 Datasets и увидели три главных шага для использования ее в процессе fine-tuning: +В [главе 3](../chapter3) вы поверхностно ознакомились с библиотекой 🤗 Datasets и увидели три главных шага для использования ее в процессе fine-tuning: 1. Загрузить датасет из Hugging Face Hub. 2. Произвести препроцессинг с помощью `Dataset.map()`. @@ -14,4 +14,4 @@ * Что, черт возьми, такое «отображение памяти» (memory mapping) и Apache Arrow? * Как вы можете создать свой собственный датасет и отправить его в Hub? -Принципы, которые вы изучите в этой главе, подготовят вас к более глубокому использованию токенизации и fine-tuning'а моделей в [главе 6](/course/ru/chapter6) и [главе 7](/course/ru/chapter7) – заваривайте кофе и мы начинаем! \ No newline at end of file +Принципы, которые вы изучите в этой главе, подготовят вас к более глубокому использованию токенизации и fine-tuning'а моделей в [главе 6](../chapter6) и [главе 7](../chapter7) – заваривайте кофе и мы начинаем! \ No newline at end of file diff --git a/chapters/ru/chapter5/3.mdx b/chapters/ru/chapter5/3.mdx index 378b05e24..e8e9e3610 100644 --- a/chapters/ru/chapter5/3.mdx +++ b/chapters/ru/chapter5/3.mdx @@ -13,7 +13,7 @@ ## Управление данными -Как и в Pandas, 🤗 Datasets предоставляет несколько функция для управления содержимым объектов `Dataset` и `DatasetDict`. Мы уже познакомились с методом `Dataset.map()` в [главе 3](/course/ru/chapter3), а далее мы посмотрим на другие функции, имеющиеся в нашем распоряжении. +Как и в Pandas, 🤗 Datasets предоставляет несколько функция для управления содержимым объектов `Dataset` и `DatasetDict`. Мы уже познакомились с методом `Dataset.map()` в [главе 3](../chapter3), а далее мы посмотрим на другие функции, имеющиеся в нашем распоряжении. Для этого примера мы будем использовать датасет [Drug Review Dataset](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29), расположенный на сервере [UC Irvine Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) и содержащий отзывы пациентов на различные лекарства, сведения о состоянии пациентов и рейтинг удовлетворенности, выраженный в 10-балльной шкале. @@ -95,7 +95,7 @@ DatasetDict({ -Далее нормализуем все лейблы столбца `condition` с применением `Dataset.map()`. Так же, как мы делали токенизацию в [главе 3](/course/ru/chapter3), мы можем определить простую функцию, которая будет применения для всех строк каждого сплита в `drug_dataset`: +Далее нормализуем все лейблы столбца `condition` с применением `Dataset.map()`. Так же, как мы делали токенизацию в [главе 3](../chapter3), мы можем определить простую функцию, которая будет применения для всех строк каждого сплита в `drug_dataset`: ```py def lowercase_condition(example): @@ -277,7 +277,7 @@ new_drug_dataset = drug_dataset.map( Если вы запустите этот код в блокноте, вы увидите, что эта команда выполняется намного быстрее, чем предыдущая. И это не потому, что наши отзывы уже были HTML-экранированными — если вы повторно выполните инструкцию из предыдущего раздела (без `batched=True`), это займет столько же времени, сколько и раньше. Это связано с тем, что обработка списков обычно выполняется быстрее, чем выполнение того же кода в цикле `for`, мы также повышаем производительность за счет одновременного доступа к множеству элементов, а не по одному. -Использование `Dataset.map()` с `batched=True` – хороший способ «разблокировать» скоростные ограничения "быстрых" токенизаторов, с которыми мы познакомимся в [главе 6](/course/chapter6), которые могут быстро токенизировать большие списки текста. Например, чтобы токенизировать все отзывы на лекарства с помощью быстрого токенизатора, мы можем использовать функцию, подобную этой: +Использование `Dataset.map()` с `batched=True` – хороший способ «разблокировать» скоростные ограничения "быстрых" токенизаторов, с которыми мы познакомимся в [главе 6](../chapter6), которые могут быстро токенизировать большие списки текста. Например, чтобы токенизировать все отзывы на лекарства с помощью быстрого токенизатора, мы можем использовать функцию, подобную этой: ```python from transformers import AutoTokenizer @@ -289,7 +289,7 @@ def tokenize_function(examples): return tokenizer(examples["review"], truncation=True) ``` -Как вы видели в [главе 3](/course/ru/chapter3), мы можем передать один или несколько элементов в токенизатор, так что мы можем использовать эту функцию без параметра `batched=True`. Давайте воспользуемся этой возможностью и сравним производительность. В ноутбуке можно замерить время выполнения функции путем добавления `%time` перед строкой кода, время исполнения которой вы хотите измерить: +Как вы видели в [главе 3](../chapter3), мы можем передать один или несколько элементов в токенизатор, так что мы можем использовать эту функцию без параметра `batched=True`. Давайте воспользуемся этой возможностью и сравним производительность. В ноутбуке можно замерить время выполнения функции путем добавления `%time` перед строкой кода, время исполнения которой вы хотите измерить: ```python no-format %time tokenized_dataset = drug_dataset.map(tokenize_function, batched=True) @@ -344,7 +344,7 @@ Options | Fast tokenizer | Slow tokenizer -Объединение всей этой функциональности во всего лишь один метод само по себе прекрасно, но это еще не все! Используя `Dataset.map()` и `batched=True` вы можете поменять число элементов в датасете. Это очень полезно во множестве ситуаций, например, когда вы хотите создать несколько обучающих признаков из одного экземпляра текста. Мы воспользуеся этой возможностью на этапе препроцессинга для нескольких NLP-задач, которые рассмотрим в [главе 7](/course/ru/chapter7) +Объединение всей этой функциональности во всего лишь один метод само по себе прекрасно, но это еще не все! Используя `Dataset.map()` и `batched=True` вы можете поменять число элементов в датасете. Это очень полезно во множестве ситуаций, например, когда вы хотите создать несколько обучающих признаков из одного экземпляра текста. Мы воспользуеся этой возможностью на этапе препроцессинга для нескольких NLP-задач, которые рассмотрим в [главе 7](../chapter7) @@ -641,7 +641,7 @@ DatasetDict({ }) ``` -Отлично, теперь мы подготовили датасет, на котором можно обучить некоторые модели. В [разделе 5](/course/ru/chapter5/5) мы покажем, как загрузить датасеты на Hugging Face Hub, а пока закончим наш обзор и посмотрим несколько способов сохранения датасетов на локальный компьютер. +Отлично, теперь мы подготовили датасет, на котором можно обучить некоторые модели. В [разделе 5](../chapter5/5) мы покажем, как загрузить датасеты на Hugging Face Hub, а пока закончим наш обзор и посмотрим несколько способов сохранения датасетов на локальный компьютер. ## Сохранение датасетов @@ -727,7 +727,7 @@ for split, dataset in drug_dataset_clean.items(): {"patient_id":141780,"drugName":"Escitalopram","condition":"depression","review":"\"I seemed to experience the regular side effects of LEXAPRO, insomnia, low sex drive, sleepiness during the day. I am taking it at night because my doctor said if it made me tired to take it at night. I assumed it would and started out taking it at night. Strange dreams, some pleasant. I was diagnosed with fibromyalgia. Seems to be helping with the pain. Have had anxiety and depression in my family, and have tried quite a few other medications that haven't worked. Only have been on it for two weeks but feel more positive in my mind, want to accomplish more in my life. Hopefully the side effects will dwindle away, worth it to stick with it from hearing others responses. Great medication.\"","rating":9.0,"date":"May 29, 2011","usefulCount":10,"review_length":125} ``` -Мы можем использовать приёмы из [раздела 2](/course/ru/chapter5/2) для загрузки JSON-файлов: +Мы можем использовать приёмы из [раздела 2](../chapter5/2) для загрузки JSON-файлов: ```py data_files = { @@ -740,8 +740,8 @@ drug_dataset_reloaded = load_dataset("json", data_files=data_files) Вот и все, что нужно для нашего экскурса при работе с 🤗 Datasets! Мы очистили датасет для обучения модели, вот некоторые идеи, которые вы могли бы реализовать самостоятельно: -1. Примените знания из [раздела 3](/course/ru/chapter3) для обучения классификатора, который может предсказывать состояние пациента по отзыву на лекарство. -2. Используйте pipeline `summarization` из [раздела 1](/course/ru/chapter1)для генерации саммари отзывов. +1. Примените знания из [раздела 3](../chapter3) для обучения классификатора, который может предсказывать состояние пациента по отзыву на лекарство. +2. Используйте pipeline `summarization` из [раздела 1](../chapter1)для генерации саммари отзывов. Далее мы посмотрим, как 🤗 Datasets могут помочь вам в работе с громадными датасетами, которые _невозможно_ обработать на вашем ноутбуке! diff --git a/chapters/ru/chapter5/4.mdx b/chapters/ru/chapter5/4.mdx index d96ca1b35..68ea60a08 100644 --- a/chapters/ru/chapter5/4.mdx +++ b/chapters/ru/chapter5/4.mdx @@ -23,7 +23,7 @@ The Pile — это корпус текстов на английском язы !pip install zstandard ``` -Затем мы можем загрузить набор данных, используя метод для подгрузки файлов, который мы изучили в [разделе 2](/course/ru/chapter5/2): +Затем мы можем загрузить набор данных, используя метод для подгрузки файлов, который мы изучили в [разделе 2](../chapter5/2): ```py from datasets import load_dataset @@ -157,7 +157,7 @@ next(iter(pubmed_dataset_streamed)) 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} ``` -Элементы из потокового набора данных можно обрабатывать на лету с помощью `IterableDataset.map()`, что полезно во время обучения, если вам нужно токенизировать входные данные. Процесс точно такой же, как тот, который мы использовали для токенизации нашего набора данных в [Главе 3] (/course/ru/chapter3), с той лишь разницей, что выходные данные возвращаются один за другим: +Элементы из потокового набора данных можно обрабатывать на лету с помощью `IterableDataset.map()`, что полезно во время обучения, если вам нужно токенизировать входные данные. Процесс точно такой же, как тот, который мы использовали для токенизации нашего набора данных в [Главе 3](../chapter3), с той лишь разницей, что выходные данные возвращаются один за другим: ```py from transformers import AutoTokenizer diff --git a/chapters/ru/chapter5/6.mdx b/chapters/ru/chapter5/6.mdx index b238ba8a9..000f8a0a2 100644 --- a/chapters/ru/chapter5/6.mdx +++ b/chapters/ru/chapter5/6.mdx @@ -22,13 +22,13 @@ {/if} -В [разделе 5](/course/ru/chapter5/5) мы создали набор данных о issues и комментариях GitHub из репозитория 🤗 Datasets. В этом разделе мы будем использовать эту информацию для создания поисковой системы, которая поможет нам найти ответы на самые насущные вопросы о библиотеке! +В [разделе 5](../chapter5/5) мы создали набор данных о issues и комментариях GitHub из репозитория 🤗 Datasets. В этом разделе мы будем использовать эту информацию для создания поисковой системы, которая поможет нам найти ответы на самые насущные вопросы о библиотеке! ## Использование эмбеддингов для семанического поиска -Как мы видели в [Главе 1](/course/ru/chapter1), языковые модели на основе Transformer представляют каждую лексему в текстовом фрагменте как _эмбеддинг-вектор_. Оказывается, можно «объединить» отдельные вложения, чтобы создать векторное представление для целых предложений, абзацев или (в некоторых случаях) документов. Затем эти вложения можно использовать для поиска похожих документов в корпусе путем вычисления скалярного произведения (или какой-либо другой метрики сходства) между каждым вложением и возврата документов с наибольшим перекрытием. +Как мы видели в [Главе 1](../chapter1), языковые модели на основе Transformer представляют каждую лексему в текстовом фрагменте как _эмбеддинг-вектор_. Оказывается, можно «объединить» отдельные вложения, чтобы создать векторное представление для целых предложений, абзацев или (в некоторых случаях) документов. Затем эти вложения можно использовать для поиска похожих документов в корпусе путем вычисления скалярного произведения (или какой-либо другой метрики сходства) между каждым вложением и возврата документов с наибольшим перекрытием. В этом разделе мы будем использовать вложения для разработки семантической поисковой системы. Эти поисковые системы предлагают несколько преимуществ по сравнению с традиционными подходами, основанными на сопоставлении ключевых слов в запросе с документами. @@ -51,7 +51,7 @@ data_files = hf_hub_url( ) ``` -С URL-адресом, сохраненным в `data_files`, мы можем загрузить удаленный набор данных, используя метод, представленный в [раздел 2](/course/ru/chapter5/2): +С URL-адресом, сохраненным в `data_files`, мы можем загрузить удаленный набор данных, используя метод, представленный в [раздел 2](../chapter5/2): ```py from datasets import load_dataset @@ -236,7 +236,7 @@ comments_dataset = comments_dataset.map(concatenate_text) ## Создание текстовых эмбединнгов -В [Главе 2](/course/ru/chapter2) мы видели, что можно получить эмбеддингов токенов с помощью класса AutoModel. Все, что нам нужно сделать, это выбрать подходящую контрольную точку для загрузки модели. К счастью, есть библиотека под названием `sentence-transformers`, предназначенная для создания эмбеддингов. Как описано в [документации](https://www.sbert.net/examples/applications/semantic-search/README.html#симметричный-vs-асимметричный-semantic-search) библиотеки, наш вариант использования является примером _асимметричного семантического поиска_ потому что у нас есть короткий запрос, ответ на который мы хотели бы найти в более длинном документе, например, в комментарии к проблеме. В удобной [таблице обзора модели](https://www.sbert.net/docs/pretrained_models.html#model-overview) в документации указано, что контрольная точка `multi-qa-mpnet-base-dot-v1` имеет лучшую производительность для семантического поиска, поэтому мы будем использовать её для нашего приложения. Мы также загрузим токенизатор, используя ту же контрольную точку: +В [Главе 2](../chapter2) мы видели, что можно получить эмбеддингов токенов с помощью класса AutoModel. Все, что нам нужно сделать, это выбрать подходящую контрольную точку для загрузки модели. К счастью, есть библиотека под названием `sentence-transformers`, предназначенная для создания эмбеддингов. Как описано в [документации](https://www.sbert.net/examples/applications/semantic-search/README.html#симметричный-vs-асимметричный-semantic-search) библиотеки, наш вариант использования является примером _асимметричного семантического поиска_ потому что у нас есть короткий запрос, ответ на который мы хотели бы найти в более длинном документе, например, в комментарии к проблеме. В удобной [таблице обзора модели](https://www.sbert.net/docs/pretrained_models.html#model-overview) в документации указано, что контрольная точка `multi-qa-mpnet-base-dot-v1` имеет лучшую производительность для семантического поиска, поэтому мы будем использовать её для нашего приложения. Мы также загрузим токенизатор, используя ту же контрольную точку: {#if fw === 'pt'} diff --git a/chapters/ru/chapter5/7.mdx b/chapters/ru/chapter5/7.mdx index d40c7f871..687891774 100644 --- a/chapters/ru/chapter5/7.mdx +++ b/chapters/ru/chapter5/7.mdx @@ -13,4 +13,4 @@ - Создавать свой собственный набор данных и отправлять его в Hugging Face Hub. - Строить свои эмбеддинги документов с помощью модели Transformer и создавать семантический поисковик с помощью FAISS. -В [Главе 7](/course/ru/chapter7) мы будем использовать все это с пользой, поскольку мы углубимся в основные задачи NLP, для которых отлично подходят модели Transformer. Однако, прежде чем идти вперед, проверьте свои знания о 🤗 Datasets с помощью быстрого теста! +В [Главе 7](../chapter7) мы будем использовать все это с пользой, поскольку мы углубимся в основные задачи NLP, для которых отлично подходят модели Transformer. Однако, прежде чем идти вперед, проверьте свои знания о 🤗 Datasets с помощью быстрого теста! diff --git a/chapters/ru/chapter6/1.mdx b/chapters/ru/chapter6/1.mdx index 93525db9d..9e323cfa2 100644 --- a/chapters/ru/chapter6/1.mdx +++ b/chapters/ru/chapter6/1.mdx @@ -5,7 +5,7 @@ classNames="absolute z-10 right-0 top-0" /> -В [Главе 3](/course/chapter3) мы рассмотрели, как дообучить модель для конкретной задачи. При этом мы используем тот же токенизатор, на котором была предварительно обучена модель, но что делать, когда мы хотим обучить модель с нуля? В таких случаях использование токенизатора, который был предварительно обучен на корпусе из другой области или языка, как правило, является неоптимальным. Например, токенизатор, обученный на корпусе английских текстов, будет плохо работать на корпусе японских текстов, поскольку использование пробелов и знаков препинания в этих двух языках сильно отличается. +В [Главе 3](../chapter3) мы рассмотрели, как дообучить модель для конкретной задачи. При этом мы используем тот же токенизатор, на котором была предварительно обучена модель, но что делать, когда мы хотим обучить модель с нуля? В таких случаях использование токенизатора, который был предварительно обучен на корпусе из другой области или языка, как правило, является неоптимальным. Например, токенизатор, обученный на корпусе английских текстов, будет плохо работать на корпусе японских текстов, поскольку использование пробелов и знаков препинания в этих двух языках сильно отличается. В этой главе вы узнаете, как обучить совершенно новый токенизатор на корпусе текстов, чтобы затем использовать его для предварительного обучения языковой модели. Все это будет сделано с помощью библиотеки [🤗 Tokenizers](https://github.com/huggingface/tokenizers), которая предоставляет "быстрые" токенизаторы в библиотеке [🤗 Transformers](https://github.com/huggingface/transformers). Мы подробно рассмотрим возможности, которые предоставляет эта библиотека, и выясним, чем быстрые токенизаторы отличаются от "медленных" версий. @@ -16,4 +16,4 @@ * Различия между тремя основными алгоритмами токенизации по подсловам, используемыми в NLP сегодня * Как создать токенизатор с нуля с помощью библиотеки 🤗 Tokenizers и обучить его на некоторых данных -Техники, представленные в этой главе, подготовят вас к разделу в [Главе 7](/course/chapter7/6), где мы рассмотрим создание языковой модели по исходному коду Python. Для начала давайте разберемся, что значит "обучить" токенизатор. \ No newline at end of file +Техники, представленные в этой главе, подготовят вас к разделу в [Главе 7](../chapter7/6), где мы рассмотрим создание языковой модели по исходному коду Python. Для начала давайте разберемся, что значит "обучить" токенизатор. \ No newline at end of file diff --git a/chapters/ru/chapter6/2.mdx b/chapters/ru/chapter6/2.mdx index 4dfd465bb..3002789e3 100644 --- a/chapters/ru/chapter6/2.mdx +++ b/chapters/ru/chapter6/2.mdx @@ -7,7 +7,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter6/section2.ipynb"}, ]} /> -Если языковая модель не доступна на интересующем вас языке или ваш корпус сильно отличается от того, на котором обучалась языковая модель, вам, скорее всего, придется заново обучать модель с нуля, используя токенизатор, адаптированный к вашим данным. Для этого потребуется обучить новый токенизатор на вашем наборе данных. Но что именно это значит? Когда мы впервые рассматривали токенизаторы в [Главе 2](/course/chapter2), мы увидели, что большинство моделей трансформеров используют _алгоритм токенизации по подсловам_. Чтобы определить, какие подслова представляют интерес и наиболее часто встречаются в корпусе, токенизатор должен внимательно изучить все тексты в корпусе - этот процесс мы называем *обучением*. Точные правила обучения зависят от типа используемого токенизатора, далее в этой главе мы рассмотрим три основных алгоритма. +Если языковая модель не доступна на интересующем вас языке или ваш корпус сильно отличается от того, на котором обучалась языковая модель, вам, скорее всего, придется заново обучать модель с нуля, используя токенизатор, адаптированный к вашим данным. Для этого потребуется обучить новый токенизатор на вашем наборе данных. Но что именно это значит? Когда мы впервые рассматривали токенизаторы в [Главе 2](../chapter2), мы увидели, что большинство моделей трансформеров используют _алгоритм токенизации по подсловам_. Чтобы определить, какие подслова представляют интерес и наиболее часто встречаются в корпусе, токенизатор должен внимательно изучить все тексты в корпусе - этот процесс мы называем *обучением*. Точные правила обучения зависят от типа используемого токенизатора, далее в этой главе мы рассмотрим три основных алгоритма. @@ -169,7 +169,7 @@ tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) Обратите внимание, что `AutoTokenizer.train_new_from_iterator()` работает только в том случае, если используемый вами токенизатор является "быстрым" токенизатором. Как вы увидите в следующем разделе, библиотека 🤗 Transformers содержит два типа токенизаторов: одни написаны исключительно на Python, а другие (быстрые) опираются на библиотеку 🤗 Tokenizers, которая написана на языке программирования [Rust](https://www.rust-lang.org). Python - это язык, который чаще всего используется для приложений data science и deep learning, но когда что-то нужно распараллелить для быстроты, это приходится писать на другом языке. Например, матричные умножения, которые лежат в основе вычислений модели, написаны на CUDA, оптимизированной библиотеке языка C для GPU. -Обучение совершенно нового токенизатора на чистом Python было бы мучительно медленным, поэтому мы разработали библиотеку 🤗 Tokenizers. Обратите внимание, что так же как вам не нужно было изучать язык CUDA, чтобы выполнить свою модель на батче входных данных на GPU, вам не понадобится изучать Rust, чтобы использовать быстрый токенизатор. Библиотека 🤗 Tokenizers предоставляет привязки к Python для многих методов, которые внутренне вызывают некоторые части кода на Rust; например, для распараллеливания обучения вашего нового токенизатора или, как мы видели в [Главе 3](/course/chapter3), токенизации батча входных данных. +Обучение совершенно нового токенизатора на чистом Python было бы мучительно медленным, поэтому мы разработали библиотеку 🤗 Tokenizers. Обратите внимание, что так же как вам не нужно было изучать язык CUDA, чтобы выполнить свою модель на батче входных данных на GPU, вам не понадобится изучать Rust, чтобы использовать быстрый токенизатор. Библиотека 🤗 Tokenizers предоставляет привязки к Python для многих методов, которые внутренне вызывают некоторые части кода на Rust; например, для распараллеливания обучения вашего нового токенизатора или, как мы видели в [Главе 3](../chapter3), токенизации батча входных данных. В большинстве моделей Transformer доступен быстрый токенизатор (есть некоторые исключения, о которых вы можете узнать [здесь](https://huggingface.co/transformers/#supported-frameworks)), а API `AutoTokenizer` всегда выбирает быстрый токенизатор, если он доступен. В следующем разделе мы рассмотрим некоторые другие особенности быстрых токенизаторов, которые будут очень полезны для таких задач, как классификация токенов и ответы на вопросы. Однако прежде чем погрузиться в эту тему, давайте попробуем наш новый токенизатор на предыдущем примере: @@ -254,4 +254,4 @@ tokenizer.push_to_hub("code-search-net-tokenizer") tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") ``` -Теперь вы готовы обучить языковую модель с нуля и дообучить ее в соответствии с поставленной задачей! Мы займемся этим в [Главе 7](/course/chapter7), но сначала в этой главе мы рассмотрим быстрые токенизаторы и подробно изучим, что происходит при вызове метода `train_new_from_iterator()`. +Теперь вы готовы обучить языковую модель с нуля и дообучить ее в соответствии с поставленной задачей! Мы займемся этим в [Главе 7](../chapter7), но сначала в этой главе мы рассмотрим быстрые токенизаторы и подробно изучим, что происходит при вызове метода `train_new_from_iterator()`. diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index 25aa85b22..0e117757e 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -22,11 +22,11 @@ {/if} -В этом разделе мы подробно рассмотрим возможности токенизаторов в 🤗 Transformers. До сих пор мы использовали их только для токенизации входных данных или декодирования идентификаторов обратно в текст, но токенизаторы -- особенно те, которые поддерживаются библиотекой 🤗 Tokenizers - могут делать гораздо больше. Чтобы проиллюстрировать эти дополнительные возможности, мы рассмотрим, как воспроизвести результаты конвейеров `token-classification` (которые мы назвали `ner`) и `question-answering`, с которыми мы впервые столкнулись в [Главе 1] (/course/chapter1). +В этом разделе мы подробно рассмотрим возможности токенизаторов в 🤗 Transformers. До сих пор мы использовали их только для токенизации входных данных или декодирования идентификаторов обратно в текст, но токенизаторы -- особенно те, которые поддерживаются библиотекой 🤗 Tokenizers - могут делать гораздо больше. Чтобы проиллюстрировать эти дополнительные возможности, мы рассмотрим, как воспроизвести результаты конвейеров `token-classification` (которые мы назвали `ner`) и `question-answering`, с которыми мы впервые столкнулись в [Главе 1](../chapter1). -В дальнейшем обсуждении мы будем часто проводить различие между "медленными" и "быстрыми" токенизаторами. Медленные токенизаторы - это те, что написаны на Python в библиотеке 🤗 Transformers, а быстрые версии - это те, что предоставляются в 🤗 Tokenizers, которые написаны на Rust. Если вы помните таблицу из [Главы 5](/course/chapter5/3), в которой приводилось, сколько времени потребовалось быстрому и медленному токенизаторам для токенизации датасета Drug Review Dataset, вы должны иметь представление о том, почему мы называем их быстрыми и медленными: +В дальнейшем обсуждении мы будем часто проводить различие между "медленными" и "быстрыми" токенизаторами. Медленные токенизаторы - это те, что написаны на Python в библиотеке 🤗 Transformers, а быстрые версии - это те, что предоставляются в 🤗 Tokenizers, которые написаны на Rust. Если вы помните таблицу из [Главы 5](../chapter5/3), в которой приводилось, сколько времени потребовалось быстрому и медленному токенизаторам для токенизации датасета Drug Review Dataset, вы должны иметь представление о том, почему мы называем их быстрыми и медленными: | | Быстрый токенизатор | Медленный токенизатор :--------------:|:----------------------:|:----------------------: @@ -139,7 +139,7 @@ Sylvain ## Внутри конвейера `token-classification`[[inside-the-token-classification-pipeline]] -В [Главе 1](/course/chapter1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2](/course/chapter2), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! +В [Главе 1](../chapter1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2](../chapter2), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! {#if fw === 'pt'} @@ -200,7 +200,7 @@ token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") {#if fw === 'pt'} -Сначала нам нужно токенизировать наш ввод и пропустить его через модель. Это делается точно так же, как в [Главе 2](/course/chapter2); мы инстанцируем токенизатор и модель с помощью классов `AutoXxx`, а затем используем их в нашем примере: +Сначала нам нужно токенизировать наш ввод и пропустить его через модель. Это делается точно так же, как в [Главе 2](../chapter2); мы инстанцируем токенизатор и модель с помощью классов `AutoXxx`, а затем используем их в нашем примере: ```py from transformers import AutoTokenizer, AutoModelForTokenClassification @@ -228,7 +228,7 @@ torch.Size([1, 19, 9]) {:else} -Сначала нам нужно токенизировать наши входные данные и пропустить их через модель. Это делается точно так же, как в [Главе 2](/course/chapter2); мы инстанцируем токенизатор и модель с помощью классов `TFAutoXxx`, а затем используем их в нашем примере: +Сначала нам нужно токенизировать наши входные данные и пропустить их через модель. Это делается точно так же, как в [Главе 2](../chapter2); мы инстанцируем токенизатор и модель с помощью классов `TFAutoXxx`, а затем используем их в нашем примере: ```py from transformers import AutoTokenizer, TFAutoModelForTokenClassification diff --git a/chapters/ru/chapter6/3b.mdx b/chapters/ru/chapter6/3b.mdx index 7902ec2ff..fed113bf4 100644 --- a/chapters/ru/chapter6/3b.mdx +++ b/chapters/ru/chapter6/3b.mdx @@ -36,7 +36,7 @@ ## Использование конвейера `question-answering`[[using-the-question-answering-pipeline]] -Как мы видели в [Главе 1](/course/chapter1), для получения ответа на вопрос мы можем использовать конвейер `question-answering` следующим образом: +Как мы видели в [Главе 1](../chapter1), для получения ответа на вопрос мы можем использовать конвейер `question-answering` следующим образом: ```py from transformers import pipeline @@ -111,7 +111,7 @@ question_answerer(question=question, context=long_context) ## Использование модели для ответа на вопросы[[using-a-model-for-question-answering]] -Как и в любом другом конвейере, мы начинаем с токенизации входных данных, а затем отправляем их через модель. По умолчанию для конвейера `question-answering` используется контрольная точка [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) (слово "squad" в названии происходит от набора данных, на котором дообучили модель; подробнее о наборе данных SQuAD мы поговорим в [главе 7](/course/chapter7/7)): +Как и в любом другом конвейере, мы начинаем с токенизации входных данных, а затем отправляем их через модель. По умолчанию для конвейера `question-answering` используется контрольная точка [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) (слово "squad" в названии происходит от набора данных, на котором дообучили модель; подробнее о наборе данных SQuAD мы поговорим в [главе 7](../chapter7/7)): {#if fw === 'pt'} diff --git a/chapters/ru/chapter6/4.mdx b/chapters/ru/chapter6/4.mdx index e3c04d37a..a220a1314 100644 --- a/chapters/ru/chapter6/4.mdx +++ b/chapters/ru/chapter6/4.mdx @@ -57,7 +57,7 @@ print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü? -Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2](/course/chapter2), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. +Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2](../chapter2), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. Чтобы увидеть, как быстрый токенизатор выполняет предварительную токенизацию, мы можем воспользоваться методом `pre_tokenize_str()` атрибута `pre_tokenizer` объекта `tokenizer`: @@ -104,7 +104,7 @@ tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you? ## SentencePiece[[sentencepiece]] -[SentencePiece](https://github.com/google/sentencepiece) - это алгоритм токенизации для предварительной обработки текста, который можно использовать с любой из моделей, которые мы рассмотрим в следующих трех разделах. Он рассматривает текст как последовательность символов Unicode и заменяет пробелы специальным символом `▁`. При использовании в сочетании с алгоритмом Unigram (см. [раздел 7](/course/chapter7/7)) он даже не требует шага предварительной токенизации, что очень полезно для языков, где символ пробела не используется (например, китайского или японского). +[SentencePiece](https://github.com/google/sentencepiece) - это алгоритм токенизации для предварительной обработки текста, который можно использовать с любой из моделей, которые мы рассмотрим в следующих трех разделах. Он рассматривает текст как последовательность символов Unicode и заменяет пробелы специальным символом `▁`. При использовании в сочетании с алгоритмом Unigram (см. [раздел 7](../chapter7/7)) он даже не требует шага предварительной токенизации, что очень полезно для языков, где символ пробела не используется (например, китайского или японского). Другой главной особенностью SentencePiece является *обратимая токенизация*: поскольку в нем нет специальной обработки пробелов, декодирование токенов осуществляется просто путем их конкатенации и замены `_` на пробелы - в результате получается нормализованный текст. Как мы видели ранее, токенизатор BERT удаляет повторяющиеся пробелы, поэтому его токенизация не является обратимой. diff --git a/chapters/ru/chapter6/8.mdx b/chapters/ru/chapter6/8.mdx index 191e1d2f4..2e579224f 100644 --- a/chapters/ru/chapter6/8.mdx +++ b/chapters/ru/chapter6/8.mdx @@ -21,7 +21,7 @@
-Библиотека 🤗 Tokenizers была создана для того, чтобы предоставить несколько вариантов каждого из этих шагов, которые вы можете смешивать и сочетать между собой. В этом разделе мы рассмотрим, как можно создать токенизатор с нуля, а не обучать новый токенизатор на основе старого, как мы делали в [разделе 2](/course/chapter6/2). После этого вы сможете создать любой токенизатор, который только сможете придумать! +Библиотека 🤗 Tokenizers была создана для того, чтобы предоставить несколько вариантов каждого из этих шагов, которые вы можете смешивать и сочетать между собой. В этом разделе мы рассмотрим, как можно создать токенизатор с нуля, а не обучать новый токенизатор на основе старого, как мы делали в [разделе 2](../chapter6/2). После этого вы сможете создать любой токенизатор, который только сможете придумать! @@ -38,7 +38,7 @@ ## Получение корпуса текста[[acquiring-a-corpus]] -Для обучения нашего нового токенизатора мы будем использовать небольшой корпус текстов (чтобы примеры выполнялись быстро). Шаги по сбору корпуса аналогичны тем, что мы делали в [начале этой главы](/course/chapter6/2), но на этот раз мы будем использовать набор данных [WikiText-2](https://huggingface.co/datasets/wikitext): +Для обучения нашего нового токенизатора мы будем использовать небольшой корпус текстов (чтобы примеры выполнялись быстро). Шаги по сбору корпуса аналогичны тем, что мы делали в [начале этой главы](../chapter6/2), но на этот раз мы будем использовать набор данных [WikiText-2](https://huggingface.co/datasets/wikitext): ```python from datasets import load_dataset diff --git a/chapters/ru/chapter7/1.mdx b/chapters/ru/chapter7/1.mdx index b25a2e19c..d9f8cb9b3 100644 --- a/chapters/ru/chapter7/1.mdx +++ b/chapters/ru/chapter7/1.mdx @@ -7,7 +7,7 @@ classNames="absolute z-10 right-0 top-0" /> -В [Главе 3](/course/chapter3) вы узнали, как дообучить модель для классификации текстов. В этой главе мы рассмотрим следующие общие задачи NLP: +В [Главе 3](../chapter3) вы узнали, как дообучить модель для классификации текстов. В этой главе мы рассмотрим следующие общие задачи NLP: - Классификация токенов (Token classification) - Маскированное языковое моделирование (Masked language modeling, например, BERT) @@ -18,13 +18,13 @@ {#if fw === 'pt'} -Для этого вам понадобится использовать все, что вы узнали об API `Trainer` и библиотеке 🤗 Accelerate в [Главе 3](/course/chapter3), библиотеке 🤗 Datasets в [Главе 5](/course/chapter5) и библиотеке 🤗 Tokenizers в [Главе 6](/course/chapter6). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](/course/chapter4), так что это действительно глава,в которой все собирается воедино! +Для этого вам понадобится использовать все, что вы узнали об API `Trainer` и библиотеке 🤗 Accelerate в [Главе 3](../chapter3), библиотеке 🤗 Datasets в [Главе 5](../chapter5) и библиотеке 🤗 Tokenizers в [Главе 6](../chapter6). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](../chapter4), так что это действительно глава,в которой все собирается воедино! Каждый раздел можно читать независимо друг от друга, и в нем вы узнаете, как обучить модель с помощью API `Trainer` или с помощью собственного цикла обучения, используя 🤗 Accelerate. Вы можете пропустить любую часть и сосредоточиться на той, которая вас больше всего интересует: API `Trainer` отлично подходит для того, чтобы дообучить или обучить вашу модель, не беспокоясь о том, что происходит за кулисами, а цикл обучения с `Accelerate` позволит вам легче настроить любую часть, которую вы хотите. {:else} -Для этого вам понадобится использовать все, что вы узнали об обучении моделей с помощью Keras API в [Главе 3](/course/chapter3), библиотеке 🤗 Datasets в [Главе 5](/course/chapter5) и библиотеке 🤗 Tokenizers в [Главе 6](/course/chapter6). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](/course/chapter4), так что это действительно глава, в которой все собирается воедино! +Для этого вам понадобится использовать все, что вы узнали об обучении моделей с помощью Keras API в [Главе 3](../chapter3), библиотеке 🤗 Datasets в [Главе 5](../chapter5) и библиотеке 🤗 Tokenizers в [Главе 6](../chapter6). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](../chapter4), так что это действительно глава, в которой все собирается воедино! Каждый раздел можно читать самостоятельно. diff --git a/chapters/ru/chapter7/2.mdx b/chapters/ru/chapter7/2.mdx index cae2eb4e6..714613db4 100644 --- a/chapters/ru/chapter7/2.mdx +++ b/chapters/ru/chapter7/2.mdx @@ -47,7 +47,7 @@ -💡 Если ваш набор данных состоит из текстов, часть которых состоит из слов с соответствующими метками, вы сможете адаптировать описанные здесь процедуры обработки данных к своему набору данных. Обратитесь к [Главе 5](/course/chapter5), если вам нужно освежить в памяти то, как загружать собственные данные в `Dataset`. +💡 Если ваш набор данных состоит из текстов, часть которых состоит из слов с соответствующими метками, вы сможете адаптировать описанные здесь процедуры обработки данных к своему набору данных. Обратитесь к [Главе 5](../chapter5), если вам нужно освежить в памяти то, как загружать собственные данные в `Dataset`. @@ -61,7 +61,7 @@ from datasets import load_dataset raw_datasets = load_dataset("conll2003") ``` -Это позволит загрузить и кэшировать датасет, как мы видели в [Главе 3](/course/chapter3) для датасета GLUE MRPC. Изучение этого объекта показывает нам присутствующие столбцы и части тренировочного, проверочного и тестового наборов: +Это позволит загрузить и кэшировать датасет, как мы видели в [Главе 3](../chapter3) для датасета GLUE MRPC. Изучение этого объекта показывает нам присутствующие столбцы и части тренировочного, проверочного и тестового наборов: ```py raw_datasets @@ -128,7 +128,7 @@ label_names ['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC', 'B-MISC', 'I-MISC'] ``` -Мы уже видели эти метки при изучении конвейера `token-classification` в [Главе 6](/course/chapter6/3), но для краткости напомним: +Мы уже видели эти метки при изучении конвейера `token-classification` в [Главе 6](../chapter6/3), но для краткости напомним: - `O` означает, что слово не соответствует какой-либо сущности. - `B-PER`/`I-PER` означает, что слово соответствует началу/находится внутри сущности персоны *person*. @@ -177,7 +177,7 @@ print(line2) -Как обычно, наши тексты должны быть преобразованы в идентификаторы токенов, прежде чем модель сможет понять их смысл. Как мы видели в [Главе 6](/course/chapter6/), существенным отличием задачи классификации токенов является то, что у нас есть предварительно токенизированные входные данные. К счастью, API токенизатора справляется с этим довольно легко; нам просто нужно предупредить `tokenizer` специальным флагом. +Как обычно, наши тексты должны быть преобразованы в идентификаторы токенов, прежде чем модель сможет понять их смысл. Как мы видели в [Главе 6](../chapter6/), существенным отличием задачи классификации токенов является то, что у нас есть предварительно токенизированные входные данные. К счастью, API токенизатора справляется с этим довольно легко; нам просто нужно предупредить `tokenizer` специальным флагом. Для начала давайте создадим объект `tokenizer`. Как мы уже говорили, мы будем использовать предварительно обученную модель BERT, поэтому начнем с загрузки и кэширования соответствующего токенизатора: @@ -211,7 +211,7 @@ inputs.tokens() Как мы видим, токенизатор добавил специальные токены, используемые моделью (`[CLS]` в начале и `[SEP]` в конце), и оставил большинство слов нетронутыми. Слово `lamb`, однако, было токенизировано на два подслова, `la` и `##mb`. Это вносит несоответствие между нашими входными данными и метками: список меток состоит всего из 9 элементов, в то время как наши входные данные теперь содержат 12 токенов. Учесть специальные токены легко (мы знаем, что они находятся в начале и в конце), но нам также нужно убедиться, что мы выровняли все метки с соответствующими словами. -К счастью, поскольку мы используем быстрый токенизатор, у нас есть доступ к суперспособностям 🤗 Tokenizers, что означает, что мы можем легко сопоставить каждый токен с соответствующим словом (как показано в [Глава 6](/course/chapter6/3)): +К счастью, поскольку мы используем быстрый токенизатор, у нас есть доступ к суперспособностям 🤗 Tokenizers, что означает, что мы можем легко сопоставить каждый токен с соответствующим словом (как показано в [Глава 6](../chapter6/3)): ```py inputs.word_ids() @@ -298,7 +298,7 @@ tokenized_datasets = raw_datasets.map( ) ``` -Мы сделали самую сложную часть! Теперь, когда данные прошли предварительную обработку, само обучение будет выглядеть примерно так, как мы делали это в [Главе 3](/course/chapter3). +Мы сделали самую сложную часть! Теперь, когда данные прошли предварительную обработку, само обучение будет выглядеть примерно так, как мы делали это в [Главе 3](../chapter3). {#if fw === 'pt'} @@ -317,7 +317,7 @@ tokenized_datasets = raw_datasets.map( ### Сопоставление данных[[data-collation]] -Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](/course/chapter3), потому что в этом случае дополняются только входные данные (идентификаторы входов, маска внимания и идентификаторы типов токенов). Здесь наши метки должны быть дополнены точно так же, как и входы, чтобы они оставались одного размера, используя `-100` в качестве значения, чтобы соответствующие прогнозы игнорировались при вычислении потерь. +Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](../chapter3), потому что в этом случае дополняются только входные данные (идентификаторы входов, маска внимания и идентификаторы типов токенов). Здесь наши метки должны быть дополнены точно так же, как и входы, чтобы они оставались одного размера, используя `-100` в качестве значения, чтобы соответствующие прогнозы игнорировались при вычислении потерь. Все это делает [`DataCollatorForTokenClassification`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorfortokenclassification). Как и `DataCollatorWithPadding`, он принимает `токенизатор`, используемый для предварительной обработки входных данных: @@ -419,7 +419,7 @@ model = TFAutoModelForTokenClassification.from_pretrained( ) ``` -Как и при определении `TFAutoModelForSequenceClassification` в [Главе 3](/course/chapter3), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (веса из предварительно обученной головы), а другие веса инициализированы случайно (веса из новой головы классификации токенов), и что эту модель нужно обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: +Как и при определении `TFAutoModelForSequenceClassification` в [Главе 3](../chapter3), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (веса из предварительно обученной головы), а другие веса инициализированы случайно (веса из новой головы классификации токенов), и что эту модель нужно обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: ```python model.config.num_labels @@ -522,7 +522,7 @@ model.fit( !pip install seqeval ``` -Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](/course/chapter3): +Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](../chapter3): {:else} @@ -532,7 +532,7 @@ model.fit( !pip install seqeval ``` -Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](/course/chapter3): +Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](../chapter3): {/if} @@ -669,7 +669,7 @@ model = AutoModelForTokenClassification.from_pretrained( ) ``` -Как и в случае определения `AutoModelForSequenceClassification` в [Главе 3](/course/chapter3), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (те, что были получены из предварительно обученной головы), а другие инициализированы случайно (те, что были получены из новой головы классификации токенов), и что эту модель необходимо обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: +Как и в случае определения `AutoModelForSequenceClassification` в [Главе 3](../chapter3), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (те, что были получены из предварительно обученной головы), а другие инициализированы случайно (те, что были получены из новой головы классификации токенов), и что эту модель необходимо обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: ```python model.config.num_labels @@ -764,7 +764,7 @@ trainer.push_to_hub(commit_message="Training complete") ## Индивидуальный цикл обучения[[a-custom-training-loop]] -Теперь давайте рассмотрим полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет очень похож на тот, что мы делали в [Главе 3](/course/chapter3/4), с некоторыми изменениями для оценки. +Теперь давайте рассмотрим полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет очень похож на тот, что мы делали в [Главе 3](../chapter3/4), с некоторыми изменениями для оценки. ### Подготовка всего к обучению[[preparing-everything-for-training]] @@ -815,7 +815,7 @@ model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( -🚨 Если вы обучаетесь на TPU, вам нужно будет перенести весь код, начиная с ячейки выше, в специальную функцию обучения. Подробнее смотрите [Главу 3](/course/chapter3). +🚨 Если вы обучаетесь на TPU, вам нужно будет перенести весь код, начиная с ячейки выше, в специальную функцию обучения. Подробнее смотрите [Главу 3](../chapter3). diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index 0fcf0ff95..323e779f6 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -43,7 +43,7 @@ -🙋 Если термины "маскированное моделирование языка (masked language modeling)" и "предварительно обученная модель (pretrained model)" кажутся вам незнакомыми, загляните в [Главу 1](/course/chapter1), где мы объясняем все эти основные понятия, сопровождая их видеороликами! +🙋 Если термины "маскированное моделирование языка (masked language modeling)" и "предварительно обученная модель (pretrained model)" кажутся вам незнакомыми, загляните в [Главу 1](../chapter1), где мы объясняем все эти основные понятия, сопровождая их видеороликами! @@ -243,7 +243,7 @@ for row in sample:
-Теперь, когда мы вкратце ознакомились с данными, давайте перейдем к их подготовке к моделированию языка по маске. Как мы увидим, есть несколько дополнительных шагов, которые необходимо сделать по сравнению с задачами классификации последовательностей, которые мы рассматривали в [Главе 3](/course/chapter3). Поехали! +Теперь, когда мы вкратце ознакомились с данными, давайте перейдем к их подготовке к моделированию языка по маске. Как мы увидим, есть несколько дополнительных шагов, которые необходимо сделать по сравнению с задачами классификации последовательностей, которые мы рассматривали в [Главе 3](../chapter3). Поехали! ## Предварительная обработка данных[[preprocessing-the-data]] @@ -251,7 +251,7 @@ for row in sample: Как для авторегрессивного, так и для масочного моделирования языка общим шагом предварительной обработки является объединение всех примеров, а затем разбиение всего корпуса на части одинакового размера. Это сильно отличается от нашего обычного подхода, когда мы просто проводим токенизацию отдельных примеров. Зачем конкатенируем все вместе? Причина в том, что отдельные примеры могут быть обрезаны, если они слишком длинные, и это приведет к потере информации, которая может быть полезна для задачи языкового моделирования! -Итак, для начала мы проведем обычную токенизацию нашего корпуса, но _без_ задания параметра `truncation=True` в нашем токенизаторе. Мы также возьмем идентификаторы слов, если они доступны (а они будут доступны, если мы используем быстрый токенизатор, как описано в [Главе 6](/course/chapter6/3)), поскольку они понадобятся нам позже для маскирования целых слов. Мы обернем это в простую функцию, а пока удалим столбцы `text` и `label`, поскольку они нам больше не нужны: +Итак, для начала мы проведем обычную токенизацию нашего корпуса, но _без_ задания параметра `truncation=True` в нашем токенизаторе. Мы также возьмем идентификаторы слов, если они доступны (а они будут доступны, если мы используем быстрый токенизатор, как описано в [Главе 6](../chapter6/3)), поскольку они понадобятся нам позже для маскирования целых слов. Мы обернем это в простую функцию, а пока удалим столбцы `text` и `label`, поскольку они нам больше не нужны: ```python def tokenize_function(examples): @@ -445,7 +445,7 @@ tokenizer.decode(lm_datasets["train"][1]["labels"]) ## Дообучение DistilBERT с помощью API `Trainer`[[fine-tuning-distilbert-with-the-trainer-api]] -Дообучить модель моделирования языка по маске почти то же самое, что и дообучить модель классификации последовательностей, как мы делали в [Главе 3](/course/chapter3). Единственное отличие заключается в том, что нам нужен специальный коллатор данных, который может случайным образом маскировать некоторые токены в каждом батче текстов. К счастью, 🤗 Transformers поставляется со специальным `DataCollatorForLanguageModeling`, предназначенным именно для этой задачи. Нам нужно только передать ему токенизатор и аргумент `mlm_probability`, который указывает, какую долю токенов нужно маскировать. Мы выберем 15 % - это количество используется для BERT и является распространенным выбором в литературе: +Дообучить модель моделирования языка по маске почти то же самое, что и дообучить модель классификации последовательностей, как мы делали в [Главе 3](../chapter3). Единственное отличие заключается в том, что нам нужен специальный коллатор данных, который может случайным образом маскировать некоторые токены в каждом батче текстов. К счастью, 🤗 Transformers поставляется со специальным `DataCollatorForLanguageModeling`, предназначенным именно для этой задачи. Нам нужно только передать ему токенизатор и аргумент `mlm_probability`, который указывает, какую долю токенов нужно маскировать. Мы выберем 15 % - это количество используется для BERT и является распространенным выбором в литературе: ```python from transformers import DataCollatorForLanguageModeling @@ -592,7 +592,7 @@ for chunk in batch["input_ids"]:
-Теперь, когда у нас есть два колатора данных, остальные шаги по дообучению стандартны. Обучение может занять много времени в Google Colab, если вам не посчастливилось получить мифический GPU P100 😭, поэтому мы сначала уменьшим размер обучающего набора до нескольких тысяч примеров. Не волнуйтесь, мы все равно получим довольно приличную языковую модель! Быстрый способ уменьшить размер датасета в 🤗 Datasets - это функция `Dataset.train_test_split()`, которую мы рассматривали в [Главе 5](/course/chapter5): +Теперь, когда у нас есть два колатора данных, остальные шаги по дообучению стандартны. Обучение может занять много времени в Google Colab, если вам не посчастливилось получить мифический GPU P100 😭, поэтому мы сначала уменьшим размер обучающего набора до нескольких тысяч примеров. Не волнуйтесь, мы все равно получим довольно приличную языковую модель! Быстрый способ уменьшить размер датасета в 🤗 Datasets - это функция `Dataset.train_test_split()`, которую мы рассматривали в [Главе 5](../chapter5): ```python train_size = 10_000 @@ -827,7 +827,7 @@ trainer.push_to_hub() ## Дообучение DistilBERT с помощью 🤗 Accelerate[[fine-tuning-distilbert-with-accelerate]] -Как мы видели на примере `Trainer`, дообучение модели маскированного языкового моделирования очень похоже на пример классификации текста из [Главы 3](/course/chapter3). Фактически, единственной особенностью является использование специального коллатора данных, о котором мы уже рассказывали ранее в этом разделе! +Как мы видели на примере `Trainer`, дообучение модели маскированного языкового моделирования очень похоже на пример классификации текста из [Главы 3](../chapter3). Фактически, единственной особенностью является использование специального коллатора данных, о котором мы уже рассказывали ранее в этом разделе! Однако мы видели, что `DataCollatorForLanguageModeling` также применяет случайное маскирование при каждой оценке, поэтому мы увидим некоторые колебания в наших оценках перплексии при каждом цикле обучения. Один из способов устранить этот источник случайности - применить маскирование _один раз_ ко всему тестовому набору, а затем использовать стандартный коллатор данных в 🤗 Transformers для сбора батчей во время оценки. Чтобы увидеть, как это работает, давайте реализуем простую функцию, которая применяет маскирование к батчу, подобно нашей первой работе с `DataCollatorForLanguageModeling`: @@ -1035,10 +1035,10 @@ for pred in preds: -На этом мы завершаем наш первый эксперимент по обучению языковой модели. В [разделе 6](/course/en/chapter7/6) вы узнаете, как обучить авторегрессионную модель типа GPT-2 с нуля; загляните туда, если хотите посмотреть, как можно предварительно обучить свою собственную модель трансформера! +На этом мы завершаем наш первый эксперимент по обучению языковой модели. В [разделе 6](../chapter7/6) вы узнаете, как обучить авторегрессионную модель типа GPT-2 с нуля; загляните туда, если хотите посмотреть, как можно предварительно обучить свою собственную модель трансформера! -✏️ **Попробуйте!** Чтобы оценить преимущества адаптации к домену, дообучите классификатор на метках IMDb как для предварительно обученных, так и для дообученных контрольных точек DistilBERT. Если вам нужно освежить в памяти классификацию текстов, ознакомьтесь с [Главой 3](/course/chapter3). +✏️ **Попробуйте!** Чтобы оценить преимущества адаптации к домену, дообучите классификатор на метках IMDb как для предварительно обученных, так и для дообученных контрольных точек DistilBERT. Если вам нужно освежить в памяти классификацию текстов, ознакомьтесь с [Главой 3](../chapter3). diff --git a/chapters/ru/chapter7/4.mdx b/chapters/ru/chapter7/4.mdx index 51c3b6121..e9b150d46 100644 --- a/chapters/ru/chapter7/4.mdx +++ b/chapters/ru/chapter7/4.mdx @@ -22,14 +22,14 @@ {/if} -Теперь давайте погрузимся в перевод. Это еще одна [задача преобразования последовательности в последовательность (sequence-to-sequence)](/course/chapter1/7), что означает, что это проблема, которую можно сформулировать как переход от одной последовательности к другой. В этом смысле задача очень близка к [резюмированию (summarization)](/course/chapter7/6), и вы можете приспособить то, что мы здесь рассмотрим, к другим задачам преобразования последовательности в последовательность, таким как: +Теперь давайте погрузимся в перевод. Это еще одна [задача преобразования последовательности в последовательность (sequence-to-sequence)](../chapter1/7), что означает, что это проблема, которую можно сформулировать как переход от одной последовательности к другой. В этом смысле задача очень близка к [резюмированию (summarization)](../chapter7/6), и вы можете приспособить то, что мы здесь рассмотрим, к другим задачам преобразования последовательности в последовательность, таким как: - **Перенос стиля (Style transfer)**: Создание модели, которая *переводит* тексты, написанные в определенном стиле, в другой (например, из формального в повседневный или из шекспировского английского в современный). - **Генеративные ответы на вопросы (Generative question answering)**: Создание модели, которая генерирует ответы на вопросы, учитывая контекст -Если у вас есть достаточно большой корпус текстов на двух (или более) языках, вы можете обучить новую модель перевода с нуля, как мы это сделаем в разделе по [казуальному языковому моделированию (causal language modeling)](/course/chapter7/6). Однако быстрее будет дообучить существующую модель перевода, будь то многоязычная модель типа mT5 или mBART, которую нужно дообучить для конкретной пары языков, или даже модель, специализированная для перевода с одного языка на другой, которую нужно дообучить для конкретного корпуса. +Если у вас есть достаточно большой корпус текстов на двух (или более) языках, вы можете обучить новую модель перевода с нуля, как мы это сделаем в разделе по [казуальному языковому моделированию (causal language modeling)](../chapter7/6). Однако быстрее будет дообучить существующую модель перевода, будь то многоязычная модель типа mT5 или mBART, которую нужно дообучить для конкретной пары языков, или даже модель, специализированная для перевода с одного языка на другой, которую нужно дообучить для конкретного корпуса. В этом разделе мы дообучим модель Marian, предварительно обученную переводу с английского на французский (поскольку многие сотрудники Hugging Face говорят на обоих этих языках), на датасете [KDE4](https://huggingface.co/datasets/kde4), который представляет собой набор локализованных файлов для приложений [KDE](https://apps.kde.org/). Модель, которую мы будем использовать, была предварительно обучена на большом корпусе французских и английских текстов, взятых из [Opus dataset](https://opus.nlpl.eu/), который фактически содержит датасет KDE4. Но даже если модель, которую мы используем, видела эти данные во время предварительного обучения, мы увидим, что после дообучения мы сможем получить ее лучшую версию. @@ -46,7 +46,7 @@ ## Подготовка данных[[preparing-the-data]] -Чтобы дообучить или обучить модель перевода с нуля, нам понадобится датасет, подходящий для этой задачи. Как уже упоминалось, мы будем использовать [датасет KDE4](https://huggingface.co/datasets/kde4) , но вы можете легко адаптировать код для использования своих собственных данных, если у вас есть пары предложений на двух языках, с которых вы хотите переводить и на которые хотите переводить. Обратитесь к [Главе 5](/course/chapter5) если вам нужно вспомнить, как загружать пользовательские данные в `Dataset`. +Чтобы дообучить или обучить модель перевода с нуля, нам понадобится датасет, подходящий для этой задачи. Как уже упоминалось, мы будем использовать [датасет KDE4](https://huggingface.co/datasets/kde4) , но вы можете легко адаптировать код для использования своих собственных данных, если у вас есть пары предложений на двух языках, с которых вы хотите переводить и на которые хотите переводить. Обратитесь к [Главе 5](../chapter5) если вам нужно вспомнить, как загружать пользовательские данные в `Dataset`. ### Датасет KDE4[[the-kde4-dataset]] @@ -77,7 +77,7 @@ DatasetDict({ }) ``` -У нас есть 210 173 пары предложений, но в одной части, поэтому нам нужно создать собственный проверочный набор. Как мы видели в [Главе 5](/course/chapter5), у `Dataset` есть метод `train_test_split()`, который может нам помочь. Мы зададим seed для воспроизводимости: +У нас есть 210 173 пары предложений, но в одной части, поэтому нам нужно создать собственный проверочный набор. Как мы видели в [Главе 5](../chapter5), у `Dataset` есть метод `train_test_split()`, который может нам помочь. Мы зададим seed для воспроизводимости: ```py split_datasets = raw_datasets["train"].train_test_split(train_size=0.9, seed=20) @@ -298,7 +298,7 @@ model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint, from_pt=True) ### Сопоставление данных[[data-collation]] -Для динамического батча нам понадобится коллатор данных для работы с дополнением (padding). Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](/course/chapter3), потому что в этом случае будут заполнены только входы (идентификаторы входов, маска внимания и идентификаторы типов токенов). Наши метки также должны быть дополнены до максимальной длины, встречающейся в метках. И, как уже говорилось, добовляемое значение, используемое для дополнения меток, должно быть `-100`, а не добавочный токен токенизатора, чтобы эти добавочные значения игнорировались при вычислении потерь. +Для динамического батча нам понадобится коллатор данных для работы с дополнением (padding). Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](../chapter3), потому что в этом случае будут заполнены только входы (идентификаторы входов, маска внимания и идентификаторы типов токенов). Наши метки также должны быть дополнены до максимальной длины, встречающейся в метках. И, как уже говорилось, добовляемое значение, используемое для дополнения меток, должно быть `-100`, а не добавочный токен токенизатора, чтобы эти добавочные значения игнорировались при вычислении потерь. Все это делает [`DataCollatorForSeq2Seq`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorforseq2seq). Как и `DataCollatorWithPadding`, он принимает `tokenizer`, используемый для препроцессирования входных данных, а также `model`. Это связано с тем, что данный коллатор данных также будет отвечать за подготовку входных идентификаторов декодера, которые представляют собой сдвинутые версии меток со специальным токеном в начале. Поскольку для разных архитектур этот сдвиг выполняется по-разному, `DataCollatorForSeq2Seq` должен знать объект `model`: @@ -403,7 +403,7 @@ tf_eval_dataset = model.prepare_tf_dataset( Свойство, которое `Seq2SeqTrainer` добавляет к своему суперклассу `Trainer`, - это возможность использовать метод `generate()` во время оценки или предсказания. Во время обучения модель будет использовать `decoder_input_ids` с маской внимания, гарантирующей, что она не будет использовать токены после токена, который пытается предсказать, чтобы ускорить обучение. Во время инференса мы не сможем использовать эти данные, так как у нас не будет меток, поэтому было бы неплохо оценить нашу модель с аналогичной настройкой. -Как мы видели в [Главе 1](/course/chapter1/6), декодер выполняет инференс, предсказывая токены один за другим - то, что за кулисами реализовано в 🤗 Transformers методом `generate()`. Тренер `Seq2SeqTrainer` позволит нам использовать этот метод для оценки, если мы установим `predict_with_generate=True`. +Как мы видели в [Главе 1](../chapter1/6), декодер выполняет инференс, предсказывая токены один за другим - то, что за кулисами реализовано в 🤗 Transformers методом `generate()`. Тренер `Seq2SeqTrainer` позволит нам использовать этот метод для оценки, если мы установим `predict_with_generate=True`. {/if} @@ -415,7 +415,7 @@ tf_eval_dataset = model.prepare_tf_dataset( !pip install sacrebleu ``` -Затем мы можем загрузить ее с помощью `evaluate.load()`, как мы это делали в [Главе 3](/course/chapter3): +Затем мы можем загрузить ее с помощью `evaluate.load()`, как мы это делали в [Главе 3](../chapter3): ```py import evaluate @@ -630,7 +630,7 @@ model.compile(optimizer=optimizer) tf.keras.mixed_precision.set_global_policy("mixed_float16") ``` -Далее мы определяем обратный вызов `PushToHubCallback` для загрузки нашей модели в Hub во время обучения, как мы видели в [разделе 2]((/course/chapter7/2)), а затем мы просто подгоняем модель с помощью этого обратного вызова: +Далее мы определяем обратный вызов `PushToHubCallback` для загрузки нашей модели в Hub во время обучения, как мы видели в [разделе 2](../chapter7/2), а затем мы просто подгоняем модель с помощью этого обратного вызова: ```python from transformers.keras_callbacks import PushToHubCallback @@ -785,7 +785,7 @@ trainer.push_to_hub(tags="translation", commit_message="Training complete") ## Индивидуальный цикл обучения[[a-custom-training-loop]] -Теперь давайте рассмотрим полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет выглядеть примерно так же, как мы делали это в [Главе 2](/course/chapter7/2) и [Главе 3](/course/chapter3/4). +Теперь давайте рассмотрим полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет выглядеть примерно так же, как мы делали это в [Главе 2](../chapter7/2) и [Главе 3](../chapter3/4). ### Подготовка всего к обучению[[preparing-everything-for-training]] @@ -892,11 +892,11 @@ def postprocess(predictions, labels): return decoded_preds, decoded_labels ``` -Цикл обучения очень похож на циклы в [разделе 2](/course/chapter7/2) и [главе 3](/course/chapter3), с некоторыми отличиями в части оценки - так что давайте сосредоточимся на этом! +Цикл обучения очень похож на циклы в [разделе 2](../chapter7/2) и [главе 3](../chapter3), с некоторыми отличиями в части оценки - так что давайте сосредоточимся на этом! Первое, что следует отметить, это то, что мы используем метод `generate()` для вычисления прогнозов, но это метод нашей базовой модели, а не обернутой модели 🤗 Accelerate, созданной в методе `prepare()`. Поэтому мы сначала развернем модель, а затем вызовем этот метод. -Второй момент заключается в том, что, как и в случае с [классификацией токенов](/course/chapter7/2), два процесса могут дополнить входы и метки до разных форм, поэтому мы используем `accelerator.pad_across_processes()`, чтобы сделать прогнозы и метки одинаковыми по форме перед вызовом метода `gather()`. Если мы этого не сделаем, оценка либо выдаст ошибку, либо зависнет навсегда. +Второй момент заключается в том, что, как и в случае с [классификацией токенов](../chapter7/2), два процесса могут дополнить входы и метки до разных форм, поэтому мы используем `accelerator.pad_across_processes()`, чтобы сделать прогнозы и метки одинаковыми по форме перед вызовом метода `gather()`. Если мы этого не сделаем, оценка либо выдаст ошибку, либо зависнет навсегда. ```py from tqdm.auto import tqdm diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx index 21fc15dbe..2c95b0c47 100644 --- a/chapters/ru/chapter7/5.mdx +++ b/chapters/ru/chapter7/5.mdx @@ -62,7 +62,7 @@ DatasetDict({ }) ``` -Как видите, для каждого языка есть 200 000 отзывов в части `train` и по 5 000 отзывов в частях `validation` и `test`. Интересующая нас информация о рецензиях содержится в столбцах `review_body` и `review_title`. Давайте рассмотрим несколько примеров, создав простую функцию, которая берет случайную выборку из обучающего множества с помощью методов, изученных в [Главе 5](/course/chapter5): +Как видите, для каждого языка есть 200 000 отзывов в части `train` и по 5 000 отзывов в частях `validation` и `test`. Интересующая нас информация о рецензиях содержится в столбцах `review_body` и `review_title`. Давайте рассмотрим несколько примеров, создав простую функцию, которая берет случайную выборку из обучающего множества с помощью методов, изученных в [Главе 5](../chapter5): ```python def show_samples(dataset, num_samples=3, seed=42): @@ -125,7 +125,7 @@ book 3756 Name: product_category, dtype: int64 ``` -Самые популярные товары в английском датасете - это бытовые товары, одежда и беспроводная электроника. Однако, чтобы поддержать тему Amazon, давайте сосредоточимся на суммаризации отзывов о книгах - в конце концов, именно для этого компания и была основана! Мы видим две категории товаров, которые подходят для этой цели (`book` и `digital_ebook_purchase`), поэтому давайте отфильтруем датасеты на обоих языках только для этих товаров. Как мы видели в [Главе 5](/course/chapter5), функция `Dataset.filter()` позволяет нам очень эффективно разделять датасет на части, поэтому мы можем определить простую функцию для этого: +Самые популярные товары в английском датасете - это бытовые товары, одежда и беспроводная электроника. Однако, чтобы поддержать тему Amazon, давайте сосредоточимся на суммаризации отзывов о книгах - в конце концов, именно для этого компания и была основана! Мы видим две категории товаров, которые подходят для этой цели (`book` и `digital_ebook_purchase`), поэтому давайте отфильтруем датасеты на обоих языках только для этих товаров. Как мы видели в [Главе 5](../chapter5), функция `Dataset.filter()` позволяет нам очень эффективно разделять датасет на части, поэтому мы можем определить простую функцию для этого: ```python def filter_books(example): @@ -205,7 +205,7 @@ books_dataset = books_dataset.filter(lambda x: len(x["review_title"].split()) > ## Модели для суммаризации текста[[models-for-text-summarization]] -Если задуматься, то суммаризация текста - это задача, похожая на машинный перевод: у нас есть текст, например рецензия, который мы хотели бы "перевести" в более короткую версию, передающую основные особенности исходного текста. Соответственно, большинство моделей Transformer для суммаризации используют архитектуру кодер-декодер, с которой мы впервые столкнулись в [Глава 1] (/course/chapter1), хотя есть и исключения, например семейство моделей GPT, которые также могут использоваться для суммаризации в условиях few-shot настроек. В следующей таблице перечислены некоторые популярные предварительно обученные модели, которые можно дообучить для суммаризации. +Если задуматься, то суммаризация текста - это задача, похожая на машинный перевод: у нас есть текст, например рецензия, который мы хотели бы "перевести" в более короткую версию, передающую основные особенности исходного текста. Соответственно, большинство моделей Transformer для суммаризации используют архитектуру кодер-декодер, с которой мы впервые столкнулись в [Глава 1](../chapter1), хотя есть и исключения, например семейство моделей GPT, которые также могут использоваться для суммаризации в условиях few-shot настроек. В следующей таблице перечислены некоторые популярные предварительно обученные модели, которые можно дообучить для суммаризации. | Модель Transformer | Описание | Многоязычная? | | :---------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------: | @@ -264,7 +264,7 @@ inputs {'input_ids': [336, 259, 28387, 11807, 287, 62893, 295, 12507, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} ``` -Здесь мы видим знакомые нам `input_ids` и `attention_mask`, с которыми мы столкнулись в наших первых экспериментах по дообучению еще в [Главе 3](/course/chapter3). Давайте декодируем эти входные идентификаторы с помощью функции токенизатора `convert_ids_to_tokens()`, чтобы понять, с каким токенизатором мы имеем дело: +Здесь мы видим знакомые нам `input_ids` и `attention_mask`, с которыми мы столкнулись в наших первых экспериментах по дообучению еще в [Главе 3](../chapter3). Давайте декодируем эти входные идентификаторы с помощью функции токенизатора `convert_ids_to_tokens()`, чтобы понять, с каким токенизатором мы имеем дело: ```python tokenizer.convert_ids_to_tokens(inputs.input_ids) @@ -274,7 +274,7 @@ tokenizer.convert_ids_to_tokens(inputs.input_ids) ['▁I', '▁', 'loved', '▁reading', '▁the', '▁Hung', 'er', '▁Games', ''] ``` -Специальный символ Юникода `▁` и токен конца последовательности `` указывают на то, что мы имеем дело с токенизатором SentencePiece, который основан на алгоритме сегментации Unigram, рассмотренном в [Главе 6](/course/chapter6). Unigram особенно полезен для многоязычных корпусов, поскольку он позволяет SentencePiece не зависеть от ударений, пунктуации и того факта, что во многих языках, например в японском, нет пробельных символов. +Специальный символ Юникода `▁` и токен конца последовательности `` указывают на то, что мы имеем дело с токенизатором SentencePiece, который основан на алгоритме сегментации Unigram, рассмотренном в [Главе 6](../chapter6). Unigram особенно полезен для многоязычных корпусов, поскольку он позволяет SentencePiece не зависеть от ударений, пунктуации и того факта, что во многих языках, например в японском, нет пробельных символов. Для токенизации нашего корпуса нам придется столкнуться с одной тонкостью, связанной с сумризацией: поскольку наши метки также являются текстом, возможно, что они превышают максимальный размер контекста модели. Это означает, что нам нужно применять усечение как к обзорам, так и к их заголовкам, чтобы не передавать в модель слишком длинные данные. Токенизаторы в 🤗 Transformers предоставляют интересный аргумент `text_target`, который позволяет вам токенизировать метки параллельно с входными данными. Вот пример того, как обрабатываются входные и целевые данные для mT5: @@ -480,7 +480,7 @@ model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) -💡 Если вы задаетесь вопросом, почему вы не видите предупреждений о необходимости дообучить модель для последующей задачи, то это потому, что для задач "последовательность-в-последовательность" мы сохраняем все веса сети. Сравните это с нашей моделью классификации текста из [Главы 3](/course/chapter3), где голова предварительно обученной модели была заменена на случайно инициализированную сеть. +💡 Если вы задаетесь вопросом, почему вы не видите предупреждений о необходимости дообучить модель для последующей задачи, то это потому, что для задач "последовательность-в-последовательность" мы сохраняем все веса сети. Сравните это с нашей моделью классификации текста из [Главы 3](../chapter3), где голова предварительно обученной модели была заменена на случайно инициализированную сеть. @@ -526,7 +526,7 @@ args = Seq2SeqTrainingArguments( ) ``` -Здесь аргумент `predict_with_generate` был задан, чтобы указать, что мы должны генерировать резюме во время оценки, чтобы мы могли вычислить баллы ROUGE для каждой эпохи. Как обсуждалось в [Главе 1](/course/chapter1), декодер выполняет инференс, предсказывая токены по одному, и это реализуется методом модели `generate()`. Задание `predict_with_generate=True` указывает `Seq2SeqTrainer` на использование этого метода для оценки. Мы также скорректировали некоторые гиперпараметры по умолчанию, такие как скорость обучения, количество эпох и затухание весов, и задали параметр `save_total_limit`, чтобы сохранять только 3 контрольные точки во время обучения - это сделано потому, что даже "маленькая" версия mT5 использует около Гигабайта места на жестком диске, и мы можем сэкономить немного места, ограничив количество копий, которые мы сохраняем. +Здесь аргумент `predict_with_generate` был задан, чтобы указать, что мы должны генерировать резюме во время оценки, чтобы мы могли вычислить баллы ROUGE для каждой эпохи. Как обсуждалось в [Главе 1](../chapter1), декодер выполняет инференс, предсказывая токены по одному, и это реализуется методом модели `generate()`. Задание `predict_with_generate=True` указывает `Seq2SeqTrainer` на использование этого метода для оценки. Мы также скорректировали некоторые гиперпараметры по умолчанию, такие как скорость обучения, количество эпох и затухание весов, и задали параметр `save_total_limit`, чтобы сохранять только 3 контрольные точки во время обучения - это сделано потому, что даже "маленькая" версия mT5 использует около Гигабайта места на жестком диске, и мы можем сэкономить немного места, ограничив количество копий, которые мы сохраняем. Аргумент `push_to_hub=True` позволит нам отправить модель в Hub после обучения; вы найдете розиторий под своим профилем пользователя в месте, определенном `output_dir`. Обратите внимание, что вы можете указать имя розитория, в который хотите отправить модель, с помощью аргумента `hub_model_id` (в частности, вам нужно использовать этот аргумент, чтобы отправить модель в организацию). Например, когда мы отправили модель в организацию [`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/mt5-finetuned-amazon-en-es"` в `Seq2SeqTrainingArguments`. @@ -558,7 +558,7 @@ def compute_metrics(eval_pred): {/if} -Далее нам нужно определить коллатор данных для нашей задачи преобразования последовательности в последовательность. Поскольку mT5 является моделью трансформера кодер-декодер, одна из тонкостей подготовки наших батчей заключается в том, что во время декодирования нам нужно сдвинуть метки вправо на единицу. Это необходимо для того, чтобы декодер видел только предыдущие метки, а не текущие или будущие, которые модели было бы легко запомнить. Это похоже на то, как маскированное самовнимание применяется к входным данным в задаче типа [каузального языкового моделирования](/course/chapter7/6). +Далее нам нужно определить коллатор данных для нашей задачи преобразования последовательности в последовательность. Поскольку mT5 является моделью трансформера кодер-декодер, одна из тонкостей подготовки наших батчей заключается в том, что во время декодирования нам нужно сдвинуть метки вправо на единицу. Это необходимо для того, чтобы декодер видел только предыдущие метки, а не текущие или будущие, которые модели было бы легко запомнить. Это похоже на то, как маскированное самовнимание применяется к входным данным в задаче типа [каузального языкового моделирования](../chapter7/6). К счастью, 🤗 Transformers предоставляет коллатор `DataCollatorForSeq2Seq`, который будет динамически дополнять входные данные и метки за нас. Чтобы инстанцировать этот коллатор, нам просто нужно предоставить `tokenizer` и `model`: @@ -791,7 +791,7 @@ result = {key: value.mid.fmeasure * 100 for key, value in result.items()} ## Дообучение mT5 с 🤗 Accelerate[[fine-tuning-mt5-with-accelerate]] -Дообучение нашей модели с помощью 🤗 Accelerate очень похоже на пример с классификацией текста, который мы рассматривали в [Главе 3](/course/chapter3). Основные отличия заключаются в необходимости явной генерации резюме во время обучения и определении способа вычисления оценок ROUGE (напомним, что `Seq2SeqTrainer` позаботился о генерации за нас). Давайте посмотрим, как мы можем реализовать эти два требования в 🤗 Accelerate! +Дообучение нашей модели с помощью 🤗 Accelerate очень похоже на пример с классификацией текста, который мы рассматривали в [Главе 3](../chapter3). Основные отличия заключаются в необходимости явной генерации резюме во время обучения и определении способа вычисления оценок ROUGE (напомним, что `Seq2SeqTrainer` позаботился о генерации за нас). Давайте посмотрим, как мы можем реализовать эти два требования в 🤗 Accelerate! ### Подготовка всего к обучению[[preparing-everything-for-training]] @@ -845,7 +845,7 @@ model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( -🚨 Если вы обучаете на TPU, вам нужно будет перенести весь приведенный выше код в специальную функцию обучения. Подробнее смотрите в [Главе 3](/course/chapter3). +🚨 Если вы обучаете на TPU, вам нужно будет перенести весь приведенный выше код в специальную функцию обучения. Подробнее смотрите в [Главе 3](../chapter3). From 0b03f5c7c202bfed286596698f4de7fe8af5ca65 Mon Sep 17 00:00:00 2001 From: MKhalusova Date: Thu, 11 Jan 2024 16:59:36 -0500 Subject: [PATCH 355/502] fixed links to chapters' intros --- chapters/ru/chapter0/1.mdx | 2 +- chapters/ru/chapter2/1.mdx | 4 ++-- chapters/ru/chapter2/2.mdx | 6 +++--- chapters/ru/chapter2/3.mdx | 2 +- chapters/ru/chapter3/1.mdx | 2 +- chapters/ru/chapter3/2.mdx | 12 ++++++------ chapters/ru/chapter3/3.mdx | 6 +++--- chapters/ru/chapter3/3_tf.mdx | 4 ++-- chapters/ru/chapter5/1.mdx | 2 +- chapters/ru/chapter5/3.mdx | 10 +++++----- chapters/ru/chapter5/4.mdx | 2 +- chapters/ru/chapter5/6.mdx | 4 ++-- chapters/ru/chapter6/1.mdx | 2 +- chapters/ru/chapter6/2.mdx | 4 ++-- chapters/ru/chapter6/3.mdx | 8 ++++---- chapters/ru/chapter6/3b.mdx | 2 +- chapters/ru/chapter6/4.mdx | 2 +- chapters/ru/chapter7/1.mdx | 6 +++--- chapters/ru/chapter7/2.mdx | 18 +++++++++--------- chapters/ru/chapter7/3.mdx | 12 ++++++------ chapters/ru/chapter7/4.mdx | 10 +++++----- chapters/ru/chapter7/5.mdx | 18 +++++++++--------- 22 files changed, 69 insertions(+), 69 deletions(-) diff --git a/chapters/ru/chapter0/1.mdx b/chapters/ru/chapter0/1.mdx index ba7dd42c8..72fce3460 100644 --- a/chapters/ru/chapter0/1.mdx +++ b/chapters/ru/chapter0/1.mdx @@ -1,6 +1,6 @@ # Введение -Добро пожаловать на курс от Hugging Face! Это введение поможет настроить рабочее окружение. Если вы только начинаете курс, мы рекомендуем сначала заглянуть в [Главу 1](../chapter1), затем вернуться и настроить среду, чтобы попробовать запустить код самостоятельно. +Добро пожаловать на курс от Hugging Face! Это введение поможет настроить рабочее окружение. Если вы только начинаете курс, мы рекомендуем сначала заглянуть в [Главу 1](../chapter1/1), затем вернуться и настроить среду, чтобы попробовать запустить код самостоятельно. Все библиотеки, которые мы будем использовать в этом курсе, доступны в качестве Python-пакетов. В этом уроке мы покажем, как установить окружение и необходимые библиотеки. diff --git a/chapters/ru/chapter2/1.mdx b/chapters/ru/chapter2/1.mdx index fa750f068..ce2dbae74 100644 --- a/chapters/ru/chapter2/1.mdx +++ b/chapters/ru/chapter2/1.mdx @@ -5,7 +5,7 @@ classNames="absolute z-10 right-0 top-0" /> -Как вы могли заметить в [Главе 1](../chapter1), модели трансформеров обычно бывают очень большие. Обучение и развертывание таких моделей с миллионами и даже десятками *миллиардов* параметров является сложной задачей. Кроме того, новые модели выпускаются почти ежедневно, и каждая из них имеет собственную реализацию, опробовать их все — непростая задача. +Как вы могли заметить в [Главе 1](../chapter1/1), модели трансформеров обычно бывают очень большие. Обучение и развертывание таких моделей с миллионами и даже десятками *миллиардов* параметров является сложной задачей. Кроме того, новые модели выпускаются почти ежедневно, и каждая из них имеет собственную реализацию, опробовать их все — непростая задача. Библиотека 🤗 Transformers была создана для решения этой проблемы. Её цель — предоставить единый API, с помощью которого можно загружать, обучать и сохранять любую модель трансформера. Основными функциями библиотеки являются: @@ -15,7 +15,7 @@ Последняя особенность сильно отличает библиотеку 🤗 Transformers от других библиотек машинного обучения. Модели не строятся на модулях, которые являются общими для всех файлов; вместо этого каждая модель имеет свои собственные слои. Это не только делает модели более доступными и понятными, но и позволяет легко экспериментировать с одной моделью, не затрагивая другие. -Эта глава начнается со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воспроизвести функцию `pipeline()` представленную в [Главе 1](../chapter1). Далее мы обсудим API модели: углубимся в классы модели и конфигурации и покажем, как загружать модель и как она обрабатывает числовые входные данные для получения прогнозов. +Эта глава начнается со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воспроизвести функцию `pipeline()` представленную в [Главе 1](../chapter1/1). Далее мы обсудим API модели: углубимся в классы модели и конфигурации и покажем, как загружать модель и как она обрабатывает числовые входные данные для получения прогнозов. Затем мы рассмотрим API токенизатора, который является другим основным компонентом функции `pipeline()`. Токенизаторы берут на себя первый и последний этапы обработки, обрабатывая преобразование текста в числовые входные данные для нейронной сети и обратное преобразование в текст, когда это необходимо. Наконец, мы покажем вам, как обработывается передача нескольких предложений в модель с помощью подготовленных пакетов, а затем завершим все это более детальным рассмотрением высокоуровневой функции `tokenizer()`. diff --git a/chapters/ru/chapter2/2.mdx b/chapters/ru/chapter2/2.mdx index 53ae80016..3960afe39 100644 --- a/chapters/ru/chapter2/2.mdx +++ b/chapters/ru/chapter2/2.mdx @@ -32,7 +32,7 @@ {/if} -Давайте начнем с готового примера, взглянув на то, что происходило за кулисами, когда мы выполняли следующий код в [Главе 1](../chapter1): +Давайте начнем с готового примера, взглянув на то, что происходило за кулисами, когда мы выполняли следующий код в [Главе 1](../chapter1/1): ```python from transformers import pipeline @@ -53,7 +53,7 @@ classifier( {'label': 'NEGATIVE', 'score': 0.9994558095932007}] ``` -Как мы уже увидели в [Главе 1](../chapter1), данный конвейер включает в себя три шага: предварительная обработка, передача входных данных через модель и постобработка: +Как мы уже увидели в [Главе 1](../chapter1/1), данный конвейер включает в себя три шага: предварительная обработка, передача входных данных через модель и постобработка:
Полный конвейер NLP: токенизация текста, преобразование в идентификаторы и вывод с помощью модели Transformer и слоя 'head' модели. @@ -176,7 +176,7 @@ model = TFAutoModel.from_pretrained(checkpoint) Если вы пока не понимаете в чем смысл, не беспокойтесь об этом. Мы объясним все это позже. -Хотя эти скрытые состояния могут быть полезны сами по себе, они обычно являются входными данными для другой части модели, известной как слой *head*. В [Главе 1](../chapter1) разные задачи могли бы выполняться с одной и той же архитектурой, но с каждой из этих задач будет связан отдельный слой "head". +Хотя эти скрытые состояния могут быть полезны сами по себе, они обычно являются входными данными для другой части модели, известной как слой *head*. В [Главе 1](../chapter1/1) разные задачи могли бы выполняться с одной и той же архитектурой, но с каждой из этих задач будет связан отдельный слой "head". ### Многомерный вектор, что это? diff --git a/chapters/ru/chapter2/3.mdx b/chapters/ru/chapter2/3.mdx index d818897ce..b7e941ac4 100644 --- a/chapters/ru/chapter2/3.mdx +++ b/chapters/ru/chapter2/3.mdx @@ -112,7 +112,7 @@ model = TFBertModel(config) ``` {/if} -Модель можно использовать в этом состоянии, но она будет выводить тарабарщину; сначала ее нужно обучить. Мы могли бы обучить модель с нуля для решения поставленной задачи, но, как вы видели в [Главе 1](../chapter1), это потребовало бы много времени и большого количества данных, а также имело бы значительное воздействие на окружающую среду. Чтобы избежать ненужных и дублирующих усилий, крайне важно иметь возможность делиться и повторно использовать модели, которые уже были обучены. +Модель можно использовать в этом состоянии, но она будет выводить тарабарщину; сначала ее нужно обучить. Мы могли бы обучить модель с нуля для решения поставленной задачи, но, как вы видели в [Главе 1](../chapter1/1), это потребовало бы много времени и большого количества данных, а также имело бы значительное воздействие на окружающую среду. Чтобы избежать ненужных и дублирующих усилий, крайне важно иметь возможность делиться и повторно использовать модели, которые уже были обучены. Загрузить уже обученную модель Transformer очень просто — мы можем сделать это с помощью метода `from_pretrained()`: diff --git a/chapters/ru/chapter3/1.mdx b/chapters/ru/chapter3/1.mdx index f17d754bd..953a2bd45 100644 --- a/chapters/ru/chapter3/1.mdx +++ b/chapters/ru/chapter3/1.mdx @@ -7,7 +7,7 @@ classNames="absolute z-10 right-0 top-0" /> -В [главе 2](../chapter2) мы увидели, как можно использовать токенизаторы и предобученные модели для построения предсказаний. Но что если мы хотим дообучить предобученную модель на собственном датасете? Это и есть тема данной главы! Мы изучим: +В [главе 2](../chapter2/1) мы увидели, как можно использовать токенизаторы и предобученные модели для построения предсказаний. Но что если мы хотим дообучить предобученную модель на собственном датасете? Это и есть тема данной главы! Мы изучим: {#if fw === 'pt'} * Как подготовить большой датасет из Model Hub diff --git a/chapters/ru/chapter3/2.mdx b/chapters/ru/chapter3/2.mdx index 1613f54d6..4c791b475 100644 --- a/chapters/ru/chapter3/2.mdx +++ b/chapters/ru/chapter3/2.mdx @@ -23,7 +23,7 @@ {/if} {#if fw === 'pt'} -Продолжим с примером из [предыдущей главы](../chapter2), вот как мы будем обучать классификатор последовательности на одном батче с помощью PyTorch: +Продолжим с примером из [предыдущей главы](../chapter2/1), вот как мы будем обучать классификатор последовательности на одном батче с помощью PyTorch: ```python import torch @@ -48,7 +48,7 @@ loss.backward() optimizer.step() ``` {:else} -Continuing with the example from the [previous chapter](../chapter2), вот как мы будем обучать классификатор последовательности на одном батче с помощью TensorFlow: +Continuing with the example from the [previous chapter](../chapter2/1), вот как мы будем обучать классификатор последовательности на одном батче с помощью TensorFlow: ```python import tensorflow as tf @@ -159,7 +159,7 @@ raw_train_dataset.features {/if} -Чтобы предобработать датасет, нам необходимо конвертировать текст в числа, которые может обработать модель. Как вы видели в [предыдущей главе](../chapter2), это делается с помощью токенайзера. Мы можем подать на вход токенайзеру одно или список предложений, т.е. можно токенизировать предложения попарно таким образом: +Чтобы предобработать датасет, нам необходимо конвертировать текст в числа, которые может обработать модель. Как вы видели в [предыдущей главе](../chapter2/1), это делается с помощью токенайзера. Мы можем подать на вход токенайзеру одно или список предложений, т.е. можно токенизировать предложения попарно таким образом: ```py from transformers import AutoTokenizer @@ -185,7 +185,7 @@ inputs } ``` -Мы уже обсуждали ключи `input_ids` и `attention_mask` в [главе 2](../chapter2), но не упоминали о `token_type_ids`. В этом примере мы указываем модели какая часть входных данных является первым предложением, а какая вторым. +Мы уже обсуждали ключи `input_ids` и `attention_mask` в [главе 2](../chapter2/1), но не упоминали о `token_type_ids`. В этом примере мы указываем модели какая часть входных данных является первым предложением, а какая вторым. @@ -216,13 +216,13 @@ tokenizer.convert_ids_to_tokens(inputs["input_ids"]) Обратите внимание, что если вы выберете другой чекпоинт, `token_type_ids` необязательно будут присутствовать в ваших токенизированных входных данных (например, они не возвращаются, если вы используете модель DistilBERT). Они возвращаются только тогда, когда модель будет знать, что с ними делать, потому что она видела их во время предобучения. -В данном случае BERT был обучен с информацией о идентификаторах типов токенов, и помимо задачи маскированной языковой модели, о которой мы говорили в [главе 1](../chapter1), он может решать еще одну задачу: предсказание следующего предложения (_next sentence prediction_). Суть этой задачи - смоделировать связь между предложениями. +В данном случае BERT был обучен с информацией о идентификаторах типов токенов, и помимо задачи маскированной языковой модели, о которой мы говорили в [главе 1](../chapter1/1), он может решать еще одну задачу: предсказание следующего предложения (_next sentence prediction_). Суть этой задачи - смоделировать связь между предложениями. В этой задаче модели на вход подаются пары предложений (со случайно замаскированными токенами), от модели требуется предсказать, является ли следующее предложение продолжением текущего. Чтобы задача не была слишком тривиальной, половина времени модель обучается на соседних предложениях из одного документа, другую половину на парах предложений, взятых из разных источников. В общем случае вам не нужно беспокоиться о наличии `token_type_ids` в ваших токенизированных данных: пока вы используете одинаковый чекпоинт и для токенизатора, и для модели – токенизатор будет знать, как нужно обработать данные. -Теперь мы знаем, что токенизатор может подготовить сразу пару предложений, а значит мы можем использовать его для целого датасета: так же как и в [предыдущей главе](../chapter2) можно подать на вход токенизатору список первых предложений и список вторых предложений. Это также сработает и для механизмов дополнения (padding) и усечения до максимальной длины (truncation) - об этом мы говорили в [главе 2](../chapter2). Итак, один из способов предобработать обучающий датасет такой: +Теперь мы знаем, что токенизатор может подготовить сразу пару предложений, а значит мы можем использовать его для целого датасета: так же как и в [предыдущей главе](../chapter2/1) можно подать на вход токенизатору список первых предложений и список вторых предложений. Это также сработает и для механизмов дополнения (padding) и усечения до максимальной длины (truncation) - об этом мы говорили в [главе 2](../chapter2). Итак, один из способов предобработать обучающий датасет такой: ```py tokenized_dataset = tokenizer( diff --git a/chapters/ru/chapter3/3.mdx b/chapters/ru/chapter3/3.mdx index 787481517..4f00a73b3 100644 --- a/chapters/ru/chapter3/3.mdx +++ b/chapters/ru/chapter3/3.mdx @@ -49,7 +49,7 @@ training_args = TrainingArguments("test-trainer") -Второй шаг – задание модели. Так же, как и в [предыдущей главе](../chapter2), мы будем использовать класс `AutoModelForSequenceClassification` с двумя лейблами: +Второй шаг – задание модели. Так же, как и в [предыдущей главе](../chapter2/1), мы будем использовать класс `AutoModelForSequenceClassification` с двумя лейблами: ```py from transformers import AutoModelForSequenceClassification @@ -57,7 +57,7 @@ from transformers import AutoModelForSequenceClassification model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` -После создания экземпляра предобученной модели будет распечатано предупреждение (в [главе 2](../chapter2) мы с таким не сталкивались). Это происходит потому, что BERT не был предобучен для задачи классификации пар предложений, его последний слой не будет использован, вместо него будет добавлен слой, позволяющий работать с такой задачей. Предупреждения сообщают, что некоторые веса не будут использованы (как раз тех слоев, которые не будут использоваться) и для новых будут инициализированы случайные веса. В заключении предлагается обучить модель, что мы и сделаем прямо сейчас. +После создания экземпляра предобученной модели будет распечатано предупреждение (в [главе 2](../chapter2/1) мы с таким не сталкивались). Это происходит потому, что BERT не был предобучен для задачи классификации пар предложений, его последний слой не будет использован, вместо него будет добавлен слой, позволяющий работать с такой задачей. Предупреждения сообщают, что некоторые веса не будут использованы (как раз тех слоев, которые не будут использоваться) и для новых будут инициализированы случайные веса. В заключении предлагается обучить модель, что мы и сделаем прямо сейчас. После того, как мы загрузили модель, мы можем определить `Trainer` и передать туда нужные объекты: `model`, `training_args`, обучающую и валидационную выборки, `data_collator` и `tokenizer` @@ -105,7 +105,7 @@ print(predictions.predictions.shape, predictions.label_ids.shape) Результат функции `predict()` - другой именованный кортеж с полями `predictions`, `label_ids` и `metrics`. Поле `metrics` будет содержать значение лосса на нашем датасете и значения метрик. После реализации функции `compute_metrics()` и передачи ее в `Trainer` поле `metrics` также будет содержать результат функции `compute_metrics()`. -Как можно заметить, `predictions` - массив 408 х 2 (408 - число элементов в датасете, который мы использовали). Это логиты для каждого элемента нашего датасета, переданного в `predict()` (как вы видели в [предыдущей главе](../chapter2) все модели Трансформеров возвращают логиты). Чтобы превратить их в предсказания и сравнить с нашими лейблами, нам необходимо узнать индекс максимального элемента второй оси: +Как можно заметить, `predictions` - массив 408 х 2 (408 - число элементов в датасете, который мы использовали). Это логиты для каждого элемента нашего датасета, переданного в `predict()` (как вы видели в [предыдущей главе](../chapter2/1) все модели Трансформеров возвращают логиты). Чтобы превратить их в предсказания и сравнить с нашими лейблами, нам необходимо узнать индекс максимального элемента второй оси: ```py import numpy as np diff --git a/chapters/ru/chapter3/3_tf.mdx b/chapters/ru/chapter3/3_tf.mdx index e4207f846..bbe24dee5 100644 --- a/chapters/ru/chapter3/3_tf.mdx +++ b/chapters/ru/chapter3/3_tf.mdx @@ -58,7 +58,7 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( -Как и в [предыдущей главе](../chapter2), мы будем использовать класс `TFAutoModelForSequenceClassification` с двумя метками: +Как и в [предыдущей главе](../chapter2/1), мы будем использовать класс `TFAutoModelForSequenceClassification` с двумя метками: ```py from transformers import TFAutoModelForSequenceClassification @@ -66,7 +66,7 @@ from transformers import TFAutoModelForSequenceClassification model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) ``` -Вы заметите, что в отличие от [Главы 2](../chapter2), вы получаете предупреждение после создания экземпляра этой предварительно обученной модели. Это связано с тем, что BERT не был предварительно обучен классификации пар предложений, поэтому последний слой предварительно обученной модели был отброшен, а вместо него был вставлен новый слой, подходящий для классификации последовательностей. Предупреждения указывают на то, что некоторые веса не использовались (те, которые соответствуют удаленным слоям), а некоторые другие были инициализированы случайным образом (те, что для новых слоев). В заключение предлагается обучить модель, что мы и собираемся сделать сейчас. +Вы заметите, что в отличие от [Главы 2](../chapter2/1), вы получаете предупреждение после создания экземпляра этой предварительно обученной модели. Это связано с тем, что BERT не был предварительно обучен классификации пар предложений, поэтому последний слой предварительно обученной модели был отброшен, а вместо него был вставлен новый слой, подходящий для классификации последовательностей. Предупреждения указывают на то, что некоторые веса не использовались (те, которые соответствуют удаленным слоям), а некоторые другие были инициализированы случайным образом (те, что для новых слоев). В заключение предлагается обучить модель, что мы и собираемся сделать сейчас. Чтобы точно настроить модель в нашем наборе данных, нам просто нужно вызвать `compile()` у нашей модели, а затем передать наши данные в метод `fit()`. Это запустит процесс fine tuning (который должен занять пару минут на графическом процессоре) и сообщит о значениях функции потерь при обучении, а также о значениях функции потерь на валидации. diff --git a/chapters/ru/chapter5/1.mdx b/chapters/ru/chapter5/1.mdx index a5a7cbb4f..911a94fa8 100644 --- a/chapters/ru/chapter5/1.mdx +++ b/chapters/ru/chapter5/1.mdx @@ -1,6 +1,6 @@ # Введение -В [главе 3](../chapter3) вы поверхностно ознакомились с библиотекой 🤗 Datasets и увидели три главных шага для использования ее в процессе fine-tuning: +В [главе 3](../chapter3/1) вы поверхностно ознакомились с библиотекой 🤗 Datasets и увидели три главных шага для использования ее в процессе fine-tuning: 1. Загрузить датасет из Hugging Face Hub. 2. Произвести препроцессинг с помощью `Dataset.map()`. diff --git a/chapters/ru/chapter5/3.mdx b/chapters/ru/chapter5/3.mdx index e8e9e3610..2b1fded9c 100644 --- a/chapters/ru/chapter5/3.mdx +++ b/chapters/ru/chapter5/3.mdx @@ -13,7 +13,7 @@ ## Управление данными -Как и в Pandas, 🤗 Datasets предоставляет несколько функция для управления содержимым объектов `Dataset` и `DatasetDict`. Мы уже познакомились с методом `Dataset.map()` в [главе 3](../chapter3), а далее мы посмотрим на другие функции, имеющиеся в нашем распоряжении. +Как и в Pandas, 🤗 Datasets предоставляет несколько функция для управления содержимым объектов `Dataset` и `DatasetDict`. Мы уже познакомились с методом `Dataset.map()` в [главе 3](../chapter3/1), а далее мы посмотрим на другие функции, имеющиеся в нашем распоряжении. Для этого примера мы будем использовать датасет [Drug Review Dataset](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29), расположенный на сервере [UC Irvine Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) и содержащий отзывы пациентов на различные лекарства, сведения о состоянии пациентов и рейтинг удовлетворенности, выраженный в 10-балльной шкале. @@ -95,7 +95,7 @@ DatasetDict({ -Далее нормализуем все лейблы столбца `condition` с применением `Dataset.map()`. Так же, как мы делали токенизацию в [главе 3](../chapter3), мы можем определить простую функцию, которая будет применения для всех строк каждого сплита в `drug_dataset`: +Далее нормализуем все лейблы столбца `condition` с применением `Dataset.map()`. Так же, как мы делали токенизацию в [главе 3](../chapter3/1), мы можем определить простую функцию, которая будет применения для всех строк каждого сплита в `drug_dataset`: ```py def lowercase_condition(example): @@ -289,7 +289,7 @@ def tokenize_function(examples): return tokenizer(examples["review"], truncation=True) ``` -Как вы видели в [главе 3](../chapter3), мы можем передать один или несколько элементов в токенизатор, так что мы можем использовать эту функцию без параметра `batched=True`. Давайте воспользуемся этой возможностью и сравним производительность. В ноутбуке можно замерить время выполнения функции путем добавления `%time` перед строкой кода, время исполнения которой вы хотите измерить: +Как вы видели в [главе 3](../chapter3/1), мы можем передать один или несколько элементов в токенизатор, так что мы можем использовать эту функцию без параметра `batched=True`. Давайте воспользуемся этой возможностью и сравним производительность. В ноутбуке можно замерить время выполнения функции путем добавления `%time` перед строкой кода, время исполнения которой вы хотите измерить: ```python no-format %time tokenized_dataset = drug_dataset.map(tokenize_function, batched=True) @@ -740,8 +740,8 @@ drug_dataset_reloaded = load_dataset("json", data_files=data_files) Вот и все, что нужно для нашего экскурса при работе с 🤗 Datasets! Мы очистили датасет для обучения модели, вот некоторые идеи, которые вы могли бы реализовать самостоятельно: -1. Примените знания из [раздела 3](../chapter3) для обучения классификатора, который может предсказывать состояние пациента по отзыву на лекарство. -2. Используйте pipeline `summarization` из [раздела 1](../chapter1)для генерации саммари отзывов. +1. Примените знания из [раздела 3](../chapter3/1) для обучения классификатора, который может предсказывать состояние пациента по отзыву на лекарство. +2. Используйте pipeline `summarization` из [раздела 1](../chapter1/1)для генерации саммари отзывов. Далее мы посмотрим, как 🤗 Datasets могут помочь вам в работе с громадными датасетами, которые _невозможно_ обработать на вашем ноутбуке! diff --git a/chapters/ru/chapter5/4.mdx b/chapters/ru/chapter5/4.mdx index 68ea60a08..e9a6d32e9 100644 --- a/chapters/ru/chapter5/4.mdx +++ b/chapters/ru/chapter5/4.mdx @@ -157,7 +157,7 @@ next(iter(pubmed_dataset_streamed)) 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} ``` -Элементы из потокового набора данных можно обрабатывать на лету с помощью `IterableDataset.map()`, что полезно во время обучения, если вам нужно токенизировать входные данные. Процесс точно такой же, как тот, который мы использовали для токенизации нашего набора данных в [Главе 3](../chapter3), с той лишь разницей, что выходные данные возвращаются один за другим: +Элементы из потокового набора данных можно обрабатывать на лету с помощью `IterableDataset.map()`, что полезно во время обучения, если вам нужно токенизировать входные данные. Процесс точно такой же, как тот, который мы использовали для токенизации нашего набора данных в [Главе 3](../chapter3/1), с той лишь разницей, что выходные данные возвращаются один за другим: ```py from transformers import AutoTokenizer diff --git a/chapters/ru/chapter5/6.mdx b/chapters/ru/chapter5/6.mdx index 000f8a0a2..7488f6cda 100644 --- a/chapters/ru/chapter5/6.mdx +++ b/chapters/ru/chapter5/6.mdx @@ -28,7 +28,7 @@ ## Использование эмбеддингов для семанического поиска -Как мы видели в [Главе 1](../chapter1), языковые модели на основе Transformer представляют каждую лексему в текстовом фрагменте как _эмбеддинг-вектор_. Оказывается, можно «объединить» отдельные вложения, чтобы создать векторное представление для целых предложений, абзацев или (в некоторых случаях) документов. Затем эти вложения можно использовать для поиска похожих документов в корпусе путем вычисления скалярного произведения (или какой-либо другой метрики сходства) между каждым вложением и возврата документов с наибольшим перекрытием. +Как мы видели в [Главе 1](../chapter1/1), языковые модели на основе Transformer представляют каждую лексему в текстовом фрагменте как _эмбеддинг-вектор_. Оказывается, можно «объединить» отдельные вложения, чтобы создать векторное представление для целых предложений, абзацев или (в некоторых случаях) документов. Затем эти вложения можно использовать для поиска похожих документов в корпусе путем вычисления скалярного произведения (или какой-либо другой метрики сходства) между каждым вложением и возврата документов с наибольшим перекрытием. В этом разделе мы будем использовать вложения для разработки семантической поисковой системы. Эти поисковые системы предлагают несколько преимуществ по сравнению с традиционными подходами, основанными на сопоставлении ключевых слов в запросе с документами. @@ -236,7 +236,7 @@ comments_dataset = comments_dataset.map(concatenate_text) ## Создание текстовых эмбединнгов -В [Главе 2](../chapter2) мы видели, что можно получить эмбеддингов токенов с помощью класса AutoModel. Все, что нам нужно сделать, это выбрать подходящую контрольную точку для загрузки модели. К счастью, есть библиотека под названием `sentence-transformers`, предназначенная для создания эмбеддингов. Как описано в [документации](https://www.sbert.net/examples/applications/semantic-search/README.html#симметричный-vs-асимметричный-semantic-search) библиотеки, наш вариант использования является примером _асимметричного семантического поиска_ потому что у нас есть короткий запрос, ответ на который мы хотели бы найти в более длинном документе, например, в комментарии к проблеме. В удобной [таблице обзора модели](https://www.sbert.net/docs/pretrained_models.html#model-overview) в документации указано, что контрольная точка `multi-qa-mpnet-base-dot-v1` имеет лучшую производительность для семантического поиска, поэтому мы будем использовать её для нашего приложения. Мы также загрузим токенизатор, используя ту же контрольную точку: +В [Главе 2](../chapter2/1) мы видели, что можно получить эмбеддингов токенов с помощью класса AutoModel. Все, что нам нужно сделать, это выбрать подходящую контрольную точку для загрузки модели. К счастью, есть библиотека под названием `sentence-transformers`, предназначенная для создания эмбеддингов. Как описано в [документации](https://www.sbert.net/examples/applications/semantic-search/README.html#симметричный-vs-асимметричный-semantic-search) библиотеки, наш вариант использования является примером _асимметричного семантического поиска_ потому что у нас есть короткий запрос, ответ на который мы хотели бы найти в более длинном документе, например, в комментарии к проблеме. В удобной [таблице обзора модели](https://www.sbert.net/docs/pretrained_models.html#model-overview) в документации указано, что контрольная точка `multi-qa-mpnet-base-dot-v1` имеет лучшую производительность для семантического поиска, поэтому мы будем использовать её для нашего приложения. Мы также загрузим токенизатор, используя ту же контрольную точку: {#if fw === 'pt'} diff --git a/chapters/ru/chapter6/1.mdx b/chapters/ru/chapter6/1.mdx index 9e323cfa2..3aaeb428a 100644 --- a/chapters/ru/chapter6/1.mdx +++ b/chapters/ru/chapter6/1.mdx @@ -5,7 +5,7 @@ classNames="absolute z-10 right-0 top-0" /> -В [Главе 3](../chapter3) мы рассмотрели, как дообучить модель для конкретной задачи. При этом мы используем тот же токенизатор, на котором была предварительно обучена модель, но что делать, когда мы хотим обучить модель с нуля? В таких случаях использование токенизатора, который был предварительно обучен на корпусе из другой области или языка, как правило, является неоптимальным. Например, токенизатор, обученный на корпусе английских текстов, будет плохо работать на корпусе японских текстов, поскольку использование пробелов и знаков препинания в этих двух языках сильно отличается. +В [Главе 3](../chapter3/1) мы рассмотрели, как дообучить модель для конкретной задачи. При этом мы используем тот же токенизатор, на котором была предварительно обучена модель, но что делать, когда мы хотим обучить модель с нуля? В таких случаях использование токенизатора, который был предварительно обучен на корпусе из другой области или языка, как правило, является неоптимальным. Например, токенизатор, обученный на корпусе английских текстов, будет плохо работать на корпусе японских текстов, поскольку использование пробелов и знаков препинания в этих двух языках сильно отличается. В этой главе вы узнаете, как обучить совершенно новый токенизатор на корпусе текстов, чтобы затем использовать его для предварительного обучения языковой модели. Все это будет сделано с помощью библиотеки [🤗 Tokenizers](https://github.com/huggingface/tokenizers), которая предоставляет "быстрые" токенизаторы в библиотеке [🤗 Transformers](https://github.com/huggingface/transformers). Мы подробно рассмотрим возможности, которые предоставляет эта библиотека, и выясним, чем быстрые токенизаторы отличаются от "медленных" версий. diff --git a/chapters/ru/chapter6/2.mdx b/chapters/ru/chapter6/2.mdx index 3002789e3..089e23962 100644 --- a/chapters/ru/chapter6/2.mdx +++ b/chapters/ru/chapter6/2.mdx @@ -7,7 +7,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter6/section2.ipynb"}, ]} /> -Если языковая модель не доступна на интересующем вас языке или ваш корпус сильно отличается от того, на котором обучалась языковая модель, вам, скорее всего, придется заново обучать модель с нуля, используя токенизатор, адаптированный к вашим данным. Для этого потребуется обучить новый токенизатор на вашем наборе данных. Но что именно это значит? Когда мы впервые рассматривали токенизаторы в [Главе 2](../chapter2), мы увидели, что большинство моделей трансформеров используют _алгоритм токенизации по подсловам_. Чтобы определить, какие подслова представляют интерес и наиболее часто встречаются в корпусе, токенизатор должен внимательно изучить все тексты в корпусе - этот процесс мы называем *обучением*. Точные правила обучения зависят от типа используемого токенизатора, далее в этой главе мы рассмотрим три основных алгоритма. +Если языковая модель не доступна на интересующем вас языке или ваш корпус сильно отличается от того, на котором обучалась языковая модель, вам, скорее всего, придется заново обучать модель с нуля, используя токенизатор, адаптированный к вашим данным. Для этого потребуется обучить новый токенизатор на вашем наборе данных. Но что именно это значит? Когда мы впервые рассматривали токенизаторы в [Главе 2](../chapter2/1), мы увидели, что большинство моделей трансформеров используют _алгоритм токенизации по подсловам_. Чтобы определить, какие подслова представляют интерес и наиболее часто встречаются в корпусе, токенизатор должен внимательно изучить все тексты в корпусе - этот процесс мы называем *обучением*. Точные правила обучения зависят от типа используемого токенизатора, далее в этой главе мы рассмотрим три основных алгоритма. @@ -169,7 +169,7 @@ tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) Обратите внимание, что `AutoTokenizer.train_new_from_iterator()` работает только в том случае, если используемый вами токенизатор является "быстрым" токенизатором. Как вы увидите в следующем разделе, библиотека 🤗 Transformers содержит два типа токенизаторов: одни написаны исключительно на Python, а другие (быстрые) опираются на библиотеку 🤗 Tokenizers, которая написана на языке программирования [Rust](https://www.rust-lang.org). Python - это язык, который чаще всего используется для приложений data science и deep learning, но когда что-то нужно распараллелить для быстроты, это приходится писать на другом языке. Например, матричные умножения, которые лежат в основе вычислений модели, написаны на CUDA, оптимизированной библиотеке языка C для GPU. -Обучение совершенно нового токенизатора на чистом Python было бы мучительно медленным, поэтому мы разработали библиотеку 🤗 Tokenizers. Обратите внимание, что так же как вам не нужно было изучать язык CUDA, чтобы выполнить свою модель на батче входных данных на GPU, вам не понадобится изучать Rust, чтобы использовать быстрый токенизатор. Библиотека 🤗 Tokenizers предоставляет привязки к Python для многих методов, которые внутренне вызывают некоторые части кода на Rust; например, для распараллеливания обучения вашего нового токенизатора или, как мы видели в [Главе 3](../chapter3), токенизации батча входных данных. +Обучение совершенно нового токенизатора на чистом Python было бы мучительно медленным, поэтому мы разработали библиотеку 🤗 Tokenizers. Обратите внимание, что так же как вам не нужно было изучать язык CUDA, чтобы выполнить свою модель на батче входных данных на GPU, вам не понадобится изучать Rust, чтобы использовать быстрый токенизатор. Библиотека 🤗 Tokenizers предоставляет привязки к Python для многих методов, которые внутренне вызывают некоторые части кода на Rust; например, для распараллеливания обучения вашего нового токенизатора или, как мы видели в [Главе 3](../chapter3/1), токенизации батча входных данных. В большинстве моделей Transformer доступен быстрый токенизатор (есть некоторые исключения, о которых вы можете узнать [здесь](https://huggingface.co/transformers/#supported-frameworks)), а API `AutoTokenizer` всегда выбирает быстрый токенизатор, если он доступен. В следующем разделе мы рассмотрим некоторые другие особенности быстрых токенизаторов, которые будут очень полезны для таких задач, как классификация токенов и ответы на вопросы. Однако прежде чем погрузиться в эту тему, давайте попробуем наш новый токенизатор на предыдущем примере: diff --git a/chapters/ru/chapter6/3.mdx b/chapters/ru/chapter6/3.mdx index 0e117757e..214e2ba13 100644 --- a/chapters/ru/chapter6/3.mdx +++ b/chapters/ru/chapter6/3.mdx @@ -22,7 +22,7 @@ {/if} -В этом разделе мы подробно рассмотрим возможности токенизаторов в 🤗 Transformers. До сих пор мы использовали их только для токенизации входных данных или декодирования идентификаторов обратно в текст, но токенизаторы -- особенно те, которые поддерживаются библиотекой 🤗 Tokenizers - могут делать гораздо больше. Чтобы проиллюстрировать эти дополнительные возможности, мы рассмотрим, как воспроизвести результаты конвейеров `token-classification` (которые мы назвали `ner`) и `question-answering`, с которыми мы впервые столкнулись в [Главе 1](../chapter1). +В этом разделе мы подробно рассмотрим возможности токенизаторов в 🤗 Transformers. До сих пор мы использовали их только для токенизации входных данных или декодирования идентификаторов обратно в текст, но токенизаторы -- особенно те, которые поддерживаются библиотекой 🤗 Tokenizers - могут делать гораздо больше. Чтобы проиллюстрировать эти дополнительные возможности, мы рассмотрим, как воспроизвести результаты конвейеров `token-classification` (которые мы назвали `ner`) и `question-answering`, с которыми мы впервые столкнулись в [Главе 1](../chapter1/1). @@ -139,7 +139,7 @@ Sylvain ## Внутри конвейера `token-classification`[[inside-the-token-classification-pipeline]] -В [Главе 1](../chapter1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2](../chapter2), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! +В [Главе 1](../chapter1/1) мы впервые попробовали применить NER - когда задача состоит в том, чтобы определить, какие части текста соответствуют сущностям, таким как люди, места или организации - с помощью функции 🤗 Transformers `pipeline()`. Затем, в [Главе 2](../chapter2/1), мы увидели, как конвейер объединяет три этапа, необходимые для получения прогнозов из необработанного текста: токенизацию, прохождение входных данных через модель и постобработку. Первые два шага в конвейере `token-classification` такие же, как и в любом другом конвейере, но постобработка немного сложнее - давайте посмотрим, как это сделать! {#if fw === 'pt'} @@ -200,7 +200,7 @@ token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") {#if fw === 'pt'} -Сначала нам нужно токенизировать наш ввод и пропустить его через модель. Это делается точно так же, как в [Главе 2](../chapter2); мы инстанцируем токенизатор и модель с помощью классов `AutoXxx`, а затем используем их в нашем примере: +Сначала нам нужно токенизировать наш ввод и пропустить его через модель. Это делается точно так же, как в [Главе 2](../chapter2/1); мы инстанцируем токенизатор и модель с помощью классов `AutoXxx`, а затем используем их в нашем примере: ```py from transformers import AutoTokenizer, AutoModelForTokenClassification @@ -228,7 +228,7 @@ torch.Size([1, 19, 9]) {:else} -Сначала нам нужно токенизировать наши входные данные и пропустить их через модель. Это делается точно так же, как в [Главе 2](../chapter2); мы инстанцируем токенизатор и модель с помощью классов `TFAutoXxx`, а затем используем их в нашем примере: +Сначала нам нужно токенизировать наши входные данные и пропустить их через модель. Это делается точно так же, как в [Главе 2](../chapter2/1); мы инстанцируем токенизатор и модель с помощью классов `TFAutoXxx`, а затем используем их в нашем примере: ```py from transformers import AutoTokenizer, TFAutoModelForTokenClassification diff --git a/chapters/ru/chapter6/3b.mdx b/chapters/ru/chapter6/3b.mdx index fed113bf4..6ad4b6ed0 100644 --- a/chapters/ru/chapter6/3b.mdx +++ b/chapters/ru/chapter6/3b.mdx @@ -36,7 +36,7 @@ ## Использование конвейера `question-answering`[[using-the-question-answering-pipeline]] -Как мы видели в [Главе 1](../chapter1), для получения ответа на вопрос мы можем использовать конвейер `question-answering` следующим образом: +Как мы видели в [Главе 1](../chapter1/1), для получения ответа на вопрос мы можем использовать конвейер `question-answering` следующим образом: ```py from transformers import pipeline diff --git a/chapters/ru/chapter6/4.mdx b/chapters/ru/chapter6/4.mdx index a220a1314..fc5eaecf0 100644 --- a/chapters/ru/chapter6/4.mdx +++ b/chapters/ru/chapter6/4.mdx @@ -57,7 +57,7 @@ print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü? -Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2](../chapter2), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. +Как мы увидим в следующих разделах, токенизатор не может быть обучен только на сыром тексте. Сначала необходимо разбить текст на небольшие части, например, на слова. Именно в этом и заключается этап предварительной токенизации. Как мы видели в [Главе 2](../chapter2/1), токенизатор на основе слов (word-based tokenizer) может просто разбить необработанный текст на слова по пробелам и знакам пунктуации. Эти слова станут границами подтокенов, которые токенизатор сможет выучить в процессе обучения. Чтобы увидеть, как быстрый токенизатор выполняет предварительную токенизацию, мы можем воспользоваться методом `pre_tokenize_str()` атрибута `pre_tokenizer` объекта `tokenizer`: diff --git a/chapters/ru/chapter7/1.mdx b/chapters/ru/chapter7/1.mdx index d9f8cb9b3..47cf244b5 100644 --- a/chapters/ru/chapter7/1.mdx +++ b/chapters/ru/chapter7/1.mdx @@ -7,7 +7,7 @@ classNames="absolute z-10 right-0 top-0" /> -В [Главе 3](../chapter3) вы узнали, как дообучить модель для классификации текстов. В этой главе мы рассмотрим следующие общие задачи NLP: +В [Главе 3](../chapter3/1) вы узнали, как дообучить модель для классификации текстов. В этой главе мы рассмотрим следующие общие задачи NLP: - Классификация токенов (Token classification) - Маскированное языковое моделирование (Masked language modeling, например, BERT) @@ -18,13 +18,13 @@ {#if fw === 'pt'} -Для этого вам понадобится использовать все, что вы узнали об API `Trainer` и библиотеке 🤗 Accelerate в [Главе 3](../chapter3), библиотеке 🤗 Datasets в [Главе 5](../chapter5) и библиотеке 🤗 Tokenizers в [Главе 6](../chapter6). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](../chapter4), так что это действительно глава,в которой все собирается воедино! +Для этого вам понадобится использовать все, что вы узнали об API `Trainer` и библиотеке 🤗 Accelerate в [Главе 3](../chapter3/1), библиотеке 🤗 Datasets в [Главе 5](../chapter5/1) и библиотеке 🤗 Tokenizers в [Главе 6](../chapter6/1). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](../chapter4/1), так что это действительно глава,в которой все собирается воедино! Каждый раздел можно читать независимо друг от друга, и в нем вы узнаете, как обучить модель с помощью API `Trainer` или с помощью собственного цикла обучения, используя 🤗 Accelerate. Вы можете пропустить любую часть и сосредоточиться на той, которая вас больше всего интересует: API `Trainer` отлично подходит для того, чтобы дообучить или обучить вашу модель, не беспокоясь о том, что происходит за кулисами, а цикл обучения с `Accelerate` позволит вам легче настроить любую часть, которую вы хотите. {:else} -Для этого вам понадобится использовать все, что вы узнали об обучении моделей с помощью Keras API в [Главе 3](../chapter3), библиотеке 🤗 Datasets в [Главе 5](../chapter5) и библиотеке 🤗 Tokenizers в [Главе 6](../chapter6). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](../chapter4), так что это действительно глава, в которой все собирается воедино! +Для этого вам понадобится использовать все, что вы узнали об обучении моделей с помощью Keras API в [Главе 3](../chapter3/1), библиотеке 🤗 Datasets в [Главе 5](../chapter5/1) и библиотеке 🤗 Tokenizers в [Главе 6](../chapter6/1). Мы также загрузим наши результаты в хаб моделей, как мы делали это в [Главе 4](../chapter4/1), так что это действительно глава, в которой все собирается воедино! Каждый раздел можно читать самостоятельно. diff --git a/chapters/ru/chapter7/2.mdx b/chapters/ru/chapter7/2.mdx index 714613db4..edc843490 100644 --- a/chapters/ru/chapter7/2.mdx +++ b/chapters/ru/chapter7/2.mdx @@ -47,7 +47,7 @@ -💡 Если ваш набор данных состоит из текстов, часть которых состоит из слов с соответствующими метками, вы сможете адаптировать описанные здесь процедуры обработки данных к своему набору данных. Обратитесь к [Главе 5](../chapter5), если вам нужно освежить в памяти то, как загружать собственные данные в `Dataset`. +💡 Если ваш набор данных состоит из текстов, часть которых состоит из слов с соответствующими метками, вы сможете адаптировать описанные здесь процедуры обработки данных к своему набору данных. Обратитесь к [Главе 5](../chapter5/1), если вам нужно освежить в памяти то, как загружать собственные данные в `Dataset`. @@ -61,7 +61,7 @@ from datasets import load_dataset raw_datasets = load_dataset("conll2003") ``` -Это позволит загрузить и кэшировать датасет, как мы видели в [Главе 3](../chapter3) для датасета GLUE MRPC. Изучение этого объекта показывает нам присутствующие столбцы и части тренировочного, проверочного и тестового наборов: +Это позволит загрузить и кэшировать датасет, как мы видели в [Главе 3](../chapter3/1) для датасета GLUE MRPC. Изучение этого объекта показывает нам присутствующие столбцы и части тренировочного, проверочного и тестового наборов: ```py raw_datasets @@ -298,7 +298,7 @@ tokenized_datasets = raw_datasets.map( ) ``` -Мы сделали самую сложную часть! Теперь, когда данные прошли предварительную обработку, само обучение будет выглядеть примерно так, как мы делали это в [Главе 3](../chapter3). +Мы сделали самую сложную часть! Теперь, когда данные прошли предварительную обработку, само обучение будет выглядеть примерно так, как мы делали это в [Главе 3](../chapter3/1). {#if fw === 'pt'} @@ -317,7 +317,7 @@ tokenized_datasets = raw_datasets.map( ### Сопоставление данных[[data-collation]] -Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](../chapter3), потому что в этом случае дополняются только входные данные (идентификаторы входов, маска внимания и идентификаторы типов токенов). Здесь наши метки должны быть дополнены точно так же, как и входы, чтобы они оставались одного размера, используя `-100` в качестве значения, чтобы соответствующие прогнозы игнорировались при вычислении потерь. +Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](../chapter3/1), потому что в этом случае дополняются только входные данные (идентификаторы входов, маска внимания и идентификаторы типов токенов). Здесь наши метки должны быть дополнены точно так же, как и входы, чтобы они оставались одного размера, используя `-100` в качестве значения, чтобы соответствующие прогнозы игнорировались при вычислении потерь. Все это делает [`DataCollatorForTokenClassification`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorfortokenclassification). Как и `DataCollatorWithPadding`, он принимает `токенизатор`, используемый для предварительной обработки входных данных: @@ -419,7 +419,7 @@ model = TFAutoModelForTokenClassification.from_pretrained( ) ``` -Как и при определении `TFAutoModelForSequenceClassification` в [Главе 3](../chapter3), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (веса из предварительно обученной головы), а другие веса инициализированы случайно (веса из новой головы классификации токенов), и что эту модель нужно обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: +Как и при определении `TFAutoModelForSequenceClassification` в [Главе 3](../chapter3/1), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (веса из предварительно обученной головы), а другие веса инициализированы случайно (веса из новой головы классификации токенов), и что эту модель нужно обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: ```python model.config.num_labels @@ -522,7 +522,7 @@ model.fit( !pip install seqeval ``` -Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](../chapter3): +Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](../chapter3/1): {:else} @@ -532,7 +532,7 @@ model.fit( !pip install seqeval ``` -Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](../chapter3): +Мы можем загрузить ее с помощью функции `evaluate.load()`, как мы это делали в [Главе 3](../chapter3/1): {/if} @@ -669,7 +669,7 @@ model = AutoModelForTokenClassification.from_pretrained( ) ``` -Как и в случае определения `AutoModelForSequenceClassification` в [Главе 3](../chapter3), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (те, что были получены из предварительно обученной головы), а другие инициализированы случайно (те, что были получены из новой головы классификации токенов), и что эту модель необходимо обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: +Как и в случае определения `AutoModelForSequenceClassification` в [Главе 3](../chapter3/1), при создании модели выдается предупреждение о том, что некоторые веса не были использованы (те, что были получены из предварительно обученной головы), а другие инициализированы случайно (те, что были получены из новой головы классификации токенов), и что эту модель необходимо обучить. Мы сделаем это через минуту, но сначала давайте перепроверим, что наша модель имеет правильное количество меток: ```python model.config.num_labels @@ -815,7 +815,7 @@ model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( -🚨 Если вы обучаетесь на TPU, вам нужно будет перенести весь код, начиная с ячейки выше, в специальную функцию обучения. Подробнее смотрите [Главу 3](../chapter3). +🚨 Если вы обучаетесь на TPU, вам нужно будет перенести весь код, начиная с ячейки выше, в специальную функцию обучения. Подробнее смотрите [Главу 3](../chapter3/1). diff --git a/chapters/ru/chapter7/3.mdx b/chapters/ru/chapter7/3.mdx index 323e779f6..da62408eb 100644 --- a/chapters/ru/chapter7/3.mdx +++ b/chapters/ru/chapter7/3.mdx @@ -43,7 +43,7 @@ -🙋 Если термины "маскированное моделирование языка (masked language modeling)" и "предварительно обученная модель (pretrained model)" кажутся вам незнакомыми, загляните в [Главу 1](../chapter1), где мы объясняем все эти основные понятия, сопровождая их видеороликами! +🙋 Если термины "маскированное моделирование языка (masked language modeling)" и "предварительно обученная модель (pretrained model)" кажутся вам незнакомыми, загляните в [Главу 1](../chapter1/1), где мы объясняем все эти основные понятия, сопровождая их видеороликами! @@ -243,7 +243,7 @@ for row in sample: -Теперь, когда мы вкратце ознакомились с данными, давайте перейдем к их подготовке к моделированию языка по маске. Как мы увидим, есть несколько дополнительных шагов, которые необходимо сделать по сравнению с задачами классификации последовательностей, которые мы рассматривали в [Главе 3](../chapter3). Поехали! +Теперь, когда мы вкратце ознакомились с данными, давайте перейдем к их подготовке к моделированию языка по маске. Как мы увидим, есть несколько дополнительных шагов, которые необходимо сделать по сравнению с задачами классификации последовательностей, которые мы рассматривали в [Главе 3](../chapter3/1). Поехали! ## Предварительная обработка данных[[preprocessing-the-data]] @@ -445,7 +445,7 @@ tokenizer.decode(lm_datasets["train"][1]["labels"]) ## Дообучение DistilBERT с помощью API `Trainer`[[fine-tuning-distilbert-with-the-trainer-api]] -Дообучить модель моделирования языка по маске почти то же самое, что и дообучить модель классификации последовательностей, как мы делали в [Главе 3](../chapter3). Единственное отличие заключается в том, что нам нужен специальный коллатор данных, который может случайным образом маскировать некоторые токены в каждом батче текстов. К счастью, 🤗 Transformers поставляется со специальным `DataCollatorForLanguageModeling`, предназначенным именно для этой задачи. Нам нужно только передать ему токенизатор и аргумент `mlm_probability`, который указывает, какую долю токенов нужно маскировать. Мы выберем 15 % - это количество используется для BERT и является распространенным выбором в литературе: +Дообучить модель моделирования языка по маске почти то же самое, что и дообучить модель классификации последовательностей, как мы делали в [Главе 3](../chapter3/1). Единственное отличие заключается в том, что нам нужен специальный коллатор данных, который может случайным образом маскировать некоторые токены в каждом батче текстов. К счастью, 🤗 Transformers поставляется со специальным `DataCollatorForLanguageModeling`, предназначенным именно для этой задачи. Нам нужно только передать ему токенизатор и аргумент `mlm_probability`, который указывает, какую долю токенов нужно маскировать. Мы выберем 15 % - это количество используется для BERT и является распространенным выбором в литературе: ```python from transformers import DataCollatorForLanguageModeling @@ -592,7 +592,7 @@ for chunk in batch["input_ids"]: -Теперь, когда у нас есть два колатора данных, остальные шаги по дообучению стандартны. Обучение может занять много времени в Google Colab, если вам не посчастливилось получить мифический GPU P100 😭, поэтому мы сначала уменьшим размер обучающего набора до нескольких тысяч примеров. Не волнуйтесь, мы все равно получим довольно приличную языковую модель! Быстрый способ уменьшить размер датасета в 🤗 Datasets - это функция `Dataset.train_test_split()`, которую мы рассматривали в [Главе 5](../chapter5): +Теперь, когда у нас есть два колатора данных, остальные шаги по дообучению стандартны. Обучение может занять много времени в Google Colab, если вам не посчастливилось получить мифический GPU P100 😭, поэтому мы сначала уменьшим размер обучающего набора до нескольких тысяч примеров. Не волнуйтесь, мы все равно получим довольно приличную языковую модель! Быстрый способ уменьшить размер датасета в 🤗 Datasets - это функция `Dataset.train_test_split()`, которую мы рассматривали в [Главе 5](../chapter5/1): ```python train_size = 10_000 @@ -827,7 +827,7 @@ trainer.push_to_hub() ## Дообучение DistilBERT с помощью 🤗 Accelerate[[fine-tuning-distilbert-with-accelerate]] -Как мы видели на примере `Trainer`, дообучение модели маскированного языкового моделирования очень похоже на пример классификации текста из [Главы 3](../chapter3). Фактически, единственной особенностью является использование специального коллатора данных, о котором мы уже рассказывали ранее в этом разделе! +Как мы видели на примере `Trainer`, дообучение модели маскированного языкового моделирования очень похоже на пример классификации текста из [Главы 3](../chapter3/1). Фактически, единственной особенностью является использование специального коллатора данных, о котором мы уже рассказывали ранее в этом разделе! Однако мы видели, что `DataCollatorForLanguageModeling` также применяет случайное маскирование при каждой оценке, поэтому мы увидим некоторые колебания в наших оценках перплексии при каждом цикле обучения. Один из способов устранить этот источник случайности - применить маскирование _один раз_ ко всему тестовому набору, а затем использовать стандартный коллатор данных в 🤗 Transformers для сбора батчей во время оценки. Чтобы увидеть, как это работает, давайте реализуем простую функцию, которая применяет маскирование к батчу, подобно нашей первой работе с `DataCollatorForLanguageModeling`: @@ -1039,6 +1039,6 @@ for pred in preds: -✏️ **Попробуйте!** Чтобы оценить преимущества адаптации к домену, дообучите классификатор на метках IMDb как для предварительно обученных, так и для дообученных контрольных точек DistilBERT. Если вам нужно освежить в памяти классификацию текстов, ознакомьтесь с [Главой 3](../chapter3). +✏️ **Попробуйте!** Чтобы оценить преимущества адаптации к домену, дообучите классификатор на метках IMDb как для предварительно обученных, так и для дообученных контрольных точек DistilBERT. Если вам нужно освежить в памяти классификацию текстов, ознакомьтесь с [Главой 3](../chapter3/1). diff --git a/chapters/ru/chapter7/4.mdx b/chapters/ru/chapter7/4.mdx index e9b150d46..53d1155ef 100644 --- a/chapters/ru/chapter7/4.mdx +++ b/chapters/ru/chapter7/4.mdx @@ -46,7 +46,7 @@ ## Подготовка данных[[preparing-the-data]] -Чтобы дообучить или обучить модель перевода с нуля, нам понадобится датасет, подходящий для этой задачи. Как уже упоминалось, мы будем использовать [датасет KDE4](https://huggingface.co/datasets/kde4) , но вы можете легко адаптировать код для использования своих собственных данных, если у вас есть пары предложений на двух языках, с которых вы хотите переводить и на которые хотите переводить. Обратитесь к [Главе 5](../chapter5) если вам нужно вспомнить, как загружать пользовательские данные в `Dataset`. +Чтобы дообучить или обучить модель перевода с нуля, нам понадобится датасет, подходящий для этой задачи. Как уже упоминалось, мы будем использовать [датасет KDE4](https://huggingface.co/datasets/kde4) , но вы можете легко адаптировать код для использования своих собственных данных, если у вас есть пары предложений на двух языках, с которых вы хотите переводить и на которые хотите переводить. Обратитесь к [Главе 5](../chapter5/1) если вам нужно вспомнить, как загружать пользовательские данные в `Dataset`. ### Датасет KDE4[[the-kde4-dataset]] @@ -77,7 +77,7 @@ DatasetDict({ }) ``` -У нас есть 210 173 пары предложений, но в одной части, поэтому нам нужно создать собственный проверочный набор. Как мы видели в [Главе 5](../chapter5), у `Dataset` есть метод `train_test_split()`, который может нам помочь. Мы зададим seed для воспроизводимости: +У нас есть 210 173 пары предложений, но в одной части, поэтому нам нужно создать собственный проверочный набор. Как мы видели в [Главе 5](../chapter5/1), у `Dataset` есть метод `train_test_split()`, который может нам помочь. Мы зададим seed для воспроизводимости: ```py split_datasets = raw_datasets["train"].train_test_split(train_size=0.9, seed=20) @@ -298,7 +298,7 @@ model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint, from_pt=True) ### Сопоставление данных[[data-collation]] -Для динамического батча нам понадобится коллатор данных для работы с дополнением (padding). Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](../chapter3), потому что в этом случае будут заполнены только входы (идентификаторы входов, маска внимания и идентификаторы типов токенов). Наши метки также должны быть дополнены до максимальной длины, встречающейся в метках. И, как уже говорилось, добовляемое значение, используемое для дополнения меток, должно быть `-100`, а не добавочный токен токенизатора, чтобы эти добавочные значения игнорировались при вычислении потерь. +Для динамического батча нам понадобится коллатор данных для работы с дополнением (padding). Мы не можем просто использовать `DataCollatorWithPadding`, как в [Главе 3](../chapter3/1), потому что в этом случае будут заполнены только входы (идентификаторы входов, маска внимания и идентификаторы типов токенов). Наши метки также должны быть дополнены до максимальной длины, встречающейся в метках. И, как уже говорилось, добовляемое значение, используемое для дополнения меток, должно быть `-100`, а не добавочный токен токенизатора, чтобы эти добавочные значения игнорировались при вычислении потерь. Все это делает [`DataCollatorForSeq2Seq`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorforseq2seq). Как и `DataCollatorWithPadding`, он принимает `tokenizer`, используемый для препроцессирования входных данных, а также `model`. Это связано с тем, что данный коллатор данных также будет отвечать за подготовку входных идентификаторов декодера, которые представляют собой сдвинутые версии меток со специальным токеном в начале. Поскольку для разных архитектур этот сдвиг выполняется по-разному, `DataCollatorForSeq2Seq` должен знать объект `model`: @@ -415,7 +415,7 @@ tf_eval_dataset = model.prepare_tf_dataset( !pip install sacrebleu ``` -Затем мы можем загрузить ее с помощью `evaluate.load()`, как мы это делали в [Главе 3](../chapter3): +Затем мы можем загрузить ее с помощью `evaluate.load()`, как мы это делали в [Главе 3](../chapter3/1): ```py import evaluate @@ -892,7 +892,7 @@ def postprocess(predictions, labels): return decoded_preds, decoded_labels ``` -Цикл обучения очень похож на циклы в [разделе 2](../chapter7/2) и [главе 3](../chapter3), с некоторыми отличиями в части оценки - так что давайте сосредоточимся на этом! +Цикл обучения очень похож на циклы в [разделе 2](../chapter7/2) и [главе 3](../chapter3/1), с некоторыми отличиями в части оценки - так что давайте сосредоточимся на этом! Первое, что следует отметить, это то, что мы используем метод `generate()` для вычисления прогнозов, но это метод нашей базовой модели, а не обернутой модели 🤗 Accelerate, созданной в методе `prepare()`. Поэтому мы сначала развернем модель, а затем вызовем этот метод. diff --git a/chapters/ru/chapter7/5.mdx b/chapters/ru/chapter7/5.mdx index 2c95b0c47..9c14bb75a 100644 --- a/chapters/ru/chapter7/5.mdx +++ b/chapters/ru/chapter7/5.mdx @@ -62,7 +62,7 @@ DatasetDict({ }) ``` -Как видите, для каждого языка есть 200 000 отзывов в части `train` и по 5 000 отзывов в частях `validation` и `test`. Интересующая нас информация о рецензиях содержится в столбцах `review_body` и `review_title`. Давайте рассмотрим несколько примеров, создав простую функцию, которая берет случайную выборку из обучающего множества с помощью методов, изученных в [Главе 5](../chapter5): +Как видите, для каждого языка есть 200 000 отзывов в части `train` и по 5 000 отзывов в частях `validation` и `test`. Интересующая нас информация о рецензиях содержится в столбцах `review_body` и `review_title`. Давайте рассмотрим несколько примеров, создав простую функцию, которая берет случайную выборку из обучающего множества с помощью методов, изученных в [Главе 5](../chapter5/1): ```python def show_samples(dataset, num_samples=3, seed=42): @@ -125,7 +125,7 @@ book 3756 Name: product_category, dtype: int64 ``` -Самые популярные товары в английском датасете - это бытовые товары, одежда и беспроводная электроника. Однако, чтобы поддержать тему Amazon, давайте сосредоточимся на суммаризации отзывов о книгах - в конце концов, именно для этого компания и была основана! Мы видим две категории товаров, которые подходят для этой цели (`book` и `digital_ebook_purchase`), поэтому давайте отфильтруем датасеты на обоих языках только для этих товаров. Как мы видели в [Главе 5](../chapter5), функция `Dataset.filter()` позволяет нам очень эффективно разделять датасет на части, поэтому мы можем определить простую функцию для этого: +Самые популярные товары в английском датасете - это бытовые товары, одежда и беспроводная электроника. Однако, чтобы поддержать тему Amazon, давайте сосредоточимся на суммаризации отзывов о книгах - в конце концов, именно для этого компания и была основана! Мы видим две категории товаров, которые подходят для этой цели (`book` и `digital_ebook_purchase`), поэтому давайте отфильтруем датасеты на обоих языках только для этих товаров. Как мы видели в [Главе 5](../chapter5/1), функция `Dataset.filter()` позволяет нам очень эффективно разделять датасет на части, поэтому мы можем определить простую функцию для этого: ```python def filter_books(example): @@ -205,7 +205,7 @@ books_dataset = books_dataset.filter(lambda x: len(x["review_title"].split()) > ## Модели для суммаризации текста[[models-for-text-summarization]] -Если задуматься, то суммаризация текста - это задача, похожая на машинный перевод: у нас есть текст, например рецензия, который мы хотели бы "перевести" в более короткую версию, передающую основные особенности исходного текста. Соответственно, большинство моделей Transformer для суммаризации используют архитектуру кодер-декодер, с которой мы впервые столкнулись в [Глава 1](../chapter1), хотя есть и исключения, например семейство моделей GPT, которые также могут использоваться для суммаризации в условиях few-shot настроек. В следующей таблице перечислены некоторые популярные предварительно обученные модели, которые можно дообучить для суммаризации. +Если задуматься, то суммаризация текста - это задача, похожая на машинный перевод: у нас есть текст, например рецензия, который мы хотели бы "перевести" в более короткую версию, передающую основные особенности исходного текста. Соответственно, большинство моделей Transformer для суммаризации используют архитектуру кодер-декодер, с которой мы впервые столкнулись в [Глава 1](../chapter1/1), хотя есть и исключения, например семейство моделей GPT, которые также могут использоваться для суммаризации в условиях few-shot настроек. В следующей таблице перечислены некоторые популярные предварительно обученные модели, которые можно дообучить для суммаризации. | Модель Transformer | Описание | Многоязычная? | | :---------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------: | @@ -264,7 +264,7 @@ inputs {'input_ids': [336, 259, 28387, 11807, 287, 62893, 295, 12507, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} ``` -Здесь мы видим знакомые нам `input_ids` и `attention_mask`, с которыми мы столкнулись в наших первых экспериментах по дообучению еще в [Главе 3](../chapter3). Давайте декодируем эти входные идентификаторы с помощью функции токенизатора `convert_ids_to_tokens()`, чтобы понять, с каким токенизатором мы имеем дело: +Здесь мы видим знакомые нам `input_ids` и `attention_mask`, с которыми мы столкнулись в наших первых экспериментах по дообучению еще в [Главе 3](../chapter3/1). Давайте декодируем эти входные идентификаторы с помощью функции токенизатора `convert_ids_to_tokens()`, чтобы понять, с каким токенизатором мы имеем дело: ```python tokenizer.convert_ids_to_tokens(inputs.input_ids) @@ -274,7 +274,7 @@ tokenizer.convert_ids_to_tokens(inputs.input_ids) ['▁I', '▁', 'loved', '▁reading', '▁the', '▁Hung', 'er', '▁Games', ''] ``` -Специальный символ Юникода `▁` и токен конца последовательности `` указывают на то, что мы имеем дело с токенизатором SentencePiece, который основан на алгоритме сегментации Unigram, рассмотренном в [Главе 6](../chapter6). Unigram особенно полезен для многоязычных корпусов, поскольку он позволяет SentencePiece не зависеть от ударений, пунктуации и того факта, что во многих языках, например в японском, нет пробельных символов. +Специальный символ Юникода `▁` и токен конца последовательности `` указывают на то, что мы имеем дело с токенизатором SentencePiece, который основан на алгоритме сегментации Unigram, рассмотренном в [Главе 6](../chapter6/1). Unigram особенно полезен для многоязычных корпусов, поскольку он позволяет SentencePiece не зависеть от ударений, пунктуации и того факта, что во многих языках, например в японском, нет пробельных символов. Для токенизации нашего корпуса нам придется столкнуться с одной тонкостью, связанной с сумризацией: поскольку наши метки также являются текстом, возможно, что они превышают максимальный размер контекста модели. Это означает, что нам нужно применять усечение как к обзорам, так и к их заголовкам, чтобы не передавать в модель слишком длинные данные. Токенизаторы в 🤗 Transformers предоставляют интересный аргумент `text_target`, который позволяет вам токенизировать метки параллельно с входными данными. Вот пример того, как обрабатываются входные и целевые данные для mT5: @@ -480,7 +480,7 @@ model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) -💡 Если вы задаетесь вопросом, почему вы не видите предупреждений о необходимости дообучить модель для последующей задачи, то это потому, что для задач "последовательность-в-последовательность" мы сохраняем все веса сети. Сравните это с нашей моделью классификации текста из [Главы 3](../chapter3), где голова предварительно обученной модели была заменена на случайно инициализированную сеть. +💡 Если вы задаетесь вопросом, почему вы не видите предупреждений о необходимости дообучить модель для последующей задачи, то это потому, что для задач "последовательность-в-последовательность" мы сохраняем все веса сети. Сравните это с нашей моделью классификации текста из [Главы 3](../chapter3/1), где голова предварительно обученной модели была заменена на случайно инициализированную сеть. @@ -526,7 +526,7 @@ args = Seq2SeqTrainingArguments( ) ``` -Здесь аргумент `predict_with_generate` был задан, чтобы указать, что мы должны генерировать резюме во время оценки, чтобы мы могли вычислить баллы ROUGE для каждой эпохи. Как обсуждалось в [Главе 1](../chapter1), декодер выполняет инференс, предсказывая токены по одному, и это реализуется методом модели `generate()`. Задание `predict_with_generate=True` указывает `Seq2SeqTrainer` на использование этого метода для оценки. Мы также скорректировали некоторые гиперпараметры по умолчанию, такие как скорость обучения, количество эпох и затухание весов, и задали параметр `save_total_limit`, чтобы сохранять только 3 контрольные точки во время обучения - это сделано потому, что даже "маленькая" версия mT5 использует около Гигабайта места на жестком диске, и мы можем сэкономить немного места, ограничив количество копий, которые мы сохраняем. +Здесь аргумент `predict_with_generate` был задан, чтобы указать, что мы должны генерировать резюме во время оценки, чтобы мы могли вычислить баллы ROUGE для каждой эпохи. Как обсуждалось в [Главе 1](../chapter1/1), декодер выполняет инференс, предсказывая токены по одному, и это реализуется методом модели `generate()`. Задание `predict_with_generate=True` указывает `Seq2SeqTrainer` на использование этого метода для оценки. Мы также скорректировали некоторые гиперпараметры по умолчанию, такие как скорость обучения, количество эпох и затухание весов, и задали параметр `save_total_limit`, чтобы сохранять только 3 контрольные точки во время обучения - это сделано потому, что даже "маленькая" версия mT5 использует около Гигабайта места на жестком диске, и мы можем сэкономить немного места, ограничив количество копий, которые мы сохраняем. Аргумент `push_to_hub=True` позволит нам отправить модель в Hub после обучения; вы найдете розиторий под своим профилем пользователя в месте, определенном `output_dir`. Обратите внимание, что вы можете указать имя розитория, в который хотите отправить модель, с помощью аргумента `hub_model_id` (в частности, вам нужно использовать этот аргумент, чтобы отправить модель в организацию). Например, когда мы отправили модель в организацию [`huggingface-course`](https://huggingface.co/huggingface-course), мы добавили `hub_model_id="huggingface-course/mt5-finetuned-amazon-en-es"` в `Seq2SeqTrainingArguments`. @@ -791,7 +791,7 @@ result = {key: value.mid.fmeasure * 100 for key, value in result.items()} ## Дообучение mT5 с 🤗 Accelerate[[fine-tuning-mt5-with-accelerate]] -Дообучение нашей модели с помощью 🤗 Accelerate очень похоже на пример с классификацией текста, который мы рассматривали в [Главе 3](../chapter3). Основные отличия заключаются в необходимости явной генерации резюме во время обучения и определении способа вычисления оценок ROUGE (напомним, что `Seq2SeqTrainer` позаботился о генерации за нас). Давайте посмотрим, как мы можем реализовать эти два требования в 🤗 Accelerate! +Дообучение нашей модели с помощью 🤗 Accelerate очень похоже на пример с классификацией текста, который мы рассматривали в [Главе 3](../chapter3/1). Основные отличия заключаются в необходимости явной генерации резюме во время обучения и определении способа вычисления оценок ROUGE (напомним, что `Seq2SeqTrainer` позаботился о генерации за нас). Давайте посмотрим, как мы можем реализовать эти два требования в 🤗 Accelerate! ### Подготовка всего к обучению[[preparing-everything-for-training]] @@ -845,7 +845,7 @@ model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( -🚨 Если вы обучаете на TPU, вам нужно будет перенести весь приведенный выше код в специальную функцию обучения. Подробнее смотрите в [Главе 3](../chapter3). +🚨 Если вы обучаете на TPU, вам нужно будет перенести весь приведенный выше код в специальную функцию обучения. Подробнее смотрите в [Главе 3](../chapter3/1). From 8f0e04407883ac91f35821ee5b3c31c5f74c108c Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Sat, 13 Jan 2024 14:10:08 +0300 Subject: [PATCH 356/502] I added myself to the Languages and translations table. --- .ipynb_checkpoints/README-checkpoint.md | 149 ++++++++++++++++++++++++ README.md | 2 +- 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 .ipynb_checkpoints/README-checkpoint.md diff --git a/.ipynb_checkpoints/README-checkpoint.md b/.ipynb_checkpoints/README-checkpoint.md new file mode 100644 index 000000000..d48e97773 --- /dev/null +++ b/.ipynb_checkpoints/README-checkpoint.md @@ -0,0 +1,149 @@ +# The Hugging Face Course + +This repo contains the content that's used to create the **[Hugging Face course](https://huggingface.co/course/chapter1/1)**. The course teaches you about applying Transformers to various tasks in natural language processing and beyond. Along the way, you'll learn how to use the [Hugging Face](https://huggingface.co/) ecosystem — [🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), and [🤗 Accelerate](https://github.com/huggingface/accelerate) — as well as the [Hugging Face Hub](https://huggingface.co/models). It's completely free and open-source! + +## 🌎 Languages and translations + +| Language | Source | Authors | +|:------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [English](https://huggingface.co/course/en/chapter1/1) | [`chapters/en`](https://github.com/huggingface/course/tree/main/chapters/en) | [@sgugger](https://github.com/sgugger), [@lewtun](https://github.com/lewtun), [@LysandreJik](https://github.com/LysandreJik), [@Rocketknight1](https://github.com/Rocketknight1), [@sashavor](https://github.com/sashavor), [@osanseviero](https://github.com/osanseviero), [@SaulLu](https://github.com/SaulLu), [@lvwerra](https://github.com/lvwerra) | +| [Bengali](https://huggingface.co/course/bn/chapter1/1) (WIP) | [`chapters/bn`](https://github.com/huggingface/course/tree/main/chapters/bn) | [@avishek-018](https://github.com/avishek-018), [@eNipu](https://github.com/eNipu) | +| [German](https://huggingface.co/course/de/chapter1/1) (WIP) | [`chapters/de`](https://github.com/huggingface/course/tree/main/chapters/de) | [@JesperDramsch](https://github.com/JesperDramsch), [@MarcusFra](https://github.com/MarcusFra), [@fabridamicelli](https://github.com/fabridamicelli) | +| [Spanish](https://huggingface.co/course/es/chapter1/1) (WIP) | [`chapters/es`](https://github.com/huggingface/course/tree/main/chapters/es) | [@camartinezbu](https://github.com/camartinezbu), [@munozariasjm](https://github.com/munozariasjm), [@fordaz](https://github.com/fordaz) | +| [Persian](https://huggingface.co/course/fa/chapter1/1) (WIP) | [`chapters/fa`](https://github.com/huggingface/course/tree/main/chapters/fa) | [@jowharshamshiri](https://github.com/jowharshamshiri), [@schoobani](https://github.com/schoobani) | +| [French](https://huggingface.co/course/fr/chapter1/1) | [`chapters/fr`](https://github.com/huggingface/course/tree/main/chapters/fr) | [@lbourdois](https://github.com/lbourdois), [@ChainYo](https://github.com/ChainYo), [@melaniedrevet](https://github.com/melaniedrevet), [@abdouaziz](https://github.com/abdouaziz) | +| [Gujarati](https://huggingface.co/course/gu/chapter1/1) (WIP) | [`chapters/gu`](https://github.com/huggingface/course/tree/main/chapters/gu) | [@pandyaved98](https://github.com/pandyaved98) | +| [Hebrew](https://huggingface.co/course/he/chapter1/1) (WIP) | [`chapters/he`](https://github.com/huggingface/course/tree/main/chapters/he) | [@omer-dor](https://github.com/omer-dor) | +| [Hindi](https://huggingface.co/course/hi/chapter1/1) (WIP) | [`chapters/hi`](https://github.com/huggingface/course/tree/main/chapters/hi) | [@pandyaved98](https://github.com/pandyaved98) | +| [Bahasa Indonesia](https://huggingface.co/course/id/chapter1/1) (WIP) | [`chapters/id`](https://github.com/huggingface/course/tree/main/chapters/id) | [@gstdl](https://github.com/gstdl) | +| [Italian](https://huggingface.co/course/it/chapter1/1) (WIP) | [`chapters/it`](https://github.com/huggingface/course/tree/main/chapters/it) | [@CaterinaBi](https://github.com/CaterinaBi), [@ClonedOne](https://github.com/ClonedOne), [@Nolanogenn](https://github.com/Nolanogenn), [@EdAbati](https://github.com/EdAbati), [@gdacciaro](https://github.com/gdacciaro) | +| [Japanese](https://huggingface.co/course/ja/chapter1/1) (WIP) | [`chapters/ja`](https://github.com/huggingface/course/tree/main/chapters/ja) | [@hiromu166](https://github.com/@hiromu166), [@younesbelkada](https://github.com/@younesbelkada), [@HiromuHota](https://github.com/@HiromuHota) | +| [Korean](https://huggingface.co/course/ko/chapter1/1) (WIP) | [`chapters/ko`](https://github.com/huggingface/course/tree/main/chapters/ko) | [@Doohae](https://github.com/Doohae), [@wonhyeongseo](https://github.com/wonhyeongseo), [@dlfrnaos19](https://github.com/dlfrnaos19), [@nsbg](https://github.com/nsbg) | +| [Portuguese](https://huggingface.co/course/pt/chapter1/1) (WIP) | [`chapters/pt`](https://github.com/huggingface/course/tree/main/chapters/pt) | [@johnnv1](https://github.com/johnnv1), [@victorescosta](https://github.com/victorescosta), [@LincolnVS](https://github.com/LincolnVS) | +| [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [`chapters/ru`](https://github.com/huggingface/course/tree/main/chapters/ru) | [@pdumin](https://github.com/pdumin), [@svv73](https://github.com/svv73), [@blademoon](https://github.com/blademoon) | +| [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [`chapters/th`](https://github.com/huggingface/course/tree/main/chapters/th) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156), [@ckingkan](https://github.com/ckingkan) | +| [Turkish](https://huggingface.co/course/tr/chapter1/1) (WIP) | [`chapters/tr`](https://github.com/huggingface/course/tree/main/chapters/tr) | [@tanersekmen](https://github.com/tanersekmen), [@mertbozkir](https://github.com/mertbozkir), [@ftarlaci](https://github.com/ftarlaci), [@akkasayaz](https://github.com/akkasayaz) | +| [Vietnamese](https://huggingface.co/course/vi/chapter1/1) | [`chapters/vi`](https://github.com/huggingface/course/tree/main/chapters/vi) | [@honghanhh](https://github.com/honghanhh) | +| [Chinese (simplified)](https://huggingface.co/course/zh-CN/chapter1/1) | [`chapters/zh-CN`](https://github.com/huggingface/course/tree/main/chapters/zh-CN) | [@zhlhyx](https://github.com/zhlhyx), [petrichor1122](https://github.com/petrichor1122), [@1375626371](https://github.com/1375626371) | +| [Chinese (traditional)](https://huggingface.co/course/zh-TW/chapter1/1) (WIP) | [`chapters/zh-TW`](https://github.com/huggingface/course/tree/main/chapters/zh-TW) | [@davidpeng86](https://github.com/davidpeng86) | + + +### Translating the course into your language + +As part of our mission to democratise machine learning, we'd love to have the course available in many more languages! Please follow the steps below if you'd like to help translate the course into your language 🙏. + +**🗞️ Open an issue** + +To get started, navigate to the [_Issues_](https://github.com/huggingface/course/issues) page of this repo and check if anyone else has opened an issue for your language. If not, open a new issue by selecting the _Translation template_ from the _New issue_ button. + +Once an issue is created, post a comment to indicate which chapters you'd like to work on and we'll add your name to the list. + +**🗣 Join our Discord** + +Since it can be difficult to discuss translation details quickly over GitHub issues, we have created dedicated channels for each language on our Discord server. If you'd like to join, follow the instructions at this channel 👉: [https://discord.gg/JfAtkvEtRb](https://discord.gg/JfAtkvEtRb) + +**🍴 Fork the repository** + +Next, you'll need to [fork this repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo). You can do this by clicking on the **Fork** button on the top-right corner of this repo's page. + +Once you've forked the repo, you'll want to get the files on your local machine for editing. You can do that by cloning the fork with Git as follows: + +```bash +git clone https://github.com/YOUR-USERNAME/course +``` + +**📋 Copy-paste the English files with a new language code** + +The course files are organised under a main directory: + +* [`chapters`](https://github.com/huggingface/course/tree/main/chapters): all the text and code snippets associated with the course. + +You'll only need to copy the files in the [`chapters/en`](https://github.com/huggingface/course/tree/main/chapters/en) directory, so first navigate to your fork of the repo and run the following: + +```bash +cd ~/path/to/course +cp -r chapters/en/CHAPTER-NUMBER chapters/LANG-ID/CHAPTER-NUMBER +``` + +Here, `CHAPTER-NUMBER` refers to the chapter you'd like to work on and `LANG-ID` should be one of the ISO 639-1 or ISO 639-2 language codes -- see [here](https://www.loc.gov/standards/iso639-2/php/code_list.php) for a handy table. + +**✍️ Start translating** + +Now comes the fun part - translating the text! The first thing we recommend is translating the part of the `_toctree.yml` file that corresponds to your chapter. This file is used to render the table of contents on the website and provide the links to the Colab notebooks. The only fields you should change are the `title`, ones -- for example, here are the parts of `_toctree.yml` that we'd translate for [Chapter 0](https://huggingface.co/course/chapter0/1?fw=pt): + +```yaml +- title: 0. Setup # Translate this! + sections: + - local: chapter0/1 # Do not change this! + title: Introduction # Translate this! +``` + +> 🚨 Make sure the `_toctree.yml` file only contains the sections that have been translated! Otherwise you won't be able to build the content on the website or locally (see below how). + + +Once you have translated the `_toctree.yml` file, you can start translating the [MDX](https://mdxjs.com/) files associated with your chapter. + +> 🙋 If the `_toctree.yml` file doesn't yet exist for your language, you can simply create one by copy-pasting from the English version and deleting the sections that aren't related to your chapter. Just make sure it exists in the `chapters/LANG-ID/` directory! + +**👷‍♂️ Build the course locally** + +Once you're happy with your changes, you can preview how they'll look by first installing the [`doc-builder`](https://github.com/huggingface/doc-builder) tool that we use for building all documentation at Hugging Face: + +``` +pip install hf-doc-builder +``` + +``` +doc-builder preview course ../course/chapters/LANG-ID --not_python_module +``` + +**`preview` command does not work with Windows. + +This will build and render the course on [http://localhost:3000/](http://localhost:3000/). Although the content looks much nicer on the Hugging Face website, this step will still allow you to check that everything is formatted correctly. + +**🚀 Submit a pull request** + +If the translations look good locally, the final step is to prepare the content for a pull request. Here, the first think to check is that the files are formatted correctly. For that you can run: + +``` +pip install -r requirements.txt +make style +``` + +Once that's run, commit any changes, open a pull request, and tag [@lewtun](https://github.com/lewtun) for a review. Congratulations, you've now completed your first translation 🥳! + +> 🚨 To build the course on the website, double-check your language code exists in `languages` field of the `build_documentation.yml` and `build_pr_documentation.yml` files in the `.github` folder. If not, just add them in their alphabetical order. + +## 📔 Jupyter notebooks + +The Jupyter notebooks containing all the code from the course are hosted on the [`huggingface/notebooks`](https://github.com/huggingface/notebooks) repo. If you wish to generate them locally, first install the required dependencies: + +```bash +python -m pip install -r requirements.txt +``` + +Then run the following script: + +```bash +python utils/generate_notebooks.py --output_dir nbs +``` + +This script extracts all the code snippets from the chapters and stores them as notebooks in the `nbs` folder (which is ignored by Git by default). + +## ✍️ Contributing a new chapter + +> Note: we are not currently accepting community contributions for new chapters. These instructions are for the Hugging Face authors. + +Adding a new chapter to the course is quite simple: + +1. Create a new directory under `chapters/en/chapterX`, where `chapterX` is the chapter you'd like to add. +2. Add numbered MDX files `sectionX.mdx` for each section. If you need to include images, place them in the [huggingface-course/documentation-images](https://huggingface.co/datasets/huggingface-course/documentation-images) repository and use the [HTML Images Syntax](https://www.w3schools.com/html/html_images.asp) with the path `https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/{langY}/{chapterX}/{your-image.png}`. +3. Update the `_toctree.yml` file to include your chapter sections -- this information will render the table of contents on the website. If your section involves both the PyTorch and TensorFlow APIs of `transformers`, make sure you include links to both Colabs in the `colab` field. + +If you get stuck, check out one of the existing chapters -- this will often show you the expected syntax. + +Once you are happy with the content, open a pull request and tag [@lewtun](https://github.com/lewtun) for a review. We recommend adding the first chapter draft as a single pull request -- the team will then provide feedback internally to iterate on the content 🤗! + +## 🙌 Acknowledgements + +The structure of this repo and README are inspired by the wonderful [Advanced NLP with spaCy](https://github.com/ines/spacy-course) course. diff --git a/README.md b/README.md index b41485d8d..d48e97773 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This repo contains the content that's used to create the **[Hugging Face course] | [Japanese](https://huggingface.co/course/ja/chapter1/1) (WIP) | [`chapters/ja`](https://github.com/huggingface/course/tree/main/chapters/ja) | [@hiromu166](https://github.com/@hiromu166), [@younesbelkada](https://github.com/@younesbelkada), [@HiromuHota](https://github.com/@HiromuHota) | | [Korean](https://huggingface.co/course/ko/chapter1/1) (WIP) | [`chapters/ko`](https://github.com/huggingface/course/tree/main/chapters/ko) | [@Doohae](https://github.com/Doohae), [@wonhyeongseo](https://github.com/wonhyeongseo), [@dlfrnaos19](https://github.com/dlfrnaos19), [@nsbg](https://github.com/nsbg) | | [Portuguese](https://huggingface.co/course/pt/chapter1/1) (WIP) | [`chapters/pt`](https://github.com/huggingface/course/tree/main/chapters/pt) | [@johnnv1](https://github.com/johnnv1), [@victorescosta](https://github.com/victorescosta), [@LincolnVS](https://github.com/LincolnVS) | -| [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [`chapters/ru`](https://github.com/huggingface/course/tree/main/chapters/ru) | [@pdumin](https://github.com/pdumin), [@svv73](https://github.com/svv73) | +| [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [`chapters/ru`](https://github.com/huggingface/course/tree/main/chapters/ru) | [@pdumin](https://github.com/pdumin), [@svv73](https://github.com/svv73), [@blademoon](https://github.com/blademoon) | | [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [`chapters/th`](https://github.com/huggingface/course/tree/main/chapters/th) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156), [@ckingkan](https://github.com/ckingkan) | | [Turkish](https://huggingface.co/course/tr/chapter1/1) (WIP) | [`chapters/tr`](https://github.com/huggingface/course/tree/main/chapters/tr) | [@tanersekmen](https://github.com/tanersekmen), [@mertbozkir](https://github.com/mertbozkir), [@ftarlaci](https://github.com/ftarlaci), [@akkasayaz](https://github.com/akkasayaz) | | [Vietnamese](https://huggingface.co/course/vi/chapter1/1) | [`chapters/vi`](https://github.com/huggingface/course/tree/main/chapters/vi) | [@honghanhh](https://github.com/honghanhh) | From 5da07e8f83568ec460034cdde4ccdda929399f1d Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Sat, 13 Jan 2024 14:13:36 +0300 Subject: [PATCH 357/502] Deleted unnecessary folder automatically created by JupyterLab. --- .ipynb_checkpoints/README-checkpoint.md | 149 ------------------------ 1 file changed, 149 deletions(-) delete mode 100644 .ipynb_checkpoints/README-checkpoint.md diff --git a/.ipynb_checkpoints/README-checkpoint.md b/.ipynb_checkpoints/README-checkpoint.md deleted file mode 100644 index d48e97773..000000000 --- a/.ipynb_checkpoints/README-checkpoint.md +++ /dev/null @@ -1,149 +0,0 @@ -# The Hugging Face Course - -This repo contains the content that's used to create the **[Hugging Face course](https://huggingface.co/course/chapter1/1)**. The course teaches you about applying Transformers to various tasks in natural language processing and beyond. Along the way, you'll learn how to use the [Hugging Face](https://huggingface.co/) ecosystem — [🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), and [🤗 Accelerate](https://github.com/huggingface/accelerate) — as well as the [Hugging Face Hub](https://huggingface.co/models). It's completely free and open-source! - -## 🌎 Languages and translations - -| Language | Source | Authors | -|:------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [English](https://huggingface.co/course/en/chapter1/1) | [`chapters/en`](https://github.com/huggingface/course/tree/main/chapters/en) | [@sgugger](https://github.com/sgugger), [@lewtun](https://github.com/lewtun), [@LysandreJik](https://github.com/LysandreJik), [@Rocketknight1](https://github.com/Rocketknight1), [@sashavor](https://github.com/sashavor), [@osanseviero](https://github.com/osanseviero), [@SaulLu](https://github.com/SaulLu), [@lvwerra](https://github.com/lvwerra) | -| [Bengali](https://huggingface.co/course/bn/chapter1/1) (WIP) | [`chapters/bn`](https://github.com/huggingface/course/tree/main/chapters/bn) | [@avishek-018](https://github.com/avishek-018), [@eNipu](https://github.com/eNipu) | -| [German](https://huggingface.co/course/de/chapter1/1) (WIP) | [`chapters/de`](https://github.com/huggingface/course/tree/main/chapters/de) | [@JesperDramsch](https://github.com/JesperDramsch), [@MarcusFra](https://github.com/MarcusFra), [@fabridamicelli](https://github.com/fabridamicelli) | -| [Spanish](https://huggingface.co/course/es/chapter1/1) (WIP) | [`chapters/es`](https://github.com/huggingface/course/tree/main/chapters/es) | [@camartinezbu](https://github.com/camartinezbu), [@munozariasjm](https://github.com/munozariasjm), [@fordaz](https://github.com/fordaz) | -| [Persian](https://huggingface.co/course/fa/chapter1/1) (WIP) | [`chapters/fa`](https://github.com/huggingface/course/tree/main/chapters/fa) | [@jowharshamshiri](https://github.com/jowharshamshiri), [@schoobani](https://github.com/schoobani) | -| [French](https://huggingface.co/course/fr/chapter1/1) | [`chapters/fr`](https://github.com/huggingface/course/tree/main/chapters/fr) | [@lbourdois](https://github.com/lbourdois), [@ChainYo](https://github.com/ChainYo), [@melaniedrevet](https://github.com/melaniedrevet), [@abdouaziz](https://github.com/abdouaziz) | -| [Gujarati](https://huggingface.co/course/gu/chapter1/1) (WIP) | [`chapters/gu`](https://github.com/huggingface/course/tree/main/chapters/gu) | [@pandyaved98](https://github.com/pandyaved98) | -| [Hebrew](https://huggingface.co/course/he/chapter1/1) (WIP) | [`chapters/he`](https://github.com/huggingface/course/tree/main/chapters/he) | [@omer-dor](https://github.com/omer-dor) | -| [Hindi](https://huggingface.co/course/hi/chapter1/1) (WIP) | [`chapters/hi`](https://github.com/huggingface/course/tree/main/chapters/hi) | [@pandyaved98](https://github.com/pandyaved98) | -| [Bahasa Indonesia](https://huggingface.co/course/id/chapter1/1) (WIP) | [`chapters/id`](https://github.com/huggingface/course/tree/main/chapters/id) | [@gstdl](https://github.com/gstdl) | -| [Italian](https://huggingface.co/course/it/chapter1/1) (WIP) | [`chapters/it`](https://github.com/huggingface/course/tree/main/chapters/it) | [@CaterinaBi](https://github.com/CaterinaBi), [@ClonedOne](https://github.com/ClonedOne), [@Nolanogenn](https://github.com/Nolanogenn), [@EdAbati](https://github.com/EdAbati), [@gdacciaro](https://github.com/gdacciaro) | -| [Japanese](https://huggingface.co/course/ja/chapter1/1) (WIP) | [`chapters/ja`](https://github.com/huggingface/course/tree/main/chapters/ja) | [@hiromu166](https://github.com/@hiromu166), [@younesbelkada](https://github.com/@younesbelkada), [@HiromuHota](https://github.com/@HiromuHota) | -| [Korean](https://huggingface.co/course/ko/chapter1/1) (WIP) | [`chapters/ko`](https://github.com/huggingface/course/tree/main/chapters/ko) | [@Doohae](https://github.com/Doohae), [@wonhyeongseo](https://github.com/wonhyeongseo), [@dlfrnaos19](https://github.com/dlfrnaos19), [@nsbg](https://github.com/nsbg) | -| [Portuguese](https://huggingface.co/course/pt/chapter1/1) (WIP) | [`chapters/pt`](https://github.com/huggingface/course/tree/main/chapters/pt) | [@johnnv1](https://github.com/johnnv1), [@victorescosta](https://github.com/victorescosta), [@LincolnVS](https://github.com/LincolnVS) | -| [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [`chapters/ru`](https://github.com/huggingface/course/tree/main/chapters/ru) | [@pdumin](https://github.com/pdumin), [@svv73](https://github.com/svv73), [@blademoon](https://github.com/blademoon) | -| [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [`chapters/th`](https://github.com/huggingface/course/tree/main/chapters/th) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156), [@ckingkan](https://github.com/ckingkan) | -| [Turkish](https://huggingface.co/course/tr/chapter1/1) (WIP) | [`chapters/tr`](https://github.com/huggingface/course/tree/main/chapters/tr) | [@tanersekmen](https://github.com/tanersekmen), [@mertbozkir](https://github.com/mertbozkir), [@ftarlaci](https://github.com/ftarlaci), [@akkasayaz](https://github.com/akkasayaz) | -| [Vietnamese](https://huggingface.co/course/vi/chapter1/1) | [`chapters/vi`](https://github.com/huggingface/course/tree/main/chapters/vi) | [@honghanhh](https://github.com/honghanhh) | -| [Chinese (simplified)](https://huggingface.co/course/zh-CN/chapter1/1) | [`chapters/zh-CN`](https://github.com/huggingface/course/tree/main/chapters/zh-CN) | [@zhlhyx](https://github.com/zhlhyx), [petrichor1122](https://github.com/petrichor1122), [@1375626371](https://github.com/1375626371) | -| [Chinese (traditional)](https://huggingface.co/course/zh-TW/chapter1/1) (WIP) | [`chapters/zh-TW`](https://github.com/huggingface/course/tree/main/chapters/zh-TW) | [@davidpeng86](https://github.com/davidpeng86) | - - -### Translating the course into your language - -As part of our mission to democratise machine learning, we'd love to have the course available in many more languages! Please follow the steps below if you'd like to help translate the course into your language 🙏. - -**🗞️ Open an issue** - -To get started, navigate to the [_Issues_](https://github.com/huggingface/course/issues) page of this repo and check if anyone else has opened an issue for your language. If not, open a new issue by selecting the _Translation template_ from the _New issue_ button. - -Once an issue is created, post a comment to indicate which chapters you'd like to work on and we'll add your name to the list. - -**🗣 Join our Discord** - -Since it can be difficult to discuss translation details quickly over GitHub issues, we have created dedicated channels for each language on our Discord server. If you'd like to join, follow the instructions at this channel 👉: [https://discord.gg/JfAtkvEtRb](https://discord.gg/JfAtkvEtRb) - -**🍴 Fork the repository** - -Next, you'll need to [fork this repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo). You can do this by clicking on the **Fork** button on the top-right corner of this repo's page. - -Once you've forked the repo, you'll want to get the files on your local machine for editing. You can do that by cloning the fork with Git as follows: - -```bash -git clone https://github.com/YOUR-USERNAME/course -``` - -**📋 Copy-paste the English files with a new language code** - -The course files are organised under a main directory: - -* [`chapters`](https://github.com/huggingface/course/tree/main/chapters): all the text and code snippets associated with the course. - -You'll only need to copy the files in the [`chapters/en`](https://github.com/huggingface/course/tree/main/chapters/en) directory, so first navigate to your fork of the repo and run the following: - -```bash -cd ~/path/to/course -cp -r chapters/en/CHAPTER-NUMBER chapters/LANG-ID/CHAPTER-NUMBER -``` - -Here, `CHAPTER-NUMBER` refers to the chapter you'd like to work on and `LANG-ID` should be one of the ISO 639-1 or ISO 639-2 language codes -- see [here](https://www.loc.gov/standards/iso639-2/php/code_list.php) for a handy table. - -**✍️ Start translating** - -Now comes the fun part - translating the text! The first thing we recommend is translating the part of the `_toctree.yml` file that corresponds to your chapter. This file is used to render the table of contents on the website and provide the links to the Colab notebooks. The only fields you should change are the `title`, ones -- for example, here are the parts of `_toctree.yml` that we'd translate for [Chapter 0](https://huggingface.co/course/chapter0/1?fw=pt): - -```yaml -- title: 0. Setup # Translate this! - sections: - - local: chapter0/1 # Do not change this! - title: Introduction # Translate this! -``` - -> 🚨 Make sure the `_toctree.yml` file only contains the sections that have been translated! Otherwise you won't be able to build the content on the website or locally (see below how). - - -Once you have translated the `_toctree.yml` file, you can start translating the [MDX](https://mdxjs.com/) files associated with your chapter. - -> 🙋 If the `_toctree.yml` file doesn't yet exist for your language, you can simply create one by copy-pasting from the English version and deleting the sections that aren't related to your chapter. Just make sure it exists in the `chapters/LANG-ID/` directory! - -**👷‍♂️ Build the course locally** - -Once you're happy with your changes, you can preview how they'll look by first installing the [`doc-builder`](https://github.com/huggingface/doc-builder) tool that we use for building all documentation at Hugging Face: - -``` -pip install hf-doc-builder -``` - -``` -doc-builder preview course ../course/chapters/LANG-ID --not_python_module -``` - -**`preview` command does not work with Windows. - -This will build and render the course on [http://localhost:3000/](http://localhost:3000/). Although the content looks much nicer on the Hugging Face website, this step will still allow you to check that everything is formatted correctly. - -**🚀 Submit a pull request** - -If the translations look good locally, the final step is to prepare the content for a pull request. Here, the first think to check is that the files are formatted correctly. For that you can run: - -``` -pip install -r requirements.txt -make style -``` - -Once that's run, commit any changes, open a pull request, and tag [@lewtun](https://github.com/lewtun) for a review. Congratulations, you've now completed your first translation 🥳! - -> 🚨 To build the course on the website, double-check your language code exists in `languages` field of the `build_documentation.yml` and `build_pr_documentation.yml` files in the `.github` folder. If not, just add them in their alphabetical order. - -## 📔 Jupyter notebooks - -The Jupyter notebooks containing all the code from the course are hosted on the [`huggingface/notebooks`](https://github.com/huggingface/notebooks) repo. If you wish to generate them locally, first install the required dependencies: - -```bash -python -m pip install -r requirements.txt -``` - -Then run the following script: - -```bash -python utils/generate_notebooks.py --output_dir nbs -``` - -This script extracts all the code snippets from the chapters and stores them as notebooks in the `nbs` folder (which is ignored by Git by default). - -## ✍️ Contributing a new chapter - -> Note: we are not currently accepting community contributions for new chapters. These instructions are for the Hugging Face authors. - -Adding a new chapter to the course is quite simple: - -1. Create a new directory under `chapters/en/chapterX`, where `chapterX` is the chapter you'd like to add. -2. Add numbered MDX files `sectionX.mdx` for each section. If you need to include images, place them in the [huggingface-course/documentation-images](https://huggingface.co/datasets/huggingface-course/documentation-images) repository and use the [HTML Images Syntax](https://www.w3schools.com/html/html_images.asp) with the path `https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/{langY}/{chapterX}/{your-image.png}`. -3. Update the `_toctree.yml` file to include your chapter sections -- this information will render the table of contents on the website. If your section involves both the PyTorch and TensorFlow APIs of `transformers`, make sure you include links to both Colabs in the `colab` field. - -If you get stuck, check out one of the existing chapters -- this will often show you the expected syntax. - -Once you are happy with the content, open a pull request and tag [@lewtun](https://github.com/lewtun) for a review. We recommend adding the first chapter draft as a single pull request -- the team will then provide feedback internally to iterate on the content 🤗! - -## 🙌 Acknowledgements - -The structure of this repo and README are inspired by the wonderful [Advanced NLP with spaCy](https://github.com/ines/spacy-course) course. From 496698046570df246176c394842f6c76d17d1603 Mon Sep 17 00:00:00 2001 From: mariosasko Date: Tue, 16 Jan 2024 18:08:08 +0100 Subject: [PATCH 358/502] Fix links to HF docs --- chapters/de/chapter1/3.mdx | 2 +- chapters/de/chapter1/5.mdx | 10 +++++----- chapters/de/chapter1/6.mdx | 6 +++--- chapters/de/chapter1/7.mdx | 8 ++++---- chapters/de/chapter3/2.mdx | 2 +- chapters/de/chapter4/2.mdx | 4 ++-- chapters/en/chapter1/3.mdx | 2 +- chapters/en/chapter1/6.mdx | 6 +++--- chapters/en/chapter1/7.mdx | 8 ++++---- chapters/en/chapter3/2.mdx | 2 +- chapters/en/chapter4/2.mdx | 4 ++-- chapters/en/chapter4/3.mdx | 2 +- chapters/en/chapter5/2.mdx | 4 ++-- chapters/en/chapter5/3.mdx | 4 ++-- chapters/en/chapter5/4.mdx | 2 +- chapters/en/chapter5/5.mdx | 2 +- chapters/en/chapter5/6.mdx | 2 +- chapters/en/chapter6/8.mdx | 16 ++++++++-------- chapters/es/chapter3/2.mdx | 2 +- chapters/es/chapter5/2.mdx | 4 ++-- chapters/es/chapter5/3.mdx | 4 ++-- chapters/es/chapter5/4.mdx | 2 +- chapters/es/chapter5/5.mdx | 2 +- chapters/es/chapter5/6.mdx | 2 +- chapters/es/chapter6/8.mdx | 16 ++++++++-------- chapters/fa/chapter3/2.mdx | 2 +- chapters/fr/chapter3/2.mdx | 2 +- chapters/fr/chapter5/2.mdx | 4 ++-- chapters/fr/chapter5/3.mdx | 4 ++-- chapters/fr/chapter5/4.mdx | 2 +- chapters/fr/chapter5/5.mdx | 2 +- chapters/fr/chapter5/6.mdx | 2 +- chapters/fr/chapter6/8.mdx | 16 ++++++++-------- chapters/hi/chapter3/2.mdx | 2 +- chapters/it/chapter3/2.mdx | 2 +- chapters/it/chapter5/2.mdx | 4 ++-- chapters/it/chapter5/3.mdx | 4 ++-- chapters/it/chapter5/4.mdx | 2 +- chapters/it/chapter5/5.mdx | 2 +- chapters/it/chapter5/6.mdx | 2 +- chapters/ko/chapter5/2.mdx | 2 +- chapters/pt/chapter5/2.mdx | 4 ++-- chapters/pt/chapter5/3.mdx | 4 ++-- chapters/pt/chapter5/4.mdx | 2 +- chapters/pt/chapter5/5.mdx | 2 +- chapters/pt/chapter5/6.mdx | 2 +- chapters/ru/chapter3/2.mdx | 2 +- chapters/ru/chapter5/2.mdx | 4 ++-- chapters/ru/chapter5/3.mdx | 8 ++++---- chapters/ru/chapter5/4.mdx | 2 +- chapters/ru/chapter5/6.mdx | 2 +- chapters/ru/chapter6/8.mdx | 16 ++++++++-------- chapters/th/chapter3/2.mdx | 2 +- chapters/th/chapter6/8.mdx | 16 ++++++++-------- chapters/vi/chapter3/2.mdx | 2 +- chapters/vi/chapter5/2.mdx | 4 ++-- chapters/vi/chapter5/3.mdx | 4 ++-- chapters/vi/chapter5/4.mdx | 2 +- chapters/vi/chapter5/5.mdx | 2 +- chapters/vi/chapter5/6.mdx | 2 +- chapters/vi/chapter6/8.mdx | 16 ++++++++-------- chapters/zh-CN/chapter3/2.mdx | 2 +- chapters/zh-CN/chapter5/2.mdx | 2 +- chapters/zh-CN/chapter5/4.mdx | 2 +- chapters/zh-CN/chapter5/5.mdx | 2 +- chapters/zh-CN/chapter5/6.mdx | 2 +- chapters/zh-CN/chapter6/8.mdx | 16 ++++++++-------- chapters/zh-TW/chapter3/2.mdx | 2 +- chapters/zh-TW/chapter5/2.mdx | 2 +- chapters/zh-TW/chapter5/4.mdx | 2 +- chapters/zh-TW/chapter5/5.mdx | 2 +- chapters/zh-TW/chapter5/6.mdx | 2 +- chapters/zh-TW/chapter6/8.mdx | 16 ++++++++-------- 73 files changed, 161 insertions(+), 161 deletions(-) diff --git a/chapters/de/chapter1/3.mdx b/chapters/de/chapter1/3.mdx index c58ba5d64..7db9cb48a 100644 --- a/chapters/de/chapter1/3.mdx +++ b/chapters/de/chapter1/3.mdx @@ -68,7 +68,7 @@ Wenn du einen Text an eine Pipeline übergibst, gibt es drei wichtige Schritte: 3. Die Vorhersagen des Modells werden so nachverarbeitet, sodass du sie nutzen kannst. -Einige der derzeit [verfügbaren Pipelines](https://huggingface.co/transformers/main_classes/pipelines.html) sind: +Einige der derzeit [verfügbaren Pipelines](https://huggingface.co/transformers/main_classes/pipelines) sind: - `feature-extraction` (Vektordarstellung eines Textes erhalten) - `fill-mask` diff --git a/chapters/de/chapter1/5.mdx b/chapters/de/chapter1/5.mdx index 502ab5d89..5f1b68f53 100644 --- a/chapters/de/chapter1/5.mdx +++ b/chapters/de/chapter1/5.mdx @@ -15,8 +15,8 @@ Rein Encoder-basierte Modelle eignen sich am besten für Aufgaben, die ein Verst Zu dieser Modellfamilie gehören unter anderem: -- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html) -- [BERT](https://huggingface.co/transformers/model_doc/bert.html) -- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) -- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) -- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) +- [ALBERT](https://huggingface.co/transformers/model_doc/albert) +- [BERT](https://huggingface.co/transformers/model_doc/bert) +- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert) +- [ELECTRA](https://huggingface.co/transformers/model_doc/electra) +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta) diff --git a/chapters/de/chapter1/6.mdx b/chapters/de/chapter1/6.mdx index 3e0e5768a..948c010a2 100644 --- a/chapters/de/chapter1/6.mdx +++ b/chapters/de/chapter1/6.mdx @@ -15,7 +15,7 @@ Diese Modelle sind am besten für Aufgaben geeignet, bei denen es um die Generie Zu dieser Modellfamilie gehören unter anderem: -- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) +- [CTRL](https://huggingface.co/transformers/model_doc/ctrl) - [GPT](https://huggingface.co/docs/transformers/model_doc/openai-gpt) -- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) -- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) +- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2) +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl) diff --git a/chapters/de/chapter1/7.mdx b/chapters/de/chapter1/7.mdx index 0ce8561cf..4bf04585f 100644 --- a/chapters/de/chapter1/7.mdx +++ b/chapters/de/chapter1/7.mdx @@ -15,7 +15,7 @@ Sequence-to-Sequence-Modelle eignen sich am besten für Aufgaben, bei denen es d Vertreter dieser Modellfamilie sind u. a.: -- [BART](https://huggingface.co/transformers/model_doc/bart.html) -- [mBART](https://huggingface.co/transformers/model_doc/mbart.html) -- [Marian](https://huggingface.co/transformers/model_doc/marian.html) -- [T5](https://huggingface.co/transformers/model_doc/t5.html) +- [BART](https://huggingface.co/transformers/model_doc/bart) +- [mBART](https://huggingface.co/transformers/model_doc/mbart) +- [Marian](https://huggingface.co/transformers/model_doc/marian) +- [T5](https://huggingface.co/transformers/model_doc/t5) diff --git a/chapters/de/chapter3/2.mdx b/chapters/de/chapter3/2.mdx index 50a183761..12c7f699a 100644 --- a/chapters/de/chapter3/2.mdx +++ b/chapters/de/chapter3/2.mdx @@ -235,7 +235,7 @@ tokenized_dataset = tokenizer( Das funktioniert gut, hat aber den Nachteil, dass ein Dictionary zurückgegeben wird (mit unseren Schlüsselwörtern `input_ids`, `attention_mask` und `token_type_ids` und Werten aus Listen von Listen). Es funktioniert auch nur, wenn du genügend RAM hast, um den gesamten Datensatz während der Tokenisierung zu im RAM zwischen zu speichern (während die Datensätze aus der Bibliothek 🤗 Datasets [Apache Arrow](https://arrow.apache.org/) Dateien sind, die auf der Festplatte gespeichert sind, sodass nur die gewünschten Samples im RAM geladen sind). -Um die Daten als Datensatz zu speichern, verwenden wir die Methode [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map). Dies gewährt uns zusätzliche Flexibilität, wenn wir zusätzliche Vorverarbeitung als nur die Tokenisierung benötigen. Die `map()`-Methode funktioniert, indem sie eine Funktion auf jedes Element des Datensatzes anwendet, also definieren wir eine Funktion, die unsere Inputs tokenisiert: +Um die Daten als Datensatz zu speichern, verwenden wir die Methode [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map). Dies gewährt uns zusätzliche Flexibilität, wenn wir zusätzliche Vorverarbeitung als nur die Tokenisierung benötigen. Die `map()`-Methode funktioniert, indem sie eine Funktion auf jedes Element des Datensatzes anwendet, also definieren wir eine Funktion, die unsere Inputs tokenisiert: ```py def tokenize_function(example): diff --git a/chapters/de/chapter4/2.mdx b/chapters/de/chapter4/2.mdx index 0b20fe1d9..a445d6f60 100644 --- a/chapters/de/chapter4/2.mdx +++ b/chapters/de/chapter4/2.mdx @@ -65,7 +65,7 @@ tokenizer = CamembertTokenizer.from_pretrained("camembert-base") model = CamembertForMaskedLM.from_pretrained("camembert-base") ``` -Dennoch empfehlen wir, dass man die [`Auto*` classes](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) stattdessen benutzt, da diese architekturunabhängig sind. Das vorherige Code-Beispiel gilt nur für Checkpoints, die in die CamemBERT Architektur zu laden sind, aber mit den `Auto*` Klassen kann man Checkpoints ziemlich einfach tauschen: +Dennoch empfehlen wir, dass man die [`Auto*` classes](https://huggingface.co/transformers/model_doc/auto?highlight=auto#auto-classes) stattdessen benutzt, da diese architekturunabhängig sind. Das vorherige Code-Beispiel gilt nur für Checkpoints, die in die CamemBERT Architektur zu laden sind, aber mit den `Auto*` Klassen kann man Checkpoints ziemlich einfach tauschen: ```py from transformers import AutoTokenizer, AutoModelForMaskedLM @@ -81,7 +81,7 @@ tokenizer = CamembertTokenizer.from_pretrained("camembert-base") model = TFCamembertForMaskedLM.from_pretrained("camembert-base") ``` -Hier empfehlen wir auch, dass man stattdessen die [`TFAuto*` classes](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) benutzt, da diese architekturunabhängig sind. Das vorherige Code-Beispiel gilt nur für Checkpoints, die in die CamemBERT Architektur zu laden sind, aber mit den `TFAuto*` Klassen kann man Checkpoints einfach tauschen: +Hier empfehlen wir auch, dass man stattdessen die [`TFAuto*` classes](https://huggingface.co/transformers/model_doc/auto?highlight=auto#auto-classes) benutzt, da diese architekturunabhängig sind. Das vorherige Code-Beispiel gilt nur für Checkpoints, die in die CamemBERT Architektur zu laden sind, aber mit den `TFAuto*` Klassen kann man Checkpoints einfach tauschen: ```py from transformers import AutoTokenizer, TFAutoModelForMaskedLM diff --git a/chapters/en/chapter1/3.mdx b/chapters/en/chapter1/3.mdx index 4ff8b0d00..a31638e9e 100644 --- a/chapters/en/chapter1/3.mdx +++ b/chapters/en/chapter1/3.mdx @@ -68,7 +68,7 @@ There are three main steps involved when you pass some text to a pipeline: 3. The predictions of the model are post-processed, so you can make sense of them. -Some of the currently [available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html) are: +Some of the currently [available pipelines](https://huggingface.co/transformers/main_classes/pipelines) are: - `feature-extraction` (get the vector representation of a text) - `fill-mask` diff --git a/chapters/en/chapter1/6.mdx b/chapters/en/chapter1/6.mdx index 396d79bd3..b0f4ba09c 100644 --- a/chapters/en/chapter1/6.mdx +++ b/chapters/en/chapter1/6.mdx @@ -15,7 +15,7 @@ These models are best suited for tasks involving text generation. Representatives of this family of models include: -- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) +- [CTRL](https://huggingface.co/transformers/model_doc/ctrl) - [GPT](https://huggingface.co/docs/transformers/model_doc/openai-gpt) -- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) -- [Transformer XL](https://huggingface.co/transformers/model_doc/transfo-xl.html) +- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2) +- [Transformer XL](https://huggingface.co/transformers/model_doc/transfo-xl) diff --git a/chapters/en/chapter1/7.mdx b/chapters/en/chapter1/7.mdx index 23599e26f..e39c5ca8e 100644 --- a/chapters/en/chapter1/7.mdx +++ b/chapters/en/chapter1/7.mdx @@ -15,7 +15,7 @@ Sequence-to-sequence models are best suited for tasks revolving around generatin Representatives of this family of models include: -- [BART](https://huggingface.co/transformers/model_doc/bart.html) -- [mBART](https://huggingface.co/transformers/model_doc/mbart.html) -- [Marian](https://huggingface.co/transformers/model_doc/marian.html) -- [T5](https://huggingface.co/transformers/model_doc/t5.html) +- [BART](https://huggingface.co/transformers/model_doc/bart) +- [mBART](https://huggingface.co/transformers/model_doc/mbart) +- [Marian](https://huggingface.co/transformers/model_doc/marian) +- [T5](https://huggingface.co/transformers/model_doc/t5) diff --git a/chapters/en/chapter3/2.mdx b/chapters/en/chapter3/2.mdx index f64747dac..ebf464fc3 100644 --- a/chapters/en/chapter3/2.mdx +++ b/chapters/en/chapter3/2.mdx @@ -235,7 +235,7 @@ tokenized_dataset = tokenizer( This works well, but it has the disadvantage of returning a dictionary (with our keys, `input_ids`, `attention_mask`, and `token_type_ids`, and values that are lists of lists). It will also only work if you have enough RAM to store your whole dataset during the tokenization (whereas the datasets from the 🤗 Datasets library are [Apache Arrow](https://arrow.apache.org/) files stored on the disk, so you only keep the samples you ask for loaded in memory). -To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: +To keep the data as a dataset, we will use the [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) method. This also allows us some extra flexibility, if we need more preprocessing done than just tokenization. The `map()` method works by applying a function on each element of the dataset, so let's define a function that tokenizes our inputs: ```py def tokenize_function(example): diff --git a/chapters/en/chapter4/2.mdx b/chapters/en/chapter4/2.mdx index 8b110ec7b..0bd50669b 100644 --- a/chapters/en/chapter4/2.mdx +++ b/chapters/en/chapter4/2.mdx @@ -65,7 +65,7 @@ tokenizer = CamembertTokenizer.from_pretrained("camembert-base") model = CamembertForMaskedLM.from_pretrained("camembert-base") ``` -However, we recommend using the [`Auto*` classes](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) instead, as these are by design architecture-agnostic. While the previous code sample limits users to checkpoints loadable in the CamemBERT architecture, using the `Auto*` classes makes switching checkpoints simple: +However, we recommend using the [`Auto*` classes](https://huggingface.co/transformers/model_doc/auto?highlight=auto#auto-classes) instead, as these are by design architecture-agnostic. While the previous code sample limits users to checkpoints loadable in the CamemBERT architecture, using the `Auto*` classes makes switching checkpoints simple: ```py from transformers import AutoTokenizer, AutoModelForMaskedLM @@ -81,7 +81,7 @@ tokenizer = CamembertTokenizer.from_pretrained("camembert-base") model = TFCamembertForMaskedLM.from_pretrained("camembert-base") ``` -However, we recommend using the [`TFAuto*` classes](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) instead, as these are by design architecture-agnostic. While the previous code sample limits users to checkpoints loadable in the CamemBERT architecture, using the `TFAuto*` classes makes switching checkpoints simple: +However, we recommend using the [`TFAuto*` classes](https://huggingface.co/transformers/model_doc/auto?highlight=auto#auto-classes) instead, as these are by design architecture-agnostic. While the previous code sample limits users to checkpoints loadable in the CamemBERT architecture, using the `TFAuto*` classes makes switching checkpoints simple: ```py from transformers import AutoTokenizer, TFAutoModelForMaskedLM diff --git a/chapters/en/chapter4/3.mdx b/chapters/en/chapter4/3.mdx index 6b27777f4..9de3fb1d8 100644 --- a/chapters/en/chapter4/3.mdx +++ b/chapters/en/chapter4/3.mdx @@ -178,7 +178,7 @@ Click on the "Files and versions" tab, and you should see the files visible in t -As you've seen, the `push_to_hub()` method accepts several arguments, making it possible to upload to a specific repository or organization namespace, or to use a different API token. We recommend you take a look at the method specification available directly in the [🤗 Transformers documentation](https://huggingface.co/transformers/model_sharing.html) to get an idea of what is possible. +As you've seen, the `push_to_hub()` method accepts several arguments, making it possible to upload to a specific repository or organization namespace, or to use a different API token. We recommend you take a look at the method specification available directly in the [🤗 Transformers documentation](https://huggingface.co/transformers/model_sharing) to get an idea of what is possible. The `push_to_hub()` method is backed by the [`huggingface_hub`](https://github.com/huggingface/huggingface_hub) Python package, which offers a direct API to the Hugging Face Hub. It's integrated within 🤗 Transformers and several other machine learning libraries, like [`allenlp`](https://github.com/allenai/allennlp). Although we focus on the 🤗 Transformers integration in this chapter, integrating it into your own code or library is simple. diff --git a/chapters/en/chapter5/2.mdx b/chapters/en/chapter5/2.mdx index d3aea7b87..acf417bba 100644 --- a/chapters/en/chapter5/2.mdx +++ b/chapters/en/chapter5/2.mdx @@ -128,7 +128,7 @@ This is exactly what we wanted. Now, we can apply various preprocessing techniqu -The `data_files` argument of the `load_dataset()` function is quite flexible and can be either a single file path, a list of file paths, or a dictionary that maps split names to file paths. You can also glob files that match a specified pattern according to the rules used by the Unix shell (e.g., you can glob all the JSON files in a directory as a single split by setting `data_files="*.json"`). See the 🤗 Datasets [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) for more details. +The `data_files` argument of the `load_dataset()` function is quite flexible and can be either a single file path, a list of file paths, or a dictionary that maps split names to file paths. You can also glob files that match a specified pattern according to the rules used by the Unix shell (e.g., you can glob all the JSON files in a directory as a single split by setting `data_files="*.json"`). See the 🤗 Datasets [documentation](https://huggingface.co/docs/datasets/loading#local-and-remote-files) for more details. @@ -160,7 +160,7 @@ This returns the same `DatasetDict` object obtained above, but saves us the step -✏️ **Try it out!** Pick another dataset hosted on GitHub or the [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) and try loading it both locally and remotely using the techniques introduced above. For bonus points, try loading a dataset that’s stored in a CSV or text format (see the [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) for more information on these formats). +✏️ **Try it out!** Pick another dataset hosted on GitHub or the [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) and try loading it both locally and remotely using the techniques introduced above. For bonus points, try loading a dataset that’s stored in a CSV or text format (see the [documentation](https://huggingface.co/docs/datasets/loading#local-and-remote-files) for more information on these formats). diff --git a/chapters/en/chapter5/3.mdx b/chapters/en/chapter5/3.mdx index 4a3ddc7b5..9e6e738bc 100644 --- a/chapters/en/chapter5/3.mdx +++ b/chapters/en/chapter5/3.mdx @@ -238,7 +238,7 @@ As you can see, this has removed around 15% of the reviews from our original tra -✏️ **Try it out!** Use the `Dataset.sort()` function to inspect the reviews with the largest numbers of words. See the [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) to see which argument you need to use sort the reviews by length in descending order. +✏️ **Try it out!** Use the `Dataset.sort()` function to inspect the reviews with the largest numbers of words. See the [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) to see which argument you need to use sort the reviews by length in descending order. @@ -385,7 +385,7 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -Oh no! That didn't work! Why not? Looking at the error message will give us a clue: there is a mismatch in the lengths of one of the columns, one being of length 1,463 and the other of length 1,000. If you've looked at the `Dataset.map()` [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), you may recall that it's the number of samples passed to the function that we are mapping; here those 1,000 examples gave 1,463 new features, resulting in a shape error. +Oh no! That didn't work! Why not? Looking at the error message will give us a clue: there is a mismatch in the lengths of one of the columns, one being of length 1,463 and the other of length 1,000. If you've looked at the `Dataset.map()` [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map), you may recall that it's the number of samples passed to the function that we are mapping; here those 1,000 examples gave 1,463 new features, resulting in a shape error. The problem is that we're trying to mix two different datasets of different sizes: the `drug_dataset` columns will have a certain number of examples (the 1,000 in our error), but the `tokenized_dataset` we are building will have more (the 1,463 in the error message; it is more than 1,000 because we are tokenizing long reviews into more than one example by using `return_overflowing_tokens=True`). That doesn't work for a `Dataset`, so we need to either remove the columns from the old dataset or make them the same size as they are in the new dataset. We can do the former with the `remove_columns` argument: diff --git a/chapters/en/chapter5/4.mdx b/chapters/en/chapter5/4.mdx index 332e171c3..8f424d99f 100644 --- a/chapters/en/chapter5/4.mdx +++ b/chapters/en/chapter5/4.mdx @@ -46,7 +46,7 @@ We can see that there are 15,518,009 rows and 2 columns in our dataset -- that's -✎ By default, 🤗 Datasets will decompress the files needed to load a dataset. If you want to preserve hard drive space, you can pass `DownloadConfig(delete_extracted=True)` to the `download_config` argument of `load_dataset()`. See the [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) for more details. +✎ By default, 🤗 Datasets will decompress the files needed to load a dataset. If you want to preserve hard drive space, you can pass `DownloadConfig(delete_extracted=True)` to the `download_config` argument of `load_dataset()`. See the [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig) for more details. diff --git a/chapters/en/chapter5/5.mdx b/chapters/en/chapter5/5.mdx index 10e43fe5e..5688ea04a 100644 --- a/chapters/en/chapter5/5.mdx +++ b/chapters/en/chapter5/5.mdx @@ -365,7 +365,7 @@ Cool, we've pushed our dataset to the Hub and it's available for others to use! -💡 You can also upload a dataset to the Hugging Face Hub directly from the terminal by using `huggingface-cli` and a bit of Git magic. See the [🤗 Datasets guide](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) for details on how to do this. +💡 You can also upload a dataset to the Hugging Face Hub directly from the terminal by using `huggingface-cli` and a bit of Git magic. See the [🤗 Datasets guide](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) for details on how to do this. diff --git a/chapters/en/chapter5/6.mdx b/chapters/en/chapter5/6.mdx index 3da60cc96..418abbbb6 100644 --- a/chapters/en/chapter5/6.mdx +++ b/chapters/en/chapter5/6.mdx @@ -178,7 +178,7 @@ Okay, this has given us a few thousand comments to work with! -✏️ **Try it out!** See if you can use `Dataset.map()` to explode the `comments` column of `issues_dataset` _without_ resorting to the use of Pandas. This is a little tricky; you might find the ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) section of the 🤗 Datasets documentation useful for this task. +✏️ **Try it out!** See if you can use `Dataset.map()` to explode the `comments` column of `issues_dataset` _without_ resorting to the use of Pandas. This is a little tricky; you might find the ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) section of the 🤗 Datasets documentation useful for this task. diff --git a/chapters/en/chapter6/8.mdx b/chapters/en/chapter6/8.mdx index 7caee98ed..38086edcf 100644 --- a/chapters/en/chapter6/8.mdx +++ b/chapters/en/chapter6/8.mdx @@ -27,14 +27,14 @@ The 🤗 Tokenizers library has been built to provide several options for each o More precisely, the library is built around a central `Tokenizer` class with the building blocks regrouped in submodules: -- `normalizers` contains all the possible types of `Normalizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). -- `pre_tokenizers` contains all the possible types of `PreTokenizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). -- `models` contains the various types of `Model` you can use, like `BPE`, `WordPiece`, and `Unigram` (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). -- `trainers` contains all the different types of `Trainer` you can use to train your model on a corpus (one per type of model; complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). -- `post_processors` contains the various types of `PostProcessor` you can use (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). -- `decoders` contains the various types of `Decoder` you can use to decode the outputs of tokenization (complete list [here](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). - -You can find the whole list of building blocks [here](https://huggingface.co/docs/tokenizers/python/latest/components.html). +- `normalizers` contains all the possible types of `Normalizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/api/normalizers)). +- `pre_tokenizers` contains all the possible types of `PreTokenizer` you can use (complete list [here](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)). +- `models` contains the various types of `Model` you can use, like `BPE`, `WordPiece`, and `Unigram` (complete list [here](https://huggingface.co/docs/tokenizers/api/models)). +- `trainers` contains all the different types of `Trainer` you can use to train your model on a corpus (one per type of model; complete list [here](https://huggingface.co/docs/tokenizers/api/trainers)). +- `post_processors` contains the various types of `PostProcessor` you can use (complete list [here](https://huggingface.co/docs/tokenizers/api/post-processors)). +- `decoders` contains the various types of `Decoder` you can use to decode the outputs of tokenization (complete list [here](https://huggingface.co/docs/tokenizers/components#decoders)). + +You can find the whole list of building blocks [here](https://huggingface.co/docs/tokenizers/components). ## Acquiring a corpus[[acquiring-a-corpus]] diff --git a/chapters/es/chapter3/2.mdx b/chapters/es/chapter3/2.mdx index 7aed993ea..624749727 100644 --- a/chapters/es/chapter3/2.mdx +++ b/chapters/es/chapter3/2.mdx @@ -240,7 +240,7 @@ tokenized_dataset = tokenizer( Esto funciona bien, pero tiene la desventaja de que devuelve un diccionario (con nuestras llaves, `input_ids`, `attention_mask`, and `token_type_ids`, y valores que son listas de listas). Además va a trabajar solo si tienes suficiente memoria principal para almacenar todo el conjunto de datos durante la tokenización (mientras que los conjuntos de datos de la librería 🤗 Datasets son archivos [Apache Arrow](https://arrow.apache.org/) almacenados en disco, y así solo mantienes en memoria las muestras que necesitas). -Para mantener los datos como un conjunto de datos, usaremos el método [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map). Este también nos ofrece una flexibilidad adicional en caso de que necesitemos preprocesamiento mas allá de la tokenización. El método `map()` trabaja aplicando una función sobre cada elemento del conjunto de datos, así que definamos una función para tokenizar nuestras entradas: +Para mantener los datos como un conjunto de datos, usaremos el método [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map). Este también nos ofrece una flexibilidad adicional en caso de que necesitemos preprocesamiento mas allá de la tokenización. El método `map()` trabaja aplicando una función sobre cada elemento del conjunto de datos, así que definamos una función para tokenizar nuestras entradas: ```py def tokenize_function(example): diff --git a/chapters/es/chapter5/2.mdx b/chapters/es/chapter5/2.mdx index a0de6264a..e68820743 100644 --- a/chapters/es/chapter5/2.mdx +++ b/chapters/es/chapter5/2.mdx @@ -129,7 +129,7 @@ Esto es exactamente lo que queríamos. Ahora podemos aplicar varias técnicas de -El argumento `data_files` de la función `load_dataset()` es muy flexible. Puede ser una única ruta de archivo, una lista de rutas o un diccionario que mapee los nombres de los conjuntos a las rutas de archivo. También puedes buscar archivos que cumplan con cierto patrón específico de acuerdo con las reglas usadas por el shell de Unix (e.g., puedes buscar todos los archivos JSON en una carpeta al definir `datafiles="*.json"`). Revisa la [documentación](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) para más detalles. +El argumento `data_files` de la función `load_dataset()` es muy flexible. Puede ser una única ruta de archivo, una lista de rutas o un diccionario que mapee los nombres de los conjuntos a las rutas de archivo. También puedes buscar archivos que cumplan con cierto patrón específico de acuerdo con las reglas usadas por el shell de Unix (e.g., puedes buscar todos los archivos JSON en una carpeta al definir `datafiles="*.json"`). Revisa la [documentación](https://huggingface.co/docs/datasets/loading#local-and-remote-files) para más detalles. @@ -161,6 +161,6 @@ Esto devuelve el mismo objeto `DatasetDict` que obtuvimos antes, pero nos ahorra -✏️ **¡Inténtalo!** Escoge otro dataset alojado en GitHub o en el [Repositorio de Machine Learning de UCI](https://archive.ics.uci.edu/ml/index.php) e intenta cargarlo local y remotamente usando las técnicas descritas con anterioridad. Para puntos extra, intenta cargar un dataset que esté guardado en un formato CSV o de texto (revisa la [documentación](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) pata tener más información sobre estos formatos). +✏️ **¡Inténtalo!** Escoge otro dataset alojado en GitHub o en el [Repositorio de Machine Learning de UCI](https://archive.ics.uci.edu/ml/index.php) e intenta cargarlo local y remotamente usando las técnicas descritas con anterioridad. Para puntos extra, intenta cargar un dataset que esté guardado en un formato CSV o de texto (revisa la [documentación](https://huggingface.co/docs/datasets/loading#local-and-remote-files) pata tener más información sobre estos formatos). diff --git a/chapters/es/chapter5/3.mdx b/chapters/es/chapter5/3.mdx index f1cc5ab69..daae902ea 100644 --- a/chapters/es/chapter5/3.mdx +++ b/chapters/es/chapter5/3.mdx @@ -238,7 +238,7 @@ Como puedes ver, esto ha eliminado alrededor del 15% de las reseñas de nuestros -✏️ **¡Inténtalo!** Usa la función `Dataset.sort()` para inspeccionar las reseñas con el mayor número de palabras. Revisa la [documentación](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) para ver cuál argumento necesitas para ordenar las reseñas de mayor a menor. +✏️ **¡Inténtalo!** Usa la función `Dataset.sort()` para inspeccionar las reseñas con el mayor número de palabras. Revisa la [documentación](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) para ver cuál argumento necesitas para ordenar las reseñas de mayor a menor. @@ -385,7 +385,7 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -¿Por qué no funcionó? El mensaje de error nos da una pista: hay un desajuste en las longitudes de una de las columnas, siendo una de longitud 1.463 y otra de longitud 1.000. Si has revisado la [documentación de `Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), te habrás dado cuenta que estamos mapeando el número de muestras que le pasamos a la función: en este caso los 1.000 ejemplos nos devuelven 1.463 features, arrojando un error. +¿Por qué no funcionó? El mensaje de error nos da una pista: hay un desajuste en las longitudes de una de las columnas, siendo una de longitud 1.463 y otra de longitud 1.000. Si has revisado la [documentación de `Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map), te habrás dado cuenta que estamos mapeando el número de muestras que le pasamos a la función: en este caso los 1.000 ejemplos nos devuelven 1.463 features, arrojando un error. El problema es que estamos tratando de mezclar dos datasets de tamaños diferentes: las columnas de `drug_dataset` tendrán un cierto número de ejemplos (los 1.000 en el error), pero el `tokenized_dataset` que estamos construyendo tendrá más (los 1.463 en el mensaje de error). Esto no funciona para un `Dataset`, así que tenemos que eliminar las columnas del anterior dataset o volverlas del mismo tamaño del nuevo. Podemos hacer la primera operación con el argumento `remove_columns`: diff --git a/chapters/es/chapter5/4.mdx b/chapters/es/chapter5/4.mdx index 38919187d..326a2a609 100644 --- a/chapters/es/chapter5/4.mdx +++ b/chapters/es/chapter5/4.mdx @@ -45,7 +45,7 @@ Como podemos ver, hay 15.518.009 filas y dos columnas en el dataset, ¡un montó -✎ Por defecto, 🤗 Datasets va a descomprimir los archivos necesarios para cargar un dataset. Si quieres ahorrar espacio de almacenamiento, puedes usar `DownloadConfig(delete_extracted=True)` al argumento `download_config` de `load_dataset()`. Revisa la [documentación](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) para más detalles. +✎ Por defecto, 🤗 Datasets va a descomprimir los archivos necesarios para cargar un dataset. Si quieres ahorrar espacio de almacenamiento, puedes usar `DownloadConfig(delete_extracted=True)` al argumento `download_config` de `load_dataset()`. Revisa la [documentación](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig) para más detalles. diff --git a/chapters/es/chapter5/5.mdx b/chapters/es/chapter5/5.mdx index e901c3717..21419d4e5 100644 --- a/chapters/es/chapter5/5.mdx +++ b/chapters/es/chapter5/5.mdx @@ -427,7 +427,7 @@ Dataset({ -💡 También puedes subir un dataset al Hub de Hugging Face directamente desde la terminal usando `huggingface-cli` y un poco de Git. Revisa la [guía de 🤗 Datasets](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) para más detalles sobre cómo hacerlo. +💡 También puedes subir un dataset al Hub de Hugging Face directamente desde la terminal usando `huggingface-cli` y un poco de Git. Revisa la [guía de 🤗 Datasets](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) para más detalles sobre cómo hacerlo. diff --git a/chapters/es/chapter5/6.mdx b/chapters/es/chapter5/6.mdx index 1e635315b..d92a1333c 100644 --- a/chapters/es/chapter5/6.mdx +++ b/chapters/es/chapter5/6.mdx @@ -189,7 +189,7 @@ Dataset({ -✏️ **¡Inténtalo!** Prueba si puedes usar la función `Dataset.map()` para "explotar" la columna `comments` en `issues_dataset` _sin_ necesidad de usar Pandas. Esto es un poco complejo; te recomendamos revisar la sección de ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) de la documentación de 🤗 Datasets para completar esta tarea. +✏️ **¡Inténtalo!** Prueba si puedes usar la función `Dataset.map()` para "explotar" la columna `comments` en `issues_dataset` _sin_ necesidad de usar Pandas. Esto es un poco complejo; te recomendamos revisar la sección de ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) de la documentación de 🤗 Datasets para completar esta tarea. diff --git a/chapters/es/chapter6/8.mdx b/chapters/es/chapter6/8.mdx index 795be36aa..0754b82d0 100644 --- a/chapters/es/chapter6/8.mdx +++ b/chapters/es/chapter6/8.mdx @@ -27,14 +27,14 @@ La librería 🤗 Tokenizers ha sido construida para proveer varias opciones par De manera más precisa, la librería está construida a partir de una clase central `Tokenizer` con las unidades más básica reagrupadas en susbmódulos: -- `normalizers` contiene todos los posibles tipos de `Normalizer` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). -- `pre_tokenizers` contiene todos los posibles tipos de `PreTokenizer` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). -- `models` contiene los distintos tipos de `Model` que puedes usar, como `BPE`, `WordPiece`, and `Unigram` (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). -- `trainers` contiene todos los distintos tipos de `Trainer` que puedes usar para entrenar tu modelo en un corpus (uno por cada tipo de modelo; la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). -- `post_processors` contiene varios tipos de `PostProcessor` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). -- `decoders` contiene varios tipos de `Decoder` que puedes usar para decodificar las salidas de la tokenización (la lista completa [aquí](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). - -Puedes encontrar la lista completas de las unidades más básicas [aquí](https://huggingface.co/docs/tokenizers/python/latest/components.html). +- `normalizers` contiene todos los posibles tipos de `Normalizer` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/api/normalizers)). +- `pre_tokenizers` contiene todos los posibles tipos de `PreTokenizer` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)). +- `models` contiene los distintos tipos de `Model` que puedes usar, como `BPE`, `WordPiece`, and `Unigram` (la lista completa [aquí](https://huggingface.co/docs/tokenizers/api/models)). +- `trainers` contiene todos los distintos tipos de `Trainer` que puedes usar para entrenar tu modelo en un corpus (uno por cada tipo de modelo; la lista completa [aquí](https://huggingface.co/docs/tokenizers/api/trainers)). +- `post_processors` contiene varios tipos de `PostProcessor` que puedes usar (la lista completa [aquí](https://huggingface.co/docs/tokenizers/api/post-processors)). +- `decoders` contiene varios tipos de `Decoder` que puedes usar para decodificar las salidas de la tokenización (la lista completa [aquí](https://huggingface.co/docs/tokenizers/components#decoders)). + +Puedes encontrar la lista completas de las unidades más básicas [aquí](https://huggingface.co/docs/tokenizers/components). ## Adquirir un corpus[[acquiring-a-corpus]] diff --git a/chapters/fa/chapter3/2.mdx b/chapters/fa/chapter3/2.mdx index 07d933cc6..696135a20 100644 --- a/chapters/fa/chapter3/2.mdx +++ b/chapters/fa/chapter3/2.mdx @@ -300,7 +300,7 @@ tokenized_dataset = tokenizer( این روش به خوبی کار می‌کند، اما مشکل‌اش این است که دیکشنری (از کلیدهای ما شامل، `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.html#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌ بر توکِن کردن نیاز داشته باشیم این روش انعطاف‌پذیری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِن کند: +به منظور نگه داشتن داده به صورت یک دیتاسِت، از تابع [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) استفاده می‌کنیم. چنانچه به پیش‌پردازش‌های بیشتری علاوه‌ بر توکِن کردن نیاز داشته باشیم این روش انعطاف‌پذیری لازم را به ما می‌دهد. تابع `map()` با اعمال کردن یک عملیات روی هر عنصر دیتاسِت عمل می‌کند، بنابراین اجازه دهید تابعی تعریف کنیم که ورودی‌ها را توکِن کند:
diff --git a/chapters/fr/chapter3/2.mdx b/chapters/fr/chapter3/2.mdx index 70b529f7b..0aa69be72 100644 --- a/chapters/fr/chapter3/2.mdx +++ b/chapters/fr/chapter3/2.mdx @@ -246,7 +246,7 @@ tokenized_dataset = tokenizer( Cela fonctionne bien, mais a l'inconvénient de retourner un dictionnaire (avec nos clés, `input_ids`, `attention_mask`, et `token_type_ids`, et des valeurs qui sont des listes de listes). Cela ne fonctionnera également que si vous avez assez de RAM pour stocker l'ensemble de votre jeu de données pendant la tokenisation (alors que les jeux de données de la bibliothèque 🤗 *Datasets* sont des fichiers [Apache Arrow](https://arrow.apache.org/) stockés sur le disque, vous ne gardez donc en mémoire que les échantillons que vous demandez). -Pour conserver les données sous forme de jeu de données, nous utiliserons la méthode [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map). Cela nous permet également une certaine flexibilité, si nous avons besoin d'un prétraitement plus poussé que la simple tokenisation. La méthode `map()` fonctionne en appliquant une fonction sur chaque élément de l'ensemble de données, donc définissons une fonction qui tokenise nos entrées : +Pour conserver les données sous forme de jeu de données, nous utiliserons la méthode [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map). Cela nous permet également une certaine flexibilité, si nous avons besoin d'un prétraitement plus poussé que la simple tokenisation. La méthode `map()` fonctionne en appliquant une fonction sur chaque élément de l'ensemble de données, donc définissons une fonction qui tokenise nos entrées : ```py def tokenize_function(example): diff --git a/chapters/fr/chapter5/2.mdx b/chapters/fr/chapter5/2.mdx index 86a218a7c..58640da8b 100644 --- a/chapters/fr/chapter5/2.mdx +++ b/chapters/fr/chapter5/2.mdx @@ -132,7 +132,7 @@ C'est exactement ce que nous voulions. Désormais, nous pouvons appliquer divers -L'argument `data_files` de la fonction `load_dataset()` est assez flexible et peut être soit un chemin de fichier unique, une liste de chemins de fichiers, ou un dictionnaire qui fait correspondre les noms des échantillons aux chemins de fichiers. Vous pouvez également regrouper les fichiers correspondant à un motif spécifié selon les règles utilisées par le shell Unix. Par exemple, vous pouvez regrouper tous les fichiers JSON d'un répertoire en une seule division en définissant `data_files="*.json"`. Voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) de 🤗 *Datasets* pour plus de détails. +L'argument `data_files` de la fonction `load_dataset()` est assez flexible et peut être soit un chemin de fichier unique, une liste de chemins de fichiers, ou un dictionnaire qui fait correspondre les noms des échantillons aux chemins de fichiers. Vous pouvez également regrouper les fichiers correspondant à un motif spécifié selon les règles utilisées par le shell Unix. Par exemple, vous pouvez regrouper tous les fichiers JSON d'un répertoire en une seule division en définissant `data_files="*.json"`. Voir la [documentation](https://huggingface.co/docs/datasets/loading#local-and-remote-files) de 🤗 *Datasets* pour plus de détails. @@ -164,6 +164,6 @@ Cela renvoie le même objet `DatasetDict` obtenu ci-dessus mais nous évite de t -✏️ **Essayez !** Choisissez un autre jeu de données hébergé sur GitHub ou dans le [*UCI Machine Learning Repository*](https://archive.ics.uci.edu/ml/index.php) et essayez de le charger localement et à distance en utilisant les techniques présentées ci-dessus. Pour obtenir des points bonus, essayez de charger un jeu de données stocké au format CSV ou texte (voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) pour plus d'informations sur ces formats). +✏️ **Essayez !** Choisissez un autre jeu de données hébergé sur GitHub ou dans le [*UCI Machine Learning Repository*](https://archive.ics.uci.edu/ml/index.php) et essayez de le charger localement et à distance en utilisant les techniques présentées ci-dessus. Pour obtenir des points bonus, essayez de charger un jeu de données stocké au format CSV ou texte (voir la [documentation](https://huggingface.co/docs/datasets/loading#local-and-remote-files) pour plus d'informations sur ces formats). diff --git a/chapters/fr/chapter5/3.mdx b/chapters/fr/chapter5/3.mdx index 271396fcb..1c38a5fff 100644 --- a/chapters/fr/chapter5/3.mdx +++ b/chapters/fr/chapter5/3.mdx @@ -249,7 +249,7 @@ Comme vous pouvez le constater, cela a supprimé environ 15 % des avis de nos je -✏️ **Essayez !** Utilisez la fonction `Dataset.sort()` pour inspecter les avis avec le plus grand nombre de mots. Consultez la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) pour voir quel argument vous devez utiliser pour trier les avis par longueur dans l'ordre décroissant. +✏️ **Essayez !** Utilisez la fonction `Dataset.sort()` pour inspecter les avis avec le plus grand nombre de mots. Consultez la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) pour voir quel argument vous devez utiliser pour trier les avis par longueur dans l'ordre décroissant. @@ -396,7 +396,7 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -Oh non ! Cela n'a pas fonctionné ! Pourquoi ? L'examen du message d'erreur nous donne un indice : il y a une incompatibilité dans les longueurs de l'une des colonnes. L'une étant de longueur 1 463 et l'autre de longueur 1 000. Si vous avez consulté la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) de `Dataset.map()`, vous vous souvenez peut-être qu'il s'agit du nombre d'échantillons passés à la fonction que nous mappons. Ici, ces 1 000 exemples ont donné 1 463 nouvelles caractéristiques, entraînant une erreur de forme. +Oh non ! Cela n'a pas fonctionné ! Pourquoi ? L'examen du message d'erreur nous donne un indice : il y a une incompatibilité dans les longueurs de l'une des colonnes. L'une étant de longueur 1 463 et l'autre de longueur 1 000. Si vous avez consulté la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) de `Dataset.map()`, vous vous souvenez peut-être qu'il s'agit du nombre d'échantillons passés à la fonction que nous mappons. Ici, ces 1 000 exemples ont donné 1 463 nouvelles caractéristiques, entraînant une erreur de forme. Le problème est que nous essayons de mélanger deux jeux de données différents de tailles différentes : les colonnes `drug_dataset` auront un certain nombre d'exemples (les 1 000 dans notre erreur), mais le `tokenized_dataset` que nous construisons en aura plus (le 1 463 dans le message d'erreur). Cela ne fonctionne pas pour un `Dataset`, nous devons donc soit supprimer les colonnes de l'ancien jeu de données, soit leur donner la même taille que dans le nouveau jeu de données. Nous pouvons faire la première option avec l'argument `remove_columns` : diff --git a/chapters/fr/chapter5/4.mdx b/chapters/fr/chapter5/4.mdx index 1fdc67418..2d3d62ba6 100644 --- a/chapters/fr/chapter5/4.mdx +++ b/chapters/fr/chapter5/4.mdx @@ -48,7 +48,7 @@ Nous pouvons voir qu'il y a 15 518 009 lignes et 2 colonnes dans notre jeu de do -✎ Par défaut, 🤗 *Datasets* décompresse les fichiers nécessaires pour charger un jeu de données. Si vous souhaitez conserver de l'espace sur le disque dur, vous pouvez passer `DownloadConfig(delete_extracted=True)` à l'argument `download_config` de `load_dataset()`. Voir la [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) pour plus de détails. +✎ Par défaut, 🤗 *Datasets* décompresse les fichiers nécessaires pour charger un jeu de données. Si vous souhaitez conserver de l'espace sur le disque dur, vous pouvez passer `DownloadConfig(delete_extracted=True)` à l'argument `download_config` de `load_dataset()`. Voir la [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig) pour plus de détails. diff --git a/chapters/fr/chapter5/5.mdx b/chapters/fr/chapter5/5.mdx index af48c82b3..63a14bf36 100644 --- a/chapters/fr/chapter5/5.mdx +++ b/chapters/fr/chapter5/5.mdx @@ -431,7 +431,7 @@ Cool, nous avons poussé notre jeu de données vers le *Hub* et il est disponibl -💡 Vous pouvez également télécharger un jeu de données sur le *Hub* directement depuis le terminal en utilisant `huggingface-cli` et un peu de magie Git. Consultez le [guide de 🤗 *Datasets*](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) pour savoir comment procéder. +💡 Vous pouvez également télécharger un jeu de données sur le *Hub* directement depuis le terminal en utilisant `huggingface-cli` et un peu de magie Git. Consultez le [guide de 🤗 *Datasets*](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) pour savoir comment procéder. diff --git a/chapters/fr/chapter5/6.mdx b/chapters/fr/chapter5/6.mdx index 610af1078..19d2e1f5d 100644 --- a/chapters/fr/chapter5/6.mdx +++ b/chapters/fr/chapter5/6.mdx @@ -193,7 +193,7 @@ D'accord, cela nous a donné quelques milliers de commentaires avec lesquels tra -✏️ **Essayez !** Voyez si vous pouvez utiliser `Dataset.map()` pour exploser la colonne `comments` de `issues_dataset` _sans_ recourir à l'utilisation de Pandas. C'est un peu délicat. La section [« Batch mapping »](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) de la documentation 🤗 *Datasets* peut être utile pour cette tâche. +✏️ **Essayez !** Voyez si vous pouvez utiliser `Dataset.map()` pour exploser la colonne `comments` de `issues_dataset` _sans_ recourir à l'utilisation de Pandas. C'est un peu délicat. La section [« Batch mapping »](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) de la documentation 🤗 *Datasets* peut être utile pour cette tâche. diff --git a/chapters/fr/chapter6/8.mdx b/chapters/fr/chapter6/8.mdx index f8a740502..5bed366b9 100644 --- a/chapters/fr/chapter6/8.mdx +++ b/chapters/fr/chapter6/8.mdx @@ -30,14 +30,14 @@ La bibliothèque 🤗 *Tokenizers* a été construite pour fournir plusieurs opt Plus précisément, la bibliothèque est construite autour d'une classe centrale `Tokenizer` avec les blocs de construction regroupés en sous-modules : -- `normalizers` contient tous les types de `Normalizer` que vous pouvez utiliser (liste complète [ici](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)), -- `pre_tokenizers` contient tous les types de `PreTokenizer` que vous pouvez utiliser (liste complète [ici](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)), -- `models` contient les différents types de `Model` que vous pouvez utiliser, comme `BPE`, `WordPiece`, et `Unigram` (liste complète [ici](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)), -- `trainers` contient tous les différents types de `Trainer` que vous pouvez utiliser pour entraîner votre modèle sur un corpus (un par type de modèle ; liste complète [ici](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)), -- `post_processors` contient les différents types de `PostProcessor` que vous pouvez utiliser (liste complète [ici](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)), -- `decoders` contient les différents types de `Decoder` que vous pouvez utiliser pour décoder les sorties de tokenization (liste complète [ici](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). - -Vous pouvez trouver la liste complète des blocs de construction [ici](https://huggingface.co/docs/tokenizers/python/latest/components.html). +- `normalizers` contient tous les types de `Normalizer` que vous pouvez utiliser (liste complète [ici](https://huggingface.co/docs/tokenizers/api/normalizers)), +- `pre_tokenizers` contient tous les types de `PreTokenizer` que vous pouvez utiliser (liste complète [ici](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)), +- `models` contient les différents types de `Model` que vous pouvez utiliser, comme `BPE`, `WordPiece`, et `Unigram` (liste complète [ici](https://huggingface.co/docs/tokenizers/api/models)), +- `trainers` contient tous les différents types de `Trainer` que vous pouvez utiliser pour entraîner votre modèle sur un corpus (un par type de modèle ; liste complète [ici](https://huggingface.co/docs/tokenizers/api/trainers)), +- `post_processors` contient les différents types de `PostProcessor` que vous pouvez utiliser (liste complète [ici](https://huggingface.co/docs/tokenizers/api/post-processors)), +- `decoders` contient les différents types de `Decoder` que vous pouvez utiliser pour décoder les sorties de tokenization (liste complète [ici](https://huggingface.co/docs/tokenizers/components#decoders)). + +Vous pouvez trouver la liste complète des blocs de construction [ici](https://huggingface.co/docs/tokenizers/components). ## Acquisition d'un corpus diff --git a/chapters/hi/chapter3/2.mdx b/chapters/hi/chapter3/2.mdx index 481fc824f..066bfddfc 100644 --- a/chapters/hi/chapter3/2.mdx +++ b/chapters/hi/chapter3/2.mdx @@ -235,7 +235,7 @@ tokenized_dataset = tokenizer( यह अच्छी तरह से काम करता है, लेकिन इसमें एक शब्दकोश (साथ में हमारी कुंजी, `input_ids`, `attention_mask`, और `token_type_ids`, और मान जो सूचियों की सूचियां हैं) के लौटने का नुकसान है। यह केवल तभी काम करेगा जब आपके पास पर्याप्त RAM हो अपने पूरे डेटासेट को टोकननाइजेशन के दौरान स्टोर करने के लिए (जबकि 🤗 डेटासेट लाइब्रेरी के डेटासेट [अपाचे एरो](https://arrow.apache.org/) फाइलें हैं जो डिस्क पर संग्रहीत है, तो आप केवल उन सैम्पल्स को रखते हैं जिन्हें आप मेमोरी मे लोड करना चाहतें है)। -डेटा को डेटासेट के रूप में रखने के लिए, हम [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) पद्धति का उपयोग करेंगे। अगर हमें सिर्फ टोकननाइजेशन की तुलना में अधिक पूर्व प्रसंस्करण की आवश्यकता होती है, तो यह हमें कुछ अधिक लचीलेपन की भी अनुमति देता है। `map()` विधि डेटासेट के प्रत्येक तत्व पर एक फ़ंक्शन लागू करके काम करती है, तो चलिए एक फ़ंक्शन को परिभाषित करते हैं जो हमारे इनपुट को टोकननाइज़ करेगा : +डेटा को डेटासेट के रूप में रखने के लिए, हम [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) पद्धति का उपयोग करेंगे। अगर हमें सिर्फ टोकननाइजेशन की तुलना में अधिक पूर्व प्रसंस्करण की आवश्यकता होती है, तो यह हमें कुछ अधिक लचीलेपन की भी अनुमति देता है। `map()` विधि डेटासेट के प्रत्येक तत्व पर एक फ़ंक्शन लागू करके काम करती है, तो चलिए एक फ़ंक्शन को परिभाषित करते हैं जो हमारे इनपुट को टोकननाइज़ करेगा : ```py def tokenize_function(example): diff --git a/chapters/it/chapter3/2.mdx b/chapters/it/chapter3/2.mdx index 5ebea52a6..0b428d08d 100644 --- a/chapters/it/chapter3/2.mdx +++ b/chapters/it/chapter3/2.mdx @@ -236,7 +236,7 @@ tokenized_dataset = tokenizer( Questo metodo funziona, ma ha lo svantaggio di restituire un dizionario (avente `input_ids`, `attention_mask`, e `token_type_ids` come chiavi, e delle liste di liste come valori). Oltretutto, questo metodo funziona solo se si ha a disposizione RAM sufficiente per contenere l'intero dataset durante la tokenizzazione (mentre i dataset dalla libreria 🤗 Datasets sono file [Apache Arrow](https://arrow.apache.org/) archiviati su disco, perciò in memoria vengono caricati solo i campioni richiesti). -Per tenere i dati come dataset, utilizzare il metodo [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map). Ciò permette anche della flessibilità extra, qualora fosse necessario del preprocessing aggiuntivo oltre alla tokenizzazione. Il metodo `map()` applica una funziona ad ogni elemento del dataset, perciò bisogna definire una funzione che tokenizzi gli input: +Per tenere i dati come dataset, utilizzare il metodo [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map). Ciò permette anche della flessibilità extra, qualora fosse necessario del preprocessing aggiuntivo oltre alla tokenizzazione. Il metodo `map()` applica una funziona ad ogni elemento del dataset, perciò bisogna definire una funzione che tokenizzi gli input: ```py def tokenize_function(example): diff --git a/chapters/it/chapter5/2.mdx b/chapters/it/chapter5/2.mdx index 738710236..c3ead7ad6 100644 --- a/chapters/it/chapter5/2.mdx +++ b/chapters/it/chapter5/2.mdx @@ -128,7 +128,7 @@ Questo è proprio ciò che volevamo. Ora possiamo applicare diverse tecniche di -L'argomento `data_files` della funzione `load_dataset()` è molto flessibile, e può essere usato con un percorso file singolo, con una lista di percorsi file, o un dizionario che mappa i nomi delle sezioni ai percorsi file. È anche possibile usare comandi glob per recuperare tutti i file che soddisfano uno specifico pattern secondo le regole dello shell di Unix (ad esempio, è possibile recuperare tutti i file JSON presenti in una cartella usando il pattern `data_files="*.json"`). Consulta la [documentazione](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) 🤗 Datasets per maggiori informazioni. +L'argomento `data_files` della funzione `load_dataset()` è molto flessibile, e può essere usato con un percorso file singolo, con una lista di percorsi file, o un dizionario che mappa i nomi delle sezioni ai percorsi file. È anche possibile usare comandi glob per recuperare tutti i file che soddisfano uno specifico pattern secondo le regole dello shell di Unix (ad esempio, è possibile recuperare tutti i file JSON presenti in una cartella usando il pattern `data_files="*.json"`). Consulta la [documentazione](https://huggingface.co/docs/datasets/loading#local-and-remote-files) 🤗 Datasets per maggiori informazioni. @@ -160,7 +160,7 @@ Questo codice restituisce lo stesso oggetto `DatasetDict` visto in precedenza, m -✏️ **Prova tu!** Scegli un altro dataset presente su GitHub o sulla [Repository di Machine Learning UCI](https://archive.ics.uci.edu/ml/index.php) e cerca di caricare sia in locale che in remoto usando le tecniche introdotte in precedenza. Per punti extra, prova a caricare un dataset archiviato in formato CSV o testuale (vedi la [documentazione](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) per ulteriori informazioni su questi formati). +✏️ **Prova tu!** Scegli un altro dataset presente su GitHub o sulla [Repository di Machine Learning UCI](https://archive.ics.uci.edu/ml/index.php) e cerca di caricare sia in locale che in remoto usando le tecniche introdotte in precedenza. Per punti extra, prova a caricare un dataset archiviato in formato CSV o testuale (vedi la [documentazione](https://huggingface.co/docs/datasets/loading#local-and-remote-files) per ulteriori informazioni su questi formati). diff --git a/chapters/it/chapter5/3.mdx b/chapters/it/chapter5/3.mdx index 6b8bc7f8f..3eafa185e 100644 --- a/chapters/it/chapter5/3.mdx +++ b/chapters/it/chapter5/3.mdx @@ -241,7 +241,7 @@ Come puoi vedere, questo ha rimosso circa il 15% delle recensioni nelle sezioni -✏️ **Prova tu!** Usa la funzione `Dataset.sort()` per analizzare le revisioni con il maggior numero di parole. Controlla la [documentazione](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) per vedere quali argomenti bisogna usare per ordinare le recensioni in ordine decrescente di lunghezza. +✏️ **Prova tu!** Usa la funzione `Dataset.sort()` per analizzare le revisioni con il maggior numero di parole. Controlla la [documentazione](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) per vedere quali argomenti bisogna usare per ordinare le recensioni in ordine decrescente di lunghezza. @@ -386,7 +386,7 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -Oh no! Non ha funzionato! Perché? Il messaggio di errore ci dà un indizio: c'è una discordanza tra la lungheza di una delle colonne (una è lunga 1.463 e l'altra 1.000). Se hai guardato la [documentazione](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) di `Dataset.map()`, ricorderai che quello è il numero di campioni passati alla funzione map; qui quei 1.000 esempi danno 1.463 nuove feature, che risulta in un errore di shape. +Oh no! Non ha funzionato! Perché? Il messaggio di errore ci dà un indizio: c'è una discordanza tra la lungheza di una delle colonne (una è lunga 1.463 e l'altra 1.000). Se hai guardato la [documentazione](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) di `Dataset.map()`, ricorderai che quello è il numero di campioni passati alla funzione map; qui quei 1.000 esempi danno 1.463 nuove feature, che risulta in un errore di shape. Il problema è che stiamo cercando di mescolare due dataset diversi di grandezze diverse: le colonne del `drug_dataset` avranno un certo numero di esempi (il 1.000 del nostro errore), ma il `tokenized_dataset` che stiamo costruendo ne avrà di più (il 1.463 nel nostro messaggio di errore). Non va bene per un `Dataset`, per cui abbiamo bisogno o di rimuovere le colonne dal dataset vecchio, o renderle della stessa dimensione del nuovo dataset. La prima opzione può essere effettuata utilizzando l'argomento `remove_columns`: diff --git a/chapters/it/chapter5/4.mdx b/chapters/it/chapter5/4.mdx index 57f15060c..ad2f6e191 100644 --- a/chapters/it/chapter5/4.mdx +++ b/chapters/it/chapter5/4.mdx @@ -47,7 +47,7 @@ Possiamo vedere che ci sono 15.518.009 righe e 2 colonne nel nostro dataset -- u -✎ Di base, 🤗 Datasets decomprimerà i file necessari a caricare un dataset. Se vuoi risparmiare sullo spazio dell'hard disk, puoi passare `DownloadConfig(delete_extracted_True)` all'argomento `download_config` di `load_dataset()`. Per maggiori dettagli leggi la [documentazione](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig). +✎ Di base, 🤗 Datasets decomprimerà i file necessari a caricare un dataset. Se vuoi risparmiare sullo spazio dell'hard disk, puoi passare `DownloadConfig(delete_extracted_True)` all'argomento `download_config` di `load_dataset()`. Per maggiori dettagli leggi la [documentazione](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig). diff --git a/chapters/it/chapter5/5.mdx b/chapters/it/chapter5/5.mdx index 3a9c0f19f..a9246a463 100644 --- a/chapters/it/chapter5/5.mdx +++ b/chapters/it/chapter5/5.mdx @@ -430,7 +430,7 @@ Bene, abbiamo caricato il nostro dataset sull'Hub, e può essere utilizzato da t -💡 Puoi caricare un dataset nell'Hub di Hugging Face anche direttamente dal terminale usando `huggingface-cli` e un po' di magia Git. La [guida a 🤗 Datasets](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) spiega come farlo. +💡 Puoi caricare un dataset nell'Hub di Hugging Face anche direttamente dal terminale usando `huggingface-cli` e un po' di magia Git. La [guida a 🤗 Datasets](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) spiega come farlo. diff --git a/chapters/it/chapter5/6.mdx b/chapters/it/chapter5/6.mdx index b1296144f..1bd0dca34 100644 --- a/chapters/it/chapter5/6.mdx +++ b/chapters/it/chapter5/6.mdx @@ -190,7 +190,7 @@ Perfetto, ora abbiamo qualche migliaio di commenti con cui lavorare! -✏️ **Prova tu!** Prova ad utilizzare `Dataset.map()` per far esplodere la colonna `commenti` di `issues_dataset` _senza_ utilizzare Pandas. È un po' difficile: potrebbe tornarti utile la sezione ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) della documentazione di 🤗 Datasets. +✏️ **Prova tu!** Prova ad utilizzare `Dataset.map()` per far esplodere la colonna `commenti` di `issues_dataset` _senza_ utilizzare Pandas. È un po' difficile: potrebbe tornarti utile la sezione ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) della documentazione di 🤗 Datasets. diff --git a/chapters/ko/chapter5/2.mdx b/chapters/ko/chapter5/2.mdx index 9f8c463f1..67ccff72a 100644 --- a/chapters/ko/chapter5/2.mdx +++ b/chapters/ko/chapter5/2.mdx @@ -128,7 +128,7 @@ DatasetDict({ -`load_dataset()` 함수의 `data_files` 인수는 매우 유연하여 하나의 파일 경로 (str), 파일 경로들의 리스트 (list) 또는 스플릿 이름을 각 파일 경로에 매핑하는 dictionary를 값으로 받을 수 있습니다. 또한 Unix 쉘에서 사용하는 규칙에 따라 지정된 패턴과 일치하는 파일들을 glob할 수도 있습니다. (예를 들어, `data_files="*.json"`와 같이 설정하면 한 폴더에 있는 모든 JSON 파일들을 하나의 스플릿으로 glob할 수 있습니다.) 자세한 내용은 🤗 Datasets [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files)에서 확인할 수 있습니다. +`load_dataset()` 함수의 `data_files` 인수는 매우 유연하여 하나의 파일 경로 (str), 파일 경로들의 리스트 (list) 또는 스플릿 이름을 각 파일 경로에 매핑하는 dictionary를 값으로 받을 수 있습니다. 또한 Unix 쉘에서 사용하는 규칙에 따라 지정된 패턴과 일치하는 파일들을 glob할 수도 있습니다. (예를 들어, `data_files="*.json"`와 같이 설정하면 한 폴더에 있는 모든 JSON 파일들을 하나의 스플릿으로 glob할 수 있습니다.) 자세한 내용은 🤗 Datasets [documentation](https://huggingface.co/docs/datasets/loading#local-and-remote-files)에서 확인할 수 있습니다. diff --git a/chapters/pt/chapter5/2.mdx b/chapters/pt/chapter5/2.mdx index 053e35ae9..2d12ad4e0 100644 --- a/chapters/pt/chapter5/2.mdx +++ b/chapters/pt/chapter5/2.mdx @@ -130,7 +130,7 @@ Isto é exatamente o que queríamos. Agora, podemos aplicar várias técnicas de -O argumento `data_files` da função `load_dataset()` é bastante flexível e pode ser um único caminho de arquivo ou uma lista de caminhos de arquivo, ou um dicionário que mapeia nomes divididos para caminhos de arquivo. Você também pode incluir arquivos que correspondam a um padrão especificado de acordo com as regras utilizadas pela Unix shell (por exemplo, você pode adicionar todos os arquivos JSON em um diretório como uma única divisão, definindo `data_files="*.json"`). Consulte a [documentação](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) do 🤗 Datasets para obter mais detalhes. +O argumento `data_files` da função `load_dataset()` é bastante flexível e pode ser um único caminho de arquivo ou uma lista de caminhos de arquivo, ou um dicionário que mapeia nomes divididos para caminhos de arquivo. Você também pode incluir arquivos que correspondam a um padrão especificado de acordo com as regras utilizadas pela Unix shell (por exemplo, você pode adicionar todos os arquivos JSON em um diretório como uma única divisão, definindo `data_files="*.json"`). Consulte a [documentação](https://huggingface.co/docs/datasets/loading#local-and-remote-files) do 🤗 Datasets para obter mais detalhes. @@ -161,7 +161,7 @@ squad_it_dataset = load_dataset("json", data_files=data_files, field="data") Isto retorna o mesmo objeto `DatasetDict` obtido anteriormente, mas nos poupa o passo de baixar e descomprimir manualmente os arquivos _SQuAD_it-*.json.gz_. Isto envolve nas várias formas de carregar conjuntos de dados que não estão hospedados no Hugging Face Hub. Agora que temos um conjunto de dados para brincar, vamos sujar as mãos com várias técnicas de manipulação de dados! -✏️ **Tente fazer isso!** Escolha outro conjunto de dados hospedado no GitHub ou no [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) e tente carregá-lo tanto local como remotamente usando as técnicas introduzidas acima. Para pontos bônus, tente carregar um conjunto de dados que esteja armazenado em formato CSV ou texto (veja a [documentação](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) para mais informações sobre estes formatos). +✏️ **Tente fazer isso!** Escolha outro conjunto de dados hospedado no GitHub ou no [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) e tente carregá-lo tanto local como remotamente usando as técnicas introduzidas acima. Para pontos bônus, tente carregar um conjunto de dados que esteja armazenado em formato CSV ou texto (veja a [documentação](https://huggingface.co/docs/datasets/loading#local-and-remote-files) para mais informações sobre estes formatos). diff --git a/chapters/pt/chapter5/3.mdx b/chapters/pt/chapter5/3.mdx index 7d48c6149..ba734d249 100644 --- a/chapters/pt/chapter5/3.mdx +++ b/chapters/pt/chapter5/3.mdx @@ -238,7 +238,7 @@ Como você pode ver, isso removeu cerca de 15% das avaliações de nossos conjun -✏️ **Experimente!** Use a função `Dataset.sort()` para inspecionar as resenhas com o maior número de palavras. Consulte a [documentação](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) para ver qual argumento você precisa usar para classificar as avaliações por tamanho em ordem decrescente. +✏️ **Experimente!** Use a função `Dataset.sort()` para inspecionar as resenhas com o maior número de palavras. Consulte a [documentação](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) para ver qual argumento você precisa usar para classificar as avaliações por tamanho em ordem decrescente. @@ -384,7 +384,7 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -Oh não! Isso não funcionou! Por que não? Observar a mensagem de erro nos dará uma pista: há uma incompatibilidade nos comprimentos de uma das colunas, sendo uma de comprimento 1.463 e a outra de comprimento 1.000. Se você consultou a [documentação] do `Dataset.map()` (https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), você deve se lembrar de que é o número de amostras passadas para a função que estamos mapeando; aqui, esses 1.000 exemplos forneceram 1.463 novos recursos, resultando em um erro de forma. +Oh não! Isso não funcionou! Por que não? Observar a mensagem de erro nos dará uma pista: há uma incompatibilidade nos comprimentos de uma das colunas, sendo uma de comprimento 1.463 e a outra de comprimento 1.000. Se você consultou a [documentação] do `Dataset.map()` (https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map), você deve se lembrar de que é o número de amostras passadas para a função que estamos mapeando; aqui, esses 1.000 exemplos forneceram 1.463 novos recursos, resultando em um erro de forma. O problema é que estamos tentando misturar dois conjuntos de dados diferentes de tamanhos diferentes: as colunas `drug_dataset` terão um certo número de exemplos (os 1.000 em nosso erro), mas o `tokenized_dataset` que estamos construindo terá mais (o 1.463 na mensagem de erro). Isso não funciona para um `Dataset`, portanto, precisamos remover as colunas do conjunto de dados antigo ou torná-las do mesmo tamanho do novo conjunto de dados. Podemos fazer o primeiro com o argumento `remove_columns`: diff --git a/chapters/pt/chapter5/4.mdx b/chapters/pt/chapter5/4.mdx index 0018334e6..2a64e2471 100644 --- a/chapters/pt/chapter5/4.mdx +++ b/chapters/pt/chapter5/4.mdx @@ -46,7 +46,7 @@ Podemos ver que há 15.518.009 linhas e 2 colunas em nosso conjunto de dados - i -✎ Por padrão, 🤗 Datasets descompactará os arquivos necessários para carregar um dataset. Se você quiser preservar espaço no disco rígido, você pode passar `DownloadConfig(delete_extracted=True)` para o argumento `download_config` de `load_dataset()`. Consulte a [documentação](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) para obter mais detalhes. +✎ Por padrão, 🤗 Datasets descompactará os arquivos necessários para carregar um dataset. Se você quiser preservar espaço no disco rígido, você pode passar `DownloadConfig(delete_extracted=True)` para o argumento `download_config` de `load_dataset()`. Consulte a [documentação](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig) para obter mais detalhes. diff --git a/chapters/pt/chapter5/5.mdx b/chapters/pt/chapter5/5.mdx index 9207fa010..23e3831dc 100644 --- a/chapters/pt/chapter5/5.mdx +++ b/chapters/pt/chapter5/5.mdx @@ -430,7 +430,7 @@ Legal, nós enviamos nosso conjunto de dados para o Hub e está disponível para -💡 Você também pode enviar um conjunto de dados para o Hugging Face Hub diretamente do terminal usando `huggingface-cli` e um pouco de magia Git. Consulte o [guia do 🤗 Datasets](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) para obter detalhes sobre como fazer isso. +💡 Você também pode enviar um conjunto de dados para o Hugging Face Hub diretamente do terminal usando `huggingface-cli` e um pouco de magia Git. Consulte o [guia do 🤗 Datasets](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) para obter detalhes sobre como fazer isso. diff --git a/chapters/pt/chapter5/6.mdx b/chapters/pt/chapter5/6.mdx index c77091eef..f0a868c57 100644 --- a/chapters/pt/chapter5/6.mdx +++ b/chapters/pt/chapter5/6.mdx @@ -188,7 +188,7 @@ Ok, isso nos deu alguns milhares de comentários para trabalhar! -✏️ **Experimente!** Veja se você pode usar `Dataset.map()` para explodir a coluna `comments` de `issues_dataset` _sem_ recorrer ao uso de Pandas. Isso é um pouco complicado; você pode achar útil para esta tarefa a seção ["Mapeamento em lote"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) da documentação do 🤗 Dataset. +✏️ **Experimente!** Veja se você pode usar `Dataset.map()` para explodir a coluna `comments` de `issues_dataset` _sem_ recorrer ao uso de Pandas. Isso é um pouco complicado; você pode achar útil para esta tarefa a seção ["Mapeamento em lote"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch#batch-mapping) da documentação do 🤗 Dataset. diff --git a/chapters/ru/chapter3/2.mdx b/chapters/ru/chapter3/2.mdx index dc8c83f24..9a79dea25 100644 --- a/chapters/ru/chapter3/2.mdx +++ b/chapters/ru/chapter3/2.mdx @@ -235,7 +235,7 @@ tokenized_dataset = tokenizer( Это хорошо работает, однако есть недостаток, который формирует токенизатор (с ключами, `input_ids`, `attention_mask`, и `token_type_ids`, и значениями в формате списка списков). Это будет работать только если у нас достаточно оперативной памяти (RAM) для хранения целого датасета во время токенизации (в то время как датасеты из библиотеки 🤗 Datasets являются [Apache Arrow](https://arrow.apache.org/) файлами, хранящимися на диске; они будут загружены только в тот момент, когда вы их будете запрашивать). -Чтобы хранить данные в формате датасета, мы будем использовать методы [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map). Это позволит нам сохранить высокую гибкость даже если нам нужно что-то большее, чем просто токенизация. Метод `map()` работает так: применяет некоторую функцию к каждому элементу датасета, давайте определим функцию, которая токенизирует наши входные данные: +Чтобы хранить данные в формате датасета, мы будем использовать методы [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map). Это позволит нам сохранить высокую гибкость даже если нам нужно что-то большее, чем просто токенизация. Метод `map()` работает так: применяет некоторую функцию к каждому элементу датасета, давайте определим функцию, которая токенизирует наши входные данные: ```py def tokenize_function(example): diff --git a/chapters/ru/chapter5/2.mdx b/chapters/ru/chapter5/2.mdx index ee50ef207..b4a9c9ab5 100644 --- a/chapters/ru/chapter5/2.mdx +++ b/chapters/ru/chapter5/2.mdx @@ -123,7 +123,7 @@ DatasetDict({ -Аргумент `data_files` функции `load_dataset()` очень гибкий и может являться путем к файлу, списком путей файлов или словарем, в котором указаны названия сплитов (обучающего и тестового) и пути к соответствующим файлам. Вы также можете найти все подходящие файлы в директории с использованием маски по правилам Unix-консоли (т.е. указать путь к директории и указать `data_files="*.json"` для конкретного сплита). Более подробно это изложено в [документации](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) 🤗 Datasets. +Аргумент `data_files` функции `load_dataset()` очень гибкий и может являться путем к файлу, списком путей файлов или словарем, в котором указаны названия сплитов (обучающего и тестового) и пути к соответствующим файлам. Вы также можете найти все подходящие файлы в директории с использованием маски по правилам Unix-консоли (т.е. указать путь к директории и указать `data_files="*.json"` для конкретного сплита). Более подробно это изложено в [документации](https://huggingface.co/docs/datasets/loading#local-and-remote-files) 🤗 Datasets. @@ -156,7 +156,7 @@ squad_it_dataset = load_dataset("json", data_files=data_files, field="data") -✏️ **Попробуйте!** Выберите другой датасет, расположенный на GitHub или в архиве [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) и попробуйте загрузить его с локальной машины и с удаленного сервера. В качестве бонуса попробуйте загрузить датасет в формате CSV или обычного тектового файла (см. детали по поддерживаемым форматам в [документации](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files)). +✏️ **Попробуйте!** Выберите другой датасет, расположенный на GitHub или в архиве [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) и попробуйте загрузить его с локальной машины и с удаленного сервера. В качестве бонуса попробуйте загрузить датасет в формате CSV или обычного тектового файла (см. детали по поддерживаемым форматам в [документации](https://huggingface.co/docs/datasets/loading#local-and-remote-files)). diff --git a/chapters/ru/chapter5/3.mdx b/chapters/ru/chapter5/3.mdx index 378b05e24..654f0cd81 100644 --- a/chapters/ru/chapter5/3.mdx +++ b/chapters/ru/chapter5/3.mdx @@ -122,7 +122,7 @@ def filter_nones(x): lambda : ``` -где `lambda` - одно из [ключевых](https://docs.python.org/3/reference/lexical_analysis.html#keywords) слов Python, а `` - список или множество разделенных запятой значений, которые пойдут на вход функции, и `` задает операции, которые вы хотите применить к аргументам. Например, мы можем задать простую лямбда-функцию, которая возводит в квадрат числа: +где `lambda` - одно из [ключевых](https://docs.python.org/3/reference/lexical_analysis#keywords) слов Python, а `` - список или множество разделенных запятой значений, которые пойдут на вход функции, и `` задает операции, которые вы хотите применить к аргументам. Например, мы можем задать простую лямбда-функцию, которая возводит в квадрат числа: ``` lambda x : x * x @@ -238,7 +238,7 @@ print(drug_dataset.num_rows) -✏️ **Попробуйте!** Используйте функцию `Dataset.sort()` для проверки наиболее длинных отзывов. Изучите [документацию](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) чтобы понять, какой аргумент нужно передать в функцию, чтобы сортировка произошла в убывающем порядке. +✏️ **Попробуйте!** Используйте функцию `Dataset.sort()` для проверки наиболее длинных отзывов. Изучите [документацию](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) чтобы понять, какой аргумент нужно передать в функцию, чтобы сортировка произошла в убывающем порядке. @@ -385,9 +385,9 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -О, нет! Не сработало! Почему? Посмотрим на ошибку: несовпадение в длинах, один из которых длиной 1463, а другой – 1000. Если вы обратитесь в [документацию](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) `Dataset.map()`, вы можете увидеть, что одно из этих чисел – число объектов, поданных на вход функции, а другое – +О, нет! Не сработало! Почему? Посмотрим на ошибку: несовпадение в длинах, один из которых длиной 1463, а другой – 1000. Если вы обратитесь в [документацию](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) `Dataset.map()`, вы можете увидеть, что одно из этих чисел – число объектов, поданных на вход функции, а другое – -Oh no! That didn't work! Why not? Looking at the error message will give us a clue: there is a mismatch in the lengths of one of the columns, one being of length 1,463 and the other of length 1,000. If you've looked at the [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), you may recall that it's the number of samples passed to the function that we are mapping; here those 1,000 examples gave 1,463 new features, resulting in a shape error. +Oh no! That didn't work! Why not? Looking at the error message will give us a clue: there is a mismatch in the lengths of one of the columns, one being of length 1,463 and the other of length 1,000. If you've looked at the [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map), you may recall that it's the number of samples passed to the function that we are mapping; here those 1,000 examples gave 1,463 new features, resulting in a shape error. Проблема заключается в том, что мы пытаемся смешать два разных датасета разной размерности: число колонок датасета `drug_dataset` равняется 1000, а нужный нам `tokenized_dataset` имеет 1463 колонки. Чтобы избежать этой ошибки, необходимо удалить несколько столбцов из старого датасета и сделать оба датасета одинакового размера. Мы можем достичь этого с помощью аргумента `remove_columns`: diff --git a/chapters/ru/chapter5/4.mdx b/chapters/ru/chapter5/4.mdx index d96ca1b35..324170caa 100644 --- a/chapters/ru/chapter5/4.mdx +++ b/chapters/ru/chapter5/4.mdx @@ -45,7 +45,7 @@ Dataset({ -✎ По умолчанию 🤗 Datasets распаковывает файлы, необходимые для загрузки набора данных. Если вы хотите сохранить место на жестком диске, вы можете передать `DownloadConfig(delete_extracted=True)` в аргумент `download_config` функции `load_dataset()`. Дополнительные сведения см. в [документации](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig). +✎ По умолчанию 🤗 Datasets распаковывает файлы, необходимые для загрузки набора данных. Если вы хотите сохранить место на жестком диске, вы можете передать `DownloadConfig(delete_extracted=True)` в аргумент `download_config` функции `load_dataset()`. Дополнительные сведения см. в [документации](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig). diff --git a/chapters/ru/chapter5/6.mdx b/chapters/ru/chapter5/6.mdx index b238ba8a9..70a52449d 100644 --- a/chapters/ru/chapter5/6.mdx +++ b/chapters/ru/chapter5/6.mdx @@ -190,7 +190,7 @@ Dataset({ -✏️ **Попробуйте!** Посмотрите, сможете ли вы использовать `Dataset.map()`, чтобы развернуть столбец `comments` столбца `issues_dataset` _без_ использования Pandas. Это немного сложно; вы можете найти раздел ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) документации 🤗 Datasets, полезным для этой задачи. +✏️ **Попробуйте!** Посмотрите, сможете ли вы использовать `Dataset.map()`, чтобы развернуть столбец `comments` столбца `issues_dataset` _без_ использования Pandas. Это немного сложно; вы можете найти раздел ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) документации 🤗 Datasets, полезным для этой задачи. diff --git a/chapters/ru/chapter6/8.mdx b/chapters/ru/chapter6/8.mdx index 191e1d2f4..6403a9ef5 100644 --- a/chapters/ru/chapter6/8.mdx +++ b/chapters/ru/chapter6/8.mdx @@ -27,14 +27,14 @@ Точнее, библиотека построена вокруг центрального класса `Tokenizer`, а строительные блоки сгруппированы в подмодули: -- `normalizers` содержит все возможные типы нормализаторов текста `Normalizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). -- `pre_tokenizers` содержит все возможные типы предварительных токенизаторов `PreTokenizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). -- `models` содержит различные типы моделей `Model`, которые вы можете использовать, такие как `BPE`, `WordPiece` и `Unigram` (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). -- `trainers` содержит все различные типы `Trainer`, которые вы можете использовать для обучения модели на корпусе (по одному на каждый тип модели; полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). -- `post_processors` содержит различные типы постпроцессоров `PostProcessor`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). -- `decoders` содержит различные типы декодеров `Decoder`, которые вы можете использовать для декодирования результатов токенизации (полный список [здесь](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). - -Весь список блоков вы можете найти [здесь](https://huggingface.co/docs/tokenizers/python/latest/components.html). +- `normalizers` содержит все возможные типы нормализаторов текста `Normalizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/api/normalizers)). +- `pre_tokenizers` содержит все возможные типы предварительных токенизаторов `PreTokenizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)). +- `models` содержит различные типы моделей `Model`, которые вы можете использовать, такие как `BPE`, `WordPiece` и `Unigram` (полный список [здесь](https://huggingface.co/docs/tokenizers/api/models)). +- `trainers` содержит все различные типы `Trainer`, которые вы можете использовать для обучения модели на корпусе (по одному на каждый тип модели; полный список [здесь](https://huggingface.co/docs/tokenizers/api/trainers)). +- `post_processors` содержит различные типы постпроцессоров `PostProcessor`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/api/post-processors)). +- `decoders` содержит различные типы декодеров `Decoder`, которые вы можете использовать для декодирования результатов токенизации (полный список [здесь](https://huggingface.co/docs/tokenizers/components#decoders)). + +Весь список блоков вы можете найти [здесь](https://huggingface.co/docs/tokenizers/components). ## Получение корпуса текста[[acquiring-a-corpus]] diff --git a/chapters/th/chapter3/2.mdx b/chapters/th/chapter3/2.mdx index 73f8ec8cf..7e33dd154 100644 --- a/chapters/th/chapter3/2.mdx +++ b/chapters/th/chapter3/2.mdx @@ -235,7 +235,7 @@ tokenized_dataset = tokenizer( ซึ่งการเขียนคำสั่งแบบนี้ก็ได้ผลลัพธ์ที่ถูกต้อง แต่จะมีจุดด้อยคือการทำแบบนี้จะได้ผลลัพธ์ออกมาเป็น dictionary (โดยมี keys ต่าง ๆ คือ `input_ids`, `attention_mask` และ `token_type_ids` และมี values เป็น lists ของ lists) วิธีการนี้จะใช้การได้ก็ต่อเมื่อคอมพิวเตอร์ของคุณมี RAM เพียงพอที่จะเก็บข้อมูลของทั้งชุดข้อมูลในตอนที่ทำการ tokenize ชุดข้อมูลทั้งหมด (ในขณะที่ dataset ที่ได้จากไลบรารี่ 🤗 Datasets จะเป็นไฟล์ [Apache Arrow](https://arrow.apache.org/) ซึ่งจะเก็บข้อมูลไว้ใน disk คุณจึงสามารถโหลดเฉพาะข้อมูลที่ต้องการมาเก็บไว้ใน memory ได้) -เพื่อให้ข้อมูลของเรายังเป็นข้อมูลชนิด dataset เราจะใช้เมธอด [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) ซึ่งจะช่วยให้เราเลือกได้ว่าเราจะทำการประมวลผลอื่น ๆ นอกเหนือจากการ tokenize หรือไม่ โดยเมธอด `map()` ทำงานโดยการเรียกใช้ฟังก์ชั่นกับแต่ละ element ของชุดข้อมูล เรามาสร้างฟังก์ชั่นสำหรับ tokenize ข้อมูลของเรากันก่อน: +เพื่อให้ข้อมูลของเรายังเป็นข้อมูลชนิด dataset เราจะใช้เมธอด [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) ซึ่งจะช่วยให้เราเลือกได้ว่าเราจะทำการประมวลผลอื่น ๆ นอกเหนือจากการ tokenize หรือไม่ โดยเมธอด `map()` ทำงานโดยการเรียกใช้ฟังก์ชั่นกับแต่ละ element ของชุดข้อมูล เรามาสร้างฟังก์ชั่นสำหรับ tokenize ข้อมูลของเรากันก่อน: ```py def tokenize_function(example): diff --git a/chapters/th/chapter6/8.mdx b/chapters/th/chapter6/8.mdx index 30369b8b3..5d7e90c33 100644 --- a/chapters/th/chapter6/8.mdx +++ b/chapters/th/chapter6/8.mdx @@ -29,14 +29,14 @@ library นี้ ประกอบด้วยส่วนหลักคือ `Tokenizer` class ที่มีส่วนประกอบย่อยสำคัญอื่นๆ แบ่งเป็นหลาย submodules -- `normalizers` ประกอบไปด้วย `Normalizer` หลายประเภทที่คุณสามารถใช้ได้ (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). -- `pre_tokenizers` ประกอบไปด้วย `PreTokenizer` หลายประเภทที่คุณสามารถใช้ได้ (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). -- `models` ประกอบไปด้วย `Model` หลายประเภทที่คุณสามารถใช้ได้ เช่น `BPE`, `WordPiece`, และ `Unigram` (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). -- `trainers` ประกอบไปด้วย `Trainer` หลายประเภทที่คุณสามารถใช้เพื่อเทรนโมเดลด้วย corpus ที่มีได้ (แต่ละโมเดลจะมีเทรนเนอร์อย่างละตัว; รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). -- `post_processors` ประกอบไปด้วย `PostProcessor` หลายประเภทที่คุณสามารถใช้ได้ (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)) -- `decoders` ประกอบไปด้วย `Decoder` หลายประเภทที่ใช้เพื่อ decode ผลลัพธ์จากการ tokenization (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)) - -คุณสามารถดูรายชื่อของส่วนประกอบสำคัญๆต่างๆได้[ที่นี่](https://huggingface.co/docs/tokenizers/python/latest/components.html) +- `normalizers` ประกอบไปด้วย `Normalizer` หลายประเภทที่คุณสามารถใช้ได้ (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/api/normalizers)). +- `pre_tokenizers` ประกอบไปด้วย `PreTokenizer` หลายประเภทที่คุณสามารถใช้ได้ (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)). +- `models` ประกอบไปด้วย `Model` หลายประเภทที่คุณสามารถใช้ได้ เช่น `BPE`, `WordPiece`, และ `Unigram` (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/api/models)). +- `trainers` ประกอบไปด้วย `Trainer` หลายประเภทที่คุณสามารถใช้เพื่อเทรนโมเดลด้วย corpus ที่มีได้ (แต่ละโมเดลจะมีเทรนเนอร์อย่างละตัว; รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/api/trainers)). +- `post_processors` ประกอบไปด้วย `PostProcessor` หลายประเภทที่คุณสามารถใช้ได้ (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/api/post-processors)) +- `decoders` ประกอบไปด้วย `Decoder` หลายประเภทที่ใช้เพื่อ decode ผลลัพธ์จากการ tokenization (รายชื่อทั้งหมดดูได้[ที่นี่](https://huggingface.co/docs/tokenizers/components#decoders)) + +คุณสามารถดูรายชื่อของส่วนประกอบสำคัญๆต่างๆได้[ที่นี่](https://huggingface.co/docs/tokenizers/components) ## การโหลด corpus diff --git a/chapters/vi/chapter3/2.mdx b/chapters/vi/chapter3/2.mdx index e04c61e6d..3d2b3af2d 100644 --- a/chapters/vi/chapter3/2.mdx +++ b/chapters/vi/chapter3/2.mdx @@ -235,7 +235,7 @@ tokenized_dataset = tokenizer( Điều này hoạt động tốt, nhưng nó có nhược điểm là trả về từ điển (với các khóa của chúng tôi, `input_ids`, `attention_mask` và `token_type_ids`, và các giá trị là danh sách các danh sách). Nó cũng sẽ chỉ hoạt động nếu bạn có đủ RAM để lưu trữ toàn bộ tập dữ liệu của mình trong quá trình tokenize (trong khi các tập dữ liệu từ thư viện 🤗 Datasets là các tệp [Apache Arrow](https://arrow.apache.org/) được lưu trữ trên đĩa, vì vậy bạn chỉ giữ các mẫu bạn yêu cầu đã tải trong bộ nhớ). -Để giữ dữ liệu dưới dạng tập dữ liệu, chúng ta sẽ sử dụng phương thức [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map). Điều này cũng cho phép chúng ta linh hoạt hơn, nếu chúng ta cần thực hiện nhiều tiền xử lý hơn là chỉ tokenize. Phương thức `map()` hoạt động bằng cách áp dụng một hàm trên mỗi phần tử của tập dữ liệu, vì vậy hãy xác định một hàm tokenize các đầu vào của chúng ta: +Để giữ dữ liệu dưới dạng tập dữ liệu, chúng ta sẽ sử dụng phương thức [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map). Điều này cũng cho phép chúng ta linh hoạt hơn, nếu chúng ta cần thực hiện nhiều tiền xử lý hơn là chỉ tokenize. Phương thức `map()` hoạt động bằng cách áp dụng một hàm trên mỗi phần tử của tập dữ liệu, vì vậy hãy xác định một hàm tokenize các đầu vào của chúng ta: ```py def tokenize_function(example): diff --git a/chapters/vi/chapter5/2.mdx b/chapters/vi/chapter5/2.mdx index 25f910110..660739c0a 100644 --- a/chapters/vi/chapter5/2.mdx +++ b/chapters/vi/chapter5/2.mdx @@ -128,7 +128,7 @@ DatasetDict({ -Tham số `data_files` của hàm `load_dataset()` khá linh hoạt và có thể là một đường dẫn tệp duy nhất, danh sách các đường dẫn tệp hoặc từ điển ánh xạ các tên tách thành đường dẫn tệp. Bạn cũng có thể tập hợp các tệp phù hợp với một mẫu được chỉ định theo các quy tắc được sử dụng bởi Unix shell (ví dụ: bạn có thể tổng hợp tất cả các tệp JSON trong một thư mục dưới dạng một lần tách duy nhất bằng cách đặt `data_files="*.json"`). Xem [tài liệu](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) 🤗 Datasets để biết thêm chi tiết. +Tham số `data_files` của hàm `load_dataset()` khá linh hoạt và có thể là một đường dẫn tệp duy nhất, danh sách các đường dẫn tệp hoặc từ điển ánh xạ các tên tách thành đường dẫn tệp. Bạn cũng có thể tập hợp các tệp phù hợp với một mẫu được chỉ định theo các quy tắc được sử dụng bởi Unix shell (ví dụ: bạn có thể tổng hợp tất cả các tệp JSON trong một thư mục dưới dạng một lần tách duy nhất bằng cách đặt `data_files="*.json"`). Xem [tài liệu](https://huggingface.co/docs/datasets/loading#local-and-remote-files) 🤗 Datasets để biết thêm chi tiết. @@ -160,6 +160,6 @@ squad_it_dataset = load_dataset("json", data_files=data_files, field="data") -✏️ **Thử nghiệm thôi!** Chọn một tập dữ liệu khác được lưu trữ trên GitHub hoặc [Kho lưu trữ Học Máy UCI](https://archive.ics.uci.edu/ml/index.php) và thử tải nó cả cục bộ và từ xa bằng cách sử dụng các kỹ thuật đã giới thiệu ở trên. Để có điểm thưởng, hãy thử tải tập dữ liệu được lưu trữ ở định dạng CSV hoặc dạng văn bản (xem [tài liệu](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) để biết thêm thông tin trên các định dạng này). +✏️ **Thử nghiệm thôi!** Chọn một tập dữ liệu khác được lưu trữ trên GitHub hoặc [Kho lưu trữ Học Máy UCI](https://archive.ics.uci.edu/ml/index.php) và thử tải nó cả cục bộ và từ xa bằng cách sử dụng các kỹ thuật đã giới thiệu ở trên. Để có điểm thưởng, hãy thử tải tập dữ liệu được lưu trữ ở định dạng CSV hoặc dạng văn bản (xem [tài liệu](https://huggingface.co/docs/datasets/loading#local-and-remote-files) để biết thêm thông tin trên các định dạng này). diff --git a/chapters/vi/chapter5/3.mdx b/chapters/vi/chapter5/3.mdx index 70eb79d19..1c0035536 100644 --- a/chapters/vi/chapter5/3.mdx +++ b/chapters/vi/chapter5/3.mdx @@ -237,7 +237,7 @@ Như bạn có thể thấy, điều này đã loại bỏ khoảng 15% bài đ -✏️ **Thử nghiệm thôi!** Sử dụng hàm `Dataset.sort()` để kiểm tra các bài đánh giá có số lượng từ lớn nhất. Tham khảo [tài liệu](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) để biết bạn cần sử dụng tham số nào để sắp xếp các bài đánh giá theo thứ tự giảm dần. +✏️ **Thử nghiệm thôi!** Sử dụng hàm `Dataset.sort()` để kiểm tra các bài đánh giá có số lượng từ lớn nhất. Tham khảo [tài liệu](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) để biết bạn cần sử dụng tham số nào để sắp xếp các bài đánh giá theo thứ tự giảm dần. @@ -384,7 +384,7 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -Ôi không! Nó đã không hoạt động! Tại sao không? Nhìn vào thông báo lỗi sẽ cho chúng ta manh mối: có sự không khớp về độ dài của một trong các cột, một cột có độ dài 1,463 và cột còn lại có độ dài 1,000. Nếu bạn đã xem [tài liệu](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) về `Dataset.map()`, bạn có thể nhớ rằng đó là số các mẫu được truyền vào hàm mà chúng ta đang ánh xạ; ở đây 1,000 mẫu đó đã cung cấp 1,463 đặc trưng mới, dẫn đến lỗi hình dạng. +Ôi không! Nó đã không hoạt động! Tại sao không? Nhìn vào thông báo lỗi sẽ cho chúng ta manh mối: có sự không khớp về độ dài của một trong các cột, một cột có độ dài 1,463 và cột còn lại có độ dài 1,000. Nếu bạn đã xem [tài liệu](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) về `Dataset.map()`, bạn có thể nhớ rằng đó là số các mẫu được truyền vào hàm mà chúng ta đang ánh xạ; ở đây 1,000 mẫu đó đã cung cấp 1,463 đặc trưng mới, dẫn đến lỗi hình dạng. Vấn đề là chúng ta đang cố gắng kết hợp hai tập dữ liệu khác nhau với các kích thước khác nhau: cột `drug_dataset` sẽ có một số mẫu nhất định (lỗi phía chúng ta là 1,000), nhưng `tokenized_dataset` mà chúng ta đang xây dựng sẽ có nhiều hơn (1,463 trong thông báo lỗi). Điều này không hoạt động đối với `Dataset`, vì vậy chúng ta cần xóa các cột khỏi tập dữ liệu cũ hoặc làm cho chúng có cùng kích thước với chúng trong tập dữ liệu mới. Chúng ta có thể thực hiện điều đầu thông qua tham số `remove_columns`: diff --git a/chapters/vi/chapter5/4.mdx b/chapters/vi/chapter5/4.mdx index 381224111..c105b0b28 100644 --- a/chapters/vi/chapter5/4.mdx +++ b/chapters/vi/chapter5/4.mdx @@ -54,7 +54,7 @@ Chúng ta có thể thấy rằng có 15,518,009 hàng và 2 cột trong tập d -✎ Theo mặc định, 🤗 Datasets sẽ giải nén các tệp cần thiết để tải tập dữ liệu. Nếu bạn muốn bảo toàn dung lượng ổ cứng, bạn có thể truyền `DownloadConfig(delete_extracted=True)` vào tham số `download_config` của `load_dataset()`. Xem [tài liệu](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) để biết thêm chi tiết. +✎ Theo mặc định, 🤗 Datasets sẽ giải nén các tệp cần thiết để tải tập dữ liệu. Nếu bạn muốn bảo toàn dung lượng ổ cứng, bạn có thể truyền `DownloadConfig(delete_extracted=True)` vào tham số `download_config` của `load_dataset()`. Xem [tài liệu](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig) để biết thêm chi tiết. diff --git a/chapters/vi/chapter5/5.mdx b/chapters/vi/chapter5/5.mdx index d8faafb4f..9b05d75d6 100644 --- a/chapters/vi/chapter5/5.mdx +++ b/chapters/vi/chapter5/5.mdx @@ -435,7 +435,7 @@ Tuyệt vời, chúng ta đã đưa tập dữ liệu của mình vào Hub và n -💡 Bạn cũng có thể tải tập dữ liệu lên Hugging Face Hub trực tiếp từ thiết bị đầu cuối bằng cách sử dụng `huggingface-cli` và một chút phép thuật từ Git. Tham khảo [hướng dẫn 🤗 Datasets](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) để biết chi tiết về cách thực hiện việc này. +💡 Bạn cũng có thể tải tập dữ liệu lên Hugging Face Hub trực tiếp từ thiết bị đầu cuối bằng cách sử dụng `huggingface-cli` và một chút phép thuật từ Git. Tham khảo [hướng dẫn 🤗 Datasets](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) để biết chi tiết về cách thực hiện việc này. diff --git a/chapters/vi/chapter5/6.mdx b/chapters/vi/chapter5/6.mdx index cfaca863b..6c29fff33 100644 --- a/chapters/vi/chapter5/6.mdx +++ b/chapters/vi/chapter5/6.mdx @@ -190,7 +190,7 @@ Dataset({ -✏️ **Thử nghiệm thôi!** Cùng xem liệu bạn có thể sử dụng `Dataset.map()` để khám phá cột `comments` của `issues_dataset` _mà không cần_ sử dụng Pandas hay không. Nó sẽ hơi khó khăn một chút; bạn có thể xem phần ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) của tài liệu 🤗 Datasets, một tài liệu hữu ích cho tác vụ này. +✏️ **Thử nghiệm thôi!** Cùng xem liệu bạn có thể sử dụng `Dataset.map()` để khám phá cột `comments` của `issues_dataset` _mà không cần_ sử dụng Pandas hay không. Nó sẽ hơi khó khăn một chút; bạn có thể xem phần ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) của tài liệu 🤗 Datasets, một tài liệu hữu ích cho tác vụ này. diff --git a/chapters/vi/chapter6/8.mdx b/chapters/vi/chapter6/8.mdx index 7ce6fd78e..aa93a0fed 100644 --- a/chapters/vi/chapter6/8.mdx +++ b/chapters/vi/chapter6/8.mdx @@ -25,14 +25,14 @@ Thư viện 🤗 Tokenizers đã được xây dựng để cung cấp nhiều s Chính xác hơn, thư viện được xây dựng tập trung vào lớp `Tokenizer` với các khối được tập hợp lại trong các mô-đun con: -- `normalizers` chứa tất cả các kiểu `Normalizer` bạn có thể sử dụng (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers)). -- `pre_tokenizers` chứa tất cả các kiểu `PreTokenizer` bạn có thể sử dụng (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers)). -- `models` chứa tất cả các kiểu `Model` bạn có thể sử dụng, như `BPE`, `WordPiece`, and `Unigram` (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models)). -- `trainers` chứa tất cả các kiểu `Trainer` khác nhau bạn có thể sử dụng để huấn luyện mô hình của bạn trên kho ngữ liệu (một cho mỗi loại mô hình; hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers)). -- `post_processors` chứa tất cả các kiểu `PostProcessor` bạn có thể sử dụng (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors)). -- `decoders` chứa tất cả các kiểu `Decoder` đa dạng bạn có thể sử dụng để giải mã đầu ra của tokenize (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders)). - -Bạn có thể tìm được toàn bộ danh sách các khối tại [đây](https://huggingface.co/docs/tokenizers/python/latest/components.html). +- `normalizers` chứa tất cả các kiểu `Normalizer` bạn có thể sử dụng (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/api/normalizers)). +- `pre_tokenizers` chứa tất cả các kiểu `PreTokenizer` bạn có thể sử dụng (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)). +- `models` chứa tất cả các kiểu `Model` bạn có thể sử dụng, như `BPE`, `WordPiece`, and `Unigram` (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/api/models)). +- `trainers` chứa tất cả các kiểu `Trainer` khác nhau bạn có thể sử dụng để huấn luyện mô hình của bạn trên kho ngữ liệu (một cho mỗi loại mô hình; hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/api/trainers)). +- `post_processors` chứa tất cả các kiểu `PostProcessor` bạn có thể sử dụng (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/api/post-processors)). +- `decoders` chứa tất cả các kiểu `Decoder` đa dạng bạn có thể sử dụng để giải mã đầu ra của tokenize (hoàn thiện danh sách tại [đây](https://huggingface.co/docs/tokenizers/components#decoders)). + +Bạn có thể tìm được toàn bộ danh sách các khối tại [đây](https://huggingface.co/docs/tokenizers/components). ## Thu thập một kho ngữ liệu diff --git a/chapters/zh-CN/chapter3/2.mdx b/chapters/zh-CN/chapter3/2.mdx index 57e649e65..fbe6d00d3 100644 --- a/chapters/zh-CN/chapter3/2.mdx +++ b/chapters/zh-CN/chapter3/2.mdx @@ -235,7 +235,7 @@ tokenized_dataset = tokenizer( 这很有效,但它的缺点是返回字典(字典的键是**输入词id(input_ids)** , **注意力遮罩(attention_mask)** 和 **类型标记ID(token_type_ids)**,字典的值是键所对应值的列表)。而且只有当您在转换过程中有足够的内存来存储整个数据集时才不会出错(而🤗数据集库中的数据集是以[Apache Arrow](https://arrow.apache.org/)文件存储在磁盘上,因此您只需将接下来要用的数据加载在内存中,因此会对内存容量的需求要低一些)。 -为了将数据保存为数据集,我们将使用[Dataset.map()](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map)方法,如果我们需要做更多的预处理而不仅仅是标记化,那么这也给了我们一些额外的自定义的方法。这个方法的工作原理是在数据集的每个元素上应用一个函数,因此让我们定义一个标记输入的函数: +为了将数据保存为数据集,我们将使用[Dataset.map()](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map)方法,如果我们需要做更多的预处理而不仅仅是标记化,那么这也给了我们一些额外的自定义的方法。这个方法的工作原理是在数据集的每个元素上应用一个函数,因此让我们定义一个标记输入的函数: ```py def tokenize_function(example): diff --git a/chapters/zh-CN/chapter5/2.mdx b/chapters/zh-CN/chapter5/2.mdx index 95b8691b1..555e35f70 100644 --- a/chapters/zh-CN/chapter5/2.mdx +++ b/chapters/zh-CN/chapter5/2.mdx @@ -160,7 +160,7 @@ squad_it_dataset = load_dataset("json", data_files=data_files, field="data") -✏️ **试试看!** 选择托管在GitHub或[UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php)上的另一个数据集并尝试使用上述技术在本地和远程加载它。另外,可以尝试加载CSV或者文本格式存储的数据集(有关这些格式的更多信息,请参阅[文档](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files))。 +✏️ **试试看!** 选择托管在GitHub或[UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php)上的另一个数据集并尝试使用上述技术在本地和远程加载它。另外,可以尝试加载CSV或者文本格式存储的数据集(有关这些格式的更多信息,请参阅[文档](https://huggingface.co/docs/datasets/loading#local-and-remote-files))。 diff --git a/chapters/zh-CN/chapter5/4.mdx b/chapters/zh-CN/chapter5/4.mdx index 70ef713ca..bf34117ff 100644 --- a/chapters/zh-CN/chapter5/4.mdx +++ b/chapters/zh-CN/chapter5/4.mdx @@ -46,7 +46,7 @@ Dataset({ -✎ 默认情况下, 🤗 Datasets 会自动解压加载数据集所需的文件。 如果你想保留硬盘空间, 你可以传递 `DownloadConfig(delete_extracted=True)` 到 `download_config` 的 `load_dataset()`参数. 有关更多详细信息, 请参阅文档](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig)。 +✎ 默认情况下, 🤗 Datasets 会自动解压加载数据集所需的文件。 如果你想保留硬盘空间, 你可以传递 `DownloadConfig(delete_extracted=True)` 到 `download_config` 的 `load_dataset()`参数. 有关更多详细信息, 请参阅文档](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig)。 diff --git a/chapters/zh-CN/chapter5/5.mdx b/chapters/zh-CN/chapter5/5.mdx index a18ee94f4..f6454f914 100644 --- a/chapters/zh-CN/chapter5/5.mdx +++ b/chapters/zh-CN/chapter5/5.mdx @@ -360,7 +360,7 @@ Dataset({ -💡 您还可以使用一些 Git 魔法直接从终端将数据集上传到 Hugging Face Hub。有关如何执行此操作的详细信息,请参阅 [🤗 Datasets guide](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) 指南。 +💡 您还可以使用一些 Git 魔法直接从终端将数据集上传到 Hugging Face Hub。有关如何执行此操作的详细信息,请参阅 [🤗 Datasets guide](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) 指南。 diff --git a/chapters/zh-CN/chapter5/6.mdx b/chapters/zh-CN/chapter5/6.mdx index 8de5fb335..f3a1044e9 100644 --- a/chapters/zh-CN/chapter5/6.mdx +++ b/chapters/zh-CN/chapter5/6.mdx @@ -177,7 +177,7 @@ Dataset({ -✏️ **Try it out!** 看看能不能不用pandas就可以完成列的扩充; 这有点棘手; 你可能会发现 🤗 Datasets 文档的 ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) 对这个任务很有用。 +✏️ **Try it out!** 看看能不能不用pandas就可以完成列的扩充; 这有点棘手; 你可能会发现 🤗 Datasets 文档的 ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) 对这个任务很有用。 diff --git a/chapters/zh-CN/chapter6/8.mdx b/chapters/zh-CN/chapter6/8.mdx index 7e6802bdc..73e07c7fa 100644 --- a/chapters/zh-CN/chapter6/8.mdx +++ b/chapters/zh-CN/chapter6/8.mdx @@ -27,14 +27,14 @@ 更准确地说,该库是围绕一个中央“Tokenizer”类构建的,构建这个类的每一部分可以在子模块的列表中重新组合: -- `normalizers` 包含你可以使用的所有可能的Normalizer类型(完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers))。 -- `pre_tokenizesr` 包含您可以使用的所有可能的PreTokenizer类型(完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers))。 -- `models` 包含您可以使用的各种类型的Model,如BPE、WordPiece和Unigram(完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models))。 -- `trainers` 包含所有不同类型的 trainer,你可以使用一个语料库训练你的模型(每种模型一个;完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers))。 -- `post_processors` 包含你可以使用的各种类型的PostProcessor(完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors))。 -- `decoders` 包含各种类型的Decoder,可以用来解码标记化的输出(完整列表[在这里](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders))。 - -您可以[在这里](https://huggingface.co/docs/tokenizers/python/latest/components.html)找到完整的模块列表。 +- `normalizers` 包含你可以使用的所有可能的Normalizer类型(完整列表[在这里](https://huggingface.co/docs/tokenizers/api/normalizers))。 +- `pre_tokenizesr` 包含您可以使用的所有可能的PreTokenizer类型(完整列表[在这里](https://huggingface.co/docs/tokenizers/api/pre-tokenizers))。 +- `models` 包含您可以使用的各种类型的Model,如BPE、WordPiece和Unigram(完整列表[在这里](https://huggingface.co/docs/tokenizers/api/models))。 +- `trainers` 包含所有不同类型的 trainer,你可以使用一个语料库训练你的模型(每种模型一个;完整列表[在这里](https://huggingface.co/docs/tokenizers/api/trainers))。 +- `post_processors` 包含你可以使用的各种类型的PostProcessor(完整列表[在这里](https://huggingface.co/docs/tokenizers/api/post-processors))。 +- `decoders` 包含各种类型的Decoder,可以用来解码标记化的输出(完整列表[在这里](https://huggingface.co/docs/tokenizers/components#decoders))。 + +您可以[在这里](https://huggingface.co/docs/tokenizers/components)找到完整的模块列表。 ## 获取语​​料库 [[获取语​​料库]] diff --git a/chapters/zh-TW/chapter3/2.mdx b/chapters/zh-TW/chapter3/2.mdx index 4970fb9eb..5dd10b0a0 100644 --- a/chapters/zh-TW/chapter3/2.mdx +++ b/chapters/zh-TW/chapter3/2.mdx @@ -235,7 +235,7 @@ tokenized_dataset = tokenizer( 這很有效,但它的缺點是返回字典(字典的鍵是**輸入詞id(input_ids)** , **注意力遮罩(attention_mask)** 和 **類型標記ID(token_type_ids)**,字典的值是鍵所對應值的列表)。而且只有當您在轉換過程中有足夠的內存來存儲整個數據集時才不會出錯(而🤗數據集庫中的數據集是以[Apache Arrow](https://arrow.apache.org/)文件存儲在磁盤上,因此您只需將接下來要用的數據加載在內存中,因此會對內存容量的需求要低一些)。 -為了將數據保存為數據集,我們將使用[Dataset.map()](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map)方法,如果我們需要做更多的預處理而不僅僅是標記化,那麼這也給了我們一些額外的自定義的方法。這個方法的工作原理是在數據集的每個元素上應用一個函數,因此讓我們定義一個標記輸入的函數: +為了將數據保存為數據集,我們將使用[Dataset.map()](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map)方法,如果我們需要做更多的預處理而不僅僅是標記化,那麼這也給了我們一些額外的自定義的方法。這個方法的工作原理是在數據集的每個元素上應用一個函數,因此讓我們定義一個標記輸入的函數: ```py def tokenize_function(example): diff --git a/chapters/zh-TW/chapter5/2.mdx b/chapters/zh-TW/chapter5/2.mdx index f47239575..90cbfdc43 100644 --- a/chapters/zh-TW/chapter5/2.mdx +++ b/chapters/zh-TW/chapter5/2.mdx @@ -160,7 +160,7 @@ squad_it_dataset = load_dataset("json", data_files=data_files, field="data") -✏️ **試試看!** 選擇託管在GitHub或[UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php)上的另一個數據集並嘗試使用上述技術在本地和遠程加載它。另外,可以嘗試加載CSV或者文本格式存儲的數據集(有關這些格式的更多信息,請參閱[文檔](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files))。 +✏️ **試試看!** 選擇託管在GitHub或[UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php)上的另一個數據集並嘗試使用上述技術在本地和遠程加載它。另外,可以嘗試加載CSV或者文本格式存儲的數據集(有關這些格式的更多信息,請參閱[文檔](https://huggingface.co/docs/datasets/loading#local-and-remote-files))。 diff --git a/chapters/zh-TW/chapter5/4.mdx b/chapters/zh-TW/chapter5/4.mdx index 4cd7ae730..96e11bb8c 100644 --- a/chapters/zh-TW/chapter5/4.mdx +++ b/chapters/zh-TW/chapter5/4.mdx @@ -46,7 +46,7 @@ Dataset({ -✎ 默認情況下, 🤗 Datasets 會自動解壓加載數據集所需的文件。 如果你想保留硬盤空間, 你可以傳遞 `DownloadConfig(delete_extracted=True)` 到 `download_config` 的 `load_dataset()`參數. 有關更多詳細信息, 請參閱文檔](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig)。 +✎ 默認情況下, 🤗 Datasets 會自動解壓加載數據集所需的文件。 如果你想保留硬盤空間, 你可以傳遞 `DownloadConfig(delete_extracted=True)` 到 `download_config` 的 `load_dataset()`參數. 有關更多詳細信息, 請參閱文檔](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig)。 diff --git a/chapters/zh-TW/chapter5/5.mdx b/chapters/zh-TW/chapter5/5.mdx index f65b1c0e2..6f9953910 100644 --- a/chapters/zh-TW/chapter5/5.mdx +++ b/chapters/zh-TW/chapter5/5.mdx @@ -423,7 +423,7 @@ Dataset({ -💡 您還可以使用一些 Git 魔法直接從終端將數據集上傳到 Hugging Face Hub。有關如何執行此操作的詳細信息,請參閱 [🤗 Datasets guide](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) 指南。 +💡 您還可以使用一些 Git 魔法直接從終端將數據集上傳到 Hugging Face Hub。有關如何執行此操作的詳細信息,請參閱 [🤗 Datasets guide](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) 指南。 diff --git a/chapters/zh-TW/chapter5/6.mdx b/chapters/zh-TW/chapter5/6.mdx index b5646f739..24bb8e9dd 100644 --- a/chapters/zh-TW/chapter5/6.mdx +++ b/chapters/zh-TW/chapter5/6.mdx @@ -188,7 +188,7 @@ Dataset({ -✏️ **Try it out!** 看看能不能不用pandas就可以完成列的擴充; 這有點棘手; 你可能會發現 🤗 Datasets 文檔的 ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) 對這個任務很有用。 +✏️ **Try it out!** 看看能不能不用pandas就可以完成列的擴充; 這有點棘手; 你可能會發現 🤗 Datasets 文檔的 ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) 對這個任務很有用。 diff --git a/chapters/zh-TW/chapter6/8.mdx b/chapters/zh-TW/chapter6/8.mdx index 9a31a2bf1..c61e14d7f 100644 --- a/chapters/zh-TW/chapter6/8.mdx +++ b/chapters/zh-TW/chapter6/8.mdx @@ -27,14 +27,14 @@ 更準確地說,該庫是圍繞一個中央「Tokenizer」類構建的,構建這個類的每一部分可以在子模塊的列表中重新組合: -- `normalizers` 包含你可以使用的所有可能的Normalizer類型(完整列表[在這裡](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.normalizers))。 -- `pre_tokenizesr` 包含您可以使用的所有可能的PreTokenizer類型(完整列表[在這裡](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.pre_tokenizers))。 -- `models` 包含您可以使用的各種類型的Model,如BPE、WordPiece和Unigram(完整列表[在這裡](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.models))。 -- `trainers` 包含所有不同類型的 trainer,你可以使用一個語料庫訓練你的模型(每種模型一個;完整列表[在這裡](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.trainers))。 -- `post_processors` 包含你可以使用的各種類型的PostProcessor(完整列表[在這裡](https://huggingface.co/docs/tokenizers/python/latest/api/reference.html#module-tokenizers.processors))。 -- `decoders` 包含各種類型的Decoder,可以用來解碼標記化的輸出(完整列表[在這裡](https://huggingface.co/docs/tokenizers/python/latest/components.html#decoders))。 - -您可以[在這裡](https://huggingface.co/docs/tokenizers/python/latest/components.html)找到完整的模塊列表。 +- `normalizers` 包含你可以使用的所有可能的Normalizer類型(完整列表[在這裡](https://huggingface.co/docs/tokenizers/api/normalizers))。 +- `pre_tokenizesr` 包含您可以使用的所有可能的PreTokenizer類型(完整列表[在這裡](https://huggingface.co/docs/tokenizers/api/pre-tokenizers))。 +- `models` 包含您可以使用的各種類型的Model,如BPE、WordPiece和Unigram(完整列表[在這裡](https://huggingface.co/docs/tokenizers/api/models))。 +- `trainers` 包含所有不同類型的 trainer,你可以使用一個語料庫訓練你的模型(每種模型一個;完整列表[在這裡](https://huggingface.co/docs/tokenizers/api/trainers))。 +- `post_processors` 包含你可以使用的各種類型的PostProcessor(完整列表[在這裡](https://huggingface.co/docs/tokenizers/api/post-processors))。 +- `decoders` 包含各種類型的Decoder,可以用來解碼標記化的輸出(完整列表[在這裡](https://huggingface.co/docs/tokenizers/components#decoders))。 + +您可以[在這裡](https://huggingface.co/docs/tokenizers/components)找到完整的模塊列表。 ## 獲取語​​料庫 From fd856289393568988a11405ab0b95d116284ea05 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 18 Jan 2024 22:50:05 +0300 Subject: [PATCH 359/502] Finalizing the translation of chapter 7. --- chapters/ru/_toctree.yml | 9 + chapters/ru/chapter7/6.mdx | 914 +++++++++++++++++++++++++++ chapters/ru/chapter7/7.mdx | 1203 ++++++++++++++++++++++++++++++++++++ chapters/ru/chapter7/8.mdx | 22 + chapters/ru/chapter7/9.mdx | 329 ++++++++++ 5 files changed, 2477 insertions(+) create mode 100644 chapters/ru/chapter7/6.mdx create mode 100644 chapters/ru/chapter7/7.mdx create mode 100644 chapters/ru/chapter7/8.mdx create mode 100644 chapters/ru/chapter7/9.mdx diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index fa28f0fca..0ec4ac451 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -125,6 +125,15 @@ title: Перевод - local: chapter7/5 title: Суммаризация + - local: chapter7/6 + title: Обучение каузальной языковой модели с нуля + - local: chapter7/7 + title: Ответы на вопросы + - local: chapter7/8 + title: Освоение NLP + - local: chapter7/9 + title: Тест в конце главы + quiz: 7 - title: Глоссарий sections: diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx new file mode 100644 index 000000000..61e1231ad --- /dev/null +++ b/chapters/ru/chapter7/6.mdx @@ -0,0 +1,914 @@ + + +# Обучение каузальной языковой модели с нуля[[training-a-causal-language-model-from-scratch]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +До сих пор мы в основном использовали предварительно обученные модели и осуществляли их дообучение для новых случаев использования, повторно используя веса, полученные в ходе предварительного обучения. Как мы видели в [Главе 1](/course/chapter1), это принято называть _трансферным обучением_, и это очень успешная стратегия применения моделей Transformer для большинства реальных случаев использования, когда размеченных данных недостаточно. В этой главе мы применим другой подход и обучим совершенно новую модель с нуля. Это хороший подход, если у вас много данных, и они сильно отличаются от данных предварительного обучения, используемых для имеющихся моделей. Однако предварительное обучение языковой модели требует значительно больше вычислительных ресурсов, чем дообучение существующей. Примеры, когда имеет смысл обучать новую модель, включают датасеты, состоящие из музыкальных нот, молекулярных последовательностей, таких как ДНК, или языков программирования. Последние в недавнее время получили широкое распространение благодаря таким инструментам, как TabNine и GitHub's Copilot, работающим на основе модели Codex от OpenAI, которые могут генерировать длинные последовательности кода. Для решения этой задачи генерации текста лучше всего подходят авторегрессионные или каузальные языковые модели, такие как GPT-2. + +В этом разделе мы построим уменьшенную версию модели генерации кода: мы сосредоточимся на однострочных завершениях вместо полных функций или классов, используя подмножество кода Python. Работая с данными на Python, вы часто сталкиваетесь со стеком Data Science на Python, состоящем из библиотек `matplotlib`, `seaborn`, `pandas` и `scikit-learn`. При использовании этих фреймворков часто возникает необходимость поиска определенных команд, поэтому было бы неплохо, если бы мы могли использовать модель выполненяющую эти вызововы за нас. + + + +В [Главе 6] (/course/chapter6) мы создали эффективный токенизатор для обработки исходного кода Python, но нам все еще нужен крупный датасет для предварительного обучения модели. Здесь мы применим наш токенизатор к корпусу кода Python, полученному из розиториев GitHub. Затем мы воспользуемся API `Trainer` и 🤗 Accelerate для обучения модели. Приступим! + + + +На самом деле это демонстрация модели, которая была обучена и загружена в Hub с помощью кода, приведенного в этом разделе. Вы можете найти ее [здесь] (https://huggingface.co/huggingface-course/codeparrot-ds?text=plt.imshow%28). Обратите внимание, что поскольку при генерации текста происходит некоторая рандомизация, вы, вероятно, получите немного другой результат. + +## Сбор данных[[gathering-the-data]] + +Код на Python в изобилии доступен в таких репозиториях кода, как GitHub, и мы можем использовать его для создания датасета путем поиска каждого розитория Python. Именно такой подход был использован в книге [Transformers textbook](https://learning.oreilly.com/library/view/natural-language-processing/9781098136789/) для предварительного обучения большой модели GPT-2. Используя дамп GitHub объемом около 180 ГБ, содержащий примерно 20 миллионов файлов Python под названием `codeparrot`, авторы создали датасет, которым затем поделились на [Hugging Face Hub](https://huggingface.co/datasets/transformersbook/codeparrot). + +Однако обучение на полном корпусе требует много времени и вычислений, а нам нужно только подмножество датасетов, связанных со стеком data science на Python. Итак, давайте начнем с фильтрации датасета `codeparrot` по всем файлам, включающим любую из библиотек из этого стека. Из-за большого размера датасета мы хотим избежать его загрузки; вместо этого мы будем использовать функцию потоковой передачи (streaming), чтобы фильтровать его на лету. To help us filter the code samples using the libraries we mentioned earlier, we'll use the following function: + +```py +def any_keyword_in_string(string, keywords): + for keyword in keywords: + if keyword in string: + return True + return False +``` + +Давайте протестируем ее на двух примерах: + +```py +filters = ["pandas", "sklearn", "matplotlib", "seaborn"] +example_1 = "import numpy as np" +example_2 = "import pandas as pd" + +print( + any_keyword_in_string(example_1, filters), any_keyword_in_string(example_2, filters) +) +``` + +```python out +False True +``` + +Мы можем использовать ее для создания функции, которая будет передавать датасет и отфильтровывать нужные нам элементы: + +```py +from collections import defaultdict +from tqdm import tqdm +from datasets import Dataset + + +def filter_streaming_dataset(dataset, filters): + filtered_dict = defaultdict(list) + total = 0 + for sample in tqdm(iter(dataset)): + total += 1 + if any_keyword_in_string(sample["content"], filters): + for k, v in sample.items(): + filtered_dict[k].append(v) + print(f"{len(filtered_dict['content'])/total:.2%} of data after filtering.") + return Dataset.from_dict(filtered_dict) +``` + +Затем мы можем просто применить эту функцию к потоковому датасету: + +```py +# Выполнение этой ячейки займет очень много времени, поэтому ее следует пропустить и перейти к +# следующей! +from datasets import load_dataset + +split = "train" # "valid" +filters = ["pandas", "sklearn", "matplotlib", "seaborn"] + +data = load_dataset(f"transformersbook/codeparrot-{split}", split=split, streaming=True) +filtered_data = filter_streaming_dataset(data, filters) +``` + +```python out +3.26% of data after filtering. +``` + +Таким образом, у нас остается около 3% от исходного датасета, что все равно довольно много - результирующий датасет занимает 6 ГБ и состоит из 600 000 Python-скриптов! + +Фильтрация полного датасета может занять 2-3 часа в зависимости от вашей машины и пропускной способности сети. Если вы не хотите выполнять этот длительный процесс самостоятельно, мы предоставляем отфильтрованный датасет на Hub для загрузки: + +```py +from datasets import load_dataset, DatasetDict + +ds_train = load_dataset("huggingface-course/codeparrot-ds-train", split="train") +ds_valid = load_dataset("huggingface-course/codeparrot-ds-valid", split="validation") + +raw_datasets = DatasetDict( + { + "train": ds_train, # .shuffle().select(range(50000)), + "valid": ds_valid, # .shuffle().select(range(500)) + } +) + +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['repo_name', 'path', 'copies', 'size', 'content', 'license'], + num_rows: 606720 + }) + valid: Dataset({ + features: ['repo_name', 'path', 'copies', 'size', 'content', 'license'], + num_rows: 3322 + }) +}) +``` + + + +Предварительное обучение языковой модели займет некоторое время. Мы рекомендуем сначала запустить цикл обучения на выборке данных, раскомментировав две частичные строки выше, и убедиться, что обучение успешно завершено и модели сохранены. Нет ничего обиднее, чем неудачное обучение на последнем этапе из-за того, что вы забыли создать папку или из-за опечатки в конце цикла обучения! + + + +Давайте рассмотрим пример из датасета. Мы покажем только первые 200 символов каждого поля: + +```py +for key in raw_datasets["train"][0]: + print(f"{key.upper()}: {raw_datasets['train'][0][key][:200]}") +``` + +```python out +'REPO_NAME: kmike/scikit-learn' +'PATH: sklearn/utils/__init__.py' +'COPIES: 3' +'SIZE: 10094' +'''CONTENT: """ +The :mod:`sklearn.utils` module includes various utilites. +""" + +from collections import Sequence + +import numpy as np +from scipy.sparse import issparse +import warnings + +from .murmurhash import murm +LICENSE: bsd-3-clause''' +``` + +Мы видим, что поле `content` содержит код, на котором мы хотим обучить нашу модель. Теперь, когда у нас есть датасет, нам нужно подготовить тексты, чтобы они были в формате, подходящем для предварительного обучения. + +## Подготовка датасета[[preparing-the-dataset]] + + + +Первым шагом будет токенизация данных, чтобы мы могли использовать их для обучения. Поскольку наша цель - автозаполнение коротких вызовов функций, мы можем оставить размер контекста относительно небольшим. Благодаря этому мы сможем обучать модель гораздо быстрее, и она будет занимать значительно меньше памяти. Если для вашего приложения важно, чтобы контекст был больше (например, если вы хотите, чтобы модель писала юнит-тесты на основе файла с определением функции), обязательно увеличьте это число, но не забывайте, что это приведет к увеличению объема памяти GPU. Пока что давайте зафиксируем размер контекста на 128 токенов, в отличие от 1 024 или 2 048, используемых в GPT-2 или GPT-3 соответственно. + +Большинство документов содержит гораздо больше 128 токенов, поэтому простое обрезание входных данных до максимальной длины приведет к тому, что большая часть нашего датасета будет удалена. Вместо этого мы используем параметр `return_overflowing_tokens` для токенизации всего ввода и разбиения его на части, как мы делали в [Главе 6](/course/chapter6/4). Мы также будем использовать параметр `return_length`, чтобы автоматически возвращать длину каждого созданного фрагмента. Часто последний фрагмент будет меньше размера контекста, и мы избавимся от этих фрагментов, чтобы избежать проблем с дополнением; на самом деле они нам не нужны, поскольку у нас и так много данных. + +
+Chunking a large texts in several pieces. + +
+ +Давайте посмотрим, как это работает, на первых двух примерах: + +```py +from transformers import AutoTokenizer + +context_length = 128 +tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") + +outputs = tokenizer( + raw_datasets["train"][:2]["content"], + truncation=True, + max_length=context_length, + return_overflowing_tokens=True, + return_length=True, +) + +print(f"Input IDs length: {len(outputs['input_ids'])}") +print(f"Input chunk lengths: {(outputs['length'])}") +print(f"Chunk mapping: {outputs['overflow_to_sample_mapping']}") +``` + +```python out +Input IDs length: 34 +Input chunk lengths: [128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 117, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 41] +Chunk mapping: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +``` + +Из этих двух примеров видно, что в общей сложности мы получили 34 сегмента. Взглянув на длину фрагментов, мы видим, что фрагменты в конце обоих документов содержат менее 128 токенов (117 и 41, соответственно). Это лишь малая часть всех имеющихся у нас фрагментов, поэтому мы можем смело отбросить их. С помощью поля `overflow_to_sample_mapping` мы также можем восстановить, какие фрагменты принадлежали каким входным примерам. + +В этой операции мы используем удобную особенность функции `Dataset.map()` из 🤗 Datasets, которая заключается в том, что она не требует отображения один к одному; как мы видели в [разделе 3](/course/chapter7/3), мы можем создавать батч с большим или меньшим количеством элементов, чем входной батч. Это полезно при выполнении таких операций, как аугментация или фильтрация данных, которые изменяют количество элементов. В нашем случае при токенизации каждого элемента на фрагменты заданного размера контекста мы создаем много примеров из каждого документа. Нам просто нужно убедиться, что мы удалили существующие столбцы, поскольку они имеют противоречивый размер. Если бы мы хотели их сохранить, то могли бы повторить их соответствующим образом и вернуть в рамках вызова `Dataset.map()`: + +```py +def tokenize(element): + outputs = tokenizer( + element["content"], + truncation=True, + max_length=context_length, + return_overflowing_tokens=True, + return_length=True, + ) + input_batch = [] + for length, input_ids in zip(outputs["length"], outputs["input_ids"]): + if length == context_length: + input_batch.append(input_ids) + return {"input_ids": input_batch} + + +tokenized_datasets = raw_datasets.map( + tokenize, batched=True, remove_columns=raw_datasets["train"].column_names +) +tokenized_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['input_ids'], + num_rows: 16702061 + }) + valid: Dataset({ + features: ['input_ids'], + num_rows: 93164 + }) +}) +``` + +Теперь у нас есть 16,7 миллиона примеров со 128 токенами в каждом, что соответствует примерно 2,1 миллиарда токенов в общей сложности. Для сравнения, модели OpenAI GPT-3 и Codex обучены на 300 и 100 миллиардах токенов соответственно, причем модели Codex инициализируются из контрольных точек GPT-3. Наша цель в этом разделе - не конкурировать с этими моделями, которые могут генерировать длинные, связные тексты, а создать уменьшенную версию, обеспечивающую быструю функцию автозаполнения для специалистов по обработке данных. + +Теперь, когда у нас есть готовый датасет, давайте создадим модель! + + + +✏️ **Попробуйте!** Избавление от всех фрагментов, размер которых меньше размера контекста, не является большой проблемой, поскольку мы используем небольшие контекстные окна. При увеличении размера контекста (или если у вас корпус коротких документов) доля отбрасываемых фрагментов также будет расти. Более эффективный способ подготовки данных - объединить все токенизированные примеры в батч с маркером `eos_token_id` между ними, а затем выполнить фрагментацию на конкатенированных последовательностях. В качестве упражнения измените функцию `tokenize()`, чтобы использовать этот подход. Обратите внимание, что вам нужно установить `truncation=False` и удалить другие аргументы из токенизатора, чтобы получить полную последовательность идентификаторов токенов. + + + + +## Initializing a new model[[initializing-a-new-model]] + +Наш первый шаг - инициализация свежей модели GPT-2. Мы будем использовать ту же конфигурацию для нашей модели, что и для маленькой модели GPT-2, поэтому загрузим предварительно обученную конфигурацию, убедимся, что размер токенизатора соответствует размеру словарного запаса модели, и передадим идентификаторы токенов `bos` и `eos` (начало и конец последовательности): + +{#if fw === 'pt'} + +```py +from transformers import AutoTokenizer, GPT2LMHeadModel, AutoConfig + +config = AutoConfig.from_pretrained( + "gpt2", + vocab_size=len(tokenizer), + n_ctx=context_length, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, +) +``` + +С этой конфигурацией мы можем загрузить новую модель. Обратите внимание, что впервые мы не используем функцию `from_pretrained()`, поскольку фактически инициализируем модель самостоятельно: + +```py +model = GPT2LMHeadModel(config) +model_size = sum(t.numel() for t in model.parameters()) +print(f"GPT-2 size: {model_size/1000**2:.1f}M parameters") +``` + +```python out +GPT-2 size: 124.2M parameters +``` + +{:else} + +```py +from transformers import AutoTokenizer, TFGPT2LMHeadModel, AutoConfig + +config = AutoConfig.from_pretrained( + "gpt2", + vocab_size=len(tokenizer), + n_ctx=context_length, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, +) +``` + +С этой конфигурацией мы можем загрузить новую модель. Обратите внимание, что впервые мы не используем функцию `from_pretrained()`, поскольку фактически инициализируем модель самостоятельно: + +```py +model = TFGPT2LMHeadModel(config) +model(model.dummy_inputs) # Builds the model +model.summary() +``` + +```python out +_________________________________________________________________ +Layer (type) Output Shape Param # +================================================================= +transformer (TFGPT2MainLayer multiple 124242432 +================================================================= +Total params: 124,242,432 +Trainable params: 124,242,432 +Non-trainable params: 0 +_________________________________________________________________ +``` + +{/if} + +Наша модель имеет 124 миллиона параметров, которые нам предстоит дообучить. Прежде чем начать обучение, нам нужно настроить коллатор данных, который займется созданием батчей. Мы можем использовать коллатор `DataCollatorForLanguageModeling`, который разработан специально для языкового моделирования (о чем недвусмысленно говорит его название). Помимо стекирования и дополнения батчей, он также заботится о создании меток языковой модели - в каузальном языковом моделировании входы тоже служат метками (просто сдвинутыми на один элемент), и этот коллатор данных создает их на лету во время обучения, так что нам не нужно дублировать `input_ids`. + +Обратите внимание, что `DataCollatorForLanguageModeling` поддерживает как маскированное языковое моделирование (masked language modeling - MLM), так и каузальное языковое моделирование (causal language modeling - CLM). По умолчанию он подготавливает данные для MLM, но мы можем переключиться на CLM, задав аргумент `mlm=False`: + +{#if fw === 'pt'} + +```py +from transformers import DataCollatorForLanguageModeling + +tokenizer.pad_token = tokenizer.eos_token +data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False) +``` + +{:else} + +```py +from transformers import DataCollatorForLanguageModeling + +tokenizer.pad_token = tokenizer.eos_token +data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False, return_tensors="tf") +``` + +{/if} + +Давайте посмотрим на пример: + +```py +out = data_collator([tokenized_datasets["train"][i] for i in range(5)]) +for key in out: + print(f"{key} shape: {out[key].shape}") +``` + +{#if fw === 'pt'} + +```python out +input_ids shape: torch.Size([5, 128]) +attention_mask shape: torch.Size([5, 128]) +labels shape: torch.Size([5, 128]) +``` + +{:else} + +```python out +input_ids shape: (5, 128) +attention_mask shape: (5, 128) +labels shape: (5, 128) +``` + +{/if} + +Мы видим, что примеры были стекированы, и все тензоры имеют одинаковую форму. + +{#if fw === 'tf'} + +Теперь мы можем использовать метод `prepare_tf_dataset()` для преобразования наших датасетов в датасеты TensorFlow с помощью коллатора данных, который мы создали выше: + +```python +tf_train_dataset = model.prepare_tf_dataset( + tokenized_dataset["train"], + collate_fn=data_collator, + shuffle=True, + batch_size=32, +) +tf_eval_dataset = model.prepare_tf_dataset( + tokenized_dataset["valid"], + collate_fn=data_collator, + shuffle=False, + batch_size=32, +) +``` + +{/if} + + + +⚠️ Сдвиг входов и меток для их выравнивания происходит внутри модели, поэтому коллатор данных просто копирует входы для создания меток. + + + + +Теперь у нас есть все необходимое для обучения нашей модели - в конце концов, это было не так уж и сложно! Прежде чем приступить к обучению, мы должны войти в Hugging Face. Если вы работаете в блокноте, вы можете сделать это с помощью следующей служебной функции: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +Появится виджет, в котором вы можете ввести свои учетные данные для входа в Hugging Face. + +Если вы работаете не в блокноте, просто введите следующую строку в терминале: + +```bash +huggingface-cli login +``` + +{#if fw === 'pt'} + +Осталось только настроить аргументы обучения и запустить `Trainer`. Мы будем использовать косинусный график скорости обучения с некоторым разогревом (warmup) и эффективным размером батча в 256 (`per_device_train_batch_size` * `gradient_accumulation_steps`). Аккумулирование градиента используется, когда один батч не помещается в память, и инкрементально накапливает градиент за несколько проходов вперед/назад. Мы увидим это в действии, когда создадим цикл обучения с использованием 🤗 Accelerate. + +```py +from transformers import Trainer, TrainingArguments + +args = TrainingArguments( + output_dir="codeparrot-ds", + per_device_train_batch_size=32, + per_device_eval_batch_size=32, + evaluation_strategy="steps", + eval_steps=5_000, + logging_steps=5_000, + gradient_accumulation_steps=8, + num_train_epochs=1, + weight_decay=0.1, + warmup_steps=1_000, + lr_scheduler_type="cosine", + learning_rate=5e-4, + save_steps=5_000, + fp16=True, + push_to_hub=True, +) + +trainer = Trainer( + model=model, + tokenizer=tokenizer, + args=args, + data_collator=data_collator, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["valid"], +) +``` + +Теперь мы можем просто запустить `Trainer` и дождаться окончания обучения. В зависимости от того, запустите ли вы его на полном или на подмножестве обучающего набора, это займет 20 или 2 часа соответственно, так что захватите несколько чашек кофе и хорошую книгу для чтения! + +```py +trainer.train() +``` + +После завершения обучения мы можем отправить модель и токенизатор в Hub: + +```py +trainer.push_to_hub() +``` + +{:else} + +Осталось только настроить гиперпараметры обучения и вызвать `compile()` и `fit()`. Мы будем использовать график скорости обучения с некоторым разогревом, чтобы повысить стабильность обучения: + +```py +from transformers import create_optimizer +import tensorflow as tf + +num_train_steps = len(tf_train_dataset) +optimizer, schedule = create_optimizer( + init_lr=5e-5, + num_warmup_steps=1_000, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) + +# Обучение со смешанной точностью float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") +``` + +Теперь мы можем просто вызвать `model.fit()` и дождаться окончания обучения. В зависимости от того, запустите ли вы его на полном или на подмножестве обучающего набора, это займет 20 или 2 часа соответственно, так что захватите несколько чашек кофе и хорошую книгу для чтения! После завершения обучения мы можем отправить модель и токенизатор в Hub: + +```py +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback(output_dir="codeparrot-ds", tokenizer=tokenizer) + +model.fit(tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback]) +``` + +{/if} + + + +✏️ **Попробуйте!** Всего около 30 строк кода в дополнение к `TrainingArguments` понадобилось нам, чтобы перейти от сырых текстов к обучению GPT-2. Попробуйте это на своем датасете и посмотрите, сможете ли вы получить хорошие результаты! + + + + + +{#if fw === 'pt'} + +💡 Если у вас есть доступ к компьютеру с несколькими GPU, попробуйте запустить код на нем. `Trainer` автоматически управляет несколькими компьютерами, и это может значительно ускорить обучение. + +{:else} + +💡 Если у вас есть доступ к компьютеру с несколькими GPU, вы можете попробовать использовать контекст `MirroredStrategy` для существенного ускорения обучения. Вам нужно будет создать объект `tf.distribute.MirroredStrategy` и убедиться, что все методы `to_tf_dataset()` или `prepare_tf_dataset()`, а также создание модели и вызов `fit()` выполняются в его контексте `scope()`. Документацию на эту тему можно посмотреть [здесь](https://www.tensorflow.org/guide/distributed_training#use_tfdistributestrategy_with_keras_modelfit). + +{/if} + + + +## Генерация кода с помощью конвейера[[code-generation-with-a-pipeline]] + +Настал момент истины: давайте посмотрим, насколько хорошо работает обученная модель! В логах мы видим, что потери постоянно снижаются, но чтобы проверить модель на практике, давайте посмотрим, насколько хорошо она работает на некоторых подсказках. Для этого мы обернем модель в `pipeline` для генерации текста и поместим ее на GPU для быстрой генерации, если таковой доступен: + +{#if fw === 'pt'} + +```py +import torch +from transformers import pipeline + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +pipe = pipeline( + "text-generation", model="huggingface-course/codeparrot-ds", device=device +) +``` + +{:else} + +```py +from transformers import pipeline + +course_model = TFGPT2LMHeadModel.from_pretrained("huggingface-course/codeparrot-ds") +course_tokenizer = AutoTokenizer.from_pretrained("huggingface-course/codeparrot-ds") +pipe = pipeline( + "text-generation", model=course_model, tokenizer=course_tokenizer, device=0 +) +``` + +{/if} + +Давайте начнем с простой задачи - создания диаграммы рассеивания (scatter plot): + +```py +txt = """\ +# create some data +x = np.random.randn(100) +y = np.random.randn(100) + +# create scatter plot with x, y +""" +print(pipe(txt, num_return_sequences=1)[0]["generated_text"]) +``` + +```python out +# create some data +x = np.random.randn(100) +y = np.random.randn(100) + +# create scatter plot with x, y +plt.scatter(x, y) + +# create scatter +``` + +Результат выглядит корректно. Работает ли это также для `pandas` операции? Давайте посмотрим, сможем ли мы создать `DataFrame` из двух массивов: + +```py +txt = """\ +# create some data +x = np.random.randn(100) +y = np.random.randn(100) + +# create dataframe from x and y +""" +print(pipe(txt, num_return_sequences=1)[0]["generated_text"]) +``` + +```python out +# create some data +x = np.random.randn(100) +y = np.random.randn(100) + +# create dataframe from x and y +df = pd.DataFrame({'x': x, 'y': y}) +df.insert(0,'x', x) +for +``` + +Отлично, это правильный ответ -- хотя затем он снова вставляет столбец `x`. Поскольку количество генерируемых токенов ограничено, следующий цикл `for` обрывается. Давайте посмотрим, сможем ли мы сделать что-то более сложное, и чтобы модель помогла нам использовать операцию `groupby`: + +```py +txt = """\ +# dataframe with profession, income and name +df = pd.DataFrame({'profession': x, 'income':y, 'name': z}) + +# calculate the mean income per profession +""" +print(pipe(txt, num_return_sequences=1)[0]["generated_text"]) +``` + +```python out +# dataframe with profession, income and name +df = pd.DataFrame({'profession': x, 'income':y, 'name': z}) + +# calculate the mean income per profession +profession = df.groupby(['profession']).mean() + +# compute the +``` + +Неплохо; это правильный способ сделать это. Наконец, давайте посмотрим, сможем ли мы также использовать его для `scikit-learn` и создать модель Random Forest: + +```py +txt = """ +# import random forest regressor from scikit-learn +from sklearn.ensemble import RandomForestRegressor + +# fit random forest model with 300 estimators on X, y: +""" +print(pipe(txt, num_return_sequences=1)[0]["generated_text"]) +``` + +```python out +# import random forest regressor from scikit-learn +from sklearn.ensemble import RandomForestRegressor + +# fit random forest model with 300 estimators on X, y: +rf = RandomForestRegressor(n_estimators=300, random_state=random_state, max_depth=3) +rf.fit(X, y) +rf +``` + +{#if fw === 'tf'} + +Глядя на эти несколько примеров, кажется, что модель усвоила часть синтаксиса стека Python Data Science. Конечно, нам нужно будет более тщательно оценить модель, прежде чем внедрять ее в реальный мир, но все же это впечатляющий прототип. + +{:else} + +Глядя на эти несколько примеров, кажется, что модель усвоила часть синтаксиса стека Python Data Science (конечно, нам нужно будет оценить это более тщательно, прежде чем разворачивать модель в реальном мире). Однако иногда требуется более тщательная настройка обучения модели, чтобы добиться необходимого качества работы для конкретного случая использования. Например, если мы хотим динамически обновлять размер батча или иметь условный цикл обучения, который пропускает плохие примеры на лету? Одним из вариантов может быть подкласс `Trainer` и добавление необходимых изменений, но иногда проще написать цикл обучения с нуля. Вот тут-то и приходит на помощь 🤗 Accelerate. + +{/if} + +{#if fw === 'pt'} + +## Обучение с 🤗 Accelerate[[training-with-accelerate]] + +Мы уже видели, как обучать модель с помощью `Trainer`, который позволяет сделать некоторые настройки. Однако иногда нам нужен полный контроль над циклом обучения, или мы хотим внести некоторые экзотические изменения. В этом случае 🤗 Accelerate - отличный выбор, и в этом разделе мы рассмотрим шаги по его использованию для обучения нашей модели. Чтобы сделать все более интересным, мы также добавим изюминку в цикл обучения. + + + +Поскольку нас в основном интересует разумное автодополнение для библиотек data science, имеет смысл придать больший вес обучающим примерам, в которых чаще используются эти библиотеки. Мы можем легко определить эти примеры по использованию таких ключевых слов, как `plt`, `pd`, `sk`, `fit` и `predict`, которые являются наиболее частыми именами для импорта `matplotlib.pyplot`, `pandas` и `sklearn`, а также шаблонам fit/predict для последней. Если каждый из них представлен в виде одного токена, мы можем легко проверить, встречаются ли они во входной последовательности. Токены могут иметь пробельный префикс, поэтому мы также проверим наличие таких версий в словаре токенизатора. Чтобы убедиться, что все работает, мы добавим один тестовый токен, который должен быть разбит на несколько токенов: + +```py +keytoken_ids = [] +for keyword in [ + "plt", + "pd", + "sk", + "fit", + "predict", + " plt", + " pd", + " sk", + " fit", + " predict", + "testtest", +]: + ids = tokenizer([keyword]).input_ids[0] + if len(ids) == 1: + keytoken_ids.append(ids[0]) + else: + print(f"Keyword has not single token: {keyword}") +``` + +```python out +'Keyword has not single token: testtest' +``` + +Отлично, похоже, это прекрасно работает! Теперь мы можем написать пользовательскую функцию потерь, которая принимает входную последовательность, логиты и ключевые токены, которые мы только что выбрали в качестве входных данных. Сначала нам нужно выровнять логиты и входные данные: входная последовательность, сдвинутая на единицу вправо, формирует метки, поскольку следующий токен является меткой для текущего токена. Мы можем добиться этого, начиная метки со второго токена входной последовательности, поскольку модель все равно не делает предсказания для первого токена. Затем мы отсекаем последний логит, поскольку у нас нет метки для токена, который следует за всей входной последовательностью. Таким образом, мы можем вычислить потери для каждого примера и подсчитать количество вхождений всех ключевых слов в каждом примере. Наконец, мы вычисляем средневзвешенное значение по всем примерам, используя вхождения в качестве весов. Поскольку мы не хотим отбрасывать все выборки, в которых нет ключевых слов, мы добавляем 1 к весам: + +```py +from torch.nn import CrossEntropyLoss +import torch + + +def keytoken_weighted_loss(inputs, logits, keytoken_ids, alpha=1.0): + # Сдвигаем так, чтобы токены < n предсказывали n + shift_labels = inputs[..., 1:].contiguous() + shift_logits = logits[..., :-1, :].contiguous() + # Вычисляем потери на каждый токен + loss_fct = CrossEntropyLoss(reduce=False) + loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) + # Изменение размера и средние потери на каждый пример + loss_per_sample = loss.view(shift_logits.size(0), shift_logits.size(1)).mean(axis=1) + # Расчет и масштабирование весов + weights = torch.stack([(inputs == kt).float() for kt in keytoken_ids]).sum( + axis=[0, 2] + ) + weights = alpha * (1.0 + weights) + # Расчет взвешенного среднего + weighted_loss = (loss_per_sample * weights).mean() + return weighted_loss +``` + +Прежде чем приступить к обучению с этой потрясающей новой функцией потерь, нам нужно подготовить несколько вещей: + +- Нам нужны загрузчики данных, чтобы загружать данные батчами. +- Нам нужно настроить параметры затухания веса (weight decay). +- Время от времени мы хотим проводить оценку, поэтому имеет смысл обернуть код оценки в функцию. + +Давайте начнем с загрузчиков данных. Нам нужно только задать для датасета формат `"torch"`, а затем мы можем передать его в PyTorch `DataLoader` с соответствующим размером батча: + +```py +from torch.utils.data.dataloader import DataLoader + +tokenized_dataset.set_format("torch") +train_dataloader = DataLoader(tokenized_dataset["train"], batch_size=32, shuffle=True) +eval_dataloader = DataLoader(tokenized_dataset["valid"], batch_size=32) +``` + +Далее мы группируем параметры, чтобы оптимизатор знал, какие из них получат дополнительное затухание веса. Обычно все смещения (bias) и весовые коэффициенты LayerNorm (LayerNorm weights) исключаются из этого правила; вот как мы можем это реализовать: + +```py +weight_decay = 0.1 + + +def get_grouped_params(model, no_decay=["bias", "LayerNorm.weight"]): + params_with_wd, params_without_wd = [], [] + for n, p in model.named_parameters(): + if any(nd in n for nd in no_decay): + params_without_wd.append(p) + else: + params_with_wd.append(p) + return [ + {"params": params_with_wd, "weight_decay": weight_decay}, + {"params": params_without_wd, "weight_decay": 0.0}, + ] +``` + +Поскольку мы хотим регулярно оценивать модель на валидационном множестве во время обучения, давайте напишем функцию и для этого. Она просто запускается через загрузчик оценочных данных и собирает все потери: + +```py +def evaluate(): + model.eval() + losses = [] + for step, batch in enumerate(eval_dataloader): + with torch.no_grad(): + outputs = model(batch["input_ids"], labels=batch["input_ids"]) + + losses.append(accelerator.gather(outputs.loss)) + loss = torch.mean(torch.cat(losses)) + try: + perplexity = torch.exp(loss) + except OverflowError: + perplexity = float("inf") + return loss.item(), perplexity.item() +``` + +С помощью функции `evaluate()` мы можем сообщать о потерях и [перплексии](/course/chapter7/3) через регулярные промежутки времени. Далее мы переопределим нашу модель, чтобы убедиться, что мы снова обучаемся с нуля: + +```py +model = GPT2LMHeadModel(config) +``` + +Затем мы можем определить наш оптимизатор, используя предыдущую функцию для части параметров для затухания веса: + +```py +from torch.optim import AdamW + +optimizer = AdamW(get_grouped_params(model), lr=5e-4) +``` + +Теперь давайте подготовим модель, оптимизатор и загрузчики данных, чтобы начать обучение: + +```py +from accelerate import Accelerator + +accelerator = Accelerator(fp16=True) + +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + + + +🚨 Если вы проводите обучение на TPU, вам нужно будет перенести весь код, начиная с ячейки выше, в выделенную функцию обучения. Подробнее смотрите [Главу 3](/course/chapter3). + + + +Теперь, когда мы отправили наш `train_dataloader` в `accelerator.prepare()`, мы можем использовать его длину для вычисления количества шагов обучения. Помните, что это всегда нужно делать после подготовки загрузчика данных, так как этот метод изменит его длину. Мы используем классический линейный график скорости обучения до 0: + +```py +from transformers import get_scheduler + +num_train_epochs = 1 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + name="linear", + optimizer=optimizer, + num_warmup_steps=1_000, + num_training_steps=num_training_steps, +) +``` + +Наконец, чтобы отправить нашу модель в Hub, нам нужно создать объект `Repository` в рабочей папке. Сначала войдите в Hub Hugging Face, если вы еще не вошли в него. Мы определим имя розитория по идентификатору модели, который мы хотим присвоить нашей модели (не стесняйтесь заменить `repo_name` на свой собственный вариант; он просто должен содержать ваше имя пользователя, что и делает функция `get_full_repo_name()`): + +```py +from huggingface_hub import Repository, get_full_repo_name + +model_name = "codeparrot-ds-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'sgugger/codeparrot-ds-accelerate' +``` + +Затем мы можем клонировать этот розиторий в локальную папку. Если она уже существует, эта локальная папка должна быть существующим клоном розитория, с которым мы работаем: + +```py +output_dir = "codeparrot-ds-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +Теперь мы можем загрузить все, что сохранили в `output_dir`, вызвав метод `repo.push_to_hub()`. Это поможет нам загружать промежуточные модели в конце каждой эпохи. + +Перед обучением давайте проведем быстрый тест, чтобы проверить, правильно ли работает функция оценки: + +```py +evaluate() +``` + +```python out +(10.934126853942871, 56057.14453125) +``` + +Это очень высокие значения для потерь и перплексии, но это неудивительно, ведь мы еще не обучили модель. Итак, у нас все готово для написания основной части скрипта обучения: цикла обучения. В цикле обучения мы выполняем итерации по загрузчику данных и передаем батчи в модель. С помощью логитов мы можем оценить нашу пользовательскую функцию потерь. Мы масштабируем потери по количеству шагов накопления градиента, чтобы не создавать больших потерь при агрегировании большего количества шагов. Перед оптимизацией мы также обрезаем градиенты для лучшей сходимости. Наконец, каждые несколько шагов мы оцениваем модель на оценочном наборе с помощью нашей новой функции `evaluate()`: + +```py +from tqdm.notebook import tqdm + +gradient_accumulation_steps = 8 +eval_steps = 5_000 + +model.train() +completed_steps = 0 +for epoch in range(num_train_epochs): + for step, batch in tqdm( + enumerate(train_dataloader, start=1), total=num_training_steps + ): + logits = model(batch["input_ids"]).logits + loss = keytoken_weighted_loss(batch["input_ids"], logits, keytoken_ids) + if step % 100 == 0: + accelerator.print( + { + "samples": step * samples_per_step, + "steps": completed_steps, + "loss/train": loss.item() * gradient_accumulation_steps, + } + ) + loss = loss / gradient_accumulation_steps + accelerator.backward(loss) + if step % gradient_accumulation_steps == 0: + accelerator.clip_grad_norm_(model.parameters(), 1.0) + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + completed_steps += 1 + if (step % (eval_steps * gradient_accumulation_steps)) == 0: + eval_loss, perplexity = evaluate() + accelerator.print({"loss/eval": eval_loss, "perplexity": perplexity}) + model.train() + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress step {step}", blocking=False + ) +``` + +Вот и все -- теперь у вас есть свой собственный цикл обучения для каузальных языковых моделей, таких как GPT-2, который вы можете дополнительно настроить под свои нужды. + + + +✏️ **Попробуйте!** Либо создайте свою собственную функцию потерь, подходящую для вашего случая, либо добавьте еще один пользовательский шаг в цикл обучения. + + + + + +✏️ **Попробуйте!** При проведении длительных экспериментов по обучению полезно регистрировать важные метрики с помощью таких инструментов, как TensorBoard или Weights & Biases. Добавьте соответствующее логирование в цикл обучения, чтобы вы всегда могли проверить, как проходит обучение. + + + +{/if} diff --git a/chapters/ru/chapter7/7.mdx b/chapters/ru/chapter7/7.mdx new file mode 100644 index 000000000..ef8371c59 --- /dev/null +++ b/chapters/ru/chapter7/7.mdx @@ -0,0 +1,1203 @@ + + +# Ответы на вопросы[[question-answering]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Пришло время взглянуть на ответы на вопросы! Эта задача имеет множество разновидностей, но та, на которой мы сосредоточимся в этом разделе, называется *экстрактивным* ответом на вопросы. Она включает в себя постановку вопросов о документе и определение ответов в виде _участков текста_ в самом документе. + + + +Мы проведем дообучение BERT-модели на датасете [SQuAD] (https://rajpurkar.github.io/SQuAD-explorer/), состоящем из вопросов, заданных краудворкерами по набору статей Википедии. В результате мы получим модель, способную вычислять прогнозы, подобные этому: + + + +На самом деле это демонстрация модели, которая была обучена и загружена на Hub с помощью кода, показанного в этом разделе. Вы можете найти ее и перепроверить прогнозы [здесь](https://huggingface.co/huggingface-course/bert-finetuned-squad?context=%F0%9F%A4%97+Transformers+is+backed+by+the+three+most+popular+deep+learning+libraries+%E2%80%94+Jax%2C+PyTorch+and+TensorFlow+%E2%80%94+with+a+seamless+integration+between+them.+It%27s+straightforward+to+train+your+models+with+one+before+loading+them+for+inference+with+the+other.&question=Which+deep+learning+libraries+back+%F0%9F%A4%97+Transformers%3F). + + + +💡 Модели, основанные только на энкодере, такие как BERT, как правило, отлично справляются с извлечением ответов на фактоидные вопросы типа "Кто изобрел архитектуру трансформера?", но плохо справляются с открытыми вопросами типа "Почему небо голубое?". В таких сложных случаях для синтеза информации обычно используются модели энкодеров-декодеров, такие как T5 и BART, что очень похоже на [сумризацию текста](/course/chapter7/5). Если вам интересен этот тип *генеративных* ответов на вопросы, рекомендуем ознакомиться с нашим [демо](https://yjernite.github.io/lfqa.html) основанным на [датасете ELI5(https://huggingface.co/datasets/eli5). + + + +## Подготовка данных[[preparing-the-data]] + +В качестве академического бенчмарка для экстрактивных ответов на вопросы чаще всего используется датасет [SQuAD](https://rajpurkar.github.io/SQuAD-explorer/), поэтому мы будем использовать именно его. Существует также более сложный датасет [SQuAD v2](https://huggingface.co/datasets/squad_v2), который включает вопросы, не имеющие ответа. Если ваш собственный датасет содержит столбец контекстов, столбец вопросов и столбец ответов, вы сможете адаптировать описанные ниже шаги. + +### Датасет SQuAD[[the-squad-dataset]] + +Как обычно, мы можем загрузить и кэшировать датасет всего за один шаг благодаря функции `load_dataset()`: + +```py +from datasets import load_dataset + +raw_datasets = load_dataset("squad") +``` + +Мы можем взглянуть на этот объект, чтобы узнать больше о датасете SQuAD: + +```py +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['id', 'title', 'context', 'question', 'answers'], + num_rows: 87599 + }) + validation: Dataset({ + features: ['id', 'title', 'context', 'question', 'answers'], + num_rows: 10570 + }) +}) +``` + +Похоже, у нас есть все необходимое в полях `context`, `question` и `answers`, так что давайте выведем их для первого элемента нашего обучающего набора: + +```py +print("Context: ", raw_datasets["train"][0]["context"]) +print("Question: ", raw_datasets["train"][0]["question"]) +print("Answer: ", raw_datasets["train"][0]["answers"]) +``` + +```python out +Context: 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.' +Question: 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?' +Answer: {'text': ['Saint Bernadette Soubirous'], 'answer_start': [515]} +``` + +Поля `context` и `question` очень просты в использовании. С полем `answers` немного сложнее, поскольку оно представляет собой словарь с двумя полями, которые оба являются списками. Именно такой формат будет ожидать метрика `squad` при оценке; если вы используете свои собственные данные, вам не обязательно беспокоиться о том, чтобы привести ответы к такому же формату. Поле `text` довольно очевидно, а поле `answer_start` содержит индекс начального символа каждого ответа в контексте. + +Во время обучения существует только один возможный ответ. Мы можем перепроверить это с помощью метода `Dataset.filter()`: + +```py +raw_datasets["train"].filter(lambda x: len(x["answers"]["text"]) != 1) +``` + +```python out +Dataset({ + features: ['id', 'title', 'context', 'question', 'answers'], + num_rows: 0 +}) +``` + +Для оценки, однако, существует несколько возможных ответов для каждого примера, которые могут быть одинаковыми или разными: + +```py +print(raw_datasets["validation"][0]["answers"]) +print(raw_datasets["validation"][2]["answers"]) +``` + +```python out +{'text': ['Denver Broncos', 'Denver Broncos', 'Denver Broncos'], 'answer_start': [177, 177, 177]} +{'text': ['Santa Clara, California', "Levi's Stadium", "Levi's Stadium in the San Francisco Bay Area at Santa Clara, California."], 'answer_start': [403, 355, 355]} +``` + +Мы не будем углубляться в сценарий оценки, поскольку все это будет завернуто в метрику 🤗 Datasets для нас, но кратко суть в том, что некоторые вопросы имеют несколько возможных ответов, и этот сценарий будет сравнивать спрогнозированный ответ со всеми допустимыми ответами и выбирать лучший результат. Если мы посмотрим, например, на выборку с индексом 2: + +```py +print(raw_datasets["validation"][2]["context"]) +print(raw_datasets["validation"][2]["question"]) +``` + +```python out +'Super Bowl 50 was an American football game to determine the champion of the National Football League (NFL) for the 2015 season. The American Football Conference (AFC) champion Denver Broncos defeated the National Football Conference (NFC) champion Carolina Panthers 24–10 to earn their third Super Bowl title. The game was played on February 7, 2016, at Levi\'s Stadium in the San Francisco Bay Area at Santa Clara, California. As this was the 50th Super Bowl, the league emphasized the "golden anniversary" with various gold-themed initiatives, as well as temporarily suspending the tradition of naming each Super Bowl game with Roman numerals (under which the game would have been known as "Super Bowl L"), so that the logo could prominently feature the Arabic numerals 50.' +'Where did Super Bowl 50 take place?' +``` + +мы можем увидеть, что ответ действительно может быть одним из трех возможных вариантов, которые мы видели ранее. + +### Подготовка обучающих данных[[processing-the-training-data]] + + + +Начнем с предварительной подготовки обучающих данных. Самое сложное - сгенерировать метки для ответа на вопрос, которые будут представлять собой начальную и конечную позиции токенов, соответствующих ответу в контексте. + +Но не будем забегать вперед. Сначала нам нужно преобразовать текст во входных данных в идентификаторы, которые модель сможет понять, используя токенизатор: + +```py +from transformers import AutoTokenizer + +model_checkpoint = "bert-base-cased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +Как упоминалось ранее, мы будем проводить дообучение модели BERT, но вы можете использовать любой другой тип модели, если в ней реализован быстрый токенизатор. Вы можете увидеть все архитектуры с быстрой версией в [этой большой таблице](https://huggingface.co/transformers/#supported-frameworks), а чтобы проверить, что используемый вами объект `tokenizer` действительно поддерживается 🤗 Tokenizers, вы можете посмотреть на его атрибут `is_fast`: + +```py +tokenizer.is_fast +``` + +```python out +True +``` + +Мы можем передать нашему токенизатору вопрос и контекст вместе, и он правильно вставит специальные токены, чтобы сформировать предложение, подобное этому: + +``` +[CLS] question [SEP] context [SEP] +``` + +Давайте перепроверим: + +```py +context = raw_datasets["train"][0]["context"] +question = raw_datasets["train"][0]["question"] + +inputs = tokenizer(question, context) +tokenizer.decode(inputs["input_ids"]) +``` + +```python out +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Architecturally, ' +'the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin ' +'Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms ' +'upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred ' +'Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a ' +'replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette ' +'Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 statues ' +'and the Gold Dome ), is a simple, modern stone statue of Mary. [SEP]' +``` + +В качестве меток будут использоваться индексы токенов, начинающих и заканчивающих ответ, а задача модели - предсказать один начальный и конечный логит для каждого токена на входе, при этом теоретические метки будут выглядеть следующим образом: + +
+One-hot encoded labels for question answering. + +
+ +В данном случае контекст не слишком длинный, но некоторые примеры в датасете имеют очень длинные контексты, которые превысят установленную нами максимальную длину (которая в данном случае равна 384). Как мы видели в [Главе 6] (/course/chapter6/4), когда изучали внутреннее устройство конвейера `question-answering`, мы будем работать с длинными контекстами, создавая несколько обучающих признаков из одной выборки нашего датасета, со скользящим окном между ними. + +Чтобы увидеть, как это работает на текущем примере, мы можем ограничить длину до 100 и использовать скользящее окно из 50 токенов. В качестве напоминания мы используем: + +- `max_length` для установки максимальной длины (здесь 100) +- `truncation="only_second"` для усечения контекста (который находится во второй позиции), когда вопрос с его контекстом слишком длинный +- `stride` для задания количества перекрывающихся токенов между двумя последовательными фрагментами (здесь 50) +- `return_overflowing_tokens=True`, чтобы сообщить токенизатору, что нам нужны переполненные токены (overflowing tokens) + +```py +inputs = tokenizer( + question, + context, + max_length=100, + truncation="only_second", + stride=50, + return_overflowing_tokens=True, +) + +for ids in inputs["input_ids"]: + print(tokenizer.decode(ids)) +``` + +```python out +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basi [SEP]' +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin [SEP]' +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 [SEP]' +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP]. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 statues and the Gold Dome ), is a simple, modern stone statue of Mary. [SEP]' +``` + +Как мы можем видеть, наш пример был разбит на четыре входа, каждый из которых содержит вопрос и часть контекста. Обратите внимание, что ответ на вопрос ("Bernadette Soubirous") появляется только в третьем и последнем входе, поэтому, работая с длинными контекстами таким образом, мы создадим несколько обучающих примеров, в которых ответ не будет включен в контекст. Для этих примеров метками будут `start_position = end_position = 0` (таким образом мы предсказываем токен `[CLS]`). Мы также зададим эти метки в неудачном случае, когда ответ был усечен, так что у нас есть только его начало (или конец). Для примеров, где ответ полностью находится в контексте, метками будут индекс токена, с которого начинается ответ, и индекс токена, на котором ответ заканчивается. + +Датасет предоставляет нам начальный символ ответа в контексте, а прибавив к нему длину ответа, мы можем найти конечный символ в контексте. Чтобы сопоставить их с индексами токенов, нам нужно использовать сопоставление смещений, которое мы изучали в [Главе 6](/course/chapter6/4). Мы можем настроить наш токенизатор на их возврат, передав `return_offsets_mapping=True`: + +```py +inputs = tokenizer( + question, + context, + max_length=100, + truncation="only_second", + stride=50, + return_overflowing_tokens=True, + return_offsets_mapping=True, +) +inputs.keys() +``` + +```python out +dict_keys(['input_ids', 'token_type_ids', 'attention_mask', 'offset_mapping', 'overflow_to_sample_mapping']) +``` + +Как мы видим, нам возвращаются обычные идентификаторы входа, идентификаторы типов токенов и маска внимания, а также необходимое нам сопоставление смещений и дополнительный ключ `overflow_to_sample_mapping`. Соответствующее значение мы будем использовать при токенизации нескольких текстов одновременно (что мы и должны делать, чтобы извлечь выгоду из того, что наш токенизатор основан на Rust). Поскольку один образец может давать несколько признаков, он сопоставляет каждый признак с примером, из которого он произошел. Поскольку здесь мы токенизировали только один пример, мы получим список `0`: + +```py +inputs["overflow_to_sample_mapping"] +``` + +```python out +[0, 0, 0, 0] +``` + +Но если мы проведем токенизацию большего количества примеров, это станет более полезным: + +```py +inputs = tokenizer( + raw_datasets["train"][2:6]["question"], + raw_datasets["train"][2:6]["context"], + max_length=100, + truncation="only_second", + stride=50, + return_overflowing_tokens=True, + return_offsets_mapping=True, +) + +print(f"The 4 examples gave {len(inputs['input_ids'])} features.") +print(f"Here is where each comes from: {inputs['overflow_to_sample_mapping']}.") +``` + +```python out +'The 4 examples gave 19 features.' +'Here is where each comes from: [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3].' +``` + +Как мы видим, первые три примера (с индексами 2, 3 и 4 в обучающем наборе) дали по четыре признака, а последний пример (с индексом 5 в обучающем наборе) - 7 признаков. + +Эта информация будет полезна для сопоставления каждого полученного признака с соответствующей меткой. Как уже упоминалось ранее, этими метками являются: + +- `(0, 0)`, если ответ не находится в соответствующей области контекста +- `(start_position, end_position)`, если ответ находится в соответствующей области контекста, причем `start_position` - это индекс токена (во входных идентификаторах) в начале ответа, а `end_position` - индекс токена (во входных идентификаторах) в конце ответа + +Чтобы определить, какой из этих случаев имеет место, и, если нужно, позиции токенов, мы сначала находим индексы, с которых начинается и заканчивается контекст во входных идентификаторах. Для этого мы могли бы использовать идентификаторы типов токенов, но поскольку они не обязательно существуют для всех моделей (например, DistilBERT их не требует), вместо этого мы воспользуемся методом `sequence_ids()` из `BatchEncoding`, который возвращает наш токенизатор. + +Получив индексы токенов, мы смотрим на соответствующие смещения, которые представляют собой кортежи из двух целых чисел, обозначающих промежуток символов внутри исходного контекста. Таким образом, мы можем определить, начинается ли фрагмент контекста в этом признаке после ответа или заканчивается до начала ответа (в этом случае метка будет `(0, 0)`). Если это не так, мы зацикливаемся, чтобы найти первый и последний токен ответа: + +```py +answers = raw_datasets["train"][2:6]["answers"] +start_positions = [] +end_positions = [] + +for i, offset in enumerate(inputs["offset_mapping"]): + sample_idx = inputs["overflow_to_sample_mapping"][i] + answer = answers[sample_idx] + start_char = answer["answer_start"][0] + end_char = answer["answer_start"][0] + len(answer["text"][0]) + sequence_ids = inputs.sequence_ids(i) + + # Найдём начало и конец контекста + idx = 0 + while sequence_ids[idx] != 1: + idx += 1 + context_start = idx + while sequence_ids[idx] == 1: + idx += 1 + context_end = idx - 1 + + # Если ответ не полностью находится внутри контекста, меткой будет (0, 0) + if offset[context_start][0] > start_char or offset[context_end][1] < end_char: + start_positions.append(0) + end_positions.append(0) + else: + # В противном случае это начальная и конечная позиции токенов + idx = context_start + while idx <= context_end and offset[idx][0] <= start_char: + idx += 1 + start_positions.append(idx - 1) + + idx = context_end + while idx >= context_start and offset[idx][1] >= end_char: + idx -= 1 + end_positions.append(idx + 1) + +start_positions, end_positions +``` + +```python out +([83, 51, 19, 0, 0, 64, 27, 0, 34, 0, 0, 0, 67, 34, 0, 0, 0, 0, 0], + [85, 53, 21, 0, 0, 70, 33, 0, 40, 0, 0, 0, 68, 35, 0, 0, 0, 0, 0]) +``` + +Давайте посмотрим на несколько результатов, чтобы убедиться в правильности нашего подхода. Для первого признака мы находим `(83, 85)` в качестве меток, поэтому давайте сравним теоретический ответ с декодированным диапазоном лексем с 83 по 85 (включительно): + +```py +idx = 0 +sample_idx = inputs["overflow_to_sample_mapping"][idx] +answer = answers[sample_idx]["text"][0] + +start = start_positions[idx] +end = end_positions[idx] +labeled_answer = tokenizer.decode(inputs["input_ids"][idx][start : end + 1]) + +print(f"Theoretical answer: {answer}, labels give: {labeled_answer}") +``` + +```python out +'Theoretical answer: the Main Building, labels give: the Main Building' +``` + +Итак, это совпадение! Теперь проверим индекс 4, где мы установили метки на `(0, 0)`, что означает, что ответ не находится в фрагменте контекста этого признака: + +```py +idx = 4 +sample_idx = inputs["overflow_to_sample_mapping"][idx] +answer = answers[sample_idx]["text"][0] + +decoded_example = tokenizer.decode(inputs["input_ids"][idx]) +print(f"Theoretical answer: {answer}, decoded example: {decoded_example}") +``` + +```python out +'Theoretical answer: a Marian place of prayer and reflection, decoded example: [CLS] What is the Grotto at Notre Dame? [SEP] Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grot [SEP]' +``` + +Действительно, мы не видим ответа в контексте. + + + +✏️ **Ваша очередь!** При использовании архитектуры XLNet дополнение применяется слева, а вопрос и контекст меняются местами. Адаптируйте весь код, который мы только что рассмотрели, к архитектуре XLNet (и добавьте `padding=True`). Имейте в виду, что токен `[CLS]` может не находиться в позиции 0 при использовании дополнения. + + + +Теперь, когда мы шаг за шагом разобрались с предварительной обработкой обучающих данных, мы можем сгруппировать их в функцию, которую будем применять ко всему датасету. Мы дополним каждый признак до максимальной длины, которую мы задали, поскольку большинство контекстов будут длинными (и соответствующие образцы будут разбиты на несколько признаков), поэтому применение динамического дополнения здесь не имеет реальной пользы: + +```py +max_length = 384 +stride = 128 + + +def preprocess_training_examples(examples): + questions = [q.strip() for q in examples["question"]] + inputs = tokenizer( + questions, + examples["context"], + max_length=max_length, + truncation="only_second", + stride=stride, + return_overflowing_tokens=True, + return_offsets_mapping=True, + padding="max_length", + ) + + offset_mapping = inputs.pop("offset_mapping") + sample_map = inputs.pop("overflow_to_sample_mapping") + answers = examples["answers"] + start_positions = [] + end_positions = [] + + for i, offset in enumerate(offset_mapping): + sample_idx = sample_map[i] + answer = answers[sample_idx] + start_char = answer["answer_start"][0] + end_char = answer["answer_start"][0] + len(answer["text"][0]) + sequence_ids = inputs.sequence_ids(i) + + # Найдём начало и конец контекста + idx = 0 + while sequence_ids[idx] != 1: + idx += 1 + context_start = idx + while sequence_ids[idx] == 1: + idx += 1 + context_end = idx - 1 + + # Если ответ не полностью находится внутри контекста, меткой будет (0, 0) + if offset[context_start][0] > start_char or offset[context_end][1] < end_char: + start_positions.append(0) + end_positions.append(0) + else: + # В противном случае это начальная и конечная позиции токенов + idx = context_start + while idx <= context_end and offset[idx][0] <= start_char: + idx += 1 + start_positions.append(idx - 1) + + idx = context_end + while idx >= context_start and offset[idx][1] >= end_char: + idx -= 1 + end_positions.append(idx + 1) + + inputs["start_positions"] = start_positions + inputs["end_positions"] = end_positions + return inputs +``` + +Обратите внимание, что мы определили две константы для определения максимальной длины и длины скользящего окна, а также добавили немного очистки перед токенизацией: некоторые вопросы в датасете SQuAD имеют лишние пробелы в начале и конце, которые ничего не добавляют (и занимают место при токенизации, если вы используете модель вроде RoBERTa), поэтому мы удалили эти лишние пробелы. + +Чтобы применить эту функцию ко всему обучающему набору, мы используем метод `Dataset.map()` с флагом `batched=True`. Это необходимо, так как мы изменяем длину датасета (поскольку один пример может давать несколько обучающих признаков): + +```py +train_dataset = raw_datasets["train"].map( + preprocess_training_examples, + batched=True, + remove_columns=raw_datasets["train"].column_names, +) +len(raw_datasets["train"]), len(train_dataset) +``` + +```python out +(87599, 88729) +``` + +Как мы видим, предварительная обработка добавила около 1 000 признаков. Теперь наш обучающий набор готов к использованию - давайте займемся предварительной обработкой валидационного набора! + +### Подготовка валидационных данных[[processing-the-validation-data]] + +Предварительная обработка валидационных данных будет немного проще, поскольку нам не нужно генерировать метки (если только мы не хотим вычислять потери на валидации, но это число не поможет нам понять, насколько хороша модель). Настоящей радостью будет интерпретация прогнозов модели в диапазонах исходного контекста. Для этого нам нужно хранить как сопоставления смещений, так и способ сопоставления каждого созданного признака с оригинальным примером, из которого он взят. Поскольку в исходном датасете есть столбец ID, мы будем использовать этот ID. + +Единственное, что мы добавим сюда, - это немного почистим сопоставления смещений. Они будут содержать смещения для вопроса и контекста, но на этапе постобработки у нас не будет возможности узнать, какая часть входных идентификаторов соответствует контексту, а какая - вопросу (метод `sequence_ids()`, который мы использовали, доступен только для выхода токенизатора). Поэтому мы установим смещения, соответствующие вопросу, в `None`: + +```py +def preprocess_validation_examples(examples): + questions = [q.strip() for q in examples["question"]] + inputs = tokenizer( + questions, + examples["context"], + max_length=max_length, + truncation="only_second", + stride=stride, + return_overflowing_tokens=True, + return_offsets_mapping=True, + padding="max_length", + ) + + sample_map = inputs.pop("overflow_to_sample_mapping") + example_ids = [] + + for i in range(len(inputs["input_ids"])): + sample_idx = sample_map[i] + example_ids.append(examples["id"][sample_idx]) + + sequence_ids = inputs.sequence_ids(i) + offset = inputs["offset_mapping"][i] + inputs["offset_mapping"][i] = [ + o if sequence_ids[k] == 1 else None for k, o in enumerate(offset) + ] + + inputs["example_id"] = example_ids + return inputs +``` + +Мы можем применить эту функцию ко всему валидационому датасету, как и раньше: + +```py +validation_dataset = raw_datasets["validation"].map( + preprocess_validation_examples, + batched=True, + remove_columns=raw_datasets["validation"].column_names, +) +len(raw_datasets["validation"]), len(validation_dataset) +``` + +```python out +(10570, 10822) +``` + +В данном случае мы добавили всего пару сотен примеров, поэтому контексты в валидационном датасете немного короче. + +Теперь, когда мы предварительно обработали все данные, можно приступать к обучению. + +{#if fw === 'pt'} + +## Дообучение модели с API `Trainer`[[fine-tuning-the-model-with-the-trainer-api]] + +Код обучения для этого примера будет очень похож на код из предыдущих разделов -- самым сложным будет написание функции `compute_metrics()`. Поскольку мы дополнили все примеры до максимальной длины, которую мы задали, нет никакого коллатора данных, поэтому вычисление метрики - это единственное, о чем нам нужно беспокоиться. Самым сложным будет постобработка прогнозов модели в отрезки текста оригинальных примеров; как только мы это сделаем, метрика из библиотеки 🤗 Datasets сделает за нас большую часть работы. + +{:else} + +## Дообучение модели с Keras[[fine-tuning-the-model-with-keras]] + +Код обучения для этого примера будет очень похож на код в предыдущих разделах, но вычисление метрик будет уникальным. Поскольку мы дополнили все примеры до максимальной длины, которую мы задали, нет коллатора данных, который нужно определить, поэтому вычисление метрики - это единственное, о чем нам нужно беспокоиться. Самое сложное - это постобработка прогнозов модели в отрезки текста в исходных примерах; как только мы это сделаем, метрика из библиотеки 🤗 Datasets сделает за нас большую часть работы. + +{/if} + +### Постобработка[[post-processing]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Модель выведет логиты для начальной и конечной позиций ответа во входных идентификаторах, как мы видели при изучении [конвейера `question-answering`](/course/chapter6/3b). Шаг постобработки будет аналогичен тому, что мы делали там, так что вот краткое напоминание о том, что мы делали: + +- Мы маскировали начальные и конечные логиты, соответствующие токенам вне контекста. +- Затем мы преобразовали начальные и конечные логиты в вероятности с помощью softmax. +- Каждой паре `(start_token, end_token)` мы присваивали оценку, взяв произведение двух соответствующих вероятностей. +- Мы искали пару с максимальной оценкой, которая давала правильный ответ (например, `start_token` меньше `end_token`). + +В данном случае мы немного изменим этот процесс, поскольку нам не нужно вычислять фактические оценки (только спрогнозированный ответ). Это означает, что мы можем пропустить шаг softmax. Чтобы ускорить процесс, мы также не будем оценивать все возможные пары `(start_token, end_token)`, а только те, которые соответствуют наибольшим `n_best` логитам (при `n_best=20`). Так как мы пропустим softmax, эти оценки будут оценками логитов, и будут получены путем взятия суммы начального и конечного логитов (вместо произведения, по правилу \\(\log(ab) = \log(a) + \log(b)\\)). + +Чтобы продемонстрировать все это, нам понадобятся некоторые прогнозы. Поскольку мы еще не обучили нашу модель, мы будем использовать модель по умолчанию для конвейера QA, чтобы сгенерировать несколько прогнозов на небольшой части набора для валидации. Мы можем использовать ту же функцию обработки, что и раньше; поскольку она опирается на глобальную константу `tokenizer`, нам просто нужно изменить этот объект на токенизатор модели, которую мы хотим временно использовать: + +```python +small_eval_set = raw_datasets["validation"].select(range(100)) +trained_checkpoint = "distilbert-base-cased-distilled-squad" + +tokenizer = AutoTokenizer.from_pretrained(trained_checkpoint) +eval_set = small_eval_set.map( + preprocess_validation_examples, + batched=True, + remove_columns=raw_datasets["validation"].column_names, +) +``` + +Теперь, когда препроцессинг завершен, мы меняем токенизатор обратно на тот, который был выбран изначально: + +```python +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +Затем мы удаляем из нашего `eval_set` столбцы, которые не ожидает модель, создаем батч со всей этой небольшой валидацией и пропускаем его через модель. Если доступен GPU, мы используем его для ускорения работы: + +{#if fw === 'pt'} + +```python +import torch +from transformers import AutoModelForQuestionAnswering + +eval_set_for_model = eval_set.remove_columns(["example_id", "offset_mapping"]) +eval_set_for_model.set_format("torch") + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +batch = {k: eval_set_for_model[k].to(device) for k in eval_set_for_model.column_names} +trained_model = AutoModelForQuestionAnswering.from_pretrained(trained_checkpoint).to( + device +) + +with torch.no_grad(): + outputs = trained_model(**batch) +``` + +Поскольку `Trainer` будет возвращать нам прогнозы в виде массивов NumPy, мы берем начальный и конечный логиты и конвертируем их в этот формат: + +```python +start_logits = outputs.start_logits.cpu().numpy() +end_logits = outputs.end_logits.cpu().numpy() +``` + +{:else} + +```python +import tensorflow as tf +from transformers import TFAutoModelForQuestionAnswering + +eval_set_for_model = eval_set.remove_columns(["example_id", "offset_mapping"]) +eval_set_for_model.set_format("numpy") + +batch = {k: eval_set_for_model[k] for k in eval_set_for_model.column_names} +trained_model = TFAutoModelForQuestionAnswering.from_pretrained(trained_checkpoint) + +outputs = trained_model(**batch) +``` + +Для облегчения экспериментов преобразуем выходные данные в массивы NumPy: + +```python +start_logits = outputs.start_logits.numpy() +end_logits = outputs.end_logits.numpy() +``` + +{/if} + +Теперь нам нужно найти спрогнозированный ответ для каждого примера в `small_eval_set`. Один пример может быть разбит на несколько признаков в `eval_set`, поэтому первым шагом будет сопоставление каждого примера в `small_eval_set` с соответствующими признаками в `eval_set`: + +```python +import collections + +example_to_features = collections.defaultdict(list) +for idx, feature in enumerate(eval_set): + example_to_features[feature["example_id"]].append(idx) +``` + +Имея это на руках, мы можем приступить к работе, итерируясь по всем примерам и, для каждого примера, по всем ассоциированным с ним признакам. Как мы уже говорили, мы рассмотрим оценки логитов для `n_best` начальных логитов и конечных логитов, исключая позиции, которые дают: + +- Ответ, который не вписывается в контекст +- Ответ с отрицательной длиной +- Слишком длинный ответ (мы ограничиваем возможности по `max_answer_length=30`). + +После того как мы получили все возможные ответы для одного примера, мы просто выбираем тот, который имеет лучшую оценку логита: + +```python +import numpy as np + +n_best = 20 +max_answer_length = 30 +predicted_answers = [] + +for example in small_eval_set: + example_id = example["id"] + context = example["context"] + answers = [] + + for feature_index in example_to_features[example_id]: + start_logit = start_logits[feature_index] + end_logit = end_logits[feature_index] + offsets = eval_set["offset_mapping"][feature_index] + + start_indexes = np.argsort(start_logit)[-1 : -n_best - 1 : -1].tolist() + end_indexes = np.argsort(end_logit)[-1 : -n_best - 1 : -1].tolist() + for start_index in start_indexes: + for end_index in end_indexes: + # Пропускаем ответы, которые не полностью соответствуют контексту + if offsets[start_index] is None or offsets[end_index] is None: + continue + # Пропускайте ответы, длина которых либо < 0, либо > max_answer_length. + if ( + end_index < start_index + or end_index - start_index + 1 > max_answer_length + ): + continue + + answers.append( + { + "text": context[offsets[start_index][0] : offsets[end_index][1]], + "logit_score": start_logit[start_index] + end_logit[end_index], + } + ) + + best_answer = max(answers, key=lambda x: x["logit_score"]) + predicted_answers.append({"id": example_id, "prediction_text": best_answer["text"]}) +``` + +Окончательный формат спрогнозированных ответов - это тот, который ожидает метрика, которую мы будем использовать. Как обычно, мы можем загрузить ее с помощью библиотеки 🤗 Evaluate: + +```python +import evaluate + +metric = evaluate.load("squad") +``` + +Эта метрика ожидает прогнозируемые ответы в формате, который мы видели выше (список словарей с одним ключом для идентификатора примера и одним ключом для прогнозируемого текста), и теоретические ответы в формате ниже (список словарей с одним ключом для идентификатора примера и одним ключом для возможных ответов): + +```python +theoretical_answers = [ + {"id": ex["id"], "answers": ex["answers"]} for ex in small_eval_set +] +``` + +Теперь мы можем убедиться, что получаем разумные результаты, посмотрев на первый элемент обоих списков: + +```python +print(predicted_answers[0]) +print(theoretical_answers[0]) +``` + +```python out +{'id': '56be4db0acb8001400a502ec', 'prediction_text': 'Denver Broncos'} +{'id': '56be4db0acb8001400a502ec', 'answers': {'text': ['Denver Broncos', 'Denver Broncos', 'Denver Broncos'], 'answer_start': [177, 177, 177]}} +``` + +Не так уж плохо! Теперь давайте посмотрим на оценку, которую дает нам метрика: + +```python +metric.compute(predictions=predicted_answers, references=theoretical_answers) +``` + +```python out +{'exact_match': 83.0, 'f1': 88.25} +``` + +Опять же, это довольно хорошо, если учесть, что согласно [его статье](https://arxiv.org/abs/1910.01108v2) DistilBERT с дообучением на SQuAD получает 79,1 и 86,9 для этих оценок на всем датасете. + +{#if fw === 'pt'} + +Теперь давайте поместим все, что мы только что сделали, в функцию `compute_metrics()`, которую мы будем использовать в `Trainer`. Обычно функция `compute_metrics()` получает только кортеж `eval_preds` с логитами и метками. Здесь нам понадобится немного больше, так как мы должны искать в датасете признаков смещения и в датасете примеров исходные контексты, поэтому мы не сможем использовать эту функцию для получения обычных результатов оценки во время обучения. Мы будем использовать ее только в конце обучения для проверки результатов. + +Функция `compute_metrics()` группирует те же шаги, что и до этого, только добавляется небольшая проверка на случай, если мы не найдем ни одного правильного ответа (в этом случае мы прогнозируем пустую строку). + +{:else} + +Теперь давайте поместим все, что мы только что сделали, в функцию `compute_metrics()`, которую мы будем использовать после обучения нашей модели. Нам нужно будет передать несколько больше, чем просто выходные логиты, поскольку мы должны искать в датасете признаков смещение, а в датасете примеров - исходные контексты: + +{/if} + +```python +from tqdm.auto import tqdm + + +def compute_metrics(start_logits, end_logits, features, examples): + example_to_features = collections.defaultdict(list) + for idx, feature in enumerate(features): + example_to_features[feature["example_id"]].append(idx) + + predicted_answers = [] + for example in tqdm(examples): + example_id = example["id"] + context = example["context"] + answers = [] + + # Итерируемся по всем признакам, ассоциированным с этим примером + for feature_index in example_to_features[example_id]: + start_logit = start_logits[feature_index] + end_logit = end_logits[feature_index] + offsets = features[feature_index]["offset_mapping"] + + start_indexes = np.argsort(start_logit)[-1 : -n_best - 1 : -1].tolist() + end_indexes = np.argsort(end_logit)[-1 : -n_best - 1 : -1].tolist() + for start_index in start_indexes: + for end_index in end_indexes: + # Пропускаем ответы, которые не полностью соответствуют контексту + if offsets[start_index] is None or offsets[end_index] is None: + continue + # Пропускайте ответы, длина которых либо < 0, либо > max_answer_length + if ( + end_index < start_index + or end_index - start_index + 1 > max_answer_length + ): + continue + + answer = { + "text": context[offsets[start_index][0] : offsets[end_index][1]], + "logit_score": start_logit[start_index] + end_logit[end_index], + } + answers.append(answer) + + # Выбираем ответ с лучшей оценкой + if len(answers) > 0: + best_answer = max(answers, key=lambda x: x["logit_score"]) + predicted_answers.append( + {"id": example_id, "prediction_text": best_answer["text"]} + ) + else: + predicted_answers.append({"id": example_id, "prediction_text": ""}) + + theoretical_answers = [{"id": ex["id"], "answers": ex["answers"]} for ex in examples] + return metric.compute(predictions=predicted_answers, references=theoretical_answers) +``` + +Мы можем проверить ее работу на наших прогнозах: + +```python +compute_metrics(start_logits, end_logits, eval_set, small_eval_set) +``` + +```python out +{'exact_match': 83.0, 'f1': 88.25} +``` + +Выглядит отлично! Теперь давайте используем это для дообучения нашей модели. + +### Дообучение модели[[fine-tuning-the-model]] + +{#if fw === 'pt'} + +Теперь мы готовы к обучению нашей модели. Давайте сначала создадим ее, используя класс `AutoModelForQuestionAnswering`, как и раньше: + +```python +model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) +``` + +{:else} + +Теперь мы готовы к обучению нашей модели. Давайте сначала создадим ее, используя класс `TFAutoModelForQuestionAnswering`, как и раньше: + +```python +model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint) +``` + +{/if} + +Как обычно, мы получаем предупреждение о том, что некоторые веса не используются (веса головы предварительного обучения), а другие инициализируются случайным образом (веса головы ответов на вопросы). Вы уже должны были привыкнуть к этому, но это означает, что модель еще не готова к использованию и нуждается в дообучении - хорошо, что мы сейчас этим займемся! + +Чтобы отправить нашу модель на Hub, нам нужно войти в Hugging Face. Если вы выполняете этот код в блокноте, вы можете сделать это с помощью следующей служебной функции, которая отображает виджет, где вы можете ввести свои учетные данные: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +Если вы работаете не в блокноте, просто введите следующую строку в терминале: + +```bash +huggingface-cli login +``` + +{#if fw === 'pt'} + +Когда это сделано, мы можем определить наши `TrainingArguments`. Как мы уже говорили, когда определяли нашу функцию для вычисления метрики, мы не сможем сделать обычный цикл оценки из-за сигнатуры функции `compute_metrics()`. Мы могли бы написать собственный подкласс `Trainer` для этого (такой подход можно найти в [примере скрипта ответа на вопросы](https://github.com/huggingface/transformers/blob/master/examples/pytorch/question-answering/trainer_qa.py)), но это слишком длинно для данного раздела. Вместо этого мы будем оценивать модель только в конце обучения, а как проводить регулярную оценку, покажем ниже в разделе "Пользовательский цикл обучения". + +Именно здесь API `Trainer` показывает свои ограничения, а библиотека 🤗 Accelerate блистает: настройка класса под конкретный случай использования может быть болезненной, но настройка полностью открытого цикла обучения - это просто. + +Let's take a look at our `TrainingArguments`: + +```python +from transformers import TrainingArguments + +args = TrainingArguments( + "bert-finetuned-squad", + evaluation_strategy="no", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, + fp16=True, + push_to_hub=True, +) +``` + +Большинство из них мы уже видели: мы задаем некоторые гиперпараметры (например, скорость обучения, количество эпох обучения и затухание веса) и указываем, что хотим сохранять модель в конце каждой эпохи, пропускать оценку и загружать результаты в Model Hub. Мы также включаем обучение со смешанной точностью с `fp16=True`, так как это может значительно ускорить обучение на современных GPU. + +{:else} + +Теперь все готово, и мы можем создать наш TF датасет. На этот раз мы можем использовать простой коллатор данных по умолчанию: + +```python +from transformers import DefaultDataCollator + +data_collator = DefaultDataCollator(return_tensors="tf") +``` + +А теперь создадим датасет, как обычно. + +```python +tf_train_dataset = model.prepare_tf_dataset( + train_dataset, + collate_fn=data_collator, + shuffle=True, + batch_size=16, +) +tf_eval_dataset = model.prepare_tf_dataset( + validation_dataset, + collate_fn=data_collator, + shuffle=False, + batch_size=16, +) +``` + +Далее мы задаем гиперпараметры обучения и компилируем нашу модель: + +```python +from transformers import create_optimizer +from transformers.keras_callbacks import PushToHubCallback +import tensorflow as tf + +# Количество шагов обучения - это количество примеров в датасете, разделенное на размер батча, затем умноженное +# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset, +# а не оригинальный датасет Hugging Face, поэтому его len() уже равен num_samples // batch_size. +num_train_epochs = 3 +num_train_steps = len(tf_train_dataset) * num_train_epochs +optimizer, schedule = create_optimizer( + init_lr=2e-5, + num_warmup_steps=0, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) + +# Обучение со смешанной точностью float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") +``` + +Наконец, мы готовы к обучению с помощью `model.fit()`. Мы используем `PushToHubCallback` для загрузки модели в Hub после каждой эпохи. + +{/if} + +По умолчанию используемый розиторий будет находиться в вашем пространстве имен и называться в соответствии с заданным выходным каталогом, так что в нашем случае он будет находиться в `"sgugger/bert-finetuned-squad"`. Мы можем переопределить это, передав `hub_model_id`; например, чтобы отправить модель в организацию `huggingface_course`, мы использовали `hub_model_id="huggingface_course/bert-finetuned-squad"` (это модель, на которую мы ссылались в начале этого раздела). + +{#if fw === 'pt'} + + + +💡 Если используемый вами выходной каталог существует, он должен быть локальным клоном того розитория, в который вы хотите отправлять данные (поэтому задайте новое имя, если вы получите ошибку при определении `Trainer`). + + + +Наконец, мы просто передаем все в класс `Trainer` и запускаем обучение: + +```python +from transformers import Trainer + +trainer = Trainer( + model=model, + args=args, + train_dataset=train_dataset, + eval_dataset=validation_dataset, + tokenizer=tokenizer, +) +trainer.train() +``` + +{:else} + +```python +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback(output_dir="bert-finetuned-squad", tokenizer=tokenizer) + +# Мы собираемся провести валидацию после обучения, поэтому не нужно проводить валидацию в середине обучения +model.fit(tf_train_dataset, callbacks=[callback], epochs=num_train_epochs) +``` + +{/if} + +Обратите внимание, что во время обучения каждый раз, когда модель сохраняется (здесь - каждую эпоху), она загружается на Hub в фоновом режиме. Таким образом, при необходимости вы сможете возобновить обучение на другой машине. Все обучение занимает некоторое время (чуть больше часа на Titan RTX), поэтому во время его проведения вы можете выпить кофе или перечитать те части курса, которые показались вам более сложными. Также обратите внимание, что как только закончится первая эпоха, вы увидите, что некоторые веса загружены в Hub, и сможете начать играть с вашей моделью на ее странице. + +{#if fw === 'pt'} + +Когда обучение завершено, мы можем наконец оценить нашу модель (и помолиться, что не потратили все это время вычислений впустую). Метод `predict()` функции `Trainer` вернет кортеж, где первыми элементами будут предсказания модели (здесь пара с начальным и конечным логитами). Мы отправляем его в нашу функцию `compute_metrics()`: + +```python +predictions, _, _ = trainer.predict(validation_dataset) +start_logits, end_logits = predictions +compute_metrics(start_logits, end_logits, validation_dataset, raw_datasets["validation"]) +``` + +{:else} + +Когда обучение завершено, мы можем наконец оценить нашу модель (и помолиться, что не потратили все это время вычислений впустую). Метод `predict()` функции `Trainer` вернет кортеж, где первыми элементами будут предсказания модели (здесь пара с начальным и конечным логитами). Мы отправляем его в нашу функцию `compute_metrics()`: + +```python +predictions = model.predict(tf_eval_dataset) +compute_metrics( + predictions["start_logits"], + predictions["end_logits"], + validation_dataset, + raw_datasets["validation"], +) +``` + +{/if} + +```python out +{'exact_match': 81.18259224219489, 'f1': 88.67381321905516} +``` + +Отлично! Для сравнения, базовые показатели, указанные в статье BERT для этой модели, составляют 80,8 и 88,5, так что мы как раз там, где должны быть. + +{#if fw === 'pt'} + +Наконец, мы используем метод `push_to_hub()`, чтобы убедиться, что мы загрузили последнюю версию модели: + +```py +trainer.push_to_hub(commit_message="Training complete") +``` + +Это возвращает URL только что выполненного коммита, если вы хотите его просмотреть: + +```python out +'https://huggingface.co/sgugger/bert-finetuned-squad/commit/9dcee1fbc25946a6ed4bb32efb1bd71d5fa90b68' +``` + +`Trainer` также создает черновик карточки модели со всеми результатами оценки и загружает ее. + +{/if} + +На этом этапе вы можете использовать виджет инференса на Model Hub, чтобы протестировать модель и поделиться ею с друзьями, семьей и любимыми питомцами. Вы успешно провели дообучение модели для задачи ответа на вопрос - поздравляем! + + + +✏️ **Ваша очередь!** Попробуйте другую архитектуру модели, чтобы узнать, лучше ли она справляется с этой задачей! + + + +{#if fw === 'pt'} + +Если вы хотите более глубоко погрузиться в тренировочный цикл, мы покажем вам, как сделать то же самое с помощью 🤗 Accelerate. + +## Пользовательский цикл обучения[[a-custom-training-loop]] + +Теперь давайте посмотрим на полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет очень похож на цикл обучения в [Главе 3](/course/chapter3/4), за исключением цикла оценки. Мы сможем регулярно оценивать модель, поскольку больше не ограничены классом `Trainer`. + +### Подготовим все для обучения[[preparing-everything-for-training]] + +Сначала нам нужно создать `DataLoader`ы из наших датасетов. Мы установим формат этих датасетов в `"torch"` и удалим столбцы в наборе валидации, которые не используются моделью. Затем мы можем использовать `default_data_collator`, предоставляемый Transformers, в качестве `collate_fn` и перемешаем обучающий набор, но не набор для валидации: + +```py +from torch.utils.data import DataLoader +from transformers import default_data_collator + +train_dataset.set_format("torch") +validation_set = validation_dataset.remove_columns(["example_id", "offset_mapping"]) +validation_set.set_format("torch") + +train_dataloader = DataLoader( + train_dataset, + shuffle=True, + collate_fn=default_data_collator, + batch_size=8, +) +eval_dataloader = DataLoader( + validation_set, collate_fn=default_data_collator, batch_size=8 +) +``` + +Затем мы реинстанцируем нашу модель, чтобы убедиться, что мы не продолжаем дообучение, а снова начинаем с предварительно обученной модели BERT: + +```py +model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) +``` + +Тогда нам понадобится оптимизатор. Как обычно, мы используем классический `AdamW`, который похож на Adam, но с исправлением в способе применения затухания веса: + +```py +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=2e-5) +``` + +Когда у нас есть все эти объекты, мы можем отправить их в метод `accelerator.prepare()`. Помните, что если вы хотите обучать на TPU в блокноте Colab, вам нужно будет перенести весь этот код в функцию обучения, которая не должна выполнять ни одну ячейку, инстанцирующую `Accelerator`. Мы можем принудительно обучать со смешанной точностью, передав `fp16=True` в `Accelerator` (или, если вы выполняете код в виде скрипта, просто убедитесь, что заполнили 🤗 Accelerate `config` соответствующим образом). + +```py +from accelerate import Accelerator + +accelerator = Accelerator(fp16=True) +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +Как вы уже поняли из предыдущих разделов, мы можем использовать длину `train_dataloader` для вычисления количества шагов обучения только после того, как она пройдет через метод `accelerator.prepare()`. Мы используем тот же линейный график, что и в предыдущих разделах: + +```py +from transformers import get_scheduler + +num_train_epochs = 3 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +Чтобы отправить нашу модель на Hub, нам нужно создать объект `Repository` в рабочей папке. Сначала войдите в Hub Hugging Face, если вы еще не вошли в него. Мы определим имя розитория по идентификатору модели, который мы хотим присвоить нашей модели (не стесняйтесь заменить `repo_name` на свое усмотрение; оно просто должно содержать ваше имя пользователя, что и делает функция `get_full_repo_name()`): + +```py +from huggingface_hub import Repository, get_full_repo_name + +model_name = "bert-finetuned-squad-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'sgugger/bert-finetuned-squad-accelerate' +``` + +Затем мы можем клонировать этот розиторий в локальную папку. Если она уже существует, эта локальная папка должна быть клоном того розитория, с которым мы работаем: + +```py +output_dir = "bert-finetuned-squad-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +Теперь мы можем загрузить все, что сохранили в `output_dir`, вызвав метод `repo.push_to_hub()`. Это поможет нам загружать промежуточные модели в конце каждой эпохи. + +### Цикл обучения[[training-loop]] + +Теперь мы готовы написать полный цикл обучения. После определения прогресс-бара, чтобы следить за ходом обучения, цикл состоит из трех частей: + +- Собственно обучение, которое представляет собой классическую итерацию по `train_dataloader`, прямой проход по модели, затем обратный проход и шаг оптимизатора. +- Оценка, в которой мы собираем все значения для `start_logits` и `end_logits` перед преобразованием их в массивы NumPy. После завершения цикла оценки мы объединяем все результаты. Обратите внимание, что нам нужно произвести усечение, потому что `Accelerator` может добавить несколько примеров в конце, чтобы убедиться, что у нас одинаковое количество примеров в каждом процессе. +- Сохранение и загрузка, где мы сначала сохраняем модель и токенизатор, а затем вызываем `repo.push_to_hub()`. Как и раньше, мы используем аргумент `blocking=False`, чтобы указать библиотеке 🤗 Hub на асинхронный процесс push. Таким образом, обучение продолжается нормально, а эта (длинная) инструкция выполняется в фоновом режиме. + +Вот полный код цикла обучения: + +```py +from tqdm.auto import tqdm +import torch + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Обучение + model.train() + for step, batch in enumerate(train_dataloader): + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Оценка + model.eval() + start_logits = [] + end_logits = [] + accelerator.print("Evaluation!") + for batch in tqdm(eval_dataloader): + with torch.no_grad(): + outputs = model(**batch) + + start_logits.append(accelerator.gather(outputs.start_logits).cpu().numpy()) + end_logits.append(accelerator.gather(outputs.end_logits).cpu().numpy()) + + start_logits = np.concatenate(start_logits) + end_logits = np.concatenate(end_logits) + start_logits = start_logits[: len(validation_dataset)] + end_logits = end_logits[: len(validation_dataset)] + + metrics = compute_metrics( + start_logits, end_logits, validation_dataset, raw_datasets["validation"] + ) + print(f"epoch {epoch}:", metrics) + + # Сохранение и загрузка + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +Если вы впервые видите модель, сохраненную с помощью 🤗 Accelerate, давайте посмотрим на три строки кода, которые с этим связаны: + +```py +accelerator.wait_for_everyone() +unwrapped_model = accelerator.unwrap_model(model) +unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) +``` + +Первая строка не требует пояснений: она предписывает всем процессам подождать, пока все не окажутся на этой стадии, прежде чем продолжить работу. Это нужно для того, чтобы убедиться, что у нас одна и та же модель в каждом процессе перед сохранением. Затем мы захватываем `unwrapped_model`, которая является базовой моделью, которую мы определили. Метод `accelerator.prepare()` изменяет модель для работы в распределенном обучении, поэтому у нее больше не будет метода `save_pretrained()`; метод `accelerator.unwrap_model()` отменяет этот шаг. Наконец, мы вызываем `save_pretrained()`, но указываем этому методу использовать `accelerator.save()` вместо `torch.save()`. + +После этого у вас должна получиться модель, которая дает результаты, очень похожие на модель, обученную с помощью `Trainer`. Вы можете проверить модель, которую мы обучили с помощью этого кода, на [*huggingface-course/bert-finetuned-squad-accelerate*](https://huggingface.co/huggingface-course/bert-finetuned-squad-accelerate). А если вы хотите протестировать какие-либо изменения в цикле обучения, вы можете напрямую реализовать их, отредактировав код, показанный выше! + +{/if} + +## Использование дообученной модели[[using-the-fine-tuned-model]] + +Мы уже показали вам, как можно использовать модель, дообучение которой мы проводили на Model Hub, с помощью виджета инференса. Чтобы использовать ее локально в `pipeline`, нужно просто указать идентификатор модели: + +```py +from transformers import pipeline + +# Replace this with your own checkpoint +model_checkpoint = "huggingface-course/bert-finetuned-squad" +question_answerer = pipeline("question-answering", model=model_checkpoint) + +context = """ +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question = "Which deep learning libraries back 🤗 Transformers?" +question_answerer(question=question, context=context) +``` + +```python out +{'score': 0.9979003071784973, + 'start': 78, + 'end': 105, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +Отлично! Наша модель работает так же хорошо, как и модель по умолчанию для этого конвейера! diff --git a/chapters/ru/chapter7/8.mdx b/chapters/ru/chapter7/8.mdx new file mode 100644 index 000000000..87842726c --- /dev/null +++ b/chapters/ru/chapter7/8.mdx @@ -0,0 +1,22 @@ +# Освоение NLP[[mastering-nlp]] + + + +Если вы дошли до конца курса, поздравляем - теперь у вас есть все знания и инструменты, необходимые для решения (почти) любой задачи НЛП с помощью 🤗 Transformers и экосистемы Hugging Face! + +Мы видели много разных коллаторов данных, поэтому сделали это небольшое видео, чтобы помочь вам определить, какой из них лучше использовать для каждой задачи: + + + +Пройдя этот молниеносный тур по основным задачам NLP, вы должны: + +* Знать, какие архитектуры (кодер, декодер или кодер-декодер) лучше всего подходят для конкретной задачи +* Понимать разницу между предварительным обучением и дообучением языковой модели +* Знать, как обучать модели Transformer, используя либо API `Trainer` и возможности распределенного обучения в 🤗 Accelerate, либо TensorFlow и Keras, в зависимости от того, какой путь вы выбрали +* Понимать значение и ограничения таких метрик, как ROUGE и BLEU, для задач генерации текста +* Знать, как взаимодействовать с вашими дообученными моделями, как на Hub, так и с помощью `pipeline` из 🤗 Transformers + +Несмотря на все эти знания, настанет момент, когда вы столкнетесь с трудной ошибкой в своем коде или у вас возникнет вопрос о том, как решить ту или иную задачу NLP. К счастью, сообщество Hugging Face готово помочь вам! В заключительной главе этой части курса мы рассмотрим, как можно отлаживать свои модели Transformer и эффективно обращаться за помощью. \ No newline at end of file diff --git a/chapters/ru/chapter7/9.mdx b/chapters/ru/chapter7/9.mdx new file mode 100644 index 000000000..3a99a72eb --- /dev/null +++ b/chapters/ru/chapter7/9.mdx @@ -0,0 +1,329 @@ + + + + +# Тест в конце главы[[end-of-chapter-quiz]] + + + +Давайте проверим, чему вы научились в этой главе! + +### 1. Какую из следующих задач можно сформулировать как проблему классификации токенов? + + + +### 2. Какая часть предварительной обработки для классификации токенов отличается от других конвейеров предварительной обработки? + +-100 для обозначения специальных токенов.", + explain: "Это не относится к классификации токенов - мы всегда используем -100 в качестве метки для токенов, которые мы хотим игнорировать в потерях." + }, + { + text: "При применении усечения/дополнения нам нужно убедиться, что метки имеют тот же размер, что и входные данные.", + explain: "Действительно! Но это не единственное отличие.", + correct: true + } + ]} +/> + +### 3. Какая проблема возникает при токенизации слов в проблеме классификации токенов и при необходимости их маркировки? + + + +### 4. Что означает "доменная адаптация"? + + + +### 5. Что такое метки в проблеме маскированного языкового моделирования? + + + +### 6. Какую из этих задач можно рассматривать как проблему преобразования последовательности-в-последовательность (sequence-to-sequence problem)? + + + +### 7. Каков правильный способ предварительной обработки данных для проблемы преобразования последовательности-в-последовательность? + +inputs=... и targets=....", + explain: "Возможно, в будущем мы добавим такой API, но сейчас это невозможно." + }, + { + text: "Входные данные и цели должны быть предварительно обработаны в двух раздельных вызовах токенизатора.", + explain: "Это правда, но неполная. Вам нужно кое-что сделать, чтобы убедиться, что токенизатор правильно обрабатывает оба варианта." + }, + { + text: "Как обычно, нам просто нужно выполнить токенизацию входных данных.", + explain: "Не в проблеме классификации последовательностей; цели - это тексты, которые мы должны преобразовать в числа!" + }, + { + text: "Входные данные должны быть переданы токенизатору, и цели тоже, но под управлением специального контекстного менеджера.", + explain: "Верно, токенизатор должен быть переведен в target режим этим менеджером контекста.", + correct: true + } + ]} +/> + +{#if fw === 'pt'} + +### 8. Почему существует специальный подкласс `Trainer` для проблем преобразования " последовательности-в-последовательность"? + +-100.", + explain: "Это вовсе не определенные пользователем потери, а то, как потери всегда вычисляются." + }, + { + text: "Поскольку проблемы преобразования последовательности-в-последовательность требуют специального цикла оценки", + explain: "Это верно. Предсказания моделей преобразующих последовательность-в-последовательность часто выполняются с помощью метода generate().", + correct: true + }, + { + text: "Поскольку целью являются тексты в проблемах преобразования последовательности-в-последовательность", + explain: "Trainer не особо заботится об этом, поскольку они уже были предварительно обработаны." + }, + { + text: "Поскольку в проблемах преобразования последовательности-в-последовательность мы используем две модели", + explain: "В некотором смысле мы используем две модели, энкодер и декодер, но они сгруппированы в одну модель." + } + ]} +/> + +{:else} + +### 9. Почему при вызове `compile()` для модели трансформера часто нет необходимости определять потери? + + + +{/if} + +### 10. Когда следует проводить предварительное обучение новой модели? + + + +### 11. Почему легко провести предварительное обучение языковой модели на большом количестве текстов? + + + +### 12. Какие основные проблемы возникают при предварительной обработке данных для задачи ответа на вопрос (question answering)? + + + +### 13. Как обычно выполняется постобработка в задаче ответов на вопросы? + + From 0afa5005ce58e5452a8d20a92ab711279203ce82 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 18 Jan 2024 23:09:23 +0300 Subject: [PATCH 360/502] Update 6.mdx Extra space --- chapters/ru/chapter7/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 61e1231ad..6aa9c0cc7 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -32,7 +32,7 @@ -На самом деле это демонстрация модели, которая была обучена и загружена в Hub с помощью кода, приведенного в этом разделе. Вы можете найти ее [здесь] (https://huggingface.co/huggingface-course/codeparrot-ds?text=plt.imshow%28). Обратите внимание, что поскольку при генерации текста происходит некоторая рандомизация, вы, вероятно, получите немного другой результат. +На самом деле это демонстрация модели, которая была обучена и загружена в Hub с помощью кода, приведенного в этом разделе. Вы можете найти ее [здесь](https://huggingface.co/huggingface-course/codeparrot-ds?text=plt.imshow%28). Обратите внимание, что поскольку при генерации текста происходит некоторая рандомизация, вы, вероятно, получите немного другой результат. ## Сбор данных[[gathering-the-data]] From 4a5a73d253c0eba4d142a651f91a6f7e5a12de77 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 18 Jan 2024 23:12:29 +0300 Subject: [PATCH 361/502] Update 7.mdx Extra space --- chapters/ru/chapter7/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/7.mdx b/chapters/ru/chapter7/7.mdx index ef8371c59..237bbe796 100644 --- a/chapters/ru/chapter7/7.mdx +++ b/chapters/ru/chapter7/7.mdx @@ -26,7 +26,7 @@ -Мы проведем дообучение BERT-модели на датасете [SQuAD] (https://rajpurkar.github.io/SQuAD-explorer/), состоящем из вопросов, заданных краудворкерами по набору статей Википедии. В результате мы получим модель, способную вычислять прогнозы, подобные этому: +Мы проведем дообучение BERT-модели на датасете [SQuAD](https://rajpurkar.github.io/SQuAD-explorer/), состоящем из вопросов, заданных краудворкерами по набору статей Википедии. В результате мы получим модель, способную вычислять прогнозы, подобные этому: From 818c74c3693776663f2ec082b97f4e3b5dc63306 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 20:55:01 +0300 Subject: [PATCH 362/502] Update chapters/ru/chapter7/6.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 6aa9c0cc7..71814065d 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -28,7 +28,7 @@ -В [Главе 6] (/course/chapter6) мы создали эффективный токенизатор для обработки исходного кода Python, но нам все еще нужен крупный датасет для предварительного обучения модели. Здесь мы применим наш токенизатор к корпусу кода Python, полученному из розиториев GitHub. Затем мы воспользуемся API `Trainer` и 🤗 Accelerate для обучения модели. Приступим! +В [Главе 6](../chapter6/1) мы создали эффективный токенизатор для обработки исходного кода Python, но нам все еще нужен крупный датасет для предварительного обучения модели. Здесь мы применим наш токенизатор к корпусу кода Python, полученному из розиториев GitHub. Затем мы воспользуемся API `Trainer` и 🤗 Accelerate для обучения модели. Приступим! From ee2e1ceb9b4a4553ee31aaa2c5dd564382291d89 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 20:55:29 +0300 Subject: [PATCH 363/502] Update chapters/ru/chapter7/6.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 71814065d..6b53aaf2b 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -22,7 +22,7 @@ {/if} -До сих пор мы в основном использовали предварительно обученные модели и осуществляли их дообучение для новых случаев использования, повторно используя веса, полученные в ходе предварительного обучения. Как мы видели в [Главе 1](/course/chapter1), это принято называть _трансферным обучением_, и это очень успешная стратегия применения моделей Transformer для большинства реальных случаев использования, когда размеченных данных недостаточно. В этой главе мы применим другой подход и обучим совершенно новую модель с нуля. Это хороший подход, если у вас много данных, и они сильно отличаются от данных предварительного обучения, используемых для имеющихся моделей. Однако предварительное обучение языковой модели требует значительно больше вычислительных ресурсов, чем дообучение существующей. Примеры, когда имеет смысл обучать новую модель, включают датасеты, состоящие из музыкальных нот, молекулярных последовательностей, таких как ДНК, или языков программирования. Последние в недавнее время получили широкое распространение благодаря таким инструментам, как TabNine и GitHub's Copilot, работающим на основе модели Codex от OpenAI, которые могут генерировать длинные последовательности кода. Для решения этой задачи генерации текста лучше всего подходят авторегрессионные или каузальные языковые модели, такие как GPT-2. +До сих пор мы в основном использовали предварительно обученные модели и осуществляли их дообучение для новых случаев использования, повторно используя веса, полученные в ходе предварительного обучения. Как мы видели в [Главе 1](../chapter1/1), это принято называть _трансферным обучением_, и это очень успешная стратегия применения моделей Transformer для большинства реальных случаев использования, когда размеченных данных недостаточно. В этой главе мы применим другой подход и обучим совершенно новую модель с нуля. Это хороший подход, если у вас много данных, и они сильно отличаются от данных предварительного обучения, используемых для имеющихся моделей. Однако предварительное обучение языковой модели требует значительно больше вычислительных ресурсов, чем дообучение существующей. Примеры, когда имеет смысл обучать новую модель, включают датасеты, состоящие из музыкальных нот, молекулярных последовательностей, таких как ДНК, или языков программирования. Последние в недавнее время получили широкое распространение благодаря таким инструментам, как TabNine и GitHub's Copilot, работающим на основе модели Codex от OpenAI, которые могут генерировать длинные последовательности кода. Для решения этой задачи генерации текста лучше всего подходят авторегрессионные или каузальные языковые модели, такие как GPT-2. В этом разделе мы построим уменьшенную версию модели генерации кода: мы сосредоточимся на однострочных завершениях вместо полных функций или классов, используя подмножество кода Python. Работая с данными на Python, вы часто сталкиваетесь со стеком Data Science на Python, состоящем из библиотек `matplotlib`, `seaborn`, `pandas` и `scikit-learn`. При использовании этих фреймворков часто возникает необходимость поиска определенных команд, поэтому было бы неплохо, если бы мы могли использовать модель выполненяющую эти вызововы за нас. From 45a369c482f6495e4c9e25f96c8532f256d1b056 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 20:55:53 +0300 Subject: [PATCH 364/502] Update chapters/ru/chapter7/6.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 6b53aaf2b..7419a5c45 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -175,7 +175,7 @@ LICENSE: bsd-3-clause''' Первым шагом будет токенизация данных, чтобы мы могли использовать их для обучения. Поскольку наша цель - автозаполнение коротких вызовов функций, мы можем оставить размер контекста относительно небольшим. Благодаря этому мы сможем обучать модель гораздо быстрее, и она будет занимать значительно меньше памяти. Если для вашего приложения важно, чтобы контекст был больше (например, если вы хотите, чтобы модель писала юнит-тесты на основе файла с определением функции), обязательно увеличьте это число, но не забывайте, что это приведет к увеличению объема памяти GPU. Пока что давайте зафиксируем размер контекста на 128 токенов, в отличие от 1 024 или 2 048, используемых в GPT-2 или GPT-3 соответственно. -Большинство документов содержит гораздо больше 128 токенов, поэтому простое обрезание входных данных до максимальной длины приведет к тому, что большая часть нашего датасета будет удалена. Вместо этого мы используем параметр `return_overflowing_tokens` для токенизации всего ввода и разбиения его на части, как мы делали в [Главе 6](/course/chapter6/4). Мы также будем использовать параметр `return_length`, чтобы автоматически возвращать длину каждого созданного фрагмента. Часто последний фрагмент будет меньше размера контекста, и мы избавимся от этих фрагментов, чтобы избежать проблем с дополнением; на самом деле они нам не нужны, поскольку у нас и так много данных. +Большинство документов содержит гораздо больше 128 токенов, поэтому простое обрезание входных данных до максимальной длины приведет к тому, что большая часть нашего датасета будет удалена. Вместо этого мы используем параметр `return_overflowing_tokens` для токенизации всего ввода и разбиения его на части, как мы делали в [Главе 6](../chapter6/4). Мы также будем использовать параметр `return_length`, чтобы автоматически возвращать длину каждого созданного фрагмента. Часто последний фрагмент будет меньше размера контекста, и мы избавимся от этих фрагментов, чтобы избежать проблем с дополнением; на самом деле они нам не нужны, поскольку у нас и так много данных.
Chunking a large texts in several pieces. From 5863024f1153e070b11cf1d90c1f3f30f879a282 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 20:56:01 +0300 Subject: [PATCH 365/502] Update chapters/ru/chapter7/7.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/7.mdx b/chapters/ru/chapter7/7.mdx index 237bbe796..465e253f8 100644 --- a/chapters/ru/chapter7/7.mdx +++ b/chapters/ru/chapter7/7.mdx @@ -217,7 +217,7 @@ for ids in inputs["input_ids"]: Как мы можем видеть, наш пример был разбит на четыре входа, каждый из которых содержит вопрос и часть контекста. Обратите внимание, что ответ на вопрос ("Bernadette Soubirous") появляется только в третьем и последнем входе, поэтому, работая с длинными контекстами таким образом, мы создадим несколько обучающих примеров, в которых ответ не будет включен в контекст. Для этих примеров метками будут `start_position = end_position = 0` (таким образом мы предсказываем токен `[CLS]`). Мы также зададим эти метки в неудачном случае, когда ответ был усечен, так что у нас есть только его начало (или конец). Для примеров, где ответ полностью находится в контексте, метками будут индекс токена, с которого начинается ответ, и индекс токена, на котором ответ заканчивается. -Датасет предоставляет нам начальный символ ответа в контексте, а прибавив к нему длину ответа, мы можем найти конечный символ в контексте. Чтобы сопоставить их с индексами токенов, нам нужно использовать сопоставление смещений, которое мы изучали в [Главе 6](/course/chapter6/4). Мы можем настроить наш токенизатор на их возврат, передав `return_offsets_mapping=True`: +Датасет предоставляет нам начальный символ ответа в контексте, а прибавив к нему длину ответа, мы можем найти конечный символ в контексте. Чтобы сопоставить их с индексами токенов, нам нужно использовать сопоставление смещений, которое мы изучали в [Главе 6](../chapter6/4). Мы можем настроить наш токенизатор на их возврат, передав `return_offsets_mapping=True`: ```py inputs = tokenizer( From 074d4c5eb5d46081673255012ce8eca0a7ea9d48 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 20:56:10 +0300 Subject: [PATCH 366/502] Update chapters/ru/chapter7/6.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 7419a5c45..321db9fa0 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -211,7 +211,7 @@ Chunk mapping: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 Из этих двух примеров видно, что в общей сложности мы получили 34 сегмента. Взглянув на длину фрагментов, мы видим, что фрагменты в конце обоих документов содержат менее 128 токенов (117 и 41, соответственно). Это лишь малая часть всех имеющихся у нас фрагментов, поэтому мы можем смело отбросить их. С помощью поля `overflow_to_sample_mapping` мы также можем восстановить, какие фрагменты принадлежали каким входным примерам. -В этой операции мы используем удобную особенность функции `Dataset.map()` из 🤗 Datasets, которая заключается в том, что она не требует отображения один к одному; как мы видели в [разделе 3](/course/chapter7/3), мы можем создавать батч с большим или меньшим количеством элементов, чем входной батч. Это полезно при выполнении таких операций, как аугментация или фильтрация данных, которые изменяют количество элементов. В нашем случае при токенизации каждого элемента на фрагменты заданного размера контекста мы создаем много примеров из каждого документа. Нам просто нужно убедиться, что мы удалили существующие столбцы, поскольку они имеют противоречивый размер. Если бы мы хотели их сохранить, то могли бы повторить их соответствующим образом и вернуть в рамках вызова `Dataset.map()`: +В этой операции мы используем удобную особенность функции `Dataset.map()` из 🤗 Datasets, которая заключается в том, что она не требует отображения один к одному; как мы видели в [разделе 3](../chapter7/3), мы можем создавать батч с большим или меньшим количеством элементов, чем входной батч. Это полезно при выполнении таких операций, как аугментация или фильтрация данных, которые изменяют количество элементов. В нашем случае при токенизации каждого элемента на фрагменты заданного размера контекста мы создаем много примеров из каждого документа. Нам просто нужно убедиться, что мы удалили существующие столбцы, поскольку они имеют противоречивый размер. Если бы мы хотели их сохранить, то могли бы повторить их соответствующим образом и вернуть в рамках вызова `Dataset.map()`: ```py def tokenize(element): From 3e9107ece6743cdde9dfd9efdb51f411387612ac Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 20:56:17 +0300 Subject: [PATCH 367/502] Update chapters/ru/chapter7/7.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/7.mdx b/chapters/ru/chapter7/7.mdx index 465e253f8..7c4dc5d70 100644 --- a/chapters/ru/chapter7/7.mdx +++ b/chapters/ru/chapter7/7.mdx @@ -529,7 +529,7 @@ len(raw_datasets["validation"]), len(validation_dataset) {/if} -Модель выведет логиты для начальной и конечной позиций ответа во входных идентификаторах, как мы видели при изучении [конвейера `question-answering`](/course/chapter6/3b). Шаг постобработки будет аналогичен тому, что мы делали там, так что вот краткое напоминание о том, что мы делали: +Модель выведет логиты для начальной и конечной позиций ответа во входных идентификаторах, как мы видели при изучении [конвейера `question-answering`](../chapter6/3b). Шаг постобработки будет аналогичен тому, что мы делали там, так что вот краткое напоминание о том, что мы делали: - Мы маскировали начальные и конечные логиты, соответствующие токенам вне контекста. - Затем мы преобразовали начальные и конечные логиты в вероятности с помощью softmax. From 8e74a576d6b948c788c46fe17ea5fa1de630c634 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 20:56:24 +0300 Subject: [PATCH 368/502] Update chapters/ru/chapter7/7.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/7.mdx b/chapters/ru/chapter7/7.mdx index 7c4dc5d70..aada9de77 100644 --- a/chapters/ru/chapter7/7.mdx +++ b/chapters/ru/chapter7/7.mdx @@ -1008,7 +1008,7 @@ trainer.push_to_hub(commit_message="Training complete") ## Пользовательский цикл обучения[[a-custom-training-loop]] -Теперь давайте посмотрим на полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет очень похож на цикл обучения в [Главе 3](/course/chapter3/4), за исключением цикла оценки. Мы сможем регулярно оценивать модель, поскольку больше не ограничены классом `Trainer`. +Теперь давайте посмотрим на полный цикл обучения, чтобы вы могли легко настроить нужные вам части. Он будет очень похож на цикл обучения в [Главе 3](../chapter3/4), за исключением цикла оценки. Мы сможем регулярно оценивать модель, поскольку больше не ограничены классом `Trainer`. ### Подготовим все для обучения[[preparing-everything-for-training]] From 18b0fdf1a37cf3cf9dc23b64dec4f26c4e7a0340 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 20:57:21 +0300 Subject: [PATCH 369/502] Update chapters/ru/chapter7/8.mdx Correction of abbreviation - NLP Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/8.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/8.mdx b/chapters/ru/chapter7/8.mdx index 87842726c..2ef75562c 100644 --- a/chapters/ru/chapter7/8.mdx +++ b/chapters/ru/chapter7/8.mdx @@ -5,7 +5,7 @@ classNames="absolute z-10 right-0 top-0" /> -Если вы дошли до конца курса, поздравляем - теперь у вас есть все знания и инструменты, необходимые для решения (почти) любой задачи НЛП с помощью 🤗 Transformers и экосистемы Hugging Face! +Если вы дошли до конца курса, поздравляем - теперь у вас есть все знания и инструменты, необходимые для решения (почти) любой задачи NLP с помощью 🤗 Transformers и экосистемы Hugging Face! Мы видели много разных коллаторов данных, поэтому сделали это небольшое видео, чтобы помочь вам определить, какой из них лучше использовать для каждой задачи: From 5bfa31b66758dfd355e98081e97c35dcffa324c7 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 21:01:17 +0300 Subject: [PATCH 370/502] Update 7.mdx Translated the code commentary --- chapters/ru/chapter7/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/7.mdx b/chapters/ru/chapter7/7.mdx index aada9de77..547200018 100644 --- a/chapters/ru/chapter7/7.mdx +++ b/chapters/ru/chapter7/7.mdx @@ -1181,7 +1181,7 @@ unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) ```py from transformers import pipeline -# Replace this with your own checkpoint +# Замените здесь на выбранную вами контрольную точку model_checkpoint = "huggingface-course/bert-finetuned-squad" question_answerer = pipeline("question-answering", model=model_checkpoint) From 9af60804271ee2bdb4469f38fa038793d4dfd343 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 21:03:44 +0300 Subject: [PATCH 371/502] Update 6.mdx Translated the missing sentence. --- chapters/ru/chapter7/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 321db9fa0..042ba69fe 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -38,7 +38,7 @@ Код на Python в изобилии доступен в таких репозиториях кода, как GitHub, и мы можем использовать его для создания датасета путем поиска каждого розитория Python. Именно такой подход был использован в книге [Transformers textbook](https://learning.oreilly.com/library/view/natural-language-processing/9781098136789/) для предварительного обучения большой модели GPT-2. Используя дамп GitHub объемом около 180 ГБ, содержащий примерно 20 миллионов файлов Python под названием `codeparrot`, авторы создали датасет, которым затем поделились на [Hugging Face Hub](https://huggingface.co/datasets/transformersbook/codeparrot). -Однако обучение на полном корпусе требует много времени и вычислений, а нам нужно только подмножество датасетов, связанных со стеком data science на Python. Итак, давайте начнем с фильтрации датасета `codeparrot` по всем файлам, включающим любую из библиотек из этого стека. Из-за большого размера датасета мы хотим избежать его загрузки; вместо этого мы будем использовать функцию потоковой передачи (streaming), чтобы фильтровать его на лету. To help us filter the code samples using the libraries we mentioned earlier, we'll use the following function: +Однако обучение на полном корпусе требует много времени и вычислений, а нам нужно только подмножество датасетов, связанных со стеком data science на Python. Итак, давайте начнем с фильтрации датасета `codeparrot` по всем файлам, включающим любую из библиотек из этого стека. Из-за большого размера датасета мы хотим избежать его загрузки; вместо этого мы будем использовать функцию потоковой передачи (streaming), чтобы фильтровать его на лету. Чтобы помочь нам отфильтровать примеры кода с использованием библиотек, о которых мы говорили ранее, мы воспользуемся следующей функцией: ```py def any_keyword_in_string(string, keywords): From f667bea7bf2783113dc95ae7c470f80db0a65a92 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 21:05:42 +0300 Subject: [PATCH 372/502] Update chapters/ru/chapter7/7.mdx Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/7.mdx b/chapters/ru/chapter7/7.mdx index 547200018..4fce30202 100644 --- a/chapters/ru/chapter7/7.mdx +++ b/chapters/ru/chapter7/7.mdx @@ -34,7 +34,7 @@ -💡 Модели, основанные только на энкодере, такие как BERT, как правило, отлично справляются с извлечением ответов на фактоидные вопросы типа "Кто изобрел архитектуру трансформера?", но плохо справляются с открытыми вопросами типа "Почему небо голубое?". В таких сложных случаях для синтеза информации обычно используются модели энкодеров-декодеров, такие как T5 и BART, что очень похоже на [сумризацию текста](/course/chapter7/5). Если вам интересен этот тип *генеративных* ответов на вопросы, рекомендуем ознакомиться с нашим [демо](https://yjernite.github.io/lfqa.html) основанным на [датасете ELI5(https://huggingface.co/datasets/eli5). +💡 Модели, основанные только на энкодере, такие как BERT, как правило, отлично справляются с извлечением ответов на фактоидные вопросы типа "Кто изобрел архитектуру трансформера?", но плохо справляются с открытыми вопросами типа "Почему небо голубое?". В таких сложных случаях для синтеза информации обычно используются модели энкодеров-декодеров, такие как T5 и BART, что очень похоже на [сумризацию текста](/course/chapter7/5). Если вам интересен этот тип *генеративных* ответов на вопросы, рекомендуем ознакомиться с нашим [демо](https://yjernite.github.io/lfqa.html) основанным на [датасете ELI5](https://huggingface.co/datasets/eli5). From 844825dd78d6cca38b65432722f6138295dab7f3 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 21:11:31 +0300 Subject: [PATCH 373/502] Update 6.mdx --- chapters/ru/chapter7/6.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 042ba69fe..56d0838c8 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -259,7 +259,7 @@ DatasetDict({ -## Initializing a new model[[initializing-a-new-model]] +## Инициализация новой модели[[initializing-a-new-model]] Наш первый шаг - инициализация свежей модели GPT-2. Мы будем использовать ту же конфигурацию для нашей модели, что и для маленькой модели GPT-2, поэтому загрузим предварительно обученную конфигурацию, убедимся, что размер токенизатора соответствует размеру словарного запаса модели, и передадим идентификаторы токенов `bos` и `eos` (начало и конец последовательности): @@ -307,7 +307,7 @@ config = AutoConfig.from_pretrained( ```py model = TFGPT2LMHeadModel(config) -model(model.dummy_inputs) # Builds the model +model(model.dummy_inputs) # Создание модели model.summary() ``` From 991c4adb2497ec452c3172c429d912d4da818574 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 21:13:17 +0300 Subject: [PATCH 374/502] Update chapters/ru/chapter7/6.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 56d0838c8..462f2b6f2 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -769,7 +769,7 @@ def evaluate(): return loss.item(), perplexity.item() ``` -С помощью функции `evaluate()` мы можем сообщать о потерях и [перплексии](/course/chapter7/3) через регулярные промежутки времени. Далее мы переопределим нашу модель, чтобы убедиться, что мы снова обучаемся с нуля: +С помощью функции `evaluate()` мы можем сообщать о потерях и [перплексии](../chapter7/3) через регулярные промежутки времени. Далее мы переопределим нашу модель, чтобы убедиться, что мы снова обучаемся с нуля: ```py model = GPT2LMHeadModel(config) From 9ca10133889a818c7fad50e26b7f85f54970a4da Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 21:14:36 +0300 Subject: [PATCH 375/502] Update chapters/ru/chapter7/7.mdx Correcting a link Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/7.mdx b/chapters/ru/chapter7/7.mdx index 4fce30202..c3c6764c1 100644 --- a/chapters/ru/chapter7/7.mdx +++ b/chapters/ru/chapter7/7.mdx @@ -185,7 +185,7 @@ tokenizer.decode(inputs["input_ids"])
-В данном случае контекст не слишком длинный, но некоторые примеры в датасете имеют очень длинные контексты, которые превысят установленную нами максимальную длину (которая в данном случае равна 384). Как мы видели в [Главе 6] (/course/chapter6/4), когда изучали внутреннее устройство конвейера `question-answering`, мы будем работать с длинными контекстами, создавая несколько обучающих признаков из одной выборки нашего датасета, со скользящим окном между ними. +В данном случае контекст не слишком длинный, но некоторые примеры в датасете имеют очень длинные контексты, которые превысят установленную нами максимальную длину (которая в данном случае равна 384). Как мы видели в [Главе 6](../chapter6/4), когда изучали внутреннее устройство конвейера `question-answering`, мы будем работать с длинными контекстами, создавая несколько обучающих признаков из одной выборки нашего датасета, со скользящим окном между ними. Чтобы увидеть, как это работает на текущем примере, мы можем ограничить длину до 100 и использовать скользящее окно из 50 токенов. В качестве напоминания мы используем: From 3540d5f5148ff4287d16efdf355f1429990cabb7 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 19 Jan 2024 21:15:04 +0300 Subject: [PATCH 376/502] Update chapters/ru/chapter7/6.mdx Co-authored-by: Maria Khalusova --- chapters/ru/chapter7/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter7/6.mdx b/chapters/ru/chapter7/6.mdx index 462f2b6f2..6ade23c1c 100644 --- a/chapters/ru/chapter7/6.mdx +++ b/chapters/ru/chapter7/6.mdx @@ -797,7 +797,7 @@ model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( -🚨 Если вы проводите обучение на TPU, вам нужно будет перенести весь код, начиная с ячейки выше, в выделенную функцию обучения. Подробнее смотрите [Главу 3](/course/chapter3). +🚨 Если вы проводите обучение на TPU, вам нужно будет перенести весь код, начиная с ячейки выше, в выделенную функцию обучения. Подробнее смотрите [Главу 3](../chapter3/1). From 03736294db6d4c96074182d2b004d8c11c3cd6e8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 27 Jan 2024 10:16:20 +0300 Subject: [PATCH 377/502] 8/1-2 done --- chapters/ru/chapter8/1.mdx | 17 ++ chapters/ru/chapter8/2.mdx | 338 +++++++++++++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 chapters/ru/chapter8/1.mdx create mode 100644 chapters/ru/chapter8/2.mdx diff --git a/chapters/ru/chapter8/1.mdx b/chapters/ru/chapter8/1.mdx new file mode 100644 index 000000000..eb58afd22 --- /dev/null +++ b/chapters/ru/chapter8/1.mdx @@ -0,0 +1,17 @@ +# Введение[[introduction]] + + + +Теперь, когда вы знаете, как решать самые распространенные задачи NLP с помощью 🤗 Transformers, вы должны быть в состоянии начать работу над своими собственными проектами! В этой главе мы рассмотрим, что делать, если вы столкнулись с проблемой. Вы узнаете, как успешно отладить свой код или обучение, как обратиться за помощью к сообществу, если не удается решить проблему самостоятельно. А если вам покажется, что вы нашли ошибку в одной из библиотек Hugging Face, мы покажем вам, как лучше сообщить об этом, чтобы проблема была решена как можно быстрее. + +Точнее, в этой главе вы узнаете: + +- Что нужно делать в первую очередь при возникновении ошибки +- Как обратиться за помощью на [форумах](https://discuss.huggingface.co/) +- Как отладить свой пайплайн обучения +- Как правильно описать проблему + +Разумеется, все это не относится конкретно к 🤗 Transformers или экосистеме Hugging Face; уроки из этой главы применимы к большинству проектов с открытым исходным кодом! \ No newline at end of file diff --git a/chapters/ru/chapter8/2.mdx b/chapters/ru/chapter8/2.mdx new file mode 100644 index 000000000..950ef99c0 --- /dev/null +++ b/chapters/ru/chapter8/2.mdx @@ -0,0 +1,338 @@ +# Что делать, если возникла ошибку[[what-to-do-when-you-get-an-error]] + + + +В этом разделе мы рассмотрим некоторые распространенные ошибки, которые могут возникнуть при попытке сгенерировать предсказания на основе только что настроенной модели Transformer. Это подготовит вас к [разделу 4](../chapter8/section4), где мы рассмотрим, как отладить сам этап обучения. + + + +Для этого раздела мы подготовили [репозиторий](https://huggingface.co/lewtun/distilbert-base-uncased-finetuned-squad-d5716d28), и если вы хотите запустить код в этой главе, вам сначала нужно скопировать модель в свой аккаунт на [Hugging Face Hub](https://huggingface.co). Для этого сначала войдите в систему, запустив в блокноте Jupyter одно из следующих действий: + +``python +from huggingface_hub import notebook_login + +notebook_login() +``` + +или следующее в вашем любимом терминале: + +``bash +huggingface-cli login +``` + +Это попросит вас ввести имя пользователя и пароль и сохранит токен в *~/.cache/huggingface/*. После того как вы вошли в систему, вы можете скопировать хранилище шаблонов с помощью следующей функции: + +``python +from distutils.dir_util import copy_tree +from huggingface_hub import Repository, snapshot_download, create_repo, get_full_repo_name + + +def copy_repository_template(): + # Клонируем репозиторий и извлекаем локальный путь + template_repo_id = "lewtun/distilbert-base-uncased-finetuned-squad-d5716d28" + commit_hash = "be3eaffc28669d7932492681cd5f3e8905e358b4" + template_repo_dir = snapshot_download(template_repo_id, revision=commit_hash) + # Создайте пустое репо на хабе + имя_модели = template_repo_id.split("/")[1] + create_repo(model_name, exist_ok=True) + # Клонирование пустого репо + new_repo_id = get_full_repo_name(model_name) + new_repo_dir = имя_модели + repo = Repository(local_dir=new_repo_dir, clone_from=new_repo_id) + # Копирование файлов + copy_tree(template_repo_dir, new_repo_dir) + # Отправить в хаб + repo.push_to_hub() +``` + +Теперь при вызове `copy_repository_template()` будет создана копия хранилища шаблонов под вашим аккаунтом. + +## Отладка конвейера из 🤗 Transformers[[debugging-the-pipeline-from-transformers]] + +Чтобы начать наше путешествие в удивительный мир отладки моделей трансформеров, рассмотрим следующий сценарий: вы работаете с коллегой над проектом ответа на вопросы, который должен помочь клиентам сайта электронной коммерции найти ответы о потребительских товарах. Ваш коллега отправляет вам сообщение следующего содержания: + +> Добрый день! Я только что провел эксперимент, используя техники из [главы 7](../chapter7/7) курса Hugging Face, и получил отличные результаты на SQuAD! Думаю, мы можем использовать эту модель в качестве отправной точки для нашего проекта. ID модели на хабе - "lewtun/distillbert-base-uncased-finetuned-squad-d5716d28". Не стесняйтесь протестировать ее :) + +и первое, что приходит в голову, это загрузить модель, используя `pipeline` из 🤗 Transformers: + +``python +from transformers import pipeline + +model_checkpoint = get_full_repo_name("distillbert-base-uncased-finetuned-squad-d5716d28") +reader = pipeline("question-answering", model=model_checkpoint) +``` + +``python out +""" +OSError: Невозможно загрузить конфигурацию для 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28'. Убедитесь, что: + +- 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' - это правильный идентификатор модели, указанный на 'https://huggingface.co/models'. + +- или 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' - это правильный путь к директории, содержащей файл config.json +""" +``` + + + +💡 Если вы столкнулись с сообщением об ошибке, которое трудно понять, просто скопируйте и вставьте его в строку поиска Google или [Stack Overflow](https://stackoverflow.com/) (да, действительно!). Велика вероятность того, что вы не первый, кто столкнулся с этой ошибкой, и это хороший способ найти решения, которые опубликовали другие члены сообщества. Например, поиск по запросу `OSError: Can't load config for` на Stack Overflow дает несколько [результатов](https://stackoverflow.com/search?q=OSError%3A+Can%27t+load+config+for+), которые можно использовать в качестве отправной точки для решения проблемы. + + + +В первом предложении нам предлагается проверить, действительно ли идентификатор модели правильный, поэтому первым делом нужно скопировать идентификатор и вставить его в строку поиска Hub: + +
+The wrong model name. +
+ +Хм, действительно, похоже, что модели нашего коллеги нет на хабе... ага, но в названии модели опечатка! В названии DistilBERT есть только одна буква "l", так что давайте исправим это и поищем вместо нее "lewtun/distilbert-base-uncased-finetuned-squad-d5716d28": + +
+The right model name. +
+ +Хорошо!. Теперь давайте попробуем загрузить модель снова с правильным идентификатором модели: + +```python +model_checkpoint = get_full_repo_name("distilbert-base-uncased-finetuned-squad-d5716d28") +reader = pipeline("question-answering", model=model_checkpoint) +``` + +```python out +""" +OSError: Can't load config for 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28'. Make sure that: + +- 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models' + +- or 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file +""" +``` + +Cнова неудача - добро пожаловать в повседневную жизнь инженера машинного обучения! Поскольку мы исправили ID модели, проблема должна заключаться в самом репозитории. Быстрый способ получить доступ к содержимому репозитория на 🤗 Hub - это функция `list_repo_files()` библиотеки `huggingface_hub`: + +```python +from huggingface_hub import list_repo_files + +list_repo_files(repo_id=model_checkpoint) +``` + +```python out +['.gitattributes', 'README.md', 'pytorch_model.bin', 'special_tokens_map.json', 'tokenizer_config.json', 'training_args.bin', 'vocab.txt'] +``` + +Интересно - похоже, что в репозитории нет файла *config.json*! Неудивительно, что наш `pipeline` не смог загрузить модель; наш коллега, должно быть, забыл выложить этот файл в Hub после того, как выполнил дообучение. В этом случае проблема кажется довольно простой: мы можем попросить его добавить этот файл, или, поскольку из идентификатора модели видно, что использовалась предварительно обученная модель [`distilbert-base-uncased`](https://huggingface.co/distilbert-base-uncased), мы можем загрузить конфигурацию для этой модели и отправить ее в наше репо, чтобы посмотреть, решит ли это проблему. Давайте попробуем это сделать. Используя приемы, изученные в [Главе 2](../chapter2/1), мы можем загрузить конфигурацию модели с помощью класса `AutoConfig`: + +```python +from transformers import AutoConfig + +pretrained_checkpoint = "distilbert-base-uncased" +config = AutoConfig.from_pretrained(pretrained_checkpoint) +``` + + + +🚨 Применяемый здесь подход не является надежным, поскольку наш коллега мог изменить конфигурацию `distilbert-base-uncased` перед дообучением модели. В реальной жизни мы бы хотели сначала уточнить у него, но для целей этого раздела будем считать, что он использовал конфигурацию по умолчанию. + + + +Затем мы можем отправить это в наш репозиторий моделей вместе с конфигурацией с помощью функции `push_to_hub()`: + +```python +config.push_to_hub(model_checkpoint, commit_message="Add config.json") +``` + +Теперь мы можем проверить, работает ли это, загрузив модель из последнего коммита в ветке `main`: + +```python +reader = pipeline("question-answering", model=model_checkpoint, revision="main") + +context = r""" +Extractive Question Answering is the task of extracting an answer from a text +given a question. An example of a question answering dataset is the SQuAD +dataset, which is entirely based on that task. If you would like to fine-tune a +model on a SQuAD task, you may leverage the +examples/pytorch/question-answering/run_squad.py script. + +🤗 Transformers is interoperable with the PyTorch, TensorFlow, and JAX +frameworks, so you can use your favourite tools for a wide variety of tasks! +""" + +question = "What is extractive question answering?" +reader(question=question, context=context) +``` + +```python out +{'score': 0.38669535517692566, + 'start': 34, + 'end': 95, + 'answer': 'the task of extracting an answer from a text given a question'} +``` + +Ух ты, сработало! Давайте вспомним, что вы только что узнали: + +- Сообщения об ошибках в Python называются _tracebacks_ и читаются снизу вверх. Последняя строка сообщения об ошибке обычно содержит информацию, необходимую для поиска источника проблемы. +- Если последняя строка не содержит достаточной информации, пройдите путь вверх по трассировке и посмотрите, сможете ли вы определить, в каком месте исходного кода возникла ошибка. +- Если ни одно из сообщений об ошибках не помогло вам отладить проблему, попробуйте поискать в Интернете решение аналогичной проблемы. +- The `huggingface_hub` +// 🤗 Hub? +предоставляет набор инструментов, с помощью которых вы можете взаимодействовать с репозиториями на Хабе и отлаживать их. + +Теперь, когда вы знаете, как отлаживать конвейер, давайте рассмотрим более сложный пример на прямом проходе самой модели. + +## Отладка прямого прохода модели[[debugging-the-forward-pass-of-your-model]] + +Хотя `pipeline` отлично подходит для большинства приложений, где вам нужно быстро генерировать предсказания, иногда вам понадобится доступ к логам модели (например, если вы хотите применить какую-то пользовательскую постобработку). Чтобы увидеть, что может пойти не так в этом случае, давайте сначала возьмем модель и токенизатор: + +```python +tokenizer = reader.tokenizer +model = reader.model +``` + +Далее нам нужен вопрос, поэтому давайте посмотрим, поддерживаются ли наши любимые фреймворки: + +```python +question = "Which frameworks can I use?" +``` + +Как мы видели в [Главе 7] (../chapter7/1), обычные шаги, которые нам нужно предпринять, - это токенизация входных данных, извлечение логитов начальных и конечных токенов, а затем декодирование диапазона ответов: + +```python +import torch + +inputs = tokenizer(question, context, add_special_tokens=True) +input_ids = inputs["input_ids"][0] +outputs = model(**inputs) +answer_start_scores = outputs.start_logits +answer_end_scores = outputs.end_logits +# Get the most likely beginning of answer with the argmax of the score +answer_start = torch.argmax(answer_start_scores) +# Get the most likely end of answer with the argmax of the score +answer_end = torch.argmax(answer_end_scores) + 1 +answer = tokenizer.convert_tokens_to_string( + tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end]) +) +print(f"Question: {question}") +print(f"Answer: {answer}") +``` + +```python out +""" +--------------------------------------------------------------------------- +AttributeError Traceback (most recent call last) +/var/folders/28/k4cy5q7s2hs92xq7_h89_vgm0000gn/T/ipykernel_75743/2725838073.py in + 1 inputs = tokenizer(question, text, add_special_tokens=True) + 2 input_ids = inputs["input_ids"] +----> 3 outputs = model(**inputs) + 4 answer_start_scores = outputs.start_logits + 5 answer_end_scores = outputs.end_logits + +~/miniconda3/envs/huggingface/lib/python3.8/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs) + 1049 if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks + 1050 or _global_forward_hooks or _global_forward_pre_hooks): +-> 1051 return forward_call(*input, **kwargs) + 1052 # Do not call functions when jit is used + 1053 full_backward_hooks, non_full_backward_hooks = [], [] + +~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, start_positions, end_positions, output_attentions, output_hidden_states, return_dict) + 723 return_dict = return_dict if return_dict is not None else self.config.use_return_dict + 724 +--> 725 distilbert_output = self.distilbert( + 726 input_ids=input_ids, + 727 attention_mask=attention_mask, + +~/miniconda3/envs/huggingface/lib/python3.8/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs) + 1049 if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks + 1050 or _global_forward_hooks or _global_forward_pre_hooks): +-> 1051 return forward_call(*input, **kwargs) + 1052 # Do not call functions when jit is used + 1053 full_backward_hooks, non_full_backward_hooks = [], [] + +~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, output_attentions, output_hidden_states, return_dict) + 471 raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time") + 472 elif input_ids is not None: +--> 473 input_shape = input_ids.size() + 474 elif inputs_embeds is not None: + 475 input_shape = inputs_embeds.size()[:-1] + +AttributeError: 'list' object has no attribute 'size' +""" +``` + +Похоже, что в нашем коде есть ошибка! Но мы не боимся небольшой отладки. Вы можете использовать отладчик Python в блокноте: + + + +or in a terminal: + + + +Здесь чтение сообщения об ошибке говорит нам, что у объекта `'list'' нет атрибута 'size', и мы видим стрелку `-->`, указывающую на строку, где возникла проблема в `model(**inputs)`. Вы можете отладить это интерактивно, используя отладчик Python, но сейчас мы просто распечатаем фрагмент `inputs`, чтобы посмотреть, что у нас есть: + +```python +inputs["input_ids"][:5] +``` + +```python out +[101, 2029, 7705, 2015, 2064] +``` + +Конечно, это выглядит как обычный `list` в Python, но давайте перепроверим тип: + +```python +type(inputs["input_ids"]) +``` + +```python out +list +``` + +Да, это точно список Python. Так что же пошло не так? Вспомним из [Главы 2](../chapter2), что классы `AutoModelForXxx` в 🤗 Transformers работают с _тензорами_ (либо в PyTorch, либо в TensorFlow), и обычной операцией является извлечение размерности тензора с помощью `Tensor.size()`, скажем, в PyTorch. Давайте еще раз посмотрим на трассировку, чтобы увидеть, какая строка вызвала исключение: + +``` +~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, output_attentions, output_hidden_states, return_dict) + 471 raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time") + 472 elif input_ids is not None: +--> 473 input_shape = input_ids.size() + 474 elif inputs_embeds is not None: + 475 input_shape = inputs_embeds.size()[:-1] + +AttributeError: 'list' object has no attribute 'size' +``` + +Похоже, что наш код пытался вызвать `input_ids.size()`, но это явно не сработает для Python `list`. Как мы можем решить эту проблему? Поиск сообщения об ошибке на Stack Overflow дает довольно много релевантных [результатов](https://stackoverflow.com/search?q=AttributeError%3A+%27list%27+object+has+no+attribute+%27size%27&s=c15ec54c-63cb-481d-a749-408920073e8f). При нажатии на первую из них появляется вопрос, аналогичный нашему, ответ на который показан на скриншоте ниже: + +
+An answer from Stack Overflow. +
+ +В ответе рекомендуется добавить в токенизатор `return_tensors='pt'`, так что давайте посмотрим, сработает ли это для нас: + +```python out +inputs = tokenizer(question, context, add_special_tokens=True, return_tensors="pt") +input_ids = inputs["input_ids"][0] +outputs = model(**inputs) +answer_start_scores = outputs.start_logits +answer_end_scores = outputs.end_logits +# Get the most likely beginning of answer with the argmax of the score +answer_start = torch.argmax(answer_start_scores) +# Get the most likely end of answer with the argmax of the score +answer_end = torch.argmax(answer_end_scores) + 1 +answer = tokenizer.convert_tokens_to_string( + tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end]) +) +print(f"Question: {question}") +print(f"Answer: {answer}") +``` + +```python out +""" +Question: Which frameworks can I use? +Answer: pytorch, tensorflow, and jax +""" +``` + +Отлично, это сработало! Это отличный пример того, насколько полезным может быть Stack Overflow: найдя похожую проблему, мы смогли воспользоваться опытом других членов сообщества. Однако подобный поиск не всегда дает нужный ответ, так что же делать в таких случаях? К счастью, на [Hugging Face forums](https://discuss.huggingface.co/) есть гостеприимное сообщество разработчиков, которые могут вам помочь! В следующем разделе мы рассмотрим, как составить хорошие вопросы на форуме, на которые, скорее всего, будет получен ответ. \ No newline at end of file From 5a822a9ebb650ea254577c2eb040bbd6495a6efa Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 27 Jan 2024 10:33:08 +0300 Subject: [PATCH 378/502] 8/3 finished --- chapters/ru/chapter8/3.mdx | 164 +++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 chapters/ru/chapter8/3.mdx diff --git a/chapters/ru/chapter8/3.mdx b/chapters/ru/chapter8/3.mdx new file mode 100644 index 000000000..2464bf683 --- /dev/null +++ b/chapters/ru/chapter8/3.mdx @@ -0,0 +1,164 @@ +# Обращение за помощью на форумах[[asking-for-help-on-the-forums]] + + + + + +Форумы [Hugging Face](https://discuss.huggingface.co) - это отличное место, где можно получить помощь от команды разработчиков с открытым исходным кодом и более широкого сообщества Hugging Face. Вот как выглядит главная страница в любой день: + +
+The Hugging Face forums. +
+ +С левой стороны вы можете увидеть все категории, по которым сгруппированы различные темы, а с правой - самые последние темы. Тема - это сообщение, содержащее заголовок, категорию и описание; это очень похоже на формат вопросов GitHub, который мы видели при создании нашего собственного набора данных в [Главе 5](../chapter5). Как следует из названия, категория [Beginners](https://discuss.huggingface.co/c/beginners/5) предназначена в первую очередь для тех, кто только начинает знакомиться с библиотеками и экосистемой Hugging Face. Здесь можно задать любой вопрос по любой из библиотек, будь то отладка кода или просьба о помощи, как что-то сделать. (При этом, если ваш вопрос касается какой-то конкретной библиотеки, вам, вероятно, следует обратиться в соответствующую категорию библиотек на форуме). + +Аналогично, категории [Intermediate](https://discuss.huggingface.co/c/intermediate/6) и [Research](https://discuss.huggingface.co/c/research/7) предназначены для более сложных вопросов, например, о библиотеках или новых крутых исследованиях в области НЛП, которые вы хотели бы обсудить. + +И, конечно же, нельзя не упомянуть категорию [Course](https://discuss.huggingface.co/c/course/20), где вы можете задавать любые вопросы, связанные с курсом "Hugging Face"! + +Выбрав категорию, вы будете готовы написать свою первую тему. На форуме вы можете найти несколько [рекомендаций](https://discuss.huggingface.co/t/how-to-request-support/3128) о том, как это сделать, а в этом разделе мы рассмотрим некоторые особенности, из которых складывается хорошая просьба о помощи. + +## Написание хорошего поста на форуме[[writing-a-good-forum-post]] + +В качестве примера предположим, что мы пытаемся сгенерировать векторные представления статей Википедии для создания пользовательской поисковой системы. Как обычно, мы загружаем токенизатор и модель следующим образом: + +```python +from transformers import AutoTokenizer, AutoModel + +model_checkpoint = "distilbert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModel.from_pretrained(model_checkpoint) +``` + +Теперь предположим, что мы попытаемся построить векторное представления для целого раздела [статьи с Википедии](https://en.wikipedia.org/wiki/Transformers), посвященной Трансформерам (модели, а не библиотеке!): + +```python +text = """ +Generation One is a retroactive term for the Transformers characters that +appeared between 1984 and 1993. The Transformers began with the 1980s Japanese +toy lines Micro Change and Diaclone. They presented robots able to transform +into everyday vehicles, electronic items or weapons. Hasbro bought the Micro +Change and Diaclone toys, and partnered with Takara. Marvel Comics was hired by +Hasbro to create the backstory; editor-in-chief Jim Shooter wrote an overall +story, and gave the task of creating the characthers to writer Dennis O'Neil. +Unhappy with O'Neil's work (although O'Neil created the name "Optimus Prime"), +Shooter chose Bob Budiansky to create the characters. + +The Transformers mecha were largely designed by Shōji Kawamori, the creator of +the Japanese mecha anime franchise Macross (which was adapted into the Robotech +franchise in North America). Kawamori came up with the idea of transforming +mechs while working on the Diaclone and Macross franchises in the early 1980s +(such as the VF-1 Valkyrie in Macross and Robotech), with his Diaclone mechs +later providing the basis for Transformers. + +The primary concept of Generation One is that the heroic Optimus Prime, the +villainous Megatron, and their finest soldiers crash land on pre-historic Earth +in the Ark and the Nemesis before awakening in 1985, Cybertron hurtling through +the Neutral zone as an effect of the war. The Marvel comic was originally part +of the main Marvel Universe, with appearances from Spider-Man and Nick Fury, +plus some cameos, as well as a visit to the Savage Land. + +The Transformers TV series began around the same time. Produced by Sunbow +Productions and Marvel Productions, later Hasbro Productions, from the start it +contradicted Budiansky's backstories. The TV series shows the Autobots looking +for new energy sources, and crash landing as the Decepticons attack. Marvel +interpreted the Autobots as destroying a rogue asteroid approaching Cybertron. +Shockwave is loyal to Megatron in the TV series, keeping Cybertron in a +stalemate during his absence, but in the comic book he attempts to take command +of the Decepticons. The TV series would also differ wildly from the origins +Budiansky had created for the Dinobots, the Decepticon turned Autobot Jetfire +(known as Skyfire on TV), the Constructicons (who combine to form +Devastator),[19][20] and Omega Supreme. The Marvel comic establishes early on +that Prime wields the Creation Matrix, which gives life to machines. In the +second season, the two-part episode The Key to Vector Sigma introduced the +ancient Vector Sigma computer, which served the same original purpose as the +Creation Matrix (giving life to Transformers), and its guardian Alpha Trion. +""" + +inputs = tokenizer(text, return_tensors="pt") +logits = model(**inputs).logits +``` + +```python output +IndexError: index out of range in self +``` + +О-о, мы столкнулись с проблемой - и сообщение об ошибке гораздо более загадочно, чем те, что мы видели в [разделе 2](2.mdx)! Мы не можем разобраться в полном её описании, поэтому решили обратиться за помощью на форум Hugging Face. Как мы можем создать тему? + +Чтобы начать, нам нужно нажать кнопку "Новая тема" в правом верхнем углу (обратите внимание, что для создания темы нам нужно войти в систему): + +
+Creating a new forum topic. +
+ +Откроется интерфейс для написания текста, где мы можем ввести название темы, выбрать категорию и составить сообщение: + +
+The interface for creating a forum topic. +
+ +Поскольку ошибка, похоже, связана исключительно с 🤗 Transformers, мы выберем эту категорию. Наша первая попытка объяснить проблему может выглядеть примерно так: + +
+Drafting the content for a new forum topic. +
+ +Хотя эта тема содержит сообщение об ошибке, с которой нам нужна помощь, есть несколько проблем с тем, как оно написано: + +1. Заголовок не очень содержателен, поэтому любой, кто просматривает форум, не сможет понять, о чем идет речь, не прочитав и основной текст. +2. В тексте недостаточно информации о том, откуда берется ошибка и как ее воспроизвести. +3. В теме прямо указывается несколько человек, причем в несколько требовательном тоне. + +Такие темы, как эта, вряд ли получат быстрый ответ (если вообще получат), так что давайте посмотрим, как можно их улучшить. Начнем с первого вопроса - выбора хорошего названия. + +### Выбор содержательного названия[[choosing-a-descriptive-title]] + +Если вы пытаетесь получить помощь по поводу ошибки в вашем коде, хорошим правилом является включение достаточного количества информации в заголовок, чтобы другие могли быстро определить, смогут ли они ответить на ваш вопрос или нет. В нашем примере мы знаем имя возникающего исключения и имеем некоторые намеки на то, что оно срабатывает в прямом проходе модели, где мы вызываем `model(**inputs)`. Чтобы сообщить об этом, один из возможных вариантов заголовка может быть таким: + +> Source of IndexError in the AutoModel forward pass? + +Этот заголовок сообщает читателю, откуда, по вашему мнению, исходит ошибка, и если он уже сталкивался с `IndexError`, велика вероятность, что он поймет, как ее отладить. Конечно, заголовок может быть любым, какой вы захотите, и возможны другие варианты, например: + +> Why does my model produce an IndexError? + +также может подойти. Теперь, когда у нас есть описательный заголовок, давайте посмотрим, как улучшить само описание ошибки. + +### Форматирование кода[[formatting-your-code-snippets]] + +Читать исходный код в IDE достаточно сложно, но еще сложнее, когда код скопирован и вставлен в виде обычного текста! К счастью, форумы Hugging Face поддерживают использование Markdown, поэтому вы всегда должны заключать свои блоки кода в три обратных знака (```), чтобы их было легче читать. Давайте сделаем это, чтобы отформатировать сообщение об ошибке - и пока мы это делаем, давайте сделаем текст немного более вежливым, чем наша первоначальная версия: + +
+Our revised forum topic, with proper code formatting. +
+ +As you can see in the screenshot, enclosing the code blocks in backticks converts the raw text into formatted code, complete with color styling! Also note that single backticks can be used to format inline variables, like we've done for `distilbert-base-uncased`. This topic is looking much better, and with a bit of luck we might find someone in the community who can guess what the error is about. However, instead of relying on luck, let's make life easier by including the traceback in its full gory detail! + +### Including the full traceback[[including-the-full-traceback]] + +Как видно на скриншоте, заключение блоков кода в обратные знаки превращает исходный текст в отформатированный код, дополненный цветовой стилизацией! Также обратите внимание, что одиночные обратные знаки могут быть использованы для форматирования встроенных переменных, как мы это сделали для `distilbert-base-uncased`. Эта тема выглядит гораздо лучше, и, если повезет, мы сможем найти кого-то из сообщества, кто догадается, в чем ошибка. Однако вместо того, чтобы полагаться на удачу, давайте облегчим себе жизнь, включив в трассировку все подробности! + +
+Our example forum topic, with the complete traceback. +
+ +Это гораздо более информативно, и внимательный читатель сможет указать на то, что проблема, похоже, связана с передачей длинного входного сигнала из-за этой строки в трассировке: + +> Token indices sequence length is longer than the specified maximum sequence length for this model (583 > 512). + +Однако мы можем еще больше облегчить им задачу, предоставив фактический код, вызвавший ошибку. Давайте сделаем это прямо сейчас. + +### Предоставление воспроизводимого примера[[providing-a-reproducible-example]] + +Если вы когда-нибудь пытались отладить чужой код, вы, вероятно, сначала пытались воссоздать проблему, о которой они сообщали, чтобы начать работать над трассировкой, чтобы точно определить ошибку. Это не отличается от того, когда речь идет о получении (или предоставлении) помощи на форумах, поэтому очень помогает, если вы можете предоставить небольшой пример, воспроизводящий ошибку. В половине случаев простое выполнение этого упражнения поможет вам понять, что происходит не так. В любом случае, недостающий фрагмент нашего примера - это показать _входы_, которые мы предоставили модели. Выполнив это, мы получим нечто похожее на следующий завершенный пример: + +
+The final version of our forum topic. +
+ +Теперь эта сообщение содержит достаточно много информации, и оно написана таким образом, что с гораздо большей вероятностью привлечет внимание сообщества и получит полезный ответ. Используя эти основные правила, вы сможете создавать отличные темы для поиска ответов на ваши вопросы по библиотеке 🤗 Transformers! + From e34e68d9f626ef4b9d3a4965886debfe512ff104 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 27 Jan 2024 12:07:40 +0300 Subject: [PATCH 379/502] 8/4 finished --- chapters/ru/chapter8/4.mdx | 791 ++++++++++++++++++++++++++++++++++ chapters/ru/chapter8/4_tf.mdx | 486 +++++++++++++++++++++ 2 files changed, 1277 insertions(+) create mode 100644 chapters/ru/chapter8/4.mdx create mode 100644 chapters/ru/chapter8/4_tf.mdx diff --git a/chapters/ru/chapter8/4.mdx b/chapters/ru/chapter8/4.mdx new file mode 100644 index 000000000..7cd728aa4 --- /dev/null +++ b/chapters/ru/chapter8/4.mdx @@ -0,0 +1,791 @@ + + +# Отладка обучения[[debugging-the-training-pipeline]] + + + +Вы написали прекрасный сценарий для обучения или дообучения модели на заданной задаче, послушно следуя советам из [Главы 7](/course/chapter7). Но когда вы запускаете команду `model.fit()`, происходит нечто ужасное: вы получаете ошибку 😱! Или, что еще хуже, все вроде бы хорошо, обучение проходит без ошибок, но результирующая модель получается плохой. В этом разделе мы покажем вам, что можно сделать для отладки подобных проблем. + +## Debugging the training pipeline[[debugging-the-training-pipeline]] + + + +Проблема, когда вы сталкиваетесь с ошибкой в `trainer.train()`, заключается в том, что она может возникнуть из нескольких источников, поскольку `Trainer` обычно собирает вместе множество вещей. Он преобразует наборы данных в загрузчики данных, поэтому проблема может заключаться в том, что в вашем наборе данных что-то не так, или в том, что вы пытаетесь объединить элементы наборов данных в батч. Затем он берет батч данных и подает его в модель, так что проблема может быть в коде модели. После этого вычисляются градиенты и выполняется этап оптимизации, так что проблема может быть и в вашем оптимизаторе. И даже если во время обучения все идет хорошо, во время валидации все равно что-то может пойти не так, если проблема в метрике. + +Лучший способ отладить ошибку, возникшую в `trainer.train()`, - это вручную пройти весь пайплайн и посмотреть, где все пошло не так. В этом случае ошибку часто очень легко устранить. + +Чтобы продемонстрировать это, мы используем следующий скрипт, который (пытается) точно настроить модель DistilBERT на наборе данных [MNLI dataset](https://huggingface.co/datasets/glue): + +```py +from datasets import load_dataset +import evaluate +from transformers import ( + AutoTokenizer, + AutoModelForSequenceClassification, + TrainingArguments, + Trainer, +) + +raw_datasets = load_dataset("glue", "mnli") + +model_checkpoint = "distilbert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) + + +def preprocess_function(examples): + return tokenizer(examples["premise"], examples["hypothesis"], truncation=True) + + +tokenized_datasets = raw_datasets.map(preprocess_function, batched=True) +model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint) + +args = TrainingArguments( + f"distilbert-finetuned-mnli", + evaluation_strategy="epoch", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, +) + +metric = evaluate.load("glue", "mnli") + + +def compute_metrics(eval_pred): + predictions, labels = eval_pred + return metric.compute(predictions=predictions, references=labels) + + +trainer = Trainer( + model, + args, + train_dataset=raw_datasets["train"], + eval_dataset=raw_datasets["validation_matched"], + compute_metrics=compute_metrics, +) +trainer.train() +``` + +Если вы попытаетесь выполнить его, то столкнетесь с довольно загадочной ошибкой: + +```python out +'ValueError: You have to specify either input_ids or inputs_embeds' +``` + +### Проверка данных[[check-your-data]] + +Это само собой разумеется, но если ваши данные повреждены, `Trainer` не сможет сформировать батчи, не говоря уже об обучении вашей модели. Поэтому прежде всего необходимо посмотреть, что находится в вашем обучающем наборе. + +Чтобы избежать бесчисленных часов, потраченных на попытки исправить то, что не является источником ошибки, мы рекомендуем использовать `trainer.train_dataset` для проверок и ничего больше. Так что давайте сделаем это здесь: + +```py +trainer.train_dataset[0] +``` + +```python out +{'hypothesis': 'Product and geography are what make cream skimming work. ', + 'idx': 0, + 'label': 1, + 'premise': 'Conceptually cream skimming has two basic dimensions - product and geography.'} +``` + +Вы заметили что-то неладное? В сочетании с сообщением об ошибке `input_ids`, вы должны понять, что это тексты, а не числа, которые модель может понять. Здесь исходная ошибка вводит в заблуждение, потому что `Trainer` автоматически удаляет столбцы, которые не соответствуют сигнатуре модели (то есть аргументам, ожидаемым моделью). Это означает, что здесь было удалено все, кроме меток. Таким образом, не было никаких проблем с созданием батчей и отправкой их модели, которая, в свою очередь, жаловалась, что не получила нужных входных данных. + +Почему данные не обрабатывались? Мы действительно использовали метод `Dataset.map()` для наборов данных, чтобы применить токенизатор к каждой выборке. Но если вы внимательно посмотрите на код, то увидите, что мы допустили ошибку при передаче обучающего и валидационного наборов в `Trainer`. Вместо того чтобы использовать `tokenized_datasets`, мы использовали `raw_datasets` 🤦. Так что давайте исправим это! + +```py +from datasets import load_dataset +import evaluate +from transformers import ( + AutoTokenizer, + AutoModelForSequenceClassification, + TrainingArguments, + Trainer, +) + +raw_datasets = load_dataset("glue", "mnli") + +model_checkpoint = "distilbert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) + + +def preprocess_function(examples): + return tokenizer(examples["premise"], examples["hypothesis"], truncation=True) + + +tokenized_datasets = raw_datasets.map(preprocess_function, batched=True) +model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint) + +args = TrainingArguments( + f"distilbert-finetuned-mnli", + evaluation_strategy="epoch", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, +) + +metric = evaluate.load("glue", "mnli") + + +def compute_metrics(eval_pred): + predictions, labels = eval_pred + return metric.compute(predictions=predictions, references=labels) + + +trainer = Trainer( + model, + args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation_matched"], + compute_metrics=compute_metrics, +) +trainer.train() +``` + +Теперь этот новый код будет выдавать другую ошибку (прогресс!): + +```python out +'ValueError: expected sequence of length 43 at dim 1 (got 37)' +``` + +Посмотрев на трассировку, мы видим, что ошибка происходит на этапе сборки данных: + +```python out +~/git/transformers/src/transformers/data/data_collator.py in torch_default_data_collator(features) + 105 batch[k] = torch.stack([f[k] for f in features]) + 106 else: +--> 107 batch[k] = torch.tensor([f[k] for f in features]) + 108 + 109 return batch +``` + +Поэтому нам следует перейти к этому. Однако перед этим давайте закончим проверку наших данных, чтобы быть на 100% уверенными в их правильности. + +При отладке обучения всегда нужно смотреть на декодированные входы модели. Мы не можем понять смысл чисел, которые подаем ей напрямую, поэтому мы должны посмотреть, что эти числа представляют. В компьютерном зрении, например, это означает просмотр декодированных изображений пройденных пикселей, в речи - прослушивание декодированных образцов звука, а в нашем примере с НЛП - использование нашего токенизатора для декодирования входных данных: + +```py +tokenizer.decode(trainer.train_dataset[0]["input_ids"]) +``` + +```python out +'[CLS] conceptually cream skimming has two basic dimensions - product and geography. [SEP] product and geography are what make cream skimming work. [SEP]' +``` + +Так что, похоже, все правильно. Вы должны сделать это для всех ключей во входах: + +```py +trainer.train_dataset[0].keys() +``` + +```python out +dict_keys(['attention_mask', 'hypothesis', 'idx', 'input_ids', 'label', 'premise']) +``` + +Обратите внимание, что ключи, не соответствующие входам, принимаемым моделью, будут автоматически отброшены, поэтому здесь мы оставим только `input_ids`, `attention_mask` и `label` (которая будет переименована в `labels`). Чтобы перепроверить сигнатуру модели, вы можете вывести класс вашей модели, а затем проверить ее документацию: + +```py +type(trainer.model) +``` + +```python out +transformers.models.distilbert.modeling_distilbert.DistilBertForSequenceClassification +``` + +So in our case, we can check the parameters accepted on [this page](https://huggingface.co/transformers/model_doc/distilbert.html#distilbertforsequenceclassification). The `Trainer` will also log the columns it's discarding. + +Мы проверили правильность входных идентификаторов, декодировав их. Далее находится `attention_mask`: + +```py +trainer.train_dataset[0]["attention_mask"] +``` + +```python out +[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +``` + +Так как мы не применяли в препроцессинге дополнение нулями, это кажется совершенно естественным. Чтобы убедиться в отсутствии проблем с этой маской внимания, давайте проверим, что она имеет ту же длину, что и наши входные идентификаторы: + +```py +len(trainer.train_dataset[0]["attention_mask"]) == len( + trainer.train_dataset[0]["input_ids"] +) +``` + +```python out +True +``` + +Это хорошо! И наконец, давайте проверим нашу метку класса: + +```py +trainer.train_dataset[0]["label"] +``` + +```python out +1 +``` + +Как и входные идентификаторы, это число, которое само по себе не имеет смысла. Как мы уже видели, соответствие между целыми числами и именами меток хранится в атрибуте `names` соответствующей *функции* набора данных: + +```py +trainer.train_dataset.features["label"].names +``` + +```python out +['entailment', 'neutral', 'contradiction'] +``` + +Итак, `1` означает `нейтральный`, а значит, два предложения, которые мы видели выше, не противоречат друг другу, и из первого не следует второе. Это кажется правильным! + +Здесь у нас нет идентификаторов типов токенов, поскольку DistilBERT их не ожидает; если в вашей модели они есть, вам также следует убедиться, что они правильно соответствуют месту первого и второго предложений во входных данных. + + + +✏️ **Ваша очередь!** Проверьте, все ли правильно со вторым элементом обучающего набора данных. + + + +В данном случае мы проверяем только обучающий набор, но, конечно, вы должны дважды проверить валидационный и тестовый наборы таким же образом. + +Теперь, когда мы знаем, что наши наборы данных выглядят хорошо, пришло время проверить следующий этап пайплайна обучения. + +### От датасетов к загрузчикам данных[[from-datasets-to-dataloaders]] + +Следующее, что может пойти не так в пайплайне обучения, - это когда `Trainer` пытается сформировать батчи из обучающего или проверочного набора. Убедившись, что наборы данных `Trainer` корректны, можно попробовать вручную сформировать батч, выполнив следующие действия (замените `train` на `eval` для валидационного загрузчика данных): + +```py +for batch in trainer.get_train_dataloader(): + break +``` + +Этот код создает загрузчик данных для обучения, затем выполняет итерации по нему, останавливаясь на первой итерации. Если код выполняется без ошибок, у вас есть первый обучающий батч, который можно проверить, а если код выдает ошибку, вы точно знаете, что проблема в загрузчике данных, как в данном случае: + +```python out +~/git/transformers/src/transformers/data/data_collator.py in torch_default_data_collator(features) + 105 batch[k] = torch.stack([f[k] for f in features]) + 106 else: +--> 107 batch[k] = torch.tensor([f[k] for f in features]) + 108 + 109 return batch + +ValueError: expected sequence of length 45 at dim 1 (got 76) +``` + +Осмотра последнего кадра трассировки должно быть достаточно, чтобы дать вам подсказку, но давайте покопаемся еще немного. Большинство проблем при создании батчей возникает из-за объединения примеров в один батч, поэтому первое, что нужно проверить при возникновении сомнений, это то, какой `collate_fn` использует ваш `DataLoader`: + +```py +data_collator = trainer.get_train_dataloader().collate_fn +data_collator +``` + +```python out + Dict[str, Any]> +``` + +Этот `default_data_collator` не то, что нам нужно в данном случае. Мы хотим разбить наши примеры на самые длинные предложения в пакете, что делает `DataCollatorWithPadding`. И этот класс данных должен использоваться по умолчанию в `Trainer`, так почему же он не используется здесь? + +Ответ заключается в том, что мы не передали `tokenizer` в `Trainer`, поэтому он не смог создать нужный нам `DataCollatorWithPadding`. На практике вам никогда не следует стесняться явно передавать data collator, который вы хотите использовать, чтобы избежать подобных ошибок. Давайте адаптируем наш код, чтобы сделать именно это: + +```py +from datasets import load_dataset +import evaluate +from transformers import ( + AutoTokenizer, + AutoModelForSequenceClassification, + DataCollatorWithPadding, + TrainingArguments, + Trainer, +) + +raw_datasets = load_dataset("glue", "mnli") + +model_checkpoint = "distilbert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) + + +def preprocess_function(examples): + return tokenizer(examples["premise"], examples["hypothesis"], truncation=True) + + +tokenized_datasets = raw_datasets.map(preprocess_function, batched=True) +model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint) + +args = TrainingArguments( + f"distilbert-finetuned-mnli", + evaluation_strategy="epoch", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, +) + +metric = evaluate.load("glue", "mnli") + + +def compute_metrics(eval_pred): + predictions, labels = eval_pred + return metric.compute(predictions=predictions, references=labels) + + +data_collator = DataCollatorWithPadding(tokenizer=tokenizer) + +trainer = Trainer( + model, + args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation_matched"], + compute_metrics=compute_metrics, + data_collator=data_collator, + tokenizer=tokenizer, +) +trainer.train() +``` + +Хорошие новости? Мы не получаем ту же ошибку, что и раньше, что, безусловно, является прогрессом. Плохие новости? Вместо нее мы получаем печально известную ошибку CUDA: + +```python out +RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling `cublasCreate(handle)` +``` + +Это плохо, потому что ошибки CUDA вообще очень трудно отлаживать. Через минуту мы увидим, как решить эту проблему, но сначала давайте закончим анализ создания батчей. + +Если вы уверены, что ваш data collator правильный, попробуйте применить его на паре примеров вашего набора данных: + +```py +data_collator = trainer.get_train_dataloader().collate_fn +batch = data_collator([trainer.train_dataset[i] for i in range(4)]) +``` + +Этот код не сработает, потому что `train_dataset` содержит строковые колонки, которые `Trainer` обычно удаляет. Вы можете удалить их вручную, или, если вы хотите в точности повторить то, что `Trainer` делает за кулисами: нужно вызвать приватный метод `Trainer._remove_unused_columns()`, который делает это: + +```py +data_collator = trainer.get_train_dataloader().collate_fn +actual_train_set = trainer._remove_unused_columns(trainer.train_dataset) +batch = data_collator([actual_train_set[i] for i in range(4)]) +``` + +Если ошибка не исчезнет, вы сможете вручную отладить, что происходит внутри data collator. + +Теперь, когда мы отладили процесс создания батча, пришло время пропустить его через модель! + +### Проверка модели[[going-through-the-model]] + +Вы должны иметь возможность получить батч, выполнив следующую команду: + +```py +for batch in trainer.get_train_dataloader(): + break +``` + +Если вы выполняете этот код в ноутбуке, вы можете получить ошибку CUDA, похожую на ту, что мы видели ранее, и в этом случае вам нужно перезапустить ноутбук и заново выполнить последний фрагмент без строки `trainer.train()`. Это вторая самая неприятная вещь в ошибках CUDA: они безвозвратно ломают ваше ядро. Самое неприятное в них то, что их трудно отлаживать. + +Почему? Это связано с тем, как работают графические процессоры. Они чрезвычайно эффективны при параллельном выполнении множества операций, но их недостаток в том, что когда одна из этих инструкций приводит к ошибке, вы не сразу об этом узнаете. Только когда программа вызовет синхронизацию нескольких процессов на GPU, она поймет, что что-то пошло не так, поэтому ошибка возникает в том месте, которое не имеет никакого отношения к тому, что ее создало. Например, если мы посмотрим на наш предыдущий трассировочный откат, ошибка была вызвана во время обратного прохода, но через минуту мы увидим, что на самом деле она возникла из-за чего-то в прямом проходе через модель. + +Так как же отладить эти ошибки? Ответ прост: никак. Если только ошибка CUDA не является ошибкой вне памяти (что означает, что в вашем GPU недостаточно памяти), вы всегда должны возвращаться к CPU, чтобы отладить ее. + +Чтобы сделать это в нашем случае, нам просто нужно вернуть модель на CPU и вызвать ее на нашем пакете - пакет, возвращаемый `DataLoader`, еще не был перемещен на GPU: + +```python +outputs = trainer.model.cpu()(**batch) +``` + +```python out +~/.pyenv/versions/3.7.9/envs/base/lib/python3.7/site-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce, reduction) + 2386 ) + 2387 if dim == 2: +-> 2388 ret = torch._C._nn.nll_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index) + 2389 elif dim == 4: + 2390 ret = torch._C._nn.nll_loss2d(input, target, weight, _Reduction.get_enum(reduction), ignore_index) + +IndexError: Target 2 is out of bounds. +``` + +Итак, картина проясняется. Вместо ошибки CUDA у нас теперь `IndexError` при вычислении функции потерь (так что обратный проход, как мы уже говорили, здесь ни при чем). Точнее, мы видим, что ошибка возникает именно в метке класса 2, так что это очень хороший момент для проверки количества меток нашей модели: + +```python +trainer.model.config.num_labels +``` + +```python out +2 +``` + +При двух метках в качестве значений допускаются только 0 и 1, но, согласно сообщению об ошибке, мы получили 2. Получение 2 на самом деле нормально: если мы помним имена меток, которые мы извлекли ранее, их было три, поэтому в нашем наборе данных есть индексы 0, 1 и 2. Проблема в том, что мы не сообщили об этом нашей модели, которая должна была быть создана с тремя метками. Так что давайте это исправим! + +```py +from datasets import load_dataset +import evaluate +from transformers import ( + AutoTokenizer, + AutoModelForSequenceClassification, + DataCollatorWithPadding, + TrainingArguments, + Trainer, +) + +raw_datasets = load_dataset("glue", "mnli") + +model_checkpoint = "distilbert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) + + +def preprocess_function(examples): + return tokenizer(examples["premise"], examples["hypothesis"], truncation=True) + + +tokenized_datasets = raw_datasets.map(preprocess_function, batched=True) +model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=3) + +args = TrainingArguments( + f"distilbert-finetuned-mnli", + evaluation_strategy="epoch", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, +) + +metric = evaluate.load("glue", "mnli") + + +def compute_metrics(eval_pred): + predictions, labels = eval_pred + return metric.compute(predictions=predictions, references=labels) + + +data_collator = DataCollatorWithPadding(tokenizer=tokenizer) + +trainer = Trainer( + model, + args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation_matched"], + compute_metrics=compute_metrics, + data_collator=data_collator, + tokenizer=tokenizer, +) +``` + +Мы пока не включаем строку `trainer.train()`, чтобы потратить время на проверку того, что все выглядит хорошо. Если мы запросим батч и передадим ее нашей модели, то теперь она работает без ошибок! + +```py +for batch in trainer.get_train_dataloader(): + break + +outputs = trainer.model.cpu()(**batch) +``` + +Следующим шагом будет возвращение к графическому процессору и проверка того, что все по-прежнему работает: + +```py +import torch + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +batch = {k: v.to(device) for k, v in batch.items()} + +outputs = trainer.model.to(device)(**batch) +``` + +Если вы все еще получаете ошибку, убедитесь, что перезагрузили ноутбук и выполнили только последнюю версию скрипта. + +### Выполнение одного шага оптиимзации[[performing-one-optimization-step]] + +Теперь, когда мы знаем, что можем создавать батчи, которые действительно проходят через модель без ошибок, мы готовы к следующему шагу пайплайна обучения: вычислению градиентов и выполнению шага оптимизации. + +Первая часть заключается в вызове метода `backward()` для функции потерь: + +```py +loss = outputs.loss +loss.backward() +``` + +Ошибки на этом этапе возникают довольно редко, но если они все же возникнут, обязательно вернитесь к процессору, чтобы получить полезное сообщение об ошибке. + +Чтобы выполнить шаг оптимизации, нам нужно просто создать `optimizer` и вызвать его метод `step()`: + +```py +trainer.create_optimizer() +trainer.optimizer.step() +``` + +Опять же, если вы используете оптимизатор по умолчанию в `Trainer`, вы не должны получить ошибку на этом этапе, но если вы используете пользовательский оптимизатор, здесь могут возникнуть некоторые проблемы для отладки. Не забудьте вернуться к процессору, если на этом этапе вы получите странную ошибку CUDA. Говоря об ошибках CUDA, ранее мы упоминали особый случай. Давайте посмотрим на него сейчас. + +### Работа с ошибкой CUDA OOM[[dealing-with-cuda-out-of-memory-errors]] + +Если вы получаете сообщение об ошибке, начинающееся с `RuntimeError: CUDA out of memory`, это означает, что вам не хватает памяти GPU. Это не связано напрямую с вашим кодом, и может произойти со скриптом, который работает совершенно нормально. Эта ошибка означает, что вы пытались поместить слишком много данных во внутреннюю память вашего GPU, и это привело к ошибке. Как и в случае с другими ошибками CUDA, вам придется перезапустить ядро, чтобы снова запустить обучение. + +Чтобы решить эту проблему, нужно просто использовать меньше памяти на GPU - что зачастую легче сказать, чем сделать. Во-первых, убедитесь, что у вас нет двух моделей на GPU одновременно (если, конечно, это не требуется для решения вашей задачи). Затем, вероятно, следует уменьшить размер батча, поскольку он напрямую влияет на размеры всех промежуточных выходов модели и их градиентов. Если проблема сохраняется, подумайте о том, чтобы использовать меньшую версию модели. + + + +В следующей части курса мы рассмотрим более продвинутые техники, которые помогут вам уменьшить объем занимаемой памяти и позволят точно настроить самые большие модели. + + + +### Валидация модели[[evaluating-the-model]] + +Теперь, когда мы решили все проблемы с нашим кодом, все идеально, и обучение должно пройти гладко, верно? Не так быстро! Если вы запустите команду `trainer.train()`, сначала все будет выглядеть хорошо, но через некоторое время вы получите следующее: + +```py +# This will take a long time and error out, so you shouldn't run this cell +trainer.train() +``` + +```python out +TypeError: only size-1 arrays can be converted to Python scalars +``` + +Вы поймете, что эта ошибка появляется во время фазы валидации, так что это последнее, что нам нужно будет отладить. + +Вы можете запустить цикл оценки `Trainer` независимо от обучения следующим образом: + +```py +trainer.evaluate() +``` + +```python out +TypeError: only size-1 arrays can be converted to Python scalars +``` + + + +💡 Перед запуском `trainer.train()` всегда следует убедиться, что вы можете запустить `trainer.evaluate()`, чтобы не тратить много вычислительных ресурсов до того, как столкнетесь с ошибкой. + + + +Прежде чем пытаться отладить проблему в цикле валидации, нужно сначала убедиться, что вы посмотрели на данные, смогли правильно сформировать батч и запустить на нем свою модель. Мы выполнили все эти шаги, поэтому следующий код может быть выполнен без ошибок: + +```py +for batch in trainer.get_eval_dataloader(): + break + +batch = {k: v.to(device) for k, v in batch.items()} + +with torch.no_grad(): + outputs = trainer.model(**batch) +``` + +Ошибка возникает позже, в конце фазы валидации, и если мы посмотрим на трассировку, то увидим следующее: + +```python trace +~/git/datasets/src/datasets/metric.py in add_batch(self, predictions, references) + 431 """ + 432 batch = {"predictions": predictions, "references": references} +--> 433 batch = self.info.features.encode_batch(batch) + 434 if self.writer is None: + 435 self._init_writer() +``` + +Это говорит нам о том, что ошибка возникает в модуле `datasets/metric.py` - так что это проблема с нашей функцией `compute_metrics()`. Она принимает кортеж с логитами и метками в виде массивов NumPy, так что давайте попробуем скормить ей это: + +```py +predictions = outputs.logits.cpu().numpy() +labels = batch["labels"].cpu().numpy() + +compute_metrics((predictions, labels)) +``` + +```python out +TypeError: only size-1 arrays can be converted to Python scalars +``` + +Мы получаем ту же ошибку, так что проблема определенно кроется в этой функции. Если мы посмотрим на ее код, то увидим, что она просто передает `predictions` и `labels` в `metric.compute()`. Так есть ли проблема в этом методе? На самом деле нет. Давайте посмотрим на размерности: + +```py +predictions.shape, labels.shape +``` + +```python out +((8, 3), (8,)) +``` + +Наши предсказания все еще являются логарифмами, а не реальными предсказаниями, поэтому метрика возвращает эту (несколько непонятную) ошибку. Исправить это довольно просто: нужно просто добавить argmax в функцию `compute_metrics()`: + +```py +import numpy as np + + +def compute_metrics(eval_pred): + predictions, labels = eval_pred + predictions = np.argmax(predictions, axis=1) + return metric.compute(predictions=predictions, references=labels) + + +compute_metrics((predictions, labels)) +``` + +```python out +{'accuracy': 0.625} +``` + +Теперь наша ошибка исправлена! Она была последней, поэтому теперь наш скрипт будет правильно обучать модель. + +Для справки, вот полностью исправленный скрипт: + +```py +import numpy as np +from datasets import load_dataset +import evaluate +from transformers import ( + AutoTokenizer, + AutoModelForSequenceClassification, + DataCollatorWithPadding, + TrainingArguments, + Trainer, +) + +raw_datasets = load_dataset("glue", "mnli") + +model_checkpoint = "distilbert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) + + +def preprocess_function(examples): + return tokenizer(examples["premise"], examples["hypothesis"], truncation=True) + + +tokenized_datasets = raw_datasets.map(preprocess_function, batched=True) +model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=3) + +args = TrainingArguments( + f"distilbert-finetuned-mnli", + evaluation_strategy="epoch", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, +) + +metric = evaluate.load("glue", "mnli") + + +def compute_metrics(eval_pred): + predictions, labels = eval_pred + predictions = np.argmax(predictions, axis=1) + return metric.compute(predictions=predictions, references=labels) + + +data_collator = DataCollatorWithPadding(tokenizer=tokenizer) + +trainer = Trainer( + model, + args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation_matched"], + compute_metrics=compute_metrics, + data_collator=data_collator, + tokenizer=tokenizer, +) +trainer.train() +``` + +В этом случае проблем больше нет, и наш скрипт обучит модель, которая должна дать приемлемые результаты. Но что делать, если обучение проходит без ошибок, а обученная модель совсем не работает? Это самая сложная часть машинного обучения, и мы покажем вам несколько приемов, которые могут помочь. + + + +💡 Если вы используете ручной цикл обучения, для отладки пайплайна обучения применимы те же шаги, но их проще разделить. Убедитесь, что вы не забыли `model.eval()` или `model.train()` в нужных местах, или `zero_grad()` на каждом шаге! + + +## Отладка скрытых ошибок во время обучения[[debugging-silent-errors-during-training]] + +Что можно сделать, чтобы отладить обучение, которое завершается без ошибок, но не дает хороших результатов? Мы дадим вам несколько советов, но имейте в виду, что такая отладка - самая сложная часть машинного обучения, и волшебного ответа на этот вопрос не существует. + +### Проверьте свои данные (еще раз!)[[check-your-data-again]] + +Ваша модель научится чему-то только в том случае, если из ваших данных действительно можно чему-то научиться. Если в данных есть ошибка, которая портит их, или метки приписаны случайным образом, то, скорее всего, вы не сможете обучить модель на своем наборе данных. Поэтому всегда начинайте с перепроверки декодированных входных данных и меток и задавайте себе следующие вопросы: + +- Понятны ли декодированные данные? +- Правильные ли метки? +- Есть ли одна метка, которая встречается чаще других? +- Каким должно быть значение функции потерь/метрики если модель предсказала случайный ответ/всегда один и тот же ответ? + + + +⚠️ Если вы проводите распределенное обучение, распечатайте образцы набора данных в каждом процессе и трижды проверьте, что вы получаете одно и то же. Одна из распространенных ошибок - наличие некоторого источника случайности при создании данных, из-за которого каждый процесс имеет свою версию набора данных. + + + +Просмотрев данные, проанализируйте несколько предсказаний модели и декодируйте их. Если модель постоянно предсказывает одно и то же, это может быть связано с тем, что ваш набор данных смещен в сторону одной категории (для проблем классификации); здесь могут помочь такие методы, как oversampling редких классов. + +Если значения функции потерь/метрики, которые вы получаете на начальной модели, сильно отличаются от значений функции потерь/метрик, которые можно было бы ожидать для случайных предсказаний, перепроверьте способ вычисления потерь или метрик, так как, возможно, в них есть ошибка. Если вы используете несколько функций потерь, убедитесь, что они имеют одинаковый масштаб. + +Когда вы убедитесь, что ваши данные идеальны, вы можете проверить, способна ли модель обучаться на них, с помощью одного простого теста. + +### Переобучение модели на одном батче[[overfit-your-model-on-one-batch]] + +Обычно мы стараемся избегать переобучения при тренировке модели, поскольку это означает, что модель не учится распознавать общие характеристики, а просто запоминает обучающие выборки. Однако попытка обучить модель на одной выборке снова и снова - это хороший тест, позволяющий проверить, может ли проблема в том виде, в котором вы ее сформулировали, быть решена с помощью модели, которую вы пытаетесь обучить. Это также поможет вам понять, не слишком ли высока ваша начальная скорость обучения. + +Сделать это после того, как вы определили свой `Trainer`, очень просто: просто возьмите батч обучающих данных, а затем запустите небольшой цикл ручного обучения, используя только этот батч в течение примерно 20 шагов: + +```py +for batch in trainer.get_train_dataloader(): + break + +batch = {k: v.to(device) for k, v in batch.items()} +trainer.create_optimizer() + +for _ in range(20): + outputs = trainer.model(**batch) + loss = outputs.loss + loss.backward() + trainer.optimizer.step() + trainer.optimizer.zero_grad() +``` + + + +💡 Если ваши обучающие данные несбалансированы, обязательно создайте батч обучающих данных, содержащий все метки. + + + +Результирующая модель должна иметь близкие к идеальным результаты на одном и том же батче. Вычислим метрику по полученным предсказаниям: + +```py +with torch.no_grad(): + outputs = trainer.model(**batch) +preds = outputs.logits +labels = batch["labels"] + +compute_metrics((preds.cpu().numpy(), labels.cpu().numpy())) +``` + +```python out +{'accuracy': 1.0} +``` + +Точность 100 %, вот это хороший пример переобучения (это значит, что если вы попробуете использовать модель на любом другом предложении, она, скорее всего, даст вам неправильный ответ)! + +Если вам не удается добиться от модели таких идеальных результатов, значит, что-то не так с постановкой задачи или данными, и вам следует это исправить. Только когда вам удастся пройти тест на переобучение, вы сможете быть уверены, что ваша модель действительно способна чему-то научиться. + + + +⚠️ Вам придется пересоздать модель и `Trainer` после этого теста на переобучение, поскольку полученная модель, вероятно, не сможет восстановиться и научиться чему-то полезному на полном наборе данных. + + + +### Не обучайте ничего, пока не получите первый бейзлайн.[[dont-tune-anything-until-you-have-a-first-baseline]] + +Настройка гиперпараметров всегда считается самой сложной частью машинного обучения, но это всего лишь последний шаг, который поможет вам немного улучшить метрику. В большинстве случаев гиперпараметры по умолчанию `Trainer` будут работать нормально и давать вам хорошие результаты, поэтому не приступайте к трудоемкому и дорогостоящему поиску гиперпараметров, пока у вас не будет чего-то, что превосходит бейзлайн, который у вас есть в вашем наборе данных. . + +Как только у вас будет достаточно хорошая модель, вы можете начать ее немного оптимизировать. Не пытайтесь запустить тысячу раз с разными гиперпараметрами, но сравните пару запусков с разными значениями одного гиперпараметра, чтобы получить представление о том, какой из них оказывает наибольшее влияние. + +Если вы настраиваете саму модель, будьте проще и не пробуйте то, что не можете обосновать. Всегда возвращайтесь к тесту на перебор, чтобы проверить, не привело ли ваше изменение к каким-либо непредвиденным последствиям. + +### Попросить о помощи[[ask-for-help]] + +Надеемся, вы нашли в этом разделе советы, которые помогли вам решить вашу проблему, но если это не так, помните, что вы всегда можете спросить у сообщества на [форумах](https://discuss.huggingface.co/). + +Вот некоторые дополнительные ресурсы, которые могут оказаться полезными: + +- [" Reproducibility as a vehicle for engineering best practices"](https://docs.google.com/presentation/d/1yHLPvPhUs2KGI5ZWo0sU-PKU3GimAk3iTsI38Z-B5Gw/edit#slide=id.p) by Joel Grus +- ["Checklist for debugging neural networks"](https://towardsdatascience.com/checklist-for-debugging-neural-networks-d8b2a9434f21) by Cecelia Shao +- [" How to unit test machine learning code"](https://medium.com/@keeper6928/how-to-unit-test-machine-learning-code-57cf6fd81765) by Chase Roberts +- [""A Recipe for Training Neural Networks"](http://karpathy.github.io/2019/04/25/recipe/) by Andrej Karpathy + +Конечно, не все проблемы, с которыми вы сталкиваетесь при обучении нейросетей, возникают по вашей вине! Если в библиотеке 🤗 Transformers или 🤗 Datasets вы столкнулись с чем-то, что кажется вам неправильным, возможно, вы обнаружили ошибку. Вам обязательно нужно рассказать нам об этом, и в следующем разделе мы объясним, как именно это сделать. diff --git a/chapters/ru/chapter8/4_tf.mdx b/chapters/ru/chapter8/4_tf.mdx new file mode 100644 index 000000000..99591374f --- /dev/null +++ b/chapters/ru/chapter8/4_tf.mdx @@ -0,0 +1,486 @@ + + +# Отладка обучения[[debugging-the-training-pipeline]] + + + +Вы написали прекрасный сценарий для обучения или дообучения модели на заданной задаче, послушно следуя советам из [Главы 7](/course/chapter7). Но когда вы запускаете команду `model.fit()`, происходит нечто ужасное: вы получаете ошибку 😱! Или, что еще хуже, все вроде бы хорошо, обучение проходит без ошибок, но результирующая модель получается плохой. В этом разделе мы покажем вам, что можно сделать для отладки подобных проблем. + +## Отладка обучающего пайплайна[[debugging-the-training-pipeline]] + + + +Проблема, когда вы сталкиваетесь с ошибкой в `model.fit()`, заключается в том, что она может возникнуть из нескольких источников, поскольку обучение обычно объединяет множество вещей, над которыми вы работали до этого момента. Проблема может заключаться в том, что в вашем наборе данных что-то не так, или в том, что вы пытаетесь объединить элементы наборов данных вместе. Или что-то не так в коде модели, функции потерь или оптимизаторе. И даже если при обучении все идет хорошо, во время оценки что-то может пойти не так, если возникнут проблемы с метрикой. + +Лучший способ отладить ошибку, возникшую в `model.fit()`, - это вручную пройти весь конвейер, чтобы увидеть, где что-то пошло не так. В этом случае ошибку часто очень легко устранить. + +Чтобы продемонстрировать это, мы используем следующий скрипт, который (пытается) дообучить модель DistilBERT на наборе данных [MNLI dataset](https://huggingface.co/datasets/glue): + +```py +from datasets import load_dataset +import evaluate +from transformers import ( + AutoTokenizer, + TFAutoModelForSequenceClassification, +) + +raw_datasets = load_dataset("glue", "mnli") + +model_checkpoint = "distilbert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) + + +def preprocess_function(examples): + return tokenizer(examples["premise"], examples["hypothesis"], truncation=True) + + +tokenized_datasets = raw_datasets.map(preprocess_function, batched=True) + +train_dataset = tokenized_datasets["train"].to_tf_dataset( + columns=["input_ids", "labels"], batch_size=16, shuffle=True +) + +validation_dataset = tokenized_datasets["validation_matched"].to_tf_dataset( + columns=["input_ids", "labels"], batch_size=16, shuffle=True +) + +model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint) + +model.compile(loss="sparse_categorical_crossentropy", optimizer="adam") + +model.fit(train_dataset) +``` + +Если вы попытаетесь выполнить его, вы можете получить несколько `VisibleDeprecationWarning` при преобразовании набора данных - это известная нам проблема UX, так что, пожалуйста, игнорируйте ее. Если вы читаете курс после, скажем, ноября 2021 года, и это все еще происходит, то отправляйте гневные твиты @carrigmat, пока он не исправит это. + +Однако более серьезной проблемой является то, что мы получаем откровенную ошибку. И она действительно ужасающе длинная: + +```python out +ValueError: No gradients provided for any variable: ['tf_distil_bert_for_sequence_classification/distilbert/embeddings/word_embeddings/weight:0', '...'] +``` + +Что это значит? Мы пытались обучиться на наших данных, но не получили градиента? Это вызывает недоумение; как мы вообще можем начать отлаживать что-то подобное? Если полученная ошибка не позволяет сразу понять, в чем проблема, лучшим решением будет последовательно пройтись по всем пунктам, убеждаясь на каждом этапе, что все выглядит правильно. И, конечно, начинать всегда нужно с... + +### Проверка собственных данных[[check-your-data]] + +Это само собой разумеется, но если ваши данные повреждены, Keras не сможет исправить их за вас. Поэтому прежде всего нужно посмотреть, что находится в вашем обучающем наборе. + +Хотя заманчиво заглянуть в `raw_datasets` и `tokenized_datasets`, мы настоятельно рекомендуем обращаться к данным непосредственно в той точке, где они попадают в модель. Это означает, что надо посмотреть на выход из `tf.data.Dataset`, который вы создали с помощью функции `to_tf_dataset()`! Как же это сделать? Объекты `tf.data.Dataset` предоставляют нам целые батчи за раз и не поддерживают индексацию, поэтому мы не можем просто запросить `train_dataset[0]`. Однако мы можем вежливо попросить у него батч: + +```py +for batch in train_dataset: + break +``` + +`break` завершает цикл после одной итерации, поэтому мы берем первый батч, полученный из `train_dataset`, и сохраняем ее как `batch`. Теперь давайте посмотрим, что находится внутри: + +```python out +{'attention_mask': , + 'label': , + 'input_ids': } +``` + +Все выглядит правильно, не так ли? Мы передаем модели `labels`, `attention_mask` и `input_ids`, этого достаточно для вычисления выходов и расчета функции потерь. Так почему же у нас нет градиента? Посмотрите внимательнее: мы передаем на вход один словарь, а обучающая партия обычно представляет собой входной тензор или словарь, плюс тензор меток. Наши метки - это просто ключ в нашем входном словаре. + +Является ли это проблемой? На самом деле, не всегда! Но это одна из самых распространенных проблем, с которыми вы столкнетесь при обучении трансформеров с помощью TensorFlow. Все наши модели могут вычислять потери внутри себя, но для этого необходимо передать метки во входной словарь. Именно это происходит, когда мы не указываем функцию потерь в `compile()`. С другой стороны, Keras обычно ожидает, что метки будут передаваться отдельно от входного словаря, и вычисление потерь обычно заканчивается неудачей, если этого не сделать. + +Теперь проблема стала яснее: мы передали аргумент `loss`, что означает, что мы просим Keras вычислить для нас функцию потерь, но мы передали наши метки как входные данные для модели, а не как метки в том месте, где их ожидает Keras! Нам нужно выбрать одно из двух: либо мы используем внутреннюю функцию потерь модели и оставляем метки на месте, либо мы продолжаем использовать функцию потерь Keras, но перемещаем метки в то место, где их ожидает Keras. Для простоты возьмем первый подход. Изменим вызов `compile()`: + +```py +model.compile(optimizer="adam") +``` + +Теперь мы будем использовать конкретную функцию потерь модели, и эта проблема должна быть решена! + + + +✏️ **Ваша очередь!** В качестве дополнительной задачи после решения других проблем вы можете попробовать вернуться к этому шагу и заставить модель работать с оригинальной функцией потерь, вычисленными Keras. Вам нужно будет добавить `"labels"` к аргументу `label_cols` в `to_tf_dataset()`, чтобы обеспечить корректный вывод меток, что позволит получить градиенты - но есть еще одна проблема с функцией потерь, которую мы указали. Обучение будет продолжаться и с этой проблемой, но обучение будет происходить очень медленно и застопорится на высоком уровне потерь при обучении. Можете ли вы понять, в чем дело? + +Подсказка в кодировке ROT13, если вы застряли: Vs lbh ybbx ng gur bhgchgf bs FrdhraprPynffvsvpngvba zbqryf va Genafsbezref, gurve svefg bhgchg vf `ybtvgf`. Jung ner ybtvgf? + +И вторая подсказка: Jura lbh fcrpvsl bcgvzvmref, npgvingvbaf be ybffrf jvgu fgevatf, Xrenf frgf nyy gur nethzrag inyhrf gb gurve qrsnhygf. Jung nethzragf qbrf FcnefrPngrtbevpnyPebffragebcl unir, naq jung ner gurve qrsnhygf? + + + +Теперь попробуем провести обучение. Теперь мы должны получить градиенты, так что, надеюсь (здесь играет зловещая музыка), мы можем просто вызвать `model.fit()` и все будет работать отлично! + +```python out + 246/24543 [..............................] - ETA: 15:52 - loss: nan +``` + +Oh no. + +`nan` is not a very encouraging loss value. Still, we've checked our data, and it looks pretty good. If that's not the problem, where can we go next? The obvious next step is to... + +### Проверка модели[[check-your-model]] + +`model.fit()` - очень удобная функция в Keras, но она делает много вещей за вас, и это может затруднить поиск того, где именно возникла проблема. Если вы отлаживаете свою модель, одна из стратегий, которая может действительно помочь, - это передать модели только одну партию данных и подробно просмотреть выходные данные для этой одной партии. Еще один очень полезный совет, если модель выдает ошибки, - запустите `compile()` модели с `run_eagerly=True`. Это сделает ее намного медленнее, но сделает сообщения об ошибках гораздо более понятными, потому что они будут указывать, где именно в коде вашей модели возникла проблема. + +Впрочем, пока что `run_eagerly` нам не нужен. Давайте прогоним полученный ранее батч через модель и посмотрим, что получится на выходе: + +```py +model(batch) +``` + +```python out +TFSequenceClassifierOutput(loss=, logits=, hidden_states=None, attentions=None) +``` + +Ну, это сложно. Все есть `nan`! Но это странно, не так ли? Как бы все наши логиты стали `nan`? `nan` означает "не число". Значения `nan` часто возникают, когда вы выполняете запрещенную операцию, например деление на ноль. Но в машинном обучении очень важно знать о `nan`: это значение имеет тенденцию к *распространению*. Если вы умножите число на `nan`, то на выходе также получится `nan`. И если вы получите `nan` где-нибудь в вашем выходе, потерях или градиенте, то это быстро распространится по всей вашей модели - потому что когда это `nan` значение распространяется обратно через вашу сеть, вы получите `nan` градиенты, а когда обновления веса вычисляются с этими градиентами, вы получите `nan` веса, а эти веса вычислят еще более `nan` выходы! Вскоре вся сеть будет представлять собой один большой блок `nan`. Когда это произойдет, будет довольно сложно понять, где началась проблема. Как мы можем определить, где `nan` впервые прокрался в сеть? + +Ответ заключается в том, чтобы попробовать *переинициализировать* нашу модель. Как только мы начали обучение, где-то появился `nan`, и он быстро распространился по всей модели. Итак, давайте загрузим модель из контрольной точки и не будем делать никаких обновлений весов, и посмотрим, где мы получим значение `nan`: + +```py +model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint) +model(batch) +``` + +When we run that, we get: + +```py out +TFSequenceClassifierOutput(loss=, logits=, hidden_states=None, attentions=None) +``` + +*Теперь* у нас что-то получается! В наших логарифмах нет значений `nan`, что обнадеживает. Но мы видим несколько `nan`-значений в наших потерях! Может быть, в этих образцах есть что-то особенное, что вызывает эту проблему? Давайте посмотрим, что это за выборки (обратите внимание, что если вы запустите этот код самостоятельно, то можете получить другие показатели, поскольку набор данных был перемешан): + +```python +import numpy as np + +loss = model(batch).loss.numpy() +indices = np.flatnonzero(np.isnan(loss)) +indices +``` + +```python out +array([ 1, 2, 5, 7, 9, 10, 11, 13, 14]) +``` + +Давайте посмотрим, какие индексы были у этих примеров: + +```python +input_ids = batch["input_ids"].numpy() +input_ids[indices] +``` + +```python out +array([[ 101, 2007, 2032, 2001, 1037, 16480, 3917, 2594, 4135, + 23212, 3070, 2214, 10170, 1010, 2012, 4356, 1997, 3183, + 6838, 12953, 2039, 2000, 1996, 6147, 1997, 2010, 2606, + 1012, 102, 6838, 2001, 3294, 6625, 3773, 1996, 2214, + 2158, 1012, 102, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0], + [ 101, 1998, 6814, 2016, 2234, 2461, 2153, 1998, 13322, + 2009, 1012, 102, 2045, 1005, 1055, 2053, 3382, 2008, + 2016, 1005, 2222, 3046, 8103, 2075, 2009, 2153, 1012, + 102, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0], + [ 101, 1998, 2007, 1996, 3712, 4634, 1010, 2057, 8108, + 2025, 3404, 2028, 1012, 1996, 2616, 18449, 2125, 1999, + 1037, 9666, 1997, 4100, 8663, 11020, 6313, 2791, 1998, + 2431, 1011, 4301, 1012, 102, 2028, 1005, 1055, 5177, + 2110, 1998, 3977, 2000, 2832, 2106, 2025, 2689, 2104, + 2122, 6214, 1012, 102, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0], + [ 101, 1045, 2001, 1999, 1037, 13090, 5948, 2007, 2048, + 2308, 2006, 2026, 5001, 2043, 2026, 2171, 2001, 2170, + 1012, 102, 1045, 2001, 3564, 1999, 2277, 1012, 102, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0], + [ 101, 2195, 4279, 2191, 2039, 1996, 2181, 2124, 2004, + 1996, 2225, 7363, 1012, 102, 2045, 2003, 2069, 2028, + 2451, 1999, 1996, 2225, 7363, 1012, 102, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0], + [ 101, 2061, 2008, 1045, 2123, 1005, 1056, 2113, 2065, + 2009, 2428, 10654, 7347, 2030, 2009, 7126, 2256, 2495, + 2291, 102, 2009, 2003, 5094, 2256, 2495, 2291, 2035, + 2105, 1012, 102, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0], + [ 101, 2051, 1010, 2029, 3216, 2019, 2503, 3444, 1010, + 6732, 1996, 2265, 2038, 19840, 2098, 2125, 9906, 1998, + 2003, 2770, 2041, 1997, 4784, 1012, 102, 2051, 6732, + 1996, 2265, 2003, 9525, 1998, 4569, 1012, 102, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0], + [ 101, 1996, 10556, 2140, 11515, 2058, 1010, 2010, 2162, + 2252, 5689, 2013, 2010, 7223, 1012, 102, 2043, 1996, + 10556, 2140, 11515, 2058, 1010, 2010, 2252, 3062, 2000, + 1996, 2598, 1012, 102, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0], + [ 101, 13543, 1999, 2049, 6143, 2933, 2443, 102, 2025, + 13543, 1999, 6143, 2933, 2003, 2443, 102, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0]]) +``` + +Здесь много всего, но ничто не выделяется. Давайте посмотрим на метки классов: + +```python out +labels = batch['labels'].numpy() +labels[indices] +``` + +```python out +array([2, 2, 2, 2, 2, 2, 2, 2, 2]) +``` + +А! Все образцы `nan` имеют одну и ту же метку, и это метка 2. Это очень сильный намек. Тот факт, что мы получаем значение функции потерь `nan` только тогда, когда наша метка равна 2, говорит о том, что сейчас самое время проверить количество меток в нашей модели: + +```python +model.config.num_labels +``` + +```python out +2 +``` + +Теперь мы видим проблему: модель считает, что существует только два класса, но метка бывает равна 2, что означает, что на самом деле существует три класса (потому что 0 - это тоже класс). Вот так мы и получили `nan` - пытаясь вычислить потери для несуществующего класса! Давайте попробуем изменить это и снова подогнать модель: + +``` +model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=3) +model.compile(optimizer='adam') +model.fit(train_dataset) +``` + +```python out + 869/24543 [>.............................] - ETA: 15:29 - loss: 1.1032 +``` + +Мы обучаемся! Больше никаких `nan`, и наши потери уменьшаются... вроде как. Если понаблюдать за этим некоторое время, можно начать испытывать некоторое нетерпение, потому что значение потерь остается упрямо высоким. Давайте остановим тренировку и попробуем подумать, в чем может быть причина этой проблемы. На данный момент мы уверены, что и данные, и модель в порядке, но наша модель плохо обучается. Что еще остается? Пришло время... + +### Проверка гиперпараметров[[check-your-hyperparameters]] + +Если вы посмотрите на приведенный выше код, то, возможно, вообще не увидите никаких гиперпараметров, кроме, возможно, `batch_size`, и это не кажется вероятной причиной. Однако не обманывайтесь: гиперпараметры есть всегда, и если вы их не видите, значит, вы просто не знаете, на что они настроены. В частности, запомните важную особенность Keras: если вы задаете функцию потерь, оптимизатора или активации с помощью строки, _все ее аргументы будут установлены в значения по умолчанию_. Это означает, что, несмотря на удобство использования строк, следует быть очень осторожным, так как это может легко скрыть от вас критические вещи. (Любой, кто попробует решить опциональную задачу, описанную выше, должен внимательно отнестись к этому факту). + +В данном случае где мы задали аргумент с помощью строки? Изначально мы задавали функцию потерь строкой, но теперь мы этого не делаем. Однако мы задаем оптимизатору строку "adam". Может ли это что-то скрывать от нас? Давайте посмотрим на [его аргументы](https://www.tensorflow.org/api_docs/python/tf/keras/optimizers/Adam). + +Здесь что-нибудь выделяется? Правильно - скорость обучения! Когда мы просто используем строку `'adam'', мы получим скорость обучения по умолчанию, которая составляет 0.001, или 1e-3. Это слишком много для модели трансформера! В целом, мы рекомендуем использовать для моделей скорость обучения от 1e-5 до 1e-4; это в 10-100 раз меньше, чем значение, которое мы используем в данном случае. Похоже, это может стать серьезной проблемой, так что давайте попробуем ее уменьшить. Для этого нам нужно импортировать настоящий объект `optimizer`. Пока мы это делаем, давайте заново инициализируем модель из контрольной точки, на случай если обучение с высокой скоростью обучения повредило ее веса: + +```python +from tensorflow.keras.optimizers import Adam + +model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint) +model.compile(optimizer=Adam(5e-5)) +``` + + + +💡 Вы также можете импортировать функцию `create_optimizer()` из 🤗 Transformers, которая даст вам оптимизатор AdamW с правильным затуханием весов, а также прогревом и затуханием скорости обучения. Этот оптимизатор часто дает несколько лучшие результаты, чем оптимизатор Adam по умолчанию. + + + +Теперь мы можем попробовать подогнать модель под новую, улучшенную скорость обучения: + +```python +model.fit(train_dataset) +``` + +```python out +319/24543 [..............................] - ETA: 16:07 - loss: 0.9718 +``` + +Теперь значения функции потерь действительно изменяются! Наконец-то обучение выглядит так, как будто оно работает. Здесь можно извлечь урок: если модель работает, но потери не уменьшаются, и вы уверены, что с данными все в порядке, стоит проверить гиперпараметры, такие как скорость обучения и затухание веса. Слишком высокое значение любого из них с большой вероятностью приведет к тому, что обучение "застопорится" при высоком значении потерь. + +## Other potential issues[[other-potential-issues]] + +Мы рассмотрели проблемы, описанные в скрипте выше, но есть еще несколько распространенных ошибок, с которыми вы можете столкнуться. Давайте рассмотрим (очень неполный) список. + +### Dealing with out-of-memory errors[[dealing-with-out-of-memory-errors]] + +Признаком нехватки памяти является ошибка типа "OOM when allocating tensor" - OOM - это сокращение от "out of memory". Это очень распространенная опасность при работе с большими языковыми моделями. Если вы столкнулись с этим, хорошая стратегия - уменьшить размер батча вдвое и попробовать снова. Однако имейте в виду, что некоторые модели *очень* велики. Например, полноразмерная модель GPT-2 имеет 1,5 млрд. параметров, что означает, что вам потребуется 6 Гб памяти только для хранения модели и еще 6 Гб для ее градиентов! Для обучения полной модели GPT-2 обычно требуется более 20 ГБ VRAM, независимо от размера батча, что есть лишь у некоторых GPU. Более легкие модели, такие как `distilbert-base-cased`, гораздо легче запускать, и они обучаются гораздо быстрее. + + + +В следующей части курса мы рассмотрим более продвинутые техники, которые помогут вам уменьшить объем занимаемой памяти и позволят дообучить самые большие модели. + + + +### Hungry Hungry TensorFlow 🦛[[hungry-hungry-tensorflow]] + +Одна особенность TensorFlow, о которой вам следует знать, заключается в том, что он выделяет *всю* память GPU под себя, как только вы загружаете модель или проводите обучение, а затем делит эту память по мере необходимости. Это отличается от поведения других фреймворков, например PyTorch, которые выделяют память по мере необходимости с помощью CUDA, а не делают это внутренне. Одним из преимуществ подхода TensorFlow является то, что он может часто выдавать полезные ошибки, когда у вас заканчивается память, и он может восстановиться из этого состояния без сбоя всего ядра CUDA. Но есть и важный недостаток: если вы запускаете два процесса TensorFlow одновременно, то **у вас будут проблемы**. + +Если вы работаете на Colab, то вам не нужно беспокоиться об этом, но если вы работаете локально, то это определенно то, с чем вам следует быть осторожным. В частности, имейте в виду, что закрытие вкладки ноутбука не обязательно приведет к его закрытию! Вам может понадобиться выбрать работающие блокноты (те, что с зеленым значком) и вручную закрыть их в списке каталогов. Любой запущенный блокнот, использующий TensorFlow, может по-прежнему занимать много памяти GPU, а это значит, что любой новый запущенный блокнот может столкнуться с очень странными проблемами. + +Если вы начинаете получать ошибки о CUDA, BLAS или cuBLAS в коде, который работал раньше, то очень часто причина кроется именно в этом. Вы можете использовать такую команду, как `nvidia-smi`, чтобы проверить - когда вы выключаете или перезапускаете текущий ноутбук, большая часть памяти свободна или она все еще используется? Если она все еще используется, значит, что-то еще держится за нее! + + +### Check your data (again!)[[check-your-data-again]] + +Ваша модель научится чему-то только в том случае, если из ваших данных действительно можно чему-то научиться. Если в данных есть ошибка, которая портит их, или метки приписываются случайным образом, то, скорее всего, вы не сможете обучить модель на своем наборе данных. Одним из полезных инструментов здесь является `tokenizer.decode()`. Он превратит `input_ids` обратно в строки, и вы сможете просмотреть данные и понять, обучают ли ваши тренировочные данные тому, чему вы хотите их обучить. Например, после получения `пакета` из `tf.data.Dataset`, как мы делали выше, вы можете декодировать первый элемент следующим образом: + +```py +input_ids = batch["input_ids"].numpy() +tokenizer.decode(input_ids[0]) +``` + +Затем вы можете сравнить его с первой меткой, например, так: + +```py +labels = batch["labels"].numpy() +label = labels[0] +``` + +Как только вы сможете просматривать данные в таком виде, вы сможете задать себе следующие вопросы: + +- Понятны ли декодированные данные? +- Правильные ли метки классов? +- Есть ли одна метка классов, которая встречается чаще других? +- Каким должно быть значение функции потерь/оценки, если модель предсказала случайный ответ/всегда один и тот же ответ? + +Просмотрев данные, проанализируйте несколько предсказаний модели - если модель выводит токены, попробуйте декодировать и их! Если модель всегда предсказывает одно и то же, это может быть связано с тем, что ваш набор данных смещен в сторону одной категории (для проблем классификации), поэтому такие методы, как oversampling редких классов, могут помочь. Кроме того, это может быть вызвано проблемами с обучением, например, неправильными настройками гиперпараметров. + +Если потери/метрики, которые вы получаете на начальной модели до обучения, сильно отличаются от потерь/метрик, ожидаемых для случайных прогнозов, перепроверьте способ вычисления функции потерь или метрик, так как, возможно, в них есть ошибка. Если вы используете несколько функций потерь, проверьте что они имеют одинаковый масштаб. + +Когда вы убедитесь, что ваши данные идеальны, вы можете проверить, способна ли модель обучаться на них, с помощью одного простого теста. + +### Переобучение модели на одном батче[[overfit-your-model-on-one-batch]] + +Обычно мы стараемся избегать (переобучения), поскольку это означает, что модель не учится распознавать общие характеристики, а просто запоминает обучающие выборки. Однако попытка обучить модель на одной выборке снова и снова - это хороший тест, позволяющий проверить, может ли проблема в том виде, в котором вы ее сформулировали, быть решена с помощью модели, которую вы пытаетесь обучить. Это также поможет вам понять, не слишком ли высока ваша начальная скорость обучения. + +Сделать это после того, как вы определили объект `model`, очень просто: просто возьмите батч обучающих данных, а затем рассматривайте этот `batch` как весь набор данных, подгоняя модель на большом количестве эпох: + +```py +for batch in train_dataset: + break + +# Убедитесь, что вы запустили model.compile() и установили свой оптимизатор, +# и ваши показатели потерь/метрики, если вы их используете + +model.fit(batch, epochs=20) +``` + + + +💡 Если ваши обучающие данные несбалансированы, обязательно создайте партию обучающих данных, содержащую все метки. + + + +Полученная модель должна иметь близкие к идеальным результаты для `батча`, значение функции потерь должно быстро уменьшаться до 0 (или минимальному значению для используемой вами функции потерь). + +Если вам не удается добиться идеальных результатов, значит, что-то не так с постановкой задачи или данными, и вам следует это исправить. Только когда вам удастся пройти тест на избыточную подгонку, вы сможете быть уверены, что ваша модель действительно способна чему-то научиться. + + + +⚠️ Вам придется пересоздать модель и перекомпилировать ее после этого теста на переобучение, поскольку полученная модель, вероятно, не сможет восстановиться и научиться чему-то полезному на полном наборе данных. + + + +### Не обучайте ничего, пока не получите первый бейзлайн.[[dont-tune-anything-until-you-have-a-first-baseline]] + +Интенсивная настройка гиперпараметров всегда подчеркивается как самая сложная часть машинного обучения, но это лишь последний шаг, который поможет вам немного продвинуться по метрике. *Очень* плохие значения гиперпараметров, например, использование стандартной скорости обучения Adam 1e-3 в модели Transformer, конечно, приведет к тому, что обучение будет идти очень медленно или полностью остановится, но в большинстве случаев "разумные" гиперпараметры, например, скорость обучения от 1e-5 до 5e-5, будут работать просто отлично и дадут вам хорошие результаты. Поэтому не начинайте трудоемкий и дорогостоящий поиск гиперпараметров до тех пор, пока не получите что-то, что превзойдет бейзлайн, имеющийся для вашего набора данных. + +Как только у вас будет достаточно хорошая модель, вы можете начать ее немного оптимизировать. Не пытайтесь запустить тысячу раз с разными гиперпараметрами, но сравните пару запусков с разными значениями одного гиперпараметра, чтобы получить представление о том, какой из них оказывает наибольшее влияние. + +Если вы настраиваете саму модель, будьте проще и не пробуйте то, что не можете обосновать. Всегда возвращайтесь к тесту на перебор, чтобы проверить, не привело ли ваше изменение к каким-либо непредвиденным последствиям. + +### Попросить о помощи[[ask-for-help]] + +Надеемся, вы нашли в этом разделе советы, которые помогли вам решить вашу проблему, но если это не так, помните, что вы всегда можете спросить у сообщества на [форумах](https://discuss.huggingface.co/). + +Вот некоторые дополнительные ресурсы, которые могут оказаться полезными: + +- [" Reproducibility as a vehicle for engineering best practices"](https://docs.google.com/presentation/d/1yHLPvPhUs2KGI5ZWo0sU-PKU3GimAk3iTsI38Z-B5Gw/edit#slide=id.p) by Joel Grus +- ["Checklist for debugging neural networks"](https://towardsdatascience.com/checklist-for-debugging-neural-networks-d8b2a9434f21) by Cecelia Shao +- [" How to unit test machine learning code"](https://medium.com/@keeper6928/how-to-unit-test-machine-learning-code-57cf6fd81765) by Chase Roberts +- [""A Recipe for Training Neural Networks"](http://karpathy.github.io/2019/04/25/recipe/) by Andrej Karpathy + +Конечно, не все проблемы, с которыми вы сталкиваетесь при обучении нейросетей, возникают по вашей вине! Если в библиотеке 🤗 Transformers или 🤗 Datasets вы столкнулись с чем-то, что кажется вам неправильным, возможно, вы обнаружили ошибку. Вам обязательно нужно рассказать нам об этом, и в следующем разделе мы объясним, как именно это сделать. From db7900174b6cb0f3a74af83de8990ea28187a5c8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 27 Jan 2024 12:23:58 +0300 Subject: [PATCH 380/502] fix typo --- chapters/ru/chapter8/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter8/2.mdx b/chapters/ru/chapter8/2.mdx index 950ef99c0..879e0bca3 100644 --- a/chapters/ru/chapter8/2.mdx +++ b/chapters/ru/chapter8/2.mdx @@ -1,4 +1,4 @@ -# Что делать, если возникла ошибку[[what-to-do-when-you-get-an-error]] +# Что делать, если возникла ошибка[[what-to-do-when-you-get-an-error]] Date: Sat, 27 Jan 2024 12:24:04 +0300 Subject: [PATCH 381/502] toc update --- chapters/ru/_toctree.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index 0ec4ac451..d676ccad0 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -134,6 +134,18 @@ - local: chapter7/9 title: Тест в конце главы quiz: 7 +-title: 8. Как попросить о помощи + sections: + - local: chapter8/1 + title: Введение + - local: chapter8/2 + title: Что делать, если возникла ошибка + - local: chapter8/3 + title: Обращение за помощью на форумах + - local: chapter8/4_tf + title: Отладка обучения + - local: chapter8/4 + title: Отладка обучения - title: Глоссарий sections: From 91b35f30d5d856ecc8cb334ddfda242ad55e96b8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 27 Jan 2024 12:33:22 +0300 Subject: [PATCH 382/502] typos fixed --- chapters/ru/chapter8/2.mdx | 2 +- chapters/ru/chapter8/3.mdx | 2 +- chapters/ru/chapter8/4.mdx | 6 +++--- chapters/ru/chapter8/4_tf.mdx | 16 ++++++++-------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/chapters/ru/chapter8/2.mdx b/chapters/ru/chapter8/2.mdx index 879e0bca3..1f7bd4d9c 100644 --- a/chapters/ru/chapter8/2.mdx +++ b/chapters/ru/chapter8/2.mdx @@ -52,7 +52,7 @@ def copy_repository_template(): Теперь при вызове `copy_repository_template()` будет создана копия хранилища шаблонов под вашим аккаунтом. -## Отладка конвейера из 🤗 Transformers[[debugging-the-pipeline-from-transformers]] +## Отладка пайплайна из 🤗 Transformers[[debugging-the-pipeline-from-transformers]] Чтобы начать наше путешествие в удивительный мир отладки моделей трансформеров, рассмотрим следующий сценарий: вы работаете с коллегой над проектом ответа на вопросы, который должен помочь клиентам сайта электронной коммерции найти ответы о потребительских товарах. Ваш коллега отправляет вам сообщение следующего содержания: diff --git a/chapters/ru/chapter8/3.mdx b/chapters/ru/chapter8/3.mdx index 2464bf683..2c32f72c9 100644 --- a/chapters/ru/chapter8/3.mdx +++ b/chapters/ru/chapter8/3.mdx @@ -138,7 +138,7 @@ IndexError: index out of range in self As you can see in the screenshot, enclosing the code blocks in backticks converts the raw text into formatted code, complete with color styling! Also note that single backticks can be used to format inline variables, like we've done for `distilbert-base-uncased`. This topic is looking much better, and with a bit of luck we might find someone in the community who can guess what the error is about. However, instead of relying on luck, let's make life easier by including the traceback in its full gory detail! -### Including the full traceback[[including-the-full-traceback]] +### Включение в текст полной трассировки[[including-the-full-traceback]] Как видно на скриншоте, заключение блоков кода в обратные знаки превращает исходный текст в отформатированный код, дополненный цветовой стилизацией! Также обратите внимание, что одиночные обратные знаки могут быть использованы для форматирования встроенных переменных, как мы это сделали для `distilbert-base-uncased`. Эта тема выглядит гораздо лучше, и, если повезет, мы сможем найти кого-то из сообщества, кто догадается, в чем ошибка. Однако вместо того, чтобы полагаться на удачу, давайте облегчим себе жизнь, включив в трассировку все подробности! diff --git a/chapters/ru/chapter8/4.mdx b/chapters/ru/chapter8/4.mdx index 7cd728aa4..c962f7b5f 100644 --- a/chapters/ru/chapter8/4.mdx +++ b/chapters/ru/chapter8/4.mdx @@ -11,7 +11,7 @@ Вы написали прекрасный сценарий для обучения или дообучения модели на заданной задаче, послушно следуя советам из [Главы 7](/course/chapter7). Но когда вы запускаете команду `model.fit()`, происходит нечто ужасное: вы получаете ошибку 😱! Или, что еще хуже, все вроде бы хорошо, обучение проходит без ошибок, но результирующая модель получается плохой. В этом разделе мы покажем вам, что можно сделать для отладки подобных проблем. -## Debugging the training pipeline[[debugging-the-training-pipeline]] +## Отладка обучающего пайплайна[[debugging-the-training-pipeline]] @@ -197,7 +197,7 @@ type(trainer.model) transformers.models.distilbert.modeling_distilbert.DistilBertForSequenceClassification ``` -So in our case, we can check the parameters accepted on [this page](https://huggingface.co/transformers/model_doc/distilbert.html#distilbertforsequenceclassification). The `Trainer` will also log the columns it's discarding. +Итак, в нашем случае мы можем проверить принятые параметры на [этой странице](https://huggingface.co/transformers/model_doc/distilbert.html#distilbertforsequenceclassification). "Trainer" также будет регистрировать столбцы, которые он отбрасывает. Мы проверили правильность входных идентификаторов, декодировав их. Далее находится `attention_mask`: @@ -516,7 +516,7 @@ trainer.optimizer.step() Опять же, если вы используете оптимизатор по умолчанию в `Trainer`, вы не должны получить ошибку на этом этапе, но если вы используете пользовательский оптимизатор, здесь могут возникнуть некоторые проблемы для отладки. Не забудьте вернуться к процессору, если на этом этапе вы получите странную ошибку CUDA. Говоря об ошибках CUDA, ранее мы упоминали особый случай. Давайте посмотрим на него сейчас. -### Работа с ошибкой CUDA OOM[[dealing-with-cuda-out-of-memory-errors]] +### Как справиться с ошибками нехватки памяти[[dealing-with-cuda-out-of-memory-errors]] Если вы получаете сообщение об ошибке, начинающееся с `RuntimeError: CUDA out of memory`, это означает, что вам не хватает памяти GPU. Это не связано напрямую с вашим кодом, и может произойти со скриптом, который работает совершенно нормально. Эта ошибка означает, что вы пытались поместить слишком много данных во внутреннюю память вашего GPU, и это привело к ошибке. Как и в случае с другими ошибками CUDA, вам придется перезапустить ядро, чтобы снова запустить обучение. diff --git a/chapters/ru/chapter8/4_tf.mdx b/chapters/ru/chapter8/4_tf.mdx index 99591374f..34cf6eb82 100644 --- a/chapters/ru/chapter8/4_tf.mdx +++ b/chapters/ru/chapter8/4_tf.mdx @@ -127,9 +127,9 @@ model.compile(optimizer="adam") 246/24543 [..............................] - ETA: 15:52 - loss: nan ``` -Oh no. +О, нет. -`nan` is not a very encouraging loss value. Still, we've checked our data, and it looks pretty good. If that's not the problem, where can we go next? The obvious next step is to... +"nan" — не очень обнадеживающаее значение функции потерь. Тем не менее, мы проверили наши данные, и они выглядят довольно хорошо. Если проблема не в этом, как двигаться дальше? Очевидным следующим шагом будет... ### Проверка модели[[check-your-model]] @@ -172,7 +172,7 @@ model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint) model(batch) ``` -When we run that, we get: +После запуска получим: ```py out TFSequenceClassifierOutput(loss= -### Hungry Hungry TensorFlow 🦛[[hungry-hungry-tensorflow]] +### "Голодный" TensorFlow 🦛[[hungry-hungry-tensorflow]] Одна особенность TensorFlow, о которой вам следует знать, заключается в том, что он выделяет *всю* память GPU под себя, как только вы загружаете модель или проводите обучение, а затем делит эту память по мере необходимости. Это отличается от поведения других фреймворков, например PyTorch, которые выделяют память по мере необходимости с помощью CUDA, а не делают это внутренне. Одним из преимуществ подхода TensorFlow является то, что он может часто выдавать полезные ошибки, когда у вас заканчивается память, и он может восстановиться из этого состояния без сбоя всего ядра CUDA. Но есть и важный недостаток: если вы запускаете два процесса TensorFlow одновременно, то **у вас будут проблемы**. @@ -403,7 +403,7 @@ model.fit(train_dataset) Если вы начинаете получать ошибки о CUDA, BLAS или cuBLAS в коде, который работал раньше, то очень часто причина кроется именно в этом. Вы можете использовать такую команду, как `nvidia-smi`, чтобы проверить - когда вы выключаете или перезапускаете текущий ноутбук, большая часть памяти свободна или она все еще используется? Если она все еще используется, значит, что-то еще держится за нее! -### Check your data (again!)[[check-your-data-again]] +### Проверьте свои данные (еще раз!)[[check-your-data-again]] Ваша модель научится чему-то только в том случае, если из ваших данных действительно можно чему-то научиться. Если в данных есть ошибка, которая портит их, или метки приписываются случайным образом, то, скорее всего, вы не сможете обучить модель на своем наборе данных. Одним из полезных инструментов здесь является `tokenizer.decode()`. Он превратит `input_ids` обратно в строки, и вы сможете просмотреть данные и понять, обучают ли ваши тренировочные данные тому, чему вы хотите их обучить. Например, после получения `пакета` из `tf.data.Dataset`, как мы делали выше, вы можете декодировать первый элемент следующим образом: @@ -481,6 +481,6 @@ model.fit(batch, epochs=20) - [" Reproducibility as a vehicle for engineering best practices"](https://docs.google.com/presentation/d/1yHLPvPhUs2KGI5ZWo0sU-PKU3GimAk3iTsI38Z-B5Gw/edit#slide=id.p) by Joel Grus - ["Checklist for debugging neural networks"](https://towardsdatascience.com/checklist-for-debugging-neural-networks-d8b2a9434f21) by Cecelia Shao - [" How to unit test machine learning code"](https://medium.com/@keeper6928/how-to-unit-test-machine-learning-code-57cf6fd81765) by Chase Roberts -- [""A Recipe for Training Neural Networks"](http://karpathy.github.io/2019/04/25/recipe/) by Andrej Karpathy +- ["A Recipe for Training Neural Networks"](http://karpathy.github.io/2019/04/25/recipe/) by Andrej Karpathy Конечно, не все проблемы, с которыми вы сталкиваетесь при обучении нейросетей, возникают по вашей вине! Если в библиотеке 🤗 Transformers или 🤗 Datasets вы столкнулись с чем-то, что кажется вам неправильным, возможно, вы обнаружили ошибку. Вам обязательно нужно рассказать нам об этом, и в следующем разделе мы объясним, как именно это сделать. From 6d161ca35474ee4dc5eede780bba2cd2db2a0a18 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 27 Jan 2024 12:34:16 +0300 Subject: [PATCH 383/502] removed english text --- chapters/ru/chapter5/3.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/chapters/ru/chapter5/3.mdx b/chapters/ru/chapter5/3.mdx index d5c232d63..49b35ca2c 100644 --- a/chapters/ru/chapter5/3.mdx +++ b/chapters/ru/chapter5/3.mdx @@ -387,8 +387,6 @@ ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 О, нет! Не сработало! Почему? Посмотрим на ошибку: несовпадение в длинах, один из которых длиной 1463, а другой – 1000. Если вы обратитесь в [документацию](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) `Dataset.map()`, вы можете увидеть, что одно из этих чисел – число объектов, поданных на вход функции, а другое – -Oh no! That didn't work! Why not? Looking at the error message will give us a clue: there is a mismatch in the lengths of one of the columns, one being of length 1,463 and the other of length 1,000. If you've looked at the [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map), you may recall that it's the number of samples passed to the function that we are mapping; here those 1,000 examples gave 1,463 new features, resulting in a shape error. - Проблема заключается в том, что мы пытаемся смешать два разных датасета разной размерности: число колонок датасета `drug_dataset` равняется 1000, а нужный нам `tokenized_dataset` имеет 1463 колонки. Чтобы избежать этой ошибки, необходимо удалить несколько столбцов из старого датасета и сделать оба датасета одинакового размера. Мы можем достичь этого с помощью аргумента `remove_columns`: ```py From b1a8e02982bd3812e676b394628ea8eed5812062 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 27 Jan 2024 12:47:05 +0300 Subject: [PATCH 384/502] 8/5 finished --- chapters/ru/chapter8/5.mdx | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 chapters/ru/chapter8/5.mdx diff --git a/chapters/ru/chapter8/5.mdx b/chapters/ru/chapter8/5.mdx new file mode 100644 index 000000000..383471bcd --- /dev/null +++ b/chapters/ru/chapter8/5.mdx @@ -0,0 +1,92 @@ +# Как сообщить об ошибке с помощью Issue[[how-to-write-a-good-issue]] + + + +Если вы столкнулись с чем-то, что кажется неправильным в одной из библиотек Hugging Face, вы должны обязательно сообщить нам об этом, чтобы мы могли это исправить (то же самое касается любой библиотеки с открытым исходным кодом, если на то пошло). Если вы не уверены, где именно кроется ошибка - в вашем собственном коде или в одной из наших библиотек, - первым делом загляните на [форумы](https://discuss.huggingface.co/). Сообщество поможет вам разобраться в этом, а команда Hugging Face также внимательно следит за обсуждениями там. + + + +Когда вы уверены, что встретили ошибку, первым шагом будет создание минимального воспроизводимого примера. + +## Создание минимального воспроизводимого примера[[creating-a-minimal-reproducible-example]] + +Очень важно изолировать часть кода, в которой возникает ошибка, поскольку никто из команды Hugging Face не является волшебником (пока), и они не могут исправить то, чего не видят. Минимальный воспроизводимый пример, как видно из названия, должен быть воспроизводимым. Это значит, что он не должен опираться на какие-либо внешние файлы или данные, которые могут у вас быть. Попробуйте заменить используемые данные какими-нибудь фиктивными значениями, которые выглядят как настоящие и при этом выдают ту же ошибку. + + + +🚨 Многие проблемы в репозитории 🤗 Transformers остаются нерешенными, потому что данные, использованные для их воспроизведения, недоступны. + + + +Когда у вас есть что-то самодостаточное, вы можете попытаться сократить его до еще меньшего количества строк кода, создав то, что мы называем _минимальным воспроизводимым примером_. Хотя это требует немного больше работы с вашей стороны, вы почти гарантированно получите помощь и исправление, если предоставите хороший, короткий пример воспроизведения ошибки. + +Если вы чувствуете себя достаточно комфортно, просмотрите исходный код, в котором произошла ваша ошибка. Возможно, вы найдете решение проблемы (в этом случае вы даже можете предложить pull request), но в целом это поможет сопровождающим лучше понять исходный код, когда они прочитают ваш отчет. + +## Заполнение шаблона проблемы[[filling-out-the-issue-template]] + +Когда вы начнете сообщать об ошибке, вы заметите, что есть шаблон, который нужно заполнить. Здесь мы будем следовать шаблону для [🤗 Transformers issues](https://github.com/huggingface/transformers/issues/new/choose), но такая же информация потребуется, если вы сообщите о проблеме в другом репозитории. Не оставляйте шаблон пустым: потратив время на его заполнение, вы увеличите свои шансы на получение ответа и решение проблемы. + +В целом, при оформлении проблемы всегда оставайтесь вежливыми. Это проект с открытым исходным кодом, поэтому вы используете свободное программное обеспечение, и никто не обязан вам помогать. Вы можете включить в свой вопрос обоснованную, на ваш взгляд, критику, но тогда сопровождающие могут воспринять это плохо и не спешить вам помогать. Обязательно прочитайте [кодекс поведения](https://github.com/huggingface/transformers/blob/master/CODE_OF_CONDUCT.md) проекта. + +### Включая информацию о вашем окружении разработки[[including-your-environment-information]] + +🤗 Transformers предоставляет утилиту для получения всей необходимой информации о вашем окружении. Просто введите в терминале следующее: + +``` +transformers-cli env +``` + +и у вас должно получиться что-то вроде этого: + +```out +Copy-and-paste the text below in your GitHub issue and FILL OUT the two last points. + +- `transformers` version: 4.12.0.dev0 +- Platform: Linux-5.10.61-1-MANJARO-x86_64-with-arch-Manjaro-Linux +- Python version: 3.7.9 +- PyTorch version (GPU?): 1.8.1+cu111 (True) +- Tensorflow version (GPU?): 2.5.0 (True) +- Flax version (CPU?/GPU?/TPU?): 0.3.4 (cpu) +- Jax version: 0.2.13 +- JaxLib version: 0.1.65 +- Using GPU in script?: +- Using distributed or parallel set-up in script?: +``` + +Вы также можете добавить `!` в начало команды `transformers-cli env`, чтобы выполнить ее из ячейки блокнота, а затем скопировать и вставить результат в начало описания проблемы. + +### Упоминание людей[[tagging-people]] + +Отметив людей, набрав `@`, а затем их GitHub-ник, вы отправите им уведомление, чтобы они увидели вашу проблему и могли быстрее ответить. Используйте этот способ аккуратно, потому что люди, которых вы помечаете, могут не обратить внимания на уведомления, если это что-то, к чему они не имеют прямого отношения. Если вы просмотрели исходные файлы, связанные с вашей ошибкой, вам следует отметить последнего человека, который внес изменения в строку, которая, по вашему мнению, ответственна за вашу проблему (вы можете найти эту информацию, посмотрев на указанную строку на GitHub, выбрав ее, а затем нажав "View git blame"). + +В противном случае шаблон предложит вам выбрать людей для пометки. В общем случае не следует отмечать более трех человек! + +### Включение воспроизводимого примера[[including-a-reproducible-example]] + +Если вам удалось создать самодостаточный пример, который выдает ошибку, самое время добавить его! Введите строку с тремя обратными знаками, за которыми следует `python`, например, так: + +``` +```python +``` + +затем вставьте свой минимальный воспроизводимый пример и введите новую строку с тремя обратными знаками. Это обеспечит правильное форматирование вашего кода. + +Если вам не удалось создать воспроизводимый пример, объясните в четких шагах, как вы пришли к своей проблеме. Если можно, включите ссылку на блокнот Google Colab, в котором вы получили ошибку. Чем больше информации вы предоставите, тем лучше смогут ответить вам сопровождающие. + +В любом случае вам следует скопировать и вставить все сообщение об ошибке, которое вы получаете. Если вы работаете в Colab, помните, что некоторые фреймы могут быть автоматически свернуты в трассировке стека, поэтому убедитесь, что вы развернули их перед копированием. Как и в примере кода, поместите сообщение об ошибке между двумя строками с тремя обратными знаками, чтобы оно было правильно отформатировано. + +### Описание ожидаемого поведения[[describing-the-expected-behavior]] + +Объясните в нескольких строках, что вы ожидали получить, чтобы сопровождающие получили полное представление о проблеме. Эта часть, как правило, довольно очевидна, поэтому должна уместиться в одном предложении, но в некоторых случаях вам будет что сказать. + +## И что потом?[[and-then-what]] + +Как только проблема будет зарегистрирована, не забудьте быстро проверить, все ли в порядке. Вы можете отредактировать вопрос, если допустили ошибку, или даже изменить его название, если поймете, что проблема отличается от того, что вы думали вначале. + +Нет смысла писать людям, если вы не получите ответа. Если никто не поможет вам в течение нескольких дней, скорее всего, никто не смог разобраться в вашей проблеме. Не стесняйтесь возвращаться к воспроизводимому примеру. Можете ли вы сделать его короче и понятнее? Если вы не получите ответа в течение недели, вы можете оставить сообщение с просьбой о помощи, особенно если вы отредактировали свой вопрос, чтобы включить в него больше информации о проблеме. + From 8c015d38e7a8e57be67d3c724df618877b189f51 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 27 Jan 2024 13:06:30 +0300 Subject: [PATCH 385/502] 8/6-7 finished --- chapters/ru/chapter8/6.mdx | 12 +++ chapters/ru/chapter8/7.mdx | 204 +++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 chapters/ru/chapter8/6.mdx create mode 100644 chapters/ru/chapter8/7.mdx diff --git a/chapters/ru/chapter8/6.mdx b/chapters/ru/chapter8/6.mdx new file mode 100644 index 000000000..d0abf9c94 --- /dev/null +++ b/chapters/ru/chapter8/6.mdx @@ -0,0 +1,12 @@ +# Часть 2 завершена![[part-2-completed]] + + + +Поздравляем, вы прошли вторую часть курса! Мы активно работаем над третьей частью, поэтому подпишитесь на нашу [рассылку](https://huggingface.curated.co/), чтобы не пропустить ее выход. + +Теперь вы должны уметь решать различные задачи NLP, дообучать или обучать модели с нуля. Не забудьте поделиться своими результатами с сообществом на [Model Hub](https://huggingface.co/models). + +Нам не терпится увидеть, что вы построите на основе полученных знаний! diff --git a/chapters/ru/chapter8/7.mdx b/chapters/ru/chapter8/7.mdx new file mode 100644 index 000000000..cfdf372e2 --- /dev/null +++ b/chapters/ru/chapter8/7.mdx @@ -0,0 +1,204 @@ + + +# Тест в конце главы[[end-of-chapter-quiz]] + + + +Let's test what you learned in this chapter! + +### 1. В каком порядке следует читать обратную трассировку в Python? + + + +### 2. Что такое минимальный воспроизводимый пример? + + + +### 3. Предположим, вы пытаетесь выполнить следующий код, который выдает ошибку: + +```py +from transformers import GPT3ForSequenceClassification + +# ImportError: cannot import name 'GPT3ForSequenceClassification' from 'transformers' (/Users/lewtun/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/__init__.py) +# --------------------------------------------------------------------------- +# ImportError Traceback (most recent call last) +# /var/folders/28/k4cy5q7s2hs92xq7_h89_vgm0000gn/T/ipykernel_30848/333858878.py in +# ----> 1 from transformers import GPT3ForSequenceClassification + +# ImportError: cannot import name 'GPT3ForSequenceClassification' from 'transformers' (/Users/lewtun/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/__init__.py) +``` + +Что из нижеперечисленного может быть хорошим выбором для названия темы на форуме с просьбой о помощи? + +ImportError: cannot import name 'GPT3ForSequenceClassification' from 'transformers' (/Users/lewtun/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/__init__.py)", + explain: "Включение последней строки трассировки может быть описательным, но это лучше оставить для основной части темы. Попробуйте еще раз!" + }, + { + text: "Проблема с from transformers import GPT3ForSequenceClassification", + explain: "Попробуйте еще раз - хотя это и полезная информация, ее лучше оставить для основной части текста.", + }, + { + text: "Почему я не могу импортировать GPT3ForSequenceClassification?", + explain: "Отличный выбор! Это название лаконично и дает читателю понять, что может быть не так (например, что GPT-3 не поддерживается в 🤗 Transformers).", + correct: true + }, + { + text: "Поддерживается ли GPT-3 в 🤗 Transformers?", + explain: "Отличный вариант! Использование вопросов в качестве заголовков тем - отличный способ донести проблему до сообщества.", + correct: true + } + ]} +/> + +### 4. Предположим, вы пытаетесь запустить `trainer.train()` и сталкиваетесь с загадочной ошибкой, которая не говорит вам, откуда именно она взялась. Что из нижеперечисленного является первым местом, где вы должны искать ошибки в вашем конвейере обучения? + + + +### 5. Каков наилучший способ отладки ошибок CUDA? + + + +### 6. Как лучше всего сообщить о проблеме на GitHub? + + + +### 7. Почему переобучение модели с одним батчем обычно является хорошим методом отладки? + + + +### 8. Почему при создании нового вопроса в репозитории 🤗 Transformers стоит указать подробности о вашем окружении разработки с помощью `transformers-cli env`?? + + From eb16954b1043a99f84fd0d27a95a70089e3a03a4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 28 Jan 2024 13:54:58 +0300 Subject: [PATCH 386/502] fix and update toc --- chapters/ru/_toctree.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index d676ccad0..3502e6e72 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -146,7 +146,14 @@ title: Отладка обучения - local: chapter8/4 title: Отладка обучения - + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: Как сообщить об ошибке с помощью Issue + - local: chapter8/6 + title: Часть 2 завершена! + - local: chapter8/7 + title: Тест в конце главы + quiz: 8 - title: Глоссарий sections: - local: glossary/1 From a7a0dac6a3cb1debc8a00a130ff9f0b8376a9881 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 30 Jan 2024 15:19:49 +0300 Subject: [PATCH 387/502] chapter8/1 fixed --- chapters/ru/chapter8/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter8/1.mdx b/chapters/ru/chapter8/1.mdx index eb58afd22..038e39e28 100644 --- a/chapters/ru/chapter8/1.mdx +++ b/chapters/ru/chapter8/1.mdx @@ -14,4 +14,4 @@ - Как отладить свой пайплайн обучения - Как правильно описать проблему -Разумеется, все это не относится конкретно к 🤗 Transformers или экосистеме Hugging Face; уроки из этой главы применимы к большинству проектов с открытым исходным кодом! \ No newline at end of file +Разумеется, все это не относится исключительно к 🤗 Transformers или экосистеме Hugging Face; уроки из этой главы применимы к большинству проектов с открытым исходным кодом! \ No newline at end of file From dd7bb8a9300e5e1ff0014d89a61a00e2fc9237ef Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 30 Jan 2024 15:19:54 +0300 Subject: [PATCH 388/502] chapter8/2 fixed --- chapters/ru/chapter8/2.mdx | 70 ++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/chapters/ru/chapter8/2.mdx b/chapters/ru/chapter8/2.mdx index 1f7bd4d9c..6b5e9a3a4 100644 --- a/chapters/ru/chapter8/2.mdx +++ b/chapters/ru/chapter8/2.mdx @@ -7,27 +7,27 @@ {label: "Aws Studio", значение: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter8/section2.ipynb"}, ]} /> -В этом разделе мы рассмотрим некоторые распространенные ошибки, которые могут возникнуть при попытке сгенерировать предсказания на основе только что настроенной модели Transformer. Это подготовит вас к [разделу 4](../chapter8/section4), где мы рассмотрим, как отладить сам этап обучения. +В этом разделе мы рассмотрим некоторые распространенные ошибки, которые могут возникнуть при попытке сгенерировать предсказания на основе только что настроенной модели Transformer. Это подготовит вас к [разделу 4](../chapter8/4), где мы рассмотрим, как отладить сам этап обучения. -Для этого раздела мы подготовили [репозиторий](https://huggingface.co/lewtun/distilbert-base-uncased-finetuned-squad-d5716d28), и если вы хотите запустить код в этой главе, вам сначала нужно скопировать модель в свой аккаунт на [Hugging Face Hub](https://huggingface.co). Для этого сначала войдите в систему, запустив в блокноте Jupyter одно из следующих действий: +Для этого раздела мы подготовили [репозиторий](https://huggingface.co/lewtun/distilbert-base-uncased-finetuned-squad-d5716d28), и если вы хотите запустить код в этой главе, вам сначала нужно скопировать модель в свой аккаунт на [Hugging Face Hub](https://huggingface.co). Для этого сначала авторизуйтесь на Hugging Face Hub. Если вы выполняете этот код в блокноте, вы можете сделать это с помощью следующей служебной функции: -``python +```python from huggingface_hub import notebook_login notebook_login() ``` -или следующее в вашем любимом терминале: +в терминале выполните следующее: -``bash +```bash huggingface-cli login ``` -Это попросит вас ввести имя пользователя и пароль и сохранит токен в *~/.cache/huggingface/*. После того как вы вошли в систему, вы можете скопировать хранилище шаблонов с помощью следующей функции: +Вас попросят ввести имя пользователя и пароль, токен будет сохранен в *~/.cache/huggingface/*. После того как вы вошли в систему, вы можете скопировать репозиторий-шаблон с помощью следующей функции: -``python +```python from distutils.dir_util import copy_tree from huggingface_hub import Repository, snapshot_download, create_repo, get_full_repo_name @@ -50,7 +50,7 @@ def copy_repository_template(): repo.push_to_hub() ``` -Теперь при вызове `copy_repository_template()` будет создана копия хранилища шаблонов под вашим аккаунтом. +Теперь при вызове `copy_repository_template()` будет создана копия репозитория-шаблона под вашим аккаунтом. ## Отладка пайплайна из 🤗 Transformers[[debugging-the-pipeline-from-transformers]] @@ -60,20 +60,46 @@ def copy_repository_template(): и первое, что приходит в голову, это загрузить модель, используя `pipeline` из 🤗 Transformers: -``python +```python from transformers import pipeline model_checkpoint = get_full_repo_name("distillbert-base-uncased-finetuned-squad-d5716d28") reader = pipeline("question-answering", model=model_checkpoint) ``` -``python out +```python out +""" +OSError: Can't load config for 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28'. Make sure that: + +- 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models' + +- or 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file +""" +``` + +О нет, кажется, что-то пошло не так! Если вы новичок в программировании, подобные ошибки могут показаться вам немного загадочными (что такое `OSError`?!). Это сообщение является лишь последней частью гораздо большего отчета об ошибке, называемого _Python traceback_ (он же трассировка стека). Например, если вы запустите этот код в Google Colab, вы увидите что-то похожее на содержимое скриншота ниже: + +
+A Python traceback. +
+ +В этих отчетах содержится много информации, поэтому давайте вместе пройдемся по ключевым местам. Первое, что следует отметить, - это то, что трассировки следует читать _снизу вверх_. Это может показаться странным, если вы привыкли читать английский текст сверху вниз, но это логично: трассировка показывает последовательность вызовов функций, которые делает `pipeline` при загрузке модели и токенизатора. (Более подробно о том, как работает `pipeline` под капотом, читайте в [Главе 2](../chapter2)). + + + +🚨 Видите синюю рамку вокруг "6 frames" в трассировке Google Colab? Это специальная функция Colab, которая помещает отчет в раскрывающийся блок текста. Если вы не можете найти источник ошибки, обязательно раскройте этот блок, нажав на эти две маленькие стрелки. + + + +Последняя строка трассировки указывает на последнее сообщение об ошибке и дает имя исключения, которое было вызвано. В данном случае тип исключения - `OSError`, что указывает на системную ошибку. Если мы прочитаем сопроводительное сообщение об ошибке, то увидим, что, похоже, возникла проблема с файлом *config.json* модели, и нам предлагается два варианта ее устранения: + +```python out """ -OSError: Невозможно загрузить конфигурацию для 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28'. Убедитесь, что: +Make sure that: -- 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' - это правильный идентификатор модели, указанный на 'https://huggingface.co/models'. +- 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models' -- или 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' - это правильный путь к директории, содержащей файл config.json +- or 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file """ ``` @@ -95,7 +121,7 @@ OSError: Невозможно загрузить конфигурацию для The right model name.
-Хорошо!. Теперь давайте попробуем загрузить модель снова с правильным идентификатором модели: +Хорошо! Теперь давайте попробуем загрузить модель снова с правильным идентификатором модели: ```python model_checkpoint = get_full_repo_name("distilbert-base-uncased-finetuned-squad-d5716d28") @@ -172,7 +198,7 @@ reader(question=question, context=context) 'answer': 'the task of extracting an answer from a text given a question'} ``` -Ух ты, сработало! Давайте вспомним, что вы только что узнали: +Ура, сработало! Давайте вспомним, что вы только что узнали: - Сообщения об ошибках в Python называются _tracebacks_ и читаются снизу вверх. Последняя строка сообщения об ошибке обычно содержит информацию, необходимую для поиска источника проблемы. - Если последняя строка не содержит достаточной информации, пройдите путь вверх по трассировке и посмотрите, сможете ли вы определить, в каком месте исходного кода возникла ошибка. @@ -198,7 +224,7 @@ model = reader.model question = "Which frameworks can I use?" ``` -Как мы видели в [Главе 7] (../chapter7/1), обычные шаги, которые нам нужно предпринять, - это токенизация входных данных, извлечение логитов начальных и конечных токенов, а затем декодирование диапазона ответов: +Как мы видели в [Главе 7](../chapter7/1), обычные шаги, которые нам нужно предпринять, - это токенизация входных данных, извлечение логитов начальных и конечных токенов, а затем декодирование диапазона ответов: ```python import torch @@ -208,9 +234,9 @@ input_ids = inputs["input_ids"][0] outputs = model(**inputs) answer_start_scores = outputs.start_logits answer_end_scores = outputs.end_logits -# Get the most likely beginning of answer with the argmax of the score +# Выберем наиболее правдоподобную позицию начала ответа с помощью функции argmax answer_start = torch.argmax(answer_start_scores) -# Get the most likely end of answer with the argmax of the score +# Выберем наиболее правдоподбную позицию окончания ответа с помощью функции argmax answer_end = torch.argmax(answer_end_scores) + 1 answer = tokenizer.convert_tokens_to_string( tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end]) @@ -290,7 +316,7 @@ type(inputs["input_ids"]) list ``` -Да, это точно список Python. Так что же пошло не так? Вспомним из [Главы 2](../chapter2), что классы `AutoModelForXxx` в 🤗 Transformers работают с _тензорами_ (либо в PyTorch, либо в TensorFlow), и обычной операцией является извлечение размерности тензора с помощью `Tensor.size()`, скажем, в PyTorch. Давайте еще раз посмотрим на трассировку, чтобы увидеть, какая строка вызвала исключение: +Да, это точно список Python. Так что же пошло не так? Вспомним из [Главы 2](../chapter2/1), что классы `AutoModelForXxx` в 🤗 Transformers работают с _тензорами_ (либо в PyTorch, либо в TensorFlow), и обычной операцией является извлечение размерности тензора с помощью `Tensor.size()`, скажем, в PyTorch. Давайте еще раз посмотрим на трассировку, чтобы увидеть, какая строка вызвала исключение: ``` ~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, output_attentions, output_hidden_states, return_dict) @@ -303,7 +329,7 @@ list AttributeError: 'list' object has no attribute 'size' ``` -Похоже, что наш код пытался вызвать `input_ids.size()`, но это явно не сработает для Python `list`. Как мы можем решить эту проблему? Поиск сообщения об ошибке на Stack Overflow дает довольно много релевантных [результатов](https://stackoverflow.com/search?q=AttributeError%3A+%27list%27+object+has+no+attribute+%27size%27&s=c15ec54c-63cb-481d-a749-408920073e8f). При нажатии на первую из них появляется вопрос, аналогичный нашему, ответ на который показан на скриншоте ниже: +Похоже, что наш код пытался вызвать `input_ids.size()`, но это явно не сработает для Python `list`. Как мы можем решить эту проблему? Поиск сообщения об ошибке на Stack Overflow дает довольно много релевантных [результатов](https://stackoverflow.com/search?q=AttributeError%3A+%27list%27+object+has+no+attribute+%27size%27&s=c15ec54c-63cb-481d-a749-408920073e8f). При нажатии на первый из них появляется вопрос, аналогичный нашему, ответ на который показан на скриншоте ниже:
An answer from Stack Overflow. @@ -317,9 +343,9 @@ input_ids = inputs["input_ids"][0] outputs = model(**inputs) answer_start_scores = outputs.start_logits answer_end_scores = outputs.end_logits -# Get the most likely beginning of answer with the argmax of the score +# Выберем наиболее правдоподобную позицию начала ответа с помощью функции argmax answer_start = torch.argmax(answer_start_scores) -# Get the most likely end of answer with the argmax of the score +# Выберем наиболее правдоподбную позицию окончания ответа с помощью функции argmax answer_end = torch.argmax(answer_end_scores) + 1 answer = tokenizer.convert_tokens_to_string( tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end]) From d24a0c183eb8c934fab3a42856f88da24ff67097 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 30 Jan 2024 15:20:01 +0300 Subject: [PATCH 389/502] chapter8/3 fixed --- chapters/ru/chapter8/3.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/chapters/ru/chapter8/3.mdx b/chapters/ru/chapter8/3.mdx index 2c32f72c9..49b56a4f8 100644 --- a/chapters/ru/chapter8/3.mdx +++ b/chapters/ru/chapter8/3.mdx @@ -9,13 +9,13 @@ -Форумы [Hugging Face](https://discuss.huggingface.co) - это отличное место, где можно получить помощь от команды разработчиков с открытым исходным кодом и более широкого сообщества Hugging Face. Вот как выглядит главная страница в любой день: +Форумы [Hugging Face](https://discuss.huggingface.co) - это отличное место, где можно получить помощь от команды разработчиков библиотек и более широкого сообщества Hugging Face. Вот как выглядит главная страница в любой день:
The Hugging Face forums.
-С левой стороны вы можете увидеть все категории, по которым сгруппированы различные темы, а с правой - самые последние темы. Тема - это сообщение, содержащее заголовок, категорию и описание; это очень похоже на формат вопросов GitHub, который мы видели при создании нашего собственного набора данных в [Главе 5](../chapter5). Как следует из названия, категория [Beginners](https://discuss.huggingface.co/c/beginners/5) предназначена в первую очередь для тех, кто только начинает знакомиться с библиотеками и экосистемой Hugging Face. Здесь можно задать любой вопрос по любой из библиотек, будь то отладка кода или просьба о помощи, как что-то сделать. (При этом, если ваш вопрос касается какой-то конкретной библиотеки, вам, вероятно, следует обратиться в соответствующую категорию библиотек на форуме). +С левой стороны вы можете увидеть все категории, по которым сгруппированы различные темы, а с правой - самые последние темы. Тема - это сообщение, содержащее заголовок, категорию и описание; это очень похоже на формат вопросов GitHub, который мы видели при создании нашего собственного набора данных в [Главе 5](../chapter5/1). Как следует из названия, категория [Beginners](https://discuss.huggingface.co/c/beginners/5) предназначена в первую очередь для тех, кто только начинает знакомиться с библиотеками и экосистемой Hugging Face. Здесь можно задать любой вопрос по любой из библиотек, будь то отладка кода или просьба о помощи, как что-то сделать. (При этом, если ваш вопрос касается какой-то конкретной библиотеки, вам, вероятно, следует обратиться в соответствующую категорию библиотек на форуме). Аналогично, категории [Intermediate](https://discuss.huggingface.co/c/intermediate/6) и [Research](https://discuss.huggingface.co/c/research/7) предназначены для более сложных вопросов, например, о библиотеках или новых крутых исследованиях в области НЛП, которые вы хотели бы обсудить. @@ -35,7 +35,7 @@ tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) model = AutoModel.from_pretrained(model_checkpoint) ``` -Теперь предположим, что мы попытаемся построить векторное представления для целого раздела [статьи с Википедии](https://en.wikipedia.org/wiki/Transformers), посвященной Трансформерам (модели, а не библиотеке!): +Теперь предположим, что мы попытаемся построить векторное представления для целого раздела [статьи с Википедии](https://en.wikipedia.org/wiki/Transformers), посвященной Трансформерам (франшизе, а не библиотеке!): ```python text = """ @@ -88,7 +88,7 @@ logits = model(**inputs).logits IndexError: index out of range in self ``` -О-о, мы столкнулись с проблемой - и сообщение об ошибке гораздо более загадочно, чем те, что мы видели в [разделе 2](2.mdx)! Мы не можем разобраться в полном её описании, поэтому решили обратиться за помощью на форум Hugging Face. Как мы можем создать тему? +О-о, мы столкнулись с проблемой - и сообщение об ошибке гораздо более загадочно, чем те, что мы видели в [разделе 2](2)! Мы не можем разобраться в полном её описании, поэтому решили обратиться за помощью на форум Hugging Face. Как мы можем создать тему? Чтобы начать, нам нужно нажать кнопку "Новая тема" в правом верхнем углу (обратите внимание, что для создания темы нам нужно войти в систему): @@ -116,7 +116,7 @@ IndexError: index out of range in self Такие темы, как эта, вряд ли получат быстрый ответ (если вообще получат), так что давайте посмотрим, как можно их улучшить. Начнем с первого вопроса - выбора хорошего названия. -### Выбор содержательного названия[[choosing-a-descriptive-title]] +### Выберите содержательное название[[choosing-a-descriptive-title]] Если вы пытаетесь получить помощь по поводу ошибки в вашем коде, хорошим правилом является включение достаточного количества информации в заголовок, чтобы другие могли быстро определить, смогут ли они ответить на ваш вопрос или нет. В нашем примере мы знаем имя возникающего исключения и имеем некоторые намеки на то, что оно срабатывает в прямом проходе модели, где мы вызываем `model(**inputs)`. Чтобы сообщить об этом, один из возможных вариантов заголовка может быть таким: @@ -128,7 +128,7 @@ IndexError: index out of range in self также может подойти. Теперь, когда у нас есть описательный заголовок, давайте посмотрим, как улучшить само описание ошибки. -### Форматирование кода[[formatting-your-code-snippets]] +### Отформатируйте код[[formatting-your-code-snippets]] Читать исходный код в IDE достаточно сложно, но еще сложнее, когда код скопирован и вставлен в виде обычного текста! К счастью, форумы Hugging Face поддерживают использование Markdown, поэтому вы всегда должны заключать свои блоки кода в три обратных знака (```), чтобы их было легче читать. Давайте сделаем это, чтобы отформатировать сообщение об ошибке - и пока мы это делаем, давайте сделаем текст немного более вежливым, чем наша первоначальная версия: @@ -138,7 +138,7 @@ IndexError: index out of range in self As you can see in the screenshot, enclosing the code blocks in backticks converts the raw text into formatted code, complete with color styling! Also note that single backticks can be used to format inline variables, like we've done for `distilbert-base-uncased`. This topic is looking much better, and with a bit of luck we might find someone in the community who can guess what the error is about. However, instead of relying on luck, let's make life easier by including the traceback in its full gory detail! -### Включение в текст полной трассировки[[including-the-full-traceback]] +### Добавьте текст полной трассировки[[including-the-full-traceback]] Как видно на скриншоте, заключение блоков кода в обратные знаки превращает исходный текст в отформатированный код, дополненный цветовой стилизацией! Также обратите внимание, что одиночные обратные знаки могут быть использованы для форматирования встроенных переменных, как мы это сделали для `distilbert-base-uncased`. Эта тема выглядит гораздо лучше, и, если повезет, мы сможем найти кого-то из сообщества, кто догадается, в чем ошибка. Однако вместо того, чтобы полагаться на удачу, давайте облегчим себе жизнь, включив в трассировку все подробности! @@ -152,7 +152,7 @@ As you can see in the screenshot, enclosing the code blocks in backticks convert Однако мы можем еще больше облегчить им задачу, предоставив фактический код, вызвавший ошибку. Давайте сделаем это прямо сейчас. -### Предоставление воспроизводимого примера[[providing-a-reproducible-example]] +### Предоставьте воспроизводимый пример[[providing-a-reproducible-example]] Если вы когда-нибудь пытались отладить чужой код, вы, вероятно, сначала пытались воссоздать проблему, о которой они сообщали, чтобы начать работать над трассировкой, чтобы точно определить ошибку. Это не отличается от того, когда речь идет о получении (или предоставлении) помощи на форумах, поэтому очень помогает, если вы можете предоставить небольшой пример, воспроизводящий ошибку. В половине случаев простое выполнение этого упражнения поможет вам понять, что происходит не так. В любом случае, недостающий фрагмент нашего примера - это показать _входы_, которые мы предоставили модели. Выполнив это, мы получим нечто похожее на следующий завершенный пример: From b4bd04970820f8c090680f22dfc32c6280d53766 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 30 Jan 2024 15:20:06 +0300 Subject: [PATCH 390/502] chapter8/4 fixed --- chapters/ru/chapter8/4.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/chapters/ru/chapter8/4.mdx b/chapters/ru/chapter8/4.mdx index c962f7b5f..2141a5afe 100644 --- a/chapters/ru/chapter8/4.mdx +++ b/chapters/ru/chapter8/4.mdx @@ -9,7 +9,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter8/section4.ipynb"}, ]} /> -Вы написали прекрасный сценарий для обучения или дообучения модели на заданной задаче, послушно следуя советам из [Главы 7](/course/chapter7). Но когда вы запускаете команду `model.fit()`, происходит нечто ужасное: вы получаете ошибку 😱! Или, что еще хуже, все вроде бы хорошо, обучение проходит без ошибок, но результирующая модель получается плохой. В этом разделе мы покажем вам, что можно сделать для отладки подобных проблем. +Вы написали прекрасный сценарий для обучения или дообучения модели на заданной задаче, послушно следуя советам из [Главы 7](/course/chapter7/1). Но когда вы запускаете команду `model.fit()`, происходит нечто ужасное: вы получаете ошибку 😱! Или, что еще хуже, все вроде бы хорошо, обучение проходит без ошибок, но результирующая модель получается плохой. В этом разделе мы покажем вам, что можно сделать для отладки подобных проблем. ## Отладка обучающего пайплайна[[debugging-the-training-pipeline]] @@ -79,7 +79,7 @@ trainer.train() ### Проверка данных[[check-your-data]] -Это само собой разумеется, но если ваши данные повреждены, `Trainer` не сможет сформировать батчи, не говоря уже об обучении вашей модели. Поэтому прежде всего необходимо посмотреть, что находится в вашем обучающем наборе. +Это может быть очевидно, но если ваши данные повреждены, `Trainer` не сможет сформировать батчи, не говоря уже об обучении вашей модели. Поэтому прежде всего необходимо посмотреть, что находится в вашем обучающем наборе. Чтобы избежать бесчисленных часов, потраченных на попытки исправить то, что не является источником ошибки, мы рекомендуем использовать `trainer.train_dataset` для проверок и ничего больше. Так что давайте сделаем это здесь: @@ -167,7 +167,7 @@ trainer.train() Поэтому нам следует перейти к этому. Однако перед этим давайте закончим проверку наших данных, чтобы быть на 100% уверенными в их правильности. -При отладке обучения всегда нужно смотреть на декодированные входы модели. Мы не можем понять смысл чисел, которые подаем ей напрямую, поэтому мы должны посмотреть, что эти числа представляют. В компьютерном зрении, например, это означает просмотр декодированных изображений пройденных пикселей, в речи - прослушивание декодированных образцов звука, а в нашем примере с НЛП - использование нашего токенизатора для декодирования входных данных: +При отладке обучения всегда нужно смотреть на декодированные входы модели. Мы не можем понять смысл чисел, которые подаем ей напрямую, поэтому мы должны посмотреть, что эти числа представляют. В компьютерном зрении, например, это означает просмотр декодированных изображений пройденных пикселей, в речи - прослушивание декодированных образцов звука, а в нашем примере с NLP - использование нашего токенизатора для декодирования входных данных: ```py tokenizer.decode(trainer.train_dataset[0]["input_ids"]) @@ -374,7 +374,7 @@ batch = data_collator([actual_train_set[i] for i in range(4)]) Теперь, когда мы отладили процесс создания батча, пришло время пропустить его через модель! -### Проверка модели[[going-through-the-model]] +### Проверьте данные[[going-through-the-model]] Вы должны иметь возможность получить батч, выполнив следующую команду: @@ -514,7 +514,7 @@ trainer.create_optimizer() trainer.optimizer.step() ``` -Опять же, если вы используете оптимизатор по умолчанию в `Trainer`, вы не должны получить ошибку на этом этапе, но если вы используете пользовательский оптимизатор, здесь могут возникнуть некоторые проблемы для отладки. Не забудьте вернуться к процессору, если на этом этапе вы получите странную ошибку CUDA. Говоря об ошибках CUDA, ранее мы упоминали особый случай. Давайте посмотрим на него сейчас. +Опять же, если вы используете оптимизатор по умолчанию в `Trainer`, вы не должны получить ошибку на этом этапе, но если вы используете собственный оптимизатор, здесь могут возникнуть некоторые проблемы для отладки. Не забудьте вернуться к процессору, если на этом этапе вы получите странную ошибку CUDA. Говоря об ошибках CUDA, ранее мы упоминали особый случай. Давайте посмотрим на него сейчас. ### Как справиться с ошибками нехватки памяти[[dealing-with-cuda-out-of-memory-errors]] @@ -533,7 +533,7 @@ trainer.optimizer.step() Теперь, когда мы решили все проблемы с нашим кодом, все идеально, и обучение должно пройти гладко, верно? Не так быстро! Если вы запустите команду `trainer.train()`, сначала все будет выглядеть хорошо, но через некоторое время вы получите следующее: ```py -# This will take a long time and error out, so you shouldn't run this cell +# Это займет много времени и приведет к ошибке, поэтому не стоит запускать эту ячейку trainer.train() ``` @@ -605,7 +605,7 @@ predictions.shape, labels.shape ((8, 3), (8,)) ``` -Наши предсказания все еще являются логарифмами, а не реальными предсказаниями, поэтому метрика возвращает эту (несколько непонятную) ошибку. Исправить это довольно просто: нужно просто добавить argmax в функцию `compute_metrics()`: +Наши предсказания все еще являются логитами, а не реальными предсказаниями, поэтому метрика возвращает эту (несколько непонятную) ошибку. Исправить это довольно просто: нужно просто добавить argmax в функцию `compute_metrics()`: ```py import numpy as np @@ -771,13 +771,13 @@ compute_metrics((preds.cpu().numpy(), labels.cpu().numpy())) ### Не обучайте ничего, пока не получите первый бейзлайн.[[dont-tune-anything-until-you-have-a-first-baseline]] -Настройка гиперпараметров всегда считается самой сложной частью машинного обучения, но это всего лишь последний шаг, который поможет вам немного улучшить метрику. В большинстве случаев гиперпараметры по умолчанию `Trainer` будут работать нормально и давать вам хорошие результаты, поэтому не приступайте к трудоемкому и дорогостоящему поиску гиперпараметров, пока у вас не будет чего-то, что превосходит бейзлайн, который у вас есть в вашем наборе данных. . +Настройка гиперпараметров всегда считается самой сложной частью машинного обучения, но это всего лишь последний шаг, который поможет вам немного улучшить метрику. В большинстве случаев гиперпараметры по умолчанию `Trainer` будут работать нормально и давать вам хорошие результаты, поэтому не приступайте к трудоемкому и дорогостоящему поиску гиперпараметров, пока у вас не будет чего-то, что превосходит базовый уровень, который у вас есть в вашем наборе данных. Как только у вас будет достаточно хорошая модель, вы можете начать ее немного оптимизировать. Не пытайтесь запустить тысячу раз с разными гиперпараметрами, но сравните пару запусков с разными значениями одного гиперпараметра, чтобы получить представление о том, какой из них оказывает наибольшее влияние. Если вы настраиваете саму модель, будьте проще и не пробуйте то, что не можете обосновать. Всегда возвращайтесь к тесту на перебор, чтобы проверить, не привело ли ваше изменение к каким-либо непредвиденным последствиям. -### Попросить о помощи[[ask-for-help]] +### Попросите о помощи[[ask-for-help]] Надеемся, вы нашли в этом разделе советы, которые помогли вам решить вашу проблему, но если это не так, помните, что вы всегда можете спросить у сообщества на [форумах](https://discuss.huggingface.co/). From 47c809aba0726c8393b85f196fc66b59c32c143a Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 30 Jan 2024 15:20:11 +0300 Subject: [PATCH 391/502] chapter8/5 fixed --- chapters/ru/chapter8/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter8/5.mdx b/chapters/ru/chapter8/5.mdx index 383471bcd..6f977272c 100644 --- a/chapters/ru/chapter8/5.mdx +++ b/chapters/ru/chapter8/5.mdx @@ -7,7 +7,7 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter8/section5.ipynb"}, ]} /> -Если вы столкнулись с чем-то, что кажется неправильным в одной из библиотек Hugging Face, вы должны обязательно сообщить нам об этом, чтобы мы могли это исправить (то же самое касается любой библиотеки с открытым исходным кодом, если на то пошло). Если вы не уверены, где именно кроется ошибка - в вашем собственном коде или в одной из наших библиотек, - первым делом загляните на [форумы](https://discuss.huggingface.co/). Сообщество поможет вам разобраться в этом, а команда Hugging Face также внимательно следит за обсуждениями там. +Если вы столкнулись с чем-то, что кажется неправильным в одной из библиотек Hugging Face, обязательно сообщите нам об этом, чтобы мы могли это исправить (то же самое касается любой библиотеки с открытым исходным кодом, если на то пошло). Если вы не уверены, где именно кроется ошибка - в вашем собственном коде или в одной из наших библиотек, - первым делом загляните на [форумы](https://discuss.huggingface.co/). Сообщество поможет вам разобраться в этом, а команда Hugging Face также внимательно следит за обсуждениями там. From 5893e53697bb58ef5d480a4ff3a4027b6903b056 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 30 Jan 2024 18:44:24 +0300 Subject: [PATCH 392/502] fix title 8/5 --- chapters/ru/chapter8/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter8/5.mdx b/chapters/ru/chapter8/5.mdx index 6f977272c..c24eabf50 100644 --- a/chapters/ru/chapter8/5.mdx +++ b/chapters/ru/chapter8/5.mdx @@ -1,4 +1,4 @@ -# Как сообщить об ошибке с помощью Issue[[how-to-write-a-good-issue]] +# Как написать хорошее сообщение об ошибке (issue)[[how-to-write-a-good-issue]] Date: Tue, 30 Jan 2024 18:44:32 +0300 Subject: [PATCH 393/502] fix title 8/5 in toc --- chapters/ru/_toctree.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index 3502e6e72..ff1d28b5b 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -148,7 +148,7 @@ title: Отладка обучения local_fw: { pt: chapter8/4, tf: chapter8/4_tf } - local: chapter8/5 - title: Как сообщить об ошибке с помощью Issue + title: Как написать хорошее сообщение об ошибке (issue) - local: chapter8/6 title: Часть 2 завершена! - local: chapter8/7 From d46939cb9e89db6ed040d46a5e5c808ebf9dc903 Mon Sep 17 00:00:00 2001 From: Pavel <60391448+pdumin@users.noreply.github.com> Date: Wed, 31 Jan 2024 00:06:05 +0400 Subject: [PATCH 394/502] Update _toctree.yml title 8 Co-authored-by: Maria Khalusova --- chapters/ru/_toctree.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index ff1d28b5b..42d2197a4 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -134,7 +134,7 @@ - local: chapter7/9 title: Тест в конце главы quiz: 7 --title: 8. Как попросить о помощи +- title: 8. Как попросить о помощи sections: - local: chapter8/1 title: Введение From e4eae4c889bc598da53b30cc1dea86c722cdaa64 Mon Sep 17 00:00:00 2001 From: lewtun Date: Wed, 31 Jan 2024 14:12:41 +0100 Subject: [PATCH 395/502] Bump black (#671) --- chapters/fr/chapter9/4.mdx | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/fr/chapter9/4.mdx b/chapters/fr/chapter9/4.mdx index ea9509a02..937ac66d0 100644 --- a/chapters/fr/chapter9/4.mdx +++ b/chapters/fr/chapter9/4.mdx @@ -48,7 +48,7 @@ gr.Interface( title=title, description=description, article=article, - examples=[["What are you doing?"], ["Where should we time travel to?"]] + examples=[["What are you doing?"], ["Where should we time travel to?"]], # ["Que faites-vous ?"], ["Où devrions-nous voyager dans le temps ?"] ).launch() ``` diff --git a/requirements.txt b/requirements.txt index 8f94be377..0a14ffdfa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ nbformat>=5.1.3 PyYAML>=5.4.1 -black==22.3.0 \ No newline at end of file +black>=24.1.1 \ No newline at end of file From b973ea809c508044d18855d64e79d0898c7deda5 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 31 Jan 2024 16:45:12 +0300 Subject: [PATCH 396/502] fix unexpected token in quiz --- chapters/ru/chapter8/7.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/ru/chapter8/7.mdx b/chapters/ru/chapter8/7.mdx index cfdf372e2..3cfc8670b 100644 --- a/chapters/ru/chapter8/7.mdx +++ b/chapters/ru/chapter8/7.mdx @@ -14,8 +14,8 @@ Let's test what you learned in this chapter! Date: Wed, 31 Jan 2024 19:15:32 +0300 Subject: [PATCH 397/502] 8/2 fixed --- chapters/ru/chapter8/2.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/ru/chapter8/2.mdx b/chapters/ru/chapter8/2.mdx index 6b5e9a3a4..08b975198 100644 --- a/chapters/ru/chapter8/2.mdx +++ b/chapters/ru/chapter8/2.mdx @@ -83,7 +83,7 @@ OSError: Can't load config for 'lewtun/distillbert-base-uncased-finetuned-squad- A Python traceback.
-В этих отчетах содержится много информации, поэтому давайте вместе пройдемся по ключевым местам. Первое, что следует отметить, - это то, что трассировки следует читать _снизу вверх_. Это может показаться странным, если вы привыкли читать английский текст сверху вниз, но это логично: трассировка показывает последовательность вызовов функций, которые делает `pipeline` при загрузке модели и токенизатора. (Более подробно о том, как работает `pipeline` под капотом, читайте в [Главе 2](../chapter2)). +В этих отчетах содержится много информации, поэтому давайте вместе пройдемся по ключевым местам. Первое, что следует отметить, - это то, что трассировки следует читать _снизу вверх_. Это может показаться странным, если вы привыкли читать английский текст сверху вниз, но это логично: трассировка показывает последовательность вызовов функций, которые делает `pipeline` при загрузке модели и токенизатора. (Более подробно о том, как работает `pipeline` под капотом, читайте в [Главе 2](../chapter2/1)). @@ -292,11 +292,11 @@ AttributeError: 'list' object has no attribute 'size' -or in a terminal: +или в терминале: -Здесь чтение сообщения об ошибке говорит нам, что у объекта `'list'' нет атрибута 'size', и мы видим стрелку `-->`, указывающую на строку, где возникла проблема в `model(**inputs)`. Вы можете отладить это интерактивно, используя отладчик Python, но сейчас мы просто распечатаем фрагмент `inputs`, чтобы посмотреть, что у нас есть: +Здесь чтение сообщения об ошибке говорит нам, что у объекта `'list'` нет атрибута 'size', и мы видим стрелку `-->`, указывающую на строку, где возникла проблема в `model(**inputs)`. Вы можете отладить это интерактивно, используя отладчик Python, но сейчас мы просто распечатаем фрагмент `inputs`, чтобы посмотреть, что у нас есть: ```python inputs["input_ids"][:5] From b62a3a4ef3db36ea0620f22cc961a8530db878cd Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 31 Jan 2024 19:15:38 +0300 Subject: [PATCH 398/502] 8/3 fixed --- chapters/ru/chapter8/3.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter8/3.mdx b/chapters/ru/chapter8/3.mdx index 49b56a4f8..ad9fd9330 100644 --- a/chapters/ru/chapter8/3.mdx +++ b/chapters/ru/chapter8/3.mdx @@ -136,7 +136,7 @@ IndexError: index out of range in self Our revised forum topic, with proper code formatting.
-As you can see in the screenshot, enclosing the code blocks in backticks converts the raw text into formatted code, complete with color styling! Also note that single backticks can be used to format inline variables, like we've done for `distilbert-base-uncased`. This topic is looking much better, and with a bit of luck we might find someone in the community who can guess what the error is about. However, instead of relying on luck, let's make life easier by including the traceback in its full gory detail! +Как видно на скриншоте, заключение блоков кода в обратные кавычки превращает исходный текст в отформатированный код, дополненный цветовой стилизацией! Также обратите внимание, что одиночные обратные кавычки могут быть использованы для форматирования встроенных переменных, как мы это сделали для `distilbert-base-uncased`. В таком оформлении сообщение выглядит гораздо лучше, и, если повезет, мы сможем найти кого-то из сообщества, кто догадается, в чем ошибка. Но вместо того, чтобы полагаться на удачу, давайте облегчим себе жизнь, включив трассировку во всех подробностях! ### Добавьте текст полной трассировки[[including-the-full-traceback]] From 0a33e6144d3f667ebcfab68df35c1493e532edef Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 31 Jan 2024 19:15:44 +0300 Subject: [PATCH 399/502] 8/4_tf fixed --- chapters/ru/chapter8/4_tf.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/ru/chapter8/4_tf.mdx b/chapters/ru/chapter8/4_tf.mdx index 34cf6eb82..c88ce58e1 100644 --- a/chapters/ru/chapter8/4_tf.mdx +++ b/chapters/ru/chapter8/4_tf.mdx @@ -349,11 +349,11 @@ model.fit(train_dataset) ### Проверка гиперпараметров[[check-your-hyperparameters]] -Если вы посмотрите на приведенный выше код, то, возможно, вообще не увидите никаких гиперпараметров, кроме, возможно, `batch_size`, и это не кажется вероятной причиной. Однако не обманывайтесь: гиперпараметры есть всегда, и если вы их не видите, значит, вы просто не знаете, на что они настроены. В частности, запомните важную особенность Keras: если вы задаете функцию потерь, оптимизатора или активации с помощью строки, _все ее аргументы будут установлены в значения по умолчанию_. Это означает, что, несмотря на удобство использования строк, следует быть очень осторожным, так как это может легко скрыть от вас критические вещи. (Любой, кто попробует решить опциональную задачу, описанную выше, должен внимательно отнестись к этому факту). +Если вы посмотрите на приведенный выше код, то, возможно, вообще не увидите никаких гиперпараметров, кроме, возможно, `batch_size`, и это не кажется вероятной причиной. Однако не обманывайтесь: гиперпараметры есть всегда, и если вы их не видите, значит, вы просто не знаете, на что они настроены. В частности, запомните важную особенность Keras: если вы задаете функцию потерь, оптимизатора или активации с помощью строки, _все ее аргументы будут установлены в значения по умолчанию_. Это означает, что, несмотря на удобство использования такого способа, следует быть очень осторожным, так как это может легко скрыть от вас критические вещи. (Любой, кто попробует решить опциональную задачу, описанную выше, должен внимательно отнестись к этому факту). -В данном случае где мы задали аргумент с помощью строки? Изначально мы задавали функцию потерь строкой, но теперь мы этого не делаем. Однако мы задаем оптимизатору строку "adam". Может ли это что-то скрывать от нас? Давайте посмотрим на [его аргументы](https://www.tensorflow.org/api_docs/python/tf/keras/optimizers/Adam). +В данном случае где мы задали аргумент с помощью строки? Изначально мы так делали с функцией потерь, но мы это исправили. Теперь мы задаем оптимизатор с помощью строки. Может ли это что-то скрывать от нас? Давайте посмотрим на [его аргументы](https://www.tensorflow.org/api_docs/python/tf/keras/optimizers/Adam). -Здесь что-нибудь выделяется? Правильно - скорость обучения! Когда мы просто используем строку `'adam'', мы получим скорость обучения по умолчанию, которая составляет 0.001, или 1e-3. Это слишком много для модели трансформера! В целом, мы рекомендуем использовать для моделей скорость обучения от 1e-5 до 1e-4; это в 10-100 раз меньше, чем значение, которое мы используем в данном случае. Похоже, это может стать серьезной проблемой, так что давайте попробуем ее уменьшить. Для этого нам нужно импортировать настоящий объект `optimizer`. Пока мы это делаем, давайте заново инициализируем модель из контрольной точки, на случай если обучение с высокой скоростью обучения повредило ее веса: +Здесь что-нибудь выделяется? Правильно - скорость обучения! Когда мы просто используем строку `'adam'`, мы получим скорость обучения по умолчанию, которая составляет 0.001, или 1e-3. Это слишком много для модели трансформера! В целом, мы рекомендуем использовать для моделей скорость обучения от 1e-5 до 1e-4; это в 10-100 раз меньше, чем значение, которое мы используем в данном случае. Похоже, это может стать серьезной проблемой, так что давайте попробуем ее уменьшить. Для этого нам нужно импортировать настоящий объект `optimizer`. Пока мы это делаем, давайте заново инициализируем модель из контрольной точки, на случай если обучение с высокой скоростью обучения повредило ее веса: ```python from tensorflow.keras.optimizers import Adam From b5090663b8819998c79f3f78ddc79233fe9ab68f Mon Sep 17 00:00:00 2001 From: Yanis ALLOUCH <75087263+yanisallouch@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:35:37 +0100 Subject: [PATCH 400/502] Update 3b.mdx fix typo --- chapters/fr/chapter6/3b.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/fr/chapter6/3b.mdx b/chapters/fr/chapter6/3b.mdx index 6e670483f..f523851ed 100644 --- a/chapters/fr/chapter6/3b.mdx +++ b/chapters/fr/chapter6/3b.mdx @@ -25,7 +25,7 @@ {/if} -Nous allons maintenant nous plonger dans le pipeline de `question-answering` et voir comment exploiter les *offsets* pour extraire d'u ncontexte la réponse à la question posée. Nous verrons ensuite comment gérer les contextes très longs qui finissent par être tronqués. Vous pouvez sauter cette section si vous n'êtes pas intéressé par la tâche de réponse aux questions. +Nous allons maintenant nous plonger dans le pipeline de `question-answering` et voir comment exploiter les *offsets* pour extraire d'un contexte la réponse à la question posée. Nous verrons ensuite comment gérer les contextes très longs qui finissent par être tronqués. Vous pouvez sauter cette section si vous n'êtes pas intéressé par la tâche de réponse aux questions. {#if fw === 'pt'} @@ -274,11 +274,11 @@ end_probabilities = tf.math.softmax(end_logits, axis=-1)[0].numpy() A ce stade, nous pourrions prendre l'argmax des probabilités de début et de fin mais nous pourrions nous retrouver avec un indice de début supérieur à l'indice de fin. Nous devons donc prendre quelques précautions supplémentaires. Nous allons calculer les probabilités de chaque `start_index` et `end_index` possible où `start_index<=end_index`, puis nous prendrons le *tuple* `(start_index, end_index)` avec la plus grande probabilité. -En supposant que les événements « La réponse commence à `start_index` » et « La réponse se termine à `end_index` » sont indépendants, la probabilité que la réponse commence à `end_index` et se termine à `end_index` est : +En supposant que les événements « La réponse commence à `start_index` » et « La réponse se termine à `end_index` » sont indépendants, la probabilité que la réponse commence à `start_index` et se termine à `end_index` est : $$\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]$$ -Ainsi, pour calculer tous les scores, il suffit de calculer tous les produits \\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\) où `start_index <= end_index`. +Ainsi, pour calculer tous les scores, il suffit de calculer tous les produits $$\\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\)$$ où `start_index <= end_index`. Calculons d'abord tous les produits possibles : From 1185e7edfb1c368bfcefe3d953931fca9b308be8 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 31 Jan 2024 20:58:13 +0300 Subject: [PATCH 401/502] Added translation of chapter 9 and Course Events. --- .../_toctree-checkpoint.yml | 201 +++++++++++++++ chapters/ru/_toctree.yml | 35 +++ chapters/ru/chapter9/1.mdx | 37 +++ chapters/ru/chapter9/2.mdx | 118 +++++++++ chapters/ru/chapter9/3.mdx | 186 ++++++++++++++ chapters/ru/chapter9/4.mdx | 147 +++++++++++ chapters/ru/chapter9/5.mdx | 67 +++++ chapters/ru/chapter9/6.mdx | 101 ++++++++ chapters/ru/chapter9/7.mdx | 236 +++++++++++++++++ chapters/ru/chapter9/8.mdx | 24 ++ chapters/ru/chapter9/9.mdx | 239 ++++++++++++++++++ chapters/ru/events/1.mdx | 48 ++++ chapters/ru/events/2.mdx | 165 ++++++++++++ chapters/ru/events/3.mdx | 9 + 14 files changed, 1613 insertions(+) create mode 100644 chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml create mode 100644 chapters/ru/chapter9/1.mdx create mode 100644 chapters/ru/chapter9/2.mdx create mode 100644 chapters/ru/chapter9/3.mdx create mode 100644 chapters/ru/chapter9/4.mdx create mode 100644 chapters/ru/chapter9/5.mdx create mode 100644 chapters/ru/chapter9/6.mdx create mode 100644 chapters/ru/chapter9/7.mdx create mode 100644 chapters/ru/chapter9/8.mdx create mode 100644 chapters/ru/chapter9/9.mdx create mode 100644 chapters/ru/events/1.mdx create mode 100644 chapters/ru/events/2.mdx create mode 100644 chapters/ru/events/3.mdx diff --git a/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml new file mode 100644 index 000000000..c8364cc6d --- /dev/null +++ b/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml @@ -0,0 +1,201 @@ +- title: 0. Setup + sections: + - local: chapter0/1 + title: Introduction + +- title: 1. Transformer models + sections: + - local: chapter1/1 + title: Introduction + - local: chapter1/2 + title: Natural Language Processing + - local: chapter1/3 + title: Transformers, what can they do? + - local: chapter1/4 + title: How do Transformers work? + - local: chapter1/5 + title: Encoder models + - local: chapter1/6 + title: Decoder models + - local: chapter1/7 + title: Sequence-to-sequence models + - local: chapter1/8 + title: Bias and limitations + - local: chapter1/9 + title: Summary + - local: chapter1/10 + title: End-of-chapter quiz + quiz: 1 + +- title: 2. Using 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Behind the pipeline + - local: chapter2/3 + title: Models + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Handling multiple sequences + - local: chapter2/6 + title: Putting it all together + - local: chapter2/7 + title: Basic usage completed! + - local: chapter2/8 + title: End-of-chapter quiz + quiz: 2 + +- title: 3. Fine-tuning a pretrained model + sections: + - local: chapter3/1 + title: Introduction + - local: chapter3/2 + title: Processing the data + - local: chapter3/3 + title: Fine-tuning a model with the Trainer API or Keras + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: A full training + - local: chapter3/5 + title: Fine-tuning, Check! + - local: chapter3/6 + title: End-of-chapter quiz + quiz: 3 + +- title: 4. Sharing models and tokenizers + sections: + - local: chapter4/1 + title: The Hugging Face Hub + - local: chapter4/2 + title: Using pretrained models + - local: chapter4/3 + title: Sharing pretrained models + - local: chapter4/4 + title: Building a model card + - local: chapter4/5 + title: Part 1 completed! + - local: chapter4/6 + title: End-of-chapter quiz + quiz: 4 + +- title: 5. The 🤗 Datasets library + sections: + - local: chapter5/1 + title: Introduction + - local: chapter5/2 + title: What if my dataset isn't on the Hub? + - local: chapter5/3 + title: Time to slice and dice + - local: chapter5/4 + title: Big data? 🤗 Datasets to the rescue! + - local: chapter5/5 + title: Creating your own dataset + - local: chapter5/6 + title: Semantic search with FAISS + - local: chapter5/7 + title: 🤗 Datasets, check! + - local: chapter5/8 + title: End-of-chapter quiz + quiz: 5 + +- title: 6. The 🤗 Tokenizers library + sections: + - local: chapter6/1 + title: Introduction + - local: chapter6/2 + title: Training a new tokenizer from an old one + - local: chapter6/3 + title: Fast tokenizers' special powers + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Normalization and pre-tokenization + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 + +- title: 7. Main NLP tasks + sections: + - local: chapter7/1 + title: Introduction + - local: chapter7/2 + title: Token classification + - local: chapter7/3 + title: Fine-tuning a masked language model + - local: chapter7/4 + title: Translation + - local: chapter7/5 + title: Summarization + - local: chapter7/6 + title: Training a causal language model from scratch + - local: chapter7/7 + title: Question answering + - local: chapter7/8 + title: Mastering NLP + - local: chapter7/9 + title: End-of-chapter quiz + quiz: 7 + +- title: 8. How to ask for help + sections: + - local: chapter8/1 + title: Introduction + - local: chapter8/2 + title: What to do when you get an error + - local: chapter8/3 + title: Asking for help on the forums + - local: chapter8/4 + title: Debugging the training pipeline + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: How to write a good issue + - local: chapter8/6 + title: Part 2 completed! + - local: chapter8/7 + title: End-of-chapter quiz + quiz: 8 + +- title: 9. Building and sharing demos + new: true + subtitle: I trained a model, but how can I show it off? + sections: + - local: chapter9/1 + title: Introduction to Gradio + - local: chapter9/2 + title: Building your first demo + - local: chapter9/3 + title: Understanding the Interface class + - local: chapter9/4 + title: Sharing demos with others + - local: chapter9/5 + title: Integrations with the Hugging Face Hub + - local: chapter9/6 + title: Advanced Interface features + - local: chapter9/7 + title: Introduction to Blocks + - local: chapter9/8 + title: Gradio, check! + - local: chapter9/9 + title: End-of-chapter quiz + quiz: 9 + +- title: Course Events + sections: + - local: events/1 + title: Live sessions and workshops + - local: events/2 + title: Part 2 release event + - local: events/3 + title: Gradio Blocks party diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index 42d2197a4..575ac4556 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -134,6 +134,7 @@ - local: chapter7/9 title: Тест в конце главы quiz: 7 + - title: 8. Как попросить о помощи sections: - local: chapter8/1 @@ -154,6 +155,40 @@ - local: chapter8/7 title: Тест в конце главы quiz: 8 + +- title: 9. Создание и распространение демо + new: true + subtitle: Я обучил модель, но как мне ее продемонстрировать? + sections: + - local: chapter9/1 + title: Введение в Gradio + - local: chapter9/2 + title: Создание вашего первого демо + - local: chapter9/3 + title: Понимание класса Interface + - local: chapter9/4 + title: Делимся демонстрациями с другими + - local: chapter9/5 + title: Интеграция с Hugging Face Hub + - local: chapter9/6 + title: Расширенные возможности Interface + - local: chapter9/7 + title: Введение в Gradio Blocks + - local: chapter9/8 + title: Gradio, проверка! + - local: chapter9/9 + title: Тест в конце главы + quiz: 9 + +- title: События курса + sections: + - local: events/1 + title: Встречи и семинары + - local: events/2 + title: Событие посвященное выходу 2 части курса + - local: events/3 + title: Вечеринка Gradio Blocks + - title: Глоссарий sections: - local: glossary/1 diff --git a/chapters/ru/chapter9/1.mdx b/chapters/ru/chapter9/1.mdx new file mode 100644 index 000000000..4af88378c --- /dev/null +++ b/chapters/ru/chapter9/1.mdx @@ -0,0 +1,37 @@ +# Введение в Gradio[[introduction-to-gradio]] + + + +В этой главе мы узнаем о том, как создавать **интерактивные демонстрации** для моделей машинного обучения. + +Зачем вообще создавать демо или графический интерфейс для модели машинного обучения? Демо позволяют: + +- **Разработчикам машинного обучения** легко представить свою работу широкой аудитории, включая нетехнические команды или клиентов +- **Исследователям** легче воспроизводить модели машинного обучения и их поведение +- **Тестировщики качества** или **конечные пользователи**, смогут легче выявлять и отлаживать точки отказа в моделях +- **Различные пользователи** смогут обнаружить алгоритмические ошибки в моделях + +Мы будем использовать библиотеку Gradio для создания демо для наших моделей. Gradio позволяет создавать, настраивать и распространять веб-демо для любой модели машинного обучения, полностью на языке Python. + +Вот несколько примеров демо машинного обучения, созданных с помощью Gradio: + +* Модель **распознавания эскизов (sketch recognition)**, которая принимает эскиз и выводит метки того, что, по ее мнению, нарисовано: + + + +* Экстрактивная модель **ответа на вопрос**, которая принимает контекстный параграф и задание и выдает ответ и оценку вероятности (мы обсуждали этот тип модели [в главе 7](../chapter7/7)): + + + +* Модель **удаления фона**, которая принимает изображение и возвращает его с удаленным фоном: + + + +Эта глава разбита на разделы, включающие как _концепции_, так и _приложения_. После изучения концепций в каждом разделе вы будете применять их для создания демо определенного типа, начиная от классификации изображений и заканчивая распознаванием речи. К тому времени, как вы закончите эту главу, вы сможете создавать эти демо (и многие другие!) всего в несколько строк кода на Python. + + +👀 Проверьте Hugging Face Spaces чтобы увидеть множество свежих примеров демо машинного обучения, созданных сообществом специалистов по машинному обучению! + \ No newline at end of file diff --git a/chapters/ru/chapter9/2.mdx b/chapters/ru/chapter9/2.mdx new file mode 100644 index 000000000..04abe6e19 --- /dev/null +++ b/chapters/ru/chapter9/2.mdx @@ -0,0 +1,118 @@ +# Создание вашего первого демо[[building-your-first-demo]] + + + +Давайте начнем с установки Gradio! Поскольку это пакет для Python, просто выполните: + +`$ pip install gradio ` + +Вы можете запускать Gradio где угодно, будь то ваша любимая IDE Python, Jupyter-блокнот или даже Google Colab 🤯! +Так что установите Gradio везде, где вы используете Python! + +Давайте начнем с простого примера "Hello World", чтобы познакомиться с синтаксисом Gradio: + +```py +import gradio as gr + + +def greet(name): + return "Hello " + name + + +demo = gr.Interface(fn=greet, inputs="text", outputs="text") + +demo.launch() +``` + +Давайте пройдемся по приведенному выше коду: + +- Сначала мы определяем функцию `greet()`. В данном случае это простая функция, которая добавляет "Hello" перед вашим именем, но это может быть *любая* функция Python в целом. Например, в приложениях машинного обучения эта функция будет *вызывать модель для прогнозирования* на входных данных и возвращать вывод. +- Затем мы создаем интерфейс Gradio `Interface` с тремя аргументами, `fn`, `inputs` и `outputs`. Эти аргументы определяют функцию прогнозирования, а также _тип_ входных и выходных компонентов, которые мы хотим получить. В нашем случае оба компонента представляют собой простые текстовые поля. +- Затем мы вызываем метод `launch()` для созданного нами `Interface`. + +Если вы запустите этот код, нижеприведенный интерфейс автоматически появится в блокноте Jupyter/Colab или откроется в браузере на **[http://localhost:7860](http://localhost:7860/)** при запуске из скрипта. + + + +Попробуйте использовать этот GUI прямо сейчас с собственным именем или другими данными! + +Вы заметите, что в этом GUI Gradio автоматически определил имя входного параметра (`name`) +и применил его в качестве метки поверх текстового поля. Что если вы захотите изменить это? +Или если вы хотите настроить текстовое поле каким-то другим способом? В этом случае вы можете +инстанцировать объект класса, представляющий компонент ввода. + +Посмотрите на пример ниже: + +```py +import gradio as gr + + +def greet(name): + return "Hello " + name + + +# Мы инстанцируем класс Textbox +textbox = gr.Textbox(label="Type your name here:", placeholder="John Doe", lines=2) + +gr.Interface(fn=greet, inputs=textbox, outputs="text").launch() +``` + + + +Здесь мы создали текстовое поле ввода с меткой, заполнителем и заданным количеством строк. +То же самое можно сделать и для выходного текстового поля, но мы пока что остановимся на этом. + +Мы увидели, что с помощью всего нескольких строк кода Gradio позволяет создать простой интерфейс вокруг любой функции +с любыми входами и выходами. В этом разделе мы начали с +простого текстового поля, но в следующих разделах мы рассмотрим другие виды входов и выходов. Теперь давайте рассмотрим применение некоторого NLP в приложении Gradio. + + +## 🤖 Добавление прогнозов модели[[including-model-predictions]] + +Теперь давайте рассмотрим простой интерфейс, который позволит продемонстрировать демо модели **генерации текста (text-generation)**, такой как GPT-2. + +Мы загрузим нашу модель с помощью функции `pipeline()` из 🤗 Transformers. +Если вам нужно быстро освежить в памяти материал, вы можете вернуться к [этому разделу в Главе 1](../chapter1/3#text-generation). + +Сначала мы определяем функцию прогнозирования, которая принимает текстовую подсказку (text prompt) и возвращает ее завершение текста: + +```py +from transformers import pipeline + +model = pipeline("text-generation") + + +def predict(prompt): + completion = model(prompt)[0]["generated_text"] + return completion +``` + +Эта функция завершает введенные вами подсказки, и вы можете запустить ее с вашими собственными подсказками, чтобы посмотреть, как она работает. Вот пример (вы можете получить другое завершение): + +``` +predict("My favorite programming language is") +``` + +``` +>> My favorite programming language is Haskell. I really enjoyed the Haskell language, but it doesn't have all the features that can be applied to any other language. For example, all it does is compile to a byte array. +``` + +Теперь, когда у нас есть функция для генерации прогнозов, мы можем создать и запустить `Interface` таким же образом, как мы делали это ранее: + +```py +import gradio as gr + +gr.Interface(fn=predict, inputs="text", outputs="text").launch() +``` + + +Вот и все! Теперь вы можете использовать этот интерфейс для генерации текста с помощью модели GPT-2, как показано ниже 🤯. + + + +Продолжайте читать, чтобы узнать, как создавать другие виды демо с помощью Gradio! \ No newline at end of file diff --git a/chapters/ru/chapter9/3.mdx b/chapters/ru/chapter9/3.mdx new file mode 100644 index 000000000..005bff120 --- /dev/null +++ b/chapters/ru/chapter9/3.mdx @@ -0,0 +1,186 @@ +# Понимание класса Interface[[understanding-the-interface-class]] + + + +В этом разделе мы подробно рассмотрим класс `Interface` и разберем +основные параметры, используемые для его создания. + +## Как создать Interface[[how-to-create-an-interface]] + +Вы заметите, что класс `Interface` имеет 3 обязательных параметра: + +`Interface(fn, inputs, outputs, ...)` + +Это параметры: + + - `fn`: функция прогнозирования, обернутая интерфейсом Gradio. Эта функция может принимать один или несколько параметров и возвращать одно или несколько значений + - `inputs`: тип(ы) компонента(ов) ввода. Gradio предоставляет множество готовых компонентов, таких как `"image"` или `"mic"`. + - `outputs`: тип(ы) компонента(ов) вывода. Опять же, Gradio предоставляет множество предварительно созданных компонентов, например, `" image"` или `"label"`. + +Полный список компонентов [смотрите в документации Gradio](https://gradio.app/docs). Каждый предварительно созданный компонент можно настроить, инстанцировав соответствующий ему класс. + +Например, как мы видели в [предыдущем разделе](../chapter9/2), +вместо передачи `"textbox"` в параметр `inputs`, вы можете передать компонент `Textbox(lines=7, label="Prompt")` для создания текстового поля с 7 строками и меткой. + +Давайте рассмотрим еще один пример, на этот раз с компонентом `Audio`. + +## Простой пример со звуком[[a-simple-example-with-audio]] + +Как уже говорилось, Gradio предоставляет множество различных входов и выходов. +Поэтому давайте создадим `Interface`, работающий с аудио. + +В этом примере мы создадим функцию audio-to-audio, которая принимает +аудиофайл и просто переворачивает его. + +Для ввода мы будем использовать компонент `Audio`. При использовании компонента `Audio`, +вы можете указать, будет ли источником звука файл, который загружает пользователь +или микрофон, с помощью которого пользователь записывает свой голос. В данном случае давайте +зададим `"microphone"`. Просто ради интереса добавим к `Audio` метку, которая будет гласить +"Speak here...". + +Кроме того, мы хотели бы получать аудио в виде массива numpy, чтобы можно было легко +"перевернуть" его. Поэтому мы зададим `"type"` в значение `"numpy"`, которое передаст входные +данные в виде кортежа (`sample_rate`, `data`) в нашу функцию. + +Мы также будем использовать компонент вывода `Audio`, который может автоматически +рендерить кортеж с частотой дискретизации и массивом данных numpy в воспроизводимый аудиофайл. +В этом случае нам не нужно делать никаких настроек, поэтому мы будем использовать строку +ярлык `"audio"`. + + +```py +import numpy as np +import gradio as gr + + +def reverse_audio(audio): + sr, data = audio + reversed_audio = (sr, np.flipud(data)) + return reversed_audio + + +mic = gr.Audio(source="microphone", type="numpy", label="Speak here...") +gr.Interface(reverse_audio, mic, "audio").launch() +``` + +Код, приведенный выше, создаст интерфейс, подобный приведенному ниже (если ваш браузер не +не запрашивает разрешения на использование микрофона, откройте демо в отдельной вкладке.) + + + +Теперь вы сможете записать свой голос и услышать, как вы говорите в обратную сторону - жутковато 👻! + +## Обработка нескольких входов и выходов[[handling-multiple-inputs-and-outputs]] + +Допустим, у нас есть более сложная функция, с несколькими входами и выходами. +В примере ниже у нас есть функция, которая принимает индекс выпадающего списка, значение слайдера и число, +и возвращает пример музыкального тона. + +Посмотрите, как мы передаем список входных и выходных компонентов, +и посмотрите, сможете ли вы проследить за тем, что происходит. + +Ключевым моментом здесь является то, что когда вы передаете: +* список входных компонентов, каждый компонент соответствует параметру по порядку. +* список выходных компонентов, каждый компонент соответствует возвращаемому значению. + +В приведенном ниже фрагменте кода показано, как три компонента ввода соответствуют трем аргументам функции `generate_tone()`: + +```py +import numpy as np +import gradio as gr + +notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] + + +def generate_tone(note, octave, duration): + sr = 48000 + a4_freq, tones_from_a4 = 440, 12 * (octave - 4) + (note - 9) + frequency = a4_freq * 2 ** (tones_from_a4 / 12) + duration = int(duration) + audio = np.linspace(0, duration, duration * sr) + audio = (20000 * np.sin(audio * (2 * np.pi * frequency))).astype(np.int16) + return (sr, audio) + + +gr.Interface( + generate_tone, + [ + gr.Dropdown(notes, type="index"), + gr.Slider(minimum=4, maximum=6, step=1), + gr.Textbox(type="number", value=1, label="Duration in seconds"), + ], + "audio", +).launch() +``` + + + + +### Метод `launch()`[[the-launch-method]] + +До сих пор мы использовали метод `launch()` для запуска интерфейса, но мы +не обсуждали, что он делает. + +По умолчанию метод `launch()` запускает демо на веб-сервере, который +работает локально. Если вы выполняете свой код в блокноте Jupyter или Colab, то +Gradio встроит демо GUI в блокнот, чтобы вы могли легко им пользоваться. + +Вы можете настроить поведение `launch()` с помощью различных параметров: + + - `inline` - отображать ли интерфейс в виде строки в блокнотах Python. + - `inbrowser` - автоматически ли запускать интерфейс в новой вкладке браузера по умолчанию. + - `share` - создавать ли для интерфейса общедоступную ссылку с вашего компьютера. Что-то вроде ссылки на Google Drive! + +Мы рассмотрим параметр `share` более подробно в следующем разделе! + +## ✏️ Давайте применим это![[lets-apply-it]] + +Давайте создадим интерфейс, который позволит вам продемонстрировать демо модели **распознавания речи**. +Чтобы было интереснее, мы будем принимать *либо* микрофонный вход, либо загруженный файл. + +Как обычно, мы загрузим нашу модель распознавания речи с помощью функции `pipeline()` из 🤗 Transformers. +Если вам нужно быстро вспомнить, вы можете вернуться к [этому разделу в Главе 1](../chapter1/3). Далее мы реализуем функцию `transcribe_audio()`, которая обрабатывает аудио и возвращает транскрипцию. Наконец, мы обернем эту функцию в `Interface` с компонентами `Audio` на входе и просто текстом на выходе. В целом, код этого приложения выглядит следующим образом: + +```py +from transformers import pipeline +import gradio as gr + +model = pipeline("automatic-speech-recognition") + + +def transcribe_audio(mic=None, file=None): + if mic is not None: + audio = mic + elif file is not None: + audio = file + else: + return "You must either provide a mic recording or a file" + transcription = model(audio)["text"] + return transcription + + +gr.Interface( + fn=transcribe_audio, + inputs=[ + gr.Audio(source="microphone", type="filepath", optional=True), + gr.Audio(source="upload", type="filepath", optional=True), + ], + outputs="text", +).launch() +``` + +Если ваш браузер не запрашивает разрешения на использование микрофона, откройте демо в отдельной вкладке. + + + + +Вот и все! Теперь вы можете использовать этот интерфейс для транскрибирования аудио. Обратите внимание, что +передавая параметр `optional` как `True`, мы позволяем пользователю предоставить +либо микрофон, либо аудиофайл (либо ни то, ни другое, но в этом случае будет выдано сообщение об ошибке). + +Продолжайте, чтобы узнать, как поделиться своим интерфейсом с другими! \ No newline at end of file diff --git a/chapters/ru/chapter9/4.mdx b/chapters/ru/chapter9/4.mdx new file mode 100644 index 000000000..08584cea3 --- /dev/null +++ b/chapters/ru/chapter9/4.mdx @@ -0,0 +1,147 @@ +# Делимся демо с другими[[sharing-demos-with-others]] + + + +Теперь, когда вы создали демо, вы наверняка захотите поделиться им с другими. Демо Gradio +можно распространять двумя способами: используя ***временную ссылку для общего доступа*** или ***постоянный хостинг на Spaces***. + +Мы рассмотрим оба этих подхода в ближайшее время. Но прежде чем выложить свое демо, вы, возможно, захотите доработать его 💅. + +### Доработка демо Gradio:[[polishing-your-gradio-demo]] + +
+Overview of a gradio interface + +
+ +Чтобы добавить дополнительный контент в демо, класс `Interface` поддерживает некоторые необязательные параметры: + - `title`: вы можете дать название своему демо, которое будет отображаться _над_ компонентами ввода и вывода. + - `description`: вы можете дать описание (в виде текста, Markdown или HTML) для интерфейса, которое отображается над компонентами ввода и вывода и под заголовком. + - `article`: вы также можете написать расширенную статью (в текстовом формате, Markdown или HTML), объясняющую интерфейс. Если она задана, она отображается _под_ компонентами ввода и вывода. + - `theme`: не нравятся цвета по умолчанию? Установите для темы одно из значений `default`, `huggingface`, `grass`, `peach`. Вы также можете добавить префикс `dark-`, например, `dark-peach` для темной темы (или просто `dark` для темной темы по умолчанию). + - `examples`: чтобы сделать ваше демо более удобным в использовании, вы можете предоставить несколько примеров входов для функции. Они появляются под компонентами пользовательского интерфейса и могут быть использованы для заполнения интерфейса. Они должны быть предоставлены в виде вложенного списка, в котором внешний список состоит из примеров, а каждый внутренний список состоит из ввода, соответствующего каждому компоненту ввода. + - `live`: если вы хотите сделать демо "живым", то есть чтобы ваша модель запускалась заново при каждом изменении входных данных, вы можете установить `live=True`. Это имеет смысл использовать с быстрыми моделями (пример мы увидим в конце этого раздела) +Используя приведенные выше варианты, мы получим более завершенный интерфейс. Запустите приведенный ниже код, и вы сможете пообщаться с Риком и Морти: + +```py +title = "Ask Rick a Question" +description = """ +The bot was trained to answer questions based on Rick and Morty dialogues. Ask Rick anything! + +""" + +article = "Check out [the original Rick and Morty Bot](https://huggingface.co/spaces/kingabzpro/Rick_and_Morty_Bot) that this demo is based off of." + +gr.Interface( + fn=predict, + inputs="textbox", + outputs="text", + title=title, + description=description, + article=article, + examples=[["What are you doing?"], ["Where should we time travel to?"]], +).launch() +``` + +Используя приведенные выше варианты, мы получим более завершенный интерфейс. Попробуйте интерфейс, представленный ниже: + + + +### Распространение демо с помощью временных ссылок[[sharing-your-demo-with-temporary-links]] +Теперь, когда у нас есть работающее демо нашей модели машинного обучения, давайте узнаем, как легко поделиться ссылкой на наш интерфейс. +Интерфейсами можно легко поделиться публично, установив `share=True` в методе `launch()`: + +```python +gr.Interface(classify_image, "image", "label").launch(share=True) +``` + +В результате создается общедоступная ссылка, которую вы можете отправить кому угодно! Когда вы отправляете эту ссылку, пользователь на другой стороне может опробовать модель в своем браузере в течение 72 часов. Поскольку обработка происходит на вашем устройстве (пока оно включено!), вам не нужно беспокоиться об упаковке каких-либо зависимостей. Если вы работаете в блокноте Google Colab, ссылка на общий доступ всегда создается автоматически. Обычно она выглядит примерно так: **XXXXX.gradio.app**. Хотя ссылка предоставляется через Gradio, мы являемся лишь прокси для вашего локального сервера и не храним никаких данных, передаваемых через интерфейсы. + +Однако не забывайте, что эти ссылки общедоступны, а значит, любой желающий может использовать вашу модель для прогнозирования! Поэтому не раскрывайте конфиденциальную информацию через написанные вами функции и не допускайте критических изменений на вашем устройстве. Если вы установите `share=False` (по умолчанию), будет создана только локальная ссылка. + +### Хостинг вашего демо на Hugging Face Spaces[[hosting-your-demo-on-hugging-face-spaces]] + +Ссылка на ресурс, которую можно передать коллегам, - это здорово, но как разместить демо на постоянном хостинге, чтобы оно существовало в своем собственном "пространстве (space)" в Интернете? + +Hugging Face Spaces предоставляет инфраструктуру для постоянного размещения вашей модели Gradio в интернете, **бесплатно**! Spaces позволяет вам создать и разместить в (публичном или частном) репозитории, +где ваш Gradio +код интерфейса будет существовать в файле `app.py`. [Прочитайте пошаговое руководство](https://huggingface.co/blog/gradio-spaces) чтобы начать работу, или посмотрите видео с примером ниже. + + + +## ✏️ Давайте применим это![[lets-apply-it]] + +Используя то, что мы узнали в предыдущих разделах, давайте создадим демо распознавания скетчей, которое мы видели в [первом разделе этой главы](../chapter9/1). Давайте добавим некоторые настройки в наш интерфейс и установим `share=True`, чтобы создать публичную ссылку, которую мы сможем передавать всем желающим. + +Мы можем загрузить метки из файла [class_names.txt](https://huggingface.co/spaces/dawood/Sketch-Recognition/blob/main/class_names.txt) и загрузить предварительно обученную модель pytorch из файла [pytorch_model.bin](https://huggingface.co/spaces/dawood/Sketch-Recognition/blob/main/pytorch_model.bin). Загрузите эти файлы, перейдя по ссылке и нажав кнопку загрузки в левом верхнем углу окна предварительного просмотра файла. Давайте посмотрим на приведенный ниже код, чтобы увидеть, как мы используем эти файлы для загрузки нашей модели и создания функции `predict()`: +```py +from pathlib import Path +import torch +import gradio as gr +from torch import nn + +LABELS = Path("class_names.txt").read_text().splitlines() + +model = nn.Sequential( + nn.Conv2d(1, 32, 3, padding="same"), + nn.ReLU(), + nn.MaxPool2d(2), + nn.Conv2d(32, 64, 3, padding="same"), + nn.ReLU(), + nn.MaxPool2d(2), + nn.Conv2d(64, 128, 3, padding="same"), + nn.ReLU(), + nn.MaxPool2d(2), + nn.Flatten(), + nn.Linear(1152, 256), + nn.ReLU(), + nn.Linear(256, len(LABELS)), +) +state_dict = torch.load("pytorch_model.bin", map_location="cpu") +model.load_state_dict(state_dict, strict=False) +model.eval() + + +def predict(im): + x = torch.tensor(im, dtype=torch.float32).unsqueeze(0).unsqueeze(0) / 255.0 + with torch.no_grad(): + out = model(x) + probabilities = torch.nn.functional.softmax(out[0], dim=0) + values, indices = torch.topk(probabilities, 5) + return {LABELS[i]: v.item() for i, v in zip(indices, values)} +``` + +Теперь у нас есть функция `predict()`. Следующим шагом будет определение и запуск нашего интерфейса Gradio: + +```py +interface = gr.Interface( + predict, + inputs="sketchpad", + outputs="label", + theme="huggingface", + title="Sketch Recognition", + description="Who wants to play Pictionary? Draw a common object like a shovel or a laptop, and the algorithm will guess in real time!", + article="

Sketch Recognition | Demo Model

", + live=True, +) +interface.launch(share=True) +``` + + + + +Обратите внимание на параметр `live=True` в `Interface`, который означает, что демо скетча делает +предсказание каждый раз, когда кто-то рисует на скетчпаде (без кнопки "Исполнить (submit)"!). + +Кроме того, мы также установили аргумент `share=True` в методе `launch()`. +Это создаст общедоступную ссылку, которую вы можете +отправить кому угодно! Когда вы отправите эту ссылку, пользователь на другой стороне сможет опробовать +модель распознавания эскизов. Повторим, что модель также можно разместить на Hugging Face Spaces, +именно так мы и разместили демо выше. + +Далее мы расскажем о других способах использования Gradio в экосистеме Hugging Face! \ No newline at end of file diff --git a/chapters/ru/chapter9/5.mdx b/chapters/ru/chapter9/5.mdx new file mode 100644 index 000000000..8e180118d --- /dev/null +++ b/chapters/ru/chapter9/5.mdx @@ -0,0 +1,67 @@ +# Интеграция с Hugging Face Hub[[integrations-with-the-hugging-face-hub]] + + + +Чтобы сделать вашу жизнь еще проще, Gradio напрямую интегрируется с Hugging Face Hub и Hugging Face Spaces. +Вы можете загружать демо из Hub и Spaces, используя всего *одну строку кода*. + +### Загрузка моделей из Hugging Face Hub[[loading-models-from-the-hugging-face-hub]] +Для начала выберите одну из тысяч моделей, которые Hugging Face предлагает в Hub, как описано в [Главе 4](../chapter4/2). + +Используя специальный метод `Interface.load()`, вы передаете `"model/"` (или, эквивалентно, `"huggingface/"`) +после чего следует имя модели. +Например, здесь приведен код для создания демо для [GPT-J](https://huggingface.co/EleutherAI/gpt-j-6B), большой языковой модели, добавьте пару примеров ввода: + +```py +import gradio as gr + +title = "GPT-J-6B" +description = "Gradio Demo for GPT-J 6B, a transformer model trained using Ben Wang's Mesh Transformer JAX. 'GPT-J' refers to the class of model, while '6B' represents the number of trainable parameters. To use it, simply add your text, or click one of the examples to load them. Read more at the links below." +article = "

GPT-J-6B: A 6 Billion Parameter Autoregressive Language Model

" + +gr.Interface.load( + "huggingface/EleutherAI/gpt-j-6B", + inputs=gr.Textbox(lines=5, label="Input Text"), + title=title, + description=description, + article=article, +).launch() +``` + +Код, приведенный выше, приведет к созданию интерфейса, представленного ниже: + + + +Загрузка модели таким образом использует [Inference API](https://huggingface.co/inference-api) Hugging Face, +вместо того, чтобы загружать модель в память. Это идеально подходит для огромных моделей, таких как GPT-J или T0pp, которые + которые требуют много RAM. + +### Загрузка с Hugging Face Spaces[[loading-from-hugging-face-spaces]] +Чтобы загрузить любое пространство (Space) из Hugging Face Hub и воссоздать его локально, вы можете передать `spaces/` в `Interface`, за которым следует имя пространства. + +Помните демо из раздела 1, которое удаляет фон изображения? Давайте загрузим его из Hugging Face Spaces: + +```py +gr.Interface.load("spaces/abidlabs/remove-bg").launch() +``` + + + +Одна из особенностей загрузки демо из Hub или Spaces заключается в том, что вы можете настраивать их +переопределив любой из +параметров. Здесь мы добавим заголовок и задействуем веб-камеру: + +```py +gr.Interface.load( + "spaces/abidlabs/remove-bg", inputs="webcam", title="Remove your webcam background!" +).launch() +``` + + + +Теперь, когда мы изучили несколько способов интеграции Gradio с Hugging Face Hub, давайте рассмотрим некоторые дополнительные возможности класса `Interface`. Этому будет посвящен следующий раздел! \ No newline at end of file diff --git a/chapters/ru/chapter9/6.mdx b/chapters/ru/chapter9/6.mdx new file mode 100644 index 000000000..7380593aa --- /dev/null +++ b/chapters/ru/chapter9/6.mdx @@ -0,0 +1,101 @@ +# Расширенные возможности Interface[[advanced-interface-features]] + + + +Теперь, когда мы можем создать базовый интерфейс и поделиться им, давайте изучим некоторые более продвинутые возможности, такие как состояние и интерпретации. + +### Использование состояния для сохранения данных[[using-state-to-persist-data]] + +Gradio поддерживает *состояние сеанса*, когда данные сохраняются при нескольких отправках в рамках +загруженной страницы. Состояние сессии полезно для создания демо, например, чат-ботов, где необходимо +сохранять данные по мере того, как пользователь взаимодействует с моделью. Обратите внимание, что состояние сессии не позволяет обмениваться данными между разными пользователями вашей модели. + +Чтобы хранить данные о состоянии сеанса, необходимо выполнить три действия: + +1. Передайте в вашу функцию *дополнительный параметр*, который представляет собой состояние интерфейса. +2. В завершении работы функции верните обновленное значение состояния в качестве *дополнительного возвращаемого значения*. +3. Добавьте входной компонент 'state' и выходной компонент 'state' при создании вашего `Interface`. + +Посмотрите пример чатбота ниже: + +```py +import random + +import gradio as gr + + +def chat(message, history): + history = history or [] + if message.startswith("How many"): + response = random.randint(1, 10) + elif message.startswith("How"): + response = random.choice(["Great", "Good", "Okay", "Bad"]) + elif message.startswith("Where"): + response = random.choice(["Here", "There", "Somewhere"]) + else: + response = "I don't know" + history.append((message, response)) + return history, history + + +iface = gr.Interface( + chat, + ["text", "state"], + ["chatbot", "state"], + allow_screenshot=False, + allow_flagging="never", +) +iface.launch() +``` + + + +Обратите внимание, что состояние выходного компонента сохраняется при всех отправках данных. +Примечание: в параметр state можно передать значение по умолчанию, +которое используется в качестве начального значения состояния. + +### Использование интерпретации для понимания прогнозов[[using-interpretation-to-understand-predictions]] + +Большинство моделей машинного обучения представляют собой "черные ящики", и внутренняя логика функции скрыта от конечного пользователя. Чтобы стимулировать прозрачность, мы упростили добавление интерпретации в вашу модель, просто задав ключевое слово interpretation в классе Interface по умолчанию. Это позволит вашим пользователям понять, какие части входных данных отвечают за вывод. Взгляните на простой интерфейс ниже, который показывает классификатор изображений, также включающий интерпретацию: + +```py +import requests +import tensorflow as tf + +import gradio as gr + +inception_net = tf.keras.applications.MobileNetV2() # load the model + +# Загрузим человекочитаемые метки для ImageNet. +response = requests.get("https://git.io/JJkYN") +labels = response.text.split("\n") + + +def classify_image(inp): + inp = inp.reshape((-1, 224, 224, 3)) + inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp) + prediction = inception_net.predict(inp).flatten() + return {labels[i]: float(prediction[i]) for i in range(1000)} + + +image = gr.Image(shape=(224, 224)) +label = gr.Label(num_top_classes=3) + +title = "Gradio Image Classifiction + Interpretation Example" +gr.Interface( + fn=classify_image, inputs=image, outputs=label, interpretation="default", title=title +).launch() +``` + +Проверьте функцию интерпретации, отправив входные данные и нажав кнопку Интерпретировать (Interpret) под компонентом вывода. + + + +Помимо метода интерпретации, предоставляемого Gradio по умолчанию, вы также можете задать `shap` для параметра `interpretation` и установить параметр `num_shap`. При этом используется интерпретация на основе Шэпли, о которой вы можете подробнее прочитать [здесь](https://christophm.github.io/interpretable-ml-book/shap.html). Наконец, в параметр `interpretation` можно передать собственную функцию интерпретации. Пример можно посмотреть на странице Gradio, посвященной началу работы [здесь](https://gradio.app/getting_started/). + +На этом мы завершаем наше глубокое погружение в класс `Interface` в Gradio. Как мы уже видели, этот класс позволяет создавать демо машинного обучения в несколько строк кода на Python. Однако иногда возникает необходимость доработать демо, изменив его макет или соединив несколько функций предсказания в цепочку. Было бы здорово, если бы мы могли как-то разделить `Interface` на настраиваемые "блоки"? К счастью, такая возможность есть! Этой теме посвящен последний раздел. \ No newline at end of file diff --git a/chapters/ru/chapter9/7.mdx b/chapters/ru/chapter9/7.mdx new file mode 100644 index 000000000..73cc38a25 --- /dev/null +++ b/chapters/ru/chapter9/7.mdx @@ -0,0 +1,236 @@ +# Введение в Gradio Blocks[[introduction-to-gradio-blocks]] + + + +В предыдущих разделах мы изучили и создали демо, используя класс `Interface`. В этом разделе мы представим наш **свеже разработанный** низкоуровневый API под названием `gradio.Blocks`. + +Итак, в чем разница между `Interface` и `Blocks`? + +- ⚡ `Interface`: высокоуровневый API, который позволяет создать полноценное демо машинного обучения, просто предоставив список входных и выходных данных. + +- 🧱 `Blocks`: низкоуровневый API, который позволяет вам полностью контролировать потоки данных и компоновку вашего приложения. Вы можете создавать очень сложные, многоступенчатые приложения, используя `Blocks` (как "строительные блоки"). + + +### Почему Blocks 🧱?[[why-blocks-]] + +Как мы видели в предыдущих разделах, класс `Interface` позволяет легко создавать полноценные демо машинного обучения с помощью всего нескольких строк кода. API `Interface` чрезвычайно прост в использовании, но ему не хватает гибкости, которую обеспечивает API `Blocks`. Например, вы можете захотеть: + +- Сгруппировать связанные демо в виде нескольких вкладок в одном веб-приложении +- Изменить макет вашего демо, например, указать, где расположены входные и выходные компоненты +- Многоступенчатые интерфейсы, в которых выход одной модели становится входом для следующей модели, или более гибкие потоки данных в целом +- Изменить свойства компонента (например, выбор в выпадающем списке) или его видимость на основе пользовательского ввода + +Ниже мы рассмотрим все эти понятия. + +### Создание простого демо с помощью блоков[[creating-a-simple-demo-using-blocks]] + +После того как вы установили Gradio, запустите приведенный ниже код в виде сценария на Python, блокнота Jupyter или блокнота Colab. + +```py +import gradio as gr + + +def flip_text(x): + return x[::-1] + + +demo = gr.Blocks() + +with demo: + gr.Markdown( + """ + # Flip Text! + Start typing below to see the output. + """ + ) + input = gr.Textbox(placeholder="Flip this text") + output = gr.Textbox() + + input.change(fn=flip_text, inputs=input, outputs=output) + +demo.launch() +``` + + + +В этом простом примере представлены 4 концепции, которые лежат в основе блоков: + +1. Блоки позволяют создавать веб-приложения, сочетающие в себе разметку, HTML, кнопки и интерактивные компоненты, просто инстанцируя объекты на Python в контексте `with gradio.Blocks`. + +🙋Если вы не знакомы с оператором `with` в Python, рекомендуем ознакомиться с отличным [руководством](https://realpython.com/python-with-statement/) от Real Python. Возвращайтесь сюда после его прочтения 🤗 + +Порядок, в котором вы инстанцируете компоненты, имеет значение, поскольку каждый элемент отображается в веб-приложении в том порядке, в котором он был создан. (Более сложные макеты рассматриваются ниже) + +2. Вы можете определять обычные функции Python в любом месте вашего кода и запускать их с пользовательским вводом с помощью `Blocks`. В нашем примере мы используем простую функцию, которая "переворачивает" введенный текст, но вы можете написать любую функцию Python, от простого вычисления до обработки прогнозов модели машинного обучения. + +3. Вы можете назначить события для любого компонента `Blocks`. Это позволит запускать вашу функцию при нажатии на компонент, его изменении и т. д. Когда вы назначаете событие, вы передаете три параметра: `fn`: функция, которая должна быть вызвана, `inputs`: (список) входных компонентов, и `outputs`: (список) выходных компонентов, которые должны быть вызваны. + + В примере выше мы запускаем функцию `flip_text()`, когда значение в `Textbox` с названием `input` изменяется. Событие считывает значение в `input`, передает его в качестве именнованного параметра в `flip_text()`, которая затем возвращает значение, которое присваивается нашему второму `Textbox` с именем `output`. + + Список событий, которые поддерживает каждый компонент, можно найти в [документации Gradio](https://www.gradio.app/docs/). + +4. Блоки автоматически определяют, должен ли компонент быть интерактивным (принимать пользовательский ввод) или нет, основываясь на определенных вами триггерах событий. В нашем примере первый textbox является интерактивным, поскольку его значение используется функцией `flip_text()`. Второй textbox не является интерактивным, поскольку его значение никогда не используется в качестве входа. В некоторых случаях вы можете переопределить это, передав булево значение в параметр `interactive` компонента (например, `gr.Textbox(placeholder="Flip this text", interactive=True)`). + +### Настройка макета вашего демо[[customizing-the-layout-of-your-demo]] + +Как мы можем использовать `Blocks` для настройки макета нашего демо? По умолчанию `Blocks` отображает созданные вами компоненты вертикально в одной колонке. Вы можете изменить это, создав дополнительные колонки `с помощью gradio.Column():` или строки `с помощью gradio.Row():` и создав компоненты в этих контекстах. + +Вот что следует иметь в виду: все компоненты, созданные в `Column` (это также значение по умолчанию), будут располагаться вертикально. Любой компонент, созданный в `Row`, будет располагаться горизонтально, аналогично [модели flexbox в веб-разработке](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox). + +Наконец, вы можете создавать вкладки для демо с помощью контекстного менеджера `with gradio.Tabs()`. В этом контексте вы можете создать несколько вкладок, указав дочерние вкладки в `with gradio.TabItem(name_of_tab):` . Любой компонент, созданный внутри контекста `with gradio.TabItem(name_of_tab):`, отображается на этой вкладке. + +Теперь давайте добавим функцию `flip_image()` в наше демо и добавим новую вкладку, которая будет переворачивать изображения. Ниже приведен пример с 2 вкладками, в котором также используется Row: + +```py +import numpy as np +import gradio as gr + +demo = gr.Blocks() + + +def flip_text(x): + return x[::-1] + + +def flip_image(x): + return np.fliplr(x) + + +with demo: + gr.Markdown("Flip text or image files using this demo.") + with gr.Tabs(): + with gr.TabItem("Flip Text"): + with gr.Row(): + text_input = gr.Textbox() + text_output = gr.Textbox() + text_button = gr.Button("Flip") + with gr.TabItem("Flip Image"): + with gr.Row(): + image_input = gr.Image() + image_output = gr.Image() + image_button = gr.Button("Flip") + + text_button.click(flip_text, inputs=text_input, outputs=text_output) + image_button.click(flip_image, inputs=image_input, outputs=image_output) + +demo.launch() +``` + + + + +Вы заметите, что в этом примере мы также создали компонент `Button` на каждой вкладке и назначили событие click для каждой кнопки, что, собственно, и запускает функцию. + +### Изучение событий и состояния[[exploring-events-and-state]] + +Так же, как вы можете управлять макетом, `Blocks` дает вам тонкий контроль над тем, какие события вызывают вызовы функций. Каждый компонент и многие макеты имеют определенные события, которые они поддерживают. + +Например, у компонента `Textbox` есть 2 события: `change()` (когда меняется значение внутри текстового поля) и `submit()` (когда пользователь нажимает клавишу ввода, будучи сфокусированным на текстовом поле). Более сложные компоненты могут иметь еще больше событий: например, компонент `Audio` также имеет отдельные события для воспроизведения аудиофайла, очистки, приостановки и так далее. О том, какие события поддерживает каждый компонент, читайте в документации. + +Вы можете прикрепить триггер события ни к одному, одному или нескольким из этих событий. Вы создаете триггер события, вызывая имя события на экземпляре компонента в виде функции - например, `textbox.change(...)` или `btn.click(...)`. Функция принимает три параметра, как говорилось выше: + +- `fn`: функция для выполнения +- `inputs`: (список (list)) компонент(ов), значения которых должны быть переданы в качестве входных параметров функции. Значение каждого компонента по порядку сопоставляется с соответствующим параметром функции. Этот параметр может иметь значение None, если функция не принимает никаких параметров. +- `outputs`: (список (list)) компонентов, значения которых должны быть обновлены на основе значений, возвращаемых функцией. Каждое возвращаемое значение устанавливает значение соответствующего компонента по порядку. Этот параметр может быть None, если функция ничего не возвращает. + +Вы даже можете сделать так, чтобы компонент ввода и компонент вывода были одним и тем же компонентом, как это сделано в данном примере, где используется модель GPT для дополнения текста: + +```py +import gradio as gr + +api = gr.Interface.load("huggingface/EleutherAI/gpt-j-6B") + + +def complete_with_gpt(text): + # Используем последние 50 символов текста в качестве контекста + return text[:-50] + api(text[-50:]) + + +with gr.Blocks() as demo: + textbox = gr.Textbox(placeholder="Type here and press enter...", lines=4) + btn = gr.Button("Generate") + + btn.click(complete_with_gpt, textbox, textbox) + +demo.launch() +``` + + + +### Создание многоступенчатых демо[[creating-multi-step-demos]] + +В некоторых случаях вам может понадобиться _многоступенчатое демо_, в котором вы повторно используете выход одной функции в качестве входа для следующей. Это очень легко сделать с помощью `Blocks`, так как вы можете использовать компонент в качестве входа для одного триггера события, но выхода для другого. Посмотрите на компонент text в примере ниже: его значение является результатом работы модели преобразования речи в текст, но также передается в модель анализа настроений: + +```py +from transformers import pipeline + +import gradio as gr + +asr = pipeline("automatic-speech-recognition", "facebook/wav2vec2-base-960h") +classifier = pipeline("text-classification") + + +def speech_to_text(speech): + text = asr(speech)["text"] + return text + + +def text_to_sentiment(text): + return classifier(text)[0]["label"] + + +demo = gr.Blocks() + +with demo: + audio_file = gr.Audio(type="filepath") + text = gr.Textbox() + label = gr.Label() + + b1 = gr.Button("Recognize Speech") + b2 = gr.Button("Classify Sentiment") + + b1.click(speech_to_text, inputs=audio_file, outputs=text) + b2.click(text_to_sentiment, inputs=text, outputs=label) + +demo.launch() +``` + + + +### Обновление свойств компонента[[updating-component-properties]] + +До сих пор мы видели, как создавать события для обновления значения другого компонента. Но что делать, если вы хотите изменить другие свойства компонента, например видимость текстового поля или варианты выбора в группе радио кнопок? Вы можете сделать это, вернув метод класса компонента `update()` вместо обычного возвращаемого значения из вашей функции. + +Это легче всего проиллюстрировать на примере: + +```py +import gradio as gr + + +def change_textbox(choice): + if choice == "short": + return gr.Textbox.update(lines=2, visible=True) + elif choice == "long": + return gr.Textbox.update(lines=8, visible=True) + else: + return gr.Textbox.update(visible=False) + + +with gr.Blocks() as block: + radio = gr.Radio( + ["short", "long", "none"], label="What kind of essay would you like to write?" + ) + text = gr.Textbox(lines=2, interactive=True) + + radio.change(fn=change_textbox, inputs=radio, outputs=text) + block.launch() +``` + + + +Мы только что изучили все основные концепции `Blocks`! Как и в случае с `Interfaces`, вы можете создавать классные демо, которыми можно поделиться, используя `share=True` в методе `launch()` или развернуть на [Hugging Face Spaces](https://huggingface.co/spaces). \ No newline at end of file diff --git a/chapters/ru/chapter9/8.mdx b/chapters/ru/chapter9/8.mdx new file mode 100644 index 000000000..179e3eee0 --- /dev/null +++ b/chapters/ru/chapter9/8.mdx @@ -0,0 +1,24 @@ +# Gradio, проверка![[gradio-check]] + + + +На этом мы завершаем главу о создании классных демо на основе ML с помощью Gradio - надеемся, вам понравилось! Напомним, что в этой главе мы узнали: + +- Как создавать демо Gradio с помощью высокоуровневого API `Interface` и как настраивать различные модальности ввода и вывода. +- Различные способы поделиться демо Gradio, с помощью временных ссылок и хостинга на [Hugging Face Spaces](https://huggingface.co/spaces). +- Как интегрировать демо Gradio с моделями и Spaces на Hugging Face Hub. +- Расширенные возможности, такие как хранение состояния в демо или обеспечение аутентификации. +- Как получить полный контроль над потоком данных и макетом демо с помощью Gradio Blocks. + +Если вы хотите проверить свое понимание концепций, рассмотренных в этой главе, пройдите тест в следующем разделе! + +## Что дальше?[[where-to-next]] + +Если вы хотите узнать больше о Gradio, вы можете + +- Взглянуть на [Demo](https://github.com/gradio-app/gradio/tree/main/demo) репозиторий, там довольно много примеров. +- Посмотреть страницу [Guides](https://gradio.app/guides/), где вы можете найти руководства о крутых и продвинутых функциях. +- Заглянуть на страницу [Docs](https://gradio.app/docs/), чтобы узнать детали. diff --git a/chapters/ru/chapter9/9.mdx b/chapters/ru/chapter9/9.mdx new file mode 100644 index 000000000..74ce11f5d --- /dev/null +++ b/chapters/ru/chapter9/9.mdx @@ -0,0 +1,239 @@ + + +# Тест в конце главы[[end-of-chapter-quiz]] + + + +Давайте проверим, чему вы научились в этой главе! + +### 1. Для чего можно использовать Gradio? + +share=True в методе запуска, вы можете сгенерировать ссылку для общего доступа, чтобы отправить ее всем желающим.", + correct: true + }, + { + text: "Отладка вашей модели", + explain: "Одно из преимуществ демо Gradio - возможность протестировать модель на реальных данных, которые можно изменять и наблюдать за изменением прогнозов модели в режиме реального времени, что поможет вам отладить модель.", + correct: true + }, + { + text: "Обучить вашу модель", + explain: "Gradio разработана для инференса модели, ПОСЛЕ того как модель обучена.", + } + ]} +/> + +### 2. Gradio работает ТОЛЬКО с моделями PyTorch + + + +### 3. Где можно запустить демо Gradio? + + + +### 4. Gradio предназначен в первую очередь для моделей NLP + + + +### 5. Какие из следующих функций поддерживаются Gradio? + +gr.Interface.load().", + correct: true + } + ]} +/> + +### 6. Какие из следующих способов загрузки модели Hugging Face из Hub или Spaces являются правильными? + + + +### 7. Выберите все шаги, необходимые для добавления состояния в интерфейс Gradio + + + +### 8. Какие из перечисленных ниже компонентов входят в библиотеку Gradio? + + + +### 9. Что позволяет делать Gradio `Blocks`? + + + +### 10. Вы можете поделиться публичной ссылкой на демо `Blocks` и разместить демо `Blocks` в пространстве Hugging Face. + + \ No newline at end of file diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx new file mode 100644 index 000000000..69e8ca9f2 --- /dev/null +++ b/chapters/ru/events/1.mdx @@ -0,0 +1,48 @@ +# Занятия и семинары[[live-sessions-and-workshops]] + +В связи с выходом первой и второй частей курса мы организовали несколько занятий и семинаров по программированию. Ссылки на записи этих сессий и семинаров вы можете найти ниже. + +## Занятия по программированию[[live-coding-sessions]] + +На первом занятии Сильвен вместе с вами изучит Главу 1 курса, объясняя ее шаг за шагом: + +
+ +
+ +На втором занятии настал черед Льюиса представить главу 2: + +
+ +
+ +Поскольку Глава 2 настолько классная, Сильвен также сделал видео к ней! + +
+ +
+ +В Главе 3 Льюис возвращается, чтобы обьяснить вам код: + +
+ +
+ +Наконец, Омар завершает занятия, связанные с первой частью курса, рассмотрением главы 4: + +
+ +
+ +## Семинары[[workshops]] +На первом семинаре Мерве приглашает Льюиса обсудить раздел 7 главы 7, посвященный задаче [ответа на вопросы](https://huggingface.co/learn/nlp-course/ru/chapter7/7). + +
+ +
+ +На втором семинаре Мерве приглашает Леандро рассказать о 6 разделе 7 главы, посвященном [обучению каузальной языковой модели с нуля](https://huggingface.co/learn/nlp-course/ru/chapter7/6) и приложению [CodeParrot](https://huggingface.co/codeparrot). + +
+ +
diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx new file mode 100644 index 000000000..f26f60c81 --- /dev/null +++ b/chapters/ru/events/2.mdx @@ -0,0 +1,165 @@ +# Событие посвященное выходу 2 части курса[[part-2-release-event]] + +В связи с выходом второй части курса мы организовали живую встречу с двумя днями выступлений перед спринтом по доработке. Если вы пропустили это мероприятие, вы можете просмотреть все выступления, которые перечислены ниже! + +## День 1: Высокоуровневое представление о трансформерах и о том, как их обучать[[day-1-a-high-level-view-of-transformers-and-how-to-train-them]] + +**Томас Вульф:** *Трансферное обучение и рождение библиотеки Transformers* + +
+ +
+ +

+A visual summary of Thom's talk +

+ +Томас Вольф - соучредитель и главный научный директор компании Hugging Face. Инструменты, созданные Томасом Вольфом и командой Hugging Face, используются более чем в 5 000 исследовательских организаций, включая Facebook Artificial Intelligence Research, Google Research, DeepMind, Amazon Research, Apple, Институт искусственного интеллекта Аллена, а также большинство университетских факультетов. Томас Вольф является инициатором и старшим председателем крупнейшей исследовательской коллаборации, когда-либо существовавшей в области искусственного интеллекта: ["BigScience"](https://bigscience.huggingface.co), а также набора широко используемых [библиотек и инструментов](https://github.com/huggingface/). Томас Вольф также является активным преподавателем, идейным лидером в области искусственного интеллекта и обработки естественного языка и постоянным приглашенным докладчиком на конференциях по всему миру [https://thomwolf.io](https://thomwolf.io). + +**Джей Аламмар:** *Легкое визуальное введение в модели трансформеры* + +
+ +
+ +

+A visual summary of Jay's talk +

+ +Благодаря своему популярному блогу Джей помог миллионам исследователей и инженеров наглядно понять инструменты и концепции машинного обучения - от базовых (заканчивая документами по NumPy, Pandas) до самых современных (Transformers, BERT, GPT-3). + +**Маргарет Митчелл:** *О ценностях в разработке ML* + +
+ +
+ +

+A visual summary of Margaret's talk +

+ +Маргарет Митчелл - исследователь, работающий в области этики ИИ. В настоящее время она занимается вопросами разработки ИИ с учетом этических норм в технологиях. Она опубликовала более 50 работ по генерации естественного языка, ассистивным технологиям, компьютерному зрению и этике ИИ, а также имеет множество патентов в области генерации диалогов и классификации настроений. Ранее она работала в Google AI в качестве штатного научного сотрудника, где основала и возглавила группу Google Ethical AI, которая занималась фундаментальными исследованиями в области этики ИИ и операционализацией этики ИИ внутри Google. До прихода в Google она работала исследователем в Microsoft Research, занимаясь вопросами создания компьютерного зрения и языка, а также была постдокторантом в Университете Джонса Хопкинса, занимаясь байесовским моделированием и извлечением информации. Она получила докторскую степень в области компьютерных наук в Абердинском университете и степень магистра в области вычислительной лингвистики в Вашингтонском университете. В период с 2005 по 2012 год она также работала в области машинного обучения, неврологических расстройств и вспомогательных технологий в Орегонском университете здоровья и науки. Она была инициатором ряда семинаров и инициатив на пересечении многообразия, инклюзивности, компьютерных наук и этики. Ее работа была отмечена наградами министра обороны Эша Картера и Американского фонда поддержки слепых, а также была внедрена несколькими технологическими компаниями. Она любит садоводство, собак и кошек. + +**Мэттью Уотсон и Чэнь Цянь:** *Рабочие процессы NLP с Keras* + +
+ +
+ +

+A visual summary of Matt and Chen's talk +

+ +Мэтью Уотсон - инженер по машинному обучению в команде Keras, специализирующийся на высокоуровневых API для моделирования. Он изучал компьютерную графику в бакалавриате и получил степень магистра в Стэнфордском университете. Получив английское образование, он выбрал компьютерную науку, но очень любит работать с разными дисциплинами и делать NLP доступным для широкой аудитории. + +Чен Цянь - инженер-программист из команды Keras, специализирующийся на высокоуровневых API для моделирования. Чен получил степень магистра электротехники в Стэнфордском университете и особенно интересуется упрощением имплементации в коде задач ML и крупномасштабным ML проектов. + +**Марк Саруфим:** *Как обучить модель с помощью Pytorch* + +
+ +
+ +

+A visual summary of Mark's talk +

+ +Марк Саруфим - инженер-партнер компании Pytorch, работающий над производственными инструментами OSS, включая TorchServe и Pytorch Enterprise. В прошлом Марк был прикладным ученым и менеджером по продуктам в Graphcore, [yuri.ai](http://yuri.ai/), Microsoft и NASA's JPL. Его главная страсть - сделать программирование более увлекательным. + +**Якоб Ушкорейт:** *Не сломалось, так не чини! Давай сломаем)* + +
+ +
+ +

+A visual summary of Jakob's talk +

+ +Якоб Ушкорейт - соучредитель компании Inceptive. Inceptive разрабатывает молекулы РНК для вакцин и терапевтических препаратов, используя крупномасштабное глубокое обучение в тесной связке с результативными экспериментами, с целью сделать лекарства на основе РНК более доступными, эффективными и широко применимыми. Ранее Якоб более десяти лет работал в Google, возглавляя группы исследований и разработок в Google Brain, Research and Search, работая над основами глубокого обучения, компьютерным зрением, пониманием языка и машинным переводом. + +## День 2: Инструменты, которые следует использовать[[day-2-the-tools-to-use]] + +**Льюис Танстолл:** *Простое обучение с 🤗 Transformers Trainer* + +
+ +
+ +Льюис - инженер по машинному обучению в компании Hugging Face, занимающейся разработкой инструментов с открытым исходным кодом и делающий их доступными для широкого круга пользователей. Он также является соавтором книги O'Reilly [Natural Language Processing with Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/). Вы можете следовать за ним в Twitter (@_lewtun) для получения советов и рекомендаций по NLP! + +**Мэтью Кэрриган:** *Новые функции TensorFlow для 🤗 Transformers и 🤗 Datasets* + +
+ +
+ +Мэтт отвечает за поддержку TensorFlow в Transformers и в конечном итоге возглавит переворот против действующей фракции PyTorch, который, вероятно, будет координироваться через его аккаунт в Twitter @carrigmat. + +**Дебют Лисандра:** *Hugging Face Hub как средство для совместной работы и обмена проектами по машинному обучению* + +
+ +
+ +

+A visual summary of Lysandre's talk +

+ +Лисандр - инженер по машинному обучению в компании Hugging Face, где он участвует во многих проектах с открытым исходным кодом. Его цель - сделать машинное обучение доступным для всех, разрабатывая мощные инструменты с очень простым API. + +**Люсиль Сольнье:** *Получите свой собственный токенизатор с помощью 🤗 Transformers & 🤗 Tokenizers* + +
+ +
+ +Люсиль - инженер по машинному обучению в компании Hugging Face, занимается разработкой и поддержкой использования инструментов с открытым исходным кодом. Она также активно участвует во многих исследовательских проектах в области обработки естественного языка, таких как коллаборативное обучение и BigScience. + +**Сильвен Гуггер:** *Ускорьте цикл обучения PyTorch с помощью 🤗 Accelerate* + +
+ +
+ +Сильвен - инженер-исследователь в Hugging Face, один из основных сопровождающих 🤗 Transformers и разработчик 🤗 Accelerate. Ему нравится делать обучение моделей более доступным. + +**Мерве Ноян:** *Демонстрируйте свои демо моделей с помощью 🤗 Spaces* + +
+ +
+ +Мерве - сторонник разработчиков (developer advocate) в Hugging Face, занимается разработкой инструментов и созданием контента для них, чтобы сделать машинное обучение демократичным для всех. + +**Абубакар Абид:** *Быстрое создание приложений машинного обучения* + +
+ +
+ +

+A visual summary of Abubakar's talk +

+ +Абубакар Абид - CEO компании [Gradio](www.gradio.app). В 2015 году он получил степень бакалавра наук по электротехнике и информатике в Массачусетском технологическом институте, а в 2021 году - степень доктора наук по прикладному машинному обучению в Стэнфорде. В качестве генерального директора Gradio Абубакар работает над тем, чтобы облегчить демонстрацию, отладку и развертывание моделей машинного обучения. + +**Матье Десве:** *AWS ML Vision: Сделать машинное обучение доступным для всех пользователей* + +
+ +
+ +

+A visual summary of Mathieu's talk +

+ +Энтузиаст технологий, в свободное время занимаюсь творчеством. Мне нравятся задачи и решение проблем клиентов и пользователей, а также работа с талантливыми людьми, чтобы учиться каждый день. С 2004 года я работаю на разных должностях, начиная с фронтенда, бэкенда, инфраструктуры, заканчивая операциями и управлением. Стараюсь оперативно решать общие технические и управленческие вопросы. + +**Филипп Шмид:** *Управляемое обучение с Amazon SageMaker и 🤗 Transformers* + +
+ +
+ +Филипп Шмид - инженер по машинному обучению и технический руководитель в Hugging Face, где он возглавляет сотрудничество с командой Amazon SageMaker. Он увлечен демократизацией и производством передовых моделей NLP и повышением простоты использования Deep Learning. diff --git a/chapters/ru/events/3.mdx b/chapters/ru/events/3.mdx new file mode 100644 index 000000000..d65badcbc --- /dev/null +++ b/chapters/ru/events/3.mdx @@ -0,0 +1,9 @@ +# Вечеринка Gradio Blocks[[gradio-blocks-party]] + +Одновременно с выпуском главы курса Gradio компания Hugging Face провела мероприятие для сообщества, посвященное созданию крутых демо машинного обучения с помощью новой функции Gradio Blocks. + +Все демо, созданные сообществом, вы можете найти в организации [`Gradio-Blocks`](https://huggingface.co/Gradio-Blocks) на Hub. Вот несколько примеров от победителей: + +**Преобразование естественного языка в SQL** + + From e3edacb78c0d6e132b45f8202273e27d4d1f8ce6 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Wed, 31 Jan 2024 20:58:39 +0300 Subject: [PATCH 402/502] Added translation of chapter 9 and Course Events. --- .../_toctree-checkpoint.yml | 201 ------------------ 1 file changed, 201 deletions(-) delete mode 100644 chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml diff --git a/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml deleted file mode 100644 index c8364cc6d..000000000 --- a/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml +++ /dev/null @@ -1,201 +0,0 @@ -- title: 0. Setup - sections: - - local: chapter0/1 - title: Introduction - -- title: 1. Transformer models - sections: - - local: chapter1/1 - title: Introduction - - local: chapter1/2 - title: Natural Language Processing - - local: chapter1/3 - title: Transformers, what can they do? - - local: chapter1/4 - title: How do Transformers work? - - local: chapter1/5 - title: Encoder models - - local: chapter1/6 - title: Decoder models - - local: chapter1/7 - title: Sequence-to-sequence models - - local: chapter1/8 - title: Bias and limitations - - local: chapter1/9 - title: Summary - - local: chapter1/10 - title: End-of-chapter quiz - quiz: 1 - -- title: 2. Using 🤗 Transformers - sections: - - local: chapter2/1 - title: Introduction - - local: chapter2/2 - title: Behind the pipeline - - local: chapter2/3 - title: Models - - local: chapter2/4 - title: Tokenizers - - local: chapter2/5 - title: Handling multiple sequences - - local: chapter2/6 - title: Putting it all together - - local: chapter2/7 - title: Basic usage completed! - - local: chapter2/8 - title: End-of-chapter quiz - quiz: 2 - -- title: 3. Fine-tuning a pretrained model - sections: - - local: chapter3/1 - title: Introduction - - local: chapter3/2 - title: Processing the data - - local: chapter3/3 - title: Fine-tuning a model with the Trainer API or Keras - local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - - local: chapter3/4 - title: A full training - - local: chapter3/5 - title: Fine-tuning, Check! - - local: chapter3/6 - title: End-of-chapter quiz - quiz: 3 - -- title: 4. Sharing models and tokenizers - sections: - - local: chapter4/1 - title: The Hugging Face Hub - - local: chapter4/2 - title: Using pretrained models - - local: chapter4/3 - title: Sharing pretrained models - - local: chapter4/4 - title: Building a model card - - local: chapter4/5 - title: Part 1 completed! - - local: chapter4/6 - title: End-of-chapter quiz - quiz: 4 - -- title: 5. The 🤗 Datasets library - sections: - - local: chapter5/1 - title: Introduction - - local: chapter5/2 - title: What if my dataset isn't on the Hub? - - local: chapter5/3 - title: Time to slice and dice - - local: chapter5/4 - title: Big data? 🤗 Datasets to the rescue! - - local: chapter5/5 - title: Creating your own dataset - - local: chapter5/6 - title: Semantic search with FAISS - - local: chapter5/7 - title: 🤗 Datasets, check! - - local: chapter5/8 - title: End-of-chapter quiz - quiz: 5 - -- title: 6. The 🤗 Tokenizers library - sections: - - local: chapter6/1 - title: Introduction - - local: chapter6/2 - title: Training a new tokenizer from an old one - - local: chapter6/3 - title: Fast tokenizers' special powers - - local: chapter6/3b - title: Fast tokenizers in the QA pipeline - - local: chapter6/4 - title: Normalization and pre-tokenization - - local: chapter6/5 - title: Byte-Pair Encoding tokenization - - local: chapter6/6 - title: WordPiece tokenization - - local: chapter6/7 - title: Unigram tokenization - - local: chapter6/8 - title: Building a tokenizer, block by block - - local: chapter6/9 - title: Tokenizers, check! - - local: chapter6/10 - title: End-of-chapter quiz - quiz: 6 - -- title: 7. Main NLP tasks - sections: - - local: chapter7/1 - title: Introduction - - local: chapter7/2 - title: Token classification - - local: chapter7/3 - title: Fine-tuning a masked language model - - local: chapter7/4 - title: Translation - - local: chapter7/5 - title: Summarization - - local: chapter7/6 - title: Training a causal language model from scratch - - local: chapter7/7 - title: Question answering - - local: chapter7/8 - title: Mastering NLP - - local: chapter7/9 - title: End-of-chapter quiz - quiz: 7 - -- title: 8. How to ask for help - sections: - - local: chapter8/1 - title: Introduction - - local: chapter8/2 - title: What to do when you get an error - - local: chapter8/3 - title: Asking for help on the forums - - local: chapter8/4 - title: Debugging the training pipeline - local_fw: { pt: chapter8/4, tf: chapter8/4_tf } - - local: chapter8/5 - title: How to write a good issue - - local: chapter8/6 - title: Part 2 completed! - - local: chapter8/7 - title: End-of-chapter quiz - quiz: 8 - -- title: 9. Building and sharing demos - new: true - subtitle: I trained a model, but how can I show it off? - sections: - - local: chapter9/1 - title: Introduction to Gradio - - local: chapter9/2 - title: Building your first demo - - local: chapter9/3 - title: Understanding the Interface class - - local: chapter9/4 - title: Sharing demos with others - - local: chapter9/5 - title: Integrations with the Hugging Face Hub - - local: chapter9/6 - title: Advanced Interface features - - local: chapter9/7 - title: Introduction to Blocks - - local: chapter9/8 - title: Gradio, check! - - local: chapter9/9 - title: End-of-chapter quiz - quiz: 9 - -- title: Course Events - sections: - - local: events/1 - title: Live sessions and workshops - - local: events/2 - title: Part 2 release event - - local: events/3 - title: Gradio Blocks party From e819ed24f9829e0de5deb3513d27ac7cfdeb7ebf Mon Sep 17 00:00:00 2001 From: Yanis ALLOUCH <75087263+yanisallouch@users.noreply.github.com> Date: Thu, 1 Feb 2024 13:22:02 +0100 Subject: [PATCH 403/502] Update 5.mdx Fix typo --- chapters/fr/chapter6/5.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fr/chapter6/5.mdx b/chapters/fr/chapter6/5.mdx index 083a8fd8a..5c9108ba3 100644 --- a/chapters/fr/chapter6/5.mdx +++ b/chapters/fr/chapter6/5.mdx @@ -103,7 +103,7 @@ Le mot « bug » sera traduit par « ["b", "ug"] ». Par contre, le mot « mug -✏️ **A votre tour !** Comment pensez-vous que le mot « unhug » (détacher en français) sera tokenized ? +✏️ **A votre tour !** Comment pensez-vous que le mot « unhug » (détacher en français) sera tokenisé ? From 5b4e2bd1a62f1cc0632e7a6698d959ca200f574f Mon Sep 17 00:00:00 2001 From: Yanis ALLOUCH <75087263+yanisallouch@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:05:44 +0100 Subject: [PATCH 404/502] Update 7.mdx Fix typo --- chapters/fr/chapter6/7.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fr/chapter6/7.mdx b/chapters/fr/chapter6/7.mdx index 2240cc023..ab970d817 100644 --- a/chapters/fr/chapter6/7.mdx +++ b/chapters/fr/chapter6/7.mdx @@ -25,7 +25,7 @@ Comparé au BPE et *WordPiece*, *Unigram* fonctionne dans l'autre sens : il part À chaque étape de l'entraînement, l'algorithme *Unigram* calcule une perte sur le corpus compte tenu du vocabulaire actuel. Ensuite, pour chaque symbole du vocabulaire, l'algorithme calcule de combien la perte globale augmenterait si le symbole était supprimé et recherche les symboles qui l'augmenteraient le moins. Ces symboles ont un effet moindre sur la perte globale du corpus, ils sont donc en quelque sorte « moins nécessaires » et sont les meilleurs candidats à la suppression. -Comme il s'agit d'une opération très coûteuse, nous ne nous contentons pas de supprimer le symbole unique associé à la plus faible augmentation de la perte mais le \\(p\\) pourcent des symboles associés à la plus faible augmentation de la perte. \(p\\) est un hyperparamètre que vous pouvez contrôler, valant généralement 10 ou 20. Ce processus est ensuite répété jusqu'à ce que le vocabulaire ait atteint la taille souhaitée. +Comme il s'agit d'une opération très coûteuse, nous ne nous contentons pas de supprimer le symbole unique associé à la plus faible augmentation de la perte mais le \\(p\\) pourcent des symboles associés à la plus faible augmentation de la perte. \\(p\\) est un hyperparamètre que vous pouvez contrôler, valant généralement 10 ou 20. Ce processus est ensuite répété jusqu'à ce que le vocabulaire ait atteint la taille souhaitée. Notez que nous ne supprimons jamais les caractères de base, afin de nous assurer que tout mot peut être tokenisé. From 23c121be61dba46515df6299465d85fae8c07e03 Mon Sep 17 00:00:00 2001 From: Yanis ALLOUCH <75087263+yanisallouch@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:46:44 +0100 Subject: [PATCH 405/502] Update 10.mdx fix tpo --- chapters/fr/chapter6/10.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/fr/chapter6/10.mdx b/chapters/fr/chapter6/10.mdx index 4846966e4..66a5c11db 100644 --- a/chapters/fr/chapter6/10.mdx +++ b/chapters/fr/chapter6/10.mdx @@ -228,7 +228,7 @@ Testons ce que vous avez appris dans ce chapitre ! explain: "C'est la façon de faire d'un autre algorithme de tokenization." }, { - text: "WordPiece Les tokenizer apprennent les règles de fusion en fusionnant la paire de tokens la plus fréquente.", + text: "Les tokenizer WordPiece apprennent les règles de fusion en fusionnant la paire de tokens la plus fréquente.", explain: "C'est la façon de faire d'un autre algorithme de tokenization." }, { From 953d8ed8e37f5d2de78de42c39118226834a5120 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:06:32 +0300 Subject: [PATCH 406/502] Update chapters/ru/chapter9/6.mdx OK Co-authored-by: Maria Khalusova --- chapters/ru/chapter9/6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/chapter9/6.mdx b/chapters/ru/chapter9/6.mdx index 7380593aa..202e47b0f 100644 --- a/chapters/ru/chapter9/6.mdx +++ b/chapters/ru/chapter9/6.mdx @@ -69,7 +69,7 @@ import tensorflow as tf import gradio as gr -inception_net = tf.keras.applications.MobileNetV2() # load the model +inception_net = tf.keras.applications.MobileNetV2() # загрузим модель # Загрузим человекочитаемые метки для ImageNet. response = requests.get("https://git.io/JJkYN") From 2e98f098211f2c37cdfdcdd8fe90dd0e575acf3e Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:06:45 +0300 Subject: [PATCH 407/502] Update chapters/ru/chapter9/7.mdx OK Co-authored-by: Maria Khalusova --- chapters/ru/chapter9/7.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/chapters/ru/chapter9/7.mdx b/chapters/ru/chapter9/7.mdx index 73cc38a25..6da6a971a 100644 --- a/chapters/ru/chapter9/7.mdx +++ b/chapters/ru/chapter9/7.mdx @@ -61,6 +61,7 @@ demo.launch() В этом простом примере представлены 4 концепции, которые лежат в основе блоков: 1. Блоки позволяют создавать веб-приложения, сочетающие в себе разметку, HTML, кнопки и интерактивные компоненты, просто инстанцируя объекты на Python в контексте `with gradio.Blocks`. + 🙋Если вы не знакомы с оператором `with` в Python, рекомендуем ознакомиться с отличным [руководством](https://realpython.com/python-with-statement/) от Real Python. Возвращайтесь сюда после его прочтения 🤗 From 7c70c6b8080d0d717f8b3dd04e9d30fc76e27a97 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:07:19 +0300 Subject: [PATCH 408/502] Update chapters/ru/chapter9/7.mdx OK Co-authored-by: Maria Khalusova --- chapters/ru/chapter9/7.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chapters/ru/chapter9/7.mdx b/chapters/ru/chapter9/7.mdx index 6da6a971a..de0e1f8db 100644 --- a/chapters/ru/chapter9/7.mdx +++ b/chapters/ru/chapter9/7.mdx @@ -64,7 +64,9 @@ demo.launch() 🙋Если вы не знакомы с оператором `with` в Python, рекомендуем ознакомиться с отличным [руководством](https://realpython.com/python-with-statement/) от Real Python. Возвращайтесь сюда после его прочтения 🤗 + + Порядок, в котором вы инстанцируете компоненты, имеет значение, поскольку каждый элемент отображается в веб-приложении в том порядке, в котором он был создан. (Более сложные макеты рассматриваются ниже) 2. Вы можете определять обычные функции Python в любом месте вашего кода и запускать их с пользовательским вводом с помощью `Blocks`. В нашем примере мы используем простую функцию, которая "переворачивает" введенный текст, но вы можете написать любую функцию Python, от простого вычисления до обработки прогнозов модели машинного обучения. From aebdc91584c556f506d1aa20c0208182829ff2d3 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:08:11 +0300 Subject: [PATCH 409/502] Update chapters/ru/events/2.mdx I agree. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index f26f60c81..4624fe0a9 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -146,7 +146,6 @@ **Матье Десве:** *AWS ML Vision: Сделать машинное обучение доступным для всех пользователей* -
From 9742e7be88e7cf12cea9286b8164080094254dbe Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:14:03 +0300 Subject: [PATCH 410/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 69e8ca9f2..6dfa6f3df 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -6,7 +6,6 @@ На первом занятии Сильвен вместе с вами изучит Главу 1 курса, объясняя ее шаг за шагом: -
From 05114e93e0ea8ca9c68e10529e7f3c34e8626f6a Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:14:13 +0300 Subject: [PATCH 411/502] Update chapters/ru/events/2.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 4624fe0a9..5143471be 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -147,7 +147,6 @@ **Матье Десве:** *AWS ML Vision: Сделать машинное обучение доступным для всех пользователей* -

A visual summary of Mathieu's talk From 93c9387af2b21a91756fb1b55bed1309cc754f40 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:14:20 +0300 Subject: [PATCH 412/502] Update chapters/ru/events/2.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 5143471be..0781d3dd8 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -156,7 +156,6 @@ **Филипп Шмид:** *Управляемое обучение с Amazon SageMaker и 🤗 Transformers* -

From 7fe2432784a6ca61b916736cc690b8edd9ccd3e3 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:14:27 +0300 Subject: [PATCH 413/502] Update chapters/ru/events/2.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 0781d3dd8..1a90c9612 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -157,6 +157,5 @@ **Филипп Шмид:** *Управляемое обучение с Amazon SageMaker и 🤗 Transformers* -
Филипп Шмид - инженер по машинному обучению и технический руководитель в Hugging Face, где он возглавляет сотрудничество с командой Amazon SageMaker. Он увлечен демократизацией и производством передовых моделей NLP и повышением простоты использования Deep Learning. From 6a8abe00a78e5e4fdb5599d34c114a9849d9ed9e Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:15:47 +0300 Subject: [PATCH 414/502] Update chapters/ru/events/2.mdx Sorry. I was hasty and made an incorrect assumption))) Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 1a90c9612..cc198b9f8 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -96,7 +96,7 @@ Мэтт отвечает за поддержку TensorFlow в Transformers и в конечном итоге возглавит переворот против действующей фракции PyTorch, который, вероятно, будет координироваться через его аккаунт в Twitter @carrigmat. -**Дебют Лисандра:** *Hugging Face Hub как средство для совместной работы и обмена проектами по машинному обучению* +**Лисандр Дебю:** *Hugging Face Hub как средство для совместной работы и обмена проектами по машинному обучению*
From f1719b3cc358f7417477a06f4b8d178fcffadb02 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:16:17 +0300 Subject: [PATCH 415/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 6dfa6f3df..01b4c71d2 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -7,7 +7,6 @@ На первом занятии Сильвен вместе с вами изучит Главу 1 курса, объясняя ее шаг за шагом: -
На втором занятии настал черед Льюиса представить главу 2: From e87666acc844df197a33db424478966c8cc938dc Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:16:28 +0300 Subject: [PATCH 416/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 01b4c71d2..b0f9991ad 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -10,7 +10,6 @@ На втором занятии настал черед Льюиса представить главу 2: -
From 2bba21181a66be3c48f19856e2e1809456de76b1 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:16:50 +0300 Subject: [PATCH 417/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index b0f9991ad..9b11ac61f 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -11,7 +11,6 @@ На втором занятии настал черед Льюиса представить главу 2: -
Поскольку Глава 2 настолько классная, Сильвен также сделал видео к ней! From 2991db03e341836c693b4b098ce2cd3941eef092 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:17:11 +0300 Subject: [PATCH 418/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 9b11ac61f..8768fd06c 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -14,7 +14,6 @@ Поскольку Глава 2 настолько классная, Сильвен также сделал видео к ней! -
From d5551b8f977504f03e9fd770a371c4979d6a4894 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:18:06 +0300 Subject: [PATCH 419/502] Update chapters/ru/events/2.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index cc198b9f8..eba0324f7 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -136,7 +136,6 @@
-

A visual summary of Abubakar's talk From 9c0fce12daf872ccda8c74a3f3b51c2b25b8eecb Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:18:22 +0300 Subject: [PATCH 420/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 8768fd06c..baaad00d2 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -40,4 +40,3 @@

-
From b9eab043414638f4bab322da2691570d0b75e728 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:18:36 +0300 Subject: [PATCH 421/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index baaad00d2..14964cc6b 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -15,7 +15,6 @@ Поскольку Глава 2 настолько классная, Сильвен также сделал видео к ней! -
В Главе 3 Льюис возвращается, чтобы обьяснить вам код: From b289071ca7d225c73cafe992aad4627dffcc6380 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:18:57 +0300 Subject: [PATCH 422/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 14964cc6b..f6f770947 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -18,7 +18,6 @@ В Главе 3 Льюис возвращается, чтобы обьяснить вам код: -
From cc95da37aa55a3d24a004cac0f576343145b2e94 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:19:14 +0300 Subject: [PATCH 423/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index f6f770947..b6db3ac1a 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -19,7 +19,6 @@ В Главе 3 Льюис возвращается, чтобы обьяснить вам код: -
Наконец, Омар завершает занятия, связанные с первой частью курса, рассмотрением главы 4: From d48ca79bf97b50f34a73b46f6b10310dba2f16f9 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:19:25 +0300 Subject: [PATCH 424/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index b6db3ac1a..55d42bf28 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -22,7 +22,6 @@ Наконец, Омар завершает занятия, связанные с первой частью курса, рассмотрением главы 4: -
From 033ef13c1d0dabe6c99a7bfe3bd1121a8d4d7d6a Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:19:37 +0300 Subject: [PATCH 425/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 55d42bf28..704013cba 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -23,7 +23,6 @@ Наконец, Омар завершает занятия, связанные с первой частью курса, рассмотрением главы 4: - ## Семинары[[workshops]] На первом семинаре Мерве приглашает Льюиса обсудить раздел 7 главы 7, посвященный задаче [ответа на вопросы](https://huggingface.co/learn/nlp-course/ru/chapter7/7). From 4bf3abb4a2b1e929310ac7b029d4962dcb458644 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:19:56 +0300 Subject: [PATCH 426/502] Update chapters/ru/events/1.mdx I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 704013cba..25f861c66 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -27,7 +27,6 @@ ## Семинары[[workshops]] На первом семинаре Мерве приглашает Льюиса обсудить раздел 7 главы 7, посвященный задаче [ответа на вопросы](https://huggingface.co/learn/nlp-course/ru/chapter7/7). -
From c86fb1e8ecd7b120b842487de042d65941ad6e9f Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:20:20 +0300 Subject: [PATCH 427/502] Update chapters/ru/events/1.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index 25f861c66..a2dbfcb81 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -28,7 +28,6 @@ На первом семинаре Мерве приглашает Льюиса обсудить раздел 7 главы 7, посвященный задаче [ответа на вопросы](https://huggingface.co/learn/nlp-course/ru/chapter7/7). - На втором семинаре Мерве приглашает Леандро рассказать о 6 разделе 7 главы, посвященном [обучению каузальной языковой модели с нуля](https://huggingface.co/learn/nlp-course/ru/chapter7/6) и приложению [CodeParrot](https://huggingface.co/codeparrot). From e5a6afb2d68713d185f7997c35adad784ff2ba9b Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:20:30 +0300 Subject: [PATCH 428/502] Update chapters/ru/events/1.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/1.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/1.mdx b/chapters/ru/events/1.mdx index a2dbfcb81..5b94f5eb6 100644 --- a/chapters/ru/events/1.mdx +++ b/chapters/ru/events/1.mdx @@ -31,5 +31,4 @@ На втором семинаре Мерве приглашает Леандро рассказать о 6 разделе 7 главы, посвященном [обучению каузальной языковой модели с нуля](https://huggingface.co/learn/nlp-course/ru/chapter7/6) и приложению [CodeParrot](https://huggingface.co/codeparrot). -
From 10fb52fa36d1a7d61f1dfa661c267d2c561e3caa Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:20:41 +0300 Subject: [PATCH 429/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index eba0324f7..fd8ed738c 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -6,7 +6,6 @@ **Томас Вульф:** *Трансферное обучение и рождение библиотеки Transformers* -
From 198b1c3c9e0816fba987f21f35ee6ef030c40f2f Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:20:53 +0300 Subject: [PATCH 430/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index fd8ed738c..bc3f457ec 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -17,7 +17,6 @@ **Джей Аламмар:** *Легкое визуальное введение в модели трансформеры* -
From 7ed5ad42e212afc703bacbf7092fceccc932b21b Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:21:06 +0300 Subject: [PATCH 431/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index bc3f457ec..854d45ef6 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -7,7 +7,6 @@ **Томас Вульф:** *Трансферное обучение и рождение библиотеки Transformers* -

A visual summary of Thom's talk From 6a18d5d8a2b30df32cfe764fb568bbfd41e026fc Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:21:17 +0300 Subject: [PATCH 432/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 854d45ef6..8a34682df 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -17,7 +17,6 @@ **Джей Аламмар:** *Легкое визуальное введение в модели трансформеры* -

A visual summary of Jay's talk From 8a3edbf2881fa18787bb1d189c459499a02b1190 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:21:26 +0300 Subject: [PATCH 433/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 8a34682df..a1b765f55 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -26,7 +26,6 @@ **Маргарет Митчелл:** *О ценностях в разработке ML* -

From f998d19ce8952d29bb06cb1ebf609c0bfabf3eae Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:21:35 +0300 Subject: [PATCH 434/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index a1b765f55..d0f30b1f5 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -27,7 +27,6 @@ **Маргарет Митчелл:** *О ценностях в разработке ML* -

A visual summary of Margaret's talk From 6b249835708889c89e26ccccb6811dc11cca5f64 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:21:43 +0300 Subject: [PATCH 435/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index d0f30b1f5..e0d0437c3 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -36,7 +36,6 @@ **Мэттью Уотсон и Чэнь Цянь:** *Рабочие процессы NLP с Keras* -

From 8e44e89b3b67d3c60371ff70b8bd6309d36003dd Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:21:57 +0300 Subject: [PATCH 436/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index e0d0437c3..034a7d00b 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -37,7 +37,6 @@ **Мэттью Уотсон и Чэнь Цянь:** *Рабочие процессы NLP с Keras* -

A visual summary of Matt and Chen's talk From dcac23a1ed53cba109d90cc0ed70fa9c07d62239 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:22:13 +0300 Subject: [PATCH 437/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 034a7d00b..301d0b23d 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -48,7 +48,6 @@ **Марк Саруфим:** *Как обучить модель с помощью Pytorch* -

From b5a52b681a5be863cea420a3ecac09361db6d685 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:22:39 +0300 Subject: [PATCH 438/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 301d0b23d..677d6eccd 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -125,7 +125,6 @@ **Абубакар Абид:** *Быстрое создание приложений машинного обучения* -

From 41ef52709c806f18f3c83e315eb06d5a4eb4cfba Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:22:54 +0300 Subject: [PATCH 439/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 677d6eccd..816115a80 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -49,7 +49,6 @@ **Марк Саруфим:** *Как обучить модель с помощью Pytorch* -

A visual summary of Mark's talk From 33ddd73a383659cd88d66271a1e13ebacaa65ab5 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:23:08 +0300 Subject: [PATCH 440/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 816115a80..31be33a59 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -58,7 +58,6 @@ **Якоб Ушкорейт:** *Не сломалось, так не чини! Давай сломаем)* -

From 2157d046daaaa9862513d0903d1f0c43fa2b763d Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:23:22 +0300 Subject: [PATCH 441/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 31be33a59..f27203ea9 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -59,7 +59,6 @@ **Якоб Ушкорейт:** *Не сломалось, так не чини! Давай сломаем)* -

A visual summary of Jakob's talk From c572649a4ddfeb2825849cf7265687ee8f10e45d Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:23:38 +0300 Subject: [PATCH 442/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index f27203ea9..8feeb89c0 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -70,7 +70,6 @@ **Льюис Танстолл:** *Простое обучение с 🤗 Transformers Trainer* -

From 6695d3656d08a1d3e9b6ac797c0bd4cd2b371a36 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:23:51 +0300 Subject: [PATCH 443/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 8feeb89c0..b671b5d6e 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -71,7 +71,6 @@ **Льюис Танстолл:** *Простое обучение с 🤗 Transformers Trainer* - Льюис - инженер по машинному обучению в компании Hugging Face, занимающейся разработкой инструментов с открытым исходным кодом и делающий их доступными для широкого круга пользователей. Он также является соавтором книги O'Reilly [Natural Language Processing with Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/). Вы можете следовать за ним в Twitter (@_lewtun) для получения советов и рекомендаций по NLP! From 162a912921f63067797f5c88fe72a6c969182d1f Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:24:03 +0300 Subject: [PATCH 444/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index b671b5d6e..0188aef4a 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -76,7 +76,6 @@ **Мэтью Кэрриган:** *Новые функции TensorFlow для 🤗 Transformers и 🤗 Datasets* -
From 3eb7d9202db20a4869f04a25f9a8bc0edffe713b Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:24:21 +0300 Subject: [PATCH 445/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 0188aef4a..9a461c727 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -77,7 +77,6 @@ **Мэтью Кэрриган:** *Новые функции TensorFlow для 🤗 Transformers и 🤗 Datasets* - Мэтт отвечает за поддержку TensorFlow в Transformers и в конечном итоге возглавит переворот против действующей фракции PyTorch, который, вероятно, будет координироваться через его аккаунт в Twitter @carrigmat. From a044b405639bafd66a9f923620bf34e189a92fbf Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:24:33 +0300 Subject: [PATCH 446/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 9a461c727..35720abd3 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -82,7 +82,6 @@ **Лисандр Дебю:** *Hugging Face Hub как средство для совместной работы и обмена проектами по машинному обучению* -
From 9c9fa42d3dd49124f1ea07c4af9004c4159114d9 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:24:49 +0300 Subject: [PATCH 447/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 35720abd3..c1a9a32ed 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -83,7 +83,6 @@ **Лисандр Дебю:** *Hugging Face Hub как средство для совместной работы и обмена проектами по машинному обучению* -

A visual summary of Lysandre's talk From ea5b060b1e57cf278dbfe3dfcfd2e78c8009599b Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:25:02 +0300 Subject: [PATCH 448/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index c1a9a32ed..20fadfff4 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -92,7 +92,6 @@ **Люсиль Сольнье:** *Получите свой собственный токенизатор с помощью 🤗 Transformers & 🤗 Tokenizers* -

From 8a9469187bbdc203199d457bc827aed9c28f4e4a Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:25:14 +0300 Subject: [PATCH 449/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 20fadfff4..f1d27b0d7 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -93,7 +93,6 @@ **Люсиль Сольнье:** *Получите свой собственный токенизатор с помощью 🤗 Transformers & 🤗 Tokenizers* - Люсиль - инженер по машинному обучению в компании Hugging Face, занимается разработкой и поддержкой использования инструментов с открытым исходным кодом. Она также активно участвует во многих исследовательских проектах в области обработки естественного языка, таких как коллаборативное обучение и BigScience. From 95127a1263fe4aac051c0716571e341a55b2a5c7 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:25:28 +0300 Subject: [PATCH 450/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index f1d27b0d7..7669c748e 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -108,7 +108,6 @@
-
Мерве - сторонник разработчиков (developer advocate) в Hugging Face, занимается разработкой инструментов и созданием контента для них, чтобы сделать машинное обучение демократичным для всех. From e04895538898f18820bbcc5a43afb6d94ed16a47 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:25:43 +0300 Subject: [PATCH 451/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 7669c748e..16836ffac 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -98,7 +98,6 @@ **Сильвен Гуггер:** *Ускорьте цикл обучения PyTorch с помощью 🤗 Accelerate* -
From 4658529797364b43251f460cf17ad7a05ecc87e9 Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:25:57 +0300 Subject: [PATCH 452/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 16836ffac..2d8e4ba66 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -99,7 +99,6 @@ **Сильвен Гуггер:** *Ускорьте цикл обучения PyTorch с помощью 🤗 Accelerate* - Сильвен - инженер-исследователь в Hugging Face, один из основных сопровождающих 🤗 Transformers и разработчик 🤗 Accelerate. Ему нравится делать обучение моделей более доступным. From 0ea1589f9c2bb33aa44bbe32de0a049f69ca1ade Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Thu, 1 Feb 2024 19:26:10 +0300 Subject: [PATCH 453/502] Update chapters/ru/events/2.mdx Removing tag. I agree with you. Co-authored-by: Maria Khalusova --- chapters/ru/events/2.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/chapters/ru/events/2.mdx b/chapters/ru/events/2.mdx index 2d8e4ba66..443cc1167 100644 --- a/chapters/ru/events/2.mdx +++ b/chapters/ru/events/2.mdx @@ -104,7 +104,6 @@ **Мерве Ноян:** *Демонстрируйте свои демо моделей с помощью 🤗 Spaces* -
Мерве - сторонник разработчиков (developer advocate) в Hugging Face, занимается разработкой инструментов и созданием контента для них, чтобы сделать машинное обучение демократичным для всех. From f9a0ca5760a2668a2641314fae503fdd224f485b Mon Sep 17 00:00:00 2001 From: Artyom Boyko Date: Fri, 2 Feb 2024 21:45:54 +0300 Subject: [PATCH 454/502] Capture the current state of the translation. Two files are translated: , . Corrections to the table of contents. --- .../_toctree-checkpoint.yml | 201 ++++++++++ .../_toctree-checkpoint.yml | 204 ++++++++++ chapters/ru/_toctree.yml | 13 +- .../.ipynb_checkpoints/1-checkpoint.mdx | 25 ++ .../.ipynb_checkpoints/2-checkpoint.mdx | 353 ++++++++++++++++++ chapters/ru/chapter2/1.mdx | 21 +- chapters/ru/chapter2/2.mdx | 125 +++---- chapters/ru/chapter2/3.mdx | 81 ++-- chapters/ru/chapter2/4.mdx | 240 ++++++++++++ chapters/ru/chapter2/5.mdx | 338 +++++++++++++++++ chapters/ru/chapter2/6.mdx | 164 ++++++++ chapters/ru/chapter2/7.mdx | 20 +- chapters/ru/chapter2/8.mdx | 310 +++++++++++++++ 13 files changed, 1970 insertions(+), 125 deletions(-) create mode 100644 chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml create mode 100644 chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml create mode 100644 chapters/ru/chapter2/.ipynb_checkpoints/1-checkpoint.mdx create mode 100644 chapters/ru/chapter2/.ipynb_checkpoints/2-checkpoint.mdx create mode 100644 chapters/ru/chapter2/4.mdx create mode 100644 chapters/ru/chapter2/5.mdx create mode 100644 chapters/ru/chapter2/6.mdx create mode 100644 chapters/ru/chapter2/8.mdx diff --git a/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml new file mode 100644 index 000000000..c8364cc6d --- /dev/null +++ b/chapters/en/.ipynb_checkpoints/_toctree-checkpoint.yml @@ -0,0 +1,201 @@ +- title: 0. Setup + sections: + - local: chapter0/1 + title: Introduction + +- title: 1. Transformer models + sections: + - local: chapter1/1 + title: Introduction + - local: chapter1/2 + title: Natural Language Processing + - local: chapter1/3 + title: Transformers, what can they do? + - local: chapter1/4 + title: How do Transformers work? + - local: chapter1/5 + title: Encoder models + - local: chapter1/6 + title: Decoder models + - local: chapter1/7 + title: Sequence-to-sequence models + - local: chapter1/8 + title: Bias and limitations + - local: chapter1/9 + title: Summary + - local: chapter1/10 + title: End-of-chapter quiz + quiz: 1 + +- title: 2. Using 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Behind the pipeline + - local: chapter2/3 + title: Models + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Handling multiple sequences + - local: chapter2/6 + title: Putting it all together + - local: chapter2/7 + title: Basic usage completed! + - local: chapter2/8 + title: End-of-chapter quiz + quiz: 2 + +- title: 3. Fine-tuning a pretrained model + sections: + - local: chapter3/1 + title: Introduction + - local: chapter3/2 + title: Processing the data + - local: chapter3/3 + title: Fine-tuning a model with the Trainer API or Keras + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: A full training + - local: chapter3/5 + title: Fine-tuning, Check! + - local: chapter3/6 + title: End-of-chapter quiz + quiz: 3 + +- title: 4. Sharing models and tokenizers + sections: + - local: chapter4/1 + title: The Hugging Face Hub + - local: chapter4/2 + title: Using pretrained models + - local: chapter4/3 + title: Sharing pretrained models + - local: chapter4/4 + title: Building a model card + - local: chapter4/5 + title: Part 1 completed! + - local: chapter4/6 + title: End-of-chapter quiz + quiz: 4 + +- title: 5. The 🤗 Datasets library + sections: + - local: chapter5/1 + title: Introduction + - local: chapter5/2 + title: What if my dataset isn't on the Hub? + - local: chapter5/3 + title: Time to slice and dice + - local: chapter5/4 + title: Big data? 🤗 Datasets to the rescue! + - local: chapter5/5 + title: Creating your own dataset + - local: chapter5/6 + title: Semantic search with FAISS + - local: chapter5/7 + title: 🤗 Datasets, check! + - local: chapter5/8 + title: End-of-chapter quiz + quiz: 5 + +- title: 6. The 🤗 Tokenizers library + sections: + - local: chapter6/1 + title: Introduction + - local: chapter6/2 + title: Training a new tokenizer from an old one + - local: chapter6/3 + title: Fast tokenizers' special powers + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Normalization and pre-tokenization + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 + +- title: 7. Main NLP tasks + sections: + - local: chapter7/1 + title: Introduction + - local: chapter7/2 + title: Token classification + - local: chapter7/3 + title: Fine-tuning a masked language model + - local: chapter7/4 + title: Translation + - local: chapter7/5 + title: Summarization + - local: chapter7/6 + title: Training a causal language model from scratch + - local: chapter7/7 + title: Question answering + - local: chapter7/8 + title: Mastering NLP + - local: chapter7/9 + title: End-of-chapter quiz + quiz: 7 + +- title: 8. How to ask for help + sections: + - local: chapter8/1 + title: Introduction + - local: chapter8/2 + title: What to do when you get an error + - local: chapter8/3 + title: Asking for help on the forums + - local: chapter8/4 + title: Debugging the training pipeline + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: How to write a good issue + - local: chapter8/6 + title: Part 2 completed! + - local: chapter8/7 + title: End-of-chapter quiz + quiz: 8 + +- title: 9. Building and sharing demos + new: true + subtitle: I trained a model, but how can I show it off? + sections: + - local: chapter9/1 + title: Introduction to Gradio + - local: chapter9/2 + title: Building your first demo + - local: chapter9/3 + title: Understanding the Interface class + - local: chapter9/4 + title: Sharing demos with others + - local: chapter9/5 + title: Integrations with the Hugging Face Hub + - local: chapter9/6 + title: Advanced Interface features + - local: chapter9/7 + title: Introduction to Blocks + - local: chapter9/8 + title: Gradio, check! + - local: chapter9/9 + title: End-of-chapter quiz + quiz: 9 + +- title: Course Events + sections: + - local: events/1 + title: Live sessions and workshops + - local: events/2 + title: Part 2 release event + - local: events/3 + title: Gradio Blocks party diff --git a/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml b/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml new file mode 100644 index 000000000..46b889425 --- /dev/null +++ b/chapters/ru/.ipynb_checkpoints/_toctree-checkpoint.yml @@ -0,0 +1,204 @@ +- title: 0. Установка + sections: + - local: chapter0/1 + title: Введение + +- title: 1. Трансформеры + sections: + - local: chapter1/1 + title: Введение + - local: chapter1/2 + title: Обработка естественного языка + - local: chapter1/3 + title: "Трансформеры: на что они способны?" + - local: chapter1/4 + title: Как работают трансформеры? + - local: chapter1/5 + title: Модели-кодировщики + - local: chapter1/6 + title: Модели-декодировщики + - local: chapter1/7 + title: Модели "seq2seq" + - local: chapter1/8 + title: Предвзятости и ограничения + - local: chapter1/9 + title: Итоги + - local: chapter1/10 + title: Проверка знаний + +- title: 2. Использование 🤗 Transformers + sections: + - local: chapter2/1 + title: Введение + - local: chapter2/2 + title: За конвейером + - local: chapter2/3 + title: Модели + - local: chapter2/4 + title: Токенизаторы + - local: chapter2/5 + title: Обработка множественных последовательностей + - local: chapter2/6 + title: Собираем все воедино + - local: chapter2/7 + title: Базовое использование завершено! + - local: chapter2/8 + title: Итоговый тест по главе + quiz: 2 + +- title: 3. Fine-tuning предобученной модели + sections: + - local: chapter3/1 + title: Введение + - local: chapter3/2 + title: Предобработка данных + - local: chapter3/3 + title: Fine-tuning модели с использованием Trainer API + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: Полное обучение модели + - local: chapter3/5 + title: Fine-tuning, итоги! + - local: chapter3/6 + title: Итоговый тест по главе + quiz: 3 + +- title: 4. Hugging Face Hub + sections: + - local: chapter4/1 + title: Hugging Face Hub + - local: chapter4/2 + title: Использование предобученных моделей + - local: chapter4/3 + title: Публикация предобученных моделей в общий доступ + - local: chapter4/4 + title: Создание карточки модели + - local: chapter4/5 + title: Первая часть завершена! + - local: chapter4/6 + title: Итоговый тест по главе + quiz: 4 + +- title: 5. Библиотека 🤗 Datasets + sections: + - local: chapter5/1 + title: Введение + - local: chapter5/2 + title: Что делать, если моего датасета на нет на Hub? + - local: chapter5/3 + title: Препарируем 🤗 Datasets + - local: chapter5/4 + title: Big data? 🤗 Datasets спешат на помощь! + - local: chapter5/6 + title: Семантический поиск с помощью FAISS + - local: chapter5/7 + title: 🤗 Datasets, итоги! + - local: chapter5/8 + title: Тест по главе 5 + +- title: 6. Бибилиотека 🤗 Tokenizers + sections: + - local: chapter6/1 + title: Введение + - local: chapter6/2 + title: Обучение нового токенизатора на основе старого + - local: chapter6/3 + title: Особые возможности быстрых токенизаторов + - local: chapter6/3b + title: Быстрые токенизаторы в QA конвейере + - local: chapter6/4 + title: Нормализация и предварительная токенизация + - local: chapter6/5 + title: Токенизация Byte-Pair Encoding + - local: chapter6/6 + title: Токенизация WordPiece + - local: chapter6/7 + title: Токенизация Unigram + - local: chapter6/8 + title: Создание токенизатора, блок за блоком + - local: chapter6/9 + title: Токенизаторы, проверка! + - local: chapter6/10 + title: Тест в конце главы + quiz: 6 + +- title: 7. Основные задачи NLP + sections: + - local: chapter7/1 + title: Введение + - local: chapter7/2 + title: Классификация токенов + - local: chapter7/3 + title: Дообучение модели маскированного языкового моделирования + - local: chapter7/4 + title: Перевод + - local: chapter7/5 + title: Суммаризация + - local: chapter7/6 + title: Обучение каузальной языковой модели с нуля + - local: chapter7/7 + title: Ответы на вопросы + - local: chapter7/8 + title: Освоение NLP + - local: chapter7/9 + title: Тест в конце главы + quiz: 7 + +- title: 8. Как попросить о помощи + sections: + - local: chapter8/1 + title: Введение + - local: chapter8/2 + title: Что делать, если возникла ошибка + - local: chapter8/3 + title: Обращение за помощью на форумах + - local: chapter8/4_tf + title: Отладка обучения + - local: chapter8/4 + title: Отладка обучения + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: Как написать хорошее сообщение об ошибке (issue) + - local: chapter8/6 + title: Часть 2 завершена! + - local: chapter8/7 + title: Тест в конце главы + quiz: 8 + +- title: 9. Создание и распространение демо + new: true + subtitle: Я обучил модель, но как мне ее продемонстрировать? + sections: + - local: chapter9/1 + title: Введение в Gradio + - local: chapter9/2 + title: Создание вашего первого демо + - local: chapter9/3 + title: Понимание класса Interface + - local: chapter9/4 + title: Делимся демонстрациями с другими + - local: chapter9/5 + title: Интеграция с Hugging Face Hub + - local: chapter9/6 + title: Расширенные возможности Interface + - local: chapter9/7 + title: Введение в Gradio Blocks + - local: chapter9/8 + title: Gradio, проверка! + - local: chapter9/9 + title: Тест в конце главы + quiz: 9 + +- title: События курса + sections: + - local: events/1 + title: Встречи и семинары + - local: events/2 + title: Событие посвященное выходу 2 части курса + - local: events/3 + title: Вечеринка Gradio Blocks + +- title: Глоссарий + sections: + - local: glossary/1 + title: Глоссарий diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index 575ac4556..46b889425 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -26,16 +26,25 @@ - local: chapter1/10 title: Проверка знаний -- title: 2. Использование библиотеки 🤗 Transformers +- title: 2. Использование 🤗 Transformers sections: - local: chapter2/1 title: Введение - local: chapter2/2 - title: Внутри конвейера + title: За конвейером - local: chapter2/3 title: Модели + - local: chapter2/4 + title: Токенизаторы + - local: chapter2/5 + title: Обработка множественных последовательностей + - local: chapter2/6 + title: Собираем все воедино - local: chapter2/7 title: Базовое использование завершено! + - local: chapter2/8 + title: Итоговый тест по главе + quiz: 2 - title: 3. Fine-tuning предобученной модели sections: diff --git a/chapters/ru/chapter2/.ipynb_checkpoints/1-checkpoint.mdx b/chapters/ru/chapter2/.ipynb_checkpoints/1-checkpoint.mdx new file mode 100644 index 000000000..94add379c --- /dev/null +++ b/chapters/ru/chapter2/.ipynb_checkpoints/1-checkpoint.mdx @@ -0,0 +1,25 @@ +# Введение[[introduction]] + + + +Как вы видели в [Главе 1](../chapter1), модели трансформеров обычно очень большие. С миллионами и десятками *миллиардов* параметров, обучение и развертывание этих моделей - сложная задача. Кроме того, поскольку новые модели выходят практически ежедневно и каждая из них имеет свою собственную реализацию, попробовать их все - задача не из легких. + +Для решения этой проблемы была создана библиотека 🤗 Transformers. Ее цель - предоставить единый API, с помощью которого можно загрузить, обучить и сохранить любую модель Transformer. Основными особенностями библиотеки являются: + +- **Простота использования**: Скачать, загрузить и использовать современную модель NLP для инференса можно всего в две строчки кода. +- **Гибкость**: По своей сути все модели представляют собой простые классы PyTorch `nn.Module` или TensorFlow `tf.keras.Model` и могут быть обработаны как любые другие модели в соответствующих фреймворках машинного обучения (ML). +- **Простота**: В библиотеке почти нет абстракций. Концепция "Все в одном файле" является основной: прямой проход модели полностью определяется в одном файле, так что сам код понятен и доступен для изменения. + +Эта последняя особенность делает 🤗 Transformers совершенно непохожей на другие ML-библиотеки. Модели не строятся на основе модулей +которые совместно используются в разных файлах; вместо этого каждая модель имеет свои собственные слои. Помимо того, что это делает модели более доступными и понятными, это позволяет легко экспериментировать с одной моделью, не затрагивая другие. + +Эта глава начнется со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воссоздать функцию `pipeline()`, представленную в [Главе 1](../chapter1). Далее мы обсудим API модели: мы погрузимся в модель и классы конфигурации, покажем, как загрузить модель и как она обрабатывает числовые данные для вывода прогнозов. + +Затем мы рассмотрим API токенизатора, который является другим основным компонентом функции `pipeline()`. Токенизаторы берут на себя первый и последний шаги препроцессинга, обработку преобразования текста в числовые входы для нейронной сети и обратное преобразование в текст, когда это необходимо. Наконец, мы покажем вам, как обрабатывать несколько предложений, передавая их в модель в подготовленном батче, затем завершим все это более подробным рассмотрением высокоуровневой функции `tokenizer()`. + + +⚠️ Чтобы воспользоваться всеми возможностями, доступными в Model Hub и 🤗 Transformers, мы рекомендуем создать учетную запись. + \ No newline at end of file diff --git a/chapters/ru/chapter2/.ipynb_checkpoints/2-checkpoint.mdx b/chapters/ru/chapter2/.ipynb_checkpoints/2-checkpoint.mdx new file mode 100644 index 000000000..baa4fdc28 --- /dev/null +++ b/chapters/ru/chapter2/.ipynb_checkpoints/2-checkpoint.mdx @@ -0,0 +1,353 @@ + + +# За конвейером[[behind-the-pipeline]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +Это первый раздел, в котором содержание немного отличается в зависимости от того, используете ли вы PyTorch или TensorFlow. Переключите переключатель в верхней части заголовка, чтобы выбрать платформу, которую вы предпочитаете! + + +{#if fw === 'pt'} + +{:else} + +{/if} + +Давайте начнем с полноценного примера и посмотрим, что произошло за кулисами, когда мы выполнили следующий код в [Главе 1](../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}] +``` + +Как мы видели в [Главе 1] (../chapter1), этот конвейер объединяет три этапа: предобработку, пропуск входных данных через модель и постобработку: + +
+The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head. + +
+ +Давайте быстро пройдемся по каждому из них. + +## Предобработка с помощью токенизатора[[preprocessing-with-a-tokenizer]] + +Как и другие нейронные сети, модели Transformer не могут напрямую обрабатывать сырой текст, поэтому первым шагом нашего конвейера является преобразование текстовых данных в числа, которые сможет воспринимать модель. Для этого мы используем *токенизатор*, который будет отвечать за: + +- Разбиение входных данных на слова, подслова или символы (например, пунктуацию), которые называются *токенами* +- Сопоставление каждого токена с целым числом +- Добавление дополнительных входных данных, которые могут быть полезны для модели + +Вся эта предобработка должна быть выполнена точно так же, как и при предварительном обучении модели, поэтому сначала нам нужно загрузить эту информацию из [Model Hub](https://huggingface.co/models). Для этого мы используем класс `AutoTokenizer` и его метод `from_pretrained()`. Используя имя контрольной точки нашей модели, он автоматически получает данные, ассоциированные с токенизатором модели, и кэширует их (таким образом, они скачиваются только в первый раз, когда вы выполняете приведенный ниже код). + +Поскольку контрольной точкой по умолчанию конвейера `sentiment-analysis` является `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) +``` + +Когда у нас есть токенизатор, мы можем напрямую передать ему наши предложения и получить в ответ словарь, готовый к передаче в нашу модель! Осталось только преобразовать список входных идентификаторов в тензоры. + +Вы можете использовать 🤗 Transformers, не задумываясь о том, какой ML-фреймворк используется в качестве бэкенда; это может быть PyTorch или TensorFlow, или Flax для некоторых моделей. Однако модели Transformer принимают на вход только *тензоры*. Если вы впервые слышите о тензорах, то можете считать их массивами NumPy. Массив NumPy может быть скаляром (0D), вектором (1D), матрицей (2D) или иметь больше измерений. По сути, это тензор; тензоры других ML-фреймворков ведут себя аналогично, и их обычно так же просто инстанцировать, как и массивы NumPy. + +Чтобы указать тип тензоров, которые мы хотим получить в ответ (PyTorch, TensorFlow или обычный 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} + +Не беспокойтесь пока о дополнении и усечении, мы расскажем об этом позже. Главное, что нужно запомнить: вы можете передать одно предложение или список предложений, а также указать тип тензоров, которые вы хотите получить в ответ (если тип не указан, то в результате вы получите список списков). + +{#if fw === 'pt'} + +Вот как выглядят результаты в виде тензоров PyTorch: + +```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, 1, 0, 0, 0, 0, 0, 0, 0, 0] + ]) +} +``` +{:else} + +Вот как выглядят результаты в виде тензоров TensorFlow: + +```python out +{ + 'input_ids': , + 'attention_mask': +} +``` +{/if} + +Сам результат представляет собой словарь, содержащий два ключа, `input_ids` и `attention_mask`. `input_ids` содержит две строки целых чисел (по одной на каждое предложение), которые являются уникальными идентификаторами токенов в каждом предложении. Мы объясним, что такое `attention_mask` позже в этой главе. + +## Проходя сквозь модель[[going-through-the-model]] + +{#if fw === 'pt'} +Мы можем загрузить нашу предварительно обученную модель так же, как мы это делали с нашим токенизатором. 🤗 Transformers предоставляет класс `AutoModel`, у которого также есть метод `from_pretrained()`: + +```python +from transformers import AutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModel.from_pretrained(checkpoint) +``` +{:else} +Мы можем загрузить нашу предварительно обученную модель так же, как мы это делали с нашим токенизатором. 🤗 Transformers предоставляет класс `TFAutoModel`, в котором также есть метод `from_pretrained`: + +```python +from transformers import TFAutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModel.from_pretrained(checkpoint) +``` +{/if} + +В этом фрагменте кода мы загрузили ту же контрольную точку, которую использовали в нашем конвейере ранее (на самом деле она уже должна была быть кэширована), и инстанцировали модель с ее помощью. + +Эта архитектура содержит только базовый модуль Transformer: при наличии некоторых входных данных он выводит то, что мы будем называть *скрытыми состояниями (hidden states)*, также известными как *признаки (features)*. Для каждого входа модели мы получим высокоразмерный вектор, представляющий **контекстное понимание этого входа моделью Transformer**. + +Если вы не поняли смысла, не волнуйтесь. Мы объясним всё это позже. + +Хотя эти скрытые состояния могут быть полезны сами по себе, обычно они являются входными данными для другой части модели, известной как *голова (head)*. В [Главе 1](../chapter1) различные задачи могли быть выполнены с помощью одной и той же архитектуры, но каждая из этих задач будет связана с разной головой. + +### Многомерный вектор?[[a-high-dimensional-vector]] + +Вектор, возвращаемый модулем Transformer, обычно большой. Обычно он имеет три измерения: + +- **Размер батча (Batch size)**: Количество последовательностей, обрабатываемых за один раз (в нашем примере - 2). +- **Длина последовательности (Sequence length)**: Длина числового представления последовательности (в нашем примере - 16). +- **Скрытый размер (Hidden size)**: Размерность вектора каждого входа модели. + +О нем говорят как о "высокоразмерном" из-за последнего значения. Скрытый размер может быть очень большим (768 - обычное явление для небольших моделей, а в больших моделях он может достигать 3072 и более). + +Мы можем убедиться в этом, если подадим в нашу модель входные данные, которые мы подвергли предобработке: + +{#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} + +Обратите внимание, что выходы моделей 🤗 Transformers ведут себя как `namedtuple` или словари. Вы можете обращаться к элементам по атрибутам (как мы это делали), по ключу (`outputs["last_hidden_state"]`) или даже по индексу, если вы точно знаете, где находится искомый элемент (`outputs[0]`). + +### Головы моделей: Извлечение смысла из чисел[[model-heads-making-sense-out-of-numbers]] + +Головы модели принимают на вход высокоразмерный вектор скрытых состояний и проецируют его на другое измерение. Обычно они состоят из одного или нескольких линейных слоев: + +
+A Transformer network alongside its head. + +
+ +Выход модели Transformer передается непосредственно в головку модели для обработки. + +На этой диаграмме модель представлена слоем эмбеддингов и последующими слоями. Слой эмбеддингов преобразует каждый входной идентификатор в токенизированном входе в вектор, который представляет соответствующий токен. Последующие слои манипулируют этими векторами с помощью механизма внимания, чтобы получить окончательное представление предложений. + +Существует множество различных архитектур 🤗 Transformers, каждая из которых предназначена для решения определенной задачи. Вот неполный список: + +- `*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} + +Поскольку у нас всего два предложения и две метки, результат, полученный с помощью нашей модели, имеет форму 2 x 2. + +## Постобработка вывода[[postprocessing-the-output]] + +Значения, которые мы получаем на выходе из нашей модели, не всегда имеют смысл сами по себе. Давайте посмотрим: + +```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]` для второго. Это не вероятности, а *логиты*, сырые, ненормированные оценки, выведенные последним слоем модели. Чтобы преобразовать их в вероятности, они должны пройти через слой [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) (все модели 🤗 Transformers выводят логиты, поскольку функция потерь для обучения обычно объединяет последнюю функцию активации, такую как SoftMax, с фактической функцией потерь, такой как кросс-энтропия): + +{#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 + +Мы успешно воспроизвели три этапа конвейера: предобработку с помощью токенизаторов, прохождение входных данных через модель и постобработку! Теперь давайте уделим немного времени тому, чтобы углубиться в каждый из этих этапов. + + + +✏️ **Попробуйте! ** Выберите два (или более) собственных текста и пропустите их через конвейер `sentiment-analysis`. Затем повторите описанные здесь шаги и убедитесь, что вы получили те же результаты! + + diff --git a/chapters/ru/chapter2/1.mdx b/chapters/ru/chapter2/1.mdx index ce2dbae74..94add379c 100644 --- a/chapters/ru/chapter2/1.mdx +++ b/chapters/ru/chapter2/1.mdx @@ -1,24 +1,25 @@ -# Введение +# Введение[[introduction]] -Как вы могли заметить в [Главе 1](../chapter1/1), модели трансформеров обычно бывают очень большие. Обучение и развертывание таких моделей с миллионами и даже десятками *миллиардов* параметров является сложной задачей. Кроме того, новые модели выпускаются почти ежедневно, и каждая из них имеет собственную реализацию, опробовать их все — непростая задача. +Как вы видели в [Главе 1](../chapter1), модели трансформеров обычно очень большие. С миллионами и десятками *миллиардов* параметров, обучение и развертывание этих моделей - сложная задача. Кроме того, поскольку новые модели выходят практически ежедневно и каждая из них имеет свою собственную реализацию, попробовать их все - задача не из легких. -Библиотека 🤗 Transformers была создана для решения этой проблемы. Её цель — предоставить единый API, с помощью которого можно загружать, обучать и сохранять любую модель трансформера. Основными функциями библиотеки являются: +Для решения этой проблемы была создана библиотека 🤗 Transformers. Ее цель - предоставить единый API, с помощью которого можно загрузить, обучить и сохранить любую модель Transformer. Основными особенностями библиотеки являются: -- **Удобство в использовании**: Скачивание, загрузку и использование современной модели NLP для вывода данных, можно выполнять всего двумя строками кода. -- **Гибкость**: По своей сути все модели представляют собой простые классы библиотек PyTorch `nn.Module` или TensorFlow `tf.keras.Model` и могут обрабатываться, как и любые другие модели, в соответствующих средах машинного обучения (МО). -- **Простота**: В библиотеке практически не используются абстракции. "Все в одном файле" является основной концепцией: прямой проход модели полностью определяется в одном файле, так что сам код понятен, но при этом доступен для взлома. +- **Простота использования**: Скачать, загрузить и использовать современную модель NLP для инференса можно всего в две строчки кода. +- **Гибкость**: По своей сути все модели представляют собой простые классы PyTorch `nn.Module` или TensorFlow `tf.keras.Model` и могут быть обработаны как любые другие модели в соответствующих фреймворках машинного обучения (ML). +- **Простота**: В библиотеке почти нет абстракций. Концепция "Все в одном файле" является основной: прямой проход модели полностью определяется в одном файле, так что сам код понятен и доступен для изменения. -Последняя особенность сильно отличает библиотеку 🤗 Transformers от других библиотек машинного обучения. Модели не строятся на модулях, которые являются общими для всех файлов; вместо этого каждая модель имеет свои собственные слои. Это не только делает модели более доступными и понятными, но и позволяет легко экспериментировать с одной моделью, не затрагивая другие. +Эта последняя особенность делает 🤗 Transformers совершенно непохожей на другие ML-библиотеки. Модели не строятся на основе модулей +которые совместно используются в разных файлах; вместо этого каждая модель имеет свои собственные слои. Помимо того, что это делает модели более доступными и понятными, это позволяет легко экспериментировать с одной моделью, не затрагивая другие. -Эта глава начнается со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воспроизвести функцию `pipeline()` представленную в [Главе 1](../chapter1/1). Далее мы обсудим API модели: углубимся в классы модели и конфигурации и покажем, как загружать модель и как она обрабатывает числовые входные данные для получения прогнозов. +Эта глава начнется со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воссоздать функцию `pipeline()`, представленную в [Главе 1](../chapter1). Далее мы обсудим API модели: мы погрузимся в модель и классы конфигурации, покажем, как загрузить модель и как она обрабатывает числовые данные для вывода прогнозов. -Затем мы рассмотрим API токенизатора, который является другим основным компонентом функции `pipeline()`. Токенизаторы берут на себя первый и последний этапы обработки, обрабатывая преобразование текста в числовые входные данные для нейронной сети и обратное преобразование в текст, когда это необходимо. Наконец, мы покажем вам, как обработывается передача нескольких предложений в модель с помощью подготовленных пакетов, а затем завершим все это более детальным рассмотрением высокоуровневой функции `tokenizer()`. +Затем мы рассмотрим API токенизатора, который является другим основным компонентом функции `pipeline()`. Токенизаторы берут на себя первый и последний шаги препроцессинга, обработку преобразования текста в числовые входы для нейронной сети и обратное преобразование в текст, когда это необходимо. Наконец, мы покажем вам, как обрабатывать несколько предложений, передавая их в модель в подготовленном батче, затем завершим все это более подробным рассмотрением высокоуровневой функции `tokenizer()`. -⚠️ Чтобы воспользоваться всеми функциями, доступными в Model Hub и 🤗 Transformers, мы рекомендуем создать учетную запись. +⚠️ Чтобы воспользоваться всеми возможностями, доступными в Model Hub и 🤗 Transformers, мы рекомендуем создать учетную запись. \ No newline at end of file diff --git a/chapters/ru/chapter2/2.mdx b/chapters/ru/chapter2/2.mdx index 3960afe39..baa4fdc28 100644 --- a/chapters/ru/chapter2/2.mdx +++ b/chapters/ru/chapter2/2.mdx @@ -1,14 +1,14 @@ -# Внутри конвейера +# За конвейером[[behind-the-pipeline]] {#if fw === 'pt'} {:else} @@ -16,14 +16,14 @@ {/if} -Это первый раздел, содержание которого будет немного отличаться в зависимости от того, используете ли вы PyTorch или TensorFlow. Нажмите переключатель над заголовком, чтобы выбрать предпочитаемую платформу! +Это первый раздел, в котором содержание немного отличается в зависимости от того, используете ли вы PyTorch или TensorFlow. Переключите переключатель в верхней части заголовка, чтобы выбрать платформу, которую вы предпочитаете! {#if fw === 'pt'} @@ -32,7 +32,7 @@ {/if} -Давайте начнем с готового примера, взглянув на то, что происходило за кулисами, когда мы выполняли следующий код в [Главе 1](../chapter1/1): +Давайте начнем с полноценного примера и посмотрим, что произошло за кулисами, когда мы выполнили следующий код в [Главе 1](../chapter1): ```python from transformers import pipeline @@ -46,33 +46,33 @@ classifier( ) ``` -и на выходе получали: +и получил: ```python out [{'label': 'POSITIVE', 'score': 0.9598047137260437}, {'label': 'NEGATIVE', 'score': 0.9994558095932007}] ``` -Как мы уже увидели в [Главе 1](../chapter1/1), данный конвейер включает в себя три шага: предварительная обработка, передача входных данных через модель и постобработка: +Как мы видели в [Главе 1] (../chapter1), этот конвейер объединяет три этапа: предобработку, пропуск входных данных через модель и постобработку:
-Полный конвейер NLP: токенизация текста, преобразование в идентификаторы и вывод с помощью модели Transformer и слоя 'head' модели. - +The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head. +
-Давайте вкратце рассмотрим каждый из этих этапов. +Давайте быстро пройдемся по каждому из них. -## Предварительная обработка с помощью токенизатора +## Предобработка с помощью токенизатора[[preprocessing-with-a-tokenizer]] -Как и другие нейронные сети, модели Transformer не могут обрабатывать необработанный текст напрямую, поэтому первым шагом нашего конвейера является преобразование входных текстовых данных в числа, понятные модели. Для этого мы используем *токенизатор*, который будет отвечать за: +Как и другие нейронные сети, модели Transformer не могут напрямую обрабатывать сырой текст, поэтому первым шагом нашего конвейера является преобразование текстовых данных в числа, которые сможет воспринимать модель. Для этого мы используем *токенизатор*, который будет отвечать за: -- Разделение входных данных на слова, подслова или символы (например, знаки препинания), которые называются *токенами* -- Отображение каждого токена в целое число +- Разбиение входных данных на слова, подслова или символы (например, пунктуацию), которые называются *токенами* +- Сопоставление каждого токена с целым числом - Добавление дополнительных входных данных, которые могут быть полезны для модели -Всю эту предварительную обработку необходимо выполнять точно так же, как и при предварительном обучении модели, поэтому сначала нам нужно загрузить эту информацию из [Model Hub](https://huggingface.co/models). Для этого мы используем класс `AutoTokenizer` и его метод `from_pretrained()`. Используя имя контрольной точки нашей модели, он автоматически извлекает данные, связанные с токенизатором модели, и кэширует их (поэтому они загружаются только при первом запуске кода ниже). +Вся эта предобработка должна быть выполнена точно так же, как и при предварительном обучении модели, поэтому сначала нам нужно загрузить эту информацию из [Model Hub](https://huggingface.co/models). Для этого мы используем класс `AutoTokenizer` и его метод `from_pretrained()`. Используя имя контрольной точки нашей модели, он автоматически получает данные, ассоциированные с токенизатором модели, и кэширует их (таким образом, они скачиваются только в первый раз, когда вы выполняете приведенный ниже код). -Поскольку контрольной точкой конвейра `sentiment-analysis` по-умолчанию является модель `distilbert-base-uncased-finetuned-sst-2-english` (вы можете увидеть карточку модели [здесь](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)), мы выполним следующие команды: +Поскольку контрольной точкой по умолчанию конвейера `sentiment-analysis` является `distilbert-base-uncased-finetuned-sst-2-english` (вы можете посмотреть ее карточку модели [здесь](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)), мы выполняем следующее: ```python from transformers import AutoTokenizer @@ -81,12 +81,11 @@ checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" tokenizer = AutoTokenizer.from_pretrained(checkpoint) ``` -После того, как мы сосздадим токенизатор, мы сможем напрямую передать ему наши предложения, и получить словарь, готовый для использования в нашей модели! Осталось только преобразовать список входных идентификаторов в тензоры. +Когда у нас есть токенизатор, мы можем напрямую передать ему наши предложения и получить в ответ словарь, готовый к передаче в нашу модель! Осталось только преобразовать список входных идентификаторов в тензоры. -Вы можете использовать библиотеку 🤗 Transformers, не беспокоясь о том, какой фреймворк ML используется в качестве бэкэнда; это может быть PyTorch или TensorFlow или Flax для некоторых моделей. Однако модели Transformer принимают только *тензоры* в качестве входных данных. Если вы впервые слышите о тензорах, вы можете представлять их как массивы NumPy. Массив NumPy может быть скаляром (0D), вектором (1D), матрицой (2D) или иметь больше измерений. Фактически это тензор; тензоры других платформ машинного обучения ведут себя аналогично, и обычно их так же просто создавать, как массивы NumPy. +Вы можете использовать 🤗 Transformers, не задумываясь о том, какой ML-фреймворк используется в качестве бэкенда; это может быть PyTorch или TensorFlow, или Flax для некоторых моделей. Однако модели Transformer принимают на вход только *тензоры*. Если вы впервые слышите о тензорах, то можете считать их массивами NumPy. Массив NumPy может быть скаляром (0D), вектором (1D), матрицей (2D) или иметь больше измерений. По сути, это тензор; тензоры других ML-фреймворков ведут себя аналогично, и их обычно так же просто инстанцировать, как и массивы NumPy. - -Чтобы указать тип тензоров, которые мы хотим получить (PyTorch, TensorFlow, или обычный NumPy), мы используем аргумент `return_tensors`: +Чтобы указать тип тензоров, которые мы хотим получить в ответ (PyTorch, TensorFlow или обычный NumPy), мы используем аргумент `return_tensors`: {#if fw === 'pt'} ```python @@ -108,11 +107,11 @@ print(inputs) ``` {/if} -Не беспокойтесь пока о параметрах дополнения (padding) и усечения (truncation); мы объясним это позже. Здесь главное помнить, что вы можете передать одно предложение или список предложений, а также указать тип тензоров, которые вы хотите получить обратно (если тип не передан, в результате вы получите список из списков). +Не беспокойтесь пока о дополнении и усечении, мы расскажем об этом позже. Главное, что нужно запомнить: вы можете передать одно предложение или список предложений, а также указать тип тензоров, которые вы хотите получить в ответ (если тип не указан, то в результате вы получите список списков). {#if fw === 'pt'} -Вот как результаты выглядят в виде тензоров PyTorch: +Вот как выглядят результаты в виде тензоров PyTorch: ```python out { @@ -122,13 +121,13 @@ print(inputs) ]), '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] + [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0] ]) } ``` {:else} -Вот как результаты выглядят в виде тензоров TensorFlow: +Вот как выглядят результаты в виде тензоров TensorFlow: ```python out { @@ -140,18 +139,18 @@ print(inputs) 'attention_mask': } ``` {/if} -Сам вывод представляет собой словарь, содержащий два ключа, `input_ids` и `attention_mask`. `input_ids` содержит две строки целых чисел (по одному для каждого предложения), которые являются уникальными идентификаторами токенов в каждом предложении. Мы объясним, что такое `attention_mask` позже в этой главе. +Сам результат представляет собой словарь, содержащий два ключа, `input_ids` и `attention_mask`. `input_ids` содержит две строки целых чисел (по одной на каждое предложение), которые являются уникальными идентификаторами токенов в каждом предложении. Мы объясним, что такое `attention_mask` позже в этой главе. -## Проходим через модель +## Проходя сквозь модель[[going-through-the-model]] {#if fw === 'pt'} -Мы можем загрузить нашу предварительно обученную модель так же, как и наш токенизатор. Библиотека 🤗 Transformers предоставляет класс `AutoModel` который также имеет метод `from_pretrained()`: +Мы можем загрузить нашу предварительно обученную модель так же, как мы это делали с нашим токенизатором. 🤗 Transformers предоставляет класс `AutoModel`, у которого также есть метод `from_pretrained()`: ```python from transformers import AutoModel @@ -160,7 +159,7 @@ checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" model = AutoModel.from_pretrained(checkpoint) ``` {:else} -Мы можем загрузить нашу предварительно обученную модель так же, как и наш токенизатор. Библиотека 🤗 Transformers предоставляет класс `TFAutoModel` который также имеет метод `from_pretrained`: +Мы можем загрузить нашу предварительно обученную модель так же, как мы это делали с нашим токенизатором. 🤗 Transformers предоставляет класс `TFAutoModel`, в котором также есть метод `from_pretrained`: ```python from transformers import TFAutoModel @@ -170,25 +169,25 @@ model = TFAutoModel.from_pretrained(checkpoint) ``` {/if} -В этом фрагменте кода мы загрузили ту же контрольную точку, которую использовали в нашем конвейере ранее (на самом деле она уже должна была быть закэширована) и создали с ее помощью экземпляр модели. +В этом фрагменте кода мы загрузили ту же контрольную точку, которую использовали в нашем конвейере ранее (на самом деле она уже должна была быть кэширована), и инстанцировали модель с ее помощью. -Эта архитектура содержит только базовый модуль Transformer: при некоторых входных данных он выводит то, что мы будем называть *скрытыми состояниями*, также известными как *параметры*. Для каждого входного набора данных модели мы получим многомерный вектор, представляющий **контекстное понимание этого входного набора моделью Transformer**. +Эта архитектура содержит только базовый модуль Transformer: при наличии некоторых входных данных он выводит то, что мы будем называть *скрытыми состояниями (hidden states)*, также известными как *признаки (features)*. Для каждого входа модели мы получим высокоразмерный вектор, представляющий **контекстное понимание этого входа моделью Transformer**. -Если вы пока не понимаете в чем смысл, не беспокойтесь об этом. Мы объясним все это позже. +Если вы не поняли смысла, не волнуйтесь. Мы объясним всё это позже. -Хотя эти скрытые состояния могут быть полезны сами по себе, они обычно являются входными данными для другой части модели, известной как слой *head*. В [Главе 1](../chapter1/1) разные задачи могли бы выполняться с одной и той же архитектурой, но с каждой из этих задач будет связан отдельный слой "head". +Хотя эти скрытые состояния могут быть полезны сами по себе, обычно они являются входными данными для другой части модели, известной как *голова (head)*. В [Главе 1](../chapter1) различные задачи могли быть выполнены с помощью одной и той же архитектуры, но каждая из этих задач будет связана с разной головой. -### Многомерный вектор, что это? +### Многомерный вектор?[[a-high-dimensional-vector]] -Вектор, выводимый модулем Transformer, обычно является большим. И как правило, он имеет три параметра: +Вектор, возвращаемый модулем Transformer, обычно большой. Обычно он имеет три измерения: -- **Размер пакета**: Количество последовательностей, обрабатываемых одновременно (в нашем примере 2). -- **Длина последовательности**: Длина числового представления последовательности (в нашем примере 16). -- **Размер скрытого слоя сети**: Количество измерений вектора каждого входного параметра модели. +- **Размер батча (Batch size)**: Количество последовательностей, обрабатываемых за один раз (в нашем примере - 2). +- **Длина последовательности (Sequence length)**: Длина числового представления последовательности (в нашем примере - 16). +- **Скрытый размер (Hidden size)**: Размерность вектора каждого входа модели. -Его называют "многомерный" из-за последнего значения. Размер скрытого слоя сети может быть очень большим (768 обычно используется для небольших моделей, а в больших моделях он может достигать 3072 или более). +О нем говорят как о "высокоразмерном" из-за последнего значения. Скрытый размер может быть очень большим (768 - обычное явление для небольших моделей, а в больших моделях он может достигать 3072 и более). -Мы можем увидеть это, если передадим входные данные, которые мы предварительно обработали, в нашу модель: +Мы можем убедиться в этом, если подадим в нашу модель входные данные, которые мы подвергли предобработке: {#if fw === 'pt'} ```python @@ -210,24 +209,24 @@ print(outputs.last_hidden_state.shape) ``` {/if} -Обратите внимание, что выходные данные моделей 🤗 Transformers ведут себя как именованные кортежи или словари. Вы можете получить доступ к элементам по атрибутам (как это сделали мы) или по ключу (`outputs["last_hidden_state"]`), или даже по индексу, если вы точно знаете, где находится то, что вы ищете (`outputs[0]`). +Обратите внимание, что выходы моделей 🤗 Transformers ведут себя как `namedtuple` или словари. Вы можете обращаться к элементам по атрибутам (как мы это делали), по ключу (`outputs["last_hidden_state"]`) или даже по индексу, если вы точно знаете, где находится искомый элемент (`outputs[0]`). -### Слои "head" модели: Разбираемся в цифрах +### Головы моделей: Извлечение смысла из чисел[[model-heads-making-sense-out-of-numbers]] -Слои "head" модели принимают многомерный вектор скрытых состояний в качестве входных данных и проецируют их в другое измерение. Они обычно состоят из одного или нескольких линейных слоев: +Головы модели принимают на вход высокоразмерный вектор скрытых состояний и проецируют его на другое измерение. Обычно они состоят из одного или нескольких линейных слоев:
-Нейронная сеть Transformer перед слоем 'head'. - +A Transformer network alongside its head. +
-Выходные данные модели Transformer отправляются непосредственно в слой "head" модели для обработки. +Выход модели Transformer передается непосредственно в головку модели для обработки. -На данной диаграмме модель представлена слоем вложений и последующими слоями. Слой вложений преобразует каждый входной идентификатор полученный токенизатором, в вектор, который представляет собой связанный с ним токен. Последующие слои манипулируют этими векторами, используя механизм внимания, чтобы получить окончательное представление предложений. +На этой диаграмме модель представлена слоем эмбеддингов и последующими слоями. Слой эмбеддингов преобразует каждый входной идентификатор в токенизированном входе в вектор, который представляет соответствующий токен. Последующие слои манипулируют этими векторами с помощью механизма внимания, чтобы получить окончательное представление предложений. -В 🤗 Transformersдоступно множество различных архитектур, каждая из которых предназначена для решения конкретной задачи. Вот неполный список: +Существует множество различных архитектур 🤗 Transformers, каждая из которых предназначена для решения определенной задачи. Вот неполный список: -- `*Model` (извлекает скрытые состояния) +- `*Model` (извлечение скрытых состояний) - `*ForCausalLM` - `*ForMaskedLM` - `*ForMultipleChoice` @@ -237,7 +236,7 @@ print(outputs.last_hidden_state.shape) - и другие 🤗 {#if fw === 'pt'} -Для нашего примера нам понадобится модель со слоем "head" для классификации последовательностей (чтобы иметь возможность классифицировать предложения как положительные или отрицательные). Итак, на самом деле мы будем использовать не класс `AutoModel`, а `AutoModelForSequenceClassification`: +Для нашего примера нам понадобится модель с головой классификации последовательности (чтобы иметь возможность классифицировать предложения как положительные или отрицательные). Поэтому мы будем использовать не класс `AutoModel`, а `AutoModelForSequenceClassification`: ```python from transformers import AutoModelForSequenceClassification @@ -247,7 +246,7 @@ model = AutoModelForSequenceClassification.from_pretrained(checkpoint) outputs = model(**inputs) ``` {:else} -Для нашего примера нам понадобится модель со слоем "head" для классификации последовательностей (чтобы иметь возможность классифицировать предложения как положительные или отрицательные). Итак, на самом деле мы будем использовать не класс `TFAutoModel`, а `TFAutoModelForSequenceClassification`: +Для нашего примера нам понадобится модель с головой классификации последовательности (чтобы иметь возможность классифицировать предложения как положительные или отрицательные). Поэтому мы будем использовать не класс `TFAutoModel`, а `TFAutoModelForSequenceClassification`: ```python from transformers import TFAutoModelForSequenceClassification @@ -258,7 +257,7 @@ outputs = model(inputs) ``` {/if} -Теперь, если мы посмотрим на форму наших входных данных, размерность будет намного ниже: слой "head" модели принимает в качестве входных данных многомерные векторы, которые мы видели ранее, и выводит векторы, содержащие всего два значения (по одному на метку): +Теперь, если мы посмотрим на форму наших выходов, размерность будет гораздо ниже: голова модели принимает на вход высокоразмерные векторы, которые мы видели ранее, и возвращает векторы, содержащие два значения (по одному на метку): ```python print(outputs.logits.shape) @@ -274,11 +273,11 @@ torch.Size([2, 2]) ``` {/if} -Поскольку у нас всего два предложения и две метки, результат, который мы получаем от нашей модели, имеет форму 2 x 2. +Поскольку у нас всего два предложения и две метки, результат, полученный с помощью нашей модели, имеет форму 2 x 2. -## Постобработка выходных данных +## Постобработка вывода[[postprocessing-the-output]] -Значения, которые мы получаем в качестве выходных данных нашей модели, не обязательно имеют смысл сами по себе. Давайте посмотрим: +Значения, которые мы получаем на выходе из нашей модели, не всегда имеют смысл сами по себе. Давайте посмотрим: ```python print(outputs.logits) @@ -297,7 +296,7 @@ tensor([[-1.5607, 1.6123], ``` {/if} -Наша модель предсказала `[-1.5607, 1.6123]` для первого предложения и `[ 4.1692, -3.3464]` для второго. Это не вероятности, а *логиты*, необработанные, ненормализованные оценки, выводимые последним слоем модели. Для преобразования в вероятности, они должны пройти через слой [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) (все модели 🤗 Transformers выводят логиты, поскольку функция потерь для обучения обычно объединяет последнюю функцию активации, такую как SoftMax, с фактической функцией потерь, такой как перекрестная энтропия): +Наша модель спрогнозировала `[-1.5607, 1.6123]` для первого предложения и `[ 4.1692, -3.3464]` для второго. Это не вероятности, а *логиты*, сырые, ненормированные оценки, выведенные последним слоем модели. Чтобы преобразовать их в вероятности, они должны пройти через слой [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) (все модели 🤗 Transformers выводят логиты, поскольку функция потерь для обучения обычно объединяет последнюю функцию активации, такую как SoftMax, с фактической функцией потерь, такой как кросс-энтропия): {#if fw === 'pt'} ```py @@ -328,9 +327,9 @@ tf.Tensor( ``` {/if} -Теперь мы видим, что модель предсказала `[0.0402, 0.9598]` для первого предложения и `[0.9995, 0.0005]` для второго. Это легко узнаваемые оценки вероятности. +Теперь мы видим, что модель спрогнозировала `[0.0402, 0.9598]` для первого предложения и `[0.9995, 0.0005]` для второго. Это узнаваемые оценки вероятности. -Чтобы получить метки, соответствующие каждой позиции, мы можем проверить атрибут `id2label` в конфигурации модели (подробнее об этом в следующем разделе): +Чтобы получить метки, соответствующие каждой позиции, мы можем обратиться к атрибуту `id2label` в конфигурации модели ( более подробно об этом в следующем разделе): ```python model.config.id2label @@ -340,15 +339,15 @@ model.config.id2label {0: 'NEGATIVE', 1: 'POSITIVE'} ``` -Теперь мы можем сделать вывод, что модель предсказала следующее: +Теперь мы можем сделать вывод, что модель спрогнозировала следующее: - Первое предложение: NEGATIVE: 0.0402, POSITIVE: 0.9598 - Второе предложение: NEGATIVE: 0.9995, POSITIVE: 0.0005 -Мы успешно воспроизвели три этапа конвейера: предварительную обработку с помощью токенизаторов, передачу входных данных через модель и постобработку! Теперь давайте уделим некоторое время тому, чтобы углубиться в каждый из этих шагов. +Мы успешно воспроизвели три этапа конвейера: предобработку с помощью токенизаторов, прохождение входных данных через модель и постобработку! Теперь давайте уделим немного времени тому, чтобы углубиться в каждый из этих этапов. -✏️ **Попробуйте это сделать!** Выберите два (или более) собственных текста и пропустите их через конвейер `sentiment-analysis`. Затем повторите шаги, которые вы видели здесь, и убедитесь, что вы получаете такие же результаты! +✏️ **Попробуйте! ** Выберите два (или более) собственных текста и пропустите их через конвейер `sentiment-analysis`. Затем повторите описанные здесь шаги и убедитесь, что вы получили те же результаты! diff --git a/chapters/ru/chapter2/3.mdx b/chapters/ru/chapter2/3.mdx index b7e941ac4..acc653704 100644 --- a/chapters/ru/chapter2/3.mdx +++ b/chapters/ru/chapter2/3.mdx @@ -1,14 +1,14 @@ -# Модели +# Models[[models]] {#if fw === 'pt'} {:else} @@ -16,8 +16,8 @@ {/if} @@ -29,22 +29,22 @@ {/if} {#if fw === 'pt'} -В этом разделе мы подробнее рассмотрим создание и использование модели. Мы будем использовать класс `AutoModel`, который удобен, когда вы хотите создать экземпляр любой модели из контрольной точки. +In this section we'll take a closer look at creating and using a model. We'll use the `AutoModel` class, which is handy when you want to instantiate any model from a checkpoint. -Класс `AutoModel` и все его родственники на самом деле являются простыми оболочками для большого количества моделей, доступных в библиотеке. Это умная оболочка, поскольку она может автоматически угадывать подходящую архитектуру модели для вашей контрольной точки, а затем создает экземпляр модели с этой архитектурой. +The `AutoModel` class and all of its relatives are actually simple wrappers over the wide variety of models available in the library. It's a clever wrapper as it can automatically guess the appropriate model architecture for your checkpoint, and then instantiates a model with this architecture. {:else} In this section we'll take a closer look at creating and using a model. We'll use the `TFAutoModel` class, which is handy when you want to instantiate any model from a checkpoint. -Класс `TFAutoModel` и все его родственники на самом деле являются простыми оболочками для большого количества моделей, доступных в библиотеке. Это умная оболочка, поскольку она может автоматически угадывать подходящую архитектуру модели для вашей контрольной точки, а затем создает экземпляр модели с этой архитектурой. +The `TFAutoModel` class and all of its relatives are actually simple wrappers over the wide variety of models available in the library. It's a clever wrapper as it can automatically guess the appropriate model architecture for your checkpoint, and then instantiates a model with this architecture. {/if} -Однако, если вы знаете тип модели, которую хотите использовать, вы можете использовать класс, который напрямую определяет ее архитектуру. Давайте посмотрим, как это работает с моделью BERT. +However, if you know the type of model you want to use, you can use the class that defines its architecture directly. Let's take a look at how this works with a BERT model. -## Создание модели Transformer +## Creating a Transformer[[creating-a-transformer]] -Первое, что нам нужно будет сделать для инициализации модели BERT, это загрузить объект конфигурации: +The first thing we'll need to do to initialize a BERT model is load a configuration object: {#if fw === 'pt'} ```py @@ -68,7 +68,7 @@ model = TFBertModel(config) ``` {/if} -Конфигурация содержит множество атрибутов, которые используются для построения модели: +The configuration contains many attributes that are used to build the model: ```py print(config) @@ -86,11 +86,11 @@ BertConfig { } ``` -Хотя вы еще не видели, что делают все эти атрибуты, вы должны узнать некоторые из них: атрибут `hidden_size` определяет размер вектора `hidden_states`, а `num_hidden_layers` определяет количество слоев, которые имеет модель. +While you haven't seen what all of these attributes do yet, you should recognize some of them: the `hidden_size` attribute defines the size of the `hidden_states` vector, and `num_hidden_layers` defines the number of layers the Transformer model has. -### Различные способы загрузки +### Different loading methods[[different-loading-methods]] -Создание модели из конфигурации по умолчанию инициализирует ее случайными значениями: +Creating a model from the default configuration initializes it with random values: {#if fw === 'pt'} ```py @@ -99,7 +99,7 @@ from transformers import BertConfig, BertModel config = BertConfig() model = BertModel(config) -# Модель инициализируется случайным образом! +# Model is randomly initialized! ``` {:else} ```py @@ -108,13 +108,13 @@ from transformers import BertConfig, TFBertModel config = BertConfig() model = TFBertModel(config) -# Модель инициализируется случайным образом! +# Model is randomly initialized! ``` {/if} -Модель можно использовать в этом состоянии, но она будет выводить тарабарщину; сначала ее нужно обучить. Мы могли бы обучить модель с нуля для решения поставленной задачи, но, как вы видели в [Главе 1](../chapter1/1), это потребовало бы много времени и большого количества данных, а также имело бы значительное воздействие на окружающую среду. Чтобы избежать ненужных и дублирующих усилий, крайне важно иметь возможность делиться и повторно использовать модели, которые уже были обучены. +The model can be used in this state, but it will output gibberish; it needs to be trained first. We could train the model from scratch on the task at hand, but as you saw in [Chapter 1](/course/chapter1), this would require a long time and a lot of data, and it would have a non-negligible environmental impact. To avoid unnecessary and duplicated effort, it's imperative to be able to share and reuse models that have already been trained. -Загрузить уже обученную модель Transformer очень просто — мы можем сделать это с помощью метода `from_pretrained()`: +Loading a Transformer model that is already trained is simple — we can do this using the `from_pretrained()` method: {#if fw === 'pt'} ```py @@ -123,7 +123,7 @@ from transformers import BertModel model = BertModel.from_pretrained("bert-base-cased") ``` -Как вы видели ранее, мы могли бы заменить `BertModel` эквивалентным классом `AutoModel`. С этого момента мы начнем делать так, поскольку таким образом создается код, не зависящий от контрольных точек; если ваш код работает для одной контрольной точки, он должен беспрепятственно работать с другой. Это применимо, даже если архитектура отличается, при условии, что контрольная точка была обучена для аналогичной задачи (например, задачи анализа тональности). +As you saw earlier, we could replace `BertModel` with the equivalent `AutoModel` class. We'll do this from now on as this produces checkpoint-agnostic code; if your code works for one checkpoint, it should work seamlessly with another. This applies even if the architecture is different, as long as the checkpoint was trained for a similar task (for example, a sentiment analysis task). {:else} ```py @@ -132,27 +132,27 @@ from transformers import TFBertModel model = TFBertModel.from_pretrained("bert-base-cased") ``` -Как вы видели ранее, мы могли бы заменить `TFBertModel` эквивалентным классом `TFAutoModel`. С этого момента мы начнем делать так, поскольку таким образом создается код, не зависящий от контрольных точек; если ваш код работает для одной контрольной точки, он должен беспрепятственно работать с другой. Это применимо, даже если архитектура отличается, при условии, что контрольная точка была обучена для аналогичной задачи (например, задачи анализа тональности). +As you saw earlier, we could replace `TFBertModel` with the equivalent `TFAutoModel` class. We'll do this from now on as this produces checkpoint-agnostic code; if your code works for one checkpoint, it should work seamlessly with another. This applies even if the architecture is different, as long as the checkpoint was trained for a similar task (for example, a sentiment analysis task). {/if} -В приведенном выше примере кода мы не использовали `BertConfig`, а вместо этого загрузили предварительно обученную модель с помощью идентификатора `bert-base-cased`. Это контрольная точка модели, которую обучили сами авторы BERT; вы можете найти более подробную информацию о ней в её [карточке модели](https://huggingface.co/bert-base-cased). +In the code sample above we didn't use `BertConfig`, and instead loaded a pretrained model via the `bert-base-cased` identifier. This is a model checkpoint that was trained by the authors of BERT themselves; you can find more details about it in its [model card](https://huggingface.co/bert-base-cased). -Теперь эта модель инициализирована со всеми весами контрольной точки. Её можно использовать непосредственно для логического вывода на задачах, для которых она обучалась, а также её можно точно донастроить для новой задачи. Тренируясь с предварительно обученными весами, а не с нуля, мы можем быстро добиться хороших результатов. +This model is now initialized with all the weights of the checkpoint. It can be used directly for inference on the tasks it was trained on, and it can also be fine-tuned on a new task. By training with pretrained weights rather than from scratch, we can quickly achieve good results. -Веса будут загружены и кэшированы (поэтому будущие вызовы метода `from_pretrained()` не будут загружать их повторно) в папку кеша, которая по умолчанию находится в *~/.cache/huggingface/transformers*. Вы можете настроить папку кэша, установив переменную среды `HF_HOME`. +The weights have been downloaded and cached (so future calls to the `from_pretrained()` method won't re-download them) in the cache folder, which defaults to *~/.cache/huggingface/transformers*. You can customize your cache folder by setting the `HF_HOME` environment variable. -Идентификатор, используемый для загрузки модели, может быть идентификатором любой модели в Model Hub, если он совместим с архитектурой BERT. Полный список доступных контрольных точек моделей BERT можно найти [здесь](https://huggingface.co/models?filter=bert). +The identifier used to load the model can be the identifier of any model on the Model Hub, as long as it is compatible with the BERT architecture. The entire list of available BERT checkpoints can be found [here](https://huggingface.co/models?filter=bert). -### Способы сохранения +### Saving methods[[saving-methods]] -Сохранить модель так же просто, как и загрузить - для этого мы используем метод `save_pretrained()`, аналогичный методу `from_pretrained()`: +Saving a model is as easy as loading one — we use the `save_pretrained()` method, which is analogous to the `from_pretrained()` method: ```py model.save_pretrained("directory_on_my_computer") ``` -Данный код сохранит два файла на вашем диске: +This saves two files to your disk: {#if fw === 'pt'} ``` @@ -168,29 +168,29 @@ config.json tf_model.h5 ``` {/if} -Если вы посмотрите на файл *config.json*, вы увидите атрибуты, необходимые для построения архитектуры модели. Этот файл также содержит некоторые метаданные, например, откуда появилась контрольная точка и какую версию 🤗 Transformers вы использовали, когда в последний раз сохраняли контрольную точку. +If you take a look at the *config.json* file, you'll recognize the attributes necessary to build the model architecture. This file also contains some metadata, such as where the checkpoint originated and what 🤗 Transformers version you were using when you last saved the checkpoint. {#if fw === 'pt'} -Файл *pytorch_model.bin* известен как *словарь состояний*; он содержит все веса вашей модели. Эти два файла идут рука об руку; конфигурация необходима, чтобы знать архитектуру вашей модели, в то время как веса модели являются параметрами вашей модели. +The *pytorch_model.bin* file is known as the *state dictionary*; it contains all your model's weights. The two files go hand in hand; the configuration is necessary to know your model's architecture, while the model weights are your model's parameters. {:else} -Файл *tf_model.h5* известен как *словарь состояний*; он содержит все веса вашей модели. Эти два файла идут рука об руку; конфигурация необходима, чтобы знать архитектуру вашей модели, в то время как веса модели являются параметрами вашей модели. +The *tf_model.h5* file is known as the *state dictionary*; it contains all your model's weights. The two files go hand in hand; the configuration is necessary to know your model's architecture, while the model weights are your model's parameters. {/if} -## Использование модели Transformer для логического вывода +## Using a Transformer model for inference[[using-a-transformer-model-for-inference]] -Теперь, когда вы знаете, как загружать и сохранять модель, давайте попробуем использовать ее для построения некоторых предсказаний. Модели Transformer могут обрабатывать только числа — числа, которые генерирует токенизатор. Но прежде чем мы обсудим токенизаторы, давайте рассмотрим, какие входные данные принимает модель. +Now that you know how to load and save a model, let's try using it to make some predictions. Transformer models can only process numbers — numbers that the tokenizer generates. But before we discuss tokenizers, let's explore what inputs the model accepts. -Токенизаторы могут позаботиться о преобразовании входных данных в соответствующие тензоры фреймворка, но чтобы помочь вам понять, что происходит, мы кратко рассмотрим, что необходимо сделать, прежде чем отправлять входные данные в модель. +Tokenizers can take care of casting the inputs to the appropriate framework's tensors, but to help you understand what's going on, we'll take a quick look at what must be done before sending the inputs to the model. -Допустим, у нас есть несколько последовательностей: +Let's say we have a couple of sequences: ```py sequences = ["Hello!", "Cool.", "Nice!"] ``` -Токенизатор преобразует их в словарные индексы, которые обычно называются *входными идентификаторами*. Каждая последовательность теперь представляет собой список чисел! В результате получается: +The tokenizer converts these to vocabulary indices which are typically called *input IDs*. Each sequence is now a list of numbers! The resulting output is: ```py no-format encoded_sequences = [ @@ -200,7 +200,7 @@ encoded_sequences = [ ] ``` -Это список закодированных последовательностей: список списков. Тензоры принимают только прямоугольные формы (например, матрицы). Этот "массив" уже имеет прямоугольную форму, поэтому преобразовать его в тензор несложно: +This is a list of encoded sequences: a list of lists. Tensors only accept rectangular shapes (think matrices). This "array" is already of rectangular shape, so converting it to a tensor is easy: {#if fw === 'pt'} ```py @@ -216,12 +216,13 @@ model_inputs = tf.constant(encoded_sequences) ``` {/if} -### Использование тензоров в качестве входных данных для модели +### Using the tensors as inputs to the model[[using-the-tensors-as-inputs-to-the-model]] -Использовать тензоры с моделью чрезвычайно просто — мы просто вызываем модель с входными данными: +Making use of the tensors with the model is extremely simple — we just call the model with the inputs: ```py output = model(model_inputs) ``` -В то время как модель принимает множество различных аргументов, необходимы только входные идентификаторы. Позже мы объясним, для чего применяются другие аргументы и когда они требуются, но сначала нам нужно поближе познакомиться с токенизаторами, которые используются для создания входных данных, понятных модели Transformer. +While the model accepts a lot of different arguments, only the input IDs are necessary. We'll explain what the other arguments do and when they are required later, +but first we need to take a closer look at the tokenizers that build the inputs that a Transformer model can understand. diff --git a/chapters/ru/chapter2/4.mdx b/chapters/ru/chapter2/4.mdx new file mode 100644 index 000000000..30167ddbd --- /dev/null +++ b/chapters/ru/chapter2/4.mdx @@ -0,0 +1,240 @@ + + +# Tokenizers[[tokenizers]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + +Tokenizers are one of the core components of the NLP pipeline. They serve one purpose: to translate text into data that can be processed by the model. Models can only process numbers, so tokenizers need to convert our text inputs to numerical data. In this section, we'll explore exactly what happens in the tokenization pipeline. + +In NLP tasks, the data that is generally processed is raw text. Here's an example of such text: + +``` +Jim Henson was a puppeteer +``` + +However, models can only process numbers, so we need to find a way to convert the raw text to numbers. That's what the tokenizers do, and there are a lot of ways to go about this. The goal is to find the most meaningful representation — that is, the one that makes the most sense to the model — and, if possible, the smallest representation. + +Let's take a look at some examples of tokenization algorithms, and try to answer some of the questions you may have about tokenization. + +## Word-based[[word-based]] + + + +The first type of tokenizer that comes to mind is _word-based_. It's generally very easy to set up and use with only a few rules, and it often yields decent results. For example, in the image below, the goal is to split the raw text into words and find a numerical representation for each of them: + +
+ An example of word-based tokenization. + +
+ +There are different ways to split the text. For example, we could use whitespace to tokenize the text into words by applying Python's `split()` function: + +```py +tokenized_text = "Jim Henson was a puppeteer".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'was', 'a', 'puppeteer'] +``` + +There are also variations of word tokenizers that have extra rules for punctuation. With this kind of tokenizer, we can end up with some pretty large "vocabularies," where a vocabulary is defined by the total number of independent tokens that we have in our corpus. + +Each word gets assigned an ID, starting from 0 and going up to the size of the vocabulary. The model uses these IDs to identify each word. + +If we want to completely cover a language with a word-based tokenizer, we'll need to have an identifier for each word in the language, which will generate a huge amount of tokens. For example, there are over 500,000 words in the English language, so to build a map from each word to an input ID we'd need to keep track of that many IDs. Furthermore, words like "dog" are represented differently from words like "dogs", and the model will initially have no way of knowing that "dog" and "dogs" are similar: it will identify the two words as unrelated. The same applies to other similar words, like "run" and "running", which the model will not see as being similar initially. + +Finally, we need a custom token to represent words that are not in our vocabulary. This is known as the "unknown" token, often represented as "[UNK]" or "<unk>". It's generally a bad sign if you see that the tokenizer is producing a lot of these tokens, as it wasn't able to retrieve a sensible representation of a word and you're losing information along the way. The goal when crafting the vocabulary is to do it in such a way that the tokenizer tokenizes as few words as possible into the unknown token. + +One way to reduce the amount of unknown tokens is to go one level deeper, using a _character-based_ tokenizer. + +## Character-based[[character-based]] + + + +Character-based tokenizers split the text into characters, rather than words. This has two primary benefits: + +- The vocabulary is much smaller. +- There are much fewer out-of-vocabulary (unknown) tokens, since every word can be built from characters. + +But here too some questions arise concerning spaces and punctuation: + +
+ An example of character-based tokenization. + +
+ +This approach isn't perfect either. Since the representation is now based on characters rather than words, one could argue that, intuitively, it's less meaningful: each character doesn't mean a lot on its own, whereas that is the case with words. However, this again differs according to the language; in Chinese, for example, each character carries more information than a character in a Latin language. + +Another thing to consider is that we'll end up with a very large amount of tokens to be processed by our model: whereas a word would only be a single token with a word-based tokenizer, it can easily turn into 10 or more tokens when converted into characters. + +To get the best of both worlds, we can use a third technique that combines the two approaches: *subword tokenization*. + +## Subword tokenization[[subword-tokenization]] + + + +Subword tokenization algorithms rely on the principle that frequently used words should not be split into smaller subwords, but rare words should be decomposed into meaningful subwords. + +For instance, "annoyingly" might be considered a rare word and could be decomposed into "annoying" and "ly". These are both likely to appear more frequently as standalone subwords, while at the same time the meaning of "annoyingly" is kept by the composite meaning of "annoying" and "ly". + +Here is an example showing how a subword tokenization algorithm would tokenize the sequence "Let's do tokenization!": + +
+ A subword tokenization algorithm. + +
+ +These subwords end up providing a lot of semantic meaning: for instance, in the example above "tokenization" was split into "token" and "ization", two tokens that have a semantic meaning while being space-efficient (only two tokens are needed to represent a long word). This allows us to have relatively good coverage with small vocabularies, and close to no unknown tokens. + +This approach is especially useful in agglutinative languages such as Turkish, where you can form (almost) arbitrarily long complex words by stringing together subwords. + +### And more![[and-more]] + +Unsurprisingly, there are many more techniques out there. To name a few: + +- Byte-level BPE, as used in GPT-2 +- WordPiece, as used in BERT +- SentencePiece or Unigram, as used in several multilingual models + +You should now have sufficient knowledge of how tokenizers work to get started with the API. + +## Loading and saving[[loading-and-saving]] + +Loading and saving tokenizers is as simple as it is with models. Actually, it's based on the same two methods: `from_pretrained()` and `save_pretrained()`. These methods will load or save the algorithm used by the tokenizer (a bit like the *architecture* of the model) as well as its vocabulary (a bit like the *weights* of the model). + +Loading the BERT tokenizer trained with the same checkpoint as BERT is done the same way as loading the model, except we use the `BertTokenizer` class: + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +Similar to `AutoModel`, the `AutoTokenizer` class will grab the proper tokenizer class in the library based on the checkpoint name, and can be used directly with any checkpoint: + +{:else} +Similar to `TFAutoModel`, the `AutoTokenizer` class will grab the proper tokenizer class in the library based on the checkpoint name, and can be used directly with any checkpoint: + +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +We can now use the tokenizer as shown in the previous section: + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +Saving a tokenizer is identical to saving a model: + +```py +tokenizer.save_pretrained("directory_on_my_computer") +``` + +We'll talk more about `token_type_ids` in [Chapter 3](/course/chapter3), and we'll explain the `attention_mask` key a little later. First, let's see how the `input_ids` are generated. To do this, we'll need to look at the intermediate methods of the tokenizer. + +## Encoding[[encoding]] + + + +Translating text to numbers is known as _encoding_. Encoding is done in a two-step process: the tokenization, followed by the conversion to input IDs. + +As we've seen, the first step is to split the text into words (or parts of words, punctuation symbols, etc.), usually called *tokens*. There are multiple rules that can govern that process, which is why we need to instantiate the tokenizer using the name of the model, to make sure we use the same rules that were used when the model was pretrained. + +The second step is to convert those tokens into numbers, so we can build a tensor out of them and feed them to the model. To do this, the tokenizer has a *vocabulary*, which is the part we download when we instantiate it with the `from_pretrained()` method. Again, we need to use the same vocabulary used when the model was pretrained. + +To get a better understanding of the two steps, we'll explore them separately. Note that we will use some methods that perform parts of the tokenization pipeline separately to show you the intermediate results of those steps, but in practice, you should call the tokenizer directly on your inputs (as shown in the section 2). + +### Tokenization[[tokenization]] + +The tokenization process is done by the `tokenize()` method of the tokenizer: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +The output of this method is a list of strings, or tokens: + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +This tokenizer is a subword tokenizer: it splits the words until it obtains tokens that can be represented by its vocabulary. That's the case here with `transformer`, which is split into two tokens: `transform` and `##er`. + +### From tokens to input IDs[[from-tokens-to-input-ids]] + +The conversion to input IDs is handled by the `convert_tokens_to_ids()` tokenizer method: + +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +These outputs, once converted to the appropriate framework tensor, can then be used as inputs to a model as seen earlier in this chapter. + + + +✏️ **Try it out!** Replicate the two last steps (tokenization and conversion to input IDs) on the input sentences we used in section 2 ("I've been waiting for a HuggingFace course my whole life." and "I hate this so much!"). Check that you get the same input IDs we got earlier! + + + +## Decoding[[decoding]] + +*Decoding* is going the other way around: from vocabulary indices, we want to get a string. This can be done with the `decode()` method as follows: + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` + +Note that the `decode` method not only converts the indices back to tokens, but also groups together the tokens that were part of the same words to produce a readable sentence. This behavior will be extremely useful when we use models that predict new text (either text generated from a prompt, or for sequence-to-sequence problems like translation or summarization). + +By now you should understand the atomic operations a tokenizer can handle: tokenization, conversion to IDs, and converting IDs back to a string. However, we've just scraped the tip of the iceberg. In the following section, we'll take our approach to its limits and take a look at how to overcome them. diff --git a/chapters/ru/chapter2/5.mdx b/chapters/ru/chapter2/5.mdx new file mode 100644 index 000000000..199877efb --- /dev/null +++ b/chapters/ru/chapter2/5.mdx @@ -0,0 +1,338 @@ + + +# Handling multiple sequences[[handling-multiple-sequences]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +In the previous section, we explored the simplest of use cases: doing inference on a single sequence of a small length. However, some questions emerge already: + +- How do we handle multiple sequences? +- How do we handle multiple sequences *of different lengths*? +- Are vocabulary indices the only inputs that allow a model to work well? +- Is there such a thing as too long a sequence? + +Let's see what kinds of problems these questions pose, and how we can solve them using the 🤗 Transformers API. + +## Models expect a batch of inputs[[models-expect-a-batch-of-inputs]] + +In the previous exercise you saw how sequences get translated into lists of numbers. Let's convert this list of numbers to a tensor and send it to the model: + +{#if fw === 'pt'} +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +input_ids = torch.tensor(ids) +# This line will fail. +model(input_ids) +``` + +```python out +IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +input_ids = tf.constant(ids) +# This line will fail. +model(input_ids) +``` + +```py out +InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape] +``` +{/if} + +Oh no! Why did this fail? "We followed the steps from the pipeline in section 2. + +The problem is that we sent a single sequence to the model, whereas 🤗 Transformers models expect multiple sentences by default. Here we tried to do everything the tokenizer did behind the scenes when we applied it to a `sequence`. But if you look closely, you'll see that the tokenizer didn't just convert the list of input IDs into a tensor, it added a dimension on top of it: + +{#if fw === 'pt'} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="pt") +print(tokenized_inputs["input_ids"]) +``` + +```python out +tensor([[ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, + 2607, 2026, 2878, 2166, 1012, 102]]) +``` +{:else} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="tf") +print(tokenized_inputs["input_ids"]) +``` + +```py out + +``` +{/if} + +Let's try again and add a new dimension: + +{#if fw === 'pt'} +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) + +input_ids = torch.tensor([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) + +input_ids = tf.constant([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{/if} + +We print the input IDs as well as the resulting logits — here's the output: + +{#if fw === 'pt'} +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` +{:else} +```py out +Input IDs: tf.Tensor( +[[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 + 2166 1012]], shape=(1, 14), dtype=int32) +Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32) +``` +{/if} + +*Batching* is the act of sending multiple sentences through the model, all at once. If you only have one sentence, you can just build a batch with a single sequence: + +``` +batched_ids = [ids, ids] +``` + +This is a batch of two identical sequences! + + + +✏️ **Try it out!** Convert this `batched_ids` list into a tensor and pass it through your model. Check that you obtain the same logits as before (but twice)! + + + +Batching allows the model to work when you feed it multiple sentences. Using multiple sequences is just as simple as building a batch with a single sequence. There's a second issue, though. When you're trying to batch together two (or more) sentences, they might be of different lengths. If you've ever worked with tensors before, you know that they need to be of rectangular shape, so you won't be able to convert the list of input IDs into a tensor directly. To work around this problem, we usually *pad* the inputs. + +## Padding the inputs[[padding-the-inputs]] + +The following list of lists cannot be converted to a tensor: + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` + +In order to work around this, we'll use *padding* to make our tensors have a rectangular shape. Padding makes sure all our sentences have the same length by adding a special word called the *padding token* to the sentences with fewer values. For example, if you have 10 sentences with 10 words and 1 sentence with 20 words, padding will ensure all the sentences have 20 words. In our example, the resulting tensor looks like this: + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` + +The padding token ID can be found in `tokenizer.pad_token_id`. Let's use it and send our two sentences through the model individually and batched together: + +{#if fw === 'pt'} +```py no-format +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence1_ids = [[200, 200, 200]] +sequence2_ids = [[200, 200]] +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +print(model(torch.tensor(sequence1_ids)).logits) +print(model(torch.tensor(sequence2_ids)).logits) +print(model(torch.tensor(batched_ids)).logits) +``` + +```python out +tensor([[ 1.5694, -1.3895]], grad_fn=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` +{:else} +```py no-format +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence1_ids = [[200, 200, 200]] +sequence2_ids = [[200, 200]] +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +print(model(tf.constant(sequence1_ids)).logits) +print(model(tf.constant(sequence2_ids)).logits) +print(model(tf.constant(batched_ids)).logits) +``` + +```py out +tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) +tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) +tf.Tensor( +[[ 1.5693681 -1.3894582] + [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32) +``` +{/if} + +There's something wrong with the logits in our batched predictions: the second row should be the same as the logits for the second sentence, but we've got completely different values! + +This is because the key feature of Transformer models is attention layers that *contextualize* each token. These will take into account the padding tokens since they attend to all of the tokens of a sequence. To get the same result when passing individual sentences of different lengths through the model or when passing a batch with the same sentences and padding applied, we need to tell those attention layers to ignore the padding tokens. This is done by using an attention mask. + +## Attention masks[[attention-masks]] + +*Attention masks* are tensors with the exact same shape as the input IDs tensor, filled with 0s and 1s: 1s indicate the corresponding tokens should be attended to, and 0s indicate the corresponding tokens should not be attended to (i.e., they should be ignored by the attention layers of the model). + +Let's complete the previous example with an attention mask: + +{#if fw === 'pt'} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask)) +print(outputs.logits) +``` + +```python out +tensor([[ 1.5694, -1.3895], + [ 0.5803, -0.4125]], grad_fn=) +``` +{:else} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) +print(outputs.logits) +``` + +```py out +tf.Tensor( +[[ 1.5693681 -1.3894582 ] + [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32) +``` +{/if} + +Now we get the same logits for the second sentence in the batch. + +Notice how the last value of the second sequence is a padding ID, which is a 0 value in the attention mask. + + + +✏️ **Try it out!** Apply the tokenization manually on the two sentences used in section 2 ("I've been waiting for a HuggingFace course my whole life." and "I hate this so much!"). Pass them through the model and check that you get the same logits as in section 2. Now batch them together using the padding token, then create the proper attention mask. Check that you obtain the same results when going through the model! + + + +## Longer sequences[[longer-sequences]] + +With Transformer models, there is a limit to the lengths of the sequences we can pass the models. Most models handle sequences of up to 512 or 1024 tokens, and will crash when asked to process longer sequences. There are two solutions to this problem: + +- Use a model with a longer supported sequence length. +- Truncate your sequences. + +Models have different supported sequence lengths, and some specialize in handling very long sequences. [Longformer](https://huggingface.co/docs/transformers/model_doc/longformer) is one example, and another is [LED](https://huggingface.co/docs/transformers/model_doc/led). If you're working on a task that requires very long sequences, we recommend you take a look at those models. + +Otherwise, we recommend you truncate your sequences by specifying the `max_sequence_length` parameter: + +```py +sequence = sequence[:max_sequence_length] +``` diff --git a/chapters/ru/chapter2/6.mdx b/chapters/ru/chapter2/6.mdx new file mode 100644 index 000000000..d26118501 --- /dev/null +++ b/chapters/ru/chapter2/6.mdx @@ -0,0 +1,164 @@ + + +# Putting it all together[[putting-it-all-together]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +In the last few sections, we've been trying our best to do most of the work by hand. We've explored how tokenizers work and looked at tokenization, conversion to input IDs, padding, truncation, and attention masks. + +However, as we saw in section 2, the 🤗 Transformers API can handle all of this for us with a high-level function that we'll dive into here. When you call your `tokenizer` directly on the sentence, you get back inputs that are ready to pass through your model: + +```py +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +Here, the `model_inputs` variable contains everything that's necessary for a model to operate well. For DistilBERT, that includes the input IDs as well as the attention mask. Other models that accept additional inputs will also have those output by the `tokenizer` object. + +As we'll see in some examples below, this method is very powerful. First, it can tokenize a single sequence: + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +It also handles multiple sequences at a time, with no change in the API: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +model_inputs = tokenizer(sequences) +``` + +It can pad according to several objectives: + +```py +# Will pad the sequences up to the maximum sequence length +model_inputs = tokenizer(sequences, padding="longest") + +# Will pad the sequences up to the model max length +# (512 for BERT or DistilBERT) +model_inputs = tokenizer(sequences, padding="max_length") + +# Will pad the sequences up to the specified max length +model_inputs = tokenizer(sequences, padding="max_length", max_length=8) +``` + +It can also truncate sequences: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# Will truncate the sequences that are longer than the model max length +# (512 for BERT or DistilBERT) +model_inputs = tokenizer(sequences, truncation=True) + +# Will truncate the sequences that are longer than the specified max length +model_inputs = tokenizer(sequences, max_length=8, truncation=True) +``` + +The `tokenizer` object can handle the conversion to specific framework tensors, which can then be directly sent to the model. For example, in the following code sample we are prompting the tokenizer to return tensors from the different frameworks — `"pt"` returns PyTorch tensors, `"tf"` returns TensorFlow tensors, and `"np"` returns NumPy arrays: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# Returns PyTorch tensors +model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") + +# Returns TensorFlow tensors +model_inputs = tokenizer(sequences, padding=True, return_tensors="tf") + +# Returns NumPy arrays +model_inputs = tokenizer(sequences, padding=True, return_tensors="np") +``` + +## Special tokens[[special-tokens]] + +If we take a look at the input IDs returned by the tokenizer, we will see they are a tiny bit different from what we had earlier: + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +print(model_inputs["input_ids"]) + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +print(ids) +``` + +```python out +[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102] +[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012] +``` + +One token ID was added at the beginning, and one at the end. Let's decode the two sequences of IDs above to see what this is about: + +```py +print(tokenizer.decode(model_inputs["input_ids"])) +print(tokenizer.decode(ids)) +``` + +```python out +"[CLS] i've been waiting for a huggingface course my whole life. [SEP]" +"i've been waiting for a huggingface course my whole life." +``` + +The tokenizer added the special word `[CLS]` at the beginning and the special word `[SEP]` at the end. This is because the model was pretrained with those, so to get the same results for inference we need to add them as well. Note that some models don't add special words, or add different ones; models may also add these special words only at the beginning, or only at the end. In any case, the tokenizer knows which ones are expected and will deal with this for you. + +## Wrapping up: From tokenizer to model[[wrapping-up-from-tokenizer-to-model]] + +Now that we've seen all the individual steps the `tokenizer` object uses when applied on texts, let's see one final time how it can handle multiple sequences (padding!), very long sequences (truncation!), and multiple types of tensors with its main API: + +{#if fw === 'pt'} +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") +output = model(**tokens) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="tf") +output = model(**tokens) +``` +{/if} diff --git a/chapters/ru/chapter2/7.mdx b/chapters/ru/chapter2/7.mdx index 708d47430..657aa28e9 100644 --- a/chapters/ru/chapter2/7.mdx +++ b/chapters/ru/chapter2/7.mdx @@ -1,18 +1,18 @@ -# Базовое использование завершено! +# Basic usage completed![[basic-usage-completed]] -Отличная работа, вы прошли курс до текущего момента! Напомним, что в этой главе вы: +Great job following the course up to here! To recap, in this chapter you: -- Изучил основные строительные блоки модели Transformer. -- Узнали, из чего состоит конвейер токенизации. -- Увидел, как использовать модель Transformer на практике. -- Научились использовать токенизатор для преобразования текста в тензоры, понятные модели. -- Настроили токенизатор и модель так, чтобы было возможно перейти от текста к прогнозированию. -- Изучили ограничения для входных идентификаторов и узнал о масках внимания. -- Поэкспериментировали с универсальными и настраиваемыми методами токенизатора. +- Learned the basic building blocks of a Transformer model. +- Learned what makes up a tokenization pipeline. +- Saw how to use a Transformer model in practice. +- Learned how to leverage a tokenizer to convert text to tensors that are understandable by the model. +- Set up a tokenizer and a model together to get from text to predictions. +- Learned the limitations of input IDs, and learned about attention masks. +- Played around with versatile and configurable tokenizer methods. -Теперь вы сможете свободно ориентироваться в документации 🤗 Transformers: словарный запас будет для вас знаком, и к тому уже вы видели методы, которые будете использовать большую часть времени. +From now on, you should be able to freely navigate the 🤗 Transformers docs: the vocabulary will sound familiar, and you've already seen the methods that you'll use the majority of the time. diff --git a/chapters/ru/chapter2/8.mdx b/chapters/ru/chapter2/8.mdx new file mode 100644 index 000000000..c41f27936 --- /dev/null +++ b/chapters/ru/chapter2/8.mdx @@ -0,0 +1,310 @@ + + + + +# End-of-chapter quiz[[end-of-chapter-quiz]] + + + +### 1. What is the order of the language modeling pipeline? + + + +### 2. How many dimensions does the tensor output by the base Transformer model have, and what are they? + +