Md. Asif Uddin

    Chapter 10 · I.10

    Problems

    A chapter that uses mathematics has to teach that mathematics by making the reader compute. A chapter that only displays equations has failed, however correct the equations are.

    M3Load-bearing

    5/5 problems5/4 variants10/10 exercisesquota met, and enforced

    The contract

    • 5 worked problems, minimum.
    • 4 distinct variants, and no variant more than half of them.
    • 10 exercises, every one with a published solution.
    • At least one numeric problem — present.
    • At least one symbolic problem — present.
    • At least one limit or counterexample problem — present.
    • At least one complexity or shape problem — present.
    • At least one ▲▲▲ problem — present.

    Numerical instantiationSymbolic derivationLimiting caseConstructed failureDimensional algebra

    Problem I.10.B01

    Write once, then keep

    numeric▲△△

    Exact values where possible; six decimal places for non-exact numerical results.

    STATEMENT

    Run a scalar LSTM through three inputs and separate what the input gate writes from what the forget gate keeps.

    GIVEN

    A scalar cell follows (I.10.1) and (I.10.2) with every recurrent weight zero. The gates read only their biases: bi=0b_i=0, bf=ln⁡3b_f=\ln3, bo=ln⁡3b_o=\ln3, and ui=uf=uo=0u_i=u_f=u_o=0. The candidate is c~t=tanh⁡(xtln⁡3)\tilde c_t=\tanh(x_t\ln3), so uc=ln⁡3u_c=\ln3 and bc=0b_c=0. Start from c0=h0=0c_0=h_0=0 and feed (1,0,0)(1,0,0).

    FIND

    The three gate values, the candidates, all three cell and hidden states, the third cell state when bf=ln⁡99b_f=\ln99 instead, and the number of trainable scalars.

    STRATEGY

    Evaluate the gates first; they are constants here. Then apply the cell update one step at a time and read each hidden state through the output gate.

    SOLUTION

    Since σ(ln⁡a)=a/(1+a)\sigma(\ln a)=a/(1+a), the gates are i=σ(0)=1/2i=\sigma(0)=1/2 and f=o=σ(ln⁡3)=3/4f=o=\sigma(\ln3)=3/4. The first candidate is

    tanh⁡(ln⁡3)=3−1/33+1/3=45,\tanh(\ln3)=\frac{3-1/3}{3+1/3}=\frac45,

    and the later candidates are tanh⁡(0)=0\tanh(0)=0.

    The cell update writes once and then only keeps:

    c1=34⋅0+12⋅45=0.4,c2=34⋅0.4+12⋅0=0.3,c3=34⋅0.3=0.225.\begin{aligned} c_1&=\tfrac34\cdot0+\tfrac12\cdot\tfrac45=0.4,\\ c_2&=\tfrac34\cdot0.4+\tfrac12\cdot0=0.3,\\ c_3&=\tfrac34\cdot0.3=0.225. \end{aligned}

    The hidden states are ht=34tanh⁡(ct)h_t=\tfrac34\tanh(c_t): 0.2849620.284962, 0.2184840.218484 and 0.1659590.165959.

    With bf=ln⁡99b_f=\ln99 the forget gate is 0.990.99, and c3=0.4⋅0.992=0.39204c_3=0.4\cdot0.99^2=0.39204. The input gate decided how much was written; the forget gate alone decided how much of it survived two silent steps.

    Each of the four blocks has one input weight, one recurrent weight and one bias, so the scalar cell has 1212 trainable scalars. The plain scalar cell of I.9.B01 had three before its readout.

    Answer

    Gates (i,f,o)=(1/2,3/4,3/4)(i,f,o)=(1/2,3/4,3/4); candidates (0.8,0,0)(0.8,0,0); cell states (0.4,0.3,0.225)(0.4,0.3,0.225); hidden states (0.284962,0.218484,0.165959)(0.284962,0.218484,0.165959); with f=0.99f=0.99, c3=0.39204c_3=0.39204; twelve trainable scalars.

    Check — sanity

    Each hidden state is smaller than its cell state. For c>0c>0, tanh⁡c<c\tanh c<c, and the output gate multiplies by a further three quarters. The hidden state is a view of the cell, not a copy of it.

    Check — numeric · i-10-gating-checks.py

    The complete reproduction script uses only the Python standard library. From a checkout of the repository, run:

    python3 scripts/snippets/i-10-gating-checks.py

    It checks all fifteen problems of the chapter. Its first line reports the cell states 0.40.4, 0.30.3, 0.2250.225, the hidden states above and the f=0.99f=0.99 cell state 0.3920400.392040. Its second line confirms that a full two-unit LSTM backward pass matches central finite differences for every parameter.

    Executed in CI. The digits above are the digits it printed.

    Where this breaks

    Nonzero recurrent weights make the gates depend on ht−1h_{t-1}, so they change from step to step and the cell states are no longer a geometric sequence. The write-then-keep reading survives; the clean numbers do not.

    Variation

    Feed (1,1,0)(1,1,0) instead. The second step keeps 0.30.3 and writes another 0.40.4, so c2=0.7c_2=0.7 and c3=0.525c_3=0.525. The cell accumulates; it does not overwrite unless the forget gate is small.

    Problem I.10.B02

    Backpropagation through one LSTM cell

    symbolic▲▲▲

    Exact values where possible; six decimal places for non-exact numerical results.

    STATEMENT

    Derive the backward pass of an LSTM step, identify the carry line in it, and measure how much of a real derivative the carry line accounts for.

    GIVEN

    The cell of (I.10.1) and (I.10.2), with a loss that may read any ht\vec h_t. For the numerical part, use the scalar cell of I.10.B01 with one change: the candidate also reads the hidden state, c~t=tanh⁡(xtln⁡3+2ht−1)\tilde c_t=\tanh(x_t\ln3+2h_{t-1}). Inputs are (1,0,0)(1,0,0) from zero states.

    FIND

    The recursions for gˉc,t\bar{\vec g}_{c,t} and the four pre-activation derivatives; the derivatives sent to ht−1\vec h_{t-1} and ct−1\vec c_{t-1}; the parameter gradients; and, in the scalar case, ∂c3/∂c1\partial c_3/\partial c_1 compared with its carry-line term.

    STRATEGY

    Draw the arrows leaving ct\vec c_t and ht\vec h_t, add the returns, and only then differentiate the activations. For the scalar part, notice that a constant output gate makes hth_t a function of ctc_t.

    SOLUTION

    Arrows out of the cell. The cell state ct\vec c_t is used twice: by ht=ot⊙tanh⁡(ct)\vec h_t=\vec o_t\odot\tanh(\vec c_t), and by the next cell update, where it is multiplied by ft+1\vec f_{t+1}. Reverse mode adds the two returns:

    gˉc,t=gˉh,t⊙ot⊙(1−tanh⁡2ct)+gˉc,t+1⊙ft+1,gˉc,T+1=0.\bar{\vec g}_{c,t}=\bar{\vec g}_{h,t}\odot\vec o_t\odot(1-\tanh^2\vec c_t) +\bar{\vec g}_{c,t+1}\odot\vec f_{t+1}, \qquad\bar{\vec g}_{c,T+1}=0.

    Here gˉh,t\bar{\vec g}_{h,t} is already the total for ht\vec h_t: its readout term plus everything step t+1t+1 returned through its gates.

    Pre-activations. Write ak,t\vec a_{k,t} for the argument of the gate or candidate kk. Differentiating ht=ot⊙tanh⁡ct\vec h_t=\vec o_t\odot\tanh\vec c_t with respect to ao,t\vec a_{o,t}, and ct=ft⊙ct−1+it⊙c~t\vec c_t=\vec f_t\odot\vec c_{t-1}+\vec i_t\odot\tilde{\vec c}_t with respect to the other three,

    δo,t=gˉh,t⊙tanh⁡(ct)⊙ot⊙(1−ot),δf,t=gˉc,t⊙ct−1⊙ft⊙(1−ft),δi,t=gˉc,t⊙c~t⊙it⊙(1−it),δc,t=gˉc,t⊙it⊙(1−c~t2).\begin{aligned} \vec\delta_{o,t}&=\bar{\vec g}_{h,t}\odot\tanh(\vec c_t)\odot\vec o_t\odot(1-\vec o_t),\\ \vec\delta_{f,t}&=\bar{\vec g}_{c,t}\odot\vec c_{t-1}\odot\vec f_t\odot(1-\vec f_t),\\ \vec\delta_{i,t}&=\bar{\vec g}_{c,t}\odot\tilde{\vec c}_t\odot\vec i_t\odot(1-\vec i_t),\\ \vec\delta_{c,t}&=\bar{\vec g}_{c,t}\odot\vec i_t\odot(1-\tilde{\vec c}_t^2). \end{aligned}

    This is (I.10.6). The output gate is the only one that reads gˉh,t\bar{\vec g}_{h,t} directly; the other three see the cell’s total.

    What goes back one step. Every pre-activation contains Wkht−1\mat W_k\vec h_{t-1}, so the recurrent return to ht−1\vec h_{t-1} is ∑k∈{i,f,o,c}WkTδk,t\sum_{k\in\{i,f,o,c\}}\mat W_k^{\mathsf T}\vec\delta_{k,t}. The cell one step back receives gˉc,t⊙ft\bar{\vec g}_{c,t}\odot\vec f_t, the carry line, which is the second term of the next gˉc,t−1\bar{\vec g}_{c,t-1}. At t=1t=1 these two quantities are the derivatives with respect to h0\vec h_0 and c0\vec c_0.

    Parameters. Each block is used at every step, so its gradients are sums, as in (I.9.4):

    ∇WkL=∑tδk,tht−1T,∇UkL=∑tδk,txtT,∇bkL=∑tδk,t.\nabla_{\mat W_k}\mathcal L=\sum_t\vec\delta_{k,t}\vec h_{t-1}^{\mathsf T},\quad \nabla_{\mat U_k}\mathcal L=\sum_t\vec\delta_{k,t}\vec x_t^{\mathsf T},\quad \nabla_{\vec b_k}\mathcal L=\sum_t\vec\delta_{k,t}.

    The scalar case. With constant gates i=1/2i=1/2, f=o=3/4f=o=3/4, the hidden state ht=34tanh⁡cth_t=\tfrac34\tanh c_t is a function of ctc_t, so the state is cc alone and the one-step derivative is

    kt=∂ct∂ct−1=f⏟carry line+i (1−c~t2)⋅2⋅o (1−tanh⁡2ct−1)⏟through ht−1.k_t=\frac{\partial c_t}{\partial c_{t-1}} =\underbrace{f}_{\text{carry line}} +\underbrace{i\,(1-\tilde c_t^2)\cdot2\cdot o\,(1-\tanh^2c_{t-1})}_{\text{through }h_{t-1}}.

    The forward pass gives c1=0.4c_1=0.4, h1=0.284962h_1=0.284962, then c~2=tanh⁡(0.569924)\tilde c_2=\tanh(0.569924) and onwards. Evaluating along that trajectory, k2=1.221326k_2=1.221326 and k3=1.078827k_3=1.078827, so

    ∂c3∂c1=k3k2=1.317600,carry line alone: f2=0.5625.\frac{\partial c_3}{\partial c_1}=k_3k_2=1.317600, \qquad\text{carry line alone: }f^2=0.5625.

    Expanding k3k2k_3k_2 gives four terms. Only f⋅ff\cdot f avoids the recurrent weight; the other three each contain it at least once, as I.10.T1 says. Here they contribute 0.7551000.755100, more than the carry line.

    The reproduction script perturbs c1c_1 by 10−610^{-6}, reruns steps two and three, and matches 1.3176001.317600 by central differences. It then checks the vector recursions above on a two-unit cell with non-symmetric recurrent weights, losses at three of four steps and nonzero initial states. All twelve parameter blocks, c0\vec c_0 and h0\vec h_0 agree with finite differences.

    Answer

    gˉc,t=gˉh,t⊙ot⊙(1−tanh⁡2ct)+gˉc,t+1⊙ft+1\bar{\vec g}_{c,t}=\bar{\vec g}_{h,t}\odot\vec o_t\odot(1-\tanh^2\vec c_t)+\bar{\vec g}_{c,t+1}\odot\vec f_{t+1}, with the four δ\vec\delta above, a return of ∑kWkTδk,t\sum_k\mat W_k^{\mathsf T}\vec\delta_{k,t} to ht−1\vec h_{t-1} and gˉc,t⊙ft\bar{\vec g}_{c,t}\odot\vec f_t to ct−1\vec c_{t-1}. In the scalar case ∂c3/∂c1=1.317600\partial c_3/\partial c_1=1.317600, of which the carry line accounts for 0.56250.5625.

    Check — sanity

    Set every recurrent weight to zero. Then Mt=0\mat M_t=0, the hidden-state return vanishes, and the derivative between cell states is exactly the product of forget values. In the scalar case kt=fk_t=f and ∂c3/∂c1=0.5625\partial c_3/\partial c_1=0.5625.

    Where this breaks

    Treating ot\vec o_t as a function of ct\vec c_t would add a false term: the output gate reads ht−1\vec h_{t-1} and xt\vec x_t, not the cell. A peephole LSTM, which does let gates read the cell, adds genuine terms of that kind and needs its own derivation.

    Variation

    Replace the candidate weight two with zero. Both factors become 3/43/4 and the derivative falls to 0.56250.5625. The weight did not change the carry line; it changed how much signal reached the cell by other routes.

    Problem I.10.B03

    How long a forget gate remembers

    limit▲▲△

    Exact values where possible; six decimal places for non-exact numerical results.

    STATEMENT

    Turn a constant forget value into a number of steps, bound that number, and find the forget value and bias a given horizon requires.

    GIVEN

    One coordinate’s forget value is f∈(0,1)f\in(0,1) at every step. The carry-line factor after nn steps is fnf^n. The memory horizon is m=−1/ln⁡fm=-1/\ln f.

    FIND

    (a) f100f^{100} and f1000f^{1000} for f=0.99f=0.99, with its horizon and half-life. (b) Bounds on mm in terms of ff. (c) The smallest ff with m≥100m\geq100, and the bias that produces it when the gate’s other inputs are zero. (d) The behaviour of mm as f→1f\to1 and as the bias grows.

    STRATEGY

    Write fn=enln⁡ff^n=e^{n\ln f} and use ln⁡x≤x−1\ln x\leq x-1 twice. For the bias, invert the sigmoid.

    SOLUTION

    (a) Directly, 0.99100=0.3660320.99^{100}=0.366032 and 0.991000=4.317125×10−50.99^{1000}=4.317125\times10^{-5}. The horizon is −1/ln⁡0.99=99.499162-1/\ln0.99=99.499162 steps. The half-life solves fn=1/2f^n=1/2, so n1/2=ln⁡2/(−ln⁡f)=mln⁡2=68.967564n_{1/2}=\ln2/(-\ln f)=m\ln2=68.967564 steps.

    (b) The inequality ln⁡x≤x−1\ln x\leq x-1 is strict for x≠1x\neq1. At x=fx=f it gives −ln⁡f>1−f-\ln f>1-f. At x=1/fx=1/f it gives ln⁡(1/f)<1/f−1\ln(1/f)<1/f-1, that is, −ln⁡f<(1−f)/f-\ln f<(1-f)/f. Taking reciprocals,

    f1−f<m<11−f.\frac{f}{1-f}<m<\frac{1}{1-f}.

    The two bounds differ by exactly one, so 1/(1−f)1/(1-f) gives the horizon to within a step. For f=0.99f=0.99 they are 9999 and 100100.

    (c) The condition m≥100m\geq100 is −ln⁡f≤1/100-\ln f\leq1/100, so f≥e−1/100=0.990050f\geq e^{-1/100}=0.990050. A gate with only its bias has f=σ(b)f=\sigma(b), so b=ln⁡(f/(1−f))=4.600166b=\ln\big(f/(1-f)\big)=4.600166.

    (d) As f→1f\to1, −ln⁡f→0+-\ln f\to0^+ and m→∞m\to\infty; by (b), mm grows like 1/(1−f)1/(1-f). With f=σ(b)f=\sigma(b), (I.10.5) gives 1/(1−f)=1+eb1/(1-f)=1+e^b. Each extra unit of bias multiplies the horizon by about ee, but no finite bias reaches f=1f=1.

    Answer

    (a) 0.3660320.366032, 4.317125×10−54.317125\times10^{-5}; horizon 99.49916299.499162; half-life 68.96756468.967564. (b) f/(1−f)<m<1/(1−f)f/(1-f)<m<1/(1-f). (c) f≥0.990050f\geq0.990050, bias at least 4.6001664.600166. (d) m→∞m\to\infty like 1/(1−f)=1+eb1/(1-f)=1+e^b, never infinite at finite bb.

    Check — sanity

    At f=1/2f=1/2 the bounds give 1<m<21<m<2, and indeed m=1/ln⁡2≈1.44m=1/\ln2\approx1.44. A zero forget bias forgets most of a value within two steps.

    Where this breaks

    A trained gate’s value changes with the input, so the horizon of a real cell is a distribution over steps, not a constant. The bound also concerns the carry line only; I.10.B02 shows the full derivative can be several times larger or smaller.

    Variation

    For a horizon of exactly mm in the sense of 1/(1−f)=m1/(1-f)=m, set b=ln⁡(m−1)b=\ln(m-1). For m=100m=100 that is ln⁡99=4.595120\ln99=4.595120, slightly below the answer to (c), because 1/(1−f)1/(1-f) exceeds −1/ln⁡f-1/\ln f.

    Problem I.10.B04

    The same weights, two GRUs

    counterexample▲▲△

    Exact values where possible; six decimal places for non-exact numerical results.

    STATEMENT

    Show that applying the reset gate before or after the recurrent matrix gives different GRUs, and find exactly when the two agree.

    GIVEN

    A two-unit GRU step with zero input contribution and zero candidate biases. The recurrent candidate matrix swaps coordinates, Wn=[0110]\mat W_n=\begin{bmatrix}0&1\\1&0\end{bmatrix}. The preceding state is ht−1=(0.5,−0.5)\vec h_{t-1}=(0.5,-0.5). The reset pre-activations are (ln⁡3,−ln⁡3)(\ln3,-\ln3) and the update pre-activations are zero. Use PyTorch’s update, ht=(1−zt)⊙nt+zt⊙ht−1\vec h_t=(1-\vec z_t)\odot\vec n_t+\vec z_t\odot\vec h_{t-1}, for both.

    FIND

    The gates, both candidates and both new states; then a condition on Wn\mat W_n and rt\vec r_t under which the two placements agree for every state.

    STRATEGY

    Compute W(r⊙h)\mat W(\vec r\odot\vec h) and r⊙(Wh)\vec r\odot(\mat W\vec h) separately. For the general condition, write both as products with diag⁡(r)\operatorname{diag}(\vec r) and compare entries.

    SOLUTION

    The gates are r=(σ(ln⁡3),σ(−ln⁡3))=(0.75,0.25)\vec r=(\sigma(\ln3),\sigma(-\ln3))=(0.75,0.25) and z=(0.5,0.5)\vec z=(0.5,0.5). The update gate is the same in both models, so any difference comes from the candidate.

    Reset before the matrix, as in Cho and colleagues: r⊙h=(0.375,−0.125)\vec r\odot\vec h=(0.375,-0.125), and the swap gives (−0.125,0.375)(-0.125,0.375). Hence

    nbefore=(tanh⁡(−0.125),tanh⁡(0.375))=(−0.124353,0.358357).\vec n^{\text{before}}=(\tanh(-0.125),\tanh(0.375))=(-0.124353,0.358357).

    Reset after the matrix, as in PyTorch: Wh=(−0.5,0.5)\mat W\vec h=(-0.5,0.5), then r⊙Wh=(−0.375,0.125)\vec r\odot\mat W\vec h=(-0.375,0.125), and

    nafter=(−0.358357,0.124353).\vec n^{\text{after}}=(-0.358357,0.124353).

    With z=1/2z=1/2, the new states are the averages of candidate and old state: (0.187823,−0.070821)(0.187823,-0.070821) before and (0.070821,−0.187823)(0.070821,-0.187823) after. Same weights, same state, same gates, and every coordinate differs by more than 0.10.1.

    When they agree. The candidates’ recurrent parts are Wdiag⁡(r)h\mat W\operatorname{diag}(\vec r)\vec h and diag⁡(r)Wh\operatorname{diag}(\vec r)\mat W\vec h. They agree for every h\vec h exactly when the matrices are equal. Their (j,k)(j,k) entries are WjkrkW_{jk}r_k and rjWjkr_jW_{jk}, so the condition is

    Wjk(rk−rj)=0for all j,k.W_{jk}(r_k-r_j)=0\quad\text{for all }j,k.

    A weight joining two coordinates may be nonzero only if their reset values are equal. A uniform reset, r=ρ1\vec r=\rho\vec 1, satisfies it for every W\mat W; a diagonal W\mat W satisfies it for every r\vec r. The swap matrix with unequal resets satisfies neither, which is why this example separates them.

    Biases add a second difference. In the after form the recurrent bias bhn\vec b_{hn} is inside the reset, r⊙(Wh+bhn)\vec r\odot(\mat W\vec h+\vec b_{hn}), so the reset scales it. In the before form a bias added outside is not scaled. Even scalar models differ when that bias is nonzero.

    Answer

    r=(0.75,0.25)\vec r=(0.75,0.25), z=(0.5,0.5)\vec z=(0.5,0.5). Before: candidate (−0.124353,0.358357)(-0.124353,0.358357), state (0.187823,−0.070821)(0.187823,-0.070821). After: candidate (−0.358357,0.124353)(-0.358357,0.124353), state (0.070821,−0.187823)(0.070821,-0.187823). They agree for all states exactly when Wjk(rk−rj)=0W_{jk}(r_k-r_j)=0 for all j,kj,k.

    Check — sanity

    The swap matrix moves each coordinate’s reset to the other side. Reset before: coordinate one’s value, scaled by 0.750.75, lands in coordinate two. Reset after: coordinate two’s value lands in coordinate one and is scaled there by 0.750.75. The mirror-image answers are what that bookkeeping predicts.

    Where this breaks

    The commutation test is for one step with fixed gates. Over a sequence the two models also produce different gates, because the gates read states that have already diverged. Load a checkpoint into the placement it was trained with. The update-gate convention can be converted by negating weights; this example gives no such conversion for the reset placement.

    Variation

    Make the reset uniform at (0.5,0.5)(0.5,0.5) and keep the swap matrix. Both forms now give the candidate (tanh⁡(−0.25),tanh⁡(0.25))=(−0.244919,0.244919)(\tanh(-0.25),\tanh(0.25))=(-0.244919,0.244919).

    Problem I.10.B05

    What four gates cost

    shape▲▲△

    Exact values where possible; six decimal places for non-exact numerical results.

    STATEMENT

    Audit the shapes, parameter counts, arithmetic and training storage of a tanh RNN, a GRU and an LSTM, then find a fair width for comparing two of them.

    GIVEN

    Input width D=3D=3, hidden width H=5H=5. Count one bias per gate as in (I.10.8), then PyTorch’s two bias vectors per block. For storage, take N=4N=4 sequences of length T=6T=6 in float32, as in I.9.B04. Assume the plain cell stores ht\vec h_t for the backward pass and the LSTM stores it,ft,ot,c~t,ct,ht\vec i_t,\vec f_t,\vec o_t,\tilde{\vec c}_t,\vec c_t,\vec h_t.

    FIND

    (a) PyTorch’s LSTM weight and bias shapes, and the rows of the forget gate. (b) Parameter counts for all three cells under both bias conventions, with the GRU’s reset-after form. (c) Multiply–accumulates per step for one sequence. (d) Stored activation bytes. (e) The GRU width whose one-bias count equals the LSTM’s at H=5H=5.

    STRATEGY

    Each gated block is a plain recurrent layer’s affine map with its own weights. Count one block, then multiply.

    SOLUTION

    (a) PyTorch stacks the four LSTM blocks in the order input, forget, candidate, output. The input weights are 4H×D=20×34H\times D=20\times3, the recurrent weights 4H×H=20×54H\times H=20\times5, and each bias vector has 4H=204H=20 entries. Counting from zero, the forget gate occupies rows 55 to 99. Rows 00 to 44 are the input gate. For a GRU the order is reset, update, new, so the blocks are 3H3H rows tall.

    (b) One block has H(D+H+1)=5⋅9=45H(D+H+1)=5\cdot9=45 parameters with one bias. So

    RNN 45,GRU 3⋅45=135,LSTM 4⋅45=180.\text{RNN }45,\qquad\text{GRU }3\cdot45=135,\qquad\text{LSTM }4\cdot45=180.

    The reset-after GRU keeps bhn\vec b_{hn} inside the reset, which cannot be merged with bn\vec b_n: 135+5=140135+5=140. PyTorch keeps two bias vectors per block, H(D+H)+2HH(D+H)+2H each: 40+10=5040+10=50, then 150150 and 200200.

    (c) One affine map from (xt,ht−1)(\vec x_t,\vec h_{t-1}) costs H(D+H)=40H(D+H)=40 multiply–accumulates. The LSTM computes four, 160160 per step; the GRU three, 120120; the plain cell one, 4040. The elementwise gate products add O(H)O(H) per step and do not change the leading count.

    (d) The plain cell stores NTH=120NTH=120 numbers, 480480 bytes. The LSTM, under the stated scheme, stores six vectors per step: 6⋅120=7206\cdot120=720 numbers, 28802880 bytes. Other schemes store tanh⁡ct\tanh\vec c_t or recompute gates in the backward pass. Name the scheme before quoting a ratio.

    (e) A GRU of width H′H' at D=3D=3 has 3H′(H′+4)3H'(H'+4) parameters. Setting this to 180180 gives H′2+4H′−60=0H'^2+4H'-60=0, whose positive root is H′=6H'=6: 3⋅6⋅10=1803\cdot6\cdot10=180 exactly. Its arithmetic is 3⋅6⋅9=1623\cdot6\cdot9=162 multiply–accumulates per step, against the LSTM’s 160160. In PyTorch’s convention the two counts are 198198 and 200200.

    A plain RNN cannot match exactly: H′(H′+4)=180H'(H'+4)=180 has no integer root, and widths 1111 and 1212 give 165165 and 192192.

    Answer

    (a) 20×320\times3, 20×520\times5, two biases of 2020; forget rows 55–99. (b) One bias: 4545, 135135 (140140 reset-after), 180180. PyTorch: 5050, 150150, 200200. (c) 4040, 120120, 160160 per step. (d) 480480 and 28802880 bytes. (e) H′=6H'=6, 180180 parameters, 162162 multiply–accumulates.

    Check — sanity

    Setting D=0D=0 removes every input weight: the one-bias LSTM count becomes 4H(H+1)=1204H(H+1)=120, four copies of a plain recurrent map with bias. Counts should always factor this way.

    Where this breaks

    Multiply–accumulate counts are not runtimes. Fused kernels compute all four LSTM blocks as one 4H4H-row product, and memory traffic often decides speed. Projection layers, peepholes and bidirectional stacks change every count above.

    Variation

    At D=H=512D=H=512, a common width, the one-bias LSTM block count is 4⋅512⋅1025=2,099,2004\cdot512\cdot1025=2{,}099{,}200 parameters, and the GRU’s is 1,574,4001{,}574{,}400.

    Exercises

    Every one has a published solution. A hidden solution is a solution; a missing one is an abandonment.

    I.10.X01A saturated gate still leakslimit▲△△

    A forget gate has bias 1010 and no other input, so f=σ(10)f=\sigma(10). Is the carry line lossless? Compute ff, 1−f1-f, the carry-line factor after 10510^5 steps and the memory horizon.

    Hint

    Use 1−σ(b)=σ(−b)1-\sigma(b)=\sigma(-b), and (I.10.5) for the horizon.

    Solution

    f=σ(10)=0.9999546f=\sigma(10)=0.9999546 and 1−f=σ(−10)=4.539787×10−51-f=\sigma(-10)=4.539787\times10^{-5}. After 10510^5 steps the factor is f100000=0.010675f^{100000}=0.010675: about one per cent of the signal is left.

    The horizon is −1/ln⁡f=22026.97-1/\ln f=22026.97 steps. By (I.10.5) it lies just below 1/(1−f)=1+e10=22027.471/(1-f)=1+e^{10}=22027.47.

    The carry line is not lossless. A sigmoid gate can be pushed as close to one as the bias allows, which sets a long but finite horizon. Only the 1997 design, with no forget gate at all, had a factor of exactly one, and I.10.X03 shows what that cost.

    I.10.X02Which slice is the forget gate?shape▲△△

    A PyTorch nn.LSTM has hidden width H=5H=5. You want the forget bias to start at one. Which entries of bias_ih_l0 hold the forget gate? What effective bias results if you set that slice to one in both bias_ih_l0 and bias_hh_l0, and what horizons 1/(1−f)1/(1-f) do the intended and the actual settings give? What range does PyTorch’s default leave each bias in?

    Hint

    PyTorch stacks the gates as input, forget, candidate, output. The two bias vectors are added inside every gate.

    Solution

    Each bias vector has 4H=204H=20 entries in four blocks of five. The forget block is the second: entries 55 to 99, counting from zero. Entries 00 to 44 are the input gate, so setting them would raise the input gate instead.

    The gate computes σ(⋯+bif+bhf)\sigma(\cdots+b_{if}+b_{hf}). Setting both slices to one gives an effective bias of two: f=σ(2)=0.880797f=\sigma(2)=0.880797 instead of σ(1)=0.731059\sigma(1)=0.731059. By (I.10.5) the horizons are 1+e2=8.3890561+e^2=8.389056 and 1+e=3.7182821+e=3.718282 steps. Set one slice to one and the other to zero, or split the target between them.

    By default PyTorch draws every bias from U(−1/5,1/5)U(-1/\sqrt5,1/\sqrt5), that is, within ±0.447214\pm0.447214. The effective forget bias is the sum of two such draws, so it lies within ±0.894427\pm0.894427, centred on zero: ff starts near one half. Keras, by contrast, adds one to the forget bias by default.

    I.10.X05Masking a padded step freezes two statesnumeric▲△△

    An LSTM coordinate has c=1c=1 before a padded step. During padding the input is zero and the gates are f=0.5f=0.5, i=0.5i=0.5, o=0.75o=0.75 with candidate 0.60.6. The next real step has f=0.5f=0.5, i=0.5i=0.5, candidate 00 and o=0.75o=0.75. Compare the next real hidden state when the padded step updates cc but freezes hh, and when it freezes both.

    Hint

    Freezing hh alone still runs the cell update.

    Solution

    Freezing only hh: the padded step computes c=0.5⋅1+0.5⋅0.6=0.8c=0.5\cdot1+0.5\cdot0.6=0.8. The next real step gives c=0.5⋅0.8=0.4c=0.5\cdot0.8=0.4 and h=0.75tanh⁡(0.4)=0.284962h=0.75\tanh(0.4)=0.284962.

    Freezing both: the cell stays at 11, the next step gives c=0.5c=0.5 and h=0.75tanh⁡(0.5)=0.346588h=0.75\tanh(0.5)=0.346588.

    The masked update of I.9 applied to h\vec h alone is not enough for an LSTM. Mask both states: if ct new\vec c_t^{\,\text{new}} is the cell update the step computed, keep mtct new+(1−mt)ct−1m_t\vec c_t^{\,\text{new}}+(1-m_t)\vec c_{t-1}, and apply the same rule to ht\vec h_t. Or pack the sequence so padded steps never run.

    I.10.X06Which side does z multiply?numeric▲△△

    A GRU’s update gate sits at z=0.9z=0.9 for ten steps while the candidate is zero. How much of the starting state survives under PyTorch’s convention, ht=(1−z)nt+z ht−1h_t=(1-z)n_t+z\,h_{t-1}, and under Chung and colleagues’, ht=(1−z)ht−1+z nth_t=(1-z)h_{t-1}+z\,n_t? How do you convert trained weights from one convention to the other?

    Hint

    With a zero candidate, each step multiplies the state by whichever factor sits next to ht−1h_{t-1}.

    Solution

    Under PyTorch’s convention each step keeps zz: after ten steps 0.910=0.3486780.9^{10}=0.348678 of the starting state remains. Under the other, each step keeps 1−z1-z: 0.110=10−100.1^{10}=10^{-10}. The direct Jacobians are diag⁡(z)\operatorname{diag}(\vec z) and diag⁡(1−z)\operatorname{diag}(1-\vec z) respectively.

    The two conventions describe the same functions. Since 1−σ(a)=σ(−a)1-\sigma(a)=\sigma(-a), negating the update gate’s input weights, recurrent weights and bias turns zz into 1−z1-z. Loading weights without that step silently swaps keeping and overwriting.

    I.10.X03No forget gate, no boundnumeric▲▲△

    A cell without a forget gate, as in 1997, has f=1f=1. Its input gate and candidate are constant at i=1i=1 and c~=0.1\tilde c=0.1, its output gate at o=1o=1, and c0=0c_0=0. Find c200c_{200} and the derivative ∂h/∂c\partial h/\partial c there, both by the formula 1−tanh⁡2c1-\tanh^2c evaluated in float64 and by sech⁡2c\operatorname{sech}^2c. Repeat with f=0.9f=0.9.

    Hint

    Without forgetting, the cell adds the same amount every step. With f<1f<1 it approaches ic~/(1−f)i\tilde c/(1-f).

    Solution

    With f=1f=1, ct=0.1 tc_t=0.1\,t, so c200=20c_{200}=20. Mathematically ∂h/∂c=1−tanh⁡2(20)=sech⁡2(20)=1.699342×10−17\partial h/\partial c=1-\tanh^2(20)=\operatorname{sech}^2(20)=1.699342\times10^{-17}. In float64, tanh⁡(20)\tanh(20) rounds to exactly one, because it differs from one by about 8.5×10−188.5\times10^{-18}, less than half the spacing of doubles below one. The formula 1−tanh⁡2c1-\tanh^2c then returns exactly 0.00.0.

    Either way the output path into the cell is closed. The carry line still passes gradients from cell to cell with factor one, but no loss on hh can send anything into the cell. On a long unsegmented stream the cell keeps growing, which is the failure Gers, Schmidhuber and Cummins identified.

    With f=0.9f=0.9, ct=0.1(1−0.9t)/(1−0.9)=1−0.9tc_t=0.1(1-0.9^t)/(1-0.9)=1-0.9^t, so c200=1.000000c_{200}=1.000000 to six places, and sech⁡2(1)=0.419974\operatorname{sech}^2(1)=0.419974. The bound of I.10.T3, 1/(1−φ)=101/(1-\varphi)=10, is not tight here, but it is finite.

    I.10.X04The hidden state is not the memorycounterexample▲▲△

    Two runs of an LSTM coordinate reach ct=0.5c_t=0.5 and ct=−0.5c_t=-0.5. At step tt the output gate is 0.010.01. At step t+1t+1 the gates are f=0.99f=0.99, i=0.01i=0.01, with candidate 00 and output gate 0.990.99. How far apart are the two hidden states at tt, and at t+1t+1? What does this say about reading the memory from hth_t?

    Hint

    The cell update at t+1t+1 writes nothing, so ct+1=0.99 ctc_{t+1}=0.99\,c_t.

    Solution

    At tt, h=0.01tanh⁡(±0.5)h=0.01\tanh(\pm0.5), a gap of 0.01⋅2tanh⁡(0.5)=0.0092420.01\cdot2\tanh(0.5)=0.009242. A readout of hth_t sees runs that are almost identical.

    At t+1t+1 the cells are ±0.495\pm0.495, and h=0.99tanh⁡(±0.495)h=0.99\tanh(\pm0.495), a gap of 0.9071880.907188. The difference was in the cell all along. The output gate hid it for one step and then exposed it.

    So hth_t is a view of the cell through a gate, not the memory itself. A probe or classifier trained on hth_t can miss information the network will use one step later. To ask what an LSTM remembers, look at ct\vec c_t.

    I.10.X07The GRU state stays in the boxproof▲▲△

    Prove that a GRU in the form (I.10.7) keeps every coordinate of ht\vec h_t in [−1,1][-1,1] for all tt if h0\vec h_0 starts there. Then show the premise matters: start a coordinate at h0=3h_0=3 with z=0.5z=0.5 and candidate 00.

    Hint

    A convex combination of two numbers lies between them.

    Solution

    Fix a coordinate and write ht=z ht−1+(1−z)nh_t=z\,h_{t-1}+(1-z)n with z∈(0,1)z\in(0,1) and n=tanh⁡(⋅)∈(−1,1)n=\tanh(\cdot)\in(-1,1). By the triangle inequality,

    ∣ht∣≤z∣ht−1∣+(1−z)∣n∣≤max⁡(∣ht−1∣,∣n∣).|h_t|\leq z|h_{t-1}|+(1-z)|n|\leq\max(|h_{t-1}|,|n|).

    If ∣ht−1∣≤1|h_{t-1}|\leq1, the right-hand side is at most one, so ∣ht∣≤1|h_t|\leq1. Induction on tt from ∣h0∣≤1|h_0|\leq1 completes the proof. In fact ∣ht∣<1|h_t|<1 for t≥1t\geq1, since 1−z>01-z>0 and ∣n∣<1|n|<1.

    The argument uses the starting value. With h0=3h_0=3, z=0.5z=0.5 and n=0n=0 the states are 33, 1.51.5, 0.750.75, 0.3750.375: outside the box for one step, then inside. The same inequality shows ∣ht∣≤max⁡(∣h0∣,1)|h_t|\leq\max(|h_0|,1) in general.

    An LSTM has no such bound on ct\vec c_t, which is why I.10.T3 needs forget values below one for the cell.

    I.10.X08Chrono initialisationsymbolic▲▲△

    Show that the forget bias bf=ln⁡(m−1)b_f=\ln(m-1), with all forget weights zero, gives 1/(1−f)=m1/(1-f)=m exactly. Show that bi=−bfb_i=-b_f then makes each cell coordinate an exponential moving average of its candidates. Give bfb_f for m=2m=2, 1010 and 100100, and say what goes wrong at m=1m=1.

    Hint

    σ(ln⁡a)=a/(1+a)\sigma(\ln a)=a/(1+a) and σ(−a)=1−σ(a)\sigma(-a)=1-\sigma(a).

    Solution

    With bf=ln⁡(m−1)b_f=\ln(m-1), f=σ(ln⁡(m−1))=(m−1)/mf=\sigma(\ln(m-1))=(m-1)/m, so 1−f=1/m1-f=1/m and 1/(1−f)=m1/(1-f)=m. Equivalently, (I.10.5) gives 1+eln⁡(m−1)=m1+e^{\ln(m-1)}=m.

    With bi=−bfb_i=-b_f, i=σ(−bf)=1−fi=\sigma(-b_f)=1-f, so

    ct=f ct−1+(1−f) c~t,c_t=f\,c_{t-1}+(1-f)\,\tilde c_t,

    a weighted average whose weights sum to one: an exponential moving average of the candidates, with horizon set by mm.

    The biases are ln⁡1=0\ln1=0, ln⁡9=2.197225\ln9=2.197225 and ln⁡99=4.595120\ln99=4.595120. At m=1m=1 the formula needs ln⁡0\ln0: a horizon of one step would require f=0f=0, which no finite bias produces.

    Tallec and Ollivier draw bf=ln⁡ub_f=\ln u with uu uniform between 11 and Tmax⁡−1T_{\max}-1, so the initial horizons spread from two steps up to the longest dependency the task is expected to need.

    I.10.X09A forget gate of one half can still amplifycounterexample▲▲△

    A scalar LSTM has constant gates f=i=1/2f=i=1/2 and o=3/4o=3/4, zero input, and a candidate c~t=tanh⁡(3ht−1)\tilde c_t=\tanh(3h_{t-1}). The state c=h=0c=h=0 is a fixed point. Linearise around it, find the factor by which a small perturbation of cc grows per step, and estimate a perturbation of 10−610^{-6} after twenty steps. Does gating remove the need for gradient clipping?

    Hint

    Near zero, tanh⁡u≈u\tanh u\approx u. Then h=34tanh⁡c≈34ch=\tfrac34\tanh c\approx\tfrac34c.

    Solution

    Near the fixed point, ht−1≈34ct−1h_{t-1}\approx\tfrac34c_{t-1} and c~t≈3ht−1\tilde c_t\approx3h_{t-1}, so

    ct≈12ct−1+12⋅3⋅34ct−1=1.625 ct−1.c_t\approx\tfrac12c_{t-1}+\tfrac12\cdot3\cdot\tfrac34c_{t-1}=1.625\,c_{t-1}.

    The carry line contributes 0.50.5; the path through ht−1h_{t-1} and the candidate contributes 1.1251.125. A perturbation of 10−610^{-6} grows to about 10−6⋅1.62520=0.01648410^{-6}\cdot1.625^{20}=0.016484 after twenty steps; the script’s nonlinear run gives 0.0164800.016480, slightly less because tanh begins to bend.

    The same factor multiplies the backward signal, so the gradient through this cell grows like 1.625n1.625^n while the trajectory stays near the origin. A forget gate below one does not bound the total Jacobian. Clipping (I.9.7) remains a standard part of training gated networks.

    I.10.X10What backpropagation through time keepscomplexity▲▲△

    A batch of N=32N=32 sequences of length T=1000T=1000 trains a layer of width H=512H=512 in float32. Under the storage scheme of I.10.B05, how many bytes of activations does a plain tanh layer keep for the backward pass, and how many does an LSTM layer keep? How do both scale with TT, and what does inference need instead?

    Hint

    The plain cell stores one HH-vector per step and sequence; the LSTM stores six.

    Solution

    The plain layer stores 4NTH=65,536,0004NTH=65{,}536{,}000 bytes, 62.562.5 MiB. The LSTM stores six times as much, 393,216,000393{,}216{,}000 bytes, 375375 MiB. Both grow linearly in TT: doubling the sequence doubles the storage.

    Streaming inference keeps only the current state: ht\vec h_t for the plain cell, ht\vec h_t and ct\vec c_t for the LSTM, about 2NH2NH numbers, independent of TT. The distinction of I.9 holds for gated cells too: constant inference memory says nothing about training memory. Truncated backpropagation or checkpointing reduces the training figure at the costs I.9 described.