# Bria Fibo 2.0

Fibo 2.0 是由 [Bria](https://huggingface.co/briaai) 推出的 8.1B 参数流匹配 Transformer，可根据结构化的 JSON 描述生成图像。其文本编码器为 [Qwen3-VL](https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct)：Perceiver 将 Qwen3-VL 的隐藏状态压缩为摘要 token，使其与图像 token 合并到同一流中；此外，Transformer 中的五个块还通过门控交叉注意力机制直接读取 Qwen3-VL。

有两个检查点：

- [`briaai/Fibo-2.0-dev`](https://huggingface.co/briaai/Fibo-2.0-dev)，支持文本生成图像和编辑的完整模型，并带有 classifier-free guidance。该流水线的默认设置（30 步，guidance 为 5）适用于此 checkpoint。
- [`briaai/Fibo-2.0-edit-turbo`](https://huggingface.co/briaai/Fibo-2.0-edit-turbo)，经过蒸馏，可在无引导（`guidance_scale=1.0`）的情况下以 4 步完成编辑。

在开启 guidance 的情况下，默认的 negative prompt 是模型训练时使用的空描述：即所有值均留空的结构化描述。

## 生成

Fibo 2.0 基于结构化 JSON 描述进行训练，因此无法很好地处理自由文本。请将描述作为 JSON 字符串传入：

```py
import json

import torch
from diffusers import BriaFibo2Pipeline

pipe = BriaFibo2Pipeline.from_pretrained("briaai/Fibo-2.0-dev", dtype=torch.bfloat16).to("cuda")

caption = {
    "short_description": "A red vintage bicycle leaning against a whitewashed wall on a narrow Mediterranean street.",
    "objects": [
        {
            "description": "A red vintage bicycle with a wicker basket of lemons on its handlebars.",
            "location": "center",
            "relative_size": "large within frame",
        }
    ],
    "background_setting": "A whitewashed wall with a blue wooden door and potted red geraniums.",
    "lighting": {"conditions": "bright morning sun", "direction": "from the right", "shadows": "long and crisp"},
    "aesthetics": {"composition": "centered", "color_scheme": "red, white and blue", "mood_atmosphere": "calm"},
    "photographic_characteristics": {"depth_of_field": "deep", "focus": "sharp on the bicycle", "camera_angle": "eye level"},
    "style_medium": "photograph",
    "context": "A travel photograph.",
    "artistic_style": "realistic",
}
image = pipe(json.dumps(caption)).images[0]
image.save("bicycle.png")
```

该流水线以与训练相同的方式清理字幕：它会丢弃空值以及 `aesthetic_score` 和 `preference_score` 字段（训练字幕中均不包含这些字段），并以紧凑格式序列化字幕。此外，还训练了两种简短形式，并原样保留：

```py
# The caption's short description alone, as plain text
image = pipe("A red vintage bicycle leaning against a whitewashed wall on a narrow Mediterranean street.").images[0]

# Exactly a "short_description" and a "text_render" list. The list is kept even when it's empty, to say the image
# has no text
caption = {"short_description": "A bakery storefront at dawn with a painted sign.", "text_render": [{"text": "FRESH BREAD"}]}
image = pipe(json.dumps(caption)).images[0]
```

要将自由文本转换为结构化字幕，请参阅 [Bria Fibo](https://huggingface.co/briaai/FIBO) 页面上的 prompt-to-JSON 模型。

## 编辑

相同的流水线用于编辑图像。将图像作为 `image` 传入，并将编辑指令作为提示词：

```py
import torch
from diffusers import BriaFibo2Pipeline
from diffusers.utils import load_image

pipe = BriaFibo2Pipeline.from_pretrained("briaai/Fibo-2.0-dev", dtype=torch.bfloat16).to("cuda")
image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/yarn-art-pikachu.png"
)
edited = pipe("Make the background a snowy forest", image=image).images[0]
edited.save("pikachu_snow.png")
```

为了更快地进行编辑，请加载 turbo 检查点并关闭 guidance：

```py
import torch
from diffusers import BriaFibo2Pipeline
from diffusers.utils import load_image

pipe = BriaFibo2Pipeline.from_pretrained("briaai/Fibo-2.0-edit-turbo", dtype=torch.bfloat16).to("cuda")
image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/yarn-art-pikachu.png"
)
edited = pipe("Make the background a snowy forest", image=image, num_inference_steps=4, guidance_scale=1.0).images[0]
edited.save("pikachu_snow.png")
```

以下示例基于其中任意一个继续，使用其 `pipe` 和 `image`。对于 turbo 检查点，请在每次调用时传入 `num_inference_steps=4` 和 `guidance_scale=1.0`。

### 编辑提示

提示词也可以是一个 JSON 对象，其中包含 `"edit_instruction"` 键以及结果的描述，其形式可以是 Fibo 2.0 训练时所采用的任意一种编辑形式。该流水线会将其转换为 Fibo 2.0 训练时所采用的编辑提示词。

完整说明：除 `"edit_instruction"` 之外的说明键，格式与 Bria 的 prompt-to-JSON 模型在编辑时生成的格式一致。该流水线会丢弃空值以及 `aesthetic_score` 和 `preference_score` 字段，因为训练已从所有说明中移除了这些字段。

```py
import json

prompt = {
    "short_description": "A crocheted yellow Pikachu doll sitting in a snowy pine forest.",
    "objects": [{"description": "A crocheted yellow Pikachu doll with red cheeks.", "location": "center"}],
    "background_setting": "A snowy pine forest with falling snow.",
    "edit_instruction": "Make the background a snowy forest",
}
edited = pipe(json.dumps(prompt), image=image).images[0]
```

简短描述：`"structured_caption"` 键中的一个字符串。

```py
prompt = {
    "structured_caption": "A crocheted yellow Pikachu doll sitting in a snowy pine forest.",
    "edit_instruction": "Make the background a snowy forest",
}
edited = pipe(json.dumps(prompt), image=image).images[0]
```

简短描述及其文本：恰好是一个 `"short_description"` 和一个 `"text_render"` 列表。即使列表为空也会保留，这表示 Fibo 2.0 的结果没有文本。`"structured_caption"` 键可以包含此格式，也可以包含完整的说明。

```py
prompt = {
    "short_description": "A crocheted yellow Pikachu doll holding a small wooden sign.",
    "text_render": [{"text": "HELLO"}],
    "edit_instruction": "Give the doll a small wooden sign that reads HELLO",
}
edited = pipe(json.dumps(prompt), image=image).images[0]
```

### 多张图片

最多可以同时编辑 5 张图片，例如将一张图片中的对象放入另一张图片中。指令会按顺序将它们称为 `<image_1>`、`<image_2>`，依此类推。

```py
cat = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/cat.png")
edited = pipe("Put the cat from <image_2> next to the doll in <image_1>", image=[image, cat]).images[0]
```

### 输出大小

除非指定了 `height` 和 `width`，否则结果将采用 Fibo 2.0 针对第一张图像的宽高比进行训练时的尺寸，大约为一百万像素。单张图像会被裁剪至结果尺寸。多张图像则各自根据其自身的宽高比裁剪至训练尺寸。

```py
edited = pipe("Make the background a snowy forest", image=image, width=1424, height=800).images[0]
```

### 掩码编辑

`mask` 标记了单张图像中需要重新生成的区域，以白底黑图的形式呈现，尺寸与图像一致。Fibo 2.0 是在图像中该区域被灰化的编辑数据上训练的，管道在编码图像前会以相同方式将其灰化：通过阈值 128 将掩码二值化，然后填充为纯 (128, 128, 128) 灰色。

```py
from PIL import Image, ImageDraw

mask = Image.new("L", image.size, 0)
ImageDraw.Draw(mask).rectangle((image.width // 2, 0, image.width, image.height // 2), fill=255)
edited = pipe("Add a red balloon floating in the sky", image=image, mask=mask).images[0]
```

## 图像中的文本

当字幕中的 `text_render` 条目要求渲染文本时，如果 Qwen3-VL 也能看到每个单独绘制的文本，Fibo 2.0 往往能更好地渲染这些文本。该流水线默认会绘制这些图像，与训练时的做法一致，并且可以将其关闭。对于包含文本的字幕，例如上面面包店的例子：

```py
prompt = json.dumps(caption)
image = pipe(prompt, render_text_images=False).images[0]
```

训练过程中，Fibo 2.0 针对部分包含文本的说明展示了这些图像，而针对其他说明则没有展示，因此两种方式均可行。

- 每个包含 `text` 的 `text_render` 条目都会生成一张图像：文本以单行形式呈现，白底黑字，使用 Pillow 内置字体，字号为 20。长度超过 256 个字符的文本会被拆分为每行 256 个字符的多行。
- 字体中缺失的字符会使用 `fonts` 中第一个包含该字符的字体来绘制。训练时使用了 Aileron，然后是 DejaVu Sans，它们位于 [`briaai/Fibo-2.0-dev`](https://huggingface.co/briaai/Fibo-2.0-dev) 的 `fonts` 文件夹中。如果没有 `fonts`，此类字符将按照 Pillow 内置字体的方式绘制，并且流水线会发出警告。
- Pipeline 会为每个条目标记一个 `image_tokens` 字段以对应其图像，而 Qwen3-VL 会在任何待编辑图像之后看到这些图像。
- 在生成过程中，当噪声水平高于 `pipe.text_images_max_noise_level`（0.9）时，前几步仅基于不含图像的文本描述进行；而在编辑过程中，每一步都会使用这些图像。
- 没有文本的标题不会生成图像，简短的描述也不会，这与训练阶段的情况相同。

要使用训练所用的字体绘制它们：

```py
from huggingface_hub import hf_hub_download

fonts = [
    hf_hub_download("briaai/Fibo-2.0-dev", name, subfolder="fonts")
    for name in ("Aileron-Regular.otf", "DejaVuSans.ttf")
]
image = pipe(prompt, fonts=fonts).images[0]
```

若要自行绘制图像，请按顺序将图像作为 `text_images` 传入，每个包含 `text` 的 `text_render` 条目对应一张图像，且针对单个提示词。这些图像会优先于流水线自身生成的图像。与训练时绘制方式不同的图像属于分布外数据。

## 注意力后端

transformer 可运行于 diffusers 的任意[注意力后端](../../optimization/attention_backends)，例如在 H100 等 Hopper GPU 上使用 FlashAttention-3：

```py
pipe.transformer.set_attention_backend("_flash_3_varlen_hub")
```

`_flash_3_hub` 同样适用于单个提示，但它不支持掩码，因此无法处理长度不同的提示批次（详见下文）。

## 批处理

可以在一次调用中生成多个提示。不同长度的提示会被填充（padding），并且填充部分会在每个注意力层中被掩码（mask）掉，因此这样的批次需要一个支持掩码的注意力后端：默认后端，或 `flash_varlen` 等变长（varlen）后端。在 float32 下，批次生成的图像与单独调用生成的图像一致；而在 bfloat16 下，填充输入与未填充输入的注意力内核存在差异，因此批次生成的图像在细节上可能与单独调用生成的图像有所不同。

## BriaFibo2Pipeline[[diffusers.BriaFibo2Pipeline]]

#### diffusers.BriaFibo2Pipeline[[diffusers.BriaFibo2Pipeline]]

```python
diffusers.BriaFibo2Pipeline(transformer: BriaFibo2Transformer2DModel, scheduler: FlowMatchEulerDiscreteScheduler, vae: AutoencoderKLFlux2, text_encoder: Qwen3VLForConditionalGeneration, processor: Qwen3VLProcessor)
```

[源代码](https://github.com/huggingface/diffusers/blob/v0.43.0/src/diffusers/pipelines/bria_fibo2/pipeline_bria_fibo2.py#L171)

**参数：**

transformer ([BriaFibo2Transformer2DModel](/docs/diffusers/v0.43.0/zh/api/models/transformer_bria_fibo2#diffusers.BriaFibo2Transformer2DModel))：用于对图像潜在表示进行去噪的 Transformer。

scheduler ([FlowMatchEulerDiscreteScheduler](/docs/diffusers/v0.43.0/zh/api/schedulers/flow_match_euler_discrete#diffusers.FlowMatchEulerDiscreteScheduler))：与 `transformer` 配合使用，用于对潜变量进行去噪的调度器。

vae (`AutoencoderKLFlux2`)：变分自编码器，可将图像映射到潜在空间并还原。

text_encoder (`Qwen3VLForConditionalGeneration`)：Qwen3-VL。其隐藏状态作为 transformer 的条件输入。

processor (`Qwen3VLProcessor`)：将提示词和待编辑的图像转换为 Qwen3-VL 的输入。

用于使用 Fibo 2.0 进行文本生成图像和图像编辑的 Pipeline。

#### __调用__[[diffusers.BriaFibo2Pipeline.__call__]]

```python
__call__(prompt: str | list[str] | None = None, image: PIL.Image.Image | list[PIL.Image.Image] | None = None, mask: PIL.Image.Image | None = None, text_images: list[PIL.Image.Image] | None = None, render_text_images: bool = True, fonts: list[str] | None = None, height: int | None = None, width: int | None = None, num_inference_steps: int = 30, guidance_scale: float = 5.0, negative_prompt: str | list[str] | None = None, num_images_per_prompt: int = 1, generator: typing.Union[torch.Generator, list[torch.Generator], NoneType] = None, latents: typing.Optional[torch.Tensor] = None, prompt_embeds: typing.Optional[torch.Tensor] = None, prompt_embeds_mask: typing.Optional[torch.Tensor] = None, negative_prompt_embeds: typing.Optional[torch.Tensor] = None, negative_prompt_embeds_mask: typing.Optional[torch.Tensor] = None, output_type: str = 'pil', return_dict: bool = True, callback_on_step_end: typing.Optional[typing.Callable[[int, int, dict], NoneType]] = None, callback_on_step_end_tensor_inputs: list[str] = ['latents'])
```

[源代码](https://github.com/huggingface/diffusers/blob/v0.43.0/src/diffusers/pipelines/bria_fibo2/pipeline_bria_fibo2.py#L571)

**参数：**

prompt (`str` 或 `list[str]`，*可选*)：用于引导图像生成的提示词，通常为结构化的 JSON 提示词，并按 Fibo 2.0 训练时清洗字幕的方式进行处理：移除空值以及 `aesthetic_score` 和 `preference_score` 字段，并以紧凑格式序列化。若与 `image` 一起使用，则为编辑指令，或一个包含 `"edit_instruction"` 键及结果字幕的 JSON 对象：其其他键，或一个包含字幕或简短描述的 `"structured_caption"` 键。

image (`PIL.Image.Image` 或 `list[PIL.Image.Image]`，*可选*)：要编辑的图像，或最多 5 张要一起编辑的图像，指令中可将其分别引用为 `<image_1>`、`<image_2>` 等。如果不提供 `image`，流水线将根据提示词生成图像。

mask (`PIL.Image.Image`, *可选*) : 在编辑单张图像时，`image` 中需要重新生成的区域，以黑底白图表示。与训练过程相同，在图像编码之前，该区域会被置灰，掩码通过 128 阈值二值化。

text_images (`list[PIL.Image.Image]`, *可选*) : 字幕中要求渲染的文本对应的图像，按顺序对应每个包含 `text` 的 `text_render` 条目：每个条目的文本单独绘制，绘制方式与 `render_text_images` 相同。Qwen3-VL 会结合提示词查看这些图像，每个图像在其对应的字幕条目中标记，这有助于 Fibo 2.0 渲染文本。需要 `prompt` 为单个 JSON 字幕，并且优先级高于 `render_text_images`。在生成过程中，当噪声水平高于 `text_images_max_noise_level`（0.9）时，前几步不使用这些图像；而在编辑过程中，每一步都会使用它们。

render_text_images (`bool`，*可选*，默认为 `True`)：是否按照 Fibo 2.0 训练时的方式绘制每个 caption 的 `text_images`：每行一个文本，白底黑字，使用 Pillow 内置字体，字号为 20；对于该字体缺失的字符，则使用 `fonts` 中第一个包含这些字符的字体。与训练时一样，没有文本的 caption，以及没有 JSON caption 的 prompt（例如简短描述），不会生成图像。

fonts (`list[str]`, *可选*) : 按顺序指定用于绘制 `text_images` 中 Pillow 内置字体所缺失字符的字体路径。训练时依次使用了 Aileron 和 DejaVu Sans，它们位于 `briaai/Fibo-2.0-dev` 的 `fonts` 文件夹中。若未提供这些字体，此类字符将按 Pillow 内置字体的方式绘制。

height (`int`, *可选*) : 生成图像的高度（以像素为单位）。必须能被 16 整除。默认值为 1024；在进行编辑时，则默认为 Fibo 2.0 针对第一张图像的宽高比所训练的尺寸，约为 100 万像素。

width (`int`，*可选*)：生成图像的宽度（以像素为单位）。必须能被 16 整除。默认值与 `height` 相同。

num_inference_steps (`int`，*可选*，默认值为 30)：去噪步数。

guidance_scale (`float`，*可选*，默认值为 5.0)：无分类器引导（Classifier-free guidance）的缩放系数。大于 1 的值会在每一步中额外运行一次负向提示词，而 1.0 则会关闭引导。

negative_prompt (`str` 或 `list[str]`，*可选*)：在启用 guidance 时，用于引导偏离的提示词。默认值为 Fibo 2.0 训练时使用的空 caption：即所有值均为空的结构化 caption。

num_images_per_prompt (`int`，*可选*，默认为 1)：每个提示词生成的图像数量。

generator (`torch.Generator` 或 `list[torch.Generator]`，*可选*)：用于生成初始噪声的生成器，以实现确定性生成。

latents (`torch.Tensor`, *可选*) : 形状为 `(batch_size, 32, height // 8, width // 8)` 的预生成起始噪声。

prompt_embeds (`torch.Tensor`，*可选*)：由 `encode_prompt` 预计算得到的文本嵌入，用于替代 `prompt`。

prompt_embeds_mask (`torch.Tensor`, *可选*) : `prompt_embeds` 随 `encode_prompt` 返回的掩码。当它们经过填充时需要使用。

negative_prompt_embeds (`torch.Tensor`, *可选*) : 负提示的预计算文本嵌入，用于替代 `negative_prompt`。

negative_prompt_embeds_mask (`torch.Tensor`, *可选*) : `negative_prompt_embeds` 随 `encode_prompt` 返回的掩码。当存在填充时需要使用。

output_type (`str`，*可选*，默认为 `"pil"`)：输出格式：`"pil"`、`"np"`、`"pt"` 或 `"latent"`。

return_dict (`bool`，*可选*，默认为 `True`)：是否返回 `BriaFibo2PipelineOutput` 而不是普通元组。

callback_on_step_end (`Callable`，*可选*)：在每个去噪步骤结束时调用的函数，形式为 `callback_on_step_end(self, step, timestep, callback_kwargs)`。

callback_on_step_end_tensor_inputs (`list[str]`，*可选*，默认为 `["latents"]`)：传递给 `callback_kwargs` 中 `callback_on_step_end` 的张量。

**返回：** `BriaFibo2PipelineOutput` 或 `tuple`

生成的图像。

调用生成 pipeline 时调用的函数。

示例：
```py
>>> import json

>>> import torch
>>> from diffusers import BriaFibo2Pipeline
>>> from diffusers.utils import load_image

>>> # Fibo 2.0 reads structured JSON captions, serialized compactly the way it was trained
>>> caption = {
...     "short_description": "A red bicycle leaning against a white brick wall on a sunny morning.",
...     "objects": [{"description": "a red city bicycle with a wicker basket", "location": "center"}],
...     "background_setting": "a white brick wall with a green door",
...     "lighting": {"conditions": "bright morning sun", "direction": "from the right"},
...     "style_medium": "photograph",
... }
>>> prompt = json.dumps(caption, separators=(",", ":"), ensure_ascii=False)

>>> # 30 steps with guidance 5, the defaults
>>> pipe = BriaFibo2Pipeline.from_pretrained("briaai/Fibo-2.0-dev", dtype=torch.bfloat16).to("cuda")
>>> image = pipe(prompt).images[0]
>>> image.save("fibo2.png")

>>> # editing: pass the image, and the instruction as the prompt
>>> image = load_image(
...     "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/yarn-art-pikachu.png"
... )
>>> edited = pipe("Make the background a snowy forest", image=image).images[0]
>>> edited.save("fibo2_edit.png")
```

#### encode_prompt[[diffusers.BriaFibo2Pipeline.encode_prompt]]

```python
encode_prompt(prompt: str | list[str], image: list[PIL.Image.Image] | None = None, device: typing.Optional[torch.device] = None, num_images_per_prompt: int = 1, prompt_embeds: typing.Optional[torch.Tensor] = None, prompt_embeds_mask: typing.Optional[torch.Tensor] = None, text_images: list[PIL.Image.Image] | list[list[PIL.Image.Image]] | None = None)
```

[源代码](https://github.com/huggingface/diffusers/blob/v0.43.0/src/diffusers/pipelines/bria_fibo2/pipeline_bria_fibo2.py#L351)

**参数：**

prompt (`str` 或 `list[str]`) : 要编码的提示词或提示词列表。当使用 `image` 时，每个提示词都是一条编辑指令，或者是一个包含 `"edit_instruction"` 键和结果说明的 JSON 对象：其其他键，或一个包含说明或简短描述的 `"structured_caption"` 键。生成提示词将按原样进行编码：`__call__` 首先会将其转换为 Fibo 2.0 训练时所使用的 JSON 说明格式。

image (`list[PIL.Image.Image]`, *可选*) : 要编辑的图像，即 Qwen3-VL 所看到的图像。每个提示词都会编辑所有这些图像。

device (`torch.device`，*可选*)：用于放置嵌入的设备。

num_images_per_prompt (`int`，默认为 1)：每个提示词生成的图像数量。

prompt_embeds (`torch.Tensor`, *可选*) : 形状为 `(batch_size, 6, text_len, 7680)` 的预计算文本嵌入，用于替代 `prompt`。

prompt_embeds_mask (`torch.Tensor`, *可选*) : `prompt_embeds` 中真实 token 的布尔掩码，形状为 `(batch_size, text_len)`。

text_images (`list[PIL.Image.Image]` 或 `list[list[PIL.Image.Image]]`，*可选*)：对应说明文本的图像，按顺序为每个包含 `text` 的 `text_render` 条目各提供一张图像，或者为每个提示词提供一组图像列表。每个条目都会获得其对应图像的视觉标记，Qwen3-VL 会在任何待编辑图像之后查看这些图像。

**返回值：**

文本嵌入及其掩码，或者在未填充提示时为 `None`。

