on master help sign in
Merge pull request #11 from HuwCampbell/topic/learning-separation

Topic/learning separation

commit70fbac3924a19fd61c34c696d733e21f5825df93 authorHuw Campbell <huw.campbell@gmail.com> dateSun 4 Dec 2016, 11:19 (10 years ago) parentbe61f9bdfbb6c1
23 files changed+303−241
.gitmodules+1−1 README.md+2−2 grenade.cabal+1 lib/p+1 main/feedforward.hs+17−16 main/mnist.hs+16−15 src/Grenade.hs−13 src/Grenade/Core/Network.hs+31−16 src/Grenade/Core/Runner.hs+26−23 src/Grenade/Core/Shape.hs+3−3 src/Grenade/Core/Vector.hs+2−2 src/Grenade/Layers/Convolution.hs+38−19 src/Grenade/Layers/Crop.hs+9−8 src/Grenade/Layers/Dropout.hs+15−16 src/Grenade/Layers/Flatten.hs+11−7 src/Grenade/Layers/FullyConnected.hs+27−14 src/Grenade/Layers/Fuse.hs+20−14 src/Grenade/Layers/Logit.hs+14−11 src/Grenade/Layers/Pad.hs+9−8 src/Grenade/Layers/Pooling.hs+14−12 src/Grenade/Layers/Relu.hs+13−11 src/Grenade/Layers/Tanh.hs+13−11 test/Test/Grenade/Layers/Convolution.hs+20−19
.gitmodules+1−1
@@ -6,7 +6,7 @@
66 url = https://github.com/ambiata/x.git
77[submodule "lib/p"]
88 path = lib/p
9− url = https://github.com/ambiata/p.git
9+ url = https://github.com/ambiata/p
1010[submodule "lib/disorder.hs"]
1111 path = lib/disorder.hs
1212 url = https://github.com/ambiata/disorder.hs.git
README.md+2−2
@@ -13,10 +13,10 @@ Five is right out.
1313Grenade is a dependently typed, practical, and pretty quick neural network library for concise and precise
1414specifications of complex networks in Haskell.
1515
16−As an example, a network which can achieve less than 1.5% error on mnist can be specified and
16+As an example, a network which can achieve less than 1.5% error on MNIST can be specified and
1717initialised with random weights in under 10 lines of code with
1818```haskell
19−randomMnistNet :: MonadRandom m => m (Network Identity '[('D2 28 28), ('D3 24 24 10), ('D3 12 12 10), ('D3 12 12 10), ('D3 8 8 16), ('D3 4 4 16), ('D1 256), ('D1 256), ('D1 80), ('D1 80), ('D1 10), ('D1 10)])
19+randomMnistNet :: MonadRandom m => m (Network '[ 'D2 28 28, 'D3 24 24 10, 'D3 12 12 10, 'D3 12 12 10, 'D3 8 8 16, 'D3 4 4 16, 'D1 256, 'D1 256, 'D1 80, 'D1 80, 'D1 10, 'D1 10])
2020randomMnistNet = do
2121 a :: Convolution 1 10 5 5 1 1 <- randomConvolution
2222 let b :: Pooling 2 2 2 2 = Pooling
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
lib/pnew file+1

Submodule changed.

main/feedforward.hs+17−16
@@ -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,32 +26,30 @@ 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
3533 c :: FullyConnected 10 1 <- randomFullyConnected
3634 return $ a :~> Tanh :~> b :~> Relu :~> c :~> O Logit
3735
38−netTest :: MonadRandom m => Double -> Int -> m String
36+netTest :: MonadRandom m => LearningParameters -> Int -> m String
3937netTest rate n = do
4038 inps <- replicateM n $ do
41− s <- getRandom
39+ s <- getRandom
4240 return $ S1D' $ SA.randomVector s SA.Uniform * 2 - 1
4341 let outs = flip map inps $ \(S1D' v) ->
44− if v `inCircle` (fromRational 0.33, 0.33)
45− || v `inCircle` (fromRational (-0.33), 0.33)
42+ if v `inCircle` (fromRational 0.33, 0.33) || v `inCircle` (fromRational (-0.33), 0.33)
4643 then S1D' $ fromRational 1
4744 else S1D' $ fromRational 0
4845 net0 <- randomNet
4946
50− return . runIdentity $ do
51− trained <- foldM trainEach net0 (zip inps outs)
52− let testIns = [ [ (x,y) | x <- [0..50] ]
53− | y <- [0..20] ]
47+ let trained = foldl trainEach net0 (zip inps outs)
48+ let testIns = [ [ (x,y) | x <- [0..50] ]
49+ | y <- [0..20] ]
5450
55− outMat <- traverse (traverse (\(x,y) -> (render . normx) <$> runNet trained (S1D' $ SA.vector [x / 25 - 1,y / 10 - 1]))) testIns
56− 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
5753
5854 where
5955 inCircle :: KnownNat n => SA.R n -> (SA.R n, Double) -> Bool
@@ -70,11 +66,16 @@ netTest rate n = do
7066 normx (S1D' r) = SA.mean r
7167
7268
73−data FeedForwardOpts = FeedForwardOpts Int Double
69+data FeedForwardOpts = FeedForwardOpts Int LearningParameters
7470
7571feedForward' :: Parser FeedForwardOpts
76−feedForward' = FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 1000000)
77− <*> option auto (long "train_rate" <> short 'r' <> value 0.01)
72+feedForward' =
73+ FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 100000)
74+ <*> (LearningParameters
75+ <$> option auto (long "train_rate" <> short 'r' <> value 0.01)
76+ <*> option auto (long "momentum" <> value 0.9)
77+ <*> option auto (long "l2" <> value 0.0001)
78+ )
7879
7980main :: IO ()
8081main = do
main/mnist.hs+16−15
@@ -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,18 +30,17 @@ 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, 'D3 24 24 10, 'D3 12 12 10, 'D3 12 12 10, 'D3 8 8 16, 'D3 4 4 16, 'D1 256, 'D1 256, 'D1 80, 'D1 80, 'D1 10, 'D1 10])
3634randomMnistNet = do
37− let pad :: Pad 2 2 2 2 = Pad
3835 a :: Convolution 1 10 5 5 1 1 <- randomConvolution
3936 let b :: Pooling 2 2 2 2 = Pooling
4037 c :: Convolution 10 16 5 5 1 1 <- randomConvolution
4138 let d :: Pooling 2 2 2 2 = Pooling
42− e :: FullyConnected 400 80 <- randomFullyConnected
39+ e :: FullyConnected 256 80 <- randomFullyConnected
4340 f :: FullyConnected 80 10 <- randomFullyConnected
44− return $ pad :~> a :~> b :~> Relu :~> c :~> d :~> FlattenLayer :~> Relu :~> e :~> Logit :~> f :~> O Logit
41+ return $ a :~> b :~> Relu :~> c :~> d :~> FlattenLayer :~> Relu :~> e :~> Logit :~> f :~> O Logit
4542
46−convTest :: Int -> FilePath -> FilePath -> Double -> IO ()
43+convTest :: Int -> FilePath -> FilePath -> LearningParameters -> IO ()
4744convTest iterations trainFile validateFile rate = do
4845 net0 <- evalRandIO randomMnistNet
4946 fT <- T.readFile trainFile
@@ -52,7 +49,7 @@ convTest iterations trainFile validateFile rate = do
5249 let validateRows = traverse (A.parseOnly p) (T.lines fV)
5350 case (trainRows, validateRows) of
5451 (Right tr', Right vr') -> foldM_ (runIteration tr' vr') net0 [1..iterations]
55− err -> putStrLn $ show err
52+ err -> print err
5653
5754 where
5855 trainEach !rate' !nt !(i, o) = train rate' i o nt
@@ -65,20 +62,24 @@ convTest iterations trainFile validateFile rate = do
6562 return (S2D' $ SA.fromList pixels, S1D' $ SA.fromList lab')
6663
6764 runIteration trainRows validateRows net i = do
68− let trained' = runIdentity $ foldM (trainEach (rate * (0.9 ^ i))) net trainRows
69− let res = runIdentity $ traverse (\(rowP,rowL) -> (rowL,) <$> runNet trained' rowP) validateRows
65+ let trained' = foldl (trainEach rate) net trainRows
66+ let res = fmap (\(rowP,rowL) -> (rowL,) $ runNet trained' rowP) validateRows
7067 let res' = fmap (\(S1D' label, S1D' prediction) -> (maxIndex (SA.extract label), maxIndex (SA.extract prediction))) res
71− putStrLn $ show trained'
68+ print trained'
7269 putStrLn $ "Iteration " ++ show i ++ ": " ++ show (length (filter ((==) <$> fst <*> snd) res')) ++ " of " ++ show (length res')
7370 return trained'
7471
75−data MnistOpts = MnistOpts FilePath FilePath Int Double
72+data MnistOpts = MnistOpts FilePath FilePath Int LearningParameters
7673
7774mnist' :: Parser MnistOpts
78−mnist' = MnistOpts <$> (argument str (metavar "TRAIN"))
79− <*> (argument str (metavar "VALIDATE"))
75+mnist' = MnistOpts <$> argument str (metavar "TRAIN")
76+ <*> argument str (metavar "VALIDATE")
8077 <*> option auto (long "iterations" <> short 'i' <> value 15)
81− <*> option auto (long "train_rate" <> short 'r' <> value 0.01)
78+ <*> (LearningParameters
79+ <$> option auto (long "train_rate" <> short 'r' <> value 0.01)
80+ <*> option auto (long "momentum" <> value 0.9)
81+ <*> option auto (long "l2" <> value 0.0001)
82+ )
8283
8384main :: IO ()
8485main = 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+31−16
@@ -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,36 +12,53 @@
1412module Grenade.Core.Network (
1513 Layer (..)
1614 , Network (..)
15+ , UpdateLayer (..)
16+ , LearningParameters (..)
1717 ) where
1818
1919import Grenade.Core.Shape
2020
21+data LearningParameters = LearningParameters {
22+ learningRate :: Double
23+ , learningMomentum :: Double
24+ , learningRegulariser :: Double
25+ } deriving (Eq, Show)
26+
27+-- | Class for updating a layer. All layers implement this, and it is
28+-- shape independent.
29+class UpdateLayer x where
30+ -- | The type for the gradient for this layer.
31+ -- Unit if there isn't a gradient to pass back.
32+ type Gradient x :: *
33+ -- | Update a layer with its gradient and learning parameters
34+ runUpdate :: LearningParameters -> x -> Gradient x -> x
35+
2136-- | Class for a layer. All layers implement this, however, they don't
2237-- need to implement it for all shapes, only ones which are appropriate.
23−class Layer (m :: * -> *) x (i :: Shape) (o :: Shape) where
38+class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
2439 -- | Used in training and scoring. Take the input from the previous
2540 -- layer, and give the output from this layer.
26− 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)
41+ runForwards :: x -> S' i -> S' o
42+ -- | Back propagate a step. Takes the current layer, the input that the
43+ -- layer gave from the input and the back propagated derivatives from
44+ -- the layer above.
45+ -- Returns the gradient layer and the derivatives to push back further.
46+ runBackards :: x -> S' i -> S' o -> (Gradient x, S' i)
3247
3348-- | Type of a network.
3449-- The [Shape] type specifies the shapes of data passed between the layers.
3550-- Could be considered to be a heterogeneous list of layers which are able to
3651-- transform the data shapes of the network.
37−data Network :: (* -> *) -> [Shape] -> * where
38− 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)
3954 => !x
40− -> Network m '[i, o]
41− (:~>) :: (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)
4257 => !x
43− -> !(Network m (h ': hs))
44− -> Network m (i ': h ': hs)
58+ -> !(Network (h ': hs))
59+ -> Network (i ': h ': hs)
4560infixr 5 :~>
4661
47−instance Show (Network m h) where
62+instance Show (Network h) where
4863 show (O a) = "O " ++ show a
4964 show (i :~> o) = show i ++ "\n:~>\n" ++ show o
src/Grenade/Core/Runner.hs+26−23
@@ -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
@@ -17,39 +15,44 @@ import Grenade.Core.Network
1715import Grenade.Core.Shape
1816
1917-- | Update a network with new weights after training with an instance.
20−train :: forall m i o hs. (Monad m, Head hs ~ i, Last hs ~ o, KnownShape i, KnownShape o)
21− => Double -- ^ learning rate
18+train :: forall i o hs. (Head hs ~ i, Last hs ~ o, KnownShape i, KnownShape o)
19+ => LearningParameters -- ^ learning rate
2220 -> S' i -- ^ input vector
2321 -> S' o -- ^ target vector
24− -> Network m hs -- ^ network to train
25− -> m (Network m hs)
26−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
2725 where
28− 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)
2927 => S' j -- ^ input vector
30− -> Network m' js -- ^ network to train
31− -> m' (Network m' js, S' j)
28+ -> Network js -- ^ network to train
29+ -> (Network js, S' j)
3230 -- handle input from the beginning, feeding upwards.
3331 go !x (layer :~> n)
34− = do y <- runForwards layer x
32+ = let y = runForwards layer x
3533 -- run the rest of the network, and get the layer from above.
36− (n', dWs') <- go y n
34+ (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+ in (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+ = let 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+ in (O newLayer, dWs)
4751
4852-- | Just forwards propagation with no training.
49−runNet :: forall m hs. (Monad m)
50− => Network m hs
51− -> (S' (Head hs)) -- ^ input vector
52− -> m (S' (Last hs)) -- ^ target vector
53−runNet (layer :~> n) !x = do y <- runForwards layer x
54− runNet n y
53+runNet :: Network hs
54+ -> S' (Head hs) -- ^ input vector
55+ -> S' (Last hs) -- ^ target vector
56+runNet (layer :~> n) !x = let y = runForwards layer x
57+ in runNet n y
5558runNet (O layer) !x = runForwards layer x
src/Grenade/Core/Shape.hs+3−3
@@ -39,17 +39,17 @@ data Shape =
3939instance KnownShape x => Num (S' x) where
4040 (+) (S1D' x) (S1D' y) = S1D' (x + y)
4141 (+) (S2D' x) (S2D' y) = S2D' (x + y)
42− (+) (S3D' x) (S3D' y) = S3D' (vectorZip (\x' y' -> x' + y') x y)
42+ (+) (S3D' x) (S3D' y) = S3D' (vectorZip (+) x y)
4343 (+) _ _ = error "Impossible to have different constructors for the same shaped network"
4444
4545 (-) (S1D' x) (S1D' y) = S1D' (x - y)
4646 (-) (S2D' x) (S2D' y) = S2D' (x - y)
47− (-) (S3D' x) (S3D' y) = S3D' (vectorZip (\x' y' -> x' - y') x y)
47+ (-) (S3D' x) (S3D' y) = S3D' (vectorZip (-) x y)
4848 (-) _ _ = error "Impossible to have different constructors for the same shaped network"
4949
5050 (*) (S1D' x) (S1D' y) = S1D' (x * y)
5151 (*) (S2D' x) (S2D' y) = S2D' (x * y)
52− (*) (S3D' x) (S3D' y) = S3D' (vectorZip (\x' y' -> x' * y') x y)
52+ (*) (S3D' x) (S3D' y) = S3D' (vectorZip (*) x y)
5353 (*) _ _ = error "Impossible to have different constructors for the same shaped network"
5454
5555 abs (S1D' x) = S1D' (abs x)
src/Grenade/Core/Vector.hs+2−2
@@ -26,7 +26,7 @@ instance Foldable (Vector n) where
2626 foldr f b (Vector as) = foldr f b as
2727
2828instance KnownNat n => Traversable (Vector n) where
29− traverse f (Vector as) = fmap mkVector $ traverse f as
29+ traverse f (Vector as) = mkVector <$> traverse f as
3030
3131instance Functor (Vector n) where
3232 fmap f (Vector as) = Vector (fmap f as)
@@ -41,7 +41,7 @@ mkVector :: forall n a. KnownNat n => [a] -> Vector n a
4141mkVector as
4242 = let du = fromIntegral . natVal $ (undefined :: Proxy n)
4343 la = length as
44− in if (du == la)
44+ in if du == la
4545 then Vector as
4646 else error $ "Error creating staticly sized Vector of length: " ++
4747 show du ++ " list is of length:" ++ show la
src/Grenade/Layers/Convolution.hs+38−19
@@ -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 #-}
@@ -13,6 +14,7 @@
1314
1415module Grenade.Layers.Convolution (
1516 Convolution (..)
17+ , Convolution' (..)
1618 , randomConvolution
1719 , im2col
1820 , vid2col
@@ -65,6 +67,24 @@ data Convolution :: Nat -- ^ Number of channels, for the first layer this could
6567 -> !(L kernelFlattened filters) -- ^ The last kernel update (or momentum)
6668 -> Convolution channels filters kernelRows kernelColumns strideRows strideColumns
6769
70+data Convolution' :: Nat -- ^ Number of channels, for the first layer this could be RGB for instance.
71+ -> Nat -- ^ Number of filters, this is the number of channels output by the layer.
72+ -> Nat -- ^ The number of rows in the kernel filter
73+ -> Nat -- ^ The number of column in the kernel filter
74+ -> Nat -- ^ The row stride of the convolution filter
75+ -> Nat -- ^ The columns stride of the convolution filter
76+ -> * where
77+ Convolution' :: ( KnownNat channels
78+ , KnownNat filters
79+ , KnownNat kernelRows
80+ , KnownNat kernelColumns
81+ , KnownNat strideRows
82+ , KnownNat strideColumns
83+ , KnownNat kernelFlattened
84+ , kernelFlattened ~ (kernelRows * kernelColumns * channels))
85+ => !(L kernelFlattened filters) -- ^ The kernel filter gradient
86+ -> Convolution' channels filters kernelRows kernelColumns strideRows strideColumns
87+
6888instance Show (Convolution c f k k' s s') where
6989 show (Convolution a _) = renderConv a
7090 where
@@ -99,9 +119,16 @@ randomConvolution = do
99119 mm = konst 0
100120 return $ Convolution wN mm
101121
122+instance UpdateLayer (Convolution channels filters kernelRows kernelCols strideRows strideCols) where
123+ type Gradient (Convolution channels filters kernelRows kernelCols strideRows strideCols) = (Convolution' channels filters kernelRows kernelCols strideRows strideCols)
124+ runUpdate LearningParameters {..} (Convolution oldKernel oldMomentum) (Convolution' kernelGradient) =
125+ let newMomentum = konst learningMomentum * oldMomentum - konst learningRate * kernelGradient
126+ regulariser = konst (learningRegulariser * learningRate) * oldKernel
127+ newKernel = oldKernel + newMomentum - regulariser
128+ in Convolution newKernel newMomentum
129+
102130-- | A two dimentional image may have a convolution filter applied to it
103−instance ( Monad m
104− , KnownNat kernelRows
131+instance ( KnownNat kernelRows
105132 , KnownNat kernelCols
106133 , KnownNat filters
107134 , KnownNat strideRows
@@ -112,7 +139,7 @@ instance ( Monad m
112139 , KnownNat outputCols
113140 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
114141 , ((outputCols - 1) * strideCols) ~ (inputCols - kernelCols)
115− ) => 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
116143 runForwards (Convolution kernel _) (S2D' input) =
117144 let ex = extract input
118145 ek = extract kernel
@@ -126,8 +153,8 @@ instance ( Monad m
126153 mt = c LA.<> ek
127154 r = col2vid 1 1 1 1 ox oy mt
128155 rs = fmap (fromJust . create) r
129− in return . S3D' $ mkVector rs
130− runBackards rate (Convolution kernel momentum) (S2D' input) (S3D' dEdy) =
156+ in S3D' $ mkVector rs
157+ runBackards (Convolution kernel _) (S2D' input) (S3D' dEdy) =
131158 let ex = extract input
132159 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
133160 iy = fromIntegral $ natVal (Proxy :: Proxy inputCols)
@@ -145,20 +172,15 @@ instance ( Monad m
145172 vs = vid2col 1 1 1 1 ox oy eo
146173
147174 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−
152175 dW = vs LA.<> tr ek
153176
154177 xW = col2im kx ky sx sy ix iy dW
155− in return (Convolution rM mm, S2D' . fromJust . create $ xW)
178+ in (Convolution' kN, S2D' . fromJust . create $ xW)
156179
157180
158181-- | A three dimensional image (or 2d with many channels) can have
159182-- an appropriately sized convolution filter run across it.
160−instance ( Monad m
161− , KnownNat kernelRows
183+instance ( KnownNat kernelRows
162184 , KnownNat kernelCols
163185 , KnownNat filters
164186 , KnownNat strideRows
@@ -170,7 +192,7 @@ instance ( Monad m
170192 , KnownNat channels
171193 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
172194 , ((outputCols - 1) * strideCols) ~ (inputCols - kernelCols)
173− ) => 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
174196 runForwards (Convolution kernel _) (S3D' input) =
175197 let ex = vecToList $ fmap extract input
176198 ek = extract kernel
@@ -186,8 +208,8 @@ instance ( Monad m
186208 mt = c LA.<> ek
187209 r = col2vid 1 1 1 1 ox oy mt
188210 rs = fmap (fromJust . create) r
189− in return . S3D' $ mkVector rs
190− runBackards rate (Convolution kernel momentum) (S3D' input) (S3D' dEdy) =
211+ in S3D' $ mkVector rs
212+ runBackards (Convolution kernel _) (S3D' input) (S3D' dEdy) =
191213 let ex = vecToList $ fmap extract input
192214 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
193215 iy = fromIntegral $ natVal (Proxy :: Proxy inputCols)
@@ -205,14 +227,11 @@ instance ( Monad m
205227 vs = vid2col 1 1 1 1 ox oy eo
206228
207229 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
211230
212231 dW = vs LA.<> tr ek
213232
214233 xW = col2vid kx ky sx sy ix iy dW
215− in return (Convolution rM mm, S3D' . mkVector . fmap (fromJust . create) $ xW)
234+ in (Convolution' kN, S3D' . mkVector . fmap (fromJust . create) $ xW)
216235
217236im2col :: Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
218237im2col nrows ncols srows scols m =
src/Grenade/Layers/Crop.hs+9−8
@@ -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,9 +37,12 @@ data Crop :: Nat
3937instance Show (Crop cropLeft cropTop cropRight cropBottom) where
4038 show Crop = "Crop"
4139
40+instance UpdateLayer (Crop l t r b) where
41+ type Gradient (Crop l t r b) = ()
42+ runUpdate _ x _ = x
43+
4244-- | A two dimentional image can be cropped.
43−instance ( Monad m
44− , KnownNat cropLeft
45+instance ( KnownNat cropLeft
4546 , KnownNat cropTop
4647 , KnownNat cropRight
4748 , KnownNat cropBottom
@@ -51,7 +52,7 @@ instance ( Monad m
5152 , KnownNat outputColumns
5253 , (inputRows - cropTop - cropBottom) ~ outputRows
5354 , (inputColumns - cropLeft - cropRight) ~ outputColumns
54− ) => 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
5556 runForwards Crop (S2D' input) =
5657 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
5758 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
@@ -59,12 +60,12 @@ instance ( Monad m
5960 ncols = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
6061 m = extract input
6162 r = subMatrix (cropt, cropl) (nrows, ncols) m
62− in return . S2D' . fromJust . create $ r
63− runBackards _ crop _ (S2D' dEdy) =
63+ in S2D' . fromJust . create $ r
64+ runBackards _ _ (S2D' dEdy) =
6465 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
6566 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
6667 cropr = fromIntegral $ natVal (Proxy :: Proxy cropRight)
6768 cropb = fromIntegral $ natVal (Proxy :: Proxy cropBottom)
6869 eo = extract dEdy
6970 vs = diagBlock [konst 0 (cropt,cropl), eo, konst 0 (cropb,cropr)]
70− in return (crop, S2D' . fromJust . create $ vs)
71+ in ((), S2D' . fromJust . create $ vs)
src/Grenade/Layers/Dropout.hs+15−16
@@ -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,15 +9,14 @@
119
1210module Grenade.Layers.Dropout (
1311 Dropout (..)
12+ , randomDropout
1413 ) where
1514
1615import Control.Monad.Random hiding (fromList)
17−import Control.Monad.State
1816
1917import GHC.TypeLits
2018import Grenade.Core.Shape
2119import Grenade.Core.Network
22−import Grenade.Core.Phase
2320
2421import Numeric.LinearAlgebra.Static
2522
@@ -29,23 +26,25 @@ import Numeric.LinearAlgebra.Static
2926-- After backpropogation, we return a new matrix/vector, with different bits dropped out.
3027-- Double is the proportion to drop in each training iteration (like 1% or 5% would be
3128-- reasonable).
32−data Dropout o = Dropout Double (R o)
29+data Dropout o =
30+ Dropout (R o)
31+ | Pass Double
3332 deriving Show
3433
34+instance (KnownNat i) => UpdateLayer (Dropout i) where
35+ type Gradient (Dropout i) = ()
36+ runUpdate _ x _ = x
37+
3538randomDropout :: (MonadRandom m, KnownNat i)
3639 => Double -> m (Dropout i)
3740randomDropout rate = do
3841 seed <- getRandom
3942 let wN = randomVector seed Uniform
4043 xs = dvmap (\a -> if a <= rate then 0 else 1) wN
41− return $ Dropout rate xs
42−
43−instance (MonadRandom m, MonadState Phase m, KnownNat i) => Layer m (Dropout i) ('D1 i) ('D1 i) where
44− runForwards (Dropout rate drops) (S1D' x) = isTrainingPhase >>= \case
45− True -> return . S1D' $ x * drops
46− 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)
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+11−7
@@ -25,20 +25,24 @@ import Grenade.Core.Network
2525data FlattenLayer = FlattenLayer
2626 deriving Show
2727
28−instance (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)
28+instance UpdateLayer FlattenLayer where
29+ type Gradient FlattenLayer = ()
30+ runUpdate _ _ _ = FlattenLayer
3131
32−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
33− runForwards _ (S3D' y) = return $ S1D' . raiseShapeError . create . vjoin . vecToList . fmap (flatten . extract) $ y
34− runBackards _ _ _ (S1D' o) = do
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)
35+
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) =
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+ in ((), S3D' ls')
4246
4347raiseShapeError :: Maybe a -> a
4448raiseShapeError (Just x) = x
src/Grenade/Layers/FullyConnected.hs+27−14
@@ -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 #-}
@@ -24,26 +23,39 @@ import Grenade.Core.Shape
2423-- | A basic fully connected (or inner product) neural network layer.
2524data FullyConnected i o = FullyConnected
2625 !(R o) -- Bias neuron weights
26+ !(R o) -- Bias neuron momentum
2727 !(L o i) -- Activation weights
28− !(L o i) -- Activation momentums
28+ !(L o i) -- Momentum
29+
30+data FullyConnected' i o = FullyConnected'
31+ !(R o) -- Bias neuron gradient
32+ !(L o i) -- Activation gradient
2933
3034instance Show (FullyConnected i o) where
31− show (FullyConnected _ _ _) = "FullyConnected"
35+ show FullyConnected {} = "FullyConnected"
36+
37+instance (KnownNat i, KnownNat o) => UpdateLayer (FullyConnected i o) where
38+ type Gradient (FullyConnected i o) = (FullyConnected' i o)
39+
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
3247
33−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
3449 -- Do a matrix vector multiplication and return the result.
35− runForwards (FullyConnected wB wN _) (S1D' v) = return $ S1D' (wB + wN #> v)
50+ runForwards (FullyConnected wB _ wN _) (S1D' v) = S1D' (wB + wN #> v)
3651
3752 -- 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'
53+ runBackards (FullyConnected _ _ wN _) (S1D' x) (S1D' dEdy) =
54+ let wB' = dEdy
55+ mm' = dEdy `outer` x
4456 -- calcluate derivatives for next step
4557 dWs = tr wN #> dEdy
46− in return (w', S1D' dWs)
58+ in (FullyConnected' wB' mm', S1D' dWs)
4759
4860randomFullyConnected :: (MonadRandom m, KnownNat i, KnownNat o)
4961 => m (FullyConnected i o)
@@ -52,5 +64,6 @@ randomFullyConnected = do
5264 s2 :: Int <- getRandom
5365 let wB = randomVector s1 Uniform * 2 - 1
5466 wN = uniformSample s2 (-1) 1
67+ bm = konst 0
5568 mm = konst 0
56− return $ FullyConnected wB wN mm
69+ return $ FullyConnected wB bm wN mm
src/Grenade/Layers/Fuse.hs+20−14
@@ -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
27− (:$$) :: (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)
2827 => !x
2928 -> !y
30− -> Fuse m i h o
29+ -> Fuse x y i h o
3130infixr 5 :$$
3231
33−instance Show (Fuse m i h o) where
32+instance Show (Fuse 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
37− runForwards (x :$$ y) input = do
38− yInput :: S' h <- runForwards x input
39− runForwards y yInput
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)
4041
41− runBackards rate (x :$$ y) input backGradient = do
42− 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)
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+14−11
@@ -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
26−instance (Monad m, KnownNat i) => Layer m Logit ('D1 i) ('D1 i) where
27− runForwards _ (S1D' y) = return $ S1D' (logistic y)
28− runBackards _ _ (S1D' y) (S1D' dEdy) = return (Logit, S1D' (logistic' y * dEdy))
25+instance UpdateLayer Logit where
26+ type Gradient Logit = ()
27+ runUpdate _ _ _ = Logit
28+
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))
2932
30−instance (Monad m, KnownNat i, KnownNat j) => Layer m Logit ('D2 i j) ('D2 i j) where
31− runForwards _ (S2D' y) = return $ S2D' (logistic y)
32− runBackards _ _ (S2D' y) (S2D' dEdy) = return (Logit, 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))
3336
34−instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Logit ('D3 i j k) ('D3 i j k) where
35− 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))
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))
3740
3841
3942logistic :: Floating a => a -> a
src/Grenade/Layers/Pad.hs+9−8
@@ -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,9 +37,12 @@ data Pad :: Nat
3937instance Show (Pad padLeft padTop padRight padBottom) where
4038 show Pad = "Pad"
4139
40+instance UpdateLayer (Pad l t r b) where
41+ type Gradient (Pad l t r b) = ()
42+ runUpdate _ x _ = x
43+
4244-- | A two dimentional image can be padped.
43−instance ( Monad m
44− , KnownNat padLeft
45+instance ( KnownNat padLeft
4546 , KnownNat padTop
4647 , KnownNat padRight
4748 , KnownNat padBottom
@@ -51,7 +52,7 @@ instance ( Monad m
5152 , KnownNat outputColumns
5253 , (inputRows + padTop + padBottom) ~ outputRows
5354 , (inputColumns + padLeft + padRight) ~ outputColumns
54− ) => 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
5556 runForwards Pad (S2D' input) =
5657 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
5758 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
@@ -59,12 +60,12 @@ instance ( Monad m
5960 padb = fromIntegral $ natVal (Proxy :: Proxy padBottom)
6061 m = extract input
6162 r = diagBlock [konst 0 (padt,padl), m, konst 0 (padb,padr)]
62− in return . S2D' . fromJust . create $ r
63− runBackards _ pad _ (S2D' dEdy) =
63+ in S2D' . fromJust . create $ r
64+ runBackards Pad _ (S2D' dEdy) =
6465 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
6566 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
6667 nrows = fromIntegral $ natVal (Proxy :: Proxy inputRows)
6768 ncols = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
6869 m = extract dEdy
6970 vs = subMatrix (padt, padl) (nrows, ncols) m
70− in return (pad, S2D' . fromJust . create $ vs)
71+ in ((), S2D' . fromJust . create $ vs)
src/Grenade/Layers/Pooling.hs+14−12
@@ -51,9 +51,12 @@ instance Show (Pooling k k' s s') where
5151 show Pooling = "Pooling"
5252
5353
54+instance UpdateLayer (Pooling kernelRows kernelColumns strideRows strideColumns) where
55+ type Gradient (Pooling kr kc sr sc) = ()
56+ runUpdate _ Pooling _ = Pooling
57+
5458-- | A two dimentional image can be pooled.
55−instance ( Monad m
56− , KnownNat kernelRows
59+instance ( KnownNat kernelRows
5760 , KnownNat kernelColumns
5861 , KnownNat strideRows
5962 , KnownNat strideColumns
@@ -63,7 +66,7 @@ instance ( Monad m
6366 , KnownNat outputColumns
6467 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
6568 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
66− ) => 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
6770 runForwards Pooling (S2D' input) =
6871 let kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
6972 ky = fromIntegral $ natVal (Proxy :: Proxy kernelColumns)
@@ -74,8 +77,8 @@ instance ( Monad m
7477 ex = extract input
7578 r = poolForward kx ky sx sy ox oy $ ex
7679 rs = fromJust . create $ r
77− in return . S2D' $ rs
78− runBackards _ Pooling (S2D' input) (S2D' dEdy) =
80+ in S2D' $ rs
81+ runBackards Pooling (S2D' input) (S2D' dEdy) =
7982 let kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
8083 ky = fromIntegral $ natVal (Proxy :: Proxy kernelColumns)
8184 sx = fromIntegral $ natVal (Proxy :: Proxy strideRows)
@@ -83,12 +86,11 @@ instance ( Monad m
8386 ex = extract input
8487 eo = extract dEdy
8588 vs = poolBackward kx ky sx sy ex eo
86− in return (Pooling, S2D' . fromJust . create $ vs)
89+ in ((), S2D' . fromJust . create $ vs)
8790
8891
8992-- | A three dimensional image can be pooled on each layer.
90−instance ( Monad m
91− , KnownNat kernelRows
93+instance ( KnownNat kernelRows
9294 , KnownNat kernelColumns
9395 , KnownNat strideRows
9496 , KnownNat strideColumns
@@ -98,7 +100,7 @@ instance ( Monad m
98100 , KnownNat outputColumns
99101 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
100102 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
101− ) => 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
102104 runForwards Pooling (S3D' input) =
103105 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
104106 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -111,8 +113,8 @@ instance ( Monad m
111113 ex = fmap extract input
112114 r = poolForwardList kx ky sx sy ix iy ox oy ex
113115 rs = fmap (fromJust . create) r
114− in return . S3D' $ rs
115− runBackards _ Pooling (S3D' input) (S3D' dEdy) =
116+ in S3D' rs
117+ runBackards Pooling (S3D' input) (S3D' dEdy) =
116118 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
117119 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
118120 kx = fromIntegral $ natVal (Proxy :: Proxy kernelRows)
@@ -123,7 +125,7 @@ instance ( Monad m
123125 eo = fmap extract dEdy
124126 ez = vectorZip (,) ex eo
125127 vs = poolBackwardList kx ky sx sy ix iy ez
126− in return (Pooling, S3D' . fmap (fromJust . create) $ vs)
128+ in ((), S3D' . fmap (fromJust . create) $ vs)
127129
128130poolForward :: Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
129131poolForward nrows ncols srows scols outputRows outputCols m =
src/Grenade/Layers/Relu.hs+13−11
@@ -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,26 +22,30 @@ import qualified Numeric.LinearAlgebra.Static as LAS
2422data Relu = Relu
2523 deriving Show
2624
27−instance (Monad m, KnownNat i) => Layer m Relu ('D1 i) ('D1 i) where
28− runForwards _ (S1D' y) = return $ S1D' (relu y)
25+instance UpdateLayer Relu where
26+ type Gradient Relu = ()
27+ runUpdate _ _ _ = Relu
28+
29+instance ( KnownNat i) => Layer Relu ('D1 i) ('D1 i) where
30+ runForwards _ (S1D' y) = 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) = ((), S1D' (relu' y * dEdy))
3234 where
3335 relu' = LAS.dvmap (\a -> if a <= 0 then 0 else 1)
3436
35−instance (Monad m, KnownNat i, KnownNat j) => Layer m Relu ('D2 i j) ('D2 i j) where
36− 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)
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) = ((), S2D' (relu' y * dEdy))
4042 where
4143 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
4244
43−instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Relu ('D3 i j k) ('D3 i j k) where
44− 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)
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) = ((), 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+13−11
@@ -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
24−instance (Monad m, KnownNat i) => Layer m Tanh ('D1 i) ('D1 i) where
25− runForwards _ (S1D' y) = return $ S1D' (tanh y)
26− runBackards _ _ (S1D' y) (S1D' dEdy) = return (Tanh, S1D' (tanh' y * dEdy))
22+instance UpdateLayer Tanh where
23+ type Gradient Tanh = ()
24+ runUpdate _ _ _ = Tanh
2725
28−instance (Monad m, KnownNat i, KnownNat j) => Layer m Tanh ('D2 i j) ('D2 i j) where
29− runForwards _ (S2D' y) = return $ S2D' (tanh y)
30− runBackards _ _ (S2D' y) (S2D' dEdy) = return (Tanh, S2D' (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))
3129
32−instance (Monad m, KnownNat i, KnownNat j, KnownNat k) => Layer m Tanh ('D3 i j k) ('D3 i j k) where
33− 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))
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))
33+
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))
3537
3638tanh' :: (Floating a) => a -> a
3739tanh' t = 1 - s ^ (2 :: Int) where s = tanh t
test/Test/Grenade/Layers/Convolution.hs+20−19
@@ -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
@@ -93,11 +91,12 @@ prop_simple_conv_forwards = once $
9391 , 0.0, 0.0, 0.0, 0.0
9492 , 0.0, 0.0, 0.0, 0.0
9593 , 0.0, 0.0, 0.0, 0.0 ] :: HStatic.L 4 4)
96− --expectedKernel = (HStatic.matrix
97− -- [ 0.0, 0.0, 0.0, -2.0
98− -- ,-2.0, 1.0, 1.0, -5.0
99− -- ,-3.0, -1.0, 1.0, -5.0
100− -- ,-5.0, 0.0, 0.0, -7.0 ] :: HStatic.L 4 4)
94+
95+ expectedGradient = (HStatic.matrix
96+ [ 1.0, 0.0, 0.0, 2.0
97+ , 2.0, 0.0, 0.0, 5.0
98+ , 3.0, 0.0, 0.0, 4.0
99+ , 4.0, 0.0, 0.0, 6.0 ] :: HStatic.L 4 4)
101100
102101 convLayer = Convolution myKernel zeroKernel :: Convolution 1 4 2 2 1 1
103102
@@ -113,7 +112,7 @@ prop_simple_conv_forwards = once $
113112 [ 5.0 , 9.0 ] :: HStatic.L 1 2)
114113 ,(HStatic.matrix
115114 [ -7.0 , -10.0 ] :: HStatic.L 1 2)]) :: [HStatic.L 1 2]
116− out = runIdentity $ runForwards convLayer input :: S' ('D3 1 2 4)
115+ out = runForwards convLayer input :: S' ('D3 1 2 4)
117116
118117 grad = S3D' ( mkVector
119118 [(HStatic.matrix
@@ -128,12 +127,13 @@ prop_simple_conv_forwards = once $
128127 expectBack = (HStatic.matrix
129128 [ 1.0, 0.0, 0.0
130129 , 0.0, -2.0,-1.0] :: HStatic.L 2 3)
131− (nc, inX) = runIdentity $ runBackards 1 convLayer input grad :: ( Convolution 1 4 2 2 1 1 , S' ('D2 2 3))
130+ (nc, inX) = runBackards convLayer input grad
132131
133132 in case (out, inX, nc) of
134− (S3D' out' , S2D' inX', Convolution _ _)
133+ (S3D' out' , S2D' inX', Convolution' backGrad)
135134 -> ((HStatic.extract <$> expect) === (HStatic.extract <$> vecToList out'))
136135 .&&. ((HStatic.extract expectBack) === (HStatic.extract inX'))
136+ .&&. ((HStatic.extract expectedGradient) === (HStatic.extract backGrad))
137137 -- Temporarily disabled, as l2 adjustment puts in off 5%
138138 -- .&&. HStatic.extract expectedKernel === HStatic.extract kernel'
139139
@@ -203,11 +203,12 @@ prop_single_conv_forwards = once $
203203 , 0.0, 0.0, 0.0, 0.0
204204 , 0.0, 0.0, 0.0, 0.0
205205 , 0.0, 0.0, 0.0, 0.0 ] :: HStatic.L 4 4)
206− --expectedKernel = (HStatic.matrix
207− -- [ 0.0, 0.0, 0.0, -2.0
208− -- ,-2.0, 1.0, 1.0, -5.0
209− -- ,-3.0, -1.0, 1.0, -5.0
210− -- ,-5.0, 0.0, 0.0, -7.0 ] :: HStatic.L 4 4)
206+
207+ expectedGradient = (HStatic.matrix
208+ [ 1.0, 0.0, 0.0, 2.0
209+ , 2.0, 0.0, 0.0, 5.0
210+ , 3.0, 0.0, 0.0, 4.0
211+ , 4.0, 0.0, 0.0, 6.0 ] :: HStatic.L 4 4)
211212
212213 convLayer = Convolution myKernel zeroKernel :: Convolution 1 4 2 2 1 1
213214
@@ -223,7 +224,7 @@ prop_single_conv_forwards = once $
223224 [ 5.0 , 9.0 ] :: HStatic.L 1 2)
224225 ,(HStatic.matrix
225226 [ -7.0 , -10.0 ] :: HStatic.L 1 2)]) :: [HStatic.L 1 2]
226− out = runIdentity $ runForwards convLayer input :: S' ('D3 1 2 4)
227+ out = runForwards convLayer input :: S' ('D3 1 2 4)
227228
228229 grad = S3D' ( mkVector
229230 [(HStatic.matrix
@@ -238,13 +239,13 @@ prop_single_conv_forwards = once $
238239 expectBack = (HStatic.matrix
239240 [ 1.0, 0.0, 0.0
240241 , 0.0, -2.0,-1.0] :: HStatic.L 2 3)
241− (nc, inX) = runIdentity $ runBackards 1 convLayer input grad :: ( Convolution 1 4 2 2 1 1 , S' ('D3 2 3 1))
242+ (nc, inX) = runBackards convLayer input grad
242243
243244 in case (out, inX, nc) of
244− (S3D' out' , S3D' inX', Convolution _ _)
245+ (S3D' out' , S3D' inX', Convolution' backGrad)
245246 -> ((HStatic.extract <$> expect) === (HStatic.extract <$> vecToList out'))
246247 .&&. ([HStatic.extract expectBack] === (HStatic.extract <$> vecToList inX'))
247− -- .&&. HStatic.extract expectedKernel === HStatic.extract kernel'
248+ .&&. ((HStatic.extract expectedGradient) === (HStatic.extract backGrad))
248249
249250return []
250251tests :: IO Bool