NLP 課程文件

遇到錯誤怎麼辦

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強型文件體驗

開始使用

遇到錯誤怎麼辦

Ask a Question Open In Colab Open In Studio Lab

在本節中,我們將研究一些常見錯誤,這些錯誤可能在您嘗試從新調整的 Transformer 模型中生成預測時出現。這將為您準備 第 4 節,我們將在其中探索如何除錯訓練階段本身。

我們為本節準備了一個 模板模型儲存庫,如果您想在本節中執行程式碼,則需要先將模型複製到您在 Hugging Face Hub 上的帳戶中。為此,首先透過在 Jupyter 筆記本中執行以下任一項進行登入

from huggingface_hub import notebook_login

notebook_login()

或在您喜歡的終端中執行以下內容

huggingface-cli login

這將提示您輸入使用者名稱和密碼,並將令牌儲存在 ~/.cache/huggingface/ 下。登入後,您可以使用以下函式複製模板儲存庫

from distutils.dir_util import copy_tree
from huggingface_hub import Repository, snapshot_download, create_repo, get_full_repo_name


def copy_repository_template():
    # Clone the repo and extract the local path
    template_repo_id = "lewtun/distilbert-base-uncased-finetuned-squad-d5716d28"
    commit_hash = "be3eaffc28669d7932492681cd5f3e8905e358b4"
    template_repo_dir = snapshot_download(template_repo_id, revision=commit_hash)
    # Create an empty repo on the Hub
    model_name = template_repo_id.split("/")[1]
    create_repo(model_name, exist_ok=True)
    # Clone the empty repo
    new_repo_id = get_full_repo_name(model_name)
    new_repo_dir = model_name
    repo = Repository(local_dir=new_repo_dir, clone_from=new_repo_id)
    # Copy files
    copy_tree(template_repo_dir, new_repo_dir)
    # Push to Hub
    repo.push_to_hub()

現在,當您呼叫 copy_repository_template() 時,它將在您的帳戶下建立一個模板儲存庫的副本。

從 🤗 Transformers 除錯管道

為了開始我們進入 Transformer 模型除錯精彩世界的旅程,請考慮以下場景:您正在與同事一起進行問答專案,以幫助電子商務網站的客戶找到有關消費產品的答案。您的同事給您發了這樣一條訊息

你好!我剛剛使用 Hugging Face 課程 第 7 章 中的技術進行了一個實驗,並在 SQuAD 上獲得了很棒的結果!我認為我們可以使用這個模型作為我們專案的起點。該模型在 Hub 上的 ID 是“lewtun/distillbert-base-uncased-finetuned-squad-d5716d28”。隨時進行測試 :)

您想到的第一件事是使用 🤗 Transformers 中的 pipeline 載入模型

from transformers import pipeline

model_checkpoint = get_full_repo_name("distillbert-base-uncased-finetuned-squad-d5716d28")
reader = pipeline("question-answering", model=model_checkpoint)
"""
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 追溯(也稱為堆疊跟蹤)的更大型錯誤報告的最後一部分。例如,如果您在 Google Colab 上執行此程式碼,您應該會看到類似以下螢幕截圖的內容

A Python traceback.

這些報告包含很多資訊,所以讓我們一起瀏覽關鍵部分。首先要注意的是,應該從下到上閱讀追溯。如果您習慣於從上到下閱讀英文文字,這聽起來可能很奇怪,但這反映了追溯顯示了 pipeline 在下載模型和分詞器時進行的一系列函式呼叫順序。(檢視 第 2 章,瞭解有關 pipeline 如何在幕後工作的更多詳細資訊。)

🚨 您看到 Google Colab 追溯中的“6 個幀”周圍的藍色方框了嗎?這是 Colab 的一個特殊功能,它將追溯壓縮成“幀”。如果您似乎找不到錯誤的來源,請確保透過點選這兩個小箭頭展開完整追溯。

這意味著追溯的最後一行指示最後一個錯誤訊息,並給出已引發的異常的名稱。在本例中,異常型別為 OSError,表示系統相關錯誤。如果我們閱讀隨附的錯誤訊息,我們可以看到似乎存在模型的config.json 檔案問題,並且我們被提供了兩個修復建議

"""
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 搜尋欄中(真的,就這麼做!)。很有可能您不是第一個遇到該錯誤的人,這是一種找到社群中其他人釋出的解決方案的好方法。例如,在 Stack Overflow 上搜索 OSError: Can't load config for 會給出幾個 命中結果,可以將其用作解決問題的起點。

