同一个提示词,换种子差别很大。先批量出小图挑种子,再出正式图,效率最高。 这篇做
seed_grid.py:一次生成“提示词 × 种子”的网格图,并把每张图的参数、耗时和像素哈希写进 runs.csv。
先看清成品
- 2 个提示词 × 4 个种子 = 8 张,每张 4.0~4.8 秒,生成网格图。
- 实测中文提示词:两个种子都只画出了雾气中的山,没有村庄,也没有日出的暖色;同样种子的英文提示词则符合描述。脚本现在遇到中文提示词会给出提醒。
- 发现并修复:网格标签中的中文显示为方块(字体顺序问题)。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 上太慢)。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
seed_grid.py |
生成网格和 runs.csv |
txt2img.py |
与 A 篇相同 |
prompts.txt |
示例提示词 |
examples/ |
本文生成的两张网格图 |
test_grid.py |
3 项测试 |
需要准备哪些环境?
| 项目 | 说明 |
|---|---|
| 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 使用 CLIP 文本编码器,训练语料以英文为主 | sd-turbo 模型页面(基于 SD 2.1);中文效果为本文实测,仅 2 个种子 |
| 同一种子在同一环境下结果确定 | 本文实测:两次运行的像素完全一致 |
文件结构
75-stable-diffusion-B-src/
├── seed_grid.py
├── txt2img.py
├── prompts.txt
├── test_grid.py
└── examples/
├── sheet.jpg
└── zh_vs_en.jpg
第 1 步:提示词
# 每行一个提示词(英文效果更稳定)
a watercolor illustration of a quiet mountain village at sunrise, soft light, mist
a ceramic teapot on a wooden table, studio product photo, soft shadows
第 2 步:脚本
"""一次生成“提示词 × 种子”的小图网格(contact sheet),并把每张图的参数和耗时写进 runs.csv,方便挑选种子再出正式图。
复用 75A 的 txt2img.py。CPU 上每张约 5 秒,先用少量种子试。"""
import argparse, csv, os, re, sys, time
from PIL import Image, ImageDraw, ImageFont
import txt2img as T
def font(size):
# 先找中文字体:DejaVu 没有汉字,中文提示词的标签会变成方块(调试时实际出现过)
for p in ("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
"C:/Windows/Fonts/msyh.ttc", "/System/Library/Fonts/PingFang.ttc", "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"):
if os.path.exists(p): return ImageFont.truetype(p, size)
return ImageFont.load_default()
def sheet(cells, prompts, seeds, thumb=192, pad=24):
W, H = len(seeds) * thumb, len(prompts) * (thumb + pad)
img = Image.new("RGB", (W, H + pad), "white"); d = ImageDraw.Draw(img); f = font(14)
for j, s in enumerate(seeds): d.text((j * thumb + 4, 4), f"seed {s}", fill="black", font=f)
for i, p in enumerate(prompts):
y = pad + i * (thumb + pad)
d.text((4, y + thumb + 4), f"P{i + 1}: {p[:60]}", fill="black", font=f)
for j, s in enumerate(seeds): img.paste(cells[(i, j)].resize((thumb, thumb)), (j * thumb, y))
return img
def main(argv=None):
ap = argparse.ArgumentParser(); ap.add_argument("prompts", help="每行一个提示词的文本文件"); ap.add_argument("--seeds", default="1,2,3,4")
ap.add_argument("--steps", type=int, default=1); ap.add_argument("--out", default="grid"); a = ap.parse_args(argv)
prompts = [l.strip() for l in open(a.prompts, encoding="utf-8") if l.strip() and not l.startswith("#")]
seeds = [int(s) for s in a.seeds.split(",")]
for p in prompts:
if re.search(r"[\u4e00-\u9fff]", p):
print(f"提醒:“{p[:20]}…”是中文。sd-turbo 的文本编码器(CLIP)主要按英文训练,实测中文提示词的画面与描述明显不符,建议改用英文。")
os.makedirs(a.out, exist_ok=True); pipe = T.load(); cells = {}
with open(os.path.join(a.out, "runs.csv"), "w", newline="", encoding="utf-8") as f:
w = csv.writer(f); w.writerow(["file", "prompt", "seed", "steps", "seconds", "pixel_hash"])
for i, p in enumerate(prompts):
for j, s in enumerate(seeds):
t = time.time(); img = T.generate(pipe, p, s, a.steps); sec = round(time.time() - t, 1)
fn = f"p{i + 1}_s{s}.png"; h = T.save(img, os.path.join(a.out, fn), {"prompt": p, "seed": s, "steps": a.steps, "model": T.MODEL})
w.writerow([fn, p, s, a.steps, sec, h]); cells[(i, j)] = img; print(f"{fn} {sec} 秒")
sheet(cells, prompts, seeds).save(os.path.join(a.out, "sheet.jpg"), quality=88)
print(f"{len(cells)} 张 → {a.out}/sheet.jpg,参数见 {a.out}/runs.csv"); return 0
if __name__ == "__main__":
sys.exit(main())
第 3 步:测试
"""test_sheet_layout 不需要模型;test_small_run 会真实生成 2 张图(约 10 秒)。"""
import csv, os
from PIL import Image
import seed_grid as G
def test_cjk_font_first():
f = G.font(14)
assert "CJK" in getattr(f, "path", "") or "msyh" in getattr(f, "path", "") or "PingFang" in getattr(f, "path", "") or "wqy" in getattr(f, "path", "")
def test_sheet_layout():
cells = {(i, j): Image.new("RGB", (512, 512), (i * 100, j * 100, 0)) for i in range(2) for j in range(3)}
s = G.sheet(cells, ["水彩山村", "teapot"], [1, 2, 3])
assert s.size == (3 * 192, 2 * (192 + 24) + 24)
def test_small_run(tmp_path, capsys):
p = tmp_path / "p.txt"; p.write_text("# 注释\n水彩画:山村\n", encoding="utf-8")
assert G.main([str(p), "--seeds", "5,6", "--out", str(tmp_path / "g")]) == 0
rows = list(csv.DictReader(open(tmp_path / "g" / "runs.csv", encoding="utf-8")))
assert [r["file"] for r in rows] == ["p1_s5.png", "p1_s6.png"] and rows[0]["pixel_hash"] != rows[1]["pixel_hash"]
assert os.path.exists(tmp_path / "g" / "sheet.jpg") and "建议改用英文" in capsys.readouterr().out
第 4 步:运行
$ python seed_grid.py prompts.txt --seeds 1,2,3,4
p1_s1.png 4.6 秒
p1_s2.png 4.8 秒
p1_s3.png 4.3 秒
p1_s4.png 4.3 秒
p2_s1.png 4.1 秒
p2_s2.png 4.2 秒
p2_s3.png 4.1 秒
p2_s4.png 4.0 秒
8 张 → grid/sheet.jpg,参数见 grid/runs.csv

