Don't pin the gated delta net norm to `cuda:0` with a hardcoded device
Author: Sunt-ing
Pull request: yes


# What does this PR do?

The gated RMSNorm inside the GDN (gated delta net) mixer is built with `device=torch.cuda.current_device()` hardcoded. When a CUDA device is present and `flash-linear-attention` is installed (so the `FusedRMSNormGated` branch is taken), every other submodule is built on the intended/default device but this one norm is forced onto `cuda:0`, regardless of where the module is being constructed.

So a plain `Qwen3NextForCausalLM(config)` (no `device_map`, no `.to()`, default CPU placement) ends up with 33 params on CPU and the single `model.layers.0.linear_attn.norm.weight` stranded on `cuda:0`. A subsequent CPU (or `cuda:1`) forward then hits a device mismatch at that norm. The fix is to drop the `device=` argument so the norm is placed by the normal loading/`.to()`/`device_map` path like every sibling submodule.

The same hardcode appears in four models. `qwen3_5` and `qwen3_5_moe` inherit the GDN mixer from `qwen3_next` via `modular`, and `olmo_hybrid` has its own copy, so the source change is in two `modular_*.py` files and `make fix-repo` regenerates the four `modeling_*.py` files (6 files, one deleted line each).

Reproduced on an RTX 4090. Same script, only the fix differs; the `FusedRMSNormGated` branch is exercised in both runs, so the fix changes placement, not which branch runs:

| | norm class | `norm.weight.device` | param devices |
|---|---|---|---|
| before | `FusedRMSNormGated` | `cuda:0` | `{'cpu': 33, 'cuda:0': 1}`, stranded |
| after | `FusedRMSNormGated` | `cpu` | `{'cpu': 34}` |

Severity is bounded and worth stating: a CPU-only host (`CUDA_VISIBLE_DEVICES=""`) takes the non-fused branch and is unaffected; a default `from_pretrained` loads the norm onto the target device and masks the strand; and a full `model.to(device)` afterwards corrects the placement. The bug bites when a CUDA device is present, `flash-linear-attention` is installed, and the model is built plainly (direct instantiation / training) and then used on a non-`cuda:0` device without an intervening whole-model `.to()`.

<details>
<summary>Reproducer (script + before/after output + environment)</summary>

Environment: RTX 4090, transformers @ 13a3042973, torch 2.8.0+cu128, flash-linear-attention 0.5.0.

```python
import importlib, torch
from transformers.utils.import_utils import is_flash_linear_attention_available
from transformers.models.qwen3_next.modeling_qwen3_next import Qwen3NextForCausalLM
import transformers.models.qwen3_next.modeling_qwen3_next as mod

assert torch.cuda.is_available()
assert is_flash_linear_attention_available()
print("FusedRMSNormGated:", getattr(mod, "FusedRMSNormGated", "MISSING"))

# legal config from the model's own tester (no hand-rolled tiny config)
m = importlib.import_module("tests.models.qwen3_next.test_modeling_qwen3_next")
tester_cls = next(getattr(m, n) for n in dir(m)
                  if n.endswith("ModelTester") and isinstance(getattr(m, n), type)
                  and getattr(m, n).__module__ == m.__name__)
config, _ = tester_cls(parent=None).prepare_config_and_inputs_for_common()

# plain construction; intended placement is the default (cpu)
model = Qwen3NextForCausalLM(config)
norm = model.model.layers[0].linear_attn.norm
print("norm class:", type(norm).__name__)
print("norm.weight.device:", norm.weight.device)

by_dev = {}
for name, p in model.named_parameters():
    by_dev.setdefault(str(p.device), []).append(name)
print("param device -> count:", {k: len(v) for k, v in by_dev.items()})
for dev, names in by_dev.items():
    if dev != "cpu":
        print(f"STRANDED on {dev}: {names}")
```

Before:
```
FusedRMSNormGated: <class 'fla.modules.fused_norm_gate.FusedRMSNormGated'>
norm class: FusedRMSNormGated
norm.weight.device: cuda:0
param device -> count: {'cpu': 33, 'cuda:0': 1}
STRANDED on cuda:0: ['model.layers.0.linear_attn.norm.weight']
```

After:
```
FusedRMSNormGated: <class 'fla.modules.fused_norm_gate.FusedRMSNormGated'>
norm class: FusedRMSNormGated
norm.weight.device: cpu
param device -> count: {'cpu': 34}
```

</details>

## Code Agent Policy

- [x] I confirm that this is not a pure code agent PR.

## Before submitting
- [ ] This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
- [x] Did you read the [contributor guideline](https://huggingface.co/docs/transformers/contributing) and the [Pull Request](https://huggingface.co/docs/transformers/pr_checks) checks?
- [ ] Was this discussed/approved via a Github issue or the [forum](https://discuss.huggingface.co/)? Please add a link to it if that's the case.
- [ ] Did you make sure to update the documentation with your changes according to the [guidelines](https://github.com/huggingface/transformers/tree/main/docs)?
- [ ] Did you write any new necessary [tests](https://huggingface.co/docs/transformers/testing)?

## Who can review?

@Cyrilvallez @vasqu



Comments:
**[For maintainers]** Suggested jobs to run (before merge)

run-slow: olmo_hybrid, qwen3_5, qwen3_5_moe, qwen3_next

**CI Dashboard:** [View test results in Grafana](https://transformers-ci.lor-e.huggingface.cool/d/pytest-observability-by-pr/pytest-observability-branch?var-pr=46817)

> from_pretrained's default low_cpu_mem_usage=True (accelerate init_empty_weights) sends the norm to meta and masks it

is a weird statement tho since we don't even use `low_cpu_mem_usage` anymore

Good catch, dropped it from the description. 

The masking does still hold, just through the normal loading path rather than that flag: on the buggy code, plain `Model(config)` strands the norm on `cuda:0`, but a default `from_pretrained` loads it onto the target device with no strand (all params on cpu). So it only bites direct `Model(config)` construction / training from scratch, not `from_pretrained` users, and dropping `device=` lets the norm follow the same placement as every sibling submodule either way.