# OSEDiff: one-step diffusion super-resolution for real photos

> OSEDiff is a NeurIPS 2024 research project that turns a Stable Diffusion 2.1 base model into a single step upscaler for real-world images, with a separate face restoration path. It runs in a fraction of a second per image on an A100, but the pinned 2023 dependency stack and a last push on 2026-04-09 make it a codebase you inherit rather than one you keep upgrading.

**cswry/OSEDiff** — [NeurlPS2024] One-Step Effective Diffusion Network for Real-World Image Super-Resolution

- Repository: https://github.com/cswry/OSEDiff
- Stars: 685 · Forks: 41
- Language: Python
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/cswry-osediff

## The problem: real photos that no clean-image upscaler handles well

OSEDiff sits in the real-world image super-resolution branch of the literature, where the input is a photograph that has already been through compression, noise, blur or a combination of them, rather than a clean downsampled version of a reference image. The project is presented as a One-Step Effective Diffusion Network and was accepted at NeurIPS 2024, with the paper published as arXiv 2406.08177. The work comes from the Hong Kong Polytechnic University together with the OPPO Research Institute, and the README records that OSEDiff was applied to the OPPO Find X8 series. The name carries the central claim: diffusion models handle degradation well, but a multi-step sampler is too slow for a product, so this project compresses the sampling process down to a single step.

## What the repository actually wires together

The interface reveals the architecture better than the prose does. The inference entry point is test_osediff.py, and it takes three external model paths: a Stable Diffusion 2.1 base model through --pretrained_model_name_or_path, a RAM checkpoint through --ram_path, and a DAPE checkpoint through --ram_ft_path. The trained artefact itself is a single pickle, referenced as preset/models/osediff.pkl for general images and preset/models/osediff_face.pkl for the face path. The source tree matches that shape, with osediff.py at the top level, a ram directory for the recognition model, a models directory, my_utils, dataloaders, scripts and a preset folder that holds the datasets, the model files and the benchmark results. Training is a separate script, train_osediff.py, with a companion train_osediff_face.py for the face variant.

## Fetching the three checkpoints the scripts insist on

There is no one-line install for the models, because the pipeline depends on three separate downloads. The README lists them as dependent models: SD21 Base, the RAM swin large checkpoint, and DAPE. The environment itself is pinned, and the pin is old, with diffusers 0.25.0, torch 2.0.1, transformers 4.28.1, xformers 0.0.20, einops 0.7.0, open-clip-torch 2.20.0, peft 0.9.0, Pillow 9.5.0, PyYAML 6.0, pyiqa 0.1.10 and huggingface_hub 0.25.0, plus basicsr, loralib and fairscale. Clone the repository and create the conda environment first.

```bash
git clone https://github.com/cswry/OSEDiff.git
cd OSEDiff
```

Then install the pinned requirements into a Python 3.10 environment.

```bash
conda create -n OSEDiff python=3.10 -y
conda activate OSEDiff
pip install --upgrade pip
pip install -r requirements.txt
```

The three model paths are then passed to the scripts as SD21BASE_PATH, RAM_PATH and DAPE_PATH placeholders, so you can point them wherever you keep the downloads.

## One inference call for photos, a second one for faces

The general path takes an input directory and writes an output directory, and the two other arguments worth noticing are the trained pickle and the three model paths. The README's example uses the preset test dataset, so the directories already exist in a fresh clone.

```bash
python test_osediff.py \
-i preset/datasets/test_dataset/input \
-o preset/datasets/test_dataset/output \
--osediff_path preset/models/osediff.pkl \
--pretrained_model_name_or_path SD21BASE_PATH \
--ram_ft_path DAPE_PATH \
--ram_path RAM_PATH
```

The face variant swaps in the face checkpoint, points at a different pair of preset directories, and adds --upscale 1 plus an --align_method of nofix, which skips the face alignment step.

```bash
python test_osediff.py \
-i preset/datasets/test_dataset/input_face \
-o preset/datasets/test_dataset/output_face \
--upscale 1 \
--osediff_path preset/models/osediff_face.pkl \
--pretrained_model_name_or_path SD21BASE_PATH \
--ram_ft_path DAPE_PATH \
--ram_path RAM_PATH \
--align_method nofix 
```

The --align_method flag is worth reading closely, because leaving the alignment path active is how faces come out misaligned rather than merely soft.

## What the measured timings and quality numbers amount to

The README does not ask you to trust a table on a blog post, it hands you a script. test_inference_time.py runs a configurable number of iterations after a warm-up, and the README shows what an A100 produced for 500 iterations at a process size of 512, an average of 0.1046 seconds per iteration and a 9.55 it/s rate.

```bash
python test_inference_time.py \
--osediff_path preset/models/osediff.pkl \
--inference_iterations 500 \
--warmup_iterations 5 \
--process_size 512 \
--pretrained_model_name_or_path SD21BASE_PATH \
--ram_ft_path DAPE_PATH  \
--ram_path RAM_PATH
```

