Skip to content

Redirect the KTO liger loss through the distributed wrapper under DDP - #7247

Merged
kashif merged 2 commits into
mainfrom
kto-ddp-grad-sync
Sep 18, 2026
Merged

kashif merged 2 commits into
mainfrom
kto-ddp-grad-sync

Conversation

@qgallouedec

@qgallouedec qgallouedec commented Sep 16, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Partially addresses #7245, for KTO only.

compute_loss entered _forward_redirection only for ZeRO-3 and FSDP, and otherwise ran the loss on the unwrapped model. Under plain DDP that means DistributedDataParallel.forward() never runs, so its reducer is never armed by prepare_for_backward(), the autograd hooks return early, and gradients are never all-reduced. Each rank keeps its own, silently.

Measured on 2 GPUs, one step, different data per rank, comparing every parameter's gradient across ranks:

params differing max abs diff
use_liger_kernel=True, before 310 / 310 5.98e-02
use_liger_kernel=True, after 0 / 310 0.0

The condition now matches the one compute_ref_log_probs already uses in this same file.

Why KTO only

DPO has the identical bug and the identical guard, but cannot take this fix yet. Its fused loss calls torch.func.grad_and_value internally, and running that inside DistributedDataParallel.forward() raises:

NotImplementedError: Cannot access storage of TensorWrapper

on every rank. KTO is unaffected because it already computes log-probabilities with _ChunkedLogProbFunction, a plain autograd.Function.

Applying this same guard on top of #7243, which moves DPO onto the chunked path, gives 0/310 differing. So the DPO half belongs there.

Not covered

  • No test. The unit-test shape used for the sibling guard (test_compute_ref_log_probs_redirects_wrapped_liger_model) only pins the if condition and would pass against if True:. What catches this is a 2-GPU gradient comparison, which does not fit tests/distributed, where run_command only asserts the process exits 0.
  • is_zero3 is left in place. DeepSpeedEngine is in accelerate's unwrap list, so model is not unwrapped_model likely covers ZeRO-3 and the term is redundant, but I could not verify that here and did not want to touch the path Fix DPO/KTO use_liger_kernel under DeepSpeed ZeRO-3 #6372 fixed.

Before submitting


Note

Medium Risk
Changes distributed training loss path for KTO+Liger; fixes incorrect gradients under DDP but touches a critical training code path.

Overview
Fixes silent broken multi-GPU training for KTO when use_liger_kernel=True under plain DDP: the Liger chunked path ran loss on the unwrapped model, so DistributedDataParallel.forward() never ran, DDP’s reducer was never armed, and gradients were not all-reduced across ranks.

compute_loss now routes the Liger loss through _forward_redirection whenever the model is still wrapped (model is not unwrapped_model) or FSDP is on—the same guard compute_ref_log_probs already uses—instead of only checking DeepSpeed ZeRO-3 explicitly. Comments are updated to note DDP and FSDP2 behavior alongside ZeRO-3.

Reviewed by Cursor Bugbot for commit 43e196e. Bugbot is set up for automated code reviews on this repo. Configure here.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-16T22:54:52.020542Z e78ddd5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e78ddd538b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread trl/trainer/kto_trainer.py Outdated
@bot-ci-comment

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

`compute_loss` entered `_forward_redirection` only for ZeRO-3 and FSDP, so under plain DDP the
loss ran on the unwrapped model. `DistributedDataParallel.forward()` never ran, its reducer was
never armed, and gradients were never all-reduced: every rank kept its own.

Measured on 2 GPUs with different data per rank, comparing every parameter's gradient across
ranks: 310/310 parameters differed before, 0/310 after.

DPO has the same bug but cannot take the same fix: its fused loss runs `torch.func.grad_and_value`
internally, which raises `NotImplementedError: Cannot access storage of TensorWrapper` when run
inside `DistributedDataParallel.forward()`. It is fixable once #7243 replaces that path.

Ref #7245
@kashif
kashif marked this pull request as ready for review September 17, 2026 07:40
A ZeRO-3 model is a `DeepSpeedEngine`, which accelerate's `extract_model_from_parallel` unwraps,
so `model is not unwrapped_model` already covers it. Only FSDP2 needs its own check, since it
shards in place and preserves object identity. Verified on 2 GPUs with zero3, zero2 and ddp.
@kashif
kashif merged commit 03b22f5 into main Sep 18, 2026
10 checks passed
@kashif
kashif deleted the kto-ddp-grad-sync branch September 18, 2026 13:05
kashif added a commit to kashif/trl that referenced this pull request Sep 19, 2026
qgallouedec: same block, same text as huggingface#7247 - drop the is_zero3 check
(accelerate already unwraps DeepSpeedEngine) and use the FSDP2 identity
check plus the DDP wrapper-identity check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants