diffusers icon indicating copy to clipboard operation
diffusers copied to clipboard

`seed` missing from `StableDiffusionPipeline()` v2*?

Open BFauber opened this issue 3 years ago • 5 comments

It appears that the seed argument is missing from v2* of StableDiffusionPipeline().

https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion.py#L397

If this is correct, I recommend editing the generator: Optional[torch.Generator] = None to include the option of a user-defined seed, such as generator: Optional[torch.Generator().manual_seed(seed)] = None, where the seed value is a separate argument for the StableDiffusionPipeline() __call__() and seed: int = None is the default. This change will enable the reproducible generation of outputs from the same input parameters.

https://pytorch.org/docs/stable/generated/torch.Generator.html

Thanks!

BFauber avatar Dec 13 '22 15:12 BFauber

For the diffusers approach (currently, at least) you need to generate the initial noise directly and provide via latents argument when you call the pipeline. For example here's a function that will generate either reproducible or random latents based on the batch size (4 images that will be reproducible with the seed 546213 in this example):

def getLatents(num_images=1, height=768, width=768, userSeed=-1, device="cuda"):
    generator = torch.Generator(device=device)

    latents = None
    # Get a new random seed, store it and use it as the generator state
    if userSeed == -1:
        seed = generator.seed()
    else:
        seed = userSeed
    generator = generator.manual_seed(seed)
    
    latents = torch.randn(
        (num_images, pipe.unet.in_channels, height // 8, width // 8),
        generator = generator,
        device = device,
        dtype = torch.float16
    )

device_str = "cuda:0"

pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipe.scheduler = KDPM2DiscreteScheduler.from_config(pipe.scheduler.config)
pipe = pipe.to(device_str)

prompt = f"an image of a cat with a hat on its head"
latents = getLatents(4, 768, 768, 546213, device_str)

image = pipe(prompt, num_inference_steps=20, width=768, height=768, latents=latents).images[0]

mlmcgoogan avatar Dec 13 '22 16:12 mlmcgoogan

Thanks @mlmcgoogan for the quick feedback.

I appreciate the ability to feed the pipe() user-defined latents. Conversely, setting the seed value in the SD v1* prompt was quite straightforward.

Why is the current getLatents() approach in place vs seed with SD v2*?

Thanks!

BFauber avatar Dec 13 '22 17:12 BFauber

Try:

generator = torch.Generator(device="cuda").manual_seed(8)
image = pipeline(prompt, generator=generator).images[0]

https://huggingface.co/docs/diffusers/main/en/using-diffusers/schedulers#access-the-scheduler

averad avatar Dec 15 '22 19:12 averad

Thanks @mlmcgoogan and @averad for these suggestions!

BFauber avatar Dec 17 '22 18:12 BFauber

Also linking this doc page on generating the same output batched vs. non-batched with a reproducible seed: https://huggingface.co/docs/diffusers/using-diffusers/reusing_seeds

patrickvonplaten avatar Dec 20 '22 00:12 patrickvonplaten

This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the contributing guidelines are likely to be ignored.

github-actions[bot] avatar Jan 13 '23 15:01 github-actions[bot]