LlamaFactory源码解析 PPO

一给  金牌会员 | 2024-7-13 04:29:16 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 649|帖子 649|积分 1947

  1. class CustomPPOTrainer(PPOTrainer, Trainer):
  2.     r"""
  3.     Inherits PPOTrainer.
  4.     """
  5.     def __init__(
  6.         self,
  7.         model_args: "ModelArguments",
  8.         training_args: "Seq2SeqTrainingArguments",
  9.         finetuning_args: "FinetuningArguments",
  10.         generating_args: "GeneratingArguments",
  11.         callbacks: List["TrainerCallback"],
  12.         model: "AutoModelForCausalLMWithValueHead",
  13.         reward_model: Optional["AutoModelForCausalLMWithValueHead"],
  14.         ref_model: Optional["AutoModelForCausalLMWithValueHead"],
  15.         tokenizer: "PreTrainedTokenizer",
  16.         dataset: "Dataset",
  17.         data_collator: "DataCollatorWithPadding",
  18.     ):
  19.         backward_batch_size = training_args.per_device_train_batch_size * training_args.gradient_accumulation_steps
  20.         ppo_config = PPOConfig(
  21.             model_name=model_args.model_name_or_path,
  22.             learning_rate=training_args.learning_rate,
  23.             mini_batch_size=training_args.per_device_train_batch_size,
  24.             batch_size=backward_batch_size * finetuning_args.ppo_buffer_size,
  25.             gradient_accumulation_steps=training_args.gradient_accumulation_steps,
  26.             ppo_epochs=finetuning_args.ppo_epochs,
  27.             max_grad_norm=training_args.max_grad_norm,
  28.             seed=training_args.seed,
  29.             optimize_device_cache=True,
  30.             target=finetuning_args.ppo_target,
  31.             use_score_scaling=finetuning_args.ppo_score_norm,
  32.             use_score_norm=finetuning_args.ppo_score_norm,
  33.             whiten_rewards=finetuning_args.ppo_whiten_rewards,
  34.             accelerator_kwargs={"step_scheduler_with_optimizer": False},
  35.             log_with=training_args.report_to[0] if training_args.report_to else None,
  36.             project_kwargs={"logging_dir": training_args.logging_dir},
  37.         )
  38.         # Create optimizer and scheduler
  39.         if training_args.max_steps > 0:
  40.             num_training_steps = training_args.max_steps
  41.         else:
  42.             total_train_batch_size = backward_batch_size * finetuning_args.ppo_buffer_size * training_args.world_size
  43.             num_training_steps = training_args.num_train_epochs * math.ceil(len(dataset) / total_train_batch_size)
  44.         optimizer = self.create_optimizer(model, training_args, finetuning_args)
  45.         scheduler = self.create_scheduler(training_args, num_training_steps, optimizer)
  46.         PPOTrainer.__init__(
  47.             self,
  48.             config=ppo_config,
  49.             model=model,
  50.             ref_model=ref_model,
  51.             tokenizer=tokenizer,
  52.             dataset=dataset,
  53.             data_collator=data_collator,
  54.             lr_scheduler=scheduler,
  55.         )
  56.         self.args = training_args
  57.         self.model_args = model_args
  58.         self.finetuning_args = finetuning_args
  59.         self.reward_model = reward_model
  60.         self.current_device = get_current_device()  # patch for deepspeed training
  61.         self.generation_config = GenerationConfig(
  62.             pad_token_id=self.tokenizer.pad_token_id,
  63.             eos_token_id=[self.tokenizer.eos_token_id] + self.tokenizer.additional_special_tokens_ids,
  64.             **generating_args.to_dict(),
  65.         )
  66.         self.state = TrainerState()
  67.         self.control = TrainerControl()
  68.         self.is_deepspeed_enabled = self.accelerator.distributed_type == "DEEPSPEED" and hasattr(
  69.             self.accelerator.state, "deepspeed_plugin"
  70.         )
  71.         self.log_callback, self.save_callback = callbacks[0], callbacks[1]
  72.         assert isinstance(self.log_callback, LogCallback) and isinstance(self.save_callback, FixValueHeadModelCallback)
  73.         if self.args.max_steps > 0:
  74.             logger.info("max_steps is given, it will override any value given in num_train_epochs")
  75.         if finetuning_args.reward_model_type == "full":
  76.             if self.is_deepspeed_enabled:
  77.                 if not (
  78.                     getattr(reward_model.pretrained_model, "is_loaded_in_8bit", False)
  79.                     or getattr(reward_model.pretrained_model, "is_loaded_in_4bit", False)
  80.                 )
  81. :  # quantized models are already set on the correct device
  82.                     self.reward_model = self._prepare_deepspeed(self.reward_model)
  83.             else:
  84.                 self.reward_model = self.accelerator.prepare_model(self.reward_model, evaluation_mode=True)
  85.         if finetuning_args.use_badam:
  86.             from badam import clip_grad_norm_for_sparse_tensor
  87.             self.accelerator.clip_grad_norm_ = MethodType(clip_grad_norm_for_sparse_tensor, self.accelerator)
