unet / VAE / 文本编码器的精度参数各管什么
翻别人贴的启动命令,最容易看晕的就是那一长串精度开关:一会儿 --fp16-unet,一会儿 --fp8_e4m3fn-text-enc,再加一个 --force-fp16,看上去像是同一件事说了三遍。其实不是。在 ComfyUI v0.31.0(2026-08-08)的 comfy/cli_args.py 里,这些参数被分在三个彼此独立的互斥组加一个全局组里,各管各的那一块权重。搞混了组,你以为在调 VAE,实际改的是扩散模型;你以为加了个全局开关就万事大吉,结果它顺手改了 unet。
先把组分清楚,再谈调不调。
一、三组互斥参数全表
下面这张表是 v0.31.0 comfy/cli_args.py 里精度相关参数的原始分组和 help 语义。同一组内部互斥,也就是说一组里只能选一个,写两个 argparse 会直接报错。
| 分组 | 参数 | help 原意 |
|---|---|---|
| 全局(互斥) | --force-fp32 | 强制 fp32;help 注明「如果这让你的 GPU 表现更好,请上报」 |
| 全局(互斥) | --force-fp16 | 强制 fp16 |
| 扩散模型 unet(同一互斥组,七选一) | --fp32-unet / --fp64-unet / --bf16-unet / --fp16-unet | 指定扩散模型使用的精度 |
| 扩散模型 unet(同上,同组) | --fp8_e4m3fn-unet / --fp8_e5m2-unet / --fp8_e8m0fnu-unet | 把 unet 权重以该 fp8 格式存储 |
| VAE(同一互斥组,三选一) | --fp16-vae | help 注明 might cause black images |
| VAE(同上,同组) | --fp32-vae / --bf16-vae | 指定 VAE 精度 |
| 文本编码器(同一互斥组,五选一) | --fp8_e4m3fn-text-enc / --fp8_e5m2-text-enc | 文本编码器用该 fp8 格式 |
| 文本编码器(同上,同组) | --fp16-text-enc / --fp32-text-enc / --bf16-text-enc | 文本编码器用该浮点精度 |
| 独立参数 | --cpu-vae | 在 CPU 上跑 VAE |
| 独立参数 | --fp16-intermediates | help 明确标 Experimental:节点之间的中间张量用 fp16 而非 fp32 |
| 独立参数 | --force-channels-last | 推理时强制 channels last 格式 |
| 独立参数 | --supports-fp8-compute | 让 ComfyUI 表现得像设备支持 fp8 计算一样 |
这张表怎么读?先看最左边一列。你要解决的问题落在哪一块,就只动那一块的那一行,别顺手把三组都加上。三组之间没有互斥关系,argparse 不会拦你同时写 --fp16-unet --fp32-vae --fp8_e4m3fn-text-enc——它是合法的,但这意味着一旦出问题,你有三个变量要排除。
二、--force-fp16 不只是「全局」那么简单
全局组只有两个成员,--force-fp32 和 --force-fp16,互斥。名字看着像是「一刀切」,但在源码层面这两个的行为并不对称:--force-fp16 会连带把 fp16_unet 置真。
这条很值得单独记一笔。它意味着当你写 --force-fp16 的时候,你实际上等于同时按下了 unet 组里 --fp16-unet 那一档。所以别再在后面追加 --fp8_e4m3fn-unet 之类的参数,然后困惑「为什么行为跟我想的不一样」——你已经通过全局开关表过态了。
反过来,--force-fp32 的 help 里写着一句很有意思的话:「如果这让你的 GPU 表现更好,请上报」。这句话的潜台词是,官方并不认为 fp32 在多数设备上是更优解,它更像是一个诊断用的兜底档。所以 --force-fp32 的正确用法是临时加上跑一次,看现象消不消失,而不是当成常驻配置写进启动脚本。如果加了它现象真的没了,那你手上就有一条挺硬的线索:问题跟精度有关,接下来才轮到去分组细调,把范围从「全局」收缩到「哪一块权重」。
三、fp8 三个变体:help 说的是「存储」,不是「计算」
unet 组里有三个 fp8 选项:--fp8_e4m3fn-unet、--fp8_e5m2-unet、--fp8_e8m0fnu-unet。文本编码器组里有两个:--fp8_e4m3fn-text-enc、--fp8_e5m2-text-enc。
这里有个特别容易误读的点:这三个 unet fp8 参数的 help 原文说的是「把 unet 权重以该 fp8 格式存储」。存储格式和计算精度是两件事。help 只承诺了权重怎么存,没有承诺矩阵乘法会以 fp8 执行。你看到这几个参数时,不要自动脑补成「开了它就走 fp8 算力」。
至于 e4m3fn、e5m2、e8m0fnu 三者之间该怎么选,cli_args.py 的 help 只是把它们并列列出,既没有给推荐顺序,也没有给适用条件,更没有任何质量损失的量化说明。所以这一点我们不比——谁比谁更好、损失多少,没有依据,不编。你能确定的只有一件事:它们和 --fp32-unet / --fp64-unet / --bf16-unet / --fp16-unet 同属一个 unet 互斥组,七个成员里只能选一个。这也是判断依据本身:当你已经写了 --bf16-unet,就不要再指望追加一个 fp8 选项来「叠加」效果,argparse 那一关就过不去。
与之配套的是那个名字很坦白的参数 --supports-fp8-compute,help 的字面语义是「让 ComfyUI 表现得像设备支持 fp8 计算一样」。注意它的措辞是「表现得像」,也就是假装设备支持,而不是「启用 fp8 计算」。这类参数的定位很清楚:它是给你在软件层面绕过能力探测用的,前提是你自己清楚硬件到底行不行。help 没说设备不支持时会发生什么,我们也就不写会发生什么——但从措辞就该嗅出来,这不是一个「加上准没坏处」的开关。
顺带提一句:--fast 的合法项里有一个 fp8_matrix_mult,而 --fast 的 help 原文注明这些是「未经测试、可能劣化质量」的优化,「用了可能让你的 ComfyUI 崩溃」。fp8 这条线上官方自己的措辞就是这么保守,别把它当成稳定路径来规划。
四、VAE 组:那句 black images 警示到底该怎么读
VAE 组三个成员:--fp16-vae、--fp32-vae、--bf16-vae,互斥。其中 --fp16-vae 的 help 里带了一句警示——might cause black images(可能导致黑图)。
这句话的分量比很多人以为的重。在整个 cli_args.py 的精度部分里,「黑图」这个现象被官方 help 明确挂钩的开关,只有 --fp16-vae 这一个。这给了你一条非常直接的排查依据:
- 如果你的启动命令里有
--fp16-vae,而你正在遇到黑图,第一动作就是把这个参数去掉再跑一次。这是成本最低、指向最明确的一步。 - 如果去掉之后现象消失,结论清楚,别再往别处找。
- 如果你的命令里根本没有
--fp16-vae,那这条线索对你不成立,别硬套。卡里没有给出其它与黑图相关的精度开关,我们也不会替你编一个出来。
另外注意,upcast 那个互斥组里的 --force-upcast-attention(它的搭档是 --dont-upcast-attention,help 写着「除调试外应该没必要」),help 也提了一句「如果它修好了黑图请上报」。但那是另一个互斥组的参数,跟精度这三组不是一回事。真要排查,一次只动一个组的一个参数,否则你根本不知道是谁修好的。
--cpu-vae 是独立参数,不在 VAE 互斥组里。这一点容易看漏。它的语义是「在 CPU 上跑 VAE」,管的是在哪跑,而不是用什么精度跑。所以它可以和精度参数并存,不冲突。判断依据也就清楚了:你要解决的是「VAE 这一步跑不动/挤不进显存」,那是 --cpu-vae 的领域;你要解决的是「VAE 输出不对劲」,才轮到精度组那三个。把这两类问题分开,能省掉一大半瞎试。
五、文本编码器:精度和位置是两条线
文本编码器组五个成员:三个浮点档 --fp16-text-enc / --fp32-text-enc / --bf16-text-enc,两个 fp8 档 --fp8_e4m3fn-text-enc / --fp8_e5m2-text-enc,五选一。
但真正影响文本编码器资源占用的,往往不止精度。显存互斥组里那几个开关的 help 就直接提到了它:--gpu-only 的说法是「所有东西(含文本编码器/CLIP 模型等)都存放并运行在 GPU」;--lowvram 的说法则是「如果启用了 dynamic vram,这个选项不做任何事;在没有用 dynamic vram 时,它让文本编码器跑在 CPU 上」。
这两条摆在一起,判断路径就出来了:文本编码器有「用什么精度」和「跑在哪」两条独立的线,前者归精度组,后者归显存组。而 --lowvram 这条在当前版本还带了个前提——dynamic vram 开着的时候它什么都不做。老教程里那种「显存不够就加 --lowvram」的说法,在 v0.31.0 上已经不能照抄了。想靠它把文本编码器挪到 CPU,你得先确认 dynamic vram 是不是关着的。
所以顺序建议是:先想清楚你要动的是精度还是位置,再去对应的组里挑参数。两条线一起动,出了问题一样没法归因。
六、--fp16-intermediates 与 --force-channels-last
--fp16-intermediates 的 help 里明明白白标着 Experimental,语义是「节点之间的中间张量用 fp16 而非 fp32」。请把这个标签当回事:它不是「稳定但小众」,而是官方自己标注为实验性的东西。放进长期启动脚本之前,你至少该意识到它随时可能变行为、变默认值,甚至消失。
--force-channels-last 是独立参数,语义是「推理时强制 channels last 格式」。help 就这一句,没有给适用条件,也没有给收益说明——那我们也就到此为止,不替官方补充它什么时候该开。
七、把这几组串成一条决策路径
现象驱动,不要参数驱动。落到具体处境:
- 黑图,且命令里有
--fp16-vae→ 先去掉它跑一遍。这是精度这一块里唯一有官方 help 背书的黑图线索。 - 怀疑输出整体不对劲、又不确定是不是精度问题 → 临时加
--force-fp32跑一次做二分。现象消失说明方向对了,再回到三组里逐个收缩;现象不变,说明大概率不在精度这条线上,把这些参数全撤掉,去别处查。 - VAE 这一步资源紧张 → 那是
--cpu-vae的场景,它是独立参数,跟精度组不冲突。 - 想压文本编码器的占用 → 先分清你要改精度(text-enc 组)还是改位置(
--gpu-only/--lowvram,且注意--lowvram在 dynamic vram 开着时不做事)。 - 想上 fp8 → 记住 unet 那三个的 help 说的是存储格式;
--supports-fp8-compute是「假装设备支持」;--fast里的fp8_matrix_mult官方自己标着未经测试、可能劣化质量、可能崩溃。这条路上没有一个开关是官方拍胸脯的。 - 看到 Experimental →
--fp16-intermediates就是。可以试,别常驻。
最后一条同样重要:什么情况说明不是精度参数的问题。如果你的启动命令里一个精度参数都没有,那上面这些开关的 help 语义对你都不成立,加它们不是排查,是引入新变量。同样,如果你把 --force-fp32 加上现象依旧,那也基本可以把精度这一整块从嫌疑名单里划掉,去看模型文件本身、节点连线、显存与加载策略那几组参数。排查的价值不在于试得多,而在于每试一次都能删掉一批可能性。
还有个通用习惯:以上所有参数名和默认行为都以 v0.31.0 的 comfy/cli_args.py 为准。ComfyUI 的迭代节奏很快,参数会增、会改、会带上新的连带效果(--force-fp16 顺手置 fp16_unet 就是个现成例子)。真要确认,跑一次 python main.py --help,看你这个版本上它到底怎么写。
延伸阅读
- ComfyUI 的五个注意力实现参数怎么选,以及 xformers 在里面扮演什么角色
- 读懂 DynamicVRAM:它什么时候会被悄悄关掉
- ComfyUI
--fast的四个优化项,开之前要知道的
本文依据 ComfyUI 官方仓库(github.com/Comfy-Org/ComfyUI)的 README、comfy/cli_args.py、
release notes 与官方安全公告整理,核对日 2026-08-09,对应版本 v0.31.0;
文中引用的 issue 状态为该日期的快照。本文内容为官方文档与源码口径,非本机实测。
参数、默认值与功能随版本变动,请以官方文档与 python main.py --help 的实际输出为准。