<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://pistilreaper.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://pistilreaper.github.io/" rel="alternate" type="text/html" /><updated>2026-04-19T09:16:50+00:00</updated><id>https://pistilreaper.github.io/feed.xml</id><title type="html">Pistil’s blog</title><subtitle>「当一个人的心中有更高的山峰想要去攀登时，就不会在意脚下的泥沼。」</subtitle><entry><title type="html">科研随笔——用RLHF重新思考符号回归中的可解释性</title><link href="https://pistilreaper.github.io/%E7%A7%91%E7%A0%94%E9%9A%8F%E7%AC%94-%E7%94%A8RLHF%E9%87%8D%E6%96%B0%E6%80%9D%E8%80%83%E7%AC%A6%E5%8F%B7%E5%9B%9E%E5%BD%92%E4%B8%AD%E7%9A%84%E5%8F%AF%E8%A7%A3%E9%87%8A%E6%80%A7/" rel="alternate" type="text/html" title="科研随笔——用RLHF重新思考符号回归中的可解释性" /><published>2026-04-10T00:00:00+00:00</published><updated>2026-04-10T00:00:00+00:00</updated><id>https://pistilreaper.github.io/%E7%A7%91%E7%A0%94%E9%9A%8F%E7%AC%94%E2%80%94%E2%80%94%E7%94%A8RLHF%E9%87%8D%E6%96%B0%E6%80%9D%E8%80%83%E7%AC%A6%E5%8F%B7%E5%9B%9E%E5%BD%92%E4%B8%AD%E7%9A%84%E5%8F%AF%E8%A7%A3%E9%87%8A%E6%80%A7</id><content type="html" xml:base="https://pistilreaper.github.io/%E7%A7%91%E7%A0%94%E9%9A%8F%E7%AC%94-%E7%94%A8RLHF%E9%87%8D%E6%96%B0%E6%80%9D%E8%80%83%E7%AC%A6%E5%8F%B7%E5%9B%9E%E5%BD%92%E4%B8%AD%E7%9A%84%E5%8F%AF%E8%A7%A3%E9%87%8A%E6%80%A7/"><![CDATA[<h1 id="1-符号回归中的复杂度与可解释性一个经常被默认却并不稳固的等号">1. 符号回归中的“复杂度”与“可解释性”：一个经常被默认、却并不稳固的等号</h1>

<p>符号回归大家都耳熟能详了：它不仅要拟合数据，还要吐出一个人可以读、可以想、甚至可以进一步拿去推导的方程。也正因为这个承诺，<strong>复杂度（complexity）</strong>几乎成了这个领域最常见的第二目标。除了拟合误差，我们通常还会最小化树大小、节点数、运算符数量、带权运算符数量，或者干脆做一个 accuracy-complexity 的 Pareto front。这个做法并不奇怪，因为表达式短一些、浅一些、少几层嵌套，通常确实更容易看。</p>

<p>但这里有一个默认前提：<strong>复杂度可以作为可解释性的代理。</strong> 根据Occam’s Razor原则，这个前提大多数时候是成立的，但并不严格。一个式子更短，不等于它更容易被人理解；一个式子包含更少的节点，也不意味着它更接近人类科学建模时偏好的形式。尤其在物理问题里，这个落差其实非常明显。一个包含少量三角、指数或嵌套分式的表达式，树长可能不大，但读起来可能非常拧；反过来，一个稍长的多项式、无量纲组合或者分层展开式，虽然节点更多，却往往更符合人的推理习惯。</p>

<p>因此，我觉得符号回归里“复杂度”这个概念可以分成三层来看。</p>

<p>第一层是<strong>纯语法复杂度</strong>。这类定义最常见，也最便宜。树大小、节点数、operator count 都属于这一类。它们的优点非常明显：稳定、通用、实现简单、适合直接放到搜索过程中做 regularization 或 Pareto optimization。SRBench 一类工作最终采用的也是这种偏统一、偏工程的复杂度指标，因为它足够可复现，方便跨算法比较。</p>

<p>第二层是<strong>轻语义复杂度</strong>。这类做法承认不同算子带给人的负担并不一样，因此尝试给函数符号加权。例如加减乘除、幂、log、exp、三角函数并不等权。Kommenda 等人的工作就明确讨论过：单纯的 size-related complexity 只描述表达式树的形状，而不能反映表达式内部运算的“认知难度”，所以可以加入对函数符号的语义区分。PSE 这篇工作在实现中采用的，也正是这种精神：表面上说是“operator 数量的 proxy”，实际代码里却已经是带权运算符复杂度了。</p>

<p>第三层才是我真正关心的：<strong>人类可解释性本身。</strong> 这件事并不是一个纯语法对象。人类在看一个公式时，会自然地受到许多因素影响：它是否容易心算或局部模拟，它是否可以分解成几个彼此可命名的块，它是否包含过多非算术操作，它是否反复嵌套某类函数，它是否和该领域常见的理论结构相似。换句话说，人类并不是在“数节点”，而是在“读结构”。</p>

<p>Virgolin 等人 2020 年的一篇工作，正是试图解决这个问题。他们没有再假设“size 越小越可解释”，而是反过来问：<strong>能不能直接从人的反馈里学一个 interpretability proxy？</strong> 他们设计了一个关于数学公式的问卷，围绕 simulatability 和 decomposability 两种常见的 proxy of human interpretability 收集数据，再用学习到的模型去估计一个公式的人类可解释性，并把这个模型嵌回多目标遗传编程中。这个思路在我看来很重要，因为它至少说明了一件事：在符号回归里，我们其实不必把“复杂度”永远当成不可动摇的手工先验；它完全可以是一个<strong>被学习的偏好函数</strong>。</p>

<p>所以，我们接下来要考虑的就不再是“什么复杂度定义最合理”，而是：<strong>人到底偏好什么样的公式？这个偏好能否被学习并在搜索中施加？</strong></p>

<p>从这个角度看，树大小、运算符数量、带权复杂度，都更像是一种廉价的、静态的、预先写死的 proxy。它们的价值在于便宜，不在于真实。它们可以作为起点，但未必适合作为终点。</p>

<h1 id="2-rlhf">2. RLHF</h1>

<p>在LLM的Post-training领域，经常用到一种名为<strong>RLHF</strong>（Reinforcement Learning from Human Feedback，基于人类反馈的强化学习）的微调技术。</p>

<p>在强化学习的传统设定里，我们默认任务目标已经被清晰地写成了奖励函数。可现实里恰恰有很多目标不是这样。</p>

<p>早在2017年，Christiano 等人指出：许多任务的目标复杂、含糊、难以精确定义，手写 reward 往往会造成“奖励函数被优化了，但真正想要的行为没有出现”。于是他们不再要求人直接写出 reward，而是让人去比较两段行为片段哪个更符合偏好，再用这些比较数据训练 reward model，最后让策略去优化这个 learned reward。</p>

<p>这个框架后来在大语言模型里被真正普及开来。InstructGPT 那篇工作给出了一条现在大家都很熟悉的流程：先做监督微调（SFT），拿到一个基本会“按要求回答”的初始策略；然后让标注者对多个回答做排序，训练一个 reward model；最后再用 PPO 之类的 RL 方法去优化语言模型，使它更符合人类偏好。这里最重要的思想是：<strong>当目标无法被显式写出时，可以先收集偏好，再学习奖励，再优化策略。</strong></p>

<p>这不正是我们想要的吗？这套思想在符号回归里同样适用：我们不必把“可解释性”这个目标硬塞进一个手写的复杂度函数里，而是可以直接从人对候选公式的偏好中学一个 interpretability reward model，再让符号生成器去优化这个 learned reward。</p>

<h1 id="3-从-virgolin-的-proxy-出发能不能用-rlhf-去约束符号回归中的可解释性">3. 从 Virgolin 的 proxy 出发：能不能用 RLHF 去约束符号回归中的可解释性？</h1>

<h2 id="31-为什么这个方向是自然的">3.1 为什么这个方向是自然的</h2>

<p>先看 Virgolin 的工作到底做了什么。它其实已经完成了 RLHF 思路中最关键的一半：<strong>从人类反馈学习一个偏好代理。</strong> 只不过它当时并不是沿着“alignment”这套叙事来讲，而是沿着“interpretable symbolic regression”去讲。它的核心逻辑是：</p>

<ol>
  <li>让人对公式的可解释性相关属性作出反馈；</li>
  <li>用这些反馈拟合一个可解释性 proxy；</li>
  <li>把这个 proxy 嵌入搜索过程，替代简单的 size minimization。</li>
</ol>

<p>这和 RLHF 的结构已经非常相似了。差别主要在于：</p>

<ul>
  <li>Virgolin 的 proxy 更像一个静态评估器，主要作为多目标优化中的第二目标；</li>
  <li>RLHF 则更强调“偏好—奖励—策略更新”的闭环，把 learned preference 直接用于改变生成分布。</li>
</ul>

<p>能否把 Virgolin 那种静态 proxy，升级为一个真正参与公式生成过程的偏好学习框架？</p>

<h2 id="31-一个可能的总体框架">3.1 一个可能的总体框架</h2>

<h3 id="第一层先把问题表述成-preference-learning而不是-complexity-engineering">第一层：先把问题表述成 preference learning，而不是 complexity engineering</h3>

<p>这一步最重要。我们不再手写一个固定复杂度函数，而是让标注者在同一任务、相近精度的前提下，对两个候选公式回答一个更自然的问题：</p>

<ul>
  <li>哪个更容易理解？</li>
  <li>哪个更像你愿意写进论文的最终公式？</li>
  <li>哪个更容易手工推演、讲给别人听、或者映射到已有理论？</li>
</ul>

<p>这里一定要强调“在相近精度下”进行比较，否则人会被拟合误差主导，偏好数据会退化成“谁更准就选谁”。换句话说，<strong>我们要学的是在 accuracy 已经基本过关之后，人对公式结构的偏好。</strong></p>

<p>这一步甚至不一定要求标注者给分数。我反而觉得 pairwise preference 更可靠，因为“7 分和 8 分的差别是什么”很难说清，但“这两个里面哪个更顺眼”通常容易得多。</p>

<h3 id="第二层学一个-task-conditioned-的-interpretability-model">第二层：学一个 task-conditioned 的 interpretability model</h3>

<p>我不太赞成只输入公式本身。因为公式是否好理解，经常是<strong>任务相关</strong>的。</p>

<p>举个简单例子：</p>

<ul>
  <li>在控制、流体、传热里，无量纲群往往很自然；</li>
  <li>在某些经验建模问题里，分段、饱和、阈值结构可能更符合人的先验；</li>
  <li>在基础物理里，某些三角或指数形式并不难懂，甚至比高阶多项式更自然。</li>
</ul>

<p>所以，一个更合理的偏好模型，输入不该只有 expression tree，还应包括任务上下文，例如变量名、量纲、物理语义标签、是否已经无量纲化、误差水平、甚至候选公式所在的 Pareto 邻域。也就是说，我们要学的可能不是单纯的 $p(\text{interpretable}\mid f)$，而是 $p(\text{preferred}\mid f, \mathcal{T})$。</p>

<p>这一步其实比“复杂度定义”前进了一大步：复杂度通常是假设全任务共享一套静态标尺，而偏好模型允许不同任务、不同学科对“好公式”的判断不同。</p>

<h3 id="第三层再决定如何把偏好注入生成器">第三层：再决定如何把偏好注入生成器</h3>

<p>这时就出现三条路线。</p>

<p>第一条，最像经典 RLHF。训练一个 reward model，分数反映公式在当前任务下的可解释性偏好，然后把公式生成器当成 policy 去优化。生成器可以是序列模型、树生成模型、MCTS、遗传编程，甚至某种 grammar-guided sampler。只要它能产出候选公式，并支持基于 reward 改变采样分布，就能接进去。</p>

<p>第二条，更像 DPO。直接对同一任务下的好/坏公式对进行优化，让生成器提高偏好公式的概率，降低不被偏好的公式概率，而不显式训练 reward model。这个方案对深度生成式符号回归尤其合适，因为它更像“语言模型偏好对齐”的公式版。</p>

<p>第三条，更像 RLAIF。先写一套比较明确的“公式宪法”，再让辅助模型或规则系统产生部分比较信号。例如：</p>

<ul>
  <li>避免连续三层以上非算术操作嵌套；</li>
  <li>优先选择可以拆成少量物理可命名模块的公式；</li>
  <li>在物理问题中优先保留量纲齐次或无量纲结构；</li>
  <li>对相同精度下的候选式，优先选择在局部极限下行为更可解释的表达；</li>
  <li>对可以符号化简到相同形式的候选，不奖励纯表面差异。</li>
