Files
worldmodel/plans/PRISM/18_lyra_inspirations.md
gaojie 0b12ff023c
Sync to site1 / sync (push) Has been cancelled
chore: update PRISM categories from worldmodel to PRISM
2026-05-21 02:25:22 +08:00

19 KiB
Raw Permalink Blame History

title, date, draft, tags, categories
title date draft tags categories
Chapter 18 — Lyra 2.0 启发的设计原则 2026-05-20 false
PRISM
世界模型
空间记忆
SLAM
点云
综述
PRISM

Chapter 18 — Lyra 2.0 启发的设计原则

本章目标:把 Lyra 2.0Self-Distillation Bootstraps 3D World Models from 2D Video Diffusion, 2025)译读 research/lyra2_review.md 第 8.4 节归纳出的 3 条核心思想 正式纳入 PRISM 设计哲学——分别约束 L2 ↔ L3 ↔ L4 的写入语义SpatialMemory 的证据保留策略Pipeline D 的巩固训练范式。本章是 PRISM v1.5.0 的新增内容。


18.1 章节目的

Lyra 2.0 是 2025 年 NVIDIA 用 2D 视频扩散模型"自蒸馏"出一个 3D 世界模型的工作;它的"3D 缓存"在工程上和 PRISM 的"空间记忆"是同类问题:都需要在多帧观测之间保留 3D 一致性、又都必须容忍几何精度不够好这一事实。Lyra 没有 SLAM、没有 TSDF,却用三个看似反直觉的工程决策——几何只做路由、per-frame 缓存绝不融合、巩固期用自己的不完美输出再训练——把"精度不够"的几何先验稳稳压在了"够用"的工作点上。这些决策与 PRISM 当下的痛点(L2 漂移、L3 写入污染、Pipeline D 缺少自监督信号)高度对应,因此值得作为独立章节沉淀下来,避免在后续 v1.x 演进中被遗忘或被工程惯性悄悄抹去。本章按"原则陈述 → 工程对应 → 风险约束"的顺序组织:每条原则先讲 Lyra 怎么做、再讲 PRISM 该怎么对应,最后在 § 18.6 集中说明哪些地方能照搬。更深的技术细节请回看 research/lyra2_review.md § 3.23D 缓存设计)与 § 3.3self-augmentation 公式)。


18.2 原则一:几何只做路由,不做合成

18.2.1 问题描述

PRISM v1.4 之前的写入逻辑里,L2 既要"提供占据栅格供避障",又要"把局部几何投到 L3 节点的子图里当内容"。这意味着 L2 的几何误差会污染 L3 的内容——例如 TSDF 在长走廊里漂了 30 cmL3 中"走廊节点"挂的那块点云也跟着歪 30 cm,后续 L4 的 bbox 估计也会跟着歪。

Lyra 2.0 § 3.2(a) 的做法给出了一个干净的解耦:3D 缓存只用来"挑选哪一帧 keyframe 该被注意到",真正的内容(颜色、纹理、语义)由原始 2D 帧的 cross-attention 提供。换言之,几何只回答"路由问题"who should write where),不回答"内容问题"what to write)。

18.2.2 PRISM 旧逻辑 vs PRISM 新逻辑

flowchart TB
    subgraph OLD["PRISM v1.4 旧:L2 既路由又写 L3"]
        direction LR
        O_L1["L1 keyframe<br/>(rgb+depth)"]
        O_L2["L2 TSDF/Octomap"]
        O_L3["L3 节点子图"]
        O_L1 --> O_L2
        O_L2 -- "投影点云<br/>(内容)" --> O_L3
        O_L2 -- "路由<br/>(选哪个节点)" --> O_L3
    end
    subgraph NEW["PRISM v1.5 新:L2 只路由,L3 内容来自 L1"]
        direction LR
        N_L1["L1 keyframe<br/>(rgb+depth)"]
        N_L2["L2 TSDF/Octomap<br/>(几何精度允许低)"]
        N_L3["L3 节点子图"]
        N_L1 --> N_L2
        N_L2 -- "路由<br/>(only: select node)" --> N_L3
        N_L1 -. "内容<br/>(keyframe ref)" .-> N_L3
    end
    style OLD fill:#fde2e2,stroke:#a33
    style NEW fill:#d4f0d4,stroke:#2e7d32

