diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml
index 0ec4ac451..575ac4556 100644
--- a/chapters/ru/_toctree.yml
+++ b/chapters/ru/_toctree.yml
@@ -135,6 +135,60 @@
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
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
diff --git a/chapters/ru/chapter8/1.mdx b/chapters/ru/chapter8/1.mdx
new file mode 100644
index 000000000..038e39e28
--- /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..08b975198
--- /dev/null
+++ b/chapters/ru/chapter8/2.mdx
@@ -0,0 +1,364 @@
+# Что делать, если возникла ошибка[[what-to-do-when-you-get-an-error]]
+
+
+
+В этом разделе мы рассмотрим некоторые распространенные ошибки, которые могут возникнуть при попытке сгенерировать предсказания на основе только что настроенной модели Transformer. Это подготовит вас к [разделу 4](../chapter8/4), где мы рассмотрим, как отладить сам этап обучения.
+
+
+
+Для этого раздела мы подготовили [репозиторий](https://huggingface.co/lewtun/distilbert-base-uncased-finetuned-squad-d5716d28), и если вы хотите запустить код в этой главе, вам сначала нужно скопировать модель в свой аккаунт на [Hugging Face Hub](https://huggingface.co). Для этого сначала авторизуйтесь на Hugging Face Hub. Если вы выполняете этот код в блокноте, вы можете сделать это с помощью следующей служебной функции:
+
+```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: 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, вы увидите что-то похожее на содержимое скриншота ниже:
+
+
+
+
+
+В этих отчетах содержится много информации, поэтому давайте вместе пройдемся по ключевым местам. Первое, что следует отметить, - это то, что трассировки следует читать _снизу вверх_. Это может показаться странным, если вы привыкли читать английский текст сверху вниз, но это логично: трассировка показывает последовательность вызовов функций, которые делает `pipeline` при загрузке модели и токенизатора. (Более подробно о том, как работает `pipeline` под капотом, читайте в [Главе 2](../chapter2/1)).
+
+
+
+🚨 Видите синюю рамку вокруг "6 frames" в трассировке Google Colab? Это специальная функция Colab, которая помещает отчет в раскрывающийся блок текста. Если вы не можете найти источник ошибки, обязательно раскройте этот блок, нажав на эти две маленькие стрелки.
+
+
+
+Последняя строка трассировки указывает на последнее сообщение об ошибке и дает имя исключения, которое было вызвано. В данном случае тип исключения - `OSError`, что указывает на системную ошибку. Если мы прочитаем сопроводительное сообщение об ошибке, то увидим, что, похоже, возникла проблема с файлом *config.json* модели, и нам предлагается два варианта ее устранения:
+
+```python out
+"""
+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
+"""
+```
+
+
+
+💡 Если вы столкнулись с сообщением об ошибке, которое трудно понять, просто скопируйте и вставьте его в строку поиска 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:
+
+
+
+
+
+Хм, действительно, похоже, что модели нашего коллеги нет на хабе... ага, но в названии модели опечатка! В названии DistilBERT есть только одна буква "l", так что давайте исправим это и поищем вместо нее "lewtun/distilbert-base-uncased-finetuned-squad-d5716d28":
+
+
+
+
+
+Хорошо! Теперь давайте попробуем загрузить модель снова с правильным идентификатором модели:
+
+```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
+# Выберем наиболее правдоподобную позицию начала ответа с помощью функции argmax
+answer_start = torch.argmax(answer_start_scores)
+# Выберем наиболее правдоподбную позицию окончания ответа с помощью функции 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])
+)
+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 в блокноте:
+
+
+
+или в терминале:
+
+
+
+Здесь чтение сообщения об ошибке говорит нам, что у объекта `'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/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)
+ 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). При нажатии на первый из них появляется вопрос, аналогичный нашему, ответ на который показан на скриншоте ниже:
+
+
+
+
+
+В ответе рекомендуется добавить в токенизатор `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
+# Выберем наиболее правдоподобную позицию начала ответа с помощью функции argmax
+answer_start = torch.argmax(answer_start_scores)
+# Выберем наиболее правдоподбную позицию окончания ответа с помощью функции 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])
+)
+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
diff --git a/chapters/ru/chapter8/3.mdx b/chapters/ru/chapter8/3.mdx
new file mode 100644
index 000000000..ad9fd9330
--- /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. Вот как выглядит главная страница в любой день:
+
+
+
+
+
+С левой стороны вы можете увидеть все категории, по которым сгруппированы различные темы, а с правой - самые последние темы. Тема - это сообщение, содержащее заголовок, категорию и описание; это очень похоже на формат вопросов 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) предназначены для более сложных вопросов, например, о библиотеках или новых крутых исследованиях в области НЛП, которые вы хотели бы обсудить.
+
+И, конечно же, нельзя не упомянуть категорию [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)! Мы не можем разобраться в полном её описании, поэтому решили обратиться за помощью на форум Hugging Face. Как мы можем создать тему?
+
+Чтобы начать, нам нужно нажать кнопку "Новая тема" в правом верхнем углу (обратите внимание, что для создания темы нам нужно войти в систему):
+
+
+
+
+
+Откроется интерфейс для написания текста, где мы можем ввести название темы, выбрать категорию и составить сообщение:
+
+
+
+
+
+Поскольку ошибка, похоже, связана исключительно с 🤗 Transformers, мы выберем эту категорию. Наша первая попытка объяснить проблему может выглядеть примерно так:
+
+
+
+
+
+Хотя эта тема содержит сообщение об ошибке, с которой нам нужна помощь, есть несколько проблем с тем, как оно написано:
+
+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, поэтому вы всегда должны заключать свои блоки кода в три обратных знака (```), чтобы их было легче читать. Давайте сделаем это, чтобы отформатировать сообщение об ошибке - и пока мы это делаем, давайте сделаем текст немного более вежливым, чем наша первоначальная версия:
+
+
+
+
+
+Как видно на скриншоте, заключение блоков кода в обратные кавычки превращает исходный текст в отформатированный код, дополненный цветовой стилизацией! Также обратите внимание, что одиночные обратные кавычки могут быть использованы для форматирования встроенных переменных, как мы это сделали для `distilbert-base-uncased`. В таком оформлении сообщение выглядит гораздо лучше, и, если повезет, мы сможем найти кого-то из сообщества, кто догадается, в чем ошибка. Но вместо того, чтобы полагаться на удачу, давайте облегчим себе жизнь, включив трассировку во всех подробностях!
+
+### Добавьте текст полной трассировки[[including-the-full-traceback]]
+
+Как видно на скриншоте, заключение блоков кода в обратные знаки превращает исходный текст в отформатированный код, дополненный цветовой стилизацией! Также обратите внимание, что одиночные обратные знаки могут быть использованы для форматирования встроенных переменных, как мы это сделали для `distilbert-base-uncased`. Эта тема выглядит гораздо лучше, и, если повезет, мы сможем найти кого-то из сообщества, кто догадается, в чем ошибка. Однако вместо того, чтобы полагаться на удачу, давайте облегчим себе жизнь, включив в трассировку все подробности!
+
+
+
+
+
+Это гораздо более информативно, и внимательный читатель сможет указать на то, что проблема, похоже, связана с передачей длинного входного сигнала из-за этой строки в трассировке:
+
+> Token indices sequence length is longer than the specified maximum sequence length for this model (583 > 512).
+
+Однако мы можем еще больше облегчить им задачу, предоставив фактический код, вызвавший ошибку. Давайте сделаем это прямо сейчас.
+
+### Предоставьте воспроизводимый пример[[providing-a-reproducible-example]]
+
+Если вы когда-нибудь пытались отладить чужой код, вы, вероятно, сначала пытались воссоздать проблему, о которой они сообщали, чтобы начать работать над трассировкой, чтобы точно определить ошибку. Это не отличается от того, когда речь идет о получении (или предоставлении) помощи на форумах, поэтому очень помогает, если вы можете предоставить небольшой пример, воспроизводящий ошибку. В половине случаев простое выполнение этого упражнения поможет вам понять, что происходит не так. В любом случае, недостающий фрагмент нашего примера - это показать _входы_, которые мы предоставили модели. Выполнив это, мы получим нечто похожее на следующий завершенный пример:
+
+
+
+
+
+Теперь эта сообщение содержит достаточно много информации, и оно написана таким образом, что с гораздо большей вероятностью привлечет внимание сообщества и получит полезный ответ. Используя эти основные правила, вы сможете создавать отличные темы для поиска ответов на ваши вопросы по библиотеке 🤗 Transformers!
+
diff --git a/chapters/ru/chapter8/4.mdx b/chapters/ru/chapter8/4.mdx
new file mode 100644
index 000000000..2141a5afe
--- /dev/null
+++ b/chapters/ru/chapter8/4.mdx
@@ -0,0 +1,791 @@
+
+
+# Отладка обучения[[debugging-the-training-pipeline]]
+
+
+
+Вы написали прекрасный сценарий для обучения или дообучения модели на заданной задаче, послушно следуя советам из [Главы 7](/course/chapter7/1). Но когда вы запускаете команду `model.fit()`, происходит нечто ужасное: вы получаете ошибку 😱! Или, что еще хуже, все вроде бы хорошо, обучение проходит без ошибок, но результирующая модель получается плохой. В этом разделе мы покажем вам, что можно сделать для отладки подобных проблем.
+
+## Отладка обучающего пайплайна[[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% уверенными в их правильности.
+
+При отладке обучения всегда нужно смотреть на декодированные входы модели. Мы не можем понять смысл чисел, которые подаем ей напрямую, поэтому мы должны посмотреть, что эти числа представляют. В компьютерном зрении, например, это означает просмотр декодированных изображений пройденных пикселей, в речи - прослушивание декодированных образцов звука, а в нашем примере с NLP - использование нашего токенизатора для декодирования входных данных:
+
+```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
+```
+
+Итак, в нашем случае мы можем проверить принятые параметры на [этой странице](https://huggingface.co/transformers/model_doc/distilbert.html#distilbertforsequenceclassification). "Trainer" также будет регистрировать столбцы, которые он отбрасывает.
+
+Мы проверили правильность входных идентификаторов, декодировав их. Далее находится `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, ранее мы упоминали особый случай. Давайте посмотрим на него сейчас.
+
+### Как справиться с ошибками нехватки памяти[[dealing-with-cuda-out-of-memory-errors]]
+
+Если вы получаете сообщение об ошибке, начинающееся с `RuntimeError: CUDA out of memory`, это означает, что вам не хватает памяти GPU. Это не связано напрямую с вашим кодом, и может произойти со скриптом, который работает совершенно нормально. Эта ошибка означает, что вы пытались поместить слишком много данных во внутреннюю память вашего GPU, и это привело к ошибке. Как и в случае с другими ошибками CUDA, вам придется перезапустить ядро, чтобы снова запустить обучение.
+
+Чтобы решить эту проблему, нужно просто использовать меньше памяти на GPU - что зачастую легче сказать, чем сделать. Во-первых, убедитесь, что у вас нет двух моделей на GPU одновременно (если, конечно, это не требуется для решения вашей задачи). Затем, вероятно, следует уменьшить размер батча, поскольку он напрямую влияет на размеры всех промежуточных выходов модели и их градиентов. Если проблема сохраняется, подумайте о том, чтобы использовать меньшую версию модели.
+
+
+
+В следующей части курса мы рассмотрим более продвинутые техники, которые помогут вам уменьшить объем занимаемой памяти и позволят точно настроить самые большие модели.
+
+
+
+### Валидация модели[[evaluating-the-model]]
+
+Теперь, когда мы решили все проблемы с нашим кодом, все идеально, и обучение должно пройти гладко, верно? Не так быстро! Если вы запустите команду `trainer.train()`, сначала все будет выглядеть хорошо, но через некоторое время вы получите следующее:
+
+```py
+# Это займет много времени и приведет к ошибке, поэтому не стоит запускать эту ячейку
+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..c88ce58e1
--- /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
+```
+
+О, нет.
+
+"nan" — не очень обнадеживающаее значение функции потерь. Тем не менее, мы проверили наши данные, и они выглядят довольно хорошо. Если проблема не в этом, как двигаться дальше? Очевидным следующим шагом будет...
+
+### Проверка модели[[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)
+```
+
+После запуска получим:
+
+```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: если вы задаете функцию потерь, оптимизатора или активации с помощью строки, _все ее аргументы будут установлены в значения по умолчанию_. Это означает, что, несмотря на удобство использования такого способа, следует быть очень осторожным, так как это может легко скрыть от вас критические вещи. (Любой, кто попробует решить опциональную задачу, описанную выше, должен внимательно отнестись к этому факту).
+
+В данном случае где мы задали аргумент с помощью строки? Изначально мы так делали с функцией потерь, но мы это исправили. Теперь мы задаем оптимизатор с помощью строки. Может ли это что-то скрывать от нас? Давайте посмотрим на [его аргументы](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]]
+
+Мы рассмотрели проблемы, описанные в скрипте выше, но есть еще несколько распространенных ошибок, с которыми вы можете столкнуться. Давайте рассмотрим (очень неполный) список.
+
+### Как справиться с ошибками нехватки памяти[[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`, гораздо легче запускать, и они обучаются гораздо быстрее.
+
+
+
+В следующей части курса мы рассмотрим более продвинутые техники, которые помогут вам уменьшить объем занимаемой памяти и позволят дообучить самые большие модели.
+
+
+
+### "Голодный" TensorFlow 🦛[[hungry-hungry-tensorflow]]
+
+Одна особенность TensorFlow, о которой вам следует знать, заключается в том, что он выделяет *всю* память GPU под себя, как только вы загружаете модель или проводите обучение, а затем делит эту память по мере необходимости. Это отличается от поведения других фреймворков, например PyTorch, которые выделяют память по мере необходимости с помощью CUDA, а не делают это внутренне. Одним из преимуществ подхода TensorFlow является то, что он может часто выдавать полезные ошибки, когда у вас заканчивается память, и он может восстановиться из этого состояния без сбоя всего ядра CUDA. Но есть и важный недостаток: если вы запускаете два процесса TensorFlow одновременно, то **у вас будут проблемы**.
+
+Если вы работаете на Colab, то вам не нужно беспокоиться об этом, но если вы работаете локально, то это определенно то, с чем вам следует быть осторожным. В частности, имейте в виду, что закрытие вкладки ноутбука не обязательно приведет к его закрытию! Вам может понадобиться выбрать работающие блокноты (те, что с зеленым значком) и вручную закрыть их в списке каталогов. Любой запущенный блокнот, использующий TensorFlow, может по-прежнему занимать много памяти GPU, а это значит, что любой новый запущенный блокнот может столкнуться с очень странными проблемами.
+
+Если вы начинаете получать ошибки о CUDA, BLAS или cuBLAS в коде, который работал раньше, то очень часто причина кроется именно в этом. Вы можете использовать такую команду, как `nvidia-smi`, чтобы проверить - когда вы выключаете или перезапускаете текущий ноутбук, большая часть памяти свободна или она все еще используется? Если она все еще используется, значит, что-то еще держится за нее!
+
+
+### Проверьте свои данные (еще раз!)[[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 вы столкнулись с чем-то, что кажется вам неправильным, возможно, вы обнаружили ошибку. Вам обязательно нужно рассказать нам об этом, и в следующем разделе мы объясним, как именно это сделать.
diff --git a/chapters/ru/chapter8/5.mdx b/chapters/ru/chapter8/5.mdx
new file mode 100644
index 000000000..c24eabf50
--- /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]]
+
+Как только проблема будет зарегистрирована, не забудьте быстро проверить, все ли в порядке. Вы можете отредактировать вопрос, если допустили ошибку, или даже изменить его название, если поймете, что проблема отличается от того, что вы думали вначале.
+
+Нет смысла писать людям, если вы не получите ответа. Если никто не поможет вам в течение нескольких дней, скорее всего, никто не смог разобраться в вашей проблеме. Не стесняйтесь возвращаться к воспроизводимому примеру. Можете ли вы сделать его короче и понятнее? Если вы не получите ответа в течение недели, вы можете оставить сообщение с просьбой о помощи, особенно если вы отредактировали свой вопрос, чтобы включить в него больше информации о проблеме.
+
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..3cfc8670b
--- /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`??
+
+
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]]
+
+
+
+
+
+
+Чтобы добавить дополнительный контент в демо, класс `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..202e47b0f
--- /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() # загрузим модель
+
+# Загрузим человекочитаемые метки для 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..de0e1f8db
--- /dev/null
+++ b/chapters/ru/chapter9/7.mdx
@@ -0,0 +1,239 @@
+# Введение в 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..5b94f5eb6
--- /dev/null
+++ b/chapters/ru/events/1.mdx
@@ -0,0 +1,34 @@
+# Занятия и семинары[[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..443cc1167
--- /dev/null
+++ b/chapters/ru/events/2.mdx
@@ -0,0 +1,135 @@
+# Событие посвященное выходу 2 части курса[[part-2-release-event]]
+
+В связи с выходом второй части курса мы организовали живую встречу с двумя днями выступлений перед спринтом по доработке. Если вы пропустили это мероприятие, вы можете просмотреть все выступления, которые перечислены ниже!
+
+## День 1: Высокоуровневое представление о трансформерах и о том, как их обучать[[day-1-a-high-level-view-of-transformers-and-how-to-train-them]]
+
+**Томас Вульф:** *Трансферное обучение и рождение библиотеки Transformers*
+
+
+
+
+
+
+
+Томас Вольф - соучредитель и главный научный директор компании 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).
+
+**Джей Аламмар:** *Легкое визуальное введение в модели трансформеры*
+
+
+
+
+
+
+
+Благодаря своему популярному блогу Джей помог миллионам исследователей и инженеров наглядно понять инструменты и концепции машинного обучения - от базовых (заканчивая документами по NumPy, Pandas) до самых современных (Transformers, BERT, GPT-3).
+
+**Маргарет Митчелл:** *О ценностях в разработке ML*
+
+
+
+
+
+
+
+Маргарет Митчелл - исследователь, работающий в области этики ИИ. В настоящее время она занимается вопросами разработки ИИ с учетом этических норм в технологиях. Она опубликовала более 50 работ по генерации естественного языка, ассистивным технологиям, компьютерному зрению и этике ИИ, а также имеет множество патентов в области генерации диалогов и классификации настроений. Ранее она работала в Google AI в качестве штатного научного сотрудника, где основала и возглавила группу Google Ethical AI, которая занималась фундаментальными исследованиями в области этики ИИ и операционализацией этики ИИ внутри Google. До прихода в Google она работала исследователем в Microsoft Research, занимаясь вопросами создания компьютерного зрения и языка, а также была постдокторантом в Университете Джонса Хопкинса, занимаясь байесовским моделированием и извлечением информации. Она получила докторскую степень в области компьютерных наук в Абердинском университете и степень магистра в области вычислительной лингвистики в Вашингтонском университете. В период с 2005 по 2012 год она также работала в области машинного обучения, неврологических расстройств и вспомогательных технологий в Орегонском университете здоровья и науки. Она была инициатором ряда семинаров и инициатив на пересечении многообразия, инклюзивности, компьютерных наук и этики. Ее работа была отмечена наградами министра обороны Эша Картера и Американского фонда поддержки слепых, а также была внедрена несколькими технологическими компаниями. Она любит садоводство, собак и кошек.
+
+**Мэттью Уотсон и Чэнь Цянь:** *Рабочие процессы NLP с Keras*
+
+
+
+
+
+
+
+Мэтью Уотсон - инженер по машинному обучению в команде Keras, специализирующийся на высокоуровневых API для моделирования. Он изучал компьютерную графику в бакалавриате и получил степень магистра в Стэнфордском университете. Получив английское образование, он выбрал компьютерную науку, но очень любит работать с разными дисциплинами и делать NLP доступным для широкой аудитории.
+
+Чен Цянь - инженер-программист из команды Keras, специализирующийся на высокоуровневых API для моделирования. Чен получил степень магистра электротехники в Стэнфордском университете и особенно интересуется упрощением имплементации в коде задач ML и крупномасштабным ML проектов.
+
+**Марк Саруфим:** *Как обучить модель с помощью Pytorch*
+
+
+
+
+
+
+
+Марк Саруфим - инженер-партнер компании Pytorch, работающий над производственными инструментами OSS, включая TorchServe и Pytorch Enterprise. В прошлом Марк был прикладным ученым и менеджером по продуктам в Graphcore, [yuri.ai](http://yuri.ai/), Microsoft и NASA's JPL. Его главная страсть - сделать программирование более увлекательным.
+
+**Якоб Ушкорейт:** *Не сломалось, так не чини! Давай сломаем)*
+
+
+
+
+
+
+
+Якоб Ушкорейт - соучредитель компании 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 как средство для совместной работы и обмена проектами по машинному обучению*
+
+
+
+
+
+
+
+Лисандр - инженер по машинному обучению в компании Hugging Face, где он участвует во многих проектах с открытым исходным кодом. Его цель - сделать машинное обучение доступным для всех, разрабатывая мощные инструменты с очень простым API.
+
+**Люсиль Сольнье:** *Получите свой собственный токенизатор с помощью 🤗 Transformers & 🤗 Tokenizers*
+
+
+
+Люсиль - инженер по машинному обучению в компании Hugging Face, занимается разработкой и поддержкой использования инструментов с открытым исходным кодом. Она также активно участвует во многих исследовательских проектах в области обработки естественного языка, таких как коллаборативное обучение и BigScience.
+
+**Сильвен Гуггер:** *Ускорьте цикл обучения PyTorch с помощью 🤗 Accelerate*
+
+
+
+Сильвен - инженер-исследователь в Hugging Face, один из основных сопровождающих 🤗 Transformers и разработчик 🤗 Accelerate. Ему нравится делать обучение моделей более доступным.
+
+**Мерве Ноян:** *Демонстрируйте свои демо моделей с помощью 🤗 Spaces*
+
+
+
+Мерве - сторонник разработчиков (developer advocate) в Hugging Face, занимается разработкой инструментов и созданием контента для них, чтобы сделать машинное обучение демократичным для всех.
+
+**Абубакар Абид:** *Быстрое создание приложений машинного обучения*
+
+
+
+
+
+
+
+Абубакар Абид - CEO компании [Gradio](www.gradio.app). В 2015 году он получил степень бакалавра наук по электротехнике и информатике в Массачусетском технологическом институте, а в 2021 году - степень доктора наук по прикладному машинному обучению в Стэнфорде. В качестве генерального директора Gradio Абубакар работает над тем, чтобы облегчить демонстрацию, отладку и развертывание моделей машинного обучения.
+
+**Матье Десве:** *AWS ML Vision: Сделать машинное обучение доступным для всех пользователей*
+
+
+
+
+
+
+
+Энтузиаст технологий, в свободное время занимаюсь творчеством. Мне нравятся задачи и решение проблем клиентов и пользователей, а также работа с талантливыми людьми, чтобы учиться каждый день. С 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**
+
+
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