- 人工智能
- 大模型
- 媒体生成
- 本地部署
【免费下载链接】ComfyUI
The most powerful and modular diffusion model GUI, api and backend with a graph/nodes interface. The fastest local inference engine in the world.
本篇技术指南以仓库 QUANTIZATION.md 为核心骨架,围绕 ComfyUI 的量化体系展开:先讲清量化的数学原理(per-tensor 绝对最大缩放),再深入到QuantizedTensor派生子类与双级注册表的分发机制,继而剖析MixedPrecisionOps的逐层混合精度策略、量化检查点的 safetensors 存储格式与_quantization_metadata元数据规范,最后给出权重量化与激活量化(PTQ 校准)的完整制作流程。读完你不仅能读懂 ComfyUI 中的量化代码与检查点结构,还能依据本指南制作出兼容 ComfyUI 加载规范的量化检查点。
量化的基本原理:为什么要引入缩放因子
量化(Quantization)的目标是把高精度数值x_f映射到低精度格式,同时把精度损失控制到最小。更小的数据格式一方面显著降低模型的内存占用,另一方面可以借助专用的硬件指令(如 NVIDIA 的 FP8 Tensor Core)提升推理吞吐。
直接使用 round-nearest(四舍五入)把 FP16 数值转成 FP8 会遇到两个典型问题:
- 动态范围不匹配导致截断(clipping):FP16 的动态范围约为 (-65,504, 65,504),而 FP8 的 E4M3 格式只有 (-448, 448),E5M2 格式为 (-57,344, 57,344)。超出低精度格式表示范围的数值会被直接截断,引入大误差。
- 有效位浪费:如果原始数值集中在很小的范围(例如 -1 到 1),直接转换后 FP8 的大部分编码位处于"闲置"状态,精度带宽被浪费。
解决思路是引入缩放因子(scaling factor),把原始数值先缩放进量化 dtype 的完整动态范围,用满整个编码空间。最常用且最简单的方案是per-tensor 绝对最大值(absolute-maximum)缩放:
absmax = max(abs(tensor)) scale = absmax / max_dynamic_range_low_precision # 量化 tensor_q = (tensor / scale).to(low_precision_dtype) # 反量化 tensor_dq = tensor_q.to(fp16) * scale # tensor_dq ≈ tensor由于量化后的数值必须结合缩放因子才能"还原"含义,这类带附加元数据的数据类型在 ComfyUI 中被称作派生数据类型(derived datatypes)。
ComfyUI 中的量化架构总览
ComfyUI 的量化运行时是一条清晰的分发流水线,见 comfy/quant_ops.py 与 comfy/ops.py:
QuantizedTensor (torch.Tensor subclass) ↓ __torch_dispatch__ Two-Level Registry (generic + layout handlers) ↓ MixedPrecisionOps + Metadata Detection整体流程是:QuantizedTensor作为torch.Tensor的派生子类承载量化数据,通过__torch_dispatch__拦截算子调用;两级注册表(通用注册表 + 布局专属注册表)决定每个算子走哪条实现路径;最终由MixedPrecisionOps与量化元数据检测驱动逐层混合精度的加载与执行。
表示层:QuantizedTensor 与 Layout
为了表示派生数据类型,ComfyUI 使用torch.Tensor的子类QuantizedTensor。从源码结构看,comfy/quant_ops.py在成功导入comfy_kitchen时直接复用其后端实现,导入失败时则提供占位类并输出日志fp8 and fp4 support will not be available(comfy/quant_ops.py),说明 FP8/FP4 支持是可选依赖。
Layout 类定义了某种量化格式的完整行为契约(QUANTIZATION.md):
- 必需参数(Required parameters)
- 量化方法(Quantize)
- 反量化方法(De-Quantize)
自定义一个布局的模板如下:
from comfy.quant_ops import QuantizedLayout class MyLayout(QuantizedLayout): @classmethod def quantize(cls, tensor, **kwargs): # Convert to quantized format qdata = ... params = {'scale': ..., 'orig_dtype': tensor.dtype} return qdata, params @staticmethod def dequantize(qdata, scale, orig_dtype, **kwargs): return qdata.to(orig_dtype) * scale在 comfy/quant_ops.py 中可以找到几个真实布局类:
TensorCoreFP8E4M3Layout/TensorCoreFP8E5M2Layout:继承_TensorCoreFP8LayoutBase,分别以torch.float8_e4m3fn/torch.float8_e5m2存储,支持scale="recalculate"动态重算缩放、随机舍入(stochastic rounding)与就地操作;其中 E4M3 布局通过TensorCoreFP8Layout = TensorCoreFP8E4M3Layout保留向后兼容别名。TensorCoreNVFP4Layout:以uint8容器存储 NVFP4 数据,要求 2D 张量,内部还会做 16 的倍数维度 padding,并额外携带block_scale。TensorCoreMXFP8Layout:MXFP8 块级缩放格式(需要较新版本的comfy_kitchen,且仅支持 2D 张量,按 32 对齐 padding)。TensorWiseINT8Layout、TensorCoreConvRotW4A4Layout、AsymW4A8Int8Layout:INT8 系列布局,分别对应逐张量 INT8、W4A4 旋转、非对称 W4A8 等量化方案。
分发层:双级注册表与torch_dispatch
要让这些QuantizedTensor真正参与运算,ComfyUI 使用了两级注册表来定义支持的操作(QUANTIZATION.md):
- 通用注册表(generic registry):处理所有量化格式共有的操作,例如
.to()、.clone()、.reshape()。 - 布局专属注册表(layout-specific registry):允许为特定布局注册快速路径,例如
nn.Linear的专用核。
from comfy.quant_ops import register_layout_op @register_layout_op(torch.ops.aten.linear.default, MyLayout) def my_linear(func, args, kwargs): # Extract tensors, call optimized kernel ...当torch.nn.functional.linear()收到QuantizedTensor参数时,__torch_dispatch__会自动路由到已注册的实现。对于任何未注册的操作,QuantizedTensor会回退到先dequantize、再以高精度实现分发——这正是"正确性兜底"的设计:没有快速路径的算子永远不会算错,只会慢一些。
此外,comfy/quant_ops.py底部维护了一张QUANT_ALGOS注册表(comfy/quant_ops.py),它把检查点元数据中的人类可读格式字符串映射到具体布局类、存储 dtype 和所需参数:
| 格式字符串 | 存储 dtype | 所需参数 | 布局类 |
|---|---|---|---|
float8_e4m3fn | torch.float8_e4m3fn | weight_scale,input_scale | TensorCoreFP8E4M3Layout |
float8_e5m2 | torch.float8_e5m2 | weight_scale,input_scale | TensorCoreFP8E5M2Layout |
nvfp4 | torch.uint8 | weight_scale,weight_scale_2,input_scale,pre_quant_scale(group_size=16) | TensorCoreNVFP4Layout |
mxfp8(需 comfy_kitchen 支持) | torch.float8_e4m3fn | weight_scale,input_scale(group_size=32) | TensorCoreMXFP8Layout |
int8_tensorwise | torch.int8 | weight_scale(不量化输入) | TensorWiseINT8Layout |
convrot_w4a4 | torch.int8 | weight_scale(不量化输入) | TensorCoreConvRotW4A4Layout |
asym_w4a8_int8 | torch.int8 | weight_scale(不量化输入) | AsymW4A8Int8Layout |
创建兼容检查点时,格式字符串必须能在QUANT_ALGOS中找到对应定义。
混合精度:MixedPrecisionOps 逐层量化决策
MixedPrecisionOps类(源码中位于 comfy/ops.py,文档描述的行号 542-648 对应旧版本)实现了逐层量化决策:同一个模型的不同层可以使用不同精度。它由模型配置中的layer_quant_config(实际源码中为quant_config)字典激活——该字典指定哪些层需要量化、用什么格式量化。
架构骨架:
class MixedPrecisionOps(disable_weight_init): _layer_quant_config = {} # Maps layer names to quantization configs _compute_dtype = torch.bfloat16 # Default compute / dequantize precision核心机制:
自定义的Linear._load_from_state_dict()在模型加载阶段逐层检查(comfy/ops.py):
- 若层名不在量化配置中:以普通张量按
_compute_dtype加载权重; - 若层名在量化配置中:把权重加载为
QuantizedTensor,使用指定布局(如TensorCoreFP8Layout),同时加载对应的量化参数(scales、block_size 等)。
与之配套,forward()在推理时还会根据pre_quant_scale对输入做 AWQ 风格平滑(smoothing),把高维输入 reshape 成 2D 再量化,并在输出后恢复原始维度;对于input_scale场景,输入激活也会被量化为QuantizedTensor(comfy/ops.py)。
为什么需要它:
并非所有层都能承受同等程度的量化。最终投影等敏感操作可以保持高精度,而计算密集的 matmul 层则量化到 FP8/INT8。这样既拿到大部分性能收益,又守住生成质量。
选择时机:
该模式在pick_operations()中被选中:当model_config.quant_config存在时,它作为最高优先级的操作模式启用(comfy/ops.py)。quant_config的来源是模型加载时的自动检测——comfy/model_detection.py 调用comfy.utils.detect_layer_quantization(state_dict, unet_key_prefix)扫描 state_dict,一旦发现量化层就把结果写入model_config.quant_config。文本编码器与音频模型也复用同一机制,例如 comfy/sd1_clip.py 从model_options["quantization_metadata"]取出配置后调用mixed_precision_ops(quant_config, dtype, full_precision_mm=True)。
量化检查点格式
量化检查点与普通模型一样存储为标准 safetensors 文件,但包含量化权重张量、关联的缩放参数,以及一段描述量化方案的_quantization_metadataJSON 元数据。
与原始检查点相比,量化检查点具有以下特点:
- 权重以量化值存储,有时使用不同的存储 dtype——例如 FP8 用
uint8容器承载(nvfp4即torch.uint8,见QUANT_ALGOS); - 每个量化权重旁边会按配方(recipe)存储若干额外的缩放参数;
- 最终 safetensors 的元数据中写入
_quantization_metadata,说明哪些层被量化、使用了什么布局。
缩放参数细节
标准定义了 4 种缩放参数,覆盖近期绝大多数配方(QUANTIZATION.md):
- weight_scale:权重的量化缩放因子
- weight_scale_2:双重缩放(double scaling)语境下的全局缩放因子
- pre_quant_scale:用于平滑突出权重(salient weights)的缩放因子
- input_scale:激活值的量化缩放因子
对应关系如下:
| 格式 | 存储 dtype | weight_scale | weight_scale_2 | pre_quant_scale | input_scale |
|---|---|---|---|---|---|
| float8_e4m3fn | float32 | float32(标量) | - | - | float32(标量) |
所有已定义格式的完整参数集合可在 comfy/quant_ops.py 的QUANT_ALGOS中查到。
量化元数据(_quantization_metadata)
与检查点一同存储的元数据包含:
- format_version:字符串,定义该标准规范的版本;
- layers:字典,把层名映射到其量化格式。格式字符串与
QUANT_ALGOS中的定义一一对应。
示例:
{ "_quantization_metadata": { "format_version": "1.0", "layers": { "model.layers.0.mlp.up_proj": {"format": "float8_e4m3fn"}, "model.layers.0.mlp.down_proj": {"format": "float8_e4m3fn"}, "model.layers.1.mlp.up_proj": {"format": "float8_e4m3fn"} } } }创建量化检查点
创建兼容检查点的通用要求:使用任何量化工具均可,但输出必须符合上述检查点格式规范,且布局必须定义在QUANT_ALGOS中。
扩散模型注意力偏好(Attention Preferences)
扩散注意力模块可以携带一个<module path>.comfy_attention.config条目,其内容为 uint8 张量包裹的 UTF-8 JSON:
{"attention": "comfy_kitchen_int8"}应用在真正执行注意力的模块上,例如 Qwen Image 2.1 的transformer_blocks.0.attn,或 MiniMax H3 的blocks.0.attn。需要注意的边界行为:
- 目前仅支持
comfy_kitchen_int8;无效目标与其他方法名在加载时会被忽略并给出警告,退回正常的注意力选择; - Kitchen INT8 支持度在每条偏好加载时按主设备检查,不支持的设备保持正常注意力选择;
- 显式的注意力覆盖(explicit attention overrides)优先级更高;
ComfyAttention子模块通过常规的 state-dict 加载/保存机制自行读写元数据;- 注意力偏好不启用权重量化;文本编码器与 VAE 加载器不应用这些偏好。
权重量化(Weight Quantization)
权重量化比较直接——用前文提到的绝对最大值方法,直接从权重张量计算缩放因子。每个层的权重独立量化,并与对应的weight_scale参数一同存储。
校准:激活量化(Calibration for Activation Quantization)
激活量化(例如 FP8 Tensor Core 运算所需的input_scale)无法只凭静态权重确定,因为激活值取决于真实输入。因此需要训练后量化校准(post-training calibration,PTQ):
- 收集统计量:在 N 个代表性样本上运行推理;
- 追踪激活:记录每个被量化层输入的绝对最大值(
amax); - 计算缩放:由收集的统计量推导
input_scale; - 写入检查点:把
input_scale参数与权重一同保存。
校准数据集必须能代表目标使用场景——对扩散模型而言,通常意味着覆盖多样的提示词与生成参数组合。
运行前提与限制
- FP8/FP4 快速路径依赖可选依赖
comfy_kitchen;未安装时 ComfyUI 会降级处理并提示fp8 and fp4 support will not be available(comfy/quant_ops.py)。 - CUDA 优化算子要求 PyTorch cu130 及以上;低于该版本时
ck.registry.disable("cuda")会被调用并输出升级警告(comfy/quant_ops.py)。AMD(HIP)与 NVIDIA(CUDA)后端在导入时自动选择,Triton 后端默认关闭、可用--enable-triton-backend等命令行参数显式启用。 pick_operations()的完整选择顺序是:存在quant_config时优先使用混合精度 ops → 支持 FP8 计算且开启 FP8 优化时使用fp8_ops→ 满足条件时使用cublas_ops→ 权重 dtype 与计算 dtype 一致时使用disable_weight_init→ 否则回退manual_cast(comfy/ops.py)。
小结
ComfyUI 的量化体系由三层构成:原理层(per-tensor 绝对最大缩放)、表示与分发层(QuantizedTensor+ Layout + 双级注册表 +__torch_dispatch__)、以及加载决策层(MixedPrecisionOps+_quantization_metadata自动检测)。量化检查点以标准 safetensors 承载量化权重与 4 类缩放参数,通过_quantization_metadata描述逐层格式。制作兼容检查点时,权重量化简单直接,而涉及激活量化的方案必须走 PTQ 校准流程;运行侧则要满足comfy_kitchen与 PyTorch 版本等前提条件。这套设计让"大部分层量化、敏感层保精度"的混合精度策略成为可能,是 ComfyUI 在保持出图质量的同时压榨推理性能的关键机制。
- 人工智能
- 大模型
- 媒体生成
- 本地部署
【免费下载链接】ComfyUI
The most powerful and modular diffusion model GUI, api and backend with a graph/nodes interface. The fastest local inference engine in the world.
相关推荐
Vue-Pure-Admin精简版入门指南:快速搭建企业级后台管理系统
Vue Pure Admin精简版入门指南:快速搭建企业级后台管理系统 Vue Pure Admin精简版是一个基于Vue3、TypeScript、Elemen
前端UI组件企业应用Stable Diffusion模型量化:INT8量化与推理加速全指南
Stable Diffusion模型量化:INT8量化与推理加速全指南 引言:量化技术解决AI绘画算力瓶颈 你是否曾因GPU内存不足而无法生成高分辨率图像?是否
计算机视觉媒体生成深度学习基础模型MXNet 模型量化(INT8)完全指南:mxnet.contrib.quantization 模块从原理到实战
MXNet 模型量化(INT8)完全指南:mxnet.contrib.quantization 模块从原理到实战 导读 本文聚焦 MXNet 官方文档 cont
人工智能深度学习机器学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考