Fix numerical instability in A_log during training (closes #72) - #996
Open
KakashiTech wants to merge 1 commit into
Open
Fix numerical instability in A_log during training (closes #72)#996KakashiTech wants to merge 1 commit into
KakashiTech wants to merge 1 commit into
Conversation
…es#72) A = -exp(A_log) can approach 0 when A_log drifts toward -inf during training with Adam. This turns the SSM recurrence into a pure accumulator, causing hidden state overflow and NaN loss after many epochs. The gradient chain: dL/dA_log = dL/dA -exp(A_log) = dL/dA A. Since A < 0, sign(dL/dA_log) = -sign(dL/dA). When the model needs weaker decay (A -> 0) to propagate long-range information, dL/dA < 0, giving dL/dA_log > 0 which pushes A_log consistently toward -inf. Fix: torch.clamp(A, max=-1e-4) guarantees |A| >= 1e-4, preventing the accumulator regime while preserving long-range memory (tau <= 2500 steps). Consistent with Mamba3 which already uses A_floor clamping for the same numerical stability reason.
Author
|
@aakashlahoti Could you take a look when you have a chance? This fixes the A_log drift issue (#72) with the same clamp pattern Mamba-3 already uses for A_floor. Only 5 lines changed across 3 files. |
Contributor
|
curious if clamping a_log changes trained checkpoints — maybe gate it behind a flag or only apply when training from scratch? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
The SSM recurrence uses
A = -exp(A_log)whereA_logis a learnable parameter. During training with Adam, the gradientdL/dA_log = dL/dA · (-exp(A_log)) = dL/dA · A. SinceA < 0always,sign(dL/dA_log) = -sign(dL/dA).When the model needs to propagate information over long distances, it requires weaker decay (
A → 0). This createsdL/dA < 0, which translates todL/dA_log > 0, pushing A_log toward-inf. ConsequentlyA = -exp(A_log) → 0⁻,deltaA = exp(dt·A) → 1, and the SSM becomes a pure accumulator. The hidden state grows unbounded and overflows fp16 → NaN loss.This reproduces after 100–750 epochs of normal fp16 training with Adam at default LR, matching all reports in #72.
Fix
Guarantees
|A| ≥ 1e-4at all times, ensuring the SSM always has minimum decay. The gradient naturally stops flowing through the clamp when A hits the boundary.Why -1e-4?
|A| = 1e-4withdt ≈ 4:exp(dt·A) ≈ 0.9996, time constant ≈ 2500 steps, comfortably exceeding typical sequence length 2048.|A| = 1e-6) barely decay over 2048 steps — still practically an accumulator.|A| = 1e-2) cap long-range memory unnecessarily.Verification
[-2.4e-6, -3.0e-7](essentially 0). With fix, A stays at-1e-4.|A|=2.0→max|h|=0.05(safe).|A|=1e-4→max|h|=4.3(safe).|A|=1e-6→ hidden state grows unbounded.Impact
-[1..d_state], well below the-1e-4boundary. Only catches pathological drift.torch.clamp(_A, max=-self.A_floor)for the same reason.Files changed
mamba_ssm/modules/mamba_simple.py— forward + step (2 locations)mamba_ssm/modules/mamba2.py— forward + step (2 locations)mamba_ssm/modules/mamba2_simple.py— forward (1 location)5 insertions total.