A standard RNN has the form:
ht=tanh(Whhht−1+Wxhxt+bh)yt=Whyht+by
We want to minimize a loss over a sequence:
L=∑t=1TLt
where Lt is the loss at time step t (e.g., cross-entropy for classification).
Challenge: To update Whh, we need ∂Whh∂L. But Whh is used at every time step, so changes to it affect all future hidden states. The gradient must account for all paths through time.
Define δt=∂ht∂L (the gradient w.r.t. the post-activation hidden state). Then:
δt=∂ht∂Lt+∂ht+1∂L⋅∂ht∂ht+1=∂ht∂Lt+δt+1⋅∂ht∂ht+1
Why this step? Gradient at ht has two sources: the immediate loss Lt and the future loss propagated back from ht+1.
For the RNN update rule, let at+1=Whhht+Wxhxt+1+bh be the pre-activation, so ht+1=tanh(at+1):
∂ht∂ht+1=diag(1−tanh2(at+1))⋅Whh=diag(1−ht+12)⋅Whh
Why this step? Derivative of tanh is 1−tanh2, and ht+1 is computed as tanh(linear combination involving ht). The Jacobian is diagonal (elementwise nonlinearity) times Whh.
The weight Whh enters the pre-activationat=Whhht−1+…, and ht=tanh(at). So the local gradient w.r.t. Whh at step tmust include the tanh derivative:
∂Whh∂Lt=(δt⊙(1−ht2))ht−1T
Why this step?δt=∂L/∂ht is post-activation. To reach Whh we pass through the tanh: ∂ht/∂at=diag(1−ht2), and ∂at/∂Whh=ht−1T. Skipping the (1−ht2) term is a common bug.
Defining the pre-activation gradientδ^t=δt⊙(1−ht2), the accumulated gradient is:
The BPTT Algorithm:
Forward pass: Compute h1,…,hT and losses L1,…,LT.
Backward pass: Initialize δT, then for t=T−1 down to 1, compute δt recursively.
Why this step? Each time step contributes δ^t⋅ht−1 (pre-activation gradient times the incoming hidden state). The t=2 term is 0.4068⋅(1−0.70682)⋅0.7616≈0.155 — not0.310. Forgetting the (1−ht2) factor doubles the answer here; that is the classic error.
For long sequences, storing all hidden states and computing exact gradients is memory-intensive. Truncated BPTT splits the sequence into chunks of length k:
Forward pass for k steps.
Backward pass for those k steps only.
Detach the gradient and continue forward for the next k steps.
Trade-off: Gradients cannot propagate beyond k steps, limiting the model's ability to learn long-range dependencies. But it reduces memory from O(T) to O(k).
Formula:
∂Whh∂L≈∑t=t0t0+kδ^tht−1T
where t0 is the start of the current chunk.
Recall Explain to a 12-Year-Old
Imagine you're learning to play a song on the piano. The song has 100 notes, and you want to get better.
Normal learning (feedforward): You play one note, your teacher corrects you, you move to the next note. Each note is independent.
Recurrent learning (RNN): Each note you play depends on the previous notes. If you mess up note 50, it affects notes 51, 52, ..., 100. To learn, you need to figure out how each note contributed to the final mistake.
Backpropagation through time: After playing all 100 notes, you "rewind" the song and ask: "How did note 1 affect the final sound?" You trace backward: note 100 depended on 99, which depended on 98, .., back to note 1. You adjust how you played note 1 based on the entire chain of effects.
The problem: the further back you go, the fuzzier your memory of what happened (vanishing gradients). That's why RNNs struggle with long songs (sequences). LSTMs are like taking better notes so you remember earlier parts clearly.
Dekho, RNN mein ek hi weight matrix Whh har time step pe baar baar use hota hai — yahi core cheez hai. Ab problem yeh hai ki jab hum gradient calculate karte hain training ke liye, tab yeh shared weight future ke saare hidden states ko affect karta hai. Toh idea yeh hai ki hum RNN ko "unroll" karte hain — matlab time ke har step ko ek alag layer ki tarah imagine karte hain, jaise ek bahut deep feedforward network ho jismein saari layers same weights share karti hain. Isiliye iska naam hai "Backpropagation Through Time" — kyunki gradient time steps ke through peeche flow karta hai. Simple words mein: temporal recurrence ko spatial depth ki tarah treat kar rahe hain.
Ab why-it-matters wala part. Chain rule apply karte waqt, kisi bhi time t pe gradient ke do sources hote hain — ek immediate loss Lt jo abhi ke output se aata hai, aur doosra future se aane wala gradient jo ht+1 ke through back-propagate hota hai. Isko hum recursively likhte hain as δt, aur har step pe WhhT aur tanh ka derivative (1−h2) multiply hota hai. Yeh jo repeated multiplication hai, wahi asli kahani hai — kyunki agar yeh factors baar-baar chhote hote gaye toh gradient vanish ho jaata hai (long-term memory nahi bachti), aur agar bade ho gaye toh explode ho jaata hai. Isi vanishing/exploding gradient problem ki wajah se aage chalke LSTM aur GRU jaise architectures invent huye.
Toh bhai, BPTT samajhna isliye zaroori hai kyunki yeh foundation hai — jab tak tumhe yeh clear nahi hoga ki gradient time ke through kaise flow karta hai aur kyun weak ya explode hota hai, tab tak tum yeh appreciate nahi kar paoge ki modern sequence models (LSTM, attention, transformers) yeh saari problems kaise solve karte hain. Ek chhoti si tip: notation mein confuse mat hona — Whh hamesha hidden-to-hidden hai, aur yahi wala matrix time ke across shared hota hai, isko baaki Wxh aur Why se alag rakhna.