use burn::{
config::Config,
module::Module,
prelude::{
Backend,
Tensor,
},
};
#[doc(inline)]
pub use crate::ops::drop::DropBlockOptions;
use crate::ops::drop::drop_block_2d;
#[derive(Config, Debug)]
pub struct DropBlock2dConfig {
#[config(default = "DropBlockOptions::default()")]
pub options: DropBlockOptions,
}
impl From<DropBlockOptions> for DropBlock2dConfig {
fn from(options: DropBlockOptions) -> Self {
Self { options }
}
}
impl DropBlock2dConfig {
pub fn init(&self) -> DropBlock2d {
DropBlock2d {
options: self.options.clone(),
}
}
}
#[derive(Module, Clone, Debug)]
pub struct DropBlock2d {
pub options: DropBlockOptions,
}
impl DropBlock2d {
pub fn forward<B: Backend>(
&self,
tensor: Tensor<B, 4>,
) -> Tensor<B, 4> {
if B::ad_enabled(&tensor.device()) {
drop_block_2d(tensor.clone(), &self.options)
} else {
tensor
}
}
}
#[cfg(test)]
mod tests {
use burn::backend::Autodiff;
use super::*;
use crate::support::testing::CpuBackend;
#[test]
fn test_module_inference() {
type B = CpuBackend;
let device = Default::default();
let config = DropBlock2dConfig::new();
let module = config.init();
let batch_size = 2;
let channels = 3;
let height = 100;
let width = height;
let shape = [batch_size, channels, height, width];
let tensor: Tensor<B, 4> = Tensor::ones(shape, &device);
assert_eq!(B::ad_enabled(&tensor.device()), false);
let result = module.forward(tensor.clone());
result.to_data().assert_eq(&tensor.to_data(), false);
}
#[test]
fn test_module_training() {
type I = CpuBackend;
type B = Autodiff<I>;
let device = Default::default();
let drop_prob = 0.1;
let config = DropBlock2dConfig::new().with_options(
DropBlockOptions::default()
.with_drop_prob(drop_prob)
.with_kernel([2, 3]),
);
let module = config.init();
let batch_size = 2;
let channels = 3;
let height = 100;
let width = height;
let shape = [batch_size, channels, height, width];
let tensor: Tensor<B, 4> = Tensor::ones(shape, &device);
assert_eq!(B::ad_enabled(&tensor.device()), true);
let drop = module.forward(tensor.clone());
let numel = drop.shape().num_elements();
let keep_count = drop.clone().greater_elem(1.0).int().sum().into_scalar() as usize;
let drop_count = numel - keep_count;
let drop_ratio = drop_count as f64 / numel as f64;
assert!((drop_ratio - drop_prob).abs() < 0.15);
let total = drop.sum().into_scalar() as f64;
let norm = total / numel as f64;
assert!((norm - 1.0).abs() < 0.01);
}
}