AI 图像同 seed 出不同结果:可复现性排查

同样的 seed 和提示词却出不同图?seed 只是约 10 个变量之一。要锁的是模型版本、采样器、调度器、步数、CFG 和后处理,而不只是 seed。

你把 seed 锁成 42,提示词原封不动复制过来,过一周再跑一遍。出来的图很接近,但不一样:头发飞丝不同,耳环换了一只,地平线略微偏移。你以为 seed 是输出的哈希,所以这看起来像 bug。其实不是。

最快的修法:一张 diffusion 图像是 seed、采样器(sampler)、调度器(scheduler)、模型权重、CFG、步数、分辨率、所有 LoRA / ControlNet / refiner pass 的确定性函数。把好图保存的元数据(用 exiftool,或 PNG 的 parameters 块)和新请求逐项对比,找出那个被改动的参数——最常见的是模型版本被静默升级,或采样器被设成了”auto”——然后把它钉死。可复现性是一套纪律,不是某个开关。

TL;DR

  1. 保存原图的完整元数据,和新请求 diff 一下,那一行不匹配的就是元凶。
  2. 钉住模型版本,不只是模型名。托管模型会在你不知情时被升级。
  3. 显式设定采样器和调度器,绝不让 UI 走”auto”。
  4. 测试时把后处理(人脸修复、放大、refiner)全关掉,再逐个加回来。
  5. 要本地逐字节一致,开启 torch.use_deterministic_algorithms(True)
  6. 有些服务(DALL-E / gpt-image、跨会话的 Midjourney)做不到精确复现。对这些,目标定为”视觉上不可区分”,或者换一家能钉版本、钉 seed 的托管商。

你属于哪一类?

现象最可能的原因跳到
上个月还能复现,这周设置没变却崩了服务商把底模升级了原因 1 / 步骤 2
同一会话里每次都不同”auto”采样器、隐藏后处理或 GPU 非确定性 kernel原因 2、5、7
只在两台机器 / 两张 GPU 间不同CUDA kernel 加硬件非确定性原因 5 / 步骤 5
细节小漂移,参数肉眼看都一样某个一格之差(CFG、步数、像素)或看不见的提示词改动原因 3、6 / 步骤 1
专门是 Midjourney 或 DALL-E这两家的 seed 是尽力而为,不是真正的确定性控制FAQ

常见原因

按”同样 seed 出不同结果”的实际锅大小排序。

1. 模型版本被静默升级

托管服务(Midjourney、Adobe Firefly、DALL-E / gpt-image、托管 SDXL 和 Flux 端点)会按自己的节奏更新底模。seed 在新权重下映射到不同的噪声张量,于是即便请求逐字节相同,图也变了。你什么都没做错,是后端换了。截至 2026 年 6 月,这是一套原本能复现的流程突然失效的头号原因。

如何识别:查看服务商的版本说明 / 版本下拉框。今天的版本号与当初保存时不同 = 模型变了。

2. 采样器或调度器被换掉

同 seed 下 DPM++ 2M KarrasEuler a 出图就不一样。一些 UI 默认走”auto”,会根据分辨率或模型自动选采样器,于是采样器可能悄悄翻了,你没察觉。(举例:Flux Dev 通常用 DPM++ 2M + sgm uniform,而 Flux Schnell 要 CFG 1 配 simple 调度器,在两者之间切换会改变一切。)

如何识别:打开保存的 PNG 元数据(或 API 请求日志),把采样器名字和今天的请求比一比。采样器不匹配 = 不同图像。

3. 步数、CFG 或分辨率有一格之差

CFG 7.0 与 7.5、步数 28 与 30、分辨率 1024x10241024x1080,同 seed 下都会出明显不同的图。UI 滑块经常隐式四舍五入;从数值输入框复制粘贴更稳妥。

如何识别:把完整参数 dump 出来逐字节比对,不要靠肉眼。

4. LoRA / ControlNet / refiner 加上了或权重变了

LoRA 强度 0.6 vs 0.7 看得出差别。Refiner pass 切换比例 0.8 vs 0.75 会改变高频细节。ControlNet 的预处理(canny 边、深度图)在某些管线里本身就对 seed 敏感。

如何识别:把每一个适配器、LoRA、embedding、后处理 pass 连同确切权重列出来。哪一项缺失或不同,就是它。

5. CUDA / 硬件非确定性

