如果 AI 模型是一座远洋货轮,那 Safetensors 就是一套现代化的“集装箱码头规则”。传统 pickle 格式像一只会在开箱时自动弹跳的玩具盒:你还没看清里面是什么,它已经执行了一段代码,可能是正常权重,也可能是恶意程序。Safetensors 则把船分成三块:船头一块 8 字节的“长度牌”、驾驶舱里一张人类可读的 JSON 舱单、货舱里一整片连续排列的二进制货物。要卸下某个张量,不需要翻遍所有货箱,只要看一眼舱单上的偏移坐标,吊机就直奔目标。这种“先读清单,再取货”的设计,让模型加载既安全又快速。格式规范 Format Spec 要回答的正是:这三块区域如何拼接、每个字段代表什么、为什么这样设计能成为跨框架的通用语言。

岗位关联

对 AI 从业者而言,掌握 Safetensors 格式规范,等于拿到理解现代模型存储与推理加载的一把钥匙:你会在部署、调优、跨框架迁移时,准确知道一个权重文件“为什么能这么快被读取”。

目录
  1. 可视化演示
  2. 文件整体布局
  3. 头部长度字段
  4. JSON 元信息
  5. 张量数据区
  6. 偏移量索引
  7. 安全加载机制
  8. 跨框架生态
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

演示Safetensors文件头与数据区的组织方式:文件头以JSON存储张量元信息,数据区按偏移量连续排列二进制张量数据。

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

文件头 + 数据区 文件头:JSON元信息(张量名、dtype、shape、偏移量) 数据区:连续二进制张量数据,按偏移量定位 offset+dtype+shape 解析时依据偏移量零拷贝加载张量

文件整体布局

把 Safetensors 文件想象成一艘集装箱货轮。船最前端钉着一块小小的电子牌,写着“本船舱单共有多长”;紧接着是驾驶舱里的纸质舱单,记录每个集装箱的名字、尺寸和货位;最后才是真正的货舱,里面整整齐齐地码着所有集装箱。Safetensors 的格式规范,就是这一整套“造船标准”:三块区域按顺序出现,任何解析器只要按标准施工,就能读懂这艘船。

在技术层面,一个 Safetensors 文件是连续的一段字节流。文件前 8 个字节保存一个整数,它表示 JSON 头部的字节长度;接下来是 JSON 格式的头部,记录张量的元信息;再往后就是二进制数据区,所有张量的原始数据一个接一个排列。解析器不需要“猜”,因为长度前缀把头部边界画得清清楚楚。

这个设计的精妙之处在于可读性与效率的平衡:JSON 头部是人类和工具都能读的“说明书”,而数据区是机器最喜欢的高密度二进制。两者之间不需要复杂的容器包装,也没有层层嵌套的对象结构。于是,文件既能被快速校验,也能被内存映射到进程地址空间,按需访问。

只要记住“长度牌 + 舱单 + 货物”的三段式布局,Safetensors 就不再是黑盒。你拿到任意一个文件,都可以像熟练的港口调度员一样,先量长度,再看舱单,最后精准卸货。

File=8 bytes⏟length prefix+Lheader⏟JSON header+Databinary⏟tensor bytes\displaystyle \text{File} =\underbrace{8\text{ bytes}}_{\text{length prefix}}+\underbrace{L_{\text{header}}}_{\text{JSON header}}+\underbrace{\text{Data}_{\text{binary}}}_{\text{tensor bytes}}
这个公式说明文件是一块连续字节流:先有固定 8 字节的“长度牌”,再有可读的 JSON 舱单,最后是真正的货物。
  1. 固定 8 字节文件开头先读 8 个字节,这是后续所有解析的起点。
    8 bytes\displaystyle 8 \text{ bytes}
  2. 头部长度这 8 个字节解码后得到 $L_{\text{header}}$,告诉我们要读多长 JSON。
    Lheader\displaystyle L_{\text{header}}
  3. 二进制数据JSON 之后剩下的所有字节都是张量数据,它们没有被转成文本。
    Databinary\displaystyle \text{Data}_{\text{binary}}

头部长度字段

一艘船停进港口,起重机操作员第一件事是看船头那块电子牌。电子牌不写货物内容,只写“舱单有多长”。没有它,操作员就不知道从哪里开始读舱单,也不知道舱单在哪里结束。Safetensors 文件的前 8 个字节,就是这块电子牌。

