可复现性
Diffusion 是一个随机过程,每次都会生成不同的输出。对于测试和复现结果等用例,你希望在一定的容差范围内,跨版本和平台每次都能生成相同的结果。
本指南将向您展示如何控制随机性来源并启用确定性算法。
生成器
Pipelines 依赖 torch.randn 来创建初始噪声张量,而该函数每次都会使用不同的随机种子。若要在 CPU 或 GPU 上生成相同的输出,请使用 Generator 来管理随机值的生成方式。
如果可复现性很重要,你应该使用 CPU 上的
Generator。性能损失通常可以忽略不计,并且你会生成更相似的数值。
如果您关注可复现性,请使用 CPU Generator。CPU 随机数生成器在不同机器上更加稳定。
当传入 CPU Generator 时,Diffusers 的 randn_tensor() 会在 CPU 上进行采样,并在流水线内部将张量移至 GPU。您无需自行调用 randn_tensor 或 .to("cuda")。GPU Generator 则直接在设备上采样,其结果可能与 CPU 上的结果存在差异。
使用 manual_seed 来设置种子。
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 设置种子。
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]向 pipeline 传入一个 Generator 对象,而不是整数种子。Generator 会维护一个随机状态,每次使用它时该状态都会被消耗并更新。因此,即使跨 pipeline,后续调用同一对象也会产生不同的结果,因为其状态已经改变。如果需要再次使用相同的种子,请在每次调用前重新设置种子或创建一个新的 Generator。
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 支持针对某些操作使用确定性算法(在可用的情况下),以确保它们产生相同的结果。确定性算法可能会更慢并降低性能。
使用 Diffusers 的 enable_full_determinism() 来启用确定性算法。
from diffusers.utils.torch_utils import enable_full_determinism
enable_full_determinism()enable_full_determinism 的工作原理如下:
- 将环境变量
CUDA_LAUNCH_BLOCKING设置为1 - 将环境变量 CUBLAS_WORKSPACE_CONFIG 设置为
:16:8,以便 cuBLAS 在运行时使用固定的工作区布局 - 调用
torch.use_deterministic_algorithms(True) - 设置
torch.backends.cudnn.deterministic = True - 设置
torch.backends.cudnn.benchmark = False,使 cuDNN 不会在每次运行时选择不同的卷积算法 - 通过
torch.backends.cuda.matmul.allow_tf32 = False禁用 TensorFloat32 (TF32),转而使用精度更高的全精度矩阵乘法
后续步骤
建议阅读 PyTorch 关于 可复现性 的开发者说明。你可以尝试限制随机性,但即使使用相同的随机种子,也无法保证结果完全一致。
Update on GitHub