项目文件夹

文件
wehub-resource-sync 542cfa195c
CI / Frontend build (push) Failing after 9m6s
CI / Plugin validate (push) Failing after 9m27s
CI / Python lint (push) Failing after 16m1s
CI / Tests (push) Successful in 18m0s
Deploy / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:27 +08:00

143 行
7.5 KiB
Markdown

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# Compressed-image SFT — Final Results
**Target:** maximize GPT-4.1 LLM-judge accuracy on `test_hn_with_answer.jsonl` (500 examples) for Qwen3-VL-4B under 2x / 3x / 5x / 9x pixel compression, **without inflating visual-token count at inference**.
**Judge:** `gpt-4.1-2025-04-14`, SimpleQA A/B/C template (`sft/eval_baseline.py`).
## Headline table
| Compression | base (no SFT) | best specialized | best universal (one adapter) | specialized config |
|---|---|---|---|---|
| **0x** (original) | **0.958** | — | — | ceiling |
| **2x** | 0.904 | **0.948** | 0.940 | r=128, 2ep, lr 2e-5 (LLM-only sufficient) |
| **3x** | 0.826 | **0.894** | 0.892 | r=256, 1ep, lr 1e-5, LLM+ViT |
| **5x** | 0.554 | **0.730** | 0.692 | r=128, 2ep, lr 3e-5, LLM+ViT |
| **9x** | 0.180 | **0.378** | 0.302 | r=512, 2ep, lr 1e-5, LLM+ViT |
Universal adapter is within **0.2–7.6 points** of each specialized adapter — at 3x essentially tied, at 9x still meaningfully behind.
## Key breakthrough: unfreezing the ViT
`lora_target: all` alone does **not** train the ViT in LlamaFactory — `freeze_vision_tower: true` is the default. Setting it to `false` unlocks LoRA on the ViT and gives big jumps at high compression:
| Compression | LLM-only | LLM+ViT | Δ |
|---|---|---|---|
| 2x | 0.948 | 0.948 | 0 |
| 3x | 0.882 | 0.894 | +1.2 |
| 5x | 0.634 | 0.730 | **+9.6** |
| 9x | 0.272 | 0.378 | **+8.2** |
**Rule:** the harder the compression, the more the ViT needs adaptation. 2x base is already near-ceiling so ViT LoRA adds nothing; 9x has the most distribution shift from pretraining so ViT capacity helps most (+30% relative).
## What worked
1. **LoRA + ViT unfrozen** → primary mechanism for 5x/9x gains.
2. **Bigger LoRA rank at high compression**: 9x went r=32→128→256→512 for +2.4, +1.2, +0.8, +0.8 (diminishing but monotonic).
3. **Mixed-compression training** (universal adapter): single LoRA trained on 2x+3x+5x+9x samples simultaneously. With r=256 + ViT unfrozen, the gap to specialized is only 0.2–7.6 points.
4. **Two epochs** at 2x/3x/5x; **one epoch** at 9x (overfits faster with bigger rank).
## What did not work
| Experiment | Outcome |
|---|---|
| **Full FT** (lr 1e-5) at 5x/9x | grad_norm 10+, output collapses (empty strings, `0000` artifacts). 9x fell to 0.176, below base 0.180. LoRA's implicit regularization wins. |
| **Pre-upscaling 9x → original dim** before ViT | Gives big accuracy boost (EM 0.78) but inflates visual tokens ~9×, defeating the compression use case. **Rejected.** |
| **LoRA dropout 0.1 at 9x** | No change in ceiling (~0.27). |
| **More epochs (3+)** at 5x | 0.620 at 3ep < 0.634 at 2ep. Overfit. |
| **Rank 256 at 5x** | 0.656 < 0.730 at r=128. Capacity saturated at r=128 for 5x. |
| **Think / CoT training** (30k GPT-generated reasoning traces, `<think>reasoning</think>answer` targets) | 9x peak 0.286 < non-think 0.378. Traces generated blindly by GPT (no image) produce plausible-but-wrong reasoning at 9x where the image is unreadable. Model learns to fabricate confident reasoning that doesn't help the final answer. |
## Compression-damage vs SFT-recovery
```
0x : ██████████████████████████████████████████ 0.958 (ceiling)
2x : ███████████████████████████████████████▏ 0.904 → SFT 0.948 (1.0 gap, 81% recovered)
3x : ████████████████████████████████████ 0.826 → SFT 0.894 (6.4 gap, 52% recovered)
5x : ████████████████████████ 0.554 → SFT 0.730 (22.8 gap, 44% recovered)
9x : ███████▌ 0.180 → SFT 0.378 (58.0 gap, 25% recovered)
```
SFT recovery at 2x/3x: 50-80%. At 5x/9x: 25-44% — residual gap is the physical compression limit the ViT can't undo.
## Full experiment matrix
### 2x
| run | r | ep | lr | ViT | LLM-judge peak |
|---|---|---|---|---|---|
| base | — | — | — | — | 0.904 |
| v1 (LLM-only) | 128 | 2 | 2e-5 | frozen | **0.948** |
| llmvit-v1 | 128 | 2 | 2e-5 | trained | 0.948 (tied) |
### 3x
| run | r | ep | lr | ViT | peak |
|---|---|---|---|---|---|
| base | — | — | — | — | 0.826 |
| v1 | 32 | 1 | 1e-5 | frozen | 0.854 |
| v2 | 128 | 2 | 2e-5 | frozen | 0.878 |
| v3 | 256 | 2 | 2e-5 | frozen | 0.882 |
| llmvit-v1 | 256 | 2 | 2e-5 | trained | 0.884 (then collapsed) |
| llmvit-v2 | 256 | 1 | 1e-5 | trained | **0.894** |
### 5x
| run | r | ep | lr | ViT | peak |
|---|---|---|---|---|---|
| base | — | — | — | — | 0.554 |
| v1 | 32 | 1 | 1e-5 | frozen | 0.598 |
| v2 | 32 | 2 | 2e-5 | frozen | 0.628 |
| v3 | 128 | 2 | 3e-5 | frozen | 0.634 |
| v4 | 256 | 2 | 2e-5 | frozen | 0.620 |
| v5 | 128 | 3 | 3e-5 | frozen | 0.620 |
| fullft | — | 1 | 1e-5 | n/a | 0.562 (bad) |
| llmvit-v1 | 128 | 2 | 3e-5 | trained | **0.730** |
| llmvit-v2 | 256 | 2 | 2e-5 | trained | 0.656 |
### 9x
| run | r | ep | lr | ViT | peak |
|---|---|---|---|---|---|
| base | — | — | — | — | 0.180 |
| v1 | 32 | 1 | 1e-5 | frozen | 0.228 |
| v2 | 128 | 2 | 3e-5 | frozen | 0.252 |
| v3 | 256 | 1 | 2e-5 | frozen | 0.264 |
| v4 | 512 | 1 | 1.5e-5 | frozen | 0.272 |
| v5 | 256 | 2 | 1e-5 dropout 0.1 | frozen | 0.266 |
| fullft | — | 1 | 1e-5 | n/a | 0.176 (broken) |
| llmvit-v1 | 256 | 1 | 2e-5 | trained | 0.354 |
| llmvit-v2 | 512 | 2 | 1e-5 | trained | **0.378** |
| think-v1 | 256 | 2 | 1e-5 | trained (+think) | 0.286 (worse) |
### Universal (one adapter for all compressions)
Trained on concatenated 2x+3x+5x+9x data (416k examples, 1 epoch).
| run | r | lr | ViT | 2x | 3x | 5x | 9x |
|---|---|---|---|---|---|---|---|
| v1 | 128 | 2e-5 | frozen | 0.924 | 0.862 | 0.620 | 0.250 |
| llmvit-v1 | 128 | 2e-5 | trained | 0.920 | 0.844 | 0.664 | 0.272 |
| **llmvit-v2** | **256** | **1e-5** | **trained** | **0.940** | **0.892** | **0.692** | **0.302** |
## Shipped artifacts (HuggingFace)
Five LoRA adapters pushed to [Chrisyichuan](https://huggingface.co/Chrisyichuan):
- `qwen3vl-4b-wiki-screenshot-2x-lora` — 0.948 at 2x
- `qwen3vl-4b-wiki-screenshot-3x-lora` — 0.894 at 3x
- `qwen3vl-4b-wiki-screenshot-5x-lora` — 0.730 at 5x
- `qwen3vl-4b-wiki-screenshot-9x-lora` — 0.378 at 9x
- `qwen3vl-4b-wiki-screenshot-universal-lora` — one LoRA, 0.940/0.892/0.692/0.302 across all four compressions
## Practical recommendation
For most deployments, ship the **universal adapter**: 1.28 GB LoRA, one merge at load time, handles any of 2x/3x/5x/9x with near-specialized accuracy (within 0.2–7.6 LLM-judge points). If you know you'll only ever serve a specific compression level, use the specialized adapter for that level.
For 2x/3x the adapters are essentially production-ready (<10 point drop from uncompressed). 5x is usable when accuracy tolerance is moderate. 9x remains difficult — 0.378 is still far from the 0.958 ceiling, and this is dominated by the physical unreadability of 9×-compressed text rather than a capacity bottleneck we can solve with more training.
## Files
- Configs: `sft/train_qwen3vl_*.yaml`
- Train logs: `logs/sft_train/sft_*.log`
- Eval JSONs: `sft/eval_out/*.json`
- Trace generator: `sft/generate_think_traces.py` (think failed but kept for reference)
- Mixed-data builder: `sft/prepare_mixed_data.py`
- Eval fanout: `sft/eval_fanout.sh`
- HF push: `sft/push_to_hf.py`, `sft/push_universal_to_hf.py`
- W&B project: https://wandb.ai/yichuan_wang-uc-berkeley-electrical-engineering-computer/qwen3vl-compressed-sft