Stable Diffusion 可以在自己的电脑上运行。sd-turbo 是一个蒸馏版本,1~4 步就能出图,没有显卡也能用 CPU 跑。 这篇做
txt2img.py:固定种子生成可复现的图片,把提示词、种子、模型版本和许可证写进 PNG 元数据,并自动检查“同一种子是否得到同一张图”。
先看清成品
- CPU 上加载约 1.5 秒(已下载时),生成一张 512×512 约 5 秒。
- 同一种子两次生成的像素哈希一致(5434373c6f30f978);不同种子不同。
- 发现并修复:diffusers 0.41 中
torch_dtype已弃用,改用dtype。pytest 3 项通过(真实加载模型)。
合规提醒:sd-turbo 使用 Stability AI Community License:研究、非商业用途,以及年收入低于 100 万美元的个人或组织的商业用途免费;超过的需要企业许可,以模型页面和 stability.ai/license 为准。sd-turbo 仓库不含安全检查器(diffusers 加载时会提示):不要把未经过滤的生成服务公开给他人使用。不生成真实人物的误导性图像,不对他人照片做未经同意的修改;图生图只处理你有权使用的图片。模型从 Hugging Face 官方仓库下载,不使用来路不明的模型文件。
运行说明:本篇在 box 上真实运行了 Stable Diffusion:stabilityai/sd-turbo(revision b261bac6),diffusers 0.41.0,torch 2.14.1(CPU 版),8 核 CPU、无显卡。512×512、1 步生成一张约 4~5 秒。文中的图片都是这次运行生成的。没有测试 GPU,也没有运行 ComfyUI 和 SD 3.5(SD 3.5 需要在 Hugging Face 上同意许可后才能下载,且 CPU 上太慢)。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
txt2img.py |
生成并写入元数据 |
test_txt2img.py |
3 项测试(真实运行模型) |
example.png |
本文生成的示例图(种子 42) |
需要准备哪些环境?
| 项目 | 说明 |
|---|---|
| Python | 3.10 以上 |
| PyTorch | CPU:pip install torch --index-url https://download.pytorch.org/whl/cpu;有 NVIDIA 显卡时按 PyTorch 官网选择 CUDA 版本 |
| diffusers 等 | pip install diffusers transformers accelerate safetensors pillow pytest |
| 磁盘 | sd-turbo 的 fp16 权重约 2.5 GB |
| 内存 | CPU 运行时建议 8 GB 以上(本文机器 15 GB) |
关键事实
| 事实 | 来源 |
|---|---|
SD-Turbo 不使用 guidance_scale 和 negative_prompt,用 guidance_scale=0.0 关闭;1~4 步生成 |
sd-turbo 模型页面 |
| 训练分辨率 512×512;更大的尺寸也能运行,但效果不保证 | 同上 |
| 许可:Stability AI Community License | 同上 / LICENSE.md |
diffusers 0.41 中 from_pretrained 的 torch_dtype 参数已弃用,提示 “Please use dtype instead.” |
本文实测 |
文件结构
75-stable-diffusion-A-src/
├── txt2img.py
├── test_txt2img.py
└── example.png
第 1 步:安装
python -m venv sd && . sd/bin/activate
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install diffusers transformers accelerate safetensors pillow pytest
# 第一次运行时会从 Hugging Face 下载约 2.5 GB 的 fp16 权重
第 2 步:脚本
"""本地运行 Stable Diffusion(diffusers + stabilityai/sd-turbo),生成可复现的图片:
- 固定种子 → 同一台机器、同一版本下得到同一张图
- 把提示词、种子、步数、模型和版本号写进 PNG 的文本元数据,以后能查到图是怎么来的
sd-turbo 使用 Stability AI Community License(研究、非商业,以及年收入低于 100 万美元的商业使用免费),以模型页面为准。
sd-turbo 仓库不含安全检查器(diffusers 加载时会提示):不要把未经过滤的生成服务公开给他人使用。"""
import argparse, hashlib, json, sys, time
import torch
from diffusers import AutoPipelineForText2Image
from huggingface_hub import model_info
from PIL import PngImagePlugin
MODEL = "stabilityai/sd-turbo"
def load(model=MODEL, device=None):
device = device or ("cuda" if torch.cuda.is_available() else "cpu")
dtype = torch.float16 if device == "cuda" else torch.float32 # CPU 上用 float32;fp16 权重会在加载时转换
# diffusers 0.41 起参数名是 dtype;旧教程里的 torch_dtype 仍可用,但会打印弃用警告
pipe = AutoPipelineForText2Image.from_pretrained(model, dtype=dtype, variant="fp16").to(device)
pipe.set_progress_bar_config(disable=True)
return pipe
def generate(pipe, prompt, seed, steps=1, size=512):
# sd-turbo 是蒸馏模型:官方用法 guidance_scale=0.0、1~4 步;它是按 512x512 训练的
g = torch.Generator(device="cpu").manual_seed(seed)
return pipe(prompt, num_inference_steps=steps, guidance_scale=0.0, width=size, height=size, generator=g).images[0]
def save(img, path, meta):
info = PngImagePlugin.PngInfo(); info.add_text("parameters", json.dumps(meta, ensure_ascii=False))
img.save(path, pnginfo=info)
return hashlib.sha256(img.tobytes()).hexdigest()[:16]
def main(argv=None):
ap = argparse.ArgumentParser(); ap.add_argument("prompt"); ap.add_argument("--seed", type=int, default=42); ap.add_argument("--steps", type=int, default=1)
ap.add_argument("--out", default="out.png"); ap.add_argument("--check", action="store_true", help="用同一种子再生成一次,确认结果一致"); a = ap.parse_args(argv)
t = time.time(); pipe = load(); print(f"加载模型 {time.time() - t:.1f} 秒")
try: rev = model_info(MODEL).sha
except Exception: rev = "unknown"
import diffusers
meta = {"prompt": a.prompt, "seed": a.seed, "steps": a.steps, "guidance_scale": 0.0, "size": 512, "model": MODEL, "revision": rev,
"diffusers": diffusers.__version__, "torch": torch.__version__, "license": "Stability AI Community License"}
t = time.time(); img = generate(pipe, a.prompt, a.seed, a.steps); dur = time.time() - t
h = save(img, a.out, meta); print(f"生成 {dur:.1f} 秒 → {a.out}(像素哈希 {h})")
if a.check:
h2 = hashlib.sha256(generate(pipe, a.prompt, a.seed, a.steps).tobytes()).hexdigest()[:16]
print("复现检查:", "一致" if h == h2 else f"不一致({h2})")
return 0
if __name__ == "__main__":
sys.exit(main())
第 3 步:测试
"""会真实加载 sd-turbo 并生成图片(CPU 上每张约 5 秒);首次运行需要先下载模型。"""
import hashlib, json, pytest
from PIL import Image
import txt2img as T
@pytest.fixture(scope="module")
def pipe(): return T.load()
P = "a watercolor illustration of a quiet mountain village at sunrise, soft light, mist"
def h(img): return hashlib.sha256(img.tobytes()).hexdigest()
def test_same_seed_same_image(pipe):
a, b = T.generate(pipe, P, 42), T.generate(pipe, P, 42)
assert a.size == (512, 512) and h(a) == h(b)
def test_different_seed(pipe):
assert h(T.generate(pipe, P, 42)) != h(T.generate(pipe, P, 43))
def test_metadata_roundtrip(pipe, tmp_path):
meta = {"prompt": P, "seed": 7, "model": T.MODEL}
T.save(T.generate(pipe, P, 7), tmp_path / "x.png", meta)
assert json.loads(Image.open(tmp_path / "x.png").text["parameters"]) == meta
第 4 步:运行
$ python txt2img.py "a watercolor illustration of a quiet mountain village at sunrise, soft light, mist" --seed 42 --check
加载模型 1.2 秒
生成 5.5 秒 → out.png(像素哈希 5434373c6f30f978)
复现检查: 一致
$ python -c "from PIL import Image; print(Image.open('out.png').text['parameters'])"
{"prompt": "a watercolor illustration of a quiet mountain village at sunrise, soft light, mist", "seed": 42, "steps": 1, "guidance_scale": 0.0, "size": 512, "model": "stabilityai/sd-turbo", "revision": "b261bac6fd2cf515557d5d0707481eafa0485ec2", "diffusers": "0.41.0", "torch": "2.14.1+cpu", "license": "Stability AI Community License"}
$ python -m pytest -q
3 passed in 28.60s
生成的图片:

