把模型权重传到云端 Mac 后,加载失败不一定是统一内存不足。下载中断、分片混入另一版本、索引指向旧文件,都可能让实验停在第一步。先用不加载张量的检查排除文件问题,再运行 MLX,能避免反复下载或盲目调整推理参数。
先固定一份权重目录
在 OsxNode 上验收时,将一次实验使用的权重、配置与索引放进独立的 weights 目录,不要覆盖正在运行的模型。准备 Python 3,另把检查脚本保存在目录外。本文仅检查 safetensors 权重,不执行模型附带的代码。
记录模型修订标识、量化配置、下载来源与文件列表;这些信息应来自实际取得的版本,不能只记一个容易变化的模型名称。下载器退出后再开始检查,避免把尚在写入的分片当成损坏文件。
文件结构合法、传输内容一致、模型能够推理,是三个不同的验收结果。任何一个通过,都不能替另外两个盖章。
用文件头检查偏移和索引
safetensors 前八字节是小端无符号整数,表示 JSON 文件头的字节长度。张量的 data_offsets 相对于文件头之后的数据区,而非文件开头。把两种位置混用,会将正常分片误报为越界。
下面脚本检查数据区是否连续覆盖、张量名是否跨分片重复,以及索引映射是否与实际文件一致。保存为 verify_weights.py。其中 16MiB 文件头上限是本地验收策略,不是格式上限;遇到合法的大头部,应核对来源后再调整。
import json
import struct
import sys
from pathlib import Path
def require(ok, message):
if not ok:
raise ValueError(message)
def unique_object(pairs):
result = {}
for key, value in pairs:
require(key not in result, f"Duplicate JSON key: {key}")
result[key] = value
return result
def read_json(raw):
return json.loads(raw, object_pairs_hook=unique_object)
def verify(root):
require(root.is_dir(), "Missing model directory")
files = sorted(root.glob("*.safetensors"))
require(bool(files), "No safetensors files")
actual = {}
for path in files:
require(not path.is_symlink(), "Symlink shard rejected")
size = path.stat().st_size
with path.open("rb") as stream:
raw = stream.read(8)
require(len(raw) == 8, f"Short prefix: {path.name}")
length = struct.unpack("<Q", raw)[0]
require(
0 < length <= min(16 * 1024 * 1024, size - 8),
f"Invalid header length: {path.name}"
)
header = read_json(stream.read(length))
require(isinstance(header, dict), "Header must be an object")
data_size = size - 8 - length
ranges = []
for name, info in header.items():
if name == "__metadata__":
continue
require(isinstance(info, dict), f"Invalid tensor: {name}")
offsets = info.get("data_offsets")
require(
isinstance(offsets, list) and len(offsets) == 2
and all(type(v) is int for v in offsets),
f"Invalid offsets: {name}"
)
start, end = offsets
require(0 <= start <= end <= data_size,
f"Out of bounds: {name}")
require(name not in actual, f"Duplicate tensor: {name}")
actual[name] = path.name
ranges.append((start, end))
cursor = 0
for start, end in sorted(ranges):
require(start == cursor, f"Gap or overlap: {path.name}")
cursor = end
require(cursor == data_size, f"Trailing data: {path.name}")
index = root / "model.safetensors.index.json"
if index.exists():
document = read_json(index.read_text(encoding="utf-8"))
mapping = document.get("weight_map")
require(isinstance(mapping, dict), "Missing weight_map")
require(mapping == actual, "Shard index mismatch")
else:
require(len(files) == 1, "Multiple shards require an index")
print(f"PASS: {len(files)} files, {len(actual)} tensors")
try:
require(len(sys.argv) == 2, "Usage: verify_weights.py DIRECTORY")
verify(Path(sys.argv[1]))
except Exception as error:
print(f"FAIL: {error}", file=sys.stderr)
sys.exit(1)
运行 python3 verify_weights.py weights,退出码为零才继续。脚本约定使用标准索引文件名、分片位于目录顶层;其他布局需要显式适配,不要直接删除索引绕过检查。
用源端哈希验收传输
结构检查读不到张量内部的数值损坏。应在可信源端、文件写入完成之后生成清单,再将同一批文件和清单传到目标机器。以下命令均在权重目录内执行:
shasum -a 256 ./*.safetensors ./config.json > SHA256SUMS
如果存在分片索引,也把它加入清单:
shasum -a 256 ./model.safetensors.index.json >> SHA256SUMS
目标机器进入对应目录,执行:
shasum -a 256 -c SHA256SUMS
所有列出的文件都应返回 OK。清单本身必须通过可信渠道取得;攻击者若能同时替换文件和清单,哈希不能提供来源认证。源端已经损坏的权重也会原样通过传输核对,因此还要保留结构检查。
按失败类型处理而非全部重下
出现 Short prefix 或文件头长度异常,先确认下载进程已退出,再核对该分片的字节数。不要手工补齐文件,也不要把下载错误页改名成权重。
出现 Shard index mismatch,逐项比较索引中的文件名与目录清单。常见原因是复制时漏掉分片,或保留了旧版本文件。先隔离多余文件并重跑检查;不要修改索引去迎合一组来源不明的权重。
结构通过但哈希失败时,只重新取得失败文件,随后重跑整套检查。若传输工具支持续传,应先确认远端源文件没有更换版本,否则旧文件前半段和新文件后半段可能被拼到一起。
哈希通过而加载失败时,才转向模型架构、量化配置、运行库版本与内存压力排查。这个顺序把文件故障与运行环境故障分开,不需要凭异常文案猜原因。
把检查放进实验入口
脚本没有校验 dtype、shape 与张量字节数的数学关系,也不判断量化参数是否配套。最后仍需使用固定版本的 MLX 环境执行一次模型加载,并用固定输入完成短输出测试;仅验证文件头不能替代这一步。
实验记录至少保留修订标识、哈希清单、脚本退出码、运行库版本和首次加载结果。不要只保存一张成功截图,否则下一次目录变动后很难解释差异。
将结构检查和哈希核对串到实验脚本前面,任一步失败就停止后续任务。更换模型修订时使用新目录、重新生成基线;租期结束前带走清单和检查记录。这样,下一台机器接手的是可核对的实验输入,而不只是一个叫作“下载完成”的文件夹。
常见问题
结构校验通过,是否说明模型一定能推理?
不能。脚本只检查文件布局和分片索引,不验证张量数值、模型架构或量化配置;仍需使用匹配的运行环境完成模型加载与固定输入测试。
文件传输后才生成 SHA-256 清单还有用吗?
可用作此后的变更基线,但不能证明本次传输正确。应在可信源端生成清单,通过可信渠道取得清单,再在目标机器核对。
按实验时长租用 Mac
独享 Mac mini M4,16GB 统一内存 / 256GB SSD。按天、周、月、季预付,到期不续即停机。模型与运行环境由用户自行准备,实际可用状态以控制台实时返回为准。
按天租用 Mac