</ul>

<p>这类方案的价值在于，它能显著降低人工标注成本，把少量高质量专家反馈扩展成较大规模的伪偏好数据。</p>

<h2 id="33-这个方向真正难的地方在哪里">3.3 这个方向真正难的地方在哪里</h2>

<p>我觉得可行性是有的，但困难也很真实，而且并不只是“算力够不够”这么简单。</p>

<h3 id="难点一可解释性不是绝对属性而是关系属性">难点一：可解释性不是绝对属性，而是关系属性</h3>

<p>一个公式的“好不好懂”往往取决于对谁而言、在什么任务里、和什么候选相比。对于熟悉傅里叶分析的人，正弦项不一定难；对于做热工关联式的人，某些经验指数关系反而很自然；而对另一类研究者，同样的形式可能完全陌生。</p>

<p>这意味着我们最好学的是<strong>偏好分布</strong>，而不是一个试图放之四海而皆准的“绝对解释性分数”。如果做得更进一步，甚至可以考虑 personalized interpretability，也就是根据不同用户群体学习不同偏好模型。</p>

<h3 id="难点二公式有等价性偏好数据会被表示法污染">难点二：公式有等价性，偏好数据会被表示法污染</h3>

<p>数学表达式的一个麻烦在于，不同写法可能是同一个式子。比如因式分解前后、常数吸收前后、对数幂变换前后，表面长度和结构差别很大，但数学上几乎等价。如果不做 canonicalization 或符号化简，偏好学习很容易学到“排版习惯”而不是“结构偏好”。</p>

<p>因此，这类系统必须把等价类处理当成核心基础设施，而不是后处理小修小补。至少要尽可能做符号化简、常数标准化、树结构规范化，最好还能对“可被局部代换解释为同一结构”的公式做聚类。</p>

<h3 id="难点三人类反馈很贵而且专家反馈更贵">难点三：人类反馈很贵，而且专家反馈更贵</h3>

<p>这也是为什么我不认为“完整人工 RLHF”会是第一步的最佳选择。符号回归的可解释性判断，经常需要一定数学或领域背景，不像一般文本偏好那样可以大规模众包。因此，更现实的路线可能是：</p>

<ul>
  <li>先用 Virgolin 一类问卷数据或小规模专家数据得到第一版 proxy；</li>
  <li>再用主动学习，只对 reward model 最不确定的候选对请求人工比较；</li>
  <li>同时引入 constitution/rule-based feedback 扩充数据；</li>
  <li>最后只在关键任务上让专家做高价值校正。</li>
</ul>

<h3 id="难点四偏好约束可能和精度发现真规律的目标发生冲突">难点四：偏好约束可能和精度、发现真规律的目标发生冲突</h3>

<p>这是我觉得最需要警惕的一点。物理规律并不保证总是“人类第一眼觉得最顺眼”的。过强的可解释性偏好，可能会把搜索推向过度简单、过度教科书式的区域，反而错过真实但稍显复杂的结构。</p>

<p>所以更合理的方式可能是：</p>

<ul>
  <li>仍然保留 accuracy 或 evidence 作为硬约束或主目标；</li>
  <li>把可解释性当作在近似等精度模型之间做选择的偏好；</li>
  <li>用 KL 约束、Pareto front 或 constrained optimization 防止生成器为了迎合偏好而牺牲太多真实性。</li>
</ul>

<h1 id="4-参考">4. 参考</h1>

<ol>
  <li>Paul F. Christiano, Jan Leike, Tom B. Brown, Miljan Martic, Shane Legg, Dario Amodei. <em>Deep Reinforcement Learning from Human Preferences</em>. NeurIPS 2017.</li>
  <li>Long Ouyang, Jeff Wu, Xu Jiang, et al. <em>Training Language Models to Follow Instructions with Human Feedback</em>. NeurIPS 2022.</li>
  <li>Rafael Rafailov, Archit Sharma, Eric Mitchell, Stefano Ermon, Christopher D. Manning, Chelsea Finn. <em>Direct Preference Optimization: Your Language Model is Secretly a Reward Model</em>. NeurIPS 2023.</li>
  <li>Yuntao Bai, Saurav Kadavath, Sandipan Kundu, et al. <em>Constitutional AI: Harmlessness from AI Feedback</em>. 2022.</li>
  <li>Marco Virgolin, Andrea De Lorenzo, Eric Medvet, Francesca Randone. <em>Learning a Formula of Interpretability to Learn Interpretable Formulas</em>. PPSN 2020.</li>
  <li>Michael Kommenda, Andreas Beham, Michael Affenzeller, Gabriel Kronberger. <em>Complexity Measures for Multi-objective Symbolic Regression</em>. 2021.</li>
  <li>William La Cava, Patryk Orzechowski, Bogdan Burlacu, et al. <em>Contemporary Symbolic Regression Methods and their Relative Performance</em>. 2021.</li>
</ol>]]></content><author><name>cty</name></author><category term="科研" /><category term="符号回归" /><category term="可解释性" /><category term="RLHF" /><summary type="html"><![CDATA[1. 符号回归中的“复杂度”与“可解释性”：一个经常被默认、却并不稳固的等号 符号回归大家都耳熟能详了：它不仅要拟合数据，还要吐出一个人可以读、可以想、甚至可以进一步拿去推导的方程。也正因为这个承诺，复杂度（complexity）几乎成了这个领域最常见的第二目标。除了拟合误差，我们通常还会最小化树大小、节点数、运算符数量、带权运算符数量，或者干脆做一个 accuracy-complexity 的 Pareto front。这个做法并不奇怪，因为表达式短一些、浅一些、少几层嵌套，通常确实更容易看。 但这里有一个默认前提：复杂度可以作为可解释性的代理。 根据Occam’s Razor原则，这个前提大多数时候是成立的，但并不严格。一个式子更短，不等于它更容易被人理解；一个式子包含更少的节点，也不意味着它更接近人类科学建模时偏好的形式。尤其在物理问题里，这个落差其实非常明显。一个包含少量三角、指数或嵌套分式的表达式，树长可能不大，但读起来可能非常拧；反过来，一个稍长的多项式、无量纲组合或者分层展开式，虽然节点更多，却往往更符合人的推理习惯。 因此，我觉得符号回归里“复杂度”这个概念可以分成三层来看。 第一层是纯语法复杂度。这类定义最常见，也最便宜。树大小、节点数、operator count 都属于这一类。它们的优点非常明显：稳定、通用、实现简单、适合直接放到搜索过程中做 regularization 或 Pareto optimization。SRBench 一类工作最终采用的也是这种偏统一、偏工程的复杂度指标，因为它足够可复现，方便跨算法比较。 第二层是轻语义复杂度。这类做法承认不同算子带给人的负担并不一样，因此尝试给函数符号加权。例如加减乘除、幂、log、exp、三角函数并不等权。Kommenda 等人的工作就明确讨论过：单纯的 size-related complexity 只描述表达式树的形状，而不能反映表达式内部运算的“认知难度”，所以可以加入对函数符号的语义区分。PSE 这篇工作在实现中采用的，也正是这种精神：表面上说是“operator 数量的 proxy”，实际代码里却已经是带权运算符复杂度了。 第三层才是我真正关心的：人类可解释性本身。 这件事并不是一个纯语法对象。人类在看一个公式时，会自然地受到许多因素影响：它是否容易心算或局部模拟，它是否可以分解成几个彼此可命名的块，它是否包含过多非算术操作，它是否反复嵌套某类函数，它是否和该领域常见的理论结构相似。换句话说，人类并不是在“数节点”，而是在“读结构”。 Virgolin 等人 2020 年的一篇工作，正是试图解决这个问题。他们没有再假设“size 越小越可解释”，而是反过来问：能不能直接从人的反馈里学一个 interpretability proxy？ 他们设计了一个关于数学公式的问卷，围绕 simulatability 和 decomposability 两种常见的 proxy of human interpretability 收集数据，再用学习到的模型去估计一个公式的人类可解释性，并把这个模型嵌回多目标遗传编程中。这个思路在我看来很重要，因为它至少说明了一件事：在符号回归里，我们其实不必把“复杂度”永远当成不可动摇的手工先验；它完全可以是一个被学习的偏好函数。 所以，我们接下来要考虑的就不再是“什么复杂度定义最合理”，而是：人到底偏好什么样的公式？这个偏好能否被学习并在搜索中施加？ 从这个角度看，树大小、运算符数量、带权复杂度，都更像是一种廉价的、静态的、预先写死的 proxy。它们的价值在于便宜，不在于真实。它们可以作为起点，但未必适合作为终点。 2. RLHF 在LLM的Post-training领域，经常用到一种名为RLHF（Reinforcement Learning from Human Feedback，基于人类反馈的强化学习）的微调技术。 在强化学习的传统设定里，我们默认任务目标已经被清晰地写成了奖励函数。可现实里恰恰有很多目标不是这样。 早在2017年，Christiano 等人指出：许多任务的目标复杂、含糊、难以精确定义，手写 reward 往往会造成“奖励函数被优化了，但真正想要的行为没有出现”。于是他们不再要求人直接写出 reward，而是让人去比较两段行为片段哪个更符合偏好，再用这些比较数据训练 reward model，最后让策略去优化这个 learned reward。 这个框架后来在大语言模型里被真正普及开来。InstructGPT 那篇工作给出了一条现在大家都很熟悉的流程：先做监督微调（SFT），拿到一个基本会“按要求回答”的初始策略；然后让标注者对多个回答做排序，训练一个 reward model；最后再用 PPO 之类的 RL 方法去优化语言模型，使它更符合人类偏好。这里最重要的思想是：当目标无法被显式写出时，可以先收集偏好，再学习奖励，再优化策略。 这不正是我们想要的吗？这套思想在符号回归里同样适用：我们不必把“可解释性”这个目标硬塞进一个手写的复杂度函数里，而是可以直接从人对候选公式的偏好中学一个 interpretability reward model，再让符号生成器去优化这个 learned reward。 3. 从 Virgolin 的 proxy 出发：能不能用 RLHF 去约束符号回归中的可解释性？ 3.1 为什么这个方向是自然的 先看 Virgolin 的工作到底做了什么。它其实已经完成了 RLHF 思路中最关键的一半：从人类反馈学习一个偏好代理。 只不过它当时并不是沿着“alignment”这套叙事来讲，而是沿着“interpretable symbolic regression”去讲。它的核心逻辑是： 让人对公式的可解释性相关属性作出反馈； 用这些反馈拟合一个可解释性 proxy； 把这个 proxy 嵌入搜索过程，替代简单的 size minimization。 这和 RLHF 的结构已经非常相似了。差别主要在于： Virgolin 的 proxy 更像一个静态评估器，主要作为多目标优化中的第二目标； RLHF 则更强调“偏好—奖励—策略更新”的闭环，把 learned preference 直接用于改变生成分布。 能否把 Virgolin 那种静态 proxy，升级为一个真正参与公式生成过程的偏好学习框架？ 3.1 一个可能的总体框架 第一层：先把问题表述成 preference learning，而不是 complexity engineering 这一步最重要。我们不再手写一个固定复杂度函数，而是让标注者在同一任务、相近精度的前提下，对两个候选公式回答一个更自然的问题： 哪个更容易理解？ 哪个更像你愿意写进论文的最终公式？ 哪个更容易手工推演、讲给别人听、或者映射到已有理论？ 这里一定要强调“在相近精度下”进行比较，否则人会被拟合误差主导，偏好数据会退化成“谁更准就选谁”。换句话说，我们要学的是在 accuracy 已经基本过关之后，人对公式结构的偏好。 这一步甚至不一定要求标注者给分数。我反而觉得 pairwise preference 更可靠，因为“7 分和 8 分的差别是什么”很难说清，但“这两个里面哪个更顺眼”通常容易得多。 第二层：学一个 task-conditioned 的 interpretability model 我不太赞成只输入公式本身。因为公式是否好理解，经常是任务相关的。 举个简单例子： 在控制、流体、传热里，无量纲群往往很自然； 在某些经验建模问题里，分段、饱和、阈值结构可能更符合人的先验； 在基础物理里，某些三角或指数形式并不难懂，甚至比高阶多项式更自然。 所以，一个更合理的偏好模型，输入不该只有 expression tree，还应包括任务上下文，例如变量名、量纲、物理语义标签、是否已经无量纲化、误差水平、甚至候选公式所在的 Pareto 邻域。也就是说，我们要学的可能不是单纯的 $p(\text{interpretable}\mid f)$，而是 $p(\text{preferred}\mid f, \mathcal{T})$。 这一步其实比“复杂度定义”前进了一大步：复杂度通常是假设全任务共享一套静态标尺，而偏好模型允许不同任务、不同学科对“好公式”的判断不同。 第三层：再决定如何把偏好注入生成器 这时就出现三条路线。 第一条，最像经典 RLHF。训练一个 reward model，分数反映公式在当前任务下的可解释性偏好，然后把公式生成器当成 policy 去优化。生成器可以是序列模型、树生成模型、MCTS、遗传编程，甚至某种 grammar-guided sampler。只要它能产出候选公式，并支持基于 reward 改变采样分布，就能接进去。 第二条，更像 DPO。直接对同一任务下的好/坏公式对进行优化，让生成器提高偏好公式的概率，降低不被偏好的公式概率，而不显式训练 reward model。这个方案对深度生成式符号回归尤其合适，因为它更像“语言模型偏好对齐”的公式版。 第三条，更像 RLAIF。先写一套比较明确的“公式宪法”，再让辅助模型或规则系统产生部分比较信号。例如： 避免连续三层以上非算术操作嵌套； 优先选择可以拆成少量物理可命名模块的公式； 在物理问题中优先保留量纲齐次或无量纲结构； 对相同精度下的候选式，优先选择在局部极限下行为更可解释的表达； 对可以符号化简到相同形式的候选，不奖励纯表面差异。 这类方案的价值在于，它能显著降低人工标注成本，把少量高质量专家反馈扩展成较大规模的伪偏好数据。 3.3 这个方向真正难的地方在哪里 我觉得可行性是有的，但困难也很真实，而且并不只是“算力够不够”这么简单。 难点一：可解释性不是绝对属性，而是关系属性 一个公式的“好不好懂”往往取决于对谁而言、在什么任务里、和什么候选相比。对于熟悉傅里叶分析的人，正弦项不一定难；对于做热工关联式的人，某些经验指数关系反而很自然；而对另一类研究者，同样的形式可能完全陌生。 这意味着我们最好学的是偏好分布，而不是一个试图放之四海而皆准的“绝对解释性分数”。如果做得更进一步，甚至可以考虑 personalized interpretability，也就是根据不同用户群体学习不同偏好模型。 难点二：公式有等价性，偏好数据会被表示法污染 数学表达式的一个麻烦在于，不同写法可能是同一个式子。比如因式分解前后、常数吸收前后、对数幂变换前后，表面长度和结构差别很大，但数学上几乎等价。如果不做 canonicalization 或符号化简，偏好学习很容易学到“排版习惯”而不是“结构偏好”。 因此，这类系统必须把等价类处理当成核心基础设施，而不是后处理小修小补。至少要尽可能做符号化简、常数标准化、树结构规范化，最好还能对“可被局部代换解释为同一结构”的公式做聚类。 难点三：人类反馈很贵，而且专家反馈更贵 这也是为什么我不认为“完整人工 RLHF”会是第一步的最佳选择。符号回归的可解释性判断，经常需要一定数学或领域背景，不像一般文本偏好那样可以大规模众包。因此，更现实的路线可能是： 先用 Virgolin 一类问卷数据或小规模专家数据得到第一版 proxy； 再用主动学习，只对 reward model 最不确定的候选对请求人工比较； 同时引入 constitution/rule-based feedback 扩充数据； 最后只在关键任务上让专家做高价值校正。 难点四：偏好约束可能和精度、发现真规律的目标发生冲突 这是我觉得最需要警惕的一点。物理规律并不保证总是“人类第一眼觉得最顺眼”的。过强的可解释性偏好，可能会把搜索推向过度简单、过度教科书式的区域，反而错过真实但稍显复杂的结构。 所以更合理的方式可能是： 仍然保留 accuracy 或 evidence 作为硬约束或主目标； 把可解释性当作在近似等精度模型之间做选择的偏好； 用 KL 约束、Pareto front 或 constrained optimization 防止生成器为了迎合偏好而牺牲太多真实性。 4. 参考 Paul F. Christiano, Jan Leike, Tom B. Brown, Miljan Martic, Shane Legg, Dario Amodei. Deep Reinforcement Learning from Human Preferences. NeurIPS 2017. Long Ouyang, Jeff Wu, Xu Jiang, et al. Training Language Models to Follow Instructions with Human Feedback. NeurIPS 2022. Rafael Rafailov, Archit Sharma, Eric Mitchell, Stefano Ermon, Christopher D. Manning, Chelsea Finn. Direct Preference Optimization: Your Language Model is Secretly a Reward Model. NeurIPS 2023. Yuntao Bai, Saurav Kadavath, Sandipan Kundu, et al. Constitutional AI: Harmlessness from AI Feedback. 2022. Marco Virgolin, Andrea De Lorenzo, Eric Medvet, Francesca Randone. Learning a Formula of Interpretability to Learn Interpretable Formulas. PPSN 2020. Michael Kommenda, Andreas Beham, Michael Affenzeller, Gabriel Kronberger. Complexity Measures for Multi-objective Symbolic Regression. 2021. William La Cava, Patryk Orzechowski, Bogdan Burlacu, et al. Contemporary Symbolic Regression Methods and their Relative Performance. 2021.]]></summary></entry><entry><title type="html">学习笔记——Agent的概念、原理与构建模式</title><link href="https://pistilreaper.github.io/Agent%E7%9A%84%E6%A6%82%E5%BF%B5-%E5%8E%9F%E7%90%86%E4%B8%8E%E6%9E%84%E5%BB%BA%E6%A8%A1%E5%BC%8F/" rel="alternate" type="text/html" title="学习笔记——Agent的概念、原理与构建模式" /><published>2026-04-09T00:00:00+00:00</published><updated>2026-04-09T00:00:00+00:00</updated><id>https://pistilreaper.github.io/Agent%E7%9A%84%E6%A6%82%E5%BF%B5%E3%80%81%E5%8E%9F%E7%90%86%E4%B8%8E%E6%9E%84%E5%BB%BA%E6%A8%A1%E5%BC%8F</id><content type="html" xml:base="https://pistilreaper.github.io/Agent%E7%9A%84%E6%A6%82%E5%BF%B5-%E5%8E%9F%E7%90%86%E4%B8%8E%E6%9E%84%E5%BB%BA%E6%A8%A1%E5%BC%8F/"><![CDATA[<h1 id="1-什么是agent">1. 什么是Agent？</h1>

