Diff2Flow ODE KSampler
Your SDXL Isn't Flow-Matching. This Node Pretends It Is.
- model
- positive
- negative
- latent_image
- LATENT
Every modern model - Flux, SD3, Z-Image - is trained with flow matching: instead of predicting the noise added at each step, the model learns a velocity along a nearly straight path from noise to image. Straight paths are why those models nail 4–8 steps while your SD1.5 or SDXL checkpoint still wants 20–30 with a curved noise schedule. Diff2Flow is a 2025 paper that bridges the two paradigms by converting a pretrained diffusion model into a flow-matching one. This node applies that math at inference time, so your existing SD checkpoint gets sampled as if it were a flow model - through a real ODE solver, no retraining required.
It comes from Koratahiu, who has more skin in this game than most custom-node authors: he's a OneTrainer contributor and the person behind the SDXL-as-flow-matching training branch (BigASP 2.5). This is the inference half of that project. The pack is explicitly experimental, so treat it as a toy worth playing with, not a replacement for your daily KSampler.
What it actually does
Diff2Flow ODE KSampler lives under sampling/custom_sampling and looks like a drop-in KSampler: MODEL, positive, negative, latent_image in, LATENT out, wire it to a VAE Decode. The trick is that when you hit Queue, it patches your loaded model in-place (enable_diff2flow), building the schedule constants that let a diffusion model speak flow-matching. It works with epsilon-prediction checkpoints (SD1.5, SDXL) and v-prediction ones (SD2.1). Other prediction types raise a hard error.
Mechanically, each step converts the flow-matching timestep back to the diffusion timestep, realigns the latent, runs your UNet, then turns its output into a velocity field (z_pred − eps_pred). That velocity gets integrated by a genuine ODE solver from torchdiffeq - not the usual discretized sampler loop.
The inputs that matter
solver- the whole point.euleris the fast, predictable default (basically standard Euler). The adaptive solvers (dopri5,bosh3,fehlberg2,adaptive_heun,dopri8) pick their own step sizes on the fly;rk4,midpoint, andheun3are fixed-step alternatives. If you want to see what the fuss is about,dopri5is the fun one.steps- how many fixed steps for non-adaptive solvers. Adaptive solvers largely ignore it; that's whatmax_steps(default 100) caps instead.cfg- standard classifier-free guidance, applied between the positive and negative velocity fields. Default 5; same ballpark as your SDXL KSampler.scheduler- defaults tosimple, and here's a KB-backed warning: on a straight flow path, Karras-style schedules that concentrate denoising in the middle tend to distort rather than help. Start withsimpleorsgm_uniformand don't reach for Karras out of habit.log_relative_tolerance/log_absolute_tolerance(optional) - only meaningful for adaptive solvers; the tolerances that telltorchdiffeqhow hard to chase accuracy. Defaults of −2.5 / −3.5 are a sane start.
Install
ComfyUI Manager: search "ComfyUI-Diff2Flow". Or the manual way:
cd ComfyUI/custom_nodes
git clone https://github.com/Koratahiu/ComfyUI-Diff2Flow
pip install torchdiffeq # the one real dependency; pins to 0.2.5
Restart ComfyUI. No model downloads - it patches whatever checkpoint you already have.
Gotchas (and when to skip it)
The source code is more honest than the README in one important spot: denoise below 1.0 raises NotImplementedError. The field exists in the node, but img2img and refining through the denoise slider just don't work yet - keep it at 1.0.
The other traps: if torchdiffeq isn't installed, the solver dropdown shows a single "torchdiffeq not installed" entry and the node fails with an ImportError - the pip install above is mandatory. ODE samplers don't support masks well, so don't feed it inpainting. And remember this is inference-only: the paper's headline 2-step results come from finetuning with the Diff2Flow objective (official CompVis code, or OneTrainer PR #1052). At plain inference you'll get a different - sometimes better, sometimes just different - rendering, not magic.
Expect it to be slower than a KSampler (adaptive solvers especially), and keep expectations measured for a pack this new with zero community chatter behind it. But if you've ever wondered what your SDXL would look like with a straight path to noise, this is the cheapest way to find out.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| solver | COMBO | euler | 11 options: adaptive_heun, bosh3, dopri5, dopri8, euler, explicit_adams, +5 |
| steps | INT | 201–10000 | — |
| cfg | FLOAT | 5.00–100 | — |
| denoise | FLOAT | 1.000–1 | — |
| seed | INT | 00–18446744073709550000 | — |
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| latent_image | LATENT | — | |
| scheduler | COMBO | simple | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 |
| log_relative_toleranceopt | FLOAT | -2.5-7–0 | — |
| log_absolute_toleranceopt | FLOAT | -3.5-7–0 | — |
| max_stepsopt | INT | 1001–1000 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT | LATENT | — |