Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e7b4051
feat(krea2): add Krea-2-Turbo model + LoRA support (WIP)
Pfannkuchensack Jun 25, 2026
63f8d1b
Merge branch 'main' into feat/krea2-turbo-support
Pfannkuchensack Jun 25, 2026
89b27b5
fix(krea2): support single-file VAE/encoder mix-and-match end-to-end
Pfannkuchensack Jun 26, 2026
32c17b6
Merge remote-tracking branch 'upstream/main' into feat/krea2-turbo-su…
Pfannkuchensack Jul 2, 2026
b57e3bd
fix(krea2): re-apply Wan→QwenImage VAE adapter after upstream merge
Pfannkuchensack Jul 2, 2026
38a0a52
fix(graph): make isMainModelWithoutUnet a type guard incl. krea2_mode…
Pfannkuchensack Jul 2, 2026
9e0318c
test(krea2): add Krea2VariantType type-test to satisfy knip
Pfannkuchensack Jul 2, 2026
5cd5f08
Merge branch 'main' into feat/krea2-turbo-support
JPPhoto Jul 4, 2026
586b36b
Merge branch 'main' into feat/krea2-turbo-support
Pfannkuchensack Jul 5, 2026
0898730
build: pin diffusers to 0.39.0 (first stable release with Krea-2)
Pfannkuchensack Jul 5, 2026
96c96c8
feat(krea2): metadata recall, starter models, and config-probe tests
Pfannkuchensack Jul 5, 2026
dc0620a
Chore Ruff
Pfannkuchensack Jul 5, 2026
484ae23
Merge remote-tracking branch 'upstream/main' into feat/krea2-turbo-su…
Pfannkuchensack Jul 9, 2026
1a084a0
Merge branch 'main' into feat/krea2-turbo-support
Pfannkuchensack Jul 11, 2026
f5a24df
Merge remote-tracking branch 'origin/main' into pr-9304-review
JPPhoto Jul 13, 2026
5cd2bf8
fix(krea2): validate denoise inputs and VAE compatibility
JPPhoto Jul 13, 2026
cc63dff
test(krea2): add loader, denoise, graph, listener, recall and starter…
Pfannkuchensack Jul 13, 2026
892661a
fix(ui): wire Krea metadata recall actions
JPPhoto Jul 13, 2026
98301a5
Merge remote-tracking branch 'refs/remotes/pr9304/source' into pr-930…
JPPhoto Jul 13, 2026
cf57b4d
fix(krea2): address adversarial review findings
JPPhoto Jul 13, 2026
e191678
fix Krea-2 review findings
JPPhoto Jul 13, 2026
197ce76
fix(krea2): use per-prompt position ids for the CFG uncond pass
Pfannkuchensack Jul 14, 2026
b0219e3
fix(krea2): resolve deep-review findings across encoder, loaders, LoR…
Pfannkuchensack Jul 14, 2026
21fb90d
fix(krea2): reshape native final-layer modulation + honor scheduler s…
Pfannkuchensack Jul 14, 2026
48a838f
fix(krea2): resolve remaining review findings
JPPhoto Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Invoke features an organized gallery system for easily storing, accessing, and r
- Flux.2 Klein 9B
- Z-Image Turbo
- Z-Image Base
- Krea 2 Turbo
- Anima
- Qwen Image
- Qwen Image Edit
Expand Down
71 changes: 71 additions & 0 deletions docs/src/content/docs/features/krea-2.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: Krea-2
description: Generate images with the Krea-2 text-to-image models (Turbo and Raw), including the GGUF / single-file workflow and the conditioning enhancers.
lastUpdated: 2026-07-13
sidebar:
order: 5
---

Krea-2 is a ~12B single-stream diffusion-transformer text-to-image family. InvokeAI supports both
published checkpoints:

- **Krea-2-Turbo** — distilled for fast, low-step generation. Runs at **8 steps** with **CFG disabled**
(CFG Scale `1.0`). This is the recommended checkpoint for everyday use.
- **Krea-2-Raw** — the undistilled base checkpoint. Runs at **more steps (~28)** with **CFG enabled**
(CFG Scale ~`5.5`, equivalent to the reference pipeline's guidance `4.5`) and supports negative prompts. It is primarily intended as a base for
finetuning / LoRA training, but full inference is supported.

The variant is detected automatically on install, and selecting a Krea-2 model sets sensible defaults
(steps, CFG, 1024×1024) for that variant.

## Hardware

Krea-2 is a large model. See the [System Requirements](../../start-here/system-requirements) table for
details. In short, on a 24 GB card enable **FP8** in the model's Default Settings to fit 1024² (with a
LoRA). For lower VRAM, use a **GGUF** transformer (Q4_K ≈ 12 GB total).