关键差异:新逻辑下 L3 节点存的不是"L2 几何投影出来的点云",而是"指向 L1 keyframe 的引用 + L2 给出的路由决策"。L2 即便漂 30 cm,只要它能正确挑出"这一帧属于走廊节点而不是卧室节点",下游就不受影响——内容由 L1 原始观测兜底。

18.2.3 伪代码

# prism/write/route_l3.py  (v1.5 新增)
def route_and_write_l3(
    keyframe: L1Keyframe,        # 原始观测:rgb + depth + pose
    l2: MetricLayer,             # 可能有漂移的 TSDF/Octomap
    l3: TopologicalLayer,        # 节点 + 边
) -> None:
    """
    几何只做路由:用 L2 决定 keyframe 该挂到哪个 L3 节点;
    L3 的"内容"始终是 keyframe 的引用,不复制几何。
    """
    # ---- 步骤 1: 用 L2 做路由(几何精度低也无妨) ----
    pose_xy = keyframe.pose.translation[:2]
    candidate_nodes = l2.query_room_id(pose_xy)         # 返回若干候选节点
    node_id = l3.disambiguate(candidate_nodes, keyframe) # 用 keyframe 视觉再确认

    # ---- 步骤 2: L3 只写引用 + 路由元数据,不写几何 ----
    l3.nodes[node_id].keyframe_refs.append(keyframe.id)
    l3.nodes[node_id].routing_log.append({
        "kf_id":       keyframe.id,
        "l2_pose":     pose_xy.tolist(),
        "l2_uncert":   l2.local_uncertainty(pose_xy),  # 路由置信度
        "ts":          keyframe.ts,
    })

    # ---- 步骤 3: 内容查询时,按需从 L1 读回 ----
    # L3.get_content(node_id) 实现里只做 L1Keyframe 的解引用,
    #   不缓存任何 L2 投影点云。这是与旧版的根本区别。)

设计含义:L2 漂移不再是 L3 的故障,而只是 L3 路由的噪声——可以通过 § 18.3 的 keyframe 独立证据来事后翻案,而不必反向修补 L2。另一个常被忽视的好处是:当未来引入 NeRF / 3DGS 之类的精细几何表示时,它们也只是 L3 的"另一种内容引用"不会与 L2 抢"几何真相代言人"的位置——L2 始终只代表"路由用的粗几何",L3 内容由谁提供、提供得多精细,是写入策略的自由度而非架构约束。这一点对应 Lyra § 3.2(d) 中 canonical coordinates 只参与 Q/K 不参与 V 的设计:粗坐标只用于"挑出谁该被注意到(Q/K 路由)",但模型实际看到的内容(V)来自原始 2D 帧。

详见对 plans/PRISM/03_data_schema.mdplans/PRISM/06_pipeline_C_online_perception.md 的影响(§ 18.5 总表)。


18.3 原则二:Per-frame 独立 keyframe 证据,而非全局融合

18.3.1 问题描述

PRISM 现行的 L2 是融合表示:TSDF 把每一帧深度都"加权累计"到体素里、OctoMap 把每一帧 ray 都更新到八叉树占据概率上。融合带来两个好处(紧凑、平滑)和一个致命缺点:一旦累计了漂移,原始证据就不可逆地丢了——你拿不回"第 t=12.3 s 那一帧 ZED 看到桌子在哪",因为它已经被融进了 240 万个体素的加权平均里。

Lyra 2.0 § 3.2(a) 把这点写得很明白:"3D 缓存绝不融合(never fuse"——每个 keyframe 是一条独立的、可追溯的证据,模型在 cross-attention 时挑出最相关的几条 keyframe,而不是查询一个"已经融合过的全局体素"。

18.3.2 三种策略对比

