Abhinaash Blog

Article thumbnail.

Long Short-Term Memory, from First Principles

plain RNN $|f'w|^q$LSTM cell state $f^q$  ·  after 100 steps:
How much of an error signal survives after travelling $q$ steps back in time (log scale). Move the sliders: the RNN curve collapses unless the factor sits at exactly $1$, which is the whole idea behind LSTM.

1. The sequence problem

A feed-forward network computes a static map $y = F(x)$. Many problems are not static: the right output at time $t$ depends on inputs seen at $t-1, t-2, \dots, t-1000$. Speech, handwriting, price series and text all have this shape. To model them we need a dynamic classifier, one with state that carries information forward.

Recurrent networks provide that state. In practice, however, a plain RNN trained by gradient descent can only exploit dependencies spanning roughly 5 to 10 steps. LSTM was designed to push that horizon beyond 1,000 steps. To see why it works, we first need to see precisely why the plain RNN fails.

2. RNNs and backpropagation through time

Take a fully recurrent network with non-input units $U$ and input units $I$. Each unit $u$ has activation function $f_u$, and $W_{[u,v]}$ is the weight from $v$ to $u$. The forward dynamics are

$$ z_u(\tau+1) = \sum_{v\in U} W_{[u,v]}\, y_v(\tau) + \sum_{i\in I} W_{[u,i]}\, y_i(\tau+1), \qquad y_u(\tau) = f_u\big(z_u(\tau)\big). $$