$ python seed_grid.py zh.txt --seeds 1,2 # 第 1 行中文,第 2 行同义英文
提醒:“水彩画:日出时宁静的山村,柔和的光线,薄…”是中文。sd-turbo 的文本编码器(CLIP)主要按英文训练,实测中文提示词的画面与描述明显不符,建议改用英文。
p1_s1.png 5.5 秒
p1_s2.png 4.8 秒
p2_s1.png 4.4 秒
p2_s2.png 4.4 秒
4 张 → zhgrid/sheet.jpg,参数见 zhgrid/runs.csv

$ python -m pytest -q
3 passed
怎么检查结果?
- runs.csv 中每张图都有种子和像素哈希,挑中后用 A 篇以同样参数重新生成,哈希应一致。
- 网格标签中的中文应正常显示。
- 时间:CPU 上每张约 4~5 秒,8 张约 40 秒。
调试示例
1. 中文提示词效果差。 我用同一组种子对比了“水彩画:日出时宁静的山村,柔和的光线,薄雾”和同义的英文提示词。中文版两张都是灰色的雾山,没有村庄,也没有日出的颜色;英文版两张都有村庄和暖色光线(见上图)。只测了 2 个种子,但差别很明显。sd-turbo 的文本编码器以英文为主,所以建议提示词用英文写。
2. 标签变成方块。 第一版字体列表先找 DejaVuSans,它没有汉字,中文提示词的标签显示为一串方块。改为优先使用中文字体(Noto Sans CJK、文泉驿、微软雅黑、苹方),找不到时才用 DejaVu。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 标签是方块 | 系统没有中文字体 | Linux 安装 fonts-noto-cjk |
| 8 张要几分钟 | CPU 太慢或内存不足 | 先用 2 个种子 |
| 想用中文写提示词 | 文本编码器以英文为主 | 先翻译成英文 |
模板规则
- 先用小图挑种子,再出正式图。
- 提示词用英文。
- 记录每张图的参数。
项目资源
| 用途 | 地址 |
|---|---|
| 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 |
多看几个种子,再决定用哪一张。