fix: AuxK loss carries no gradient, now backprop combined loss, not reconstruction only#3
Open
SohrabTa wants to merge 1 commit into
Open
Conversation
…on only _calculate_loss_and_log builds loss = reconstruction_loss + lambda_aux * aux_loss but returns reconstruction_loss for backprop in both branches, so the AuxK dead-latent revival term never contributes a gradient. Return the combined loss so the auxiliary loss is actually optimized. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
The TopK / BatchTopK / GroupMax trainer computes the combined loss
loss = reconstruction_loss + lambda_aux * aux_loss, but_calculate_loss_and_logreturnsreconstruction_loss(notloss) in both the logging and non-logging branches. The returned tensor is the one that gets.backward()called on it (base_acausal_trainer.run_batch→base_trainer'sloss.div(grad_accum).backward()), so the AuxK dead-latent revival term never contributes any gradient. The auxiliary loss is logged to W&B but is effectively inert, since it does nothing to revive dead latents.Fix
Return
loss(the combined reconstruction + AuxK loss) in both branches so the auxiliary term is actually optimized. Two-line change and logging is unaffected.How we found it
We forked this repo to train Anthropic-style sparse crosscoders on the residual-stream activations of ProtT5 (a protein language model) for a research project on disentangling and interpreting its internal representations. When we inspected our dead-latent counts, they stayed stubbornly high throughout training even though
train/aux_losswas being logged, but it kept increasing. Tracing the loss that reaches.backward()showed the AuxK term was logged but never backpropped and the returned tensor wasreconstruction_loss, solambda_aux * aux_losswas dropped from the gradient. The symptom (AuxK appears active in logs but has zero effect on dead latents) makes this easy to miss without following the exact tensor that gets differentiated.Testing
Verified the combined loss now flows to backprop and that
train/loss,train/reconstruction_loss, andtrain/aux_losslogging is unchanged. We are re-running our full crosscoder training pipeline with this fix.