这 8 个字节按小端序保存一个无符号 64 位整数。小端序可以理解为“低位放在前面”:就像我们读数字时从个位开始。解析器用统一的规则把这 8 个字节还原成整数,这个整数就是 JSON 头部的字节数。头部在写入时还会做 8 字节对齐:如果 JSON 文本长度不是 8 的倍数,就在末尾补空格,让整个头部长度凑成 8 的倍数。这样数据区就能对齐到 8 字节边界,更适合底层硬件读取。

有了这个字段,读取器可以算出数据区起点:8 + 头部长度。它不需要扫描整个文件,也不需要尝试解析“可能很长”的头部,而是读一个整数、跳转一次、直接进入舱单。这个简单的 8 字节前缀,是整份格式规范最不起眼却最关键的“门把手”。

这块电子牌虽然只有巴掌大,却决定了整船货物能否高效卸运。一个 AI 工程师在加载模型时,可能不会直接看见这 8 个字节,但它就是所有快速加载魔法开始的地方。

Lheader=LE_U64(bytes[0:8])\displaystyle L_{\text{header}} = \text{LE\_U64}(\text{bytes}[0:8])
头部长度字段不是模型参数,而是“券”:它告诉加载器 JSON 舱单从第 8 字节开始,总共占多少字节。
  1. 读取前 8 字节使用 bytes[0:8] 取出文件最开始的 8 个字节。
    bytes[0:8]\displaystyle \text{bytes}[0:8]
  2. 按小端解码LE_U64 表示按小端序解码成 64 位整数。
    LE_U64\displaystyle \text{LE\_U64}
  3. 得到头部长度解码结果就是 JSON 头部的字节数。
    Lheader\displaystyle L_{\text{header}}

JSON 元信息

现在,操作员走进驾驶舱,翻开舱单。舱单不是天书,而是白纸黑字的 JSON:每个集装箱的编号就是张量名,旁边标注着“货种”“尺寸”和“货位”。JSON 是互联网世界最通用的“白纸黑字”,人眼能读,程序能解析,几乎不需要专门定制复杂的二进制解释器。

Safetensors 的 JSON 头部正是这样一个对象。它支持一个保留字段 __metadata__ 存放文件级说明;其余每个键都是一个张量名,对应的值描述这个张量:dtype 表示数据类型,比如 F32、BF16、I64;shape 表示张量形状,比如 [4, 8];data_offsets 表示这个张量的数据在数据区中的起止位置。头部可能还会带有少量空格填充,目的就是让头部长度对齐到 8 字节。

由于头部是 JSON,任何框架都可以用现成的 JSON 解析器打开它,而不必为“私有二进制元数据”单独写一套工具。这也让恶意文件更容易被人工检查:平台可以在加载数据前先审计头部,看看是否有可疑字段。用一个比喻说,舱单越透明,海关越放心。

JSON 元信息让 Safetensors 文件“透明可见”。即使你从未加载过某个模型,只要打开头部,就可以像读货运舱单一样,知道船上有哪些张量、各自多大、放在哪。这种透明性,是传统 pickle 格式给不了的。

header[t]={dtype, shape, data_offsets:[b,e]}\displaystyle \text{header}[t] = \{\text{dtype},\ \text{shape},\ \text{data\_offsets}:[b,e]\}
对任意张量名 $t$,头部里都能找到一条记录,相当于舱单上的一个条目。
  1. 张量名作为键header[t] 表示以张量名为索引去查舱单。
    header[t]\displaystyle \text{header}[t]
  2. 三个核心字段dtype 告诉解析器数字类型,shape 告诉它维度。
    dtype, shape\displaystyle \text{dtype},\ \text{shape}
  3. 起止偏移data_offsets:[b,e] 表示数据区中从 b 到 e 的字节区间。
    data_offsets:[b,e]\displaystyle \text{data\_offsets}:[b,e]

张量数据区

舱单看完,真正的重头戏是货舱。货舱里没有包装盒,没有绳子,只有集装箱按顺序一个接一个紧密排列。Safetensors 的数据区也是这样:所有张量的原始二进制字节,按它们在头部出现的顺序连续拼接,中间没有分隔符、没有索引表、没有压缩流。

为什么要把数据区做得这么“朴素”?因为机器最喜欢的格式就是连续字节。连续可以内存映射:加载器把文件映射到内存后,数据区变成一段连续地址,张量可以直接复用这些字节,不需要额外拷贝。连续也可以随机定位:给定偏移区间,seek 到目标位置后一次性读出。它不存字符串、不存对象图,更不存可执行代码,因此反序列化时无需运行任何业务逻辑。