(以上为本文实际生成结果)
怎么检查结果?
- 同一台机器、同一版本下,同一种子得到同一张图(像素哈希一致)。
- 换显卡、换 torch 或 diffusers 版本后,同一种子的结果可能不同,所以元数据中记下了版本。
- 用任意 PNG 查看工具或
Image.open(...).text都能读到参数。 - 图片被社交平台压缩或另存为 JPG 后,元数据通常会丢失。
调试示例
1. torch_dtype 弃用警告。 照很多教程写 from_pretrained(..., torch_dtype=torch.float32),diffusers 0.41.0 打印:
deprecate("torch_dtype", "1.0.0", _TORCH_DTYPE_DEPRECATION_MESSAGE) # 内容是 "Please use `dtype` instead."
现在还能运行,但计划在 1.0.0 移除。改为 dtype=。
2. 安全检查器提示。 加载时 diffusers 提示 “You have disabled the safety checker…”。原因是 sd-turbo 仓库本身不带安全检查器,不是我关掉的。自己本地使用没有问题,但如果要做成给别人用的服务,必须自己加内容过滤(见合规提醒)。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 下载很慢或中断 | 网络问题 | 重新运行会续传;也可以先用 huggingface-cli download 下载 |
| CPU 上每张几十秒 | 线程少或内存不足 | 减少其他程序;先用 1 步 |
| 同一种子结果不同 | 换了设备或版本 | 对照元数据中的版本 |
| 图片发糊 | sd-turbo 只适合 512×512 | 保持 512;需要大图用其他模型 |
模板规则
- 固定种子,记录参数和版本。
- sd-turbo 用 guidance_scale=0.0、1~4 步、512×512。
- 遵守许可证;对外服务必须加内容过滤。
项目资源
| 用途 | 地址 |
|---|---|
| sd-turbo 模型页面(官方) | https://huggingface.co/stabilityai/sd-turbo |
| sd-turbo 许可证 | https://huggingface.co/stabilityai/sd-turbo/blob/main/LICENSE.md |
| Stability AI 许可说明 | https://stability.ai/license |
| diffusers 文档 | https://huggingface.co/docs/diffusers/index |
能复现的图,才说得清它是怎么来的。