Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -29,6 +29,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 |
| Wan 2.2 A14B (T2V/I2V) | 1280x720 | Nvidia 30xx+ | 12GB | 32GB | Dual-expert MoE; Q4_K_M 12GB; Q8 18GB+; Diffusers requires 32GB+ |
| Wan 2.2 TI2V-5B | 1280x720 | Nvidia 20xx+ | 8GB | 16GB | Single transformer; Q4_K_M 6GB+; Q8 8GB+; Diffusers 12GB+ |

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 @@ -66,6 +66,7 @@
ConditioningFieldData,
FLUXConditioningInfo,
Ideogram4ConditioningInfo,
Krea2ConditioningInfo,
QwenImageConditioningInfo,
SD3ConditioningInfo,
SDXLConditioningInfo,
Expand Down Expand Up @@ -166,6 +167,7 @@ def initialize(
ZImageConditioningInfo,
Ideogram4ConditioningInfo,
QwenImageConditioningInfo,
Krea2ConditioningInfo,
AnimaConditioningInfo,
WanConditioningInfo,
],
Expand Down
7 changes: 5 additions & 2 deletions invokeai/app/invocations/anima_latents_to_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,12 @@ def _use_tiled_decode(device: torch.device, full_decode_working_memory: int) ->
memory would consume most of the device, otherwise a single-pass decode is
faster (~0.65s vs ~1.05s at 1024x1024) and exact.
"""
if device.type != "cuda":
if device.type == "cuda":
total_vram = torch.cuda.get_device_properties(device).total_memory
elif device.type == "xpu":
total_vram = torch.xpu.get_device_properties(device).total_memory
else:
return False
total_vram = torch.cuda.get_device_properties(device).total_memory
return full_decode_working_memory > 0.7 * total_vram

@torch.no_grad()
Expand Down
4 changes: 4 additions & 0 deletions invokeai/app/invocations/baseinvocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ def invoke(self, context: InvocationContext) -> BaseInvocationOutput:
"""Invoke with provided context and return outputs."""
pass

def get_event_invocation(self) -> "BaseInvocation":
"""Returns the invocation representation included in execution events."""
return self

def invoke_internal(self, context: InvocationContext, services: "InvocationServices") -> BaseInvocationOutput:
"""
Internal invoke method, calls `invoke()` after some prep.
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 @@ -157,6 +157,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 @@ -173,6 +174,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"
wan_model = "Wan 2.2 model (Transformer) to load"
Expand Down Expand Up @@ -366,6 +368,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