维度 OctoMap-onlyPRISM v1.0 TSDF-onlyPRISM v1.3 Lyra-style per-frame PRISM v1.5 选择
表示 八叉树占据概率 体素 SDF keyframe 列表(pose + depth + 特征) TSDF(路由)+ keyframe 列表(证据)
漂移可逆 ✗(已融合) ✗(已融合) ✓(每帧独立) ✓(keyframe 兜底)
内存 O(体素数) O(体素数) O(帧数 × 单帧大小) O(体素 + 关键帧子集)
避障查询 快(直接查体素) 慢(要做近邻) 快(用 TSDF
"翻案"能力 强(保留 keyframe
写入语义 累加 加权融合 append-only append-only on keyframes

PRISM v1.5 不是把 TSDF 扔掉,而是让 TSDF 和 keyframe 列表并存TSDF 负责 § 18.2 的"路由 + 避障"两个对几何精度要求不高的任务;keyframe 列表负责"翻案"——当 L4 发现某个语义节点和 L3 节点对不齐时,可以回退到 keyframe 重新估计 bbox。

18.3.3 SpatialMemory 新增字段 schema

# prism/schema/spatial_memory.py  (v1.5 新增字段)
@dataclass
class KeyframeEvidence:
    """
    每个 L1 keyframe 在巩固后保留的"独立证据"。
    一律 append-only,绝不被 L2 融合操作覆盖。
    """
    kf_id:          str                # 全局唯一,匹配 L1.frames[i].id
    ts:             float              # 采集时间戳 (epoch sec)
    pose:           SE3                # 该帧位姿 (世界系)
    pose_uncert:    np.ndarray         # 6x6 协方差 (路由置信度的来源)
    depth_ref:      str                # 指向 L1 存储的深度图 blob (lazy load)
    feat_ref:       str                # 指向 L1 存储的视觉特征 blob (DINO/CLIP)
    routed_l3:      Optional[str]      # 当时路由到的 L3 节点 id (可空)
    routed_l4:      List[str]          # 当时关联的 L4 实体 id 列表
    fused_into_l2:  bool = False       # 是否曾参与 L2 TSDF 融合
    immutable:      bool = True        # 一律 True;写入后不可被覆盖

@dataclass
class SpatialMemory:
    l1: L1Buffer
    l2: MetricLayer
    l3: TopologicalLayer
    l4: SemanticGraph
    # ---- v1.5 新增 ----
    keyframe_evidence: List[KeyframeEvidence]   # append-only,巩固期挑选关键帧入库

实现要点:

  1. append-onlyKeyframeEvidence 一旦写入即 immutable=True,禁止任何 pipeline 反向修改;
  2. lazy loaddepth_ref / feat_ref 只存路径,原始张量留在 L1 的 zarr/parquet 里,避免内存爆掉;
  3. 不是全部 keyframe 都进Pipeline D 巩固期会按"信息增益"挑一个子集(如每 0.5 m 或每 30° 视角变化保留一帧),典型规模 200–2000 帧/场景。

详见 § 18.5 对 plans/PRISM/03_data_schema.md 的影响。


18.4 原则三:巩固期的 Self-Augmentation

18.4.1 问题描述

Pipeline D(巩固期,离线 / 夜间)目前的逻辑是:拿白天采集的 L1 keyframe,运行更慢更准的离线管线(高分辨率 depth、bundle adjustment、全局优化),把结果写回 L3/L4。这个过程没有自监督信号——它假设"离线版的输出就是 ground-truth",但实际工程中离线版本身也会犯错,且模型从不学会"识别并纠正自己之前的错"。

Lyra 2.0 § 3.3(b) 给了一个简洁的 self-augmentation 公式:用模型自己之前的不完美输出作为输入,用干净的 ground-truth 作为监督。具体地,对训练样本的潜变量 $z$,以概率 p_{\text{aug}}=0.7 做扰动:


\tilde z_0 = z_t - t \cdot v_\theta(z_t, t, c), \quad t \sim \mathcal{U}(0, 0.5)

其中 v_\theta 是当前正在训练的流匹配模型自己。这相当于让模型把"自己一步去噪后的结果"当成新输入,再去预测真值——模型在训练中反复见到自己会犯的错,因此学会了自我纠错。

18.4.2 在 PRISM 巩固期的对应

把上面的范式翻译到 PRISM Pipeline D

  • z:当前场景的 L3/L4 表示(拓扑节点 + 场景图 bbox);
  • 不完美输入 $\tilde z_0$:用 Pipeline C 在线版(实时但粗)的 L3/L4 输出;
  • ground-truth 监督:用 Pipeline A 离线版(慢但准)的 L3/L4 输出。

模型(这里指 L3/L4 的精炼网络,未来 v2.0 的研究方向)学会的不是"从零产生 L3/L4",而是"从一份带错的 L3/L4 + 当时的 keyframe 证据,产生干净的 L3/L4"——这恰好就是"巩固"的本质。

18.4.3 伪代码

# prism/pipeline_d/self_aug.py  (v1.5 新增,实际实现见 v2.0 路线图)
def consolidate_with_self_aug(
    online_l3l4:  SceneRepr,           # Pipeline C 的不完美输出
    offline_l3l4: SceneRepr,           # Pipeline A 的"较干净"输出 (监督信号)
    kf_evidence:  List[KeyframeEvidence],
    refiner:      RefinerNet,          # 待训练的精炼网络
    p_aug:        float = 0.7,
    t_max:        float = 0.5,
) -> RefinerNet:
    """
    巩固期 self-augmentation:
    以 p_aug 概率用模型自己产生的"伪不完美样本"替换 online_l3l4,
    用 offline_l3l4 作为干净监督。
    """
    for batch in iterate_scenes():
        # ---- 1. 决定本步是否使用 self-aug ----
        if np.random.rand() < p_aug:
            # 用模型自己生成一个"扰动版"的输入
            t = np.random.uniform(0.0, t_max)
            z_clean = encode(offline_l3l4)                  # 干净潜变量
            z_t     = add_flow_noise(z_clean, t)            # 沿流方向加噪
            v_pred  = refiner.predict_velocity(z_t, t, kf_evidence)
            z_tilde = z_t - t * v_pred                      # 模型一步去噪结果
            x_in    = decode(z_tilde)                       # 解回 L3/L4 表示
        else:
            # 1 - p_aug = 0.3 概率用真实的"在线不完美输出"
            x_in    = online_l3l4

        # ---- 2. 统一的监督:始终向 offline 版对齐 ----
        x_pred  = refiner(x_in, kf_evidence)                # keyframe 证据可被检索
        loss    = scene_repr_loss(x_pred, offline_l3l4)
        loss.backward(); refiner.step()

    return refiner

18.4.4 关于 p_{\text{aug}} = 0.7 的取值讨论

Lyra 2.0 实验里取 p_{\text{aug}}=0.7 而非 0.5 或 1.0,有两个工程意涵值得我们沿用:

  1. 0.7 > 0.5 表示模型主要见到的是"自己生成的扰动样本"——这是它真正会犯的错;如果 p 太低(如 0.3),模型大部分时间在做"干净到干净"的精炼,巩固期就退化成普通监督学习,失去自我纠错能力。
  2. 0.7 < 1.0 留了 30% 真实的"在线不完美样本"——这部分确保模型不会沉迷于自己的失败模式,仍然能见到 Pipeline C 在真实工况下产生的、分布与 self-aug 不一样的错(如 ZED 在暗光下的深度毛刺,模型自己生成的样本里不一定包含)。

经验上:当 Pipeline C 已经相当稳定(错误率低且类型集中)时,可降到 0.5;当 Pipeline C 仍在快速演化、错误模式多样时,可推到 0.8。PRISM v1.5 起步采用 0.7,作为后续 ablation 的中点。

t \sim \mathcal{U}(0, 0.5) 的含义是:只在流匹配的"前半程"加噪——避免把样本扰动到几乎全噪声,那样监督信号会失效。

详见 § 18.5 对 plans/PRISM/07_pipeline_D_consolidation.md 的影响。


18.5 与 PRISM 现有章节的关系

本章的三条原则并不是"另起炉灶",而是约束既有章节在 v1.5 及之后的演进方向。下表列出影响面:

本章原则 影响的现有章节 具体影响内容 回链
§ 18.2 几何只做路由 Chapter 02 架构 L2 ↔ L3 边的语义从"投影内容 + 路由"收窄为"只做路由" plans/PRISM/02_architecture.md
§ 18.2 几何只做路由 Chapter 03 数据 schema L3Node.content 从"几何点云"改为"keyframe 引用列表" plans/PRISM/03_data_schema.md
§ 18.2 几何只做路由 Chapter 06 Pipeline C 在线 route_and_write_l3() 替换原"投影 + 写内容"两步 plans/PRISM/06_pipeline_C_online_perception.md
§ 18.3 keyframe 独立证据 Chapter 03 数据 schema 新增 SpatialMemory.keyframe_evidence: List[KeyframeEvidence] 字段 plans/PRISM/03_data_schema.md
§ 18.3 keyframe 独立证据 Chapter 13 评估 新增"翻案能力"指标:被 keyframe 推翻的 L4 bbox 占比 plans/PRISM/13_evaluation.md
§ 18.4 self-augmentation Chapter 07 Pipeline D 巩固 巩固期训练范式从"监督学习"升级为"self-aug 监督学习" plans/PRISM/07_pipeline_D_consolidation.md
§ 18.4 self-augmentation Chapter 13 评估 新增"巩固后纠错率"指标:online → offline 之间被纠正的错误数 plans/PRISM/13_evaluation.md

上述章节本次 v1.5.0 升级暂不强制改动——本章先以"设计原则"形式独立存在;后续 v1.6 / v2.0 在演进对应章节时,再逐条把约束落地。


18.6 风险与限制

本章列出的三条原则源自 Lyra 2.0 的工程实践,但 Lyra 与 PRISM 在问题设定上有根本差异,因此必须把"借鉴"与"复制"严格区分:

  1. Lyra 是生成式,PRISM 是判别式 + 真实传感器。Lyra 的"3D 缓存"服务于像素生成(视频扩散解码),它的几何粗糙是可以容忍的,因为下游 cross-attention 会用 2D 帧把内容补回;PRISM 的 L2 服务于机器人避障,几何粗糙的容忍度有刚性下限(栅格分辨率不能粗于半个机器人宽度)。§ 18.2"几何只做路由"不能被滥用为"几何精度可以任意低"——它只是说"L2 精度不要影响 L3 内容",并不是说"L2 精度可以任意差到避障也失败"。
  2. Lyra 的训练数据是合成的(视频扩散先验),PRISM 的数据是真实 ZED / iPhone。Self-augmentation 在 Lyra 里之所以好用,部分是因为合成数据的"分布"和模型 capacity 是匹配的;PRISM 的真实数据带有显著的传感器噪声(ZED 在反光面、低纹理面会大面积失败),把模型自己生成的样本当训练源,可能把传感器特有的失败模式当成"正常分布"学下来。§ 18.4 中保留 30% 真实在线样本($1 - p_{\text{aug}} = 0.3$)就是为了对冲这个风险,但仍需要在 Pipeline D 的实施中加 ablation 验证。
  3. per-frame 证据保留有存储代价。Lyra 的 keyframe 数量受限于扩散模型的 context 长度(数十帧);PRISM 在长期部署中一个酒店场景可能积累数万帧。§ 18.3 的"保留子集"策略(每 0.5 m 或每 30° 视角一帧)是经验值,长期边界尚未被验证——可能需要 v2.0 引入"keyframe 退役 / 压缩"机制,否则会成为新的内存瓶颈。
  4. 原则之间也存在张力。"§ 18.2 只用 L2 路由"要求 L2 几何只承担轻任务;"§ 18.3 保留 keyframe 翻案"要求事后能纠正 L4——但到底何时触发翻案?由谁判定 L4 出错? 当前章节未给出闭环规则,留给 plans/PRISM/13_evaluation.md 在新增"翻案能力"指标时配套定义。

综上,本章是 PRISM 在 v1.5 节点上对 Lyra 2.0 的有节制的吸收:原则被写下来,但落地节奏由后续章节按版本逐步推进,确保每一条都经过实验回归而非仅凭直觉。一个简明的检验标准是:v1.6 在改动 plans/PRISM/03_data_schema.md 引入 keyframe_evidence 字段时,必须同步在 plans/PRISM/13_evaluation.md 加入"翻案命中率"与"翻案误报率"两项指标——只有这两个数能稳定测出来,§ 18.3 的原则才算真正落地;否则就只是"看上去更优雅"的架构装饰。Self-aug 的 p_{\text{aug}} 与 § 18.2 路由置信度阈值同理,必须以可被 ablation 推翻的形式写进评估章节,本章才算完成它的设计哲学使命。


章节版本v1.0(新增于 PRISM v1.5.0 估计阅读时间810 分钟 关键收获:几何只做路由 / 不做合成;keyframe 独立证据;巩固期 self-aug。