Diffusers 集成 FLUX-2 模型

Hugging Face:Blog(RSS)·2025-11-25 08:00·278天前
AI 导读

Hugging Face 的 Diffusers 库正式集成 Black Forest Labs 开发的 FLUX-2 文生图模型。该模型拥有 120 亿参数,采用多模态扩散 Transformer 架构,在图像质量、提示遵循和分辨率方面表现优异,支持生成 1024x1024 像素图像。此次集成让开发者能通过 Diffusers API 便捷使用这一先进模型。

Hugging Face:Blog(RSS)
精选
80AI 编辑部评分,满分 100

Diffusers 集成 FLUX-2 模型

2025-11-25 08:00· 278天前
AI 导读

Hugging Face 的 Diffusers 库正式集成 Black Forest Labs 开发的 FLUX-2 文生图模型。该模型拥有 120 亿参数,采用多模态扩散 Transformer 架构,在图像质量、提示遵循和分辨率方面表现优异,支持生成 1024x1024 像素图像。此次集成让开发者能通过 Diffusers API 便捷使用这一先进模型。

推荐理由

FLUX-2 图像生成模型正式进入 Diffusers 生态,本地部署和微调更便捷

正文 · AI 翻译

欢迎 FLUX.2——Black Forest Labs 推出的全新开源图像生成模型 🤗

发布于 2025 年 11 月 25 日

FLUX.2 是 Black Forest Labs 继 Flux.1 系列之后推出的最新图像生成模型系列。这是一个采用全新架构、从头开始预训练的全新模型!本文将讨论 FLUX.2 引入的关键变化、在不同配置下执行推理的方法,以及 LoRA 微调。

🚨 FLUX.2 并非 FLUX.1 的直接替代品,而是一个全新的图像生成与编辑模型。

目录

  • FLUX.2 简介
  • 使用 Diffusers 进行推理
  • 高级提示词
  • LoRA 微调

FLUX.2 简要介绍

FLUX.2 既可用于图像引导的图像生成,也可用于文本引导的图像生成。此外,它还能将多张图像作为参考输入,同时生成最终输出图像。下面,我们简要讨论 FLUX.2 引入的关键变化。

文本编码器

首先,与 Flux.1 使用两个文本编码器不同,FLUX.2 仅使用一个文本编码器——Mistral Small 3.1。使用单一文本编码器大大简化了提示词嵌入向量的计算过程。该流水线支持最大序列长度(max_sequence_length)为 512。FLUX.2 并非使用单层输出作为提示词嵌入向量,而是堆叠中间层的输出,已知这种做法更为有益。

DiT

FLUX.2 沿用了与 Flux.1 相同的通用多模态扩散 Transformer(MM-DiT)+ 并行 DiT 架构。回顾一下,MM-DiT 块首先在独立的流中处理图像潜变量和条件文本,仅在注意力操作时将两者合并,因此被称为"双流"块。随后,并行块对拼接后的图像和文本流进行操作,可视为"单流"块。

从 Flux.1 到 FLUX.2,DiT 的关键变化如下:

  • 时间信息和引导信息(以 AdaLayerNorm-Zero 调制参数的形式)分别在所有双流和单流 Transformer 块之间共享,而非像 Flux.1 那样为每个块设置独立的调制参数。

  • 模型中的任何层都不使用偏置参数。具体来说,两个 Transformer 模块中的注意力子块和前馈(FF)子块,在其任何层中均不使用偏置参数。

  • 在 Flux.1 中,单流 Transformer 模块将注意力输出投影与前馈输出投影融合在一起。FLUX.2 的单流模块还将注意力 QKV 投影与前馈输入投影融合,从而创建了一个完全并行的 Transformer 模块:

图片取自 ViT-22B 论文。

请注意,与上图所示的 ViT-22B 模块相比,FLUX.2 使用了 SwiGLU 风格的 MLP 激活函数,而非 GELU 激活函数(并且同样不使用偏置参数)。

  • FLUX.2 中单流 Transformer 模块的比例更大(8 个双流模块对 48 个单流模块,而 Flux.1 的比例为 19/38)。这也意味着单流模块在 DiT 参数中占据了更大比例:Flux.1[dev]-12B 约 54% 的总参数位于双流模块中,而 FLUX.2[dev]-32B 约 24% 的参数位于双流模块中(约 73% 位于单流模块中)。

