metrale_model_weights/fast_weights/
load.rs1use super::*;
7
8impl WeightLoader for FastSafetensorsLoader {
9 fn load(
10 &self,
11 model_dir: &Path,
12 gpu: &dyn GpuBackend,
13 oom_reserve_bytes: usize,
14 ) -> Result<WeightStore> {
15 let skip_fn = |name: &str| self.should_skip_tensor(name);
16 let defer_fn =
17 |name: &str, dtype: crate::weights::WeightDtype| self.is_deferred(name, dtype);
18
19 let (shard_files, tensor_to_shard): (Vec<PathBuf>, Option<HashMap<String, String>>) =
21 resolve_shards(model_dir)?;
22
23 let preflight_skip = |name: &str| skip_fn(name) || crate::weights::is_ngram_table(name);
37 {
38 let estimated = estimate_load_bytes(&shard_files, &preflight_skip, &defer_fn)?;
39 let has_fp8 = estimate_has_fp8(&shard_files, &preflight_skip, &defer_fn)?;
40 let mult = self
41 .peak_memory_multiplier
42 .unwrap_or(if has_fp8 { 1.5 } else { 1.3 });
43 let peak = (estimated as f64 * mult) as usize;
44 let free = gpu.free_memory()?;
45 let gib = |b: usize| b as f64 / (1024.0 * 1024.0 * 1024.0);
46 tracing::info!(
47 "Fast-load pre-flight: {:.2} GB on-disk, {:.1}x overhead = {:.2} GB peak, \
48 {:.2} GB free, {:.1} GB reserve (FP8: {})",
49 gib(estimated),
50 mult,
51 gib(peak),
52 gib(free),
53 gib(oom_reserve_bytes),
54 has_fp8,
55 );
56 metrale_telemetry::progress::preflight(gib(estimated), gib(free));
57 if peak + oom_reserve_bytes > free {
58 bail!(
59 "OOM pre-flight: peak {:.2} GB + {:.2} GB reserve exceeds {:.2} GB free. \
60 Use a smaller quantization or add more GPUs for EP.",
61 gib(peak),
62 gib(oom_reserve_bytes),
63 gib(free),
64 );
65 }
66 }
67
68 let mut weights: HashMap<String, WeightTensor> = HashMap::new();
70 let mut deferred: HashMap<String, crate::weights::DeferredTensor> = HashMap::new();
72 let total_shards = shard_files.len();
73 let initial_free = gpu.free_memory()?;
74 let mut offload_logged = false;
75
76 for (i, shard_path) in shard_files.iter().enumerate() {
77 let shard_name = shard_path
80 .file_name()
81 .and_then(|n| n.to_str())
82 .unwrap_or_default();
83 let tensor_filter: Option<Vec<String>> = tensor_to_shard.as_ref().map(|map| {
84 map.iter()
85 .filter(|(_, s)| *s == shard_name)
86 .map(|(t, _)| t.clone())
87 .collect()
88 });
89
90 tracing::info!(
91 "Fast-loading shard {}/{}: {}{}",
92 i + 1,
93 total_shards,
94 shard_name,
95 tensor_filter
96 .as_ref()
97 .map(|v| format!(" ({} tensors)", v.len()))
98 .unwrap_or_default(),
99 );
100 metrale_telemetry::progress::shard_start(i + 1, total_shards, shard_name);
101
102 load_shard_fast(
103 shard_path,
104 tensor_filter.as_deref(),
105 gpu,
106 &skip_fn,
107 &defer_fn,
108 self.try_direct_io,
109 self.direct_io_tensor_cap,
110 self.prefetch_shards,
111 &mut weights,
112 &mut deferred,
113 &mut offload_logged,
114 )?;
115
116 let free_now = gpu.free_memory().unwrap_or(0);
117 let used = initial_free.saturating_sub(free_now);
118 tracing::info!(
119 " Shard {}/{} done — GPU memory: {:.2} GB used, {:.2} GB free",
120 i + 1,
121 total_shards,
122 used as f64 / (1024.0 * 1024.0 * 1024.0),
123 free_now as f64 / (1024.0 * 1024.0 * 1024.0),
124 );
125 metrale_telemetry::progress::shard_done(
126 i + 1,
127 total_shards,
128 used as f64 / (1024.0 * 1024.0 * 1024.0),
129 free_now as f64 / (1024.0 * 1024.0 * 1024.0),
130 );
131 if !offload_logged {
132 check_oom_guard(
133 gpu,
134 oom_reserve_bytes,
135 &format!("fast weight loading (shard {}/{})", i + 1, total_shards),
136 )?;
137 }
138 }
139
140 let no_skip = |_: &str| false;
142 let no_defer = |_: &str, _: crate::weights::WeightDtype| false;
143 let extra = model_dir.join("extra_weights.safetensors");
144 if extra.exists() {
145 tracing::info!("Fast-loading extra_weights.safetensors");
146 let mut extra_offload = false;
147 load_shard_fast(
148 &extra,
149 None,
150 gpu,
151 &no_skip,
152 &no_defer,
153 self.try_direct_io,
154 self.direct_io_tensor_cap,
155 self.prefetch_shards,
156 &mut weights,
157 &mut deferred,
158 &mut extra_offload,
159 )?;
160 }
161
162 tracing::info!("Fast-loaded {} weight tensors", weights.len());
163 let mut store = WeightStore::from_map(weights);
164 for (name, d) in deferred {
165 store.defer(name, d);
166 }
167 Ok(store)
168 }
169}