Multiple-choice VQA on everyday smartphone photos
- Event: 2025 Samsung Collegiate Programming Challenge: AI (JunβJul 2025)
- Task: Select the correct answer to multiple-choice questions about everyday gallery photos
- Approach: BLIP2-FLAN-T5-XL fine-tuned with LoRA + partial 4-bit quantization on a synthetically generated dataset
- Result: 4th on private leaderboard β score 0.8344 (Leaderboard)
The system has three phases:
1. Synthetic dataset generation β a three-step pipeline produces labeled VQA examples:
Qwen/Qwen-1_8Bgenerates scene prompts across categories (nature, travel, food, casual)dreamlike-art/dreamlike-photoreal-2.0renders each prompt into a realistic photollava-hf/llava-1.5-7b-hfannotates each image with a description, a multiple-choice question, and the correct answer
2. Fine-tuning β Salesforce/blip2-flan-t5-xl is trained with:
- 8-bit quantization during training to fit within 40 GB VRAM
- LoRA adapters on the Q-Former (
query,key,value,dense) β only ~0.1% of parameters are trainable
3. Two-stage inference β for each test image:
- Generate a free-form description conditioned on the image + question
- Predict the answer letter (A/B/C/D) using the description, image, and choices together
At inference the T5 decoder is swapped to a 4-bit quantized version for lower VRAM usage.
| Model | Public score |
|---|---|
| Baseline | 0.30486 |
| FLAN-T5 only | 0.81298 |
| This work | 0.83262 |
.
βββ configs/
β βββ config.py # All hyperparameters and paths in one dataclass
βββ dataset/
β βββ generate/
β β βββ prompts.py # Step 1: scene prompt generation (Qwen)
β β βββ images.py # Step 2: image synthesis (Stable Diffusion)
β β βββ qa_pairs.py # Step 3: VQA annotation (LLaVA)
β β βββ real_qa.py # COCO val2017 download + annotation
β β βββ eval_images.py # Flickr30k download for eval
β βββ loader.py # Dataset preprocessing for training
βββ model/
β βββ build.py # Model loading (training / inference variants)
β βββ trainer.py # CustomTrainer + TrainingArguments factory
β βββ predictor.py # Two-stage inference logic
βββ utils/
β βββ postprocess.py # Answer extraction, submission builder
βββ generate_train_dataset.py # Entry point: run full training data generation pipeline
βββ generate_eval_dataset.py # Entry point: build external eval set (Flickr30k + LLaVA)
βββ train.py # Entry point: fine-tune the model
βββ train_dataset_ablation.py # Entry point: train synthetic_only / synthetic_real for ablation
βββ inference.py # Entry point: run inference, save submission
βββ inference_ablation.py # Entry point: compare inference variants on a labeled eval set
βββ pyproject.toml
βββ requirements.txt
Legacy prototype notebooks and scripts are preserved in .legacy/.
- OS: Linux
- GPU: NVIDIA GPU (~20 GB VRAM minimum)
- CUDA: 12.8
- Python: 3.10+
Step 1 β PyTorch with CUDA 12.8:
pip install torch==2.7.1+cu128 torchvision==0.22.1+cu128 torchaudio==2.7.1+cu128 \
--index-url https://download.pytorch.org/whl/cu128Step 2 β remaining dependencies:
pip install -r requirements.txt
# or as an editable install (includes Jupyter extras):
pip install -e ".[jupyter]"python generate_train_dataset.pyRuns the three-step pipeline sequentially. Each step is skipped automatically if its output already exists.
python train.pySaves the LoRA adapter and tokenizer to ./model/finetuned-blip2-flan-t5-xl/.
python inference.pyReads ./data/given/test.csv, runs two-stage prediction, and writes test_inference_final.csv.
python generate_eval_dataset.pyDownloads Flickr30k images (a different source from the COCO training data) and annotates them with LLaVA. Outputs a labeled CSV at data/eval/eval_question_answer.csv. Each step is skipped if its output already exists.
Image count is controlled by num_eval_images in configs/config.py (default 500).
python train_dataset_ablation.py # trains both sequentially
python train_dataset_ablation.py --composition synthetic_only
python train_dataset_ablation.py --composition synthetic_realTrains two checkpoints under ./model/ for the dataset composition ablation:
synthetic_onlyβ AI-generated images + LLaVA QA pairs onlysynthetic_realβ synthetic + COCO val2017 real images
python inference_ablation.py --eval_csv data/eval/eval_question_answer.csv
python inference_ablation.py --eval_csv data/eval/eval_question_answer.csv --output results.csvCompares named variants on a labeled eval set. The eval CSV must include an answer column with ground-truth labels.
Default variants: two-stage vs. single-stage inference, fine-tuned vs. base model, dataset composition.
LoRA rank variants can be enabled by editing the VARIANTS list in inference_ablation.py.
All paths, model IDs, and hyperparameters live in configs/config.py. Edit the dataclass fields directly β no CLI flags or YAML files needed.
Key fields:
| Field | Default | Description |
|---|---|---|
base_model_id |
Salesforce/blip2-flan-t5-xl |
Base BLIP2 model |
lora_r / lora_alpha |
32 / 64 | LoRA rank and scaling |
lr_scheduler_type |
"cosine" |
LR scheduler ("cosine", "linear", etc.) |
warmup_ratio |
0.1 | Fraction of steps used for LR warmup |
num_epochs |
5 | Training epochs |
batch_size |
8 | Per-device batch size |
input_max_length |
384 | Tokenizer input truncation |
num_prompt_generations |
1000 | Scene prompt generation iterations |
eval_dir |
./data/eval |
Eval dataset directory |
num_eval_images |
500 | Number of Flickr30k images to download for eval |

