Skip to content

🚨 [Kernels] Refactor all linear attn models & native kernels fallback - #47630

Merged
vasqu merged 48 commits into
huggingface:mainfrom
vasqu:kernels-fallback
Aug 5, 2026
Merged

🚨 [Kernels] Refactor all linear attn models & native kernels fallback#47630
vasqu merged 48 commits into
huggingface:mainfrom
vasqu:kernels-fallback

Conversation

@vasqu

@vasqu vasqu commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

CI

Tl;dr: Allow kernels, og, and torch only to natively coexist along each other. This is also makes kernels as opt in, not as mandatory which caused very weird behavior where it suddenly took precedence even over the og kernels

Model types

  • GDN
  • Mamba2
  • Conv only (inkling, lfm2 etc)
  • Mamba1

Dependent on

Note:

  • There is one subtle difference between the og conv1ds and the hf kernels conv1ds
    • Og fuses the activation into the kernel while the torch fallback and hf kernel do this afterwards (unfused)
    • This is negligible and can be even explained by the difference complation of the kernel binaries
  • It can be negated by passing activation=None and manually applying the activation ...; act(hidden_states)

@HuggingFaceDocBuilderDev

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.

@Cyrilvallez Cyrilvallez 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.

Very very nice, cannot wait for this PR! Just checked bamba for now to give a few early thoughts!

Comment thread src/transformers/models/bamba/modeling_bamba.py Outdated
Comment thread src/transformers/models/bamba/modeling_bamba.py Outdated
Comment on lines +708 to +710
# Only kernels can use this shortcircuit, fallback to normal torch otherwise
if fused_output is not None:
return fused_output

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.

This makes it a bit awkward IMO... Any way to check if the function was found in kernels instead?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Hard to do because kernels can be swapped at runtime at any time

