A pipeline for generating and evaluating images on visual analogy and other visual reasoning tasks using vision-language models and image generation models.
Given images A, A', and B (forming the analogy A:A'::B:?), this pipeline:
The pipeline supports three prompting strategies for image generation, described below.
| Task | Flag | Description |
|---|---|---|
| Visual Analogy | --task analogy | A:A'::B:? using the VASR dataset |
| Clothing Owner | --task clothing | Track clothing ownership across transfers |
| Object Attributes | --task object_attributes | Reason about object attribute changes |
| Human Action | --task human_action | Understand and replicate human actions |
Three strategies control how image prompts are constructed and refined:
naivePasses images A, A', B directly to the image generation model along with a fixed template prompt. No VLM reasoning is used to construct the prompt.
Best for: Quick baselines; testing image generation quality without prompt engineering.
guidedThe VLM first reasons about the analogy from captions, then produces a text-only description of the target image D. The image generation model generates from text only (no input images).
Best for: Situations where images may be misleading or when clean text-based prompting is preferred.
feedbackExtends guided by iteratively refining the generated image. After each generation, the VLM evaluates the result against the rubric and produces feedback. A new, improved prompt is constructed and the image is regenerated. The best-scoring image across all iterations is selected.
Best for: Maximizing generation quality; exploring how iterative refinement affects the final result.
Note:
guidedis equivalent tofeedbackwith--n_iteration 1.
conda create -n analogygen python=3.10
conda activate analogygen
pip install -r requirements.txt
For the Bagel image generation model, use the separate Bagel environment:
conda activate bagel
The pipeline requires a running vLLM endpoint for captioning, reasoning, rubric generation, and evaluation. The default endpoint is http://localhost:8010/v1/chat/completions.
# Example: start Qwen2.5-VL-7B-Instruct (or similar) on port 8010
tmux new-session -d -s vllm_server bash -c "
source \$(conda info --base)/etc/profile.d/conda.sh
conda activate analogygen
vllm serve Qwen/Qwen3-VL-4B-Instruct \
--served-model-name thinker \
--port 8010
"
Alternatively, pass --is_openai_endpoint to use the OpenAI API (requires ./utils/openai_key.txt).
If using --preload, place a pre-computed rubric file at:
vasr/gpt5_rubrics/reasoning_rubrics_train-gold.json
Each entry in the JSON has the following structure:
{
"sample_index": 0,
"captions": {
"A": "A lion leaping at a wildebeest...",
"A_prime": "A lion resting on grass...",
"B": "A polar bear swimming...",
"D": "A polar bear resting on ice..."
},
"reasoning": "The transformation changes the animal from active hunting to resting...",
"rubric": [
{
"criterion": "Species substitution (0-1)",
"description": "The subject is unmistakably a polar bear (ice bear), not a lion...",
"max_score": 1
},
...
]
}
To download the task problems, rubrics, and input images directly from the Huggingface dataset, run
sh download_data.sh
To download it in the local layout needed by the code.
Alternatively, download in a parquet format from Huggingface for custom usage:
mivigenbench/mivigenbench
python3 pipeline.py \
--task <analogy|clothing|object_attributes|human_action> \
--prompt_strategy <naive|guided|feedback> \
--image_gen_pipeline <bagel|qwenimageeditplus> \
--model_name <thinker|gpt-4o-mini|...> \
--output_dir <path/to/results> \
[--preload] \
[--n_iteration N] \
[--limit N] \
[--data_split <train|val>]
Naive strategy (direct image + template prompt):
CUDA_VISIBLE_DEVICES=1,2 python3 pipeline.py \
--task analogy \
--prompt_strategy naive \
--image_gen_pipeline bagel \
--model_name thinker \
--output_dir results/bagel_naive \
--preload \
--limit 10
Guided strategy (VLM-generated text prompt, no input images):
CUDA_VISIBLE_DEVICES=1,2 python3 pipeline.py \
--task analogy \
--prompt_strategy guided \
--image_gen_pipeline bagel \
--model_name thinker \
--output_dir results/bagel_guided \
--preload \
--limit 10
Feedback strategy (iterative refinement, N iterations):
CUDA_VISIBLE_DEVICES=1,2 python3 pipeline.py \
--task analogy \
--prompt_strategy feedback \
--image_gen_pipeline bagel \
--model_name thinker \
--output_dir results/bagel_feedback \
--preload \
--n_iteration 3 \
--limit 10
| Argument | Default | Description |
|---|---|---|
--task | analogy | Task type: analogy, clothing, object_attributes, human_action |
--prompt_strategy | naive | Generation strategy: naive, guided, feedback |
--image_gen_pipeline | bagel | Image generation model: bagel, qwenimageeditplus |
--model_name | thinker | VLM model name sent in request payload |
--output_dir | results | Root directory for all outputs |
--preload | False | Load pre-computed rubrics instead of generating them |
--n_iteration | 3 | Number of feedback iterations (only for feedback strategy) |
--limit | None | Max number of examples to process (useful for quick tests) |
--data_split | train | Dataset split for analogy task: train, val |
--is_openai_endpoint | False | Use OpenAI API instead of local vLLM |
--use_existing_images | False | Skip image generation; re-use previously generated images |
All outputs are organized per-index under {output_dir}/index_{N}/.
results/bagel_naive/
└── index_0/
├── generated.jpg # Generated D image
└── results.json # Evaluation scores and metadata
results/bagel_guided/
└── index_0/
├── iter_0.png # Generated D image (iteration 0)
└── results.json # Evaluation scores and metadata
results/bagel_feedback/
└── index_0/
├── iter_0.png # Generated image, iteration 0
├── iter_1.png # Generated image, iteration 1 (after VLM feedback)
├── iter_2.png # Generated image, iteration 2
└── results.json # Best-iteration scores + full feedback history
results.json format{
"index": 0,
"A_str": "lion_hunting.jpg",
"B_str": "polar_bear_swimming.jpg",
"captions": { "A": "...", "B": "...", "C": "...", "D": "..." },
"reasoning": "...",
"rubric": [...],
"generated_instructions": "A polar bear pounces on a wildebeest...",
"criteria_scores": [
{ "criterion": "Species substitution (0-1)", "score": 1, "max_score": 1, "explanation": "..." },
{ "criterion": "Action continuity from C (0-2)", "score": 2, "max_score": 2, "explanation": "..." }
],
"total_score": 3,
"max_score": 5,
"score_percentage": 60.0,
"best_iteration": 0,
"feedback_history": [
{ "iteration": 0, "score": 3, "feedback": "...", "instructions": "..." }
]
}
python3 visualization.py
The visualization/ folder contains pre-computed example outputs for reference.
Four people (A, B, C, D) each start with a clothing item in a specific color (provided as images). After a sequence of transfers, the model is asked to generate the final state of one person's clothing.
Generate the dataset (problems + images):
python3 clothing_owner_task/create_data.py
To generate clothing images from scratch, you need access to:
stabilityai/stable-diffusion-3.5-medium
and place them in ./clothing_owner_task/problem_data/images/.
python3 pipeline.py \
--task clothing \
--preload \
--image_gen_pipeline bagel \
--output_dir results/clothing
python3 object_attributes_task/create_data.py
python3 pipeline.py \
--task object_attributes \
--preload \
--image_gen_pipeline bagel \
--output_dir results/object_attributes
python3 human_action_task/create_data.py
python3 pipeline.py \
--task human_action \
--preload \
--image_gen_pipeline bagel \
--output_dir results/human_action
AnalogyGen/
├── pipeline.py # Main entry point
├── pipeline_utils/
│ ├── __init__.py
│ ├── base_pipeline.py # Base Pipeline class (VLM calls, generation, eval)
│ ├── visual_analogy_pipeline.py # VisualAnalogyPipeline (VASR)
│ ├── clothing_owner_pipeline.py # ClothingOwnerPipeline
│ ├── object_attributes_pipeline.py # ObjectAttributesPipeline
│ └── human_action_pipeline.py # HumanActionPipeline
├── clothing_owner_task/
│ └── create_data.py # Problem + image generation for clothing task
├── object_attributes_task/
│ └── create_data.py
├── human_action_task/
│ └── create_data.py
├── Bagel/ # Bagel model integration
│ ├── inferencer.py
│ └── bagel_init.py
├── utils/
│ └── utils.py # OpenAI key loading, multimodal API helpers
├── vasr/
│ ├── train_gold.csv
│ └── dev_gold.csv
├── results/ # All pipeline outputs (auto-created)
├── visualization.py
└── requirements.txt
infer_auto_device_map). Set CUDA_VISIBLE_DEVICES to select specific GPUs.Example: if GPUs 0 and 5 are in use by the vLLM server:
CUDA_VISIBLE_DEVICES=1,2 python3 pipeline.py ...
1 commits
Python
98.7%
A pipeline for generating and evaluating images on visual analogy and other visual reasoning tasks using vision-language models and image generation models.
Given images A, A', and B (forming the analogy A:A'::B:?), this pipeline:
The pipeline supports three prompting strategies for image generation, described below.
| Task | Flag | Description |
|---|---|---|
| Visual Analogy | --task analogy | A:A'::B:? using the VASR dataset |
| Clothing Owner | --task clothing | Track clothing ownership across transfers |
| Object Attributes | --task object_attributes | Reason about object attribute changes |
| Human Action | --task human_action | Understand and replicate human actions |
Three strategies control how image prompts are constructed and refined:
naivePasses images A, A', B directly to the image generation model along with a fixed template prompt. No VLM reasoning is used to construct the prompt.
Best for: Quick baselines; testing image generation quality without prompt engineering.
guidedThe VLM first reasons about the analogy from captions, then produces a text-only description of the target image D. The image generation model generates from text only (no input images).
Best for: Situations where images may be misleading or when clean text-based prompting is preferred.
feedbackExtends guided by iteratively refining the generated image. After each generation, the VLM evaluates the result against the rubric and produces feedback. A new, improved prompt is constructed and the image is regenerated. The best-scoring image across all iterations is selected.
Best for: Maximizing generation quality; exploring how iterative refinement affects the final result.
Note:
guidedis equivalent tofeedbackwith--n_iteration 1.
conda create -n analogygen python=3.10
conda activate analogygen
pip install -r requirements.txt
For the Bagel image generation model, use the separate Bagel environment:
conda activate bagel
The pipeline requires a running vLLM endpoint for captioning, reasoning, rubric generation, and evaluation. The default endpoint is http://localhost:8010/v1/chat/completions.
# Example: start Qwen2.5-VL-7B-Instruct (or similar) on port 8010
tmux new-session -d -s vllm_server bash -c "
source \$(conda info --base)/etc/profile.d/conda.sh
conda activate analogygen
vllm serve Qwen/Qwen3-VL-4B-Instruct \
--served-model-name thinker \
--port 8010
"
Alternatively, pass --is_openai_endpoint to use the OpenAI API (requires ./utils/openai_key.txt).
If using --preload, place a pre-computed rubric file at:
vasr/gpt5_rubrics/reasoning_rubrics_train-gold.json
Each entry in the JSON has the following structure:
{
"sample_index": 0,
"captions": {
"A": "A lion leaping at a wildebeest...",
"A_prime": "A lion resting on grass...",
"B": "A polar bear swimming...",
"D": "A polar bear resting on ice..."
},
"reasoning": "The transformation changes the animal from active hunting to resting...",
"rubric": [
{
"criterion": "Species substitution (0-1)",
"description": "The subject is unmistakably a polar bear (ice bear), not a lion...",
"max_score": 1
},
...
]
}
To download the task problems, rubrics, and input images directly from the Huggingface dataset, run
sh download_data.sh
To download it in the local layout needed by the code.
Alternatively, download in a parquet format from Huggingface for custom usage:
mivigenbench/mivigenbench
python3 pipeline.py \
--task <analogy|clothing|object_attributes|human_action> \
--prompt_strategy <naive|guided|feedback> \
--image_gen_pipeline <bagel|qwenimageeditplus> \
--model_name <thinker|gpt-4o-mini|...> \
--output_dir <path/to/results> \
[--preload] \
[--n_iteration N] \
[--limit N] \
[--data_split <train|val>]
Naive strategy (direct image + template prompt):
CUDA_VISIBLE_DEVICES=1,2 python3 pipeline.py \
--task analogy \
--prompt_strategy naive \
--image_gen_pipeline bagel \
--model_name thinker \
--output_dir results/bagel_naive \
--preload \
--limit 10
Guided strategy (VLM-generated text prompt, no input images):
CUDA_VISIBLE_DEVICES=1,2 python3 pipeline.py \
--task analogy \
--prompt_strategy guided \
--image_gen_pipeline bagel \
--model_name thinker \
--output_dir results/bagel_guided \
--preload \
--limit 10
Feedback strategy (iterative refinement, N iterations):
CUDA_VISIBLE_DEVICES=1,2 python3 pipeline.py \
--task analogy \
--prompt_strategy feedback \
--image_gen_pipeline bagel \
--model_name thinker \
--output_dir results/bagel_feedback \
--preload \
--n_iteration 3 \
--limit 10
| Argument | Default | Description |
|---|---|---|
--task | analogy | Task type: analogy, clothing, object_attributes, human_action |
--prompt_strategy | naive | Generation strategy: naive, guided, feedback |
--image_gen_pipeline | bagel | Image generation model: bagel, qwenimageeditplus |
--model_name | thinker | VLM model name sent in request payload |
--output_dir | results | Root directory for all outputs |
--preload | False | Load pre-computed rubrics instead of generating them |
--n_iteration | 3 | Number of feedback iterations (only for feedback strategy) |
--limit | None | Max number of examples to process (useful for quick tests) |
--data_split | train | Dataset split for analogy task: train, val |
--is_openai_endpoint | False | Use OpenAI API instead of local vLLM |
--use_existing_images | False | Skip image generation; re-use previously generated images |
All outputs are organized per-index under {output_dir}/index_{N}/.
results/bagel_naive/
└── index_0/
├── generated.jpg # Generated D image
└── results.json # Evaluation scores and metadata
results/bagel_guided/
└── index_0/
├── iter_0.png # Generated D image (iteration 0)
└── results.json # Evaluation scores and metadata
results/bagel_feedback/
└── index_0/
├── iter_0.png # Generated image, iteration 0
├── iter_1.png # Generated image, iteration 1 (after VLM feedback)
├── iter_2.png # Generated image, iteration 2
└── results.json # Best-iteration scores + full feedback history
results.json format{
"index": 0,
"A_str": "lion_hunting.jpg",
"B_str": "polar_bear_swimming.jpg",
"captions": { "A": "...", "B": "...", "C": "...", "D": "..." },
"reasoning": "...",
"rubric": [...],
"generated_instructions": "A polar bear pounces on a wildebeest...",
"criteria_scores": [
{ "criterion": "Species substitution (0-1)", "score": 1, "max_score": 1, "explanation": "..." },
{ "criterion": "Action continuity from C (0-2)", "score": 2, "max_score": 2, "explanation": "..." }
],
"total_score": 3,
"max_score": 5,
"score_percentage": 60.0,
"best_iteration": 0,
"feedback_history": [
{ "iteration": 0, "score": 3, "feedback": "...", "instructions": "..." }
]
}
python3 visualization.py
The visualization/ folder contains pre-computed example outputs for reference.
Four people (A, B, C, D) each start with a clothing item in a specific color (provided as images). After a sequence of transfers, the model is asked to generate the final state of one person's clothing.
Generate the dataset (problems + images):
python3 clothing_owner_task/create_data.py
To generate clothing images from scratch, you need access to:
stabilityai/stable-diffusion-3.5-medium
and place them in ./clothing_owner_task/problem_data/images/.
python3 pipeline.py \
--task clothing \
--preload \
--image_gen_pipeline bagel \
--output_dir results/clothing
python3 object_attributes_task/create_data.py
python3 pipeline.py \
--task object_attributes \
--preload \
--image_gen_pipeline bagel \
--output_dir results/object_attributes
python3 human_action_task/create_data.py
python3 pipeline.py \
--task human_action \
--preload \
--image_gen_pipeline bagel \
--output_dir results/human_action
AnalogyGen/
├── pipeline.py # Main entry point
├── pipeline_utils/
│ ├── __init__.py
│ ├── base_pipeline.py # Base Pipeline class (VLM calls, generation, eval)
│ ├── visual_analogy_pipeline.py # VisualAnalogyPipeline (VASR)
│ ├── clothing_owner_pipeline.py # ClothingOwnerPipeline
│ ├── object_attributes_pipeline.py # ObjectAttributesPipeline
│ └── human_action_pipeline.py # HumanActionPipeline
├── clothing_owner_task/
│ └── create_data.py # Problem + image generation for clothing task
├── object_attributes_task/
│ └── create_data.py
├── human_action_task/
│ └── create_data.py
├── Bagel/ # Bagel model integration
│ ├── inferencer.py
│ └── bagel_init.py
├── utils/
│ └── utils.py # OpenAI key loading, multimodal API helpers
├── vasr/
│ ├── train_gold.csv
│ └── dev_gold.csv
├── results/ # All pipeline outputs (auto-created)
├── visualization.py
└── requirements.txt
infer_auto_device_map). Set CUDA_VISIBLE_DEVICES to select specific GPUs.Example: if GPUs 0 and 5 are in use by the vLLM server:
CUDA_VISIBLE_DEVICES=1,2 python3 pipeline.py ...
1 commits
Python
98.7%