You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Diffusers同一种子搭配不同噪声调度器生成图像遇故障求助

问题解决:Diffusers中Euler系列调度器生成无效噪声的修复

问题根源

  1. 共用输入噪声导致初始状态错误
    原代码里三个调度器复用了同一个input变量,第一个DDPMScheduler处理后的噪声直接传给了后面的Euler调度器,完全没用到原始随机噪声,根本不符合“同一初始噪声去噪”的要求。

  2. 调度器step方法调用逻辑错误
    Euler系列调度器(EulerDiscrete、EulerAncestral)不需要提前调用scale_model_input,这个方法是给DDPMScheduler这类特定调度器设计的,强行调用会把模型输出的残差搞乱,导致去噪完全错误。

  3. 调度器初始化方式不当
    直接用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 01:40:18