use crate::autograd::ops::unary::{
AbsBackward, ClampBackward, ExpBackward, LogBackward, NegBackward, PowBackward, SqrtBackward,
};
use crate::cuda::{ffi, kernels};
use crate::tensor::Tensor;
use crate::tensor::storage::Storage;
use super::{scalar_op, unary_op};
impl Tensor {
pub fn neg(&self) -> Tensor {
unary_op(self, |x| -x, ffi::fastnn_cuda_neg).with_grad(&[self], || NegBackward)
}
pub fn exp(&self) -> Tensor {
let out = unary_op(self, f32::exp, ffi::fastnn_cuda_exp);
let saved = out.clone();
out.with_grad(&[self], || ExpBackward { output: saved })
}
pub fn log(&self) -> Tensor {
unary_op(self, f32::ln, ffi::fastnn_cuda_log).with_grad(&[self], || LogBackward {
input: self.detach(),
})
}
pub fn sqrt(&self) -> Tensor {
let out = unary_op(self, f32::sqrt, ffi::fastnn_cuda_sqrt);
let saved = out.clone();
out.with_grad(&[self], || SqrtBackward { output: saved })
}
pub fn abs(&self) -> Tensor {
unary_op(self, f32::abs, ffi::fastnn_cuda_abs).with_grad(&[self], || AbsBackward {
input: self.detach(),
})
}
pub fn powf(&self, exponent: f32) -> Tensor {
scalar_op(
self,
exponent,
|x, p| x.powf(p),
ffi::fastnn_cuda_pow_scalar,
)
.with_grad(&[self], || PowBackward {
input: self.detach(),
exponent,
})
}
pub fn square(&self) -> Tensor {
self.mul(self)
}
pub fn clamp(&self, lo: f32, hi: f32) -> Tensor {
let out = match self.storage() {
Storage::Cpu(data) => {
Tensor::from_vec(super::map(data, |x| x.clamp(lo, hi)), self.shape())
}
Storage::Cuda(buf) => {
let out = kernels::clamp(buf, lo, hi, self.numel()).expect("cuda clamp");
Tensor::raw(Storage::Cuda(out), self.shape().to_vec(), self.device())
}
};
out.with_grad(&[self], || ClampBackward {
input: self.detach(),
lo,
hi,
})
}
}