metrale_model_arch/weight_loader/
glm5_next_mtp.rs1use anyhow::{Context, Result};
16use metrale_config::ModelConfig;
17use metrale_gpu_runtime::gpu::{DevicePtr, GpuBackend};
18use metrale_model_weights::weights::WeightStore;
19
20use crate::glm5next_dsa::build::build_dsa_weights;
21use crate::glm5next_dsa::layer::{Glm5NextDsaLayer, Glm5NextDsaLayerKernels, Glm5NextDsaWorkspace};
22use crate::glm5next_dsa::{Glm5NextDsaConfig, Glm5NextDsaKernels};
23use crate::glm5next_layer::{Glm5NextLayer, Glm5NextMixer, Glm5NextMlpSite};
24use crate::glm5next_mlp::{Glm5NextMlpConfig, Glm5NextMlpKernels, build as mlp_build};
25use metrale_model_layers::weight_map::DenseWeight;
26
27pub struct Glm5NextMtpModule {
29 pub layer: Glm5NextLayer,
31 pub eh_proj: DenseWeight,
34 pub enorm: DevicePtr,
37 pub hnorm: DevicePtr,
38 pub final_norm: DevicePtr,
40}
41
42pub fn load_glm5next_mtp_module(
48 store: &WeightStore,
49 config: &ModelConfig,
50 gpu: &dyn GpuBackend,
51) -> Result<Option<Glm5NextMtpModule>> {
52 let idx = config.num_hidden_layers;
53 let prefix = format!("model.language_model.layers.{idx}.");
54 if !store.names().any(|n| n.starts_with(&prefix)) {
55 return Ok(None);
56 }
57 let src = super::glm5_next_load::layer_source(gpu, store, idx)
58 .with_context(|| format!("glm5_next MTP: collecting layer {idx}"))?;
59 let load = |n: &str| src.f32(n);
60
61 let dsa_cfg = Glm5NextDsaConfig::from_config(config)?;
62 let mlp_cfg = Glm5NextMlpConfig::from_config(config)?;
63 let dsa_plan = crate::glm5next_dsa::tp::DsaTpPlan::new(
64 config.tp_rank,
65 config.tp_world_size.max(1),
66 &dsa_cfg,
67 )?;
68 let dsa_layer_kernels = Glm5NextDsaLayerKernels::resolve(gpu)?;
69 let dsa_kernels = Glm5NextDsaKernels::resolve(gpu)?;
70 let mlp_kernels = Glm5NextMlpKernels::resolve(gpu)?;
71
72 let mixer = Glm5NextMixer::Dsa(Box::new(Glm5NextDsaLayer {
73 persist_bt: std::env::var("METRALE_GLM_DSA_ALLOC_PER_STEP").as_deref() != Ok("1"),
74 cfg: dsa_cfg,
75 weights: build_dsa_weights(gpu, &dsa_cfg, &dsa_plan, &load)?,
76 kernels: dsa_layer_kernels,
77 select_kernels: dsa_kernels,
78 decode_kernel: crate::glm5next_dsa::attend::Glm5NextDsaDecodeKernel::resolve(gpu)?,
79 workspace: Glm5NextDsaWorkspace::new(gpu, &dsa_cfg, 1)?,
81 layer_idx: idx,
82 attn_layer_idx: 0,
84 rms_eps: config.rms_norm_eps as f32,
85 kv_scale: 1.0,
86 }));
87
88 let expert = |id: usize| super::glm5_next_load::bind_expert_at(gpu, store, idx, id);
89 let mlp = Glm5NextMlpSite::Moe(Box::new(mlp_build::build_moe(
90 gpu,
91 &mlp_cfg,
92 config.tp_rank,
93 config.shared_expert_intermediate_size,
94 &load,
95 &expert,
96 )?));
97
98 let up =
99 |n: &str| -> Result<DevicePtr> { super::glm5_next_load::upload_bf16(gpu, &src.f32(n)?) };
100 Ok(Some(Glm5NextMtpModule {
101 layer: Glm5NextLayer {
102 layer_idx: idx,
103 mixer,
104 mlp,
105 mlp_cfg,
106 mlp_kernels,
107 mlp_ws: std::sync::Arc::new(crate::glm5next_mlp::forward::Glm5NextMlpWorkspace::new(
110 gpu, &mlp_cfg, 1,
111 )?),
112 mhc: None,
115 input_norm: up("input_layernorm.weight")?,
116 post_attn_norm: up("post_attention_layernorm.weight")?,
117 rms_norm_k: gpu.kernel("rms_norm_vanilla", "rms_norm_vanilla")?,
118 add_k: metrale_model_layers::layers::try_kernel(gpu, "bf16_add", "bf16_add_inplace"),
119 rms_eps: config.rms_norm_eps as f32,
120 hidden: config.hidden_size,
121 mixer_all_reduce: dsa_plan.needs_output_all_reduce(),
123 is_first: false,
125 is_last: false,
126 },
127 eh_proj: DenseWeight {
128 weight: store.get(&format!("{prefix}eh_proj.weight"))?.ptr,
129 },
130 enorm: up("enorm.weight")?,
131 hnorm: up("hnorm.weight")?,
132 final_norm: up("shared_head.norm.weight")?,
133 }))
134}