广告位 · 页头(后台-模块管理-新建模块后替换此区域)

如何用SD WebUI将.ckpt模型安全转换为.safetensors格式?

把.ckpt模型文件直接交给Stable Diffusion WebUI加载,本质上等于让一个可能包含任意代码的文件进入你的机器。.ckpt格式基于PyTorch的pickle序列化机制,反序列化时有机会执行隐藏的函数,而.safetensors只存储张量数据,不携带额外的可执行逻辑。因此,把已有模型从.ckpt转换成.safetensors格式,是降低加载风险、同时保证模型能够继续使用的重要操作。本文围绕SD WebUI环境展开,说明单文件转换、批量转换以及结果验证的完整流程。

如何用SD WebUI将.ckpt模型安全转换为.safetensors格式?

一、.ckpt的安全风险与.safetensors的加载差异

PyTorch在保存模型权重时,长期使用torch.save将对象序列化到磁盘。这个序列化过程依赖Python的pickle模块,pickle允许在反序列化时调用类的__reduce__、__setstate__等魔术方法。也就是说,如果模型文件在保存前被塞入了恶意对象,加载时这些方法会被执行,轻则弹窗,重则下载木马、修改系统文件。公开下载的.ckpt模型文件可能来自不可信渠道,格式本身又不提供任何防篡改校验,因此加载行为等同于运行一段未知代码。

safetensors则针对这一设计做了釜底抽薪式的改变。它只保存张量数值和元信息,文件头是一个JSON对象,之后是连续存储的张量数据。加载时不会恢复Python对象,也不会执行任何自定义逻辑。这意味着即使文件来自来路不明的作者,最坏情况也只是得到一组无效权重,无法直接攻击你的系统。对经常下载社区模型的用户来说,转换成.safetensors可以明显缩小风险面。

当然,转换过程本身仍然需要读取一次.ckpt。如果你无法确认模型来源,建议先在隔离环境或虚拟机中执行转换,确认文件头正常后再移动到正式模型目录。日常使用中,把这个转换环节当作下载后的必做清理步骤,能够长期降低维护成本。

二、在SD WebUI中转换单个.ckpt模型

SD WebUI的模型管理一直处于快速迭代中。部分版本的Checkpoint Merger页面提供了输出格式选项,你可以选择同一个模型作为A和B,将插值权重调整为0,输出格式选择.safetensors,再填一个新的模型名称。这样保存出的文件就是目标格式。不过,不同版本的界面差异较大,有些旧版合并器固定输出.ckpt,这时就需要转到命令行或其他扩展来处理。

更通用的做法是直接调用Python脚本。安装好torch和safetensors两个库后,以下脚本可以把单个模型从.ckpt转为.safetensors。它先通过torch.load读取权重字典,再使用save_file写出新文件。代码中的map_location="cpu"可以避免显存不足的问题,转换过程不会占用过多GPU资源。

import torch
from safetensors.torch import save_file
def convert_ckpt_to_safetensors(ckpt_path, output_path):
    model = torch.load(ckpt_path, map_location="cpu")
    if isinstance(model, dict) and "state_dict" in model:
        model = model["state_dict"]
    save_file(model, output_path)
    print(f"converted {ckpt_path} to {output_path}")
convert_ckpt_to_safetensors(
    "models/Stable-diffusion/example.ckpt",
    "models/Stable-diffusion/example.safetensors"
)

执行前请把路径改成你自己的模型实际位置。如果模型目录在SD WebUI安装目录下,通常位于models/Stable-diffusion。转换完成后不要立刻删除源文件,先在WebUI中加载新模型做一次生成测试,确认权重没有丢失。

三、批量转换与文件头验证

当模型库里有十几个甚至几十个.ckpt文件时,逐个手动转换非常低效。可以用一个简单的循环脚本遍历目录,自动转换所有匹配的模型文件。为了保证后续维护方便,代码里只转换不删除,转换结束后你确认文件都在,再手动清理原始.ckpt。

import os
import glob
import torch
from safetensors.torch import save_file
model_dir = "models/Stable-diffusion"
for ckpt in glob.glob(os.path.join(model_dir, "*.ckpt")):
    data = torch.load(ckpt, map_location="cpu")
    if "state_dict" in data:
        data = data["state_dict"]
    output = ckpt.replace(".ckpt", ".safetensors")
    save_file(data, output)
    print(f"done: {output}")

除了转换,还可以通过读取safetensors文件头来验证文件是否完整。safetensors的前8个字节记录了头部JSON的长度,解析出来可以看到文件中包含的张量名称和形状。下面的脚本会输出头部键值,如果能够正常打印,说明文件结构基本正确。

import json
import struct
def read_safetensors_header(path):
    with open(path, "rb") as f:
        length_bytes = f.read(8)
        header_len = struct.unpack("<Q", length_bytes)[0]
        header = json.loads(f.read(header_len).decode("utf-8"))
    return header
header = read_safetensors_header("models/Stable-diffusion/example.safetensors")
print(header.keys())

另一种更直观的验证方式是在WebUI的模型下拉菜单中重新加载转换后的模型。如果终端日志没有报出加载错误,并且生成一张图的时间、质量与转换前一致,就可以认为转换成功。对比时注意保持采样器、步数、种子等参数完全一致,避免其他变量干扰判断。

四、转换后的清理与常见问题

转换完成后,建议把原始.ckpt文件移动到备份目录或直接删除。不要把两种格式的同名模型都留在models/Stable-diffusion里,因为WebUI会同时扫到两个条目,列表变长之外,还容易选错版本。清理前务必确认.safetensors文件大小合理,通常与.ckpt相差不超过几十MB,如果缩小到只有几KB,说明转换过程中可能只保存了空字典。

常见问题之一是torch.load报内存不足。大模型在CPU上加载时可能占用大量RAM,解决方法是把map_location保持为"cpu",并关闭其他占用内存的程序。另一个问题是旧版safetensors库不支持某些张量类型,此时升级到最新版本即可。转换后的.safetensors文件可以继续参与模型融合、LoRA训练等操作,不需要额外修改流程。

长期来看,把默认模型格式统一到.safetensors,能让你在下载社区模型时更加从容。即使某天不小心加载了一个来路不明的文件,风险也被限制在数据解析层,而不会直接威胁系统。配合WebUI自身的启动日志检查,整个模型管理链路会清晰很多。

广告位 · 文章底部(后台-模块管理替换此区域)