与常见的 Zip 或 pickle 不同,Safetensors 不做主动压缩。它追求的是“零拷贝”和“极速加载”,而不是把文件压到最小。对大型模型来说,推理时的加载时间往往比磁盘节省的那几 MB 更重要。数据区保持原始二进制,等于货舱里的集装箱本身已经是最适合搬运的状态。

这种“货物一个挨一个”的设计,可能让文件看起来不够花哨,但恰恰是效率的核心。真正专业的码头,往往不需要华丽的分拣系统,只需要一条笔直的传送带。

data region=tensor1 ∥ tensor2 ∥ … ∥ tensorn\displaystyle \text{data region} = \text{tensor}_1 \,\|\, \text{tensor}_2 \,\|\, \dots \,\|\, \text{tensor}_n
这里用 $\|$ 表示“拼接”:第 1 个张量的字节后面紧跟着第 2 个张量,依次排完。
  1. 张量序列tensor_1, tensor_2, ..., tensor_n 表示所有张量按顺序排列。
    tensor1,tensor2,…,tensorn\displaystyle \text{tensor}_1, \text{tensor}_2, \dots, \text{tensor}_n
  2. 拼接符号$\|$ 表示把前一段字节末尾与后一段开头直接相连。
     ∥ \displaystyle \,\|\,
  3. 数据区整体整个表达式代表数据区就是若干段字节的连续合成。
    data region\displaystyle \text{data region}

偏移量索引

舱单上每个条目都写着“第几排第几列”,吊机司机一眼就能定位。如果舱单只写“货物在船上”,司机就得翻遍全船。Safetensors 的 data_offsets 就是这种精确坐标:它给每个张量写清“从数据区起点算起,从第几个字节开始,到第几个字节结束”。

需要特别注意的是,data_offsets 不是相对文件开头的绝对地址,而是相对数据区起点的偏移。因此,要定位某个张量在文件中的真实位置,必须先算 8 + header_length 作为数据区起点,再加上这个相对偏移。这个设计让头部与数据区解耦:无论头部以后如何改动,数据区内部的坐标体系不会变。

有了偏移索引,读取器就能实现“随机读取”。比如一个文件里有 100 个张量,推理时只需要其中 2 个,加载器就不必读完整份文件。它可以计算目标张量的文件位置,精确地 seek 过去,只读取需要的字节。这就是大模型快速冷启动的基础之一。

有了这套索引,加载器就像拥有 GPS 的吊机,不需要绕路。AI 从业者在写高性能推理代码时,最惦记的往往就是这组坐标:它决定了一个权重文件能否被“按需读取”。

position(t)=(8+Lheader)+data_offsets[t][0]\displaystyle \text{position}(t) = (8 + L_{\text{header}}) + \text{data\_offsets}[t][0]
公式意思是:想找到张量 $t$,先走到数据区起点,再按舱单坐标向前走对应距离。
  1. 数据区起点8 + L_header 是文件头部之后、数据区开始的位置。
    8+Lheader\displaystyle 8 + L_{\text{header}}
  2. 张量偏移data_offsets[t][0] 是从数据区起点到张量起点的字节数。
    data_offsets[t][0]\displaystyle \text{data\_offsets}[t][0]
  3. 两点相加两者相加,就得到张量 $t$ 在文件中的绝对字节位置。
    position(t)\displaystyle \text{position}(t)

安全加载机制

传统 pickle 格式像一只“会自动爆炸的快递箱”:你只要 load 它,它就可能执行一段隐藏代码,可能是正常对象,也可能是恶意指令。这正是 AI 社区长期担心的供应链风险。Safetensors 的回应很朴素:我们只运集装箱,不接受“会自己动的箱子”。

Safetensors 的加载过程本质上只做三件事:读头部长度、解析 JSON、按偏移读取二进制。这三步都不需要执行文件里的代码。头部如果被篡改,解析器会在构建张量前发现异常;数据区里的字节无论是什么,都只是被当作普通数字处理。因此恶意代码没有“被触发”的机会。它不加密,不校验文件来源,而是从根上移除了“执行任意代码”这个危险入口。

