use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::computation_graph::ComputationGraphStore;
use super::GradientError;
#[derive(Debug, Serialize, Deserialize)]
pub struct GradientCheckpoint {
pub graph: ComputationGraphStore,
pub step: u64,
pub loss_cid: Option<String>,
pub optimizer_state: HashMap<String, Vec<u8>>,
pub timestamp: u64,
}
impl GradientCheckpoint {
pub fn new(graph: ComputationGraphStore, step: u64) -> Self {
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
Self {
graph,
step,
loss_cid: None,
optimizer_state: HashMap::new(),
timestamp,
}
}
pub fn with_loss_cid(mut self, cid: impl Into<String>) -> Self {
self.loss_cid = Some(cid.into());
self
}
pub fn set_optimizer_state(&mut self, param: impl Into<String>, state: Vec<u8>) {
self.optimizer_state.insert(param.into(), state);
}
pub fn save(&self, path: &std::path::Path) -> Result<(), GradientError> {
let bytes = serde_json::to_vec_pretty(self).map_err(|e| {
GradientError::InvalidGradient(format!("Checkpoint save serialization: {e}"))
})?;
let parent = path.parent().unwrap_or_else(|| std::path::Path::new("."));
let tmp_path = parent.join(format!(".ckpt_tmp_{}.json", uuid::Uuid::new_v4()));
std::fs::write(&tmp_path, &bytes)
.map_err(|e| GradientError::InvalidGradient(format!("Checkpoint write: {e}")))?;
std::fs::rename(&tmp_path, path)
.map_err(|e| GradientError::InvalidGradient(format!("Checkpoint rename: {e}")))?;
Ok(())
}
pub fn load(path: &std::path::Path) -> Result<Self, GradientError> {
let bytes = std::fs::read(path)
.map_err(|e| GradientError::InvalidGradient(format!("Checkpoint read: {e}")))?;
serde_json::from_slice(&bytes)
.map_err(|e| GradientError::InvalidGradient(format!("Checkpoint load parse: {e}")))
}
}