ipfrs_tensorlogic/gradient/
checkpoint.rs1use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10use super::computation_graph::ComputationGraphStore;
11use super::GradientError;
12
13#[derive(Debug, Serialize, Deserialize)]
19pub struct GradientCheckpoint {
20 pub graph: ComputationGraphStore,
22 pub step: u64,
24 pub loss_cid: Option<String>,
26 pub optimizer_state: HashMap<String, Vec<u8>>,
28 pub timestamp: u64,
30}
31
32impl GradientCheckpoint {
33 pub fn new(graph: ComputationGraphStore, step: u64) -> Self {
35 let timestamp = std::time::SystemTime::now()
36 .duration_since(std::time::UNIX_EPOCH)
37 .map(|d| d.as_secs())
38 .unwrap_or(0);
39
40 Self {
41 graph,
42 step,
43 loss_cid: None,
44 optimizer_state: HashMap::new(),
45 timestamp,
46 }
47 }
48
49 pub fn with_loss_cid(mut self, cid: impl Into<String>) -> Self {
51 self.loss_cid = Some(cid.into());
52 self
53 }
54
55 pub fn set_optimizer_state(&mut self, param: impl Into<String>, state: Vec<u8>) {
57 self.optimizer_state.insert(param.into(), state);
58 }
59
60 pub fn save(&self, path: &std::path::Path) -> Result<(), GradientError> {
65 let bytes = serde_json::to_vec_pretty(self).map_err(|e| {
66 GradientError::InvalidGradient(format!("Checkpoint save serialization: {e}"))
67 })?;
68
69 let parent = path.parent().unwrap_or_else(|| std::path::Path::new("."));
71 let tmp_path = parent.join(format!(".ckpt_tmp_{}.json", uuid::Uuid::new_v4()));
72
73 std::fs::write(&tmp_path, &bytes)
74 .map_err(|e| GradientError::InvalidGradient(format!("Checkpoint write: {e}")))?;
75
76 std::fs::rename(&tmp_path, path)
77 .map_err(|e| GradientError::InvalidGradient(format!("Checkpoint rename: {e}")))?;
78
79 Ok(())
80 }
81
82 pub fn load(path: &std::path::Path) -> Result<Self, GradientError> {
84 let bytes = std::fs::read(path)
85 .map_err(|e| GradientError::InvalidGradient(format!("Checkpoint read: {e}")))?;
86
87 serde_json::from_slice(&bytes)
88 .map_err(|e| GradientError::InvalidGradient(format!("Checkpoint load parse: {e}")))
89 }
90}