复制代码
下面是对代码中每一行的逐行表明:
python
复制
  1. class CustomPPOTrainer(PPOTrainer, Trainer):
复制代码
定义一个名为 CustomPPOTrainer 的类,继承自 PPOTrainer 和 Trainer 这两个类。
python
复制
  1.     r"""
  2.     Inherits PPOTrainer.
  3.     """
复制代码
文档字符串,说明这个类继承自 PPOTrainer。
python
复制
  1.     def __init__(
  2.         self,
复制代码
定义 CustomPPOTrainer 类的构造函数。
python
复制
  1.         model_args: "ModelArguments",
复制代码
构造函数的参数之一,model_args,代表模型的参数。
python
复制
  1.         training_args: "Seq2SeqTrainingArguments",
复制代码
构造函数的参数之一,training_args,代表练习相关的参数。

  1.         finetuning_args: "FinetuningArguments",
复制代码
构造函数的参数之一,finetuning_args,代表微调相关的参数。
python
复制
  1.         generating_args: "GeneratingArguments",
复制代码
构造函数的参数之一,generating_args,代表生成相关的参数。
python
复制
  1.         callbacks: List["TrainerCallback"],
复制代码
构造函数的参数之一,callbacks,是一个包罗 TrainerCallback 对象的列表,用于处理练习过程中的各种事件。
python
复制
  1.         model: "AutoModelForCausalLMWithValueHead",
复制代码
构造函数的参数之一,model,代表带有价值头的因果语言模型。
python
复制
  1.         reward_model: Optional["AutoModelForCausalLMWithValueHead"],
复制代码
构造函数的参数之一,reward_model,可选,代表用于盘算嘉奖的模型。
python
复制
  1.         ref_model: Optional["AutoModelForCausalLMWithValueHead"],
复制代码
构造函数的参数之一,ref_model,可选,代表参考模型,可能用于对比或其他目标。
python
复制
  1.         tokenizer: "PreTrainedTokenizer",
复制代码
构造函数的参数之一,tokenizer,代表预练习的分词器。
python
复制
  1.         dataset: "Dataset",
复制代码
构造函数的参数之一,dataset,代表用于练习的数据集。
python
复制
  1.         data_collator: "DataCollatorWithPadding",
复制代码
构造函数的参数之一,data_collator,用于处理数据批次,通常包括填充等操作。
python
复制
  1.         backward_batch_size = training_args.per_device_train_batch_size * training_args.gradient_accumulation_steps
复制代码
盘算每个设备上的反向传播批量大小,乘以梯度累积步数。
python
复制
  1.         ppo_config = PPOConfig(
复制代码
创建一个 PPOConfig 配置对象,用于配置 PPO 练习。
python
复制
  1.             model_name=model_args.model_name_or_path,
复制代码
配置模型名称或路径。
python
复制
  1.             learning_rate=training_args.learning_rate,
复制代码
配置学习率。
python
复制
  1.             mini_batch_size=training_args.per_device_train_batch_size,
复制代码
配置小批量大小。
python
复制
  1.             batch_size=backward_batch_size * finetuning_args.ppo_buffer_size,
复制代码
配置团体批量大小,为反向批量大小乘以 PPO 缓冲区大小。
python
复制
  1.             gradient_accumulation_steps=training_args.gradient_accumulation_steps,
复制代码
配置梯度累积步数。
python
复制
  1.             ppo_epochs=finetuning_args.ppo_epochs,
复制代码
配置 PPO 练习的迭代次数。
python
复制
  1.             max_grad_norm=training_args.max_grad_norm,
复制代码
配置梯度裁剪的最大范数。
python
复制
  1.             seed=training_args.seed,
复制代码
配置随机种子。
python
复制
  1.             optimize_device_cache=True,
复制代码
启用设备缓存优化。
python
复制
  1.             target=finetuning_args.ppo_target,
复制代码
配置 PPO 练习的目标。
python
复制
  1.             use_score_scaling=finetuning_args.ppo_score_norm,
复制代码
配置是否利用分数缩放。
python
复制
  1.             use_score_norm=finetuning_args.ppo_score_norm,
  2. ```python
  3.             whiten_rewards=finetuning_args.ppo_whiten_rewards,
复制代码
配置是否对嘉奖举行白化处理,以淘汰嘉奖的方差和偏差。
python
复制
  1.             accelerator_kwargs={"step_scheduler_with_optimizer": False},
复制代码
配置加快器的参数,此处设置 step_scheduler_with_optimizer 为 False。
python
复制
  1.             log_with=training_args.report_to[0] if training_args.report_to else None,
复制代码
配置日记记载方式,如果 training_args.report_to 存在,则利用列表中的第一个元素,否则不记载。
python
复制
  1.             project_kwargs={"logging_dir": training_args.logging_dir},
复制代码
设置项目相关的关键参数,此处设置日记目录。
python
复制
  1.         )
复制代码
竣事 PPOConfig 的构造。
python
复制
  1.         # Create optimizer and scheduler
复制代码
注释,说明下面的代码块是用来创建优化器和调理器的。
python
复制
  1.         if training_args.max_steps > 0:
复制代码
如果 training_args.max_steps 大于0,利用这个值来设置练习步数。
python
复制
  1.             num_training_steps = training_args.max_steps
复制代码
将练习步数设置为 max_steps。
python
复制
  1.         else:
复制代码
如果 max_steps 没有设置,则盘算练习步数。
python
复制
  1.             total_train_batch_size = backward_batch_size * finetuning_args.ppo_buffer_size * training_args.world_size
复制代码
盘算总的练习批量大小。
python
复制
  1.             num_training_steps = training_args.num_train_epochs * math.ceil(len(dataset) / total_train_batch_size)
复制代码
根据数据集的大小、批量大小和练习周期数盘算总的练习步数。
python
复制
  1.         optimizer = self.create_optimizer(model, training_args, finetuning_args)
复制代码
创建优化器。
python
复制
  1.         scheduler = self.create_scheduler(training_args, num_training_steps, optimizer)
复制代码
创建调理器,用来调解优化器的学习率。
python
复制
  1.         PPOTrainer.__init__(
复制代码
调用 PPOTrainer 类的构造器初始化。
python
复制
  1.             self,
复制代码
转达自身实例。
python
复制
  1.             config=ppo_config,
复制代码
转达 PPO 配置。
python
复制
  1.             model=model,
复制代码
转达模型。
python
复制
  1.             ref_model=ref_model,
复制代码
转达参考模型。
python
复制
  1.             tokenizer=tokenizer,
复制代码
转达分词器。
python
复制
  1.             dataset=dataset,
复制代码
转达数据集。
python
复制
  1.             data_collator=data_collator,
复制代码
转达数据整理器。
python
复制
  1.             lr_scheduler=scheduler,
复制代码
转达学习率调理器。
python
复制
  1.         )
复制代码
竣事 PPOTrainer 的构造函数调用。
python
复制
  1.         self.args = training_args
复制代码
将练习参数保存到实例变量 args。
python
复制
  1.         self.model_args = model_args
复制代码
将模型参数保存到实例变量 model_args。
python
复制
  1.         self.finetuning_args = finetuning_args
复制代码
将微调参数保存到实例变量 finetuning_args。
python
复制
  1.         self.reward_model = reward_model
复制代码
将嘉奖模型保存到实例变量 reward_model。
python
复制
  1.         self.current_device = get_current_device()  # patch for deepspeed training
复制代码
获取当前设备,用于支持 DeepSpeed 练习。
python
复制
  1.         self.generation_config = GenerationConfig(
复制代码
创建生成配置。
python
复制
  1.             pad_token_id=self.tokenizer.pad_token_id,
复制代码
设置填充符号的 ID。
python
复制
  1.             eos_token_id=[self.tokenizer.eos_token_id] + self.tokenizer.additional_special_tokens_ids,
复制代码
设置竣事符号的 ID 列表,包括 EOS 和其他特殊符号。
python
复制
  1.             **generating_args.to_dict(),
复制代码
将生成参数转换为字典,并睁开到配置中。
python
复制
  1.         )
复制代码
竣事生成配置的创建。
python
复制
  1.         self.state = TrainerState()
复制代码
创建练习状态对象。
python
复制
  1.         self.control = TrainerControl()
复制代码
创建练习控制对象。

很高兴你对上述 CustomPPOTrainer 类的详细表明感兴趣。下面,我将提供更多关于这个类的功能、用途以及它在机器学习和天然语言处理领域中的潜在应用的信息。
功能和用途

CustomPPOTrainer 类是为了在天然语言处理(NLP)领域中利用强化学习技能而设计的。通过继承 PPOTrainer,这个类可以利用近端策略优化(Proximal Policy Optimization, PPO)算法来优化模型。PPO 是一种在策略梯度方法中常用的强化学习算法,因为它在样本服从和易用性之间提供了一个很好的平衡。
此类的紧张功能包括:

  • 模型微调:利用PPO算法对特定使命举行微调。这在NLP中非常有用,尤其是在没有大量标注数据的环境下,可以通过嘉奖信号来引导模型学习。
  • 嘉奖模型的集成:支持利用独立的嘉奖模型来定义和盘算练习期间的嘉奖,这对于主动化文本生成使命中的目标优化至关紧张。
  • 高度可配置:提供了广泛的配置选项,使研究职员能够在差别的实行设置和使命需求下调解模型的行为。
  • 生成控制:通过 generation_config 支持高级生成控制,如指定特殊符号和调解生成参数。
  • 支持多设备练习:支持利用像DeepSpeed如许的加快库来举行分布式练习,优化练习速度和资源利用。
潜在应用

在NLP领域,CustomPPOTrainer 可以应用于多种场景,例如:


  • 对话系统:通过PPO优化对话代理的回应,以进步对话质量和用户满意度。
  • 内容生成:在内容生成使命中,如消息文章、故事或诗歌生成,利用PPO练习可以帮助模型学习生成更符合特定风格或质量标准的文本。
  • 游戏与模拟:在互动式模拟或游戏环境中,PPO可以练习模型生整天然语言形貌或指令,加强用户体验。
  • 教育和培训:主动化生成讲授材料或举行学术研究辅助,如主动生成题目、解决方案或表明性文本。
总结

通过 CustomPPOTrainer,研究职员和开发者可以更有用地在各种NLP使命中实现和测试PPO和其他强化学习技能的应用。这个类提供了一个灵活的框架,不仅支持标准的模型练习和微调,还允许通过强化学习方法来优化生成的文本,使其更具有目标导向和应用适应性。


请仔细表明ppo近段策略优化算法,以及在大模型微调中的具体应用步骤。

Poe

近端策略优化 (PPO) 算法详解

近端策略优化(Proximal Policy Optimization, PPO) 是一种流行的强化学习算法,由 OpenAI 提出。它紧张用于解决议略梯度方法中的服从和稳定性题目,特别适用于处理高维和连续动作空间的使命。PPO 的核心思想是在举行策略更新时,限制更新步骤的大小,从而避免过大的策略更新造成的性能下降。
PPO 的关键特点:


  • 目标函数:PPO 利用一种特殊的目标函数,它通过引入裁剪概率比率来避免太大的策略更新。这个比率是新策略与旧策略之间概率的比值,当这个比值超出预设的阈值时,目标函数会将其裁剪,以维持更新的稳定性。
  • 两种紧张变体

    • PPO-Clip:利用裁剪的概率比例来限制策略更新的幅度。
    • PPO-Penalty:通过增加一个关于概率比率的约束项来调解目标函数。

  • 多次更新:在每个数据批次上执行多次梯度更新,从而进步数据的利用服从。

    • 在大模型微调中的应用步骤:

      PPO 可以用于大型模型(如 Transformer 模型)的微调,特别是在涉及序列决议使命,如文本生成或游戏中。以下是利用 PPO 微调大模型的具体步骤:
    • 环境与模型的设置

      • 定义或选择一个环境,该环境应能生成与使命相关的状态,并能担当模型输出的动作来返回嘉奖。
      • 准备或预练习一个大型神经网络模型,如 GPT 或 BERT,作为策略网络。

    • 收集数据

      • 利用当前策略(模型)与环境交互,收集一系列状态、动作、嘉奖和新状态。

    • 上风估计

      • 盘算上风函数,通常利用 Generalized Advantage Estimation (GAE)。上风函数帮助算法评估某一动作相比均匀水平好到什么水平。

    • 目标函数的构建与优化

      • 利用收集到的数据,构建 PPO 的目标函数。这包括盘算旧策略和新策略的比率,并应用裁剪。
      • 对策略网络举行梯度上升,以最大化目标函数。

    • 多次迭代

      • 重复数据收集和策略更新过程多次,每次迭代都根据新的策略与环境交互,继续优化模型。

    • 评估与调解

      • 定期评估策略的性能,必要时调解算法参数,如裁剪阈值、上风估计的折扣因子等。

    • 集成与部署

      • 微调完成后,集成并部署模型到实际应用中。

    • PPO 在处理需要长期序列决议和高维动作空间的使命时表现出色,因此它在天然语言处理和复杂策略游戏等领域的应用尤为有用。通过得当的环境设计和嘉奖布局,PPO 可以帮助大型模型学习如何在复杂环境中做出更优的决议,从而提升团体性能和应用的实用性。

  1. def ppo_train(self, resume_from_checkpoint: Optional[str] = None) -> None:
  2.         r"""        Implements training loop for the PPO stage, like _inner_training_loop() in Huggingface's Trainer.        """        if resume_from_checkpoint is not None:            raise ValueError("`resume_from_checkpoint` will be supported in the future version.")        total_train_batch_size = (            self.args.per_device_train_batch_size            * self.args.gradient_accumulation_steps            * self.finetuning_args.ppo_buffer_size            * self.args.world_size        )
  3.         if self.args.max_steps > 0:            num_examples = total_train_batch_size * self.args.max_steps            num_train_epochs = sys.maxsize            max_steps = self.args.max_steps            steps_in_epoch = self.args.max_steps        else:
  4.             len_dataloader = len(self.dataloader)            num_examples = len(self.dataset)            num_train_epochs = self.args.num_train_epochs            max_steps = math.ceil(num_train_epochs * len_dataloader)            steps_in_epoch = len_dataloader        self.state.max_steps = max_steps        self.state.num_train_epochs = num_train_epochs        self.state.is_local_process_zero = self.is_local_process_zero()        self.state.is_world_process_zero = self.is_world_process_zero()        if self.is_world_process_zero():            logger.info("***** Running training *****")            logger.info("  Num examples = {}".format(num_examples))            logger.info("  Num Epochs = {}".format(num_train_epochs))            logger.info("  Instantaneous batch size per device = {}".format(self.args.per_device_train_batch_size))            logger.info(                "  Total train batch size (w. parallel, buffer, distributed & accumulation) = {}".format(                    total_train_batch_size                )
  5.             )
  6.             logger.info("  Gradient Accumulation steps = {}".format(self.args.gradient_accumulation_steps))            logger.info("  Num optimization epochs per batch = {}".format(self.finetuning_args.ppo_epochs))            logger.info("  Total training steps = {}".format(max_steps))            logger.info("  Number of trainable parameters = {}".format(count_parameters(self.model)[0]))        unwrapped_model: "AutoModelForCausalLMWithValueHead" = self.accelerator.unwrap_model(self.model)        dataiter = iter(self.dataloader)        loss_meter = AverageMeter()        reward_meter = AverageMeter()        self.log_callback.on_train_begin(self.args, self.state, self.control)        for step in tqdm(range(max_steps), disable=not self.is_local_process_zero()):            try:                batch = next(dataiter)            except StopIteration:                dataiter = iter(self.dataloader)                batch = next(dataiter)            # Cast to inference mode            unwrapped_model.gradient_checkpointing_disable()            unwrapped_model.config.use_cache = True            self.model.eval()            # Get inputs            self.tokenizer.padding_side = "right"  # change padding side            queries, responses, rewards = [], [], []            for idx in range(0, self.config.batch_size, self.config.mini_batch_size):                mini_batch_queries, mini_batch_responses = self.get_inputs(                    batch[idx : idx + self.config.mini_batch_size]                )
  7.                 mini_batch_rewards = self.get_rewards(mini_batch_queries, mini_batch_responses, unwrapped_model)                queries.extend(mini_batch_queries)                responses.extend(mini_batch_responses)                rewards.extend(mini_batch_rewards)            # Cast to training mode            unwrapped_model.gradient_checkpointing_enable()            unwrapped_model.config.use_cache = False            self.model.train()            # Run PPO step            stats = self.step(queries, responses, rewards)            self.tokenizer.padding_side = "left"  # restore padding side            loss_meter.update(float(stats["ppo/loss/total"]), n=len(rewards))            reward_meter.update(torch.stack(rewards).mean().item(), n=len(rewards))            if self.config.log_with is not None:                try:                    batch["query"] = self.tokenizer.batch_decode(queries, skip_special_tokens=True)                    batch["response"] = self.tokenizer.batch_decode(responses, skip_special_tokens=True)                    self.log_stats(stats, batch, rewards)                except Exception:                    logger.warning("Failed to save stats due to unknown errors.")            self.state.global_step += 1            self.log_callback.on_step_end(self.args, self.state, self.control)            if self.is_local_process_zero() and (step + 1) % self.args.logging_steps == 0:                logs = dict(                    loss=round(loss_meter.avg, 4),                    reward=round(reward_meter.avg, 4),                    learning_rate=stats["ppo/learning_rate"],                    epoch=round(step / steps_in_epoch, 2),                )
  8.                 tqdm.write(str(logs))                logs["step"] = step                self.state.log_history.append(logs)                self.log_callback.on_log(self.args, self.state, self.control)                loss_meter.reset()                reward_meter.reset()            if (step + 1) % self.args.save_steps == 0:  # save checkpoint                self.save_model(                    os.path.join(self.args.output_dir, "{}-{}".format(PREFIX_CHECKPOINT_DIR, self.state.global_step))                )
  9.                 self.save_callback.on_save(                    self.args, self.state, self.control, model=self.accelerator.unwrap_model(self.model)                )
  10.             if self.control.should_epoch_stop or self.control.should_training_stop:                break        self.log_callback.on_train_end(self.args, self.state, self.control)        self.save_callback.on_train_end(            self.args, self.state, self.control, model=self.accelerator.unwrap_model(self.model)        )
复制代码
这段代码是一个较为复杂的 PPO 练习循环实现,涵盖了从模型初始化到循环练习,以及日记记载和模型保存等功能。我们将逐行表明其核心内容:
python
复制
  1. def ppo_train(self, resume_from_checkpoint: Optional[str] = None) -> None:
复制代码


  • 定义了 ppo_train 方法,该方法担当一个可选的参数 resume_from_checkpoint,用于未来版本支持从查抄点规复练习。
python
复制
  1. if resume_from_checkpoint is not None:
  2.     raise ValueError("`resume_from_checkpoint` will be supported in the future version.")
复制代码


  • 如果传入 resume_from_checkpoint 参数,当前版本会抛出非常,提示该功能将在未来版本中支持。
python
复制
  1. total_train_batch_size = (
  2.     self.args.per_device_train_batch_size
  3.     * self.args.gradient_accumulation_steps
  4.     * self.finetuning_args.ppo_buffer_size
  5.     * self.args.world_size
  6. )
复制代码


  • 盘算总练习批次大小,考虑了每设备批次大小、梯度累积步数、PPO缓冲区大小和分布式练习中的天下大小(即处理器数量)。
python
复制
  1. if self.args.max_steps > 0:
  2.     num_examples = total_train_batch_size * self.args.max_steps
  3.     num_train_epochs = sys.maxsize
  4.     max_steps = self.args.max_steps
  5.     steps_in_epoch = self.args.max_steps
  6. else:
  7.     len_dataloader = len(self.dataloader)
  8.     num_examples = len(self.dataset)
  9.     num_train_epochs = self.args.num_train_epochs
  10.     max_steps = math.ceil(num_train_epochs * len_dataloader)
  11.     steps_in_epoch = len_dataloader
复制代码


  • 根据是否指定了最大步数 (max_steps) 来决定练习的迭代方式和周期。如果指定了最大步数,则利用最大步数来盘算总例数和练习周期,否则根据数据加载器和数据集的大小盘算。
python
复制
  1. self.state.max_steps = max_steps
  2. self.state.num_train_epochs = num_train_epochs
  3. self.state.is_local_process_zero = self.is_local_process_zero()
  4. self.state.is_world_process_zero = self.is_world_process_zero()
复制代码


  • 初始化练习状态,包括最大步数、练习周期数以及是否是本地或全局的主进程(用于控制日记和模型保存等操作)。
python
复制
  1. if self.is_world_process_zero():
  2.     ...
复制代码


  • 如果当前进程是全局主进程,则记载练习的相关信息,包括例数、周期数、批次大小、梯度累积步数等。
python
复制
  1. unwrapped_model: "AutoModelForCausalLMWithValueHead" = self.accelerator.unwrap_model(self.model)
  2. dataiter = iter(self.dataloader)
  3. loss_meter = AverageMeter()
  4. reward_meter = AverageMeter()
  5. self.log_callback.on_train_begin(self.args, self.state, self.control)
复制代码


  • 解包模型以便直接操作,初始化数据加载器的迭代器,创建丧失和嘉奖的度量工具,并触发练习开始的回调。
python
复制
  1. for step in tqdm(range(max_steps), disable=not self.is_local_process_zero()):
  2.     ...
复制代码


  • 主练习循环,利用 tqdm 来展示进度条。循环将根据最大步数执行,并在本地主进程中表现进度。
接下来的代码块涉及处理数据批次、执行模型的推理和练习、记载统计数据、处理日记和保存模型的功能。由于篇幅限制,这里不对每一行代码举行详细表明,但大致流程包括:


  • 从数据加载器中获取批次数据。
  • 将模型置于推理模式,处理输入数据,获取嘉奖。
  • 切换到练习模式,执行 PPO 练习步骤。
  • 更新丧失和嘉奖的度量,记载日记和统计信息。
  • 根据设定的间隔保存模型和执行回调。
这个过程循环,直到到达最大步数或满足特定的停止条件。整个练习循环详细地处理了模型的运行状态、性能监控以及与分布式练习相关的特定操作。
  1. def create_optimizer(        self,        model: "AutoModelForCausalLMWithValueHead",
  2.         training_args: "Seq2SeqTrainingArguments",
  3.         finetuning_args: "FinetuningArguments",
  4.     ) -> "torch.optim.Optimizer":        optimizer = create_custom_optimzer(model, training_args, finetuning_args)        if optimizer is None:            decay_params, nodecay_params = [], []            decay_param_names = self.get_decay_parameter_names(model)            for name, param in model.named_parameters():                if param.requires_grad:                    if name in decay_param_names:                        decay_params.append(param)                    else:
  5.                         nodecay_params.append(param)            optim_class, optim_kwargs = Trainer.get_optimizer_cls_and_kwargs(training_args)            param_groups = [                dict(params=nodecay_params),                dict(params=decay_params, weight_decay=training_args.weight_decay),            ]            optimizer = optim_class(param_groups, **optim_kwargs)        return optimizer    def create_scheduler(        self, training_args: "Seq2SeqTrainingArguments", num_training_steps: int, optimizer: "torch.optim.Optimizer"    ) -> "torch.optim.lr_scheduler.LRScheduler":        create_custom_scheduler(training_args, num_training_steps, optimizer)        lr_scheduler = get_scheduler(            training_args.lr_scheduler_type,            optimizer=optimizer,            num_warmup_steps=training_args.get_warmup_steps(num_training_steps),            num_training_steps=num_training_steps,        )
  6.         return lr_scheduler    @torch.no_grad()    def get_inputs(self, batch: Dict[str, torch.Tensor]) -> Tuple[List[torch.Tensor], List[torch.Tensor]]:        r"""        Generates model's responses given queries.        """        if self.model_args.upcast_layernorm:            layernorm_params = dump_layernorm(self.model)        if batch["input_ids"].size(0) == 1:  # handle llama2 ppo with gradient accumulation > 1            start_index = (batch["input_ids"][0] != self.tokenizer.pad_token_id).nonzero()[0].item()            for k, v in batch.items():                batch[k] = v[:, start_index:]        unwrapped_model: "AutoModelForCausalLMWithValueHead" = self.accelerator.unwrap_model(self.model)        generate_output: torch.Tensor = unwrapped_model.generate(            generation_config=self.generation_config, logits_processor=get_logits_processor(), **batch        )
  7.         if self.model_args.upcast_layernorm:            restore_layernorm(self.model, layernorm_params)        query = batch["input_ids"].detach().cpu()        response = generate_output[:, batch["input_ids"].size(-1) :].detach().cpu()        queries, responses = [], []        for i in range(len(query)):            query_start_index = (query[i] != self.tokenizer.pad_token_id).nonzero()[0].item()            response_index = (response[i] != self.tokenizer.pad_token_id).nonzero()            if len(response_index) == 0:                response_length = 1  # allow empty response            else:
  8.                 response_length = response_index[-1].item() + 1            queries.append(query[i, query_start_index:])  # remove padding from left            responses.append(response[i, :response_length])  # remove padding from right        return queries, responses    @torch.no_grad()    def get_rewards(        self,        queries: List[torch.Tensor],        responses: List[torch.Tensor],        unwrapped_model: "AutoModelForCausalLMWithValueHead",    ) -> List[torch.Tensor]:        r"""        Computes scores using given reward model.        Both inputs and outputs are put on CPU.        """        if self.finetuning_args.reward_model_type == "api":            token_ids = [torch.cat((q, r), dim=-1).tolist() for q, r in zip(queries, responses)]            messages = self.tokenizer.batch_decode(token_ids, skip_special_tokens=True)            return get_rewards_from_server(self.reward_model, messages)        if self.finetuning_args.reward_model_type == "lora":            replace_model(unwrapped_model, target="reward")            reward_model = self.model        else:
  9.             reward_model = self.reward_model        batch = self.prepare_model_inputs(queries, responses)        with torch.cuda.amp.autocast(dtype=self.model_args.compute_dtype):  # support bf16            _, _, values = reward_model(**batch, output_hidden_states=True, return_dict=True, use_cache=False)        if getattr(unwrapped_model.config, "model_type", None) == "chatglm":  # assume same architecture            values = torch.transpose(values, 0, 1)        rewards = []        for i in range(values.size(0)):            end_indexes = (batch["input_ids"][i] != self.tokenizer.pad_token_id).nonzero()            end_index = end_indexes[-1].item() if len(end_indexes) else 0            rewards.append(values[i, end_index].float().detach().cpu())  # use fp32 type        if self.finetuning_args.reward_model_type == "lora":            replace_model(unwrapped_model, target="default")        return rewards
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

一给

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表