第一個建議是讓我們檢查模型 ID 是否確實正確,因此首要任務是複製識別符號並將其貼上到 Hub 的搜尋欄中

The wrong model name.

嗯,看起來我們的同事的模型不在 Hub 上……啊哈,但模型名稱中有一個拼寫錯誤!DistilBERT 的名稱中只有一個“l”,所以讓我們糾正一下,然後搜尋“lewtun/distilbert-base-uncased-finetuned-squad-d5716d28”

The right model name.

好的,這樣就找到結果了。現在讓我們嘗試使用正確的模型 ID 再次下載模型

model_checkpoint = get_full_repo_name("distilbert-base-uncased-finetuned-squad-d5716d28")
reader = pipeline("question-answering", model=model_checkpoint)
"""
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
"""

啊,又被阻止了——歡迎來到機器學習工程師的日常生活!由於我們已經修正了模型 ID,問題一定在於儲存庫本身。快速訪問 🤗 Hub 上儲存庫內容的一種方法是使用 huggingface_hub 庫的 list_repo_files() 函式

from huggingface_hub import list_repo_files

list_repo_files(repo_id=model_checkpoint)
['.gitattributes', 'README.md', 'pytorch_model.bin', 'special_tokens_map.json', 'tokenizer_config.json', 'training_args.bin', 'vocab.txt']

有趣的是——儲存庫中似乎沒有config.json 檔案!難怪我們的 pipeline 無法載入模型;我們的同事一定是在微調模型後忘記將此檔案推送到 Hub 上了。在這種情況下,問題似乎很容易解決:我們可以要求他們新增該檔案,或者,由於我們可以從模型 ID 中看到使用的預訓練模型是 distilbert-base-uncased,我們可以下載此模型的配置並將其推送到我們的儲存庫中,看看是否能解決問題。讓我們試試。使用我們在 第 2 章 中學習的技術,我們可以使用 AutoConfig 類下載模型的配置

from transformers import AutoConfig

pretrained_checkpoint = "distilbert-base-uncased"
config = AutoConfig.from_pretrained(pretrained_checkpoint)

🚨 我們在這裡採用的方法並非萬無一失,因為我們的同事可能在微調模型之前調整了 distilbert-base-uncased 的配置。在現實生活中,我們想先與他們核實,但為了本節的目的,我們將假設他們使用了預設配置。

然後,我們可以使用配置的 push_to_hub() 函式將它推送到我們的模型儲存庫

config.push_to_hub(model_checkpoint, commit_message="Add config.json")

現在,我們可以透過從 main 分支上的最新提交載入模型來測試它是否有效

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)
{'score': 0.38669535517692566,
 'start': 34,
 'end': 95,
 'answer': 'the task of extracting an answer from a text given a question'}

太好了,成功了!讓我們回顧一下您剛學到的內容

  • Python 中的錯誤訊息稱為追溯,從下到上閱讀。錯誤訊息的最後一行通常包含您需要查詢問題來源的資訊。
  • 如果最後一行沒有包含足夠的資訊,請向上追溯,看看您是否可以確定錯誤發生在原始碼中的哪個位置。
  • 如果沒有任何錯誤訊息可以幫助您除錯問題,請嘗試線上搜尋類似問題的解決方案。
  • huggingface_hub // 🤗 Hub?庫提供了一套工具,您可以使用這些工具與 Hub 上的儲存庫進行互動並除錯儲存庫。

