use crate::{Tensor, kind::Autodiff};
#[cfg(feature = "autodiff")]
use crate::ops::BridgeTensor;
#[cfg(feature = "autodiff")]
use burn_backend::AutodiffBackend;
#[cfg(feature = "autodiff")]
use burn_dispatch::Dispatch;
#[cfg(feature = "autodiff")]
type AutodiffGradients = <Dispatch as AutodiffBackend>::Gradients;
#[cfg(feature = "autodiff")]
burn_std::obfuscate!(
type: AutodiffGradients,
module: gradients_opaque,
derives: [Send]
);
#[cfg(feature = "autodiff")]
pub struct Gradients {
blob: gradients_opaque::Opaque,
}
#[cfg(feature = "autodiff")]
impl Gradients {
pub(crate) fn from_inner(inner: AutodiffGradients) -> Self {
Self {
blob: gradients_opaque::Opaque::new(inner),
}
}
pub(crate) fn as_inner(&self) -> &AutodiffGradients {
self.blob.as_ref()
}
pub(crate) fn as_inner_mut(&mut self) -> &mut AutodiffGradients {
self.blob.as_mut()
}
}
#[cfg(feature = "autodiff")]
impl<const D: usize> Tensor<D> {
pub fn backward(&self) -> Gradients {
backward_impl(&self.primitive)
}
pub fn grad(&self, grads: &Gradients) -> Option<Tensor<D>> {
grad_impl(&self.primitive, grads).map(Tensor::new)
}
pub fn grad_remove(&self, grads: &mut Gradients) -> Option<Tensor<D>> {
grad_remove_impl(&self.primitive, grads).map(Tensor::new)
}
pub fn grad_replace(&self, grads: &mut Gradients, grad: Tensor<D>) {
grad_replace_impl(&self.primitive, grads, grad.primitive)
}
}
#[cfg(feature = "autodiff")]
fn backward_impl(p: &BridgeTensor) -> Gradients {
Gradients::from_inner(Dispatch::backward(p.clone().into_float()))
}
#[cfg(feature = "autodiff")]
fn grad_impl(p: &BridgeTensor, grads: &Gradients) -> Option<BridgeTensor> {
Dispatch::grad(p.as_float(), grads.as_inner()).map(BridgeTensor::float)
}
#[cfg(feature = "autodiff")]
fn grad_remove_impl(p: &BridgeTensor, grads: &mut Gradients) -> Option<BridgeTensor> {
Dispatch::grad_remove(p.as_float(), grads.as_inner_mut()).map(BridgeTensor::float)
}
#[cfg(feature = "autodiff")]
fn grad_replace_impl(p: &BridgeTensor, grads: &mut Gradients, grad: BridgeTensor) {
Dispatch::grad_replace(p.as_float(), grads.as_inner_mut(), grad.into_float())
}
impl<const D: usize, K: Autodiff> Tensor<D, K> {
pub fn inner(self) -> Tensor<D, K> {
Tensor::new(K::inner(self.primitive))
}
pub fn from_inner(inner: Tensor<D, K>) -> Self {
Self::new(K::from_inner(inner.primitive))
}
}