Skip to content

Commit c31418c

Browse files
fix(metrics): correct four RL trainer diagnostics
Two of the four are padding problems and two are not. No loss or gradient path changes in any of them. Online DPO summed raw `(B, T)` logprobs for `objective/kl`, `objective/entropy` and, through `non_score_reward`, `objective/rlhf_reward`, two lines below a loss that already multiplies by `~cr_padding_mask`. PPO masked `pg_loss` and `pg_clipfrac` but left `policy/approxkl_avg`, `policy/entropy_avg` and `policy/ratio_avg` on a bare `.mean()`. Both now use the mask already in scope. The padded positions hold `log p(pad | context)`: `_forward` returns `selective_log_softmax` over the full padded width and nothing zeroes it before the stat sites. That value rises toward zero as the policy learns to emit pad after EOS, so the contamination shrinks during training instead of sitting at a fixed offset. Holding the true masked entropy fixed and moving only `p(pad|ctx)` from 0.01 to 0.99 slides the reported value from 48.99 to 37.51, a downward trend that nothing real is producing. XPO logged `logps/chosen` and `logps/rejected` as policy plus reference logps. Online DPO logs the policy term alone and Nash-MD logs the two separately, so the sum matches neither and has no interpretation. Now the policy term. GRPO computed `policy_loss` on every loss branch but appended it only inside the entropy-bonus block, so the metric vanished for standard runs. The append moves out. Its value is unchanged: it is captured after the KL term is folded in, so with `beta != 0` it carries that too, and excludes only the entropy bonus and the MoE auxiliary loss. Resolves #6809
1 parent 6d484ba commit c31418c

4 files changed

Lines changed: 18 additions & 9 deletions

File tree

trl/experimental/online_dpo/online_dpo_trainer.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,9 @@ def training_step(
12491249
self.stats["logps/chosen"].append(self.accelerator.gather_for_metrics(chosen_logprobs_sum).mean().item())
12501250
self.stats["logps/rejected"].append(self.accelerator.gather_for_metrics(rejected_logprobs_sum).mean().item())
12511251

1252-
kl = logprobs - ref_logprobs
1252+
# Exclude padding positions, as the loss path above does: `logprobs` and `ref_logprobs` span the padded
1253+
# completion width, so summing them raw adds post-EOS garbage to every objective below.
1254+
kl = (logprobs - ref_logprobs) * ~padding_mask
12531255
mean_kl = kl.sum(1).mean()
12541256
self.stats["objective/kl"].append(self.accelerator.gather_for_metrics(mean_kl).mean().item())
12551257
non_score_reward = (-self.beta * kl).sum(1)
@@ -1262,7 +1264,7 @@ def training_step(
12621264
rlhf_reward = rewards + non_score_reward
12631265
self.stats["objective/rlhf_reward"].append(self.accelerator.gather_for_metrics(rlhf_reward).mean().item())
12641266

1265-
mean_entropy = -logprobs.sum(1).mean()
1267+
mean_entropy = -(logprobs * ~padding_mask).sum(1).mean()
12661268
self.stats["objective/entropy"].append(self.accelerator.gather_for_metrics(mean_entropy).mean().item())
12671269
chosen_rewards = self.beta * (chosen_logprobs_sum - chosen_ref_logprobs_sum)
12681270
gathered_chosen_rewards = self.accelerator.gather_for_metrics(chosen_rewards)

trl/experimental/ppo/ppo_trainer.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ def repeat_generator():
854854
)
855855
prob_dist = torch.nn.functional.softmax(logits, dim=-1)
856856
entropy = torch.logsumexp(logits, dim=-1) - torch.sum(prob_dist * logits, dim=-1)
857-
approxkl = 0.5 * (logprobs_diff**2).mean()
857+
approxkl = 0.5 * masked_mean(logprobs_diff**2, ~padding_mask[micro_batch_inds])
858858
approxkl_stats[ppo_epoch_idx, minibatch_idx, gradient_accumulation_idx] = approxkl
859859
pg_clipfrac_stats[ppo_epoch_idx, minibatch_idx, gradient_accumulation_idx] = (
860860
pg_clipfrac
@@ -864,8 +864,12 @@ def repeat_generator():
864864
vf_clipfrac_stats[ppo_epoch_idx, minibatch_idx, gradient_accumulation_idx] = (
865865
vf_clipfrac
866866
)
867-
entropy_stats[ppo_epoch_idx, minibatch_idx, gradient_accumulation_idx] = entropy.mean()
868-
ratio_stats[ppo_epoch_idx, minibatch_idx, gradient_accumulation_idx] = ratio.mean()
867+
entropy_stats[ppo_epoch_idx, minibatch_idx, gradient_accumulation_idx] = masked_mean(
868+
entropy, ~padding_mask[micro_batch_inds]
869+
)
870+
ratio_stats[ppo_epoch_idx, minibatch_idx, gradient_accumulation_idx] = masked_mean(
871+
ratio, ~padding_mask[micro_batch_inds]
872+
)
869873
gradient_accumulation_idx += 1
870874
minibatch_idx += 1
871875
# del everything and empty cache

trl/experimental/xpo/xpo_trainer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,8 @@ def gather_mean(tensor):
384384
rejected_ref_logprobs = torch.where(~chosen_mask, ref_logprobs_model_data_sum, ref_logprobs_ref_data_sum)
385385
rejected_log_ratios = rejected_model_logprobs - rejected_ref_logprobs
386386

387-
self.stats["logps/chosen"].append(gather_mean(chosen_model_logprobs.mean() + chosen_ref_logprobs.mean()))
388-
self.stats["logps/rejected"].append(gather_mean(rejected_model_logprobs.mean() + rejected_ref_logprobs.mean()))
387+
self.stats["logps/chosen"].append(gather_mean(chosen_model_logprobs.mean()))
388+
self.stats["logps/rejected"].append(gather_mean(rejected_model_logprobs.mean()))
389389

390390
# Log rewards
391391
# Compute various statistics

trl/trainer/grpo_trainer.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3272,6 +3272,11 @@ def _compute_loss(self, model, inputs):
32723272
else:
32733273
raise ValueError(f"Unknown loss type: {self.loss_type}")
32743274

3275+
# Log for every run, not only the ones with an entropy bonus enabled. `policy_loss` is captured after the
3276+
# KL term is folded in above, so with `beta != 0` it carries that too; it excludes only the entropy bonus
3277+
# and the MoE auxiliary loss, both added below.
3278+
self._metrics[mode]["policy_loss"].append(self.accelerator.gather(policy_loss).nanmean().item())
3279+
32753280
# Entropy bonus: add entropy regularization to encourage exploration. _entropy_bonus_enabled is set
32763281
# whenever a non-zero static coef is set OR adaptive mode is enabled (adaptive stays enabled even when
32773282
# entropy_coef has been decremented to entropy_coef_min so it can recover once entropy drops again).
@@ -3299,8 +3304,6 @@ def _compute_loss(self, model, inputs):
32993304

33003305
loss = loss - apply_coef * entropy_loss
33013306

3302-
self._metrics[mode]["policy_loss"].append(self.accelerator.gather(policy_loss).nanmean().item())
3303-
33043307
# Adaptive update. Gated on train mode so evaluation cannot mutate the entropy controller state.
33053308
if self.use_adaptive_entropy and mode == "train":
33063309
# Accumulate the entropy sum and active-token count of every micro-batch into a running window

0 commit comments

Comments
 (0)