Skip to content

Fix FLOPs overcount for models with untied word embeddings - #7450

Merged
albertvillanova merged 2 commits into
huggingface:mainfrom
jayzuccarelli:fix-flops-embedding-lmhead
Sep 30, 2026
Merged

albertvillanova merged 2 commits into
huggingface:mainfrom
jayzuccarelli:fix-flops-embedding-lmhead

Conversation

@jayzuccarelli

@jayzuccarelli jayzuccarelli commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #6708.
compute_flops_per_token charges the input embedding as a 2·V·h matmul, but it's a lookup with no FLOPs, and it charges the LM head as 0 when weights are tied, but the LM head is a 2·V·h matmul either way. So tied models come out right by accident; untied models are overcounted by 2·V·h forward FLOPs per token: +5.44% MFU on a Llama-3-8B-shaped config at seq_len 8192, +3.49% on the tiny Qwen3 test model.

Fix: drop the embedding term, always count the LM head once (removes the tie_word_embeddings branch). Tied-model numbers remain unchanged.

Tests: test_tied_vs_untied_lm_head now asserts tied == untied; new test_vocab_size_scaling checks +ΔV adds exactly 3·2·ΔV·h. Both fail on main, pass with the fix.
Matches how nanochat counts it (raised on the original MFU PR #5698).

Before submitting

  • This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
  • Did you read the contributor guideline, Pull Request section?
  • Was this discussed/approved via a GitHub issue? Please add a link to it if that's the case. Accounting error in FLOPS calculation #6708
  • Did you make sure to update the documentation with your changes?
  • Did you write any new necessary tests?

AI writing disclosure

We welcome the use of AI tools to help with contributions. For transparency and to help us improve our review process, please indicate the level of AI involvement in this PR.

  • No AI usage: the PR was written entirely by a human.
  • AI-assisted: some parts were suggested or improved by AI, but the PR was written and reviewed by a human.
  • AI-generated: the PR was mostly or fully generated by an AI tool.

Who can review?

Anyone in the community is free to review the PR once the tests have passed. Feel free to tag members/contributors who may be interested in your PR.


Note

Low Risk
Changes only analytical FLOP/MFU helpers and unit tests; no training forward/backward or model behavior is modified.

Overview
Corrects per-token training FLOP estimates in compute_flops_per_token used for MFU reporting.

Embedding is no longer counted as a 2·V·h matmul (it's a lookup with zero FLOPs). LM head is always counted once as 2·V·h, regardless of tie_word_embeddings—weight tying saves memory, not the projection compute.

Untied models were previously overcounted by one embedding-sized term; tied totals were accidentally right. Reported MFU for untied configs will increase slightly because the denominator shrinks.

Tests now expect tied and untied FLOPs to match, and add test_vocab_size_scaling so vocab-only changes affect FLOPs by 3·2·ΔV·h (fwd+bwd).

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

Fixes huggingface#6708

compute_flops_per_token charged the input embedding as a 2*V*h matmul
and dropped the LM head when word embeddings are tied. The embedding is
a lookup, and the LM head is a 2*V*h matmul whether or not its weight is
tied. Drop the embedding term and always count the LM head. Tied models
are unchanged; untied models no longer get an extra 2*V*h per token
(+5.4% for a Llama-3-8B shaped config at seq_len 8192).

Tests: test_tied_vs_untied_lm_head now asserts tied == untied, and
test_vocab_size_scaling checks that vocab size adds 3 * 2 * dV * h.
Both fail on main and pass here; TestComputeFlopsPerToken and the rest
of tests/test_utils.py pass; ruff check/format clean.

AI assistance (Claude) was used; I reviewed the change and ran the tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@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.

@albertvillanova albertvillanova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks, the fix is correct: the input embedding is a lookup, and the LM head costs 2 * V * h whether or not its weight is tied, so untied models were overcounted by exactly one vocabulary projection. Pinning tie_word_embeddings = False in test_vocab_size_scaling is the right call, since on a tied config the old code already gave the correct vocabulary delta and the test would not catch the regression.

One nit: could you make the code comments shorter?

@albertvillanova albertvillanova changed the title Fix FLOPS count for input embedding and tied LM head Fix FLOPs overcount for models with untied word embeddings Sep 30, 2026
@albertvillanova
albertvillanova merged commit 3151505 into huggingface:main Sep 30, 2026
2 checks passed
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.

Accounting error in FLOPS calculation

2 participants