微调 HuggingFace NLI 模型(RoBERTa/BART)时,损失为“nan”

Posted

技术标签:

【中文标题】微调 HuggingFace NLI 模型(RoBERTa/BART)时,损失为“nan”【英文标题】:Loss is “nan” when fine-tuning HuggingFace NLI model (both RoBERTa/BART) 【发布时间】:2021-03-27 15:20:49 【问题描述】:

我正在使用 HuggingFace 的 Transformer 库,我正在尝试在大约 276.000 个假设-前提对的数据集上微调一个预训练的 NLI 模型 (ynie/roberta-large-snli_mnli_fever_anli_R1_R2_R3-nli)。我按照文档 here 和 here 的说明进行操作。我的印象是微调有效(它进行训练并保存检查点),但 trainer.train()trainer.evaluate() 为损失返回“nan”。

我的尝试:

我尝试同时使用 ynie/roberta-large-snli_mnli_fever_anli_R1_R2_R3-nlifacebook/bart-large-mnli 以确保它未链接到特定型号,但我发现这两种型号都有问题 我尝试按照related github issue 中的建议进行操作,但将num_labels=3 添加到配置文件并不能解决问题。 (我认为我的问题有所不同,因为在我的案例中,模型已经在 NLI 上进行了微调) 我尝试了许多不同的方法来更改我的输入数据,因为我怀疑我的输入数据可能存在问题,但我也无法以这种方式解决它。 问题的可能来源: 我在训练期间检查了模型的预测输出,奇怪的是预测值在 100% 的情况下似乎总是“0”(蕴含) (请参阅下面代码中的打印输出)。这显然是一个错误。我认为这是因为模型在训练期间返回的 logits 似乎是 torch.tensor([[np.nan, np.nan, np.nan]]),当你将 .argmax(-1) 应用到这个时,你会得到 torch.tensor(0)。对我来说最大的谜团是为什么 logits 会变成“nan”,因为当我只在训练器之外使用相同的输入数据时,模型不会这样做。 => 有谁知道这个问题来自哪里?请参阅下面的代码。

非常感谢您的任何建议!

这是我的代码:

### load model & tokenize
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch

max_length = 256
hg_model_hub_name = "ynie/roberta-large-snli_mnli_fever_anli_R1_R2_R3-nli"
# also tried: hg_model_hub_name = "facebook/bart-large-mnli"
tokenizer = AutoTokenizer.from_pretrained(hg_model_hub_name)
model = AutoModelForSequenceClassification.from_pretrained(hg_model_hub_name)
model.config

device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Device: device")
if device == "cuda":
  model = model.half()
model.to(device)
model.train();

#... some data preprocessing

encodings_train = tokenizer(premise_train, hypothesis_train, return_tensors="pt", max_length=max_length,
                            return_token_type_ids=True, truncation=False, padding=True)
encodings_val = tokenizer(premise_val, hypothesis_val, return_tensors="pt", max_length=max_length,
                          return_token_type_ids=True, truncation=False, padding=True)
encodings_test = tokenizer(premise_test, hypothesis_test, return_tensors="pt", max_length=max_length,
                           return_token_type_ids=True, truncation=False, padding=True)


### create pytorch dataset object
class XDataset(torch.utils.data.Dataset):
    def __init__(self, encodings, labels):
        self.encodings = encodings
        self.labels = labels
    def __getitem__(self, idx):
        item = key: torch.as_tensor(val[idx]) for key, val in self.encodings.items()
        #item = key: torch.as_tensor(val[idx]).to(device) for key, val in self.encodings.items()
        item['labels'] = torch.as_tensor(self.labels[idx])
        #item['labels'] = self.labels[idx]
        return item
    def __len__(self):
        return len(self.labels)

dataset_train = XDataset(encodings_train, label_train)
dataset_val = XDataset(encodings_val, label_val)
dataset_test = XDataset(encodings_test, label_test)

# compute metrics with trainer
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
def compute_metrics(pred):
    labels = pred.label_ids
    print(labels)
    preds = pred.predictions.argmax(-1)
    print(preds)
    precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='binary', pos_label=0)
    acc = accuracy_score(labels, preds)
    return 
        'accuracy': acc,
        'f1': f1,
        'precision': precision,
        'recall': recall
    


