@@ -1,8 +1,8 @@
2{-# LANGUAGE BangPatterns #-}
1{-# LANGUAGE BangPatterns #-}
3{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DataKinds #-}
4{-# LANGUAGE GADTs #-}
3{-# LANGUAGE GADTs #-}
5{-# LANGUAGE RankNTypes #-}
4{-# LANGUAGE RankNTypes #-}
5+{-# LANGUAGE RecordWildCards #-}
6{-# LANGUAGE TypeOperators #-}
6{-# LANGUAGE TypeOperators #-}
7{-# LANGUAGE TypeFamilies #-}
7{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
@@ -21,7 +21,7 @@ import Control.Monad.Random ( MonadRandom, getRandom )
21-- import Data.List ( foldl1' )
21-- import Data.List ( foldl1' )
22import Data.Proxy
22import Data.Proxy
23import Data.Serialize
23import Data.Serialize
24−import Data.Kind (Type)
24+import Data.Singletons.TypeLits
26import qualified Numeric.LinearAlgebra as LA
26import qualified Numeric.LinearAlgebra as LA
27import Numeric.LinearAlgebra.Static
27import Numeric.LinearAlgebra.Static
@@ -29,7 +29,6 @@ import Numeric.LinearAlgebra.Static
29import Grenade.Core
29import Grenade.Core
30import Grenade.Recurrent.Core
30import Grenade.Recurrent.Core
31import Grenade.Layers.Internal.Update
31import Grenade.Layers.Internal.Update
35-- | Long Short Term Memory Recurrent unit
34-- | Long Short Term Memory Recurrent unit
@@ -37,14 +36,14 @@ import GHC.TypeLits
37-- This is a Peephole formulation, so the recurrent shape is
36-- This is a Peephole formulation, so the recurrent shape is
38-- just the cell state, the previous output is not held or used
37-- just the cell state, the previous output is not held or used
40−data LSTM :: Nat -> Nat -> Type where
39+data LSTM :: Nat -> Nat -> * where
41 LSTM :: ( KnownNat input
40 LSTM :: ( KnownNat input
42 , KnownNat output
41 , KnownNat output
43 ) => !(LSTMWeights input output) -- Weights
42 ) => !(LSTMWeights input output) -- Weights
44 -> !(LSTMWeights input output) -- Momentums
43 -> !(LSTMWeights input output) -- Momentums
45 -> LSTM input output
44 -> LSTM input output
47−data LSTMWeights :: Nat -> Nat -> Type where
46+data LSTMWeights :: Nat -> Nat -> * where
48 LSTMWeights :: ( KnownNat input
47 LSTMWeights :: ( KnownNat input
49 , KnownNat output
48 , KnownNat output
@@ -71,7 +70,7 @@ instance (KnownNat i, KnownNat o) => UpdateLayer (LSTM i o) where
72 -- Run the update function for each group matrix/vector of weights, momentums and gradients.
71 -- Run the update function for each group matrix/vector of weights, momentums and gradients.
73 -- Hmm, maybe the function should be used instead of passing in the learning parameters.
72 -- Hmm, maybe the function should be used instead of passing in the learning parameters.
74− runUpdate lp (LSTM w m) g =
73+ runUpdate LearningParameters {..} (LSTM w m) g =
75 let (wf, wf') = u lstmWf w m g
74 let (wf, wf') = u lstmWf w m g
76 (uf, uf') = u lstmUf w m g
75 (uf, uf') = u lstmUf w m g
77 (bf, bf') = v lstmBf w m g
76 (bf, bf') = v lstmBf w m g
@@ -88,11 +87,11 @@ instance (KnownNat i, KnownNat o) => UpdateLayer (LSTM i o) where
88 -- Utility function for updating with the momentum, gradients, and weights.
87 -- Utility function for updating with the momentum, gradients, and weights.
89 u :: forall x ix out. (KnownNat ix, KnownNat out) => (x -> (L out ix)) -> x -> x -> x -> ((L out ix), (L out ix))
88 u :: forall x ix out. (KnownNat ix, KnownNat out) => (x -> (L out ix)) -> x -> x -> x -> ((L out ix), (L out ix))
90 u e (e -> weights) (e -> momentum) (e -> gradient) =
89 u e (e -> weights) (e -> momentum) (e -> gradient) =
91− descendMatrix (learningRate lp) (learningMomentum lp) (learningRegulariser lp) weights gradient momentum
90+ descendMatrix learningRate learningMomentum learningRegulariser weights gradient momentum
93 v :: forall x ix. (KnownNat ix) => (x -> (R ix)) -> x -> x -> x -> ((R ix), (R ix))
92 v :: forall x ix. (KnownNat ix) => (x -> (R ix)) -> x -> x -> x -> ((R ix), (R ix))
94 v e (e -> weights) (e -> momentum) (e -> gradient) =
93 v e (e -> weights) (e -> momentum) (e -> gradient) =
95− descendVector (learningRate lp) (learningMomentum lp) (learningRegulariser lp) weights gradient momentum
94+ descendVector learningRate learningMomentum learningRegulariser weights gradient momentum
97 -- There's a lot of updates here, so to try and minimise the number of data copies
96 -- There's a lot of updates here, so to try and minimise the number of data copies
98 -- we'll create a mutable bucket for each.
97 -- we'll create a mutable bucket for each.
@@ -133,18 +132,18 @@ instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) w
133 type RecTape (LSTM i o) ('D1 i) ('D1 o) = (R o, R i, R o, R o, R o, R o, R o, R o, R o, R o, R o)
132 type RecTape (LSTM i o) ('D1 i) ('D1 o) = (R o, R i, R o, R o, R o, R o, R o, R o, R o, R o, R o)
134 -- Forward propagation for the LSTM layer.
133 -- Forward propagation for the LSTM layer.
135 -- The size of the cell state is also the size of the output.
134 -- The size of the cell state is also the size of the output.
136− runRecurrentForwards (LSTM lw _) (S1D cell) (S1D input) =
135+ runRecurrentForwards (LSTM (LSTMWeights {..}) _) (S1D cell) (S1D input) =
137 let -- Forget state vector
136 let -- Forget state vector
138− f_s = lstmBf lw + lstmWf lw #> input + lstmUf lw #> cell
137+ f_s = lstmBf + lstmWf #> input + lstmUf #> cell
139 f_t = sigmoid f_s
138 f_t = sigmoid f_s
140 -- Input state vector
139 -- Input state vector
141− i_s = lstmBi lw + lstmWi lw #> input + lstmUi lw #> cell
140+ i_s = lstmBi + lstmWi #> input + lstmUi #> cell
142 i_t = sigmoid i_s
141 i_t = sigmoid i_s
143 -- Output state vector
142 -- Output state vector
144− o_s = lstmBo lw + lstmWo lw #> input + lstmUo lw #> cell
143+ o_s = lstmBo + lstmWo #> input + lstmUo #> cell
145 o_t = sigmoid o_s
144 o_t = sigmoid o_s
146 -- Cell input state vector
145 -- Cell input state vector
147− c_s = lstmBc lw + lstmWc lw #> input
146+ c_s = lstmBc + lstmWc #> input
148 c_x = tanh c_s
147 c_x = tanh c_s
149 -- Cell state
148 -- Cell state
150 c_t = f_t * cell + i_t * c_x
149 c_t = f_t * cell + i_t * c_x
@@ -158,7 +157,7 @@ instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) w
159 -- There's a test version using the AD library without hmatrix in the test
158 -- There's a test version using the AD library without hmatrix in the test
160 -- suite. These should match always.
159 -- suite. These should match always.
161− runRecurrentBackwards (LSTM lw _) (cell, input, f_s, f_t, i_s, i_t, o_s, o_t, c_s, c_x, c_t) (S1D cellGrad) (S1D h_t') =
160+ runRecurrentBackwards (LSTM (LSTMWeights {..}) _) (cell, input, f_s, f_t, i_s, i_t, o_s, o_t, c_s, c_x, c_t) (S1D cellGrad) (S1D h_t') =
162 let -- Reverse Mode AD Derivitives
161 let -- Reverse Mode AD Derivitives
163 c_t' = h_t' * o_t + cellGrad
162 c_t' = h_t' * o_t + cellGrad
@@ -175,8 +174,8 @@ instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) w
175 c_s' = tanh' c_s * c_x'
174 c_s' = tanh' c_s * c_x'
177 -- The derivatives to pass sideways (recurrent) and downwards
176 -- The derivatives to pass sideways (recurrent) and downwards
178− cell' = tr (lstmUf lw) #> f_s' + tr (lstmUo lw) #> o_s' + tr (lstmUi lw) #> i_s' + c_t' * f_t
177+ cell' = tr lstmUf #> f_s' + tr lstmUo #> o_s' + tr lstmUi #> i_s' + c_t' * f_t
179− input' = tr (lstmWf lw) #> f_s' + tr (lstmWo lw) #> o_s' + tr (lstmWi lw) #> i_s' + tr (lstmWc lw) #> c_s'
178+ input' = tr lstmWf #> f_s' + tr lstmWo #> o_s' + tr lstmWi #> i_s' + tr lstmWc #> c_s'
181 -- Calculate the gradient Matricies for the input
180 -- Calculate the gradient Matricies for the input
182 lstmWf' = f_s' `outer` input
181 lstmWf' = f_s' `outer` input
@@ -235,34 +234,44 @@ tanh' :: (Floating a) => a -> a
235tanh' t = 1 - s ^ (2 :: Int) where s = tanh t
234tanh' t = 1 - s ^ (2 :: Int) where s = tanh t
237instance (KnownNat i, KnownNat o) => Serialize (LSTM i o) where
236instance (KnownNat i, KnownNat o) => Serialize (LSTM i o) where
238− put (LSTM lw _) = do
237+ put (LSTM LSTMWeights {..} _) = do
239− u (lstmWf lw)
238+ u lstmWf
240− u (lstmUf lw)
239+ u lstmUf
241− v (lstmBf lw)
240+ v lstmBf
242− u (lstmWi lw)
241+ u lstmWi
243− u (lstmUi lw)
242+ u lstmUi
244− v (lstmBi lw)
243+ v lstmBi
245− u (lstmWo lw)
244+ u lstmWo
246− u (lstmUo lw)
245+ u lstmUo
247− v (lstmBo lw)
246+ v lstmBo
248− u (lstmWc lw)
247+ u lstmWc
249− v (lstmBc lw)
248+ v lstmBc
251− u :: forall a b. (KnownNat a, KnownNat b) => Putter (L b a)
250+ u :: forall a b. (KnownNat a, KnownNat b) => Putter (L b a)
252− u = putListOf put . LA.toList . LA.flatten . extract
251+ u = putListOf put . LA.toList . LA.flatten . extract
253− v :: forall a. (KnownNat a) => Putter (R a)
252+ v :: forall a. (KnownNat a) => Putter (R a)
254− v = putListOf put . LA.toList . extract
253+ v = putListOf put . LA.toList . extract
257− w <- LSTMWeights <$> u <*> u <*> v <*> u <*> u <*> v <*> u <*> u <*> v <*> u <*> v
256+ lstmWf <- u
258− return $ LSTM w (LSTMWeights w0 u0 v0 w0 u0 v0 w0 u0 v0 w0 v0)
267+ return $ LSTM (LSTMWeights {..}) (LSTMWeights w0 u0 v0 w0 u0 v0 w0 u0 v0 w0 v0)
260− u :: forall a b. (KnownNat a, KnownNat b) => Get (L b a)
269+ u :: forall a b. (KnownNat a, KnownNat b) => Get (L b a)
261− u = let f = fromIntegral $ natVal (Proxy :: Proxy a)
270+ u = let f = fromIntegral $ natVal (Proxy :: Proxy a)
262− in maybe (fail "Vector of incorrect size") return . create . LA.reshape f . LA.fromList =<< getListOf get
271+ in maybe (fail "Vector of incorrect size") return . create . LA.reshape f . LA.fromList =<< getListOf get
263− v :: forall a. (KnownNat a) => Get (R a)
272+ v :: forall a. (KnownNat a) => Get (R a)
264− v = maybe (fail "Vector of incorrect size") return . create . LA.fromList =<< getListOf get
273+ v = maybe (fail "Vector of incorrect size") return . create . LA.fromList =<< getListOf get
266− w0 = konst 0
275+ w0 = konst 0
267− u0 = konst 0
276+ u0 = konst 0
268− v0 = konst 0
277+ v0 = konst 0