mod perceptron;
use perceptron::Perceptron;
#[derive(Debug)]
pub enum CnnksError {
IncompatibeTrainingSample
}
#[derive(Debug, Clone)]
pub struct MultiLayerPercetron {
pub bias: f64, pub eta: f64, pub layers: Vec<usize>, pub values: Vec<Vec<f64>>,
pub d: Vec<Vec<f64>>,
pub network: Vec<Vec<Perceptron>>,
}
impl MultiLayerPercetron {
pub fn new(input_layer: usize, output_layer: usize, middle_layers: Vec<usize>, bias: f64, eta: f64) -> Self {
let input_layer: Vec<usize> = Vec::from([input_layer]);
let output_layer: Vec<usize> = Vec::from([output_layer]);
let layers = [input_layer, middle_layers, output_layer].concat();
let mut values = Vec::new();
let mut d = Vec::new();
let mut network = Vec::new();
network.push(Vec::new());
for i in 0..layers.len() {
values.push(vec![0.0; layers[i]]);
d.push(vec![0.0; layers[i]]);
if i > 0 {
network.push(vec![Perceptron::new(layers[i - 1], bias); layers[i]]);
}
}
Self {
bias,
eta,
layers,
values,
d,
network,
}
}
pub fn set_weight(&mut self, w_init: f64) {
for i in 1..self.layers.len() {
for j in 0..self.layers[i] {
self.network[i][j].set_weights(w_init);
}
}
}
pub fn print_weights(&self) {
for i in 1..self.layers.len() {
println!("Layer {}", i);
for j in 0..self.layers[i] {
println!("Neuron {}, Weight {:?}", j + 1, self.network[i][j].weight)
}
}
}
pub fn run(&mut self, x: Vec<f64>) -> &Vec<f64> {
self.values[0] = x;
for i in 1..self.layers.len() {
for j in 0..self.layers[i] {
self.values[i][j] = self.network[i][j].run(self.values[i - 1].clone());
}
}
match self.values.last() {
Some(t) => t,
None => panic!("Problem in running the MultiLayerPercetron"),
}
}
pub fn back_propagation(&mut self, x: Vec<f64>, y: Vec<f64>) -> Result<f64, CnnksError> {
let output = self.run(x).clone();
match output.len() == y.len() {
true => {},
false => return Err(CnnksError::IncompatibeTrainingSample)
}
let mut error: Vec<f64> = Vec::new();
let mut mse: f64 = 0.0;
for i in (0..self.layers.len()).rev() {
for j in 0..self.network[i].len() {
if i == self.layers.len() - 1 {
error.push(y[j] - output[j]);
self.d[i][j] = output[j] * (1.0 - output[j]) * (y[j] - output[j]);
} else {
let mut fwd_error = 0.0;
for k in 0..self.layers[i + 1] {
fwd_error += self.network[i + 1][k].weight[j] * self.d[i + 1][k];
}
self.d[i][j] = self.values[i][j] * (1.0 - self.values[i][j]) * fwd_error;
}
}
match self.layers.last() {
Some(n) => mse = error.iter().sum::<f64>().powf(2.0) / *n as f64,
None => panic!("Invalid layer value at the end of the NN"),
}
}
for i in 1..self.layers.len() {
for j in 0..self.layers[i] {
for k in 0..self.layers[i - 1] + 1 {
let delta: f64;
if k == self.layers[i - 1] {
delta = self.eta * self.d[i][j] * self.bias; }
else {
delta = self.eta * self.d[i][j] * self.values[i - 1][k];
}
self.network[i][j].weight[k] += delta;
}
}
}
Ok(mse)
}
}