use core::fmt::Debug;
use burn_backend::Backend;
use crate::{graph::ComputingProperty, tensor::AutodiffTensor};
use alloc::sync::Arc;
use super::{
builder::{ActionType, CheckpointerBuilder},
retro_forward::RetroForward,
};
pub trait CheckpointStrategy: Clone + Copy + Debug + Default + Send + Sync + 'static {
fn compute_property<R: RetroForward>(retro_forward: R) -> ComputingProperty;
fn checkpoint_parents<'a, B2, A>(
parents: A,
builder: &mut CheckpointerBuilder,
) -> Result<(), CheckpointingError>
where
B2: Backend,
A: IntoIterator<Item = &'a AutodiffTensor<B2>>;
}
#[derive(Debug)]
pub enum CheckpointingError {
UntrackedParent,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct NoCheckpointing {}
impl CheckpointStrategy for NoCheckpointing {
fn compute_property<R: RetroForward>(_retro_forward: R) -> ComputingProperty {
ComputingProperty::ComputeBound
}
fn checkpoint_parents<'a, B2, A>(
_parents: A,
_builder: &mut CheckpointerBuilder,
) -> Result<(), CheckpointingError>
where
B2: Backend,
A: IntoIterator<Item = &'a AutodiffTensor<B2>>,
{
Ok(())
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct BalancedCheckpointing {}
impl CheckpointStrategy for BalancedCheckpointing {
fn compute_property<R: RetroForward>(retro_forward: R) -> ComputingProperty {
ComputingProperty::MemoryBound {
retro_forward: Arc::new(retro_forward),
}
}
fn checkpoint_parents<'a, B2, A>(
parents: A,
builder: &mut CheckpointerBuilder,
) -> Result<(), CheckpointingError>
where
B2: Backend,
A: IntoIterator<Item = &'a AutodiffTensor<B2>>,
{
let mut can_checkpoint = true;
for tensor in parents.into_iter() {
if let crate::graph::Requirement::None = tensor.node.requirement {
can_checkpoint = false;
} else {
builder.checkpoint(tensor, ActionType::Backup);
}
}
if !can_checkpoint {
*builder = CheckpointerBuilder::default();
return Err(CheckpointingError::UntrackedParent);
}
Ok(())
}
}