Repository navigation
Allow option to choose between fused LCE and CE loss - #704
Conversation
|
Would appreciate feedback on the interface here:
Not sure who to flag, maybe @shivam15s ? |
|
Thanks for the contribution! But I'm a little bit confused the goal of this PR. My understanding of the proposal is that it enables users to access logits while the model is in training mode. Am I understanding this correctly? How is it different from patching CE without patching FLCE? If a user only want to retrieve logits for validation, simply setting the model to evaluation mode can materialize full logits and the model is still able to calculate CE loss if Or is it for a flexible option to swtich between CE and FLCE in training mode? Could you elaborate on the scenarios where users can benefit from this option? |
|
@Tcc0403 I think this PR is valuable when the validation metric is just loss in SFT scenario. There is no need to materialize logits if the validation metric is just validation loss. However, Liger-Kernel currently materializes the logits even if we just compute validation loss. #703 (as posted by the PR author) shows the efficient usage of this option. |
|
@connermanuel BTW, you need to implement this feature for qwen3_moe models that is recently merged in #706. |
|
@chiwanpark Thanks for the explanation. I misunderstood the intent of this PR. So it's more about boardening the use of flce in eval mode, not about falling back to CE in training mode. |
|
@Tcc0403 @chiwanpark Thanks both. The primary intent is to enable FLCE for validation, but I suppose a secondary benefit is enabling accessing logits during training. |
Yes, put it in llava as well. It seems we missing validation mode support for llava, keep the interface so later PR can handle it.
I think we can adjust the workflow of convergence test for it. Adding an additional validation step (forward pass only) after for loop to check the following metrics:
This change should be applied to |
Sounds good
Ok, so I just add these steps then run |
|
@Tcc0403 I modified the tests, can you see if this is what you meant? |
| batch = next(loader_iter).to(model.device) | ||
| optimizer.zero_grad() | ||
| if with_liger: | ||
| batch["skip_logits"] = True |
There was a problem hiding this comment.
We don't need to pass skip_logits in training loop because default is True for liger patched model.
There was a problem hiding this comment.
Sounds good, by this reasoning I should remove skip_logits=False from validation as well
There was a problem hiding this comment.
We can keep skip_logits=False in validation since we want to make sure the logits can be computed correctly.
| return { | ||
| "train_loss": train_loss_list, | ||
| "eval_loss": eval_output.loss.item(), | ||
| "eval_logits": eval_output.logits, | ||
| "model": model, | ||
| } |
There was a problem hiding this comment.
nit: I prefer keeping existing names loss and logits to minimize the difference between files.
There was a problem hiding this comment.
Sounds good, I can add eval loss to the loss list then
| # rtol=logits_rtol, | ||
| # ) | ||
| # Compare the logits from the last step | ||
| if expected_output["eval_logits"] is not None and actual_output["eval_logits"] is not None: |
There was a problem hiding this comment.
Is this line only for llava since it's the only model that doesn't generate logits?
|
On an H100, three of the convergence tests are failing: They all have similar trajectories as the reference I think it's a product of introducing logits tests where there were none to begin with, rather than this PR changing logit computation behavior. No problems with loss. |
|
@connermanuel What you showed seems like a numerical error to me. Feel free to relax logits tolerances of those failing models. |
|
@Tcc0403 I have updated the logits tolerances for select models. I tried to keep them reasonable but |
Mark a TODO next to qwen_25_vl logits tolerances. I'll further investigate the issue. |
|
There is already a TODO beside the params for those models because the loss was already relaxed. I'll adjust that todo. I also left the original logits tolerances in a comment |
|
@Tcc0403 @yundai424 |
Yes, merging it now. Thanks for the contribution! |
## Summary `llama4.lce_forward` is the only one of the 42 forwards under `transformers/model/` that has no `skip_logits` parameter. It still decides on its own: ```python if self.training and (labels is not None or shift_labels is not None): ``` linkedin#704 added `skip_logits` precisely so a caller could override that, and swept every model that existed on 2025-05-23. llama4 arrived a month later in linkedin#740 and never picked it up; everything added since has it. Because the signature does not name it, a `skip_logits` argument lands in `**kwargs` and is silently ignored, so `skip_logits=False` during training still takes the fused path and returns `logits=None`. That is the one thing the flag exists to prevent, and the convergence harness relies on it, setting `eval_batch["skip_logits"] = False` before reading `eval_output.logits`. The change mirrors `mllama`, which has the identical `LigerForCausalLMLoss` shape. `skip_logits=None` evaluates to the previous condition, so nothing moves for callers that do not pass it. ## Testing Done New `test/transformers/test_llama4.py`. Both cases stay on the non-fused branch, so they run without a GPU: - `skip_logits=False` in training mode returns logits and a loss. On `main` this fails: the flag is ignored, the fused path runs, and on a CPU box Triton raises `RuntimeError: 0 active drivers`. On a GPU box it fails on `logits is None` instead. - `skip_logits=True` with no labels raises `ValueError`, as it does on every other model. On `main` this is `DID NOT RAISE`. - `pytest test/transformers/test_monkey_patch.py test/transformers/test_llama4.py`: 65 passed / 1 skipped (63 + the 2 new; the skip is `muse_glimmer` missing from the installed transformers). - `ruff check .` and `ruff format --check .` with the v0.14.11 pinned in `.pre-commit-config.yaml`: clean. Hardware Type: CPU. Ran on transformers 5.9.0 / torch 2.11.0. --------- Co-authored-by: Vaibhav Jindal <vaibhav.jndl@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
More context in #703
This adds a kwarg to the forward method of models that allows users to choose if they want to use fused LCE or if they want to materialize logits and use regular CE loss. Currently this decision is made implicitly using model state.
Testing Done
Ran this on a downstream transformers pipeline and measured peak memory consumption. Reduced by as much as 80% on some runs as confirmed, with no effect on quality. Still running repo tests, but shouldnt expect any surprises.
make testto ensure correctnessmake checkstyleto ensure code stylemake test-convergenceto ensure convergence