照着 Mage-Flow 仓库的命令敲下去,第一张图没跑出来,问题通常不在提示词写得好不好,而在三处对不上:权重文件没下全、依赖版本和仓库声明不一致、显存不够这个规格的最小生成。这三件事的报错长得很像,都表现为进程退出或卡住,所以建议先把它们逐项验证一遍,再谈画质和速度。下面的顺序是:先核对文件,再固定环境,然后用最小脚本跑通一次,最后把命令固化成脚本,避免每次重开终端都重新试错。
跑 Mage-Flow 的第一张图,判断顺序建议是:先确认权重清单与实际目录逐项对得上,再在独立虚拟环境里装依赖并导出实际版本号,最后用低分辨率最小脚本观察显存峰值。三者中任何一步没过,后面的调参都没有意义。适用场景是本地单机首次部署;边界是不同仓库版本、不同显卡驱动下的文件命名和显存表现可能不同,需要结合自己的环境确认,不能照搬别人的数字。
把仓库说明里的权重清单和配置文件逐项对上
先别急着运行。打开仓库说明里列出的文件清单,把它当成一张核对表:主权重文件、分片索引、配置文件、分词器目录、VAE 或其他辅助组件,各自应该落在哪个相对路径下。清单里只记文件名和相对路径,例如 models/ 下放主权重,configs/ 下放推理配置,tokenizers/ 放分词相关文件,具体以仓库说明为准。
然后在仓库根目录生成一份实际文件列表,和清单逐行比对:
find ./models ./configs -maxdepth 2 -type f -printf '%P\n' | sort > actual.txt
cat actual.txt
如果主权重是分片存储的,索引文件里会列出每个分片的文件名,索引文件存在不代表分片齐全。可以先用文本方式打开索引,看列出的文件名数量,再和 ls ./models 的实际数量对比。缺一个分片,加载阶段往往不是报「文件不存在」,而是报解析或键不匹配,很容易被误判成依赖问题。这一步的结论应该是明确的:缺哪几个文件、放在哪个相对路径下,标注出来,补齐后再进入下一步。
在独立虚拟环境里装依赖并记录实际版本号
全局环境里同时装过多个项目的情况很常见,版本互相覆盖之后,报错信息会指向一个你根本没改过的包。建议每个仓库单独一个虚拟环境,把安装结果导出成文件,后续对不上时才有据可查。
cd /path/to/Mage-Flow
python -m venv .venv
source .venv/bin/activate # Windows 下为 .venv\Scripts\activate
python -m pip install -U pip
pip install -r requirements.txt
pip freeze > freeze.txt
接着把 freeze.txt 和仓库声明版本逐行比对。仓库里声明方式可能是 requirements.txt、pyproject.toml 或说明文档里的表格,需要分别确认。常见做法是先把声明行整理成纯版本清单,再和 freeze.txt 的 包名==版本 格式对齐后对比:
# 只做展示,声明文件里的写法需要人工整理成 包名==版本 再比对
sort freeze.txt | grep -i -E 'torch|transformers|diffusers|accelerate|safetensors'
重点看带编译扩展的包,例如 PyTorch 和加速相关库:它们的版本和 CUDA 运行时是绑定的,装错之后报错信息往往不指向版本本身。比对结果记下来,哪个包偏高、哪个偏低,写清楚再决定是改依赖还是换环境,不要直接在全局环境里试 pip install 覆盖。
用最小脚本生成一张低分辨率图并观察显存峰值
这一步的目的只有一个:确认从加载到出图的链路是通的。所以先固定低分辨率,只暴露三个参数,其余全部写死。参数骨架可以是这样,加载部分替换成仓库里实际的调用方式:
# run_one.py
import argparse, torch
def load_pipeline(model_dir):
# 替换成仓库里实际的加载方式,例如 from_pretrained 之类的调用
raise NotImplementedError
def main():
p = argparse.ArgumentParser()
p.add_argument("`--prompt`", required=True)
p.add_argument("`--out`", default="out/first.png")
p.add_argument("`--size`", type=int, nargs=2, default=[512, 512])
a = p.parse_args()
pipe = load_pipeline("./models")
img = pipe(prompt=a.prompt, width=a.size[0], height=a.size[1]).images[0]
img.save(a.out)
print("max_alloc_MB", torch.cuda.max_memory_allocated() // 1024 // 1024)
if __name__ == "__main__":
main()
运行时另开一个终端轮询显存,或者直接在脚本里读 torch.cuda.max_memory_allocated()。前者能看到占用的变化过程,后者给出峰值,两种都留一下:
( while true; do nvidia-smi `--query-gpu`=memory.used `--format`=csv,noheader; sleep 0.5; done ) & MON=$!
python run_one.py `--prompt` "a cat" `--out` out/first.png `--size` 512 512
kill $MON
如果 512 尺寸能出图但显存峰值贴着实卡容量上限,那么后面放大尺寸出现卡死或进程被杀,就是显存问题而不是权重问题,判断方向要改。这一步跑通之前,不建议去调采样步数和画质参数。
按报错关键词判断卡在权重路径还是依赖冲突
把「跑不起来」拆成三类,逐一排除:
- 文件不存在类:出现
FileNotFoundError、No such file or directory、cannot find model之类。检查动作是回到第一节的清单,确认脚本里写的相对路径和实际目录一致,尤其注意当前工作目录。验证命令:ls -l ./models与脚本里传入的路径逐字对比。 - 符号未定义类:出现
undefined symbol、ImportError、DLL load failed、cannot import name。这通常是编译扩展和运行时版本不配套。检查动作是先确认当前激活的是虚拟环境,再对pip freeze里的关键包做版本比对。验证命令:python -c "import torch; print(torch.__version__, torch.version.cuda)"。 - 版本不匹配类:出现
requires ... but you have、incompatible version、参数名不识别等。检查动作是把报错里要求的版本和freeze.txt对上,判断是仓库声明过期还是本地装错。验证命令:pip show 包名看实际安装版本和依赖要求。
三类报错的顺序建议按权重、依赖、版本依次排除,因为路径问题的排查成本最低。如果三类都对不上,再去看显存和驱动,那时候报错一般更直接,例如显存不足或设备初始化失败。
把跑通的命令固化成可重复执行的启动脚本
跑通一次之后,把当时用的参数抽成命令行选项,写成一个脚本,下次不用回忆。骨架如下,放在仓库根目录:
#!/usr/bin/env bash
set -euo pipefail
PROMPT="a cat"
SIZE=512
OUT="out/first.png"
while getopts "p:s:o:" opt; do
case $opt in
p) PROMPT=$OPTARG ;;
s) SIZE=$OPTARG ;;
o) OUT=$OPTARG ;;
*) echo "usage: $0 [-p prompt] [-s size] [-o out]" >&2; exit 2 ;;
esac
done
source .venv/bin/activate
mkdir -p "$(dirname "$OUT")"
python run_one.py `--prompt` "$PROMPT" `--out` "$OUT" `--size` "$SIZE" "$SIZE"
验证方法是固定随机种子后连跑两次,把输出文件做一次哈希对比。种子要写进 run_one.py 里,否则两次结果本来就不一样,比对没有意义:
chmod +x start.sh
./start.sh -p "a cat" -s 512 -o out/a.png
./start.sh -p "a cat" -s 512 -o out/b.png
sha256sum out/a.png out/b.png
两次哈希一致,说明这一组参数在你的机器上是可重复的,后续换尺寸、换提示词出现差异时,才有参照。需要说明的是,不同显卡型号、驱动和库版本下生成结果未必完全一致,哈希比对只适合在同一个环境里做回归,跨机器比哈希没有意义。