先看结论与判断条件
- 只要模型字节、权重精度、图结构、算子集合或关联文件发生变化,就应生成新的产物标识,而不是继续使用原始模型版本号。
- 模型身份必须覆盖主文件和 tokenizer、标签、归一化参数、词表等关联文件,单独校验主模型摘要会留下混搭空间。
- 格式兼容、运行时可装载、算子受支持和业务输出可接受属于不同证据,不能用一次启动成功合并结论。
- 输出容差应由具体任务、数据集、决策后果和设备路径定义,不存在适用于所有量化模型的统一数值。
- provenance 与 attestation 可绑定量化构建声明和产物摘要,但仍要验证签名者、转换参数、材料与当前候选的对应关系。
- 更新门禁要识别回滚、冻结和主模型与元数据混搭,并把发布决定绑定到完整模型包和移动应用候选身份。
量化完成后,模型已经成为另一件交付物
原始模型与量化模型可能共享业务名称和训练来源,但它们的交付字节、权重表示、计算路径和运行时要求并不相同。量化过程可能改变权重精度,也可能插入或转换算子、附加比例参数、调整输入输出约束。若继续沿用原模型的文件名和版本结论,测试人员很难确认报告对应哪一份真实文件。
独立产物身份至少包含稳定 artifactId、主文件 SHA-256、格式、量化方法、权重与激活精度、图或算子摘要、元数据摘要、关联文件集合、目标运行时和生成时间。业务模型版本可以作为 lineage 字段保留,说明量化产物源自哪个原模型,但不能替代当前字节身份。任何重新转换、重新打包或关联文件变化都应产生新记录。
身份与功能标签也要分离。同一个“离线识别模型”可能有原始精度、动态量化、全整数量化或面向特定设备的多个变体。客户端选择逻辑需要依据明确的格式、设备能力和策略,而不是猜文件名。工程判断是让每个变体拥有唯一主 URL 或包内路径及清单,再由发布配置声明哪些变体进入某个候选。
| 字段 | 原始模型 | 量化模型 | 不能共用的原因 |
|---|---|---|---|
| 文件摘要 | 绑定训练导出字节 | 绑定转换后字节 | 内容已经不同 |
| 数值表示 | 原始权重与激活精度 | 量化精度与比例参数 | 计算语义可能变化 |
| 算子集合 | 原始图需求 | 转换后的算子需求 | 运行时支持可能不同 |
| 输出基线 | 原始验证结果 | 量化后单独对照 | 输出不能假定完全等价 |
| 运行时清单 | 导出格式和版本 | 格式、后端与设备约束 | 装载路径可能不同 |
身份清单要覆盖结构、精度、格式和输出边界
只记录模型文件摘要能确认字节,却不能帮助团队理解它如何生成和在哪里运行。清单应明确模型格式、导出工具、量化策略、输入输出张量描述、权重与激活精度、是否存在校准材料、目标运行时和算子要求。对于图结构可稳定序列化的格式,可以保存图摘要;无法稳定序列化时,则保存转换配置和算子清单摘要。
输出容差属于身份的验收侧属性。量化会引入数值差异,但差异是否可接受取决于任务。例如排序、分类、生成和安全决策对误差的后果不同,数据分布也会影响结果。项目应保存评测数据版本、指标定义、基线模型身份、量化模型身份和放行理由。没有项目证据时只能标记输出待验证,不能声称两者等价。
产物身份还要区分预期兼容与已验证兼容。清单声明某运行时版本、执行提供程序或设备类别,表示构建目标;只有同一摘要产物在指定环境完成装载和业务回归,才能记录运行证据。把“格式受支持”写成“当前模型已通过”会跨越证据边界,尤其当模型含自定义算子或设备特定后端时。
| 维度 | 清单内容 | 核验方式 | 缺失时的结论 |
|---|---|---|---|
| 字节身份 | 主文件和关联文件摘要 | 对候选文件重新计算 | 无法确认报告对应物 |
| 转换身份 | 工具、参数、材料和量化策略 | 核对构建证明与配置 | 无法解释产物来源 |
| 语义身份 | 输入输出、标签和预处理 | 比对元数据与调用代码 | 无法确认接口一致 |
| 运行身份 | 格式、算子和目标运行时 | 静态检查加设备验证 | 只能记录目标未验证 |
| 验收身份 | 数据集、指标和输出容差 | 同基线独立评测 | 不能声明量化等价 |
尺寸优化是交付取舍,不是身份或安全证明
Reduce Core ML app size 说明模型交付可以在应用包体、下载、本地存储和精度之间做取舍。量化、压缩或把模型从应用包拆到下载流程,都会改变交付结构。团队因此需要分别记录应用内置模型、首次下载模型和更新后模型的身份,不能用应用版本号推断设备当前实际使用的模型。
模型更小不代表来源更可信、内容更完整或资产更保密。尺寸优化文档解决交付问题,不提供模型签名、授权或防回滚结论。工程上应把大小字段作为运营和设备预算输入,把摘要、签名、provenance 和更新元数据作为供应链输入,把运行测试和输出评测作为功能输入。三类记录可以相互引用,但不能互相替代。
拆分下载还会产生应用与模型版本组合。一个客户端版本可能接受多个模型版本,一个模型版本也可能被多个客户端使用。兼容矩阵应显式列出 app candidate、model artifact、runtime、schema 和关联文件包,发布回执绑定具体组合。若下载失败后会回退到内置模型,回退目标也必须有独立身份和仍在允许窗口内的版本策略。
| 交付方式 | 设备上的真实对象 | 主要风险 | 必须保存 |
|---|---|---|---|
| 应用内置 | 随候选包交付的模型 | 应用更新才能替换 | 应用摘要与模型摘要映射 |
| 首次下载 | 安装后获取的模型包 | 下载与首次使用错配 | 目标版本、签名和完成回执 |
| 后台更新 | 运行中替换模型 | 冻结、回滚或部分更新 | 旧新身份与原子切换记录 |
| 设备选择 | 按能力选择不同变体 | 选错格式或后端 | 选择条件与实际产物 |
| 失败回退 | 更新失败使用旧模型 | 退回已撤销版本 | 允许回退列表和触发原因 |
LiteRT 元数据和关联文件必须进入同一身份包
LiteRT model metadata 说明模型元数据可以描述输入输出、归一化参数、标签以及关联文件。移动端推理常依赖 tokenizer、词表、标签映射、预处理配置或后处理阈值。主模型字节不变时,任一关联文件变化都可能改变最终业务输出,因此身份清单应把这些文件作为完整模型包的一部分逐项计算摘要。
元数据既服务调用方,也可能参与自动生成绑定或界面说明。验收应记录元数据格式版本、输入输出张量名称与类型、归一化参数、标签语言和关联文件路径,并确认应用代码实际读取的是这份元数据。只有文件存在并不代表它被运行时采用,只有调用代码写了参数也不代表与模型声明一致,两边需要对照。
混搭是最容易被忽略的失败方式。客户端下载新主模型但保留旧 tokenizer,或者更新标签却未更新模型,会形成每个单文件都合法、组合却错误的状态。工程判断是为完整文件集合生成 packageDigest,并在激活前验证清单中的全部成员。更新流程要么原子切换整个目录,要么使用内容寻址路径,避免逐文件覆盖产生中间状态。
| 对象 | 可能承载 | 变化影响 | 验收动作 |
|---|---|---|---|
| 主模型 | 图、权重和量化参数 | 计算路径与输出变化 | 计算摘要并核对格式 |
| Tokenizer 或词表 | 分词规则与标识映射 | 输入序列改变 | 绑定版本和文件摘要 |
| 标签文件 | 类别到文案的映射 | 展示或决策含义改变 | 核对语言、顺序和摘要 |
| 预处理配置 | 尺寸、归一化和颜色顺序 | 输入分布改变 | 与元数据和代码对照 |
| 后处理配置 | 解码、过滤和业务映射 | 最终输出解释改变 | 纳入 packageDigest 与回归 |
ONNX Runtime Mobile 的可装载性要绑定算子与后端
ONNX Runtime Mobile 面向 Android 和 iOS 装载 ONNX 模型,同时受到模型使用的算子、移动包体和执行提供程序约束。量化转换可能改变算子类型或引入特定内核需求,因此模型格式同为 ONNX 也不能保证每个移动运行时构建都可执行。身份清单应保存 opset、实际算子集合、目标运行时版本和执行提供程序。
运行时裁剪会让兼容关系更具体。为了控制包体,应用可能只包含模型所需算子;模型更新后若出现新算子,旧运行时包可能无法装载。反过来,运行时升级也可能改变执行路径。可执行的门禁是从当前模型生成算子清单,与应用候选内运行时能力对照,再在目标设备上完成装载和关键输入回归。
运行时支持不提供模型签名、授权或防回滚能力。它回答怎样执行模型,而不是模型是否来自允许来源或是否仍在发布窗口。工程判断是把 runtime compatibility、artifact authenticity 和 business acceptance 分成三列。某一列通过时只写对应结论,避免一次推理成功被扩展成来源、完整性和业务质量全部通过。
| 检查项 | 静态输入 | 运行证据 | 边界 |
|---|---|---|---|
| 模型格式 | 文件头与格式版本 | 运行时实际解析 | 格式正确不等于算子齐全 |
| opset 与算子 | 图扫描和转换报告 | 装载与关键路径执行 | 单次执行不覆盖全部分支 |
| 执行提供程序 | 候选配置与设备能力 | 实际后端选择日志 | 选择成功不证明输出可接受 |
| 运行时版本 | 应用依赖与二进制摘要 | 同候选设备回归 | 版本声明不证明打包正确 |
| 输出容差 | 基线身份和评测定义 | 同数据集对照结果 | 项目结果不能外推到其他模型 |
用 provenance 和 attestation 记录量化转换血缘
SLSA Provenance v1.1 提供把产物 subject 与 builder、buildType、外部参数和依赖材料关联的结构。量化流水线可以把量化模型摘要作为 subject,把原始模型、校准材料摘要、转换脚本和运行环境作为 materials 或构建输入,并记录不含敏感数据的转换参数。这样评审者可以确认产物由哪条流程生成。
in-toto Attestation Statement v1 使用 subject 摘要与 predicateType、predicate 绑定有类型声明。量化评测、算子扫描和兼容矩阵都可以形成独立声明,并引用同一 artifact digest。格式化绑定能降低报告拿错候选的风险,但声明内容仍要由可信签名者产生,并经过策略验证。任意未签名 JSON 不能仅因字段齐全就视为可信证明。
血缘记录必须区分可公开材料与受控材料。训练数据、校准样本和专有转换配置可能不能进入公开清单,但可以保存内容摘要、受控引用和审批身份。工程判断是让发布门禁核对材料摘要与受控记录,不在移动包或日志中泄露训练资产。provenance 证明记录的构建过程,不单独证明模型运行安全或输出质量。
| 证明字段 | 量化场景内容 | 核验问题 | 不能推出 |
|---|---|---|---|
| subject | 量化模型或完整模型包摘要 | 是否对应当前候选 | 模型没有漏洞 |
| builder | 受控转换流水线身份 | 是否属于认可构建者 | 转换参数必然正确 |
| buildType | 量化流程类型与配置结构 | 是否使用允许流程 | 输出质量达到业务标准 |
| parameters | 精度、策略与公开安全参数 | 是否与发布配置一致 | 敏感材料可以公开 |
| materials | 原模型和受控材料摘要 | 能否复核转换血缘 | 材料内容本身可信 |
更新元数据要阻止回滚、冻结和文件混搭
The Update Framework specification 关注客户端验证签名、版本、过期时间和一致快照,以识别回滚、冻结与混搭风险。移动模型更新可以借鉴这些属性:目标清单绑定模型包摘要和长度,版本策略拒绝已撤销产物,元数据有明确过期时间,一致快照避免客户端把不同发布批次的文件拼在一起。
更新版本不等于业务模型版本。一个量化变体可以有自己的 artifactVersion 和 packageDigest,同时引用 baseModelId 与 baseModelDigest。服务端发布配置还要声明最低客户端版本、目标运行时、允许回退版本和撤销状态。客户端只有在签名、版本、过期、完整文件集和兼容规则全部通过后,才把新目录标为可激活。
TUF 是通用更新框架,不规定移动模型的业务授权,也不替代应用商店签名或模型输出评测。项目可以完整采用框架,也可以根据威胁模型实现等价门禁,但不能只复制版本号而省略签名和一致性。没有真实更新回执时,结论应限制为静态元数据与本地模拟通过,线上分发和设备激活仍待确认。
- 目标元数据绑定 packageDigest 与文件长度
- 拒绝已撤销或低于允许窗口的版本
- 元数据过期后停止接受旧声明
- 完整文件集合通过后再原子激活
- 回退目标拥有独立身份且仍被允许
- 发布回执绑定客户端、运行时和模型组合
用只读脚本核对完整模型包身份
下面的 Python 脚本读取量化产物清单,只读计算主模型和关联文件 SHA-256,并检查 artifactId、格式、量化策略、运行时、算子、输出容差说明与基线模型身份是否齐全。清单中的路径限制在指定根目录内,避免把绝对路径或上级目录误当模型成员。任何文件缺失或摘要不符都会返回非零状态。
脚本输出 packageDigest,用规范排序后的成员路径和摘要描述完整模型包。它不验证签名、不解析模型图,也不证明输出容差已通过;这些工作应由独立的签名门禁、格式检查和项目评测承担。示例要求 tolerancePolicy 是文字引用而非通用数值,避免把某个项目的阈值误用到所有模型。
准备端侧模型的软件加固评估时,可整理应用候选、原模型与量化产物身份、完整文件清单、转换证明、运行时与算子矩阵、更新策略和输出评测边界,再通过御盾中央平台提交申请。评估材料必须绑定真实摘要;在项目证据到位之前,不声称性能、兼容通过、资产保密或攻击阻断结果。
- 原模型与每个量化变体使用不同 artifactId
- 主模型和全部关联文件逐项计算摘要
- 格式、精度、算子与运行时要求进入清单
- 输出容差引用具体项目评测策略
- 转换证明绑定当前 packageDigest
- 更新元数据拒绝回滚、冻结和混搭
- 发布决定绑定同一移动应用候选
from pathlib import Path
import hashlib
import json
import sys
if len(sys.argv) != 3:
raise SystemExit(2)
manifest_path = Path(sys.argv[1])
artifact_root = Path(sys.argv[2]).resolve()
if not manifest_path.is_file() or not artifact_root.is_dir():
raise SystemExit(2)
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
required = ["artifactId", "baseModelId", "baseModelDigest", "format", "quantization", "runtime", "operators", "tolerancePolicy", "files"]
if any(not manifest.get(field) for field in required):
raise SystemExit(2)
if not isinstance(manifest["operators"], list) or not manifest["operators"]:
raise SystemExit(2)
file_records = manifest["files"]
if not isinstance(file_records, list) or not file_records:
raise SystemExit(2)
verified = []
for record in file_records:
relative_path = str(record.get("path", ""))
expected_digest = str(record.get("sha256", "")).lower()
candidate = (artifact_root / relative_path).resolve()
if artifact_root not in candidate.parents or not candidate.is_file():
raise SystemExit(2)
actual_digest = hashlib.sha256(candidate.read_bytes()).hexdigest()
if len(expected_digest) != 64 or actual_digest != expected_digest:
raise SystemExit(2)
verified.append({"path": relative_path, "sha256": actual_digest})
canonical = json.dumps(sorted(verified, key=lambda item: item["path"]), sort_keys=True, separators=(",", ":"))
package_digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
result = {"artifactId": manifest["artifactId"], "baseModelId": manifest["baseModelId"], "format": manifest["format"], "quantization": manifest["quantization"], "runtime": manifest["runtime"], "operators": sorted(manifest["operators"]), "tolerancePolicy": manifest["tolerancePolicy"], "packageDigest": package_digest, "files": verified}
print(json.dumps(result, ensure_ascii=False, indent=2))事实依据与适用边界
以下内容区分官方事实、本文工程判断和不能外推的范围,避免把设计建议写成未经验证的产品结论。
| 本文判断 | 事实或工程依据 | 适用限制 |
|---|---|---|
| 模型交付可在应用包体、下载、本地存储和精度之间进行取舍。 | Reduce Core ML app size 说明 Core ML 模型尺寸优化与应用交付的相关选择。 | 尺寸优化不证明模型来源、完整性、保密性或量化输出可接受。 |
| 模型元数据可以携带输入输出描述、归一化参数、标签和关联文件。 | LiteRT model metadata 描述模型元数据与关联文件的结构和用途。 | 只验证主模型摘要会遗漏 tokenizer、标签、预处理与后处理配置。 |
| 移动 ONNX 运行受到模型算子、运行时包和执行提供程序的共同约束。 | ONNX Runtime Mobile 说明 Android 和 iOS 上的模型装载及移动运行时约束。 | 运行时兼容不提供模型签名、业务授权、防回滚或输出质量保证。 |
| 构建证明可以把产物主体与构建者、构建类型、外部参数和依赖材料关联。 | SLSA Provenance v1.1 定义 provenance 中 subject、builder、buildType、parameters 与 dependencies 等字段。 | provenance 记录构建声明,不单独证明运行时安全、模型保密或输出正确。 |
| 有类型的供应链声明可以用摘要绑定当前模型产物。 | in-toto Attestation Statement v1 定义 subject、predicateType 与 predicate 的通用结构。 | 声明格式正确不保证内容真实,仍需验证签名者、策略和候选摘要。 |
| 更新客户端可通过签名、版本、过期时间和一致快照识别回滚、冻结与混搭风险。 | The Update Framework specification 定义更新元数据与客户端验证的安全属性。 | TUF 不规定移动模型业务授权、应用签名流程或模型输出验收标准。 |
| 原始模型和每个量化变体应拥有不同 artifactId 与 packageDigest。 | 工程判断:转换后的字节、数值表示、算子和关联文件可能变化,复用身份会导致报告错配。 | 独立身份只能保证可追溯,实际兼容性、性能和输出质量仍需项目证据。 |
| 输出容差必须绑定具体基线模型、数据集、指标和业务后果。 | 工程判断:不同任务与数据分布对量化误差的可接受程度不同。 | 本文不提供通用容差、性能范围或任何具体项目的放行结论。 |
工程常见问题
量化模型只是文件更小,为什么不能继续使用原模型版本号?
量化可能改变权重表示、算子、运行时要求和输出。原模型版本可保留为血缘字段,但量化后的实际字节必须有独立 artifactId、摘要和验收记录。
只给量化模型文件计算 SHA-256 是否足够?
不够。还要覆盖 tokenizer、词表、标签、预处理和后处理配置等关联文件,并为完整集合生成 packageDigest,防止合法单文件被错误混搭。
模型能够被移动运行时装载,是否说明量化结果可以上线?
不能。装载只覆盖格式和部分算子兼容,还要验证来源、签名、关联文件、目标设备路径和绑定具体任务的输出容差。
provenance 可以证明量化模型没有安全问题吗?
不能。它可记录构建者、流程、参数、材料和产物摘要,但仍需验证声明签名,也不替代漏洞分析、运行测试和业务输出评测。
模型更新如何避免新模型与旧 tokenizer 混用?
把主模型和关联文件纳入同一目标清单和 packageDigest,全部下载并验证后再原子激活;更新元数据还要检查签名、版本、过期和一致性。
申请端侧量化模型加固评估前要准备哪些材料?
准备真实应用候选、原模型和量化模型摘要、完整文件清单、转换证明、运行时与算子矩阵、更新策略及输出评测范围,再从御盾中央平台提交申请。