use crate::{reduce_grad, tensor::*};
use super::super::grad::*;
#[derive(Debug)]
pub struct BinaryStepGrad {
lhs: Tensor,
output: Tensor,
}
impl BinaryStepGrad {
pub fn new(lhs: &Tensor, output: &Tensor) -> Self {
BinaryStepGrad {
lhs: lhs.clone(),
output: output.clone(),
}
}
}
impl GradientFunction for BinaryStepGrad {
fn backward(&self) {
if let Some(lhs_grad) = &self.lhs.grad() {
let zeros = Storage::zeros(self.lhs.tensor().shape().to_vec(), Some(self.lhs.device()), None);
lhs_grad.borrow_mut().add_tensor_assign(&zeros);
}
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}
#[derive(Debug)]
pub struct SigmoidGrad {
lhs: Tensor,
output: Tensor,
}
impl SigmoidGrad {
pub fn new(lhs: &Tensor, output: &Tensor) -> Self {
SigmoidGrad {
lhs: lhs.clone(),
output: output.clone(),
}
}
}
impl GradientFunction for SigmoidGrad {
fn backward(&self) {
let out_grad = self.output.grad().unwrap();
let out_grad = out_grad.borrow();
if let Some(lhs_grad) = &self.lhs.grad() {
let sigmoid_op = |x: f32| 1./(1. + f32::exp(-x));
let grad_for_lhs = &*out_grad * &self.lhs.storage.apply(|x| sigmoid_op(x) * (1. - sigmoid_op(x)));
let reduced_grad = reduce_grad!(grad_for_lhs, self.lhs.tensor().shape());
lhs_grad.borrow_mut().add_tensor_assign(&reduced_grad);
}
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}
#[derive(Debug)]
pub struct TanhGrad {
lhs: Tensor,
output: Tensor,
}
impl TanhGrad {
pub fn new(lhs: &Tensor, output: &Tensor) -> Self {
TanhGrad {
lhs: lhs.clone(),
output: output.clone(),
}
}
}
impl GradientFunction for TanhGrad {
fn backward(&self) {
let out_grad = self.output.grad().unwrap();
let out_grad = out_grad.borrow();
if let Some(lhs_grad) = &self.lhs.grad() {
let tanh_op = |x: f32| (f32::exp(x) - f32::exp(-x))/(f32::exp(x) + f32::exp(-x));
let grad_for_lhs = &*out_grad * &self.lhs.storage.apply(|x| 1. - tanh_op(x));
let reduced_grad = reduce_grad!(grad_for_lhs, self.lhs.tensor().shape());
lhs_grad.borrow_mut().add_tensor_assign(&reduced_grad);
}
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}
#[derive(Debug)]
pub struct ReluGrad {
lhs: Tensor,
output: Tensor,
}
impl ReluGrad {
pub fn new(lhs: &Tensor, output: &Tensor) -> Self {
ReluGrad {
lhs: lhs.clone(),
output: output.clone(),
}
}
}
impl GradientFunction for ReluGrad {
fn backward(&self) {
let out_grad = self.output.grad().unwrap();
let out_grad = out_grad.borrow();
if let Some(lhs_grad) = &self.lhs.grad() {
let grad_for_lhs = &*out_grad * &self.lhs.storage.apply(|x| if x <= 0. {0.} else {1.});
let reduced_grad = reduce_grad!(grad_for_lhs, self.lhs.tensor().shape());
lhs_grad.borrow_mut().add_tensor_assign(&reduced_grad);
}
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}
#[derive(Debug)]
pub struct LeakyReluGrad {
lhs: Tensor,
output: Tensor,
}
impl LeakyReluGrad {
pub fn new(lhs: &Tensor, output: &Tensor) -> Self {
LeakyReluGrad {
lhs: lhs.clone(),
output: output.clone(),
}
}
}
impl GradientFunction for LeakyReluGrad {
fn backward(&self) {
let out_grad = self.output.grad().unwrap();
let out_grad = out_grad.borrow();
if let Some(lhs_grad) = &self.lhs.grad() {
let grad_for_lhs = &*out_grad * &self.lhs.storage.apply(|x| if x <= 0. {0.1} else {1.});
let reduced_grad = reduce_grad!(grad_for_lhs, self.lhs.tensor().shape());
lhs_grad.borrow_mut().add_tensor_assign(&reduced_grad);
}
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}
#[derive(Debug)]
pub struct ParametricReluGrad {
lhs: Tensor,
a: f32,
output: Tensor,
}
impl ParametricReluGrad {
pub fn new(lhs: &Tensor, a: f32, output: &Tensor) -> Self {
ParametricReluGrad {
lhs: lhs.clone(),
a: a,
output: output.clone(),
}
}
}
impl GradientFunction for ParametricReluGrad {
fn backward(&self) {
let out_grad = self.output.grad().unwrap();
let out_grad = out_grad.borrow();
if let Some(lhs_grad) = &self.lhs.grad() {
let grad_for_lhs = &*out_grad * &self.lhs.storage.apply(|x| if x <= 0. {self.a} else {1.});
let reduced_grad = reduce_grad!(grad_for_lhs, self.lhs.tensor().shape());
lhs_grad.borrow_mut().add_tensor_assign(&reduced_grad);
}
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}
#[derive(Debug)]
pub struct EluGrad {
lhs: Tensor,
alpha: f32,
output: Tensor,
}
impl EluGrad {
pub fn new(lhs: &Tensor, alpha: f32, output: &Tensor) -> Self {
EluGrad {
lhs: lhs.clone(),
alpha: alpha,
output: output.clone(),
}
}
}
impl GradientFunction for EluGrad {
fn backward(&self) {
let out_grad = self.output.grad().unwrap();
let out_grad = out_grad.borrow();
if let Some(lhs_grad) = &self.lhs.grad() {
let grad_for_lhs = &*out_grad * &self.lhs.storage.apply(|x| if x <= 0. {self.alpha * f32::exp(x)} else {1.});
let reduced_grad = reduce_grad!(grad_for_lhs, self.lhs.tensor().shape());
lhs_grad.borrow_mut().add_tensor_assign(&reduced_grad);
}
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}
#[derive(Debug)]
pub struct SoftmaxGrad {
lhs: Tensor,
output: Tensor,
}
impl SoftmaxGrad {
pub fn new(lhs: &Tensor, output: &Tensor) -> Self {
SoftmaxGrad {
lhs: lhs.clone(),
output: output.clone(),
}
}
}
impl GradientFunction for SoftmaxGrad {
fn backward(&self) {
let out_grad = self.output.grad().unwrap();
let out_grad = out_grad.borrow();
if let Some(lhs_grad) = &self.lhs.grad() {
let s = self.output.tensor();
let grad_times_s = &*out_grad * s;
let axis = s.shape().len() - 1;
let sum_along_axis = grad_times_s.sum_axis(axis);
let grad_for_lhs = s * &(&*out_grad - &sum_along_axis);
let reduced_grad = reduce_grad!(grad_for_lhs, self.lhs.tensor().shape());
lhs_grad.borrow_mut().add_tensor_assign(&reduced_grad);
}
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}
#[derive(Debug)]
pub struct SwishGrad {
lhs: Tensor,
output: Tensor,
}
impl SwishGrad {
pub fn new(lhs: &Tensor, output: &Tensor) -> Self {
SwishGrad {
lhs: lhs.clone(),
output: output.clone(),
}
}
}
impl GradientFunction for SwishGrad {
fn backward(&self) {
unimplemented!()
}
fn prev(&self) -> Vec<&Tensor> {
vec![&self.lhs]
}
}