# Tính khả tái lập

Diffusion là một quá trình ngẫu nhiên, tạo ra kết quả khác nhau mỗi lần chạy. Đối với các trường hợp sử dụng như kiểm thử và tái tạo kết quả, bạn muốn tạo ra cùng một kết quả mỗi lần, xuyên suốt các phiên bản và nền tảng khác nhau trong một khoảng dung sai nhất định.

Hướng dẫn này sẽ cho bạn thấy cách kiểm soát các nguồn ngẫu nhiên và bật các thuật toán tất định.

## Generator

Pipelines dựa vào [torch.randn](https://pytorch.org/docs/stable/generated/torch.randn.html), vốn sử dụng một hạt ngẫu nhiên khác nhau mỗi lần, để tạo ra các tensor nhiễu ban đầu. Để tạo ra cùng một kết quả trên CPU hoặc GPU, hãy sử dụng [Generator](https://docs.pytorch.org/docs/stable/generated/torch.Generator.html) để quản lý cách các giá trị ngẫu nhiên được tạo ra.

> [!TIP]
> Nếu tính tái lập quan trọng, bạn nên sử dụng `Generator` trên CPU. Sự suy giảm hiệu năng thường không đáng kể và bạn sẽ tạo ra các giá trị tương tự hơn.

Sử dụng `Generator` trên CPU khi bạn quan tâm đến khả năng tái lập. RNG trên CPU ổn định hơn giữa các máy khác nhau.

Khi bạn truyền một `Generator` CPU, [randn_tensor()](/docs/diffusers/v0.43.0/vi/api/utilities#diffusers.utils.torch_utils.randn_tensor) của Diffusers sẽ lấy mẫu trên CPU và di chuyển tensor sang GPU bên trong pipeline. Bạn không tự gọi `randn_tensor` hoặc `.to("cuda")`. Một `Generator` GPU sẽ lấy mẫu trực tiếp trên thiết bị và có thể cho kết quả khác so với CPU.

Sử dụng [manual_seed](https://docs.pytorch.org/docs/stable/generated/torch.manual_seed.html) để đặt hạt giống.

```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]
```

Tạo một `Generator` CPU và đặt seed bằng [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]
```

Truyền một đối tượng `Generator` vào pipeline thay vì một hạt giống (seed) dạng số nguyên. Một `Generator` giữ một trạng thái ngẫu nhiên, được tiêu thụ và cập nhật khi bạn sử dụng nó. Sau đó, cùng một đối tượng sẽ tạo ra các kết quả khác nhau ở các lần gọi tiếp theo, kể cả giữa các pipeline, vì trạng thái của nó đã thay đổi. Hãy đặt lại hạt giống hoặc tạo một `Generator` mới trước mỗi lần gọi khi bạn cần sử dụng lại cùng một hạt giống.

```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]
```

## Thuật toán tất định

PyTorch hỗ trợ [các thuật toán tất định](https://docs.pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms) (khi có sẵn) cho một số thao tác để chúng tạo ra cùng kết quả. Các thuật toán tất định có thể chạy chậm hơn và làm giảm hiệu suất.

Sử dụng `enable_full_determinism()` của Diffusers để bật các thuật toán tất định.

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

enable_full_determinism()
```

`enable_full_determinism` hoạt động bằng cách:

- Đặt biến môi trường `CUDA_LAUNCH_BLOCKING` thành `1`
- Đặt biến môi trường [CUBLAS_WORKSPACE_CONFIG](https://docs.nvidia.com/cuda/cublas/index.html#results-reproducibility) thành `:16:8` để cuBLAS sử dụng bố cục workspace cố định khi chạy
- Gọi `torch.use_deterministic_algorithms(True)`
- Đặt `torch.backends.cudnn.deterministic = True`
- Đặt `torch.backends.cudnn.benchmark = False` để cuDNN không chọn một thuật toán convolution khác nhau ở mỗi lần chạy
- Tắt TensorFloat32 (TF32) bằng `torch.backends.cuda.matmul.allow_tf32 = False` để ưu tiên phép nhân ma trận độ chính xác đầy đủ hơn

## Các bước tiếp theo

Bạn nên đọc ghi chú dành cho nhà phát triển của PyTorch về [Reproducibility](https://docs.pytorch.org/docs/stable/notes/randomness.html). Bạn có thể cố gắng hạn chế tính ngẫu nhiên, nhưng điều này không được *đảm bảo* ngay cả khi sử dụng cùng một seed.

