Gradient-Based Program Synthesis with Neurally Interpreted Languages¶
会议: ICLR 2026
OpenReview: https://openreview.net/forum?id=NAORIWBaoO
代码: 待确认
领域: 神经符号 / 程序合成 / 组合泛化
关键词: 程序归纳, 神经解释器, 离散潜在空间, Gumbel-Softmax, 测试时梯度搜索, 组合泛化
一句话总结¶
NLI 让一个编码器-解码器架构端到端地自己发明一套离散的、类符号的编程语言,并配一个可微分的循环神经执行器逐 token 解释程序,从而既能像符号方法那样组合泛化,又能用梯度下降在程序空间里搜索,在测试时把归纳器给出的初始程序猜测精修到能解释数据为止。
研究背景与动机¶
领域现状:程序归纳长期被困在符号与神经两条路线的取舍里。符号方法(DSL、归纳综合)天然具备组合泛化和数据高效性,少量样例就能学到规律;神经网络则数据驱动、可扩展,但知识全纠缠在权重里,难以在分布外重用。
现有痛点:符号路线依赖人手设计领域专用语言(DSL),构建成本高、跨域不可迁移,且搜索空间组合爆炸;神经路线则是单体模型,在组合泛化和分布外(OOD)场景下表现糟糕,即便泛化只需要重组已学过的概念也做不到。已有的潜在程序网络(LPN)虽然能在连续潜在空间做快速测试时适应、抗过拟合,但组合泛化能力有限,因为它用一个固定维度的连续嵌入表示整个程序,计算步数被锁死。
核心矛盾:如何让模型既保留离散符号语言的可组合、可重用结构,又能享受神经网络端到端可微、梯度可搜索的便利——也就是把"组合性"和"梯度搜索"这两个原本互斥的优点合到一个模型里。
本文目标:不再人手写 DSL、也不再学外部的搜索引导函数,而是让模型直接从输入-输出样例端到端学出自己的领域专用神经语言 + 配套解释器,并把搜索引导内嵌进这套语言本身。
核心 idea:[离散潜在 + 可微执行] 把程序表示成一串离散 token 的变长序列(而非单个连续向量),用 Gumbel-Softmax 让离散采样可微,再用一个逐 token 推进的循环神经执行器解释程序——这样既能表达任意长度的程序(步数随 token 长度增长,可解决比训练时更复杂的问题),又能在测试时对 token 的连续松弛做梯度上升搜索。
方法详解¶
整体框架¶
NLI(Neural Language Interpreter)是一个 Latent Adaptation Network:编码器 \(q_\phi\) 作为程序归纳器,把规约(一组输入-输出样例)映射成一串离散 token 程序 \(z=(z_1,\dots,z_T)\);解码器 \(p_\theta\) 作为神经解释器,逐 token 把查询输入执行成输出。两者全程可微,端到端训练;测试时归纳器先给一个初始程序猜测,再用梯度搜索在 token 的连续松弛空间里精修,直到找到最能解释规约的神经程序。
flowchart LR
S["规约 S<br/>{(xi,yi)}"] --> ENC["归纳器 qφ<br/>Transformer+mean-pool"]
ENC --> Z["离散程序 z=(z1..zT)<br/>Gumbel-Softmax over 码本"]
Z --> SEARCH["神经程序搜索<br/>梯度上升精修 e*"]
SEARCH --> EXEC["神经解释器 pθ<br/>循环逐token执行"]
XQ["查询 x_{n+1}"] --> EXEC
EXEC --> Y["输出 ŷ"]
关键设计¶
1. 离散 token 程序归纳器:让规约变成一串可重组的"指令"。 归纳器先用一个 Transformer \(h_\phi\) 独立处理每个样例对 \((x_i,y_i)\),得到 \(T\) 个 token 嵌入,再对所有样例对在每个 token 位置上做均值池化 \(\bar e_t=\frac{1}{|S|}\sum_i e_t^{(i)}\)——这一步对样例顺序置换不变(借鉴 Neural Processes),还能让模型适应测试时不同的规约规模。随后每个 \(\bar e_t\) 经共享前馈网络 \(f_\phi\) 投影成码本上的 logits,并用 Gumbel-Softmax 松弛 \(z_t=\mathrm{Softmax}((l_t+g_t)/\tau_e)\) 得到可微的离散近似。码本里有一个专门的 skip token,让解释器执行 no-op,从而能表示比固定序列长度 \(T\) 更短的程序。训练时把温度 \(\tau_e\) 逐步退火到接近零,逼近真离散采样、逼模型用稀疏的码本激活。
2. 循环神经解释器:逐 token 执行换来变长与组合泛化。 标准解码器容易过拟合训练时见过的程序长度与结构,NLI 的解释器 \(p_\theta\) 改用递归:它把查询 \(x\) 先嵌成初始隐状态 \(s_0\)、输出分布初始化为 \(x\) 的 one-hot,然后在 \(T\) 步里逐位置消费程序 token,用一个共享执行网络 \(d\) 反复更新中间状态。第 \(t\) 步执行网络从上一步状态 \(s_{t-1}\) 和嵌入的潜 token \(E_v^\top z_t\) 产出 logits \(n_t\),经 Gumbel-Softmax 得候选分布 \(\tilde\pi_t\),再用 skip 门控更新:\(\pi_t=z_{t,\text{skip}}\cdot\pi_{t-1}+(1-z_{t,\text{skip}})\cdot\tilde\pi_t\)——skip token 的概率质量决定这一步是"跳过"还是真执行。因为执行器一次只吃一个 token,NLI 的程序步数不被锁死,能把学到的 token 以不同方式、不同长度重组,天然支持变长程序和新组合。
3. 鼓励重用的编码器正则:逼出紧凑的原语词表。 重构损失 \(L_{\text{recon}}=-\log p_\theta(y\mid x,q_\phi(S))\) 用 leave-one-out 方式(拿 \(m-1\) 对归纳、在留出那对上算预测误差)保证潜程序能真正泛化执行而非死记样例对。在此之上加一个编码器正则 \(L_{\text{reg}}\),它是"批次内被用到的 unique token 数"的可微近似:对每个 token \(k\),\(1-\exp(\sum\log(1-q^{(k,j)}_\phi))\) 近似它在批次里至少被用一次的概率,对所有 \(k\) 求和即期望 unique token 数。惩罚用太多不同词表项,就逼模型用一小撮已发现的原语重组出新程序,而不是给每个新任务发明一个新 token——这正是组合性的来源。
4. 测试时神经程序搜索:在 token 松弛空间做带梯度的局部搜索。 编码器给的快速首猜未必最优(尤其 OOD 程序),于是 NLI 在 token 的连续松弛空间(而非离散程序空间)做梯度上升,找使规约似然最大的连续嵌入 \(e^*=\arg\max_e \mathbb{E}_{g,h}[\sum_{(x_j,y_j)}\log p_\theta(y_j\mid x_j, z(e,\tau_e,g),\tau_d,h)]\)。因为执行全程可微,这等价于在符号空间做局部搜索但带梯度信号。两个温度 \(\tau_e,\tau_d\) 在搜索中一起退火:先高温平滑目标、广泛探索,再降温逼出锐利离散的程序;末了用最终软表示直接解码,避免硬采样带来优化-执行的不一致。为避免陷局部极小,从归纳器首猜附近采 \(s\) 个高斯起点(\(\mu=e_t,\sigma=\sigma_s\))并行跑 \(L\) 步梯度上升——既利于探索又高度可并行(可跨多卡)。由于搜索空间被限制在重组一组离散嵌入上,比连续潜在搜索更不易过拟合到不泛化的程序。
实验关键数据¶
主实验表格(自建组合泛化套件,ID/OOD 最终准确率)¶
| Method | Shift-L ID | Shift-L OOD | Shift-P ID | Shift-P OOD | Comp-I ID | Comp-I OOD |
|---|---|---|---|---|---|---|
| In-Context | 1.00 | 0.00 | 1.00 | 0.00 | 1.00 | 0.13 |
| TTT | 1.00 | 0.00 | 1.00 | 0.00 | 0.95 | 0.14 |
| LPN | 1.00 | 0.00 | 1.00 | 0.00 | 1.00 | 0.18 |
| LPN Gradient Search | 1.00 | 0.03 | 1.00 | 0.00 | 1.00 | 0.29 |
| D-LPN | 1.00 | 0.02 | 1.00 | 0.00 | 0.99 | 0.15 |
| D-LPN Gradient Search | 1.00 | 0.01 | 1.00 | 0.00 | 0.99 | 0.20 |
| NLI | 1.00 | 0.00 | 1.00 | 0.00 | 1.00 | 0.17 |
| NLI Prior Search | 1.00 | 0.10 | 1.00 | 0.00 | 1.00 | 0.23 |
| NLI Gradient Search | 1.00 | 0.99 | 1.00 | 1.00 | 1.00 | 0.91 |
三个 split 分别测:Shift-L(长度外推,训练 shift 1–5、测 6–10)、Shift-P(原语抽取,训大 shift、测小 shift)、Comp-I(组合隔离,训单原语、测 \(f(g(x))\) 组合)。所有模型 ID 都近完美;OOD 上所有 baseline 和 NLI 的非搜索变体几乎全崩,唯有 NLI + 梯度搜索在长度外推 99%、原语抽取 100%、新组合 91%。学到的码本显示系统性重用:单步左移恒用 token 231、两步移用 476,8 步移(OOD)由这两块拼出(四个 231 + 两个 476),说明泛化来自重组而非记忆。
消融实验(去掉单个组件后的 OOD 准确率,base=97%)¶
| 去掉的组件 | OOD 准确率 |
|---|---|
| no discrete program | 1% |
| no recurrent execution | 2% |
| no discrete layer | 5% |
| no interpreter gumbel | 5% |
| no skip token | 24% |
| no encoder loss | 66% |
| no inductor gumbel | 76% |
| Base | 97% |
去掉循环执行、归纳器或解释器的离散性,OOD 直接塌到 1–5%——这三者都是组合泛化的命门;去掉 skip token 降到 24%(模型能自学 skip 但专用 token 训练更快更稳);解释器级 Gumbel 是最大性能驱动(去掉降到 5%),归纳器级 Gumbel 去掉则从 97% 降到 76%;编码器正则只对 Shift-P 这类"需要把原语解出来再组更短程序"的组合有用,对纯长度外推无影响。
关键发现¶
- 测试时计算量正相关:在 Comp-I 上同时扩展梯度步数(1→400)与并行起点数(1→4096),准确率随两轴单调上升——梯度搜索把测试时算力直接换成泛化。
- DeepCoder 上对标神经符号方法:在 1160 万归纳任务上训练,NLI/LPN 仅用输入-输出对、无任何 ground-truth 程序监督,却能与用了程序标注的 ExeDec 竞争,并大幅超过 Latent Programmer 和 Transformer 程序合成。
- NLI 与 LPN 互补:NLI 更擅长长度泛化和新概念组合(得益于可变长程序),LPN 更擅长切换概念顺序和扩展新操作——两者学到的潜在结构带不同归纳偏置。
- Gumbel-Softmax 非必需但更稳:原则上任何离散采样的平滑松弛(如 VQ-VAE + 直通估计)都可替代,作者选 Gumbel-Softmax 主要图它训练稳定,避开 VQ 的码本坍缩与梯度有偏;代价是需要小心的温度退火,退火太快会严重掉点。
亮点与洞察¶
- 把"语言"本身当成可学习对象:不再外挂搜索引导函数,而是让模型把引导内嵌进它自学的离散语言里,搜索因此变成对一组可重组原语的梯度局部搜索——这是对"DSL 必须人手设计"这一前提的釜底抽薪。
- 离散 + 可微的统一:用 Gumbel-Softmax 把"我要离散符号的组合性"和"我要梯度搜索的端到端"两个诉求在同一损失里调和,而且训练用的可微执行器和测试时搜索用的是同一套机制,避免了训练-推理不一致。
- 变长执行是组合泛化的物理基础:把程序步数从"固定"解放成"随 token 长度增长",才让模型有能力表达比训练更长更复杂的程序,这也是它能 99% 长度外推、而 LPN 单体嵌入只能 0–3% 的根因。
- 可解释的副产物:学到的码本是人可读的(231=单步移、476=双步移),让"泛化来自重组而非记忆"这一论断有了直接证据。
局限与展望¶
- 测试时成本高:梯度搜索 + 多起点并行虽可并行扩展,但相比单次前向的 baseline 推理成本显著更大;为公平作者还做了等算力 baseline 但那会让 baseline ID 退化。
- 基准偏合成/受限:自建套件是固定长度 20 的序列任务,DeepCoder 也是受限 DSL 的列表操作,离真实世界程序合成(带控制流、递归、副作用)还有距离。
- 数据规模受限:DeepCoder 原始组合训练集未公开,作者从头生成 1160 万任务(少于原文 6000 万),采样函数代价过高限制了规模上限。
- Gumbel-Softmax 的温度敏感:退火调度需要小心,退火太快会严重掉点,稳定性依赖经验性的调度。
- 展望:把这套"自学语言 + 可微执行 + 梯度搜索"推广到带更丰富控制结构的语言、更大规模真实代码,以及与 LPN 互补的归纳偏置如何融合,都是自然的下一步。
相关工作与启发¶
- 符号程序合成:Summers、Gulwani 等经典归纳综合与 DSL 方法提供组合泛化与数据高效性,但受限于人手设计 DSL 与组合搜索——NLI 正是要去掉"人手 DSL"这块。
- Latent Adaptation Networks / LPN(Macfarlane & Bonnet, 2025):NLI 同属 LAN 家族,但把 LPN 的单体连续潜在嵌入换成变长离散 token 序列,针对性补上 LPN 的组合泛化短板。
- 离散表示学习:Gumbel-Softmax(Jang/Maddison 2017)与 VQ-VAE(van den Oord 2017)是让离散采样可微的两条路,本文选前者图稳定性。
- 神经执行器 / 世界模型:解释器逐 token 解释程序的设计借鉴了条件世界模型(Ha & Schmidhuber 2018)的神经执行思路。
- 神经符号对标方法:ExeDec、Transformer 程序合成、Latent Programmer 是 DeepCoder 上的强 baseline,它们都用 ground-truth 程序监督,NLI 在无程序监督下与之竞争凸显了纯 PBE 路线的潜力。
评分¶
- 新颖性: ⭐⭐⭐⭐⭐ 把"模型自学离散语言 + 可微神经执行器 + 测试时梯度程序搜索"三件事统一进一个端到端架构,从根上重构了符号-神经取舍,思路新颖且自洽。
- 实验充分度: ⭐⭐⭐⭐ 自建套件三类组合泛化 + DeepCoder 对标神经符号方法 + 细致的逐组件消融 + 测试时算力双轴扩展,证据链完整;扣分在基准仍偏合成、数据规模受公开性所限。
- 写作质量: ⭐⭐⭐⭐ 动机-方法-实验逻辑清晰,算法与公式交代到位,码本可视化让"重组而非记忆"很有说服力;部分符号细节略密集。
- 价值: ⭐⭐⭐⭐ 给"无 DSL、无程序监督的可组合程序归纳"提供了一条可行且可扩展的新路径,对神经符号、组合泛化与测试时适应都有借鉴意义。