既然您已經瞭解瞭如何除錯管道,那麼讓我們看看模型本身的前向傳遞中一個更棘手的示例。

除錯模型的前向傳播

雖然 pipeline 在大多數需要快速生成預測的應用中都很好用,但有時您需要訪問模型的 logits(比如,如果您想要應用一些自定義後處理)。為了瞭解在這種情況下可能出現的問題,讓我們首先從 pipeline 中獲取模型和 tokenizer

tokenizer = reader.tokenizer
model = reader.model

接下來我們需要一個問題,讓我們看看我們最喜歡的框架是否受支援

question = "Which frameworks can I use?"

正如我們在第 7 章 中看到的那樣,我們需要採取的步驟是將輸入進行標記化,提取開始和結束標記的 logits,然後解碼答案跨度

import torch

inputs = tokenizer(question, context, add_special_tokens=True)
input_ids = inputs["input_ids"][0]
outputs = model(**inputs)
answer_start_scores = outputs.start_logits
answer_end_scores = outputs.end_logits
# Get the most likely beginning of answer with the argmax of the score
answer_start = torch.argmax(answer_start_scores)
# Get the most likely end of answer with the argmax of the score
answer_end = torch.argmax(answer_end_scores) + 1
answer = tokenizer.convert_tokens_to_string(
    tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end])
)
print(f"Question: {question}")
print(f"Answer: {answer}")
"""
---------------------------------------------------------------------------
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'
"""

哦,天哪,看來我們的程式碼中有一個 bug!但我們不怕除錯。您可以在筆記本中使用 Python 偵錯程式

或在終端中

在這裡,閱讀錯誤訊息告訴我們 'list' 物件沒有屬性 'size',我們可以看到一個 --> 箭頭指向 model(**inputs) 中引發問題的行。您可以使用 Python 偵錯程式互動式地除錯此問題,但現在我們將簡單地打印出 inputs 的一部分以檢視我們有什麼

inputs["input_ids"][:5]
[101, 2029, 7705, 2015, 2064]

這看起來確實像一個普通的 Python list,但讓我們仔細檢查一下型別

type(inputs["input_ids"])
list

沒錯,那肯定是一個 Python list。那麼哪裡出錯了?回想一下第 2 章 中 🤗 Transformers 中的 AutoModelForXxx 類在張量(在 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 上搜索錯誤訊息會給出一些相關的結果。點選第一個結果顯示了一個與我們類似的問題,答案如下圖所示

An answer from Stack Overflow.

答案建議我們在 tokenizer 中新增 return_tensors='pt',讓我們看看這對我們是否有用

inputs = tokenizer(question, context, add_special_tokens=True, return_tensors="pt")
input_ids = inputs["input_ids"][0]
outputs = model(**inputs)
answer_start_scores = outputs.start_logits
answer_end_scores = outputs.end_logits
# Get the most likely beginning of answer with the argmax of the score
answer_start = torch.argmax(answer_start_scores)
# Get the most likely end of answer with the argmax of the score
answer_end = torch.argmax(answer_end_scores) + 1
answer = tokenizer.convert_tokens_to_string(
    tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end])
)
print(f"Question: {question}")
print(f"Answer: {answer}")
"""
Question: Which frameworks can I use?
Answer: pytorch, tensorflow, and jax
"""

太好了,成功了!這是一個很好的例子,說明 Stack Overflow 有多麼有用:透過識別一個類似的問題,我們能夠從社群中其他人的經驗中受益。但是,這樣的搜尋並不總是能找到相關的答案,在這種情況下,你能做什麼?幸運的是,在Hugging Face 論壇 上有一個友好的開發人員社群可以幫助你!在下一節中,我們將看看如何編寫有效的論壇問題,這樣更有可能得到解答。

© . This site is unofficial and not affiliated with Hugging Face, Inc.