Split a model into per-worker bundles. Each bundle contains a reduced safetensors file with only the worker's assigned tensors, a matching index file, and the worker's topology.
(
model_path: &Path,
topology_path: &str,
worker: Option<&str>,
output: &Path,
)
| 153 | /// Each bundle contains a reduced safetensors file with only the worker's assigned tensors, |
| 154 | /// a matching index file, and the worker's topology. |
| 155 | pub fn split_model( |
| 156 | model_path: &Path, |
| 157 | topology_path: &str, |
| 158 | worker: Option<&str>, |
| 159 | output: &Path, |
| 160 | ) -> Result<()> { |
| 161 | let topology = Topology::from_path(topology_path, &ModelType::TextModel)?; |
| 162 | let index = load_index(model_path)?; |
| 163 | |
| 164 | log::info!("index has {} tensors", index.weight_map.len()); |
| 165 | |
| 166 | let selected_workers: Vec<String> = if let Some(name) = worker { |
| 167 | vec![name.to_string()] |
| 168 | } else { |
| 169 | topology.keys().map(|s| s.to_string()).collect() |
| 170 | }; |
| 171 | |
| 172 | log::info!("processing {} workers", selected_workers.len()); |
| 173 | |
| 174 | for worker_name in &selected_workers { |
| 175 | log::info!("processing worker {worker_name} ..."); |
| 176 | |
| 177 | let worker_node = topology |
| 178 | .get(worker_name) |
| 179 | .ok_or_else(|| anyhow!("can't find worker '{}' in topology", worker_name))?; |
| 180 | |
| 181 | let (new_index, reduced) = reduce_for_worker(&index, worker_node)?; |
| 182 | |
| 183 | log::info!("compacting {} tensors ...", new_index.weight_map.len()); |
| 184 | |
| 185 | let metadata = create_new_metadata(model_path, &reduced)?; |
| 186 | |
| 187 | let bundle_name = format!("{worker_name}-node"); |
| 188 | let output_path = output.join(&bundle_name); |
| 189 | let model_output_path = output_path.join("model"); |
| 190 | if !output_path.exists() { |
| 191 | log::info!("creating {}", model_output_path.display()); |
| 192 | std::fs::create_dir_all(&model_output_path)?; |
| 193 | } else { |
| 194 | log::info!("saving model to {}", model_output_path.display()); |
| 195 | } |
| 196 | |
| 197 | let new_index_path = model_output_path.join("model.safetensors.index.json"); |
| 198 | |
| 199 | log::info!("saving new index to {} ...", new_index_path.display()); |
| 200 | |
| 201 | let new_index_data = serde_json::to_string_pretty(&new_index)?; |
| 202 | std::fs::write(&new_index_path, new_index_data)?; |
| 203 | |
| 204 | let new_tensors_path = model_output_path.join("reduced.safetensors"); |
| 205 | |
| 206 | log::info!( |
| 207 | "saving reduced tensors to {} ...", |
| 208 | new_tensors_path.display() |
| 209 | ); |
| 210 | |
| 211 | safetensors::serialize_to_file(metadata, None, &new_tensors_path)?; |
| 212 |
no test coverage detected