(十六)组织一份完整模型版本
models/
├── current.json 保存下次默认加载的版本名
└── v1/
├── weights.pt PyTorch state_dict
├── preprocess.npz x/y 的训练均值与标准差
├── metadata.json 特征顺序、结构、数据摘要与版本
├── metrics.json 验证选中轮数与评估结果
├── history.json 每轮训练和验证损失
├── splits.json 原始数据的三组下标
└── manifest.json 前六个文件各自的 SHA-256
preprocess.npz 回到第十一章的数组文件格式,保存四个具名数组。metadata.json 中的 architecture="linear-2-1" 与 FEATURES 使加载代码能先核对解释方式;CSV 摘要和保存的下标帮助复查实验来源。
# 项目文件:model_project/src/modeldelivery/releases.py
import hashlib
import json
import os
from pathlib import Path
import re
from tempfile import TemporaryDirectory
import numpy as np
import torch
from .data import FEATURES, prepare
from .training import fit
FILES = {
"weights.pt",
"preprocess.npz",
"metadata.json",
"metrics.json",
"history.json",
"splits.json",
}
def version_path(root, version):
if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]{0,63}", version):
raise ValueError("版本名请使用字母数字开头的简短名称")
return Path(root).resolve() / version
def write_json(path, value):
path.write_text(json.dumps(value, ensure_ascii=False, indent=2), encoding="utf-8")
def verify(folder):
# 先检查完整清单,再逐个比较文件字节的摘要。
folder = Path(folder)
manifest = json.loads((folder / "manifest.json").read_text(encoding="utf-8"))
if manifest.get("format") != 1 or set(manifest["files"]) != FILES:
raise ValueError("模型交付目录的文件清单不完整")
for name, expected in manifest["files"].items():
if hashlib.sha256((folder / name).read_bytes()).hexdigest() != expected:
raise ValueError(f"模型文件摘要不一致:{name}")
return manifestverify() 要求清单列出六个配套文件,再逐个计算摘要。复制过程中少了一个文件或某个字节发生变化,装载前就会发现。摘要用于检查文件完整性;模型目录的来源仍由发布和传输过程确定。