A GPU accelerated library that creates/trains/runs neural networks in pure safe Rust code.
Intricate has a layout very similar to popular libraries out there such as Keras.
As said before, similar to Tensorflow, Intricate defines Models as basically
a list of Layers
that are explained down bellow.
Every layer receives inputs and returns outputs,
they must also implement a back_propagate
method that
will mutate the layer if needed and then return the derivatives
of the loss function with respected to the inputs,
written with I as the inputs of the layer,
E as the loss and O as the outputs of the layer:
dE/dI <- Model <- dE/dO
These layers can be anything you want and just propagates the previous inputs to the next inputs for the next layer or for the outputs of the whole Model.
There are a few activations already implemented, but still many to be implemented.
If you look at the examples/
in the repository
you will find XoR implemented using Intricate.
The following is basically just that example with some separate explanation.
```rs let training_inputs = Vec::from([ Vec::from([0.0, 0.0]), Vec::from([0.0, 1.0]), Vec::from([1.0, 0.0]), Vec::from([1.0, 1.0]), ]);
let expected_outputs = Vec::from([ Vec::from([0.0]), Vec::from([1.0]), Vec::from([1.0]), Vec::from([0.0]), ]); ```
```rs
let mut layers: Vec
// inputsamount|outputsamount layers.push(Box::new(DenseF64::new(2, 3))); layers.push(Box::new(TanHF64::new())); // activation functions are layers layers.push(Box::new(DenseF64::new(3, 1))); layers.push(Box::new(TanHF64::new())); ```
rs
// Instantiate our model using the layers
let mut xor_model = ModelF64::new(layers);
// mutable because the 'fit' method lets the layers tweak themselves
rs
xor_model.fit(
&training_inputs,
&expected_outputs,
TrainingOptionsF64 {
learning_rate: 0.1,
loss_algorithm: Box::new(MeanSquared), // The Mean Squared loss function
should_print_information: true, // Should be verbose
instantiate_gpu: false, // Should initialize WGPU Device and Queue for GPU layers
epochs: 10000,
},
).await;
As you can see it is extremely easy creating these models, and blazingly fast as well.
Although if you wish to do (just like in the actual XoR example) you could write this using the F32 version of numbers which is 30% faster overall and uses half the RAM but at the price of less precision.
Intricate implements a few functions for each layer that saves and loads the necessary layer information to some file using the savefile crate.
But a layer can save and load the data anyway it sees fit, as long as it does what the trait Layer requires.
To load and save data, as an example, say for the XoR model
we trained above, we can just call the save
function as such:
rs
xor_model.layers[0].save("xor-model-first-dense.bin", 0).unwrap();
xor_model.layers[2].save("xor-model-second-dense.bin", 0).unwrap();
And we save only the Dense layers here because the Activation layers don't really hold any valuable information, only the Dense layers do.
As for the loading of the data we must create some dummy dense layers and tell them to load their data from the paths created above
```rs
let mut firstdense: Box
let mut newlayers: Vec
let loadedxormodel = ModelF32::new(new_layers); ```