Quality numbers come from the same philosophy. Results for the RealSR and DrealSR benchmarks sit in the repository under preset/datasets/benchmark_realsr/results_osediff and preset/datasets/benchmark_drealsr/results_osediff, and the README states the RealSR averages as PSNR 25.1511, SSIM 0.7341, LPIPS 0.2921, DISTS 0.2128, FID 123.493817, with the DrealSR set at PSNR 27.9243 and FID 135.296586. A separate script recomputes image quality metrics from those folders against the ground truth images.

```bash
python test_metrics.py \
--inp_imgs preset/datasets/benchmark_realsr/results_osediff \
--gt_imgs preset/datasets/benchmark_realsr/test_HR \
--log preset/datasets/benchmark_realsr/results_osediff/metrics
```

The DIV2K validation results are not in the repository because of the image count, and are hosted on Google Drive instead.

## Training data, the training script and the thin documentation around them

The training side is where the documentation is noticeably thinner than the inference side. The README states the data recipe in one line: LSDIR, listed as 84991 images, plus the first 10k images of FFHQ. The paths go into a plain text file, one absolute image path per line.

```
LSDIR/HR_merge/0000001.png
LSDIR/HR_merge/0000002.png
...
```

Training is launched with accelerate and a four GPU device list, with the same SD21 base, RAM and DAPE paths passed in.

```bash
CUDA_VISIBLE_DEVICES="0,1,2,3," accelerate launch train_osediff.py \
    --pretrained_model_name_or_path=SD21BASE_PATH \
    --ram_path=RAM_PATH \
```

What the README does not do is state the remaining arguments, the loss schedule, the number of steps or how long a run takes. If your plan involves retraining rather than running the released pickle, you are reading train_osediff.py in the repository for that, and you should budget for the four GPU assumption rather than a single workstation.

## Where OSEDiff loses to its own successors, and what to use instead

The README itself points past OSEDiff to a set of newer projects from the same group, and the differences are specific enough to be useful. AdcSR, accepted at CVPR 2025, is an adversarial diffusion compression framework for super-resolution and the README states it offers up to 9.3 times speedup over OSEDiff, which matters if your bottleneck is the sampling step. CCSRv2, accepted at TIP 2026, is a flexible and efficient diffusion sampling method that supports an arbitrary number of inference steps, for example 1 to 15, so it is the option when you want to trade latency against quality rather than fix the count at one. PiSA-SR, accepted at CVPR 2025, is an adjustable diffusion network for super-resolution, aimed at letting you pick a quality preference. VOSR, accepted at CVPR 2026, is described as a vision-only native generative framework for image restoration, and TVT, accepted at ICCV 2025, re-trains the VAE of SD2.1 while keeping its UNet for more precise Real-ISR.

Two cases make OSEDiff the wrong tool. The first is a production service that needs a maintained model line, because this repository has no GitHub releases at all and the last push was on 2026-04-09. The second is a team already on a modern CUDA and diffusers stack, because the pinned requirements here are from the 2023 generation of those libraries and moving forward means rewriting the environment.

## Conclusion

OSEDiff fits a research team that needs one-shot upscaling of degraded photographs and can freeze a Python environment around torch 2.0.1 and diffusers 0.25.0, or a team that wants to study one-step distillation rather than ship a service. It does not fit production image pipelines that need new model releases, current CUDA stacks or a maintenance commitment, since the repository has no GitHub releases and the last push was on 2026-04-09. Before you adopt it, run test_inference_time.py on your own GPU to check the timing, and read the train_osediff.py launch arguments in the README because the training section is where the documentation is thinnest.

## FAQ

### What is OSEDiff and what does the one-step part mean?

OSEDiff is a One-Step Effective Diffusion Network for real-world image super-resolution, accepted at NeurIPS 2024. It is a diffusion model that produces its upscaled result in a single sampling step rather than running the many-step loop of a standard diffusion sampler.

### Which models do I need to download before running OSEDiff?

Three: SD21 Base, the RAM swin large checkpoint and DAPE, all listed as dependent models in the README. The scripts take them as the --pretrained_model_name_or_path, --ram_path and --ram_ft_path arguments.

### How fast does OSEDiff run on a GPU?

The README reports an average of 0.1046 seconds per iteration on an A100, at a process size of 512, over 500 iterations after 5 warm-up iterations. You can reproduce the measurement with test_inference_time.py, which takes the iteration count, warm-up count and process size as arguments.

### Can OSEDiff restore faces as well as general images?

Yes, there is a separate face path with its own checkpoint, osediff_face.pkl, and a dedicated train_osediff_face.py script. The face inference example adds an --upscale 1 argument and an --align_method of nofix, which turns off face alignment during the run.

## Sources

- [cswry/OSEDiff on GitHub](https://github.com/cswry/OSEDiff)
- [Issues](https://github.com/cswry/OSEDiff/issues)
- [License: Apache-2.0](https://github.com/cswry/OSEDiff/blob/main/LICENSE)
- [README](https://github.com/cswry/OSEDiff/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cswry-osediff