Comment thread src/transformers/models/bamba/modeling_bamba.py Outdated
Comment thread src/transformers/models/bamba/modeling_bamba.py
Comment thread src/transformers/integrations/hub_kernels.py
' I will be talking about the importance of the internet in our lives.\nThe internet is a global'
],
("cuda", 9): [
' I am going to talk about the “Theory of Relativity” by Albert Einstein.\n',

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not sure what caused the change on A10 but the output is the same across all devices now so I wouldn't see it as a regression as the outputs are aligned. I assumed some small matmul diff causing slightly different gens previously

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Workflow Run ⚙️

This comment contains run-slow, running the specified jobs:

models: ["models/falcon_mamba"]
quantizations: []

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

CI Results

Workflow Run ⚙️

Commit Info

Context Commit Description
RUN 142930d3 workflow commit (merge commit)
PR d81829f6 branch commit (from PR)
main 49140dd1 base commit (on main)

⚠️ No test being reported (jobs are skipped or cancelled)!

@vasqu

vasqu commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

run-slow: bamba, falcon_h1, falcon_mamba, granitemoehybrid, inkling, jamba, lfm2, lfm2_moe, mamba, mamba2, minimax, nemotron_h, olmo_hybrid, qwen3_5, qwen3_5_moe, qwen3_next

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Workflow Run ⚙️

This comment contains run-slow, running the specified jobs:

models: ["models/bamba", "models/falcon_h1", "models/falcon_mamba", "models/granitemoehybrid", "models/inkling", "models/jamba", "models/lfm2", "models/lfm2_moe", "models/mamba", "models/mamba2", "models/minimax", "models/nemotron_h", "models/olmo_hybrid", "models/qwen3_5", "models/qwen3_5_moe", "models/qwen3_next"]
quantizations: []

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

CI Results

Workflow Run ⚙️

Commit Info

Context Commit Description
RUN 62f56867 workflow commit (merge commit)
PR 9dabdf29 branch commit (from PR)
main 49140dd1 base commit (on main)

✅ No failing test specific to this PR 🎉 👏 !

@vasqu vasqu mentioned this pull request Aug 4, 2026

@Cyrilvallez Cyrilvallez 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.

All right, very nice work! Still a few important details to fix, but should not be much efforts. Most notably:

  • Make sure we align the name of the torch functions and kernels function everywhere, as most are not the same. This makes it much harder to understand what we do. Having the same name makes it clear for anyone that it's supposed to do the same thing in pure torch
  • Correctly guard all conv parts with and not record_past for speculative decoding/mtp etc, and be coherent between all our implems

Comment on lines +387 to +412
@use_kernel_func_from_hub_with_fallback(
"mamba_split_conv1d_scan_combined",
"mamba_ssm",
)
def mamba2_split_conv1d_scan_combined(
zxbcdt: torch.Tensor,
conv1d_weight: torch.Tensor,
conv1d_bias: torch.Tensor | None,
dt_bias: torch.Tensor,
A: torch.Tensor,
D: torch.Tensor,
chunk_size: int,
initial_states: torch.Tensor | None = None,
dt_limit: tuple[float, float] = (0.0, float("inf")),
return_final_states: bool = False,
activation: str = "silu",
rmsnorm_weight: torch.Tensor | None = None,
rmsnorm_eps: float = 1e-6,
outproj_weight: torch.Tensor | None = None,
outproj_bias: torch.Tensor | None = None,
headdim: int | None = None,
ngroups: int = 1,
norm_before_gate: bool = True,
**kwargs,
):
return None

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.

This is still a bit awkward IMO 🥲 We do need to have all the args and kwargs so that kernels can match the signature right? We cannot simply use mamba2_split_conv1d_scan_combined(*args, **kwargs)?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yea not possible because we need to match the kernels signature

Comment thread src/transformers/models/bamba/modeling_bamba.py Outdated
Comment thread src/transformers/models/bamba/modeling_bamba.py Outdated
Comment thread src/transformers/models/bamba/modeling_bamba.py Outdated
Comment thread src/transformers/models/falcon_h1/modeling_falcon_h1.py Outdated
Comment on lines -96 to +101
class JambaMambaMixer(MambaMixer):
class JambaMambaMixer(FalconMambaMixer):

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.

Is it really better to switch inheritance? Why do we want to add use_mambapy etc?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The main goal here is to show that it's nearly 1:1 in the forward minus mamba inner fn not being usable

Comment thread src/transformers/models/olmo_hybrid/modeling_olmo_hybrid.py
Comment thread src/transformers/models/olmo_hybrid/modeling_olmo_hybrid.py Outdated
Comment on lines +624 to +628
q, k, v = torch.split(
mixed_qkv.transpose(1, 2),
[self.key_dim, self.key_dim, self.value_dim],
dim=-1,
)

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.

Humm actually, is it really better to merge them given that we need to cat and split?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Pretty sure it's worth it, the conv is a bigger limiting factor than the cat and split

(also just easier for our cache in general)

Comment thread src/transformers/models/qwen3_5/modeling_qwen3_5.py
@Cyrilvallez Cyrilvallez changed the title [Kernels] Native fallback 🚨 [Kernels] Refactor all mamba's recurrent part & Native kernels fallback Aug 5, 2026
@Cyrilvallez Cyrilvallez changed the title 🚨 [Kernels] Refactor all mamba's recurrent part & Native kernels fallback 🚨 [Kernels] Refactor all mamba models recurrent part & Native kernels fallback Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

[For maintainers] Suggested jobs to run (before merge)

run-slow: bamba, falcon_h1, falcon_mamba, granitemoehybrid, inkling, jamba, lfm2, lfm2_moe, mamba, mamba2, minimax, nemotron_h, olmo_hybrid, qwen3_5, qwen3_5_moe, qwen3_next

@vasqu vasqu changed the title 🚨 [Kernels] Refactor all mamba models recurrent part & Native kernels fallback 🚨 [Kernels] Refactor all linear attn models & native kernels fallback Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

CI recap

Dashboard: View test results in Grafana
Latest run: 30919052742:1
Result: success | Jobs: 1 | Tests: 1,786 | Failures: 24 | Duration: 2h 31m

@Cyrilvallez Cyrilvallez 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.

Alright, let's go now if you're done with all the changes after offline discussion!! Thanks again, super happy to land it and finally have fully clean mambas! 🤗

@vasqu
vasqu added this pull request to the merge queue Aug 5, 2026
Merged via the queue into huggingface:main with commit e91f7ef Aug 5, 2026
111 checks passed
@vasqu
vasqu deleted the kernels-fallback branch August 5, 2026 09:44
Hakureirm added a commit to Hakureirm/transformers-rwkv that referenced this pull request Aug 6, 2026
…e, adopt standard names

- Drop the private RWKV7_WKV_FUNCTIONS registry and its config knob: it
  duplicated the kernel-substitution mechanism huggingface#47630 just unified across
  linear-attention models. The torch reference is called directly; an
  optimised kernel arrives via hub-kernels when one exists, not a per-model
  registry. The doc section demonstrating the registry goes with it.
- Gate generate's input truncation on is_first_iteration instead of the
  state's existence: a pre-allocated state (the compile contract) or a warm
  state (a resumed chat turn) silently dropped every prompt token but the
  last one. Same gate Mamba uses; bare callers keep the old behaviour.
- Rename cu_seq_lens to the ecosystem's cu_seq_lens_q, so padding-free
  collators reach the packed path instead of being swallowed by kwargs.
- Refuse Rwkv7Cache.crop() loudly (the state is not invertible), fix
  keys_to_ignore_at_inference to name the output this model actually has,
  add the missing explicit models/__init__ re-export, and drop the
  attentions=None output field and ignored output_attentions parameter.
- Tests: generate-with-state equalities, end-to-end left-padded batch
  generate, compiled decode step over allocate_state, the chunked-prefill
  mask-slicing contract, a multi-chunk numpy-oracle case; pin the numpy
  reference to its external sources and the rwkv package version used for
  the integration expectations; let the shared gradient-checkpointing
  trainings run via test_all_params_have_gradient.
- Docs: compile guidance now reflects measurement (reduce-overhead with an
  eager prefill; max-autotune measured slower on this kernel chain).
@Hakureirm Hakureirm mentioned this pull request Aug 6, 2026
5 tasks
Hakureirm added a commit to Hakureirm/transformers-rwkv that referenced this pull request Aug 8, 2026
…e, adopt standard names

- Drop the private RWKV7_WKV_FUNCTIONS registry and its config knob: it
  duplicated the kernel-substitution mechanism huggingface#47630 just unified across
  linear-attention models. The torch reference is called directly; an
  optimised kernel arrives via hub-kernels when one exists, not a per-model
  registry. The doc section demonstrating the registry goes with it.
- Gate generate's input truncation on is_first_iteration instead of the
  state's existence: a pre-allocated state (the compile contract) or a warm
  state (a resumed chat turn) silently dropped every prompt token but the
  last one. Same gate Mamba uses; bare callers keep the old behaviour.
- Rename cu_seq_lens to the ecosystem's cu_seq_lens_q, so padding-free
  collators reach the packed path instead of being swallowed by kwargs.
- Refuse Rwkv7Cache.crop() loudly (the state is not invertible), fix
  keys_to_ignore_at_inference to name the output this model actually has,
  add the missing explicit models/__init__ re-export, and drop the
  attentions=None output field and ignored output_attentions parameter.
- Tests: generate-with-state equalities, end-to-end left-padded batch
  generate, compiled decode step over allocate_state, the chunked-prefill
  mask-slicing contract, a multi-chunk numpy-oracle case; pin the numpy
  reference to its external sources and the rwkv package version used for
  the integration expectations; let the shared gradient-checkpointing
  trainings run via test_all_params_have_gradient.
- Docs: compile guidance now reflects measurement (reduce-overhead with an
  eager prefill; max-autotune measured slower on this kernel chain).
Hakureirm added a commit to Hakureirm/transformers-rwkv that referenced this pull request Aug 15, 2026
…e, adopt standard names

- Drop the private RWKV7_WKV_FUNCTIONS registry and its config knob: it
  duplicated the kernel-substitution mechanism huggingface#47630 just unified across
  linear-attention models. The torch reference is called directly; an
  optimised kernel arrives via hub-kernels when one exists, not a per-model
  registry. The doc section demonstrating the registry goes with it.
- Gate generate's input truncation on is_first_iteration instead of the
  state's existence: a pre-allocated state (the compile contract) or a warm
  state (a resumed chat turn) silently dropped every prompt token but the
  last one. Same gate Mamba uses; bare callers keep the old behaviour.
- Rename cu_seq_lens to the ecosystem's cu_seq_lens_q, so padding-free
  collators reach the packed path instead of being swallowed by kwargs.
- Refuse Rwkv7Cache.crop() loudly (the state is not invertible), fix
  keys_to_ignore_at_inference to name the output this model actually has,
  add the missing explicit models/__init__ re-export, and drop the
  attentions=None output field and ignored output_attentions parameter.
- Tests: generate-with-state equalities, end-to-end left-padded batch
  generate, compiled decode step over allocate_state, the chunked-prefill
  mask-slicing contract, a multi-chunk numpy-oracle case; pin the numpy
  reference to its external sources and the rwkv package version used for
  the integration expectations; let the shared gradient-checkpointing
  trainings run via test_all_params_have_gradient.
- Docs: compile guidance now reflects measurement (reduce-overhead with an
  eager prefill; max-autotune measured slower on this kernel chain).
danielhanchen added a commit to unslothai/unsloth-zoo that referenced this pull request Aug 25, 2026
#1102)

* Vendored FLA: re-resolve kernel closures on modules imported before us

Since huggingface/transformers#47630 the gated delta kernels are bound by
use_kernel_func_from_hub_with_fallback, which resolves the implementation at
decoration time and closes over it. A modeling module imported before fla is live
freezes the pure-PyTorch fallback into that closure, and nothing done to fla
afterwards can reach it. _repair_already_imported_modeling only rebinds module
globals, which these modules no longer have.

Re-apply the decorator to the undecorated function once fla is live, rather than
writing to cell_contents: the wrapper also closes over the implementation's
parameter names, and those differ between the fallback and the kernel, so patching
the implementation alone would filter out arguments the kernel needs.

* Test the repair against the live fla, not against the fallback

A modeling module imported while a real fla install was live froze that install's
kernel into the wrapper. UNSLOTH_FORCE_VENDORED_FLA and the Hopper #640 switch then
purge the install, but the old check treated any non-fallback implementation as
valid and skipped it, so the wrapper kept calling the kernel we replaced the install
to avoid, which is the miscompiled backward.

Compare against the kernel fla resolves to now instead. When there is no live
replacement the rebuild lands on the pure-torch fallback, which is taken
deliberately: torch beats calling into a purged install.

The kernel-hub tests now skip on a transformers predating #47630, where the repair
correctly returns () and there is nothing to patch.
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.

3 participants