Only Brain
A very simple Neural Network library built in Rust with the objective to allow the user to create, manipulate and train a neural network directly. The user has direct access to weights and biases of the network, allowing them to manipulate the NN as wanted: "without the learning part", so you can bring your own.
Usage
The input and output widths are part of the network's type, so feeding a wrongly
sized input is a compile error. The hidden layers are given at construction time.
Weights and biases are plain arrays, slices or Vecs, so you don't need nalgebra
to use the network.
use NeuralNetwork;
Activation per layer
Every layer has its own activation function, so hidden layers and the output layer
can differ. The available ones are Sigmoid (the default), Tanh, ReLU,
BinaryStep and Identity.
use ;
let mut nn = new;
nn.set_activation_function; // every layer
nn.set_output_activation; // then just the output
Evolving networks: the flat parameter view
Genetic algorithms and other black-box searches work on a flat list of numbers. A network converts to and from one in a documented, stable order: layer by layer, each layer's weights row by row (one row per neuron), then that layer's biases.
use NeuralNetwork;
// The genome length for a 10 -> 8 -> 3 network.
let genes = parameter_count_for; // 115
// In a fitness function: a genome becomes a network.
let genome = vec!;
let nn = from_parameters;
// And a network becomes a genome.
assert_eq!;
set_parameters updates an existing network in place, keeping its activation
functions. NeuralNetwork is Send + Sync, so fitness can be scored in parallel.
See examples/xor_evolution.rs for a complete,
seeded neuroevolution run.
Saving and loading
Saving and loading a model checks the stored shape against the type you ask for:
use ;
#
Models are stored in a small, versioned binary format (documented in src/io.rs)
that does not depend on any serialization library, so saved models keep loading as
the library evolves. Files written by 0.1 and 0.2 still load. write_model and
read_model do the same with any Write or Read, such as a Vec<u8>.
NeuralNetwork also implements serde's Serialize and Deserialize through a
plain form ({"layers": [{"activation", "weights", "biases"}]}), so it can be
embedded in your own types and formats, such as JSON. Deserializing validates the
shape too.
Examples
| Example | Shows |
|---|---|
neural_network |
Building a network by hand and running it. |
dump_load |
Saving and loading a model. |
xor_evolution |
Evolving a network with a genetic algorithm through the flat parameter view. |
perceptron |
A single perceptron. |
perceptron_iris |
Training a perceptron on the Iris dataset with the perceptron rule. |
Run one with cargo run --example xor_evolution.
TODO
- Abstract better the DVector and DMatrix from the user's perspective;
- Perceptron
- Neural Network
- Make the types know the size of the NeuralNetwork/inputs and outputs neurons;
- Input and output widths are compile-time checked; hidden layers stay dynamic.
- Fix and improve model dump and load;
- Typed errors, buffered IO, and shape validation on load
- Versioned format header, without bincode
- Flat parameter view, for genetic algorithms
- Activation function per layer