<p>普通的LLM擅长回答问题，但也存在一个限制，那就是它们<strong>无法感知或者是改变外界环境</strong>。</p>

<p>比如，让GPT5-4写一段关于xxx的代码，它只能提供给你代码段，但具体生成代码文件、运行和测试代码文件的过程需要我们自己来做，也就是说，LLM无法改变外界环境。而如果当本地已经有部分代码，希望增加部分功能时，必须将本地的代码文件上传给LLM或者直接粘贴代码块，如果不主动告诉LLM，它是不可能知道我们的代码啥样的，这正是LLM无法感知外界环境的表现。</p>

<p>一种解决这个问题的方案是让LLM使用对应的<strong>工具（tools）</strong>，例如让它可以读写文件内容、查看文件列表、运行终端命令，这样它就能完全自动化的构建代码项目。像这样把一个LLM和一堆工具组装起来，使其变成一个能改变或感知外界环境的程序，我们就称其为<strong>Agent</strong>。</p>

<p>Agent是多样的，具体为不同的任务可以设计不同的Agent，例如编程Agent，cursor，用于办公和分析的Agent，Manus。</p>

<h1 id="2-agent的运行模式">2. Agent的运行模式</h1>

<h2 id="21-react模式">2.1 ReAct模式</h2>

<p><strong>ReAct</strong>全称为Reasoning and Acting，可能是目前使用最为广泛的Agent运行模式。该模式最早由姚顺雨（现在，也就是2026年在腾讯挂帅AI首席科学家）在ICLR 2023提出。</p>

<p><img src="..\images\Agent\react.png" alt="REAC T: SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS" /></p>

<p>在该模式下，用户先提交任务，然后Agent做思考（thought），然后去判断是否调用工具，如果是，Agent将进行行动（action），然后观察（observation）行动的执行结果，随后继续进行思考，循环往复，直到Agent认为不再需要调用工具，可以直接给出结论了，则会输出最终答案（Final answer）。以上即为ReAct模式的流程。</p>

<p>那么如何实现ReAct模式呢？简单来说，其实就是设计系统提示词。</p>
<h2 id="22-plan-and-execute模式">2.2 Plan and Execute模式</h2>

<p>从总体上看，这种模式遵循了先规划、再执行的流程。在整个流程中，粗粒度看只有两个关键角色，一个是用户，另一个是Plan-And-Execute Agent。这个PAE Agent由以下几个部分组成：首先是负责出执行计划的Plan model，然后呢，我们在运行的过程中，还需要一个能够根据每一步的执行结果来动态调整计划的Re-Plan model，负责修改执行计划，Plan model和Re-plan model可以是同一个模型负责两个部分，也可以是独立的两个模型，除此之外，我们还需要一个可以按照计划执行的模型，即执行Agent（这是一个子Agent），最后，我们需要一套主程序来把上述这些模型组织起来。</p>

<p>具体来说，首先，用户会把问题提交给Agent主程序，Agent主程序接到这个指令后，会把这个指令发给Plan模型，让它给出具体的执行步骤；有了计划后，主程序会把计划传递给执行Agent，告诉他请执行第一步（这个执行Agent本身可以用上一节的ReAct模式来运行）；执行Agent会把执行结果反馈给Agent主程序，而主程序会把这些执行结果、执行记录和上一次的Plan都发给Re-Plan模型，让它生成一个新的执行计划；主程序会接受这个新的执行计划，并再一次将计划传递给执行Agent。重复该过程n次，直到Re-Plan模型认为结果已经得到，结束循环，返回答案给主程序。最终主程序将这个答案转发给用户。</p>

<p>在整个过程中，执行记录是会一直边长的，即过去的记录会保留，而一般来说，执行计划是不断变化的，他会经过Plan model和Re-plan model一直更新。</p>

<h1 id="3-运行模式的比较">3. 运行模式的比较</h1>

<p>ReAct模式的优势是，由于system prompt是你自己写的，约束是你自己加的，所以约束相对于整个prompt的嵌入就会很自然。自然的好处就是自定义空间很大，另外可以通过集中LLM的注意力来增强prompt的效果（这里有一个稍微复杂点的attention的问题，理解它对应用来讲不是很重要所以我就不细讲了），以及出了问题（例如LLM的返回不符合预期）后好找问题，回去读一遍自己写的prompt嘛。如果你有一些相对关键的约束，希望LLM可以严格执行的那种，也建议自己动手写进system prompt并且用语言着重强调，这是通过代码注册无法办到的。</p>

<p>Plan and Execute模式的优势是tools list非常灵活，可以随时添加减少。这个优势在一些大型项目中比较有用，因为这两年流行的一种节省窗口的方式是根据对话需求先用一个小agent筛选工具，然后只将有用的工具提供给主agent（可以理解为你工具箱里有1000个各式各样的道具，你的用户说他想装修房子，先有个人从工具箱里挑了十几个工具出来，然后你抱着这十几个工具去找装修师傅去了）。这种情况下可以通过Python来随时结构tools list就非常有用，因为这意味着你不需要在system prompt里面通过string搞来搞去了（当然本质上就是langchain替你去搞这些了）。</p>

<p>简单来讲，第二种模式相当于是第一种模式的预制菜。如果第二种模式能满足你的需求，那么它的优势就是上手简单。但如果你使用第二种模式时遇到了某种瓶颈，无论是算力还是别的什么，你可以试试用第一种模式，说不定有奇效。</p>

<h2 id="4-实践">4. 实践</h2>

<p>之后如果博主应该会抽时间做一系列小的Agent项目，这一部分待更新。</p>

<h2 id="参考">参考</h2>

