问题:收到更新不等于已有可用模型
一个工业传感器读取温度与振动,再用小型人工智能模型判断机器状态。设备收到新版本的权重,也就是训练得到的数值。在保存过程中,有人断开电源。恢复供电后,传感器必须决定加载什么。问题不仅是完成传输,还要避免把不完整的副本当作可用模型,同时不能毁掉唯一可工作的旧副本。
本文的问题很具体:能否组织更新过程,让每次重启都找到完整旧版本或完整新版本?我们将建立状态机,即描述操作及其留下的持久状态,并执行模型涵盖的所有中断位置,比较直接覆盖与两个独立区域加最后激活步骤的方案。得到的结论依赖明确的假设,不是对商业开发板可靠性的测量。
进入细节前:“就绪”的三种含义
已收到,表示传输交付了数据;已验证,表示数据通过了规定的检查,例如预期长度、密码学摘要以及与模型执行程序的兼容性;已激活,表示启动过程允许选择它们。这三件事不必同时发生。下载完成通知不能证明数据已经持久保存,验证成功也不要求立即激活候选版本。把这些事件分开,才能讨论两者之间断电会怎样。
在这个场景中,称为运行时的推理程序保持不变,我们把权重作为数据更新。闪存断电后仍保存信息,而 RAM 通常不能。我们将为一份副本保留的内存区域称为槽位,激活日志保存可选副本的简短描述。可以把它想象成一本书的可用版本目录,但类比仅止于此:真实存储器存在擦除块、编程约束和写入中断,纸质目录并不能表达这些问题。
推理成立所需的约定
我们假设写入是持久且有序的:程序完成一个步骤再开始下一步,重启后能保留已完成的步骤。还假设最终标记具有原子性:重启后它只能是未设置或已设置,不能以模糊状态被误接受。两个槽位相互独立,已确认的旧副本保持完整,元数据和预期摘要来自可信来源,代数计数器不断增长且不会溢出。这些是数学模型的前提,硬件项目必须说明如何实现;若不成立,就要改变协议。
我们仅在已完成的抽象操作之间引入中断,不模拟闪存电压下降时的电路行为、写到一半的数据、尚未刷新的缓存或相邻扇区损坏。这一区别非常重要:枚举 Python 程序中的所有状态,并不等于测试微控制器的所有故障。这个小实验回答的是协议的逻辑问题。电气、时序和存储寿命测试属于第二层验证,在设备使用此设计前仍然必需。
最小示例:四个部分与一份副本
将旧模型简化为四个字节 [1, 1, 1, 1],新模型为 [2, 2, 2, 2]。它们不是可推理的权重,而是代表文件的四个部分,让完整性变得直观。简单方案先擦除槽位,再逐部分写入,共五个操作和六个可观察中断点,包括首次操作之前。擦除前有旧模型,全部写完后有新模型,而四个中间位置没有任何完整副本。
即使以后会继续传输,[2, 2, 空, 空] 此刻也不是正确模型。重启时所需内容已经缺失。可以停止推理等待恢复,这在某些场景可以接受,但不能声称持续可用。提前写入“版本 2”标签也无济于事,因为标签不会补齐数据。如果标签被解释为加载许可,提前写入反而更容易选中不完整副本。因此所需性质必须同时约束数据与选择程序。
两份副本,把决定留到最后
将已确认的副本保存在 A 槽,在 B 槽准备候选版本。八个操作依次是:擦除 B、写入四部分、验证摘要、追加尚未激活的日志记录、设置提交标记。提交意味着让这项决定在重启后可见。记录包含代数、槽位名称、所需运行时版本和预期摘要。代数只对激活顺序排序,不衡量模型质量,更不能当作科学性能评估。
重启时按新到旧的顺序读取记录,接受首个已提交、兼容且对应数据完整、摘要正确的记录。验证针对实际存在的数据重新执行,不能仅凭断电前“下载已检查”的记忆。如果候选版本失败,就尝试上一条记录;全都失败则返回“没有有效模型”。明确的失败结果可防止在没有可用副本时随意加载,却表现得像成功一样。
这个公式回答“哪些副本允许被选择”。r 表示记录,AND 要求全部条件成立;complete 检查是否缺少部分,hash_ok 比较计算摘要与预期摘要。代码将后二者合并在 valid 函数中。这里没有物理单位,只有逻辑判断。例如记录已提交但要求运行时 2,而设备运行时为 1,即使每个字节都与接收数据一致,也不能选择它。
实验究竟说明什么
图中汇总两个程序的执行结果,每个点表示完成若干操作后重启。上图的红点表示副本不可用,下图则在最终提交之前始终选择旧版本。两个协议横轴统计的是不同操作,不是秒数:上图第 5 点并不对应下图第 5 点的同一时刻。比较的是可能的选择结果,而不是更新速度。

