on master help sign in
Purity is the best option

I had a basic monadic interface on, thinking that it might be nice to use for dropout and the like. In retrospect I think that was too heavy. Being a purely functional heterogeneous list, substituting layers is easy, so it one wants to do that using MonadRandom it can still be done.

commitca4b0fe912e2d6845587fed503f00ccacbffdc99 authorHuw Campbell <huw.campbell@ambiata.com> dateFri 2 Dec 2016, 23:44 (10 years ago) parentb01ef9f
16 files changed+171−183
main/feedforward.hs+7−10 main/mnist.hs+3−5 src/Grenade/Core/Network.hs+12−12 src/Grenade/Core/Runner.hs+21−22 src/Grenade/Layers/Convolution.hs+11−13 src/Grenade/Layers/Crop.hs+6−7 src/Grenade/Layers/Dropout.hs+13−14 src/Grenade/Layers/Flatten.hs+9−9 src/Grenade/Layers/FullyConnected.hs+15−12 src/Grenade/Layers/Fuse.hs+21−21 src/Grenade/Layers/Logit.hs+11−11 src/Grenade/Layers/Pad.hs+6−7 src/Grenade/Layers/Pooling.hs+10−12 src/Grenade/Layers/Relu.hs+11−11 src/Grenade/Layers/Tanh.hs+11−11 test/Test/Grenade/Layers/Convolution.hs+4−6
main/feedforward.hs+7−10
@@ -1,6 +1,5 @@
11{-# LANGUAGE BangPatterns #-}
22{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE KindSignatures #-}
43{-# LANGUAGE ScopedTypeVariables #-}
54{-# LANGUAGE TypeOperators #-}
65{-# LANGUAGE TupleSections #-}
@@ -8,7 +7,6 @@
87{-# LANGUAGE FlexibleContexts #-}
98
109import Control.Monad
11−import Control.Monad.Identity
1210import Control.Monad.Random
1311
1412import GHC.TypeLits
@@ -28,7 +26,7 @@ import Grenade
2826-- between the shapes, so inference can't do it all for us.
2927
3028-- With around 100000 examples, this should show two clear circles which have been learned by the network.
31−randomNet :: (MonadRandom m) => m (Network Identity '[('D1 2), ('D1 40), ('D1 40), ('D1 10), ('D1 10), ('D1 1), ('D1 1)])
29+randomNet :: (MonadRandom m) => m (Network '[('D1 2), ('D1 40), ('D1 40), ('D1 10), ('D1 10), ('D1 1), ('D1 1)])
3230randomNet = do
3331 a :: FullyConnected 2 40 <- randomFullyConnected
3432 b :: FullyConnected 40 10 <- randomFullyConnected
@@ -46,13 +44,12 @@ netTest rate n = do
4644 else S1D' $ fromRational 0
4745 net0 <- randomNet
4846
49− return . runIdentity $ do
50− trained <- foldM trainEach net0 (zip inps outs)
51− let testIns = [ [ (x,y) | x <- [0..50] ]
52− | y <- [0..20] ]
47+ let trained = foldl trainEach net0 (zip inps outs)
48+ let testIns = [ [ (x,y) | x <- [0..50] ]
49+ | y <- [0..20] ]
5350
54− outMat <- traverse (traverse (\(x,y) -> (render . normx) <$> runNet trained (S1D' $ SA.vector [x / 25 - 1,y / 10 - 1]))) testIns
55− return $ unlines outMat
51+ let outMat = fmap (fmap (\(x,y) -> (render . normx) $ runNet trained (S1D' $ SA.vector [x / 25 - 1,y / 10 - 1]))) testIns
52+ return $ unlines outMat
5653
5754 where
5855 inCircle :: KnownNat n => SA.R n -> (SA.R n, Double) -> Bool
@@ -73,7 +70,7 @@ data FeedForwardOpts = FeedForwardOpts Int LearningParameters
7370
7471feedForward' :: Parser FeedForwardOpts
7572feedForward' =
76− FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 1000000)
73+ FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 100000)
7774 <*> (LearningParameters
7875 <$> option auto (long "train_rate" <> short 'r' <> value 0.01)
7976 <*> option auto (long "momentum" <> value 0.9)
main/mnist.hs+3−5
@@ -1,6 +1,5 @@
11{-# LANGUAGE BangPatterns #-}
22{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE KindSignatures #-}
43{-# LANGUAGE ScopedTypeVariables #-}
54{-# LANGUAGE TypeOperators #-}
65{-# LANGUAGE TupleSections #-}
@@ -9,7 +8,6 @@
98
109import Control.Applicative
1110import Control.Monad
12−import Control.Monad.Identity
1311import Control.Monad.Random
1412
1513import qualified Data.Attoparsec.Text as A
@@ -32,7 +30,7 @@ import Grenade
3230
3331-- With the mnist data from Kaggle normalised to doubles between 0 and 1, learning rate of 0.01 and 15 iterations,
3432-- this network should get down to about a 1.3% error rate.
35−randomMnistNet :: (MonadRandom m) => m (Network Identity '[('D2 28 28), ('D2 32 32), ('D3 28 28 10), ('D3 14 14 10), ('D3 14 14 10), ('D3 10 10 16), ('D3 5 5 16), ('D1 400), ('D1 400), ('D1 80), ('D1 80), ('D1 10), ('D1 10)])
33+randomMnistNet :: (MonadRandom m) => m (Network '[('D2 28 28), ('D2 32 32), ('D3 28 28 10), ('D3 14 14 10), ('D3 14 14 10), ('D3 10 10 16), ('D3 5 5 16), ('D1 400), ('D1 400), ('D1 80), ('D1 80), ('D1 10), ('D1 10)])
3634randomMnistNet = do
3735 let pad :: Pad 2 2 2 2 = Pad
3836 a :: Convolution 1 10 5 5 1 1 <- randomConvolution
@@ -65,8 +63,8 @@ convTest iterations trainFile validateFile rate = do
6563 return (S2D' $ SA.fromList pixels, S1D' $ SA.fromList lab')
6664
6765 runIteration trainRows validateRows net i = do
68− let trained' = runIdentity $ foldM (trainEach rate) net trainRows
69− let res = runIdentity $ traverse (\(rowP,rowL) -> (rowL,) <$> runNet trained' rowP) validateRows
66+ let trained' = foldl (trainEach rate) net trainRows
67+ let res = fmap (\(rowP,rowL) -> (rowL,) $ runNet trained' rowP) validateRows
7068 let res' = fmap (\(S1D' label, S1D' prediction) -> (maxIndex (SA.extract label), maxIndex (SA.extract prediction))) res
7169 print trained'
7270 putStrLn $ "Iteration " ++ show i ++ ": " ++ show (length (filter ((==) <$> fst <*> snd) res')) ++ " of " ++ show (length res')
src/Grenade/Core/Network.hs+12−12
@@ -26,39 +26,39 @@ data LearningParameters = LearningParameters {
2626
2727-- | Class for updating a layer. All layers implement this, and it is
2828-- shape independent.
29−class UpdateLayer (m :: * -> *) x where
29+class UpdateLayer x where
3030 -- | The type for the gradient for this layer.
3131 -- Unit if there isn't a gradient to pass back.
3232 type Gradient x :: *
3333 -- | Update a layer with its gradient and learning parameters
34− runUpdate :: LearningParameters -> x -> Gradient x -> m x
34+ runUpdate :: LearningParameters -> x -> Gradient x -> x
3535
3636-- | Class for a layer. All layers implement this, however, they don't
3737-- need to implement it for all shapes, only ones which are appropriate.
38−class UpdateLayer m x => Layer (m :: * -> *) x (i :: Shape) (o :: Shape) where
38+class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
3939 -- | Used in training and scoring. Take the input from the previous
4040 -- layer, and give the output from this layer.
41− runForwards :: x -> S' i -> m (S' o)
41+ runForwards :: x -> S' i -> S' o
4242 -- | Back propagate a step. Takes the current layer, the input that the
4343 -- layer gave from the input and the back propagated derivatives from
4444 -- the layer above.
4545 -- Returns the gradient layer and the derivatives to push back further.
46− runBackards :: x -> S' i -> S' o -> m (Gradient x, S' i)
46+ runBackards :: x -> S' i -> S' o -> (Gradient x, S' i)
4747
4848-- | Type of a network.
4949-- The [Shape] type specifies the shapes of data passed between the layers.
5050-- Could be considered to be a heterogeneous list of layers which are able to
5151-- transform the data shapes of the network.
52−data Network :: (* -> *) -> [Shape] -> * where
53− O :: (Show x, Layer m x i o, KnownShape o, KnownShape i)
52+data Network :: [Shape] -> * where
53+ O :: (Show x, Layer x i o, KnownShape o, KnownShape i)
5454 => !x
55− -> Network m '[i, o]
56− (:~>) :: (Show x, Layer m x i h, KnownShape h, KnownShape i)
55+ -> Network '[i, o]
56+ (:~>) :: (Show x, Layer x i h, KnownShape h, KnownShape i)
5757 => !x
58− -> !(Network m (h ': hs))
59− -> Network m (i ': h ': hs)
58+ -> !(Network (h ': hs))
59+ -> Network (i ': h ': hs)
6060infixr 5 :~>
6161
62−instance Show (Network m h) where
62+instance Show (Network h) where
6363 show (O a) = "O " ++ show a
6464 show (i :~> o) = show i ++ "\n:~>\n" ++ show o
src/Grenade/Core/Runner.hs+21−22
@@ -15,45 +15,44 @@ import Grenade.Core.Network
1515import Grenade.Core.Shape
1616
1717-- | Update a network with new weights after training with an instance.
18−train :: forall m i o hs. (Monad m, Head hs ~ i, Last hs ~ o, KnownShape i, KnownShape o)
18+train :: forall i o hs. (Head hs ~ i, Last hs ~ o, KnownShape i, KnownShape o)
1919 => LearningParameters -- ^ learning rate
2020 -> S' i -- ^ input vector
2121 -> S' o -- ^ target vector
22− -> Network m hs -- ^ network to train
23− -> m (Network m hs)
24−train rate x0 target = fmap fst . go x0
22+ -> Network hs -- ^ network to train
23+ -> Network hs
24+train rate x0 target = fst . go x0
2525 where
26− go :: forall m' j js. (Monad m', Head js ~ j, Last js ~ o, KnownShape j)
26+ go :: forall j js. (Head js ~ j, Last js ~ o, KnownShape j)
2727 => S' j -- ^ input vector
28− -> Network m' js -- ^ network to train
29− -> m' (Network m' js, S' j)
28+ -> Network js -- ^ network to train
29+ -> (Network js, S' j)
3030 -- handle input from the beginning, feeding upwards.
3131 go !x (layer :~> n)
32− = do y <- runForwards layer x
32+ = let y = runForwards layer x
3333 -- run the rest of the network, and get the layer from above.
34− (n', dWs') <- go y n
34+ (n', dWs') = go y n
3535 -- calculate the gradient for this layer to pass down,
36− (layer', dWs) <- runBackards layer x dWs'
36+ (layer', dWs) = runBackards layer x dWs'
3737
38− -- Update this layer using the gradient
39− newLayer <- runUpdate rate layer layer'
38+ -- Update this layer using the gradient
39+ newLayer = runUpdate rate layer layer'
4040
41− return (newLayer :~> n', dWs)
41+ in (newLayer :~> n', dWs)
4242
4343 -- handle the output layer, bouncing the derivatives back down.
4444 go !x (O layer)
45− = do y <- runForwards layer x
45+ = let y = runForwards layer x
4646 -- the gradient (how much y affects the error)
47− (layer', dWs) <- runBackards layer x (y - target)
48− newLayer <- runUpdate rate layer layer'
47+ (layer', dWs) = runBackards layer x (y - target)
48+ newLayer = runUpdate rate layer layer'
4949
50− return (O newLayer, dWs)
50+ in (O newLayer, dWs)
5151
5252-- | Just forwards propagation with no training.
53−runNet :: forall m hs. (Monad m)
54− => Network m hs
53+runNet :: Network hs
5554 -> S' (Head hs) -- ^ input vector
56− -> m (S' (Last hs)) -- ^ target vector
57−runNet (layer :~> n) !x = do y <- runForwards layer x
58− runNet n y
55+ -> S' (Last hs) -- ^ target vector
56+runNet (layer :~> n) !x = let y = runForwards layer x
57+ in runNet n y
5958runNet (O layer) !x = runForwards layer x
src/Grenade/Layers/Convolution.hs+11−13
@@ -119,17 +119,16 @@ randomConvolution = do
119119 mm = konst 0
120120 return $ Convolution wN mm
121121
122−instance ( Monad m ) => UpdateLayer m (Convolution channels filters kernelRows kernelCols strideRows strideCols) where
122+instance UpdateLayer (Convolution channels filters kernelRows kernelCols strideRows strideCols) where
123123 type Gradient (Convolution channels filters kernelRows kernelCols strideRows strideCols) = (Convolution' channels filters kernelRows kernelCols strideRows strideCols)
124− runUpdate LearningParameters {..} (Convolution oldKernel oldMomentum) (Convolution' kernelGradient) = do
124+ runUpdate LearningParameters {..} (Convolution oldKernel oldMomentum) (Convolution' kernelGradient) =
125125 let newMomentum = konst learningMomentum * oldMomentum - konst learningRate * kernelGradient
126126 regulariser = konst (learningRegulariser * learningRate) * oldKernel
127127 newKernel = oldKernel + newMomentum - regulariser
128− return $ Convolution newKernel newMomentum
128+ in Convolution newKernel newMomentum
129129
130130-- | A two dimentional image may have a convolution filter applied to it
131−instance ( Monad m
132− , KnownNat kernelRows
131+instance ( KnownNat kernelRows
133132 , KnownNat kernelCols
134133 , KnownNat filters
135134 , KnownNat strideRows
@@ -140,7 +139,7 @@ instance ( Monad m
140139 , KnownNat outputCols
141140 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
142141 , ((outputCols - 1) * strideCols) ~ (inputCols - kernelCols)
143− ) => Layer m (Convolution 1 filters kernelRows kernelCols strideRows strideCols) ('D2 inputRows inputCols) ('D3 outputRows outputCols filters) where
142+ ) => Layer (Convolution 1 filters kernelRows kernelCols strideRows strideCols) ('D2 inputRows inputCols) ('D3 outputRows outputCols filters) where
144143 runForwards (Convolution kernel _) (S2D' input) =
145144 let ex = extract input
146145 ek = extract kernel
@@ -154,7 +153,7 @@ instance ( Monad m
154153 mt = c LA.<> ek
155154 r = col2vid 1 1 1 1 ox oy mt
156155 rs = fmap (fromJust . create) r
157− in return . S3D' $ mkVector rs
156+ in S3D' $ mkVector rs
158157 runBackards (Convolution kernel _) (S2D' input) (S3D' dEdy) =
159158 let ex = extract input
160159 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
@@ -176,13 +175,12 @@ instance ( Monad m
176175 dW = vs LA.<> tr ek
177176
178177 xW = col2im kx ky sx sy ix iy dW
179− in return (Convolution' kN, S2D' . fromJust . create $ xW)
178+ in (Convolution' kN, S2D' . fromJust . create $ xW)
180179
181180
182181-- | A three dimensional image (or 2d with many channels) can have
183182-- an appropriately sized convolution filter run across it.
184−instance ( Monad m
185− , KnownNat kernelRows
183+instance ( KnownNat kernelRows
186184 , KnownNat kernelCols
187185 , KnownNat filters
188186 , KnownNat strideRows
@@ -194,7 +192,7 @@ instance ( Monad m
194192 , KnownNat channels
195193 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
196194 , ((outputCols - 1) * strideCols) ~ (inputCols - kernelCols)
197− ) => Layer m (Convolution channels filters kernelRows kernelCols strideRows strideCols) ('D3 inputRows inputCols channels) ('D3 outputRows outputCols filters) where
195+ ) => Layer (Convolution channels filters kernelRows kernelCols strideRows strideCols) ('D3 inputRows inputCols channels) ('D3 outputRows outputCols filters) where
198196 runForwards (Convolution kernel _) (S3D' input) =
199197 let ex = vecToList $ fmap extract input
200198 ek = extract kernel
@@ -210,7 +208,7 @@ instance ( Monad m
210208 mt = c LA.<> ek
211209 r = col2vid 1 1 1 1 ox oy mt
212210 rs = fmap (fromJust . create) r
213− in return . S3D' $ mkVector rs
211+ in S3D' $ mkVector rs
214212 runBackards (Convolution kernel _) (S3D' input) (S3D' dEdy) =
215213 let ex = vecToList $ fmap extract input
216214 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
@@ -233,7 +231,7 @@ instance ( Monad m
233231 dW = vs LA.<> tr ek
234232
235233 xW = col2vid kx ky sx sy ix iy dW
236− in return (Convolution' kN, S3D' . mkVector . fmap (fromJust . create) $ xW)
234+ in (Convolution' kN, S3D' . mkVector . fmap (fromJust . create) $ xW)
237235
238236im2col :: Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
239237im2col nrows ncols srows scols m =
src/Grenade/Layers/Crop.hs+6−7
@@ -37,13 +37,12 @@ data Crop :: Nat
3737instance Show (Crop cropLeft cropTop cropRight cropBottom) where
3838 show Crop = "Crop"
3939
40−instance Monad m => UpdateLayer m (Crop l t r b) where
40+instance UpdateLayer (Crop l t r b) where
4141 type Gradient (Crop l t r b) = ()
42− runUpdate _ x _ = return x
42+ runUpdate _ x _ = x
4343
4444-- | A two dimentional image can be cropped.
45−instance ( Monad m
46− , KnownNat cropLeft
45+instance ( KnownNat cropLeft
4746 , KnownNat cropTop
4847 , KnownNat cropRight
4948 , KnownNat cropBottom
@@ -53,7 +52,7 @@ instance ( Monad m
5352 , KnownNat outputColumns
5453 , (inputRows - cropTop - cropBottom) ~ outputRows
5554 , (inputColumns - cropLeft - cropRight) ~ outputColumns
56− ) => Layer m (Crop cropLeft cropTop cropRight cropBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
55+ ) => Layer (Crop cropLeft cropTop cropRight cropBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
5756 runForwards Crop (S2D' input) =
5857 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
5958 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
@@ -61,7 +60,7 @@ instance ( Monad m
6160 ncols = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
6261 m = extract input
6362 r = subMatrix (cropt, cropl) (nrows, ncols) m
64− in return . S2D' . fromJust . create $ r
63+ in S2D' . fromJust . create $ r
6564 runBackards _ _ (S2D' dEdy) =
6665 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
6766 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
@@ -69,4 +68,4 @@ instance ( Monad m
6968 cropb = fromIntegral $ natVal (Proxy :: Proxy cropBottom)
7069 eo = extract dEdy
7170 vs = diagBlock [konst 0 (cropt,cropl), eo, konst 0 (cropb,cropr)]
72− in return ((), S2D' . fromJust . create $ vs)
71+ in ((), S2D' . fromJust . create $ vs)
src/Grenade/Layers/Dropout.hs+13−14
@@ -9,15 +9,14 @@
99
1010module Grenade.Layers.Dropout (
1111 Dropout (..)
12+ , randomDropout
1213 ) where
1314
1415import Control.Monad.Random hiding (fromList)
15−import Control.Monad.State
1616
1717import GHC.TypeLits
1818import Grenade.Core.Shape
1919import Grenade.Core.Network
20−import Grenade.Core.Phase
2120
2221import Numeric.LinearAlgebra.Static
2322
@@ -27,12 +26,14 @@ import Numeric.LinearAlgebra.Static
2726-- After backpropogation, we return a new matrix/vector, with different bits dropped out.
2827-- Double is the proportion to drop in each training iteration (like 1% or 5% would be
2928-- reasonable).
30−data Dropout o = Dropout Double (R o)
29+data Dropout o =
30+ Dropout (R o)
31+ | Pass Double
3132 deriving Show
3233
33−instance (MonadRandom m, KnownNat i) => UpdateLayer m (Dropout i) where
34+instance (KnownNat i) => UpdateLayer (Dropout i) where
3435 type Gradient (Dropout i) = ()
35− runUpdate _ (Dropout rate _) _ = randomDropout rate
36+ runUpdate _ x _ = x
3637
3738randomDropout :: (MonadRandom m, KnownNat i)
3839 => Double -> m (Dropout i)
@@ -40,12 +41,10 @@ randomDropout rate = do
4041 seed <- getRandom
4142 let wN = randomVector seed Uniform
4243 xs = dvmap (\a -> if a <= rate then 0 else 1) wN
43− return $ Dropout rate xs
44−
45−instance (MonadRandom m, MonadState Phase m, KnownNat i) => Layer m (Dropout i) ('D1 i) ('D1 i) where
46− runForwards (Dropout rate drops) (S1D' x) = isTrainingPhase >>= \case
47− True -> return . S1D' $ x * drops
48− False -> return . 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)
44+ return $ Dropout xs
45+
46+instance (KnownNat i) => Layer (Dropout i) ('D1 i) ('D1 i) where
47+ runForwards (Dropout drops) (S1D' x) = S1D' $ x * drops
48+ runForwards (Pass rate) (S1D' x)= S1D' $ dvmap (* (1 - rate)) x
49+ runBackards (Dropout drops) _ (S1D' x) = ((), S1D' $ x * drops)
50+ runBackards (Pass rate) _ (S1D' x) = ((), S1D' $ dvmap (* (1 - rate)) x)
src/Grenade/Layers/Flatten.hs+9−9
@@ -25,24 +25,24 @@ import Grenade.Core.Network
2525data FlattenLayer = FlattenLayer
2626 deriving Show
2727
28−instance Monad m => UpdateLayer m FlattenLayer where
28+instance UpdateLayer FlattenLayer where
2929 type Gradient FlattenLayer = ()
30− runUpdate _ _ _ = return FlattenLayer
30+ runUpdate _ _ _ = FlattenLayer
3131
32−instance (Monad m, KnownNat a, KnownNat x, KnownNat y, a ~ (x * y)) => Layer m FlattenLayer ('D2 x y) ('D1 a) where
33− runForwards _ (S2D' y) = return $ S1D' . fromList . toList . flatten . extract $ y
34− runBackards _ _ (S1D' y) = return ((), S2D' . fromList . toList . unwrap $ y)
32+instance (KnownNat a, KnownNat x, KnownNat y, a ~ (x * y)) => Layer FlattenLayer ('D2 x y) ('D1 a) where
33+ runForwards _ (S2D' y) = S1D' . fromList . toList . flatten . extract $ y
34+ runBackards _ _ (S1D' y) = ((), S2D' . fromList . toList . unwrap $ y)
3535
36−instance (Monad m, KnownNat a, KnownNat x, KnownNat y, KnownNat z, a ~ (x * y * z)) => Layer m FlattenLayer ('D3 x y z) ('D1 a) where
37− runForwards _ (S3D' y) = return $ S1D' . raiseShapeError . create . vjoin . vecToList . fmap (flatten . extract) $ y
38− runBackards _ _ (S1D' o) = do
36+instance (KnownNat a, KnownNat x, KnownNat y, KnownNat z, a ~ (x * y * z)) => Layer FlattenLayer ('D3 x y z) ('D1 a) where
37+ runForwards _ (S3D' y) = S1D' . raiseShapeError . create . vjoin . vecToList . fmap (flatten . extract) $ y
38+ runBackards _ _ (S1D' o) =
3939 let x' = fromIntegral $ natVal (Proxy :: Proxy x)
4040 y' = fromIntegral $ natVal (Proxy :: Proxy y)
4141 z' = fromIntegral $ natVal (Proxy :: Proxy z)
4242 vecs = takesV (replicate z' (x' * y')) (extract o)
4343 ls = fmap (raiseShapeError . create . reshape y') vecs
4444 ls' = mkVector ls :: Vector z (L x y)
45− return ((), S3D' ls')
45+ in ((), S3D' ls')
4646
4747raiseShapeError :: Maybe a -> a
4848raiseShapeError (Just x) = x
src/Grenade/Layers/FullyConnected.hs+15−12
@@ -23,6 +23,7 @@ import Grenade.Core.Shape
2323-- | A basic fully connected (or inner product) neural network layer.
2424data FullyConnected i o = FullyConnected
2525 !(R o) -- Bias neuron weights
26+ !(R o) -- Bias neuron momentum
2627 !(L o i) -- Activation weights
2728 !(L o i) -- Momentum
2829
@@ -33,27 +34,28 @@ data FullyConnected' i o = FullyConnected'
3334instance Show (FullyConnected i o) where
3435 show FullyConnected {} = "FullyConnected"
3536
36−instance (Monad m, KnownNat i, KnownNat o) => UpdateLayer m (FullyConnected i o) where
37+instance (KnownNat i, KnownNat o) => UpdateLayer (FullyConnected i o) where
3738 type Gradient (FullyConnected i o) = (FullyConnected' i o)
3839
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
40+ runUpdate LearningParameters {..} (FullyConnected oldBias oldBiasMomentum oldActivations oldMomentum) (FullyConnected' biasGradient activationGradient) =
41+ let newBiasMomentum = konst learningMomentum * oldBiasMomentum - konst learningRate * biasGradient
42+ newBias = oldBias + newBiasMomentum
43+ newMomentum = konst learningMomentum * oldMomentum - konst learningRate * activationGradient
44+ regulariser = konst (learningRegulariser * learningRate) * oldActivations
45+ newActivations = oldActivations + newMomentum - regulariser
46+ in FullyConnected newBias newBiasMomentum newActivations newMomentum
4547
46−instance (Monad m, KnownNat i, KnownNat o) => Layer m (FullyConnected i o) ('D1 i) ('D1 o) where
48+instance (KnownNat i, KnownNat o) => Layer (FullyConnected i o) ('D1 i) ('D1 o) where
4749 -- Do a matrix vector multiplication and return the result.
48− runForwards (FullyConnected wB wN _) (S1D' v) = return $ S1D' (wB + wN #> v)
50+ runForwards (FullyConnected wB _ wN _) (S1D' v) = S1D' (wB + wN #> v)
4951
5052 -- Run a backpropogation step for a full connected layer.
51− runBackards (FullyConnected _ wN _) (S1D' x) (S1D' dEdy) =
53+ runBackards (FullyConnected _ _ wN _) (S1D' x) (S1D' dEdy) =
5254 let wB' = dEdy
5355 mm' = dEdy `outer` x
5456 -- calcluate derivatives for next step
5557 dWs = tr wN #> dEdy
56− in return (FullyConnected' wB' mm', S1D' dWs)
58+ in (FullyConnected' wB' mm', S1D' dWs)
5759
5860randomFullyConnected :: (MonadRandom m, KnownNat i, KnownNat o)
5961 => m (FullyConnected i o)
@@ -62,5 +64,6 @@ randomFullyConnected = do
6264 s2 :: Int <- getRandom
6365 let wB = randomVector s1 Uniform * 2 - 1
6466 wN = uniformSample s2 (-1) 1
67+ bm = konst 0
6568 mm = konst 0
66− return $ FullyConnected wB wN mm
69+ return $ FullyConnected wB bm wN mm
src/Grenade/Layers/Fuse.hs+21−21
@@ -22,30 +22,30 @@ import Grenade.Core.Shape
2222-- This can be used to simplify a network if a complicated repeated structure is used.
2323-- This does however have a trade off, internal incremental states in the Wengert tape are
2424-- not retained during reverse accumulation. So less RAM is used, but more compute is required.
25−data Fuse :: (* -> *) -> * -> * -> Shape -> Shape -> Shape -> * where
26− (:$$) :: (Show x, Show y, Layer m x i h, Layer m y h o, KnownShape h, KnownShape i, KnownShape o)
25+data Fuse :: * -> * -> Shape -> Shape -> Shape -> * where
26+ (:$$) :: (Show x, Show y, Layer x i h, Layer y h o, KnownShape h, KnownShape i, KnownShape o)
2727 => !x
2828 -> !y
29− -> Fuse m x y i h o
29+ -> Fuse x y i h o
3030infixr 5 :$$
3131
32−instance Show (Fuse m x y i h o) where
32+instance Show (Fuse x y i h o) where
3333 show (x :$$ y) = "(" ++ show x ++ " :$$ " ++ show y ++ ")"
3434
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
43− runForwards (x :$$ y) input = do
44− yInput :: S' h <- runForwards x input
45− runForwards y yInput
46−
47− runBackards (x :$$ y) input backGradient = do
48− yInput :: S' h <- runForwards x input
49− (y', yGrad) <- runBackards y yInput backGradient
50− (x', xGrad) <- runBackards x input yGrad
51− return ((x', y'), xGrad)
35+instance (KnownShape i, KnownShape h, KnownShape o) => UpdateLayer (Fuse x y i h o) where
36+ type Gradient (Fuse x y i h o) = (Gradient x, Gradient y)
37+ runUpdate lr (x :$$ y) (x', y') =
38+ let newX = runUpdate lr x x'
39+ newY = runUpdate lr y y'
40+ in (newX :$$ newY)
41+
42+instance (KnownShape i, KnownShape h, KnownShape o) => Layer (Fuse x y i h o) i o where
43+ runForwards (x :$$ y) input =
44+ let yInput :: S' h = runForwards x input
45+ in runForwards y yInput
46+
47+ runBackards (x :$$ y) input backGradient =
48+ let yInput :: S' h = runForwards x input
49+ (y', yGrad) = runBackards y yInput backGradient
50+ (x', xGrad) = runBackards x input yGrad
51+ in ((x', y'), xGrad)
src/Grenade/Layers/Logit.hs+11−11
@@ -22,21 +22,21 @@ import Grenade.Core.Shape
2222data Logit = Logit
2323 deriving Show
2424
25−instance Monad m => UpdateLayer m Logit where
25+instance UpdateLayer Logit where
2626 type Gradient Logit = ()
27− runUpdate _ _ _ = return Logit
27+ runUpdate _ _ _ = Logit
2828
29−instance (Monad m, KnownNat i) => Layer m Logit ('D1 i) ('D1 i) where
30− runForwards _ (S1D' y) = return $ S1D' (logistic y)
31− runBackards _ (S1D' y) (S1D' dEdy) = return ((), S1D' (logistic' y * dEdy))
29+instance (KnownNat i) => Layer Logit ('D1 i) ('D1 i) where
30+ runForwards _ (S1D' y) = S1D' (logistic y)
31+ runBackards _ (S1D' y) (S1D' dEdy) = ((), S1D' (logistic' y * dEdy))
3232
33−instance (Monad m, KnownNat i, KnownNat j) => Layer m Logit ('D2 i j) ('D2 i j) where
34− runForwards _ (S2D' y) = return $ S2D' (logistic y)
35− runBackards _ (S2D' y) (S2D' dEdy) = return ((), S2D' (logistic' y * dEdy))
33+instance (KnownNat i, KnownNat j) => Layer Logit ('D2 i j) ('D2 i j) where
34+ runForwards _ (S2D' y) = S2D' (logistic y)
35+ runBackards _ (S2D' y) (S2D' dEdy) = ((), S2D' (logistic' y * dEdy))
3636
37−instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Logit ('D3 i j k) ('D3 i j k) where
38− runForwards _ (S3D' y) = return $ S3D' (fmap logistic y)
39− runBackards _ (S3D' y) (S3D' dEdy) = return ((), S3D' (vectorZip (\y' dEdy' -> logistic' y' * dEdy') y dEdy))
37+instance (KnownNat i, KnownNat j, KnownNat k) => Layer Logit ('D3 i j k) ('D3 i j k) where
38+ runForwards _ (S3D' y) = S3D' (fmap logistic y)
39+ runBackards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> logistic' y' * dEdy') y dEdy))
4040
4141
4242logistic :: Floating a => a -> a
src/Grenade/Layers/Pad.hs+6−7
@@ -37,13 +37,12 @@ data Pad :: Nat
3737instance Show (Pad padLeft padTop padRight padBottom) where
3838 show Pad = "Pad"
3939
40−instance Monad m => UpdateLayer m (Pad l t r b) where
40+instance UpdateLayer (Pad l t r b) where
4141 type Gradient (Pad l t r b) = ()
42− runUpdate _ x _ = return x
42+ runUpdate _ x _ = x
4343
4444-- | A two dimentional image can be padped.
45−instance ( Monad m
46− , KnownNat padLeft
45+instance ( KnownNat padLeft
4746 , KnownNat padTop
4847 , KnownNat padRight
4948 , KnownNat padBottom
@@ -53,7 +52,7 @@ instance ( Monad m
5352 , KnownNat outputColumns
5453 , (inputRows + padTop + padBottom) ~ outputRows
5554 , (inputColumns + padLeft + padRight) ~ outputColumns
56− ) => Layer m (Pad padLeft padTop padRight padBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
55+ ) => Layer (Pad padLeft padTop padRight padBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
5756 runForwards Pad (S2D' input) =
5857 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
5958 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
@@ -61,7 +60,7 @@ instance ( Monad m
6160 padb = fromIntegral $ natVal (Proxy :: Proxy padBottom)
6261 m = extract input
6362 r = diagBlock [konst 0 (padt,padl), m, konst 0 (padb,padr)]
64− in return . S2D' . fromJust . create $ r
63+ in S2D' . fromJust . create $ r
6564 runBackards Pad _ (S2D' dEdy) =
6665 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
6766 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
@@ -69,4 +68,4 @@ instance ( Monad m
6968 ncols = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
7069 m = extract dEdy
7170 vs = subMatrix (padt, padl) (nrows, ncols) m
72− in return ((), S2D' . fromJust . create $ vs)
71+ in ((), S2D' . fromJust . create $ vs)
src/Grenade/Layers/Pooling.hs+10−12
@@ -51,13 +51,12 @@ 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
54+instance UpdateLayer (Pooling kernelRows kernelColumns strideRows strideColumns) where
5555 type Gradient (Pooling kr kc sr sc) = ()
56− runUpdate _ Pooling _ = return Pooling
56+ runUpdate _ Pooling _ = Pooling
5757
5858-- | A two dimentional image can be pooled.
59−instance ( Monad m
60− , KnownNat kernelRows
59+instance ( KnownNat kernelRows
6160 , KnownNat kernelColumns
6261 , KnownNat strideRows
6362 , KnownNat strideColumns
@@ -67,7 +66,7 @@ instance ( Monad m
6766 , KnownNat outputColumns
6867 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
6968 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
70− ) => Layer m (Pooling kernelRows kernelColumns strideRows strideColumns) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
69+ ) => Layer (Pooling kernelRows kernelColumns strideRows strideColumns) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
7170 runForwards Pooling (S2D' input) =
7271 let kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
7372 ky = fromIntegral $ natVal (Proxy :: Proxy kernelColumns)
@@ -78,7 +77,7 @@ instance ( Monad m
7877 ex = extract input
7978 r = poolForward kx ky sx sy ox oy $ ex
8079 rs = fromJust . create $ r
81− in return . S2D' $ rs
80+ in S2D' $ rs
8281 runBackards Pooling (S2D' input) (S2D' dEdy) =
8382 let kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
8483 ky = fromIntegral $ natVal (Proxy :: Proxy kernelColumns)
@@ -87,12 +86,11 @@ instance ( Monad m
8786 ex = extract input
8887 eo = extract dEdy
8988 vs = poolBackward kx ky sx sy ex eo
90− in return ((), S2D' . fromJust . create $ vs)
89+ in ((), S2D' . fromJust . create $ vs)
9190
9291
9392-- | A three dimensional image can be pooled on each layer.
94−instance ( Monad m
95− , KnownNat kernelRows
93+instance ( KnownNat kernelRows
9694 , KnownNat kernelColumns
9795 , KnownNat strideRows
9896 , KnownNat strideColumns
@@ -102,7 +100,7 @@ instance ( Monad m
102100 , KnownNat outputColumns
103101 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
104102 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
105− ) => Layer m (Pooling kernelRows kernelColumns strideRows strideColumns) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) where
103+ ) => Layer (Pooling kernelRows kernelColumns strideRows strideColumns) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) where
106104 runForwards Pooling (S3D' input) =
107105 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
108106 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -115,7 +113,7 @@ instance ( Monad m
115113 ex = fmap extract input
116114 r = poolForwardList kx ky sx sy ix iy ox oy ex
117115 rs = fmap (fromJust . create) r
118− in return . S3D' $ rs
116+ in S3D' rs
119117 runBackards Pooling (S3D' input) (S3D' dEdy) =
120118 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
121119 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -127,7 +125,7 @@ instance ( Monad m
127125 eo = fmap extract dEdy
128126 ez = vectorZip (,) ex eo
129127 vs = poolBackwardList kx ky sx sy ix iy ez
130− in return ((), S3D' . fmap (fromJust . create) $ vs)
128+ in ((), S3D' . fmap (fromJust . create) $ vs)
131129
132130poolForward :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
133131poolForward nrows ncols srows scols outputRows outputCols m =
src/Grenade/Layers/Relu.hs+11−11
@@ -22,30 +22,30 @@ import qualified Numeric.LinearAlgebra.Static as LAS
2222data Relu = Relu
2323 deriving Show
2424
25−instance Monad m => UpdateLayer m Relu where
25+instance UpdateLayer Relu where
2626 type Gradient Relu = ()
27− runUpdate _ _ _ = return Relu
27+ runUpdate _ _ _ = Relu
2828
29−instance (Monad m, KnownNat i) => Layer m Relu ('D1 i) ('D1 i) where
30− runForwards _ (S1D' y) = return $ S1D' (relu y)
29+instance ( KnownNat i) => Layer Relu ('D1 i) ('D1 i) where
30+ runForwards _ (S1D' y) = S1D' (relu y)
3131 where
3232 relu = LAS.dvmap (\a -> if a <= 0 then 0 else a)
33− runBackards _ (S1D' y) (S1D' dEdy) = return ((), S1D' (relu' y * dEdy))
33+ runBackards _ (S1D' y) (S1D' dEdy) = ((), S1D' (relu' y * dEdy))
3434 where
3535 relu' = LAS.dvmap (\a -> if a <= 0 then 0 else 1)
3636
37−instance (Monad m, KnownNat i, KnownNat j) => Layer m Relu ('D2 i j) ('D2 i j) where
38− runForwards _ (S2D' y) = return $ S2D' (relu y)
37+instance (KnownNat i, KnownNat j) => Layer Relu ('D2 i j) ('D2 i j) where
38+ runForwards _ (S2D' y) = S2D' (relu y)
3939 where
4040 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
41− runBackards _ (S2D' y) (S2D' dEdy) = return ((), S2D' (relu' y * dEdy))
41+ runBackards _ (S2D' y) (S2D' dEdy) = ((), S2D' (relu' y * dEdy))
4242 where
4343 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
4444
45−instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Relu ('D3 i j k) ('D3 i j k) where
46− runForwards _ (S3D' y) = return $ S3D' (fmap relu y)
45+instance (KnownNat i, KnownNat j, KnownNat k) => Layer Relu ('D3 i j k) ('D3 i j k) where
46+ runForwards _ (S3D' y) = S3D' (fmap relu y)
4747 where
4848 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
49− runBackards _ (S3D' y) (S3D' dEdy) = return ((), S3D' (vectorZip (\y' dEdy' -> relu' y' * dEdy') y dEdy))
49+ runBackards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> relu' y' * dEdy') y dEdy))
5050 where
5151 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
src/Grenade/Layers/Tanh.hs+11−11
@@ -19,21 +19,21 @@ import Grenade.Core.Shape
1919data Tanh = Tanh
2020 deriving Show
2121
22−instance Monad m => UpdateLayer m Tanh where
22+instance UpdateLayer Tanh where
2323 type Gradient Tanh = ()
24− runUpdate _ _ _ = return Tanh
24+ runUpdate _ _ _ = Tanh
2525
26−instance (Monad m, KnownNat i) => Layer m Tanh ('D1 i) ('D1 i) where
27− runForwards _ (S1D' y) = return $ S1D' (tanh y)
28− runBackards _ (S1D' y) (S1D' dEdy) = return ((), S1D' (tanh' y * dEdy))
26+instance KnownNat i => Layer Tanh ('D1 i) ('D1 i) where
27+ runForwards _ (S1D' y) = S1D' (tanh y)
28+ runBackards _ (S1D' y) (S1D' dEdy) = ((), S1D' (tanh' y * dEdy))
2929
30−instance (Monad m, KnownNat i, KnownNat j) => Layer m Tanh ('D2 i j) ('D2 i j) where
31− runForwards _ (S2D' y) = return $ S2D' (tanh y)
32− runBackards _ (S2D' y) (S2D' dEdy) = return ((), S2D' (tanh' y * dEdy))
30+instance (KnownNat i, KnownNat j) => Layer Tanh ('D2 i j) ('D2 i j) where
31+ runForwards _ (S2D' y) = S2D' (tanh y)
32+ runBackards _ (S2D' y) (S2D' dEdy) = ((), S2D' (tanh' y * dEdy))
3333
34−instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Tanh ('D3 i j k) ('D3 i j k) where
35− runForwards _ (S3D' y) = return $ S3D' (fmap tanh y)
36− runBackards _ (S3D' y) (S3D' dEdy) = return ((), S3D' (vectorZip (\y' dEdy' -> tanh' y' * dEdy') y dEdy))
34+instance (KnownNat i, KnownNat j, KnownNat k) => Layer Tanh ('D3 i j k) ('D3 i j k) where
35+ runForwards _ (S3D' y) = S3D' (fmap tanh y)
36+ runBackards _ (S3D' y) (S3D' dEdy) = ((), S3D' (vectorZip (\y' dEdy' -> tanh' y' * dEdy') y dEdy))
3737
3838tanh' :: (Floating a) => a -> a
3939tanh' t = 1 - s ^ (2 :: Int) where s = tanh t
test/Test/Grenade/Layers/Convolution.hs+4−6
@@ -4,8 +4,6 @@
44{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
55module Test.Grenade.Layers.Convolution where
66
7−import Control.Monad.Identity
8−
97import Grenade.Core.Shape
108import Grenade.Core.Vector as Grenade
119import Grenade.Core.Network
@@ -114,7 +112,7 @@ prop_simple_conv_forwards = once $
114112 [ 5.0 , 9.0 ] :: HStatic.L 1 2)
115113 ,(HStatic.matrix
116114 [ -7.0 , -10.0 ] :: HStatic.L 1 2)]) :: [HStatic.L 1 2]
117− out = runIdentity $ runForwards convLayer input :: S' ('D3 1 2 4)
115+ out = runForwards convLayer input :: S' ('D3 1 2 4)
118116
119117 grad = S3D' ( mkVector
120118 [(HStatic.matrix
@@ -129,7 +127,7 @@ prop_simple_conv_forwards = once $
129127 expectBack = (HStatic.matrix
130128 [ 1.0, 0.0, 0.0
131129 , 0.0, -2.0,-1.0] :: HStatic.L 2 3)
132− (nc, inX) = runIdentity $ runBackards convLayer input grad
130+ (nc, inX) = runBackards convLayer input grad
133131
134132 in case (out, inX, nc) of
135133 (S3D' out' , S2D' inX', Convolution' backGrad)
@@ -226,7 +224,7 @@ prop_single_conv_forwards = once $
226224 [ 5.0 , 9.0 ] :: HStatic.L 1 2)
227225 ,(HStatic.matrix
228226 [ -7.0 , -10.0 ] :: HStatic.L 1 2)]) :: [HStatic.L 1 2]
229− out = runIdentity $ runForwards convLayer input :: S' ('D3 1 2 4)
227+ out = runForwards convLayer input :: S' ('D3 1 2 4)
230228
231229 grad = S3D' ( mkVector
232230 [(HStatic.matrix
@@ -241,7 +239,7 @@ prop_single_conv_forwards = once $
241239 expectBack = (HStatic.matrix
242240 [ 1.0, 0.0, 0.0
243241 , 0.0, -2.0,-1.0] :: HStatic.L 2 3)
244− (nc, inX) = runIdentity $ runBackards convLayer input grad
242+ (nc, inX) = runBackards convLayer input grad
245243
246244 in case (out, inX, nc) of
247245 (S3D' out' , S3D' inX', Convolution' backGrad)