<p><a href="https://www.bilibili.com/video/BV1TSg7zuEqR/?share_source=copy_web&amp;vd_source=0d8ad99fdd9c0fbacc16ee9eb5ad0f9e">Agent 的概念、原理与构建模式 —— 从零打造一个简化版的 Claude Code</a></p>]]></content><author><name>cty</name></author><category term="学习笔记" /><category term="LLM" /><category term="Agent" /><summary type="html"><![CDATA[1. 什么是Agent？ 普通的LLM擅长回答问题，但也存在一个限制，那就是它们无法感知或者是改变外界环境。 比如，让GPT5-4写一段关于xxx的代码，它只能提供给你代码段，但具体生成代码文件、运行和测试代码文件的过程需要我们自己来做，也就是说，LLM无法改变外界环境。而如果当本地已经有部分代码，希望增加部分功能时，必须将本地的代码文件上传给LLM或者直接粘贴代码块，如果不主动告诉LLM，它是不可能知道我们的代码啥样的，这正是LLM无法感知外界环境的表现。 一种解决这个问题的方案是让LLM使用对应的工具（tools），例如让它可以读写文件内容、查看文件列表、运行终端命令，这样它就能完全自动化的构建代码项目。像这样把一个LLM和一堆工具组装起来，使其变成一个能改变或感知外界环境的程序，我们就称其为Agent。 Agent是多样的，具体为不同的任务可以设计不同的Agent，例如编程Agent，cursor，用于办公和分析的Agent，Manus。 2. Agent的运行模式 2.1 ReAct模式 ReAct全称为Reasoning and Acting，可能是目前使用最为广泛的Agent运行模式。该模式最早由姚顺雨（现在，也就是2026年在腾讯挂帅AI首席科学家）在ICLR 2023提出。 在该模式下，用户先提交任务，然后Agent做思考（thought），然后去判断是否调用工具，如果是，Agent将进行行动（action），然后观察（observation）行动的执行结果，随后继续进行思考，循环往复，直到Agent认为不再需要调用工具，可以直接给出结论了，则会输出最终答案（Final answer）。以上即为ReAct模式的流程。 那么如何实现ReAct模式呢？简单来说，其实就是设计系统提示词。 2.2 Plan and Execute模式 从总体上看，这种模式遵循了先规划、再执行的流程。在整个流程中，粗粒度看只有两个关键角色，一个是用户，另一个是Plan-And-Execute Agent。这个PAE Agent由以下几个部分组成：首先是负责出执行计划的Plan model，然后呢，我们在运行的过程中，还需要一个能够根据每一步的执行结果来动态调整计划的Re-Plan model，负责修改执行计划，Plan model和Re-plan model可以是同一个模型负责两个部分，也可以是独立的两个模型，除此之外，我们还需要一个可以按照计划执行的模型，即执行Agent（这是一个子Agent），最后，我们需要一套主程序来把上述这些模型组织起来。 具体来说，首先，用户会把问题提交给Agent主程序，Agent主程序接到这个指令后，会把这个指令发给Plan模型，让它给出具体的执行步骤；有了计划后，主程序会把计划传递给执行Agent，告诉他请执行第一步（这个执行Agent本身可以用上一节的ReAct模式来运行）；执行Agent会把执行结果反馈给Agent主程序，而主程序会把这些执行结果、执行记录和上一次的Plan都发给Re-Plan模型，让它生成一个新的执行计划；主程序会接受这个新的执行计划，并再一次将计划传递给执行Agent。重复该过程n次，直到Re-Plan模型认为结果已经得到，结束循环，返回答案给主程序。最终主程序将这个答案转发给用户。 在整个过程中，执行记录是会一直边长的，即过去的记录会保留，而一般来说，执行计划是不断变化的，他会经过Plan model和Re-plan model一直更新。 3. 运行模式的比较 ReAct模式的优势是，由于system prompt是你自己写的，约束是你自己加的，所以约束相对于整个prompt的嵌入就会很自然。自然的好处就是自定义空间很大，另外可以通过集中LLM的注意力来增强prompt的效果（这里有一个稍微复杂点的attention的问题，理解它对应用来讲不是很重要所以我就不细讲了），以及出了问题（例如LLM的返回不符合预期）后好找问题，回去读一遍自己写的prompt嘛。如果你有一些相对关键的约束，希望LLM可以严格执行的那种，也建议自己动手写进system prompt并且用语言着重强调，这是通过代码注册无法办到的。 Plan and Execute模式的优势是tools list非常灵活，可以随时添加减少。这个优势在一些大型项目中比较有用，因为这两年流行的一种节省窗口的方式是根据对话需求先用一个小agent筛选工具，然后只将有用的工具提供给主agent（可以理解为你工具箱里有1000个各式各样的道具，你的用户说他想装修房子，先有个人从工具箱里挑了十几个工具出来，然后你抱着这十几个工具去找装修师傅去了）。这种情况下可以通过Python来随时结构tools list就非常有用，因为这意味着你不需要在system prompt里面通过string搞来搞去了（当然本质上就是langchain替你去搞这些了）。 简单来讲，第二种模式相当于是第一种模式的预制菜。如果第二种模式能满足你的需求，那么它的优势就是上手简单。但如果你使用第二种模式时遇到了某种瓶颈，无论是算力还是别的什么，你可以试试用第一种模式，说不定有奇效。 4. 实践 之后如果博主应该会抽时间做一系列小的Agent项目，这一部分待更新。 参考 Agent 的概念、原理与构建模式 —— 从零打造一个简化版的 Claude Code]]></summary></entry><entry><title type="html">善用SDD助力AI coding</title><link href="https://pistilreaper.github.io/%E5%96%84%E7%94%A8SDD%E7%94%9F%E6%80%81%E5%8A%A9%E5%8A%9BAI-coding/" rel="alternate" type="text/html" title="善用SDD助力AI coding" /><published>2026-03-25T00:00:00+00:00</published><updated>2026-03-25T00:00:00+00:00</updated><id>https://pistilreaper.github.io/%E5%96%84%E7%94%A8SDD%E7%94%9F%E6%80%81%E5%8A%A9%E5%8A%9BAI%20coding</id><content type="html" xml:base="https://pistilreaper.github.io/%E5%96%84%E7%94%A8SDD%E7%94%9F%E6%80%81%E5%8A%A9%E5%8A%9BAI-coding/"><![CDATA[<h1 id="1-什么是sdd">1. 什么是SDD？</h1>

<p>AI coding时下十分火爆，大家纷纷尝试claude code、codex、open code等AI编程工具加速开发，但使用这些工具时，抛开飞速跳跃的消耗token数不谈，一个很让人难受的点是AI工具一顿猛写，结果发现先出来的代码与自己的想法总是有偏差。而且，我们大部分科研人一般不会让AI从0开发，常见的需求一般是让AI结合已有框架或仓库做增量开发或功能修改，这时候AI工具被限制在了框框里（如果给AI从0开发的空间，有时候它甚至会表现得更好），往往会写出与原始代码风格完全不同的东西，很多功能倾向于另起炉灶，而这是我们不愿意看到的。</p>

<p>那么，有没有什么方法让AI能像一个可靠的合作者一样，基于一套规范的开发流程，按照用户的要求在限制内做好二次开发呢？这里我们要引入一个叫做<strong>SDD</strong>（<strong>Spec-Driven Development</strong>）的方法论，也就是“规范驱动开发”。SDD的核心理念是先编写‌<strong>结构化、可执行的规范</strong>‌（Spec），再由AI生成代码，确保质量与可维护性。</p>

<p>这里我记录一个帮助我们进行SDD的开源仓库<a href="https://github.com/Fission-AI/OpenSpec">OpenSpec</a>，并使用codex做演示，介绍OpenSpec的常见功能。</p>

<h1 id="2-openspec">2. OpenSpec</h1>

<p>OpenSpec是一个轻量化的工具，可以辅助我们的coding agent生成规范的代码。每次提出新的需求前，它会先让agent按照一个工作流生成标准文档，用户审核这些文档后，再开始具体的代码编写工作。</p>
<h2 id="21-安装和初始化">2.1 安装和初始化</h2>

<p>首先在全局安装OpenSpec：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install</span> <span class="nt">-g</span> @fission-ai/openspec@latest
</code></pre></div></div>

<p>可以用以下命令验证安装是否成功：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openspec <span class="nt">--version</span>
</code></pre></div></div>

<p>然后进入工作目录，进行项目规范初始化：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>your-project
openspec init
</code></pre></div></div>

<p>初始化成功如图所示，图中也展示了我们常用的几个命令：</p>

<p><img src="..\images\Agent\openspec.png" alt="初始化" /></p>

<p>按enter选择工具，这里我们选择Codex，当然你也可以选择Claude Code或其他coding agent。</p>

<p>初始化后，OpenSpec会在当前工作区根目录下创建一个文件夹<code class="language-plaintext highlighter-rouge">openspec</code>，其中会有两个子文件夹，分别是<code class="language-plaintext highlighter-rouge">spec</code>（放我们项目的规范）和<code class="language-plaintext highlighter-rouge">changes</code>(放每个正在进行的变更)。</p>

<h2 id="22-斜杠命令">2.2 斜杠命令</h2>

<p>初始化好之后，我们就可以正常的在coding agent中使用斜杠命令来与OpenSpec进行交互了。</p>

<p>正常使用命令唤起coding agent，这里我们使用<code class="language-plaintext highlighter-rouge">codex</code>唤起Codex，接下来就是使用以下命令告诉AI我们想实现的是什么了：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opsx:propose &lt;what-you-want-to-build&gt;
</code></pre></div></div>

<p>这个命令会强制让agent进行思考，生成<code class="language-plaintext highlighter-rouge">design.md</code>, <code class="language-plaintext highlighter-rouge">proposal.md</code>, <code class="language-plaintext highlighter-rouge">task.md</code>这三个文件，分别是技术设计、提案和任务清单，此时我们要做的就是Review这些文档，有问题的地方直接修改，当然，我们也可以用自然语言告诉agent我们需要改什么，让他来修改这些文档。</p>

<p>确定没问题后，运行：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opsx:apply
</code></pre></div></div>

<p>Agent会按照<code class="language-plaintext highlighter-rouge">task.md</code>的指示去实习提案。</p>

<h1 id="3-总结">3. 总结</h1>

<p>其实OpenSpec做的事非常简单，他就是把plan and execute模式落实得更具体了，强制Agent先做规范设计，再去实现代码，同时，它会让Agent把过去工作中我们的规范保留下来，在做后续更新时这些规范依然会生效。</p>]]></content><author><name>cty</name></author><category term="学习笔记" /><category term="Agent" /><category term="SDD" /><summary type="html"><![CDATA[1. 什么是SDD？ AI coding时下十分火爆，大家纷纷尝试claude code、codex、open code等AI编程工具加速开发，但使用这些工具时，抛开飞速跳跃的消耗token数不谈，一个很让人难受的点是AI工具一顿猛写，结果发现先出来的代码与自己的想法总是有偏差。而且，我们大部分科研人一般不会让AI从0开发，常见的需求一般是让AI结合已有框架或仓库做增量开发或功能修改，这时候AI工具被限制在了框框里（如果给AI从0开发的空间，有时候它甚至会表现得更好），往往会写出与原始代码风格完全不同的东西，很多功能倾向于另起炉灶，而这是我们不愿意看到的。 那么，有没有什么方法让AI能像一个可靠的合作者一样，基于一套规范的开发流程，按照用户的要求在限制内做好二次开发呢？这里我们要引入一个叫做SDD（Spec-Driven Development）的方法论，也就是“规范驱动开发”。SDD的核心理念是先编写‌结构化、可执行的规范‌（Spec），再由AI生成代码，确保质量与可维护性。 这里我记录一个帮助我们进行SDD的开源仓库OpenSpec，并使用codex做演示，介绍OpenSpec的常见功能。 2. OpenSpec OpenSpec是一个轻量化的工具，可以辅助我们的coding agent生成规范的代码。每次提出新的需求前，它会先让agent按照一个工作流生成标准文档，用户审核这些文档后，再开始具体的代码编写工作。 2.1 安装和初始化 首先在全局安装OpenSpec： npm install -g @fission-ai/openspec@latest 可以用以下命令验证安装是否成功： openspec --version 然后进入工作目录，进行项目规范初始化： cd your-project openspec init 初始化成功如图所示，图中也展示了我们常用的几个命令： 按enter选择工具，这里我们选择Codex，当然你也可以选择Claude Code或其他coding agent。 初始化后，OpenSpec会在当前工作区根目录下创建一个文件夹openspec，其中会有两个子文件夹，分别是spec（放我们项目的规范）和changes(放每个正在进行的变更)。 2.2 斜杠命令 初始化好之后，我们就可以正常的在coding agent中使用斜杠命令来与OpenSpec进行交互了。 正常使用命令唤起coding agent，这里我们使用codex唤起Codex，接下来就是使用以下命令告诉AI我们想实现的是什么了： /opsx:propose &lt;what-you-want-to-build&gt; 这个命令会强制让agent进行思考，生成design.md, proposal.md, task.md这三个文件，分别是技术设计、提案和任务清单，此时我们要做的就是Review这些文档，有问题的地方直接修改，当然，我们也可以用自然语言告诉agent我们需要改什么，让他来修改这些文档。 确定没问题后，运行： /opsx:apply Agent会按照task.md的指示去实习提案。 3. 总结 其实OpenSpec做的事非常简单，他就是把plan and execute模式落实得更具体了，强制Agent先做规范设计，再去实现代码，同时，它会让Agent把过去工作中我们的规范保留下来，在做后续更新时这些规范依然会生效。]]></summary></entry><entry><title type="html">科研随笔——量纲与符号回归</title><link href="https://pistilreaper.github.io/%E7%A7%91%E7%A0%94%E9%9A%8F%E7%AC%94-%E9%87%8F%E7%BA%B2%E4%B8%8E%E7%AC%A6%E5%8F%B7%E5%9B%9E%E5%BD%92/" rel="alternate" type="text/html" title="科研随笔——量纲与符号回归" /><published>2026-03-18T00:00:00+00:00</published><updated>2026-03-18T00:00:00+00:00</updated><id>https://pistilreaper.github.io/%E7%A7%91%E7%A0%94%E9%9A%8F%E7%AC%94%E2%80%94%E2%80%94%E9%87%8F%E7%BA%B2%E4%B8%8E%E7%AC%A6%E5%8F%B7%E5%9B%9E%E5%BD%92</id><content type="html" xml:base="https://pistilreaper.github.io/%E7%A7%91%E7%A0%94%E9%9A%8F%E7%AC%94-%E9%87%8F%E7%BA%B2%E4%B8%8E%E7%AC%A6%E5%8F%B7%E5%9B%9E%E5%BD%92/"><![CDATA[<h1 id="1-超越量纲本身的语义">1. 超越量纲本身的语义</h1>

