-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Add FLUX.2 Klein Inpaint Pipeline #13050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add FLUX.2 Klein Inpaint Pipeline #13050
Conversation
|
I have to be honest, I am not getting good results at all so far, especially when working with bounding box masks, even without a reference. At On the other hand, I don't have the same issues with the regular If you ask, I can provide examples of the results I get once my GPU frees up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds the Flux2KleinInpaintPipeline to enable image inpainting capabilities for the FLUX.2 Klein model. The pipeline supports both basic text-guided inpainting and experimental reference image conditioning, addressing issue #13005.
Changes:
- Implements a new inpainting pipeline for FLUX.2 Klein with masking support
- Adds optional reference image conditioning for more controlled inpainting
- Extends
Flux2ImageProcessorwithdo_binarizeanddo_convert_grayscaleparameters for mask processing
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/diffusers/pipelines/flux2/pipeline_flux2_klein_inpaint.py |
Main pipeline implementation with inpainting logic, mask handling, and reference image support |
tests/pipelines/flux2/test_pipeline_flux2_klein_inpaint.py |
Test suite covering basic inpainting functionality including different prompts, output shapes, and strength variations |
src/diffusers/pipelines/flux2/image_processor.py |
Enhanced image processor with binarization and grayscale conversion options |
src/diffusers/pipelines/flux2/__init__.py |
Export declarations for the new pipeline |
src/diffusers/pipelines/__init__.py |
Top-level export declarations |
src/diffusers/__init__.py |
Main package export declarations |
src/diffusers/utils/dummy_torch_and_transformers_objects.py |
Dummy object for missing dependencies |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| height is not None | ||
| and height % (self.vae_scale_factor * 2) != 0 | ||
| or width is not None | ||
| and width % (self.vae_scale_factor * 2) != 0 |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition has a logical error due to operator precedence. The and operators bind more tightly than or, causing incorrect evaluation. This should be:
if (
(height is not None and height % (self.vae_scale_factor * 2) != 0)
or (width is not None and width % (self.vae_scale_factor * 2) != 0)
):Otherwise, when height is None, the condition height is not None and height % (self.vae_scale_factor * 2) != 0 evaluates to False, but then it will evaluate width is not None and width % (self.vae_scale_factor * 2) != 0, which could raise a TypeError if width is None when trying to perform the modulo operation.
Alternatively, following the pattern in FluxInpaintPipeline (line 515), you can remove the None checks entirely if height and width are guaranteed to be set by this point.
| height is not None | |
| and height % (self.vae_scale_factor * 2) != 0 | |
| or width is not None | |
| and width % (self.vae_scale_factor * 2) != 0 | |
| (height is not None and height % (self.vae_scale_factor * 2) != 0) | |
| or (width is not None and width % (self.vae_scale_factor * 2) != 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have followed the pattern from Flux2KleinPipeline and seems correct to me.
In Python, operator precedence is and > or
so, Python will evaluate this as
(height is not None and height % (self.vae_scale_factor * 2) != 0) or
(width is not None and width % (self.vae_scale_factor * 2) != 0)So, there is no precedence bug here.
And
could raise a TypeError if width is None when trying to perform the modulo operation.
This cannot happen because of short-circuiting.
|
|
||
| class Flux2KleinInpaintPipelineFastTests(PipelineTesterMixin, unittest.TestCase): | ||
| pipeline_class = Flux2KleinInpaintPipeline | ||
| params = frozenset(["prompt", "height", "width", "guidance_scale", "prompt_embeds"]) |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The params frozenset should include "image" and "mask_image" since these are required parameters for an inpainting pipeline. Following the pattern in other inpainting pipelines (see tests/pipelines/pipeline_params.py TEXT_GUIDED_IMAGE_INPAINTING_PARAMS), the params should be:
params = frozenset(["prompt", "image", "mask_image", "height", "width", "guidance_scale", "prompt_embeds"])Without including these parameters, the standard pipeline tests from PipelineTesterMixin may not properly validate these critical inputs.
| @unittest.skip("Needs to be revisited") | ||
| def test_encode_prompt_works_in_isolation(self): | ||
| pass |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR description highlights the reference image conditioning feature (image_reference parameter), which is a key differentiating feature of this pipeline. However, there are no tests for this functionality. Consider adding a test like:
def test_flux2_klein_inpaint_with_reference_image(self):
pipe = self.pipeline_class(**self.get_dummy_components()).to(torch_device)
inputs = self.get_dummy_inputs(torch_device)
# Add a reference image
image_reference = floats_tensor((1, 3, 32, 32), rng=random.Random(0)).to(torch_device)
inputs["image_reference"] = image_reference
output_with_ref = pipe(**inputs).images[0]
# Test without reference
inputs_no_ref = self.get_dummy_inputs(torch_device)
output_no_ref = pipe(**inputs_no_ref).images[0]
# Outputs should be different
max_diff = np.abs(output_with_ref - output_no_ref).max()
assert max_diff > 1e-6This would help ensure the reference image functionality works as intended.
|
I'd missed patchifying the mask latents earlier. With that corrected, here are some new example generations: Below all are using 9B model with
@Natans8 this might improve what you observed but I'll suggest wait till maintainers' review. |





















What does this PR do?
Fixes #13005
This PR adds the
Flux2KleinInpaintPipelinefor image inpainting using the FLUX.2 [Klein] model with optional reference image conditioning.Examples
Basic Inpainting
Inpainting with Reference Image
Known Limitations
Generation quality may vary - Some outputs may contain artifacts. This can often be mitigated with better prompts and tuning hyperparameters (strength, guidance_scale, num_inference_steps).
Reference image conditioning is experimental - Inpainting with
image_referencemay not consistently produce desired results.These limitations may stem either from a bug in the pipeline implementation by me or from inherent constraints of the model. Feedback is appreciated.
Before submitting
documentation guidelines, and
here are tips on formatting docstrings.
Who can review?
@asomoza @sayakpaul
Anyone in the community is free to review the PR once the tests have passed.