4.3 KiB
Training Report — 2026-04-02
Summary
Ran contrastive fine-tuning of Qwen3-VL-Embedding-2B with GradCache + hard negatives. Fixed 3 bugs in the training pipeline, ran ablation experiments on hyperparameters, and completed a 1000-step training run.
Bug Fixes
1. NCCL Deadlock (critical)
prefetched() used a ThreadPoolExecutor for background data loading.
Background threads conflicted with NCCL all-reduce, causing random deadlocks in multi-GPU training.
Fix: Removed prefetch, iterate train_loader directly. No performance impact (~8.2s/step before and after).
2. Processor max_pixels Misconfigured
--max-num-visual-tokens default was 1024, and we added code to set
processor.image_processor.max_pixels = max_num_visual_tokens * 784.
However, the processor's grid alignment means it doesn't strictly enforce this limit:
an 875×1024 image produces 3000 tokens regardless of the setting.
The default of 1024 actually degraded image quality slightly (3000 vs 3456 tokens) without achieving precise token control.
Fix: Changed default to 4096. At this value, 875×1024 images produce 3456 tokens (same as processor default), so no quality loss.
3. Retrieval Eval NCCL Timeout
--test-max-pairs defaulted to 0 (unlimited). With large test sets (e.g., 4575 queries × 36430 docs),
retrieval eval runs only on rank 0 while other ranks wait at a barrier.
This exceeded the 60-minute NCCL timeout.
Fix: Changed --test-max-pairs default from 0 to 500.
1000-Step Training Run
Config: 2×H100, batch_size=16, lr=1e-5, cosine schedule, warmup=20, 5 hard negatives per sample.
Data: 2400 pairs from train_hn.jsonl (1833 with hard negatives).
Checkpoints: output_1000steps/checkpoint-{100..1000}
| Step | Eval Loss | Eval Acc |
|---|---|---|
| 50 | 0.613 | 80.6% |
| 100 | 0.502 | 82.5% |
| 200 | 0.445 | 82.8% |
| 300 | 0.428 | 83.4% |
| 400 | 0.421 | 84.4% |
| 500 | 0.418 | 83.8% |
| 600 | 0.414 | 83.8% |
| 700 | 0.411 | 84.4% |
| 800 | 0.410 | 84.4% |
| 900 | 0.406 | 84.1% |
| 1000 | 0.407 | 83.8% |
Eval loss converges around step 400–500. Eval acc saturates at ~84.4% (step 400/700/800). Best checkpoint region: step 400–700.
wandb: https://wandb.ai/andylizf-university-of-california-berkeley/wiki-screenshot-training/runs/jswdrobj
Note: No retrieval eval (R@1/R@5) was run — we had no test.jsonl and used --test-eval-steps 0.
Eval acc is contrastive accuracy on the validation set, not retrieval recall.
Ablation Experiments (200 steps)
All compared against baseline: batch_size=16, lr=1e-5, temp=0.07, 2×H100.
| Experiment | Change | Eval Loss | Eval Acc | Verdict |
|---|---|---|---|---|
| baseline | — | 0.489 | 82.5% | best |
| bigbatch | batch 16→32 | 0.670 | 80.0% | worse (lr too low for larger batch) |
| lowlr | lr 1e-5→3e-6 | 0.609 | 81.3% | slightly worse |
| hightemp | temp 0.07→0.15 | 1.091 | 78.1% | worst |
wandb links:
- bigbatch: https://wandb.ai/andylizf-university-of-california-berkeley/wiki-screenshot-training/runs/3938ypgz
- lowlr: https://wandb.ai/andylizf-university-of-california-berkeley/wiki-screenshot-training/runs/ym4epldm
- hightemp: https://wandb.ai/andylizf-university-of-california-berkeley/wiki-screenshot-training/runs/5lmvi76m
Train Loss Oscillation
Train loss oscillates between 1.5–6.0 throughout training without a clear downward trend. This is expected in contrastive learning with small batches — each step's loss depends heavily on which hard negatives are sampled. Eval loss (averaged over 20 batches) is the stable metric and decreases monotonically.
Increasing batch size did not reduce oscillation (and hurt accuracy, likely because lr wasn't scaled up).
Open Questions
- No retrieval eval done — eval acc measures contrastive accuracy, not actual retrieval performance (R@1 etc.). Need to run retrieval eval on checkpoints to confirm real-world improvement.
- max_num_visual_tokens doesn't precisely control token count due to processor grid alignment. The parameter is approximate at best.
- Data scale — we trained on 2400 pairs. Wang Yichuan is training on 76K+. Results may differ significantly at scale.