<p>量纲分析，或者 Buckingham-PI 定理被经常拿来做符号回归算法的先验物理约束。量纲提供了一种极其廉价、却又确实有效的物理正则。它把变量从纯粹的数值列中拎出来，使模型至少知道哪些量可以相加，哪些量只能相乘，哪些组合在物理上没有意义。</p>

<p>常见的量纲约束分为2种：</p>

<ul>
  <li>
    <ol>
      <li>以本课题组发展的DHC-GEP、SITE框架为代表的量纲校核约束。这类方法常常先任意进行符号组合，随后将预先给定的符号量纲进行运算，给无法通过校核的表达式赋予大额的损失，强制淘汰。另一种类似的方式是，把量纲的匹配程度量化为一个罚函数，再通过一个可调超参数进行scaling，然后加到主损失函数上，这种做法不会百分百杜绝量纲不齐次的方程，但也因此不至于出现种群难以进化的现象（SITE的seed injection strategy就是用来解决直接赋予大损失带来的进化停滞问题）。</li>
    </ol>
  </li>
  <li>
    <ol>
      <li>以Fukami的JFM（2024）、Bakarji的NCS（2022）、Xie的NC（2021）以及Xia的EAAI（2026）为代表的无量纲学习（dimensionless learning）方法。这类方法都是先用<strong>量纲约束</strong>把候选表达限制在“物理上允许”的空间里，再用数据去解决 Buckingham Π 定理“<strong>可行但不唯一</strong>”的问题，找出最能解释输出、最有泛化能力的低维无量纲表示。</li>
    </ol>
  </li>
</ul>

<p>然而，量纲能提供的物理量的物理本质信息是很有限的，它刻画的是物理量可参与何种形式运算的边界，却没有触及这个物理量在理论结构中究竟扮演什么角色。同量纲变量之间的差别，正好暴露了这一层缺失。例如，速度、声速、扩散波速、相速度，量纲完全一致，数值尺度却可能相差多个数量级，更关键的是，它们进入方程的方式并不相同。某些量是系统状态，某些量是传输通量，某些量是材料参数，某些量则体现外部驱动或边界条件。只看量纲，这些差异全部被压缩了；只看数值，这些差异又被具体问题中的尺度、单位和采样方式淹没了。真正缺失的，似乎是<strong>量纲之上、数值之下的那一层物理语义</strong>。</p>

<p>这层语义首先不是语言学意义上的名字，而是变量在物理结构中的位置。一个物理量是否守恒，是否可积，是否依赖参考系，是否具有方向性，是否描述局域状态还是跨边界交换，是否更接近原因还是结果，这些性质比变量名稳定得多，也比量纲更接近机制。换句话说，速度之所以不是声速，不在于它们叫法不同，也不在于单位不同，而在于它们分别对应不同的生成机制、不同的控制参数、不同的理论角色。前者通常是物体运动状态的一部分，后者更接近介质性质与热力学状态共同决定的传播特征。二者可以在同一组方程中相遇，但很少处于同一语义位置。</p>

<p>因此，更合适的中间表示，未必是再造一个比量纲稍复杂一些的离散标签，而应当是一组描述变量物理角色的语义坐标。这个表示可以包含若干彼此独立的轴：它是状态量还是参数，是广延量还是强度量，是守恒变量还是本构变量，是局域定义还是非局域定义，是标量、矢量还是张量，是坐标变换下不变还是协变，是主要体现时间演化还是空间耦合。它们不像自然语言那样松散，也不像数值那样依赖具体样本分布，而是贴近理论建模时真正关心的结构信息。</p>

<p>这件事还有一层更深的意义。量纲本质上是一种代数约束，它告诉我们表达式能否成立；语义角色则更接近结构约束，它告诉我们表达式为何会出现。代数约束能缩小搜索空间，结构约束则能改变搜索空间的形状。符号回归若只使用量纲，它依然在表达式层面搜索，只是少走一些死路；若进一步掌握变量的语义角色，它就有机会在机制层面组织搜索，把候选表达式限制在某类物理过程允许的范围内。这样一来，模型寻找的就不再只是形式上合法的组合，而是更可能对应真实生成机制的组合。从这个角度看，变量名本身也不应被简单丢弃。多数工作把变量名视为无信息标签，这在机器学习上很自然，因为字符串本身确实不携带稳定的数学结构。但在科学问题里，变量名往往是研究共同体长期压缩后的知识入口。压力、温度、密度、化学势，这些名称背后连着的是实验操作、理论传统、适用范围与典型近似。直接把名字输入模型当然过于粗糙，也容易引入语料偏见；可若把它们完全抹去，同样是在主动舍弃知识。更合理的做法，是不把名称当作最终表示，而把它当作检索语义属性的入口，再把这些较稳定、可形式化的属性编码为中间层。</p>

<h1 id="2-beyond-data-to-equation">2. Beyond data-to-equation</h1>

<p>我们知道符号回归的目标是给定一组labeled的data（其实很多论文中都不做labeled，例如PSE和phyE2E，举例说就是输入数据的标签是无信息的，他只是$x_1$, $x_2$, … 这样子，不关注这列数据向量背后的名字是啥，因为模型也不知道这个名字有什么意义，很多端到端的模型都是只看数据的语义信息），那么上一点中说的量纲其实很特殊，它仍属于标签信息，却已不再是纯粹的符号，而是物理语义压缩后的最简投影（仅用长度为7的向量，且该向量的值一般为小整数，用INT4即可表示）。问题在于，这种压缩也极其剧烈。量纲保留下来的是代数兼容性，折叠掉的却是变量在物理理论中的角色、生成机制和适用范围。</p>

<p>我的直觉告诉我，真正的差异，可能真是在这部分被折叠的信息里。数值序列携带的信息量最大，却高度依赖尺度、单位、采样区间和具体任务；量纲最容易处理，却只给出最低限度的结构边界。两者之间显然还存在一层更有价值的中间表示。它不必像原始数据那样拥挤，也不能像量纲那样过于稀薄。对速度这一类同量纲变量而言，模型需要辨认的并不是单位是否一致，而是它究竟属于系统状态、传播特征、材料参数，还是某种外部驱动；它是否参与守恒关系，是否受参考系影响，是否主要决定时间演化，是否对应局域传输或全局约束。声速、光速和物体运动速度之所以不能互换，关键不在量纲，也不在数值大小，而在它们处于不同的物理角色。</p>

<p>一旦这层表示能够稳定提取，从数据到方程之间那段过长的推断链条就会明显缩短。模型面对的将不再只是匿名数值列，而是一组带有物理角色和结构关系的变量。它先判断哪些量更像状态变量，哪些量更像本构参数，哪些组合可能形成不变量，哪些相互作用更接近守恒律、响应关系或尺度律；随后再在这些语义边界内搜索表达式。这样得到的方程，并非只是拟合误差更小，而是更接近科学问题本身的生成逻辑。</p>

<p>早期的端到端 Transformer 模型则直接从样本点预测完整公式，试图跳过先定骨架、再拟合常数的两阶段流程；SymFormer 又把符号与常数一并生成，减少了后续优化与前向生成之间的割裂。这些工作证明，数据到公式的直接映射是可能的，也说明预训练模型确实能学到某种分布层面的公式先验；不过输入端依旧大多是匿名表格，变量在物理上的身份并未真正进入模型内部。</p>

<p>PhyE2E 往前多走了一步。它先借助 oracle neural network 的二阶导数把问题拆成若干更易处理的子问题，再用 Transformer 做端到端公式翻译（这里还嵌入了量纲信息），并在末端接上 MCTS 与遗传编程做精修。这里最值得注意的，不是具体用了哪一套搜索器，而是它已经不满足于让模型从原始数值直接猜公式，而是先从数据中抽取局部结构信号，再把这些信号送入符号生成阶段。LLM 路线也呈现出类似趋势。LLM-SR 把方程视为程序，用预训练科学知识提出骨架假设，DrSR 更进一步，先分析数据中的单调性、非线性和相关结构，再让生成与反思形成闭环。到了 2026 年，PiT-PO 框架把物理约束与 token 级正则一并纳入策略优化，使搜索反馈真正进入模型参数更新；符号回归的重心也随之从更快生成公式，转向更早恢复决定公式形态的结构信息。</p>

<p>因此，我认为量纲约束的下一步，并不是再设计一个比量纲稍复杂一些的标签系统，而是学习一种可计算的物理语义表征。它既能比量纲承载更多内容，又不至于像原始数值那样混杂。这样的表征至少应当包含三层信息：变量自身的角色，变量之间的关系，变量进入方程时可能服从的结构规则。前一层区分状态量、控制量、材料参数、响应量、守恒量、本构量；中间一层刻画依赖图、耦合强弱、可分离性、对称性、尺度关系和可能的不变量；最后一层限定候选算子族与组合方式，例如哪些量更可能通过梯度、散度、乘性耦合、指数律或幂律进入表达式。到这一步，模型做的就不再是无差别的式子拼接，而是在一个已经受到语义约束的空间里搜索。</p>

