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
196
197
198
199
//! Neural network primitives: layers, loss functions, optimizers, the 2 models, and the traits
//! that tie them together
//!
//! The module builds, trains, and runs neural networks.
//! Layers, optimizers, and losses live in the [`layers`](crate::neural_network::layers),
//! [`optimizers`](crate::neural_network::optimizers), and
//! [`losses`](crate::neural_network::losses) submodules.
//! [`Sequential`](crate::neural_network::sequential::Sequential) stacks layers into a
//! chain, and [`Graph`](crate::neural_network::graph::Graph) wires them into a directed graph.
//! The shared interfaces live in [`traits`](crate::neural_network::traits).
//! Every tensor in the framework is a [`Tensor`](crate::neural_network::Tensor), an `f32`
//! n-dimensional array
//!
//! A layer computes, and it holds no cache and no gradient.
//! [`forward`](crate::neural_network::traits::UnaryLayer::forward) and
//! [`backward`](crate::neural_network::traits::UnaryLayer::backward) take `&self` and a
//! [`Ctx`](crate::neural_network::Ctx). The context carries the training flag, the caches of the
//! pass, every parameter gradient, and the non-trainable state that a training pass changes.
//! [`Ctx::training`](crate::neural_network::Ctx::training) and
//! [`Ctx::inference`](crate::neural_network::Ctx::inference) pick the mode. A built model is
//! therefore `Send` and `Sync`, and several threads can run inference against 1 model
//!
//! # Core components
//!
//! ## Layers
//! - **Dense**: fully connected layer with a configurable activation
//! - **Embedding**: trainable lookup table that turns whole-number indices into dense vectors
//! - **Reshaping**: `Flatten` collapses to rank 2, and `Reshape` rewrites the non-batch axes
//! - **Border**: `ZeroPadding1D/2D/3D` and `Cropping1D/2D/3D` resize the spatial axes at
//! their ends
//! - **Upsampling**: `UpSampling1D/2D/3D` enlarge the spatial axes by a whole-number factor,
//! with 5 interpolation modes on the 2D layer
//! - **Axis order**: `Permute` reorders the non-batch axes, `Reverse` flips the order inside
//! 1 axis, and `RepeatVector` repeats a feature vector into a sequence
//! - **Identity**: passes its input through unchanged, as a placeholder where a model needs a
//! layer that does nothing
//! - **Rescaling**: applies the fixed affine map `y = x * scale + offset` to every element, to
//! condition an input in front of the first weight that a model trains
//! - **Activation**: standalone activation layers (ReLU, LeakyReLU, ELU, SELU, Sigmoid, Tanh, ...)
//! - **PReLU**: a ReLU whose negative-side slope is trainable, with a `shared_axes` rule that
//! sets how many slopes it holds
//! - **Convolution**: 1D/2D/3D convolution, their transposed counterparts for a decoder, plus
//! depthwise and separable variants in 1D and 2D
//! - **Pooling**: max and average pooling and their global variants for 1D, 2D, and 3D
//! - **Recurrent**: SimpleRNN, LSTM, and GRU sequence layers
//! - **Regularization**: dropout (including spatial), noise injection, and normalization layers,
//! the last of which includes `UnitNormalization` for an L2 norm of 1 per group
//! - **Merge**: `Add`, `Subtract`, `Multiply`, `Average`, `Maximum`, and `Minimum` reduce several
//! inputs element by element, and `Concatenate` joins them along 1 axis. Each layer takes
//! several inputs and gives 1 output, so a graph model joins its branches with them.
//! [`Concatenate::new`](crate::neural_network::layers::Concatenate::new) never fails, and its
//! axis counts against the full rank. The axis 0 therefore joins the batch axis, and a
//! negative axis counts back from the end.
//! [`Average`](crate::neural_network::layers::Average) is the 1 name that 2 categories of the
//! crate give to an item. The root of [`prelude`](crate::prelude) keeps the averaging mode of
//! the classification scores, so a caller that wants the layer must write
//! `prelude::neural_network::Average` or `neural_network::layers::Average`
//!
//! ## Optimizers
//! - **SGD**: stochastic gradient descent with momentum
//! - **Adam**: adaptive moment estimation (coupled L2 weight decay)
//! - **AdamW**: Adam with decoupled weight decay
//! - **RMSprop**: root-mean-square propagation
//! - **AdaGrad**: adaptive gradient
//!
//! ## Loss functions
//! - **MeanSquaredError** / **MeanAbsoluteError**: regression
//! - **BinaryCrossEntropy**: binary classification
//! - **CategoricalCrossEntropy** / **SparseCategoricalCrossEntropy**: multi-class classification
//!
//! ## Shapes
//! - [`Shape`](crate::neural_network::Shape): the shape of a tensor as a layer describes it,
//! with a free axis for an extent that no configuration fixes. Every layer maps an input
//! shape to an output shape through
//! [`compute_output_shape`](crate::neural_network::traits::UnaryLayer::compute_output_shape),
//! which reads the layer configuration alone and answers before any tensor exists
//!
//! ## Weight initialization
//! - [`Initializer`](crate::neural_network::Initializer): how a layer draws the starting values
//! of a weight array. Every drawn array of the module comes from this closed set of 3 rules.
//! The layer supplies the [`Fans`](crate::neural_network::Fans) pair, because a kernel shape
//! alone cannot tell a plain convolution from a transposed one
//!
//! ## Models
//! - [`Sequential`](crate::neural_network::sequential::Sequential): a linear stack of layers with
//! an integrated training loop, prediction, and weight save and load. `fit` and
//! `fit_with_batches` return a [`History`](crate::neural_network::sequential::History) with 1
//! loss value per epoch. Both build on the public `train_batch` step. `evaluate` scores a model
//! without training it
//! - [`Graph`](crate::neural_network::graph::Graph): a directed graph of layers, with the same
//! training loop, prediction, and weight save and load. It takes several inlets and gives
//! several outlets, and it holds a layer arena. Several nodes can call 1 layer of that arena.
//! Those nodes then share 1 set of arrays, and the sum of their gradients updates that set.
//! [`GraphBuilder`](crate::neural_network::graph::GraphBuilder) is the only way to reach one
//!
//! # Examples
//!
//! ## A chain of layers
//!
//! ```rust
//! use rustyml::neural_network::{
//! Shape,
//! sequential::SequentialBuilder,
//! layers::{Activation, Dense},
//! optimizers::Adam,
//! losses::MeanSquaredError,
//! };
//! use ndarray::Array;
//!
//! // Create input and target tensors
//! let x = Array::ones((2, 4)).into_dyn(); // 2 samples, 4 features
//! let y = Array::ones((2, 1)).into_dyn(); // 2 samples, 1 output
//!
//! // Build sequential model
//! let mut model = SequentialBuilder::new()
//! .add(Dense::new(8, Activation::ReLU).unwrap()) // Input layer: 4 -> 8
//! .add(Dense::new(3, Activation::ReLU).unwrap()) // Hidden layer: 8 -> 3
//! .add(Dense::new(1, Activation::Linear).unwrap()) // Output layer: 3 -> 1
//! .build(&Shape::known(x.shape()))
//! .unwrap();
//!
//! // Compile with optimizer and loss function
//! model.compile(Adam::new(0.001, 0.9, 0.999, 1e-8, 0.0).unwrap(), MeanSquaredError::new());
//!
//! // Display model architecture
//! model.summary();
//!
//! // Train the model
//! model.fit(&x, &y, 100).unwrap();
//!
//! // Make predictions
//! let predictions = model.predict(&x);
//! ```
//!
//! ## A graph of layers, joined by a merge layer
//!
//! ```rust
//! use rustyml::neural_network::{
//! Shape,
//! graph::GraphBuilder,
//! layers::{Activation, Concatenate, Dense},
//! optimizers::SGD,
//! losses::MeanSquaredError,
//! };
//! use ndarray::Array;
//!
//! // 2 inlets of 4 samples each, and 1 target of 2 values per sample
//! let left = Array::ones((4, 3)).into_dyn();
//! let right = Array::ones((4, 5)).into_dyn();
//! let y = Array::ones((4, 2)).into_dyn();
//!
//! // The 2 inlets keep registration order, and every call takes its tensors in that order
//! let mut builder = GraphBuilder::new();
//! let a = builder.input(Shape::known(&[4, 3]));
//! let b = builder.input(Shape::known(&[4, 5]));
//! let joined = builder.add(Concatenate::new(-1), &[a, b]);
//! let head = builder.add(Dense::new(2, Activation::Linear).unwrap(), &[joined]);
//! let mut model = builder.build(&[head]).unwrap();
//!
//! // The merge layer adds the 2 feature counts, so the head reads 8 features
//! assert_eq!(model.output_shapes()[0].to_string(), "(4, 2)");
//!
//! model.compile(SGD::new(0.01, 0.0, false, 0.0).unwrap(), MeanSquaredError::new());
//! model.fit(&[&left, &right], &[&y], 5).unwrap();
//!
//! let predictions = model.predict(&[&left, &right]).unwrap();
//! assert_eq!(predictions[0].shape(), &[4, 2]);
//! ```
use ArrayD;
/// N-dimensional array used as a tensor in the neural network
pub type Tensor = ;
/// The per-pass context that carries caches, gradients and state between layers
/// Neural-network error type, aggregated into the crate-wide [`Error`](crate::error::Error)
/// A model whose layers form a directed graph, rather than a chain
/// How a layer draws the starting values of a weight array
/// Neural network layer implementations
/// Loss function implementations
/// Optimization algorithms for neural network training
/// Sequential model architecture
/// The tensor shape a layer computes, with a free axis for an extent no configuration fixes
/// Trait interfaces for neural network models
pub use ;
pub use NnError;
pub use ;
pub use Shape;