From f438a2e842ef5205e705f913d1558c35cb394af1 Mon Sep 17 00:00:00 2001 From: Cyril Vallez Date: Mon, 13 Jul 2026 18:29:08 +0900 Subject: [PATCH 1/9] kernel native --- .../models/qwen3_5/modeling_qwen3_5.py | 58 +++++++++----- .../qwen3_5_moe/modeling_qwen3_5_moe.py | 58 +++++++++----- .../models/qwen3_next/modeling_qwen3_next.py | 79 +++++++++++-------- .../models/qwen3_next/modular_qwen3_next.py | 77 ++++++++++-------- 4 files changed, 167 insertions(+), 105 deletions(-) diff --git a/src/transformers/models/qwen3_5/modeling_qwen3_5.py b/src/transformers/models/qwen3_5/modeling_qwen3_5.py index 1f695935030c..f56c33ae37fd 100644 --- a/src/transformers/models/qwen3_5/modeling_qwen3_5.py +++ b/src/transformers/models/qwen3_5/modeling_qwen3_5.py @@ -32,7 +32,7 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_kernel_forward_from_hub +from ...integrations import use_kernel_forward_from_hub, use_kernel_func_from_hub from ...integrations.accelerate import force_accelerate_hooks from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs @@ -58,18 +58,13 @@ maybe_autocast, merge_with_config_defaults, ) -from ...utils.import_utils import is_causal_conv1d_available, is_flash_linear_attention_available +from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import capture_outputs from ...vision_utils import get_vision_bilinear_indices_and_weights, get_vision_cu_seqlens, get_vision_position_ids from ..auto.modeling_auto import AutoModel from .configuration_qwen3_5 import Qwen3_5Config, Qwen3_5TextConfig, Qwen3_5VisionConfig -if is_causal_conv1d_available(): - from causal_conv1d import causal_conv1d_fn, causal_conv1d_update -else: - causal_conv1d_update, causal_conv1d_fn = None, None - if is_flash_linear_attention_available(): from fla.modules import FusedRMSNormGated from fla.ops.gated_delta_rule import chunk_gated_delta_rule, fused_recurrent_gated_delta_rule @@ -216,17 +211,16 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): return hidden_states -is_fast_path_available = all( - (causal_conv1d_fn, causal_conv1d_update, chunk_gated_delta_rule, fused_recurrent_gated_delta_rule) -) +is_fast_path_available = all((chunk_gated_delta_rule, fused_recurrent_gated_delta_rule)) -def torch_causal_conv1d_update( - hidden_states, - conv_state, - weight, - bias=None, - activation=None, +@use_kernel_func_from_hub("causal_conv1d_update") +def causal_conv1d_update( + hidden_states: torch.Tensor, + conv_state: torch.Tensor, + weight: nn.Parameter, + bias: nn.Parameter | None = None, + activation: str | None = None, ): _, hidden_size, seq_len = hidden_states.shape state_len = conv_state.shape[-1] @@ -234,9 +228,33 @@ def torch_causal_conv1d_update( hidden_states_new = torch.cat([conv_state, hidden_states], dim=-1).to(weight.dtype) conv_state.copy_(hidden_states_new[:, :, -state_len:]) out = F.conv1d(hidden_states_new, weight.unsqueeze(1), bias, padding=0, groups=hidden_size) - out = F.silu(out[:, :, -seq_len:]) - out = out.to(hidden_states.dtype) - return out + out = out[:, :, -seq_len:] + if activation is not None: + out = ACT2FN[activation](out) + return out.to(hidden_states.dtype) + + +@use_kernel_func_from_hub("causal_conv1d_fn") +def causal_conv1d_fn( + hidden_states: torch.Tensor, + weight: nn.Parameter, + bias: nn.Parameter | None = None, + activation: str | None = None, + **kwargs, +): + _, hidden_size, seq_len = hidden_states.shape + padding = weight.shape[-1] - 1 + + out = F.conv1d( + hidden_states.to(weight.dtype), + weight=weight.unsqueeze(1), + bias=bias, + padding=padding, + groups=hidden_size, + )[:, :, :seq_len] + if activation is not None: + out = ACT2FN[activation](out) + return out.to(hidden_states.dtype) def l2norm(x: torch.FloatTensor, dim: int = -1, eps: float = 1e-6): @@ -418,8 +436,6 @@ def __init__(self, config: Qwen3_5Config, layer_idx: int): self.out_proj = nn.Linear(self.value_dim, self.hidden_size, bias=False) - self.causal_conv1d_fn = causal_conv1d_fn - self.causal_conv1d_update = causal_conv1d_update or torch_causal_conv1d_update self.chunk_gated_delta_rule = chunk_gated_delta_rule or torch_chunk_gated_delta_rule self.recurrent_gated_delta_rule = fused_recurrent_gated_delta_rule or torch_recurrent_gated_delta_rule diff --git a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py index 643af3afd48b..d601fb7c6ac7 100644 --- a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py +++ b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py @@ -32,7 +32,7 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_experts_implementation, use_kernel_forward_from_hub +from ...integrations import use_experts_implementation, use_kernel_forward_from_hub, use_kernel_func_from_hub from ...integrations.accelerate import force_accelerate_hooks from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs @@ -55,18 +55,13 @@ maybe_autocast, merge_with_config_defaults, ) -from ...utils.import_utils import is_causal_conv1d_available, is_flash_linear_attention_available +from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import OutputRecorder, capture_outputs from ...vision_utils import get_vision_bilinear_indices_and_weights, get_vision_cu_seqlens, get_vision_position_ids from ..auto.modeling_auto import AutoModel from .configuration_qwen3_5_moe import Qwen3_5MoeConfig, Qwen3_5MoeTextConfig, Qwen3_5MoeVisionConfig -if is_causal_conv1d_available(): - from causal_conv1d import causal_conv1d_fn, causal_conv1d_update -else: - causal_conv1d_update, causal_conv1d_fn = None, None - if is_flash_linear_attention_available(): from fla.modules import FusedRMSNormGated from fla.ops.gated_delta_rule import chunk_gated_delta_rule, fused_recurrent_gated_delta_rule @@ -213,17 +208,16 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): return hidden_states -is_fast_path_available = all( - (causal_conv1d_fn, causal_conv1d_update, chunk_gated_delta_rule, fused_recurrent_gated_delta_rule) -) +is_fast_path_available = all((chunk_gated_delta_rule, fused_recurrent_gated_delta_rule)) -def torch_causal_conv1d_update( - hidden_states, - conv_state, - weight, - bias=None, - activation=None, +@use_kernel_func_from_hub("causal_conv1d_update") +def causal_conv1d_update( + hidden_states: torch.Tensor, + conv_state: torch.Tensor, + weight: nn.Parameter, + bias: nn.Parameter | None = None, + activation: str | None = None, ): _, hidden_size, seq_len = hidden_states.shape state_len = conv_state.shape[-1] @@ -231,9 +225,33 @@ def torch_causal_conv1d_update( hidden_states_new = torch.cat([conv_state, hidden_states], dim=-1).to(weight.dtype) conv_state.copy_(hidden_states_new[:, :, -state_len:]) out = F.conv1d(hidden_states_new, weight.unsqueeze(1), bias, padding=0, groups=hidden_size) - out = F.silu(out[:, :, -seq_len:]) - out = out.to(hidden_states.dtype) - return out + out = out[:, :, -seq_len:] + if activation is not None: + out = ACT2FN[activation](out) + return out.to(hidden_states.dtype) + + +@use_kernel_func_from_hub("causal_conv1d_fn") +def causal_conv1d_fn( + hidden_states: torch.Tensor, + weight: nn.Parameter, + bias: nn.Parameter | None = None, + activation: str | None = None, + **kwargs, +): + _, hidden_size, seq_len = hidden_states.shape + padding = weight.shape[-1] - 1 + + out = F.conv1d( + hidden_states.to(weight.dtype), + weight=weight.unsqueeze(1), + bias=bias, + padding=padding, + groups=hidden_size, + )[:, :, :seq_len] + if activation is not None: + out = ACT2FN[activation](out) + return out.to(hidden_states.dtype) def l2norm(x: torch.FloatTensor, dim: int = -1, eps: float = 1e-6): @@ -415,8 +433,6 @@ def __init__(self, config: Qwen3_5MoeConfig, layer_idx: int): self.out_proj = nn.Linear(self.value_dim, self.hidden_size, bias=False) - self.causal_conv1d_fn = causal_conv1d_fn - self.causal_conv1d_update = causal_conv1d_update or torch_causal_conv1d_update self.chunk_gated_delta_rule = chunk_gated_delta_rule or torch_chunk_gated_delta_rule self.recurrent_gated_delta_rule = fused_recurrent_gated_delta_rule or torch_recurrent_gated_delta_rule diff --git a/src/transformers/models/qwen3_next/modeling_qwen3_next.py b/src/transformers/models/qwen3_next/modeling_qwen3_next.py index 95c506aaf8e1..0881208a4a23 100644 --- a/src/transformers/models/qwen3_next/modeling_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modeling_qwen3_next.py @@ -29,7 +29,7 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_experts_implementation +from ...integrations import use_experts_implementation, use_kernel_func_from_hub from ...integrations.accelerate import force_accelerate_hooks from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs @@ -45,16 +45,11 @@ from ...processing_utils import Unpack from ...utils import TransformersKwargs, auto_docstring, can_return_tuple, logging from ...utils.generic import maybe_autocast, merge_with_config_defaults -from ...utils.import_utils import is_causal_conv1d_available, is_flash_linear_attention_available +from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import OutputRecorder, capture_outputs from .configuration_qwen3_next import Qwen3NextConfig -if is_causal_conv1d_available(): - from causal_conv1d import causal_conv1d_fn, causal_conv1d_update -else: - causal_conv1d_update, causal_conv1d_fn = None, None - if is_flash_linear_attention_available(): from fla.modules import FusedRMSNormGated from fla.ops.gated_delta_rule import chunk_gated_delta_rule, fused_recurrent_gated_delta_rule @@ -342,17 +337,16 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): return hidden_states -is_fast_path_available = all( - (causal_conv1d_fn, causal_conv1d_update, chunk_gated_delta_rule, fused_recurrent_gated_delta_rule) -) +is_fast_path_available = all((chunk_gated_delta_rule, fused_recurrent_gated_delta_rule)) -def torch_causal_conv1d_update( - hidden_states, - conv_state, - weight, - bias=None, - activation=None, +@use_kernel_func_from_hub("causal_conv1d_update") +def causal_conv1d_update( + hidden_states: torch.Tensor, + conv_state: torch.Tensor, + weight: nn.Parameter, + bias: nn.Parameter | None = None, + activation: str | None = None, ): _, hidden_size, seq_len = hidden_states.shape state_len = conv_state.shape[-1] @@ -360,9 +354,33 @@ def torch_causal_conv1d_update( hidden_states_new = torch.cat([conv_state, hidden_states], dim=-1).to(weight.dtype) conv_state.copy_(hidden_states_new[:, :, -state_len:]) out = F.conv1d(hidden_states_new, weight.unsqueeze(1), bias, padding=0, groups=hidden_size) - out = F.silu(out[:, :, -seq_len:]) - out = out.to(hidden_states.dtype) - return out + out = out[:, :, -seq_len:] + if activation is not None: + out = ACT2FN[activation](out) + return out.to(hidden_states.dtype) + + +@use_kernel_func_from_hub("causal_conv1d_fn") +def causal_conv1d_fn( + hidden_states: torch.Tensor, + weight: nn.Parameter, + bias: nn.Parameter | None = None, + activation: str | None = None, + **kwargs, +): + _, hidden_size, seq_len = hidden_states.shape + padding = weight.shape[-1] - 1 + + out = F.conv1d( + hidden_states.to(weight.dtype), + weight=weight.unsqueeze(1), + bias=bias, + padding=padding, + groups=hidden_size, + )[:, :, :seq_len] + if activation is not None: + out = ACT2FN[activation](out) + return out.to(hidden_states.dtype) def l2norm(x: torch.FloatTensor, dim: int = -1, eps: float = 1e-6): @@ -549,8 +567,6 @@ def __init__(self, config: Qwen3NextConfig, layer_idx: int): self.out_proj = nn.Linear(self.value_dim, self.hidden_size, bias=False) - self.causal_conv1d_fn = causal_conv1d_fn - self.causal_conv1d_update = causal_conv1d_update or torch_causal_conv1d_update self.chunk_gated_delta_rule = chunk_gated_delta_rule or torch_chunk_gated_delta_rule self.recurrent_gated_delta_rule = fused_recurrent_gated_delta_rule or torch_recurrent_gated_delta_rule @@ -626,7 +642,7 @@ def forward( if use_precomputed_states and seq_len == 1: # Single-token cached decode: the fused per-step kernel updates the conv state in-place. - mixed_qkv = self.causal_conv1d_update( + mixed_qkv = causal_conv1d_update( mixed_qkv, conv_state, self.conv1d.weight.squeeze(1), @@ -643,16 +659,15 @@ def forward( if cache_params is not None: new_conv_state = F.pad(mixed_qkv, (self.conv_kernel_size - mixed_qkv.shape[-1], 0)) cache_params.update_conv_state(new_conv_state, self.layer_idx) - if self.causal_conv1d_fn is not None: - mixed_qkv = self.causal_conv1d_fn( - x=mixed_qkv, - weight=self.conv1d.weight.squeeze(1), - bias=self.conv1d.bias, - activation=self.activation, - seq_idx=kwargs.get("seq_idx"), - ) - else: - mixed_qkv = F.silu(self.conv1d(mixed_qkv)[:, :, : mixed_qkv.shape[-1]]) + + mixed_qkv = causal_conv1d_fn( + mixed_qkv, + self.conv1d.weight.squeeze(1), + self.conv1d.bias, + activation=self.activation, + seq_idx=kwargs.get("seq_idx"), + ) + if use_precomputed_states: mixed_qkv = mixed_qkv[:, :, -seq_len:] diff --git a/src/transformers/models/qwen3_next/modular_qwen3_next.py b/src/transformers/models/qwen3_next/modular_qwen3_next.py index 86f31ad1431d..6266587a3ff9 100644 --- a/src/transformers/models/qwen3_next/modular_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modular_qwen3_next.py @@ -23,6 +23,7 @@ from ... import initialization as init from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache +from ...integrations import use_kernel_func_from_hub from ...integrations.accelerate import force_accelerate_hooks from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs @@ -32,7 +33,6 @@ from ...utils import TransformersKwargs, auto_docstring, logging from ...utils.generic import merge_with_config_defaults, no_inherit_decorator from ...utils.import_utils import ( - is_causal_conv1d_available, is_flash_linear_attention_available, ) from ...utils.output_capturing import OutputRecorder, capture_outputs @@ -55,11 +55,6 @@ from .configuration_qwen3_next import Qwen3NextConfig -if is_causal_conv1d_available(): - from causal_conv1d import causal_conv1d_fn, causal_conv1d_update -else: - causal_conv1d_update, causal_conv1d_fn = None, None - if is_flash_linear_attention_available(): from fla.modules import FusedRMSNormGated from fla.ops.gated_delta_rule import chunk_gated_delta_rule, fused_recurrent_gated_delta_rule @@ -68,9 +63,7 @@ FusedRMSNormGated = None -is_fast_path_available = all( - (causal_conv1d_fn, causal_conv1d_update, chunk_gated_delta_rule, fused_recurrent_gated_delta_rule) -) +is_fast_path_available = all((chunk_gated_delta_rule, fused_recurrent_gated_delta_rule)) logger = logging.get_logger(__name__) @@ -188,12 +181,13 @@ def forward( return attn_output, attn_weights -def torch_causal_conv1d_update( - hidden_states, - conv_state, - weight, - bias=None, - activation=None, +@use_kernel_func_from_hub("causal_conv1d_update") +def causal_conv1d_update( + hidden_states: torch.Tensor, + conv_state: torch.Tensor, + weight: nn.Parameter, + bias: nn.Parameter | None = None, + activation: str | None = None, ): _, hidden_size, seq_len = hidden_states.shape state_len = conv_state.shape[-1] @@ -201,9 +195,33 @@ def torch_causal_conv1d_update( hidden_states_new = torch.cat([conv_state, hidden_states], dim=-1).to(weight.dtype) conv_state.copy_(hidden_states_new[:, :, -state_len:]) out = F.conv1d(hidden_states_new, weight.unsqueeze(1), bias, padding=0, groups=hidden_size) - out = F.silu(out[:, :, -seq_len:]) - out = out.to(hidden_states.dtype) - return out + out = out[:, :, -seq_len:] + if activation is not None: + out = ACT2FN[activation](out) + return out.to(hidden_states.dtype) + + +@use_kernel_func_from_hub("causal_conv1d_fn") +def causal_conv1d_fn( + hidden_states: torch.Tensor, + weight: nn.Parameter, + bias: nn.Parameter | None = None, + activation: str | None = None, + **kwargs, +): + _, hidden_size, seq_len = hidden_states.shape + padding = weight.shape[-1] - 1 + + out = F.conv1d( + hidden_states.to(weight.dtype), + weight=weight.unsqueeze(1), + bias=bias, + padding=padding, + groups=hidden_size, + )[:, :, :seq_len] + if activation is not None: + out = ACT2FN[activation](out) + return out.to(hidden_states.dtype) def l2norm(x: torch.FloatTensor, dim: int = -1, eps: float = 1e-6): @@ -390,8 +408,6 @@ def __init__(self, config: Qwen3NextConfig, layer_idx: int): self.out_proj = nn.Linear(self.value_dim, self.hidden_size, bias=False) - self.causal_conv1d_fn = causal_conv1d_fn - self.causal_conv1d_update = causal_conv1d_update or torch_causal_conv1d_update self.chunk_gated_delta_rule = chunk_gated_delta_rule or torch_chunk_gated_delta_rule self.recurrent_gated_delta_rule = fused_recurrent_gated_delta_rule or torch_recurrent_gated_delta_rule @@ -467,7 +483,7 @@ def forward( if use_precomputed_states and seq_len == 1: # Single-token cached decode: the fused per-step kernel updates the conv state in-place. - mixed_qkv = self.causal_conv1d_update( + mixed_qkv = causal_conv1d_update( mixed_qkv, conv_state, self.conv1d.weight.squeeze(1), @@ -484,16 +500,15 @@ def forward( if cache_params is not None: new_conv_state = F.pad(mixed_qkv, (self.conv_kernel_size - mixed_qkv.shape[-1], 0)) cache_params.update_conv_state(new_conv_state, self.layer_idx) - if self.causal_conv1d_fn is not None: - mixed_qkv = self.causal_conv1d_fn( - x=mixed_qkv, - weight=self.conv1d.weight.squeeze(1), - bias=self.conv1d.bias, - activation=self.activation, - seq_idx=kwargs.get("seq_idx"), - ) - else: - mixed_qkv = F.silu(self.conv1d(mixed_qkv)[:, :, : mixed_qkv.shape[-1]]) + + mixed_qkv = causal_conv1d_fn( + mixed_qkv, + self.conv1d.weight.squeeze(1), + self.conv1d.bias, + activation=self.activation, + seq_idx=kwargs.get("seq_idx"), + ) + if use_precomputed_states: mixed_qkv = mixed_qkv[:, :, -seq_len:] From 7c1335b8e8da5085fa460dd7d3be4f841717038a Mon Sep 17 00:00:00 2001 From: Cyril Vallez Date: Mon, 13 Jul 2026 18:31:08 +0900 Subject: [PATCH 2/9] fix warning --- src/transformers/models/qwen3_5/modeling_qwen3_5.py | 5 ++--- src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py | 5 ++--- src/transformers/models/qwen3_next/modeling_qwen3_next.py | 5 ++--- src/transformers/models/qwen3_next/modular_qwen3_next.py | 5 ++--- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/transformers/models/qwen3_5/modeling_qwen3_5.py b/src/transformers/models/qwen3_5/modeling_qwen3_5.py index f56c33ae37fd..dba996a00d99 100644 --- a/src/transformers/models/qwen3_5/modeling_qwen3_5.py +++ b/src/transformers/models/qwen3_5/modeling_qwen3_5.py @@ -441,9 +441,8 @@ def __init__(self, config: Qwen3_5Config, layer_idx: int): if not is_fast_path_available: logger.warning_once( - "The fast path is not available because one of the required library is not installed. Falling back to " - "torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation and" - " https://github.com/Dao-AILab/causal-conv1d" + "The fast path is not available because the required library is not installed. Falling back to " + "torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation" ) self.layer_type = config.layer_types[layer_idx] diff --git a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py index d601fb7c6ac7..b3b2b631ea91 100644 --- a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py +++ b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py @@ -438,9 +438,8 @@ def __init__(self, config: Qwen3_5MoeConfig, layer_idx: int): if not is_fast_path_available: logger.warning_once( - "The fast path is not available because one of the required library is not installed. Falling back to " - "torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation and" - " https://github.com/Dao-AILab/causal-conv1d" + "The fast path is not available because the required library is not installed. Falling back to " + "torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation" ) self.layer_type = config.layer_types[layer_idx] diff --git a/src/transformers/models/qwen3_next/modeling_qwen3_next.py b/src/transformers/models/qwen3_next/modeling_qwen3_next.py index 0881208a4a23..e94b08a2c120 100644 --- a/src/transformers/models/qwen3_next/modeling_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modeling_qwen3_next.py @@ -572,9 +572,8 @@ def __init__(self, config: Qwen3NextConfig, layer_idx: int): if not is_fast_path_available: logger.warning_once( - "The fast path is not available because one of the required library is not installed. Falling back to " - "torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation and" - " https://github.com/Dao-AILab/causal-conv1d" + "The fast path is not available because the required library is not installed. Falling back to " + "torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation" ) self.layer_type = config.layer_types[layer_idx] diff --git a/src/transformers/models/qwen3_next/modular_qwen3_next.py b/src/transformers/models/qwen3_next/modular_qwen3_next.py index 6266587a3ff9..32a7c69964f6 100644 --- a/src/transformers/models/qwen3_next/modular_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modular_qwen3_next.py @@ -413,9 +413,8 @@ def __init__(self, config: Qwen3NextConfig, layer_idx: int): if not is_fast_path_available: logger.warning_once( - "The fast path is not available because one of the required library is not installed. Falling back to " - "torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation and" - " https://github.com/Dao-AILab/causal-conv1d" + "The fast path is not available because the required library is not installed. Falling back to " + "torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation" ) self.layer_type = config.layer_types[layer_idx] From f8ff0db041cf17c35fa6eb0c1ed659ff6de3d301 Mon Sep 17 00:00:00 2001 From: Cyril Vallez Date: Mon, 13 Jul 2026 18:35:27 +0900 Subject: [PATCH 3/9] have to fix other modular to be coherent --- .../models/qwen3_5/modeling_qwen3_5.py | 21 ++++++++--------- .../models/qwen3_5/modular_qwen3_5.py | 23 ++++++++++--------- .../qwen3_5_moe/modeling_qwen3_5_moe.py | 21 ++++++++--------- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/transformers/models/qwen3_5/modeling_qwen3_5.py b/src/transformers/models/qwen3_5/modeling_qwen3_5.py index dba996a00d99..653d6dd2747c 100644 --- a/src/transformers/models/qwen3_5/modeling_qwen3_5.py +++ b/src/transformers/models/qwen3_5/modeling_qwen3_5.py @@ -487,7 +487,7 @@ def forward( if use_precomputed_states and seq_len == 1: # Single-token cached decode: the fused per-step kernel updates the conv state in-place. - mixed_qkv = self.causal_conv1d_update( + mixed_qkv = causal_conv1d_update( mixed_qkv, conv_state, self.conv1d.weight.squeeze(1), @@ -504,16 +504,15 @@ def forward( if cache_params is not None: new_conv_state = F.pad(mixed_qkv, (self.conv_kernel_size - mixed_qkv.shape[-1], 0)) cache_params.update_conv_state(new_conv_state, self.layer_idx) - if self.causal_conv1d_fn is not None: - mixed_qkv = self.causal_conv1d_fn( - x=mixed_qkv, - weight=self.conv1d.weight.squeeze(1), - bias=self.conv1d.bias, - activation=self.activation, - seq_idx=kwargs.get("seq_idx"), - ) - else: - mixed_qkv = F.silu(self.conv1d(mixed_qkv)[:, :, : mixed_qkv.shape[-1]]) + + mixed_qkv = causal_conv1d_fn( + mixed_qkv, + self.conv1d.weight.squeeze(1), + self.conv1d.bias, + activation=self.activation, + seq_idx=kwargs.get("seq_idx"), + ) + if use_precomputed_states: mixed_qkv = mixed_qkv[:, :, -seq_len:] diff --git a/src/transformers/models/qwen3_5/modular_qwen3_5.py b/src/transformers/models/qwen3_5/modular_qwen3_5.py index 2b88938d533d..d81edf5015a3 100644 --- a/src/transformers/models/qwen3_5/modular_qwen3_5.py +++ b/src/transformers/models/qwen3_5/modular_qwen3_5.py @@ -46,6 +46,8 @@ Qwen3NextPreTrainedModel, Qwen3NextRMSNorm, apply_mask_to_padding_states, + causal_conv1d_fn, + causal_conv1d_update, ) from ..qwen3_vl.configuration_qwen3_vl import Qwen3VLConfig, Qwen3VLVisionConfig from ..qwen3_vl.modeling_qwen3_vl import ( @@ -251,7 +253,7 @@ def forward( if use_precomputed_states and seq_len == 1: # Single-token cached decode: the fused per-step kernel updates the conv state in-place. - mixed_qkv = self.causal_conv1d_update( + mixed_qkv = causal_conv1d_update( mixed_qkv, conv_state, self.conv1d.weight.squeeze(1), @@ -268,16 +270,15 @@ def forward( if cache_params is not None: new_conv_state = F.pad(mixed_qkv, (self.conv_kernel_size - mixed_qkv.shape[-1], 0)) cache_params.update_conv_state(new_conv_state, self.layer_idx) - if self.causal_conv1d_fn is not None: - mixed_qkv = self.causal_conv1d_fn( - x=mixed_qkv, - weight=self.conv1d.weight.squeeze(1), - bias=self.conv1d.bias, - activation=self.activation, - seq_idx=kwargs.get("seq_idx"), - ) - else: - mixed_qkv = F.silu(self.conv1d(mixed_qkv)[:, :, : mixed_qkv.shape[-1]]) + + mixed_qkv = causal_conv1d_fn( + mixed_qkv, + self.conv1d.weight.squeeze(1), + self.conv1d.bias, + activation=self.activation, + seq_idx=kwargs.get("seq_idx"), + ) + if use_precomputed_states: mixed_qkv = mixed_qkv[:, :, -seq_len:] diff --git a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py index b3b2b631ea91..e12ee94ea268 100644 --- a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py +++ b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py @@ -484,7 +484,7 @@ def forward( if use_precomputed_states and seq_len == 1: # Single-token cached decode: the fused per-step kernel updates the conv state in-place. - mixed_qkv = self.causal_conv1d_update( + mixed_qkv = causal_conv1d_update( mixed_qkv, conv_state, self.conv1d.weight.squeeze(1), @@ -501,16 +501,15 @@ def forward( if cache_params is not None: new_conv_state = F.pad(mixed_qkv, (self.conv_kernel_size - mixed_qkv.shape[-1], 0)) cache_params.update_conv_state(new_conv_state, self.layer_idx) - if self.causal_conv1d_fn is not None: - mixed_qkv = self.causal_conv1d_fn( - x=mixed_qkv, - weight=self.conv1d.weight.squeeze(1), - bias=self.conv1d.bias, - activation=self.activation, - seq_idx=kwargs.get("seq_idx"), - ) - else: - mixed_qkv = F.silu(self.conv1d(mixed_qkv)[:, :, : mixed_qkv.shape[-1]]) + + mixed_qkv = causal_conv1d_fn( + mixed_qkv, + self.conv1d.weight.squeeze(1), + self.conv1d.bias, + activation=self.activation, + seq_idx=kwargs.get("seq_idx"), + ) + if use_precomputed_states: mixed_qkv = mixed_qkv[:, :, -seq_len:] From 9a8127e887e92062a74e51425aaf07f5f7d2d40e Mon Sep 17 00:00:00 2001 From: Cyril Vallez Date: Mon, 13 Jul 2026 18:41:13 +0900 Subject: [PATCH 4/9] remove useless --- src/transformers/models/qwen3_5/modeling_qwen3_5.py | 1 - src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py | 1 - src/transformers/models/qwen3_next/modeling_qwen3_next.py | 1 - src/transformers/models/qwen3_next/modular_qwen3_next.py | 1 - 4 files changed, 4 deletions(-) diff --git a/src/transformers/models/qwen3_5/modeling_qwen3_5.py b/src/transformers/models/qwen3_5/modeling_qwen3_5.py index 653d6dd2747c..a648a30bdd23 100644 --- a/src/transformers/models/qwen3_5/modeling_qwen3_5.py +++ b/src/transformers/models/qwen3_5/modeling_qwen3_5.py @@ -403,7 +403,6 @@ def __init__(self, config: Qwen3_5Config, layer_idx: int): self.conv_kernel_size = config.linear_conv_kernel_dim self.layer_idx = layer_idx self.activation = config.hidden_act - self.act = ACT2FN[config.hidden_act] self.layer_norm_epsilon = config.rms_norm_eps # QKV diff --git a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py index e12ee94ea268..029e7c6ca572 100644 --- a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py +++ b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py @@ -400,7 +400,6 @@ def __init__(self, config: Qwen3_5MoeConfig, layer_idx: int): self.conv_kernel_size = config.linear_conv_kernel_dim self.layer_idx = layer_idx self.activation = config.hidden_act - self.act = ACT2FN[config.hidden_act] self.layer_norm_epsilon = config.rms_norm_eps # QKV diff --git a/src/transformers/models/qwen3_next/modeling_qwen3_next.py b/src/transformers/models/qwen3_next/modeling_qwen3_next.py index e94b08a2c120..5b3d4d7201a2 100644 --- a/src/transformers/models/qwen3_next/modeling_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modeling_qwen3_next.py @@ -528,7 +528,6 @@ def __init__(self, config: Qwen3NextConfig, layer_idx: int): self.conv_kernel_size = config.linear_conv_kernel_dim self.layer_idx = layer_idx self.activation = config.hidden_act - self.act = ACT2FN[config.hidden_act] self.layer_norm_epsilon = config.rms_norm_eps # QKV diff --git a/src/transformers/models/qwen3_next/modular_qwen3_next.py b/src/transformers/models/qwen3_next/modular_qwen3_next.py index 32a7c69964f6..02a370b2d34c 100644 --- a/src/transformers/models/qwen3_next/modular_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modular_qwen3_next.py @@ -369,7 +369,6 @@ def __init__(self, config: Qwen3NextConfig, layer_idx: int): self.conv_kernel_size = config.linear_conv_kernel_dim self.layer_idx = layer_idx self.activation = config.hidden_act - self.act = ACT2FN[config.hidden_act] self.layer_norm_epsilon = config.rms_norm_eps # QKV From 72b45caf021e8f37d7a1facd1885471d60113ae4 Mon Sep 17 00:00:00 2001 From: Cyril Vallez Date: Mon, 13 Jul 2026 23:17:20 +0900 Subject: [PATCH 5/9] use native lib as well --- src/transformers/integrations/hub_kernels.py | 3 +-- .../models/qwen3_next/modular_qwen3_next.py | 11 +++++----- src/transformers/utils/generic.py | 20 +++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/transformers/integrations/hub_kernels.py b/src/transformers/integrations/hub_kernels.py index 25885dbb2b05..87c30ec543e7 100644 --- a/src/transformers/integrations/hub_kernels.py +++ b/src/transformers/integrations/hub_kernels.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import functools +import importlib import os import re import sys @@ -531,8 +532,6 @@ def lazy_load_kernel(kernel_name: str, mapping: dict[str, ModuleType | None] = _ else: # Try to import is_{kernel_name}_available from ..utils - import importlib - new_kernel_name = kernel_name.replace("-", "_") func_name = f"is_{new_kernel_name}_available" diff --git a/src/transformers/models/qwen3_next/modular_qwen3_next.py b/src/transformers/models/qwen3_next/modular_qwen3_next.py index 02a370b2d34c..463761254842 100644 --- a/src/transformers/models/qwen3_next/modular_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modular_qwen3_next.py @@ -23,7 +23,7 @@ from ... import initialization as init from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache -from ...integrations import use_kernel_func_from_hub +from ...integrations import use_kernel_func_from_hub, use_kernelized_func from ...integrations.accelerate import force_accelerate_hooks from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs @@ -31,10 +31,8 @@ from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel from ...processing_utils import Unpack from ...utils import TransformersKwargs, auto_docstring, logging -from ...utils.generic import merge_with_config_defaults, no_inherit_decorator -from ...utils.import_utils import ( - is_flash_linear_attention_available, -) +from ...utils.generic import merge_with_config_defaults, no_inherit_decorator, replace_with_function_from_package +from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import OutputRecorder, capture_outputs from ..bamba.modeling_bamba import apply_mask_to_padding_states, apply_rotary_pos_emb from ..gemma2.modeling_gemma2 import Gemma2RotaryEmbedding @@ -182,6 +180,7 @@ def forward( @use_kernel_func_from_hub("causal_conv1d_update") +@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") def causal_conv1d_update( hidden_states: torch.Tensor, conv_state: torch.Tensor, @@ -202,6 +201,7 @@ def causal_conv1d_update( @use_kernel_func_from_hub("causal_conv1d_fn") +@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") def causal_conv1d_fn( hidden_states: torch.Tensor, weight: nn.Parameter, @@ -355,6 +355,7 @@ def torch_recurrent_gated_delta_rule( return core_attn_out, last_recurrent_state +@use_kernelized_func([causal_conv1d_update, causal_conv1d_fn]) class Qwen3NextGatedDeltaNet(nn.Module): def __init__(self, config: Qwen3NextConfig, layer_idx: int): super().__init__() diff --git a/src/transformers/utils/generic.py b/src/transformers/utils/generic.py index 9a5a97a023fd..7cb8e0a46949 100644 --- a/src/transformers/utils/generic.py +++ b/src/transformers/utils/generic.py @@ -17,6 +17,7 @@ from __future__ import annotations +import importlib import inspect import json import os @@ -1156,3 +1157,22 @@ def wrapper(*args, **kwargs): return wrapper return decorator + + +def replace_with_function_from_package(function_name: str, package: str): + """ + Decorator that tries to replace the decorated function with `function_name` imported from `package`, if it's available. If not, + simply returns the decorated function. + Useful to define explicit torch fallback functions, while still using an optimized kernel imported from somewhere else if available. + """ + + def decorator(func: Callable) -> Callable: + try: + module = importlib.import_module(package) + function = getattr(module, function_name) + except Exception: + function = func + + return function + + return decorator From 54d80dfb9d3de813a0432f3decc705b854003f34 Mon Sep 17 00:00:00 2001 From: Cyril Vallez Date: Mon, 13 Jul 2026 23:18:59 +0900 Subject: [PATCH 6/9] modular --- src/transformers/models/qwen3_5/modeling_qwen3_5.py | 3 +++ .../models/qwen3_5_moe/modeling_qwen3_5_moe.py | 3 +++ src/transformers/models/qwen3_next/modeling_qwen3_next.py | 7 +++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/transformers/models/qwen3_5/modeling_qwen3_5.py b/src/transformers/models/qwen3_5/modeling_qwen3_5.py index a648a30bdd23..7324b9c23818 100644 --- a/src/transformers/models/qwen3_5/modeling_qwen3_5.py +++ b/src/transformers/models/qwen3_5/modeling_qwen3_5.py @@ -57,6 +57,7 @@ is_flash_attention_requested, maybe_autocast, merge_with_config_defaults, + replace_with_function_from_package, ) from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import capture_outputs @@ -215,6 +216,7 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): @use_kernel_func_from_hub("causal_conv1d_update") +@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") def causal_conv1d_update( hidden_states: torch.Tensor, conv_state: torch.Tensor, @@ -235,6 +237,7 @@ def causal_conv1d_update( @use_kernel_func_from_hub("causal_conv1d_fn") +@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") def causal_conv1d_fn( hidden_states: torch.Tensor, weight: nn.Parameter, diff --git a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py index 029e7c6ca572..4742680964f2 100644 --- a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py +++ b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py @@ -54,6 +54,7 @@ is_flash_attention_requested, maybe_autocast, merge_with_config_defaults, + replace_with_function_from_package, ) from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import OutputRecorder, capture_outputs @@ -212,6 +213,7 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): @use_kernel_func_from_hub("causal_conv1d_update") +@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") def causal_conv1d_update( hidden_states: torch.Tensor, conv_state: torch.Tensor, @@ -232,6 +234,7 @@ def causal_conv1d_update( @use_kernel_func_from_hub("causal_conv1d_fn") +@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") def causal_conv1d_fn( hidden_states: torch.Tensor, weight: nn.Parameter, diff --git a/src/transformers/models/qwen3_next/modeling_qwen3_next.py b/src/transformers/models/qwen3_next/modeling_qwen3_next.py index 5b3d4d7201a2..007318584ab9 100644 --- a/src/transformers/models/qwen3_next/modeling_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modeling_qwen3_next.py @@ -29,7 +29,7 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_experts_implementation, use_kernel_func_from_hub +from ...integrations import use_experts_implementation, use_kernel_func_from_hub, use_kernelized_func from ...integrations.accelerate import force_accelerate_hooks from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs @@ -44,7 +44,7 @@ from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel from ...processing_utils import Unpack from ...utils import TransformersKwargs, auto_docstring, can_return_tuple, logging -from ...utils.generic import maybe_autocast, merge_with_config_defaults +from ...utils.generic import maybe_autocast, merge_with_config_defaults, replace_with_function_from_package from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import OutputRecorder, capture_outputs from .configuration_qwen3_next import Qwen3NextConfig @@ -341,6 +341,7 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): @use_kernel_func_from_hub("causal_conv1d_update") +@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") def causal_conv1d_update( hidden_states: torch.Tensor, conv_state: torch.Tensor, @@ -361,6 +362,7 @@ def causal_conv1d_update( @use_kernel_func_from_hub("causal_conv1d_fn") +@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") def causal_conv1d_fn( hidden_states: torch.Tensor, weight: nn.Parameter, @@ -514,6 +516,7 @@ def torch_recurrent_gated_delta_rule( return core_attn_out, last_recurrent_state +@use_kernelized_func([causal_conv1d_update, causal_conv1d_fn]) class Qwen3NextGatedDeltaNet(nn.Module): def __init__(self, config: Qwen3NextConfig, layer_idx: int): super().__init__() From d2beaf6423d3617cd4b133e0423671fa08903742 Mon Sep 17 00:00:00 2001 From: Cyril Vallez Date: Mon, 13 Jul 2026 23:30:44 +0900 Subject: [PATCH 7/9] combine them --- src/transformers/integrations/hub_kernels.py | 21 +++++++++++++++++++ .../models/qwen3_5/modeling_qwen3_5.py | 10 ++++----- .../qwen3_5_moe/modeling_qwen3_5_moe.py | 10 ++++----- .../models/qwen3_next/modeling_qwen3_next.py | 11 +++++----- .../models/qwen3_next/modular_qwen3_next.py | 11 +++++----- src/transformers/utils/generic.py | 20 ------------------ 6 files changed, 39 insertions(+), 44 deletions(-) diff --git a/src/transformers/integrations/hub_kernels.py b/src/transformers/integrations/hub_kernels.py index 87c30ec543e7..732b56f30181 100644 --- a/src/transformers/integrations/hub_kernels.py +++ b/src/transformers/integrations/hub_kernels.py @@ -853,6 +853,27 @@ def _noop_forward(self, *args, **kwargs): kernel_config.kernel_mapping = new_mapping +def use_kernel_func_from_hub_with_fallback(func_name: str, package: str): + """ + Decorator that tries to replace the decorated function with `func_name` imported from `package`, if it's available. If not, + simply returns the decorated function. + Useful to define explicit torch fallback functions, while still using an optimized kernel imported from somewhere else if available. + """ + + kernel_wrapper_decorator = use_kernel_func_from_hub(func_name) + + def decorator(func: Callable) -> Callable: + try: + module = importlib.import_module(package) + function = getattr(module, func_name) + except Exception: + function = func + + return kernel_wrapper_decorator(function) + + return decorator + + __all__ = [ "LayerRepository", "get_kernel", diff --git a/src/transformers/models/qwen3_5/modeling_qwen3_5.py b/src/transformers/models/qwen3_5/modeling_qwen3_5.py index 7324b9c23818..0441d04002fc 100644 --- a/src/transformers/models/qwen3_5/modeling_qwen3_5.py +++ b/src/transformers/models/qwen3_5/modeling_qwen3_5.py @@ -32,8 +32,9 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_kernel_forward_from_hub, use_kernel_func_from_hub +from ...integrations import use_kernel_forward_from_hub from ...integrations.accelerate import force_accelerate_hooks +from ...integrations.hub_kernels import use_kernel_func_from_hub_with_fallback from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_layers import ( @@ -57,7 +58,6 @@ is_flash_attention_requested, maybe_autocast, merge_with_config_defaults, - replace_with_function_from_package, ) from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import capture_outputs @@ -215,8 +215,7 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): is_fast_path_available = all((chunk_gated_delta_rule, fused_recurrent_gated_delta_rule)) -@use_kernel_func_from_hub("causal_conv1d_update") -@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") +@use_kernel_func_from_hub_with_fallback("causal_conv1d_update", "causal_conv1d") def causal_conv1d_update( hidden_states: torch.Tensor, conv_state: torch.Tensor, @@ -236,8 +235,7 @@ def causal_conv1d_update( return out.to(hidden_states.dtype) -@use_kernel_func_from_hub("causal_conv1d_fn") -@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") +@use_kernel_func_from_hub_with_fallback("causal_conv1d_fn", "causal_conv1d") def causal_conv1d_fn( hidden_states: torch.Tensor, weight: nn.Parameter, diff --git a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py index 4742680964f2..ff6bb720eaf5 100644 --- a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py +++ b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py @@ -32,8 +32,9 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_experts_implementation, use_kernel_forward_from_hub, use_kernel_func_from_hub +from ...integrations import use_experts_implementation, use_kernel_forward_from_hub from ...integrations.accelerate import force_accelerate_hooks +from ...integrations.hub_kernels import use_kernel_func_from_hub_with_fallback from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_layers import GradientCheckpointingLayer @@ -54,7 +55,6 @@ is_flash_attention_requested, maybe_autocast, merge_with_config_defaults, - replace_with_function_from_package, ) from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import OutputRecorder, capture_outputs @@ -212,8 +212,7 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): is_fast_path_available = all((chunk_gated_delta_rule, fused_recurrent_gated_delta_rule)) -@use_kernel_func_from_hub("causal_conv1d_update") -@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") +@use_kernel_func_from_hub_with_fallback("causal_conv1d_update", "causal_conv1d") def causal_conv1d_update( hidden_states: torch.Tensor, conv_state: torch.Tensor, @@ -233,8 +232,7 @@ def causal_conv1d_update( return out.to(hidden_states.dtype) -@use_kernel_func_from_hub("causal_conv1d_fn") -@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") +@use_kernel_func_from_hub_with_fallback("causal_conv1d_fn", "causal_conv1d") def causal_conv1d_fn( hidden_states: torch.Tensor, weight: nn.Parameter, diff --git a/src/transformers/models/qwen3_next/modeling_qwen3_next.py b/src/transformers/models/qwen3_next/modeling_qwen3_next.py index 007318584ab9..8bc3ae758c76 100644 --- a/src/transformers/models/qwen3_next/modeling_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modeling_qwen3_next.py @@ -29,8 +29,9 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_experts_implementation, use_kernel_func_from_hub, use_kernelized_func +from ...integrations import use_experts_implementation, use_kernelized_func from ...integrations.accelerate import force_accelerate_hooks +from ...integrations.hub_kernels import use_kernel_func_from_hub_with_fallback from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_layers import ( @@ -44,7 +45,7 @@ from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel from ...processing_utils import Unpack from ...utils import TransformersKwargs, auto_docstring, can_return_tuple, logging -from ...utils.generic import maybe_autocast, merge_with_config_defaults, replace_with_function_from_package +from ...utils.generic import maybe_autocast, merge_with_config_defaults from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import OutputRecorder, capture_outputs from .configuration_qwen3_next import Qwen3NextConfig @@ -340,8 +341,7 @@ def apply_mask_to_padding_states(hidden_states, attention_mask): is_fast_path_available = all((chunk_gated_delta_rule, fused_recurrent_gated_delta_rule)) -@use_kernel_func_from_hub("causal_conv1d_update") -@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") +@use_kernel_func_from_hub_with_fallback("causal_conv1d_update", "causal_conv1d") def causal_conv1d_update( hidden_states: torch.Tensor, conv_state: torch.Tensor, @@ -361,8 +361,7 @@ def causal_conv1d_update( return out.to(hidden_states.dtype) -@use_kernel_func_from_hub("causal_conv1d_fn") -@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") +@use_kernel_func_from_hub_with_fallback("causal_conv1d_fn", "causal_conv1d") def causal_conv1d_fn( hidden_states: torch.Tensor, weight: nn.Parameter, diff --git a/src/transformers/models/qwen3_next/modular_qwen3_next.py b/src/transformers/models/qwen3_next/modular_qwen3_next.py index 463761254842..9658c252d0c2 100644 --- a/src/transformers/models/qwen3_next/modular_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modular_qwen3_next.py @@ -23,15 +23,16 @@ from ... import initialization as init from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache -from ...integrations import use_kernel_func_from_hub, use_kernelized_func +from ...integrations import use_kernelized_func from ...integrations.accelerate import force_accelerate_hooks +from ...integrations.hub_kernels import use_kernel_func_from_hub_with_fallback from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_outputs import MoeCausalLMOutputWithPast, MoeModelOutputWithPast from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel from ...processing_utils import Unpack from ...utils import TransformersKwargs, auto_docstring, logging -from ...utils.generic import merge_with_config_defaults, no_inherit_decorator, replace_with_function_from_package +from ...utils.generic import merge_with_config_defaults, no_inherit_decorator from ...utils.import_utils import is_flash_linear_attention_available from ...utils.output_capturing import OutputRecorder, capture_outputs from ..bamba.modeling_bamba import apply_mask_to_padding_states, apply_rotary_pos_emb @@ -179,8 +180,7 @@ def forward( return attn_output, attn_weights -@use_kernel_func_from_hub("causal_conv1d_update") -@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") +@use_kernel_func_from_hub_with_fallback("causal_conv1d_update", "causal_conv1d") def causal_conv1d_update( hidden_states: torch.Tensor, conv_state: torch.Tensor, @@ -200,8 +200,7 @@ def causal_conv1d_update( return out.to(hidden_states.dtype) -@use_kernel_func_from_hub("causal_conv1d_fn") -@replace_with_function_from_package("causal_conv1d_update", "causal_conv1d") +@use_kernel_func_from_hub_with_fallback("causal_conv1d_fn", "causal_conv1d") def causal_conv1d_fn( hidden_states: torch.Tensor, weight: nn.Parameter, diff --git a/src/transformers/utils/generic.py b/src/transformers/utils/generic.py index 7cb8e0a46949..9a5a97a023fd 100644 --- a/src/transformers/utils/generic.py +++ b/src/transformers/utils/generic.py @@ -17,7 +17,6 @@ from __future__ import annotations -import importlib import inspect import json import os @@ -1157,22 +1156,3 @@ def wrapper(*args, **kwargs): return wrapper return decorator - - -def replace_with_function_from_package(function_name: str, package: str): - """ - Decorator that tries to replace the decorated function with `function_name` imported from `package`, if it's available. If not, - simply returns the decorated function. - Useful to define explicit torch fallback functions, while still using an optimized kernel imported from somewhere else if available. - """ - - def decorator(func: Callable) -> Callable: - try: - module = importlib.import_module(package) - function = getattr(module, function_name) - except Exception: - function = func - - return function - - return decorator From c256c47b5d7aeb8670f11735983d23d07a7adb90 Mon Sep 17 00:00:00 2001 From: Cyril Vallez Date: Mon, 13 Jul 2026 23:36:51 +0900 Subject: [PATCH 8/9] doc --- src/transformers/integrations/hub_kernels.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/transformers/integrations/hub_kernels.py b/src/transformers/integrations/hub_kernels.py index 732b56f30181..d774575ad3cd 100644 --- a/src/transformers/integrations/hub_kernels.py +++ b/src/transformers/integrations/hub_kernels.py @@ -855,9 +855,14 @@ def _noop_forward(self, *args, **kwargs): def use_kernel_func_from_hub_with_fallback(func_name: str, package: str): """ - Decorator that tries to replace the decorated function with `func_name` imported from `package`, if it's available. If not, - simply returns the decorated function. - Useful to define explicit torch fallback functions, while still using an optimized kernel imported from somewhere else if available. + Similar to `use_kernel_func_from_hub`, but first tries to replace the decorated function with `func_name` imported from `package`, + if it's available. If not, simply applies `use_kernel_func_from_hub` on the decorated function. + Useful to define explicit torch fallback functions, while still using an optimized implementations from either `kernels` or + an auxiliary package (e.g. `causal_conv1d`) if available. + This means that the precedence order will be the following: + - 1st `kernels`, if it's available and `use_kernels=True` + - if the above is not True, then `func_name` imported from `package` if `package` is available + - if None of the above are True, the base decorated function """ kernel_wrapper_decorator = use_kernel_func_from_hub(func_name) From 30e0ff74e97487c9a64694e919fb406a99f2cf45 Mon Sep 17 00:00:00 2001 From: vasqu Date: Mon, 13 Jul 2026 20:42:50 +0200 Subject: [PATCH 9/9] ignore kwargs, allow og --- src/transformers/integrations/__init__.py | 2 + src/transformers/integrations/hub_kernels.py | 54 ++++++++++--------- .../models/qwen3_5/modeling_qwen3_5.py | 3 +- .../qwen3_5_moe/modeling_qwen3_5_moe.py | 7 ++- .../models/qwen3_next/modeling_qwen3_next.py | 3 +- .../models/qwen3_next/modular_qwen3_next.py | 3 +- 6 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/transformers/integrations/__init__.py b/src/transformers/integrations/__init__.py index 2ecc31ae54cf..5d6fc98f1f25 100755 --- a/src/transformers/integrations/__init__.py +++ b/src/transformers/integrations/__init__.py @@ -80,6 +80,7 @@ "replace_kernel_forward_from_hub", "use_kernel_forward_from_hub", "use_kernel_func_from_hub", + "use_kernel_func_from_hub_with_fallback", "use_kernelized_func", ], "integration_utils": [ @@ -241,6 +242,7 @@ replace_kernel_forward_from_hub, use_kernel_forward_from_hub, use_kernel_func_from_hub, + use_kernel_func_from_hub_with_fallback, use_kernelized_func, ) from .integration_utils import ( diff --git a/src/transformers/integrations/hub_kernels.py b/src/transformers/integrations/hub_kernels.py index d774575ad3cd..c69528c001c1 100644 --- a/src/transformers/integrations/hub_kernels.py +++ b/src/transformers/integrations/hub_kernels.py @@ -13,6 +13,7 @@ # limitations under the License. import functools import importlib +import inspect import os import re import sys @@ -32,6 +33,7 @@ is_kernels_available, is_rocm_platform, is_torch_available, + resolve_internal_import, ) from .flash_attention import flash_attention_forward @@ -654,6 +656,32 @@ def new_init(self, *args, **kwargs): return decorator +def use_kernel_func_from_hub_with_fallback(package: str, func_name: str, internal_path: str | None = None): + # TODO: change when we sync to 0.16.x+ + kernel_wrapper_decorator = use_kernel_func_from_hub(func_name) + + def decorator(torch_function: Callable) -> Callable: + implementation = None + try: + module = importlib.import_module(package) + implementation = resolve_internal_import(module, internal_path or func_name) + except Exception: + implementation = torch_function + finally: + implementation = torch_function if implementation is None else implementation + + applicable_params = inspect.signature(implementation).parameters + + @functools.wraps(torch_function) + def wrapped(*args, **kwargs): + kwargs = {k: v for k, v in kwargs.items() if k in applicable_params} + return implementation(*args, **kwargs) + + return kernel_wrapper_decorator(wrapped) + + return decorator + + # Whether to allow hub kernels coming from untrusted repos, i.e. repos outside `kernels-community` ALLOW_ALL_KERNELS = False @@ -853,32 +881,6 @@ def _noop_forward(self, *args, **kwargs): kernel_config.kernel_mapping = new_mapping -def use_kernel_func_from_hub_with_fallback(func_name: str, package: str): - """ - Similar to `use_kernel_func_from_hub`, but first tries to replace the decorated function with `func_name` imported from `package`, - if it's available. If not, simply applies `use_kernel_func_from_hub` on the decorated function. - Useful to define explicit torch fallback functions, while still using an optimized implementations from either `kernels` or - an auxiliary package (e.g. `causal_conv1d`) if available. - This means that the precedence order will be the following: - - 1st `kernels`, if it's available and `use_kernels=True` - - if the above is not True, then `func_name` imported from `package` if `package` is available - - if None of the above are True, the base decorated function - """ - - kernel_wrapper_decorator = use_kernel_func_from_hub(func_name) - - def decorator(func: Callable) -> Callable: - try: - module = importlib.import_module(package) - function = getattr(module, func_name) - except Exception: - function = func - - return kernel_wrapper_decorator(function) - - return decorator - - __all__ = [ "LayerRepository", "get_kernel", diff --git a/src/transformers/models/qwen3_5/modeling_qwen3_5.py b/src/transformers/models/qwen3_5/modeling_qwen3_5.py index 0441d04002fc..dad105e8b954 100644 --- a/src/transformers/models/qwen3_5/modeling_qwen3_5.py +++ b/src/transformers/models/qwen3_5/modeling_qwen3_5.py @@ -32,9 +32,8 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_kernel_forward_from_hub +from ...integrations import use_kernel_forward_from_hub, use_kernel_func_from_hub_with_fallback from ...integrations.accelerate import force_accelerate_hooks -from ...integrations.hub_kernels import use_kernel_func_from_hub_with_fallback from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_layers import ( diff --git a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py index ff6bb720eaf5..2ad29909ec05 100644 --- a/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py +++ b/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py @@ -32,9 +32,12 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_experts_implementation, use_kernel_forward_from_hub +from ...integrations import ( + use_experts_implementation, + use_kernel_forward_from_hub, + use_kernel_func_from_hub_with_fallback, +) from ...integrations.accelerate import force_accelerate_hooks -from ...integrations.hub_kernels import use_kernel_func_from_hub_with_fallback from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_layers import GradientCheckpointingLayer diff --git a/src/transformers/models/qwen3_next/modeling_qwen3_next.py b/src/transformers/models/qwen3_next/modeling_qwen3_next.py index 8bc3ae758c76..e618ad1462e8 100644 --- a/src/transformers/models/qwen3_next/modeling_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modeling_qwen3_next.py @@ -29,9 +29,8 @@ from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin -from ...integrations import use_experts_implementation, use_kernelized_func +from ...integrations import use_experts_implementation, use_kernel_func_from_hub_with_fallback, use_kernelized_func from ...integrations.accelerate import force_accelerate_hooks -from ...integrations.hub_kernels import use_kernel_func_from_hub_with_fallback from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_layers import ( diff --git a/src/transformers/models/qwen3_next/modular_qwen3_next.py b/src/transformers/models/qwen3_next/modular_qwen3_next.py index 9658c252d0c2..6e9e7bffba37 100644 --- a/src/transformers/models/qwen3_next/modular_qwen3_next.py +++ b/src/transformers/models/qwen3_next/modular_qwen3_next.py @@ -23,9 +23,8 @@ from ... import initialization as init from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache -from ...integrations import use_kernelized_func +from ...integrations import use_kernel_func_from_hub_with_fallback, use_kernelized_func from ...integrations.accelerate import force_accelerate_hooks -from ...integrations.hub_kernels import use_kernel_func_from_hub_with_fallback from ...masking_utils import create_causal_mask, create_recurrent_attention_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_outputs import MoeCausalLMOutputWithPast, MoeModelOutputWithPast