1use std::fs;
4
5use indicatif::ProgressIterator;
6
7#[allow(unused_imports)]
8use crate::linalg::{
9    Vector,
10    Matrix,
11    Activation,
12    ReLU,
13    Sigmoid,
14    Softmax,
15};
16
17pub struct Layer<const N: usize, const M: usize> {
19    weights: Matrix<M, N>,
20    biases: Vector<M>,
21    activation: Box<dyn Activation<M>>,
22    learning_rate: f64,
23    input: Vector<N>,
24    output: Vector<M>,
25}
26
27impl<const N: usize, const M: usize> Layer<N, M> {
28    pub fn new(activation: Box<dyn Activation<M>>, learning_rate: f64) -> Self {
30        Self {
31            weights: Matrix::<M, N>::random(),
32            biases: Vector::<M>::random(),
33            activation,
34            learning_rate,
35            input: Vector::<N>::zero(),
36            output: Vector::<M>::zero(),
37        }
38    }
39
40    pub fn evaluate(&mut self, vector: Vector<N>) -> Vector<M> {
42        self.input = vector;
43        self.output = self.activation.evaluate(self.weights.mult(vector) + self.biases);
44        self.output
45    }
46
47    pub fn backpropagate(&mut self, next_error: Vector<M>) -> Vector<N> {
49        let error = next_error.mult(self.activation.backpropagate(self.output));
51
52        let weight_adjust = error.transpose_mult(self.input).scaled(self.learning_rate);
54
55        let bias_adjust = error;
57
58        self.weights = self.weights - weight_adjust;
60        self.biases = self.biases - bias_adjust;
61
62        let prev_error = self.weights.transposed().mult(error);
64
65        prev_error
66    }
67}
68
69#[test]
70fn evaluate_layer() {
71    let mut layer = Layer::<3, 1>::new(Box::new(Sigmoid::<1>), 1.0);
72    let vector = Vector::new([1.0, 1.0, 0.0]);
73    let output = layer.evaluate(vector);
74    let expected = Vector::new([1.0]);
75    let error = output - expected;
76    layer.backpropagate(error);
77
78    dbg!(error);
79    dbg!(output);
80
81    let output = layer.evaluate(vector);
82    let error = output - expected;
83
84    dbg!(error);
85    dbg!(output);
86}
87
88#[derive(Clone, Debug)]
89pub struct TrainingDataset<const X: usize, const Y: usize> {
91    data: Vec<(Vector<X>, Vector<Y>)>,
92}
93
94impl<const X: usize, const Y: usize> TrainingDataset<X, Y> {
95    pub fn new(data: Vec<(Vector<X>, Vector<Y>)>) -> Self {
97        Self {
98            data,
99        }
100    }
101
102    pub fn import<'a>(filename: &'a str) -> Self {
104        let raw = match fs::read_to_string(filename) {
105            Ok(s) => s,
106            Err(_) => String::new(),
107        };
108
109        let mut data = Vec::new();
110
111        for line in raw.split("\n") {
112            let cells = line.split("|")
113                .map(|s| s.trim())
114                .collect::<Vec<&str>>();
115            let inputs = cells[0].split(" ")
116                .map(|d| str::parse::<f64>(d).unwrap_or(0.0))
117                .collect::<Vec<f64>>();
118            let outputs = cells[1].split(" ")
119                .map(|d| str::parse::<f64>(d).unwrap_or(0.0))
120                .collect::<Vec<f64>>();
121
122            let input = Vector::<X>::from(inputs);
123            let expected = Vector::<Y>::from(outputs);
124
125            data.push((input, expected));
126        }
127
128        Self {
129            data,
130        }
131    }
132
133    pub fn yield_data(&self) -> &Vec<(Vector<X>, Vector<Y>)> {
135        &self.data
136    }
137}
138
139#[test]
140fn import_dataset() {
141    let dataset = TrainingDataset::<3, 3>::import("iris.nntd");
142    dbg!(dataset);
143}
144
145pub struct Network<const X: usize, const H: usize, const Y: usize> {
147    input_layer: Layer<X, H>,
148    hidden_layers: Vec<Layer<H, H>>,
149    output_layer: Layer<H, Y>,
150    learning_rate: f64,
151}
152
153impl<const X: usize, const H: usize, const Y: usize> Network<X, H, Y> {
154    pub fn new(
156        input_activation: Box<dyn Activation<H>>,
157        output_activation: Box<dyn Activation<Y>>,
158        learning_rate: f64,
159    ) -> Self {
160        Self {
161            input_layer: Layer::new(input_activation, learning_rate),
162            hidden_layers: Vec::new(),
163            output_layer: Layer::new(output_activation, learning_rate),
164            learning_rate,
165        }
166    }
167
168    pub fn add_hidden_layer(&mut self, activation: Box<dyn Activation<H>>) {
170        let layer = Layer::new(activation, self.learning_rate);
171        self.hidden_layers.push(layer);
172    }
173
174    pub fn evaluate(&mut self, vector: Vector<X>) -> Vector<Y> {
176        let mut output: Vector<H> = self.input_layer.evaluate(vector);
177
178        for layer in self.hidden_layers.iter_mut() {
179            output = layer.evaluate(output);
180        }
181
182        self.output_layer.evaluate(output)
183    }
184
185    fn backpropagate(&mut self, error: Vector<Y>) {
187        let mut error_signal: Vector<H> = self.output_layer.backpropagate(error);
188
189        for layer in self.hidden_layers.iter_mut().rev() {
190            error_signal = layer.backpropagate(error_signal);
191        }
192
193        self.input_layer.backpropagate(error_signal);
194    }
195
196    pub fn train_once(&mut self, input: Vector<X>, expected: Vector<Y>) -> f64 {
198        let output = self.evaluate(input);
199        let error = output - expected;
200        self.backpropagate(error);
201        0.5*error.norm()*error.norm()
202    }
203
204    pub fn train_all(&mut self, dataset: &TrainingDataset<X, Y>) -> f64 {
206        let data = dataset.yield_data();
207
208        let mut cost: f64 = 0.0;
209
210        for &(input, expected) in data {
211            cost += self.train_once(input, expected);
212        }
213        
214        cost/(data.len() as f64)
215    }
216
217    pub fn train(&mut self, dataset: &TrainingDataset<X, Y>, generations: usize) {
219        println!("Training network...");
220        for _ in (0..generations).progress() {
221            let _ = self.train_all(dataset);
222        }
223    }
224}
225
226#[test]
227fn train_network() {
228    let mut network = Network::<3, 6, 3>::new(
229        Box::new(Sigmoid::<6>),
230        Box::new(Sigmoid::<3>),
231        0.01,
232    );
233
234    network.add_hidden_layer(Box::new(Sigmoid::<6>));
235    network.add_hidden_layer(Box::new(Sigmoid::<6>));
236
237    let dataset = TrainingDataset::<3, 3>::import("iris.nntd");
238
239    network.train(&dataset, 4000);
240
241    let vector = Vector::new([5.1, 3.5, 1.4]);
242    dbg!(network.evaluate(vector));
243}