<p>TLDR，符号回归未必要从数据直接走到方程。中间完全可以插入一个物理语义层，把数值、量纲、变量名、实验条件、坐标系信息、边界条件和已有知识库共同压缩成统一表示。端到端并不要求取消这一步；更成熟的端到端系统，很可能要把这一步学进模型内部。它先输出变量的语义角色和关系图，再在此基础上生成表达式。符号回归若要真正进入科学发现的核心地带，恐怕绕不过这一步。</p>]]></content><author><name>cty</name></author><category term="科研" /><category term="符号回归" /><category term="量纲分析" /><summary type="html"><![CDATA[1. 超越量纲本身的语义 量纲分析，或者 Buckingham-PI 定理被经常拿来做符号回归算法的先验物理约束。量纲提供了一种极其廉价、却又确实有效的物理正则。它把变量从纯粹的数值列中拎出来，使模型至少知道哪些量可以相加，哪些量只能相乘，哪些组合在物理上没有意义。 常见的量纲约束分为2种： 以本课题组发展的DHC-GEP、SITE框架为代表的量纲校核约束。这类方法常常先任意进行符号组合，随后将预先给定的符号量纲进行运算，给无法通过校核的表达式赋予大额的损失，强制淘汰。另一种类似的方式是，把量纲的匹配程度量化为一个罚函数，再通过一个可调超参数进行scaling，然后加到主损失函数上，这种做法不会百分百杜绝量纲不齐次的方程，但也因此不至于出现种群难以进化的现象（SITE的seed injection strategy就是用来解决直接赋予大损失带来的进化停滞问题）。 以Fukami的JFM（2024）、Bakarji的NCS（2022）、Xie的NC（2021）以及Xia的EAAI（2026）为代表的无量纲学习（dimensionless learning）方法。这类方法都是先用量纲约束把候选表达限制在“物理上允许”的空间里，再用数据去解决 Buckingham Π 定理“可行但不唯一”的问题，找出最能解释输出、最有泛化能力的低维无量纲表示。 然而，量纲能提供的物理量的物理本质信息是很有限的，它刻画的是物理量可参与何种形式运算的边界，却没有触及这个物理量在理论结构中究竟扮演什么角色。同量纲变量之间的差别，正好暴露了这一层缺失。例如，速度、声速、扩散波速、相速度，量纲完全一致，数值尺度却可能相差多个数量级，更关键的是，它们进入方程的方式并不相同。某些量是系统状态，某些量是传输通量，某些量是材料参数，某些量则体现外部驱动或边界条件。只看量纲，这些差异全部被压缩了；只看数值，这些差异又被具体问题中的尺度、单位和采样方式淹没了。真正缺失的，似乎是量纲之上、数值之下的那一层物理语义。 这层语义首先不是语言学意义上的名字，而是变量在物理结构中的位置。一个物理量是否守恒，是否可积，是否依赖参考系，是否具有方向性，是否描述局域状态还是跨边界交换，是否更接近原因还是结果，这些性质比变量名稳定得多，也比量纲更接近机制。换句话说，速度之所以不是声速，不在于它们叫法不同，也不在于单位不同，而在于它们分别对应不同的生成机制、不同的控制参数、不同的理论角色。前者通常是物体运动状态的一部分，后者更接近介质性质与热力学状态共同决定的传播特征。二者可以在同一组方程中相遇，但很少处于同一语义位置。 因此，更合适的中间表示，未必是再造一个比量纲稍复杂一些的离散标签，而应当是一组描述变量物理角色的语义坐标。这个表示可以包含若干彼此独立的轴：它是状态量还是参数，是广延量还是强度量，是守恒变量还是本构变量，是局域定义还是非局域定义，是标量、矢量还是张量，是坐标变换下不变还是协变，是主要体现时间演化还是空间耦合。它们不像自然语言那样松散，也不像数值那样依赖具体样本分布，而是贴近理论建模时真正关心的结构信息。 这件事还有一层更深的意义。量纲本质上是一种代数约束，它告诉我们表达式能否成立；语义角色则更接近结构约束，它告诉我们表达式为何会出现。代数约束能缩小搜索空间，结构约束则能改变搜索空间的形状。符号回归若只使用量纲，它依然在表达式层面搜索，只是少走一些死路；若进一步掌握变量的语义角色，它就有机会在机制层面组织搜索，把候选表达式限制在某类物理过程允许的范围内。这样一来，模型寻找的就不再只是形式上合法的组合，而是更可能对应真实生成机制的组合。从这个角度看，变量名本身也不应被简单丢弃。多数工作把变量名视为无信息标签，这在机器学习上很自然，因为字符串本身确实不携带稳定的数学结构。但在科学问题里，变量名往往是研究共同体长期压缩后的知识入口。压力、温度、密度、化学势，这些名称背后连着的是实验操作、理论传统、适用范围与典型近似。直接把名字输入模型当然过于粗糙，也容易引入语料偏见；可若把它们完全抹去，同样是在主动舍弃知识。更合理的做法，是不把名称当作最终表示，而把它当作检索语义属性的入口，再把这些较稳定、可形式化的属性编码为中间层。 2. Beyond data-to-equation 我们知道符号回归的目标是给定一组labeled的data（其实很多论文中都不做labeled，例如PSE和phyE2E，举例说就是输入数据的标签是无信息的，他只是$x_1$, $x_2$, … 这样子，不关注这列数据向量背后的名字是啥，因为模型也不知道这个名字有什么意义，很多端到端的模型都是只看数据的语义信息），那么上一点中说的量纲其实很特殊，它仍属于标签信息，却已不再是纯粹的符号，而是物理语义压缩后的最简投影（仅用长度为7的向量，且该向量的值一般为小整数，用INT4即可表示）。问题在于，这种压缩也极其剧烈。量纲保留下来的是代数兼容性，折叠掉的却是变量在物理理论中的角色、生成机制和适用范围。 我的直觉告诉我，真正的差异，可能真是在这部分被折叠的信息里。数值序列携带的信息量最大，却高度依赖尺度、单位、采样区间和具体任务；量纲最容易处理，却只给出最低限度的结构边界。两者之间显然还存在一层更有价值的中间表示。它不必像原始数据那样拥挤，也不能像量纲那样过于稀薄。对速度这一类同量纲变量而言，模型需要辨认的并不是单位是否一致，而是它究竟属于系统状态、传播特征、材料参数，还是某种外部驱动；它是否参与守恒关系，是否受参考系影响，是否主要决定时间演化，是否对应局域传输或全局约束。声速、光速和物体运动速度之所以不能互换，关键不在量纲，也不在数值大小，而在它们处于不同的物理角色。 一旦这层表示能够稳定提取，从数据到方程之间那段过长的推断链条就会明显缩短。模型面对的将不再只是匿名数值列，而是一组带有物理角色和结构关系的变量。它先判断哪些量更像状态变量，哪些量更像本构参数，哪些组合可能形成不变量，哪些相互作用更接近守恒律、响应关系或尺度律；随后再在这些语义边界内搜索表达式。这样得到的方程，并非只是拟合误差更小，而是更接近科学问题本身的生成逻辑。 早期的端到端 Transformer 模型则直接从样本点预测完整公式，试图跳过先定骨架、再拟合常数的两阶段流程；SymFormer 又把符号与常数一并生成，减少了后续优化与前向生成之间的割裂。这些工作证明，数据到公式的直接映射是可能的，也说明预训练模型确实能学到某种分布层面的公式先验；不过输入端依旧大多是匿名表格，变量在物理上的身份并未真正进入模型内部。 PhyE2E 往前多走了一步。它先借助 oracle neural network 的二阶导数把问题拆成若干更易处理的子问题，再用 Transformer 做端到端公式翻译（这里还嵌入了量纲信息），并在末端接上 MCTS 与遗传编程做精修。这里最值得注意的，不是具体用了哪一套搜索器，而是它已经不满足于让模型从原始数值直接猜公式，而是先从数据中抽取局部结构信号，再把这些信号送入符号生成阶段。LLM 路线也呈现出类似趋势。LLM-SR 把方程视为程序，用预训练科学知识提出骨架假设，DrSR 更进一步，先分析数据中的单调性、非线性和相关结构，再让生成与反思形成闭环。到了 2026 年，PiT-PO 框架把物理约束与 token 级正则一并纳入策略优化，使搜索反馈真正进入模型参数更新；符号回归的重心也随之从更快生成公式，转向更早恢复决定公式形态的结构信息。 因此，我认为量纲约束的下一步，并不是再设计一个比量纲稍复杂一些的标签系统，而是学习一种可计算的物理语义表征。它既能比量纲承载更多内容，又不至于像原始数值那样混杂。这样的表征至少应当包含三层信息：变量自身的角色，变量之间的关系，变量进入方程时可能服从的结构规则。前一层区分状态量、控制量、材料参数、响应量、守恒量、本构量；中间一层刻画依赖图、耦合强弱、可分离性、对称性、尺度关系和可能的不变量；最后一层限定候选算子族与组合方式，例如哪些量更可能通过梯度、散度、乘性耦合、指数律或幂律进入表达式。到这一步，模型做的就不再是无差别的式子拼接，而是在一个已经受到语义约束的空间里搜索。 TLDR，符号回归未必要从数据直接走到方程。中间完全可以插入一个物理语义层，把数值、量纲、变量名、实验条件、坐标系信息、边界条件和已有知识库共同压缩成统一表示。端到端并不要求取消这一步；更成熟的端到端系统，很可能要把这一步学进模型内部。它先输出变量的语义角色和关系图，再在此基础上生成表达式。符号回归若要真正进入科学发现的核心地带，恐怕绕不过这一步。]]></summary></entry><entry><title type="html">论文阅读——SNIP (ICLR 2024)</title><link href="https://pistilreaper.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB-SNIP-(ICLR-2024)/" rel="alternate" type="text/html" title="论文阅读——SNIP (ICLR 2024)" /><published>2026-03-11T00:00:00+00:00</published><updated>2026-03-11T00:00:00+00:00</updated><id>https://pistilreaper.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E2%80%94%E2%80%94SNIP%20(ICLR%202024)</id><content type="html" xml:base="https://pistilreaper.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB-SNIP-(ICLR-2024)/"><![CDATA[<p><a href="https://openreview.net/forum?id=KZSEgJGPxu">SNIP: Bridging Mathematical Symbolic and Numeric Realms with Unified Pre-training</a></p>

<h2 id="intro">Intro</h2>

<p>这篇论文中了 ICLR 2024 的 spotlight，4 个审稿人给出了 <strong>8 8 6 8</strong> 的高评价。其实，早在 2023 年 NeurIPS 的 AI4S track上，这篇论文就已经作为 poster 展示。这是一篇典型的 AI 本位论文，将最时下最新的多模态思想和预训练概念完美应用到了符号学习上，本文的思路十分严谨，并非简单的套用AI模型。</p>

<p>值得一提的是，本文一作 Kazem Meidani 老哥来自卡赖基梅隆大学（CMU），他同时也是 <a href="https://openreview.net/forum?id=m2nmp8P5in">LLM-SR</a> 的作者，那篇论文之后我应该也会发布精读笔记。</p>

<p>让我们言归正传，进入这篇论文的内容。</p>

<h2 id="motivation">Motivation</h2>

<p>SNIP 框架可以分为两部分，即数值编码器和符号编码器。</p>

<p>方法名 Symbolic-Numeric Integrated Pre-training (SNIP) 就比较有意思，和多模态领域的 Contrastive Language-Image Pre-training (CLIP [1]) 很相似，CLIP 是将图片与文本做对比学习，帮助模型获得图片和文字互相理解语义的能力，而SNIP把这样的对比学习对象从<strong>图片-文字</strong>换成了<strong>方程（symbolic）-数据（numeric）</strong>，预训练得到的一个能理解从数据到方程的潜空间映射（世界地图）。以后，针对任何其他具体任务，不需要做特定的监督训练，能直接端到端给出一个对映关系。</p>

<p>SNIP 真正想回答的，不是“怎么把一个更强的模型塞进符号回归领域”，而是一个更前置、也更本质的问题：<strong>同一个科学对象，本来就天然同时存在于两个世界里——一个是符号世界里的方程，一个是数值世界里的观测。我们过去的模型，大多只站在其中一边说话。</strong> 现有工作要么从公式出发做数学推理（比如PINN，算子学习之类方法），要么从点集出发做符号回归（笔者老本行，往往就是给一组数据，用GA跑一个方程出来），而且通常都是围绕具体任务做监督训练；这样训练出来的模型，很容易学会某个任务的映射，却未必真的学会“这条曲线和这个公式为什么是一回事”。SNIP 的出发点，恰恰就是把这个缺口当作问题本身：先不急着做下游任务，先学会两种模态之间的对应关系。</p>

<p>所以作者的方法提出得非常自然。既然图像和文本可以通过对比学习形成共同语义空间，那么<strong>符号表达式</strong>和<strong>数值观测序列</strong>也可以。这就是 SNIP 的第一层motivation。但作者没有停在一个漂亮比喻上，而是很认真地问了第二层问题：这两种模态到底该怎么编码，哪些结构该保留，哪些结构该刻意忽略。于是我们看到一个很克制的设计：数值端和符号端都用 Transformer 编码，但两边不是简单镜像，而是各自尊重本模态的结构约束。</p>

<h2 id="method">Method</h2>

<p>具体来说，数值编码器处理的是一组 $((x,y))$ 点。作者沿用了此前 NeSymReS [2] 工作中的数值 tokenization，把浮点数转成 base-10 token；更重要的是，他们明确利用了<strong>点集的置换不变性</strong>，因此在 numeric encoder 中去掉了 positional embedding。</p>

<p>这里我想聊聊什么是<strong>置换不变性</strong>。在 NLP 任务中，一句话被 tokenize 后显然不是置换不变的，比如”你爱我“和”我爱你“具有完全不同的语义，因此语言模型中的 transformer 往往引入位置编码（positional embedding）来考虑 tokens 在输入序列中相对位置的影响。而在符号回归任务中，我们通常是不去考虑数据点的空间（位置）特性的，举例说，对方程
\(y = 4x^2, \tag{1}\)
我们给出的数据对 $(x,y)$ 很可能是局部采样，且不连续的，因此，我们训练一个 end-to-end 的模型时，不希望模型根据先给 $(1,4)$ 还是先给  $(0.5,1)$ 而改变输出的方程。这时候，以随意的顺序放入数据对可能就自然满足了置换不变的 bias。或者简单来想，不管 $x$ 取什么，只要 $y$ 服从方程给出的函数关系就行，方程形式不随输入的取值而产生改变。</p>

