@@ -127,37 +127,12 @@ instance (KnownNat i, KnownNat o) => RecurrentUpdateLayer (LSTM i o) where
128instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) where
128instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) where
130+ -- The tape stores essentially every variable we calculate,
131+ -- so we don't have to run any forwards component again.
130− type RecTape (LSTM i o) ('D1 i) ('D1 o) = (S ('D1 o), S ('D1 i))
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)
131 -- Forward propagation for the LSTM layer.
133 -- Forward propagation for the LSTM layer.
132 -- 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.
133 runRecurrentForwards (LSTM (LSTMWeights {..}) _) (S1D cell) (S1D input) =
135 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
143− c_t = f_t * cell + i_t * c_x
144− -- Output (it's sometimes recommended to use tanh c_t)
146− in ((S1D cell, S1D input), S1D c_t, S1D h_t)
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.
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.
158− -- If I was being generous, I'd call it checkpointing.
160− -- Maybe think about better ways to store some intermediate states.
161 let -- Forget state vector
136 let -- Forget state vector
162 f_s = lstmBf + lstmWf #> input + lstmUf #> cell
137 f_s = lstmBf + lstmWf #> input + lstmUf #> cell
163 f_t = sigmoid f_s
138 f_t = sigmoid f_s
@@ -172,8 +147,18 @@ instance (KnownNat i, KnownNat o) => RecurrentLayer (LSTM i o) ('D1 i) ('D1 o) w
172 c_x = tanh c_s
147 c_x = tanh c_s
173 -- Cell state
148 -- Cell state
174 c_t = f_t * cell + i_t * c_x
149 c_t = f_t * cell + i_t * c_x
150+ -- Output (it's sometimes recommended to use tanh 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)
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.
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') =
176− -- Reverse Mode AD Derivitives
161+ let -- Reverse Mode AD Derivitives
177 c_t' = h_t' * o_t + cellGrad
162 c_t' = h_t' * o_t + cellGrad
179 f_t' = c_t' * cell
164 f_t' = c_t' * cell
@@ -235,7 +220,8 @@ randomLSTM = do
236-- | Maths
221-- | Maths
238−-- TODO: move to not here
223+-- TODO: Move to not here
224+-- Optimise backwards derivative
239sigmoid :: Floating a => a -> a
225sigmoid :: Floating a => a -> a
240sigmoid x = 1 / (1 + exp (-x))
226sigmoid x = 1 / (1 + exp (-x))