当前位置: 首页 > news >正文

使用Trainer传入自定义的compute_metrics函数时,oom报错

遇到的问题:

在使用hugging face封装的Trainer的时候,使用了自定义的compute_metric函数,但是会出现OOM的情况。

我的transformer版本是:

经过验证,发现哪怕compute_metrics里的内容写的再简单,只有一个print,也不行,根本就执行不到这个函数内部。才发现,原来不是这个东西的内部的问题。

原因:

经过探究发现,Trainer会把所有 logits、label都算好,拼在一起后,再从CUDA传到内存,然后,再给compute_metrics计算指标。这样导致需要特别大的内存。直接就报错了。

有一些解决思路是:

1. 调节per_device_eval_batch_size=1, eval_accumulation_steps  这俩参数来解决。

        经过尝试,确实会好一点,但是速度非常慢,但是对于较大的验证集,还是不行,治标不治本。原理就是:

        per_device_eval_batch_size 用来 设置验证的时候的batchsize,但是不能解决,拼接了很大的数据量的问题。

        eval_accumulation_steps 是分步骤累积评估结果,减少显存峰值,可能对于 GPU的oom 会有点用吧。但是同样还是没有解决计算所有logits之后,拼接的问题。

training_args = TrainingArguments(
    # 其他的参数设置
    # .....
    # 这两个参数的使用
    per_device_eval_batch_size=1,
    eval_accumulation_steps=100
    
)

最优解:preprocess_logits_for_metrics 函数

使用 preprocess_logits_for_metrics 函数 ,这个函数就是用于在每个评估步骤中缓存 logits之前对其进行预处理。

使用方法如下,注意搭配的compute_metrics 可能需要进一步修改,因为,已经在preprocess_logits_for_metrics计算出来需要使用的东西了。

def compute_metrics(pred):

    labels_ids = pred.label_ids
    pred_ids = pred.predictions[0]

    pred_str = tokenizer.batch_decode(pred_ids, skip_special_tokens=True)
    labels_ids[labels_ids == -100] = tokenizer.pad_token_id
    label_str = tokenizer.batch_decode(labels_ids, skip_special_tokens=True)

    rouge_output = rouge.compute(
        predictions=pred_str,
        references=label_str,
        rouge_types=["rouge1", "rouge2", "rougeL", "rougeLsum"],
    )

    return {
        "R1": round(rouge_output["rouge1"], 4),
        "R2": round(rouge_output["rouge2"], 4),
        "RL": round(rouge_output["rougeL"], 4),
        "RLsum": round(rouge_output["rougeLsum"], 4),
    }

def preprocess_logits_for_metrics(logits, labels):
    """
    Original Trainer may have a memory leak. 
    This is a workaround to avoid storing too many tensors that are not needed.
    """
    pred_ids = torch.argmax(logits[0], dim=-1)
    return pred_ids, labels

 trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=test_dataset,
    compute_metrics=compute_metrics,
    
    # 关键函数
    preprocess_logits_for_metrics=preprocess_logits_for_metrics
)

参考的:

https://discuss.huggingface.co/t/cuda-out-of-memory-when-using-trainer-with-compute-metrics/2941/13

https://huggingface.co/docs/transformers/main_classes/trainer#transformers.Trainer.preprocess_logits_for_metrics

相关文章:

  • Diffusion Transformers (DiTs) - 用Transformer革新Diffusion模型
  • 构建高可靠NFS存储:自动化挂载保障机制的设计与优势
  • 【Vuex:在带命名空间的模块内访问全局内容】
  • Docker运行postgreSQL,由于异常启动或者退出后,提示could not locate a valid checkpoint record
  • JS—事件委托:3分钟掌握事件委托
  • vlan初学的总结
  • NLP高频面试题(四)——BN和LN的区别与联系,为什么attention要用LN
  • Visual Studio2022 中的键盘注释快捷方式
  • 多线程(四)----线程安全
  • 力扣刷题994. 腐烂的橘子
  • 比特币牛市还在不在
  • 「Wi-Fi学习」节能模式
  • Java常用类
  • Android第四次面试总结(基础算法篇)
  • LeetCode-274.H 指数
  • C#进阶(多线程相关)
  • SMT贴片机销售实战技巧解析
  • Python高级:GIL、C扩展与分布式系统深度解析
  • 汽车机械钥匙升级一键启动的优点
  • CentOS下安装ElasticSearch(日志分析)
  • 印度证实印巴已同意停火
  • 卢正已任上海市司法局党委委员、副局长
  • 湖北宜昌:在青山绿水间解锁乡村振兴“密码”
  • 比特币价格重返10万美元,哪些因素使然?
  • 深圳两家会所涉卖淫嫖娼各被罚7万元逾期未缴,警方发催告书
  • 梵蒂冈选出新教皇,外交部:望新教皇推动中梵关系不断改善