这种设计也让平台可以做更细的防护。现代推理框架常使用 safe_open 结合内存映射打开文件,先查头部,再按需读取具体张量。无论是 Hugging Face Hub 的下载校验,还是企业内部模型仓库的扫描,都可以在加载前检查 JSON 舱单,而不用信任数据区的任何“行为”。

没有公式能描述“安全”,但你可以这样理解:pickle 是一封会自动朗读的信,Safetensors 是一箱沉默的货物。它不朗读,不执行,不表态;它只是安静地等待程序用明确的方式读取。这艘船最值钱的不是导航系统,而是它从不搭载“自动执行器”。

跨框架生态

当同一套集装箱标准被全世界港口接受,船就能在任意码头靠岸。Safetensors 从诞生起就绑定开源生态,而不是某一个深度学习框架的私有密码。它由 Hugging Face 推动,迅速被 PyTorch、JAX、Flax 等主流工具支持,成为模型仓库中最常见的权重格式之一。

在 AI 工程链路上,Safetensors 常常扮演“通用语言”:PyTorch 训练出的权重,导出成 Safetensors 后,可以被 JAX 推理服务读取;Hugging Face Hub 上的开源模型,也大量使用 Safetensors 作为默认权重格式。这种互操作能力,让模型不再被“框架锁死”,也让部署系统只需要实现一份格式解析器,就能服务来自不同训练框架的模型。

跨框架的背后,是格式规范本身的克制。它不保存特定框架的对象结构,不依赖 Python 运行时,不绑定 GPU 厂商,只保存最底层的“张量名 + 类型 + 形状 + 偏移 + 原始字节”。这种最小化设计,恰恰换来了最大化兼容。就像集装箱不关心里面装的是玩具还是机床,只关心尺寸合规,于是全世界港口都愿意为它改造设备。

对 AI 从业者来说,理解 Safetensors 格式规范,不只是读懂一个文件头,更是看懂现代模型交付的通用底座。当你把模型从训练环境搬到推理集群,或者在 Hub 上发布开源权重时,Safetensors 就是那张让所有港口都认的通行证。它用最简单的三段式布局,把安全、速度与开放同时装进了同一艘船。

AI 应用场景

Hugging Face 模型仓库托管

阶段:模型存储与发布

解决的问题:过去使用 pickle 序列化权重,用户下载后 load 时可能执行恶意代码;同时 pickle 难以跨框架复用。Safetensors 将权重保存为“长度前缀 + JSON 头部 + 二进制数据”的标准格式,平台可以安全审计头部,用户下载后可直接读取张量,极大降低供应链攻击风险。

具体案例:工程师把微调后的模型上传到 Hugging Face Hub,选择 Safetensors 格式发布。平台在文件卡片上展示张量名、dtype 和 shape,其他用户用一行 from_pretrained 就能安全加载。下载时也不必担心本地执行未知代码。

LLM 推理服务快速冷启动

阶段:模型部署与推理优化

解决的问题:大型语言模型动辄几十 GB,传统加载方式需要把全部权重读入内存,冷启动慢且浪费带宽。Safetensors 的 data_offsets 支持随机访问,配合 mmap 可只读取当前推理请求需要的张量,或按需加载部分层。

具体案例:一个 70B 参数的推理服务,收到首个请求时,并不一次性读入全部 140GB 权重,而是通过 mmap 映射文件,按数据区偏移加载当前层权重。头部 JSON 提供完整索引,框架无需扫描整个文件即可定位。

跨框架模型转换管道

阶段:模型转换与互操作

解决的问题:团队使用 PyTorch 训练,但生产环境使用 JAX/Flax 或 TensorRT 推理,不同框架的 checkpoint 格式互不兼容。Safetensors 作为中立的通用格式,把权重从训练框架中解耦,转换时只需重新读取元信息,不需要反序列化框架专用对象。

具体案例:算法团队训练完模型后导出为 Safetensors,推理团队在同一份文件上执行 JAX 加载,配合 data_offsets 高效读取各层参数。整个管道不再出现 pickle,跨团队协作更加顺畅。

Python 演示

