ludwig 为None类型LLM训练器(用于批处理推理)实现批处理大小调整,

u0njafvf  于 2个月前  发布在  其他
关注(0)|答案(5)|浏览(37)

当前,它仅返回最小批量大小为1。我们希望在发生内存溢出之前尽可能增加批量大小。这只需要进行前向传递。

b4qexyjb

b4qexyjb3#

关于Ludwig Slack的问题:

  1. 在模型训练过程中(即作为微调的一部分),是否要最大化"forward"路径的batch_size,还是仅在predict()部分(即纯粹作为推理的一部分——“零梯度”)?如果是前者,那么这意味着我们正在处理微调的情况,那么eval_batch_size是否应该接受FineTuneTrainerConfig中的auto和None值?如果是后者,那么同样的问题也会出现在LLMTrainerConfig中(因为NoneTrainerConfig继承了LLMTrainerConfig,实际功能将进入NoneTrainer)。或者是另一个配置类?通过尝试ECD测试,test_trainer.py::test_tune_batch_size_and_lr,我假设对于LLM情况,它将是关于LLMTrainerConfig或NoneTrainerConfig;然而,初步实验表明是FineTuneTrainerConfig,因为这是解析配置的方式(即在FineTuneTrainerConfig中验证eval_batch_size)。

  2. 如果有额外的背景信息,将不胜感激。

py49o6xq

py49o6xq4#

在模型训练过程中(即作为微调的一部分),是想最大化"forward"路径的batch_size,还是只在predict()部分(即纯粹作为推理——“零梯度”——使用,在这种情况下,我们不使用基础模型,而是将config["adapter"]["pretrained_adapter_weights"]设置为已经微调过的模型名称)?
NoneType LLM Trainer类用于零样本/少量样本推理!因此,这将是最大化model.train()函数调用中的batch_size,其中trainer: type设置为None,类似于这样:

trainer:
   type: none

在这种情况下,我们要么使用预训练/微调的基础模型,要么使用预训练的基础模型加上适配器来执行前向传播并最大化batch大小。
如果是前者,意味着我们正在处理微调的情况,那么eval_batch_size是否应该接受FineTuneTrainerConfig中的auto和None值?如果是后者,那么同样的问题也会出现在LLMTrainerConfig(因为NoneTrainerConfig扩展了LLMTrainerConfig,实际功能将进入NoneTrainer)。或者是不同的配置类?通过在ECD测试中进行实验,test_trainer.py::test_tune_batch_size_and_lr,我假设对于LLM情况,它将是关于LLMTrainerConfig或NoneTrainerConfig;然而,初始实验指向FineTuneTrainerConfig,因为这是解析配置的方式(即,在FineTuneTrainerConfig中验证eval_batch_size)。
既然是后者的情况,我们基本上可以将batch_size: auto作为训练器配置的一部分:

trainer:
    type: none
    batch_size: auto

这将尝试从最小可能的batch大小(1)一直到epoch大小的batch大小,并适应可以放入内存而不会导致CPU/GPU OOMs的最大可能的batch大小(我们在这里主要关注的是GPU OOMs)。实际代码实现将进入NoneTypeTrainer实现:https://github.com/ludwig-ai/ludwig/blob/master/ludwig/trainers/trainer_llm.py#L217。由于此函数在训练器中被调用时模型已经在内存中初始化,因此它只需要执行前向传播直到OOM。
任何额外的背景都将非常有帮助。
我认为这里有两件事我们想要做:

  1. 使用torch.no_grad()上下文管理器调用前向传播,这样我们就不必担心梯度的内存问题,这将有效地允许更大的batch大小。
  2. 我们想要创建合成数据,其中生成的max_new_tokens等于输出特征的max_sequence_length个数或者指定的global_max_sequence_length(哪个都行),然后使用每个样本包含最大可能生成的令牌的批次从1递增到epoch长度。原因是我们希望根据最坏情况下每个样本产生的所有max_new_tokens令牌来调整batch大小。由于传统的注意力计算序列长度与所需内存呈二次关系,因此我们希望调整以获得产生最坏情况max_new_tokens的前向传播的最大batch大小。我知道这些模型是自回归的,所以我们不能保证达到这个最坏情况,但我认为实际上可以通过Generation Config参数强制实现这一点:https://github.com/ludwig-ai/ludwig/blob/master/ludwig/schema/llms/generation.py#L10 通过将min_new_tokens设置为输出特征之一的max_sequence_lengthglobal_max_sequence_length或某个回退值(如256个令牌)来实现。
    请告诉我是否有帮助!我很乐意回答更多的问题
t0ybt7op

t0ybt7op5#

以下是对情况的分析(由@arnavgarg1和@alexsherstinsky提出),并提出了未来工作的想法。

TL/DR

暂停对这个功能的进一步开发;需要进行更深入的产品级和设计讨论才能继续进行。

详细信息

分析

零样本/少样本推理要求在执行 model.predict() 之前必须先执行 model.train() ,这是与生成元数据有关的特殊情况,只能通过执行 model.train() 调用来获得。因此,我们必须“伪训练”模型以进行零样本/少样本推理。为此,我们将训练器类型配置为“none”,然后当 LudwigModel.train() 执行时,将调用 LudwigModel._tune_batch_size() 。执行 LudwigModel._tune_batch_size() 将更新内存中的 LudwigModel.config_obj.trainer.batch_size = tuned_batch_size 。在内部,它会调用训练器的 tune_batch_size() 方法。对于 ECD 模型,如果 batch_size 设置为“auto”或 eval_batch_size 设置为“auto”/ None ,那么它实际上只会做一些事情;否则,它会被跳过,因为这些批量大小是用户明确设置的。对于 NoneTrainer ,我们目前只是返回 1 (https://github.com/ludwig-ai/ludwig/blob/master/ludwig/trainers/trainer_llm.py#L217)。“伪训练”实际上只是在表面上为每个数据集调用 model.evaluate() ,计算一组“指标”;本质上,需要调用 model.train() -- 即使没有进行训练 -- 以便能够使用预训练的 LLMs 进行 model.predict() 调用(否则,Ludwig 会报错,提示模型“尚未训练”)。然而,在当前实现中,这种最优的 batch_size 将无法提供给 model.predict() (因为 model.predict()128 为默认参数接受 batch_size 作为参数)。这一事实意味着当前的 batch_size 优化(没有进行架构更改的情况下)仅是为了加速最终过时的 model.train() 调用。此外,当训练器 type 被配置为“none”并在新鲜加载的微调 LLM 上执行推理时, model.train() 调用执行速度极快(在 Ludwig 从存储中加载模型后)。下面是一个 Google Colab笔记本中的示例配置,用于说明所进行的实验:

相关问题