## Installing

The easiest path is the **Krea-2 launchpad bundle** in the Model Manager, which installs the models and
their dependencies together.

Krea-2 needs three components:

| Component | Diffusers install | GGUF / single-file install |
| ----------------------- | ----------------------- | ------------------------------------ |
| Transformer | bundled in the pipeline | the `.gguf` / single-file checkpoint |
| VAE (Qwen-Image) | bundled | installed separately |
| Text encoder (Qwen3-VL) | bundled | installed separately |

- **Diffusers** (e.g. `krea/Krea-2-Turbo`, `krea/Krea-2-Raw`): a single ~26 GB install that bundles the
VAE and text encoder. Nothing else is required.
- **GGUF / single-file**: the checkpoint ships **only the transformer**. You must also install a
standalone **Qwen-Image VAE** and a **Qwen3-VL encoder** (both included in the launchpad bundle).

When you select a GGUF/single-file Krea-2 model, InvokeAI auto-selects an installed VAE and Qwen3-VL
encoder if you have them. If none are installed, you'll be prompted to pick them (in the model dropdowns)
before you can generate. Selecting a Diffusers Krea-2 model clears those standalone selections and uses
the bundled components.

:::note[Qwen3-VL encoder download]
Single-file Qwen3-VL encoders bundle only the weights. The tokenizer/config are fetched once from
HuggingFace (`Qwen/Qwen3-VL-4B-Instruct`) on first use, then cached for offline use. A single-file fp8
encoder is kept resident in fp8 (roughly half the VRAM of the bf16 encoder).
:::

## Conditioning enhancers

Two optional, off-by-default toggles are available under **Advanced Options** (below CFG Scale). They
transform the text conditioning and are especially useful for the distilled Turbo checkpoint:

- **Conditioning Rebalance** — per-layer weighting of the text embedding to improve prompt adherence.
- **Seed Variance Enhancer** — injects controlled noise into the conditioning to restore per-seed
diversity (the distilled model otherwise produces near-identical images across seeds), trading some
prompt adherence for variety.

Both are recorded in image metadata and can be recalled.

## LoRA

Krea-2 LoRAs (diffusers PEFT format) are supported and apply to both the transformer and — where the
LoRA includes text-encoder layers — the Qwen3-VL encoder.
1 change: 1 addition & 0 deletions docs/src/content/docs/start-here/system-requirements.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ The requirements below are rough guidelines for best performance. GPUs with less
| FLUX.2 Klein 4B | 1024x1024 | Nvidia 30xx+ | 12GB | 16GB | FP8 works with 8GB+; Diffusers + encoder |
| FLUX.2 Klein 9B | 1024x1024 | Nvidia 40xx | 24GB | 32GB | FP8 works with 12GB+; Diffusers + encoder |
| Z-Image Turbo | 1024x1024 | Nvidia 20xx+ | 8GB | 16GB | Q4_K 8GB; Q8/BF16 16GB+ |
| Krea-2 (Turbo / Raw) | 1024x1024 | Nvidia 40xx | 24GB | 32GB | FP8 works with 16GB+; GGUF Q4_K ~12GB. Diffusers ~26GB; GGUF needs a standalone VAE + Qwen3-VL encoder |

:::tip[`tmpfs` on Linux]
If your temporary directory is mounted as a `tmpfs`, ensure it has sufficient space.
Expand Down
2 changes: 2 additions & 0 deletions invokeai/app/api/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
CogView4ConditioningInfo,
ConditioningFieldData,
FLUXConditioningInfo,
Krea2ConditioningInfo,
QwenImageConditioningInfo,
SD3ConditioningInfo,
SDXLConditioningInfo,
Expand Down Expand Up @@ -153,6 +154,7 @@ def initialize(
CogView4ConditioningInfo,
ZImageConditioningInfo,
QwenImageConditioningInfo,
Krea2ConditioningInfo,
AnimaConditioningInfo,
],
ephemeral=True,
Expand Down
8 changes: 8 additions & 0 deletions invokeai/app/invocations/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ class FieldDescriptions:
t5_encoder = "T5 tokenizer and text encoder"
glm_encoder = "GLM (THUDM) tokenizer and text encoder"
qwen3_encoder = "Qwen3 tokenizer and text encoder"
qwen3_vl_encoder = "Qwen3-VL tokenizer and text encoder"
clip_embed_model = "CLIP Embed loader"
clip_g_model = "CLIP-G Embed loader"
unet = "UNet (scheduler, LoRAs)"
Expand All @@ -172,6 +173,7 @@ class FieldDescriptions:
sd3_model = "SD3 model (MMDiTX) to load"
cogview4_model = "CogView4 model (Transformer) to load"
z_image_model = "Z-Image model (Transformer) to load"
krea2_model = "Krea-2 model (Transformer) to load"
qwen_image_model = "Qwen Image Edit model (Transformer) to load"
qwen_vl_encoder = "Qwen2.5-VL tokenizer, processor and text/vision encoder"
sdxl_main_model = "SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load"
Expand Down Expand Up @@ -350,6 +352,12 @@ class QwenImageConditioningField(BaseModel):
conditioning_name: str = Field(description="The name of conditioning tensor")


