@@ -1,5 +1,7 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE GADTs #-}
3{-# LANGUAGE GADTs #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE TypeFamilies #-}
6{-# LANGUAGE TypeFamilies #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
@@ -17,63 +19,24 @@ Neural network we support.
19module Grenade.Core.Network (
21module Grenade.Core.Network (
21− , Network (..)
22+ Network (..)
23− , LearningParameters (..)
24 , Gradients (..)
23 , Gradients (..)
25 , Tapes (..)
24 , Tapes (..)
26 , CreatableNetwork (..)
25 , CreatableNetwork (..)
29−import Control.Monad.Random (MonadRandom)
30+import Control.Monad.Random ( MonadRandom )
30−import Data.List ( foldl' )
31−import Data.Singletons
32+import Data.Singletons
33+import Data.Singletons.Prelude
33import Data.Serialize
34import Data.Serialize
36+import Grenade.Core.Layer
37+import Grenade.Core.LearningParameters
35import Grenade.Core.Shape
38import Grenade.Core.Shape
37−-- | Learning parameters for stochastic gradient descent.
38−data LearningParameters = LearningParameters {
39− learningRate :: Double
40− , learningMomentum :: Double
41− , learningRegulariser :: Double
42− } deriving (Eq, Show)
44−-- | Class for updating a layer. All layers implement this, and it is
46−class UpdateLayer x where
47− {-# MINIMAL runUpdate, createRandom #-}
48− -- | The type for the gradient for this layer.
49− -- Unit if there isn't a gradient to pass back.
51− -- | Update a layer with its gradient and learning parameters
52− runUpdate :: LearningParameters -> x -> Gradient x -> x
54− -- | Create a random layer, many layers will use pure
55− createRandom :: MonadRandom m => m x
57− -- | Update a layer with many Gradients
58− runUpdates :: LearningParameters -> x -> [Gradient x] -> x
59− runUpdates rate = foldl' (runUpdate rate)
61−-- | Class for a layer. All layers implement this, however, they don't
62−-- need to implement it for all shapes, only ones which are appropriate.
63−class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
64− -- | The Wengert tape for this layer. Includes all that is required
65− -- to generate the back propagated gradients efficiently. As a
66− -- default, `S i` is fine.
68− -- | Used in training and scoring. Take the input from the previous
69− -- layer, and give the output from this layer.
70− runForwards :: x -> S i -> (Tape x i o, S o)
71− -- | Back propagate a step. Takes the current layer, the input that the
72− -- layer gave from the input and the back propagated derivatives from
74− -- Returns the gradient layer and the derivatives to push back further.
75− runBackwards :: x -> Tape x i o -> S o -> (Gradient x, S i)
77-- | Type of a network.
40-- | Type of a network.
79-- The [*] type specifies the types of the layers.
42-- The [*] type specifies the types of the layers.
@@ -92,6 +55,16 @@ instance Show (Network '[] '[i]) where
92instance (Show x, Show (Network xs rs)) => Show (Network (x ': xs) (i ': rs)) where
55instance (Show x, Show (Network xs rs)) => Show (Network (x ': xs) (i ': rs)) where
93 show (x :~> xs) = show x ++ "\n~>\n" ++ show xs
56 show (x :~> xs) = show x ++ "\n~>\n" ++ show xs
59+-- | Apply one step of stochastic gradient decent across the network.
60+applyUpdate :: LearningParameters -> Network ls ss -> Gradients ls -> Network ls ss
61+applyUpdate _ NNil GNil
63+applyUpdate rate (layer :~> rest) (gradient :/> grest)
64+ = runUpdate rate layer gradient :~> applyUpdate rate rest grest
95-- | Gradients of a network.
68-- | Gradients of a network.
96-- Parameterised on the layers of a Network.
69-- Parameterised on the layers of a Network.
97data Gradients :: [*] -> * where
70data Gradients :: [*] -> * where
@@ -116,7 +89,6 @@ instance SingI i => CreatableNetwork '[] '[i] where
116instance (SingI i, SingI o, Layer x i o, CreatableNetwork xs (o ': rs)) => CreatableNetwork (x ': xs) (i ': o ': rs) where
89instance (SingI i, SingI o, Layer x i o, CreatableNetwork xs (o ': rs)) => CreatableNetwork (x ': xs) (i ': o ': rs) where
117 randomNetwork = (:~>) <$> createRandom <*> randomNetwork
90 randomNetwork = (:~>) <$> createRandom <*> randomNetwork
120-- | Add very simple serialisation to the network
92-- | Add very simple serialisation to the network
121instance SingI i => Serialize (Network '[] '[i]) where
93instance SingI i => Serialize (Network '[] '[i]) where
122 put NNil = pure ()
94 put NNil = pure ()
@@ -125,3 +97,43 @@ instance SingI i => Serialize (Network '[] '[i]) where
125instance (SingI i, SingI o, Layer x i o, Serialize x, Serialize (Network xs (o ': rs))) => Serialize (Network (x ': xs) (i ': o ': rs)) where
97instance (SingI i, SingI o, Layer x i o, Serialize x, Serialize (Network xs (o ': rs))) => Serialize (Network (x ': xs) (i ': o ': rs)) where
126 put (x :~> r) = put x >> put r
98 put (x :~> r) = put x >> put r
127 get = (:~>) <$> get <*> get
99 get = (:~>) <$> get <*> get
102+-- | Ultimate composition.
104+-- This allows a complete network to be treated as a layer in a bigger network.
105+instance CreatableNetwork sublayers subshapes => UpdateLayer (Network sublayers subshapes) where
106+ type Gradient (Network sublayers subshapes) = Gradients sublayers
107+ runUpdate = applyUpdate
108+ createRandom = randomNetwork
110+instance (CreatableNetwork sublayers subshapes, i ~ (Head subshapes), o ~ (Last subshapes)) => Layer (Network sublayers subshapes) i o where
111+ type Tape (Network sublayers subshapes) i o = Tapes sublayers subshapes
116+ go :: forall js ss. (Last js ~ Last subshapes)
117+ => S (Head js) -- ^ input vector
118+ -> Network ss js -- ^ network to train
119+ -> (Tapes ss js, S (Last js))
120+ go !x (layer :~> n) =
121+ let (tape, forward) = runForwards layer x
122+ (tapes, answer) = go forward n
123+ in (tape :\> tapes, answer)
127+ runBackwards net tapes o =
130+ go :: forall js ss. (Last js ~ Last subshapes)
131+ => Network ss js -- ^ network to train
132+ -> Tapes ss js -- ^ network to train
133+ -> (Gradients ss, S (Head js))
134+ go (layer :~> n) (tape :\> nt) =
135+ let (gradients, feed) = go n nt
136+ (layer', backGrad) = runBackwards layer tape feed
137+ in (layer' :/> gradients, backGrad)