Over an epoch $[t', t]$ we minimise the summed squared error

$$ E_{\text{total}}(t',t) = \sum_{\tau=t'}^{t} E(\tau),\qquad E(\tau) = \tfrac12 \sum_{u\in U} e_u(\tau)^2,\qquad e_u(\tau) = \begin{cases} d_u(\tau) - y_u(\tau) & u \text{ has a target at } \tau\\ 0 & \text{otherwise.}\end{cases} $$

Backpropagation through time (BPTT) unrolls the network into a deep feed-forward net with one layer per time step and shared weights. The error signal $\vartheta_u(\tau)$ obeys the backward recursion

$$ \vartheta_u(\tau) = \begin{cases} f_u'\big(z_u(\tau)\big)\, e_u(\tau) & \tau = t,\\[4pt] f_u'\big(z_u(\tau)\big) \Big( e_u(\tau) + \sum_{k\in U} W_{[k,u]}\, \vartheta_k(\tau+1) \Big) & t' \le \tau < t, \end{cases} $$

and because weights are shared, their gradient is the sum over time:

$$ \frac{\partial E_{\text{total}}}{\partial W_{[u,v]}} = -\sum_{\tau=t'}^{t} \vartheta_u(\tau)\, y_v(\tau-1). $$

Real-time recurrent learning (RTRL) computes the same gradient forwards instead, by carrying sensitivities $p^k_{uv}(\tau) = \partial y_k(\tau)/\partial W_{[u,v]}$:

$$ p^k_{uv}(\tau+1) = f_k'\big(z_k(\tau+1)\big)\Big[\delta_{uk}\, y_v(\tau) + \sum_{l\in U} W_{[k,l]}\, p^l_{uv}(\tau)\Big],\qquad p^k_{uv}(t')=0. $$

BPTT needs memory proportional to sequence length; RTRL needs no history but costs $O(n^4)$ per step for $n$ units. The original LSTM uses a hybrid of the two, as we will see.

3. Why gradients vanish or explode

Hochreiter's 1991 analysis asks: if an error appears at unit $u$ at time $t$, how much of it reaches unit $v$ at time $t-q$? Differentiating the recursion above gives

$$ \frac{\partial \vartheta_v(t-q)}{\partial \vartheta_u(t)} = \begin{cases} f_v'\big(\text{net}_v(t-1)\big)\, w_{uv} & q=1,\\[4pt] f_v'\big(\text{net}_v(t-q)\big) \displaystyle\sum_{l=1}^{n} \frac{\partial \vartheta_l(t-q+1)}{\partial \vartheta_u(t)}\, w_{lv} & q>1. \end{cases} $$

Unrolling this by induction, with $l_0 = u$ and $l_q = v$:

$$ \boxed{\; \frac{\partial \vartheta_v(t-q)}{\partial \vartheta_u(t)} = \sum_{l_1=1}^{n}\cdots\sum_{l_{q-1}=1}^{n}\;\prod_{m=1}^{q} f'_{l_m}\big(\text{net}_{l_m}(t-m)\big)\, w_{l_m l_{m-1}} \;} $$

This is a sum of $n^{q-1}$ paths, each a product of $q$ factors of the form $f'\cdot w$. The consequence is immediate:

The sigmoid makes vanishing the default

For the logistic sigmoid $\sigma(x) = 1/(1+e^{-x})$ we have $\sigma'(x) = \sigma(x)(1-\sigma(x)) \le \tfrac14$. So $|f' w| < 1$ whenever $|w| < 4$, which covers nearly every weight at initialisation. Making weights larger does not help: for fixed input $y$, $|\sigma'(wy)\,w| \to 0$ as $|w|\to\infty$, because the derivative decays exponentially while the weight grows only linearly. Raising the learning rate does not help either, since it scales long- and short-range gradients equally.

A matrix bound

In matrix form, with $F'(t-m)$ the diagonal matrix of derivatives, the path sum equals

$$ (W_{u^T})^{\!T}\, F'(t-1) \prod_{m=2}^{q-1}\big(W F'(t-m)\big)\, W_v\, f_v'\big(\text{net}_v(t-q)\big). $$

Using the max-row-sum norm $\|W\|_A = \max_r \sum_s |w_{rs}|$ and $f'_{\max} = \max_m \|F'(t-m)\|_A = \tfrac14$, one obtains

$$ \left|\frac{\partial \vartheta_v(t-q)}{\partial \vartheta_u(t)}\right| \le n\big(f'_{\max}\,\|W\|_A\big)^q . $$

If every $|w_{ij}| \le w_{\max} < 4/n$, set $\rho = n w_{\max}/4 < 1$ and the bound becomes $n\rho^q$: guaranteed exponential decay. Summing over all output units shows that global error flow vanishes too. The same conclusion was reached independently by Bengio, Simard and Frasconi (1994).

4. The constant error carousel

The analysis tells us exactly what to demand. Consider a single unit $j$ with a self-connection $w_{jj}$. Its local backflow is

$$ \vartheta_j(t) = f_j'\big(\text{net}_j(t)\big)\, w_{jj}\, \vartheta_j(t+1). $$

For the error to neither shrink nor grow we need

$$ f_j'\big(\text{net}_j(t)\big)\, w_{jj} = 1 . $$

Integrating this differential equation gives $f_j(\text{net}_j) = \text{net}_j / w_{jj}$, so $f_j$ must be linear, and the activation must stay constant:

$$ y_j(t+1) = f_j\big(w_{jj}\, y_j(t)\big) = y_j(t). $$

The simplest choice is $f_j = \mathrm{id}$ and $w_{jj} = 1$. This linear, self-connected unit is the constant error carousel (CEC), and it is the heart of LSTM: an error that enters it circulates unchanged for any number of steps.

Why the naive CEC is not enough

The unit is also connected to the rest of the network, and this creates two conflicts.

Input weight conflict. A single incoming weight $w_{ji}$ must both write relevant inputs into $j$ and ignore irrelevant ones later. It receives contradictory updates.

Output weight conflict. A single outgoing weight $w_{kj}$ must both read $j$'s content when useful and shield unit $k$ from it otherwise. Again, contradictory updates.

Both conflicts worsen as time lags grow, because stored information must be protected for longer. The remedy is to make reading and writing context-dependent.

5. Gates: the 1997 memory cell

LSTM wraps the CEC with two multiplicative gate units. An input gate $\text{in}_j$ decides when to write; an output gate $\text{out}_j$ decides when to read. The result is the memory cell $c_j$.

With all net inputs computed from the previous step's activations,

$$ \begin{aligned} y^{\text{in}_j}(t) &= f_{\text{in}_j}\Big(\sum_u w_{\text{in}_j u}\, y^u(t-1)\Big), & y^{\text{out}_j}(t) &= f_{\text{out}_j}\Big(\sum_u w_{\text{out}_j u}\, y^u(t-1)\Big),\\ \text{net}_{c_j}(t) &= \sum_u w_{c_j u}\, y^u(t-1), & & \end{aligned} $$

the cell updates its internal state and output as

$$ \boxed{\; s_{c_j}(0)=0,\qquad s_{c_j}(t) = s_{c_j}(t-1) + y^{\text{in}_j}(t)\; g\big(\text{net}_{c_j}(t)\big),\qquad y^{c_j}(t) = y^{\text{out}_j}(t)\; h\big(s_{c_j}(t)\big). \;} $$

The self-connection has weight exactly $1$, so the CEC is intact. The squashing functions used in the paper are

$$ f(x) = \frac{1}{1+e^{-x}}\in[0,1],\qquad g(x) = \frac{4}{1+e^{-x}} - 2\in[-2,2],\qquad h(x) = \frac{2}{1+e^{-x}} - 1\in[-1,1]. $$
g × + s h × in gate out gate weight 1.0 constant error carousel net_c y_c
The original memory cell. The input gate scales what is written into the linear self-loop; the output gate scales what is read out. There is no forget gate yet.

A memory cell block of size $S$ is a group of $S$ cells sharing one input gate and one output gate. It stores distributed information at the cost of only two gate units.

How gates resolve the conflicts

The input gate controls error flow into the cell's input weights $w_{c_j i}$, so writing happens only when $y^{\text{in}_j}\approx 1$. The output gate controls error flow out of the cell, so the cell disturbs the rest of the network only when $y^{\text{out}_j}\approx 1$. Errors trapped inside the CEC cannot change; the gates learn which errors to let in and when to release them.

6. Truncated learning and exact error flow

The 1997 algorithm deliberately cuts gradient paths that leave a cell. It sets

$$ \frac{\partial\, \text{net}_{\text{in}_j}(t)}{\partial y^u(t-1)} \approx_{tr} 0,\qquad \frac{\partial\, \text{net}_{\text{out}_j}(t)}{\partial y^u(t-1)} \approx_{tr} 0,\qquad \frac{\partial\, \text{net}_{c_j}(t)}{\partial y^u(t-1)} \approx_{tr} 0 . $$

Errors may still change the incoming weights, but they are not propagated further back through those connections. Only inside the cell do errors travel back through previous states. The immediate consequence is

$$ \frac{\partial s_{c_j}(t-k)}{\partial s_{c_j}(t-k-1)} \approx_{tr} 1, \qquad\text{hence}\qquad \frac{\partial \vartheta_{s_{c_j}}(t)}{\partial \vartheta_{s_{c_j}}(t+1)} \approx_{tr} 1 . $$

Now trace an error $\vartheta_j(t)$ that arrives at the cell output and flows back $q$ steps to the cell input or the input gate:

$$ \frac{\partial \vartheta_v(t-q)}{\partial \vartheta_j(t)} \approx_{tr} y^{\text{out}_j}(t)\, h'\big(s_{c_j}(t)\big)\cdot \begin{cases} g'\big(\text{net}_{c_j}(t-q)\big)\, y^{\text{in}_j}(t-q) & v = c_j,\\[3pt] g\big(\text{net}_{c_j}(t-q)\big)\, f'_{\text{in}_j}\big(\text{net}_{\text{in}_j}(t-q)\big) & v = \text{in}_j. \end{cases} $$
The key observation

The error is scaled only at the moment it enters the cell (time $t$) and the moment it leaves (time $t-q$). Nothing in between depends on $q$. Compare this with the $q$-fold product in Section 3.

Learning rules of the truncated algorithm

With squared error $E(t) = \sum_k (t^k(t) - y^k(t))^2$ and unit error $e_l(t) = -\partial E(t)/\partial\,\text{net}_l(t)$, the updates for output units, hidden units and output gates are ordinary backpropagation:

$$ \begin{aligned} e_k(t) &= f_k'\big(\text{net}_k(t)\big)\big(t^k(t) - y^k(t)\big),\\ e_i(t) &= f_i'\big(\text{net}_i(t)\big)\sum_k w_{ki}\, e_k(t),\\ e_{\text{out}_j}(t) &= f'_{\text{out}_j}\big(\text{net}_{\text{out}_j}(t)\big)\sum_{v=1}^{S_j} h\big(s_{c_j^v}(t)\big)\sum_k w_{k c_j^v}\, e_k(t),\\ \Delta w_{lm}(t) &= \alpha\, e_l(t)\, y^m(t-1). \end{aligned} $$

Input gates and cell inputs use an RTRL-style forward recursion. Define the internal-state error

$$ e_{s_{c_j^v}}(t) = f_{\text{out}_j}\big(\text{net}_{\text{out}_j}(t)\big)\, h'\big(s_{c_j^v}(t)\big)\sum_k w_{k c_j^v}\, e_k(t) $$

and carry the derivatives of the state forward in time:

$$ \begin{aligned} \frac{\partial s_{c_j^v}(t)}{\partial w_{\text{in}_j m}} &= \frac{\partial s_{c_j^v}(t-1)}{\partial w_{\text{in}_j m}} + g\big(\text{net}_{c_j^v}(t)\big)\, f'_{\text{in}_j}\big(\text{net}_{\text{in}_j}(t)\big)\, y^m(t-1),\\ \frac{\partial s_{c_j^v}(t)}{\partial w_{c_j^v m}} &= \frac{\partial s_{c_j^v}(t-1)}{\partial w_{c_j^v m}} + g'\big(\text{net}_{c_j^v}(t)\big)\, f_{\text{in}_j}\big(\text{net}_{\text{in}_j}(t)\big)\, y^m(t-1). \end{aligned} $$

The weight updates are then $\Delta w_{\text{in}_j m}(t) = \alpha \sum_v e_{s_{c_j^v}}(t)\, \partial s_{c_j^v}(t)/\partial w_{\text{in}_j m}$ and $\Delta w_{c_j^v m}(t) = \alpha\, e_{s_{c_j^v}}(t)\, \partial s_{c_j^v}(t)/\partial w_{c_j^v m}$. Only these state derivatives need storing, so the algorithm is local in both space and time.

Two practical problems and their fixes

Abuse. Early in training the network can reduce error without memory, and may misuse cells as constant bias units. Fixes: add cells only when error stops falling, or give output gates negative initial biases (e.g. $-1, -2, -3$) so cells are "allocated" one at a time.

Internal state drift. If a cell's inputs are mostly of one sign, $s_{c_j}$ drifts, $h'(s_{c_j})\to 0$, and the gradient vanishes at the exit point. Fix: bias input gates negatively at initialisation (e.g. $-3, -6$).

7. Forget gates (Gers et al., 2000)

A fixed self-weight of $1$ has a flaw on continuous input streams: nothing ever resets the state. $s_{c}$ grows without bound, $h$ saturates, and the cell degenerates into an ordinary unit. Gers, Schmidhuber and Cummins replaced the constant $1$ with a learned forget gate $y^{\varphi}$:

$$ y^{\varphi_m}(\tau+1) = f\big(z_{\varphi_m}(\tau+1) + b_{\varphi_m}\big),\qquad s_{m_c}(\tau+1) = s_{m_c}(\tau)\, y^{\varphi_m}(\tau+1) + y^{\text{in}_m}(\tau+1)\, g\big(z_{m_c}(\tau+1)\big). $$

The error through the carousel is now scaled by the forget gate each step, $\partial s(\tau+1)/\partial s(\tau) = y^{\varphi}(\tau+1)$. This is no longer exactly $1$, but it is a learned, input-dependent factor that the network can hold near $1$ for as long as it needs to remember and drop to $0$ when it wants to reset. The truncated state derivative for forget-gate weights is

$$ \frac{\partial s_{m_c}(\tau+1)}{\partial W_{[\varphi_m,v]}} = \frac{\partial s_{m_c}(\tau)}{\partial W_{[\varphi_m,v]}}\, y^{\varphi_m}(\tau+1) + s_{m_c}(\tau)\, f'_{\varphi_m}\big(z_{\varphi_m}(\tau+1)\big)\, y_v(\tau). $$
Initialise the forget bias to 1

With $b_\varphi$ around $1$ the gate starts near $\sigma(1)\approx 0.73$ or higher, so the cell remembers before it has learned what to forget. Jozefowicz et al. (2015) found this single change closes much of the gap between LSTM and GRU.

8. The modern LSTM in vector form

Today's standard cell (as in PyTorch and TensorFlow) is the forget-gate LSTM with full backpropagation through time, $g=\tanh$, $h=\tanh$, and all four transforms computed from $[h_{t-1}, x_t]$. With hidden size $n$ and input size $d$:

$$ \boxed{\; \begin{aligned} f_t &= \sigma\big(W_f\,[h_{t-1}, x_t] + b_f\big) &&\text{forget gate}\\ i_t &= \sigma\big(W_i\,[h_{t-1}, x_t] + b_i\big) &&\text{input gate}\\ o_t &= \sigma\big(W_o\,[h_{t-1}, x_t] + b_o\big) &&\text{output gate}\\ \tilde c_t &= \tanh\big(W_c\,[h_{t-1}, x_t] + b_c\big) &&\text{candidate}\\ c_t &= f_t \odot c_{t-1} + i_t \odot \tilde c_t &&\text{cell state}\\ h_t &= o_t \odot \tanh(c_t) &&\text{hidden state} \end{aligned} \;} $$

Here $W_\ast \in \mathbb{R}^{n\times(n+d)}$, $b_\ast\in\mathbb{R}^n$, and $\odot$ is the element-wise product. The dictionary to the notation above is: $c_t \leftrightarrow s_c$, $\tilde c_t \leftrightarrow g(\text{net}_c)$, $i_t \leftrightarrow y^{\text{in}}$, $o_t\leftrightarrow y^{\text{out}}$, $f_t\leftrightarrow y^{\varphi}$, $h_t \leftrightarrow y^{c}$.

Two structural facts carry the whole design:

  1. The cell update is additive. New information is added to $c_{t-1}$ rather than pushed through a matrix and a squashing function.
  2. The direct Jacobian of the cell path is diagonal: $\dfrac{\partial c_t}{\partial c_{t-1}}\Big|_{\text{direct}} = \operatorname{diag}(f_t)$. Across $q$ steps this gives $\prod_{k=1}^{q}\operatorname{diag}(f_{t-k+1})$, with no weight matrices and no $\sigma'\le\tfrac14$ factors.

Some variants add peephole connections, letting gates see $c_{t-1}$ (or $c_t$ for the output gate), e.g. $f_t = \sigma(W_f[h_{t-1},x_t] + p_f\odot c_{t-1} + b_f)$. Gers et al. (2002) used these for precise timing tasks.

9. Backpropagation through the modern cell

Let $\delta h_t = \partial L/\partial h_t$ (loss gradient at step $t$ plus the gradient arriving from step $t+1$) and $\delta c_{t+1}$ be the gradient flowing back into the cell state from the future. Write $z_f, z_i, z_o, z_c$ for the pre-activations. Applying the chain rule to each line of the forward pass:

$$ \begin{aligned} \delta c_t &= \delta h_t \odot o_t \odot \big(1-\tanh^2 c_t\big) \;+\; \delta c_{t+1}\odot f_{t+1},\\[3pt] \delta z_o &= \delta h_t \odot \tanh(c_t)\odot o_t\odot(1-o_t),\\ \delta z_f &= \delta c_t \odot c_{t-1}\odot f_t\odot(1-f_t),\\ \delta z_i &= \delta c_t \odot \tilde c_t\odot i_t\odot(1-i_t),\\ \delta z_c &= \delta c_t \odot i_t\odot\big(1-\tilde c_t^{\,2}\big). \end{aligned} $$

Stacking $\delta z_t = [\delta z_f;\delta z_i;\delta z_o;\delta z_c]$ and $W = [W_f;W_i;W_o;W_c]$, with $v_t = [h_{t-1},x_t]$:

$$ \frac{\partial L}{\partial W} = \sum_t \delta z_t\, v_t^{\!\top},\qquad \frac{\partial L}{\partial b} = \sum_t \delta z_t,\qquad \big[\delta h_{t-1}^{\text{rec}};\ \delta x_t\big] = W^{\!\top}\delta z_t,\qquad \delta c_{t-1} \mathrel{+}= \delta c_t\odot f_t . $$

Where the long-range gradient lives

Ignoring the paths through the gates, the gradient from $c_t$ back to $c_{t-q}$ is

$$ \frac{\partial c_t}{\partial c_{t-q}} \approx \prod_{k=0}^{q-1} \operatorname{diag}\big(f_{t-k}\big) \quad\Longrightarrow\quad \Big|\frac{\partial c_{t,r}}{\partial c_{t-q,r}}\Big| \approx \prod_{k=0}^{q-1} f_{t-k,r}. $$

With $f\equiv 1$ this is exactly the CEC. With $f = 0.99$ the signal after $100$ steps is still $0.99^{100}\approx 0.37$, while a plain RNN with factor $0.9$ retains $0.9^{100}\approx 2.7\times10^{-5}$. The chart at the top plots precisely this comparison. The full Jacobian also contains terms through $h_{t-1}$ and the gates; those behave like an ordinary RNN and do decay, which is why modern LSTMs are usually trained with gradient clipping.

10. A worked scalar example

Take $n=1$, $c_{t-1}=0.5$, and suppose the pre-activations come out as $z_f=1$, $z_i=0$, $z_o=2$, $z_c=1$.

QuantityComputationValue
$f_t$$\sigma(1)$0.7311
$i_t$$\sigma(0)$0.5000
$o_t$$\sigma(2)$0.8808
$\tilde c_t$$\tanh(1)$0.7616
$c_t$$0.7311\cdot0.5 + 0.5\cdot0.7616$0.7463
$h_t$$0.8808\cdot\tanh(0.7463)$0.5575

Now backpropagate $\delta h_t = 1$ with $\delta c_{t+1}=0$:

GradientComputationValue
$\delta c_t$$1\cdot 0.8808\cdot(1-0.6330^2)$0.5279
$\delta z_o$$0.6330\cdot 0.8808\cdot 0.1192$0.0665
$\delta z_f$$0.5279\cdot 0.5\cdot 0.7311\cdot 0.2689$0.0519
$\delta z_i$$0.5279\cdot 0.7616\cdot 0.25$0.1005
$\delta z_c$$0.5279\cdot 0.5\cdot(1-0.7616^2)$0.1109
$\delta c_{t-1}$$0.5279\cdot 0.7311$0.3859

Notice that $\delta c_{t-1}$ is simply $\delta c_t$ times the forget gate. No weight and no sigmoid derivative appears on that path.

11. A reference implementation

The NumPy code below implements Sections 8 and 9 directly. It passes a finite-difference gradient check with relative error around $4\times10^{-10}$.

import numpy as np

def sigmoid(z):
    return 1.0 / (1.0 + np.exp(-z))

def lstm_forward(X, h0, c0, W, b):
    """X: (T, d); W: (4n, n+d); b: (4n,). Gate order: f, i, o, g."""
    n = h0.shape[0]
    h, c, cache, H = h0, c0, [], []
    for x in X:
        v = np.concatenate([h, x])
        z = W @ v + b
        f, i, o = sigmoid(z[:n]), sigmoid(z[n:2*n]), sigmoid(z[2*n:3*n])
        g = np.tanh(z[3*n:])
        c_new = f * c + i * g
        tc = np.tanh(c_new)
        h_new = o * tc
        cache.append((v, c, f, i, o, g, tc))
        h, c = h_new, c_new
        H.append(h)
    return np.array(H), cache

def lstm_backward(dH, cache, W):
    """dH: (T, n) = dL/dh_t from the loss at each step."""
    n = dH.shape[1]
    dW, db = np.zeros_like(W), np.zeros(W.shape[0])
    dh_next, dc_next = np.zeros(n), np.zeros(n)
    for t in reversed(range(len(cache))):
        v, c_prev, f, i, o, g, tc = cache[t]
        dh = dH[t] + dh_next
        dc = dh * o * (1 - tc**2) + dc_next
        dz = np.concatenate([
            dc * c_prev * f * (1 - f),   # forget gate
            dc * g * i * (1 - i),        # input gate
            dh * tc * o * (1 - o),       # output gate
            dc * i * (1 - g**2),         # candidate
        ])
        dW += np.outer(dz, v)
        db += dz
        dh_next = (W.T @ dz)[:n]
        dc_next = dc * f                 # the carousel
    return dW, db

12. Cost, and the family of variants

Parameters and complexity

A modern LSTM layer has four weight matrices and four bias vectors:

$$ \#\text{params} = 4\big(n(n+d) + n\big). $$

For $n=128$, $d=10$ that is $4(128\cdot138+128) = 71{,}168$. For the original architecture, Hochreiter and Schmidhuber show the per-step update cost is

$$ O(KH + KCS + HI + CSI) = O(W), $$

where $K$ is the number of outputs, $C$ the number of blocks of size $S$, $H$ conventional hidden units, $I$ the fan-in, and $W$ the number of weights. That is $O(1)$ per weight and time step, the same as BPTT, but without storing the activation history: only the $2CSI$ state derivatives $\partial s/\partial w$ are kept.

Gated recurrent unit (GRU)

Cho et al. (2014) merged the cell and hidden state and used two gates:

$$ \begin{aligned} r_t &= \sigma(W_r[h_{t-1},x_t] + b_r), \qquad u_t = \sigma(W_u[h_{t-1},x_t] + b_u),\\ \tilde h_t &= \tanh\big(W_x x_t + r_t\odot (W_h h_{t-1}) + b\big),\\ h_t &= u_t\odot h_{t-1} + (1-u_t)\odot \tilde h_t . \end{aligned} $$

Comparing with $c_t = f_t\odot c_{t-1} + i_t\odot\tilde c_t$: the update gate $u_t$ plays the forget gate, and $1-u_t$ plays the input gate, coupling the two. GRU has three weight blocks instead of four and no output gate.

Architectural extensions

13. What the 1997 experiments showed

Every task except the first was built so that no short-lag training examples exist, and most were too hard for random weight guessing.

TaskWhat it testsResult
Embedded Reber grammarStandard benchmark, short lagsLSTM solved it in nearly all 150 trials; RTRL, Elman nets and RCC succeeded rarely or never, and more slowly
Long-lag sequences (2a–2c)Remember one symbol for up to 1,000 steps among distractorsLSTM always succeeded; RTRL and BPTT already failed at 10-step lags
Two-sequence problem (3a–3c)Noise and signal on one channel, noisy real-valued targetsSolved, including the version guessing cannot crack
Adding problem (4)Store two real numbers for up to 500 steps and sum themAt most 3 of 2,560 test sequences wrong
Multiplication problem (5)Non-additive combination of stored valuesSolved, showing LSTM is not limited to integration
Temporal order (6a, 6b)Classify by the order of widely separated symbolsAt most 3 of 2,560 wrong

One scaling result stands out: when the number of distractor symbols grows in proportion to the time lag, training time grows very slowly, from 30,000 sequences at lag 50 to 49,000 at lag 1,000.

14. Limitations

The whole idea in one line

Plain RNNs multiply the error by $f'w$ every step, so it decays like $c^q$. LSTM routes memory through an additive path whose per-step factor is exactly $1$ (1997) or a learned gate near $1$ (2000 onward), and uses multiplicative gates to decide what enters, what leaves and what is forgotten.

A note on sources

The tutorial by Staudemeyer and Rothstein Morris prints the sigmoid threshold unit as $1/(1-e^{-l s})$; the correct form is $1/(1+e^{-l s})$. This page uses the correct sign throughout.

References

  1. S. Hochreiter and J. Schmidhuber. Long Short-Term Memory. Neural Computation 9(8):1735–1780, 1997.
  2. R. C. Staudemeyer and E. Rothstein Morris. Understanding LSTM: a tutorial into Long Short-Term Memory Recurrent Neural Networks. arXiv:1909.09586, 2019.
  3. S. Hochreiter. Untersuchungen zu dynamischen neuronalen Netzen. Diploma thesis, TU München, 1991.
  4. Y. Bengio, P. Simard, P. Frasconi. Learning long-term dependencies with gradient descent is difficult. IEEE Transactions on Neural Networks 5(2), 1994.
  5. F. A. Gers, J. Schmidhuber, F. Cummins. Learning to forget: continual prediction with LSTM. Neural Computation 12(10), 2000.
  6. F. A. Gers, N. Schraudolph, J. Schmidhuber. Learning precise timing with LSTM recurrent networks. JMLR 3, 2002.
  7. A. Graves et al. Connectionist temporal classification. ICML, 2006.
  8. K. Cho et al. Learning phrase representations using RNN encoder–decoder. EMNLP, 2014.
  9. R. Jozefowicz, W. Zaremba, I. Sutskever. An empirical exploration of recurrent network architectures. ICML, 2015.
  10. N. Kalchbrenner, I. Danihelka, A. Graves. Grid Long Short-Term Memory. ICLR, 2016.
Repository: https://github.com/abhinaash-broski/Portfolio