use crate::core::{error::BellandeError, tensor::Tensor};
use crate::layer::{
activation::ReLU, avgpool2d::AvgPool2d, conv::Conv2d, dropout::Dropout, linear::Linear,
pooling::MaxPool2d,
};
use crate::models::sequential::{NeuralLayer, Sequential};
pub struct VGG {
features: Sequential,
avgpool: AvgPool2d,
classifier: Sequential,
}
impl VGG {
pub fn vgg16(num_classes: usize) -> Result<Self, BellandeError> {
let mut features = Sequential::new();
features.add(Box::new(Conv2d::new(
3,
64,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(Conv2d::new(
64,
64,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(MaxPool2d::new((2, 2), Some((2, 2)))));
features.add(Box::new(Conv2d::new(
64,
128,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(Conv2d::new(
128,
128,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(MaxPool2d::new((2, 2), Some((2, 2)))));
features.add(Box::new(Conv2d::new(
128,
256,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(Conv2d::new(
256,
256,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(Conv2d::new(
256,
256,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(MaxPool2d::new((2, 2), Some((2, 2)))));
features.add(Box::new(Conv2d::new(
256,
512,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(Conv2d::new(
512,
512,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(Conv2d::new(
512,
512,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(MaxPool2d::new((2, 2), Some((2, 2)))));
features.add(Box::new(Conv2d::new(
512,
512,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(Conv2d::new(
512,
512,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(Conv2d::new(
512,
512,
(3, 3),
Some((1, 1)),
Some((1, 1)),
true,
)));
features.add(Box::new(ReLU::new()));
features.add(Box::new(MaxPool2d::new((2, 2), Some((2, 2)))));
let mut classifier = Sequential::new();
classifier.add(Box::new(Linear::new(512 * 7 * 7, 4096, true)));
classifier.add(Box::new(ReLU::new()));
classifier.add(Box::new(Dropout::new(0.5)?)); classifier.add(Box::new(Linear::new(4096, 4096, true)));
classifier.add(Box::new(ReLU::new()));
classifier.add(Box::new(Dropout::new(0.5)?)); classifier.add(Box::new(Linear::new(4096, num_classes, true)));
Ok(VGG {
features,
avgpool: AvgPool2d::new(
(7, 7), Some((1, 1)), None, ),
classifier,
})
}
pub fn forward(&mut self, x: &Tensor) -> Result<Tensor, BellandeError> {
let mut out = self.features.forward(x)?;
out = NeuralLayer::forward(&mut self.avgpool, &out)?;
let batch_size = out.shape[0];
let flattened_size = out.data.len() / batch_size;
out = out.reshape(&[batch_size, flattened_size])?;
out = self.classifier.forward(&out)?;
Ok(out)
}
}
impl NeuralLayer for ReLU {
fn forward(&mut self, input: &Tensor) -> Result<Tensor, BellandeError> {
self.forward(input)
}
fn backward(&mut self, grad_output: &Tensor) -> Result<Tensor, BellandeError> {
self.backward(grad_output)
}
fn parameters(&self) -> Vec<Tensor> {
Vec::new() }
fn named_parameters(&self) -> Vec<(String, Tensor)> {
Vec::new() }
fn set_parameter(&mut self, _name: &str, _value: Tensor) -> Result<(), BellandeError> {
Err(BellandeError::InvalidParameter(
"ReLU has no parameters".into(),
))
}
fn train(&mut self) {} fn eval(&mut self) {} }
unsafe impl Send for VGG {}
unsafe impl Sync for VGG {}