python - 微调 HuggingFace NLI 模型(RoBERTa/BART)时,损失为“nan”
问题描述
我正在使用HuggingFaceynie/roberta-large-snli_mnli_fever_anli_R1_R2_R3-nli
的 Transformer 库,并尝试在大约 276.000 个假设-前提对的数据集上微调预训练的 NLI 模型 ( )。我正在按照此处和此处的文档中的说明进行操作。我的印象是微调有效(它进行训练并保存检查点),但trainer.train()
返回trainer.evaluate()
“nan”作为损失。
我试过的:
- 我尝试使用两者
ynie/roberta-large-snli_mnli_fever_anli_R1_R2_R3-nli
并facebook/bart-large-mnli
确保它没有链接到特定模型,但我得到了两个模型的问题 - 我尝试按照此相关 github 问题中的建议进行操作,但添加
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
解决方案
我在 github 上收到了 HuggingFace 团队的一个很好的回答。问题在于model.half()
,它具有提高速度和减少内存使用量的优势,但它也会以产生错误的方式改变模型。删除model.half()
解决了我的问题。详情见https://github.com/huggingface/transformers/issues/9160
推荐阅读
- json - 如何从 HttpServletRequest 中读取 Json 对象?
- typescript - 如何从.net core 2.1 Angular 6模板中的非相对路径导入ts和scss文件
- java - 导出用spring boot加密的json
- ruby-on-rails - 来自不同控制器的 Rails 编辑模型
- java - 出于某种原因,我的拉普拉斯滤波器程序不起作用
- java - 我在 Eclipse 中创建的程序作为可运行 JAR 运行时没有输出
- iis - 无法浏览在 IIS 中创建的网站
- instagram - 用于保存收藏的 Instagram api 端点
- c++ - 如何声明一个包含整数数组的对象
- javascript - 如何在浏览器中设置 currentUser emailVerified: true (替换实际的电子邮件验证)?