class Krea2ConditioningField(BaseModel):
"""A Krea-2 conditioning tensor primitive value"""

conditioning_name: str = Field(description="The name of conditioning tensor")


class AnimaConditioningField(BaseModel):
"""An Anima conditioning tensor primitive value.

Expand Down
79 changes: 79 additions & 0 deletions invokeai/app/invocations/krea2_conditioning_rebalance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import math

import torch

from invokeai.app.invocations.baseinvocation import BaseInvocation, Classification, invocation
from invokeai.app.invocations.fields import FieldDescriptions, Input, InputField, Krea2ConditioningField
from invokeai.app.invocations.primitives import Krea2ConditioningOutput
from invokeai.app.services.shared.invocation_context import InvocationContext
from invokeai.backend.krea2.sampling_utils import KREA2_SELECT_LAYERS
from invokeai.backend.stable_diffusion.diffusion.conditioning_data import (
ConditioningFieldData,
Krea2ConditioningInfo,
)

_NUM_TEXT_LAYERS = len(KREA2_SELECT_LAYERS) # 12


@invocation(
"krea2_conditioning_rebalance",
title="Conditioning Rebalance - Krea-2",
tags=["conditioning", "krea2", "krea-2"],
category="conditioning",
version="1.0.0",
classification=Classification.Prototype,
)
class Krea2ConditioningRebalanceInvocation(BaseInvocation):
"""Per-layer rebalancing of Krea-2 text conditioning (improves prompt adherence).

Krea-2 conditioning stacks 12 Qwen3-VL hidden-state layers per token. Weighting those layers
individually (and applying an overall multiplier) lets you push the model harder toward the prompt,
counteracting the quality-dilution from distillation. Ported from the ComfyUI
`ConditioningKrea2Rebalance` node. This is an optional pass between the text encoder and denoise.
"""

conditioning: Krea2ConditioningField = InputField(
description=FieldDescriptions.cond, input=Input.Connection, title="Conditioning"
)
per_layer_weights: str = InputField(
default="1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.5,5.0,1.1,4.0,1.0",
description=f"Comma-separated gains for the {_NUM_TEXT_LAYERS} tapped encoder layers (exactly "
f"{_NUM_TEXT_LAYERS} values).",
)
multiplier: float = InputField(
default=4.0,
allow_inf_nan=False,
description="Overall multiplier applied to the conditioning after per-layer weighting.",
)

def _parse_weights(self) -> list[float]:
try:
weights = [float(x.strip()) for x in self.per_layer_weights.split(",") if x.strip() != ""]
except ValueError as e:
raise ValueError(f"per_layer_weights must be comma-separated numbers: {e}") from e
if len(weights) != _NUM_TEXT_LAYERS:
raise ValueError(f"per_layer_weights must have exactly {_NUM_TEXT_LAYERS} values, got {len(weights)}.")
if not all(math.isfinite(weight) for weight in weights):
raise ValueError("per_layer_weights must contain only finite values.")
return weights

@torch.no_grad()
def invoke(self, context: InvocationContext) -> Krea2ConditioningOutput:
weights = self._parse_weights()

cond_data = context.conditioning.load(self.conditioning.conditioning_name)
assert len(cond_data.conditionings) == 1
conditioning = cond_data.conditionings[0]
assert isinstance(conditioning, Krea2ConditioningInfo)

embeds = conditioning.prompt_embeds # (B, seq, 12, hidden)
gains = torch.tensor(weights, dtype=embeds.dtype, device=embeds.device).view(1, 1, _NUM_TEXT_LAYERS, 1)
embeds = embeds * gains * self.multiplier

new_data = ConditioningFieldData(
conditionings=[
Krea2ConditioningInfo(prompt_embeds=embeds, prompt_embeds_mask=conditioning.prompt_embeds_mask)
]
)
conditioning_name = context.conditioning.save(new_data)
return Krea2ConditioningOutput.build(conditioning_name)
Loading
Loading