on master help sign in
Merge pull request #22 from HuwCampbell/topic/tape
7e47a6aHuw Campbell
README.md+15−6
@@ -16,8 +16,10 @@ for concise and precise specifications of complex networks in Haskell.
16As an example, a network which can achieve ~1.5% error on MNIST can be
16As an example, a network which can achieve ~1.5% error on MNIST can be
17specified and initialised with random weights in a few lines of code with
17specified and initialised with random weights in a few lines of code with
18```haskell
18```haskell
19+type MNIST
20+ = Network
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]
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]
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]
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]
21
23
22randomMnist :: MonadRandom m => m MNIST
24randomMnist :: MonadRandom m => m MNIST
23randomMnist = randomNetwork
25randomMnist = randomNetwork
@@ -31,8 +33,10 @@ If recurrent neural networks are more your style, you can try defining something
31["unreasonably effective"](http://karpathy.github.io/2015/05/21/rnn-effectiveness/)
33["unreasonably effective"](http://karpathy.github.io/2015/05/21/rnn-effectiveness/)
32with
34with
33```haskell
35```haskell
36+type Shakespeare
37+ = RecurrentNetwork
34−type Shakespeare = RecurrentNetwork '[ R (LSTM 40 80), R (LSTM 80 40), F (FullyConnected 40 40), F Logit]
38+ '[ 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 ]
39+ '[ 'D1 40, 'D1 80, 'D1 40, 'D1 40, 'D1 40 ]
36```
40```
37
41
38Design
42Design
@@ -45,8 +49,13 @@ data that are passed between the layers.
45The definition of a network is surprisingly simple:
49The definition of a network is surprisingly simple:
46```haskell
50```haskell
47data Network :: [*] -> [Shape] -> * where
51data Network :: [*] -> [Shape] -> * where
52+ NNil :: SingI i
48− O :: (SingI i, SingI o, Layer x i o) => !x -> Network '[x] '[i, o]
53+ => Network '[] '[i]
54+
49− (:~>) :: (SingI i, SingI h, Layer x i h) => !x -> !(Network xs (h ': hs)) -> Network (x ': xs) (i ': h ': hs)
55+ (:~>) :: (SingI i, SingI h, Layer x i h)
56+ => !x
57+ -> !(Network xs (h ': hs))
58+ -> Network (x ': xs) (i ': h ': hs)
50```
59```
51
60
52The `Layer x i o` constraint ensures that the layer `x` can sensibly perform a
61The `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
22 let upIn512 :: H.R 262144 = H.randomVector 1 H.Uniform * 2 - 1
22 let upIn512 :: H.R 262144 = H.randomVector 1 H.Uniform * 2 - 1
23
23
24 defaultMain [
24 defaultMain [
25− bgroup "lstm" [ bench "forwards-60" $ nf (nfT2 . uncurry (testRun60 layer60)) (rec60, input40)
25+ bgroup "lstm" [ bench "forwards-60" $ nf (nfT3 . uncurry (testRun60 layer60)) (rec60, input40)
26− , bench "forwards-512" $ nf (nfT2 . uncurry (testRun512 layer512)) (rec512, input40)
26+ , bench "forwards-512" $ nf (nfT3 . uncurry (testRun512 layer512)) (rec512, input40)
27 , bench "backwards-60" $ nf (nfT3 . uncurry4 (testRun60' layer60)) (rec60, input40, rec60, rec60)
27 , bench "backwards-60" $ nf (nfT3 . uncurry4 (testRun60' layer60)) (rec60, input40, rec60, rec60)
28 , bench "backwards-512" $ nf (nfT3 . uncurry4 (testRun512' layer512)) (rec512, input40, rec512, rec512)
28 , bench "backwards-512" $ nf (nfT3 . uncurry4 (testRun512' layer512)) (rec512, input40, rec512, rec512)
29 ]
29 ]
@@ -36,17 +36,17 @@ main = do
36 ]
36 ]
37 ]
37 ]
38
38
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))
40testRun60 = runRecurrentForwards
40testRun60 = runRecurrentForwards
41
41
42testRun60' :: 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))
42testRun60' :: 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
44
44
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))
46testRun512 = runRecurrentForwards
46testRun512 = runRecurrentForwards
47
47
48testRun512' :: 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))
48testRun512' :: 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
50
50
51uncurry4 :: (t -> t1 -> t2 -> t3 -> t4) -> (t, t1, t2, t3) -> t4
51uncurry4 :: (t -> t1 -> t2 -> t3 -> t4) -> (t, t1, t2, t3) -> t4
52uncurry4 f (a,b,c,d) = f a b c d
52uncurry4 f (a,b,c,d) = f a b c d
@@ -61,12 +61,11 @@ nfT3 :: (a, b, c) -> (b, c)
61nfT3 (!_, !b, !c) = (b, c)
61nfT3 (!_, !b, !c) = (b, c)
62
62
63
63
64−type F = FeedForward
65type R = Recurrent
64type R = Recurrent
66−type RecNet = RecurrentNetwork '[ R (LSTM 40 512), R (LSTM 512 40), F (FullyConnected 40 40), F Logit]
65+type RecNet = RecurrentNetwork '[ R (LSTM 40 512), R (LSTM 512 40) ]
67− '[ 'D1 40, 'D1 512, 'D1 40, 'D1 40, 'D1 40 ]
66+ '[ 'D1 40, 'D1 512, 'D1 40 ]
68
67
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) ]
70
69
71lp :: LearningParameters
70lp :: LearningParameters
72lp = LearningParameters 0.1 0 0
71lp = LearningParameters 0.1 0 0
bench/bench.hs+47−18
@@ -1,26 +1,55 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
1import Criterion.Main
3import Criterion.Main
2
4
5+import Grenade
6+
3import Grenade.Layers.Internal.Convolution
7import Grenade.Layers.Internal.Convolution
4import Grenade.Layers.Internal.Pooling
8import Grenade.Layers.Internal.Pooling
5
9
6import Numeric.LinearAlgebra
10import Numeric.LinearAlgebra
7
11
8main :: IO ()
12main :: IO ()
13+main = do
14+ x :: S ('D2 60 60 ) <- randomOfShape
15+ y :: S ('D3 60 60 1) <- randomOfShape
16+
9−main = defaultMain [
17+ defaultMain [
10− bgroup "im2col" [ bench "im2col 3x4" $ whnf (im2col 2 2 1 1) ((3><4) [1..])
18+ 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..])
19+ , 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..])
20+ , bench "im2col 100x100" $ whnf (im2col 10 10 1 1) ((100><100) [1..])
13− ]
21+ ]
14− , bgroup "col2im" [ bench "col2im 3x4" $ whnf (col2im 2 2 1 1 3 4) ((6><4) [1..])
22+ , 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..])
23+ , 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..])
24+ , bench "col2im 100x100" $ whnf (col2im 10 10 1 1 100 100) ((8281><100) [1..])
17− ]
25+ ]
18− , bgroup "poolfw" [ bench "poolforwards 3x4" $ whnf (poolForward 1 3 4 2 2 1 1) ((3><4) [1..])
26+ , 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..])
27+ , 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..])
28+ , bench "poolforwards 100x100" $ whnf (poolForward 1 100 100 10 10 1 1) ((100><100) [1..])
21− ]
29+ ]
22− , bgroup "poolbw" [ bench "poolbackwards 3x4" $ whnf (poolBackward 1 3 4 2 2 1 1 ((3><4) [1..])) ((2><3) [1..])
30+ , 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..])
31+ , 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..])
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
25− ]
38+ ]
26− ]
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.
13extra-source-files:
13extra-source-files:
14 cbits/im2col.h
14 cbits/im2col.h
15 cbits/im2col.c
15 cbits/im2col.c
16+ cbits/gradient_decent.h
17+ cbits/gradient_decent.c
18+ cbits/pad.h
19+ cbits/pad.c
16
20
17library
21library
18 build-depends:
22 build-depends:
19 base >= 4.8 && < 5
23 base >= 4.8 && < 5
20 , bytestring == 0.10.*
24 , bytestring == 0.10.*
21− , async
22 , containers
25 , containers
23 , deepseq
26 , deepseq
24 , either == 4.4.*
27 , either == 4.4.*
25 , cereal
28 , cereal
26 , exceptions == 0.8.*
29 , exceptions == 0.8.*
27− , hmatrix
30+ , hmatrix == 0.18.*
28 , MonadRandom
31 , MonadRandom
29 , mtl >= 2.2.1 && < 2.3
32 , mtl >= 2.2.1 && < 2.3
30− , parallel == 3.2.*
31 , primitive
33 , primitive
32− , reflection
33 , text == 1.2.*
34 , text == 1.2.*
34 , transformers
35 , transformers
35− , singletons
36+ , singletons >= 2.1 && < 2.3
36− , vector
37+ , vector == 0.11.*
37
38
38 ghc-options:
39 ghc-options:
39 -Wall
40 -Wall
@@ -43,22 +44,28 @@ library
43
44
44 exposed-modules:
45 exposed-modules:
45 Grenade
46 Grenade
47+ Grenade.Core
48+ Grenade.Core.Layer
49+ Grenade.Core.LearningParameters
46 Grenade.Core.Network
50 Grenade.Core.Network
47 Grenade.Core.Runner
51 Grenade.Core.Runner
48 Grenade.Core.Shape
52 Grenade.Core.Shape
49 Grenade.Layers.Crop
53 Grenade.Layers.Crop
54+ Grenade.Layers.Concat
50 Grenade.Layers.Convolution
55 Grenade.Layers.Convolution
51 Grenade.Layers.Dropout
56 Grenade.Layers.Dropout
52 Grenade.Layers.FullyConnected
57 Grenade.Layers.FullyConnected
53− Grenade.Layers.Flatten
58+ Grenade.Layers.Reshape
54− Grenade.Layers.Fuse
55 Grenade.Layers.Logit
59 Grenade.Layers.Logit
60+ Grenade.Layers.Merge
56 Grenade.Layers.Relu
61 Grenade.Layers.Relu
62+ Grenade.Layers.Elu
57 Grenade.Layers.Tanh
63 Grenade.Layers.Tanh
58 Grenade.Layers.Pad
64 Grenade.Layers.Pad
59 Grenade.Layers.Pooling
65 Grenade.Layers.Pooling
60
66
61 Grenade.Layers.Internal.Convolution
67 Grenade.Layers.Internal.Convolution
68+ Grenade.Layers.Internal.Pad
62 Grenade.Layers.Internal.Pooling
69 Grenade.Layers.Internal.Pooling
63 Grenade.Layers.Internal.Update
70 Grenade.Layers.Internal.Update
64
71
@@ -69,14 +76,15 @@ library
69
76
70 Grenade.Recurrent.Layers.BasicRecurrent
77 Grenade.Recurrent.Layers.BasicRecurrent
71 Grenade.Recurrent.Layers.LSTM
78 Grenade.Recurrent.Layers.LSTM
72− Grenade.Recurrent.Layers.Trivial
73
79
74 Grenade.Utils.OneHot
80 Grenade.Utils.OneHot
75
81
76 includes: cbits/im2col.h
82 includes: cbits/im2col.h
77 cbits/gradient_decent.h
83 cbits/gradient_decent.h
84+ cbits/pad.h
78 c-sources: cbits/im2col.c
85 c-sources: cbits/im2col.c
79 cbits/gradient_decent.c
86 cbits/gradient_decent.c
87+ cbits/pad.c
80
88
81 cc-options: -std=c99 -O3 -msse4.2 -Wall -Werror -DCABAL=1
89 cc-options: -std=c99 -O3 -msse4.2 -Wall -Werror -DCABAL=1
82
90
@@ -89,12 +97,13 @@ executable feedforward
89 , bytestring
97 , bytestring
90 , cereal
98 , cereal
91 , either
99 , either
92− , optparse-applicative == 0.12.*
100+ , optparse-applicative == 0.13.*
93 , text == 1.2.*
101 , text == 1.2.*
94 , mtl >= 2.2.1 && < 2.3
102 , mtl >= 2.2.1 && < 2.3
95 , hmatrix
103 , hmatrix
96 , transformers
104 , transformers
97 , singletons
105 , singletons
106+ , semigroups
98 , MonadRandom
107 , MonadRandom
99
108
100executable mnist
109executable mnist
@@ -104,11 +113,12 @@ executable mnist
104 , grenade
113 , grenade
105 , attoparsec
114 , attoparsec
106 , either
115 , either
107− , optparse-applicative == 0.12.*
116+ , optparse-applicative == 0.13.*
108 , text == 1.2.*
117 , text == 1.2.*
109 , mtl >= 2.2.1 && < 2.3
118 , mtl >= 2.2.1 && < 2.3
110 , hmatrix >= 0.18 && < 0.19
119 , hmatrix >= 0.18 && < 0.19
111 , transformers
120 , transformers
121+ , semigroups
112 , singletons
122 , singletons
113 , MonadRandom
123 , MonadRandom
114 , vector
124 , vector
@@ -120,11 +130,12 @@ executable recurrent
120 , grenade
130 , grenade
121 , attoparsec
131 , attoparsec
122 , either
132 , either
123− , optparse-applicative == 0.12.*
133+ , optparse-applicative == 0.13.*
124 , text == 1.2.*
134 , text == 1.2.*
125 , mtl >= 2.2.1 && < 2.3
135 , mtl >= 2.2.1 && < 2.3
126 , hmatrix >= 0.18 && < 0.19
136 , hmatrix >= 0.18 && < 0.19
127 , transformers
137 , transformers
138+ , semigroups
128 , singletons
139 , singletons
129 , MonadRandom
140 , MonadRandom
130
141
@@ -138,11 +149,12 @@ executable shakespeare
138 , bytestring
149 , bytestring
139 , cereal
150 , cereal
140 , either
151 , either
141− , optparse-applicative == 0.12.*
152+ , optparse-applicative == 0.13.*
142 , text == 1.2.*
153 , text == 1.2.*
143 , mtl >= 2.2.1 && < 2.3
154 , mtl >= 2.2.1 && < 2.3
144 , hmatrix >= 0.18 && < 0.19
155 , hmatrix >= 0.18 && < 0.19
145 , transformers
156 , transformers
157+ , semigroups
146 , singletons
158 , singletons
147 , vector
159 , vector
148 , MonadRandom
160 , MonadRandom
mafia+1−1
@@ -120,4 +120,4 @@ case "$MODE" in
120upgrade) shift; run_upgrade "$@" ;;
120upgrade) shift; run_upgrade "$@" ;;
121*) exec_mafia "$@"
121*) exec_mafia "$@"
122esac
122esac
123−# Version: 3044e63eb472fb9e16926d4ab2ca9dd9e255829c
123+# Version: 360716306a06db842ec022a7b9f161d2208483f0
main/feedforward.hs+1
@@ -10,6 +10,7 @@ import Data.List ( foldl' )
10
10
11import qualified Data.ByteString as B
11import qualified Data.ByteString as B
12import Data.Serialize
12import Data.Serialize
13+import Data.Semigroup ( (<>) )
13
14
14import GHC.TypeLits
15import GHC.TypeLits
15
16
main/mnist.hs+2−1
@@ -12,6 +12,7 @@ import Control.Monad.Trans.Except
12
12
13import qualified Data.Attoparsec.Text as A
13import qualified Data.Attoparsec.Text as A
14import Data.List ( foldl' )
14import Data.List ( foldl' )
15+import Data.Semigroup ( (<>) )
15import qualified Data.Text as T
16import qualified Data.Text as T
16import qualified Data.Text.IO as T
17import qualified Data.Text.IO as T
17import qualified Data.Vector.Storable as V
18import qualified Data.Vector.Storable as V
@@ -33,7 +34,7 @@ import Grenade.Utils.OneHot
33
34
34-- With the mnist data from Kaggle normalised to doubles between 0 and 1, learning rate of 0.01 and 15 iterations,
35-- With the mnist data from Kaggle normalised to doubles between 0 and 1, learning rate of 0.01 and 15 iterations,
35-- this network should get down to about a 1.3% error rate.
36-- 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]
37 '[ '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]
38 '[ '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]
38
39
39randomMnist :: MonadRandom m => m MNIST
40randomMnist :: MonadRandom m => m MNIST
main/recurrent.hs+12−5
@@ -1,4 +1,5 @@
1{-# LANGUAGE BangPatterns #-}
1{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE CPP #-}
2{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE TypeOperators #-}
@@ -8,7 +9,13 @@
8import Control.Monad ( foldM )
9import Control.Monad ( foldM )
9import Control.Monad.Random ( MonadRandom, getRandomR )
10import Control.Monad.Random ( MonadRandom, getRandomR )
10
11
12+#if __GLASGOW_HASKELL__ < 800
13+import Data.List ( unfoldr )
14+#else
11import Data.List ( cycle, unfoldr )
15import Data.List ( cycle, unfoldr )
16+#endif
17+import Data.Semigroup ( (<>) )
18+
12import qualified Numeric.LinearAlgebra.Static as SA
19import qualified Numeric.LinearAlgebra.Static as SA
13
20
14import Options.Applicative
21import Options.Applicative
@@ -16,19 +23,19 @@ import Options.Applicative
16import Grenade
23import Grenade
17import Grenade.Recurrent
24import Grenade.Recurrent
18
25
26+{-# OPTIONS_GHC -fno-redundant-imports #-}
19-- The defininition for our simple recurrent network.
27-- The defininition for our simple recurrent network.
20-- This file just trains a network to generate a repeating sequence
28-- This file just trains a network to generate a repeating sequence
21-- of 0 0 1.
29-- of 0 0 1.
22--
30--
23-- The F and R types are Tagging types to ensure that the runner and
31-- The F and R types are Tagging types to ensure that the runner and
24-- creation function know how to treat the layers.
32-- creation function know how to treat the layers.
25−type F = FeedForward
26type R = Recurrent
33type R = Recurrent
27
34
28−type RecNet = RecurrentNetwork '[ R (LSTM 1 4), R (LSTM 4 1), F Trivial]
35+type RecNet = RecurrentNetwork '[ R (LSTM 1 4), R (LSTM 4 1)]
29− '[ 'D1 1, 'D1 4, 'D1 1, 'D1 1 ]
36+ '[ 'D1 1, 'D1 4, 'D1 1 ]
30
37
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)]
32
39
33randomNet :: MonadRandom m => m (RecNet, RecInput)
40randomNet :: MonadRandom m => m (RecNet, RecInput)
34randomNet = randomRecurrent
41randomNet = randomRecurrent
@@ -51,7 +58,7 @@ netTest net0 i0 rate iterations =
51data FeedForwardOpts = FeedForwardOpts Int LearningParameters
58data FeedForwardOpts = FeedForwardOpts Int LearningParameters
52
59
53feedForward' :: Parser FeedForwardOpts
60feedForward' :: Parser FeedForwardOpts
54−feedForward' = FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 20000)
61+feedForward' = FeedForwardOpts <$> option auto (long "examples" <> short 'e' <> value 40000)
55 <*> (LearningParameters
62 <*> (LearningParameters
56 <$> option auto (long "train_rate" <> short 'r' <> value 0.01)
63 <$> option auto (long "train_rate" <> short 'r' <> value 0.01)
57 <*> option auto (long "momentum" <> value 0.9)
64 <*> option auto (long "momentum" <> value 0.9)
main/shakespeare.hs+1
@@ -13,6 +13,7 @@ import Control.Monad.Trans.Except
13import Data.Char ( isUpper, toUpper, toLower )
13import Data.Char ( isUpper, toUpper, toLower )
14import Data.List ( foldl' )
14import Data.List ( foldl' )
15import Data.Maybe ( fromMaybe )
15import Data.Maybe ( fromMaybe )
16+import Data.Semigroup ( (<>) )
16
17
17import qualified Data.Vector as V
18import qualified Data.Vector as V
18import Data.Vector ( Vector )
19import Data.Vector ( Vector )
src/Grenade.hs+10−5
@@ -2,17 +2,22 @@ module Grenade (
2 module X
2 module X
3 ) where
3 ) where
4
4
5+import Grenade.Core.LearningParameters as X
6+import Grenade.Core.Layer as X
5import Grenade.Core.Network as X
7import Grenade.Core.Network as X
6import Grenade.Core.Runner as X
8import Grenade.Core.Runner as X
7import Grenade.Core.Shape as X
9import Grenade.Core.Shape as X
10+import Grenade.Layers.Concat as X
8import Grenade.Layers.Crop as X
11import Grenade.Layers.Crop as X
9import Grenade.Layers.Dropout as X
12import Grenade.Layers.Dropout as X
10import Grenade.Layers.Pad as X
13import Grenade.Layers.Pad as X
11import Grenade.Layers.Pooling as X
14import Grenade.Layers.Pooling as X
12−import Grenade.Layers.Flatten as X
15+import Grenade.Layers.Reshape as X
13−import Grenade.Layers.Fuse as X
14import Grenade.Layers.FullyConnected as X
16import Grenade.Layers.FullyConnected as X
15import Grenade.Layers.Logit as X
17import Grenade.Layers.Logit as X
16−import Grenade.Layers.Convolution as X
18+import Grenade.Layers.Merge as X
19+import Grenade.Layers.Convolution as X
17−import Grenade.Layers.Relu as X
20+import Grenade.Layers.Relu as X
21+import Grenade.Layers.Elu as X
18−import Grenade.Layers.Tanh 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 #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE GADTs #-}
4{-# LANGUAGE GADTs #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE TypeOperators #-}
6{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE TypeFamilies #-}
7{-# LANGUAGE TypeFamilies #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
@@ -12,63 +15,36 @@ Copyright : (c) Huw Campbell, 2016-2017
12License : BSD2
15License : BSD2
13Stability : experimental
16Stability : experimental
14
17
15−This module defines the core data type for the simplest
18+This module defines the core data types and functions
16−Neural network we support.
19+for non-recurrent neural networks.
17−
18-}
20-}
21+
22+#if __GLASGOW_HASKELL__ < 800
23+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
24+#endif
25+
19module Grenade.Core.Network (
26module Grenade.Core.Network (
20− Layer (..)
21− , Network (..)
27+ Network (..)
22− , UpdateLayer (..)
23− , LearningParameters (..)
24 , Gradients (..)
28 , Gradients (..)
25− , CreatableNetwork (..)
29+ , Tapes (..)
30+
31+ , runNetwork
32+ , runGradient
33+ , applyUpdate
34+
35+ , randomNetwork
26 ) where
36 ) where
27
37
28−import Control.Monad.Random (MonadRandom)
38+import Control.Monad.Random ( MonadRandom )
29−import Data.List ( foldl' )
30−import Data.Singletons
31
39
40+import Data.Singletons
41+import Data.Singletons.Prelude
32import Data.Serialize
42import Data.Serialize
33
43
44+import Grenade.Core.Layer
45+import Grenade.Core.LearningParameters
34import Grenade.Core.Shape
46import Grenade.Core.Shape
35
47
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−
72-- | Type of a network.
48-- | Type of a network.
73--
49--
74-- The [*] type specifies the types of the layers.
50-- The [*] type specifies the types of the layers.
@@ -78,39 +54,144 @@ class UpdateLayer x => Layer x (i :: Shape) (o :: Shape) where
78-- Can be considered to be a heterogeneous list of layers which are able to
54-- Can be considered to be a heterogeneous list of layers which are able to
79-- transform the data shapes of the network.
55-- transform the data shapes of the network.
80data Network :: [*] -> [Shape] -> * where
56data Network :: [*] -> [Shape] -> * where
57+ NNil :: SingI i
81− O :: (SingI i, SingI o, Layer x i o) => !x -> Network '[x] '[i, o]
58+ => Network '[] '[i]
59+
82− (:~>) :: (SingI i, SingI h, Layer x i h) => !x -> !(Network xs (h ': hs)) -> Network (x ': xs) (i ': h ': hs)
60+ (:~>) :: (SingI i, SingI h, Layer x i h)
61+ => !x
62+ -> !(Network xs (h ': hs))
63+ -> Network (x ': xs) (i ': h ': hs)
83infixr 5 :~>
64infixr 5 :~>
84
65
85−instance Show (Network l h) where
66+instance Show (Network '[] '[i]) where
86− show (O a) = "O " ++ show a
67+ show NNil = "NNil"
68+instance (Show x, Show (Network xs rs)) => Show (Network (x ': xs) (i ': rs)) where
87− show (i :~> o) = show i ++ "\n:~>\n" ++ show o
69+ show (x :~> xs) = show x ++ "\n~>\n" ++ show xs
88
70
89−-- | Gradients of a network.
71+-- | Gradient of a network.
72+--
90−-- Parameterised on the layers of a Network.
73+-- Parameterised on the layers of the network.
91data Gradients :: [*] -> * where
74data Gradients :: [*] -> * where
92− OG :: UpdateLayer x => Gradient x -> Gradients '[x]
75+ GNil :: Gradients '[]
76+
93− (:/>) :: UpdateLayer x => Gradient x -> Gradients xs -> Gradients (x ': xs)
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+
94
94
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+
95−-- | A network can easily be created by hand with (:~>), but an easy way to initialise a random
161+-- | A network can easily be created by hand with (:~>), but an easy way to
96−-- network is with the randomNetwork.
162+-- initialise a random network is with the randomNetwork.
97class CreatableNetwork (xs :: [*]) (ss :: [Shape]) where
163class 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.
99 randomNetwork :: MonadRandom m => m (Network xs ss)
168 randomNetwork :: MonadRandom m => m (Network xs ss)
100
169
101−instance (SingI i, SingI o, Layer x i o) => CreatableNetwork (x ': '[]) (i ': o ': '[]) where
170+instance SingI i => CreatableNetwork '[] '[i] where
102− randomNetwork = O <$> createRandom
171+ randomNetwork = return NNil
103
172
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
105 randomNetwork = (:~>) <$> createRandom <*> randomNetwork
174 randomNetwork = (:~>) <$> createRandom <*> randomNetwork
106
175
107−
108-- | Add very simple serialisation to the network
176-- | 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
177+instance SingI i => Serialize (Network '[] '[i]) where
110− put (O x) = put x
178+ put NNil = pure ()
111− put _ = error "impossible"
179+ get = return NNil
112− get = O <$> get
113
180
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
115 put (x :~> r) = put x >> put r
182 put (x :~> r) = put x >> put r
116 get = (:~>) <$> get <*> get
183 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 #-}
3{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
4−{-# LANGUAGE ScopedTypeVariables #-}
2+{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE TypeOperators #-}
6−{-# LANGUAGE TypeFamilies #-}
7{-|
3{-|
8Module : Grenade.Core.Shape
4Module : Grenade.Core.Shape
9Description : Core definition of the Shapes of data we understand
5Description : Core definition of the Shapes of data we understand
@@ -18,10 +14,11 @@ module Grenade.Core.Runner (
18 train
14 train
19 , backPropagate
15 , backPropagate
20 , runNet
16 , runNet
21− , applyUpdate
22 ) where
17 ) where
23
18
24import Data.Singletons.Prelude
19import Data.Singletons.Prelude
20+
21+import Grenade.Core.LearningParameters
25import Grenade.Core.Network
22import Grenade.Core.Network
26import Grenade.Core.Shape
23import Grenade.Core.Shape
27
24
@@ -30,51 +27,32 @@ import Grenade.Core.Shape
30--
27--
31-- /Note:/ The loss function pushed backwards is appropriate
28-- /Note:/ The loss function pushed backwards is appropriate
32-- for both regression and classification as a squared loss
29-- for both regression and classification as a squared loss
33−-- or log-loss respectively. Other loss functions are not yet
30+-- or log-loss respectively.
34−-- implemented.
31+--
32+-- For other loss functions, use runNetwork and runGradient
33+-- with the back propagated gradient of your loss.
34+--
35−backPropagate :: forall shapes layers.
35+backPropagate :: SingI (Last shapes)
36− Network layers shapes -> S (Head shapes) -> S (Last shapes) -> Gradients layers
36+ => Network layers shapes
37+ -> S (Head shapes)
38+ -> S (Last shapes)
39+ -> Gradients layers
37backPropagate network input target =
40backPropagate network input target =
38− fst $ go input network
41+ let (tapes, output) = runNetwork network input
39− where
42+ (grads, _) = runGradient network tapes (output - target)
40− go :: forall js sublayers. (Last js ~ Last shapes)
43+ in grads
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"
70
44
71-- | Update a network with new weights after training with an instance.
45-- | 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
73train rate network input output =
52train rate network input output =
74 let grads = backPropagate network input output
53 let grads = backPropagate network input output
75 in applyUpdate rate network grads
54 in applyUpdate rate network grads
76
55
77-- | Run the network with input and return the given output.
56-- | Run the network with input and return the given output.
78runNet :: Network layers shapes -> S (Head shapes) -> S (Last shapes)
57runNet :: Network layers shapes -> S (Head shapes) -> S (Last shapes)
79−runNet (layer :~> n) !x = let y = runForwards layer x in runNet n y
58+runNet net = snd . runNetwork net
80−runNet (O layer) !x = runForwards layer x
src/Grenade/Core/Shape.hs+31−10
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE GADTs #-}
3{-# LANGUAGE GADTs #-}
3{-# LANGUAGE KindSignatures #-}
4{-# LANGUAGE KindSignatures #-}
@@ -8,10 +9,10 @@
8{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE RankNTypes #-}
10{-# LANGUAGE RankNTypes #-}
10
11
11−-- Ghc 8.0 gives a warning on `n2 _ _ = error ...` but ghc 7.10 fails to
12+-- Ghc 7.10 fails to recognise n2 is complete.
12−-- compile without this default pattern.
13+#if __GLASGOW_HASKELL__ < 800
13−{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}
14+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
14−
15+#endif
15{-|
16{-|
16Module : Grenade.Core.Shape
17Module : Grenade.Core.Shape
17Description : Core definition of the Shapes of data we understand
18Description : Core definition of the Shapes of data we understand
@@ -25,6 +26,8 @@ are understood by Grenade.
25module Grenade.Core.Shape (
26module Grenade.Core.Shape (
26 Shape (..)
27 Shape (..)
27 , S (..)
28 , S (..)
29+ , Sing (..)
30+
28 , randomOfShape
31 , randomOfShape
29 , fromStorable
32 , fromStorable
30 ) where
33 ) where
@@ -47,27 +50,46 @@ import qualified Numeric.LinearAlgebra as NLA
47-- | The current shapes we accept.
50-- | The current shapes we accept.
48-- at the moment this is just one, two, and three dimensional
51-- at the moment this is just one, two, and three dimensional
49-- Vectors/Matricies.
52-- Vectors/Matricies.
53+--
54+-- These are only used with DataKinds, as Kind `Shape`, with Types 'D1, 'D2, 'D3.
50data Shape
55data Shape
51 = D1 Nat
56 = D1 Nat
57+ -- ^ One dimensional vector
52 | D2 Nat Nat
58 | D2 Nat Nat
59+ -- ^ Two dimensional matrix. Row, Column.
53 | D3 Nat Nat Nat
60 | D3 Nat Nat Nat
61+ -- ^ Three dimensional matrix. Row, Column, Channels.
54
62
55−-- | Given a Shape n, these are the possible data structures with that shape.
63+-- | Concrete data structures for a Shape.
64+--
56-- All shapes are held in contiguous memory.
65-- All shapes are held in contiguous memory.
57-- 3D is held in a matrix (usually row oriented) which has height depth * rows.
66-- 3D is held in a matrix (usually row oriented) which has height depth * rows.
58data S (n :: Shape) where
67data S (n :: Shape) where
68+ -- | One dimensional data
59− S1D :: ( KnownNat o ) => R o -> S ('D1 o)
69+ S1D :: ( KnownNat len )
70+ => R len
71+ -> S ('D1 len)
72+
73+ -- | Two dimensional data
60− S2D :: ( KnownNat rows, KnownNat columns ) => L rows columns -> S ('D2 rows columns)
74+ S2D :: ( KnownNat rows, KnownNat columns )
75+ => L rows columns
76+ -> S ('D2 rows columns)
77+
78+ -- | Three dimensional data
61 S3D :: ( KnownNat rows
79 S3D :: ( KnownNat rows
62 , KnownNat columns
80 , KnownNat columns
63 , KnownNat depth
81 , KnownNat depth
82+ , KnownNat (rows * depth))
83+ => L (rows * depth) columns
64− , KnownNat (rows * depth)) => L (rows * depth) columns -> S ('D3 rows columns depth)
84+ -> S ('D3 rows columns depth)
65
85
66deriving instance Show (S n)
86deriving instance Show (S n)
67
87
68−-- Singletons
88+-- Singleton instances.
89+--
69-- These could probably be derived with template haskell, but this seems
90-- These could probably be derived with template haskell, but this seems
70-- clear and makes adding the KnownNat constraints simple.
91-- clear and makes adding the KnownNat constraints simple.
92+-- We can also keep our code TH free, which is great.
71data instance Sing (n :: Shape) where
93data instance Sing (n :: Shape) where
72 D1Sing :: KnownNat a => Sing ('D1 a)
94 D1Sing :: KnownNat a => Sing ('D1 a)
73 D2Sing :: (KnownNat a, KnownNat b) => Sing ('D2 a b)
95 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
160n2 f (S1D x) (S1D y) = S1D (f x y)
182n2 f (S1D x) (S1D y) = S1D (f x y)
161n2 f (S2D x) (S2D y) = S2D (f x y)
183n2 f (S2D x) (S2D y) = S2D (f x y)
162n2 f (S3D x) (S3D y) = S3D (f x y)
184n2 f (S3D x) (S3D y) = S3D (f x y)
163−n2 _ _ _ = error "Impossible to have different constructors for the same shaped network"
164
185
165-- Helper function for creating the number instances
186-- Helper function for creating the number instances
166nk :: forall x. SingI x => Double -> S x
187nk :: 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 )
25import qualified Numeric.LinearAlgebra as LA
25import qualified Numeric.LinearAlgebra as LA
26import Numeric.LinearAlgebra.Static hiding ((|||), build, toRows)
26import Numeric.LinearAlgebra.Static hiding ((|||), build, toRows)
27
27
28−import Grenade.Core.Network
28+import Grenade.Core
29−import Grenade.Core.Shape
30import Grenade.Layers.Internal.Convolution
29import Grenade.Layers.Internal.Convolution
31import Grenade.Layers.Internal.Update
30import Grenade.Layers.Internal.Update
32
31
@@ -157,6 +156,7 @@ instance ( KnownNat kernelRows
157 , KnownNat (kernelRows * kernelCols * 1)
156 , KnownNat (kernelRows * kernelCols * 1)
158 , KnownNat (outputRows * filters)
157 , KnownNat (outputRows * filters)
159 ) => Layer (Convolution 1 filters kernelRows kernelCols strideRows strideCols) ('D2 inputRows inputCols) ('D3 outputRows outputCols filters) where
158 ) => 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)
160 runForwards (Convolution kernel _) (S2D input) =
160 runForwards (Convolution kernel _) (S2D input) =
161 let ex = extract input
161 let ex = extract input
162 ek = extract kernel
162 ek = extract kernel
@@ -170,7 +170,7 @@ instance ( KnownNat kernelRows
170 mt = c LA.<> ek
170 mt = c LA.<> ek
171 r = col2vid 1 1 1 1 ox oy mt
171 r = col2vid 1 1 1 1 ox oy mt
172 rs = fromJust . create $ r
172 rs = fromJust . create $ r
173− in S3D rs
173+ in (S2D input, S3D rs)
174
174
175 runBackwards (Convolution kernel _) (S2D input) (S3D dEdy) =
175 runBackwards (Convolution kernel _) (S2D input) (S3D dEdy) =
176 let ex = extract input
176 let ex = extract input
@@ -214,6 +214,9 @@ instance ( KnownNat kernelRows
214 , KnownNat (kernelRows * kernelCols * channels)
214 , KnownNat (kernelRows * kernelCols * channels)
215 , KnownNat (outputRows * filters)
215 , KnownNat (outputRows * filters)
216 ) => Layer (Convolution channels filters kernelRows kernelCols strideRows strideCols) ('D3 inputRows inputCols channels) ('D3 outputRows outputCols filters) where
216 ) => 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+
217 runForwards (Convolution kernel _) (S3D input) =
220 runForwards (Convolution kernel _) (S3D input) =
218 let ex = extract input
221 let ex = extract input
219 ek = extract kernel
222 ek = extract kernel
@@ -230,7 +233,7 @@ instance ( KnownNat kernelRows
230 mt = c LA.<> ek
233 mt = c LA.<> ek
231 r = col2vid 1 1 1 1 ox oy mt
234 r = col2vid 1 1 1 1 ox oy mt
232 rs = fromJust . create $ r
235 rs = fromJust . create $ r
233− in S3D rs
236+ in (S3D input, S3D rs)
234 runBackwards (Convolution kernel _) (S3D input) (S3D dEdy) =
237 runBackwards (Convolution kernel _) (S3D input) (S3D dEdy) =
235 let ex = extract input
238 let ex = extract input
236 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
239 ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
src/Grenade/Layers/Crop.hs+50−3
@@ -3,6 +3,7 @@
3{-# LANGUAGE GADTs #-}
3{-# LANGUAGE GADTs #-}
4{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE TypeFamilies #-}
5{-# LANGUAGE TypeFamilies #-}
6+{-# LANGUAGE FlexibleContexts #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
7module Grenade.Layers.Crop (
8module Grenade.Layers.Crop (
8 Crop (..)
9 Crop (..)
@@ -13,8 +14,8 @@ import Data.Proxy
13import Data.Singletons.TypeLits
14import Data.Singletons.TypeLits
14import GHC.TypeLits
15import GHC.TypeLits
15
16
16−import Grenade.Core.Network
17+import Grenade.Core
17−import Grenade.Core.Shape
18+import Grenade.Layers.Internal.Pad
18
19
19import Numeric.LinearAlgebra (konst, subMatrix, diagBlock)
20import Numeric.LinearAlgebra (konst, subMatrix, diagBlock)
20import Numeric.LinearAlgebra.Static (extract, create)
21import Numeric.LinearAlgebra.Static (extract, create)
@@ -46,6 +47,7 @@ instance ( KnownNat cropLeft
46 , (inputRows - cropTop - cropBottom) ~ outputRows
47 , (inputRows - cropTop - cropBottom) ~ outputRows
47 , (inputColumns - cropLeft - cropRight) ~ outputColumns
48 , (inputColumns - cropLeft - cropRight) ~ outputColumns
48 ) => Layer (Crop cropLeft cropTop cropRight cropBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
49 ) => 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) = ()
49 runForwards Crop (S2D input) =
51 runForwards Crop (S2D input) =
50 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
52 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
51 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
53 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
@@ -53,7 +55,7 @@ instance ( KnownNat cropLeft
53 ncols = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
55 ncols = fromIntegral $ natVal (Proxy :: Proxy outputColumns)
54 m = extract input
56 m = extract input
55 r = subMatrix (cropt, cropl) (nrows, ncols) m
57 r = subMatrix (cropt, cropl) (nrows, ncols) m
56− in S2D . fromJust . create $ r
58+ in ((), S2D . fromJust . create $ r)
57 runBackwards _ _ (S2D dEdy) =
59 runBackwards _ _ (S2D dEdy) =
58 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
60 let cropl = fromIntegral $ natVal (Proxy :: Proxy cropLeft)
59 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
61 cropt = fromIntegral $ natVal (Proxy :: Proxy cropTop)
@@ -62,3 +64,48 @@ instance ( KnownNat cropLeft
62 eo = extract dEdy
64 eo = extract dEdy
63 vs = diagBlock [konst 0 (cropt,cropl), eo, konst 0 (cropb,cropr)]
65 vs = diagBlock [konst 0 (cropt,cropl), eo, konst 0 (cropb,cropr)]
64 in ((), S2D . fromJust . create $ vs)
66 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 (
10import Control.Monad.Random hiding (fromList)
10import Control.Monad.Random hiding (fromList)
11
11
12import GHC.TypeLits
12import GHC.TypeLits
13−import Grenade.Core.Shape
13+import Grenade.Core
14−import Grenade.Core.Network
15−
16−import Numeric.LinearAlgebra.Static
17−
18
14
19-- Dropout layer help to reduce overfitting.
15-- Dropout layer help to reduce overfitting.
20-- Idea here is that the vector is a shape of 1s and 0s, which we multiply the input by.
16-- Idea here is that the vector is a shape of 1s and 0s, which we multiply the input by.
21-- After backpropogation, we return a new matrix/vector, with different bits dropped out.
17-- After backpropogation, we return a new matrix/vector, with different bits dropped out.
22-- Double is the proportion to drop in each training iteration (like 1% or 5% would be
18-- Double is the proportion to drop in each training iteration (like 1% or 5% would be
23-- reasonable).
19-- reasonable).
24−data Dropout o =
20+data Dropout = Dropout {
25− Dropout (R o)
26− | Pass Double
21+ dropoutRate :: Double
22+ , dropoutSeed :: Int
27− deriving Show
23+ } deriving Show
28
24
29−instance (KnownNat i) => UpdateLayer (Dropout i) where
25+instance UpdateLayer Dropout where
30− type Gradient (Dropout i) = ()
26+ type Gradient Dropout = ()
31 runUpdate _ x _ = x
27 runUpdate _ x _ = x
32 createRandom = randomDropout 0.95
28 createRandom = randomDropout 0.95
33
29
34−randomDropout :: (MonadRandom m, KnownNat i)
30+randomDropout :: MonadRandom m
35− => Double -> m (Dropout i)
31+ => Double -> m Dropout
36−randomDropout rate = do
32+randomDropout rate = Dropout rate <$> getRandom
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
41
33
42−instance (KnownNat i) => Layer (Dropout i) ('D1 i) ('D1 i) where
34+instance (KnownNat i) => Layer Dropout ('D1 i) ('D1 i) where
43− runForwards (Dropout drops) (S1D x) = S1D $ x * drops
35+ type Tape Dropout ('D1 i) ('D1 i) = ()
44− runForwards (Pass rate) (S1D x)= S1D $ dvmap (* (1 - rate)) x
36+ runForwards (Dropout _ _) (S1D x) = ((), S1D x)
45− runBackwards (Dropout drops) _ (S1D x) = ((), S1D $ x * drops)
46− runBackwards (Pass rate) _ (S1D x) = ((), S1D $ dvmap (* (1 - rate)) 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 @@
6{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE ScopedTypeVariables #-}
7module Grenade.Layers.FullyConnected (
7module Grenade.Layers.FullyConnected (
8 FullyConnected (..)
8 FullyConnected (..)
9+ , FullyConnected' (..)
9 , randomFullyConnected
10 , randomFullyConnected
10 ) where
11 ) where
11
12
@@ -18,21 +19,18 @@ import Data.Singletons.TypeLits
18import qualified Numeric.LinearAlgebra as LA
19import qualified Numeric.LinearAlgebra as LA
19import Numeric.LinearAlgebra.Static
20import Numeric.LinearAlgebra.Static
20
21
21−import Grenade.Core.Network
22+import Grenade.Core
22−import Grenade.Core.Shape
23
23
24import Grenade.Layers.Internal.Update
24import Grenade.Layers.Internal.Update
25
25
26-- | A basic fully connected (or inner product) neural network layer.
26-- | A basic fully connected (or inner product) neural network layer.
27data FullyConnected i o = FullyConnected
27data FullyConnected i o = FullyConnected
28− !(R o) -- Bias neuron weights
28+ !(FullyConnected' i o) -- Neuron weights
29− !(R o) -- Bias neuron momentum
29+ !(FullyConnected' i o) -- Neuron momentum
30− !(L o i) -- Activation weights
31− !(L o i) -- Momentum
32
30
33data FullyConnected' i o = FullyConnected'
31data FullyConnected' i o = FullyConnected'
34− !(R o) -- Bias neuron gradient
32+ !(R o) -- Bias
35− !(L o i) -- Activation gradient
33+ !(L o i) -- Activations
36
34
37instance Show (FullyConnected i o) where
35instance Show (FullyConnected i o) where
38 show FullyConnected {} = "FullyConnected"
36 show FullyConnected {} = "FullyConnected"
@@ -40,19 +38,20 @@ instance Show (FullyConnected i o) where
40instance (KnownNat i, KnownNat o) => UpdateLayer (FullyConnected i o) where
38instance (KnownNat i, KnownNat o) => UpdateLayer (FullyConnected i o) where
41 type Gradient (FullyConnected i o) = (FullyConnected' i o)
39 type Gradient (FullyConnected i o) = (FullyConnected' i o)
42
40
43− runUpdate LearningParameters {..} (FullyConnected oldBias oldBiasMomentum oldActivations oldMomentum) (FullyConnected' biasGradient activationGradient) =
41+ runUpdate LearningParameters {..} (FullyConnected (FullyConnected' oldBias oldActivations) (FullyConnected' oldBiasMomentum oldMomentum)) (FullyConnected' biasGradient activationGradient) =
44 let (newBias, newBiasMomentum) = decendVector learningRate learningMomentum learningRegulariser oldBias biasGradient oldBiasMomentum
42 let (newBias, newBiasMomentum) = decendVector learningRate learningMomentum learningRegulariser oldBias biasGradient oldBiasMomentum
45 (newActivations, newMomentum) = decendMatrix learningRate learningMomentum learningRegulariser oldActivations activationGradient oldMomentum
43 (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)
47
45
48 createRandom = randomFullyConnected
46 createRandom = randomFullyConnected
49
47
50instance (KnownNat i, KnownNat o) => Layer (FullyConnected i o) ('D1 i) ('D1 o) where
48instance (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)
51 -- Do a matrix vector multiplication and return the result.
50 -- 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))
53
52
54 -- Run a backpropogation step for a full connected layer.
53 -- 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) =
56 let wB' = dEdy
55 let wB' = dEdy
57 mm' = dEdy `outer` x
56 mm' = dEdy `outer` x
58 -- calcluate derivatives for next step
57 -- calcluate derivatives for next step
@@ -60,7 +59,7 @@ instance (KnownNat i, KnownNat o) => Layer (FullyConnected i o) ('D1 i) ('D1 o)
60 in (FullyConnected' wB' mm', S1D dWs)
59 in (FullyConnected' wB' mm', S1D dWs)
61
60
62instance (KnownNat i, KnownNat o) => Serialize (FullyConnected i o) where
61instance (KnownNat i, KnownNat o) => Serialize (FullyConnected i o) where
63− put (FullyConnected b _ w _) = do
62+ put (FullyConnected (FullyConnected' b w) _) = do
64 putListOf put . LA.toList . extract $ b
63 putListOf put . LA.toList . extract $ b
65 putListOf put . LA.toList . LA.flatten . extract $ w
64 putListOf put . LA.toList . LA.flatten . extract $ w
66
65
@@ -70,7 +69,7 @@ instance (KnownNat i, KnownNat o) => Serialize (FullyConnected i o) where
70 k <- maybe (fail "Vector of incorrect size") return . create . LA.reshape f . LA.fromList =<< getListOf get
69 k <- maybe (fail "Vector of incorrect size") return . create . LA.reshape f . LA.fromList =<< getListOf get
71 let bm = konst 0
70 let bm = konst 0
72 let mm = konst 0
71 let mm = konst 0
73− return $ FullyConnected b bm k mm
72+ return $ FullyConnected (FullyConnected' b k) (FullyConnected' bm mm)
74
73
75randomFullyConnected :: (MonadRandom m, KnownNat i, KnownNat o)
74randomFullyConnected :: (MonadRandom m, KnownNat i, KnownNat o)
76 => m (FullyConnected i o)
75 => m (FullyConnected i o)
@@ -81,4 +80,4 @@ randomFullyConnected = do
81 wN = uniformSample s2 (-1) 1
80 wN = uniformSample s2 (-1) 1
82 bm = konst 0
81 bm = konst 0
83 mm = konst 0
82 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 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE TypeOperators #-}
2{-# LANGUAGE TypeOperators #-}
3{-# LANGUAGE TypeFamilies #-}
3{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
5module Grenade.Layers.Logit (
6module Grenade.Layers.Logit (
6 Logit (..)
7 Logit (..)
@@ -8,10 +9,9 @@ module Grenade.Layers.Logit (
8
9
9
10
10import Data.Serialize
11import Data.Serialize
12+import Data.Singletons
11
13
12−import Data.Singletons.TypeLits
13−import Grenade.Core.Network
14−import Grenade.Core.Shape
14+import Grenade.Core
15
15
16-- | A Logit layer.
16-- | A Logit layer.
17-- A layer which can act between any shape of the same dimension, perfoming an sigmoid function.
17-- A layer which can act between any shape of the same dimension, perfoming an sigmoid function.
@@ -25,17 +25,10 @@ instance UpdateLayer Logit where
25 runUpdate _ _ _ = Logit
25 runUpdate _ _ _ = Logit
26 createRandom = return Logit
26 createRandom = return Logit
27
27
28−instance (KnownNat i) => Layer Logit ('D1 i) ('D1 i) where
28+instance (a ~ b, SingI a) => Layer Logit a b where
29− runForwards _ (S1D y) = S1D (logistic y)
29+ type Tape Logit a b = S a
30− runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (logistic' y * dEdy))
30+ runForwards _ a = (a, logistic a)
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))
31+ runBackwards _ a g = ((), logistic' a * g)
39
32
40instance Serialize Logit where
33instance Serialize Logit where
41 put _ = return ()
34 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 @@
4{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE TypeFamilies #-}
5{-# LANGUAGE TypeFamilies #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE FlexibleContexts #-}
7module Grenade.Layers.Pad (
8module Grenade.Layers.Pad (
8 Pad (..)
9 Pad (..)
9 ) where
10 ) where
@@ -14,8 +15,8 @@ import Data.Serialize
14import Data.Singletons.TypeLits
15import Data.Singletons.TypeLits
15import GHC.TypeLits
16import GHC.TypeLits
16
17
17−import Grenade.Core.Network
18+import Grenade.Core
18−import Grenade.Core.Shape
19+import Grenade.Layers.Internal.Pad
19
20
20import Numeric.LinearAlgebra (konst, subMatrix, diagBlock)
21import Numeric.LinearAlgebra (konst, subMatrix, diagBlock)
21import Numeric.LinearAlgebra.Static (extract, create)
22import Numeric.LinearAlgebra.Static (extract, create)
@@ -51,6 +52,7 @@ instance ( KnownNat padLeft
51 , (inputRows + padTop + padBottom) ~ outputRows
52 , (inputRows + padTop + padBottom) ~ outputRows
52 , (inputColumns + padLeft + padRight) ~ outputColumns
53 , (inputColumns + padLeft + padRight) ~ outputColumns
53 ) => Layer (Pad padLeft padTop padRight padBottom) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
54 ) => 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) = ()
54 runForwards Pad (S2D input) =
56 runForwards Pad (S2D input) =
55 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
57 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
56 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
58 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
@@ -58,7 +60,7 @@ instance ( KnownNat padLeft
58 padb = fromIntegral $ natVal (Proxy :: Proxy padBottom)
60 padb = fromIntegral $ natVal (Proxy :: Proxy padBottom)
59 m = extract input
61 m = extract input
60 r = diagBlock [konst 0 (padt,padl), m, konst 0 (padb,padr)]
62 r = diagBlock [konst 0 (padt,padl), m, konst 0 (padb,padr)]
61− in S2D . fromJust . create $ r
63+ in ((), S2D . fromJust . create $ r)
62 runBackwards Pad _ (S2D dEdy) =
64 runBackwards Pad _ (S2D dEdy) =
63 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
65 let padl = fromIntegral $ natVal (Proxy :: Proxy padLeft)
64 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
66 padt = fromIntegral $ natVal (Proxy :: Proxy padTop)
@@ -67,3 +69,47 @@ instance ( KnownNat padLeft
67 m = extract dEdy
69 m = extract dEdy
68 vs = subMatrix (padt, padl) (nrows, ncols) m
70 vs = subMatrix (padt, padl) (nrows, ncols) m
69 in ((), S2D . fromJust . create $ vs)
71 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
16import Data.Singletons.TypeLits
16import Data.Singletons.TypeLits
17import GHC.TypeLits
17import GHC.TypeLits
18
18
19−import Grenade.Core.Network
19+import Grenade.Core
20−import Grenade.Core.Shape
21import Grenade.Layers.Internal.Pooling
20import Grenade.Layers.Internal.Pooling
22
21
23import Numeric.LinearAlgebra.Static as LAS hiding ((|||), build, toRows)
22import Numeric.LinearAlgebra.Static as LAS hiding ((|||), build, toRows)
@@ -56,6 +55,7 @@ instance ( KnownNat kernelRows
56 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
55 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
57 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
56 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
58 ) => Layer (Pooling kernelRows kernelColumns strideRows strideColumns) ('D2 inputRows inputColumns) ('D2 outputRows outputColumns) where
57 ) => 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)
59 runForwards Pooling (S2D input) =
59 runForwards Pooling (S2D input) =
60 let height = fromIntegral $ natVal (Proxy :: Proxy inputRows)
60 let height = fromIntegral $ natVal (Proxy :: Proxy inputRows)
61 width = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
61 width = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -66,7 +66,7 @@ instance ( KnownNat kernelRows
66 ex = extract input
66 ex = extract input
67 r = poolForward 1 height width kx ky sx sy ex
67 r = poolForward 1 height width kx ky sx sy ex
68 rs = fromJust . create $ r
68 rs = fromJust . create $ r
69− in S2D $ rs
69+ in (S2D input, S2D rs)
70 runBackwards Pooling (S2D input) (S2D dEdy) =
70 runBackwards Pooling (S2D input) (S2D dEdy) =
71 let height = fromIntegral $ natVal (Proxy :: Proxy inputRows)
71 let height = fromIntegral $ natVal (Proxy :: Proxy inputRows)
72 width = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
72 width = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -94,6 +94,7 @@ instance ( KnownNat kernelRows
94 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
94 , ((outputRows - 1) * strideRows) ~ (inputRows - kernelRows)
95 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
95 , ((outputColumns - 1) * strideColumns) ~ (inputColumns - kernelColumns)
96 ) => Layer (Pooling kernelRows kernelColumns strideRows strideColumns) ('D3 inputRows inputColumns channels) ('D3 outputRows outputColumns channels) where
96 ) => 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)
97 runForwards Pooling (S3D input) =
98 runForwards Pooling (S3D input) =
98 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
99 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
99 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
100 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
@@ -105,7 +106,7 @@ instance ( KnownNat kernelRows
105 ex = extract input
106 ex = extract input
106 r = poolForward ch ix iy kx ky sx sy ex
107 r = poolForward ch ix iy kx ky sx sy ex
107 rs = fromJust . create $ r
108 rs = fromJust . create $ r
108− in S3D rs
109+ in (S3D input, S3D rs)
109 runBackwards Pooling (S3D input) (S3D dEdy) =
110 runBackwards Pooling (S3D input) (S3D dEdy) =
110 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
111 let ix = fromIntegral $ natVal (Proxy :: Proxy inputRows)
111 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
112 iy = fromIntegral $ natVal (Proxy :: Proxy inputColumns)
src/Grenade/Layers/Relu.hs+11−5
@@ -9,8 +9,7 @@ module Grenade.Layers.Relu (
9import Data.Serialize
9import Data.Serialize
10
10
11import GHC.TypeLits
11import GHC.TypeLits
12−import Grenade.Core.Network
12+import Grenade.Core
13−import Grenade.Core.Shape
14
13
15import qualified Numeric.LinearAlgebra.Static as LAS
14import qualified Numeric.LinearAlgebra.Static as LAS
16
15
@@ -30,7 +29,9 @@ instance Serialize Relu where
30 get = return Relu
29 get = return Relu
31
30
32instance ( KnownNat i) => Layer Relu ('D1 i) ('D1 i) where
31instance ( KnownNat i) => Layer Relu ('D1 i) ('D1 i) where
32+ type Tape Relu ('D1 i) ('D1 i) = S ('D1 i)
33+
33− runForwards _ (S1D y) = S1D (relu y)
34+ runForwards _ (S1D y) = (S1D y, S1D (relu y))
34 where
35 where
35 relu = LAS.dvmap (\a -> if a <= 0 then 0 else a)
36 relu = LAS.dvmap (\a -> if a <= 0 then 0 else a)
36 runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (relu' y * dEdy))
37 runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (relu' y * dEdy))
@@ -38,7 +39,9 @@ instance ( KnownNat i) => Layer Relu ('D1 i) ('D1 i) where
38 relu' = LAS.dvmap (\a -> if a <= 0 then 0 else 1)
39 relu' = LAS.dvmap (\a -> if a <= 0 then 0 else 1)
39
40
40instance (KnownNat i, KnownNat j) => Layer Relu ('D2 i j) ('D2 i j) where
41instance (KnownNat i, KnownNat j) => Layer Relu ('D2 i j) ('D2 i j) where
42+ type Tape Relu ('D2 i j) ('D2 i j) = S ('D2 i j)
43+
41− runForwards _ (S2D y) = S2D (relu y)
44+ runForwards _ (S2D y) = (S2D y, S2D (relu y))
42 where
45 where
43 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
46 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
44 runBackwards _ (S2D y) (S2D dEdy) = ((), S2D (relu' y * dEdy))
47 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
46 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
49 relu' = LAS.dmmap (\a -> if a <= 0 then 0 else 1)
47
50
48instance (KnownNat i, KnownNat j, KnownNat k) => Layer Relu ('D3 i j k) ('D3 i j k) where
51instance (KnownNat i, KnownNat j, KnownNat k) => Layer Relu ('D3 i j k) ('D3 i j k) where
52+
53+ type Tape Relu ('D3 i j k) ('D3 i j k) = S ('D3 i j k)
54+
49− runForwards _ (S3D y) = S3D (relu y)
55+ runForwards _ (S3D y) = (S3D y, S3D (relu y))
50 where
56 where
51 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
57 relu = LAS.dmmap (\a -> if a <= 0 then 0 else a)
52 runBackwards _ (S3D y) (S3D dEdy) = ((), S3D (relu' y * dEdy))
58 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 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE TypeOperators #-}
2{-# LANGUAGE TypeOperators #-}
3{-# LANGUAGE TypeFamilies #-}
3{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
5module Grenade.Layers.Tanh (
6module Grenade.Layers.Tanh (
6 Tanh (..)
7 Tanh (..)
7 ) where
8 ) where
8
9
9import Data.Serialize
10import Data.Serialize
11+import Data.Singletons
10
12
11−import GHC.TypeLits
12−import Grenade.Core.Network
13−import Grenade.Core.Shape
13+import Grenade.Core
14
14
15-- | A Tanh layer.
15-- | A Tanh layer.
16-- A layer which can act between any shape of the same dimension, perfoming a tanh function.
16-- A layer which can act between any shape of the same dimension, perfoming a tanh function.
@@ -26,17 +26,10 @@ instance Serialize Tanh where
26 put _ = return ()
26 put _ = return ()
27 get = return Tanh
27 get = return Tanh
28
28
29−instance KnownNat i => Layer Tanh ('D1 i) ('D1 i) where
29+instance (a ~ b, SingI a) => Layer Tanh a b where
30− runForwards _ (S1D y) = S1D (tanh y)
30+ type Tape Tanh a b = S a
31− runBackwards _ (S1D y) (S1D dEdy) = ((), S1D (tanh' y * dEdy))
31+ runForwards _ a = (a, tanh a)
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))
32+ runBackwards _ a g = ((), tanh' a * g)
40
33
41tanh' :: (Floating a) => a -> a
34tanh' :: (Floating a) => a -> a
42tanh' t = 1 - s ^ (2 :: Int) where s = tanh t
35tanh' 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 @@
3{-# LANGUAGE TypeFamilies #-}
3{-# LANGUAGE TypeFamilies #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6−module Grenade.Recurrent.Layers.Trivial (
6+module Grenade.Layers.Trivial (
7 Trivial (..)
7 Trivial (..)
8 ) where
8 ) where
9
9
src/Grenade/Recurrent.hs−1
@@ -6,4 +6,3 @@ import Grenade.Recurrent.Core.Network as X
6import Grenade.Recurrent.Core.Runner as X
6import Grenade.Recurrent.Core.Runner as X
7import Grenade.Recurrent.Layers.BasicRecurrent as X
7import Grenade.Recurrent.Layers.BasicRecurrent as X
8import Grenade.Recurrent.Layers.LSTM as X
8import 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 )
22import Data.Serialize
22import Data.Serialize
23import qualified Data.Vector.Storable as V
23import qualified Data.Vector.Storable as V
24
24
25−import Grenade.Core.Shape
25+import Grenade.Core
26−import Grenade.Core.Network
27
26
28import qualified Numeric.LinearAlgebra as LA
27import qualified Numeric.LinearAlgebra as LA
29import qualified Numeric.LinearAlgebra.Static as LAS
28import qualified Numeric.LinearAlgebra.Static as LAS
@@ -43,33 +42,44 @@ class UpdateLayer x => RecurrentUpdateLayer x where
43 type RecurrentShape x :: Shape
42 type RecurrentShape x :: Shape
44
43
45class (RecurrentUpdateLayer x, SingI (RecurrentShape x)) => RecurrentLayer x (i :: Shape) (o :: Shape) where
44class (RecurrentUpdateLayer x, SingI (RecurrentShape x)) => RecurrentLayer x (i :: Shape) (o :: Shape) where
45+ -- | Wengert Tape
46+ type RecTape x i o :: *
46 -- | Used in training and scoring. Take the input from the previous
47 -- | Used in training and scoring. Take the input from the previous
47 -- layer, and give the output from this layer.
48 -- 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)
49 -- | Back propagate a step. Takes the current layer, the input that the
50 -- | Back propagate a step. Takes the current layer, the input that the
50 -- layer gave from the input and the back propagated derivatives from
51 -- layer gave from the input and the back propagated derivatives from
51 -- the layer above.
52 -- the layer above.
52 -- Returns the gradient layer and the derivatives to push back further.
53 -- 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)
54
55
55data RecurrentNetwork :: [*] -> [Shape] -> * where
56data RecurrentNetwork :: [*] -> [Shape] -> * where
57+ RNil :: SingI i
56− OR :: (SingI i, SingI o, Layer x i o) => !x -> RecurrentNetwork '[FeedForward x] '[i, o]
58+ => RecurrentNetwork '[] '[i]
59+
60+ (:~~>) :: (SingI i, Layer x i h)
61+ => !x
62+ -> !(RecurrentNetwork xs (h ': hs))
57− (:~~>) :: (SingI i, Layer x i h) => !x -> !(RecurrentNetwork xs (h ': hs)) -> RecurrentNetwork (FeedForward x ': xs) (i ': 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))
58− (:~@>) :: (SingI i, RecurrentLayer x i h) => !x -> !(RecurrentNetwork xs (h ': hs)) -> RecurrentNetwork (Recurrent x ': xs) (i ': h ': hs)
68+ -> RecurrentNetwork (Recurrent x ': xs) (i ': h ': hs)
59infixr 5 :~~>
69infixr 5 :~~>
60infixr 5 :~@>
70infixr 5 :~@>
61
71
62−instance Show (RecurrentNetwork l h) where
72+instance Show (RecurrentNetwork '[] '[i]) where
63− show (OR a) = "OR " ++ show a
73+ show RNil = "NNil"
74+instance (Show x, Show (RecurrentNetwork xs rs)) => Show (RecurrentNetwork (FeedForward x ': xs) (i ': rs)) where
64− show (i :~~> o) = show i ++ "\n:~~>\n" ++ show o
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
65− show (i :~@> o) = show i ++ "\n:~@>\n" ++ show o
77+ show (x :~@> xs) = show x ++ "\n~~>\n" ++ show xs
66−
67
78
68-- | Recurrent inputs (sideways shapes on an imaginary unrolled graph)
79-- | Recurrent inputs (sideways shapes on an imaginary unrolled graph)
69-- Parameterised on the layers of a Network.
80-- Parameterised on the layers of a Network.
70data RecurrentInputs :: [*] -> * where
81data RecurrentInputs :: [*] -> * where
71− ORS :: UpdateLayer x
72− => () -> RecurrentInputs '[FeedForward x]
82+ RINil :: RecurrentInputs '[]
73 (:~~+>) :: UpdateLayer x
83 (:~~+>) :: UpdateLayer x
74 => () -> !(RecurrentInputs xs) -> RecurrentInputs (FeedForward x ': xs)
84 => () -> !(RecurrentInputs xs) -> RecurrentInputs (FeedForward x ': xs)
75 (:~@+>) :: (SingI (RecurrentShape x), RecurrentUpdateLayer x)
85 (:~@+>) :: (SingI (RecurrentShape x), RecurrentUpdateLayer x)
@@ -83,18 +93,17 @@ class CreatableRecurrent (xs :: [*]) (ss :: [Shape]) where
83 -- | Create a network of the types requested
93 -- | Create a network of the types requested
84 randomRecurrent :: MonadRandom m => m (RecurrentNetwork xs ss, RecurrentInputs xs)
94 randomRecurrent :: MonadRandom m => m (RecurrentNetwork xs ss, RecurrentInputs xs)
85
95
86−instance (SingI i, SingI o, Layer x i o) => CreatableRecurrent (FeedForward x ': '[]) (i ': o ': '[]) where
96+instance SingI i => CreatableRecurrent '[] '[i] where
87− randomRecurrent = do
97+ randomRecurrent =
88− thisLayer <- createRandom
98+ return (RNil, RINil)
89− return (OR thisLayer, ORS ())
90
99
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
92 randomRecurrent = do
101 randomRecurrent = do
93 thisLayer <- createRandom
102 thisLayer <- createRandom
94 (rest, resti) <- randomRecurrent
103 (rest, resti) <- randomRecurrent
95 return (thisLayer :~~> rest, () :~~+> resti)
104 return (thisLayer :~~> rest, () :~~+> resti)
96
105
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
98 randomRecurrent = do
107 randomRecurrent = do
99 thisLayer <- createRandom
108 thisLayer <- createRandom
100 thisShape <- randomOfShape
109 thisShape <- randomOfShape
@@ -102,28 +111,27 @@ instance (SingI i, RecurrentLayer x i o, CreatableRecurrent xs (o ': r ': rs)) =
102 return (thisLayer :~@> rest, thisShape :~@+> resti)
111 return (thisLayer :~@> rest, thisShape :~@+> resti)
103
112
104-- | Add very simple serialisation to the recurrent network
113-- | 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
114+instance SingI i => Serialize (RecurrentNetwork '[] '[i]) where
106− put (OR x) = put x
115+ put RNil = pure ()
107− put _ = error "impossible"
116+ get = pure RNil
108− get = OR <$> get
109
117
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
111 put (x :~~> r) = put x >> put r
119 put (x :~~> r) = put x >> put r
112 get = (:~~>) <$> get <*> get
120 get = (:~~>) <$> get <*> get
113
121
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
115 put (x :~@> r) = put x >> put r
123 put (x :~@> r) = put x >> put r
116 get = (:~@>) <$> get <*> get
124 get = (:~@>) <$> get <*> get
117
125
118−instance (UpdateLayer x) => (Serialize (RecurrentInputs '[FeedForward x])) where
126+instance (Serialize (RecurrentInputs '[])) where
119 put _ = return ()
127 put _ = return ()
120− get = return (ORS ())
128+ get = return RINil
121
129
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
123 put ( () :~~+> rest) = put rest
131 put ( () :~~+> rest) = put rest
124 get = ( () :~~+> ) <$> get
132 get = ( () :~~+> ) <$> get
125
133
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
127 put ( i :~@+> rest ) = do
135 put ( i :~@+> rest ) = do
128 _ <- (case i of
136 _ <- (case i of
129 (S1D x) -> putListOf put . LA.toList . LAS.extract $ x
137 (S1D x) -> putListOf put . LA.toList . LAS.extract $ x
src/Grenade/Recurrent/Core/Runner.hs+36−41
@@ -3,18 +3,23 @@
3{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE DataKinds #-}
4{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE TypeOperators #-}
6+{-# LANGUAGE CPP #-}
6{-# LANGUAGE TypeFamilies #-}
7{-# LANGUAGE TypeFamilies #-}
7{-# LANGUAGE FlexibleContexts #-}
8{-# LANGUAGE FlexibleContexts #-}
8{-# LANGUAGE RankNTypes #-}
9{-# LANGUAGE RankNTypes #-}
9{-# LANGUAGE RecordWildCards #-}
10{-# LANGUAGE RecordWildCards #-}
11+
12+#if __GLASGOW_HASKELL__ < 800
13+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
14+#endif
15+
10module Grenade.Recurrent.Core.Runner (
16module Grenade.Recurrent.Core.Runner (
11 trainRecurrent
17 trainRecurrent
12 , runRecurrent
18 , runRecurrent
13 ) where
19 ) where
14
20
15import Data.Singletons.Prelude
21import Data.Singletons.Prelude
16−import Grenade.Core.Network
22+import Grenade.Core
17−import Grenade.Core.Shape
18
23
19import Grenade.Recurrent.Core.Network
24import Grenade.Recurrent.Core.Network
20
25
@@ -48,11 +53,13 @@ trainRecurrent rate network recinputs examples =
48 -- Note we're doing training here, we could just return a list of gradients
53 -- Note we're doing training here, we could just return a list of gradients
49 -- (and probably will in future).
54 -- (and probably will in future).
50 go !xs (layer :~~> n) (() :~~+> nIn)
55 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
52 -- recursively run the rest of the network, and get the gradients from above.
59 -- recursively run the rest of the network, and get the gradients from above.
53 (newFN, ig, grads) = go ys n nIn
60 (newFN, ig, grads) = go ys n nIn
54 -- calculate the gradient for this layer to pass down,
61 -- 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
56 -- the new trained layer.
63 -- the new trained layer.
57 newlayer = runUpdates rate layer (fst <$> back)
64 newlayer = runUpdates rate layer (fst <$> back)
58
65
@@ -61,11 +68,13 @@ trainRecurrent rate network recinputs examples =
61 -- This is a recurrent layer, so we need to do a scan, first input to last, providing
68 -- This is a recurrent layer, so we need to do a scan, first input to last, providing
62 -- the recurrent shape output to the next layer.
69 -- the recurrent shape output to the next layer.
63 go !xs (layer :~@> n) (g :~@+> nIn)
70 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
65
74
66− (newFN, ig, grads) = go (snd <$> ys) n nIn
75+ (newFN, ig, grads) = go ys n nIn
67
76
68− backExamples = zip3 (fst <$> reverse ys) (reverse xs) grads
77+ backExamples = zip (reverse tapes) grads
69
78
70 (rg, back) = myscanbackward layer backExamples
79 (rg, back) = myscanbackward layer backExamples
71 -- the new trained layer.
80 -- the new trained layer.
@@ -74,21 +83,12 @@ trainRecurrent rate network recinputs examples =
74
83
75 -- Handle the output layer, bouncing the derivatives back down.
84 -- Handle the output layer, bouncing the derivatives back down.
76 -- We may not have a target for each example, so when we don't use 0 gradient.
85 -- We may not have a target for each example, so when we don't use 0 gradient.
77− go !xs (OR layer) (ORS ())
86+ go !xs RNil RINil
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)
87+ = (RNil, RINil, reverse (zipWith makeError xs targets))
81− -- the new trained layer.
88+ where
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)
89+ makeError :: S (Last shapes) -> Maybe (S (Last shapes)) -> S (Last shapes)
90− makeError _ Nothing = 0
90+ makeError _ Nothing = 0
91− makeError y (Just t) = y - t
91+ makeError y (Just t) = y - t
92
92
93 updateRecInputs :: forall sublayers.
93 updateRecInputs :: forall sublayers.
94 LearningParameters
94 LearningParameters
@@ -102,31 +102,29 @@ trainRecurrent rate network recinputs examples =
102 updateRecInputs l@LearningParameters {..} (x :~@+> xs) (y :~@+> ys)
102 updateRecInputs l@LearningParameters {..} (x :~@+> xs) (y :~@+> ys)
103 = (realToFrac (learningRate * learningRegulariser) * x - realToFrac learningRate * y) :~@+> updateRecInputs l xs ys
103 = (realToFrac (learningRate * learningRegulariser) * x - realToFrac learningRate * y) :~@+> updateRecInputs l xs ys
104
104
105− updateRecInputs _ (ORS ()) (ORS ())
105+ updateRecInputs _ RINil RINil
106− = ORS ()
106+ = RINil
107− updateRecInputs _ _ _
108− = error "Impossible for updateRecInputs to have different shapes"
109
107
110scanlFrom :: forall x i o. RecurrentLayer x i o
108scanlFrom :: forall x i o. RecurrentLayer x i o
111 => x -- ^ the layer
109 => x -- ^ the layer
112 -> S (RecurrentShape x) -- ^ place to start
110 -> S (RecurrentShape x) -- ^ place to start
113 -> [S i] -- ^ list of inputs to scan through
111 -> [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
115scanlFrom !layer !recShape (x:xs) =
113scanlFrom !layer !recShape (x:xs) =
116− let (lerec, lepush) = runRecurrentForwards layer recShape x
114+ let (tape, lerec, lepush) = runRecurrentForwards layer recShape x
117− in (recShape, lepush) : scanlFrom layer lerec xs
115+ in (tape, lepush) : scanlFrom layer lerec xs
118scanlFrom _ _ [] = []
116scanlFrom _ _ [] = []
119
117
120myscanbackward :: forall x i o. RecurrentLayer x i o
118myscanbackward :: forall x i o. RecurrentLayer x i o
121 => x -- ^ the layer
119 => 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
123 -> (S (RecurrentShape x), [(Gradient x, S i)]) -- ^ list of gradients to fold and inputs to backprop
121 -> (S (RecurrentShape x), [(Gradient x, S i)]) -- ^ list of gradients to fold and inputs to backprop
124myscanbackward layer =
122myscanbackward layer =
125 goX 0
123 goX 0
126 where
124 where
127− goX :: S (RecurrentShape x) -> [(S (RecurrentShape x), S i, S o)] -> (S (RecurrentShape x), [(Gradient x, S i)])
125+ goX :: S (RecurrentShape x) -> [(RecTape x i o, S o)] -> (S (RecurrentShape x), [(Gradient x, S i)])
128− goX !lastback ((recShape, lastin, backgrad):xs) =
126+ goX !lastback ((recTape, backgrad):xs) =
129− let (layergrad, recgrad, ingrad) = runRecurrentBackwards layer recShape lastin lastback backgrad
127+ let (layergrad, recgrad, ingrad) = runRecurrentBackwards layer recTape lastback backgrad
130 (pushedback, ll) = goX recgrad xs
128 (pushedback, ll) = goX recgrad xs
131 in (pushedback, (layergrad, ingrad) : ll)
129 in (pushedback, (layergrad, ingrad) : ll)
132 goX !lastback [] = (lastback, [])
130 goX !lastback [] = (lastback, [])
@@ -136,15 +134,12 @@ runRecurrent :: RecurrentNetwork layers shapes
136 -> RecurrentInputs layers -> S (Head shapes)
134 -> RecurrentInputs layers -> S (Head shapes)
137 -> (RecurrentInputs layers, S (Last shapes))
135 -> (RecurrentInputs layers, S (Last shapes))
138runRecurrent (layer :~~> n) (() :~~+> nr) !x
136runRecurrent (layer :~~> n) (() :~~+> nr) !x
139− = let ys = runForwards layer x
137+ = let (_, ys) = runForwards layer x
140 (nr', o) = runRecurrent n nr ys
138 (nr', o) = runRecurrent n nr ys
141 in (() :~~+> nr', o)
139 in (() :~~+> nr', o)
142runRecurrent (layer :~@> n) (recin :~@+> nr) !x
140runRecurrent (layer :~@> n) (recin :~@+> nr) !x
143− = let (recin', y) = runRecurrentForwards layer recin x
141+ = let (_, recin', y) = runRecurrentForwards layer recin x
144− (nr', o) = runRecurrent n nr y
142+ (nr', o) = runRecurrent n nr y
145 in (recin' :~@+> nr', o)
143 in (recin' :~@+> nr', o)
146−runRecurrent (OR layer) (ORS ()) !x
144+runRecurrent RNil RINil !x
147− = (ORS (), runForwards layer x)
145+ = (RINil, x)
148−
149−runRecurrent _ _ _
150− = error "Impossible for the gradients of a network to have a different length or shape to the network"
src/Grenade/Recurrent/Layers/BasicRecurrent.hs+5−4
@@ -24,8 +24,7 @@ import Numeric.LinearAlgebra.Static
24
24
25import GHC.TypeLits
25import GHC.TypeLits
26
26
27−import Grenade.Core.Network
27+import Grenade.Core
28−import Grenade.Core.Shape
29import Grenade.Recurrent.Core.Network
28import Grenade.Recurrent.Core.Network
30
29
31data BasicRecurrent :: Nat -- Input layer size
30data BasicRecurrent :: Nat -- Input layer size
@@ -72,13 +71,15 @@ instance (KnownNat i, KnownNat o, KnownNat (i + o), i <= (i + o), o ~ ((i + o) -
72 type RecurrentShape (BasicRecurrent i o) = 'D1 o
71 type RecurrentShape (BasicRecurrent i o) = 'D1 o
73
72
74instance (KnownNat i, KnownNat o, KnownNat (i + o), i <= (i + o), o ~ ((i + o) - i)) => RecurrentLayer (BasicRecurrent i o) ('D1 i) ('D1 o) where
73instance (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))
75 -- Do a matrix vector multiplication and return the result.
76 -- Do a matrix vector multiplication and return the result.
76 runRecurrentForwards (BasicRecurrent wB _ wN _) (S1D lastOutput) (S1D thisInput) =
77 runRecurrentForwards (BasicRecurrent wB _ wN _) (S1D lastOutput) (S1D thisInput) =
77 let thisOutput = S1D $ wB + wN #> (thisInput # lastOutput)
78 let thisOutput = S1D $ wB + wN #> (thisInput # lastOutput)
78− in (thisOutput, thisOutput)
79+ in ((S1D lastOutput, S1D thisInput), thisOutput, thisOutput)
79
80
80 -- Run a backpropogation step for a full connected layer.
81 -- 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) =
82 let biasGradient = (dRec + dEdy)
83 let biasGradient = (dRec + dEdy)
83 layerGrad = (dRec + dEdy) `outer` (thisInput # lastOutput)
84 layerGrad = (dRec + dEdy) `outer` (thisInput # lastOutput)
84 -- calcluate derivatives for next step
85 -- calcluate derivatives for next step
src/Grenade/Recurrent/Layers/LSTM.hs+5−5
@@ -20,7 +20,6 @@ module Grenade.Recurrent.Layers.LSTM (
20
20
21import Control.Monad.Random ( MonadRandom, getRandom )
21import Control.Monad.Random ( MonadRandom, getRandom )
22
22
23−
24-- import Data.List ( foldl1' )
23-- import Data.List ( foldl1' )
25import Data.Proxy
24import Data.Proxy
26import Data.Serialize
25import Data.Serialize
@@ -29,8 +28,7 @@ import Data.Singletons.TypeLits
29import qualified Numeric.LinearAlgebra as LA
28import qualified Numeric.LinearAlgebra as LA
30import Numeric.LinearAlgebra.Static
29import Numeric.LinearAlgebra.Static
31
30
32−import Grenade.Core.Network
31+import Grenade.Core
33−import Grenade.Core.Shape
34
32
35import Grenade.Layers.Internal.Update
33import Grenade.Layers.Internal.Update
36
34
@@ -131,6 +129,8 @@ instance (KnownNat i, KnownNat o) => RecurrentUpdateLayer (LSTM i o) where
131 type RecurrentShape (LSTM i o) = 'D1 o
129 type RecurrentShape (LSTM i o) = 'D1 o
132
130
133instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) where
131instance (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))
134 -- Forward propagation for the LSTM layer.
134 -- Forward propagation for the LSTM layer.
135 -- The size of the cell state is also the size of the output.
135 -- The size of the cell state is also the size of the output.
136 runRecurrentForwards (LSTM (LSTMWeights {..}) _) (S1D cell) (S1D input) =
136 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
146 c_t = f_t * cell + i_t * c_x
146 c_t = f_t * cell + i_t * c_x
147 -- Output (it's sometimes recommended to use tanh c_t)
147 -- Output (it's sometimes recommended to use tanh c_t)
148 h_t = o_t * c_t
148 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)
150
150
151 -- Run a backpropogation step for an LSTM layer.
151 -- Run a backpropogation step for an LSTM layer.
152 -- We're doing all the derivatives by hand here, so one should
152 -- 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
154 --
154 --
155 -- There's a test version using the AD library without hmatrix in the test
155 -- There's a test version using the AD library without hmatrix in the test
156 -- suite. These should match always.
156 -- 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') =
158 -- We're not keeping the Wengert tape during the forward pass,
158 -- We're not keeping the Wengert tape during the forward pass,
159 -- so we're duplicating some work here.
159 -- so we're duplicating some work here.
160 --
160 --
test/Test/Grenade/Layers/Convolution.hs+3−4
@@ -15,8 +15,7 @@ import Data.Singletons ()
15import GHC.TypeLits
15import GHC.TypeLits
16import GHC.TypeLits.Witnesses
16import GHC.TypeLits.Witnesses
17
17
18−import Grenade.Core.Shape
18+import Grenade.Core
19−import Grenade.Core.Network
20import Grenade.Layers.Convolution
19import Grenade.Layers.Convolution
21
20
22import Disorder.Jack
21import Disorder.Jack
@@ -92,9 +91,9 @@ prop_conv_net =
92 , (unsafeCoerce (Dict :: Dict ()) :: Dict (((outCols - 1) * strideCols) ~ (inCols - kernelCols)))) of
91 , (unsafeCoerce (Dict :: Dict ()) :: Dict (((outCols - 1) * strideCols) ~ (inCols - kernelCols)))) of
93 (Dict, Dict, Dict, Dict) ->
92 (Dict, Dict, Dict, Dict) ->
94 gamble (S3D <$> uniformSample) $ \(input :: S ('D3 inRows inCols channels)) ->
93 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
96 backed :: (Gradient (Convolution channels filters kernelRows kernelCols strideRows strideCols), S ('D3 inRows inCols channels))
95 backed :: (Gradient (Convolution channels filters kernelRows kernelCols strideRows strideCols), S ('D3 inRows inCols channels))
97− = runBackwards convLayer input output
96+ = runBackwards convLayer tape output
98 in backed `seq` True
97 in backed `seq` True
99 ) :: Property
98 ) :: Property
100 ) :: Property
99 ) :: Property
test/Test/Grenade/Layers/FullyConnected.hs+4−5
@@ -12,8 +12,7 @@ import Data.Singletons ()
12
12
13import GHC.TypeLits
13import GHC.TypeLits
14
14
15−import Grenade.Core.Shape
15+import Grenade.Core
16−import Grenade.Core.Network
17import Grenade.Layers.FullyConnected
16import Grenade.Layers.FullyConnected
18
17
19import Disorder.Jack
18import Disorder.Jack
@@ -39,15 +38,15 @@ genOpaqueFullyConnected = do
39 bM <- randomVector
38 bM <- randomVector
40 wN <- uniformSample
39 wN <- uniformSample
41 kM <- uniformSample
40 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')
43
42
44prop_fully_connected_forwards :: Property
43prop_fully_connected_forwards :: Property
45prop_fully_connected_forwards =
44prop_fully_connected_forwards =
46 gamble genOpaqueFullyConnected $ \(OpaqueFullyConnected (fclayer :: FullyConnected i o)) ->
45 gamble genOpaqueFullyConnected $ \(OpaqueFullyConnected (fclayer :: FullyConnected i o)) ->
47 gamble (S1D <$> randomVector) $ \(input :: S ('D1 i)) ->
46 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
49 backed :: (Gradient (FullyConnected i o), S ('D1 i))
48 backed :: (Gradient (FullyConnected i o), S ('D1 i))
50− = runBackwards fclayer input output
49+ = runBackwards fclayer tape output
51 in backed `seq` True
50 in backed `seq` True
52
51
53return []
52return []
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 =
44 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
44 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
45 let actual = runRecurrentForwards net (S1D cell) (S1D input)
45 let actual = runRecurrentForwards net (S1D cell) (S1D input)
46 in case actual of
46 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)) ->
48 let cellOut' = Reference.Vector . H.toList . S.extract $ cellOut
48 let cellOut' = Reference.Vector . H.toList . S.extract $ cellOut
49 output' = Reference.Vector . H.toList . S.extract $ output
49 output' = Reference.Vector . H.toList . S.extract $ output
50 refNet = Reference.lstmToReference lstmWeights
50 refNet = Reference.lstmToReference lstmWeights
@@ -57,9 +57,9 @@ prop_lstm_reference_backwards =
57 gamble randomVector $ \(input :: S.R 3) ->
57 gamble randomVector $ \(input :: S.R 3) ->
58 gamble randomVector $ \(cell :: S.R 2) ->
58 gamble randomVector $ \(cell :: S.R 2) ->
59 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
59 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))
61 in case actualBacks of
61 in case actualBacks of
62− (actualGradients, _, _) ->
62+ (actualGradients, _, _ :: S ('D1 3)) ->
63 let refNet = Reference.lstmToReference lstmWeights
63 let refNet = Reference.lstmToReference lstmWeights
64 refCell = Reference.Vector . H.toList . S.extract $ cell
64 refCell = Reference.Vector . H.toList . S.extract $ cell
65 refInput = Reference.Vector . H.toList . S.extract $ input
65 refInput = Reference.Vector . H.toList . S.extract $ input
@@ -70,9 +70,9 @@ prop_lstm_reference_backwards_input =
70 gamble randomVector $ \(input :: S.R 3) ->
70 gamble randomVector $ \(input :: S.R 3) ->
71 gamble randomVector $ \(cell :: S.R 2) ->
71 gamble randomVector $ \(cell :: S.R 2) ->
72 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
72 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))
74 in case actualBacks of
74 in case actualBacks of
75− (_, _, S1D actualGradients) ->
75+ (_, _, S1D actualGradients :: S ('D1 3)) ->
76 let refNet = Reference.lstmToReference lstmWeights
76 let refNet = Reference.lstmToReference lstmWeights
77 refCell = Reference.Vector . H.toList . S.extract $ cell
77 refCell = Reference.Vector . H.toList . S.extract $ cell
78 refInput = Reference.Vector . H.toList . S.extract $ input
78 refInput = Reference.Vector . H.toList . S.extract $ input
@@ -83,9 +83,9 @@ prop_lstm_reference_backwards_cell =
83 gamble randomVector $ \(input :: S.R 3) ->
83 gamble randomVector $ \(input :: S.R 3) ->
84 gamble randomVector $ \(cell :: S.R 2) ->
84 gamble randomVector $ \(cell :: S.R 2) ->
85 gamble genLSTM $ \(net@(LSTM lstmWeights _) :: LSTM 3 2) ->
85 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))
87 in case actualBacks of
87 in case actualBacks of
88− (_, S1D actualGradients, _) ->
88+ (_, S1D actualGradients, _ :: S ('D1 3)) ->
89 let refNet = Reference.lstmToReference lstmWeights
89 let refNet = Reference.lstmToReference lstmWeights
90 refCell = Reference.Vector . H.toList . S.extract $ cell
90 refCell = Reference.Vector . H.toList . S.extract $ cell
91 refInput = Reference.Vector . H.toList . S.extract $ input
91 refInput = Reference.Vector . H.toList . S.extract $ input
test/Test/Jack/Hmatrix.hs+12
@@ -1,9 +1,13 @@
1{-# LANGUAGE RankNTypes #-}
1{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4+{-# LANGUAGE GADTs #-}
4
5
5module Test.Jack.Hmatrix where
6module Test.Jack.Hmatrix where
6
7
8+import Grenade
9+import Data.Singletons
10+
7import Disorder.Jack
11import Disorder.Jack
8
12
9import GHC.TypeLits
13import GHC.TypeLits
@@ -15,3 +19,11 @@ randomVector = (\s -> HStatic.randomVector s HStatic.Uniform * 2 - 1) <$> sizedN
15
19
16uniformSample :: forall m n. (KnownNat m, KnownNat n) => Jack (HStatic.L m n)
20uniformSample :: forall m n. (KnownNat m, KnownNat n) => Jack (HStatic.L m n)
17uniformSample = (\s -> HStatic.uniformSample s (-1) 1 ) <$> sizedNat
21uniformSample = (\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 #-}
1{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE ScopedTypeVariables #-}
4−
5+{-# LANGUAGE PolyKinds #-}
5module Test.Jack.TypeLits where
6module Test.Jack.TypeLits where
6
7
8+import Data.Constraint
9+#if __GLASGOW_HASKELL__ < 800
10+import Data.Proxy
11+#endif
12+import Data.Singletons
7import Disorder.Jack
13import Disorder.Jack
8
14
15+import Grenade
16+
9import GHC.TypeLits
17import GHC.TypeLits
18+import GHC.TypeLits.Witnesses
10
19
11genNat :: Jack SomeNat
20genNat :: Jack SomeNat
12genNat = do
21genNat = do
13 Just n <- someNatVal <$> choose (1, 10)
22 Just n <- someNatVal <$> choose (1, 10)
14 return n
23 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
3import qualified Test.Grenade.Layers.Pooling
3import qualified Test.Grenade.Layers.Pooling
4import qualified Test.Grenade.Layers.Convolution
4import qualified Test.Grenade.Layers.Convolution
5import qualified Test.Grenade.Layers.FullyConnected
5import qualified Test.Grenade.Layers.FullyConnected
6+import qualified Test.Grenade.Layers.Nonlinear
7+import qualified Test.Grenade.Layers.PadCrop
6
8
7import qualified Test.Grenade.Layers.Internal.Convolution
9import qualified Test.Grenade.Layers.Internal.Convolution
8import qualified Test.Grenade.Layers.Internal.Pooling
10import qualified Test.Grenade.Layers.Internal.Pooling
@@ -15,6 +17,8 @@ main =
15 Test.Grenade.Layers.Pooling.tests
17 Test.Grenade.Layers.Pooling.tests
16 , Test.Grenade.Layers.Convolution.tests
18 , Test.Grenade.Layers.Convolution.tests
17 , Test.Grenade.Layers.FullyConnected.tests
19 , Test.Grenade.Layers.FullyConnected.tests
20+ , Test.Grenade.Layers.Nonlinear.tests
21+ , Test.Grenade.Layers.PadCrop.tests
18
22
19 , Test.Grenade.Layers.Internal.Convolution.tests
23 , Test.Grenade.Layers.Internal.Convolution.tests
20 , Test.Grenade.Layers.Internal.Pooling.tests
24 , Test.Grenade.Layers.Internal.Pooling.tests