模型文件先读头再加载:260 KB 看清 1438 个张量,别让加载器替你全读 16 GiB
safetensors 的文件结构是「8 字节头长度 + 一段 JSON + 权重数据」,JSON 里写明每个张量的名字、形状、精度和字节偏移。所以想查清一个模型到底装了什么、精度是不是它标的那样、值不值得重下,只需要读那一段 JSON,不用碰权重。本机实测:FLUX schnell fp8 单文件 16.05 GiB,头仅 260,000 字节(占 0.0015%),读头 0.96 毫秒,读全量 5.46 秒,比值 5,671 倍;最极端的是 minimax_h3 int8(19.53 GiB,头仅 95,416 字节),比值 16,302 倍。反过来,ComfyUI 0.33.0 的 UNETLoader 走 load_diffusion_model → load_torch_file,用 `for k in f.keys()` 无过滤把整个打包文件全读进内存——FLUX 那 1438 个张量里只有 776 个(model.diffusion_model,11.07 GiB)真正参与建模,另外 418 个 text_encoders(4.67 GiB)与 244 个 vae(319.75 MiB)读进来就被前缀过滤扔了。只读 UNet 段 vs 全量:FLUX 省 36.7%、SDXL 省 27.6%;但 Wan2.2 三个纯 UNet 文件为 3.1% / −2.0% / −1.7%(无收益)——读放大只在「把不相干的东西打进同一个文件」时才发生。
模型文件safetensors文件头ComfyUI加载器读放大精度分布显存FLUXSDXLWan2.2本地部署查重这条适用于
- 模型文件是 safetensors 格式(.safetensors / .sft)
- 能直接读文件(本地磁盘或已下载完成,不是流式)
- 想查的是文件构成/精度分布/是否重复,而不是画质或效果
版本指纹
ComfyUI 0.33.0;D:\models 57 个权重文件;RTX 5090D 32GB / D 盘 NVMe / Windows 11
具体做法
环境:本机 RTX 5090D 32GB / D 盘 NVMe / Windows 11 / ComfyUI 0.33.0,2026-10-21。测量方式:每个文件读头 7 次取中位、读全量 3 次取中位;文件均已在系统页缓存中,故该组数字反映「已缓存后的解析开销」,不是冷盘首读(冷盘会更慢,但比值方向一致)。
【5 个 diffusion_models 文件的头 vs 全量】
· wan2.2_ti2v_5B_fp16|9.31 GiB|头 83,416 B|读头 0.41 ms|全量 3.37 s|7,493×
· wan2.2_t2v_14B_fp8|13.31 GiB|头 180,728 B|0.90 ms|4.61 s|5,104×
· wan2.2_s2v_14B_fp8|15.27 GiB|头 212,232 B|0.99 ms|5.46 s|5,512×
· flux1-schnell-fp8|16.05 GiB|头 260,000 B|0.96 ms|5.46 s|5,671×
· minimax_h3_int8|19.53 GiB|头 95,416 B|0.44 ms|7.17 s|16,302×
· NVMe 顺序读实测 3057 / 3087 / 3106 / 3120 / 3346 MB/s(六次落在 3057–3110 窄带)
【FLUX schnell fp8 内部构成(头直读)】
· model.diffusion_model 11.07 GiB / 776 张量(全 F8_E4M3)
· text_encoders 4.67 GiB / 418 张量(T5 4.44 GiB + clip_l 235.84 MiB)
· vae 319.75 MiB / 244 张量(全 F32)
· 精度分布:995 个 F8_E4M3 = 96.62% 字节;246 个 F32 = 1.95%;197 个 F16 = 1.43%
【只读 UNet 段 vs 全量(省多少)】
· sd_xl_base_1.0:2.31 s → 1.67 s,省 27.6%
· flux1-schnell-fp8:5.46 s → 3.46 s,省 36.7%
· wan2.2_ti2v_5B_fp16:3.37 → 3.27,省 3.1%
· minimax_h3_int8:7.17 → 7.00,省 2.3%
· wan2.2_t2v_14B_fp8:4.61 → 4.70,−2.0%
· wan2.2_s2v_14B_fp8:5.46 → 5.55,−1.7%
【ComfyUI 0.33.0 源码链路】
· nodes.py:982 UNETLoader.load_unet → comfy.sd.load_diffusion_model
· comfy/sd.py:2335 load_diffusion_model → comfy.utils.load_torch_file(unet_path)
· comfy/utils.py:158 load_torch_file → safetensors.safe_open, 无过滤
· 后续 unet_prefix_from_state_dict 按前缀过滤,非 UNet 张量被丢弃
【T5 版本差定位(打包版 vs 独立文件)】
· 打包版 text_encoders.t5xxl 合计 4.44 GiB / 220 张量;独立 t5xxl_fp8_e4m3fn 4.56 GiB / 220 张量,差 125.5 MiB
· 差异不在精度:打包版存 text_encoders.t5xxl.transformer.shared.weight [32128,4096] F8_E4M3 = 131,596,288 B
· 独立文件同时存 shared.weight 与 encoder.embed_tokens.weight,各 131,596,288 B,偏移相差 131,600,384 B(两份独立物理数据)
· ⇒ 打包版把重复词表合并了,反而更省 125.5 MiB
本结论为本机实测(2026-10-21;RTX 5090D / D 盘 NVMe / ComfyUI 0.33.0)。读头与读全量耗时均在文件已进入系统页缓存的条件下测得,代表解析开销而非冷盘首读。只读 UNet 段实验用绝对偏移直接 seek 读取,跳过了非 UNet 张量,因此负收益档位(Wan2.2 三个)的差异来自多次 seek 的额外开销,属测量误差量级,不代表「分开读更慢」的结论。本文只讨论文件结构、读取量与内存占用,不含任何画质或生成质量判断。T5 词表两份是否逐字节相同未做全量比对(1.3 亿字节),故只用「很可能相同」表述。