Begin either SFT or DPO training, with periodic evaluation.
(self)
| 270 | return losses.mean(), metrics |
| 271 | |
| 272 | def train(self): |
| 273 | """Begin either SFT or DPO training, with periodic evaluation.""" |
| 274 | |
| 275 | rank0_print(f'Using {self.config.optimizer} optimizer') |
| 276 | self.optimizer = getattr(torch.optim, self.config.optimizer)(self.policy.parameters(), lr=self.config.lr) |
| 277 | self.scheduler = torch.optim.lr_scheduler.LambdaLR(self.optimizer, lr_lambda=lambda step: min(1.0, (step + 1) / (self.config.warmup_steps + 1))) |
| 278 | |
| 279 | torch.manual_seed(self.seed) |
| 280 | np.random.seed(self.seed) |
| 281 | random.seed(self.seed) |
| 282 | |
| 283 | if self.config.loss.name in {'dpo', 'ipo'}: |
| 284 | self.reference_model.eval() |
| 285 | |
| 286 | self.example_counter = 0 |
| 287 | self.batch_counter = 0 |
| 288 | last_log = None |
| 289 | |
| 290 | for batch in self.train_iterator: |
| 291 | #### BEGIN EVALUATION #### |
| 292 | if self.example_counter % self.config.eval_every == 0 and (self.example_counter > 0 or self.config.do_first_eval): |
| 293 | rank0_print(f'Running evaluation after {self.example_counter} train examples') |
| 294 | self.policy.eval() |
| 295 | |
| 296 | all_eval_metrics = defaultdict(list) |
| 297 | if self.config.sample_during_eval: |
| 298 | all_policy_samples, all_reference_samples = [], [] |
| 299 | policy_text_table = wandb.Table(columns=["step", "prompt", "sample"]) |
| 300 | if self.config.loss.name in {'dpo', 'ipo'}: |
| 301 | reference_text_table = wandb.Table(columns=["step", "prompt", "sample"]) |
| 302 | |
| 303 | for eval_batch in (tqdm.tqdm(self.eval_batches, desc='Computing eval metrics') if self.rank == 0 else self.eval_batches): |
| 304 | local_eval_batch = slice_and_move_batch_for_device(eval_batch, self.rank, self.world_size, self.rank) |
| 305 | with torch.no_grad(): |
| 306 | _, eval_metrics = self.get_batch_metrics(local_eval_batch, self.config.loss, train=False) |
| 307 | |
| 308 | for k, v in eval_metrics.items(): |
| 309 | all_eval_metrics[k].extend(v) |
| 310 | |
| 311 | if self.config.sample_during_eval: |
| 312 | if self.config.n_eval_model_samples < self.config.eval_batch_size: |
| 313 | rank0_print(f'Warning: n_eval_model_samples ({self.config.n_eval_model_samples}) < eval_batch_size ({self.config.eval_batch_size}). Sampling from the first complete eval batch of prompts.') |
| 314 | sample_batches = self.eval_batches[:1] |
| 315 | else: |
| 316 | n_sample_batches = self.config.n_eval_model_samples // self.config.eval_batch_size |
| 317 | sample_batches = self.eval_batches[:n_sample_batches] |
| 318 | for eval_batch in (tqdm.tqdm(sample_batches, desc='Generating samples...') if self.rank == 0 else sample_batches): |
| 319 | local_eval_batch = slice_and_move_batch_for_device(eval_batch, self.rank, self.world_size, self.rank) |
| 320 | policy_samples, reference_samples = self.get_batch_samples(local_eval_batch) |
| 321 | |
| 322 | all_policy_samples.extend(policy_samples) |
| 323 | all_reference_samples.extend(reference_samples) |
| 324 | |
| 325 | for prompt, sample in zip(eval_batch['prompt'], policy_samples): |
| 326 | policy_text_table.add_data(self.example_counter, prompt, sample) |
| 327 | if self.config.loss.name in {'dpo', 'ipo'}: |
| 328 | for prompt, sample in zip(eval_batch['prompt'], reference_samples): |
| 329 | reference_text_table.add_data(self.example_counter, prompt, sample) |
no test coverage detected