use crate::models::llama_family::LlamaFamilyConfig;
#[derive(Debug, Clone, PartialEq)]
pub struct Qwen3MoeConfig {
pub base: LlamaFamilyConfig,
pub num_experts: usize,
pub num_experts_per_tok: usize,
pub expert_intermediate_size: usize,
pub norm_topk_prob: bool,
}
impl Qwen3MoeConfig {
pub fn from_base(
base: LlamaFamilyConfig,
num_experts: usize,
num_experts_per_tok: usize,
expert_intermediate_size: usize,
norm_topk_prob: bool,
) -> Self {
Self {
base,
num_experts,
num_experts_per_tok,
expert_intermediate_size,
norm_topk_prob,
}
}
pub fn is_truly_sparse(&self) -> bool {
self.num_experts_per_tok > 0 && self.num_experts_per_tok < self.num_experts
}
pub fn from_def(def: &crate::definition::ModelDefinition) -> ferrum_types::Result<Self> {
let mut base = crate::models::llama_family::LlamaFamilyConfig::qwen3_from_def(def);
let extra = &def.extra_params;
let num_experts = extra
.get("num_experts")
.and_then(|v| v.as_u64())
.ok_or_else(|| {
ferrum_types::FerrumError::model("qwen3_moe config.json missing num_experts")
})? as usize;
let num_experts_per_tok = extra
.get("num_experts_per_tok")
.and_then(|v| v.as_u64())
.unwrap_or(8) as usize;
let expert_intermediate_size = extra
.get("moe_intermediate_size")
.and_then(|v| v.as_u64())
.ok_or_else(|| {
ferrum_types::FerrumError::model(
"qwen3_moe config.json missing moe_intermediate_size",
)
})? as usize;
let norm_topk_prob = extra
.get("norm_topk_prob")
.and_then(|v| v.as_bool())
.unwrap_or(true);
base.intermediate_size = expert_intermediate_size;
Ok(Self {
base,
num_experts,
num_experts_per_tok,
expert_intermediate_size,
norm_topk_prob,
})
}
}