其他

  • 新的自编码器,即 AutoencoderKLFlux2
  • 整合分辨率相关时间步调度的更好方法

使用 Diffusers 进行推理

FLUX.2 使用了更大的 DiT 和 Mistral3 Small 作为其文本编码器。当两者一起使用且不进行任何卸载时,推理需要超过 80GB 的显存。在以下章节中,我们将展示如何在各种系统级限制下,以更易实现的方式对 FLUX.2 进行推理。

安装与身份验证

在尝试以下代码片段之前,请确保你已从 main 分支安装了 diffusers,并运行了 `hf auth login`。

pip uninstall diffusers -y && pip install git+https://github.com/huggingface/diffusers -U

常规推理

from diffusers import Flux2Pipeline
import torch

repo_id = "black-forest-labs/FLUX.2-dev"
pipe = Flux2Pipeline.from_pretrained(repo_id, torch_dtype=torch.bfloat16)
pipe.enable_model_cpu_offload()

image = pipe(
    prompt="dog dancing near the sun",
    num_inference_steps=50, # 28 is a good trade-off
    guidance_scale=4,
    height=1024,
    width=1024
).images[0]

上述代码片段已在 H100 上测试过,如果不启用 CPU 卸载,它不足以在该 GPU 上运行推理。启用 CPU 卸载后,此配置运行大约需要 62GB 显存。

拥有 Hopper 系列 GPU 的用户可以利用 Flash Attention 3 来加速推理:

from diffusers import Flux2Pipeline
import torch

repo_id = "black-forest-labs/FLUX.2-dev"
pipe = Flux2Pipeline.from_pretrained(path, torch_dtype=torch.bfloat16)
+ pipe.transformer.set_attention_backend("_flash_3_hub")
pipe.enable_model_cpu_offload()

image = pipe(
    prompt="dog dancing near the sun",
    num_inference_steps=50,
    guidance_scale=2.5,
    height=1024,
    width=1024
).images[0]

你可以在此处查看支持的注意力后端(我们有很多!)。

资源受限

使用 4 位量化

借助 bitsandbytes,我们可以将 Transformer 和文本编码器模型加载为 4-bit 精度,从而使拥有 24GB GPU 的用户能够在本地使用该模型。你可以在拥有约 20 GB 空闲显存的 GPU 上运行这段代码。

展开

import torch
from transformers import Mistral3ForConditionalGeneration

from diffusers import Flux2Pipeline, Flux2Transformer2DModel

repo_id = "diffusers/FLUX.2-dev-bnb-4bit"
device = "cuda:0"
torch_dtype = torch.bfloat16

transformer = Flux2Transformer2DModel.from_pretrained(
  repo_id, subfolder="transformer", torch_dtype=torch_dtype, device_map="cpu"
)
text_encoder = Mistral3ForConditionalGeneration.from_pretrained(
  repo_id, subfolder="text_encoder", dtype=torch_dtype, device_map="cpu"
)

pipe = Flux2Pipeline.from_pretrained(
  repo_id, transformer=transformer, text_encoder=text_encoder, torch_dtype=torch_dtype
)
pipe.enable_model_cpu_offload()

prompt = "Realistic macro photograph of a hermit crab using a soda can as its shell, partially emerging from the can, captured with sharp detail and natural colors, on a sunlit beach with soft shadows and a shallow depth of field, with blurred ocean waves in the background. The can has the text `BFL Diffusers` on it and it has a color gradient that start with #FF5733 at the top and transitions to #33FF57 at the bottom."

image = pipe(
  prompt=prompt,
  generator=torch.Generator(device=device).manual_seed(42),
  num_inference_steps=50, # 28 is a good trade-off
  guidance_scale=4,
).images[0]

image.save("flux2_t2i_nf4.png")

请注意,我们使用的仓库包含了 FLUX.2 DiT 和 Mistral 文本编码器的 NF4 量化版本。

本地 + 远程

