@@ -127,37 +127,12 @@ instance (KnownNat i, KnownNat o) => RecurrentUpdateLayer (LSTM i o) where
127127
128128instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) where
129129
130− type RecTape (LSTM i o) ('D1 i) ('D1 o) = (S ('D1 o), S ('D1 i))
130+ -- The tape stores essentially every variable we calculate,
131+ -- so we don't have to run any forwards component again.
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)
131133 -- Forward propagation for the LSTM layer.
132134 -- The size of the cell state is also the size of the output.
133135 runRecurrentForwards (LSTM (LSTMWeights {..}) _) (S1D cell) (S1D input) =
134− let -- Forget state vector
135− f_t = sigmoid $ lstmBf + lstmWf #> input + lstmUf #> cell
136− -- Input state vector
137− i_t = sigmoid $ lstmBi + lstmWi #> input + lstmUi #> cell
138− -- Output state vector
139− o_t = sigmoid $ lstmBo + lstmWo #> input + lstmUo #> cell
140− -- Cell input state vector
141− c_x = tanh $ lstmBc + lstmWc #> input
142− -- Cell state
143− c_t = f_t * cell + i_t * c_x
144− -- Output (it's sometimes recommended to use tanh c_t)
145− h_t = o_t * c_t
146− in ((S1D cell, S1D input), S1D c_t, S1D h_t)
147−
148− -- Run a backpropogation step for an LSTM layer.
149− -- We're doing all the derivatives by hand here, so one should
150− -- be extra careful when changing this.
151− --
152− -- There's a test version using the AD library without hmatrix in the test
153− -- suite. These should match always.
154− runRecurrentBackwards (LSTM (LSTMWeights {..}) _) (S1D cell, S1D input) (S1D cellGrad) (S1D h_t') =
155− -- We're not keeping the Wengert tape during the forward pass,
156− -- so we're duplicating some work here.
157− --
158− -- If I was being generous, I'd call it checkpointing.
159− --
160− -- Maybe think about better ways to store some intermediate states.
161136 let -- Forget state vector
162137 f_s = lstmBf + lstmWf #> input + lstmUf #> cell
163138 f_t = sigmoid f_s
@@ -172,8 +147,18 @@ instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) w
172147 c_x = tanh c_s
173148 -- Cell state
174149 c_t = f_t * cell + i_t * c_x
150+ -- Output (it's sometimes recommended to use tanh c_t)
151+ h_t = o_t * c_t
152+ in ((cell, input, f_s, f_t, i_s, i_t, o_s, o_t, c_s, c_x, c_t), S1D c_t, S1D h_t)
175153
176− -- Reverse Mode AD Derivitives
154+ -- Run a backpropogation step for an LSTM layer.
155+ -- We're doing all the derivatives by hand here, so one should
156+ -- be extra careful when changing this.
157+ --
158+ -- There's a test version using the AD library without hmatrix in the test
159+ -- suite. These should match always.
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') =
161+ let -- Reverse Mode AD Derivitives
177162 c_t' = h_t' * o_t + cellGrad
178163
179164 f_t' = c_t' * cell
@@ -235,7 +220,8 @@ randomLSTM = do
235220
236221-- | Maths
237222--
238−-- TODO: move to not here
223+-- TODO: Move to not here
224+-- Optimise backwards derivative
239225sigmoid :: Floating a => a -> a
240226sigmoid x = 1 / (1 + exp (-x))
241227