<p>符号端则相反，表达式按照前缀树序列化，保留顺序信息，因此 symbolic encoder 继续使用 positional embedding。两个编码器最终都经过 attention pooling （普通 pooling 是“平均一下”或者“取最大值”，而 attention pooling 是“让模型自己决定，哪些 token 更重要，然后做加权平均”）压成固定长度向量，落到同一个 latent space。补充材料里还能看到，两边编码器都配成了 <strong>8 层、16 头、512 维</strong>；这引来了 reviewer 追问，作者也明确回应：它们的设置比 Kamienny（E2E-SR [3]）和 Biggio（NeSymReS [2]）等先前工作更深，是因为这里不只是做任务拟合，而是要学 <em>richer joint representations</em>。</p>

<p><img src="..\images\SNIP\SNIP_overview.png" alt="The SNIP Framework" /></p>

<p>有了双编码器以后，SNIP 的核心就变得非常简单：对每个成对出现的“公式—数据”样本，做一个对称的 CLIP 式对比学习目标，让正确配对靠近、错误配对远离。该过程也是一个典型的无监督/自监督学习过程，此过程的代理任务为在batch内预测正确的 $(s_i,v_i)$ 配对关系，目标函数为一个对称的 InfoNCE 损失：</p>

\[\mathcal L_{\text{SNIP}}=
\frac{1}{2}
\left(
\mathcal L_{S\rightarrow V}
+
\mathcal L_{V\rightarrow S}
\right).
\tag{2}\]

<p>其中 symbolic-to-numeric 的损失为：</p>

\[\mathcal{L}_{S\rightarrow V}=
-\frac{1}{|\mathcal B|}
\sum_{(s,v)\in\mathcal B}
\log
\frac{
\sum_{v^+\in V^+(s)}
\exp\!\left(\frac{z_s^\top z_{v^+}}{\tau}\right)
}{
\sum_{v'\in V(\mathcal B)}
\exp\!\left(\frac{z_s^\top z_{v'}}{\tau}\right)
}.
\tag{3}\]

<p>对应地，$\mathcal{L}_{V\rightarrow S}$ 完全对称，只是把 symbolic 和 numeric 的角色互换。</p>

<p>从机制上看，这个损失一方面是<strong>拉近正配对</strong>：对应同一个函数的符号式和数值点集，它们的 embedding 相似度要变大。另一方面是<strong>推远错配对</strong>：  同一个 batch 里其他不对应的 $v_j$​ 或 $s_j$​ 都被当作负样本，让模型学会区分“这是同一个数学对象的两种表示”与“这不是”。</p>

<p>值得注意的是，作者指出了如何生成用于训练的<strong>合成数据</strong>：样本由随机函数生成，再采样数据点、清理超出定义域或数值爆炸的样本，并在预训练阶段把 $(y)$ 归一化到 $(0,1)$，强调函数行为而非数值尺度。最终，模型在训练中见到了大约 6000 万个合成的 symbolic-numeric pair。</p>

<h2 id="symbolic-regression">Symbolic regression</h2>

<p>接下来是把训练好的潜空间判别器拿来应用到下游的符号回归任务上。</p>

<p><img src="..\images\SNIP\SNIP_for_SR.png" alt="Using SNIP for Symbolic Regression" /></p>

<p>论文把预训练好的潜空间“判别器”真正接到符号回归上时，并不是直接让 SNIP 从数值点集端到端吐出公式，而是把 <strong>预训练的 numeric encoder</strong> 先当成一个更好的表征前端：输入一组数值观测 $v$，先得到其潜表示 $z_v$ 。但下游解码器仍沿用已有的 E2E symbolic regression 框架，因此作者额外训练了一个 <strong>mapping network</strong> （上图a中的红色部分），把 $z_v$ ​ 映射成 decoder 可以接收的 token-like latent sequence，再交给已经预训练好的 expression decoder 生成公式。也就是说，SNIP 在这里不直接取代原有 SR 系统，而是先把“数据长什么样”编码得更好，再把这个表征喂给已有的公式生成器。这一段设计借鉴了 ClipCap [5]：结合预训练好的图片编码器和 GPT-2 的专业编码器，保留强大的生成端，只替换和重塑前端表示。</p>

<p>但作者并没有止步于此。他们更进一步意识到，如果 SNIP 学到的 latent space 真有语义结构，那么它不应该只被拿来喂 decoder 一次，而应该成为搜索空间本身。顺其自然的，作者提出了 <strong>Latent Space Optimization (LSO)</strong>。做法是：先围绕输入样本的潜表示初始化一批 latent population，再在连续潜空间里用梯度自由优化器不断更新这些 latent code；每一步都把候选 latent 解码成表达式，去重 skeleton、再对常数做数值优化，最后按拟合分数筛选最优公式。这样一来，符号回归就不再只是在离散公式树空间里硬搜，而是先在一个已经被 symbolic-numeric 对比学习塑形过的“语义潜空间”里找更有希望的区域，再把它译回显式公式。</p>

<p>很多 AI 研究者做 SR 时的直觉，是直接从 numeric input 到 symbolic output 搞一个 end-to-end seq2seq，SNIP 没有完全否定这条路，而是踩在了前人的肩膀上。这点实在是巧妙，SNIP 擅长的是“把数据编码好”，而不是“一步到位把表达式吐出来”。这种模块化复用，反而让整个方法更可信。<strong>这里也是笔者感悟很深的地方，很多时候做一个新方法并不是每个 component 都应该 design/build from scratch，往往 A+B+X 会比 X1+X2+X3 效果好，踩得坑也会少很多。</strong></p>

<h2 id="experiments-and-results">Experiments and results</h2>

<p>实验上，作者没有只和一个 transformer baseline 比，而是直接放到经典的 <strong>SRBench</strong> [6] 体系里，与 E2E 以及经典 GP 类方法一起看 accuracy-complexity trade-off。他们评估了 119 个 Feynman、14 个 Strogatz、以及 57 个 black-box 数据集，并且由于复用了 E2E decoder，整个设置限制在连续特征、维度 ($D \le 10$) 的范围内。</p>

<p>结果很有说服力：SNIP 在三类数据集上都落在第一 Pareto front；在 Strogatz 上达到 <strong>0.928</strong> 的 top-tier accuracy；在 black-box 上以更低复杂度 <strong>47.52</strong> 超过 Operon 的 <strong>64.95</strong>；在 Feynman 上又同时展示出比 Operon 更低的复杂度、比 AIFeynman 更高的精度。</p>

<p>此外，作者在补充材料里做了严谨的消融实验：没有 LSO 时，($R^2&gt;0.99$) 的平均成功率只有 <strong>0.683</strong>；加上 LSO 后，能稳定提升到 <strong>0.80+</strong>，这与 LSO 过程中使用梯度/无梯度优化器关系不大。可见 LSO 对提升准确率的巨大作用。</p>

<h2 id="my-thinking">My thinking</h2>

<p>这篇论文对符号回归乃至所有 AI4S 领域的研究者都很有启发。</p>

<ol>
  <li><strong>不要把下游任务当作唯一入口</strong>。作者不是盯着 SR 本身开始研究，而是先问：SR 为什么难？难在 numeric realm 和 symbolic realm 之间没有一个共享语义层。这个问题一旦被提对了，后面的架构、预训练和优化几乎都是顺理成章的。很多时候，提升不是来自更大的模型，而是来自把任务往上抽象一层。</li>
  <li><strong>实验设计要能证明你方法的“中间假设”</strong>。论文不止 SNIP 给出了 SRBench 的基准表现，还插入了 cross-modal property prediction 和 latent space visualization，专门验证模型是否真的学到了共同语义。这类实验特别值得学习，因为很多论文的方法故事听起来都很顺，但缺的恰恰是对中间机制的验证。如何向读者证明我们好的根本原因，其中有很深的学问。</li>
  <li><strong>不要迷信纯 end-to-end</strong>。SNIP 把 representation learning、sequence generation、continuous optimization 三者拆开，又通过映射层和 latent search 把它们重新链接。这种“分而治之，再重新耦合”的思想，对科学发现类问题尤其重要，因为这类问题往往既有结构先验、又有搜索难度、还要求可解释。</li>
  <li><strong>AI4S 里，预训练到底应该预训练什么。</strong> SNIP 给出的答案是——不是预训练某个任务，而是预训练不同科学表述之间的对齐关系。可以看到，本文几乎没有做物理语义空间上的对齐，这是否是一个可行的方向？笔者未来应该也会尝试。</li>
</ol>

<p>当然，本文中也讨论了 SNIP 的局限性：SNIP 仍然依赖闭式函数的数据生成协议，输入维度被限制在 ($D \le 10$)，operator vocabulary 也受预定义语法约束；对那些本身就不适合被紧凑公式描述的模式，它并不总会 work。</p>

<h2 id="reference">Reference</h2>

<p>[1] Alec Radford, Jong Wook Kim, Chris Hallacy, Aditya Ramesh, Gabriel Goh, Sandhini Agarwal, Girish Sastry, Amanda Askell, Pamela Mishkin, Jack Clark, Gretchen Krueger, and Ilya Sutskever. Learning transferable visual models from natural language supervision. In Marina Meila and Tong Zhang (eds.), Proceedings of the 38th International Conference on Machine Learning, volume 139 of Proceedings of Machine Learning Research, pp. 8748–8763. PMLR, 18–24 Jul 2021.</p>

<p>[2] Luca Biggio, Tommaso Bendinelli, Alexander Neitz, Aurelien Lucchi, and Giambattista Parascandolo. Neural symbolic regression that scales. In Marina Meila and Tong Zhang (eds.), Proceedings of the 38th International Conference on Machine Learning, volume 139 of Proceedings of Machine Learning Research, pp. 936–945. PMLR, 18–24 Jul 2021.</p>

<p>[3] Pierre-Alexandre Kamienny, Stephane d’Ascoli, Guillaume Lample, and Francois Charton. End-to-end symbolic regression with transformers. In Advances in Neural Information Processing Systems, 2022.</p>

<p>[4] <a href="https://mp.weixin.qq.com/s/sUAoNXGvwWa6lecq73pyAg">对比学习（Contrastive Learning），必知必会</a></p>

<p>[5] Ron Mokady, Amir Hertz, and Amit H Bermano. Clipcap: Clip prefix for image captioning. arXiv preprint arXiv:2111.09734, 2021.</p>

<p>[6] William La Cava, Patryk Orzechowski, Bogdan Burlacu, Fabricio de Franca, Marco Virgolin, Ying Jin, Michael Kommenda, and Jason Moore. Contemporary symbolic regression methods and their relative performance. In J. Vanschoren and S. Yeung (eds.), Proceedings of the Neural Information Processing Systems Track on Datasets and Benchmarks, volume 1, 2021.</p>]]></content><author><name>cty</name></author><category term="科研" /><category term="论文阅读" /><category term="符号回归" /><summary type="html"><![CDATA[SNIP: Bridging Mathematical Symbolic and Numeric Realms with Unified Pre-training Intro 这篇论文中了 ICLR 2024 的 spotlight，4 个审稿人给出了 8 8 6 8 的高评价。其实，早在 2023 年 NeurIPS 的 AI4S track上，这篇论文就已经作为 poster 展示。这是一篇典型的 AI 本位论文，将最时下最新的多模态思想和预训练概念完美应用到了符号学习上，本文的思路十分严谨，并非简单的套用AI模型。 值得一提的是，本文一作 Kazem Meidani 老哥来自卡赖基梅隆大学（CMU），他同时也是 LLM-SR 的作者，那篇论文之后我应该也会发布精读笔记。 让我们言归正传，进入这篇论文的内容。 Motivation SNIP 框架可以分为两部分，即数值编码器和符号编码器。 方法名 Symbolic-Numeric Integrated Pre-training (SNIP) 就比较有意思，和多模态领域的 Contrastive Language-Image Pre-training (CLIP [1]) 很相似，CLIP 是将图片与文本做对比学习，帮助模型获得图片和文字互相理解语义的能力，而SNIP把这样的对比学习对象从图片-文字换成了方程（symbolic）-数据（numeric），预训练得到的一个能理解从数据到方程的潜空间映射（世界地图）。以后，针对任何其他具体任务，不需要做特定的监督训练，能直接端到端给出一个对映关系。 SNIP 真正想回答的，不是“怎么把一个更强的模型塞进符号回归领域”，而是一个更前置、也更本质的问题：同一个科学对象，本来就天然同时存在于两个世界里——一个是符号世界里的方程，一个是数值世界里的观测。我们过去的模型，大多只站在其中一边说话。 现有工作要么从公式出发做数学推理（比如PINN，算子学习之类方法），要么从点集出发做符号回归（笔者老本行，往往就是给一组数据，用GA跑一个方程出来），而且通常都是围绕具体任务做监督训练；这样训练出来的模型，很容易学会某个任务的映射，却未必真的学会“这条曲线和这个公式为什么是一回事”。SNIP 的出发点，恰恰就是把这个缺口当作问题本身：先不急着做下游任务，先学会两种模态之间的对应关系。 所以作者的方法提出得非常自然。既然图像和文本可以通过对比学习形成共同语义空间，那么符号表达式和数值观测序列也可以。这就是 SNIP 的第一层motivation。但作者没有停在一个漂亮比喻上，而是很认真地问了第二层问题：这两种模态到底该怎么编码，哪些结构该保留，哪些结构该刻意忽略。于是我们看到一个很克制的设计：数值端和符号端都用 Transformer 编码，但两边不是简单镜像，而是各自尊重本模态的结构约束。 Method 具体来说，数值编码器处理的是一组 $((x,y))$ 点。作者沿用了此前 NeSymReS [2] 工作中的数值 tokenization，把浮点数转成 base-10 token；更重要的是，他们明确利用了点集的置换不变性，因此在 numeric encoder 中去掉了 positional embedding。 这里我想聊聊什么是置换不变性。在 NLP 任务中，一句话被 tokenize 后显然不是置换不变的，比如”你爱我“和”我爱你“具有完全不同的语义，因此语言模型中的 transformer 往往引入位置编码（positional embedding）来考虑 tokens 在输入序列中相对位置的影响。而在符号回归任务中，我们通常是不去考虑数据点的空间（位置）特性的，举例说，对方程 \(y = 4x^2, \tag{1}\) 我们给出的数据对 $(x,y)$ 很可能是局部采样，且不连续的，因此，我们训练一个 end-to-end 的模型时，不希望模型根据先给 $(1,4)$ 还是先给 $(0.5,1)$ 而改变输出的方程。这时候，以随意的顺序放入数据对可能就自然满足了置换不变的 bias。或者简单来想，不管 $x$ 取什么，只要 $y$ 服从方程给出的函数关系就行，方程形式不随输入的取值而产生改变。 符号端则相反，表达式按照前缀树序列化，保留顺序信息，因此 symbolic encoder 继续使用 positional embedding。两个编码器最终都经过 attention pooling （普通 pooling 是“平均一下”或者“取最大值”，而 attention pooling 是“让模型自己决定，哪些 token 更重要，然后做加权平均”）压成固定长度向量，落到同一个 latent space。补充材料里还能看到，两边编码器都配成了 8 层、16 头、512 维；这引来了 reviewer 追问，作者也明确回应：它们的设置比 Kamienny（E2E-SR [3]）和 Biggio（NeSymReS [2]）等先前工作更深，是因为这里不只是做任务拟合，而是要学 richer joint representations。 有了双编码器以后，SNIP 的核心就变得非常简单：对每个成对出现的“公式—数据”样本，做一个对称的 CLIP 式对比学习目标，让正确配对靠近、错误配对远离。该过程也是一个典型的无监督/自监督学习过程，此过程的代理任务为在batch内预测正确的 $(s_i,v_i)$ 配对关系，目标函数为一个对称的 InfoNCE 损失： \[\mathcal L_{\text{SNIP}}= \frac{1}{2} \left( \mathcal L_{S\rightarrow V} + \mathcal L_{V\rightarrow S} \right). \tag{2}\] 其中 symbolic-to-numeric 的损失为： \[\mathcal{L}_{S\rightarrow V}= -\frac{1}{|\mathcal B|} \sum_{(s,v)\in\mathcal B} \log \frac{ \sum_{v^+\in V^+(s)} \exp\!\left(\frac{z_s^\top z_{v^+}}{\tau}\right) }{ \sum_{v'\in V(\mathcal B)} \exp\!\left(\frac{z_s^\top z_{v'}}{\tau}\right) }. \tag{3}\] 对应地，$\mathcal{L}_{V\rightarrow S}$ 完全对称，只是把 symbolic 和 numeric 的角色互换。 从机制上看，这个损失一方面是拉近正配对：对应同一个函数的符号式和数值点集，它们的 embedding 相似度要变大。另一方面是推远错配对： 同一个 batch 里其他不对应的 $v_j$​ 或 $s_j$​ 都被当作负样本，让模型学会区分“这是同一个数学对象的两种表示”与“这不是”。 值得注意的是，作者指出了如何生成用于训练的合成数据：样本由随机函数生成，再采样数据点、清理超出定义域或数值爆炸的样本，并在预训练阶段把 $(y)$ 归一化到 $(0,1)$，强调函数行为而非数值尺度。最终，模型在训练中见到了大约 6000 万个合成的 symbolic-numeric pair。 Symbolic regression 接下来是把训练好的潜空间判别器拿来应用到下游的符号回归任务上。 论文把预训练好的潜空间“判别器”真正接到符号回归上时，并不是直接让 SNIP 从数值点集端到端吐出公式，而是把 预训练的 numeric encoder 先当成一个更好的表征前端：输入一组数值观测 $v$，先得到其潜表示 $z_v$ 。但下游解码器仍沿用已有的 E2E symbolic regression 框架，因此作者额外训练了一个 mapping network （上图a中的红色部分），把 $z_v$ ​ 映射成 decoder 可以接收的 token-like latent sequence，再交给已经预训练好的 expression decoder 生成公式。也就是说，SNIP 在这里不直接取代原有 SR 系统，而是先把“数据长什么样”编码得更好，再把这个表征喂给已有的公式生成器。这一段设计借鉴了 ClipCap [5]：结合预训练好的图片编码器和 GPT-2 的专业编码器，保留强大的生成端，只替换和重塑前端表示。 但作者并没有止步于此。他们更进一步意识到，如果 SNIP 学到的 latent space 真有语义结构，那么它不应该只被拿来喂 decoder 一次，而应该成为搜索空间本身。顺其自然的，作者提出了 Latent Space Optimization (LSO)。做法是：先围绕输入样本的潜表示初始化一批 latent population，再在连续潜空间里用梯度自由优化器不断更新这些 latent code；每一步都把候选 latent 解码成表达式，去重 skeleton、再对常数做数值优化，最后按拟合分数筛选最优公式。这样一来，符号回归就不再只是在离散公式树空间里硬搜，而是先在一个已经被 symbolic-numeric 对比学习塑形过的“语义潜空间”里找更有希望的区域，再把它译回显式公式。 很多 AI 研究者做 SR 时的直觉，是直接从 numeric input 到 symbolic output 搞一个 end-to-end seq2seq，SNIP 没有完全否定这条路，而是踩在了前人的肩膀上。这点实在是巧妙，SNIP 擅长的是“把数据编码好”，而不是“一步到位把表达式吐出来”。这种模块化复用，反而让整个方法更可信。这里也是笔者感悟很深的地方，很多时候做一个新方法并不是每个 component 都应该 design/build from scratch，往往 A+B+X 会比 X1+X2+X3 效果好，踩得坑也会少很多。 Experiments and results 实验上，作者没有只和一个 transformer baseline 比，而是直接放到经典的 SRBench [6] 体系里，与 E2E 以及经典 GP 类方法一起看 accuracy-complexity trade-off。他们评估了 119 个 Feynman、14 个 Strogatz、以及 57 个 black-box 数据集，并且由于复用了 E2E decoder，整个设置限制在连续特征、维度 ($D \le 10$) 的范围内。 结果很有说服力：SNIP 在三类数据集上都落在第一 Pareto front；在 Strogatz 上达到 0.928 的 top-tier accuracy；在 black-box 上以更低复杂度 47.52 超过 Operon 的 64.95；在 Feynman 上又同时展示出比 Operon 更低的复杂度、比 AIFeynman 更高的精度。 此外，作者在补充材料里做了严谨的消融实验：没有 LSO 时，($R^2&gt;0.99$) 的平均成功率只有 0.683；加上 LSO 后，能稳定提升到 0.80+，这与 LSO 过程中使用梯度/无梯度优化器关系不大。可见 LSO 对提升准确率的巨大作用。 My thinking 这篇论文对符号回归乃至所有 AI4S 领域的研究者都很有启发。 不要把下游任务当作唯一入口。作者不是盯着 SR 本身开始研究，而是先问：SR 为什么难？难在 numeric realm 和 symbolic realm 之间没有一个共享语义层。这个问题一旦被提对了，后面的架构、预训练和优化几乎都是顺理成章的。很多时候，提升不是来自更大的模型，而是来自把任务往上抽象一层。 实验设计要能证明你方法的“中间假设”。论文不止 SNIP 给出了 SRBench 的基准表现，还插入了 cross-modal property prediction 和 latent space visualization，专门验证模型是否真的学到了共同语义。这类实验特别值得学习，因为很多论文的方法故事听起来都很顺，但缺的恰恰是对中间机制的验证。如何向读者证明我们好的根本原因，其中有很深的学问。 不要迷信纯 end-to-end。SNIP 把 representation learning、sequence generation、continuous optimization 三者拆开，又通过映射层和 latent search 把它们重新链接。这种“分而治之，再重新耦合”的思想，对科学发现类问题尤其重要，因为这类问题往往既有结构先验、又有搜索难度、还要求可解释。 AI4S 里，预训练到底应该预训练什么。 SNIP 给出的答案是——不是预训练某个任务，而是预训练不同科学表述之间的对齐关系。可以看到，本文几乎没有做物理语义空间上的对齐，这是否是一个可行的方向？笔者未来应该也会尝试。 当然，本文中也讨论了 SNIP 的局限性：SNIP 仍然依赖闭式函数的数据生成协议，输入维度被限制在 ($D \le 10$)，operator vocabulary 也受预定义语法约束；对那些本身就不适合被紧凑公式描述的模式，它并不总会 work。 Reference [1] Alec Radford, Jong Wook Kim, Chris Hallacy, Aditya Ramesh, Gabriel Goh, Sandhini Agarwal, Girish Sastry, Amanda Askell, Pamela Mishkin, Jack Clark, Gretchen Krueger, and Ilya Sutskever. Learning transferable visual models from natural language supervision. In Marina Meila and Tong Zhang (eds.), Proceedings of the 38th International Conference on Machine Learning, volume 139 of Proceedings of Machine Learning Research, pp. 8748–8763. PMLR, 18–24 Jul 2021. [2] Luca Biggio, Tommaso Bendinelli, Alexander Neitz, Aurelien Lucchi, and Giambattista Parascandolo. Neural symbolic regression that scales. In Marina Meila and Tong Zhang (eds.), Proceedings of the 38th International Conference on Machine Learning, volume 139 of Proceedings of Machine Learning Research, pp. 936–945. PMLR, 18–24 Jul 2021. [3] Pierre-Alexandre Kamienny, Stephane d’Ascoli, Guillaume Lample, and Francois Charton. End-to-end symbolic regression with transformers. In Advances in Neural Information Processing Systems, 2022. [4] 对比学习（Contrastive Learning），必知必会 [5] Ron Mokady, Amir Hertz, and Amit H Bermano. Clipcap: Clip prefix for image captioning. arXiv preprint arXiv:2111.09734, 2021. [6] William La Cava, Patryk Orzechowski, Bogdan Burlacu, Fabricio de Franca, Marco Virgolin, Ying Jin, Michael Kommenda, and Jason Moore. Contemporary symbolic regression methods and their relative performance. In J. Vanschoren and S. Yeung (eds.), Proceedings of the Neural Information Processing Systems Track on Datasets and Benchmarks, volume 1, 2021.]]></summary></entry><entry><title type="html">第一篇文章：新起点</title><link href="https://pistilreaper.github.io/letter_to_you/" rel="alternate" type="text/html" title="第一篇文章：新起点" /><published>2026-03-10T00:00:00+00:00</published><updated>2026-03-10T00:00:00+00:00</updated><id>https://pistilreaper.github.io/letter_to_you</id><content type="html" xml:base="https://pistilreaper.github.io/letter_to_you/"><![CDATA[]]></content><author><name>cty</name></author><category term="生活" /><summary type="html"><![CDATA[]]></summary></entry></feed>