Skip to content

Commit c1efc3e

Browse files
authored
chore: clean leftover comments and println + fix shuffle (#69)
* remove print from flatten * use stored gates * ignore 0 * start only when cost exists * generate wasm * fix shuffle * update iris example
1 parent 7248029 commit c1efc3e

File tree

9 files changed

+167
-121
lines changed

9 files changed

+167
-121
lines changed

crates/core/src/cpu/backend.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ impl Backend {
203203
total = 0.0;
204204
}
205205
}
206-
if self.patience != 0 {
206+
if self.patience != 0 && cost != 0.0 {
207207
if best_cost < 0.0 {
208208
best_cost = cost;
209209
}

crates/core/src/cpu/layers/embedding.rs

+44-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::ops::AddAssign;
21
use ndarray::{Array2, ArrayD, Axis, Ix2, IxDyn};
2+
use std::ops::AddAssign;
33

44
use crate::{CPUInit, CPURegularizer, EmbeddingLayer, Init};
55

@@ -21,7 +21,10 @@ impl EmbeddingCPULayer {
2121
pub fn new(config: EmbeddingLayer, size: IxDyn) -> Self {
2222
let init = CPUInit::from(Init::Uniform);
2323
let output_size = vec![size[0], size[1], config.embedding_size];
24-
let embeddings = init.init(IxDyn(&[config.vocab_size, config.embedding_size]), 0, 0).into_dimensionality::<Ix2>().unwrap();
24+
let embeddings = init
25+
.init(IxDyn(&[config.vocab_size, config.embedding_size]), 0, 0)
26+
.into_dimensionality::<Ix2>()
27+
.unwrap();
2528
let d_embeddings = Array2::zeros((config.vocab_size, config.embedding_size));
2629
Self {
2730
input_size: size,
@@ -32,7 +35,10 @@ impl EmbeddingCPULayer {
3235
embeddings,
3336
d_embeddings,
3437
l_embeddings: Array2::zeros((config.vocab_size, config.embedding_size)),
35-
regularizer: CPURegularizer::from(config.c.unwrap_or(0.0), config.l1_ratio.unwrap_or(1.0))
38+
regularizer: CPURegularizer::from(
39+
config.c.unwrap_or(0.0),
40+
config.l1_ratio.unwrap_or(1.0),
41+
),
3642
}
3743
}
3844

@@ -48,21 +54,46 @@ impl EmbeddingCPULayer {
4854
let input_indices: Vec<usize> = inputs.iter().map(|&x| x as usize).collect();
4955
self.input_indices = input_indices.clone();
5056
let embeddings = self.embeddings.select(Axis(0), input_indices.as_slice());
51-
// let output_size = IxDyn(&self.output_size);
52-
embeddings.into_shape_with_order(IxDyn(&[inputs.shape()[0], inputs.shape()[1], self.embedding_size])).unwrap()
57+
// let output_size = IxDyn(&self.output_size);
58+
embeddings
59+
.into_shape_with_order(IxDyn(&[
60+
inputs.shape()[0],
61+
inputs.shape()[1],
62+
self.embedding_size,
63+
]))
64+
.unwrap()
5365
}
5466

5567
pub fn backward_propagate(&mut self, d_outputs: ArrayD<f32>) -> ArrayD<f32> {
56-
let indices = Array2::from_shape_vec(Ix2(d_outputs.shape()[0], self.input_size[1]), self.input_indices.clone());
57-
self.d_embeddings = Array2::zeros((self.d_embeddings.shape()[0], self.d_embeddings.shape()[1]));
58-
d_outputs.axis_iter(Axis(0)).zip(indices).for_each(|(rec, i)| {
59-
rec.axis_iter(Axis(0)).zip(i).for_each(|(grad, idx)| {
60-
self.d_embeddings.index_axis_mut(Axis(0), idx).add_assign(&grad);
68+
let indices = Array2::from_shape_vec(
69+
Ix2(d_outputs.shape()[0], self.input_size[1]),
70+
self.input_indices.clone(),
71+
)
72+
.unwrap();
73+
self.d_embeddings.fill(0.0);
74+
d_outputs
75+
.axis_iter(Axis(0))
76+
.zip(indices.axis_iter(Axis(0)))
77+
.for_each(|(rec, i)| {
78+
rec.axis_iter(Axis(0)).zip(i).for_each(|(grad, idx)| {
79+
if idx != &0 {
80+
self.d_embeddings
81+
.index_axis_mut(Axis(0), *idx)
82+
.add_assign(&grad);
83+
}
84+
});
6185
});
62-
});
63-
self.l_embeddings = self.regularizer.coeff(&self.embeddings.clone().into_dyn()).into_dimensionality::<Ix2>().unwrap();
86+
self.l_embeddings = self
87+
.regularizer
88+
.coeff(&self.embeddings.clone().into_dyn())
89+
.into_dimensionality::<Ix2>()
90+
.unwrap();
6491
let mut input_size = self.input_size.clone();
6592
input_size[0] = d_outputs.shape()[0];
66-
ArrayD::from_shape_vec(input_size, self.input_indices.iter().map(|x| *x as f32).collect()).unwrap()
93+
ArrayD::from_shape_vec(
94+
input_size,
95+
self.input_indices.iter().map(|x| *x as f32).collect(),
96+
)
97+
.unwrap()
6798
}
6899
}

crates/core/src/cpu/layers/flatten.rs

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ impl FlattenCPULayer {
2323

2424
pub fn forward_propagate(&mut self, inputs: ArrayD<f32>) -> ArrayD<f32> {
2525
let output_size = IxDyn(&[inputs.shape()[0], self.output_size[1]]);
26-
println!("O {:?} {:?}", inputs.shape(), self.output_size);
2726
inputs.into_shape_with_order(output_size).unwrap()
2827
}
2928

crates/core/src/cpu/layers/lstm.rs

+63-62
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use crate::{CPUActivation, Activation, CPUInit, CPURegularizer, Init, LSTMLayer, Tensors, LayerNorm};
2-
use core::f32;
3-
use ndarray::{
4-
concatenate, s, Array2, Array3, ArrayD, Axis, Dimension, Ix2, Ix3, IxDyn,
1+
use crate::{
2+
Activation, CPUActivation, CPUInit, CPURegularizer, Init, LSTMLayer, LayerNorm, Tensors,
53
};
4+
use core::f32;
5+
use ndarray::{concatenate, s, Array2, Array3, ArrayD, Axis, Dimension, Ix2, Ix3, IxDyn};
66
use std::ops::AddAssign;
77
/// Indices
88
/// 0 - Input Gate
@@ -30,12 +30,18 @@ pub struct LSTMCPULayer {
3030
pub l_w_hh: Array3<f32>,
3131
pub l_biases: Array2<f32>,
3232

33-
pub h: Array3<f32>,
34-
pub c: Array3<f32>,
33+
pub i_t: Array3<f32>,
34+
pub f_t: Array3<f32>,
35+
pub o_t: Array3<f32>,
36+
pub g_t: Array3<f32>,
37+
38+
pub h_prev: Array2<f32>,
39+
pub c_prev: Array2<f32>,
3540

3641
pub regularizer: CPURegularizer,
3742
}
3843

44+
#[allow(unused_mut)]
3945
impl LSTMCPULayer {
4046
pub fn new(config: LSTMLayer, size: IxDyn, _tensors: Option<Tensors>) -> Self {
4147
let return_sequences = config.return_sequences.unwrap_or(false);
@@ -68,14 +74,20 @@ impl LSTMCPULayer {
6874
l_w_ih: Array3::zeros(weight_size),
6975
l_w_hh: Array3::zeros((4, config.size, config.size)),
7076
l_biases: Array2::zeros((4, config.size)),
71-
h: Array3::zeros((size[1], size[0], config.size)),
72-
c: Array3::zeros((size[1], size[0], config.size)),
77+
i_t: Array3::zeros((size[1], size[0], config.size)),
78+
f_t: Array3::zeros((size[1], size[0], config.size)),
79+
o_t: Array3::zeros((size[1], size[0], config.size)),
80+
g_t: Array3::zeros((size[1], size[0], config.size)),
81+
h_prev: Array2::zeros((size[0], config.size)),
82+
c_prev: Array2::zeros((size[0], config.size)),
7383
regularizer: CPURegularizer::from(
7484
config.c.unwrap_or(0.0),
7585
config.l1_ratio.unwrap_or(1.0),
7686
),
7787

78-
activation_h: CPUActivation::from(config.recurrent_activation.unwrap_or(Activation::Sigmoid)),
88+
activation_h: CPUActivation::from(
89+
config.recurrent_activation.unwrap_or(Activation::Sigmoid),
90+
),
7991
activation_o: CPUActivation::from(config.activation.unwrap_or(Activation::Tanh)),
8092
}
8193
}
@@ -92,10 +104,13 @@ impl LSTMCPULayer {
92104
pub fn forward_propagate(&mut self, inputs: ArrayD<f32>) -> ArrayD<f32> {
93105
self.inputs = inputs.into_dimensionality::<Ix3>().unwrap();
94106
let output_size = self.w_ih.shape()[2];
95-
self.h = Array3::zeros((self.inputs.shape()[1], self.inputs.shape()[0], output_size));
96-
self.c = Array3::zeros((self.inputs.shape()[1], self.inputs.shape()[0], output_size));
97-
let mut h_t = self.h.index_axis(Axis(0), 0).clone().to_owned();
98-
let mut c_t = self.c.index_axis(Axis(0), 0).clone().to_owned();
107+
let mut h_t = Array2::zeros((self.inputs.shape()[0], output_size));
108+
let mut c_t = Array2::zeros(h_t.raw_dim());
109+
110+
self.i_t = Array3::zeros((self.inputs.shape()[1], self.inputs.shape()[0], output_size));
111+
self.f_t = Array3::zeros(self.i_t.raw_dim());
112+
self.o_t = Array3::zeros(self.i_t.raw_dim());
113+
self.g_t = Array3::zeros(self.i_t.raw_dim());
99114

100115
let mut outputs = Array3::zeros(if self.return_sequences {
101116
(self.inputs.shape()[0], self.inputs.shape()[1], output_size)
@@ -109,7 +124,8 @@ impl LSTMCPULayer {
109124
.slice(s![.., t, ..])
110125
.to_owned()
111126
.into_dimensionality::<Ix2>()
112-
.unwrap(); // Current input
127+
.unwrap();
128+
113129
let i_t = (&x_t.dot(&self.w_ih.index_axis(Axis(0), 0))
114130
+ &h_t.dot(&self.w_hh.index_axis(Axis(0), 0))
115131
+ &self.biases.index_axis(Axis(0), 0))
@@ -127,56 +143,40 @@ impl LSTMCPULayer {
127143
+ &self.biases.index_axis(Axis(0), 3))
128144
.mapv(|x| (self.activation_o.activate)(&x));
129145

146+
self.i_t.index_axis_mut(Axis(0), t).assign(&i_t);
147+
self.f_t.index_axis_mut(Axis(0), t).assign(&f_t);
148+
self.o_t.index_axis_mut(Axis(0), t).assign(&o_t);
149+
self.g_t.index_axis_mut(Axis(0), t).assign(&g_t);
150+
130151
c_t = &(&c_t * &f_t) + &(&g_t * &i_t);
131152
h_t = &c_t.mapv(|x| (self.activation_o.activate)(&x)) * &o_t;
132153

133-
self.h.index_axis_mut(Axis(0), t).assign(&h_t);
134-
self.c.index_axis_mut(Axis(0), t).assign(&c_t);
135-
136154
if self.return_sequences {
137155
outputs.slice_mut(s![.., t, ..]).assign(&h_t);
138156
}
139157
}
158+
self.h_prev = h_t.clone();
159+
self.c_prev = c_t.clone();
140160

141161
if self.return_sequences {
142162
outputs.into_dyn()
143-
}
144-
else {
163+
} else {
145164
h_t.into_dyn()
146165
}
147166
}
148-
149-
fn split_gates(
150-
&self,
151-
z: &Array2<f32>,
152-
hidden_size: usize,
153-
) -> (Array2<f32>, Array2<f32>, Array2<f32>, Array2<f32>) {
154-
let i_t = z
155-
.slice(ndarray::s![.., ..hidden_size])
156-
.mapv(|x| (self.activation_h.activate)(&x));
157-
let f_t = z
158-
.slice(ndarray::s![.., hidden_size..2 * hidden_size])
159-
.mapv(|x| (self.activation_h.activate)(&x));
160-
let o_t = z
161-
.slice(ndarray::s![.., 2 * hidden_size..3 * hidden_size])
162-
.mapv(|x| (self.activation_h.activate)(&x));
163-
let g_t = z
164-
.slice(ndarray::s![.., 3 * hidden_size..])
165-
.mapv(|x| (self.activation_o.activate)(&x));
166-
167-
(i_t, f_t, o_t, g_t)
168-
}
169167
pub fn backward_propagate(&mut self, d_outputs: ArrayD<f32>) -> ArrayD<f32> {
170168
match d_outputs.shape().len() {
171169
2 => {
172-
let d_inputs = self.backward_propagate_2d(d_outputs.into_dimensionality::<Ix2>().unwrap());
170+
let d_inputs =
171+
self.backward_propagate_2d(d_outputs.into_dimensionality::<Ix2>().unwrap());
173172
d_inputs.into_dyn()
174173
}
175174
3 => {
176-
let d_inputs = self.backward_propagate_3d(d_outputs.into_dimensionality::<Ix3>().unwrap());
175+
let d_inputs =
176+
self.backward_propagate_3d(d_outputs.into_dimensionality::<Ix3>().unwrap());
177177
d_inputs.into_dyn()
178178
}
179-
_ => d_outputs
179+
_ => d_outputs,
180180
}
181181
}
182182
pub fn backward_propagate_3d(&mut self, d_outputs: Array3<f32>) -> Array3<f32> {
@@ -189,8 +189,8 @@ impl LSTMCPULayer {
189189
self.d_w_hh = Array3::zeros((4, hidden_size, hidden_size));
190190
self.d_biases = Array2::zeros((4, hidden_size));
191191

192-
let h_prev = self.h.index_axis(Axis(0), sequence_length - 1);
193-
let c_prev = self.c.index_axis(Axis(0), sequence_length - 1);
192+
let h_prev = self.h_prev.clone();
193+
let c_prev = self.c_prev.clone();
194194

195195
let mut d_inputs = Array3::<f32>::zeros((batch_size, sequence_length, input_size));
196196

@@ -224,27 +224,28 @@ impl LSTMCPULayer {
224224
.into_dimensionality::<Ix2>()
225225
.unwrap();
226226

227-
let d_h = d_outputs.slice(s![.., t, ..]).clone().to_owned().into_dimensionality::<Ix2>().unwrap();
227+
let d_h = d_outputs
228+
.slice(s![.., t, ..])
229+
.clone()
230+
.to_owned()
231+
.into_dimensionality::<Ix2>()
232+
.unwrap();
228233

229234
d_h_prev = d_h_prev + d_h;
230-
// clip_gradients(&mut d_h_prev, 5f32);
231235

232-
let gates = x_t.dot(&w_ih)
233-
+ h_prev.dot(&w_hh)
234-
+ &self.biases.to_shape(4 * hidden_size).unwrap();
235-
let (i_t, f_t, o_t, g_t) = self.split_gates(&gates, hidden_size);
236+
let i_t = self.i_t.index_axis(Axis(0), t);
237+
let f_t = self.f_t.index_axis(Axis(0), t);
238+
let o_t = self.o_t.index_axis(Axis(0), t);
239+
let g_t = self.g_t.index_axis(Axis(0), t);
236240

237241
let d_tanned_c = &d_h_prev * &o_t * c_prev.map(|x| (self.activation_o.activate)(&x));
238242
let mut d_c_t = d_tanned_c + &d_c_prev;
239-
// clip_gradients(&mut d_c_t, 5f32);
240243

241244
let d_o_t = &d_h_prev * &c_prev.mapv(|x| (self.activation_o.activate)(&x));
242245
let d_f_t = &d_c_t * &c_prev * &f_t.map(|x| (self.activation_h.prime)(x));
243246
let d_i_t = &d_c_t * &g_t * &i_t.map(|x| (self.activation_h.prime)(x));
244247
let d_g_t = &d_c_t * &i_t * &g_t.map(|x| (self.activation_o.prime)(x));
245248
let d_gates = concatenate![Axis(1), d_i_t, d_f_t, d_o_t, d_g_t];
246-
// println!("ADD {:?}", concatenate![Axis(0), d_i_t, d_f_t, d_o_t, d_g_t].shape());
247-
// println!("DG {:?} {:?}", d_gates.shape(), &w_ih.shape());
248249
d_inputs
249250
.slice_mut(s![.., t, ..])
250251
.assign(&d_gates.dot(&w_ih.t()));
@@ -303,8 +304,8 @@ impl LSTMCPULayer {
303304
self.d_w_hh = Array3::zeros((4, hidden_size, hidden_size));
304305
self.d_biases = Array2::zeros((4, hidden_size));
305306

306-
let h_prev = self.h.index_axis(Axis(0), sequence_length - 1);
307-
let c_prev = self.c.index_axis(Axis(0), sequence_length - 1);
307+
let h_prev = self.h_prev.clone();
308+
let c_prev = self.c_prev.clone();
308309

309310
let mut d_inputs = Array3::<f32>::zeros((batch_size, sequence_length, input_size));
310311

@@ -339,22 +340,21 @@ impl LSTMCPULayer {
339340
.into_dimensionality::<Ix2>()
340341
.unwrap();
341342

342-
let gates = x_t.dot(&w_ih)
343-
+ h_prev.dot(&w_hh)
344-
+ &self.biases.to_shape(4 * hidden_size).unwrap();
345-
let (i_t, f_t, o_t, g_t) = self.split_gates(&gates, hidden_size);
343+
let i_t = self.i_t.index_axis(Axis(0), t);
344+
let f_t = self.f_t.index_axis(Axis(0), t);
345+
let o_t = self.o_t.index_axis(Axis(0), t);
346+
let g_t = self.g_t.index_axis(Axis(0), t);
346347

347348
let d_tanned_c = &d_h_prev * &o_t * c_prev.map(|x| (self.activation_o.activate)(&x));
348349
let mut d_c_t = d_tanned_c + &d_c_prev;
349-
// clip_gradients(&mut d_c_t, 5f32);
350350

351351
let d_o_t = &d_h_prev * &c_prev.mapv(|x| (self.activation_o.activate)(&x));
352352
let d_f_t = &d_c_t * &c_prev * &f_t.map(|x| (self.activation_h.prime)(x));
353353
let d_i_t = &d_c_t * &g_t * &i_t.map(|x| (self.activation_h.prime)(x));
354354
let d_g_t = &d_c_t * &i_t * &g_t.map(|x| (self.activation_o.prime)(x));
355355

356356
let d_gates = concatenate![Axis(1), d_i_t, d_f_t, d_o_t, d_g_t];
357-
// println!("OT: {:?}\n\nFT {:?}", &d_h_prev, &d_c_prev);
357+
358358
d_inputs
359359
.slice_mut(s![.., t, ..])
360360
.assign(&d_gates.dot(&w_ih.t()));
@@ -405,6 +405,7 @@ impl LSTMCPULayer {
405405
}
406406
}
407407

408+
#[allow(dead_code)]
408409
fn clip_gradients(grad: &mut Array2<f32>, threshold: f32) -> () {
409410
let norm = grad.mapv(|x| x.powi(2)).sum().sqrt();
410411
if norm > threshold {

examples/classification/iris.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,12 @@ const net = new Sequential({
5555

5656
// Define each layer of the network
5757
layers: [
58-
// A dense layer with 16 neurons
59-
DenseLayer({ size: [16] }),
58+
// A dense layer with 8 neurons
59+
DenseLayer({ size: [8] }),
60+
// A ReLu activation layer
61+
ReluLayer(),
62+
// A dense layer with 8 neurons
63+
DenseLayer({ size: [8] }),
6064
// A ReLu activation layer
6165
ReluLayer(),
6266
// A dense layer with 3 neurons

packages/core/src/backends/wasm/lib/netsaur.generated.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// deno-fmt-ignore-file
55
/// <reference types="./netsaur.generated.d.ts" />
66

7-
// source-hash: 60e03f192e01f72854ad537d5cc565c02235b170
7+
// source-hash: 6fae1da844014c6af84634327825fa20fac7ef5f
88
let wasm;
99
let cachedInt32Memory0;
1010

@@ -223,10 +223,10 @@ const imports = {
223223
__wbindgen_object_drop_ref: function (arg0) {
224224
takeObject(arg0);
225225
},
226-
__wbg_log_6f7dfa87fad40a57: function (arg0, arg1) {
226+
__wbg_log_860f982bd7b08de8: function (arg0, arg1) {
227227
console.log(getStringFromWasm0(arg0, arg1));
228228
},
229-
__wbg_now_de5fe0de473bcd7d: typeof Date.now == "function"
229+
__wbg_now_aa5f80cbe756bd45: typeof Date.now == "function"
230230
? Date.now
231231
: notDefined("Date.now"),
232232
__wbindgen_number_new: function (arg0) {
Binary file not shown.

0 commit comments

Comments
 (0)