on master help sign in
Separate Gradient calculation from update
commit114dab4103cba69632303dc322f4632708e6ead0 authorHuw Campbell <huw.campbell@ambiata.com> dateFri 2 Dec 2016, 18:22 (10 years ago) parentcef1b14
17 files changed+193−114
grenade.cabal+1 main/feedforward.hs+11−7 main/mnist.hs+10−6 src/Grenade.hs−13 src/Grenade/Core/Network.hs+26−10 src/Grenade/Core/Runner.hs+13−9 src/Grenade/Layers/Convolution.hs+39−11 src/Grenade/Layers/Crop.hs+6−4 src/Grenade/Layers/Dropout.hs+7−7 src/Grenade/Layers/Flatten.hs+8−4 src/Grenade/Layers/FullyConnected.hs+21−11 src/Grenade/Layers/Fuse.hs+15−9 src/Grenade/Layers/Logit.hs+8−5 src/Grenade/Layers/Pad.hs+6−4 src/Grenade/Layers/Pooling.hs+8−4 src/Grenade/Layers/Relu.hs+7−5 src/Grenade/Layers/Tanh.hs+7−5
grenade.cabal+1
@@ -14,6 +14,7 @@ library
1414 build-depends:
1515 base >= 4.8 && < 5
1616 , bytestring == 0.10.*
17+ , async
1718 , either == 4.4.*
1819 , exceptions == 0.8.*
1920 , hmatrix
main/feedforward.hs+11−7
@@ -35,14 +35,13 @@ randomNet = do
3535 c :: FullyConnected 10 1 <- randomFullyConnected
3636 return $ a :~> Tanh :~> b :~> Relu :~> c :~> O Logit
3737
38−netTest :: MonadRandom m => Double -> Int -> m String
38+netTest :: MonadRandom m => LearningParameters -> Int -> m String
3939netTest rate n = do
4040 inps <- replicateM n $ do
41− s <- getRandom
41+ s <- getRandom
4242 return $ S1D' $ SA.randomVector s SA.Uniform * 2 - 1
4343 let outs = flip map inps $ \(S1D' v) ->
44− if v `inCircle` (fromRational 0.33, 0.33)
45− || v `inCircle` (fromRational (-0.33), 0.33)
44+ if v `inCircle` (fromRational 0.33, 0.33) || v `inCircle` (fromRational (-0.33), 0.33)
4645 then S1D' $ fromRational 1
4746 else S1D' $ fromRational 0
4847 net0 <- randomNet
@@ -70,11 +69,16 @@ netTest rate n = do
7069 normx (S1D' r) = SA.mean r
7170
7271
73−data FeedForwardOpts = FeedForwardOpts Int Double
72+data FeedForwardOpts = FeedForwardOpts Int LearningParameters
7473
7574feedForward' :: Parser FeedForwardOpts
76−feedForward' = FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 1000000)
77− <*> option auto (long "train_rate" <> short 'r' <> value 0.01)
75+feedForward' =
76+ FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 1000000)
77+ <*> (LearningParameters
78+ <$> option auto (long "train_rate" <> short 'r' <> value 0.01)
79+ <*> option auto (long "momentum" <> value 0.9)
80+ <*> option auto (long "l2" <> value 0.0001)
81+ )
7882
7983main :: IO ()
8084main = do
main/mnist.hs+10−6
@@ -43,7 +43,7 @@ randomMnistNet = do
4343 f :: FullyConnected 80 10 <- randomFullyConnected
4444 return $ pad :~> a :~> b :~> Relu :~> c :~> d :~> FlattenLayer :~> Relu :~> e :~> Logit :~> f :~> O Logit
4545
46−convTest :: Int -> FilePath -> FilePath -> Double -> IO ()
46+convTest :: Int -> FilePath -> FilePath -> LearningParameters -> IO ()
4747convTest iterations trainFile validateFile rate = do
4848 net0 <- evalRandIO randomMnistNet
4949 fT <- T.readFile trainFile
@@ -52,7 +52,7 @@ convTest iterations trainFile validateFile rate = do
5252 let validateRows = traverse (A.parseOnly p) (T.lines fV)
5353 case (trainRows, validateRows) of
5454 (Right tr', Right vr') -> foldM_ (runIteration tr' vr') net0 [1..iterations]
55− err -> putStrLn $ show err
55+ err -> print err
5656
5757 where
5858 trainEach !rate' !nt !(i, o) = train rate' i o nt
@@ -65,20 +65,24 @@ convTest iterations trainFile validateFile rate = do
6565 return (S2D' $ SA.fromList pixels, S1D' $ SA.fromList lab')
6666
6767 runIteration trainRows validateRows net i = do
68− let trained' = runIdentity $ foldM (trainEach (rate * (0.9 ^ i))) net trainRows
68+ let trained' = runIdentity $ foldM (trainEach rate) net trainRows
6969 let res = runIdentity $ traverse (\(rowP,rowL) -> (rowL,) <$> runNet trained' rowP) validateRows
7070 let res' = fmap (\(S1D' label, S1D' prediction) -> (maxIndex (SA.extract label), maxIndex (SA.extract prediction))) res
71− putStrLn $ show trained'
71+ print trained'
7272 putStrLn $ "Iteration " ++ show i ++ ": " ++ show (length (filter ((==) <$> fst <*> snd) res')) ++ " of " ++ show (length res')
7373 return trained'
7474
75−data MnistOpts = MnistOpts FilePath FilePath Int Double
75+data MnistOpts = MnistOpts FilePath FilePath Int LearningParameters
7676
7777mnist' :: Parser MnistOpts
7878mnist' = MnistOpts <$> (argument str (metavar "TRAIN"))
7979 <*> (argument str (metavar "VALIDATE"))
8080 <*> option auto (long "iterations" <> short 'i' <> value 15)
81− <*> option auto (long "train_rate" <> short 'r' <> value 0.01)
81+ <*> (LearningParameters
82+ <$> option auto (long "train_rate" <> short 'r' <> value 0.01)
83+ <*> option auto (long "momentum" <> value 0.9)
84+ <*> option auto (long "l2" <> value 0.0001)
85+ )
8286
8387main :: IO ()
8488main = do
src/Grenade.hs−13
@@ -1,16 +1,3 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE GADTs #-}
4−{-# LANGUAGE KindSignatures #-}
5−{-# LANGUAGE ScopedTypeVariables #-}
6−{-# LANGUAGE StandaloneDeriving #-}
7−{-# LANGUAGE TypeOperators #-}
8−{-# LANGUAGE TypeFamilies #-}
9−{-# LANGUAGE PolyKinds #-}
10−{-# LANGUAGE MultiParamTypeClasses #-}
11−{-# LANGUAGE FlexibleContexts #-}
12−{-# LANGUAGE FlexibleInstances #-}
13−
141module Grenade (
152 module X
163 ) where
src/Grenade/Core/Network.hs+26−10
@@ -1,9 +1,7 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE DataKinds #-}
32{-# LANGUAGE GADTs #-}
43{-# LANGUAGE KindSignatures #-}
54{-# LANGUAGE ScopedTypeVariables #-}
6−{-# LANGUAGE StandaloneDeriving #-}
75{-# LANGUAGE TypeOperators #-}
86{-# LANGUAGE TypeFamilies #-}
97{-# LANGUAGE PolyKinds #-}
@@ -14,31 +12,49 @@
1412module Grenade.Core.Network (
1513 Layer (..)
1614 , Network (..)
15+ , UpdateLayer (..)
16+ , LearningParameters (..)
1717 ) where
1818
19+import Data.Typeable
1920import Grenade.Core.Shape
2021
22+data LearningParameters = LearningParameters {
23+ learningRate :: Double
24+ , learningMomentum :: Double
25+ , learningRegulariser :: Double
26+ } deriving (Eq, Show)
27+
28+-- | Class for updating a layer. All layers implement this, and it is
29+-- shape independent.
30+class UpdateLayer (m :: * -> *) x where
31+ -- | The type for the gradient for this layer.
32+ -- Unit if there isn't a gradient to pass back.
33+ type Gradient x :: *
34+ -- | Update a layer with its gradient and learning parameters
35+ runUpdate :: LearningParameters -> x -> Gradient x -> m x
36+
2137-- | Class for a layer. All layers implement this, however, they don't
2238-- need to implement it for all shapes, only ones which are appropriate.
23−class Layer (m :: * -> *) x (i :: Shape) (o :: Shape) where
39+class UpdateLayer m x => Layer (m :: * -> *) x (i :: Shape) (o :: Shape) where
2440 -- | Used in training and scoring. Take the input from the previous
2541 -- layer, and give the output from this layer.
2642 runForwards :: x -> S' i -> m (S' o)
27− -- | Back propagate a step. Takes a learning rate (move from here?)
28− -- the current layer, the input that the layer gave from the input
29− -- and the back propagated derivatives from the layer above.
30− -- Returns the updated layer and the derivatives to push back further.
31− runBackards :: Double -> x -> S' i -> S' o -> m (x, S' i)
43+ -- | Back propagate a step. Takes the current layer, the input that the
44+ -- layer gave from the input and the back propagated derivatives from
45+ -- the layer above.
46+ -- Returns the gradient layer and the derivatives to push back further.
47+ runBackards :: x -> S' i -> S' o -> m (Gradient x, S' i)
3248
3349-- | Type of a network.
3450-- The [Shape] type specifies the shapes of data passed between the layers.
3551-- Could be considered to be a heterogeneous list of layers which are able to
3652-- transform the data shapes of the network.
3753data Network :: (* -> *) -> [Shape] -> * where
38− O :: (Show x, Layer m x i o, KnownShape o, KnownShape i)
54+ O :: (Typeable x, Show x, Layer m x i o, KnownShape o, KnownShape i)
3955 => !x
4056 -> Network m '[i, o]
41− (:~>) :: (Show x, Layer m x i h, KnownShape h, KnownShape i)
57+ (:~>) :: (Typeable x, Show x, Layer m x i h, KnownShape h, KnownShape i)
4258 => !x
4359 -> !(Network m (h ': hs))
4460 -> Network m (i ': h ': hs)
src/Grenade/Core/Runner.hs+13−9
@@ -1,9 +1,7 @@
11{-# LANGUAGE BangPatterns #-}
22{-# LANGUAGE GADTs #-}
33{-# LANGUAGE DataKinds #-}
4−{-# LANGUAGE KindSignatures #-}
54{-# LANGUAGE ScopedTypeVariables #-}
6−{-# LANGUAGE StandaloneDeriving #-}
75{-# LANGUAGE TypeOperators #-}
86{-# LANGUAGE TypeFamilies #-}
97
@@ -18,7 +16,7 @@ import Grenade.Core.Shape
1816
1917-- | Update a network with new weights after training with an instance.
2018train :: forall m i o hs. (Monad m, Head hs ~ i, Last hs ~ o, KnownShape i, KnownShape o)
21− => Double -- ^ learning rate
19+ => LearningParameters -- ^ learning rate
2220 -> S' i -- ^ input vector
2321 -> S' o -- ^ target vector
2422 -> Network m hs -- ^ network to train
@@ -35,20 +33,26 @@ train rate x0 target = fmap fst . go x0
3533 -- run the rest of the network, and get the layer from above.
3634 (n', dWs') <- go y n
3735 -- calculate the gradient for this layer to pass down,
38− (layer', dWs) <- runBackards rate layer x dWs'
39− return (layer' :~> n', dWs)
36+ (layer', dWs) <- runBackards layer x dWs'
37+
38+ -- Update this layer using the gradient
39+ newLayer <- runUpdate rate layer layer'
40+
41+ return (newLayer :~> n', dWs)
4042
4143 -- handle the output layer, bouncing the derivatives back down.
4244 go !x (O layer)
43− = do y <- runForwards layer x
45+ = do y <- runForwards layer x
4446 -- the gradient (how much y affects the error)
45− (layer', dWs) <- runBackards rate layer x (y - target)
46− return (O layer', dWs)
47+ (layer', dWs) <- runBackards layer x (y - target)
48+ newLayer <- runUpdate rate layer layer'
49+
50+ return (O newLayer, dWs)
4751
4852-- | Just forwards propagation with no training.
4953runNet :: forall m hs. (Monad m)
5054 => Network m hs
51− -> (S' (Head hs)) -- ^ input vector
55+ -> S' (Head hs) -- ^ input vector
5256 -> m (S' (Last hs)) -- ^ target vector
5357runNet (layer :~> n) !x = do y <- runForwards layer x
5458 runNet n y
src/Grenade/Layers/Convolution.hs+39−11
@@ -2,6 +2,7 @@
22{-# LANGUAGE DataKinds #-}
33{-# LANGUAGE ScopedTypeVariables #-}
44{-# LANGUAGE StandaloneDeriving #-}
5+{-# LANGUAGE RecordWildCards #-}
56{-# LANGUAGE GADTs #-}
67{-# LANGUAGE TypeOperators #-}
78{-# LANGUAGE TypeFamilies #-}
@@ -65,6 +66,24 @@ data Convolution :: Nat -- ^ Number of channels, for the first layer this could
6566 -> !(L kernelFlattened filters) -- ^ The last kernel update (or momentum)
6667 -> Convolution channels filters kernelRows kernelColumns strideRows strideColumns
6768
69+data Convolution' :: Nat -- ^ Number of channels, for the first layer this could be RGB for instance.
70+ -> Nat -- ^ Number of filters, this is the number of channels output by the layer.
71+ -> Nat -- ^ The number of rows in the kernel filter
72+ -> Nat -- ^ The number of column in the kernel filter
73+ -> Nat -- ^ The row stride of the convolution filter
74+ -> Nat -- ^ The columns stride of the convolution filter
75+ -> * where
76+ Convolution' :: ( KnownNat channels
77+ , KnownNat filters
78+ , KnownNat kernelRows
79+ , KnownNat kernelColumns
80+ , KnownNat strideRows
81+ , KnownNat strideColumns
82+ , KnownNat kernelFlattened
83+ , kernelFlattened ~ (kernelRows * kernelColumns * channels))
84+ => !(L kernelFlattened filters) -- ^ The kernel filter gradient
85+ -> Convolution' channels filters kernelRows kernelColumns strideRows strideColumns
86+
6887instance Show (Convolution c f k k' s s') where
6988 show (Convolution a _) = renderConv a
7089 where
@@ -99,6 +118,22 @@ randomConvolution = do
99118 mm = konst 0
100119 return $ Convolution wN mm
101120
121+instance ( Monad m
122+ , KnownNat kernelRows
123+ , KnownNat kernelCols
124+ , KnownNat channels
125+ , KnownNat filters
126+ , KnownNat strideRows
127+ , KnownNat strideCols
128+ , kernelFlattened ~ (kernelRows * kernelColumns * channels)
129+ ) => UpdateLayer m (Convolution channels filters kernelRows kernelCols strideRows strideCols) where
130+ type Gradient (Convolution channels filters kernelRows kernelCols strideRows strideCols) = (Convolution' channels filters kernelRows kernelCols strideRows strideCols)
131+ runUpdate LearningParameters {..} (Convolution oldKernel oldMomentum) (Convolution' kernelGradient) = do
132+ let newMomentum = konst learningMomentum * oldMomentum - konst learningRate * kernelGradient
133+ regulariser = konst (learningRegulariser * learningRate) * oldKernel
134+ newKernel = oldKernel + newMomentum - regulariser
135+ return $ Convolution newKernel newMomentum
136+
102137-- | A two dimentional image may have a convolution filter applied to it
103138instance ( Monad m
104139 , KnownNat kernelRows
@@ -127,7 +162,7 @@ instance ( Monad m
127162 r = col2vid 1 1 1 1 ox oy mt
128163 rs = fmap (fromJust . create) r
129164 in return . S3D' $ mkVector rs
130− runBackards rate (Convolution kernel momentum) (S2D' input) (S3D' dEdy) =
165+ runBackards (Convolution kernel _) (S2D' input) (S3D' dEdy) =
131166 let ex = extract input
132167 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
133168 iy = fromIntegral $ natVal (Proxy :: Proxy inputCols)
@@ -145,14 +180,10 @@ instance ( Monad m
145180 vs = vid2col 1 1 1 1 ox oy eo
146181
147182 kN = fromJust . create $ tr c LA.<> vs
148− mm = momentum * 0.9 - konst rate * kN
149− wd = konst (0.0001 * rate) * kernel
150− rM = kernel + mm - wd
151−
152183 dW = vs LA.<> tr ek
153184
154185 xW = col2im kx ky sx sy ix iy dW
155− in return (Convolution rM mm, S2D' . fromJust . create $ xW)
186+ in return (Convolution' kN, S2D' . fromJust . create $ xW)
156187
157188
158189-- | A three dimensional image (or 2d with many channels) can have
@@ -187,7 +218,7 @@ instance ( Monad m
187218 r = col2vid 1 1 1 1 ox oy mt
188219 rs = fmap (fromJust . create) r
189220 in return . S3D' $ mkVector rs
190− runBackards rate (Convolution kernel momentum) (S3D' input) (S3D' dEdy) =
221+ runBackards (Convolution kernel _) (S3D' input) (S3D' dEdy) =
191222 let ex = vecToList $ fmap extract input
192223 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
193224 iy = fromIntegral $ natVal (Proxy :: Proxy inputCols)
@@ -205,14 +236,11 @@ instance ( Monad m
205236 vs = vid2col 1 1 1 1 ox oy eo
206237
207238 kN = fromJust . create $ tr c LA.<> vs
208− mm = momentum * 0.9 - konst rate * kN
209− wd = konst (0.0005 * rate) * kernel
210− rM = kernel + mm - wd
211239
212240 dW = vs LA.<> tr ek
213241
214242 xW = col2vid kx ky sx sy ix iy dW
215− in return (Convolution rM mm, S3D' . mkVector . fmap (fromJust . create) $ xW)
243+ in return (Convolution' kN, S3D' . mkVector . fmap (fromJust . create) $ xW)
216244
217245im2col :: Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
218246im2col nrows ncols srows scols m =
src/Grenade/Layers/Crop.hs+6−4
@@ -1,7 +1,5 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE DataKinds #-}
32{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE StandaloneDeriving #-}
53{-# LANGUAGE GADTs #-}
64{-# LANGUAGE TypeOperators #-}
75{-# LANGUAGE TypeFamilies #-}
@@ -39,6 +37,10 @@ data Crop :: Nat
3937instance Show (Crop cropLeft cropTop cropRight cropBottom) where
4038 show Crop = "Crop"
4139
40+instance Monad m => UpdateLayer m (Crop l t r b) where
41+ type Gradient (Crop l t r b) = ()
42+ runUpdate _ x _ = return x
43+
4244-- | A two dimentional image can be cropped.
4345instance ( Monad m
4446 , KnownNat cropLeft
@@ -60,11 +62,11 @@ instance ( Monad m
6062 m = extract input
6163 r = subMatrix (cropt, cropl) (nrows, ncols) m
6264 in return . S2D' . fromJust . create $ r
63− runBackards _ crop _ (S2D' dEdy) =
65+ runBackards _ _ (S2D' dEdy) =
6466 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
6567 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
6668 cropr = fromIntegral $ natVal (Proxy :: Proxy cropRight)
6769 cropb = fromIntegral $ natVal (Proxy :: Proxy cropBottom)
6870 eo = extract dEdy
6971 vs = diagBlock [konst 0 (cropt,cropl), eo, konst 0 (cropb,cropr)]
70− in return (crop, S2D' . fromJust . create $ vs)
72+ in return ((), S2D' . fromJust . create $ vs)
src/Grenade/Layers/Dropout.hs+7−7
@@ -1,7 +1,5 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE DataKinds #-}
32{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE StandaloneDeriving #-}
53{-# LANGUAGE TypeOperators #-}
64{-# LANGUAGE TypeFamilies #-}
75{-# LANGUAGE MultiParamTypeClasses #-}
@@ -32,6 +30,10 @@ import Numeric.LinearAlgebra.Static
3230data Dropout o = Dropout Double (R o)
3331 deriving Show
3432
33+instance (MonadRandom m, KnownNat i) => UpdateLayer m (Dropout i) where
34+ type Gradient (Dropout i) = ()
35+ runUpdate _ (Dropout rate _) _ = randomDropout rate
36+
3537randomDropout :: (MonadRandom m, KnownNat i)
3638 => Double -> m (Dropout i)
3739randomDropout rate = do
@@ -44,8 +46,6 @@ instance (MonadRandom m, MonadState Phase m, KnownNat i) => Layer m (Dropout i)
4446 runForwards (Dropout rate drops) (S1D' x) = isTrainingPhase >>= \case
4547 True -> return . S1D' $ x * drops
4648 False -> return . S1D' $ dvmap (* (1 - rate)) x
47− runBackards _ oldDropout@(Dropout rate drops) _ (S1D' x) = isTrainingPhase >>= \case
48− True -> do
49− newDropout <- randomDropout rate
50− return (newDropout, S1D' $ x * drops)
51− False -> return (oldDropout, S1D' $ dvmap (* (1 - rate)) x)
49+ runBackards (Dropout rate drops) _ (S1D' x) = isTrainingPhase >>= \case
50+ True -> return ((), S1D' $ x * drops)
51+ False -> return ((), S1D' $ dvmap (* (1 - rate)) x)
src/Grenade/Layers/Flatten.hs+8−4
@@ -25,20 +25,24 @@ import Grenade.Core.Network
2525data FlattenLayer = FlattenLayer
2626 deriving Show
2727
28+instance Monad m => UpdateLayer m FlattenLayer where
29+ type Gradient FlattenLayer = ()
30+ runUpdate _ _ _ = return FlattenLayer
31+
2832instance (Monad m, KnownNat a, KnownNat x, KnownNat y, a ~ (x * y)) => Layer m FlattenLayer ('D2 x y) ('D1 a) where
29− runForwards _ (S2D' y) = return $ S1D' . fromList . toList . flatten . extract $ y
30− runBackards _ _ _ (S1D' y) = return (FlattenLayer, S2D' . fromList . toList . unwrap $ y)
33+ runForwards _ (S2D' y) = return $ S1D' . fromList . toList . flatten . extract $ y
34+ runBackards _ _ (S1D' y) = return ((), S2D' . fromList . toList . unwrap $ y)
3135
3236instance (Monad m, KnownNat a, KnownNat x, KnownNat y, KnownNat z, a ~ (x * y * z)) => Layer m FlattenLayer ('D3 x y z) ('D1 a) where
3337 runForwards _ (S3D' y) = return $ S1D' . raiseShapeError . create . vjoin . vecToList . fmap (flatten . extract) $ y
34− runBackards _ _ _ (S1D' o) = do
38+ runBackards _ _ (S1D' o) = do
3539 let x' = fromIntegral $ natVal (Proxy :: Proxy x)
3640 y' = fromIntegral $ natVal (Proxy :: Proxy y)
3741 z' = fromIntegral $ natVal (Proxy :: Proxy z)
3842 vecs = takesV (replicate z' (x' * y')) (extract o)
3943 ls = fmap (raiseShapeError . create . reshape y') vecs
4044 ls' = mkVector ls :: Vector z (L x y)
41− return (FlattenLayer, S3D' ls')
45+ return ((), S3D' ls')
4246
4347raiseShapeError :: Maybe a -> a
4448raiseShapeError (Just x) = x
src/Grenade/Layers/FullyConnected.hs+21−11
@@ -1,7 +1,6 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE DataKinds #-}
32{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE StandaloneDeriving #-}
3+{-# LANGUAGE RecordWildCards #-}
54{-# LANGUAGE TypeOperators #-}
65{-# LANGUAGE TypeFamilies #-}
76{-# LANGUAGE MultiParamTypeClasses #-}
@@ -25,25 +24,36 @@ import Grenade.Core.Shape
2524data FullyConnected i o = FullyConnected
2625 !(R o) -- Bias neuron weights
2726 !(L o i) -- Activation weights
28− !(L o i) -- Activation momentums
27+ !(L o i) -- Momentum
28+
29+data FullyConnected' i o = FullyConnected'
30+ !(R o) -- Bias neuron gradient
31+ !(L o i) -- Activation gradient
2932
3033instance Show (FullyConnected i o) where
31− show (FullyConnected _ _ _) = "FullyConnected"
34+ show FullyConnected {} = "FullyConnected"
35+
36+instance (Monad m, KnownNat i, KnownNat o) => UpdateLayer m (FullyConnected i o) where
37+ type Gradient (FullyConnected i o) = (FullyConnected' i o)
38+
39+ runUpdate LearningParameters {..} (FullyConnected oldBias oldActivations oldMomentum) (FullyConnected' biasGradient activationGradient) = do
40+ let newBias = oldBias - konst learningRate * biasGradient
41+ newMomentum = konst learningMomentum * oldMomentum - konst learningRate * activationGradient
42+ regulariser = konst (learningRegulariser * learningRate) * oldActivations
43+ newActivations = oldActivations + newMomentum - regulariser
44+ return $ FullyConnected newBias newActivations newMomentum
3245
3346instance (Monad m, KnownNat i, KnownNat o) => Layer m (FullyConnected i o) ('D1 i) ('D1 o) where
3447 -- Do a matrix vector multiplication and return the result.
3548 runForwards (FullyConnected wB wN _) (S1D' v) = return $ S1D' (wB + wN #> v)
3649
3750 -- Run a backpropogation step for a full connected layer.
38− runBackards rate (FullyConnected wB wN mm) (S1D' x) (S1D' dEdy) =
39− let wB' = wB - konst rate * dEdy
40− mm' = 0.9 * mm - konst rate * (dEdy `outer` x)
41− wd' = konst (0.0001 * rate) * wN
42− wN' = wN + mm' - wd'
43− w' = FullyConnected wB' wN' mm'
51+ runBackards (FullyConnected _ wN _) (S1D' x) (S1D' dEdy) =
52+ let wB' = dEdy
53+ mm' = dEdy `outer` x
4454 -- calcluate derivatives for next step
4555 dWs = tr wN #> dEdy
46− in return (w', S1D' dWs)
56+ in return (FullyConnected' wB' mm', S1D' dWs)
4757
4858randomFullyConnected :: (MonadRandom m, KnownNat i, KnownNat o)
4959 => m (FullyConnected i o)
src/Grenade/Layers/Fuse.hs+15−9
@@ -3,7 +3,6 @@
33{-# LANGUAGE GADTs #-}
44{-# LANGUAGE KindSignatures #-}
55{-# LANGUAGE ScopedTypeVariables #-}
6−{-# LANGUAGE StandaloneDeriving #-}
76{-# LANGUAGE TypeOperators #-}
87{-# LANGUAGE TypeFamilies #-}
98{-# LANGUAGE PolyKinds #-}
@@ -23,23 +22,30 @@ import Grenade.Core.Shape
2322-- This can be used to simplify a network if a complicated repeated structure is used.
2423-- This does however have a trade off, internal incremental states in the Wengert tape are
2524-- not retained during reverse accumulation. So less RAM is used, but more compute is required.
26−data Fuse :: (* -> *) -> Shape -> Shape -> Shape -> * where
25+data Fuse :: (* -> *) -> * -> * -> Shape -> Shape -> Shape -> * where
2726 (:$$) :: (Show x, Show y, Layer m x i h, Layer m y h o, KnownShape h, KnownShape i, KnownShape o)
2827 => !x
2928 -> !y
30− -> Fuse m i h o
29+ -> Fuse m x y i h o
3130infixr 5 :$$
3231
33−instance Show (Fuse m i h o) where
32+instance Show (Fuse m x y i h o) where
3433 show (x :$$ y) = "(" ++ show x ++ " :$$ " ++ show y ++ ")"
3534
36−instance (Monad m, KnownShape i, KnownShape h, KnownShape o) => Layer m (Fuse m i h o) i o where
35+instance (Monad m, KnownShape i, KnownShape h, KnownShape o) => UpdateLayer m (Fuse m x y i h o) where
36+ type Gradient (Fuse m x y i h o) = (Gradient x, Gradient y)
37+ runUpdate lr (x :$$ y) (x', y') = do
38+ newX <- runUpdate lr x x'
39+ newY <- runUpdate lr y y'
40+ return (newX :$$ newY)
41+
42+instance (Monad m, KnownShape i, KnownShape h, KnownShape o) => Layer m (Fuse m x y i h o) i o where
3743 runForwards (x :$$ y) input = do
3844 yInput :: S' h <- runForwards x input
3945 runForwards y yInput
4046
41− runBackards rate (x :$$ y) input backGradient = do
47+ runBackards (x :$$ y) input backGradient = do
4248 yInput :: S' h <- runForwards x input
43− (y', yGrad) <- runBackards rate y yInput backGradient
44− (x', xGrad) <- runBackards rate x input yGrad
45− return (x' :$$ y', xGrad)
49+ (y', yGrad) <- runBackards y yInput backGradient
50+ (x', xGrad) <- runBackards x input yGrad
51+ return ((x', y'), xGrad)
src/Grenade/Layers/Logit.hs+8−5
@@ -1,7 +1,5 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE DataKinds #-}
32{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE StandaloneDeriving #-}
53{-# LANGUAGE TypeOperators #-}
64{-# LANGUAGE TypeFamilies #-}
75{-# LANGUAGE MultiParamTypeClasses #-}
@@ -11,6 +9,7 @@ module Grenade.Layers.Logit (
119 Logit (..)
1210 ) where
1311
12+
1413import Data.Singletons.TypeLits
1514import Grenade.Core.Network
1615import Grenade.Core.Vector
@@ -23,17 +22,21 @@ import Grenade.Core.Shape
2322data Logit = Logit
2423 deriving Show
2524
25+instance Monad m => UpdateLayer m Logit where
26+ type Gradient Logit = ()
27+ runUpdate _ _ _ = return Logit
28+
2629instance (Monad m, KnownNat i) => Layer m Logit ('D1 i) ('D1 i) where
2730 runForwards _ (S1D' y) = return $ S1D' (logistic y)
28− runBackards _ _ (S1D' y) (S1D' dEdy) = return (Logit, S1D' (logistic' y * dEdy))
31+ runBackards _ (S1D' y) (S1D' dEdy) = return ((), S1D' (logistic' y * dEdy))
2932
3033instance (Monad m, KnownNat i, KnownNat j) => Layer m Logit ('D2 i j) ('D2 i j) where
3134 runForwards _ (S2D' y) = return $ S2D' (logistic y)
32− runBackards _ _ (S2D' y) (S2D' dEdy) = return (Logit, S2D' (logistic' y * dEdy))
35+ runBackards _ (S2D' y) (S2D' dEdy) = return ((), S2D' (logistic' y * dEdy))
3336
3437instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Logit ('D3 i j k) ('D3 i j k) where
3538 runForwards _ (S3D' y) = return $ S3D' (fmap logistic y)
36− runBackards _ _ (S3D' y) (S3D' dEdy) = return (Logit, S3D' (vectorZip (\y' dEdy' -> logistic' y' * dEdy') y dEdy))
39+ runBackards _ (S3D' y) (S3D' dEdy) = return ((), S3D' (vectorZip (\y' dEdy' -> logistic' y' * dEdy') y dEdy))
3740
3841
3942logistic :: Floating a => a -> a
src/Grenade/Layers/Pad.hs+6−4
@@ -1,7 +1,5 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE DataKinds #-}
32{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE StandaloneDeriving #-}
53{-# LANGUAGE GADTs #-}
64{-# LANGUAGE TypeOperators #-}
75{-# LANGUAGE TypeFamilies #-}
@@ -39,6 +37,10 @@ data Pad :: Nat
3937instance Show (Pad padLeft padTop padRight padBottom) where
4038 show Pad = "Pad"
4139
40+instance Monad m => UpdateLayer m (Pad l t r b) where
41+ type Gradient (Pad l t r b) = ()
42+ runUpdate _ x _ = return x
43+
4244-- | A two dimentional image can be padped.
4345instance ( Monad m
4446 , KnownNat padLeft
@@ -60,11 +62,11 @@ instance ( Monad m
6062 m = extract input
6163 r = diagBlock [konst 0 (padt,padl), m, konst 0 (padb,padr)]
6264 in return . S2D' . fromJust . create $ r
63− runBackards _ pad _ (S2D' dEdy) =
65+ runBackards Pad _ (S2D' dEdy) =
6466 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
6567 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
6668 nrows = fromIntegral $ natVal (Proxy :: Proxy inputRows)
6769 ncols = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
6870 m = extract dEdy
6971 vs = subMatrix (padt, padl) (nrows, ncols) m
70− in return (pad, S2D' . fromJust . create $ vs)
72+ in return ((), S2D' . fromJust . create $ vs)
src/Grenade/Layers/Pooling.hs+8−4
@@ -51,6 +51,10 @@ instance Show (Pooling k k' s s') where
5151 show Pooling = "Pooling"
5252
5353
54+instance Monad m => UpdateLayer m (Pooling kernelRows kernelColumns strideRows strideColumns) where
55+ type Gradient (Pooling kr kc sr sc) = ()
56+ runUpdate _ Pooling _ = return Pooling
57+
5458-- | A two dimentional image can be pooled.
5559instance ( Monad m
5660 , KnownNat kernelRows
@@ -75,7 +79,7 @@ instance ( Monad m
7579 r = poolForward kx ky sx sy ox oy $ ex
7680 rs = fromJust . create $ r
7781 in return . S2D' $ rs
78− runBackards _ Pooling (S2D' input) (S2D' dEdy) =
82+ runBackards Pooling (S2D' input) (S2D' dEdy) =
7983 let kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
8084 ky = fromIntegral $ natVal (Proxy :: Proxy kernelColumns)
8185 sx = fromIntegral $ natVal (Proxy :: Proxy strideRows)
@@ -83,7 +87,7 @@ instance ( Monad m
8387 ex = extract input
8488 eo = extract dEdy
8589 vs = poolBackward kx ky sx sy ex eo
86− in return (Pooling, S2D' . fromJust . create $ vs)
90+ in return ((), S2D' . fromJust . create $ vs)
8791
8892
8993-- | A three dimensional image can be pooled on each layer.
@@ -112,7 +116,7 @@ instance ( Monad m
112116 r = poolForwardList kx ky sx sy ix iy ox oy ex
113117 rs = fmap (fromJust . create) r
114118 in return . S3D' $ rs
115− runBackards _ Pooling (S3D' input) (S3D' dEdy) =
119+ runBackards Pooling (S3D' input) (S3D' dEdy) =
116120 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
117121 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
118122 kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
@@ -123,7 +127,7 @@ instance ( Monad m
123127 eo = fmap extract dEdy
124128 ez = vectorZip (,) ex eo
125129 vs = poolBackwardList kx ky sx sy ix iy ez
126− in return (Pooling, S3D' . fmap (fromJust . create) $ vs)
130+ in return ((), S3D' . fmap (fromJust . create) $ vs)
127131
128132poolForward :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
129133poolForward nrows ncols srows scols outputRows outputCols m =
src/Grenade/Layers/Relu.hs+7−5
@@ -1,7 +1,5 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE DataKinds #-}
32{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE StandaloneDeriving #-}
53{-# LANGUAGE TypeOperators #-}
64{-# LANGUAGE TypeFamilies #-}
75{-# LANGUAGE MultiParamTypeClasses #-}
@@ -24,11 +22,15 @@ import qualified Numeric.LinearAlgebra.Static as LAS
2422data Relu = Relu
2523 deriving Show
2624
25+instance Monad m => UpdateLayer m Relu where
26+ type Gradient Relu = ()
27+ runUpdate _ _ _ = return Relu
28+
2729instance (Monad m, KnownNat i) => Layer m Relu ('D1 i) ('D1 i) where
2830 runForwards _ (S1D' y) = return $ S1D' (relu y)
2931 where
3032 relu = LAS.dvmap (\a -> if a <= 0 then 0 else a)
31− runBackards _ _ (S1D' y) (S1D' dEdy) = return (Relu, S1D' (relu' y * dEdy))
33+ runBackards _ (S1D' y) (S1D' dEdy) = return ((), S1D' (relu' y * dEdy))
3234 where
3335 relu' = LAS.dvmap (\a -> if a <= 0 then 0 else 1)
3436
@@ -36,7 +38,7 @@ instance (Monad m, KnownNat i, KnownNat j) => Layer m Relu ('D2 i j) ('D2 i j) w
3638 runForwards _ (S2D' y) = return $ S2D' (relu y)
3739 where
3840 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
39− runBackards _ _ (S2D' y) (S2D' dEdy) = return (Relu, S2D' (relu' y * dEdy))
41+ runBackards _ (S2D' y) (S2D' dEdy) = return ((), S2D' (relu' y * dEdy))
4042 where
4143 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
4244
@@ -44,6 +46,6 @@ instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Relu ('D3 i j
4446 runForwards _ (S3D' y) = return $ S3D' (fmap relu y)
4547 where
4648 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
47− runBackards _ _ (S3D' y) (S3D' dEdy) = return (Relu, S3D' (vectorZip (\y' dEdy' -> relu' y' * dEdy') y dEdy))
49+ runBackards _ (S3D' y) (S3D' dEdy) = return ((), S3D' (vectorZip (\y' dEdy' -> relu' y' * dEdy') y dEdy))
4850 where
4951 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
src/Grenade/Layers/Tanh.hs+7−5
@@ -1,7 +1,5 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE DataKinds #-}
32{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE StandaloneDeriving #-}
53{-# LANGUAGE TypeOperators #-}
64{-# LANGUAGE TypeFamilies #-}
75{-# LANGUAGE MultiParamTypeClasses #-}
@@ -21,17 +19,21 @@ import Grenade.Core.Shape
2119data Tanh = Tanh
2220 deriving Show
2321
22+instance Monad m => UpdateLayer m Tanh where
23+ type Gradient Tanh = ()
24+ runUpdate _ _ _ = return Tanh
25+
2426instance (Monad m, KnownNat i) => Layer m Tanh ('D1 i) ('D1 i) where
2527 runForwards _ (S1D' y) = return $ S1D' (tanh y)
26− runBackards _ _ (S1D' y) (S1D' dEdy) = return (Tanh, S1D' (tanh' y * dEdy))
28+ runBackards _ (S1D' y) (S1D' dEdy) = return ((), S1D' (tanh' y * dEdy))
2729
2830instance (Monad m, KnownNat i, KnownNat j) => Layer m Tanh ('D2 i j) ('D2 i j) where
2931 runForwards _ (S2D' y) = return $ S2D' (tanh y)
30− runBackards _ _ (S2D' y) (S2D' dEdy) = return (Tanh, S2D' (tanh' y * dEdy))
32+ runBackards _ (S2D' y) (S2D' dEdy) = return ((), S2D' (tanh' y * dEdy))
3133
3234instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Tanh ('D3 i j k) ('D3 i j k) where
3335 runForwards _ (S3D' y) = return $ S3D' (fmap tanh y)
34− runBackards _ _ (S3D' y) (S3D' dEdy) = return (Tanh, S3D' (vectorZip (\y' dEdy' -> tanh' y' * dEdy') y dEdy))
36+ runBackards _ (S3D' y) (S3D' dEdy) = return ((), S3D' (vectorZip (\y' dEdy' -> tanh' y' * dEdy') y dEdy))
3537
3638tanh' :: (Floating a) => a -> a
3739tanh' t = 1 - s ^ (2 :: Int) where s = tanh t