grenade-0.1.0: src/Grenade/Core/Layer.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE FlexibleInstances #-}
{-|
Module : Grenade.Core.Layer
Description : Defines the Layer Classes
Copyright : (c) Huw Campbell, 2016-2017
License : BSD2
Stability : experimental
This module defines what a Layer is in a Grenade
neural network.
There are two classes of interest: `UpdateLayer` and `Layer`.
`UpdateLayer` is required for all types which are used as a layer
in a network. Having no shape information, this class is agnotostic
to the input and output data of the layer.
An instance of `Layer` on the other hand is required for usage in
a neural network, but also specifies the shapes of data that the
network can transform. Multiple instance of `Layer` are permitted
for a single type, to transform different shapes. The `Reshape` layer
for example can act as a flattening layer, and its inverse, projecting
a 1D shape up to 2 or 3 dimensions.
Instances of `Layer` should be as strict as possible, and not emit
runtime errors.
-}
module Grenade.Core.Layer (
Layer (..)
, UpdateLayer (..)
) where
import Control.Monad.Random ( MonadRandom )
import Data.List ( foldl' )
import Grenade.Core.Shape
import Grenade.Core.LearningParameters
-- | Class for updating a layer. All layers implement this, as it
-- describes how to create and update the layer.
--
class UpdateLayer x where
-- | The type for the gradient for this layer.
-- Unit if there isn't a gradient to pass back.
type Gradient x :: *
-- | Update a layer with its gradient and learning parameters
runUpdate :: LearningParameters -> x -> Gradient x -> x
-- | Create a random layer, many layers will use pure
createRandom :: MonadRandom m => m x
-- | Update a layer with many Gradients
runUpdates :: LearningParameters -> x -> [Gradient x] -> x
runUpdates rate = foldl' (runUpdate rate)
{-# MINIMAL runUpdate, createRandom #-}
-- | Class for a layer. All layers implement this, however, they don't
-- need to implement it for all shapes, only ones which are
-- appropriate.
--
class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
-- | The Wengert tape for this layer. Includes all that is required
-- to generate the back propagated gradients efficiently. As a
-- default, `S i` is fine.
type Tape x i o :: *
-- | Used in training and scoring. Take the input from the previous
-- layer, and give the output from this layer.
runForwards :: x -> S i -> (Tape x i o, S o)
-- | Back propagate a step. Takes the current layer, the input that
-- the layer gave from the input and the back propagated derivatives
-- from the layer above.
--
-- Returns the gradient layer and the derivatives to push back
-- further.
runBackwards :: x -> Tape x i o -> S o -> (Gradient x, S i)