No ComfyUI, no node graph — just a .py file and the diffusers library. The same models and weights ComfyUI runs, called directly. Everything below works locally on CPU; a GPU only makes it faster.不用 ComfyUI,没有节点图——只要一个 .py 文件和 diffusers 库。和 ComfyUI 跑的是同样的模型与权重,只是直接调用。下面的一切都能在本地 CPU 上运行;GPU 只是让它更快。
ComfyUI looks like magic because it paints a graph of nodes. But under the hood every node is calling Hugging Face diffusers + PyTorch — the same library you can import yourself. A diffusers pipeline is one Python object that bundles every node ComfyUI wires by hand:ComfyUI 看起来很神奇,因为它画出一张节点图。但底层每个节点都在调用 Hugging Face 的 diffusers + PyTorch——也就是你自己可以 import 的那个库。一个 diffusers pipeline 就是一个 Python 对象,把 ComfyUI 手工连接的每个节点都打包在一起:
| ComfyUI nodeComfyUI 节点 | diffusers equivalentdiffusers 中的对应 |
|---|---|
| Load Checkpoint | AutoPipelineForText2Image.from_pretrained(...) |
| CLIP Text Encode (positive / negative) | prompt= / negative_prompt= arguments参数 |
| KSampler | num_inference_steps, guidance_scale, generator |
| VAE Decode | automatic — happens inside the pipeline自动——在 pipeline 内部完成 |
| Save Image | image.save("out.png") |
You need Python 3.10+ and these packages. torch CPU wheels are large but install with one command; no CUDA, no drivers required.你需要 Python 3.10+ 和以下这些包。torch 的 CPU 版本体积较大,但一条命令即可安装;无需 CUDA、无需驱动。
# a clean virtual environment keeps this off your system Python
python -m venv .venv
# Windows: .venv\Scripts\activate · macOS/Linux: source .venv/bin/activate
pip install diffusers transformers accelerate safetensors
pip install torch # CPU build is the default
pip install imageio imageio-ffmpeg pillow # for saving the video file
from_pretrained() downloads weights once and caches them. You never manage .safetensors files by hand like in ComfyUI — diffusers fetches and stores them under:~/.cache/huggingface/hub (macOS/Linux) · C:\Users\<you>\.cache\huggingface\hub (Windows). Delete that folder to free space.from_pretrained() 会只下载一次权重并缓存。你不必像在 ComfyUI 里那样手动管理 .safetensors 文件——diffusers 自动获取并存放在:~/.cache/huggingface/hub(macOS/Linux)· C:\Users\<你>\.cache\huggingface\hub(Windows)。删掉这个目录即可释放空间。
If you'd rather not install torch and the rest, everything above is pre-baked into ddtraveller/diffusers-cpu — CPU-only, multi-arch (Intel + Apple Silicon/ARM). The two tools below, t2i and i2v, are exactly the scripts from sections 2 and 3, already on the image's PATH.如果你不想安装 torch 等一堆依赖,上面这一切都已经打包进 ddtraveller/diffusers-cpu 镜像——纯 CPU、多架构(Intel + Apple Silicon/ARM)。下面的两个工具 t2i 和 i2v 就是第 2、3 节里的脚本,已经放在镜像的 PATH 上。
# 1 — pull it
docker pull ddtraveller/diffusers-cpu
# 2 — make two host folders: one for outputs, one to cache downloaded models
mkdir -p ~/diffusers/work ~/diffusers/cache
# text -> image (first run downloads sd-turbo into the cache, then it's instant)
docker run --rm \
-v ~/diffusers/work:/work \
-v ~/diffusers/cache:/cache \
ddtraveller/diffusers-cpu \
t2i --prompt "misty Doi Suthep temple at dawn, lanna style" --out /work/temple.png
# image -> video (SVD is gated — pass your Hugging Face token)
docker run --rm -e HF_TOKEN=hf_xxx \
-v ~/diffusers/work:/work \
-v ~/diffusers/cache:/cache \
ddtraveller/diffusers-cpu \
i2v --image /work/temple.png --out /work/temple.mp4
Your temple.png / temple.mp4 land in ~/diffusers/work on your host. The /cache mount means models download once and are reused next run. Run docker run --rm ddtraveller/diffusers-cpu t2i --help to see every flag (--model, --steps, --seed, …).生成的 temple.png / temple.mp4 会出现在宿主机的 ~/diffusers/work 里。挂载 /cache 意味着模型只下载一次,下次运行直接复用。运行 docker run --rm ddtraveller/diffusers-cpu t2i --help 可查看所有参数(--model、--steps、--seed……)。
On Windows, replace ~/diffusers/... with a full path and use ${PWD} (PowerShell) or %cd% (cmd) for the current folder.在 Windows 上,把 ~/diffusers/... 换成完整路径,当前目录用 ${PWD}(PowerShell)或 %cd%(cmd)。
Using stabilityai/sd-turbo as the example: it is ungated — no Hugging Face login, no license to accept — and the download is about 2.5 GB. Both methods below write to the same cache, so your script finds the weights either way. You only need one.以 stabilityai/sd-turbo 为例:它是非受限模型——不需要登录 Hugging Face、不需要接受许可——下载约 2.5 GB。下面两种方法写入的是同一个缓存,所以脚本都能找到权重。你只需选其一。
The first time from_pretrained() runs, it fetches the weights and caches them; every run after that loads from disk. This is the whole "download step" — there isn't a separate one.第一次执行 from_pretrained() 时会拉取权重并缓存;之后每次运行都从磁盘加载。这就是全部的“下载步骤”——并没有单独的一步。
# run the t2i.py from section 2 — the download happens on this line, once:
# pipe = AutoPipelineForText2Image.from_pretrained("stabilityai/sd-turbo", ...)
python t2i.py # first run pulls ~2.5 GB into the cache, then a few seconds per image
hf CLI方法 B——用 hf 命令行提前下载Use this to grab the weights ahead of time (offline prep, or to inspect the files). It installs nothing your script doesn't already need.用它可以提前把权重拉下来(离线准备,或想查看文件)。它安装的东西脚本本来也需要。
pip install -U "huggingface_hub[cli]"
# downloads the repo into ~/.cache/huggingface/hub — your script finds it automatically
hf download stabilityai/sd-turbo
# …or put the files in a folder you can see, instead of the hidden cache:
hf download stabilityai/sd-turbo --local-dir ./sd-turbo
# confirm what landed (size + on-disk path):
hf cache scan
hf download is the current command; the older huggingface-cli download still works but is deprecated. No hf auth login is needed for sd-turbo — that step is only for gated models like SVD in section 3.hf download 是现在的命令;旧的 huggingface-cli download 仍可用但已弃用。sd-turbo 不需要 hf auth login——那一步只对第 3 节里 SVD 这类受限模型才需要。
"cpu" on any non-CUDA box. On a Mac, swap in Apple's Metal backend for a big speed-up — set device = "mps" and dtype = torch.float16. With "mps" the variant="fp16" argument also halves the download:第 2 节的脚本在非 CUDA 机器上会退回 "cpu"。在 Mac 上换成 Apple 的 Metal 后端能大幅提速——设 device = "mps"、dtype = torch.float16。配合 "mps" 时,variant="fp16" 还能把下载体积减半:
pipe = AutoPipelineForText2Image.from_pretrained(
"stabilityai/sd-turbo", torch_dtype=torch.float16, variant="fp16",
).to("mps")
Cache location on macOS: ~/.cache/huggingface/hub. Delete that folder (or run hf cache delete) to free the space. To pull only the smaller fp16 weights via the CLI: hf download stabilityai/sd-turbo --include "*.json" "*.txt" "*fp16*".macOS 上的缓存位置:~/.cache/huggingface/hub。删除该目录(或运行 hf cache delete)即可释放空间。只想用命令行拉取较小的 fp16 权重:hf download stabilityai/sd-turbo --include "*.json" "*.txt" "*fp16*"。
The whole program is four lines of real work. We use SD-Turbo: a distilled model that produces a 512×512 image in 1–4 steps (regular Stable Diffusion needs ~25), so it finishes in seconds even on CPU. Turbo models are trained without classifier-free guidance, so set guidance_scale=0.0.真正干活的代码就四行。我们用 SD-Turbo:一个蒸馏模型,1–4 步就能生成 512×512 的图(普通 Stable Diffusion 需要约 25 步),所以即便在 CPU 上也几秒完成。Turbo 模型训练时没有使用 classifier-free guidance,所以要设 guidance_scale=0.0。
# t2i.py — text to image, runs on CPU
import torch
from diffusers import AutoPipelineForText2Image
# pick the best device available; CPU needs float32 (float16 is GPU-only)
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if device == "cuda" else torch.float32
# 1 — Load Checkpoint (downloads + caches on first run)
pipe = AutoPipelineForText2Image.from_pretrained(
"stabilityai/sd-turbo", torch_dtype=dtype,
).to(device)
pipe.enable_attention_slicing() # less RAM on small machines
# 2 — CLIP Text Encode + KSampler + VAE Decode, all in one call
image = pipe(
prompt="misty Doi Suthep temple at dawn, golden light, lanna architecture, highly detailed",
num_inference_steps=4, # sd-turbo: 1 is fastest, 4 is a touch nicer
guidance_scale=0.0, # turbo models: CFG OFF
generator=torch.Generator(device).manual_seed(42), # reproducible
).images[0]
# 3 — Save Image
image.save("temple.png")
print("saved temple.png")
python t2i.py # first run downloads ~2.5 GB, then a few seconds per image on CPU
The only thing that changes between models is the repo name in from_pretrained() and the step/guidance settings. The pipeline class auto-detects the architecture.在不同模型之间,唯一要改的就是 from_pretrained() 里的仓库名,以及步数 / guidance 设置。pipeline 类会自动识别模型结构。
| Model (repo id)模型(仓库 id) | Settings设置 | Use it for适用于 |
|---|---|---|
stabilityai/sd-turbo | 1–4 steps, CFG 0, 512²1–4 步,CFG 0,512² | Fastest — the default above.最快——上面的默认。 |
stabilityai/sdxl-turbo | 1–4 steps, CFG 0, 512–10241–4 步,CFG 0,512–1024 | Higher quality, slower on CPU.质量更高,CPU 上更慢。 |
stable-diffusion-v1-5/stable-diffusion-v1-5 | ~25 steps, CFG 7, 512²约 25 步,CFG 7,512² | The classic SD1.5; needs a negative_prompt.经典 SD1.5;需要 negative_prompt。 |
Hard-coding one prompt is fine for a test, but the real win of a script is running many unattended. Move the two things that change — the description and the output filename — out of the code and into a small prompts.json. Now anyone can add images by editing data, never the Python.写死一个提示词用来测试没问题,但脚本真正的价值是无人值守地批量运行很多个。把会变的两样东西——描述文本和输出文件名——从代码里挪到一个小小的 prompts.json 中。这样谁都能通过改数据来添加图片,而不用碰 Python。
// prompts.json — a list of { description, filename } jobs
[
{ "prompt": "misty Doi Suthep temple at dawn, lanna architecture, highly detailed", "out": "temple.png" },
{ "prompt": "lantern festival on the Ping River at dusk, warm light, reflections", "out": "lanterns.png" },
{ "prompt": "a bowl of khao soi on a wooden table, steam, soft window light", "out": "khaosoi.png" }
]
Then change t2i.py to load that file and loop. Build the pipeline once (the slow part), then reuse it for every job:然后把 t2i.py 改成读取该文件并循环。pipeline 只构建一次(最慢的一步),之后每个任务都复用它:
# t2i.py — read prompts + filenames from prompts.json, generate each
import json, torch
from diffusers import AutoPipelineForText2Image
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if device == "cuda" else torch.float32
# build the pipeline ONCE, outside the loop (loading ~2.5 GB is the slow step)
pipe = AutoPipelineForText2Image.from_pretrained(
"stabilityai/sd-turbo", torch_dtype=dtype,
).to(device)
pipe.enable_attention_slicing()
# load the job list — encoding="utf-8" so Thai / Chinese prompts survive
with open("prompts.json", encoding="utf-8") as f:
jobs = json.load(f)
for job in jobs:
image = pipe(
prompt=job["prompt"], # description ← from JSON
num_inference_steps=4,
guidance_scale=0.0,
generator=torch.Generator(device).manual_seed(42),
).images[0]
image.save(job["out"]) # filename ← from JSON
print("saved", job["out"])
python t2i.py # generates temple.png, lanterns.png, khaosoi.png in one run
prompts.json and run. That file can be hand-written, generated by another program, or come from a spreadsheet export. Add "steps" or "seed" keys per job and read them with job.get("seed", 42) if you want per-image control. This is the leap a UI can't make.代码再也不用改了——你在 prompts.json 里描述想要什么,然后运行即可。这个文件可以手写、可以由另一个程序生成、也可以来自表格导出。如果想对每张图单独控制,给每个任务加 "steps" 或 "seed" 字段,并用 job.get("seed", 42) 读取。这一步是界面无法做到的飞跃。
Same shape, different pipeline. Stable Video Diffusion (SVD) takes one still image and predicts a short clip of motion from it. The base model makes 14 frames; ...-xt makes 25. Feed it the temple.png you just generated.套路一样,换个 pipeline。Stable Video Diffusion(SVD)接收一张静态图,并据此预测一小段运动画面。基础模型生成 14 帧;...-xt 生成 25 帧。把你刚生成的 temple.png 喂给它。
# i2v.py — image to video
import torch
from diffusers import StableVideoDiffusionPipeline
from diffusers.utils import load_image, export_to_video
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if device == "cuda" else torch.float32
pipe = StableVideoDiffusionPipeline.from_pretrained(
"stabilityai/stable-video-diffusion-img2vid", torch_dtype=dtype,
).to(device)
pipe.enable_attention_slicing()
# SVD wants a specific size; resize the still first
image = load_image("temple.png").resize((1024, 576))
frames = pipe(
image,
num_frames=14, # base = 14, the -xt model = 25
decode_chunk_size=2, # lower = less memory (decode fewer frames at once)
generator=torch.Generator(device).manual_seed(42),
).frames[0]
export_to_video(frames, "temple.mp4", fps=7)
print("saved temple.mp4")
num_frames=14 and decode_chunk_size=2.用 turbo 模型做文生图在 CPU 上是几秒。视频则完全不同:SVD 一次要对 14–25 帧去噪,所以在 CPU 上一段短视频可能要 几十分钟到一个多小时。代码是对的、也能跑——只是没有 GPU 就得有耐心。先从 num_frames=14、decode_chunk_size=2 开始。
huggingface-cli login # paste a token from huggingface.co/settings/tokens
On a 16–24 GB machine, two flags do most of the work. They trade a little speed for a lot less peak memory — the difference between "runs" and "killed: out of memory".在 16–24 GB 内存的机器上,两个开关就能解决大部分问题。它们用一点速度换取大幅降低的峰值内存——这正是“能跑”与“被系统杀掉:内存不足”的区别。
| Call调用 | What it does作用 |
|---|---|
pipe.enable_attention_slicing() | Computes attention in chunks — biggest single RAM saver.分块计算注意力——单项最省内存。 |
pipe.enable_vae_slicing() | Decodes the image/frames in slices (helps SVD most).分片解码图像 / 帧(对 SVD 帮助最大)。 |
pipe.enable_model_cpu_offload() | GPU only — keeps idle sub-models on CPU, moving each to GPU just in time. Frees VRAM.仅 GPU——把空闲的子模型留在 CPU,需要时才搬到 GPU。释放显存。 |
num_inference_steps ↓ | Fewer steps = faster. Turbo models are built for this.步数越少越快。Turbo 模型正是为此而生。 |
generator=torch.Generator(device).manual_seed(N) and the same prompt + settings produce the exact same image every run — across machines. This is the part a UI makes fiddly and a script makes trivial.传入固定的 generator=torch.Generator(device).manual_seed(N),相同的提示词和设置每次都会生成完全相同的图——跨机器也一样。这正是界面里麻烦、而脚本里轻而易举的地方。
| Text → image文生图 | Image → video图生视频 | |
|---|---|---|
| Pipeline classPipeline 类 | AutoPipelineForText2Image | StableVideoDiffusionPipeline |
| Default model默认模型 | stabilityai/sd-turbo | stabilityai/stable-video-diffusion-img2vid |
| Input输入 | a text prompt一段文本提示词 | a still image一张静态图 |
| Output输出 | image.save("out.png") | export_to_video(...,"out.mp4") |
| CPU speedCPU 速度 | seconds (turbo)几秒(turbo) | minutes–hours几十分钟–数小时 |
| Gated?是否受限? | No否 | Yes — accept license + login是——需接受许可并登录 |
diffusers pipelines. Learn from_pretrained(...) → pipe(...) → .save() and you can drive all of them from plain Python, locally, with no UI in the way.每一个扩散模型工具——ComfyUI、Automatic1111、网页 demo、还有这个脚本——调用的都是同一小撮 diffusers pipeline。掌握 from_pretrained(...) → pipe(...) → .save(),你就能用纯 Python 在本地驱动它们全部,中间没有任何界面挡路。