1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//! Minidx helps you implement small to medium-sized neural networks.
//!
//! ### Defining network architecture
//!
//! In minidx, you define your network using tuples of layers, with the
//! dimensionality of inputs/outputs defined as generic constants.
//! For instance, the below example defines a network which takes 2 inputs
//! and produces 3 outputs, by first going through two hidden layers with
//! a hidden dimension of 3 and a relu activation, before a softmax layer.
//!
//! ```
//! use minidx::prelude::*;
//! use layers::*;
//!
//! type network = (
//! (Linear::<2, 3>, Relu), // Fully-connected + bias layer with relu activation
//! (Linear::<3, 3>, Relu),
//! Softmax,
//! );
//!
//! // Instantiates our neural network.
//! let mut network = Buildable::<f32>::build(&network::default());
//! ```
//!
//! You can see the full set of implemented layers in the [layer_spec] module.
//!
//! ### Random initialization of a network
//!
//! Before training, you likely want to initialize the parameters of the network
//! to reasonable random values.
//!
//! ```
//! # use minidx::prelude::*;
//! # use layers::*;
//! # type network = (
//! # (Linear::<2, 3>, Relu),
//! # Softmax,
//! # );
//! # let mut network = Buildable::<f32>::build(&network::default());
//! use rand::{SeedableRng, rngs::SmallRng};
//! let mut rng = SmallRng::seed_from_u64(42);
//! network.rand_params(&mut rng, 0.5).unwrap();
//! ```
//!
//! [`rand_params`](`core::ResetParams::rand_params`) performs sensible initialization of each layer using
//! the given RNG. The float argument represents the max magnitude of random parameters. `0.5` to `1.0` is a good starting parameter.
//!
//! ### Training
//!
//! Training a network in minidx requires two things:
//!
//! - An updater: some object that stores training state and implements
//! the optimizer algorithm you want to use
//! - A training loop: a loop where you call [train_step] or [train_batch]
//! with network inputs and their correct outputs, and a closure that wires up
//! the loss function you want to use.
//!
//! ```
//! # use minidx::prelude::*;
//! # use layers::*;
//! # type network = (
//! # (Linear::<2, 3>, Relu),
//! # Softmax,
//! # );
//! # let mut network = Buildable::<f32>::build(&network::default());
//! # use rand::{SeedableRng, rngs::SmallRng};
//! # let mut rng = SmallRng::seed_from_u64(42);
//! # network.rand_params(&mut rng, 0.5).unwrap();
//! // initialize training state
//! let mut updater = network.new_momentum(
//! TrainParams::with_lr(1.0e-5).and_l2(1.0e-6), 0.4);
//!
//! // train the network with 50 examples
//! for _i in 0..50 {
//! // fake training data
//! let input = [1.0, 2.0];
//! let output = [1.0, 0.0, 0.0];
//! // train on an individual input/output pair, using the
//! // mean-square error (MSE) loss function.
//! use loss::DiffLoss;
//! train_step(
//! &mut updater,
//! &mut network,
//! |got, want| (got.mse(want), got.mse_input_grads(want)),
//! input,
//! output,
//! );
//! }
//! ```
//!
//! Everything is fairly self-explanatory except for the closure you need to pass for your loss function.
//! That function takes both the output of the network as well as the correct output of the network, and
//! needs to return the loss with respect to the output as well as the gradient of the loss with respect
//! to the loss function. The [prelude::loss] module contains implemented loss functions and
//! corresponding methods to compute their gradients.
//!
//! Its also worth noting that there are batch and threaded-batch variants of [train_step], namely [train_batch]
//! and [train_batch_parallel]. Both batch training methods return the average loss over the samples.
//!
//! ### Inference
//!
//! You can run inference over a trained network using [`forward()`](`core::Module::forward`):
//!
//! ```
//! # use minidx::prelude::*;
//! # use layers::*;
//! # type network = (
//! # (Linear::<2, 3>, Relu),
//! # Softmax,
//! # );
//! # let mut network = Buildable::<f32>::build(&network::default());
//! let output = network.forward(&[1.0, 2.0]).unwrap(); // outputs [f32; 3]
//! ```
//!
//! Networks can be loaded and stored using [`LoadableModule`](core::LoadableModule).
pub use minidx_core as core;
pub use ;
use ;
/// Common types and traits needed when using minidx.
/// OneHotEncoder describes the encoding of some integer value modulus N into
/// a vector where exactly one value is set.
/// A layer or composition of layers that can be constructed, using some Dtype as the element type.
tuple_impls!;
tuple_impls!;
tuple_impls!;
tuple_impls!;
tuple_impls!;
tuple_impls!;