| 协议 | 检查点数 | 旧版本 | 新版本 | 无有效版本 |
|---|---|---|---|---|
| A: overwrite | 6 | 1 | 1 | 4 |
| B: dual + commit | 9 | 8 | 1 | 0 |
六个位置中四个有问题,不意味着故障概率为 66.7%。我们没有给中断时间指定分布,没有测量操作耗时,也没有模拟供电电压。擦除块与写一个字节的耗时未必相同。同样,九个检查点中零个无效状态,也不是零风险的统计估计。这只是穷尽检查了抽象模型允许的切断位置。混淆两者,会把有用的逻辑结论变成没有数据支持的可靠性承诺。
结果的原因:保持不变量
不变量是每个允许步骤之后都成立的性质。这里的不变量是:提交前至少有一个可选副本,即 A。初始时按构造成立。槽位独立,因此擦写 B 不改变 A;验证 B 也不改变 A;追加未激活记录不会让 B 可选。由此可对步骤归纳:若提交前某一步执行前成立,执行后仍成立。在这些位置重启都会返回 A。
原子标记激活时,B 已完整并验证通过,较新的记录让它优先被选。如果重启检查发现候选版本不可用,A 仍然存在。顺序至关重要:数据完整之前激活记录,会破坏上述推理。独立性同样关键:若两个区域共用扇区,擦除 B 会同时擦掉 A 的一部分,不变量也就不成立。仅在存储映射上画两个方框不够,还必须遵守破坏性操作的实际粒度。
三个负面测试,其中一个必须失败
程序还执行三个独立于中断的测试。第一,损坏已提交候选版本的一个字节,摘要不匹配,重启选择 A。第二,将候选记录所需运行时从 1 改为 2,数据虽完整但不兼容,仍选择 A。第三,损坏 B 并擦除 A,选择函数返回 None,表示没有可用副本。最后一个测试与前两个同样重要:它揭示了性质的边界,两个槽位不能抵御两份副本同时丢失,程序也不能掩盖这种情况。
使用的摘要函数为 SHA-256,它将字节序列概括为固定长度序列。本例能检测人为修改的测试数据,但不能证明模型来自谁。若攻击者能同时替换文件与预期摘要,即使文件未获授权,比较也可能通过。软件包真实性、密钥保护、签名验证和更新授权需要另行设计。本文假设元数据可信,没有评估分发渠道的安全性。
保留退路需要多少存储空间?
从四字节教学模型转向假设性容量计算,不将其归于任何开发板。模型占 W = 1,048,576 字节,即 1 MiB;每份副本有 H = 256 字节头部。擦除块为 E = 4,096 字节,日志预留 J = 8,192 字节。为防止擦除跨越副本边界,每个槽位向上对齐到 E 的整数倍。因此下面公式回答的是具体物理问题:此方案需要预留多少闪存字节?
S 是一个槽位的预留大小,F 是总大小,ceil 表示向上取整。1 KiB 为 1,024 字节,1 MiB 为 1,048,576 字节。实际计算得到 2,113,536 字节,比 2 MiB 多 16,384 字节,而且尚未计入运行时、启动代码和其他数据。即使在这个最小例子里,“模型一兆,所以两兆足够”也不成立。这里计算的是持久存储,而不是推理峰值 RAM;后者还取决于激活值、缓冲区和算子实现。
完整性不等于完全兼容,更不等于质量
兼容性检查只使用一个运行时整数,刻意保持简单。在 AI 应用中,权重文件可能要求特定输入形状、通道顺序、传感器单位、归一化、算子和标签映射。改变归一化却保留旧权重,系统可能正常启动但判断错误。因此软件包清单应标明相互一致的依赖组合。如果其他配置已经不兼容地改变,仅恢复权重并不构成完整回滚。
本程序的提交只让 B 可选,没有实现试运行后确认。实际扩展可以区分候选、试启动和已确认版本,结合健康检查与尝试次数限制;随后还必须定义确认期间断电的行为。通过启动测试也不证明模型对未来数据准确。启动连续性、接口正确性与预测有效性是不同性质,任何一个都不能由另外两个自动推导。
真实系统与其他方案
MCUboot 官方文档描述固件镜像更新中的试运行、确认、回退模式,以及恢复中断交换所需的持久信息。它有助于理解抽象规则与可配置引导程序的差距。本文代码没有运行 MCUboot,没有复现其算法,也没有更新固件。
其他方案取决于主要约束。单槽加网络恢复节省本地空间,但接受一段无法推理的时间,并依赖恢复通道可用。双槽以额外存储为代价保留可用副本。差分更新只传输变化,但传输字节减少不保证应用补丁时可安全中断,仍需要保留先前状态的策略。临时文件写完后替换文件名,则把部分问题交给文件系统契约,包括掉电后操作是否持久。
日志也必须考虑寿命。代码中它是每次启动排序的 Python 列表,计数器不会溢出。但真实存储有限,删除旧记录、回收扇区和管理磨损都会引入需要分析的新状态转换。R 条记录的教学排序成本为 O(R log R);验证 W 字节需要 O(W) 哈希工作,退回 A 时可能要读取两份副本。这些复杂度不能直接给出毫秒或毫焦,必须通过平台测量得到延迟与能耗。
如何复现,以及设备上还需验证什么
附件包含 experiment.py、plot.py、JSON 结果及四种语言说明。实验是确定性的,因此不使用随机种子。运行 experiment.py 会枚举状态并自动检查所述性质;plot.py 绘制结果,不测量硬件。文末短代码调用相同计算,输出检查点与结果、三个负面案例以及总字节数。完整文件中决定加载的条件要求记录已提交、兼容且副本验证通过,解释在此变为可执行规则。
硬件上应在擦除、编程、元数据更新和确认过程中实施受控断电,而不仅在软件函数之间。需要说明板卡、闪存、版本、配置、电压与协议,并检查候选损坏、依赖错误、日志丢失和试启动失败。这只是尚未执行的验证计划。本文没有重启时间、能耗、磨损或故障概率测量,也不将实验归为 EL-AI 嵌入式产品成果;它是教学分析,不是企业部署记录。
答案:先保住副本,再选择新版本
断电后,本协议在提交前启动 A,提交后若候选通过检查则启动 B,否则在 A 仍有效时退回 A。原因并非人工智能的特殊能力,而是保留完整副本,并等到另一份数据准备好才决定使用它。由此可明确嵌入式更新应满足什么:可验证的选择规则、受保护的先前状态,以及能在实际存储器上实现的假设。模拟说明这些假设下推理成立,设备仍需证明自己满足假设。
技术来源与可复现材料
from experiment import run
r = run()
for name in ['naive', 'dual']:
print(name, [(x['cut'], x['outcome']) for x in r[name]])
print(r['negative_cases'])
print(r['memory']['total_flash_bytes'])
代码、数据与说明 · JSON. 教学计算使用 Python 3.14.0,图使用 Matplotlib 3.11.2。分析由 AI 辅助,不声称经过同行评审或人工审核。原创 ImageGen 封面仅作示意,不记录 EL-AI 人员、场所或实际安装。来源查阅于 2026 年 10 月 6 日。

