@@ -1144,6 +1144,18 @@ void llama_model::load_hparams(llama_model_loader & ml) {
11441144 default : type = LLM_TYPE_UNKNOWN ;
11451145 }
11461146 } break ;
1147+ case LLM_ARCH_QWEN3OMNIMOE :
1148+ {
1149+ // Qwen3-Omni Thinker: Qwen3MOE with M-RoPE and shared experts
1150+ ml.get_key_or_arr (LLM_KV_ROPE_DIMENSION_SECTIONS , hparams.rope_sections , 4 , true );
1151+ ml.get_key (LLM_KV_EXPERT_FEED_FORWARD_LENGTH , hparams.n_ff_exp , false );
1152+ ml.get_key (LLM_KV_EXPERT_SHARED_FEED_FORWARD_LENGTH , hparams.n_ff_shexp , false );
1153+ ml.get_key (LLM_KV_ATTENTION_LAYERNORM_RMS_EPS , hparams.f_norm_rms_eps );
1154+ switch (hparams.n_layer ) {
1155+ case 48 : type = LLM_TYPE_30B ; break ;
1156+ default : type = LLM_TYPE_UNKNOWN ;
1157+ }
1158+ } break ;
11471159 case LLM_ARCH_PHI2 :
11481160 {
11491161 ml.get_key (LLM_KV_ATTENTION_LAYERNORM_EPS , hparams.f_norm_eps );
@@ -3622,6 +3634,55 @@ bool llama_model::load_tensors(llama_model_loader & ml) {
36223634 layer.ffn_up_exps = create_tensor (tn (LLM_TENSOR_FFN_UP_EXPS , " weight" , i), { n_embd, n_ff_exp, n_expert}, 0 );
36233635 }
36243636 } break ;
3637+ case LLM_ARCH_QWEN3OMNIMOE :
3638+ {
3639+ // Qwen3-Omni Thinker: Qwen3MOE with M-RoPE and shared experts
3640+ tok_embd = create_tensor (tn (LLM_TENSOR_TOKEN_EMBD , " weight" ), {n_embd, n_vocab}, 0 );
3641+
3642+ output_norm = create_tensor (tn (LLM_TENSOR_OUTPUT_NORM , " weight" ), {n_embd}, 0 );
3643+ output = create_tensor (tn (LLM_TENSOR_OUTPUT , " weight" ), {n_embd, n_vocab}, TENSOR_NOT_REQUIRED );
3644+ if (output == NULL ) {
3645+ output = create_tensor (tn (LLM_TENSOR_TOKEN_EMBD , " weight" ), {n_embd, n_vocab}, TENSOR_DUPLICATED );
3646+ }
3647+
3648+ for (int i = 0 ; i < n_layer; ++i) {
3649+ auto & layer = layers[i];
3650+
3651+ layer.attn_norm = create_tensor (tn (LLM_TENSOR_ATTN_NORM , " weight" , i), {n_embd}, 0 );
3652+
3653+ layer.wq = create_tensor (tn (LLM_TENSOR_ATTN_Q , " weight" , i), {n_embd, n_embd_head_k * n_head}, 0 );
3654+ layer.wk = create_tensor (tn (LLM_TENSOR_ATTN_K , " weight" , i), {n_embd, n_embd_gqa}, 0 );
3655+ layer.wv = create_tensor (tn (LLM_TENSOR_ATTN_V , " weight" , i), {n_embd, n_embd_gqa}, 0 );
3656+ layer.wo = create_tensor (tn (LLM_TENSOR_ATTN_OUT , " weight" , i), {n_embd_head_k * n_head, n_embd}, 0 );
3657+
3658+ layer.attn_k_norm = create_tensor (tn (LLM_TENSOR_ATTN_K_NORM , " weight" , i), {n_embd_head_k}, 0 );
3659+ layer.attn_q_norm = create_tensor (tn (LLM_TENSOR_ATTN_Q_NORM , " weight" , i), {n_embd_head_k}, 0 );
3660+
3661+ layer.ffn_norm = create_tensor (tn (LLM_TENSOR_FFN_NORM , " weight" , i), {n_embd}, 0 );
3662+
3663+ layer.ffn_gate_inp = create_tensor (tn (LLM_TENSOR_FFN_GATE_INP , " weight" , i), {n_embd, n_expert}, 0 );
3664+
3665+ if (n_expert == 0 ) {
3666+ throw std::runtime_error (" n_expert must be > 0 for QWEN3OMNIMOE" );
3667+ }
3668+ if (n_expert_used == 0 ) {
3669+ throw std::runtime_error (" n_expert_used must be > 0 for QWEN3OMNIMOE" );
3670+ }
3671+
3672+ // MoE experts
3673+ const int64_t n_ff_exp = hparams.n_ff_exp ? hparams.n_ff_exp : n_ff / n_expert_used;
3674+ layer.ffn_gate_exps = create_tensor (tn (LLM_TENSOR_FFN_GATE_EXPS , " weight" , i), { n_embd, n_ff_exp, n_expert}, 0 );
3675+ layer.ffn_down_exps = create_tensor (tn (LLM_TENSOR_FFN_DOWN_EXPS , " weight" , i), {n_ff_exp, n_embd, n_expert}, 0 );
3676+ layer.ffn_up_exps = create_tensor (tn (LLM_TENSOR_FFN_UP_EXPS , " weight" , i), { n_embd, n_ff_exp, n_expert}, 0 );
3677+
3678+ // Shared expert (optional)
3679+ if (hparams.n_ff_shexp > 0 ) {
3680+ layer.ffn_gate_shexp = create_tensor (tn (LLM_TENSOR_FFN_GATE_SHEXP , " weight" , i), {n_embd, hparams.n_ff_shexp }, 0 );
3681+ layer.ffn_down_shexp = create_tensor (tn (LLM_TENSOR_FFN_DOWN_SHEXP , " weight" , i), {hparams.n_ff_shexp , n_embd}, 0 );
3682+ layer.ffn_up_shexp = create_tensor (tn (LLM_TENSOR_FFN_UP_SHEXP , " weight" , i), {n_embd, hparams.n_ff_shexp }, 0 );
3683+ }
3684+ }
3685+ } break ;
36253686 case LLM_ARCH_PHI2 :
36263687 {
36273688 tok_embd = create_tensor (tn (LLM_TENSOR_TOKEN_EMBD , " weight" ), {n_embd, n_vocab}, 0 );
@@ -7452,6 +7513,11 @@ ggml_cgraph * llama_model::build_graph(const llm_graph_params & params) const {
74527513 {
74537514 llm = std::make_unique<llm_build_qwen3vlmoe>(*this , params);
74547515 } break ;
7516+ case LLM_ARCH_QWEN3OMNIMOE :
7517+ {
7518+ // Reuse Qwen3VLMOE builder - supports M-RoPE and shared experts
7519+ llm = std::make_unique<llm_build_qwen3vlmoe>(*this , params);
7520+ } break ;
74557521 case LLM_ARCH_PHI2 :
74567522 {
74577523 llm = std::make_unique<llm_build_phi2>(*this , params);
@@ -8014,6 +8080,7 @@ llama_rope_type llama_model_rope_type(const llama_model * model) {
80148080 return LLAMA_ROPE_TYPE_MROPE ;
80158081 case LLM_ARCH_QWEN3VL :
80168082 case LLM_ARCH_QWEN3VLMOE :
8083+ case LLM_ARCH_QWEN3OMNIMOE :
80178084 return LLAMA_ROPE_TYPE_IMROPE ;
80188085
80198086 case LLM_ARCH_GLM4 :
0 commit comments