Skip to content

fix(nn): initialize random-signs batch-ensemble scaling in place - #498

Open
ChrisW09 wants to merge 2 commits into
mainfrom
fix/random-signs-init
Open

ChrisW09 wants to merge 2 commits into
mainfrom
fix/random-signs-init

Conversation

@ChrisW09

@ChrisW09 ChrisW09 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #497

Problem

The "random-signs" option of scaling_init was implemented as lambda x: torch.sign(torch.randn_like(x)). That lambda returns a new tensor, which reset_parameters throws away. The batch-ensemble scaling parameters r and s therefore kept the uninitialized torch.empty memory. That memory was all zeros in my runs, so the first TabM layer only output its bias and its shared weight matrix got no gradient. The same code is in LinearBatchEnsembleLayer, RNNBatchEnsembleLayer and MultiHeadAttentionBatchEnsemble.

Fix

A small in-place initializer, _random_signs_(tensor) in deeptab/nn/blocks/common.py, fills the tensor with -1/+1 under torch.no_grad(). Like the torch.nn.init functions it modifies its argument and returns it. The three scaling_init_fn tables use it in place of the lambda. "ones" and "normal" are unchanged.

Tests

  • tests/nn/blocks/test_common_blocks.py::TestRandomSignsScalingInit: for all three layers, r/s contain only -1 and +1. The test makes torch.empty return NaN-filled memory, so leftover zeros or uninitialized values can't pass by accident.
  • tests/architectures/test_architecture_contracts.py::test_tabm_random_signs_scaling_init_trains_first_layer: a TabM built with scaling_init="random-signs" has ±1 scaling factors, and the first layer's weight matrix gets a non-zero gradient.

All of these fail on main and pass with this change.

Docs

  • TabMConfig.scaling_init and the LinearBatchEnsembleLayer and RNNBatchEnsembleLayer docstrings describe the three options: 'ones' sets the scaling factors to 1, 'random-signs' draws each from {-1, +1}, and 'normal' draws them from N(0, 1). MultiHeadAttentionBatchEnsemble already did. LinearBatchEnsembleLayer's scaling_init annotation now includes "normal", which it already accepted.
  • docs/model_zoo/stable/tabm.md names the three initializations instead of "Diversity initialization for scaling factors".

Checks

  • just test: 3240 passed, 46 skipped, 28 xfailed; coverage 91.29%
  • just docs: build succeeded (warnings treated as errors)
  • just check: all hooks passed (ruff, prettier, pyright)

The "random-signs" entry of the scaling-init table built a new tensor with
torch.sign(torch.randn_like(x)) and discarded it, so the r/s scaling
parameters of LinearBatchEnsembleLayer, RNNBatchEnsembleLayer and
MultiHeadAttentionBatchEnsemble kept the uninitialized torch.empty memory
(often zeros, which blocks the gradient of the shared weight matrix).

Add an in-place _random_signs_ initializer that fills the tensor with
-1/+1 values, matching the other torch.nn.init entries.

Fixes #497
TabMConfig and the batch-ensemble layers now say what 'ones',
'random-signs' and 'normal' initialize the scaling factors to, and the
TabM page names the values. The TabM test checks |r| == 1 instead of
expecting both signs in a 4 x 3 tensor, which can draw a single sign.

Refs #497

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] scaling_init="random-signs" leaves batch-ensemble scaling factors uninitialized

1 participant