From 5129d1d80839e80679bee29ac89d0d49da9f5c75 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 29 May 2026 06:04:24 +0000 Subject: [PATCH] Research-production instrument: node -> hypothesis -> code-verified result -> paper draft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns the atlas from a map into a research instrument, addressing the 'paper-production pipeline' intent: - labs/research/harness.py: dependency-free (stdlib only, CPU, deterministic) harness that takes a falsifiable Hypothesis tied to a graph node, sweeps one independent variable, records a metric, decides whether the claim survived its own falsifier, and emits a results table + SVG figure + findings note. - labs/research/exp_overestimation_bias.py: code-verifies the lens of insight:q_learning_max_is_optimistically_biased. Result reproduces the textbook effect — single-max bias grows 0.20 -> 0.83 as actions go 2 -> 64, while the double estimator stays ~0 — so the lens claim survives, by code. - tools/scaffold_paper.py: given a node, assembles a paper-draft scaffold from the graph neighbourhood + research lens (research question, positioned related work, load-bearing assumption, gap, method primitives, cross-domain prior, experiment plan with a harness pointer, falsification criteria). Example drafts for UniAD, offline-RL-as-constrained-DP, differentiable-E2E, and conditional-generation planning in research/drafts/. - Research lenses 56 -> 66 (completed RL/decision lens-wave fragment). QC green: 0 dead links, 0/231 lint findings, math test passing, all 66 lens links resolve, seed validator OK. (Lands on the branch after the PR-23 merge.) --- docs/data/lens_fragments/wave2_rl.json | 62 +++++ docs/data/research_lens.json | 60 +++++ labs/research/exp_overestimation_bias.py | 96 +++++++ labs/research/harness.py | 126 ++++++++++ .../results/overestimation_bias/figure.svg | 26 ++ .../results/overestimation_bias/findings.md | 33 +++ ...ctually_constrained_dynamic_programming.md | 42 ++++ ...reat_planning_as_conditional_generation.md | 44 ++++ research/drafts/paper_2212.10156.md | 68 +++++ ...igm_differentiable_end_to_end_imitation.md | 44 ++++ tools/scaffold_paper.py | 236 ++++++++++++++++++ 11 files changed, 837 insertions(+) create mode 100644 docs/data/lens_fragments/wave2_rl.json create mode 100644 labs/research/exp_overestimation_bias.py create mode 100644 labs/research/harness.py create mode 100644 labs/research/results/overestimation_bias/figure.svg create mode 100644 labs/research/results/overestimation_bias/findings.md create mode 100644 research/drafts/insight_offline_rl_is_actually_constrained_dynamic_programming.md create mode 100644 research/drafts/move_treat_planning_as_conditional_generation.md create mode 100644 research/drafts/paper_2212.10156.md create mode 100644 research/drafts/paradigm_differentiable_end_to_end_imitation.md create mode 100644 tools/scaffold_paper.py diff --git a/docs/data/lens_fragments/wave2_rl.json b/docs/data/lens_fragments/wave2_rl.json new file mode 100644 index 0000000..1a523af --- /dev/null +++ b/docs/data/lens_fragments/wave2_rl.json @@ -0,0 +1,62 @@ +{ + "paradigm:model_free_rl": { + "assumption": "环境的转移结构 $P(s'\\mid s,a)$ 难建模但廉价可采样,因此 Bellman 递推 $Q^*(s,a)=\\mathbb{E}[r+\\gamma\\max_{a'}Q^*(s',a')]$ 这一条信号就足够把策略推到接近最优,无需重建动力学。隐含前提是\"时间换样本\"可接受——典型 DQN 量级要 $2\\times10^8$ 帧交互,且标量奖励 $r$ 被设计得既能表达性能又能表达安全。", + "failure": "在真实驾驶这类样本昂贵、不可任意重置的环境里,$2\\times10^8$ 帧对应数十万小时实车,押注直接破产;同时分布外状态让函数逼近的 $Q$ 估计任意发散,稀疏长视野奖励下 $\\nabla_\\theta J$ 期望近零导致策略梯度\"无信号可学\"。奖励工程一旦写错,无模型 RL 会忠实地把策略优化到错误方向(reward hacking)。", + "experiment": "自变量:仿真器交互预算(帧数,从 $10^6$ 扫到 $2\\times10^8$);在固定的 CARLA 城区路线上比较无模型 PPO 与一个等预算的 [模仿学习](paradigm_imitation_learning.md) 基线的闭环成功率与样本效率曲线。可证伪点:若在任何预算点上无模型 RL 的成功率都不超过同预算 BC,则\"环境反馈值得用海量交互去换\"在该域不成立。", + "isomorphism": "同一结构出现在演化策略/黑箱优化中——都放弃对目标函数内部结构建模,仅靠大量采样估计改进方向;其在测试时的对位是 [搜索替代训练时计算](insight_test_time_compute_substitutes_train_time_via_search.md),即用在线展开补足离线样本效率短板。" + }, + "paradigm:model_based_rl": { + "assumption": "存在比策略本身更紧凑、更易学的环境近似 $\\hat{P}(s'\\mid s,a),\\hat{R}(s,a)$(常压在隐空间 $z_t$ 上),且在 $\\hat{P}$ 下做想象 rollout 得到的虚拟经验对真实策略仍然有用——前提是模型偏差有界,不会被规划/价值迭代循环放大。它愿意用一到两个数量级的真实样本节省,去换这份偏差风险。", + "failure": "长视野展开(>50 步)时单步预测误差几何累积,规划在\"自信的错误\"上做最优化;策略还会主动学会利用模型预测漏洞(model exploitation),在 $\\hat{P}$ 里刷出真实环境不存在的高回报。多智能体场景下把他车塞进 $\\hat{P}$ 的转移函数至今未解,sim-to-real gap 在学得模型上比手工仿真器更隐蔽。", + "experiment": "自变量:想象 rollout 的 horizon $H\\in\\{1,5,15,50,100\\}$;在 [DreamerV3](paper_dreamer_v3.md) 类骨架上固定真实样本预算,度量真实环境回报与\"模型内估计回报减真实回报\"的乐观偏差。可证伪点:若回报随 $H$ 单调上升且乐观偏差不随 $H$ 增长,则\"模型偏差被长展开放大\"这一核心顾虑在该任务不成立。", + "isomorphism": "与 [AlphaZero 自我对弈 + MCTS 引导策略](validation_trace_alpha_zero_self_play_with_mcts_guided_policy.md) 同构——用学得/已知的模型在想象中前瞻搜索,再把搜索结果蒸馏回反应式策略;也对应模型预测控制(MPC)在辨识模型上滚动优化的经典控制范式。" + }, + "paradigm:imitation_learning": { + "assumption": "示教比奖励容易获取,且专家轨迹 $\\{(s_i,a_i)\\}$ 在 i.i.d. 假设下覆盖了足够多的正常状态,使得监督损失 $\\min_\\theta\\sum_i\\ell(\\pi_\\theta(s_i),a_i)$ 下降即对应闭环行为接近专家。它还押注示教是某个隐式奖励的优解,因此\"模仿\"等价于在反推该奖励。", + "failure": "i.i.d. 假设在闭环里崩塌:策略自身的微小动作误差把它带到训练分布外的状态,那里没有标签,误差按 horizon 复合(compounding error),最坏情形误差随步数 $T$ 以 $O(T^2)$ 增长。人类数据几乎不含碰撞,模型学不到\"碰撞前如何避让\";开环 L2 低不蕴含闭环安全,是 driving BC 的核心争论。", + "experiment": "自变量:训练集是否包含 DAgger 风格的策略访问状态再标注(纯 BC vs [DAgger](paper_ross2011_dagger.md));在 nuPlan/CARLA 闭环上度量成功率与脱离里程随展开步数的衰减斜率。可证伪点:若纯 BC 的闭环成功率随 horizon 的衰减斜率与 DAgger 无显著差异,则\"复合误差来自协变量偏移、需在线标注修正\"在该数据规模上不成立。", + "isomorphism": "同一原则边界写在 [模仿学习无法从复合误差中自我恢复](insight_imitation_learning_alone_cannot_recover_from_compounding_errors.md);\"示教压缩隐式奖励\"则与逆强化学习同构([最大熵 IRL](paper_ziebart_max_ent_irl.md)),都把行为数据当作未明示目标函数的证据去反演。" + }, + "paper:rlhf_dpo": { + "assumption": "人类难写完整奖励但能做可靠的成对比较,且偏好服从 Bradley-Terry 模型,使得最优策略对参考策略的对数比恰好就是隐含奖励——DPO 据此把奖励建模与 PPO 合并成封闭形式 $\\mathcal{L}_{\\text{DPO}}=-\\log\\sigma\\big(\\beta\\log\\frac{\\pi_\\theta(y_w|x)}{\\pi_{\\text{ref}}(y_w|x)}-\\beta\\log\\frac{\\pi_\\theta(y_l|x)}{\\pi_{\\text{ref}}(y_l|x)}\\big)$,无需在线采样与显式 reward model。", + "failure": "偏好数据本身带标注者偏见,且\"看起来合理\"的语言解释并不等于物理上安全的轨迹;当目标分布远离参考策略 $\\pi_{\\text{ref}}$ 的支撑、或偏好对里 $y_w,y_l$ 都是低概率离群样本时,$\\beta$ 控制的 KL 锚失效,DPO 易过拟合到表面格式偏好(reward over-optimization)。其离线性质使它无法纠正训练分布之外的新失败模式。", + "experiment": "自变量:$\\beta$(KL 正则强度,扫 $\\{0.01,0.1,0.5\\}$)与偏好对是否含安全反例;在驾驶语言-轨迹偏好集上度量\"语言偏好胜率\"与\"实际闭环碰撞率\"的相关系数。可证伪点:若两者相关系数随训练步数下降甚至转负(语言更受偏好而轨迹更危险),则\"人类成对偏好是安全对齐的可靠监督\"在驾驶域被推翻。", + "isomorphism": "与 [安全 RL 的拉格朗日约束](paper_lagrangian_safe_rl.md) 同构——RLHF 中的安全 reward model 充当 cost critic,$\\beta\\cdot\\mathrm{KL}$ 锚等价于把\"别偏离可信参考\"写成软约束;DPO 的封闭形式则呼应\"少手写奖励、多让学习器从反馈改进\"的 [苦涩的教训](essay_bitter_lesson.md)。" + }, + "paper:diffuser": { + "assumption": "把规划当作对整段未来轨迹的条件生成:从噪声轨迹 $x_T$ 逐步去噪到可行序列 $x_0\\sim p_\\theta(x_{t-1}\\mid x_t,c)$,其中条件 $c$(起点、目标、奖励、约束)像磁铁把随机未来拉向高价值可行解。它押注训练数据的轨迹分布足够覆盖好决策的模式,且引导(guidance)能在采样时把约束注入而不破坏动力学一致性。", + "failure": "多步去噪在实时控制里比一次前向规划慢一两个数量级,30Hz 闭环下采样预算被挤压;当条件 $c$(如硬安全约束或长尾目标)落在训练轨迹分布之外时,guidance 把样本推向数据未覆盖区,生成出动力学上违规或穿越障碍的\"幻觉轨迹\"。离线数据里没有的避险机动,扩散同样生成不出来。", + "experiment": "自变量:去噪步数 $T\\in\\{5,20,50,100\\}$(直接换算为单次规划延迟);在闭环驾驶任务上度量成功率与每决策延迟,并与一次前向的概率规划基线 [VADv2](paper_vadv2.md) 对比。可证伪点:若不存在任何 $T$ 使 Diffuser 在\"成功率不降\"的同时满足实时延迟预算,则\"多样未来的收益足以抵消采样成本\"在驾驶落地中不成立。", + "isomorphism": "与 [扩散策略](paper_diffusion_policy_chi2023.md) 同构(同为 score-based 动作/轨迹采样器),都把决策视作 [生成式建模](paradigm_imitation_learning.md) 而非回归;其\"在执行前于想象中筛掉坏未来\"的动机与 [世界模型](paper_world_models.md) 一脉相承,只是把想象放进轨迹空间而非观测空间。" + }, + "paper:lagrangian_safe_rl": { + "assumption": "安全可写成 CMDP 的折扣代价约束 $\\mathbb{E}[\\sum_t\\gamma^t C_i]\\le d_i$,并通过拉格朗日 $\\mathcal{L}(\\pi,\\lambda)=-J^R(\\pi)+\\sum_i\\lambda_i(J^{C_i}(\\pi)-d_i)$ 的原始-对偶交替($\\theta$ 下降、$\\lambda\\ge0$ 上升)逼近最优——押注违约时 $\\lambda_i$ 上升把策略拉回安全、满足后衰减放开探索,这套软约束能稳定收敛到约束边界。", + "failure": "乘子学习率 $\\eta_\\lambda$ 调不好时出现极限环振荡:一旦违约 $\\lambda$ 暴涨把策略硬拉回安全区,随即 $\\lambda$ 衰减过快又放开、再次违约,循环往复,期间仍产生不安全交互。对约束尺度极敏感——把碰撞代价从 1 改到 100 等价于把 $\\lambda$ 初值除以 100;软约束只在期望意义成立,不保证逐回合零违约。", + "experiment": "自变量:乘子学习率 $\\eta_\\lambda$(对数扫 4 个量级)以及是否换成 [PID-Lagrangian](paper_pid_lagrangian.md) 的反馈更新;在 Safety Gym PointGoal1 上记录约束违反率曲线的振荡幅度与收敛后稳态违约率。可证伪点:若在任意 $\\eta_\\lambda$ 下固定步长对偶上升都能达到 PID-Lagrangian 同等的低振荡,则\"对偶变量需额外反馈控制稳定化\"不成立。", + "isomorphism": "与控制论的积分控制器同构——$\\lambda$ 对约束违反量做积分累加正是 PI 控制器的 I 项,这解释了为何 PID 版本能消除超调;理论根在 [Altman 约束 MDP](paper_altman_constrained_mdp.md),对位是 [CPO](paper_cpo_safe_rl.md) 的信赖域硬约束投影。" + }, + "validation:trace_clipped_policy_gradient_surrogate": { + "assumption": "策略空间不是欧氏空间、单步更新过大会摧毁策略,因此需限制新旧策略的距离;TRPO 的二阶 KL 信赖域 $\\mathbb{E}[\\mathrm{KL}(\\pi_{\\theta_{\\text{old}}},\\pi_\\theta)]\\le\\delta$ 可用对概率比 $r_t(\\theta)=\\pi_\\theta/\\pi_{\\theta_{\\text{old}}}$ 的一阶剪裁 $\\mathrm{clip}(r_t,1-\\epsilon,1+\\epsilon)$ 近似替代——押注这个局部一阶约束足以保持策略改进的实践稳定,省掉共轭梯度与 line search。", + "failure": "剪裁只解决\"单步更新别过大\",不保证整体策略单调改进;在长 horizon、稀疏奖励任务(Montezuma、长程驾驶)上,优势 $A_t$ 本身的梯度信号接近零,剪裁无能为力——它治不了\"信号在哪里\"的问题。该再发明链路缺\"长视野信用分配\"构件,因此推不出 RND、go-explore。", + "experiment": "自变量:剪裁参数 $\\epsilon\\in\\{0.1,0.2,0.3,0.4\\}$;在 MuJoCo HalfCheetah(密集奖励)与一个稀疏奖励长程任务上分别跑 [PPO](paper_schulman2017_ppo.md),度量最终回报与训练稳定性。可证伪点:若调大 $\\epsilon$ 能让稀疏奖励任务回报显著上升,则\"剪裁解决稳定性、不解决信号缺失\"的判断在该任务被推翻。", + "isomorphism": "与近端点法/邻近梯度(proximal methods)同构——都在每步给更新加一个\"别离当前点太远\"的邻近罚项以换取稳定;剪裁这一思想被 [IQL](paper_iql.md) 的优势加权回归继承进离线 RL。" + }, + "validation:trace_safe_rl_via_lagrangian_constrained_optimization": { + "assumption": "标量奖励无法稳健表达安全(策略可用高 reward 抵消碰撞惩罚),必须改用 CMDP:在奖励 $R$ 之外定义代价 $C_i$ 与阈值 $d_i$,再用拉格朗日 $\\mathcal{L}(\\pi,\\lambda)=\\mathbb{E}_\\pi[R]-\\sum_i\\lambda_i(\\mathbb{E}_\\pi[C_i]-d_i)$ 把硬约束化软,原始变量用 PPO 剪裁目标优化、对偶变量 $\\lambda_i\\leftarrow[\\lambda_i+\\eta_\\lambda(\\mathbb{E}_\\pi[C_i]-d_i)]^+$ 在线自适应。", + "failure": "乘子学习率失调引发振荡——违约后 $\\lambda$ 暴涨、策略被强拉回安全、$\\lambda$ 又衰减过快,循环反复;该链路缺\"对偶变量稳定化\"构件,给出原理性正确解但工程稳定性需额外反馈控制,因此推不出 PID-Lagrangian。软约束仅在期望意义满足,训练期内仍有逐回合违约,不适合零容忍安全场景。", + "experiment": "自变量:cost critic 的目标阈值 $d_1$(碰撞代价预算,扫多档);在 CARLA 安全 RL 任务上把\"不碰撞\"设为 $C_1$、\"不违规\"设为 $C_2$,度量 $\\lambda_1$ 曲线、约束违反率与最终任务回报的帕累托前沿。可证伪点:若收紧 $d_1$ 时违约率不随之单调下降(对偶上升未能把策略压向约束边界),则\"拉格朗日对偶能实现可控的安全-性能权衡\"在该域不成立。", + "isomorphism": "落地 [安全靠约束对偶而非奖励塑形](insight_safety_emerges_from_constraint_lagrangian_not_reward_shaping.md) 与 [对安全约束施加对偶拉格朗日](move_apply_dual_lagrangian_to_safety_constraint.md);与经济学中影子价格同构——$\\lambda_i$ 正是松弛约束 $d_i$ 一单位带来的边际回报,对位 [CPO](paper_cpo_safe_rl.md) 的信赖域投影硬约束。" + }, + "validation:trace_deep_q_network_with_replay_and_target": { + "assumption": "Atari 可写成以 4 帧像素为状态的 MDP,Bellman 最优方程 $Q^*(s,a)=\\mathbb{E}[r+\\gamma\\max_{a'}Q^*(s',a')]$ 给出递推目标,CNN 足以从像素逼近 $Q_\\theta$;关键押注是经验回放把相关样本拉回近似 i.i.d.、目标网络 $Q_{\\theta^-}$ 每 $C$ 步同步以打破\"目标即损失项\"的自举回路,从而把 TD 学习变成对静态目标的稳定回归。", + "failure": "在 Montezuma's Revenge 这类极稀疏奖励任务上失败:$\\epsilon$-greedy 探索覆盖不到关键状态,奖励信号根本不出现——DQN 解决\"信号到了之后如何学\",不解决\"信号本身在哪里\"。该链路缺\"长视野探索\"构件,推不出好奇心驱动;此外 $\\max_{a'}$ 算子带来系统性过估计偏差。", + "experiment": "自变量:是否启用目标网络与经验回放(四种组合:全有/去回放/去目标网/全无);在 CartPole 上从零实现最小 DQN,度量训练曲线的发散频率与最终回报。可证伪点:若去掉目标网络后训练仍稳定收敛,则\"目标网络是打破自举发散的必要构件\"在该任务被推翻。", + "isomorphism": "目标网络的\"慢更新目标\"思想被 [AlphaZero](validation_trace_alpha_zero_self_play_with_mcts_guided_policy.md) 继承用于稳定自举;$\\max$ 算子的乐观偏差与统计学\"赢家诅咒\"(winner's curse)/极值估计上偏同构,正是 [Q-learning 的 max 是乐观偏置](insight_q_learning_max_is_optimistically_biased.md) 所指、并催生 Double DQN。" + }, + "essay:bitter_lesson": { + "assumption": "在 Moore 定律让算力 $C$ 指数变便宜的长期里,唯一长期重要的算法属性是\"能 scale\",于是通用学习+搜索的渐近性能压过注入领域知识的方法:$\\lim_{C\\to\\infty}P_{\\text{general}}(C)>\\lim_{C\\to\\infty}P_{\\text{knowledge}}(C)$。它假定算力会持续指数增长、且对应任务的数据/交互供给能跟上算力扩张。", + "failure": "命题只在 $C\\to\\infty$ 的极限成立——短跑(小算力/小数据,或样本昂贵不可堆的真实驾驶)里排序未必如此;当数据供给先于算力触顶(数据墙),$P_{\\text{general}}$ 的曲线提前饱和,极限论断失去经验支撑。它自身也只是对短期人类经验的概括,当成戒律会陷入\"拒绝注入先验本身即注入'不要注入'先验\"的循环。", + "experiment": "自变量:训练算力/数据规模(沿 [Chinchilla](paper_chinchilla.md) 风格的多档扫描);在同一驾驶任务上同时拟合一个纯端到端通用学习器与一个注入对象级/规则先验的系统,画两条性能-算力曲线。可证伪点:若在覆盖的算力范围内通用学习曲线始终位于知识注入曲线之下且无交叉趋势,则\"通用方法在长跑里胜出\"在该域的可观测区间内不成立。", + "isomorphism": "与 [缩放定律预测能力涌现](insight_scaling_laws_predict_capability_emergence.md) 同构——都把\"算力/数据是主因、结构是次因\"作为经验律;其正面教科书是 [AlphaGo Zero](paper_silver2017_alphazero.md) 用自我对弈搜索取代人类棋谱知识,反面被知识驱动 agent(如 DiLu、Agent-Driver)所质问。" + } +} diff --git a/docs/data/research_lens.json b/docs/data/research_lens.json index 786ce4e..f45aef3 100644 --- a/docs/data/research_lens.json +++ b/docs/data/research_lens.json @@ -334,5 +334,65 @@ "failure": "潜动力学在数据稀疏区失真,CEM 规划会专门挑到模型高估回报的动作序列(model exploitation),在想象里很强、上车就崩。去掉 RSSM 的确定性骨干会让长程预测迅速发散,去掉随机分量又无法建模环境噪声;像素重建损失还会把模型容量耗在视觉细节而非任务相关动力学上。", "experiment": "用 PlaNet 在像素观测任务上展开 $H=1\\ldots 50$ 步,画\"想象累积奖励\"与\"真实累积奖励\"的相关系数随 $H$ 的衰减曲线,定位相关性跌破 0.5 的临界 $H^\\star$;再对比保留/移除 latent overshooting 时 $H^\\star$ 的变化。可证伪点:若 $H^\\star$ 与最终规划性能无关,则\"长程预测保真度主导规划质量\"不成立。", "isomorphism": "等同于模型预测控制(MPC)在学得动力学上滚动优化、卡尔曼滤波维持内部状态做前瞻、以及 [MuZero](paper_muzero.md) 在隐空间做树搜索——都是\"用一个可查询的环境替身把昂贵真实试错搬进廉价内部推演\",是 [世界模型让规划在想象中进行](insight_world_models_let_planning_be_done_in_imagination.md) 的潜空间-规划实例。" + }, + "paradigm:model_free_rl": { + "assumption": "环境的转移结构 $P(s'\\mid s,a)$ 难建模但廉价可采样,因此 Bellman 递推 $Q^*(s,a)=\\mathbb{E}[r+\\gamma\\max_{a'}Q^*(s',a')]$ 这一条信号就足够把策略推到接近最优,无需重建动力学。隐含前提是\"时间换样本\"可接受——典型 DQN 量级要 $2\\times10^8$ 帧交互,且标量奖励 $r$ 被设计得既能表达性能又能表达安全。", + "failure": "在真实驾驶这类样本昂贵、不可任意重置的环境里,$2\\times10^8$ 帧对应数十万小时实车,押注直接破产;同时分布外状态让函数逼近的 $Q$ 估计任意发散,稀疏长视野奖励下 $\\nabla_\\theta J$ 期望近零导致策略梯度\"无信号可学\"。奖励工程一旦写错,无模型 RL 会忠实地把策略优化到错误方向(reward hacking)。", + "experiment": "自变量:仿真器交互预算(帧数,从 $10^6$ 扫到 $2\\times10^8$);在固定的 CARLA 城区路线上比较无模型 PPO 与一个等预算的 [模仿学习](paradigm_imitation_learning.md) 基线的闭环成功率与样本效率曲线。可证伪点:若在任何预算点上无模型 RL 的成功率都不超过同预算 BC,则\"环境反馈值得用海量交互去换\"在该域不成立。", + "isomorphism": "同一结构出现在演化策略/黑箱优化中——都放弃对目标函数内部结构建模,仅靠大量采样估计改进方向;其在测试时的对位是 [搜索替代训练时计算](insight_test_time_compute_substitutes_train_time_via_search.md),即用在线展开补足离线样本效率短板。" + }, + "paradigm:model_based_rl": { + "assumption": "存在比策略本身更紧凑、更易学的环境近似 $\\hat{P}(s'\\mid s,a),\\hat{R}(s,a)$(常压在隐空间 $z_t$ 上),且在 $\\hat{P}$ 下做想象 rollout 得到的虚拟经验对真实策略仍然有用——前提是模型偏差有界,不会被规划/价值迭代循环放大。它愿意用一到两个数量级的真实样本节省,去换这份偏差风险。", + "failure": "长视野展开(>50 步)时单步预测误差几何累积,规划在\"自信的错误\"上做最优化;策略还会主动学会利用模型预测漏洞(model exploitation),在 $\\hat{P}$ 里刷出真实环境不存在的高回报。多智能体场景下把他车塞进 $\\hat{P}$ 的转移函数至今未解,sim-to-real gap 在学得模型上比手工仿真器更隐蔽。", + "experiment": "自变量:想象 rollout 的 horizon $H\\in\\{1,5,15,50,100\\}$;在 [DreamerV3](paper_dreamer_v3.md) 类骨架上固定真实样本预算,度量真实环境回报与\"模型内估计回报减真实回报\"的乐观偏差。可证伪点:若回报随 $H$ 单调上升且乐观偏差不随 $H$ 增长,则\"模型偏差被长展开放大\"这一核心顾虑在该任务不成立。", + "isomorphism": "与 [AlphaZero 自我对弈 + MCTS 引导策略](validation_trace_alpha_zero_self_play_with_mcts_guided_policy.md) 同构——用学得/已知的模型在想象中前瞻搜索,再把搜索结果蒸馏回反应式策略;也对应模型预测控制(MPC)在辨识模型上滚动优化的经典控制范式。" + }, + "paradigm:imitation_learning": { + "assumption": "示教比奖励容易获取,且专家轨迹 $\\{(s_i,a_i)\\}$ 在 i.i.d. 假设下覆盖了足够多的正常状态,使得监督损失 $\\min_\\theta\\sum_i\\ell(\\pi_\\theta(s_i),a_i)$ 下降即对应闭环行为接近专家。它还押注示教是某个隐式奖励的优解,因此\"模仿\"等价于在反推该奖励。", + "failure": "i.i.d. 假设在闭环里崩塌:策略自身的微小动作误差把它带到训练分布外的状态,那里没有标签,误差按 horizon 复合(compounding error),最坏情形误差随步数 $T$ 以 $O(T^2)$ 增长。人类数据几乎不含碰撞,模型学不到\"碰撞前如何避让\";开环 L2 低不蕴含闭环安全,是 driving BC 的核心争论。", + "experiment": "自变量:训练集是否包含 DAgger 风格的策略访问状态再标注(纯 BC vs [DAgger](paper_ross2011_dagger.md));在 nuPlan/CARLA 闭环上度量成功率与脱离里程随展开步数的衰减斜率。可证伪点:若纯 BC 的闭环成功率随 horizon 的衰减斜率与 DAgger 无显著差异,则\"复合误差来自协变量偏移、需在线标注修正\"在该数据规模上不成立。", + "isomorphism": "同一原则边界写在 [模仿学习无法从复合误差中自我恢复](insight_imitation_learning_alone_cannot_recover_from_compounding_errors.md);\"示教压缩隐式奖励\"则与逆强化学习同构([最大熵 IRL](paper_ziebart_max_ent_irl.md)),都把行为数据当作未明示目标函数的证据去反演。" + }, + "paper:rlhf_dpo": { + "assumption": "人类难写完整奖励但能做可靠的成对比较,且偏好服从 Bradley-Terry 模型,使得最优策略对参考策略的对数比恰好就是隐含奖励——DPO 据此把奖励建模与 PPO 合并成封闭形式 $\\mathcal{L}_{\\text{DPO}}=-\\log\\sigma\\big(\\beta\\log\\frac{\\pi_\\theta(y_w|x)}{\\pi_{\\text{ref}}(y_w|x)}-\\beta\\log\\frac{\\pi_\\theta(y_l|x)}{\\pi_{\\text{ref}}(y_l|x)}\\big)$,无需在线采样与显式 reward model。", + "failure": "偏好数据本身带标注者偏见,且\"看起来合理\"的语言解释并不等于物理上安全的轨迹;当目标分布远离参考策略 $\\pi_{\\text{ref}}$ 的支撑、或偏好对里 $y_w,y_l$ 都是低概率离群样本时,$\\beta$ 控制的 KL 锚失效,DPO 易过拟合到表面格式偏好(reward over-optimization)。其离线性质使它无法纠正训练分布之外的新失败模式。", + "experiment": "自变量:$\\beta$(KL 正则强度,扫 $\\{0.01,0.1,0.5\\}$)与偏好对是否含安全反例;在驾驶语言-轨迹偏好集上度量\"语言偏好胜率\"与\"实际闭环碰撞率\"的相关系数。可证伪点:若两者相关系数随训练步数下降甚至转负(语言更受偏好而轨迹更危险),则\"人类成对偏好是安全对齐的可靠监督\"在驾驶域被推翻。", + "isomorphism": "与 [安全 RL 的拉格朗日约束](paper_lagrangian_safe_rl.md) 同构——RLHF 中的安全 reward model 充当 cost critic,$\\beta\\cdot\\mathrm{KL}$ 锚等价于把\"别偏离可信参考\"写成软约束;DPO 的封闭形式则呼应\"少手写奖励、多让学习器从反馈改进\"的 [苦涩的教训](essay_bitter_lesson.md)。" + }, + "paper:diffuser": { + "assumption": "把规划当作对整段未来轨迹的条件生成:从噪声轨迹 $x_T$ 逐步去噪到可行序列 $x_0\\sim p_\\theta(x_{t-1}\\mid x_t,c)$,其中条件 $c$(起点、目标、奖励、约束)像磁铁把随机未来拉向高价值可行解。它押注训练数据的轨迹分布足够覆盖好决策的模式,且引导(guidance)能在采样时把约束注入而不破坏动力学一致性。", + "failure": "多步去噪在实时控制里比一次前向规划慢一两个数量级,30Hz 闭环下采样预算被挤压;当条件 $c$(如硬安全约束或长尾目标)落在训练轨迹分布之外时,guidance 把样本推向数据未覆盖区,生成出动力学上违规或穿越障碍的\"幻觉轨迹\"。离线数据里没有的避险机动,扩散同样生成不出来。", + "experiment": "自变量:去噪步数 $T\\in\\{5,20,50,100\\}$(直接换算为单次规划延迟);在闭环驾驶任务上度量成功率与每决策延迟,并与一次前向的概率规划基线 [VADv2](paper_vadv2.md) 对比。可证伪点:若不存在任何 $T$ 使 Diffuser 在\"成功率不降\"的同时满足实时延迟预算,则\"多样未来的收益足以抵消采样成本\"在驾驶落地中不成立。", + "isomorphism": "与 [扩散策略](paper_diffusion_policy_chi2023.md) 同构(同为 score-based 动作/轨迹采样器),都把决策视作 [生成式建模](paradigm_imitation_learning.md) 而非回归;其\"在执行前于想象中筛掉坏未来\"的动机与 [世界模型](paper_world_models.md) 一脉相承,只是把想象放进轨迹空间而非观测空间。" + }, + "paper:lagrangian_safe_rl": { + "assumption": "安全可写成 CMDP 的折扣代价约束 $\\mathbb{E}[\\sum_t\\gamma^t C_i]\\le d_i$,并通过拉格朗日 $\\mathcal{L}(\\pi,\\lambda)=-J^R(\\pi)+\\sum_i\\lambda_i(J^{C_i}(\\pi)-d_i)$ 的原始-对偶交替($\\theta$ 下降、$\\lambda\\ge0$ 上升)逼近最优——押注违约时 $\\lambda_i$ 上升把策略拉回安全、满足后衰减放开探索,这套软约束能稳定收敛到约束边界。", + "failure": "乘子学习率 $\\eta_\\lambda$ 调不好时出现极限环振荡:一旦违约 $\\lambda$ 暴涨把策略硬拉回安全区,随即 $\\lambda$ 衰减过快又放开、再次违约,循环往复,期间仍产生不安全交互。对约束尺度极敏感——把碰撞代价从 1 改到 100 等价于把 $\\lambda$ 初值除以 100;软约束只在期望意义成立,不保证逐回合零违约。", + "experiment": "自变量:乘子学习率 $\\eta_\\lambda$(对数扫 4 个量级)以及是否换成 [PID-Lagrangian](paper_pid_lagrangian.md) 的反馈更新;在 Safety Gym PointGoal1 上记录约束违反率曲线的振荡幅度与收敛后稳态违约率。可证伪点:若在任意 $\\eta_\\lambda$ 下固定步长对偶上升都能达到 PID-Lagrangian 同等的低振荡,则\"对偶变量需额外反馈控制稳定化\"不成立。", + "isomorphism": "与控制论的积分控制器同构——$\\lambda$ 对约束违反量做积分累加正是 PI 控制器的 I 项,这解释了为何 PID 版本能消除超调;理论根在 [Altman 约束 MDP](paper_altman_constrained_mdp.md),对位是 [CPO](paper_cpo_safe_rl.md) 的信赖域硬约束投影。" + }, + "validation:trace_clipped_policy_gradient_surrogate": { + "assumption": "策略空间不是欧氏空间、单步更新过大会摧毁策略,因此需限制新旧策略的距离;TRPO 的二阶 KL 信赖域 $\\mathbb{E}[\\mathrm{KL}(\\pi_{\\theta_{\\text{old}}},\\pi_\\theta)]\\le\\delta$ 可用对概率比 $r_t(\\theta)=\\pi_\\theta/\\pi_{\\theta_{\\text{old}}}$ 的一阶剪裁 $\\mathrm{clip}(r_t,1-\\epsilon,1+\\epsilon)$ 近似替代——押注这个局部一阶约束足以保持策略改进的实践稳定,省掉共轭梯度与 line search。", + "failure": "剪裁只解决\"单步更新别过大\",不保证整体策略单调改进;在长 horizon、稀疏奖励任务(Montezuma、长程驾驶)上,优势 $A_t$ 本身的梯度信号接近零,剪裁无能为力——它治不了\"信号在哪里\"的问题。该再发明链路缺\"长视野信用分配\"构件,因此推不出 RND、go-explore。", + "experiment": "自变量:剪裁参数 $\\epsilon\\in\\{0.1,0.2,0.3,0.4\\}$;在 MuJoCo HalfCheetah(密集奖励)与一个稀疏奖励长程任务上分别跑 [PPO](paper_schulman2017_ppo.md),度量最终回报与训练稳定性。可证伪点:若调大 $\\epsilon$ 能让稀疏奖励任务回报显著上升,则\"剪裁解决稳定性、不解决信号缺失\"的判断在该任务被推翻。", + "isomorphism": "与近端点法/邻近梯度(proximal methods)同构——都在每步给更新加一个\"别离当前点太远\"的邻近罚项以换取稳定;剪裁这一思想被 [IQL](paper_iql.md) 的优势加权回归继承进离线 RL。" + }, + "validation:trace_safe_rl_via_lagrangian_constrained_optimization": { + "assumption": "标量奖励无法稳健表达安全(策略可用高 reward 抵消碰撞惩罚),必须改用 CMDP:在奖励 $R$ 之外定义代价 $C_i$ 与阈值 $d_i$,再用拉格朗日 $\\mathcal{L}(\\pi,\\lambda)=\\mathbb{E}_\\pi[R]-\\sum_i\\lambda_i(\\mathbb{E}_\\pi[C_i]-d_i)$ 把硬约束化软,原始变量用 PPO 剪裁目标优化、对偶变量 $\\lambda_i\\leftarrow[\\lambda_i+\\eta_\\lambda(\\mathbb{E}_\\pi[C_i]-d_i)]^+$ 在线自适应。", + "failure": "乘子学习率失调引发振荡——违约后 $\\lambda$ 暴涨、策略被强拉回安全、$\\lambda$ 又衰减过快,循环反复;该链路缺\"对偶变量稳定化\"构件,给出原理性正确解但工程稳定性需额外反馈控制,因此推不出 PID-Lagrangian。软约束仅在期望意义满足,训练期内仍有逐回合违约,不适合零容忍安全场景。", + "experiment": "自变量:cost critic 的目标阈值 $d_1$(碰撞代价预算,扫多档);在 CARLA 安全 RL 任务上把\"不碰撞\"设为 $C_1$、\"不违规\"设为 $C_2$,度量 $\\lambda_1$ 曲线、约束违反率与最终任务回报的帕累托前沿。可证伪点:若收紧 $d_1$ 时违约率不随之单调下降(对偶上升未能把策略压向约束边界),则\"拉格朗日对偶能实现可控的安全-性能权衡\"在该域不成立。", + "isomorphism": "落地 [安全靠约束对偶而非奖励塑形](insight_safety_emerges_from_constraint_lagrangian_not_reward_shaping.md) 与 [对安全约束施加对偶拉格朗日](move_apply_dual_lagrangian_to_safety_constraint.md);与经济学中影子价格同构——$\\lambda_i$ 正是松弛约束 $d_i$ 一单位带来的边际回报,对位 [CPO](paper_cpo_safe_rl.md) 的信赖域投影硬约束。" + }, + "validation:trace_deep_q_network_with_replay_and_target": { + "assumption": "Atari 可写成以 4 帧像素为状态的 MDP,Bellman 最优方程 $Q^*(s,a)=\\mathbb{E}[r+\\gamma\\max_{a'}Q^*(s',a')]$ 给出递推目标,CNN 足以从像素逼近 $Q_\\theta$;关键押注是经验回放把相关样本拉回近似 i.i.d.、目标网络 $Q_{\\theta^-}$ 每 $C$ 步同步以打破\"目标即损失项\"的自举回路,从而把 TD 学习变成对静态目标的稳定回归。", + "failure": "在 Montezuma's Revenge 这类极稀疏奖励任务上失败:$\\epsilon$-greedy 探索覆盖不到关键状态,奖励信号根本不出现——DQN 解决\"信号到了之后如何学\",不解决\"信号本身在哪里\"。该链路缺\"长视野探索\"构件,推不出好奇心驱动;此外 $\\max_{a'}$ 算子带来系统性过估计偏差。", + "experiment": "自变量:是否启用目标网络与经验回放(四种组合:全有/去回放/去目标网/全无);在 CartPole 上从零实现最小 DQN,度量训练曲线的发散频率与最终回报。可证伪点:若去掉目标网络后训练仍稳定收敛,则\"目标网络是打破自举发散的必要构件\"在该任务被推翻。", + "isomorphism": "目标网络的\"慢更新目标\"思想被 [AlphaZero](validation_trace_alpha_zero_self_play_with_mcts_guided_policy.md) 继承用于稳定自举;$\\max$ 算子的乐观偏差与统计学\"赢家诅咒\"(winner's curse)/极值估计上偏同构,正是 [Q-learning 的 max 是乐观偏置](insight_q_learning_max_is_optimistically_biased.md) 所指、并催生 Double DQN。" + }, + "essay:bitter_lesson": { + "assumption": "在 Moore 定律让算力 $C$ 指数变便宜的长期里,唯一长期重要的算法属性是\"能 scale\",于是通用学习+搜索的渐近性能压过注入领域知识的方法:$\\lim_{C\\to\\infty}P_{\\text{general}}(C)>\\lim_{C\\to\\infty}P_{\\text{knowledge}}(C)$。它假定算力会持续指数增长、且对应任务的数据/交互供给能跟上算力扩张。", + "failure": "命题只在 $C\\to\\infty$ 的极限成立——短跑(小算力/小数据,或样本昂贵不可堆的真实驾驶)里排序未必如此;当数据供给先于算力触顶(数据墙),$P_{\\text{general}}$ 的曲线提前饱和,极限论断失去经验支撑。它自身也只是对短期人类经验的概括,当成戒律会陷入\"拒绝注入先验本身即注入'不要注入'先验\"的循环。", + "experiment": "自变量:训练算力/数据规模(沿 [Chinchilla](paper_chinchilla.md) 风格的多档扫描);在同一驾驶任务上同时拟合一个纯端到端通用学习器与一个注入对象级/规则先验的系统,画两条性能-算力曲线。可证伪点:若在覆盖的算力范围内通用学习曲线始终位于知识注入曲线之下且无交叉趋势,则\"通用方法在长跑里胜出\"在该域的可观测区间内不成立。", + "isomorphism": "与 [缩放定律预测能力涌现](insight_scaling_laws_predict_capability_emergence.md) 同构——都把\"算力/数据是主因、结构是次因\"作为经验律;其正面教科书是 [AlphaGo Zero](paper_silver2017_alphazero.md) 用自我对弈搜索取代人类棋谱知识,反面被知识驱动 agent(如 DiLu、Agent-Driver)所质问。" } } diff --git a/labs/research/exp_overestimation_bias.py b/labs/research/exp_overestimation_bias.py new file mode 100644 index 0000000..9dd7881 --- /dev/null +++ b/labs/research/exp_overestimation_bias.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +r"""Code-verify the lens of `insight:q_learning_max_is_optimistically_biased`. + +The lens claims: taking $\max_a$ over noisy action-value estimates is +systematically optimistic, because $\mathbb{E}[\max_a \hat Q(s,a)] \ge +\max_a \mathbb{E}[\hat Q(s,a)]$ (Jensen, since $\max$ is convex), and the bias +grows with the number of actions and the estimation noise; decoupling +"which action" from "its value" (the double estimator) removes it. + +Falsifier (from the lens): if the single-estimator bias does NOT grow with the +action count, or the double estimator is not materially less biased, the claim +is wrong. + +Setup (deliberately minimal and exactly analysable): all true action values are +equal, $q^\*(a)=0$, so $\max_a \mathbb{E}[\hat Q(a)] = 0$ and any positive +expected estimate is pure overestimation. Each action's value is estimated from +`m` noisy samples ~ N(0, sigma^2). We sweep the action count `n` and report the +mean estimator over many trials. This is the driving-relevant micro-version of +why vanilla DQN over-values actions in large/branchy action spaces and why +Double-DQN was introduced. + +Pure standard library; deterministic; CPU-only. Run: + python3 labs/research/exp_overestimation_bias.py +""" +from __future__ import annotations + +import random +from pathlib import Path + +from harness import Hypothesis, Study, mean + +HYP = Hypothesis( + node="insight:q_learning_max_is_optimistically_biased", + claim="对等价动作的噪声估计取 max 会产生正偏差,且偏差随动作数 n 增长;把“选动作”与“估其值”解耦的双估计器几乎消除该偏差。", + independent="动作数 n (number of equally-valued actions)", + metric="期望估计值 E[V](真值为 0,越大=越乐观)", + falsifier="若单估计器偏差不随 n 增长,或双估计器偏差未显著小于单估计器,则该洞察被推翻。", +) + + +def single_estimator(n: int, m: int, sigma: float, rng: random.Random) -> float: + """max_a mean of m noisy samples of a zero-mean value.""" + return max(mean(rng.gauss(0.0, sigma) for _ in range(m)) for _ in range(n)) + + +def double_estimator(n: int, m: int, sigma: float, rng: random.Random) -> float: + """Split samples: pick argmax on set A, evaluate that action on set B.""" + half = max(1, m // 2) + means_a, means_b = [], [] + for _ in range(n): + means_a.append(mean(rng.gauss(0.0, sigma) for _ in range(half))) + means_b.append(mean(rng.gauss(0.0, sigma) for _ in range(half))) + a_star = max(range(n), key=lambda i: means_a[i]) + return means_b[a_star] + + +def run(seed: int = 0, trials: int = 4000, m: int = 8, sigma: float = 1.0) -> Study: + study = Study(hypothesis=HYP, seed=seed) + rng = random.Random(seed) + for n in (2, 4, 8, 16, 32, 64): + s = mean(single_estimator(n, m, sigma, rng) for _ in range(trials)) + d = mean(double_estimator(n, m, sigma, rng) for _ in range(trials)) + study.record("single max (vanilla Q)", n, s) + study.record("double estimator (Double-Q)", n, d) + return study + + +def main() -> int: + study = run() + single = dict(study.series["single max (vanilla Q)"]) + double = dict(study.series["double estimator (Double-Q)"]) + ns = sorted(single) + grows = single[ns[-1]] > single[ns[0]] + 1e-3 + double_smaller = all(abs(double[n]) < single[n] for n in ns if single[n] > 1e-3) + survived = grows and double_smaller + verdict = ("洞察成立:单估计器偏差随动作数单调上升,双估计器把它压到接近 0。" + if survived else "洞察未通过本次检验(见下)。") + detail = ( + f"- 单估计器偏差从 n={ns[0]} 的 {single[ns[0]]:.3f} 升到 n={ns[-1]} 的 {single[ns[-1]]:.3f}" + f"(真值为 0,全部是乐观高估)。\n" + f"- 双估计器在同一范围内保持在 [{min(double.values()):.3f}, {max(double.values()):.3f}]," + f"几乎无偏。\n" + f"- 自变量随动作数增长印证了 Jensen 间隙 $\\mathbb{{E}}[\\max]\\ge\\max\\mathbb{{E}}$ 的方向;" + f"对自动驾驶里动作空间大、Q 估计有噪声的价值方法,这正是 Double-DQN 一类解耦估计的动机。\n" + f"- 复现:`python3 labs/research/exp_overestimation_bias.py`(seed={study.seed},确定性)。" + ) + out = Path(__file__).resolve().parent / "results" / "overestimation_bias" + path = study.write(out, verdict, detail) + print(study.results_table()) + print(verdict) + print(f"wrote {path.relative_to(Path(__file__).resolve().parents[2])} + figure.svg") + return 0 if survived else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/labs/research/harness.py b/labs/research/harness.py new file mode 100644 index 0000000..1c3a6a2 --- /dev/null +++ b/labs/research/harness.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +"""A tiny, dependency-free research harness. + +The atlas points every core node at a *falsifiable* next experiment (the +"研究透镜 / Research lens"). This harness is the other half: it turns such a +hypothesis into a runnable study that sweeps one independent variable, records a +metric, decides whether the hypothesis survived its own falsifier, and emits a +results table, an SVG figure, and a findings note. + +Design choices: + * Pure standard library (random/math/statistics) — runs on a free CPU, in CI, + or in Colab with no install, matching the rest of labs/. + * Deterministic: every study fixes a seed, so a result is reproducible and a + reviewer can re-run it byte-for-byte. + * The unit of work is a Hypothesis tied to a graph node id, so a study is + traceable back to the exact place in the atlas it came from. +""" +from __future__ import annotations + +import math +import statistics +from dataclasses import dataclass, field +from pathlib import Path +from typing import Callable + + +@dataclass +class Hypothesis: + """A falsifiable claim attached to a node in the atlas.""" + node: str # graph node id this experiment tests, e.g. "insight:..." + claim: str # the prediction in one sentence + independent: str # the variable being swept (with units) + metric: str # what is measured + falsifier: str # the condition that, if observed, refutes the claim + + +@dataclass +class Study: + hypothesis: Hypothesis + seed: int = 0 + # series name -> list of (x, y) points, filled by run() + series: dict[str, list[tuple[float, float]]] = field(default_factory=dict) + notes: list[str] = field(default_factory=list) + + def record(self, series_name: str, x: float, y: float) -> None: + self.series.setdefault(series_name, []).append((float(x), float(y))) + + # ---- reporting ------------------------------------------------------- + def results_table(self) -> str: + xs = sorted({x for pts in self.series.values() for x, _ in pts}) + names = list(self.series) + head = "| " + " | ".join([self.hypothesis.independent] + names) + " |\n" + head += "|" + "|".join(["---"] * (len(names) + 1)) + "|\n" + lookup = {n: dict(pts) for n, pts in self.series.items()} + rows = [] + for x in xs: + cells = [f"{x:g}"] + [ + (f"{lookup[n].get(x):.4f}" if x in lookup[n] else "—") for n in names + ] + rows.append("| " + " | ".join(cells) + " |") + return head + "\n".join(rows) + "\n" + + def svg(self, width: int = 640, height: int = 360, pad: int = 48) -> str: + pts_all = [(x, y) for pts in self.series.values() for x, y in pts] + if not pts_all: + return "" + xmin = min(x for x, _ in pts_all); xmax = max(x for x, _ in pts_all) + ymin = min(y for _, y in pts_all); ymax = max(y for _, y in pts_all) + ymin = min(ymin, 0.0) + if xmax == xmin: xmax = xmin + 1 + if ymax == ymin: ymax = ymin + 1 + def sx(x): return pad + (x - xmin) / (xmax - xmin) * (width - 2 * pad) + def sy(y): return height - pad - (y - ymin) / (ymax - ymin) * (height - 2 * pad) + palette = ["#6cb1ff", "#f97316", "#a78bfa", "#5fd38d", "#fcd34d"] + out = [f''] + out.append(f'') + # zero line + axes + y0 = sy(0.0) + out.append(f'') + out.append(f'') + out.append(f'') + out.append(f'{_esc(self.hypothesis.independent)}') + out.append(f'{_esc(self.hypothesis.metric)}') + for i, (name, pts) in enumerate(self.series.items()): + color = palette[i % len(palette)] + pts_sorted = sorted(pts) + d = " ".join(f"{'M' if j==0 else 'L'}{sx(x):.1f},{sy(y):.1f}" for j, (x, y) in enumerate(pts_sorted)) + out.append(f'') + for x, y in pts_sorted: + out.append(f'') + ly = pad + 14 + i * 18 + out.append(f'') + out.append(f'{_esc(name)}') + out.append("") + return "\n".join(out) + + def findings(self, verdict: str, detail: str) -> str: + h = self.hypothesis + return ( + f"# Findings — {h.node}\n\n" + f"> 这是由 [研究透镜] 中的可证伪实验自动跑出的结果,可被任何人原样复现" + f"(固定随机种子 seed={self.seed})。\n\n" + f"**被检验的论断 / Claim.** {h.claim}\n\n" + f"**自变量 / Independent variable.** {h.independent}\n\n" + f"**度量 / Metric.** {h.metric}\n\n" + f"**证伪条件 / Falsifier.** {h.falsifier}\n\n" + f"## 结果 / Results\n\n{self.results_table()}\n" + f"![figure](figure.svg)\n\n" + f"## 结论 / Verdict\n\n**{verdict}**\n\n{detail}\n" + ) + + def write(self, out_dir: str | Path, verdict: str, detail: str) -> Path: + d = Path(out_dir) + d.mkdir(parents=True, exist_ok=True) + (d / "figure.svg").write_text(self.svg(), encoding="utf-8") + path = d / "findings.md" + path.write_text(self.findings(verdict, detail), encoding="utf-8") + return path + + +def _esc(s: str) -> str: + return (str(s).replace("&", "&").replace("<", "<").replace(">", ">")) + + +def mean(xs) -> float: + return statistics.fmean(xs) diff --git a/labs/research/results/overestimation_bias/figure.svg b/labs/research/results/overestimation_bias/figure.svg new file mode 100644 index 0000000..74562be --- /dev/null +++ b/labs/research/results/overestimation_bias/figure.svg @@ -0,0 +1,26 @@ + + + + + +动作数 n (number of equally-valued actions) +期望估计值 E[V](真值为 0,越大=越乐观) + + + + + + + + +single max (vanilla Q) + + + + + + + + +double estimator (Double-Q) + \ No newline at end of file diff --git a/labs/research/results/overestimation_bias/findings.md b/labs/research/results/overestimation_bias/findings.md new file mode 100644 index 0000000..01453cd --- /dev/null +++ b/labs/research/results/overestimation_bias/findings.md @@ -0,0 +1,33 @@ +# Findings — insight:q_learning_max_is_optimistically_biased + +> 这是由 [研究透镜] 中的可证伪实验自动跑出的结果,可被任何人原样复现(固定随机种子 seed=0)。 + +**被检验的论断 / Claim.** 对等价动作的噪声估计取 max 会产生正偏差,且偏差随动作数 n 增长;把“选动作”与“估其值”解耦的双估计器几乎消除该偏差。 + +**自变量 / Independent variable.** 动作数 n (number of equally-valued actions) + +**度量 / Metric.** 期望估计值 E[V](真值为 0,越大=越乐观) + +**证伪条件 / Falsifier.** 若单估计器偏差不随 n 增长,或双估计器偏差未显著小于单估计器,则该洞察被推翻。 + +## 结果 / Results + +| 动作数 n (number of equally-valued actions) | single max (vanilla Q) | double estimator (Double-Q) | +|---|---|---| +| 2 | 0.2046 | -0.0082 | +| 4 | 0.3700 | 0.0024 | +| 8 | 0.4995 | -0.0030 | +| 16 | 0.6229 | 0.0005 | +| 32 | 0.7329 | 0.0017 | +| 64 | 0.8281 | -0.0037 | + +![figure](figure.svg) + +## 结论 / Verdict + +**洞察成立:单估计器偏差随动作数单调上升,双估计器把它压到接近 0。** + +- 单估计器偏差从 n=2.0 的 0.205 升到 n=64.0 的 0.828(真值为 0,全部是乐观高估)。 +- 双估计器在同一范围内保持在 [-0.008, 0.002],几乎无偏。 +- 自变量随动作数增长印证了 Jensen 间隙 $\mathbb{E}[\max]\ge\max\mathbb{E}$ 的方向;对自动驾驶里动作空间大、Q 估计有噪声的价值方法,这正是 Double-DQN 一类解耦估计的动机。 +- 复现:`python3 labs/research/exp_overestimation_bias.py`(seed=0,确定性)。 diff --git a/research/drafts/insight_offline_rl_is_actually_constrained_dynamic_programming.md b/research/drafts/insight_offline_rl_is_actually_constrained_dynamic_programming.md new file mode 100644 index 0000000..4ce0d0e --- /dev/null +++ b/research/drafts/insight_offline_rl_is_actually_constrained_dynamic_programming.md @@ -0,0 +1,42 @@ +# 论文骨架 · 由「离线 RL 本质上是带约束的动态规划」生成 + +> 这是一份**可编辑的论文草稿骨架**,由图谱节点 `insight:offline_rl_is_actually_constrained_dynamic_programming` 的研究透镜与其关系网络自动组装。每一节都被钉在一个具体、可证伪的论断与它的上下文文献上——用来消除空白页,而不是替代你的研究。 + +## 摘要骨架 / Abstract skeleton +- **问题**:当最优动作根本不在支撑内(日志里从未出现"紧急左打方向"),没有任何离线算法能学出它——这是信息缺失,不是优化失败。另一端,惩罚强度 $\alpha$ 过大时连支撑内的 Bellman 备份也被压平,策略退化为行为克隆;$\alpha$ 的可用区间通常很窄,需要在留出集上扫调。 +- **关键观察**:数据集 $\mathcal{D}$ 的状态-动作支撑 $\mathrm{supp}(\pi_\beta)$ 已经覆盖了通向高回报所必需的关键动作;惩罚项只压制支撑外的乐观,而不伤害支撑内的价值传播。换句话说,约束动态规划能达到的上界,被数据覆盖范围而非算法本身钉死。 +- **做法**:(填:你用下方“方法骨架”中的原语如何组合出新方法) +- **可证伪的主张**:固定一份驾驶日志,按动作类型系统性"挖洞",剔除 5% / 10% / 20% 的支撑,测 [CQL](paper_cql.md) 与 [IQL](paper_iql.md) 的闭环成功率随支撑覆盖率的衰减曲线,再与数据总量做对照回归。可证伪的预测:闭环性能由覆盖率单调决定、与总量近似无关;若总量能补偿覆盖缺失,则本洞察被推翻。 + +## 1. 研究问题 / Research question +固定一份驾驶日志,按动作类型系统性"挖洞",剔除 5% / 10% / 20% 的支撑,测 [CQL](paper_cql.md) 与 [IQL](paper_iql.md) 的闭环成功率随支撑覆盖率的衰减曲线,再与数据总量做对照回归。可证伪的预测:闭环性能由覆盖率单调决定、与总量近似无关;若总量能补偿覆盖缺失,则本洞察被推翻。 + +## 2. 背景与定位 / Related work(来自关系网络) +(该节点邻接稀疏;先在图谱里补边,定位会更准。) + +## 3. 关键假设 / Load-bearing assumption +数据集 $\mathcal{D}$ 的状态-动作支撑 $\mathrm{supp}(\pi_\beta)$ 已经覆盖了通向高回报所必需的关键动作;惩罚项只压制支撑外的乐观,而不伤害支撑内的价值传播。换句话说,约束动态规划能达到的上界,被数据覆盖范围而非算法本身钉死。 + +## 4. 现有方法的失效边界 / The gap +当最优动作根本不在支撑内(日志里从未出现"紧急左打方向"),没有任何离线算法能学出它——这是信息缺失,不是优化失败。另一端,惩罚强度 $\alpha$ 过大时连支撑内的 Bellman 备份也被压平,策略退化为行为克隆;$\alpha$ 的可用区间通常很窄,需要在留出集上扫调。 + +## 5. 方法骨架 / Method(可复用的研究原语) +(该节点未直接连到方法学原语 `move:*`;从第 2 节的先修工作里挑组件,或在图谱里补 `composes` 边。) + +## 6. 跨域先验 / Cross-domain prior +同一结构出现在监督学习的"经验风险 $\le$ 真实风险 + 复杂度项"、离策略评估的 importance-sampling 权重截断、模型预测控制的可行域约束 $u\in\mathcal{U}$、推荐系统的 propensity clipping——都是"在可信区域内最优化、对区域外保持悲观"。 + +## 7. 实验设计 / Experiment plan +固定一份驾驶日志,按动作类型系统性"挖洞",剔除 5% / 10% / 20% 的支撑,测 [CQL](paper_cql.md) 与 [IQL](paper_iql.md) 的闭环成功率随支撑覆盖率的衰减曲线,再与数据总量做对照回归。可证伪的预测:闭环性能由覆盖率单调决定、与总量近似无关;若总量能补偿覆盖缺失,则本洞察被推翻。 + +可复现脚手架:`labs/research/harness.py` 提供固定随机种子的扫描-度量-出图-下结论流水线;参见已跑通的范例 `labs/research/exp_overestimation_bias.py`(它把一条研究透镜的论断用代码验了一遍)。 + +## 8. 可复现性 / Reproducibility +- 暂无 `implements` 边指向现成代码;用第 7 节的 harness 起一个最小可复现实验。 + +## 9. 证伪判据 / Falsification criteria +明确写下“看到什么结果就说明本主张错了”。一个无法被证伪的主张不值得投稿—— +固定一份驾驶日志,按动作类型系统性"挖洞",剔除 5% / 10% / 20% 的支撑,测 [CQL](paper_cql.md) 与 [IQL](paper_iql.md) 的闭环成功率随支撑覆盖率的衰减曲线,再与数据总量做对照回归。可证伪的预测:闭环性能由覆盖率单调决定、与总量近似无关;若总量能补偿覆盖缺失,则本洞察被推翻。 + +--- +seeded from atlas node `insight:offline_rl_is_actually_constrained_dynamic_programming` · 关系网络 + 研究透镜自动组装 · 由 tools/scaffold_paper.py 生成 diff --git a/research/drafts/move_treat_planning_as_conditional_generation.md b/research/drafts/move_treat_planning_as_conditional_generation.md new file mode 100644 index 0000000..09520c9 --- /dev/null +++ b/research/drafts/move_treat_planning_as_conditional_generation.md @@ -0,0 +1,44 @@ +# 论文骨架 · 由「把规划看作条件生成问题」生成 + +> 这是一份**可编辑的论文草稿骨架**,由图谱节点 `move:treat_planning_as_conditional_generation` 的研究透镜与其关系网络自动组装。每一节都被钉在一个具体、可证伪的论断与它的上下文文献上——用来消除空白页,而不是替代你的研究。 + +## 摘要骨架 / Abstract skeleton +- **问题**:模仿专家会把专家偶发的危险样本一并学进,需 reward-aware 训练或后置安全过滤;扩散采样几十步在车端跑不动,要靠一致性模型或蒸馏压步数;遇到训练未见的条件组合(罕见路口拓扑),模型会强行生成熟悉模式造成无声失效。 +- **关键观察**:专家轨迹的经验分布里"好轨迹的形状"可被生成模型 $p_\theta(\tau\mid s_0,g,\mathcal{C})$ 直接学到,从而以采样替代显式非凸优化。相信整条分布的输出比单点最优更有用——尤其在多模态决策处。 +- **做法**:(填:你用下方“方法骨架”中的原语如何组合出新方法) +- **可证伪的主张**:在分叉路口构造双峰示教(直行/让行各半),对比高斯策略与 [扩散策略](paper_diffusion_policy_chi2023.md) 复现双峰的能力:测生成轨迹的模态覆盖率与"取均值塌缩到道路中央"的发生率。可证伪点:若高斯策略也能避免模态塌缩,则生成式规划在多模态上的优势被推翻。 + +## 1. 研究问题 / Research question +在分叉路口构造双峰示教(直行/让行各半),对比高斯策略与 [扩散策略](paper_diffusion_policy_chi2023.md) 复现双峰的能力:测生成轨迹的模态覆盖率与"取均值塌缩到道路中央"的发生率。可证伪点:若高斯策略也能避免模态塌缩,则生成式规划在多模态上的优势被推翻。 + +## 2. 背景与定位 / Related work(来自关系网络) +(该节点邻接稀疏;先在图谱里补边,定位会更准。) + +## 3. 关键假设 / Load-bearing assumption +专家轨迹的经验分布里"好轨迹的形状"可被生成模型 $p_\theta(\tau\mid s_0,g,\mathcal{C})$ 直接学到,从而以采样替代显式非凸优化。相信整条分布的输出比单点最优更有用——尤其在多模态决策处。 + +## 4. 现有方法的失效边界 / The gap +模仿专家会把专家偶发的危险样本一并学进,需 reward-aware 训练或后置安全过滤;扩散采样几十步在车端跑不动,要靠一致性模型或蒸馏压步数;遇到训练未见的条件组合(罕见路口拓扑),模型会强行生成熟悉模式造成无声失效。 + +## 5. 方法骨架 / Method(可复用的研究原语) +把以下原语按你的问题重新编排,就是方法章的骨架: +- **在推理时用分类器梯度引导扩散采样** — 在扩散模型的反向采样过程中按某个外部代价函数的梯度对样本做扰动,从而把碰撞、舒适度、目标到达等约束在不重新训练模型的情况下注入轨迹生成。 +- **把预训练大语言模型当作动作序列先验** — 用预训练大语言模型在符号或代码层面提出候选动作序列,再交给数值优化器或仿真器评估。这种动作把 LLM 的常识与场景理解嫁接到了细粒度控制,是 LLM 规划器的关键构件。 + +## 6. 跨域先验 / Cross-domain prior +与把检测当 [集合预测](move_treat_detection_as_set_prediction_with_learnable_queries.md)、把决策当 [序列建模](paradigm_sequence_modeling_for_decision.md) 是同一次"从判别/优化转向生成"的范式迁移;也对应文本生成、分子设计里"从分布采样可行解"的思路。 + +## 7. 实验设计 / Experiment plan +在分叉路口构造双峰示教(直行/让行各半),对比高斯策略与 [扩散策略](paper_diffusion_policy_chi2023.md) 复现双峰的能力:测生成轨迹的模态覆盖率与"取均值塌缩到道路中央"的发生率。可证伪点:若高斯策略也能避免模态塌缩,则生成式规划在多模态上的优势被推翻。 + +可复现脚手架:`labs/research/harness.py` 提供固定随机种子的扫描-度量-出图-下结论流水线;参见已跑通的范例 `labs/research/exp_overestimation_bias.py`(它把一条研究透镜的论断用代码验了一遍)。 + +## 8. 可复现性 / Reproducibility +- 暂无 `implements` 边指向现成代码;用第 7 节的 harness 起一个最小可复现实验。 + +## 9. 证伪判据 / Falsification criteria +明确写下“看到什么结果就说明本主张错了”。一个无法被证伪的主张不值得投稿—— +在分叉路口构造双峰示教(直行/让行各半),对比高斯策略与 [扩散策略](paper_diffusion_policy_chi2023.md) 复现双峰的能力:测生成轨迹的模态覆盖率与"取均值塌缩到道路中央"的发生率。可证伪点:若高斯策略也能避免模态塌缩,则生成式规划在多模态上的优势被推翻。 + +--- +seeded from atlas node `move:treat_planning_as_conditional_generation` · 关系网络 + 研究透镜自动组装 · 由 tools/scaffold_paper.py 生成 diff --git a/research/drafts/paper_2212.10156.md b/research/drafts/paper_2212.10156.md new file mode 100644 index 0000000..3b1cada --- /dev/null +++ b/research/drafts/paper_2212.10156.md @@ -0,0 +1,68 @@ +# 论文骨架 · 由「UniAD(统一规划导向 AD)」生成 + +> 这是一份**可编辑的论文草稿骨架**,由图谱节点 `paper:2212.10156` 的研究透镜与其关系网络自动组装。每一节都被钉在一个具体、可证伪的论断与它的上下文文献上——用来消除空白页,而不是替代你的研究。 + +## 摘要骨架 / Abstract skeleton +- **问题**:规划导向的联合训练让梯度被最终规划损失主导,可能牺牲上游子任务在其自身指标上的精度;query 总线一旦在某一环退化,误差会沿链路传播。开环 nuScenes 指标与真实闭环安全的相关性也受质疑,漂亮的位移误差未必转化为闭环成功率。 +- **关键观察**:把检测、跟踪、建图、运动预测、占据预测全部用共享的 query 串成一条以"规划为最终目标"的可微管线,相信各子任务的中间表征若都服务于规划,则联合训练优于各自为政。query 充当模块间无损的信息总线。 +- **做法**:(填:你用下方“方法骨架”中的原语如何组合出新方法) +- **可证伪的主张**:复刻 [lab03 的 query 直觉](../../labs/lab03_uniad_query_intuition.ipynb),逐个冻结上游任务头,测规划 L2 与碰撞率的变化,量化每个子任务对规划的边际贡献。可证伪点:若冻结运动预测头后规划几乎不退化,则"预测必须进规划闭环"的设计前提需重估。 + +## 1. 研究问题 / Research question +复刻 [lab03 的 query 直觉](../../labs/lab03_uniad_query_intuition.ipynb),逐个冻结上游任务头,测规划 L2 与碰撞率的变化,量化每个子任务对规划的边际贡献。可证伪点:若冻结运动预测头后规划几乎不退化,则"预测必须进规划闭环"的设计前提需重估。 + +## 2. 背景与定位 / Related work(来自关系网络) +**站在什么之上(先修基础)** +- [Bench2Drive(端到端闭环 CARLA 基准)] (`paper:bench2drive`) — Bench2Drive 在 CARLA Leaderboard 2.0 之上提供 44 个能力分桶与统一训练协议,使 UniAD、VAD 等端到端模型可在同一闭环环境下被公平比较,… +- [把检测任务转化为学习查询集合的预测问题] (`move:treat_detection_as_set_prediction_with_learnable_queries`) — 用一组固定数量的可学习查询向量代替密集锚框,每个查询通过注意力机制竞争性地"认领"一个目标,最后由匈牙利匹配与真值对齐。这一移动消除了非极大值抑制等手工后处理,使得检测器变成纯可微… +- [通过共享隐表示使整条管线可微] (`move:make_pipeline_differentiable_via_shared_latent`) — 把"感知-预测-规划"等本来用规则连接的模块,改用共享的隐表示(查询、鸟瞰特征、占用体素)做接口,让梯度从最后的任务损失一直反传到原始图像。这是 UniAD、VAD 等端到端方案的… +- [在多个下游任务之间共享同一组查询] (`move:share_queries_across_multiple_tasks`) — 让检测、跟踪、地图、占用、规划等任务复用同一组对象级查询,把多任务联合训练变成天然的隐表示对齐器。这一移动是 UniAD"以规划为目的统一感知"的方法论核心,也是 PETRv2 等… +- [DETR(端到端检测)] (`paper:carion2020`) +- [BEVFormer(时空 BEV transformer)] (`paper:li2022bevformer`) +- [CARLA / nuScenes / NAVSIM / Bench2Drive] (`paper:ad_benchmarks`) + +**它延伸/喂入的工作** +- [VADv2(向量化端到端 + 概率规划)] (`paper:vadv2`) +- [DriveVLM / DriveVLM-Dual] (`paper:2402.12289`) +- [DINOv3] (`paper:2508.10104`) +- [BEVFormer(时空 BEV transformer)] (`paper:li2022bevformer`) +- [BEVFusion(鸟瞰特征空间的多模态融合)] (`paper:bevfusion`) — BEVFusion 把相机分支的鸟瞰特征和点云分支的鸟瞰特征在同一个鸟瞰栅格上对齐后再融合,而不是在感知头处晚融合或在图像-点云层面早融合。这种统一的中间表示使得任一模态失效时另一… +- [StreamPETR(流式查询的长时序三维感知)] (`paper:streampetr`) — StreamPETR 把 PETR 的目标查询做成跨帧持续传播的隐状态:每个查询不仅做当前帧的检测,还把更新后的状态传到下一帧继续推理。它把时序融合从"对齐特征图"上升到"对齐对象… +- [Tesla 占用网络(占用栅格替代检测框)] (`paper:occupancy_networks_tesla`) — Tesla 在 AI Day 公开的占用网络把场景表示从"对每个已知类别画三维框"换成"对空间每一个体素预测是否被占用以及流速",从而天然地处理未知类别物体和不规则形状。这一表示让… + +**平行替代路线(对照基线)** +- [Tesla AI Day] (`paper:tesla_ai_day`) + +**对照张力(必须讲清差异)** +- [PlanT(对象级规划 transformer)] (`paper:2210.14222`) + +## 3. 关键假设 / Load-bearing assumption +把检测、跟踪、建图、运动预测、占据预测全部用共享的 query 串成一条以"规划为最终目标"的可微管线,相信各子任务的中间表征若都服务于规划,则联合训练优于各自为政。query 充当模块间无损的信息总线。 + +## 4. 现有方法的失效边界 / The gap +规划导向的联合训练让梯度被最终规划损失主导,可能牺牲上游子任务在其自身指标上的精度;query 总线一旦在某一环退化,误差会沿链路传播。开环 nuScenes 指标与真实闭环安全的相关性也受质疑,漂亮的位移误差未必转化为闭环成功率。 + +## 5. 方法骨架 / Method(可复用的研究原语) +把以下原语按你的问题重新编排,就是方法章的骨架: +- **在多个下游任务之间共享同一组查询** — 让检测、跟踪、地图、占用、规划等任务复用同一组对象级查询,把多任务联合训练变成天然的隐表示对齐器。这一移动是 UniAD"以规划为目的统一感知"的方法论核心,也是 PETRv2 等… +- **把检测任务转化为学习查询集合的预测问题** — 用一组固定数量的可学习查询向量代替密集锚框,每个查询通过注意力机制竞争性地"认领"一个目标,最后由匈牙利匹配与真值对齐。这一移动消除了非极大值抑制等手工后处理,使得检测器变成纯可微… +- **通过共享隐表示使整条管线可微** — 把"感知-预测-规划"等本来用规则连接的模块,改用共享的隐表示(查询、鸟瞰特征、占用体素)做接口,让梯度从最后的任务损失一直反传到原始图像。这是 UniAD、VAD 等端到端方案的… +- **share_object_query_across_tasks_for_e2e_planning** + +## 6. 跨域先验 / Cross-domain prior +query 总线与 [DETR](paper_carion2020.md) 的 object query、感知里把任务统一到一组可学习查询是同一招;"以下游目标统领上游表征"则与端到端语音识别取代手工对齐、可微渲染统一图形学子任务同构。 + +## 7. 实验设计 / Experiment plan +复刻 [lab03 的 query 直觉](../../labs/lab03_uniad_query_intuition.ipynb),逐个冻结上游任务头,测规划 L2 与碰撞率的变化,量化每个子任务对规划的边际贡献。可证伪点:若冻结运动预测头后规划几乎不退化,则"预测必须进规划闭环"的设计前提需重估。 + +可复现脚手架:`labs/research/harness.py` 提供固定随机种子的扫描-度量-出图-下结论流水线;参见已跑通的范例 `labs/research/exp_overestimation_bias.py`(它把一条研究透镜的论断用代码验了一遍)。 + +## 8. 可复现性 / Reproducibility +- 已有实现:[lab03 UniAD query intuition] (`lab:lab03`) + +## 9. 证伪判据 / Falsification criteria +明确写下“看到什么结果就说明本主张错了”。一个无法被证伪的主张不值得投稿—— +复刻 [lab03 的 query 直觉](../../labs/lab03_uniad_query_intuition.ipynb),逐个冻结上游任务头,测规划 L2 与碰撞率的变化,量化每个子任务对规划的边际贡献。可证伪点:若冻结运动预测头后规划几乎不退化,则"预测必须进规划闭环"的设计前提需重估。 + +--- +seeded from atlas node `paper:2212.10156` · 关系网络 + 研究透镜自动组装 · 由 tools/scaffold_paper.py 生成 diff --git a/research/drafts/paradigm_differentiable_end_to_end_imitation.md b/research/drafts/paradigm_differentiable_end_to_end_imitation.md new file mode 100644 index 0000000..3017708 --- /dev/null +++ b/research/drafts/paradigm_differentiable_end_to_end_imitation.md @@ -0,0 +1,44 @@ +# 论文骨架 · 由「范式:可微端到端模仿」生成 + +> 这是一份**可编辑的论文草稿骨架**,由图谱节点 `paradigm:differentiable_end_to_end_imitation` 的研究透镜与其关系网络自动组装。每一节都被钉在一个具体、可证伪的论断与它的上下文文献上——用来消除空白页,而不是替代你的研究。 + +## 摘要骨架 / Abstract skeleton +- **问题**:当信号弱(罕见场景演示极少)或存在因果混淆(专家看后视镜才变道,模型只学到"变道前总会减速"的相关而非因果),端到端会学到捷径而非策略。可微也不等于可解释:一个不可分解的黑箱在认证与事故归因上代价高昂。 +- **关键观察**:从传感器到轨迹的整条管线可微,且监督信号(专家轨迹)足够强、足够多,梯度能穿过感知-预测-规划把误差正确分配到上游。相信联合优化的全局最优优于各模块各自最优的拼装。 +- **做法**:(填:你用下方“方法骨架”中的原语如何组合出新方法) +- **可证伪的主张**:在 [UniAD](paper_2212.10156_uniad.md) 上做模块消融:逐一切断 BEV→检测、检测→预测、预测→规划之间的梯度(停止反传),测闭环分数下降幅度,定位"联合可微"真正贡献最大的那一环。可证伪点:若切断所有跨模块梯度后分数几乎不变,则"端到端联合优化"的收益被推翻。 + +## 1. 研究问题 / Research question +在 [UniAD](paper_2212.10156_uniad.md) 上做模块消融:逐一切断 BEV→检测、检测→预测、预测→规划之间的梯度(停止反传),测闭环分数下降幅度,定位"联合可微"真正贡献最大的那一环。可证伪点:若切断所有跨模块梯度后分数几乎不变,则"端到端联合优化"的收益被推翻。 + +## 2. 背景与定位 / Related work(来自关系网络) +**它延伸/喂入的工作** +- [GameFormer(用层级 transformer 做博弈式交互预测与规划)] (`paper:gameformer`) — 用层级 transformer 解码器迭代地让每个 agent 在他者上一层预测条件下更新自己,把 level-k 博弈推理可微化,统一交互预测与自车规划。 + +## 3. 关键假设 / Load-bearing assumption +从传感器到轨迹的整条管线可微,且监督信号(专家轨迹)足够强、足够多,梯度能穿过感知-预测-规划把误差正确分配到上游。相信联合优化的全局最优优于各模块各自最优的拼装。 + +## 4. 现有方法的失效边界 / The gap +当信号弱(罕见场景演示极少)或存在因果混淆(专家看后视镜才变道,模型只学到"变道前总会减速"的相关而非因果),端到端会学到捷径而非策略。可微也不等于可解释:一个不可分解的黑箱在认证与事故归因上代价高昂。 + +## 5. 方法骨架 / Method(可复用的研究原语) +把以下原语按你的问题重新编排,就是方法章的骨架: +- **类型化 cross-attention query** — 把任何关心的实体表达为一组可学习的 query 向量,让它们通过 cross-attention 从一个公共特征记忆中拉取信息,是一类极其普适的方法学移动。DETR 把它用于目标检… + +## 6. 跨域先验 / Cross-domain prior +与深度学习取代手工特征工程是同一支"特征学习 > 手工设计"的脉络(见 [Bitter Lesson](essay_bitter_lesson.md));也对应可微渲染把图形学反问题变成端到端优化、可微物理把控制问题接进梯度下降。 + +## 7. 实验设计 / Experiment plan +在 [UniAD](paper_2212.10156_uniad.md) 上做模块消融:逐一切断 BEV→检测、检测→预测、预测→规划之间的梯度(停止反传),测闭环分数下降幅度,定位"联合可微"真正贡献最大的那一环。可证伪点:若切断所有跨模块梯度后分数几乎不变,则"端到端联合优化"的收益被推翻。 + +可复现脚手架:`labs/research/harness.py` 提供固定随机种子的扫描-度量-出图-下结论流水线;参见已跑通的范例 `labs/research/exp_overestimation_bias.py`(它把一条研究透镜的论断用代码验了一遍)。 + +## 8. 可复现性 / Reproducibility +- 暂无 `implements` 边指向现成代码;用第 7 节的 harness 起一个最小可复现实验。 + +## 9. 证伪判据 / Falsification criteria +明确写下“看到什么结果就说明本主张错了”。一个无法被证伪的主张不值得投稿—— +在 [UniAD](paper_2212.10156_uniad.md) 上做模块消融:逐一切断 BEV→检测、检测→预测、预测→规划之间的梯度(停止反传),测闭环分数下降幅度,定位"联合可微"真正贡献最大的那一环。可证伪点:若切断所有跨模块梯度后分数几乎不变,则"端到端联合优化"的收益被推翻。 + +--- +seeded from atlas node `paradigm:differentiable_end_to_end_imitation` · 关系网络 + 研究透镜自动组装 · 由 tools/scaffold_paper.py 生成 diff --git a/tools/scaffold_paper.py b/tools/scaffold_paper.py new file mode 100644 index 0000000..c80bea2 --- /dev/null +++ b/tools/scaffold_paper.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 +"""Turn an atlas node into a paper-draft scaffold. + +This is the "production" half of the atlas: given a node, it assembles a +structured draft from material the graph already carries — + + * the research question and falsification criteria from the node's research + lens (the falsifiable next experiment); + * a positioned related-work section from the typed graph neighbourhood + (foundations via `prereq`, alternatives via `parallel`, tensions via + `contrasts`, extensions via `extends`/`feeds`); + * a method skeleton from the `move:` primitives the node composes/manifests + (the reusable research actions); + * the load-bearing assumption, the gap (failure boundary) and a cross-domain + prior, again from the lens; + * a runnable experiment pointer into labs/research/. + +The output is a draft a researcher edits, not a finished paper — but it removes +the blank-page step and forces every section to be grounded in a concrete, +falsifiable claim and its surrounding literature. + +Usage: + python tools/scaffold_paper.py # one draft + python tools/scaffold_paper.py --examples # a curated set + python tools/scaffold_paper.py --all-lensed # every lensed node +Outputs to research/drafts/.md +""" +from __future__ import annotations + +import json +import re +import sys +from collections import defaultdict +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +GRAPH = ROOT / "docs" / "data" / "graph_extended.json" +LENS = ROOT / "docs" / "data" / "research_lens.json" +OUT = ROOT / "research" / "drafts" + +REL_ZH = { + "prereq": "先修基础", "covers": "讲解", "extends": "扩展", "parallel": "平行替代", + "contrasts": "对照张力", "feeds": "下游衔接", "implements": "代码实现", + "composes": "组成方法", "motivates": "动机", "manifests": "具现", + "enables": "释放", "validates": "推演验证", "unsolved_by": "尚未解决", +} + + +def load(): + g = json.loads(GRAPH.read_text(encoding="utf-8")) + lens = json.loads(LENS.read_text(encoding="utf-8")) + by_id = {n["id"]: n for n in g["nodes"]} + adj_out = defaultdict(list) + adj_in = defaultdict(list) + for e in g["edges"]: + adj_out[e["source"]].append((e["rel"], e["target"])) + adj_in[e["target"]].append((e["rel"], e["source"])) + return g, lens, by_id, adj_out, adj_in + + +def label(by_id, nid): + n = by_id.get(nid) + if not n: + return nid + return n.get("label_zh") or n.get("label") or nid + + +def one_liner(by_id, nid): + n = by_id.get(nid) or {} + s = (n.get("summary_zh") or n.get("summary") or "").strip() + s = re.sub(r"\s+", " ", s) + return (s[:90] + "…") if len(s) > 92 else s + + +def safe(nid: str) -> str: + return re.sub(r"[^a-zA-Z0-9._-]", "_", nid) + + +def neighbours(adj_out, adj_in, nid, rels, limit=8): + seen, out = set(), [] + for rel, other in adj_out.get(nid, []): + if rel in rels and other not in seen: + seen.add(other); out.append((rel, other, "→")) + for rel, other in adj_in.get(nid, []): + if rel in rels and other not in seen: + seen.add(other); out.append((rel, other, "←")) + if len(out) >= limit: + break + return out[:limit] + + +def scaffold(nid, by_id, lens, adj_out, adj_in) -> str: + n = by_id.get(nid) + if not n: + return f"# (node not found: {nid})\n" + name = label(by_id, nid) + L = lens.get(nid, {}) + lines = [] + lines.append(f"# 论文骨架 · 由「{name}」生成") + lines.append("") + lines.append(f"> 这是一份**可编辑的论文草稿骨架**,由图谱节点 `{nid}` 的研究透镜与其关系网络自动组装。" + f"每一节都被钉在一个具体、可证伪的论断与它的上下文文献上——用来消除空白页,而不是替代你的研究。") + lines.append("") + + # Abstract scaffold + lines.append("## 摘要骨架 / Abstract skeleton") + if L: + lines.append(f"- **问题**:{L.get('failure','(填:现有方法在何处、因何机制失效)')}") + lines.append(f"- **关键观察**:{L.get('assumption','(填:本工作押注的承重假设)')}") + lines.append(f"- **做法**:(填:你用下方“方法骨架”中的原语如何组合出新方法)") + lines.append(f"- **可证伪的主张**:{L.get('experiment','(填:一个可被实验证伪的明确预测)')}") + else: + lines.append("- (该节点尚无研究透镜;先在 docs/data 里为它补一面透镜,再生成骨架。)") + lines.append("") + + # 1 Research question + lines.append("## 1. 研究问题 / Research question") + lines.append(L.get("experiment", "(从该节点的可证伪实验出发,写下一个能被数据回答的问题。)")) + lines.append("") + + # 2 Related work from neighbourhood + lines.append("## 2. 背景与定位 / Related work(来自关系网络)") + groups = [ + (("prereq", "covers"), "**站在什么之上(先修基础)**"), + (("extends", "feeds"), "**它延伸/喂入的工作**"), + (("parallel",), "**平行替代路线(对照基线)**"), + (("contrasts",), "**对照张力(必须讲清差异)**"), + ] + any_nb = False + for rels, title in groups: + nbs = neighbours(adj_out, adj_in, nid, set(rels)) + if not nbs: + continue + any_nb = True + lines.append(f"{title}") + for rel, other, arrow in nbs: + ol = one_liner(by_id, other) + tail = f" — {ol}" if ol else "" + lines.append(f"- [{label(by_id, other)}] (`{other}`){tail}") + lines.append("") + if not any_nb: + lines.append("(该节点邻接稀疏;先在图谱里补边,定位会更准。)") + lines.append("") + + # 3 Assumption + lines.append("## 3. 关键假设 / Load-bearing assumption") + lines.append(L.get("assumption", "(这套方法成立,必须先相信什么?写下来,它就是审稿人第一刀砍向的地方。)")) + lines.append("") + + # 4 Gap + lines.append("## 4. 现有方法的失效边界 / The gap") + lines.append(L.get("failure", "(现有最强基线在什么条件下、因什么机制崩?这就是你的切入点。)")) + lines.append("") + + # 5 Method skeleton from move primitives + lines.append("## 5. 方法骨架 / Method(可复用的研究原语)") + moves = neighbours(adj_out, adj_in, nid, {"composes", "manifests", "enables"}, limit=10) + moves = [(r, o, a) for (r, o, a) in moves if o.startswith("move:") or by_id.get(o, {}).get("kind") == "move"] + if moves: + lines.append("把以下原语按你的问题重新编排,就是方法章的骨架:") + for rel, other, arrow in moves: + ol = one_liner(by_id, other) + tail = f" — {ol}" if ol else "" + lines.append(f"- **{label(by_id, other)}**{tail}") + else: + lines.append("(该节点未直接连到方法学原语 `move:*`;从第 2 节的先修工作里挑组件,或在图谱里补 `composes` 边。)") + lines.append("") + + # 6 Cross-domain prior + lines.append("## 6. 跨域先验 / Cross-domain prior") + lines.append(L.get("isomorphism", "(同一结构在别的领域出现过吗?借它的成熟工具,常常就是创新点。)")) + lines.append("") + + # 7 Experiment plan + lines.append("## 7. 实验设计 / Experiment plan") + lines.append(L.get("experiment", "(自变量、度量、基线、消融。)")) + lines.append("") + lines.append("可复现脚手架:`labs/research/harness.py` 提供固定随机种子的扫描-度量-出图-下结论流水线;" + "参见已跑通的范例 `labs/research/exp_overestimation_bias.py`(它把一条研究透镜的论断用代码验了一遍)。") + lines.append("") + + # 8 Reproducibility / lab links + impl = neighbours(adj_out, adj_in, nid, {"implements"}, limit=6) + lines.append("## 8. 可复现性 / Reproducibility") + if impl: + for rel, other, arrow in impl: + lines.append(f"- 已有实现:[{label(by_id, other)}] (`{other}`)") + else: + lines.append("- 暂无 `implements` 边指向现成代码;用第 7 节的 harness 起一个最小可复现实验。") + lines.append("") + + # 9 Falsification + lines.append("## 9. 证伪判据 / Falsification criteria") + lines.append("明确写下“看到什么结果就说明本主张错了”。一个无法被证伪的主张不值得投稿——") + lines.append(L.get("experiment", "(把第 1 节实验的反面预测写成验收红线。)")) + lines.append("") + lines.append("---") + lines.append(f"seeded from atlas node `{nid}` · 关系网络 + 研究透镜自动组装 · 由 tools/scaffold_paper.py 生成") + return "\n".join(lines) + "\n" + + +EXAMPLES = [ + "insight:offline_rl_is_actually_constrained_dynamic_programming", + "paradigm:differentiable_end_to_end_imitation", + "paper:2212.10156", + "move:treat_planning_as_conditional_generation", +] + + +def main() -> int: + g, lens, by_id, adj_out, adj_in = load() + args = sys.argv[1:] + if not args: + print(__doc__) + return 0 + OUT.mkdir(parents=True, exist_ok=True) + if args[0] == "--all-lensed": + targets = list(lens.keys()) + elif args[0] == "--examples": + targets = EXAMPLES + else: + targets = args + written = 0 + for nid in targets: + if nid not in by_id: + print(f"skip (no node): {nid}") + continue + path = OUT / f"{safe(nid)}.md" + path.write_text(scaffold(nid, by_id, lens, adj_out, adj_in), encoding="utf-8") + written += 1 + print(f"wrote {written} draft(s) to research/drafts/") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())