[nemotron_h] respect _no_reinit flag on dt_bias and out_proj.weight (#45591)
* [nemotron_h] respect _no_reinit flag on dt_bias and out_proj.weight
_init_weights() on `NemotronHPreTrainedModel` unconditionally overwrites
`dt_bias` (random `inv_softplus(dt)`) and `out_proj.weight` (kaiming_uniform
scaled by 1/sqrt(n_layer)) every time it is invoked on a mamba block.
It sets `module.dt_bias._no_reinit = True` after the copy, but the flag is
never checked by either code path (only the Linear-bias branch reads it).
On transformers>=5.0, `_init_weights` is triggered a second time after
`from_pretrained()` has loaded the checkpoint (the post-load safety pass
that initializes tensors staying on `meta`). For `NemotronHForCausalLM`
that silently overwrites the checkpoint values for `dt_bias` and
`out_proj.weight` with fresh random draws. The model then outputs
repetitive stop-word streams like ` and and and and ,` for any input.
Minimal repro with any Nemotron-H checkpoint:
from transformers import AutoConfig, AutoModelForCausalLM
from safetensors.torch import load_file
import json, pathlib
path = ".../NVIDIA-Nemotron-Cascade-2-30B-A3B-BF16" # or Nano
cfg = AutoConfig.from_pretrained(path); cfg._attn_implementation='eager'
m = AutoModelForCausalLM.from_pretrained(path, config=cfg, torch_dtype='bfloat16')
idx = json.loads((pathlib.Path(path) / 'model.safetensors.index.json').read_text())['weight_map']
k = 'backbone.layers.0.mixer.dt_bias'
on_disk = load_file(f'{path}/{idx[k]}')[k]
in_mem = m.backbone.layers[0].mixer.dt_bias
print((on_disk.float() - in_mem.float().cpu()).abs().max()) # ~26.8
This patch makes `_init_weights` honour `_no_reinit` on both `dt_bias` and
`out_proj.weight` (the only two params that re-init unconditionally), and
sets `_no_reinit = True` on `out_proj.weight` after the initial kaiming
scale so a second pass is a no-op. Ordinary fresh-init training is
unaffected; only the second invocation becomes idempotent.
Signed-off-by: Min Zhou <minzhou@virtueai.com>
* Switch to canonical _is_hf_initialized flag per review
Per @Rocketknight1's review: replace the ad-hoc `_no_reinit` flag with the
existing `_is_hf_initialized` flag that `from_pretrained` already sets on
checkpoint-loaded parameters. Guard each Mamba2 init target
(A_log / D / dt_bias) and the residual-scaled `out_proj.weight`
independently, so parameters restored from a checkpoint survive any
subsequent `_init_weights` pass.
* Use _is_hf_initialized for nn.Linear.bias check too
---------
Signed-off-by: Min Zhou <minzhou@virtueai.com>