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}