use std::collections::BTreeMap;
use crate::error::{Error, Result};
use crate::nn::Param;
use crate::tensor::Tensor;
#[derive(Default)]
pub struct OptimizerState {
pub tensors: BTreeMap<String, Tensor>,
pub steps: u64,
}
impl OptimizerState {
pub fn new(steps: u64) -> OptimizerState {
OptimizerState {
tensors: BTreeMap::new(),
steps,
}
}
pub fn put(&mut self, slot: &str, series: &[Option<Tensor>]) {
for (index, value) in series.iter().enumerate() {
if let Some(tensor) = value {
self.tensors
.insert(format!("{slot}/{index}"), tensor.detach().cpu());
}
}
}
pub fn take(&self, slot: &str, len: usize) -> Result<Vec<Option<Tensor>>> {
let prefix = format!("{slot}/");
if let Some(name) = self.tensors.keys().find(|k| {
k.strip_prefix(&prefix)
.and_then(|i| i.parse::<usize>().ok())
.is_some_and(|i| i >= len)
}) {
return Err(Error::Checkpoint(format!(
"optimizer state holds '{name}' but this optimizer has only {len} parameters"
)));
}
Ok((0..len)
.map(|i| self.tensors.get(&format!("{prefix}{i}")).cloned())
.collect())
}
}
pub fn place(series: Vec<Option<Tensor>>, params: &[Param]) -> Vec<Option<Tensor>> {
series
.into_iter()
.zip(params)
.map(|(value, param)| value.map(|t| t.to(param.device())))
.collect()
}