由于 Diffusers 管线的模块化设计,我们可以将各个模块分离并按顺序处理。我们将文本编码器解耦,并将其部署到推理端点(Inference Endpoint)上。这有助于我们释放显存,使其仅用于 DiT 和 VAE。

⚠️ 要使用远程文本编码器,你需要拥有一个有效的 token。如果你已经完成身份验证,则无需进一步操作。

下面的示例结合使用了本地推理和远程推理。此外,我们还通过 bitsandbytes 对 DiT 进行了 NF4 量化。

你可以在拥有 18 GB 显存的 GPU 上运行这段代码:

展开

from diffusers import Flux2Pipeline, Flux2Transformer2DModel
from diffusers import BitsAndBytesConfig as DiffBitsAndBytesConfig
from huggingface_hub import get_token
import requests
import torch
import io

def remote_text_encoder(prompts: str | list[str]):
  def _encode_single(prompt: str):
      response = requests.post(
          "https://remote-text-encoder-flux-2.huggingface.co/predict",
          json={"prompt": prompt},
          headers={
              "Authorization": f"Bearer {get_token()}",
              "Content-Type": "application/json"
          }
      )
      assert response.status_code == 200, f"{response.status_code=}"
      return torch.load(io.BytesIO(response.content))

  if isinstance(prompts, (list, tuple)):
      embeds = [_encode_single(p) for p in prompts]
      return torch.cat(embeds, dim=0)

  return _encode_single(prompts).to("cuda")

repo_id = "black-forest-labs/FLUX.2-dev"
quantized_dit_id = "diffusers/FLUX.2-dev-bnb-4bit"
dit = Flux2Transformer2DModel.from_pretrained(
  quantized_dit_id, subfolder="transformer", torch_dtype=torch_dtype, device_map="cpu"
)

pipe = Flux2Pipeline.from_pretrained(
  repo_id,
  text_encoder=None,
  transformer=dit,
  torch_dtype=torch.bfloat16,
)
pipe.enable_model_cpu_offload()

print("Running remote text encoder ☁️")
prompt1 = "a photo of a forest with mist swirling around the tree trunks. The word 'FLUX.2' is painted over it in big, red brush strokes with visible texture"
prompt2 = "a photo of a dense forest with rain. The word 'FLUX.2' is painted over it in big, red brush strokes with visible texture"
prompt_embeds = remote_text_encoder([prompt1, prompt2])
print("Done ✅")

out = pipe(
  prompt_embeds=prompt_embeds,
  generator=torch.Generator(device="cuda").manual_seed(42),
  num_inference_steps=50, # 28 is a good trade-off
  guidance_scale=4,
  height=1024,
  width=1024,
)

for idx, image in enumerate(out.images):
  image.save(f"flux_out_{idx}.png")

对于显存更低的 GPU,我们提供了 group_offloading 功能,这使得显存低至 8GB 的 GPU 也能使用该模型。不过,你需要 32GB 的空闲内存。或者,如果你愿意牺牲一些速度,可以将 `low_cpu_mem_usage=True` 设置为 True,从而将内存需求降低到仅 10GB。

展开

import io
import os

import requests
import torch

from diffusers import Flux2Pipeline, Flux2Transformer2DModel

repo_id = "diffusers/FLUX.2-dev-bnb-4bit"
torch_dtype = torch.bfloat16
device = "cuda"

def remote_text_encoder(prompts: str | list[str]):
  def _encode_single(prompt: str):
      response = requests.post(
          "https://remote-text-encoder-flux-2.huggingface.co/predict",
          json={"prompt": prompt},
          headers={"Authorization": f"Bearer {os.environ['HF_TOKEN']}", "Content-Type": "application/json"},
      )
      assert response.status_code == 200, f"{response.status_code=}"
      return torch.load(io.BytesIO(response.content))

  if isinstance(prompts, (list, tuple)):
      embeds = [_encode_single(p) for p in prompts]
      return torch.cat(embeds, dim=0)

  return _encode_single(prompts).to("cuda")

transformer = Flux2Transformer2DModel.from_pretrained(
  repo_id, subfolder="transformer", torch_dtype=torch_dtype, device_map="cpu"
)

