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 trait NeuraTrainableNetwork<Input>: NeuraLayer<Input> {
|
||||
pub trait NeuraTrainableNetworkBase<Input>: NeuraLayer<Input> {
|
||||
type Gradient: NeuraVectorSpace;
|
||||
type LayerOutput;
|
||||
|
||||
fn default_gradient(&self) -> 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
|
||||
fn regularize(&self) -> Self::Gradient;
|
||||
|
||||
/// Called before an iteration begins, to allow the network to set itself up for training or not.
|
||||
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