Guides

    Same seed, different image on the API

    Seeds do not survive precision, hardware or library changes. Pin dtype, batch size, sampler and library version with the seed if a render must be reproducible.

    Versely Team8 min read

    A seed is an index into a noise generator. It is not a photograph. Change the dtype, the GPU, the library version or the batch size, and the same index produces a different field of noise, which means a different image.

    That is why a still that reproduced three times on a local box comes back as a cousin from a hosted endpoint, and why "I locked the seed" is not a complete sentence. The seed only names which draw to take from a specific generator in a specific numeric environment. The environment is the rest of the sentence.

    If you need a render to be reproducible, pin a bundle alongside the seed: dtype, batch size, sampler, step count, guidance, resolution, model version, and the library versions that produced the noise. If you cannot pin those (you are calling a vendor API, which is most production work), treat the seed as a way to iterate on that endpoint this week, and treat the output file as the only portable artefact.

    Laptop showing code on a dark editor screen

    A seed is an index, not a photograph

    Diffusion starts from random static and refines it toward the prompt. The static is not true randomness. It is a pseudo-random number generator, and the seed is the number that initialises it. Same seed, same starting noise, if every other input to that generator is also the same. Different seed, different noise, different walk through the same prompt's landscape.

    The useful default is still: same seed, same prompt, same model, same settings, same output. "Same settings" has to include things the UI often does not show. Precision is a setting. GPU architecture is a setting. Whether you drew one image or eight in one kernel launch is a setting. Change any of those and the noise has changed, even if the seed field still says 42.

    PyTorch's own reproducibility notes are blunt: completely reproducible results are not guaranteed across PyTorch releases, individual commits, or different platforms, and results may not be reproducible between CPU and GPU even with identical seeds. A seed is a contract with one implementation, not with "the model" as an abstract object. A seed recorded from ComfyUI on an NVIDIA card will not, as a rule, reproduce on a hosted API running the same named model. The name is not the implementation.

    What actually changes the noise

    Four classes of change produce a different image from the same seed, not a slightly noisier version of the same image.

    Precision / dtype. Hugging Face Diffusers issue 11056 documents that randn_tensor produces different noise per dtype even with a seeded generator. BF16, FP16 and FP32 are not three encodings of the same random field. They are three different random fields. Switch from FP16 locally to BF16 on the endpoint (or the reverse) and seed 42 is a different starting picture.

    Hardware. CPU versus GPU is enough. Different platforms are enough. Anything that changes which kernels run, or in which order reductions happen, can change the numeric path enough that the sampler walks somewhere else.

    Library version. A PyTorch bump, a Diffusers bump, a CUDA bump. The seed does not version-lock the code that consumes it. Record torch, diffusers, CUDA and the model weight hash if you have it. "Flux on 12 May" is not a pin.

    Batch size and GPU count. The generator is consumed as a stream. Drawing eight latents in one call is not the same sequence of draws as drawing one latent eight times. Multi-GPU splits the work and the RNG state with it. If the image must match, generate it alone, on one device, at batch size 1. A batched launch and eight singles are different numeric paths even when the seed list is identical.

    A 2025 study of numerical nondeterminism in LLM inference (arXiv 2506.09501) is not a diffusion paper, but it lands on the same constraint: a seed does not survive a precision or hardware change. In that stack BF16 showed the most run-to-run variance and FP32 the least; PyTorch still will not promise even FP32 across devices. If a tooltip says "reproducible with seed," read it as "reproducible in this numeric environment with seed." Neighbouring seeds are unrelated, and a lucky seed on one prompt carries no luck to the next. Copy the wording that worked. Re-roll the number.

    The bundle to pin with the seed

    If a render must be reproducible, the seed is one row in a record, not the record. Write this down with every keeper:

    Field Why it is in the bundle
    Seed Indexes the generator
    Prompt, exact One word changes the walk
    Model name and version / weight hash Silent updates void the seed
    Sampler / scheduler Different solver, different path
    Steps Early-stop is a different picture
    Guidance / CFG Changes the denoising direction
    Resolution and aspect ratio Different latent shape, different noise shape
    Dtype (FP32 / FP16 / BF16) randn_tensor is dtype-specific
    Batch size Stream consumption changes
    Device count Splits the RNG
    torch / Diffusers / CUDA versions The generator is code
    Reference images, if any They condition the walk

    Versely's generate_images and generate_image_from_image tools accept a seed. Use it to lock the noise while you change one other thing, so a prompt edit is actually an experiment. That is the same discipline as A/B testing models on one prompt and as the iteration patterns in seeds and reproducibility. A hosted endpoint cannot accept a dtype pin, a GPU pin, or a PyTorch pin. Fill in everything you can control. Keep the file for everything you cannot.

    While exploring, leave the seed floating. When a take is close, freeze it and edit the prompt in small steps. When a take is a keeper, save the output file and the bundle. If a client wants "that one again, but with a different jacket," start from the file (img2img, a masked edit, a reference slot), not from the seed alone.

    What a hosted API can and cannot promise

    Never assume a vendor endpoint's seed is portable. That includes every hosted catalog, Versely's included. The endpoint is a different machine: different GPU, different precision, different library pin, often a different serving stack in front of the same public model name. A seed that matched three times on that endpoint is evidence that that endpoint, this week, with those settings, is stable enough to iterate on. It is not evidence it will match a local ComfyUI graph or next month's weights.

    What a hosted API can do: hold a seed while you change one variable (wording, sampling steps, guidance, aspect ratio); fan the same prompt across named models in one generate_images request (a comparison, not a reproduction: each model interprets the seed in its own noise space); and give you the file. The PNG is the portable object. The seed is a recipe you may not be able to cook again.

    What it cannot do: match seed 42 on your GPU, survive a weight bump, or make an eight-image call equal eight singles with those seeds.

    If you are automating, the CLI provisions a key. Dispatch is still HTTP. Poll request_id and store the result URL. There is no "run this on my local numeric environment" flag. The text-to-image studio is the same hosted environment. Use the seed as an iteration lock, not as an archive format.

    Video is looser. A near-identical first frame can still be a different camera move by second three, and several video models do not expose a seed. Check the model page before you assume one. Lock the look in a still, then animate the still.

    FAQ

    Why did the same seed look different on the API than on my GPU?

    Because the seed does not travel with the dtype, the hardware or the library version. randn_tensor draws different noise in BF16, FP16 and FP32 even when the generator is seeded. CPU versus GPU, different platforms, and PyTorch or Diffusers bumps all void the match. The API is a different numeric environment. The seed is not enough.

    What do I actually need to record besides the seed?

    Dtype, batch size, sampler, steps, guidance, resolution, model version, device count, and the library versions (torch, Diffusers, CUDA). Plus the exact prompt and any reference images. If you cannot record dtype and device, you cannot claim portability. Save the output file in every case.

    Is FP32 enough to make a seed portable across machines?

    No. FP32 is the least noisy option on a single setup. PyTorch still does not guarantee reproducibility across devices, platforms or library versions. FP32 plus batch size 1 plus one GPU plus a version pin is the honest local target. It is not a promise that the same seed will match a hosted API.

    Should I trust a seed I saved last month?

    As an iteration starting point on the same endpoint and the same model version, yes. As a way to recreate a client-approved still without the file, no. Providers update weights. Serving stacks change. If the still matters, the still is the source of truth. Use the seed to get back into the neighbourhood, then edit from the file.