Metadata-Version: 2.4
Name: stablei2i
Version: 0.1.1
Summary: StableI2I: evaluate unintended changes in image-to-image transitions.
Author-email: Jiayang Li <lijiayang.cs@gmail.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/Henry-Lee-real/StableI2I
Project-URL: Issues, https://github.com/Henry-Lee-real/StableI2I/issues
Project-URL: Paper, https://arxiv.org/abs/2605.04453
Project-URL: HuggingFace, https://huggingface.co/collections/lijiayangCS/stablei2i
Project-URL: PyPI, https://pypi.org/project/stablei2i/
Keywords: image-to-image,evaluation,fidelity,Qwen3-VL,reinforcement-learning
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: torch
Requires-Dist: Pillow
Requires-Dist: transformers>=4.57.0
Requires-Dist: tqdm
Requires-Dist: qwen-vl-utils==0.0.14
Provides-Extra: app
Requires-Dist: fastapi; extra == "app"
Requires-Dist: uvicorn; extra == "app"
Requires-Dist: python-multipart; extra == "app"
Requires-Dist: pydantic; extra == "app"
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# StableI2I

Official implementation of **StableI2I: Spotting Unintended Changes in Image-to-Image Transition** (ICML 2026)

Questions: [lijiayang.cs@gmail.com](mailto:lijiayang.cs@gmail.com) · looking forward to your ⭐

[![PyPI](https://img.shields.io/pypi/v/stablei2i.svg)](https://pypi.org/project/stablei2i/)
[![HuggingFace](https://img.shields.io/badge/HuggingFace-StableI2I-ffcc4d?logo=huggingface&logoColor=white&style=flat)](https://huggingface.co/collections/lijiayangCS/stablei2i)
[![Project Page](https://img.shields.io/badge/Project%20Page-StableI2I-blue?style=flat)](https://henry-lee-real.github.io/StableI2I_Page/)
[![arXiv 2605.04453](https://img.shields.io/badge/arXiv-2605.04453-b31b1b?logo=arXiv&logoColor=white&style=flat)](https://arxiv.org/pdf/2605.04453)
[![License](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/Henry-Lee-real/StableI2I/blob/main/LICENSE)

### 📌 TODOs

> - [X] release code
> - [X] release ckpt
> - [X] release pip-pkg ([PyPI](https://pypi.org/project/stablei2i/))
> - [X] 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

```bash
pip install stablei2i
```

The runtime matches [Qwen3-VL](https://github.com/QwenLM/Qwen3-VL) (`transformers>=4.57.0`). From source:

```bash
git clone https://github.com/Henry-Lee-real/StableI2I.git
cd StableI2I
pip install -e .
```

## Checkpoints

| Checkpoint | Use when |
| --- | --- |
| [`lijiayangCS/StableI2I_PLUS`](https://huggingface.co/lijiayangCS/StableI2I_PLUS) | Numeric fidelity score (`mode="score"`), online RL reward |
| [`lijiayangCS/StableI2I`](https://huggingface.co/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.

```python
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

```python
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.

```json
{"id":"case-1","input_image":"example/000155856.jpg","output_image":"example/000155856_dup2.png","prompt":"Add a wooden bench along the path."}
```

```python
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]`.

```python
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:

```python
judge = StableI2I(model="lijiayangCS/StableI2I_PLUS", deterministic=False, gpu_id=0)
```

## CLI

```bash
# 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](https://github.com/Henry-Lee-real/StableI2I/blob/main/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

![StableI2I demo](https://github.com/user-attachments/assets/8104c802-58c4-4b63-bb44-f86158f960d2)

`app.py` starts a FastAPI UI (built-in examples, local path, upload).

```bash
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](https://github.com/QwenLM/Qwen3-VL) finetuning
- GRPO / alignment: [ms-swift](https://github.com/modelscope/ms-swift), using `StableI2I.as_reward_fn()` as the online fidelity reward

## Citation

```bibtex
@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}
}
```
