StableI2I
Official implementation of StableI2I: Spotting Unintended Changes in Image-to-Image Transition (ICML 2026)
Questions: lijiayang.cs@gmail.com · looking forward to your ⭐
📌 TODOs
- release code
- release ckpt
- release pip-pkg (PyPI)
- release arxiv
- ICML version paper
Overview
Most image-to-image (I2I) evaluations focus on instruction following and perceptual quality. They rarely check whether the output still preserves the semantic correspondence and spatial structure of the input. StableI2I is a unified evaluation framework for content fidelity and pre–post consistency across editing and restoration, without requiring a reference image.
Evaluation prompts are bundled in the Python package. Callers only pass the input image, output image, and task prompt.
Install
pip install stablei2i
The runtime matches Qwen3-VL (transformers>=4.57.0). From source:
git clone https://github.com/Henry-Lee-real/StableI2I.git
cd StableI2I
pip install -e .
Checkpoints
| Checkpoint | Use when |
|---|---|
lijiayangCS/StableI2I_PLUS |
Numeric fidelity score (mode="score"), online RL reward |
lijiayangCS/StableI2I |
Fine-grained semantic / structure / low-level diagnosis (mode="simple" or "cot") |
StableI2I defaults to lijiayangCS/StableI2I_PLUS. You can also pass a local folder.
Quick Start
Load the judge once, then reuse it.
from stablei2i import StableI2I
judge = StableI2I(model="lijiayangCS/StableI2I_PLUS") # or a local ckpt path
Images may be a file path, PIL.Image, numpy array, or torch.Tensor.
Single pair
result = judge.evaluate(
input_image="before.png",
output_image="after.png",
prompt="Add a wooden bench along the path.",
mode="cot", # simple | cot | score, or a list of them
dimensions="semantic,structure,lowlevel",
)
print(result["result"])
JSONL batch
Each line needs id, input_image, output_image. prompt is optional. Aliases before_image / after_image are accepted.
{"id":"case-1","input_image":"example/000155856.jpg","output_image":"example/000155856_dup2.png","prompt":"Add a wooden bench along the path."}
rows = judge.evaluate_jsonl(
"test_jsonl/sample.jsonl",
output_jsonl="outputs/results.jsonl",
mode="cot",
)
Online evaluation / RL
Keep one StableI2I in the training process and score in-memory images. score mode returns 0–10; normalize=True maps it to [0, 1].
reward = judge.reward(src_image, gen_image, prompt, normalize=True)
reward_fn = judge.as_reward_fn(normalize=True) # (input, output, prompt) -> float
# GRPO / custom loop
r = reward_fn(src_image, gen_image, task_prompt)
For training, disable forced CuDNN determinism:
judge = StableI2I(model="lijiayangCS/StableI2I_PLUS", deterministic=False, gpu_id=0)
CLI
# single pair
stablei2i \
--input-image before.png \
--output-image after.png \
--prompt "Restore the image." \
--mode score \
--ckpt lijiayangCS/StableI2I_PLUS
# jsonl
stablei2i \
--jsonl test_jsonl/sample.jsonl \
--ckpt lijiayangCS/StableI2I_PLUS \
--mode cot \
--dimensions semantic,structure,lowlevel \
--output-jsonl outputs/results.jsonl
python test.py ... is the same entry as stablei2i. Full flags, JSONL rules, and output schemas: infer.md.
Modes
| Mode | What it runs | Typical output |
|---|---|---|
simple |
Semantic / structure / low-level branches | { "Semantic": ..., "Structure": ..., "Low-Level": ... } |
cot |
Main branches + follow-up reasoning when an issue is flagged | Adds Semantic_think / Low-Level_think |
score |
Fidelity score 0–10 | { "Score": { "score": 8 } } |
Pass several modes at once (--mode simple,cot,score) to group results by mode name.
Web Demo
app.py starts a FastAPI UI (built-in examples, local path, upload).
export MODEL_PATH=path/to/ckpt
export GPU_ID=0
export HOST=127.0.0.1
export PORT=10004
python app.py
Then open http://127.0.0.1:10004
Training
- SFT: official Qwen3-VL finetuning
- GRPO / alignment: ms-swift, using
StableI2I.as_reward_fn()as the online fidelity reward
Citation
@article{li2026stablei2i,
title={StableI2I: Spotting Unintended Changes in Image-to-Image Transition},
author={Li, Jiayang and Cao, Shuo and Li, Xiaohui and Zhang, Zhizhen and Zhu, Kaiwen and Duan, Yule and Qiao, Yu and Zhang, Jian and Liu, Yihao},
journal={arXiv preprint arXiv:2605.04453},
year={2026}
}
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stablei2i-0.1.1.tar.gz.
File metadata
- Download URL: stablei2i-0.1.1.tar.gz
- Upload date:
- Size: 24.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c2b6cd17236ddcbc1c1cbbfcaf151593b4d5e9e1579dd2f6700cddc031db002
|
|
| MD5 |
02a6240cdf1f20b9704c50f5f585f33f
|
|
| BLAKE2b-256 |
e68c02016ab2ae8b0f8d71f8a275a2bd0ef1836e25f204f6532a0c29094c9f85
|
File details
Details for the file stablei2i-0.1.1-py3-none-any.whl.
File metadata
- Download URL: stablei2i-0.1.1-py3-none-any.whl
- Upload date:
- Size: 24.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
458fb70e15d3ff66316eeafa98e03c7f0f3ce234f6462beceb9ce1826869472a
|
|
| MD5 |
4b0599ba27f6b7f5b8e16a644bc5345e
|
|
| BLAKE2b-256 |
2f05f1621e1c8d40163a952dbe20b62474cade9f99d0de50d7456101a1d4d7f0
|