Fix device_map="auto" under-packing that spills quantized models to cpu (#46823)
Author: dhruv7477
Pull request: yes

<!-- ci-dashboard-badge:start -->
[![CI](https://transformers-ci.lor-e.huggingface.cool/badge/pr?pr=47061)](https://transformers-ci.lor-e.huggingface.cool/d/pytest-observability-by-pr/pytest-observability-branch?var-pr=47061)
<!-- ci-dashboard-badge:end -->

# What does this PR do?

Fixes #46823

`load_in_4bit` + `device_map="auto"` + an explicit, ample `max_memory` could still dispatch modules to CPU and fail with `Some modules are dispatched on the CPU or the disk...`.

**Root cause** (all in `integrations/accelerate.py`, reproducible CPU-only on a meta model):
`get_balanced_memory` caps every GPU except the last at `total/num_gpus + 1.25 × buffer`, but the buffer only measured `_no_split_modules`. The packing in `infer_auto_device_map`, however, treats any childless module (e.g. `embed_tokens`, `lm_head` — which quantization does not shrink) as an un-splittable atom, and it never returns to a device it has skipped. A single leaf bigger than the balanced caps therefore skipped GPUs 0..n-2 permanently, the whole model collapsed onto the last GPU (the only one keeping the full user budget) and then spilled to cpu — with most GPUs empty. In my repro this raised the ValueError with the total GPU budget at **6×** the model size.

**Fix:**
- Size the buffer in `get_balanced_memory` with the same largest-atom helper the packing step uses for its own reservation (`get_max_layer_size`), so per-device caps are never smaller than a placeable atom. The repro then places cleanly at 6×/3×/2× budgets (all previously raised). 
- Warn when accelerators were requested but the final map places everything on cpu/disk — this previously passed silently (the quantizer check only rejects *mixed* cpu/gpu maps).

**Known limitation** (pre-existing, unchanged): the packing walks devices monotonically, so the first device can still end up idle when the first treated module exceeds its cap minus the largest-layer reservation. Fixing that needs backtracking in the packer — out of scope here.

## Tests

`tests/utils/test_device_map.py` (new): a structural regression test (no bitsandbytes required) and the literal issue scenario gated on `require_bitsandbytes` — both run on CPU via fake `max_memory` devices, both fail without the fix and pass with it.

## Who can review?

@SunMarc @Cyrilvallez

Comments:
Note on CI: the 6 failing `tests/cli` tests are unrelated to this diff — they are the repo-wide breakage from `huggingface_hub 1.22.0` tracked in #47059 (`typer_factory` now returns an `HFCliTyperGroup`, which `typer.testing.CliRunner` can't drive). They fail identically on clean `main`. The `tests/utils/test_device_map.py` tests added here pass, including under `huggingface_hub 1.22.0`.

Fixes #46823.

<!-- ci-dashboard-recap:start -->

---

### CI recap

**Dashboard:** [View test results in Grafana](https://transformers-ci.lor-e.huggingface.cool/d/pytest-observability-by-pr/pytest-observability-branch?var-pr=47061)
**Latest run:** [28855723630:2](https://github.com/huggingface/transformers/actions/runs/28855723630)
**Result:** `success` | **Jobs:** 15 | **Tests:** 172,284 | **Failures:** 0 | **Duration:** 23h 14m

<!-- ci-dashboard-recap:end -->

@SunMarc @Cyrilvallez Ready for review CI is green after updating over the `tests/cli` fix (#47064).

Recap: `get_balanced_memory` sized its per-device caps only from `_no_split_modules`, while `infer_auto_device_map` treats any large childless module (e.g. embeddings, which quantization doesn't shrink) as an un-splittable atom and never returns to a skipped device, so a single big leaf collapsed the whole placement onto the last GPU and then cpu, failing 4-bit loads whose explicit `max_memory` budget fit the model several times over. The fix sizes the caps with the same largest-atom helper the packer uses, plus a warning for the previously silent all-CPU map. CPU-only regression tests included (verified to fail without the fix).

Superseded by https://github.com/huggingface/transformers/pull/47203 with the correct fix