pipe = Flux2Pipeline.from_pretrained(
  repo_id,
  text_encoder=None,
  transformer=transformer,
  torch_dtype=torch_dtype,
)
pipe.transformer.enable_group_offload(
  onload_device=device,
  offload_device="cpu",
  offload_type="leaf_level",
  use_stream=True,
  # low_cpu_mem_usage=True # uncomment for lower RAM usage
)
pipe.to(device)

prompt = "a photo of a forest with mist swirling around the tree trunks. The word 'FLUX.2' is painted over it in big, red brush strokes with visible texture"
prompt_embeds = remote_text_encoder(prompt)

image = pipe(
  prompt_embeds=prompt_embeds,
  generator=torch.Generator(device=device).manual_seed(42),
  num_inference_steps=50,
  guidance_scale=4,
  height=1024,
  width=1024,
).images[0]

你可以在此处查看其他支持的量化后端,以及在此处查看其他节省内存的技术。

要查看不同量化方式对图像的影响,你可以在下面的交互式演示中尝试,或者直接在 FLUX.2 量化实验 Space 中独立访问。

多张图像作为参考

FLUX.2 支持使用多张图像作为输入,允许你最多使用 10 张图像。但请注意,每增加一张图像都需要更多的显存。你可以通过索引(例如,图像 1、图像 2)或自然语言(例如,袋鼠、乌龟)来引用这些图像。为了获得最佳效果,最好的方法是结合使用这两种方式。

展开

import torch
from transformers import Mistral3ForConditionalGeneration

from diffusers import Flux2Pipeline, Flux2Transformer2DModel
from diffusers.utils import load_image

repo_id = "diffusers-internal-dev/new-model-image-final-weights"
device = "cuda:0"
torch_dtype = torch.bfloat16

pipe = Flux2Pipeline.from_pretrained(
  repo_id, torch_dtype=torch_dtype
)
pipe.enable_model_cpu_offload()

image_one = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/flux2_blog/kangaroo.png")
image_two = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/flux2_blog/turtle.png")

prompt = "the boxer kangaroo from image 1 and the martial artist turtle from image 2 are fighting in an epic battle scene at a beach of a tropical island, 35mm, depth of field, 50mm lens, f/3.5, cinematic lighting"

image = pipe(
  prompt=prompt,
  image=[image_one, image_two],
  generator=torch.Generator(device=device).manual_seed(42),
  num_inference_steps=50,
  guidance_scale=2.5,
  width=1024,
  height=768,
).images[0]

image.save(f"./flux2_t2i.png")

多图像输入

高级提示词

FLUX.2 支持高级提示词技术,例如结构化 JSON 提示词、精确的十六进制颜色控制以及多参考图像编辑。除了提供更强的控制能力外,这还允许在保持其他属性整体不变的情况下,灵活地更改特定属性。

例如,我们先以这个 JSON 作为基础架构(取自官方 FLUX.2 提示词指南):

{
  "scene": "overall scene description",
  "subjects": [
    {
      "description": "detailed subject description",
      "position": "where in frame",
      "action": "what they're doing"
    }
  ],
  "style": "artistic style",
  "color_palette": ["#hex1", "#hex2", "#hex3"],
  "lighting": "lighting description",
  "mood": "emotional tone",
  "background": "background details",
  "composition": "framing and layout",
  "camera": {
    "angle": "camera angle",
    "lens": "lens type",
    "depth_of_field": "focus behavior"
  }
}

在此基础上,我们将其转化为一个提示词,用于生成一张老式随身听放在地毯上的画面(只需将这段提示词传入你上面选定的 diffusers 推理示例即可):

prompt = """
{
  "scene": "Professional studio product photography setup with soft-textured carpet surface",
  "subjects": [
    {
      "description": "Old silver Walkman placed on a carpet in the middle of an empty room",
      "pose": "Stationary, lying flat",
      "position": "Center foreground on carpeted surface",
      "color_palette": ["brushed silver", "dark gray accents"]
    }
  ],
  "style": "Ultra-realistic product photography with commercial quality",
  "color_palette": ["brushed silver", "neutral beige", "soft white highlights"],
  "lighting": "Three-point softbox setup creating soft, diffused highlights with no harsh shadows",
  "mood": "Clean, professional, minimalist",
  "background": "Soft-textured carpet surface with subtle studio backdrop suggesting an empty room",
  "composition": "rule of thirds",
  "camera": {
    "angle": "high angle",
    "distance": "medium shot",
    "focus": "Sharp focus on metallic Walkman textures and physical controls",
    "lens-mm": 85,
    "f-number": "f/5.6",
    "ISO": 200
  }
}

"""

