metrale_model_arch/mistral_loader/loader_impl/
mod.rs1use anyhow::{Context, Result};
20use metrale_cache::kv_cache::KvCacheDtype;
21use metrale_config::ModelConfig;
22use metrale_gpu_runtime::gpu::GpuBackend;
23use metrale_model_weights::weights::WeightStore;
24
25use super::MistralWeightLoader;
26use crate::weight_loader::ModelWeightLoader;
27use metrale_model_layers::layer::TransformerLayer;
28use metrale_model_layers::layers::VisionTower;
29use metrale_model_layers::weight_map::{DenseWeight, MtpWeights, dense};
30
31pub(crate) mod ctx;
35mod phase_assemble;
36pub(crate) mod phase_block_diag;
37mod phase_lora_qkv;
38mod phase_o_proj;
39pub(crate) mod phase_per_head;
40pub(crate) mod phase_qk_absorbed;
41mod yarn;
42
43impl ModelWeightLoader for MistralWeightLoader {
44 fn supports_tp(&self) -> bool {
45 true
51 }
52
53 fn load_layers(
54 &self,
55 store: &WeightStore,
56 config: &ModelConfig,
57 gpu: &dyn GpuBackend,
58 layer_kv_dtypes: &[KvCacheDtype],
59 ) -> Result<Vec<Box<dyn TransformerLayer>>> {
60 self.load_layers_inner(store, config, gpu, layer_kv_dtypes)
61 }
62
63 fn load_embedding(
64 &self,
65 store: &WeightStore,
66 _config: &ModelConfig,
67 _gpu: &dyn GpuBackend,
68 ) -> Result<DenseWeight> {
69 dense(store, "tok_embeddings.weight")
70 .or_else(|_| dense(store, "model.embed_tokens.weight"))
71 .context("Mistral: embedding not found")
72 }
73
74 fn load_final_norm(
75 &self,
76 store: &WeightStore,
77 _config: &ModelConfig,
78 _gpu: &dyn GpuBackend,
79 ) -> Result<DenseWeight> {
80 dense(store, "norm.weight")
81 .or_else(|_| dense(store, "model.norm.weight"))
82 .context("Mistral: final norm not found")
83 }
84
85 fn load_lm_head(
86 &self,
87 store: &WeightStore,
88 config: &ModelConfig,
89 _gpu: &dyn GpuBackend,
90 ) -> Result<DenseWeight> {
91 if store.contains("output.weight") {
92 dense(store, "output.weight")
93 } else if store.contains("lm_head.weight") {
94 dense(store, "lm_head.weight")
95 } else if config.tie_word_embeddings {
96 dense(store, "tok_embeddings.weight")
97 .or_else(|_| dense(store, "model.embed_tokens.weight"))
98 .context("Mistral: tied embedding lm_head not found")
99 } else {
100 anyhow::bail!("Mistral: lm_head/output weight not found")
101 }
102 }
103
104 fn load_mtp_weights(
105 &self,
106 _store: &WeightStore,
107 _config: &ModelConfig,
108 _gpu: &dyn GpuBackend,
109 ) -> Result<Option<MtpWeights>> {
110 Ok(None)
111 }
112
113 fn load_vision_encoder(
114 &self,
115 _store: &WeightStore,
116 _config: &ModelConfig,
117 _gpu: &dyn GpuBackend,
118 ) -> Result<Option<VisionTower>> {
119 Ok(None)
120 }
121}
122
123impl MistralWeightLoader {
124 pub(crate) fn load_layers_inner(
125 &self,
126 store: &WeightStore,
127 config: &ModelConfig,
128 gpu: &dyn GpuBackend,
129 layer_kv_dtypes: &[KvCacheDtype],
130 ) -> Result<Vec<Box<dyn TransformerLayer>>> {
131 let n = config.num_hidden_layers;
132 let q_lora = config.q_lora_rank;
133 let kv_lora = config.kv_lora_rank;
134 let nope = config.qk_nope_head_dim;
135 let rope = config.qk_rope_head_dim;
136 let v_dim = config.v_head_dim;
137
138 tracing::info!(
139 "Mistral MLA→GQA: expanding LoRA on GPU (q_lora={q_lora}, kv_lora={kv_lora}, \
140 nope={nope}, rope={rope}, v_dim={v_dim})"
141 );
142
143 let absmax_k = gpu.kernel("quantize_nvfp4", "nvfp4_global_absmax")?;
144 let quantize_k = gpu.kernel("quantize_nvfp4", "quantize_bf16_to_nvfp4")?;
145 let stream = gpu.default_stream();
146
147 let mut layers: Vec<Box<dyn TransformerLayer>> = Vec::with_capacity(n);
148 let mut yarn_inv_freq_shared = metrale_gpu_runtime::gpu::DevicePtr::NULL;
149
150 for i in 0..n {
151 let mut ctx =
152 ctx::MistralLayerCtx::new(store, config, gpu, absmax_k, quantize_k, stream, i);
153 phase_lora_qkv::load_lora_qkv(&mut ctx)?;
154 phase_per_head::build_per_head_views(&mut ctx)?;
155 phase_qk_absorbed::build_w_qk_absorbed(&mut ctx)?;
156 phase_block_diag::build_block_diagonals(&mut ctx)?;
157 phase_o_proj::load_o_proj(&mut ctx)?;
158 let yarn_inv_freq =
159 ctx::ensure_yarn_inv_freq(&mut yarn_inv_freq_shared, config, rope, gpu)?;
160 let layer = phase_assemble::assemble_layer(ctx, yarn_inv_freq, layer_kv_dtypes)?;
161 layers.push(layer);
162
163 if (i + 1) % 6 == 0 || i == n - 1 {
164 let free = gpu.free_memory().unwrap_or(0);
165 tracing::info!("L{}/{n} done — {:.1} GB free", i + 1, free as f64 / 1e9);
166 }
167 }
168 Ok(layers)
169 }
170}