这个问题与如何在使用自定义数据集进行微调后检查混淆矩阵?在Data Science Stack Exchange上相同。
背景
我想在使用自定义数据集进行微调后,检查类似下面的混淆矩阵,包括精确度、召回率和F1分数。
微调过程和任务是使用IMDb评论进行序列分类,在Hugging Face的自定义数据集微调教程上进行的。
在使用Trainer完成微调后,如何在这种情况下检查混淆矩阵?
混淆矩阵的图像,包括精确度、召回率和F1分数,来自原始网站:仅作为示例输出图像
predictions = np.argmax(trainer.test(test_x), axis=1)# 混淆矩阵和分类报告print(classification_report(test_y, predictions)) 精确度 召回率 F1分数 支持量 0 0.75 0.79 0.77 1000 1 0.81 0.87 0.84 1000 2 0.63 0.61 0.62 1000 3 0.55 0.47 0.50 1000 4 0.66 0.66 0.66 1000 5 0.62 0.64 0.63 1000 6 0.74 0.83 0.78 1000 7 0.80 0.74 0.77 1000 8 0.85 0.81 0.83 1000 9 0.79 0.80 0.80 1000平均 / 总计 0.72 0.72 0.72 10000
代码
from transformers import DistilBertForSequenceClassification, Trainer, TrainingArgumentstraining_args = TrainingArguments( output_dir='./results', # 输出目录 num_train_epochs=3, # 总训练轮数 per_device_train_batch_size=16, # 训练期间每个设备的批次大小 per_device_eval_batch_size=64, # 评估的批次大小 warmup_steps=500, # 学习率调度器的预热步数 weight_decay=0.01, # 权重衰减的强度 logging_dir='./logs', # 存储日志的目录 logging_steps=10,)model = DistilBertForSequenceClassification.from_pretrained("distilbert-base-uncased")trainer = Trainer( model=model, # 要训练的实例化🤗 Transformers模型 args=training_args, # 上面定义的训练参数 train_dataset=train_dataset, # 训练数据集 eval_dataset=val_dataset # 评估数据集)trainer.train()
我所做的
为使用IMDb评论进行序列分类准备数据集,我正在使用Trainer进行微调。
from pathlib import Pathdef read_imdb_split(split_dir): split_dir = Path(split_dir) texts = [] labels = [] for label_dir in ["pos", "neg"]: for text_file in (split_dir/label_dir).iterdir(): texts.append(text_file.read_text()) labels.append(0 if label_dir is "neg" else 1) return texts, labelstrain_texts, train_labels = read_imdb_split('aclImdb/train')test_texts, test_labels = read_imdb_split('aclImdb/test')from sklearn.model_selection import train_test_splittrain_texts, val_texts, train_labels, val_labels = train_test_split(train_texts, train_labels, test_size=.2)from transformers import DistilBertTokenizerFasttokenizer = DistilBertTokenizerFast.from_pretrained('distilbert-base-uncased')train_encodings = tokenizer(train_texts, truncation=True, padding=True)val_encodings = tokenizer(val_texts, truncation=True, padding=True)test_encodings = tokenizer(test_texts, truncation=True, padding=True)import torchclass IMDbDataset(torch.utils.data.Dataset): def __init__(self, encodings, labels): self.encodings = encodings self.labels = labels def __getitem__(self, idx): item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()} item['labels'] = torch.tensor(self.labels[idx]) return item def __len__(self): return len(self.labels)train_dataset = IMDbDataset(train_encodings, train_labels)val_dataset = IMDbDataset(val_encodings, val_labels)test_dataset = IMDbDataset(test_encodings, test_labels)
回答:
在这种情况下,您可以遍历验证集(或测试集),并手动创建y_true
和y_pred
的列表。
import torchimport torch.nn.functional as Ffrom sklearn import metrics y_preds = []y_trues = []for index,val_text in enumerate(val_texts): tokenized_val_text = tokenizer([val_text], truncation=True, padding=True, return_tensor='pt') logits = model(tokenized_val_text) prediction = F.softmax(logits, dim=1) y_pred = torch.argmax(prediction).numpy() y_true = val_labels[index] y_preds.append(y_pred) y_trues.append(y_true)
最后,
confusion_matrix = metrics.confusion_matrix(y_trues, y_preds, labels=["neg", "pos"]))print(confusion_matrix)
观察:
- 模型的输出是
logits
,而不是归一化的概率。 - 因此,我们在第一维度上应用
softmax
以转换为实际的概率(例如,0.2% 类别0
,0.8% 类别1
)。 - 我们应用
.argmax()
操作来获取类别的索引。