pub mod activation;
pub mod batchnorm;
pub mod conv;
pub mod linear;
pub mod pooling;
pub mod quantized_conv2d;
pub mod quantized_depthwise;
pub mod quantized_linear;
pub mod quantized_pooling;
pub mod quantized_residual;
pub use activation::{Activation, ActivationType, HardSwish, ReLU, ReLU6, Sigmoid, Swish};
pub use batchnorm::{BatchNorm, BatchNorm2d};
pub use conv::{Conv2d, DepthwiseSeparableConv};
pub use linear::Linear;
pub use pooling::{AvgPool2d, GlobalAvgPool, GlobalAvgPool2d, MaxPool2d};
pub use quantized_conv2d::QuantizedConv2d;
pub use quantized_depthwise::QuantizedDepthwiseConv2d;
pub use quantized_linear::QuantizedLinear;
pub use quantized_pooling::{QuantizedAvgPool2d, QuantizedMaxPool2d};
pub use quantized_residual::QuantizedResidualAdd;
use crate::{CnnResult, Tensor};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TensorShape {
pub n: usize,
pub c: usize,
pub h: usize,
pub w: usize,
}
impl TensorShape {
pub fn new(n: usize, c: usize, h: usize, w: usize) -> Self {
Self { n, c, h, w }
}
pub fn numel(&self) -> usize {
self.n * self.c * self.h * self.w
}
pub fn spatial_size(&self) -> usize {
self.h * self.w
}
pub fn channel_size(&self) -> usize {
self.c * self.h * self.w
}
}
impl std::fmt::Display for TensorShape {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}, {}, {}, {}]", self.n, self.c, self.h, self.w)
}
}
pub fn conv_output_size(input: usize, kernel: usize, stride: usize, padding: usize, dilation: usize) -> usize {
let effective_kernel = dilation * (kernel - 1) + 1;
(input + 2 * padding - effective_kernel) / stride + 1
}
pub trait Layer {
fn forward(&self, input: &Tensor) -> CnnResult<Tensor>;
fn name(&self) -> &'static str;
fn num_params(&self) -> usize {
0
}
}
pub fn conv2d_3x3(
input: &[f32],
weights: &[f32],
in_channels: usize,
out_channels: usize,
height: usize,
width: usize,
) -> Vec<f32> {
let out_h = height; let out_w = width;
let mut output = vec![0.0f32; out_h * out_w * out_channels];
crate::simd::scalar::conv_3x3_scalar(
input,
weights,
&mut output,
height,
width,
in_channels,
out_channels,
1, 1, );
output
}
pub fn batch_norm(
input: &[f32],
gamma: &[f32],
beta: &[f32],
mean: &[f32],
var: &[f32],
epsilon: f32,
) -> Vec<f32> {
let mut output = vec![0.0f32; input.len()];
let channels = gamma.len();
crate::simd::batch_norm_simd(
input,
&mut output,
gamma,
beta,
mean,
var,
epsilon,
channels,
);
output
}
pub fn hard_swish(input: &[f32]) -> Vec<f32> {
let mut output = vec![0.0f32; input.len()];
crate::simd::scalar::hard_swish_scalar(input, &mut output);
output
}
pub fn relu(input: &[f32]) -> Vec<f32> {
let mut output = vec![0.0f32; input.len()];
crate::simd::relu_simd(input, &mut output);
output
}
pub fn relu6(input: &[f32]) -> Vec<f32> {
let mut output = vec![0.0f32; input.len()];
crate::simd::relu6_simd(input, &mut output);
output
}
pub fn global_avg_pool(input: &[f32], channels: usize) -> Vec<f32> {
let spatial_size = input.len() / channels;
let mut output = vec![0.0f32; channels];
for i in 0..input.len() {
let c = i % channels;
output[c] += input[i];
}
let inv_spatial = 1.0 / spatial_size as f32;
for o in output.iter_mut() {
*o *= inv_spatial;
}
output
}
pub use conv::Conv2dBuilder;
impl Activation {
pub fn relu() -> Self {
Self::new(ActivationType::ReLU)
}
pub fn relu6() -> Self {
Self::new(ActivationType::ReLU6)
}
pub fn hard_swish() -> Self {
Self::new(ActivationType::HardSwish)
}
pub fn hard_sigmoid() -> Self {
Self::new(ActivationType::Sigmoid)
}
pub fn identity() -> Self {
Self::new(ActivationType::Identity)
}
}