Fix CPM-Ant LM head tying (vocabulary-slice tie)
Author: jiqing-feng
Pull request: yes

## Problem

Loading `openbmb/cpm-ant-10b` fails in `tie_weights`:

```
NotImplementedError: aten::equal: attempted to run this operator with Meta tensors ...
```

and with `ignore_mismatched_sizes=True`, generation later fails:

```
RuntimeError: shape '[1, 92160]' is invalid for input of size 95232
```

## Cause

The input embedding carries extra soft-prompt rows:

```
input_embedding = (vocab_size + prompt_types * prompt_length, hidden)
                = (30720 + 32 * 32, 4096) = (31744, 4096)
```

The last 1024 rows are soft-prompt embeddings, never decoding targets, so the LM head
should be `vocab_size`-wide (30720). The model instead built a 31744-wide head and tied
the whole tensor:

```python
_tied_weights_keys = {"lm_head.weight": "cpmant.input_embedding.weight"}
self.lm_head = nn.Linear(hidden, vocab_size + prompt_types * prompt_length, bias=False)
```

Both released checkpoints (`openbmb/cpm-ant-10b`, `hf-internal-testing/cpm-ant-10b-testing`)
store `lm_head.weight` as `(30720, 4096)`, equal to `input_embedding.weight[:30720]`, and
omit it from the `*.index.json` weight map — the head is a vocab slice of the embedding,
derived by tying when absent. The old loader tolerated the size mismatch; the meta-device
loader does not.

## Fix

`src/transformers/models/cpmant/modeling_cpmant.py` only.

- Head sized to vocab: `nn.Linear(hidden, vocab_size, bias=False)`.
- Slice-tie in `tie_weights`, only when the checkpoint omits its own head:

```python
_tied_weights_keys = {}

def tie_weights(self, missing_keys=None, recompute_mapping=True):
    lm_head_missing = missing_keys is not None and "lm_head.weight" in missing_keys
    input_embeddings = self.get_input_embeddings()
    if (
        lm_head_missing
        and input_embeddings is not None
        and input_embeddings.weight.device.type != "meta"
        and self.lm_head.weight.device.type != "meta"
    ):
        self.lm_head.weight.data = input_embeddings.weight.data[: self.config.vocab_size].clone()
```

`_tied_weights_keys` is left empty because a whole-tensor mapping can't express a
shape-mismatched slice tie. The slice is `.clone()`d so the head keeps its own storage
instead of aliasing the embedding (see Tests).

## Reproduction

`repro_cpmant_lmhead.py`:

```python
import torch
from transformers import AutoModelForCausalLM, CpmAntTokenizer

model_id = "openbmb/cpm-ant-10b"  # requires the `rjieba` backend for the tokenizer
tok = CpmAntTokenizer.from_pretrained(model_id)
m = AutoModelForCausalLM.from_pretrained(model_id, dtype=torch.bfloat16).eval()

vocab = m.config.vocab_size
print("lm_head:", tuple(m.lm_head.weight.shape))            # (30720, 4096)
print("input_embedding:", tuple(m.cpmant.input_embedding.weight.shape))  # (31744, 4096)
print("slice-tied:", torch.equal(
    m.lm_head.weight.float(),
    m.cpmant.input_embedding.weight[:vocab].float(),
))                                                          # True

ids = tok(["Today is a good day"], return_tensors="pt")
out = m.generate(**ids, max_new_tokens=10, do_sample=False, num_beams=1, use_cache=False)
print(tok.decode(out[0]))

# checkpoint-without-head path: head is re-derived from the embedding slice
m.lm_head.weight.data.zero_()
m.tie_weights(missing_keys={"lm_head.weight"})
assert torch.equal(m.lm_head.weight.float(), m.cpmant.input_embedding.weight[:vocab].float())

# checkpoint-with-head path: an already-loaded head is preserved
m.lm_head.weight.data.fill_(0.5)
m.tie_weights(missing_keys=set())
assert torch.allclose(m.lm_head.weight, torch.full_like(m.lm_head.weight, 0.5))
print("ok")
```

Comments:
Thank you for your contribution 🤗!

## CI Security Gate — automatic approval blocked

This PR was **not** automatically approved for CI because the security gate failed.

**Possible reasons:**
- The PR touches 50 or more files — only PRs with fewer than 50 changed files are automatically approved
- A changed file is outside the allowed directories (`src/`, `tests/`, `docs/`, `utils/`), has a disallowed extension (only `.py`, `.txt`, `.md` permitted outside `tests/` and `docs/`), or is not `.md`/`.yml` inside `docs/`
- A new high-severity security issue was detected in the changed Python files (Bandit check)

See the [workflow run](https://github.com/huggingface/transformers/actions/runs/28011452115) for the exact violations.

A maintainer can review and manually approve CI if a finding is a false positive.

cc @arthurzucker for text models I think!

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

run-slow: cpmant

## Tests

`tests/models/cpmant/test_modeling_cpmant.py`: `create_and_check_lm_head_model` now
expects logits of width `vocab_size` (was `vocab_size + prompt_types * prompt_length`),
matching the vocab-sized head.

Two details keep the model suite green:

- The derived slice is `.clone()`d, not aliased. Aliasing makes `lm_head.weight` and
  `input_embedding.weight` share storage with no resolvable `_tied_weights_keys`, which
  trips `save_pretrained`'s shared-tensor check and breaks the save/load tests
  (`test_can_use_safetensors`, `test_load_save_without_tied_weights`,
  `test_model_weights_reload_no_missing_tied_weights`, etc.).
- `tie_weights` only derives the head when `missing_keys` explicitly lists it, so a
  checkpoint that ships its own `lm_head.weight` is left untouched.

Result: 69 passed, 127 skipped (integration tests are `@tooslow`).


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