2020import torch
2121from torch import nn
2222from torch .nn import functional as F
23+ from transformers import initialization as init
2324from transformers .activations import ACT2FN
2425from transformers .cache_utils import Cache , DynamicCache
2526from transformers .generation import GenerationMixin
4243from .configuration_qwen3_asr import (
4344 Qwen3ASRAudioEncoderConfig ,
4445 Qwen3ASRConfig ,
46+ Qwen3ASRTextConfig ,
4547 Qwen3ASRThinkerConfig ,
4648)
4749
@@ -293,6 +295,11 @@ class Qwen3ASRPreTrainedModel(PreTrainedModel):
293295 "attentions" : Qwen3ASRTextAttention ,
294296 }
295297
298+ def _init_weights (self , module : nn .Module ) -> None :
299+ super ()._init_weights (module )
300+ if isinstance (module , SinusoidsPositionEmbedding ):
301+ init .copy_ (module .positional_embedding , module .compute_default_singular_positional_embedding ())
302+
296303
297304@dataclass
298305class Qwen3ASRThinkerCausalLMOutputWithPast (MoeCausalLMOutputWithPast ):
@@ -439,10 +446,11 @@ def get_rope_index(
439446 """
440447 mrope_position_deltas = []
441448
442- position_ids = attention_mask .float ().cumsum (- 1 ) - 1
449+ position_ids = attention_mask .long ().cumsum (- 1 ) - 1
450+ # Padding uses a placeholder position, which must not affect the reported offset.
451+ max_position_ids = position_ids .max (- 1 , keepdim = True ).values
443452 position_ids .masked_fill_ (attention_mask == 0 , 1 )
444453 position_ids = position_ids .unsqueeze (0 ).expand (3 , - 1 , - 1 ).to (attention_mask .device )
445- max_position_ids = position_ids .max (0 , keepdim = False )[0 ].max (- 1 , keepdim = True )[0 ]
446454 mrope_position_deltas = max_position_ids + 1 - torch .sum (attention_mask , dim = - 1 , keepdim = True )
447455
448456 return position_ids , mrope_position_deltas
@@ -581,15 +589,20 @@ def __init__(self, length, channels, max_timescale=10000):
581589 super ().__init__ ()
582590 if channels % 2 != 0 :
583591 raise ValueError ("SinusoidsPositionEmbedding needs even channels input" )
584- log_timescale_increment = np . log ( max_timescale ) / ( channels // 2 - 1 )
585- inv_timescales = torch . exp ( - log_timescale_increment * torch . arange ( channels // 2 ). float ())
586- scaled_time = torch . arange ( length )[:, np . newaxis ] * inv_timescales [ np . newaxis , :]
592+ self . length = length
593+ self . channels = channels
594+ self . max_timescale = max_timescale
587595 self .register_buffer (
588- "positional_embedding" ,
589- torch .cat ([torch .sin (scaled_time ), torch .cos (scaled_time )], dim = 1 ),
590- persistent = False ,
596+ "positional_embedding" , self .compute_default_singular_positional_embedding (), persistent = False
591597 )
592598
599+ def compute_default_singular_positional_embedding (self ) -> torch .Tensor :
600+ """Rebuild the deterministic audio positions, including after checkpoint loading."""
601+ log_timescale_increment = np .log (self .max_timescale ) / (self .channels // 2 - 1 )
602+ inv_timescales = torch .exp (- log_timescale_increment * torch .arange (self .channels // 2 ).float ())
603+ scaled_time = torch .arange (self .length )[:, np .newaxis ] * inv_timescales [np .newaxis , :]
604+ return torch .cat ([torch .sin (scaled_time ), torch .cos (scaled_time )], dim = 1 )
605+
593606 def forward (self , seqlen : int ):
594607 return self .positional_embedding [:seqlen , :]
595608
@@ -779,25 +792,39 @@ def padded_and_mask_function(self, tensor_list, tensor_len, padding_value=0, pad
779792
780793
781794class Qwen3ASRThinkerTextRotaryEmbedding (nn .Module ):
795+ attention_scaling : float
782796 inv_freq : torch .Tensor # fix linting for `register_buffer`
783797
784798 def __init__ (self , config : Qwen3ASRConfig , device = None ):
785799 super ().__init__ ()
786- if hasattr (config , "rope_scaling" ) and config .rope_scaling is not None :
787- self .rope_type = config .rope_scaling .get ("rope_type" , "default" )
788- else :
789- self .rope_type = "default"
800+ self .rope_type = config .rope_parameters ["rope_type" ]
790801 self .max_seq_len_cached = config .max_position_embeddings
791802 self .original_max_seq_len = config .max_position_embeddings
792803
793804 self .config = config
794- self .rope_init_fn = ROPE_INIT_FUNCTIONS [self .rope_type ]
805+ self .rope_init_fn = (
806+ self .compute_default_rope_parameters
807+ if self .rope_type == "default"
808+ else ROPE_INIT_FUNCTIONS [self .rope_type ]
809+ )
795810
796811 inv_freq , self .attention_scaling = self .rope_init_fn (self .config , device )
797812 self .register_buffer ("inv_freq" , inv_freq , persistent = False )
798813 self .original_inv_freq = self .inv_freq
799814
800- self .mrope_section = config .rope_scaling .get ("mrope_section" , [24 , 20 , 20 ])
815+ self .mrope_section = config .rope_parameters .get ("mrope_section" , [24 , 20 , 20 ])
816+
817+ @staticmethod
818+ def compute_default_rope_parameters (
819+ config : Qwen3ASRTextConfig ,
820+ device : torch .device | None = None ,
821+ seq_len : int | None = None ,
822+ ) -> tuple [torch .Tensor , float ]:
823+ """Return unscaled rotary frequencies for initialization and checkpoint loading."""
824+ base = config .rope_parameters ["rope_theta" ]
825+ head_dim = config .head_dim
826+ inv_freq = 1.0 / (base ** (torch .arange (0 , head_dim , 2 , dtype = torch .float32 , device = device ) / head_dim ))
827+ return inv_freq , 1.0
801828
802829 def apply_interleaved_mrope (self , freqs , mrope_section ):
803830 """Apply interleaved MRoPE to 3D rotary embeddings.
@@ -967,7 +994,7 @@ class Qwen3ASRThinkerTextModel(Qwen3ASRPreTrainedModel):
967994
968995 def __init__ (self , config : Qwen3ASRConfig ):
969996 super ().__init__ (config )
970- self .padding_idx = config . pad_token_id
997+ self .padding_idx = getattr ( config , " pad_token_id" , None )
971998 self .vocab_size = config .vocab_size
972999
9731000 self .embed_tokens = nn .Embedding (config .vocab_size , config .hidden_size , self .padding_idx )
@@ -1027,9 +1054,8 @@ def forward(
10271054
10281055 attention_mask = create_causal_mask (
10291056 config = self .config ,
1030- input_embeds = inputs_embeds ,
1057+ inputs_embeds = inputs_embeds ,
10311058 attention_mask = attention_mask ,
1032- cache_position = cache_position ,
10331059 past_key_values = past_key_values ,
10341060 position_ids = text_position_ids ,
10351061 )
@@ -1070,7 +1096,7 @@ class Qwen3ASRThinkerForConditionalGeneration(Qwen3ASRPreTrainedModelForConditio
10701096
10711097 config : Qwen3ASRThinkerConfig
10721098 base_model_prefix = "thinker"
1073- _tied_weights_keys = [ "model.embed_tokens. weight", "lm_head. weight"]
1099+ _tied_weights_keys = { "lm_head. weight": "model.embed_tokens. weight"}
10741100 _no_split_modules = [
10751101 "Qwen3ASRAudioEncoderLayer" ,
10761102 "Qwen3ASRThinkerTextDecoderLayer" ,
@@ -1081,6 +1107,8 @@ class Qwen3ASRThinkerForConditionalGeneration(Qwen3ASRPreTrainedModelForConditio
10811107 }
10821108
10831109 def __init__ (self , config ):
1110+ # Transformers checks the owning model's config; Bridge uses the nested text setting.
1111+ config .tie_word_embeddings = config .text_config .tie_word_embeddings
10841112 super ().__init__ (config )
10851113 self .audio_tower = Qwen3ASRAudioEncoder ._from_config (config .audio_config )
10861114 self .vocab_size = config .text_config .vocab_size
@@ -1089,7 +1117,8 @@ def __init__(self, config):
10891117 self .lm_head = nn .Linear (config .text_config .hidden_size , config .classify_num , bias = False )
10901118 else :
10911119 self .lm_head = nn .Linear (config .text_config .hidden_size , config .text_config .vocab_size , bias = False )
1092- self .pad_token_id = self .config .pad_token_id if self .config .pad_token_id is not None else - 1
1120+ pad_token_id = getattr (config , "pad_token_id" , None )
1121+ self .pad_token_id = pad_token_id if pad_token_id is not None else - 1
10931122 self .rope_deltas = None
10941123 self .post_init ()
10951124
@@ -1212,25 +1241,18 @@ def forward(
12121241 else :
12131242 audio_feature_lengths = None
12141243
1215- if attention_mask is not None and position_ids is None :
1216- if (
1217- cache_position is None
1218- or (cache_position is not None and cache_position [0 ] == 0 )
1219- or self .rope_deltas is None
1220- ):
1221- delta0 = (1 - attention_mask ).sum (dim = - 1 ).unsqueeze (1 )
1222- position_ids , rope_deltas = self .get_rope_index (
1223- attention_mask ,
1224- )
1225- rope_deltas = rope_deltas - delta0
1226- self .rope_deltas = rope_deltas
1227- else :
1228- batch_size , seq_length = input_ids .shape
1229- delta = cache_position [0 ] + self .rope_deltas if cache_position is not None else 0
1230- position_ids = torch .arange (seq_length , device = input_ids .device )
1231- position_ids = position_ids .view (1 , - 1 ).expand (batch_size , - 1 )
1232- position_ids = position_ids .add (delta )
1233- position_ids = position_ids .unsqueeze (0 ).expand (3 , - 1 , - 1 )
1244+ # Transformers 5 generation tracks the cache length instead of passing cache_position.
1245+ if cache_position is None :
1246+ past_seen_tokens = past_key_values .get_seq_length () if past_key_values is not None else 0
1247+ cache_position = torch .arange (
1248+ past_seen_tokens , past_seen_tokens + inputs_embeds .shape [1 ], device = inputs_embeds .device
1249+ )
1250+
1251+ if attention_mask is not None and attention_mask .ndim == 2 and position_ids is None :
1252+ # Derive positions from this request, including padding, rather than mutable model state.
1253+ position_ids , rope_deltas = self .get_rope_index (attention_mask )
1254+ self .rope_deltas = rope_deltas - (1 - attention_mask ).sum (dim = - 1 ).unsqueeze (1 )
1255+ position_ids = position_ids [..., - inputs_embeds .shape [1 ] :]
12341256
12351257 outputs = self .model (
12361258 attention_mask = attention_mask ,
@@ -1260,39 +1282,6 @@ def forward(
12601282 rope_deltas = self .rope_deltas ,
12611283 )
12621284
1263- def prepare_inputs_for_generation (
1264- self ,
1265- input_ids ,
1266- past_key_values = None ,
1267- attention_mask = None ,
1268- inputs_embeds = None ,
1269- cache_position = None ,
1270- position_ids = None ,
1271- use_cache = True ,
1272- input_features = None ,
1273- feature_attention_mask = None ,
1274- ** kwargs ,
1275- ):
1276- model_inputs = super ().prepare_inputs_for_generation (
1277- input_ids ,
1278- past_key_values = past_key_values ,
1279- attention_mask = attention_mask ,
1280- inputs_embeds = inputs_embeds ,
1281- cache_position = cache_position ,
1282- position_ids = position_ids ,
1283- use_cache = use_cache ,
1284- input_features = input_features ,
1285- feature_attention_mask = feature_attention_mask ,
1286- ** kwargs ,
1287- )
1288-
1289- model_inputs ["position_ids" ] = None
1290-
1291- if cache_position [0 ] != 0 :
1292- model_inputs ["input_features" ] = None
1293-
1294- return model_inputs
1295-
12961285
12971286@auto_docstring
12981287class Qwen3ASRThinkerTextPreTrainedModel (PreTrainedModel ):
0 commit comments