Buckets:

rtrm's picture
|
download
raw
27.4 kB
# Что делать, если возникла ошибка[[what-to-do-when-you-get-an-error]]
<CourseFloatingBanner chapter={8}
classNames="absolute z-10 right-0 top-0"
notebook={[
{label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter8/section2.ipynb"},
{label: "Aws Studio", значение: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter8/section2.ipynb"},
]} />
В этом разделе мы рассмотрим некоторые распространенные ошибки, которые могут возникнуть при попытке сгенерировать предсказания на основе только что настроенной модели Transformer. Это подготовит вас к [разделу 4](../chapter8/4), где мы рассмотрим, как отладить сам этап обучения.
<Youtube id="DQ-CpJn6Rc4" />
Для этого раздела мы подготовили [репозиторий](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, вы увидите что-то похожее на содержимое скриншота ниже:
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/traceback.png" alt="A Python traceback." width="100%"/>
</div>
В этих отчетах содержится много информации, поэтому давайте вместе пройдемся по ключевым местам. Первое, что следует отметить, - это то, что трассировки следует читать _снизу вверх_. Это может показаться странным, если вы привыкли читать английский текст сверху вниз, но это логично: трассировка показывает последовательность вызовов функций, которые делает `pipeline` при загрузке модели и токенизатора. (Более подробно о том, как работает `pipeline` под капотом, читайте в [Главе 2](../chapter2/1)).
> [!TIP]
> 🚨 Видите синюю рамку вокруг "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
"""
```
> [!TIP]
> 💡 Если вы столкнулись с сообщением об ошибке, которое трудно понять, просто скопируйте и вставьте его в строку поиска 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:
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/wrong-model-id.png" alt="The wrong model name." width="100%"/>
</div>
Хм, действительно, похоже, что модели нашего коллеги нет на хабе... ага, но в названии модели опечатка! В названии DistilBERT есть только одна буква "l", так что давайте исправим это и поищем вместо нее "lewtun/distilbert-base-uncased-finetuned-squad-d5716d28":
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/true-model-id.png" alt="The right model name." width="100%"/>
</div>
Хорошо! Теперь давайте попробуем загрузить модель снова с правильным идентификатором модели:
```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)
```
> [!WARNING]
> 🚨 Применяемый здесь подход не является надежным, поскольку наш коллега мог изменить конфигурацию `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 <module>
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 в блокноте:
<Youtube id="rSPyvPw0p9k"/>
или в терминале:
<Youtube id="5PkZ4rbHL6c"/>
Здесь чтение сообщения об ошибке говорит нам, что у объекта `'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). При нажатии на первый из них появляется вопрос, аналогичный нашему, ответ на который показан на скриншоте ниже:
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/stack-overflow.png" alt="An answer from Stack Overflow." width="100%"/>
</div>
В ответе рекомендуется добавить в токенизатор `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/) есть гостеприимное сообщество разработчиков, которые могут вам помочь! В следующем разделе мы рассмотрим, как составить хорошие вопросы на форуме, на которые, скорее всего, будет получен ответ.
<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ru/chapter8/2.mdx" />

Xet Storage Details

Size:
27.4 kB
·
Xet hash:
bdbeae6e08e647614e6f7ab4dcc6354e00d314a62471e159240505024388dc72

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.