Skip to content

[Modular] Krea2 Img2Img, Inpaint and Reference Images modular pipeline - #14370

Open
lucasruan1618 wants to merge 2 commits into
huggingface:mainfrom
lucasruan1618:feature/krea2-modular-img2img-inpaint
Open

[Modular] Krea2 Img2Img, Inpaint and Reference Images modular pipeline#14370
lucasruan1618 wants to merge 2 commits into
huggingface:mainfrom
lucasruan1618:feature/krea2-modular-img2img-inpaint

Conversation

@lucasruan1618

Copy link
Copy Markdown

What does this PR do?

This PR adds img2img, inpainting, and reference-conditioned generation to the Krea 2 Raw and Turbo modular pipelines. It resolves #14290.

The modular pipeline automatically selects the workflow from the supplied inputs:

  • Passing image runs img2img.
  • Passing both image and mask_image runs inpainting.
  • Passing reference_image runs reference-conditioned generation from pure noise.
  • Passing an ordered list to reference_image supports any number of references, with optional per-reference attention scaling.

The reference workflow is generic and can be used by LoRAs trained with clean reference-image tokens, including Krea 2 Identity Edit.

Img2img example

import torch

from diffusers import ModularPipeline
from diffusers.utils import load_image


MODEL_ID = "krea/Krea-2-Turbo"

pipe = ModularPipeline.from_pretrained(MODEL_ID)
pipe.load_components(dtype=torch.bfloat16)
pipe.to("cuda")

init_image = load_image(
    "https://github.com/lucasruan1618/Image_storage/blob/main/Input/cute_cat.png?raw=true"
).convert("RGB")

prompt = "wizard cat, Gandalf-inspired, majestic yet cute, detailed fantasy illustration"

for strength in [0.5, 0.6, 0.7, 0.8, 0.9, 1.0]:
    image = pipe(
        prompt=prompt,
        image=init_image,
        height=1024,
        width=1024,
        strength=strength,
        num_inference_steps=8,
        generator=torch.Generator(device="cuda").manual_seed(42),
        output="images",
    )[0]
    image.save(f"krea2_turbo_modular_img2img_{strength}.png")

Inpainting example

import torch

from diffusers import ModularPipeline
from diffusers.utils import load_image


MODEL_ID = "krea/Krea-2-Turbo"

pipe = ModularPipeline.from_pretrained(MODEL_ID)
pipe.load_components(dtype=torch.bfloat16)
pipe.to("cuda")

init_image = load_image(
    "https://github.com/lucasruan1618/Image_storage/blob/main/Input/cute_cat.png?raw=true"
).convert("RGB")
mask_image = load_image(
    "https://github.com/lucasruan1618/Image_storage/blob/main/Input/mask_cat.png?raw=true"
).convert("L")

prompt = "cat wizard wearing a detailed red hat, Gandalf-inspired fantasy illustration"

for strength in [0.5, 0.6, 0.7, 0.8, 0.9, 1.0]:
    image = pipe(
        prompt=prompt,
        image=init_image,
        mask_image=mask_image,
        height=1024,
        width=1024,
        strength=strength,
        num_inference_steps=8,
        generator=torch.Generator(device="cuda").manual_seed(42),
        output="images",
    )[0]
    image.save(f"krea2_turbo_modular_inpaint_{strength}.png")

Img2img results at different strengths

Init image
0.5
0.6
0.7
0.8
0.9
1.0

Inpainting results at different strengths

Init image
Mask image
0.5
0.6
0.7
0.8
0.9
1.0

Why strengths 0.9 and 1.0 produce the same result

These examples use only 8 inference steps. The strength calculation effectively uses t_start = int(8 - 8 * strength). For strength=0.9, int(0.8) is 0; for strength=1.0, it is also 0. Both strengths therefore use the same full 8-step denoising schedule. With identical inputs and generator seed, img2img and inpainting produce identical outputs. This is expected discrete-step rounding behavior.