现在,将地毯颜色改为特定的蓝绿色调(#367588),并添加连接到随身听的有线耳机:

prompt = """
{
  "scene": "Professional studio product photography setup with soft-textured carpet surface",
  "subjects": [
    {
      "description": "Old silver Walkman placed on a teal-blue carpet (#367588) in the middle of an empty room, with wired headphones plugged in",
      "pose": "Stationary, lying flat",
      "position": "Center foreground on carpeted surface",
      "color_palette": ["brushed silver", "dark gray accents", "#367588"]
    },
    {
      "description": "Wired headphones connected to the Walkman, cable loosely coiled on the carpet",
      "pose": "Stationary",
      "position": "Next to and partially in front of the Walkman on the carpet",
      "color_palette": ["dark gray", "soft black", "#367588"]
    }
  ],
  "style": "Ultra-realistic product photography with commercial quality",
  "color_palette": ["brushed silver", "#367588", "neutral beige", "soft white highlights"],
  "lighting": "Three-point softbox setup creating soft, diffused highlights with no harsh shadows",
  "mood": "Clean, professional, minimalist",
  "background": "Soft-textured teal-blue carpet surface (#367588) with subtle studio backdrop suggesting an empty room",
  "composition": "rule of thirds",
  "camera": {
    "angle": "high angle",
    "distance": "medium shot",
    "focus": "Sharp focus on metallic Walkman textures, wired headphones, and carpet fibers",
    "lens-mm": 85,
    "f-number": "f/5.6",
    "ISO": 200
  }
}
"""

地毯颜色现已与提供的十六进制色码匹配,耳机也已添加,整体场景有细微调整。

更多示例和详情请查阅官方提示词指南。

LoRA 微调

作为一款同时支持文生图和图生图的模型,FLUX.2 非常适合针对多种使用场景进行微调!然而,由于仅推理就需要超过 80GB 显存,LoRA 微调在消费级 GPU 上运行更具挑战。为了尽可能节省显存,我们将上述部分推理优化技术也应用于训练,并结合共享显存节省技术,大幅降低显存消耗。要训练该模型,你可以使用下方的 diffusers 代码或 Ostris 的 AI Toolkit。

我们提供了文生图和图生图两种训练脚本,本篇博客将重点介绍文生图训练示例。

微调显存优化

其中许多技术可以相互补充,并同时使用以进一步降低显存消耗。不过,某些技术可能互斥,因此在启动训练前务必检查确认。

展开查看所用显存节省技术的详情:

  • 远程文本编码器:要利用远程文本编码进行训练,只需传入 `--remote_text_encoder` 参数。请注意,你必须已登录 Hugging Face 账户(`hf auth login`)或通过 `--hub_token` 传入一个 token。

  • CPU 卸载:通过传入 `--offload` 参数,VAE 和文本编码器将被卸载到 CPU 内存,仅在需要时移至 GPU。

  • 潜在缓存:使用 VAE 对训练图像进行预编码,然后删除 VAE 以释放部分显存。要启用潜在缓存,只需传入 `--cache_latents` 参数。

  • QLoRA:基于量化的低精度训练——使用 8 位或 4 位量化。你可以使用以下标志:

    • 基于 torchao 的 FP8 训练:通过传入 `--do_fp8_training` 启用 FP8 训练。由于我们使用的是 FP8 张量核心,因此需要计算能力至少为 8.9 或更高的 CUDA GPU。如果你希望在相对较旧的显卡上进行内存高效的训练,我们建议你查看其他训练器,例如 SimpleTuner、ai-toolkit 等。
    • 基于 bitsandbytes 的 NF4 训练:或者,你也可以通过 bitsandbytes 使用 8 位或 4 位量化:传入 `--bnb_quantization_config_path`,并附带一个指向包含你配置的 json 文件的相应路径。详情请见下文。
  • 梯度检查点与梯度累积:`--gradient_accumulation` 指的是在执行反向传播/更新步骤之前累积的更新步数。通过传入一个大于 1 的值,你可以减少反向传播/更新步骤的次数,从而也降低内存需求。* 使用 `--gradient_checkpointing`,我们可以通过不在前向传播过程中存储所有中间激活值来节省内存。相反,只存储这些激活值的一个子集(检查点),其余部分在反向传播过程中根据需要重新计算。请注意,这是以反向传播速度变慢为代价的。

  • 8 位 Adam 优化器:在使用 AdamW 进行训练时(不适用于 prodigy),你可以传入 `--use_8bit_adam` 来降低训练的内存需求。如果这样做,请确保已安装 bitsandbytes。

在开始训练之前,请务必查看 README 以了解先决条件。

对于这个示例,我们将使用 `multimodalart/1920-raider-waite-tarot-public-domain` 数据集,并采用以下配置进行 FP8 训练。欢迎尝试更多超参数并分享你的结果 🤗

accelerate launch train_dreambooth_lora_flux2.py \
  --pretrained_model_name_or_path="black-forest-labs/FLUX.2-dev"  \
  --mixed_precision="bf16" \
  --gradient_checkpointing \
  --remote_text_encoder \
  --cache_latents \
  --caption_column="caption"\
  --do_fp8_training \
  --dataset_name="multimodalart/1920-raider-waite-tarot-public-domain" \
  --output_dir="tarot_card_Flux2_LoRA" \
  --instance_prompt="trcrd tarot card" \
  --resolution=1024 \
  --train_batch_size=2 \
  --guidance_scale=1 \
  --gradient_accumulation_steps=1 \
  --optimizer="adamW" \
  --use_8bit_adam\
  --learning_rate=1e-4 \
  --report_to="wandb" \
  --lr_scheduler="constant_with_warmup" \
  --lr_warmup_steps=200 \
  --checkpointing_steps=250\
  --max_train_steps=1000 \
  --rank=8\
  --validation_prompt="a trtcrd of a person on a computer, on the computer you see a meme being made with an ancient looking trollface, 'the shitposter' arcana, in the style of TOK a trtcrd, tarot style" \
  --validation_epochs=25 \
  --seed="0"\
  --push_to_hub

LoRA 微调

预训练的 FLUX.2

LoRA 微调后的 FLUX.2

左侧图像由预训练的 FLUX.2 模型生成,右侧图像由 LoRA 生成。

如果你的硬件与 FP8 训练不兼容,你可以使用 bitsandbytes 进行 QLoRA 训练。你首先需要定义一个如下的 `config.json` 文件:

{
    "load_in_4bit": true,
    "bnb_4bit_quant_type": "nf4"
}

然后将其路径传给 `--bnb_quantization_config_path`:

accelerate launch train_dreambooth_lora_flux2.py \
  --pretrained_model_name_or_path="black-forest-labs/FLUX.2-dev"  \
  --mixed_precision="bf16" \
  --gradient_checkpointing \
  --remote_text_encoder \
  --cache_latents \
  --caption_column="caption"\
  **--bnb_quantization_config_path="config.json" \**
  --dataset_name="multimodalart/1920-raider-waite-tarot-public-domain" \
  --output_dir="tarot_card_Flux2_LoRA" \
  --instance_prompt="a tarot card" \
  --resolution=1024 \
  --train_batch_size=2 \
  --guidance_scale=1 \
  --gradient_accumulation_steps=1 \
  --optimizer="adamW" \
  --use_8bit_adam\
  --learning_rate=1e-4 \
  --report_to="wandb" \
  --lr_scheduler="constant_with_warmup" \
  --lr_warmup_steps=200 \
  --max_train_steps=1000 \
  --rank=8\
  --validation_prompt="a trtcrd of a person on a computer, on the computer you see a meme being made with an ancient looking trollface, 'the shitposter' arcana, in the style of TOK a trtcrd, tarot style" \
  --seed="0"

资源

  • FLUX.2 发布公告
  • Diffusers 文档
  • FLUX.2 官方演示
  • Hub 上的 FLUX.2
  • FLUX.2 原始代码库

来源:Hugging Face:Blog(RSS)· huggingface.co