python50 行
import jsonimport struct  def write_safetensors_like(path, tensors):    header = {}    data = bytearray()     for name, (dtype, shape, raw) in tensors.items():        begin = len(data)        data.extend(raw)        end = len(data)        header[name] = {            "dtype": dtype,            "shape": shape,            "data_offsets": [begin, end],        }     header_bytes = json.dumps(header, separators=(",", ":")).encode("utf-8")    while len(header_bytes) % 8 != 0:        header_bytes += b" "     with open(path, "wb") as f:        f.write(struct.pack("<Q", len(header_bytes)))        f.write(header_bytes)        f.write(data)  def read_safetensors_like(path, tensor_name):    with open(path, "rb") as f:        header_len = struct.unpack("<Q", f.read(8))[0]        header_bytes = f.read(header_len)     header = json.loads(header_bytes)    begin, end = header[tensor_name]["data_offsets"]     with open(path, "rb") as f:        f.seek(8 + header_len + begin)        return f.read(end - begin)  if __name__ == "__main__":    fake_tensors = {        "embedding": ("F32", [4, 8], bytes(range(128))),        "weight": ("F16", [2, 3], bytes(range(12))),    }    path = "demo.safetensors"    write_safetensors_like(path, fake_tensors)    blob = read_safetensors_like(path, "embedding")    print("tensor bytes:", len(blob), "prefix:", list(blob[:4]))
目的:用纯 Python 实现一个简化版 Safetensors 写入与读取器,演示“8 字节长度前缀 + JSON 头部 + 二进制数据区”的格式核心。
  1. header[name] = {...}为每个张量记录 dtype、shape 和数据区起止偏移,相当于写舱单。
  2. json.dumps(header, separators=(",", ":"))把头部压缩成紧凑 JSON,节省空间且保持可读。
  3. while len(header_bytes) % 8 != 0给 JSON 头部补空格,使其长度对齐到 8 字节。
  4. struct.pack("<Q", len(header_bytes))用 8 字节小端整数写出头部长度,这是文件的第一块“长度牌”。
  5. f.seek(8 + header_len + begin)从数据区起点再加相对偏移,精确跳转到目标张量。
  6. return f.read(end - begin)只读取该张量的字节区间,而不是读完整份文件。

常见误区

误区我以为 Safetensors 和 Zip 一样,会把模型文件压缩变小,所以选它就是为了省硬盘空间。

正解Safetensors 的核心目标是安全、快速、可随机读取,而不是压缩。它的数据区是原始二进制连续排列,不做压缩算法处理。文件体积通常与原始权重大小相当,省空间只是副产品,真正红利是加载速度和安全性。

为何常见:人们看到“二进制数据区”会自然联想到压缩,再加上 AI 模型文件通常很大,容易误以为格式会主动压紧数据。

误区既然头部是 JSON,那 Safetensors 文件应该就是一个大文本文件,任何部分都能直接读出来。

正解只有最前面的 JSON 头部是人类可读的元信息;头部长度的 8 字节是二进制整数;真正的张量数据区是一堆按 dtype 编码的原始字节,在文本编辑器里几乎是乱码。JSON 只负责“说明”,不负责“承载”数据。

为何常见:教程里总强调“头部是 JSON”,学习者容易把“文件的一部分可读”放大成“整个文件可读”。

误区我以为 Safetensors 加载安全,是因为文件被加密或加了数字签名,所以别人改不了。

正解Safetensors 不是加密格式,也不默认提供签名。它的安全来自加载过程不执行文件中的任意代码:解析器只读长度、解析 JSON、按偏移取字节,没有“反序列化时执行对象”这一步。恶意代码没有执行入口,自然不会“跑起来”。

为何常见:“安全”这个词太宽泛,很多人把它等同于加密、防篡改,忽略了 Safetensors 真正防的是 pickle 式的代码注入。

误区我看到 `data_offsets` 里的数字,觉得它就是张量在文件里的绝对位置,直接拿去做 `seek`。

正解data_offsets 是相对数据区起点的偏移。要得到文件中的真实位置,必须先加上 8 + header_length。这样设计让头部长度即使变化,数据区的内部坐标仍然稳定,也方便加载器统一处理数据区。

为何常见:许多格式的数据索引都直接给绝对偏移,人们用惯性思维套用到 Safetensors,忽略了它前面还有 8 字节长度前缀和 JSON 头部。

面试题

Q1. Safetensors 文件开头 8 字节的含义是什么?

单选题 · easy

  • A.JSON 头部总长度← 正确答案
  • B.文件内张量总数
  • C.数据区最大字节数
  • D.写入时的压缩级别

答案:A。开头 8 字节保存小端序无符号整数,表示 JSON 头部的字节长度。它帮助解析器确定头部边界和数据区起点。张量总数要从 JSON 里数,压缩级别更是与格式无关。

