# JoyAI-Image-Edit-Plus

[JoyAI-Image](https://github.com/jd-opensource/JoyAI-Image) — это единая мультимодальная базовая модель для понимания изображений, генерации изображений по тексту и редактирования изображений по инструкциям. Она объединяет мультимодальную большую языковую модель (MLLM) на 8 млрд параметров и мультимодальный диффузионный трансформер (MMDiT) на 16 млрд параметров.

JoyAI-Image-Edit-Plus — это модель редактирования по текстовым инструкциям, работающая с несколькими изображениями. Она принимает **несколько референсных изображений** и текстовую инструкцию, чтобы сгенерировать новое изображение, сочетающее элементы из референсов в соответствии с инструкцией. Поддерживается от 1 до 5 референсных изображений на один пример.

| Модель | Описание | Загрузить |
|:-----:|:-----------:|:--------:|
| JoyAI-Image-Edit-Plus | Редактирование по инструкции с несколькими изображениями с композицией элементов из нескольких источников | [Hugging Face](https://huggingface.co/jdopensource/JoyAI-Image-Edit-Plus-Diffusers) |

```python
import torch
from PIL import Image
from diffusers import JoyImageEditPlusPipeline

pipeline = JoyImageEditPlusPipeline.from_pretrained(
    "jdopensource/JoyAI-Image-Edit-Plus-Diffusers", dtype=torch.bfloat16
)
pipeline.to("cuda")  # or "mps", "xpu", "cpu"

images = [
    Image.open("reference_0.png").convert("RGB"),
    Image.open("reference_1.png").convert("RGB"),
]

target_h, target_w = pipeline.image_processor.get_default_height_width(images[-1])

output = pipeline(
    images=images,
    prompt="Combine the person from the second image with the scene from the first image.",
    negative_prompt="low quality, blurry, deformed",
    height=target_h,
    width=target_w,
    num_inference_steps=30,
    guidance_scale=4.0,
    generator=torch.Generator("cuda").manual_seed(42),
).images[0]
output.save("joyimage_edit_plus_output.png")
```

## JoyImageEditPlusPipeline[[diffusers.JoyImageEditPlusPipeline]]

#### diffusers.JoyImageEditPlusPipeline[[diffusers.JoyImageEditPlusPipeline]]

```python
diffusers.JoyImageEditPlusPipeline(scheduler: FlowMatchEulerDiscreteScheduler, vae: AutoencoderKLWan, text_encoder: Qwen3VLForConditionalGeneration, tokenizer: Qwen2Tokenizer, transformer: JoyImageEditPlusTransformer3DModel, processor: Qwen3VLProcessor, text_token_max_length: int = 2048)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit_plus.py#L129)

**Параметры:**

scheduler ([FlowMatchEulerDiscreteScheduler](/docs/diffusers/main/ru/api/schedulers/flow_match_euler_discrete#diffusers.FlowMatchEulerDiscreteScheduler)) : планировщик, используемый в связке с `transformer` для удаления шума из закодированных латентов изображения.

vae ([AutoencoderKLWan](/docs/diffusers/main/ru/api/models/autoencoder_kl_wan#diffusers.AutoencoderKLWan)) : вариационная автокодирующая модель (VAE) для кодирования изображений в латентные представления и декодирования из них.

text_encoder (`Qwen3VLForConditionalGeneration`) : мультимодальный текстовый энкодер для кодирования промптов с пониманием встроенных изображений.

tokenizer (`Qwen2Tokenizer`) : Токенизатор для обработки текста.

transformer ([JoyImageEditPlusTransformer3DModel](/docs/diffusers/main/ru/api/models/transformer_joyimage_edit_plus#diffusers.JoyImageEditPlusTransformer3DModel)) : архитектура условного трансформера (MMDiT) для удаления шума из закодированных латентов изображения.

processor (`Qwen3VLProcessor`) : процессор для мультимодальных входных данных (текст + изображения).

text_token_max_length (`int`, по умолчанию `2048`) : Максимальная длина токенов для кодирования текста.

Diffusion pipeline для редактирования нескольких изображений по инструкциям с использованием JoyImage Edit Plus.

Поддерживает несколько эталонных изображений с различными разрешениями. Каждое эталонное изображение независимо кодируется VAE и преобразуется в патчи, после чего конкатенируется с целевыми шумовыми патчами для совместного шумоподавления.

#### __call__[[diffusers.JoyImageEditPlusPipeline.__call__]]

```python
__call__(images: list[PIL.Image.Image] | list[list[PIL.Image.Image]] | None = None, prompt: str | list[str] = None, height: int | None = None, width: int | None = None, num_inference_steps: int = 30, timesteps: list[int] = None, sigmas: list[float] = None, guidance_scale: float = 4.0, negative_prompt: str | list[str] | None = None, 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 | None = 'pil', return_dict: bool = True, callback_on_step_end: typing.Union[typing.Callable[[int, int, dict], NoneType], diffusers.callbacks.PipelineCallback, diffusers.callbacks.MultiPipelineCallbacks, NoneType] = None, callback_on_step_end_tensor_inputs: list[str] = ['latents'], max_sequence_length: int = 4096)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit_plus.py#L441)

**Параметры:**

images (`list[Image.Image]` или `list[list[Image.Image]]`, *необязательный*) : Ссылочные изображения для редактирования. Каждое изображение может иметь различное разрешение. Если предоставлен плоский список, он рассматривается как один образец с несколькими ссылочными изображениями.

prompt (`str` или `list[str]`, *необязательный*) : Промпт или промпты для управления генерацией изображения. Если не задан, необходимо передать `prompt_embeds`.

height (`int`, *optional*) : Высота генерируемого изображения в пикселях. Если `None`, определяется по последнему опорному изображению.

width (`int`, *optional*) : Ширина сгенерированного изображения в пикселях. Если `None`, определяется по последнему референсному изображению.

num_inference_steps (`int`, *optional*, по умолчанию `30`) : Количество шагов денойзинга. Как правило, большее число шагов денойзинга приводит к изображению более высокого качества, но за счёт более медленного вывода.

timesteps (`list[int]`, *optional*) : Пользовательские шаги для процесса денойзинга. Если не заданы, используется равномерное распределение.

sigmas (`list[float]`, *необязательный*) : Пользовательские сигмы для использования в процессе денойзинга.

guidance_scale (`float`, *необязательный*, по умолчанию `4.0`) : Масштаб classifier-free guidance. Более высокие значения побуждают модель генерировать изображения, более точно соответствующие `prompt`, за счёт снижения качества изображения.

negative_prompt (`str` или `list[str]`, *необязательный*) : Промпт или промпты, которые не следует использовать для управления генерацией изображения. Если не задано, для classifier-free guidance используется пустой промпт.

generator (`torch.Generator` или `list[torch.Generator]`, *необязательный*) : Один или список [генераторов torch](https://pytorch.org/docs/stable/generated/torch.Generator.html) для обеспечения детерминированности генерации.

latents (`torch.Tensor`, *необязательный*) : Предварительно сгенерированные зашумленные латенты, используемые в качестве входных данных для генерации изображений.

prompt_embeds (`torch.Tensor`, *необязательный*) : Предварительно сгенерированные текстовые эмбеддинги. Можно использовать для простой настройки текстовых входных данных.

prompt_embeds_mask (`torch.Tensor`, *необязательный*) : Маска внимания для предсгенерированных текстовых эмбеддингов.

negative_prompt_embeds (`torch.Tensor`, *необязательный*) : Предварительно сгенерированные отрицательные текстовые эмбеддинги.

negative_prompt_embeds_mask (`torch.Tensor`, *необязательный*) : Маска внимания для предсгенерированных эмбеддингов отрицательного текста.

output_type (`str`, *необязательный*, по умолчанию `"pil"`) : Формат вывода сгенерированного изображения. Выберите один из вариантов: `"pil"` (`PIL.Image.Image`), `"np"` (`np.ndarray`), `"pt"` (`torch.Tensor`) или `"latent"` для вывода в сыром латентном пространстве.

return_dict (`bool`, *необязательный*, по умолчанию `True`) : Возвращать ли [JoyImageEditPlusPipelineOutput](/docs/diffusers/main/ru/api/pipelines/joyimage_edit_plus#diffusers.JoyImageEditPlusPipelineOutput) вместо обычного кортежа.

callback_on_step_end (`Callable`, *необязательный*) : функция, вызываемая в конце каждого шага денойзинга с аргументами: конвейер, индекс шага, временной шаг и словарь тензорных входных данных для обратного вызова.

callback_on_step_end_tensor_inputs (`list[str]`, *необязательный*, по умолчанию `["latents"]`) : Список тензорных входных данных для функции `callback_on_step_end`.

max_sequence_length (`int`, *необязательный*, по умолчанию `4096`) : Максимальная длина последовательности для текстового энкодера.

**Возвращает:** [JoyImageEditPlusPipelineOutput](/docs/diffusers/main/ru/api/pipelines/joyimage_edit_plus#diffusers.JoyImageEditPlusPipelineOutput) или `tuple`

Если `return_dict` равно `True`, возвращается [JoyImageEditPlusPipelineOutput](/docs/diffusers/main/ru/api/pipelines/joyimage_edit_plus#diffusers.JoyImageEditPlusPipelineOutput), иначе возвращается `tuple`, первым элементом которого является список сгенерированных изображений.

Функция, вызываемая при обращении к конвейеру для генерации.

Примеры:
```python
>>> import torch
>>> from diffusers import JoyImageEditPlusPipeline
>>> from diffusers.utils import load_image

>>> model_id = "jdopensource/JoyAI-Image-Edit-Plus-Diffusers"
>>> pipe = JoyImageEditPlusPipeline.from_pretrained(model_id, torch_dtype=torch.bfloat16)
>>> pipe.to("cuda")

>>> images = [
...     load_image("dog.png"),
...     load_image("person.png"),
... ]
>>> output = pipe(
...     images=images,
...     prompt="Let the person lovingly play with the dog.",
...     height=1024,
...     width=1024,
...     num_inference_steps=30,
...     guidance_scale=4.0,
...     generator=torch.manual_seed(42),
... )
>>> output.images[0].save("output.png")
```

#### encode_prompt_multiple_images[[diffusers.JoyImageEditPlusPipeline.encode_prompt_multiple_images]]

```python
encode_prompt_multiple_images(prompt: str | list[str], device: typing.Optional[torch.device] = None, images: list[PIL.Image.Image] | None = None, max_sequence_length: int | None = None)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit_plus.py#L229)

Кодируйте промпты с встроенными токенами с помощью процессора Qwen3-VL.

#### prepare_latents[[diffusers.JoyImageEditPlusPipeline.prepare_latents]]

```python
prepare_latents(batch_size: int, num_channels_latents: int, height: int, width: int, dtype: dtype, device: device, generator: typing.Union[torch.Generator, list[torch.Generator], NoneType], reference_images: list[list[PIL.Image.Image]] | None = None, latents: typing.Optional[torch.Tensor] = None)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit_plus.py#L274)

**Параметры:**

latents : Необязательный заранее вычисленный шум для целевого слота. Форма `(B, C, 1, H', W')`, где `H'` и `W'` — размеры в латентном пространстве. Если `None`, шум генерируется случайно.

**Возвращает:** `padded_latents`

[B, max_patches, C, pt, ph, pw] target_mask: [B, max_patches] (True для целевых патчей) shape_list: список кортежей (t, h, w) для каждого компонента в каждом образце

Подготовьте 6D тензор латентов с заполнением, содержащий целевой шум и латенты референсного изображения.

## JoyImageEditPlusPipelineOutput[[diffusers.JoyImageEditPlusPipelineOutput]]

#### diffusers.JoyImageEditPlusPipelineOutput[[diffusers.JoyImageEditPlusPipelineOutput]]

```python
diffusers.JoyImageEditPlusPipelineOutput(images: typing.Union[typing.List[PIL.Image.Image], numpy.ndarray])
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_output.py#L20)

Класс вывода для пайплайнов многоизображенияльного редактирования JoyImage Edit Plus.

