这个问题苦恼我几个月,之前一直用替代方案。这次实在没替代方案了,transformers源码和文档看了一整天,终于在晚上12点找到了。。。
解决方案:在TrainingArguments中指定label_names、remove_unused_columns、include_inputs_for_metrics三个参数
问题描述
使用transformers.Trainer就图个快和优雅,它包装了一整套的训练逻辑,让我们不用从数据加载、模型训练、评估、预测、保存模型、计算评价指标等等一整套写完。
但是显然,模型和任务一复杂的时候,loss的计算、评价指标的实现,我们还是需要重写的。于是问题就来了:
在计算评价指标时,即重写compute_metrics方法时,形参pred是EvalPrediction类,然而它只提供三个变量:(predictions=all_preds, label_ids=all_labels, inputs=all_inputs),但是我们还需要其他的数据来算评价指标怎么办??
解决方案
在TrainingArguments
中添加以下三个参数
args = TrainingArguments( ... label_names=['labels','自定义数据名'], remove_unused_columns= False, # 在compute_loss 时需要额外输入 include_inputs_for_metrics= True # compute_metrics 时需要原始输出来计算评价指标 )
然后你会发现,compute_metrics
的形参的label_ids
存的就不知原始标签了,现在存的是元组,就是你指定的label_names
里面的数据。
详细使用方法
1、在构建输入的时候,除了PLM
模型本身就需要的数据,还要有我们想使用的自定义数据,格式如下:
feature_dict = { // PLM规定的输入 'input_ids': torch.tensor([f.input_ids for f in features], dtype=torch.long), 'attention_mask': torch.tensor([f.attention_mask for f in features], dtype=torch.long), 'token_type_ids': torch.tensor([f.token_type_ids for f in features], dtype=torch.long), 'labels': torch.tensor([f.labels for f in features], dtype=torch.long), // 自定义的输入 '自定义名': torch.tensor([f.自定义名 for f in features], dtype=torch.long) }
2、在TrainingArguments中设置remove_unused_columns= False,意思是在重写compute_loos方法时,不会删除我们自定义的列。
这样,在compute_loos方法中,我们就可以使用自定义的列的数据了。但是要注意在把输入喂给model的时候,要把自定义列摘出来,不然会报错:
def compute_loss(self, model, inputs, return_outputs=False): # 运行模型 new_inputs = {k:v for k, v in inputs.items() if k not in ['自定义名']} outputs = model(**new_inputs) ...
3、在TrainingArguments
中设置label_names=['labels','自定义数据名']
,意思是在重写compute_metrics
方法时,形参的label_ids
属性会存入我们设置的那些列。使用方法:
# 重写评价指标计算 def compute_metrics(pred): labels, 自定义数据名 = pred.label_ids ...
Prompt最近这么火,一个方向的朋友一定会出现和我一样的问题,看到这篇帖子麻烦评论个1,哈哈哈哈