Q2. 为什么头部选择 JSON 格式?

单选题 · easy

  • A.人可读且实现简单← 正确答案
  • B.能压缩所有张量
  • C.可以加载任意代码
  • D.不需要偏移量字段

答案:A。JSON 是人类可读、工具易解析的标准文本格式,适合做元信息清单。它能压缩张量数据和能加载代码都不是 JSON 的特点;偏移量字段仍然保存在 JSON 中。

Q3. data_offsets 中 [begin, end] 表示什么?

单选题 · easy

  • A.张量数据的起止区间← 正确答案
  • B.张量名称的字符编号
  • C.JSON 头部的分页范围
  • D.文件的创建时间范围

答案:A。[begin, end] 表示该张量的原始字节在数据区中的起止位置。它不是字符编号、头部范围或时间信息,而是定位张量的核心坐标。

Q4. 数据区偏移量以什么为基准?

单选题 · mid

  • A.数据区的起始位置← 正确答案
  • B.文件开头的第 0 字节
  • C.上一个张量的末尾
  • D.JSON 中间某个字段

答案:A。data_offsets 是相对数据区起点的偏移,不是文件绝对地址。计算文件真实位置要加上 8 + header_length,即先跳过长度前缀和 JSON 头部,再进入数据区坐标体系。

Q5. Safetensors 比 pickle 更安全的关键原因是?

单选题 · easy

  • A.加载时不会执行任意代码← 正确答案
  • B.所有内容都经过 AES 加密
  • C.文件头部是纯二进制格式
  • D.数据区只保存文本参数

答案:A。Safetensors 只解析 JSON 头部和读取二进制数据,不执行文件内的代码;pickle 反序列化时会实例化对象,可能触发恶意代码。Safetensors 不是加密格式,数据也不是文本。

Q6. 大模型推理服务优先用 mmap 读取 Safetensors,核心收益是?

单选题 · mid

  • A.按需映射,避免一次读入全部权重← 正确答案
  • B.文件会被自动压缩成更小尺寸
  • C.不需要 JSON 头部参与解析
  • D.数据类型会自动变成更低精度

答案:A。内存映射让操作系统按页懒加载,配合 data_offsets 可以只读取目标张量,减少冷启动开销。mmap 不压缩文件,也不改变数据类型,解析头部仍然是定位张量的前提。

Q7. 下列关于头部填充的说法正确的是?

单选题 · mid

  • A.JSON 头部尾部补齐到 8 字节倍数← 正确答案
  • B.每个张量之间必须补 1024 字节
  • C.文件开头还要保存一份冗余副本
  • D.数据区必须以十六进制文本存放

答案:A。Safetensors 会为 JSON 头部补充空格,使头部长度对齐到 8 字节,便于数据区对齐。张量之间没有强制补位,文件开头也没有冗余副本,数据区仍是二进制。

Q8. 在 JSON 头部的张量描述中,通常会包含哪些信息?

多选题 · mid

  • A.dtype 与 shape← 正确答案
  • B.data_offsets 区间← 正确答案
  • C.张量名称作为键← 正确答案
  • D.模型作者与版本号

答案:ABC。每个张量条目以张量名作为键,值中包含 dtype、shape 和 data_offsets。模型作者与版本号通常属于文件级 __metadata__,不是张量描述的必要字段。

Q9. 下列哪些数据类型是 Safetensors 规范支持的?

多选题 · hard

  • A.F32 与 BF16← 正确答案
  • B.I64 与 F8_E4M3← 正确答案
  • C.STRING 与 UUID
  • D.PICKLE 与 EXE

答案:AB。Safetensors 只描述数值型张量,包括 F32、BF16、I64、F8_E4M3 等。STRING、UUID、PICKLE、EXE 都不是张量的原生数据类型,Safetensors 也不用于打包可执行对象。

Q10. 关于 Safetensors 文件结构,以下说法正确的有?

多选题 · extreme

  • A.文件包含 8 字节长度前缀与 JSON 头部← 正确答案
  • B.data_offsets 是相对数据区起点的区间← 正确答案
  • C.读取任意张量前必须读完整个数据区
  • D.数据区按张量原始字节顺序连续拼接← 正确答案

答案:ABD。Safetensors 由长度前缀、JSON 头部和连续数据区组成;偏移量相对数据区起点;读取单个张量时只需按偏移读取对应区间,不需要读完整个数据区。因此 C 错误,A、B、D 正确。