运行时错误:使用Trainer API进行微调时发现dtype Long,但预期Float



我正在尝试使用Huggingface Trainer API对情绪分析(将文本分类为正面/负面(的BERT模型进行微调。我的数据集有两列,TextSentiment,看起来是这样的。

Text                     Sentiment
This was good place          1
This was bad place           0

这是我的代码:

from datasets import load_dataset
from datasets import load_dataset_builder
from datasets import Dataset
import datasets
import transformers
from transformers import TrainingArguments
from transformers import Trainer
dataset = load_dataset('csv', data_files='./train/test.csv', sep=';')
tokenizer = transformers.BertTokenizer.from_pretrained("TurkuNLP/bert-base-finnish-cased-v1")
model = transformers.BertForSequenceClassification.from_pretrained("TurkuNLP/bert-base-finnish-cased-v1", num_labels=1) 
def tokenize_function(examples):
return tokenizer(examples["Text"], truncation=True, padding='max_length')
tokenized_datasets = dataset.map(tokenize_function, batched=True)
tokenized_datasets = tokenized_datasets.rename_column('Sentiment', 'label')
tokenized_datasets = tokenized_datasets.remove_columns('Text')
training_args = TrainingArguments("test_trainer")
trainer = Trainer(
model=model, args=training_args, train_dataset=tokenized_datasets['train']
)
trainer.train()

运行此操作会引发错误:

Variable._execution_engine.run_backward(
RuntimeError: Found dtype Long but expected Float

错误可能来自数据集本身,但我能用代码修复它吗?我在互联网上搜索了一下,这个错误似乎以前已经通过";将张量转换为浮点";但我该如何使用Trainer API?非常感谢您的任何建议。

一些参考:

https://discuss.pytorch.org/t/run-backward-expected-dtype-float-but-got-dtype-long/61650/10

最有可能的问题是损失函数。如果您正确设置了模型,主要是通过指定要使用的正确损失,就可以修复此问题。请参阅此代码以查看决定正确损失的逻辑。

你的问题有二元标签,因此应该被定义为一个单标签分类问题。因此,您共享的代码将被推断为一个回归问题,这解释了它期望浮动但发现目标标签的长类型的错误。

你需要通过正确的问题类型。

model = transformers.BertForSequenceClassification.from_pretrained(
"TurkuNLP/bert-base-finnish-cased-v1", 
num_labels=1, 
problem_type = "single_label_classification"
) 

这将利用BCE损失。对于BCE损失,您需要目标浮动,因此您还必须将标签强制转换为浮动。我认为您可以使用数据集API来做到这一点。看看这个。

另一种方法是使用多类分类器或CE损失。为此,只需修复num_labels就可以了。

model = transformers.BertForSequenceClassification.from_pretrained(
"TurkuNLP/bert-base-finnish-cased-v1", 
num_labels=2,
) 

这里我假设您正在尝试进行一个标签分类,即预测单个结果,而不是预测多个结果。

但是你使用的损失函数(我不知道你在用什么,但它可能是BCE(,期望你提供一个向量作为标签。

因此,要么你需要像人们在评论中建议的那样将标签转换为向量,要么你可以用交叉熵损失代替损失函数,并将标签参数的数量更改为2(或其他(。这两种解决方案都会奏效。

如果你想把你的模型训练成多标签分类器,你可以用sklearn.preprrocessing:把你的标签转换成向量

from sklearn.preprocessing import OneHotEncoder
import pandas as pd
import numpy as np
dataset = pd.read_csv("filename.csv", encoding="utf-8")
enc_labels = preprocessing.LabelEncoder()
int_encoded = enc_labels.fit_transform(np.array(dataset["Sentiment"].to_list()))
onehot_encoder = OneHotEncoder(sparse = False)
int_encoded = int_encoded.reshape(len(int_encoded),1)
onehot_encoded = onehot_encoder.fit_transform(int_encoded)
for index, cat in dataset.iterrows():
dataset.at[index , 'Sentiment'] = onehot_encoded[index]

您可以强制转换数据。

如果你有Pandas格式的。你可以做:

df['column_name'] = df['column_name'].astype(float)

如果你有HuggingFace格式的。你应该这样做:

from datasets import load_dataset
dataset = load_dataset('glue', 'mrpc', split='train')
from datasets import Value, ClassLabel
new_features = dataset.features.copy()
new_features["idx"] = Value('int64')
new_features["label"] = ClassLabel(names=['negative', 'positive'])
new_features["idx"] = Value('int64')
dataset = dataset.cast(new_features)

之前:

dataset.features
{'idx': Value(dtype='int32', id=None),
'label': ClassLabel(num_classes=2, names=['not_equivalent', 'equivalent'], id=None),
'sentence1': Value(dtype='string', id=None),
'sentence2': Value(dtype='string', id=None)}

之后:

dataset.features
{'idx': Value(dtype='int64', id=None),
'label': ClassLabel(num_classes=2, names=['negative', 'positive'], id=None),
'sentence1': Value(dtype='string', id=None),
'sentence2': Value(dtype='string', id=None)}

最新更新