on master help sign in
Merge pull request #32 from HuwCampbell/topic/compose-recurrent

Topic/compose recurrent

commit9b18913acd2c8dfaed8be51b696afb25aa024588 authorHuw Campbell <huw.campbell@gmail.com> dateSat 15 Jul 2017, 20:39 (9 years ago) parent46a1d83a9aeb76
12 files changed+374−165
bench/bench-lstm.hs+4−6 examples/main/recurrent.hs+5−5 examples/main/shakespeare.hs+7−7 grenade.cabal+2−1 src/Grenade/Core/Shape.hs+13 src/Grenade/Recurrent/Core/Layer.hs+4−6 src/Grenade/Recurrent/Core/Network.hs+112−110 src/Grenade/Recurrent/Core/Runner.hs+49−28 src/Grenade/Recurrent/Layers.hs+2 src/Grenade/Recurrent/Layers/BasicRecurrent.hs+1−1 src/Grenade/Recurrent/Layers/ConcatRecurrent.hs+174 src/Grenade/Recurrent/Layers/LSTM.hs+1−1
bench/bench-lstm.hs+4−6
@@ -16,7 +16,7 @@ main = do
1616 input40 :: S ('D1 40) <- randomOfShape
1717 rec60 :: S ('D1 60) <- randomOfShape
1818 rec512 :: S ('D1 512) <- randomOfShape
19− (lstm, lstm') :: (RecNet, RecInput) <- randomRecurrent
19+ lstm :: RecNet <- randomRecurrent
2020
2121 let upIn60 :: H.R 3600 = H.randomVector 1 H.Uniform * 2 - 1
2222 let upIn512 :: H.R 262144 = H.randomVector 1 H.Uniform * 2 - 1
@@ -30,9 +30,9 @@ main = do
3030 , bgroup "update" [ bench "matrix-60x60" $ nf (uncurry3 (decendVector 1 1 1)) (upIn60, upIn60, upIn60)
3131 , bench "matrix-512x512" $ nf (uncurry3 (decendVector 1 1 1)) (upIn512, upIn512, upIn512)
3232 ]
33− , bgroup "train" [ bench "one-time-step" $ whnf (nfT2 . trainRecurrent lp lstm lstm') [(input40, Just input40)]
34− , bench "ten-time-steps" $ whnf (nfT2 . trainRecurrent lp lstm lstm') $ replicate 10 (input40, Just input40)
35− , bench "fifty-time-steps" $ whnf (nfT2 . trainRecurrent lp lstm lstm') $ replicate 50 (input40, Just input40)
33+ , bgroup "train" [ bench "one-time-step" $ whnf (nfT2 . trainRecurrent lp lstm 0) [(input40, Just input40)]
34+ , bench "ten-time-steps" $ whnf (nfT2 . trainRecurrent lp lstm 0) $ replicate 10 (input40, Just input40)
35+ , bench "fifty-time-steps" $ whnf (nfT2 . trainRecurrent lp lstm 0) $ replicate 50 (input40, Just input40)
3636 ]
3737 ]
3838
@@ -65,7 +65,5 @@ type R = Recurrent
6565type RecNet = RecurrentNetwork '[ R (LSTM 40 512), R (LSTM 512 40) ]
6666 '[ 'D1 40, 'D1 512, 'D1 40 ]
6767
68−type RecInput = RecurrentInputs '[ R (LSTM 40 512), R (LSTM 512 40) ]
69−
7068lp :: LearningParameters
7169lp = LearningParameters 0.1 0 0
examples/main/recurrent.hs+5−5
@@ -36,7 +36,7 @@ type RecNet = RecurrentNetwork '[ R (LSTM 1 4), R (LSTM 4 1)]
3636
3737type RecInput = RecurrentInputs '[ R (LSTM 1 4), R (LSTM 4 1)]
3838
39−randomNet :: MonadRandom m => m (RecNet, RecInput)
39+randomNet :: MonadRandom m => m RecNet
4040randomNet = randomRecurrent
4141
4242netTest :: MonadRandom m => RecNet -> RecInput -> LearningParameters -> Int -> m (RecNet, RecInput)
@@ -69,8 +69,8 @@ generateRecurrent n s i =
6969 unfoldr go (s, i)
7070 where
7171 go (x, y) =
72− do let (ns, o) = runRecurrent n x y
73− o' = heat o
72+ do let (_, ns, o) = runRecurrent n x y
73+ o' = heat o
7474 Just (o', (ns, fromIntegral o'))
7575
7676 heat :: S ('D1 1) -> Int
@@ -82,8 +82,8 @@ main = do
8282 FeedForwardOpts examples rate <- execParser (info (feedForward' <**> helper) idm)
8383 putStrLn "Training network..."
8484
85− (net0, i0) <- randomNet
86− (trained, bestInput) <- netTest net0 i0 rate examples
85+ net0 <- randomNet
86+ (trained, bestInput) <- netTest net0 0 rate examples
8787
8888 let results = generateRecurrent trained bestInput (c 1)
8989
examples/main/shakespeare.hs+7−7
@@ -61,7 +61,7 @@ type Shakespeare = RecurrentNetwork '[ R (LSTM 40 80), R (LSTM 80 40), F (FullyC
6161-- The definition of the "sideways" input, which the network is fed recurrently.
6262type Shakespearian = RecurrentInputs '[ R (LSTM 40 80), R (LSTM 80 40), F (FullyConnected 40 40), F Logit]
6363
64−randomNet :: MonadRandom m => m (Shakespeare, Shakespearian)
64+randomNet :: MonadRandom m => m Shakespeare
6565randomNet = randomRecurrent
6666
6767-- | Load the data files and prepare a map of characters to a compressed int representation.
@@ -90,7 +90,7 @@ runShakespeare ShakespeareOpts {..} = do
9090 (net0, i0) <- lift $
9191 case loadPath of
9292 Just loadFile -> netLoad loadFile
93− Nothing -> randomNet
93+ Nothing -> (,0) <$> randomNet
9494
9595 (trained, bestInput) <- lift $ foldM (\(!net, !io) size -> do
9696 xs <- take (iterations `div` 10) <$> getRandomRs (0, length shakespeare - size - 1)
@@ -102,7 +102,7 @@ runShakespeare ShakespeareOpts {..} = do
102102 ) (net0, i0) $ replicate 10 sequenceSize
103103
104104 case savePath of
105− Just saveFile -> lift . B.writeFile saveFile $ runPut (put (trained, bestInput))
105+ Just saveFile -> lift . B.writeFile saveFile $ runPut (put trained >> put bestInput)
106106 Nothing -> return ()
107107
108108generateParagraph :: forall layers shapes n a. (Last shapes ~ 'D1 n, Head shapes ~ 'D1 n, KnownNat n, Ord a)
@@ -117,10 +117,10 @@ generateParagraph n s temperature hotmap hotdict =
117117 go s
118118 where
119119 go x y =
120− do let (ns, o) = runRecurrent n x y
121− un <- sample temperature hotdict o
122− Just re <- return $ makeHot hotmap un
123− rest <- unsafeInterleaveIO $ go ns re
120+ do let (_, ns, o) = runRecurrent n x y
121+ un <- sample temperature hotdict o
122+ Just re <- return $ makeHot hotmap un
123+ rest <- unsafeInterleaveIO $ go ns re
124124 return (un : rest)
125125
126126data ShakespeareOpts = ShakespeareOpts {
grenade.cabal+2−1
@@ -48,7 +48,7 @@ library
4848 , mtl >= 2.2.1 && < 2.3
4949 , primitive >= 0.6 && < 0.7
5050 , text == 1.2.*
51− , singletons >= 2.1 && < 2.3
51+ , singletons >= 2.1 && < 2.4
5252 , vector >= 0.11 && < 0.13
5353
5454 ghc-options:
@@ -102,6 +102,7 @@ library
102102
103103 Grenade.Recurrent.Layers
104104 Grenade.Recurrent.Layers.BasicRecurrent
105+ Grenade.Recurrent.Layers.ConcatRecurrent
105106 Grenade.Recurrent.Layers.LSTM
106107
107108 Grenade.Utils.OneHot
src/Grenade/Core/Shape.hs+13
@@ -29,6 +29,7 @@ import Control.DeepSeq (NFData (..))
2929import Control.Monad.Random ( MonadRandom, getRandom )
3030
3131import Data.Proxy
32+import Data.Serialize
3233import Data.Singletons
3334import Data.Singletons.TypeLits
3435import Data.Vector.Storable ( Vector )
@@ -171,6 +172,18 @@ fromStorable xs = case sing :: Sing x of
171172 then H.create $ NLA.reshape columns v
172173 else Nothing
173174
175+
176+instance SingI x => Serialize (S x) where
177+ put i = (case i of
178+ (S1D x) -> putListOf put . NLA.toList . H.extract $ x
179+ (S2D x) -> putListOf put . NLA.toList . NLA.flatten . H.extract $ x
180+ (S3D x) -> putListOf put . NLA.toList . NLA.flatten . H.extract $ x
181+ ) :: PutM ()
182+
183+ get = do
184+ Just i <- fromStorable . V.fromList <$> getListOf get
185+ return i
186+
174187-- Helper function for creating the number instances
175188n1 :: ( forall a. Floating a => a -> a ) -> S x -> S x
176189n1 f (S1D x) = S1D (f x)
src/Grenade/Recurrent/Core/Layer.hs+4−6
@@ -8,8 +8,6 @@ module Grenade.Recurrent.Core.Layer (
88 , RecurrentUpdateLayer (..)
99 ) where
1010
11−import Data.Singletons ( SingI )
12−
1311import Grenade.Core
1412
1513-- | Class for a recurrent layer.
@@ -17,16 +15,16 @@ import Grenade.Core
1715-- of an extra recurrent data shape.
1816class UpdateLayer x => RecurrentUpdateLayer x where
1917 -- | Shape of data that is passed between each subsequent run of the layer
20− type RecurrentShape x :: Shape
18+ type RecurrentShape x :: *
2119
22−class (RecurrentUpdateLayer x, SingI (RecurrentShape x)) => RecurrentLayer x (i :: Shape) (o :: Shape) where
20+class (RecurrentUpdateLayer x, Num (RecurrentShape x)) => RecurrentLayer x (i :: Shape) (o :: Shape) where
2321 -- | Wengert Tape
2422 type RecTape x i o :: *
2523 -- | Used in training and scoring. Take the input from the previous
2624 -- layer, and give the output from this layer.
27− runRecurrentForwards :: x -> S (RecurrentShape x) -> S i -> (RecTape x i o, S (RecurrentShape x), S o)
25+ runRecurrentForwards :: x -> RecurrentShape x -> S i -> (RecTape x i o, RecurrentShape x, S o)
2826 -- | Back propagate a step. Takes the current layer, the input that the
2927 -- layer gave from the input and the back propagated derivatives from
3028 -- the layer above.
3129 -- Returns the gradient layer and the derivatives to push back further.
32− runRecurrentBackwards :: x -> RecTape x i o -> S (RecurrentShape x) -> S o -> (Gradient x, S (RecurrentShape x), S i)
30+ runRecurrentBackwards :: x -> RecTape x i o -> RecurrentShape x -> S o -> (Gradient x, RecurrentShape x, S i)
src/Grenade/Recurrent/Core/Network.hs+112−110
@@ -17,12 +17,12 @@ module Grenade.Recurrent.Core.Network (
1717
1818 , RecurrentNetwork (..)
1919 , RecurrentInputs (..)
20− , RecurrentTapes (..)
21− , RecurrentGradients (..)
20+ , RecurrentTape (..)
21+ , RecurrentGradient (..)
2222
2323 , randomRecurrent
24− , runRecurrentNetwork
25− , runRecurrentGradient
24+ , runRecurrent
25+ , runRecurrent'
2626 , applyRecurrentUpdate
2727 ) where
2828
@@ -31,14 +31,10 @@ import Control.Monad.Random ( MonadRandom )
3131import Data.Singletons ( SingI )
3232import Data.Singletons.Prelude ( Head, Last )
3333import Data.Serialize
34−import qualified Data.Vector.Storable as V
3534
3635import Grenade.Core
3736import Grenade.Recurrent.Core.Layer
3837
39−import qualified Numeric.LinearAlgebra as LA
40−import qualified Numeric.LinearAlgebra.Static as LAS
41−
4238-- | Witness type to say indicate we're building up with a normal feed
4339-- forward layer.
4440data FeedForward :: * -> *
@@ -75,96 +71,82 @@ infixr 5 :~@>
7571-- | Gradient of a network.
7672--
7773-- Parameterised on the layers of the network.
78−data RecurrentGradients :: [*] -> * where
79− RGNil :: RecurrentGradients '[]
74+data RecurrentGradient :: [*] -> * where
75+ RGNil :: RecurrentGradient '[]
8076
8177 (://>) :: UpdateLayer x
82− => [Gradient x]
83− -> RecurrentGradients xs
84− -> RecurrentGradients (phantom x ': xs)
78+ => Gradient x
79+ -> RecurrentGradient xs
80+ -> RecurrentGradient (phantom x ': xs)
8581
8682-- | Recurrent inputs (sideways shapes on an imaginary unrolled graph)
8783-- Parameterised on the layers of a Network.
8884data RecurrentInputs :: [*] -> * where
8985 RINil :: RecurrentInputs '[]
9086
91− (:~~+>) :: UpdateLayer x
87+ (:~~+>) :: (UpdateLayer x, Fractional (RecurrentInputs xs))
9288 => () -> !(RecurrentInputs xs) -> RecurrentInputs (FeedForward x ': xs)
9389
94− (:~@+>) :: (SingI (RecurrentShape x), RecurrentUpdateLayer x)
95− => !(S (RecurrentShape x)) -> !(RecurrentInputs xs) -> RecurrentInputs (Recurrent x ': xs)
90+ (:~@+>) :: (Fractional (RecurrentShape x), Fractional (RecurrentInputs xs), RecurrentUpdateLayer x)
91+ => !(RecurrentShape x) -> !(RecurrentInputs xs) -> RecurrentInputs (Recurrent x ': xs)
9692
9793-- | All the information required to backpropogate
9894-- through time safely.
9995--
10096-- We index on the time step length as well, to ensure
10197-- that that all Tape lengths are the same.
102−data RecurrentTapes :: [*] -> [Shape] -> * where
98+data RecurrentTape :: [*] -> [Shape] -> * where
10399 TRNil :: SingI i
104− => RecurrentTapes '[] '[i]
105−
106− (:\~>) :: [Tape x i h]
107− -> !(RecurrentTapes xs (h ': hs))
108− -> RecurrentTapes (FeedForward x ': xs) (i ': h ': hs)
100+ => RecurrentTape '[] '[i]
109101
102+ (:\~>) :: Tape x i h
103+ -> !(RecurrentTape xs (h ': hs))
104+ -> RecurrentTape (FeedForward x ': xs) (i ': h ': hs)
110105
111− (:\@>) :: [RecTape x i h]
112− -> !(RecurrentTapes xs (h ': hs))
113− -> RecurrentTapes (Recurrent x ': xs) (i ': h ': hs)
106+ (:\@>) :: RecTape x i h
107+ -> !(RecurrentTape xs (h ': hs))
108+ -> RecurrentTape (Recurrent x ': xs) (i ': h ': hs)
114109
115110
116−runRecurrentNetwork :: forall shapes layers.
117− RecurrentNetwork layers shapes
118− -> RecurrentInputs layers
119− -> [S (Head shapes)]
120− -> (RecurrentTapes layers shapes, RecurrentInputs layers, [S (Last shapes)])
121−runRecurrentNetwork =
111+runRecurrent :: forall shapes layers.
112+ RecurrentNetwork layers shapes
113+ -> RecurrentInputs layers
114+ -> S (Head shapes)
115+ -> (RecurrentTape layers shapes, RecurrentInputs layers, S (Last shapes))
116+runRecurrent =
122117 go
123118 where
124119 go :: forall js sublayers. (Last js ~ Last shapes)
125120 => RecurrentNetwork sublayers js
126121 -> RecurrentInputs sublayers
127− -> [S (Head js)]
128− -> (RecurrentTapes sublayers js, RecurrentInputs sublayers, [S (Last js)])
129− -- This is a simple non-recurrent layer, just map it forwards
130− go (layer :~~> n) (() :~~+> nIn) !xs
131− = let tys = runForwards layer <$> xs
132− feedForwardTapes = fst <$> tys
133− forwards = snd <$> tys
122+ -> S (Head js)
123+ -> (RecurrentTape sublayers js, RecurrentInputs sublayers, S (Last js))
124+ go (!layer :~~> n) (() :~~+> nIn) !x
125+ = let (!tape, !forwards) = runForwards layer x
126+
134127 -- recursively run the rest of the network, and get the gradients from above.
135− (newFN, ig, answer) = go n nIn forwards
136− in (feedForwardTapes :\~> newFN, () :~~+> ig, answer)
128+ (!newFN, !ig, !answer) = go n nIn forwards
129+ in (tape :\~> newFN, () :~~+> ig, answer)
137130
138131 -- This is a recurrent layer, so we need to do a scan, first input to last, providing
139132 -- the recurrent shape output to the next layer.
140− go (layer :~@> n) (recIn :~@+> nIn) !xs
141− = let (recOut, tys) = goR layer recIn xs
142− recurrentTapes = fst <$> tys
143− forwards = snd <$> tys
144−
133+ go (layer :~@> n) (recIn :~@+> nIn) !x
134+ = let (tape, shape, forwards) = runRecurrentForwards layer recIn x
145135 (newFN, ig, answer) = go n nIn forwards
146− in (recurrentTapes :\@> newFN, recOut :~@+> ig, answer)
136+ in (tape :\@> newFN, shape :~@+> ig, answer)
147137
148138 -- Handle the output layer, bouncing the derivatives back down.
149139 -- We may not have a target for each example, so when we don't use 0 gradient.
150140 go RNil RINil !x
151141 = (TRNil, RINil, x)
152142
153− -- Helper function for recurrent layers
154− -- Scans over the recurrent direction of the graph.
155− goR !layer !recShape (x:xs) =
156− let (tape, lerec, lepush) = runRecurrentForwards layer recShape x
157− (rems, push) = goR layer lerec xs
158− in (rems, (tape, lepush) : push)
159− goR _ rin [] = (rin, [])
160−
161−runRecurrentGradient :: forall layers shapes.
162− RecurrentNetwork layers shapes
163− -> RecurrentTapes layers shapes
164− -> RecurrentInputs layers
165− -> [S (Last shapes)]
166− -> (RecurrentGradients layers, RecurrentInputs layers, [S (Head shapes)])
167−runRecurrentGradient net tapes r o =
143+runRecurrent' :: forall layers shapes.
144+ RecurrentNetwork layers shapes
145+ -> RecurrentTape layers shapes
146+ -> RecurrentInputs layers
147+ -> S (Last shapes)
148+ -> (RecurrentGradient layers, RecurrentInputs layers, S (Head shapes))
149+runRecurrent' net tapes r o =
168150 go net tapes r
169151 where
170152 -- We have to be careful regarding the direction of the lists
@@ -172,51 +154,41 @@ runRecurrentGradient net tapes r o =
172154 -- through time.
173155 go :: forall js ss. (Last js ~ Last shapes)
174156 => RecurrentNetwork ss js
175− -> RecurrentTapes ss js
157+ -> RecurrentTape ss js
176158 -> RecurrentInputs ss
177− -> (RecurrentGradients ss, RecurrentInputs ss, [S (Head js)])
159+ -> (RecurrentGradient ss, RecurrentInputs ss, S (Head js))
178160 -- This is a simple non-recurrent layer
179− -- Run the rest of the network, then fmap the tapes and gradients
180− go (layer :~~> n) (feedForwardTapes :\~> nTapes) (() :~~+> nRecs) =
181− let (gradients, rins, feed) = go n nTapes nRecs
182− backs = uncurry (runBackwards layer) <$> zip (reverse feedForwardTapes) feed
183− in ((fst <$> backs) ://> gradients, () :~~+> rins, snd <$> backs)
161+ -- Run the rest of the network, update with the tapes and gradients
162+ go (!layer :~~> n) (!tape :\~> nTapes) (() :~~+> nRecs) =
163+ let (!gradients, !rins, !feed) = go n nTapes nRecs
164+ (!grad, !back) = runBackwards layer tape feed
165+ in (grad ://> gradients, () :~~+> rins, back)
184166
185167 -- This is a recurrent layer
186168 -- Run the rest of the network, scan over the tapes in reverse
187− go (layer :~@> n) (recurrentTapes :\@> nTapes) (recGrad :~@+> nRecs) =
188− let (gradients, rins, feed) = go n nTapes nRecs
189− backExamples = zip (reverse recurrentTapes) feed
190− (rg, backs) = goX layer recGrad backExamples
191− in ((fst <$> backs) ://> gradients, rg :~@+> rins, snd <$> backs)
169+ go (!layer :~@> n) (!tape :\@> nTapes) (!recGrad :~@+> nRecs) =
170+ let (!gradients, !rins, !feed) = go n nTapes nRecs
171+ (!grad, !sidegrad, !back) = runRecurrentBackwards layer tape recGrad feed
172+ in (grad ://> gradients, sidegrad :~@+> rins, back)
192173
193174 -- End of the road, so we reflect the given gradients backwards.
194175 -- Crucially, we reverse the list, so it's backwards in time as
195176 -- well.
196− go RNil TRNil RINil
197− = (RGNil, RINil, reverse o)
198−
199− -- Helper function for recurrent layers
200− -- Scans over the recurrent direction of the graph.
201− goX :: RecurrentLayer x i o => x -> S (RecurrentShape x) -> [(RecTape x i o, S o)] -> (S (RecurrentShape x), [(Gradient x, S i)])
202− goX layer !lastback ((recTape, backgrad):xs) =
203− let (layergrad, recgrad, ingrad) = runRecurrentBackwards layer recTape lastback backgrad
204− (pushedback, ll) = goX layer recgrad xs
205− in (pushedback, (layergrad, ingrad) : ll)
206− goX _ !lastback [] = (lastback, [])
177+ go !RNil !TRNil !RINil
178+ = (RGNil, RINil, o)
207179
208180-- | Apply a batch of gradients to the network
209181-- Uses runUpdates which can be specialised for
210182-- a layer.
211183applyRecurrentUpdate :: LearningParameters
212184 -> RecurrentNetwork layers shapes
213− -> RecurrentGradients layers
185+ -> RecurrentGradient layers
214186 -> RecurrentNetwork layers shapes
215187applyRecurrentUpdate rate (layer :~~> rest) (gradient ://> grest)
216− = runUpdates rate layer gradient :~~> applyRecurrentUpdate rate rest grest
188+ = runUpdate rate layer gradient :~~> applyRecurrentUpdate rate rest grest
217189
218190applyRecurrentUpdate rate (layer :~@> rest) (gradient ://> grest)
219− = runUpdates rate layer gradient :~@> applyRecurrentUpdate rate rest grest
191+ = runUpdate rate layer gradient :~@> applyRecurrentUpdate rate rest grest
220192
221193applyRecurrentUpdate _ RNil RGNil
222194 = RNil
@@ -234,24 +206,23 @@ instance (Show x, Show (RecurrentNetwork xs rs)) => Show (RecurrentNetwork (Recu
234206-- recurrent network and a set of random inputs for it is with the randomRecurrent.
235207class CreatableRecurrent (xs :: [*]) (ss :: [Shape]) where
236208 -- | Create a network of the types requested
237− randomRecurrent :: MonadRandom m => m (RecurrentNetwork xs ss, RecurrentInputs xs)
209+ randomRecurrent :: MonadRandom m => m (RecurrentNetwork xs ss)
238210
239211instance SingI i => CreatableRecurrent '[] '[i] where
240212 randomRecurrent =
241− return (RNil, RINil)
213+ return RNil
242214
243215instance (SingI i, Layer x i o, CreatableRecurrent xs (o ': rs)) => CreatableRecurrent (FeedForward x ': xs) (i ': o ': rs) where
244216 randomRecurrent = do
245217 thisLayer <- createRandom
246− (rest, resti) <- randomRecurrent
247− return (thisLayer :~~> rest, () :~~+> resti)
218+ rest <- randomRecurrent
219+ return (thisLayer :~~> rest)
248220
249221instance (SingI i, RecurrentLayer x i o, CreatableRecurrent xs (o ': rs)) => CreatableRecurrent (Recurrent x ': xs) (i ': o ': rs) where
250222 randomRecurrent = do
251223 thisLayer <- createRandom
252− thisShape <- randomOfShape
253− (rest, resti) <- randomRecurrent
254− return (thisLayer :~@> rest, thisShape :~@+> resti)
224+ rest <- randomRecurrent
225+ return (thisLayer :~@> rest)
255226
256227-- | Add very simple serialisation to the recurrent network
257228instance SingI i => Serialize (RecurrentNetwork '[] '[i]) where
@@ -270,23 +241,13 @@ instance (Serialize (RecurrentInputs '[])) where
270241 put _ = return ()
271242 get = return RINil
272243
273−instance (UpdateLayer x, Serialize (RecurrentInputs ys)) => (Serialize (RecurrentInputs (FeedForward x ': ys))) where
244+instance (UpdateLayer x, Serialize (RecurrentInputs ys), Fractional (RecurrentInputs ys)) => (Serialize (RecurrentInputs (FeedForward x ': ys))) where
274245 put ( () :~~+> rest) = put rest
275246 get = ( () :~~+> ) <$> get
276247
277−instance (SingI (RecurrentShape x), RecurrentUpdateLayer x, Serialize (RecurrentInputs ys)) => (Serialize (RecurrentInputs (Recurrent x ': ys))) where
278− put ( i :~@+> rest ) = do
279− _ <- (case i of
280− (S1D x) -> putListOf put . LA.toList . LAS.extract $ x
281− (S2D x) -> putListOf put . LA.toList . LA.flatten . LAS.extract $ x
282− (S3D x) -> putListOf put . LA.toList . LA.flatten . LAS.extract $ x
283− ) :: PutM ()
284− put rest
285−
286− get = do
287− Just i <- fromStorable . V.fromList <$> getListOf get
288− rest <- get
289− return ( i :~@+> rest)
248+instance (Serialize (RecurrentShape x), Fractional (RecurrentShape x), RecurrentUpdateLayer x, Serialize (RecurrentInputs ys), Fractional (RecurrentInputs ys)) => (Serialize (RecurrentInputs (Recurrent x ': ys))) where
249+ put ( i :~@+> rest ) = put i >> put rest
250+ get = (:~@+>) <$> get <*> get
290251
291252
292253-- Num instance for `RecurrentInputs layers`
@@ -307,7 +268,7 @@ instance (Num (RecurrentInputs '[])) where
307268 signum _ = RINil
308269 fromInteger _ = RINil
309270
310−instance (UpdateLayer x, Num (RecurrentInputs ys)) => (Num (RecurrentInputs (FeedForward x ': ys))) where
271+instance (UpdateLayer x, Fractional (RecurrentInputs ys)) => (Num (RecurrentInputs (FeedForward x ': ys))) where
311272 (+) (() :~~+> x) (() :~~+> y) = () :~~+> (x + y)
312273 (-) (() :~~+> x) (() :~~+> y) = () :~~+> (x - y)
313274 (*) (() :~~+> x) (() :~~+> y) = () :~~+> (x * y)
@@ -315,10 +276,51 @@ instance (UpdateLayer x, Num (RecurrentInputs ys)) => (Num (RecurrentInputs (Fee
315276 signum (() :~~+> x) = () :~~+> signum x
316277 fromInteger x = () :~~+> fromInteger x
317278
318−instance (SingI (RecurrentShape x), RecurrentUpdateLayer x, Num (RecurrentInputs ys)) => (Num (RecurrentInputs (Recurrent x ': ys))) where
279+instance (Fractional (RecurrentShape x), RecurrentUpdateLayer x, Fractional (RecurrentInputs ys)) => (Num (RecurrentInputs (Recurrent x ': ys))) where
319280 (+) (x :~@+> x') (y :~@+> y') = (x + y) :~@+> (x' + y')
320281 (-) (x :~@+> x') (y :~@+> y') = (x - y) :~@+> (x' - y')
321282 (*) (x :~@+> x') (y :~@+> y') = (x * y) :~@+> (x' * y')
322283 abs (x :~@+> x') = abs x :~@+> abs x'
323284 signum (x :~@+> x') = signum x :~@+> signum x'
324285 fromInteger x = fromInteger x :~@+> fromInteger x
286+
287+instance (Fractional (RecurrentInputs '[])) where
288+ (/) _ _ = RINil
289+ recip _ = RINil
290+ fromRational _ = RINil
291+
292+instance (UpdateLayer x, Fractional (RecurrentInputs ys)) => (Fractional (RecurrentInputs (FeedForward x ': ys))) where
293+ (/) (() :~~+> x) (() :~~+> y) = () :~~+> (x / y)
294+ recip (() :~~+> x) = () :~~+> recip x
295+ fromRational x = () :~~+> fromRational x
296+
297+instance (Fractional (RecurrentShape x), RecurrentUpdateLayer x, Fractional (RecurrentInputs ys)) => (Fractional (RecurrentInputs (Recurrent x ': ys))) where
298+ (/) (x :~@+> x') (y :~@+> y') = (x / y) :~@+> (x' / y')
299+ recip (x :~@+> x') = recip x :~@+> recip x'
300+ fromRational x = fromRational x :~@+> fromRational x
301+
302+
303+-- | Ultimate composition.
304+--
305+-- This allows a complete network to be treated as a layer in a larger network.
306+instance CreatableRecurrent sublayers subshapes => UpdateLayer (RecurrentNetwork sublayers subshapes) where
307+ type Gradient (RecurrentNetwork sublayers subshapes) = RecurrentGradient sublayers
308+ runUpdate = applyRecurrentUpdate
309+ createRandom = randomRecurrent
310+
311+-- | Ultimate composition.
312+--
313+-- This allows a complete network to be treated as a layer in a larger network.
314+instance CreatableRecurrent sublayers subshapes => RecurrentUpdateLayer (RecurrentNetwork sublayers subshapes) where
315+ type RecurrentShape (RecurrentNetwork sublayers subshapes) = RecurrentInputs sublayers
316+
317+-- | Ultimate composition.
318+--
319+-- This allows a complete network to be treated as a layer in a larger network.
320+instance ( CreatableRecurrent sublayers subshapes
321+ , i ~ (Head subshapes), o ~ (Last subshapes)
322+ , Num (RecurrentShape (RecurrentNetwork sublayers subshapes))
323+ ) => RecurrentLayer (RecurrentNetwork sublayers subshapes) i o where
324+ type RecTape (RecurrentNetwork sublayers subshapes) i o = RecurrentTape sublayers subshapes
325+ runRecurrentForwards = runRecurrent
326+ runRecurrentBackwards = runRecurrent'
src/Grenade/Recurrent/Core/Runner.hs+49−28
@@ -9,30 +9,65 @@
99{-# LANGUAGE RecordWildCards #-}
1010
1111module Grenade.Recurrent.Core.Runner (
12− trainRecurrent
13− , runRecurrent
12+ runRecurrentExamples
13+ , runRecurrentBackprop
1414 , backPropagateRecurrent
15+ , trainRecurrent
16+
17+ , RecurrentGradients
1518 ) where
1619
20+import Data.List ( foldl' )
1721import Data.Singletons.Prelude
1822import Grenade.Core
1923
20−import Grenade.Recurrent.Core.Layer
2124import Grenade.Recurrent.Core.Network
2225
26+type RecurrentGradients layers = [RecurrentGradient layers]
27+
28+runRecurrentExamples :: forall shapes layers.
29+ RecurrentNetwork layers shapes
30+ -> RecurrentInputs layers
31+ -> [S (Head shapes)]
32+ -> ([(RecurrentTape layers shapes, S (Last shapes))], RecurrentInputs layers)
33+runRecurrentExamples net =
34+ go
35+ where
36+ go !side [] = ([], side)
37+ go !side (!x : xs) =
38+ let (!tape, !side', !o) = runRecurrent net side x
39+ (!res, !finalSide) = go side' xs
40+ in (( tape, o ) : res, finalSide)
41+
42+runRecurrentBackprop :: forall layers shapes.
43+ RecurrentNetwork layers shapes
44+ -> RecurrentInputs layers
45+ -> [(RecurrentTape layers shapes, S (Last shapes))]
46+ -> ([(RecurrentGradient layers, S (Head shapes))], RecurrentInputs layers)
47+runRecurrentBackprop net =
48+ go
49+ where
50+ go !side [] = ([], side)
51+ go !side ((!tape,!x):xs) =
52+ let (res, !side') = go side xs
53+ (!grad, !finalSide, !o) = runRecurrent' net tape side' x
54+ in (( grad, o ) : res, finalSide)
55+
56+
2357-- | Drive and network and collect its back propogated gradients.
24−backPropagateRecurrent :: forall shapes layers. (SingI (Last shapes), Num (RecurrentInputs layers))
58+backPropagateRecurrent :: forall shapes layers. (SingI (Last shapes), Fractional (RecurrentInputs layers))
2559 => RecurrentNetwork layers shapes
2660 -> RecurrentInputs layers
2761 -> [(S (Head shapes), Maybe (S (Last shapes)))]
2862 -> (RecurrentGradients layers, RecurrentInputs layers)
2963backPropagateRecurrent network recinputs examples =
30− let (tapes, _, guesses) = runRecurrentNetwork network recinputs inputs
64+ let (outForwards, _) = runRecurrentExamples network recinputs inputs
3165
32− backPropagations = zipWith makeError guesses targets
66+ backPropagations = zipWith makeError outForwards targets
3367
34− (gradients, input', _) = runRecurrentGradient network tapes 0 backPropagations
68+ (outBackwards, input') = runRecurrentBackprop network 0 backPropagations
3569
70+ gradients = fmap fst outBackwards
3671 in (gradients, input')
3772
3873 where
@@ -40,12 +75,12 @@ backPropagateRecurrent network recinputs examples =
4075 inputs = fst <$> examples
4176 targets = snd <$> examples
4277
43− makeError :: S (Last shapes) -> Maybe (S (Last shapes)) -> S (Last shapes)
44− makeError _ Nothing = 0
45− makeError y (Just t) = y - t
78+ makeError :: (x, S (Last shapes)) -> Maybe (S (Last shapes)) -> (x, S (Last shapes))
79+ makeError (x, _) Nothing = (x, 0)
80+ makeError (x, y) (Just t) = (x, y - t)
4681
4782
48−trainRecurrent :: forall shapes layers. (SingI (Last shapes), Num (RecurrentInputs layers))
83+trainRecurrent :: forall shapes layers. (SingI (Last shapes), Fractional (RecurrentInputs layers))
4984 => LearningParameters
5085 -> RecurrentNetwork layers shapes
5186 -> RecurrentInputs layers
@@ -56,11 +91,12 @@ trainRecurrent rate network recinputs examples =
5691
5792 newInputs = updateRecInputs rate recinputs recinputs'
5893
59− newNetwork = applyRecurrentUpdate rate network gradients
94+ newNetwork = foldl' (applyRecurrentUpdate rate) network gradients
6095
6196 in (newNetwork, newInputs)
6297
63−updateRecInputs :: LearningParameters
98+updateRecInputs :: Fractional (RecurrentInputs sublayers)
99+ => LearningParameters
64100 -> RecurrentInputs sublayers
65101 -> RecurrentInputs sublayers
66102 -> RecurrentInputs sublayers
@@ -73,18 +109,3 @@ updateRecInputs l@LearningParameters {..} (x :~@+> xs) (y :~@+> ys)
73109
74110updateRecInputs _ RINil RINil
75111 = RINil
76−
77−-- | Just forwards propagation with no training.
78−runRecurrent :: RecurrentNetwork layers shapes
79− -> RecurrentInputs layers -> S (Head shapes)
80− -> (RecurrentInputs layers, S (Last shapes))
81−runRecurrent (layer :~~> n) (() :~~+> nr) !x
82− = let (_, ys) = runForwards layer x
83− (nr', o) = runRecurrent n nr ys
84− in (() :~~+> nr', o)
85−runRecurrent (layer :~@> n) (recin :~@+> nr) !x
86− = let (_, recin', y) = runRecurrentForwards layer recin x
87− (nr', o) = runRecurrent n nr y
88− in (recin' :~@+> nr', o)
89−runRecurrent RNil RINil !x
90− = (RINil, x)
src/Grenade/Recurrent/Layers.hs+2
@@ -1,7 +1,9 @@
11module Grenade.Recurrent.Layers (
22 module Grenade.Recurrent.Layers.BasicRecurrent
3+ , module Grenade.Recurrent.Layers.ConcatRecurrent
34 , module Grenade.Recurrent.Layers.LSTM
45 ) where
56
67import Grenade.Recurrent.Layers.BasicRecurrent
8+import Grenade.Recurrent.Layers.ConcatRecurrent
79import Grenade.Recurrent.Layers.LSTM
src/Grenade/Recurrent/Layers/BasicRecurrent.hs+1−1
@@ -66,7 +66,7 @@ instance (KnownNat i, KnownNat o, KnownNat (i + o)) => UpdateLayer (BasicRecurre
6666 createRandom = randomBasicRecurrent
6767
6868instance (KnownNat i, KnownNat o, KnownNat (i + o), i <= (i + o), o ~ ((i + o) - i)) => RecurrentUpdateLayer (BasicRecurrent i o) where
69− type RecurrentShape (BasicRecurrent i o) = 'D1 o
69+ type RecurrentShape (BasicRecurrent i o) = S ('D1 o)
7070
7171instance (KnownNat i, KnownNat o, KnownNat (i + o), i <= (i + o), o ~ ((i + o) - i)) => RecurrentLayer (BasicRecurrent i o) ('D1 i) ('D1 o) where
7272
src/Grenade/Recurrent/Layers/ConcatRecurrent.hsnew file+174
@@ -0,0 +1,174 @@
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.Layers.Concat
13+Description : Concatenation layer
14+Copyright : (c) Huw Campbell, 2016-2017
15+License : BSD2
16+Stability : experimental
17+
18+This module provides the concatenation layer, which runs two chilld layers in parallel and combines their outputs.
19+-}
20+module Grenade.Recurrent.Layers.ConcatRecurrent (
21+ ConcatRecurrent (..)
22+ ) where
23+
24+import Data.Serialize
25+
26+import Data.Singletons
27+import GHC.TypeLits
28+
29+import Grenade.Core
30+import Grenade.Recurrent.Core
31+
32+import Numeric.LinearAlgebra.Static ( (#), split, R )
33+
34+-- | A Concatentating Layer.
35+--
36+-- This layer shares it's input state between two sublayers, and concatenates their output.
37+--
38+-- With Networks able to be Layers, this allows for very expressive composition of complex Networks.
39+--
40+-- The Concat layer has a few instances, which allow one to flexibly "bash" together the outputs.
41+--
42+-- Two 1D vectors, can go to a 2D shape with 2 rows if their lengths are identical.
43+-- Any 2 1D vectors can also become a longer 1D Vector.
44+--
45+-- 3D images become 3D images with more channels. The sizes must be the same, one can use Pad
46+-- and Crop layers to ensure this is the case.
47+data ConcatRecurrent :: Shape -> * -> Shape -> * -> * where
48+ ConcatRecLeft :: x -> y -> ConcatRecurrent m (Recurrent x) n (FeedForward y)
49+ ConcatRecRight :: x -> y -> ConcatRecurrent m (FeedForward x) n (Recurrent y)
50+ ConcatRecBoth :: x -> y -> ConcatRecurrent m (Recurrent x) n (Recurrent y)
51+
52+instance (Show x, Show y) => Show (ConcatRecurrent m (p x) n (q y)) where
53+ show (ConcatRecLeft x y) = "ConcatRecLeft\n" ++ show x ++ "\n" ++ show y
54+ show (ConcatRecRight x y) = "ConcatRecRight\n" ++ show x ++ "\n" ++ show y
55+ show (ConcatRecBoth x y) = "ConcatRecBoth\n" ++ show x ++ "\n" ++ show y
56+
57+instance (RecurrentUpdateLayer x, UpdateLayer y) => UpdateLayer (ConcatRecurrent m (Recurrent x) n (FeedForward y)) where
58+ type Gradient (ConcatRecurrent m (Recurrent x) n (FeedForward y)) = (Gradient x, Gradient y)
59+ runUpdate lr (ConcatRecLeft x y) (x', y')
60+ = ConcatRecLeft (runUpdate lr x x') (runUpdate lr y y')
61+ createRandom
62+ = ConcatRecLeft <$> createRandom <*> createRandom
63+
64+instance (UpdateLayer x, RecurrentUpdateLayer y) => UpdateLayer (ConcatRecurrent m (FeedForward x) n (Recurrent y)) where
65+ type Gradient (ConcatRecurrent m (FeedForward x) n (Recurrent y)) = (Gradient x, Gradient y)
66+ runUpdate lr (ConcatRecRight x y) (x', y')
67+ = ConcatRecRight (runUpdate lr x x') (runUpdate lr y y')
68+ createRandom
69+ = ConcatRecRight <$> createRandom <*> createRandom
70+
71+instance (RecurrentUpdateLayer x, RecurrentUpdateLayer y) => UpdateLayer (ConcatRecurrent m (Recurrent x) n (Recurrent y)) where
72+ type Gradient (ConcatRecurrent m (Recurrent x) n (Recurrent y)) = (Gradient x, Gradient y)
73+ runUpdate lr (ConcatRecBoth x y) (x', y')
74+ = ConcatRecBoth (runUpdate lr x x') (runUpdate lr y y')
75+ createRandom
76+ = ConcatRecBoth <$> createRandom <*> createRandom
77+
78+instance (RecurrentUpdateLayer x, UpdateLayer y) => RecurrentUpdateLayer (ConcatRecurrent m (Recurrent x) n (FeedForward y)) where
79+ type RecurrentShape (ConcatRecurrent m (Recurrent x) n (FeedForward y)) = RecurrentShape x
80+
81+instance (UpdateLayer x, RecurrentUpdateLayer y) => RecurrentUpdateLayer (ConcatRecurrent m (FeedForward x) n (Recurrent y)) where
82+ type RecurrentShape (ConcatRecurrent m (FeedForward x) n (Recurrent y)) = RecurrentShape y
83+
84+instance (RecurrentUpdateLayer x, RecurrentUpdateLayer y) => RecurrentUpdateLayer (ConcatRecurrent m (Recurrent x) n (Recurrent y)) where
85+ type RecurrentShape (ConcatRecurrent m (Recurrent x) n (Recurrent y)) = RecurrentInputs '[ Recurrent x, Recurrent y ]
86+
87+instance ( SingI i
88+ , Layer x i ('D1 m)
89+ , RecurrentLayer y i ('D1 n)
90+ , KnownNat o
91+ , KnownNat m
92+ , KnownNat n
93+ , o ~ (m + n)
94+ , n ~ (o - m)
95+ , (m <=? o) ~ 'True
96+ ) => RecurrentLayer (ConcatRecurrent ('D1 m) (FeedForward x) ('D1 n) (Recurrent y)) i ('D1 o) where
97+ type RecTape (ConcatRecurrent ('D1 m) (FeedForward x) ('D1 n) (Recurrent y)) i ('D1 o) = (Tape x i ('D1 m), RecTape y i ('D1 n))
98+
99+ runRecurrentForwards (ConcatRecRight x y) s input =
100+ let (xT, xOut :: S ('D1 m)) = runForwards x input
101+ (yT, side, yOut :: S ('D1 n)) = runRecurrentForwards y s input
102+ in case (xOut, yOut) of
103+ (S1D xOut', S1D yOut') ->
104+ ((xT, yT), side, S1D (xOut' # yOut'))
105+
106+ runRecurrentBackwards (ConcatRecRight x y) (xTape, yTape) s (S1D o) =
107+ let (ox :: R m , oy :: R n) = split o
108+ (x', xB :: S i) = runBackwards x xTape (S1D ox)
109+ (y', side, yB :: S i) = runRecurrentBackwards y yTape s (S1D oy)
110+ in ((x', y'), side, xB + yB)
111+
112+instance ( SingI i
113+ , RecurrentLayer x i ('D1 m)
114+ , Layer y i ('D1 n)
115+ , KnownNat o
116+ , KnownNat m
117+ , KnownNat n
118+ , o ~ (m + n)
119+ , n ~ (o - m)
120+ , (m <=? o) ~ 'True
121+ ) => RecurrentLayer (ConcatRecurrent ('D1 m) (Recurrent x) ('D1 n) (FeedForward y)) i ('D1 o) where
122+ type RecTape (ConcatRecurrent ('D1 m) (Recurrent x) ('D1 n) (FeedForward y)) i ('D1 o) = (RecTape x i ('D1 m), Tape y i ('D1 n))
123+
124+ runRecurrentForwards (ConcatRecLeft x y) s input =
125+ let (xT, side, xOut :: S ('D1 m)) = runRecurrentForwards x s input
126+ (yT, yOut :: S ('D1 n)) = runForwards y input
127+ in case (xOut, yOut) of
128+ (S1D xOut', S1D yOut') ->
129+ ((xT, yT), side, S1D (xOut' # yOut'))
130+
131+ runRecurrentBackwards (ConcatRecLeft x y) (xTape, yTape) s (S1D o) =
132+ let (ox :: R m , oy :: R n) = split o
133+ (x', side, xB :: S i) = runRecurrentBackwards x xTape s (S1D ox)
134+ (y', yB :: S i) = runBackwards y yTape (S1D oy)
135+ in ((x', y'), side, xB + yB)
136+
137+instance ( SingI i
138+ , RecurrentLayer x i ('D1 m)
139+ , RecurrentLayer y i ('D1 n)
140+ , Fractional (RecurrentShape x)
141+ , Fractional (RecurrentShape y)
142+ , KnownNat o
143+ , KnownNat m
144+ , KnownNat n
145+ , o ~ (m + n)
146+ , n ~ (o - m)
147+ , (m <=? o) ~ 'True
148+ ) => RecurrentLayer (ConcatRecurrent ('D1 m) (Recurrent x) ('D1 n) (Recurrent y)) i ('D1 o) where
149+ type RecTape (ConcatRecurrent ('D1 m) (Recurrent x) ('D1 n) (Recurrent y)) i ('D1 o) = (RecTape x i ('D1 m), RecTape y i ('D1 n))
150+
151+ runRecurrentForwards (ConcatRecBoth x y) (sx :~@+> (sy :~@+> RINil)) input =
152+ let (xT, s'x, xOut :: S ('D1 m)) = runRecurrentForwards x sx input
153+ (yT, s'y, yOut :: S ('D1 n)) = runRecurrentForwards y sy input
154+ in case (xOut, yOut) of
155+ (S1D xOut', S1D yOut') ->
156+ ((xT, yT), (s'x :~@+> (s'y :~@+> RINil)), S1D (xOut' # yOut'))
157+
158+ runRecurrentBackwards (ConcatRecBoth x y) (xTape, yTape) (sx :~@+> (sy :~@+> RINil)) (S1D o) =
159+ let (ox :: R m , oy :: R n) = split o
160+ (x', s'x, xB :: S i) = runRecurrentBackwards x xTape sx (S1D ox)
161+ (y', s'y, yB :: S i) = runRecurrentBackwards y yTape sy (S1D oy)
162+ in ((x', y'), (s'x :~@+> (s'y :~@+> RINil)), xB + yB)
163+
164+instance (Serialize a, Serialize b) => Serialize (ConcatRecurrent sa (FeedForward a) sb (Recurrent b)) where
165+ put (ConcatRecRight a b) = put a *> put b
166+ get = ConcatRecRight <$> get <*> get
167+
168+instance (Serialize a, Serialize b) => Serialize (ConcatRecurrent sa (Recurrent a) sb (Recurrent b)) where
169+ put (ConcatRecBoth a b) = put a *> put b
170+ get = ConcatRecBoth <$> get <*> get
171+
172+instance (Serialize a, Serialize b) => Serialize (ConcatRecurrent sa (Recurrent a) sb (FeedForward b)) where
173+ put (ConcatRecLeft a b) = put a *> put b
174+ get = ConcatRecLeft <$> get <*> get
src/Grenade/Recurrent/Layers/LSTM.hs+1−1
@@ -123,7 +123,7 @@ instance (KnownNat i, KnownNat o) => UpdateLayer (LSTM i o) where
123123instance (KnownNat i, KnownNat o) => RecurrentUpdateLayer (LSTM i o) where
124124 -- The recurrent shape is the same size as the output.
125125 -- It's actually the cell state however, as this is a peephole variety LSTM.
126− type RecurrentShape (LSTM i o) = 'D1 o
126+ type RecurrentShape (LSTM i o) = S ('D1 o)
127127
128128instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) where
129129