# Воспроизводимость

Diffusion — это случайный процесс, который каждый раз генерирует разный результат. Для таких сценариев использования, как тестирование и воспроизведение результатов, вам нужно получать одинаковый результат при каждом запуске, в пределах допустимого диапазона отклонений, независимо от версии и платформы.

В этом руководстве показано, как управлять источниками случайности и включать детерминированные алгоритмы.

## Генератор

Pipelines используют [torch.randn](https://pytorch.org/docs/stable/generated/torch.randn.html), который каждый раз применяет другое случайное зерно, для создания начальных шумовых тензоров. Чтобы получить одинаковый вывод на CPU или GPU, используйте [Generator](https://docs.pytorch.org/docs/stable/generated/torch.Generator.html) для управления генерацией случайных значений.

> [!TIP]
> Если важна воспроизводимость, следует использовать генератор `Generator` на CPU. Потеря производительности часто незначительна, а генерируемые значения будут более похожи.

Используйте `Generator` на CPU, если важна воспроизводимость. Генератор случайных чисел на CPU более стабилен на разных машинах.

Если вы передаёте CPU `Generator`, функция [randn_tensor()](/docs/diffusers/v0.43.0/ru/api/utilities#diffusers.utils.torch_utils.randn_tensor) в Diffusers выполняет выборку на CPU и перемещает тензор на GPU внутри пайплайна. Вам не нужно самостоятельно вызывать `randn_tensor` или `.to("cuda")`. GPU `Generator` выполняет выборку непосредственно на устройстве, поэтому результаты могут отличаться от CPU.

Используйте [manual_seed](https://docs.pytorch.org/docs/stable/generated/torch.manual_seed.html), чтобы задать сид.

```py
import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
    "Qwen/Qwen-Image", dtype=torch.bfloat16, device_map="cuda"  # or "mps", "xpu", "cpu"
)
generator = torch.manual_seed(0)
image = pipeline(
    prompt="a red apple on a wooden table",
    generator=generator,
    num_inference_steps=4,
).images[0]
```

Создайте CPU-генератор `Generator` и задайте сид с помощью [Generator.manual_seed](https://docs.pytorch.org/docs/stable/generated/torch.Generator.html#torch.Generator.manual_seed).

```py
import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
    "Qwen/Qwen-Image", dtype=torch.bfloat16, device_map="cpu"
)
generator = torch.Generator(device="cpu").manual_seed(0)
image = pipeline(
    prompt="a red apple on a wooden table",
    generator=generator,
    num_inference_steps=4,
).images[0]
```

Передавайте в пайплайн объект `Generator` вместо целочисленного seed. Объект `Generator` хранит случайное состояние, которое потребляется и обновляется при каждом использовании. После этого тот же объект будет выдавать разные результаты при последующих вызовах, даже в разных пайплайнах, поскольку его состояние изменилось. Если вам снова нужен тот же seed, сбрасывайте состояние или создавайте новый `Generator` перед каждым вызовом.

```py
import torch

prompt = "a red apple on a wooden table"

for _ in range(5):
    generator = torch.manual_seed(0)
    image = pipeline(prompt, generator=generator, num_inference_steps=4).images[0]
```

## Детерминированные алгоритмы

PyTorch поддерживает [детерминированные алгоритмы](https://docs.pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms) (если они доступны) для определённых операций, чтобы они давали одинаковые результаты. Детерминированные алгоритмы могут работать медленнее и снижать производительность.

Используйте `enable_full_determinism()` в Diffusers, чтобы включить детерминированные алгоритмы.

```py
from diffusers.utils.torch_utils import enable_full_determinism

enable_full_determinism()
```

`enable_full_determinism` работает следующим образом:

- Установка переменной окружения `CUDA_LAUNCH_BLOCKING` в значение `1`
- Установка переменной окружения [CUBLAS_WORKSPACE_CONFIG](https://docs.nvidia.com/cuda/cublas/index.html#results-reproducibility) в значение `:16:8`, чтобы cuBLAS использовал фиксированную структуру рабочего пространства во время выполнения
- Вызов `torch.use_deterministic_algorithms(True)`
- Установка `torch.backends.cudnn.deterministic = True`
- Установка `torch.backends.cudnn.benchmark = False`, чтобы cuDNN не выбирал другой алгоритм свёртки при каждом запуске
- Отключение TensorFloat32 (TF32) с помощью `torch.backends.cuda.matmul.allow_tf32 = False` в пользу более точного матричного умножения с полной точностью

## Дальнейшие шаги

Вам следует ознакомиться с заметками разработчиков PyTorch о [воспроизводимости](https://docs.pytorch.org/docs/stable/notes/randomness.html). Вы можете попытаться ограничить случайность, но она не *гарантирована* даже при использовании одинакового семени.