## training
from transformers import Trainer, TrainingArguments

# https://huggingface.co/transformers/main_classes/trainer.html#transformers.TrainingArguments
training_args = TrainingArguments(
    output_dir='./results',          # output directory
    num_train_epochs=1,              # total number of training epochs
    per_device_train_batch_size=8,  # batch size per device during training
    per_device_eval_batch_size=8,   # batch size for evaluation
    warmup_steps=500,                # number of warmup steps for learning rate scheduler
    weight_decay=0.01,               # strength of weight decay
    logging_dir='./logs',            # directory for storing logs
    logging_steps=100,
)

trainer = Trainer(
    model=model,                         # the instantiated ???? Transformers model to be trained
    args=training_args,                  # training arguments, defined above
    train_dataset=dataset_train,         # training dataset
    eval_dataset=dataset_val             # evaluation dataset
)

trainer.train()
# output: TrainOutput(global_step=181, training_loss=nan)
trainer.evaluate()
# output: 
[2 2 2 0 0 2 2 2 0 2 0 0 2 2 2 2 0 2 0 2 2 2 2 0 2 0 2 0 0 2 0 0 2 0 0 0 2
 0 2 0 0 0 0 0 2 0 0 2 2 2 0 2 2 2 2 2 0 0 0 0 2 0 0 0 2 2 0 0 0 2 0 0 0 2
 2 0 2 0 0 2 2 2 0 2 2 0 0 0 0 0 0 0 2 0 0 0 0 2 0 2 2 0 2 0 0 2 2 2 2 2 2
 2 0 0 0 0 2 0 0 2 0 0 0 0 2 2 2 0 0 0 0 0 2 0 0 2 0 2 0 2 0 2 0 0 2 2 0 0
 2 2 2 2 2 2 0 0 2 2 2 2 0 2 0 0 2 2 2 0 0 2 0 2 0 2 0 0 0 0 0 0 2 0 0 2 2
 0 2 2 2 0 2 2 0 2 2 2 2 2 2 0 0 2 0 0 2 2 0 0 0 2 0 2 2 2 0 0 0 0 0 0 0 0
 2 0 2 2 2 0 2 0 0 2 0 2 2 0 0 0 0 2 2 2 0 0 0 2 2 2 2 0 2 0 2 2 2]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

'epoch': 1.0,
 'eval_accuracy': 0.5137254901960784,
 'eval_f1': 0.6787564766839378,
 'eval_loss': nan,
 'eval_precision': 0.5137254901960784,
 'eval_recall': 1.0

编辑:我还打开了一个 github 问题,在此处对问题进行了更详细的描述:https://github.com/huggingface/transformers/issues/9160

【问题讨论】:

尝试在CPU上运行,我有过这种经历,当我尝试使用cpu时,它运行良好。 不幸的是,我不得不使用 GPU,因为我想在超过 276.000 条句子上对模型进行微调,而这在 GPU 上已经花费了很多小时 只需在 GPU 和 CPU 上使用少量样本运行测试即可。 【参考方案1】:

我在 github 上收到了 HuggingFace 团队的一个很好的回答。问题在于model.half(),它具有提高速度和减少内存使用量的优势,但它也会以产生错误的方式改变模型。删除 model.half() 为我解决了这个问题。详情见https://github.com/huggingface/transformers/issues/9160

【讨论】:

以上是关于微调 HuggingFace NLI 模型(RoBERTa/BART)时,损失为“nan”的主要内容,如果未能解决你的问题,请参考以下文章

如何微调 HuggingFace BERT 模型以进行文本分类 [关闭]

使用 Huggingface TFTrainer 类微调模型时如何指定损失函数?

使用 HuggingFace 微调 ALBERT 问答

输入文件应该如何格式化以进行语言模型微调(BERT 通过 Huggingface Transformers)?

在 Huggingface BERT 模型之上添加密集层

微调 T5 以使用 HuggingFace 进行汇总时出现关键错误