acyclib 0.3.0

ML library for directed acyclic tensor graphs.
Documentation
use std::{collections::HashMap, sync::Arc};

use crate::device::{Device, OperationError, tensor::DenseMatrix};

use super::{OptimiserState, utils::Placement};

#[derive(Clone, Debug)]
pub struct WeightClippingParams<T> {
    pub inner: T,
    pub placement: Placement,
    pub min: f32,
    pub max: f32,
}

impl<T: Default> Default for WeightClippingParams<T> {
    fn default() -> Self {
        Self { inner: T::default(), placement: Placement::Before, min: -1.98, max: 1.98 }
    }
}

pub struct WeightClipping<S> {
    inner: S,
    placement: Placement,
    min: f32,
    max: f32,
}

impl<D: Device, S: OptimiserState<D>> OptimiserState<D> for WeightClipping<S> {
    type Params = WeightClippingParams<S::Params>;

    fn new(device: Arc<D>, size: usize, params: Self::Params) -> Result<Self, D::DeviceError> {
        Ok(Self {
            inner: S::new(device, size, params.inner.clone())?,
            placement: params.placement,
            min: params.min,
            max: params.max,
        })
    }

    fn update(
        &mut self,
        weights: &mut DenseMatrix<D>,
        grads: &mut DenseMatrix<D>,
        gradient_factor: f32,
        learning_rate: f32,
    ) -> Result<(), OperationError<D::DeviceError>> {
        if self.placement == Placement::Before {
            weights.clamp(self.min, self.max)?;
        }

        self.inner.update(weights, grads, gradient_factor, learning_rate)?;

        if self.placement == Placement::After {
            weights.clamp(self.min, self.max)?;
        }

        Ok(())
    }

    fn reset(&mut self) -> Result<(), D::DeviceError> {
        self.inner.reset()
    }

    fn set_params(&mut self, params: Self::Params) {
        self.inner.set_params(params.inner);
        self.min = params.min;
        self.max = params.max;
    }

    fn load_from_checkpoint(
        map: &mut HashMap<String, &mut Self>,
        path: &str,
        old_format: bool,
    ) -> Result<(), OperationError<D::DeviceError>> {
        let mut map = map.iter_mut().map(|(id, single)| (id.clone(), &mut single.inner)).collect();
        S::load_from_checkpoint(&mut map, path, old_format)
    }

    fn write_to_checkpoint(map: &HashMap<String, &Self>, path: &str) -> Result<(), D::DeviceError> {
        let map = map.iter().map(|(id, single)| (id.clone(), &single.inner)).collect();
        S::write_to_checkpoint(&map, path)
    }
}