on master help sign in
Merge pull request #22 from HuwCampbell/topic/tape

Topic/tape

commit7e47a6ad7e9ac6df9d66634a2c950dfb838781e2 authorHuw Campbell <huw.campbell@gmail.com> dateSat 4 Feb 2017, 00:04 (10 years ago) parent51ae147c2d48a3
50 files changed+1348−466
README.md+15−6 bench/bench-lstm.hs+9−10 bench/bench.hs+47−18 cbits/pad.c+39 cbits/pad.h+13 grenade.cabal+25−13 mafia+1−1 main/feedforward.hs+1 main/mnist.hs+2−1 main/recurrent.hs+12−5 main/shakespeare.hs+1 src/Grenade.hs+10−5 src/Grenade/Core.hs+8 src/Grenade/Core/Layer.hs+71 src/Grenade/Core/LearningParameters.hs+10 src/Grenade/Core/Network.hs+149−68 src/Grenade/Core/Runner.hs+23−45 src/Grenade/Core/Shape.hs+31−10 src/Grenade/Layers/Concat.hs+125 src/Grenade/Layers/Convolution.hs+7−4 src/Grenade/Layers/Crop.hs+50−3 src/Grenade/Layers/Dropout.hs+14−23 src/Grenade/Layers/Elu.hs+60 src/Grenade/Layers/Flatten.hs−53 src/Grenade/Layers/FullyConnected.hs+14−15 src/Grenade/Layers/Fuse.hs−47 src/Grenade/Layers/Inception.hs+48 src/Grenade/Layers/Internal/Pad.hs+54 src/Grenade/Layers/Logit.hs+7−14 src/Grenade/Layers/Merge.hs+55 src/Grenade/Layers/Pad.hs+49−3 src/Grenade/Layers/Pooling.hs+5−4 src/Grenade/Layers/Relu.hs+11−5 src/Grenade/Layers/Reshape.hs+60 src/Grenade/Layers/Softmax.hs+53 src/Grenade/Layers/Tanh.hs+7−14 src/Grenade/Recurrent/Layers/Trivial.hs → src/Grenade/Layers/Trivial.hs+1−1 src/Grenade/Recurrent.hs−1 src/Grenade/Recurrent/Core/Network.hs+38−30 src/Grenade/Recurrent/Core/Runner.hs+36−41 src/Grenade/Recurrent/Layers/BasicRecurrent.hs+5−4 src/Grenade/Recurrent/Layers/LSTM.hs+5−5 test/Test/Grenade/Layers/Convolution.hs+3−4 test/Test/Grenade/Layers/FullyConnected.hs+4−5 test/Test/Grenade/Layers/Nonlinear.hs+72 test/Test/Grenade/Layers/PadCrop.hs+34 test/Test/Grenade/Recurrent/Layers/LSTM.hs+7−7 test/Test/Jack/Hmatrix.hs+12 test/Test/Jack/TypeLits.hs+41−1 test/test.hs+4
README.md+15−6
@@ -16,8 +16,10 @@ for concise and precise specifications of complex networks in Haskell.
1616As an example, a network which can achieve ~1.5% error on MNIST can be
1717specified and initialised with random weights in a few lines of code with
1818```haskell
19−type MNIST = Network '[ Convolution 1 10 5 5 1 1, Pooling 2 2 2 2, Relu, Convolution 10 16 5 5 1 1, Pooling 2 2 2 2, FlattenLayer, Relu, FullyConnected 256 80, Logit, FullyConnected 80 10, Logit]
20− '[ '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+type MNIST
20+ = Network
21+ '[ Convolution 1 10 5 5 1 1, Pooling 2 2 2 2, Relu, Convolution 10 16 5 5 1 1, Pooling 2 2 2 2, FlattenLayer, Relu, FullyConnected 256 80, Logit, FullyConnected 80 10, Logit]
22+ '[ '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]
2123
2224randomMnist :: MonadRandom m => m MNIST
2325randomMnist = randomNetwork
@@ -31,8 +33,10 @@ If recurrent neural networks are more your style, you can try defining something
3133["unreasonably effective"](http://karpathy.github.io/2015/05/21/rnn-effectiveness/)
3234with
3335```haskell
34−type Shakespeare = RecurrentNetwork '[ R (LSTM 40 80), R (LSTM 80 40), F (FullyConnected 40 40), F Logit]
35− '[ 'D1 40, 'D1 80, 'D1 40, 'D1 40, 'D1 40 ]
36+type Shakespeare
37+ = RecurrentNetwork
38+ '[ R (LSTM 40 80), R (LSTM 80 40), F (FullyConnected 40 40), F Logit]
39+ '[ 'D1 40, 'D1 80, 'D1 40, 'D1 40, 'D1 40 ]
3640```
3741
3842Design
@@ -45,8 +49,13 @@ data that are passed between the layers.
4549The definition of a network is surprisingly simple:
4650```haskell
4751data Network :: [*] -> [Shape] -> * where
48− O :: (SingI i, SingI o, Layer x i o) => !x -> Network '[x] '[i, o]
49− (:~>) :: (SingI i, SingI h, Layer x i h) => !x -> !(Network xs (h ': hs)) -> Network (x ': xs) (i ': h ': hs)
52+ NNil :: SingI i
53+ => Network '[] '[i]
54+
55+ (:~>) :: (SingI i, SingI h, Layer x i h)
56+ => !x
57+ -> !(Network xs (h ': hs))
58+ -> Network (x ': xs) (i ': h ': hs)
5059```
5160
5261The `Layer x i o` constraint ensures that the layer `x` can sensibly perform a
bench/bench-lstm.hs+9−10
@@ -22,8 +22,8 @@ main = do
2222 let upIn512 :: H.R 262144 = H.randomVector 1 H.Uniform * 2 - 1
2323
2424 defaultMain [
25− bgroup "lstm" [ bench "forwards-60" $ nf (nfT2 . uncurry (testRun60 layer60)) (rec60, input40)
26− , bench "forwards-512" $ nf (nfT2 . uncurry (testRun512 layer512)) (rec512, input40)
25+ bgroup "lstm" [ bench "forwards-60" $ nf (nfT3 . uncurry (testRun60 layer60)) (rec60, input40)
26+ , bench "forwards-512" $ nf (nfT3 . uncurry (testRun512 layer512)) (rec512, input40)
2727 , bench "backwards-60" $ nf (nfT3 . uncurry4 (testRun60' layer60)) (rec60, input40, rec60, rec60)
2828 , bench "backwards-512" $ nf (nfT3 . uncurry4 (testRun512' layer512)) (rec512, input40, rec512, rec512)
2929 ]
@@ -36,17 +36,17 @@ main = do
3636 ]
3737 ]
3838
39−testRun60 :: LSTM 40 60 -> S ('D1 60) -> S ('D1 40) -> (S ('D1 60), S ('D1 60))
39+testRun60 :: LSTM 40 60 -> S ('D1 60) -> S ('D1 40) -> ((S ('D1 60), S ('D1 40)), S ('D1 60), S ('D1 60))
4040testRun60 = runRecurrentForwards
4141
4242testRun60' :: LSTM 40 60 -> S ('D1 60) -> S ('D1 40) -> S ('D1 60) -> S ('D1 60) -> (Gradient (LSTM 40 60), S ('D1 60), S ('D1 40))
43−testRun60' = runRecurrentBackwards
43+testRun60' = curry . runRecurrentBackwards
4444
45−testRun512 :: LSTM 40 512 -> S ('D1 512) -> S ('D1 40) -> (S ('D1 512), S ('D1 512))
45+testRun512 :: LSTM 40 512 -> S ('D1 512) -> S ('D1 40) -> ((S ('D1 512), S ('D1 40)), S ('D1 512), S ('D1 512))
4646testRun512 = runRecurrentForwards
4747
4848testRun512' :: LSTM 40 512 -> S ('D1 512) -> S ('D1 40) -> S ('D1 512) -> S ('D1 512) -> (Gradient (LSTM 40 512), S ('D1 512), S ('D1 40))
49−testRun512' = runRecurrentBackwards
49+testRun512' = curry . runRecurrentBackwards
5050
5151uncurry4 :: (t -> t1 -> t2 -> t3 -> t4) -> (t, t1, t2, t3) -> t4
5252uncurry4 f (a,b,c,d) = f a b c d
@@ -61,12 +61,11 @@ nfT3 :: (a, b, c) -> (b, c)
6161nfT3 (!_, !b, !c) = (b, c)
6262
6363
64−type F = FeedForward
6564type R = Recurrent
66−type RecNet = RecurrentNetwork '[ R (LSTM 40 512), R (LSTM 512 40), F (FullyConnected 40 40), F Logit]
67− '[ 'D1 40, 'D1 512, 'D1 40, 'D1 40, 'D1 40 ]
65+type RecNet = RecurrentNetwork '[ R (LSTM 40 512), R (LSTM 512 40) ]
66+ '[ 'D1 40, 'D1 512, 'D1 40 ]
6867
69−type RecInput = RecurrentInputs '[ R (LSTM 40 512), R (LSTM 512 40), F (FullyConnected 40 40), F Logit]
68+type RecInput = RecurrentInputs '[ R (LSTM 40 512), R (LSTM 512 40) ]
7069
7170lp :: LearningParameters
7271lp = LearningParameters 0.1 0 0
bench/bench.hs+47−18
@@ -1,26 +1,55 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
13import Criterion.Main
24
5+import Grenade
6+
37import Grenade.Layers.Internal.Convolution
48import Grenade.Layers.Internal.Pooling
59
610import Numeric.LinearAlgebra
711
812main :: IO ()
9−main = defaultMain [
10− bgroup "im2col" [ bench "im2col 3x4" $ whnf (im2col 2 2 1 1) ((3><4) [1..])
11− , bench "im2col 28x28" $ whnf (im2col 5 5 1 1) ((28><28) [1..])
12− , bench "im2col 100x100" $ whnf (im2col 10 10 1 1) ((100><100) [1..])
13− ]
14− , bgroup "col2im" [ bench "col2im 3x4" $ whnf (col2im 2 2 1 1 3 4) ((6><4) [1..])
15− , bench "col2im 28x28" $ whnf (col2im 5 5 1 1 28 28) ((576><25) [1..])
16− , bench "col2im 100x100" $ whnf (col2im 10 10 1 1 100 100) ((8281><100) [1..])
17− ]
18− , bgroup "poolfw" [ bench "poolforwards 3x4" $ whnf (poolForward 1 3 4 2 2 1 1) ((3><4) [1..])
19− , bench "poolforwards 28x28" $ whnf (poolForward 1 28 28 5 5 1 1) ((28><28) [1..])
20− , bench "poolforwards 100x100" $ whnf (poolForward 1 100 100 10 10 1 1) ((100><100) [1..])
21− ]
22− , bgroup "poolbw" [ bench "poolbackwards 3x4" $ whnf (poolBackward 1 3 4 2 2 1 1 ((3><4) [1..])) ((2><3) [1..])
23− , bench "poolbackwards 28x28" $ whnf (poolBackward 1 28 28 5 5 1 1 ((28><28) [1..])) ((24><24) [1..])
24− , bench "poolbackwards 100x100" $ whnf (poolBackward 1 100 100 10 10 1 1 ((100><100) [1..])) ((91><91) [1..])
25− ]
26− ]
13+main = do
14+ x :: S ('D2 60 60 ) <- randomOfShape
15+ y :: S ('D3 60 60 1) <- randomOfShape
16+
17+ defaultMain [
18+ bgroup "im2col" [ bench "im2col 3x4" $ whnf (im2col 2 2 1 1) ((3><4) [1..])
19+ , bench "im2col 28x28" $ whnf (im2col 5 5 1 1) ((28><28) [1..])
20+ , bench "im2col 100x100" $ whnf (im2col 10 10 1 1) ((100><100) [1..])
21+ ]
22+ , bgroup "col2im" [ bench "col2im 3x4" $ whnf (col2im 2 2 1 1 3 4) ((6><4) [1..])
23+ , bench "col2im 28x28" $ whnf (col2im 5 5 1 1 28 28) ((576><25) [1..])
24+ , bench "col2im 100x100" $ whnf (col2im 10 10 1 1 100 100) ((8281><100) [1..])
25+ ]
26+ , bgroup "poolfw" [ bench "poolforwards 3x4" $ whnf (poolForward 1 3 4 2 2 1 1) ((3><4) [1..])
27+ , bench "poolforwards 28x28" $ whnf (poolForward 1 28 28 5 5 1 1) ((28><28) [1..])
28+ , bench "poolforwards 100x100" $ whnf (poolForward 1 100 100 10 10 1 1) ((100><100) [1..])
29+ ]
30+ , bgroup "poolbw" [ bench "poolbackwards 3x4" $ whnf (poolBackward 1 3 4 2 2 1 1 ((3><4) [1..])) ((2><3) [1..])
31+ , bench "poolbackwards 28x28" $ whnf (poolBackward 1 28 28 5 5 1 1 ((28><28) [1..])) ((24><24) [1..])
32+ , bench "poolbackwards 100x100" $ whnf (poolBackward 1 100 100 10 10 1 1 ((100><100) [1..])) ((91><91) [1..])
33+ ]
34+ , bgroup "padcrop" [ bench "pad 2D 60x60" $ whnf (testRun2D Pad) x
35+ , bench "pad 3D 60x60" $ whnf (testRun3D Pad) y
36+ , bench "crop 2D 60x60" $ whnf (testRun2D' Crop) x
37+ , bench "crop 3D 60x60" $ whnf (testRun3D' Crop) y
38+ ]
39+ ]
40+
41+
42+testRun2D :: Pad 1 1 1 1 -> S ('D2 60 60) -> S ('D2 62 62)
43+testRun2D = snd ... runForwards
44+
45+testRun3D :: Pad 1 1 1 1 -> S ('D3 60 60 1) -> S ('D3 62 62 1)
46+testRun3D = snd ... runForwards
47+
48+testRun2D' :: Crop 1 1 1 1 -> S ('D2 60 60) -> S ('D2 58 58)
49+testRun2D' = snd ... runForwards
50+
51+testRun3D' :: Crop 1 1 1 1 -> S ('D3 60 60 1) -> S ('D3 58 58 1)
52+testRun3D' = snd ... runForwards
53+
54+(...) :: (a -> b) -> (c -> d -> a) -> c -> d -> b
55+(...) = (.) . (.)
cbits/pad.cnew file+39
@@ -0,0 +1,39 @@
1+#include "pad.h"
2+
3+void pad_cpu(double* data, const int channels,
4+ const int height, const int width, const int pad_left, const int pad_top,
5+ const int pad_right, const int pad_bottom,
6+ double* data_padded) {
7+
8+ const int pad_width = width + pad_left + pad_right;
9+ const int pad_height = height + pad_top + pad_bottom;
10+
11+ memset(data_padded, 0, pad_height * pad_width * channels * sizeof(double));
12+
13+ for (int channel = 0; channel < channels; channel++) {
14+ double* px = data_padded + (pad_width * pad_top + pad_left) + channel * (pad_width * pad_height);
15+ for (int y = 0; y < height; y++) {
16+ memcpy(px, data, sizeof(double) * width);
17+ px += pad_width;
18+ data += width;
19+ }
20+ }
21+}
22+
23+void crop_cpu(double* data, const int channels,
24+ const int height, const int width, const int crop_left, const int crop_top,
25+ const int crop_right, const int crop_bottom,
26+ double* data_cropped) {
27+
28+ const int crop_width = width + crop_left + crop_right;
29+ const int crop_height = height + crop_top + crop_bottom;
30+
31+ for (int channel = 0; channel < channels; channel++) {
32+ double* px = data + (crop_width * crop_top + crop_left) + channel * (crop_width * crop_height);
33+ for (int y = 0; y < height; y++) {
34+ memcpy(data_cropped, px, sizeof(double) * width);
35+ px += crop_width;
36+ data_cropped += width;
37+ }
38+ }
39+}
cbits/pad.hnew file+13
@@ -0,0 +1,13 @@
1+#include <stdio.h>
2+#include <stdint.h>
3+#include <string.h>
4+
5+void pad_cpu(double* data_im, const int channels,
6+ const int height, const int width, const int pad_left, const int pad_top,
7+ const int pad_right, const int pad_bottom,
8+ double* data_col);
9+
10+void crop_cpu(double* data_im, const int channels,
11+ const int height, const int width, const int crop_left, const int crop_top,
12+ const int crop_right, const int crop_bottom,
13+ double* data_col);
grenade.cabal+25−13
@@ -13,27 +13,28 @@ description: grenade.
1313extra-source-files:
1414 cbits/im2col.h
1515 cbits/im2col.c
16+ cbits/gradient_decent.h
17+ cbits/gradient_decent.c
18+ cbits/pad.h
19+ cbits/pad.c
1620
1721library
1822 build-depends:
1923 base >= 4.8 && < 5
2024 , bytestring == 0.10.*
21− , async
2225 , containers
2326 , deepseq
2427 , either == 4.4.*
2528 , cereal
2629 , exceptions == 0.8.*
27− , hmatrix
30+ , hmatrix == 0.18.*
2831 , MonadRandom
2932 , mtl >= 2.2.1 && < 2.3
30− , parallel == 3.2.*
3133 , primitive
32− , reflection
3334 , text == 1.2.*
3435 , transformers
35− , singletons
36− , vector
36+ , singletons >= 2.1 && < 2.3
37+ , vector == 0.11.*
3738
3839 ghc-options:
3940 -Wall
@@ -43,22 +44,28 @@ library
4344
4445 exposed-modules:
4546 Grenade
47+ Grenade.Core
48+ Grenade.Core.Layer
49+ Grenade.Core.LearningParameters
4650 Grenade.Core.Network
4751 Grenade.Core.Runner
4852 Grenade.Core.Shape
4953 Grenade.Layers.Crop
54+ Grenade.Layers.Concat
5055 Grenade.Layers.Convolution
5156 Grenade.Layers.Dropout
5257 Grenade.Layers.FullyConnected
53− Grenade.Layers.Flatten
54− Grenade.Layers.Fuse
58+ Grenade.Layers.Reshape
5559 Grenade.Layers.Logit
60+ Grenade.Layers.Merge
5661 Grenade.Layers.Relu
62+ Grenade.Layers.Elu
5763 Grenade.Layers.Tanh
5864 Grenade.Layers.Pad
5965 Grenade.Layers.Pooling
6066
6167 Grenade.Layers.Internal.Convolution
68+ Grenade.Layers.Internal.Pad
6269 Grenade.Layers.Internal.Pooling
6370 Grenade.Layers.Internal.Update
6471
@@ -69,14 +76,15 @@ library
6976
7077 Grenade.Recurrent.Layers.BasicRecurrent
7178 Grenade.Recurrent.Layers.LSTM
72− Grenade.Recurrent.Layers.Trivial
7379
7480 Grenade.Utils.OneHot
7581
7682 includes: cbits/im2col.h
7783 cbits/gradient_decent.h
84+ cbits/pad.h
7885 c-sources: cbits/im2col.c
7986 cbits/gradient_decent.c
87+ cbits/pad.c
8088
8189 cc-options: -std=c99 -O3 -msse4.2 -Wall -Werror -DCABAL=1
8290
@@ -89,12 +97,13 @@ executable feedforward
8997 , bytestring
9098 , cereal
9199 , either
92− , optparse-applicative == 0.12.*
100+ , optparse-applicative == 0.13.*
93101 , text == 1.2.*
94102 , mtl >= 2.2.1 && < 2.3
95103 , hmatrix
96104 , transformers
97105 , singletons
106+ , semigroups
98107 , MonadRandom
99108
100109executable mnist
@@ -104,11 +113,12 @@ executable mnist
104113 , grenade
105114 , attoparsec
106115 , either
107− , optparse-applicative == 0.12.*
116+ , optparse-applicative == 0.13.*
108117 , text == 1.2.*
109118 , mtl >= 2.2.1 && < 2.3
110119 , hmatrix >= 0.18 && < 0.19
111120 , transformers
121+ , semigroups
112122 , singletons
113123 , MonadRandom
114124 , vector
@@ -120,11 +130,12 @@ executable recurrent
120130 , grenade
121131 , attoparsec
122132 , either
123− , optparse-applicative == 0.12.*
133+ , optparse-applicative == 0.13.*
124134 , text == 1.2.*
125135 , mtl >= 2.2.1 && < 2.3
126136 , hmatrix >= 0.18 && < 0.19
127137 , transformers
138+ , semigroups
128139 , singletons
129140 , MonadRandom
130141
@@ -138,11 +149,12 @@ executable shakespeare
138149 , bytestring
139150 , cereal
140151 , either
141− , optparse-applicative == 0.12.*
152+ , optparse-applicative == 0.13.*
142153 , text == 1.2.*
143154 , mtl >= 2.2.1 && < 2.3
144155 , hmatrix >= 0.18 && < 0.19
145156 , transformers
157+ , semigroups
146158 , singletons
147159 , vector
148160 , MonadRandom
mafia+1−1
@@ -120,4 +120,4 @@ case "$MODE" in
120120upgrade) shift; run_upgrade "$@" ;;
121121*) exec_mafia "$@"
122122esac
123−# Version: 3044e63eb472fb9e16926d4ab2ca9dd9e255829c
123+# Version: 360716306a06db842ec022a7b9f161d2208483f0
main/feedforward.hs+1
@@ -10,6 +10,7 @@ import Data.List ( foldl' )
1010
1111import qualified Data.ByteString as B
1212import Data.Serialize
13+import Data.Semigroup ( (<>) )
1314
1415import GHC.TypeLits
1516
main/mnist.hs+2−1
@@ -12,6 +12,7 @@ import Control.Monad.Trans.Except
1212
1313import qualified Data.Attoparsec.Text as A
1414import Data.List ( foldl' )
15+import Data.Semigroup ( (<>) )
1516import qualified Data.Text as T
1617import qualified Data.Text.IO as T
1718import qualified Data.Vector.Storable as V
@@ -33,7 +34,7 @@ import Grenade.Utils.OneHot
3334
3435-- With the mnist data from Kaggle normalised to doubles between 0 and 1, learning rate of 0.01 and 15 iterations,
3536-- this network should get down to about a 1.3% error rate.
36−type MNIST = Network '[ Convolution 1 10 5 5 1 1, Pooling 2 2 2 2, Relu, Convolution 10 16 5 5 1 1, Pooling 2 2 2 2, FlattenLayer, Relu, FullyConnected 256 80, Logit, FullyConnected 80 10, Logit]
37+type MNIST = Network '[ Convolution 1 10 5 5 1 1, Pooling 2 2 2 2, Relu, Convolution 10 16 5 5 1 1, Pooling 2 2 2 2, Reshape, Relu, FullyConnected 256 80, Logit, FullyConnected 80 10, Logit]
3738 '[ '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]
3839
3940randomMnist :: MonadRandom m => m MNIST
main/recurrent.hs+12−5
@@ -1,4 +1,5 @@
11{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE CPP #-}
23{-# LANGUAGE DataKinds #-}
34{-# LANGUAGE ScopedTypeVariables #-}
45{-# LANGUAGE TypeOperators #-}
@@ -8,7 +9,13 @@
89import Control.Monad ( foldM )
910import Control.Monad.Random ( MonadRandom, getRandomR )
1011
12+#if __GLASGOW_HASKELL__ < 800
13+import Data.List ( unfoldr )
14+#else
1115import Data.List ( cycle, unfoldr )
16+#endif
17+import Data.Semigroup ( (<>) )
18+
1219import qualified Numeric.LinearAlgebra.Static as SA
1320
1421import Options.Applicative
@@ -16,19 +23,19 @@ import Options.Applicative
1623import Grenade
1724import Grenade.Recurrent
1825
26+{-# OPTIONS_GHC -fno-redundant-imports #-}
1927-- The defininition for our simple recurrent network.
2028-- This file just trains a network to generate a repeating sequence
2129-- of 0 0 1.
2230--
2331-- The F and R types are Tagging types to ensure that the runner and
2432-- creation function know how to treat the layers.
25−type F = FeedForward
2633type R = Recurrent
2734
28−type RecNet = RecurrentNetwork '[ R (LSTM 1 4), R (LSTM 4 1), F Trivial]
29− '[ 'D1 1, 'D1 4, 'D1 1, 'D1 1 ]
35+type RecNet = RecurrentNetwork '[ R (LSTM 1 4), R (LSTM 4 1)]
36+ '[ 'D1 1, 'D1 4, 'D1 1 ]
3037
31−type RecInput = RecurrentInputs '[ R (LSTM 1 4), R (LSTM 4 1), F Trivial]
38+type RecInput = RecurrentInputs '[ R (LSTM 1 4), R (LSTM 4 1)]
3239
3340randomNet :: MonadRandom m => m (RecNet, RecInput)
3441randomNet = randomRecurrent
@@ -51,7 +58,7 @@ netTest net0 i0 rate iterations =
5158data FeedForwardOpts = FeedForwardOpts Int LearningParameters
5259
5360feedForward' :: Parser FeedForwardOpts
54−feedForward' = FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 20000)
61+feedForward' = FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 40000)
5562 <*> (LearningParameters
5663 <$> option auto (long "train_rate" <> short 'r' <> value 0.01)
5764 <*> option auto (long "momentum" <> value 0.9)
main/shakespeare.hs+1
@@ -13,6 +13,7 @@ import Control.Monad.Trans.Except
1313import Data.Char ( isUpper, toUpper, toLower )
1414import Data.List ( foldl' )
1515import Data.Maybe ( fromMaybe )
16+import Data.Semigroup ( (<>) )
1617
1718import qualified Data.Vector as V
1819import Data.Vector ( Vector )
src/Grenade.hs+10−5
@@ -2,17 +2,22 @@ module Grenade (
22 module X
33 ) where
44
5+import Grenade.Core.LearningParameters as X
6+import Grenade.Core.Layer as X
57import Grenade.Core.Network as X
68import Grenade.Core.Runner as X
79import Grenade.Core.Shape as X
10+import Grenade.Layers.Concat as X
811import Grenade.Layers.Crop as X
912import Grenade.Layers.Dropout as X
1013import Grenade.Layers.Pad as X
1114import Grenade.Layers.Pooling as X
12−import Grenade.Layers.Flatten as X
13−import Grenade.Layers.Fuse as X
15+import Grenade.Layers.Reshape as X
1416import Grenade.Layers.FullyConnected as X
1517import Grenade.Layers.Logit as X
16−import Grenade.Layers.Convolution as X
17−import Grenade.Layers.Relu as X
18−import Grenade.Layers.Tanh as X
18+import Grenade.Layers.Merge as X
19+import Grenade.Layers.Convolution as X
20+import Grenade.Layers.Relu as X
21+import Grenade.Layers.Elu as X
22+import Grenade.Layers.Tanh as X
23+import Grenade.Layers.Softmax as X
src/Grenade/Core.hsnew file+8
@@ -0,0 +1,8 @@
1+module Grenade.Core (
2+ module X
3+ ) where
4+
5+import Grenade.Core.Layer as X
6+import Grenade.Core.LearningParameters as X
7+import Grenade.Core.Shape as X
8+import Grenade.Core.Network as X
src/Grenade/Core/Layer.hsnew file+71
@@ -0,0 +1,71 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE RankNTypes #-}
8+{-# LANGUAGE FlexibleInstances #-}
9+{-|
10+Module : Grenade.Core.Network
11+Description : Core definition a simple neural etwork
12+Copyright : (c) Huw Campbell, 2016-2017
13+License : BSD2
14+Stability : experimental
15+
16+This module defines what a Layer is in a Grenade
17+neural network.
18+-}
19+module Grenade.Core.Layer (
20+ Layer (..)
21+ , UpdateLayer (..)
22+ ) where
23+
24+import Control.Monad.Random ( MonadRandom )
25+
26+import Data.List ( foldl' )
27+
28+import Grenade.Core.Shape
29+import Grenade.Core.LearningParameters
30+
31+-- | Class for updating a layer. All layers implement this, as it
32+-- describes how to create and update the layer.
33+--
34+class UpdateLayer x where
35+ -- | The type for the gradient for this layer.
36+ -- Unit if there isn't a gradient to pass back.
37+ type Gradient x :: *
38+
39+ -- | Update a layer with its gradient and learning parameters
40+ runUpdate :: LearningParameters -> x -> Gradient x -> x
41+
42+ -- | Create a random layer, many layers will use pure
43+ createRandom :: MonadRandom m => m x
44+
45+ -- | Update a layer with many Gradients
46+ runUpdates :: LearningParameters -> x -> [Gradient x] -> x
47+ runUpdates rate = foldl' (runUpdate rate)
48+
49+ {-# MINIMAL runUpdate, createRandom #-}
50+
51+-- | Class for a layer. All layers implement this, however, they don't
52+-- need to implement it for all shapes, only ones which are
53+-- appropriate.
54+--
55+class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
56+ -- | The Wengert tape for this layer. Includes all that is required
57+ -- to generate the back propagated gradients efficiently. As a
58+ -- default, `S i` is fine.
59+ type Tape x i o :: *
60+
61+ -- | Used in training and scoring. Take the input from the previous
62+ -- layer, and give the output from this layer.
63+ runForwards :: x -> S i -> (Tape x i o, S o)
64+
65+ -- | Back propagate a step. Takes the current layer, the input that
66+ -- the layer gave from the input and the back propagated derivatives
67+ -- from the layer above.
68+ --
69+ -- Returns the gradient layer and the derivatives to push back
70+ -- further.
71+ runBackwards :: x -> Tape x i o -> S o -> (Gradient x, S i)
src/Grenade/Core/LearningParameters.hsnew file+10
@@ -0,0 +1,10 @@
1+module Grenade.Core.LearningParameters (
2+ LearningParameters (..)
3+ ) where
4+
5+-- | Learning parameters for stochastic gradient descent.
6+data LearningParameters = LearningParameters {
7+ learningRate :: Double
8+ , learningMomentum :: Double
9+ , learningRegulariser :: Double
10+ } deriving (Eq, Show)
src/Grenade/Core/Network.hs+149−68
@@ -1,5 +1,8 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE BangPatterns #-}
24{-# LANGUAGE GADTs #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
36{-# LANGUAGE TypeOperators #-}
47{-# LANGUAGE TypeFamilies #-}
58{-# LANGUAGE MultiParamTypeClasses #-}
@@ -12,63 +15,36 @@ Copyright : (c) Huw Campbell, 2016-2017
1215License : BSD2
1316Stability : experimental
1417
15−This module defines the core data type for the simplest
16−Neural network we support.
17−
18+This module defines the core data types and functions
19+for non-recurrent neural networks.
1820-}
21+
22+#if __GLASGOW_HASKELL__ < 800
23+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
24+#endif
25+
1926module Grenade.Core.Network (
20− Layer (..)
21− , Network (..)
22− , UpdateLayer (..)
23− , LearningParameters (..)
27+ Network (..)
2428 , Gradients (..)
25− , CreatableNetwork (..)
29+ , Tapes (..)
30+
31+ , runNetwork
32+ , runGradient
33+ , applyUpdate
34+
35+ , randomNetwork
2636 ) where
2737
28−import Control.Monad.Random (MonadRandom)
29−import Data.List ( foldl' )
30−import Data.Singletons
38+import Control.Monad.Random ( MonadRandom )
3139
40+import Data.Singletons
41+import Data.Singletons.Prelude
3242import Data.Serialize
3343
44+import Grenade.Core.Layer
45+import Grenade.Core.LearningParameters
3446import Grenade.Core.Shape
3547
36−-- | Learning parameters for stochastic gradient descent.
37−data LearningParameters = LearningParameters {
38− learningRate :: Double
39− , learningMomentum :: Double
40− , learningRegulariser :: Double
41− } deriving (Eq, Show)
42−
43−-- | Class for updating a layer. All layers implement this, and it is
44−-- shape independent.
45−class Show x => UpdateLayer x where
46− {-# MINIMAL runUpdate, createRandom #-}
47− -- | The type for the gradient for this layer.
48− -- Unit if there isn't a gradient to pass back.
49− type Gradient x :: *
50− -- | Update a layer with its gradient and learning parameters
51− runUpdate :: LearningParameters -> x -> Gradient x -> x
52−
53− -- | Create a random layer, many layers will use pure
54− createRandom :: MonadRandom m => m x
55−
56− -- | Update a layer with many Gradients
57− runUpdates :: LearningParameters -> x -> [Gradient x] -> x
58− runUpdates rate = foldl' (runUpdate rate)
59−
60−-- | Class for a layer. All layers implement this, however, they don't
61−-- need to implement it for all shapes, only ones which are appropriate.
62−class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
63− -- | Used in training and scoring. Take the input from the previous
64− -- layer, and give the output from this layer.
65− runForwards :: x -> S i -> S o
66− -- | Back propagate a step. Takes the current layer, the input that the
67− -- layer gave from the input and the back propagated derivatives from
68− -- the layer above.
69− -- Returns the gradient layer and the derivatives to push back further.
70− runBackwards :: x -> S i -> S o -> (Gradient x, S i)
71−
7248-- | Type of a network.
7349--
7450-- The [*] type specifies the types of the layers.
@@ -78,39 +54,144 @@ class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
7854-- Can be considered to be a heterogeneous list of layers which are able to
7955-- transform the data shapes of the network.
8056data Network :: [*] -> [Shape] -> * where
81− O :: (SingI i, SingI o, Layer x i o) => !x -> Network '[x] '[i, o]
82− (:~>) :: (SingI i, SingI h, Layer x i h) => !x -> !(Network xs (h ': hs)) -> Network (x ': xs) (i ': h ': hs)
57+ NNil :: SingI i
58+ => Network '[] '[i]
59+
60+ (:~>) :: (SingI i, SingI h, Layer x i h)
61+ => !x
62+ -> !(Network xs (h ': hs))
63+ -> Network (x ': xs) (i ': h ': hs)
8364infixr 5 :~>
8465
85−instance Show (Network l h) where
86− show (O a) = "O " ++ show a
87− show (i :~> o) = show i ++ "\n:~>\n" ++ show o
66+instance Show (Network '[] '[i]) where
67+ show NNil = "NNil"
68+instance (Show x, Show (Network xs rs)) => Show (Network (x ': xs) (i ': rs)) where
69+ show (x :~> xs) = show x ++ "\n~>\n" ++ show xs
8870
89−-- | Gradients of a network.
90−-- Parameterised on the layers of a Network.
71+-- | Gradient of a network.
72+--
73+-- Parameterised on the layers of the network.
9174data Gradients :: [*] -> * where
92− OG :: UpdateLayer x => Gradient x -> Gradients '[x]
93− (:/>) :: UpdateLayer x => Gradient x -> Gradients xs -> Gradients (x ': xs)
75+ GNil :: Gradients '[]
76+
77+ (:/>) :: UpdateLayer x
78+ => Gradient x
79+ -> Gradients xs
80+ -> Gradients (x ': xs)
81+
82+-- | Wegnert Tape of a network.
83+--
84+-- Parameterised on the layers and shapes of the network.
85+data Tapes :: [*] -> [Shape] -> * where
86+ TNil :: SingI i
87+ => Tapes '[] '[i]
88+
89+ (:\>) :: (SingI i, SingI h, Layer x i h)
90+ => !(Tape x i h)
91+ -> !(Tapes xs (h ': hs))
92+ -> Tapes (x ': xs) (i ': h ': hs)
93+
9494
95−-- | A network can easily be created by hand with (:~>), but an easy way to initialise a random
96−-- network is with the randomNetwork.
95+-- | Running a network forwards with some input data.
96+--
97+-- This gives the output, and the Wengert tape required for back
98+-- propagation.
99+--
100+runNetwork :: forall layers shapes.
101+ Network layers shapes
102+ -> S (Head shapes)
103+ -> (Tapes layers shapes, S (Last shapes))
104+runNetwork =
105+ go
106+ where
107+ go :: forall js ss. (Last js ~ Last shapes)
108+ => Network ss js
109+ -> S (Head js)
110+ -> (Tapes ss js, S (Last js))
111+ go (layer :~> n) !x =
112+ let (tape, forward) = runForwards layer x
113+ (tapes, answer) = go n forward
114+ in (tape :\> tapes, answer)
115+
116+ go NNil !x
117+ = (TNil, x)
118+
119+
120+-- | Running a loss gradient back through the network.
121+--
122+-- This requires a Wengert tape, generated with the appropriate input
123+-- for the loss.
124+--
125+-- Gives the gradients for the layer, and the gradient across the
126+-- input (which may not be required).
127+--
128+runGradient :: forall layers shapes.
129+ Network layers shapes
130+ -> Tapes layers shapes
131+ -> S (Last shapes)
132+ -> (Gradients layers, S (Head shapes))
133+runGradient net tapes o =
134+ go net tapes
135+ where
136+ go :: forall js ss. (Last js ~ Last shapes)
137+ => Network ss js
138+ -> Tapes ss js
139+ -> (Gradients ss, S (Head js))
140+ go (layer :~> n) (tape :\> nt) =
141+ let (gradients, feed) = go n nt
142+ (layer', backGrad) = runBackwards layer tape feed
143+ in (layer' :/> gradients, backGrad)
144+
145+ go NNil TNil
146+ = (GNil, o)
147+
148+
149+-- | Apply one step of stochastic gradient decent across the network.
150+applyUpdate :: LearningParameters
151+ -> Network layers shapes
152+ -> Gradients layers
153+ -> Network layers shapes
154+applyUpdate rate (layer :~> rest) (gradient :/> grest)
155+ = runUpdate rate layer gradient :~> applyUpdate rate rest grest
156+
157+applyUpdate _ NNil GNil
158+ = NNil
159+
160+
161+-- | A network can easily be created by hand with (:~>), but an easy way to
162+-- initialise a random network is with the randomNetwork.
97163class CreatableNetwork (xs :: [*]) (ss :: [Shape]) where
98− -- | Create a network of the types requested
164+ -- | Create a network with randomly initialised weights.
165+ --
166+ -- Calls to this function will not compile if the type of the neural
167+ -- network is not sound.
99168 randomNetwork :: MonadRandom m => m (Network xs ss)
100169
101−instance (SingI i, SingI o, Layer x i o) => CreatableNetwork (x ': '[]) (i ': o ': '[]) where
102− randomNetwork = O <$> createRandom
170+instance SingI i => CreatableNetwork '[] '[i] where
171+ randomNetwork = return NNil
103172
104−instance (SingI i, SingI o, Layer x i o, CreatableNetwork xs (o ': r ': rs)) => CreatableNetwork (x ': xs) (i ': o ': r ': rs) where
173+instance (SingI i, SingI o, Layer x i o, CreatableNetwork xs (o ': rs)) => CreatableNetwork (x ': xs) (i ': o ': rs) where
105174 randomNetwork = (:~>) <$> createRandom <*> randomNetwork
106175
107−
108176-- | Add very simple serialisation to the network
109−instance (SingI i, SingI o, Layer x i o, Serialize x) => Serialize (Network '[x] '[i, o]) where
110− put (O x) = put x
111− put _ = error "impossible"
112− get = O <$> get
177+instance SingI i => Serialize (Network '[] '[i]) where
178+ put NNil = pure ()
179+ get = return NNil
113180
114−instance (SingI i, SingI o, Layer x i o, Serialize x, Serialize (Network xs (o ': r ': rs))) => Serialize (Network (x ': xs) (i ': o ': r ': rs)) where
181+instance (SingI i, SingI o, Layer x i o, Serialize x, Serialize (Network xs (o ': rs))) => Serialize (Network (x ': xs) (i ': o ': rs)) where
115182 put (x :~> r) = put x >> put r
116183 get = (:~>) <$> get <*> get
184+
185+
186+-- | Ultimate composition.
187+--
188+-- This allows a complete network to be treated as a layer in a bigger network.
189+instance CreatableNetwork sublayers subshapes => UpdateLayer (Network sublayers subshapes) where
190+ type Gradient (Network sublayers subshapes) = Gradients sublayers
191+ runUpdate = applyUpdate
192+ createRandom = randomNetwork
193+
194+instance (CreatableNetwork sublayers subshapes, i ~ (Head subshapes), o ~ (Last subshapes)) => Layer (Network sublayers subshapes) i o where
195+ type Tape (Network sublayers subshapes) i o = Tapes sublayers subshapes
196+ runForwards = runNetwork
197+ runBackwards = runGradient
src/Grenade/Core/Runner.hs+23−45
@@ -1,9 +1,5 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE GADTs #-}
31{-# LANGUAGE DataKinds #-}
4−{-# LANGUAGE ScopedTypeVariables #-}
5−{-# LANGUAGE TypeOperators #-}
6−{-# LANGUAGE TypeFamilies #-}
2+{-# LANGUAGE FlexibleContexts #-}
73{-|
84Module : Grenade.Core.Shape
95Description : Core definition of the Shapes of data we understand
@@ -18,10 +14,11 @@ module Grenade.Core.Runner (
1814 train
1915 , backPropagate
2016 , runNet
21− , applyUpdate
2217 ) where
2318
2419import Data.Singletons.Prelude
20+
21+import Grenade.Core.LearningParameters
2522import Grenade.Core.Network
2623import Grenade.Core.Shape
2724
@@ -30,51 +27,32 @@ import Grenade.Core.Shape
3027--
3128-- /Note:/ The loss function pushed backwards is appropriate
3229-- for both regression and classification as a squared loss
33−-- or log-loss respectively. Other loss functions are not yet
34−-- implemented.
35−backPropagate :: forall shapes layers.
36− Network layers shapes -> S (Head shapes) -> S (Last shapes) -> Gradients layers
30+-- or log-loss respectively.
31+--
32+-- For other loss functions, use runNetwork and runGradient
33+-- with the back propagated gradient of your loss.
34+--
35+backPropagate :: SingI (Last shapes)
36+ => Network layers shapes
37+ -> S (Head shapes)
38+ -> S (Last shapes)
39+ -> Gradients layers
3740backPropagate network input target =
38− fst $ go input network
39− where
40− go :: forall js sublayers. (Last js ~ Last shapes)
41− => S (Head js) -- ^ input vector
42− -> Network sublayers js -- ^ network to train
43− -> (Gradients sublayers, S (Head js))
44− -- handle input from the beginning, feeding upwards.
45− go !x (layer :~> n)
46− = let y = runForwards layer x
47− -- recursively run the rest of the network, and get the gradients from above.
48− (n', dWs') = go y n
49− -- calculate the gradient for this layer to pass down,
50− (layer', dWs) = runBackwards layer x dWs'
51−
52− in (layer' :/> n', dWs)
53−
54− -- handle the output layer, bouncing the derivatives back down.
55− go !x (O layer)
56− = let y = runForwards layer x
57− -- the gradient (how much y affects the error)
58− (layer', dWs) = runBackwards layer x (y - target)
59−
60− in (OG layer', dWs)
61−
62−-- | Apply one step of stochastic gradient decent across the network.
63−applyUpdate :: LearningParameters -> Network ls ss -> Gradients ls -> Network ls ss
64−applyUpdate rate (O layer) (OG gradient)
65− = O (runUpdate rate layer gradient)
66−applyUpdate rate (layer :~> rest) (gradient :/> grest)
67− = runUpdate rate layer gradient :~> applyUpdate rate rest grest
68−applyUpdate _ _ _
69− = error "Impossible for the gradients of a network to have a different length to the network"
41+ let (tapes, output) = runNetwork network input
42+ (grads, _) = runGradient network tapes (output - target)
43+ in grads
7044
7145-- | Update a network with new weights after training with an instance.
72−train :: LearningParameters -> Network layers shapes -> S (Head shapes) -> S (Last shapes) -> Network layers shapes
46+train :: SingI (Last shapes)
47+ => LearningParameters
48+ -> Network layers shapes
49+ -> S (Head shapes)
50+ -> S (Last shapes)
51+ -> Network layers shapes
7352train rate network input output =
7453 let grads = backPropagate network input output
7554 in applyUpdate rate network grads
7655
7756-- | Run the network with input and return the given output.
7857runNet :: Network layers shapes -> S (Head shapes) -> S (Last shapes)
79−runNet (layer :~> n) !x = let y = runForwards layer x in runNet n y
80−runNet (O layer) !x = runForwards layer x
58+runNet net = snd . runNetwork net
src/Grenade/Core/Shape.hs+31−10
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE DataKinds #-}
23{-# LANGUAGE GADTs #-}
34{-# LANGUAGE KindSignatures #-}
@@ -8,10 +9,10 @@
89{-# LANGUAGE ScopedTypeVariables #-}
910{-# LANGUAGE RankNTypes #-}
1011
11−-- Ghc 8.0 gives a warning on `n2 _ _ = error ...` but ghc 7.10 fails to
12−-- compile without this default pattern.
13−{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}
14−
12+-- Ghc 7.10 fails to recognise n2 is complete.
13+#if __GLASGOW_HASKELL__ < 800
14+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
15+#endif
1516{-|
1617Module : Grenade.Core.Shape
1718Description : Core definition of the Shapes of data we understand
@@ -25,6 +26,8 @@ are understood by Grenade.
2526module Grenade.Core.Shape (
2627 Shape (..)
2728 , S (..)
29+ , Sing (..)
30+
2831 , randomOfShape
2932 , fromStorable
3033 ) where
@@ -47,27 +50,46 @@ import qualified Numeric.LinearAlgebra as NLA
4750-- | The current shapes we accept.
4851-- at the moment this is just one, two, and three dimensional
4952-- Vectors/Matricies.
53+--
54+-- These are only used with DataKinds, as Kind `Shape`, with Types 'D1, 'D2, 'D3.
5055data Shape
5156 = D1 Nat
57+ -- ^ One dimensional vector
5258 | D2 Nat Nat
59+ -- ^ Two dimensional matrix. Row, Column.
5360 | D3 Nat Nat Nat
61+ -- ^ Three dimensional matrix. Row, Column, Channels.
5462
55−-- | Given a Shape n, these are the possible data structures with that shape.
63+-- | Concrete data structures for a Shape.
64+--
5665-- All shapes are held in contiguous memory.
5766-- 3D is held in a matrix (usually row oriented) which has height depth * rows.
5867data S (n :: Shape) where
59− S1D :: ( KnownNat o ) => R o -> S ('D1 o)
60− S2D :: ( KnownNat rows, KnownNat columns ) => L rows columns -> S ('D2 rows columns)
68+ -- | One dimensional data
69+ S1D :: ( KnownNat len )
70+ => R len
71+ -> S ('D1 len)
72+
73+ -- | Two dimensional data
74+ S2D :: ( KnownNat rows, KnownNat columns )
75+ => L rows columns
76+ -> S ('D2 rows columns)
77+
78+ -- | Three dimensional data
6179 S3D :: ( KnownNat rows
6280 , KnownNat columns
6381 , KnownNat depth
64− , KnownNat (rows * depth)) => L (rows * depth) columns -> S ('D3 rows columns depth)
82+ , KnownNat (rows * depth))
83+ => L (rows * depth) columns
84+ -> S ('D3 rows columns depth)
6585
6686deriving instance Show (S n)
6787
68−-- Singletons
88+-- Singleton instances.
89+--
6990-- These could probably be derived with template haskell, but this seems
7091-- clear and makes adding the KnownNat constraints simple.
92+-- We can also keep our code TH free, which is great.
7193data instance Sing (n :: Shape) where
7294 D1Sing :: KnownNat a => Sing ('D1 a)
7395 D2Sing :: (KnownNat a, KnownNat b) => Sing ('D2 a b)
@@ -160,7 +182,6 @@ n2 :: ( forall a. Floating a => a -> a -> a ) -> S x -> S x -> S x
160182n2 f (S1D x) (S1D y) = S1D (f x y)
161183n2 f (S2D x) (S2D y) = S2D (f x y)
162184n2 f (S3D x) (S3D y) = S3D (f x y)
163−n2 _ _ _ = error "Impossible to have different constructors for the same shaped network"
164185
165186-- Helper function for creating the number instances
166187nk :: forall x. SingI x => Double -> S x
src/Grenade/Layers/Concat.hsnew file+125
@@ -0,0 +1,125 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE RankNTypes #-}
8+{-# LANGUAGE FlexibleInstances #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE StandaloneDeriving #-}
11+{-|
12+Module : Grenade.Core.Network
13+Description : Core definition a simple neural etwork
14+Copyright : (c) Huw Campbell, 2016-2017
15+License : BSD2
16+Stability : experimental
17+-}
18+module Grenade.Layers.Concat (
19+ Concat (..)
20+ ) where
21+
22+import Data.Singletons
23+import GHC.TypeLits
24+
25+import Grenade.Core
26+
27+import Numeric.LinearAlgebra.Static ( row, (===), splitRows, unrow, (#), split, R )
28+
29+-- | A Concatentating Layer.
30+--
31+-- This layer shares it's input state between two sublayers, and concatenates their output.
32+--
33+-- With Networks able to be Layers, this allows for very expressive composition of complex Networks.
34+--
35+-- The Concat layer has a few instances, which allow one to flexibly "bash" together the outputs.
36+--
37+-- Two 1D vectors, can go to a 2D shape with 2 rows if their lengths are identical.
38+-- Any 2 1D vectors can also become a longer 1D Vector.
39+--
40+-- 3D images become 3D images with more channels. The sizes must be the same, one can use Pad
41+-- and Crop layers to ensure this is the case.
42+data Concat :: Shape -> * -> Shape -> * -> * where
43+ Concat :: x -> y -> Concat m x n y
44+
45+instance (Show x, Show y) => Show (Concat m x n y) where
46+ show (Concat x y) = "Concat\n" ++ show x ++ "\n" ++ show y
47+
48+-- | Run two layers in parallel, combining their outputs.
49+instance (UpdateLayer x, UpdateLayer y) => UpdateLayer (Concat m x n y) where
50+ type Gradient (Concat m x n y) = (Gradient x, Gradient y)
51+ runUpdate lr (Concat x y) (x', y') = Concat (runUpdate lr x x') (runUpdate lr y y')
52+ createRandom = Concat <$> createRandom <*> createRandom
53+
54+instance ( SingI i
55+ , Layer x i ('D1 o)
56+ , Layer y i ('D1 o)
57+ ) => Layer (Concat ('D1 o) x ('D1 o) y) i ('D2 2 o) where
58+ type Tape (Concat ('D1 o) x ('D1 o) y) i ('D2 2 o) = (Tape x i ('D1 o), Tape y i ('D1 o))
59+
60+ runForwards (Concat x y) input =
61+ let (xT, xOut :: S ('D1 o)) = runForwards x input
62+ (yT, yOut :: S ('D1 o)) = runForwards y input
63+ in case (xOut, yOut) of
64+ (S1D xOut', S1D yOut') ->
65+ ((xT, yT), S2D (row xOut' === row yOut'))
66+
67+ runBackwards (Concat x y) (xTape, yTape) (S2D o) =
68+ let (ox, oy) = splitRows o
69+ (x', xB :: S i) = runBackwards x xTape (S1D $ unrow ox)
70+ (y', yB :: S i) = runBackwards y yTape (S1D $ unrow oy)
71+ in ((x', y'), xB + yB)
72+
73+instance ( SingI i
74+ , Layer x i ('D1 m)
75+ , Layer y i ('D1 n)
76+ , KnownNat o
77+ , KnownNat m
78+ , KnownNat n
79+ , o ~ (m + n)
80+ , n ~ (o - m)
81+ , (m <=? o) ~ 'True
82+ ) => Layer (Concat ('D1 m) x ('D1 n) y) i ('D1 o) where
83+ type Tape (Concat ('D1 m) x ('D1 n) y) i ('D1 o) = (Tape x i ('D1 m), Tape y i ('D1 n))
84+
85+ runForwards (Concat x y) input =
86+ let (xT, xOut :: S ('D1 m)) = runForwards x input
87+ (yT, yOut :: S ('D1 n)) = runForwards y input
88+ in case (xOut, yOut) of
89+ (S1D xOut', S1D yOut') ->
90+ ((xT, yT), S1D (xOut' # yOut'))
91+
92+ runBackwards (Concat x y) (xTape, yTape) (S1D o) =
93+ let (ox :: R m , oy :: R n) = split o
94+ (x', xB :: S i) = runBackwards x xTape (S1D ox)
95+ (y', yB :: S i) = runBackwards y yTape (S1D oy)
96+ in ((x', y'), xB + yB)
97+
98+-- | Concat 3D shapes, increasing the number of channels.
99+instance ( SingI i
100+ , Layer x i ('D3 rows cols m)
101+ , Layer y i ('D3 rows cols n)
102+ , KnownNat (rows * n)
103+ , KnownNat (rows * m)
104+ , KnownNat (rows * o)
105+ , KnownNat o
106+ , KnownNat m
107+ , KnownNat n
108+ , ((rows * m) + (rows * n)) ~ (rows * o)
109+ , ((rows * o) - (rows * m)) ~ (rows * n)
110+ , ((rows * m) <=? (rows * o)) ~ 'True
111+ ) => Layer (Concat ('D3 rows cols m) x ('D3 rows cols n) y) i ('D3 rows cols o) where
112+ type Tape (Concat ('D3 rows cols m) x ('D3 rows cols n) y) i ('D3 rows cols o) = (Tape x i ('D3 rows cols m), Tape y i ('D3 rows cols n))
113+
114+ runForwards (Concat x y) input =
115+ let (xT, xOut :: S ('D3 rows cols m)) = runForwards x input
116+ (yT, yOut :: S ('D3 rows cols n)) = runForwards y input
117+ in case (xOut, yOut) of
118+ (S3D xOut', S3D yOut') ->
119+ ((xT, yT), S3D (xOut' === yOut'))
120+
121+ runBackwards (Concat x y) (xTape, yTape) (S3D o) =
122+ let (ox, oy) = splitRows o
123+ (x', xB :: S i) = runBackwards x xTape (S3D ox :: S ('D3 rows cols m))
124+ (y', yB :: S i) = runBackwards y yTape (S3D oy :: S ('D3 rows cols n))
125+ in ((x', y'), xB + yB)
src/Grenade/Layers/Convolution.hs+7−4
@@ -25,8 +25,7 @@ import Numeric.LinearAlgebra hiding ( uniformSample, konst )
2525import qualified Numeric.LinearAlgebra as LA
2626import Numeric.LinearAlgebra.Static hiding ((|||), build, toRows)
2727
28−import Grenade.Core.Network
29−import Grenade.Core.Shape
28+import Grenade.Core
3029import Grenade.Layers.Internal.Convolution
3130import Grenade.Layers.Internal.Update
3231
@@ -157,6 +156,7 @@ instance ( KnownNat kernelRows
157156 , KnownNat (kernelRows * kernelCols * 1)
158157 , KnownNat (outputRows * filters)
159158 ) => Layer (Convolution 1 filters kernelRows kernelCols strideRows strideCols) ('D2 inputRows inputCols) ('D3 outputRows outputCols filters) where
159+ type Tape (Convolution 1 filters kernelRows kernelCols strideRows strideCols) ('D2 inputRows inputCols) ('D3 outputRows outputCols filters) = S ('D2 inputRows inputCols)
160160 runForwards (Convolution kernel _) (S2D input) =
161161 let ex = extract input
162162 ek = extract kernel
@@ -170,7 +170,7 @@ instance ( KnownNat kernelRows
170170 mt = c LA.<> ek
171171 r = col2vid 1 1 1 1 ox oy mt
172172 rs = fromJust . create $ r
173− in S3D rs
173+ in (S2D input, S3D rs)
174174
175175 runBackwards (Convolution kernel _) (S2D input) (S3D dEdy) =
176176 let ex = extract input
@@ -214,6 +214,9 @@ instance ( KnownNat kernelRows
214214 , KnownNat (kernelRows * kernelCols * channels)
215215 , KnownNat (outputRows * filters)
216216 ) => Layer (Convolution channels filters kernelRows kernelCols strideRows strideCols) ('D3 inputRows inputCols channels) ('D3 outputRows outputCols filters) where
217+
218+ type Tape (Convolution channels filters kernelRows kernelCols strideRows strideCols) ('D3 inputRows inputCols channels) ('D3 outputRows outputCols filters) = S ('D3 inputRows inputCols channels)
219+
217220 runForwards (Convolution kernel _) (S3D input) =
218221 let ex = extract input
219222 ek = extract kernel
@@ -230,7 +233,7 @@ instance ( KnownNat kernelRows
230233 mt = c LA.<> ek
231234 r = col2vid 1 1 1 1 ox oy mt
232235 rs = fromJust . create $ r
233− in S3D rs
236+ in (S3D input, S3D rs)
234237 runBackwards (Convolution kernel _) (S3D input) (S3D dEdy) =
235238 let ex = extract input
236239 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
src/Grenade/Layers/Crop.hs+50−3
@@ -3,6 +3,7 @@
33{-# LANGUAGE GADTs #-}
44{-# LANGUAGE TypeOperators #-}
55{-# LANGUAGE TypeFamilies #-}
6+{-# LANGUAGE FlexibleContexts #-}
67{-# LANGUAGE MultiParamTypeClasses #-}
78module Grenade.Layers.Crop (
89 Crop (..)
@@ -13,8 +14,8 @@ import Data.Proxy
1314import Data.Singletons.TypeLits
1415import GHC.TypeLits
1516
16−import Grenade.Core.Network
17−import Grenade.Core.Shape
17+import Grenade.Core
18+import Grenade.Layers.Internal.Pad
1819
1920import Numeric.LinearAlgebra (konst, subMatrix, diagBlock)
2021import Numeric.LinearAlgebra.Static (extract, create)
@@ -46,6 +47,7 @@ instance ( KnownNat cropLeft
4647 , (inputRows - cropTop - cropBottom) ~ outputRows
4748 , (inputColumns - cropLeft - cropRight) ~ outputColumns
4849 ) => Layer (Crop cropLeft cropTop cropRight cropBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
50+ type Tape (Crop cropLeft cropTop cropRight cropBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) = ()
4951 runForwards Crop (S2D input) =
5052 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
5153 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
@@ -53,7 +55,7 @@ instance ( KnownNat cropLeft
5355 ncols = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
5456 m = extract input
5557 r = subMatrix (cropt, cropl) (nrows, ncols) m
56− in S2D . fromJust . create $ r
58+ in ((), S2D . fromJust . create $ r)
5759 runBackwards _ _ (S2D dEdy) =
5860 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
5961 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
@@ -62,3 +64,48 @@ instance ( KnownNat cropLeft
6264 eo = extract dEdy
6365 vs = diagBlock [konst 0 (cropt,cropl), eo, konst 0 (cropb,cropr)]
6466 in ((), S2D . fromJust . create $ vs)
67+
68+
69+-- | A two dimentional image can be cropped.
70+instance ( KnownNat cropLeft
71+ , KnownNat cropTop
72+ , KnownNat cropRight
73+ , KnownNat cropBottom
74+ , KnownNat inputRows
75+ , KnownNat inputColumns
76+ , KnownNat outputRows
77+ , KnownNat outputColumns
78+ , KnownNat channels
79+ , KnownNat (inputRows * channels)
80+ , KnownNat (outputRows * channels)
81+ , (outputRows + cropTop + cropBottom) ~ inputRows
82+ , (outputColumns + cropLeft + cropRight) ~ inputColumns
83+ ) => Layer (Crop cropLeft cropTop cropRight cropBottom) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) where
84+ type Tape (Crop cropLeft cropTop cropRight cropBottom) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) = ()
85+ runForwards Crop (S3D input) =
86+ let padl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
87+ padt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
88+ padr = fromIntegral $ natVal (Proxy :: Proxy cropRight)
89+ padb = fromIntegral $ natVal (Proxy :: Proxy cropBottom)
90+ inr = fromIntegral $ natVal (Proxy :: Proxy inputRows)
91+ inc = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
92+ outr = fromIntegral $ natVal (Proxy :: Proxy outputRows)
93+ outc = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
94+ ch = fromIntegral $ natVal (Proxy :: Proxy channels)
95+ m = extract input
96+ cropped = crop ch padl padt padr padb outr outc inr inc m
97+ in ((), S3D . fromJust . create $ cropped)
98+
99+ runBackwards Crop () (S3D gradient) =
100+ let padl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
101+ padt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
102+ padr = fromIntegral $ natVal (Proxy :: Proxy cropRight)
103+ padb = fromIntegral $ natVal (Proxy :: Proxy cropBottom)
104+ inr = fromIntegral $ natVal (Proxy :: Proxy inputRows)
105+ inc = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
106+ outr = fromIntegral $ natVal (Proxy :: Proxy outputRows)
107+ outc = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
108+ ch = fromIntegral $ natVal (Proxy :: Proxy channels)
109+ m = extract gradient
110+ padded = pad ch padl padt padr padb outr outc inr inc m
111+ in ((), S3D . fromJust . create $ padded)
src/Grenade/Layers/Dropout.hs+14−23
@@ -10,37 +10,28 @@ module Grenade.Layers.Dropout (
1010import Control.Monad.Random hiding (fromList)
1111
1212import GHC.TypeLits
13−import Grenade.Core.Shape
14−import Grenade.Core.Network
15−
16−import Numeric.LinearAlgebra.Static
17−
13+import Grenade.Core
1814
1915-- Dropout layer help to reduce overfitting.
2016-- Idea here is that the vector is a shape of 1s and 0s, which we multiply the input by.
2117-- After backpropogation, we return a new matrix/vector, with different bits dropped out.
2218-- Double is the proportion to drop in each training iteration (like 1% or 5% would be
2319-- reasonable).
24−data Dropout o =
25− Dropout (R o)
26− | Pass Double
27− deriving Show
20+data Dropout = Dropout {
21+ dropoutRate :: Double
22+ , dropoutSeed :: Int
23+ } deriving Show
2824
29−instance (KnownNat i) => UpdateLayer (Dropout i) where
30− type Gradient (Dropout i) = ()
25+instance UpdateLayer Dropout where
26+ type Gradient Dropout = ()
3127 runUpdate _ x _ = x
3228 createRandom = randomDropout 0.95
3329
34−randomDropout :: (MonadRandom m, KnownNat i)
35− => Double -> m (Dropout i)
36−randomDropout rate = do
37− seed <- getRandom
38− let wN = randomVector seed Uniform
39− xs = dvmap (\a -> if a <= rate then 0 else 1) wN
40− return $ Dropout xs
30+randomDropout :: MonadRandom m
31+ => Double -> m Dropout
32+randomDropout rate = Dropout rate <$> getRandom
4133
42−instance (KnownNat i) => Layer (Dropout i) ('D1 i) ('D1 i) where
43− runForwards (Dropout drops) (S1D x) = S1D $ x * drops
44− runForwards (Pass rate) (S1D x)= S1D $ dvmap (* (1 - rate)) x
45− runBackwards (Dropout drops) _ (S1D x) = ((), S1D $ x * drops)
46− runBackwards (Pass rate) _ (S1D x) = ((), S1D $ dvmap (* (1 - rate)) x)
34+instance (KnownNat i) => Layer Dropout ('D1 i) ('D1 i) where
35+ type Tape Dropout ('D1 i) ('D1 i) = ()
36+ runForwards (Dropout _ _) (S1D x) = ((), S1D x)
37+ runBackwards (Dropout _ _) _ (S1D x) = ((), S1D x)
src/Grenade/Layers/Elu.hsnew file+60
@@ -0,0 +1,60 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+module Grenade.Layers.Elu (
6+ Elu (..)
7+ ) where
8+
9+import Data.Serialize
10+
11+import GHC.TypeLits
12+import Grenade.Core
13+
14+import qualified Numeric.LinearAlgebra.Static as LAS
15+
16+-- | An exponential linear unit.
17+-- A layer which can act between any shape of the same dimension, acting as a
18+-- diode on every neuron individually.
19+data Elu = Elu
20+ deriving Show
21+
22+instance UpdateLayer Elu where
23+ type Gradient Elu = ()
24+ runUpdate _ _ _ = Elu
25+ createRandom = return Elu
26+
27+instance Serialize Elu where
28+ put _ = return ()
29+ get = return Elu
30+
31+instance ( KnownNat i) => Layer Elu ('D1 i) ('D1 i) where
32+ type Tape Elu ('D1 i) ('D1 i) = S ('D1 i)
33+
34+ runForwards _ (S1D y) = (S1D y, S1D (elu y))
35+ where
36+ elu = LAS.dvmap (\a -> if a <= 0 then exp a - 1 else a)
37+ runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (elu' y * dEdy))
38+ where
39+ elu' = LAS.dvmap (\a -> if a <= 0 then exp a else 1)
40+
41+instance (KnownNat i, KnownNat j) => Layer Elu ('D2 i j) ('D2 i j) where
42+ type Tape Elu ('D2 i j) ('D2 i j) = S ('D2 i j)
43+
44+ runForwards _ (S2D y) = (S2D y, S2D (elu y))
45+ where
46+ elu = LAS.dmmap (\a -> if a <= 0 then exp a - 1 else a)
47+ runBackwards _ (S2D y) (S2D dEdy) = ((), S2D (elu' y * dEdy))
48+ where
49+ elu' = LAS.dmmap (\a -> if a <= 0 then exp a else 1)
50+
51+instance (KnownNat i, KnownNat j, KnownNat k) => Layer Elu ('D3 i j k) ('D3 i j k) where
52+
53+ type Tape Elu ('D3 i j k) ('D3 i j k) = S ('D3 i j k)
54+
55+ runForwards _ (S3D y) = (S3D y, S3D (elu y))
56+ where
57+ elu = LAS.dmmap (\a -> if a <= 0 then exp a - 1 else a)
58+ runBackwards _ (S3D y) (S3D dEdy) = ((), S3D (elu' y * dEdy))
59+ where
60+ elu' = LAS.dmmap (\a -> if a <= 0 then exp a else 1)
src/Grenade/Layers/Flatten.hsdeleted−53
@@ -1,53 +0,0 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE TypeOperators #-}
3−{-# LANGUAGE TypeFamilies #-}
4−{-# LANGUAGE MultiParamTypeClasses #-}
5−{-# LANGUAGE FlexibleContexts #-}
6−module Grenade.Layers.Flatten (
7− FlattenLayer (..)
8− ) where
9−
10−import Data.Serialize
11−
12−import Data.Singletons.TypeLits
13−import GHC.TypeLits
14−
15−import Numeric.LinearAlgebra.Static
16−import Numeric.LinearAlgebra.Data as LA ( flatten )
17−
18−import Grenade.Core.Shape
19−import Grenade.Core.Network
20−
21−-- | Flatten Layer
22−--
23−-- Flattens input down to D1 from either 2D or 3D data.
24−--
25−-- Can also be used to turn a 3D image with only one channel into a 2D image.
26−data FlattenLayer = FlattenLayer
27− deriving Show
28−
29−instance UpdateLayer FlattenLayer where
30− type Gradient FlattenLayer = ()
31− runUpdate _ _ _ = FlattenLayer
32− createRandom = return FlattenLayer
33−
34−instance (KnownNat a, KnownNat x, KnownNat y, a ~ (x * z)) => Layer FlattenLayer ('D2 x y) ('D1 a) where
35− runForwards _ (S2D y) = fromJust' . fromStorable . flatten . extract $ y
36− runBackwards _ _ (S1D y) = ((), fromJust' . fromStorable . extract $ y)
37−
38−instance (KnownNat a, KnownNat x, KnownNat y, KnownNat (x * z), KnownNat z, a ~ (x * y * z)) => Layer FlattenLayer ('D3 x y z) ('D1 a) where
39− runForwards _ (S3D y) = fromJust' . fromStorable . flatten . extract $ y
40− runBackwards _ _ (S1D y) = ((), fromJust' . fromStorable . extract $ y)
41−
42−instance (KnownNat y, KnownNat x, KnownNat z, z ~ 1) => Layer FlattenLayer ('D3 x y z) ('D2 x y) where
43− runForwards _ (S3D y) = S2D y
44− runBackwards _ _ (S2D y) = ((), S3D y)
45−
46−instance Serialize FlattenLayer where
47− put _ = return ()
48− get = return FlattenLayer
49−
50−
51−fromJust' :: Maybe x -> x
52−fromJust' (Just x) = x
53−fromJust' Nothing = error $ "FlattenLayer error: data shape couldn't be converted."
src/Grenade/Layers/FullyConnected.hs+14−15
@@ -6,6 +6,7 @@
66{-# LANGUAGE ScopedTypeVariables #-}
77module Grenade.Layers.FullyConnected (
88 FullyConnected (..)
9+ , FullyConnected' (..)
910 , randomFullyConnected
1011 ) where
1112
@@ -18,21 +19,18 @@ import Data.Singletons.TypeLits
1819import qualified Numeric.LinearAlgebra as LA
1920import Numeric.LinearAlgebra.Static
2021
21−import Grenade.Core.Network
22−import Grenade.Core.Shape
22+import Grenade.Core
2323
2424import Grenade.Layers.Internal.Update
2525
2626-- | A basic fully connected (or inner product) neural network layer.
2727data FullyConnected i o = FullyConnected
28− !(R o) -- Bias neuron weights
29− !(R o) -- Bias neuron momentum
30− !(L o i) -- Activation weights
31− !(L o i) -- Momentum
28+ !(FullyConnected' i o) -- Neuron weights
29+ !(FullyConnected' i o) -- Neuron momentum
3230
3331data FullyConnected' i o = FullyConnected'
34− !(R o) -- Bias neuron gradient
35− !(L o i) -- Activation gradient
32+ !(R o) -- Bias
33+ !(L o i) -- Activations
3634
3735instance Show (FullyConnected i o) where
3836 show FullyConnected {} = "FullyConnected"
@@ -40,19 +38,20 @@ instance Show (FullyConnected i o) where
4038instance (KnownNat i, KnownNat o) => UpdateLayer (FullyConnected i o) where
4139 type Gradient (FullyConnected i o) = (FullyConnected' i o)
4240
43− runUpdate LearningParameters {..} (FullyConnected oldBias oldBiasMomentum oldActivations oldMomentum) (FullyConnected' biasGradient activationGradient) =
41+ runUpdate LearningParameters {..} (FullyConnected (FullyConnected' oldBias oldActivations) (FullyConnected' oldBiasMomentum oldMomentum)) (FullyConnected' biasGradient activationGradient) =
4442 let (newBias, newBiasMomentum) = decendVector learningRate learningMomentum learningRegulariser oldBias biasGradient oldBiasMomentum
4543 (newActivations, newMomentum) = decendMatrix learningRate learningMomentum learningRegulariser oldActivations activationGradient oldMomentum
46− in FullyConnected newBias newBiasMomentum newActivations newMomentum
44+ in FullyConnected (FullyConnected' newBias newActivations) (FullyConnected' newBiasMomentum newMomentum)
4745
4846 createRandom = randomFullyConnected
4947
5048instance (KnownNat i, KnownNat o) => Layer (FullyConnected i o) ('D1 i) ('D1 o) where
49+ type Tape (FullyConnected i o) ('D1 i) ('D1 o) = S ('D1 i)
5150 -- Do a matrix vector multiplication and return the result.
52− runForwards (FullyConnected wB _ wN _) (S1D v) = S1D (wB + wN #> v)
51+ runForwards (FullyConnected (FullyConnected' wB wN) _) (S1D v) = (S1D v, S1D (wB + wN #> v))
5352
5453 -- Run a backpropogation step for a full connected layer.
55− runBackwards (FullyConnected _ _ wN _) (S1D x) (S1D dEdy) =
54+ runBackwards (FullyConnected (FullyConnected' _ wN) _) (S1D x) (S1D dEdy) =
5655 let wB' = dEdy
5756 mm' = dEdy `outer` x
5857 -- calcluate derivatives for next step
@@ -60,7 +59,7 @@ instance (KnownNat i, KnownNat o) => Layer (FullyConnected i o) ('D1 i) ('D1 o)
6059 in (FullyConnected' wB' mm', S1D dWs)
6160
6261instance (KnownNat i, KnownNat o) => Serialize (FullyConnected i o) where
63− put (FullyConnected b _ w _) = do
62+ put (FullyConnected (FullyConnected' b w) _) = do
6463 putListOf put . LA.toList . extract $ b
6564 putListOf put . LA.toList . LA.flatten . extract $ w
6665
@@ -70,7 +69,7 @@ instance (KnownNat i, KnownNat o) => Serialize (FullyConnected i o) where
7069 k <- maybe (fail "Vector of incorrect size") return . create . LA.reshape f . LA.fromList =<< getListOf get
7170 let bm = konst 0
7271 let mm = konst 0
73− return $ FullyConnected b bm k mm
72+ return $ FullyConnected (FullyConnected' b k) (FullyConnected' bm mm)
7473
7574randomFullyConnected :: (MonadRandom m, KnownNat i, KnownNat o)
7675 => m (FullyConnected i o)
@@ -81,4 +80,4 @@ randomFullyConnected = do
8180 wN = uniformSample s2 (-1) 1
8281 bm = konst 0
8382 mm = konst 0
84− return $ FullyConnected wB bm wN mm
83+ return $ FullyConnected (FullyConnected' wB wN) (FullyConnected' bm mm)
src/Grenade/Layers/Fuse.hsdeleted−47
@@ -1,47 +0,0 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE GADTs #-}
3−{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE TypeOperators #-}
5−{-# LANGUAGE TypeFamilies #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE FlexibleContexts #-}
8−{-# LANGUAGE FlexibleInstances #-}
9−module Grenade.Layers.Fuse (
10− Fuse (..)
11− ) where
12−
13−import Grenade.Core.Network
14−import Grenade.Core.Shape
15−
16−-- | Fuse two layers into one layer.
17−-- This can be used to simplify a network if a complicated repeated structure is used.
18−-- This does however have a trade off, internal incremental states in the Wengert tape are
19−-- not retained during reverse accumulation. So less RAM is used, but more compute is required.
20−data Fuse :: * -> * -> Shape -> Shape -> Shape -> * where
21− (:$$) :: (Layer x i h, Layer y h o)
22− => !x
23− -> !y
24− -> Fuse x y i h o
25−infixr 5 :$$
26−
27−instance (Show x, Show y) => Show (Fuse x y i h o) where
28− show (x :$$ y) = "(" ++ show x ++ " :$$ " ++ show y ++ ")"
29−
30−instance (Layer x i h, Layer y h o) => UpdateLayer (Fuse x y i h o) where
31− type Gradient (Fuse x y i h o) = (Gradient x, Gradient y)
32− runUpdate lr (x :$$ y) (x', y') =
33− let newX = runUpdate lr x x'
34− newY = runUpdate lr y y'
35− in (newX :$$ newY)
36− createRandom = (:$$) <$> createRandom <*> createRandom
37−
38−instance (Layer x i h, Layer y h o) => Layer (Fuse x y i h o) i o where
39− runForwards (x :$$ y) input =
40− let yInput :: S h = runForwards x input
41− in runForwards y yInput
42−
43− runBackwards (x :$$ y) input backGradient =
44− let yInput :: S h = runForwards x input
45− (y', yGrad) = runBackwards y yInput backGradient
46− (x', xGrad) = runBackwards x input yGrad
47− in ((x', y'), xGrad)
src/Grenade/Layers/Inception.hsnew file+48
@@ -0,0 +1,48 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE RankNTypes #-}
8+{-# LANGUAGE FlexibleInstances #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-|
11+Module : Grenade.Core.Network
12+Description : Core definition a simple neural etwork
13+Copyright : (c) Huw Campbell, 2016-2017
14+License : BSD2
15+Stability : experimental
16+-}
17+module Grenade.Layers.Inception (
18+ Inception
19+ ) where
20+
21+import GHC.TypeLits
22+
23+import Grenade.Core
24+import Grenade.Layers.Convolution
25+import Grenade.Layers.Pad
26+import Grenade.Layers.Concat
27+
28+
29+type Inception rows cols channels chx chy chz
30+ = Network '[ Concat ('D3 (rows - 2) (cols - 2) (chx + chy)) (InceptionS rows cols channels chx chy) ('D3 (rows - 2) (cols - 2) chz) (Inception7x7 rows cols channels chz) ]
31+ '[ 'D3 rows cols channels, 'D3 (rows -2) (cols -2) (chx + chy + chz) ]
32+
33+type InceptionS rows cols channels chx chy
34+ = Network '[ Concat ('D3 (rows - 2) (cols - 2) chx) (Inception3x3 rows cols channels chx) ('D3 (rows - 2) (cols - 2) chy) (Inception5x5 rows cols channels chy) ]
35+ '[ 'D3 rows cols channels, 'D3 (rows -2) (cols -2) (chx + chy) ]
36+
37+type Inception3x3 rows cols channels chx
38+ = Network '[ Convolution channels chx 3 3 1 1 ]
39+ '[ 'D3 rows cols channels, 'D3 (rows -2) (cols -2) chx ]
40+
41+type Inception5x5 rows cols channels chx
42+ = Network '[ Pad 1 1 1 1, Convolution channels chx 5 5 1 1 ]
43+ '[ 'D3 rows cols channels, 'D3 (rows + 2) (cols + 2) channels, 'D3 (rows - 2) (cols - 2) chx ]
44+
45+type Inception7x7 rows cols channels chx
46+ = Network '[ Pad 2 2 2 2, Convolution channels chx 7 7 1 1 ]
47+ '[ 'D3 rows cols channels, 'D3 (rows + 4) (cols + 4) channels, 'D3 (rows - 2) (cols - 2) chx ]
48+
src/Grenade/Layers/Internal/Pad.hsnew file+54
@@ -0,0 +1,54 @@
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+module Grenade.Layers.Internal.Pad (
3+ pad
4+ , crop
5+ ) where
6+
7+import qualified Data.Vector.Storable as U ( unsafeToForeignPtr0, unsafeFromForeignPtr0 )
8+
9+import Foreign ( mallocForeignPtrArray, withForeignPtr )
10+import Foreign.Ptr ( Ptr )
11+
12+import Numeric.LinearAlgebra ( flatten, Matrix )
13+import qualified Numeric.LinearAlgebra.Devel as U
14+
15+import System.IO.Unsafe ( unsafePerformIO )
16+
17+pad :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
18+pad channels padLeft padTop padRight padBottom rows cols rows' cols' m
19+ = let outMatSize = rows' * cols' * channels
20+ vec = flatten m
21+ in unsafePerformIO $ do
22+ outPtr <- mallocForeignPtrArray outMatSize
23+ let (inPtr, _) = U.unsafeToForeignPtr0 vec
24+
25+ withForeignPtr inPtr $ \inPtr' ->
26+ withForeignPtr outPtr $ \outPtr' ->
27+ pad_cpu inPtr' channels rows cols padLeft padTop padRight padBottom outPtr'
28+
29+ let matVec = U.unsafeFromForeignPtr0 outPtr outMatSize
30+ return (U.matrixFromVector U.RowMajor (rows' * channels) cols' matVec)
31+{-# INLINE pad #-}
32+
33+foreign import ccall unsafe
34+ pad_cpu
35+ :: Ptr Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Ptr Double -> IO ()
36+
37+crop :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Matrix Double -> Matrix Double
38+crop channels padLeft padTop padRight padBottom rows cols _ _ m
39+ = let outMatSize = rows * cols * channels
40+ vec = flatten m
41+ in unsafePerformIO $ do
42+ outPtr <- mallocForeignPtrArray outMatSize
43+ let (inPtr, _) = U.unsafeToForeignPtr0 vec
44+
45+ withForeignPtr inPtr $ \inPtr' ->
46+ withForeignPtr outPtr $ \outPtr' ->
47+ crop_cpu inPtr' channels rows cols padLeft padTop padRight padBottom outPtr'
48+
49+ let matVec = U.unsafeFromForeignPtr0 outPtr outMatSize
50+ return (U.matrixFromVector U.RowMajor (rows * channels) cols matVec)
51+
52+foreign import ccall unsafe
53+ crop_cpu
54+ :: Ptr Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Ptr Double -> IO ()
src/Grenade/Layers/Logit.hs+7−14
@@ -1,6 +1,7 @@
11{-# LANGUAGE DataKinds #-}
22{-# LANGUAGE TypeOperators #-}
33{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE FlexibleInstances #-}
45{-# LANGUAGE MultiParamTypeClasses #-}
56module Grenade.Layers.Logit (
67 Logit (..)
@@ -8,10 +9,9 @@ module Grenade.Layers.Logit (
89
910
1011import Data.Serialize
12+import Data.Singletons
1113
12−import Data.Singletons.TypeLits
13−import Grenade.Core.Network
14−import Grenade.Core.Shape
14+import Grenade.Core
1515
1616-- | A Logit layer.
1717-- A layer which can act between any shape of the same dimension, perfoming an sigmoid function.
@@ -25,17 +25,10 @@ instance UpdateLayer Logit where
2525 runUpdate _ _ _ = Logit
2626 createRandom = return Logit
2727
28−instance (KnownNat i) => Layer Logit ('D1 i) ('D1 i) where
29− runForwards _ (S1D y) = S1D (logistic y)
30− runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (logistic' y * dEdy))
31−
32−instance (KnownNat i, KnownNat j) => Layer Logit ('D2 i j) ('D2 i j) where
33− runForwards _ (S2D y) = S2D (logistic y)
34− runBackwards _ (S2D y) (S2D dEdy) = ((), S2D (logistic' y * dEdy))
35−
36−instance (KnownNat i, KnownNat j, KnownNat k) => Layer Logit ('D3 i j k) ('D3 i j k) where
37− runForwards _ (S3D y) = S3D (logistic y)
38− runBackwards _ (S3D y) (S3D dEdy) = ((), S3D (logistic' y * dEdy))
28+instance (a ~ b, SingI a) => Layer Logit a b where
29+ type Tape Logit a b = S a
30+ runForwards _ a = (a, logistic a)
31+ runBackwards _ a g = ((), logistic' a * g)
3932
4033instance Serialize Logit where
4134 put _ = return ()
src/Grenade/Layers/Merge.hsnew file+55
@@ -0,0 +1,55 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE RankNTypes #-}
8+{-# LANGUAGE FlexibleInstances #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE StandaloneDeriving #-}
11+{-|
12+Module : Grenade.Core.Network
13+Description : Core definition a simple neural etwork
14+Copyright : (c) Huw Campbell, 2016-2017
15+License : BSD2
16+Stability : experimental
17+-}
18+module Grenade.Layers.Merge (
19+ Merge (..)
20+ ) where
21+
22+import Data.Singletons
23+
24+import Grenade.Core
25+
26+-- | A Merging layer.
27+--
28+-- Similar to Concat layer, except sums the activations instead of creating a larger
29+-- shape.
30+data Merge :: * -> * -> * where
31+ Merge :: x -> y -> Merge x y
32+
33+instance (Show x, Show y) => Show (Merge x y) where
34+ show (Merge x y) = "Merge\n" ++ show x ++ "\n" ++ show y
35+
36+-- | Run two layers in parallel, combining their outputs.
37+-- This just kind of "smooshes" the weights together.
38+instance (UpdateLayer x, UpdateLayer y) => UpdateLayer (Merge x y) where
39+ type Gradient (Merge x y) = (Gradient x, Gradient y)
40+ runUpdate lr (Merge x y) (x', y') = Merge (runUpdate lr x x') (runUpdate lr y y')
41+ createRandom = Merge <$> createRandom <*> createRandom
42+
43+-- | Combine the outputs and the inputs, summing the output shape
44+instance (SingI i, SingI o, Layer x i o, Layer y i o) => Layer (Merge x y) i o where
45+ type Tape (Merge x y) i o = (Tape x i o, Tape y i o)
46+
47+ runForwards (Merge x y) input =
48+ let (xT, xOut) = runForwards x input
49+ (yT, yOut) = runForwards y input
50+ in ((xT, yT), xOut + yOut)
51+
52+ runBackwards (Merge x y) (xTape, yTape) o =
53+ let (x', xB) = runBackwards x xTape o
54+ (y', yB) = runBackwards y yTape o
55+ in ((x', y'), xB + yB)
src/Grenade/Layers/Pad.hs+49−3
@@ -4,6 +4,7 @@
44{-# LANGUAGE TypeOperators #-}
55{-# LANGUAGE TypeFamilies #-}
66{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE FlexibleContexts #-}
78module Grenade.Layers.Pad (
89 Pad (..)
910 ) where
@@ -14,8 +15,8 @@ import Data.Serialize
1415import Data.Singletons.TypeLits
1516import GHC.TypeLits
1617
17−import Grenade.Core.Network
18−import Grenade.Core.Shape
18+import Grenade.Core
19+import Grenade.Layers.Internal.Pad
1920
2021import Numeric.LinearAlgebra (konst, subMatrix, diagBlock)
2122import Numeric.LinearAlgebra.Static (extract, create)
@@ -51,6 +52,7 @@ instance ( KnownNat padLeft
5152 , (inputRows + padTop + padBottom) ~ outputRows
5253 , (inputColumns + padLeft + padRight) ~ outputColumns
5354 ) => Layer (Pad padLeft padTop padRight padBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
55+ type Tape (Pad padLeft padTop padRight padBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) = ()
5456 runForwards Pad (S2D input) =
5557 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
5658 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
@@ -58,7 +60,7 @@ instance ( KnownNat padLeft
5860 padb = fromIntegral $ natVal (Proxy :: Proxy padBottom)
5961 m = extract input
6062 r = diagBlock [konst 0 (padt,padl), m, konst 0 (padb,padr)]
61− in S2D . fromJust . create $ r
63+ in ((), S2D . fromJust . create $ r)
6264 runBackwards Pad _ (S2D dEdy) =
6365 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
6466 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
@@ -67,3 +69,47 @@ instance ( KnownNat padLeft
6769 m = extract dEdy
6870 vs = subMatrix (padt, padl) (nrows, ncols) m
6971 in ((), S2D . fromJust . create $ vs)
72+
73+-- | A two dimentional image can be padped.
74+instance ( KnownNat padLeft
75+ , KnownNat padTop
76+ , KnownNat padRight
77+ , KnownNat padBottom
78+ , KnownNat inputRows
79+ , KnownNat inputColumns
80+ , KnownNat outputRows
81+ , KnownNat outputColumns
82+ , KnownNat channels
83+ , KnownNat (inputRows * channels)
84+ , KnownNat (outputRows * channels)
85+ , (inputRows + padTop + padBottom) ~ outputRows
86+ , (inputColumns + padLeft + padRight) ~ outputColumns
87+ ) => Layer (Pad padLeft padTop padRight padBottom) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) where
88+ type Tape (Pad padLeft padTop padRight padBottom) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) = ()
89+ runForwards Pad (S3D input) =
90+ let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
91+ padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
92+ padr = fromIntegral $ natVal (Proxy :: Proxy padRight)
93+ padb = fromIntegral $ natVal (Proxy :: Proxy padBottom)
94+ outr = fromIntegral $ natVal (Proxy :: Proxy outputRows)
95+ outc = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
96+ inr = fromIntegral $ natVal (Proxy :: Proxy inputRows)
97+ inc = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
98+ ch = fromIntegral $ natVal (Proxy :: Proxy channels)
99+ m = extract input
100+ padded = pad ch padl padt padr padb inr inc outr outc m
101+ in ((), S3D . fromJust . create $ padded)
102+
103+ runBackwards Pad () (S3D gradient) =
104+ let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
105+ padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
106+ padr = fromIntegral $ natVal (Proxy :: Proxy padRight)
107+ padb = fromIntegral $ natVal (Proxy :: Proxy padBottom)
108+ outr = fromIntegral $ natVal (Proxy :: Proxy outputRows)
109+ outc = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
110+ inr = fromIntegral $ natVal (Proxy :: Proxy inputRows)
111+ inc = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
112+ ch = fromIntegral $ natVal (Proxy :: Proxy channels)
113+ m = extract gradient
114+ cropped = crop ch padl padt padr padb inr inc outr outc m
115+ in ((), S3D . fromJust . create $ cropped)
src/Grenade/Layers/Pooling.hs+5−4
@@ -16,8 +16,7 @@ import Data.Serialize
1616import Data.Singletons.TypeLits
1717import GHC.TypeLits
1818
19−import Grenade.Core.Network
20−import Grenade.Core.Shape
19+import Grenade.Core
2120import Grenade.Layers.Internal.Pooling
2221
2322import Numeric.LinearAlgebra.Static as LAS hiding ((|||), build, toRows)
@@ -56,6 +55,7 @@ instance ( KnownNat kernelRows
5655 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
5756 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
5857 ) => Layer (Pooling kernelRows kernelColumns strideRows strideColumns) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
58+ type Tape (Pooling kernelRows kernelColumns strideRows strideColumns) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) = S ('D2 inputRows inputColumns)
5959 runForwards Pooling (S2D input) =
6060 let height = fromIntegral $ natVal (Proxy :: Proxy inputRows)
6161 width = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -66,7 +66,7 @@ instance ( KnownNat kernelRows
6666 ex = extract input
6767 r = poolForward 1 height width kx ky sx sy ex
6868 rs = fromJust . create $ r
69− in S2D $ rs
69+ in (S2D input, S2D rs)
7070 runBackwards Pooling (S2D input) (S2D dEdy) =
7171 let height = fromIntegral $ natVal (Proxy :: Proxy inputRows)
7272 width = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -94,6 +94,7 @@ instance ( KnownNat kernelRows
9494 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
9595 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
9696 ) => Layer (Pooling kernelRows kernelColumns strideRows strideColumns) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) where
97+ type Tape (Pooling kernelRows kernelColumns strideRows strideColumns) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) = S ('D3 inputRows inputColumns channels)
9798 runForwards Pooling (S3D input) =
9899 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
99100 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -105,7 +106,7 @@ instance ( KnownNat kernelRows
105106 ex = extract input
106107 r = poolForward ch ix iy kx ky sx sy ex
107108 rs = fromJust . create $ r
108− in S3D rs
109+ in (S3D input, S3D rs)
109110 runBackwards Pooling (S3D input) (S3D dEdy) =
110111 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
111112 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
src/Grenade/Layers/Relu.hs+11−5
@@ -9,8 +9,7 @@ module Grenade.Layers.Relu (
99import Data.Serialize
1010
1111import GHC.TypeLits
12−import Grenade.Core.Network
13−import Grenade.Core.Shape
12+import Grenade.Core
1413
1514import qualified Numeric.LinearAlgebra.Static as LAS
1615
@@ -30,7 +29,9 @@ instance Serialize Relu where
3029 get = return Relu
3130
3231instance ( KnownNat i) => Layer Relu ('D1 i) ('D1 i) where
33− runForwards _ (S1D y) = S1D (relu y)
32+ type Tape Relu ('D1 i) ('D1 i) = S ('D1 i)
33+
34+ runForwards _ (S1D y) = (S1D y, S1D (relu y))
3435 where
3536 relu = LAS.dvmap (\a -> if a <= 0 then 0 else a)
3637 runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (relu' y * dEdy))
@@ -38,7 +39,9 @@ instance ( KnownNat i) => Layer Relu ('D1 i) ('D1 i) where
3839 relu' = LAS.dvmap (\a -> if a <= 0 then 0 else 1)
3940
4041instance (KnownNat i, KnownNat j) => Layer Relu ('D2 i j) ('D2 i j) where
41− runForwards _ (S2D y) = S2D (relu y)
42+ type Tape Relu ('D2 i j) ('D2 i j) = S ('D2 i j)
43+
44+ runForwards _ (S2D y) = (S2D y, S2D (relu y))
4245 where
4346 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
4447 runBackwards _ (S2D y) (S2D dEdy) = ((), S2D (relu' y * dEdy))
@@ -46,7 +49,10 @@ instance (KnownNat i, KnownNat j) => Layer Relu ('D2 i j) ('D2 i j) where
4649 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
4750
4851instance (KnownNat i, KnownNat j, KnownNat k) => Layer Relu ('D3 i j k) ('D3 i j k) where
49− runForwards _ (S3D y) = S3D (relu y)
52+
53+ type Tape Relu ('D3 i j k) ('D3 i j k) = S ('D3 i j k)
54+
55+ runForwards _ (S3D y) = (S3D y, S3D (relu y))
5056 where
5157 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
5258 runBackwards _ (S3D y) (S3D dEdy) = ((), S3D (relu' y * dEdy))
src/Grenade/Layers/Reshape.hsnew file+60
@@ -0,0 +1,60 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE FlexibleContexts #-}
6+module Grenade.Layers.Reshape (
7+ Reshape (..)
8+ ) where
9+
10+import Data.Serialize
11+
12+import Data.Singletons.TypeLits
13+import GHC.TypeLits
14+
15+import Numeric.LinearAlgebra.Static
16+import Numeric.LinearAlgebra.Data as LA ( flatten )
17+
18+import Grenade.Core
19+
20+-- | Reshape Layer
21+--
22+-- Flattens input down to D1 from either 2D or 3D data.
23+--
24+-- Can also be used to turn a 3D image with only one channel into a 2D image.
25+data Reshape = Reshape
26+ deriving Show
27+
28+instance UpdateLayer Reshape where
29+ type Gradient Reshape = ()
30+ runUpdate _ _ _ = Reshape
31+ createRandom = return Reshape
32+
33+instance (KnownNat a, KnownNat x, KnownNat y, a ~ (x * y)) => Layer Reshape ('D2 x y) ('D1 a) where
34+ type Tape Reshape ('D2 x y) ('D1 a) = ()
35+ runForwards _ (S2D y) = ((), fromJust' . fromStorable . flatten . extract $ y)
36+ runBackwards _ _ (S1D y) = ((), fromJust' . fromStorable . extract $ y)
37+
38+instance (KnownNat a, KnownNat x, KnownNat y, KnownNat (x * z), KnownNat z, a ~ (x * y * z)) => Layer Reshape ('D3 x y z) ('D1 a) where
39+ type Tape Reshape ('D3 x y z) ('D1 a) = ()
40+ runForwards _ (S3D y) = ((), fromJust' . fromStorable . flatten . extract $ y)
41+ runBackwards _ _ (S1D y) = ((), fromJust' . fromStorable . extract $ y)
42+
43+instance (KnownNat y, KnownNat x, KnownNat z, z ~ 1) => Layer Reshape ('D3 x y z) ('D2 x y) where
44+ type Tape Reshape ('D3 x y z) ('D2 x y) = ()
45+ runForwards _ (S3D y) = ((), S2D y)
46+ runBackwards _ _ (S2D y) = ((), S3D y)
47+
48+instance (KnownNat y, KnownNat x, KnownNat z, z ~ 1) => Layer Reshape ('D2 x y) ('D3 x y z) where
49+ type Tape Reshape ('D2 x y) ('D3 x y z) = ()
50+ runForwards _ (S2D y) = ((), S3D y)
51+ runBackwards _ _ (S3D y) = ((), S2D y)
52+
53+instance Serialize Reshape where
54+ put _ = return ()
55+ get = return Reshape
56+
57+
58+fromJust' :: Maybe x -> x
59+fromJust' (Just x) = x
60+fromJust' Nothing = error $ "Reshape error: data shape couldn't be converted."
src/Grenade/Layers/Softmax.hsnew file+53
@@ -0,0 +1,53 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+module Grenade.Layers.Softmax (
7+ Softmax (..)
8+ , softmax
9+ , softmax'
10+ ) where
11+
12+import Data.Serialize
13+
14+import GHC.TypeLits
15+import Grenade.Core
16+
17+import Numeric.LinearAlgebra.Static as LAS
18+
19+-- | A Softmax layer
20+-- This layer is like a logit layer, but normalises
21+-- a set of matricies to be probabilities.
22+data Softmax = Softmax
23+ deriving Show
24+
25+instance UpdateLayer Softmax where
26+ type Gradient Softmax = ()
27+ runUpdate _ _ _ = Softmax
28+ createRandom = return Softmax
29+
30+instance ( KnownNat i ) => Layer Softmax ('D1 i) ('D1 i) where
31+ type Tape Softmax ('D1 i) ('D1 i) = S ('D1 i)
32+
33+ runForwards _ (S1D y) = (S1D y, S1D (softmax y))
34+ runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (softmax' y dEdy))
35+
36+instance Serialize Softmax where
37+ put _ = return ()
38+ get = return Softmax
39+
40+softmax :: KnownNat i => LAS.R i -> LAS.R i
41+softmax xs =
42+ let xs' = LAS.dvmap exp xs
43+ s = LAS.dot xs' 1
44+ in LAS.dvmap (/ s) xs'
45+
46+softmax' :: KnownNat i => LAS.R i -> LAS.R i -> LAS.R i
47+softmax' x grad =
48+ let yTy = outer sm sm
49+ d = diag sm
50+ g = d - yTy
51+ in g #> grad
52+ where
53+ sm = softmax x
src/Grenade/Layers/Tanh.hs+7−14
@@ -1,16 +1,16 @@
11{-# LANGUAGE DataKinds #-}
22{-# LANGUAGE TypeOperators #-}
33{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE FlexibleInstances #-}
45{-# LANGUAGE MultiParamTypeClasses #-}
56module Grenade.Layers.Tanh (
67 Tanh (..)
78 ) where
89
910import Data.Serialize
11+import Data.Singletons
1012
11−import GHC.TypeLits
12−import Grenade.Core.Network
13−import Grenade.Core.Shape
13+import Grenade.Core
1414
1515-- | A Tanh layer.
1616-- A layer which can act between any shape of the same dimension, perfoming a tanh function.
@@ -26,17 +26,10 @@ instance Serialize Tanh where
2626 put _ = return ()
2727 get = return Tanh
2828
29−instance KnownNat i => Layer Tanh ('D1 i) ('D1 i) where
30− runForwards _ (S1D y) = S1D (tanh y)
31− runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (tanh' y * dEdy))
32−
33−instance (KnownNat i, KnownNat j) => Layer Tanh ('D2 i j) ('D2 i j) where
34− runForwards _ (S2D y) = S2D (tanh y)
35− runBackwards _ (S2D y) (S2D dEdy) = ((), S2D (tanh' y * dEdy))
36−
37−instance (KnownNat i, KnownNat j, KnownNat k) => Layer Tanh ('D3 i j k) ('D3 i j k) where
38− runForwards _ (S3D y) = S3D (tanh y)
39− runBackwards _ (S3D y) (S3D dEdy) = ((), S3D (tanh' y * dEdy))
29+instance (a ~ b, SingI a) => Layer Tanh a b where
30+ type Tape Tanh a b = S a
31+ runForwards _ a = (a, tanh a)
32+ runBackwards _ a g = ((), tanh' a * g)
4033
4134tanh' :: (Floating a) => a -> a
4235tanh' t = 1 - s ^ (2 :: Int) where s = tanh t
src/Grenade/Recurrent/Layers/Trivial.hs → src/Grenade/Layers/Trivial.hsrenamed+1−1
@@ -3,7 +3,7 @@
33{-# LANGUAGE TypeFamilies #-}
44{-# LANGUAGE MultiParamTypeClasses #-}
55{-# LANGUAGE FlexibleInstances #-}
6−module Grenade.Recurrent.Layers.Trivial (
6+module Grenade.Layers.Trivial (
77 Trivial (..)
88 ) where
99
src/Grenade/Recurrent.hs−1
@@ -6,4 +6,3 @@ import Grenade.Recurrent.Core.Network as X
66import Grenade.Recurrent.Core.Runner as X
77import Grenade.Recurrent.Layers.BasicRecurrent as X
88import Grenade.Recurrent.Layers.LSTM as X
9−import Grenade.Recurrent.Layers.Trivial as X
src/Grenade/Recurrent/Core/Network.hs+38−30
@@ -22,8 +22,7 @@ import Data.Singletons ( SingI )
2222import Data.Serialize
2323import qualified Data.Vector.Storable as V
2424
25−import Grenade.Core.Shape
26−import Grenade.Core.Network
25+import Grenade.Core
2726
2827import qualified Numeric.LinearAlgebra as LA
2928import qualified Numeric.LinearAlgebra.Static as LAS
@@ -43,33 +42,44 @@ class UpdateLayer x => RecurrentUpdateLayer x where
4342 type RecurrentShape x :: Shape
4443
4544class (RecurrentUpdateLayer x, SingI (RecurrentShape x)) => RecurrentLayer x (i :: Shape) (o :: Shape) where
45+ -- | Wengert Tape
46+ type RecTape x i o :: *
4647 -- | Used in training and scoring. Take the input from the previous
4748 -- layer, and give the output from this layer.
48− runRecurrentForwards :: x -> S (RecurrentShape x) -> S i -> (S (RecurrentShape x), S o)
49+ runRecurrentForwards :: x -> S (RecurrentShape x) -> S i -> (RecTape x i o, S (RecurrentShape x), S o)
4950 -- | Back propagate a step. Takes the current layer, the input that the
5051 -- layer gave from the input and the back propagated derivatives from
5152 -- the layer above.
5253 -- Returns the gradient layer and the derivatives to push back further.
53− runRecurrentBackwards :: x -> S (RecurrentShape x) -> S i -> S (RecurrentShape x) -> S o -> (Gradient x, S (RecurrentShape x), S i)
54+ runRecurrentBackwards :: x -> RecTape x i o -> S (RecurrentShape x) -> S o -> (Gradient x, S (RecurrentShape x), S i)
5455
5556data RecurrentNetwork :: [*] -> [Shape] -> * where
56− OR :: (SingI i, SingI o, Layer x i o) => !x -> RecurrentNetwork '[FeedForward x] '[i, o]
57− (:~~>) :: (SingI i, Layer x i h) => !x -> !(RecurrentNetwork xs (h ': hs)) -> RecurrentNetwork (FeedForward x ': xs) (i ': h ': hs)
58− (:~@>) :: (SingI i, RecurrentLayer x i h) => !x -> !(RecurrentNetwork xs (h ': hs)) -> RecurrentNetwork (Recurrent x ': xs) (i ': h ': hs)
57+ RNil :: SingI i
58+ => RecurrentNetwork '[] '[i]
59+
60+ (:~~>) :: (SingI i, Layer x i h)
61+ => !x
62+ -> !(RecurrentNetwork xs (h ': hs))
63+ -> RecurrentNetwork (FeedForward x ': xs) (i ': h ': hs)
64+
65+ (:~@>) :: (SingI i, RecurrentLayer x i h)
66+ => !x
67+ -> !(RecurrentNetwork xs (h ': hs))
68+ -> RecurrentNetwork (Recurrent x ': xs) (i ': h ': hs)
5969infixr 5 :~~>
6070infixr 5 :~@>
6171
62−instance Show (RecurrentNetwork l h) where
63− show (OR a) = "OR " ++ show a
64− show (i :~~> o) = show i ++ "\n:~~>\n" ++ show o
65− show (i :~@> o) = show i ++ "\n:~@>\n" ++ show o
66−
72+instance Show (RecurrentNetwork '[] '[i]) where
73+ show RNil = "NNil"
74+instance (Show x, Show (RecurrentNetwork xs rs)) => Show (RecurrentNetwork (FeedForward x ': xs) (i ': rs)) where
75+ show (x :~~> xs) = show x ++ "\n~~>\n" ++ show xs
76+instance (Show x, Show (RecurrentNetwork xs rs)) => Show (RecurrentNetwork (Recurrent x ': xs) (i ': rs)) where
77+ show (x :~@> xs) = show x ++ "\n~~>\n" ++ show xs
6778
6879-- | Recurrent inputs (sideways shapes on an imaginary unrolled graph)
6980-- Parameterised on the layers of a Network.
7081data RecurrentInputs :: [*] -> * where
71− ORS :: UpdateLayer x
72− => () -> RecurrentInputs '[FeedForward x]
82+ RINil :: RecurrentInputs '[]
7383 (:~~+>) :: UpdateLayer x
7484 => () -> !(RecurrentInputs xs) -> RecurrentInputs (FeedForward x ': xs)
7585 (:~@+>) :: (SingI (RecurrentShape x), RecurrentUpdateLayer x)
@@ -83,18 +93,17 @@ class CreatableRecurrent (xs :: [*]) (ss :: [Shape]) where
8393 -- | Create a network of the types requested
8494 randomRecurrent :: MonadRandom m => m (RecurrentNetwork xs ss, RecurrentInputs xs)
8595
86−instance (SingI i, SingI o, Layer x i o) => CreatableRecurrent (FeedForward x ': '[]) (i ': o ': '[]) where
87− randomRecurrent = do
88− thisLayer <- createRandom
89− return (OR thisLayer, ORS ())
96+instance SingI i => CreatableRecurrent '[] '[i] where
97+ randomRecurrent =
98+ return (RNil, RINil)
9099
91−instance (SingI i, Layer x i o, CreatableRecurrent xs (o ': r ': rs)) => CreatableRecurrent (FeedForward x ': xs) (i ': o ': r ': rs) where
100+instance (SingI i, Layer x i o, CreatableRecurrent xs (o ': rs)) => CreatableRecurrent (FeedForward x ': xs) (i ': o ': rs) where
92101 randomRecurrent = do
93102 thisLayer <- createRandom
94103 (rest, resti) <- randomRecurrent
95104 return (thisLayer :~~> rest, () :~~+> resti)
96105
97−instance (SingI i, RecurrentLayer x i o, CreatableRecurrent xs (o ': r ': rs)) => CreatableRecurrent (Recurrent x ': xs) (i ': o ': r ': rs) where
106+instance (SingI i, RecurrentLayer x i o, CreatableRecurrent xs (o ': rs)) => CreatableRecurrent (Recurrent x ': xs) (i ': o ': rs) where
98107 randomRecurrent = do
99108 thisLayer <- createRandom
100109 thisShape <- randomOfShape
@@ -102,28 +111,27 @@ instance (SingI i, RecurrentLayer x i o, CreatableRecurrent xs (o ': r ': rs)) =
102111 return (thisLayer :~@> rest, thisShape :~@+> resti)
103112
104113-- | Add very simple serialisation to the recurrent network
105−instance (SingI i, SingI o, Layer x i o, Serialize x) => Serialize (RecurrentNetwork '[FeedForward x] '[i, o]) where
106− put (OR x) = put x
107− put _ = error "impossible"
108− get = OR <$> get
114+instance SingI i => Serialize (RecurrentNetwork '[] '[i]) where
115+ put RNil = pure ()
116+ get = pure RNil
109117
110−instance (SingI i, Layer x i o, Serialize x, Serialize (RecurrentNetwork xs (o ': r ': rs))) => Serialize (RecurrentNetwork (FeedForward x ': xs) (i ': o ': r ': rs)) where
118+instance (SingI i, Layer x i o, Serialize x, Serialize (RecurrentNetwork xs (o ': rs))) => Serialize (RecurrentNetwork (FeedForward x ': xs) (i ': o ': rs)) where
111119 put (x :~~> r) = put x >> put r
112120 get = (:~~>) <$> get <*> get
113121
114−instance (SingI i, RecurrentLayer x i o, Serialize x, Serialize (RecurrentNetwork xs (o ': r ': rs))) => Serialize (RecurrentNetwork (Recurrent x ': xs) (i ': o ': r ': rs)) where
122+instance (SingI i, RecurrentLayer x i o, Serialize x, Serialize (RecurrentNetwork xs (o ': rs))) => Serialize (RecurrentNetwork (Recurrent x ': xs) (i ': o ': rs)) where
115123 put (x :~@> r) = put x >> put r
116124 get = (:~@>) <$> get <*> get
117125
118−instance (UpdateLayer x) => (Serialize (RecurrentInputs '[FeedForward x])) where
126+instance (Serialize (RecurrentInputs '[])) where
119127 put _ = return ()
120− get = return (ORS ())
128+ get = return RINil
121129
122−instance (UpdateLayer x, Serialize (RecurrentInputs (y ': ys))) => (Serialize (RecurrentInputs (FeedForward x ': y ': ys))) where
130+instance (UpdateLayer x, Serialize (RecurrentInputs ys)) => (Serialize (RecurrentInputs (FeedForward x ': ys))) where
123131 put ( () :~~+> rest) = put rest
124132 get = ( () :~~+> ) <$> get
125133
126−instance (SingI (RecurrentShape x), RecurrentUpdateLayer x, Serialize (RecurrentInputs (y ': ys))) => (Serialize (RecurrentInputs (Recurrent x ': y ': ys))) where
134+instance (SingI (RecurrentShape x), RecurrentUpdateLayer x, Serialize (RecurrentInputs ys)) => (Serialize (RecurrentInputs (Recurrent x ': ys))) where
127135 put ( i :~@+> rest ) = do
128136 _ <- (case i of
129137 (S1D x) -> putListOf put . LA.toList . LAS.extract $ x
src/Grenade/Recurrent/Core/Runner.hs+36−41
@@ -3,18 +3,23 @@
33{-# LANGUAGE DataKinds #-}
44{-# LANGUAGE ScopedTypeVariables #-}
55{-# LANGUAGE TypeOperators #-}
6+{-# LANGUAGE CPP #-}
67{-# LANGUAGE TypeFamilies #-}
78{-# LANGUAGE FlexibleContexts #-}
89{-# LANGUAGE RankNTypes #-}
910{-# LANGUAGE RecordWildCards #-}
11+
12+#if __GLASGOW_HASKELL__ < 800
13+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
14+#endif
15+
1016module Grenade.Recurrent.Core.Runner (
1117 trainRecurrent
1218 , runRecurrent
1319 ) where
1420
1521import Data.Singletons.Prelude
16−import Grenade.Core.Network
17−import Grenade.Core.Shape
22+import Grenade.Core
1823
1924import Grenade.Recurrent.Core.Network
2025
@@ -48,11 +53,13 @@ trainRecurrent rate network recinputs examples =
4853 -- Note we're doing training here, we could just return a list of gradients
4954 -- (and probably will in future).
5055 go !xs (layer :~~> n) (() :~~+> nIn)
51− = let ys = runForwards layer <$> xs
56+ = let tys = runForwards layer <$> xs
57+ tapes = fst <$> tys
58+ ys = snd <$> tys
5259 -- recursively run the rest of the network, and get the gradients from above.
5360 (newFN, ig, grads) = go ys n nIn
5461 -- calculate the gradient for this layer to pass down,
55− back = uncurry (runBackwards layer) <$> zip (reverse xs) grads
62+ back = uncurry (runBackwards layer) <$> zip (reverse tapes) grads
5663 -- the new trained layer.
5764 newlayer = runUpdates rate layer (fst <$> back)
5865
@@ -61,11 +68,13 @@ trainRecurrent rate network recinputs examples =
6168 -- This is a recurrent layer, so we need to do a scan, first input to last, providing
6269 -- the recurrent shape output to the next layer.
6370 go !xs (layer :~@> n) (g :~@+> nIn)
64− = let ys = scanlFrom layer g xs
71+ = let tys = scanlFrom layer g xs
72+ tapes = fst <$> tys
73+ ys = snd <$> tys
6574
66− (newFN, ig, grads) = go (snd <$> ys) n nIn
75+ (newFN, ig, grads) = go ys n nIn
6776
68− backExamples = zip3 (fst <$> reverse ys) (reverse xs) grads
77+ backExamples = zip (reverse tapes) grads
6978
7079 (rg, back) = myscanbackward layer backExamples
7180 -- the new trained layer.
@@ -74,21 +83,12 @@ trainRecurrent rate network recinputs examples =
7483
7584 -- Handle the output layer, bouncing the derivatives back down.
7685 -- We may not have a target for each example, so when we don't use 0 gradient.
77− go !xs (OR layer) (ORS ())
78− = let ys = runForwards layer <$> xs
79− -- recursively run the rest of the network, and get the gradients from above.
80− back = uncurry (runBackwards layer) <$> zip xs (zipWith makeError ys targets)
81− -- the new trained layer.
82− newlayer = runUpdates rate layer (reverse $ fst <$> back)
83− in (OR newlayer, ORS (), reverse (snd <$> back))
84−
85− go _ _ _ =
86− error "Impossible for network and recurrent inputs to have different shapes"
87−
88−
89− makeError :: S (Last shapes) -> Maybe (S (Last shapes)) -> S (Last shapes)
90− makeError _ Nothing = 0
91− makeError y (Just t) = y - t
86+ go !xs RNil RINil
87+ = (RNil, RINil, reverse (zipWith makeError xs targets))
88+ where
89+ makeError :: S (Last shapes) -> Maybe (S (Last shapes)) -> S (Last shapes)
90+ makeError _ Nothing = 0
91+ makeError y (Just t) = y - t
9292
9393 updateRecInputs :: forall sublayers.
9494 LearningParameters
@@ -102,31 +102,29 @@ trainRecurrent rate network recinputs examples =
102102 updateRecInputs l@LearningParameters {..} (x :~@+> xs) (y :~@+> ys)
103103 = (realToFrac (learningRate * learningRegulariser) * x - realToFrac learningRate * y) :~@+> updateRecInputs l xs ys
104104
105− updateRecInputs _ (ORS ()) (ORS ())
106− = ORS ()
107− updateRecInputs _ _ _
108− = error "Impossible for updateRecInputs to have different shapes"
105+ updateRecInputs _ RINil RINil
106+ = RINil
109107
110108scanlFrom :: forall x i o. RecurrentLayer x i o
111109 => x -- ^ the layer
112110 -> S (RecurrentShape x) -- ^ place to start
113111 -> [S i] -- ^ list of inputs to scan through
114− -> [(S (RecurrentShape x), S o)] -- ^ list of scan inputs and outputs
112+ -> [(RecTape x i o, S o)] -- ^ list of scan inputs and outputs
115113scanlFrom !layer !recShape (x:xs) =
116− let (lerec, lepush) = runRecurrentForwards layer recShape x
117− in (recShape, lepush) : scanlFrom layer lerec xs
114+ let (tape, lerec, lepush) = runRecurrentForwards layer recShape x
115+ in (tape, lepush) : scanlFrom layer lerec xs
118116scanlFrom _ _ [] = []
119117
120118myscanbackward :: forall x i o. RecurrentLayer x i o
121119 => x -- ^ the layer
122− -> [(S (RecurrentShape x), S i, S o)] -- ^ the list of inputs and output to scan over
120+ -> [(RecTape x i o, S o)] -- ^ the list of inputs and output to scan over
123121 -> (S (RecurrentShape x), [(Gradient x, S i)]) -- ^ list of gradients to fold and inputs to backprop
124122myscanbackward layer =
125123 goX 0
126124 where
127− goX :: S (RecurrentShape x) -> [(S (RecurrentShape x), S i, S o)] -> (S (RecurrentShape x), [(Gradient x, S i)])
128− goX !lastback ((recShape, lastin, backgrad):xs) =
129− let (layergrad, recgrad, ingrad) = runRecurrentBackwards layer recShape lastin lastback backgrad
125+ goX :: S (RecurrentShape x) -> [(RecTape x i o, S o)] -> (S (RecurrentShape x), [(Gradient x, S i)])
126+ goX !lastback ((recTape, backgrad):xs) =
127+ let (layergrad, recgrad, ingrad) = runRecurrentBackwards layer recTape lastback backgrad
130128 (pushedback, ll) = goX recgrad xs
131129 in (pushedback, (layergrad, ingrad) : ll)
132130 goX !lastback [] = (lastback, [])
@@ -136,15 +134,12 @@ runRecurrent :: RecurrentNetwork layers shapes
136134 -> RecurrentInputs layers -> S (Head shapes)
137135 -> (RecurrentInputs layers, S (Last shapes))
138136runRecurrent (layer :~~> n) (() :~~+> nr) !x
139− = let ys = runForwards layer x
137+ = let (_, ys) = runForwards layer x
140138 (nr', o) = runRecurrent n nr ys
141139 in (() :~~+> nr', o)
142140runRecurrent (layer :~@> n) (recin :~@+> nr) !x
143− = let (recin', y) = runRecurrentForwards layer recin x
144− (nr', o) = runRecurrent n nr y
141+ = let (_, recin', y) = runRecurrentForwards layer recin x
142+ (nr', o) = runRecurrent n nr y
145143 in (recin' :~@+> nr', o)
146−runRecurrent (OR layer) (ORS ()) !x
147− = (ORS (), runForwards layer x)
148−
149−runRecurrent _ _ _
150− = error "Impossible for the gradients of a network to have a different length or shape to the network"
144+runRecurrent RNil RINil !x
145+ = (RINil, x)
src/Grenade/Recurrent/Layers/BasicRecurrent.hs+5−4
@@ -24,8 +24,7 @@ import Numeric.LinearAlgebra.Static
2424
2525import GHC.TypeLits
2626
27−import Grenade.Core.Network
28−import Grenade.Core.Shape
27+import Grenade.Core
2928import Grenade.Recurrent.Core.Network
3029
3130data BasicRecurrent :: Nat -- Input layer size
@@ -72,13 +71,15 @@ instance (KnownNat i, KnownNat o, KnownNat (i + o), i <= (i + o), o ~ ((i + o) -
7271 type RecurrentShape (BasicRecurrent i o) = 'D1 o
7372
7473instance (KnownNat i, KnownNat o, KnownNat (i + o), i <= (i + o), o ~ ((i + o) - i)) => RecurrentLayer (BasicRecurrent i o) ('D1 i) ('D1 o) where
74+
75+ type RecTape (BasicRecurrent i o) ('D1 i) ('D1 o) = (S ('D1 o), S ('D1 i))
7576 -- Do a matrix vector multiplication and return the result.
7677 runRecurrentForwards (BasicRecurrent wB _ wN _) (S1D lastOutput) (S1D thisInput) =
7778 let thisOutput = S1D $ wB + wN #> (thisInput # lastOutput)
78− in (thisOutput, thisOutput)
79+ in ((S1D lastOutput, S1D thisInput), thisOutput, thisOutput)
7980
8081 -- Run a backpropogation step for a full connected layer.
81− runRecurrentBackwards (BasicRecurrent _ _ wN _) (S1D lastOutput) (S1D thisInput) (S1D dRec) (S1D dEdy) =
82+ runRecurrentBackwards (BasicRecurrent _ _ wN _) (S1D lastOutput, S1D thisInput) (S1D dRec) (S1D dEdy) =
8283 let biasGradient = (dRec + dEdy)
8384 layerGrad = (dRec + dEdy) `outer` (thisInput # lastOutput)
8485 -- calcluate derivatives for next step
src/Grenade/Recurrent/Layers/LSTM.hs+5−5
@@ -20,7 +20,6 @@ module Grenade.Recurrent.Layers.LSTM (
2020
2121import Control.Monad.Random ( MonadRandom, getRandom )
2222
23−
2423-- import Data.List ( foldl1' )
2524import Data.Proxy
2625import Data.Serialize
@@ -29,8 +28,7 @@ import Data.Singletons.TypeLits
2928import qualified Numeric.LinearAlgebra as LA
3029import Numeric.LinearAlgebra.Static
3130
32−import Grenade.Core.Network
33−import Grenade.Core.Shape
31+import Grenade.Core
3432
3533import Grenade.Layers.Internal.Update
3634
@@ -131,6 +129,8 @@ instance (KnownNat i, KnownNat o) => RecurrentUpdateLayer (LSTM i o) where
131129 type RecurrentShape (LSTM i o) = 'D1 o
132130
133131instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) where
132+
133+ type RecTape (LSTM i o) ('D1 i) ('D1 o) = (S ('D1 o), S ('D1 i))
134134 -- Forward propagation for the LSTM layer.
135135 -- The size of the cell state is also the size of the output.
136136 runRecurrentForwards (LSTM (LSTMWeights {..}) _) (S1D cell) (S1D input) =
@@ -146,7 +146,7 @@ instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) w
146146 c_t = f_t * cell + i_t * c_x
147147 -- Output (it's sometimes recommended to use tanh c_t)
148148 h_t = o_t * c_t
149− in (S1D c_t, S1D h_t)
149+ in ((S1D cell, S1D input), S1D c_t, S1D h_t)
150150
151151 -- Run a backpropogation step for an LSTM layer.
152152 -- We're doing all the derivatives by hand here, so one should
@@ -154,7 +154,7 @@ instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) w
154154 --
155155 -- There's a test version using the AD library without hmatrix in the test
156156 -- suite. These should match always.
157− runRecurrentBackwards (LSTM (LSTMWeights {..}) _) (S1D cell) (S1D input) (S1D cellGrad) (S1D h_t') =
157+ runRecurrentBackwards (LSTM (LSTMWeights {..}) _) (S1D cell, S1D input) (S1D cellGrad) (S1D h_t') =
158158 -- We're not keeping the Wengert tape during the forward pass,
159159 -- so we're duplicating some work here.
160160 --
test/Test/Grenade/Layers/Convolution.hs+3−4
@@ -15,8 +15,7 @@ import Data.Singletons ()
1515import GHC.TypeLits
1616import GHC.TypeLits.Witnesses
1717
18−import Grenade.Core.Shape
19−import Grenade.Core.Network
18+import Grenade.Core
2019import Grenade.Layers.Convolution
2120
2221import Disorder.Jack
@@ -92,9 +91,9 @@ prop_conv_net =
9291 , (unsafeCoerce (Dict :: Dict ()) :: Dict (((outCols - 1) * strideCols) ~ (inCols - kernelCols)))) of
9392 (Dict, Dict, Dict, Dict) ->
9493 gamble (S3D <$> uniformSample) $ \(input :: S ('D3 inRows inCols channels)) ->
95− let output :: S ('D3 outRows outCols filters) = runForwards convLayer input
94+ let (tape, output :: S ('D3 outRows outCols filters)) = runForwards convLayer input
9695 backed :: (Gradient (Convolution channels filters kernelRows kernelCols strideRows strideCols), S ('D3 inRows inCols channels))
97− = runBackwards convLayer input output
96+ = runBackwards convLayer tape output
9897 in backed `seq` True
9998 ) :: Property
10099 ) :: Property
test/Test/Grenade/Layers/FullyConnected.hs+4−5
@@ -12,8 +12,7 @@ import Data.Singletons ()
1212
1313import GHC.TypeLits
1414
15−import Grenade.Core.Shape
16−import Grenade.Core.Network
15+import Grenade.Core
1716import Grenade.Layers.FullyConnected
1817
1918import Disorder.Jack
@@ -39,15 +38,15 @@ genOpaqueFullyConnected = do
3938 bM <- randomVector
4039 wN <- uniformSample
4140 kM <- uniformSample
42− return . OpaqueFullyConnected $ (FullyConnected wB bM wN kM :: FullyConnected i' o')
41+ return . OpaqueFullyConnected $ (FullyConnected (FullyConnected' wB wN) (FullyConnected' bM kM) :: FullyConnected i' o')
4342
4443prop_fully_connected_forwards :: Property
4544prop_fully_connected_forwards =
4645 gamble genOpaqueFullyConnected $ \(OpaqueFullyConnected (fclayer :: FullyConnected i o)) ->
4746 gamble (S1D <$> randomVector) $ \(input :: S ('D1 i)) ->
48− let output :: S ('D1 o) = runForwards fclayer input
47+ let (tape, output :: S ('D1 o)) = runForwards fclayer input
4948 backed :: (Gradient (FullyConnected i o), S ('D1 i))
50− = runBackwards fclayer input output
49+ = runBackwards fclayer tape output
5150 in backed `seq` True
5251
5352return []
test/Test/Grenade/Layers/Nonlinear.hsnew file+72
@@ -0,0 +1,72 @@
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE TemplateHaskell #-}
3+{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE KindSignatures #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
7+{-# LANGUAGE LambdaCase #-}
8+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
9+module Test.Grenade.Layers.Nonlinear where
10+
11+import Data.Singletons
12+
13+import Grenade
14+import GHC.TypeLits
15+
16+import Disorder.Jack
17+
18+import Test.Jack.Hmatrix
19+import Test.Jack.TypeLits
20+
21+import Numeric.LinearAlgebra.Static ( norm_Inf )
22+
23+prop_sigmoid_grad :: Property
24+prop_sigmoid_grad =
25+ gambleDisplay (const "Shape") genShape $ \case
26+ (SomeSing (r :: Sing s)) ->
27+ withSingI r $
28+ gamble genOfShape $ \(ds :: S s) ->
29+ let (tape, f :: S s) = runForwards Logit ds
30+ ((), ret :: S s) = runBackwards Logit tape (1 :: S s)
31+ (_, numer :: S s) = runForwards Logit (ds + 0.0001)
32+ numericalGradient = (numer - f) * 10000
33+ in counterexample (show numericalGradient ++ show ret)
34+ ((case numericalGradient - ret of
35+ (S1D x) -> norm_Inf x < 0.0001
36+ (S2D x) -> norm_Inf x < 0.0001
37+ (S3D x) -> norm_Inf x < 0.0001) :: Bool)
38+
39+prop_tanh_grad :: Property
40+prop_tanh_grad =
41+ gambleDisplay (const "Shape") genShape $ \case
42+ (SomeSing (r :: Sing s)) ->
43+ withSingI r $
44+ gamble genOfShape $ \(ds :: S s) ->
45+ let (tape, f :: S s) = runForwards Tanh ds
46+ ((), ret :: S s) = runBackwards Tanh tape (1 :: S s)
47+ (_, numer :: S s) = runForwards Tanh (ds + 0.0001)
48+ numericalGradient = (numer - f) * 10000
49+ in counterexample (show numericalGradient ++ show ret)
50+ ((case numericalGradient - ret of
51+ (S1D x) -> norm_Inf x < 0.001
52+ (S2D x) -> norm_Inf x < 0.001
53+ (S3D x) -> norm_Inf x < 0.001) :: Bool)
54+
55+prop_softmax_grad :: Property
56+prop_softmax_grad =
57+ gamble genNat $ \case
58+ (SomeNat (_ :: Proxy s)) ->
59+ gamble genOfShape $ \(ds :: S ('D1 s)) ->
60+ let (tape, f :: S ('D1 s)) = runForwards Relu ds
61+ ((), ret :: S ('D1 s)) = runBackwards Relu tape (1 :: S ('D1 s))
62+ (_, numer :: S ('D1 s)) = runForwards Relu (ds + 0.0001)
63+ numericalGradient = (numer - f) * 10000
64+ in counterexample (show numericalGradient ++ show ret)
65+ ((case numericalGradient - ret of
66+ (S1D x) -> norm_Inf x < 0.0001) :: Bool)
67+
68+
69+return []
70+tests :: IO Bool
71+tests = $quickCheckAll
72+
test/Test/Grenade/Layers/PadCrop.hsnew file+34
@@ -0,0 +1,34 @@
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE TemplateHaskell #-}
3+{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE KindSignatures #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
7+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
8+module Test.Grenade.Layers.PadCrop where
9+
10+import Grenade
11+
12+import Disorder.Jack
13+
14+import Numeric.LinearAlgebra.Static ( norm_Inf )
15+
16+import Test.Jack.Hmatrix
17+
18+prop_pad_crop :: Property
19+prop_pad_crop =
20+ let net :: Network '[Pad 2 3 4 6, Crop 2 3 4 6] '[ 'D3 7 9 5, 'D3 16 15 5, 'D3 7 9 5 ]
21+ net = Pad :~> Crop :~> NNil
22+ in gamble genOfShape $ \(d :: S ('D3 7 9 5)) ->
23+ let (tapes, res) = runForwards net d
24+ (_ , grad) = runBackwards net tapes d
25+ in d ~~~ res .&&. grad ~~~ d
26+
27+(~~~) :: S x -> S x -> Bool
28+(S1D x) ~~~ (S1D y) = norm_Inf (x - y) < 0.00001
29+(S2D x) ~~~ (S2D y) = norm_Inf (x - y) < 0.00001
30+(S3D x) ~~~ (S3D y) = norm_Inf (x - y) < 0.00001
31+
32+return []
33+tests :: IO Bool
34+tests = $quickCheckAll
test/Test/Grenade/Recurrent/Layers/LSTM.hs+7−7
@@ -44,7 +44,7 @@ prop_lstm_reference_forwards =
4444 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
4545 let actual = runRecurrentForwards net (S1D cell) (S1D input)
4646 in case actual of
47− ((S1D cellOut) :: S ('D1 2), (S1D output) :: S ('D1 2)) ->
47+ (_, (S1D cellOut) :: S ('D1 2), (S1D output) :: S ('D1 2)) ->
4848 let cellOut' = Reference.Vector . H.toList . S.extract $ cellOut
4949 output' = Reference.Vector . H.toList . S.extract $ output
5050 refNet = Reference.lstmToReference lstmWeights
@@ -57,9 +57,9 @@ prop_lstm_reference_backwards =
5757 gamble randomVector $ \(input :: S.R 3) ->
5858 gamble randomVector $ \(cell :: S.R 2) ->
5959 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
60− let actualBacks = runRecurrentBackwards net (S1D cell) (S1D input) (S1D (S.konst 1) :: S ('D1 2)) (S1D (S.konst 1) :: S ('D1 2))
60+ let actualBacks = runRecurrentBackwards net (S1D cell, S1D input) (S1D (S.konst 1) :: S ('D1 2)) (S1D (S.konst 1) :: S ('D1 2))
6161 in case actualBacks of
62− (actualGradients, _, _) ->
62+ (actualGradients, _, _ :: S ('D1 3)) ->
6363 let refNet = Reference.lstmToReference lstmWeights
6464 refCell = Reference.Vector . H.toList . S.extract $ cell
6565 refInput = Reference.Vector . H.toList . S.extract $ input
@@ -70,9 +70,9 @@ prop_lstm_reference_backwards_input =
7070 gamble randomVector $ \(input :: S.R 3) ->
7171 gamble randomVector $ \(cell :: S.R 2) ->
7272 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
73− let actualBacks = runRecurrentBackwards net (S1D cell) (S1D input) (S1D (S.konst 1) :: S ('D1 2)) (S1D (S.konst 1) :: S ('D1 2))
73+ let actualBacks = runRecurrentBackwards net (S1D cell, S1D input) (S1D (S.konst 1) :: S ('D1 2)) (S1D (S.konst 1) :: S ('D1 2))
7474 in case actualBacks of
75− (_, _, S1D actualGradients) ->
75+ (_, _, S1D actualGradients :: S ('D1 3)) ->
7676 let refNet = Reference.lstmToReference lstmWeights
7777 refCell = Reference.Vector . H.toList . S.extract $ cell
7878 refInput = Reference.Vector . H.toList . S.extract $ input
@@ -83,9 +83,9 @@ prop_lstm_reference_backwards_cell =
8383 gamble randomVector $ \(input :: S.R 3) ->
8484 gamble randomVector $ \(cell :: S.R 2) ->
8585 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
86− let actualBacks = runRecurrentBackwards net (S1D cell) (S1D input) (S1D (S.konst 1) :: S ('D1 2)) (S1D (S.konst 1) :: S ('D1 2))
86+ let actualBacks = runRecurrentBackwards net (S1D cell, S1D input) (S1D (S.konst 1) :: S ('D1 2)) (S1D (S.konst 1) :: S ('D1 2))
8787 in case actualBacks of
88− (_, S1D actualGradients, _) ->
88+ (_, S1D actualGradients, _ :: S ('D1 3)) ->
8989 let refNet = Reference.lstmToReference lstmWeights
9090 refCell = Reference.Vector . H.toList . S.extract $ cell
9191 refInput = Reference.Vector . H.toList . S.extract $ input
test/Test/Jack/Hmatrix.hs+12
@@ -1,9 +1,13 @@
11{-# LANGUAGE RankNTypes #-}
22{-# LANGUAGE DataKinds #-}
33{-# LANGUAGE ScopedTypeVariables #-}
4+{-# LANGUAGE GADTs #-}
45
56module Test.Jack.Hmatrix where
67
8+import Grenade
9+import Data.Singletons
10+
711import Disorder.Jack
812
913import GHC.TypeLits
@@ -15,3 +19,11 @@ randomVector = (\s -> HStatic.randomVector s HStatic.Uniform * 2 - 1) <$> sizedN
1519
1620uniformSample :: forall m n. (KnownNat m, KnownNat n) => Jack (HStatic.L m n)
1721uniformSample = (\s -> HStatic.uniformSample s (-1) 1 ) <$> sizedNat
22+
23+-- | Generate random data of the desired shape
24+genOfShape :: forall x. ( SingI x ) => Jack (S x)
25+genOfShape =
26+ case (sing :: Sing x) of
27+ D1Sing -> S1D <$> randomVector
28+ D2Sing -> S2D <$> uniformSample
29+ D3Sing -> S3D <$> uniformSample
test/Test/Jack/TypeLits.hs+41−1
@@ -1,14 +1,54 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE RankNTypes #-}
23{-# LANGUAGE DataKinds #-}
34{-# LANGUAGE ScopedTypeVariables #-}
4−
5+{-# LANGUAGE PolyKinds #-}
56module Test.Jack.TypeLits where
67
8+import Data.Constraint
9+#if __GLASGOW_HASKELL__ < 800
10+import Data.Proxy
11+#endif
12+import Data.Singletons
713import Disorder.Jack
814
15+import Grenade
16+
917import GHC.TypeLits
18+import GHC.TypeLits.Witnesses
1019
1120genNat :: Jack SomeNat
1221genNat = do
1322 Just n <- someNatVal <$> choose (1, 10)
1423 return n
24+
25+genShape :: Jack (SomeSing Shape)
26+genShape
27+ = oneOf [
28+ genD1
29+ , genD2
30+ , genD3
31+ ]
32+
33+genD1 :: Jack (SomeSing Shape)
34+genD1 = do
35+ n <- genNat
36+ return $ case n of
37+ SomeNat (_ :: Proxy x) -> SomeSing (sing :: Sing ('D1 x))
38+
39+genD2 :: Jack (SomeSing Shape)
40+genD2 = do
41+ n <- genNat
42+ m <- genNat
43+ return $ case (n, m) of
44+ (SomeNat (_ :: Proxy x), SomeNat (_ :: Proxy y)) -> SomeSing (sing :: Sing ('D2 x y))
45+
46+genD3 :: Jack (SomeSing Shape)
47+genD3 = do
48+ n <- genNat
49+ m <- genNat
50+ o <- genNat
51+ return $ case (n, m, o) of
52+ (SomeNat (px :: Proxy x), SomeNat (_ :: Proxy y), SomeNat (pz :: Proxy z)) ->
53+ case natDict px %* natDict pz of
54+ Dict -> SomeSing (sing :: Sing ('D3 x y z))
test/test.hs+4
@@ -3,6 +3,8 @@ import Disorder.Core.Main
33import qualified Test.Grenade.Layers.Pooling
44import qualified Test.Grenade.Layers.Convolution
55import qualified Test.Grenade.Layers.FullyConnected
6+import qualified Test.Grenade.Layers.Nonlinear
7+import qualified Test.Grenade.Layers.PadCrop
68
79import qualified Test.Grenade.Layers.Internal.Convolution
810import qualified Test.Grenade.Layers.Internal.Pooling
@@ -15,6 +17,8 @@ main =
1517 Test.Grenade.Layers.Pooling.tests
1618 , Test.Grenade.Layers.Convolution.tests
1719 , Test.Grenade.Layers.FullyConnected.tests
20+ , Test.Grenade.Layers.Nonlinear.tests
21+ , Test.Grenade.Layers.PadCrop.tests
1822
1923 , Test.Grenade.Layers.Internal.Convolution.tests
2024 , Test.Grenade.Layers.Internal.Pooling.tests