使用Diffusers同一种子搭配不同噪声调度器生成图像遇故障求助
问题解决:Diffusers中Euler系列调度器生成无效噪声的修复
问题根源
共用输入噪声导致初始状态错误
原代码里三个调度器复用了同一个input变量,第一个DDPMScheduler处理后的噪声直接传给了后面的Euler调度器,完全没用到原始随机噪声,根本不符合“同一初始噪声去噪”的要求。调度器step方法调用逻辑错误
Euler系列调度器(EulerDiscrete、EulerAncestral)不需要提前调用scale_model_input,这个方法是给DDPMScheduler这类特定调度器设计的,强行调用会把模型输出的残差搞乱,导致去噪完全错误。调度器初始化方式不当
直接用from_pretrained加载Euler系列调度器到DDPM预训练模型,没法正确转换调度器的参数配置,得先加载DDPM的调度器配置,再用这个配置生成Euler调度器。
修正后的完整代码
import torch from diffusers import DDPMScheduler, EulerAncestralDiscreteScheduler, EulerDiscreteScheduler, UNet2DModel from PIL import Image # 正确初始化调度器:基于DDPM的配置转换Euler系列 ddpm_scheduler = DDPMScheduler.from_pretrained("google/ddpm-cat-256") schedulers = [ ddpm_scheduler, EulerAncestralDiscreteScheduler.from_config(ddpm_scheduler.config), EulerDiscreteScheduler.from_config(ddpm_scheduler.config) ] # 加载预训练模型 model = UNet2DModel.from_pretrained("google/ddpm-cat-256", use_safetensors=True) # 给每个调度器设置50步时间步 for scheduler in schedulers: scheduler.set_timesteps(50) sample_size = model.config.sample_size # 生成原始随机噪声,每个调度器都用这个初始值 original_noise = torch.randn((1, 3, sample_size, sample_size)) denoised_dict = {} # 每个调度器独立处理,用克隆的原始噪声做初始输入 for i, scheduler in enumerate(schedulers): input = original_noise.clone() # 每次都从原始噪声开始 for t in scheduler.timesteps: with torch.no_grad(): noisy_residual = model(input, t).sample # 根据调度器类型调用step方法 if isinstance(scheduler, DDPMScheduler): # DDPMScheduler需要先缩放模型输入 scaled_residual = scheduler.scale_model_input(noisy_residual, t) previous_noisy_sample = scheduler.step(scaled_residual, t, input).prev_sample else: # Euler系列直接传模型输出的残差 previous_noisy_sample = scheduler.step(noisy_residual, t, input).prev_sample input = previous_noisy_sample denoised_dict[i] = input # 输出每个调度器的结果 for idx in denoised_dict: image = (denoised_dict[idx] / 2 + 0.5).clamp(0, 1).squeeze() image = (image.permute(1, 2, 0) * 255).round().to(torch.uint8).cpu().numpy() image = Image.fromarray(image) # Notebook里直接显示,本地运行可以改成保存图片 print(f"调度器{idx}生成结果:") display(image) # image.save(f"cat_result_{idx}.png")
关键修复点说明
- 独立初始噪声:每个调度器循环时都克隆原始噪声,确保三者从完全相同的起点开始去噪。
- 分类型调用step:针对DDPMScheduler和Euler系列做不同处理,避免错误调用
scale_model_input。 - 正确初始化调度器:用DDPM的配置生成Euler调度器,保证参数和预训练模型匹配。
内容的提问来源于stack exchange,提问作者Gesser
相关产品推荐
相关产品推荐