PyTorch 的 torch.backends.cudnn.benchmark = True(以及 cudnn.deterministic = False 这个默认)允许 GPU 为同一操作选择不同的 kernel,产生微小的浮点差异,并在 diffusion 步数中累积。同 seed 在同一张 GPU 上仍可能出微差;换一张 GPU 型号几乎一定不同。

如何识别:本地跑时设 torch.use_deterministic_algorithms(True) 并配上 CUBLAS_WORKSPACE_CONFIG 环境变量。若可复现性变好,这是贡献因素之一。

6. 提示词被无意改动

末尾多一个空格、弯引号 vs 直引号、em 破折号 vs 短横:分词器看它们是不同 token。从富文本应用(Notion、Google Docs)复制粘贴往往会被悄悄改写标点。

如何识别:用 diffcmp 比对提示词字符串。肉眼检查不可靠。

7. 服务商加了隐藏的后处理

一些托管 API 会在输出环节跑人脸增强、放大、安全过滤。这些 pass 通常不跟随 seed,会加入随机性,于是你得到一个确定性的核心图像加一个非确定性的修饰层。

如何识别:如果 API 支持,请求未经处理的原图(enhance: falseupscale: 1)。原图稳定但成片不稳,说明后处理是元凶。

开始前准备

  • 在开始任何新的运行前,保存原始”好图”和它的完整元数据(PNG parameters 块,或 API 响应 JSON)。
  • 记下出原图时所用的具体服务商、模型名和版本号字符串。
  • 在重跑之前,记录今天的服务商版本号字符串。
  • 决定你的目标:在托管 API 上很难做到逐字节一致,“视觉上不可区分”是那里更现实的目标。

需要收集的信息

  • seed 值(整数;确认是以 int 传递的,不是字符串 "42")。
  • 采样器名和调度器名,精确字符串。
  • 步数、CFG、宽度和高度。
  • 完整提示词字符串和负向提示词字符串,逐字节。
  • 每一个 LoRA、embedding、ControlNet、IP-Adapter 及其权重值。
  • 模型文件名 + 哈希(本地)或版本号字符串(托管)。
  • 硬件:GPU 型号、CUDA 版本、torch 版本(本地)。

一步步修复

按从最小代价到最大代价排序。

步骤 1:比对参数 dump

把两套元数据保存到文本文件并 diff:

exiftool -PNG:parameters good.png > good.txt
exiftool -PNG:parameters bad.png > bad.txt
diff good.txt bad.txt

任何一行不同就是嫌疑点。哪怕只有一个参数不匹配,也先把它修了再往下走。

步骤 2:显式锁定模型版本

托管 API 里传版本 ID,不只是模型名。在 Replicate 上这是版本哈希(version hash);在自部署里就是你加载的那个 checkpoint 文件:

{
  "model": "stable-diffusion-xl-base-1.0",
  "model_version": "39ed52f2-a78c-4ce1-9c1d-aaaaaaaaaa",
  "seed": 42
}

如果服务商不提供版本锁,换一家支持的。Replicate 每次模型运行都暴露版本哈希,Google Vertex AI Imagen 也写明支持基于 seed 的确定性输出,两者都能让你复现某个特定构建。自部署(RunPod、你自己的 GPU)能给到最强保证。

步骤 3:锁定采样器和调度器

明确指定两者,不要让”auto”来选:

{
  "sampler": "DPM++ 2M Karras",
  "scheduler": "karras",
  "steps": 30,
  "cfg_scale": 7.0
}

如果你的 UI 把它们藏起来了,换 API 或换暴露这些参数的 UI(ComfyUI、InvokeAI、AUTOMATIC1111 / Forge)。具体到 ComfyUI,要用一个固定 seed 的 RandomNoise 节点,而不是让采样器每次重新取种。

步骤 4:从管线里剥掉隐式随机源

可复现性测试期间关闭人脸修复、放大、refiner,只跑底模。底模稳定之后再逐个加回每个后处理,并验证每一个也是可 seed 化的。

{
  "enhance_face": false,
  "upscale": 1,
  "refiner": null
}

步骤 5:强制 torch 确定性(本地管线)

import torch
import os

# ":4096:8" 或 ":16:8" 都有效;HF diffusers 文档用的是 ":16:8"。
os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"
torch.use_deterministic_algorithms(True, warn_only=True)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False

generator = torch.Generator(device="cuda").manual_seed(42)