One-reference example

With one reference, generation starts from pure noise while the reference supplies the subject identity and image-grounded prompt context.

import torch

from diffusers import ModularPipeline
from diffusers.utils import load_image


pipe = ModularPipeline.from_pretrained("krea/Krea-2-Turbo")
pipe.load_components(dtype=torch.bfloat16)
pipe.load_lora_weights(
    "conradlocke/krea2-identity-edit",
    weight_name="krea2_identity_edit_v1_2_r64.safetensors",
    adapter_name="krea2_edit",
)
pipe.to("cuda")

wizard_cat = load_image(
    "https://github.com/lucasruan1618/Image_storage/blob/main/Input/cute_cat.png?raw=true"
).convert("RGB")

image = pipe(
    prompt="Place this wizard cat in a busy night market while preserving its appearance and clothing.",
    reference_image=[wizard_cat],
    height=1024,
    width=1024,
    reference_image_encoder_resolution=768,
    reference_attention_scale=4.0,
    num_inference_steps=10,
    generator=torch.Generator(device="cuda").manual_seed(42),
    output="images",
)[0]
image.save("krea2_reference_cat_in_market.png")
Reference image
One-reference result

Two-reference example

reference_image accepts an ordered list of any length. In this example, the first reference supplies the scene and composition while the second supplies the subject. The attention scale can be set separately for each reference.

import torch

from diffusers import ModularPipeline
from diffusers.utils import load_image


pipe = ModularPipeline.from_pretrained("krea/Krea-2-Turbo")
pipe.load_components(dtype=torch.bfloat16)
pipe.load_lora_weights(
    "conradlocke/krea2-identity-edit",
    weight_name="krea2_identity_edit_v1_2_r64.safetensors",
    adapter_name="krea2_edit",
)
pipe.to("cuda")

dog_and_bench = load_image(
    "https://github.com/lucasruan1618/Image_storage/blob/main/Input/cute_dog.png?raw=true"
).convert("RGB")
wizard_cat = load_image(
    "https://github.com/lucasruan1618/Image_storage/blob/main/Input/cute_cat.png?raw=true"
).convert("RGB")

image = pipe(
    prompt=(
        "Place the wizard cat from the second image sitting on the bench beside the white dog from the first image. "
        "Preserve the bench, field, dog, and wizard cat."
    ),
    reference_image=[dog_and_bench, wizard_cat],
    height=1024,
    width=1024,
    reference_image_encoder_resolution=768,
    reference_attention_scale=[1.0, 4.0],
    num_inference_steps=10,
    generator=torch.Generator(device="cuda").manual_seed(42),
    output="images",
)[0]
image.save("krea2_reference_cat_with_dog.png")
First reference: dog and bench
Second reference: wizard cat
Two-reference result

Before submitting

  • Did you use an AI agent (Claude Code, Codex, Cursor, etc.) to help with this PR? If so:
    • Did you read the Coding with AI agents guide?
    • Did you run the self-review skill on the diff?
    • Did you share the final self-review notes in the PR description or a comment?
  • Did you read the contributor guideline?
  • Did you read our philosophy doc? (important for complex PRs)
  • Was this discussed/approved via a GitHub issue or the forum? Please add a link to it if that's the case.
  • Did you make sure to update the documentation with your changes? Here are the
    documentation guidelines, and
    here are tips on formatting docstrings.
  • Did you write any new necessary tests?
  • Are you the author (or part of the team) of the model/pipeline (only applicable for model/pipeline related PRs)?

Who can review?

  • Pipelines and models: @dg845 and @asomoza
    Anyone in the community is free to review the PR !

@github-actions github-actions Bot added fixes-issue size/L PR with diff > 200 LOC documentation Improvements or additions to documentation models tests modular-pipelines and removed size/L PR with diff > 200 LOC labels Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Modular] Krea 2 image-to-image generation

1 participant