parent
cb862f12cc
commit
81de6ddbcd
@ -1,25 +1,29 @@
|
|||||||
use crate::{algebra::NeuraVectorSpace, derivable::NeuraLoss, layer::NeuraLayer};
|
use crate::{algebra::NeuraVectorSpace, layer::NeuraLayer, optimize::NeuraOptimizerBase};
|
||||||
|
|
||||||
pub mod sequential;
|
pub mod sequential;
|
||||||
|
|
||||||
pub trait NeuraTrainableNetwork<Input>: NeuraLayer<Input> {
|
pub trait NeuraTrainableNetworkBase<Input>: NeuraLayer<Input> {
|
||||||
type Gradient: NeuraVectorSpace;
|
type Gradient: NeuraVectorSpace;
|
||||||
|
type LayerOutput;
|
||||||
|
|
||||||
fn default_gradient(&self) -> Self::Gradient;
|
fn default_gradient(&self) -> Self::Gradient;
|
||||||
|
|
||||||
fn apply_gradient(&mut self, gradient: &Self::Gradient);
|
fn apply_gradient(&mut self, gradient: &Self::Gradient);
|
||||||
|
|
||||||
/// Should implement the backpropagation algorithm, see `NeuraTrainableLayer::backpropagate` for more information.
|
|
||||||
fn backpropagate<Loss: NeuraLoss<Self::Output>>(
|
|
||||||
&self,
|
|
||||||
input: &Input,
|
|
||||||
target: &Loss::Target,
|
|
||||||
loss: Loss,
|
|
||||||
) -> (Input, Self::Gradient);
|
|
||||||
|
|
||||||
/// Should return the regularization gradient
|
/// Should return the regularization gradient
|
||||||
fn regularize(&self) -> Self::Gradient;
|
fn regularize(&self) -> Self::Gradient;
|
||||||
|
|
||||||
/// Called before an iteration begins, to allow the network to set itself up for training or not.
|
/// Called before an iteration begins, to allow the network to set itself up for training or not.
|
||||||
fn prepare(&mut self, train_iteration: bool);
|
fn prepare(&mut self, train_iteration: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait NeuraTrainableNetwork<Input, Optimizer>: NeuraTrainableNetworkBase<Input>
|
||||||
|
where
|
||||||
|
Optimizer: NeuraOptimizerBase,
|
||||||
|
{
|
||||||
|
fn traverse(
|
||||||
|
&self,
|
||||||
|
input: &Input,
|
||||||
|
optimizer: &Optimizer,
|
||||||
|
) -> Optimizer::Output<Input, Self::Gradient>;
|
||||||
|
}
|
||||||
|
@ -0,0 +1,112 @@
|
|||||||
|
use num::ToPrimitive;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
derivable::NeuraLoss,
|
||||||
|
layer::NeuraTrainableLayer,
|
||||||
|
network::{NeuraTrainableNetwork, NeuraTrainableNetworkBase},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait NeuraOptimizerBase {
|
||||||
|
type Output<NetworkInput, NetworkGradient>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NeuraOptimizerFinal<LayerOutput>: NeuraOptimizerBase {
|
||||||
|
fn eval_final(&self, output: LayerOutput) -> Self::Output<LayerOutput, ()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NeuraOptimizerTransient<LayerOutput>: NeuraOptimizerBase {
|
||||||
|
fn eval_layer<
|
||||||
|
Input,
|
||||||
|
NetworkGradient,
|
||||||
|
RecGradient,
|
||||||
|
Layer: NeuraTrainableLayer<Input, Output = LayerOutput>,
|
||||||
|
>(
|
||||||
|
&self,
|
||||||
|
layer: &Layer,
|
||||||
|
input: &Input,
|
||||||
|
rec_opt_output: Self::Output<LayerOutput, RecGradient>,
|
||||||
|
combine_gradients: impl Fn(Layer::Gradient, RecGradient) -> NetworkGradient,
|
||||||
|
) -> Self::Output<Input, NetworkGradient>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NeuraOptimizer<Input, Target, Trainable: NeuraTrainableNetworkBase<Input>> {
|
||||||
|
fn get_gradient(
|
||||||
|
&self,
|
||||||
|
trainable: &Trainable,
|
||||||
|
input: &Input,
|
||||||
|
target: &Target,
|
||||||
|
) -> Trainable::Gradient;
|
||||||
|
|
||||||
|
fn score(&self, trainable: &Trainable, input: &Input, target: &Target) -> f64;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NeuraBackprop<Loss> {
|
||||||
|
loss: Loss,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Loss> NeuraBackprop<Loss> {
|
||||||
|
pub fn new(loss: Loss) -> Self {
|
||||||
|
Self { loss }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
Input,
|
||||||
|
Target,
|
||||||
|
Trainable: NeuraTrainableNetworkBase<Input>,
|
||||||
|
Loss: NeuraLoss<Trainable::Output, Target = Target> + Clone,
|
||||||
|
> NeuraOptimizer<Input, Target, Trainable> for NeuraBackprop<Loss>
|
||||||
|
where
|
||||||
|
<Loss as NeuraLoss<Trainable::Output>>::Output: ToPrimitive,
|
||||||
|
Trainable: for<'a> NeuraTrainableNetwork<Input, (&'a NeuraBackprop<Loss>, &'a Target)>,
|
||||||
|
{
|
||||||
|
fn get_gradient(
|
||||||
|
&self,
|
||||||
|
trainable: &Trainable,
|
||||||
|
input: &Input,
|
||||||
|
target: &Target,
|
||||||
|
) -> Trainable::Gradient {
|
||||||
|
let (_, gradient) = trainable.traverse(input, &(self, target));
|
||||||
|
|
||||||
|
gradient
|
||||||
|
}
|
||||||
|
|
||||||
|
fn score(&self, trainable: &Trainable, input: &Input, target: &Target) -> f64 {
|
||||||
|
let output = trainable.eval(&input);
|
||||||
|
self.loss.eval(target, &output).to_f64().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Loss, Target> NeuraOptimizerBase for (&NeuraBackprop<Loss>, &Target) {
|
||||||
|
type Output<NetworkInput, NetworkGradient> = (NetworkInput, NetworkGradient); // epsilon, gradient
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<LayerOutput, Target, Loss: NeuraLoss<LayerOutput, Target = Target>>
|
||||||
|
NeuraOptimizerFinal<LayerOutput> for (&NeuraBackprop<Loss>, &Target)
|
||||||
|
{
|
||||||
|
fn eval_final(&self, output: LayerOutput) -> Self::Output<LayerOutput, ()> {
|
||||||
|
(self.0.loss.nabla(self.1, &output), ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<LayerOutput, Target, Loss> NeuraOptimizerTransient<LayerOutput>
|
||||||
|
for (&NeuraBackprop<Loss>, &Target)
|
||||||
|
{
|
||||||
|
fn eval_layer<
|
||||||
|
Input,
|
||||||
|
NetworkGradient,
|
||||||
|
RecGradient,
|
||||||
|
Layer: NeuraTrainableLayer<Input, Output = LayerOutput>,
|
||||||
|
>(
|
||||||
|
&self,
|
||||||
|
layer: &Layer,
|
||||||
|
input: &Input,
|
||||||
|
rec_opt_output: Self::Output<LayerOutput, RecGradient>,
|
||||||
|
combine_gradients: impl Fn(Layer::Gradient, RecGradient) -> NetworkGradient,
|
||||||
|
) -> Self::Output<Input, NetworkGradient> {
|
||||||
|
let (epsilon_in, rec_gradient) = rec_opt_output;
|
||||||
|
let (epsilon_out, layer_gradient) = layer.backprop_layer(input, epsilon_in);
|
||||||
|
|
||||||
|
(epsilon_out, combine_gradients(layer_gradient, rec_gradient))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue