1use crate::activations::Activation;
2
3use arrayfire::{constant, gt, matmul, mul, randu, sum, Array, Dim4, MatProp};
4
5pub struct DenseLayer {
7 pub activation: Activation,
8 pub biases: Array<f32>,
9 pub weights: Array<f32>,
10}
11impl DenseLayer {
12 pub fn new(from: u64, size: u64, activation: Activation) -> DenseLayer {
14 if size == 0 {
15 panic!("All dense layer sizes must be >0.");
16 }
17 return DenseLayer {
18 activation,
19 biases: (randu::<f32>(Dim4::new(&[size, 1, 1, 1])) * 2f32) - 1f32,
20 weights: ((randu::<f32>(Dim4::new(&[size, from, 1, 1])) * 2f32) - 1f32)
21 / (from as f32).sqrt(),
22 };
23 }
24 pub fn new_constant(from: u64, size: u64, activation: Activation, val: f32) -> DenseLayer {
26 if size == 0 {
27 panic!("All dense layer sizes must be >0.");
28 }
29 return DenseLayer {
30 activation,
31 biases: constant(val, Dim4::new(&[size, 1, 1, 1])),
32 weights: constant(val, Dim4::new(&[size, from, 1, 1])),
33 };
34 }
35 pub fn forepropagate(&self, a: &Array<f32>, ones: &Array<f32>) -> (Array<f32>, Array<f32>) {
37 let weighted_inputs: Array<f32> = matmul(&self.weights, &a, MatProp::NONE, MatProp::NONE);
38
39 let bias_matrix: Array<f32> = matmul(&self.biases, &ones, MatProp::NONE, MatProp::NONE);
41
42 let input = weighted_inputs + bias_matrix;
44
45 let activation = self.activation.run(&input);
47
48 return (activation, input);
49 }
50 pub fn backpropagate(
55 &mut self,
56 partial_error: &Array<f32>, z: &Array<f32>, a: &Array<f32>, learning_rate: f32,
60 l2: Option<f32>,
61 training_set_length: usize,
62 ) -> Array<f32> {
63 let error = self.activation.derivative(z) * partial_error;
66
67 let bias_error = sum(&error, 1);
69
70 let weight_error = matmul(&error, a, MatProp::NONE, MatProp::TRANS);
72
73 let nxt_partial_error = matmul(&self.weights, &error, MatProp::TRANS, MatProp::NONE);
75
76 let batch_len = z.dims().get()[1] as f32;
78
79 if let Some(lambda) = l2 {
82 self.weights = ((1f32 - (learning_rate * lambda / training_set_length as f32))
83 * &self.weights)
84 - (learning_rate * weight_error / batch_len)
85 } else {
86 self.weights = &self.weights - (learning_rate * weight_error / batch_len);
87 }
88
89 self.biases = &self.biases - (learning_rate * bias_error / batch_len);
91
92 return nxt_partial_error;
94 }
95}
96pub struct DropoutLayer {
98 pub p: f32,
99 mask: Array<f32>,
100}
101impl DropoutLayer {
102 pub fn new(p: f32) -> DropoutLayer {
104 DropoutLayer {
105 p,
106 mask: Array::<f32>::new_empty(Dim4::new(&[1, 1, 1, 1])),
107 }
108 }
109 pub fn forepropagate(&mut self, z: &Array<f32>, ones: &Array<f32>) -> Array<f32> {
112 let z_dims = z.dims();
114 let z_dim_arr = z_dims.get();
115 let mask_dims = Dim4::new(&[z_dim_arr[0], 1, 1, 1]);
116 self.mask = matmul(
119 >(&randu::<f32>(mask_dims), &self.p, false).cast::<f32>(),
120 ones,
121 MatProp::NONE,
122 MatProp::NONE,
123 );
124 return mul(z, &self.mask, false);
126 }
127 pub fn backpropagate(&self, partial_error: &Array<f32>) -> Array<f32> {
130 return mul(partial_error, &self.mask, false);
131 }
132}