会损失大约 10-20% 推理速度,但同一硬件上能得到逐字节一致的输出。CUBLAS_WORKSPACE_CONFIG 必须在 CUDA 初始化之前设好(即第一次调用 torch.cuda 之前),否则不起作用。

步骤 6:把提示词当字节而非文本

把提示词和参数 JSON 一起存到文本文件里。不要从截图里重新打字。用 cmp 比对:

cmp good_prompt.txt new_prompt.txt

这里的差异通常是看不见的空白或标点替换。参见 提示词太长反而效果更差,讲提示词脆弱性的更多模式。

步骤 7:本地快照模型权重以做真正的长期可复现

对于需要逐年可复现的项目,把模型文件(.safetensors)下载下来并保存 sha256。托管版本会被废弃;你的本地快照不会。

sha256sum sd_xl_base_1.0.safetensors > sd_xl_base_1.0.sha256

如何确认已修复

  • 同一提示词加同一 seed 连续跑两次。对两张 PNG 像素缓冲做哈希(shasum -a 256 a.png b.png)。在完全锁定的本地管线下,哈希一致。
  • 跨两个会话 / 两天跑同样的提示词和 seed。除非服务商升级了模型,哈希应仍相同。
  • 故意改一个参数(比如 cfg 7.0 改成 7.5),确认输出现在不同。这证明你的管线响应正常,不是卡在缓存图上。
  • 在做不到像素哈希相等的托管 API 上,现实的通过标准是:重跑视觉上不可区分,且版本号字符串没变。

长期预防

  • 把参数集合视为一个元组 (model_version, seed, sampler, scheduler, steps, cfg, width, height, prompt_sha, negprompt_sha, adapters_json)。把每个元组连同输出一起记录。
  • 在每张保存图旁边存完整的元数据 JSON。若工具支持,把它嵌入 PNG。
  • 在你的服务商客户端里钉住模型版本;订阅服务商的”模型即将废弃”通知,提前知道哪个版本要下线。
  • 对几个月后可能要重跑的客户项目,本地快照模型文件。
  • 本地管线默认开启确定性模式;只有需要吞吐时再关掉。
  • 复制粘贴后用 cmp 比对提示词;不要相信肉眼。

常见坑

  • 以为”锁了 seed”就够了。seed 只是约十个参数之一。
  • 通过 Slack / Notion 复制提示词,引号和破折号会被悄悄改写。
  • 相信托管服务商没升级。查版本号字符串。
  • 信任 UI 里的”auto”采样器,它跨发布是非确定性的。
  • 肉眼比较两张图就宣布”一样”,而像素 diff 说不一样。真正的可复现性需要像素哈希相等。
  • 跳过后处理剥除。人脸增强器是头号隐藏随机源。

FAQ

Q:我什么都锁了,但图像还是略有差异,为什么?

很可能是 GPU 上的 cudnn 非确定性。开启 torch.use_deterministic_algorithms(True) 并关掉 cudnn.benchmark。如果你运行的 GPU 型号与原图不同,可能永远拿不到逐字节一致,接受视觉等价就好。

Q:Midjourney 加了 --seed 还是复现不出原图,怎么办?

Midjourney 有 --seed 参数(给作品发”信封”emoji 反应,或在网站上,都能查到一个 job 的 seed)。在 V8.1 之后,它在同一会话、同一模型版本内大约 99% 一致,但跨会话、跨模型版本、以及 Fast 和 Relaxed 模式之间都不可靠。对可复现性要求严格的工作,请改用钉了版本的 SDXL 或 Flux 托管。

Q:DALL-E / gpt-image 支持可复现的 seed 吗?

不支持精确复现。那里的 seed 只是把风格和角色往一致里推一推,OpenAI 并不保证确定性图像输出;而且如果提示词里带了参考图,确定性会彻底失效。把它当成”相似”,而非”一致”。

Q:我直接保存输出文件不就行了,何必复现?

成片确实应该保存 PNG。可复现性的价值在于迭代时(改一个参数干净地看效果),或一年前的图被客户要新变体时。

Q:增加步数会让输出更确定吗?

不会。步数多只是降噪更彻底,并不能让 seed-to-image 函数更稳定。确定性是整个管线配置的属性,不是步数的。

相关阅读

外部参考:Hugging Face Diffusers 可复现性指南Midjourney Seeds 官方文档

标签: #排查 #ai-image #seed #reproducibility #diffusion