Default Gemma4 processor text padding to False (align with Gemma3 / Qwen3-VL)
Author: yuvrajsharma9981
Pull request: yes

## Summary

`Gemma4ProcessorKwargs._defaults["text_kwargs"]["padding"]` defaults to `True`. So any batched call to the Gemma4 processor (`apply_chat_template` / `__call__`) that doesn't explicitly pass `padding` pads every sequence in the batch up to the batch's longest (and up to `max_length` when truncation is on and a row reaches it).

Every sibling multimodal processor defaults this to `False` — including Gemma4's immediate predecessor, Gemma3. Gemma4 is the only one shipping `True`.

## Why `False` is the correct default

Padding is a **batching** concern, not a tokenization concern. The right place to pad is **dynamically, per-batch, at train/inference time** — which is exactly what `DataCollatorWithPadding` / `return_tensors` do: pad each batch to its own longest sequence, nothing wasted. Tokenization — especially when caching a dataset via `datasets.map(...)` — should emit **ragged** sequences and leave padding to the collator. A processor should pad at tokenization time **only when the caller explicitly asks**.

That is the established default for the other processors; Gemma4 is the outlier:

| Processor | `text_kwargs["padding"]` default |
|---|---|
| `Gemma3Processor` | `False` |
| `Qwen3VLProcessor` | `False` |
| **`Gemma4Processor`** | **`True`**  ← outlier |

## Impact

Because it pads at tokenization time, tokenizing a dataset in batches — e.g. `datasets.map(batched=True)` (default batch size 1000) — bakes padding into the **cached** dataset: every row is padded to its map-chunk's longest sequence, permanently.

Same real text-classification dataset (~2.6M short rows, `max_length=2048`), tokenized two ways — the bare tokenizer vs the processor as the training pipeline calls it (batched):

| Model | path | mean | median | p90 | p99 | total tokens |
|---|---|---:|---:|---:|---:|---:|
| gemma-3-4b | tokenizer | 208 | 163 | 400 | 695 | 537.6M |
| gemma-3-4b | processor | 207 | 162 | 399 | 694 | 535.0M |
| qwen3.5-4b | tokenizer | 232 | 174 | 439 | 1044 | 601.4M |
| qwen3.5-4b | processor | 232 | 174 | 439 | 1044 | 601.4M |
| **gemma-4-e2b** | tokenizer | 211 | 166 | 403 | 698 | 545.4M |
| **gemma-4-e2b** | **processor** | **1479** | **1401** | **2048** | **2048** | **3.83B** |

The bare-tokenizer column shows the actual content is the same size across all three models (~210–230 tokens). For Gemma3 and Qwen3-VL the processor output equals the tokenizer output — no padding. For Gemma4 the processor inflates it **~7×** (mean 211 → 1479, total 0.55B → 3.83B), entirely padding, which makes fine-tuning ~5–7× slower — silently, since nothing errors.

## Fix

Default `text_kwargs["padding"]` to `False` in `Gemma4ProcessorKwargs`, matching Gemma3 and Qwen3-VL. Callers that want padding can still pass it explicitly.

`gemma4_unified` inherits this processor through the modular system, so its generated `processing_gemma4_unified.py` is regenerated via `make fix-repo` to carry the same default — hence the two-file diff.

## Multimodal safety

This default affects **text** padding only. Image/audio placeholder expansion happens on the raw strings *before* tokenization (`get_text_with_replacements`), and `create_mm_token_type_ids` iterates per-sequence and explicitly supports unpadded variable-length input — so flipping the default does not affect image/audio token alignment. Audio uses its own `audio_kwargs`, independent of text padding.

## Tests

`tests/models/gemma4/test_processing_gemma4.py`: **45 passed, 13 skipped** — identical to `main` before the change. The only failures are pre-existing, environment-dependent optional-backend issues present on unchanged `main` as well (`librosa` for audio, `torchvision.io.read_video` / `torchcodec` for video), unrelated to this change.


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

run-slow: gemma4, gemma4_unified

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