use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Neg, Sub};
use super::{Elementary, Shape, Tensor};
pub trait Recordable:
Clone
+ Debug
+ Send
+ Sync
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Div<Output = Self>
+ Neg<Output = Self>
{
fn shape(&self) -> Shape;
fn zero_like(&self) -> Self;
fn one_like(&self) -> Self;
fn exp(&self) -> Self;
fn ln(&self) -> Self;
fn sqrt(&self) -> Self;
fn tanh(&self) -> Self;
fn sin(&self) -> Self;
fn cos(&self) -> Self;
fn log1p(&self) -> Self;
fn expm1(&self) -> Self;
fn erf(&self) -> Self;
fn erf_derivative(&self) -> Self;
fn powf(&self, exponent: Self) -> Self;
fn maximum(&self, other: &Self) -> Self;
fn step(&self, threshold: &Self) -> Self;
fn matmul(&self, rhs: &Self) -> Self;
fn sum(&self) -> Self;
fn sum_along(&self, axis: usize) -> Self;
fn logsumexp(&self, axis: usize) -> Self;
fn log_softmax(&self, axis: usize) -> Self;
fn broadcast(&self, shape: Shape) -> Self;
fn broadcast_along(&self, axis: usize, extent: usize) -> Self;
fn reshape(&self, shape: Shape) -> Self;
fn permute(&self, order: &[usize]) -> Self;
fn narrow(&self, axis: usize, start: usize, len: usize) -> Self;
fn pad(&self, axis: usize, start: usize, full_extent: usize) -> Self;
fn unfold(&self, axis: usize, size: usize, step: usize, dilation: usize) -> Self;
fn fold(&self, axis: usize, size: usize, step: usize, dilation: usize, extent: usize) -> Self;
fn gather(&self, selection: &Self) -> Self;
fn scatter(&self, selection: &Self) -> Self;
}
pub fn composed_windowed_patches<Element: Elementary>(
input: &Tensor<Element>,
kernel_height: usize,
kernel_width: usize,
stride: usize,
padding: usize,
) -> Tensor<Element> {
let shape = input.shape();
let axes = shape.axes();
let (batch, channels, height, width) = (axes[0], axes[1], axes[2], axes[3]);
let mut padded = input.clone();
if padding > 0 {
padded = padded.pad(2, padding, height + 2 * padding);
padded = padded.pad(3, padding, width + 2 * padding);
}
let windows = padded
.unfold(2, kernel_height, stride, 1)
.unfold(4, kernel_width, stride, 1);
let windows_shape = windows.shape();
let out_height = windows_shape.axes()[2];
let out_width = windows_shape.axes()[4];
windows.permute(&[0, 2, 4, 1, 3, 5]).reshape(Shape::new([
batch * out_height * out_width,
channels * kernel_height * kernel_width,
]))
}
pub fn composed_batch_norm<Element: Elementary>(
input: &Tensor<Element>,
scale: &Tensor<Element>,
shift: &Tensor<Element>,
epsilon: &Tensor<Element>,
) -> (Tensor<Element>, Tensor<Element>, Tensor<Element>) {
let shape = input.shape();
let batch = shape.axes()[0];
let reduced = shape.without_axis(0);
let mean = input.sum_along(0) / Tensor::counted(reduced.clone(), batch);
let centered = input.clone() - mean.broadcast_along_like(0, input);
let variance =
(centered.clone() * centered.clone()).sum_along(0) / Tensor::counted(reduced, batch);
let deviation = (variance.clone() + epsilon.broadcast_like(&variance)).sqrt();
let normalized = centered.clone() / deviation.broadcast_along_like(0, ¢ered);
let output = normalized * scale.broadcast_along_like(0, ¢ered)
+ shift.broadcast_along_like(0, ¢ered);
(output, mean, variance)
}
pub fn composed_max_pool<Element: Elementary>(
input: &Tensor<Element>,
size: usize,
stride: usize,
) -> Tensor<Element> {
let shape = input.shape();
let axes = shape.axes();
let (batch, channels, height, width) = (axes[0], axes[1], axes[2], axes[3]);
let out_height = (height - size) / stride + 1;
let out_width = (width - size) / stride + 1;
let lanes = input
.unfold(2, size, stride, 1)
.unfold(4, size, stride, 1)
.permute(&[0, 1, 2, 4, 3, 5])
.reshape(Shape::new([
batch,
channels,
out_height,
out_width,
size * size,
]));
let mut largest = lanes.narrow(4, 0, 1);
for lane in 1..size * size {
largest = largest.maximum(&lanes.narrow(4, lane, 1));
}
largest.reshape(Shape::new([batch, channels, out_height, out_width]))
}