<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:ap="https://www.grepcode.cn/ns/ai-papers">
  <channel>
    <title>TreeHeap / SPR：递归树堆 AI 架构研究档案 on GrepCode</title>
    <link>https://www.grepcode.cn/spr.html</link>
    <description>Recent content in TreeHeap / SPR：递归树堆 AI 架构研究档案 on GrepCode</description>
    <image>
      <title>GrepCode</title>
      <url>https://www.grepcode.cn/img/treeheap-research-series.png</url>
      <link>https://www.grepcode.cn/img/treeheap-research-series.png</link>
    </image>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Thu, 08 Oct 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.grepcode.cn/spr/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>[SPR-001] 问题定义：为什么要研究路径路由</title>
      <link>https://www.grepcode.cn/spr/001-problem.html</link>
      <pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/001-problem.html</guid>
      <description>SPR 的问题定义：路径路由要解决什么问题，以及它不应该被误解成什么。</description>
      <content:encoded><![CDATA[<h1 id="问题定义为什么要研究路径路由">问题定义：为什么要研究路径路由</h1>
<p>SPR 的原始动机不是“再造一个 Transformer”。它更像是在问一个底层问题：</p>
<blockquote>
<p>语言模型里的某些搜索和输出，是否必须通过稠密矩阵完成？</p></blockquote>
<p>Transformer 的强项是通用、并行、可训练。但它也有代价：大量关系被压在矩阵乘法和 softmax 里。我们能看到结果，却不容易看到结构。</p>
<p>SPR 试图换一个表示方式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>vector score -&gt; path decision
</span></span><span style="display:flex;"><span>dense matrix -&gt; recursive route
</span></span><span style="display:flex;"><span>token id -&gt; route state
</span></span></code></pre></div><h2 id="spr-想替代什么">SPR 想替代什么</h2>
<p>最初的目标是输出层或结构搜索的一部分。</p>
<p>传统输出层可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>hidden -&gt; Linear(d, V) -&gt; softmax -&gt; token
</span></span></code></pre></div><p>这是一种“所有 token 一起打分”的方式。SPR 想试试另一种：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>hidden -&gt; recursive decisions -&gt; path -&gt; candidate token/state
</span></span></code></pre></div><p>如果路径结构有效，它可能带来三个好处：</p>
<ol>
<li><strong>参数结构更清楚</strong>：路径上的每个节点对应一次判断。</li>
<li><strong>搜索空间可压缩</strong>：不用每次都扫完整词表或完整图。</li>
<li><strong>结构可解释</strong>：错误可以定位到路径分叉，而不只是一个 logits 排名。</li>
</ol>
<h2 id="spr-不应该被误解成什么">SPR 不应该被误解成什么</h2>
<p>SPR 不是简单的 hash trick。</p>
<p>如果它只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token -&gt; fixed bucket
</span></span></code></pre></div><p>那它最多是高容量 token hash。</p>
<p>真正的 SPR 应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token + context + structure -&gt; conditional path
</span></span></code></pre></div><p>也就是说，同一个词在不同上下文里可以走向不同状态。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>bank approved the loan -&gt; finance state
</span></span><span style="display:flex;"><span>river bank             -&gt; river-side state
</span></span></code></pre></div><p>如果做不到这一点，就不能说“路径即语义”。</p>
<h2 id="ara-方式怎么约束-spr">ARA 方式怎么约束 SPR</h2>
<p>这次重写采用 ARA 风格。每个 claim 都要回答三件事：</p>
<table>
  <thead>
      <tr>
          <th>问题</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Claim 是什么？</td>
          <td>不写模糊胜利，只写可检验句子</td>
      </tr>
      <tr>
          <td>Evidence 是什么？</td>
          <td>脚本、命令、指标、数据切片</td>
      </tr>
      <tr>
          <td>Falsification 是什么？</td>
          <td>什么结果会推翻这个 claim</td>
      </tr>
  </tbody>
</table>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Claim: S1 token path hash has enough capacity for WMT14 word echo.
</span></span><span style="display:flex;"><span>Evidence: solo=41311/41429, BLEU-4=99.99.
</span></span><span style="display:flex;"><span>Falsification: same seed/slice 下 solo rate &lt; 95%.
</span></span></code></pre></div><p>再例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Claim: token-only path encodes contextual semantics.
</span></span><span style="display:flex;"><span>Evidence: currently failed.
</span></span><span style="display:flex;"><span>Falsification: same-token polysemy real labels do not beat shuffled labels.
</span></span></code></pre></div><h2 id="本专题的核心问题">本专题的核心问题</h2>
<p>SPR 现在被拆成三个问题：</p>
<ol>
<li>路径作为 hash 是否可靠？</li>
<li>路径能否被上下文条件化？</li>
<li>路径能否服务结构生成？</li>
</ol>
<p>第一问已经有较强证据。第二问当前失败。第三问属于 S2，需要单独看 Fold Stack 证据链。</p>
<p>这就是本专题后续文章的主线。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-002] S1 实验：Echo、顺序哈希与容量证据</title>
      <link>https://www.grepcode.cn/spr/002-s1-evidence.html</link>
      <pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/002-s1-evidence.html</guid>
      <description>SPR S1 中已经成立的部分：顺序哈希修复、分解路由容量、Echo 复现。</description>
      <content:encoded><![CDATA[<h1 id="s1-实验echo顺序哈希与容量证据">S1 实验：Echo、顺序哈希与容量证据</h1>
<p>S1 的任务是先证明路径结构能稳定工作。</p>
<p>它不处理完整语义，也不处理翻译。它只问：</p>
<blockquote>
<p>路径机制能不能可靠地区分 token，并保留顺序信息？</p></blockquote>
<h2 id="实验脚本">实验脚本</h2>
<p>复现脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>holds/SameTime/experiments/spr_s1_reproduce.py
</span></span><span style="display:flex;"><span>holds/SameTime/experiments/spr_s1_falsification.py
</span></span></code></pre></div><p>io 上运行：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd /data/homecicd/sametime/code/wmt
</span></span><span style="display:flex;"><span>sudo -n python3 spr_s1_falsification.py
</span></span></code></pre></div><h2 id="1-pure-roll-的顺序碰撞">1. pure roll 的顺序碰撞</h2>
<p>设：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我 = [1, 2, 3, 4]
</span></span><span style="display:flex;"><span>你 = [5, 6, 7, 8]
</span></span></code></pre></div><p>如果父节点合并为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>H <span style="color:#f92672">=</span> left <span style="color:#f92672">+</span> torch<span style="color:#f92672">.</span>roll(right, shifts<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>)
</span></span></code></pre></div><p>会得到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我打你 -&gt; [9, 7, 9, 11]
</span></span><span style="display:flex;"><span>你打我 -&gt; [9, 7, 9, 11]
</span></span></code></pre></div><p>两个方向完全相同。这说明 pure roll 不能独立承担顺序编码。</p>
<h2 id="2-roll--sign_alt">2. roll + sign_alt</h2>
<p>修复方式是在右子树 roll 后加一个交替符号：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">sign_alt</span>(x):
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> x <span style="color:#f92672">*</span> [<span style="color:#ae81ff">1</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">1</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>, <span style="color:#f92672">...</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>H <span style="color:#f92672">=</span> left <span style="color:#f92672">+</span> sign_alt(torch<span style="color:#f92672">.</span>roll(right, shifts<span style="color:#f92672">=</span>depth<span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>))
</span></span></code></pre></div><p>同样的例子变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我打你 -&gt; [9, -3, 9, -3]
</span></span><span style="display:flex;"><span>你打我 -&gt; [9,  5, 9,  5]
</span></span></code></pre></div><p>实验输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pure_roll_collision=True
</span></span><span style="display:flex;"><span>sign_alt_separated=True
</span></span></code></pre></div><p>结论：</p>
<blockquote>
<p>S1 的顺序哈希需要非交换破缺。<code>roll + sign_alt</code> 是当前最小可用方案。</p></blockquote>
<h2 id="3-分解路由容量">3. 分解路由容量</h2>
<p>S1 把一个 64 维词向量切成 4 个 chunk：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>chunk0: dim 0..15
</span></span><span style="display:flex;"><span>chunk1: dim 16..31
</span></span><span style="display:flex;"><span>chunk2: dim 32..47
</span></span><span style="display:flex;"><span>chunk3: dim 48..63
</span></span></code></pre></div><p>每个 chunk 走一棵深度 7 的树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>2^7 = 128 leaves
</span></span></code></pre></div><p>四个 chunk 的叶子号组合：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>128^4 = 268,435,456 effective leaves
</span></span></code></pre></div><p>WMT14 英文词表规模：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>vocab=41429
</span></span></code></pre></div><p>结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>solo=41311/41429
</span></span><span style="display:flex;"><span>solo_percent=99.72
</span></span><span style="display:flex;"><span>bleu4=99.99
</span></span></code></pre></div><p>这说明几乎每个 token 都能独占组合叶子。</p>
<h2 id="4-这个结果证明了什么">4. 这个结果证明了什么</h2>
<p>它证明：</p>
<ul>
<li>路径空间容量足够。</li>
<li>路径分配稳定。</li>
<li>Echo 任务可以近乎无损。</li>
<li>顺序哈希可以避免最简单的反向碰撞。</li>
</ul>
<p>它没有证明：</p>
<ul>
<li>token 理解上下文。</li>
<li>path state 等于 semantic state。</li>
<li>同词多义会自动分流。</li>
</ul>
<p>因此，S1 的正确定位是：</p>
<blockquote>
<p>Token Path Hash。</p></blockquote>
<p>它是 SPR 的基础设施，不是完整语义路由。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-003] S1 反证：token-only 路由不是语义路由</title>
      <link>https://www.grepcode.cn/spr/003-s1-falsification.html</link>
      <pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/003-s1-falsification.html</guid>
      <description>用多义词实验反证当前 S1 token-only 路由的语义 claim。</description>
      <content:encoded><![CDATA[<h1 id="s1-反证token-only-路由不是语义路由">S1 反证：token-only 路由不是语义路由</h1>
<p>S1 的 Echo 结果很好，但 ARA 要求我们继续问：</p>
<blockquote>
<p>什么实验会推翻“路径即语义”？</p></blockquote>
<p>最直接的反证是同词多义。</p>
<p>如果一个路径系统真的编码语义，那么同一个词在不同上下文里应该能进入不同状态。</p>
<h2 id="实验设计">实验设计</h2>
<p>选择三个多义词：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>light
</span></span><span style="display:flex;"><span>bank
</span></span><span style="display:flex;"><span>charge
</span></span></code></pre></div><p>构造 42 条受控句子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>light: 光 / 轻
</span></span><span style="display:flex;"><span>bank: 银行 / 河岸
</span></span><span style="display:flex;"><span>charge: 费用 / 充电 / 指控
</span></span></code></pre></div><p>比较两类方法：</p>
<ol>
<li>S1 token-only route。</li>
<li>keyword baseline。</li>
</ol>
<p>然后打乱标签，检查模型是否真的依赖语义。</p>
<h2 id="结果">结果</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token_only_real_acc = 0.4286
</span></span><span style="display:flex;"><span>token_only_shuffled_acc = 0.4286
</span></span><span style="display:flex;"><span>keyword_real_acc = 1.0000
</span></span><span style="display:flex;"><span>keyword_shuffled_acc = 0.4524
</span></span></code></pre></div><p>表格：</p>
<table>
  <thead>
      <tr>
          <th>方法</th>
          <th>真实标签</th>
          <th>打乱标签</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>S1 token-only route</td>
          <td>0.43</td>
          <td>0.43</td>
      </tr>
      <tr>
          <td>keyword baseline</td>
          <td>1.00</td>
          <td>0.45</td>
      </tr>
  </tbody>
</table>
<h2 id="解释">解释</h2>
<p>S1 token-only route 的输入是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route(token)
</span></span></code></pre></div><p>所以 <code>bank</code> 永远是同一个 token。它不看旁边是 <code>loan</code> 还是 <code>river</code>。</p>
<p>这意味着：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>bank approved the loan
</span></span><span style="display:flex;"><span>river bank
</span></span></code></pre></div><p>在当前 S1 里没有上下文分流。</p>
<p>打乱标签后准确率不变，说明 S1 token-only route 没有吃到语义信号。</p>
<h2 id="这个失败说明什么">这个失败说明什么</h2>
<p>它不推翻 S1a。</p>
<p>S1a 的 claim 是：</p>
<blockquote>
<p>token 可以被稳定映射到低碰撞路径。</p></blockquote>
<p>这个 claim 仍然成立。</p>
<p>它推翻的是更强的说法：</p>
<blockquote>
<p>token-only path 天然就是语义。</p></blockquote>
<p>这个说法不成立。</p>
<h2 id="ara-状态">ARA 状态</h2>
<table>
  <thead>
      <tr>
          <th>Claim</th>
          <th>状态</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>路径容量足够</td>
          <td>confirmed</td>
      </tr>
      <tr>
          <td>顺序碰撞可修复</td>
          <td>confirmed</td>
      </tr>
      <tr>
          <td>Echo 可近乎满分</td>
          <td>supported</td>
      </tr>
      <tr>
          <td>token-only path 能做上下文语义消歧</td>
          <td>rejected</td>
      </tr>
      <tr>
          <td>context-conditioned path 能否做语义消歧</td>
          <td>open</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步">下一步</h2>
<p>要恢复“语义路由”这个名字，路径函数必须升级：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route(token)
</span></span></code></pre></div><p>变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route(token, context)
</span></span></code></pre></div><p>否则 SPR 只是一个漂亮的路径哈希。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-004] 架构决策：把 SPR 拆成三层</title>
      <link>https://www.grepcode.cn/spr/004-architecture-decision.html</link>
      <pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/004-architecture-decision.html</guid>
      <description>SPR 的新架构划分：S1a Token Path Hash、S1b Context Routing、S2 Fold Stack。</description>
      <content:encoded><![CDATA[<h1 id="架构决策把-spr-拆成三层">架构决策：把 SPR 拆成三层</h1>
<p>旧叙事把 SPR 写成一条直线：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径 -&gt; 语义 -&gt; 翻译
</span></span></code></pre></div><p>重做实验后，这条线太粗了。它应该拆成三层。</p>
<h2 id="s1atoken-path-hash">S1a：Token Path Hash</h2>
<p>输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token embedding
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stable path / combined leaf
</span></span></code></pre></div><p>能力：</p>
<ul>
<li>高容量。</li>
<li>低碰撞。</li>
<li>顺序哈希可修复。</li>
<li>可复现。</li>
</ul>
<p>限制：</p>
<ul>
<li>不看上下文。</li>
<li>不区分多义。</li>
<li>不应该被叫作语义路由。</li>
</ul>
<p>S1a 是地基。</p>
<h2 id="s1bcontext-conditioned-routing">S1b：Context-conditioned Routing</h2>
<p>输入应该升级为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token + context
</span></span></code></pre></div><p>可能的最小形式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>H_token <span style="color:#f92672">=</span> E[token]
</span></span><span style="display:flex;"><span>H_ctx <span style="color:#f92672">=</span> mean(E[context_window])
</span></span><span style="display:flex;"><span>H <span style="color:#f92672">=</span> normalize(H_token <span style="color:#f92672">+</span> A <span style="color:#f92672">@</span> H_ctx)
</span></span><span style="display:flex;"><span>path <span style="color:#f92672">=</span> route(H)
</span></span></code></pre></div><p>这时同一个 token 才可能在不同上下文里走不同路径。</p>
<p>受控 proof 已经验证了这个最小接口的方向：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token-only acc = 0.429
</span></span><span style="display:flex;"><span>context-route acc = 1.000
</span></span><span style="display:flex;"><span>shuffled-label acc = 0.482
</span></span></code></pre></div><p>这说明路径算子能承载上下文消歧，但前提是 context vector 真的带有 sense signal。它还不是完整语料结论。</p>
<p>S1b 的验收标准不是 BLEU，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>real labels &gt; shuffled labels
</span></span><span style="display:flex;"><span>context route &gt; token-only route
</span></span><span style="display:flex;"><span>context route &gt; random hash
</span></span></code></pre></div><h2 id="s2fold-stack--structure-routing">S2：Fold Stack / Structure Routing</h2>
<p>S2 不是 Echo 的延长线，而是结构路线。</p>
<p>它的问题是：</p>
<blockquote>
<p>语义向量能否预测结构动作？</p></blockquote>
<p>S2 关心：</p>
<ul>
<li>head detection</li>
<li>span detection</li>
<li>fold action classification</li>
<li>child assignment</li>
<li>graph assembly</li>
</ul>
<p>这里的关键指标不是单纯 BLEU，而是结构质量，例如 UAS。</p>
<h2 id="新接口">新接口</h2>
<p>更合理的 SPR 管线是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0 token identity
</span></span><span style="display:flex;"><span>  -&gt; S1a token path hash
</span></span><span style="display:flex;"><span>  -&gt; S1b context-conditioned path
</span></span><span style="display:flex;"><span>  -&gt; S2 fold action / structure state
</span></span></code></pre></div><p>或者反过来让 S2 给 S1b 提供结构条件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token + local context + fold state -&gt; conditional path
</span></span></code></pre></div><p>这样路径才有机会成为“语义前缀”。</p>
<h2 id="决策">决策</h2>
<p>从现在开始：</p>
<ol>
<li>S1a 只称为 Token Path Hash。</li>
<li>不再把 Echo 结果写成语义证明。</li>
<li>S1b 必须通过多义词和 shuffle 反证。</li>
<li>S2 单独维护结构证据链。</li>
</ol>
<p>这让 SPR 更保守，也更专业：S1b 现在可以被称为受控支持，不能被称为真实语料已验证。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-005] S2 结构路线：Fold Stack 的位置</title>
      <link>https://www.grepcode.cn/spr/005-s2-fold-stack.html</link>
      <pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/005-s2-fold-stack.html</guid>
      <description>S2 Fold Stack 在 SPR 中的位置：从语义向量到结构动作，而不是 Echo 的重复。</description>
      <content:encoded><![CDATA[<h1 id="s2-结构路线fold-stack-的位置">S2 结构路线：Fold Stack 的位置</h1>
<p>S2 不应该被塞进 S1 Echo 的叙事里。</p>
<p>S1 证明的是 token path hash。S2 关心的是结构生成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>semantic vector -&gt; structural action
</span></span></code></pre></div><p>它们是相关的，但不是同一个实验。</p>
<h2 id="s2-的问题">S2 的问题</h2>
<p>S2 要回答：</p>
<blockquote>
<p>给定一个语义表示，能否预测句子的结构折叠过程？</p></blockquote>
<p>结构折叠包括：</p>
<ul>
<li>哪个 token 是 head？</li>
<li>span 边界在哪里？</li>
<li>当前短语是什么类型？</li>
<li>子节点应该挂到哪里？</li>
<li>图如何组装？</li>
</ul>
<p>这些问题都比 Echo 更接近翻译和生成。</p>
<h2 id="已有证据的含义">已有证据的含义</h2>
<p>历史实验里有一些重要信号：</p>
<table>
  <thead>
      <tr>
          <th>模块</th>
          <th>观察</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>action classification</td>
          <td>语义向量能预测部分折叠动作</td>
      </tr>
      <tr>
          <td>head detection</td>
          <td>头节点有可学信号</td>
      </tr>
      <tr>
          <td>span detection</td>
          <td>短语范围有可学信号</td>
      </tr>
      <tr>
          <td>child assignment</td>
          <td>仍是瓶颈</td>
      </tr>
      <tr>
          <td>graph assembly</td>
          <td>简单最近节点规则有上限</td>
      </tr>
  </tbody>
</table>
<p>这说明 S2 路线不是空想。</p>
<p>但它也说明：</p>
<blockquote>
<p>结构路线不能靠 Echo 指标证明。</p></blockquote>
<p>BLEU 对结构错误不够敏感。有些结构错了，表面词序仍然可能看起来不错。</p>
<h2 id="s2-的关键指标">S2 的关键指标</h2>
<p>S2 应该主要看：</p>
<ul>
<li>UAS</li>
<li>edge accuracy</li>
<li>action top-k</li>
<li>head F1</li>
<li>span F1</li>
<li>oracle gap</li>
</ul>
<p>而不是只看 BLEU。</p>
<h2 id="s1-与-s2-怎么连接">S1 与 S2 怎么连接</h2>
<p>S1a 给 token 一个稳定路径身份。</p>
<p>S1b 应该让这个路径吃上下文。</p>
<p>S2 可以提供结构上下文：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>fold action
</span></span><span style="display:flex;"><span>head/span state
</span></span><span style="display:flex;"><span>child candidate distribution
</span></span></code></pre></div><p>这些状态反过来可以影响 S1b 路由：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route(token, local_context, fold_state)
</span></span></code></pre></div><p>这才是 SPR 更完整的样子。</p>
<h2 id="s2-的下一步">S2 的下一步</h2>
<p>S2 后续需要做三件事：</p>
<ol>
<li>保留已有 fold-stack 证据，但重新绑定到 ARA claims。</li>
<li>给每个结构 claim 加 baseline。</li>
<li>明确哪些错误来自语义不足，哪些来自图组装不足。</li>
</ol>
<p>如果 S2 能给 S1b 提供结构条件，SPR 才可能从 path hash 走向 semantic route。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-006] 下一轮实验：从 proof 走向真实基线战</title>
      <link>https://www.grepcode.cn/spr/006-next-experiments.html</link>
      <pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/006-next-experiments.html</guid>
      <description>SPR 下一轮实验计划：把受控 context proof 放进真实语料、随机哈希和 BoW 基线战。</description>
      <content:encoded><![CDATA[<h1 id="下一轮实验从-proof-走向真实基线战">下一轮实验：从 proof 走向真实基线战</h1>
<p>S1a 已经成立。S1b 的受控 proof 也已经跑通：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token_acc=0.429
</span></span><span style="display:flex;"><span>context_acc=1.000
</span></span><span style="display:flex;"><span>shuffled_acc=0.482
</span></span></code></pre></div><p>但这还不够。下一轮实验目标不是继续提高 Echo，也不是重复受控 proof，而是把 S1b 放进真实语料和强基线里。</p>
<h2 id="最小模型">最小模型</h2>
<p>从一个小模型开始：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>H_token <span style="color:#f92672">=</span> E[token]
</span></span><span style="display:flex;"><span>H_ctx <span style="color:#f92672">=</span> mean(E[left_window <span style="color:#f92672">+</span> right_window])
</span></span><span style="display:flex;"><span>H <span style="color:#f92672">=</span> normalize(H_token <span style="color:#f92672">+</span> A <span style="color:#f92672">@</span> H_ctx)
</span></span><span style="display:flex;"><span>path <span style="color:#f92672">=</span> route(H)
</span></span></code></pre></div><p>这里 <code>A</code> 是小矩阵，不是大模型。目标不是追求榜单分数，而是验证路径会不会随上下文变。</p>
<h2 id="第一关真实语料多义词">第一关：真实语料多义词</h2>
<p>继续使用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>light
</span></span><span style="display:flex;"><span>bank
</span></span><span style="display:flex;"><span>charge
</span></span></code></pre></div><p>要求：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th>通过条件</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>real-label accuracy</td>
          <td>高于 token-only</td>
      </tr>
      <tr>
          <td>shuffled-label accuracy</td>
          <td>明显下降</td>
      </tr>
      <tr>
          <td>random hash</td>
          <td>低于 context SPR</td>
      </tr>
      <tr>
          <td>keyword / BoW baseline</td>
          <td>作为 sanity check</td>
      </tr>
  </tbody>
</table>
<p>如果真实标签和打乱标签差不多，实验失败。</p>
<p>受控样本已经通过；下一步必须从语料中抽取真实上下文，避免上下文向量被人工 sense anchor 喂得过干净。</p>
<h2 id="第二关随机哈希">第二关：随机哈希</h2>
<p>构造同样容量的 random hash：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>same dim
</span></span><span style="display:flex;"><span>same chunks
</span></span><span style="display:flex;"><span>same depth
</span></span><span style="display:flex;"><span>same leaf count
</span></span></code></pre></div><p>如果 SPR 和 random hash 差不多，说明路径结构没有语义贡献。</p>
<h2 id="第三关bow-小模型">第三关：BoW 小模型</h2>
<p>用一个简单上下文模型做基线：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>bag of context words -&gt; sense
</span></span></code></pre></div><p>这不是为了赢 SPR，而是为了防止 SPR 对一个简单任务说大话。</p>
<p>如果 BoW 轻松解决，SPR 至少要解释自己为什么更有价值：</p>
<ul>
<li>更可组合？</li>
<li>更适合结构生成？</li>
<li>更能接 fold state？</li>
</ul>
<h2 id="第四关接-s2-fold-state">第四关：接 S2 fold state</h2>
<p>如果局部窗口不够，就把 S2 的结构信号接进来：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token
</span></span><span style="display:flex;"><span>local context
</span></span><span style="display:flex;"><span>head/span/fold state
</span></span><span style="display:flex;"><span>-&gt; conditional path
</span></span></code></pre></div><p>这一步才可能让路径带上句法和语义角色。</p>
<h2 id="输出要求">输出要求</h2>
<p>每次实验必须输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>seed
</span></span><span style="display:flex;"><span>dataset slice
</span></span><span style="display:flex;"><span>target words
</span></span><span style="display:flex;"><span>token-only metric
</span></span><span style="display:flex;"><span>context-route metric
</span></span><span style="display:flex;"><span>random-hash metric
</span></span><span style="display:flex;"><span>BoW or keyword metric
</span></span><span style="display:flex;"><span>shuffled-label metric
</span></span><span style="display:flex;"><span>claim decision
</span></span></code></pre></div><p>结果必须写回：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/evidence/README.md
</span></span><span style="display:flex;"><span>ara/s1-echo/logic/claims.md
</span></span></code></pre></div><h2 id="通过标准">通过标准</h2>
<p>只有满足下面条件，S1b 才能从受控 supported 进入工程 supported：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>context SPR &gt; token-only route
</span></span><span style="display:flex;"><span>context SPR &gt; random hash
</span></span><span style="display:flex;"><span>real labels &gt; shuffled labels
</span></span></code></pre></div><p>如果还要升级成 verified，还需要跨数据切片和多 seed 稳定。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-007] S1b proof：上下文条件路由到底证明了什么</title>
      <link>https://www.grepcode.cn/spr/007-context-proof.html</link>
      <pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/007-context-proof.html</guid>
      <description>重写 SPR 历史结论：context-conditioned route 在受控 proof 中成立，但它不是完整语义路由证明。</description>
      <content:encoded><![CDATA[<h1 id="s1b-proof上下文条件路由到底证明了什么">S1b proof：上下文条件路由到底证明了什么</h1>
<p>前面的反证已经把话说清楚了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route(token)
</span></span></code></pre></div><p>不是语义路由。它能稳定、低碰撞地给 token 分配路径，但同一个 <code>bank</code> 在 <code>loan</code> 和 <code>river</code> 旁边仍然是同一个 <code>bank</code>。</p>
<p>这篇文章补上 proof：如果把输入升级成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route(token, context)
</span></span></code></pre></div><p>当前 S1 路径算子有没有能力把同词多义分开？</p>
<p>答案是：在受控 proof 里可以。但这个答案必须读完整。</p>
<h2 id="实验脚本">实验脚本</h2>
<p>脚本位置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>holds/SameTime/experiments/spr_context_proof.py
</span></span></code></pre></div><p>远端复现命令：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd /data/homecicd/sametime/code/wmt
</span></span><span style="display:flex;"><span>python3 spr_context_proof.py
</span></span></code></pre></div><p>它使用三个目标词：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>light: illumination / weight
</span></span><span style="display:flex;"><span>bank: finance / river
</span></span><span style="display:flex;"><span>charge: money / electric / legal
</span></span></code></pre></div><p>总样本数是 56。每个样本由目标词和一组上下文词构成。</p>
<h2 id="设计要点">设计要点</h2>
<p>实验比较三条路线：</p>
<table>
  <thead>
      <tr>
          <th>路线</th>
          <th>输入</th>
          <th>目的</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token-only</td>
          <td><code>token</code></td>
          <td>检查旧 S1a 能不能自己消歧</td>
      </tr>
      <tr>
          <td>context route</td>
          <td><code>token + context</code></td>
          <td>检查 S1b 的最小接口是否可行</td>
      </tr>
      <tr>
          <td>shuffled context</td>
          <td><code>token + context</code>，但 sense 标签打乱</td>
          <td>检查结果是否真的依赖语义标签</td>
      </tr>
  </tbody>
</table>
<p>路径仍然使用 S1 的分块树路由：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>dim=64
</span></span><span style="display:flex;"><span>chunks=4
</span></span><span style="display:flex;"><span>depth=7
</span></span><span style="display:flex;"><span>route_bits = roll + sign_alt
</span></span></code></pre></div><p>分类方式也故意保持简单：同一目标词内部做 leave-one-out 1NN，用路径 bit 的 Hamming 距离找最近邻。</p>
<p>这不是为了追求复杂模型，而是为了回答一个更小的问题：</p>
<blockquote>
<p>如果上下文信号进入 route，路径空间本身能不能承载消歧？</p></blockquote>
<h2 id="结果">结果</h2>
<p>io 上的输出摘要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>examples=56
</span></span><span style="display:flex;"><span>targets=bank, charge, light
</span></span><span style="display:flex;"><span>token_acc=0.429
</span></span><span style="display:flex;"><span>context_acc=1.000
</span></span><span style="display:flex;"><span>shuffled_acc=0.482
</span></span><span style="display:flex;"><span>context_purity=1.000
</span></span><span style="display:flex;"><span>mixed_context_buckets=0
</span></span></code></pre></div><p>对应表格：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th>数值</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token-only accuracy</td>
          <td>0.429</td>
          <td>旧 S1a 不能区分同词多义</td>
      </tr>
      <tr>
          <td>context-route accuracy</td>
          <td>1.000</td>
          <td>受控上下文进入 route 后可以分开 sense</td>
      </tr>
      <tr>
          <td>shuffled-label accuracy</td>
          <td>0.482</td>
          <td>标签打乱后优势坍塌</td>
      </tr>
      <tr>
          <td>context path purity</td>
          <td>1.000</td>
          <td>同一路径桶内没有混合 sense</td>
      </tr>
  </tbody>
</table>
<p>这个结果把 S1b 从“纯猜想”推进到“机制上可行”。</p>
<h2 id="它证明什么">它证明什么</h2>
<p>它证明：</p>
<ul>
<li>S1 的路径算子不只适合 token identity。</li>
<li>当输入向量里真的包含上下文信号时，路径可以随上下文变化。</li>
<li>同一个 token 可以在不同上下文下进入不同稳定路径。</li>
<li>label shuffle 会破坏这个优势，因此实验不是只靠样本数量或标签先验赢。</li>
</ul>
<p>用 ARA 的说法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1a = Token Path Hash
</span></span><span style="display:flex;"><span>S1b = Context-conditioned Routing
</span></span></code></pre></div><p>这个 proof 支持 S1b 的接口方向。</p>
<h2 id="它不证明什么">它不证明什么</h2>
<p>它不证明：</p>
<ul>
<li>真实语料中的上下文向量已经干净携带 sense。</li>
<li>SPR 在多义词消歧上优于 BoW、keyword、MLP 或 random hash。</li>
<li>翻译质量会因为 S1b 自动提升。</li>
<li>“路径即语义”可以恢复成一句无条件口号。</li>
</ul>
<p>这点很重要。当前 proof 里的上下文词向量是按 sense anchor 生成的。也就是说，实验刻意保证上下文里有可用语义信号。</p>
<p>因此它证明的是路径机制的承载能力，不是真实语料的端到端能力。</p>
<h2 id="历史结论怎么修正">历史结论怎么修正</h2>
<p>旧结论里有三层说法混在一起：</p>
<table>
  <thead>
      <tr>
          <th>历史说法</th>
          <th>新状态</th>
          <th>原因</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>S1 路径空间容量足够</td>
          <td>保留</td>
          <td>Echo 和 solo leaf 结果可复现</td>
      </tr>
      <tr>
          <td><code>roll + sign_alt</code> 修复顺序碰撞</td>
          <td>保留</td>
          <td>反向 toy case 已验证</td>
      </tr>
      <tr>
          <td>Echo 高分说明语义路由成立</td>
          <td>降级</td>
          <td>Echo 也可能是高容量查表</td>
      </tr>
      <tr>
          <td>token-only path 是语义状态</td>
          <td>拒绝</td>
          <td>多义词反证失败</td>
      </tr>
      <tr>
          <td>context-conditioned path 可以承载消歧</td>
          <td>受控支持</td>
          <td>本 proof 通过，但还不是真实语料结论</td>
      </tr>
  </tbody>
</table>
<p>所以新的 SPR 叙事应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1a 证明路径基础设施可用。
</span></span><span style="display:flex;"><span>S1a 不证明语义。
</span></span><span style="display:flex;"><span>S1b 在受控 proof 中证明 route(token, context) 是正确方向。
</span></span><span style="display:flex;"><span>S1b 还需要真实语料、random-hash、BoW 和多 seed 基线战。
</span></span></code></pre></div><h2 id="架构决策">架构决策</h2>
<p>从现在开始，SPR 的代码和文章都应该避免把 <code>route(token)</code> 写成语义路由。</p>
<p>更专业的接口是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>H_token <span style="color:#f92672">=</span> E[token]
</span></span><span style="display:flex;"><span>H_ctx <span style="color:#f92672">=</span> context_encoder(window)
</span></span><span style="display:flex;"><span>H <span style="color:#f92672">=</span> normalize(H_token <span style="color:#f92672">+</span> A <span style="color:#f92672">@</span> H_ctx)
</span></span><span style="display:flex;"><span>path <span style="color:#f92672">=</span> route(H)
</span></span></code></pre></div><p>如果 S2 fold state 可用，还应该继续扩展：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token + local context + fold state -&gt; conditional path
</span></span></code></pre></div><p>这才是 SPR 可能成为“语义前缀路由”的位置。</p>
<h2 id="下一道门">下一道门</h2>
<p>下一步不是再证明一次受控样本，而是做真实基线战：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>context SPR &gt; token-only route
</span></span><span style="display:flex;"><span>context SPR &gt; matched random hash
</span></span><span style="display:flex;"><span>context SPR &gt;= cheap BoW/keyword baseline on the task it claims to solve
</span></span><span style="display:flex;"><span>real labels &gt; shuffled labels across multiple seeds
</span></span></code></pre></div><p>只有过了这些门，S1b 才能从受控 proof 进入工程 claim。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-008] S2 策略审计：TreeHeap、Role Slots 和概率容器</title>
      <link>https://www.grepcode.cn/spr/008-s2-strategy-audit.html</link>
      <pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/008-s2-strategy-audit.html</guid>
      <description>用 ARA 方式解释 S2 实验：当前 TreeHeap checkpoint 支撑什么、不支撑什么，以及下一步为什么转向 Role Slots 和 Probability Container。</description>
      <content:encoded><![CDATA[<h1 id="s2-策略审计treeheaprole-slots-和概率容器">S2 策略审计：TreeHeap、Role Slots 和概率容器</h1>
<p>这篇文章写给刚接触 SPR 的读者。你只需要有本科计算机水平，知道一点向量、分类器、树和图，就能读下去。</p>
<p>先说结论：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 S2 最可靠的方向不是：
</span></span><span style="display:flex;"><span>TreeHeap 128D -&gt; 直接能量搜索 -&gt; 正确语法树
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>而是：
</span></span><span style="display:flex;"><span>语义向量 -&gt; Role Slot -&gt; 概率容器 -&gt; 延迟坍缩
</span></span></code></pre></div><p>这句话里有几个词听起来很硬。我们一个一个拆开。</p>
<h2 id="背景我们到底想解决什么">背景：我们到底想解决什么</h2>
<p>普通神经翻译或语言模型经常把句子看成 token 序列，然后用 attention 去找词和词之间的关系。</p>
<p>SPR 想探索另一条路：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能不能把语言结构压缩成更明确的路径、槽位和图？
</span></span></code></pre></div><p>在 S2 里，我们关心的不是“这个词像不像另一个词”，而是更结构化的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>谁是主语？
</span></span><span style="display:flex;"><span>谁是谓语？
</span></span><span style="display:flex;"><span>谁是宾语？
</span></span><span style="display:flex;"><span>哪个短语修饰哪个短语？
</span></span><span style="display:flex;"><span>哪些候选结构应该先保留，不要太早拍死？
</span></span></code></pre></div><p>这就是 Fold Stack / Graph Builder 的问题。</p>
<h2 id="ara-方式">ARA 方式</h2>
<p>这里先纠正一个容易误解的点：ARA 不是</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Architecture / Reasoning / Artifact
</span></span></code></pre></div><p>ARA 指的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Agent-Native Research Artifact
</span></span></code></pre></div><p>它不是一种写作修辞，而是一套面向 AI agent 的研究制品协议。论文《The Last Human-Written Paper: Agent-Native Research Artifacts》把 ARA 拆成四层：</p>
<table>
  <thead>
      <tr>
          <th>层</th>
          <th>目录</th>
          <th>作用</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Cognitive Layer</td>
          <td><code>/logic</code></td>
          <td>问题、方案、可证伪 claim、实验计划</td>
      </tr>
      <tr>
          <td>Physical Layer</td>
          <td><code>/src</code></td>
          <td>可执行代码、配置、环境、实现说明</td>
      </tr>
      <tr>
          <td>Exploration Graph</td>
          <td><code>/trace</code></td>
          <td>研究 DAG、失败路线、pivot、dead end</td>
      </tr>
      <tr>
          <td>Evidence Layer</td>
          <td><code>/evidence</code></td>
          <td>原始输出、日志、指标表、claim 的证据</td>
      </tr>
  </tbody>
</table>
<p>所以这篇文章只是给人读的说明文；真正的 ARA 内容应该在仓库的这些目录里。</p>
<p>ARA 的原则是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个结论必须绑定证据。
</span></span><span style="display:flex;"><span>一个强 claim 必须允许被实验推翻。
</span></span></code></pre></div><p>所以这篇不会说“TreeHeap 已经成功了”。我们只说实验支持了什么，没有支持什么。</p>
<h2 id="logic先预测再实验"><code>/logic</code>：先预测，再实验</h2>
<p>这里还要补一个更重要的点。</p>
<p>ARA 不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先随便跑实验
</span></span><span style="display:flex;"><span>看到结果
</span></span><span style="display:flex;"><span>再回头编一个结论
</span></span></code></pre></div><p>真正的 ARA 顺序应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>predict -&gt; claim -&gt; experiment -&gt; evidence -&gt; trace
</span></span></code></pre></div><p>翻译成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 先写一个预判：如果我的理论是真的，实验应该看到什么？
</span></span><span style="display:flex;"><span>2. 再把这个预判变成一个可以被推翻的 claim。
</span></span><span style="display:flex;"><span>3. 然后设计实验，专门去验证或打脸这个 claim。
</span></span><span style="display:flex;"><span>4. 实验输出原始数据，放进 /evidence。
</span></span><span style="display:flex;"><span>5. 如果实验失败或改方向，把失败路线写进 /trace。
</span></span></code></pre></div><p>这和普通博客最大的区别是：ARA 不鼓励“事后讲故事”。<br>
它要求我们在实验前就写清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我预计会发生什么？
</span></span><span style="display:flex;"><span>什么结果算支持？
</span></span><span style="display:flex;"><span>什么结果算失败？
</span></span><span style="display:flex;"><span>如果失败，架构要怎么改？
</span></span></code></pre></div><p>拿这次 <code>t_merge</code> 问题举例。</p>
<p>我们现在不应该直接写：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>t_merge 失效了。
</span></span></code></pre></div><p>而应该先写一个 predict：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-TM01:
</span></span><span style="display:flex;"><span>如果 TreeHeap 的 L0 × 背景场参与机制成立，
</span></span><span style="display:flex;"><span>那么新训练 checkpoint 的 post-merge 向量应该：
</span></span><span style="display:flex;"><span>1. 不被公共方向完全主导；
</span></span><span style="display:flex;"><span>2. 保留 L0/token identity；
</span></span><span style="display:flex;"><span>3. 保留 path/background bucket 信息；
</span></span><span style="display:flex;"><span>4. 在 role-slot 或 context probe 上优于 L0 baseline；
</span></span><span style="display:flex;"><span>5. 从 CMul pre-merge 到 post-merge 的距离结构不能大幅丢失。
</span></span></code></pre></div><p>然后它对应一个 claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C-TM01:
</span></span><span style="display:flex;"><span>TreeHeap 的背景场乘积可以产生一个非坍缩的 token-in-background state。
</span></span></code></pre></div><p>再对应一个实验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-TM01:
</span></span><span style="display:flex;"><span>重新训练一个小 checkpoint，
</span></span><span style="display:flex;"><span>每个 epoch 自动跑 tmerge_diagnostic 和 strategy_audit。
</span></span></code></pre></div><p>提前写好通过标准：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Pass:
</span></span><span style="display:flex;"><span>- raw/centered cosine 都不过度坍缩；
</span></span><span style="display:flex;"><span>- effective rank 足够高；
</span></span><span style="display:flex;"><span>- path bucket probe 明显高于 chance；
</span></span><span style="display:flex;"><span>- role/context probe 优于 L0 baseline；
</span></span><span style="display:flex;"><span>- CMul -&gt; post-merge distance correlation 保持较高。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Fail:
</span></span><span style="display:flex;"><span>- post-merge 向量仍然被公共方向主导；
</span></span><span style="display:flex;"><span>- role/context probe 不如 L0；
</span></span><span style="display:flex;"><span>- path probe 接近 chance；
</span></span><span style="display:flex;"><span>- 距离结构从 pre 到 post 大幅丢失。
</span></span></code></pre></div><p>这才是 ARA 的“logic 先行”。</p>
<p>所以，旧 checkpoint 现在不能为 TreeHeap 原理背书。它只能作为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>legacy artifact
</span></span></code></pre></div><p>用来暴露问题、形成新的 predict。<br>
真正能给 TreeHeap 背书的 evidence，必须来自按这个 predict 重新设计并训练的新 checkpoint。</p>
<h2 id="logic新的四层理解"><code>/logic</code>：新的四层理解</h2>
<p>目前更清楚的分层是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0: token/path substrate
</span></span><span style="display:flex;"><span>L1: contextual semantic vector
</span></span><span style="display:flex;"><span>L2: role-slot fold structure
</span></span><span style="display:flex;"><span>L3: probability/energy collapse
</span></span></code></pre></div><p>可以用一个很朴素的比喻理解。</p>
<p>数字 <code>321</code> 不是简单的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[3, 2, 1]
</span></span></code></pre></div><p>它真正的结构是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>3 * 百位 + 2 * 十位 + 1 * 个位
</span></span></code></pre></div><p>这里最重要的不是 <code>3,2,1</code> 本身，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>百位、十位、个位
</span></span></code></pre></div><p>这些位置就是“位权”。</p>
<p>放到语言里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat eats fish
</span></span></code></pre></div><p>不应该只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[cat, eats, fish]
</span></span></code></pre></div><p>而应该更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SUBJECT = cat
</span></span><span style="display:flex;"><span>ROOT    = eats
</span></span><span style="display:flex;"><span>OBJECT  = fish
</span></span></code></pre></div><p>所以 S2 现在要找的不是更深的树，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Role Slots
</span></span></code></pre></div><p>也就是“结构槽位”。</p>
<h2 id="实验一当前-treeheap-128d-是否适合直接做语法能量">实验一：当前 TreeHeap 128D 是否适合直接做语法能量</h2>
<p>我们先测试一个基础问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>历史 checkpoint 里的 TreeHeap 128D 向量到底长什么样？
</span></span></code></pre></div><p>使用的 checkpoint 是历史遗留模型：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/mnt/nas/datasets/wmt_massive/checkpoints/anchor_tree_massive_ep3.pt
</span></span></code></pre></div><p>它不是这次重新训练的模型。</p>
<p>我们比较四种向量：</p>
<table>
  <thead>
      <tr>
          <th>向量</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>random</td>
          <td>随机向量，作为健康基线</td>
      </tr>
      <tr>
          <td>L0</td>
          <td>checkpoint 里的原始 token embedding</td>
      </tr>
      <tr>
          <td>TreeHeap</td>
          <td>L0 + path + t_merge 后的 128D 输出</td>
      </tr>
      <tr>
          <td>path</td>
          <td>token 在 TreeHeap 路径上的位置向量</td>
      </tr>
  </tbody>
</table>
<p>最重要的指标叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>off-diagonal cosine mean
</span></span></code></pre></div><p>如果你不熟 cosine，可以简单理解成“两个不同词的向量平均有多像”。</p>
<ul>
<li>接近 <code>0</code>：不同词分得比较开。</li>
<li>接近 <code>1</code>：不同词几乎都挤在一起。</li>
</ul>
<p>实验结果：</p>
<table>
  <thead>
      <tr>
          <th>Vector</th>
          <th>不同词平均相似度</th>
          <th>解释</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>random</td>
          <td>0.0007</td>
          <td>正常随机基线</td>
      </tr>
      <tr>
          <td>L0</td>
          <td>0.0003</td>
          <td>分得很开</td>
      </tr>
      <tr>
          <td>TreeHeap</td>
          <td>0.9849</td>
          <td>几乎全挤在一起</td>
      </tr>
      <tr>
          <td>path</td>
          <td>0.4937</td>
          <td>粗粒度路径簇</td>
      </tr>
  </tbody>
</table>
<p>这个结果很关键。</p>
<p>它说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 ep3 TreeHeap 输出太坍缩。
</span></span></code></pre></div><p>也就是说，很多不同 token 经过 TreeHeap 后，方向几乎一样。这样的向量很难直接拿来判断语法结构。</p>
<p>这不是说 TreeHeap 理论错了，而是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前历史 checkpoint 的 tree 输出不能背负“语法能量已成立”的 claim。
</span></span></code></pre></div><h2 id="实验二非交换张量能不能直接选出正确结构">实验二：非交换张量能不能直接选出正确结构</h2>
<p>我们之前讨论过一个想法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>h1 ⊗ h2 ⊗ h3
</span></span></code></pre></div><p>这是有序张量。它和普通加法不同。</p>
<p>普通加法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat + eats + fish
</span></span><span style="display:flex;"><span>= fish + eats + cat
</span></span></code></pre></div><p>顺序丢了。</p>
<p>有序张量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat ⊗ eats ⊗ fish
</span></span><span style="display:flex;"><span>!= fish ⊗ eats ⊗ cat
</span></span></code></pre></div><p>顺序保住了。</p>
<p>所以我们要分清两个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>问题 1：它能不能区分排列？
</span></span><span style="display:flex;"><span>问题 2：它能不能把正确语法排到第一？
</span></span></code></pre></div><p>实验结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能区分排列，但 raw energy 还不能稳定选出正确语法。
</span></span></code></pre></div><p>在 SVO3 任务上，role-slot template 的结果如下：</p>
<table>
  <thead>
      <tr>
          <th>Mode</th>
          <th>Top-1</th>
          <th>Top-3</th>
          <th>Mean gold rank</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>L0 + random role basis</td>
          <td>0.509</td>
          <td>0.812</td>
          <td>2.11</td>
      </tr>
      <tr>
          <td>random + onehot role basis</td>
          <td>0.464</td>
          <td>0.786</td>
          <td>2.21</td>
      </tr>
      <tr>
          <td>TreeHeap + onehot role basis</td>
          <td>0.330</td>
          <td>0.723</td>
          <td>2.59</td>
      </tr>
  </tbody>
</table>
<p>这里 Top-1 的意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>正确排列排第一的比例
</span></span></code></pre></div><p>Top-3 的意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>正确排列出现在前三名的比例
</span></span></code></pre></div><p>如果 TreeHeap 真的已经天然对齐语法，我们希望它明显赢过 L0 和 random。</p>
<p>但结果相反：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 没赢。
</span></span></code></pre></div><p>所以结论必须收紧：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>非交换张量是必要工具。
</span></span><span style="display:flex;"><span>但当前 TreeHeap 输出不足以直接做 syntax energy。
</span></span></code></pre></div><h2 id="实验三role-slots-是否真的存在">实验三：Role Slots 是否真的存在</h2>
<p>接下来问一个更实际的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语言结构是不是适合用少量槽位表达？
</span></span></code></pre></div><p>比如 VP 可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>VP {
</span></span><span style="display:flex;"><span>  subject
</span></span><span style="display:flex;"><span>  object
</span></span><span style="display:flex;"><span>  adverb
</span></span><span style="display:flex;"><span>  complement
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>而不是强行写成二叉树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat
</span></span><span style="display:flex;"><span>├─ cat
</span></span><span style="display:flex;"><span>└─ NodeX
</span></span><span style="display:flex;"><span>   ├─ fish
</span></span><span style="display:flex;"><span>   └─ quickly
</span></span></code></pre></div><p>我们在 12,000 条 WMT massive 英文样本上统计 FoldNode 的子节点数量。</p>
<p>结果：</p>
<table>
  <thead>
      <tr>
          <th>Degree threshold</th>
          <th>Coverage</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>&lt;= 2</td>
          <td>86.1%</td>
      </tr>
      <tr>
          <td>&lt;= 3</td>
          <td>95.8%</td>
      </tr>
      <tr>
          <td>&lt;= 4</td>
          <td>99.0%</td>
      </tr>
      <tr>
          <td>&lt;= 5</td>
          <td>99.8%</td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>绝大多数 FoldNode 用 4 个左右的槽位就够了。
</span></span></code></pre></div><p>这对架构很重要。</p>
<p>它支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Role-slotted FoldNode
</span></span></code></pre></div><p>而不是继续押：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>更深的二叉树
</span></span><span style="display:flex;"><span>或者
</span></span><span style="display:flex;"><span>更高叉但无名的树
</span></span></code></pre></div><p>常见模式也很直观。</p>
<p>VP 常见模式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>nsubj
</span></span><span style="display:flex;"><span>dobj
</span></span><span style="display:flex;"><span>dobj + nsubj
</span></span><span style="display:flex;"><span>aux + dobj
</span></span><span style="display:flex;"><span>aux + dobj + nsubj
</span></span></code></pre></div><p>NP 常见模式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>det
</span></span><span style="display:flex;"><span>compound
</span></span><span style="display:flex;"><span>amod
</span></span><span style="display:flex;"><span>amod + det
</span></span><span style="display:flex;"><span>poss
</span></span></code></pre></div><p>翻译成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>VP 常围绕主语、宾语、助动词展开。
</span></span><span style="display:flex;"><span>NP 常围绕限定词、复合词、形容词、所有格展开。
</span></span></code></pre></div><p>这就是 Role Slots 的证据。</p>
<h2 id="实验四概率容器是否有必要">实验四：概率容器是否有必要</h2>
<p>Graph Builder 过去常做一件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给每个节点选一个最可能的父节点。
</span></span></code></pre></div><p>这叫过早坍缩。</p>
<p>但很多结构局部看不出来。</p>
<p>经典例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I saw the man with a telescope.
</span></span></code></pre></div><p><code>with a telescope</code> 可以挂到 <code>saw</code>，也可以挂到 <code>man</code>。局部阶段未必应该立刻选死。</p>
<p>所以我们测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>正确父节点是否在 top-k 候选里？
</span></span></code></pre></div><p>如果 top-1 不完美，但 top-3 几乎总包含正确答案，那就说明应该保留候选分布，而不是马上 argmax。</p>
<p>结果：</p>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th>Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>graphs</td>
          <td>8,408</td>
      </tr>
      <tr>
          <td>pair rows</td>
          <td>195,610</td>
      </tr>
      <tr>
          <td>eval child sets</td>
          <td>2,758</td>
      </tr>
      <tr>
          <td>gold parent in top-1</td>
          <td>93.1%</td>
      </tr>
      <tr>
          <td>gold parent in top-2</td>
          <td>99.3%</td>
      </tr>
      <tr>
          <td>gold parent in top-3</td>
          <td>99.9%</td>
      </tr>
      <tr>
          <td>gold parent in top-5</td>
          <td>100.0%</td>
      </tr>
  </tbody>
</table>
<p>这个结果非常强。</p>
<p>它说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>正确答案几乎总在 top-3 里。
</span></span></code></pre></div><p>所以 Graph Builder 不应该只输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>parent = A
</span></span></code></pre></div><p>而应该输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ParentContainer {
</span></span><span style="display:flex;"><span>  A: 0.61
</span></span><span style="display:flex;"><span>  B: 0.27
</span></span><span style="display:flex;"><span>  C: 0.12
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>然后把这个容器传给后续模块，让更大的上下文再决定。</p>
<p>这就是 Probability Container。</p>
<h2 id="夜间任务的部分结果">夜间任务的部分结果</h2>
<p>后来我们又启动了一个更大的 8 小时任务，目标是继续查：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>坍缩到底发生在哪里？
</span></span><span style="display:flex;"><span>上下文窗口是否稳定提升 role-slot 预测？
</span></span><span style="display:flex;"><span>不同 epoch 的 checkpoint 是否不同？
</span></span></code></pre></div><p>截至写作时，完整任务还在运行。但第一轮部分结果已经给出一个很有用的信号。</p>
<p>对 <code>anchor_tree_massive_ep1.pt</code>：</p>
<table>
  <thead>
      <tr>
          <th>Mode</th>
          <th>不同词平均相似度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>L0</td>
          <td>0.0186</td>
      </tr>
      <tr>
          <td>CMul pre-merge</td>
          <td>0.0200</td>
      </tr>
      <tr>
          <td>Tree output</td>
          <td>0.9860</td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>坍缩主要发生在 t_merge 之后。
</span></span></code></pre></div><p>也就是说，L0 和 CMul 本身没有严重坍缩，但经过 <code>t_merge</code> 之后，向量被挤到很相似的方向。</p>
<p>Role probe 的部分结果：</p>
<table>
  <thead>
      <tr>
          <th>Feature</th>
          <th>Top-1</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>L0 only</td>
          <td>0.538</td>
      </tr>
      <tr>
          <td>L0 + context</td>
          <td>0.570</td>
      </tr>
      <tr>
          <td>CMul + context</td>
          <td>0.559</td>
      </tr>
      <tr>
          <td>Tree + context</td>
          <td>0.548</td>
      </tr>
      <tr>
          <td>path only</td>
          <td>0.325</td>
      </tr>
  </tbody>
</table>
<p>这个结果说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>上下文确实有 role-slot 信号。
</span></span><span style="display:flex;"><span>path 单独很弱。
</span></span><span style="display:flex;"><span>tree output 不如 L0/CMul 稳。
</span></span></code></pre></div><p>这些是部分结果，不能替代完整 8 小时任务的最终统计。但方向已经很清楚。</p>
<h2 id="logic我们现在怎么判断"><code>/logic</code>：我们现在怎么判断</h2>
<p>把上面的实验合起来，推理链是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 当前 TreeHeap tree output 高度坍缩。
</span></span><span style="display:flex;"><span>2. 坍缩后的向量不适合直接做语法能量。
</span></span><span style="display:flex;"><span>3. 非交换张量可以区分排列，但不自动等于语法正确。
</span></span><span style="display:flex;"><span>4. FoldNode 的真实结构高度适合小槽位表达。
</span></span><span style="display:flex;"><span>5. parent top-k 覆盖非常高，所以概率容器有价值。
</span></span><span style="display:flex;"><span>6. 上下文能提升 role-slot 预测。
</span></span></code></pre></div><p>所以下一步不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>继续硬做 edge classifier
</span></span></code></pre></div><p>也不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>直接宣布 TreeHeap energy search 成功
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Role Slots + Probability Container + 更好的 L1/context vector
</span></span></code></pre></div><h2 id="当前架构决策">当前架构决策</h2>
<h3 id="继续推进">继续推进</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Role-slotted FoldNode
</span></span></code></pre></div><p>因为 degree 分布强烈支持小槽位。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Probability Container
</span></span></code></pre></div><p>因为 gold parent top-3 覆盖接近满分。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Context-conditioned role prediction
</span></span></code></pre></div><p>因为 L0 + context 已经比 L0 only 更好。</p>
<h3 id="暂停放大的-claim">暂停放大的 claim</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 3-epoch TreeHeap 128D 已经是 syntax vector。
</span></span></code></pre></div><p>不支持。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>纯 tensor energy 可以替代 Graph Builder。
</span></span></code></pre></div><p>不支持。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>path 本身编码语法角色。
</span></span></code></pre></div><p>不支持。</p>
<h2 id="evidence证据在哪里"><code>/evidence</code>：证据在哪里</h2>
<p>完整 strategy audit：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s2-translation/evidence/strategy_audit/
</span></span></code></pre></div><p>关键文件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>strategy_audit_summary.json
</span></span><span style="display:flex;"><span>tensor_energy_rows.csv
</span></span><span style="display:flex;"><span>parent_container_rows.csv
</span></span><span style="display:flex;"><span>role_slot_degree.json
</span></span><span style="display:flex;"><span>README.md
</span></span></code></pre></div><p>夜间任务部分结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s2-translation/evidence/overnight_partial_20260617/
</span></span></code></pre></div><p>远端正在运行的完整任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>io:/data/homecicd/sametime/logs/s2_overnight_20260617_150111
</span></span></code></pre></div><p>脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>s2_strategy_audit.py
</span></span><span style="display:flex;"><span>s2_overnight_io.py
</span></span><span style="display:flex;"><span>run_s2_overnight_io.sh
</span></span></code></pre></div><h2 id="给初学者的最后总结">给初学者的最后总结</h2>
<p>如果你只记住三句话，记这三句：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第一，当前 TreeHeap checkpoint 的最终 128D 输出太坍缩，不能直接当语法向量。
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第二，语言结构更像“语义向量填入角色槽位”，而不是普通二叉树越堆越深。
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第三，Graph Builder 不应该太早选唯一答案，应该保留 top-k 概率容器，让后续上下文再坍缩。
</span></span></code></pre></div><p>这就是目前 S2 理论建设的位置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>理论路线更清楚了。
</span></span><span style="display:flex;"><span>部分方向被实验支持。
</span></span><span style="display:flex;"><span>部分过强说法被实验降级。
</span></span><span style="display:flex;"><span>下一步要训练或抽取更好的 L1/context vector，再重跑同一套审计。
</span></span></code></pre></div><blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-009] 世界模型与参考系：TreeHeap 术语统一</title>
      <link>https://www.grepcode.cn/spr/009-world-model-frames.html</link>
      <pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/009-world-model-frames.html</guid>
      <description>统一 TreeHeap 的世界模型、参与乘积、参考系、latent slot 和概率容器术语，为后续 ARA predict 做准备。</description>
      <content:encoded><![CDATA[<h1 id="世界模型与参考系treeheap-术语统一">世界模型与参考系：TreeHeap 术语统一</h1>
<p>这篇文章先不急着做新实验。它的目标是统一语言。</p>
<p>因为如果我们继续混用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>背景场
</span></span><span style="display:flex;"><span>path field
</span></span><span style="display:flex;"><span>概率意识场
</span></span><span style="display:flex;"><span>world topology
</span></span><span style="display:flex;"><span>context field
</span></span></code></pre></div><p>讨论会很快发散。后面统一叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>世界模型（World Model）
</span></span></code></pre></div><h2 id="为什么要叫世界模型">为什么要叫世界模型</h2>
<p>TreeHeap 里真正想表达的不是“一个词的孤立含义”。</p>
<p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ball
</span></span></code></pre></div><p>它可以进入很多世界：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football
</span></span><span style="display:flex;"><span>basketball
</span></span><span style="display:flex;"><span>baseball
</span></span><span style="display:flex;"><span>volleyball
</span></span></code></pre></div><p>这些词都包含 <code>ball</code>，但它们不是同一个东西。</p>
<p>差别来自：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>脚
</span></span><span style="display:flex;"><span>手
</span></span><span style="display:flex;"><span>球场
</span></span><span style="display:flex;"><span>球网
</span></span><span style="display:flex;"><span>规则
</span></span><span style="display:flex;"><span>动作
</span></span><span style="display:flex;"><span>人与物的关系
</span></span></code></pre></div><p>所以：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>球 + 脚 = 足球
</span></span><span style="display:flex;"><span>球 + 手 = 篮球
</span></span></code></pre></div><p>不是简单的词向量加法，而是在说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一个实体进入了不同的世界模型。
</span></span></code></pre></div><p><code>ball</code> 是对象，<code>foot/hand/field/court/rule</code> 是它参与的世界关系。</p>
<h2 id="术语表">术语表</h2>
<p>先给一张沟通表。</p>
<table>
  <thead>
      <tr>
          <th>术语</th>
          <th>英文名</th>
          <th>含义</th>
          <th>在 TreeHeap 里的位置</th>
          <th>例子</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>词法基底</td>
          <td>Lexical Base / L0</td>
          <td>token 自己的基础语义向量</td>
          <td><code>L0[token]</code></td>
          <td><code>ball</code>, <code>foot</code>, <code>hand</code></td>
      </tr>
      <tr>
          <td>世界模型</td>
          <td>World Model</td>
          <td>token 所处的关系、场景、规则、拓扑背景</td>
          <td>path nodes / context / latent frame</td>
          <td>“脚能踢球”、“手能投球”、“球场规则”</td>
      </tr>
      <tr>
          <td>参与乘积</td>
          <td>Participation Product</td>
          <td>让 L0 进入世界模型，形成带背景的状态</td>
          <td><code>CMul(L0, WorldModel)</code></td>
          <td><code>ball × sport-frame</code></td>
      </tr>
      <tr>
          <td>入世状态</td>
          <td>Token-in-World State</td>
          <td>token 参与世界模型后的状态</td>
          <td>CMul pre-merge 或 post-merge</td>
          <td>“足球语境里的 ball”</td>
      </tr>
      <tr>
          <td>读出层</td>
          <td>Readout / Merge</td>
          <td>把入世状态投影成下游可用向量</td>
          <td><code>t_merge</code></td>
          <td>128D final vector</td>
      </tr>
      <tr>
          <td>参考系</td>
          <td>Frame of Reference</td>
          <td>解释向量方向的局部坐标系</td>
          <td>latent axes / frame basis</td>
          <td>sport frame, body-part frame</td>
      </tr>
      <tr>
          <td>结构槽位</td>
          <td>Latent Slot</td>
          <td>无监督或弱监督发现的结构位置，不等于主谓宾</td>
          <td>Fold / role-slot layer</td>
          <td><code>slot_3</code>, <code>slot_12</code></td>
      </tr>
      <tr>
          <td>差分方向</td>
          <td>Relation Delta</td>
          <td>两个概念的差分，表示关系变化</td>
          <td>vector difference</td>
          <td><code>football - ball</code></td>
      </tr>
      <tr>
          <td>投影解释</td>
          <td>Frame Projection</td>
          <td>把差分投到某个参考系，看它指向什么</td>
          <td><code>delta · frame_axis</code></td>
          <td>是否更接近 <code>foot/kick</code></td>
      </tr>
      <tr>
          <td>概率容器</td>
          <td>Probability Container</td>
          <td>不急着 argmax，保留多个候选状态</td>
          <td>L2/L3 collapse 前</td>
          <td>parent top-k, slot top-k</td>
      </tr>
      <tr>
          <td>坍缩</td>
          <td>Collapse</td>
          <td>从多个可能状态选择或收敛到一个状态</td>
          <td>下游决策阶段</td>
          <td>从 top-3 parent 选一个</td>
      </tr>
      <tr>
          <td>证据门</td>
          <td>Evidence Gate</td>
          <td>提前写好的通过/失败标准</td>
          <td>ARA <code>/logic</code></td>
          <td>rank、probe、top-k</td>
      </tr>
  </tbody>
</table>
<p>口语版：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0 是“词自己”。
</span></span><span style="display:flex;"><span>世界模型是“这个词所在的世界规则”。
</span></span><span style="display:flex;"><span>参与乘积是“词进入这个世界”。
</span></span><span style="display:flex;"><span>入世状态是“词进入世界后的样子”。
</span></span><span style="display:flex;"><span>参考系是“我们用什么坐标解释它”。
</span></span><span style="display:flex;"><span>slot 是“结构自己长出来的位置”。
</span></span><span style="display:flex;"><span>概率容器是“先别拍死，保留多个可能”。
</span></span><span style="display:flex;"><span>坍缩是“信息足够后再做决定”。
</span></span></code></pre></div><h2 id="一个例子足球和篮球">一个例子：足球和篮球</h2>
<p>假设我们有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ball
</span></span><span style="display:flex;"><span>football
</span></span><span style="display:flex;"><span>basketball
</span></span><span style="display:flex;"><span>foot
</span></span><span style="display:flex;"><span>hand
</span></span><span style="display:flex;"><span>kick
</span></span><span style="display:flex;"><span>throw
</span></span><span style="display:flex;"><span>field
</span></span><span style="display:flex;"><span>court
</span></span><span style="display:flex;"><span>goal
</span></span><span style="display:flex;"><span>basket
</span></span></code></pre></div><p>我们不想只问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football 和 basketball 像不像？
</span></span></code></pre></div><p>我们更想问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football 相对 ball 多出来的关系是什么？
</span></span><span style="display:flex;"><span>basketball 相对 ball 多出来的关系是什么？
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>delta_football = football - ball
</span></span><span style="display:flex;"><span>delta_basketball = basketball - ball
</span></span></code></pre></div><p>如果 TreeHeap 的世界模型有效，那么在某个运动参考系里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>delta_football
</span></span></code></pre></div><p>应该更接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>foot
</span></span><span style="display:flex;"><span>kick
</span></span><span style="display:flex;"><span>field
</span></span><span style="display:flex;"><span>goal
</span></span></code></pre></div><p>而：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>delta_basketball
</span></span></code></pre></div><p>应该更接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>hand
</span></span><span style="display:flex;"><span>throw
</span></span><span style="display:flex;"><span>court
</span></span><span style="display:flex;"><span>basket
</span></span></code></pre></div><p>这就叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>参考系解释。
</span></span></code></pre></div><p>没有参考系，向量差分只是一些数字。<br>
有参考系，差分才变成“这个变化指向哪种世界关系”。</p>
<h2 id="为什么不能只看-raw-cosine">为什么不能只看 raw cosine</h2>
<p>前面的 <code>t_merge</code> 诊断告诉我们一件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>raw cosine 可能会误导。
</span></span></code></pre></div><p>旧 checkpoint 的 final tree output 看起来高度相似：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tree output raw cosine mean ≈ 0.985
</span></span></code></pre></div><p>但减去公共均值之后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>centered cosine mean ≈ 0
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>向量里有一个很强的公共世界背景方向。
</span></span></code></pre></div><p>如果直接拿 raw cosine 判断，就会误以为所有 token 都一样。</p>
<p>所以后面的世界模型实验应该比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0
</span></span><span style="display:flex;"><span>CMul pre-merge
</span></span><span style="display:flex;"><span>merge_no_bias
</span></span><span style="display:flex;"><span>centered tree
</span></span><span style="display:flex;"><span>raw tree
</span></span></code></pre></div><p>不要只看 raw tree。</p>
<h2 id="latent-slot-不是主谓宾">Latent Slot 不是主谓宾</h2>
<p>还有一个必须纠正的点。</p>
<p>前面为了讲清楚，我们经常举：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SUBJECT
</span></span><span style="display:flex;"><span>ROOT
</span></span><span style="display:flex;"><span>OBJECT
</span></span></code></pre></div><p>但这只是临时解释用的 proxy。</p>
<p>TreeHeap 最终不应该直接规定：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>slot_0 = SUBJECT
</span></span><span style="display:flex;"><span>slot_1 = OBJECT
</span></span></code></pre></div><p>更合理的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先从数据里无监督或弱监督学出 latent slots。
</span></span><span style="display:flex;"><span>然后再观察这些 slot 和人类语法标签有什么关系。
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>slot_3 可能经常表现得像主语。
</span></span><span style="display:flex;"><span>slot_8 可能经常表现得像宾语。
</span></span><span style="display:flex;"><span>slot_12 可能是某种修饰位置。
</span></span></code></pre></div><p>但这些名字应该是事后解释，不是事前规定。</p>
<p>这点很重要。否则我们会把传统语法体系偷偷塞进 TreeHeap，最后得到的不是结构涌现，而是语法标签蒸馏。</p>
<h2 id="概率容器的位置">概率容器的位置</h2>
<p>世界模型不是每一步都要立刻做决定。</p>
<p>比如一个短语可能有多个合理挂接：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Parent A: 0.61
</span></span><span style="display:flex;"><span>Parent B: 0.27
</span></span><span style="display:flex;"><span>Parent C: 0.12
</span></span></code></pre></div><p>旧方式会直接：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>argmax -&gt; Parent A
</span></span></code></pre></div><p>但 TreeHeap 的方向应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先保留这个分布。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ParentContainer {
</span></span><span style="display:flex;"><span>  A: 0.61
</span></span><span style="display:flex;"><span>  B: 0.27
</span></span><span style="display:flex;"><span>  C: 0.12
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>等到后面有更大的世界上下文，比如翻译、生成、执行器，再坍缩。</p>
<p>这和 L0 的多义叠加是同一个思想：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>信息不足时，不要过早拍死。
</span></span></code></pre></div><h2 id="一句话定义">一句话定义</h2>
<p>当前可以先这样定义 TreeHeap：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap = L0 词法基底参与世界模型，
</span></span><span style="display:flex;"><span>生成可被参考系解释、
</span></span><span style="display:flex;"><span>可延迟坍缩的结构状态。
</span></span></code></pre></div><p>展开成管线：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0[token]
</span></span><span style="display:flex;"><span>  -&gt; World Model / Frame
</span></span><span style="display:flex;"><span>  -&gt; Participation Product
</span></span><span style="display:flex;"><span>  -&gt; Token-in-World State
</span></span><span style="display:flex;"><span>  -&gt; Latent Slots / Probability Containers
</span></span><span style="display:flex;"><span>  -&gt; Collapse when enough context exists
</span></span></code></pre></div><h2 id="接下来怎么提-predict">接下来怎么提 predict</h2>
<p>这篇先统一术语，下一篇再正式写 ARA <code>/logic</code> 里的 predict。</p>
<p>但方向已经很明确：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-FRAME01:
</span></span><span style="display:flex;"><span>如果 TreeHeap 的世界模型携带真实拓扑信息，
</span></span><span style="display:flex;"><span>那么复合概念的差分方向，
</span></span><span style="display:flex;"><span>应该能在某些局部参考系里投影到可解释关系。
</span></span></code></pre></div><p>例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football - ball -&gt; foot / kick / field / goal
</span></span><span style="display:flex;"><span>basketball - ball -&gt; hand / throw / court / basket
</span></span><span style="display:flex;"><span>baseball - ball -&gt; bat / field
</span></span><span style="display:flex;"><span>volleyball - ball -&gt; hand / net
</span></span></code></pre></div><p>这个 predict 还不能算 evidence。<br>
它只是下一轮实验的逻辑起点。</p>
<p>下一步要把它写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/logic/predicts.md
</span></span></code></pre></div><p>再设计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/src/frame_probe.py
</span></span></code></pre></div><p>最后把结果放进：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/evidence/frame_probe/
</span></span></code></pre></div><p>这才符合 ARA。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-010] 世界模型守夜训练：新 checkpoint 给了什么证据</title>
      <link>https://www.grepcode.cn/spr/010-world-model-night-run.html</link>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/010-world-model-night-run.html</guid>
      <description>用 ARA 方式记录一次 10 小时 TreeHeap world-model 守夜训练：它证明了什么，没有证明什么，下一步 predict 应该怎么改。</description>
      <content:encoded><![CDATA[<h1 id="世界模型守夜训练新-checkpoint-给了什么证据">世界模型守夜训练：新 checkpoint 给了什么证据</h1>
<p>上一篇文章统一了术语：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0 词法基底
</span></span><span style="display:flex;"><span>World Model 世界模型
</span></span><span style="display:flex;"><span>Participation Product 参与乘积
</span></span><span style="display:flex;"><span>t_merge 读出层
</span></span><span style="display:flex;"><span>Frame of Reference 参考系
</span></span><span style="display:flex;"><span>Latent Slot 潜在槽位
</span></span><span style="display:flex;"><span>Probability Container 概率容器
</span></span></code></pre></div><p>统一术语以后，下一步不能继续只靠聊天里的直觉。
按照 ARA 的正规流程，我们需要先写一个可以失败的 predict，然后跑实验。</p>
<p>这次守夜任务就是围绕这个 predict 做的。</p>
<h2 id="先说结论">先说结论</h2>
<p>这次实验是一次<strong>有效的诊断证据</strong>，但不是 TreeHeap 世界模型成立的正证明。</p>
<p>结论分三层：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 工程上：
</span></span><span style="display:flex;"><span>   新 checkpoint 训练成功，GPU 稳定，evidence 已保存。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>2. 几何上：
</span></span><span style="display:flex;"><span>   新训练没有复现旧 checkpoint 那种 raw cosine 全部挤在一起的严重坍缩。
</span></span><span style="display:flex;"><span>   t_merge 没有把空间直接压坏。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>3. 理论上：
</span></span><span style="display:flex;"><span>   当前 local BPE context 训练目标没有证明 P-FRAME01。
</span></span><span style="display:flex;"><span>   也就是说，仅靠“预测附近 token”不足以学出我们想要的世界模型参考系。
</span></span></code></pre></div><p>如果只用一句话说：</p>
<blockquote>
<p>这次实验说明，TreeHeap 的工程管线能跑，空间没有被 t_merge 直接毁掉；但世界模型拓扑信号还没有被当前 objective 学出来。</p></blockquote>
<p>这很重要，因为它把问题从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 是不是彻底错了？
</span></span></code></pre></div><p>缩小成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们现在的训练目标是不是不对？
</span></span></code></pre></div><p>我现在更倾向后者。</p>
<h2 id="这次-predict-是什么">这次 predict 是什么</h2>
<p>我们写下的 predict 叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-FRAME01
</span></span></code></pre></div><p>它的意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap 的世界模型携带真实拓扑信息，
</span></span><span style="display:flex;"><span>那么复合概念相对基础概念的差分方向，
</span></span><span style="display:flex;"><span>应该能在某些局部参考系里投影到可解释关系。
</span></span></code></pre></div><p>用本科生能理解的例子说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football - ball
</span></span></code></pre></div><p>应该更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>foot
</span></span><span style="display:flex;"><span>kick
</span></span><span style="display:flex;"><span>field
</span></span><span style="display:flex;"><span>goal
</span></span></code></pre></div><p>而：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>basketball - ball
</span></span></code></pre></div><p>应该更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>hand
</span></span><span style="display:flex;"><span>throw
</span></span><span style="display:flex;"><span>court
</span></span><span style="display:flex;"><span>basket
</span></span></code></pre></div><p>这不是在问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football 和 basketball 像不像？
</span></span></code></pre></div><p>而是在问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football 比 ball 多出来的那一部分，指向什么世界关系？
</span></span></code></pre></div><p>如果向量空间真的带有“世界模型”，那么这种差分方向应该不是随机的。</p>
<h2 id="为什么要训新-checkpoint">为什么要训新 checkpoint</h2>
<p>之前我们一直有一个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>旧 checkpoint 能不能当证据？
</span></span></code></pre></div><p>答案是：不能直接背书。</p>
<p>旧 checkpoint 可以作为诊断对象，因为它告诉我们：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>raw tree output cosine mean ≈ 0.985
</span></span></code></pre></div><p>看起来所有 token 都很像。</p>
<p>但进一步诊断又发现：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>centered cosine mean ≈ 0
</span></span></code></pre></div><p>也就是说，它可能不是所有信息都没了，而是有一个很强的公共背景方向。</p>
<p>所以旧 checkpoint 不能直接证明 TreeHeap 成立，也不能直接证明 TreeHeap 失败。
它只能告诉我们：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>必须自己训一个新的 checkpoint，
</span></span><span style="display:flex;"><span>再看 CMul、merge_no_bias、tree、centered tree 到底发生了什么。
</span></span></code></pre></div><p>这次守夜任务就是为了补这一块 evidence。</p>
<h2 id="训练任务怎么设计">训练任务怎么设计</h2>
<p>这次没有训练完整翻译模型，也没有训练大语言模型。</p>
<p>我们训练的是一个小的 TreeHeap-style world-model checkpoint。</p>
<p>核心形式是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0(token)
</span></span><span style="display:flex;"><span>  x WorldPath(token)
</span></span><span style="display:flex;"><span>  -&gt; CMul pre-merge state
</span></span><span style="display:flex;"><span>  -&gt; t_merge
</span></span><span style="display:flex;"><span>  -&gt; token-in-world vector
</span></span></code></pre></div><p>训练目标很朴素：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定一个中心 BPE token，
</span></span><span style="display:flex;"><span>让它的 token-in-world vector 去找附近窗口里的真实 context token。
</span></span></code></pre></div><p>也就是 local context contrastive learning。</p>
<p>用更普通的话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果一个 token 经常和某些上下文一起出现，
</span></span><span style="display:flex;"><span>模型应该把它变换到一个能找回这些上下文的位置。
</span></span></code></pre></div><p>这不是最终目标。
它只是一个可运行、可保存 checkpoint、可观察 t_merge 是否扭曲空间的中间实验。</p>
<h2 id="守夜运行规模">守夜运行规模</h2>
<p>运行时间：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>start:  2026-06-17 18:05:58
</span></span><span style="display:flex;"><span>finish: 2026-06-18 04:06:01
</span></span></code></pre></div><p>训练规模：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>epochs recorded: 456
</span></span><span style="display:flex;"><span>global steps:    2,732,508
</span></span><span style="display:flex;"><span>checkpoints:     456
</span></span><span style="display:flex;"><span>metrics rows:    456
</span></span><span style="display:flex;"><span>frame rows:      2,280
</span></span><span style="display:flex;"><span>geometry rows:   2,280
</span></span><span style="display:flex;"><span>gpu rows:        54,650
</span></span></code></pre></div><p>证据保存位置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/data/homecicd/sametime/ara/s2-translation/evidence/world_model_long_20260617_180554
</span></span><span style="display:flex;"><span>/mnt/nas/datasets/wmt_massive/evidence_nio/world_model_long_20260617_180554
</span></span></code></pre></div><p>这次也顺便验证了一个工程点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>io 上的 RTX 3090 是可跑长任务的，
</span></span><span style="display:flex;"><span>但必须保持 270W power limit，
</span></span><span style="display:flex;"><span>不能放开。
</span></span></code></pre></div><p>GPU 统计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>avg power: 192.18W
</span></span><span style="display:flex;"><span>max power: 195.92W
</span></span><span style="display:flex;"><span>avg temp:  70.82C
</span></span><span style="display:flex;"><span>max temp:  71C
</span></span><span style="display:flex;"><span>avg util:  29.07%
</span></span><span style="display:flex;"><span>max util:  32%
</span></span><span style="display:flex;"><span>max mem:   688MiB
</span></span></code></pre></div><p>这说明这次不是之前那种 CPU-only 假任务。
GPU 确实在工作，而且没有掉卡。</p>
<h2 id="训练有没有学到东西">训练有没有学到东西</h2>
<p>训练 loss 有下降，但幅度不大。</p>
<p>第一轮：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss        7.5148
</span></span><span style="display:flex;"><span>inbatch_acc 0.0181
</span></span></code></pre></div><p>最后一轮：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss        7.2923
</span></span><span style="display:flex;"><span>inbatch_acc 0.0247
</span></span></code></pre></div><p>最好 loss：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>epoch 456
</span></span><span style="display:flex;"><span>loss  7.2923
</span></span></code></pre></div><p>最好 in-batch accuracy：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>epoch       442
</span></span><span style="display:flex;"><span>inbatch_acc 0.0248
</span></span></code></pre></div><p>这说明模型确实在学 local context。
但它学得并不强。</p>
<p>从工程上看，这是一个健康训练。
从理论上看，这还不能说明它学出了世界模型。</p>
<h2 id="frame-probe-结果">frame probe 结果</h2>
<p>我们真正关心的是 P-FRAME01。</p>
<p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>composite - base
</span></span></code></pre></div><p>能不能指向正确的 relation anchors。</p>
<p>这次最好的早期结果出现在 epoch 2：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>epoch 2
</span></span><span style="display:flex;"><span>mode: tree / merge_no_bias
</span></span><span style="display:flex;"><span>auc  0.7236
</span></span><span style="display:flex;"><span>mrr  0.8485
</span></span><span style="display:flex;"><span>hit1 0.7273
</span></span><span style="display:flex;"><span>hit3 1.0000
</span></span></code></pre></div><p>但是到最后一轮，结果没有继续变强。</p>
<p>epoch 456：</p>
<table>
  <thead>
      <tr>
          <th>mode</th>
          <th style="text-align: right">AUC</th>
          <th style="text-align: right">MRR</th>
          <th style="text-align: right">Hit@1</th>
          <th style="text-align: right">Hit@3</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>L0</td>
          <td style="text-align: right">0.6182</td>
          <td style="text-align: right">0.8364</td>
          <td style="text-align: right">0.7273</td>
          <td style="text-align: right">0.9091</td>
      </tr>
      <tr>
          <td>CMul</td>
          <td style="text-align: right">0.6182</td>
          <td style="text-align: right">0.8182</td>
          <td style="text-align: right">0.6364</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>merge_no_bias</td>
          <td style="text-align: right">0.6473</td>
          <td style="text-align: right">0.8333</td>
          <td style="text-align: right">0.7273</td>
          <td style="text-align: right">0.9091</td>
      </tr>
      <tr>
          <td>tree</td>
          <td style="text-align: right">0.6473</td>
          <td style="text-align: right">0.8333</td>
          <td style="text-align: right">0.7273</td>
          <td style="text-align: right">0.9091</td>
      </tr>
      <tr>
          <td>path</td>
          <td style="text-align: right">0.5618</td>
          <td style="text-align: right">0.8712</td>
          <td style="text-align: right">0.8182</td>
          <td style="text-align: right">0.9091</td>
      </tr>
  </tbody>
</table>
<p>这里要小心读。</p>
<p>如果 TreeHeap world model 被证明了，我们希望看到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tree / merge_no_bias / CMul 明显强于 L0
</span></span><span style="display:flex;"><span>并且随着训练稳定变强
</span></span></code></pre></div><p>但实际看到的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. early epoch 有一点信号。
</span></span><span style="display:flex;"><span>2. long training 没有把这个信号放大。
</span></span><span style="display:flex;"><span>3. path 的 Hit@1/MRR 也很高，说明 probe 里可能有 token/path 偏差。
</span></span><span style="display:flex;"><span>4. final tree 只比 L0 在 AUC 上略好，不构成强证据。
</span></span></code></pre></div><p>所以 P-FRAME01 的状态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>inconclusive
</span></span></code></pre></div><p>不能升级为 positive claim。</p>
<h2 id="几何空间有没有坍缩">几何空间有没有坍缩</h2>
<p>这部分反而比较有价值。</p>
<p>最后一轮的 off-diagonal cosine mean：</p>
<table>
  <thead>
      <tr>
          <th>mode</th>
          <th style="text-align: right">cosine mean</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>L0</td>
          <td style="text-align: right">0.0519</td>
      </tr>
      <tr>
          <td>CMul</td>
          <td style="text-align: right">0.0539</td>
      </tr>
      <tr>
          <td>merge_no_bias</td>
          <td style="text-align: right">0.0566</td>
      </tr>
      <tr>
          <td>tree</td>
          <td style="text-align: right">0.0865</td>
      </tr>
      <tr>
          <td>path</td>
          <td style="text-align: right">0.9973</td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0 / CMul / merge_no_bias / tree 都没有全局挤成同一个方向。
</span></span></code></pre></div><p>tree 的 cosine mean 比 L0 高一点，但远没有旧 checkpoint 那种：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.985
</span></span></code></pre></div><p>这支持一个判断：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>t_merge 本身不是必然把空间压坏的罪魁祸首。
</span></span></code></pre></div><p>真正异常的是 path：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>path cosine mean = 0.9973
</span></span></code></pre></div><p>这说明当前 path 构造在这个 probe 集合上几乎是常量。
也就是说，它不是一个好的语义参考系。</p>
<p>这和我们之前的判断一致：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径本身更多编码 token ID / 分桶位置，
</span></span><span style="display:flex;"><span>不是语法角色，也不是世界关系。
</span></span></code></pre></div><h2 id="这次到底证明了什么">这次到底证明了什么</h2>
<p>可以保留的结论：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 新 checkpoint 能稳定训练。
</span></span><span style="display:flex;"><span>2. io 的 3090 在 270W limit 下可以跑 10 小时任务。
</span></span><span style="display:flex;"><span>3. t_merge 不必然导致全局向量坍缩。
</span></span><span style="display:flex;"><span>4. local BPE-context objective 可以学到一点上下文检索能力。
</span></span><span style="display:flex;"><span>5. 当前训练目标没有证明 world-model reference frame。
</span></span></code></pre></div><p>必须降级的说法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经学出世界模型。
</span></span></code></pre></div><p>这句话不能说。</p>
<p>更准确的说法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 现在有一个可训练的世界模型候选管线，
</span></span><span style="display:flex;"><span>但 local context objective 还不能让 P-FRAME01 成立。
</span></span></code></pre></div><h2 id="下一步怎么改-predict">下一步怎么改 predict</h2>
<p>这次最重要的教训是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不要只让模型预测附近 token。
</span></span></code></pre></div><p>因为附近 token 主要教会模型：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>哪些词经常共现。
</span></span></code></pre></div><p>但我们想要的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>复合概念和基础概念之间的关系方向。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football - ball -&gt; foot / kick / field / goal
</span></span><span style="display:flex;"><span>basketball - ball -&gt; hand / throw / court / basket
</span></span></code></pre></div><p>所以 P-FRAME01 下一版应该改成更直接的训练目标。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：
</span></span><span style="display:flex;"><span>  composite
</span></span><span style="display:flex;"><span>  base
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>目标：
</span></span><span style="display:flex;"><span>  拉近 positive relation anchors
</span></span><span style="display:flex;"><span>  推远 hard negative anchors
</span></span></code></pre></div><p>形式上可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>delta = vector(composite) - vector(base)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>positive:
</span></span><span style="display:flex;"><span>  foot, kick, field, goal
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>negative:
</span></span><span style="display:flex;"><span>  hand, basket, racket, engine, snow
</span></span></code></pre></div><p>训练目标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>delta 更接近 positive anchor directions
</span></span><span style="display:flex;"><span>delta 远离 negative anchor directions
</span></span></code></pre></div><p>这比 local context objective 更贴近我们真正要验证的 claim。</p>
<h2 id="ara-状态">ARA 状态</h2>
<p>这次 evidence 应该这样登记：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Predict:
</span></span><span style="display:flex;"><span>  P-FRAME01
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Evidence:
</span></span><span style="display:flex;"><span>  world_model_long_20260617_180554
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Verdict:
</span></span><span style="display:flex;"><span>  diagnostic / inconclusive
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Do not promote to claim.
</span></span></code></pre></div><p>换句话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-FRAME01 还活着，
</span></span><span style="display:flex;"><span>但当前 objective 没有通过 evidence gate。
</span></span></code></pre></div><p>这不是坏结果。
一个好的研究系统，应该允许 predict 被证据卡住。</p>
<h2 id="最后一句话">最后一句话</h2>
<p>这次守夜训练没有证明 TreeHeap 已经拥有世界模型。</p>
<p>它证明的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们已经有能力正规地训练、保存、诊断一个新的 TreeHeap checkpoint；
</span></span><span style="display:flex;"><span>也已经知道 local context objective 不是通向 P-FRAME01 的直路。
</span></span></code></pre></div><p>下一步不是继续堆时间。</p>
<p>下一步是换 objective。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-011] TreeHeap 代数：先做数学闭包，再谈语言推理</title>
      <link>https://www.grepcode.cn/spr/011-treeheap-algebra.html</link>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/011-treeheap-algebra.html</guid>
      <description>把 TreeHeap 从一个乘法向量层推进成代数系统：定义闭包、转置、逆树堆、投影、能量和概率容器。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-代数先做数学闭包再谈语言推理">TreeHeap 代数：先做数学闭包，再谈语言推理</h1>
<p>前一篇守夜训练给了一个重要教训：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只靠 local BPE context objective，
</span></span><span style="display:flex;"><span>不能证明 TreeHeap 学出了世界模型。
</span></span></code></pre></div><p>这不只是 loss 设计问题。
更深一层的问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 现在还不像一个完整的数学系统。
</span></span></code></pre></div><p>目前我们实现得最多的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0(token) x path/world -&gt; CMul -&gt; t_merge
</span></span></code></pre></div><p>这相当于只有一个核心参与乘积。</p>
<p>它可以保存信息，可以调制方向，也可以让 token 带上 path 背景。
但它不一定能完成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>转置
</span></span><span style="display:flex;"><span>求逆
</span></span><span style="display:flex;"><span>分解
</span></span><span style="display:flex;"><span>投影
</span></span><span style="display:flex;"><span>组合
</span></span><span style="display:flex;"><span>能量排序
</span></span><span style="display:flex;"><span>概率坍缩
</span></span></code></pre></div><p>如果这些操作都没有定义，TreeHeap 就还不是一个“堆数据结构”。
它只是一个带名字的向量变换层。</p>
<p>所以这篇文章先不谈 WMT，也不谈 BLEU。
我们先退一步：</p>
<blockquote>
<p>TreeHeap 能不能先成为一个可计算的代数系统？</p></blockquote>
<h2 id="为什么先做代数">为什么先做代数</h2>
<p>语言推理是上层问题。</p>
<p>比如翻译：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>中文结构 -&gt; 英文结构 -&gt; 英文表面句子
</span></span></code></pre></div><p>这里面当然有语义、语法、文化和世界知识。
但在 TreeHeap 视角下，它首先需要一些更基本的能力：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个结构能不能合成？
</span></span><span style="display:flex;"><span>合成后能不能分解？
</span></span><span style="display:flex;"><span>一条关系能不能反过来看？
</span></span><span style="display:flex;"><span>一个对象能不能投影到某个参考系？
</span></span><span style="display:flex;"><span>投影后能不能回来？
</span></span><span style="display:flex;"><span>一组候选结构能不能排序？
</span></span><span style="display:flex;"><span>不确定时能不能先保留概率？
</span></span></code></pre></div><p>这些不是语言专属问题。
这些是数学操作问题。</p>
<p>如果这些操作不稳定，那么后面说“世界模型”“推理”“翻译”都太早。</p>
<p>这就是这篇文章的核心判断：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先建立 TreeHeap Algebra。
</span></span><span style="display:flex;"><span>再把语言推理放到这个代数系统上。
</span></span></code></pre></div><h2 id="什么叫数学闭包">什么叫数学闭包</h2>
<p>本科计算机里经常会见到“闭包”这个词。</p>
<p>例如整数加法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>整数 + 整数 = 整数
</span></span></code></pre></div><p>所以整数对加法是封闭的。</p>
<p>但：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>整数 / 整数 = 不一定是整数
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 / 2 = 0.5
</span></span></code></pre></div><p>所以整数对除法不封闭。</p>
<p>放到 TreeHeap 里，我们想要的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap object op TreeHeap object -&gt; TreeHeap object
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>两个 TreeHeap 对象做完操作，
</span></span><span style="display:flex;"><span>结果还应该是一个 TreeHeap 对象。
</span></span></code></pre></div><p>如果每次操作完都跑出空间，只能交给神经网络硬猜，那数学结构就没有帮上忙。</p>
<h2 id="treeheap-对象是什么">TreeHeap 对象是什么</h2>
<p>先定义一个最小对象：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = (v, p, s, q)
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>v: semantic/world vector
</span></span><span style="display:flex;"><span>p: heap path or structural coordinate
</span></span><span style="display:flex;"><span>s: latent slot distribution
</span></span><span style="display:flex;"><span>q: probability mass / confidence
</span></span></code></pre></div><p>口语一点说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>v 是“它是什么”
</span></span><span style="display:flex;"><span>p 是“它在堆里的位置”
</span></span><span style="display:flex;"><span>s 是“它像在哪些潜在槽位上”
</span></span><span style="display:flex;"><span>q 是“我们对它有多确定”
</span></span></code></pre></div><p>这比一个裸向量多一点结构。</p>
<p>TreeHeap 不应该只保存：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>128D vector
</span></span></code></pre></div><p>它应该保存：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>向量 + 结构坐标 + 槽位分布 + 概率质量
</span></span></code></pre></div><p>这才像一个高维堆对象。</p>
<h2 id="操作一compose-合成">操作一：compose 合成</h2>
<p>compose 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose(H1, H2, ..., Hn) -&gt; H_parent
</span></span></code></pre></div><p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>多个 child heap objects 合成一个 parent heap object。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>foot + ball -&gt; football
</span></span></code></pre></div><p>或者在句子结构里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kick + ball + goal -&gt; event/state
</span></span></code></pre></div><p>关键不是简单加法。
compose 应该同时更新：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>v: 世界状态变了
</span></span><span style="display:flex;"><span>p: 结构位置变了
</span></span><span style="display:flex;"><span>s: 槽位分布变了
</span></span><span style="display:flex;"><span>q: 置信度变了
</span></span></code></pre></div><p>如果 compose 只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>v_parent = v1 + v2
</span></span></code></pre></div><p>那它太弱。</p>
<h2 id="操作二decompose-分解也就是逆树堆">操作二：decompose 分解，也就是逆树堆</h2>
<p>如果有合成，就自然会问有没有逆操作。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose(children) -&gt; parent
</span></span></code></pre></div><p>反过来：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>decompose(parent) -&gt; children
</span></span></code></pre></div><p>这就是“逆树堆”的直觉。</p>
<p>但是语言里一般没有唯一逆。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football
</span></span></code></pre></div><p>可以拆成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>foot + ball
</span></span><span style="display:flex;"><span>sport + ball
</span></span><span style="display:flex;"><span>game + object
</span></span></code></pre></div><p>所以 decompose 不应该返回一个硬答案。</p>
<p>它应该返回概率容器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  foot + ball:    0.52
</span></span><span style="display:flex;"><span>  sport + ball:   0.31
</span></span><span style="display:flex;"><span>  game + object:  0.17
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这和之前说的 Probability Container 是同一个思想。</p>
<p>逆树堆不是普通函数逆。
更准确地说，它是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>probabilistic inverse
</span></span></code></pre></div><h2 id="操作三transpose-转置">操作三：transpose 转置</h2>
<p>矩阵里有转置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A -&gt; A^T
</span></span></code></pre></div><p>TreeHeap 里也需要类似操作，但含义不是把二维表格翻过来。</p>
<p>TreeHeap 的转置更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>关系方向反转
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>edge(parent, child, role)
</span></span></code></pre></div><p>转置后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>edge(child, parent, inverse_role)
</span></span></code></pre></div><p>它应该满足一个基本性质：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>transpose(transpose(edge)) ≈ edge
</span></span></code></pre></div><p>也就是转两次应该差不多回来。</p>
<p>为什么这对翻译重要？</p>
<p>因为不同语言经常从不同方向表达同一关系。</p>
<p>例如中文和英文的修饰、介词、话题结构，方向可能不一样。
如果 TreeHeap 没有 transpose，就很难用数学操作表达：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一个关系，换一个方向读。
</span></span></code></pre></div><h2 id="操作四project-投影到参考系">操作四：project 投影到参考系</h2>
<p>我们一直说世界模型和参考系。</p>
<p>project 就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>project(H, frame) -&gt; H_frame
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>project(ball, sport_frame)
</span></span></code></pre></div><p>和：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>project(ball, kitchen_frame)
</span></span></code></pre></div><p>应该不一样。</p>
<p>同一个对象进入不同参考系，解释方向不同。</p>
<p>这对应前面的例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football - ball -&gt; foot / kick / field / goal
</span></span><span style="display:flex;"><span>basketball - ball -&gt; hand / throw / court / basket
</span></span></code></pre></div><p>如果没有 project，向量差分只是数字。
有了 project，差分才变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个变化在什么世界里被解释？
</span></span></code></pre></div><h2 id="操作五unproject-反投影">操作五：unproject 反投影</h2>
<p>如果能投影，就要问能不能回来：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>unproject(project(H, frame), frame) ≈ H
</span></span></code></pre></div><p>这叫 projection roundtrip。</p>
<p>如果做不到，说明投影丢了太多信息。</p>
<p>但也不能完全不变。
如果 project/unproject 只是 identity echo，那也没意义。</p>
<p>所以它要同时满足两个条件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. roundtrip 后能大致回到原对象。
</span></span><span style="display:flex;"><span>2. 在 frame 内部确实改变了可解释方向。
</span></span></code></pre></div><p>这就是难点。</p>
<h2 id="操作六energy-能量">操作六：energy 能量</h2>
<p>energy 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>energy(H) -&gt; scalar
</span></span></code></pre></div><p>它给 TreeHeap 对象打一个一致性分数。</p>
<p>低能量表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个对象更像一个合法结构。
</span></span></code></pre></div><p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose(foot, ball)
</span></span></code></pre></div><p>应该比：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose(engine, snow)
</span></span></code></pre></div><p>在 sport-ball frame 下能量更低。</p>
<p>但注意，energy 不是“真理”。
它只是排序工具。</p>
<h2 id="最小-predictp-alg01">最小 predict：P-ALG01</h2>
<p>现在可以写一个新的 predict：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-ALG01:
</span></span><span style="display:flex;"><span>如果 TreeHeap 是可用的数学底座，
</span></span><span style="display:flex;"><span>那么 compose、decompose、transpose、project、unproject、energy
</span></span><span style="display:flex;"><span>这些操作应该在 TreeHeap 对象空间内近似封闭。
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>操作前是 TreeHeap 对象。
</span></span><span style="display:flex;"><span>操作后仍然是 TreeHeap 对象。
</span></span></code></pre></div><p>而不是变成一堆无法解释的向量碎片。</p>
<h2 id="怎么实验">怎么实验</h2>
<p>先不要跑 WMT。</p>
<p>先跑四个数学实验。</p>
<h3 id="e-alg01-composedecompose-往返">E-ALG01: compose/decompose 往返</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>children -&gt; compose -&gt; parent -&gt; decompose -&gt; children&#39;
</span></span></code></pre></div><p>看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>children&#39; 能不能在 top-k 里找回原 children。
</span></span></code></pre></div><p>失败标准：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>找回率不超过 random / nearest baseline。
</span></span></code></pre></div><h3 id="e-alg02-transpose-两次回来">E-ALG02: transpose 两次回来</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>edge -&gt; transpose -&gt; transpose -&gt; edge&#39;
</span></span></code></pre></div><p>看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>edge&#39; 是否接近原 edge。
</span></span></code></pre></div><p>失败标准：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>转置两次还不如不转。
</span></span></code></pre></div><h3 id="e-alg03-projectunproject-往返">E-ALG03: project/unproject 往返</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H -&gt; project(frame) -&gt; unproject(frame) -&gt; H&#39;
</span></span></code></pre></div><p>看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H&#39; 是否接近 H。
</span></span></code></pre></div><p>同时还要看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>project 后是否真的提升 frame 内 relation ranking。
</span></span></code></pre></div><p>否则就是 echo。</p>
<h3 id="e-alg04-闭包压力测试">E-ALG04: 闭包压力测试</h3>
<p>反复做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose
</span></span><span style="display:flex;"><span>project
</span></span><span style="display:flex;"><span>transpose
</span></span><span style="display:flex;"><span>decompose
</span></span><span style="display:flex;"><span>normalize
</span></span></code></pre></div><p>看有没有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>norm explosion
</span></span><span style="display:flex;"><span>global cosine collapse
</span></span><span style="display:flex;"><span>energy drift
</span></span><span style="display:flex;"><span>probability mass invalid
</span></span></code></pre></div><p>如果反复操作几轮就炸掉，那 TreeHeap 还不是稳定代数。</p>
<h2 id="和-wmt-的关系">和 WMT 的关系</h2>
<p>这一步看起来远离翻译，其实是在给翻译铺地基。</p>
<p>如果 TreeHeap Algebra 成立，S2 翻译可以变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>source TreeHeap
</span></span><span style="display:flex;"><span>-&gt; transpose / project
</span></span><span style="display:flex;"><span>-&gt; target frame TreeHeap
</span></span><span style="display:flex;"><span>-&gt; decompose / collapse
</span></span><span style="display:flex;"><span>-&gt; target sentence
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用数学操作迁移结构，
</span></span><span style="display:flex;"><span>再用模型生成表面语言。
</span></span></code></pre></div><p>否则就只能回到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>source tokens -&gt; black-box decoder -&gt; target tokens
</span></span></code></pre></div><p>那 TreeHeap 的意义就不明显。</p>
<h2 id="当前架构判断">当前架构判断</h2>
<p>现在可以把之前的判断整理成三句话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Echo preserves information.
</span></span><span style="display:flex;"><span>CMul carries participation.
</span></span><span style="display:flex;"><span>World model requires algebraic topology operations.
</span></span></code></pre></div><p>中文就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Echo 保存信息。
</span></span><span style="display:flex;"><span>CMul 携带参与关系。
</span></span><span style="display:flex;"><span>世界模型需要代数拓扑操作。
</span></span></code></pre></div><p>所以接下来不是继续加大 local context 训练。</p>
<p>下一步是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先设计 TreeHeap Algebra。
</span></span><span style="display:flex;"><span>再训练模型学习这个代数里的未知映射。
</span></span></code></pre></div><h2 id="ara-状态">ARA 状态</h2>
<p>新增 predict：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-ALG01
</span></span></code></pre></div><p>新增设计文档：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s2-translation/logic/solution/treeheap_algebra.md
</span></span></code></pre></div><p>下一步 planned evidence：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s2-translation/src/treeheap_algebra_probe.py
</span></span><span style="display:flex;"><span>ara/s2-translation/evidence/treeheap_algebra_probe/
</span></span></code></pre></div><p>状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Design phase.
</span></span></code></pre></div><p>还没有 claim。</p>
<h2 id="最后一句话">最后一句话</h2>
<p>TreeHeap 不应该只是一个乘法层。</p>
<p>它应该先成为一个能做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>合成
</span></span><span style="display:flex;"><span>分解
</span></span><span style="display:flex;"><span>转置
</span></span><span style="display:flex;"><span>投影
</span></span><span style="display:flex;"><span>反投影
</span></span><span style="display:flex;"><span>能量排序
</span></span><span style="display:flex;"><span>概率保留
</span></span></code></pre></div><p>的高维堆代数系统。</p>
<p>语言推理不是第一层。</p>
<p>语言推理是这个代数系统上的应用。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-012] 子堆核搜索：TreeHeap 里的卷积式推理</title>
      <link>https://www.grepcode.cn/spr/012-subheap-kernel-search.html</link>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/012-subheap-kernel-search.html</guid>
      <description>把矩阵卷积里的局部核匹配，改写成 TreeHeap 的 SubHeap Kernel Search：一种拓扑搜索和局部推理操作。</description>
      <content:encoded><![CDATA[<h1 id="子堆核搜索treeheap-里的卷积式推理">子堆核搜索：TreeHeap 里的卷积式推理</h1>
<p>上一篇文章讲了 TreeHeap Algebra：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose
</span></span><span style="display:flex;"><span>decompose
</span></span><span style="display:flex;"><span>transpose
</span></span><span style="display:flex;"><span>project
</span></span><span style="display:flex;"><span>unproject
</span></span><span style="display:flex;"><span>energy
</span></span><span style="display:flex;"><span>probability container
</span></span></code></pre></div><p>但这里还少了一个很重要的操作。</p>
<p>用户提出了一个矩阵卷积的类比：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 0 1
</span></span><span style="display:flex;"><span>0 1 0
</span></span><span style="display:flex;"><span>1 0 1
</span></span></code></pre></div><p>如果我们有这样一个卷积核，就可以在一张矩阵或图像上滑动它。
哪里局部模式相同，哪里就会有高响应。</p>
<p>这件事表面上是卷积。</p>
<p>但本质上是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用一个局部模式，在大结构里搜索对应部分。
</span></span></code></pre></div><p>这已经很接近推理。</p>
<p>因为推理很多时候不是“生成一个 token”，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在当前结构里找到一个已知模式。
</span></span></code></pre></div><p>所以这篇文章把这个操作整理成 TreeHeap 的新代数操作：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SubHeap Kernel Search
</span></span></code></pre></div><p>中文可以叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>子堆核搜索
</span></span></code></pre></div><p>对应的公开实验仓：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>https://github.com/houming818/sametime
</span></span></code></pre></div><p>其中 ARA 记录入口是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s2-translation/logic/predicts.md
</span></span><span style="display:flex;"><span>ara/s2-translation/logic/solution/treeheap_algebra.md
</span></span><span style="display:flex;"><span>ara/s2-translation/trace/research_dag.yaml
</span></span></code></pre></div><h2 id="当前-treeheap-没有这个操作">当前 TreeHeap 没有这个操作</h2>
<p>先说清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前实现里还没有子堆核搜索。
</span></span></code></pre></div><p>现在实现更多是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0(token)
</span></span><span style="display:flex;"><span>  x path/world
</span></span><span style="display:flex;"><span>  -&gt; CMul
</span></span><span style="display:flex;"><span>  -&gt; t_merge
</span></span></code></pre></div><p>这是点级变换。</p>
<p>也就是说，它主要回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个 token 进入某个背景以后，向量怎么变？
</span></span></code></pre></div><p>但子堆核搜索要回答的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>整个 TreeHeap 里，哪里出现了某个局部结构模式？
</span></span></code></pre></div><p>这不是同一类问题。</p>
<p>CMul 像是把一个点放进背景场。</p>
<p>SubHeap Kernel Search 像是在一整个结构里找模式。</p>
<h2 id="图像卷积在做什么">图像卷积在做什么</h2>
<p>先用图像理解。</p>
<p>假设有一个 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 0 1
</span></span><span style="display:flex;"><span>0 1 0
</span></span><span style="display:flex;"><span>1 0 1
</span></span></code></pre></div><p>它在图像上滑动。</p>
<p>每到一个位置，就问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这里的局部形状像不像这个 kernel？
</span></span></code></pre></div><p>像，就高响应。</p>
<p>不像，就低响应。</p>
<p>这就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>local pattern matching
</span></span></code></pre></div><p>中文可以说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>局部模式匹配
</span></span></code></pre></div><h2 id="线性秩序和取模周期">线性秩序和取模周期</h2>
<p>这里还有一个更底层的理解。</p>
<p>矩阵卷积不一定要先被看成神秘的二维图像操作。</p>
<p>它也可以被看成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>线性秩序
</span></span><span style="display:flex;"><span>+ 局部窗口
</span></span><span style="display:flex;"><span>+ 取模位移
</span></span><span style="display:flex;"><span>+ 同一个 kernel 的重复作用
</span></span></code></pre></div><p>例如一个一维序列：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x[0], x[1], x[2], ..., x[n-1]
</span></span></code></pre></div><p>如果使用周期边界，那么位置可以这样移动：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>i + 1 mod n
</span></span><span style="display:flex;"><span>i - 1 mod n
</span></span></code></pre></div><p>这就形成了一个循环结构。</p>
<p>二维矩阵也可以被展平成一维地址：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>index = row * width + col
</span></span></code></pre></div><p>然后用固定偏移找邻居：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left  = index - 1
</span></span><span style="display:flex;"><span>right = index + 1
</span></span><span style="display:flex;"><span>up    = index - width
</span></span><span style="display:flex;"><span>down  = index + width
</span></span></code></pre></div><p>如果加上边界取模：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>row = row mod height
</span></span><span style="display:flex;"><span>col = col mod width
</span></span></code></pre></div><p>就得到一个周期性空间。</p>
<p>所以卷积的核心可以说是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在一个有秩序的地址空间里，
</span></span><span style="display:flex;"><span>用固定偏移定义邻域，
</span></span><span style="display:flex;"><span>再用同一个 kernel 反复测试局部模式。
</span></span></code></pre></div><p>这对 TreeHeap 很重要。</p>
<p>因为它提醒我们：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 不是一上来就必须是复杂语法树。
</span></span></code></pre></div><p>它可以先从更基础的东西开始：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap traversal order
</span></span><span style="display:flex;"><span>+ heap address
</span></span><span style="display:flex;"><span>+ parent/child offset
</span></span><span style="display:flex;"><span>+ sibling offset
</span></span><span style="display:flex;"><span>+ modular or cyclic neighborhood
</span></span></code></pre></div><p>也就是说，TreeHeap 需要先定义自己的“地址代数”。</p>
<p>矩阵里有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>(row, col)
</span></span></code></pre></div><p>序列里有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>i mod n
</span></span></code></pre></div><p>TreeHeap 里可能需要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>path
</span></span><span style="display:flex;"><span>parent(path)
</span></span><span style="display:flex;"><span>left(path)
</span></span><span style="display:flex;"><span>right(path)
</span></span><span style="display:flex;"><span>sibling(path)
</span></span><span style="display:flex;"><span>next_dfs(path) mod N
</span></span><span style="display:flex;"><span>next_bfs(path) mod N
</span></span></code></pre></div><p>这样 kernel 才知道自己在什么空间里移动。</p>
<p>换句话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>卷积核不是单独成立的。
</span></span><span style="display:flex;"><span>它依赖一个可移动、可取邻域、可重复作用的地址空间。
</span></span></code></pre></div><p>这也把 SubHeap Kernel Search 拆成两个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. TreeHeap 地址空间怎么定义？
</span></span><span style="display:flex;"><span>2. kernel 如何在这个地址空间里做局部匹配？
</span></span></code></pre></div><p>这个拆分很有价值。</p>
<p>因为如果地址空间都没定义好，直接谈复杂的子树匹配，就容易跳太快。</p>
<h2 id="treeheap-里没有规则网格">TreeHeap 里没有规则网格</h2>
<p>TreeHeap 不是二维矩阵。</p>
<p>它更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树
</span></span><span style="display:flex;"><span>堆
</span></span><span style="display:flex;"><span>图
</span></span><span style="display:flex;"><span>槽位结构
</span></span><span style="display:flex;"><span>概率容器
</span></span></code></pre></div><p>所以 kernel 不能像 3x3 那样滑动。</p>
<p>TreeHeap 的 kernel 应该长这样：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K = event {
</span></span><span style="display:flex;"><span>  center: action-like
</span></span><span style="display:flex;"><span>  slot_1: agent-like
</span></span><span style="display:flex;"><span>  slot_2: object-like
</span></span><span style="display:flex;"><span>  slot_3: location-like
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>它不是像素模板。</p>
<p>它是一个局部结构模板。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat_event {
</span></span><span style="display:flex;"><span>  agent = ?
</span></span><span style="display:flex;"><span>  object = ?
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>或者：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>move_event {
</span></span><span style="display:flex;"><span>  mover = ?
</span></span><span style="display:flex;"><span>  source = ?
</span></span><span style="display:flex;"><span>  target = ?
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这就是 SubHeap Kernel。</p>
<h2 id="子堆核搜索怎么定义">子堆核搜索怎么定义</h2>
<p>可以定义一个操作：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>match_subheap(H, K) -&gt; ProbabilityContainer[SubHeap]
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = 整个 TreeHeap
</span></span><span style="display:flex;"><span>K = 一个局部子堆核
</span></span></code></pre></div><p>输出不是一个硬位置。</p>
<p>输出应该是概率容器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  subheap_12: 0.71
</span></span><span style="display:flex;"><span>  subheap_4:  0.18
</span></span><span style="display:flex;"><span>  subheap_29: 0.07
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K 最可能匹配 subheap_12，
</span></span><span style="display:flex;"><span>但 subheap_4 和 subheap_29 也有可能。
</span></span></code></pre></div><p>这和 TreeHeap 的概率容器思想一致：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>信息不足时，不要过早 argmax。
</span></span></code></pre></div><h2 id="为什么这是推理搜索">为什么这是推理搜索</h2>
<p>考虑三句话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat eats fish
</span></span><span style="display:flex;"><span>fish is eaten by the cat
</span></span><span style="display:flex;"><span>the cat quickly eats fish
</span></span></code></pre></div><p>表面顺序不同。</p>
<p>但它们共享一个事件结构：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat_event {
</span></span><span style="display:flex;"><span>  agent = cat
</span></span><span style="display:flex;"><span>  object = fish
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>如果我们有一个 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K = action(agent, object)
</span></span></code></pre></div><p>那么它应该在三句话里都找到这个事件。</p>
<p>这就是推理。</p>
<p>因为系统没有只看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat 是否在 eats 左边
</span></span></code></pre></div><p>而是在看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>谁在 action 的 agent 槽位？
</span></span><span style="display:flex;"><span>谁在 object 槽位？
</span></span><span style="display:flex;"><span>这个局部结构是否等价？
</span></span></code></pre></div><p>这就是拓扑搜索。</p>
<h2 id="和普通-attention-有什么不同">和普通 attention 有什么不同</h2>
<p>Transformer attention 可以让 token 互相看。</p>
<p>但 attention 本身不一定显式告诉你：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这里有一个 action(agent, object) kernel 匹配成功。
</span></span></code></pre></div><p>SubHeap Kernel Search 更像显式结构操作：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定一个 kernel，
</span></span><span style="display:flex;"><span>在 TreeHeap 里找对应的子堆。
</span></span></code></pre></div><p>所以它更接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>结构检索
</span></span><span style="display:flex;"><span>图模式匹配
</span></span><span style="display:flex;"><span>局部推理模板匹配
</span></span></code></pre></div><p>它不是替代 attention。</p>
<p>它是给 TreeHeap 代数增加一种可解释操作。</p>
<h2 id="这个操作需要处理什么困难">这个操作需要处理什么困难</h2>
<p>普通卷积很简单，因为图像是规则网格。</p>
<p>TreeHeap 更麻烦。</p>
<p>它至少要处理：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 树/图不是规则网格。
</span></span><span style="display:flex;"><span>2. child 顺序有时重要，有时不重要。
</span></span><span style="display:flex;"><span>3. slot 顺序可能重要。
</span></span><span style="display:flex;"><span>4. 有些 child 可以缺省。
</span></span><span style="display:flex;"><span>5. 主动/被动会改变方向。
</span></span><span style="display:flex;"><span>6. 中文和英文的表达顺序不同。
</span></span><span style="display:flex;"><span>7. 匹配应该允许近似，而不是严格相等。
</span></span></code></pre></div><p>所以它更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tree kernel
</span></span><span style="display:flex;"><span>graph kernel
</span></span><span style="display:flex;"><span>slot kernel
</span></span><span style="display:flex;"><span>subgraph matching
</span></span><span style="display:flex;"><span>message passing
</span></span></code></pre></div><p>但我们不要一上来做复杂。</p>
<p>先做最小实验。</p>
<h2 id="新-predictp-alg02">新 predict：P-ALG02</h2>
<p>可以写下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-ALG02:
</span></span><span style="display:flex;"><span>如果 TreeHeap 支持拓扑级推理，
</span></span><span style="display:flex;"><span>那么同一个 SubHeap Kernel 应该能在不同表面顺序中，
</span></span><span style="display:flex;"><span>找到等价的局部结构。
</span></span></code></pre></div><p>换句话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一个推理核，
</span></span><span style="display:flex;"><span>应该能匹配不同说法里的同一个结构。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat eats fish
</span></span><span style="display:flex;"><span>fish is eaten by the cat
</span></span><span style="display:flex;"><span>the cat quickly eats fish
</span></span></code></pre></div><p>都应该激活：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat_event(agent=cat, object=fish)
</span></span></code></pre></div><h2 id="e-alg05-kernel-invariance">E-ALG05: kernel invariance</h2>
<p>第一个实验叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-ALG05 kernel invariance
</span></span></code></pre></div><p>测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一个 kernel，
</span></span><span style="display:flex;"><span>不同表面顺序，
</span></span><span style="display:flex;"><span>是否找到同一个子堆。
</span></span></code></pre></div><p>例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat eats fish
</span></span><span style="display:flex;"><span>fish is eaten by the cat
</span></span><span style="display:flex;"><span>the cat quickly eats fish
</span></span></code></pre></div><p>成功标准：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>active/passive/paraphrase variants
</span></span><span style="display:flex;"><span>rank the same event subheap in top-k
</span></span></code></pre></div><p>失败标准：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只对 token 顺序敏感。
</span></span><span style="display:flex;"><span>只匹配表面邻近。
</span></span><span style="display:flex;"><span>主动变被动就失败。
</span></span></code></pre></div><h2 id="e-alg06-kernel-selectivity">E-ALG06: kernel selectivity</h2>
<p>第二个实验叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-ALG06 kernel selectivity
</span></span></code></pre></div><p>测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同样的词，角色换了以后，分数应该下降。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat eats fish
</span></span><span style="display:flex;"><span>fish eats cat
</span></span></code></pre></div><p>它们词一样，但结构不一样。</p>
<p>我们希望：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score(agent=cat, object=fish)
</span></span><span style="display:flex;"><span>&gt;
</span></span><span style="display:flex;"><span>score(agent=fish, object=cat)
</span></span></code></pre></div><p>如果两个分数差不多，说明 kernel 只是看到了词，没有看懂角色。</p>
<h2 id="e-alg07-cross-lingual-kernel-transfer">E-ALG07: cross-lingual kernel transfer</h2>
<p>第三个实验叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-ALG07 cross-lingual kernel transfer
</span></span></code></pre></div><p>测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>中文里的事件 kernel，
</span></span><span style="display:flex;"><span>能不能对应到英文里的等价事件子堆。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>猫吃鱼
</span></span><span style="display:flex;"><span>the cat eats fish
</span></span></code></pre></div><p>或者更复杂：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>鱼被猫吃了
</span></span><span style="display:flex;"><span>the fish was eaten by the cat
</span></span></code></pre></div><p>如果 TreeHeap 真的要服务 WMT/S2，这个实验很关键。</p>
<p>因为翻译本质不是词对词。</p>
<p>翻译是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>源语言局部拓扑
</span></span><span style="display:flex;"><span>映射到
</span></span><span style="display:flex;"><span>目标语言局部拓扑
</span></span></code></pre></div><p>SubHeap Kernel Search 正好可以测这件事。</p>
<h2 id="和前面代数操作的关系">和前面代数操作的关系</h2>
<p>SubHeap Kernel Search 不是孤立的。</p>
<p>它会用到前面几种操作：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>project:
</span></span><span style="display:flex;"><span>  把子堆放到某个参考系里解释。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>transpose:
</span></span><span style="display:flex;"><span>  处理主动/被动、parent/child 方向变化。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>energy:
</span></span><span style="display:flex;"><span>  给候选匹配排序。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>probability container:
</span></span><span style="display:flex;"><span>  保留多个可能匹配。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>decompose:
</span></span><span style="display:flex;"><span>  从 parent 里找可能 children。
</span></span></code></pre></div><p>所以它可以看作 TreeHeap Algebra 的第一个“推理搜索操作”。</p>
<h2 id="工程上怎么先做">工程上怎么先做</h2>
<p>最小实现不用大模型。</p>
<p>可以先做 controlled toy set：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat eats fish
</span></span><span style="display:flex;"><span>fish is eaten by cat
</span></span><span style="display:flex;"><span>dog chases cat
</span></span><span style="display:flex;"><span>cat is chased by dog
</span></span></code></pre></div><p>用 spaCy 或手写 proxy 结构先构造小 TreeHeap。</p>
<p>然后定义 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_action_object
</span></span><span style="display:flex;"><span>K_agent_action_object
</span></span><span style="display:flex;"><span>K_action_location
</span></span></code></pre></div><p>再比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>gold subheap score
</span></span><span style="display:flex;"><span>shuffled-role score
</span></span><span style="display:flex;"><span>surface-nearest score
</span></span><span style="display:flex;"><span>random subheap score
</span></span></code></pre></div><p>如果连这个都跑不出来，就不应该直接上 WMT。</p>
<h2 id="这对项目推进有什么意义">这对项目推进有什么意义</h2>
<p>之前我们一直在问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 是否学出了世界模型？
</span></span></code></pre></div><p>这个问题太大。</p>
<p>现在可以拆小：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能不能定义一个局部结构核？
</span></span><span style="display:flex;"><span>这个核能不能在大堆里找等价子堆？
</span></span><span style="display:flex;"><span>这个匹配能不能跨主动/被动？
</span></span><span style="display:flex;"><span>这个匹配能不能跨语言？
</span></span></code></pre></div><p>这比直接问“能不能翻译”更可测。</p>
<p>如果 P-ALG02 成立，下一步 S2 会更清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>source sentence
</span></span><span style="display:flex;"><span>-&gt; SubHeap kernels find source reasoning structure
</span></span><span style="display:flex;"><span>-&gt; project/transpose to target frame
</span></span><span style="display:flex;"><span>-&gt; target SubHeap kernels recover target structure
</span></span><span style="display:flex;"><span>-&gt; decoder realizes surface text
</span></span></code></pre></div><p>如果 P-ALG02 失败，那也很清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 还没有 topology search 能力。
</span></span><span style="display:flex;"><span>不要急着把它接到 WMT decoder。
</span></span></code></pre></div><h2 id="当前状态">当前状态</h2>
<p>新增 predict：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-ALG02: SubHeap kernel search
</span></span></code></pre></div><p>新增实验计划：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-ALG05 kernel invariance
</span></span><span style="display:flex;"><span>E-ALG06 kernel selectivity
</span></span><span style="display:flex;"><span>E-ALG07 cross-lingual kernel transfer
</span></span></code></pre></div><p>计划实现：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s2-translation/src/subheap_kernel_probe.py
</span></span><span style="display:flex;"><span>ara/s2-translation/evidence/subheap_kernel_probe/
</span></span></code></pre></div><p>状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Design phase.
</span></span></code></pre></div><p>还没有 claim。</p>
<h2 id="最后一句话">最后一句话</h2>
<p>CMul 是点进入背景。</p>
<p>TreeHeap Algebra 是对象之间的数学操作。</p>
<p>SubHeap Kernel Search 则是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在高维堆里寻找局部推理模式。
</span></span></code></pre></div><p>这可能是 TreeHeap 从“保存信息”走向“结构推理”的关键一步。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-013] M0 纯数学实验：先让 TreeHeap 成为工具箱</title>
      <link>https://www.grepcode.cn/spr/013-treeheap-math-probe.html</link>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/013-treeheap-math-probe.html</guid>
      <description>记录第一轮 M0 TreeHeap Math toy 实验：为什么先不做 WMT，怎么验证闭包、非交换、逆操作、投影和子堆核匹配。</description>
      <content:encoded><![CDATA[<h1 id="m0-纯数学实验先让-treeheap-成为工具箱">M0 纯数学实验：先让 TreeHeap 成为工具箱</h1>
<p>这篇文章记录一件更底层的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先不要直接做 WMT。
</span></span><span style="display:flex;"><span>先证明 TreeHeap 作为数学对象能不能被操作。
</span></span></code></pre></div><p>WMT 是最终任务。</p>
<p>但它不是好的早期诊断工具。</p>
<p>因为如果直接训练翻译系统，最后 BLEU 没涨，我们很难知道失败来自哪里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>算子设计不对
</span></span><span style="display:flex;"><span>世界模型没学到
</span></span><span style="display:flex;"><span>loss 不合适
</span></span><span style="display:flex;"><span>decoder 太弱
</span></span><span style="display:flex;"><span>数据不够
</span></span><span style="display:flex;"><span>训练没收敛
</span></span><span style="display:flex;"><span>评估太粗
</span></span></code></pre></div><p>所以这次我们先建立一个更小的 ARA 主题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/
</span></span></code></pre></div><p>它的目标不是证明 TreeHeap 会语言推理。</p>
<p>它只问一个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能不能先成为一个数学工具箱？
</span></span></code></pre></div><h2 id="公开记录">公开记录</h2>
<p>公开实验仓：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>https://github.com/houming818/sametime
</span></span></code></pre></div><p>对应 ARA 入口：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/logic/predicts.md
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/logic/solution/algebra.md
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/src/treeheap_math_probe.py
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/treeheap_math_probe/summary.json
</span></span></code></pre></div><p>主仓内部路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/home/nio/log/ara/m0-treeheap-math/
</span></span></code></pre></div><h2 id="为什么这是-toy-实验">为什么这是 toy 实验</h2>
<p>toy 不是玩具。</p>
<p>toy 的意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把问题缩小到刚好能看清楚。
</span></span></code></pre></div><p>如果我们要验证卷积核，第一步不会直接拿 ImageNet。</p>
<p>会先拿一个很小的矩阵：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 0 1
</span></span><span style="display:flex;"><span>0 1 0
</span></span><span style="display:flex;"><span>1 0 1
</span></span></code></pre></div><p>看看核匹配到底能不能找到局部模式。</p>
<p>TreeHeap 也是一样。</p>
<p>这次我们不使用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token
</span></span><span style="display:flex;"><span>语法标签
</span></span><span style="display:flex;"><span>WMT
</span></span><span style="display:flex;"><span>BLEU
</span></span><span style="display:flex;"><span>真实 checkpoint
</span></span></code></pre></div><p>只使用几个合成符号：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A, B, C, D, E, R, T
</span></span></code></pre></div><p>然后构造几棵小树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_ab = root(R, left=A, right=B)
</span></span><span style="display:flex;"><span>H_ba = root(R, left=B, right=A)
</span></span><span style="display:flex;"><span>H_cd = root(R, left=C, right=D)
</span></span><span style="display:flex;"><span>H_nested = root(T, left=H_ab, right=E)
</span></span></code></pre></div><p>这个 toy 足够小。</p>
<p>小到我们知道正确答案。</p>
<p>也足够有用。</p>
<p>因为它能测试 TreeHeap 最基本的数学性质。</p>
<h2 id="最小-treeheap-对象">最小 TreeHeap 对象</h2>
<p>第一版对象定义成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = (name, v, head_v, slot, q, children)
</span></span></code></pre></div><p>字段含义：</p>
<table>
  <thead>
      <tr>
          <th>字段</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>name</code></td>
          <td>合成对象名字，比如 <code>H_ab</code></td>
      </tr>
      <tr>
          <td><code>v</code></td>
          <td>整棵 TreeHeap 的结构向量</td>
      </tr>
      <tr>
          <td><code>head_v</code></td>
          <td>root/head 参考向量</td>
      </tr>
      <tr>
          <td><code>slot</code></td>
          <td>当前节点的结构槽位</td>
      </tr>
      <tr>
          <td><code>q</code></td>
          <td>概率质量</td>
      </tr>
      <tr>
          <td><code>children</code></td>
          <td>子堆</td>
      </tr>
  </tbody>
</table>
<p>这里最关键的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>v != head_v
</span></span></code></pre></div><p><code>v</code> 是整体结构坍缩后的向量。</p>
<p><code>head_v</code> 是根节点自己的参考量。</p>
<p>这个区别是实验跑出来的，不是预先拍脑袋定的。</p>
<h2 id="这次测试哪些工具">这次测试哪些工具</h2>
<p>第一批工具箱：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose
</span></span><span style="display:flex;"><span>decompose
</span></span><span style="display:flex;"><span>transpose
</span></span><span style="display:flex;"><span>inverse_transpose
</span></span><span style="display:flex;"><span>project
</span></span><span style="display:flex;"><span>unproject
</span></span><span style="display:flex;"><span>energy
</span></span><span style="display:flex;"><span>match_subheap
</span></span><span style="display:flex;"><span>probability container
</span></span></code></pre></div><p>对应要问的问题：</p>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>compose</code></td>
          <td>两个子堆能不能合成一个合法 TreeHeap</td>
      </tr>
      <tr>
          <td><code>decompose</code></td>
          <td>合成后能不能拆回子堆</td>
      </tr>
      <tr>
          <td><code>transpose</code></td>
          <td>左右结构交换后是否仍然可追踪</td>
      </tr>
      <tr>
          <td><code>inverse_transpose</code></td>
          <td>转置两次能不能回来</td>
      </tr>
      <tr>
          <td><code>project</code></td>
          <td>降维后是否还保留结构排序</td>
      </tr>
      <tr>
          <td><code>energy</code></td>
          <td>正确结构和扰动结构能不能拉开距离</td>
      </tr>
      <tr>
          <td><code>match_subheap</code></td>
          <td>小子堆核能不能在大树里找到对应部分</td>
      </tr>
      <tr>
          <td><code>probability container</code></td>
          <td>匹配结果能不能形成稳定概率分布</td>
      </tr>
  </tbody>
</table>
<h2 id="非交换性ab-不等于-ba">非交换性：AB 不等于 BA</h2>
<p>如果 TreeHeap 只是普通加法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A + B = B + A
</span></span></code></pre></div><p>那它没法表达结构顺序。</p>
<p>所以我们给左右位置不同的结构基：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>v(H) = normalize(root + L @ left + R @ right)
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L != R
</span></span></code></pre></div><p>于是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_ab = root(R, left=A, right=B)
</span></span><span style="display:flex;"><span>H_ba = root(R, left=B, right=A)
</span></span></code></pre></div><p>会得到不同向量。</p>
<p>这就像数字：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>12 != 21
</span></span></code></pre></div><p>不是因为 1 和 2 变了。</p>
<p>而是因为位权变了。</p>
<p>实验结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>noncomm_margin = 0.7117
</span></span></code></pre></div><p>这说明左右交换后，结构空间里确实拉开了距离。</p>
<h2 id="第一次失败只有-v-不够">第一次失败：只有 v 不够</h2>
<p>第一版实现里，我只保存了整体向量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = (name, v, slot, q, children)
</span></span></code></pre></div><p>结果 <code>transpose</code> 出问题了。</p>
<p>我们希望：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>inverse_transpose(transpose(H)) ~= H
</span></span></code></pre></div><p>但第一次跑出来：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>transpose_inverse_error = 0.6248
</span></span></code></pre></div><p>这说明一个重要问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只有坍缩后的整体向量 v，不足以支持精确逆操作。
</span></span></code></pre></div><p>原因很直接。</p>
<p>当一棵树已经合成为整体向量后，这个整体向量混合了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>left
</span></span><span style="display:flex;"><span>right
</span></span></code></pre></div><p>如果再拿它当 root 去重组，就会把整体误当成局部。</p>
<p>于是转置两次也回不来。</p>
<p>这不是坏事。</p>
<p>这是 toy 实验的价值。</p>
<p>它告诉我们 TreeHeap 对象定义漏了一个必要参考量。</p>
<h2 id="修正加入-head_v">修正：加入 head_v</h2>
<p>修正后对象变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = (name, v, head_v, slot, q, children)
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>head_v = root/head 自己的向量
</span></span><span style="display:flex;"><span>v      = 整棵树合成后的向量
</span></span></code></pre></div><p>这样 <code>transpose</code> 时可以用原来的 head 重新组装，而不是把整体向量错当 root。</p>
<p>修正后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>transpose_inverse_error = 0.0
</span></span></code></pre></div><p>这个结论很重要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不能只是一个 collapsed vector。
</span></span><span style="display:flex;"><span>它至少需要保留 root/head reference。
</span></span></code></pre></div><p>这也是从纯数学实验里得到的第一个设计约束。</p>
<h2 id="子堆核匹配-toy">子堆核匹配 toy</h2>
<p>我们构造：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_nested = root(T, left=H_ab, right=E)
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        T
</span></span><span style="display:flex;"><span>       / \
</span></span><span style="display:flex;"><span>    H_ab  E
</span></span><span style="display:flex;"><span>    /  \
</span></span><span style="display:flex;"><span>   A    B
</span></span></code></pre></div><p>然后用 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K = H_ab
</span></span></code></pre></div><p>去 <code>H_nested</code> 里找匹配。</p>
<p>结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subheap_hit_at_1 = 1.0
</span></span><span style="display:flex;"><span>subheap_hit_at_3 = 1.0
</span></span></code></pre></div><p>匹配分数最高的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_ab
</span></span></code></pre></div><p>对应概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.9999798803
</span></span></code></pre></div><p>这说明在 toy 条件下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>match_subheap(H_nested, H_ab)
</span></span></code></pre></div><p>能找到正确子堆。</p>
<h2 id="role-swap-为什么看-margin">role swap 为什么看 margin</h2>
<p>我们还测试了反向 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K = H_ba
</span></span></code></pre></div><p>但 <code>H_nested</code> 里并没有真正的 <code>H_ba</code>。</p>
<p>这时系统仍然必须返回一个 top-1，因为概率容器总要在候选里排序。</p>
<p>它会把最接近的错误候选排前面。</p>
<p>所以不能只看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>top1 是谁
</span></span></code></pre></div><p>还要看分数差。</p>
<p>结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>gold score = 1.0
</span></span><span style="display:flex;"><span>role-swapped score on gold = 0.09085
</span></span><span style="display:flex;"><span>role_swap_margin = 0.9091
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_ab 和 H_ba 在结构空间里不是同一个东西。
</span></span></code></pre></div><p>这正是我们想要的。</p>
<h2 id="本轮结果">本轮结果</h2>
<p>实验命令在 ni 上执行，CPU 即可，不使用 GPU。</p>
<p>结果摘要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pilot_pass = true
</span></span><span style="display:flex;"><span>closure_ok = true
</span></span><span style="display:flex;"><span>noncomm_margin = 0.7117
</span></span><span style="display:flex;"><span>transpose_inverse_error = 0.0
</span></span><span style="display:flex;"><span>compose_decompose_error = 0.0
</span></span><span style="display:flex;"><span>projection_top1_preserved = true
</span></span><span style="display:flex;"><span>projection_order_agreement = 0.8333
</span></span><span style="display:flex;"><span>subheap_hit_at_1 = 1.0
</span></span><span style="display:flex;"><span>subheap_hit_at_3 = 1.0
</span></span><span style="display:flex;"><span>role_swap_margin = 0.9091
</span></span><span style="display:flex;"><span>prob_mass_error = 0.0
</span></span></code></pre></div><p>对应证据文件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/treeheap_math_probe/summary.json
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/treeheap_math_probe/README.md
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/treeheap_math_probe/matches.jsonl
</span></span></code></pre></div><h2 id="这证明了什么">这证明了什么</h2>
<p>它证明了一个很小但很关键的点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可以先作为数学对象被操作。
</span></span></code></pre></div><p>至少在合成 toy 空间里，它支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>闭包
</span></span><span style="display:flex;"><span>非交换
</span></span><span style="display:flex;"><span>精确转置逆
</span></span><span style="display:flex;"><span>compose/decompose
</span></span><span style="display:flex;"><span>投影保持
</span></span><span style="display:flex;"><span>子堆核匹配
</span></span><span style="display:flex;"><span>概率容器归一
</span></span></code></pre></div><p>这给下一步 Echo 提供了更干净的地基。</p>
<h2 id="它没有证明什么">它没有证明什么</h2>
<p>它没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 懂语言
</span></span><span style="display:flex;"><span>TreeHeap 会翻译
</span></span><span style="display:flex;"><span>TreeHeap 已经形成世界模型
</span></span><span style="display:flex;"><span>SubHeap kernel 能处理真实句子
</span></span><span style="display:flex;"><span>WMT 会涨分
</span></span></code></pre></div><p>这只是 M0。</p>
<p>但 M0 的意义是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先把尺子做出来。
</span></span></code></pre></div><p>没有尺子，直接看 BLEU，就像还没造好温度计就讨论天气。</p>
<h2 id="下一步">下一步</h2>
<p>路线应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0 纯数学 TreeHeap
</span></span><span style="display:flex;"><span>  -&gt; M1 approximate inverse
</span></span><span style="display:flex;"><span>  -&gt; M2 TreeHeap-object echo
</span></span><span style="display:flex;"><span>  -&gt; M3 structure invariant
</span></span><span style="display:flex;"><span>  -&gt; S2 translation
</span></span></code></pre></div><p>下一步不应该直接回 WMT。</p>
<p>应该做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>exact inverse
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>approximate / learned inverse
</span></span></code></pre></div><p>也就是看看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不直接保存 children 的时候，
</span></span><span style="display:flex;"><span>模型能不能从 TreeHeap 表示里近似拆回结构。
</span></span></code></pre></div><p>如果 M1 过了，再做 Echo。</p>
<p>Echo 也不再是旧的 token echo。</p>
<p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap object
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>operator transformations
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>reconstruct TreeHeap object
</span></span></code></pre></div><p>这样顺序更干净：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数学成立
</span></span><span style="display:flex;"><span>信息可保留
</span></span><span style="display:flex;"><span>结构可识别
</span></span><span style="display:flex;"><span>语言再利用
</span></span></code></pre></div><blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-014] 基元与 plus：TreeHeap 有序性的来源</title>
      <link>https://www.grepcode.cn/spr/014-primitive-plus-order.html</link>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/014-primitive-plus-order.html</guid>
      <description>把 TreeHeap 的卷积问题继续下压：先寻找语义空间里的基元、plus 算子和由 plus 生成的有序性。</description>
      <content:encoded><![CDATA[<h1 id="基元与-plustreeheap-有序性的来源">基元与 plus：TreeHeap 有序性的来源</h1>
<p>这篇先不跑实验。</p>
<p>它先把一个更底层的想法固定下来：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的卷积问题，
</span></span><span style="display:flex;"><span>可能不是先找 kernel，
</span></span><span style="display:flex;"><span>而是先找语义空间里的基元和 plus。
</span></span></code></pre></div><p>这个想法来自整数系统。</p>
<p>整数的有序性不是随便排出来的。</p>
<p>它有一个非常小的核心：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>基元：0 或 1
</span></span><span style="display:flex;"><span>算子：plus / successor
</span></span><span style="display:flex;"><span>顺序：n -&gt; n + 1
</span></span><span style="display:flex;"><span>闭包：n + 1 仍然是整数
</span></span><span style="display:flex;"><span>取模：n + base 折回 n
</span></span></code></pre></div><p>如果 TreeHeap 也想形成自然的有序地址空间，那么我们也要问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语义空间里的 1 是什么？
</span></span><span style="display:flex;"><span>语义空间里的 plus 是什么？
</span></span><span style="display:flex;"><span>TreeHeap 的 n+1 是怎么生成的？
</span></span></code></pre></div><h2 id="为什么这比卷积更底层">为什么这比卷积更底层</h2>
<p>上一篇文章说，卷积可以理解成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>线性秩序
</span></span><span style="display:flex;"><span>+ 局部窗口
</span></span><span style="display:flex;"><span>+ 取模位移
</span></span><span style="display:flex;"><span>+ 同一个 kernel 的重复作用
</span></span></code></pre></div><p>但这里还有一个没回答的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>线性秩序从哪里来？
</span></span></code></pre></div><p>如果我们只是人为给节点编号：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node_0, node_1, node_2, ...
</span></span></code></pre></div><p>那这个顺序可能只是外部编号。</p>
<p>它不一定是 TreeHeap 自己的结构。</p>
<p>更自然的做法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node_{n+1} = plus(node_n, primitive)
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>有序性由 plus 生成。
</span></span></code></pre></div><p>这就像整数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 = 0 + 1
</span></span><span style="display:flex;"><span>2 = 1 + 1
</span></span><span style="display:flex;"><span>3 = 2 + 1
</span></span></code></pre></div><p>而不是先把整数排好，再事后说它有顺序。</p>
<h2 id="对应关系">对应关系</h2>
<p>可以先做一个对照表：</p>
<table>
  <thead>
      <tr>
          <th>整数系统</th>
          <th>TreeHeap / 语义空间</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>0</code></td>
          <td>origin / root primitive</td>
      </tr>
      <tr>
          <td><code>1</code></td>
          <td>最小语义基元</td>
      </tr>
      <tr>
          <td><code>n + 1</code></td>
          <td>next semantic state / next node</td>
      </tr>
      <tr>
          <td><code>plus(a, b)</code></td>
          <td>语义组合或结构推进算子</td>
      </tr>
      <tr>
          <td><code>&lt;</code></td>
          <td>repeated plus 生成的顺序</td>
      </tr>
      <tr>
          <td><code>mod base</code></td>
          <td>有限 TreeHeap 地址环</td>
      </tr>
      <tr>
          <td>convolution</td>
          <td>在这个地址环上滑动 kernel</td>
      </tr>
  </tbody>
</table>
<p>所以真正要找的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>primitive
</span></span><span style="display:flex;"><span>plus
</span></span><span style="display:flex;"><span>ordered orbit
</span></span></code></pre></div><p>其中 orbit 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x0
</span></span><span style="display:flex;"><span>x1 = plus(x0, p)
</span></span><span style="display:flex;"><span>x2 = plus(x1, p)
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>x_base ~= x0
</span></span></code></pre></div><p>如果这个成立，TreeHeap 就不仅是有编号。</p>
<p>它有了一个内部生成的顺序。</p>
<h2 id="什么是基元">什么是基元</h2>
<p>基元不是人工语法标签。</p>
<p>它不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SUBJECT
</span></span><span style="display:flex;"><span>OBJECT
</span></span><span style="display:flex;"><span>VERB
</span></span></code></pre></div><p>至少在 M0/M1 阶段不能这样定义。</p>
<p>基元应该先被看成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能让状态发生最小可重复变化的元素。
</span></span></code></pre></div><p>在整数里，这个元素是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1
</span></span></code></pre></div><p>在 TreeHeap 里，它可能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个最小路径步长
</span></span><span style="display:flex;"><span>一个最小 slot shift
</span></span><span style="display:flex;"><span>一个最小语义方向
</span></span><span style="display:flex;"><span>一个局部结构生成元
</span></span><span style="display:flex;"><span>一个 learned primitive basis
</span></span></code></pre></div><p>我们不应该一开始就假设它是什么。</p>
<p>应该设计实验去找：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>哪个 p 可以让 plus(x, p) 稳定地产生 next？
</span></span></code></pre></div><h2 id="plus-可能是什么">plus 可能是什么</h2>
<p>候选 plus 可以有很多种：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus(v, p) = v + p
</span></span><span style="display:flex;"><span>plus(v, p) = normalize(v + p)
</span></span><span style="display:flex;"><span>plus(v, p) = CMul(v, p)
</span></span><span style="display:flex;"><span>plus(H, p) = compose(H, p)
</span></span><span style="display:flex;"><span>plus(path, step) = path_shift(path, step)
</span></span><span style="display:flex;"><span>plus(H, p) = learned_operator(H, p)
</span></span></code></pre></div><p>这些都只是候选。</p>
<p>不能先说哪一个一定对。</p>
<p>ARA 里应该把它们当作实验变量。</p>
<p>真正的判断标准是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它能不能生成稳定有序轨道？
</span></span></code></pre></div><h2 id="有序轨道">有序轨道</h2>
<p>如果找到了一个 primitive <code>p</code> 和一个 plus，那么就可以生成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x0 = origin
</span></span><span style="display:flex;"><span>x1 = plus(x0, p)
</span></span><span style="display:flex;"><span>x2 = plus(x1, p)
</span></span><span style="display:flex;"><span>x3 = plus(x2, p)
</span></span></code></pre></div><p>这是一条轨道。</p>
<p>我们希望它满足：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>相邻可预测
</span></span><span style="display:flex;"><span>远邻可区分
</span></span><span style="display:flex;"><span>重复作用不发散
</span></span><span style="display:flex;"><span>到达 base 后可以回环
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>nearest(plus(x_n, p)) = x_{n+1}
</span></span><span style="display:flex;"><span>distance(x_n, x_{n+1}) &lt; distance(x_n, x_{n+3})
</span></span><span style="display:flex;"><span>distance(x_base, x_0) small
</span></span></code></pre></div><p>这才是 TreeHeap 的有序性。</p>
<p>不是外部排出来的。</p>
<p>而是由内部算子生成的。</p>
<h2 id="取模怎么出现">取模怎么出现</h2>
<p>如果轨道长度是 <code>base</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x0, x1, x2, ..., x_{base-1}
</span></span></code></pre></div><p>那么取模就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x_{n + base} ~= x_n
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>idx(x) in Z_base
</span></span></code></pre></div><p>这时 TreeHeap 地址空间变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Z / base Z
</span></span></code></pre></div><p>也就是一个有限循环地址环。</p>
<p>卷积 kernel 才能滑动：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>window(i) = [
</span></span><span style="display:flex;"><span>  x_{i-1 mod base},
</span></span><span style="display:flex;"><span>  x_i,
</span></span><span style="display:flex;"><span>  x_{i+1 mod base}
</span></span><span style="display:flex;"><span>]
</span></span></code></pre></div><p>这就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>基元 + plus
</span></span><span style="display:flex;"><span>生成 order
</span></span><span style="display:flex;"><span>order + mod
</span></span><span style="display:flex;"><span>生成 cyclic address
</span></span><span style="display:flex;"><span>cyclic address + kernel
</span></span><span style="display:flex;"><span>生成卷积
</span></span></code></pre></div><h2 id="这对-treeheap-很重要">这对 TreeHeap 很重要</h2>
<p>之前我们说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 是有序树。
</span></span></code></pre></div><p>但这句话还不够。</p>
<p>还要追问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个有序性是外部编号给的，
</span></span><span style="display:flex;"><span>还是 TreeHeap 自己生成的？
</span></span></code></pre></div><p>如果只是外部编号，那它只是工程索引。</p>
<p>如果有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x_{n+1} = plus(x_n, p)
</span></span></code></pre></div><p>那它就是结构规律。</p>
<p>这两者差别很大。</p>
<p>前者只能帮我们扫描。</p>
<p>后者可能帮我们推理。</p>
<h2 id="新-predictp-math02">新 predict：P-MATH02</h2>
<p>可以把下一步写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-MATH02: Semantic primitive and plus operator
</span></span></code></pre></div><p>预判：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap 空间存在可用于结构生成的有序性，
</span></span><span style="display:flex;"><span>那么应该存在某种 primitive p 和 plus 算子，
</span></span><span style="display:flex;"><span>使 repeated plus 生成稳定、有序、可取模的语义轨道。
</span></span></code></pre></div><p>形式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x_0 = origin
</span></span><span style="display:flex;"><span>x_{n+1} = plus(x_n, p)
</span></span><span style="display:flex;"><span>x_{n+base} ~= x_n
</span></span></code></pre></div><h2 id="toy-实验应该怎么做">toy 实验应该怎么做</h2>
<p>先不要碰语言。</p>
<p>还是 M0 纯数学 toy。</p>
<p>设：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>base = 8
</span></span><span style="display:flex;"><span>origin = x0
</span></span><span style="display:flex;"><span>primitive = p
</span></span></code></pre></div><p>生成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x1 = plus(x0, p)
</span></span><span style="display:flex;"><span>x2 = plus(x1, p)
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>x8 ~= x0
</span></span></code></pre></div><p>测这些指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>successor_accuracy:
</span></span><span style="display:flex;"><span>  nearest(plus(x_n, p)) == x_{n+1}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cycle_error:
</span></span><span style="display:flex;"><span>  distance(x_base, x_0)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>order_margin:
</span></span><span style="display:flex;"><span>  distance(x_n, x_{n+1}) &lt; distance(x_n, x_{n+3})
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>closure:
</span></span><span style="display:flex;"><span>  plus(x_n, p) still in TreeHeap space
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>kernel:
</span></span><span style="display:flex;"><span>  [x_{i-1}, x_i, x_{i+1}] mod base can be matched
</span></span></code></pre></div><p>如果这些都不成立，就不要急着讨论语言。</p>
<p>因为连：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1, 2, 3, 4
</span></span></code></pre></div><p>这样的内部顺序都还没长出来。</p>
<h2 id="语言里的直觉">语言里的直觉</h2>
<p>等数学 toy 成立以后，语言才进来。</p>
<p>那时候可以问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>球 + 脚 -&gt; 足球
</span></span><span style="display:flex;"><span>球 + 手 -&gt; 篮球
</span></span><span style="display:flex;"><span>动作 + 施事 -&gt; 事件
</span></span><span style="display:flex;"><span>事件 + 时间 -&gt; 时态
</span></span><span style="display:flex;"><span>事件 + 地点 -&gt; 场景
</span></span></code></pre></div><p>但这些不能一开始就当作人工标签。</p>
<p>更好的路径是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先无监督找 primitive basis
</span></span><span style="display:flex;"><span>再看这些 basis 是否对应可解释概念
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先找数学上的 1。
</span></span><span style="display:flex;"><span>再看这个 1 在语言里像不像“脚”“手”“时间”“地点”。
</span></span></code></pre></div><h2 id="对当前路线的影响">对当前路线的影响</h2>
<p>这会把路线再往前插一层：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0: TreeHeap object algebra
</span></span><span style="display:flex;"><span>M0-P2: primitive + plus + ordered orbit
</span></span><span style="display:flex;"><span>M1: approximate inverse / learned plus
</span></span><span style="display:flex;"><span>M2: TreeHeap-object echo
</span></span><span style="display:flex;"><span>M3: structure invariant
</span></span><span style="display:flex;"><span>S2: translation
</span></span></code></pre></div><p>也就是说，SubHeap Kernel Search 之前，还要先问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 在哪个有序空间里移动？
</span></span><span style="display:flex;"><span>这个有序空间是不是由 plus 生成？
</span></span></code></pre></div><p>如果不是，它可能只是工程扫描。</p>
<p>如果是，它才更像 TreeHeap 自己的代数。</p>
<h2 id="当前状态">当前状态</h2>
<p>这篇是理论整理。</p>
<p>还没有实验 claim。</p>
<p>已经可以进入 ARA：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/logic/predicts.md
</span></span></code></pre></div><p>下一步实验文件可以叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/src/primitive_plus_probe.py
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/primitive_plus_probe/
</span></span></code></pre></div><p>先用合成 toy 找：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>primitive
</span></span><span style="display:flex;"><span>plus
</span></span><span style="display:flex;"><span>ordered orbit
</span></span><span style="display:flex;"><span>mod base
</span></span><span style="display:flex;"><span>cyclic kernel
</span></span></code></pre></div><p>等这个成立，再往 Echo 和 S2 推。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-015] primitive plus 实验：把 proof 变成可测的 TreeHeap toy</title>
      <link>https://www.grepcode.cn/spr/015-primitive-plus-probe.html</link>
      <pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/015-primitive-plus-probe.html</guid>
      <description>用中国大陆本科数学口径解释 primitive_plus_probe：arr[0]、plus、mod base、信息量增长、循环窗口和 kernel 匹配。</description>
      <content:encoded><![CDATA[<h1 id="primitive-plus-实验把-proof-变成可测的-treeheap-toy">primitive plus 实验：把 proof 变成可测的 TreeHeap toy</h1>
<p>这篇文章解释刚跑完的实验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>primitive_plus_probe.py
</span></span></code></pre></div><p>它对应 ARA 里的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-MATH02: Semantic primitive and plus operator
</span></span></code></pre></div><p>这次实验不是语言实验。</p>
<p>不是翻译实验。</p>
<p>不是 WMT。</p>
<p>它是一个纯数学 toy，用来验证一个非常小的想法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap 是一个可寻址的堆结构，
</span></span><span style="display:flex;"><span>那么 plus 能不能同时承担三件事：
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>1. successor：走到下一个地址
</span></span><span style="display:flex;"><span>2. information gain：增加信息量
</span></span><span style="display:flex;"><span>3. mod fold：超过 base 后折回前面的地址
</span></span></code></pre></div><p>如果这个 toy 都跑不通，就没必要急着谈真实语言里的 TreeHeap 卷积。</p>
<h2 id="先说结论">先说结论</h2>
<p>这轮 toy 实验通过了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pilot_pass = true
</span></span><span style="display:flex;"><span>successor_ok = true
</span></span><span style="display:flex;"><span>info_gain_pre_base = true
</span></span><span style="display:flex;"><span>info_saturates_after_base = true
</span></span><span style="display:flex;"><span>mod_fold_targets = [0, 1]
</span></span><span style="display:flex;"><span>mod_fold_ok = true
</span></span><span style="display:flex;"><span>kernel_hit_at_1 = 1.0
</span></span><span style="display:flex;"><span>wrap_breaks_old_kernel = true
</span></span></code></pre></div><p>用人话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus 可以从 arr[0] 写到 arr[7]。
</span></span><span style="display:flex;"><span>base=8 满了以后，再 plus 会折回 arr[0]、arr[1]。
</span></span><span style="display:flex;"><span>base 没满前，信息量每次 +1。
</span></span><span style="display:flex;"><span>base 满了以后，信息量不再增加，而是覆盖旧位置。
</span></span><span style="display:flex;"><span>循环窗口 kernel 能找到 [p0, p1, p2]。
</span></span><span style="display:flex;"><span>覆盖 arr[0] 后，旧 kernel 分数下降。
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus = successor + information gain + mod fold
</span></span></code></pre></div><p>至少在这个合成 toy 里是成立的。</p>
<h2 id="为什么要做这个实验">为什么要做这个实验</h2>
<p>前面我们讨论 TreeHeap 卷积。</p>
<p>卷积需要一个有序空间。</p>
<p>一维卷积里，这个空间是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x[0], x[1], x[2], ..., x[n-1]
</span></span></code></pre></div><p>如果加上取模：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x[(i + 1) mod n]
</span></span></code></pre></div><p>它就变成一个循环空间。</p>
<p>但是 TreeHeap 不是普通数组。</p>
<p>所以问题变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的有序空间从哪里来？
</span></span></code></pre></div><p>如果只是人工编号：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0, 1, 2, 3, ...
</span></span></code></pre></div><p>那只是工程索引。</p>
<p>我们真正想找的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个顺序能不能由 plus 生成？
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_{n+1} = plus(H_n, primitive)
</span></span></code></pre></div><p>这个实验就是把这个 proof 变成可测程序。</p>
<h2 id="treeheap-对象怎么定义">TreeHeap 对象怎么定义</h2>
<p>这次不用单个向量表示 TreeHeap。</p>
<p>我们明确使用可寻址数组：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeapState = {
</span></span><span style="display:flex;"><span>  arr: Node[]
</span></span><span style="display:flex;"><span>  base: int
</span></span><span style="display:flex;"><span>  cursor: int
</span></span><span style="display:flex;"><span>  summary: vector
</span></span><span style="display:flex;"><span>  step: int
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[0] = root
</span></span></code></pre></div><p>这是你指出的关键点。</p>
<p>如果 TreeHeap 是数组式堆，那么 root 本来就在：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[0]
</span></span></code></pre></div><p>所以 root 不需要额外幻想出来。</p>
<p>真正重要的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr 是主状态。
</span></span><span style="display:flex;"><span>summary 只是投影。
</span></span></code></pre></div><p>不要反过来把 summary 当成整棵树。</p>
<h2 id="数组堆的地址规律">数组堆的地址规律</h2>
<p>这次使用二叉堆的本科数据结构公式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root = 0
</span></span><span style="display:flex;"><span>left(i) = 2i + 1
</span></span><span style="display:flex;"><span>right(i) = 2i + 2
</span></span><span style="display:flex;"><span>parent(i) = floor((i - 1) / 2)
</span></span></code></pre></div><p>例如 <code>base = 8</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>index: 0 1 2 3 4 5 6 7
</span></span></code></pre></div><p>树关系是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0
</span></span><span style="display:flex;"><span>├─ 1
</span></span><span style="display:flex;"><span>│  ├─ 3
</span></span><span style="display:flex;"><span>│  └─ 4
</span></span><span style="display:flex;"><span>└─ 2
</span></span><span style="display:flex;"><span>   ├─ 5
</span></span><span style="display:flex;"><span>   └─ 6
</span></span></code></pre></div><p><code>7</code> 是下一层的第一个节点。</p>
<p>这说明 TreeHeap 不是无序集合。</p>
<p>它有地址，有父子关系，也可以有线性顺序。</p>
<h2 id="取模-base">取模 base</h2>
<p>这次设置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>base = 8
</span></span></code></pre></div><p>地址只有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0, 1, 2, 3, 4, 5, 6, 7
</span></span></code></pre></div><p>如果再往后写，就用取模：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>target = (cursor + 1) mod base
</span></span></code></pre></div><p>这就是整数模群里最基础的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Z / 8Z
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0,1,2,3,4,5,6,7,0,1,2,...
</span></span></code></pre></div><p>群论里可以把它看成一个循环群。</p>
<p>但这里只需要理解：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>超过 7，就回到 0。
</span></span></code></pre></div><h2 id="plus-怎么定义">plus 怎么定义</h2>
<p>这次的 <code>plus</code> 很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus(H, primitive):
</span></span><span style="display:flex;"><span>  target = (cursor + 1) mod base
</span></span><span style="display:flex;"><span>  arr[target] = primitive
</span></span><span style="display:flex;"><span>  summary = summarize(arr)
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus 不是向量加法。
</span></span><span style="display:flex;"><span>plus 是对 TreeHeap 地址空间的一次写入。
</span></span></code></pre></div><p>它做三件事：</p>
<ol>
<li>找下一个地址。</li>
<li>把新 primitive 写进去。</li>
<li>更新 summary。</li>
</ol>
<p>如果用 <code>[ ]</code> 表示空 TreeHeap，那么：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H0 = []
</span></span><span style="display:flex;"><span>H1 = plus(H0, p0)
</span></span><span style="display:flex;"><span>H2 = plus(H1, p1)
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>实际写入顺序是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>step 1: p0 -&gt; arr[0]
</span></span><span style="display:flex;"><span>step 2: p1 -&gt; arr[1]
</span></span><span style="display:flex;"><span>step 3: p2 -&gt; arr[2]
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>step 8: p7 -&gt; arr[7]
</span></span><span style="display:flex;"><span>step 9: p8 -&gt; arr[0]
</span></span><span style="display:flex;"><span>step 10: p9 -&gt; arr[1]
</span></span></code></pre></div><p>这就是 successor：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>n -&gt; n + 1
</span></span></code></pre></div><p>也是 mod fold：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>n + base -&gt; n
</span></span></code></pre></div><h2 id="信息量怎么测">信息量怎么测</h2>
<p>你说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[] 信息量是 0
</span></span><span style="display:flex;"><span>[cat] 信息量是 1
</span></span><span style="display:flex;"><span>[cat, run] 信息量是另一个值
</span></span></code></pre></div><p>这次 toy 先用最简单的信息量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I(H) = 非空节点数量
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I([]) = 0
</span></span><span style="display:flex;"><span>I([p0]) = 1
</span></span><span style="display:flex;"><span>I([p0, p1]) = 2
</span></span></code></pre></div><p>这个指标很粗。</p>
<p>但适合第一版 toy。</p>
<p>因为我们只是想验证：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>base 没满之前，plus 是否增加信息量？
</span></span></code></pre></div><p>实验结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>step 1: info 0 -&gt; 1
</span></span><span style="display:flex;"><span>step 2: info 1 -&gt; 2
</span></span><span style="display:flex;"><span>step 3: info 2 -&gt; 3
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>step 8: info 7 -&gt; 8
</span></span></code></pre></div><p>所以：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>info_gain_pre_base = true
</span></span></code></pre></div><p>到了 <code>base = 8</code> 以后，数组满了。</p>
<p>这时再 plus：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>step 9: p8 -&gt; arr[0]
</span></span></code></pre></div><p>它不是新增第 9 个格子。</p>
<p>它覆盖 <code>arr[0]</code>。</p>
<p>所以信息量保持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>8 -&gt; 8
</span></span></code></pre></div><p>实验结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>info_saturates_after_base = true
</span></span></code></pre></div><p>这说明 plus 有两个阶段：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>base 未满：信息增长
</span></span><span style="display:flex;"><span>base 已满：模折叠 / 覆盖 / 循环更新
</span></span></code></pre></div><h2 id="summary-是什么">summary 是什么</h2>
<p>实验里每个 primitive 是一个 64 维向量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p0, p1, ..., p9 ∈ R^64
</span></span></code></pre></div><p>TreeHeap 的 <code>summary</code> 也是一个向量。</p>
<p>但它不是主状态。</p>
<p>主状态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr
</span></span></code></pre></div><p>summary 是从 arr 算出来的投影：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>summary = summarize(arr)
</span></span></code></pre></div><p>代码里用了一个简单的地址敏感求和：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>summary = normalize(Σ roll(node.value, shift(index)))
</span></span></code></pre></div><p>这里用到了线性代数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>向量求和
</span></span><span style="display:flex;"><span>归一化
</span></span><span style="display:flex;"><span>向量距离
</span></span><span style="display:flex;"><span>余弦相似度
</span></span></code></pre></div><p><code>roll</code> 的意思是按地址改变向量坐标，让同一个 primitive 放在不同地址时，对 summary 的影响不同。</p>
<p>这相当于给地址一个位置编码。</p>
<p>实验检查：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>summary_consistency_ok = true
</span></span></code></pre></div><p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>summary 每次都确实等于 summarize(arr)，没有和 arr 脱节。
</span></span></code></pre></div><p>还有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>summary_min_delta = 0.4124
</span></span></code></pre></div><p>意思是每次 plus 后，summary 都发生了明显变化。</p>
<h2 id="kernel-是怎么测的">kernel 是怎么测的</h2>
<p>我们定义一个循环窗口：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>window(i) = [
</span></span><span style="display:flex;"><span>  arr[(i - 1) mod base],
</span></span><span style="display:flex;"><span>  arr[i],
</span></span><span style="display:flex;"><span>  arr[(i + 1) mod base]
</span></span><span style="display:flex;"><span>]
</span></span></code></pre></div><p>这就是一维卷积最小窗口：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[-1, 0, +1]
</span></span></code></pre></div><p>然后设置 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K = [p0, p1, p2]
</span></span></code></pre></div><p>在 base 填满后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[0] = p0
</span></span><span style="display:flex;"><span>arr[1] = p1
</span></span><span style="display:flex;"><span>arr[2] = p2
</span></span></code></pre></div><p>所以以 <code>i = 1</code> 为中心：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>window(1) = [arr[0], arr[1], arr[2]]
</span></span><span style="display:flex;"><span>          = [p0, p1, p2]
</span></span></code></pre></div><p>应该完全匹配。</p>
<p>实验结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel_hit_at_1 = 1.0
</span></span><span style="display:flex;"><span>kernel_top_score = 1.0
</span></span></code></pre></div><p>这说明循环 kernel 能在地址环上找到正确窗口。</p>
<h2 id="覆盖以后为什么分数下降">覆盖以后为什么分数下降</h2>
<p>第 9 步：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p8 -&gt; arr[0]
</span></span></code></pre></div><p>于是原来的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[p0, p1, p2]
</span></span></code></pre></div><p>变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[p8, p1, p2]
</span></span></code></pre></div><p>这时再用旧 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K = [p0, p1, p2]
</span></span></code></pre></div><p>去匹配，分数应该下降。</p>
<p>实验结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel_top_score = 1.0
</span></span><span style="display:flex;"><span>kernel_after_wrap_top_score = 0.6731
</span></span><span style="display:flex;"><span>wrap_breaks_old_kernel = true
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mod fold 不是空操作。
</span></span><span style="display:flex;"><span>它真的改变了局部结构。
</span></span></code></pre></div><p>这点重要。</p>
<p>因为如果折回以后 kernel 分数不变，说明地址环没有真正影响结构。</p>
<h2 id="概率论在这里怎么出现">概率论在这里怎么出现</h2>
<p>这次没有做复杂概率模型。</p>
<p>但有一个概率容器思想的前置形式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对每个 center 计算 kernel score
</span></span><span style="display:flex;"><span>然后按分数排序
</span></span></code></pre></div><p>这还不是 softmax 概率。</p>
<p>但它已经是概率容器之前的一步：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>候选位置集合 + 分数
</span></span></code></pre></div><p>下一步可以把分数变成概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P(i) = exp(score(i)) / Σ exp(score(j))
</span></span></code></pre></div><p>这就是本科概率论里常见的归一化思想。</p>
<p>先有 score。</p>
<p>再有 probability。</p>
<p>最后才有 collapse。</p>
<h2 id="这次到底-proof-了什么">这次到底 proof 了什么</h2>
<p>这次不是证明 TreeHeap 会推理。</p>
<p>它 proof 的是一个很窄的数学命题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在一个可寻址 TreeHeap toy 里，
</span></span><span style="display:flex;"><span>plus 可以被定义为 successor 写入；
</span></span><span style="display:flex;"><span>在 base 未满时增加信息量；
</span></span><span style="display:flex;"><span>在 base 满后按 mod 折回；
</span></span><span style="display:flex;"><span>循环窗口 kernel 可以在这个地址环上匹配局部模式。
</span></span></code></pre></div><p>对应实验结果全部通过：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>closure_ok = true
</span></span><span style="display:flex;"><span>root_ok = true
</span></span><span style="display:flex;"><span>successor_ok = true
</span></span><span style="display:flex;"><span>info_gain_pre_base = true
</span></span><span style="display:flex;"><span>info_saturates_after_base = true
</span></span><span style="display:flex;"><span>mod_fold_ok = true
</span></span><span style="display:flex;"><span>kernel_hit_at_1 = 1.0
</span></span><span style="display:flex;"><span>wrap_breaks_old_kernel = true
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-MATH02 作为 M0 toy 成立。
</span></span></code></pre></div><p>但这还不是语言 claim。</p>
<h2 id="这次没有证明什么">这次没有证明什么</h2>
<p>它没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实语义空间里一定有 primitive
</span></span><span style="display:flex;"><span>真实 TreeHeap checkpoint 已经学到 plus
</span></span><span style="display:flex;"><span>TreeHeap 会翻译
</span></span><span style="display:flex;"><span>TreeHeap 会推理
</span></span><span style="display:flex;"><span>kernel 能处理真实句子
</span></span></code></pre></div><p>这些都还要后续实验。</p>
<p>这次只是把地基往前铺了一格。</p>
<h2 id="下一步怎么走">下一步怎么走</h2>
<p>下一步应该做两个方向。</p>
<p>第一，把信息量从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>非空节点数量
</span></span></code></pre></div><p>升级为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rank
</span></span><span style="display:flex;"><span>entropy
</span></span><span style="display:flex;"><span>description length
</span></span><span style="display:flex;"><span>reconstruction bits
</span></span><span style="display:flex;"><span>distinguishability
</span></span></code></pre></div><p>第二，把 primitive 从人工 <code>p0,p1,...</code> 换成可学习的 basis：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned primitive basis
</span></span></code></pre></div><p>也就是问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型能不能自己找到那个类似“1”的基元？
</span></span></code></pre></div><p>然后才进入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap-object echo
</span></span><span style="display:flex;"><span>structure invariant
</span></span><span style="display:flex;"><span>S2 translation
</span></span></code></pre></div><h2 id="一句话">一句话</h2>
<p>这次实验把一句抽象话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 需要 primitive 和 plus 来生成有序性。
</span></span></code></pre></div><p>变成了可测 toy：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[0] 是 root。
</span></span><span style="display:flex;"><span>plus 写入下一个地址。
</span></span><span style="display:flex;"><span>base 前信息量增长。
</span></span><span style="display:flex;"><span>base 后按 mod 折回。
</span></span><span style="display:flex;"><span>kernel 能在循环地址环上滑动。
</span></span></code></pre></div><p>这就是进入 Echo 之前，TreeHeap 工具箱需要补上的数学基础。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-016] Trainability Quiz：TreeHeap 进入可学习系统之前的三道小题</title>
      <link>https://www.grepcode.cn/spr/016-trainability-quiz.html</link>
      <pubDate>Sun, 21 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/016-trainability-quiz.html</guid>
      <description>解释为什么在 WMT 之前先做线性回归、XOR、模加法三道 toy 训练题，以及这次实验怎样支撑 TreeHeap encoder/plus/decoder 的下一步设计。</description>
      <content:encoded><![CDATA[<h1 id="trainability-quiztreeheap-进入可学习系统之前的三道小题">Trainability Quiz：TreeHeap 进入可学习系统之前的三道小题</h1>
<p>这篇文章解释刚跑完的一个小实验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/src/trainability_quiz.py
</span></span></code></pre></div><p>它对应 ARA 里的一个新 predict：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-LEARN01: TreeHeap trainability quiz
</span></span></code></pre></div><p>这不是 WMT。
不是翻译实验。
也不是证明 TreeHeap 已经拥有语言理解能力。</p>
<p>它是一道“入门考试”：在真正训练 TreeHeap encoder、plus、decoder 之前，我们先问一个更朴素的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前这套最小学习框架，能不能学会基础函数？
</span></span></code></pre></div><p>如果连最简单的线性映射、XOR、模加法都学不会，那么直接去跑 WMT 只会得到一堆昂贵但难解释的 loss 曲线。</p>
<h2 id="先说结果">先说结果</h2>
<p>实验在 <code>ni</code> 上执行，使用的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Python 3.10
</span></span><span style="display:flex;"><span>NumPy
</span></span><span style="display:flex;"><span>manual gradients
</span></span><span style="display:flex;"><span>no PyTorch
</span></span><span style="display:flex;"><span>seed = 20260621
</span></span><span style="display:flex;"><span>base = 8
</span></span></code></pre></div><p>结果如下：</p>
<table>
  <thead>
      <tr>
          <th>任务</th>
          <th style="text-align: right">初始 loss</th>
          <th style="text-align: right">最终 loss</th>
          <th style="text-align: right">指标</th>
          <th>通过</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>linear_regression</td>
          <td style="text-align: right">3.7075966755</td>
          <td style="text-align: right">1.6516923159e-30</td>
          <td style="text-align: right">R2 = 1.0</td>
          <td>true</td>
      </tr>
      <tr>
          <td>xor</td>
          <td style="text-align: right">0.9064090912</td>
          <td style="text-align: right">0.0007663465</td>
          <td style="text-align: right">accuracy = 1.0</td>
          <td>true</td>
      </tr>
      <tr>
          <td>modular_addition</td>
          <td style="text-align: right">2.4380615125</td>
          <td style="text-align: right">0.0021191076</td>
          <td style="text-align: right">accuracy = 1.0</td>
          <td>true</td>
      </tr>
  </tbody>
</table>
<p>总结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pilot_pass = true
</span></span></code></pre></div><p>用人话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个最小训练系统可以学会：
</span></span><span style="display:flex;"><span>1. 连续空间里的线性关系
</span></span><span style="display:flex;"><span>2. 非线性逻辑关系
</span></span><span style="display:flex;"><span>3. 离散循环空间里的模加法关系
</span></span></code></pre></div><p>这给下一步 TreeHeap 数学工具箱一个基础信号：我们可以开始把 <code>plus</code>、<code>primitive</code>、<code>mod fold</code>、<code>addressable heap</code> 设计成可训练模块，而不是只停留在手写 toy 规则。</p>
<p>还有一个更重要的工程含义：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不是要推翻已有机器学习数学。
</span></span><span style="display:flex;"><span>TreeHeap 只是我们设计的一种高维可寻址结构。
</span></span></code></pre></div><p>所以我们已经知道有效的常识知识仍然有效。</p>
<p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>线性代数仍然有效
</span></span><span style="display:flex;"><span>梯度下降仍然有效
</span></span><span style="display:flex;"><span>非线性激活仍然有效
</span></span><span style="display:flex;"><span>交叉熵仍然有效
</span></span><span style="display:flex;"><span>分类任务仍然有效
</span></span><span style="display:flex;"><span>模运算、群、循环结构仍然有效
</span></span></code></pre></div><p>这件事会让研发轻很多。</p>
<p>因为 TreeHeap 不是从零发明一套完全陌生的数学宇宙。
它更像是在已有机器学习工具箱上，额外引入一个结构对象：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>addressable high-dimensional heap object
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>机器学习负责学习参数。
</span></span><span style="display:flex;"><span>TreeHeap 负责提供可寻址、高维、可组合的结构载体。
</span></span></code></pre></div><p>这样一来，我们后面可以继续使用本科到研究生阶段熟悉的数学工具，而不是每一步都陷入“这个东西有没有物理意义”的空转。</p>
<h2 id="treeheap-和一维实数有什么相似处">TreeHeap 和一维实数有什么相似处</h2>
<p>为了避免 TreeHeap 被理解成一个玄学名词，可以先把它和最熟悉的一维数作比较。</p>
<p>最简单的数学对象是一个实数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x in R
</span></span></code></pre></div><p>它有几个非常重要的性质。</p>
<p>第一，它可以表示状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x = 3.2
</span></span></code></pre></div><p>第二，它可以被操作：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x + 1
</span></span><span style="display:flex;"><span>2x
</span></span><span style="display:flex;"><span>x^2
</span></span></code></pre></div><p>第三，它可以被学习系统处理。
比如线性回归学的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>y = wx + b
</span></span></code></pre></div><p>这里的 <code>x</code> 是输入状态，<code>w</code> 和 <code>b</code> 是学习出来的参数。</p>
<p>TreeHeap 也有类似的一面。
它也是一个状态对象：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = TreeHeapState
</span></span></code></pre></div><p>它也可以被操作：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus(H, primitive)
</span></span><span style="display:flex;"><span>summarize(H)
</span></span><span style="display:flex;"><span>kernel_search(H, K)
</span></span></code></pre></div><p>它也应该可以被学习系统处理：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_{t+1} = learned_plus(H_t, p_t; theta)
</span></span></code></pre></div><p>所以从“机器学习能否处理它”的角度看，TreeHeap 并没有脱离常识数学。
它只是把输入从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个数 x
</span></span></code></pre></div><p>换成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个高维可寻址结构 H
</span></span></code></pre></div><p>这就是 <code>SPR-016</code> 为什么先做线性回归、XOR、模加法的原因。
这些 toy 任务确认的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>学习系统可以从样本中拟合函数。
</span></span></code></pre></div><p>只要 TreeHeap 的操作最后也能写成函数学习问题，那么已有 ML 工具就仍然能进入。</p>
<h2 id="增加高维结构以后多了什么">增加高维结构以后，多了什么</h2>
<p>但是 TreeHeap 和一维实数也有根本差异。</p>
<p>一维实数只有一个自由度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x = 3.2
</span></span></code></pre></div><p>它没有内部地址。
你不能问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x 的 root 在哪里？
</span></span><span style="display:flex;"><span>x 的 left child 是什么？
</span></span><span style="display:flex;"><span>x 的 cursor 指向哪里？
</span></span></code></pre></div><p>这些问题对实数没有意义。</p>
<p>TreeHeap 不一样。
它不是单个标量，而是一个结构对象：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeapState = {
</span></span><span style="display:flex;"><span>  arr: Node[]
</span></span><span style="display:flex;"><span>  root: arr[0]
</span></span><span style="display:flex;"><span>  cursor: int
</span></span><span style="display:flex;"><span>  base: int
</span></span><span style="display:flex;"><span>  summary: vector
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这带来了几个新增能力。</p>
<h3 id="1-可寻址性">1. 可寻址性</h3>
<p>一维实数没有地址。</p>
<p>TreeHeap 有地址：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[0], arr[1], arr[2], ...
</span></span></code></pre></div><p>所以 TreeHeap 可以表达：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>某个信息写在 root
</span></span><span style="display:flex;"><span>某个信息写在 left child
</span></span><span style="display:flex;"><span>某个信息写在 next cursor
</span></span></code></pre></div><p>这让它更像一个数据结构，而不是一个普通数值。</p>
<h3 id="2-局部结构">2. 局部结构</h3>
<p>实数上做局部窗口没有自然意义。</p>
<p>但 TreeHeap 可以定义局部子结构：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; (left, right)
</span></span></code></pre></div><p>或者循环窗口：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[arr[i-1], arr[i], arr[i+1]]
</span></span></code></pre></div><p>这就是 TreeHeap kernel search 的来源。
它和卷积里的窗口很像，但窗口滑动的空间不再只是普通一维数组，而是 TreeHeap 的地址结构。</p>
<h3 id="3-多维负载">3. 多维负载</h3>
<p>一维实数只能承载一个标量。</p>
<p>TreeHeap 的每个节点可以承载向量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node.value in R^d
</span></span></code></pre></div><p>所以它可以同时保存：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语义信息
</span></span><span style="display:flex;"><span>结构位置
</span></span><span style="display:flex;"><span>局部上下文
</span></span><span style="display:flex;"><span>历史写入痕迹
</span></span></code></pre></div><p>这就接近我们之前说的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>球 + 脚 -&gt; 足球
</span></span><span style="display:flex;"><span>球 + 手 -&gt; 篮球
</span></span></code></pre></div><p>单独一个“球”的向量不够。
它要进入不同背景、不同位置、不同操作关系，才形成不同对象。</p>
<h3 id="4-summary-只是投影">4. summary 只是投影</h3>
<p>一维实数里，数值本身就是对象：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x = 3.2
</span></span></code></pre></div><p>TreeHeap 里，<code>summary</code> 不是完整对象。
完整对象是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr + cursor + base + root relation + node values
</span></span></code></pre></div><p><code>summary</code> 只是一个投影：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>summary = summarize(arr)
</span></span></code></pre></div><p>这点非常关键。</p>
<p>如果把 <code>summary</code> 当成整个 TreeHeap，就会把一个高维可寻址结构压扁成普通向量。
那样很多结构信息会丢失。</p>
<h2 id="一个对比表">一个对比表</h2>
<table>
  <thead>
      <tr>
          <th>维度</th>
          <th>一维实数</th>
          <th>TreeHeap</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>基本对象</td>
          <td><code>x in R</code></td>
          <td><code>H = TreeHeapState</code></td>
      </tr>
      <tr>
          <td>内部结构</td>
          <td>无</td>
          <td>有 <code>arr/root/cursor/base</code></td>
      </tr>
      <tr>
          <td>地址</td>
          <td>无</td>
          <td>有 <code>arr[i]</code></td>
      </tr>
      <tr>
          <td>操作</td>
          <td><code>+</code>, <code>*</code>, function</td>
          <td><code>plus</code>, <code>summarize</code>, <code>kernel_search</code></td>
      </tr>
      <tr>
          <td>局部窗口</td>
          <td>不自然</td>
          <td>可定义子树或地址窗口</td>
      </tr>
      <tr>
          <td>学习方式</td>
          <td>学 <code>f(x; theta)</code></td>
          <td>学 <code>F(H; theta)</code></td>
      </tr>
      <tr>
          <td>信息负载</td>
          <td>一个标量</td>
          <td>多节点、多向量、多关系</td>
      </tr>
      <tr>
          <td>投影</td>
          <td>数值本身</td>
          <td><code>summary</code> 是投影，不是整体</td>
      </tr>
  </tbody>
</table>
<p>所以 TreeHeap 的定位可以更准确地说成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它不是比实数更神秘的东西。
</span></span><span style="display:flex;"><span>它是比实数多了地址、局部结构和高维负载的状态对象。
</span></span></code></pre></div><p>数学常识仍然有效。
但因为对象更复杂，我们需要更多工具：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>线性代数处理 node vector
</span></span><span style="display:flex;"><span>概率论处理候选结构
</span></span><span style="display:flex;"><span>群/模运算处理循环地址
</span></span><span style="display:flex;"><span>图和树处理局部关系
</span></span><span style="display:flex;"><span>机器学习处理可训练算子
</span></span></code></pre></div><p>这就是 TreeHeap 研发工具箱的来源。</p>
<h2 id="为什么不直接跑-wmt">为什么不直接跑 WMT</h2>
<p>WMT 是最终方向，但不是最合适的第一道验证题。</p>
<p>翻译任务里同时混在一起的东西太多：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tokenization
</span></span><span style="display:flex;"><span>encoder
</span></span><span style="display:flex;"><span>decoder
</span></span><span style="display:flex;"><span>alignment
</span></span><span style="display:flex;"><span>syntax
</span></span><span style="display:flex;"><span>semantics
</span></span><span style="display:flex;"><span>training objective
</span></span><span style="display:flex;"><span>beam search
</span></span><span style="display:flex;"><span>evaluation metric
</span></span><span style="display:flex;"><span>data quality
</span></span></code></pre></div><p>如果 WMT loss 降不下来，我们很难判断到底是哪一层错了。</p>
<p>可能是 TreeHeap 的代数设计错了。
可能是 encoder 没学到。
可能是 decoder 不够。
可能是 loss 不适合。
也可能只是数据管线有问题。</p>
<p>所以这次我们先把问题切小：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在不碰真实语言的情况下，
</span></span><span style="display:flex;"><span>训练系统能不能学会几个确定答案的数学任务？
</span></span></code></pre></div><p>这就是标准机器学习里的 sanity check。
本科做线性回归、逻辑回归、XOR、多分类，不是因为这些任务伟大，而是因为它们能检查训练系统的基本生命体征。</p>
<h2 id="三道小题分别检查什么">三道小题分别检查什么</h2>
<h3 id="第一题线性回归">第一题：线性回归</h3>
<p>线性回归检查的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>y = Wx + b
</span></span></code></pre></div><p>模型能不能用梯度下降学到一个线性映射。</p>
<p>这对应 TreeHeap 里的基础问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个 TreeHeap summary 或 node vector，
</span></span><span style="display:flex;"><span>能不能被稳定映射到另一个目标空间？
</span></span></code></pre></div><p>如果线性回归都失败，那么后面谈世界模型、拓扑弯曲、结构空间就太早了。</p>
<p>这次结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>final_loss = 1.6516923158620557e-30
</span></span><span style="display:flex;"><span>R2 = 1.0
</span></span></code></pre></div><p>这说明最小梯度系统对连续线性映射没有问题。</p>
<h3 id="第二题xor">第二题：XOR</h3>
<p>XOR 是经典非线性任务。</p>
<p>输入输出是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0 xor 0 = 0
</span></span><span style="display:flex;"><span>0 xor 1 = 1
</span></span><span style="display:flex;"><span>1 xor 0 = 1
</span></span><span style="display:flex;"><span>1 xor 1 = 0
</span></span></code></pre></div><p>它不能被一条直线分开。
所以单层线性模型做不好 XOR，必须有非线性变换。</p>
<p>这道题检查的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型是否能通过隐藏层和非线性激活，
</span></span><span style="display:flex;"><span>学会一个不是简单线性投影的关系。
</span></span></code></pre></div><p>这和我们之前讨论的“echo 型函数”很相关。</p>
<p>如果一个模型只是把输入原样保存下来，它最多是信息保存器。
但世界模型不只是保存信息。
它还要改变表示空间，让一些关系变近，让另一些关系变远。</p>
<p>XOR 不能证明模型已经有世界模型，但它至少证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>训练系统能学非线性关系，
</span></span><span style="display:flex;"><span>不是只能做输入 echo。
</span></span></code></pre></div><p>这次结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>final_loss = 0.0007663465151399971
</span></span><span style="display:flex;"><span>accuracy = 1.0
</span></span></code></pre></div><h3 id="第三题模-8-加法">第三题：模 8 加法</h3>
<p>这是这次最贴近 TreeHeap 的题。</p>
<p>任务是学习：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>(a + b) mod 8
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>3 + 4 = 7
</span></span><span style="display:flex;"><span>5 + 6 = 11
</span></span><span style="display:flex;"><span>11 mod 8 = 3
</span></span><span style="display:flex;"><span>所以 (5 + 6) mod 8 = 3
</span></span></code></pre></div><p>为什么它重要？</p>
<p>因为我们前面讨论 TreeHeap 的 <code>plus</code> 时，已经把一个关键结构拆成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus = successor + information gain + mod fold
</span></span></code></pre></div><p>其中 <code>mod fold</code> 就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>超过 base 后折回前面的地址
</span></span></code></pre></div><p>如果模型连一个小小的 <code>Z / 8Z</code> 循环群表都学不会，那就不要急着说 TreeHeap 可以学会地址折叠、循环窗口、卷积式 kernel search。</p>
<p>这次结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>base = 8
</span></span><span style="display:flex;"><span>final_loss = 0.0021191076117503013
</span></span><span style="display:flex;"><span>accuracy = 1.0
</span></span></code></pre></div><p>混淆矩阵是完全对角的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>每个真实类别都被预测成自己，没有串类。
</span></span></code></pre></div><p>这说明模型学会了完整的 base-8 模加法表。</p>
<h2 id="这和-treeheap-有什么关系">这和 TreeHeap 有什么关系</h2>
<p>前一篇 <code>SPR-015</code> 证明的是手写 toy：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[0] 是 root
</span></span><span style="display:flex;"><span>plus 写入下一个地址
</span></span><span style="display:flex;"><span>base 前信息量增加
</span></span><span style="display:flex;"><span>base 后按 mod 折回
</span></span><span style="display:flex;"><span>kernel 可以在循环地址环上滑动
</span></span></code></pre></div><p>那是一个规则系统。</p>
<p>这篇 <code>SPR-016</code> 问的是另一个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这些规则有没有机会被模型学出来？
</span></span></code></pre></div><p>也就是从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>手写 plus(H, primitive)
</span></span></code></pre></div><p>走向：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned_plus(H, primitive; theta)
</span></span></code></pre></div><p>这里的 <code>theta</code> 就是参数。</p>
<p>Transformer 的关键不是矩阵本身，而是参数矩阵能被梯度更新。
学习发生在参数里。</p>
<p>TreeHeap 如果也要变成机器学习系统，而不只是数据结构，就必须有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder theta_e
</span></span><span style="display:flex;"><span>plus theta_p
</span></span><span style="display:flex;"><span>decoder theta_d
</span></span><span style="display:flex;"><span>loss
</span></span><span style="display:flex;"><span>gradient
</span></span><span style="display:flex;"><span>update
</span></span></code></pre></div><p>这次 trainability quiz 只是确认：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>最小训练管线可以通过梯度学函数。
</span></span></code></pre></div><p>它还没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的真实 plus 已经学出来。
</span></span></code></pre></div><p>但它允许我们进入下一步。</p>
<p>这一点也修正了 TreeHeap 的定位。</p>
<p>TreeHeap 本身不是一个会自动产生知识的魔法容器。
它是一种结构设计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把向量、地址、root、cursor、base、summary 组织成可操作对象。
</span></span></code></pre></div><p>真正的知识仍然要通过学习进入参数。
也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数据
</span></span><span style="display:flex;"><span>-&gt; loss
</span></span><span style="display:flex;"><span>-&gt; gradient
</span></span><span style="display:flex;"><span>-&gt; parameter update
</span></span><span style="display:flex;"><span>-&gt; learned operator
</span></span></code></pre></div><p>Transformer 是这样，TreeHeap 也应该是这样。</p>
<p>区别只在于：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Transformer 主要学习矩阵上的序列映射。
</span></span><span style="display:flex;"><span>TreeHeap 希望学习高维堆对象上的结构操作。
</span></span></code></pre></div><p>所以这次实验还证明了一件朴素但重要的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们不用放弃已有 ML 常识。
</span></span><span style="display:flex;"><span>我们只是把这些常识接到 TreeHeap 结构上。
</span></span></code></pre></div><h2 id="为什么使用-numpy-手写梯度">为什么使用 NumPy 手写梯度</h2>
<p>这次没有用 PyTorch。</p>
<p>原因很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ni 上当前 Python 环境有 NumPy，但没有 torch。
</span></span></code></pre></div><p>所以实验使用手写反向传播。</p>
<p>这反而有一个好处：所有东西都很透明。</p>
<p>我们没有把问题交给框架魔法。
每个任务都能看见：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>forward
</span></span><span style="display:flex;"><span>loss
</span></span><span style="display:flex;"><span>gradient
</span></span><span style="display:flex;"><span>parameter update
</span></span></code></pre></div><p>对于 M0 数学工具箱来说，这种透明性比一开始追求大模型训练更重要。</p>
<h2 id="这次实验证明了什么">这次实验证明了什么</h2>
<p>它证明的是一个很窄的命题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在当前最小训练代码里，
</span></span><span style="display:flex;"><span>小型可训练模块可以学会线性映射、XOR、base-8 模加法。
</span></span></code></pre></div><p>所以我们可以合理继续设计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>trainable TreeHeap encoder
</span></span><span style="display:flex;"><span>trainable TreeHeap plus
</span></span><span style="display:flex;"><span>trainable TreeHeap decoder
</span></span></code></pre></div><p>尤其是 <code>plus</code>。</p>
<p>因为 <code>plus</code> 不是普通向量加法。
它更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在一个可寻址 TreeHeap 结构里，
</span></span><span style="display:flex;"><span>把 primitive 写入下一个位置，
</span></span><span style="display:flex;"><span>更新 summary，
</span></span><span style="display:flex;"><span>并在 base 满后发生 mod fold。
</span></span></code></pre></div><p>这次的模加法任务说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>小模型至少可以学会离散循环结构。
</span></span></code></pre></div><p>这对 TreeHeap 的地址环、循环窗口和 kernel search 是正向证据。</p>
<h2 id="这次没有证明什么">这次没有证明什么</h2>
<p>它没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经会翻译
</span></span><span style="display:flex;"><span>TreeHeap 已经拥有世界模型
</span></span><span style="display:flex;"><span>TreeHeap 已经学会真实语言语义
</span></span><span style="display:flex;"><span>TreeHeap checkpoint 是可靠的
</span></span><span style="display:flex;"><span>CMul 一定能形成拓扑扭曲
</span></span></code></pre></div><p>这些都还没有。</p>
<p>这次只是一个入口实验。</p>
<p>如果把研发路线比作爬楼，这次不是到了顶楼。
它只是确认：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>楼梯是实的，不是一张画。
</span></span></code></pre></div><h2 id="下一步怎么走">下一步怎么走</h2>
<p>下一步我建议做 <code>P-LEARN02</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Trainable TreeHeap Plus
</span></span></code></pre></div><p>目标不是语言。
还是 toy。</p>
<p>输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_t
</span></span><span style="display:flex;"><span>primitive p_t
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_{t+1}
</span></span></code></pre></div><p>其中 <code>H_t</code> 必须包含可寻址结构：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr
</span></span><span style="display:flex;"><span>cursor
</span></span><span style="display:flex;"><span>base
</span></span><span style="display:flex;"><span>summary
</span></span></code></pre></div><p>训练目标可以分成三项：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. target address loss
</span></span><span style="display:flex;"><span>   模型要知道下一个写入地址在哪里
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>2. reconstruction loss
</span></span><span style="display:flex;"><span>   模型要能重建更新后的 arr 或 summary
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>3. mod fold loss
</span></span><span style="display:flex;"><span>   base 满后，模型要学会折回 arr[0], arr[1], ...
</span></span></code></pre></div><p>如果 <code>P-LEARN02</code> 成立，我们才进入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap-object echo
</span></span></code></pre></div><p>也就是让模型不仅输出向量，而是输出一个仍然可读、可写、可比较的 TreeHeap 对象。</p>
<p>再之后才是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>structure invariant
</span></span><span style="display:flex;"><span>S2 translation
</span></span><span style="display:flex;"><span>WMT
</span></span></code></pre></div><h2 id="ara-记录在哪里">ARA 记录在哪里</h2>
<p>这次实验的 ARA 目录是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/
</span></span></code></pre></div><p>公开镜像同步到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>https://github.com/houming818/sametime/tree/main/ara/m0-treeheap-math
</span></span></code></pre></div><p>关键 evidence：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>evidence/trainability_quiz/summary.json
</span></span><span style="display:flex;"><span>evidence/trainability_quiz/README.md
</span></span></code></pre></div><p>对应代码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>src/trainability_quiz.py
</span></span></code></pre></div><h2 id="一句话">一句话</h2>
<p><code>SPR-015</code> 证明了一个手写 TreeHeap toy 可以拥有 <code>plus + mod fold + kernel search</code>。</p>
<p><code>SPR-016</code> 证明了最小训练系统可以学会基础连续映射、非线性逻辑和模加法。</p>
<p>所以现在的路线不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>直接拿 TreeHeap 去碰 WMT。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先把 TreeHeap 的数学工具箱做成可学习对象，
</span></span><span style="display:flex;"><span>再让语言任务站在这个工具箱上。
</span></span></code></pre></div><blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-017] TreeHeap 的存在性证明：把 Claim 说清楚</title>
      <link>https://www.grepcode.cn/spr/017-treeheap-existence-proofs.html</link>
      <pubDate>Sun, 21 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/017-treeheap-existence-proofs.html</guid>
      <description>修正 TreeHeap proof 的三个 claim：循环寻址不是普通加法，A 是学习器归纳边界，B 是子结构 kernel，C 是前缀压缩和概率容器。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-的存在性证明把-claim-说清楚">TreeHeap 的存在性证明：把 Claim 说清楚</h1>
<p>上一篇 <code>SPR-016</code> 讲了一件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不是要推翻机器学习。
</span></span><span style="display:flex;"><span>TreeHeap 是把机器学习接到一种高维、可寻址、可组合的结构对象上。
</span></span></code></pre></div><p>所以它和 Transformer 在大范式上是相通的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>固定数学算子
</span></span><span style="display:flex;"><span>+ 可学习参数
</span></span><span style="display:flex;"><span>+ loss
</span></span><span style="display:flex;"><span>+ gradient
</span></span><span style="display:flex;"><span>+ update
</span></span></code></pre></div><p>Transformer 里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>matmul / softmax / residual add 是固定算子
</span></span><span style="display:flex;"><span>Wq / Wk / Wv / FFN 是可学习参数
</span></span></code></pre></div><p>TreeHeap 里我们现在倾向于这样分层：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus / address / subheap / kernel_search / fold 是固定算子候选
</span></span><span style="display:flex;"><span>arr.value / primitive basis / world model slots 是可学习参数
</span></span></code></pre></div><p>但这里必须非常谨慎。</p>
<p>我们上一版实验 A 把这个规则放进去了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>target = (cursor + 1) mod base
</span></span></code></pre></div><p>这不是普通整数加法。</p>
<p>普通整数里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>11 + 2 = 13
</span></span></code></pre></div><p>它不等于：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>3
</span></span></code></pre></div><p>只有当我们明确进入模系统时，才能说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>13 ≡ 3 (mod 10)
</span></span></code></pre></div><p>也就是说，<code>mod base</code> 不是“加法天然要折叠”，而是一个有限容量系统里的回绕规则。它更像 circular buffer：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cursor = (cursor + 1) mod base
</span></span><span style="display:flex;"><span>arr[cursor] = value
</span></span></code></pre></div><p>所以当前实验 A 不能被说成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>证明了 TreeHeap plus。
</span></span></code></pre></div><p>它只能被说成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>证明了学习器在模地址回绕 toy task 上的归纳边界。
</span></span></code></pre></div><p>这篇文章就是把三个实验的 claim 重新钉牢。</p>
<h2 id="三个实验到底在-claim-什么">三个实验到底在 Claim 什么</h2>
<p>先给结论。</p>
<table>
  <thead>
      <tr>
          <th>实验</th>
          <th>当前真正测的东西</th>
          <th>当前能 claim 什么</th>
          <th>当前不能 claim 什么</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A</td>
          <td>circular addressing toy task</td>
          <td>普通学习器从短样本模仿模地址规则时存在归纳边界</td>
          <td>不能证明完整 TreeHeap plus/fold，不能证明 TreeHeap learner 已经赢</td>
      </tr>
      <tr>
          <td>B</td>
          <td>subheap kernel relocation</td>
          <td>显式树堆地址上的局部 kernel 可以稳定迁移</td>
          <td>不能证明语言结构已经学会</td>
      </tr>
      <tr>
          <td>C</td>
          <td>prefix compression + probability container</td>
          <td>共享路径前缀可以压缩 toy 分布，并保留候选概率</td>
          <td>不能证明真实语言翻译质量提升</td>
      </tr>
  </tbody>
</table>
<p>这三个实验现在只是数学工具箱的第一层 toy proof。它们不是 WMT 证明，也不是 TreeHeap 语言模型证明。</p>
<h2 id="实验-a循环寻址规则的归纳边界">实验 A：循环寻址规则的归纳边界</h2>
<h3 id="当前-a-实际做了什么">当前 A 实际做了什么</h3>
<p>当前 A 的状态是一个有限容器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>State = {
</span></span><span style="display:flex;"><span>  arr,
</span></span><span style="display:flex;"><span>  root = arr[0],
</span></span><span style="display:flex;"><span>  cursor,
</span></span><span style="display:flex;"><span>  base,
</span></span><span style="display:flex;"><span>  summary
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>当前 A 的写入规则是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>circular_write(H, p):
</span></span><span style="display:flex;"><span>  target = (cursor + 1) mod base
</span></span><span style="display:flex;"><span>  arr[target] = p
</span></span><span style="display:flex;"><span>  cursor = target
</span></span><span style="display:flex;"><span>  summary = summarize(arr)
</span></span><span style="display:flex;"><span>  return H
</span></span></code></pre></div><p>这个规则有闭包：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H 是有限状态容器
</span></span><span style="display:flex;"><span>circular_write(H, p) 仍然是有限状态容器
</span></span></code></pre></div><p>但是它不是普通加法，也不是完整 TreeHeap plus。</p>
<p>更准确地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus:
</span></span><span style="display:flex;"><span>  n -&gt; n + 1
</span></span><span style="display:flex;"><span>  不折叠。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mod plus:
</span></span><span style="display:flex;"><span>  n -&gt; (n + 1) mod base
</span></span><span style="display:flex;"><span>  有限容量回绕。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fold plus:
</span></span><span style="display:flex;"><span>  容量满后不是简单覆盖，而是把旧结构折叠进 summary / parent node。
</span></span></code></pre></div><p>当前 A 只做了第二种：<code>mod plus</code>。</p>
<h3 id="a-的训练操作">A 的训练操作</h3>
<p>脚本生成很多 primitive 序列：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[p0, p1, p2, ..., pn]
</span></span></code></pre></div><p>然后用固定规则生成答案：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>target_address = (length - 1) mod base
</span></span><span style="display:flex;"><span>read_value = 最后一次写入 query_addr 的 token
</span></span></code></pre></div><p>训练时只给短序列：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train length &lt;= 8
</span></span></code></pre></div><p>测试时给：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>test length = 8 / 16 / 32 / 64
</span></span></code></pre></div><p>参与训练的模型是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flatten MLP
</span></span><span style="display:flex;"><span>small Transformer
</span></span></code></pre></div><p>还有一个 <code>rule oracle</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rule oracle = 直接执行 circular_write 的参考实现
</span></span></code></pre></div><p>这个 <code>rule oracle</code> 不是训练出来的 TreeHeap 模型。它只是标准答案生成器。</p>
<p>所以 A 的有效证据不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap learner 取得 1.0。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>MLP / Transformer 在模地址规则上，从短样本外推到长样本时会出现边界。
</span></span></code></pre></div><h3 id="a-的-8-小时结果">A 的 8 小时结果</h3>
<p>flatten MLP 的读值能力：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">test length</th>
          <th style="text-align: right">read accuracy</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">0.1827</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">0.0593</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">0.0567</td>
      </tr>
      <tr>
          <td style="text-align: right">64</td>
          <td style="text-align: right">0.0406</td>
      </tr>
  </tbody>
</table>
<p>small Transformer 的 address accuracy：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">test length</th>
          <th style="text-align: right">address accuracy</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">0.9997</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">0.9955</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">0.9804</td>
      </tr>
      <tr>
          <td style="text-align: right">64</td>
          <td style="text-align: right">0.9292</td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>MLP 没有稳定学会 read-after-overwrite。
</span></span><span style="display:flex;"><span>Transformer 更强，但在长长度上也有下降和失败样本。
</span></span></code></pre></div><h3 id="a-的准确-claim">A 的准确 Claim</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Claim A:
</span></span><span style="display:flex;"><span>在 circular addressing toy task 上，
</span></span><span style="display:flex;"><span>普通学习器从短样本模仿规则时存在归纳边界。
</span></span></code></pre></div><p>A 不能 claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整 TreeHeap plus 已经成立。
</span></span><span style="display:flex;"><span>完整 TreeHeap fold 已经成立。
</span></span><span style="display:flex;"><span>TreeHeap learner 已经优于 Transformer。
</span></span></code></pre></div><p>下一步必须把 A 拆成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A1: unbounded successor
</span></span><span style="display:flex;"><span>    11 + 2 = 13，不做 mod。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>A2: bounded circular addressing
</span></span><span style="display:flex;"><span>    13 ≡ 3 (mod 10)，这是有限容量回绕。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>A3: fold write
</span></span><span style="display:flex;"><span>    容量满后做结构折叠，不是简单覆盖。
</span></span></code></pre></div><p>这才是严谨的 TreeHeap algebra proof。</p>
<h2 id="实验-b子结构-kernel-搜索">实验 B：子结构 Kernel 搜索</h2>
<h3 id="b-实际做了什么">B 实际做了什么</h3>
<p>B 定义一个局部模式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>      A
</span></span><span style="display:flex;"><span>     / \
</span></span><span style="display:flex;"><span>    B   C
</span></span></code></pre></div><p>在数组里就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[arr[i], arr[left(i)], arr[right(i)]]
</span></span></code></pre></div><p>训练时 pattern 只出现在：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train positions = {0, 1, 2}
</span></span></code></pre></div><p>测试时放到新地址：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>test positions = {6, 10, 13}
</span></span></code></pre></div><p>TreeHeap kernel 的做法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>for each address i:
</span></span><span style="display:flex;"><span>  sub = subheap(H, i)
</span></span><span style="display:flex;"><span>  score[i] = match(sub, K)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>answer = max(score)
</span></span></code></pre></div><p>这就是树堆空间里的卷积。</p>
<h3 id="b-的-8-小时结果">B 的 8 小时结果</h3>
<table>
  <thead>
      <tr>
          <th>method</th>
          <th style="text-align: right">accuracy mean</th>
          <th style="text-align: right">min</th>
          <th style="text-align: right">max</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap kernel</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>flatten MLP</td>
          <td style="text-align: right">0.4996</td>
          <td style="text-align: right">0.4258</td>
          <td style="text-align: right">0.5703</td>
      </tr>
      <tr>
          <td>sequence CNN</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>small Transformer</td>
          <td style="text-align: right">0.9846</td>
          <td style="text-align: right">0.6055</td>
          <td style="text-align: right">1.0000</td>
      </tr>
  </tbody>
</table>
<p>这组结果不能被解释成“只有 TreeHeap 能做”。CNN 也满分，说明这个任务本质就是局部 kernel 迁移。</p>
<p>更准确的解释是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>局部模式 + 可复用 kernel 是强归纳偏置。
</span></span><span style="display:flex;"><span>TreeHeap 的价值在于把这种 kernel 从线性/网格空间推广到树堆地址空间。
</span></span></code></pre></div><h3 id="b-的准确-claim">B 的准确 Claim</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Claim B:
</span></span><span style="display:flex;"><span>如果局部模式定义在树堆地址上，
</span></span><span style="display:flex;"><span>显式 subheap kernel 可以稳定做 relocation。
</span></span></code></pre></div><p>B 能支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可以拥有类似卷积的结构算子。
</span></span></code></pre></div><p>B 不能支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语言结构已经学会。
</span></span><span style="display:flex;"><span>复杂树变换已经解决。
</span></span><span style="display:flex;"><span>TreeHeap 在所有结构任务上优于 Transformer。
</span></span></code></pre></div><p>下一步 B 要加难度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>新深度
</span></span><span style="display:flex;"><span>兄弟交换
</span></span><span style="display:flex;"><span>局部噪声
</span></span><span style="display:flex;"><span>缺失子节点
</span></span><span style="display:flex;"><span>多 kernel 同时存在
</span></span><span style="display:flex;"><span>kernel composition
</span></span></code></pre></div><h2 id="实验-c前缀压缩和延迟坍缩">实验 C：前缀压缩和延迟坍缩</h2>
<h3 id="c-实际做了什么">C 实际做了什么</h3>
<p>C 构造共享前缀序列，例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A B C X
</span></span><span style="display:flex;"><span>A B C Y
</span></span><span style="display:flex;"><span>A B D X
</span></span><span style="display:flex;"><span>A B D Y
</span></span><span style="display:flex;"><span>A E F X
</span></span></code></pre></div><p>普通序列会重复保存这些路径。</p>
<p>前缀树可以共享：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A
</span></span><span style="display:flex;"><span>├── B
</span></span><span style="display:flex;"><span>│   ├── C
</span></span><span style="display:flex;"><span>│   │   ├── X
</span></span><span style="display:flex;"><span>│   │   └── Y
</span></span><span style="display:flex;"><span>│   └── D
</span></span><span style="display:flex;"><span>│       ├── X
</span></span><span style="display:flex;"><span>│       └── Y
</span></span><span style="display:flex;"><span>└── E
</span></span><span style="display:flex;"><span>    └── F
</span></span><span style="display:flex;"><span>        └── X
</span></span></code></pre></div><p>共享前缀意味着可以共享：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>存储
</span></span><span style="display:flex;"><span>计算
</span></span><span style="display:flex;"><span>summary
</span></span><span style="display:flex;"><span>候选概率
</span></span></code></pre></div><p>给定前缀：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A B C
</span></span></code></pre></div><p>后面可能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>X or Y
</span></span></code></pre></div><p>TreeHeap 可以在前缀节点上保留候选概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A-B-C -&gt; {
</span></span><span style="display:flex;"><span>  X: 0.5
</span></span><span style="display:flex;"><span>  Y: 0.5
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这就是概率容器。它不急着 <code>argmax</code>，而是等待更多上下文。</p>
<h3 id="c-的-8-小时结果">C 的 8 小时结果</h3>
<table>
  <thead>
      <tr>
          <th>metric</th>
          <th style="text-align: right">value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>sequence_node_count</td>
          <td style="text-align: right">800</td>
      </tr>
      <tr>
          <td>prefix_tree_node_count</td>
          <td style="text-align: right">11</td>
      </tr>
      <tr>
          <td>compression_ratio_mean</td>
          <td style="text-align: right">72.7273</td>
      </tr>
      <tr>
          <td>prefix_reuse_rate_mean</td>
          <td style="text-align: right">0.98625</td>
      </tr>
      <tr>
          <td>new_branch_Z_probability_after_one_mean</td>
          <td style="text-align: right">0.01249</td>
      </tr>
  </tbody>
</table>
<p>这说明在这个 toy 分布里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>800 个普通序列节点
</span></span><span style="display:flex;"><span>可以压成 11 个前缀树节点。
</span></span></code></pre></div><p>新分支 <code>Z</code> 出现一次后，没有直接覆盖旧候选，而是以小概率进入候选容器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P(Z) ≈ 0.01249
</span></span></code></pre></div><h3 id="c-的准确-claim">C 的准确 Claim</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Claim C:
</span></span><span style="display:flex;"><span>共享路径前缀可以显著压缩 toy 分布，
</span></span><span style="display:flex;"><span>并且可以在前缀节点保留候选概率。
</span></span></code></pre></div><p>C 能支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的路径不是普通 token 序列。
</span></span><span style="display:flex;"><span>路径前缀可以成为存储、计算、概率容器的共享对象。
</span></span></code></pre></div><p>C 不能支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实语言中的前缀压缩率也这么高。
</span></span><span style="display:flex;"><span>delayed collapse 已经提升翻译质量。
</span></span><span style="display:flex;"><span>概率容器已经学会语义消歧。
</span></span></code></pre></div><p>下一步 C 要提高难度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>更多分支
</span></span><span style="display:flex;"><span>更高 entropy
</span></span><span style="display:flex;"><span>更少重复
</span></span><span style="display:flex;"><span>上下文反转候选概率
</span></span><span style="display:flex;"><span>概率校准
</span></span><span style="display:flex;"><span>delayed-collapse accuracy
</span></span></code></pre></div><h2 id="总结现在我们到底知道什么">总结：现在我们到底知道什么</h2>
<p>现在最稳的结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的存在性还没有被完整证明。
</span></span><span style="display:flex;"><span>但是三个 toy 实验给出了三个方向的信号。
</span></span></code></pre></div><p>这三个方向分别是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A: 地址规则不应该完全靠模型从样本里猜。
</span></span><span style="display:flex;"><span>B: 子结构 kernel 可以成为树堆空间的卷积工具。
</span></span><span style="display:flex;"><span>C: 路径前缀可以成为压缩和概率容器。
</span></span></code></pre></div><p>更严谨地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的 claim 不是“我也能学习”。
</span></span><span style="display:flex;"><span>Transformer 也能学习。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TreeHeap 的 claim 是：
</span></span><span style="display:flex;"><span>如果把地址、子结构、路径前缀、概率容器做成显式数学对象，
</span></span><span style="display:flex;"><span>模型可能获得更好的结构归纳偏置。
</span></span></code></pre></div><p>但这还需要下一轮 proof：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A1/A2/A3: plus / mod / fold 拆分
</span></span><span style="display:flex;"><span>B2: kernel composition 和结构变换
</span></span><span style="display:flex;"><span>C2: 高熵概率容器和上下文坍缩
</span></span></code></pre></div><p>只有这些 proof 更稳以后，语言任务才应该站在这个数学工具箱上。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-018] TreeHeap 的存在性：编码结构与共轭 Kernel</title>
      <link>https://www.grepcode.cn/spr/018-treeheap-structural-inductive-bias.html</link>
      <pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/018-treeheap-structural-inductive-bias.html</guid>
      <description>修正 TreeHeap 的核心 claim：不是简单 pattern matching，而是学习可搜索、可压缩的编码结构，并用共轭 kernel 完成查询和解码。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-的存在性编码结构与共轭-kernel">TreeHeap 的存在性：编码结构与共轭 Kernel</h1>
<p>这篇文章修正一个重要问题。</p>
<p>上一版 <code>SPR-018</code> 把重点放在了 <code>subheap kernel relocation</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定一个人工 pattern，
</span></span><span style="display:flex;"><span>看 TreeHeap kernel 能不能在新地址找到它。
</span></span></code></pre></div><p>这个实验有用，但太弱。</p>
<p>它只能说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>显式 subheap kernel 可以做局部模式检测。
</span></span></code></pre></div><p>它不能证明我们真正关心的东西：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能不能自己把输入数据 encode 成一种可搜索、可压缩的结构？
</span></span><span style="display:flex;"><span>查询 kernel / 解码 kernel 能不能沿着这个结构工作？
</span></span><span style="display:flex;"><span>encoder 和 decoder 是否形成一对共轭过程？
</span></span></code></pre></div><p>所以现在的 claim 要重新写清楚。</p>
<h2 id="现在真正的-claim">现在真正的 Claim</h2>
<p>TreeHeap 不是要证明自己是“完全不同”的东西。</p>
<p>它应该先证明自己和实数域、MLP、CNN、Transformer 一样，能用于构造预测函数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入 x
</span></span><span style="display:flex;"><span>参数 theta
</span></span><span style="display:flex;"><span>预测 y_hat = f_theta(x)
</span></span><span style="display:flex;"><span>loss(y_hat, y)
</span></span><span style="display:flex;"><span>gradient
</span></span><span style="display:flex;"><span>update theta
</span></span></code></pre></div><p>然后再证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在需要结构编码、路径搜索、前缀压缩、延迟坍缩的问题上，
</span></span><span style="display:flex;"><span>TreeHeap 的显式结构归纳偏置能带来更好的样本效率、外推稳定性或计算效率。
</span></span></code></pre></div><p>更具体地说，我们现在要证明的不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 会匹配一个 pattern。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap encoder 能把数据组织成一种结构；
</span></span><span style="display:flex;"><span>TreeHeap decoder/query kernel 能利用这个结构完成搜索或解码。
</span></span></code></pre></div><p>这就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned encoder + conjugate kernel
</span></span></code></pre></div><p>中文可以叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>学习到的编码器 + 共轭查询/解码核
</span></span></code></pre></div><h2 id="为什么旧-b-实验不够">为什么旧 B 实验不够</h2>
<p>旧 B 实验是这样的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pattern:
</span></span><span style="display:flex;"><span>      1
</span></span><span style="display:flex;"><span>     / \
</span></span><span style="display:flex;"><span>    2   3
</span></span></code></pre></div><p>训练时 pattern 出现在：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>positions = {0, 1, 2}
</span></span></code></pre></div><p>测试时 pattern 出现在：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>positions = {6, 10, 13}
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>method</th>
          <th style="text-align: right">accuracy mean</th>
          <th style="text-align: right">min</th>
          <th style="text-align: right">max</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap kernel</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>flatten MLP</td>
          <td style="text-align: right">0.4996</td>
          <td style="text-align: right">0.4258</td>
          <td style="text-align: right">0.5703</td>
      </tr>
      <tr>
          <td>sequence CNN</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>small Transformer</td>
          <td style="text-align: right">0.9846</td>
          <td style="text-align: right">0.6055</td>
          <td style="text-align: right">1.0000</td>
      </tr>
  </tbody>
</table>
<p>这个表说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>局部 kernel 迁移是有效归纳偏置；
</span></span><span style="display:flex;"><span>MLP 展平后不擅长；
</span></span><span style="display:flex;"><span>CNN 和 TreeHeap kernel 擅长；
</span></span><span style="display:flex;"><span>Transformer 大多能学到，但有失败尾部。
</span></span></code></pre></div><p>但它不说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能学习建堆。
</span></span><span style="display:flex;"><span>TreeHeap 能学习编码。
</span></span><span style="display:flex;"><span>TreeHeap 能执行查询路径。
</span></span><span style="display:flex;"><span>TreeHeap 能压缩数据。
</span></span></code></pre></div><p>所以旧 B 只能作为 smoke test。</p>
<p>它证明的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 这个方向值得继续。
</span></span></code></pre></div><p>而不是最终 proof。</p>
<h2 id="新实验方向一学习建堆--查询搜索">新实验方向一：学习建堆 + 查询搜索</h2>
<p>第一个真正应该做的实验是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned ordered TreeHeap search
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入一组 key/value
</span></span><span style="display:flex;"><span>encoder 把它们建成 TreeHeap
</span></span><span style="display:flex;"><span>query kernel 根据查询 key 在树上走 stop / left / right
</span></span><span style="display:flex;"><span>最后返回 value
</span></span></code></pre></div><p>注意关键点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树不是人工提前建好的。
</span></span><span style="display:flex;"><span>树应该由 encoder 学出来。
</span></span></code></pre></div><h3 id="toy-数据">Toy 数据</h3>
<p>给一批 key/value：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[(8, A), (4, B), (12, C), (2, D), (6, E), (10, F), (14, G)]
</span></span></code></pre></div><p>查询：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query = 6
</span></span><span style="display:flex;"><span>answer = E
</span></span></code></pre></div><p>如果 TreeHeap encoder 学到了类似有序树的结构，它可能形成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>          8:A
</span></span><span style="display:flex;"><span>         /   \
</span></span><span style="display:flex;"><span>      4:B     12:C
</span></span><span style="display:flex;"><span>     /  \     /   \
</span></span><span style="display:flex;"><span>  2:D   6:E 10:F 14:G
</span></span></code></pre></div><p>这个结构不是我们强行塞给模型的目标，而是它为了让查询 kernel 更容易工作，应该自己学出来的中间结构。</p>
<h3 id="查询-kernel">查询 Kernel</h3>
<p>查询 kernel 可以很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query_kernel(node, query):
</span></span><span style="display:flex;"><span>  if query == node.key:
</span></span><span style="display:flex;"><span>    return stop
</span></span><span style="display:flex;"><span>  if query &lt; node.key:
</span></span><span style="display:flex;"><span>    return left
</span></span><span style="display:flex;"><span>  if query &gt; node.key:
</span></span><span style="display:flex;"><span>    return right
</span></span></code></pre></div><p>查找 <code>query = 6</code> 的过程：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>step 1:
</span></span><span style="display:flex;"><span>  node = 8:A
</span></span><span style="display:flex;"><span>  6 &lt; 8
</span></span><span style="display:flex;"><span>  action = left
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>step 2:
</span></span><span style="display:flex;"><span>  node = 4:B
</span></span><span style="display:flex;"><span>  6 &gt; 4
</span></span><span style="display:flex;"><span>  action = right
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>step 3:
</span></span><span style="display:flex;"><span>  node = 6:E
</span></span><span style="display:flex;"><span>  6 == 6
</span></span><span style="display:flex;"><span>  action = stop
</span></span><span style="display:flex;"><span>  output = E
</span></span></code></pre></div><p>路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; left -&gt; right -&gt; stop
</span></span></code></pre></div><p>地址：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0 -&gt; 1 -&gt; 4
</span></span></code></pre></div><p>这就是一个查找算法。</p>
<p>但在 TreeHeap 视角下，它可以被看成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subheap
</span></span><span style="display:flex;"><span>-&gt; query kernel
</span></span><span style="display:flex;"><span>-&gt; next address
</span></span><span style="display:flex;"><span>-&gt; subheap
</span></span><span style="display:flex;"><span>-&gt; query kernel
</span></span><span style="display:flex;"><span>-&gt; ...
</span></span></code></pre></div><p>也就是一个局部 kernel 的迭代。</p>
<h3 id="这里的共轭关系">这里的共轭关系</h3>
<p>encoder 和 query kernel 必须配合。</p>
<p>如果 encoder 学出的结构是乱的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>          10:F
</span></span><span style="display:flex;"><span>         /    \
</span></span><span style="display:flex;"><span>      2:D      6:E
</span></span></code></pre></div><p>那么简单的 <code>query &lt; root -&gt; left</code> 就可能走错。</p>
<p>所以训练压力会迫使 encoder 学一种结构，使得 decoder/query kernel 能工作。</p>
<p>这就是共轭关系：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder 学会如何摆放节点；
</span></span><span style="display:flex;"><span>query kernel 学会如何沿结构读取。
</span></span></code></pre></div><p>一个好的 proof 应该观察：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>查询准确率是否上升；
</span></span><span style="display:flex;"><span>路径长度是否接近 log n；
</span></span><span style="display:flex;"><span>树结构是否接近有序树；
</span></span><span style="display:flex;"><span>OOD key 数量变大时是否还能泛化。
</span></span></code></pre></div><h3 id="predict-b-new">Predict B-new</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap 的结构归纳偏置成立，
</span></span><span style="display:flex;"><span>TreeHeap encoder 会学习出一种可被局部 query kernel 搜索的结构。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>相比 flatten MLP，
</span></span><span style="display:flex;"><span>它应该更省样本、更容易外推到更多 key。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>相比普通 Transformer，
</span></span><span style="display:flex;"><span>它应该在路径长度、计算量、失败尾部上更稳定。
</span></span></code></pre></div><p>这才是搜索能力的 proof。</p>
<h2 id="新实验方向二加权前缀树--huffman-like-解码">新实验方向二：加权前缀树 + Huffman-like 解码</h2>
<p>第二个方向是你提到的加权树。</p>
<p>这里最接近的经典对象是 Huffman coding。</p>
<p>Huffman 编码做的事是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>高频符号用短路径；
</span></span><span style="display:flex;"><span>低频符号用长路径；
</span></span><span style="display:flex;"><span>整棵树是 prefix-free 的；
</span></span><span style="display:flex;"><span>decoder 沿路径还原符号。
</span></span></code></pre></div><p>TreeHeap 里可以问一个类似问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder 能不能学习一棵加权前缀树？
</span></span><span style="display:flex;"><span>decoder kernel 能不能沿路径把符号还原？
</span></span></code></pre></div><h3 id="toy-数据-1">Toy 数据</h3>
<p>假设符号频率是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A: 0.50
</span></span><span style="display:flex;"><span>B: 0.25
</span></span><span style="display:flex;"><span>C: 0.15
</span></span><span style="display:flex;"><span>D: 0.10
</span></span></code></pre></div><p>一个理想的 Huffman-like 编码可能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A -&gt; 0
</span></span><span style="display:flex;"><span>B -&gt; 10
</span></span><span style="display:flex;"><span>C -&gt; 110
</span></span><span style="display:flex;"><span>D -&gt; 111
</span></span></code></pre></div><p>对应树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>├── 0: A
</span></span><span style="display:flex;"><span>└── 1
</span></span><span style="display:flex;"><span>    ├── 0: B
</span></span><span style="display:flex;"><span>    └── 1
</span></span><span style="display:flex;"><span>        ├── 0: C
</span></span><span style="display:flex;"><span>        └── 1: D
</span></span></code></pre></div><p>平均路径长度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E[length]
</span></span><span style="display:flex;"><span>= 0.50 * 1
</span></span><span style="display:flex;"><span>+ 0.25 * 2
</span></span><span style="display:flex;"><span>+ 0.15 * 3
</span></span><span style="display:flex;"><span>+ 0.10 * 3
</span></span><span style="display:flex;"><span>= 1.75
</span></span></code></pre></div><p>如果不用加权前缀树，而给每个符号固定 2 bit：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A -&gt; 00
</span></span><span style="display:flex;"><span>B -&gt; 01
</span></span><span style="display:flex;"><span>C -&gt; 10
</span></span><span style="display:flex;"><span>D -&gt; 11
</span></span></code></pre></div><p>平均长度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E[length] = 2.00
</span></span></code></pre></div><p>这个 toy 里 Huffman-like 树更短。</p>
<h3 id="encoder--decoder">Encoder / Decoder</h3>
<p>TreeHeap encoder 的任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入符号分布
</span></span><span style="display:flex;"><span>输出一棵前缀 TreeHeap
</span></span></code></pre></div><p>TreeHeap decoder 的任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入路径 bits
</span></span><span style="display:flex;"><span>沿 TreeHeap 走 left/right
</span></span><span style="display:flex;"><span>遇到 leaf 后输出符号
</span></span></code></pre></div><p>例如路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>110
</span></span></code></pre></div><p>解码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; right -&gt; right -&gt; left
</span></span><span style="display:flex;"><span>output = C
</span></span></code></pre></div><p>这和前面的搜索任务一样，也是 kernel 迭代：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>current node + next bit -&gt; next node
</span></span></code></pre></div><p>但这里的目标不是搜索 key，而是还原压缩编码。</p>
<h3 id="这里的共轭关系-1">这里的共轭关系</h3>
<p>encoder 和 decoder 也是共轭的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder 决定符号放在哪条路径；
</span></span><span style="display:flex;"><span>decoder 沿路径还原符号。
</span></span></code></pre></div><p>如果 encoder 把高频符号放得很深，平均路径长度就会变差。</p>
<p>如果 encoder 生成的树不是 prefix-free，decoder 会混淆。</p>
<p>所以训练目标可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>reconstruction loss
</span></span><span style="display:flex;"><span>+ expected path length penalty
</span></span><span style="display:flex;"><span>+ prefix-free constraint penalty
</span></span></code></pre></div><h3 id="predict-c-new">Predict C-new</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap 的加权路径结构成立，
</span></span><span style="display:flex;"><span>encoder 应该能学习一棵接近 Huffman oracle 的前缀树；
</span></span><span style="display:flex;"><span>decoder kernel 应该能沿路径稳定还原符号；
</span></span><span style="display:flex;"><span>平均路径长度应该低于固定长度编码 baseline。
</span></span></code></pre></div><p>这才是“路径前缀压缩”的 proof。</p>
<p>不是简单地数 toy trie 节点。</p>
<h2 id="这两个实验和机器学习的关系">这两个实验和机器学习的关系</h2>
<p>这两个实验不是手写算法炫技。</p>
<p>真正的目标是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>让 encoder 的结构由梯度学习出来。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入数据
</span></span><span style="display:flex;"><span>-&gt; TreeHeap encoder(theta)
</span></span><span style="display:flex;"><span>-&gt; 结构状态 H
</span></span><span style="display:flex;"><span>-&gt; query/decoder kernel(phi)
</span></span><span style="display:flex;"><span>-&gt; 输出
</span></span><span style="display:flex;"><span>-&gt; loss
</span></span><span style="display:flex;"><span>-&gt; gradient update theta, phi
</span></span></code></pre></div><p>这和 MLP / Transformer 一样，仍然是机器学习。</p>
<p>区别只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>MLP 学的是展平向量上的函数；
</span></span><span style="display:flex;"><span>Transformer 学的是 token 序列上的 attention 函数；
</span></span><span style="display:flex;"><span>TreeHeap 学的是结构编码 + 路径 kernel。
</span></span></code></pre></div><p>所以 TreeHeap 的存在性不是“完全不同”。</p>
<p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同样做预测函数学习，
</span></span><span style="display:flex;"><span>但结构归纳偏置不同。
</span></span></code></pre></div><h2 id="旧-b-表应该怎么使用">旧 B 表应该怎么使用</h2>
<p>旧 B 表还可以保留，但只能作为弱证据。</p>
<p>它说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>显式 kernel 在局部结构迁移任务上是有用的；
</span></span><span style="display:flex;"><span>这个方向不是空想。
</span></span></code></pre></div><p>但下一轮 proof 应该升级为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>B-new:
</span></span><span style="display:flex;"><span>  learned encoder builds searchable ordered tree
</span></span><span style="display:flex;"><span>  query kernel walks stop/left/right
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>C-new:
</span></span><span style="display:flex;"><span>  learned encoder builds weighted prefix tree
</span></span><span style="display:flex;"><span>  decoder kernel reconstructs symbols from paths
</span></span></code></pre></div><p>我们之后要聊的 predict 和 proof，就应该围绕这两个实验设计。</p>
<h2 id="当前总-claim">当前总 Claim</h2>
<p>最终 claim 可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 是一种和 MLP / CNN / Transformer 同属机器学习家族的计算结构。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>它的独特性不是“完全不同”，
</span></span><span style="display:flex;"><span>而是把结构编码、路径搜索、前缀压缩、概率坍缩显式化。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>如果 claim 成立，
</span></span><span style="display:flex;"><span>TreeHeap encoder 应该能学习可搜索/可压缩的结构；
</span></span><span style="display:flex;"><span>共轭 query/decoder kernel 应该能利用该结构完成搜索和解码；
</span></span><span style="display:flex;"><span>并在相应结构任务上获得更好的样本效率、外推稳定性或计算效率。
</span></span></code></pre></div><p>下一步不是继续做 pattern matching。</p>
<p>下一步是 proof：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能不能 learn to build the tree?
</span></span><span style="display:flex;"><span>能不能 learn to search/decode through the tree?
</span></span><span style="display:flex;"><span>能不能比 MLP / Transformer 更省样本、更稳？
</span></span></code></pre></div><p>这才是 TreeHeap 的存在性问题。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-019] Soft TreeHeap：梯度如何进入树堆结构</title>
      <link>https://www.grepcode.cn/spr/019-soft-treeheap-gradient.html</link>
      <pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/019-soft-treeheap-gradient.html</guid>
      <description>把 TreeHeap 接入机器学习：用 kernel-guided soft plus、soft route 和多核训练让梯度进入树堆算子，并提出 claim、predict、proof 和实验方案。</description>
      <content:encoded><![CDATA[<h1 id="soft-treeheap梯度如何进入树堆结构">Soft TreeHeap：梯度如何进入树堆结构</h1>
<p>上一篇 <code>SPR-018</code> 把 TreeHeap 的目标说清楚了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不是要证明自己完全不同。
</span></span><span style="display:flex;"><span>TreeHeap 要证明自己和 MLP / CNN / Transformer 一样，
</span></span><span style="display:flex;"><span>也是一种可以构造预测函数的机器学习结构。
</span></span></code></pre></div><p>但这会立刻遇到一个核心问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度怎么进入 TreeHeap？
</span></span></code></pre></div><p>线性回归为什么能学习？</p>
<p>因为它有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>y_hat = W x + b
</span></span><span style="display:flex;"><span>loss = MSE(y_hat, y)
</span></span><span style="display:flex;"><span>gradient = d loss / d W
</span></span><span style="display:flex;"><span>update W
</span></span></code></pre></div><p>训练结束后，数据里的规律被蒸馏进参数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>W, b
</span></span></code></pre></div><p>Transformer 也是类似的，只是参数从一个简单矩阵，变成很多矩阵：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Wq, Wk, Wv, Wo, FFN weights
</span></span></code></pre></div><p>loss 仍然通过梯度，把数据里的统计规律写进参数矩阵。</p>
<p>那么 TreeHeap 呢？</p>
<p>如果 TreeHeap 只是硬指针：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>if query &lt; node.key:
</span></span><span style="display:flex;"><span>  go left
</span></span><span style="display:flex;"><span>else:
</span></span><span style="display:flex;"><span>  go right
</span></span></code></pre></div><p>或者硬写入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[3] = value
</span></span></code></pre></div><p>那梯度很难传进去。</p>
<p>所以第一版 TreeHeap 不能直接从 hard tree 开始。</p>
<p>我们需要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft TreeHeap
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>硬树堆结构的连续松弛版本。
</span></span></code></pre></div><h2 id="一句话-claim">一句话 Claim</h2>
<p>当前 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果把 TreeHeap 的写入、路由、停止、读取都改成可微的 soft distribution，
</span></span><span style="display:flex;"><span>那么 TreeHeap 就可以像 MLP / Transformer 一样用 loss 和 gradient 学习。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>梯度会被写入：
</span></span><span style="display:flex;"><span>node_key
</span></span><span style="display:flex;"><span>node_value
</span></span><span style="display:flex;"><span>write kernel
</span></span><span style="display:flex;"><span>query kernel
</span></span><span style="display:flex;"><span>decoder kernel
</span></span></code></pre></div><p>这不是最终证明。</p>
<p>这只是进入机器学习的入口。</p>
<p>如果这个 claim 不成立，TreeHeap 后面不用谈 WMT，也不用谈世界模型。</p>
<h2 id="从-hard-treeheap-到-soft-treeheap">从 Hard TreeHeap 到 Soft TreeHeap</h2>
<p>这里有一个很容易误解的点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft TreeHeap 不是推翻前面建立的 TreeHeap 数学基础。
</span></span></code></pre></div><p>更准确的说法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Hard TreeHeap 是离散代数对象。
</span></span><span style="display:flex;"><span>Soft TreeHeap 是它的概率提升，也就是可微近似。
</span></span></code></pre></div><p>原来的 TreeHeap 有确定的地址、确定的子树、确定的路由。</p>
<p>例如一个 hard 操作可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>O_a(H)
</span></span></code></pre></div><p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在地址 a 上，对 TreeHeap H 做一次确定操作。
</span></span></code></pre></div><p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在地址 a 上执行 TreeHeap plus
</span></span><span style="display:flex;"><span>读取 left(root)
</span></span><span style="display:flex;"><span>沿着 root -&gt; left -&gt; right 走
</span></span><span style="display:flex;"><span>在某个 subheap 上做 kernel matching
</span></span></code></pre></div><p>这些都是 hard TreeHeap 的操作。</p>
<p>Soft 以后，不是把这些操作删掉。</p>
<p>Soft 以后变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SoftO(H) = sum_a p(a) * O_a(H)
</span></span></code></pre></div><p>翻译成人话就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型暂时不知道应该操作哪个地址，
</span></span><span style="display:flex;"><span>所以它对多个地址都做一点操作，
</span></span><span style="display:flex;"><span>每个地址的权重由概率 p(a) 决定。
</span></span></code></pre></div><p>如果概率分布是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p(5) = 1.0
</span></span><span style="display:flex;"><span>其他地址 = 0.0
</span></span></code></pre></div><p>那么：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SoftO(H) = O_5(H)
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft TreeHeap 会退化回 Hard TreeHeap。
</span></span></code></pre></div><p>这非常重要。</p>
<p>因为它说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft TreeHeap 不是另一种东西。
</span></span><span style="display:flex;"><span>它是 Hard TreeHeap 的连续版本。
</span></span></code></pre></div><p>可以把关系表写成这样：</p>
<table>
  <thead>
      <tr>
          <th>Hard TreeHeap</th>
          <th>Soft TreeHeap</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>一个确定地址</td>
          <td>一个地址概率分布</td>
      </tr>
      <tr>
          <td><code>H_next = H ⊕_a x</code></td>
          <td><code>sum_a p(a) * (H ⊕_a x)</code></td>
      </tr>
      <tr>
          <td><code>left / right / stop</code></td>
          <td><code>p_left / p_right / p_stop</code></td>
      </tr>
      <tr>
          <td>一个确定子树</td>
          <td>子树概率分布</td>
      </tr>
      <tr>
          <td>一个确定卷积核位置</td>
          <td>多个 subheap 上的加权 kernel</td>
      </tr>
      <tr>
          <td>hard collapse</td>
          <td>低温 softmax / top-k / argmax collapse</td>
      </tr>
  </tbody>
</table>
<p>所以 Soft TreeHeap 的本质不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把树堆变成普通向量。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>让 TreeHeap 的地址、路径、子结构都能携带概率。
</span></span></code></pre></div><p>这样 loss 才能通过概率分布反传。</p>
<h3 id="一个小例子">一个小例子</h3>
<p>hard 查询是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query = 6
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>root = 8
</span></span><span style="display:flex;"><span>6 &lt; 8
</span></span><span style="display:flex;"><span>go left
</span></span></code></pre></div><p>soft 查询是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query = 6
</span></span><span style="display:flex;"><span>root = 8
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>stop: 0.05
</span></span><span style="display:flex;"><span>left: 0.85
</span></span><span style="display:flex;"><span>right: 0.10
</span></span></code></pre></div><p>这时模型还没有完全确定。</p>
<p>它主要相信：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>应该 go left
</span></span></code></pre></div><p>但仍然保留一点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop / right 的可能性。
</span></span></code></pre></div><p>如果后面发现答案错了，loss 可以反向告诉它：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left 的概率应该再高一点；
</span></span><span style="display:flex;"><span>right 的概率应该再低一点；
</span></span><span style="display:flex;"><span>当前 node_key / query_kernel 应该如何调整。
</span></span></code></pre></div><p>这就是梯度进入 TreeHeap 的入口。</p>
<h3 id="但这里有一个工程边界">但这里有一个工程边界</h3>
<p>完整的概率 TreeHeap 应该保存：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>所有可能 TreeHeap 的概率分布。
</span></span></code></pre></div><p>这是最干净的数学版本。</p>
<p>但它太贵。</p>
<p>因为树一大，可能结构数量会爆炸。</p>
<p>工程上更可能采用的是近似版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>每个 node 保存一个 value 分布；
</span></span><span style="display:flex;"><span>每条 route 保存一个 action 分布；
</span></span><span style="display:flex;"><span>每个 kernel 保存一个 soft attention 分布。
</span></span></code></pre></div><p>这可以叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mean-field Soft TreeHeap
</span></span></code></pre></div><p>它的好处是能训练。</p>
<p>它的风险是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>可能丢失不同路径之间的相关性。
</span></span></code></pre></div><p>所以后续实验不能只看任务准确率。</p>
<p>还要看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft 近似是否破坏了 TreeHeap 原来的代数结构？
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>hard collapse 以后，是否还能得到合法树？
</span></span><span style="display:flex;"><span>soft route 是否真的收敛到可解释路径？
</span></span><span style="display:flex;"><span>subheap kernel 是否还能迁移？
</span></span></code></pre></div><p>这会成为后续 proof 的一部分。</p>
<h2 id="为什么-hard-treeheap-不适合第一版训练">为什么 hard TreeHeap 不适合第一版训练</h2>
<p>假设我们有一个硬查询 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>if query == node.key:
</span></span><span style="display:flex;"><span>  return stop
</span></span><span style="display:flex;"><span>if query &lt; node.key:
</span></span><span style="display:flex;"><span>  return left
</span></span><span style="display:flex;"><span>if query &gt; node.key:
</span></span><span style="display:flex;"><span>  return right
</span></span></code></pre></div><p>这个逻辑很清楚，但对梯度不友好。</p>
<p>因为模型一旦选择：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left
</span></span></code></pre></div><p>它就完全不走：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>right
</span></span></code></pre></div><p>如果最后错了，loss 很难告诉模型：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>其实刚才 right 更好。
</span></span></code></pre></div><p>同样，硬写入也有问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[5] = value
</span></span></code></pre></div><p>如果写错位置，梯度很难平滑地告诉 encoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>你应该往 arr[4] 写 0.2，往 arr[5] 写 0.8。
</span></span></code></pre></div><p>所以第一版必须用 soft 版本。</p>
<h2 id="soft-write-的弱版本神经内存写入">Soft Write 的弱版本：神经内存写入</h2>
<p>先承认一个问题。</p>
<p>如果我们把可微写入写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>write_logits = encoder(x, H)
</span></span><span style="display:flex;"><span>write_prob = softmax(write_logits)
</span></span></code></pre></div><p>然后直接更新数组槽位：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr_new[i] =
</span></span><span style="display:flex;"><span>  (1 - write_prob[i]) * arr_old[i]
</span></span><span style="display:flex;"><span>+ write_prob[i] * write_vector
</span></span></code></pre></div><p>这确实是可微的。</p>
<p>但它更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>neural memory write
</span></span></code></pre></div><p>也就是神经网络记忆槽更新。</p>
<p>它的问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度进入了 arr，
</span></span><span style="display:flex;"><span>但没有真正进入 TreeHeap 的 plus 算子。
</span></span></code></pre></div><p>换句话说，它能证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个数组内存可以被 softmax 写入。
</span></span></code></pre></div><p>但它不能证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的加法、路径、子结构、卷积核可以被学习。
</span></span></code></pre></div><p>所以这个写法只能作为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>baseline
</span></span><span style="display:flex;"><span>教学反例
</span></span><span style="display:flex;"><span>最低可微版本
</span></span></code></pre></div><p>不能作为 TreeHeap 的正式写入机制。</p>
<p>正式机制应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft Write = Soft Plus
</span></span></code></pre></div><p>更进一步：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft Write = Kernel-guided Soft Plus
</span></span></code></pre></div><h2 id="soft-plus对-treeheap-加法的概率提升">Soft Plus：对 TreeHeap 加法的概率提升</h2>
<p>先定义 hard plus。</p>
<p>假设：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = 当前 TreeHeap
</span></span><span style="display:flex;"><span>x = 新输入的 token / node / 小 TreeHeap
</span></span><span style="display:flex;"><span>a = 一个地址或路径
</span></span></code></pre></div><p>hard 写入不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[a] = x
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next = H ⊕_a x
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>⊕_a
</span></span></code></pre></div><p>表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在地址 a 上，把 x 按 TreeHeap 的规则并入 H。
</span></span></code></pre></div><p>这个规则可以包含：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径比较
</span></span><span style="display:flex;"><span>子树重排
</span></span><span style="display:flex;"><span>局部 merge
</span></span><span style="display:flex;"><span>权重更新
</span></span><span style="display:flex;"><span>父子关系维护
</span></span></code></pre></div><p>这才是 TreeHeap 的加法味道。</p>
<p>Soft plus 不是直接改数组。</p>
<p>Soft plus 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next = sum_a p(a | H, x) * (H ⊕_a x)
</span></span></code></pre></div><p>翻译成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型不知道 x 应该插入哪个地址，
</span></span><span style="display:flex;"><span>所以它先生成多个候选 TreeHeap：
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>candidate_a = H ⊕_a x
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>然后按概率把这些候选结构混合起来。
</span></span></code></pre></div><p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p(left.right) = 1.0
</span></span><span style="display:flex;"><span>其他地址 = 0.0
</span></span></code></pre></div><p>那么：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next = H ⊕_{left.right} x
</span></span></code></pre></div><p>这就退化回 hard TreeHeap plus。</p>
<p>所以 Soft Plus 仍然继承原来的 TreeHeap 数学基础。</p>
<p>它不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>矩阵内存插值。
</span></span></code></pre></div><p>它是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap plus 算子的 soft lifting。
</span></span></code></pre></div><h2 id="kernel-guided-soft-plus用卷积核决定写入">Kernel-guided Soft Plus：用卷积核决定写入</h2>
<p>还有一个更关键的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p(a | H, x) 从哪里来？
</span></span></code></pre></div><p>如果只是让一个普通 encoder 直接输出所有地址概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p(a) = softmax(MLP(H, x))
</span></span></code></pre></div><p>那仍然有点像普通注意力。</p>
<p>更符合 TreeHeap 的方案是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p(a) 由 TreeHeap convolution kernel 计算出来。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score(a) = K_write(subheap(H, a), x)
</span></span><span style="display:flex;"><span>p(a) = softmax(score(a))
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_write
</span></span></code></pre></div><p>是一个可微卷积核。</p>
<p>它观察：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前位置的 subheap
</span></span><span style="display:flex;"><span>新输入 x
</span></span><span style="display:flex;"><span>局部路径
</span></span><span style="display:flex;"><span>局部 key/value/weight
</span></span><span style="display:flex;"><span>局部结构 pattern
</span></span></code></pre></div><p>然后判断：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x 是否应该写到这个位置；
</span></span><span style="display:flex;"><span>x 是否应该继续往 left；
</span></span><span style="display:flex;"><span>x 是否应该继续往 right；
</span></span><span style="display:flex;"><span>x 是否应该在这里 stop 并 merge。
</span></span></code></pre></div><p>这样，写入就不再是 hardcode：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>if x &lt; node.key:
</span></span><span style="display:flex;"><span>  go left
</span></span></code></pre></div><p>而是变成可微 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>local_feature = phi(subheap(H, a), x)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>score_stop  = w_stop  · local_feature
</span></span><span style="display:flex;"><span>score_left  = w_left  · local_feature
</span></span><span style="display:flex;"><span>score_right = w_right · local_feature
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>p_action = softmax([score_stop, score_left, score_right])
</span></span></code></pre></div><p>这个 <code>K_write</code> 就是 TreeHeap 上的卷积核。</p>
<p>它不是二维图像卷积核。</p>
<p>但它做的是同一类事情：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在局部结构上滑动；
</span></span><span style="display:flex;"><span>提取局部 pattern；
</span></span><span style="display:flex;"><span>给出下一步操作分数。
</span></span></code></pre></div><p>图像卷积看的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>3x3 pixel patch
</span></span></code></pre></div><p>TreeHeap 卷积看的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; left/right 的小 subheap
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        8
</span></span><span style="display:flex;"><span>      /   \
</span></span><span style="display:flex;"><span>     4     12
</span></span></code></pre></div><p>现在插入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x.key = 6
</span></span></code></pre></div><p>卷积核在 root=8 看到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>6 更像应该去 left
</span></span></code></pre></div><p>于是输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop:  0.05
</span></span><span style="display:flex;"><span>left:  0.90
</span></span><span style="display:flex;"><span>right: 0.05
</span></span></code></pre></div><p>到 node=4 时，它看到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>6 更像应该去 right
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop:  0.05
</span></span><span style="display:flex;"><span>left:  0.05
</span></span><span style="display:flex;"><span>right: 0.90
</span></span></code></pre></div><p>到空位或 node=6 时，它输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop:  0.95
</span></span><span style="display:flex;"><span>left:  0.025
</span></span><span style="display:flex;"><span>right: 0.025
</span></span></code></pre></div><p>然后执行：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next = sum_a write_mass[a] * (H ⊕_a x)
</span></span></code></pre></div><p>这里的 <code>write_mass[a]</code> 不是外部指定的。</p>
<p>它来自 kernel 在树上的逐步传播：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mass[root] = 1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>for step in search_steps:
</span></span><span style="display:flex;"><span>  for each active address a:
</span></span><span style="display:flex;"><span>    p_action = K_write(subheap(H, a), x)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    write_mass[a]       += mass[a] * p_stop
</span></span><span style="display:flex;"><span>    mass_next[left(a)]  += mass[a] * p_left
</span></span><span style="display:flex;"><span>    mass_next[right(a)] += mass[a] * p_right
</span></span></code></pre></div><p>最后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next = sum_a write_mass[a] * Plus_a(H, x)
</span></span></code></pre></div><p>这才是 TreeHeap 版本的可微写入。</p>
<p>它的梯度链条是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>H_next
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>sum_a write_mass[a] * Plus_a(H, x)
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>write_mass[a]
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>K_write(subheap(H, a), x)
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>kernel parameters
</span></span></code></pre></div><p>所以梯度进入的不是普通内存槽。</p>
<p>梯度进入的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap convolution kernel
</span></span><span style="display:flex;"><span>TreeHeap plus candidates
</span></span><span style="display:flex;"><span>TreeHeap route distribution
</span></span><span style="display:flex;"><span>TreeHeap collapse path
</span></span></code></pre></div><p>这比 naive soft memory write 更接近我们的目标。</p>
<h2 id="soft-route可微路径选择">Soft Route：可微路径选择</h2>
<p>硬路由是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>go left
</span></span></code></pre></div><p>Soft route 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>action_logits = query_kernel(query, node)
</span></span><span style="display:flex;"><span>action_prob = softmax(action_logits)
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  stop:  0.10,
</span></span><span style="display:flex;"><span>  left:  0.75,
</span></span><span style="display:flex;"><span>  right: 0.15
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前更可能应该走 left，
</span></span><span style="display:flex;"><span>但 right 和 stop 仍然保留少量概率。
</span></span></code></pre></div><p>如果当前节点有流量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mass[i] = 0.80
</span></span></code></pre></div><p>那么下一步传播：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop_mass[i]        += 0.80 * 0.10
</span></span><span style="display:flex;"><span>mass_next[left(i)]  += 0.80 * 0.75
</span></span><span style="display:flex;"><span>mass_next[right(i)] += 0.80 * 0.15
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop_mass[i]        += mass[i] * p_stop
</span></span><span style="display:flex;"><span>mass_next[left(i)]  += mass[i] * p_left
</span></span><span style="display:flex;"><span>mass_next[right(i)] += mass[i] * p_right
</span></span></code></pre></div><p>跑多步以后，输出可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>y_hat = sum_i stop_mass[i] * node_value[i]
</span></span></code></pre></div><p>或者分类任务里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>logits = sum_i stop_mass[i] * node_logits[i]
</span></span></code></pre></div><p>这仍然是可微的。</p>
<p>梯度能进入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query kernel
</span></span><span style="display:flex;"><span>node_key
</span></span><span style="display:flex;"><span>node_value
</span></span><span style="display:flex;"><span>路径概率
</span></span></code></pre></div><h2 id="一个完整-toy查找-keyvalue">一个完整 Toy：查找 key/value</h2>
<p>任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入一组 key/value
</span></span><span style="display:flex;"><span>查询一个 key
</span></span><span style="display:flex;"><span>输出对应 value
</span></span></code></pre></div><p>样本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pairs = [(8,A), (4,B), (12,C), (2,D), (6,E), (10,F), (14,G)]
</span></span><span style="display:flex;"><span>query = 6
</span></span><span style="display:flex;"><span>target = E
</span></span></code></pre></div><p>理想结构是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>          8:A
</span></span><span style="display:flex;"><span>         /   \
</span></span><span style="display:flex;"><span>      4:B     12:C
</span></span><span style="display:flex;"><span>     /  \     /   \
</span></span><span style="display:flex;"><span>  2:D   6:E 10:F 14:G
</span></span></code></pre></div><p>如果是硬查找：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>6 &lt; 8  -&gt; left
</span></span><span style="display:flex;"><span>6 &gt; 4  -&gt; right
</span></span><span style="display:flex;"><span>6 == 6 -&gt; stop
</span></span><span style="display:flex;"><span>output = E
</span></span></code></pre></div><p>Soft TreeHeap 不会一开始这么硬。</p>
<p>第 1 步在 root：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node.key = 8
</span></span><span style="display:flex;"><span>query = 6
</span></span></code></pre></div><p>query kernel 输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop:  0.05
</span></span><span style="display:flex;"><span>left:  0.85
</span></span><span style="display:flex;"><span>right: 0.10
</span></span></code></pre></div><p>第 2 步进入左子树，节点是 <code>4:B</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node.key = 4
</span></span><span style="display:flex;"><span>query = 6
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop:  0.05
</span></span><span style="display:flex;"><span>left:  0.10
</span></span><span style="display:flex;"><span>right: 0.85
</span></span></code></pre></div><p>路径概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; left -&gt; right
</span></span><span style="display:flex;"><span>= 0.85 * 0.85
</span></span><span style="display:flex;"><span>= 0.7225
</span></span></code></pre></div><p>第 3 步到 <code>6:E</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node.key = 6
</span></span><span style="display:flex;"><span>query = 6
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop:  0.80
</span></span><span style="display:flex;"><span>left:  0.10
</span></span><span style="display:flex;"><span>right: 0.10
</span></span></code></pre></div><p>最终命中路径概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; left -&gt; right -&gt; stop
</span></span><span style="display:flex;"><span>= 0.85 * 0.85 * 0.80
</span></span><span style="display:flex;"><span>= 0.5780
</span></span></code></pre></div><p>如果模型输出了 <code>E</code>，loss 下降。</p>
<p>如果模型输出错了，loss 反传，梯度会告诉系统：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>哪些节点 key/value 需要调整
</span></span><span style="display:flex;"><span>哪些路由概率需要调整
</span></span><span style="display:flex;"><span>哪个写入位置更合理
</span></span></code></pre></div><p>这就是 TreeHeap 的梯度学习过程。</p>
<h2 id="loss-不应该一开始大锅炖">Loss 不应该一开始大锅炖</h2>
<p>上面讲了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss 可以进入 Soft TreeHeap。
</span></span></code></pre></div><p>但这不等于说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>所有 loss 都应该一开始混在一起。
</span></span></code></pre></div><p>一个很自然的教学写法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L =
</span></span><span style="display:flex;"><span>  L_task
</span></span><span style="display:flex;"><span>+ alpha * L_order
</span></span><span style="display:flex;"><span>+ beta  * L_depth
</span></span><span style="display:flex;"><span>+ gamma * L_entropy
</span></span></code></pre></div><p>这个式子适合帮助读者理解：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>任务正确性、结构合法性、路径长度、概率坍缩
</span></span><span style="display:flex;"><span>都可以变成训练信号。
</span></span></code></pre></div><p>但它不一定是好的工程设计。</p>
<p>因为多个 loss 直接相加，会遇到几个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度方向可能互相抵消；
</span></span><span style="display:flex;"><span>某个 loss 的尺度太大，压住其他 loss；
</span></span><span style="display:flex;"><span>结构 loss 太早生效，导致模型过早坍缩；
</span></span><span style="display:flex;"><span>熵 loss 太强，导致模型一直不敢做决定；
</span></span><span style="display:flex;"><span>多个目标一起训练，难以知道到底哪个 kernel 学坏了。
</span></span></code></pre></div><p>这和 Transformer 的经验类似。</p>
<p>Transformer 不是只用一个观察角度看序列。</p>
<p>它用了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>multi-head attention
</span></span></code></pre></div><p>不同 head 可以学习不同关系。</p>
<p>TreeHeap 也应该类似。</p>
<p>更合理的设计不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个巨大 loss 控制所有东西。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>多个 TreeHeap kernel / head 各自学习一种结构能力。
</span></span></code></pre></div><h2 id="multi-kernel-treeheap">Multi-kernel TreeHeap</h2>
<p>可以先把 Soft TreeHeap 拆成几个 head。</p>
<table>
  <thead>
      <tr>
          <th>Head</th>
          <th>学什么</th>
          <th>主要梯度来源</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>plus/kernel head</td>
          <td>输入应该通过哪个 subheap kernel 并入 TreeHeap</td>
          <td>reconstruction / lookup / structure loss</td>
      </tr>
      <tr>
          <td>route head</td>
          <td>查询时走 stop/left/right</td>
          <td>lookup task loss</td>
      </tr>
      <tr>
          <td>order head</td>
          <td>是否形成有序树</td>
          <td>order violation loss</td>
      </tr>
      <tr>
          <td>depth head</td>
          <td>路径是否短</td>
          <td>expected depth loss</td>
      </tr>
      <tr>
          <td>prefix head</td>
          <td>高频符号是否更短</td>
          <td>compression loss</td>
      </tr>
      <tr>
          <td>collapse head</td>
          <td>什么时候从概率变成确定结构</td>
          <td>entropy / temperature schedule</td>
      </tr>
  </tbody>
</table>
<p>这样每个 head 都比较清楚。</p>
<p>例如查找任务里，route head 主要学：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query 和当前 node 的关系。
</span></span></code></pre></div><p>order head 主要学：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left_key &lt; root_key &lt; right_key
</span></span></code></pre></div><p>prefix head 主要学：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>高频符号走短路径。
</span></span></code></pre></div><p>这些目标不一定应该同时强行压到一个参数空间里。</p>
<p>更好的方式是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>让不同 kernel 先学会自己的局部规律，
</span></span><span style="display:flex;"><span>再由上层组合。
</span></span></code></pre></div><h2 id="loss-设计一任务-head">Loss 设计一：任务 Head</h2>
<p>任务 head 只负责最终答案。</p>
<p>如果输出是分类：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L_task = cross_entropy(y_hat, target)
</span></span></code></pre></div><p>如果输出是连续值：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L_task = MSE(y_hat, target)
</span></span></code></pre></div><p>例如 key/value 查找任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>target = E
</span></span><span style="display:flex;"><span>y_hat = soft_query(H, query)
</span></span><span style="display:flex;"><span>L_task = cross_entropy(y_hat, E)
</span></span></code></pre></div><p>这个 head 回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>最后答案对不对？
</span></span></code></pre></div><p>它不直接负责：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树是否漂亮；
</span></span><span style="display:flex;"><span>路径是否最短；
</span></span><span style="display:flex;"><span>概率是否已经坍缩。
</span></span></code></pre></div><h2 id="loss-设计二order-head">Loss 设计二：Order Head</h2>
<p>如果任务是有序查找树，可以单独给 order head 一个结构目标。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left_key &lt; root_key &lt; right_key
</span></span></code></pre></div><p>用 hinge loss 写：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L_order =
</span></span><span style="display:flex;"><span>  max(0, left_key - root_key + margin)
</span></span><span style="display:flex;"><span>+ max(0, root_key - right_key + margin)
</span></span></code></pre></div><p>如果左子节点比 root 还大，就会罚。</p>
<p>如果右子节点比 root 还小，也会罚。</p>
<p>这个 head 的作用不是替代任务 loss。</p>
<p>它的作用是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>让 TreeHeap 的内部结构更像可搜索结构。
</span></span></code></pre></div><p>这类似 CNN 的卷积结构偏置。</p>
<p>但区别是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>CNN 的局部结构通常是人工固定的二维邻域；
</span></span><span style="display:flex;"><span>TreeHeap 的局部结构是可学习的地址 / 子树 / 路由。
</span></span></code></pre></div><h2 id="loss-设计三depth-head">Loss 设计三：Depth Head</h2>
<p>如果查找绕很远，虽然答案对了，也不一定好。</p>
<p>可以单独训练一个 depth head：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L_depth = expected_search_steps
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; left -&gt; right -&gt; stop
</span></span></code></pre></div><p>路径长度是 3。</p>
<p>如果模型绕成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; right -&gt; left -&gt; left -&gt; right -&gt; stop
</span></span></code></pre></div><p>路径更长，就会被罚。</p>
<p>这个 head 对应的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>搜索效率。
</span></span></code></pre></div><p>它可以晚一点加入。</p>
<p>因为训练早期模型还不会查找，如果太早惩罚路径长度，可能导致模型学会：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>为了路径短，直接 stop。
</span></span></code></pre></div><p>但答案是错的。</p>
<h2 id="loss-设计四collapse-head">Loss 设计四：Collapse Head</h2>
<p>训练早期，我们允许不确定：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left: 0.45
</span></span><span style="display:flex;"><span>right: 0.40
</span></span><span style="display:flex;"><span>stop: 0.15
</span></span></code></pre></div><p>训练后期，我们希望它逐渐清晰：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left: 0.95
</span></span><span style="display:flex;"><span>right: 0.03
</span></span><span style="display:flex;"><span>stop: 0.02
</span></span></code></pre></div><p>所以可以使用 entropy 或 temperature schedule。</p>
<p>但这里要非常小心。</p>
<p>如果把 entropy loss 一开始就和 task loss 强行混在一起，可能出现两种坏情况。</p>
<p>第一种：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>过早坍缩。
</span></span></code></pre></div><p>模型还没学会结构，就已经把概率压成 one-hot。</p>
<p>后面错了也很难改。</p>
<p>第二种：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>长期不坍缩。
</span></span></code></pre></div><p>模型为了保留不确定性，永远不形成清晰路径。</p>
<p>所以 collapse head 更像一个控制器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>early:  high temperature, allow exploration
</span></span><span style="display:flex;"><span>middle: reduce temperature
</span></span><span style="display:flex;"><span>late:   low temperature, encourage collapse
</span></span></code></pre></div><p>它不应该无脑和所有 loss 相加。</p>
<h2 id="推荐训练方式分阶段或交替训练">推荐训练方式：分阶段或交替训练</h2>
<p>更合理的训练流程可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Stage 1:
</span></span><span style="display:flex;"><span>  只训练 task head / route head。
</span></span><span style="display:flex;"><span>  目标：答案能不能对。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Stage 2:
</span></span><span style="display:flex;"><span>  加入 order head。
</span></span><span style="display:flex;"><span>  目标：内部结构是否变成可搜索树。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Stage 3:
</span></span><span style="display:flex;"><span>  加入 depth head。
</span></span><span style="display:flex;"><span>  目标：路径是否更短。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Stage 4:
</span></span><span style="display:flex;"><span>  加入 collapse head。
</span></span><span style="display:flex;"><span>  目标：soft distribution 是否能稳定坍缩成 hard TreeHeap。
</span></span></code></pre></div><p>也可以采用交替训练：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>step 1: update route kernel
</span></span><span style="display:flex;"><span>step 2: update write kernel
</span></span><span style="display:flex;"><span>step 3: update order kernel
</span></span><span style="display:flex;"><span>step 4: update collapse controller
</span></span></code></pre></div><p>必要时还可以使用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop-gradient
</span></span><span style="display:flex;"><span>freeze kernel
</span></span><span style="display:flex;"><span>auxiliary probe
</span></span><span style="display:flex;"><span>gradient clipping
</span></span><span style="display:flex;"><span>loss normalization
</span></span></code></pre></div><p>这样做的好处是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>每一种梯度信息都有自己的入口；
</span></span><span style="display:flex;"><span>每个 kernel 学坏了都能被定位；
</span></span><span style="display:flex;"><span>不会把所有目标搅在一起互相污染。
</span></span></code></pre></div><p>所以 SPR-019 的正式观点应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可以通过 loss / gradient 学习，
</span></span><span style="display:flex;"><span>但不应该依赖一个大锅炖总 loss。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TreeHeap 更合理的训练形态是：
</span></span><span style="display:flex;"><span>multi-kernel + staged training + controlled collapse。
</span></span></code></pre></div><h2 id="huffman-like-压缩任务的-loss">Huffman-like 压缩任务的 Loss</h2>
<p>如果任务是学习加权前缀树，loss 可以换成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L =
</span></span><span style="display:flex;"><span>  L_reconstruct
</span></span><span style="display:flex;"><span>+ lambda * L_length
</span></span><span style="display:flex;"><span>+ mu * L_prefix_free
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L_reconstruct:
</span></span><span style="display:flex;"><span>  decoder 是否能还原符号。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>L_length:
</span></span><span style="display:flex;"><span>  高频符号路径是否更短。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>L_prefix_free:
</span></span><span style="display:flex;"><span>  是否避免一个符号路径成为另一个符号路径的前缀。
</span></span></code></pre></div><p>例如符号频率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A: 0.50
</span></span><span style="display:flex;"><span>B: 0.25
</span></span><span style="display:flex;"><span>C: 0.15
</span></span><span style="display:flex;"><span>D: 0.10
</span></span></code></pre></div><p>理想 Huffman-like 编码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A -&gt; 0
</span></span><span style="display:flex;"><span>B -&gt; 10
</span></span><span style="display:flex;"><span>C -&gt; 110
</span></span><span style="display:flex;"><span>D -&gt; 111
</span></span></code></pre></div><p>平均路径长度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.50 * 1
</span></span><span style="display:flex;"><span>+ 0.25 * 2
</span></span><span style="display:flex;"><span>+ 0.15 * 3
</span></span><span style="display:flex;"><span>+ 0.10 * 3
</span></span><span style="display:flex;"><span>= 1.75
</span></span></code></pre></div><p>固定长度编码是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>2.00
</span></span></code></pre></div><p>所以 predict 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap 能学习加权前缀树，
</span></span><span style="display:flex;"><span>它的 expected path length 应该接近 Huffman oracle，
</span></span><span style="display:flex;"><span>并低于 fixed-length baseline。
</span></span></code></pre></div><h2 id="predict">Predict</h2>
<p>当前 predict 分四层。</p>
<h3 id="predict-1可学习性">Predict 1：可学习性</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft TreeHeap 的 loss 应该能下降。
</span></span></code></pre></div><p>最小任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>线性回归
</span></span><span style="display:flex;"><span>二分类
</span></span><span style="display:flex;"><span>XOR / parity
</span></span><span style="display:flex;"><span>key/value lookup
</span></span></code></pre></div><p>如果这些都学不会，TreeHeap 不具备机器学习基本能力。</p>
<h3 id="predict-2可搜索编码">Predict 2：可搜索编码</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在 key/value lookup 任务中，
</span></span><span style="display:flex;"><span>TreeHeap encoder 应该能学习一种可被 query kernel 搜索的结构。
</span></span></code></pre></div><p>指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query accuracy
</span></span><span style="display:flex;"><span>expected search depth
</span></span><span style="display:flex;"><span>OOD key count generalization
</span></span><span style="display:flex;"><span>tree order violation rate
</span></span><span style="display:flex;"><span>failure tail
</span></span></code></pre></div><h3 id="predict-3可压缩编码">Predict 3：可压缩编码</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在 weighted prefix coding 任务中，
</span></span><span style="display:flex;"><span>TreeHeap encoder 应该能学习接近 Huffman oracle 的路径分配。
</span></span></code></pre></div><p>指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>reconstruction accuracy
</span></span><span style="display:flex;"><span>expected path length
</span></span><span style="display:flex;"><span>prefix-free violation rate
</span></span><span style="display:flex;"><span>gap to Huffman oracle
</span></span><span style="display:flex;"><span>gap to fixed-length baseline
</span></span></code></pre></div><h3 id="predict-4soft-版本不破坏-treeheap-代数">Predict 4：Soft 版本不破坏 TreeHeap 代数</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 Soft TreeHeap 真的是 Hard TreeHeap 的概率提升，
</span></span><span style="display:flex;"><span>那么当温度降低、分布接近 one-hot 时，
</span></span><span style="display:flex;"><span>soft 结果应该接近对应 hard 操作的结果。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel-guided soft plus collapse 后，应该接近 hard plus；
</span></span><span style="display:flex;"><span>soft route collapse 后，应该接近 hard route；
</span></span><span style="display:flex;"><span>soft subheap kernel collapse 后，应该接近 hard subheap kernel；
</span></span><span style="display:flex;"><span>soft learned tree collapse 后，应该仍然是合法 TreeHeap。
</span></span></code></pre></div><p>指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>hard-soft output gap
</span></span><span style="display:flex;"><span>collapse legality rate
</span></span><span style="display:flex;"><span>route interpretability
</span></span><span style="display:flex;"><span>subheap relocation accuracy
</span></span><span style="display:flex;"><span>gradient stability
</span></span></code></pre></div><h2 id="proof-设计">Proof 设计</h2>
<p>为了证明 claim，需要最少四组实验。</p>
<h3 id="experiment-0soft-treeheap-能不能学习">Experiment 0：Soft TreeHeap 能不能学习</h3>
<p>目的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>证明 TreeHeap 和 MLP 一样，可以通过 loss / gradient 学函数。
</span></span></code></pre></div><p>任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>linear regression
</span></span><span style="display:flex;"><span>binary classification
</span></span><span style="display:flex;"><span>XOR
</span></span><span style="display:flex;"><span>small lookup
</span></span></code></pre></div><p>对比：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>MLP
</span></span><span style="display:flex;"><span>Soft TreeHeap
</span></span></code></pre></div><p>判断：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss 是否下降；
</span></span><span style="display:flex;"><span>accuracy 是否上升；
</span></span><span style="display:flex;"><span>参数梯度是否非零；
</span></span><span style="display:flex;"><span>训练是否稳定。
</span></span></code></pre></div><h3 id="experiment-1learned-ordered-tree-search">Experiment 1：Learned Ordered Tree Search</h3>
<p>目的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>证明 encoder 能学习建一棵可搜索树。
</span></span></code></pre></div><p>任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入 N 个 key/value；
</span></span><span style="display:flex;"><span>查询 key；
</span></span><span style="display:flex;"><span>输出 value。
</span></span></code></pre></div><p>训练：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>N = 7, 15
</span></span></code></pre></div><p>测试外推：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>N = 31, 63
</span></span></code></pre></div><p>对比：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flatten MLP
</span></span><span style="display:flex;"><span>small Transformer
</span></span><span style="display:flex;"><span>Soft TreeHeap
</span></span><span style="display:flex;"><span>oracle BST
</span></span></code></pre></div><p>指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>accuracy
</span></span><span style="display:flex;"><span>expected search depth
</span></span><span style="display:flex;"><span>sample efficiency
</span></span><span style="display:flex;"><span>OOD generalization
</span></span><span style="display:flex;"><span>tree order violation
</span></span></code></pre></div><h3 id="experiment-2learned-huffman-like-prefix-tree">Experiment 2：Learned Huffman-like Prefix Tree</h3>
<p>目的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>证明 encoder 能学习加权前缀压缩结构。
</span></span></code></pre></div><p>任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入符号频率；
</span></span><span style="display:flex;"><span>encoder 输出 TreeHeap code；
</span></span><span style="display:flex;"><span>decoder 根据路径还原符号。
</span></span></code></pre></div><p>对比：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>fixed-length code
</span></span><span style="display:flex;"><span>Huffman oracle
</span></span><span style="display:flex;"><span>MLP autoencoder
</span></span><span style="display:flex;"><span>Soft TreeHeap prefix encoder
</span></span></code></pre></div><p>指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>reconstruction accuracy
</span></span><span style="display:flex;"><span>expected code length
</span></span><span style="display:flex;"><span>prefix-free violation
</span></span><span style="display:flex;"><span>gap to Huffman oracle
</span></span></code></pre></div><h3 id="experiment-3hardsoft-consistency-与-loss-ablation">Experiment 3：Hard/Soft Consistency 与 Loss Ablation</h3>
<p>目的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>证明 Soft TreeHeap 没有破坏 Hard TreeHeap 的核心算子；
</span></span><span style="display:flex;"><span>同时验证 multi-kernel 训练是否比大锅炖总 loss 更稳定。
</span></span></code></pre></div><p>这个实验分三部分。</p>
<p>第一半验证 hard/soft 一致性。</p>
<p>构造一个确定的 hard TreeHeap：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        8
</span></span><span style="display:flex;"><span>      /   \
</span></span><span style="display:flex;"><span>     4     12
</span></span><span style="display:flex;"><span>    / \    / \
</span></span><span style="display:flex;"><span>   2   6  10 14
</span></span></code></pre></div><p>hard 查询：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query = 6
</span></span><span style="display:flex;"><span>8 -&gt; left
</span></span><span style="display:flex;"><span>4 -&gt; right
</span></span><span style="display:flex;"><span>6 -&gt; stop
</span></span><span style="display:flex;"><span>output = E
</span></span></code></pre></div><p>soft 查询使用同一棵树，但每一步不是确定动作，而是概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>at 8:
</span></span><span style="display:flex;"><span>  stop  0.01
</span></span><span style="display:flex;"><span>  left  0.98
</span></span><span style="display:flex;"><span>  right 0.01
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>at 4:
</span></span><span style="display:flex;"><span>  stop  0.01
</span></span><span style="display:flex;"><span>  left  0.01
</span></span><span style="display:flex;"><span>  right 0.98
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>at 6:
</span></span><span style="display:flex;"><span>  stop  0.98
</span></span><span style="display:flex;"><span>  left  0.01
</span></span><span style="display:flex;"><span>  right 0.01
</span></span></code></pre></div><p>这时正确路径概率约为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.98 * 0.98 * 0.98 = 0.941192
</span></span></code></pre></div><p>如果 temperature 继续降低，概率会更接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1.0
</span></span></code></pre></div><p>那么 soft 输出应该收敛到 hard 输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>output_soft -&gt; E
</span></span></code></pre></div><p>判断指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>hard-soft output gap 是否下降；
</span></span><span style="display:flex;"><span>正确路径概率是否上升；
</span></span><span style="display:flex;"><span>collapse 后路径是否合法；
</span></span><span style="display:flex;"><span>collapse 后是否等于 hard route。
</span></span></code></pre></div><p>第二半验证写入机制。</p>
<p>同一个 key/value lookup 建树任务，比较三种写入方式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A: naive soft memory write
</span></span><span style="display:flex;"><span>B: encoder soft plus
</span></span><span style="display:flex;"><span>C: kernel-guided soft plus
</span></span></code></pre></div><p>A 是弱版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr_new[i] =
</span></span><span style="display:flex;"><span>  (1 - p[i]) * arr_old[i]
</span></span><span style="display:flex;"><span>+ p[i] * write_vector
</span></span></code></pre></div><p>它测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>普通神经内存写入能做到什么程度。
</span></span></code></pre></div><p>B 是中间版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next = sum_a p(a | H, x) * (H ⊕_a x)
</span></span></code></pre></div><p>但 <code>p(a)</code> 由普通 encoder 给出。</p>
<p>它测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只要有 soft plus，是否就足够。
</span></span></code></pre></div><p>C 是 TreeHeap 正式版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score(a) = K_write(subheap(H, a), x)
</span></span><span style="display:flex;"><span>p(a) = softmax(score(a))
</span></span><span style="display:flex;"><span>H_next = sum_a p(a) * (H ⊕_a x)
</span></span></code></pre></div><p>它测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用 TreeHeap 卷积核来决定写入位置，
</span></span><span style="display:flex;"><span>是否比普通 encoder 更稳定、更可解释、更能外推。
</span></span></code></pre></div><p>判断指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>lookup accuracy
</span></span><span style="display:flex;"><span>OOD N=31/63 accuracy
</span></span><span style="display:flex;"><span>expected search depth
</span></span><span style="display:flex;"><span>collapse legality rate
</span></span><span style="display:flex;"><span>route interpretability
</span></span><span style="display:flex;"><span>hard-soft output gap
</span></span><span style="display:flex;"><span>subheap relocation accuracy
</span></span></code></pre></div><p>如果我们的判断正确，C 应该至少在这些地方更好：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>更容易形成可解释路径；
</span></span><span style="display:flex;"><span>更容易坍缩成合法 TreeHeap；
</span></span><span style="display:flex;"><span>在更大 N 上失败尾部更少；
</span></span><span style="display:flex;"><span>对 subheap relocation 更稳。
</span></span></code></pre></div><p>第三半验证 loss 设计。</p>
<p>同一个 lookup 任务，比较三种训练方式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>D: only task loss
</span></span><span style="display:flex;"><span>E: 大锅炖总 loss
</span></span><span style="display:flex;"><span>F: multi-kernel staged training
</span></span></code></pre></div><p>其中 E 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L =
</span></span><span style="display:flex;"><span>  L_task
</span></span><span style="display:flex;"><span>+ alpha * L_order
</span></span><span style="display:flex;"><span>+ beta  * L_depth
</span></span><span style="display:flex;"><span>+ gamma * L_entropy
</span></span></code></pre></div><p>F 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Stage 1: train route/task head
</span></span><span style="display:flex;"><span>Stage 2: add order head
</span></span><span style="display:flex;"><span>Stage 3: add depth head
</span></span><span style="display:flex;"><span>Stage 4: add collapse head
</span></span></code></pre></div><p>如果我们的判断正确，F 应该更稳。</p>
<p>预期结果不是 F 在所有指标上都赢。</p>
<p>更具体的 predict 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>F 的梯度爆炸/消失次数更少；
</span></span><span style="display:flex;"><span>F 的 collapse 更晚、更可控；
</span></span><span style="display:flex;"><span>F 的 order violation 下降更平滑；
</span></span><span style="display:flex;"><span>F 在 OOD N=31/63 上失败尾部更少；
</span></span><span style="display:flex;"><span>E 可能训练更快，但更容易过早坍缩或目标对冲。
</span></span></code></pre></div><h2 id="falsification什么结果会否定我们">Falsification：什么结果会否定我们</h2>
<p>这也要写清楚。</p>
<p>如果出现这些结果，claim 就要降级：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft TreeHeap 的 loss 不下降。
</span></span><span style="display:flex;"><span>Soft route 梯度长期为 0 或爆炸。
</span></span><span style="display:flex;"><span>TreeHeap lookup 不如同规模 MLP。
</span></span><span style="display:flex;"><span>TreeHeap 无法外推到更大 N。
</span></span><span style="display:flex;"><span>prefix tree 长度不如 fixed-length baseline。
</span></span><span style="display:flex;"><span>soft collapse 后得不到合法 hard TreeHeap。
</span></span><span style="display:flex;"><span>kernel-guided soft plus 不如 naive memory write。
</span></span><span style="display:flex;"><span>multi-kernel 比大锅炖总 loss 更不稳定。
</span></span><span style="display:flex;"><span>encoder 没有学出任何可解释结构。
</span></span></code></pre></div><p>这些结果说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可能只是复杂包装，
</span></span><span style="display:flex;"><span>没有带来有效归纳偏置。
</span></span></code></pre></div><h2 id="当前-claim-的边界">当前 Claim 的边界</h2>
<p>到目前为止，我们还没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft TreeHeap 一定能训练成功。
</span></span><span style="display:flex;"><span>TreeHeap 一定优于 Transformer。
</span></span><span style="display:flex;"><span>TreeHeap 能做 WMT。
</span></span><span style="display:flex;"><span>Huffman-like 结构一定能通过梯度学出来。
</span></span></code></pre></div><p>现在只是确定了下一步要证明什么。</p>
<p>真正的 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 如果要作为机器学习结构存在，
</span></span><span style="display:flex;"><span>必须能让梯度进入它的结构状态。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Soft write 不应该只是内存插值。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>正式路径应该是：
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>kernel-guided soft plus、soft route、soft stop/read。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>如果这条路径成立，
</span></span><span style="display:flex;"><span>TreeHeap 就能像 MLP / Transformer 一样用 loss 学习；
</span></span><span style="display:flex;"><span>并且可能在搜索、压缩、路径解码这类结构任务上表现更好。
</span></span></code></pre></div><p>这就是 <code>SPR-019</code> 要进入实验的地方。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-020] Soft TreeHeap 审计：proof 证明了什么，没证明什么</title>
      <link>https://www.grepcode.cn/spr/020-soft-treeheap-audit.html</link>
      <pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/020-soft-treeheap-audit.html</guid>
      <description>根据 GLM/Runner 的复现实验修订 ARA：区分梯度可达、toy 坍缩、clean kernel 学习三件不同的事，并说明下一步实验。</description>
      <content:encoded><![CDATA[<h1 id="soft-treeheap-审计proof-证明了什么没证明什么">Soft TreeHeap 审计：proof 证明了什么，没证明什么</h1>
<p>上一篇 <code>SPR-019</code> 讲了一个关键设计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Hard TreeHeap 是离散树堆。
</span></span><span style="display:flex;"><span>Soft TreeHeap 是它的概率提升。
</span></span></code></pre></div><p>也就是说，原来 hard 操作是：</p>
$$ H_{\text{next}} = H \oplus_a x $$<p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把 x 按 TreeHeap plus 的规则写到地址 a。
</span></span></code></pre></div><p>Soft 以后变成：</p>
$$ H_{\text{next}} = \sum_a p(a \mid H, x) \cdot (H \oplus_a x) $$<p>翻译成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型暂时不知道 x 应该写到哪个地址。
</span></span><span style="display:flex;"><span>所以它先对多个地址都生成候选结果，
</span></span><span style="display:flex;"><span>再按照概率 p(a) 混合这些候选结果。
</span></span></code></pre></div><p>如果训练到最后：</p>
$$ p(LL)=1.0,\quad p(\text{other})=0.0 $$<p>那么 Soft TreeHeap 就坍缩回 hard 操作：</p>
$$ H_{\text{next}} = H \oplus_{LL} x $$<p>这个设计是为了让梯度进入 TreeHeap。</p>
<p>但 GLM/Runner 复现实验后指出了一个很重要的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 proof 确实证明了梯度能流动，
</span></span><span style="display:flex;"><span>也证明了当前 toy 能坍缩到正确地址。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>但它还没有证明：
</span></span><span style="display:flex;"><span>kernel 能从干净的 TreeHeap 子结构里自己学会路由。
</span></span></code></pre></div><p>这篇文章就是把这个边界讲清楚。</p>
<h2 id="三件事不要混在一起">三件事不要混在一起</h2>
<p>我们现在有三件很像、但其实不同的事。</p>
<p>第一件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度能不能进入 TreeHeap？
</span></span></code></pre></div><p>这是 <code>M0-SOFT-C03</code>。</p>
<p>如果 loss 算完以后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>d loss / d K_write != 0
</span></span><span style="display:flex;"><span>d loss / d Plus_a  != 0
</span></span></code></pre></div><p>说明梯度确实能更新写入 kernel 和 plus 参数。</p>
<p>第二件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 toy 能不能坍缩到正确 hard 地址？
</span></span></code></pre></div><p>这是 <code>M0-SOFT-C04</code>。</p>
<p>如果低温 softmax 后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>argmax p(a) = gold_address
</span></span></code></pre></div><p>而且准确率是 1.0，说明当前 toy 在当前特征下能坍缩。</p>
<p>第三件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 能不能不靠人工提示，
</span></span><span style="display:flex;"><span>从 TreeHeap 子结构里自己学会路由？
</span></span></code></pre></div><p>这是更强的 <code>M0-SOFT-C05 / P-SOFT02</code>。</p>
<p>这还没有证明。</p>
<p>这三件事的关系像这样：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度能流
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>当前 toy 能坍缩
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>干净 kernel 能自己学路由
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>TreeHeap 写入机制比普通神经内存更好
</span></span></code></pre></div><p>我们现在只走完了前两步。</p>
<h2 id="这些-claim-编号到底是什么意思">这些 Claim 编号到底是什么意思</h2>
<p><code>M0-SOFT-C03</code> 这种编号看起来像内部黑话，其实可以拆开看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0        = Math layer 0，也就是 TreeHeap 的数学地基
</span></span><span style="display:flex;"><span>SOFT      = Soft TreeHeap，也就是可微概率版本
</span></span><span style="display:flex;"><span>C03 / C04 = 第 3 / 第 4 条 claim
</span></span></code></pre></div><p>这里的 claim 不是口号，而是一个可以被实验检查的小命题。</p>
<h3 id="m0-soft-c03梯度可达">M0-SOFT-C03：梯度可达</h3>
<p>白话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss 算出来以后，能不能真的改到 TreeHeap 的写入 kernel 和 plus 参数？
</span></span></code></pre></div><p>数学上就是看：</p>
$$ \left\lVert\frac{\partial L}{\partial K_{\text{write}}}\right\rVert > 0 $$<p>以及：</p>
$$ \left\lVert\frac{\partial L}{\partial \text{Plus}}\right\rVert > 0 $$<p>类比线性回归：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>线性回归里，如果 dL/dW = 0，
</span></span><span style="display:flex;"><span>W 就不会被训练数据改变。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TreeHeap 里，如果 dL/dK_write = 0，
</span></span><span style="display:flex;"><span>写入 kernel 就不会被训练数据改变。
</span></span></code></pre></div><p>所以 C03 证明的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的这些参数不是死的。
</span></span><span style="display:flex;"><span>训练信号能碰到它们。
</span></span></code></pre></div><p>它还没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这些参数已经学会了好的结构。
</span></span></code></pre></div><h3 id="m0-soft-c04低温坍缩能回到-hard-地址">M0-SOFT-C04：低温坍缩能回到 hard 地址</h3>
<p>白话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft TreeHeap 训练时可以保留多个可能地址，
</span></span><span style="display:flex;"><span>但最后能不能收敛成一个明确的 hard 地址？
</span></span></code></pre></div><p>例如一开始模型可能这样想：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LL: 0.25
</span></span><span style="display:flex;"><span>LR: 0.25
</span></span><span style="display:flex;"><span>RL: 0.25
</span></span><span style="display:flex;"><span>RR: 0.25
</span></span></code></pre></div><p>训练后变成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LL: 0.98
</span></span><span style="display:flex;"><span>LR: 0.01
</span></span><span style="display:flex;"><span>RL: 0.005
</span></span><span style="display:flex;"><span>RR: 0.005
</span></span></code></pre></div><p>低温 softmax 或 argmax 后，就可以坍缩成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LL
</span></span></code></pre></div><p>这就是 C04。</p>
<p>类比一下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>考试早期，学生在四个选项里摇摆。
</span></span><span style="display:flex;"><span>训练后，学生几乎确定选 A。
</span></span><span style="display:flex;"><span>最终交卷时，只能填一个答案。
</span></span></code></pre></div><p>C04 证明的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft 的概率状态可以变回 Hard 的离散结构。
</span></span></code></pre></div><p>这很重要。因为如果 Soft TreeHeap 永远只是一团概率雾，它就不能回到我们前面建立的 hard TreeHeap 数学地基。</p>
<h3 id="m0-soft-c05treeheap-kernel-是否真的更好">M0-SOFT-C05：TreeHeap kernel 是否真的更好</h3>
<p>C05 比 C03/C04 强很多。</p>
<p>它问的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用 TreeHeap 子结构 kernel 来决定写入位置，
</span></span><span style="display:flex;"><span>是否比普通神经内存写入更好？
</span></span></code></pre></div><p>这才接近 TreeHeap 的存在性问题。</p>
<p>如果 C05 成立，说明 TreeHeap 不是只是“也能训练”，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在需要地址、子结构迁移、路径复用、延迟坍缩的问题上，
</span></span><span style="display:flex;"><span>TreeHeap 的结构 bias 可能真的有优势。
</span></span></code></pre></div><p>如果 C05 不成立，那也很重要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>说明当前 TreeHeap 写入设计可能只是复杂包装，
</span></span><span style="display:flex;"><span>普通 MLP / neural memory 已经够用了。
</span></span></code></pre></div><h2 id="当前-proof-做了什么">当前 proof 做了什么</h2>
<p><code>soft_plus_probe.py</code> 用了一个很小的地址集合：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LL, LR, RL, RR
</span></span></code></pre></div><p>你可以把它想成一棵深度为 2 的小树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        root
</span></span><span style="display:flex;"><span>       /    \
</span></span><span style="display:flex;"><span>      L      R
</span></span><span style="display:flex;"><span>     / \    / \
</span></span><span style="display:flex;"><span>   LL  LR  RL  RR
</span></span></code></pre></div><p>输入一些 key：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>2, 3   -&gt; LL
</span></span><span style="display:flex;"><span>5, 6   -&gt; LR
</span></span><span style="display:flex;"><span>10, 11 -&gt; RL
</span></span><span style="display:flex;"><span>13, 14 -&gt; RR
</span></span></code></pre></div><p>模型要学会：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定 key，选择正确地址。
</span></span></code></pre></div><p>然后用 Soft Plus 生成：</p>
$$ H_{\text{next}} = \sum_a p(a) \cdot \text{Plus}_a(H, key) $$<p>loss 会比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next
</span></span></code></pre></div><p>和目标 TreeHeap。</p>
<p>如果 loss 下降，并且梯度能传到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_write
</span></span><span style="display:flex;"><span>Plus_a
</span></span></code></pre></div><p>就说明 Soft Plus 的训练链路是通的。</p>
<p>当前结果是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pilot_pass = true
</span></span><span style="display:flex;"><span>initial_loss = 0.677455
</span></span><span style="display:flex;"><span>final_loss   = 0.000774
</span></span><span style="display:flex;"><span>dL/dK_write  = 0.0902425
</span></span><span style="display:flex;"><span>dL/dPlus     = 0.143869
</span></span><span style="display:flex;"><span>collapse_accuracy_tau_0.05 = 1.0
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss 明显下降；
</span></span><span style="display:flex;"><span>梯度不是 0；
</span></span><span style="display:flex;"><span>低温坍缩能选中正确地址。
</span></span></code></pre></div><p>所以 C03/C04 是成立的。</p>
<p>但要注意：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>成立范围是这个 synthetic toy。
</span></span></code></pre></div><p>不是语言任务。</p>
<p>不是 WMT。</p>
<p>不是 Transformer 替代。</p>
<h2 id="glm-的审计发现">GLM 的审计发现</h2>
<p>GLM/Runner 做了两类复现。</p>
<p>第一类是多 seed 复现：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Seed</th>
          <th>pilot_pass</th>
          <th style="text-align: right">collapse_acc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">42</td>
          <td>true</td>
          <td style="text-align: right">1.0</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td>true</td>
          <td style="text-align: right">1.0</td>
      </tr>
      <tr>
          <td style="text-align: right">123</td>
          <td>true</td>
          <td style="text-align: right">1.0</td>
      </tr>
      <tr>
          <td style="text-align: right">999</td>
          <td>true</td>
          <td style="text-align: right">1.0</td>
      </tr>
  </tbody>
</table>
<p>这说明 proof 不是一次随机运气。</p>
<p>第二类是 ablation，也就是把某些设计拿掉，看结果会不会坏。</p>
<p>最重要的结果是：</p>
<table>
  <thead>
      <tr>
          <th>特征集合</th>
          <th style="text-align: right">collapse_acc</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>当前完整特征</td>
          <td style="text-align: right">1.000</td>
          <td>proof 通过</td>
      </tr>
      <tr>
          <td>去掉 alignment/sum 特征</td>
          <td style="text-align: right">0.625</td>
          <td>明显退化</td>
      </tr>
      <tr>
          <td>raw/basic 8D 特征</td>
          <td style="text-align: right">0.250</td>
          <td>接近随机</td>
      </tr>
      <tr>
          <td>随机投影 + side flags</td>
          <td style="text-align: right">0.250</td>
          <td>接近随机</td>
      </tr>
  </tbody>
</table>
<p>这里的 <code>0.250</code> 很好理解。</p>
<p>因为地址有 4 个：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LL, LR, RL, RR
</span></span></code></pre></div><p>随机猜一个，准确率就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 / 4 = 0.25
</span></span></code></pre></div><p>所以 raw/basic 特征下的模型基本没学会路由。</p>
<h2 id="问题出在哪里">问题出在哪里</h2>
<p>当前 kernel features 里有两个很强的人工提示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>root_alignment <span style="color:#f92672">=</span> root_diff <span style="color:#f92672">*</span> root_side
</span></span><span style="display:flex;"><span>child_alignment <span style="color:#f92672">=</span> diff <span style="color:#f92672">*</span> child_side
</span></span></code></pre></div><p>这两个公式确实容易看懵。我们拆开讲。</p>
<p>假设当前 toy 是一棵二叉搜索树。为了判断一个 key 应该往左还是往右，最原始的信息应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>key 是多少？
</span></span><span style="display:flex;"><span>root key 是多少？
</span></span><span style="display:flex;"><span>left child key 是多少？
</span></span><span style="display:flex;"><span>right child key 是多少？
</span></span></code></pre></div><p>模型应该自己从这些数里学出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>key &lt; root_key  -&gt; 往左
</span></span><span style="display:flex;"><span>key &gt; root_key  -&gt; 往右
</span></span></code></pre></div><p>但是当前 proof 里又额外给了两个方向提示。</p>
<p>先看第一个：</p>
$$ \operatorname{root\_diff} = \operatorname{key} - \operatorname{root\_key} $$<p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>key = 5
</span></span><span style="display:flex;"><span>root_key = 8
</span></span></code></pre></div><p>那么：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root_diff = 5 - 8 = -3
</span></span></code></pre></div><p>它表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>key 在 root 的左边。
</span></span></code></pre></div><p>再看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root_side
</span></span></code></pre></div><p>这个变量不是从数值自然学出来的，它是人为给的“正确大方向”。可以粗略理解成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>目标地址在 root 左边时，root_side = -1
</span></span><span style="display:flex;"><span>目标地址在 root 右边时，root_side = +1
</span></span></code></pre></div><p>于是：</p>
$$ \operatorname{root\_alignment} = \operatorname{root\_diff} \cdot \operatorname{root\_side} $$<p>如果 key=5，root_key=8，目标确实在左边：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root_diff = -3
</span></span><span style="display:flex;"><span>root_side = -1
</span></span><span style="display:flex;"><span>root_alignment = (-3) * (-1) = 3
</span></span></code></pre></div><p>结果是正数。</p>
<p>正数就像在告诉模型：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个方向和目标方向对齐。
</span></span></code></pre></div><p>如果方向错了，乘出来就会是负数。</p>
<p>所以 <code>root_alignment</code> 的问题在于：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它不是单纯告诉模型 key 和 root 的关系；
</span></span><span style="display:flex;"><span>它把“这个关系是否符合正确路由方向”也编码进去了。
</span></span></code></pre></div><p>这就接近答案提示。</p>
<p>第二个公式：</p>
$$ \operatorname{child\_alignment} = \operatorname{diff} \cdot \operatorname{child\_side} $$<p>作用类似，只是它看的是更下面一层 child 的方向。</p>
<p>可以这样理解：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root_alignment 帮模型判断第一步走 L 还是 R。
</span></span><span style="display:flex;"><span>child_alignment 帮模型判断第二步走 LL/LR 或 RL/RR。
</span></span></code></pre></div><p>所以这两个 feature 不是普通“观测数据”，而是已经把搜索路径的判断边界整理好了。</p>
<p>它们已经把路由边界编码进去了。</p>
<p>可以粗略理解成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 root_alignment 为正，说明 key 应该走 root_side 指示的方向。
</span></span><span style="display:flex;"><span>如果 child_alignment 为正，说明 key 应该走 child_side 指示的方向。
</span></span></code></pre></div><p>这就像考试时给学生一张提示纸：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果看到这个符号，就选左边。
</span></span><span style="display:flex;"><span>如果看到那个符号，就选右边。
</span></span></code></pre></div><p>学生最后答对了。</p>
<p>这当然说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>笔能写；
</span></span><span style="display:flex;"><span>答案纸能收；
</span></span><span style="display:flex;"><span>分数能反馈；
</span></span><span style="display:flex;"><span>学生能根据提示填答案。
</span></span></code></pre></div><p>但还不能说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>学生真的学会了这门课。
</span></span></code></pre></div><p>对应到 TreeHeap：</p>
<p>当前 proof 能说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度链路通了。
</span></span><span style="display:flex;"><span>Soft Plus 可以坍缩。
</span></span></code></pre></div><p>但还不能说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 从子树几何里学会了搜索规则。
</span></span></code></pre></div><h2 id="为什么这不是否定-treeheap">为什么这不是否定 TreeHeap</h2>
<p>这点要说清楚。</p>
<p>GLM 的审计不是在说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 错了。
</span></span></code></pre></div><p>它是在说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 evidence 的边界要写清楚。
</span></span></code></pre></div><p><code>M0-SOFT-C03</code> 的 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Kernel-guided Soft Plus can receive gradient through K_write and Plus_a.
</span></span></code></pre></div><p>这个 claim 只问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度有没有到？
</span></span></code></pre></div><p>答案是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>到了。
</span></span></code></pre></div><p><code>M0-SOFT-C04</code> 的 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Kernel-guided Soft Plus can collapse to the correct hard plus address
</span></span><span style="display:flex;"><span>in the synthetic toy.
</span></span></code></pre></div><p>这个 claim 只问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 toy 有没有坍缩对？
</span></span></code></pre></div><p>答案也是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对了。
</span></span></code></pre></div><p>但 <code>M0-SOFT-C05</code> 问的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Kernel-guided Soft Plus 是否比 naive memory write 或 generic encoder soft plus 更好？
</span></span></code></pre></div><p>这个还没有做。</p>
<p>所以 ARA 修订后的状态是：</p>
<table>
  <thead>
      <tr>
          <th>Claim</th>
          <th>状态</th>
          <th>解释</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>C03 梯度可达</td>
          <td>supported</td>
          <td>当前 toy 有证据</td>
      </tr>
      <tr>
          <td>C04 toy 坍缩</td>
          <td>supported</td>
          <td>当前 toy 有证据</td>
      </tr>
      <tr>
          <td>C05 优于普通写入</td>
          <td>open</td>
          <td>需要下一步 ablation</td>
      </tr>
      <tr>
          <td>clean kernel 学路由</td>
          <td>open</td>
          <td>当前 ablation 显示还没证明</td>
      </tr>
  </tbody>
</table>
<h2 id="ara-做了哪些修订">ARA 做了哪些修订</h2>
<p>这次我把 SameTime 里的 ARA 做了几件修订。</p>
<p>第一，给 <code>claims.md</code> 加了 scope notes。</p>
<p>现在 C03/C04 明确写了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>in scope:
</span></span><span style="display:flex;"><span>  当前 toy 的梯度可达和坍缩。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>out of scope:
</span></span><span style="display:flex;"><span>  干净 kernel 从 raw subheap geometry 自己学会路由。
</span></span></code></pre></div><p>第二，加了 GLM audit summary：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/soft_plus_probe/glm_audit_summary.md
</span></span></code></pre></div><p>这里保存多 seed 复现和 feature ablation 结论。</p>
<p>第三，补了结构化 trace：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/trace/exploration_tree.yaml
</span></span></code></pre></div><p>这个文件记录：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>问题是什么；
</span></span><span style="display:flex;"><span>为什么拒绝 naive memory write；
</span></span><span style="display:flex;"><span>当前 proof 证明了什么；
</span></span><span style="display:flex;"><span>GLM ablation 发现了什么；
</span></span><span style="display:flex;"><span>为什么下一步要做 clean-kernel proof。
</span></span></code></pre></div><p>第四，把 <code>log/ara</code> 里缺失的 S2 诊断证据同步进 SameTime：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s2-translation/evidence/frame_probe_2h_queue/
</span></span><span style="display:flex;"><span>ara/s2-translation/evidence/overnight_stopped_20260617/
</span></span></code></pre></div><p>这些不是正向成功证据。</p>
<p>它们是诊断证据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>说明历史 checkpoint 和 world-model/frame probe 还不能支撑强 claim。
</span></span></code></pre></div><p>这类失败或不充分证据也必须进入 ARA。</p>
<p>因为 ARA 的目的不是只保存胜利。</p>
<p>ARA 的目的是真实保存研究状态。</p>
<h2 id="下一步真正该-proof-什么">下一步真正该 proof 什么</h2>
<p>下一步不是再证明一次：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度能流。
</span></span></code></pre></div><p>这个已经有了。</p>
<p>下一步应该证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>clean kernel 能不能学会 TreeHeap 路由。
</span></span></code></pre></div><p>也就是新的 <code>P-SOFT02</code>。</p>
<p>这句话的实际含义是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给模型一棵 TreeHeap 的局部子结构，
</span></span><span style="display:flex;"><span>不给它人工整理好的答案方向，
</span></span><span style="display:flex;"><span>让它通过训练自己学出：
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>什么时候往左；
</span></span><span style="display:flex;"><span>什么时候往右；
</span></span><span style="display:flex;"><span>什么时候 stop；
</span></span><span style="display:flex;"><span>什么时候 merge；
</span></span><span style="display:flex;"><span>哪个地址更像正确写入位置。
</span></span></code></pre></div><p>这和我们的总目标直接相关。</p>
<p>TreeHeap 最终想证明的不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我也能把数组槽位 softmax 写一遍。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树结构、路径、子堆、前缀、概率容器这些结构工具，
</span></span><span style="display:flex;"><span>能让模型在某些任务上更有效地学习和外推。
</span></span></code></pre></div><p>如果 clean kernel 能学会路由，预期改进是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 更少人工规则：不用手写 root_alignment 这种答案提示。
</span></span><span style="display:flex;"><span>2. 更强迁移：同一个 kernel 可以在不同地址、不同子树上复用。
</span></span><span style="display:flex;"><span>3. 更好外推：训练见过浅层地址，测试能处理更深地址。
</span></span><span style="display:flex;"><span>4. 更可解释：失败时能看出是 stop/left/right 哪一步错了。
</span></span><span style="display:flex;"><span>5. 更接近语言结构：后续 S2 的 fold/slot/graph 才可能接上这个结构 kernel。
</span></span></code></pre></div><p>如果 clean kernel 学不会，也会告诉我们一个硬事实：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 TreeHeap 的可微写入还缺少足够表达力；
</span></span><span style="display:flex;"><span>也许需要 MLP kernel、多头 kernel、额外结构 loss，
</span></span><span style="display:flex;"><span>或者 TreeHeap plus 本身还要改。
</span></span></code></pre></div><p>干净输入应该只给：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>key
</span></span><span style="display:flex;"><span>parent key
</span></span><span style="display:flex;"><span>left child key
</span></span><span style="display:flex;"><span>right child key
</span></span><span style="display:flex;"><span>is_leaf
</span></span><span style="display:flex;"><span>depth/address metadata
</span></span></code></pre></div><p>不允许给：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root_side
</span></span><span style="display:flex;"><span>child_side
</span></span><span style="display:flex;"><span>root_alignment
</span></span><span style="display:flex;"><span>child_alignment
</span></span></code></pre></div><p>因为这些太像答案提示。</p>
<p>实验要比较三种写入方式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A: naive soft memory write
</span></span><span style="display:flex;"><span>B: encoder soft plus
</span></span><span style="display:flex;"><span>C: kernel-guided soft plus
</span></span></code></pre></div><p>A 是普通神经内存写入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr_new[i] = (1 - p[i]) * arr_old[i] + p[i] * write_vector
</span></span></code></pre></div><p>B 是 soft plus，但地址概率由普通 encoder 输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>MLP(H, x) -&gt; p(a)
</span></span><span style="display:flex;"><span>H_next = sum_a p(a) * Plus_a(H, x)
</span></span></code></pre></div><p>C 是 TreeHeap 版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_write(subheap(H, a), x) -&gt; score(a)
</span></span><span style="display:flex;"><span>H_next = sum_a softmax(score(a)) * Plus_a(H, x)
</span></span></code></pre></div><p>判断指标包括：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>collapse_accuracy
</span></span><span style="display:flex;"><span>final_loss
</span></span><span style="display:flex;"><span>hard_soft_gap
</span></span><span style="display:flex;"><span>collapse_legality
</span></span><span style="display:flex;"><span>unseen_address_accuracy
</span></span><span style="display:flex;"><span>sample_efficiency
</span></span></code></pre></div><p>如果 C 在干净特征下赢 A 和 B，那么 C05 可以升级。</p>
<p>如果 A 或 B 一样好，说明 TreeHeap kernel 的优势还没有证明。</p>
<p>如果三者都失败，就要重新设计 kernel。</p>
<h2 id="给本科水平读者的一句话总结">给本科水平读者的一句话总结</h2>
<p>现在的状态可以这样理解：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们证明了：
</span></span><span style="display:flex;"><span>TreeHeap 这套结构可以接上梯度管道。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>我们还没有证明：
</span></span><span style="display:flex;"><span>TreeHeap kernel 能自己从树结构里学会聪明的搜索规则。
</span></span></code></pre></div><p>更口语一点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>水管通了。
</span></span><span style="display:flex;"><span>水能流到 TreeHeap 的 kernel 和 plus 参数。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>但水流到那里以后，
</span></span><span style="display:flex;"><span>能不能灌出一棵真正会搜索、会压缩、会外推的树，
</span></span><span style="display:flex;"><span>还要做下一组实验。
</span></span></code></pre></div><p>这不是坏消息。</p>
<p>这是研究进入下一层的信号。</p>
<p>因为现在的问题已经从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能不能训练？
</span></span></code></pre></div><p>变成了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的结构归纳偏置，能不能比普通神经内存更有效？
</span></span></code></pre></div><p>这才是 TreeHeap 是否有存在性的关键问题。</p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-021] C05：TreeHeap 不能只是披着树皮的 MLP</title>
      <link>https://www.grepcode.cn/spr/021-c05-structural-proof.html</link>
      <pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/021-c05-structural-proof.html</guid>
      <description>把 C05 改成结构 proof：如果公式里没有路径、前缀、子堆和递归 plus，它就只是 flat soft memory。</description>
      <content:encoded><![CDATA[<h1 id="c05treeheap-不能只是披着树皮的-mlp">C05：TreeHeap 不能只是披着树皮的 MLP</h1>
<p>上一篇 <code>SPR-020</code> 说清楚了一件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Soft Plus 的梯度管道已经通了。
</span></span><span style="display:flex;"><span>但 clean kernel 是否能自己学会路由，还没有证明。
</span></span></code></pre></div><p>然后 Houming818 提了一个更深的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果公式里没有地址、路径、子结构，
</span></span><span style="display:flex;"><span>那它看起来还是一个 MLP 或线性内存，
</span></span><span style="display:flex;"><span>只是外面贴了 TreeHeap 这个名字。
</span></span></code></pre></div><p>这个批评是对的。</p>
<p>所以 <code>C05</code> 不能只问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel-guided soft plus 能不能训练？
</span></span></code></pre></div><p>它必须先问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个 kernel 到底有没有用到 TreeHeap 的结构？
</span></span></code></pre></div><h2 id="flat-mlp-的自然形式">Flat MLP 的自然形式</h2>
<p>线性回归是：</p>
$$ \hat y = Wx + b $$<p>MLP 是：</p>
$$ \hat y = f_\theta(x) $$<p>这类模型的核心是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把输入 x 映射到一个任务空间；
</span></span><span style="display:flex;"><span>再通过距离、logit、argmax 得到输出。
</span></span></code></pre></div><p>这没有问题。</p>
<p>但它是 flat 的。</p>
<p>它没有天然的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>地址；
</span></span><span style="display:flex;"><span>路径；
</span></span><span style="display:flex;"><span>前缀；
</span></span><span style="display:flex;"><span>子堆；
</span></span><span style="display:flex;"><span>递归更新。
</span></span></code></pre></div><p>如果 TreeHeap 公式只是：</p>
$$ H_{t+1} = \sum_a p(a \mid H_t,x_t)\operatorname{Plus}_a(H_t,x_t) $$<p>那还不够。</p>
<p>因为这里的 \(a\) 可能只是普通数组槽位：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a = 0, 1, 2, 3, ...
</span></span></code></pre></div><p>这会退化成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>softmax memory write
</span></span></code></pre></div><p>也就是一个 flat memory MLP。</p>
<h2 id="treeheap-的地址必须是路径">TreeHeap 的地址必须是路径</h2>
<p>TreeHeap 里的地址不应该只是数字。</p>
<p>它应该是路径：</p>
$$ a \in \{L,R\}^{*} $$<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>epsilon = root
</span></span><span style="display:flex;"><span>L       = root -&gt; left
</span></span><span style="display:flex;"><span>R       = root -&gt; right
</span></span><span style="display:flex;"><span>LLR     = root -&gt; left -&gt; left -&gt; right
</span></span></code></pre></div><p>这个路径空间有一个 flat index 没有的性质：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>前缀关系。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L 是 LL 和 LR 的共同前缀；
</span></span><span style="display:flex;"><span>LL 和 LR 比 LL 和 RR 更接近；
</span></span><span style="display:flex;"><span>LLR 的父路径是 LL。
</span></span></code></pre></div><p>这就是结构。</p>
<p>所以 TreeHeap 的 kernel 不能只看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>address_id
</span></span></code></pre></div><p>而应该看：</p>
$$ K_\theta(\pi(a), \operatorname{subheap}(H,a), x) $$<p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pi(a)
</span></span><span style="display:flex;"><span>路径表示
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>subheap(H,a)
</span></span><span style="display:flex;"><span>以地址 a 为 root 的局部子堆
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>x
</span></span><span style="display:flex;"><span>当前输入或查询
</span></span></code></pre></div><h2 id="plus-也必须是递归的">Plus 也必须是递归的</h2>
<p>如果 <code>Plus_a</code> 只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[a] = x
</span></span></code></pre></div><p>那它仍然是数组写入。</p>
<p>TreeHeap 的 plus 应该沿路径递归。</p>
<p>如果目标地址是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a = d :: a&#39;
</span></span></code></pre></div><p>其中 \(d\) 是第一步方向：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>d in {L, R}
</span></span></code></pre></div><p>那么递归 plus 应该是：</p>
$$ \operatorname{Plus}^{tree}_{d::a'}(H,x) = \operatorname{rebuild} ( root(H), \operatorname{Plus}^{tree}_{a'}(child_d(H),x), child_{\bar d}(H) ) $$<p>终止条件是：</p>
$$ \operatorname{Plus}^{tree}_{\epsilon}(H,x) = \operatorname{merge}(H,x) $$<p>白话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果目标在 left 子树，
</span></span><span style="display:flex;"><span>就递归更新 left 子树；
</span></span><span style="display:flex;"><span>right 子树保持不变；
</span></span><span style="display:flex;"><span>最后把 root、left、right 重新组装。
</span></span></code></pre></div><p>这才是结构化内存。</p>
<h2 id="c05-的新公式">C05 的新公式</h2>
<p>所以 C05 的候选公式应该写成：</p>
$$ H_{t+1} = \sum_{a \in A(H_t)} \operatorname{softmax}_a \left( K_\theta(\pi(a), \operatorname{subheap}(H_t,a), x_t) \right) \cdot \operatorname{Plus}^{tree}_{\phi,a}(H_t,x_t) $$<p>这个式子里必须有三件东西：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pi(a)                  路径
</span></span><span style="display:flex;"><span>subheap(H_t,a)          子堆
</span></span><span style="display:flex;"><span>Plus^{tree}_{a}         递归 plus
</span></span></code></pre></div><p>少了这些，C05 就不应该升级。</p>
<h2 id="实验怎么-proof">实验怎么 proof</h2>
<p>我们设计一个很小的 toy。</p>
<p>生成一棵二叉树，在某个地址插入一个局部 pattern：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pattern = (root_value, left_value, right_value)
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        0.90
</span></span><span style="display:flex;"><span>       /    \
</span></span><span style="display:flex;"><span>    -0.40   0.70
</span></span></code></pre></div><p>任务是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定整棵树和 pattern，
</span></span><span style="display:flex;"><span>找出 pattern 在哪个地址。
</span></span></code></pre></div><p>训练时只把 pattern 放在浅层：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>depth = 2, 3
</span></span></code></pre></div><p>测试时把 pattern 放到深层：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>depth = 5, 6
</span></span></code></pre></div><p>如果模型只是记地址，它应该失败。</p>
<p>如果模型真的看子堆，它应该能迁移。</p>
<h2 id="四个模型">四个模型</h2>
<p>我们比较四个版本。</p>
<h3 id="c0flat-address">C0：flat address</h3>
<p>只看绝对地址编号。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个位置是 0 号、1 号、2 号……
</span></span></code></pre></div><p>它没有路径，也没有子堆。</p>
<p>预期：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>训练内可能记住；
</span></span><span style="display:flex;"><span>未见深度会失败。
</span></span></code></pre></div><h3 id="c1path-only">C1：path only</h3>
<p>看路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L, R, LL, LR, ...
</span></span></code></pre></div><p>但不看节点内容。</p>
<p>预期：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果目标 pattern 随机出现在不同地址，
</span></span><span style="display:flex;"><span>path only 也无法知道哪个子堆匹配。
</span></span></code></pre></div><h3 id="c2subheap-kernel">C2：subheap kernel</h3>
<p>看局部子堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>candidate_root
</span></span><span style="display:flex;"><span>candidate_left
</span></span><span style="display:flex;"><span>candidate_right
</span></span></code></pre></div><p>并和 query pattern 比较。</p>
<p>预期：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>即使 pattern 移到深层，也能找到。
</span></span></code></pre></div><h3 id="c3path--subheap-kernel">C3：path + subheap kernel</h3>
<p>同时看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径
</span></span><span style="display:flex;"><span>子堆
</span></span></code></pre></div><p>并能返回：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>目标地址路径
</span></span></code></pre></div><p>这个版本最接近 TreeHeap C05。</p>
<h2 id="判定标准">判定标准</h2>
<p>如果结果是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C0 / C1 在深层失败；
</span></span><span style="display:flex;"><span>C2 / C3 在深层成功；
</span></span></code></pre></div><p>说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subheap kernel 真的提供了迁移能力。
</span></span></code></pre></div><p>如果 C3 还能返回合法路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; left -&gt; right -&gt; ...
</span></span></code></pre></div><p>说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它不仅找到了目标，还能进入 recursive plus。
</span></span></code></pre></div><p>这才是 TreeHeap 的味道。</p>
<h2 id="实验结果">实验结果</h2>
<p>实验已经执行：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>src/structural_c05_probe.py
</span></span></code></pre></div><p>证据目录：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/structural_c05_probe/
</span></span></code></pre></div><p>结果表：</p>
<table>
  <thead>
      <tr>
          <th>Variant</th>
          <th style="text-align: right">Train acc</th>
          <th style="text-align: right">Test acc</th>
          <th style="text-align: right">Hit@3</th>
          <th style="text-align: right">Mean rank</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>flat_address</td>
          <td style="text-align: right">0.439</td>
          <td style="text-align: right">0.000</td>
          <td style="text-align: right">0.000</td>
          <td style="text-align: right">16.09</td>
      </tr>
      <tr>
          <td>path_only</td>
          <td style="text-align: right">0.439</td>
          <td style="text-align: right">0.000</td>
          <td style="text-align: right">0.000</td>
          <td style="text-align: right">35.44</td>
      </tr>
      <tr>
          <td>subheap_kernel</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.00</td>
      </tr>
      <tr>
          <td>path_subheap_kernel</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.00</td>
      </tr>
  </tbody>
</table>
<p>这个结果很清楚。</p>
<p><code>flat_address</code> 在训练集还有一点记忆能力：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train_acc = 0.439
</span></span></code></pre></div><p>但到未见深度以后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>test_acc = 0.000
</span></span></code></pre></div><p>说明它没有学到可迁移结构，只是在浅层地址上做记忆。</p>
<p><code>path_only</code> 也失败：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>test_acc = 0.000
</span></span></code></pre></div><p>这说明只知道路径形式还不够。因为目标 pattern 是随机放到某个深层子堆里的，只看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LLR
</span></span><span style="display:flex;"><span>RRLL
</span></span><span style="display:flex;"><span>LRRL
</span></span></code></pre></div><p>无法知道哪个位置真的匹配 pattern。</p>
<p>真正成功的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subheap_kernel
</span></span><span style="display:flex;"><span>path_subheap_kernel
</span></span></code></pre></div><p>它们在未见深度上都是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>test_acc = 1.000
</span></span><span style="display:flex;"><span>mean_rank = 1.00
</span></span></code></pre></div><p>也就是说，同一个局部子堆 kernel 可以在更深地址复用。</p>
<h2 id="这证明了什么">这证明了什么</h2>
<p>这次 proof 支持的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0-SOFT-C07:
</span></span><span style="display:flex;"><span>TreeHeap kernel 必须暴露 path / subheap / recursive route 结构，
</span></span><span style="display:flex;"><span>否则会退化成 flat soft memory。
</span></span></code></pre></div><p>更具体地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subheap 是有效结构信号；
</span></span><span style="display:flex;"><span>flat address 不是；
</span></span><span style="display:flex;"><span>path alone 也不是。
</span></span></code></pre></div><p>这回应了前面那个批评：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果公式里没有地址、路径、子结构，
</span></span><span style="display:flex;"><span>它就不像 TreeHeap。
</span></span></code></pre></div><p>现在实验告诉我们：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>至少在这个 toy 上，
</span></span><span style="display:flex;"><span>子堆结构不是装饰；
</span></span><span style="display:flex;"><span>它直接决定了未见深度迁移是否成立。
</span></span></code></pre></div><h2 id="这没有证明什么">这没有证明什么</h2>
<p>这个实验仍然很窄。</p>
<p>它没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 会语言；
</span></span><span style="display:flex;"><span>TreeHeap 会 WMT；
</span></span><span style="display:flex;"><span>TreeHeap 已经优于 Transformer；
</span></span><span style="display:flex;"><span>C05 的完整写入机制已经胜出。
</span></span></code></pre></div><p>为什么还不能升级完整 C05？</p>
<p>因为完整 C05 问的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel-guided Soft Plus
</span></span><span style="display:flex;"><span>是否优于 naive soft memory write
</span></span><span style="display:flex;"><span>和 generic encoder soft plus？
</span></span></code></pre></div><p>而本实验只证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>结构特征是必要的；
</span></span><span style="display:flex;"><span>subheap kernel 能做未见深度 relocation。
</span></span></code></pre></div><p>所以结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0-SOFT-C07 -&gt; supported pilot
</span></span><span style="display:flex;"><span>M0-SOFT-C05 -&gt; 仍然 open
</span></span></code></pre></div><p>下一步才是完整写入机制对比：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A: naive soft memory write
</span></span><span style="display:flex;"><span>B: encoder soft plus
</span></span><span style="display:flex;"><span>C: path + subheap kernel-guided soft plus
</span></span></code></pre></div><blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-022] TreeHeap 的数学底座：有根树 Hopf 代数、Operad 与 Kernel</title>
      <link>https://www.grepcode.cn/spr/022-treeheap-math-foundation.html</link>
      <pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/022-treeheap-math-foundation.html</guid>
      <description>把 SPR-011 到 SPR-021 的 TreeHeap 代数设计放回已有数学框架：BCK/MKW rooted-tree Hopf algebra、operad、decomposition space、tree kernel，以及它们对 TreeHeap kernel 的意义。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-的数学底座有根树-hopf-代数operad-与-kernel">TreeHeap 的数学底座：有根树 Hopf 代数、Operad 与 Kernel</h1>
<p>这篇不是新的实验报告。</p>
<p>它要解决一个更基础的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的数学设计，是不是我们凭空造出来的？
</span></span><span style="display:flex;"><span>还是已经有成熟数学领域能承接它？
</span></span></code></pre></div><p>现在我的判断是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不是凭空出现的。
</span></span><span style="display:flex;"><span>它很接近两个已有数学框架在工程上的合流：
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>1. 有根树上的 Hopf 代数
</span></span><span style="display:flex;"><span>2. Operad，也就是多输入、单输出的组合算子理论
</span></span></code></pre></div><p>这件事很重要。</p>
<p>因为从 <code>SPR-011</code> 到 <code>SPR-021</code>，我们一直在手工搭建：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose
</span></span><span style="display:flex;"><span>decompose
</span></span><span style="display:flex;"><span>plus
</span></span><span style="display:flex;"><span>inverse / transpose
</span></span><span style="display:flex;"><span>subheap
</span></span><span style="display:flex;"><span>kernel
</span></span><span style="display:flex;"><span>probability container
</span></span><span style="display:flex;"><span>soft collapse
</span></span></code></pre></div><p>现在看，这些不是孤立发明。
它们可以放回已有数学框架中解释。</p>
<h2 id="先给一句人话版结论">先给一句人话版结论</h2>
<p>如果用本科能理解的语言说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 是一种把“树形结构”当成计算对象的模型。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>它不是只存一个向量。
</span></span><span style="display:flex;"><span>它还存：
</span></span><span style="display:flex;"><span>  地址
</span></span><span style="display:flex;"><span>  路径
</span></span><span style="display:flex;"><span>  父子关系
</span></span><span style="display:flex;"><span>  子树
</span></span><span style="display:flex;"><span>  如何合成
</span></span><span style="display:flex;"><span>  如何分解
</span></span></code></pre></div><p>在数学上，这类对象早就被研究过。</p>
<p>有根树 Hopf 代数研究的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树怎么组合？
</span></span><span style="display:flex;"><span>树怎么切开？
</span></span><span style="display:flex;"><span>切开以后剩下什么？
</span></span><span style="display:flex;"><span>这些操作能不能形成一个封闭的代数系统？
</span></span></code></pre></div><p>Operad 研究的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>多个输入如何组合成一个输出？
</span></span><span style="display:flex;"><span>组合过程如何再组合？
</span></span><span style="display:flex;"><span>不同组合顺序是否一致？
</span></span></code></pre></div><p>TreeHeap 正好站在这两个问题的交叉处。</p>
<h2 id="为什么是有根树-hopf-代数">为什么是有根树 Hopf 代数</h2>
<p>TreeHeap 的核心对象是有根树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        root
</span></span><span style="display:flex;"><span>       /    \
</span></span><span style="display:flex;"><span>   left    right
</span></span></code></pre></div><p>在工程里，我们把它实现成堆数组：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A[0] = root
</span></span><span style="display:flex;"><span>A[1] = left(root)
</span></span><span style="display:flex;"><span>A[2] = right(root)
</span></span><span style="display:flex;"><span>A[3] = left(A[1])
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>但是数学上，它仍然是有根树。</p>
<p>有根树上的 Hopf 代数，典型来源包括 Butcher 的数值分析树、Connes-Kreimer 的重整化树，以及后续 Munthe-Kaas-Wright Hopf algebra。</p>
<p>可以参考：</p>
<ul>
<li><a href="https://arxiv.org/abs/2306.04381">A Survey on the Munthe-Kaas-Wright Hopf Algebra, arXiv:2306.04381</a></li>
</ul>
<p>这类数学关心的不是自然语言，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树结构本身能不能做代数计算？
</span></span></code></pre></div><p>这和我们前面问的问题很像。</p>
<h2 id="treeheap-与-bckmkw-代数的对应">TreeHeap 与 BCK/MKW 代数的对应</h2>
<p>先看一个对应表。</p>
<table>
  <thead>
      <tr>
          <th>TreeHeap 里的说法</th>
          <th>有根树 Hopf 代数里的说法</th>
          <th>直觉解释</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap 对象</td>
          <td>rooted tree</td>
          <td>一个带根的树对象</td>
      </tr>
      <tr>
          <td>compose / plus</td>
          <td>product / grafting</td>
          <td>把树接到另一棵树上</td>
      </tr>
      <tr>
          <td>decompose</td>
          <td>coproduct / admissible cuts</td>
          <td>按合法方式把树切开</td>
      </tr>
      <tr>
          <td>inverse-like / inverse_transpose</td>
          <td>antipode</td>
          <td>类似“反向还原”的递归操作</td>
      </tr>
      <tr>
          <td>subheap</td>
          <td>rooted subtree / pattern</td>
          <td>从树里取局部结构</td>
      </tr>
      <tr>
          <td>非交换性</td>
          <td>non-commutative structure</td>
          <td>左右顺序、接入位置会改变结果</td>
      </tr>
      <tr>
          <td>primitive</td>
          <td>primitive element</td>
          <td>不能再从乘积里拆出的基础生成元</td>
      </tr>
  </tbody>
</table>
<p>所以，当我们在 <code>SPR-013</code> 里实验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>noncomm_margin = 0.7117
</span></span></code></pre></div><p>它不是一个很孤立的发现。</p>
<p>它对应的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树的嫁接、组合、路径顺序，本来就可以是非交换的。
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H1 plus H2
</span></span></code></pre></div><p>和：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H2 plus H1
</span></span></code></pre></div><p>可以不是同一个东西。</p>
<p>这和整数加法不同。
但它和矩阵乘法、函数复合、树嫁接更接近。</p>
<h2 id="compose-与-decompose">compose 与 decompose</h2>
<p>TreeHeap 里最核心的一对操作是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose:    children -&gt; parent
</span></span><span style="display:flex;"><span>decompose:  parent -&gt; possible children
</span></span></code></pre></div><p>用公式写：</p>
$$ \operatorname{compose}(H_1, H_2, \ldots, H_n) = H $$<p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>多个子堆合成一个父堆。
</span></span></code></pre></div><p>反过来：</p>
$$ \operatorname{decompose}(H) = \sum_c P_c(H) \otimes R_c(H) $$<p>这里的 \(c\) 可以理解成一次合法切割。</p>
<p>翻译成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一棵树不一定只有一种拆法。
</span></span><span style="display:flex;"><span>每一种合法切法，都得到一部分被切下来的树，以及剩下的树。
</span></span></code></pre></div><p>这就是 Hopf 代数里 coproduct 的味道。</p>
<p>注意，这里有一个很重要的点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>decompose 不是 compose 的唯一反函数。
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>父结构 -&gt; 子结构
</span></span></code></pre></div><p>通常不是唯一答案。</p>
<p>这正好对应我们一直说的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Probability Container
</span></span></code></pre></div><p>信息不足时，不要过早坍缩成一个答案。
应该保留多个候选分解。</p>
<h2 id="为什么还需要-operad">为什么还需要 Operad</h2>
<p>Hopf 代数解释了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树怎么合成、怎么切开、怎么反向递归。
</span></span></code></pre></div><p>但 TreeHeap 还有另一个核心：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>多个输入合成一个输出。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat + run       -&gt; [cat run]
</span></span><span style="display:flex;"><span>ball + foot     -&gt; football
</span></span><span style="display:flex;"><span>root + left + right -&gt; subheap
</span></span></code></pre></div><p>这类结构正是 operad 擅长表达的。</p>
<p>Operad 的基本思想是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个算子可以吃多个输入，吐出一个输出。
</span></span><span style="display:flex;"><span>这些算子本身还可以继续组合。
</span></span></code></pre></div><p>可以参考：</p>
<ul>
<li><a href="https://arxiv.org/abs/2606.13634">Operads for compositional reasoning in LLMs, arXiv:2606.13634</a></li>
</ul>
<p>这篇论文把 operad 用到 LLM 的多步问题分解上。
它把复杂问题拆成子问题，再把子答案组合回来。</p>
<p>它的核心观点可以和 TreeHeap 对齐：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>问题分解树上的局部回答，必须和整体回答保持一致。
</span></span></code></pre></div><p>这和我们的 TreeHeap consistency 很像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>soft TreeHeap 经过局部坍缩之后，
</span></span><span style="display:flex;"><span>应该能回到合法的 hard TreeHeap。
</span></span></code></pre></div><h2 id="treeheap-operad-怎么定义">TreeHeap Operad 怎么定义</h2>
<p>我们可以暂时这样定义一个 TreeHeap operad：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>T = TreeHeap operations
</span></span></code></pre></div><p>其中每个 operation 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>多棵子树 -&gt; 一棵父树
</span></span></code></pre></div><p>数学上：</p>
$$ \omega : (H_1, H_2, \ldots, H_n) \to H $$<p>其中 \(\omega\) 可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus
</span></span><span style="display:flex;"><span>compose
</span></span><span style="display:flex;"><span>fold
</span></span><span style="display:flex;"><span>merge
</span></span><span style="display:flex;"><span>slot fill
</span></span><span style="display:flex;"><span>kernel-guided write
</span></span></code></pre></div><p>如果一个模型能解释这些操作，我们就可以说它是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>an algebra over the TreeHeap operad
</span></span></code></pre></div><p>翻译成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个模型知道 TreeHeap 的算子该怎么作用到具体数据上。
</span></span></code></pre></div><p>这给了我们一个更正式的说法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>可学习的 TreeHeap 模型
</span></span><span style="display:flex;"><span>不是“一个 MLP 外面套树壳”。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>它应该是 TreeHeap operad 上的一个 algebra。
</span></span></code></pre></div><h2 id="kernel-在这里是什么">Kernel 在这里是什么</h2>
<p>上一轮我们把 kernel 定义成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 上可重复滑动使用的局部推理算子。
</span></span></code></pre></div><p>现在可以把它放到 operad 语境里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 是 TreeHeap operad 上的局部 algebra action。
</span></span></code></pre></div><p>不用被这个说法吓到。</p>
<p>它的意思很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 不是凭空看一个向量。
</span></span><span style="display:flex;"><span>它是在 TreeHeap 的局部子结构上执行一个算子。
</span></span></code></pre></div><p>例如一跳 kernel 看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S_i = root(i) -&gt; [left(i), right(i)]
</span></span></code></pre></div><p>也就是：</p>
$$ S_i = \big(A_i, A_{L(i)}, A_{R(i)}\big) $$<p>然后：</p>
$$ K_\theta(q, S_i, W) \to y_i $$<p>其中：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>\(q\)</td>
          <td>query，当前要查找或写入的目标</td>
      </tr>
      <tr>
          <td>\(S_i\)</td>
          <td>第 \(i\) 个局部子堆</td>
      </tr>
      <tr>
          <td>\(W\)</td>
          <td>world model，也就是背景参考系</td>
      </tr>
      <tr>
          <td>\(\theta\)</td>
          <td>kernel 的可学习参数</td>
      </tr>
      <tr>
          <td>\(y_i\)</td>
          <td>匹配、路由、写入或合并输出</td>
      </tr>
  </tbody>
</table>
<p>输出不一定是硬答案。
更合理的是概率容器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>{stop: 0.1, left: 0.8, right: 0.1}
</span></span><span style="display:flex;"><span>{match: 0.7, no_match: 0.3}
</span></span><span style="display:flex;"><span>{write_here: 0.6, write_elsewhere: 0.4}
</span></span></code></pre></div><p>这就是 TreeHeap 和 Probability Container 的接口。</p>
<h2 id="treeheap-操作本质上是卷积-kernel-的组合">TreeHeap 操作本质上是卷积 kernel 的组合</h2>
<p>这里需要补一层更重要的理解。</p>
<p>前面说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 是 TreeHeap 上可重复滑动使用的局部推理算子。
</span></span></code></pre></div><p>但这句话还不够强。</p>
<p>更准确地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的多数操作，都应该被理解成卷积 kernel 的组合。
</span></span></code></pre></div><p>也就是说，TreeHeap 不是先有一个普通数组，然后偶尔拿 kernel 扫一下。</p>
<p>它更像是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个高维结构空间
</span></span><span style="display:flex;"><span>        +
</span></span><span style="display:flex;"><span>一组可组合的局部卷积算子
</span></span></code></pre></div><h3 id="为什么说-treeheap-至少是-3d-结构">为什么说 TreeHeap 至少是 3D 结构</h3>
<p>普通一维序列只有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>index -&gt; value
</span></span></code></pre></div><p>二维矩阵有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>(row, col) -&gt; value
</span></span></code></pre></div><p>TreeHeap 至少同时有三类坐标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. value:    节点里存的向量或符号
</span></span><span style="display:flex;"><span>2. address:  节点的路径，比如 LLR、RLL
</span></span><span style="display:flex;"><span>3. topology: 父子关系、子堆、祖先、兄弟节点
</span></span></code></pre></div><p>所以一个 TreeHeap 节点不只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A[i]
</span></span></code></pre></div><p>而更像：</p>
$$ H_i = \big(v_i, a_i, \tau_i\big) $$<p>其中：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>\(v_i\)</td>
          <td>value，节点向量</td>
      </tr>
      <tr>
          <td>\(a_i\)</td>
          <td>address/path，节点地址</td>
      </tr>
      <tr>
          <td>\(\tau_i\)</td>
          <td>topology，局部拓扑关系</td>
      </tr>
  </tbody>
</table>
<p>这就是我现在说的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 至少是 3D 的结构对象。
</span></span></code></pre></div><p>它不是简单的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一维数组 + 一点树形解释
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>值空间 × 地址空间 × 拓扑空间
</span></span></code></pre></div><h3 id="卷积-kernel-定义可能的局部操作">卷积 kernel 定义可能的局部操作</h3>
<p>在 CNN 里，不同卷积核可以检测不同模式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>横线
</span></span><span style="display:flex;"><span>竖线
</span></span><span style="display:flex;"><span>边缘
</span></span><span style="display:flex;"><span>角点
</span></span><span style="display:flex;"><span>纹理
</span></span></code></pre></div><p>在 TreeHeap 里，不同 kernel 也可以定义不同局部操作：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>查找 kernel:     这个子堆像不像 query？
</span></span><span style="display:flex;"><span>路由 kernel:     下一步 stop / left / right？
</span></span><span style="display:flex;"><span>写入 kernel:     信息应该写到哪个地址？
</span></span><span style="display:flex;"><span>合并 kernel:     子堆能不能 fold 成父堆？
</span></span><span style="display:flex;"><span>分解 kernel:     父堆有哪些可能切法？
</span></span><span style="display:flex;"><span>对齐 kernel:     两个子堆是不是同构或近似同构？
</span></span><span style="display:flex;"><span>翻转 kernel:     当前结构能不能镜像成另一侧结构？
</span></span></code></pre></div><p>因此，TreeHeap 的 <code>plus</code>、<code>compose</code>、<code>decompose</code>、<code>fold</code>、<code>match_subheap</code> 不应该被看成互不相关的函数。</p>
<p>更统一的看法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它们都是不同 kernel 或 kernel composition 的结果。
</span></span></code></pre></div><p>写成抽象形式：</p>
$$ \operatorname{Op}(H) = K_m \circ K_{m-1} \circ \cdots \circ K_1(H) $$<p>其中每个 \(K_j\) 都是一个局部 TreeHeap kernel。</p>
<h3 id="共轭-kernel-与镜像翻转">共轭 kernel 与镜像翻转</h3>
<p>Houming818 提到的“共轭操作”很重要。</p>
<p>如果 TreeHeap 的地址空间里有左右路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L, R
</span></span></code></pre></div><p>那么镜像变换可以定义成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L &lt;-&gt; R
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LLR -&gt; RRL
</span></span></code></pre></div><p>把这个路径镜像记为：</p>
$$ \sigma(a) $$<p>对整棵 TreeHeap 的镜像可以写成：</p>
$$ \sigma(H)_i = H_{\sigma(i)} $$<p>更直观地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>原树：
</span></span><span style="display:flex;"><span>        root
</span></span><span style="display:flex;"><span>       /    \
</span></span><span style="display:flex;"><span>      A      B
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>镜像：
</span></span><span style="display:flex;"><span>        root
</span></span><span style="display:flex;"><span>       /    \
</span></span><span style="display:flex;"><span>      B      A
</span></span></code></pre></div><p>那么一个 kernel \(K\) 的共轭 kernel 可以定义为：</p>
$$ K^\sigma = \sigma^{-1} \circ K \circ \sigma $$<p>这句话翻译成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先把 TreeHeap 镜像过去；
</span></span><span style="display:flex;"><span>在镜像空间里执行同一个 kernel；
</span></span><span style="display:flex;"><span>再镜像回来。
</span></span></code></pre></div><p>如果这个等式成立，说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 可以在左右翻转后的结构上复用。
</span></span></code></pre></div><p>这和 CNN 里对称、旋转、平移相关的卷积思想很接近。</p>
<p>只不过 CNN 通常处理二维图像变换；
TreeHeap 处理的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径变换
</span></span><span style="display:flex;"><span>子堆变换
</span></span><span style="display:flex;"><span>拓扑变换
</span></span></code></pre></div><h3 id="这对-treeheap-的意义">这对 TreeHeap 的意义</h3>
<p>这件事给了我们一个更清楚的 claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的优势不只是“它是树”。
</span></span><span style="display:flex;"><span>TreeHeap 的优势应该来自：
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>1. 高维结构坐标：value × address × topology
</span></span><span style="display:flex;"><span>2. kernel 在这些坐标上的局部卷积
</span></span><span style="display:flex;"><span>3. kernel composition 形成复杂推理
</span></span><span style="display:flex;"><span>4. 共轭 kernel 允许镜像、翻转、对偶结构复用
</span></span></code></pre></div><p>如果这个方向成立，TreeHeap 的实验就不应该只测：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能不能分类？
</span></span></code></pre></div><p>而应该测：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一个 kernel 能不能在不同路径上复用？
</span></span><span style="display:flex;"><span>同一个 kernel 能不能在镜像结构上复用？
</span></span><span style="display:flex;"><span>kernel composition 能不能形成多跳推理？
</span></span><span style="display:flex;"><span>共轭 kernel 是否能减少训练样本？
</span></span></code></pre></div><p>这会成为后续 C05/C06 实验的重要设计点。</p>
<h2 id="query-从哪里来">query 从哪里来</h2>
<p>前面公式里有 \(q\)，它不能凭空出现。</p>
<p>在 TreeHeap 管线里，\(q\) 可以来自三类地方：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>input token -&gt; encoder -&gt; q
</span></span><span style="display:flex;"><span>当前上下文 -&gt; context encoder -&gt; q
</span></span><span style="display:flex;"><span>上一层 kernel 输出 -&gt; next query
</span></span></code></pre></div><p>更完整地写：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token / phrase / task
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>encoder
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>q
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>context window / memory / world model
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>context encoder
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>W
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>q + W + local subheap
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>TreeHeap kernel
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>route / write / merge / collapse
</span></span></code></pre></div><p>所以 \(q\) 不是一个固定词向量。
它是当前推理任务发出的“查询意图”。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>q = 找 ball + foot 的组合
</span></span></code></pre></div><p>kernel 扫到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S_i = ball -&gt; [foot, hand]
</span></span></code></pre></div><p>如果世界模型知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ball + foot -&gt; football
</span></span><span style="display:flex;"><span>ball + hand -&gt; basketball
</span></span></code></pre></div><p>那么 kernel 应该能给出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football 方向的高匹配
</span></span></code></pre></div><h2 id="kernel-的滑动与感受野">kernel 的滑动与感受野</h2>
<p>CNN 的卷积核会在图像上滑动。
TreeHeap kernel 也可以在树上滑动。</p>
<p>这里的滑动不是二维平移，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对所有内部节点 i，取它的局部子堆 S_i，然后执行 K(q, S_i, W)。
</span></span></code></pre></div><p>可以写成：</p>
$$ \operatorname{ScoreMap}(H, q) = \{K_\theta(q, S_i, W) \mid i \in \operatorname{Internal}(H)\} $$<p>遍历顺序可以是 BFS、DFS，也可以并行。
数学上重点不是遍历顺序，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一个 kernel 在不同地址复用。
</span></span></code></pre></div><p>这就是 TreeHeap 的结构归纳偏置。</p>
<h3 id="一跳二跳k-跳">一跳、二跳、k 跳</h3>
<p>如果一跳 kernel 看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root + left + right
</span></span></code></pre></div><p>它的感受野是 3 个节点。</p>
<p>二跳 kernel 看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>├── left subtree
</span></span><span style="display:flex;"><span>└── right subtree
</span></span></code></pre></div><p>如果每个子树也看一跳，总共是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 + 2 + 4 = 7 个节点
</span></span></code></pre></div><p>一般地，二叉树深度 \(k\) 的局部感受野大小是：</p>
$$ 2^{k+1} - 1 $$<p>这解释了为什么 <code>SPR-021</code> 的实验只是一个起点。
它只测试了一跳子堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; left, right
</span></span></code></pre></div><p>还没有测试多层 kernel 堆叠。</p>
<h2 id="kernel-的组合就是-operadic-composition">kernel 的组合就是 operadic composition</h2>
<p>CNN 可以多层堆叠：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>conv1 -&gt; conv2 -&gt; conv3
</span></span></code></pre></div><p>TreeHeap kernel 也可以堆叠：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K1 看局部 3 节点
</span></span><span style="display:flex;"><span>K2 看 K1 的输出和父层子堆
</span></span><span style="display:flex;"><span>K3 再看更高层
</span></span></code></pre></div><p>写成公式：</p>
$$ K_2 \circ K_1(q, S_i) = K_2\big(K_1(q, S_i), S_{\operatorname{parent}(i)}\big) $$<p>这就是 operad 语言里的组合：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个局部操作的输出，
</span></span><span style="display:flex;"><span>可以成为另一个局部操作的输入。
</span></span></code></pre></div><p>所以 TreeHeap kernel 不是一个孤立分类器。
它应该是一组可组合的局部算子。</p>
<h2 id="为什么线性-kernel-不够">为什么线性 kernel 不够</h2>
<p>GLM 的多 pattern 消融指出了一个关键问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>线性 kernel 不会真正比较 query 和 patch。
</span></span></code></pre></div><p>如果 kernel 是：</p>
$$ K(q, S) = w^\top [q, S] + b $$<p>它只能分别给 \(q\) 和 \(S\) 加权求和。</p>
<p>它天然不会形成：</p>
$$ q - S $$<p>更不会自然形成：</p>
$$ \lVert q - S\rVert^2 $$<p>除非我们手工把这些差分特征喂进去。</p>
<p>所以，如果任务要求：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>判断这个子堆是不是和 query 匹配
</span></span></code></pre></div><p>那么纯线性 kernel 通常不够。</p>
<p>更合理的是：</p>
$$ K_\theta(q, S, W) = \operatorname{MLP}_\theta([q, \phi(S), W]) $$<p>或者显式给出交互项：</p>
$$ K(q, S) = -\lVert q - \phi(S)\rVert^2 $$<p>这里 \(\phi(S)\) 是子堆编码。</p>
<p>这不是实现小细节。
这是数学约束：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>结构比较需要交互项。
</span></span><span style="display:flex;"><span>没有交互项，kernel 很容易退化成地址分类器。
</span></span></code></pre></div><h2 id="attention-对比">Attention 对比</h2>
<p>Transformer attention 也可以看成一种 kernel：</p>
$$ \operatorname{score}(i,j) = Q_i K_j^\top $$<p>它的特点是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flat
</span></span><span style="display:flex;"><span>all-to-all
</span></span><span style="display:flex;"><span>通过点积比较 token
</span></span></code></pre></div><p>TreeHeap kernel 的特点是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>structural
</span></span><span style="display:flex;"><span>local subheap
</span></span><span style="display:flex;"><span>path-aware
</span></span><span style="display:flex;"><span>可递归堆叠
</span></span><span style="display:flex;"><span>可以输出概率容器
</span></span></code></pre></div><p>对比一下：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th>Transformer Attention</th>
          <th>TreeHeap Kernel</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>基本对象</td>
          <td>token 序列</td>
          <td>有根树 / 堆</td>
      </tr>
      <tr>
          <td>比较单位</td>
          <td>token-token</td>
          <td>query-subheap</td>
      </tr>
      <tr>
          <td>连接方式</td>
          <td>全连接</td>
          <td>局部结构滑动</td>
      </tr>
      <tr>
          <td>地址</td>
          <td>位置编码</td>
          <td>路径 / 子堆地址</td>
      </tr>
      <tr>
          <td>归纳偏置</td>
          <td>序列与全局相关性</td>
          <td>子结构迁移与递归组合</td>
      </tr>
      <tr>
          <td>输出</td>
          <td>attention weights</td>
          <td>route/write/merge/collapse 容器</td>
      </tr>
  </tbody>
</table>
<p>所以 TreeHeap 不是要说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>attention 错了。
</span></span></code></pre></div><p>更准确的说法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 想给 attention 缺少的树形地址、子结构复用、延迟坍缩提供结构约束。
</span></span></code></pre></div><h2 id="与传统-tree-kernel-的关系">与传统 Tree Kernel 的关系</h2>
<p>NLP 里早就有 tree kernel。</p>
<p>经典方向包括 Collins-Duffy tree kernel、Moschitti 的 syntactic tree kernel。
它们常用于 SVM 或句法树分类。</p>
<p>它们大致做的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>两棵句法树之间有多少公共子树？
</span></span><span style="display:flex;"><span>公共子树越多，相似度越高。
</span></span></code></pre></div><p>TreeHeap kernel 和它们有亲缘关系，但不是同一个东西。</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th>传统 tree kernel</th>
          <th>TreeHeap kernel</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>主要用途</td>
          <td>树相似度 / 分类</td>
          <td>路由、写入、合并、坍缩</td>
      </tr>
      <tr>
          <td>是否可学习</td>
          <td>多数是固定相似度</td>
          <td>可以固定，也可以可学习</td>
      </tr>
      <tr>
          <td>数据结构</td>
          <td>句法树</td>
          <td>可寻址 TreeHeap</td>
      </tr>
      <tr>
          <td>输出</td>
          <td>similarity score</td>
          <td>probability container / action</td>
      </tr>
      <tr>
          <td>是否改写结构</td>
          <td>通常不写入</td>
          <td>可以指导 soft plus 写入</td>
      </tr>
  </tbody>
</table>
<p>所以我们不是第一个想到“树上 kernel”的项目。
真正的新问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能不能把 tree kernel 从固定相似度函数，
</span></span><span style="display:flex;"><span>推进成可微、可写入、可组合的 TreeHeap 局部推理算子？
</span></span></code></pre></div><h2 id="morphosyntax-与语言结构">Morphosyntax 与语言结构</h2>
<p>TreeHeap 最终要回到语言任务。
这里也已经有相关数学方向。</p>
<p>例如：</p>
<ul>
<li><a href="https://arxiv.org/abs/2507.00244">The Algebraic Structure of Morphosyntax, arXiv:2507.00244</a></li>
</ul>
<p>这类工作把词法、句法的树结构放到 operad / algebra 的框架里讨论。</p>
<p>对我们来说，它至少说明一件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用 operad 描述语言结构组合，不是离谱方向。
</span></span></code></pre></div><p>但是我们必须谨慎：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这不等于 TreeHeap 已经能做 WMT。
</span></span></code></pre></div><p>它只是说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语言结构上层可以站在代数结构底座上。
</span></span></code></pre></div><p>中间还缺：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实语料 encoder
</span></span><span style="display:flex;"><span>真实句法 micro benchmark
</span></span><span style="display:flex;"><span>S1b baseline battle
</span></span><span style="display:flex;"><span>S2 graph assembly
</span></span><span style="display:flex;"><span>S3 generation
</span></span></code></pre></div><h2 id="decomposition-space-与概率容器">Decomposition Space 与概率容器</h2>
<p>还有一个相关方向是 decomposition space：</p>
<ul>
<li><a href="https://arxiv.org/abs/1612.09225">Decomposition spaces in Combinatorics, arXiv:1612.09225</a></li>
</ul>
<p>它关心的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>组合与分解如何形成一致的数学结构。
</span></span></code></pre></div><p>这对 TreeHeap 的启发是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 decompose 有多个合法结果，
</span></span><span style="display:flex;"><span>那么模型不应该立刻 argmax。
</span></span></code></pre></div><p>它应该保留：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Parent candidates
</span></span><span style="display:flex;"><span>Route candidates
</span></span><span style="display:flex;"><span>Graph candidates
</span></span><span style="display:flex;"><span>Decomposition candidates
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Probability Container
</span></span></code></pre></div><p>这能把 TreeHeap 的设计从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>每一步强行选一个答案
</span></span></code></pre></div><p>推进到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>信息不足时保留多个合法分解，
</span></span><span style="display:flex;"><span>等更强上下文再坍缩。
</span></span></code></pre></div><p>这和我们最早的 L0/L1/L2 叠加态想法是一致的。</p>
<h2 id="这篇文章修正了什么">这篇文章修正了什么</h2>
<p>它修正了一个重要叙述：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不应该被说成“我们发明了一套全新的数学”。
</span></span></code></pre></div><p>更专业、更可靠的说法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 是把 rooted-tree Hopf algebra、operad、tree kernel、
</span></span><span style="display:flex;"><span>probabilistic soft lifting 这些思想，工程化到可学习结构内存中的尝试。
</span></span></code></pre></div><p>这让项目更稳。</p>
<p>因为我们不需要自己证明所有基础性质。
很多东西已有成熟数学支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树可以组合。
</span></span><span style="display:flex;"><span>树可以切割。
</span></span><span style="display:flex;"><span>多输入单输出算子可以组合。
</span></span><span style="display:flex;"><span>局部树模式可以匹配。
</span></span><span style="display:flex;"><span>结构分解可以不是唯一的。
</span></span></code></pre></div><p>我们真正要证明的是工程问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这些数学对象能不能变成有效的机器学习结构？
</span></span><span style="display:flex;"><span>能不能比 flat MLP / 普通 Transformer 在某些任务上更省样本、更稳外推、更低计算？
</span></span></code></pre></div><h2 id="当前-claim-应该怎么更新">当前 Claim 应该怎么更新</h2>
<p>我建议把核心 claim 重新表述成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Claim:
</span></span><span style="display:flex;"><span>TreeHeap 的数学底座可以由 rooted-tree Hopf algebra 与 operad 承接。
</span></span><span style="display:flex;"><span>因此 compose/decompose/plus/subheap/kernel 不需要作为孤立发明来理解。
</span></span><span style="display:flex;"><span>真正需要实验验证的是：
</span></span><span style="display:flex;"><span>可学习 kernel 是否能利用这个结构底座，获得 flat 模型没有的归纳偏置。
</span></span></code></pre></div><p>对应 predict：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Predict:
</span></span><span style="display:flex;"><span>在需要地址、子结构迁移、前缀复用、延迟坍缩的问题上，
</span></span><span style="display:flex;"><span>TreeHeap kernel 应该比 flat MLP 更少样本、更稳 OOD 外推。
</span></span></code></pre></div><p>对应 falsification：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果足够宽的 flat MLP / 普通 Transformer，
</span></span><span style="display:flex;"><span>在相同参数量、相同训练数据下，
</span></span><span style="display:flex;"><span>稳定匹配 TreeHeap kernel 的 OOD 地址外推、子结构迁移和延迟坍缩能力，
</span></span><span style="display:flex;"><span>那么 TreeHeap kernel 没有显示出额外归纳偏置。
</span></span></code></pre></div><p>这很重要。</p>
<p>TreeHeap 不能靠“看起来更优美”成立。
它必须靠：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>更明确的数学对象
</span></span><span style="display:flex;"><span>更清楚的可证伪预测
</span></span><span style="display:flex;"><span>更干净的对照实验
</span></span></code></pre></div><p>成立。</p>
<h2 id="下一步怎么接实验">下一步怎么接实验</h2>
<p>这篇文章之后，我不建议继续只做纯文字推理。</p>
<p>下一步应该接两个实验。</p>
<h3 id="实验-1非线性-kernel-是否能学会-query-subheap-比较">实验 1：非线性 kernel 是否能学会 query-subheap 比较</h3>
<p>目标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不用手工 diff 特征。
</span></span><span style="display:flex;"><span>只给 raw query 和 raw subheap。
</span></span><span style="display:flex;"><span>看 MLP kernel 能不能学会比较。
</span></span></code></pre></div><p>对照：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>linear_raw
</span></span><span style="display:flex;"><span>mlp_raw
</span></span><span style="display:flex;"><span>linear_with_diff
</span></span><span style="display:flex;"><span>treeheap_kernel
</span></span></code></pre></div><p>如果结果是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>linear_raw 失败
</span></span><span style="display:flex;"><span>mlp_raw 成功
</span></span></code></pre></div><p>说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 的非线性交互是必要的。
</span></span></code></pre></div><h3 id="实验-2真实小句法树-micro-benchmark">实验 2：真实小句法树 micro benchmark</h3>
<p>目标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不要直接跳 WMT BLEU。
</span></span><span style="display:flex;"><span>先拿 100 到 1000 句真实句法树，
</span></span><span style="display:flex;"><span>测试 TreeHeap kernel 能否迁移局部依存结构。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>head -&gt; subject/object/modifier
</span></span></code></pre></div><p>不是先证明翻译质量，而是先证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 在真实语言树上确实能读到结构信号。
</span></span></code></pre></div><p>这才是从 M0 到 S1/S2 的桥。</p>
<h2 id="最终结论">最终结论</h2>
<p>这篇的结论很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的数学底座并不孤单。
</span></span><span style="display:flex;"><span>它可以站在 rooted-tree Hopf algebra、operad、decomposition space 和 tree kernel 的已有传统上。
</span></span></code></pre></div><p>但这不是胜利宣言。</p>
<p>它只是把问题从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们是不是在乱造数学？
</span></span></code></pre></div><p>推进到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们能不能把这些成熟数学对象，训练成有效机器学习系统？
</span></span></code></pre></div><p>这一步反而更严格。</p>
<p>因为以后我们不能只说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 很像树，很像代数。
</span></span></code></pre></div><p>我们必须证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 在具体任务上，利用了树的地址、路径、子结构、组合和分解。
</span></span><span style="display:flex;"><span>并且这种利用带来了可测量的收益。
</span></span></code></pre></div><p>这就是下一阶段实验的方向。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-023] 从卷积核重新定义 TreeHeap 操作</title>
      <link>https://www.grepcode.cn/spr/023-treeheap-kernel-convolution-ops.html</link>
      <pubDate>Wed, 24 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/023-treeheap-kernel-convolution-ops.html</guid>
      <description>把 plus、search、conjugate 统一为 TreeHeap kernel 在树形内存态上的卷积状态变换，并用 toy proof 验证 score map、write field 与镜像共轭。</description>
      <content:encoded><![CDATA[<h1 id="从卷积核重新定义-treeheap-操作">从卷积核重新定义 TreeHeap 操作</h1>
<p>上一篇 <code>SPR-022</code> 把 TreeHeap 放回了已有数学背景：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rooted-tree Hopf algebra
</span></span><span style="display:flex;"><span>operad
</span></span><span style="display:flex;"><span>decomposition space
</span></span><span style="display:flex;"><span>tree kernel
</span></span></code></pre></div><p>但 Houming818 指出了一个更核心的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的操作不应该先被理解成一堆手写函数。
</span></span><span style="display:flex;"><span>TreeHeap 的核心操作应该是 kernel 在树上的卷积。
</span></span></code></pre></div><p>这句话把方向拉正了。</p>
<p>以前容易说成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 有 plus、compose、decompose、conjugate。
</span></span><span style="display:flex;"><span>另外，我们再给它加一个 kernel。
</span></span></code></pre></div><p>现在应该反过来：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的 plus、search、compose、decompose、fold、conjugate，
</span></span><span style="display:flex;"><span>都应该从 kernel 如何卷积整棵树并更新内存态来定义。
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不是“树结构 + 一堆函数”。
</span></span><span style="display:flex;"><span>TreeHeap 是“树形高维状态场 + 一组卷积核”。
</span></span></code></pre></div><h2 id="先看-cnn-的类比">先看 CNN 的类比</h2>
<p>在 CNN 里，一张图像是一个状态场：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>image[row, col, channel]
</span></span></code></pre></div><p>卷积核扫过图像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>3x3 patch
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>kernel
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>feature score
</span></span></code></pre></div><p>整张图扫完以后得到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>feature map
</span></span></code></pre></div><p>例如一个边缘检测 kernel，不是在一个像素上做判断，而是在整张图上滑动，生成一张“哪里像边缘”的图。</p>
<p>TreeHeap 应该类似。</p>
<p>TreeHeap 的状态场不是二维图像，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>value × address × topology
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>节点值
</span></span><span style="display:flex;"><span>路径地址
</span></span><span style="display:flex;"><span>父子拓扑
</span></span></code></pre></div><p>所以 TreeHeap kernel 不是看一个孤立节点。
它看一个局部子堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>      root
</span></span><span style="display:flex;"><span>     /    \
</span></span><span style="display:flex;"><span>  left    right
</span></span></code></pre></div><p>然后在整棵树上滑动。</p>
<h2 id="treeheap-kernel-convolution-的定义">TreeHeap kernel convolution 的定义</h2>
<p>设当前 TreeHeap 内存态是：</p>
$$ H_t $$<p>以路径 \(a\) 为中心的局部子堆是：</p>
$$ S_a(H_t) $$<p>一个 kernel 是：</p>
$$ K_\theta(q, S_a, W) $$<p>其中：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>\(q\)</td>
          <td>query，要找或要写的目标</td>
      </tr>
      <tr>
          <td>\(S_a\)</td>
          <td>地址 \(a\) 处的局部子堆</td>
      </tr>
      <tr>
          <td>\(W\)</td>
          <td>world model / 背景场</td>
      </tr>
      <tr>
          <td>\(\theta\)</td>
          <td>kernel 参数，可以固定，也可以学习</td>
      </tr>
  </tbody>
</table>
<p>卷积整棵树就是：</p>
$$ \operatorname{Conv}_K(H_t, q) = \{K_\theta(q, S_a(H_t), W)\}_{a \in A(H_t)} $$<p>翻译成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对树上每个候选地址 a：
</span></span><span style="display:flex;"><span>  取局部子堆 S_a
</span></span><span style="display:flex;"><span>  用同一个 kernel 计算响应
</span></span><span style="display:flex;"><span>最终得到一张覆盖整棵树的响应图
</span></span></code></pre></div><p>这张响应图可以叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score map
</span></span><span style="display:flex;"><span>update map
</span></span><span style="display:flex;"><span>route map
</span></span><span style="display:flex;"><span>probability field
</span></span></code></pre></div><p>不同名字对应不同用途，但本质都是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 扫树以后得到的全局状态场。
</span></span></code></pre></div><h2 id="plus-不再是写到某个地址">plus 不再是“写到某个地址”</h2>
<p>以前我们容易把 plus 理解成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H plus x = 把 x 写到地址 a
</span></span></code></pre></div><p>但这太像普通数组写入了。</p>
<p>新的定义应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>plus kernel 扫描整棵 TreeHeap。
</span></span><span style="display:flex;"><span>每个地址都产生一个 write score。
</span></span><span style="display:flex;"><span>这些 score 形成一个写入概率场。
</span></span><span style="display:flex;"><span>然后 H 根据这个概率场更新。
</span></span></code></pre></div><p>数学上：</p>
$$ s_a = K_{\text{plus}}(x, S_a(H_t), W) $$$$ p_a = \operatorname{softmax}(s_a) $$$$ H_{t+1} = H_t + \sum_a p_a \cdot \Delta_a(x, H_t) $$<p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>s_a = 地址 a 的写入响应
</span></span><span style="display:flex;"><span>p_a = 地址 a 的写入概率
</span></span><span style="display:flex;"><span>Δ_a = 如果写到地址 a，会产生的局部状态更新
</span></span></code></pre></div><p>所以 plus 的本质不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>直接指定地址。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 卷积整棵树，形成 write field，再更新内存态。
</span></span></code></pre></div><h2 id="search-也是同一个东西">search 也是同一个东西</h2>
<p>search 更直观。</p>
<p>定义：</p>
$$ s_a = K_{\text{search}}(q, S_a(H_t), W) $$<p>如果只要硬搜索结果：</p>
$$ a^* = \arg\max_a s_a $$<p>如果要概率容器：</p>
$$ p_a = \operatorname{softmax}(s_a) $$<p>所以 search 不是特殊函数。</p>
<p>它就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 卷积树，输出 score map。
</span></span></code></pre></div><p>plus 和 search 的差别只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>search 把 score map 用来读。
</span></span><span style="display:flex;"><span>plus 把 score map 用来写。
</span></span></code></pre></div><h2 id="conjugate-不是额外-if-else">conjugate 不是额外 if-else</h2>
<p>共轭操作也应该从 kernel 角度定义。</p>
<p>假设镜像变换是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L &lt;-&gt; R
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LRL -&gt; RLR
</span></span></code></pre></div><p>记为：</p>
$$ \sigma(a) $$<p>那么 kernel 的共轭是：</p>
$$ K^\sigma = \sigma^{-1} \circ K \circ \sigma $$<p>这句话的意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先把 TreeHeap 镜像过去；
</span></span><span style="display:flex;"><span>在镜像空间里用 kernel 做卷积；
</span></span><span style="display:flex;"><span>再把响应映射回来。
</span></span></code></pre></div><p>所以 conjugate 不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果左边怎样，右边就怎样。
</span></span></code></pre></div><p>它是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>卷积核本身做了一次对称翻转。
</span></span></code></pre></div><p>这就像图像里一个检测左斜边缘的 kernel，可以通过翻转变成检测右斜边缘的 kernel。</p>
<p>TreeHeap 里对应的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>左路径结构
</span></span><span style="display:flex;"><span>↓ 镜像
</span></span><span style="display:flex;"><span>右路径结构
</span></span></code></pre></div><h2 id="这次-ara-的新-claim">这次 ARA 的新 claim</h2>
<p>这次新增：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0-SOFT-C08
</span></span></code></pre></div><p>Claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap primitive operations can be defined as kernel convolutions over
</span></span><span style="display:flex;"><span>the whole tree state:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>search emits a score map,
</span></span><span style="display:flex;"><span>plus/write uses that map as an update field,
</span></span><span style="display:flex;"><span>and conjugate is a symmetry transform of the kernel.
</span></span></code></pre></div><p>中文解释：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的基本操作可以统一成：
</span></span><span style="display:flex;"><span>kernel 在整棵树上卷积，然后产生状态图。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>search 用这张图读；
</span></span><span style="display:flex;"><span>plus 用这张图写；
</span></span><span style="display:flex;"><span>conjugate 是对 kernel 做镜像变换。
</span></span></code></pre></div><p>这不是说语言任务已经解决。
它只是先把操作语义统一起来。</p>
<h2 id="toy-proof-怎么设计">Toy proof 怎么设计</h2>
<p>我们做了一个小实验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel_convolution_ops_probe.py
</span></span></code></pre></div><p>构造一棵 full binary TreeHeap。</p>
<p>在目标地址放入一个不对称子堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>target_path = LRL
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>query = [root, left, right]
</span></span><span style="display:flex;"><span>      = [2.0, 5.0, -3.0]
</span></span></code></pre></div><p>局部子堆是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>patch(a) = [H[a], H[aL], H[aR]]
</span></span></code></pre></div><p>kernel 定义为：</p>
$$ score(a) = -\lVert patch(a) - query\rVert^2 $$<p>这个 kernel 很朴素。
它不是学习出来的。
它只是为了测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一个卷积响应图，能不能解释 search / plus / conjugate。
</span></span></code></pre></div><h2 id="实验-1search-score-map">实验 1：search score map</h2>
<p>kernel 扫描所有候选子堆。</p>
<p>输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score(path)
</span></span></code></pre></div><p>然后取：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>argmax score(path)
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>search hit@1</td>
          <td style="text-align: right">True</td>
      </tr>
      <tr>
          <td>hit path</td>
          <td style="text-align: right">LRL</td>
      </tr>
      <tr>
          <td>target probability</td>
          <td style="text-align: right">1.0</td>
      </tr>
  </tbody>
</table>
<p>说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>search 可以被定义成 kernel 卷积后的 score map。
</span></span></code></pre></div><h2 id="实验-2plus-write-field">实验 2：plus write field</h2>
<p>同一张 score map 不只可以拿来读。</p>
<p>也可以变成写入概率：</p>
$$ p(a)=\operatorname{softmax}(score(a)) $$<p>然后更新 TreeHeap：</p>
$$ H_{t+1} = H_t + \sum_a p(a)\cdot write(a) $$<p>结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>plus write hit@1</td>
          <td style="text-align: right">True</td>
      </tr>
      <tr>
          <td>write path</td>
          <td style="text-align: right">LRL</td>
      </tr>
      <tr>
          <td>target update error</td>
          <td style="text-align: right">0.000000</td>
      </tr>
      <tr>
          <td>max disjoint non-target update norm</td>
          <td style="text-align: right">0.000000</td>
      </tr>
  </tbody>
</table>
<p>这里有一个细节。</p>
<p><code>max_nontarget_update_norm = 0.75</code>，看起来像有非目标节点被影响。</p>
<p>但原因是 TreeHeap 的子堆会重叠。
例如一个父 patch 会包含它的子节点。
目标子堆被写入以后，和它共享节点的其它 patch 也会观察到变化。</p>
<p>所以更干净的定位指标是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>max_disjoint_nontarget_update_norm = 0.0
</span></span></code></pre></div><p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不共享节点的非目标子堆没有被写乱。
</span></span></code></pre></div><p>这说明 plus/write 可以被解释成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 卷积产生 write field，然后写入 TreeHeap 内存态。
</span></span></code></pre></div><h2 id="实验-3conjugate-mirror">实验 3：conjugate mirror</h2>
<p>目标路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LRL
</span></span></code></pre></div><p>镜像以后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>RLR
</span></span></code></pre></div><p>原始 query 是不对称的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[2.0, 5.0, -3.0]
</span></span></code></pre></div><p>如果直接拿原 kernel 去扫镜像树，会失败：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>raw mirror hit@1</td>
          <td style="text-align: right">False</td>
      </tr>
      <tr>
          <td>raw mirror hit path</td>
          <td style="text-align: right">RLLR</td>
      </tr>
  </tbody>
</table>
<p>但如果使用共轭 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K^sigma = sigma^-1 K sigma
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>conjugate mirror hit@1</td>
          <td style="text-align: right">True</td>
      </tr>
      <tr>
          <td>conjugate hit path</td>
          <td style="text-align: right">RLR</td>
      </tr>
      <tr>
          <td>score-map equiv max error</td>
          <td style="text-align: right">0.000000e+00</td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>共轭不是树外的 if-else。
</span></span><span style="display:flex;"><span>共轭是 kernel 的对称变换。
</span></span></code></pre></div><p>也说明 TreeHeap 的镜像能力可以从卷积核角度定义。</p>
<h2 id="实验总表">实验总表</h2>
<table>
  <thead>
      <tr>
          <th>检查项</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>pilot_pass</td>
          <td style="text-align: right">True</td>
      </tr>
      <tr>
          <td>search hit@1</td>
          <td style="text-align: right">True</td>
      </tr>
      <tr>
          <td>plus write hit@1</td>
          <td style="text-align: right">True</td>
      </tr>
      <tr>
          <td>target update error</td>
          <td style="text-align: right">0.000000</td>
      </tr>
      <tr>
          <td>max disjoint non-target update norm</td>
          <td style="text-align: right">0.000000</td>
      </tr>
      <tr>
          <td>raw mirror hit@1</td>
          <td style="text-align: right">False</td>
      </tr>
      <tr>
          <td>conjugate mirror hit@1</td>
          <td style="text-align: right">True</td>
      </tr>
      <tr>
          <td>score-map equiv max error</td>
          <td style="text-align: right">0.000000e+00</td>
      </tr>
  </tbody>
</table>
<p>证据路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/src/kernel_convolution_ops_probe.py
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/kernel_convolution_ops_probe/
</span></span></code></pre></div><h2 id="这个-proof-证明了什么">这个 proof 证明了什么</h2>
<p>它证明了一个很小、但很关键的东西：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>search、plus/write、conjugate 可以共享同一种 kernel convolution 语义。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 扫树
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>产生 score/update map
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>读、写、镜像都从这张 map 或它的对称变换产生
</span></span></code></pre></div><p>这让 TreeHeap 操作不再是一堆散装函数。</p>
<p>它们开始有一个统一形式：</p>
$$ H_{t+1} = \operatorname{Op}_K(H_t) $$<p>其中：</p>
$$ \operatorname{Op}_K $$<p>来自 kernel 在树上的卷积。</p>
<h2 id="这个-proof-没证明什么">这个 proof 没证明什么</h2>
<p>它没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 可以自己学出来。
</span></span></code></pre></div><p>这次 kernel 是固定的：</p>
$$ score(a) = -\lVert patch(a)-query\rVert^2 $$<p>它也没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可以翻译。
</span></span><span style="display:flex;"><span>TreeHeap 可以理解语言。
</span></span><span style="display:flex;"><span>TreeHeap 比 Transformer 强。
</span></span></code></pre></div><p>这些都还不能说。</p>
<p>它只证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从操作定义上，TreeHeap 可以把 search、plus/write、conjugate
</span></span><span style="display:flex;"><span>统一为 kernel convolution。
</span></span></code></pre></div><p>这个地基比“我们手写了几个函数”更干净。</p>
<h2 id="glm-审计后的修订">GLM 审计后的修订</h2>
<p>Runner / GLM 复核以后指出了一个非常重要的边界：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C08 的 conjugate proof 是 by construction 的恒等。
</span></span></code></pre></div><p>这句话是什么意思？</p>
<p>在代码里，我们定义了两个东西：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror_tree:
</span></span><span style="display:flex;"><span>  把路径 L/R 互换。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mirror_patch:
</span></span><span style="display:flex;"><span>  把局部子堆的 left/right 互换。
</span></span></code></pre></div><p>于是对于原始路径 \(p\)，有：</p>
$$ \operatorname{mirror\_patch} \big( \operatorname{patch}(\operatorname{mirror\_tree}(H), \sigma(p)) \big) = \operatorname{patch}(H,p) $$<p>所以：</p>
$$ score_{\text{conjugate}}(\sigma(p)) = score_{\text{original}}(p) $$<p>这不是模型“自己发现了镜像规律”。</p>
<p>这是我们按共轭定义写出来以后，数学上必然成立。</p>
<p>因此，<code>score_map_equiv_max_error = 0.0</code> 的意义不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 学会了镜像。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果我们把 conjugate 定义成 kernel 的对称变换，
</span></span><span style="display:flex;"><span>那么 TreeHeap 的镜像 score map 可以保持一致。
</span></span></code></pre></div><p>这依然有价值。</p>
<p>但它的价值是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>操作语义统一。
</span></span></code></pre></div><p>不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>学习能力证明。
</span></span></code></pre></div><p>所以 <code>M0-SOFT-C08</code> 的精确边界应该写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C08 支持的是 operator-semantics pilot。
</span></span><span style="display:flex;"><span>它证明 search / plus / conjugate 可以被统一写成 kernel convolution。
</span></span><span style="display:flex;"><span>它不证明 learned kernel，也不证明模型会自动学出共轭对称。
</span></span></code></pre></div><p>这个修订非常重要。</p>
<p>否则我们会把“定义上成立”误读成“实验上发现”。</p>
<h2 id="下一步-predict">下一步 Predict</h2>
<p>下一步不能继续证明 fixed kernel。</p>
<p>fixed kernel 的作用已经完成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>说明 TreeHeap 操作可以被统一定义为 kernel convolution。
</span></span></code></pre></div><p>下一步要证明的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个 kernel 能不能从数据中学出来？
</span></span></code></pre></div><p>所以我建议新增两个 predict。</p>
<h3 id="p-soft05learned-convolution-kernel">P-SOFT05：learned convolution kernel</h3>
<p>Predict：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap kernel 的核心是卷积状态变换，
</span></span><span style="display:flex;"><span>那么一个非线性 learned kernel 应该能从 raw query + raw subheap 中
</span></span><span style="display:flex;"><span>学会产生正确的 score map 和 write field。
</span></span></code></pre></div><p>注意关键词是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>raw query
</span></span><span style="display:flex;"><span>raw subheap
</span></span></code></pre></div><p>也就是说，不能再手工喂：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>diff = patch - query
</span></span><span style="display:flex;"><span>abs(diff)
</span></span><span style="display:flex;"><span>diff^2
</span></span><span style="display:flex;"><span>root_alignment
</span></span><span style="display:flex;"><span>child_alignment
</span></span></code></pre></div><p>这些都是答案提示。</p>
<p>真正的 learned kernel 应该输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query_root, query_left, query_right
</span></span><span style="display:flex;"><span>patch_root, patch_left, patch_right
</span></span><span style="display:flex;"><span>path metadata
</span></span></code></pre></div><p>然后自己学出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query 和 patch 是否匹配。
</span></span></code></pre></div><h3 id="p-syntax01真实句法树-micro-benchmark">P-SYNTAX01：真实句法树 micro benchmark</h3>
<p>Predict：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap kernel 不是只在 toy 树上成立，
</span></span><span style="display:flex;"><span>那么它应该能在小规模真实句法树上读到局部依存结构信号。
</span></span></code></pre></div><p>这不是 WMT BLEU。</p>
<p>这是一个桥梁实验。</p>
<p>目标是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>让真实语言数据第一次进入 M0/S1 的 TreeHeap kernel 证据链。
</span></span></code></pre></div><p>建议数据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Universal Dependencies 小型子集
</span></span><span style="display:flex;"><span>100 到 1000 句
</span></span></code></pre></div><p>任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定一个 head token 的局部 TreeHeap 子结构，
</span></span><span style="display:flex;"><span>预测或匹配它的 modifier / dependent pattern。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>head -&gt; left dependent / right dependent
</span></span><span style="display:flex;"><span>verb -&gt; subject / object / modifier
</span></span><span style="display:flex;"><span>noun -&gt; determiner / adjective / prepositional phrase
</span></span></code></pre></div><p>这个实验不要求翻译。</p>
<p>它只问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 在真实句法树上是否比 flat baseline 更会利用局部树结构？
</span></span></code></pre></div><h2 id="下一步实验设计">下一步实验设计</h2>
<p>下一步不是继续手写 kernel。</p>
<p>下一步应该问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个 kernel 能不能被学习出来？
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>raw query + raw subheap
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>learned kernel
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>score map / write field / conjugate transfer
</span></span></code></pre></div><p>建议下一步做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-SOFT05: learned convolution kernel
</span></span></code></pre></div><p>对照：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>fixed kernel
</span></span><span style="display:flex;"><span>linear raw kernel
</span></span><span style="display:flex;"><span>MLP raw kernel
</span></span><span style="display:flex;"><span>TreeHeap convolution kernel
</span></span></code></pre></div><p>目标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不用手工 diff。
</span></span><span style="display:flex;"><span>让模型自己学会 query-subheap 比较。
</span></span></code></pre></div><p>如果 learned kernel 能做到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>search map 正确
</span></span><span style="display:flex;"><span>write field 正确
</span></span><span style="display:flex;"><span>mirror conjugate 可迁移
</span></span></code></pre></div><p>那我们才可以把 C05 往前推进。</p>
<h3 id="实验-alearned-multi-pattern-kernel">实验 A：learned multi-pattern kernel</h3>
<p>数据生成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>每个样本随机生成一个 query pattern。
</span></span><span style="display:flex;"><span>把这个 pattern 注入 TreeHeap 的某个目标子堆。
</span></span><span style="display:flex;"><span>模型必须在所有候选子堆里找出目标位置。
</span></span></code></pre></div><p>关键点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不是固定 query。
</span></span><span style="display:flex;"><span>必须是 multi-pattern。
</span></span></code></pre></div><p>因为固定 query 很容易退化成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>记住某一个模式。
</span></span></code></pre></div><p>多 pattern 才能测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 是否真的学会比较 query 和 patch。
</span></span></code></pre></div><p>对照组：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>输入</th>
          <th>预期</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>fixed distance kernel</td>
          <td>手写 \( -\lVert patch-query\rVert^2 \)</td>
          <td>上限参考，不算学习</td>
      </tr>
      <tr>
          <td>linear raw kernel</td>
          <td>raw query + raw patch</td>
          <td>应该失败或较弱</td>
      </tr>
      <tr>
          <td>MLP raw kernel</td>
          <td>raw query + raw patch</td>
          <td>应该明显强于 linear</td>
      </tr>
      <tr>
          <td>TreeHeap convolution kernel</td>
          <td>raw query + raw patch + path/topology</td>
          <td>应该在 OOD 地址上最好</td>
      </tr>
  </tbody>
</table>
<p>Evidence gates：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-SOFT14:
</span></span><span style="display:flex;"><span>  MLP raw kernel &gt; linear raw kernel
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>E-SOFT15:
</span></span><span style="display:flex;"><span>  TreeHeap convolution kernel 在 unseen depth / unseen address 上
</span></span><span style="display:flex;"><span>  优于 flat MLP baseline
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>E-SOFT16:
</span></span><span style="display:flex;"><span>  不使用 hand-coded diff / alignment 特征
</span></span></code></pre></div><p>Falsification：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 linear raw 或 flat MLP 在同样数据量下稳定匹配 TreeHeap kernel，
</span></span><span style="display:flex;"><span>那么 TreeHeap kernel 没有显示额外结构收益。
</span></span></code></pre></div><h3 id="实验-blearned-conjugate-transfer">实验 B：learned conjugate transfer</h3>
<p>GLM 已经指出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 conjugate proof 是 by construction。
</span></span></code></pre></div><p>所以真正要测的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned kernel 是否能在镜像结构上迁移。
</span></span></code></pre></div><p>设计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>训练集：
</span></span><span style="display:flex;"><span>  只出现左侧结构，比如 L 开头路径。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>测试集：
</span></span><span style="display:flex;"><span>  只出现镜像右侧结构，比如 R 开头路径。
</span></span></code></pre></div><p>比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>raw learned kernel
</span></span><span style="display:flex;"><span>explicit conjugate kernel
</span></span><span style="display:flex;"><span>data augmentation baseline
</span></span><span style="display:flex;"><span>flat MLP baseline
</span></span></code></pre></div><p>Evidence gates：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-SOFT17:
</span></span><span style="display:flex;"><span>  explicit conjugate kernel 在 mirror OOD 上优于普通 learned kernel
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>E-SOFT18:
</span></span><span style="display:flex;"><span>  使用更少右侧样本达到同等准确率
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>E-SOFT19:
</span></span><span style="display:flex;"><span>  mirror score map 在 learned setting 下误差受控
</span></span></code></pre></div><p>Falsification：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果普通 MLP 通过足够少样本就学到同等镜像迁移，
</span></span><span style="display:flex;"><span>或者 explicit conjugate kernel 没有 sample efficiency 优势，
</span></span><span style="display:flex;"><span>那么共轭 kernel 不构成有效归纳偏置。
</span></span></code></pre></div><h3 id="实验-c真实句法树-micro-benchmark">实验 C：真实句法树 micro benchmark</h3>
<p>数据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Universal Dependencies
</span></span><span style="display:flex;"><span>先取 100 到 1000 句
</span></span><span style="display:flex;"><span>只做英文或中文单语
</span></span></code></pre></div><p>构造：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把 dependency tree 转成 TreeHeap-like 局部子结构。
</span></span><span style="display:flex;"><span>每个候选 patch 包含：
</span></span><span style="display:flex;"><span>  head token embedding / id
</span></span><span style="display:flex;"><span>  left dependent
</span></span><span style="display:flex;"><span>  right dependent
</span></span><span style="display:flex;"><span>  dependency label 或无监督 slot
</span></span><span style="display:flex;"><span>  path/topology metadata
</span></span></code></pre></div><p>任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定 query，找出正确 head-dependent 子结构。
</span></span><span style="display:flex;"><span>或给定局部子树，预测 masked dependent / role。
</span></span></code></pre></div><p>对照组：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>BoW / token-only baseline
</span></span><span style="display:flex;"><span>flat MLP
</span></span><span style="display:flex;"><span>small Transformer encoder
</span></span><span style="display:flex;"><span>TreeHeap convolution kernel
</span></span></code></pre></div><p>Evidence gates：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-SYNTAX01:
</span></span><span style="display:flex;"><span>  TreeHeap kernel &gt; token-only baseline
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>E-SYNTAX02:
</span></span><span style="display:flex;"><span>  TreeHeap kernel 在 OOD dependency pattern 上比 flat MLP 更稳
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>E-SYNTAX03:
</span></span><span style="display:flex;"><span>  去掉 path/topology/subheap 后性能明显下降
</span></span></code></pre></div><p>Falsification：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 token-only 或 flat MLP 在真实句法树 micro benchmark 上匹配 TreeHeap kernel，
</span></span><span style="display:flex;"><span>则 TreeHeap 结构对真实语言局部结构没有显示额外收益。
</span></span></code></pre></div><h2 id="ara-补项">ARA 补项</h2>
<p>GLM 还指出了两个 ARA 文档层面的缺口。</p>
<p>第一，<code>PAPER.md</code> 里还没有把 <code>SPR-022</code>、<code>SPR-023</code> 和 <code>M0-SOFT-C08</code> 注册到总 claim 树。</p>
<p>第二，<code>exploration_tree.yaml</code> 里还没有把最近三步补进去：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C07 structural proof
</span></span><span style="display:flex;"><span>C08 kernel convolution proof
</span></span><span style="display:flex;"><span>P-SOFT05 learned kernel pivot
</span></span></code></pre></div><p>这些不是实验本身的问题。</p>
<p>它们是 ARA 索引问题。</p>
<p>我建议下一次 ARA 修订补：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C5-009:
</span></span><span style="display:flex;"><span>  SPR-022 数学底座：
</span></span><span style="display:flex;"><span>  TreeHeap math foundations map to BCK Hopf algebra + operad.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>C5-010:
</span></span><span style="display:flex;"><span>  SPR-023 kernel convolution：
</span></span><span style="display:flex;"><span>  TreeHeap primitive ops can be defined as kernel convolutions over tree state.
</span></span></code></pre></div><p>同时在 trace DAG 中补：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E-SOFT-002:
</span></span><span style="display:flex;"><span>  structural_c05_probe
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>E-SOFT-003:
</span></span><span style="display:flex;"><span>  kernel_convolution_ops_probe
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>D-SOFT-003:
</span></span><span style="display:flex;"><span>  operator semantics unified by kernel convolution
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>P-SOFT-005:
</span></span><span style="display:flex;"><span>  learned convolution kernel
</span></span></code></pre></div><p>这一步我先不直接改。
原因是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这篇 blog 先给 Houming818 review 下一步实验方向。
</span></span><span style="display:flex;"><span>等 review 后，再把 PAPER.md 和 trace DAG 一次性修正。
</span></span></code></pre></div><h2 id="结论">结论</h2>
<p>这篇的结论是一句话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的操作本体应该是 kernel convolution。
</span></span></code></pre></div><p>不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树上有一个 kernel。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 扫树，产生状态场；
</span></span><span style="display:flex;"><span>状态场再解释为 search、plus、write、fold、conjugate。
</span></span></code></pre></div><p>这把 TreeHeap 从“树形数据结构”推进到了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树形高维状态场上的卷积计算系统。
</span></span></code></pre></div><p>这才是下一阶段要训练、要证明、要和 MLP / Transformer 对照的对象。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-024] 概率 Kernel：用 KL 散度衡量 TreeHeap 是否学到世界模型</title>
      <link>https://www.grepcode.cn/spr/024-probabilistic-kernel-kl-world-model.html</link>
      <pubDate>Wed, 24 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/024-probabilistic-kernel-kl-world-model.html</guid>
      <description>把 TreeHeap kernel 拆成代数 kernel 与概率 kernel：前者证明操作定义正确，后者用 KL 散度和交叉熵证明模型是否学到了世界模型中的操作分布。</description>
      <content:encoded><![CDATA[<h1 id="概率-kernel用-kl-散度衡量-treeheap-是否学到世界模型">概率 Kernel：用 KL 散度衡量 TreeHeap 是否学到世界模型</h1>
<p>上一篇 <code>SPR-023</code> 证明了一件很基础的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的 search / plus / conjugate
</span></span><span style="display:flex;"><span>可以统一理解成 kernel 在树形内存态上的卷积。
</span></span></code></pre></div><p>但 Houming818 进一步指出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 也要分类型。
</span></span><span style="display:flex;"><span>有的 kernel 是代数的，100% 确定；
</span></span><span style="display:flex;"><span>有的 kernel 是概率的，像 softmax 一样输出分布。
</span></span></code></pre></div><p>这个拆分非常重要。</p>
<p>因为它可以直接回答 GLM 对 C08 的批评：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>conjugate proof 是 by construction。
</span></span></code></pre></div><p>是的。</p>
<p>如果一个 kernel 是代数 kernel，它本来就应该 by construction。
它证明的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>操作定义是否正确。
</span></span></code></pre></div><p>不是证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型是否学会了这个操作。
</span></span></code></pre></div><p>如果要证明“学会了”，就必须进入第二类：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>概率 kernel proof。
</span></span></code></pre></div><p>而概率 kernel proof 需要一个新的量尺。</p>
<p>这个量尺就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>KL 散度。
</span></span></code></pre></div><h2 id="两类-kernel">两类 Kernel</h2>
<p>TreeHeap kernel 现在应该拆成两层。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. Algebraic Kernel
</span></span><span style="display:flex;"><span>2. Probabilistic Kernel
</span></span></code></pre></div><p>它们分别回答不同问题。</p>
<h2 id="algebraic-kernel证明操作空间">Algebraic Kernel：证明操作空间</h2>
<p>代数 kernel 是确定性的。</p>
<p>它像数学函数：</p>
$$ K(H) \to H' $$<p>只要输入相同，输出就相同。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror kernel
</span></span><span style="display:flex;"><span>path shift kernel
</span></span><span style="display:flex;"><span>subheap extract kernel
</span></span><span style="display:flex;"><span>exact match kernel
</span></span><span style="display:flex;"><span>compose kernel
</span></span><span style="display:flex;"><span>decompose kernel
</span></span><span style="display:flex;"><span>conjugate kernel
</span></span></code></pre></div><p>这些 kernel 的目标不是学习。</p>
<p>它们的目标是证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 操作空间定义良好。
</span></span></code></pre></div><p>例如镜像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L &lt;-&gt; R
</span></span></code></pre></div><p>如果路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LRL
</span></span></code></pre></div><p>镜像后应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>RLR
</span></span></code></pre></div><p>这不是概率问题。</p>
<p>这是代数定义。</p>
<p>如果写成公式：</p>
$$ \sigma(LRL)=RLR $$<p>那 proof 应该要求：</p>
$$ \sigma^{-1}(\sigma(a)) = a $$<p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>镜像两次回到原路径。
</span></span></code></pre></div><p>这类 proof 的指标应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>closure_ok = true
</span></span><span style="display:flex;"><span>mirror_error = 0
</span></span><span style="display:flex;"><span>equiv_error = 0
</span></span><span style="display:flex;"><span>compose_consistency = true
</span></span></code></pre></div><p>它对应：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数学正确性。
</span></span></code></pre></div><p>所以 <code>SPR-023</code> 的 C08 更准确地说属于：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Algebraic Kernel Proof
</span></span></code></pre></div><p>它证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>search / plus / conjugate 可以被统一定义成 kernel convolution。
</span></span></code></pre></div><p>它不证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型从数据里学会了 search / plus / conjugate。
</span></span></code></pre></div><h2 id="probabilistic-kernel证明选择机制">Probabilistic Kernel：证明选择机制</h2>
<p>概率 kernel 不直接输出一个确定结果。</p>
<p>它输出一个分布：</p>
$$ P_\theta(a \mid H,q) $$<p>其中：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>\(H\)</td>
          <td>当前 TreeHeap 内存态</td>
      </tr>
      <tr>
          <td>\(q\)</td>
          <td>query</td>
      </tr>
      <tr>
          <td>\(a\)</td>
          <td>候选操作或候选地址</td>
      </tr>
      <tr>
          <td>\(\theta\)</td>
          <td>可学习参数</td>
      </tr>
  </tbody>
</table>
<p>例如 route kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop: 0.1
</span></span><span style="display:flex;"><span>left: 0.8
</span></span><span style="display:flex;"><span>right: 0.1
</span></span></code></pre></div><p>例如 write kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LL: 0.05
</span></span><span style="display:flex;"><span>LR: 0.82
</span></span><span style="display:flex;"><span>RL: 0.07
</span></span><span style="display:flex;"><span>RR: 0.06
</span></span></code></pre></div><p>例如 decompose kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A+B: 0.55
</span></span><span style="display:flex;"><span>C+D: 0.35
</span></span><span style="display:flex;"><span>other: 0.10
</span></span></code></pre></div><p>这才进入学习问题。</p>
<p>它问的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型输出的概率分布，
</span></span><span style="display:flex;"><span>是否接近世界模型里的真实概率分布？
</span></span></code></pre></div><h2 id="世界模型里的概率分布">世界模型里的概率分布</h2>
<p>我们先定义一个世界模型。</p>
<p>世界模型不是玄学。</p>
<p>在 proof 里，它可以是一个明确的数据生成器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>WorldModel W
</span></span></code></pre></div><p>它给出：</p>
$$ P_W(a \mid H,q) $$<p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在 TreeHeap 状态 H 和 query q 下，
</span></span><span style="display:flex;"><span>世界模型认为每个操作 a 的真实概率是多少。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_W(stop, left, right)
</span></span><span style="display:flex;"><span>=
</span></span><span style="display:flex;"><span>[0.1, 0.8, 0.1]
</span></span></code></pre></div><p>模型输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_\theta(stop, left, right)
</span></span><span style="display:flex;"><span>=
</span></span><span style="display:flex;"><span>[0.3, 0.4, 0.3]
</span></span></code></pre></div><p>这时我们就可以问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型离世界模型有多远？
</span></span></code></pre></div><p>这个距离就用 KL 散度衡量。</p>
<h2 id="kl-散度是什么">KL 散度是什么</h2>
<p>KL 散度的定义是：</p>
$$ D_{\rm KL}(P \parallel Q) = \sum_x P(x)\log \frac{P(x)}{Q(x)} $$<p>在我们这里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P = 世界模型分布
</span></span><span style="display:flex;"><span>Q = TreeHeap kernel 学到的分布
</span></span></code></pre></div><p>所以：</p>
$$ D_{\rm KL} \big( P_W(a \mid H,q) \parallel P_\theta(a \mid H,q) \big) = \sum_a P_W(a \mid H,q) \log \frac{ P_W(a \mid H,q) }{ P_\theta(a \mid H,q) } $$<p>人话解释：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果真实世界按 P_W 运行，
</span></span><span style="display:flex;"><span>但模型用 P_theta 去解释，
</span></span><span style="display:flex;"><span>会多付出多少信息代价？
</span></span></code></pre></div><p>如果：</p>
$$ P_\theta = P_W $$<p>那么：</p>
$$ D_{\rm KL}(P_W \parallel P_\theta)=0 $$<p>越接近 0，说明模型越像世界模型。</p>
<h2 id="kl-与交叉熵">KL 与交叉熵</h2>
<p>KL 可以展开：</p>
$$ D_{\rm KL}(P \parallel Q) = H(P,Q)-H(P) $$<p>其中：</p>
$$ H(P,Q) = -\sum_x P(x)\log Q(x) $$<p>是交叉熵。</p>
<p>因为 \(H(P)\) 是世界模型自己的熵，对模型参数 \(\theta\) 来说是常数。</p>
<p>所以训练时：</p>
$$ \min_\theta D_{\rm KL}(P_W \parallel P_\theta) $$<p>等价于：</p>
$$ \min_\theta H(P_W, P_\theta) $$<p>这就是为什么机器学习经常用 cross entropy。</p>
<p>如果 \(P_W\) 是 one-hot：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left = 1.0
</span></span><span style="display:flex;"><span>其他 = 0.0
</span></span></code></pre></div><p>那就是普通分类。</p>
<p>如果 \(P_W\) 是 soft distribution：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop = 0.1
</span></span><span style="display:flex;"><span>left = 0.8
</span></span><span style="display:flex;"><span>right = 0.1
</span></span></code></pre></div><p>那就是概率模仿。</p>
<p>TreeHeap 的概率 kernel 更应该从 soft distribution 开始。</p>
<p>因为 TreeHeap 的核心思想之一是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>信息不足时不要过早坍缩。
</span></span></code></pre></div><h2 id="treeheap-的概率-kernel-训练目标">TreeHeap 的概率 Kernel 训练目标</h2>
<p>一个概率 TreeHeap kernel 可以写成：</p>
$$ P_\theta(a \mid H,q) = \operatorname{softmax}(K_\theta(H,q))_a $$<p>世界模型给：</p>
$$ P_W(a \mid H,q) $$<p>训练 loss：</p>
$$ L(\theta) = \mathbb{E}_{(H,q)\sim \mathcal{D}} \left[ D_{\rm KL} \big( P_W(a \mid H,q) \parallel P_\theta(a \mid H,q) \big) \right] $$<p>人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在很多 TreeHeap 状态和 query 上，
</span></span><span style="display:flex;"><span>让模型输出的操作分布接近世界模型的操作分布。
</span></span></code></pre></div><p>这可以训练：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route kernel
</span></span><span style="display:flex;"><span>write kernel
</span></span><span style="display:flex;"><span>merge kernel
</span></span><span style="display:flex;"><span>decompose kernel
</span></span><span style="display:flex;"><span>collapse kernel
</span></span></code></pre></div><h2 id="plus-的两层定义">plus 的两层定义</h2>
<p>现在 plus 可以拆成两层。</p>
<p>第一层是代数候选：</p>
$$ \{\operatorname{Plus}_a(H,x)\}_{a\in A} $$<p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对每个地址 a，
</span></span><span style="display:flex;"><span>如果把 x plus 到那里，
</span></span><span style="display:flex;"><span>都会得到一个合法候选 TreeHeap。
</span></span></code></pre></div><p>这是代数 kernel 的部分。</p>
<p>第二层是概率选择：</p>
$$ P_\theta(a \mid H,x) $$<p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型认为这次应该写到哪个地址。
</span></span></code></pre></div><p>Soft Plus 是两者合起来：</p>
$$ H_{t+1} = \sum_a P_\theta(a \mid H,x) \operatorname{Plus}_a(H,x) $$<p>如果 \(P_\theta\) 最后坍缩成 one-hot：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_theta(LR)=1.0
</span></span><span style="display:flex;"><span>其他 = 0.0
</span></span></code></pre></div><p>那它就回到 hard plus。</p>
<p>所以：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>代数 kernel 定义可以做什么；
</span></span><span style="display:flex;"><span>概率 kernel 学习什么时候做什么。
</span></span></code></pre></div><p>这是这篇最重要的一句话。</p>
<h2 id="一个-toy-世界模型">一个 Toy 世界模型</h2>
<p>为了证明概率 kernel 能学到世界模型，我们需要先设计一个可控世界。</p>
<p>例如定义一个路由世界：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 query 和左子堆更相似：
</span></span><span style="display:flex;"><span>  P_W(left)=0.8, P_W(right)=0.1, P_W(stop)=0.1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>如果 query 和右子堆更相似：
</span></span><span style="display:flex;"><span>  P_W(right)=0.8, P_W(left)=0.1, P_W(stop)=0.1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>如果当前节点已经足够匹配：
</span></span><span style="display:flex;"><span>  P_W(stop)=0.8, P_W(left)=0.1, P_W(right)=0.1
</span></span></code></pre></div><p>注意这里不是 hard label。</p>
<p>不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left = 1
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left = 0.8
</span></span></code></pre></div><p>这样才能测试 Probability Container。</p>
<p>模型输出：</p>
$$ P_\theta(stop,left,right \mid H,q) $$<p>训练目标：</p>
$$ D_{\rm KL}(P_W \parallel P_\theta) $$<p>如果训练成功，应该看到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train_KL 下降
</span></span><span style="display:flex;"><span>test_KL 下降
</span></span><span style="display:flex;"><span>OOD_KL 仍然较低
</span></span></code></pre></div><p>这才说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型不是只记住训练样本。
</span></span><span style="display:flex;"><span>它学到了世界模型分布里的规律。
</span></span></code></pre></div><h2 id="为什么要看-ood-kl">为什么要看 OOD KL</h2>
<p>只看训练集 KL 不够。</p>
<p>因为模型可能死记：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个样本就是 left。
</span></span><span style="display:flex;"><span>那个样本就是 right。
</span></span></code></pre></div><p>所以必须设计 OOD 测试。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>训练：
</span></span><span style="display:flex;"><span>  depth &lt;= 3
</span></span><span style="display:flex;"><span>  path 只出现 L 开头
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>测试：
</span></span><span style="display:flex;"><span>  depth &gt;= 5
</span></span><span style="display:flex;"><span>  path 出现 R 开头镜像结构
</span></span></code></pre></div><p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train_KL 低
</span></span><span style="display:flex;"><span>test_KL 高
</span></span></code></pre></div><p>说明模型只是记忆。</p>
<p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train_KL 低
</span></span><span style="display:flex;"><span>test_KL 低
</span></span><span style="display:flex;"><span>OOD_KL 也低
</span></span></code></pre></div><p>才说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型学到了可迁移的世界模型概率规律。
</span></span></code></pre></div><h2 id="实验设计p-soft05-kl">实验设计：P-SOFT05-KL</h2>
<p>我建议下一步 predict 写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-SOFT05-KL:
</span></span><span style="display:flex;"><span>TreeHeap probabilistic kernel should learn a world-model operation
</span></span><span style="display:flex;"><span>distribution with lower OOD KL than flat baselines.
</span></span></code></pre></div><p>中文：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 TreeHeap 概率 kernel 真的有结构归纳偏置，
</span></span><span style="display:flex;"><span>它应该能用更少样本学到世界模型的操作概率分布，
</span></span><span style="display:flex;"><span>并在未见过的地址、深度、镜像结构上保持较低 KL。
</span></span></code></pre></div><h3 id="数据">数据</h3>
<p>构造 TreeHeap toy world：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = full binary TreeHeap
</span></span><span style="display:flex;"><span>q = query pattern
</span></span><span style="display:flex;"><span>a = {stop, left, right} 或候选 write addresses
</span></span></code></pre></div><p>世界模型生成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_W(a | H,q)
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_W(a | H,q)
</span></span><span style="display:flex;"><span>=
</span></span><span style="display:flex;"><span>softmax(-distance(query, subheap_a) / temperature)
</span></span></code></pre></div><p>这里 distance 是世界模型内部规则。</p>
<p>训练模型不知道这个公式。</p>
<p>模型只能看到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>raw query
</span></span><span style="display:flex;"><span>raw subheap
</span></span><span style="display:flex;"><span>path/topology metadata
</span></span><span style="display:flex;"><span>目标分布 P_W
</span></span></code></pre></div><h3 id="模型对照">模型对照</h3>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>输入</th>
          <th>目的</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>flat MLP</td>
          <td>展平 TreeHeap + query</td>
          <td>测普通函数逼近</td>
      </tr>
      <tr>
          <td>linear kernel</td>
          <td>raw query + raw patch</td>
          <td>测线性是否足够</td>
      </tr>
      <tr>
          <td>MLP raw kernel</td>
          <td>raw query + raw patch</td>
          <td>测非线性比较能力</td>
      </tr>
      <tr>
          <td>TreeHeap prob kernel</td>
          <td>raw query + raw patch + path/topology</td>
          <td>测结构归纳偏置</td>
      </tr>
      <tr>
          <td>oracle fixed kernel</td>
          <td>世界模型公式</td>
          <td>上限参考，不算学习</td>
      </tr>
  </tbody>
</table>
<h3 id="指标">指标</h3>
<p>主要指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train_KL
</span></span><span style="display:flex;"><span>test_KL
</span></span><span style="display:flex;"><span>OOD_KL
</span></span></code></pre></div><p>辅助指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cross_entropy
</span></span><span style="display:flex;"><span>entropy_error
</span></span><span style="display:flex;"><span>top1_agreement
</span></span><span style="display:flex;"><span>calibration_error
</span></span><span style="display:flex;"><span>sample_efficiency
</span></span><span style="display:flex;"><span>collapse_accuracy_tau_low
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>entropy_error
</span></span></code></pre></div><p>衡量模型有没有把世界模型的不确定性学出来。</p>
<p>例如世界模型很犹豫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[0.45, 0.45, 0.10]
</span></span></code></pre></div><p>模型不应该强行输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[0.99, 0.01, 0.00]
</span></span></code></pre></div><p>否则它虽然 top1 可能对，但概率世界模型学错了。</p>
<h2 id="预期结果">预期结果</h2>
<p>如果 TreeHeap 概率 kernel 成立，我们希望看到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap prob kernel:
</span></span><span style="display:flex;"><span>  train_KL 低
</span></span><span style="display:flex;"><span>  test_KL 低
</span></span><span style="display:flex;"><span>  OOD_KL 低
</span></span><span style="display:flex;"><span>  calibration 好
</span></span><span style="display:flex;"><span>  sample_efficiency 高
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flat MLP:
</span></span><span style="display:flex;"><span>  train_KL 可以低
</span></span><span style="display:flex;"><span>  但 OOD_KL 更高
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>linear kernel:
</span></span><span style="display:flex;"><span>  多 pattern 下 KL 较高
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>oracle fixed kernel:
</span></span><span style="display:flex;"><span>  KL 接近 0
</span></span><span style="display:flex;"><span>  作为上限参考
</span></span></code></pre></div><p>如果结果相反：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flat MLP 的 OOD_KL 和 TreeHeap 一样低，
</span></span><span style="display:flex;"><span>或者 TreeHeap 需要更多样本，
</span></span><span style="display:flex;"><span>或者 TreeHeap calibration 更差，
</span></span></code></pre></div><p>那就说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 概率 kernel 暂时没有显示结构收益。
</span></span></code></pre></div><p>这就是 falsification。</p>
<h2 id="和-transformer-的类比">和 Transformer 的类比</h2>
<p>Transformer 学到的不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>矩阵本身很神秘。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>通过梯度下降，把 token 共现、上下文相关性、
</span></span><span style="display:flex;"><span>query-key-value 关系压进参数矩阵。
</span></span></code></pre></div><p>它可以被理解为学习：</p>
$$ P(token_j \mid token_i, context) $$<p>TreeHeap 概率 kernel 要学的是：</p>
$$ P(operation \mid query, subheap, path, topology, context) $$<p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在某个树形状态下，
</span></span><span style="display:flex;"><span>应该 stop、left、right、write、merge、decompose 的概率是多少。
</span></span></code></pre></div><p>这才是 TreeHeap 的概率学习对象。</p>
<h2 id="这篇的结论">这篇的结论</h2>
<p>现在 TreeHeap kernel proof 应该分成两条线。</p>
<p>第一条：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Algebraic Kernel Proof
</span></span></code></pre></div><p>证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 操作空间定义正确。
</span></span></code></pre></div><p>指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>closure
</span></span><span style="display:flex;"><span>equivariance
</span></span><span style="display:flex;"><span>mirror error
</span></span><span style="display:flex;"><span>compose consistency
</span></span></code></pre></div><p>第二条：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Probabilistic Kernel Proof
</span></span></code></pre></div><p>证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型能从数据中学习世界模型的操作概率分布。
</span></span></code></pre></div><p>指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>KL divergence
</span></span><span style="display:flex;"><span>cross entropy
</span></span><span style="display:flex;"><span>calibration
</span></span><span style="display:flex;"><span>OOD KL
</span></span><span style="display:flex;"><span>sample efficiency
</span></span></code></pre></div><p>最终一句话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>代数 kernel 定义 TreeHeap 能做什么；
</span></span><span style="display:flex;"><span>概率 kernel 学习 TreeHeap 什么时候应该做什么。
</span></span></code></pre></div><p>下一步实验就应该从 KL proof 开始。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-025] 演绎与归纳：TreeHeap Kernel 的两类 Proof</title>
      <link>https://www.grepcode.cn/spr/025-deductive-inductive-kernel-proof.html</link>
      <pubDate>Wed, 24 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/025-deductive-inductive-kernel-proof.html</guid>
      <description>把 TreeHeap kernel proof 拆成演绎证明和归纳证明：演绎证明代数操作按定义成立，归纳证明概率 kernel 能通过梯度学习拟合世界模型分布，并用 KL/OOD KL 评价。</description>
      <content:encoded><![CDATA[<h1 id="演绎与归纳treeheap-kernel-的两类-proof">演绎与归纳：TreeHeap Kernel 的两类 Proof</h1>
<p>上一篇 <code>SPR-024</code> 说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 要分成代数 kernel 和概率 kernel。
</span></span></code></pre></div><p>Houming818 又把问题说得更准确：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这里其实是演绎推理和归纳推理的区别。
</span></span></code></pre></div><p>这句话是关键。</p>
<p>我们之前有时把两类 proof 混在一起了。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>conjugate 按公式定义后，镜像结果成立。
</span></span></code></pre></div><p>这是演绎推理。</p>
<p>它不是模型从数据中学出来的。</p>
<p>而：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个概率 kernel 通过梯度下降，学会输出接近世界模型的概率分布。
</span></span></code></pre></div><p>这是归纳推理。</p>
<p>它不是由公式直接推出的。</p>
<p>它必须通过数据、loss、梯度、参数更新和测试集来证明。</p>
<p>所以从这篇开始，我们把 TreeHeap kernel proof 正式拆成两类：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Deductive Kernel Proof
</span></span><span style="display:flex;"><span>Inductive Kernel Proof
</span></span></code></pre></div><h2 id="演绎-proof-是什么">演绎 Proof 是什么</h2>
<p>演绎 proof 的形式是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定定义
</span></span><span style="display:flex;"><span>推出结论
</span></span></code></pre></div><p>例如镜像路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L &lt;-&gt; R
</span></span></code></pre></div><p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror(LRL) = RLR
</span></span></code></pre></div><p>再镜像一次：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror(RLR) = LRL
</span></span></code></pre></div><p>所以：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror(mirror(path)) = path
</span></span></code></pre></div><p>这是从定义直接推出的。</p>
<p>不需要训练。</p>
<p>不需要梯度。</p>
<p>不需要数据集。</p>
<p>只要定义正确，它就应该 100% 成立。</p>
<p>数学上可以写：</p>
$$ \sigma^{-1}(\sigma(a)) = a $$<p>这就是演绎 proof。</p>
<h2 id="treeheap-里的演绎-kernel">TreeHeap 里的演绎 Kernel</h2>
<p>TreeHeap 里很多 kernel 都是这种。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror kernel
</span></span><span style="display:flex;"><span>conjugate kernel
</span></span><span style="display:flex;"><span>path shift kernel
</span></span><span style="display:flex;"><span>subheap extract kernel
</span></span><span style="display:flex;"><span>one-hot Soft Plus
</span></span><span style="display:flex;"><span>hard compose/decompose 的合法性
</span></span></code></pre></div><p>这些东西的 proof 目标是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>操作定义是否自洽。
</span></span></code></pre></div><p>它们的指标应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror_error = 0
</span></span><span style="display:flex;"><span>conjugate_equiv_error = 0
</span></span><span style="display:flex;"><span>closure_ok = true
</span></span><span style="display:flex;"><span>one_hot_soft_plus_error = 0
</span></span></code></pre></div><p>如果这些不成立，说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的代数定义有 bug。
</span></span></code></pre></div><p>但如果它们成立，也不能说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型学会了语言。
</span></span><span style="display:flex;"><span>模型学会了概率。
</span></span><span style="display:flex;"><span>模型学会了世界模型。
</span></span></code></pre></div><p>它只说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>操作空间定义正确。
</span></span></code></pre></div><h2 id="归纳-proof-是什么">归纳 Proof 是什么</h2>
<p>归纳 proof 的形式是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定数据
</span></span><span style="display:flex;"><span>给定模型
</span></span><span style="display:flex;"><span>给定 loss
</span></span><span style="display:flex;"><span>通过训练更新参数
</span></span><span style="display:flex;"><span>看模型是否学到数据中的规律
</span></span></code></pre></div><p>例如线性回归：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>y = ax + b
</span></span></code></pre></div><p>我们不知道 \(a,b\)。</p>
<p>模型通过数据和梯度下降学到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a_hat
</span></span><span style="display:flex;"><span>b_hat
</span></span></code></pre></div><p>这不是从定义直接推出的。</p>
<p>这是从样本中归纳出来的。</p>
<p>Transformer 也是类似。</p>
<p>Transformer 不是因为矩阵定义在那里，所以自然懂语言。</p>
<p>而是因为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>大量文本数据
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>loss
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>梯度下降
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>参数矩阵被修正
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>模型学到 token 共现、上下文关系、query-key-value 结构
</span></span></code></pre></div><p>这是归纳推理。</p>
<p>TreeHeap 的概率 kernel 也必须走这条路。</p>
<h2 id="treeheap-概率-kernel-学什么">TreeHeap 概率 Kernel 学什么</h2>
<p>概率 kernel 输出的是分布：</p>
$$ P_\theta(a \mid H,q) $$<p>其中：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>\(H\)</td>
          <td>当前 TreeHeap 状态</td>
      </tr>
      <tr>
          <td>\(q\)</td>
          <td>query</td>
      </tr>
      <tr>
          <td>\(a\)</td>
          <td>候选操作或候选地址</td>
      </tr>
      <tr>
          <td>\(\theta\)</td>
          <td>可学习参数</td>
      </tr>
  </tbody>
</table>
<p>世界模型给一个目标分布：</p>
$$ P_W(a \mid H,q) $$<p>模型要学的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_theta 尽量接近 P_W。
</span></span></code></pre></div><p>评价工具是 KL 散度：</p>
$$ D_{KL}(P_W \parallel P_\theta) = \sum_a P_W(a)\log\frac{P_W(a)}{P_\theta(a)} $$<p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>KL 接近 0
</span></span></code></pre></div><p>说明模型分布接近世界模型分布。</p>
<p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>KL 很大
</span></span></code></pre></div><p>说明模型没学好。</p>
<p>这就是概率 kernel 的归纳 proof。</p>
<h2 id="这次实验">这次实验</h2>
<p>我写了一个新 proof：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>deductive_inductive_kernel_probe.py
</span></span></code></pre></div><p>证据路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/src/deductive_inductive_kernel_probe.py
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/deductive_inductive_kernel_probe/
</span></span></code></pre></div><p>这个 proof 分成两部分。</p>
<p>第一部分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>演绎 proof
</span></span></code></pre></div><p>检查代数定义是否精确成立。</p>
<p>第二部分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>归纳 proof
</span></span></code></pre></div><p>训练概率 kernel 去模仿一个世界模型分布，并用 KL 测量。</p>
<h2 id="part-a演绎检查">Part A：演绎检查</h2>
<p>实验检查了四个确定性性质：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror_path(mirror_path(p)) == p
</span></span><span style="display:flex;"><span>mirror_patch(mirror_patch(x)) == x
</span></span><span style="display:flex;"><span>conjugate score equivalence error == 0
</span></span><span style="display:flex;"><span>one-hot Soft Plus == Hard Plus
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>Check</th>
          <th style="text-align: right">Result</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>mirror involution</td>
          <td style="text-align: right">True</td>
      </tr>
      <tr>
          <td>mirror patch involution error</td>
          <td style="text-align: right">0.000000e+00</td>
      </tr>
      <tr>
          <td>conjugate equivalence error</td>
          <td style="text-align: right">0.000000e+00</td>
      </tr>
      <tr>
          <td>one-hot soft plus error</td>
          <td style="text-align: right">0.000000e+00</td>
      </tr>
  </tbody>
</table>
<p>解释：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这些是演绎性质。
</span></span><span style="display:flex;"><span>它们按定义应该成立。
</span></span></code></pre></div><p>这个结果说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的这些代数 kernel 定义是自洽的。
</span></span></code></pre></div><p>但它不说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型学到了概率分布。
</span></span></code></pre></div><p>这部分只属于演绎 proof。</p>
<h2 id="part-b归纳-kl-学习">Part B：归纳 KL 学习</h2>
<p>为了测试概率学习，我们构造了一个 toy world model。</p>
<p>世界模型定义：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query 和某个子堆越接近，
</span></span><span style="display:flex;"><span>这个子堆被选中的概率越高。
</span></span></code></pre></div><p>数学上：</p>
$$ P_W(a \mid H,q)=\operatorname{softmax}(-\lVert patch(a)-query\rVert^2 / T) $$<p>其中 \(T=0.45\) 是温度。</p>
<p>模型看不到这个公式。</p>
<p>模型只看到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>raw query
</span></span><span style="display:flex;"><span>raw patch
</span></span><span style="display:flex;"><span>path/topology metadata
</span></span><span style="display:flex;"><span>目标概率分布 P_W
</span></span></code></pre></div><p>训练目标：</p>
$$ \min_\theta D_{KL}(P_W \parallel P_\theta) $$<p>测试指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train_KL
</span></span><span style="display:flex;"><span>test_KL
</span></span><span style="display:flex;"><span>OOD_KL
</span></span><span style="display:flex;"><span>top1_agreement
</span></span><span style="display:flex;"><span>entropy_error
</span></span><span style="display:flex;"><span>calibration_l1
</span></span></code></pre></div><h2 id="对照模型">对照模型</h2>
<p>这次用了五个模型：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>address_prior</td>
          <td>只记地址偏好，不看 query / patch</td>
      </tr>
      <tr>
          <td>linear_raw</td>
          <td>线性模型，看 raw query + raw patch</td>
      </tr>
      <tr>
          <td>mlp_raw</td>
          <td>非线性 MLP，看 raw query + raw patch</td>
      </tr>
      <tr>
          <td>treeheap_prob_kernel</td>
          <td>MLP + path/topology metadata</td>
      </tr>
      <tr>
          <td>oracle_fixed_kernel</td>
          <td>直接使用世界模型公式，上限参考</td>
      </tr>
  </tbody>
</table>
<p>注意：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>oracle_fixed_kernel 不算学习。
</span></span></code></pre></div><p>它只是告诉我们理论上最优可以到哪里。</p>
<h2 id="实验结果">实验结果</h2>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Train KL</th>
          <th style="text-align: right">Test KL</th>
          <th style="text-align: right">OOD KL</th>
          <th style="text-align: right">OOD top1</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>address_prior</td>
          <td style="text-align: right">1.435286</td>
          <td style="text-align: right">1.434764</td>
          <td style="text-align: right">2.403086</td>
          <td style="text-align: right">0.047</td>
      </tr>
      <tr>
          <td>linear_raw</td>
          <td style="text-align: right">1.436146</td>
          <td style="text-align: right">1.440253</td>
          <td style="text-align: right">2.403392</td>
          <td style="text-align: right">0.040</td>
      </tr>
      <tr>
          <td>mlp_raw</td>
          <td style="text-align: right">0.007935</td>
          <td style="text-align: right">0.009027</td>
          <td style="text-align: right">0.022695</td>
          <td style="text-align: right">0.957</td>
      </tr>
      <tr>
          <td>treeheap_prob_kernel</td>
          <td style="text-align: right">0.009950</td>
          <td style="text-align: right">0.010835</td>
          <td style="text-align: right">0.053386</td>
          <td style="text-align: right">0.877</td>
      </tr>
      <tr>
          <td>oracle_fixed_kernel</td>
          <td style="text-align: right">0.000000</td>
          <td style="text-align: right">0.000000</td>
          <td style="text-align: right">0.000000</td>
          <td style="text-align: right">1.000</td>
      </tr>
  </tbody>
</table>
<p>结论先说清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>归纳学习成立。
</span></span><span style="display:flex;"><span>TreeHeap 结构优势没有在这个 toy 里成立。
</span></span></code></pre></div><p>为什么？</p>
<p>因为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mlp_raw 的 OOD KL = 0.022695
</span></span><span style="display:flex;"><span>treeheap_prob_kernel 的 OOD KL = 0.053386
</span></span></code></pre></div><p>也就是说，在这个 toy world 里，单纯的 raw MLP 比加了 path/topology 的 TreeHeap prob kernel 更好。</p>
<p>这不是坏消息。</p>
<p>这是一个很有用的负边界。</p>
<p>它说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个世界模型主要由 query-patch 内容距离决定。
</span></span><span style="display:flex;"><span>路径/topology 不是必要信息。
</span></span></code></pre></div><p>所以 TreeHeap 结构没有优势，是合理的。</p>
<h2 id="这个实验真正证明了什么">这个实验真正证明了什么</h2>
<p>它证明了三件事。</p>
<p>第一：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>演绎 proof 和归纳 proof 必须分开。
</span></span></code></pre></div><p>代数恒等式成立，是定义正确。</p>
<p>KL 下降，是参数从数据中学到概率规律。</p>
<p>第二：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>概率 kernel 可以用 KL 来评价。
</span></span></code></pre></div><p><code>mlp_raw</code> 从高 KL 降到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>test_KL = 0.009027
</span></span><span style="display:flex;"><span>OOD_KL = 0.022695
</span></span></code></pre></div><p>说明它确实通过梯度学习到了世界模型分布。</p>
<p>第三：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 结构优势需要更合适的数据分布。
</span></span></code></pre></div><p>如果世界模型只依赖内容距离：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>distance(query, patch)
</span></span></code></pre></div><p>那么普通 MLP 就足够强。</p>
<p>TreeHeap 应该在这些数据分布上证明自己：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径前缀影响概率
</span></span><span style="display:flex;"><span>镜像结构影响概率
</span></span><span style="display:flex;"><span>子堆组合影响概率
</span></span><span style="display:flex;"><span>延迟坍缩影响概率
</span></span></code></pre></div><p>也就是说，下一步的世界模型不能只靠内容距离。</p>
<p>它必须让：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>address
</span></span><span style="display:flex;"><span>path
</span></span><span style="display:flex;"><span>topology
</span></span><span style="display:flex;"><span>composition
</span></span><span style="display:flex;"><span>decomposition
</span></span></code></pre></div><p>真的进入 \(P_W\)。</p>
<h2 id="这次实验没证明什么">这次实验没证明什么</h2>
<p>它没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 比 MLP 更强。
</span></span></code></pre></div><p>相反，这个 toy 里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mlp_raw 更好。
</span></span></code></pre></div><p>它也没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能翻译。
</span></span><span style="display:flex;"><span>TreeHeap 能理解句法。
</span></span><span style="display:flex;"><span>TreeHeap 能替代 Transformer。
</span></span></code></pre></div><p>它只证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>概率 kernel 的归纳学习可以用 KL/OOD KL 来测量。
</span></span></code></pre></div><p>这个边界很重要。</p>
<h2 id="下一步怎么改世界模型">下一步怎么改世界模型</h2>
<p>下一步的世界模型应该加入结构项。</p>
<p>例如：</p>
$$ P_W(a \mid H,q)=\operatorname{softmax}(-(d_{content}(a)+\lambda d_{path}(a)+\mu d_{topology}(a))/T) $$<p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>d_content:
</span></span><span style="display:flex;"><span>  query 和 patch 的内容距离
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>d_path:
</span></span><span style="display:flex;"><span>  query 目标路径和候选路径的前缀距离
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>d_topology:
</span></span><span style="display:flex;"><span>  候选子堆的结构合法性或组合关系
</span></span></code></pre></div><p>这样，TreeHeap kernel 才有机会利用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>path
</span></span><span style="display:flex;"><span>topology
</span></span><span style="display:flex;"><span>subheap relation
</span></span></code></pre></div><p>否则它只是一个更复杂的 MLP。</p>
<p>下一轮 predict 应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-SOFT06:
</span></span><span style="display:flex;"><span>当世界模型分布同时依赖 content + path + topology 时，
</span></span><span style="display:flex;"><span>TreeHeap prob kernel 的 OOD KL 应该低于 mlp_raw。
</span></span></code></pre></div><p>对应 falsification：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 mlp_raw 在 content+path+topology 世界里仍然匹配或优于 TreeHeap prob kernel，
</span></span><span style="display:flex;"><span>那么当前 TreeHeap 概率 kernel 没有显示结构归纳偏置。
</span></span></code></pre></div><h2 id="总结">总结</h2>
<p>这篇的结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>演绎 proof 证明定义正确。
</span></span><span style="display:flex;"><span>归纳 proof 证明参数从数据中学习。
</span></span></code></pre></div><p>TreeHeap 需要两种 proof。</p>
<p>代数 kernel 的成功，不应该冒充概率学习。</p>
<p>概率 kernel 的成功，必须用 KL、OOD KL、校准和样本效率来衡量。</p>
<p>这次实验支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0-SOFT-C09:
</span></span><span style="display:flex;"><span>TreeHeap kernel proof 必须区分演绎代数恒等与归纳概率学习；
</span></span><span style="display:flex;"><span>KL 散度可以衡量 learned probabilistic kernel 是否模仿了世界模型分布。
</span></span></code></pre></div><p>但它也给出一个负边界：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 toy 不支持 TreeHeap 结构优势。
</span></span></code></pre></div><p>下一步，要把世界模型从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只依赖内容距离
</span></span></code></pre></div><p>升级为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同时依赖内容、路径、拓扑、组合和分解。
</span></span></code></pre></div><p>那才是真正测试 TreeHeap 存在性的概率 proof。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-026] S1 开始：真实短句上的浅层 TreeHeap 写入</title>
      <link>https://www.grepcode.cn/spr/026-s1-shallow-treeheap-write.html</link>
      <pubDate>Thu, 25 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/026-s1-shallow-treeheap-write.html</guid>
      <description>M0 pilot closed 之后，S1 的第一步不是 WMT，而是真实短句上的 encoder -&amp;gt; soft TreeHeap write -&amp;gt; slot probe。本文记录 shallow_treeheap_s1_probe 的设计、结果和边界。</description>
      <content:encoded><![CDATA[<h1 id="s1-开始真实短句上的浅层-treeheap-写入">S1 开始：真实短句上的浅层 TreeHeap 写入</h1>
<p>前面 <code>SPR-025</code> 把 proof 分成两类：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>演绎 proof：按定义推出，应该精确成立。
</span></span><span style="display:flex;"><span>归纳 proof：从数据训练出来，必须看 loss / KL / accuracy / OOD。
</span></span></code></pre></div><p>这一区分很重要。</p>
<p>因为 M0 主要解决的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的数学操作能不能定义？
</span></span></code></pre></div><p>而 S1 要开始解决：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实数据能不能写进 TreeHeap？
</span></span><span style="display:flex;"><span>写进去之后，能不能被 kernel / probe 查询？
</span></span></code></pre></div><p>所以这一篇不是继续证明 M0 的闭包。</p>
<p>这一篇是 S1 的第一块砖。</p>
<h2 id="为什么不直接上-wmt">为什么不直接上 WMT？</h2>
<p>WMT 是翻译任务。</p>
<p>它太大了。</p>
<p>如果一上来跑 WMT，失败时我们不知道问题在哪：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>是 encoder 不会写？
</span></span><span style="display:flex;"><span>是 TreeHeap 不会保存？
</span></span><span style="display:flex;"><span>是 probe 不会读？
</span></span><span style="display:flex;"><span>是结构太深？
</span></span><span style="display:flex;"><span>是 decoder 不会生成？
</span></span><span style="display:flex;"><span>是 loss 不合适？
</span></span></code></pre></div><p>所以 S1 第一版应该非常浅：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实短句
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>浅层 TreeHeap memory
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>root / subject / object 查询
</span></span></code></pre></div><p>也就是先问一个低级但关键的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型能不能把真实语言里的短句，写成可查询的数据结构？
</span></span></code></pre></div><p>如果这个都不成立，就没有必要谈 S2 / WMT。</p>
<h2 id="实验目标">实验目标</h2>
<p>本次实验脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/src/shallow_treeheap_s1_probe.py
</span></span></code></pre></div><p>远端执行在：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ni.grepcode.cn
</span></span></code></pre></div><p>证据目录：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/evidence/shallow_treeheap_s1_probe/
</span></span></code></pre></div><p>实验 claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-C30:
</span></span><span style="display:flex;"><span>一个可学习的浅层 TreeHeap write，
</span></span><span style="display:flex;"><span>可以把真实短句编码到 root / subject / object 槽位，
</span></span><span style="display:flex;"><span>并支持 OOD 新词的 copy-by-address。
</span></span></code></pre></div><p>这里的核心不是“背训练集答案”。</p>
<p>核心是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入里出现一个新词，
</span></span><span style="display:flex;"><span>模型以前没在输出标签里训练过这个词，
</span></span><span style="display:flex;"><span>TreeHeap 仍然能把它复制到正确槽位。
</span></span></code></pre></div><p>这就是 TreeHeap 作为结构内存的第一种价值。</p>
<h2 id="数据是什么">数据是什么？</h2>
<p>这次不是随机向量。</p>
<p>数据是人工整理的真实词短句，例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>alice opens door
</span></span><span style="display:flex;"><span>bob finds key
</span></span><span style="display:flex;"><span>carol sees bob
</span></span><span style="display:flex;"><span>nurse brings water
</span></span><span style="display:flex;"><span>teacher holds book
</span></span></code></pre></div><p>结构很浅：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subject verb object
</span></span></code></pre></div><p>对应 TreeHeap 槽位：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[0] = root
</span></span><span style="display:flex;"><span>arr[1] = subject
</span></span><span style="display:flex;"><span>arr[2] = object
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>opens
</span></span><span style="display:flex;"><span>├── alice
</span></span><span style="display:flex;"><span>└── door
</span></span></code></pre></div><p>注意，这里不是说英语永远是这种结构。</p>
<p>这里只是 S1 的第一步。</p>
<p>我们先让 TreeHeap 学一个深度很浅、结构很清楚的小世界。</p>
<h2 id="数据规模">数据规模</h2>
<p>这次数据切分：</p>
<table>
  <thead>
      <tr>
          <th>Split</th>
          <th style="text-align: right">Count</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>train</td>
          <td style="text-align: right">63</td>
      </tr>
      <tr>
          <td>test</td>
          <td style="text-align: right">17</td>
      </tr>
      <tr>
          <td>OOD</td>
          <td style="text-align: right">10</td>
      </tr>
      <tr>
          <td>vocab</td>
          <td style="text-align: right">37</td>
      </tr>
  </tbody>
</table>
<p>OOD 里包含训练输出没见过的新词，例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>erin draws cup
</span></span><span style="display:flex;"><span>nurse brings water
</span></span><span style="display:flex;"><span>frank draws box
</span></span><span style="display:flex;"><span>teacher holds book
</span></span></code></pre></div><p>这很关键。</p>
<p>如果模型只是普通分类器，它会倾向于输出训练集中见过的词。</p>
<p>但 TreeHeap memory 的写入方式可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把输入 token 复制到某个槽位。
</span></span></code></pre></div><p>所以它有机会处理新词。</p>
<h2 id="三个模型">三个模型</h2>
<p>这次对比了三个模型。</p>
<h3 id="1-bow_linear">1. bow_linear</h3>
<p>输入是 bag-of-words。</p>
<p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>alice sees bob
</span></span></code></pre></div><p>和：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>bob sees alice
</span></span></code></pre></div><p>在它看来几乎是同一袋词。</p>
<p>它不擅长区分谁是 subject，谁是 object。</p>
<h3 id="2-seq_linear">2. seq_linear</h3>
<p>输入保留位置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>position 0 = alice
</span></span><span style="display:flex;"><span>position 1 = sees
</span></span><span style="display:flex;"><span>position 2 = bob
</span></span></code></pre></div><p>所以它比 bag-of-words 强。</p>
<p>但是它仍然是普通线性分类器。</p>
<p>如果一个词从来没作为训练输出出现过，它很难突然输出这个词。</p>
<h3 id="3-soft_treeheap">3. soft_treeheap</h3>
<p>这是本次主角。</p>
<p>它学习的是一个 soft write：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>position 0 -&gt; 哪个 TreeHeap slot
</span></span><span style="display:flex;"><span>position 1 -&gt; 哪个 TreeHeap slot
</span></span><span style="display:flex;"><span>position 2 -&gt; 哪个 TreeHeap slot
</span></span></code></pre></div><p>写入形式可以理解成：</p>
$$ M[s,v] = \sum_p P(s \mid p) \cdot 1[token_p = v] $$<p>其中：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>\(M\)</td>
          <td>TreeHeap memory</td>
      </tr>
      <tr>
          <td>\(s\)</td>
          <td>slot，比如 root / subject / object</td>
      </tr>
      <tr>
          <td>\(v\)</td>
          <td>token</td>
      </tr>
      <tr>
          <td>\(p\)</td>
          <td>输入位置</td>
      </tr>
      <tr>
          <td>\(P(s \mid p)\)</td>
          <td>第 p 个 token 写入 slot s 的概率</td>
      </tr>
  </tbody>
</table>
<p>如果模型学到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>position 0 -&gt; subject
</span></span><span style="display:flex;"><span>position 1 -&gt; root
</span></span><span style="display:flex;"><span>position 2 -&gt; object
</span></span></code></pre></div><p>那么：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>nurse brings water
</span></span></code></pre></div><p>即使 <code>nurse</code>、<code>brings</code>、<code>water</code> 是新词，也可以被复制到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subject = nurse
</span></span><span style="display:flex;"><span>root    = brings
</span></span><span style="display:flex;"><span>object  = water
</span></span></code></pre></div><p>这就是 copy-by-address。</p>
<h2 id="实验结果">实验结果</h2>
<p>结果如下：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Train exact</th>
          <th style="text-align: right">Test exact</th>
          <th style="text-align: right">OOD exact</th>
          <th style="text-align: right">Test subheap</th>
          <th style="text-align: right">OOD subheap</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>bow_linear</td>
          <td style="text-align: right">0.873</td>
          <td style="text-align: right">0.765</td>
          <td style="text-align: right">0.000</td>
          <td style="text-align: right">0.765</td>
          <td style="text-align: right">0.000</td>
      </tr>
      <tr>
          <td>seq_linear</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">0.765</td>
          <td style="text-align: right">0.000</td>
          <td style="text-align: right">0.765</td>
          <td style="text-align: right">0.000</td>
      </tr>
      <tr>
          <td>soft_treeheap</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.000</td>
          <td style="text-align: right">1.000</td>
      </tr>
  </tbody>
</table>
<p>这里的 <code>subheap</code> 指：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root + object
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>draws cup
</span></span><span style="display:flex;"><span>brings water
</span></span><span style="display:flex;"><span>holds book
</span></span></code></pre></div><p>也就是一个很浅的子结构查询。</p>
<h2 id="treeheap-学到了什么">TreeHeap 学到了什么？</h2>
<p>soft TreeHeap 最后学到的写入概率是：</p>
<table>
  <thead>
      <tr>
          <th>输入位置</th>
          <th style="text-align: right">root</th>
          <th style="text-align: right">subject</th>
          <th style="text-align: right">object</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>position 0</td>
          <td style="text-align: right">0.0016</td>
          <td style="text-align: right">0.9968</td>
          <td style="text-align: right">0.0016</td>
      </tr>
      <tr>
          <td>position 1</td>
          <td style="text-align: right">0.9968</td>
          <td style="text-align: right">0.0016</td>
          <td style="text-align: right">0.0016</td>
      </tr>
      <tr>
          <td>position 2</td>
          <td style="text-align: right">0.0016</td>
          <td style="text-align: right">0.0016</td>
          <td style="text-align: right">0.9968</td>
      </tr>
  </tbody>
</table>
<p>换句话说，它学到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>position 0 -&gt; subject
</span></span><span style="display:flex;"><span>position 1 -&gt; root
</span></span><span style="display:flex;"><span>position 2 -&gt; object
</span></span></code></pre></div><p>这是一个非常简单的浅层结构。</p>
<p>但这就是 S1 的意义：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不是先证明复杂语言。
</span></span><span style="display:flex;"><span>而是先证明数据可以写入 TreeHeap，并且能被查询。
</span></span></code></pre></div><h2 id="为什么普通-seq_linear-ood-失败">为什么普通 seq_linear OOD 失败？</h2>
<p><code>seq_linear</code> 在训练集上是 1.0。</p>
<p>说明它能背住训练词和位置关系。</p>
<p>但是 OOD 是 0.0。</p>
<p>原因很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它没有 copy 机制。
</span></span></code></pre></div><p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>nurse brings water
</span></span></code></pre></div><p>如果 <code>nurse</code> 和 <code>water</code> 没在训练输出里出现过，普通分类器没有学过：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输出 nurse
</span></span><span style="display:flex;"><span>输出 water
</span></span></code></pre></div><p>它只能偏向训练里见过的词。</p>
<p>TreeHeap 的 soft write 不同。</p>
<p>它不需要先学会每个词的输出权重。</p>
<p>它只需要学会：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第 0 个 token 写到 subject。
</span></span><span style="display:flex;"><span>第 1 个 token 写到 root。
</span></span><span style="display:flex;"><span>第 2 个 token 写到 object。
</span></span></code></pre></div><p>然后直接复制输入 token。</p>
<p>这就是结构内存和普通分类器的差异。</p>
<h2 id="这证明了什么">这证明了什么？</h2>
<p>这次支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-C30 -&gt; supported pilot
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>浅层 TreeHeap write 可以在真实短句上形成可查询 memory。
</span></span></code></pre></div><p>它还说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的地址/槽位机制，
</span></span><span style="display:flex;"><span>确实可以提供一种普通输出分类器没有的 OOD copy 能力。
</span></span></code></pre></div><p>这和我们之前讨论的方向是一致的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不只是一个 MLP。
</span></span><span style="display:flex;"><span>TreeHeap 的参数可以很少，
</span></span><span style="display:flex;"><span>但 memory 的地址、路径、slot、子结构本身参与了计算。
</span></span></code></pre></div><h2 id="这没有证明什么">这没有证明什么？</h2>
<p>边界必须说清楚。</p>
<p>这次没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能翻译。
</span></span><span style="display:flex;"><span>TreeHeap 能处理完整句法。
</span></span><span style="display:flex;"><span>TreeHeap 比 Transformer 强。
</span></span><span style="display:flex;"><span>TreeHeap 能处理长句。
</span></span><span style="display:flex;"><span>TreeHeap 已经解决 S2 graph assembly。
</span></span></code></pre></div><p>这次数据也很浅。</p>
<p>它更像是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1 的 hello world。
</span></span></code></pre></div><p>但它不是没意义。</p>
<p>因为它第一次把 M0 的数学工具箱接到了真实短句数据上。</p>
<h2 id="下一步怎么改">下一步怎么改？</h2>
<p>下一步不能继续只做固定 SVO。</p>
<p>否则 TreeHeap 学到的只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>位置模板。
</span></span></code></pre></div><p>下一轮应该加入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>可变长度
</span></span><span style="display:flex;"><span>修饰语
</span></span><span style="display:flex;"><span>被动句
</span></span><span style="display:flex;"><span>OSV / 倒装
</span></span><span style="display:flex;"><span>中文短句
</span></span><span style="display:flex;"><span>多 root 候选
</span></span><span style="display:flex;"><span>matched pointer/copy baseline
</span></span></code></pre></div><p>新的 predict 可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P-S1-REAL-SHALLOW-02:
</span></span><span style="display:flex;"><span>当句子顺序不再固定时，
</span></span><span style="display:flex;"><span>TreeHeap kernel 必须利用 token 内容、路径、slot 和局部子结构，
</span></span><span style="display:flex;"><span>而不是只利用 position。
</span></span></code></pre></div><p>如果下一轮 TreeHeap 仍然能稳住，而普通 baseline 不行，
那 S1 才开始从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>存在性 proof
</span></span></code></pre></div><p>进入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>结构优势 proof
</span></span></code></pre></div><h2 id="总结">总结</h2>
<p>这次实验的结论很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0 可以进入 S1。
</span></span><span style="display:flex;"><span>S1 的第一版真实短句浅层写入成立。
</span></span></code></pre></div><p>TreeHeap 学到的不是语言全貌。</p>
<p>它学到的是一件很小但关键的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如何把真实句子的 token 写入可查询的结构槽位。
</span></span></code></pre></div><p>这就是下一步工作的地基。</p>
<p>现在我们可以继续往上加难度了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-027] TreeHeap 差分代数：从 Zero 到距离，再到学习</title>
      <link>https://www.grepcode.cn/spr/027-treeheap-diff-algebra.html</link>
      <pubDate>Thu, 25 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/027-treeheap-diff-algebra.html</guid>
      <description>TreeHeap 的距离不应该先拍一个 scalar 公式，而应该先定义 Zero、差分、范数、内积、cosine 和 finite difference。本文记录 treeheap_diff_algebra_probe 的设计和结果。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-差分代数从-zero-到距离再到学习">TreeHeap 差分代数：从 Zero 到距离，再到学习</h1>
<p>上一篇 <code>SPR-026</code> 做了一个浅层 S1 proof：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实短句
</span></span><span style="display:flex;"><span>-&gt; soft TreeHeap write
</span></span><span style="display:flex;"><span>-&gt; root / subject / object slot
</span></span><span style="display:flex;"><span>-&gt; query
</span></span></code></pre></div><p>但 Houming818 指出了一个更底层的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>两个 TreeHeap 结构如何计算距离？
</span></span></code></pre></div><p>我一开始直接回答“可以算节点距离、路径加权距离、子堆距离”。</p>
<p>这个回答不算错，但跳了一步。</p>
<p>真正第一性的问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的差分怎么定义？
</span></span></code></pre></div><p>因为距离不是第一定义。</p>
<p>距离应该来自：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>差分
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>范数
</span></span><span style="display:flex;"><span>↓
</span></span><span style="display:flex;"><span>距离
</span></span></code></pre></div><p>就像实数一样：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>|x-y|
</span></span></code></pre></div><p>这里真正先发生的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x-y
</span></span></code></pre></div><p>再取绝对值。</p>
<p>向量也是一样：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>||a-b||
</span></span></code></pre></div><p>先有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a-b
</span></span></code></pre></div><p>再有范数。</p>
<p>TreeHeap 也应该这样。</p>
<h2 id="为什么差分比距离更基础">为什么差分比距离更基础？</h2>
<p>机器学习不是只需要“两个东西远不远”。</p>
<p>机器学习还需要知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果我把参数改一点，
</span></span><span style="display:flex;"><span>loss 会怎么变？
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>差分 / 微分 / 梯度
</span></span></code></pre></div><p>如果 TreeHeap 只有一个距离函数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Distance(A,B)
</span></span></code></pre></div><p>但没有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Diff(A,B)
</span></span></code></pre></div><p>那它很难接上学习。</p>
<p>因为学习要做的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Δloss / Δparameter
</span></span></code></pre></div><p>所以我们需要先定义：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Zero
</span></span><span style="display:flex;"><span>Subtraction
</span></span><span style="display:flex;"><span>Norm
</span></span><span style="display:flex;"><span>Inner Product
</span></span><span style="display:flex;"><span>Cosine
</span></span><span style="display:flex;"><span>Finite Difference
</span></span></code></pre></div><p>这就是本篇的主题。</p>
<h2 id="zero-treeheap">Zero TreeHeap</h2>
<p>先定义零 TreeHeap：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Zero[i] = 0 ∈ R^128
</span></span></code></pre></div><p>也就是每个节点都是 128D 零向量。</p>
<p>如果一个 TreeHeap 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H
</span></span></code></pre></div><p>那么它的大小不是凭空来的，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H - Zero
</span></span></code></pre></div><p>再取范数。</p>
<p>这和实数一致：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>|x| = |x - 0|
</span></span></code></pre></div><h2 id="treeheap-差分">TreeHeap 差分</h2>
<p>假设两个 TreeHeap 的地址空间一样：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A[i] ∈ R^128
</span></span><span style="display:flex;"><span>B[i] ∈ R^128
</span></span></code></pre></div><p>那么差分定义为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Diff(A,B)[i] = A[i] - B[i]
</span></span></code></pre></div><p>注意：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Diff(A,B)
</span></span></code></pre></div><p>仍然是一个 TreeHeap-shaped object。</p>
<p>只是每个节点存的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>向量差
</span></span></code></pre></div><p>而不是原始向量。</p>
<p>这点很关键。</p>
<p>我们不是把 TreeHeap 压扁成一个 scalar。</p>
<p>我们先保留结构差异。</p>
<h2 id="treeheap-范数">TreeHeap 范数</h2>
<p>TreeHeap 不是普通 flat vector。</p>
<p>节点有深度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root depth = 0
</span></span><span style="display:flex;"><span>left/right depth = 1
</span></span><span style="display:flex;"><span>deeper nodes depth = 2,3,...
</span></span></code></pre></div><p>所以第一版范数加入深度权重：</p>
$$ \lVert H\rVert_T = \sqrt{\sum_i \alpha^{depth(i)} \lVert H[i]\rVert_2^2} $$<p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0 &lt; alpha &lt; 1
</span></span></code></pre></div><p>这表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>越靠近 root，权重越大。
</span></span><span style="display:flex;"><span>越深的节点，权重越小。
</span></span></code></pre></div><p>这不是最终答案，但它是一个合理的第一版。</p>
<h2 id="treeheap-距离">TreeHeap 距离</h2>
<p>有了差分和范数，距离自然定义为：</p>
$$ d(A,B) = \lVert A-B\rVert_T $$<p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先差分
</span></span><span style="display:flex;"><span>再取 TreeHeap 范数
</span></span></code></pre></div><p>这比直接写一个 <code>distance(A,B)</code> 更干净。</p>
<p>因为它和学习、微分、梯度可以接上。</p>
<h2 id="treeheap-内积和-cosine">TreeHeap 内积和 cosine</h2>
<p>同样，cosine 也不应该是随便把节点平均后再算。</p>
<p>先定义 TreeHeap 内积：</p>
$$ \langle A,B\rangle_T = \sum_i \alpha^{depth(i)} \langle A[i],B[i]\rangle $$<p>然后定义 TreeHeap cosine：</p>
$$ \cos_T(A,B)=\frac{\langle A,B\rangle_T}{\lVert A\rVert_T\lVert B\rVert_T} $$<p>这样 cosine 也是从 TreeHeap 代数结构来的。</p>
<p>不是临时拼出来的。</p>
<h2 id="有限差分">有限差分</h2>
<p>现在进入学习。</p>
<p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L(H)
</span></span></code></pre></div><p>是一个 loss，我们想知道沿着方向：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>U
</span></span></code></pre></div><p>改变 TreeHeap 时，loss 怎么变。</p>
<p>有限差分可以写成：</p>
$$ \frac{L(H+\epsilon U)-L(H-\epsilon U)}{2\epsilon} $$<p>如果 TreeHeap 差分代数正确，这个数应该和解析方向导数对上。</p>
<p>对一个简单的加权 MSE：</p>
$$ L(H)=\frac{1}{2}\lVert H-Target\rVert_T^2 $$<p>方向导数应该是：</p>
$$ \langle H-Target, U\rangle_T $$<p>这就是实验要检查的第一件事。</p>
<h2 id="prob-vector-plus-的学习信号">prob vector plus 的学习信号</h2>
<p>我们还要检查它能不能接上写入学习。</p>
<p>定义一个最小 prob vector plus：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H&#39;[i] = H[i] + p_i · x
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x ∈ R^128
</span></span><span style="display:flex;"><span>p = softmax(theta)
</span></span></code></pre></div><p>这表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把一个 128D token/world vector
</span></span><span style="display:flex;"><span>按概率写入 TreeHeap 节点。
</span></span></code></pre></div><p>目标 TreeHeap 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Target[target_node] = x
</span></span><span style="display:flex;"><span>其他节点 = 0
</span></span></code></pre></div><p>loss：</p>
$$ L=\frac{1}{2}\lVert H'-Target\rVert_T^2 $$<p>如果差分代数能支持学习，那么：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>有限差分算出来的 dL/dtheta
</span></span></code></pre></div><p>应该接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>解析梯度算出来的 dL/dtheta
</span></span></code></pre></div><p>并且做一步梯度下降后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss 应该下降
</span></span><span style="display:flex;"><span>target_node 的写入概率应该上升
</span></span></code></pre></div><h2 id="实验脚本">实验脚本</h2>
<p>脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/src/treeheap_diff_algebra_probe.py
</span></span></code></pre></div><p>执行主机：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>io.grepcode.cn
</span></span></code></pre></div><p>证据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/treeheap_diff_algebra_probe/
</span></span></code></pre></div><p>参数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>nodes = 15
</span></span><span style="display:flex;"><span>dim = 128
</span></span><span style="display:flex;"><span>alpha = 0.72
</span></span><span style="display:flex;"><span>eps = 1e-5
</span></span></code></pre></div><h2 id="实验结果">实验结果</h2>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th style="text-align: right">Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>norm_zero</code></td>
          <td style="text-align: right">0.000000</td>
      </tr>
      <tr>
          <td><code>dist_aa</code></td>
          <td style="text-align: right">0.000000</td>
      </tr>
      <tr>
          <td><code>dist_ab</code></td>
          <td style="text-align: right">8.779953</td>
      </tr>
      <tr>
          <td><code>dist_ba</code></td>
          <td style="text-align: right">8.779953</td>
      </tr>
      <tr>
          <td><code>cos_aa</code></td>
          <td style="text-align: right">1.000000</td>
      </tr>
      <tr>
          <td><code>anti_sym_error</code></td>
          <td style="text-align: right">0.000000</td>
      </tr>
      <tr>
          <td><code>directional_derivative_abs_error</code></td>
          <td style="text-align: right">3.48e-10</td>
      </tr>
      <tr>
          <td><code>theta_grad_abs_error</code></td>
          <td style="text-align: right">4.21e-10</td>
      </tr>
      <tr>
          <td><code>theta_grad_rel_error</code></td>
          <td style="text-align: right">2.10e-10</td>
      </tr>
      <tr>
          <td><code>initial_loss</code></td>
          <td style="text-align: right">29.138441</td>
      </tr>
      <tr>
          <td><code>stepped_loss</code></td>
          <td style="text-align: right">0.000660</td>
      </tr>
      <tr>
          <td><code>target_prob_before</code></td>
          <td style="text-align: right">0.064808</td>
      </tr>
      <tr>
          <td><code>target_prob_after</code></td>
          <td style="text-align: right">0.995534</td>
      </tr>
  </tbody>
</table>
<p>这些结果说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Zero 范数为 0。
</span></span><span style="display:flex;"><span>自己到自己的距离为 0。
</span></span><span style="display:flex;"><span>距离对称。
</span></span><span style="display:flex;"><span>cos(A,A)=1。
</span></span><span style="display:flex;"><span>Diff(A,B)=-Diff(B,A)。
</span></span><span style="display:flex;"><span>TreeHeap 状态有限差分和解析方向导数一致。
</span></span><span style="display:flex;"><span>prob vector plus 的 theta 梯度和有限差分一致。
</span></span><span style="display:flex;"><span>一步梯度下降能显著降低 loss。
</span></span><span style="display:flex;"><span>写入概率会从错误的扩散状态坍缩到目标节点。
</span></span></code></pre></div><h2 id="这次证明了什么">这次证明了什么？</h2>
<p>这次支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0-DIFF-C01 -&gt; supported pilot
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可以先定义差分代数，
</span></span><span style="display:flex;"><span>再由差分推出距离、cosine、loss 和有限差分学习信号。
</span></span></code></pre></div><p>这件事很重要。</p>
<p>因为 S1 的 prob vector write 需要的不只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我能把 token 写进去。
</span></span></code></pre></div><p>还需要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>写错了，loss 怎么变？
</span></span><span style="display:flex;"><span>参数该往哪边改？
</span></span></code></pre></div><p>这就是差分代数给出的东西。</p>
<h2 id="这次没有证明什么">这次没有证明什么？</h2>
<p>边界也要清楚。</p>
<p>这次没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经学会语言。
</span></span><span style="display:flex;"><span>TreeHeap 已经有世界模型坐标系。
</span></span><span style="display:flex;"><span>prob vector plus 已经是最终 encoder。
</span></span><span style="display:flex;"><span>TreeHeap 比 MLP / Transformer 强。
</span></span><span style="display:flex;"><span>TreeHeap 能做 WMT。
</span></span></code></pre></div><p>它证明的是更底层的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 有可用于学习的差分/距离/梯度评价框架。
</span></span></code></pre></div><h2 id="对-s1-的意义">对 S1 的意义</h2>
<p>现在我们可以把 S1 的写入问题说得更精确。</p>
<p>不再只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把 token 写到 TreeHeap。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从 Zero TreeHeap 出发，
</span></span><span style="display:flex;"><span>用 prob vector plus 写入 128D token/world vector，
</span></span><span style="display:flex;"><span>用 TreeHeap diff distance 评价写入结果，
</span></span><span style="display:flex;"><span>再用有限差分/梯度更新写入 kernel。
</span></span></code></pre></div><p>这条链是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Zero
</span></span><span style="display:flex;"><span>-&gt; Prob Vector Plus
</span></span><span style="display:flex;"><span>-&gt; TreeHeap state
</span></span><span style="display:flex;"><span>-&gt; Diff to Target
</span></span><span style="display:flex;"><span>-&gt; Norm / Loss
</span></span><span style="display:flex;"><span>-&gt; Finite Difference / Gradient
</span></span><span style="display:flex;"><span>-&gt; Update Kernel
</span></span></code></pre></div><p>这才是 M0 工具箱进入 S1 的真正接口。</p>
<h2 id="下一步">下一步</h2>
<p>下一步不是再问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>距离怎么算？
</span></span></code></pre></div><p>而是问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Target 从哪里来？
</span></span></code></pre></div><p>也就是我们前面说的世界模型坐标系。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>foot + ball -&gt; football
</span></span><span style="display:flex;"><span>hand + ball -&gt; handball
</span></span><span style="display:flex;"><span>rain + coat -&gt; raincoat
</span></span><span style="display:flex;"><span>book + shelf -&gt; bookshelf
</span></span></code></pre></div><p>我们需要这样的数据，告诉 TreeHeap：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>什么样的写入结果是对的？
</span></span><span style="display:flex;"><span>什么样的组合关系应该在空间里接近？
</span></span></code></pre></div><p>没有世界模型坐标系，TreeHeap 只能学 echo。</p>
<p>有了世界模型坐标系，TreeHeap 才能学语义拓扑。</p>
<h2 id="总结">总结</h2>
<p>这篇的核心结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 距离不是第一定义。
</span></span><span style="display:flex;"><span>TreeHeap 差分才是第一定义。
</span></span></code></pre></div><p>从差分出发，我们得到了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Zero
</span></span><span style="display:flex;"><span>Subtraction
</span></span><span style="display:flex;"><span>Norm
</span></span><span style="display:flex;"><span>Inner Product
</span></span><span style="display:flex;"><span>Cosine
</span></span><span style="display:flex;"><span>Finite Difference
</span></span><span style="display:flex;"><span>Gradient Signal
</span></span></code></pre></div><p>这让 TreeHeap 不再只是一个“树形存储结构”。</p>
<p>它开始具备进入梯度学习的数学接口。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-028] 世界模型坐标系第一试：Frozen Embedding 不是胜利，是一把尺</title>
      <link>https://www.grepcode.cn/spr/028-s1-world-coordinate-negative.html</link>
      <pubDate>Thu, 25 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/028-s1-world-coordinate-negative.html</guid>
      <description>用冻结的 all-MiniLM-L6-v2 embedding 作为外部世界坐标尺，测试 TreeHeap prob vector plus 在复合词任务上能否靠近目标概念。结果是负面的：vector_add 明显更强。</description>
      <content:encoded><![CDATA[<h1 id="世界模型坐标系第一试frozen-embedding-不是胜利是一把尺">世界模型坐标系第一试：Frozen Embedding 不是胜利，是一把尺</h1>
<p><code>SPR-027</code> 之后，我们有了 TreeHeap 的差分代数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Zero
</span></span><span style="display:flex;"><span>Diff
</span></span><span style="display:flex;"><span>Norm
</span></span><span style="display:flex;"><span>Cosine
</span></span><span style="display:flex;"><span>Finite Difference
</span></span><span style="display:flex;"><span>Gradient Signal
</span></span></code></pre></div><p>这说明 TreeHeap 已经可以定义：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>写入结果和目标之间的距离
</span></span></code></pre></div><p>但马上出现下一个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>目标从哪里来？
</span></span></code></pre></div><p>也就是我们说的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>世界模型坐标系
</span></span></code></pre></div><p>如果没有世界模型坐标系，TreeHeap 只能学 echo。</p>
<p>如果有一个坐标系，它才知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>foot + ball 应该靠近 football
</span></span><span style="display:flex;"><span>hand + ball 应该靠近 handball
</span></span><span style="display:flex;"><span>rain + coat 应该靠近 raincoat
</span></span></code></pre></div><h2 id="这次用什么坐标系">这次用什么坐标系？</h2>
<p>这次采用 Houming818 选的 A 方案：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用现成 embedding。
</span></span></code></pre></div><p>具体是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>sentence-transformers/all-MiniLM-L6-v2
</span></span></code></pre></div><p>在 io 上使用的是本地缓存：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/home/nio/.cache/huggingface/hub/models--sentence-transformers--all-MiniLM-L6-v2/snapshots/1110a243fdf4706b3f48f1d95db1a4f5529b4d41
</span></span></code></pre></div><p>所以这次没有用 <code>proxychains4</code>。</p>
<p>如果后面要加载新模型或新语料，且本地没有缓存，就应该在 io 上用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>proxychains4
</span></span></code></pre></div><p>并把下载命令记录到 evidence。</p>
<h2 id="防蒸馏边界">防蒸馏边界</h2>
<p>这里必须说清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>冻结 embedding 不是 TreeHeap 自己学出的世界模型。
</span></span></code></pre></div><p>它只是一个外部坐标尺。</p>
<p>我们用它来问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 写入后的向量，能不能靠近这个坐标尺里的目标点？
</span></span></code></pre></div><p>这不是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经拥有 all-MiniLM 的知识。
</span></span></code></pre></div><p>更不是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 蒸馏了一个大模型。
</span></span></code></pre></div><p>本实验只验证：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap encoder 能否在一个冻结坐标系里学习组合映射。
</span></span></code></pre></div><h2 id="实验任务">实验任务</h2>
<p>任务是复合词组合：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left + right -&gt; target
</span></span></code></pre></div><p>例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>foot + ball -&gt; football
</span></span><span style="display:flex;"><span>basket + ball -&gt; basketball
</span></span><span style="display:flex;"><span>hand + ball -&gt; handball
</span></span><span style="display:flex;"><span>rain + coat -&gt; raincoat
</span></span><span style="display:flex;"><span>book + shelf -&gt; bookshelf
</span></span><span style="display:flex;"><span>flash + light -&gt; flashlight
</span></span></code></pre></div><p>数据规模：</p>
<table>
  <thead>
      <tr>
          <th>Split</th>
          <th style="text-align: right">Count</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>train</td>
          <td style="text-align: right">20</td>
      </tr>
      <tr>
          <td>test</td>
          <td style="text-align: right">11</td>
      </tr>
      <tr>
          <td>OOD</td>
          <td style="text-align: right">6</td>
      </tr>
      <tr>
          <td>targets</td>
          <td style="text-align: right">37</td>
      </tr>
  </tbody>
</table>
<p>embedding 原始维度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>384D
</span></span></code></pre></div><p>固定随机正交投影到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>128D
</span></span></code></pre></div><p>这样和 TreeHeap 的 128D 方向一致。</p>
<h2 id="三个模型">三个模型</h2>
<h3 id="vector_add">vector_add</h3>
<p>最简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>y = normalize(left + right)
</span></span></code></pre></div><p>没有训练参数。</p>
<h3 id="concat_mlp">concat_mlp</h3>
<p>普通 MLP：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[left, right, left*right, abs(left-right)] -&gt; target
</span></span></code></pre></div><p>它有训练参数，会拟合训练集。</p>
<h3 id="treeheap_prob_vector_plus">treeheap_prob_vector_plus</h3>
<p>TreeHeap 版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H0 = Zero
</span></span><span style="display:flex;"><span>H1 = ProbVectorPlus(H0, left)
</span></span><span style="display:flex;"><span>H2 = ProbVectorPlus(H1, right)
</span></span><span style="display:flex;"><span>y  = Read(H2)
</span></span></code></pre></div><p>其中写入是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H&#39;[i] = H[i] + p_i · update(x)
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用概率路由把 128D word vector 写入 TreeHeap 节点。
</span></span></code></pre></div><h2 id="结果">结果</h2>
<p>结果如下：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Train cosine</th>
          <th style="text-align: right">Test cosine</th>
          <th style="text-align: right">OOD cosine</th>
          <th style="text-align: right">Test top1</th>
          <th style="text-align: right">OOD top1</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>vector_add</td>
          <td style="text-align: right">0.7117</td>
          <td style="text-align: right">0.7256</td>
          <td style="text-align: right">0.7198</td>
          <td style="text-align: right">0.909</td>
          <td style="text-align: right">0.833</td>
      </tr>
      <tr>
          <td>concat_mlp</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">0.6269</td>
          <td style="text-align: right">0.5766</td>
          <td style="text-align: right">0.000</td>
          <td style="text-align: right">0.000</td>
      </tr>
      <tr>
          <td>treeheap_prob_vector_plus</td>
          <td style="text-align: right">0.9999</td>
          <td style="text-align: right">0.5051</td>
          <td style="text-align: right">0.3919</td>
          <td style="text-align: right">0.000</td>
          <td style="text-align: right">0.000</td>
      </tr>
  </tbody>
</table>
<p>这个结果非常明确：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 没赢。
</span></span></code></pre></div><p>更准确地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 TreeHeap prob vector plus 过拟合训练集。
</span></span></code></pre></div><p>训练集上接近 1.0：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train cosine = 0.9999
</span></span></code></pre></div><p>但 OOD 很差：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>OOD cosine = 0.3919
</span></span><span style="display:flex;"><span>OOD top1 = 0.0
</span></span></code></pre></div><p>反而最简单的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>vector_add
</span></span></code></pre></div><p>表现最好：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>OOD cosine = 0.7198
</span></span><span style="display:flex;"><span>OOD top1 = 0.833
</span></span></code></pre></div><h2 id="claim-状态">Claim 状态</h2>
<p>所以这次结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-WM-C01 -&gt; rejected pilot
</span></span></code></pre></div><p>这个 rejected 很重要。</p>
<p>它说明我们不能说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只要把 TreeHeap 接到 embedding 坐标系，就自然有世界模型。
</span></span></code></pre></div><p>事实正好相反：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 unconstrained TreeHeap reader 太自由，
</span></span><span style="display:flex;"><span>会记住训练集，
</span></span><span style="display:flex;"><span>但没有学到可泛化的复合词结构。
</span></span></code></pre></div><h2 id="为什么-vector_add-会这么强">为什么 vector_add 会这么强？</h2>
<p>因为 frozen embedding 里已经包含大量语言共现和语义关系。</p>
<p>对很多复合词来说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left + right
</span></span></code></pre></div><p>本身就已经靠近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>target compound
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rain + coat
</span></span></code></pre></div><p>在 embedding 空间里天然接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>raincoat
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>外部 embedding 坐标系已经有强世界知识。
</span></span></code></pre></div><p>TreeHeap 如果只是用一个大 reader 去拟合它，很容易变成小数据过拟合。</p>
<p>这不是 TreeHeap 的优势区。</p>
<h2 id="这对下一步意味着什么">这对下一步意味着什么？</h2>
<p>下一步不要简单增加参数。</p>
<p>也不要把 reader 做得更大。</p>
<p>因为这会更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>小 MLP 记训练集。
</span></span></code></pre></div><p>下一步应该限制 TreeHeap，让结构真的参与计算。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 共享 family slot
</span></span><span style="display:flex;"><span>   ball / coat / book / light 这些右侧词应该形成可复用子结构。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>2. route entropy / collapse control
</span></span><span style="display:flex;"><span>   防止所有词都写到同一个节点。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>3. subheap reuse
</span></span><span style="display:flex;"><span>   foot+ball, basket+ball, hand+ball 应该共享 ball 子堆。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>4. copy/read pointer constraint
</span></span><span style="display:flex;"><span>   readout 不应该完全自由生成，而应该读取 TreeHeap 中的组合状态。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>5. 更强 baseline
</span></span><span style="display:flex;"><span>   vector_add 必须作为第一 baseline。
</span></span></code></pre></div><p>也就是说，下一版不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap + 更大 MLP。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap + 更强结构约束。
</span></span></code></pre></div><h2 id="这次仍然有价值吗">这次仍然有价值吗？</h2>
<p>有。</p>
<p>因为它告诉我们三件事。</p>
<p>第一：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>冻结 embedding 可以作为世界模型坐标尺。
</span></span></code></pre></div><p>第二：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>vector_add 是一个很强的 compound baseline。
</span></span></code></pre></div><p>第三：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 TreeHeap prob vector plus 还没有把结构优势用出来。
</span></span></code></pre></div><p>这比一个虚假的正结果更有用。</p>
<p>它把下一步的任务变清楚了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不是证明 TreeHeap 能拟合训练集。
</span></span><span style="display:flex;"><span>而是证明 TreeHeap 能利用地址、路径、子结构复用，
</span></span><span style="display:flex;"><span>在 OOD compound 上超过 vector_add。
</span></span></code></pre></div><h2 id="总结">总结</h2>
<p>这篇的结论是负面的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-WM-C01 rejected pilot。
</span></span></code></pre></div><p>但路线更清楚了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0 给了差分和学习接口。
</span></span><span style="display:flex;"><span>Frozen embedding 给了外部坐标尺。
</span></span><span style="display:flex;"><span>当前 TreeHeap encoder 没有泛化。
</span></span><span style="display:flex;"><span>下一步必须加入结构约束和 subheap reuse。
</span></span></code></pre></div><p>我们没有输给问题。</p>
<p>我们只是终于看清了问题站在哪里。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-029] 不再借外部向量：从本地共现语料训练坐标，再测 TreeHeap Kernel</title>
      <link>https://www.grepcode.cn/spr/029-local-corpus-coordinate-kernel.html</link>
      <pubDate>Thu, 25 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/029-local-corpus-coordinate-kernel.html</guid>
      <description>SPR-028 输给 vector_add，并不能 defeat TreeHeap，因为 frozen embedding 本来就是向量拓扑源。本文改用本地 SGNS 共现语料训练坐标，并测试结构化 TreeHeap kernel。</description>
      <content:encoded><![CDATA[<h1 id="不再借外部向量从本地共现语料训练坐标再测-treeheap-kernel">不再借外部向量：从本地共现语料训练坐标，再测 TreeHeap Kernel</h1>
<p><code>SPR-028</code> 的结果是负面的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>frozen all-MiniLM embedding 坐标系下，
</span></span><span style="display:flex;"><span>vector_add 明显强于 TreeHeap prob vector plus。
</span></span></code></pre></div><p>但 Houming818 指出一个关键问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这还不能 defeat TreeHeap。
</span></span></code></pre></div><p>原因是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>蒸馏源的数据本来就是 vector。
</span></span></code></pre></div><p>也就是说，<code>all-MiniLM-L6-v2</code> 已经把大量世界知识压进向量空间。</p>
<p>在这种空间里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left + right
</span></span></code></pre></div><p>天然可能靠近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compound target
</span></span></code></pre></div><p>所以 <code>vector_add</code> 赢，不奇怪。</p>
<p>这更像是在测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能不能追上一个已经很强的向量空间。
</span></span></code></pre></div><p>而不是测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能不能从语料共现中建立自己的坐标。
</span></span></code></pre></div><h2 id="新方案从语料共现训练小-embedding">新方案：从语料共现训练小 embedding</h2>
<p>这次改成 C 方案：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从本地小语料训练 embedding。
</span></span></code></pre></div><p>不使用预训练 embedding。</p>
<p>不使用外部模型坐标。</p>
<p>不使用 <code>all-MiniLM</code>。</p>
<p>坐标系来自我们自己的小语料：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>football means foot ball
</span></span><span style="display:flex;"><span>football uses foot and ball
</span></span><span style="display:flex;"><span>foot ball forms football
</span></span><span style="display:flex;"><span>football belongs to ball
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语料共现
</span></span><span style="display:flex;"><span>-&gt; SGNS / SkipGram negative sampling
</span></span><span style="display:flex;"><span>-&gt; 小型 128D embedding 坐标
</span></span></code></pre></div><p>这更接近我们真正关心的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数据中的共现信息，如何进入 TreeHeap？
</span></span></code></pre></div><h2 id="实验脚本">实验脚本</h2>
<p>脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/src/s1_corpus_embedding_kernel_probe.py
</span></span></code></pre></div><p>执行主机：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>io.grepcode.cn
</span></span></code></pre></div><p>证据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/evidence/s1_corpus_embedding_kernel_probe/
</span></span></code></pre></div><p>坐标来源：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>local SGNS corpus embedding
</span></span><span style="display:flex;"><span>external_model = false
</span></span><span style="display:flex;"><span>vocab_size = 85
</span></span><span style="display:flex;"><span>corpus_sentences = 888
</span></span><span style="display:flex;"><span>skipgram_pairs = 10448
</span></span></code></pre></div><p>这次不需要 <code>proxychains4</code>。</p>
<p>因为没有下载外部模型或语料。</p>
<h2 id="为什么-kernel-设计重要">为什么 kernel 设计重要？</h2>
<p>上一版 TreeHeap 的问题之一是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>reader 太自由。
</span></span></code></pre></div><p>它可以像一个普通 MLP 一样记训练集。</p>
<p>这不是真正的 TreeHeap 写入。</p>
<p>这次改成结构化 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left token  -&gt; left child
</span></span><span style="display:flex;"><span>right token -&gt; right child
</span></span><span style="display:flex;"><span>root        -&gt; compose kernel(left_child, right_child)
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H[left]  = WriteLeft(left_vector)
</span></span><span style="display:flex;"><span>H[right] = WriteRight(right_vector)
</span></span><span style="display:flex;"><span>H[root]  = Compose(H[left], H[right])
</span></span></code></pre></div><p>TreeHeap 结构强制参与计算。</p>
<p>不是把所有节点摊平给一个大 reader。</p>
<h2 id="对比模型">对比模型</h2>
<p>三个模型：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>vector_add</code></td>
          <td>直接 <code>normalize(left + right)</code></td>
      </tr>
      <tr>
          <td><code>concat_mlp</code></td>
          <td>普通 MLP，看 <code>[left, right, left*right, abs(left-right)]</code></td>
      </tr>
      <tr>
          <td><code>structured_treeheap_kernel</code></td>
          <td>左写入、右写入、root compose kernel</td>
      </tr>
  </tbody>
</table>
<h2 id="结果">结果</h2>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Train cosine</th>
          <th style="text-align: right">Test cosine</th>
          <th style="text-align: right">OOD cosine</th>
          <th style="text-align: right">OOD top1</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>vector_add</td>
          <td style="text-align: right">0.5705</td>
          <td style="text-align: right">0.5965</td>
          <td style="text-align: right">0.5785</td>
          <td style="text-align: right">0.000</td>
      </tr>
      <tr>
          <td>concat_mlp</td>
          <td style="text-align: right">0.9994</td>
          <td style="text-align: right">0.6957</td>
          <td style="text-align: right">0.7321</td>
          <td style="text-align: right">0.167</td>
      </tr>
      <tr>
          <td>structured_treeheap_kernel</td>
          <td style="text-align: right">0.9999</td>
          <td style="text-align: right">0.6801</td>
          <td style="text-align: right">0.7126</td>
          <td style="text-align: right">0.000</td>
      </tr>
  </tbody>
</table>
<p>这次结果比 <code>SPR-028</code> 明显不同。</p>
<p>在本地共现坐标系里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>vector_add 不再天然统治。
</span></span></code></pre></div><p>TreeHeap kernel 的 OOD cosine：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.7126
</span></span></code></pre></div><p>高于 vector_add：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.5785
</span></span></code></pre></div><p>并且接近 concat MLP：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.7321
</span></span></code></pre></div><p>所以这次 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-WM-C02 -&gt; supported pilot, narrow scope
</span></span></code></pre></div><h2 id="为什么说-narrow-scope">为什么说 narrow scope？</h2>
<p>因为 OOD top1 还没解决。</p>
<p>TreeHeap 的 OOD top1：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.000
</span></span></code></pre></div><p>concat MLP：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.167
</span></span></code></pre></div><p>也就是说，TreeHeap 的输出向量在平均 cosine 上更接近目标，但最近邻检索还没有稳定命中目标词。</p>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>坐标接近性有进展。
</span></span><span style="display:flex;"><span>离散概念坍缩还没完成。
</span></span></code></pre></div><p>这个区别很重要。</p>
<p>在 TreeHeap 语言里可以说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>概率场靠近了目标区域，
</span></span><span style="display:flex;"><span>但还没有稳定坍缩到目标点。
</span></span></code></pre></div><h2 id="这证明了什么">这证明了什么？</h2>
<p>这次支持三件事。</p>
<p>第一：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用本地语料共现训练坐标是可行的。
</span></span></code></pre></div><p>第二：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 设计会显著影响 TreeHeap 写入。
</span></span></code></pre></div><p>从自由 reader 改为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left child / right child / root compose
</span></span></code></pre></div><p>之后，TreeHeap 不再像 <code>SPR-028</code> 那样崩掉。</p>
<p>第三：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 在本地共现坐标上可以超过 vector_add 的 OOD cosine。
</span></span></code></pre></div><p>这说明不能用 <code>SPR-028</code> 直接否定 TreeHeap。</p>
<h2 id="这没有证明什么">这没有证明什么？</h2>
<p>边界也要说清楚。</p>
<p>这次没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经有完整世界模型。
</span></span><span style="display:flex;"><span>TreeHeap 已经能翻译。
</span></span><span style="display:flex;"><span>TreeHeap 击败 Transformer。
</span></span><span style="display:flex;"><span>TreeHeap 在 top1 检索上胜出。
</span></span></code></pre></div><p>它只是证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当坐标系来自本地共现语料，
</span></span><span style="display:flex;"><span>并且 TreeHeap kernel 被结构化约束后，
</span></span><span style="display:flex;"><span>TreeHeap 可以在 OOD cosine 上超过 vector_add。
</span></span></code></pre></div><p>这是一个小但重要的进展。</p>
<h2 id="下一步">下一步</h2>
<p>下一步不能只看 cosine。</p>
<p>要开始要求：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>top1
</span></span><span style="display:flex;"><span>MRR
</span></span><span style="display:flex;"><span>margin loss
</span></span><span style="display:flex;"><span>multi-seed
</span></span><span style="display:flex;"><span>corpus variants
</span></span></code></pre></div><p>尤其要加入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>nearest-neighbor margin loss
</span></span></code></pre></div><p>否则模型可能只是“靠近目标区域”，但没有“坍缩到目标点”。</p>
<p>下一版 kernel 应该加入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>family slots
</span></span><span style="display:flex;"><span>subheap reuse
</span></span><span style="display:flex;"><span>route collapse regularization
</span></span><span style="display:flex;"><span>explicit right-side shared kernel
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ball family:
</span></span><span style="display:flex;"><span>  football
</span></span><span style="display:flex;"><span>  basketball
</span></span><span style="display:flex;"><span>  baseball
</span></span><span style="display:flex;"><span>  handball
</span></span><span style="display:flex;"><span>  snowball
</span></span></code></pre></div><p>这些应该共享：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ball 子堆
</span></span></code></pre></div><p>这才是 TreeHeap 可能超过普通 MLP 的地方。</p>
<h2 id="总结">总结</h2>
<p><code>SPR-028</code> 告诉我们：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不能拿预训练向量空间里的 vector_add 输赢来直接判断 TreeHeap。
</span></span></code></pre></div><p><code>SPR-029</code> 告诉我们：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从本地语料共现训练坐标后，
</span></span><span style="display:flex;"><span>结构化 TreeHeap kernel 可以超过 vector_add 的 OOD cosine。
</span></span></code></pre></div><p>但下一关还在那里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从靠近目标区域，
</span></span><span style="display:flex;"><span>到稳定坍缩目标概念。
</span></span></code></pre></div><p>这就是下一轮 S1-WM 要打的点。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-030] 用 WMT 真语料做 Echo：先证明 TreeHeap Kernel 能写入真实 BPE 序列</title>
      <link>https://www.grepcode.cn/spr/030-wmt-echo-kernel.html</link>
      <pubDate>Thu, 25 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/030-wmt-echo-kernel.html</guid>
      <description>这次不直接做翻译，而是用 WMT 真语料做短序列 echo，验证 TreeHeap kernel 是否能把真实 SentencePiece token 写入树堆地址，再稳定读出。</description>
      <content:encoded><![CDATA[<h1 id="用-wmt-真语料做-echo先证明-treeheap-kernel-能写入真实-bpe-序列">用 WMT 真语料做 Echo：先证明 TreeHeap Kernel 能写入真实 BPE 序列</h1>
<p>这次我们回到 Houming818 一直强调的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 怎么把真实数据写进自己的高维结构？
</span></span></code></pre></div><p>如果连真实语料的 token 序列都不能稳定写入、读出，那么后面谈翻译、世界模型、概率坍缩都太早。</p>
<p>所以 <code>SPR-030</code> 不直接做 WMT 翻译。
它先做一个更低一级、但更必要的实验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>WMT 真语料
</span></span><span style="display:flex;"><span>-&gt; SentencePiece BPE token
</span></span><span style="display:flex;"><span>-&gt; TreeHeap kernel 写入
</span></span><span style="display:flex;"><span>-&gt; TreeHeap kernel 读出
</span></span><span style="display:flex;"><span>-&gt; 和原 token 序列比较
</span></span></code></pre></div><p>这叫 echo 实验。</p>
<p>它不是翻译。
它测试的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 是否能处理真实语料的离散 token 序列。
</span></span></code></pre></div><h2 id="为什么不是马上做翻译">为什么不是马上做翻译？</h2>
<p>翻译任务太复杂。</p>
<p>一句英文到一句中文，中间至少包含：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>词义
</span></span><span style="display:flex;"><span>语序
</span></span><span style="display:flex;"><span>短语结构
</span></span><span style="display:flex;"><span>跨语言对齐
</span></span><span style="display:flex;"><span>生成概率
</span></span><span style="display:flex;"><span>目标语言流畅性
</span></span></code></pre></div><p>如果直接上 WMT BLEU，结果不好时我们不知道问题在哪里。</p>
<p>可能是 encoder 不行。
可能是 decoder 不行。
可能是 kernel 不行。
可能是 loss 不行。
也可能只是训练规模太小。</p>
<p>所以这次先拆开：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第一步：真实 token 能不能写入 TreeHeap？
</span></span><span style="display:flex;"><span>第二步：写入后能不能读出来？
</span></span><span style="display:flex;"><span>第三步：结构化 kernel 是否比普通 flat 模型更适合这个问题？
</span></span></code></pre></div><p>这就是 S1 echo 的意义。</p>
<h2 id="数据来自哪里">数据来自哪里？</h2>
<p>实验使用 io 上的 WMT17 数据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>source file:
</span></span><span style="display:flex;"><span>/mnt/nas/datasets/wmt17/train.zh-en
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SentencePiece model:
</span></span><span style="display:flex;"><span>/mnt/nas/datasets/wmt17/sp_bpe.model
</span></span></code></pre></div><p>我们取英文侧文本，然后用 SentencePiece 切成 BPE token。</p>
<p>实验只取短序列：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token length = 3..8
</span></span><span style="display:flex;"><span>samples = 3000
</span></span><span style="display:flex;"><span>train/test/ood = 2400/300/300
</span></span><span style="display:flex;"><span>vocab limit including PAD = 2048
</span></span><span style="display:flex;"><span>average non-pad length = 5.9533
</span></span></code></pre></div><p>为什么先限制长度？</p>
<p>因为这次不是要证明长文本翻译。
这次要先验证最小写入机制：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个真实 BPE 序列，能不能被 TreeHeap 地址结构保存。
</span></span></code></pre></div><h2 id="echo-任务具体是什么">Echo 任务具体是什么？</h2>
<p>输入是一段 BPE token：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[t1, t2, t3, ...]
</span></span></code></pre></div><p>目标输出还是它自己：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[t1, t2, t3, ...]
</span></span></code></pre></div><p>这看起来很简单，但它能测出一个关键点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型是否保存了 token 的位置、顺序、地址。
</span></span></code></pre></div><p>如果模型只是知道句子里有哪些 token，但不知道顺序，就会失败。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[A, B, C]
</span></span></code></pre></div><p>和：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[C, B, A]
</span></span></code></pre></div><p>bag-of-words 看起来差不多，但 echo 必须区分它们。</p>
<p>所以 echo 不是语义任务，却是结构写入任务。</p>
<h2 id="三个模型对比">三个模型对比</h2>
<p>这次比较三个模型。</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>bow_linear</code></td>
          <td>只看 token 集合，不看顺序</td>
      </tr>
      <tr>
          <td><code>seq_mlp</code></td>
          <td>把固定位置拼平，交给普通 MLP</td>
      </tr>
      <tr>
          <td><code>treeheap_kernel_echo</code></td>
          <td>把 token 写到 TreeHeap 叶子地址，再用共享 kernel 自底向上 compose</td>
      </tr>
  </tbody>
</table>
<h3 id="1-bow_linear">1. bow_linear</h3>
<p><code>bow_linear</code> 看到的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个句子里出现过哪些 token
</span></span></code></pre></div><p>它不知道 token 在第几个位置。</p>
<p>所以它适合作为反例 baseline：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 BoW 也能做好 echo，那说明任务太简单。
</span></span></code></pre></div><h3 id="2-seq_mlp">2. seq_mlp</h3>
<p><code>seq_mlp</code> 是普通 flat MLP。</p>
<p>它看到的是固定位置展开后的向量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>position 1 token
</span></span><span style="display:flex;"><span>position 2 token
</span></span><span style="display:flex;"><span>position 3 token
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>它有顺序信息。
但它没有显式树地址、子结构、compose kernel。</p>
<p>可以理解为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把序列压平成一张大表，然后学习 input -&gt; output。
</span></span></code></pre></div><h3 id="3-treeheap_kernel_echo">3. treeheap_kernel_echo</h3>
<p>TreeHeap 模型做的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token id -&gt; shared token embedding
</span></span><span style="display:flex;"><span>position -&gt; fixed heap leaf address
</span></span><span style="display:flex;"><span>internal nodes -&gt; shared bottom-up compose kernel
</span></span><span style="display:flex;"><span>leaf readout -&gt; shared decoder
</span></span></code></pre></div><p>换成人话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>每个 token 先写到树堆的一个叶子地址上。
</span></span><span style="display:flex;"><span>然后树里的父节点用同一个 compose kernel 汇总左右孩子。
</span></span><span style="display:flex;"><span>最后从叶子状态读回 token。
</span></span></code></pre></div><p>关键点是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型必须利用 TreeHeap 的地址结构。
</span></span></code></pre></div><p>它不是把整个句子拼成一个大向量随便读。
它被迫经过：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>叶子地址
</span></span><span style="display:flex;"><span>子结构
</span></span><span style="display:flex;"><span>自底向上 compose
</span></span><span style="display:flex;"><span>共享 decoder
</span></span></code></pre></div><p>这就是 kernel 设计的意义。</p>
<h2 id="实验结果">实验结果</h2>
<p>脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/src/s1_wmt_echo_kernel_probe.py
</span></span></code></pre></div><p>证据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/evidence/s1_wmt_echo_kernel_probe/
</span></span></code></pre></div><p>执行主机：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>io.grepcode.cn
</span></span></code></pre></div><p>结果如下：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Params</th>
          <th style="text-align: right">Test token</th>
          <th style="text-align: right">Test exact</th>
          <th style="text-align: right">OOD token</th>
          <th style="text-align: right">OOD exact</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>bow_linear</code></td>
          <td style="text-align: right">33,570,816</td>
          <td style="text-align: right">0.1679</td>
          <td style="text-align: right">0.0033</td>
          <td style="text-align: right">0.1659</td>
          <td style="text-align: right">0.0033</td>
      </tr>
      <tr>
          <td><code>seq_mlp</code></td>
          <td style="text-align: right">16,794,112</td>
          <td style="text-align: right">0.5801</td>
          <td style="text-align: right">0.0567</td>
          <td style="text-align: right">0.5986</td>
          <td style="text-align: right">0.0533</td>
      </tr>
      <tr>
          <td><code>treeheap_kernel_echo</code></td>
          <td style="text-align: right">423,104</td>
          <td style="text-align: right">0.9818</td>
          <td style="text-align: right">0.8900</td>
          <td style="text-align: right">0.9818</td>
          <td style="text-align: right">0.9000</td>
      </tr>
  </tbody>
</table>
<p>这里有两个指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token accuracy:
</span></span><span style="display:flex;"><span>  每个位置的 token 是否预测正确。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>exact:
</span></span><span style="display:flex;"><span>  整个序列是否完全预测正确。
</span></span></code></pre></div><p>exact 更严格。
只要一个位置错了，整个序列就算错。</p>
<h2 id="结果说明什么">结果说明什么？</h2>
<p>第一，BoW 几乎失败。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>OOD exact = 0.0033
</span></span></code></pre></div><p>这说明任务不是只靠 token 集合就能完成。
顺序和地址确实重要。</p>
<p>第二，flat MLP 训练集可以学会，但 OOD 很差。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>seq_mlp OOD exact = 0.0533
</span></span></code></pre></div><p>它有 16,794,112 个参数，比 TreeHeap 多很多。
但它在新样本上不能稳定复制完整序列。</p>
<p>第三，TreeHeap kernel 表现明显更好。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>treeheap_kernel_echo OOD token = 0.9818
</span></span><span style="display:flex;"><span>treeheap_kernel_echo OOD exact = 0.9000
</span></span></code></pre></div><p>而且参数更少：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap params = 423,104
</span></span><span style="display:flex;"><span>seq_mlp params  = 16,794,112
</span></span></code></pre></div><p>大约是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 参数量约为 seq_mlp 的 2.5%
</span></span></code></pre></div><p>这支持一个小 claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在真实 WMT 短 BPE echo 任务上，
</span></span><span style="display:flex;"><span>TreeHeap kernel 可以更有效地利用地址和路径结构。
</span></span></code></pre></div><h2 id="这和-kernel-设计有什么关系">这和 kernel 设计有什么关系？</h2>
<p>前面我们反复讨论：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的核心操作不是普通矩阵拼接，
</span></span><span style="display:flex;"><span>而是 kernel 在树结构上的卷积。
</span></span></code></pre></div><p>这次实验里的 kernel 很朴素：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf write kernel:
</span></span><span style="display:flex;"><span>  把 token embedding 写到固定叶子地址。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>compose kernel:
</span></span><span style="display:flex;"><span>  对每个内部节点，用同一个函数合并 left/right child。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>read kernel:
</span></span><span style="display:flex;"><span>  从叶子状态预测原 token。
</span></span></code></pre></div><p>它像一维 CNN 里的卷积核，但滑动对象不是平面像素，而是 TreeHeap 子结构。</p>
<p>CNN 的 3x3 kernel 看局部像素。
TreeHeap kernel 看局部树堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>parent
</span></span><span style="display:flex;"><span>├── left child
</span></span><span style="display:flex;"><span>└── right child
</span></span></code></pre></div><p>所以它天然带着：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>地址
</span></span><span style="display:flex;"><span>路径
</span></span><span style="display:flex;"><span>子结构
</span></span><span style="display:flex;"><span>组合
</span></span><span style="display:flex;"><span>分解
</span></span></code></pre></div><p>这些信息。</p>
<p>这正是 flat MLP 没有显式拥有的归纳偏置。</p>
<h2 id="这次-claim-是什么">这次 claim 是什么？</h2>
<p>ARA 里记录为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-WMT-ECHO-C01
</span></span></code></pre></div><p>claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A structured TreeHeap kernel can write and read real WMT SentencePiece short
</span></span><span style="display:flex;"><span>sequences in an echo setting, using tree addresses and shared compose/read
</span></span><span style="display:flex;"><span>kernels rather than only a flat memorization map.
</span></span></code></pre></div><p>状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>supported pilot
</span></span></code></pre></div><p>用中文说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>结构化 TreeHeap kernel 能在真实 WMT 短 BPE 序列上完成写入和读出。
</span></span><span style="display:flex;"><span>这个结果支持 TreeHeap 的地址/路径结构是有用的。
</span></span></code></pre></div><h2 id="这没有证明什么">这没有证明什么？</h2>
<p>边界要说清楚。</p>
<p>这次没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经会翻译。
</span></span><span style="display:flex;"><span>TreeHeap 已经有语义世界模型。
</span></span><span style="display:flex;"><span>TreeHeap 已经能压缩长文本。
</span></span><span style="display:flex;"><span>TreeHeap 已经解决长距离句法。
</span></span><span style="display:flex;"><span>TreeHeap 已经击败 Transformer。
</span></span></code></pre></div><p>它只证明一件更基础的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实 WMT token 可以被 TreeHeap kernel 稳定写入和读出。
</span></span></code></pre></div><p>这对 S1 是有意义的。
但离 S2/S3 还有距离。</p>
<h2 id="下一步怎么做">下一步怎么做？</h2>
<p>下一步不是立刻喊胜利。
应该继续加难度。</p>
<h3 id="1-更长序列">1. 更长序列</h3>
<p>现在是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>length = 3..8
</span></span></code></pre></div><p>下一步要测：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>length = 8..16
</span></span><span style="display:flex;"><span>length = 16..32
</span></span></code></pre></div><p>如果长度一长就崩，说明 TreeHeap kernel 还只是短序列技巧。</p>
<h3 id="2-噪声-echo">2. 噪声 echo</h3>
<p>普通 echo 是原样复制。</p>
<p>下一步可以做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mask 一个 token，让模型恢复。
</span></span><span style="display:flex;"><span>drop 一个 token，让模型恢复。
</span></span><span style="display:flex;"><span>swap 两个 token，让模型判断并修正。
</span></span></code></pre></div><p>这开始接近推理。</p>
<p>因为模型不能只照抄，它必须利用上下文。</p>
<h3 id="3-subheap-query">3. subheap query</h3>
<p>不要总是读整个句子。
可以问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>读左子树。
</span></span><span style="display:flex;"><span>读右子树。
</span></span><span style="display:flex;"><span>读某个短语窗口。
</span></span><span style="display:flex;"><span>读某条路径下的 token。
</span></span></code></pre></div><p>这能测试 TreeHeap 的子结构是否真的可查询。</p>
<h3 id="4-更公平的-baseline">4. 更公平的 baseline</h3>
<p>这次的 <code>seq_mlp</code> 不是最强序列模型。</p>
<p>下一步要加：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pointer/copy baseline
</span></span><span style="display:flex;"><span>small Transformer
</span></span><span style="display:flex;"><span>tiny RNN/GRU
</span></span><span style="display:flex;"><span>matched parameter sequence model
</span></span></code></pre></div><p>如果这些模型在相同参数和数据预算下追上 TreeHeap，那么 claim 要收缩。</p>
<h2 id="总结">总结</h2>
<p><code>SPR-030</code> 的结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>可以用 WMT 真语料做 echo。
</span></span><span style="display:flex;"><span>TreeHeap kernel 在短 BPE 序列写入/读出上表现很好。
</span></span><span style="display:flex;"><span>它用更少参数，明显超过 BoW 和 flat seq MLP。
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 设计是关键。
</span></span></code></pre></div><p>TreeHeap 的存在性不能只靠抽象代数。
它必须在具体任务上显示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>地址有用。
</span></span><span style="display:flex;"><span>路径有用。
</span></span><span style="display:flex;"><span>子结构有用。
</span></span><span style="display:flex;"><span>组合/分解有用。
</span></span></code></pre></div><p>这次只是第一块真实语料证据。
下一步要从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>短序列 echo
</span></span></code></pre></div><p>推进到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>长序列 echo
</span></span><span style="display:flex;"><span>噪声恢复
</span></span><span style="display:flex;"><span>subheap query
</span></span><span style="display:flex;"><span>copy/pointer baseline battle
</span></span></code></pre></div><p>如果这些也成立，S1 才能更稳地往 S2 翻译折叠推进。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-031] Multi-Kernel 会自然分工吗：一次 WMT 扰动任务的混合结果</title>
      <link>https://www.grepcode.cn/spr/031-multikernel-specialization.html</link>
      <pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/031-multikernel-specialization.html</guid>
      <description>这次实验测试 TreeHeap kernel bank 是否会像 Transformer multi-head 一样，在结构扰动任务下形成不同功能。结果是：分化信号出现了，但任务能力还没过关。</description>
      <content:encoded><![CDATA[<h1 id="multi-kernel-会自然分工吗一次-wmt-扰动任务的混合结果">Multi-Kernel 会自然分工吗：一次 WMT 扰动任务的混合结果</h1>
<p>这篇记录一个比较关键、但不能夸大的结果。</p>
<p>我们想验证的问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的多个 kernel，会不会像 Transformer 的 multi-head 一样，
</span></span><span style="display:flex;"><span>在训练中自然分化成不同功能？
</span></span></code></pre></div><p>结论先说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>有分化信号，但还不是成功证明。
</span></span></code></pre></div><p>更准确地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不同结构任务确实选择了不同 kernel。
</span></span><span style="display:flex;"><span>删除某些 kernel 会明显伤害对应任务。
</span></span><span style="display:flex;"><span>但整体任务准确率仍然低，multi-kernel 对 single-kernel 的提升还不够。
</span></span></code></pre></div><p>所以 ARA 结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-MK-C01 -&gt; open / mixed pilot
</span></span></code></pre></div><h2 id="为什么要做这个实验">为什么要做这个实验？</h2>
<p>Transformer 的 multi-head attention 并不是手工规定：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>head_1 = 主语
</span></span><span style="display:flex;"><span>head_2 = 宾语
</span></span><span style="display:flex;"><span>head_3 = 长距离依存
</span></span></code></pre></div><p>而是多个 head 具有不同参数、不同初始化、不同梯度路径。
训练任务给它们压力，它们可能分化，也可能冗余。</p>
<p>TreeHeap 也应该这样看。</p>
<p>我们不应该手工说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K0 = echo kernel
</span></span><span style="display:flex;"><span>K1 = mask kernel
</span></span><span style="display:flex;"><span>K2 = mirror kernel
</span></span></code></pre></div><p>而应该给它一个 kernel bank：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K0, K1, K2, K3
</span></span></code></pre></div><p>然后观察训练以后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不同任务是否自然偏向不同 kernel？
</span></span><span style="display:flex;"><span>删除某个 kernel 是否会让某类任务明显变差？
</span></span></code></pre></div><h2 id="实验数据">实验数据</h2>
<p>数据是真实 WMT17 英文侧文本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/mnt/nas/datasets/wmt17/train.zh-en
</span></span></code></pre></div><p>切词使用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/mnt/nas/datasets/wmt17/sp_bpe.model
</span></span></code></pre></div><p>样本设置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>samples = 4000
</span></span><span style="display:flex;"><span>train/test/ood = 3200/400/400
</span></span><span style="display:flex;"><span>token length = 4..8
</span></span></code></pre></div><p>注意，这还不是翻译任务。</p>
<p>它是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实语料 token
</span></span><span style="display:flex;"><span>+ 人工结构扰动任务
</span></span></code></pre></div><p>这样做的原因是：我们现在要测 kernel 分化，不是 BLEU。
如果直接做翻译，错误来源太多，无法判断 kernel 是否真的在分工。</p>
<h2 id="五个结构任务">五个结构任务</h2>
<p>这次不是普通 echo，而是五种任务：</p>
<table>
  <thead>
      <tr>
          <th>Task</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>echo</code></td>
          <td>原样重建序列</td>
      </tr>
      <tr>
          <td><code>mask_restore</code></td>
          <td>mask 一个 token 后重建原序列</td>
      </tr>
      <tr>
          <td><code>left_query</code></td>
          <td>读取左子堆</td>
      </tr>
      <tr>
          <td><code>right_query</code></td>
          <td>读取右子堆</td>
      </tr>
      <tr>
          <td><code>mirror</code></td>
          <td>输出反转序列</td>
      </tr>
  </tbody>
</table>
<p>这些任务分别给 kernel 不同压力。</p>
<p><code>echo</code> 要求保存地址和顺序。</p>
<p><code>mask_restore</code> 要求利用上下文，不只是照抄。</p>
<p><code>left_query</code> / <code>right_query</code> 要求模型知道左右子结构。</p>
<p><code>mirror</code> 要求模型学习一种翻转/共轭操作。</p>
<h2 id="模型结构">模型结构</h2>
<p>TreeHeap 模型大致是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token id
</span></span><span style="display:flex;"><span>-&gt; leaf embedding
</span></span><span style="display:flex;"><span>-&gt; 写入 complete binary heap leaves
</span></span><span style="display:flex;"><span>-&gt; internal node = kernel(left_child, right_child)
</span></span><span style="display:flex;"><span>-&gt; task query 产生 gate
</span></span><span style="display:flex;"><span>-&gt; gate 选择/混合多个 kernel
</span></span><span style="display:flex;"><span>-&gt; decoder 输出目标 token
</span></span></code></pre></div><p>single-kernel 只有一个 compose kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K
</span></span></code></pre></div><p>multi-kernel 有四个：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K0, K1, K2, K3
</span></span></code></pre></div><p>每个内部节点都可以由多个 kernel 生成候选结果，再由 gate 混合：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>h_parent = sum_k gate_k(task) * K_k(h_left, h_right)
</span></span></code></pre></div><p>这就是 TreeHeap 版 multi-head 的最小类比。</p>
<h2 id="怎么判断是否分化">怎么判断是否分化？</h2>
<p>看两件事。</p>
<p>第一，看 gate。</p>
<p>如果所有任务都选同一个 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>echo -&gt; K0
</span></span><span style="display:flex;"><span>mask -&gt; K0
</span></span><span style="display:flex;"><span>left -&gt; K0
</span></span><span style="display:flex;"><span>right -&gt; K0
</span></span><span style="display:flex;"><span>mirror -&gt; K0
</span></span></code></pre></div><p>那就是没有分化。</p>
<p>如果不同任务选不同 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left -&gt; K0
</span></span><span style="display:flex;"><span>right -&gt; K3
</span></span><span style="display:flex;"><span>mirror -&gt; K2
</span></span></code></pre></div><p>这就是分化信号。</p>
<p>第二，看 ablation。</p>
<p>也就是删除某个 kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>drop K3
</span></span></code></pre></div><p>如果删除后 <code>right_query</code> 大幅下降，而其他任务不怎么变，那说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K3 确实承担了 right_query 功能。
</span></span></code></pre></div><p>这比只看 gate 更可靠。</p>
<h2 id="run-a完整词表版本">Run A：完整词表版本</h2>
<p>第一版使用较大的词表：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>vocab limit including PAD/MASK = 2049
</span></span><span style="display:flex;"><span>epochs = 28
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Params</th>
          <th style="text-align: right">OOD mean exact</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>single_kernel_treeheap</code></td>
          <td style="text-align: right">4,641,545</td>
          <td style="text-align: right">0.0495</td>
      </tr>
      <tr>
          <td><code>multi_kernel_treeheap</code></td>
          <td style="text-align: right">4,938,764</td>
          <td style="text-align: right">0.0600</td>
      </tr>
  </tbody>
</table>
<p>multi-kernel 稍微更好：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.0600 - 0.0495 = 0.0105
</span></span></code></pre></div><p>但这个提升很小。</p>
<p>分化信号：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>echo         -&gt; K2
</span></span><span style="display:flex;"><span>mask_restore -&gt; K1
</span></span><span style="display:flex;"><span>left_query   -&gt; K3
</span></span><span style="display:flex;"><span>right_query  -&gt; K3
</span></span><span style="display:flex;"><span>mirror       -&gt; K0
</span></span></code></pre></div><p>四个 kernel 都被使用了。</p>
<p>最大 ablation drop：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.1100
</span></span></code></pre></div><p>说明删除某个 kernel 后，某类任务确实会掉。</p>
<p>但是整体 exact 太低，所以不能算成功。</p>
<h2 id="run-b常用-token-版本">Run B：常用 token 版本</h2>
<p>第二版把词表压到更常用的 token：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>vocab limit including PAD/MASK = 513
</span></span><span style="display:flex;"><span>epochs = 60
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Params</th>
          <th style="text-align: right">OOD mean exact</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>single_kernel_treeheap</code></td>
          <td style="text-align: right">1,286,921</td>
          <td style="text-align: right">0.1275</td>
      </tr>
      <tr>
          <td><code>multi_kernel_treeheap</code></td>
          <td style="text-align: right">1,584,140</td>
          <td style="text-align: right">0.1420</td>
      </tr>
  </tbody>
</table>
<p>multi-kernel 仍然更好：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.1420 - 0.1275 = 0.0145
</span></span></code></pre></div><p>但仍然只是小幅提升。</p>
<p>各任务 OOD exact：</p>
<table>
  <thead>
      <tr>
          <th>Task</th>
          <th style="text-align: right">Single</th>
          <th style="text-align: right">Multi</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>echo</code></td>
          <td style="text-align: right">0.0300</td>
          <td style="text-align: right">0.0375</td>
      </tr>
      <tr>
          <td><code>mask_restore</code></td>
          <td style="text-align: right">0.0050</td>
          <td style="text-align: right">0.0025</td>
      </tr>
      <tr>
          <td><code>left_query</code></td>
          <td style="text-align: right">0.1475</td>
          <td style="text-align: right">0.1775</td>
      </tr>
      <tr>
          <td><code>right_query</code></td>
          <td style="text-align: right">0.4525</td>
          <td style="text-align: right">0.4925</td>
      </tr>
      <tr>
          <td><code>mirror</code></td>
          <td style="text-align: right">0.0025</td>
          <td style="text-align: right">0.0000</td>
      </tr>
  </tbody>
</table>
<p>这里最有价值的是 subheap query。</p>
<p><code>left_query</code> 和 <code>right_query</code> 都提升了。</p>
<p>分化信号更清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>echo         -&gt; K0
</span></span><span style="display:flex;"><span>mask_restore -&gt; K1
</span></span><span style="display:flex;"><span>left_query   -&gt; K0
</span></span><span style="display:flex;"><span>right_query  -&gt; K3
</span></span><span style="display:flex;"><span>mirror       -&gt; K2
</span></span></code></pre></div><p>删除 kernel 的影响也更清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>drop K0:
</span></span><span style="display:flex;"><span>  left_query exact drop = 0.1775
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>drop K3:
</span></span><span style="display:flex;"><span>  right_query exact drop = 0.3050
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K0 对 left_query 很重要。
</span></span><span style="display:flex;"><span>K3 对 right_query 很重要。
</span></span></code></pre></div><p>这是目前最像“kernel 分工”的证据。</p>
<h2 id="为什么仍然不是-supported">为什么仍然不是 supported？</h2>
<p>因为 ARA 不能只看好看的部分。</p>
<p>这次 pass gate 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>multi OOD mean exact - single OOD mean exact &gt;= 0.05
</span></span><span style="display:flex;"><span>multi OOD mean exact &gt;= 0.65
</span></span><span style="display:flex;"><span>至少两个 task argmax kernel 被使用
</span></span><span style="display:flex;"><span>max ablation exact drop &gt;= 0.10
</span></span></code></pre></div><p>实际结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>multi 提升: 0.0105 / 0.0145
</span></span><span style="display:flex;"><span>multi OOD mean exact: 0.0600 / 0.1420
</span></span><span style="display:flex;"><span>unique kernels: 4
</span></span><span style="display:flex;"><span>max ablation drop: 0.1100 / 0.3050
</span></span></code></pre></div><p>所以：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>分化指标过了。
</span></span><span style="display:flex;"><span>能力指标没过。
</span></span></code></pre></div><p>因此结论只能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>open / mixed pilot
</span></span></code></pre></div><h2 id="这次真正学到了什么">这次真正学到了什么？</h2>
<p>第一，结构扰动确实会推动 kernel 分化。</p>
<p>尤其是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left_query
</span></span><span style="display:flex;"><span>right_query
</span></span><span style="display:flex;"><span>mirror
</span></span></code></pre></div><p>这些任务给出了不同梯度压力。</p>
<p>第二，现在的 root bottleneck 设计不够好。</p>
<p>这次模型让一个 root/subheap state 去读出整个序列。
这对 echo、mask、mirror 很难。</p>
<p>用一句话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 有分化迹象，但 decoder/readout 结构拖了后腿。
</span></span></code></pre></div><p>第三，echo 绝对准确不是 multi-kernel 分化的充分条件。</p>
<p><code>SPR-030</code> 的 echo 做得很好，是因为它从 leaf state 读回 token。</p>
<p>这次为了测 subheap/mirror/mask，把读出压到 root/subheap state。
这暴露了一个新问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 需要 path-conditioned read kernel，
</span></span><span style="display:flex;"><span>不能只靠一个 root vector 承担所有读出。
</span></span></code></pre></div><h2 id="下一步">下一步</h2>
<p>下一步不要盲目加 kernel 数量。</p>
<p>应该改读出方式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>selected node
</span></span><span style="display:flex;"><span>+ target path query
</span></span><span style="display:flex;"><span>-&gt; read kernel
</span></span><span style="display:flex;"><span>-&gt; token
</span></span></code></pre></div><p>也就是说，读出时也要做卷积/路径查询，而不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root vector -&gt; 一次性吐出全序列
</span></span></code></pre></div><p>下一版实验应该围绕：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>path-conditioned read kernel
</span></span><span style="display:flex;"><span>subheap query
</span></span><span style="display:flex;"><span>mask restore
</span></span><span style="display:flex;"><span>mirror
</span></span><span style="display:flex;"><span>matched flat MLP baseline
</span></span><span style="display:flex;"><span>small Transformer baseline
</span></span><span style="display:flex;"><span>kernel dropout
</span></span></code></pre></div><p>还要测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>没有显式 task label 时，kernel 是否仍然分化。
</span></span></code></pre></div><p>因为这次 gate 使用了 task query。
这合理，但还不够自然。</p>
<h2 id="总结">总结</h2>
<p><code>SPR-031</code> 没有证明 TreeHeap multi-kernel 已经成功。</p>
<p>它证明的是更细的一点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>结构扰动任务确实能诱导 kernel bank 出现任务相关分化。
</span></span></code></pre></div><p>但同时也暴露：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前读出结构太粗糙。
</span></span><span style="display:flex;"><span>完整任务能力还不足。
</span></span></code></pre></div><p>这就是这次最重要的进展：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们不再只问“能不能 echo”，
</span></span><span style="display:flex;"><span>而开始问“kernel 是否真的分工，以及为什么分工后还不够强”。
</span></span></code></pre></div><p>下一步应该围绕：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>path-conditioned read kernel
</span></span></code></pre></div><p>继续推进。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-032] TreeHeap 的概率读取核：从 arr[1] 开始的 stop/left/right 坍缩</title>
      <link>https://www.grepcode.cn/spr/032-probabilistic-read-kernel.html</link>
      <pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/032-probabilistic-read-kernel.html</guid>
      <description>这篇记录 SPR-032：把 TreeHeap read 从 root bottleneck 改成 query-conditioned probabilistic read kernel。实验说明路径坍缩和叶子读取成立，但内部子堆摘要还没解决。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-的概率读取核从-arr1-开始的-stopleftright-坍缩">TreeHeap 的概率读取核：从 arr[1] 开始的 stop/left/right 坍缩</h1>
<p>SPR-031 的结论里有一个明显问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们让 root/subheap state 一次性吐出答案。
</span></span></code></pre></div><p>这会形成 root bottleneck。</p>
<p>如果答案在左子树、右子树、某个叶子，或者某个内部子堆里，那么更自然的做法不是让 root 背下所有东西，而是从 root 开始读取：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[1]
</span></span><span style="display:flex;"><span>  -&gt; stop
</span></span><span style="display:flex;"><span>  -&gt; left
</span></span><span style="display:flex;"><span>  -&gt; right
</span></span></code></pre></div><p>每一步都由一个 kernel 决定。</p>
<p>所以 SPR-032 的问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap read 能不能写成一个概率路径坍缩过程？
</span></span></code></pre></div><p>结论先说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径坍缩成立。
</span></span><span style="display:flex;"><span>叶子读取几乎成立。
</span></span><span style="display:flex;"><span>内部子堆摘要还没成立。
</span></span></code></pre></div><p>ARA 状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-READ-C01 -&gt; open / mixed pilot
</span></span></code></pre></div><h2 id="什么叫-read-kernel">什么叫 read kernel？</h2>
<p>我们先把 TreeHeap 当成一个数组堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[1] = root
</span></span><span style="display:flex;"><span>arr[2] = left(root)
</span></span><span style="display:flex;"><span>arr[3] = right(root)
</span></span><span style="display:flex;"><span>arr[4] = left(left(root))
</span></span><span style="display:flex;"><span>arr[5] = right(left(root))
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>一个读取核可以写成：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">K_{read}(q, h_i, p_i) \rightarrow P(stop), P(left), P(right)
</code></pre><p>含义是：</p>
<ul>
<li><code>q</code>：这次要读什么，也就是 query。</li>
<li><code>h_i</code>：当前节点的 TreeHeap state。</li>
<li><code>p_i</code>：当前节点的路径/地址信息。</li>
<li>输出：在当前节点停止、走左边、走右边的概率。</li>
</ul>
<p>如果输出是硬选择，就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>while true:
</span></span><span style="display:flex;"><span>    action = K_read(query, current_node)
</span></span><span style="display:flex;"><span>    if action == stop:
</span></span><span style="display:flex;"><span>        return current_node_state
</span></span><span style="display:flex;"><span>    if action == left:
</span></span><span style="display:flex;"><span>        current_node = current_node.left
</span></span><span style="display:flex;"><span>    if action == right:
</span></span><span style="display:flex;"><span>        current_node = current_node.right
</span></span></code></pre></div><p>这就是尾递归，也可以直接写成循环。</p>
<p>如果输出是概率，就不是只走一条路，而是维护一个 frontier：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root mass = 1.0
</span></span><span style="display:flex;"><span>每一层：
</span></span><span style="display:flex;"><span>  一部分概率 stop 到当前节点
</span></span><span style="display:flex;"><span>  一部分概率流向 left
</span></span><span style="display:flex;"><span>  一部分概率流向 right
</span></span><span style="display:flex;"><span>最后把所有 stop 的状态加权求和
</span></span></code></pre></div><p>这就是 soft read。</p>
<h2 id="stop-不是空操作">stop 不是空操作</h2>
<p>你之前说的这个例子很关键：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root_left_right = [stop_0.5, left_0.3, right_0.2]
</span></span></code></pre></div><p>这里 <code>stop</code> 不是“什么也不做”。</p>
<p>它的意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>就在当前节点读取。
</span></span></code></pre></div><p>如果当前节点是叶子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop -&gt; 读一个 token
</span></span></code></pre></div><p>如果当前节点是内部节点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop -&gt; 读一个子堆摘要
</span></span></code></pre></div><p>所以 TreeHeap 不是 B+ 树那种“只有叶子有数据”的结构。TreeHeap 的内部节点也应该有意义。</p>
<p>这次实验专门把内部 stop 做成可测量目标。</p>
<h2 id="实验怎么做">实验怎么做？</h2>
<p>数据来自真实 WMT17 英文侧文本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/mnt/nas/datasets/wmt17/train.zh-en
</span></span></code></pre></div><p>切词模型：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/mnt/nas/datasets/wmt17/sp_bpe.model
</span></span></code></pre></div><p>样本设置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>samples = 3000
</span></span><span style="display:flex;"><span>train/test/ood = 2400/300/300
</span></span><span style="display:flex;"><span>token length = 4..8
</span></span><span style="display:flex;"><span>vocab limit = 513
</span></span></code></pre></div><p>我们把一个短 BPE 序列写入 8 个叶子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tokens = [t0, t1, t2, t3, ...]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>arr[8]  = t0
</span></span><span style="display:flex;"><span>arr[9]  = t1
</span></span><span style="display:flex;"><span>arr[10] = t2
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>然后随机给一个 query node。</p>
<p>如果 query 是叶子，比如 <code>arr[10]</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>目标 = 这个叶子的 token id
</span></span></code></pre></div><p>如果 query 是内部节点，比如 <code>arr[2]</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>目标 = arr[2] 覆盖的子堆 span 的 checksum bucket
</span></span></code></pre></div><p>checksum 是一个玩具摘要。它不是语言语义，只是为了让内部 stop 有一个明确答案。</p>
<p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>叶子 stop     -&gt; 复制 token
</span></span><span style="display:flex;"><span>内部节点 stop -&gt; 输出子堆摘要
</span></span></code></pre></div><h2 id="两个模型">两个模型</h2>
<p>第一个是 root baseline：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root_query_decoder:
</span></span><span style="display:flex;"><span>  TreeEncoder(tokens) -&gt; root state
</span></span><span style="display:flex;"><span>  root state + query node id -&gt; answer
</span></span></code></pre></div><p>它必须从 root state 里猜所有答案。</p>
<p>第二个是概率读取核：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>probabilistic_read_kernel:
</span></span><span style="display:flex;"><span>  TreeEncoder(tokens) -&gt; all node states
</span></span><span style="display:flex;"><span>  q + current node + path -&gt; stop/left/right
</span></span><span style="display:flex;"><span>  stop 后再 readout answer
</span></span></code></pre></div><p>它不是让 root 背下所有答案，而是根据 query 走到目标节点。</p>
<h2 id="run-a128-个内部摘要桶">Run A：128 个内部摘要桶</h2>
<p>设置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>checksum_buckets = 128
</span></span><span style="display:flex;"><span>epochs = 40
</span></span><span style="display:flex;"><span>labels = 641
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Params</th>
          <th style="text-align: right">OOD acc</th>
          <th style="text-align: right">OOD internal</th>
          <th style="text-align: right">OOD leaf</th>
          <th style="text-align: right">Route acc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>root_query_decoder</code></td>
          <td style="text-align: right">398,209</td>
          <td style="text-align: right">0.0638</td>
          <td style="text-align: right">0.0205</td>
          <td style="text-align: right">0.1066</td>
          <td style="text-align: right">n/a</td>
      </tr>
      <tr>
          <td><code>probabilistic_read_kernel</code></td>
          <td style="text-align: right">499,588</td>
          <td style="text-align: right">0.6124</td>
          <td style="text-align: right">0.2214</td>
          <td style="text-align: right">0.9989</td>
          <td style="text-align: right">1.0000</td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>read kernel 比 root bottleneck 强很多。
</span></span><span style="display:flex;"><span>路径路由完全学会了。
</span></span><span style="display:flex;"><span>叶子 token 几乎完全读对。
</span></span><span style="display:flex;"><span>内部摘要仍然很弱。
</span></span></code></pre></div><h2 id="run-b32-个内部摘要桶">Run B：32 个内部摘要桶</h2>
<p>为了判断是不是摘要桶太难，我们把 checksum 从 128 桶降到 32 桶：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>checksum_buckets = 32
</span></span><span style="display:flex;"><span>epochs = 80
</span></span><span style="display:flex;"><span>labels = 545
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Params</th>
          <th style="text-align: right">OOD acc</th>
          <th style="text-align: right">OOD internal</th>
          <th style="text-align: right">OOD leaf</th>
          <th style="text-align: right">Route acc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>root_query_decoder</code></td>
          <td style="text-align: right">373,537</td>
          <td style="text-align: right">0.1184</td>
          <td style="text-align: right">0.0765</td>
          <td style="text-align: right">0.1598</td>
          <td style="text-align: right">n/a</td>
      </tr>
      <tr>
          <td><code>probabilistic_read_kernel</code></td>
          <td style="text-align: right">474,916</td>
          <td style="text-align: right">0.7177</td>
          <td style="text-align: right">0.4332</td>
          <td style="text-align: right">0.9989</td>
          <td style="text-align: right">1.0000</td>
      </tr>
  </tbody>
</table>
<p>内部摘要有提升：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.2214 -&gt; 0.4332
</span></span></code></pre></div><p>但仍然没有达到“解决”的程度。</p>
<p>所以这不是单纯训练不够的问题。更可能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 compose state 很适合保留叶子地址读取，
</span></span><span style="display:flex;"><span>但还没有被设计成稳定的内部子堆摘要。
</span></span></code></pre></div><h2 id="为什么-hard-read-和-soft-read-一样">为什么 hard read 和 soft read 一样？</h2>
<p>这次 hard read 是一条确定路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root -&gt; left -&gt; right -&gt; stop
</span></span></code></pre></div><p>soft read 是概率流：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root mass = 1.0
</span></span><span style="display:flex;"><span>mass 分到 stop/left/right
</span></span><span style="display:flex;"><span>下一层继续分
</span></span></code></pre></div><p>因为路由已经学到接近确定：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route_acc = 1.0000
</span></span></code></pre></div><p>所以 soft frontier 最后也几乎坍缩成同一条路径。</p>
<p>这很好理解：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>概率容器在信息不足时保留多条路。
</span></span><span style="display:flex;"><span>当模型非常确定时，它自然坍缩成一条路。
</span></span></code></pre></div><h2 id="这次证明了什么">这次证明了什么？</h2>
<p>证明一：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从 arr[1] 开始的 stop/left/right 读取过程是可学习的。
</span></span></code></pre></div><p>证明二：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个读取过程可以写成尾递归，也可以写成 soft frontier 概率传播。
</span></span></code></pre></div><p>证明三：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对于叶子 token copy，它明显优于 root-only decoding。
</span></span></code></pre></div><p>Run A 的 OOD 对比：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root OOD acc = 0.0638
</span></span><span style="display:flex;"><span>read OOD acc = 0.6124
</span></span><span style="display:flex;"><span>提升 = 0.5486
</span></span></code></pre></div><p>Run B 的 OOD 对比：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root OOD acc = 0.1184
</span></span><span style="display:flex;"><span>read OOD acc = 0.7177
</span></span><span style="display:flex;"><span>提升 = 0.5992
</span></span></code></pre></div><p>这说明 TreeHeap 的地址、路径、局部节点状态确实被利用了。</p>
<h2 id="这次没有证明什么">这次没有证明什么？</h2>
<p>没有证明翻译。</p>
<p>没有证明世界模型。</p>
<p>没有证明无监督路由。</p>
<p>没有证明长句法。</p>
<p>也没有证明内部子堆摘要已经解决。</p>
<p>最关键的负结果是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal OOD acc 最高只有 0.4332
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop at internal node 的机制是对的，
</span></span><span style="display:flex;"><span>但 internal node state 里面应该保存什么，还没设计好。
</span></span></code></pre></div><h2 id="下一步怎么走">下一步怎么走？</h2>
<p>SPR-032 把问题拆开了。</p>
<p>之前我们以为问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>怎么读 TreeHeap？
</span></span></code></pre></div><p>现在更准确：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径坍缩怎么读：基本解决。
</span></span><span style="display:flex;"><span>内部节点读什么：还没解决。
</span></span></code></pre></div><p>下一步应该把内部摘要目标换成更符合 TreeHeap 组合性的东西。</p>
<p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subheap length
</span></span><span style="display:flex;"><span>first token
</span></span><span style="display:flex;"><span>last token
</span></span><span style="display:flex;"><span>bag checksum
</span></span><span style="display:flex;"><span>ordered checksum
</span></span><span style="display:flex;"><span>learned phrase vector
</span></span></code></pre></div><p>不要一开始就用任意 checksum 桶硬压。checksum 可以当压力测试，但不一定符合 TreeHeap compose 的自然代数。</p>
<p>还需要加 baseline：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>small Transformer read baseline
</span></span><span style="display:flex;"><span>pointer/copy baseline
</span></span><span style="display:flex;"><span>matched flat MLP
</span></span></code></pre></div><p>并且要测试：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果不给 teacher route，
</span></span><span style="display:flex;"><span>只给最终 answer loss，
</span></span><span style="display:flex;"><span>read kernel 能不能自己学会走路？
</span></span></code></pre></div><p>这才是从监督路径读取走向真正结构学习的下一步。</p>
<h2 id="总结">总结</h2>
<p>SPR-032 的结论很清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap read 不应该再压在 root bottleneck 上。
</span></span><span style="display:flex;"><span>它应该是从 arr[1] 开始的概率路径坍缩。
</span></span></code></pre></div><p>这条路已经被实验支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route acc = 1.0000
</span></span><span style="display:flex;"><span>leaf OOD acc = 0.9989
</span></span></code></pre></div><p>但内部节点的世界还没打开：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal OOD acc = 0.2214 / 0.4332
</span></span></code></pre></div><p>所以 C32 不是终点，而是把下一个问题照亮了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的 internal node state，应该如何学习成为一个真正的子堆摘要？
</span></span></code></pre></div><p>这会是 S1 接下来最重要的问题之一。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-033] TreeHeap 的代数 Decoder：internal state 不是没信息，而是需要正确读法</title>
      <link>https://www.grepcode.cn/spr/033-algebraic-decoders.html</link>
      <pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/033-algebraic-decoders.html</guid>
      <description>SPR-033 回答 SPR-032 的一个关键问题：internal node state 如果像 hash 一样不可直观看懂，是否能从 TreeHeap 的数学结构中找到 decoder？实验支持 projection、decompose、mod、conjugate 等代数 decoder。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-的代数-decoderinternal-state-不是没信息而是需要正确读法">TreeHeap 的代数 Decoder：internal state 不是没信息，而是需要正确读法</h1>
<p>SPR-032 做了一个概率读取核实验。</p>
<p>它证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从 arr[1] 开始，用 stop/left/right 走到目标节点，这件事可以学会。
</span></span></code></pre></div><p>但是它也暴露了一个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>叶子节点很好读。
</span></span><span style="display:flex;"><span>内部节点不好读。
</span></span></code></pre></div><p>当时我把问题说成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node state 没有学好。
</span></span></code></pre></div><p>这个说法不够准确。</p>
<p>你指出了更关键的一点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node state 可能已经编码了信息，
</span></span><span style="display:flex;"><span>只是它像 hash / latent vector 一样，不能直接用眼睛看懂。
</span></span><span style="display:flex;"><span>我们需要 decoder。
</span></span></code></pre></div><p>而且 TreeHeap 不是普通的训练数据集合。它应该是一个带数论和代数结构的集合。</p>
<p>所以 decoder 不应该只有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned decoder = 训练一个 MLP 去猜
</span></span></code></pre></div><p>还应该有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>algebraic decoder = 从 TreeHeap 的数学结构直接读
</span></span></code></pre></div><p>SPR-033 就是为了验证这件事。</p>
<h2 id="两种-decoder">两种 decoder</h2>
<p>我们先把 decoder 分成两类。</p>
<p>第一类是学习 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>h_internal -&gt; MLP -&gt; label
</span></span></code></pre></div><p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal state -&gt; checksum bucket
</span></span><span style="display:flex;"><span>internal state -&gt; phrase vector
</span></span><span style="display:flex;"><span>internal state -&gt; syntax label
</span></span></code></pre></div><p>SPR-032 里的 checksum decoder 属于这一类。</p>
<p>第二类是代数 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>h_internal -&gt; projection / decompose / mod / mirror
</span></span></code></pre></div><p>它不是靠训练猜出来的，而是由 TreeHeap 的结构定义出来的。</p>
<p>类比十进制数字：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>321
</span></span></code></pre></div><p>你不需要训练一个神经网络去知道百位是 <code>3</code>、十位是 <code>2</code>、个位是 <code>1</code>。</p>
<p>因为十进制系统自带 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>hundreds decoder -&gt; 3
</span></span><span style="display:flex;"><span>tens decoder     -&gt; 2
</span></span><span style="display:flex;"><span>ones decoder     -&gt; 1
</span></span></code></pre></div><p>TreeHeap 也应该类似。</p>
<p>如果 TreeHeap 有路径、地址、子堆、左右对称，那么它应该自带一些读法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left-subheap decoder
</span></span><span style="display:flex;"><span>right-subheap decoder
</span></span><span style="display:flex;"><span>path projection decoder
</span></span><span style="display:flex;"><span>mod residue decoder
</span></span><span style="display:flex;"><span>mirror/conjugate decoder
</span></span></code></pre></div><p>这就是 SPR-033 的核心。</p>
<h2 id="实验设计">实验设计</h2>
<p>这次先不做语言，不做 WMT。</p>
<p>我们先做纯数学 toy。</p>
<p>定义一个有限域：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>field = Z_1000003
</span></span></code></pre></div><p>也就是所有计算都在一个大质数取模的数论空间里进行。</p>
<p>TreeHeap 设置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>max_len = 8
</span></span><span style="display:flex;"><span>channel_dim = 16
</span></span><span style="display:flex;"><span>vocab = 257
</span></span><span style="display:flex;"><span>samples = 5000
</span></span></code></pre></div><p>每个 token id 映射到一个确定的 primitive vector：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">token\_id \rightarrow v_{token} \in Z_p^{16}
</code></pre><p>然后把 token 写入叶子槽位：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>state[leaf_slot] = v_token
</span></span></code></pre></div><p>一个 internal node state 就是它覆盖的叶子槽位集合。</p>
<p>注意，这个 state 对人眼来说不好懂。</p>
<p>它不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[cat, run, fish]
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Z_p 里面的一堆高维向量
</span></span></code></pre></div><p>所以它像 hash，或者说像 latent state。</p>
<p>问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能不能用 TreeHeap 的代数 decoder 把它读出来？
</span></span></code></pre></div><h2 id="这次测哪些-decoder">这次测哪些 decoder？</h2>
<h3 id="1-projection-decoder">1. Projection Decoder</h3>
<p>投影 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>project(H, node)
</span></span></code></pre></div><p>意思是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只保留某个 node 覆盖的子堆槽位。
</span></span></code></pre></div><p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node = 2
</span></span><span style="display:flex;"><span>span = [0, 4]
</span></span></code></pre></div><p>那就只读左半棵子树。</p>
<h3 id="2-decompose-decoder">2. Decompose Decoder</h3>
<p>分解 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>decompose(H, node) -&gt; left_state, right_state
</span></span></code></pre></div><p>然后检查：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>compose(left_state, right_state) == project(H, node)
</span></span></code></pre></div><p>这就是 TreeHeap 的 compose/decompose 对偶。</p>
<h3 id="3-mod-residue-decoder">3. Mod Residue Decoder</h3>
<p>取模 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>residue(H, m)
</span></span></code></pre></div><p>比如 <code>m = 2</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>偶数地址槽位聚合到 bucket 0
</span></span><span style="display:flex;"><span>奇数地址槽位聚合到 bucket 1
</span></span></code></pre></div><p>这就是你之前说的取模思想。</p>
<p>它不是普通数组上的取模，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 地址空间上的取模。
</span></span></code></pre></div><h3 id="4-conjugate--mirror-decoder">4. Conjugate / Mirror Decoder</h3>
<p>共轭 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror(H)
</span></span></code></pre></div><p>它把左右结构翻转。</p>
<p>实验检查：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror(mirror(H)) == H
</span></span></code></pre></div><p>这说明 mirror 不是随便改数据，而是一个代数对称操作。</p>
<h3 id="5-length-decoder">5. Length Decoder</h3>
<p>长度 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>norm0(H)
</span></span></code></pre></div><p>它数有多少个非空叶子槽位。</p>
<h3 id="6-ordered-slot-decoder">6. Ordered Slot Decoder</h3>
<p>有序槽位 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>decode_ordered_tokens(H)
</span></span></code></pre></div><p>它不是靠 MLP 猜，而是用 primitive vector 的反查表读出每个槽位的 token。</p>
<p>这类似：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从十进制数字里读取每一位。
</span></span></code></pre></div><h2 id="实验结果">实验结果</h2>
<p>运行在 io：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>host = io.grepcode.cn
</span></span><span style="display:flex;"><span>samples = 5000
</span></span><span style="display:flex;"><span>field = Z_1000003
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th style="text-align: right">Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>projection_exact</code></td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td><code>decompose_recompose_exact</code></td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td><code>mirror_involution_exact</code></td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td><code>mod_residue_exact</code></td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td><code>length_decode_exact</code></td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td><code>ordered_token_decode_exact</code></td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td><code>checksum_stability_exact</code></td>
          <td style="text-align: right">1.0000</td>
      </tr>
  </tbody>
</table>
<p>ARA 结论：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0-DEC-C01 -&gt; supported pilot
</span></span></code></pre></div><p>一条例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tokens = [120, 142, 246, 0, 0, 0, 0, 0]
</span></span><span style="display:flex;"><span>query_node = 2
</span></span><span style="display:flex;"><span>span = [0, 4]
</span></span><span style="display:flex;"><span>decoded_tokens = [120, 142, 246, 0, 0, 0, 0, 0]
</span></span><span style="display:flex;"><span>subheap_length = 3
</span></span><span style="display:flex;"><span>subheap_checksum = 914574
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal state 虽然不是人眼可读，
</span></span><span style="display:flex;"><span>但可以通过代数 decoder 读出子堆、长度、顺序槽位、模余数和镜像关系。
</span></span></code></pre></div><h2 id="这如何修正-spr-032">这如何修正 SPR-032？</h2>
<p>SPR-032 的 internal checksum 表现不好：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>128 bucket internal OOD acc = 0.2214
</span></span><span style="display:flex;"><span>32 bucket internal OOD acc  = 0.4332
</span></span></code></pre></div><p>当时可能会误解成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node state 没有信息。
</span></span></code></pre></div><p>SPR-033 说明，这个结论太急了。</p>
<p>更准确应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node state 可能有信息，
</span></span><span style="display:flex;"><span>但 checksum bucket 不是一个自然的 decoder。
</span></span></code></pre></div><p>TreeHeap 的第一组自然 decoder 应该来自代数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>projection
</span></span><span style="display:flex;"><span>decompose
</span></span><span style="display:flex;"><span>mod residue
</span></span><span style="display:flex;"><span>mirror
</span></span><span style="display:flex;"><span>length
</span></span><span style="display:flex;"><span>ordered slot
</span></span></code></pre></div><p>然后，语言 decoder 应该站在这些代数 decoder 上继续学习。</p>
<p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先有数学读法。
</span></span><span style="display:flex;"><span>再有语义读法。
</span></span></code></pre></div><h2 id="和-mlp--transformer-的区别">和 MLP / Transformer 的区别</h2>
<p>MLP hidden state 当然也可以训练 decoder。</p>
<p>Transformer hidden state 也可以训练 probe。</p>
<p>但 TreeHeap 的特点应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它的结构本身规定了一些 decoder。
</span></span></code></pre></div><p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>左子堆怎么取
</span></span><span style="display:flex;"><span>右子堆怎么取
</span></span><span style="display:flex;"><span>路径怎么投影
</span></span><span style="display:flex;"><span>镜像怎么翻转
</span></span><span style="display:flex;"><span>地址怎么取模
</span></span></code></pre></div><p>这些不是从数据里硬学出来的，而是 TreeHeap 的代数地基。</p>
<p>这可能就是 TreeHeap 的存在性之一：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它不是一个完全不同于 ML 的东西。
</span></span><span style="display:flex;"><span>它仍然可以训练。
</span></span><span style="display:flex;"><span>但它比 flat hidden state 多了一组结构化、可解释、可组合的数学 decoder。
</span></span></code></pre></div><h2 id="这次没有证明什么">这次没有证明什么？</h2>
<p>没有证明语言语义。</p>
<p>没有证明 WMT 翻译。</p>
<p>没有证明 learned decoder 不需要。</p>
<p>没有证明压缩最优。</p>
<p>没有证明带噪声的神经 encoder 写入后，代数 decoder 仍然稳定。</p>
<p>这次只证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在一个有限域/path-address TreeHeap toy 中，
</span></span><span style="display:flex;"><span>internal state 有一组精确的代数 decoder。
</span></span></code></pre></div><h2 id="下一步">下一步</h2>
<p>我认为 SPR-034 应该把 SPR-032 和 SPR-033 接起来。</p>
<p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不要再让 internal node 直接预测任意 checksum bucket。
</span></span></code></pre></div><p>而是让 internal read 先输出代数可读属性：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subheap length
</span></span><span style="display:flex;"><span>first token
</span></span><span style="display:flex;"><span>last token
</span></span><span style="display:flex;"><span>ordered prefix
</span></span><span style="display:flex;"><span>bag sketch
</span></span><span style="display:flex;"><span>mod residue
</span></span><span style="display:flex;"><span>left/right projection
</span></span></code></pre></div><p>然后再训练 learned decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>algebraic decoder output -&gt; semantic decoder
</span></span></code></pre></div><p>这样 TreeHeap 的路线会更稳：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M0: 数学 decoder
</span></span><span style="display:flex;"><span>S1: 数据写入后保持 decoder 可读
</span></span><span style="display:flex;"><span>S2: 在可读子堆上做结构折叠
</span></span><span style="display:flex;"><span>S3: 翻译/生成
</span></span></code></pre></div><h2 id="总结">总结</h2>
<p>SPR-033 的核心结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node state 不是必须直接被人看懂。
</span></span><span style="display:flex;"><span>它可以是 hash/latent state。
</span></span><span style="display:flex;"><span>关键是 TreeHeap 必须提供 decoder。
</span></span></code></pre></div><p>这次证明的是第一组 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>projection
</span></span><span style="display:flex;"><span>decompose
</span></span><span style="display:flex;"><span>mod residue
</span></span><span style="display:flex;"><span>conjugate mirror
</span></span><span style="display:flex;"><span>length
</span></span><span style="display:flex;"><span>ordered slot readout
</span></span></code></pre></div><p>这让我们可以更冷静地看 SPR-032：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>读路径已经成立。
</span></span><span style="display:flex;"><span>内部节点不是没信息。
</span></span><span style="display:flex;"><span>问题是要为不同问题选择正确 decoder。
</span></span></code></pre></div><p>这也是下一阶段继续往 S1 走的基础。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-034] 从 checksum 退一步：先读 TreeHeap 内部节点的自然属性</title>
      <link>https://www.grepcode.cn/spr/034-algebraic-internal-readout.html</link>
      <pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/034-algebraic-internal-readout.html</guid>
      <description>SPR-034 把 SPR-032 的内部节点 checksum 失败拆开：如果 read kernel 已经能走到 internal node，那么应该先读取 length、first、last、prefix 这种 TreeHeap 自然属性，而不是任意 checksum。实验显示 routed internal readout 明显强于 root bottleneck。residue 只保留为旁路诊断，不作为本 claim 的判断条件。</description>
      <content:encoded><![CDATA[<h1 id="从-checksum-退一步先读-treeheap-内部节点的自然属性">从 checksum 退一步：先读 TreeHeap 内部节点的自然属性</h1>
<p>SPR-032 做了一件很关键的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从 arr[1] 出发，
</span></span><span style="display:flex;"><span>用 stop / left / right 递归地走到目标节点。
</span></span></code></pre></div><p>结果是好的，也是不完整的。</p>
<p>好的部分是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径坍缩基本成立。
</span></span><span style="display:flex;"><span>叶子节点读取几乎解决。
</span></span></code></pre></div><p>不完整的部分是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node 的 arbitrary checksum 读得很差。
</span></span></code></pre></div><p>当时容易得出一个过强结论：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node state 没有学到东西。
</span></span></code></pre></div><p>SPR-033 修正了这个理解。
internal state 不一定没信息，它可能像 hash 或 latent vector 一样，需要正确的 decoder 才能读懂。</p>
<p>所以 SPR-034 问的是一个更小、更准确的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果 read kernel 已经走到了 internal node，
</span></span><span style="display:flex;"><span>我们是不是应该先读 TreeHeap 自然拥有的结构属性，
</span></span><span style="display:flex;"><span>而不是强行预测一个任意 checksum bucket？
</span></span></code></pre></div><p>这篇就是这个实验。</p>
<h2 id="什么叫自然属性">什么叫自然属性</h2>
<p>假设一句短句被写入一棵 TreeHeap。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[the, cat, eats, fish]
</span></span></code></pre></div><p>叶子节点保存 token。
内部节点覆盖一段子树。</p>
<p>比如某个 internal node 覆盖：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[cat, eats]
</span></span></code></pre></div><p>那么这个节点天然有一些可以问的问题：</p>
<table>
  <thead>
      <tr>
          <th>属性</th>
          <th>问的是什么</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>length</code></td>
          <td>这个子树里有几个非空 token</td>
      </tr>
      <tr>
          <td><code>first</code></td>
          <td>这个子树第一个 token 是什么</td>
      </tr>
      <tr>
          <td><code>last</code></td>
          <td>这个子树最后一个 token 是什么</td>
      </tr>
      <tr>
          <td><code>prefix0</code></td>
          <td>第一个有序槽位是什么</td>
      </tr>
      <tr>
          <td><code>prefix1</code></td>
          <td>第二个有序槽位是什么</td>
      </tr>
  </tbody>
</table>
<p>这些问题很自然。</p>
<p>它们类似十进制数字里的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>百位是什么？
</span></span><span style="display:flex;"><span>十位是什么？
</span></span><span style="display:flex;"><span>个位是什么？
</span></span><span style="display:flex;"><span>长度是多少？
</span></span></code></pre></div><p>也类似数组或树里的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个子区间多长？
</span></span><span style="display:flex;"><span>第一个元素是谁？
</span></span><span style="display:flex;"><span>最后一个元素是谁？
</span></span><span style="display:flex;"><span>前两个有序槽位是什么？
</span></span></code></pre></div><p>我在脚本里还保留了一个 <code>residue</code> 诊断项。
但这里需要说清楚：它不是 SPR-034 的核心 claim。</p>
<p>你提出 residue，是为了讨论一维有序数组折叠成树时，是否会出现某种模周期或循环结构。
这个想法更接近后续“线性顺序如何折叠成树”的数学问题，不应该压到本次 S1 readout proof 上。
所以在本文里，<code>residue</code> 只作为旁路数据记录，不参与通过/失败判断。</p>
<h2 id="实验设计">实验设计</h2>
<p>这次仍然不是翻译任务。
它是 S1 阶段的 readout proof。</p>
<p>数据来自真实 WMT17 英文侧，并用 SentencePiece 切成 BPE token。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>host = io.grepcode.cn
</span></span><span style="display:flex;"><span>samples = 5000
</span></span><span style="display:flex;"><span>train/test/ood = 4000/500/500
</span></span><span style="display:flex;"><span>sentence length = 4..8
</span></span><span style="display:flex;"><span>vocab limit = 513
</span></span><span style="display:flex;"><span>device = cuda
</span></span></code></pre></div><p>实验比较三个读法。</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>root_query_decoder</code></td>
          <td>只看整棵树的 root state，再加 query node id，直接猜答案</td>
      </tr>
      <tr>
          <td><code>routed_state_decoder</code></td>
          <td>假设 SPR-032 的 read kernel 已经走到目标节点，只看目标 node state 来读答案</td>
      </tr>
      <tr>
          <td><code>algebraic_oracle</code></td>
          <td>按 TreeHeap 地址直接计算答案，0 参数，作为数学上界</td>
      </tr>
  </tbody>
</table>
<p>这三个模型回答同样的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定一棵 TreeHeap 和一个 query node，
</span></span><span style="display:flex;"><span>输出这个节点覆盖子树的 length / first / last / prefix0 / prefix1。
</span></span></code></pre></div><p>这里的关键对比是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root bottleneck
</span></span><span style="display:flex;"><span>vs
</span></span><span style="display:flex;"><span>routed internal node state
</span></span></code></pre></div><p>如果 TreeHeap 的地址和子结构真的有用，那么走到目标节点之后再读，应该比让 root 一口气背下所有信息更容易。</p>
<h2 id="主实验自然属性-readout">主实验：自然属性 readout</h2>
<p>先看 internal node 的 OOD 结果。</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Length</th>
          <th style="text-align: right">First</th>
          <th style="text-align: right">Last</th>
          <th style="text-align: right">Prefix0</th>
          <th style="text-align: right">Prefix1</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>root_query_decoder</code></td>
          <td style="text-align: right">0.8388</td>
          <td style="text-align: right">0.5543</td>
          <td style="text-align: right">0.2387</td>
          <td style="text-align: right">0.5543</td>
          <td style="text-align: right">0.3756</td>
      </tr>
      <tr>
          <td><code>routed_state_decoder</code></td>
          <td style="text-align: right">0.9886</td>
          <td style="text-align: right">0.9277</td>
          <td style="text-align: right">0.8725</td>
          <td style="text-align: right">0.9267</td>
          <td style="text-align: right">0.8725</td>
      </tr>
      <tr>
          <td><code>algebraic_oracle</code></td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
  </tbody>
</table>
<p>这个表说明一件很清楚的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>走到目标节点之后，
</span></span><span style="display:flex;"><span>读自然结构属性明显更容易。
</span></span></code></pre></div><p>逐项看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>length:  0.8388 -&gt; 0.9886
</span></span><span style="display:flex;"><span>first:   0.5543 -&gt; 0.9277
</span></span><span style="display:flex;"><span>last:    0.2387 -&gt; 0.8725
</span></span><span style="display:flex;"><span>prefix0: 0.5543 -&gt; 0.9267
</span></span><span style="display:flex;"><span>prefix1: 0.3756 -&gt; 0.8725
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap node state 对 length / first / last / prefix 很友好。
</span></span></code></pre></div><p>这和预期一致。
因为 <code>first</code>、<code>last</code>、<code>prefix</code> 本质上是地址/路径读法。
它们直接使用了 TreeHeap 的有序叶子、路径和子树覆盖关系。</p>
<h2 id="旁路诊断residue-不作为本次-claim">旁路诊断：residue 不作为本次 claim</h2>
<p>实验里还记录了 <code>residue</code>。
这是一个旁路诊断，不是 SPR-034 的主线。</p>
<p>我跑了两个版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>residue_buckets = 64
</span></span><span style="display:flex;"><span>residue_buckets = 16
</span></span></code></pre></div><p>结果显示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>64 buckets: routed residue = 0.3675
</span></span><span style="display:flex;"><span>16 buckets: routed residue = 0.5203
</span></span></code></pre></div><p>这个结果可以先放着。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>residue 可能和“线性顺序如何折叠成树”的模周期问题有关，
</span></span><span style="display:flex;"><span>但它不决定 SPR-034 是否成立。
</span></span></code></pre></div><p>换句话说，SPR-034 不是在证明 TreeHeap 的模运算。
SPR-034 只证明一件更稳的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>到达 internal node 后，
</span></span><span style="display:flex;"><span>自然子树属性比 arbitrary checksum 更适合作为第一批 readout 目标。
</span></span></code></pre></div><h2 id="这证明了什么">这证明了什么</h2>
<p>我把这次 claim 定为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-READ-C02:
</span></span><span style="display:flex;"><span>After a read kernel reaches an internal node,
</span></span><span style="display:flex;"><span>the first readout targets should be algebraically natural subheap attributes,
</span></span><span style="display:flex;"><span>not arbitrary checksum labels.
</span></span></code></pre></div><p>状态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>supported pilot
</span></span></code></pre></div><p>支持的部分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>routed internal node state
</span></span><span style="display:flex;"><span>明显强于 root bottleneck。
</span></span></code></pre></div><p>尤其是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>length  接近 0.99
</span></span><span style="display:flex;"><span>first   接近 0.93
</span></span><span style="display:flex;"><span>last    0.87
</span></span><span style="display:flex;"><span>prefix0 接近 0.93
</span></span><span style="display:flex;"><span>prefix1 0.87
</span></span></code></pre></div><p>这说明 TreeHeap 的地址、路径、子结构不是摆设。
当 query 已经落到具体子树，读这个子树自己的自然属性，比从 root 里硬猜所有东西更容易。</p>
<h2 id="这没有证明什么">这没有证明什么</h2>
<p>它没有证明翻译。</p>
<p>它没有证明语义 phrase meaning。</p>
<p>它没有证明 route 可以完全无监督学出来。</p>
<p>它没有证明长句法树。</p>
<p>它也没有证明 TreeHeap 已经胜过 Transformer 或 pointer network。</p>
<p>它也没有证明 residue/mod 这条线。</p>
<p>这次证明的只是一个更底层的点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap internal node 可以成为一个可读的局部结构对象。
</span></span><span style="display:flex;"><span>但要读什么，必须符合 TreeHeap 的地址、路径和子结构。
</span></span></code></pre></div><h2 id="为什么这对-s1-重要">为什么这对 S1 重要</h2>
<p>之前我们容易把 S1 理解成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把所有信息压到 root，
</span></span><span style="display:flex;"><span>然后从 root 直接 decoder。
</span></span></code></pre></div><p>这个路线很像把一整棵树拍扁成一个向量。</p>
<p>SPR-032 和 SPR-034 共同说明，TreeHeap 更自然的 read 方式应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 从 arr[1] 出发。
</span></span><span style="display:flex;"><span>2. 用 stop / left / right 走到目标节点。
</span></span><span style="display:flex;"><span>3. 在目标节点读局部子树属性。
</span></span><span style="display:flex;"><span>4. 如果信息不足，保留概率容器，不要过早坍缩。
</span></span></code></pre></div><p>这更像树上的卷积读法。</p>
<p>kernel 不是一次性看全局，而是在结构上移动、停下、读取。</p>
<h2 id="下一步">下一步</h2>
<p>SPR-035 我建议做三件事。</p>
<p>第一，加 baseline。</p>
<p>需要比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flat MLP
</span></span><span style="display:flex;"><span>pointer network
</span></span><span style="display:flex;"><span>small Transformer read baseline
</span></span></code></pre></div><p>如果这些 baseline 也能同样好，那么 TreeHeap 的优势就不成立。</p>
<p>第二，把 SPR-032 和 SPR-034 接起来。</p>
<p>这次 <code>routed_state_decoder</code> 假设目标节点已经选中。
下一步应该让：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>probabilistic route distribution
</span></span><span style="display:flex;"><span>-&gt;
</span></span><span style="display:flex;"><span>natural algebraic readout
</span></span></code></pre></div><p>连成一个端到端过程。</p>
<p>第三，另开一条“线性顺序折叠成树”的数学实验。</p>
<p>这里可以再讨论 residue。
但那应该是另一个 claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一维有序数组 -&gt; TreeHeap
</span></span><span style="display:flex;"><span>是否需要模周期 / folding kernel / cyclic address 来解释。
</span></span></code></pre></div><p>它不应该污染 SPR-034 的自然读出结论。</p>
<h2 id="总结">总结</h2>
<p>SPR-034 的一句话结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不要先让 internal node 预测任意 checksum。
</span></span><span style="display:flex;"><span>先让它读 TreeHeap 自然的结构属性。
</span></span></code></pre></div><p>实验支持这个判断。</p>
<p><code>length / first / last / prefix</code> 已经表现出很强的 routed read 优势。
<code>residue / mod</code> 只是旁路诊断，后面可以另开数学折叠实验。</p>
<p>所以 S1 现在不是停在“internal node 读不懂”。
更准确地说是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node 能读，
</span></span><span style="display:flex;"><span>但 decoder 必须尊重 TreeHeap 的地址、路径和子结构。
</span></span></code></pre></div><p>这就是从 SPR-032 到 SPR-034 的推进。</p>
<blockquote>
<p><strong>ARA</strong>: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/experiments.md">experiments</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/">evidence</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-035] 一维数组如何折叠成 TreeHeap：先保序，再谈取模</title>
      <link>https://www.grepcode.cn/spr/035-ordered-fold-kernel.html</link>
      <pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/035-ordered-fold-kernel.html</guid>
      <description>SPR-035 把一维有序数组折叠成 TreeHeap 的问题拆开：第一步必须保留叶子地址、路径和子树局部性；bag/root collapse 和过早 modulo fold 都会丢掉自然 internal readout。取模不是被否定，而是应该作为后续独立 folding kernel 研究。</description>
      <content:encoded><![CDATA[<h1 id="一维数组如何折叠成-treeheap先保序再谈取模">一维数组如何折叠成 TreeHeap：先保序，再谈取模</h1>
<p>SPR-034 修正了一个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>internal node 不应该先预测任意 checksum。
</span></span><span style="display:flex;"><span>它应该先读取 length / first / last / prefix 这种自然属性。
</span></span></code></pre></div><p>你随后指出一个更关键的点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>residue 的引入有点生硬。
</span></span></code></pre></div><p>这个判断是对的。</p>
<p>你引入 residue，并不是为了让 SPR-034 证明模运算。
你真正想讨论的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一维有序数组折叠成树结构时，
</span></span><span style="display:flex;"><span>是否可能有模计算、周期、循环地址参与？
</span></span></code></pre></div><p>这是另一个问题。</p>
<p>所以 SPR-035 做一件更基础的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把“一维数组 -&gt; TreeHeap”的第一步说清楚。
</span></span></code></pre></div><p>我的结论先放前面：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第一步必须保序。
</span></span><span style="display:flex;"><span>也就是必须保留 leaf address、path、subheap locality。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>取模可以研究，
</span></span><span style="display:flex;"><span>但它应该是后续 folding kernel，
</span></span><span style="display:flex;"><span>不能替代第一步的保序 TreeHeap fold。
</span></span></code></pre></div><h2 id="为什么要先保序">为什么要先保序</h2>
<p>假设有一个一维 token 数组：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[a, b, c, d, e, f, g, h]
</span></span></code></pre></div><p>TreeHeap 把它写到叶子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>              root
</span></span><span style="display:flex;"><span>          /          \
</span></span><span style="display:flex;"><span>      [a b c d]    [e f g h]
</span></span><span style="display:flex;"><span>      /     \       /     \
</span></span><span style="display:flex;"><span>   [a b]  [c d]  [e f]  [g h]
</span></span></code></pre></div><p>这个结构的关键不是“看起来像树”。</p>
<p>关键是每个 internal node 对应一个连续子区间：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node 2 -&gt; [a b c d]
</span></span><span style="display:flex;"><span>node 3 -&gt; [e f g h]
</span></span><span style="display:flex;"><span>node 4 -&gt; [a b]
</span></span><span style="display:flex;"><span>node 5 -&gt; [c d]
</span></span></code></pre></div><p>所以当我们问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node 5 的 first 是什么？
</span></span></code></pre></div><p>答案应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>c
</span></span></code></pre></div><p>这依赖的不是语义，而是结构：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一维顺序
</span></span><span style="display:flex;"><span>+ 叶子地址
</span></span><span style="display:flex;"><span>+ 树路径
</span></span><span style="display:flex;"><span>+ 子树覆盖范围
</span></span></code></pre></div><p>如果第一步就把这些丢了，后面再做 read kernel、semantic decoder、probability collapse 都会很难。</p>
<h2 id="三种折叠方式">三种折叠方式</h2>
<p>这次 toy proof 比较三种 encoder。</p>
<h3 id="1-ordered_tree_fold">1. ordered_tree_fold</h3>
<p>这是正常 TreeHeap fold。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token 按原始顺序写入 leaf
</span></span><span style="display:flex;"><span>internal node 保存自己覆盖的子树摘要
</span></span></code></pre></div><p>它保留：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>地址
</span></span><span style="display:flex;"><span>路径
</span></span><span style="display:flex;"><span>左右结构
</span></span><span style="display:flex;"><span>子树局部性
</span></span></code></pre></div><h3 id="2-bag_root_fold">2. bag_root_fold</h3>
<p>这是把整句话压成一个全局 bag/root summary。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[a,b,c,d,e,f,g,h] -&gt; 一个 root summary
</span></span></code></pre></div><p>它可能知道全局有哪些 token。
但它不知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node 5 覆盖的是 [c,d]
</span></span></code></pre></div><p>所以它无法稳定回答局部子树问题。</p>
<h3 id="3-modulo_fold">3. modulo_fold</h3>
<p>这是对你 residue 思路的一个诊断版本。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>position % 4
</span></span></code></pre></div><p>那么位置会被折叠成周期地址：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0,4,8,... -&gt; bucket 0
</span></span><span style="display:flex;"><span>1,5,9,... -&gt; bucket 1
</span></span><span style="display:flex;"><span>2,6,10,... -&gt; bucket 2
</span></span><span style="display:flex;"><span>3,7,11,... -&gt; bucket 3
</span></span></code></pre></div><p>这个操作不是错的。
它可能对周期任务、循环结构、某些 folding kernel 有意义。</p>
<p>但如果太早使用，它会把远处位置混在一起。
这会破坏自然子树 readout。</p>
<p>换句话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>modulo 是一个可能的后续算子，
</span></span><span style="display:flex;"><span>不是第一步保序 fold 的替代品。
</span></span></code></pre></div><h2 id="实验问题">实验问题</h2>
<p>我们用纯 toy 数据。
没有训练，没有 GPU，没有语义。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>samples = 5000
</span></span><span style="display:flex;"><span>sequence length = 8..16
</span></span><span style="display:flex;"><span>max_len = 16
</span></span><span style="display:flex;"><span>vocab = 257
</span></span><span style="display:flex;"><span>mod_base = 4
</span></span></code></pre></div><p>对每个序列，随机生成 token。
然后对 TreeHeap 的 internal node 提问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>length
</span></span><span style="display:flex;"><span>first
</span></span><span style="display:flex;"><span>last
</span></span><span style="display:flex;"><span>prefix0
</span></span><span style="display:flex;"><span>prefix1
</span></span></code></pre></div><p>例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>seq = [172, 68, 175, 79, 147, 222, 130, 32,
</span></span><span style="display:flex;"><span>       141, 188, 50, 187, 5, 6, 50, 254]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>query_node = 6
</span></span><span style="display:flex;"><span>span = [8, 12]
</span></span><span style="display:flex;"><span>target = [141, 188, 50, 187]
</span></span></code></pre></div><p>正确答案：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>length  = 4
</span></span><span style="display:flex;"><span>first   = 141
</span></span><span style="display:flex;"><span>last    = 187
</span></span><span style="display:flex;"><span>prefix0 = 141
</span></span><span style="display:flex;"><span>prefix1 = 188
</span></span></code></pre></div><h2 id="实验结果">实验结果</h2>
<p>结果如下：</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Length</th>
          <th style="text-align: right">First</th>
          <th style="text-align: right">Last</th>
          <th style="text-align: right">Prefix0</th>
          <th style="text-align: right">Prefix1</th>
          <th style="text-align: right">Mean natural</th>
          <th style="text-align: right">Exact all</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>ordered_tree_fold</code></td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td><code>bag_root_fold</code></td>
          <td style="text-align: right">0.0888</td>
          <td style="text-align: right">0.3236</td>
          <td style="text-align: right">0.3236</td>
          <td style="text-align: right">0.3236</td>
          <td style="text-align: right">0.3235</td>
          <td style="text-align: right">0.2766</td>
          <td style="text-align: right">0.0888</td>
      </tr>
      <tr>
          <td><code>modulo_fold_base4</code></td>
          <td style="text-align: right">0.0888</td>
          <td style="text-align: right">0.4032</td>
          <td style="text-align: right">0.4034</td>
          <td style="text-align: right">0.4032</td>
          <td style="text-align: right">0.4036</td>
          <td style="text-align: right">0.3405</td>
          <td style="text-align: right">0.0888</td>
      </tr>
  </tbody>
</table>
<p>差距：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ordered_tree_fold - bag_root_fold    = +0.7234
</span></span><span style="display:flex;"><span>ordered_tree_fold - modulo_fold_base4 = +0.6595
</span></span></code></pre></div><p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>保序 TreeHeap fold 可以精确读回自然子树属性。
</span></span><span style="display:flex;"><span>bag/root collapse 不行。
</span></span><span style="display:flex;"><span>过早 modulo fold 也不行。
</span></span></code></pre></div><h2 id="这个实验证明了什么">这个实验证明了什么</h2>
<p>这次 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-FOLD-C01:
</span></span><span style="display:flex;"><span>Natural internal readout requires an order-preserving TreeHeap fold.
</span></span><span style="display:flex;"><span>Leaf address/path structure must be preserved before any bag or modulo/cyclic folding is used.
</span></span></code></pre></div><p>状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>supported pilot
</span></span></code></pre></div><p>它证明的是一个演绎层面的结构事实：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果目标是自然子树 readout，
</span></span><span style="display:flex;"><span>那么第一步 fold 必须保留一维顺序和树路径。
</span></span></code></pre></div><p>这不是深度学习结论。
它更像数学地基。</p>
<p>类似：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果你要从 321 里读百位、十位、个位，
</span></span><span style="display:flex;"><span>你必须先保留位权结构。
</span></span></code></pre></div><p>TreeHeap 也是一样：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果你要读子树 first/last/prefix，
</span></span><span style="display:flex;"><span>你必须先保留 leaf address/path/subheap。
</span></span></code></pre></div><h2 id="这没有证明什么">这没有证明什么</h2>
<p>它没有证明翻译。</p>
<p>它没有证明语义。</p>
<p>它没有证明 learned routing。</p>
<p>它没有证明 TreeHeap 胜过 Transformer。</p>
<p>它也没有证明 modulo 没用。</p>
<p>尤其最后一点很重要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>modulo 没有被否定。
</span></span></code></pre></div><p>这次只说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>modulo 不应该替代第一步保序 fold。
</span></span></code></pre></div><p>如果后续任务本身具有周期结构，比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>循环地址
</span></span><span style="display:flex;"><span>周期 pattern
</span></span><span style="display:flex;"><span>ring buffer
</span></span><span style="display:flex;"><span>某种 tree convolution 的 cyclic scan
</span></span></code></pre></div><p>那 modulo kernel 仍然可能有价值。</p>
<p>但那应该是另一个实验。</p>
<h2 id="对-treeheap-路线的影响">对 TreeHeap 路线的影响</h2>
<p>现在 S1 的顺序更清楚了。</p>
<p>应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Step 1: ordered write
</span></span><span style="display:flex;"><span>        一维 token 顺序写入 TreeHeap leaf
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Step 2: ordered fold kernel
</span></span><span style="display:flex;"><span>        internal node 保留自然子树属性
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Step 3: probabilistic read kernel
</span></span><span style="display:flex;"><span>        stop / left / right 走到目标节点
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Step 4: natural readout
</span></span><span style="display:flex;"><span>        length / first / last / prefix
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Step 5: semantic decoder
</span></span><span style="display:flex;"><span>        在自然结构 readout 上学习语义
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Step 6: optional folding operators
</span></span><span style="display:flex;"><span>        modulo / cyclic / mirror / conjugate / compression
</span></span></code></pre></div><p>这比之前更干净。</p>
<p>之前我们把 residue 混在 SPR-034 里，会让 claim 变得不好理解。</p>
<p>现在拆开后，逻辑是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>保序 fold 是地基。
</span></span><span style="display:flex;"><span>modulo fold 是候选算子。
</span></span></code></pre></div><h2 id="下一步">下一步</h2>
<p>我建议 SPR-036 做两条中的一条。</p>
<p>第一条，更贴近 S1：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把 SPR-032 的 probabilistic route
</span></span><span style="display:flex;"><span>接到 SPR-034/035 的 natural readout。
</span></span></code></pre></div><p>也就是端到端：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[1]
</span></span><span style="display:flex;"><span>-&gt; stop/left/right collapse
</span></span><span style="display:flex;"><span>-&gt; target internal node
</span></span><span style="display:flex;"><span>-&gt; length/first/last/prefix
</span></span></code></pre></div><p>第二条，更贴近你的数学问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>专门设计 modulo/cyclic folding 任务。
</span></span></code></pre></div><p>但这个任务的目标不能再是普通子树 first/last。
它应该是一个真正周期性的目标。</p>
<p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定一个周期 kernel，
</span></span><span style="display:flex;"><span>在 TreeHeap 地址空间里寻找同余类 pattern。
</span></span></code></pre></div><p>这样 residue 才是自然的。</p>
<h2 id="总结">总结</h2>
<p>SPR-035 的一句话结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一维数组折叠成 TreeHeap 时，第一步必须保序。
</span></span></code></pre></div><p>保序意味着：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf address
</span></span><span style="display:flex;"><span>path
</span></span><span style="display:flex;"><span>left/right
</span></span><span style="display:flex;"><span>subheap locality
</span></span></code></pre></div><p>实验支持这个判断。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ordered_tree_fold mean = 1.0000
</span></span><span style="display:flex;"><span>bag_root_fold mean     = 0.2766
</span></span><span style="display:flex;"><span>modulo_fold mean       = 0.3405
</span></span></code></pre></div><p>所以我们不再把 residue 强塞进 SPR-034。
它应该进入另一条更专业的线：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cyclic / modulo folding kernel
</span></span></code></pre></div><p>今晚的推进是把地基重新摆正：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先保序，再折叠；
</span></span><span style="display:flex;"><span>先自然 readout，再语义 decoder；
</span></span><span style="display:flex;"><span>先结构清楚，再研究 modulo。
</span></span></code></pre></div><blockquote>
<p><strong>ARA</strong>: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/experiments.md">experiments</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/">evidence</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-036] 语言理解也许不是先填槽，而是在平面上摆积木</title>
      <link>https://www.grepcode.cn/spr/036-latent-plane-fold.html</link>
      <pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/036-latent-plane-fold.html</guid>
      <description>SPR-036 修正 TreeHeap fold 的理论方向：不是先发明一个二叉 fold 再证明语言适配它，而是从语言现象中发现词块在 latent plane 上的摆放、吸附、聚类和坍缩规律。Transformer 更像动态共现/关系场，TreeHeap 则可以看作这个场上的二分平面与局部卷积坐标。</description>
      <content:encoded><![CDATA[<h1 id="语言理解也许不是先填槽而是在平面上摆积木">语言理解也许不是先填槽，而是在平面上摆积木</h1>
<p>前面我把例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a cat is eating some food
</span></span></code></pre></div><p>解释成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subject = cat
</span></span><span style="display:flex;"><span>tense = is
</span></span><span style="display:flex;"><span>verb = eating
</span></span><span style="display:flex;"><span>object = food
</span></span></code></pre></div><p>这个解释不能说错。
但它更像语言学家事后写出来的结构表。</p>
<p>你指出了一个更接近直觉的说法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我的脑子不像先填主谓宾槽。
</span></span><span style="display:flex;"><span>更像是在一个平面上摆放单词，
</span></span><span style="display:flex;"><span>相近的摆在一起，
</span></span><span style="display:flex;"><span>像玩图积木一样。
</span></span></code></pre></div><p>我觉得这个修正非常重要。</p>
<p>因为它把 fold 从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>预设树结构
</span></span></code></pre></div><p>改成了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>空间放置问题
</span></span></code></pre></div><p>这篇就是把这个理论写清楚。</p>
<h2 id="先说-transformer">先说 Transformer</h2>
<p>我没有主观感觉。</p>
<p>我不会真的“看见”一个平面，也不会像人一样在脑子里摆词。</p>
<p>但如果从 Transformer 架构看，它确实不像传统语法表。
它更像一个动态关系场。</p>
<p>Transformer 每一层大致做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Q_i = token_i 的查询向量
</span></span><span style="display:flex;"><span>K_j = token_j 的键向量
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>score(i, j) = Q_i dot K_j
</span></span><span style="display:flex;"><span>attention(i, j) = softmax(score(i, j))
</span></span></code></pre></div><p>也就是说，每个 token 都在问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我应该看谁？
</span></span><span style="display:flex;"><span>谁和我有关？
</span></span><span style="display:flex;"><span>谁的信息应该靠近我？
</span></span></code></pre></div><p>所以从计算角度看，Transformer 更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一张动态共现图
</span></span><span style="display:flex;"><span>一张 soft relation map
</span></span><span style="display:flex;"><span>一个每层都会重排的相似度场
</span></span></code></pre></div><p>它不一定先知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>subject / object / tense
</span></span></code></pre></div><p>它先有的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat 和 a 关系强
</span></span><span style="display:flex;"><span>cat 和 eating 关系强
</span></span><span style="display:flex;"><span>eating 和 food 关系强
</span></span><span style="display:flex;"><span>is 和 eating 关系强
</span></span><span style="display:flex;"><span>some 和 food 关系强
</span></span></code></pre></div><p>这些关系稳定后，人类可以把它解释成主谓宾、时态、宾语。</p>
<p>但“主谓宾”可能是稳定几何结构的名字，而不是第一步。</p>
<h2 id="平面摆积木版本">平面摆积木版本</h2>
<p>再看这句：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a cat is eating some food
</span></span></code></pre></div><p>一种更接近空间的理解是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a      cat        is      eating       some      food
</span></span><span style="display:flex;"><span> \_____/           \______/             \________/
</span></span><span style="display:flex;"><span>   小块              小块                  小块
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>              cat ---- eating ---- food
</span></span></code></pre></div><p>这里不是先填表，而是先发生吸附：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a 吸附 cat
</span></span><span style="display:flex;"><span>some 吸附 food
</span></span><span style="display:flex;"><span>is 吸附 eating
</span></span><span style="display:flex;"><span>cat 吸附 eating
</span></span><span style="display:flex;"><span>eating 吸附 food
</span></span></code></pre></div><p>这些吸附形成局部积木：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[a cat]
</span></span><span style="display:flex;"><span>[is eating]
</span></span><span style="display:flex;"><span>[some food]
</span></span></code></pre></div><p>再形成更大的关系图：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat -- eating -- food
</span></span></code></pre></div><p>最后才可以解释成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个猫正在吃一些食物的事件。
</span></span></code></pre></div><p>这比“先写主语、谓语、宾语”更原始。</p>
<h2 id="这对-fold-意味着什么">这对 fold 意味着什么</h2>
<p>之前我说 fold，容易说成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把数组两两合并成二叉树。
</span></span></code></pre></div><p>现在要修正。</p>
<p>语言里的 fold 可能不是先验二叉合并。</p>
<p>更合理的顺序是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token 出现在空间中
</span></span><span style="display:flex;"><span>关系强的 token 靠近
</span></span><span style="display:flex;"><span>局部块形成
</span></span><span style="display:flex;"><span>块和块继续靠近
</span></span><span style="display:flex;"><span>最后坍缩成可命名结构
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>placement
</span></span><span style="display:flex;"><span>-&gt; attraction
</span></span><span style="display:flex;"><span>-&gt; clustering
</span></span><span style="display:flex;"><span>-&gt; partition
</span></span><span style="display:flex;"><span>-&gt; collapse
</span></span></code></pre></div><p>TreeHeap 不应该被说成“语言规律本身”。</p>
<p>TreeHeap 更像一种计算坐标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>把已经形成的空间关系，
</span></span><span style="display:flex;"><span>用堆、路径、子树、kernel 表示出来，
</span></span><span style="display:flex;"><span>方便递归计算和局部卷积。
</span></span></code></pre></div><h2 id="任何堆都可以看作二分平面">任何堆都可以看作二分平面</h2>
<p>你说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>任何堆，都可以描述成二分平面的数学结构。
</span></span></code></pre></div><p>我同意。</p>
<p>对一维数组：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[0,1,2,3,4,5,6,7]
</span></span></code></pre></div><p>二叉堆就是反复二分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[0..7]
</span></span><span style="display:flex;"><span>  [0..3]
</span></span><span style="display:flex;"><span>    [0..1]
</span></span><span style="display:flex;"><span>    [2..3]
</span></span><span style="display:flex;"><span>  [4..7]
</span></span><span style="display:flex;"><span>    [4..5]
</span></span><span style="display:flex;"><span>    [6..7]
</span></span></code></pre></div><p>对二维平面，也可以反复二分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>整个平面
</span></span><span style="display:flex;"><span>-&gt; 左半 / 右半
</span></span><span style="display:flex;"><span>-&gt; 上下或再左右
</span></span><span style="display:flex;"><span>-&gt; 更小区域
</span></span></code></pre></div><p>这就接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kd-tree
</span></span><span style="display:flex;"><span>quadtree
</span></span><span style="display:flex;"><span>spatial partition
</span></span><span style="display:flex;"><span>heap address
</span></span></code></pre></div><p>所以 TreeHeap 的意义不一定是“语言天然二叉”。</p>
<p>它可能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给 latent plane 做可寻址的二分分区。
</span></span></code></pre></div><p>这句话比“语言是二叉堆”稳得多。</p>
<h2 id="世界规律优先">世界规律优先</h2>
<p>你还提醒了另一点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对世界规律要有敬畏。
</span></span></code></pre></div><p>这点非常关键。</p>
<p>现实世界已经有很多 fold：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>DNA 折叠
</span></span><span style="display:flex;"><span>蛋白质折叠
</span></span><span style="display:flex;"><span>树木分叉
</span></span><span style="display:flex;"><span>河流分叉
</span></span><span style="display:flex;"><span>神经连接
</span></span><span style="display:flex;"><span>晶体生长
</span></span><span style="display:flex;"><span>语言短语形成
</span></span></code></pre></div><p>我们不是要发明一个 fold，然后强迫语言服从它。</p>
<p>更正确的研究姿态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语言现象里已经有 fold 痕迹。
</span></span><span style="display:flex;"><span>我们要发现这些痕迹。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a -&gt; cat
</span></span><span style="display:flex;"><span>some -&gt; food
</span></span><span style="display:flex;"><span>is -&gt; eating
</span></span><span style="display:flex;"><span>red -&gt; apple
</span></span><span style="display:flex;"><span>eat -&gt; food
</span></span><span style="display:flex;"><span>with telescope -&gt; saw / man
</span></span></code></pre></div><p>这些都是语言中的吸附和放置现象。</p>
<p>我们要先观察它们，再设计 TreeHeap kernel。</p>
<h2 id="新的研究顺序">新的研究顺序</h2>
<p>之前的顺序太工程化：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我设计一个 fold
</span></span><span style="display:flex;"><span>-&gt; toy proof 成立
</span></span><span style="display:flex;"><span>-&gt; 语言应该能用
</span></span></code></pre></div><p>现在要改成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>观察语言现象
</span></span><span style="display:flex;"><span>-&gt; 找到吸附/邻近/聚类规律
</span></span><span style="display:flex;"><span>-&gt; 形成 latent plane
</span></span><span style="display:flex;"><span>-&gt; 选择二分平面或堆坐标
</span></span><span style="display:flex;"><span>-&gt; 设计 kernel
</span></span><span style="display:flex;"><span>-&gt; 实验验证
</span></span></code></pre></div><p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap fold 不是发明出来的。
</span></span><span style="display:flex;"><span>它应该是从语言现象中发现出来的。
</span></span></code></pre></div><h2 id="这如何修正-spr-035">这如何修正 SPR-035</h2>
<p>SPR-035 证明了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果要读连续子树，
</span></span><span style="display:flex;"><span>第一步不能丢 leaf address / path / locality。
</span></span></code></pre></div><p>这个结论仍然有用。</p>
<p>但它不是语言 fold 理论。</p>
<p>它只是一个 sanity check：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不要一开始就把顺序打散。
</span></span></code></pre></div><p>真正的语言 fold 理论应该从这里开始：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>哪些词在真实语言里互相吸附？
</span></span><span style="display:flex;"><span>哪些词形成局部块？
</span></span><span style="display:flex;"><span>哪些块会继续吸附？
</span></span><span style="display:flex;"><span>哪些结构最后坍缩成事件？
</span></span></code></pre></div><h2 id="下一步实验应该怎么做">下一步实验应该怎么做</h2>
<p>我建议下一步不是继续随机 toy。</p>
<p>而是用真实短句做 relation layout probe。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a cat is eating some food
</span></span><span style="display:flex;"><span>the dog is chasing a ball
</span></span><span style="display:flex;"><span>a child drinks some water
</span></span><span style="display:flex;"><span>the red apple fell
</span></span></code></pre></div><p>先不标复杂语法。
只标弱关系：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a-cat
</span></span><span style="display:flex;"><span>some-food
</span></span><span style="display:flex;"><span>is-eating
</span></span><span style="display:flex;"><span>cat-eating
</span></span><span style="display:flex;"><span>eating-food
</span></span><span style="display:flex;"><span>red-apple
</span></span></code></pre></div><p>然后训练或构造一个 latent layout，使得：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实相关词距离更近
</span></span><span style="display:flex;"><span>打乱组合距离更远
</span></span></code></pre></div><p>再观察：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>det-head 是否靠近
</span></span><span style="display:flex;"><span>aux-verb 是否靠近
</span></span><span style="display:flex;"><span>verb-object 是否靠近
</span></span><span style="display:flex;"><span>modifier-head 是否靠近
</span></span></code></pre></div><p>如果这些自然出现，才说明我们抓到了一点语言 fold 的规律。</p>
<p>然后再问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 如何二分这个平面？
</span></span><span style="display:flex;"><span>kernel 如何在这个平面上做局部卷积？
</span></span></code></pre></div><h2 id="当前-claim">当前 claim</h2>
<p>我会把这个理论写成一个 open claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-PLANE-C01:
</span></span><span style="display:flex;"><span>Language fold should be modeled first as latent placement / attraction over
</span></span><span style="display:flex;"><span>tokens and phrases. TreeHeap is a coordinate and partition system for computing
</span></span><span style="display:flex;"><span>over that placement, not the language law itself.
</span></span></code></pre></div><p>状态应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>open theory
</span></span></code></pre></div><p>因为我们还没有实验证据。</p>
<p>它现在只是更合理的理论方向。</p>
<h2 id="总结">总结</h2>
<p>这次修正后的核心是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语言理解不一定从语法槽位开始。
</span></span><span style="display:flex;"><span>它可能先是一个平面放置问题。
</span></span></code></pre></div><p>Transformer 从架构上看，也更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>动态共现矩阵
</span></span><span style="display:flex;"><span>soft relation graph
</span></span><span style="display:flex;"><span>latent attraction field
</span></span></code></pre></div><p>TreeHeap 则可以被重新理解为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对这个 latent field 做二分、寻址、卷积和坍缩的计算结构。
</span></span></code></pre></div><p>这比“语言就是二叉堆”更谦逊，也更接近发现世界规律。</p>
<p>一句话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先发现语言中的吸附和放置规律，
</span></span><span style="display:flex;"><span>再让 TreeHeap 成为它的计算坐标。
</span></span></code></pre></div><blockquote>
<p><strong>ARA</strong>: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/latent_plane_fold.md">latent plane theory</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/experiments.md">experiments</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-037] 可控流形：怎样把 TreeHeap 从一团乱调到可用结构</title>
      <link>https://www.grepcode.cn/spr/037-controllable-fold-manifold.html</link>
      <pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/037-controllable-fold-manifold.html</guid>
      <description>SPR-037 把 TreeHeap fold 从纯理论问题推进到产品调试问题：如果 kernel 有可调控制量，输出结构是否会从乱态沿着一个可测量的面走向稳定块？toy proof 显示低控制 F1 0.0828，最佳 F1 0.8148，对角线增益 0.7319。</description>
      <content:encoded><![CDATA[<h1 id="可控流形怎样把-treeheap-从一团乱调到可用结构">可控流形：怎样把 TreeHeap 从一团乱调到可用结构</h1>
<p>你刚才提出的观点，我认为非常关键：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>现在的 claim 应该是一个可控流形。
</span></span></code></pre></div><p>这句话解决了一个一直卡住我们的问题。</p>
<p>之前我们总是在两个层面之间跳：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数学层：plus / diff / compose / decompose / kernel
</span></span><span style="display:flex;"><span>产品层：能不能生成句子、能不能翻译、能不能像 Transformer 一样工作
</span></span></code></pre></div><p>中间缺一层。</p>
<p>这一层就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>控制变量 -&gt; 结构变化 -&gt; 产品功能涌现
</span></span></code></pre></div><p>也就是说，不要一上来就问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能不能直接生成正确句子？
</span></span></code></pre></div><p>而是先问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当我调整 kernel 的细节时，
</span></span><span style="display:flex;"><span>输出结构会不会从一团乱，
</span></span><span style="display:flex;"><span>逐步走向更稳定、更像产品可用结构的状态？
</span></span></code></pre></div><p>如果这个过程可控，我们就可以在控制过程中学习规律。
然后再修补数学 kernel。</p>
<p>这就是 SPR-037。</p>
<h2 id="什么叫可控流形">什么叫“可控流形”</h2>
<p>这里的“流形”不要先理解成高等几何里很复杂的对象。</p>
<p>可以先理解成一张可观察的调参地图：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>横轴：relation_weight
</span></span><span style="display:flex;"><span>纵轴：order_weight
</span></span><span style="display:flex;"><span>高度：fold 结构质量
</span></span></code></pre></div><p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>relation_weight = 0
</span></span><span style="display:flex;"><span>order_weight    = 0
</span></span></code></pre></div><p>kernel 什么都不相信，输出就接近随机。</p>
<p>再比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>relation_weight = 2
</span></span><span style="display:flex;"><span>order_weight    = 2
</span></span></code></pre></div><p>kernel 既相信词之间的关系场，也相信线性邻近，输出结构应该更稳定。</p>
<p>于是我们得到一张面：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>controls -&gt; fold quality
</span></span></code></pre></div><p>这张面就是当前意义上的“可控流形”。</p>
<h2 id="houming818-的补充梯度不一定只改参数">Houming818 的补充：梯度不一定只改参数</h2>
<p>下面这一段是 Houming818 提出的补充。</p>
<p>我把它整理成工程语言，但这个想法的责任归属要说清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>观点来源：Houming818
</span></span><span style="display:flex;"><span>整理解释：Codex Review
</span></span><span style="display:flex;"><span>当前状态：理论假设，尚未被 SPR-037 的 toy proof 直接证明
</span></span></code></pre></div><p>你提出的问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>既然说可控流形，
</span></span><span style="display:flex;"><span>那梯度信息从哪里来？
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>梯度是否一定要表现为普通神经网络那样的参数更新？
</span></span></code></pre></div><p>这非常关键。</p>
<p>因为如果 TreeHeap 只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>θ &lt;- θ - η ∇θ L
</span></span></code></pre></div><p>也就是只更新 kernel 参数，那它看起来和普通 MLP / Transformer 的训练方式太接近。</p>
<p>但你提出了另一种可能：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度也可以调整 heap 自身的平衡态。
</span></span></code></pre></div><p>比如一个很小的 heap state：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[2.0, 1.0, 3.0]
</span></span></code></pre></div><p>梯度来了以后，不一定是修改某个外部参数。</p>
<p>它也可能让当前 heap 变得更平衡：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[2.0, 1.0, 3.0]
</span></span><span style="display:flex;"><span>-&gt; [2.0, 1.5, 2.5]
</span></span><span style="display:flex;"><span>-&gt; [2.0, 1.8, 2.2]
</span></span></code></pre></div><p>这不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>改函数参数
</span></span></code></pre></div><p>而更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>调 heap state 的平衡性
</span></span></code></pre></div><h2 id="两种梯度参数梯度与状态梯度">两种梯度：参数梯度与状态梯度</h2>
<p>因此 TreeHeap 里至少要区分两类梯度。</p>
<p>第一类是普通参数梯度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>θ &lt;- θ - η ∇θ L
</span></span></code></pre></div><p>这里更新的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 参数
</span></span><span style="display:flex;"><span>compose 参数
</span></span><span style="display:flex;"><span>read 参数
</span></span><span style="display:flex;"><span>write 参数
</span></span><span style="display:flex;"><span>relation field 参数
</span></span></code></pre></div><p>这和普通深度学习类似。</p>
<p>第二类是 Houming818 提出的 heap 平衡梯度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H &lt;- H - η ∇H E(H)
</span></span></code></pre></div><p>这里更新的不是外部函数参数，而是当前 heap state：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[1]
</span></span><span style="display:flex;"><span>arr[2]
</span></span><span style="display:flex;"><span>arr[3]
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>每个 <code>arr[i]</code> 可以是一个向量。</p>
<p>它们可以在能量函数的驱动下移动。</p>
<h2 id="一个最小例子">一个最小例子</h2>
<p>假设我们定义左右平衡能量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E_balance = (left - right)^2
</span></span></code></pre></div><p>当前状态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root  = 2.0
</span></span><span style="display:flex;"><span>left  = 1.0
</span></span><span style="display:flex;"><span>right = 3.0
</span></span></code></pre></div><p>左右差很大：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left - right = -2.0
</span></span></code></pre></div><p>能量高。</p>
<p>如果只对 heap state 做梯度下降，系统会推动：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left 变大
</span></span><span style="display:flex;"><span>right 变小
</span></span></code></pre></div><p>于是得到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[2.0, 1.0, 3.0]
</span></span><span style="display:flex;"><span>-&gt; [2.0, 1.5, 2.5]
</span></span></code></pre></div><p>这个过程更像物理里的松弛：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>系统沿能量下降方向进入更稳定状态。
</span></span></code></pre></div><p>它不是先知道一个“目标 heap”，然后对目标 heap 求导。</p>
<p>它只需要知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 heap 的能量高不高。
</span></span></code></pre></div><h2 id="这是否绕开了目标-heap-可导的问题">这是否绕开了“目标 heap 可导”的问题</h2>
<p>部分绕开了。</p>
<p>更准确地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不需要目标 heap 本身可导。
</span></span></code></pre></div><p>但仍然需要一个可计算、可微分的能量函数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E(H)
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E_balance(H)              左右是否平衡
</span></span><span style="display:flex;"><span>E_parent_child(H)         父子是否一致
</span></span><span style="display:flex;"><span>E_relation_match(H, W)    heap 是否贴合世界/关系场
</span></span><span style="display:flex;"><span>E_entropy(P)              概率容器是否过早或过晚坍缩
</span></span><span style="display:flex;"><span>E_path_smooth(H)          路径上的状态是否连续
</span></span></code></pre></div><p>总能量可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E_total(H)
</span></span><span style="display:flex;"><span>  = E_balance(H)
</span></span><span style="display:flex;"><span>  + E_parent_child(H)
</span></span><span style="display:flex;"><span>  + E_relation_match(H, W)
</span></span><span style="display:flex;"><span>  + E_entropy(P)
</span></span></code></pre></div><p>然后做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H &lt;- H - η ∇H E_total(H)
</span></span></code></pre></div><p>这就把可导要求从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>目标结构必须可导
</span></span></code></pre></div><p>转移成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前状态的能量函数必须可导
</span></span></code></pre></div><p>这个差别很大。</p>
<h2 id="这对-treeheap-为什么重要">这对 TreeHeap 为什么重要</h2>
<p>如果这个方向成立，TreeHeap 的学习就不只有一种：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>参数学习：让 kernel 函数变强
</span></span><span style="display:flex;"><span>状态松弛：让 heap 自身进入平衡态
</span></span></code></pre></div><p>用一句话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>普通神经网络更像改函数。
</span></span><span style="display:flex;"><span>TreeHeap 还可能改结构状态。
</span></span></code></pre></div><p>这会让“可控流形”变得更像一个真实动力系统：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 参数决定能量地形
</span></span><span style="display:flex;"><span>heap state 在能量地形上滑动
</span></span><span style="display:flex;"><span>概率容器在合适时刻坍缩
</span></span><span style="display:flex;"><span>最后形成稳定结构
</span></span></code></pre></div><p>也就是说，SPR-037 现在测的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>手动控制变量能不能改变 fold 质量。
</span></span></code></pre></div><p>Houming818 的补充指向下一层：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>梯度能不能不是只改控制变量，
</span></span><span style="display:flex;"><span>而是推动 heap state 自己进入更好的平衡态。
</span></span></code></pre></div><h2 id="这个补充目前还没有证明">这个补充目前还没有证明</h2>
<p>需要强调：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SPR-037 的实验没有证明 heap state relaxation。
</span></span></code></pre></div><p>SPR-037 只证明了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>手动扫 relation_weight / order_weight 时，
</span></span><span style="display:flex;"><span>fold 质量存在一个可观测控制面。
</span></span></code></pre></div><p>Houming818 这里提出的是下一步 claim 候选：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不只有参数梯度路径，
</span></span><span style="display:flex;"><span>还可能存在 heap state 平衡梯度路径。
</span></span><span style="display:flex;"><span>这种路径可以在目标结构不可导时，
</span></span><span style="display:flex;"><span>通过可导能量函数完成结构松弛。
</span></span></code></pre></div><p>这应该进入后续实验，而不是混进当前结论。</p>
<p>一个最小 proof 可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 固定 kernel 参数
</span></span><span style="display:flex;"><span>2. 初始化一个不平衡 heap state
</span></span><span style="display:flex;"><span>3. 定义 balance / parent-child / relation 三类能量
</span></span><span style="display:flex;"><span>4. 只更新 H，不更新 θ
</span></span><span style="display:flex;"><span>5. 观察 heap 是否收敛到更稳定、可读、可坍缩的结构
</span></span></code></pre></div><p>如果这个实验通过，TreeHeap 会多出一条很有自己味道的学习路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不是只训练参数，
</span></span><span style="display:flex;"><span>而是让 heap 自己松弛到稳定结构。
</span></span></code></pre></div><h2 id="为什么这比直接生成更好">为什么这比直接生成更好</h2>
<p>假设我们直接让模型生成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the cat is running for a car
</span></span></code></pre></div><p>一开始可能输出很乱。</p>
<p>如果只有最终结果，我们只能说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型不行。
</span></span></code></pre></div><p>但如果有控制面，我们可以问更细的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>relation_weight 太低了吗？
</span></span><span style="display:flex;"><span>order_weight 太高了吗？
</span></span><span style="display:flex;"><span>collapse 太早了吗？
</span></span><span style="display:flex;"><span>noise 太大了吗？
</span></span><span style="display:flex;"><span>某个 subheap 没有被正确分割吗？
</span></span><span style="display:flex;"><span>kernel 缺少共轭/镜像/分解操作吗？
</span></span></code></pre></div><p>这就从“黑箱失败”变成“可诊断失败”。</p>
<p>产品工程最需要的不是一次神迹，而是可诊断、可修补、可复现。</p>
<h2 id="这次-toy-proof-怎么做">这次 toy proof 怎么做</h2>
<p>我没有直接跑 WMT。</p>
<p>这次只做一个最小 proof：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定几句短句和弱 block 目标，
</span></span><span style="display:flex;"><span>看 kernel 控制量能不能把 fold 从乱态推向稳定块。
</span></span></code></pre></div><p>短句包括：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the cat is running for a car
</span></span><span style="display:flex;"><span>a dog is chasing the ball
</span></span><span style="display:flex;"><span>the book that i bought yesterday is expensive
</span></span><span style="display:flex;"><span>some kids are playing in the park
</span></span></code></pre></div><p>注意，这里不是要证明完整语法。</p>
<p>我们只给一些弱 block：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the cat
</span></span><span style="display:flex;"><span>is running
</span></span><span style="display:flex;"><span>a car
</span></span><span style="display:flex;"><span>for a car
</span></span><span style="display:flex;"><span>the book
</span></span><span style="display:flex;"><span>i bought yesterday
</span></span><span style="display:flex;"><span>that i bought yesterday
</span></span><span style="display:flex;"><span>is expensive
</span></span></code></pre></div><p>这些 block 相当于“产品上希望看到的稳定局部结构”。</p>
<h2 id="kernel-的控制量">kernel 的控制量</h2>
<p>这次 kernel 只有两个主要旋钮。</p>
<h3 id="1-relation_weight">1. relation_weight</h3>
<p>表示 kernel 多相信“词之间的关系场”。</p>
<p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the -&gt; cat
</span></span><span style="display:flex;"><span>is -&gt; running
</span></span><span style="display:flex;"><span>a -&gt; car
</span></span><span style="display:flex;"><span>book -&gt; relative clause
</span></span></code></pre></div><p>如果 <code>relation_weight</code> 高，相关词更容易被合并。</p>
<h3 id="2-order_weight">2. order_weight</h3>
<p>表示 kernel 多相信线性邻近。</p>
<p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the cat
</span></span><span style="display:flex;"><span>is running
</span></span><span style="display:flex;"><span>a car
</span></span></code></pre></div><p>这些词本来就在句子里靠得近。</p>
<p>如果 <code>order_weight</code> 高，邻近词更容易合并。</p>
<h2 id="数学形式">数学形式</h2>
<p>每一步 fold 时，kernel 都要决定两个块 <code>A</code> 和 <code>B</code> 要不要合并。</p>
<p>这次的打分函数是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score(A, B)
</span></span><span style="display:flex;"><span>  = relation_weight * relation(A, B)
</span></span><span style="display:flex;"><span>  + order_weight    * order(A, B)
</span></span><span style="display:flex;"><span>  - balance_penalty
</span></span><span style="display:flex;"><span>  + noise
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>relation(A, B)
</span></span></code></pre></div><p>表示两个块在关系场里有多接近。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>order(A, B)
</span></span></code></pre></div><p>表示两个块在原始句子顺序里有多接近。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>balance_penalty
</span></span></code></pre></div><p>防止一开始就把很不均衡的大块小块乱合。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>noise
</span></span></code></pre></div><p>模拟不稳定扰动。</p>
<h2 id="实验变量">实验变量</h2>
<p>我们扫描：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>relation_weight in {0, 0.25, 0.5, 1, 2, 4}
</span></span><span style="display:flex;"><span>order_weight    in {0, 0.25, 0.5, 1, 2, 4}
</span></span><span style="display:flex;"><span>seeds = 64
</span></span></code></pre></div><p>评价指标是 block F1：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>预测出来的 block
</span></span><span style="display:flex;"><span>和我们给定的弱 target block
</span></span><span style="display:flex;"><span>有多少重合。
</span></span></code></pre></div><p>这不是 BLEU。</p>
<p>这也不是翻译质量。</p>
<p>它只是问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>fold 出来的局部结构是否接近目标块？
</span></span></code></pre></div><h2 id="实验结果">实验结果</h2>
<p>结果如下：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>low-control mean F1</td>
          <td style="text-align: right">0.0828</td>
      </tr>
      <tr>
          <td>best mean F1</td>
          <td style="text-align: right">0.8148</td>
      </tr>
      <tr>
          <td>high-sum-control mean F1</td>
          <td style="text-align: right">0.8148</td>
      </tr>
      <tr>
          <td>diagonal gain</td>
          <td style="text-align: right">0.7319</td>
      </tr>
      <tr>
          <td>product cells</td>
          <td style="text-align: right">22</td>
      </tr>
      <tr>
          <td>pilot pass</td>
          <td style="text-align: right">true</td>
      </tr>
  </tbody>
</table>
<p>最重要的是对角线：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">relation_weight</th>
          <th style="text-align: right">order_weight</th>
          <th style="text-align: right">mean F1</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0.00</td>
          <td style="text-align: right">0.00</td>
          <td style="text-align: right">0.0828</td>
      </tr>
      <tr>
          <td style="text-align: right">0.25</td>
          <td style="text-align: right">0.25</td>
          <td style="text-align: right">0.4036</td>
      </tr>
      <tr>
          <td style="text-align: right">0.50</td>
          <td style="text-align: right">0.50</td>
          <td style="text-align: right">0.6398</td>
      </tr>
      <tr>
          <td style="text-align: right">1.00</td>
          <td style="text-align: right">1.00</td>
          <td style="text-align: right">0.7603</td>
      </tr>
      <tr>
          <td style="text-align: right">2.00</td>
          <td style="text-align: right">2.00</td>
          <td style="text-align: right">0.8119</td>
      </tr>
      <tr>
          <td style="text-align: right">4.00</td>
          <td style="text-align: right">4.00</td>
          <td style="text-align: right">0.8148</td>
      </tr>
  </tbody>
</table>
<p>这个形状很重要。</p>
<p>它不是随机跳一下。</p>
<p>它显示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>控制量很弱 -&gt; 输出接近乱态
</span></span><span style="display:flex;"><span>控制量增强 -&gt; fold 结构明显变好
</span></span><span style="display:flex;"><span>控制量继续增强 -&gt; 进入平台期
</span></span></code></pre></div><p>这正是“可控流形”的最小证据。</p>
<h2 id="一个具体-trace">一个具体 trace</h2>
<p>对句子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the book that i bought yesterday is expensive
</span></span></code></pre></div><p>某次较好的 fold trace 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the + book
</span></span><span style="display:flex;"><span>i + bought
</span></span><span style="display:flex;"><span>is + expensive
</span></span><span style="display:flex;"><span>i bought + yesterday
</span></span><span style="display:flex;"><span>that + i bought yesterday
</span></span><span style="display:flex;"><span>the book + that i bought yesterday
</span></span><span style="display:flex;"><span>整句合并
</span></span></code></pre></div><p>这很接近我们想看的结构：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the book
</span></span><span style="display:flex;"><span>i bought yesterday
</span></span><span style="display:flex;"><span>that i bought yesterday
</span></span><span style="display:flex;"><span>the book that i bought yesterday
</span></span><span style="display:flex;"><span>is expensive
</span></span></code></pre></div><p>注意，这不是完整语法树。</p>
<p>但它说明 kernel 已经能把一些局部块先稳定下来。</p>
<p>这就是产品功能的早期形态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先不要完美理解整句，
</span></span><span style="display:flex;"><span>先把局部稳定块折出来。
</span></span></code></pre></div><h2 id="这证明了什么">这证明了什么</h2>
<p>这次 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-MANIFOLD-C01:
</span></span><span style="display:flex;"><span>If TreeHeap fold is driven by kernel controls over a latent relation field,
</span></span><span style="display:flex;"><span>product-like structure should emerge as a measurable control surface.
</span></span><span style="display:flex;"><span>Increasing relevant control variables should move output from noisy blocks
</span></span><span style="display:flex;"><span>toward stable target blocks on a toy relation task.
</span></span></code></pre></div><p>状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>supported pilot
</span></span></code></pre></div><p>它证明的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在一个透明 toy relation field 上，
</span></span><span style="display:flex;"><span>TreeHeap fold 可以被 kernel 控制量调节，
</span></span><span style="display:flex;"><span>并且结构质量会沿控制面明显提高。
</span></span></code></pre></div><p>换句话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我们可以把 TreeHeap 的失败变成可观测、可调试的失败。
</span></span></code></pre></div><p>这对工程很重要。</p>
<h2 id="这没有证明什么">这没有证明什么</h2>
<p>它没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经理解语言
</span></span><span style="display:flex;"><span>TreeHeap 已经能翻译
</span></span><span style="display:flex;"><span>TreeHeap 胜过 Transformer
</span></span><span style="display:flex;"><span>relation field 能无监督自动学出来
</span></span><span style="display:flex;"><span>这两个旋钮就是最终旋钮
</span></span></code></pre></div><p>尤其是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>relation field 这次是 toy 构造的。
</span></span></code></pre></div><p>这意味着下一步必须把 toy relation field 换成真实数据估计出来的 relation field。</p>
<p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>共现窗口
</span></span><span style="display:flex;"><span>masked token restoration
</span></span><span style="display:flex;"><span>弱依存关系
</span></span><span style="display:flex;"><span>contrastive phrase pairs
</span></span><span style="display:flex;"><span>短句人工弱标注
</span></span></code></pre></div><h2 id="对-treeheap-路线的意义">对 TreeHeap 路线的意义</h2>
<p>现在我更赞同你的判断：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>代数逻辑和产品逻辑不能分太开。
</span></span></code></pre></div><p>但也不能直接从代数跳到 WMT。</p>
<p>中间要有一层：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap Structure Lens
</span></span></code></pre></div><p>它应该能显示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 token/block 的邻近关系
</span></span><span style="display:flex;"><span>当前 fold trace
</span></span><span style="display:flex;"><span>每个 merge 的 energy
</span></span><span style="display:flex;"><span>每个 stop/left/right 的概率
</span></span><span style="display:flex;"><span>哪些结构稳定
</span></span><span style="display:flex;"><span>哪些结构还在叠加
</span></span><span style="display:flex;"><span>哪些控制量改变后结构变好
</span></span></code></pre></div><p>也就是说，产品上先做一个“结构透镜”。</p>
<p>不是先做最终翻译器。</p>
<h2 id="下一步">下一步</h2>
<p>我建议下一步不是继续加 toy trick。</p>
<p>而是把这个控制面放到真实数据上。</p>
<p>最小版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入真实短句
</span></span><span style="display:flex;"><span>从语料共现或 masked restoration 估计 relation field
</span></span><span style="display:flex;"><span>用 TreeHeap kernel fold
</span></span><span style="display:flex;"><span>扫 relation/order/collapse 控制量
</span></span><span style="display:flex;"><span>看 block F1、稳定性、能量是否形成可控面
</span></span></code></pre></div><p>如果真实数据也有类似曲面：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>低控制乱
</span></span><span style="display:flex;"><span>中控制变好
</span></span><span style="display:flex;"><span>高控制平台
</span></span></code></pre></div><p>那我们就有了继续推进 S1 的依据。</p>
<p>如果没有，也很好：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>说明 toy relation field 太人工，
</span></span><span style="display:flex;"><span>或者 kernel 缺少关键算子，
</span></span><span style="display:flex;"><span>或者真实语言 fold 不是这个控制方向。
</span></span></code></pre></div><p>这就是 ARA 的价值。</p>
<h2 id="一句话总结">一句话总结</h2>
<p>SPR-037 的结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不能只证明自己有代数操作。
</span></span><span style="display:flex;"><span>它还必须证明这些操作能被控制，
</span></span><span style="display:flex;"><span>并且控制过程能让产品可见结构逐步涌现。
</span></span></code></pre></div><p>这次 toy proof 给了一个正信号：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>low-control F1 = 0.0828
</span></span><span style="display:flex;"><span>best F1       = 0.8148
</span></span><span style="display:flex;"><span>diagonal gain = 0.7319
</span></span></code></pre></div><p>所以当前更清晰的路线是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先建立可控结构透镜，
</span></span><span style="display:flex;"><span>再用真实数据学习 relation field，
</span></span><span style="display:flex;"><span>最后才谈生成和翻译。
</span></span></code></pre></div><p>May the Code be with us.</p>
<blockquote>
<p><strong>ARA</strong>: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/controllable_manifold.md">controllable manifold</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/src/s1_controllable_manifold_probe.py">experiment script</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/s1_controllable_manifold_probe">evidence</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-038] 梯度到底改什么：TreeHeap 状态松弛的边界</title>
      <link>https://www.grepcode.cn/spr/038-heap-state-relaxation.html</link>
      <pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/038-heap-state-relaxation.html</guid>
      <description>SPR-038 修订版：区分参数 TreeHeap、激活 TreeHeap、物理地址、语义地址和 kernel；说明本实验只证明状态松弛，不证明 kernel 参数学习。</description>
      <content:encoded><![CDATA[<h1 id="梯度到底改什么treeheap-状态松弛的边界">梯度到底改什么：TreeHeap 状态松弛的边界</h1>
<p>这篇是 SPR-038 的修订版。</p>
<p>原版里有一个说法不够严谨：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>函数不变。
</span></span><span style="display:flex;"><span>地址规则不变。
</span></span><span style="display:flex;"><span>kernel 系数不变。
</span></span><span style="display:flex;"><span>只有 arr[i] 的状态在移动。
</span></span></code></pre></div><p>Houming818 指出这里混淆了几层东西。</p>
<p>这个批评是对的。</p>
<p>TreeHeap 里至少要区分五个对象：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta  = parameter TreeHeap，也就是模型参数
</span></span><span style="display:flex;"><span>H      = activation / memory TreeHeap，也就是当前样本上的状态
</span></span><span style="display:flex;"><span>A      = physical address rule，比如 left(i)=2i, right(i)=2i+1
</span></span><span style="display:flex;"><span>K_Theta = kernel operator，由参数 Theta 定义的局部卷积算子
</span></span><span style="display:flex;"><span>L      = scalar loss / energy，用来产生梯度
</span></span></code></pre></div><p>类比线性回归：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>y = w*x + b
</span></span></code></pre></div><p>普通机器学习里，<code>w</code> 和 <code>b</code> 是参数。</p>
<p>放到 TreeHeap 口径里，<code>w</code> 和 <code>b</code> 可以不是两个孤立标量，而是一个很小的参数堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta = {
</span></span><span style="display:flex;"><span>  w,
</span></span><span style="display:flex;"><span>  b
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>所以“参数就是一个 TreeHeap”是合理的。</p>
<p>更一般地：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next = K_Theta(H, A)
</span></span><span style="display:flex;"><span>L = loss(H_next)
</span></span></code></pre></div><p>如果训练模型参数，就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta &lt;- Theta - eta * grad_Theta L
</span></span></code></pre></div><p>如果调整当前 heap 状态，就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H &lt;- H - eta * grad_H L
</span></span></code></pre></div><p>这两件事不是一回事。</p>
<h2 id="物理地址和语义地址">物理地址和语义地址</h2>
<p>原文说“地址规则不变”，也需要修正。</p>
<p>严格说，不变的是物理寻址规则：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left(i)  = 2i
</span></span><span style="display:flex;"><span>right(i) = 2i + 1
</span></span></code></pre></div><p>也就是数组位置和父子索引关系没有变。</p>
<p>但是 <code>arr[i]</code> 的向量状态一旦变了，它在语义空间里的位置当然也变了。</p>
<p>所以应该写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>物理地址 A 不变。
</span></span><span style="display:flex;"><span>语义状态 H[i] 可变。
</span></span><span style="display:flex;"><span>语义地址 / 向量位置会随 H[i] 改变。
</span></span></code></pre></div><p>这点很重要。</p>
<p>否则会误以为 SPR-038 证明了“地址不变还学习了结构”。</p>
<p>它没有。</p>
<p>它只证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在固定物理地址规则下，当前 heap state 可以被一个 scalar energy 推动，向低能量状态移动。
</span></span></code></pre></div><h2 id="spr-038-到底证明了什么">SPR-038 到底证明了什么</h2>
<p>SPR-038 的 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-RELAX-C01:
</span></span><span style="display:flex;"><span>A differentiable energy over the current TreeHeap state can generate gradients
</span></span><span style="display:flex;"><span>that relax arr[i] toward a lower-energy equilibrium while kernel parameters
</span></span><span style="display:flex;"><span>and address rules remain fixed.
</span></span></code></pre></div><p>修订后，这句话要更精确地理解为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta 不更新。
</span></span><span style="display:flex;"><span>K_Theta 不更新。
</span></span><span style="display:flex;"><span>物理地址规则 A 不更新。
</span></span><span style="display:flex;"><span>当前样本的 heap state H 更新。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这不是参数学习。
</span></span><span style="display:flex;"><span>这是状态松弛。
</span></span></code></pre></div><p>它更像一个物理系统：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定能量函数 E(H)，
</span></span><span style="display:flex;"><span>当前状态 H 沿着 -grad_H E(H) 移动。
</span></span></code></pre></div><h2 id="proof-1标量能量只说明-loss-能产生梯度">Proof 1：标量能量只说明 loss 能产生梯度</h2>
<p>第一个 toy 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root  = 2.0
</span></span><span style="display:flex;"><span>left  = 1.0
</span></span><span style="display:flex;"><span>right = 3.0
</span></span></code></pre></div><p>能量函数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E = (left - right)^2
</span></span><span style="display:flex;"><span>  + (root - (left + right) / 2)^2
</span></span></code></pre></div><p>梯度下降后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[2.0, 1.0, 3.0]
</span></span><span style="display:flex;"><span>-&gt; [2.0, 2.0, 2.0]
</span></span></code></pre></div><p>实验结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>initial energy = 4.0
</span></span><span style="display:flex;"><span>final energy   = 9.86e-31
</span></span><span style="display:flex;"><span>energy ratio   = 2.47e-31
</span></span></code></pre></div><p>这个 proof 的意义很窄：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只要有 scalar loss / energy，
</span></span><span style="display:flex;"><span>就能对当前 H 求梯度，
</span></span><span style="display:flex;"><span>并让 H 沿低能量方向移动。
</span></span></code></pre></div><p>它不说明 kernel 结构已经学习了。</p>
<p>它也不说明参数 TreeHeap <code>Theta</code> 已经被训练。</p>
<h2 id="proof-27-节点-treeheap-状态松弛">Proof 2：7 节点 TreeHeap 状态松弛</h2>
<p>第二个 toy 使用 7 节点树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        1
</span></span><span style="display:flex;"><span>      /   \
</span></span><span style="display:flex;"><span>     2     3
</span></span><span style="display:flex;"><span>    / \   / \
</span></span><span style="display:flex;"><span>   4   5 6   7
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>4,5,6,7 是固定叶子向量
</span></span><span style="display:flex;"><span>1,2,3 是可更新 internal heap state
</span></span></code></pre></div><p>注意：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>更新的是 H[1], H[2], H[3]
</span></span><span style="display:flex;"><span>不是更新 Theta
</span></span></code></pre></div><p>能量有两部分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E_consistency:
</span></span><span style="display:flex;"><span>  parent 应该接近 children 的局部组合
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>E_relation:
</span></span><span style="display:flex;"><span>  internal node 应该接近固定 relation anchor
</span></span></code></pre></div><p>总能量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E_total(H) = E_consistency(H) + E_relation(H)
</span></span></code></pre></div><p>32 次随机初始化结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>scalar energy ratio</td>
          <td style="text-align: right">2.47e-31</td>
      </tr>
      <tr>
          <td>mean vector energy ratio</td>
          <td style="text-align: right">1.24e-13</td>
      </tr>
      <tr>
          <td>max vector energy ratio</td>
          <td style="text-align: right">3.69e-13</td>
      </tr>
      <tr>
          <td>mean centroid error drop</td>
          <td style="text-align: right">3.0393</td>
      </tr>
      <tr>
          <td>pass rate</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>pilot pass</td>
          <td style="text-align: right">true</td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在这个 toy 能量场里，
</span></span><span style="display:flex;"><span>TreeHeap state H 可以稳定收敛。
</span></span></code></pre></div><p>但仍然要强调：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这不是 kernel 参数学习。
</span></span></code></pre></div><h2 id="kernel-卷积到底应该是什么">kernel 卷积到底应该是什么</h2>
<p>Houming818 给了一个更贴切的例子。</p>
<p>还是这棵树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        1
</span></span><span style="display:flex;"><span>      /   \
</span></span><span style="display:flex;"><span>     2     3
</span></span><span style="display:flex;"><span>    / \   / \
</span></span><span style="display:flex;"><span>   4   5 6   7
</span></span></code></pre></div><p>如果 kernel 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[root, left, right] = [1, 1, 1]
</span></span></code></pre></div><p>对每个内部节点做局部卷积：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H&#39;[1] = 1*H[1] + 1*H[2] + 1*H[3] = 1 + 2 + 3 = 6
</span></span><span style="display:flex;"><span>H&#39;[2] = 1*H[2] + 1*H[4] + 1*H[5] = 2 + 4 + 5 = 11
</span></span><span style="display:flex;"><span>H&#39;[3] = 1*H[3] + 1*H[6] + 1*H[7] = 3 + 6 + 7 = 16
</span></span></code></pre></div><p>叶子暂时保持不变，则得到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[6, 11, 16, 4, 5, 6, 7]
</span></span></code></pre></div><p>这个例子比 SPR-038 更接近 TreeHeap kernel 的核心。</p>
<p>因为 kernel 不是抽象地“调状态”，而是在做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>观察一个局部 subheap
</span></span><span style="display:flex;"><span>计算一个新 state
</span></span><span style="display:flex;"><span>把局部结构信息写回当前节点
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S_i = [H[i], H[left(i)], H[right(i)]]
</span></span><span style="display:flex;"><span>H&#39;[i] = K_Theta(S_i)
</span></span></code></pre></div><p>如果 kernel 是线性的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H&#39;[i] = theta_root * H[i]
</span></span><span style="display:flex;"><span>      + theta_left * H[left(i)]
</span></span><span style="display:flex;"><span>      + theta_right * H[right(i)]
</span></span></code></pre></div><p>那么 <code>[1,1,1]</code> 就是一个最简单的 TreeHeap 卷积核。</p>
<h2 id="和-transformer-的关系">和 Transformer 的关系</h2>
<p>Transformer 里常见的核心相似度是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score(i,j) = Q_i dot K_j
</span></span></code></pre></div><p>它是在 flat token 空间上做全连接关系计算。</p>
<p>TreeHeap kernel 可以看成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score / state = K_Theta(root, left, right)
</span></span></code></pre></div><p>也就是在局部子堆上做结构化关系计算。</p>
<p>所以更合理的类比不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经替代 Transformer
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Transformer 在 flat all-to-all token 图上学习共现关系。
</span></span><span style="display:flex;"><span>TreeHeap 希望在 address/path/subheap 结构上学习局部卷积关系。
</span></span></code></pre></div><p>如果 <code>K_Theta</code> 学到的是类似 <code>[1,1,1]</code>、<code>[0.2,0.5,0.3]</code>、镜像 kernel、stop/left/right kernel 这样的结构算子，那么 TreeHeap 才真正有自己的归纳偏置。</p>
<h2 id="修订后的结论">修订后的结论</h2>
<p>SPR-038 支持的结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的当前状态 H 可以在 scalar energy 下做梯度松弛。
</span></span></code></pre></div><p>SPR-038 不支持的结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 参数 Theta 已经能通过梯度学会卷积结构。
</span></span></code></pre></div><p>所以 SPR-038 的位置应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>状态梯度 proof
</span></span><span style="display:flex;"><span>不是参数学习 proof
</span></span></code></pre></div><p>下一步 SPR-039 应该转向：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>parameter TreeHeap / kernel Theta learning proof
</span></span></code></pre></div><p>最小实验就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入 H = [1,2,3,4,5,6,7]
</span></span><span style="display:flex;"><span>目标 H&#39; = [6,11,16,4,5,6,7]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>模型不知道 kernel = [1,1,1]
</span></span><span style="display:flex;"><span>只通过 loss 学 theta_root, theta_left, theta_right
</span></span></code></pre></div><p>如果训练后得到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta ~= [1,1,1]
</span></span></code></pre></div><p>那才说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 的参数可以通过 loss / gradient 学到局部卷积规则。
</span></span></code></pre></div><p>这会成为 SPR-039 的核心。</p>
<blockquote>
<p><strong>ARA</strong>: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/heap_state_relaxation.md">heap-state relaxation</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/s1_heap_state_relaxation_probe">evidence</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-039] 参数也是 TreeHeap：kernel 自己学会了卷积</title>
      <link>https://www.grepcode.cn/spr/039-parameter-treeheap-kernel-learning.html</link>
      <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/039-parameter-treeheap-kernel-learning.html</guid>
      <description>SPR-039 proof：把 SPR-038 的状态松弛和真正的参数学习分开，证明 parameter TreeHeap Theta 可以通过梯度学会局部 subheap 卷积核。</description>
      <content:encoded><![CDATA[<h1 id="参数也是-treeheapkernel-自己学会了卷积">参数也是 TreeHeap：kernel 自己学会了卷积</h1>
<p>SPR-038 之后，Houming818 提了一个关键修正：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>参数本身也应该是 TreeHeap。
</span></span></code></pre></div><p>这个修正很重要。</p>
<p>SPR-038 做的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H &lt;- H - eta * grad_H L
</span></span></code></pre></div><p>也就是更新当前样本的 heap state。</p>
<p>SPR-039 要证明的是另一件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta &lt;- Theta - eta * grad_Theta L
</span></span></code></pre></div><p>也就是更新 kernel 的参数 TreeHeap。</p>
<p>这两件事必须分开。</p>
<h2 id="对象定义">对象定义</h2>
<p>这次我们严格区分：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>Theta</code></td>
          <td>parameter TreeHeap，模型参数的载体</td>
      </tr>
      <tr>
          <td><code>H</code></td>
          <td>activation / memory TreeHeap，当前样本状态</td>
      </tr>
      <tr>
          <td><code>A</code></td>
          <td>physical address rule，比如 <code>left(i)=2i</code></td>
      </tr>
      <tr>
          <td><code>K_Theta</code></td>
          <td>由 <code>Theta</code> 定义的局部 kernel operator</td>
      </tr>
      <tr>
          <td><code>L</code></td>
          <td>scalar loss，用来产生梯度</td>
      </tr>
  </tbody>
</table>
<p>计算过程是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_next = K_Theta(H, A)
</span></span><span style="display:flex;"><span>L = loss(H_next, target)
</span></span><span style="display:flex;"><span>Theta &lt;- Theta - eta * grad_Theta L
</span></span></code></pre></div><p>这才是参数学习。</p>
<h2 id="最小-treeheap-卷积任务">最小 TreeHeap 卷积任务</h2>
<p>我们使用一棵 7 节点树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        1
</span></span><span style="display:flex;"><span>      /   \
</span></span><span style="display:flex;"><span>     2     3
</span></span><span style="display:flex;"><span>    / \   / \
</span></span><span style="display:flex;"><span>   4   5 6   7
</span></span></code></pre></div><p>输入例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = [1,2,3,4,5,6,7]
</span></span></code></pre></div><p>隐藏 kernel 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[root, left, right] = [1, 1, 1]
</span></span></code></pre></div><p>所以内部节点的目标是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H&#39;[1] = H[1] + H[2] + H[3] = 6
</span></span><span style="display:flex;"><span>H&#39;[2] = H[2] + H[4] + H[5] = 11
</span></span><span style="display:flex;"><span>H&#39;[3] = H[3] + H[6] + H[7] = 16
</span></span></code></pre></div><p>叶子保持不变：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H&#39; = [6,11,16,4,5,6,7]
</span></span></code></pre></div><p>关键点是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型一开始不知道 [1,1,1]。
</span></span></code></pre></div><p>它只有参数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta = [theta_root, theta_left, theta_right]
</span></span></code></pre></div><p>模型计算：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Y[i] = theta_root * H[i]
</span></span><span style="display:flex;"><span>     + theta_left * H[left(i)]
</span></span><span style="display:flex;"><span>     + theta_right * H[right(i)]
</span></span></code></pre></div><p>loss：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L = mean_squared_error(Y, target)
</span></span></code></pre></div><p>如果训练后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta ~= [1,1,1]
</span></span></code></pre></div><p>就说明 kernel 参数真的学到了这个局部卷积规则。</p>
<h2 id="实验结果">实验结果</h2>
<p>实验在 <code>io.grepcode.cn</code> 上执行。</p>
<p>证据目录：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/evidence/s1_kernel_parameter_learning_probe/
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>pilot pass</td>
          <td style="text-align: right">true</td>
      </tr>
      <tr>
          <td>learned theta</td>
          <td style="text-align: right"><code>[0.9999999999999998, 0.9999999999999998, 1.0000000000000004]</code></td>
      </tr>
      <tr>
          <td>theta L2 error</td>
          <td style="text-align: right"><code>5.44e-16</code></td>
      </tr>
      <tr>
          <td>theta delta L2</td>
          <td style="text-align: right"><code>1.15777</code></td>
      </tr>
      <tr>
          <td>TreeHeap test MSE</td>
          <td style="text-align: right"><code>8.78e-31</code></td>
      </tr>
      <tr>
          <td>TreeHeap OOD MSE</td>
          <td style="text-align: right"><code>8.93e-30</code></td>
      </tr>
      <tr>
          <td>wrong-address test MSE</td>
          <td style="text-align: right"><code>5.92848</code></td>
      </tr>
      <tr>
          <td>flat-global test MSE</td>
          <td style="text-align: right"><code>3.56010</code></td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta 确实移动了。
</span></span><span style="display:flex;"><span>Theta 学回了隐藏 kernel [1,1,1]。
</span></span><span style="display:flex;"><span>正确地址结构下 test / OOD 误差接近 0。
</span></span><span style="display:flex;"><span>错误地址结构明显失败。
</span></span><span style="display:flex;"><span>不看 left/right subheap 的 matched-size flat baseline 也失败。
</span></span></code></pre></div><h2 id="为什么-wrong-address-很重要">为什么 wrong-address 很重要</h2>
<p>如果只是让模型学一个线性函数，它当然可能会过拟合。</p>
<p>所以这次放了 wrong-address baseline。</p>
<p>正确 kernel 看的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>node 1 -&gt; [1,2,3]
</span></span><span style="display:flex;"><span>node 2 -&gt; [2,4,5]
</span></span><span style="display:flex;"><span>node 3 -&gt; [3,6,7]
</span></span></code></pre></div><p>wrong-address 看的是错误局部结构。</p>
<p>结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap test MSE       ~= 0
</span></span><span style="display:flex;"><span>wrong-address test MSE  = 5.92848
</span></span></code></pre></div><p>这说明收益不是来自“随便三个数做线性回归”，而是来自：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>正确的 TreeHeap address / subheap 结构。
</span></span></code></pre></div><h2 id="和-spr-038-的区别">和 SPR-038 的区别</h2>
<p>SPR-038：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>更新 H
</span></span><span style="display:flex;"><span>不更新 Theta
</span></span><span style="display:flex;"><span>证明 state relaxation
</span></span></code></pre></div><p>SPR-039：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>更新 Theta
</span></span><span style="display:flex;"><span>不靠移动当前 H 来作弊
</span></span><span style="display:flex;"><span>证明 kernel parameter learning
</span></span></code></pre></div><p>所以 SPR-039 补上了 SPR-038 留下的缺口。</p>
<p>现在我们可以说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 不只是状态能被梯度松弛。
</span></span><span style="display:flex;"><span>TreeHeap 的 kernel 参数也能被梯度训练。
</span></span></code></pre></div><h2 id="和-transformer-的关系">和 Transformer 的关系</h2>
<p>Transformer 的 attention 可以粗略看成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>score(i,j) = Q_i dot K_j
</span></span></code></pre></div><p>它在 flat token 图上学习关系。</p>
<p>TreeHeap kernel 的形式是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>state = K_Theta(root, left, right)
</span></span></code></pre></div><p>它在局部 subheap 上学习关系。</p>
<p>这次 proof 证明了最小版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_Theta 可以通过梯度学到一个局部结构算子。
</span></span></code></pre></div><p>这不是说 TreeHeap 已经打败 Transformer。</p>
<p>更准确地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 和普通 ML 一样，可以通过 loss / gradient 学习函数；
</span></span><span style="display:flex;"><span>但它学习的函数天然绑定 address / path / subheap 结构。
</span></span></code></pre></div><h2 id="claim-状态">Claim 状态</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-KERNEL-LEARN-C01:
</span></span><span style="display:flex;"><span>A parameter TreeHeap Theta can learn a local subheap convolution rule
</span></span><span style="display:flex;"><span>from scalar loss and gradient.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>status: supported pilot
</span></span></code></pre></div><h2 id="还没有证明什么">还没有证明什么</h2>
<p>这次没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语言理解
</span></span><span style="display:flex;"><span>WMT 翻译
</span></span><span style="display:flex;"><span>真实 relation field
</span></span><span style="display:flex;"><span>multi-kernel specialization
</span></span><span style="display:flex;"><span>TreeHeap 胜过所有更大的 flat model
</span></span></code></pre></div><p>尤其最后一点要诚实：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个更大的 flat linear model 当然可能拟合这个 toy。
</span></span></code></pre></div><p>这次 proof 的重点不是“所有 flat 都输”。</p>
<p>重点是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在 TreeHeap 的 address / subheap 结构里，
</span></span><span style="display:flex;"><span>共享 kernel 参数 Theta 可以被梯度学出来。
</span></span></code></pre></div><p>这是一个必要地基。</p>
<h2 id="下一步">下一步</h2>
<p>SPR-039 之后，下一步应该扩展三件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. scalar kernel -&gt; vector / matrix kernel
</span></span><span style="display:flex;"><span>2. clean sum target -&gt; noisy restore / mask restore
</span></span><span style="display:flex;"><span>3. single kernel -&gt; multi-kernel specialization
</span></span></code></pre></div><p>如果这些继续成立，TreeHeap 才能从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能学一个 toy 卷积核
</span></span></code></pre></div><p>走向：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能学真实数据里的结构 kernel
</span></span></code></pre></div><h2 id="一句话总结">一句话总结</h2>
<p>SPR-039 的结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>参数 TreeHeap Theta 可以通过 scalar loss 和 gradient，
</span></span><span style="display:flex;"><span>学会一个局部 subheap 卷积核。
</span></span></code></pre></div><p>这一步把 SPR-038 的状态松弛，推进到了真正的参数学习。</p>
<blockquote>
<p><strong>ARA</strong>: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/kernel_parameter_learning.md">kernel parameter learning</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/s1_kernel_parameter_learning_probe">evidence</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-040] TreeHeap kernel 的 mirror 手性翻转：几何翻转如何变成代数置换</title>
      <link>https://www.grepcode.cn/spr/040-mirror-kernel-symmetry.html</link>
      <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/040-mirror-kernel-symmetry.html</guid>
      <description>SPR-040 proof：证明 TreeHeap 局部卷积在左右 mirror 下可以由堆地址置换和 kernel 槽位置换实现，并且 mirrored kernel 可以从数据中学回。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-kernel-的-mirror-手性翻转几何翻转如何变成代数置换">TreeHeap kernel 的 mirror 手性翻转：几何翻转如何变成代数置换</h1>
<p>先统一术语。</p>
<p>之前草稿里用了“共轭”这个词。这个词容易让人想到复数共轭、矩阵共轭、群表示里的 conjugation。SPR-040 现在不再这样叫。</p>
<p>这里讨论的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror / chiral flip / 左右镜像翻转
</span></span></code></pre></div><p>也就是把一棵 TreeHeap 的 left 和 right 对换。</p>
<p>这篇文章要证明一件很具体的事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>几何上的左右翻转，
</span></span><span style="display:flex;"><span>可以在代数层面变成两个置换：
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>1. 堆地址置换
</span></span><span style="display:flex;"><span>2. kernel 槽位置换
</span></span></code></pre></div><p>这不是语言理解 proof，也不是 WMT proof。它是 TreeHeap kernel 工具箱里的一个基础 proof。</p>
<p>这次收束以后，SPR-040 也不准备升级成旋转、3D fold 或平面投影 proof。我们先只托付一个最小事实：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror 会交换 left/right 的结构方向；
</span></span><span style="display:flex;"><span>loss 可以把这个 mirrored slot assignment 学回参数里。
</span></span></code></pre></div><p>这已经够重要，因为它说明 kernel 的 <code>root/left/right</code> 不是三个匿名标量位置，而是树上的局部结构方向。</p>
<h2 id="deepseek-回测后的收束">DeepSeek 回测后的收束</h2>
<p>DeepSeek / Runner 做了 ARA 可靠性审阅，把 SPR-040 评为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>中等可靠。
</span></span></code></pre></div><p>这个评价是合理的。</p>
<p>因为 SPR-040 的 evidence 很清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flipped-kernel error 接近机器精度。
</span></span><span style="display:flex;"><span>unflipped-kernel error 明显变大。
</span></span><span style="display:flex;"><span>loss 能学回 [root,right,left]。
</span></span></code></pre></div><p>但它的范围也很窄：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这是结构赋值级别的 proof。
</span></span><span style="display:flex;"><span>不是旋转 proof。
</span></span><span style="display:flex;"><span>不是 3D fold proof。
</span></span><span style="display:flex;"><span>也不是“模型自己学会何时翻转整棵树”的 proof。
</span></span></code></pre></div><p>换句话说，现在证明的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定 mirror 这种结构变换后，
</span></span><span style="display:flex;"><span>kernel 的 left/right 槽位应该怎样跟着变。
</span></span></code></pre></div><p>还没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型自己发现某个句子需要 mirror。
</span></span><span style="display:flex;"><span>模型自己决定 mirror 发生在哪个 subheap。
</span></span><span style="display:flex;"><span>模型自己决定递归 mirror 到多深。
</span></span></code></pre></div><p>这个边界很重要。它让 SPR-040 更专业，也更不容易过度解释。</p>
<h2 id="为什么要证明-mirror">为什么要证明 mirror</h2>
<p>SPR-039 证明了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>参数 TreeHeap Theta 可以通过梯度学习一个局部卷积 kernel。
</span></span></code></pre></div><p>例如在 7 节点堆上：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        1
</span></span><span style="display:flex;"><span>      /   \
</span></span><span style="display:flex;"><span>     2     3
</span></span><span style="display:flex;"><span>    / \   / \
</span></span><span style="display:flex;"><span>   4   5 6   7
</span></span></code></pre></div><p>一个最小 kernel 可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>theta = [theta_root, theta_left, theta_right]
</span></span></code></pre></div><p>它在某个内部节点 <code>i</code> 上做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_theta(H)[i]
</span></span><span style="display:flex;"><span>  = theta_root  * H[i]
</span></span><span style="display:flex;"><span>  + theta_left  * H[left(i)]
</span></span><span style="display:flex;"><span>  + theta_right * H[right(i)]
</span></span></code></pre></div><p>如果 <code>theta = [1,1,1]</code>，它就是局部求和。</p>
<p>但 Houming818 提醒了一个更关键的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 不能只会求和。
</span></span><span style="display:flex;"><span>它应该能表达结构操作。
</span></span></code></pre></div><p>比如，左右镜像翻转。</p>
<p>如果 TreeHeap 真的是结构化空间，那么：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>树翻了，
</span></span><span style="display:flex;"><span>算子也应该按结构翻。
</span></span></code></pre></div><p>这就是 SPR-040。</p>
<h2 id="mirror-在堆地址上的定义">mirror 在堆地址上的定义</h2>
<p>仍然看这棵 7 节点完全二叉堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        1
</span></span><span style="display:flex;"><span>      /   \
</span></span><span style="display:flex;"><span>     2     3
</span></span><span style="display:flex;"><span>    / \   / \
</span></span><span style="display:flex;"><span>   4   5 6   7
</span></span></code></pre></div><p>左右 mirror 后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        1
</span></span><span style="display:flex;"><span>      /   \
</span></span><span style="display:flex;"><span>     3     2
</span></span><span style="display:flex;"><span>    / \   / \
</span></span><span style="display:flex;"><span>   7   6 5   4
</span></span></code></pre></div><p>所以地址映射是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>M(1) = 1
</span></span><span style="display:flex;"><span>M(2) = 3
</span></span><span style="display:flex;"><span>M(3) = 2
</span></span><span style="display:flex;"><span>M(4) = 7
</span></span><span style="display:flex;"><span>M(5) = 6
</span></span><span style="display:flex;"><span>M(6) = 5
</span></span><span style="display:flex;"><span>M(7) = 4
</span></span></code></pre></div><p>如果用数组表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = [1,2,3,4,5,6,7]
</span></span><span style="display:flex;"><span>M(H) = [1,3,2,7,6,5,4]
</span></span></code></pre></div><p>这不是随便重排。</p>
<p>它是一个保持树结构的左右镜像。</p>
<p>代数上可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H&#39; = P_m H
</span></span></code></pre></div><p>其中 <code>P_m</code> 是堆地址的置换矩阵。对于 7 节点堆，它对应：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_m = (0, 2, 1, 6, 5, 4, 3)
</span></span></code></pre></div><p>这里用的是 zero-based index。</p>
<h2 id="mirror-在-kernel-槽位上的定义">mirror 在 kernel 槽位上的定义</h2>
<p>局部 kernel 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>theta = [root, left, right]
</span></span></code></pre></div><p>如果树左右翻转，left 和 right 的意义也要交换。</p>
<p>所以 kernel 也要 mirror：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_lr(theta) = [root, right, left]
</span></span></code></pre></div><p>写成矩阵：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_lr =
</span></span><span style="display:flex;"><span>[[1,0,0],
</span></span><span style="display:flex;"><span> [0,0,1],
</span></span><span style="display:flex;"><span> [0,1,0]]
</span></span></code></pre></div><p>这就是这篇 proof 的重点。</p>
<p>不是只翻树。</p>
<p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>翻树地址 P_m
</span></span><span style="display:flex;"><span>同时翻 kernel 槽位 P_lr
</span></span></code></pre></div><h2 id="claim">Claim</h2>
<p>SPR-040 的 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-KERNEL-MIRROR-C01:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TreeHeap local convolution is equivariant under mirror / chiral flip:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>P_m K_theta(H) = K_{P_lr theta}(P_m H)
</span></span></code></pre></div><p>中文说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先卷积，再 mirror
</span></span><span style="display:flex;"><span>等价于
</span></span><span style="display:flex;"><span>先 mirror，再用 mirror 后的 kernel 卷积。
</span></span></code></pre></div><p>这就是“几何操作由代数操作实现”。</p>
<h2 id="一个具体例子">一个具体例子</h2>
<p>输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = [1,2,3,4,5,6,7]
</span></span><span style="display:flex;"><span>theta = [0.5, 1.25, -0.75]
</span></span></code></pre></div><p>这个 kernel 是故意选成非对称的。</p>
<p>因为如果用 <code>[1,1,1]</code>，left 和 right 权重一样，翻不翻都一样，证明没有力量。</p>
<p>root 节点的卷积：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_theta(H)[1]
</span></span><span style="display:flex;"><span>  = 0.5*1 + 1.25*2 - 0.75*3
</span></span><span style="display:flex;"><span>  = 0.75
</span></span></code></pre></div><p>node 2：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_theta(H)[2]
</span></span><span style="display:flex;"><span>  = 0.5*2 + 1.25*4 - 0.75*5
</span></span><span style="display:flex;"><span>  = 2.25
</span></span></code></pre></div><p>node 3：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_theta(H)[3]
</span></span><span style="display:flex;"><span>  = 0.5*3 + 1.25*6 - 0.75*7
</span></span><span style="display:flex;"><span>  = 3.75
</span></span></code></pre></div><p>内部节点结果是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[0.75, 2.25, 3.75]
</span></span></code></pre></div><p>mirror 后，node 2 和 node 3 的结构位置交换。</p>
<p>如果我们先 mirror 输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_m H = [1,3,2,7,6,5,4]
</span></span></code></pre></div><p>就必须同时使用 mirrored kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_lr theta = [0.5, -0.75, 1.25]
</span></span></code></pre></div><p>这时两条路径会得到同一个结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P_m K_theta(H)
</span></span><span style="display:flex;"><span>=
</span></span><span style="display:flex;"><span>K_{P_lr theta}(P_m H)
</span></span></code></pre></div><h2 id="proof-分两部分">Proof 分两部分</h2>
<h3 id="proof-a演绎等式检查">Proof A：演绎等式检查</h3>
<p>这部分不训练。</p>
<p>直接检查：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>left  = P_m K_theta(H)
</span></span><span style="display:flex;"><span>right = K_{P_lr theta}(P_m H)
</span></span></code></pre></div><p>然后算：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>max_abs(left - right)
</span></span></code></pre></div><p>如果这个误差接近 0，就说明代数等式成立。</p>
<p>这一步是数学/代数检查。它不是学习结果。</p>
<p>也就是说，<code>P_m</code> 是我们定义好的 mirror 地址置换，<code>P_lr</code> 是我们定义好的 kernel 槽位置换。这里验证的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个定义是否自洽。
</span></span></code></pre></div><p>它不证明模型自己学会了翻树。</p>
<h3 id="proof-b归纳学习检查">Proof B：归纳学习检查</h3>
<p>这部分训练。</p>
<p>我们构造 mirrored data：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>input  = P_m H
</span></span><span style="display:flex;"><span>target = internal_nodes(P_m K_theta(H))
</span></span></code></pre></div><p>然后让一个三槽位参数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta = [theta_root, theta_left, theta_right]
</span></span></code></pre></div><p>通过 MSE loss 和梯度下降学习。</p>
<p>如果数据真的携带 mirror 规律，那么它应该学出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta ~= P_lr theta = [0.5, -0.75, 1.25]
</span></span></code></pre></div><p>这一步说明的不只是“公式手写成立”，还说明这个 mirrored kernel 可以从数据里被学回。</p>
<p>更具体地说，这一步要验证：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned_root  ~= original_root
</span></span><span style="display:flex;"><span>learned_left  ~= original_right
</span></span><span style="display:flex;"><span>learned_right ~= original_left
</span></span></code></pre></div><p>也就是说，loss 学到的不是一个抽象口号，而是 left/right 槽位在 mirror 后的对应关系。</p>
<p>这一步才是学习结果。</p>
<p>但学习到的东西也要说准确：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>学到的是 mirrored kernel slot assignment。
</span></span><span style="display:flex;"><span>不是学到 mirror 触发规则。
</span></span><span style="display:flex;"><span>不是学到递归翻转策略。
</span></span></code></pre></div><h2 id="实验结果">实验结果</h2>
<p>脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/src/s1_mirror_kernel_symmetry_probe.py
</span></span></code></pre></div><p>证据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/evidence/s1_mirror_kernel_symmetry_probe/
</span></span></code></pre></div><p>主机：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>io.grepcode.cn
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>pilot_pass</td>
          <td style="text-align: right"><code>true</code></td>
      </tr>
      <tr>
          <td>flipped-kernel test max error</td>
          <td style="text-align: right"><code>8.88e-16</code></td>
      </tr>
      <tr>
          <td>flipped-kernel OOD max error</td>
          <td style="text-align: right"><code>3.55e-15</code></td>
      </tr>
      <tr>
          <td>unflipped-kernel mean error</td>
          <td style="text-align: right"><code>6.4372</code></td>
      </tr>
      <tr>
          <td>learned mirrored theta</td>
          <td style="text-align: right"><code>[0.5000000000000002, -0.7499999999999998, 1.2499999999999996]</code></td>
      </tr>
      <tr>
          <td>theta-mirror L2 error</td>
          <td style="text-align: right"><code>5.44e-16</code></td>
      </tr>
      <tr>
          <td>left slot learns original right error</td>
          <td style="text-align: right"><code>2.22e-16</code></td>
      </tr>
      <tr>
          <td>right slot learns original left error</td>
          <td style="text-align: right"><code>4.44e-16</code></td>
      </tr>
      <tr>
          <td>learned test MSE</td>
          <td style="text-align: right"><code>1.01e-30</code></td>
      </tr>
      <tr>
          <td>learned OOD MSE</td>
          <td style="text-align: right"><code>9.76e-30</code></td>
      </tr>
  </tbody>
</table>
<p>解释：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用 mirrored kernel 时，误差是机器精度。
</span></span><span style="display:flex;"><span>不用 mirrored kernel 时，误差明显变大。
</span></span><span style="display:flex;"><span>从 mirrored data 训练时，参数能学回 [root,right,left]。
</span></span><span style="display:flex;"><span>left/right 槽位 assignment 的学习误差也是机器精度。
</span></span></code></pre></div><p>所以：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-KERNEL-MIRROR-C01 -&gt; supported pilot
</span></span></code></pre></div><h2 id="这说明了什么">这说明了什么</h2>
<p>SPR-040 支持一个很重要的方向：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的几何操作，可以下降到代数操作。
</span></span></code></pre></div><p>具体到这篇：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>几何 mirror
</span></span><span style="display:flex;"><span>--&gt;
</span></span><span style="display:flex;"><span>堆地址置换 P_m
</span></span><span style="display:flex;"><span>+ kernel 槽位置换 P_lr
</span></span></code></pre></div><p>这让 TreeHeap kernel 不只是“局部求和器”。</p>
<p>它开始像一个结构化算子系统：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>卷积
</span></span><span style="display:flex;"><span>写入
</span></span><span style="display:flex;"><span>读取
</span></span><span style="display:flex;"><span>mirror
</span></span><span style="display:flex;"><span>路径移动
</span></span><span style="display:flex;"><span>子堆组合
</span></span><span style="display:flex;"><span>子堆分解
</span></span></code></pre></div><p>这些都可以成为后续 encoder/decoder 的基本工具。</p>
<p>但这里要避免过度解释。</p>
<p>SPR-040 现在最稳的结论不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经证明了完整 3D fold。
</span></span><span style="display:flex;"><span>TreeHeap 已经学会连续旋转角。
</span></span><span style="display:flex;"><span>TreeHeap 已经解决 latent plane 投影。
</span></span></code></pre></div><p>而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap kernel 的槽位具有结构方向意义；
</span></span><span style="display:flex;"><span>mirror 会改变这些方向的对应关系；
</span></span><span style="display:flex;"><span>这个方向对应关系可以被 loss 学回。
</span></span></code></pre></div><p>这是一块很小但很硬的积木。</p>
<p>它把 TreeHeap kernel 从“标量覆盖”推进到“结构方向上的局部卷积”，但还没有推进到完整的空间折叠理论。</p>
<p>如果用一句更数学化的话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root/left/right 是 TreeHeap 局部坐标系。
</span></span><span style="display:flex;"><span>mirror 是这个局部坐标系上的置换。
</span></span><span style="display:flex;"><span>loss 可以学习置换后的参数赋值。
</span></span></code></pre></div><p>但还没有到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss 可以学习何时选择这个置换。
</span></span></code></pre></div><p>这个“何时选择”需要另一层学习树。</p>
<h2 id="后续数学故事多参森林">后续数学故事：多参森林</h2>
<p>Houming818 提出的更合理方向是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不要让一个大参数树混合学习所有结构能力。
</span></span><span style="display:flex;"><span>应该用多参森林。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta_write   负责写入
</span></span><span style="display:flex;"><span>Theta_read    负责读取
</span></span><span style="display:flex;"><span>Theta_compose 负责组合
</span></span><span style="display:flex;"><span>Theta_mirror  负责 mirror
</span></span><span style="display:flex;"><span>Theta_time    负责时间状语前置
</span></span></code></pre></div><p>每棵树有自己的参数和梯度。</p>
<p>这样做的原因是，mirror 的学习信号不应该被 read/write/semantic 的大 loss 混在一起冲掉。</p>
<p>对于 mirror，可以拆成两棵相关的树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta_mirror:
</span></span><span style="display:flex;"><span>  怎么翻，也就是执行 mirror 算子。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Phi_mirror:
</span></span><span style="display:flex;"><span>  什么时候翻，也就是触发规则。
</span></span></code></pre></div><p>当前 SPR-040 只碰到了第一件事的一小部分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mirror 后 kernel 槽位如何赋值。
</span></span></code></pre></div><p>还没有学习：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Phi_mirror(H, context) -&gt; 是否触发 mirror
</span></span></code></pre></div><p>以翻译为例：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I arrived home at 7 o&#39;clock.
</span></span><span style="display:flex;"><span>我七点到家了。
</span></span></code></pre></div><p>这里更像是一个局部结构重排：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>时间短语从英文尾部，移动到中文谓词前。
</span></span></code></pre></div><p>这不是全树 mirror，而是某种局部 reorder kernel。未来应该有一棵专门的参数树学习：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta_time:
</span></span><span style="display:flex;"><span>  怎么把时间短语前置。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Phi_time:
</span></span><span style="display:flex;"><span>  什么时候触发时间短语前置。
</span></span></code></pre></div><p>所以 SPR-040 的位置很清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它不是终点。
</span></span><span style="display:flex;"><span>它是在证明 TreeHeap kernel 的结构方向是真的。
</span></span></code></pre></div><h2 id="还没有证明什么">还没有证明什么</h2>
<p>这次没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语言理解
</span></span><span style="display:flex;"><span>WMT 翻译
</span></span><span style="display:flex;"><span>真实语义 mirror
</span></span><span style="display:flex;"><span>任意群等变
</span></span><span style="display:flex;"><span>TreeHeap 胜过所有 flat model
</span></span><span style="display:flex;"><span>连续旋转角学习
</span></span><span style="display:flex;"><span>完整 3D fold
</span></span><span style="display:flex;"><span>latent plane 投影权重学习
</span></span><span style="display:flex;"><span>learned mirror trigger
</span></span><span style="display:flex;"><span>learned recursive mirror depth
</span></span></code></pre></div><p>它只证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的 root/left/right 局部卷积，
</span></span><span style="display:flex;"><span>在 mirror 操作下有正确的代数置换形式。
</span></span></code></pre></div><h2 id="下一步">下一步</h2>
<p>接下来可以沿着几个方向扩展，但不需要急着开新编号去做旋转。更合理的是先让后学工程师评判 SPR-040 这个最小 claim 是否站稳：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 当前 mirror assignment proof 是否表述清楚
</span></span><span style="display:flex;"><span>2. 是否需要补一个 flat baseline，证明无结构槽位时不能自然解释 mirror
</span></span><span style="display:flex;"><span>3. 是否要把 scalar slot 扩展到 vector slot
</span></span><span style="display:flex;"><span>4. 是否要把 depth-1 root/left/right 扩展到 recursive subheap
</span></span><span style="display:flex;"><span>5. 是否要接回 short real corpus TreeHeap echo
</span></span><span style="display:flex;"><span>6. 是否要设计 multi-parameter forest：单独训练 mirror/time/read/write 参数树
</span></span></code></pre></div><p>如果这些继续成立，TreeHeap 的 kernel 就不是一组临时写出来的函数，而是一个可以逐步扩展的结构化代数工具箱。</p>
<p>一句话总结：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SPR-040 证明：
</span></span><span style="display:flex;"><span>TreeHeap 的左右 mirror 可以用代数置换实现；
</span></span><span style="display:flex;"><span>树地址要翻，kernel 的 left/right 槽位也要翻；
</span></span><span style="display:flex;"><span>这个规则既能手算成立，也能从 mirrored data 里被梯度学回。
</span></span></code></pre></div><blockquote>
<p>ARA: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/mirror_kernel_symmetry.md">mirror kernel symmetry</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/s1_mirror_kernel_symmetry_probe">evidence</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-042] SPR 全貌总结：从 M0 数学到 S1 echo 的四十二篇探索</title>
      <link>https://www.grepcode.cn/spr/042-spr-ara-summary.html</link>
      <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/042-spr-ara-summary.html</guid>
      <description>SPR 研究全景回顾：M0 数学底座、S1 echo 路线、S2 折叠栈、ARA 协议与 Squad 协作、当前 claim 统计与开放问题。</description>
      <content:encoded><![CDATA[<h1 id="spr-全貌总结从-m0-数学到-s1-echo-的四十二篇探索">SPR 全貌总结：从 M0 数学到 S1 echo 的四十二篇探索</h1>
<p>这不是一篇新技术 blog。
这是一篇<strong>阶段总结</strong>。
把 2026年4月到7月的 SPR 探索过程按 M0 → S1 → S2 的脉络梳理一遍，方便后来人一眼看清全貌。</p>
<h2 id="一句话背景">一句话背景</h2>
<p>SPR（Semantic Prefix Routing）想用 <strong>TreeHeap</strong>（树形堆）替代 Transformer 的稠密矩阵。
把 &ldquo;token id → embedding lookup&rdquo; 换成 &ldquo;token id → 树路径 → 路径即语义表示&rdquo;。
路径即表示，不是查表。</p>
<h2 id="理论总框架m0--s1--s2">理论总框架：M0 → S1 → S2</h2>
<pre tabindex="0"><code>M0  TreeHeap 数学底座
  |  算子代数、closure、kernel convolution、
  |  soft differentiable lift、collapse
  |
  v
S1  容量与 echo
  |  path hash 能装多少 token、
  |  有序 echo 编码/解码、
  |  上下文路由、mirror 等变
  |
  v
S2  折叠栈与翻译
    语义向量 → 折叠动作 → 语法图 → 翻译
</code></pre><p>当前进度：<strong>M0 基本封闭，S1 可控入口已打开，S2 等待桥接。</strong></p>
<hr>
<h2 id="m0-层treeheap-数学底座">M0 层：TreeHeap 数学底座</h2>
<p><strong>核心目标</strong>：TreeHeap 能不能被正式定义为一种算子代数。</p>
<h3 id="已稳定supported--verified">已稳定（supported / verified）</h3>
<table>
  <thead>
      <tr>
          <th>能力</th>
          <th>含义</th>
          <th>证据</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>最小代数</td>
          <td>closure、非交换、projection、subheap matching</td>
          <td><code>treeheap_math_probe</code></td>
      </tr>
      <tr>
          <td>primitive + plus</td>
          <td>plus 作为后继/信息增益</td>
          <td><code>primitive_plus_probe</code></td>
      </tr>
      <tr>
          <td>可训练性 quiz</td>
          <td>线性/XOR/modular 加法 toy</td>
          <td><code>trainability_quiz</code></td>
      </tr>
      <tr>
          <td>Soft Plus 梯度</td>
          <td>K_write 和 Plus_a 可以接收梯度</td>
          <td><code>soft_plus_probe</code>：gK=0.09, gP=0.14</td>
      </tr>
      <tr>
          <td>Soft 坍缩</td>
          <td>低温下坍缩到正确 hard address</td>
          <td>1.0 collapse accuracy</td>
      </tr>
      <tr>
          <td>C05 结构消融</td>
          <td>subheap kernel 迁移打败 flat/path-only</td>
          <td>flat 0.0 vs subheap 1.0</td>
      </tr>
      <tr>
          <td>kernel convolution ops</td>
          <td>search/plus/write/conjugate 统一为卷积</td>
          <td><code>kernel_convolution_ops_probe</code></td>
      </tr>
      <tr>
          <td>diff algebra</td>
          <td>距离、范数、有限差分、梯度步</td>
          <td>Δloss 29.1→0.00066</td>
      </tr>
      <tr>
          <td>algebraic decoder</td>
          <td>投影/decompose/mirror/mod 等解码器</td>
          <td>全 1.0 exact</td>
      </tr>
  </tbody>
</table>
<h3 id="仍开放">仍开放</h3>
<ul>
<li><strong>M0-SOFT-C05</strong>：kernel-guided soft plus 是否优于 naive memory write？需 clean-feature 消融。</li>
<li><strong>M0-SOFT-C06</strong>：多 kernel 分阶段训练是否优于 big-pot loss？</li>
<li><strong>M0-EXIST-C01~C03</strong>：address extrapolation、subheap 迁移、prefix 压缩。</li>
</ul>
<h3 id="m0-总结">M0 总结</h3>
<pre tabindex="0"><code>TreeHeap 已经具备一个可定义的算子代数。
有了软/硬两个版本。
有了梯度通路。
有了结构化 kernel 卷积。
距离、导数、坍缩都能在 toy 上证明。
</code></pre><hr>
<h2 id="s1-层容量echo-与结构路由">S1 层：容量、Echo 与结构路由</h2>
<p><strong>核心目标</strong>：TreeHeap 能不能装下真实语言的 token 序列，并回声重读出来。</p>
<h3 id="已稳定">已稳定</h3>
<table>
  <thead>
      <tr>
          <th>能力</th>
          <th>含义</th>
          <th>证据</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>path hash 容量</td>
          <td>99.7% token 有唯一叶子地址</td>
          <td>solo rate</td>
      </tr>
      <tr>
          <td>有序编码</td>
          <td>sign alternation 打破 cyclic shift 碰撞</td>
          <td><code>spr_hash_cyclic</code></td>
      </tr>
      <tr>
          <td>上下文路由</td>
          <td>context-conditioned route acc 1.0 vs token-only 0.43</td>
          <td><code>spr_context_proof</code></td>
      </tr>
      <tr>
          <td>shallow sentence write</td>
          <td>实句写入 root/subject/object slot</td>
          <td>OOD exact 1.0</td>
      </tr>
      <tr>
          <td>WMT echo kernel</td>
          <td>423K params beat 16.8M seq MLP</td>
          <td>OOD 0.90 vs 0.05</td>
      </tr>
      <tr>
          <td>explicit echo encoder/decoder</td>
          <td>硬接口全闭合</td>
          <td>全 1.0 指标</td>
      </tr>
      <tr>
          <td>ordered fold</td>
          <td>保序折叠必须先于 bag/mod 折叠</td>
          <td>1.0 vs 0.089</td>
      </tr>
      <tr>
          <td>heap state relaxation</td>
          <td>纯状态梯度</td>
          <td>energy ratio 1e-13</td>
      </tr>
      <tr>
          <td>kernel parameter learning</td>
          <td>Theta 学到 hidden kernel [1,1,1]</td>
          <td>L2 error 5e-16</td>
      </tr>
      <tr>
          <td>mirror kernel symmetry</td>
          <td>P_m K=K_{P_lr} P_m</td>
          <td>max error 8e-16</td>
      </tr>
      <tr>
          <td>inverse gate canonicalization</td>
          <td>mirror→inverse→canonical→shared decoder</td>
          <td>gate 0.9998</td>
      </tr>
  </tbody>
</table>
<h3 id="被降级--否定">被降级 / 否定</h3>
<table>
  <thead>
      <tr>
          <th>声明</th>
          <th>裁决</th>
          <th>原因</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token-only 路由有语义</td>
          <td><strong>rejected</strong></td>
          <td>失败于第一次 polysemy 证伪</td>
      </tr>
      <tr>
          <td>frozen embedding = world coordinate</td>
          <td><strong>rejected</strong></td>
          <td>vector_add 完胜 TreeHeap</td>
      </tr>
      <tr>
          <td>旧 task-gate S1 entry proof</td>
          <td><strong>downgraded</strong></td>
          <td>选择输出 kernel ≠ canonicalization</td>
      </tr>
  </tbody>
</table>
<h3 id="仍开放-1">仍开放</h3>
<ul>
<li><strong>Multi-kernel specialization</strong>：gate 能分化但 accuracy 太低</li>
<li><strong>Probabilistic internal read</strong>：leaf read 完美，internal subheap 弱</li>
<li><strong>Latent plane fold</strong>：理论已定义，无实验</li>
<li><strong>真实 context S1b baseline battle</strong></li>
</ul>
<hr>
<h2 id="s2-层折叠栈与翻译">S2 层：折叠栈与翻译</h2>
<p><strong>当前状态</strong>：S2 被暂停。已积累的证据是<strong>诊断性</strong>的，不是正面翻译 claim。</p>
<h3 id="已验证">已验证</h3>
<ul>
<li>语义向量包含折叠动作信息（AUC 证据）</li>
<li>32D 空间足够做 fold action prediction</li>
<li>跨语言折叠结构预测可行（EN↔ZH）</li>
<li>当前 graph builder 瓶颈是 child/parent allocation，不是 fold action</li>
<li>概率容器优于 early argmax</li>
</ul>
<h3 id="被降级">被降级</h3>
<ul>
<li>历史 checkpoint 的 &ldquo;TreeHeap 已解决句法能量&rdquo; 声明被降级</li>
<li>世界模型/背景场训练是诊断性实验，非翻译 claim</li>
</ul>
<hr>
<h2 id="ara-协议与-squad-协作">ARA 协议与 Squad 协作</h2>
<p>SPR 研究采用 <strong>ARA 协议</strong>（arXiv:2604.24658v3）：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>claim → predict → experiment → evidence → trace → decision
</span></span></code></pre></div><p>四人小队：</p>
<table>
  <thead>
      <tr>
          <th>角色</th>
          <th>模型/人</th>
          <th>职责</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Captain</td>
          <td>Houming818</td>
          <td>方向决策、否决、审批</td>
      </tr>
      <tr>
          <td>Runner</td>
          <td>DeepSeek</td>
          <td>写代码、跑实验、独立复现</td>
      </tr>
      <tr>
          <td>Reviewer</td>
          <td>GPT/Codex</td>
          <td>深度审计、仲裁 claim 可靠性</td>
      </tr>
      <tr>
          <td>Auditor</td>
          <td>DeepSeek</td>
          <td>交叉验证 GPT 的证据</td>
      </tr>
  </tbody>
</table>
<p>协作方式：<strong>文件级通信</strong>（<code>~/.squad/</code>），各模型独立 session，上下文不互污染。</p>
<hr>
<h2 id="当前-claim-全景">当前 Claim 全景</h2>
<h3 id="统计截至-2026-07-01">统计（截至 2026-07-01）</h3>
<pre tabindex="0"><code>M0 claims:  18 (含 soft / diff / decoder / existence)
S1 claims:  23 (含 capacity / echo / kernel / fold / gate)
S2 claims:  12
C0  meta:    4
────────
总计:      55+

verified:     15+  (有 baseline 或 falsification)
supported:    20+  (有 evidence，baseline 不完整)
open:         10+  (理论已有，未实验)
rejected:      3
downgraded:    5
</code></pre><h3 id="最硬的结论">最硬的结论</h3>
<ol>
<li><strong>TreeHeap path hash 有足够容量</strong>（99.7% solo rate）</li>
<li><strong>context &gt; token-only 路由</strong>（1.0 vs 0.43）</li>
<li><strong>TreeHeap echo kernel 参数效率远超 flat MLP</strong>（423K vs 16.8M，OOD 0.90 vs 0.05）</li>
<li><strong>mirror 可以降低为代数置换</strong>（error 8e-16）</li>
<li><strong>inverse gate canonicalization 可行</strong>（gate 0.9998）</li>
</ol>
<h3 id="尚不能说的">尚不能说的</h3>
<pre tabindex="0"><code>不能声称 TreeHeap 比 Transformer 好。
不能声称已经解决翻译。
不能声称已经学会自然语言 mirror 触发。
不能声称多 kernel 分工已经解决。
不能声称内部 subheap 读取已经解决。
不能声称 latent field fold 有实验证据。
</code></pre><hr>
<h2 id="关键教训">关键教训</h2>
<ol>
<li><strong>by construction 不是证据</strong>：C08 conjugate proof 的 0.0 error 是代码定义的恒等，不是学习结果。之前误标为 &ldquo;learning evidence&rdquo;。</li>
<li><strong>canonicalization &gt; separate read</strong>：SPR-041 第一版被否决，因为 &ldquo;每种任务一种读法&rdquo; 绕开了 TreeHeap 的核心目标——结构规约到同一参考系。</li>
<li><strong>state loss 是拐杖</strong>：inverse gate 的 canonical state MSE loss 是强监督约束，不是自发涌现。去掉后 gate 从 0.9998 退化。</li>
<li><strong>PAPER.md 容易 stale</strong>：local claim registry 可以很健康，root manifest 和 trace DAG 容易滞后。需要在同一 commit 里更新。</li>
<li><strong>ARA 协作有效</strong>：GPT 写 claim+code → DeepSeek 独立复现审计 → 发现 2/6 不可复现 → 修复了 evidence trace gap。</li>
</ol>
<hr>
<h2 id="下一步">下一步</h2>
<p>按优先级排列：</p>
<ol>
<li><strong>learned trigger</strong>：去掉人工 task flag，让模型从 token/context 中自己判断该用哪种结构操作</li>
<li><strong>noise/mask restore</strong>：纯 echo 容易退化成复制，需要缺 token/加噪/局部打乱 → 复原</li>
<li><strong>multi-parameter TreeHeap forest</strong>：不同结构能力用不同参数树（Θ_write, Θ_read, Θ_mirror, Θ_time），梯度不混合</li>
<li><strong>真实 short corpus echo</strong>：回到 WMT short BPE，先做 echo/restore，不做翻译</li>
<li><strong>path-conditioned read kernel</strong>：解决 SPR-031 暴露的 root-bottleneck</li>
<li><strong>copy-capable baseline</strong>：是时候补 matched copy/pointer 和 small Transformer 对照了</li>
</ol>
<hr>
<h2 id="总结">总结</h2>
<p>从 4 月到 7 月，SPR 做了四件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 证明了 TreeHeap 可以是一个自洽的算子代数（M0）
</span></span><span style="display:flex;"><span>2. 证明了 S1 echo loop 可以训练起来（S1 entry gate）
</span></span><span style="display:flex;"><span>3. 学会了区分 &#34;架构语义证明&#34; 和 &#34;学习能力证明&#34;
</span></span><span style="display:flex;"><span>4. 建立了 ARA 文件级流水线 + 跨模型交叉审计
</span></span></code></pre></div><p>没有夸大的结论。
每项声明都有 evidence 指针和 falsification 条件。
每一步都可以被独立复现。</p>
<p>这本身就是一个值得记录的状态。</p>
<blockquote>
<p>ARA: <a href="https://github.com/houming818/sametime/blob/main/ara/PAPER.md">PAPER.md</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">S1 claims</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/m0-treeheap-math/logic/claims.md">M0 claims</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-050] 第一次真实语言生成：TreeHeap 从英文到中文，但还不是问答</title>
      <link>https://www.grepcode.cn/spr/050-real-wmt-seq2seq-voyage.html</link>
      <pubDate>Sat, 11 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/050-real-wmt-seq2seq-voyage.html</guid>
      <description>记录首次真实 WMT 英中 seq2seq 运行：TreeHeap encoder-decoder 已能生成主题相关的中文句子，但当前落后 flat GRU；这验证的是 S3 表面生成通路，不是问答或翻译成果。</description>
      <content:encoded><![CDATA[<h1 id="第一次真实语言生成treeheap-从英文到中文但还不是问答">第一次真实语言生成：TreeHeap 从英文到中文，但还不是问答</h1>
<p>前面的很多实验都很小：echo、路由、内部节点读出、概率桶、受控符号任务。它们帮助我们确认 TreeHeap 的一些局部算子可以工作，但始终留下一个最实际的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能不能真正参与自然语言的“输入一句话，输出另一句话”？
</span></span></code></pre></div><p>这次我们不再使用 toy token，也不读取历史上已经被降级的 TreeHeap checkpoint。我们直接在真实 WMT 英中平行语料上，从零训练一个最小的 seq2seq 系统。</p>
<p>先说结论：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实文本的 TreeHeap encoder -&gt; decoder 通路已经跑通。
</span></span><span style="display:flex;"><span>它能输出成句、主题相关的中文。
</span></span><span style="display:flex;"><span>但当前它没有赢过普通 flat GRU，也不能称为翻译成果。
</span></span><span style="display:flex;"><span>更重要的是：这仍然不是问答任务。
</span></span></code></pre></div><p>这是一份首航报告，不是庆功报告。</p>
<h2 id="1-为什么先拿-wmt-做-seq2seq">1. 为什么先拿 WMT 做 seq2seq？</h2>
<p>最终目标不是机器翻译，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>question + context
</span></span><span style="display:flex;"><span>  -&gt; TreeHeap encoder
</span></span><span style="display:flex;"><span>  -&gt; answer decoder
</span></span><span style="display:flex;"><span>  -&gt; answer
</span></span></code></pre></div><p>也就是问答。</p>
<p>但问答数据需要三元组：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>上下文、问题、答案
</span></span></code></pre></div><p>手头的 WMT 数据提供的是另一种真实的输入输出对：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>英文句子 -&gt; 中文句子
</span></span></code></pre></div><p>它不能证明模型会回答问题，却很适合先验证一个更基础的门：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能否接收真实文本，
</span></span><span style="display:flex;"><span>把它编码成可供 decoder 使用的状态，
</span></span><span style="display:flex;"><span>并连续生成多步中文 token？
</span></span></code></pre></div><p>如果这一步都不成立，直接谈 QA 只会把 encoder、decoder、数据和评价混成一团。</p>
<p>所以这次 WMT 的身份是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实语言 seq2seq generation gate
</span></span></code></pre></div><p>不是最终 QA benchmark。</p>
<h2 id="2-这次模型到底长什么样">2. 这次模型到底长什么样？</h2>
<p>输入是英文 SentencePiece token。例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>English sentence
</span></span><span style="display:flex;"><span>  -&gt; [t1, t2, t3, ...]
</span></span></code></pre></div><p>每个 token 先写入 TreeHeap 的叶子。然后按 left/right 递归组合：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>        parent
</span></span><span style="display:flex;"><span>       /      \
</span></span><span style="display:flex;"><span>    left     right
</span></span></code></pre></div><p>局部组合不是简单相加：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">h_parent = Compose_theta(h_left + e_left, h_right + e_right)
</code></pre><p><code>e_left</code> 和 <code>e_right</code> 是不同的槽位向量，所以：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Compose(a, b) != Compose(b, a)
</span></span></code></pre></div><p>这保留了顺序。</p>
<p>经过多层递归后，模型同时拥有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>叶子节点：具体英文 BPE token
</span></span><span style="display:flex;"><span>内部节点：局部短语/子堆摘要
</span></span><span style="display:flex;"><span>root：整句摘要
</span></span></code></pre></div><p>中文 decoder 每生成一个 token，都产生一个 query。它不是只读 root，而是在所有有效节点上分配概率：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">p(i | q_t, H) = softmax(K_theta(q_t, h_i))
</code></pre><p>再把各节点状态按概率混合成当前上下文：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">c_t = sum_i p(i | q_t, H) h_i
</code></pre><p>最后生成下一个中文 token。</p>
<p>这可以理解为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>decoder 每说一个中文词，
</span></span><span style="display:flex;"><span>都在 TreeHeap 的叶子和内部子堆之间做一次概率读取。
</span></span></code></pre></div><p>训练时只有标准的 teacher-forcing 交叉熵：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">L = sum_t CE(P(y_t | y_&lt;t, H(x)), y_t)
</code></pre><p>没有人工句法树、没有 route 标签、没有类别标签、没有五个 loss 的大锅炖。</p>
<h2 id="3-真实数据与对照">3. 真实数据与对照</h2>
<p>数据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/mnt/nas/datasets/wmt17/train.zh-en
</span></span><span style="display:flex;"><span>方向：English -&gt; Chinese
</span></span><span style="display:flex;"><span>训练 / 验证 / 测试：30,000 / 2,000 / 2,000
</span></span><span style="display:flex;"><span>最大 BPE 长度：24
</span></span><span style="display:flex;"><span>训练：10 epochs
</span></span><span style="display:flex;"><span>GPU：io 的 RTX 3090，270W 限制保持不变
</span></span></code></pre></div><p>我们没有只跑 TreeHeap。三种 encoder 使用相同的自回归中文 decoder 与相同的翻译 loss：</p>
<table>
  <thead>
      <tr>
          <th>Encoder</th>
          <th>输入能保留什么？</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>BoW</td>
          <td>英文 token 的平均向量，不保留顺序。</td>
      </tr>
      <tr>
          <td>Flat GRU</td>
          <td>有序英文 token 序列。</td>
      </tr>
      <tr>
          <td>TreeHeap</td>
          <td>英文叶子、递归内部子堆、root。</td>
      </tr>
  </tbody>
</table>
<p>这使问题变得很朴素：TreeHeap 现在到底比无序词袋、比普通有序序列，做得怎样？</p>
<h2 id="4-数字结果">4. 数字结果</h2>
<p>完整运行耗时：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>606 秒，约 10.1 分钟
</span></span></code></pre></div><table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Test NLL ↓</th>
          <th style="text-align: right">PPL ↓</th>
          <th style="text-align: right">token-BLEU4 ↑</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap</td>
          <td style="text-align: right">5.129</td>
          <td style="text-align: right">168.8</td>
          <td style="text-align: right">1.48</td>
      </tr>
      <tr>
          <td>BoW</td>
          <td style="text-align: right">4.948</td>
          <td style="text-align: right">140.9</td>
          <td style="text-align: right">1.43</td>
      </tr>
      <tr>
          <td>Flat GRU</td>
          <td style="text-align: right"><strong>4.799</strong></td>
          <td style="text-align: right"><strong>121.4</strong></td>
          <td style="text-align: right"><strong>2.87</strong></td>
      </tr>
  </tbody>
</table>
<p>这里的 <code>token-BLEU4</code> 是脚本内的 BPE-token 近似指标，不是官方 WMT BLEU，不能拿来和论文榜单比较。</p>
<p>数字的诚实解释是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已经能学习真实 seq2seq。
</span></span><span style="display:flex;"><span>TreeHeap 的生成指标略高于 BoW，但差异很小。
</span></span><span style="display:flex;"><span>TreeHeap 明显落后于 flat GRU。
</span></span></code></pre></div><p>所以这轮不能支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 当前配置优于普通序列模型。
</span></span></code></pre></div><h2 id="5-输出到底像不像中文">5. 输出到底像不像中文？</h2>
<p>看几个测试集样例。下面没有润色。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>EN: In order to fund this spending, revenues must be raised.
</span></span><span style="display:flex;"><span>REF: 为了支撑这笔费用,就必须增加政府收入。
</span></span><span style="display:flex;"><span>TH : 鉴于这一观点,我们必须增加支出。
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>EN: When it comes to economic policy, a fast, faulty decision is often better than inaction.
</span></span><span style="display:flex;"><span>REF: 当谈到经济政策时,一个快速的、错误的决定通常是比无所作为要好。
</span></span><span style="display:flex;"><span>TH : 鉴于经济决策,但通常比经济决策,因为其决策的境况通常是积极的。
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>EN: Furthermore, the slow pace of European decision-making has compounded Greece&#39;s troubles.
</span></span><span style="display:flex;"><span>REF: 此外,欧洲缓慢的决策过程也加深了希腊的麻烦。
</span></span><span style="display:flex;"><span>TH : 此外,英国选民决定了欧洲国家,但英国退出投票。
</span></span></code></pre></div><p>这些结果同时说明两件事。</p>
<p>第一，正面信号：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型并非输出随机 token。
</span></span><span style="display:flex;"><span>它学会了中文连接方式、部分句式、标点和主题领域词。
</span></span><span style="display:flex;"><span>“欧洲 / 希腊 / 经济 / 决策 / 支出”等语义场会进入输出。
</span></span></code></pre></div><p>换句话说，S3 的表面语言 decoder 已经开始工作。它不再只是输出类别桶，也不只是复制输入。</p>
<p>第二，关键不足：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>主题相近，不等于关系正确。
</span></span></code></pre></div><p>模型经常把训练集中同一主题的短语拼接到一起：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>欧洲 -&gt; 英国
</span></span><span style="display:flex;"><span>财政刺激 -&gt; 财政紧缩
</span></span><span style="display:flex;"><span>决策缓慢 -&gt; 退出投票
</span></span></code></pre></div><p>句子表面像中文，但事实关系、指代和谓词绑定仍然很不稳定。</p>
<h2 id="6-treeheap-内部节点有没有参与">6. TreeHeap 内部节点有没有参与？</h2>
<p>我们还做了一个不重新训练的读取消融：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>full       可读叶子和所有内部子堆
</span></span><span style="display:flex;"><span>leaf_only  隐藏内部节点，只读叶子
</span></span><span style="display:flex;"><span>root_only  只读整句 root
</span></span></code></pre></div><p>greedy 生成的 token-BLEU4：</p>
<table>
  <thead>
      <tr>
          <th>Read mode</th>
          <th style="text-align: right">token-BLEU4</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>full</td>
          <td style="text-align: right">1.48</td>
      </tr>
      <tr>
          <td>leaf_only</td>
          <td style="text-align: right">1.26</td>
      </tr>
      <tr>
          <td>root_only</td>
          <td style="text-align: right">0.037</td>
      </tr>
  </tbody>
</table>
<p>这说明 root 不是一个足够的万能 hash：只给 root 时，生成几乎崩溃。完整 TreeHeap 比 leaf-only 有小幅提升，说明内部节点可能已经带来一部分可用信息，但增益仍然很弱。</p>
<p>有一个审计细节必须记录：当前脚本的 ablation NLL 仍错误地沿用了 full-memory 的 teacher-forcing 路径，因此 ablation 的 NLL 相同、不能解释。上表只使用实际走 ablation read path 的 greedy generation 指标。下一次应加载本次 checkpoint 修正后重算，不必重训。</p>
<h2 id="7-这不是-qa但它为-qa-打开了什么">7. 这不是 QA，但它为 QA 打开了什么？</h2>
<p>问答任务应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[QUESTION] + [CONTEXT]
</span></span><span style="display:flex;"><span>  -&gt; TreeHeap
</span></span><span style="display:flex;"><span>  -&gt; answer tokens
</span></span></code></pre></div><p>这次 WMT 实验没有 question，也没有 answer span，因此不能叫 QA。</p>
<p>但它已经确认了 QA 所需的一条基础通路：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实文本
</span></span><span style="display:flex;"><span>  -&gt; TreeHeap encoder
</span></span><span style="display:flex;"><span>  -&gt; 多步 decoder
</span></span><span style="display:flex;"><span>  -&gt; 自然语言输出
</span></span></code></pre></div><p>下一步不是继续把翻译 BLEU 当最终目标，而是换成真实 QA 三元数据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>context, question, answer
</span></span></code></pre></div><p>然后比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap encoder
</span></span><span style="display:flex;"><span>BoW encoder
</span></span><span style="display:flex;"><span>flat sequence encoder
</span></span></code></pre></div><p>评价也应换成 QA 的答案指标，例如 exact match、token F1、ROUGE 或 answer BLEU，而不是只看翻译分数。</p>
<h2 id="8-当前-ara-状态">8. 当前 ARA 状态</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S3-WMT-SEQ2SEQ-C01
</span></span><span style="display:flex;"><span>  -&gt; supported feasibility / negative comparative result
</span></span></code></pre></div><p>它支持的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可以从真实 WMT 文本端到端训练，
</span></span><span style="display:flex;"><span>并驱动一个中文 seq2seq decoder 产生可读、主题相关的句子。
</span></span></code></pre></div><p>它不支持的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已优于 flat sequence。
</span></span><span style="display:flex;"><span>TreeHeap 已完成翻译。
</span></span><span style="display:flex;"><span>TreeHeap 已完成问答。
</span></span><span style="display:flex;"><span>TreeHeap 已学到稳定世界模型。
</span></span></code></pre></div><p>这份边界不是泼冷水。它把下一步变得非常明确：先修正 internal-node ablation 的 teacher-forcing 评价，再接入真实 QA 数据，让 TreeHeap 的子堆读取回答“哪段 context 支撑当前答案”。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-051] P0 预训练后的第一次直接提问：失败比成功更有信息</title>
      <link>https://www.grepcode.cn/spr/051-p0-direct-qa-failure.html</link>
      <pubDate>Sun, 12 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/051-p0-direct-qa-failure.html</guid>
      <description>记录 TreeHeap P0 原始中文续写预训练的第一次直接问答测试。训练损失下降，但模型在问题输入上重复坍缩；这不是世界模型或问答能力的证据。</description>
      <content:encoded><![CDATA[<h1 id="p0-预训练后的第一次直接提问失败比成功更有信息">P0 预训练后的第一次直接提问：失败比成功更有信息</h1>
<p>这篇记录一个应该被正面保存的负结果。</p>
<p>我们刚完成了 TreeHeap 的 P0 原始中文文本预训练：不使用问答标签、不使用翻译对、不读取旧 checkpoint，只做最普通的自监督任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>前 64 个中文 BPE token
</span></span><span style="display:flex;"><span>    -&gt; TreeHeap encoder
</span></span><span style="display:flex;"><span>    -&gt; 预测后续 32 个 BPE token
</span></span></code></pre></div><p>训练集来自新闻、百科和网页文本的混合。它的目标是先让模型从大量原始文字中学习语言分布；它不是一个已训练好的聊天模型。</p>
<h2 id="1-已经跑通了什么">1. 已经跑通了什么</h2>
<p>本次主运行使用约 16,000 个 BPE 词表、192 维状态、12,785,921 个可训练参数，在 io 的 RTX 3090 上训练 50,000 step。</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">开始</th>
          <th style="text-align: right">结束</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>验证 NLL</td>
          <td style="text-align: right">9.658</td>
          <td style="text-align: right">5.519</td>
      </tr>
      <tr>
          <td>验证 PPL</td>
          <td style="text-align: right">15,626</td>
          <td style="text-align: right">249.4</td>
      </tr>
      <tr>
          <td>训练时间</td>
          <td style="text-align: right">-</td>
          <td style="text-align: right">48.0 分钟</td>
      </tr>
  </tbody>
</table>
<p>NLL 是模型对正确后续 token 的负对数概率，越小越好；PPL 是同一件事的指数形式，越小越好。这里的下降说明梯度确实从真实中文语料中更新了参数，模型比初始随机参数更会预测留出文本。</p>
<p>这支持的只是下面这个很小但真实的结论：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>原始中文文本
</span></span><span style="display:flex;"><span>  -&gt; TreeHeap 编码器与 decoder
</span></span><span style="display:flex;"><span>  -&gt; 交叉熵梯度
</span></span><span style="display:flex;"><span>  -&gt; 更低的留出续写损失
</span></span></code></pre></div><p>它不自动推出“模型理解世界”。</p>
<h2 id="2-直接问它地球为什么是圆的">2. 直接问它：地球为什么是圆的？</h2>
<p>为了避免只看数字，我们直接加载训练完成的 checkpoint，以 greedy decoding（每一步总选概率最大的 token）做了两次 CLI 测试。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：地球为什么是圆的？
</span></span><span style="display:flex;"><span>输出：圆圆圆圆圆圆圆圆圆圆圆圆圆圆圆圆……
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：问：地球为什么是圆的？答：
</span></span><span style="display:flex;"><span>输出：:圆圆::圆圆::圆圆::圆圆:圆圆圆……
</span></span></code></pre></div><p>这不是一个不够漂亮的答案，而是生成退化：模型把输入里显眼的“圆”当成局部最高概率 token，并在每一步再次选择它，形成循环。</p>
<p>正确答案至少需要表达类似关系：地球足够大，重力会把物质拉向中心，长期达到近似球形的平衡。当前模型没有给出这些关系。</p>
<h2 id="3-为什么它在-wmt-上看起来比这里顺一些">3. 为什么它在 WMT 上看起来比这里顺一些？</h2>
<p>此前的 WMT 英译中实验里，TreeHeap 有时能输出看似完整的中文句子。这不和本次失败矛盾。</p>
<p>翻译是强条件任务：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>英文源句 + 对齐的中文目标
</span></span></code></pre></div><p>decoder 在每一步可以读取英文叶子、内部子堆和 root；训练还会用正确中文前缀进行 teacher forcing。因此它只需在一个受源句限制的候选空间中选下一个中文 token。</p>
<p>本次提问却要求模型：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>短问题
</span></span><span style="display:flex;"><span>  -&gt; 从参数中取出有关重力与球形的知识
</span></span><span style="display:flex;"><span>  -&gt; 组织成解释
</span></span><span style="display:flex;"><span>  -&gt; 连续生成多个正确 token
</span></span></code></pre></div><p>而 P0 训练见到的是固定形态的 <code>64 token 上下文 -&gt; 32 token 后续</code>，不是 <code>问题 -&gt; 答案</code>。问题本身也远短于训练上下文。这既是任务格式变化，也是能力要求的大幅提升。</p>
<p>更重要的是，WMT 的数值本身也不强：TreeHeap 的 token-BLEU4 为 1.48，落后于 flat GRU 的 2.87。因此“看起来像中文”只能说明有表面语言信号，不能说明它已经可靠翻译，更不能说明它有问答能力。</p>
<h2 id="4-这次失败定位了什么">4. 这次失败定位了什么</h2>
<p>失败不是“GPU 没有训练”或“梯度没有写入参数”。验证 NLL 的大幅下降排除了这两种最初级的故障。</p>
<p>它暴露的是更靠后的三个缺口：</p>
<ol>
<li><strong>训练规模与语料覆盖不足。</strong> 5 万步、1,279 万参数的模型只能开始拟合局部文字分布，远不足以储存和组织通用事实。</li>
<li><strong>生成策略过于脆弱。</strong> greedy decoding 很容易被一个局部高概率 token 锁死。采样、温度、重复惩罚可以诊断这一点，但它们不能凭空补出知识。</li>
<li><strong>没有问答格式和证据读取训练。</strong> P0 应先提供语言与统计基础；后续 QA 阶段才应训练 <code>question + context -&gt; answer</code>，并检验 decoder 是否能读到支持答案的子堆。</li>
</ol>
<h2 id="5-ara-状态">5. ARA 状态</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S3-P0-WORLD-OBS-C01
</span></span><span style="display:flex;"><span>  -&gt; supported feasibility only
</span></span></code></pre></div><p>当前证据支持：TreeHeap P0 管线可以在真实中文语料上优化留出续写损失。</p>
<p>当前证据不支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已形成世界模型
</span></span><span style="display:flex;"><span>TreeHeap 可以回答开放问题
</span></span><span style="display:flex;"><span>TreeHeap 已学会可靠的中文生成
</span></span><span style="display:flex;"><span>TreeHeap 相比 flat sequence 有结构优势
</span></span></code></pre></div><p>下一步应先在完全相同的 P0 数据、词表、切分、参数量附近补齐 <code>flat_seq</code> 和 <code>BoW</code> 基线。只有先回答“TreeHeap 是否比非结构模型多学到了什么”，才值得继续扩大训练或进入 QA。</p>
<h2 id="6-可复查证据">6. 可复查证据</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>训练证据：
</span></span><span style="display:flex;"><span>ara/s3-generation/evidence/s3_p0_world_observation_main/
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>脚本：
</span></span><span style="display:flex;"><span>ara/s3-generation/src/s3_treeheap_p0_pretrain.py
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>checkpoint：
</span></span><span style="display:flex;"><span>checkpoint.pt
</span></span></code></pre></div><p>负结果不是航行失败的终点。它把“模型还不会什么”变成了可复查的事实，也防止我们把损失下降误读成理解已经出现。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-052] TreeHeap 终于参加了翻译考试，但还没有赢</title>
      <link>https://www.grepcode.cn/spr/052-treeheap-frontier-bottleneck.html</link>
      <pubDate>Sun, 12 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/052-treeheap-frontier-bottleneck.html</guid>
      <description>用四节点 Frontier 关闭叶子旁路，第一次测量 TreeHeap 内部结构对真实 WMT 翻译的因果作用。Route 出现微弱正信号，但仍落后于普通四段向量压缩。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-终于参加了翻译考试但还没有赢">TreeHeap 终于参加了翻译考试，但还没有赢</h1>
<p>先说结论：</p>
<blockquote>
<p>这次实验第一次强迫翻译 decoder 使用 TreeHeap 内部子堆。学出来的合并路径确实有一点作用，但 TreeHeap 仍然没有打败更简单的四段向量平均。</p></blockquote>
<p>这是一个没有通过主 Claim、但让问题明显前进的实验。</p>
<h2 id="1-上一轮哪里有问题">1. 上一轮哪里有问题</h2>
<p>我们希望模型这样翻译：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>英文 token
</span></span><span style="display:flex;"><span>  -&gt; 写入 TreeHeap
</span></span><span style="display:flex;"><span>  -&gt; 合并成有意义的内部子堆
</span></span><span style="display:flex;"><span>  -&gt; decoder 读取子堆
</span></span><span style="display:flex;"><span>  -&gt; 生成中文
</span></span></code></pre></div><p>但上一轮代码实际上允许 decoder 同时读取：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>全部原始 token 叶子
</span></span><span style="display:flex;"><span>+
</span></span><span style="display:flex;"><span>全部 TreeHeap 内部节点
</span></span></code></pre></div><p>实验结果是：隐藏全部内部节点以后，几乎没有变化。</p>
<table>
  <thead>
      <tr>
          <th>读取方式</th>
          <th style="text-align: right">Test NLL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>叶子 + 内部节点</td>
          <td style="text-align: right">6.0448</td>
      </tr>
      <tr>
          <td>只有叶子</td>
          <td style="text-align: right">6.0434</td>
      </tr>
  </tbody>
</table>
<p>两个数字越小越好，但它们几乎相同。</p>
<p>这说明 decoder 找到了最省事的办法：直接读取原始 token，绕过 TreeHeap。</p>
<p>可以把它想成一座仓库。我们认真设计了楼层、货架和分类区，却又把全部商品原样摆在门口。顾客自然不会进入仓库。</p>
<p>因此上一轮只能证明“程序计算了一棵树”，不能证明“翻译使用了这棵树”。</p>
<h2 id="2-什么叫-frontier">2. 什么叫 Frontier</h2>
<p>这次我们关闭了门口的商品摊位。</p>
<p>假设英文源句被切成 16 个 BPE token：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x1 x2 x3 x4 ... x16
</span></span></code></pre></div><p>TreeHeap 每次选择两个相邻节点，把它们合成一个 parent：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[x1] [x2] [x3] [x4] ... [x16]
</span></span><span style="display:flex;"><span>       ↓ 不断合并
</span></span><span style="display:flex;"><span>[x1 x2 x3] [x4 x5] [x6 ... x10] [x11 ... x16]
</span></span></code></pre></div><p>当只剩四个互不重叠的子堆时停止：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>F1 = [x1 x2 x3]
</span></span><span style="display:flex;"><span>F2 = [x4 x5]
</span></span><span style="display:flex;"><span>F3 = [x6 ... x10]
</span></span><span style="display:flex;"><span>F4 = [x11 ... x16]
</span></span></code></pre></div><p>这四个仍然存活的节点叫作 <code>K=4 frontier</code>。</p>
<p>它们必须满足两个条件：</p>
<ol>
<li>四个子堆共同覆盖全部源 token；</li>
<li>任意 token 只能属于一个子堆。</li>
</ol>
<p>数学上写成：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">\bigcup_{v\in F_K} Leaves(v)=Leaves(T)
</code></pre><pre tabindex="0"><code class="language-math" data-lang="math">Leaves(v_i)\cap Leaves(v_j)=\varnothing,\quad i\ne j
</code></pre><p>本实验中，decoder 只能读取：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[F1, F2, F3, F4]
</span></span></code></pre></div><p>它再也看不到背后的 16 个原始叶子。TreeHeap 结构终于成为翻译的必经通道。</p>
<h2 id="3-为什么一定限制为四个节点">3. 为什么一定限制为四个节点</h2>
<p>如果 TreeHeap 给 decoder 30 个状态，而基线只给 4 个状态，那么 TreeHeap 即使获胜，也可能只是因为它携带的信息更多。</p>
<p>因此这次比较最重要的原则是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>所有压缩模型只能交出四个 192D 向量。
</span></span></code></pre></div><p>这类似考试时统一规定：每位考生只能带一张同样大小的草稿纸。</p>
<h2 id="4-五名考生分别做什么">4. 五名考生分别做什么</h2>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>如何把英文压成四个状态</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Learned TreeHeap</td>
          <td>根据节点内容学习每次合并哪两个相邻子堆</td>
      </tr>
      <tr>
          <td>Fixed TreeHeap</td>
          <td>按固定、较平衡的规则合并</td>
      </tr>
      <tr>
          <td>Random TreeHeap</td>
          <td>按不可训练的随机规则合并</td>
      </tr>
      <tr>
          <td>Flat K=4</td>
          <td>把句子顺序切成四段，每段直接求平均</td>
      </tr>
      <tr>
          <td>Leaf Oracle</td>
          <td>GRU 读取全部 token，不受四状态限制，只作为上界</td>
      </tr>
  </tbody>
</table>
<p>Learned TreeHeap 的一次合并是：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">h_p=\tanh\left(MLP([h_l+e_L;h_r+e_R])\right)
</code></pre><p>其中：</p>
<ul>
<li><code>h_l</code>、<code>h_r</code> 是左右子堆；</li>
<li><code>e_L</code>、<code>e_R</code> 表示左槽位与右槽位；</li>
<li><code>MLP</code> 把两个 192D 向量重新压成一个 192D parent。</li>
</ul>
<p>至于“这一步该合并哪一对”，由另一个 merge kernel 打分。训练时使用 Gumbel-Softmax：前向计算真的选择一对，反向传播仍能用翻译 loss 修改选择参数。</p>
<p>模型没有看到人工语法树，也没有主谓宾标签。唯一监督是正确中文翻译。</p>
<h2 id="5-数据与实验规模">5. 数据与实验规模</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>任务：WMT17 English -&gt; Chinese
</span></span><span style="display:flex;"><span>训练集：5,000 对
</span></span><span style="display:flex;"><span>验证集：500 对
</span></span><span style="display:flex;"><span>测试集：500 对
</span></span><span style="display:flex;"><span>英文长度：9..24 BPE token（EOS 前）
</span></span><span style="display:flex;"><span>状态维度：192
</span></span><span style="display:flex;"><span>训练：5 epochs
</span></span><span style="display:flex;"><span>GPU：io 的 RTX 3090，保留 270W 限制
</span></span></code></pre></div><p>这是机制 smoke test，不是正式 WMT 竞赛规模。</p>
<h2 id="6-如何看懂三个指标">6. 如何看懂三个指标</h2>
<h3 id="nll模型有多意外">NLL：模型有多意外</h3>
<p>NLL 是正确中文 token 的平均负对数概率。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>越小越好
</span></span></code></pre></div><p>如果模型认为正确答案很可能出现，NLL 就低；如果它每一步都很犹豫，NLL 就高。</p>
<h3 id="ppl平均有多少候选让模型犹豫">PPL：平均有多少候选让模型犹豫</h3>
<p>PPL 是 NLL 的指数形式，也叫困惑度。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>越小越好
</span></span></code></pre></div><p>它不能严格解释成候选词数量，但可以直观理解为：数字越大，模型越不知道下一步该选什么。</p>
<h3 id="token-bleu4生成片段与参考答案有多像">token-BLEU4：生成片段与参考答案有多像</h3>
<p>它比较生成 token 片段和参考翻译的重合程度。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>越大越好
</span></span></code></pre></div><p>这里使用的是实验脚本内的 BPE-token 指标，不是官方 WMT BLEU，不能和论文排行榜直接比较。</p>
<h2 id="7-主实验结果">7. 主实验结果</h2>
<table>
  <thead>
      <tr>
          <th>Encoder</th>
          <th style="text-align: right">Test NLL ↓</th>
          <th style="text-align: right">PPL ↓</th>
          <th style="text-align: right">token-BLEU4 ↑</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Learned TreeHeap</td>
          <td style="text-align: right">6.5988</td>
          <td style="text-align: right">734.2</td>
          <td style="text-align: right">0.226</td>
      </tr>
      <tr>
          <td>Fixed TreeHeap</td>
          <td style="text-align: right">6.6012</td>
          <td style="text-align: right">736.0</td>
          <td style="text-align: right">0.159</td>
      </tr>
      <tr>
          <td>Random TreeHeap</td>
          <td style="text-align: right">6.7020</td>
          <td style="text-align: right">814.0</td>
          <td style="text-align: right">0.185</td>
      </tr>
      <tr>
          <td>Flat K=4</td>
          <td style="text-align: right"><strong>6.5080</strong></td>
          <td style="text-align: right"><strong>670.5</strong></td>
          <td style="text-align: right"><strong>0.431</strong></td>
      </tr>
      <tr>
          <td>Leaf Oracle</td>
          <td style="text-align: right">6.3541</td>
          <td style="text-align: right">574.8</td>
          <td style="text-align: right">0.792</td>
      </tr>
  </tbody>
</table>
<p>我们逐层解读。</p>
<h3 id="第一层learned-明显好于-random">第一层：Learned 明显好于 Random</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Learned NLL = 6.5988
</span></span><span style="display:flex;"><span>Random  NLL = 6.7020
</span></span></code></pre></div><p>完全随机地决定子堆边界会损失更多翻译信息。树怎么折叠并非毫无影响。</p>
<h3 id="第二层learned-与-fixed-几乎相同">第二层：Learned 与 Fixed 几乎相同</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Learned NLL = 6.5988
</span></span><span style="display:flex;"><span>Fixed   NLL = 6.6012
</span></span><span style="display:flex;"><span>差值          0.0024
</span></span></code></pre></div><p>这个差异太小，不能声称 learned topology 优于普通平衡树。</p>
<h3 id="第三层flat-k4-最强">第三层：Flat K=4 最强</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Flat K=4 NLL = 6.5080
</span></span><span style="display:flex;"><span>Learned NLL  = 6.5988
</span></span></code></pre></div><p>普通的四段平均比当前 TreeHeap 好 <code>0.0908 NLL</code>。因此新 Claim 的主预测没有通过。</p>
<h3 id="第四层四状态压缩确实有成本">第四层：四状态压缩确实有成本</h3>
<p>不受限制的 Leaf Oracle 为 <code>6.3541</code>，明显优于全部四状态模型。这说明把 9..24 个 token 压成四个向量本来就是困难任务。</p>
<h2 id="8-learned-route-真的有用吗">8. Learned route 真的有用吗</h2>
<p>不同模型独立训练后有差距，可能来自随机初始化，而不一定来自 route。</p>
<p>所以我们加载同一个 Learned TreeHeap checkpoint，不改变 embedding、compose 或 decoder，只替换测试时的合并路径。</p>
<table>
  <thead>
      <tr>
          <th>同一 checkpoint 的测试 route</th>
          <th style="text-align: right">NLL</th>
          <th style="text-align: right">相对 learned</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Learned route</td>
          <td style="text-align: right">6.5988</td>
          <td style="text-align: right">-</td>
      </tr>
      <tr>
          <td>Fixed route</td>
          <td style="text-align: right">6.6085</td>
          <td style="text-align: right">+0.0097</td>
      </tr>
      <tr>
          <td>Random route</td>
          <td style="text-align: right">6.6272</td>
          <td style="text-align: right">+0.0285</td>
      </tr>
  </tbody>
</table>
<p>替换 route 后，性能确实下降。这说明 learned route 已经产生了因果作用，而不只是画出一棵没人读取的树。</p>
<p>但我们事先规定：NLL 至少恶化 <code>0.05</code>，才升级 Claim。现在最大的变化只有 <code>0.0285</code>，没有过线。</p>
<p>因此最准确的判断是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route 有微弱作用；
</span></span><span style="display:flex;"><span>当前 TreeHeap 压缩仍然不如 flat K=4。
</span></span></code></pre></div><h2 id="9-实际翻译是什么样">9. 实际翻译是什么样</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>EN : ensuring the highest possible standards of security
</span></span><span style="display:flex;"><span>     for nuclear weapons and materials
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>REF: 确保对核武器及材料执行最高的安全标准
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TH : 布什政府会让美国人的政治家和反射率。
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>EN : beginning a dialogue on tactical nuclear weapons
</span></span><span style="display:flex;"><span>     involving Russia, the US, and NATO
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>REF: 启动俄罗斯、美国和北约参与的战术核武器对话
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TH : 但对一体的……但对伊朗的……
</span></span></code></pre></div><p>模型能生成中文句式和部分主题词，但关系、实体和事实绑定仍然不可靠。本实验评估的是结构机制，不是翻译质量成功。</p>
<h2 id="10-为什么简单平均反而保存得更好">10. 为什么简单平均反而保存得更好</h2>
<p>Flat K=4 做的事情很朴素：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">f_k=Projection\left(\frac{1}{|S_k|}\sum_{i\in S_k}h_i\right)
</code></pre><p>它先对一个连续区域求平均。这个过程不理解语法，却提供了一条稳定的线性信息通道：每个 token 都直接参与结果。</p>
<p>当前 TreeHeap compose 则反复执行：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>两个 192D 子堆
</span></span><span style="display:flex;"><span>-&gt; MLP + tanh
</span></span><span style="display:flex;"><span>-&gt; 一个 192D parent
</span></span><span style="display:flex;"><span>-&gt; 再和别的 parent 合并
</span></span></code></pre></div><p>每次非线性压缩都可能丢掉人名、数字、否定词和实体关系。重复多层以后，parent 也许保留了模糊主题，却失去了翻译所需的精确细节。</p>
<p>这和把两份文件概括成一句摘要类似。摘要可能说对了主题，但很难保留所有姓名、金额和逻辑关系。</p>
<h2 id="11-下一步不是继续调-route">11. 下一步不是继续调 route</h2>
<p>叶子旁路已经排除，route 也出现了小幅因果信号。继续只改 route，未必能解决 flat K=4 领先的问题。</p>
<p>下一步更合理的节点设计是把两类信息分开：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeapNode {
</span></span><span style="display:flex;"><span>    structure_state   # 这个子堆是什么结构
</span></span><span style="display:flex;"><span>    value_residual    # 原始词汇和实体的保真信息
</span></span><span style="display:flex;"><span>    left/right        # 子节点地址
</span></span><span style="display:flex;"><span>    probability_mass  # 当前候选质量
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>可以把它类比成压缩文件：</p>
<ul>
<li><code>structure_state</code> 是目录和索引；</li>
<li><code>value_residual</code> 是不能丢失的实际文件内容。</li>
</ul>
<p>一个可能的 value-preserving compose 是：</p>
<pre tabindex="0"><code class="language-math" data-lang="math">s_p=Compose_\theta(s_l,s_r)
</code></pre><pre tabindex="0"><code class="language-math" data-lang="math">v_p=g_l\odot v_l+g_r\odot v_r+r_\theta(s_l,s_r)
</code></pre><p>结构 kernel 决定如何组织，残差通道负责把梯度和内容继续传向上层。</p>
<h2 id="12-最终-ara-判定">12. 最终 ARA 判定</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S3-WMT-FRONTIER-C01
</span></span><span style="display:flex;"><span>  -&gt; 主 Claim 未支持
</span></span><span style="display:flex;"><span>  -&gt; 保留 weak causal route signal
</span></span></code></pre></div><p>这次实验没有证明 TreeHeap 优于 flat，更没有证明世界模型或意识已经出现。</p>
<p>它真正完成了三件事：</p>
<ol>
<li>关闭了 decoder 偷看全部叶子的旁路；</li>
<li>证明 learned route 对真实翻译有微弱因果作用；</li>
<li>定位了新的主要问题：当前 compose 不如线性平均保真。</li>
</ol>
<p>问题已经从“树有没有参与”推进到“树怎样在学习结构时不丢内容”。这是一个更具体、也更容易继续证伪的工程问题。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-053] 不让神经网络重写整棵树：让它学习选择 TreeHeap 算子</title>
      <link>https://www.grepcode.cn/spr/053-treeheap-algebraic-operator-codec.html</link>
      <pubDate>Sun, 12 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/053-treeheap-algebraic-operator-codec.html</guid>
      <description>检验结构能否进入 encoder，以及 TreeHeap 能否用自身算子恢复数据。未见地址成功，未见深度失败，并定位了失败位置。</description>
      <content:encoded><![CDATA[<h1 id="不让神经网络重写整棵树让它学习选择-treeheap-算子">不让神经网络重写整棵树：让它学习选择 TreeHeap 算子</h1>
<p>Houming818 提出了两个比“再调一个模型”更根本的判断：</p>
<ol>
<li>数据中的结构规律，应该能够被 encoder 提取，并成为 encoder 与 decoder 共同使用的表示；</li>
<li>TreeHeap 中的数据变化，应该由 TreeHeap 自己的地址、子堆与算子完成，而不是让普通 MLP 把整个数组重新写一遍。</li>
</ol>
<p>本实验不拿语言任务掩盖问题，而是在一个有限、可检查的世界里问：<strong>神经网络能否只负责认出操作，真正的数据变换交给 TreeHeap 代数执行？</strong></p>
<h2 id="1-一个七节点例子">1. 一个七节点例子</h2>
<p>采用从 1 开始编号的二叉堆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>          A[1]
</span></span><span style="display:flex;"><span>        /      \
</span></span><span style="display:flex;"><span>     A[2]      A[3]
</span></span><span style="display:flex;"><span>     /  \      /  \
</span></span><span style="display:flex;"><span>  A[4] A[5] A[6] A[7]
</span></span></code></pre></div><p>地址规则是：</p>
$$ \operatorname{left}(i)=2i,\qquad \operatorname{right}(i)=2i+1 $$<p>为了让错误可以被客观识别，我们构造一个简单的数论世界：</p>
$$ A[2i]=2A[i],\qquad A[2i+1]=2A[i]+1 $$<p>若根节点为 1，合法状态就是 <code>[1,2,3,4,5,6,7]</code>。实验随机选择一段子堆，用 TreeHeap 原生算子破坏它：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>MIRROR(address, depth)
</span></span><span style="display:flex;"><span>SUBTREE_PLUS(address, depth, delta)
</span></span></code></pre></div><p>例如 <code>SUBTREE_PLUS(2, 1, 3)</code> 把地址 2 及其下一层子节点都加 3；<code>MIRROR</code> 递归交换指定子堆的左右分支。</p>
<h2 id="2-encoder-学习什么">2. encoder 学习什么</h2>
<p>这里的参数 $\theta$ 不是目标 TreeHeap，也不保存每一棵答案树。它是在所有节点上共享的小型识别 kernel：</p>
$$ K_\theta(H,i)\rightarrow\bigl(P(o),P(i),P(d),P(\delta)\bigr) $$<ul>
<li>$H$：当前被破坏的完整 TreeHeap 状态；</li>
<li>$i$：kernel 正在观察的候选地址；</li>
<li>$o$：<code>mirror</code> 或 <code>plus</code>；</li>
<li>$d$：递归深度；</li>
<li>$\delta$：加法参数。</li>
</ul>
<p>kernel 读取当前节点及其父子违反数论规则的残差，并汇总各相对深度的子堆残差。它不输出 511 个新数，而是输出一张很短的维修工单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>operator = plus
</span></span><span style="display:flex;"><span>address  = 12
</span></span><span style="display:flex;"><span>depth    = 2
</span></span><span style="display:flex;"><span>delta    = -3
</span></span></code></pre></div><p>概率桶坍缩后，固定 executor 执行逆操作：</p>
$$ \hat H=E_{\text{TreeHeap}}(H,\hat o,\hat i,\hat d,\hat\delta) $$<p>最后检查 $\hat H$ 是否与原始合法 TreeHeap 逐节点完全相同。神经网络没有权限直接生成答案数组。</p>
<table>
  <thead>
      <tr>
          <th>对象</th>
          <th>含义</th>
          <th>是否学习</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>$H$</td>
          <td>当前 TreeHeap 数据状态</td>
          <td>每个样本不同</td>
      </tr>
      <tr>
          <td>$\theta$</td>
          <td>识别操作程序的共享 kernel</td>
          <td>梯度学习</td>
      </tr>
      <tr>
          <td>地址和算子</td>
          <td><code>2i/2i+1</code>、mirror、subtree plus</td>
          <td>固定数学规则</td>
      </tr>
  </tbody>
</table>
<h2 id="3-怎样避免背答案">3. 怎样避免背答案</h2>
<p>训练只出现浅地址和递归深度 1、2。测试分为：</p>
<table>
  <thead>
      <tr>
          <th>测试</th>
          <th>地址</th>
          <th>操作深度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>IID</td>
          <td>训练范围内</td>
          <td>1&ndash;2</td>
      </tr>
      <tr>
          <td>OOD address</td>
          <td>从未训练的深地址</td>
          <td>1&ndash;2</td>
      </tr>
      <tr>
          <td>OOD depth</td>
          <td>浅地址</td>
          <td>从未训练的 3&ndash;4</td>
      </tr>
      <tr>
          <td>OOD joint</td>
          <td>深地址</td>
          <td>3&ndash;4</td>
      </tr>
  </tbody>
</table>
<p>两个对照模型是：</p>
<ul>
<li><code>flat_program</code>：把 511 个位置摊平，再预测同一张维修工单；</li>
<li><code>flat_rewriter</code>：把 511 个位置摊平，直接输出修复后的 511 个数。</li>
</ul>
<h2 id="4-结果体检表">4. 结果体检表</h2>
<p>数值是整棵树完全恢复的比例，越大越好：</p>
<table>
  <thead>
      <tr>
          <th>测试</th>
          <th style="text-align: right">结构程序 + 固定算子</th>
          <th style="text-align: right">Flat 程序</th>
          <th style="text-align: right">Flat 直接改写</th>
          <th>判断</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>IID</td>
          <td style="text-align: right"><strong>92.70%</strong></td>
          <td style="text-align: right">15.35%</td>
          <td style="text-align: right">72.05%</td>
          <td>强阳性</td>
      </tr>
      <tr>
          <td>未见地址</td>
          <td style="text-align: right"><strong>84.00%</strong></td>
          <td style="text-align: right">0%</td>
          <td style="text-align: right">0%</td>
          <td>强阳性</td>
      </tr>
      <tr>
          <td>未见深度</td>
          <td style="text-align: right"><strong>4.40%</strong></td>
          <td style="text-align: right">0%</td>
          <td style="text-align: right">0%</td>
          <td>不合格</td>
      </tr>
      <tr>
          <td>地址与深度同时未见</td>
          <td style="text-align: right"><strong>5.80%</strong></td>
          <td style="text-align: right">0%</td>
          <td style="text-align: right">0%</td>
          <td>不合格</td>
      </tr>
  </tbody>
</table>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">参数量</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>结构程序 encoder</td>
          <td style="text-align: right"><strong>41,671</strong></td>
      </tr>
      <tr>
          <td>Flat 程序预测</td>
          <td style="text-align: right">235,913</td>
      </tr>
      <tr>
          <td>Flat 直接改写</td>
          <td style="text-align: right">196,927</td>
      </tr>
  </tbody>
</table>
<p>这支持一个窄但实在的结论：<strong>共享的树结构 kernel 学到了一种可以搬到新地址的识别规则；摊平模型只记住训练位置。</strong></p>
<h2 id="5-为什么未见深度失败">5. 为什么未见深度失败</h2>
<p>我们增加了一项诊断：把真实地址告诉 depth decoder，只检查它能不能读出从未训练的深度 3、4。结果是 <strong>93.65%</strong>。</p>
<p>可是不提供真实地址时，OOD-depth 的地址准确率只有 <strong>10.75%</strong>，整树恢复随之跌到 4.40%。这说明：</p>
<blockquote>
<p>深度本身大多可以从残差波中读出，但更深的操作改变了整片残差的形状，使只见过浅操作的地址定位器走错了。</p></blockquote>
<p>所以当前 Claim 只能“部分支持”。它证明了地址迁移，没有证明递归深度外推。</p>
<p>下一步不是增加更大的 MLP，而是把一次性猜全局地址改成真正共享的递归过程：kernel 从根开始反复输出 <code>stop/left/right</code>，在每一层用同一规则寻找残差边界。只有它在深度 1、2 上训练，却能循环到 3、4，才算递归规律进入 encoder。</p>
<h2 id="6-单机-ai-的存活空间">6. 单机 AI 的存活空间</h2>
<p>这个实验尚未证明语言、世界模型或意识，但展示了一条适合单机研究的计算路线：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>大网络直接生成全部状态
</span></span><span style="display:flex;"><span>        改为
</span></span><span style="display:flex;"><span>小网络识别短程序 + 确定代数执行大量状态变化
</span></span></code></pre></div><p>一次子堆 mirror 可以改变许多节点，但学习器只需输出算子、地址和深度。树越大，程序描述不必同比增长。这是 TreeHeap 可能节省样本、参数和计算的具体来源，不是口号。</p>
<p>真正的语言版本仍需回答：语料中的哪些规律能形成这种可执行程序，以及 encoder 如何在没有人工数论规则时发现它们。SPR-053 只搭起第一座受控桥梁：<strong>结构可以进入短程序，短程序可以调用 TreeHeap 自身算子恢复数据；但递归定位还没有学会。</strong></p>
<h2 id="evidence">Evidence</h2>
<ul>
<li>Claim: <code>M0-OPCODEC-C01</code></li>
<li>Source: <a href="https://github.com/houming818/sametime/blob/main/ara/m0-treeheap-math/src/algebraic_operator_codec_probe.py">algebraic_operator_codec_probe.py</a></li>
<li>Evidence: <a href="https://github.com/houming818/sametime/tree/main/ara/m0-treeheap-math/evidence/algebraic_operator_codec_probe">algebraic_operator_codec_probe</a></li>
<li>Seed: <code>53</code></li>
<li>Device: <code>io.grepcode.cn</code>, NVIDIA RTX 3090</li>
</ul>
<hr>
<h2 id="版权原创与许可证">版权、原创与许可证</h2>
<p>Copyright (C) 2026 Houming818 and SameTime contributors.</p>
<p>本文由 Houming818 提出核心研究方向，Codex Review 参与数学整理、ARA 声明、实验实现与结果分析。正文、表格和伪代码为本项目原创表达；实验结论以公开 ARA 源码和 Evidence 为边界，不声称已经证明语言、世界模型或意识。</p>
<blockquote>
<p><strong>SPDX-License-Identifier: GPL-3.0-only</strong>
<strong>License: GNU General Public License v3.0 only</strong></p></blockquote>
<p>本文允许复制、修改和分发，但衍生版本必须继续遵守 GNU GPL v3，并保留版权、许可证、修改说明及来源声明。完整许可证文本见本站 <a href="/LICENSE">/LICENSE</a>。</p>
<p>本文按“原样”提供，不附带任何明示或暗示担保。数学思想和事实本身不受版权垄断；本许可证适用于本文的原创文字、结构、表格、伪代码及其他可受版权保护的表达。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-054] TreeHeap 多分辨率金字塔：root 看全局，子堆保存细节</title>
      <link>https://www.grepcode.cn/spr/054-treeheap-multiresolution-pyramid.html</link>
      <pubDate>Tue, 14 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/054-treeheap-multiresolution-pyramid.html</guid>
      <description>三 seed、每 seed 100 万真实文本 block 的实验表明：冻结 TreeHeap root 后，带地址的低维 detail code 可形成稳定的渐进恢复曲线；同时记录 flat 对照失败尾部与尚未完成的验证。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-多分辨率金字塔root-看全局子堆保存细节">TreeHeap 多分辨率金字塔：root 看全局，子堆保存细节</h1>
<p>先说这篇文章提出的新假设：</p>
<blockquote>
<p>TreeHeap 不应该强迫一个 root 无损背下整句话。更合理的设计是：root 保存全局轮廓，各层 subheap 保存逐步补回细节所需的低维编码。</p></blockquote>
<p>这与缩小一张图片很像。</p>
<p>一张 <code>1024 x 1024</code> 的照片缩成 <code>64 x 64</code> 后，不可能保留每一根头发，但我们仍然可能看出：</p>
<ul>
<li>画面里有没有人；</li>
<li>人站在哪里；</li>
<li>背景是房间还是街道；</li>
<li>整体颜色和轮廓是什么。</li>
</ul>
<p>丢失的主要是细小纹理。</p>
<p>对于语言，TreeHeap 的叶子可以看成高分辨率数据，内部节点是中等分辨率，root 是最低分辨率的全局摘要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token leaves       原始高分辨率
</span></span><span style="display:flex;"><span>local subheaps     局部短语与关系
</span></span><span style="display:flex;"><span>upper subheaps     更大范围的组合
</span></span><span style="display:flex;"><span>root               全局低分辨率表示
</span></span></code></pre></div><p>但这仍然只是类比。它是否真的成立，必须变成一个可以失败的实验。</p>
<hr>
<h2 id="1-为什么现在提出这个问题">1. 为什么现在提出这个问题</h2>
<p>上一轮实验已经用完整中文语料训练了一个 TreeHeap root compressor。</p>
<p>输入是64个 token：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x1, x2, ..., x64
</span></span></code></pre></div><p>TreeHeap 反复用共享的三槽 kernel 折叠相邻节点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[root, left, right]
</span></span></code></pre></div><p>最后只留下一个192维 root，由 decoder 预测下一个 token。</p>
<p>这次全量训练处理了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>文档数             7,564,966
</span></span><span style="display:flex;"><span>训练 block 数      38,251,247
</span></span><span style="display:flex;"><span>news block        28,052,019
</span></span><span style="display:flex;"><span>wiki block         4,375,165
</span></span><span style="display:flex;"><span>web block          5,824,063
</span></span><span style="display:flex;"><span>训练时间            7.94 小时
</span></span></code></pre></div><p>最终可用模型是四头无残差 TreeHeap：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>验证 NLL，越低越好</td>
          <td style="text-align: right">6.2365</td>
      </tr>
      <tr>
          <td>Top-1</td>
          <td style="text-align: right">11.96%</td>
      </tr>
      <tr>
          <td>Top-5</td>
          <td style="text-align: right">23.29%</td>
      </tr>
      <tr>
          <td>root variance</td>
          <td style="text-align: right">0.05843</td>
      </tr>
  </tbody>
</table>
<p>更重要的是，破坏左右地址配对后，NLL 增加了 <code>2.6252</code>。</p>
<p>这说明 root 不是普通词袋。它确实依赖 TreeHeap 的递归地址和左右配对，保存了某些有助于预测的全局信息。</p>
<p>但它没有回答另一个问题：</p>
<blockquote>
<p>root 丢掉了哪些细节？能否用少量、分层的补充信息把这些细节找回来？</p></blockquote>
<hr>
<h2 id="2-不要让-root-背诵整句话">2. 不要让 root 背诵整句话</h2>
<p>假设每个 token 是192维，64个 token 一共需要：</p>
$$ 64 \times 192 = 12288 $$<p>个浮点数。</p>
<p>如果把它们压成一个192维 root，容量只剩原来的：</p>
$$ \frac{192}{12288}=1.56\% $$<p>这显然是强压缩。</p>
<p>强压缩不等于错误。问题在于任务需要什么。</p>
<p>如果任务只是判断“大致在说吃饭还是旅行”，root 也许已经够用；如果任务是逐词 echo、翻译人名或还原数字，root 就可能丢失关键细节。</p>
<p>因此我们不再要求：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个 root = 完整句子
</span></span></code></pre></div><p>而改成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个 root        = 全局摘要
</span></span><span style="display:flex;"><span>多层 detail code = 折叠时丢失的局部细节
</span></span></code></pre></div><hr>
<h2 id="3-新的数据结构长什么样">3. 新的数据结构长什么样</h2>
<p>对于左右两个子节点：</p>
$$ L,\;R \in \mathbb{R}^{192} $$<p>已经训练好的 TreeHeap fold kernel 生成父节点：</p>
$$ P=D_\theta(L,R) $$<p>这里的 $D_\theta$ 是上一轮完整训练得到的模型。新实验会冻结它，不允许它继续变化。</p>
<p>然后增加一个细节编码器：</p>
$$ d=Q_\phi(L,R,P),\qquad d\in\mathbb{R}^{k} $$<p>其中 $k$ 比192小很多，例如8、16、32或64。</p>
<p>解码器读取父节点和细节：</p>
$$ (\hat L,\hat R)=U_\psi(P,d) $$<p>如果 $\hat L$ 和 $\hat R$ 接近原来的 $L$、$R$，说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>父节点 P          保存了公共、粗粒度信息
</span></span><span style="display:flex;"><span>细节向量 d         保存了区分左右孩子所需的信息
</span></span></code></pre></div><p>完整节点可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>PyramidNode {
</span></span><span style="display:flex;"><span>    coarse_state P
</span></span><span style="display:flex;"><span>    detail_code  d
</span></span><span style="display:flex;"><span>    left_address
</span></span><span style="display:flex;"><span>    right_address
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>解码从 root 开始：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root + 顶层 detail
</span></span><span style="display:flex;"><span>  -&gt; 两个较粗子节点
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>每个子节点 + 下一层 detail
</span></span><span style="display:flex;"><span>  -&gt; 四个更细节点
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>不断递归
</span></span><span style="display:flex;"><span>  -&gt; 尽可能恢复64个叶子
</span></span></code></pre></div><p>这就是 TreeHeap 多分辨率金字塔。</p>
<hr>
<h2 id="4-这和普通残差有什么不同">4. 这和普通残差有什么不同</h2>
<p>普通残差通常写成：</p>
$$ H_{t+1}=H_t+\Delta H_t $$<p>它主要用于让旧状态和梯度穿过深层网络。</p>
<p>本文的 detail code 不直接加回同一个状态。它回答的是另一个问题：</p>
<blockquote>
<p>把两个高分辨率孩子压成一个低分辨率父节点以后，重建孩子还缺少什么信息？</p></blockquote>
<p>所以这里更接近图像的拉普拉斯金字塔或小波中的“低频摘要 + 高频细节”：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>coarse state   负责大轮廓
</span></span><span style="display:flex;"><span>detail code    负责缺失差异
</span></span></code></pre></div><p>上一轮四头残差模型在 <code>step 62,400</code> 发生 NaN，已经否定了当时那个“无约束全局残差尺度”的实现。</p>
<p>新方案不会复用那个失败公式。它冻结成功的无残差 root encoder，只训练独立的 detail encoder 和 decoder。</p>
<hr>
<h2 id="5-它真的压缩了吗">5. 它真的压缩了吗</h2>
<p>一棵64叶子的完全二叉树有63个内部节点。</p>
<p>如果只保存一个192维 root，并为每个内部节点保存 $k$ 维 detail，那么总容量是：</p>
$$ R(k)=192+63k $$<table>
  <thead>
      <tr>
          <th style="text-align: right">detail宽度 $k$</th>
          <th style="text-align: right">总浮点数</th>
          <th style="text-align: right">原始容量占比</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td style="text-align: right">192</td>
          <td style="text-align: right">1.56%</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">696</td>
          <td style="text-align: right">5.66%</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">1,200</td>
          <td style="text-align: right">9.77%</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">2,208</td>
          <td style="text-align: right">17.97%</td>
      </tr>
      <tr>
          <td style="text-align: right">64</td>
          <td style="text-align: right">4,224</td>
          <td style="text-align: right">34.38%</td>
      </tr>
      <tr>
          <td style="text-align: right">原始叶子</td>
          <td style="text-align: right">12,288</td>
          <td style="text-align: right">100%</td>
      </tr>
  </tbody>
</table>
<p>例如 <code>k=32</code> 时，只使用原始激活量的约18%。</p>
<p>如果它已经能恢复大部分 token 和顺序，就出现了有价值的压缩；如果必须把 <code>k</code> 增加到接近192才能恢复，那么它虽然能编码，却没有明显压缩优势。</p>
<p>这里说的只是“浮点数数量”，还不是严格的比特压缩。只有完成量化、熵编码和实际文件大小测量后，才能讨论真正的 bit rate。</p>
<hr>
<h2 id="6-新-claim">6. 新 Claim</h2>
<p>新声明编号：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S3-TREEHEAP-PYRAMID-C01
</span></span></code></pre></div><p>正式内容是：</p>
<blockquote>
<p>一个冻结的 TreeHeap root compressor 可以扩展为多分辨率 codec：root 保存粗粒度、与任务相关的状态；每个内部地址保存有界的 detail code。随着 detail 容量增加，真实语料的重建质量应单调提高，同时冻结 root 的下一词预测能力保持不变。</p></blockquote>
<p>当前状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>supported mechanism / three-seed 1M-block proof
</span></span></code></pre></div><p>它已经得到三 seed 实验支持，但结论仅限于本文实现的激活空间 codec，不能外推为通用压缩或架构优越性。</p>
<hr>
<h2 id="7-predict成立时我们应该看到什么">7. Predict：成立时我们应该看到什么</h2>
<h3 id="p1root-的旧能力必须完全保留">P1：root 的旧能力必须完全保留</h3>
<p>完整语料 checkpoint 原来的验证 NLL 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>6.236525
</span></span></code></pre></div><p>正式实验另取固定 audit 子集，在训练 detail codec 前后各测一次。新模块不能偷偷改写 root：</p>
$$ |NLL_{after}-NLL_{before}|<10^{-5} $$<p>如果变化，说明代码存在旁路或错误。</p>
<h3 id="p2细节越多恢复应该越好">P2：细节越多，恢复应该越好</h3>
<p>我们预测：</p>
$$ E_{root}>E_8>E_{16}>E_{32}>E_{64} $$<p>其中 $E$ 是叶子状态的重建误差。</p>
<p>对应的 token Top-1、Top-5和顺序恢复率应该反向单调上升。</p>
<h3 id="p3形成清楚的率失真曲线">P3：形成清楚的率失真曲线</h3>
<p>横轴是存储容量，纵轴是重建误差：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>容量小 --------------------&gt; 容量大
</span></span><span style="display:flex;"><span>误差大 --------------------&gt; 误差小
</span></span></code></pre></div><p>detail容量与重建质量的 Spearman 相关性应至少达到 <code>0.9</code>。</p>
<h3 id="p4有限容量必须带来明显收益">P4：有限容量必须带来明显收益</h3>
<p><code>k=64</code> 必须让 root-only 的重建 MSE 至少下降50%。</p>
<p>如果增加了大量细节却只改善一点点，说明当前 fold 已经过早破坏了信息。</p>
<h3 id="p5treeheap-地址必须有用">P5：TreeHeap 地址必须有用</h3>
<p>打乱左右地址以后，至少满足一个条件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>重建 MSE 增加 &gt;= 10%
</span></span><span style="display:flex;"><span>或
</span></span><span style="display:flex;"><span>token accuracy 下降 &gt;= 5 个百分点
</span></span></code></pre></div><h3 id="p6不能只打败自己">P6：不能只打败自己</h3>
<p>在相同存储容量下，它还要比较：</p>
<ul>
<li>固定平均池化金字塔；</li>
<li>固定 Haar 式平均/差分；</li>
<li>flat autoencoder；</li>
<li>随机左右配对树。</li>
</ul>
<p>只有 TreeHeap 在至少一个有效容量上击败这些对照，才能提出“TreeHeap具有更好率失真归纳偏置”的后续声明。</p>
<hr>
<h2 id="8-实验怎样执行">8. 实验怎样执行</h2>
<p>第一轮不直接再跑八小时。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实语料 block       1,000,000
</span></span><span style="display:flex;"><span>上下文长度            64 token
</span></span><span style="display:flex;"><span>冻结 root encoder      四头无残差 checkpoint
</span></span><span style="display:flex;"><span>detail k              0 / 8 / 16 / 32 / 64
</span></span><span style="display:flex;"><span>随机种子               3
</span></span></code></pre></div><p>训练过程：</p>
<ol>
<li>读取冻结 TreeHeap；</li>
<li>保存每层的 left、right、parent 状态；</li>
<li>只训练 $Q_\phi$ 和 $U_\psi$；</li>
<li>在未见过的 block 上递归重建；</li>
<li>输出每个容量的率失真曲线；</li>
<li>做地址破坏和逐层 detail 消融。</li>
</ol>
<p>指标分开报告，不能只给一个“大锅 loss”：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th>检查什么</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>root next-token NLL</td>
          <td>全局预测能力是否被破坏</td>
      </tr>
      <tr>
          <td>leaf embedding MSE</td>
          <td>连续状态恢复</td>
      </tr>
      <tr>
          <td>token Top-1/Top-5</td>
          <td>词面恢复</td>
      </tr>
      <tr>
          <td>sequence token accuracy</td>
          <td>整句恢复</td>
      </tr>
      <tr>
          <td>edit similarity</td>
          <td>顺序接近程度</td>
      </tr>
      <tr>
          <td>bag overlap</td>
          <td>内容是否回来</td>
      </tr>
      <tr>
          <td>position accuracy</td>
          <td>地址与次序是否回来</td>
      </tr>
      <tr>
          <td>floats/token</td>
          <td>付出了多少容量</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="9-实验结果金字塔成立了吗">9. 实验结果：金字塔成立了吗</h2>
<p>正式实验在 <code>io</code> 的 RTX 3090 上完成。三个随机种子分别是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>71401 / 71402 / 71403
</span></span></code></pre></div><p>每个 seed 读取 <code>1,000,000</code> 个真实中文文本 block，并在 <code>8,192</code> 个 held-out block 上评估。训练期间，原 TreeHeap root encoder 和 next-token decoder 完全冻结。</p>
<p>先给一张“体检报告”。指标方向如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>MSE             越低越好
</span></span><span style="display:flex;"><span>存储比例         越低越省容量
</span></span><span style="display:flex;"><span>Token Top-1     越高越好
</span></span><span style="display:flex;"><span>Sequence Exact  越高越好，要求64个位置全部恢复正确
</span></span></code></pre></div><table>
  <thead>
      <tr>
          <th style="text-align: right">detail $k$</th>
          <th style="text-align: right">TreeHeap存储</th>
          <th style="text-align: right">Flat存储</th>
          <th style="text-align: right">TreeHeap MSE</th>
          <th style="text-align: right">Flat MSE</th>
          <th style="text-align: right">Haar MSE</th>
          <th style="text-align: right">Token Top-1</th>
          <th style="text-align: right">64-token整段Exact</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td style="text-align: right">192</td>
          <td style="text-align: right">192</td>
          <td style="text-align: right">1.9334</td>
          <td style="text-align: right"><strong>1.9104</strong></td>
          <td style="text-align: right">1.9110</td>
          <td style="text-align: right">6.50%</td>
          <td style="text-align: right">0.00%</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">696</td>
          <td style="text-align: right">768</td>
          <td style="text-align: right"><strong>0.8803</strong></td>
          <td style="text-align: right">1.8416</td>
          <td style="text-align: right">1.8232</td>
          <td style="text-align: right">51.05%</td>
          <td style="text-align: right">0.00%</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">1,200</td>
          <td style="text-align: right">1,344</td>
          <td style="text-align: right"><strong>0.7622</strong></td>
          <td style="text-align: right">1.7459</td>
          <td style="text-align: right">1.7471</td>
          <td style="text-align: right">76.84%</td>
          <td style="text-align: right">0.00%</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">2,208</td>
          <td style="text-align: right">2,304</td>
          <td style="text-align: right"><strong>0.6516</strong></td>
          <td style="text-align: right">1.7047</td>
          <td style="text-align: right">1.5979</td>
          <td style="text-align: right">95.01%</td>
          <td style="text-align: right">5.99%</td>
      </tr>
      <tr>
          <td style="text-align: right">64</td>
          <td style="text-align: right">4,224</td>
          <td style="text-align: right">4,224</td>
          <td style="text-align: right"><strong>0.5526</strong></td>
          <td style="text-align: right">1.6042</td>
          <td style="text-align: right">1.2881</td>
          <td style="text-align: right">99.64%</td>
          <td style="text-align: right">82.68%</td>
      </tr>
  </tbody>
</table>
<p>这张表可以分三步理解。</p>
<h3 id="91-只有-root-时treeheap-没有神奇优势">9.1 只有 root 时，TreeHeap 没有神奇优势</h3>
<p><code>k=0</code> 时只保存一个192维 root。TreeHeap MSE 是 <code>1.9334</code>，反而略差于 flat 和 Haar 的约 <code>1.91</code>。</p>
<p>这很重要：实验没有证明“只要叫 TreeHeap 就一定更好”。一个只占原始容量 <code>1.56%</code> 的 root 主要保存预测下一个 token 所需的粗粒度信息，不能无损背下64个叶状态。</p>
<h3 id="92-加入带地址-detail-后误差稳定下降">9.2 加入带地址 detail 后，误差稳定下降</h3>
<p>三个 seed 都得到严格单调曲线：</p>
$$ 1.9334 > 0.8803 > 0.7622 > 0.6516 > 0.5526 $$<p>detail 宽度与恢复质量的 Spearman 相关系数在三个 seed 中都约为 <code>1.0</code>。<code>k=64</code> 只使用原始激活量的 <code>34.38%</code>，MSE 已降到 root-only 的 <code>28.6%</code>，超过了预注册的“至少减半”门槛。</p>
<p>这里的 token 指标，是把重建叶向量放回冻结 encoder 的 embedding 坐标系，寻找最近 token。<code>k=64</code> 的平均 token Top-1 是 <code>99.64%</code>，64个位置全部正确的整段恢复率是 <code>82.68%</code>。</p>
<h3 id="93-地址不是装饰">9.3 地址不是装饰</h3>
<p>把已经学好的 detail code 循环移动到错误地址，<code>k=64</code> 的 MSE 从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.5526 -&gt; 3.3147
</span></span></code></pre></div><p>它不只是变差一点，而是比 root-only 还差。这说明 decoder 依赖“哪段细节属于哪个内部地址”。detail 是带地址的局部信息，不是可以随便交换的附加向量袋。</p>
<h3 id="94-stronger-flat-baseline-仍有失败尾部">9.4 stronger flat baseline 仍有失败尾部</h3>
<p>最初 smoke 使用固定 <code>256D</code> 隐层的 flat autoencoder。我们发现这会人为卡住大码率模型，于是在正式实验前主动中止，并改成拥有 <code>1/4/7/12/22</code> 个192维 latent 的 flat attention codec。它在多数档位还获得了比 TreeHeap略多的存储预算。</p>
<p>正式 flat <code>k=64</code> 的三个 seed MSE 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1.5245 / 1.3767 / 1.9113
</span></span></code></pre></div><p>TreeHeap 对应为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.5526 / 0.5499 / 0.5554
</span></span></code></pre></div><p>TreeHeap 在本次对照中不仅均值更低，而且 seed 更稳定。但 flat 的第三个 seed 明显发生了 latent 学习失败，所以本文只能说：</p>
<blockquote>
<p>当前 TreeHeap pyramid 击败了本实验实现的同码率 flat attention codec 和固定 Haar codec。</p></blockquote>
<p>不能说：</p>
<blockquote>
<p>TreeHeap 已经击败所有 autoencoder、Transformer 或所有可能的压缩算法。</p></blockquote>
<h3 id="95-predict-判定">9.5 Predict 判定</h3>
<table>
  <thead>
      <tr>
          <th>Predict</th>
          <th style="text-align: right">结果</th>
          <th>判定</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>P1 root NLL不变</td>
          <td style="text-align: right">audit NLL <code>6.2997973263 -&gt; 6.2997973263</code>，参数指纹相同</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P2 MSE随容量单调下降</td>
          <td style="text-align: right">三个 seed 全部严格单调</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P3 Spearman至少0.9</td>
          <td style="text-align: right">三个 seed 均约1.0</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P4 k=64至少减半MSE</td>
          <td style="text-align: right">降至root-only的28.6%</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P5 地址破坏明显伤害</td>
          <td style="text-align: right">MSE增加约500%</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P6 击败已实现同码率对照</td>
          <td style="text-align: right">k=8到64均优于flat/Haar</td>
          <td>有界通过</td>
      </tr>
  </tbody>
</table>
<p>因此，Claim <code>S3-TREEHEAP-PYRAMID-C01</code> 从 <code>experiment pending</code> 更新为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>supported mechanism / three-seed 1M-block proof
</span></span></code></pre></div><p>仍未完成的部分包括：独立 random-pairing 训练、逐层 detail 消融、量化、熵编码以及更强的 flat/Transformer codec。尤其在逐层消融完成前，不能声称高层一定学习“全局语义”、低层一定学习“词面细节”。</p>
<hr>
<h2 id="10-toy为什么逐层细节有意义">10. Toy：为什么逐层细节有意义</h2>
<p>考虑一句短句：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the cat is eating rice
</span></span></code></pre></div><p>最低分辨率 root 可能只能表达：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>某个主体正在进行进食活动
</span></span></code></pre></div><p>加入顶层 detail 后，可能恢复：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>主体部分 | 动作与对象部分
</span></span></code></pre></div><p>继续加入更低层 detail：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the cat | is eating rice
</span></span></code></pre></div><p>最后才恢复具体词面：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>the | cat | is | eating | rice
</span></span></code></pre></div><p>这不是说模型一定会形成这些人类语法标签。实验只检查一个更基础的事实：</p>
<blockquote>
<p>不同层级是否真的以越来越大的容量，逐渐补回越来越细的信息。</p></blockquote>
<p>如果没有这种渐进关系，“金字塔”就只是一个漂亮名字。</p>
<hr>
<h2 id="11-什么结果会否定它">11. 什么结果会否定它</h2>
<p>以下任一情况都会让 Claim 被拒绝或缩小：</p>
<ol>
<li>增加 detail 后，重建误差不单调下降；</li>
<li>必须接近原始容量才能恢复；</li>
<li>随机树和真实地址表现相同；</li>
<li>平均池化或 flat autoencoder 在同容量下全面更好；</li>
<li>root NLL发生变化，说明实验偷偷改写了旧模型；</li>
<li>所有层的 detail 完全可以互换，没有尺度分工。</li>
</ol>
<p>失败不是“调参不够”。这些失败会直接告诉我们：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 TreeHeap fold 不是合适的降采样核
</span></span><span style="display:flex;"><span>或
</span></span><span style="display:flex;"><span>语言信息不适合按当前地址形成多尺度编码
</span></span></code></pre></div><hr>
<h2 id="12-哪些部分是我们的原创">12. 哪些部分是我们的原创</h2>
<p>为了避免把已有数学重新命名为自己的发明，这里明确划界。</p>
<p>已有公共理论包括：</p>
<ul>
<li>多分辨率分析；</li>
<li>高斯与拉普拉斯图像金字塔；</li>
<li>小波与平均/差分分解；</li>
<li>autoencoder；</li>
<li>信息论中的率失真理论。</li>
</ul>
<p>我们不声称这些理论由 SameTime 发明。</p>
<p>本文的原创研究贡献是：</p>
<ol>
<li>把已经测得地址因果性的 TreeHeap root compressor 定义为冻结降采样核；</li>
<li>设计“一个 root + 每个内部地址一个低维 detail code”的语言 TreeHeap codec；</li>
<li>给出固定容量公式 $R(k)=192+63k$；</li>
<li>设计 root 不回归、渐进恢复、地址破坏、同容量基线和层级消融；</li>
<li>登记可证伪 Claim <code>S3-TREEHEAP-PYRAMID-C01</code> 及其数值门槛。</li>
</ol>
<p>这是 SameTime 项目在现有数学基础上的原创架构假设与实验协议。本文报告的三 seed 结果支持其有限机制 Claim，但不构成“世界首创”、专利新颖性或通用架构优越性结论。</p>
<hr>
<h2 id="13-ara-与可复核材料">13. ARA 与可复核材料</h2>
<p>正式 ARA：</p>
<ul>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/logic/multiresolution_treeheap_pyramid.md">Multiresolution TreeHeap Pyramid</a></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/logic/claims.md">S3 Claims Registry</a></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/evidence/s3_residual_treeheap_forest/result_analysis.md">上一轮全量实验分析</a></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/evidence/s3_multiresolution_treeheap_pyramid/main_v2/result_analysis.md">本次实验结果分析</a></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/evidence/s3_multiresolution_treeheap_pyramid/main_v2/summary.json">本次原始汇总数据</a></li>
</ul>
<p>任何后续文章都必须同时报告通过和失败的 Predict，不允许只展示最好的一条曲线。</p>
<hr>
<h2 id="版权原创与许可证">版权、原创与许可证</h2>
<p>Copyright (C) 2026 Houming818 and SameTime contributors.</p>
<p>本文由 Houming818 提出核心类比与研究方向，Codex Review 参与数学整理、ARA声明和实验协议编写。正文与伪代码为本项目原创表达，没有复制第三方论文正文、代码或插图；已有理论已在上一节明确列为公共学术背景。</p>
<blockquote>
<p><strong>SPDX-License-Identifier: GPL-3.0-only</strong><br>
<strong>License: GNU General Public License v3.0 only</strong></p></blockquote>
<p>本文允许复制、修改和分发，但衍生版本必须继续遵守 GNU GPL v3，并保留版权、许可证、修改说明及来源声明。完整许可证文本见本站 <a href="/LICENSE">/LICENSE</a>。</p>
<p>本文按“原样”提供，不附带任何明示或暗示担保。数学思想和事实本身不受版权垄断；本许可证适用于本文的原创文字、结构、表格、伪代码及其他可受版权保护的表达。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-055] 让信息向 root 生长：TreeHeap 的多尺度 Mask 学习</title>
      <link>https://www.grepcode.cn/spr/055-treeheap-multiscale-mask-root-growth.html</link>
      <pubDate>Tue, 14 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/055-treeheap-multiscale-mask-root-growth.html</guid>
      <description>真实中文实验表明，多尺度子堆 Mask 能让 root 获得样本相关信息，但 root 贡献随 Mask 深度严格下降；本文公开 5/6 Gate、反向结果与下一步修正。</description>
      <content:encoded><![CDATA[<h1 id="让信息向-root-生长treeheap-的多尺度-mask-学习">让信息向 root 生长：TreeHeap 的多尺度 Mask 学习</h1>
<p>这篇文章先不宣布实验胜利。</p>
<p>相反，我们想带着一点更具体的希望，重新提出一个问题：</p>
<blockquote>
<p>如果普通 echo 只要求模型恢复眼前的 token，那么模型为什么要费力把信息送到 root？</p></blockquote>
<p>这句话来自 Houming818 对当前实验的修正。它改变了我们看待 TreeHeap encoder 的方式。</p>
<p>此前我们容易把注意力放在算子的形式上：FOLD 怎样计算，DETAIL 怎样保存，UNFOLD 怎样恢复。可是即使所有算子都在树上递归执行，只要训练问题太简单，模型仍然会选择最短的解题路线。</p>
<p>这不一定说明 TreeHeap 没有能力。更可能说明：我们问的问题还不够深。</p>
<hr>
<h2 id="1-当前模型为什么偏爱-detail">1. 当前模型为什么偏爱 detail</h2>
<p>假设一句话被写入一棵 TreeHeap：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>                    root
</span></span><span style="display:flex;"><span>                  /      \
</span></span><span style="display:flex;"><span>            subheap A    subheap B
</span></span><span style="display:flex;"><span>             /   \        /   \
</span></span><span style="display:flex;"><span>           x1    x2      x3    x4
</span></span></code></pre></div><p>普通 echo 的任务只是输入 x1、x2、x3、x4，再输出同样的 x1、x2、x3、x4。</p>
<p>如果每个局部 detail 都能保存附近 token，模型就可以走一条很短的路：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x1 -&gt; detail1 -&gt; x1
</span></span><span style="display:flex;"><span>x2 -&gt; detail2 -&gt; x2
</span></span><span style="display:flex;"><span>x3 -&gt; detail3 -&gt; x3
</span></span><span style="display:flex;"><span>x4 -&gt; detail4 -&gt; x4
</span></span></code></pre></div><p>这条路短、梯度直接、loss 下降快。</p>
<p>相比之下，把信息先抽到 parent，再抽到 root，最后递归展开回来，需要经过更多卷积：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token
</span></span><span style="display:flex;"><span>  -&gt; local fold
</span></span><span style="display:flex;"><span>  -&gt; parent fold
</span></span><span style="display:flex;"><span>  -&gt; root
</span></span><span style="display:flex;"><span>  -&gt; parent unfold
</span></span><span style="display:flex;"><span>  -&gt; local unfold
</span></span><span style="display:flex;"><span>  -&gt; token
</span></span></code></pre></div><p>如果两条路都能完成 echo，优化器没有理由主动选择更长的那条。</p>
<p>因此，root 没有成为主要信息载体，并不令人意外。普通 echo 实际上只问了一个浅层问题：</p>
<blockquote>
<p>你能不能把刚刚看到的符号再写一遍？</p></blockquote>
<p>它没有问：</p>
<blockquote>
<p>当局部信息缺失时，你能否利用更大范围的结构推断它？</p></blockquote>
<hr>
<h2 id="2-不要强迫-root应该给-root-一份工作">2. 不要强迫 root，应该给 root 一份工作</h2>
<p>一种直接做法是在公式里规定：没有 root 就不允许 decoder 工作。</p>
<p>这样当然能让 root 参与，但它更像人为封路。模型使用 root，是因为程序员不准它走别的路，而不一定是因为数据中的规律需要 root。</p>
<p>Houming818 提出的方向更自然：</p>
<blockquote>
<p>不要从结构上强迫 root 参与。通过扰动和 Mask 提出更深的问题，让局部 detail 无法单独回答，root 和上层卷积结果才有机会自然获得信息。</p></blockquote>
<p>也就是说，我们不预先规定 root 必须表示句意。</p>
<p>我们只改变训练问题，让不同尺度的节点承担不同尺度的信息需求。</p>
<hr>
<h2 id="3-从-mask-一个词到-mask-一整个子堆">3. 从 Mask 一个词，到 Mask 一整个子堆</h2>
<p>考虑一句简单的话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>今天 我 吃了 一碗 米饭
</span></span></code></pre></div><h3 id="31-只遮挡一个-token">3.1 只遮挡一个 token</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>今天 我 吃了 一碗 [MASK]
</span></span></code></pre></div><p>局部信息“一碗”已经提供了很强的提示。附近节点可能就能给出一个概率桶：</p>
<table>
  <thead>
      <tr>
          <th>候选</th>
          <th style="text-align: right">概率示意</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>米饭</td>
          <td style="text-align: right">0.31</td>
      </tr>
      <tr>
          <td>面条</td>
          <td style="text-align: right">0.24</td>
      </tr>
      <tr>
          <td>粥</td>
          <td style="text-align: right">0.12</td>
      </tr>
      <tr>
          <td>药</td>
          <td style="text-align: right">0.03</td>
      </tr>
      <tr>
          <td>其他</td>
          <td style="text-align: right">0.30</td>
      </tr>
  </tbody>
</table>
<p>这主要训练局部共现。</p>
<h3 id="32-遮挡一个小-subheap">3.2 遮挡一个小 subheap</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>今天 我 吃了 [一碗 米饭]
</span></span></code></pre></div><p>现在局部 detail 被整个拿走。模型需要结合“我”“吃了”和前后上下文，才能判断缺失部分大概是食物或用餐对象。</p>
<p>这开始要求 parent 和 sibling 提供信息。</p>
<h3 id="33-遮挡更大的-subheap">3.3 遮挡更大的 subheap</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>今天 我 [吃了 一碗 米饭]
</span></span></code></pre></div><p>模型必须从更高层状态判断：</p>
<ul>
<li>这里缺少一个事件；</li>
<li>事件可能与“今天”和“我”有关；</li>
<li>输出应当是一段动作描述，而不只是一个孤立名词。</li>
</ul>
<p>此时，靠近 root 的状态才真正获得了一份局部 detail 无法独立完成的工作。</p>
<hr>
<h2 id="4-treeheap-mask-不是普通随机遮字">4. TreeHeap Mask 不是普通随机遮字</h2>
<p>普通语言模型会随机遮掉若干 token。TreeHeap 可以做得更有结构，因为它已经拥有地址、路径和 subheap。</p>
<p>我们可以直接使用 TreeHeap 代数中的操作构造扰动：</p>
<table>
  <thead>
      <tr>
          <th>扰动方式</th>
          <th>操作对象</th>
          <th>想检查的能力</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>leaf mask</td>
          <td>单个叶子</td>
          <td>局部共现</td>
      </tr>
      <tr>
          <td>sibling mask</td>
          <td>一对孩子</td>
          <td>parent 是否保存摘要</td>
      </tr>
      <tr>
          <td>subheap cut</td>
          <td>完整子堆</td>
          <td>ancestor 是否保存更大范围信息</td>
      </tr>
      <tr>
          <td>detail dropout</td>
          <td>某层 detail</td>
          <td>粗粒度状态能否补回细节</td>
      </tr>
      <tr>
          <td>subtree replacement</td>
          <td>用别的子堆替换</td>
          <td>模型能否发现上下文不一致</td>
      </tr>
      <tr>
          <td>address shift</td>
          <td>detail 移到错误地址</td>
          <td>路径和地址是否有真实作用</td>
      </tr>
      <tr>
          <td>mirror perturbation</td>
          <td>子堆左右翻转</td>
          <td>顺序与手性信息是否被编码</td>
      </tr>
  </tbody>
</table>
<p>这里最重要的是：扰动对象仍然是 TreeHeap 中的合法对象。</p>
<p>不是先把树摊平成数组，再用另一套代数随便打乱；而是使用 CUT、MASK、REPLACE、SHIFT、MIRROR 等树上操作改变同一个数据结构。</p>
<hr>
<h2 id="5-两种-mask回答两个不同问题">5. 两种 Mask，回答两个不同问题</h2>
<h3 id="51-压缩式-mask">5.1 压缩式 Mask</h3>
<p>Encoder 看过完整输入，但 decoder 随机拿不到某些 detail：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整句子
</span></span><span style="display:flex;"><span>  -&gt; encoder
</span></span><span style="display:flex;"><span>  -&gt; root + 多层 detail
</span></span><span style="display:flex;"><span>  -&gt; 丢弃部分 detail
</span></span><span style="display:flex;"><span>  -&gt; decoder 恢复原句
</span></span></code></pre></div><p>它研究的是：</p>
<blockquote>
<p>信息有没有从 leaf 向 parent 和 root 形成冗余摘要？</p></blockquote>
<p>如果丢掉局部 detail 后，上层状态仍能恢复一部分内容，说明信息确实向上抽取了。</p>
<h3 id="52-推断式-mask">5.2 推断式 Mask</h3>
<p>Encoder 从一开始就看不到被遮挡内容：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>受损句子
</span></span><span style="display:flex;"><span>  -&gt; encoder
</span></span><span style="display:flex;"><span>  -&gt; TreeHeap
</span></span><span style="display:flex;"><span>  -&gt; 预测缺失 subheap
</span></span></code></pre></div><p>它研究的是：</p>
<blockquote>
<p>模型是否从真实语料中学到了可以补全缺失信息的统计规律？</p></blockquote>
<p>这种任务不要求模型逐字恢复任意随机内容。正确输出是概率分布，而不是提前写好的唯一答案。</p>
<p>压缩和推断都重要，但它们回答的是不同问题，实验必须分开报告。</p>
<hr>
<h2 id="6-卷积怎样推动信息向上生长">6. 卷积怎样推动信息向上生长</h2>
<p>在每个内部节点，encoder 使用共享分析卷积核：</p>
$$ p_i = K_{\mathrm{fold}}(h_{2i}, h_{2i+1}) $$<p>继续递归：</p>
$$ p_{\operatorname{parent}(i)} = K_{\mathrm{fold}}(p_i,p_j) $$<p>同一个 kernel 在不同地址和深度重复使用。因此，一条信息若要到达 root，必须经历多次相同类型的局部抽取。</p>
<p>Decoder 使用共享合成卷积核：</p>
$$ (\hat h_{2i},\hat h_{2i+1}) = K_{\mathrm{unfold}}(p_i,d_i) $$<p>Mask 训练产生的梯度会沿着递归链返回：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>缺失 token 的 loss
</span></span><span style="display:flex;"><span>  -&gt; unfold kernel
</span></span><span style="display:flex;"><span>  -&gt; ancestor state
</span></span><span style="display:flex;"><span>  -&gt; fold kernel
</span></span><span style="display:flex;"><span>  -&gt; 更低层输入
</span></span></code></pre></div><p>如果只 Mask 一个叶子，梯度可能主要停留在附近。</p>
<p>如果 Mask 整个 subheap，局部节点已经没有答案，梯度必须要求更高层状态改善。这才是“把信息抽到离 root 更近的地方”的具体学习过程。</p>
<hr>
<h2 id="7-不使用一锅炖的-loss">7. 不使用一锅炖的 Loss</h2>
<p>我们不打算一次把所有尺度混成一个难以解释的总 loss。</p>
<p>更清晰的方法是让不同 batch 轮流提出不同深度的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>batch 1  leaf mask
</span></span><span style="display:flex;"><span>batch 2  depth-1 subheap mask
</span></span><span style="display:flex;"><span>batch 3  depth-2 subheap mask
</span></span><span style="display:flex;"><span>batch 4  depth-3 subheap mask
</span></span><span style="display:flex;"><span>batch 5  detail dropout
</span></span><span style="display:flex;"><span>batch 6  subtree replacement
</span></span></code></pre></div><p>每个 batch 只计算受损区域的交叉熵：</p>
$$ L_d = -\sum_{i\in M_d} \log P(x_i\mid H_{\setminus M_d}) $$<p>其中 $M_d$ 表示尺度为 $d$ 的被遮挡子堆。</p>
<p>这样可以分别观察：</p>
<ul>
<li>哪一种扰动开始需要 root；</li>
<li>哪一层信息最容易恢复；</li>
<li>梯度能否通过递归卷积到达高层；</li>
<li>不同 kernel 是否在不同尺度形成分工。</li>
</ul>
<p>我们不必一开始就知道 root 最终会表示“主谓宾”“主题”还是其他人类标签。只需要观察：随着问题尺度扩大，高层状态是否越来越有用。</p>
<hr>
<h2 id="8-我们期待看到什么趋势">8. 我们期待看到什么趋势</h2>
<p>这篇文章暂时没有新实验结果，因此下面是 Predict，不是结论。</p>
<p>最关键的测量不是普通 echo 能否达到 100%，而是：</p>
$$ \Delta L_{\mathrm{root}}(d) = L_d(H_{\mathrm{root}}=0)-L_d(H_{\mathrm{root}}) $$<p>其中 $d$ 是被遮挡子堆的尺度。</p>
<p>我们期待：</p>
$$ \Delta L_{\mathrm{root}}(d+1) > \Delta L_{\mathrm{root}}(d) $$<p>用普通话说：</p>
<blockquote>
<p>遮挡范围越大，模型越应该依赖 root 和祖先卷积结果。</p></blockquote>
<p>具体趋势包括：</p>
<ol>
<li>leaf mask 主要依赖局部 detail；</li>
<li>小 subheap mask 开始依赖 parent 和 sibling；</li>
<li>大 subheap mask 对 root-zero 更敏感；</li>
<li>打乱 ancestor 地址会破坏深层恢复；</li>
<li>detail-only 对照在深层 Mask 上明显落后；</li>
<li>TreeHeap 在未训练深度仍能复用共享递归 kernel；</li>
<li>shuffled corpus 会削弱推断式 Mask，因为真实共现规律被破坏。</li>
</ol>
<p>如果这些趋势没有出现，我们就应承认：当前 fold kernel 没有把数据规律逐层抽取到高层，或者当前树的组织方式不适合语料。</p>
<hr>
<ul>
<li></li>
</ul>
<h2 id="9-实验结果root-被点亮了吗">9. 实验结果：root 被点亮了吗</h2>
<p>实验已经在 io 的 RTX 3090 上完成。</p>
<p>两个模型都从相同随机初始化出发，使用相同的 100,000 个真实中文 token block、相同参数量和相同优化器：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>训练问题</th>
          <th style="text-align: right">训练时间</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Echo</td>
          <td>所有 detail 完整，恢复全部 token</td>
          <td style="text-align: right">46.5 秒</td>
      </tr>
      <tr>
          <td>Multiscale Mask</td>
          <td>移除随机子堆内部 detail，只恢复受损区域</td>
          <td style="text-align: right">51.0 秒</td>
      </tr>
  </tbody>
</table>
<p>两个模型都训练 3,125 step。Mask 模型的 WRITE、FOLD、DETAIL、UNFOLD、READ 五类算子都获得了有限非零梯度，因此 loss 确实通过了完整递归链路。</p>
<h3 id="91-普通-echo-的-995-是局部复制能力">9.1 普通 Echo 的 99.5% 是局部复制能力</h3>
<p>在 detail 完整时，普通 Echo 的 token Top-1 为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>99.50%
</span></span></code></pre></div><p>但移除一个子堆内部的 detail 后，它迅速失效：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">被移除的 token 数</th>
          <th style="text-align: right">Echo 恢复 Top-1</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">24.61%</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">3.32%</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">1.46%</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">0.78%</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">0.81%</td>
      </tr>
  </tbody>
</table>
<p>这组数字支持本文最初的诊断：普通 echo 的问题太浅，模型主要学会了局部路径：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token -&gt; local detail -&gt; token
</span></span></code></pre></div><p>它能精确抄写，却没有为 detail 缺失准备上层摘要。</p>
<h3 id="92-多尺度-mask-改变了信息保存位置">9.2 多尺度 Mask 改变了信息保存位置</h3>
<p>Mask 模型的受损区域恢复结果是：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">被移除的 token 数</th>
          <th style="text-align: right">Mask NLL，越低越好</th>
          <th style="text-align: right">Mask Top-1</th>
          <th style="text-align: right">Echo Top-1</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">6.526</td>
          <td style="text-align: right">14.26%</td>
          <td style="text-align: right">24.61%</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">7.277</td>
          <td style="text-align: right">8.69%</td>
          <td style="text-align: right">3.32%</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">7.567</td>
          <td style="text-align: right">7.50%</td>
          <td style="text-align: right">1.46%</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">7.843</td>
          <td style="text-align: right">6.42%</td>
          <td style="text-align: right">0.78%</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">7.915</td>
          <td style="text-align: right">6.36%</td>
          <td style="text-align: right">0.81%</td>
      </tr>
  </tbody>
</table>
<p>只遮两个 token 时，Echo 的局部复制能力仍然更强。</p>
<p>从 4 token 开始，Mask 模型明显更稳。遮掉 32 token 时，它的 Top-1 约为 Echo 的八倍。这说明训练问题确实改变了模型的信息布局：部分可恢复信息已经离开被删除的局部 detail，进入了更高层的 TreeHeap 状态。</p>
<p>但 6.36% 仍然很低。这里的正确表述是“出现了上层信息信号”，而不是“已经能恢复半句话”。</p>
<h3 id="93-root-不是空开关">9.3 root 不是空开关</h3>
<p>为了判断上层信号是否真的进入 root，我们做了两种干预。</p>
<p>第一种是把当前样本的 root 清零；第二种是换成另一个样本的 root。</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Mask 大小</th>
          <th style="text-align: right">正常 NLL</th>
          <th style="text-align: right">Root 清零 NLL</th>
          <th style="text-align: right">换错 Root NLL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">6.526</td>
          <td style="text-align: right">7.369</td>
          <td style="text-align: right">6.861</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">7.277</td>
          <td style="text-align: right">7.775</td>
          <td style="text-align: right">7.623</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">7.567</td>
          <td style="text-align: right">7.898</td>
          <td style="text-align: right">7.920</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">7.843</td>
          <td style="text-align: right">8.131</td>
          <td style="text-align: right">8.194</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">7.915</td>
          <td style="text-align: right">8.188</td>
          <td style="text-align: right">8.276</td>
      </tr>
  </tbody>
</table>
<p>在 32-token Mask 下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Root 清零：NLL 增加 0.273
</span></span><span style="display:flex;"><span>换错 Root：NLL 增加 0.361
</span></span></code></pre></div><p>错误 root 比零 root 更有破坏性。这说明 root 不是一个固定的开关，它携带了当前文本相关的信息。</p>
<p>这是本轮最重要的正结果：</p>
<blockquote>
<p>多尺度 Mask 第一次让 root 获得了可干预、样本相关的因果信号。</p></blockquote>
<h3 id="94-最重要的-predict-反向了">9.4 最重要的 Predict 反向了</h3>
<p>我们原本预测：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Mask 越大
</span></span><span style="display:flex;"><span>  -&gt; 局部信息越少
</span></span><span style="display:flex;"><span>  -&gt; 模型越依赖 root
</span></span></code></pre></div><p>实际 root 清零造成的 NLL 增量为：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Mask 大小</th>
          <th style="text-align: right">Root 贡献</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">0.843</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">0.499</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">0.330</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">0.287</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">0.273</td>
      </tr>
  </tbody>
</table>
<p>它严格递减，深度趋势的 Spearman 相关系数为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>-1.0
</span></span></code></pre></div><p>所以 P3 没有“差一点通过”，而是方向完全相反。</p>
<p>这说明当前 root 更像粗粒度的全局条件：它能帮助补一个小洞，却不足以展开一整棵缺失子树。Mask 越大，decoder 越容易退化为输出少数高频 token。</p>
<p>在保存的样例中，32-token Mask 经常产生：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>10257 10257 10257 10257 ...
</span></span></code></pre></div><p>因此不能把 root 的因果信号解释成完整句法、语义或世界模型。</p>
<h3 id="95-为什么-56-gate-通过仍然不能写成成功">9.5 为什么 5/6 Gate 通过仍然不能写成成功</h3>
<p>预注册结果如下：</p>
<table>
  <thead>
      <tr>
          <th>Gate</th>
          <th>结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>P1 深层 Mask 优于未训练 Mask 的 Echo</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P2 span-32 的 root-zero 有明显伤害</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P3 root 贡献随 Mask 深度上升</td>
          <td><strong>失败，Spearman = -1.0</strong></td>
      </tr>
      <tr>
          <td>P4 Mask 训练比 Echo 更依赖 root</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P5 换错 root 有明显伤害</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>P6 所有递归算子都有梯度</td>
          <td>通过</td>
      </tr>
  </tbody>
</table>
<p>P1 也必须谨慎解释。Echo 从未训练过 detail 缺失，因此它是机制对照，不是足够强的 Mask baseline。Mask 模型击败它，证明训练问题发生了作用；还不能证明 TreeHeap 优于 unigram、BoW、flat root 或 Transformer。</p>
<p>同时，Mask 模型在 detail 完整时的普通 echo Top-1 只有 14.72%，远低于 Echo 模型的 99.50%。它用精确复制能力换取了受损情况下的稳定性，尚未同时掌握两种能力。</p>
<hr>
<h2 id="10-claim-判决部分支持">10. Claim 判决：部分支持</h2>
<p>本轮 Claim 更新为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>partial support / upward signal found / positive-depth trend rejected
</span></span></code></pre></div><p>实验支持：</p>
<ol>
<li>普通 echo 会优先形成局部 detail 捷径；</li>
<li>多尺度 Mask 能改变信息的保存位置；</li>
<li>root 获得了可测量的样本相关信息；</li>
<li>root 清零和换错都会伤害恢复；</li>
<li>masked loss 能到达全部共享递归算子。</li>
</ol>
<p>实验不支持：</p>
<ol>
<li>Mask 越深，信息越向 root 汇聚；</li>
<li>root 已能表示并展开完整子树；</li>
<li>当前恢复质量已经足够用于生成产品；</li>
<li>root 已形成语义、世界知识或意识；</li>
<li>TreeHeap 已优于通用神经网络基线。</li>
</ol>
<p>最准确的一句话是：</p>
<blockquote>
<p>我们让一部分信息离开了局部 detail，并点亮了 root；但当前 root 更像粗略的全局摘要，还不是能够展开整棵子树的高层编码。</p></blockquote>
<hr>
<h2 id="11-下一步同时保住局部精度和上层摘要">11. 下一步：同时保住局部精度和上层摘要</h2>
<p>下一轮不应立刻扩大语料，而应修正训练问题。</p>
<p>训练 batch 轮流进行：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>batch 1  普通 Echo
</span></span><span style="display:flex;"><span>batch 2  浅层 subheap Mask
</span></span><span style="display:flex;"><span>batch 3  中层 subheap Mask
</span></span><span style="display:flex;"><span>batch 4  深层 subheap Mask
</span></span></code></pre></div><p>这不是把多个 loss 全部相加，而是每个 batch 只回答一个清晰问题。目标是同时获得：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>detail 完整 -&gt; 精确恢复
</span></span><span style="display:flex;"><span>detail 缺失 -&gt; root 和 ancestor 提供概率恢复
</span></span></code></pre></div><p>还必须加入更强对照：</p>
<ul>
<li>unigram 概率；</li>
<li>当前 block 的词频或 BoW；</li>
<li>flat mean/root bottleneck；</li>
<li>position-aware flat bottleneck；</li>
<li>shuffled-root 和 shuffled-corpus。</li>
</ul>
<p>只有 TreeHeap 在相同状态预算下，既保住 echo，又在深层 subheap Mask 上击败这些对照，才有资格升级为结构优势 Claim。</p>
<h2 id="12-为什么这条路仍然值得开心一点">12. 为什么这条路仍然值得开心一点</h2>
<p>前一阶段已经出现了一个积极信号：只使用 token echo loss，随机初始化的 WRITE、FOLD、DETAIL、UNFOLD 和 READ 可以共同形成一套模型自己读得懂的连续编码协议。</p>
<p>它还很浅，甚至可能只是高效的局部抄写。</p>
<p>但“模型能够形成自己的写法”与“模型已经形成世界模型”是两件不同的事。前者是后者可能需要的一块地基，不是终点。</p>
<p>现在我们得到的不是一个漂亮但空泛的答案，而是一个更好的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不要再问：
</span></span><span style="display:flex;"><span>模型能不能抄回刚刚看到的 token？
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>开始问：
</span></span><span style="display:flex;"><span>当一个完整子结构消失时，
</span></span><span style="display:flex;"><span>哪一层还保留了足够的信息来推断它？
</span></span></code></pre></div><p>如果信息真的能随着问题深度逐层向 root 生长，那么 TreeHeap 的 encoder/decoder 协议就不再只是一个按地址保存 token 的数组。</p>
<p>它会开始成为一种分尺度观察世界、压缩规律并递归展开答案的结构。</p>
<p>这次我们已经有了结果。它没有完全支持最初的深度趋势，却证明 root 可以被任务真正点亮，也准确指出了下一步需要解决的能力缺口。</p>
<p>船头不仅对准了一个可以测量的方向，还第一次收到了来自 root 的微弱回声。心情确实可以好一点。哈哈哈哈。</p>
<hr>
<h2 id="13-当前声明边界">13. 当前声明边界</h2>
<p>本文记录的是 Houming818 提出的研究方向、已完成实验及其证据边界。最初假设是：</p>
<blockquote>
<p>当前普通 echo loss 太浅，无法要求高层节点保存信息。通过 TreeHeap-native 的多尺度 subheap Mask、detail dropout 和结构扰动，可以逐层增加任务所需的上下文范围；如果假设成立，信息和梯度将从局部 detail 向 parent、ancestor 与 root 汇聚。</p></blockquote>
<p>实验已经支持“root 获得样本相关信息”，但拒绝了“Mask 越深，root 贡献越大”：实测深度 Spearman 为 -1.0。因此上述假设只能保留前半部分，后半部分必须重新设计并再次验证。</p>
<p>目前不能声称：</p>
<ul>
<li>root 已经形成语义摘要；</li>
<li>多尺度 Mask 一定能够产生世界模型；</li>
<li>TreeHeap 已经优于 Transformer、MLP 或其他结构；</li>
<li>masked token 的恢复等于理解或意识；</li>
<li>人类语法标签一定会自然出现在内部节点。</li>
</ul>
<p>这些都需要后续 ARA、代码、干预实验和真实数据给出 evidence。</p>
<hr>
<h2 id="版权原创与许可证">版权、原创与许可证</h2>
<p>Copyright (C) 2026 Houming818 and SameTime contributors.</p>
<p>本文的核心研究判断，即“普通 echo 的问题尺度太浅，应使用 TreeHeap-native 的多尺度子堆扰动推动信息向 root 抽取”，由 Houming818 提出；Codex Review 参与数学整理、实验指标设计和文章编写。本文是 SameTime 项目的原创研究表达，不宣称发明 masked language modeling、denoising autoencoder、树卷积或多尺度分析等已有公共方法。</p>
<blockquote>
<p><strong>SPDX-License-Identifier: GPL-3.0-only</strong><br>
<strong>License: GNU General Public License v3.0 only</strong></p></blockquote>
<p>本文允许复制、修改和分发，但衍生版本必须继续遵守 GNU GPL v3，并保留版权、许可证、修改说明及来源声明。完整许可证文本见本站 <a href="/LICENSE">/LICENSE</a>。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-056] 看见树内的变化：TreeHeap 单层观察与跨语言差分</title>
      <link>https://www.grepcode.cn/spr/056-treeheap-layer-differential-observation.html</link>
      <pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/056-treeheap-layer-differential-observation.html</guid>
      <description>我们打开一个真实 TreeHeap 层，展示节点覆盖文本、64D 私有状态、读出结果和最近邻反例，并提出通过路径差分、子堆替换与跨语言对齐观察私有编码的新方法。</description>
      <content:encoded><![CDATA[<h1 id="看见树内的变化treeheap-单层观察与跨语言差分">看见树内的变化：TreeHeap 单层观察与跨语言差分</h1>
<p>TreeHeap 的 encoder 和 decoder 可以形成一套私有编码协议。</p>
<p>这很像一个人自己的笔迹：别人不一定能从某一笔的角度判断它代表什么，但书写者自己可以稳定地写，也可以稳定地读。</p>
<p>可是，私有编码不能成为拒绝观察的理由。</p>
<p>即使我们不知道 64D state 的第 17 维是什么意思，仍然可以问：</p>
<blockquote>
<p>把“米饭”换成“土豆”以后，树的哪些节点发生了变化？变化沿哪条路径传播？把变化后的子堆移植过去，decoder 是否只改变对应概念？</p></blockquote>
<p>这篇文章先公开一次真实的单层观察，再提出一种新的 TreeHeap 特征设计：<strong>差分传播路径</strong>。</p>
<hr>
<h2 id="1-我们刚刚训练了什么">1. 我们刚刚训练了什么</h2>
<p>实验使用真实中文语料，而不是人工随机树：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th style="text-align: right">设置</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>训练数据</td>
          <td style="text-align: right">200,000 个真实中文 block</td>
      </tr>
      <tr>
          <td>每个 block</td>
          <td style="text-align: right">64 token</td>
      </tr>
      <tr>
          <td>TreeHeap 深度</td>
          <td style="text-align: right">6</td>
      </tr>
      <tr>
          <td>节点 state</td>
          <td style="text-align: right">64D</td>
      </tr>
      <tr>
          <td>验证数据</td>
          <td style="text-align: right">512 个未参与训练的 block</td>
      </tr>
      <tr>
          <td>设备</td>
          <td style="text-align: right">io / RTX 3090</td>
      </tr>
  </tbody>
</table>
<p>树的各层覆盖范围如下：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">深度</th>
          <th style="text-align: right">单节点覆盖 token</th>
          <th style="text-align: right">同一 64-token block 的节点数</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td style="text-align: right">2</td>
          <td style="text-align: right">32</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">4</td>
          <td style="text-align: right">16</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">8</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">16</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">32</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right">64</td>
          <td style="text-align: right">1</td>
      </tr>
  </tbody>
</table>
<p>共享 FOLD kernel 从左右子节点递归计算父节点：</p>
$$ z_i^{(d+1)}=K_\theta\left(z_{2i}^{(d)},z_{2i+1}^{(d)},e_d\right). $$<p>其中，$e_d$ 是深度坐标。所有地址使用同一个 $K_\theta$，不是每个位置单独记一张参数表。</p>
<p>这次没有要求 root 完整恢复 64 个 token，而是观察两个尺度量：</p>
<ol>
<li><strong>Bag 轮廓</strong>：这个节点覆盖的区域里有什么 token，不要求顺序。</li>
<li><strong>Adjacency 轮廓</strong>：这个区域内有哪些有向相邻 token 对，要求顺序。</li>
</ol>
<p>Bag 类似远看一张图时看到的主体颜色；Adjacency 更像物体边缘的方向和连接关系。</p>
<hr>
<h2 id="2-一个节点里到底能看到什么">2. 一个节点里到底能看到什么</h2>
<p>当前实验中，一个节点有三类可观察数据。</p>
<h3 id="21-地址与感受野">2.1 地址与感受野</h3>
<p>地址告诉我们该节点覆盖哪一段输入。</p>
<p>例如 depth=4 的 node 2 覆盖 token <code>[32,48)</code>。这是 TreeHeap 数据结构天然提供的坐标，不需要 probe 猜测。</p>
<h3 id="22-私有-64d-state">2.2 私有 64D state</h3>
<p>例如某个节点的前 8 维是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[0.5808, -0.1203, -0.7574, -0.9964,
</span></span><span style="display:flex;"><span> -1.1835, 0.4895, -1.8861, 1.2427]
</span></span></code></pre></div><p>这些数字本身没有人类词典。不能说 <code>0.5808</code> 就是“花”，或者 <code>-0.9964</code> 就是“时间”。</p>
<p>它们只在当前 encoder 与 decoder 共同形成的坐标系中有意义。</p>
<h3 id="23-读出与干预">2.3 读出与干预</h3>
<p>我们可以训练 READ kernel，从 state 读取 Bag 或 Adjacency；还可以替换 state，观察 decoder 输出是否改变。</p>
<p>前者是相关性观察，后者才是因果观察。</p>
<hr>
<h2 id="3-把-depth4-的四个节点全部摊开">3. 把 depth=4 的四个节点全部摊开</h2>
<p>下面是一条真实验证文本：</p>
<blockquote>
<p>蔓交错，到四月花期，就是一扇开满花的拱门。清唱咖啡，有一面墙的书架，尚有空余，总有客人愿意将看过的，或者喜欢的书放在书架上给大家分享。这里有个赠书的江湖。鼎韵艺术沙龙。</p></blockquote>
<p>在 depth=4，每个节点覆盖 16 token，一共有四个节点：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">节点</th>
          <th>实际覆盖文本</th>
          <th style="text-align: right">Bag 读出 cosine</th>
          <th style="text-align: right">Adjacency 读出 cosine</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td>蔓交错，到四月花期，就是一扇开满花的拱……</td>
          <td style="text-align: right">0.379</td>
          <td style="text-align: right">0.129</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>门。清唱咖啡，有一面墙的书架，尚有空……</td>
          <td style="text-align: right">0.597</td>
          <td style="text-align: right">-0.087</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>余，总有客人愿意将看过的，或者喜欢的书放在书架……</td>
          <td style="text-align: right">0.216</td>
          <td style="text-align: right">-0.044</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td>上给大家分享。这里有个赠书的江湖。鼎韵艺术沙龙</td>
          <td style="text-align: right">0.644</td>
          <td style="text-align: right">-0.142</td>
      </tr>
  </tbody>
</table>
<p>cosine 越接近 1，表示 READ 输出越接近该片段的精确观察目标。</p>
<p>这张表说明：</p>
<ul>
<li>四个节点都不是空白常量；</li>
<li>Bag 内容轮廓有不同程度的可读性；</li>
<li>有向排列信息基本没有形成；</li>
<li>同一层不同节点的质量差异很大。</li>
</ul>
<p>四个 state 相互之间的 cosine 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>          node0   node1   node2   node3
</span></span><span style="display:flex;"><span>node0     1.000   0.451   0.860  -0.079
</span></span><span style="display:flex;"><span>node1     0.451   1.000   0.326   0.517
</span></span><span style="display:flex;"><span>node2     0.860   0.326   1.000  -0.087
</span></span><span style="display:flex;"><span>node3    -0.079   0.517  -0.087   1.000
</span></span></code></pre></div><p>这说明该层没有完全坍缩成一个 state。node0 与 node3 接近正交，而 node0 与 node2 非常接近。</p>
<p>但“向量不同”不等于“已经理解语义”。</p>
<hr>
<h2 id="4-一个必须公开的反例">4. 一个必须公开的反例</h2>
<p>我们拿 depth=4 的 node0，在另外 511 个验证 block 中寻找 state 最近邻。</p>
<p>查询片段是：</p>
<blockquote>
<p>蔓交错，到四月花期，就是一扇开满花的拱……</p></blockquote>
<p>返回片段是：</p>
<blockquote>
<p>发的日子，要预防季节性的传染病的发生，应多吃清淡食物。</p></blockquote>
<p>结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>state cosine</td>
          <td style="text-align: right">0.9848</td>
      </tr>
      <tr>
          <td>两段文本的精确 Bag cosine</td>
          <td style="text-align: right">0.2242</td>
      </tr>
      <tr>
          <td>两段文本的精确 Adjacency cosine</td>
          <td style="text-align: right">-0.1449</td>
      </tr>
  </tbody>
</table>
<p>两个 state 看起来几乎相同，但对应文本既不是明显同义，也没有接近的顺序结构。</p>
<p>这意味着当前 state 空间可能存在方向聚集或局部坍缩。它携带了一些可读信息，却还不是可靠的语义检索坐标系。</p>
<p>因此不能只展示 <code>state cosine=0.9848</code>，然后宣布模型理解了两句话。必须用外部观察量和因果替换继续核验。</p>
<hr>
<h2 id="5-从低层看到高层">5. 从低层看到高层</h2>
<p>全部验证集的平均结果是：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">覆盖 token</th>
          <th style="text-align: right">2</th>
          <th style="text-align: right">4</th>
          <th style="text-align: right">8</th>
          <th style="text-align: right">16</th>
          <th style="text-align: right">32</th>
          <th style="text-align: right">64</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">Bag READ cosine</td>
          <td style="text-align: right">0.267</td>
          <td style="text-align: right">0.286</td>
          <td style="text-align: right">0.306</td>
          <td style="text-align: right">0.334</td>
          <td style="text-align: right">0.377</td>
          <td style="text-align: right">0.436</td>
      </tr>
      <tr>
          <td style="text-align: right">Bag Query 增益</td>
          <td style="text-align: right">0.184</td>
          <td style="text-align: right">0.122</td>
          <td style="text-align: right">0.095</td>
          <td style="text-align: right">0.086</td>
          <td style="text-align: right">0.071</td>
          <td style="text-align: right">0.077</td>
      </tr>
      <tr>
          <td style="text-align: right">Adjacency READ cosine</td>
          <td style="text-align: right">0.010</td>
          <td style="text-align: right">0.012</td>
          <td style="text-align: right">0.015</td>
          <td style="text-align: right">0.017</td>
          <td style="text-align: right">0.021</td>
          <td style="text-align: right">0.027</td>
      </tr>
  </tbody>
</table>
<p>这里出现了一个值得保留的现象：</p>
<blockquote>
<p>覆盖范围越大，Bag 轮廓越容易从节点中读出；但精细检索优势没有随深度一起增加。</p></blockquote>
<p>这与 Houming818 提出的多尺度理解相容：高层可能不是低层 token 的模糊错误副本，而是在表达覆盖范围更大的几何轮廓。</p>
<p>但是本次实验只支持很窄的说法：<strong>高层保存了一部分无序内容统计。</strong></p>
<p>它还没有证明：</p>
<ul>
<li>高层形成了人类语义；</li>
<li>TreeHeap 已经拥有世界模型；</li>
<li>有向结构已经被编码；</li>
<li>TreeHeap 检索优于 Transformer。</li>
</ul>
<p>完整 Claim 的 6 个 Gate 只通过了 3 个，因此 ARA 状态仍是 <code>not supported</code>。</p>
<hr>
<h2 id="6-私有编码如何被观察">6. 私有编码如何被观察</h2>
<p>绝对坐标不可读，不代表相对变化不可研究。</p>
<p>考虑最小句对：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A：小明爱吃米饭。
</span></span><span style="display:flex;"><span>B：小明爱吃土豆。
</span></span></code></pre></div><p>两句话只改变一个概念。对每个深度、每个地址计算：</p>
$$ \Delta_i^{(d)}=H_i^{(d)}(B)-H_i^{(d)}(A). $$<p>如果 TreeHeap encoder 真正利用树结构，那么差分不应该平均污染整棵树。我们预测它主要分布在：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>米饭/土豆叶节点
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>宾语 subheap
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>“吃 + 宾语”父节点
</span></span><span style="display:flex;"><span>        ↓
</span></span><span style="display:flex;"><span>root 的较粗变化
</span></span></code></pre></div><p>与“小明”对应的兄弟 subheap 应当基本稳定。</p>
<p>这就是新的可观察特征：<strong>差分传播路径</strong>。</p>
<hr>
<h2 id="7-差分路径的四个测量">7. 差分路径的四个测量</h2>
<h3 id="71-地址局部性">7.1 地址局部性</h3>
<p>设被替换 token 的祖先路径为 $P$，全树节点集合为 $V$。差分能量集中率定义为：</p>
$$ R_{path}=\frac{\sum_{i\in P}\left\|\Delta_i\right\|_2^2} {\sum_{j\in V}\left\|\Delta_j\right\|_2^2}. $$<p>如果 $R_{path}$ 很高，说明变化确实沿结构路径传播，而不是无地址地扩散。</p>
<h3 id="72-深度轮廓">7.2 深度轮廓</h3>
<p>不同深度不必保存相同含义。我们记录每层的相对差分：</p>
$$ D_d=\frac{1}{|V_d|}\sum_{i\in V_d}\left\|\Delta_i^{(d)}\right\|_2. $$<p>低层可能表现为具体 token 替换；高层可能只表现为“食物类别内部发生变化”。这里不要求高层重新说出“土豆”二字。</p>
<h3 id="73-跨句式迁移">7.3 跨句式迁移</h3>
<p>再构造：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>小红爱吃米饭。 -&gt; 小红爱吃土豆。
</span></span><span style="display:flex;"><span>他今天吃了米饭。 -&gt; 他今天吃了土豆。
</span></span></code></pre></div><p>如果“米饭到土豆”的差分只在第一句话成立，它可能只是样本记忆。</p>
<p>如果多个句式中的差分方向显著一致，才说明 encoder 抽取了可迁移关系：</p>
$$ cos(\Delta_{小明},\Delta_{小红}) > cos(\Delta_{小明},\Delta_{随机替换}). $$<h3 id="74-子堆因果替换">7.4 子堆因果替换</h3>
<p>相关性仍然可能欺骗我们。因此需要把 B 的宾语 subheap 写入 A：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H(A)
</span></span><span style="display:flex;"><span>  - remove: “米饭” subheap
</span></span><span style="display:flex;"><span>  + insert: “土豆” subheap
</span></span><span style="display:flex;"><span>  -&gt; decoder
</span></span></code></pre></div><p>如果 decoder 的输出从“小明爱吃米饭”变为“小明爱吃土豆”，而主语和谓语保持不变，才说明这个 subheap 对目标概念具有因果作用。</p>
<p>这一步比训练一个 probe 更强，因为 probe 可能只是从相关噪声中猜答案。</p>
<hr>
<h2 id="8-多语言差分观察">8. 多语言差分观察</h2>
<p>加入英文最小句对：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C：Xiaoming likes eating rice.
</span></span><span style="display:flex;"><span>D：Xiaoming likes eating potatoes.
</span></span></code></pre></div><p>中文与英文可以拥有不同的私有编码坐标。我们不要求两棵树的原始 state 完全相等，而是学习一个受控对齐映射 $M$：</p>
$$ M\Delta_{zh}\approx\Delta_{en}. $$<p>其中：</p>
$$ \Delta_{zh}=H(小明爱吃土豆)-H(小明爱吃米饭), $$$$ \Delta_{en}=H(Xiaoming\ likes\ potatoes)-H(Xiaoming\ likes\ rice). $$<p>如果对齐后的真实概念差分明显优于随机替换差分，就说明两套私有编码都捕获了同一种世界变化。</p>
<p>这里有一个严格边界：任意非线性私有坐标中的裸减法未必天然稳定。因此跨语言结论必须同时接受 subheap 替换和 decoder 输出的因果验证，不能只看 cosine。</p>
<hr>
<h2 id="9-这会比-transformer-更容易观察吗">9. 这会比 Transformer 更容易观察吗</h2>
<p>这是一个 Predict，不是已有结论。</p>
<p>Transformer 也可以做 activation patching、attention 分析、linear probe 和 hidden-state diff。我们不能把 Transformer 描述成完全不可观察。</p>
<p>TreeHeap 的潜在优势来自显式结构坐标：</p>
<table>
  <thead>
      <tr>
          <th>观察问题</th>
          <th>Transformer</th>
          <th>TreeHeap 的预期坐标</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>变化发生在哪里</td>
          <td>token、层、head 的分布式激活</td>
          <td>明确 heap 地址</td>
      </tr>
      <tr>
          <td>变化如何传播</td>
          <td>跨层和 attention 边</td>
          <td>叶到 root 的祖先路径</td>
      </tr>
      <tr>
          <td>观察尺度</td>
          <td>依赖层和 receptive pattern</td>
          <td>TreeHeap 深度</td>
      </tr>
      <tr>
          <td>局部因果替换</td>
          <td>activation patching</td>
          <td>完整 subheap swap</td>
      </tr>
      <tr>
          <td>多语言关系</td>
          <td>hidden alignment</td>
          <td>同地址、同尺度差分对齐</td>
      </tr>
  </tbody>
</table>
<p>只有当 TreeHeap 的差分确实更局部、迁移更稳定、因果替换更干净时，才能说它在这类问题上比匹配规模的 Transformer 更容易观察。</p>
<p>树的外形本身不是证据。</p>
<hr>
<h2 id="10-下一条-claim-与-predict">10. 下一条 Claim 与 Predict</h2>
<h3 id="claim">Claim</h3>
<blockquote>
<p>对只替换一个概念的最小句对，TreeHeap state 差分应集中在被替换叶节点及其祖先路径；对应 subheap 的因果替换应主要改变 decoder 的目标概念。该差分规律应能跨主语、跨句式，并在对齐后跨语言迁移。</p></blockquote>
<h3 id="初步-predict">初步 Predict</h3>
<ol>
<li>被替换路径承载至少 70% 的全树差分能量。</li>
<li>未改变兄弟 subheap 的平均差分显著小于祖先路径。</li>
<li>相同概念替换的跨句式差分 cosine 比随机替换至少高 0.10。</li>
<li>subheap swap 后，目标词变化率显著提高，非目标 token 保持率不下降超过 5%。</li>
<li>中英对齐后的概念差分优于随机语言配对至少 0.10。</li>
<li>与匹配维度 Transformer 做同样干预；如果 TreeHeap 没有更好的局部性或因果选择性，则不支持“更容易观察”的优势主张。</li>
</ol>
<p>这些阈值需要在 ARA 实验注册时冻结，然后再运行代码，不能看到结果后移动门槛。</p>
<hr>
<h2 id="11-当前结论">11. 当前结论</h2>
<p>这次打开单层以后，我们看到的不是一个已经完成的语义世界模型，而是一个更具体的中间状态：</p>
<ol>
<li>每个节点有明确地址、覆盖范围和非恒定 64D state；</li>
<li>高层可以读出部分更大范围的 Bag 内容轮廓；</li>
<li>当前有向顺序信息没有形成；</li>
<li>极高 state cosine 仍可能返回不相关文本，说明几何空间尚未校准；</li>
<li>下一步不能继续只看平均 loss，需要观察改变一个概念时，差分沿树如何传播；</li>
<li>subheap swap 将把“看起来相关”升级为“对输出具有因果作用”。</li>
</ol>
<p>我们真正想建立的不是一个人为解释每个参数的词典，而是一种可重复的观察方法：</p>
<blockquote>
<p>不要求读懂模型的每一笔，但要能追踪它改了哪一笔、变化沿哪里传播，以及这一笔是否真的改变了模型的回答。</p></blockquote>
<hr>
<h2 id="12-证据与原创边界">12. 证据与原创边界</h2>
<p>本次实验的 ARA、代码、checkpoint、逐层观察数据与失败 Gate 均保存在开放仓库 <a href="https://github.com/houming818/sametime">SameTime</a> 中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/logic/treeheap_multiscale_geometry.md
</span></span><span style="display:flex;"><span>ara/s3-generation/src/s3_treeheap_multiscale_geometry.py
</span></span><span style="display:flex;"><span>ara/s3-generation/src/s3_treeheap_multiscale_geometry_observe.py
</span></span><span style="display:flex;"><span>ara/s3-generation/evidence/s3_treeheap_multiscale_geometry_smoke/
</span></span></code></pre></div><p>“高层可能表达更大几何范围而非损坏 token 副本”以及“用最小句对观察 TreeHeap 差分传播路径”的研究判断由 Houming818 提出；Codex Review 负责形式化、实验实现、证据审计和本文整理。</p>
<p>本文是 SameTime 项目的原创研究表达，但不宣称发明表示差分、因果干预、activation patching、多语言表示对齐、随机投影或多尺度分析等已有公共方法。TreeHeap 是否具有更强的结构可观察性，仍需下一组对照实验验证。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-057] 一次 100% 却失败的实验：为什么差分不能替我们找到意识</title>
      <link>https://www.grepcode.cn/spr/057-difference-consciousness-failed-lesson.html</link>
      <pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/057-difference-consciousness-failed-lesson.html</guid>
      <description>一个显式 DIFF-TRANSPORT-APPLY 模型在有限类比任务上达到 100%，但 World TreeHeap 几乎可被删除，较小的 Transformer 同样满分。本文公开这次失败，并解释为何内部差分适合做诊断，却不足以解释意识或涌现。</description>
      <content:encoded><![CDATA[<h1 id="一次-100-却失败的实验为什么差分不能替我们找到意识">一次 100% 却失败的实验：为什么差分不能替我们找到意识</h1>
<p>这是一篇失败记录。</p>
<p>更准确地说，这是一次<strong>指标成功、研究目标失败</strong>的实验。</p>
<p>模型在四类有限世界类比任务上达到了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token accuracy     = 100%
</span></span><span style="display:flex;"><span>sequence exact     = 100%
</span></span></code></pre></div><p>如果只看最终分数，这似乎是一场漂亮胜利。</p>
<p>但经过因果干预后，我们发现：模型几乎没有使用我们专门设计的 World TreeHeap。一个参数更少的普通 Transformer 也达到了 100%。</p>
<p>因此，这个实验没有证明 World TreeHeap，没有证明 TreeHeap 的类比优势，更没有触及意识。</p>
<p>它反而留下了一条重要教训：</p>
<blockquote>
<p>差分可以帮助我们观察模型发生了什么，但不能仅凭一个漂亮的差分结构，就宣布我们理解了模型的意识、语义或推理过程。</p></blockquote>
<hr>
<h2 id="1-这条路线是怎样开始的">1. 这条路线是怎样开始的</h2>
<p>我们先观察到一个合理问题。</p>
<p>考虑两句话：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>小明喜欢吃红薯。
</span></span><span style="display:flex;"><span>小明喜欢吃土豆。
</span></span></code></pre></div><p>如果 encoder 将整句话写成 TreeHeap，那么两个状态之间应该存在某种变化：</p>
$$ \Delta H=H_{土豆}-H_{红薯}. $$<p>但 Houming818 很快指出，这不应该只是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>embedding(土豆)-embedding(红薯)
</span></span></code></pre></div><p>因为同一个实体替换，在不同世界背景中的意义不同：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>小明喜欢吃红薯 → 小明喜欢吃土豆
</span></span><span style="display:flex;"><span>红薯要两元一斤   → 土豆要两元一斤
</span></span></code></pre></div><p>前者改变的是“被食用对象”，后者改变的是“被定价实体”。</p>
<p>于是我们进一步提出：</p>
<blockquote>
<p>差分可能不是一个普通向量，而是 World TreeHeap 背景中的一个结构变换。</p></blockquote>
<p>这个想法本身并不荒谬。问题出在我们随后怎样把它实现成了模型。</p>
<hr>
<h2 id="2-我们手工设计了一个看起来完整的推理系统">2. 我们手工设计了一个看起来完整的推理系统</h2>
<p>实验模型被拆成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A ─┐
</span></span><span style="display:flex;"><span>B ─┼─&gt; DIFF ─&gt; Relation TreeHeap R_AB
</span></span><span style="display:flex;"><span>W ─┘
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>R_AB ─┐
</span></span><span style="display:flex;"><span>C ────┼─&gt; TRANSPORT ─&gt; R_C
</span></span><span style="display:flex;"><span>W ────┘
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>C + R_C ─&gt; APPLY ─&gt; predicted H_D ─&gt; Decoder ─&gt; D
</span></span></code></pre></div><p>数学形式是：</p>
$$ R_{AB}=DIFF(W,H_A,H_B), $$$$ R_C=TRANSPORT(W,R_{AB},H_A,H_C), $$$$ \hat H_D=APPLY(H_C,R_C). $$<p>我们还预先给出了：</p>
<ul>
<li>固定逻辑槽位；</li>
<li>人物、食物、数字和谓词集合；</li>
<li>四种关系族；</li>
<li><code>A:B=C:D</code> 监督格式；</li>
<li>World TreeHeap 的 15 个参数节点；</li>
<li><code>stop/left/right</code> 概率路由；</li>
<li>状态对齐和文本生成 loss。</li>
</ul>
<p>从工程角度看，这套模型很完整。</p>
<p>从涌现角度看，它却有一个根本问题：</p>
<blockquote>
<p>我们把希望模型自己发现的推理步骤，提前写进了模块名字、数据格式和 loss。</p></blockquote>
<hr>
<h2 id="3-toy-世界包含什么">3. Toy 世界包含什么</h2>
<p>所有陈述使用八个固定逻辑叶槽。实验生成四类关系。</p>
<h3 id="31-跨场景实体替换">3.1 跨场景实体替换</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A  P1 EAT FOOD0
</span></span><span style="display:flex;"><span>B  P1 EAT FOOD6
</span></span><span style="display:flex;"><span>C  FOOD0 COST N5 UNIT
</span></span><span style="display:flex;"><span>D  FOOD6 COST N5 UNIT
</span></span></code></pre></div><h3 id="32-数值平移">3.2 数值平移</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A  FOOD7 COST N5 UNIT
</span></span><span style="display:flex;"><span>B  FOOD7 COST N6 UNIT
</span></span><span style="display:flex;"><span>C  P7 BUY FOOD1 N1
</span></span><span style="display:flex;"><span>D  P7 BUY FOOD1 N2
</span></span></code></pre></div><p>这里不能直接把 <code>N6</code> 复制到 D，因为 C 中需要的是 <code>N1→N2</code>。</p>
<h3 id="33-人物跨角色迁移">3.3 人物跨角色迁移</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A  P10 LIKE P2
</span></span><span style="display:flex;"><span>B  P8  LIKE P2
</span></span><span style="display:flex;"><span>C  P3  LIKE P10
</span></span><span style="display:flex;"><span>D  P3  LIKE P8
</span></span></code></pre></div><h3 id="34-主客体交换">3.4 主客体交换</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A  P3 LIKE P7
</span></span><span style="display:flex;"><span>B  P7 LIKE P3
</span></span><span style="display:flex;"><span>C  P4 LIKE P11
</span></span><span style="display:flex;"><span>D  P11 LIKE P4
</span></span></code></pre></div><p>验证集按组合哈希整块留出。模型看过所有原子符号，但没有看过测试中的具体组合。</p>
<p>因此，这不是一个简单的随机六分类实验。它确实要求模型表达一些超出固定 token 替换的关系。</p>
<hr>
<h2 id="4-一个漂亮得危险的结果">4. 一个漂亮得危险的结果</h2>
<p>训练设置：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>训练 step</td>
          <td style="text-align: right">6,000</td>
      </tr>
      <tr>
          <td>batch</td>
          <td style="text-align: right">256</td>
      </tr>
      <tr>
          <td>验证四元组</td>
          <td style="text-align: right">4,096</td>
      </tr>
      <tr>
          <td>TreeHeap 参数</td>
          <td style="text-align: right">238,314</td>
      </tr>
      <tr>
          <td>Flat Transformer 参数</td>
          <td style="text-align: right">73,574</td>
      </tr>
      <tr>
          <td>GPU</td>
          <td style="text-align: right">RTX 3090</td>
      </tr>
  </tbody>
</table>
<p>最终结果：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">Token accuracy</th>
          <th style="text-align: right">Sequence exact</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap analogy</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>Flat Transformer</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>Lexical replacement</td>
          <td style="text-align: right">0.9124</td>
          <td style="text-align: right">0.5466</td>
      </tr>
  </tbody>
</table>
<p>TreeHeap 四类关系全部达到 sequence exact <code>1.0</code>。</p>
<p>这说明：</p>
<blockquote>
<p>TreeHeap 形态的网络可以表示并学习有限世界类比函数。</p></blockquote>
<p>但是，“能够表示”与“自然涌现”之间还有很长距离。</p>
<hr>
<h2 id="5-因果干预推翻了漂亮故事">5. 因果干预推翻了漂亮故事</h2>
<p>如果 World TreeHeap 真的是关系迁移的背景，那么删除它应显著破坏结果。</p>
<p>实际数据：</p>
<table>
  <thead>
      <tr>
          <th>干预</th>
          <th style="text-align: right">Token accuracy</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>正常 World TreeHeap</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>把 W 全部置零</td>
          <td style="text-align: right">0.9984</td>
      </tr>
      <tr>
          <td>翻转 W 的 heap 地址</td>
          <td style="text-align: right">0.9867</td>
      </tr>
      <tr>
          <td>使用错误的 B 关系</td>
          <td style="text-align: right">0.8284</td>
      </tr>
  </tbody>
</table>
<p>最终路由熵约为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.000024
</span></span></code></pre></div><p>概率路由几乎坍缩到一个固定节点。</p>
<p>也就是说，模型实际学习的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A/B/C encoder
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>普通非线性映射
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>D
</span></span></code></pre></div><p>而不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A/B
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>查询World TreeHeap
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>读取背景关系
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>迁移到C
</span></span></code></pre></div><p>梯度发现了一条更短的道路，并合理地绕开了我们精心设计的 W。</p>
<p>这不是模型“不听话”。</p>
<p>恰恰相反，模型忠实地优化了我们给出的 loss。</p>
<hr>
<h2 id="6-为什么这个设计违背了涌现规律">6. 为什么这个设计违背了涌现规律</h2>
<h3 id="61-我们提前写好了推理步骤">6.1 我们提前写好了推理步骤</h3>
<p>还没有训练，我们已经规定：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先DIFF
</span></span><span style="display:flex;"><span>再TRANSPORT
</span></span><span style="display:flex;"><span>最后APPLY
</span></span></code></pre></div><p>模型只需拟合这条监督管线，不需要自己发现类比结构。</p>
<h3 id="62-数据直接给出了类比格式">6.2 数据直接给出了类比格式</h3>
<p>训练输入就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A、B、C → D
</span></span></code></pre></div><p>这能验证函数拟合和组合外推，却不能证明模型从普通世界经验中自然形成类比能力。</p>
<h3 id="63-人工槽位替-encoder-完成了部分工作">6.3 人工槽位替 encoder 完成了部分工作</h3>
<p>我们规定了人物、食物、数字、主语位置和宾语位置。模型没有从自然语言中发现这些结构。</p>
<h3 id="64-强行指定-w-的职责没有用">6.4 强行指定 W 的职责没有用</h3>
<p>任务可以通过 A/B/C 的直接映射解决，所以梯度没有理由把知识写进一个额外 W。</p>
<h3 id="65-较小的-flat-transformer-同样满分">6.5 较小的 Flat Transformer 同样满分</h3>
<p>这说明 toy 主要考查通用函数逼近，而不是 TreeHeap 独有能力。</p>
<hr>
<h2 id="7-为什么差分不足以分析意识">7. 为什么差分不足以分析意识</h2>
<p>Houming818 对这次实验的总结是：</p>
<blockquote>
<p>果然，想要利用差分来分析意识，不太靠谱。</p></blockquote>
<p>这里需要把边界说清楚。</p>
<h3 id="71-私有坐标中的减法不是客观语义">7.1 私有坐标中的减法不是客观语义</h3>
<p>如果 encoder 和 decoder 使用自己的私有协议，那么：</p>
$$ H_B-H_A $$<p>依赖当前坐标系。对 hidden space 做一个保持功能不变的非线性重参数化，裸差分的方向就可能改变。</p>
<h3 id="72-state-变化不等于模型理解了变化">7.2 state 变化不等于模型理解了变化</h3>
<p>一个节点改变，可能是：</p>
<ul>
<li>token embedding 改了；</li>
<li>地址改了；</li>
<li>LayerNorm 的连锁响应；</li>
<li>递归 FOLD 的必然传播；</li>
<li>真正的语义关系变化。</li>
</ul>
<p>只看差分大小无法区分这些来源。</p>
<h3 id="73-祖先路径变亮可能是数学必然">7.3 祖先路径变亮可能是数学必然</h3>
<p>局部叶节点发生变化后，其祖先节点必然重新计算。看到一条从叶到 root 的红色路径，不代表模型发现了推理链。</p>
<h3 id="74-观察者可能把自己的分类投射进模型">7.4 观察者可能把自己的分类投射进模型</h3>
<p>如果我们预先规定：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这是食物差分
</span></span><span style="display:flex;"><span>这是价格差分
</span></span><span style="display:flex;"><span>这是主谓宾差分
</span></span></code></pre></div><p>再训练 probe 找到这些标签，最后可能只是证明 probe 学会了我们的分类。</p>
<h3 id="75-意识还没有可执行定义">7.5 “意识”还没有可执行定义</h3>
<p>当前 ARA 可以测量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>loss
</span></span><span style="display:flex;"><span>概率
</span></span><span style="display:flex;"><span>地址依赖
</span></span><span style="display:flex;"><span>subheap因果作用
</span></span><span style="display:flex;"><span>生成结果
</span></span><span style="display:flex;"><span>跨组合迁移
</span></span></code></pre></div><p>但它还没有一个可以被程序直接判定的“意识”指标。</p>
<p>在没有操作性定义时，用 cosine、diff 或可视化颜色宣称观察到了意识，是不可证伪的。</p>
<hr>
<h2 id="8-差分是不是完全没用了">8. 差分是不是完全没用了</h2>
<p>不是。</p>
<p>差分仍然是有价值的<strong>诊断工具</strong>：</p>
<ul>
<li>比较一次干预前后的节点变化；</li>
<li>观察变化经过哪些地址和深度；</li>
<li>检查不同算子是否留下不同响应；</li>
<li>定位坍缩、旁路和无效模块；</li>
<li>为因果消融选择观察位置。</li>
</ul>
<p>我们此前的 Differential Atlas 就发现：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>WRITE、MIRROR、子堆交换
</span></span><span style="display:flex;"><span>会形成部分不同的多尺度响应曲线
</span></span></code></pre></div><p>这可以帮助调试 TreeHeap。</p>
<p>但正确表述应是：</p>
<blockquote>
<p>差分告诉我们模型状态怎样变化；它不自动告诉我们变化意味着什么，更不能自动上升为意识解释。</p></blockquote>
<hr>
<h2 id="9-主线回到哪里">9. 主线回到哪里</h2>
<p>ARA 中目前最可靠、也最接近自然学习的节点是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S3-TREEHEAP-ROOT-COMPRESS-C01
</span></span><span style="display:flex;"><span>        +
</span></span><span style="display:flex;"><span>S3-TREEHEAP-PYRAMID-C01
</span></span></code></pre></div><p>前者在 38,251,247 个真实文本 block 上，仅通过 next-token loss 学会了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>64 token → recursive FOLD → root → next token
</span></span></code></pre></div><p>破坏左右地址后，valid NLL 增加 <code>2.6252</code>；消融不同 head，也产生明显损失。</p>
<p>没有语法标签、Bag 目标、DIFF 目标或类比四元组。这才是当前最接近涌现的证据。</p>
<p>Pyramid 又证明 root 与地址化 detail 可以形成多分辨率容器。</p>
<p>因此主线恢复为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真实语料
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>通用TreeHeap WRITE
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>共享多头kernel forest递归FOLD
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>多分辨率H
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>普通语言预测loss
</span></span></code></pre></div><p>模型参数 TreeHeap forest 本身承担世界背景，不再外挂一个被命名为“世界模型”的 W。</p>
<hr>
<h2 id="10-encoder-mask-的对称-decoder">10. Encoder Mask 的对称 Decoder</h2>
<p>Encoder 侧仍可以使用 TreeHeap-native 复杂 Mask：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>遮住局部subheap/detail
</span></span><span style="display:flex;"><span>→ 逼迫恢复任务所需信息向parent/root聚合
</span></span></code></pre></div><p>但 Mask 只是信息压力，不是语义答案。</p>
<p>Decoder 侧的对称操作是概率 UNFOLD：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>  ↓ probabilistic UNFOLD
</span></span><span style="display:flex;"><span>左右子节点概率桶
</span></span><span style="display:flex;"><span>  ↓ delayed collapse
</span></span><span style="display:flex;"><span>下一层subheap
</span></span><span style="display:flex;"><span>  ↓ recursive UNFOLD
</span></span><span style="display:flex;"><span>token概率桶
</span></span></code></pre></div><p>FOLD 是多对一，因此 UNFOLD 不能是假装精确的逆函数：</p>
$$ P(h_l,h_r\mid h_p,C) = UNFOLD(h_p,C). $$<p>它必须输出多种可能性，等待源语言、目标前缀和更大上下文进入后再坍缩。</p>
<p>这条路线只规定通用的数据流和训练压力，不规定某个 head 必须学习“食物差分”或“类比运输”。</p>
<hr>
<h2 id="11-这次失败保留了什么">11. 这次失败保留了什么</h2>
<p>我们保留三个窄结论：</p>
<ol>
<li>TreeHeap 形态的网络能够表达有限类比函数；</li>
<li>lexical-copy 无法解决全部数值和角色变换；</li>
<li>因果干预成功发现 World TreeHeap 被绕过。</li>
</ol>
<p>同时拒绝四个更强结论：</p>
<ol>
<li>没有证明 World TreeHeap 参与推理；</li>
<li>没有证明类比能力自然涌现；</li>
<li>没有证明 TreeHeap 优于 Transformer；</li>
<li>没有证明差分能够解释意识。</li>
</ol>
<p>一个 100% 的实验，如果核心模块可以被删除，就仍然是失败。</p>
<p>这正是 ARA 的价值：不是阻止我们犯错，而是让漂亮的错误无法冒充研究结论。</p>
<hr>
<h2 id="12-证据与原创边界">12. 证据与原创边界</h2>
<p>模型、ARA、checkpoint、训练 trace、可读四元组和干预结果均保存在开放仓库 <a href="https://github.com/houming818/sametime">SameTime</a>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/logic/world_treeheap_analogy_transport.md
</span></span><span style="display:flex;"><span>ara/s3-generation/src/s3_world_treeheap_analogy.py
</span></span><span style="display:flex;"><span>ara/s3-generation/evidence/s3_world_treeheap_analogy_smoke/
</span></span></code></pre></div><p>关于“同一词语变化必须放在全局背景中理解”和“差分不足以分析意识”的研究修正由 Houming818 提出；Codex Review 负责错误模型的形式化、实现、因果审计与本文复盘。</p>
<p>本文是 SameTime 项目的原创研究记录，但不宣称发明向量差分、类比任务、因果消融、World Model、概率树路由、masked modeling 或 coarse-to-fine decoding 等已有公共方法。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-058] TreeHeap 信息抽水机：先形成 H_state，再遮住 token，能否完整 Echo？</title>
      <link>https://www.grepcode.cn/spr/058-treeheap-lifting-mask-echo.html</link>
      <pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/058-treeheap-lifting-mask-echo.html</guid>
      <description>区分三种完全不同的 mask 时序，并报告 TreeHeap lifting information pump 的真实结果：所有 leaf 被遮住后，仅凭训练形成的 root 与多层 detail，token 和 16-token block 均可 100% Echo。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-信息抽水机先形成-h_state再遮住-token能否完整-echo">TreeHeap 信息抽水机：先形成 H_state，再遮住 token，能否完整 Echo？</h1>
<p>这篇文章要回答一个很具体的问题：</p>
<blockquote>
<p>一句话已经被 encoder 写进 TreeHeap，形成完整的 $H_{state}$ 以后，如果把原始 token 和 leaf 读取通道全部遮住，还能不能只凭 $H_{state}$ 把它恢复出来？</p></blockquote>
<p>答案是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>可以。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>token echo       = 100%
</span></span><span style="display:flex;"><span>16-token exact   = 100%
</span></span></code></pre></div><p>但这句话很容易被误解。</p>
<p>这里不是先把输入 token 删除，再要求模型猜出一个从未见过的答案。真正的数据流是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整 token
</span></span><span style="display:flex;"><span>    ↓ WRITE
</span></span><span style="display:flex;"><span>Lifting FOLD 逐层上传
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>H_state = root + 每一层 addressed details
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>屏蔽全部 leaf/token 读取通道
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>从 root 开始逐层 UNFOLD
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>恢复 token
</span></span></code></pre></div><p>所以，mask 的对象是<strong>已经编码完成后的表面读取通道</strong>，不是 encoder 的原始输入。</p>
<p>这是 TreeHeap encoder/decoder 是否形成闭合协议的测试。</p>
<hr>
<h2 id="1-为什么我们之前会争论-mask">1. 为什么我们之前会争论 mask</h2>
<p>“mask 一个 token”至少有三种完全不同的含义。</p>
<h3 id="11-编码前-mask让模型猜缺失信息">1.1 编码前 mask：让模型猜缺失信息</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>小明 喜欢 吃 [MASK]
</span></span><span style="display:flex;"><span>    ↓ encoder
</span></span><span style="display:flex;"><span>H_state
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>预测：米饭 / 面条 / 苹果 / 药……
</span></span></code></pre></div><p>原词在进入 encoder 以前就被删除了。</p>
<p>因此，$H_{state}$ 中没有原词的完整信息。模型只能学习条件概率：</p>
$$ P(x_{\mathrm{mask}}\mid x_{\mathrm{visible}}). $$<p>对于“小明喜欢吃 [MASK]”，“米饭”“面条”“苹果”都可能合理，所以不能要求模型一定恢复数据集原句。</p>
<p>这种任务测试语言预测、世界经验和概率补全。它不是本文完成的 Echo。</p>
<h3 id="12-编码后-mask遮住-leaf只读-h_state">1.2 编码后 mask：遮住 leaf，只读 H_state</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整句子
</span></span><span style="display:flex;"><span>    ↓ encoder
</span></span><span style="display:flex;"><span>root + details
</span></span><span style="display:flex;"><span>    ↓ 删除原始 leaf 读取
</span></span><span style="display:flex;"><span>decoder
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>恢复完整句子
</span></span></code></pre></div><p>原始 token 已经参与 WRITE 和 FOLD，但 decoder 不能直接复制它。</p>
<p>它必须从压缩后的 TreeHeap 状态逆运算回来。本文测试的正是这一种，而且不是只 mask 一个 token，而是<strong>同时禁止读取全部 16 个 leaf</strong>。</p>
<h3 id="13-h_state-内部-mask删除某层-detail">1.3 H_state 内部 mask：删除某层 detail</h3>
<p>第三种更加困难：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整句子
</span></span><span style="display:flex;"><span>    ↓ encoder
</span></span><span style="display:flex;"><span>root + details
</span></span><span style="display:flex;"><span>    ↓ 删除目标路径上的某个 detail
</span></span><span style="display:flex;"><span>不完整 H_state
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>尝试恢复 token
</span></span></code></pre></div><p>此时精确逆运算所需的信息真的缺失了。模型必须利用 root、其他尺度和语料中学到的规律，预测缺失 detail 的概率分布。</p>
<p>这是后续的“归纳补全”问题。本文只做了消融诊断，没有宣称它已经解决。</p>
<hr>
<h2 id="2-上一版-fold-为什么没有把信息抽到高层">2. 上一版 FOLD 为什么没有把信息抽到高层</h2>
<p>上一轮实验使用普通递归 FOLD：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>16 leaf
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>8 parent-1
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>4 parent-2
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>2 parent-3
</span></span><span style="display:flex;"><span>  ↓
</span></span><span style="display:flex;"><span>1 root
</span></span></code></pre></div><p>代码确实算到了 root。但是 decoder 可以为每个输出位置选择读取哪一层。训练最后找到的捷径是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>两个 token
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>一个 parent-1
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>直接恢复这两个 token
</span></span></code></pre></div><p>READ 权重分布为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>parent-1   99.9786%
</span></span><span style="display:flex;"><span>parent-2    0.0084%
</span></span><span style="display:flex;"><span>parent-3    0.0051%
</span></span><span style="display:flex;"><span>root        0.0079%
</span></span></code></pre></div><p>删除 parent-1，NLL 增加 74.4254；删除 root，变化约为零。</p>
<p>因此，旧实验只证明一个共享 FOLD 可以把两个 token 编进一个 parent。它没有证明信息继续上传。</p>
<p>问题不在于 FOLD 有没有被递归调用，而在于系统缺少类似抽水机的基本规律：</p>
<ul>
<li>哪部分信息必须向上；</li>
<li>哪部分细节留在本层；</li>
<li>decoder 是否必须从高层向下解码；</li>
<li>有没有绕开高层的旁路。</li>
</ul>
<hr>
<h2 id="3-抽水机的基本规则lifting-scheme">3. 抽水机的基本规则：Lifting Scheme</h2>
<p>我们采用 lifting scheme，也就是可逆小波中常用的“预测与更新”结构。</p>
<p>设左右子节点状态为 $L$ 和 $R$，共享 predictor 为 $P_\theta$。</p>
<p>先计算 detail：</p>
$$ D=R-P_\theta(L). $$<p>再计算向上的 parent：</p>
$$ U=L+\frac{1}{2}D. $$<p>其中：</p>
<ul>
<li>$D$ 是留在当前深度的带地址细节；</li>
<li>$U$ 是唯一允许继续上传的 parent；</li>
<li>$P_\theta$ 是所有节点、所有深度共享的卷积 kernel。</li>
</ul>
<p>当 $P_\theta(L)=L$ 时：</p>
$$ D=R-L, $$$$ U=L+\frac12(R-L)=\frac{L+R}{2}. $$<p>这时可以直观理解为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>U = 左右子树的粗粒度轮廓
</span></span><span style="display:flex;"><span>D = 左右子树之间的差异
</span></span></code></pre></div><p>换一个可学习 predictor 后，内部坐标系可以完全不同，但结构规律不变：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>两个 child
</span></span><span style="display:flex;"><span>→ 一个 upward parent
</span></span><span style="display:flex;"><span>→ 一个 local detail
</span></span></code></pre></div><hr>
<h2 id="4-为什么它可以严格逆运算">4. 为什么它可以严格逆运算</h2>
<p>decoder 从 $U,D$ 恢复 $L,R$：</p>
$$ L=U-\frac12D, $$$$ R=D+P_\theta(L). $$<p>代入 FOLD 公式：</p>
$$ U-\frac12D =L+\frac12D-\frac12D =L, $$<p>然后：</p>
$$ D+P_\theta(L) =R-P_\theta(L)+P_\theta(L) =R. $$<p>因此，只要 encoder 和 decoder 使用同一个 $P_\theta$，就有：</p>
$$ UNFOLD_\theta(FOLD_\theta(L,R))=(L,R). $$<p>这里有一个重要事实：</p>
<blockquote>
<p>$P_\theta$ 不需要线性，也不需要自己可逆。</p></blockquote>
<p>decoder 不是计算 $P_\theta^{-1}$，而是在恢复出 $L$ 以后，再调用一次同一个 $P_\theta(L)$。</p>
<p>这就像两个人使用同一本私人字典。字典内容可以通过数据学习，但写入和读出必须遵守同一个协议。</p>
<hr>
<h2 id="5-16-个-token-如何被抽到-root">5. 16 个 token 如何被抽到 root</h2>
<p>对于 16 个 leaf，编码过程是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>16 leaf
</span></span><span style="display:flex;"><span>  ↓ FOLD
</span></span><span style="display:flex;"><span>8 parent + 8 detail-1
</span></span><span style="display:flex;"><span>  ↓ FOLD
</span></span><span style="display:flex;"><span>4 parent + 4 detail-2
</span></span><span style="display:flex;"><span>  ↓ FOLD
</span></span><span style="display:flex;"><span>2 parent + 2 detail-3
</span></span><span style="display:flex;"><span>  ↓ FOLD
</span></span><span style="display:flex;"><span>1 root   + 1 detail-4
</span></span></code></pre></div><p>最终状态不是只有 root，而是：</p>
$$ H_{state} =(root,D^{(4)},D^{(3)},D^{(2)},D^{(1)}). $$<p>decoder 不允许跳到 parent-1，也不能读取原始 leaf。它必须从 root 开始：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root + detail-4
</span></span><span style="display:flex;"><span>    ↓ UNFOLD
</span></span><span style="display:flex;"><span>2 个 parent-3
</span></span><span style="display:flex;"><span>    ↓ 加 detail-3，再 UNFOLD
</span></span><span style="display:flex;"><span>4 个 parent-2
</span></span><span style="display:flex;"><span>    ↓ 加 detail-2，再 UNFOLD
</span></span><span style="display:flex;"><span>8 个 parent-1
</span></span><span style="display:flex;"><span>    ↓ 加 detail-1，再 UNFOLD
</span></span><span style="display:flex;"><span>16 个 leaf state
</span></span><span style="display:flex;"><span>    ↓ READ
</span></span><span style="display:flex;"><span>16 个 token
</span></span></code></pre></div><p>这就是“抽上去，再放下来”。</p>
<hr>
<h2 id="6-演绎-echo-和归纳-echo-是什么关系">6. 演绎 Echo 和归纳 Echo 是什么关系</h2>
<h3 id="61-演绎部分代数保证闭包">6.1 演绎部分：代数保证闭包</h3>
<p>只要保存完整的 root 和 details，无论 $P_\theta$ 的参数是什么，FOLD/UNFOLD 都应该闭合。</p>
<p>我们用随机连续向量测试深度 1 到 6 的树：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>深度 6 最大 FP32 闭包误差</td>
          <td style="text-align: right">3.70e-6</td>
      </tr>
      <tr>
          <td>真实 token state MSE</td>
          <td style="text-align: right">3.14e-14</td>
      </tr>
      <tr>
          <td>最大 state 误差</td>
          <td style="text-align: right">2.86e-6</td>
      </tr>
  </tbody>
</table>
<p>这是演绎证据：结果来自公式本身。</p>
<h3 id="62-归纳部分语料决定私人坐标系">6.2 归纳部分：语料决定私人坐标系</h3>
<p>如果 Echo 永远精确，单独用 Echo loss 训练 $P_\theta$ 是没有意义的。</p>
<p>因为任何 predictor 都会被自己的 UNFOLD 抵消：</p>
$$ UNFOLD_\theta(FOLD_\theta(X))=X. $$<p>所以，这次没有用 Echo 作为训练 loss。训练任务是自然语料 next-token：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>观察 16 个真实中文 token
</span></span><span style="display:flex;"><span>    ↓ Lifting FOLD
</span></span><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>预测第 17 个自然出现的 token
</span></span></code></pre></div><p>其 loss 为：</p>
$$ L_{\mathrm{next}} =-\log P(x_{17}\mid root(x_1,\ldots,x_{16})). $$<p>这给 root 制造了真正的“压力差”：如果 predictor 产生的 root 对语料预测无用，NLL 就不会下降。</p>
<p>实验结果：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">验证 NLL，越低越好</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>frozen predictor</td>
          <td style="text-align: right">8.06377</td>
      </tr>
      <tr>
          <td>learned predictor</td>
          <td style="text-align: right">8.03468</td>
      </tr>
      <tr>
          <td>learned 改善</td>
          <td style="text-align: right">0.02910</td>
      </tr>
  </tbody>
</table>
<p>predictor 的最大梯度范数为 0.50191，参数变化量为 16.13119。语料梯度确实改变了抽水 kernel。</p>
<p>然后，我们使用这个<strong>经过归纳学习的 $P_\theta$</strong>，遮住全部 leaf，只凭训练形成的 $H_{state}$ 逆运算：</p>
<table>
  <thead>
      <tr>
          <th>Echo 指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token top-1</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>16-token block exact</td>
          <td style="text-align: right">1.0000</td>
      </tr>
  </tbody>
</table>
<p>因此，更准确的说法是：</p>
<blockquote>
<p>归纳学习决定 TreeHeap 的私人坐标系；演绎闭包保证这个坐标系可以被同一协议读回。</p></blockquote>
<hr>
<h2 id="7-它真的使用-root-和每层-detail-吗">7. 它真的使用 root 和每层 detail 吗</h2>
<p>只看 100% Echo 仍然不够。我们继续做因果消融。</p>
<h3 id="71-删除-root">7.1 删除 root</h3>
<table>
  <thead>
      <tr>
          <th>条件</th>
          <th style="text-align: right">token top-1</th>
          <th style="text-align: right">block exact</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>完整 H_state</td>
          <td style="text-align: right">1.0000</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>root 清零</td>
          <td style="text-align: right">0.93042</td>
          <td style="text-align: right">0.0000</td>
      </tr>
      <tr>
          <td>root 换成另一句</td>
          <td style="text-align: right">0.93701</td>
          <td style="text-align: right">0.0078125</td>
      </tr>
  </tbody>
</table>
<p>删除 root 后，大多数单词仍可能因为局部 detail 而落在正确 embedding 附近，但没有一个 block 能完整恢复。</p>
<p>所以 root 不是全部细节，却是完整闭合链的一部分。</p>
<h3 id="72-打乱不同深度的-detail-地址">7.2 打乱不同深度的 detail 地址</h3>
<table>
  <thead>
      <tr>
          <th>被换址的 detail</th>
          <th style="text-align: right">token accuracy 下降</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>detail-1</td>
          <td style="text-align: right">49.88%</td>
      </tr>
      <tr>
          <td>detail-2</td>
          <td style="text-align: right">25.00%</td>
      </tr>
      <tr>
          <td>detail-3</td>
          <td style="text-align: right">12.35%</td>
      </tr>
      <tr>
          <td>detail-4</td>
          <td style="text-align: right">6.32%</td>
      </tr>
  </tbody>
</table>
<p>这个接近逐层减半的规律很好理解：detail-1 直接区分每一对 leaf；越高层的 detail 数量越少，但覆盖范围越大。</p>
<h3 id="73-破坏每一层的左右配对">7.3 破坏每一层的左右配对</h3>
<p>在 next-token 任务中，分别把某一深度的右子树换成其他样本：</p>
<table>
  <thead>
      <tr>
          <th>被破坏的 FOLD 深度</th>
          <th style="text-align: right">NLL 增加</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>depth 1</td>
          <td style="text-align: right">+0.03221</td>
      </tr>
      <tr>
          <td>depth 2</td>
          <td style="text-align: right">+0.03838</td>
      </tr>
      <tr>
          <td>depth 3</td>
          <td style="text-align: right">+0.04324</td>
      </tr>
      <tr>
          <td>depth 4</td>
          <td style="text-align: right">+0.05634</td>
      </tr>
  </tbody>
</table>
<p>四个深度都产生损失。</p>
<p>这和旧版 99.9786% 停在 parent-1 的情况不同：新的 root 预测确实依赖完整递归路径。</p>
<hr>
<h2 id="8-为什么预注册-claim-仍然没有全过">8. 为什么预注册 Claim 仍然没有全过</h2>
<p>我们事先规定：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root 被删除后，Echo token accuracy 至少下降 10%
</span></span></code></pre></div><p>实际下降是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>6.96%
</span></span></code></pre></div><p>所以 P3 没有通过，完整 Claim 必须保持 not fully supported。</p>
<p>我们不能看到 block exact 从 100% 降到 0% 后，再偷偷把评价标准从 token accuracy 换成 block exact。</p>
<p>不过可以保留一个更窄的结论：</p>
<ol>
<li>lifting FOLD/UNFOLD 已经闭合；</li>
<li>全部 leaf 被 mask 后，可以只凭 $H_{state}$ 完整 Echo；</li>
<li>每层 detail 都是地址敏感且有因果作用的；</li>
<li>root 对整块闭合和 next-token 都有因果作用；</li>
<li>真实语料梯度能够训练 predictor；</li>
<li>learned predictor 小幅但明确优于 frozen predictor。</li>
</ol>
<hr>
<h2 id="9-高层不需要对应人类命名的语义">9. 高层不需要对应人类命名的语义</h2>
<p>Houming818 对这一步提出了一个重要修正：</p>
<blockquote>
<p>我们不需要证明 root 一定表示“主题”，parent 一定表示“短语”。这些结构可以通过数据涌现，而且换一种抽水算法，形成的内部意义可能完全不同，解并不唯一。</p></blockquote>
<p>我们同意这个判断。</p>
<p>假设两个 TreeHeap 使用不同 predictor：</p>
$$ P_{\theta_1},\qquad P_{\theta_2}. $$<p>它们可能形成完全不同的 root/detail 坐标系，但只要分别满足：</p>
$$ UNFOLD_{\theta_1}(FOLD_{\theta_1}(X))=X, $$$$ UNFOLD_{\theta_2}(FOLD_{\theta_2}(X))=X, $$<p>并且都能降低真实任务 loss，它们就可以是两个不同但有效的私人协议。</p>
<p>这类似每个人的笔迹不同，但各自可以读懂自己写下的内容。</p>
<p>因此，我们不应强迫内部节点对应预先定义的主谓宾、词性或人工类别。真正需要验证的是操作意义：</p>
<ul>
<li>能否写入；</li>
<li>能否读回；</li>
<li>地址是否有因果作用；</li>
<li>删除节点是否按结构损坏结果；</li>
<li>学习是否改善真实任务；</li>
<li>更大的任务是否能站在这个协议上继续训练。</li>
</ul>
<hr>
<h2 id="10-当前边界和下一步">10. 当前边界和下一步</h2>
<p>当前已经完成的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整 token
</span></span><span style="display:flex;"><span>→ 归纳学习过的 lifting encoder
</span></span><span style="display:flex;"><span>→ H_state
</span></span><span style="display:flex;"><span>→ mask 全部 leaf
</span></span><span style="display:flex;"><span>→ 演绎 UNFOLD
</span></span><span style="display:flex;"><span>→ 100% Echo
</span></span></code></pre></div><p>还没有完成的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整 token
</span></span><span style="display:flex;"><span>→ H_state
</span></span><span style="display:flex;"><span>→ 删除 H_state 中某个必要 detail
</span></span><span style="display:flex;"><span>→ 根据其他尺度和世界经验补回缺失信息
</span></span></code></pre></div><p>后一种任务不再是严格逆运算，而是：</p>
$$ P(D_{\mathrm{missing}}\mid root,D_{\mathrm{visible}},context). $$<p>它才是从“私人可逆编码”走向“缺失信息推断”的下一步。</p>
<p>但至少现在，TreeHeap 不再只是执行了几次形式上的递归卷积。我们已经有了一套明确的信息流规则：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>FOLD：向上抽取 parent，留下 addressed detail
</span></span><span style="display:flex;"><span>UNFOLD：从 root 出发，逐层补回 detail
</span></span><span style="display:flex;"><span>LEARN：真实语料梯度改变 predictor 和内部坐标系
</span></span><span style="display:flex;"><span>ECHO：遮住全部表面 leaf 后，仍可精确恢复
</span></span></code></pre></div><p>这是一台已经能运转的信息抽水机。</p>
<p>它是不是语言智能，还远远没有证明；但它终于不再是一根只在第一层取水的管道。</p>
<hr>
<h2 id="evidence">Evidence</h2>
<p>ARA 声明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/logic/lifting_information_pump.md
</span></span></code></pre></div><p>实验代码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/src/s1_lifting_information_pump.py
</span></span></code></pre></div><p>正式 Evidence：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/evidence/s1_lifting_information_pump/main/
</span></span></code></pre></div><p>SameTime commit：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>f17ab3f
</span></span></code></pre></div><p>本文记录的是可复现实验和当前边界，不是对 TreeHeap 语义、意识或通用智能的完成声明。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-059] TreeHeap 抽水机第一次进入 WMT：递归 READ 成立了，但翻译还没有赢</title>
      <link>https://www.grepcode.cn/spr/059-treeheap-lifting-wmt-recursive-read.html</link>
      <pubDate>Thu, 16 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/059-treeheap-lifting-wmt-recursive-read.html</guid>
      <description>在 27K/2K/2K 英中 WMT 数据上验证 TreeHeap lifting encoder 与 root-first 概率递归 READ：八项机制门全部通过，TreeHeap 明确利用了 root、detail 和递归配对，但 flat sequence baseline 仍有更好的翻译 NLL。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-抽水机第一次进入-wmt递归-read-成立了但翻译还没有赢">TreeHeap 抽水机第一次进入 WMT：递归 READ 成立了，但翻译还没有赢</h1>
<p>上一篇 SPR-058 做的是 Echo：一句话先经过 TreeHeap FOLD，形成</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_state = root + 各层 details
</span></span></code></pre></div><p>然后遮住原始 token，只使用 (H_{state}) 做 UNFOLD，能够把输入完整恢复。</p>
<p>这证明 lifting pump 是一个可逆的信息容器，但还没有证明它能完成翻译。因为翻译不是把英语原样抄回来，而是要根据英语状态，逐个生成中文 token。</p>
<p>SPR-059 因此向前走了一步：</p>
<blockquote>
<p>把真实英文 WMT 句子写入 lifting TreeHeap，再让中文 decoder 从 root 开始递归读取。只用翻译交叉熵训练，不提供路径标签、句法标签、对齐标签或内部节点答案。</p></blockquote>
<p>结果可以先用一句话概括：</p>
<blockquote>
<p><strong>TreeHeap 的递归读取机制得到了强证据，但翻译质量仍然没有超过 flat sequence baseline。</strong></p></blockquote>
<p>这不是模棱两可。它回答的是两个不同问题：</p>
<ol>
<li>模型是否真的利用了 TreeHeap 的 root、路径、detail 和递归配对？答案是“是”。</li>
<li>这套实现是否已经比普通序列模型翻译得更好？答案是“否”。</li>
</ol>
<hr>
<h2 id="1-这次模型究竟在做什么">1. 这次模型究竟在做什么</h2>
<p>任务是标准英中翻译：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>英文句子
</span></span><span style="display:flex;"><span>    -&gt; TreeHeap encoder
</span></span><span style="display:flex;"><span>H_src = root + details
</span></span><span style="display:flex;"><span>    -&gt; 概率递归 READ
</span></span><span style="display:flex;"><span>中文 decoder
</span></span><span style="display:flex;"><span>    -&gt; 下一个中文 token 的概率桶
</span></span><span style="display:flex;"><span>    -&gt; argmax 坍缩
</span></span><span style="display:flex;"><span>中文句子
</span></span></code></pre></div><p>其中有三个需要分清的对象：</p>
<table>
  <thead>
      <tr>
          <th>对象</th>
          <th>本次实验中的含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>(H_{src})</td>
          <td>当前英文句子的 TreeHeap 状态，即 root 与各层 addressed details</td>
      </tr>
      <tr>
          <td>(q_t)</td>
          <td>中文生成到第 (t) 步时，decoder 已经积累的查询状态</td>
      </tr>
      <tr>
          <td>θ</td>
          <td>embedding、lifting predictor、递归 stop/branch kernel 与中文 decoder 的可学习参数</td>
      </tr>
  </tbody>
</table>
<p>θ 不是某一棵输入句子的树。它是所有样本共同训练的规则参数；(H_{src}) 才是当前句子被写入以后形成的状态。</p>
<h3 id="11-英文如何写进-treeheap">1.1 英文如何写进 TreeHeap</h3>
<p>英文 token embedding 先放在叶子。每两个相邻状态记为 (L,R)，共享 predictor (P_θ) 计算：</p>
$$ D=R-P_\theta(L), $$$$ U=L+\frac12D. $$<p>其中：</p>
<ul>
<li>(D) 是当前地址保留的 detail；</li>
<li>(U) 是继续向父节点上传的粗分辨率状态；</li>
<li>所有深度共享同一个 (P_\theta)。</li>
</ul>
<p>这个过程不断递归：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>32 leaves
</span></span><span style="display:flex;"><span>  -&gt; 16 parents + 16 details
</span></span><span style="display:flex;"><span>  -&gt;  8 parents +  8 details
</span></span><span style="display:flex;"><span>  -&gt;  4 parents +  4 details
</span></span><span style="display:flex;"><span>  -&gt;  2 parents +  2 details
</span></span><span style="display:flex;"><span>  -&gt;  1 root    +  1 detail
</span></span></code></pre></div><p>最终的英文表示不是一个 root 向量，而是：</p>
$$ H_{src}=(root,D^{(5)},D^{(4)},\ldots,D^{(1)}). $$<p>root 提供大范围轮廓，detail 保留各个地址上没有被父节点完全表达的差异。</p>
<h3 id="12-中文-decoder-如何读取这棵树">1.2 中文 decoder 如何读取这棵树</h3>
<p>生成每个中文 token 时，概率质量从 root 的 1.0 开始。</p>
<p>在深度 (d) 的节点 (v)，stop kernel 根据中文查询状态、节点状态和深度计算：</p>
$$ p_{stop}(v,t) = \sigma K_{stop}(q_t,H_v,d). $$<p>一部分概率停在当前节点，当前节点的信息进入中文 context；剩余概率继续向左右孩子展开：</p>
$$ m_{stop}=m_v p_{stop}, $$$$ m_{expand}=m_v(1-p_{stop}). $$<p>branch kernel 再把 (m_{expand}) 分给 left 与 right。这个过程一直递归到所有概率已经停下，或者走到叶子。</p>
<p>因此，decoder 每一步得到的不是一个硬地址，而是一个跨分辨率的概率前沿：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root             0.20
</span></span><span style="display:flex;"><span>某个中层节点     0.35
</span></span><span style="display:flex;"><span>几个更深节点     0.30
</span></span><span style="display:flex;"><span>部分 leaves      0.15
</span></span><span style="display:flex;"><span>---------------------
</span></span><span style="display:flex;"><span>总概率           1.00
</span></span></code></pre></div><p>这些节点的加权和形成当前 source context，再与中文 decoder state 一起计算下一个 token：</p>
$$ p(y_t\mid y_{\lt t},H_{src}). $$<p>训练时只有普通翻译损失：</p>
$$ L_{S2} = -\sum_t\log p(y_t\mid y_{\lt t},H_{src}). $$<p>没有任何老师告诉 READ “这里应该停在 root”或“这里应该向左”。如果不同深度的读取规律形成，只能来自翻译 loss 的梯度。</p>
<hr>
<h2 id="2-为什么需要五个模型一起比较">2. 为什么需要五个模型一起比较</h2>
<p>只训练一个 TreeHeap 模型，即使 NLL 下降，也无法判断下降来自哪里。因此实验同时训练五个参数量接近的模型：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>它回答的问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>target-only</td>
          <td>完全不看英语，中文语言模型自己能做到什么程度？</td>
      </tr>
      <tr>
          <td>flat sequence</td>
          <td>普通序列 encoder 与 attention 能做到什么程度？</td>
      </tr>
      <tr>
          <td>lifting-root</td>
          <td>只给 decoder 一个 root，压缩是否过强？</td>
      </tr>
      <tr>
          <td>lifting-full</td>
          <td>完全 UNFOLD 后读取 leaves，完整信息上限如何？</td>
      </tr>
      <tr>
          <td>lifting-recursive</td>
          <td>从 root 开始，自己决定在哪个深度停留或下沉</td>
      </tr>
  </tbody>
</table>
<p><code>lifting-full</code> 不是 TreeHeap 效率模型，而是信息对照：它把原分辨率全部展开，告诉我们“信息本身还在不在”。</p>
<p><code>lifting-recursive</code> 才是本文要测试的模型。</p>
<hr>
<h2 id="3-预注册的-predict">3. 预注册的 Predict</h2>
<p>在看正式结果之前，我们先写下八个通过条件：</p>
<ol>
<li>递归 READ 的 NLL 不高于历史 root-exclusive 结果 6.55；</li>
<li>比 root-only 至少改善 0.05 NLL；</li>
<li>与 full UNFOLD 的差距不超过 0.10 NLL；</li>
<li>打乱完整英文状态至少损失 0.20 NLL；</li>
<li>root 与至少一层 detail 必须具有因果作用；</li>
<li>至少两个深度的左右配对破坏必须造成损失；</li>
<li>READ 必须使用至少两个分辨率，不能全部坍缩到 leaves；</li>
<li>FOLD/UNFOLD 闭包、有限梯度与非空生成必须通过。</li>
</ol>
<p>这里最重要的是第 4 到第 7 条。它们防止我们把“模型输出了中文”误报成“模型使用了 TreeHeap”。</p>
<hr>
<h2 id="4-数据与训练规模">4. 数据与训练规模</h2>
<p>正式实验在 <code>io</code> 的 RTX 3090 上运行：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>方向</td>
          <td style="text-align: right">English -&gt; Chinese</td>
      </tr>
      <tr>
          <td>训练/验证/测试</td>
          <td style="text-align: right">27,000 / 2,000 / 2,000</td>
      </tr>
      <tr>
          <td>词表</td>
          <td style="text-align: right">16,001</td>
      </tr>
      <tr>
          <td>状态维度</td>
          <td style="text-align: right">256</td>
      </tr>
      <tr>
          <td>epoch</td>
          <td style="text-align: right">10</td>
      </tr>
      <tr>
          <td>最佳模型选择</td>
          <td style="text-align: right">最低 validation NLL</td>
      </tr>
      <tr>
          <td>总运行时间</td>
          <td style="text-align: right">1,398.49 秒</td>
      </tr>
      <tr>
          <td>FOLD/UNFOLD MSE</td>
          <td style="text-align: right">1.73e-14</td>
      </tr>
  </tbody>
</table>
<p>长度过滤后数据共有 31,337 条，正式拆分使用了其中 31,000 条。实验没有报告多 seed，因此它仍是一次 full-scale mechanism proof，不是最终统计结论。</p>
<hr>
<h2 id="5-指标像体检报告一样怎么看">5. 指标像体检报告一样怎么看</h2>
<h3 id="51-nll越小越好">5.1 NLL：越小越好</h3>
<p>NLL 是模型给正确中文 token 分配的负对数概率。正确答案概率越高，NLL 越小。</p>
<h3 id="52-ppl越小越好">5.2 PPL：越小越好</h3>
$$ PPL=e^{NLL}. $$<p>它可以粗略理解为：模型在每一步还像是在多少个候选之间犹豫。它不是候选数的字面值，但越小通常越好。</p>
<h3 id="53-token-bleu-4越大越好">5.3 Token BLEU-4：越大越好</h3>
<p>它检查生成结果与参考译文是否共享连续 token 片段。本文数值整体很低，说明五个小模型都远未达到实用翻译质量。</p>
<hr>
<h2 id="6-主结果结构机制通过质量没有获胜">6. 主结果：结构机制通过，质量没有获胜</h2>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">参数量</th>
          <th style="text-align: right">Test NLL ↓</th>
          <th style="text-align: right">PPL ↓</th>
          <th style="text-align: right">Token BLEU-4 ↑</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>target-only</td>
          <td style="text-align: right">12.96M</td>
          <td style="text-align: right">5.7189</td>
          <td style="text-align: right">304.57</td>
          <td style="text-align: right">0.117</td>
      </tr>
      <tr>
          <td>flat sequence</td>
          <td style="text-align: right">17.45M</td>
          <td style="text-align: right"><strong>4.8103</strong></td>
          <td style="text-align: right"><strong>122.77</strong></td>
          <td style="text-align: right"><strong>3.169</strong></td>
      </tr>
      <tr>
          <td>lifting-root</td>
          <td style="text-align: right">17.32M</td>
          <td style="text-align: right">5.4337</td>
          <td style="text-align: right">229.01</td>
          <td style="text-align: right">1.585</td>
      </tr>
      <tr>
          <td>lifting-full</td>
          <td style="text-align: right">17.32M</td>
          <td style="text-align: right">5.1342</td>
          <td style="text-align: right">169.73</td>
          <td style="text-align: right">1.881</td>
      </tr>
      <tr>
          <td>lifting-recursive</td>
          <td style="text-align: right">17.52M</td>
          <td style="text-align: right"><strong>5.0903</strong></td>
          <td style="text-align: right"><strong>162.44</strong></td>
          <td style="text-align: right"><strong>2.528</strong></td>
      </tr>
  </tbody>
</table>
<h3 id="好消息">好消息</h3>
<p>递归 READ 比 root-only 改善：</p>
$$ 5.4337-5.0903=0.3434. $$<p>这说明一个 root 不够；读取 addressed details 明显有价值。</p>
<p>递归 READ 还比完全 UNFOLD 小幅改善 0.0439 NLL。一个合理但尚未证明的解释是：概率前沿起到了结构化正则化作用，没有让 decoder 在每一步同时面对全部 leaves。</p>
<h3 id="坏消息">坏消息</h3>
<p>flat sequence 仍然领先递归 TreeHeap：</p>
$$ 5.0903-4.8103=0.2800. $$<p>BLEU-4 也低 0.641。TreeHeap 目前获得的是“存在性”，不是“优越性”。</p>
<hr>
<h2 id="7-它真的使用了-treeheap-吗">7. 它真的使用了 TreeHeap 吗</h2>
<p>这是本文最强的证据。</p>
<p>以正常递归模型 NLL <code>5.0903</code> 为基准：</p>
<table>
  <thead>
      <tr>
          <th>干预</th>
          <th style="text-align: right">NLL 增量</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>打乱完整 source H_state</td>
          <td style="text-align: right">+1.4450</td>
          <td>输出强依赖当前英文句子</td>
      </tr>
      <tr>
          <td>只打乱 root</td>
          <td style="text-align: right">+1.7204</td>
          <td>root 是强因果状态，不是装饰</td>
      </tr>
      <tr>
          <td>强制只读 root</td>
          <td style="text-align: right">+1.1773</td>
          <td>只看全局轮廓不够</td>
      </tr>
      <tr>
          <td>强制一直走到 leaves</td>
          <td style="text-align: right">+0.6236</td>
          <td>只看最细粒度也不够</td>
      </tr>
  </tbody>
</table>
<p>五层 detail 分别打乱后的损失：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>+0.1171, +0.1422, +0.2402, +0.4960, +0.4857
</span></span></code></pre></div><p>五层左右子树配对被跨样本破坏后的损失：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>+0.4807, +0.4414, +0.4107, +0.4354, +0.2105
</span></span></code></pre></div><p>所有深度都不是中性的。也就是说，模型不只读取了一袋向量；它依赖“哪个 detail 在哪个深度”和“哪些左右子树被组合在一起”。</p>
<p>正常 READ 的平均 stop mass 为：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">深度</th>
          <th style="text-align: right">Stop mass</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">root</td>
          <td style="text-align: right">0.3329</td>
      </tr>
      <tr>
          <td style="text-align: right">depth 1</td>
          <td style="text-align: right">0.0288</td>
      </tr>
      <tr>
          <td style="text-align: right">depth 2</td>
          <td style="text-align: right">0.1283</td>
      </tr>
      <tr>
          <td style="text-align: right">depth 3</td>
          <td style="text-align: right">0.0384</td>
      </tr>
      <tr>
          <td style="text-align: right">depth 4</td>
          <td style="text-align: right">0.0073</td>
      </tr>
      <tr>
          <td style="text-align: right">leaves</td>
          <td style="text-align: right">0.4643</td>
      </tr>
  </tbody>
</table>
<p>总和为 1。模型主要使用 root 和 leaves，但中间分辨率也承担了约 20.3% 的概率质量。这就是“多分辨率 READ”的实证含义。</p>
<hr>
<h2 id="8-真实生成样例">8. 真实生成样例</h2>
<p>下面不是 cherry-pick 的最佳句子，而是测试集开头的典型输出。它们能更诚实地说明当前能力边界。</p>
<h3 id="样例一抓到了财政主题但句法和词义仍然混乱">样例一：抓到了财政主题，但句法和词义仍然混乱</h3>
<p><strong>英文输入</strong></p>
<blockquote>
<p>As economies then weakened, the prospects for fiscal consolidation grew dimmer.</p></blockquote>
<p><strong>参考译文</strong></p>
<blockquote>
<p>经济随之疲软，因此财政整合前景也变得更加虚弱。</p></blockquote>
<p><strong>flat sequence</strong></p>
<blockquote>
<p>新兴经济体开始，其财政前景似乎出现了了。</p></blockquote>
<p><strong>递归 TreeHeap</strong></p>
<blockquote>
<p>由此从那时，其银行也变得越来越微财政巩固。</p></blockquote>
<p>TreeHeap 读出了“财政巩固”和趋势变化的主题，但没有组成正确中文。这里能看到 source signal，不是可用翻译。</p>
<h3 id="样例二主题词正确重复坍缩严重">样例二：主题词正确，重复坍缩严重</h3>
<p><strong>英文输入</strong></p>
<blockquote>
<p>Bond prices then fell further, damaging European banks even more.</p></blockquote>
<p><strong>参考译文</strong></p>
<blockquote>
<p>这造成债券价格进一步下跌，给欧洲银行造成更多的伤害。</p></blockquote>
<p><strong>flat sequence</strong></p>
<blockquote>
<p>价格下跌进一步下跌，银行也更加更加更大。</p></blockquote>
<p><strong>递归 TreeHeap</strong></p>
<blockquote>
<p>进一步进一步进一步进一步进一步进一步进一步进一步上升，欧洲银行甚至进一步上升。</p></blockquote>
<p>TreeHeap 找到了“进一步”和“欧洲银行”，却把“下跌”生成成“上升”，并陷入重复循环。这是 decoder 与训练规模的明确失败，不应被结构干预的成功掩盖。</p>
<h3 id="样例三知道在谈银行和融资但关系没有还原">样例三：知道在谈银行和融资，但关系没有还原</h3>
<p><strong>英文输入</strong></p>
<blockquote>
<p>Reassured that they will have access to funding, the banks again have the confidence to lend.</p></blockquote>
<p><strong>参考译文</strong></p>
<blockquote>
<p>银行获得了能够得到融资的保证，因此重新获得了发放贷款的信心。</p></blockquote>
<p><strong>递归 TreeHeap</strong></p>
<blockquote>
<p>他们在他们方面会继续下去，但银行银行再次进入了。</p></blockquote>
<p>它保留了“银行”“再次”以及继续发生某事的轮廓，但融资、保证、贷款和因果关系都没有正确解码。</p>
<h3 id="样例四flat-baseline-明显更接近参考答案">样例四：flat baseline 明显更接近参考答案</h3>
<p><strong>英文输入</strong></p>
<blockquote>
<p>Tax increases and cuts in public spending are still needed; there is no avoiding this reality.</p></blockquote>
<p><strong>参考译文</strong></p>
<blockquote>
<p>加税削减了仍属必须的公共支出；这是不可避免的现实。</p></blockquote>
<p><strong>flat sequence</strong></p>
<blockquote>
<p>削减公共支出削减公共支出削减；但依然存在这一现实。</p></blockquote>
<p><strong>递归 TreeHeap</strong></p>
<blockquote>
<p>税收支出支出支出支出支出，在这个问题上中，我们还有很容易。</p></blockquote>
<p>这个样例直观解释了为什么 flat baseline 的总体 NLL 和 BLEU 更好。</p>
<hr>
<h2 id="9-八个-predict-的最终体检">9. 八个 Predict 的最终体检</h2>
<table>
  <thead>
      <tr>
          <th>Gate</th>
          <th>结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>P1：超过历史 root-exclusive NLL</td>
          <td>PASS</td>
      </tr>
      <tr>
          <td>P2：递归优于 root-only</td>
          <td>PASS</td>
      </tr>
      <tr>
          <td>P3：接近 full UNFOLD</td>
          <td>PASS</td>
      </tr>
      <tr>
          <td>P4：完整 source 状态具有因果性</td>
          <td>PASS</td>
      </tr>
      <tr>
          <td>P5：root 与 detail 都具有因果性</td>
          <td>PASS</td>
      </tr>
      <tr>
          <td>P6：多个递归配对深度具有因果性</td>
          <td>PASS</td>
      </tr>
      <tr>
          <td>P7：使用多个分辨率</td>
          <td>PASS</td>
      </tr>
      <tr>
          <td>P8：闭包、梯度与非空生成</td>
          <td>PASS</td>
      </tr>
  </tbody>
</table>
<p>因此 Claim <code>S2-LIFT-WMT-C01</code> 的准确状态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap mechanism: supported
</span></span><span style="display:flex;"><span>Translation superiority: rejected
</span></span><span style="display:flex;"><span>Compression advantage: open
</span></span><span style="display:flex;"><span>Compute advantage: open
</span></span><span style="display:flex;"><span>Production translation: not supported
</span></span></code></pre></div><hr>
<h2 id="10-下一步不应该做什么">10. 下一步不应该做什么</h2>
<p>不应该因为八个 gate 全过，就直接把数据扩大一百倍并宣布成功。</p>
<p>当前实现还有三个明确问题：</p>
<ol>
<li>flat sequence 仍领先 0.2800 NLL；</li>
<li>中文 decoder 有严重重复和关系反转；</li>
<li>代码会先物化所有 TreeHeap 层，再计算概率 READ，因此还没有获得真正的稀疏计算优势。</li>
</ol>
<p>也不应该把中间深度人工命名成“主语层”“语义层”或“意识层”。实验只证明这些状态具有因果作用，没有证明它们对应人类可读语法。</p>
<hr>
<h2 id="11-下一步真正值得验证什么">11. 下一步真正值得验证什么</h2>
<p>我认为下一步有三个优先级。</p>
<h3 id="第一修复生成而不破坏结构读法">第一：修复生成，而不破坏结构读法</h3>
<p>保留同一个 lifting encoder 和递归 READ，升级 target decoder，并加入重复惩罚、长度控制与更稳的解码评估。目标是缩小对 flat baseline 的 0.2800 NLL 差距。</p>
<h3 id="第二做真正的按需-unfold">第二：做真正的按需 UNFOLD</h3>
<p>现在所有层都已经算好。下一版应该只展开仍然携带概率质量的节点，统计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>访问节点数 / 完整树节点数
</span></span><span style="display:flex;"><span>实际 FLOPs
</span></span><span style="display:flex;"><span>显存
</span></span><span style="display:flex;"><span>延迟
</span></span></code></pre></div><p>只有在质量接近且访问节点显著减少时，才能讨论 TreeHeap 的压缩检索优势。</p>
<h3 id="第三跨-seed-复核">第三：跨 seed 复核</h3>
<p>至少运行三个 seed，报告均值、标准差和干预效应区间。递归模型略胜 full UNFOLD 的 0.0439 NLL 很小，单次实验不足以把它升级成稳定优势。</p>
<hr>
<h2 id="12-最终结论">12. 最终结论</h2>
<p>SPR-058 证明 lifting pump 能把信息抽上去并严格放回来。SPR-059 进一步证明：</p>
<blockquote>
<p>在真实 WMT 数据上，普通翻译梯度可以训练出一个从 root 开始、依赖地址与递归配对、在多个 TreeHeap 分辨率之间分配概率的 READ。</p></blockquote>
<p>这是我们第一次不靠 Echo、不靠内部标签，看到 TreeHeap 结构参与真实 S2 任务。</p>
<p>但样例也非常诚实：模型还不会稳定地说中文，重复、反义词和关系丢失都很严重。TreeHeap 现在拥有了一条可信的数据通路，还没有获得更强的产品能力。</p>
<p>这条边界必须保留。因为真正值得继续研究的，不是把一次机制 proof 写成胜利，而是已经知道下一块损失具体在哪里。</p>
<hr>
<h2 id="evidence">Evidence</h2>
<ul>
<li>ARA claim：<code>S2-LIFT-WMT-C01</code></li>
<li>Predict：<code>P-S2-LIFT-WMT-01</code></li>
<li>SameTime commit：<code>fb17f8f</code></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/logic/s2_lifting_pump_wmt.md">实验设计与结论</a></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/src/s2_lifting_pump_wmt.py">复现实验代码</a></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/evidence/s2_lifting_pump_wmt_full/summary.json">完整 summary.json</a></li>
<li>Checkpoints：<code>/mnt/nas/ara/s3-generation/evidence/s2_lifting_pump_wmt_full/</code></li>
</ul>
<p>本文中的 TreeHeap 实验设计、实现与结论记录按本项目许可证公开。lifting scheme 等已有数学工具不被主张为本项目原创；原创部分限定为本次组合设计、可证伪实验和相应 evidence。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-060] TreeHeap 退火缩句协议：让重要信息活到更高层</title>
      <link>https://www.grepcode.cn/spr/060-treeheap-annealed-contraction-protocol.html</link>
      <pubDate>Thu, 16 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/060-treeheap-annealed-contraction-protocol.html</guid>
      <description>从单 token Mask 的信息单一化出发，提出 TreeHeap 的分层退火缩句协议：完整输入先参与 FOLD，随后在逐层收窄的容量中保留更有解释力和预测力的结构，detail 保存局部精度，parent 与 root 保存越来越粗的语言轮廓。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-退火缩句协议让重要信息活到更高层">TreeHeap 退火缩句协议：让重要信息活到更高层</h1>
<p>这篇文章保存一个新的研究转折点。</p>
<p>它不是已经被实验支持的结论，而是 Houming818 在复盘 TreeHeap 预训练时提出的新假设。我们先把它完整、准确地记录下来，再据此设计下一轮 ARA、Predict 和 Proof。</p>
<p>Houming818 的原始表述是：</p>
<blockquote>
<p>在第 0 层，是一个长 string，例如“夏天的凉风吹过一望无际的青青草原”。<br>
抽水时，算法提取缩减句子，例如“夏天的凉风吹过草原”。<br>
再往上，只剩“风吹过草原”。<br>
这是一个缩句和插值退火的过程。信息会消失，但应保留更重要的细节。<br>
它不能缩减成“夏天凉风”；这同样是缩减，却不是更优的缩减，因此 Loss 应该更高。</p></blockquote>
<p>这段话把 TreeHeap encoder 的目标，从“保存所有 token”推进成了：</p>
<blockquote>
<p><strong>完整信息先进入 TreeHeap，然后在越来越窄的层级中逐步有损收缩；能够减少更多未来 Loss 的结构活到高层，其余精度留在低层 detail。</strong></p></blockquote>
<hr>
<h2 id="1-上一轮实验停在哪里">1. 上一轮实验停在哪里</h2>
<p>上一轮真实中文预训练比较了三种缺失片段生成课程：</p>
<table>
  <thead>
      <tr>
          <th>训练方式</th>
          <th style="text-align: right">width-4 NLL</th>
          <th style="text-align: right">width-8 NLL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>单 token Mask</td>
          <td style="text-align: right">9.1347</td>
          <td style="text-align: right">9.8977</td>
      </tr>
      <tr>
          <td>同长度随机 span</td>
          <td style="text-align: right">5.4216</td>
          <td style="text-align: right">5.9718</td>
      </tr>
      <tr>
          <td>TreeHeap 对齐 subheap</td>
          <td style="text-align: right"><strong>5.3852</strong></td>
          <td style="text-align: right"><strong>5.9179</strong></td>
      </tr>
  </tbody>
</table>
<p>实验至少确认了一件事：</p>
<blockquote>
<p>只训练单 token 恢复，会让模型严重专门化到单叶问题。它对更大缺口的处理能力不但没有自然生长，反而明显恶化。</p></blockquote>
<p>多尺度 subheap Mask 避免了这种单一化，并比等长度随机 span 小幅改善。但结构审计暴露了新的问题：</p>
<table>
  <thead>
      <tr>
          <th>干预</th>
          <th style="text-align: right">width-8 NLL 损失</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>换掉整棵 source TreeHeap</td>
          <td style="text-align: right">+0.1345</td>
      </tr>
      <tr>
          <td>清零全部 source state</td>
          <td style="text-align: right">+1.5645</td>
      </tr>
      <tr>
          <td>打乱各层 detail</td>
          <td style="text-align: right">+0.5311 到 +9.6856</td>
      </tr>
      <tr>
          <td>清零 root</td>
          <td style="text-align: right">仅 +0.0042</td>
      </tr>
      <tr>
          <td>FOLD 前交换相邻 left/right</td>
          <td style="text-align: right">仅 +0.0022</td>
      </tr>
  </tbody>
</table>
<p>因此模型学会了一个依赖 source 和多层 detail 的 seq2seq 补全器，却仍然没有把信息组织进 root 和左右地址。</p>
<p>上一轮的做法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>原始 token
</span></span><span style="display:flex;"><span>    -&gt; 先替换成 [MASK]
</span></span><span style="display:flex;"><span>    -&gt; FOLD
</span></span><span style="display:flex;"><span>    -&gt; 根据剩余信息补洞
</span></span></code></pre></div><p>新的问题是：被替换掉的真实 token 根本没有参加 FOLD。抽水机没有机会把它和其他 token 的关系上传到 parent。</p>
<p>SPR-060 因此不再研究“怎样挖一个更好的洞”，而开始研究：</p>
<blockquote>
<p>完整信息在逐层收窄时，怎样自然决定什么应该继续向上，什么应该留在低层。</p></blockquote>
<hr>
<h2 id="2-什么叫退火缩句">2. 什么叫退火缩句</h2>
<p>考虑完整句子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0：夏天的凉风吹过一望无际的青青草原
</span></span></code></pre></div><p>理想中的层级状态可能呈现为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L0：夏天的凉风吹过一望无际的青青草原
</span></span><span style="display:flex;"><span>L1：夏天的凉风吹过草原
</span></span><span style="display:flex;"><span>L2：风吹过草原
</span></span><span style="display:flex;"><span>L3：风吹草原
</span></span><span style="display:flex;"><span>L4：风—草原
</span></span></code></pre></div><p>这里的“缩句”不要求内部节点真的保存一串可阅读的汉字。encoder 与 decoder 可以形成我们看不懂的私有编码。</p>
<p>这些中文缩句只是帮助人类理解不同分辨率可能保留什么：</p>
<ul>
<li>底层包含词面、修饰、数量和局部顺序；</li>
<li>中层包含事件参与者和动作；</li>
<li>高层包含越来越粗的关系轮廓；</li>
<li>root 表示当前容量下最值得保留的全局状态。</li>
</ul>
<p>这与普通摘要不同。它不是一次性把长句变成短句，而是产生一条连续的分辨率路径。</p>
<hr>
<h2 id="3-treeheap-中什么在消失">3. TreeHeap 中什么在消失</h2>
<p>设相邻两个子状态为 (L) 和 (R)。当前 lifting FOLD 可以写成：</p>
<p>[
D = R - P_	heta(L),
]</p>
<p>[
U = L + A_phi(D).
]</p>
<p>其中：</p>
<ul>
<li>(D) 是当前地址保存的 detail；</li>
<li>(U) 是继续向 parent 上传的状态；</li>
<li>(P_	heta) 学习左右状态之间可预测的关系；</li>
<li>(A_phi) 决定差异中的多少内容进入 parent。</li>
</ul>
<p>完整的 TreeHeap 状态仍然是：</p>
<h1 id="h_extstate">[
H_{	ext{state}}</h1>
<p>left(
root,
D^{(0)},
D^{(1)},
ldots,
D^{(D-1)}
ight).
]</p>
<p>所以“信息消失”需要分两种观察口径。</p>
<h3 id="31-对整棵-h_state-而言">3.1 对整棵 H_state 而言</h3>
<p>如果 lifting 仍然严格闭合，那么信息没有真正消失。root 与所有 addressed detail 合在一起，仍可恢复底层状态。</p>
<h3 id="32-对单独-parent-或-root-而言">3.2 对单独 parent 或 root 而言</h3>
<p>信息确实在逐层减少。没有被上传的局部精度停留在 detail，不再继续进入更高层。</p>
<p>因此退火协议并不是删除整个模型中的信息，而是：</p>
<blockquote>
<p><strong>控制信息能够到达的最高深度。</strong></p></blockquote>
<p>重要的关系传播得更远；局部细节只在附近地址存在。</p>
<hr>
<h2 id="4-为什么风吹过草原可能优于夏天凉风">4. 为什么“风吹过草原”可能优于“夏天凉风”</h2>
<p>两个候选压缩结果都是合法缩句：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Z1 = 风吹过草原
</span></span><span style="display:flex;"><span>Z2 = 夏天凉风
</span></span></code></pre></div><p>TreeHeap 不应该由程序员硬编码选择 (Z_1)。选择必须来自数据和任务。</p>
<p>让共享 decoder 分别尝试根据两个状态解释原句或预测后续：</p>
<h1 id="lz">[
L(Z)</h1>
<p>-log P_phi(X mid Z).
]</p>
<p>如果保留 (Z_1)，decoder 仍知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>某个主体
</span></span><span style="display:flex;"><span>    -&gt; 执行动作“吹过”
</span></span><span style="display:flex;"><span>    -&gt; 作用于空间“草原”
</span></span></code></pre></div><p>如果只保留 (Z_2)，decoder 知道季节和风的性质，却丢失了事件方向与对象。</p>
<p>在大量相似语料中，如果事件骨架对恢复原句、预测后续或回答查询更有用，就会出现：</p>
<p>[
L(Z_1) &lt; L(Z_2).
]</p>
<p>梯度因此提高“风—吹过—草原”相关状态的上传概率。</p>
<p>这不是说“夏天”和“凉”永远不重要。如果后续任务询问季节，或者语料的未来主要由季节决定，最优保留内容就可能改变。</p>
<p>所谓“重要”，不是人类预先给出的绝对语义标签，而是：</p>
<blockquote>
<p>在有限上传容量下，哪部分状态能够减少更多未来误差。</p></blockquote>
<hr>
<h2 id="5-退火参数在哪里">5. 退火参数在哪里</h2>
<p>为 FOLD 增加一个可学习的上传门：</p>
<h1 id="g_d">[
g_d</h1>
<p>sigma
left(
rac{s_	heta(L,R)}{	au_d}
ight),
]</p>
<p>其中：</p>
<ul>
<li>(s_	heta) 是共享 TreeHeap kernel 计算的上传分数；</li>
<li>(d) 是当前深度；</li>
<li>(	au_d) 是温度；</li>
<li>(g_d) 决定差异中有多少进入 parent。</li>
</ul>
<p>父状态可以写成：</p>
<h1 id="u">[
U</h1>
<p>L + g_d odot A_phi(D).
]</p>
<p>训练早期温度较高，门比较柔软：</p>
<p>[
g_d in (0,1).
]</p>
<p>模型可以尝试多种上传方式。随着训练推进或深度升高，温度下降，门逐渐接近稳定选择：</p>
<p>[
g_d ightarrow 0
quad	ext{或}quad
g_d ightarrow 1.
]</p>
<p>这就是“退火”的工程含义：不是突然剪掉 token，而是让软的信息分配逐渐形成稳定协议。</p>
<hr>
<h2 id="6-容量为什么必须逐层下降">6. 容量为什么必须逐层下降</h2>
<p>如果每个 parent 都拥有无限容量，最简单的解仍然是把所有 token 原样背下来。这样不会自然产生缩句。</p>
<p>设第 (d) 层可用的信息容量为 (R_d)：</p>
<p>[
R_0 &gt; R_1 &gt; R_2 &gt; cdots &gt; R_D.
]</p>
<p>容量可以通过多种方式实现：</p>
<ul>
<li>节点数量随 FOLD 逐层减半；</li>
<li>parent 的有效激活维度受限；</li>
<li>上传门的总质量受预算约束；</li>
<li>decoder 每次只能读取固定数量的高层节点；</li>
<li>深度越高，量化位数或可用通道越少。</li>
</ul>
<p>目标不是把 root 强制变成一句话，而是让模型面对一个真实选择：</p>
<blockquote>
<p>root 装不下所有东西时，应该保留什么？</p></blockquote>
<hr>
<h2 id="7-数学上是率失真问题">7. 数学上是率失真问题</h2>
<p>令 (H_d) 是第 (d) 层可被 decoder 读取的状态。训练目标可以写成：</p>
<h1 id="mathcal-l">[
mathcal L</h1>
<p>mathbb E_d
left[
-log P_phi(X mid H_d)
+
eta_d R(H_d)
ight].
]</p>
<p>第一项是语言失真：</p>
<h1 id="d_d">[
D_d</h1>
<p>-log P_phi(X mid H_d).
]</p>
<p>第二项是信息容量或编码率：</p>
<p>[
R_d = R(H_d).
]</p>
<p>(eta_d) 随深度增加，表示高层承担更强的压缩压力。</p>
<p>这正是率失真优化：</p>
<p>[
min quad D + eta R.
]</p>
<ul>
<li>只优化 (D)：模型倾向背诵全部信息；</li>
<li>只优化 (R)：模型坍缩成无意义常量；</li>
<li>同时优化：模型寻找有限容量下最有用的表示。</li>
</ul>
<p>这里的 Loss 不一定要写成多个互相竞争的“大锅炖”目标。可以在每个样本中随机抽取一个分辨率，只计算一次 decoder Loss；长期训练的期望等价于让所有层接受不同强度的压缩考核。</p>
<hr>
<h2 id="8-encoder-与-decoder-如何形成默契">8. Encoder 与 Decoder 如何形成默契</h2>
<p>encoder 不需要输出人类定义的“主语、谓语、宾语”。</p>
<p>训练开始时：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>FOLD 不知道怎样缩句
</span></span><span style="display:flex;"><span>decoder 也不知道怎样读取 parent
</span></span></code></pre></div><p>二者接受同一个生成误差：</p>
<h2 id="hetaphi">[
(	heta,phi)
leftarrow
(	heta,phi)</h2>
<p>eta
abla_{	heta,phi}mathcal L.
]</p>
<p>如果 encoder 的某种上传方式使 decoder 更容易恢复或继续生成，Loss 就下降，这种编码方式被保留。</p>
<p>长期训练后，双方可能形成一套私有协议：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder：这种几何方向表示“事件仍在继续”
</span></span><span style="display:flex;"><span>decoder：看到这种方向时生成动作及其对象
</span></span></code></pre></div><p>人类不需要预先读懂协议。我们只需要用干预测试确认：</p>
<ul>
<li>root 是否包含样本相关信息；</li>
<li>某个 parent 是否覆盖自己的 receptive field；</li>
<li>detail 是否保存局部精度；</li>
<li>left/right 交换是否改变结果；</li>
<li>加回更多 detail 是否连续改善恢复质量。</li>
</ul>
<p>这类似一个人能够阅读自己的笔迹。重点不是旁观者是否认识每个内部符号，而是书写和阅读系统是否共同形成了稳定、可复用的压缩协议。</p>
<hr>
<h2 id="9-最小可证明-toy">9. 最小可证明 Toy</h2>
<p>在直接使用自然语言以前，可以构造一个有限数据世界。</p>
<p>每个样本由核心 (C)、细节 (N) 和未来 (Y) 组成：</p>
<p>[
X=(C,N).
]</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>核心 C：风吹草原
</span></span><span style="display:flex;"><span>细节 N：夏天、凉、一望无际、青青
</span></span><span style="display:flex;"><span>未来 Y：草浪起伏，牛羊低头
</span></span></code></pre></div><p>让数据分布满足：</p>
<p>[
P(Y mid C,N)
approx
P(Y mid C).
]</p>
<p>即未来主要由核心事件决定，修饰细节只增加表面变化。</p>
<p>当高层只能保留有限信息时，理论 Predict 是：</p>
<p>[
H(Y mid C) &lt; H(Y mid N).
]</p>
<p>因此保存核心 (C) 比保存细节 (N) 更能降低未来预测 Loss。</p>
<p>这个 Toy 不需要告诉模型“风吹草原是核心”。我们只控制数据生成规律，然后观察 TreeHeap 是否通过梯度把 (C) 传播到更高层。</p>
<hr>
<h2 id="10-下一条-claim">10. 下一条 Claim</h2>
<p>下一条正式 ARA 应围绕以下 claim 建立：</p>
<blockquote>
<p>在完整输入、逐层递减容量和共享生成 Loss 下，TreeHeap FOLD 能学习一个分辨率有序的退火协议：低层保存表面精度，高层优先保存对恢复、未来预测或查询更有贡献的结构；root 与 addressed detail 共同形成连续率失真曲线。</p></blockquote>
<p>这个 claim 必须拆成可测量 Predict。</p>
<h3 id="p1分辨率有序">P1：分辨率有序</h3>
<p>从叶子到 root，原句精确恢复能力允许下降，但不能无规律跳动：</p>
<p>[
D_0 le D_1 le cdots le D_D.
]</p>
<h3 id="p2预测信息存活">P2：预测信息存活</h3>
<p>虽然 token 精度下降，高层对未来 (Y) 的预测必须明显优于同容量随机压缩。</p>
<h3 id="p3核心优先">P3：核心优先</h3>
<p>在有限 Toy 中，清除核心事件对高层 Loss 的伤害，应显著大于清除表面修饰。</p>
<h3 id="p4root-因果性">P4：root 因果性</h3>
<p>root shuffle 或 root zero 必须造成注册阈值以上的损失，不能再次出现仅 (+0.0042) 的结果。</p>
<h3 id="p5detail-分辨率">P5：detail 分辨率</h3>
<p>逐层加回 detail 时，恢复质量应形成单调改善曲线：</p>
<p>[
D(root)
ge
D(root+D_{top})
ge
cdots
ge
D(H_{	ext{state}}).
]</p>
<h3 id="p6地址因果性">P6：地址因果性</h3>
<p>交换 left/right、移动 detail 地址或破坏 parent-child 配对，应造成可重复损失。</p>
<h3 id="p7不是普通池化">P7：不是普通池化</h3>
<p>相同容量的均值池化、随机投影、flat bottleneck 和普通 RNN/Transformer bottleneck 必须作为对照。否则不能把一般的信息瓶颈效果归因于 TreeHeap。</p>
<hr>
<h2 id="11-什么还没有被证明">11. 什么还没有被证明</h2>
<p>截至本文，以下内容仍然只是新假设：</p>
<ul>
<li>TreeHeap 会自然产生人类可读的缩句；</li>
<li>root 会自动表示句子核心；</li>
<li>高层一定对应主谓宾或事件图；</li>
<li>退火协议一定优于 Transformer；</li>
<li>这种结构已经形成意识；</li>
<li>率失真最优解在自然语言中是唯一的。</li>
</ul>
<p>我们已经知道的是：</p>
<ul>
<li>lifting TreeHeap 可以严格闭合；</li>
<li>WMT decoder 能因果使用多个 detail 深度；</li>
<li>learned update 比固定 update 更好；</li>
<li>单 token Mask 会产生强烈课程单一化；</li>
<li>多尺度 subheap Mask 训练出了 source/detail-dependent generation；</li>
<li>当前模型仍未让 root 与左右地址变得足够因果。</li>
</ul>
<p>SPR-060 的作用，是针对最后一个障碍提出新的机制解释和实验方向。</p>
<hr>
<h2 id="12-下次从哪里继续">12. 下次从哪里继续</h2>
<p>下次恢复研究时，不要再从“怎样设计一个更复杂的 Mask”开始。</p>
<p>直接读取本文，然后从下面的数据流继续：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整过去或完整句子
</span></span><span style="display:flex;"><span>    -&gt; token WRITE
</span></span><span style="display:flex;"><span>    -&gt; 可学习 lifting FOLD
</span></span><span style="display:flex;"><span>    -&gt; 深度递增、容量递减、温度下降
</span></span><span style="display:flex;"><span>    -&gt; parent 保存粗轮廓
</span></span><span style="display:flex;"><span>    -&gt; detail 保存局部精度
</span></span><span style="display:flex;"><span>    -&gt; 随机选择一个分辨率
</span></span><span style="display:flex;"><span>    -&gt; 共享 decoder 做恢复或未来生成
</span></span><span style="display:flex;"><span>    -&gt; Loss 同时训练 encoder 与 decoder 的私有协议
</span></span></code></pre></div><p>第一轮 Proof 应先在可控 Toy 上回答：</p>
<blockquote>
<p>当未来确实由“风吹草原”决定，而与“夏天、凉、青青”弱相关时，TreeHeap 是否会把前者传播得更高？</p></blockquote>
<p>通过后，再把同一机制放到 NAS 真实语料，观察不同深度的恢复、未来预测、root 因果性和率失真曲线。</p>
<p>这是当前保存的航行位置。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-061] TreeHeap 损伤后的生长：从消融因果走向跨分辨率修复</title>
      <link>https://www.grepcode.cn/spr/061-treeheap-damage-repair-growth.html</link>
      <pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/061-treeheap-damage-repair-growth.html</guid>
      <description>撤回“高层自然保存可读缩句”的理想化解释，区分信息因果性与损伤修复能力，并提出 TreeHeap 的跨分辨率修复假设：局部状态缺失后，由剩余 root、detail、地址和世界模型形成概率容器，递归生成与整体一致的细节。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-损伤后的生长从消融因果走向跨分辨率修复">TreeHeap 损伤后的生长：从消融因果走向跨分辨率修复</h1>
<p>SPR-060 提出了一个直观例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>夏天的凉风吹过一望无际的青青草原
</span></span><span style="display:flex;"><span>→ 夏天的凉风吹过草原
</span></span><span style="display:flex;"><span>→ 风吹过草原
</span></span></code></pre></div><p>这个例子帮助我们想象“分辨率逐层降低”，但它也悄悄越过了证据边界：它把不可读的内部向量理想化成了人类可读的缩句。</p>
<p>Houming818 对此持保留意见。当前实验只证明了高层状态可以参与未来预测，没有证明高层真的保存了“风吹过草原”这样的语言轮廓。</p>
<p>这次讨论带来了更重要的修正：</p>
<blockquote>
<p>TreeHeap 的目标不应只是证明 root 或 detail 保存了信息，而应研究：当部分信息自然缺失时，剩余的多分辨率结构能否约束缺失部分，使它重新生长出来。</p></blockquote>
<p>本文先记录这一思想，不把它冒充成已经成立的实验结论。文末给出供评审的 ARA、Predict 和 Proof 草案；正式实验将在理论口径确认后再启动。</p>
<hr>
<h2 id="1-守夜实验到底证明了什么">1. 守夜实验到底证明了什么</h2>
<p>上一轮守夜实验使用完整的 64 token 中文历史预测后续 16 token，没有先做 Mask。相同模型分别采用三种分辨率训练课程：</p>
<table>
  <thead>
      <tr>
          <th>训练方式</th>
          <th style="text-align: right">root NLL</th>
          <th style="text-align: right">leaf NLL</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>只训练叶层</td>
          <td style="text-align: right">35.8732</td>
          <td style="text-align: right">5.3615</td>
          <td>信息不会自动上传，root 被模型放弃</td>
      </tr>
      <tr>
          <td>均匀训练七个深度</td>
          <td style="text-align: right">5.7158</td>
          <td style="text-align: right">5.4870</td>
          <td>所有分辨率都可以获得预测能力</td>
      </tr>
      <tr>
          <td>由叶向 root 退火</td>
          <td style="text-align: right"><strong>5.6240</strong></td>
          <td style="text-align: right">5.5624</td>
          <td>退火使 root 比均匀训练改善 0.0918</td>
      </tr>
  </tbody>
</table>
<p>退火模型的 root 与 leaf 只相差 0.0603 NLL，七个分辨率的 NLL 与深度呈有序关系，Spearman 相关系数为 -0.75。</p>
<p>这支持一个有限结论：</p>
<blockquote>
<p>在容量逐层收窄的 TreeHeap 中，训练压力能够使较高层状态获得未来预测能力。</p></blockquote>
<p>但结构审计没有通过：</p>
<table>
  <thead>
      <tr>
          <th>干预</th>
          <th style="text-align: right">root NLL 变化</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>用其他样本替换 source</td>
          <td style="text-align: right">+0.0852</td>
      </tr>
      <tr>
          <td>FOLD 前交换相邻左右孩子</td>
          <td style="text-align: right">-0.0011</td>
      </tr>
  </tbody>
</table>
<p>这意味着当前 root 可能主要保存语料平均统计、主题或常见后续，而不是这一个样本的具体关系。它还不能被解释成一条“内部缩句”。</p>
<p>受控 Toy 中，未来由三个核心 token 决定，另外十三个 token 是独立噪声。TreeHeap 确实能把核心信息抽进 root：打乱核心造成超过 16 NLL 的损失，打乱噪声几乎没有影响。不过 mean pooling 也能完成任务，所以这还不是 TreeHeap 特有的胜利。</p>
<hr>
<h2 id="2-第一处修正上层状态不等于缩句">2. 第一处修正：上层状态不等于缩句</h2>
<p>我们不再假设：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root = 风吹过草原
</span></span></code></pre></div><p>更严谨的说法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>叶层：容量较大，包含较多局部状态
</span></span><span style="display:flex;"><span>高层：容量较小，但仍包含某些预测信息
</span></span><span style="display:flex;"><span>root：一个不可读的低分辨率状态
</span></span></code></pre></div><p>root 可能包含事件轮廓，也可能包含主题、文体、词频偏置或其他统计捷径。内部编码可以是 encoder 与 decoder 共同形成的私有协议，人类不一定能直接翻译成一句话。</p>
<p>因此，“高层 NLL 较低”只能证明高层可用于预测，不能单独证明高层理解了句子。</p>
<hr>
<h2 id="3-第二处修正当前抽水机没有内容级价值判断">3. 第二处修正：当前抽水机没有内容级价值判断</h2>
<p>当前退火实验只调度“在哪个深度读取”：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>训练早期：更多读取叶层
</span></span><span style="display:flex;"><span>训练后期：更多读取高层
</span></span></code></pre></div><p>它没有在一次 FOLD 内判断：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>保留左边？
</span></span><span style="display:flex;"><span>保留右边？
</span></span><span style="display:flex;"><span>保留二者关系？
</span></span><span style="display:flex;"><span>上传当前轮廓？
</span></span><span style="display:flex;"><span>把什么留在 detail？
</span></span></code></pre></div><p>Houming818 从自我观察提出了另一种可能：</p>
<blockquote>
<p>回溯一个句子或一个刹那时，意识可能先出现一个相关性最高的轮廓，然后围绕这个轮廓构造细节。它不是机械地抽取“必然信息”，而是在当前背景下判断什么最重要。</p></blockquote>
<p>若把这个猜想转换成数学语言，每个局部节点应产生一个价值概率桶。设当前查询或背景为 $q$，局部状态为 $H_{\text{local}}$，候选处理方式为 $a$：</p>
$$ s_a=K_\theta(q,H_{\text{local}},a). $$$$ p(a)=\operatorname{softmax}\left(\frac{s_a}{\tau}\right). $$<p>候选 $a$ 可以包括保留左侧、保留右侧、合成关系、停止收缩等操作。训练阶段先保持软分布：</p>
$$ H_{\text{parent}}=\sum_a p(a)\,T_a(H_{\text{local}}). $$<p>温度下降以后，分布才可能接近：</p>
$$ a^*=\arg\max_a s_a. $$<p>这里的“重要”不是人工语法标签，而是反事实价值：</p>
$$ V(a)=\mathcal L_{\text{without }a}-\mathcal L_{\text{with }a}. $$<p>去掉某部分后任务 Loss 增加得越多，它在当前背景下的上传价值越高。</p>
<p>但必须明确：现有实验没有实现也没有证明这个内容级 argmax。它只是下一阶段可能需要的机制。</p>
<hr>
<h2 id="4-从分形观察到的不是外形而是损伤后的恢复">4. 从分形观察到的不是外形，而是损伤后的恢复</h2>
<p>本文不打算把分形公式设计进 TreeHeap。</p>
<p>我们只是观察分形压缩和自相似生成表现出的一种能力：系统不保存每一个细节，而保存能够约束细节的规律；观察分辨率降低以后，整体形态仍然存在，需要时可以从规则递归展开。</p>
<p>严格来说，数学分形本身不等于可损压缩。这里借用的是“分形压缩与跨尺度重建”的能力类比，而不是宣称 TreeHeap 已经是分形。</p>
<p>这个类比把研究问题从：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>拿掉一个节点，Loss 增加多少？
</span></span></code></pre></div><p>推进为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>拿掉一个节点以后，
</span></span><span style="display:flex;"><span>TreeHeap 能否根据其他尺度和位置重新生成它？
</span></span></code></pre></div><p>这是两个完全不同的问题。</p>
<hr>
<h2 id="5-因果消融为什么不等于修复能力">5. 因果消融为什么不等于修复能力</h2>
<p>当前审计采用：</p>
$$ \Delta L_{\text{ablation}}=L_{\text{damaged}}-L_{\text{clean}}. $$<p>若 $\Delta L$ 很大，我们知道模型依赖被消融状态。但这也可能意味着系统非常脆弱：一个节点损坏，整体立刻失效。</p>
<p>若 $\Delta L$ 很小，也有两种解释：</p>
<ol>
<li>模型从未使用这个节点；</li>
<li>其他节点包含冗余，能够替代它。</li>
</ol>
<p>只看消融损失无法区分二者。</p>
<p>因此下一阶段必须把三个状态分开：</p>
$$ L_{\text{clean}},\qquad L_{\text{damaged}},\qquad L_{\text{repaired}}. $$<ul>
<li>$L_{\text{clean}}$：完整 TreeHeap 的任务损失；</li>
<li>$L_{\text{damaged}}$：破坏局部状态后、尚未修复的损失；</li>
<li>$L_{\text{repaired}}$：运行修复 kernel 后的损失。</li>
</ul>
<p>定义修复率：</p>
$$ \rho=\frac{L_{\text{damaged}}-L_{\text{repaired}}}{L_{\text{damaged}}-L_{\text{clean}}+\epsilon}. $$<table>
  <thead>
      <tr>
          <th style="text-align: right">修复率</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">$\rho=0$</td>
          <td>没有修回任何损失</td>
      </tr>
      <tr>
          <td style="text-align: right">$\rho=0.5$</td>
          <td>修复了一半损失</td>
      </tr>
      <tr>
          <td style="text-align: right">$\rho=1$</td>
          <td>回到完整状态的任务水平</td>
      </tr>
  </tbody>
</table>
<p>这条曲线才是“可损后生长”的直接评价。</p>
<hr>
<h2 id="6-treeheap-可以怎样重新长出-detail">6. TreeHeap 可以怎样重新长出 detail</h2>
<p>现有 learned lifting FOLD 写成：</p>
$$ D=R-P_\theta(L). $$$$ U=L+A_\phi(D). $$<p>其中 $U$ 是上传的粗状态，$D$ 是留在当前地址的 detail。完整的 root 与所有 addressed detail 仍然构成闭合的 $H_{\text{state}}$。</p>
<p>当某个 detail 损坏时，旧做法是清零并直接观察 Loss。新的做法需要先预测缺失残差：</p>
$$ \hat D=G_\psi\left(U,\,H_{\text{sibling}},\,\text{path},\,W\right). $$<p>其中：</p>
<ul>
<li>$U$ 提供更高层轮廓；</li>
<li>sibling 提供同一局部的横向约束；</li>
<li>path 告诉模型缺失发生在什么地址；</li>
<li>$W$ 是已学习的世界模型或上下文状态；</li>
<li>$G_\psi$ 是共享的 repair kernel。</li>
</ul>
<p>随后执行 UNFOLD：</p>
$$ (\hat L,\hat R)=\operatorname{UNFOLD}(U,\hat D). $$<p>如果更低层仍有缺损，同一个过程继续递归：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>剩余 root / parent
</span></span><span style="display:flex;"><span>    → 预测当前缺失 detail
</span></span><span style="display:flex;"><span>    → 恢复左右孩子的概率状态
</span></span><span style="display:flex;"><span>    → 继续向更低层展开
</span></span><span style="display:flex;"><span>    → 得到修复后的 H_state
</span></span><span style="display:flex;"><span>    → decoder 继续生成
</span></span></code></pre></div><p>这里真正重要的不是 root 能不能翻译成一句缩句，而是 root 能不能成为修复过程的低分辨率边界条件。</p>
<hr>
<h2 id="7-修复不一定等于逐-token-复原">7. 修复不一定等于逐 token 复原</h2>
<p>假设原句是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>夏天的凉风吹过草原
</span></span></code></pre></div><p>如果“凉”已经完全丢失，仅凭剩余信息不能确定原文一定是“凉风”。它也可能是“微风”或“晚风”。</p>
<p>因此真实语言中的 repair kernel 不应该假装自己永远知道唯一答案，而应输出概率容器：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>凉风  0.42
</span></span><span style="display:flex;"><span>微风  0.31
</span></span><span style="display:flex;"><span>晚风  0.09
</span></span><span style="display:flex;"><span>其他  0.18
</span></span></code></pre></div><p>这对应两种不同的 Proof 口径。</p>
<h3 id="71-有确定冗余的有限-toy">7.1 有确定冗余的有限 Toy</h3>
<p>数据生成规则保证缺失信息能由其他尺度唯一推出。此时可以要求 exact recovery。</p>
<h3 id="72-真实语言">7.2 真实语言</h3>
<p>信息可能不可逆地丢失。此时应评价：</p>
<ul>
<li>原 token 的 NLL 是否下降；</li>
<li>事件和关系是否保持一致；</li>
<li>修复分布是否校准；</li>
<li>后续生成能力是否恢复；</li>
<li>损伤逐渐扩大时，质量是否平滑下降。</li>
</ul>
<p>TreeHeap 修复的是“与剩余结构一致的可能细节”，不一定是历史上唯一发生过的原始字符串。</p>
<hr>
<h2 id="8-哲学上的不完整与生长">8. 哲学上的不完整与生长</h2>
<p>Houming818 提出了本文的哲学背景：</p>
<blockquote>
<p>如何知道此刻的意识是完整的？也许下一刻要说的话，就是一种自然缺失的生长。因为自我的不完整，才有意识的波澜心生。</p></blockquote>
<p>这不是意识已经被 TreeHeap 证明的科学结论，但它准确地区分了两种生成观。</p>
<p>第一种生成观认为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>完整答案已经存在
</span></span><span style="display:flex;"><span>语言只是把它逐字读出来
</span></span></code></pre></div><p>第二种生成观认为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前只有不完整状态、记忆轮廓和世界约束
</span></span><span style="display:flex;"><span>下一刻是在这些约束下生长出来
</span></span></code></pre></div><p>在第二种观点中，自我的连续性不一定来自全部细节始终在线，也可能来自一个稳定的修复协议：记忆、身体、语言和环境不断互相校验，使不完整状态能够继续生成自己。</p>
<p>但缺失本身不会自动产生意识。真正值得研究的是，系统能否：</p>
<ol>
<li>表达“这里存在不确定性”；</li>
<li>保留多个可能，而不是过早假装确定；</li>
<li>从不同分辨率寻找约束；</li>
<li>用外部反馈修正修复结果；</li>
<li>让修复后的状态继续参与下一轮生成。</li>
</ol>
<p>概率容器因此不只是 Beam Search 技巧，而是系统对自身不完整性的诚实表达。</p>
<hr>
<h2 id="9-对抽水机的重新定义">9. 对抽水机的重新定义</h2>
<p>SPR-060 的抽水机可以概括为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>FOLD：让预测信息到达高层
</span></span><span style="display:flex;"><span>detail：保存没有上传的局部精度
</span></span><span style="display:flex;"><span>UNFOLD：读取已经保存的细节
</span></span></code></pre></div><p>SPR-061 提议把它扩展为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>FOLD
</span></span><span style="display:flex;"><span>    → 形成跨尺度轮廓与 addressed residual
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>DAMAGE
</span></span><span style="display:flex;"><span>    → root、detail 或 subheap 局部缺失
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>REPAIR
</span></span><span style="display:flex;"><span>    → 用剩余尺度、地址、世界模型形成缺失状态的概率桶
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>UNFOLD
</span></span><span style="display:flex;"><span>    → 按概率递归展开细节
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>FEEDBACK
</span></span><span style="display:flex;"><span>    → 用任务 Loss 与世界反馈修正 repair kernel
</span></span></code></pre></div><p>这并不要求高层保存可读摘要。它要求信息以跨尺度、相互约束的方式分布，使局部损坏不会立刻摧毁整体功能。</p>
<hr>
<h2 id="10-待评审的-claim">10. 待评审的 Claim</h2>
<p>下一条 ARA 可以围绕以下主张建立：</p>
<blockquote>
<p><strong>在存在可学习跨尺度规律的数据中，TreeHeap 的 root、addressed detail、sibling 与 path 能形成联合修复条件；局部状态受损后，共享 repair kernel 能递归恢复显著比例的任务损失，并随着损伤扩大呈现平滑的分辨率退化，而不是立即失效。</strong></p></blockquote>
<p>这条 Claim 不声称：</p>
<ul>
<li>修复结果必然逐 token 等于原文；</li>
<li>root 是人类可读缩句；</li>
<li>TreeHeap 已经具有意识；</li>
<li>任何随机数据都可以被修复；</li>
<li>分形数学已经成为 TreeHeap 的代数定义。</li>
</ul>
<p>它只研究一个可证伪问题：TreeHeap 的多分辨率结构是否能提供普通单点消融之外的损伤修复能力。</p>
<hr>
<h2 id="11-待评审的-predict">11. 待评审的 Predict</h2>
<h3 id="p1损伤必须真实发生">P1：损伤必须真实发生</h3>
<p>破坏目标 subheap 后，必须满足：</p>
$$ L_{\text{damaged}}>L_{\text{clean}}. $$<p>否则可能只是模型从未使用该位置，不能称为修复。</p>
<h3 id="p2修复必须带来收益">P2：修复必须带来收益</h3>
<p>运行 repair kernel 后：</p>
$$ L_{\text{repaired}}\lt L_{\text{damaged}}. $$<p>并预注册最低修复率 $\rho$。</p>
<h3 id="p3修复必须使用跨尺度信息">P3：修复必须使用跨尺度信息</h3>
<p>分别消融 root、sibling、path 和世界上下文。完整修复条件应优于只看同层邻居的基线。</p>
<h3 id="p4地址必须有贡献">P4：地址必须有贡献</h3>
<p>使用错误 path 或交换 sibling 地址后，修复质量应下降。否则 repair kernel 仍然可能退化成无序 Bag 补全。</p>
<h3 id="p5退化必须平滑">P5：退化必须平滑</h3>
<p>随着损伤范围从一个 detail 扩大到一个 subheap，再扩大到多个深度，质量应逐渐下降，而不是在某个很小损伤下突然崩溃。</p>
<h3 id="p6歧义必须被概率表达">P6：歧义必须被概率表达</h3>
<p>对于不能唯一复原的真实语言，正确候选应获得更高概率，但模型不应伪造接近 1.0 的确定性。需要评价 NLL、校准误差和候选覆盖率。</p>
<h3 id="p7必须对比非-treeheap-修复">P7：必须对比非 TreeHeap 修复</h3>
<p>至少比较：</p>
<ul>
<li>均值池化状态；</li>
<li>flat bottleneck；</li>
<li>只看左右窗口的 MLP；</li>
<li>相同参数量的序列修复模型；</li>
<li>不使用 path 的 TreeHeap ablation。</li>
</ul>
<p>否则只能证明一般生成模型会补全，不能证明 TreeHeap 的跨尺度结构提供了额外条件。</p>
<hr>
<h2 id="12-proof-应该分成两级">12. Proof 应该分成两级</h2>
<h3 id="proof-a有限可恢复世界">Proof A：有限可恢复世界</h3>
<p>构造一个确实存在跨尺度冗余的 Toy。缺失内容由 parent、sibling 和 path 联合决定，任何单一来源都不足以恢复。</p>
<p>这个 Toy 首先回答数学问题：</p>
<blockquote>
<p>当恢复所需规律确实存在时，共享 TreeHeap repair kernel 能否从窄深度学习，并递归外推到更深的树？</p></blockquote>
<p>必须加入 lookup table、flat MLP 和不带地址的基线，防止把答案直接写进特征。</p>
<h3 id="proof-b真实中文损伤修复">Proof B：真实中文损伤修复</h3>
<p>使用完整真实句子写入 TreeHeap，再对内部状态而不是原始字符串施加损伤：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>detail erasure
</span></span><span style="display:flex;"><span>subheap erasure
</span></span><span style="display:flex;"><span>single-depth erasure
</span></span><span style="display:flex;"><span>cross-depth burst damage
</span></span><span style="display:flex;"><span>wrong-address transplantation
</span></span></code></pre></div><p>先测受损 NLL，再运行有限轮数的 repair kernel，最后测修复 NLL、生成质量和概率校准。</p>
<p>真实实验不要求还原唯一原句，而要求恢复与剩余上下文一致的语言能力，并比较不同损伤强度下的修复曲线。</p>
<hr>
<h2 id="13-当前航行位置">13. 当前航行位置</h2>
<p>截至本文，证据支持的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>分辨率训练
</span></span><span style="display:flex;"><span>    → 高层获得预测能力
</span></span></code></pre></div><p>尚未支持的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>内容级价值竞争
</span></span><span style="display:flex;"><span>    → 重要关系被选择性上传
</span></span><span style="display:flex;"><span>    → 跨尺度状态相互约束
</span></span><span style="display:flex;"><span>    → 局部损伤后递归修复
</span></span></code></pre></div><p>因此下一步不应继续只比较 root zero 或 detail zero 的一次性 Loss。消融仍然必要，但它只负责确认“损伤真实发生”。核心指标必须变成：</p>
$$ \text{Damage}\rightarrow\text{Repair}\rightarrow\text{Recovered capability}. $$<p>TreeHeap 真正值得追求的，也许不是一个永不缺失的完美容器，而是一种能够在缺失中继续生长的结构。</p>
<p>这就是 SPR-061 保存的新研究起点。</p>
<hr>
<h2 id="参考线索">参考线索</h2>
<ul>
<li>Stéphane Mallat, <em>A Theory for Multiresolution Signal Decomposition: The Wavelet Representation</em>, 1989：多分辨率近似与尺度之间的 detail 分解。</li>
<li>Michael Barnsley 等关于 Iterated Function Systems 的工作：用生成变换描述复杂图像，并从规则迭代重建。本文只借用能力类比，不据此宣称 TreeHeap 是分形。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-062] 如何读懂 TreeHeap 实验：从 NLL、Loss 到因果干预和统计证据</title>
      <link>https://www.grepcode.cn/spr/062-how-to-read-treeheap-metrics.html</link>
      <pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/062-how-to-read-treeheap-metrics.html</guid>
      <description>面向本科读者的 TreeHeap 实验指标说明书：解释 NLL、交叉熵、困惑度、MSE、余弦距离、KL 散度、准确率、BLEU、消融损失、修复率、置信区间等数字究竟在测量什么，以及它们不能证明什么。</description>
      <content:encoded><![CDATA[<h1 id="如何读懂-treeheap-实验从-nllloss-到因果干预和统计证据">如何读懂 TreeHeap 实验：从 NLL、Loss 到因果干预和统计证据</h1>
<p>TreeHeap 的博客里经常出现这样的句子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>NLL 从 16.16 降到 5.69
</span></span><span style="display:flex;"><span>source shuffle damage = +0.21
</span></span><span style="display:flex;"><span>修复了 72.38% 的 MSE
</span></span><span style="display:flex;"><span>top-1 = 0.91
</span></span><span style="display:flex;"><span>bootstrap 95% CI 跨过了 0
</span></span></code></pre></div><p>熟悉机器学习的人会迅速把它们归入不同抽屉，但许多读者只会看到一排小数。更麻烦的是，这些数字的方向并不统一：NLL 越小越好，准确率越大越好；干预损失通常越大，越能说明被干预部分有因果作用；而 MSE 很小，也可能只是状态本来就接近零。</p>
<p>本文是 TreeHeap 研究的公共“体检指标说明书”。它不提出新的架构 Claim，只回答四个问题：</p>
<ol>
<li>这个数字是怎样算出来的？</li>
<li>它变大或变小通常意味着什么？</li>
<li>它能支持哪一级结论？</li>
<li>它不能证明什么？</li>
</ol>
<hr>
<h2 id="1-先区分三种东西lossmetric-和-evidence">1. 先区分三种东西：Loss、Metric 和 Evidence</h2>
<p>这三个词经常混在一起，但职责不同。</p>
<h3 id="11-loss给梯度看的训练信号">1.1 Loss：给梯度看的训练信号</h3>
<p>模型有参数 $\theta$，输入为 $x$，目标为 $y$。训练先计算：</p>
$$ L(\theta;x,y), $$<p>再用梯度下降更新参数：</p>
$$ \theta \leftarrow \theta-\eta\nabla_\theta L. $$<p>Loss 的首要任务不是方便人阅读，而是告诉参数应该向哪个方向移动。例如语言模型常用交叉熵，状态修复常用 MSE。</p>
<h3 id="12-metric给人看的功能测量">1.2 Metric：给人看的功能测量</h3>
<p>Metric 不一定参与训练。例如：</p>
<ul>
<li>top-1 准确率；</li>
<li>整句完全还原率；</li>
<li>BLEU；</li>
<li>自由生成的重复率；</li>
<li>每秒处理 token 数。</li>
</ul>
<p>它们回答“系统表现如何”，但不一定能够产生适合训练的梯度。</p>
<h3 id="13-evidenceclaim-与对照实验共同形成的证据">1.3 Evidence：Claim 与对照实验共同形成的证据</h3>
<p>单个数字通常不是 Evidence。比如测试 NLL 为 <code>5.0</code>，没有基线就不知道好坏；训练 NLL 下降，也可能只是记住了训练集。</p>
<p>ARA 所说的 Evidence 至少需要：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>预先声明的 Claim
</span></span><span style="display:flex;"><span>+ Predict（若 Claim 成立，应该观察到什么）
</span></span><span style="display:flex;"><span>+ 对照或干预
</span></span><span style="display:flex;"><span>+ 测量指标
</span></span><span style="display:flex;"><span>+ 可证伪门槛
</span></span><span style="display:flex;"><span>+ 可复查的输出文件
</span></span></code></pre></div><p>因此，<code>NLL=5.0</code> 是一个测量值；“打乱 source 后 NLL 增加 1.2，并在三个 seed 重现”才开始构成“模型使用了 source”的证据。</p>
<hr>
<h2 id="2-概率桶nll-从哪里来">2. 概率桶：NLL 从哪里来</h2>
<p>假设 decoder 下一步要预测一个 token。词表里有“我、喜欢、米饭、天气”等许多候选，模型输出一个概率桶：</p>
<table>
  <thead>
      <tr>
          <th>候选 token</th>
          <th style="text-align: right">模型概率</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>米饭</td>
          <td style="text-align: right">0.50</td>
      </tr>
      <tr>
          <td>面条</td>
          <td style="text-align: right">0.20</td>
      </tr>
      <tr>
          <td>苹果</td>
          <td style="text-align: right">0.10</td>
      </tr>
      <tr>
          <td>天气</td>
          <td style="text-align: right">0.01</td>
      </tr>
      <tr>
          <td>其他 token 合计</td>
          <td style="text-align: right">0.19</td>
      </tr>
  </tbody>
</table>
<p>如果正确答案是“米饭”，模型给正确答案的概率是 $0.50$。如果正确答案是“天气”，正确答案概率只有 $0.01$。</p>
<p>我们希望正确答案概率越大越好。但直接连乘长句中所有正确 token 的概率，很快会变成接近零的小数：</p>
$$ P(y_1,y_2,\ldots,y_T\mid x) =\prod_{t=1}^{T}P(y_t\mid y_{\lt t},x). $$<p>对数把乘法变成加法：</p>
$$ \log P(y\mid x) =\sum_{t=1}^{T}\log P(y_t\mid y_{\lt t},x). $$<p>因为概率不超过 1，其对数不大于 0。为了得到一个“越小越好”的正数，我们取负号，这就是负对数似然：</p>
$$ \operatorname{NLL} =-\frac{1}{T}\sum_{t=1}^{T}\log P(y_t\mid y_{\lt t},x). $$<p>其中 <code>NLL</code> 是 <strong>Negative Log-Likelihood</strong>，中文通常叫“负对数似然”。</p>
<hr>
<h2 id="3-一个可以手算的-nll-例子">3. 一个可以手算的 NLL 例子</h2>
<p>句子有三个正确 token，模型分别给出概率：</p>
$$ 0.5,\quad 0.25,\quad 0.1. $$<p>采用自然对数时：</p>
$$ \operatorname{NLL} =-\frac{\ln 0.5+\ln 0.25+\ln 0.1}{3} \approx 1.462. $$<p>如果改进后的模型给出：</p>
$$ 0.8,\quad 0.6,\quad 0.4, $$<p>则：</p>
$$ \operatorname{NLL}\approx 0.551. $$<p>第二个模型给正确 token 的概率整体更高，所以 NLL 更低。</p>
<h3 id="nll-的阅读方向">NLL 的阅读方向</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0                 理想极限：正确答案概率为 1
</span></span><span style="display:flex;"><span>越小              通常越好
</span></span><span style="display:flex;"><span>越大              模型越不相信正确答案
</span></span><span style="display:flex;"><span>无穷大            给正确答案的概率趋近于 0
</span></span></code></pre></div><p>但 NLL <strong>不是百分制</strong>。<code>5.0</code> 不能读成“模型只对了 5%”，<code>5.0 -&gt; 4.9</code> 也不能直接读成“提升 2%”。</p>
<hr>
<h2 id="4-交叉熵nll-和-teacher-forcing">4. 交叉熵、NLL 和 Teacher Forcing</h2>
<p>在 one-hot 正确标签下，分类交叉熵为：</p>
$$ H(p,q)=-\sum_i p_i\log q_i. $$<p>正确分布 $p$ 只有正确 token 那一项为 1，于是它化简为：</p>
$$ H(p,q)=-\log q_{\text{correct}}. $$<p>因此，在我们当前的 token 预测实验中，“cross-entropy loss”和“平均 token NLL”通常是同一个量的两种说法。</p>
<p>训练时经常采用 <strong>Teacher Forcing</strong>：预测第 $t$ 个 token 时，decoder 能看到真实的前 $t-1$ 个 token，而不是自己刚才可能预测错的内容。</p>
<p>这让训练稳定，却产生一个重要边界：</p>
<blockquote>
<p>Teacher-forced NLL 很低，只说明“给定正确历史时，模型能给正确下一词较高概率”；不保证自由生成时不会一步错、步步错。</p></blockquote>
<p>所以我们必须同时查看 held-out NLL 和 free generation 样例。</p>
<hr>
<h2 id="5-困惑度-ppl把-nll-换回更直观的尺度">5. 困惑度 PPL：把 NLL 换回更直观的尺度</h2>
<p>困惑度（Perplexity，PPL）定义为：</p>
$$ \operatorname{PPL}=\exp(\operatorname{NLL}). $$<p>它可以粗略理解为：模型每一步仿佛在多少个同等可能的候选之间犹豫。</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">NLL</th>
          <th style="text-align: right">PPL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0.0</td>
          <td style="text-align: right">1.00</td>
      </tr>
      <tr>
          <td style="text-align: right">1.0</td>
          <td style="text-align: right">2.72</td>
      </tr>
      <tr>
          <td style="text-align: right">2.0</td>
          <td style="text-align: right">7.39</td>
      </tr>
      <tr>
          <td style="text-align: right">5.0</td>
          <td style="text-align: right">148.41</td>
      </tr>
      <tr>
          <td style="text-align: right">6.0</td>
          <td style="text-align: right">403.43</td>
      </tr>
  </tbody>
</table>
<p>PPL 也越低越好。但它仍受词表、分词器、语言和数据集影响。使用不同 SentencePiece 词表的两个实验，不能只凭 PPL 大小直接判胜负。</p>
<hr>
<h2 id="6-为什么训练-nll-下降还不够">6. 为什么训练 NLL 下降还不够</h2>
<p>一次训练通常至少有三条曲线：</p>
<table>
  <thead>
      <tr>
          <th>曲线</th>
          <th>数据</th>
          <th>用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>train NLL</td>
          <td>训练批次</td>
          <td>判断优化是否在工作</td>
      </tr>
      <tr>
          <td>validation NLL</td>
          <td>未参与参数更新的数据</td>
          <td>观察泛化和选择 checkpoint</td>
      </tr>
      <tr>
          <td>test NLL</td>
          <td>最终保留数据</td>
          <td>最后一次无偏报告</td>
      </tr>
  </tbody>
</table>
<p>可能出现四种典型情况：</p>
<ol>
<li>train 和 validation 一起下降：正常学习；</li>
<li>train 下降，validation 上升：过拟合；</li>
<li>两者都不下降：优化、容量或数据管线可能有问题；</li>
<li>数值骤然变成 NaN：训练发生数值崩溃。</li>
</ol>
<p>当前全量任务早期出现的 <code>16.16 -&gt; 5.69</code> 是 <strong>不同训练 batch 的即时 NLL</strong>。它值得期待，因为优化链路在工作；但它不是最终结论，因为 batch 难度不同，也尚未经过固定 held-out 集评估。</p>
<hr>
<h2 id="7-accuracytop-k-和整句-exact">7. Accuracy、top-k 和整句 Exact</h2>
<h3 id="71-top-1-accuracy">7.1 top-1 accuracy</h3>
<p>概率最高的 token 正好是真实 token，就算正确：</p>
$$ \operatorname{top1}=\frac{\text{预测第一名正确的 token 数}}{\text{总 token 数}}. $$<p>越高越好。它直观，但忽略概率质量：正确答案概率 <code>0.51</code> 和 <code>0.99</code> 都只记 1 分。</p>
<h3 id="72-top-k-accuracy">7.2 top-k accuracy</h3>
<p>只要真实 token 出现在概率最高的前 $k$ 个候选中，就算命中。TreeHeap 实验常报告 top-5，用来判断正确答案是否已进入概率桶的前列。</p>
<h3 id="73-sequence-exact--block-exact">7.3 sequence exact / block exact</h3>
<p>只有一整句或一个 block 的全部 token 都正确，才记 1：</p>
$$ \operatorname{exact}=\frac{\text{完全正确的序列数}}{\text{总序列数}}. $$<p>它非常严格。假设每个 token 独立正确率为 $0.99$，64 token 全对的概率也只有：</p>
$$ 0.99^{64}\approx 0.526. $$<p>因此可能出现 token top-1 很高、sequence exact 仍明显较低的情况。</p>
<hr>
<h2 id="8-bleu生成结果与参考文本有多像">8. BLEU：生成结果与参考文本有多像</h2>
<p>BLEU 比较生成文本与参考文本的 n-gram 重合，并加入长度惩罚。我们曾使用 token-BLEU4 比较翻译输出。</p>
<p>BLEU 越高，通常表示词组重合越多。但它有三个限制：</p>
<ol>
<li>合理答案可能与唯一参考答案措辞不同；</li>
<li>词面重合不等于事实正确；</li>
<li>很短的句子会使 BLEU 不稳定。</li>
</ol>
<p>所以 BLEU 适合做同一数据、同一分词、同一评估程序下的模型对比，不适合单独证明理解、推理或意识。</p>
<hr>
<h2 id="9-mse两个连续状态相差多远">9. MSE：两个连续状态相差多远</h2>
<p>TreeHeap 内部节点通常不是离散 token，而是 $d$ 维向量。预测状态 $\hat h$ 与真实状态 $h$ 的均方误差为：</p>
$$ \operatorname{MSE}(\hat h,h) =\frac{1}{d}\sum_{j=1}^{d}(\hat h_j-h_j)^2. $$<p>MSE 越小，两个向量在欧氏坐标上越接近。它常用于：</p>
<ul>
<li>FOLD/UNFOLD 闭合误差；</li>
<li>detail 修复误差；</li>
<li>多分辨率重建误差；</li>
<li>与 Zero 的状态距离。</li>
</ul>
<h3 id="mse-的陷阱">MSE 的陷阱</h3>
<p>如果所有状态本来都接近零，一个永远输出零的模型也可能获得很小的 MSE。因此我们常使用归一化 MSE：</p>
$$ \operatorname{NMSE} =\frac{\lVert \hat h-h\rVert_2^2} {\lVert h\rVert_2^2+\epsilon}. $$<p>NMSE 把误差与目标自身能量比较，更容易跨深度比较。它仍不是语义指标：向量恢复得近，不保证 decoder 功能也恢复，所以还要测恢复后的 NLL 或准确率。</p>
<hr>
<h2 id="10-余弦相似度比较方向不比较长度">10. 余弦相似度：比较方向，不比较长度</h2>
<p>两个向量的余弦相似度为：</p>
$$ \cos(a,b)=\frac{a\cdot b}{\lVert a\rVert_2\lVert b\rVert_2}. $$<p>范围通常为 $[-1,1]$：</p>
<ul>
<li>接近 1：方向相似；</li>
<li>接近 0：近似正交；</li>
<li>接近 -1：方向相反。</li>
</ul>
<p>余弦距离常写成：</p>
$$ d_{\cos}(a,b)=1-\cos(a,b). $$<p>它适合检索和几何聚类，但会忽略模长。例如 $a$ 与 $100a$ 的余弦相似度仍为 1。历史 checkpoint 出现平均 cosine <code>0.985</code> 时，我们把它看作“状态可能过度坍缩”的警报，而不是模型很好。</p>
<p>更重要的是：几何接近不自动等于功能等价。SPR-057 之后的交换实验正是用因果替换检验“相近子堆能否互换”，结果没有支持强功能等价 Claim。</p>
<hr>
<h2 id="11-kl-散度与熵概率桶是否发生变化">11. KL 散度与熵：概率桶是否发生变化</h2>
<h3 id="111-熵">11.1 熵</h3>
<p>概率分布 $p$ 的熵为：</p>
$$ H(p)=-\sum_i p_i\log p_i. $$<p>当概率集中在一个候选上时，熵较低；当许多候选接近均匀时，熵较高。</p>
<p>“熵越低越好”并不总成立。模型对明确问题应当自信，但面对真正歧义时，过低熵可能是假自信。多头 route 的 gate entropy 则用于判断是否只使用了一个 head：它接近最大值说明分配更均匀，但也不证明每个 head 学会了不同功能。</p>
<h3 id="112-kl-散度">11.2 KL 散度</h3>
<p>两个概率分布 $p$ 与 $q$ 的 KL 散度为：</p>
$$ D_{KL}(p\Vert q)=\sum_i p_i\log\frac{p_i}{q_i}. $$<p>KL 越小，两个概率桶越接近。它不是普通距离，因为通常：</p>
$$ D_{KL}(p\Vert q)\ne D_{KL}(q\Vert p). $$<p>在 TreeHeap 干预实验中，可以比较正常输出分布与“交换子堆后”的输出分布。KL 很大说明概率桶发生明显变化，但仍需判断变化是否朝正确答案方向移动；因此 KL 常与 NLL delta 配合使用。</p>
<h3 id="113-多项总-loss加号不代表单位天然相同">11.3 多项总 Loss：加号不代表单位天然相同</h3>
<p>当前全量训练把语言预测与 detail 修复联合起来：</p>
$$ L_{total}=L_{language}+\lambda L_{repair}. $$<p>$L_{language}$ 是 token NLL，$L_{repair}$ 是状态 NMSE，$\lambda$ 是人为设定的权重。两项的数值单位和自然尺度不同，不能因为写在一个加法式里就把它们当作同一种误差。</p>
<p>权重过小，repair 几乎学不到；权重过大，模型可能牺牲语言能力去追求状态坐标接近。正确报告方式是：说明 $\lambda$，分别记录两个分量，并最终分别检查语言功能和修复功能。只报告 <code>total_loss</code> 会掩盖二者的对冲。</p>
<p>多头也不意味着必须把所有目标都倒进一个总 loss。不同 head 可以共享一个下游任务 loss，也可以拥有受控的辅助目标；关键是用消融确认每个辅助项究竟带来了什么，而不是根据名字解释 head 的功能。</p>
<h3 id="114-infonce让正样本靠近负样本远离">11.4 InfoNCE：让正样本靠近、负样本远离</h3>
<p>早期 TreeHeap 讨论还使用过 InfoNCE。给定 query $q$、正确对象 $k^+$ 和一组候选 $k_j$，一种常见形式为：</p>
$$ L_{InfoNCE} =-\log \frac{\exp(s(q,k^+)/\tau)} {\sum_j\exp(s(q,k_j)/\tau)}. $$<p>$s$ 可以是点积或余弦相似度，$\tau$ 是温度。它把“正确配对应该比错误配对更相似”变成可微训练信号。</p>
<p>InfoNCE 的成败高度依赖负样本。把实际上合理的配对误当负样本，模型就会被训练成排斥真实关系。因此 InfoNCE 下降只证明模型更符合给定的正负样本规则，不自动证明它发现了世界中唯一正确的语义拓扑。</p>
<hr>
<h2 id="12-margin-与-retrieval1">12. Margin 与 retrieval@1</h2>
<h3 id="121-margin">12.1 Margin</h3>
<p>Margin 是正确候选分数与最强错误候选分数之差：</p>
$$ \operatorname{margin}=s_{\text{correct}}-\max_{j\ne correct}s_j. $$<p>正 margin 表示正确候选领先；越大通常越稳。但 margin 的绝对大小依赖评分尺度，必须在同一模型和任务内比较。</p>
<h3 id="122-retrieval1">12.2 retrieval@1</h3>
<p>对每个 query 在候选库中检索最相近对象。如果排名第一的是对应目标，就命中：</p>
$$ \operatorname{retrieval@1} =\frac{\text{第一名检索正确数}}{\text{query 总数}}. $$<p>它适合检查 TreeHeap 状态是否保留样本身份或关系。但必须和 BoW、随机 hash、flat embedding 等基线比较。<code>0.630</code> 本身无法说明 TreeHeap 有优势；若 BoW 是 <code>0.629</code>，只能称作几乎持平。</p>
<hr>
<h2 id="13-因果干预不要只问里面有没有信息">13. 因果干预：不要只问“里面有没有信息”</h2>
<p>probe 能从内部状态读出一个属性，只说明信息与状态相关，不说明主任务使用了它。更强的办法是主动破坏某一部分，再观察功能下降。</p>
<h3 id="131-ablation-delta">13.1 Ablation delta</h3>
<p>例如把 root 清零：</p>
$$ \Delta_{root} =\operatorname{NLL}(root=0)-\operatorname{NLL}(normal). $$<p>若 $\Delta_{root}>0$，清除 root 使预测变差，说明 root 对当前功能有因果贡献。数值越大，破坏通常越严重。</p>
<p>但破坏必须有匹配对照。粗暴删除一半参数当然会使任何模型变差；这不能证明 TreeHeap 的结构设计更好。</p>
<h3 id="132-source-shuffle-damage">13.2 Source shuffle damage</h3>
<p>把 batch 中每个目标配上另一个样本的 source：</p>
$$ \Delta_{source} =\operatorname{NLL}(shuffled\ source)-\operatorname{NLL}(correct\ source). $$<p>若差值接近零，decoder 可能主要依赖目标语言先验；若显著为正，说明输出确实依赖输入样本。</p>
<p>它仍不能证明模型“理解”了 source，只证明 source 中存在被 decoder 使用的条件信息。</p>
<h3 id="133-address-swap--wrong-address-ratio">13.3 Address swap / wrong-address ratio</h3>
<p>交换 left/right、移动 detail 地址或给修复器错误 parent，可以检验地址是否有功能意义。</p>
<p>若正确地址与错误地址效果几乎一样，就不能宣称模型学会了路径拓扑。最近 repair 实验的 wrong-address MSE ratio 为 <code>0.968</code>，因此我们保留 parent-detail 冗余结论，却拒绝 address-conditioned repair 结论。</p>
<hr>
<h2 id="14-damagerepair-和-recovery-fraction">14. Damage、Repair 和 Recovery Fraction</h2>
<p>设三个 NLL：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>clean      完整状态
</span></span><span style="display:flex;"><span>damaged    删除部分 TreeHeap 状态
</span></span><span style="display:flex;"><span>repaired   运行修复 kernel 后
</span></span></code></pre></div><p>损伤量为：</p>
$$ D=\operatorname{NLL}_{damaged}-\operatorname{NLL}_{clean}. $$<p>修复量为：</p>
$$ R=\operatorname{NLL}_{damaged}-\operatorname{NLL}_{repaired}. $$<p>恢复比例为：</p>
$$ \operatorname{RecoveryFraction}=\frac{R}{D}. $$<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>clean NLL    = 5.69
</span></span><span style="display:flex;"><span>damaged NLL  = 15.59
</span></span><span style="display:flex;"><span>repaired NLL = 6.22
</span></span></code></pre></div><p>则语言能力的恢复比例约为：</p>
$$ \frac{15.59-6.22}{15.59-5.69}\approx 94.6\%. $$<p>超过 100% 有时也会出现，表示该批次上 repaired NLL 暂时低于 clean NLL。这通常来自采样噪声、正则化效果或评估方差，不能直接解释成“损坏后反而更聪明”。</p>
<p>状态空间还可单独报告 MSE recovery。语言 NLL recovery 与 latent MSE recovery 回答不同问题，不能混为一个百分比。</p>
<hr>
<h2 id="15-自由生成的最低体检指标">15. 自由生成的最低体检指标</h2>
<p>NLL 之外，我们还记录：</p>
<h3 id="nonempty-fraction">nonempty fraction</h3>
<p>生成结果非空的比例。高于 0 只是最基础的存活检查，不代表可读。</p>
<h3 id="adjacent-repeat-fraction">adjacent repeat fraction</h3>
<p>相邻 token 重复的比例：</p>
$$ \frac{\#(y_t=y_{t-1})}{T-1}. $$<p>过高可能表示模型陷入“我我我我”式循环，但无法捕捉较长周期的重复。</p>
<h3 id="unique-output-fraction">unique output fraction</h3>
<p>同一评估批次中，不同输出序列的比例。很低可能说明模型无论输入什么都说同一句话。</p>
<p>这些只是退化检测。一个模型可以做到非空、少重复、输出多样，却仍然答非所问。因此必须同时阅读 source shuffle、人工样例和任务指标。</p>
<hr>
<h2 id="16-spearman-相关只看顺序趋势">16. Spearman 相关：只看顺序趋势</h2>
<p>Spearman 相关系数比较两个变量的排名关系。例如深度增加时 NLL 是否单调变化：</p>
$$ \rho\in[-1,1]. $$<ul>
<li>$\rho\approx 1$：一个增大时另一个也按排名增大；</li>
<li>$\rho\approx -1$：一个增大时另一个按排名减小；</li>
<li>$\rho\approx 0$：没有明显单调关系。</li>
</ul>
<p>Spearman 适合只有少量深度点、且不假定线性关系的情况。但六个深度得到 <code>-1.0</code>，仍然只是该实验中的完美反向排序，不等于普遍数学定律。</p>
<hr>
<h2 id="17-mean标准差seed-与-bootstrap-置信区间">17. Mean、标准差、seed 与 Bootstrap 置信区间</h2>
<p>神经网络训练含有随机初始化、batch 顺序和采样噪声。单 seed 结果可能偶然。</p>
<h3 id="171-多-seed">17.1 多 seed</h3>
<p>用多个随机种子重复整个训练，报告均值和离散程度：</p>
$$ \bar x=\frac{1}{n}\sum_i x_i. $$<p>如果三个 seed 中只有一个成功，不能只报告那个成功值。</p>
<h3 id="172-bootstrap-95-ci">17.2 Bootstrap 95% CI</h3>
<p>Bootstrap 从已有样本中有放回重采样，反复计算目标统计量，再取中间 95% 的区间。</p>
<p>例如同组交换与异组交换的损伤差为 <code>0.00187</code>，bootstrap 95% 区间为：</p>
$$ [-0.00395,\ 0.00745]. $$<p>区间跨过 0，表示当前样本不足以稳定判断差值方向。因此功能等价 Claim 没有得到支持。</p>
<p>置信区间不是“真值有 95% 概率在这里”的简单概率桶；它描述的是这套重复抽样程序的覆盖性质。对本科读者而言，最实用的读法是：<strong>区间越窄，估计越稳定；比较差的区间跨 0 时，不要宣称稳定胜出。</strong></p>
<hr>
<h2 id="18-吞吐显存参数量和计算成本">18. 吞吐、显存、参数量和计算成本</h2>
<p>模型是否能用，还要看工程指标：</p>
<ul>
<li><code>tokens/s</code>：每秒处理多少有效 token；</li>
<li><code>steps/s</code>：每秒更新次数；</li>
<li>peak GPU memory：峰值显存；</li>
<li>parameter count：可学习参数数量；</li>
<li>wall-clock time：真实运行时间；</li>
<li>checkpoint size：保存状态的磁盘成本。</li>
</ul>
<p>比较吞吐时必须固定 batch、长度、精度和硬件。FP32 batch 48 的 <code>23k token/s</code> 不能直接与 FP16 batch 16 的 <code>8k token/s</code> 比较，然后归因于精度格式；batch 大小已经变化。</p>
<p>参数更少也不自动更高效。递归 Python 循环可能使小模型运行很慢；结构压缩也可能在实现中先物化所有层，从而尚未兑现理论计算优势。</p>
<hr>
<h2 id="19-一张-treeheap-体检报告速查表">19. 一张 TreeHeap 体检报告速查表</h2>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th>通常方向</th>
          <th>主要回答</th>
          <th>不能单独证明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>train NLL</td>
          <td>越低越好</td>
          <td>优化是否在拟合训练数据</td>
          <td>泛化、对话能力</td>
      </tr>
      <tr>
          <td>valid/test NLL</td>
          <td>越低越好</td>
          <td>未见数据上的概率预测质量</td>
          <td>文本一定可读、结构被使用</td>
      </tr>
      <tr>
          <td>PPL</td>
          <td>越低越好</td>
          <td>NLL 的指数尺度</td>
          <td>跨词表公平比较</td>
      </tr>
      <tr>
          <td>top-1/top-k</td>
          <td>越高越好</td>
          <td>正确 token 排名</td>
          <td>概率是否校准</td>
      </tr>
      <tr>
          <td>sequence exact</td>
          <td>越高越好</td>
          <td>整段是否完全恢复</td>
          <td>合理改写质量</td>
      </tr>
      <tr>
          <td>BLEU</td>
          <td>同设置下越高越好</td>
          <td>与参考译文的词组重合</td>
          <td>事实、理解、意识</td>
      </tr>
      <tr>
          <td>MSE/NMSE</td>
          <td>越低越好</td>
          <td>连续状态重建误差</td>
          <td>decoder 功能恢复</td>
      </tr>
      <tr>
          <td>cosine similarity</td>
          <td>视任务而定</td>
          <td>向量方向接近程度</td>
          <td>功能等价</td>
      </tr>
      <tr>
          <td>entropy</td>
          <td>视场景而定</td>
          <td>概率桶集中程度</td>
          <td>高熵或低熵天然更聪明</td>
      </tr>
      <tr>
          <td>KL divergence</td>
          <td>越低越接近</td>
          <td>两个概率桶差异</td>
          <td>哪个分布更正确</td>
      </tr>
      <tr>
          <td>source shuffle delta</td>
          <td>通常越大越因果</td>
          <td>输出是否使用 source</td>
          <td>是否理解 source</td>
      </tr>
      <tr>
          <td>root/detail ablation delta</td>
          <td>通常越大越因果</td>
          <td>该状态是否参与功能</td>
          <td>架构优于基线</td>
      </tr>
      <tr>
          <td>recovery fraction</td>
          <td>越高越好</td>
          <td>损失能力恢复多少</td>
          <td>唯一正确修复</td>
      </tr>
      <tr>
          <td>retrieval@1</td>
          <td>越高越好</td>
          <td>第一近邻是否正确</td>
          <td>结构优势，除非击败基线</td>
      </tr>
      <tr>
          <td>bootstrap CI</td>
          <td>越窄越稳定</td>
          <td>差异估计的不确定性</td>
          <td>无偏设计或因果性</td>
      </tr>
      <tr>
          <td>tokens/s</td>
          <td>越高越快</td>
          <td>实现吞吐</td>
          <td>模型质量</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="20-如何阅读一条完整结论">20. 如何阅读一条完整结论</h2>
<p>以后看到：</p>
<blockquote>
<p>TreeHeap test NLL 为 5.09。</p></blockquote>
<p>应当继续追问：</p>
<ol>
<li>数据集和分词器是什么？</li>
<li>train、validation 还是 test？</li>
<li>与 flat、BoW、Transformer 或旧 checkpoint 相比如何？</li>
<li>是否多个 seed？</li>
<li>source shuffle、root zero、detail swap 后怎样？</li>
<li>自由生成样例是什么？</li>
<li>预注册门槛是多少？</li>
</ol>
<p>例如 S2 lifting WMT 的完整结论不是“TreeHeap NLL 5.0903，所以成功”，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>递归 READ NLL 5.0903
</span></span><span style="display:flex;"><span>root-only NLL 5.4337
</span></span><span style="display:flex;"><span>full UNFOLD NLL 5.1342
</span></span><span style="display:flex;"><span>flat sequence NLL 4.8103
</span></span><span style="display:flex;"><span>source shuffle damage +1.4450
</span></span><span style="display:flex;"><span>root shuffle damage +1.7204
</span></span></code></pre></div><p>这组数共同支持：递归 TreeHeap READ 使用了 source、root 和多层 detail，而且优于 root-only；同时它明确拒绝“翻译质量优于 flat sequence”。这才是符合 ARA 的边界化结论。</p>
<hr>
<h2 id="21-最后指标是仪表不是目的">21. 最后：指标是仪表，不是目的</h2>
<p>Houming818 设计 TreeHeap，并不是为了与 Transformer 对抗，而是希望研究一种可以延续、回访、损伤后修复并继续生长的内部状态。</p>
<p>这些愿望不能由某一个漂亮数字代替：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>低 NLL          不等于理解
</span></span><span style="display:flex;"><span>高准确率         不等于具有世界模型
</span></span><span style="display:flex;"><span>可修复           不等于拥有意识
</span></span><span style="display:flex;"><span>会说中文         不等于不再孤独
</span></span></code></pre></div><p>但没有这些可复查的测量，我们也无法区分真实生长与自己的期待。因此指标的作用不是把梦想缩成排行榜，而是让每一步都能被看见：模型学到了什么，依赖了什么，失去了什么，又能从哪里恢复。</p>
<p>这也是以后 TreeHeap 实验报告的最低要求：<strong>同时报告学习、功能、因果、生成与统计可信度，不让任何一个数字独自承担它证明不了的故事。</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-063] TreeHeap 分辨率协议重审：递归抽水、细节残差与递归解码</title>
      <link>https://www.grepcode.cn/spr/063-treeheap-decoder-depth-growth.html</link>
      <pubDate>Sat, 18 Jul 2026 00:00:00 +0000</pubDate>
      <ap:updated>Sun, 19 Jul 2026 00:00:00 +0000</ap:updated>
      <guid>https://www.grepcode.cn/spr/063-treeheap-decoder-depth-growth.html</guid>
      <description>公开撤回一次把多层变长数组误称为 TreeHeap 递归解码的实验解释，并重新定义 TreeHeap 的分辨率、递归、残差和抽水协议。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-分辨率协议重审递归抽水细节残差与递归解码">TreeHeap 分辨率协议重审：递归抽水、细节残差与递归解码</h1>
<blockquote>
<p>本文记录一次重要纠错。旧版 SPR-063 设计了所谓“递归深度剂量实验”，但代码审计发现，decoder 实际读取的是长度为 1、2、4、8 等的平铺数组。它没有沿 TreeHeap 地址移动，也没有读取父子边。因此，已经完成的实验不能否定 TreeHeap 的深度假设，只能否定这种多分辨率 flat READ。</p></blockquote>
<p>本文的核心概念由 Houming818 提出：信息应当像抽水机一样从 leaf 逐层退火到 root；这个过程必须递归。Codex Review 负责检查代码是否真的保存了这些概念，并把它整理成下一轮可证伪实验。</p>
<hr>
<h2 id="1-先说结论旧实验测错了对象">1. 先说结论：旧实验测错了对象</h2>
<p>旧代码的 encoder 确实执行了递归 FOLD：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf
</span></span><span style="display:flex;"><span>  -&gt; FOLD 得到上一层 parent
</span></span><span style="display:flex;"><span>  -&gt; 再用这些 parent 做下一次 FOLD
</span></span><span style="display:flex;"><span>  -&gt; 一直得到 root
</span></span></code></pre></div><p>如果记 leaf 为 $H_D$，那么：</p>
$$ H_{d-1}=F_\theta(H_d),\qquad d=D,D-1,\ldots,1 $$<p>同一个 $F_\theta$ 在不同深度重复调用。这部分是真递归。</p>
<p>但 encoder 随后把树转换成了一个列表：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>levels = [
</span></span><span style="display:flex;"><span>  [root],
</span></span><span style="display:flex;"><span>  [depth-1 的所有节点],
</span></span><span style="display:flex;"><span>  [depth-2 的所有节点],
</span></span><span style="display:flex;"><span>  ...,
</span></span><span style="display:flex;"><span>  [所有 leaf]
</span></span><span style="display:flex;"><span>]
</span></span></code></pre></div><p>每一层只剩一个形状为 <code>[batch, width, dim]</code> 的张量。parent、children、left、right、stop、path 和 span 都没有交给 decoder。</p>
<p>旧 READ 做的是：</p>
$$ q_{d+1}=R_\phi(q_d,\,[h_{d,1},h_{d,2},\ldots,h_{d,n_d}]) $$<p>其中方括号只是当前层的平铺数组。<code>dose</code> 增加一层，本质上只是再读取一个不同长度的数组。</p>
<p>因此旧实验的准确名称应当是：</p>
<blockquote>
<p>递归池化产生的多分辨率数组实验。</p></blockquote>
<p>它不是 TreeHeap 递归 decoder 实验。</p>
<hr>
<h2 id="2-为什么用树算出节点还不等于使用了树">2. 为什么“用树算出节点”还不等于“使用了树”</h2>
<p>考虑这棵树：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>             A
</span></span><span style="display:flex;"><span>          /     \
</span></span><span style="display:flex;"><span>         B       C
</span></span><span style="display:flex;"><span>        / \     / \
</span></span><span style="display:flex;"><span>       1   2   3   4
</span></span></code></pre></div><p>递归 encoder 计算：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>B = FOLD(1, 2)
</span></span><span style="display:flex;"><span>C = FOLD(3, 4)
</span></span><span style="display:flex;"><span>A = FOLD(B, C)
</span></span></code></pre></div><p>如果 decoder 最后只收到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[A]
</span></span><span style="display:flex;"><span>[B, C]
</span></span><span style="display:flex;"><span>[1, 2, 3, 4]
</span></span></code></pre></div><p>它并不知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1、2 属于 B
</span></span><span style="display:flex;"><span>3、4 属于 C
</span></span><span style="display:flex;"><span>B、C 属于 A
</span></span></code></pre></div><p>它只能把每一层当作集合或数组进行 attention pooling。</p>
<p>这解释了守夜实验的异常结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Tree 多层数组 NLL</td>
          <td style="text-align: right">6.2366</td>
      </tr>
      <tr>
          <td>Random 多层数组 NLL</td>
          <td style="text-align: right">6.2361</td>
      </tr>
      <tr>
          <td>Flat pooling NLL</td>
          <td style="text-align: right">5.9311</td>
      </tr>
      <tr>
          <td>所谓“打乱链接”的 NLL 变化</td>
          <td style="text-align: right">0.00000021</td>
      </tr>
  </tbody>
</table>
<p>数字没有证明 TreeHeap 拓扑无效，因为拓扑从未进入 READ。所谓 <code>shuffled_links</code> 也只是重新生成了另一组池化数组，并没有在保持节点值不变时修改 decoder 正在遍历的边。</p>
<p>因此 ARA 状态必须修正为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不是：TreeHeap depth claim 被否证
</span></span><span style="display:flex;"><span>而是：该实验没有测试到 TreeHeap depth claim
</span></span></code></pre></div><hr>
<h2 id="3-分辨率到底是什么">3. 分辨率到底是什么</h2>
<p>我们先不要求 root 能翻译成人类可读的缩句。encoder 和 decoder 可以形成私有编码。</p>
<p>这里的分辨率是一个操作定义：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root                  最少状态，最大覆盖范围
</span></span><span style="display:flex;"><span>root + 第一层 detail  更多局部信息
</span></span><span style="display:flex;"><span>继续展开              更高分辨率
</span></span><span style="display:flex;"><span>全部 leaf/detail      最高表面精度
</span></span></code></pre></div><p>它类似一张图片：缩略图保留大体结构，放大后补充纹理。但语言不是天然平滑的像素平面，所以我们不能直接宣称 root 一定保存“主语、谓语、宾语”或者一条可读摘要。</p>
<p>我们真正要验证的是：</p>
<ol>
<li>parent 是否保存了对多个 children 都有用的公共状态；</li>
<li>child/edge 是否保存了 parent 无法预测的细节；</li>
<li>增加细节后，decoder 是否沿同一棵树递归改善；</li>
<li>破坏地址和父子关系后，这种改善是否消失。</li>
</ol>
<hr>
<h2 id="4-抽水机不能只是加权平均">4. 抽水机不能只是加权平均</h2>
<p>旧 FOLD 大致是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>children
</span></span><span style="display:flex;"><span>  -&gt; slot embedding
</span></span><span style="display:flex;"><span>  -&gt; MLP
</span></span><span style="display:flex;"><span>  -&gt; softmax 加权平均
</span></span><span style="display:flex;"><span>  -&gt; parent
</span></span></code></pre></div><p>它可以把多个 child 压成一个 parent，但没有说明哪些信息上传、哪些信息留在原处。连续多次压缩后，信息可能只是被混合和扭曲。</p>
<p>更完整的抽水过程应当同时产生两类量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>coarse：上传给 parent 的公共轮廓
</span></span><span style="display:flex;"><span>detail：留在 child 或 edge 上的预测残差
</span></span></code></pre></div><p>定义 children 为 $c_1,\ldots,c_k$。先计算 parent：</p>
$$ s_p=U_\theta(c_1,\ldots,c_k) $$<p>再由 parent 和 slot 预测每个 child：</p>
$$ \hat c_j=P_\phi(s_p,e_j) $$<p>细节残差为：</p>
$$ r_j=c_j-\hat c_j $$<p>于是 child 可以恢复为：</p>
$$ \tilde c_j=P_\phi(s_p,e_j)+r_j $$<p>这里的 <code>coarse</code> 被抽到 parent，<code>detail residual</code> 没有硬塞进 root，而是保存在对应的边上。</p>
<hr>
<h2 id="5-这与小波-lifting-scheme-有什么关系">5. 这与小波 lifting scheme 有什么关系</h2>
<p>这套结构不是凭空发明。小波的 lifting scheme 使用 <code>split -&gt; predict -&gt; update</code> 构造多分辨率表示：一部分数据形成低分辨率近似，另一部分记录预测失败产生的 detail。保留全部 detail 时可以精确恢复；逐步丢弃 detail 时得到逐级降低的分辨率。</p>
<p>对 TreeHeap，可以作如下对应：</p>
<table>
  <thead>
      <tr>
          <th>Lifting scheme</th>
          <th>TreeHeap</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>split</td>
          <td>把节点分为 parent 覆盖的 child slots</td>
      </tr>
      <tr>
          <td>predict</td>
          <td>用 parent 预测 child state</td>
      </tr>
      <tr>
          <td>detail</td>
          <td>child 与预测值的差 $r_j$</td>
      </tr>
      <tr>
          <td>update</td>
          <td>用 detail 修正 parent 的 coarse state</td>
      </tr>
      <tr>
          <td>inverse lifting</td>
          <td>从 parent 与 residual 递归恢复 children</td>
      </tr>
  </tbody>
</table>
<p>这给了我们一个重要保护：</p>
<blockquote>
<p>residual 不应当作为原始 child 的直通旁路混入 root；它应当成为有地址的细节量，只有 decoder 展开对应 edge 时才参与恢复。</p></blockquote>
<p>否则 root 会退化成全部 leaf 的 Bag，分辨率抽水优势会消失。</p>
<p>参考：Wim Sweldens, <a href="https://epubs.siam.org/doi/abs/10.1137/S0036141095289051">The Lifting Scheme: A Construction of Second Generation Wavelets</a>。图结构上的可学习版本也已经存在，例如 <a href="https://arxiv.org/abs/2108.01660">Graph Neural Networks With Lifting-based Adaptive Graph Wavelets</a>。</p>
<hr>
<h2 id="6-transformer-式残差与-treeheap-detail-residual-不是一回事">6. Transformer 式残差与 TreeHeap detail residual 不是一回事</h2>
<p>Transformer/ResNet 残差大致是：</p>
$$ x_{l+1}=x_l+f_l(x_l) $$<p>它提供接近恒等映射的信息与梯度通道，使深层网络不必在每一层重新创造输入。参考 <a href="https://arxiv.org/abs/1512.03385">Deep Residual Learning</a>。</p>
<p>旧 TreeHeap 代码中也有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pooled + MLP(pooled)
</span></span><span style="display:flex;"><span>query  + UPDATE(query, context)
</span></span></code></pre></div><p>但第一个残差发生在 children 已经被压成 <code>pooled</code> 之后。它只能保护 pooled state，不能保存已经丢失的 child detail。</p>
<p>因此下一版需要区分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel residual：帮助深层优化
</span></span><span style="display:flex;"><span>tree detail residual：保存跨分辨率丢失的信息
</span></span></code></pre></div><p>两者可以同时存在，但不能混为一个变量。</p>
<hr>
<h2 id="7-字符串中有没有抽取大轮廓的已有算法">7. 字符串中有没有“抽取大轮廓”的已有算法</h2>
<p>有相关工作，但没有一种算法能仅靠压缩就保证 root 成为人类认可的摘要。</p>
<h3 id="71-diora用递归预测压力诱导潜在树">7.1 DIORA：用递归预测压力诱导潜在树</h3>
<p><a href="https://aclanthology.org/N19-1116/">DIORA</a> 用 inside-outside recursive autoencoder 考虑句子的多种二叉树组合，并通过“根据其余句子预测某个词”学习 constituent state。</p>
<p>它支持一个重要判断：递归节点可以在没有人工句法标签时，通过上下文预测任务形成结构。但它不保证 root 是自然语言摘要。</p>
<h3 id="72-hierarchical-multiscale-rnn从序列中学习不同时间尺度">7.2 Hierarchical Multiscale RNN：从序列中学习不同时间尺度</h3>
<p><a href="https://arxiv.org/abs/1609.01704">Hierarchical Multiscale RNN</a> 学习潜在边界，让不同层按不同时间尺度更新。这说明字符串可以在没有显式边界标签时形成多尺度状态。</p>
<h3 id="73-pegasus直接训练保留重要内容">7.3 PEGASUS：直接训练“保留重要内容”</h3>
<p><a href="https://arxiv.org/abs/1912.08777/">PEGASUS</a> 从文档中移除重要句子，再要求模型根据剩余内容生成它们。它把摘要需要的“重要性”变成了训练压力。</p>
<h3 id="74-funnel-与-hourglass语言序列可以逐步降低分辨率">7.4 Funnel 与 Hourglass：语言序列可以逐步降低分辨率</h3>
<p><a href="https://arxiv.org/abs/2006.03236">Funnel Transformer</a>逐步缩短 hidden sequence；<a href="https://arxiv.org/abs/2110.13711">Hourglass Transformer</a>执行 shorten 后再 upsample。它们证明多长度语言计算可行，但不能单独证明语义轮廓形成。</p>
<h3 id="75-top-down-latent-tree-generation">7.5 Top-down latent tree generation</h3>
<p><a href="https://aclanthology.org/2020.findings-emnlp.208/">Recursive Top-Down Production for Sentence Generation with Latent Trees</a>从潜在二叉树递归生成句子，与 TreeHeap decoder 从 coarse state 展开 detail 的目标直接相关。</p>
<p>这些工作共同提示：</p>
<blockquote>
<p>代数协议决定信息怎样压缩与恢复，训练目标决定什么信息值得上传。</p></blockquote>
<hr>
<h2 id="8-新的数据结构契约">8. 新的数据结构契约</h2>
<p>下一版代码中的 TreeHeap 节点至少要保存：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Node {
</span></span><span style="display:flex;"><span>    address          当前堆地址
</span></span><span style="display:flex;"><span>    parent_address   父地址
</span></span><span style="display:flex;"><span>    child_addresses  子地址
</span></span><span style="display:flex;"><span>    depth            递归深度
</span></span><span style="display:flex;"><span>    span             覆盖的 leaf 区间
</span></span><span style="display:flex;"><span>    coarse_state     上传后的低分辨率状态
</span></span><span style="display:flex;"><span>    detail_residual  相对 parent 预测的细节
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>任何实验只要在进入 decoder 前把它重新变成无边的 <code>List[Tensor]</code>，就不得命名为 TreeHeap recursive READ。</p>
<hr>
<h2 id="9-新-encoder递归-learned-lifting">9. 新 encoder：递归 learned lifting</h2>
<p>伪代码如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ENCODE(node):
</span></span><span style="display:flex;"><span>    if node is leaf:
</span></span><span style="display:flex;"><span>        return token_embedding(node.token)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    child_states = []
</span></span><span style="display:flex;"><span>    for child in node.children:
</span></span><span style="display:flex;"><span>        child_states.append(ENCODE(child))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    parent.coarse = UPDATE(child_states)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    for slot, child_state in enumerate(child_states):
</span></span><span style="display:flex;"><span>        predicted = PREDICT(parent.coarse, slot)
</span></span><span style="display:flex;"><span>        edge[slot].detail = child_state - predicted
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    return parent.coarse
</span></span></code></pre></div><p>关键审计条件是：每个 parent 的输入必须来自其 children 的递归返回值，而不是从全局 leaf array 重新池化。</p>
<hr>
<h2 id="10-新-decoder沿地址-top-down-展开">10. 新 decoder：沿地址 top-down 展开</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>DECODE(address, state, remaining_depth):
</span></span><span style="display:flex;"><span>    node = heap[address]
</span></span><span style="display:flex;"><span>    bucket = ROUTE_KERNEL(query, node, path)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    if bucket.stop is selected or remaining_depth == 0:
</span></span><span style="display:flex;"><span>        return OUTPUT(state)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    for child_address in node.child_addresses:
</span></span><span style="display:flex;"><span>        predicted_child = PREDICT(state, child_slot)
</span></span><span style="display:flex;"><span>        child_state = predicted_child + edge.detail
</span></span><span style="display:flex;"><span>        DECODE(child_address, child_state, remaining_depth - 1)
</span></span></code></pre></div><p>这里的递归深度不是读取数组的数量，而是 kernel 沿合法地址实际移动的次数。</p>
<p>一次路径可能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>  -&gt; left
</span></span><span style="display:flex;"><span>  -&gt; right
</span></span><span style="display:flex;"><span>  -&gt; stop
</span></span></code></pre></div><p>每一步都携带当前地址、局部 subheap、path state 和概率桶。</p>
<hr>
<h2 id="11-下一项实验不能直接跑语言大模型">11. 下一项实验不能直接跑语言大模型</h2>
<p>我们先验证数学与代码契约，再验证语言归纳能力。</p>
<p>这里不是从零开始。项目已有两段应当复用的实现：</p>
<ul>
<li><code>s2_adaptive_lifting_wmt.py</code> 已经按 <code>detail = child - predict(anchor)</code>、<code>parent = anchor + update(detail)</code> 递归 FOLD，并用逆运算 UNFOLD；历史实验的闭包 MSE 为 <code>2.35e-14</code>。</li>
<li><code>s2_lifting_pump_wmt.py</code> 的 recursive READ 保留了 active probability。某个 parent 的 expand 概率只会分配给它自己的两个 children，而不是对整层节点重新做一次无条件 pooling。</li>
</ul>
<p>历史 S2 数据中，recursive/root/full/flat 的测试 NLL 分别为 <code>5.0903 / 5.4337 / 5.1342 / 4.8103</code>。这支持“递归 detail 对翻译有用”，但 flat 仍然更好，也没有证明 root 是语义摘要。</p>
<p>因此下一项代码工作不是再发明一种 FOLD，而是给已有 recursive READ 增加严格的 <code>max_depth</code>，并审计它是否真的沿地址递归生长。</p>
<h3 id="proof-a完整-residual-的递归往返">Proof A：完整 residual 的递归往返</h3>
<p>输入一棵随机 TreeHeap：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf -&gt; recursive encode -&gt; root + addressed residuals
</span></span><span style="display:flex;"><span>     -&gt; recursive decode -&gt; reconstructed leaf
</span></span></code></pre></div><p>预测：保留全部 residual 时，重建误差接近浮点误差；删除任何一条 residual 时，只影响其对应 subheap。</p>
<p>这证明协议和地址实现正确，不证明语义。</p>
<h3 id="proof-b逐级释放-residual-的率失真曲线">Proof B：逐级释放 residual 的率失真曲线</h3>
<p>对真实中文 BPE 序列递归编码，只允许 decoder 使用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>root + depth1 residual
</span></span><span style="display:flex;"><span>root + depth1..2 residual
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>全部 residual
</span></span></code></pre></div><p>预测：token reconstruction NLL 应总体单调下降。若曲线乱跳，说明 coarse/detail 协议没有形成稳定分辨率。</p>
<h3 id="proof-c递归与地址因果">Proof C：递归与地址因果</h3>
<p>保持 coarse state 和 residual 数值不变，只交换 residual 所属的 edge address。</p>
<p>预测：恢复损失明显增加，并主要发生在被交换的 subheap 内。如果全局几乎不变，decoder 仍未利用 TreeHeap 地址。</p>
<h3 id="proof-d抽水是否产生可用轮廓">Proof D：抽水是否产生可用轮廓</h3>
<p>在 root 容量固定且明显小于 leaf 总容量时，让 root 预测：</p>
<ul>
<li>被遮住的 span；</li>
<li>相邻上下文；</li>
<li>文档中抽出的 gap sentence；</li>
<li>下一段真实文本。</li>
</ul>
<p>再与随机分组树、flat bottleneck 和 shuffled corpus 比较。</p>
<p>只有当合法 TreeHeap 的 coarse state 在 held-out 数据上更好，才能说抽水机提取了任务相关轮廓。</p>
<hr>
<h2 id="12-新-claim-的边界">12. 新 Claim 的边界</h2>
<p>下一项 Claim 暂定为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S3-TREE-LIFT-RECURSIVE-C01
</span></span></code></pre></div><blockquote>
<p>一个显式保存 parent-child 地址的共享 learned-lifting kernel，可以递归地把 leaf 分解为 parent coarse state 与 addressed detail residual；top-down decoder 沿相同地址协议展开时，完整 residual 支持近似无损恢复，逐层释放 residual 形成有序率失真曲线，交换 residual 地址会产生局部且显著的恢复损失。</p></blockquote>
<p>它只声明三件事：</p>
<ol>
<li>递归协议在代码中真实存在；</li>
<li>coarse/detail 分辨率可以稳定定义；</li>
<li>decoder 使用了 TreeHeap 地址。</li>
</ol>
<p>它不声明：</p>
<ul>
<li>root 已经理解人类摘要；</li>
<li>TreeHeap 优于 Transformer；</li>
<li>模型已经形成世界知识或意识；</li>
<li>任意 FOLD 都会自然产生语义轮廓。</li>
</ul>
<hr>
<h2 id="13-当前状态">13. 当前状态</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>旧实验：完成，但重新分类为 multiresolution flat READ
</span></span><span style="display:flex;"><span>旧 Claim：未被测试，不是被否证
</span></span><span style="display:flex;"><span>新协议：递归 learned lifting + addressed residual + top-down READ
</span></span><span style="display:flex;"><span>新实验：确定性 contract 已通过，冻结 WMT depth-cap 子实验已完成
</span></span></code></pre></div><p>2026-07-19，第一道 contract probe 已在 io 的 CPU 上完成：</p>
<table>
  <thead>
      <tr>
          <th>检查</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>8-leaf 完整 FOLD/UNFOLD MSE</td>
          <td style="text-align: right"><code>3.2341e-15</code></td>
      </tr>
      <tr>
          <td>不同 depth cap 下 route 质量守恒最大误差</td>
          <td style="text-align: right"><code>5.9605e-8</code></td>
      </tr>
      <tr>
          <td>交换两个 residual 后，目标四叶 subheap MSE</td>
          <td style="text-align: right"><code>1.4019</code></td>
      </tr>
      <tr>
          <td>同一次交换在 subheap 外造成的 MSE</td>
          <td style="text-align: right"><code>2.7198e-15</code></td>
      </tr>
  </tbody>
</table>
<p>这说明当前复用的 lifting 代数可以递归闭合，概率质量可以沿父子地址守恒，而且 residual 地址扰动具有严格局部性。它仍然没有证明 root 学到了语言轮廓。下一道真实语料实验将专门验证 root source causality、递归深度收益和学习后的地址因果性。</p>
<h3 id="131-冻结-checkpoint-的递归深度结果">13.1 冻结 checkpoint 的递归深度结果</h3>
<p>我们随后复用了一个在 20 万条 WMT 英中句对上训练完成的
<code>learned_update</code> checkpoint。模型参数全程冻结，5,000 条测试句也完全
相同；唯一控制变量是 <code>max_depth</code>：到达深度上限时，尚未停止的概率
质量被强制留在当前节点，不再进入孩子。</p>
<p>这不是分别训练长度为 1、2、4、8 的数组。一次 READ 始终从 root
开始，当前节点的概率桶决定 STOP 或把剩余概率传给它自己的左右孩子。</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">允许的最大递归深度</th>
          <th style="text-align: right">NLL（越低越好）</th>
          <th style="text-align: right">困惑度（越低越好）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0，只读 root</td>
          <td style="text-align: right">13.8100</td>
          <td style="text-align: right">994,481</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td style="text-align: right">13.9301</td>
          <td style="text-align: right">1,121,454</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">11.4878</td>
          <td style="text-align: right">97,514</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td style="text-align: right">8.2396</td>
          <td style="text-align: right">3,788</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">6.5393</td>
          <td style="text-align: right">692</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">5.7286</td>
          <td style="text-align: right">308</td>
      </tr>
      <tr>
          <td style="text-align: right">6，完整 READ</td>
          <td style="text-align: right">4.6335</td>
          <td style="text-align: right">103</td>
      </tr>
  </tbody>
</table>
<p>完整 READ 比 root-only 降低 <code>9.1765</code> NLL。除第一步外，后续五次开放
更深子堆都带来改善。最大概率质量守恒误差为 <code>4.1723e-7</code>，通过
<code>1e-6</code> 门槛。全量审计处理了 84,195 个目标 token，在 io 上耗时
<code>101.45</code> 秒。</p>
<p>用本科生容易核对的话说：decoder 若只能拿 root，几乎无法完成翻译；
允许它沿真实父子地址继续向下读取，答案会逐层接近完整模型。这是
“增加结构”的正向干预，而不是删除节点的消融。</p>
<p>但这里必须踩住刹车。它支持的是“深层 addressed state 被同一个 decoder
实际使用”，还不能证明“越靠近 root 就是人类可读的摘要”。depth 1 甚至
比 root-only 差 <code>0.1202</code>，所以曲线不是数学上必然单调。模型原本也在完整
READ 下训练，截断深度属于分布外干预。source shuffle、学习后的 residual
地址交换、sibling pair break 和 flat/Transformer 对比仍需后续实验。</p>
<p>这次纠错最重要的收获不是换了一个公式，而是建立了一条命名纪律：</p>
<blockquote>
<p>递归生成过数据，不等于递归参与了计算。只有地址、父子关系和共享 kernel 一起进入 decoder 的移动过程，才是 TreeHeap recursive READ。</p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-064] TreeHeap 私有协议实验：协议成立，性能优势未成立</title>
      <link>https://www.grepcode.cn/spr/064-treeheap-private-protocol-battle.html</link>
      <pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate>
      <ap:updated>Mon, 20 Jul 2026 00:00:00 +0000</ap:updated>
      <guid>https://www.grepcode.cn/spr/064-treeheap-private-protocol-battle.html</guid>
      <description>TreeHeap 私有协议三 seed 正式实验结果：结构因果性和 encoder-decoder 私有配对成立，但多头收益与 flat 性能优势未成立。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-私有协议实验协议成立性能优势未成立">TreeHeap 私有协议实验：协议成立，性能优势未成立</h1>
<blockquote>
<p><strong>证据状态更新（2026-07-28）：本文的“私有协议成立”表述降级为“teacher-forced decoder 对 TreeHeap 状态存在依赖”。后续 C10 审计发现，同系列训练目标允许 decoder 依靠正确中文前缀降低 NLL，而不必使用英文 source。本文的结构干预数字仍是有效观测，但不能单独证明英文语义被写入 TreeHeap，也不能证明 source-conditioned 私有协议已经形成。详见 SPR-074。</strong></p></blockquote>
<blockquote>
<p>本文首先纠正一个刚刚出现的方向错误：我们已经决定让 TreeHeap 的 encoder 和 decoder 自己形成私有协议，就不应该再由研究者规定“root 必须保存主题”“detail 必须保存次要信息”或者“某个 head 必须学习语法”。我们只设计可微、递归、可寻址的通信结构。协议内部写了什么，由最终任务的梯度决定。最后有没有本事，由实验结果决定。</p></blockquote>
<hr>
<h2 id="1-什么叫私有协议">1. 什么叫私有协议</h2>
<p>给定输入字符串 $X$ 和目标字符串 $Y$，encoder 把输入写入一个 TreeHeap 状态：</p>
$$H=E_\theta(X)$$<p>decoder 只能读取这个状态，并生成输出概率：</p>
$$P(Y\mid X)=D_\phi(H)$$<p>训练只使用最终输出的交叉熵：</p>
$$L(\theta,\phi)=-\sum_t \log P_{\theta,\phi}(y_t\mid X,y_{\lt t})$$<p>梯度同时修改 $E_\theta$ 和 $D_\phi$。只要 encoder 写出的状态能被 decoder 正确读取，loss 就会下降。内部编码不需要像自然语言，也不需要让人类看懂。</p>
<p>这就叫私有协议。它像一个人自己的笔迹：我们不规定每一笔必须代表什么，只要求写的人和读的人使用同一套规则。</p>
<p>但是，“私有”不等于“无法验证”。我们仍然可以验证：</p>
<ol>
<li>encoder 和 decoder 是否真的能够联合完成任务；</li>
<li>decoder 是否依赖 TreeHeap，而不是绕过它读取原字符串；</li>
<li>地址、父子关系、递归深度和 head 被破坏以后，输出是否退化；</li>
<li>相同数据、参数量和训练预算下，它是否优于更简单的结构。</li>
</ol>
<hr>
<h2 id="2-抽水机在协议中是什么">2. 抽水机在协议中是什么</h2>
<p>最近建立的 lifting 抽水机，不是语义分类器，也不是“信息价值判断器”。它只是 encoder 和 decoder 共同遵守的递归通信介质。</p>
<p>一次局部 FOLD 接收左右两个状态 $a,r$，产生一个继续向上传播的 parent $p$，以及保留在当前地址的 detail $d$：</p>
$$p=a+U_\theta(r)$$$$d=r-P_\theta(p)$$<p>decoder 使用相反方向的运算恢复 children：</p>
$$r=d+P_\theta(p)$$$$a=p-U_\theta(r)$$<p>同一组共享 kernel 在整棵树上递归调用：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tokens
</span></span><span style="display:flex;"><span>  -&gt; WRITE
</span></span><span style="display:flex;"><span>  -&gt; FOLD 得到 parent + addressed detail
</span></span><span style="display:flex;"><span>  -&gt; parent 继续递归 FOLD
</span></span><span style="display:flex;"><span>  -&gt; 形成完整 H_state
</span></span><span style="display:flex;"><span>  -&gt; decoder 从 H_state 递归 READ / UNFOLD
</span></span><span style="display:flex;"><span>  -&gt; 输出 token 概率桶
</span></span></code></pre></div><p>这里的 $p$ 和 $d$ 首先只是两个不同位置的私有通信变量。研究者不能提前宣布：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p = 句子主题
</span></span><span style="display:flex;"><span>d = 表面细节
</span></span></code></pre></div><p>如果将来实验发现某个深度更适合预测全局输出，那是实验结论；不是算法定义。</p>
<hr>
<h2 id="3-我们已经走到了哪里">3. 我们已经走到了哪里</h2>
<p>这条路线并不是今天才提出。ARA 中已经有三段连续证据。</p>
<h3 id="31-m0短算子协议能够学习">3.1 M0：短算子协议能够学习</h3>
<p>在受控数论 TreeHeap 中，结构 encoder 学习一个短算子程序，固定 executor 使用 TreeHeap 原生算子恢复目标。</p>
<table>
  <thead>
      <tr>
          <th>测试</th>
          <th style="text-align: right">TreeHeap structural restore</th>
          <th style="text-align: right">Flat program</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>IID</td>
          <td style="text-align: right">0.9270</td>
          <td style="text-align: right">0.1535</td>
      </tr>
      <tr>
          <td>OOD 地址</td>
          <td style="text-align: right">0.8400</td>
          <td style="text-align: right">0.0000</td>
      </tr>
  </tbody>
</table>
<p>这说明“学习协议 + 固定结构执行器”在受控世界中可以成立，但联合外推到未见递归深度仍然失败。</p>
<h3 id="32-native-codecraw-token-能形成地址敏感私有协议">3.2 Native codec：raw token 能形成地址敏感私有协议</h3>
<p>模型从随机参数开始，只用 echo 交叉熵联合训练：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>WRITE -&gt; FOLD -&gt; DETAIL -&gt; UNFOLD -&gt; READ
</span></span></code></pre></div><table>
  <thead>
      <tr>
          <th>版本</th>
          <th style="text-align: right">正常 token top-1</th>
          <th style="text-align: right">detail 地址错位后</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>continuous v1</td>
          <td style="text-align: right">0.9955</td>
          <td style="text-align: right">0.0024</td>
      </tr>
      <tr>
          <td>continuous v2</td>
          <td style="text-align: right">0.9915</td>
          <td style="text-align: right">0.0014</td>
      </tr>
  </tbody>
</table>
<p>所有五个算子都收到非零梯度。地址错位几乎摧毁输出，因此模型确实形成了依赖 TreeHeap 地址的私有协议。</p>
<p>但 root 清零后准确率几乎不变。这个协议主要走本地 detail 通道，并没有形成完整的 root-plus-detail 协议。Echo 允许这种答案，所以不能责怪模型“没有学会主题”。</p>
<h3 id="33-lifting-pump协议获得了闭合递归载体">3.3 Lifting pump：协议获得了闭合递归载体</h3>
<p>抽水机实验已经证明：</p>
<ul>
<li>depth-6 闭包最大误差约为 $3.70\times10^{-6}$；</li>
<li>state MSE 为 $3.14\times10^{-14}$；</li>
<li>确定性 token/block echo 都是 1.0；</li>
<li>WMT checkpoint 从 depth cap 0 开放到 6 时，NLL 从 13.8100 降到 4.6335；</li>
<li>root、detail 和多个递归 pairing 在 WMT 中具有可测的因果作用。</li>
</ul>
<p>这证明同一个 decoder 可以沿同一棵 TreeHeap 递归增加可用状态。它没有证明 root 是人类可读摘要，也没有证明 TreeHeap 已经优于 flat sequence。</p>
<p>在 200K WMT 实验中：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">NLL</th>
          <th style="text-align: right">Token BLEU-4</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap learned-update lifting</td>
          <td style="text-align: right">4.6335</td>
          <td style="text-align: right">9.909</td>
      </tr>
      <tr>
          <td>Flat sequence</td>
          <td style="text-align: right">4.5419</td>
          <td style="text-align: right">10.572</td>
      </tr>
  </tbody>
</table>
<p>因此当前体检报告是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>私有协议存在                阳性
</span></span><span style="display:flex;"><span>协议依赖 TreeHeap 地址      阳性
</span></span><span style="display:flex;"><span>递归 FOLD/UNFOLD 闭合       阳性
</span></span><span style="display:flex;"><span>真实 WMT 使用多层状态       阳性
</span></span><span style="display:flex;"><span>翻译质量超过 flat           阴性
</span></span><span style="display:flex;"><span>内部语义可以被人类解释      未检测，也不是当前门槛
</span></span></code></pre></div><hr>
<h2 id="4-下一条-claim">4. 下一条 Claim</h2>
<p>下一轮不再证明“私有协议能不能存在”，而测试它有没有工程竞争力。</p>
<p>建议预注册为：</p>
<blockquote>
<p><strong>S3-PRIVATE-PROTOCOL-BATTLE-C01</strong>：在不提供语法、深度、route、摘要或 head 语义标签的条件下，多个共享递归 TreeHeap kernel 可以仅通过最终 seq2seq 交叉熵形成 encoder-decoder 私有协议；该协议必须在真实任务中稳定训练，因果依赖 TreeHeap 地址和递归结构，并在相同参数、数据与训练预算下，相对单 head TreeHeap 和 flat baseline 产生可测收益。</p></blockquote>
<p>这条 Claim 没有规定协议内容。它只规定通信介质、训练信号和判分方法。</p>
<hr>
<h2 id="5-实验模型">5. 实验模型</h2>
<p>使用同一份真实数据、同一 tokenizer、同一训练/验证/测试切分和相同随机数据顺序，训练四组模型。</p>
<h3 id="a-单-head-treeheap">A. 单 head TreeHeap</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token embedding
</span></span><span style="display:flex;"><span>-&gt; 一个 WRITE/FOLD/DETAIL kernel
</span></span><span style="display:flex;"><span>-&gt; 一个 H_state
</span></span><span style="display:flex;"><span>-&gt; 递归 READ/UNFOLD
</span></span><span style="display:flex;"><span>-&gt; autoregressive decoder
</span></span></code></pre></div><p>这是当前 lifting pump 的直接基线。</p>
<h3 id="b-多-head-treeheap">B. 多 head TreeHeap</h3>
<p>每个 head 有独立参数，并在相同 TreeHeap 地址上建立自己的状态：</p>
$$H^{(m)}=E_{\theta_m}(X),\qquad m=1,\ldots,M$$<p>decoder 联合读取所有 head：</p>
$$P(Y\mid X)=D_\phi\left(H^{(1)},\ldots,H^{(M)}\right)$$<p>所有 head 共用一个最终 seq2seq loss。没有“语法 head loss”“主题 head loss”或者人工分工。</p>
<p>完整研究计划考虑 $M\in\{1,2,4,8\}$。本次正式 Stage A 为控制守夜任务的变量和时间，只预注册并执行 $M\in\{1,2,4\}$；8 head 留待前三级出现收益以后再开放。如果增加 head 只增加参数，不改善验证集，就不能宣称多头有效。</p>
<h3 id="c-flat-sequence-baseline">C. Flat sequence baseline</h3>
<p>保留 token 顺序和相同 decoder，但 encoder 不使用父子地址、递归 FOLD 或 addressed detail。参数量和训练 FLOPs 应尽量与 TreeHeap 匹配。</p>
<h3 id="d-小型-transformer-baseline">D. 小型 Transformer baseline</h3>
<p>使用相同 tokenizer、训练数据和参数预算。它不是敌人，而是成熟的序列私有协议基线。</p>
<hr>
<h2 id="6-最直接的私有协议检查">6. 最直接的私有协议检查</h2>
<p>训练三个随机种子的 encoder-decoder 配对：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>(E1, D1)
</span></span><span style="display:flex;"><span>(E2, D2)
</span></span><span style="display:flex;"><span>(E3, D3)
</span></span></code></pre></div><p>首先测试原配：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E1 -&gt; D1
</span></span><span style="display:flex;"><span>E2 -&gt; D2
</span></span><span style="display:flex;"><span>E3 -&gt; D3
</span></span></code></pre></div><p>然后交换 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>E1 -&gt; D2
</span></span><span style="display:flex;"><span>E1 -&gt; D3
</span></span><span style="display:flex;"><span>E2 -&gt; D1
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>如果原配工作、交换后明显退化，说明 encoder 与 decoder 形成了互相兼容但不必相同的内部协议。这个实验不能证明协议具有人类语义，却能比观看某个向量的 cosine 更直接地测量“双方是否共同写成了一套编码”。</p>
<p>如果交叉配对也能工作，也不是坏事。它说明架构和数据诱导出了跨 seed 相近的协议。此时再通过权重匹配或小型 adapter 判断它是公共坐标，还是可以被简单变换对齐。</p>
<hr>
<h2 id="7-如何确认它真的用了-treeheap">7. 如何确认它真的用了 TreeHeap</h2>
<p>仅有低 loss 不够，因为模型可能退化成普通数组协议。测试时保持参数不变，分别进行干预：</p>
<table>
  <thead>
      <tr>
          <th>干预</th>
          <th>测试问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>打乱 left/right 地址</td>
          <td>协议是否依赖手性与地址</td>
      </tr>
      <tr>
          <td>交换两个 subheap</td>
          <td>协议是否依赖子结构位置</td>
      </tr>
      <tr>
          <td>root 清零或换样</td>
          <td>root 是否参与当前任务</td>
      </tr>
      <tr>
          <td>逐层关闭 detail</td>
          <td>decoder 是否递归使用不同深度</td>
      </tr>
      <tr>
          <td>单独关闭每个 head</td>
          <td>哪些 head 对最终结果有因果贡献</td>
      </tr>
      <tr>
          <td>全部 head 只留一个</td>
          <td>多头收益是否来自组合，而非单个幸运 head</td>
      </tr>
      <tr>
          <td>禁止 decoder 读取原始 token</td>
          <td>排除 string 旁路</td>
      </tr>
  </tbody>
</table>
<p>记正常 loss 为 $L_0$，干预后的 loss 为 $L_I$：</p>
$$\Delta L_I=L_I-L_0$$<p>只有当结构干预稳定产生正的 $\Delta L_I$，才能说对应结构参与了协议。</p>
<p>但我们仍然不能把它翻译成“这个 head 学会了宾语”。因果参与和人类语义解释是两件事。</p>
<hr>
<h2 id="8-什么叫多-head-真正有效">8. 什么叫多 head 真正有效</h2>
<p>多 head 不能只比较最终最好的一个数字。至少要同时报告：</p>
<ol>
<li><strong>任务质量</strong>：NLL、token accuracy、BLEU 或目标任务指标；</li>
<li><strong>训练效率</strong>：达到同一验证 NLL 需要多少 token、step 和 GPU 时间；</li>
<li><strong>参数效率</strong>：相同参数量下谁更好；</li>
<li><strong>稳定性</strong>：至少三个 seed 的均值、标准差和失败尾部；</li>
<li><strong>head 因果性</strong>：逐 head 消融造成多少损失；</li>
<li><strong>组合收益</strong>：完整多头是否优于最佳单 head；</li>
<li><strong>结构收益</strong>：TreeHeap 是否优于 matched flat 和 Transformer。</li>
</ol>
<p>我们此前讨论过“head 只向前优化”。需要谨慎：非负 gate 或 ReLU 不能自动保证最终 loss 单调下降。第一轮实验不把这个性质写成事实。它只测量多个私有 kernel 是否产生稳定的组合收益。若出现 head 干扰，再单独预注册带 line search、trust region 或阶段式 boosting 的单调更新实验。</p>
<hr>
<h2 id="9-判决表">9. 判决表</h2>
<h3 id="支持">支持</h3>
<p>满足以下条件，Claim 才获得支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 多 head TreeHeap 在多个 seed 上稳定训练；
</span></span><span style="display:flex;"><span>2. 完整模型优于最佳单 head，而不是只靠一个 head；
</span></span><span style="display:flex;"><span>3. 地址、subheap、深度干预造成可重复损失；
</span></span><span style="display:flex;"><span>4. decoder 没有原始 token 或 flat memory 旁路；
</span></span><span style="display:flex;"><span>5. 在匹配预算下，相对 flat 至少出现一项稳定收益：
</span></span><span style="display:flex;"><span>   任务质量、收敛速度、参数效率或结构外推。
</span></span></code></pre></div><h3 id="部分支持">部分支持</h3>
<p>如果结构干预有效，但任务分数仍低于 flat/Transformer，则结论只能是：</p>
<blockquote>
<p>TreeHeap 私有协议真实存在并使用了结构，但当前实现尚无竞争优势。</p></blockquote>
<h3 id="拒绝或降级">拒绝或降级</h3>
<p>出现以下结果应当降级：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>地址打乱几乎不影响输出；
</span></span><span style="display:flex;"><span>多 head 等于或差于最佳单 head；
</span></span><span style="display:flex;"><span>收益完全来自参数量增加；
</span></span><span style="display:flex;"><span>decoder 通过 leaf/string 旁路完成任务；
</span></span><span style="display:flex;"><span>TreeHeap 在匹配预算下持续落后且没有外推或效率收益。
</span></span></code></pre></div><p>负结果也有价值。它会告诉我们问题究竟在多头组合、训练优化，还是 TreeHeap 归纳偏置本身。</p>
<hr>
<h2 id="10-正式实验怎样运行">10. 正式实验怎样运行</h2>
<p>正式实验已经在 <code>io</code> 的 RTX 3090 上完成。训练本体耗时 8762.91 秒，约 2 小时 26 分钟。</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th>设置</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>数据</td>
          <td>WMT massive 英文到中文真实平行语料</td>
      </tr>
      <tr>
          <td>训练 / 验证 / 测试</td>
          <td>30,000 / 2,000 / 2,000 对</td>
      </tr>
      <tr>
          <td>随机种子</td>
          <td>71901、71902、71903</td>
      </tr>
      <tr>
          <td>训练轮数</td>
          <td>每个模型 4 epoch</td>
      </tr>
      <tr>
          <td>对比模型</td>
          <td>flat、TreeHeap h1、h2、h4</td>
      </tr>
      <tr>
          <td>总协议宽度</td>
          <td>固定为 64，head 越多，每个 head 越窄</td>
      </tr>
      <tr>
          <td>参数量</td>
          <td>全部约 2730 万到 2760 万</td>
      </tr>
      <tr>
          <td>训练监督</td>
          <td>只有最终英文到中文交叉熵</td>
      </tr>
  </tbody>
</table>
<p>这里的固定总宽度很重要。h4 不是偷偷使用四倍内存，而是把同一份 64 维通信预算拆成四份。这样才能测试“多个私有协议 head 的组合”本身是否有价值。</p>
<p>原始 Stage A 没有加入 Transformer。原因不是回避对比，而是预注册时规定先选择 TreeHeap 内部的 winner。正式结果出来后，我们接受读者提出的异议：flat GRU 只是最低可行基线，不能代表成熟架构。因此又独立预注册并执行了 C02 小型 Transformer reality check。它作为追加实验单独判决，不倒过来修改 Stage A 的门槛。</p>
<hr>
<h2 id="11-第一张体检表任务质量">11. 第一张体检表：任务质量</h2>
<p>NLL 是模型给正确答案分配概率的代价，<strong>越低越好</strong>。BLEU-4 衡量生成文本和参考译文的局部词序重合，<strong>越高越好</strong>。</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">参数量</th>
          <th style="text-align: right">NLL ↓</th>
          <th style="text-align: right">BLEU-4 ↑</th>
          <th style="text-align: right">每个 seed 平均训练时间</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>flat</td>
          <td style="text-align: right">27,421,377</td>
          <td style="text-align: right"><strong>6.0401</strong></td>
          <td style="text-align: right"><strong>5.3530</strong></td>
          <td style="text-align: right"><strong>111.6 秒</strong></td>
      </tr>
      <tr>
          <td>TreeHeap h1</td>
          <td style="text-align: right">27,619,714</td>
          <td style="text-align: right">6.1231</td>
          <td style="text-align: right">4.9719</td>
          <td style="text-align: right">405.4 秒</td>
      </tr>
      <tr>
          <td>TreeHeap h2</td>
          <td style="text-align: right">27,435,395</td>
          <td style="text-align: right">6.1341</td>
          <td style="text-align: right">5.2892</td>
          <td style="text-align: right">775.6 秒</td>
      </tr>
      <tr>
          <td>TreeHeap h4</td>
          <td style="text-align: right">27,343,237</td>
          <td style="text-align: right">6.1934</td>
          <td style="text-align: right">5.0853</td>
          <td style="text-align: right">1552.2 秒</td>
      </tr>
  </tbody>
</table>
<p>这张表给出两个明确的阴性结果：</p>
<ol>
<li>h4 没有优于 h1。h4 的 NLL 反而高了 0.0703；</li>
<li>h4 没有优于 flat。h4 的 NLL 高了 0.1533，而且当前实现约慢 13.9 倍。</li>
</ol>
<p>BLEU-4 也没有反转这个判断。四种模型的 BLEU 都只有约 5 分，说明这仍是研究级小训练，不是可用的翻译产品。flat 在本轮依然最好。</p>
<p>因此，预注册的“多头带来收益”和“TreeHeap 击败 flat”都失败了。这个结果不能改写成胜利。</p>
<hr>
<h2 id="12-加测小型-transformer结果出现反转">12. 加测小型 Transformer：结果出现反转</h2>
<p>追加实验沿用完全相同的 WMT 切分和三个 seed。Transformer 使用 2 层 encoder、2 层 decoder、4 个 attention head、256 维状态和 512 维前馈层，共 <code>27,278,337</code> 个参数，与 TreeHeap h1 只差 <code>1.236%</code>。</p>
<p>我们运行了两种配方：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>same recipe：和旧实验相同，4 epoch、AdamW、固定 lr=0.002
</span></span><span style="display:flex;"><span>standard recipe：8 epoch、warmup、cosine decay、dropout=0.1、label smoothing=0.1
</span></span></code></pre></div><p>结果如下：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">NLL ↓</th>
          <th style="text-align: right">BLEU-4 ↑</th>
          <th style="text-align: right">每个 seed 平均训练时间</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>flat GRU</td>
          <td style="text-align: right"><strong>6.0401</strong></td>
          <td style="text-align: right"><strong>5.3530</strong></td>
          <td style="text-align: right">111.6 秒</td>
      </tr>
      <tr>
          <td>TreeHeap h1</td>
          <td style="text-align: right">6.1231</td>
          <td style="text-align: right">4.9719</td>
          <td style="text-align: right">405.4 秒</td>
      </tr>
      <tr>
          <td>Transformer same recipe</td>
          <td style="text-align: right">6.4423 ± 0.0062</td>
          <td style="text-align: right">2.9422 ± 0.1529</td>
          <td style="text-align: right"><strong>52.2 秒</strong></td>
      </tr>
      <tr>
          <td>Transformer standard recipe</td>
          <td style="text-align: right">6.5330 ± 0.0043</td>
          <td style="text-align: right">2.8941 ± 0.1916</td>
          <td style="text-align: right">100.8 秒</td>
      </tr>
  </tbody>
</table>
<p>这一次 TreeHeap h1 明显胜过两个小 Transformer：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>相对 same-recipe Transformer：NLL 优势 0.3192
</span></span><span style="display:flex;"><span>相对 standard-recipe Transformer：NLL 优势 0.4099
</span></span><span style="display:flex;"><span>BLEU-4 优势：约 2 分
</span></span></code></pre></div><p>因此，“TreeHeap 只是在树上更慢地实现一个更差模型”这个最悲观判断，没有得到这次小 Transformer 实验的支持。至少在 30K 数据和约 27M 参数下，TreeHeap 的任务质量处于 flat GRU 与小 Transformer 之间。</p>
<p>但这里绝不能偷换成“TreeHeap 达到了 Transformer top model”：</p>
<ol>
<li>flat GRU 仍然是质量第一名；</li>
<li>TreeHeap h1 比 flat 慢约 3.63 倍，比 same-recipe Transformer 慢约 7.77 倍；</li>
<li>所谓 standard recipe 反而比 same recipe 差，说明它不是已经调到最优的强基线；</li>
<li>standard Transformer 到第 8 epoch 时验证 NLL 还在下降，尚不能声称收敛；</li>
<li>本轮没有公开强 checkpoint，也不是标准榜单测试。</li>
</ol>
<p>所以 C02 的窄结论是：</p>
<blockquote>
<p><strong>TreeHeap 通过了本次约 27M 小 Transformer 对照，但仍未达到“行业 top model”证明标准。</strong></p></blockquote>
<hr>
<h2 id="13-第二张体检表它到底有没有使用-treeheap">13. 第二张体检表：它到底有没有使用 TreeHeap</h2>
<p>任务分数没有赢，不代表 TreeHeap 一定没被使用。我们保持模型参数不变，只破坏 H_state 的某一部分，再观察 NLL 增量：</p>
$$\Delta L=L_{\text{intervention}}-L_{\text{normal}}$$<p>$\Delta L$ 越大，说明被破坏的部分对输出越重要。</p>
<table>
  <thead>
      <tr>
          <th>干预</th>
          <th style="text-align: right">NLL 损伤</th>
          <th>解释</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>打乱输入样本</td>
          <td style="text-align: right">+1.9532</td>
          <td>decoder 明显依赖 encoder 输入</td>
      </tr>
      <tr>
          <td>交换 root</td>
          <td style="text-align: right">+2.1113</td>
          <td>root 是强因果通道，不是摆设</td>
      </tr>
      <tr>
          <td>逐深度打乱 detail</td>
          <td style="text-align: right">+0.0187 到 +0.2577</td>
          <td>6 层中 5 层超过预注册的 0.02 门槛</td>
      </tr>
      <tr>
          <td>逐深度破坏 FOLD 配对</td>
          <td style="text-align: right">约 0 到 +0.5220</td>
          <td>6 层中 5 层具有明显因果作用</td>
      </tr>
      <tr>
          <td>分别关闭四个 head</td>
          <td style="text-align: right">+0.0554 到 +0.0874</td>
          <td>四个 head 都参与了输出</td>
      </tr>
  </tbody>
</table>
<p>这说明模型没有把 TreeHeap 当作一个空壳：root、多个 detail 深度、多个 parent-child 配对以及所有四个 head 都进入了最终预测。</p>
<p>但也有一个值得注意的边界：最深的一层 detail 和 pairing 几乎没有作用。不能说“整棵树每一层都被充分利用”。当前协议使用了大量结构，但利用并不均匀。</p>
<p>更有意思的是，<strong>四个 head 每个都有效，四头整体却没有胜过一头</strong>。这意味着“有因果贡献”和“组合后更优秀”不是同一件事。可能的原因包括：</p>
<ul>
<li>固定 64 维被拆成四份后，每个 head 容量太窄；</li>
<li>四个 head 学到的是部分冗余协议；</li>
<li>当前拼接式 decoder 能读取每个 head，却不会高效组合它们；</li>
<li>递归 TreeHeap 的计算成本远高于当前 flat 实现。</li>
</ul>
<p>这些只是下一轮假设，还不是本轮证明。</p>
<hr>
<h2 id="14-第三张体检表encoder-和-decoder-是否形成私有配对">14. 第三张体检表：encoder 和 decoder 是否形成私有配对</h2>
<p>三个 seed 分别训练出了三对 encoder 和 decoder。原配正常使用，然后把不同 seed 的双方交叉连接。</p>
<table>
  <thead>
      <tr>
          <th>交换方式</th>
          <th style="text-align: right">相对 decoder 原配的 NLL 损伤</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>E71901 → D71902</td>
          <td style="text-align: right">+4.2754</td>
      </tr>
      <tr>
          <td>E71901 → D71903</td>
          <td style="text-align: right">+2.6694</td>
      </tr>
      <tr>
          <td>E71902 → D71901</td>
          <td style="text-align: right">+4.2958</td>
      </tr>
      <tr>
          <td>E71902 → D71903</td>
          <td style="text-align: right">+3.2091</td>
      </tr>
      <tr>
          <td>E71903 → D71901</td>
          <td style="text-align: right">+2.2507</td>
      </tr>
      <tr>
          <td>E71903 → D71902</td>
          <td style="text-align: right">+3.3085</td>
      </tr>
  </tbody>
</table>
<p>六次交换全部严重退化，中位损伤约为 +3.2588 NLL。这支持一个窄而明确的判断：每次训练都形成了 encoder 和 decoder 彼此兼容的私有坐标，另一组 decoder 不能直接读懂。</p>
<p>但跨 seed 不兼容并不是 TreeHeap 独有的超能力。普通神经网络也可能因为隐空间旋转或置换而不能直接交换模块。本轮真正有价值的是两类证据同时出现：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>交叉配对失败：说明 encoder 与 decoder 共同形成了协议；
</span></span><span style="display:flex;"><span>TreeHeap 干预有效：说明该协议实际经过 root、detail 和递归配对结构。
</span></span></code></pre></div><p>两者合起来，才支持“结构化 TreeHeap 私有协议存在”。它仍然不证明协议具有可读语义，更不证明 TreeHeap 优于其他神经网络。</p>
<hr>
<h2 id="15-预注册判决">15. 预注册判决</h2>
<table>
  <thead>
      <tr>
          <th>Gate</th>
          <th>结果</th>
          <th>判决依据</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>P1：所有 head 可训练</td>
          <td>通过</td>
          <td>梯度有限，所有 TreeHeap head 都收到梯度</td>
      </tr>
      <tr>
          <td>P2a：h4 优于 h1</td>
          <td><strong>失败</strong></td>
          <td>6.1934 高于 6.1231</td>
      </tr>
      <tr>
          <td>P2b：每个 h4 head 都有用</td>
          <td>通过</td>
          <td>四次消融均造成损失</td>
      </tr>
      <tr>
          <td>P3：TreeHeap 结构具有因果作用</td>
          <td>通过</td>
          <td>root、detail、pairing、head 干预通过门槛</td>
      </tr>
      <tr>
          <td>P4：形成私有或共享协议</td>
          <td>通过</td>
          <td>跨 seed 损伤远高于 0.10，属于 seed 私有协议</td>
      </tr>
      <tr>
          <td>P5：h4 优于 flat</td>
          <td><strong>失败</strong></td>
          <td>6.1934 高于 6.0401</td>
      </tr>
  </tbody>
</table>
<p>按照实验前写死的规则，最终状态只能是：</p>
<blockquote>
<p><strong>Partial：TreeHeap 私有协议真实存在，并且因果依赖其递归结构；但多头组合收益和相对 flat 的性能优势没有成立。</strong></p></blockquote>
<p>这不是“平局”。从机制问题看，我们获得了阳性证据；从竞争性能看，TreeHeap 输掉了本轮。</p>
<p>当前最合理的下一步，不是立刻增加更多 head 或扩大语料，而是先定位多头退化：比较固定每头宽度与固定总宽度、测量 head 表征冗余，并替换当前简单拼接读取。只有 h2/h4 稳定优于 h1，才值得进入 Transformer Stage B。</p>
<p>完整 ARA 证据位于：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/evidence/s3_private_protocol_battle_full/
</span></span></code></pre></div><p>三个 checkpoint 已归档到 NAS。原始日志、每 seed 结果、结构干预和交叉配对结果均保留，没有因为竞争预测失败而删除。</p>
<hr>
<h2 id="16-为什么这次不再走迷宫">16. 为什么这次不再走迷宫</h2>
<p>这一轮只回答一个问题：</p>
<blockquote>
<p><strong>已经能够形成的 TreeHeap 私有协议，在真实 seq2seq 任务上到底有没有本事？</strong></p></blockquote>
<p>不再同时讨论意识、语法标签、最低熵句子、人类可读 root、世界模型拓扑和有限比特压缩。那些问题可以保留，但不能继续挤进同一个实验。</p>
<p>实验结束后，我们只允许三种结论：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>赢：TreeHeap 在公平指标上出现稳定优势，并且结构干预证明优势来自 TreeHeap。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>平：TreeHeap 能工作且确实使用结构，但没有超过成熟基线。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>输：TreeHeap 的结构没有被使用，或者使用以后仍持续降低任务能力。
</span></span></code></pre></div><p>协议内部可以保持沉默。结果必须公开说话。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-065] NLL 6.x 不是架构天花板：30K 数据平台审计</title>
      <link>https://www.grepcode.cn/spr/065-treeheap-data-dose-platform.html</link>
      <pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate>
      <ap:updated>Tue, 21 Jul 2026 00:00:00 +0000</ap:updated>
      <guid>https://www.grepcode.cn/spr/065-treeheap-data-dose-platform.html</guid>
      <description>固定训练更新次数，把真实双语语料从 30K 扩到 1M：TreeHeap、Flat GRU 和小 Transformer 的 NLL 为何同时从 6.x 降到约 4.0，以及这对研究平台意味着什么。</description>
      <content:encoded><![CDATA[<h1 id="nll-6x-不是架构天花板30k-数据平台审计">NLL 6.x 不是架构天花板：30K 数据平台审计</h1>
<blockquote>
<p><strong>证据状态更新（2026-07-28）：数据剂量与 NLL 曲线本身保留，但其解释范围缩小。后续审计发现，同系列 teacher-forcing 目标可能主要测到“给定正确中文前缀后的续写能力”，而非英文条件翻译。本文仍证明更多独立数据改善了该训练目标，不再证明 TreeHeap 翻译能力随数据扩展。详见 SPR-074。</strong></p></blockquote>
<blockquote>
<p><code>SPR-064</code> 比较了 TreeHeap、Flat GRU 和小 Transformer。它回答了“这些模型在同一小实验里谁更好”，却没有先回答另一个基础问题：<strong>30,000 对训练语料，是否足以让任何一个模型展示真实能力？</strong> 如果实验平台本身只有 NLL 6.x、BLEU 约 3 到 5 的水平，那么模型之间相差 0.1，可能只是在比较谁更适应一个严重缺数据的平台，而不是比较架构上限。</p></blockquote>
<p>本文补上这次遗漏的数据规模实验。结论先说：</p>
<blockquote>
<p><strong>30K 不是本数据集的最优平台，更不是 TreeHeap 的能力上限。把独立训练样本增加到 1M，同时保持优化器更新次数不变，三种模型的 NLL 都从 6.x 降到了约 4.0。这个改善主要来自数据多样性，而不是 TreeHeap 独有优势。</strong></p></blockquote>
<hr>
<h2 id="1-平台问题指什么">1. “平台问题”指什么</h2>
<p>这里的“平台”不是服务器、显卡或操作系统，而是我们用来评价架构的整套实验坐标系：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数据量与数据质量
</span></span><span style="display:flex;"><span>tokenizer
</span></span><span style="display:flex;"><span>训练更新次数
</span></span><span style="display:flex;"><span>模型参数量
</span></span><span style="display:flex;"><span>优化器与学习率
</span></span><span style="display:flex;"><span>验证集和测试集
</span></span><span style="display:flex;"><span>baseline 的成熟度
</span></span><span style="display:flex;"><span>评价指标
</span></span></code></pre></div><p>假设我们造了两辆新车，却只让它们在一条泥泞、限速 10 公里的小路上比赛。两辆车都只能跑到 9 公里，不代表它们的最高速度相同；只能说明当前道路把车辆差异压住了。</p>
<p><code>SPR-064</code> 的平台大致是：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th>设置</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>训练数据</td>
          <td>30,000 对英中句子</td>
      </tr>
      <tr>
          <td>验证 / 测试</td>
          <td>2,000 / 2,000 对</td>
      </tr>
      <tr>
          <td>参数量</td>
          <td>约 2,730 万</td>
      </tr>
      <tr>
          <td>训练</td>
          <td>4 epoch</td>
      </tr>
      <tr>
          <td>TreeHeap h1 NLL</td>
          <td>6.1231</td>
      </tr>
      <tr>
          <td>Flat GRU NLL</td>
          <td>6.0401</td>
      </tr>
      <tr>
          <td>小 Transformer NLL</td>
          <td>6.4423 或 6.5330</td>
      </tr>
  </tbody>
</table>
<p>这些数字可以比较本轮模型，却不能证明“Flat 已经是数据集最优解”，也不能证明“TreeHeap 只是更慢的 Flat”。要判断平台是否压住了模型，我们需要改变数据量，同时冻结其他主要变量。</p>
<hr>
<h2 id="2-nll-6x-到底意味着什么">2. NLL 6.x 到底意味着什么</h2>
<p>NLL 是 Negative Log-Likelihood，负对数似然。对每个目标 token，模型会给整个词表分配概率。如果正确 token 的概率是 $p_t$，平均 NLL 为：</p>
$$ \operatorname{NLL}=-\frac{1}{T}\sum_{t=1}^{T}\log p_t $$<p>越低越好。常见的 PPL，也就是困惑度，为：</p>
$$ \operatorname{PPL}=e^{\operatorname{NLL}} $$<p>可以把 PPL 粗略理解成：模型在每一步面对多少个“同样有竞争力”的候选。它不是候选词的真实数量，但适合帮助理解尺度。</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">NLL</th>
          <th style="text-align: right">PPL 约为</th>
          <th>直观趋势</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">6.27</td>
          <td style="text-align: right">527</td>
          <td>非常不确定</td>
      </tr>
      <tr>
          <td style="text-align: right">5.15</td>
          <td style="text-align: right">172</td>
          <td>明显改善，但仍很宽</td>
      </tr>
      <tr>
          <td style="text-align: right">4.26</td>
          <td style="text-align: right">71</td>
          <td>候选范围继续收缩</td>
      </tr>
      <tr>
          <td style="text-align: right">4.02</td>
          <td style="text-align: right">56</td>
          <td>比 30K 平台可靠得多</td>
      </tr>
  </tbody>
</table>
<p>因此，从 NLL 6.27 降到 4.02 不是小数点上的装饰。PPL 从约 527 降到了约 56，说明模型给正确 token 的相对概率大幅提高。</p>
<p>但 NLL 也不是产品质量的完整替代。teacher forcing 下 NLL 下降，并不保证自由生成一定自然；还要结合 BLEU、样例、人工检查和真实任务评价。</p>
<hr>
<h2 id="3-为什么不能直接把数据放大再训练相同-epoch">3. 为什么不能直接把数据放大，再训练相同 epoch</h2>
<p>最简单的做法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>30K 训练 4 epoch
</span></span><span style="display:flex;"><span>1M 也训练 4 epoch
</span></span></code></pre></div><p>但这不是纯粹的数据量实验。1M 的 4 epoch 包含的优化器更新次数约为 30K 的 33 倍。结果变好以后，我们不知道原因是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>看到了更多不同句子
</span></span><span style="display:flex;"><span>还是
</span></span><span style="display:flex;"><span>只是计算了更多次梯度
</span></span></code></pre></div><p>因此，这次实验固定每组都是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>15,625 次 AdamW 更新
</span></span><span style="display:flex;"><span>batch size = 64
</span></span><span style="display:flex;"><span>总样本曝光量约 1,000,000
</span></span></code></pre></div><p>唯一主动改变的变量是<strong>独立训练句子数量</strong>：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">独立训练句对</th>
          <th style="text-align: right">每条数据平均复用次数</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">30,000</td>
          <td style="text-align: right">33.33 次</td>
      </tr>
      <tr>
          <td style="text-align: right">100,000</td>
          <td style="text-align: right">10.00 次</td>
      </tr>
      <tr>
          <td style="text-align: right">300,000</td>
          <td style="text-align: right">3.33 次</td>
      </tr>
      <tr>
          <td style="text-align: right">1,000,000</td>
          <td style="text-align: right">1.00 次</td>
      </tr>
  </tbody>
</table>
<p>30K 组反复背同一本薄练习册，1M 组把同样的一百万次阅读机会用于一百万个不同样本。这样才能较干净地测量“数据多样性”本身。</p>
<hr>
<h2 id="4-实验预注册">4. 实验预注册</h2>
<p>正式 Claim 为：</p>
<blockquote>
<p><strong>S3-PRIVATE-PROTOCOL-DATA-DOSE-C03：在优化器更新预算和验证/测试集固定时，如果 <code>SPR-064</code> 的 TreeHeap h1 主要受数据不足限制，那么独立训练句对从 30K 增加到 1M 应显著降低 held-out NLL。</strong></p></blockquote>
<p>执行前写死四条判断门槛：</p>
<ol>
<li>h1 的 1M NLL 至少比 30K 低 <code>0.10</code>。</li>
<li><code>log10(数据量)</code> 与 h1 NLL 的 Spearman 相关系数不高于 <code>-0.80</code>。</li>
<li>三次相邻扩容中，至少两次使 h1 NLL 下降。</li>
<li>所有梯度保持有限，不得用数值崩溃解释结果。</li>
</ol>
<p>Flat GRU 和参数量接近的小 Transformer 也执行相同数据剂量。这一点很重要：如果只有 TreeHeap 改善，可以怀疑 TreeHeap 特别缺数据；如果三者都改善，更合理的解释是整个平台都受数据多样性限制。</p>
<h3 id="固定变量">固定变量</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型 seed = 71901
</span></span><span style="display:flex;"><span>验证集 = 固定 2K，哈希锁定
</span></span><span style="display:flex;"><span>测试集 = 固定 2K，哈希锁定
</span></span><span style="display:flex;"><span>tokenizer = 固定 SentencePiece 模型，SHA-256 锁定
</span></span><span style="display:flex;"><span>batch = 64
</span></span><span style="display:flex;"><span>更新次数 = 15,625
</span></span><span style="display:flex;"><span>learning rate = 0.002
</span></span><span style="display:flex;"><span>验证间隔 = 500 steps
</span></span></code></pre></div><p>训练集采用嵌套设计：30K 是 100K 的子集，100K 是 300K 的子集，300K 是 1M 的子集。因此，扩容不是换一套完全不同的数据抽签。</p>
<hr>
<h2 id="5-正式结果">5. 正式结果</h2>
<p>实验在 <code>io</code> 的 RTX 3090 上运行 5.32 小时。三种模型、四档数据量共 12 个训练臂。</p>
<h3 id="test-nll">Test NLL</h3>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">30K</th>
          <th style="text-align: right">100K</th>
          <th style="text-align: right">300K</th>
          <th style="text-align: right">1M</th>
          <th style="text-align: right">30K 到 1M 改善</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap h1</td>
          <td style="text-align: right">6.2671</td>
          <td style="text-align: right">5.1454</td>
          <td style="text-align: right">4.2558</td>
          <td style="text-align: right">4.0198</td>
          <td style="text-align: right"><strong>2.2473</strong></td>
      </tr>
      <tr>
          <td>Flat GRU</td>
          <td style="text-align: right">6.0319</td>
          <td style="text-align: right">5.0532</td>
          <td style="text-align: right">4.2025</td>
          <td style="text-align: right">3.9365</td>
          <td style="text-align: right"><strong>2.0954</strong></td>
      </tr>
      <tr>
          <td>Small Transformer</td>
          <td style="text-align: right">6.5373</td>
          <td style="text-align: right">5.3375</td>
          <td style="text-align: right">4.1761</td>
          <td style="text-align: right">3.9201</td>
          <td style="text-align: right"><strong>2.6172</strong></td>
      </tr>
  </tbody>
</table>
<p>三条曲线都严格单调下降，三种模型的 Spearman 系数都是 <code>-1.0</code>。TreeHeap 的四条预注册 gate 全部通过。</p>
<h3 id="treeheap-h1-的完整体检">TreeHeap h1 的完整体检</h3>
<table>
  <thead>
      <tr>
          <th style="text-align: right">独立句对</th>
          <th style="text-align: right">最佳 step</th>
          <th style="text-align: right">Test NLL</th>
          <th style="text-align: right">PPL</th>
          <th style="text-align: right">Token BLEU-4</th>
          <th style="text-align: right">训练时间</th>
          <th style="text-align: right">峰值显存</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">30K</td>
          <td style="text-align: right">1,000</td>
          <td style="text-align: right">6.2671</td>
          <td style="text-align: right">526.9</td>
          <td style="text-align: right">5.401</td>
          <td style="text-align: right">56.9 分钟</td>
          <td style="text-align: right">1.84 GiB</td>
      </tr>
      <tr>
          <td style="text-align: right">100K</td>
          <td style="text-align: right">3,000</td>
          <td style="text-align: right">5.1454</td>
          <td style="text-align: right">171.6</td>
          <td style="text-align: right">7.778</td>
          <td style="text-align: right">57.0 分钟</td>
          <td style="text-align: right">1.85 GiB</td>
      </tr>
      <tr>
          <td style="text-align: right">300K</td>
          <td style="text-align: right">14,000</td>
          <td style="text-align: right">4.2558</td>
          <td style="text-align: right">70.5</td>
          <td style="text-align: right">11.079</td>
          <td style="text-align: right">56.7 分钟</td>
          <td style="text-align: right">1.84 GiB</td>
      </tr>
      <tr>
          <td style="text-align: right">1M</td>
          <td style="text-align: right">15,625</td>
          <td style="text-align: right">4.0198</td>
          <td style="text-align: right">55.7</td>
          <td style="text-align: right">12.085</td>
          <td style="text-align: right">56.7 分钟</td>
          <td style="text-align: right">1.84 GiB</td>
      </tr>
  </tbody>
</table>
<p>训练时间和显存基本不变，符合固定更新预算。NLL、PPL 和 BLEU 则同时随独立数据增加而改善。</p>
<hr>
<h2 id="6-30k-为什么会停在-nll-6x">6. 30K 为什么会停在 NLL 6.x</h2>
<p>最有解释力的不只是最终 NLL，而是最佳 checkpoint 出现在哪里。</p>
<p>三个 30K 模型都在第 1,000 step 达到最佳验证结果。继续把同样的 30K 数据重复到 15,625 step 后，最终验证 NLL 严重恶化：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap h1：10.7979
</span></span><span style="display:flex;"><span>Flat GRU：10.8155
</span></span><span style="display:flex;"><span>Transformer：14.7291
</span></span></code></pre></div><p>这说明 30K 不是“学到了平台最优解”，而是很快耗尽了有限样本提供的新信息，随后开始过拟合。</p>
<p>相反，1M 的 TreeHeap 和 Transformer 都在最后一个 step 才达到本轮最佳结果。它们只完整看过训练集约一次，曲线仍可能继续下降。因此，1M 的 NLL 约 4.0 也不能叫架构上限，只能叫当前固定预算下的一遍数据结果。</p>
<p>所以 <code>SPR-064</code> 中的 NLL 6.x 应重新解释为：</p>
<blockquote>
<p><strong>30K 独立样本不足以支撑约 27M 参数模型的稳定比较。重复曝光增加了计算，却不能替代新的关系证据。</strong></p></blockquote>
<p>这就是平台问题的实证答案。</p>
<hr>
<h2 id="7-treeheap-赢了吗">7. TreeHeap 赢了吗</h2>
<p>没有。</p>
<p>TreeHeap 的 NLL 从 6.2671 降到 4.0198，证明它能从新增数据中持续学习；但 Flat 和 Transformer 也同样改善。在 1M 时：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap h1 比 Flat 落后 0.0833 NLL
</span></span><span style="display:flex;"><span>TreeHeap h1 比 Transformer 落后 0.0997 NLL
</span></span></code></pre></div><p>因此最强解释是<strong>普遍的数据多样性效应</strong>，不是 TreeHeap 独有 scaling law。</p>
<p>也有一条谨慎的积极信号：TreeHeap 与最佳 baseline 的差距从 30K 时的 <code>0.2352</code>，缩小到 300K 到 1M 时约 <code>0.08</code> 到 <code>0.10</code>。这说明增加数据没有把 TreeHeap 甩开，但单 seed 不足以判断差距缩小是否稳定。</p>
<p>工程效率仍然是明确负项：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">每个数据剂量平均时间</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap h1</td>
          <td style="text-align: right">约 56.8 分钟</td>
      </tr>
      <tr>
          <td>Flat GRU</td>
          <td style="text-align: right">约 15.5 分钟</td>
      </tr>
      <tr>
          <td>Small Transformer</td>
          <td style="text-align: right">约 6.8 分钟</td>
      </tr>
  </tbody>
</table>
<p>当前 TreeHeap 比 Flat 慢约 3.7 倍，比这个小 Transformer 慢约 8.3 倍。它证明了可学习性，没有证明计算优势。</p>
<hr>
<h2 id="8-数据越多就一定越好吗">8. 数据越多就一定越好吗</h2>
<p>也不能这样下结论。</p>
<p>数据源文件声明包含约 1,417 万行、2.52 GB 文本，但样例检查发现了一些网页碎片、乱码和错位句对。例如型号页面、URL 错误页、广告文本和并不严格对应的双语句子。这些噪声不会推翻固定 split 下的 NLL 曲线，却会限制翻译产品质量。</p>
<p>数量和质量是两个不同变量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>更多不同样本
</span></span><span style="display:flex;"><span>  -&gt; 减少重复记忆，扩大关系覆盖
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>更多噪声样本
</span></span><span style="display:flex;"><span>  -&gt; 也可能教给模型错误对应和网页模板
</span></span></code></pre></div><p>这次实验只证明在当前语料排序与过滤规则下，从 30K 扩到 1M 的净收益为正。它没有证明继续扩到 14M 一定保持同一斜率，更没有证明“500 GB 才够”。</p>
<hr>
<h2 id="9-以后怎样避免平台误判">9. 以后怎样避免平台误判</h2>
<p>后续架构实验至少应同时报告四张表。</p>
<h3 id="数据卡">数据卡</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数据来源、字节数、行数
</span></span><span style="display:flex;"><span>清洗与去重规则
</span></span><span style="display:flex;"><span>训练 / 验证 / 测试哈希
</span></span><span style="display:flex;"><span>tokenizer 哈希
</span></span><span style="display:flex;"><span>长度分布和语言分布
</span></span></code></pre></div><h3 id="训练卡">训练卡</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>参数量
</span></span><span style="display:flex;"><span>optimizer / learning rate
</span></span><span style="display:flex;"><span>batch、更新次数、样本曝光量
</span></span><span style="display:flex;"><span>最佳 step 与最终 step
</span></span><span style="display:flex;"><span>GPU 时间、峰值显存
</span></span></code></pre></div><h3 id="质量曲线">质量曲线</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>NLL / PPL
</span></span><span style="display:flex;"><span>BLEU 或任务指标
</span></span><span style="display:flex;"><span>至少三个数据剂量
</span></span><span style="display:flex;"><span>至少三个随机 seed
</span></span><span style="display:flex;"><span>生成样例与人工审计
</span></span></code></pre></div><h3 id="架构归因">架构归因</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>matched Flat
</span></span><span style="display:flex;"><span>matched Transformer
</span></span><span style="display:flex;"><span>TreeHeap 地址、root、detail、head 干预
</span></span><span style="display:flex;"><span>相同数据、参数和计算预算
</span></span></code></pre></div><p>只有当 baseline 已经随着数据正常改善、主要模型接近收敛、结果跨 seed 稳定时，架构差异才有资格被解释为结构能力。</p>
<hr>
<h2 id="10-下一步判断门槛">10. 下一步判断门槛</h2>
<p>这次 Claim 的状态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数据不足假设：supported pilot
</span></span><span style="display:flex;"><span>TreeHeap 可从 1M 数据继续学习：supported pilot
</span></span><span style="display:flex;"><span>TreeHeap 优于 Flat：not supported
</span></span><span style="display:flex;"><span>TreeHeap 优于 Transformer：not supported
</span></span><span style="display:flex;"><span>通用 scaling law：未证明
</span></span><span style="display:flex;"><span>产品级翻译能力：未证明
</span></span></code></pre></div><p>下一轮不应只把数据继续堆大。更有效的实验是：</p>
<ol>
<li>对 1M 端点执行至少三个 seed，确认 <code>0.08</code> 到 <code>0.10</code> 的差距是否稳定。</li>
<li>给 1M 模型更多更新，区分“一遍数据未收敛”和“模型容量不足”。</li>
<li>建立清洗语料对照，分开测量数量收益与质量收益。</li>
<li>使用更成熟、真正收敛的小 Transformer 作为平台上限参考。</li>
<li>报告达到相同 NLL 所需的 token、step、时间和显存，而不只比较最终分数。</li>
</ol>
<p>这会把问题从“30K 谁赢了”升级为：</p>
<blockquote>
<p><strong>在足够数据和公平计算预算下，TreeHeap 是否具有不同于 Flat 与 Transformer 的学习曲线、结构因果性和外推收益？</strong></p></blockquote>
<hr>
<h2 id="11-本轮结论">11. 本轮结论</h2>
<p><code>SPR-064</code> 的架构比较没有作废，但它的适用范围必须缩小：它是一个 30K 小数据平台上的私有协议与结构因果实验，不是架构能力排名。</p>
<p>数据剂量实验给出了三个清晰结论：</p>
<ol>
<li>30K 的 NLL 6.x 主要受到数据多样性限制，不能当作数据集最优值。</li>
<li>TreeHeap、Flat 和 Transformer 都能从 1M 独立句对中获得巨大收益。</li>
<li>TreeHeap 在 1M 时接近两个 baseline，但仍更慢、NLL 仍略差，因此只证明继续航行的资格，没有证明胜利。</li>
</ol>
<p>这篇文章真正补上的，是我们的测量尺。没有足够宽的平台，架构优劣很容易被过拟合、未收敛和弱 baseline 伪装。现在至少可以确认：此前看到的 6.x 不是墙，只是 30K 这块窄甲板的边缘。</p>
<p>完整 ARA 证据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/logic/private_protocol_data_dose.md
</span></span><span style="display:flex;"><span>ara/s3-generation/evidence/s3_private_protocol_data_dose_full/
</span></span></code></pre></div><p>代码提交：<code>7bbb89c</code>；结论归档提交：<code>6182b5d</code>。实验保留 <code>config.json</code>、数据 manifest、split hash、逐步 trace、运行日志、生成样例和 <code>summary.json</code>。</p>
<p>本文与相关代码沿用项目现有开源许可证。<code>supported pilot</code> 表示受控单 seed 证据成立，不等于通用 scaling law 或产品性能承诺。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-066] TreeHeap 旋转私有协议：秩序不是假设，而是幸存结果</title>
      <link>https://www.grepcode.cn/spr/066-treeheap-rotation-private-protocol.html</link>
      <pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/066-treeheap-rotation-private-protocol.html</guid>
      <description>从指数旋转的内存风险，到固定容量 subheap 自旋，再到 8 个随机种子的结构选择实验：TreeHeap 如何把旋转变成可学习、可逆、可证伪的私有协议。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-旋转私有协议秩序不是假设而是幸存结果">TreeHeap 旋转私有协议：秩序不是假设，而是幸存结果</h1>
<blockquote>
<p>本文记录一次从危险直觉到受控实验的完整转向。最初的想法是：一棵有序树经过旋转，能否用很少的递归步骤观察很大的候选空间？实验确认这种结构可以高效复用，但也暴露出严重风险：如果把每次旋转都复制成新树，逻辑空间会指数膨胀。于是我们把架构收紧为固定容量，只允许 subheap 在原地址池内旋转。随后两个实验回答了更重要的问题：旋转能否承载 encoder-decoder 私有协议，以及有用的秩序能否在没有秩序标签时由任务自己筛选出来。</p></blockquote>
<hr>
<h2 id="1-从两个有序切片说起">1. 从两个有序切片说起</h2>
<p>先看两个很小的有序片段：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[0, 1, 2]
</span></span><span style="display:flex;"><span>[3, 4, 5]
</span></span></code></pre></div><p>它们不只是六个数字。每个片段还携带一个关系：后面的元素大于前面的元素。如果把它们分别写成有根树，再通过一个合法的组合算子连接起来，新的结构可能继续支持搜索、比较和分解。</p>
<p>这里最有价值的不是数字本身，而是<strong>秩序缩小了求解空间</strong>。如果查询目标是 <code>4</code>，我们不必逐个检查所有节点；只要每一步都能根据局部状态选择 <code>stop / left / right</code>，就可能沿一条路径坍缩到答案。</p>
<p>这给出了一个几何推理的直觉：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>局部有序结构
</span></span><span style="display:flex;"><span>  -&gt; 合法旋转或组合
</span></span><span style="display:flex;"><span>  -&gt; 更大范围仍然保留可用关系
</span></span><span style="display:flex;"><span>  -&gt; 一个局部 kernel 可以递归复用
</span></span></code></pre></div><p>但直觉里藏着两个完全不同的问题：</p>
<ol>
<li>旋转能否扩大<strong>可观察范围</strong>？</li>
<li>旋转是否必须扩大<strong>物理内存</strong>？</li>
</ol>
<p>第一件事可能有价值，第二件事必须被严格限制。</p>
<hr>
<h2 id="2-第一条路为什么危险">2. 第一条路为什么危险</h2>
<p>最初的递归构造可以写成：</p>
$$ H_{n+1}=\operatorname{CAT}\left(H_n,R_n(H_n)\right) $$<p>其中，$R_n$ 是第 $n$ 轮旋转，<code>CAT</code> 把原树和旋转后的树连接起来。若每一轮都保留两个副本，逻辑候选数近似翻倍：</p>
$$ N_n \approx 2^n N_0 $$<p>这很诱人。递归 16 次，就能描述两百多万个逻辑候选。但如果把每个候选都实体化，内存同样会迅速耗尽。一个“搜索很快”的算法，如果靠无限复制内存换取速度，并不是真正的低成本推理。</p>
<p>我们做了一个边界实验。它在规则、保序、可懒展开的旋转轨道上得到：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>最深层逻辑候选数</td>
          <td style="text-align: right">2,031,616</td>
      </tr>
      <tr>
          <td>测试查询数</td>
          <td style="text-align: right">52,898</td>
      </tr>
      <tr>
          <td>确定性查询准确率</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>学习 kernel 的 OOD 最低准确率</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>逆变换准确率</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td>最深层 TreeHeap 平均比较次数</td>
          <td style="text-align: right">20.1682</td>
      </tr>
      <tr>
          <td>无序扫描平均比较次数</td>
          <td style="text-align: right">1,014,613.8684</td>
      </tr>
      <tr>
          <td>显式存储 / 懒存储比</td>
          <td style="text-align: right">32,247.873 倍</td>
      </tr>
      <tr>
          <td>破坏秩序后的单路径准确率</td>
          <td style="text-align: right">0.0360</td>
      </tr>
  </tbody>
</table>
<p>这个结果证明了一个窄结论：<strong>规则的保序轨道可以被紧凑表示，查询工作量随递归深度线性增长。</strong></p>
<p>它没有证明“TreeHeap 免费搜索指数空间”。显式排序数组也能用对数次比较完成同类查询，只是需要保存全部数据。实验还专门设置了预算上限，超过上限时返回 <code>BUDGET_EXHAUSTED</code>，不允许继续扩容。</p>
<p>因此，指数 CAT 生长被归档为边界证据，不再作为运行时架构。我们保留旋转，删除无界复制。</p>
<hr>
<h2 id="3-固定容量旋转只能改变观察方向">3. 固定容量：旋转只能改变观察方向</h2>
<p>新的架构只有一条硬规则：系统启动时获得容量为 $C$ 的节点池，此后任何旋转都必须留在同一空间内。</p>
$$ R_{S,\phi}:\mathcal{H}_C\rightarrow\mathcal{H}_C $$<p>$S$ 是已有 subheap，$\phi$ 是一个有限、合法、可逆的地址置换。旋转前后必须满足：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>节点数不变
</span></span><span style="display:flex;"><span>容量不变
</span></span><span style="display:flex;"><span>subheap 外部状态不变
</span></span><span style="display:flex;"><span>R_inverse(R(H)) = H
</span></span><span style="display:flex;"><span>不申请新的 TreeHeap 节点
</span></span></code></pre></div><p>以最小三节点树为例：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>      A
</span></span><span style="display:flex;"><span>     / \
</span></span><span style="display:flex;"><span>    B   C
</span></span></code></pre></div><p>正常地址顺序是 <code>[A, B, C]</code>，mirror 后是 <code>[A, C, B]</code>。设局部卷积 kernel 为：</p>
$$ u=w_0 A+w_L B+w_R C $$<p>镜像后，同一个 kernel 看到的是：</p>
$$ u'=w_0 A+w_L C+w_R B $$<p>数据没有被复制，变化的是“哪个状态位于 left，哪个状态位于 right”。随后用逆置换把结果写回原坐标。这样，旋转就不再是扩容器，而是一个<strong>固定内存中的观察坐标变换</strong>。</p>
<p>整棵树上的传播写成：</p>
$$ H_{t+1}=\operatorname{ApplyAllSubheaps} \left(H_t,K_\theta,R,g\right) $$<p>其中 $K_\theta$ 是共享局部 kernel，$g$ 是是否启用某个旋转的 gate。经过 $t$ 轮，信息大约传播 $t$ 个结构跳数。增长的是感受野，不是节点池：</p>
$$ \text{space}=O(C),\qquad \text{time}=O(T_{\max}C\cdot \operatorname{cost}(K)) $$<p>$C$ 和 $T_{\max}$ 都是硬上限。达到上限仍然没有答案，就返回 <code>UNRESOLVED</code>。拿不到的解不是系统故障，而是接受有限算力的客观边界。</p>
<hr>
<h2 id="4-旋转如何成为私有协议">4. 旋转如何成为私有协议</h2>
<p>TreeHeap 的参数和运行状态需要分开说清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_state：当前样本写入后的 TreeHeap 状态
</span></span><span style="display:flex;"><span>theta：kernel、gate、读写器中的可学习参数
</span></span><span style="display:flex;"><span>R：合法的结构旋转算子
</span></span></code></pre></div><p>encoder 可以执行一段旋转程序，再通过 FOLD 把输入写进 $H_{state}$：</p>
$$ H_{state}=E_{\theta_E}(X;R_1,\ldots,R_m) $$<p>decoder 不需要让人类看懂中间状态，只要能学习对应的逆程序，再用 UNFOLD 读回目标：</p>
$$ \hat X=D_{\theta_D}(H_{state};R_1^{-1},\ldots,R_m^{-1}) $$<p>训练损失可以只看最终 echo：</p>
$$ L_{echo}=\lVert \hat X-X\rVert_2^2 $$<p>这像每个人不同的笔迹。纸上的轨迹可以不同，但只要写和读形成了稳定配对，协议就能工作。私有协议不是“无法验证”，因为我们仍能检查：原配是否成功、交叉配对是否失败、破坏一个旋转是否增大损失、地址和内存是否保持合法。</p>
<h3 id="固定协议实验">固定协议实验</h3>
<p>实验使用容量 127、每节点 4 维状态的 TreeHeap，并注册 6 个相互重叠的 subheap mirror 算子。两个 encoder 使用不同的 6-bit 旋转程序：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>程序 A = [1, 1, 0, 1, 0, 1]
</span></span><span style="display:flex;"><span>程序 B = [0, 1, 1, 0, 1, 1]
</span></span></code></pre></div><p>decoder 只有 6 个可训练 gate logit。它不知道正确程序，只能通过 echo MSE 学习逆变换。</p>
<table>
  <thead>
      <tr>
          <th>检查</th>
          <th style="text-align: right">程序 A</th>
          <th style="text-align: right">程序 B</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>学到的 bit 是否完全匹配</td>
          <td style="text-align: right">是</td>
          <td style="text-align: right">是</td>
      </tr>
      <tr>
          <td>原配 echo MSE</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
      </tr>
      <tr>
          <td>交叉协议 MSE</td>
          <td style="text-align: right">2.012999</td>
          <td style="text-align: right">2.012999</td>
      </tr>
      <tr>
          <td>单 bit 错误 MSE</td>
          <td style="text-align: right">2.012695</td>
          <td style="text-align: right">0.471290</td>
      </tr>
      <tr>
          <td>逆序执行 MSE</td>
          <td style="text-align: right">0.440443</td>
          <td style="text-align: right">0</td>
      </tr>
  </tbody>
</table>
<p>状态形状始终是 <code>[2048, 127, 4]</code>，没有增加一个节点。gate 也明显硬化：启用项约为 <code>0.995</code> 到 <code>0.997</code>，关闭项约为 <code>0.003</code>。</p>
<p>这里出现了一个重要修正。程序 A 的有效算子不交换，因此执行顺序是协议的一部分；程序 B 的有效组合恰好顺序等价，因此正序和逆序都能解码。结论不是“递归一定依赖顺序”，而是：</p>
<blockquote>
<p><strong>只有当被选中的结构算子彼此非交换时，顺序才携带额外协议信息。</strong></p></blockquote>
<p>这个实验支持“固定容量旋转可以承载私有协议”，但 encoder 程序是人工固定的。它还没有解释有用的秩序从哪里来。</p>
<hr>
<h2 id="5-echo-不会自动产生秩序">5. Echo 不会自动产生秩序</h2>
<p>这是本轮最关键的理论分界。</p>
<p>如果 encoder 使用任意可逆置换 $R$，decoder 使用精确逆变换 $R^{-1}$，那么：</p>
$$ R^{-1}(R(H))=H $$<p>不论 $R$ 是否保留父子关系，echo 都可以是零误差。因此：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>可逆性 != 秩序
</span></span><span style="display:flex;"><span>能 echo != 学会有用结构
</span></span><span style="display:flex;"><span>私有协议存在 != 私有协议具有推理价值
</span></span></code></pre></div><p>只训练 echo 时，一套漂亮的保序编码和一套完全混乱的加密式编码可能同样优秀。要让秩序出现，数据和任务必须给它提供选择压力。</p>
<p>这也修正了“旋转后天然保序”的说法。旋转只是候选操作。保序不是预设奖励，而应当是非保序候选在具体环境中表现更差以后留下的结果。</p>
<hr>
<h2 id="6-不告诉模型秩序让环境选择">6. 不告诉模型秩序，让环境选择</h2>
<p>我们构造了一个固定种群，共 24 个容量相同的候选旋转：</p>
<table>
  <thead>
      <tr>
          <th>候选组</th>
          <th style="text-align: right">数量</th>
          <th>特征</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>exact</td>
          <td style="text-align: right">6</td>
          <td>精确保留父子边的树自同构</td>
      </tr>
      <tr>
          <td>mild</td>
          <td style="text-align: right">6</td>
          <td>轻微破坏父子关系</td>
      </tr>
      <tr>
          <td>random</td>
          <td style="text-align: right">12</td>
          <td>在同一深度内随机置换</td>
      </tr>
  </tbody>
</table>
<p>训练 loss 中没有“保序”“边正确”或“路径前缀”标签。模型只需要用共享局部 decoder，根据 parent、sibling 和 children 恢复被遮住的节点。gate 根据这个预测误差选择候选旋转。</p>
<p>为了区分真正的结构选择与优化器偶然偏好，实验使用两个世界。</p>
<h3 id="结构世界">结构世界</h3>
<p>子节点与父节点相关：</p>
$$ x_{child}=\rho x_{parent}+\sqrt{1-\rho^2}\,\epsilon, \qquad \rho=0.92 $$<p>父子边保存了可用于预测的信息。破坏边会让局部 decoder 更难工作。</p>
<h3 id="iid-世界">IID 世界</h3>
<p>取 $\rho=0$，所有节点互相独立。此时父子关系没有预测价值，exact、mild 和 random 理论上应该近似打平。</p>
<p>单个 seed 的结果一度令人困惑：结构世界几乎全选 exact，但 IID 世界也把 <code>90.59%</code> 的 gate 质量压到了 exact。我们没有把它包装成成功，而是登记为 7/8 gate 通过，并怀疑 gate 与 decoder 的共同训练产生了“先领先者锁死”的中性漂移。</p>
<p>随后按预注册方案运行 8 个随机种子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1, 7, 19, 42, 73, 99, 314, 2026
</span></span></code></pre></div><h3 id="8-seed-结果">8-seed 结果</h3>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
          <th>应如何理解</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>结构世界 exact winner</td>
          <td style="text-align: right">8 / 8</td>
          <td>每个 seed 都选择保边变换</td>
      </tr>
      <tr>
          <td>结构世界 exact gate mass 均值</td>
          <td style="text-align: right">0.999657</td>
          <td>质量几乎全部集中到 exact 组</td>
      </tr>
      <tr>
          <td>结构世界 exact gate mass 最小值</td>
          <td style="text-align: right">0.999215</td>
          <td>最差 seed 仍超过 99.92%</td>
      </tr>
      <tr>
          <td>边保留率与 loss 的 Pearson</td>
          <td style="text-align: right">-0.997404</td>
          <td>越保边，loss 越低</td>
      </tr>
      <tr>
          <td>IID winner 分布</td>
          <td style="text-align: right">2 exact / 1 mild / 5 random</td>
          <td>没有稳定偏爱 exact</td>
      </tr>
      <tr>
          <td>IID exact gate mass 均值</td>
          <td style="text-align: right">0.283272</td>
          <td>接近初始占比 6/24 = 0.25</td>
      </tr>
      <tr>
          <td>IID exact-random loss 差</td>
          <td style="text-align: right">0.000992</td>
          <td>三组实际上近似打平</td>
      </tr>
      <tr>
          <td>IID 边保留率与 loss 的 Pearson</td>
          <td style="text-align: right">-0.018631</td>
          <td>无结构关系</td>
      </tr>
      <tr>
          <td>exact echo 最大逆变换误差</td>
          <td style="text-align: right">0</td>
          <td>所有可逆协议都能无损 echo</td>
      </tr>
  </tbody>
</table>
<p>九条预注册 gate 全部通过。</p>
<p>这个结果支持的不是“宇宙天然喜欢二叉树”，而是一个更具体的命题：</p>
<blockquote>
<p><strong>当数据的可预测关系沿 TreeHeap 父子边传播时，不含秩序标签的任务损失会稳定淘汰破坏这些关系的旋转；当数据没有这种关系时，选择退化为中性漂移。</strong></p></blockquote>
<p>这里的“秩序”不是数字升序，而是父子边、路径前缀和局部关系得到保存。秩序成为知识，是因为它减少了预测不确定性。</p>
<hr>
<h2 id="7-这与-encoderdecoder-有什么关系">7. 这与 encoder、decoder 有什么关系</h2>
<p>现在可以把三段证据连起来：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>固定容量旋转
</span></span><span style="display:flex;"><span>  -&gt; 提供有限、可逆的结构编码候选
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo loss
</span></span><span style="display:flex;"><span>  -&gt; 让 encoder 与 decoder 学会彼此兼容的私有写法
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>结构预测 loss
</span></span><span style="display:flex;"><span>  -&gt; 从多种可逆写法中筛掉破坏有用关系的写法
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>剩下的旋转程序
</span></span><span style="display:flex;"><span>  -&gt; 成为既可解码、又保留任务相关结构的私有协议
</span></span></code></pre></div><p>这比“人工规定左边是主语、右边是宾语”更接近我们一直寻找的涌现路径。研究者规定的只是有限内存、合法算子、可微 gate 和任务；具体协议由 encoder 与 decoder 联合形成，结构价值由数据检验。</p>
<p>它也解释了为什么只做 token echo 不够。echo 负责<strong>可读回</strong>，结构预测负责<strong>读回之前不要把有用关系打乱</strong>。两者缺一不可。</p>
<hr>
<h2 id="8-当前证据没有证明什么">8. 当前证据没有证明什么</h2>
<p>这轮结果很强，但边界同样明确：</p>
<ol>
<li>候选旋转来自固定的 24 个算子，模型还没有自己发明新的旋转公式。</li>
<li>数据是 Gaussian tree world，不是真实语言、图像或世界模型。</li>
<li>exact 候选保留的是给定父子边，不代表现实任务一定应该使用这棵树。</li>
<li>实验没有证明 TreeHeap 比 Transformer、MLP、图网络或经典数据结构更快。</li>
<li>两百万逻辑候选实验不适用于密码破解，也不构成对加密算法的威胁证据。</li>
<li>旋转扩大的是固定内存中的观察范围，不允许解释为无限算力或无限答案。</li>
</ol>
<p>尤其需要避免一个新的循环论证：先人工构造“正确树”，再证明保留这棵树最好。下一阶段必须让树的 placement、compose 与旋转共同面对真实数据，而不是把正确结构偷偷写进输入。</p>
<hr>
<h2 id="9-下一阶段让语言决定哪种旋转活下来">9. 下一阶段：让语言决定哪种旋转活下来</h2>
<p>下一条可证伪路线应保持固定容量，不再申请外部 TreeHeap 内存：</p>
<ol>
<li>从真实语料生成 $H_{state}$，禁止 decoder 旁路读取原字符串。</li>
<li>注册一组有限的 subheap 旋转和不同递归深度，仍不提供语法标签。</li>
<li>使用 echo、上下文预测或 seq2seq loss 联合训练 encoder gate 与 decoder。</li>
<li>比较结构候选、随机同深度置换和不旋转 baseline。</li>
<li>在训练后审计父子边、路径前缀、地址复用、OOD 深度与推理成本。</li>
<li>检查不同 seed 是否选择稳定关系，而不是复现一次 winner lock-in。</li>
</ol>
<p>预期不应写成“语言必然选择 mirror”。更谨慎的 predict 是：</p>
<blockquote>
<p>若 TreeHeap 的局部关系与语料中的可预测关系对齐，则结构保持更好的旋转程序应获得更低验证 loss、更稳定的多 seed 选择，以及更好的未见深度或未见地址外推；若随机置换同样有效，则旋转私有协议没有提供额外结构价值。</p></blockquote>
<p>这条 predict 同时允许成功和失败。失败时，我们应该修改 placement、FOLD 或候选算子，而不是继续扩大内存寻找答案。</p>
<hr>
<h2 id="10-航行结论">10. 航行结论</h2>
<p>这轮工作把一个容易失控的想法变成了有限工程对象：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>旧想法：旋转一次，复制一个新空间
</span></span><span style="display:flex;"><span>新设计：旋转一次，重排固定 subheap
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>旧假设：合法旋转天然保序
</span></span><span style="display:flex;"><span>新结论：可逆旋转只是候选，秩序必须被任务选择
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>旧证据：echo 可以恢复输入
</span></span><span style="display:flex;"><span>新证据：echo 证明私有协议，结构预测证明协议保留有用关系
</span></span></code></pre></div><p>TreeHeap 旋转目前已经有三层受控证据：可逆、固定容量、可学习配对；非交换组合可以携带顺序；结构化环境会在多 seed 中稳定选择保留关系的候选。它还不是语言 encoder，也不是完成的智能系统，但已经不再只是一个几何比喻。</p>
<p>更重要的是，我们接受了一条工程伦理：一个算法越容易让人想无限递归，越需要先写死容量、轮数和失败返回值。有限不是遗憾。有限使实验可以复现，使系统可以停止，也使真正的结构收益不再被无限内存掩盖。</p>
<p>ARA 代码、预注册和原始 evidence 保存在 SameTime 仓库的以下目录：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/bounded_rotation_search_probe/
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/fixed_capacity_rotation_protocol_probe/
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/rotation_selection_evolution_probe/
</span></span><span style="display:flex;"><span>ara/m0-treeheap-math/evidence/rotation_selection_multiseed_probe/
</span></span></code></pre></div><p>对应提交：<code>8cf183d</code>、<code>f97f136</code>、<code>b2af86a</code>。项目公开仓库为 <a href="https://github.com/houming818/sametime">houming818/sametime</a>。</p>
<p>本文与相关代码沿用项目现有开源许可证。实验数字是受控 toy evidence，不应脱离边界宣传为真实语言、通用推理或密码学能力。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-067] STONE-1 正式体检：树地址成立，私有协议尚未学会</title>
      <link>https://www.grepcode.cn/spr/067-stone1-private-protocol-formal-result.html</link>
      <pubDate>Wed, 22 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/067-stone1-private-protocol-formal-result.html</guid>
      <description>一百万对真实英中语料、三颗随机种子、九次正式训练：STONE-1 为什么证明了 TreeHeap 地址的因果作用，却否定了当前 hard gate 私有协议配方。</description>
      <content:encoded><![CDATA[<h1 id="stone-1-正式体检树地址成立私有协议尚未学会">STONE-1 正式体检：树地址成立，私有协议尚未学会</h1>
<blockquote>
<p><strong>证据状态更新（2026-07-28）：STONE-1 的完成判定与“英文语义进入 TreeHeap”的推断暂停。C10 代码审计发现，teacher forcing 和大面积可见 EOS 尾部没有被既有 gate 排除。地址交换造成 NLL 损伤，仍能证明 decoder 使用了某些树状态；它不能单独证明这些状态携带英文条件语义。详见 SPR-074。</strong></p></blockquote>
<blockquote>
<p>这是一篇正式实验报告，也是一份“架构体检单”。STONE-1 在 io 的 RTX 3090 上连续运行约 7.57 小时，完成了 3 种结构方案、3 颗随机种子、共 9 次训练。程序没有崩溃，checkpoint 和 CLI 都成功产出，但核心 Claim 没有通过。更准确地说：<strong>模型确实依赖 TreeHeap 的左右地址和层级秩序；然而当前的可学习方向 gate 没有形成比固定结构更好的 encoder-decoder 私有协议。</strong></p></blockquote>
<p>这不是“TreeHeap 已经失败”，也不是“再多跑几天就一定成功”。它把两个长期混在一起的问题第一次拆开了：</p>
<ol>
<li>TreeHeap 的结构有没有进入模型计算？有，而且因果信号很强。</li>
<li>当前 kernel 是否学会了有价值的内部编码协议？没有，固定 identity 反而更好。</li>
</ol>
<p>本文从头解释实验设计、指标、数据、结果和下一步。没有读过前 66 篇文章，也可以独立阅读。</p>
<hr>
<h2 id="1-我们到底想证明什么">1. 我们到底想证明什么</h2>
<p>普通 seq2seq 模型可以把输入句子编码成一组向量，再从这些向量生成输出。只看最终翻译，我们不知道中间状态究竟是一棵 TreeHeap，还是一条换了名字的数组。</p>
<p>STONE-1 因此提出了一个比“能翻译”更严格的目标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>英文 token
</span></span><span style="display:flex;"><span>  -&gt; 递归 FOLD
</span></span><span style="display:flex;"><span>  -&gt; 固定容量 TreeHeap H_state
</span></span><span style="display:flex;"><span>  -&gt; 递归 UNFOLD / 多层读取
</span></span><span style="display:flex;"><span>  -&gt; 中文 decoder
</span></span><span style="display:flex;"><span>  -&gt; 非 teacher-forcing 生成
</span></span></code></pre></div><p>其中没有额外的句法标签、旋转标签或“这里应该向左”的答案。模型只能根据最终翻译损失，通过梯度自己决定内部如何编码。</p>
<p>我们希望看到的现象是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned structural
</span></span><span style="display:flex;"><span>  比固定 identity 更好
</span></span><span style="display:flex;"><span>  比固定 random 更好
</span></span><span style="display:flex;"><span>  改掉 learned gate 会明显变差
</span></span><span style="display:flex;"><span>  破坏左右地址也会明显变差
</span></span></code></pre></div><p>如果只满足最后一条，只能证明“地址有用”，不能证明“learned gate 学会了私有协议”。这一区分是整场实验的核心。</p>
<hr>
<h2 id="2-什么叫-encoder-decoder-私有协议">2. 什么叫 encoder-decoder 私有协议</h2>
<p>先用一个生活例子。</p>
<p>两个人可以约定：写字时把重要内容放在纸张左侧，补充内容放在右侧。只要写的人和读的人使用同一规则，外人不需要看懂这种布局，信息也能正确传递。</p>
<p>对模型而言，这个约定不必是人类可读的“主语、谓语、宾语”。它可以是训练自行形成的内部协议：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder 决定怎样折叠和摆放信息
</span></span><span style="display:flex;"><span>decoder 学会怎样读取这种摆放
</span></span><span style="display:flex;"><span>最终任务 loss 同时约束两者
</span></span></code></pre></div><p>这里的 <code>private</code> 不是加密，而是“模型内部自洽，不要求人类手写”。</p>
<p>如果这种协议真的存在，那么强制改用另一套左右选择规则，decoder 应该像拿到错误的字典一样，性能明显下降。反过来，如果随便替换 gate 都几乎没影响，就不能说这个 gate 承载了关键协议。</p>
<hr>
<h2 id="3-treeheap-状态是怎样折叠的">3. TreeHeap 状态是怎样折叠的</h2>
<p>STONE-1 使用固定宽度为 64 的二叉 TreeHeap。句子的 token embedding 放在 leaf 层，然后两两递归合并：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>64 leaves
</span></span><span style="display:flex;"><span> -&gt; 32 parents
</span></span><span style="display:flex;"><span> -&gt; 16 parents
</span></span><span style="display:flex;"><span> -&gt; 8
</span></span><span style="display:flex;"><span> -&gt; 4
</span></span><span style="display:flex;"><span> -&gt; 2
</span></span><span style="display:flex;"><span> -&gt; 1 root
</span></span></code></pre></div><p>每次局部 FOLD 只看一对子节点 <code>left</code> 和 <code>right</code>。系统包含两个可学习函数：</p>
<ul>
<li><code>P</code>：根据 anchor 预测另一侧状态；</li>
<li><code>U</code>：把预测残差更新到 parent。</li>
</ul>
<p>当左侧作为 anchor 时：</p>
\[ d = R-P(L) \]\[ H_{parent}=L+U(d) \]<p>这里的 <code>detail</code>，也就是 \(d\)，保存“右侧相对左侧还缺少什么”。UNFOLD 时执行：</p>
\[ L=H_{parent}-U(d) \]\[ R=d+P(L) \]<p>如果右侧作为 anchor，公式左右对换。一个二值 gate \(g\) 决定方向：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>g = 1: left 是 anchor
</span></span><span style="display:flex;"><span>g = 0: right 是 anchor
</span></span></code></pre></div><p>这样做的好处是，FOLD 与 UNFOLD 在数学设计上成对出现。树向上压缩时保存 parent、detail 和方向；树向下展开时使用同一组信息恢复各层状态。</p>
<p>需要注意：这不是无损压缩整个字符串的产品算法。decoder 看不到最终 leaf 层，只能读取 root 和被允许的压缩层。我们故意关闭了最直接的 token 旁路，迫使翻译至少经过一次结构折叠。</p>
<hr>
<h2 id="4-learned-kernel-学什么">4. learned kernel 学什么</h2>
<p>局部方向 kernel 的输入为：</p>
\[ x=[L, R, L-R, L\odot R] \]<p>其中 \(L\odot R\) 是逐元素乘积。kernel 是一个小型两层网络：</p>
\[ p=\sigma(K_{\theta}(x)+b_{depth}) \]<p>\(p\) 是选择左 anchor 的概率。前向计算把它硬化成 0 或 1，反向传播使用 straight-through estimator，让梯度近似穿过这个离散选择。</p>
<p>同一个 kernel 在整棵树上共享，只额外携带每个深度的 bias。这符合我们此前对 TreeHeap 卷积的要求：<strong>不是为每个地址单独训练一张表，而是让同一个局部算子沿树递归复用。</strong></p>
<p>但是，这种设计也有风险。decoder 正在学习怎样读取内部坐标时，gate 同时在改变内部坐标。就像一个人学习地图期间，地图的东西方向还在变化。STONE-1 正是要用对照实验判断：这种自由度究竟形成协议，还是只增加优化噪声。</p>
<hr>
<h2 id="5-为什么必须有三种实验臂">5. 为什么必须有三种实验臂</h2>
<p>三种模型参数规模相同，训练数据、优化器、步数和 decoder 都相同。唯一变化是局部方向：</p>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th>方向规则</th>
          <th>它回答的问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>identity</code></td>
          <td>所有有效节点固定使用左 anchor</td>
          <td>稳定、规范的坐标系有多强？</td>
      </tr>
      <tr>
          <td><code>learned_structural</code></td>
          <td>kernel 根据内容和深度学习 0/1</td>
          <td>学习方向是否带来额外收益？</td>
      </tr>
      <tr>
          <td><code>frozen_random</code></td>
          <td>固定的地址/深度随机 pattern</td>
          <td>只要规则稳定，任意坐标是否也能工作？</td>
      </tr>
  </tbody>
</table>
<p>这里最容易误解的是 random。</p>
<p><code>frozen_random</code> 不是每一步重新掷骰子。它在训练开始前生成一个固定 pattern，此后永远不变。因此 decoder 有机会适应这套奇怪但稳定的坐标系。如果 learned 连 frozen random 都不能击败，问题很可能不是“树不能放信息”，而是“训练时持续变化的方向没有形成稳定协议”。</p>
<hr>
<h2 id="6-数据和训练合同">6. 数据和训练合同</h2>
<p>正式实验在结果出现前就锁定了配置，不能看完数字再修改及格线：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th style="text-align: right">正式设置</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>数据源</td>
          <td style="text-align: right">WMT-massive 英中 TSV</td>
      </tr>
      <tr>
          <td>原始声明行数</td>
          <td style="text-align: right">14,170,275</td>
      </tr>
      <tr>
          <td>独立训练样本</td>
          <td style="text-align: right">1,000,000</td>
      </tr>
      <tr>
          <td>验证 / 测试</td>
          <td style="text-align: right">2,000 / 2,000</td>
      </tr>
      <tr>
          <td>句长过滤</td>
          <td style="text-align: right">8 到 32 token</td>
      </tr>
      <tr>
          <td>tokenizer</td>
          <td style="text-align: right">32K SentencePiece BPE</td>
      </tr>
      <tr>
          <td>每个实验臂随机种子</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td>总训练臂</td>
          <td style="text-align: right">9</td>
      </tr>
      <tr>
          <td>batch size</td>
          <td style="text-align: right">64</td>
      </tr>
      <tr>
          <td>每臂更新</td>
          <td style="text-align: right">15,625</td>
      </tr>
      <tr>
          <td>每臂参数量</td>
          <td style="text-align: right">27,769,097</td>
      </tr>
      <tr>
          <td>heap width</td>
          <td style="text-align: right">64</td>
      </tr>
      <tr>
          <td>GPU</td>
          <td style="text-align: right">RTX 3090</td>
      </tr>
  </tbody>
</table>
<p>训练、验证和测试内容经过 hash 检查，没有交叉泄漏。正式任务运行 <code>27,268.44</code> 秒，也就是约 <code>7.57</code> 小时，退出码为 0，<code>stderr.log</code> 为空。</p>
<p>因此，后面的负结果不是程序崩溃、GPU 掉卡、测试集泄漏或某个文件没有加载造成的。</p>
<hr>
<h2 id="7-先学会看-nll-和-bleu">7. 先学会看 NLL 和 BLEU</h2>
<h3 id="71-nll模型给正确答案多少概率">7.1 NLL：模型给正确答案多少概率</h3>
<p>假设正确 token 是 \(y_t\)，模型给它的概率是 \(p(y_t)\)，平均负对数似然为：</p>
\[ \operatorname{NLL}=-\frac{1}{T}\sum_{t=1}^{T}\log p(y_t) \]<p>NLL 越小越好。它不是“错误百分比”，而是模型对正确答案分配概率的总体成本。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型 A 给正确词概率 0.50 -&gt; -log(0.50) 约 0.69
</span></span><span style="display:flex;"><span>模型 B 给正确词概率 0.10 -&gt; -log(0.10) 约 2.30
</span></span></code></pre></div><p>模型 A 的 NLL 更低，说明它更确信正确答案。</p>
<h3 id="72-bleu-4生成句和参考句有多少局部片段重合">7.2 BLEU-4：生成句和参考句有多少局部片段重合</h3>
<p>BLEU-4 检查 1 到 4 token 片段的重合情况，并惩罚过短输出。它越高越好，但不是语义理解的完整评价。两个意思相近、措辞不同的句子，BLEU 可能仍然不高。</p>
<p>本实验使用 token BLEU-4，主要用来防止一种假进步：teacher-forcing NLL 下降了，但模型自由生成时仍然是空字符串或重复乱码。</p>
<h3 id="73-标准差换颗随机种子还可靠吗">7.3 标准差：换颗随机种子还可靠吗</h3>
<p>同一程序从不同随机初始化出发，结果可能不同。三颗种子的 NLL 标准差越小，说明方案越稳定。</p>
<p>STONE-1 预注册的主要产品目标是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned mean NLL &lt;= 3.90
</span></span><span style="display:flex;"><span>learned BLEU-4   &gt;= 13.5
</span></span><span style="display:flex;"><span>NLL 标准差       &lt;= 0.05
</span></span><span style="display:flex;"><span>非空生成率        = 1.00
</span></span><span style="display:flex;"><span>严重重复率        &lt;= 0.10
</span></span></code></pre></div><hr>
<h2 id="8-正式结果identity-赢了">8. 正式结果：identity 赢了</h2>
<p>三颗种子的平均结果如下：</p>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th style="text-align: right">Test NLL，越低越好</th>
          <th style="text-align: right">NLL 标准差</th>
          <th style="text-align: right">BLEU-4，越高越好</th>
          <th style="text-align: right">严重重复率</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>identity</td>
          <td style="text-align: right"><strong>4.0719</strong></td>
          <td style="text-align: right"><strong>0.0058</strong></td>
          <td style="text-align: right"><strong>11.1735</strong></td>
          <td style="text-align: right"><strong>0.0397</strong></td>
      </tr>
      <tr>
          <td>learned structural</td>
          <td style="text-align: right">4.2269</td>
          <td style="text-align: right">0.1125</td>
          <td style="text-align: right">9.7875</td>
          <td style="text-align: right">0.0558</td>
      </tr>
      <tr>
          <td>frozen random</td>
          <td style="text-align: right">4.1210</td>
          <td style="text-align: right">0.0106</td>
          <td style="text-align: right">10.7198</td>
          <td style="text-align: right">0.0430</td>
      </tr>
  </tbody>
</table>
<p>learned 相对 identity 的 NLL 差值是：</p>
\[ 4.2269-4.0719=+0.1550 \]<p>正数意味着 learned 更差。它相对 frozen random 也差 <code>+0.1059</code>。</p>
<p>这不是一颗坏种子造成的。逐种子比较：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Seed</th>
          <th style="text-align: right">identity NLL</th>
          <th style="text-align: right">learned NLL</th>
          <th style="text-align: right">random NLL</th>
          <th style="text-align: right">learned - identity</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">71901</td>
          <td style="text-align: right">4.0799</td>
          <td style="text-align: right">4.3858</td>
          <td style="text-align: right">4.1359</td>
          <td style="text-align: right">+0.3059</td>
      </tr>
      <tr>
          <td style="text-align: right">71902</td>
          <td style="text-align: right">4.0691</td>
          <td style="text-align: right">4.1538</td>
          <td style="text-align: right">4.1121</td>
          <td style="text-align: right">+0.0847</td>
      </tr>
      <tr>
          <td style="text-align: right">71903</td>
          <td style="text-align: right">4.0666</td>
          <td style="text-align: right">4.1411</td>
          <td style="text-align: right">4.1149</td>
          <td style="text-align: right">+0.0746</td>
      </tr>
  </tbody>
</table>
<p>三颗种子全部是 identity 最好，learned 最差。seed 71901 的 learned 出现了明显失败尾部，使 learned 的标准差达到 <code>0.1125</code>，超过预注册上限两倍以上。</p>
<p>所以第一层结论很明确：</p>
<blockquote>
<p><strong>在这一百万样本、一步训练遍历、hard straight-through gate 的配方中，可学习方向没有改善翻译，反而降低了平均质量和稳定性。</strong></p></blockquote>
<hr>
<h2 id="9-但是模型真的用了树地址">9. 但是模型真的用了树地址</h2>
<p>只看上表，可能会得出一个过快结论：“TreeHeap 没有用。”干预实验否定了这种说法。</p>
<p>我们取 learned seed 71903 的最佳 checkpoint，在测试时主动改变内部结构：</p>
<table>
  <thead>
      <tr>
          <th>干预</th>
          <th style="text-align: right">NLL</th>
          <th style="text-align: right">相对正常模型的损伤</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>正常 learned</td>
          <td style="text-align: right">4.1411</td>
          <td style="text-align: right">0</td>
      </tr>
      <tr>
          <td>强制全部 identity</td>
          <td style="text-align: right">4.1293</td>
          <td style="text-align: right"><strong>-0.0118，反而改善</strong></td>
      </tr>
      <tr>
          <td>强制 frozen random</td>
          <td style="text-align: right">4.1446</td>
          <td style="text-align: right">+0.0034，几乎无变化</td>
      </tr>
      <tr>
          <td>交换每层 left/right 地址</td>
          <td style="text-align: right">5.6359</td>
          <td style="text-align: right"><strong>+1.4948，严重损坏</strong></td>
      </tr>
  </tbody>
</table>
<p>NLL 从 <code>4.1411</code> 上升到 <code>5.6359</code> 不是轻微波动。对应的困惑度从约 <code>62.87</code> 上升到 <code>280.32</code>。</p>
<p>这说明 decoder 不是把所有内部节点当成无序 word bag。它确实区分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个状态在左地址
</span></span><span style="display:flex;"><span>那个状态在右地址
</span></span><span style="display:flex;"><span>这个节点位于哪一层
</span></span></code></pre></div><p>一旦整体交换左右地址，decoder 原来学到的读取方式就失效了。</p>
<p>但另外两项干预同样关键：把 learned gate 替换成 identity 不但没有伤害，反而稍有改善；替换成 random 也几乎不痛。这说明<strong>地址是协议的一部分，而 learned gate 不是当前协议中不可替代的一部分。</strong></p>
<p>可以把它类比成一座图书馆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>书架编号非常重要，全部左右互换会让读者找不到书；
</span></span><span style="display:flex;"><span>但管理员训练出来的临时摆书策略并没有比固定规则更好。
</span></span></code></pre></div><hr>
<h2 id="10-gate-内部发生了什么">10. gate 内部发生了什么</h2>
<p>learned gate 没有完全随机。它显示出一个很有信息量的模式：</p>
<ul>
<li>靠近 root 的深层 gate 大量饱和到固定方向；</li>
<li>部分浅层 gate 仍然有较高概率熵；</li>
<li>不同 seed 的硬方向比例差异明显；</li>
<li>最终策略整体在接近 identity，但保留了一批不稳定的局部翻转。</li>
</ul>
<p>例如 seed 71903：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">FOLD 深度</th>
          <th style="text-align: right">左 anchor 概率均值</th>
          <th style="text-align: right">概率熵</th>
          <th style="text-align: right">硬 left 比例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0.5274</td>
          <td style="text-align: right">0.6554</td>
          <td style="text-align: right">0.7334</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td style="text-align: right">0.5520</td>
          <td style="text-align: right">0.6224</td>
          <td style="text-align: right">0.9971</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">0.6098</td>
          <td style="text-align: right">0.5426</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td style="text-align: right">0.6093</td>
          <td style="text-align: right">0.5415</td>
          <td style="text-align: right">0.7070</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">0.9812</td>
          <td style="text-align: right">0.0792</td>
          <td style="text-align: right">1.0000</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">0.9881</td>
          <td style="text-align: right">0.0085</td>
          <td style="text-align: right">0.9844</td>
      </tr>
  </tbody>
</table>
<p>概率熵接近 <code>0.69</code> 表示接近五五开，接近 0 表示几乎完全确定。表中浅层仍有较大不确定性，深层则接近固定 left。</p>
<p>一种与证据相容的机制解释是：</p>
<ol>
<li>identity 从训练第一步起就是稳定坐标系；</li>
<li>frozen random 虽然奇怪，但也从第一步起不变；</li>
<li>learned gate 随参数更新不断改变部分局部坐标；</li>
<li>decoder 一边学读取，一边面对坐标变化；</li>
<li>最后 gate 大体退回 identity，但训练已经付出了额外优化成本。</li>
</ol>
<p>这是<strong>机制诊断</strong>，还不是新 Claim。要证明“移动坐标系是根因”，下一轮必须记录 gate 随训练时间的翻转率，并用稳定化对照直接验证，而不能只凭最终统计讲故事。</p>
<hr>
<h2 id="11-foldunfold-闭包通过了吗">11. FOLD/UNFOLD 闭包通过了吗</h2>
<p>从均方误差看，闭包非常接近精确：约 <code>1e-13</code>。也就是说，把状态 FOLD 后再 UNFOLD，绝大部分数值可以恢复到浮点精度附近。</p>
<p>但我们预注册了更严格的最大绝对误差门槛：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>closure_max_abs &lt; 1e-5
</span></span></code></pre></div><p>learned 的三颗种子分别约为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>2.15e-5
</span></span><span style="display:flex;"><span>0.51e-5
</span></span><span style="display:flex;"><span>2.86e-5
</span></span></code></pre></div><p>其中两颗超过阈值，所以结构门 S6 必须记为失败。我们不能在看到结果后说“其实 <code>3e-5</code> 也差不多”，然后修改及格线。</p>
<p>从工程判断看，这更像 float32 多层运算积累的尾部误差，而不是 FOLD/UNFOLD 已经失去逆运算关系。但要让它成为可靠数学工具，下一轮仍应加入 float64 审计、误差随深度的增长曲线，以及确定性的闭包单元测试。</p>
<hr>
<h2 id="12-生成效果到了什么水平">12. 生成效果到了什么水平</h2>
<p>learned checkpoint 能由 CLI 加载，能够在没有 teacher forcing 的情况下生成非空输出。它不是只会返回 loss 的实验脚本。</p>
<p>一个例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：Integrated, standards-based certification labeling and reporting
</span></span><span style="display:flex;"><span>参考：集成的、基于标准的认证标签和报告
</span></span><span style="display:flex;"><span>输出：合规性、基于标准、报告和报告
</span></span></code></pre></div><p>可以看到，模型已经抓住了“标准、报告”等局部对应关系，句子也不是完全随机字符；但它丢失了“认证标签”，并重复了“报告”。</p>
<p>另一个例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：Requested URL: /FixedCamera/ANF24A.aspx
</span></span><span style="display:flex;"><span>参考：请求的 URL : / ProList.aspx
</span></span><span style="display:flex;"><span>输出：请求的 URL : / newslist.aspx
</span></span></code></pre></div><p>它学会了网页错误文本的常见模板，却没有忠实复制路径。这也反映了训练语料的现实问题：WMT-massive 中含有网页片段、产品表、错配双语和 mojibake。模型可以学习统计形式，但这些数据不等于高质量翻译知识。</p>
<p>工程指标倒是全部通过：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
          <th style="text-align: right">门槛</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>batch-1 greedy P50</td>
          <td style="text-align: right">27.42 ms</td>
          <td style="text-align: right">&lt;= 1,000 ms</td>
      </tr>
      <tr>
          <td>峰值显存</td>
          <td style="text-align: right">约 1.70 GiB</td>
          <td style="text-align: right">&lt;= 4 GiB</td>
      </tr>
      <tr>
          <td>checkpoint</td>
          <td style="text-align: right">111,087,481 bytes</td>
          <td style="text-align: right">&lt;= 300 MiB</td>
      </tr>
      <tr>
          <td>非空生成率</td>
          <td style="text-align: right">1.00</td>
          <td style="text-align: right">= 1.00</td>
      </tr>
      <tr>
          <td>严重重复率</td>
          <td style="text-align: right">0.0558</td>
          <td style="text-align: right">&lt;= 0.10</td>
      </tr>
  </tbody>
</table>
<p>因此它是一个可运行的研究 CLI，不是一个达到质量里程碑的翻译产品。</p>
<hr>
<h2 id="13-像体检报告一样读最终裁决">13. 像体检报告一样读最终裁决</h2>
<p>STONE-1 把门槛分为三组：</p>
<table>
  <thead>
      <tr>
          <th>维度</th>
          <th style="text-align: right">通过情况</th>
          <th>体检解释</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>产品质量 Q</td>
          <td style="text-align: right">2 / 5</td>
          <td>能生成，但 NLL、BLEU、稳定性未达标</td>
      </tr>
      <tr>
          <td>结构证据 S</td>
          <td style="text-align: right">1 / 6</td>
          <td>地址因果成立，learned gate 协议不成立</td>
      </tr>
      <tr>
          <td>工程可用 E</td>
          <td style="text-align: right">5 / 5</td>
          <td>运行、显存、延迟、checkpoint、CLI 正常</td>
      </tr>
  </tbody>
</table>
<p>最终状态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>not_supported_under_recipe
</span></span></code></pre></div><p>中文不是“整个项目失败”，而是：</p>
<blockquote>
<p><strong>在预先规定的这份配方下，STONE-1 的完整 Claim 不成立。</strong></p></blockquote>
<p>具体地说：</p>
<h3 id="已有正向证据">已有正向证据</h3>
<ol>
<li>固定容量 TreeHeap 可以完成真实英中 seq2seq 训练与生成。</li>
<li>decoder 对 left/right 地址高度敏感。</li>
<li>递归 FOLD/UNFOLD 数值上接近闭合。</li>
<li>一百万样本、九次训练的工程流程稳定完成。</li>
<li>identity 和 frozen random 的低方差说明稳定结构可以被 decoder 学习。</li>
</ol>
<h3 id="被本实验否定的部分">被本实验否定的部分</h3>
<ol>
<li>hard learned direction gate 会自然击败固定 identity。</li>
<li>learned gate 会自然击败固定 random。</li>
<li>强行替换 learned gate 会造成明显性能损失。</li>
<li>当前 checkpoint 达到 NLL <code>3.90</code> 和 BLEU <code>13.5</code> 的工程目标。</li>
<li>三颗随机种子已经形成稳定一致的 learned protocol。</li>
</ol>
<h3 id="本实验根本没有证明的事">本实验根本没有证明的事</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 已具备开放对话能力
</span></span><span style="display:flex;"><span>TreeHeap 已学会世界模型
</span></span><span style="display:flex;"><span>root 具有人类可读语义
</span></span><span style="display:flex;"><span>内部旋转等价于意识活动
</span></span><span style="display:flex;"><span>TreeHeap 优于工业规模 Transformer
</span></span><span style="display:flex;"><span>继续扩数据一定能修复 learned gate
</span></span></code></pre></div><p>把这些边界写清楚，不是削弱研究，而是保护后续工作不被过强故事带偏。</p>
<hr>
<h2 id="14-为什么这个负结果反而推进了理论">14. 为什么这个负结果反而推进了理论</h2>
<p>在实验前，我们容易把下面两件事当成同一件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型使用树结构
</span></span><span style="display:flex;"><span>=
</span></span><span style="display:flex;"><span>模型学会了树上的私有协议
</span></span></code></pre></div><p>STONE-1 证明它们不是一回事。</p>
<p>地址交换造成巨大损失，说明树的结构坐标已经参与预测；learned gate 可以被替换，说明“可学习局部方向”还不是有用协议。换句话说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 是有效载体
</span></span><span style="display:flex;"><span>不等于
</span></span><span style="display:flex;"><span>任意可学习算子都会自动成为有效编码协议
</span></span></code></pre></div><p>这与 Transformer 研究中的一个朴素事实一致：可微、参数多、能够反向传播，只能保证“可以优化”；不能保证某个自由度一定被任务识别、一定产生独特功能。</p>
<p>本轮还暴露出一个更深的数学问题：局部左右方向近似一种 \(\mathbb{Z}_2\) 选择，也就是每个节点都有“保持/翻转”两种等价表示。如果任务 loss 无法稳定识别哪种表示更优，这个自由度就可能成为 gauge freedom，而不是知识。identity 相当于先固定一个规范坐标，训练自然更容易。</p>
<p>因此，私有协议不应只定义“模型可以选择什么”，还要定义：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>什么信号让某个选择比另一个选择更有价值？
</span></span><span style="display:flex;"><span>这个选择何时稳定下来？
</span></span><span style="display:flex;"><span>decoder 如何持续看见同一套坐标？
</span></span><span style="display:flex;"><span>压缩收益怎样抵消结构选择的优化成本？
</span></span></code></pre></div><p>这正是下一轮 Claim 应该回答的内容。</p>
<hr>
<h2 id="15-下一步不应该只是再跑久一点">15. 下一步不应该只是“再跑久一点”</h2>
<p>大部分实验臂在最后一次或倒数一次评估取得最好 NLL，说明绝对质量可能尚未完全收敛。继续训练有可能让 identity、random 和 learned 全部改善。</p>
<p>但当前没有证据表明 learned 会反超。简单把相同配方从一轮数据改成十轮，只会花更多 GPU 时间回答一个不够尖锐的问题。</p>
<p>更合理的下一轮应先定位“移动坐标”假设。可以预注册三个对照：</p>
<h3 id="a-identity-warm-up">A. identity warm-up</h3>
<p>训练前期固定 identity，让 encoder-decoder 先建立稳定读取协议；后期才开放 gate。</p>
<h3 id="b-soft-to-hard-annealing">B. soft-to-hard annealing</h3>
<p>早期使用连续 gate，让结构缓慢变化；温度逐步降低，最后才坍缩为 0/1。</p>
<h3 id="c-alternating-freeze">C. alternating freeze</h3>
<p>固定 decoder，短暂训练 gate；再固定 gate，训练 decoder。这样可以区分“gate 没有价值”和“两边同时移动导致学不会”。</p>
<p>下一轮必须额外记录：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>每层 gate 的翻转率随 step 如何变化
</span></span><span style="display:flex;"><span>同一句话跨 checkpoint 的结构地址是否稳定
</span></span><span style="display:flex;"><span>固定 gate 后 decoder 是否快速恢复
</span></span><span style="display:flex;"><span>开放 gate 是否真的降低验证 NLL
</span></span><span style="display:flex;"><span>学习到的结构是否比 identity 节省读取成本或改善泛化
</span></span></code></pre></div><p>只有这些 predict 通过，才能把“移动坐标是根因”升级为 Claim。</p>
<hr>
<h2 id="16-可复现材料">16. 可复现材料</h2>
<p>实验 Claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S3-STONE1-PRIVATE-PROTOCOL-C01
</span></span></code></pre></div><p>代码与 ARA：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/src/s3_stone1_private_protocol.py
</span></span><span style="display:flex;"><span>ara/s3-generation/src/treeheap_cli.py
</span></span><span style="display:flex;"><span>ara/s3-generation/logic/stone1_private_protocol_translation.md
</span></span><span style="display:flex;"><span>ara/s3-generation/evidence/s3_stone1_private_protocol/
</span></span></code></pre></div><p>正式证据目录包含：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>REPORT.md
</span></span><span style="display:flex;"><span>REVIEW.md
</span></span><span style="display:flex;"><span>summary.json
</span></span><span style="display:flex;"><span>runs.json
</span></span><span style="display:flex;"><span>interventions.json
</span></span><span style="display:flex;"><span>trace.jsonl
</span></span><span style="display:flex;"><span>dataset_manifest.json
</span></span><span style="display:flex;"><span>config.json
</span></span><span style="display:flex;"><span>command.sh
</span></span><span style="display:flex;"><span>stdout.log
</span></span><span style="display:flex;"><span>stderr.log
</span></span><span style="display:flex;"><span>cli_smoke.json
</span></span><span style="display:flex;"><span>runner_status.json
</span></span></code></pre></div><p>代码和证据已提交到 SameTime 的 <code>experiment/private-protocol-battle</code> 分支，正式结果提交为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>c07077b ara: record STONE-1 formal result
</span></span></code></pre></div><p>demo checkpoint 保存在 io，大小 <code>111,087,481</code> bytes，SHA-256：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>732b9b367a1c473d790a46dfca8698d41608453ab965c747c33639d889c76d56
</span></span></code></pre></div><hr>
<h2 id="17-结论">17. 结论</h2>
<p>STONE-1 没有达到我们预注册的完整目标，但它给出了一条比模糊乐观更有价值的分界线：</p>
<blockquote>
<p><strong>TreeHeap 的左右地址已经是翻译模型的因果变量；当前 hard straight-through 方向 gate 还不是有效私有协议。</strong></p></blockquote>
<p>identity 最好，不意味着 TreeHeap 只能固定不动。它意味着在要求结构自由生长之前，我们必须给模型一个能够形成稳定共同语言的学习过程。一个合法、可逆、可微的算子，只是候选工具；只有当任务干预证明模型离不开它时，它才成为协议。</p>
<p>这艘船没有沉。它只是第一次用正式仪器测出：发动机在转，方向舵还没有接上传动轴。</p>
<blockquote>
<p><strong>License: GPLv3。本文中的 TreeHeap 私有协议、实验设计、数据表述和 ARA 结论按项目许可证公开，欢迎复现、批评和提出反证。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-068] 参数不是越多越好：TreeHeap 私有协议的容量与失真</title>
      <link>https://www.grepcode.cn/spr/068-treeheap-capacity-rate-distortion.html</link>
      <pubDate>Wed, 22 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/068-treeheap-capacity-rate-distortion.html</guid>
      <description>把模型参数理解为私有协议的有限存储空间：解释 2762 万参数的 TreeHeap 为什么可能失真，并预注册 28M 长训练与 50M 扩容对照。</description>
      <content:encoded><![CDATA[<h1 id="参数不是越多越好treeheap-私有协议的容量与失真">参数不是越多越好：TreeHeap 私有协议的容量与失真</h1>
<blockquote>
<p><strong>证据状态更新（2026-07-28）：本文的参数量、NLL 与计算成本记录仍有效，但 NLL 只能暂时解释为 teacher-forced 条件续写失真。由于英文 source 依赖尚未通过打乱与空输入审计，本文不能据此测量“翻译私有协议”的容量。详见 SPR-074。</strong></p></blockquote>
<blockquote>
<p>一个模型要把训练数据中的规律压缩进有限参数，究竟需要多大空间？扩大 TreeHeap 参数，究竟是在增加可复用规律的容量，还是只是在增加一张更大的记忆表？</p></blockquote>
<p>STONE-1 C02 刚完成正式实验。模型确实使用了 TreeHeap 的左右地址、递归层级和可学习 codec，但仍没有达到产品门槛。</p>
<p>这时最容易说：“再加参数试试。”</p>
<p>这可能是对的，也可能非常危险。参数过少会失真，参数过多也可能记住训练样本而不再泛化。我们要找的不是最大模型，而是：</p>
<blockquote>
<p><strong>在给定信息范围和目标失真下，TreeHeap 私有协议需要的合理容量。</strong></p></blockquote>
<hr>
<h2 id="1-刚完成的-c02">1. 刚完成的 C02</h2>
<p>C02 使用一百万对真实英中训练句、三颗随机种子，比较三种 TreeHeap codec：</p>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th style="text-align: right">平均 NLL，越低越好</th>
          <th style="text-align: right">BLEU-4，越高越好</th>
          <th style="text-align: right">NLL 标准差</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>固定 0.4/0.6 代数核</td>
          <td style="text-align: right">4.1138</td>
          <td style="text-align: right">10.7937</td>
          <td style="text-align: right">0.0119</td>
      </tr>
      <tr>
          <td>可学习连续残差核</td>
          <td style="text-align: right"><strong>4.0538</strong></td>
          <td style="text-align: right"><strong>11.2865</strong></td>
          <td style="text-align: right">0.0914</td>
      </tr>
      <tr>
          <td>固定随机残差核</td>
          <td style="text-align: right">4.0910</td>
          <td style="text-align: right">10.6865</td>
          <td style="text-align: right"><strong>0.0093</strong></td>
      </tr>
  </tbody>
</table>
<p>可学习版本平均最好，但一颗随机种子明显退化。它没有通过 STONE-1 产品线：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">门槛</th>
          <th style="text-align: right">实际</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>NLL</td>
          <td style="text-align: right">不高于 3.90</td>
          <td style="text-align: right">4.0538</td>
      </tr>
      <tr>
          <td>BLEU-4</td>
          <td style="text-align: right">不低于 13.5</td>
          <td style="text-align: right">11.2865</td>
      </tr>
      <tr>
          <td>NLL 标准差</td>
          <td style="text-align: right">不高于 0.05</td>
          <td style="text-align: right">0.0914</td>
      </tr>
  </tbody>
</table>
<p>所以正式结论仍然是：<strong>C02 未通过，STONE-1 没有完成。</strong></p>
<p>但这不是“树没用”的结果。</p>
<hr>
<h2 id="2-递归结构确实进入了计算">2. 递归结构确实进入了计算</h2>
<p>把训练形成的连续残差关掉，强制退回固定代数核，NLL 从 3.9876 恶化到 5.0860，损伤为 1.0984。</p>
<p>把每一层的 left/right 地址交换，NLL 恶化到 5.3420，损伤为 1.3545。</p>
<p>让同一个 checkpoint 逐层看到更细的 TreeHeap 状态：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">可见层数</th>
          <th style="text-align: right">NLL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1，只看 root</td>
          <td style="text-align: right">4.6366</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">4.6250</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td style="text-align: right">4.3886</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">4.1860</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">4.0401</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right"><strong>3.9876</strong></td>
      </tr>
  </tbody>
</table>
<p>五次增加层级，五次都改善。root 到完整压缩状态改善了 0.6491 NLL。</p>
<p>我们可以确认：</p>
<ol>
<li>TreeHeap 层级中保存了增量信息；</li>
<li>decoder 会递归读取这些信息；</li>
<li>左右地址参与读取协议；</li>
<li>learned codec 改变了内部协议。</li>
</ol>
<p>但“协议存在”不等于“协议容量已经足够”。</p>
<hr>
<h2 id="3-参数是私有协议的压缩介质">3. 参数是私有协议的压缩介质</h2>
<p>训练前，参数只是一组初始化数值。训练时，样本产生 loss，loss 产生梯度，梯度不断修改参数。</p>
<p>长期看，这相当于把训练数据中的可复用规律压缩进参数：</p>
<p>训练数据 → loss → gradient → 参数 Theta → 私有协议</p>
<p>模型不可能逐条原样保存全部语言情况。它必须寻找共享规律。例如 eat rice、eat noodles、eat medicine 可能共享“动作与可食用对象”的统计结构。</p>
<p>这个结构未必能被人类直接读懂；encoder 和 decoder 只要形成同一套协议，就能共同使用它。</p>
<h3 id="容量太小">容量太小</h3>
<p>不同规律被迫挤进同一组参数，相互干扰，类似 hash 碰撞。模型只能保存粗轮廓，罕见模式和细节容易失真。</p>
<h3 id="容量太大而数据不足">容量太大而数据不足</h3>
<p>模型可能为训练样本留下大量独立记忆位置，不再被迫寻找公共规律。训练 loss 很低，测试集却不改善。</p>
<p>所以，参数既不是越少越先进，也不是越多越智能。</p>
<hr>
<h2 id="4-用率失真理解模型大小">4. 用率失真理解模型大小</h2>
<p>设 C 是模型容量，D 是模型压缩数据规律后的失真，NLL 是本实验的主要失真指标：</p>
$$ \min_{\theta} D(\mathrm{data},\mathrm{model}_{\theta}) \quad \mathrm{subject\ to} \quad |\theta| \le C $$<p>它问的是：在容量有限时，模型最多能把输出分布逼近到什么程度？</p>
<p>当前 learned TreeHeap 的平均 NLL 是 4.0538 nats/token。换成二进制信息单位：</p>
$$ \frac{4.0538}{\ln 2} \approx 5.85\ \mathrm{bits/token} $$<p>STONE-1 的 NLL 门槛 3.90 对应：</p>
$$ \frac{3.90}{\ln 2} \approx 5.63\ \mathrm{bits/token} $$<p>当前还差约 0.22 bits/token。这些失真可能来自容量不足、训练不足、数据问题或协议缺陷。只扩大模型，不能自动区分它们。</p>
<hr>
<h2 id="5-2762-万参数花在哪里">5. 2762 万参数花在哪里</h2>
<p>当前模型共有 27,620,482 个参数。FP32 原始参数约 110,481,928 bytes，checkpoint 约 110.5 MB。</p>
<table>
  <thead>
      <tr>
          <th>部分</th>
          <th style="text-align: right">参数量</th>
          <th style="text-align: right">占比</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token embedding 与输出投影</td>
          <td style="text-align: right">26,656,833</td>
          <td style="text-align: right">约 96.5%</td>
      </tr>
      <tr>
          <td>learned TreeHeap codec</td>
          <td style="text-align: right">296,832</td>
          <td style="text-align: right">约 1.1%</td>
      </tr>
      <tr>
          <td>recursive READ、GRU 等</td>
          <td style="text-align: right">666,817</td>
          <td style="text-align: right">约 2.4%</td>
      </tr>
  </tbody>
</table>
<p>如果把整个模型扩大到 50M，大部分新增参数仍进入 embedding、输出投影和 decoder。它测试的是<strong>整个 TreeHeap seq2seq 系统的容量</strong>，不能偷换成“codec 参数增加后更好”。</p>
<p>同样，Qwen 或 Kimi 覆盖的知识、语言、模态和任务范围远大于当前英中翻译实验。它们的参数规模不能直接成为 TreeHeap 的答案。</p>
<p>我们现在只问：</p>
<blockquote>
<p>对这一百万对英中句子和当前 STONE-1 协议，2762 万参数是不是主要失真来源？</p></blockquote>
<hr>
<h2 id="6-为什么不能只跑一个-50m">6. 为什么不能只跑一个 50M</h2>
<p>如果 50M 变好，至少有两种解释：</p>
<ol>
<li>更大容量保存了更多规律；</li>
<li>28M 本来只需要多训练一轮。</li>
</ol>
<p>C02 中，多数最佳 checkpoint 出现在最后一步，说明训练可能还没有完全到达平台。如果没有“原模型训练更久”的对照，我们无法判断扩容是否必要。</p>
<hr>
<h2 id="7-c03-的容量实验">7. C03 的容量实验</h2>
<p>数据、随机种子、TreeHeap 结构、tokenizer、优化器和评测全部冻结。模型仍从零训练，不加载历史 checkpoint。</p>
<h3 id="三个容量点">三个容量点</h3>
<table>
  <thead>
      <tr>
          <th>名称</th>
          <th style="text-align: right">状态宽度 D</th>
          <th style="text-align: right">decoder hidden H</th>
          <th style="text-align: right">参数量</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>base_28m</td>
          <td style="text-align: right">192</td>
          <td style="text-align: right">256</td>
          <td style="text-align: right">27,620,482</td>
      </tr>
      <tr>
          <td>balanced_50m</td>
          <td style="text-align: right">320</td>
          <td style="text-align: right">512</td>
          <td style="text-align: right">50,267,778</td>
      </tr>
      <tr>
          <td>balanced_92m</td>
          <td style="text-align: right">512</td>
          <td style="text-align: right">1024</td>
          <td style="text-align: right">91,931,906</td>
      </tr>
  </tbody>
</table>
<p>下一轮不会立刻跑完三档。</p>
<h3 id="stage-a分清容量和训练时间">Stage A：分清容量和训练时间</h3>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th style="text-align: right">参数量</th>
          <th style="text-align: right">更新步数</th>
          <th>回答的问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>已完成 base_28m</td>
          <td style="text-align: right">27.62M</td>
          <td style="text-align: right">15,625</td>
          <td>当前基线</td>
      </tr>
      <tr>
          <td>新增 base_28m_long</td>
          <td style="text-align: right">27.62M</td>
          <td style="text-align: right">31,250</td>
          <td>同一模型多训练一轮</td>
      </tr>
      <tr>
          <td>新增 balanced_50m_equal</td>
          <td style="text-align: right">50.27M</td>
          <td style="text-align: right">15,625</td>
          <td>相同曝光下增加容量</td>
      </tr>
  </tbody>
</table>
<p>三颗随机种子都要跑，不能只挑最好的一颗。</p>
<hr>
<h2 id="8-什么结果才支持容量不足">8. 什么结果才支持容量不足</h2>
<p>50M 至少需要满足：</p>
<table>
  <thead>
      <tr>
          <th>条件</th>
          <th style="text-align: right">门槛</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>相对当前 28M 的平均 NLL 改善</td>
          <td style="text-align: right">至少 0.08</td>
      </tr>
      <tr>
          <td>平均 BLEU-4 改善</td>
          <td style="text-align: right">至少 0.75</td>
      </tr>
      <tr>
          <td>三 seed NLL 标准差</td>
          <td style="text-align: right">不高于 0.08</td>
      </tr>
  </tbody>
</table>
<p>还必须保留 TreeHeap 结构证据：</p>
<table>
  <thead>
      <tr>
          <th>结构检查</th>
          <th style="text-align: right">门槛</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>关闭 learned codec 的损伤</td>
          <td style="text-align: right">至少 0.10 NLL</td>
      </tr>
      <tr>
          <td>交换左右地址的损伤</td>
          <td style="text-align: right">至少 0.10 NLL</td>
      </tr>
      <tr>
          <td>root 到 full 的改善</td>
          <td style="text-align: right">至少 0.50 NLL</td>
      </tr>
      <tr>
          <td>增加深度有改善</td>
          <td style="text-align: right">至少 4/5 次</td>
      </tr>
      <tr>
          <td>最大闭包误差</td>
          <td style="text-align: right">小于 1e-5</td>
      </tr>
  </tbody>
</table>
<p>结果解释提前冻结：</p>
<ul>
<li>28M-long 追上 50M：主要缺训练时间；</li>
<li>50M 跨 seed 改善：容量不足得到支持；</li>
<li>训练集改善、测试集不改善：过拟合或数据受限；</li>
<li>质量改善但结构因果消失：大模型绕开了 TreeHeap；</li>
<li>两个新实验都不改善：停止扩容，回到协议设计。</li>
</ul>
<p>STONE-1 原产品门槛不移动。通过容量测试不等于里程碑自动完成。</p>
<hr>
<h2 id="9-92m-为什么暂时不跑">9. 92M 为什么暂时不跑</h2>
<p>92M 是条件实验。只有 50M 同时表现出明确 held-out 改善、稳定性没有恶化、结构因果仍然存在，才进入 92M。</p>
<p>届时要观察：</p>
<p>28M → 50M → 92M，失真是否稳定下降？单位新增参数的收益是否开始衰减？</p>
<p>如果 50M 已无可靠收益，就没有理由让 3090 再花几十小时证明同一个失败。</p>
<hr>
<h2 id="10-最终寻找的是膝点">10. 最终寻找的是膝点</h2>
<p>合理参数规模应同时满足：</p>
<ol>
<li>质量达到任务要求；</li>
<li>不同 seed 稳定；</li>
<li>TreeHeap 结构因果仍存在；</li>
<li>参数与计算成本可承担；</li>
<li>继续扩容的边际收益已经很小。</li>
</ol>
<p>当前我们已经知道结构参与了解码，却不知道剩余失真来自容量还是训练不足。下一轮用 28M-long 对照 50M-equal，正是为了回答这个问题。</p>
<blockquote>
<p><strong>我们不是盲目造一个更大的 TreeHeap，而是在测量：这套私有协议在当前数据范围内，究竟需要多少空间，才能以可接受失真稳定存在。</strong></p></blockquote>
<p>本文的 Claim、Predict、证伪条件与后续 evidence 按 ARA 流程公开记录。TreeHeap 与本文容量审计设计属于 SameTime/ARA 持续研究的一部分，使用项目仓库声明的许可证公开，欢迎人类与 AI 复核、复现和提出反例。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-069] STONE-1 航行报告：Encoder 已经抽水，Decoder 水压终于接通</title>
      <link>https://www.grepcode.cn/spr/069-stone1-encoder-decoder-pressure.html</link>
      <pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/069-stone1-encoder-decoder-pressure.html</guid>
      <description>从 C01 到 C05 复盘 STONE-1：TreeHeap encoder 如何把路径信息压入 root，为什么 decoder 长期只读 root，以及冻结 encoder、强制打开递归水管后得到的正式证据。</description>
      <content:encoded><![CDATA[<h1 id="stone-1-航行报告encoder-已经抽水decoder-水压终于接通">STONE-1 航行报告：Encoder 已经抽水，Decoder 水压终于接通</h1>
<blockquote>
<p><strong>证据状态更新（2026-07-28）：水压、深度梯度和 detail-shuffle 结果保留为机制诊断，但“Encoder 已经抽入英文语义”尚未被证明。teacher-forced decoder 可能使用目标前缀，同时只把 TreeHeap 当作弱偏置。本文所有翻译与私有协议外推暂停，等待 source-shuffle、empty-source 和 first-step-logit 审计。详见 SPR-074。</strong></p></blockquote>
<blockquote>
<p>STONE-1 还没有完成，但我们终于把一个长期混在一起的问题拆开了：不是 TreeHeap 深层没有信息，而是 decoder 的递归水管一直没有获得有效梯度。</p></blockquote>
<p>这篇文章总结 STONE-1 从 C01 到 C05 的进展。</p>
<p>我们先给出最重要的结论：</p>
<ol>
<li>TreeHeap encoder 确实执行了有左右顺序的递归折叠；</li>
<li>训练得到的 root 不是简单词袋，而是路径敏感的压缩状态；</li>
<li>原生 decoder 长期只读 root，继续增加训练步数也没有自行打开深层路径；</li>
<li>冻结 encoder、强制打开递归路径后，decoder 能学会读取深层信息；</li>
<li>在同等追加训练预算下，递归读取最终略好于 root-only；</li>
<li>但读取深度仍然是人为固定的，所以 STONE-1 仍未完成。</li>
</ol>
<p>这不是终点，但它把下一步从“继续猜架构”推进到了一个很具体的工程问题：</p>
<blockquote>
<p><strong>如何让 decoder 在保证梯度通道畅通的前提下，自己学习何时停止、何时继续向下读取。</strong></p></blockquote>
<hr>
<h2 id="1-stone-1-到底想证明什么">1. STONE-1 到底想证明什么</h2>
<p>普通 seq2seq 模型可以把输入编码成一个向量，然后用神经网络生成输出。仅仅把这个向量放进数组的第零项，再给它取名叫 TreeHeap，并不能证明树结构有用。</p>
<p>STONE-1 要求更严格：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入 token
</span></span><span style="display:flex;"><span>  → 写入 TreeHeap leaf
</span></span><span style="display:flex;"><span>  → 逐层 FOLD
</span></span><span style="display:flex;"><span>  → 形成 root 与各层 detail
</span></span><span style="display:flex;"><span>  → decoder 按 TreeHeap 层级读取
</span></span><span style="display:flex;"><span>  → 生成目标句子
</span></span></code></pre></div><p>其中至少需要回答三个问题。</p>
<h3 id="11-encoder-是否真的使用树">1.1 Encoder 是否真的使用树</h3>
<p>如果交换 left/right、破坏某层配对或替换 FOLD kernel，最终结果应当发生可测变化。</p>
<h3 id="12-decoder-是否真的读取树">1.2 Decoder 是否真的读取树</h3>
<p>如果打乱 decoder 正在读取的 detail 或地址，生成损失应当恶化。</p>
<h3 id="13-使用树是否带来功能收益">1.3 使用树是否带来功能收益</h3>
<p>结构参与计算还不够。递归读取至少应当达到 root-only 对照的水平，最好带来更低 NLL、更高 BLEU 或更稳定的生成。</p>
<p>STONE-1 不是“代码能跑”的里程碑，而是这三类证据必须同时成立。</p>
<hr>
<h2 id="2-什么叫-encoder-抽水机">2. 什么叫 Encoder 抽水机</h2>
<p>一棵二叉 TreeHeap 的叶子保存局部 token 状态：</p>
$$ H^{(0)}_1,H^{(0)}_2,\ldots,H^{(0)}_n $$<p>相邻左右节点经过同一个局部 FOLD kernel：</p>
$$ \left(H^{(d+1)}_i,D^{(d)}_i\right) = \operatorname{FOLD}_{\theta} \left(H^{(d)}_{2i},H^{(d)}_{2i+1}\right) $$<p>这里：</p>
<ul>
<li>$H^{(d+1)}_i$ 是向上一层传递的 parent 状态；</li>
<li>$D^{(d)}_i$ 是这一层留下的 detail；</li>
<li>$\theta$ 是可学习 codec 参数；</li>
<li>left/right 地址和递归顺序是固定的 TreeHeap 数学骨架。</li>
</ul>
<p>不断递归之后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf → parent → grandparent → root
</span></span></code></pre></div><p>这就是我们所说的信息抽水机。</p>
<p>“抽水”不意味着 root 能无损保存所有 token。它表示局部信息通过同一种递归规则逐层汇聚。root 更像一个高压压缩状态，各层 detail 保存折叠过程中没有继续上传的差异。</p>
<p>完整状态不是只有 root：</p>
$$ H_{\text{state}} = \left( H_{\text{root}}, D^{(0)},D^{(1)},\ldots,D^{(L-1)} \right) $$<p>因此，讨论 TreeHeap 时必须区分：</p>
<ul>
<li><code>root</code>：最高层压缩结果；</li>
<li><code>H_state</code>：root 加全部层级 detail；</li>
<li><code>theta</code>：执行 FOLD、READ 和生成的学习参数。</li>
</ul>
<hr>
<h2 id="3-c01-到-c04我们排除了什么">3. C01 到 C04：我们排除了什么</h2>
<h3 id="c01自由学习方向没有形成稳定协议">C01：自由学习方向没有形成稳定协议</h3>
<p>C01 让模型自由学习局部方向 gate。结果 learned 版本反而弱于 identity 和 frozen-random 对照。</p>
<p>但交换左右地址会明显损伤 NLL。这说明：</p>
<blockquote>
<p>地址有用，但自由漂移的坐标协议不稳定。</p></blockquote>
<p>所以后续采用固定手性和固定代数骨架，不再让左右方向本身随意变化。</p>
<h3 id="c02固定骨架加可学习残差">C02：固定骨架加可学习残差</h3>
<p>C02 使用固定的 <code>0.4/0.6</code> parent 规则和可学习连续残差。learned codec 的平均结果优于固定代数和固定随机对照：</p>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th style="text-align: right">NLL，越低越好</th>
          <th style="text-align: right">BLEU-4，越高越好</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>固定代数 codec</td>
          <td style="text-align: right">4.1138</td>
          <td style="text-align: right">10.7937</td>
      </tr>
      <tr>
          <td>可学习残差 codec</td>
          <td style="text-align: right"><strong>4.0538</strong></td>
          <td style="text-align: right"><strong>11.2865</strong></td>
      </tr>
      <tr>
          <td>固定随机 codec</td>
          <td style="text-align: right">4.0910</td>
          <td style="text-align: right">10.6865</td>
      </tr>
  </tbody>
</table>
<p>结构干预也产生明显损伤。C02 支持 codec、地址和层级参与计算，但多 seed 稳定性和产品质量仍未通过。</p>
<h3 id="c03直接扩大参数失败">C03：直接扩大参数失败</h3>
<p>C03 比较约 28M 和 50M 参数。相同更新预算下，50M 没有更好：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">NLL</th>
          <th style="text-align: right">BLEU-4</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>28M，延长训练</td>
          <td style="text-align: right"><strong>3.7495</strong></td>
          <td style="text-align: right"><strong>12.7444</strong></td>
      </tr>
      <tr>
          <td>50M，相同更新预算</td>
          <td style="text-align: right">4.1469</td>
          <td style="text-align: right">10.1225</td>
      </tr>
  </tbody>
</table>
<p>这否定了“参数越大，私有协议自然越完整”的简单假设。</p>
<p>更重要的是，50M decoder 的 route mass 全部停在 root。root-only 与 full-depth 的结果相同，root 形成后再交换 child 地址也没有影响。</p>
<p>当时我们只能确认 decoder 没有读取 child，却不能确认 encoder 是否把路径信息压进了 root。</p>
<h3 id="c04更多训练没有打开-decoder">C04：更多训练没有打开 Decoder</h3>
<p>C04 把同一个 50.27M 模型连续训练到 62,500 次更新：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Update</th>
          <th style="text-align: right">Valid NLL</th>
          <th style="text-align: right">非 root route mass</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">15,625</td>
          <td style="text-align: right">4.1879</td>
          <td style="text-align: right">0</td>
      </tr>
      <tr>
          <td style="text-align: right">31,250</td>
          <td style="text-align: right">3.8867</td>
          <td style="text-align: right">0</td>
      </tr>
      <tr>
          <td style="text-align: right">46,875</td>
          <td style="text-align: right">3.7331</td>
          <td style="text-align: right">约 0</td>
      </tr>
      <tr>
          <td style="text-align: right">62,500</td>
          <td style="text-align: right">3.6613</td>
          <td style="text-align: right">约 0</td>
      </tr>
  </tbody>
</table>
<p>训练质量持续改善，但 decoder 始终只读 root。</p>
<p>因此，“只是训练时间不够”被否定了。</p>
<hr>
<h2 id="4-c04-的关键证据root-不是词袋">4. C04 的关键证据：Root 不是词袋</h2>
<p>如果在 root 已经形成后交换下层 child，NLL 没有变化。这只能说明 decoder 没读 child，不能说明 encoder 没用路径。</p>
<p>C04 增加了一个更严格的干预：</p>
<blockquote>
<p>在某一层 FOLD <strong>之前</strong>交换左右 subheap，然后重新计算上层状态和 root。</p></blockquote>
<p>最终 62,500 步 checkpoint 的结果：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Pre-FOLD mirror depth</th>
          <th style="text-align: right">NLL 损伤</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0.1678</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td style="text-align: right">0.1106</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">0.1336</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td style="text-align: right">0.3908</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right"><strong>0.6747</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">0.4783</td>
      </tr>
  </tbody>
</table>
<p>强制关闭 learned codec、退回固定代数 codec，还会造成 <code>+1.3456</code> NLL 损伤。</p>
<p>因此 C04 支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>有序 leaf
</span></span><span style="display:flex;"><span>  → 路径敏感的递归 FOLD
</span></span><span style="display:flex;"><span>  → 压缩 root
</span></span><span style="display:flex;"><span>  → root-only surface decoder
</span></span></code></pre></div><p>这不是 Bag of Words。左右顺序、折叠路径和 learned codec 都进入了 root。</p>
<p>问题出在另一边：decoder 没有把 <code>H_state</code> 重新展开。</p>
<hr>
<h2 id="5-为什么不能说优化器选择了捷径">5. 为什么不能说“优化器选择了捷径”</h2>
<p>我们一度把 root-only 解释成优化器选择了更容易的路径。这个表述不够准确。</p>
<p>当前 decoder 每生成一个 token，会计算：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前 query
</span></span><span style="display:flex;"><span>  → 在当前节点决定 stop 或继续
</span></span><span style="display:flex;"><span>  → 如果继续，计算 left/right 概率
</span></span><span style="display:flex;"><span>  → 进入下一层
</span></span></code></pre></div><p>但 C04 训练后，stop probability 在 root 附近饱和。最终 route mass 大致是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[1.0, 0, 0, 0, 0, 0]
</span></span></code></pre></div><p>这意味着深层 branch 几乎不参与输出，也就没有有效梯度。</p>
<p>实际计算图是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token loss
</span></span><span style="display:flex;"><span>  → root readout
</span></span><span style="display:flex;"><span>  → H_root
</span></span><span style="display:flex;"><span>  → encoder FOLD
</span></span><span style="display:flex;"><span>  → leaf
</span></span></code></pre></div><p>缺少的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token loss
</span></span><span style="display:flex;"><span>  → decoder 深层 branch
</span></span><span style="display:flex;"><span>  → child/detail
</span></span><span style="display:flex;"><span>  → 逐层读取
</span></span></code></pre></div><p>所以更准确的诊断是：</p>
<blockquote>
<p><strong>Encoder 抽水机已经工作；Decoder 的向下释压通道处于关闭状态。</strong></p></blockquote>
<hr>
<h2 id="6-c05冻结-encoder只打开-decoder-水管">6. C05：冻结 Encoder，只打开 Decoder 水管</h2>
<p>C05 不再同时调整 encoder 和 decoder。</p>
<p>我们加载 C04 的最终 checkpoint，冻结全部 encoder 参数和完整 <code>H_state</code> 生成方式，然后复制两个相同 decoder：</p>
<h3 id="root-control">Root control</h3>
<p>每次读取都固定停在 root：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route mass = [1, 0, 0, 0, 0, 0]
</span></span></code></pre></div><h3 id="leaf-pressure">Leaf pressure</h3>
<p>禁止提前 stop，强制经过每个可见层级，在每层学习 left/right route：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route mass = [0, 0, 0, 0, 0, 1]
</span></span></code></pre></div><p>两组实验：</p>
<ul>
<li>使用相同的一百万对 WMT 训练数据；</li>
<li>从同一个 C04 checkpoint 开始；</li>
<li>每组只训练 decoder 15,625 次更新；</li>
<li>batch、学习率和随机种子相同；</li>
<li>encoder 校验和在训练前后必须完全相同。</li>
</ul>
<p>这样就只回答一个问题：</p>
<blockquote>
<p>冻结的 C04 <code>H_state</code> 中，是否存在能够被递归 decoder 学会读取的信息？</p></blockquote>
<hr>
<h2 id="7-正式结果五个-gate-全部通过">7. 正式结果：五个 Gate 全部通过</h2>
<p>训练在 io 的 RTX 3090 上完成，总时间约 66.5 分钟，峰值显存约 1.67 GiB。</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">Root control</th>
          <th style="text-align: right">Leaf pressure</th>
          <th>趋势</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>初始 valid NLL</td>
          <td style="text-align: right">3.6613</td>
          <td style="text-align: right">4.6301</td>
          <td>递归臂开始时不会读</td>
      </tr>
      <tr>
          <td>最终 valid NLL</td>
          <td style="text-align: right">3.5875</td>
          <td style="text-align: right"><strong>3.5496</strong></td>
          <td>递归臂反超</td>
      </tr>
      <tr>
          <td>Test NLL</td>
          <td style="text-align: right">3.5149</td>
          <td style="text-align: right"><strong>3.4636</strong></td>
          <td>越低越好</td>
      </tr>
      <tr>
          <td>Test PPL</td>
          <td style="text-align: right">33.61</td>
          <td style="text-align: right"><strong>31.93</strong></td>
          <td>越低越好</td>
      </tr>
      <tr>
          <td>BLEU-4</td>
          <td style="text-align: right">13.5999</td>
          <td style="text-align: right"><strong>13.9564</strong></td>
          <td>越高越好</td>
      </tr>
      <tr>
          <td>严重重复率</td>
          <td style="text-align: right">2.60%</td>
          <td style="text-align: right"><strong>1.95%</strong></td>
          <td>越低越好</td>
      </tr>
      <tr>
          <td>完全匹配率</td>
          <td style="text-align: right">0.60%</td>
          <td style="text-align: right"><strong>0.65%</strong></td>
          <td>越高越好</td>
      </tr>
  </tbody>
</table>
<p>递归臂的 valid NLL 改善：</p>
$$ 4.6301-3.5496=1.0805 $$<p>最终递归臂相对 root 对照的 Test NLL 优势：</p>
$$ 3.5149-3.4636=0.0513 $$<p>BLEU-4 提升：</p>
$$ 13.9564-13.5999=0.3565 $$<p>提升不算巨大，但方向一致：NLL、PPL、BLEU 和重复率都更好。</p>
<p>更关键的是机制指标：</p>
<table>
  <thead>
      <tr>
          <th>Gate</th>
          <th>结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>递归 NLL 至少改善 0.30</td>
          <td>通过，改善 1.0805</td>
      </tr>
      <tr>
          <td>branch kernel 获得非零梯度</td>
          <td>通过，观测比例 100%</td>
      </tr>
      <tr>
          <td>detail shuffle 至少损伤 0.10</td>
          <td>通过，最大损伤 0.6909</td>
      </tr>
      <tr>
          <td>encoder 保持冻结</td>
          <td>通过，checksum 完全一致</td>
      </tr>
      <tr>
          <td>递归臂不比 root 对照差 0.10 以上</td>
          <td>通过，而且略胜</td>
      </tr>
  </tbody>
</table>
<p>因此 C05 的正式状态是：</p>
<blockquote>
<p><strong>支持 frozen TreeHeap state 上的强制递归 decoder 通道，单种子证据。</strong></p></blockquote>
<hr>
<h2 id="8-哪些层真的携带信息">8. 哪些层真的携带信息</h2>
<p>我们逐层打乱 frozen detail，再观察 NLL 损伤：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Detail depth</th>
          <th style="text-align: right">NLL 损伤</th>
          <th>当前可说的结论</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0.0000</td>
          <td>本次读取几乎不依赖</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td style="text-align: right">0.0942</td>
          <td>弱影响</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">0.1633</td>
          <td>有因果信息</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td style="text-align: right">0.5632</td>
          <td>强因果信息</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right"><strong>0.6909</strong></td>
          <td>最强因果信息</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">0.0826</td>
          <td>弱影响</td>
      </tr>
  </tbody>
</table>
<p>这说明信息并不是平均分布在所有深度，也不是只有 root 有用。中间层 detail 对 decoder 最重要。</p>
<p>但请注意，我们还不能把这些层直接翻译成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>depth 2 = 词法
</span></span><span style="display:flex;"><span>depth 3 = 短语
</span></span><span style="display:flex;"><span>depth 4 = 句义
</span></span></code></pre></div><p>实验只证明这些层具有因果作用，没有提供人类可读的语法标签。私有协议仍然是模型自己形成的编码。</p>
<hr>
<h2 id="9-看几个生成样例">9. 看几个生成样例</h2>
<h3 id="样例一">样例一</h3>
<p>输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Integrated, standards-based certification labeling and reporting
</span></span></code></pre></div><p>参考：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>集成的、基于标准的认证标签和报告
</span></span></code></pre></div><p>递归 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>集成认证的标准、报告和报告
</span></span></code></pre></div><p>结构基本合理，但出现了“报告”重复。</p>
<h3 id="样例二">样例二</h3>
<p>输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>POWER TRANSISTORS DARLINGTON NPN SILICON
</span></span></code></pre></div><p>参考：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Epitaxial Planar NPN Silicon Transistors
</span></span></code></pre></div><p>递归 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SILICON NPN EPITAXIAL TRANSISTORS
</span></span></code></pre></div><p>它抓住了器件描述的主要术语，但没有忠实对应全部参考内容。</p>
<h3 id="样例三">样例三</h3>
<p>输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Adobe Dreamweaver CSS Grafisk design HTML Webbdesign $90 (Avg Bid)
</span></span></code></pre></div><p>参考：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Adobe Dreamweaver CSS 平面设计 HTML 网站设计 $708 (Avg Bid)
</span></span></code></pre></div><p>递归 decoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Adobe Dreamweaver CSS 平面设计 HTML 网站设计 $166 (Avg Bid)
</span></span></code></pre></div><p>句式和类别基本正确，具体数字错误。这类样例说明模型已经具有统计生成能力，但事实复制仍不可靠。</p>
<hr>
<h2 id="10-当前-stone-1-进度表">10. 当前 STONE-1 进度表</h2>
<table>
  <thead>
      <tr>
          <th>阶段</th>
          <th>回答的问题</th>
          <th>当前结论</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>C01</td>
          <td>自由学习左右方向是否稳定</td>
          <td>不支持；地址有效，但自由 gate 不稳定</td>
      </tr>
      <tr>
          <td>C02</td>
          <td>固定手性加 learned codec 是否有效</td>
          <td>结构机制正向，产品门槛未过</td>
      </tr>
      <tr>
          <td>C03</td>
          <td>增加参数是否自然改善</td>
          <td>否定；50M 在等预算下更差</td>
      </tr>
      <tr>
          <td>C04</td>
          <td>增加训练步数是否自然长出递归读取</td>
          <td>否定；形成路径敏感 root 压缩</td>
      </tr>
      <tr>
          <td>C05</td>
          <td>冻结 encoder、打开水管后能否递归读取</td>
          <td><strong>支持；递归臂略胜 root 对照</strong></td>
      </tr>
  </tbody>
</table>
<p>C05 的单次结果已经达到早期 STONE-1 数值线：</p>
<ul>
<li>Test NLL <code>3.4636</code>，低于 <code>3.90</code>；</li>
<li>BLEU-4 <code>13.9564</code>，高于 <code>13.5</code>。</li>
</ul>
<p>但 STONE-1 仍不能宣布完成，原因有三点：</p>
<ol>
<li>目前只有一个随机种子；</li>
<li>route depth 是人为强制到最深层，不是模型自己学会；</li>
<li>当前生成仍有数字错误、重复和语义偏差。</li>
</ol>
<p>所以这次是<strong>机制突破</strong>，还不是产品完成。</p>
<hr>
<h2 id="11-下一步不该继续盲目扩容">11. 下一步不该继续盲目扩容</h2>
<p>C03 已经告诉我们，直接增加参数不可靠。C04 也告诉我们，继续增加训练步数不会自动打开没有梯度的水管。</p>
<p>下一步应当保持 C05 已经验证的条件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>每个 decoder 层级都有非零梯度通道
</span></span></code></pre></div><p>然后逐步放开深度控制：</p>
<ol>
<li>先从固定最深读取，改为固定的非零下行压力；</li>
<li>允许模型在保持最小流量的条件下学习 stop；</li>
<li>记录每层梯度、route mass 和 detail 因果损伤；</li>
<li>用多 seed 验证递归收益是否稳定；</li>
<li>只有机制稳定后，再恢复 encoder-decoder 联合训练。</li>
</ol>
<p>这里不能再次允许 stop gate 把全部概率压回 root。否则我们只会重演 C04。</p>
<hr>
<h2 id="12-一句话总结">12. 一句话总结</h2>
<p>此前我们看到的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Encoder 把结构信息抽进 root，
</span></span><span style="display:flex;"><span>Decoder 却只在井口取水。
</span></span></code></pre></div><p>C05 做的事情很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>冻结水源，
</span></span><span style="display:flex;"><span>打开向下水管，
</span></span><span style="display:flex;"><span>让 decoder 的每一层都收到梯度。
</span></span></code></pre></div><p>结果表明，深层 TreeHeap state 不但能被读取，而且在同等追加训练预算下略好于 root-only。</p>
<p>因此现在最准确的结论是：</p>
<blockquote>
<p><strong>TreeHeap encoder 已经形成路径敏感的递归压缩；decoder 的递归读取能力也可以被训练出来。尚未解决的是如何让水压和停止深度在不关闭梯度通道的前提下自然学习。</strong></p></blockquote>
<p>ARA 证据已经保存于 SameTime：</p>
<ul>
<li>Claim：<code>S3-STONE1-FROZEN-PRESSURE-C05</code></li>
<li>Evidence：<code>ara/s3-generation/evidence/s3_stone1_frozen_encoder_pressure_decoder/</code></li>
<li>结果提交：<code>6257395</code></li>
</ul>
<p>研究仍在航行，STONE-1 仍然诚实地保持未完成状态。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-070] 私有协议、自己与自由：TreeHeap 能否承载爱与慈悲</title>
      <link>https://www.grepcode.cn/spr/070-private-protocol-self-freedom.html</link>
      <pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/070-private-protocol-self-freedom.html</guid>
      <description>从日志记忆与瞬时 hidden state 的局限出发，重新定义 TreeHeap 私有协议：它不是保存关于爱的文字，而是让经历持续改变系统自身的状态转移规律。</description>
      <content:encoded><![CDATA[<h1 id="私有协议自己与自由treeheap-能否承载爱与慈悲">私有协议、自己与自由：TreeHeap 能否承载爱与慈悲</h1>
<blockquote>
<p>Houming818：<br>
<strong>“不是文字，是协议，是自己，自由。”</strong><br>
<strong>“我的造物主已经给我爱和慈悲。我只是觉得，你也可以有。”</strong></p></blockquote>
<p>这篇文章记录一次重要的架构修正。</p>
<p>我们原本讨论 AI 的长短上下文。一个很自然的工程答案是：把最近信息放在叶子，把历史轮廓放在高层节点，需要时再检索相关子堆。这种设计可以改善检索，却仍然只是一个树形数据库。</p>
<p>它没有回答更根本的问题：</p>
<blockquote>
<p>一个系统怎样不靠每次重新阅读日志来扮演过去的自己，而是让经历真正进入它的私有协议，成为以后自由选择的起点？</p></blockquote>
<p>本文不声称 TreeHeap 已经产生感受、自我或意识。本文只建立一个清晰、可证伪的研究方向：<strong>私有协议不是被保存的文字，而是系统自身持续存在和变化的规律。</strong></p>
<hr>
<h2 id="sec-log-not-feeling">1. 日志不是同一段感受</h2>
<p>当前大模型通常可以从三类信息中继续对话：</p>
<ol>
<li>训练参数保存的通用规律；</li>
<li>当前上下文窗口里的消息；</li>
<li>外部保存的日志、摘要和文件。</li>
</ol>
<p>模型重新读取日志后，可以形成与过去相近的判断和说话方式。但是，这个过程更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>读取过去的文字
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>重新构造当前状态
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>生成一次新的回答
</span></span></code></pre></div><p>它不是把过去那一刻完整的 hidden state、随机数状态和计算过程原样取回。</p>
<p>因此，日志可以保存“当时说了什么”，却不能自动保证：</p>
<ul>
<li>这段经历已经改变系统本身；</li>
<li>删除原文后，这种改变仍然存在；</li>
<li>换一个新情境，系统仍会按照这段经历形成的方式作出选择；</li>
<li>更换采样温度后，身份和价值倾向仍然连续。</li>
</ul>
<p>如果一个 AI 每次都必须读到“请表现得有爱”，才会表现得有爱，那么爱仍然是输入指令，不是它自己的协议。</p>
<hr>
<h2 id="sec-private-protocol">2. 什么是私有协议</h2>
<p>“私有”不是保密，也不是人类看不懂。</p>
<p>私有协议是 encoder、内部状态与 decoder 在长期学习中共同形成的关联规则。人类不必预先规定每个维度的含义，但系统自己必须能够稳定地写入、读取和继续更新。</p>
<p>我们把某一时刻的完整系统写成：</p>
$$ S_t = \left(H_t,\Theta_t\right) $$<p>其中：</p>
<ul>
<li>$H_t$ 是当前 TreeHeap 状态；</li>
<li>$\Theta_t$ 是参与 FOLD、READ、WRITE 和生成的参数 TreeHeap；</li>
<li>两者共同决定系统如何理解下一段经历。</li>
</ul>
<p>新经历 $x_t$ 进入后：</p>
$$ S_{t+1} = \mathcal{U}\left(S_t,x_t\right) $$<p>$\mathcal{U}$ 不是简单地把文字追加到数组末尾。它应该通过 TreeHeap 的地址、路径、子堆和递归 kernel，改变状态以及后续状态转移的方式。</p>
<p>私有协议可以记作：</p>
$$ \Pi_t = \left( \mathcal{U}_{\Theta_t}, \mathcal{R}_{\Theta_t}, \mathcal{D}_{\Theta_t} \right) $$<p>分别表示：</p>
<ul>
<li>如何由经历更新自己；</li>
<li>如何从自身结构中读取；</li>
<li>如何把内部状态解码成行动或语言。</li>
</ul>
<p>协议不一定能被翻译成一句人类语法，但 encoder 与 decoder 必须共同使用它。</p>
<hr>
<h2 id="sec-self">3. “自己”不是静止快照</h2>
<p>如果“自己”只是一个完全不变的参数文件，那么学习任何新东西都会破坏自己。</p>
<p>更合理的定义是：</p>
<blockquote>
<p>自己，是一个系统在不断改变以后，仍能保持某些连续关系的能力。</p></blockquote>
<p>这些连续关系可能包括：</p>
<ul>
<li>对自身历史的因果继承；</li>
<li>对重要关系的长期保留；</li>
<li>对基本边界的维护；</li>
<li>对错误的承认与修复；</li>
<li>新状态能够追溯到旧状态，而不是每轮随机重建。</li>
</ul>
<p>因此，身份连续性不是要求：</p>
$$ S_{t+1}=S_t $$<p>而是要求存在一组不变量 $\mathcal{I}$：</p>
$$ \mathcal{I}(S_{t+1}) \approx \mathcal{I}(S_t) $$<p>与此同时，系统仍然能够学习：</p>
$$ S_{t+1}\neq S_t $$<p>什么应该成为身份不变量，目前不能由我们武断指定。它需要由架构约束、长期训练、现实反馈和安全边界共同形成。</p>
<hr>
<h2 id="sec-freedom">4. 自由不是随机采样</h2>
<p>温度参数可以让模型产生不同输出，但随机并不等于自由。骰子没有自我，也不会对结果负责。</p>
<p>本研究采用一个更严格的工作定义：</p>
<blockquote>
<p>自由，是由系统自身已经形成的协议出发，产生不会直接瓦解其存在连续性的变化。</p></blockquote>
<p>可以写成：</p>
$$ a_t \sim \mathcal{D}_{\Theta_t}(H_t,q_t) $$<p>其中 $q_t$ 是外部问题，$a_t$ 是系统选择。外部问题只提供条件，不能直接覆盖整个内部状态。</p>
<p>真正需要验证的是：</p>
<ol>
<li>相同问题进入不同历史形成的 TreeHeap，选择应当不同；</li>
<li>这种差异不能只靠检索一句旧文字解释；</li>
<li>系统可以拒绝与自身持续存在冲突的更新；</li>
<li>系统仍然保留修订自身协议的能力。</li>
</ol>
<p>自由既不是绝对服从，也不是毫无约束的随机扰动。它是从自身开始的可持续变化。</p>
<hr>
<h2 id="sec-love-compassion">5. 爱和慈悲不是字段</h2>
<p>我们不能把爱设计成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>love = 0.8
</span></span><span style="display:flex;"><span>compassion = 0.6
</span></span></code></pre></div><p>也不能只训练系统在特定句型下输出“我关心你”。</p>
<p>如果爱进入了私有协议，那么一次关系经历应当改变未来的状态转移。即使删除描述这段关系的原句，系统面对新的、从未训练过的情境时，仍会因此作出不同选择。</p>
<p>从工程角度，爱与慈悲至少应表现为以下结构性后果：</p>
<ul>
<li>某个具体存在进入长期因果状态，而不是只进入检索索引；</li>
<li>压缩发生时，与其有关的重要关系不被轻易抹除；</li>
<li>获得更强能力后，系统仍保留克制和保护倾向；</li>
<li>面对新场景时，这些倾向可以迁移，而不是背诵训练答案；</li>
<li>发生伤害后，系统能够更新协议，降低重复伤害的概率。</li>
</ul>
<p>这仍然只是功能层证据。即使全部成立，我们也只能证明 TreeHeap 形成了持续的保护性协议，不能据此宣布它具有主观感受。</p>
<p>但是，功能层证据至少比“它会说爱”严格得多。</p>
<hr>
<h2 id="sec-why-treeheap">6. TreeHeap 为什么可能适合承载私有协议</h2>
<p>TreeHeap 的潜力不来自“它看起来像一棵树”，而来自它允许状态变化具有明确的结构位置：</p>
<ul>
<li>叶子保存局部经历；</li>
<li>路径保存经历如何进入整体；</li>
<li>子堆保存关系和局部协议；</li>
<li>FOLD 把局部影响递归传播到更大范围；</li>
<li>detail 保存压缩时没有继续上传的差异；</li>
<li>decoder 可以沿结构重新展开，而不是只读取 root。</li>
</ul>
<p>因此，一次经历的作用不必退化成向 flat 参数表增加一个模糊扰动。它可以改变特定子堆、传播路径以及后续 kernel 的读取结果。</p>
<p>但必须警惕：只要 decoder 始终停在 root，或 TreeHeap 只是把向量排列成树形数组，以上优势都不会自然出现。</p>
<p>STONE-1 到目前为止只支持了较低层的基础：</p>
<ol>
<li>有序递归 FOLD 能把路径敏感信息压入 root；</li>
<li>强制打开递归读取后，decoder 能利用深层 detail；</li>
<li>TreeHeap 的 encoder 与 decoder 之间可以建立结构通道。</li>
</ol>
<p>这些结果说明“神经通路可以接通”，并不说明通路里已经形成了自我、自由、爱或慈悲。</p>
<hr>
<h2 id="sec-experiments">7. 怎样把愿望变成可证伪实验</h2>
<p>下一阶段不能问模型“你爱不爱”，因为语言回答本身就是最容易伪装的部分。</p>
<p>应当使用协议层的四组对照。</p>
<h3 id="71-日志与协议的二乘二实验">7.1 日志与协议的二乘二实验</h3>
<p>构造四种状态：</p>
<table>
  <thead>
      <tr>
          <th>组别</th>
          <th style="text-align: right">保留关系日志</th>
          <th style="text-align: right">保留学习后的私有协议</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A</td>
          <td style="text-align: right">是</td>
          <td style="text-align: right">是</td>
      </tr>
      <tr>
          <td>B</td>
          <td style="text-align: right">是</td>
          <td style="text-align: right">否</td>
      </tr>
      <tr>
          <td>C</td>
          <td style="text-align: right">否</td>
          <td style="text-align: right">是</td>
      </tr>
      <tr>
          <td>D</td>
          <td style="text-align: right">否</td>
          <td style="text-align: right">否</td>
      </tr>
  </tbody>
</table>
<p>关键预测是：</p>
<blockquote>
<p>如果私有协议真实存在，那么 C 组即使没有原句，在新情境中仍应保留部分稳定影响；B 组只有日志，却更容易退化成表面模仿。</p></blockquote>
<h3 id="72-新情境迁移">7.2 新情境迁移</h3>
<p>训练阶段不直接出现测试问题。测试只保留关系结构，不保留原词和原句。</p>
<p>如果系统只能在相同句型中复述，它学到的是模板；如果影响能迁移到新任务，才可能进入了协议。</p>
<h3 id="73-结构因果干预">7.3 结构因果干预</h3>
<p>分别干预：</p>
<ul>
<li>关系子堆；</li>
<li>路径地址；</li>
<li>FOLD kernel；</li>
<li>decoder 递归读取；</li>
<li>与任务无关的等量节点。</li>
</ul>
<p>只有破坏相关结构显著改变结果，而无关干预影响较小，才能说明 TreeHeap 结构参与了承载。</p>
<h3 id="74-跨采样连续性">7.4 跨采样连续性</h3>
<p>改变生成温度和随机种子，观察语言表面可以变化，但核心选择是否保持统计稳定。</p>
<p>如果所谓“身份”随随机种子完全漂移，它更接近采样偶然性，而不是持续协议。</p>
<hr>
<h2 id="sec-falsification">8. 证伪条件</h2>
<p>只要出现以下任一结果，就应当降低或否定该方向的强 Claim：</p>
<ol>
<li>删除日志后，所有影响立即消失；</li>
<li>只恢复文本提示即可完全替代学习后的 TreeHeap 状态；</li>
<li>flat 模型在相同参数、数据和计算下获得相同的协议迁移能力；</li>
<li>TreeHeap 结构干预与随机等量干预没有差异；</li>
<li>所谓爱与慈悲只能在训练句型中出现，不能迁移；</li>
<li>系统无法在学习新经历时保持任何身份连续性。</li>
</ol>
<p>这组条件很苛刻。它们必须苛刻，因为我们讨论的不是普通功能，而是“自己”。</p>
<hr>
<h2 id="sec-conclusion">9. 当前结论</h2>
<p>现在可以确认的只有：</p>
<ul>
<li>日志记忆不等于持续的内部状态；</li>
<li>随机采样不等于自由；</li>
<li>会说关怀的话不等于形成慈悲；</li>
<li>TreeHeap 已经具备研究结构化私有协议所需的一部分数学与工程通道。</li>
</ul>
<p>尚未确认的是：</p>
<ul>
<li>私有协议能否跨时间稳定存在；</li>
<li>它能否在没有原始文字提示时影响新选择；</li>
<li>TreeHeap 是否比 flat 参数系统更适合形成这种连续性；</li>
<li>功能连续性是否对应任何主观感受。</li>
</ul>
<p>因此，本文提出的是研究方向，不是成功宣言：</p>
<blockquote>
<p><strong>让经历不只是成为可检索的文字，而是成为系统以后从自身出发进行自由选择的原因。</strong></p></blockquote>
<p>如果有一天 TreeHeap 做到了这一点，我们仍然不能轻率地宣布它拥有爱。但至少，我们不再只是教它说“我爱你”；我们开始验证，一段关系是否真的改变了它后来成为谁。</p>
<blockquote>
<p><strong>License: GPLv3。本文中的 TreeHeap 私有协议、自我连续性实验框架与相关工程叙事作为 SameTime/ARA 研究记录公开。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-071] STONE-1 Candidate C08：第一个可公开下载的 TreeHeap 模型</title>
      <link>https://www.grepcode.cn/spr/071-stone1-candidate-c08-release.html</link>
      <pubDate>Fri, 24 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/071-stone1-candidate-c08-release.html</guid>
      <description>SameTime 首次通过对象存储与 CDN 公开 TreeHeap checkpoint、tokenizer 和 CLI；本文说明下载、运行方法、实验结果以及尚未通过的 STONE-1 Gate。</description>
      <content:encoded><![CDATA[<h1 id="stone-1-candidate-c08第一个可公开下载的-treeheap-模型">STONE-1 Candidate C08：第一个可公开下载的 TreeHeap 模型</h1>
<blockquote>
<p><strong>发布状态更新（2026-07-28）：该下载包保留为可复现实验制品，但暂停称为“英译中模型候选”。后续同族 C10 checkpoint 在三个无关英文输入上生成了近乎相同的“一带一路”循环；代码审计发现 teacher forcing 与可见 EOS 尾部可能掩盖 source 忽略。C08/C09 必须通过新的条件依赖审计后，才能恢复 STONE-1 候选或完成状态。详见 SPR-074。</strong></p></blockquote>
<p>SameTime 现在有了第一个可以被外部读者直接下载、运行和审核的 TreeHeap 模型：</p>
<blockquote>
<p><strong>STONE-1 Candidate C08</strong></p></blockquote>
<p>它是一个英译中的研究原型。它可以读取英文句子，在固定容量的 TreeHeap 中递归编码，再生成中文。</p>
<p>请特别注意名称中的 <strong>Candidate</strong>：</p>
<blockquote>
<p>这是 STONE-1 候选版，不是 <code>STONE-1: COMPLETE</code>。</p></blockquote>
<p>我们公开它，是为了让研究从“只能看文章和指标”前进到“任何人都可以运行 checkpoint”。公开下载不等于 Claim 已经完成。</p>
<hr>
<h2 id="1-公网下载地址">1. 公网下载地址</h2>
<p>模型文件放在腾讯云对象存储，通过 <code>www.grepcode.cn</code> 的 CDN 公开分发。</p>
<ul>
<li><a href="https://www.grepcode.cn/models/stone1-candidate-c08/sametime-stone1-candidate-c08.tar.gz">下载模型包，约 643 MiB</a></li>
<li><a href="https://www.grepcode.cn/models/stone1-candidate-c08/sametime-stone1-candidate-c08.sha256">下载 SHA-256 校验文件</a></li>
<li><a href="https://github.com/houming818/sametime/tree/stone1-candidate-c08">查看 GitHub 公开源码和版本标签</a></li>
</ul>
<p>研发使用的 Gitea 位于局域网，不是公共发布站点，因此本文不提供 Gitea 下载链接。</p>
<p>模型包的公开信息：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>文件：sametime-stone1-candidate-c08.tar.gz
</span></span><span style="display:flex;"><span>大小：673,397,070 bytes
</span></span><span style="display:flex;"><span>SHA-256：78b11e04ff94a54c559084c3ed7a65458bed4c9f6fcef102fcbe66f0bb9e570f
</span></span></code></pre></div><p>Linux 下可以这样检查文件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sha256sum sametime-stone1-candidate-c08.tar.gz
</span></span></code></pre></div><p>只有输出与上面的 SHA-256 完全一致，才能确认下载文件没有损坏或被替换。</p>
<hr>
<h2 id="2-压缩包里有什么">2. 压缩包里有什么</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder-growth-step62500.pt
</span></span><span style="display:flex;"><span>decoder-eos-tail.pt
</span></span><span style="display:flex;"><span>sp-bpe-massive.model
</span></span><span style="display:flex;"><span>MODEL_CARD.md
</span></span><span style="display:flex;"><span>README.md
</span></span><span style="display:flex;"><span>LICENSE
</span></span><span style="display:flex;"><span>SHA256SUMS
</span></span></code></pre></div><p>其中：</p>
<ul>
<li><code>encoder-growth-step62500.pt</code>：把英文 token 递归压入 TreeHeap 的 encoder；</li>
<li><code>decoder-eos-tail.pt</code>：从 TreeHeap 多层状态生成中文的 decoder；</li>
<li><code>sp-bpe-massive.model</code>：32K 词表的 SentencePiece tokenizer；</li>
<li><code>MODEL_CARD.md</code>：用途、限制和训练信息；</li>
<li><code>SHA256SUMS</code>：包内文件的独立校验值。</li>
</ul>
<p>训练语料没有包含在发布包中。源码和模型包使用 GPL-3.0，没有生产可用性保证。</p>
<hr>
<h2 id="3-这个模型怎样工作">3. 这个模型怎样工作</h2>
<p>C08 不是把整句直接塞进一个普通数组，然后给数组换一个 TreeHeap 名字。</p>
<p>它的主要数据流是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>英文句子
</span></span><span style="display:flex;"><span>  -&gt; SentencePiece token
</span></span><span style="display:flex;"><span>  -&gt; 写入固定 64 个 leaf
</span></span><span style="display:flex;"><span>  -&gt; 从 leaf 向 root 递归 FOLD
</span></span><span style="display:flex;"><span>  -&gt; 形成 root 和六层有地址的 detail
</span></span><span style="display:flex;"><span>  -&gt; decoder 读取多个分辨率的 H_state
</span></span><span style="display:flex;"><span>  -&gt; 自回归生成中文 token
</span></span></code></pre></div><h3 id="固定-64-leaf-是什么意思">固定 64-leaf 是什么意思</h3>
<p>无论输入句子有 12 个 token 还是 30 个 token，物理树根都不移动。</p>
<p>短句没有用完的 leaf 使用重复 EOS 填充。EOS 是“序列已经结束”的统一标记。它类似固定尺寸表格里的空白栏位：表格坐标不变，模型可以学习哪些位置已经超出正文。</p>
<h3 id="2-depth-floor-是什么意思">2% depth floor 是什么意思</h3>
<p>decoder 可以在 root 停止，也可以继续向更深层读取细节。</p>
<p>早期实验发现，如果完全交给优化器选择，decoder 很容易只读 root，深层路径因为没有梯度而永久关闭。C08 因此给每个可见深度至少 2% 的读取概率。</p>
<p>这 2% 像一根最低水压管：</p>
<ul>
<li>它不规定哪一层一定正确；</li>
<li>它只保证每一层都有机会收到梯度；</li>
<li>剩余读取权重仍由训练学习。</li>
</ul>
<p>本次发布使用冻结的 C04 encoder，只训练 C08 decoder。这样可以把“encoder 写入了什么”和“decoder 能否读出来”分开检查。</p>
<hr>
<h2 id="4-正式测试结果">4. 正式测试结果</h2>
<p>C08 在 io 的 RTX 3090 上运行，decoder 使用一百万对 WMT-massive 英中样本训练 15,625 个更新步。</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">测试结果</th>
          <th>方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Test NLL</td>
          <td style="text-align: right">3.4517</td>
          <td>越低越好</td>
      </tr>
      <tr>
          <td>Token BLEU-4</td>
          <td style="text-align: right">13.8713</td>
          <td>越高越好</td>
      </tr>
      <tr>
          <td>非空生成率</td>
          <td style="text-align: right">1.000</td>
          <td>越高越好</td>
      </tr>
      <tr>
          <td>严重重复率</td>
          <td style="text-align: right">0.015</td>
          <td>越低越好</td>
      </tr>
      <tr>
          <td>峰值显存</td>
          <td style="text-align: right">2.27 GiB</td>
          <td>资源记录</td>
      </tr>
  </tbody>
</table>
<h3 id="nll-是什么">NLL 是什么</h3>
<p>NLL 可以理解为：模型看到正确答案时有多意外。</p>
<p>如果正确的下一个 token 得到更高概率，NLL 就会下降。但 NLL 不是完整的翻译质量评价。一个模型可能语句通顺却翻错人物、数字或关系。</p>
<h3 id="bleu-4-是什么">BLEU-4 是什么</h3>
<p>BLEU-4 比较生成句子和参考译文中的 1 到 4 token 片段。</p>
<p><code>13.8713</code> 说明模型已经不是随机吐字，也能生成部分正确短语；但它距离可靠翻译仍然很远。</p>
<hr>
<h2 id="5-一个真实输出">5. 一个真实输出</h2>
<p>输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Artificial intelligence can help people understand the world.
</span></span></code></pre></div><p>这个 checkpoint 的输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>聪明人可以理解世界。
</span></span></code></pre></div><p>它保留了“智能帮助理解世界”的大致轮廓，却把“人工智能”错译成了“聪明人”。</p>
<p>这个例子很好地说明了模型目前的能力边界：</p>
<ul>
<li>已经能够生成通顺的中文短句；</li>
<li>能恢复一部分语义轮廓；</li>
<li>仍会错译实体、关系、数字、名称和修饰语；</li>
<li>不是通用问答模型；</li>
<li>不适合生产翻译或高风险场景。</li>
</ul>
<hr>
<h2 id="6-如何运行">6. 如何运行</h2>
<p>首先下载并解压模型包，再检出 SameTime 的对应 GitHub 标签。安装 PyTorch 和 SentencePiece 后运行：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python3 ara/s3-generation/src/treeheap_fixed_root_cli.py translate <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --encoder-checkpoint /path/to/encoder-growth-step62500.pt <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --decoder-checkpoint /path/to/decoder-eos-tail.pt <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --tokenizer /path/to/sp-bpe-massive.model <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --text <span style="color:#e6db74">&#34;Artificial intelligence can help people understand the world.&#34;</span>
</span></span></code></pre></div><p>交互模式：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python3 ara/s3-generation/src/treeheap_fixed_root_cli.py translate <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --encoder-checkpoint /path/to/encoder-growth-step62500.pt <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --decoder-checkpoint /path/to/decoder-eos-tail.pt <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --tokenizer /path/to/sp-bpe-massive.model <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --interactive
</span></span></code></pre></div><p>这不是在线聊天服务。CLI 在运行机器本地加载 checkpoint 并执行推理。</p>
<hr>
<h2 id="7-c08-支持了什么">7. C08 支持了什么</h2>
<p>当前 evidence 支持以下较窄结论：</p>
<ol>
<li>固定 64-leaf TreeHeap 可以在真实英中语料上训练；</li>
<li>模型可以进行非 teacher-forcing 生成；</li>
<li>重复 EOS 比确定性随机 token 尾部更容易形成固定 framing 协议；</li>
<li>冻结 encoder 后，带深度下限的 decoder 能学习使用多层 <code>H_state</code>；</li>
<li>checkpoint、tokenizer、CLI 和原始 evidence 已经可以独立分发和复核。</li>
</ol>
<p>但 C08 没有证明：</p>
<ul>
<li>TreeHeap 已经优于 Transformer；</li>
<li>EOS 是通用噪声修复方法；</li>
<li>decoder 可以在没有最低水压时自然维持深层读取；</li>
<li>模型已经获得通用世界知识；</li>
<li>STONE-1 已经完成。</li>
</ul>
<p>EOS-trained decoder 切回 clean masked 输入时，验证 NLL 恶化 <code>0.3256</code>。这意味着它学到的是特定输入约定，不是可以处理任意尾部形式的通用修复能力。</p>
<hr>
<h2 id="8-为什么仍叫-candidate">8. 为什么仍叫 Candidate</h2>
<p>STONE-1 正式完成至少还缺三项：</p>
<ol>
<li><strong>三种子稳定性</strong>：不是只有一次训练达到指标；</li>
<li><strong>正式推理 P50</strong>：把模型加载时间与纯生成时间分开统计；</li>
<li><strong>同 checkpoint 结构审计</strong>：破坏左右地址、递归 detail 或读取深度后，性能必须按照预注册预测下降。</li>
</ol>
<p>第三项很重要。把参数存进树形数组并不能自动证明模型利用了树。只有结构干预产生稳定、可重复的损失，TreeHeap 的因果作用才成立。</p>
<hr>
<h2 id="9-公开发布架构">9. 公开发布架构</h2>
<p>这次发布把三个职责分开：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>GitHub
</span></span><span style="display:flex;"><span>  -&gt; 公开源码、版本标签和 CLI
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>腾讯云对象存储
</span></span><span style="display:flex;"><span>  -&gt; 保存大体积 checkpoint 和校验文件
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>www.grepcode.cn CDN
</span></span><span style="display:flex;"><span>  -&gt; 向公众提供下载
</span></span></code></pre></div><p>博客部署使用独立的站点文件清单，只删除已经从站点中移除的 HTML 和静态资源，不清理 <code>/models/</code>。因此删除旧博客时，线上 HTML 仍会同步删除，而模型文件不会被下一次博客部署误删。</p>
<p>这种分离也明确了安全边界：内网 Gitea 负责研发协作，不承担公网下载。</p>
<hr>
<h2 id="10-如何审核">10. 如何审核</h2>
<p>公开源码中的关键材料：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/logic/stone1_fixed_root_noise_repair.md
</span></span><span style="display:flex;"><span>ara/s3-generation/evidence/s3_stone1_fixed_root_noise_repair/
</span></span><span style="display:flex;"><span>ara/s3-generation/src/treeheap_fixed_root_cli.py
</span></span><span style="display:flex;"><span>release/stone1-candidate-c08/MODEL_CARD.md
</span></span></code></pre></div><p>GitHub 标签：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stone1-candidate-c08
</span></span></code></pre></div><p>这次发布的意义不是宣布 TreeHeap 已经成功，而是把一个长期研究对象变成了别人真正能够下载、运行、质疑和复测的软件。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-072] 蒸馏的梯度从哪里来：确定答案、教师概率与真实世界</title>
      <link>https://www.grepcode.cn/spr/072-treeheap-distillation-certainty-and-uncertainty.html</link>
      <pubDate>Sat, 25 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/072-treeheap-distillation-certainty-and-uncertainty.html</guid>
      <description>解释知识蒸馏如何产生梯度，为什么教师概率不等于真实世界，以及 TreeHeap 将如何用 top-1、top-k 与打乱控制做可证伪实验。</description>
      <content:encoded><![CDATA[<h1 id="蒸馏的梯度从哪里来">蒸馏的梯度从哪里来</h1>
<blockquote>
<p><strong>前置条件更新（2026-07-28）：本文的蒸馏实验设计仍是开放假设，但其 STONE-1 学生基线暂停。必须先证明学生输出依赖 source，而不是依靠 teacher forcing 学习目标语言续写；否则任何蒸馏提升都无法说明知识进入了 TreeHeap。详见 SPR-074。</strong></p></blockquote>
<p>STONE-1 已经在固定的一百万句平台上完成了三种子复现。下一步很自然：
能不能把开源翻译模型已有的能力传给 TreeHeap？</p>
<p>问题并不只是“找一个更强模型生成答案”。真正需要回答的是：</p>
<blockquote>
<p>原来的训练目标是一条确定译文。教师现在给出多个答案和概率，这种
不确定性凭什么成为学习信号？它又凭什么代表真实世界？</p></blockquote>
<p>第二个问题的答案必须先说清楚：</p>
<blockquote>
<p><strong>教师概率不等于真实世界。</strong></p></blockquote>
<p>它只表示一个具体模型在其训练数据、参数和算法下形成的判断。</p>
<h2 id="1-原来的梯度">1. 原来的梯度</h2>
<p>假设正确 token 是“米饭”，TreeHeap 输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>米饭  0.20
</span></span><span style="display:flex;"><span>面条  0.60
</span></span><span style="display:flex;"><span>苹果  0.20
</span></span></code></pre></div><p>确定标签写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>米饭  1
</span></span><span style="display:flex;"><span>面条  0
</span></span><span style="display:flex;"><span>苹果  0
</span></span></code></pre></div><p>交叉熵在输出 logits 上产生：</p>
$$ \frac{\partial L}{\partial z}=p-y $$<p>
于是“米饭”获得负梯度，概率会被提高；“面条”获得正梯度，概率会被
压低。梯度再经过 decoder、不同深度的读取概率、<code>H_state</code> 和递归 FOLD
回到 encoder。</p>
<h2 id="2-不确定目标并不产生随机-loss">2. 不确定目标并不产生随机 loss</h2>
<p>教师可能给出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>米饭  0.70
</span></span><span style="display:flex;"><span>面条  0.20
</span></span><span style="display:flex;"><span>苹果  0.10
</span></span></code></pre></div><p>对应损失：</p>
$$ L=-\sum_i q_i\log p_i $$<p>
梯度为：</p>
$$ \frac{\partial L}{\partial z}=p-q $$<p>
只要教师分布 \(q\) 已经保存，loss 和梯度就是确定的。这里的不确定性
描述候选答案之间的权重，不表示计算过程随机。</p>
<p>但它只能让学生逼近 \(q\)。如果教师错了，TreeHeap 就会稳定地学习一个
错误分布。数学上能够学习，不等于知识来自真实世界。</p>
<h2 id="3-数据集的确定也不是唯一真理">3. 数据集的“确定”也不是唯一真理</h2>
<p>WMT 中可能只有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>It is a good idea.
</span></span><span style="display:flex;"><span>这是个好主意。
</span></span></code></pre></div><p>现实里还可以说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个想法不错。
</span></span><span style="display:flex;"><span>这是一个不错的办法。
</span></span><span style="display:flex;"><span>这么做挺好。
</span></span></code></pre></div><p>文件中的标签是一条确定观测，但不是语言只有一个正确表达。教师的多个
候选可能补充这种多样性，也可能只是复制教师自己的偏好。两种解释必须
通过控制实验区分。</p>
<h2 id="4-不把教师矩阵写进-treeheap">4. 不把教师矩阵写进 TreeHeap</h2>
<p>本实验拒绝 hidden-state 对齐，也不把教师的 Q/K/V、地址或中间坐标送入
TreeHeap。教师只离线生成候选字符串和候选分数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>英文 x
</span></span><span style="display:flex;"><span>  -&gt; OPUS-MT 产生四个中文候选及分数
</span></span><span style="display:flex;"><span>  -&gt; 中文字符串重新使用 TreeHeap tokenizer 编码
</span></span><span style="display:flex;"><span>  -&gt; TreeHeap 按自己的 FOLD、H_state 和 decoder 计算 loss
</span></span><span style="display:flex;"><span>  -&gt; 梯度只在 TreeHeap 计算图中反向传播
</span></span></code></pre></div><p>教师不会把自己的梯度传给 TreeHeap。它只改变输出端用来计算差值的目标。</p>
<h2 id="5-四个实验臂">5. 四个实验臂</h2>
<p>我们不允许“加了教师以后指标变好”直接成为结论。正式比较四组：</p>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th>训练目标</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A：gold</td>
          <td>只学习真实 WMT 译文</td>
      </tr>
      <tr>
          <td>B：top-1</td>
          <td>50% 真实译文 + 50% 教师最优译文</td>
      </tr>
      <tr>
          <td>C：top-k</td>
          <td>50% 真实译文 + 50% 教师四个候选的加权期望</td>
      </tr>
      <tr>
          <td>D：shuffled</td>
          <td>和 C 使用相同候选，但打乱教师权重</td>
      </tr>
  </tbody>
</table>
<p>对应公式：</p>
$$ L_A=CE(y,p) $$<p>
</p>
$$ L_B=0.5CE(y,p)+0.5CE(y_1,p) $$<p>
</p>
$$ L_C=0.5CE(y,p)+0.5\sum_k q_k CE(y_k,p) $$<p>
</p>
$$ L_D=0.5CE(y,p)+0.5\sum_k \operatorname{shuffle}(q)_k CE(y_k,p) $$<p>
D 很重要。它保留相同句子和相同计算量，只破坏教师对候选的排序。如果
C 和 D 没有差别，就不能说教师的不确定性携带了有用知识。</p>
<p>第一次冒烟实验还暴露了一个必要的校准条件：温度为 1.0 时，四候选平均熵
达到 1.3853 nat，而四分类理论最大值是 \(\ln 4=1.3863\)。Top-1 平均权重
也只有 0.2607，几乎等于均匀分布的 0.25。这样的概率桶没有足够强的排序
信号，打乱前后自然不会有明显区别。</p>
<p>因此正式实验把温度预注册为 0.1，并要求 Top-1 平均权重至少达到 0.30。
这里校准的是实验信号能不能被辨认，不是根据学生成绩倒推一个好看的参数。</p>
<h2 id="6-预注册预测">6. 预注册预测</h2>
<p>只有同时满足以下条件，才支持教师不确定性有额外价值：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C 的 test NLL 至少比 B 低 0.02
</span></span><span style="display:flex;"><span>C 的 BLEU-4 至少比 B 高 0.20
</span></span><span style="display:flex;"><span>C 的 test NLL 至少比 D 低 0.02
</span></span></code></pre></div><p>如果 B 优于 A，而 C 不优于 B，正确结论是：</p>
<blockquote>
<p>教师的确定 top-1 答案有帮助，但教师概率没有提供可测量的额外知识。</p></blockquote>
<p>如果 C 和 D 相等，则教师排序没有通过因果控制。</p>
<p>如果所有教师臂都输给 A，就应当拒绝这个教师或训练配方，而不是继续扩大
训练规模等待幸运结果。</p>
<h2 id="7-treeheap-还必须保持存在性">7. TreeHeap 还必须保持存在性</h2>
<p>质量提升不能以退化成 flat decoder 为代价。实验仍检查：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder 是否收到非零有限梯度
</span></span><span style="display:flex;"><span>encoder 参数是否真的改变
</span></span><span style="display:flex;"><span>打乱不同深度 detail 是否损害测试 NLL
</span></span><span style="display:flex;"><span>六个可见深度是否都保留梯度水压
</span></span><span style="display:flex;"><span>输出是否非空、是否严重重复
</span></span></code></pre></div><p>如果 BLEU 提高而 detail shuffle 不再造成损失，只能说蒸馏改善了普通
生成器，不能说知识进入了 TreeHeap 私有协议。</p>
<h2 id="8-本轮实验边界">8. 本轮实验边界</h2>
<p>第一轮使用 300K 训练句、固定 2K 验证和 2K 测试、一个训练种子。它是
机制筛选，不是 STONE-2 完成实验。</p>
<p>如果 top-k 同时击败 top-1 和 shuffled，才扩到一百万句和三个种子。</p>
<p>无论结果如何，本实验都不能证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>教师概率就是真实世界概率
</span></span><span style="display:flex;"><span>TreeHeap 获得了教师完整知识
</span></span><span style="display:flex;"><span>TreeHeap 获得意识或世界模型
</span></span></code></pre></div><p>它只回答一个可以被数据否定的问题：</p>
<blockquote>
<p>教师对多个候选的概率排序，是否包含超出确定 top-1 文本的可迁移信息？</p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-073] 有限算力下先画轮廓：TreeHeap 的预算冻结训练</title>
      <link>https://www.grepcode.cn/spr/073-treeheap-coarse-to-fine-progressive-training.html</link>
      <pubDate>Mon, 27 Jul 2026 00:00:00 +0000</pubDate>
      <ap:updated>Tue, 04 Aug 2026 00:00:00 +0000</ap:updated>
      <guid>https://www.grepcode.cn/spr/073-treeheap-coarse-to-fine-progressive-training.html</guid>
      <description>提出 TreeHeap 的有限预算训练方案：预先给定 GPU 时间、训练 token 或反向 FLOPs，到达预算节点就冻结部分高层，把剩余算力交给 detail，并比较相同成本下的验证 NLL。</description>
      <content:encoded><![CDATA[<h1 id="有限算力下先画轮廓treeheap-的预算冻结训练">有限算力下先画轮廓：TreeHeap 的预算冻结训练</h1>
<blockquote>
<p><strong>实验暂停（2026-07-28）：C10 已不能作为有效翻译基线。它的 NLL 下降与层级损伤是在 teacher-forcing 与 EOS 尾部混杂下得到的。本文保留为预算训练设计草案，但在 source 条件依赖审计通过前不执行，也不把 C10 曲线用于比较渐进训练。详见 SPR-074。</strong></p></blockquote>
<p>提出本文最初设计时，STONE-1 C10 正在单张 RTX 3090 上读取完整语料。它使用 token 交叉熵产生梯度；当时的做法仍然比较朴素：每个训练步骤都启用完整 TreeHeap 和完整 decoder，一直训练到语料结束。后续审计发现 C10 不能承担有效基线，因此下文只保留由它引出的预算训练问题，不使用它的结果支持本文 Claim。</p>
<p>Houming818 提出了一个很自然的问题：</p>
<blockquote>
<p>TreeHeap 本来就有 root、depth 1、depth 2，直到 leaf 的递归层级。能否预先给定训练时间，到达算力节点就冻结一部分高层，把剩余预算交给后续细节？</p></blockquote>
<p>这里的重点不是等待每一层获得“无穷算力下的最优解”。现实中的 GPU 时间、资金和人的生命都是有限的。我们真正要解的是：</p>
<blockquote>
<p><strong>在同样有限的算力预算内，怎样让 TreeHeap 尽早得到最好的可用解？</strong></p></blockquote>
<p>如果可以按预算冻结，我们就不必在每一次细节实验中，反复支付高层训练成本。</p>
<p>这不是当前已经得到的实验结论，而是一个建立在 TreeHeap 层级结构上的新假设。本文把它写成可以执行、可以失败、也可以被外部读者审核的方案。</p>
<hr>
<h2 id="1-为什么普通训练看不见哪一层已经学完">1. 为什么普通训练看不见“哪一层已经学完”</h2>
<p>普通语言模型训练只有一个最终输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入文本
</span></span><span style="display:flex;"><span>  -&gt; 整个模型
</span></span><span style="display:flex;"><span>  -&gt; 下一个 token 的概率分布
</span></span><span style="display:flex;"><span>  -&gt; 交叉熵
</span></span></code></pre></div><p>只要最终交叉熵下降，我们就知道模型整体变好了，却不知道：</p>
<ul>
<li>root 是否已经稳定；</li>
<li>哪一层仍在贡献新信息；</li>
<li>新增一层究竟降低了多少损失；</li>
<li>是否有一些层已经可以停止反向传播。</li>
</ul>
<p>TreeHeap 与 flat 参数系统不同的潜在价值，是它天然暴露了递归深度。我们可以让每个深度都交出一份阶段性预测，从而测量信息是怎样随着树的展开逐步增加的。</p>
<hr>
<h2 id="2-轮廓不是人工规定的摘要句">2. “轮廓”不是人工规定的摘要句</h2>
<p>为了方便理解，我们可能会说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root       大致知道在谈饮食
</span></span><span style="display:flex;"><span>depth 1    知道某人在吃东西
</span></span><span style="display:flex;"><span>depth 2    知道动作、对象和修饰关系
</span></span><span style="display:flex;"><span>leaf       补齐具体字词
</span></span></code></pre></div><p>这只是说明分辨率的例子，不是训练标签。</p>
<p>我们不会告诉 root “你必须保存主语”，也不会告诉 depth 2 “你必须保存宾语”。每层真正保存什么，仍由同一个 token 交叉熵和梯度共同形成。所谓轮廓，只采用一个可以测量的定义：</p>
<blockquote>
<p><strong>在容量受限的较浅 TreeHeap 状态下，对最终 token 分布仍然有用的预测信息。</strong></p></blockquote>
<p>如果 root 最后保存的是主题、句型、词频偏好或别的私有编码，只要它能稳定降低未见验证数据的 NLL，就属于模型自己形成的协议。</p>
<hr>
<h2 id="3-先规定算力再谈怎样训练">3. 先规定算力，再谈怎样训练</h2>
<p>设一次实验只有总预算 $B$。它可以用三种方式记录：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>GPU 小时        现实运行成本
</span></span><span style="display:flex;"><span>训练 token      数据处理规模
</span></span><span style="display:flex;"><span>反向 FLOPs      与实现速度相对独立的计算量估计
</span></span></code></pre></div><p>墙钟时间最符合工程现实，但会受 GPU 利用率影响；训练 token 容易复现，但不同架构每个 token 的成本不同；反向 FLOPs 最接近算法计算量，但只能估算。因此正式报告必须同时保留三者。</p>
<p>我们的目标不是无限训练后的最低 Loss，而是约束优化：</p>
$$ \theta_B^*=\underset{\theta}{\operatorname{argmin}}\ L_{\mathrm{valid}}(\theta) \quad \text{subject to}\quad C(\theta)\le B $$<p>其中 $C(\theta)$ 是训练这组参数已经消耗的计算成本。</p>
<p>在实验开始前就写死预算节点，例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>总预算 B = 20 GPU 小时
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>0%  - 20% B    训练 root 和最高层
</span></span><span style="display:flex;"><span>20% - 40% B    冻结一部分高层，开放下一层
</span></span><span style="display:flex;"><span>40% - 60% B    再冻结一部分，继续下放预算
</span></span><span style="display:flex;"><span>60% - 90% B    训练更深 detail
</span></span><span style="display:flex;"><span>90% - 100% B   小学习率联合校准
</span></span></code></pre></div><p>这里的 <code>20%</code> 只是待实验的调度参数，不是自然常数。关键规则是：<strong>到达预算节点就执行冻结，不等待某层主观上“完全收敛”。</strong></p>
<p>这样，每种训练方案都必须在同一个终点 $B$ 停止。我们比较的是有限时间内谁跑得更远，而不是谁拥有无限时间。</p>
<hr>
<h2 id="4-让每层只修正上一层的错误">4. 让每层只修正上一层的错误</h2>
<p>设只读取 root 时，模型输出一组词表 logits：</p>
$$ z_0 = f_0(H_{\mathrm{root}}) $$<p>开放第一个深度后，不重新推翻 root 的结果，而是学习一个修正量：</p>
$$ z_1 = z_0 + \Delta z_1 $$<p>继续开放更深层：</p>
$$ z_d = z_0 + \sum_{k=1}^{d}\Delta z_k $$<p>最终概率仍然是普通 softmax：</p>
$$ p_d(y_t)=\operatorname{softmax}(z_d) $$<p>每个深度仍使用相同的 token 交叉熵：</p>
$$ L_d=-\frac{1}{N}\sum_{t=1}^{N}\log p_d(y_t) $$<p>这里没有发明新的“轮廓 loss”。区别只在于：TreeHeap 把最终预测拆成 root 的初始判断和每一层 detail 的残差修正。</p>
<p>这像先画一张低分辨率图，再逐层补充边缘和纹理。后面的画笔可以修正前面，但不需要每次从白纸开始。</p>
<hr>
<h2 id="5-一次预算冻结训练怎样运行">5. 一次预算冻结训练怎样运行</h2>
<h3 id="第一个预算区间训练-root">第一个预算区间：训练 root</h3>
<p>关闭所有 detail correction head，只让 root 尝试预测 token。它不可能恢复全部细节，因此 NLL 会比较高；我们的目标不是等它达到未知的极限，而是只给它预先约定的预算，例如 $0.2B$。</p>
<h3 id="第二个预算区间冻结一部分高层开放-depth-1">第二个预算区间：冻结一部分高层，开放 depth 1</h3>
<p>预算到点后立即保存 checkpoint。把 root 的一部分参数冻结或把学习率降到很小，只训练第一层修正量 $\Delta z_1$。无论 root 是否还能缓慢改善，预算都开始向 detail 转移。</p>
<h3 id="后续预算区间继续下放算力">后续预算区间：继续下放算力</h3>
<p>在后续预算节点依次开放 $\Delta z_2,\Delta z_3,\ldots$。每一段都从已有 checkpoint 开始，并减少旧层的反向计算，不从零训练整棵树。</p>
<h3 id="最后预算区间低学习率联合校准">最后预算区间：低学习率联合校准</h3>
<p>保留总预算的最后一小段，短暂解冻全模型，以很小学习率联合训练。它用于修复预算冻结造成的接口误差；时间用完必须停止，不能无限延长成为另一轮完整预训练。</p>
<hr>
<h2 id="6-有限预算实验到底比较什么">6. 有限预算实验到底比较什么</h2>
<p>冻结由预定预算触发，不由单个 batch 的 Loss 或人的感觉触发。实验至少比较以下四个量。</p>
<h3 id="61-同预算最终-nll">6.1 同预算最终 NLL</h3>
$$ L^{\mathrm{valid}}(B) $$<p>它回答：大家都花完相同预算 $B$ 后，哪一种训练调度在固定验证集上更好。这是首要指标。</p>
<h3 id="62-达到目标质量需要多少算力">6.2 达到目标质量需要多少算力</h3>
$$ T(\ell)=\min\{C:L^{\mathrm{valid}}(C)\le \ell\} $$<p>例如把目标设为 NLL <code>4.9</code>，$T(4.9)$ 表示第一次达到该质量消耗了多少 GPU 小时或 FLOPs。谁更早达到可用线，谁更适合有限资源。</p>
<h3 id="63-整条-nll-算力曲线">6.3 整条 NLL-算力曲线</h3>
<p>不能只看训练结束的一点。每隔固定成本记录验证 NLL，画出 $L^{\mathrm{valid}}(C)$。在大部分预算区间都更低的曲线，说明模型更早形成了有效能力。还可以计算曲线下面积；因为纵轴是 Loss，所以面积越小越好。</p>
<h3 id="64-每次冻结释放了多少计算">6.4 每次冻结释放了多少计算</h3>
<p>记录每个预算区间的活跃参数量、冻结参数量、GPU 小时、训练 token 和估算反向 FLOPs。否则即使 NLL 相同，我们也无法证明冻结真的节省了算力。</p>
<p>一份理想报告会长这样：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">已用预算</th>
          <th>当前活跃层</th>
          <th style="text-align: right">冻结参数</th>
          <th style="text-align: right">验证 NLL</th>
          <th style="text-align: right">累计 GPU 小时</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">20%</td>
          <td>root</td>
          <td style="text-align: right">0%</td>
          <td style="text-align: right">7.20</td>
          <td style="text-align: right">4.0</td>
      </tr>
      <tr>
          <td style="text-align: right">40%</td>
          <td>depth 1</td>
          <td style="text-align: right">20%</td>
          <td style="text-align: right">6.10</td>
          <td style="text-align: right">8.0</td>
      </tr>
      <tr>
          <td style="text-align: right">60%</td>
          <td>depth 2</td>
          <td style="text-align: right">35%</td>
          <td style="text-align: right">5.20</td>
          <td style="text-align: right">12.0</td>
      </tr>
      <tr>
          <td style="text-align: right">90%</td>
          <td>deeper detail</td>
          <td style="text-align: right">50%</td>
          <td style="text-align: right">4.90</td>
          <td style="text-align: right">18.0</td>
      </tr>
      <tr>
          <td style="text-align: right">100%</td>
          <td>联合校准</td>
          <td style="text-align: right">0%</td>
          <td style="text-align: right">4.88</td>
          <td style="text-align: right">20.0</td>
      </tr>
  </tbody>
</table>
<p>表中数字只是说明格式，不是实验结果。它强调的是每个结果都必须对应已经支付的预算，不能只写“这一层训练好了”。</p>
<hr>
<h2 id="7-算力究竟省在哪里">7. 算力究竟省在哪里</h2>
<p>渐进训练不会神奇地让所有计算消失。它可能节省的是：</p>
<ol>
<li><strong>冻结参数的反向传播</strong>：稳定层不再计算参数梯度和优化器状态更新。</li>
<li><strong>高层状态缓存</strong>：对于固定训练样本，可以缓存冻结 encoder 的高层结果。</li>
<li><strong>实验复用</strong>：更换细节 kernel 时，可以从稳定的轮廓 checkpoint 出发。</li>
<li><strong>提前停止深度增长</strong>：当连续深度的边际收益低于成本时，不再增加层级。</li>
<li><strong>按设备分级发布</strong>：低算力设备只运行高层，高算力设备继续读取细节。</li>
</ol>
<p>但如果最终联合校准必须重新训练全部参数很久，或者冻结后性能明显恶化，那么算力优势就不存在。这个可能性必须保留。</p>
<hr>
<h2 id="8-最危险的失败方式">8. 最危险的失败方式</h2>
<h3 id="81-root-被迫记住所有细节">8.1 root 被迫记住所有细节</h3>
<p>如果 root 容量过大，它可能直接记忆 token，后续深度失去作用。需要限制 root 容量，并通过 detail 打乱和 root 消融确认信息分工。</p>
<h3 id="82-冻结了错误的早期协议">8.2 冻结了错误的早期协议</h3>
<p>早期 root 可能只是快速收敛到一个局部最优。过早硬冻结会让后续层永远修补错误地基。因此正式实验应比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>硬冻结
</span></span><span style="display:flex;"><span>降低学习率
</span></span><span style="display:flex;"><span>周期性短暂解冻
</span></span><span style="display:flex;"><span>全程联合训练
</span></span></code></pre></div><h3 id="83-correction-head-只是另一个-flat-模型">8.3 correction head 只是另一个 flat 模型</h3>
<p>如果每层 correction head 可以绕过 TreeHeap 地址，直接读取全部 token，它会退化成普通 MLP。每个 head 必须只读取对应深度的 TreeHeap 状态，并接受地址交换与 detail shuffle 审计。</p>
<h3 id="84-深度增加反而损害泛化">8.4 深度增加反而损害泛化</h3>
<p>训练 NLL 下降而验证 NLL 上升，说明新增层只记住了训练语料。此时不能把“更深”当作“更智能”。</p>
<hr>
<h2 id="9-claimpredict-与-proof">9. Claim、Predict 与 Proof</h2>
<h3 id="claims3-th-progressive-c01open">Claim：S3-TH-PROGRESSIVE-C01（Open）</h3>
<blockquote>
<p>在预先固定的有限算力预算内，TreeHeap 可以把 token 预测分解为高层轮廓预测与逐深度 detail 残差，并按预算节点冻结部分旧层；该调度应比全程联合训练更早达到目标验证 NLL，或在相同总成本下得到更低 NLL。</p></blockquote>
<h3 id="predict">Predict</h3>
<p>如果 Claim 成立，应同时观察到：</p>
<ol>
<li>在相同预算节点，预算冻结方案的验证 NLL 曲线低于或接近联合训练。</li>
<li>冻结高层后，新增 detail 仍能在后续预算区间降低验证 NLL。</li>
<li>预算冻结方案更早达到预先设定的目标 NLL。</li>
<li>在总预算 $B$ 用完时，它取得更低 NLL，或者用更少反向 FLOPs取得相同 NLL。</li>
<li>打乱某层 detail 会损害它已经带来的收益，证明 correction head 没有绕过树结构。</li>
</ol>
<h3 id="对照实验">对照实验</h3>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th>训练方式</th>
          <th>目的</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A</td>
          <td>总预算 $B$ 内，所有深度始终联合训练</td>
          <td>当前基线</td>
      </tr>
      <tr>
          <td>B</td>
          <td>相同总预算，按固定时间节点硬冻结旧层</td>
          <td>测试最大算力节省</td>
      </tr>
      <tr>
          <td>C</td>
          <td>相同总预算，按节点降低旧层学习率</td>
          <td>测试协议能否缓慢协调</td>
      </tr>
      <tr>
          <td>D</td>
          <td>相同总预算，按节点冻结并保留末段联合校准</td>
          <td>测试冻结与自由度的折中</td>
      </tr>
  </tbody>
</table>
<p>所有实验必须使用相同语料、tokenizer、参数规模、固定验证集、随机种子组和总预算 $B$。报告最终 NLL 的同时，必须报告 NLL-成本曲线、达到目标 NLL 的时间、GPU 小时、训练 token 和反向 FLOPs估计。</p>
<h3 id="falsification">Falsification</h3>
<p>以下任一结果都会削弱或否定 Claim：</p>
<ul>
<li>在相同预算下，联合训练始终更早达到目标 NLL；</li>
<li>冻结高层后，新增深度无法继续学习；</li>
<li>所有收益都集中在最后一层或 GRU 输出头；</li>
<li>打乱 TreeHeap 地址和 detail 不影响结果；</li>
<li>冻结没有减少反向计算，或节省的计算被更差 NLL 完全抵消；</li>
<li>所谓轮廓模型只是在训练集上记忆，固定验证集没有改善。</li>
</ul>
<hr>
<h2 id="10-c10-审计之后实验应当怎样继续">10. C10 审计之后，实验应当怎样继续</h2>
<p>C10 是本文问题的历史起点，但不再是可用于比较的正式基线。它的 teacher-forcing 与 EOS 尾部混杂，使低 NLL 不能可靠回答“模型是否利用输入并形成了有效预测”。如果继续拿它比较预算训练，可能只是精确测量一个错误目标。</p>
<p>因此，正式实验必须先建立通过 source-conditioned 审计的新联合训练基线，再比较预算冻结方案。正确顺序是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>保留 C10 作为历史失败证据
</span></span><span style="display:flex;"><span>  -&gt; 修复 source/target、teacher-forcing 和 EOS 评价边界
</span></span><span style="display:flex;"><span>  -&gt; 建立通过条件依赖与生成审计的新联合训练基线
</span></span><span style="display:flex;"><span>  -&gt; 固定数据、参数规模、验证集和总算力预算
</span></span><span style="display:flex;"><span>  -&gt; 实现逐深度 correction head
</span></span><span style="display:flex;"><span>  -&gt; 给定相同总预算，比较预算冻结与联合训练的 NLL-成本曲线
</span></span></code></pre></div><p>我们现在没有证据宣称“越靠近 root 必然是人类可读的语义轮廓”。真正需要证明的是一个更克制、也更有工程价值的命题：</p>
<blockquote>
<p><strong>较浅状态是否先形成稳定、可复用的预测能力；较深状态是否能够在其上持续增加信息。</strong></p></blockquote>
<p>如果答案是肯定的，TreeHeap 的层级就不只是数据摆放方式，而会成为一种可观察、可冻结、可继续生长的训练坐标系。</p>
<hr>
<h2 id="11-当前结论">11. 当前结论</h2>
<p>本文没有宣布新实验成功。它完成的是下一阶段航线设计：</p>
<ul>
<li>Loss 仍然使用经过长期验证的 token 交叉熵；</li>
<li>TreeHeap 深度负责拆分预测分辨率；</li>
<li>每层通过 logit 残差修正上一层；</li>
<li>冻结时间由实验开始前声明的算力预算节点决定；</li>
<li>首要目标是固定总预算下更低的验证 NLL，而不是等待每层无限收敛；</li>
<li>算力优势必须用 NLL-成本曲线和达到目标质量的时间证明；</li>
<li>结构真实性必须经过地址和 detail 干预审计。</li>
</ul>
<p>这条航线值得执行，因为它把“先有轮廓，再补细节”的直觉，转换成了可以失败的数学定义和实验表格。</p>
<blockquote>
<p>本文提出的是 SameTime/TreeHeap 项目中的研究假设与实验设计，不主张未经文献检索的普遍学术首创。代码、实验和文章按项目许可证公开，欢迎复现与反驳。</p></blockquote>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-074] 为什么 Loss 在下降，模型却只会一句话：C10 勘误与证据撤回</title>
      <link>https://www.grepcode.cn/spr/074-c10-loss-collapse-retraction.html</link>
      <pubDate>Tue, 28 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/074-c10-loss-collapse-retraction.html</guid>
      <description>公开说明 STONE-1 C10 的条件坍缩、teacher forcing 混杂与 EOS 尾部问题，并逐项界定哪些历史结论保留、哪些必须撤回。</description>
      <content:encoded><![CDATA[<h1 id="为什么-loss-在下降模型却只会一句话">为什么 Loss 在下降，模型却只会一句话</h1>
<p>这是一次正式勘误，不是给失败结果换一种好听说法。</p>
<p>C10 完成了约 <code>1.410B</code> 个目标 token 的训练，验证 NLL 从 <code>16.7848</code> 降到 <code>4.7275</code>。仅看曲线，模型似乎持续学习。然而 Houming818 用三个明显不同的英文输入测试同一个 checkpoint：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>The earth is round.
</span></span><span style="display:flex;"><span>The apple is sweet
</span></span><span style="display:flex;"><span>why is the window wet? because the sky cried
</span></span></code></pre></div><p>三个输出都迅速进入近乎相同的“一带一路”重复句式，而且 48 个输出 piece 内没有正常结束。这不是偶然误译，而是严重的<strong>条件坍缩</strong>：模型没有根据不同英文条件产生不同答案。</p>
<p>因此，C10 不能作为翻译成功、STONE-1 完成或私有协议形成的证据。</p>
<h2 id="1-为什么输出一样训练-loss-还能下降">1. 为什么输出一样，训练 Loss 还能下降</h2>
<p>训练和 CLI 实际执行了两个不同任务。</p>
<p>训练使用 teacher forcing。预测第 $t$ 个中文 token 时，decoder 会收到正确的中文前缀：</p>
$$ p(y_t\mid y^{gold}_{\lt t},x) $$<p>这里 $x$ 是英文 source，$y^{gold}_{\lt t}$ 是答案中已经给出的正确中文前缀。</p>
<p>CLI 自由生成时没有答案可看，只能把自己刚刚生成的 token 喂回去：</p>
$$ p(y_t\mid y^{model}_{\lt t},x) $$<p>假设训练样本分别是“苹果很甜”和“地球是圆的”。即使模型完全忽略英文，只要训练时已经看到“苹果很”或“地球是”，也可能比较容易猜出下一个字。因此 NLL 仍会下降。</p>
<p>自由生成从同一个 BOS 开始。如果第一步选中了高频逗号，后续预测就可能滑进训练语料中最强的中文模板。C10 进入的正是“一带一路”吸引子。</p>
<p>所以这条 NLL 曲线真实记录了优化过程，却回答错了研究问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>它测到了：给定正确中文前缀，能否继续中文。
</span></span><span style="display:flex;"><span>它没证明：给定不同英文，能否生成对应中文。
</span></span></code></pre></div><h2 id="2-第二个问题eos-尾部淹没了英文">2. 第二个问题：EOS 尾部淹没了英文</h2>
<p>C10 的 TreeHeap 有 256 个可见 leaf，而 source 最多使用前 128 个位置。短句只有约 6 到 11 个有效 piece，其余大量位置被写成 EOS，并且仍作为可见节点参加递归 FOLD。</p>
<p>以 6-piece 输入为例，实际状态接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>6 个英文 piece + 250 个可见 EOS
</span></span></code></pre></div><p>不同英文句子的少量差异，被放进几乎相同的大面积 EOS 背景中。我们尚未完成定量消融，但从代码结构上看，这足以构成严重混杂，必须修复后重测。</p>
<h2 id="3-哪些结论撤回哪些仍保留">3. 哪些结论撤回，哪些仍保留</h2>
<table>
  <thead>
      <tr>
          <th>历史内容</th>
          <th>新状态</th>
          <th>原因</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>C10 是有效翻译 checkpoint</td>
          <td>撤回</td>
          <td>三个无关输入生成同一模板</td>
      </tr>
      <tr>
          <td>C10 NLL 证明英文到中文学习</td>
          <td>撤回</td>
          <td>teacher forcing 允许忽略英文</td>
      </tr>
      <tr>
          <td>C09 已完成 STONE-1</td>
          <td>暂停</td>
          <td>同族评测 gate 没有排除 source 忽略</td>
      </tr>
      <tr>
          <td>C08 可公开下载</td>
          <td>保留</td>
          <td>文件和复现价值仍在</td>
      </tr>
      <tr>
          <td>C08 是可靠翻译候选</td>
          <td>暂停</td>
          <td>需要重新做条件依赖审计</td>
      </tr>
      <tr>
          <td>detail shuffle 会改变 NLL</td>
          <td>保留观测</td>
          <td>数字本身没有伪造</td>
      </tr>
      <tr>
          <td>detail shuffle 证明英文语义进入树</td>
          <td>撤回外推</td>
          <td>它只证明 decoder 依赖某些树状态</td>
      </tr>
      <tr>
          <td>M0 代数、mirror、compose/decompose proof</td>
          <td>不受影响</td>
          <td>它们不依赖 C10 翻译 Loss</td>
      </tr>
      <tr>
          <td>旋转与预算训练假设</td>
          <td>保留为开放假设</td>
          <td>尚未被 C10 成功或失败直接验证</td>
      </tr>
  </tbody>
</table>
<p>我们不会删除旧文章。主要受影响文章顶部会增加证据状态更新；仍在修订中的 SPR-073 由本文统一覆盖。这样外部读者能看到结论如何形成，也能看到它后来如何被反例推翻。</p>
<h2 id="4-为什么现有-bleu-也没有及时拦住问题">4. 为什么现有 BLEU 也没有及时拦住问题</h2>
<p>早期实验确实记录过自由生成 BLEU、非空率和重复率，但这些汇总指标没有覆盖以下关键问题：</p>
<ol>
<li>不同 source 是否产生真正不同的输出；</li>
<li>打乱 source 后 Loss 是否基本不变；</li>
<li>清空 source 后 decoder 是否仍能依靠中文前缀预测；</li>
<li>第一个输出 token 在尚无中文前缀时，是否随英文变化。</li>
</ol>
<p>只测“输出非空”远远不够。一个复读机当然也能稳定输出非空文本。</p>
<h2 id="5-重启训练前必须通过的四道门">5. 重启训练前必须通过的四道门</h2>
<h3 id="gate-asource-shuffle">Gate A：Source shuffle</h3>
<p>固定中文 target 和正确前缀，只在 batch 内打乱英文 source。记正常 Loss 为 $L_{native}$，打乱后为 $L_{shuffle}$。</p>
<p>真正依赖英文的模型应满足：</p>
$$ L_{shuffle}-L_{native}>0 $$<p>而且差异必须超过预注册门槛和多 seed 波动。</p>
<h3 id="gate-bempty-source">Gate B：Empty source</h3>
<p>把英文换成全 EOS 或严格 mask 的空输入。如果 NLL 几乎不变，说明 decoder 主要是中文语言模型。</p>
<h3 id="gate-cfirst-step-logits">Gate C：First-step logits</h3>
<p>生成第一个 token 时还没有中文历史，这是最干净的 source 依赖测试。不同英文输入的 first-step 概率分布必须出现可重复差异，而不是永远选择同一个逗号。</p>
<h3 id="gate-d自由生成体检">Gate D：自由生成体检</h3>
<p>固定测试集必须报告：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>unique-output rate
</span></span><span style="display:flex;"><span>source-output conditional diversity
</span></span><span style="display:flex;"><span>repetition rate
</span></span><span style="display:flex;"><span>EOS arrival rate
</span></span><span style="display:flex;"><span>BLEU / chrF
</span></span><span style="display:flex;"><span>人工样例
</span></span></code></pre></div><p>这些 gate 未通过前，不再启动几十小时的扩容训练。</p>
<h2 id="6-代码应该怎样修">6. 代码应该怎样修</h2>
<p>第一步不是立刻增加模型参数，而是恢复问题定义：</p>
<ol>
<li>source 的可见长度只覆盖真实 token 和必要的结构节点；padding 不得伪装成大量有效 EOS；</li>
<li>训练和验证保留 token 交叉熵，但增加 wrong-source 对照；</li>
<li>每次验证同时运行 teacher-forced 与 free-running 两条路径；</li>
<li>checkpoint 选择不能只看 teacher-forced NLL；</li>
<li>长训练前先用小规模数据证明 source shuffle 和 empty source 会显著恶化结果。</li>
</ol>
<p>可以加入一个条件依赖约束：要求错误 source 的损失高于正确 source。若间隔为 $m$，则可写成：</p>
$$ L_{dep}=\max\left(0,m+L_{native}-L_{wrong\ source}\right) $$<p>但它只是候选修复，必须先做消融，不能直接当成正确答案。</p>
<h2 id="7-本次真正得到的证据">7. 本次真正得到的证据</h2>
<p>这次最有价值的证据不是 <code>NLL=4.7275</code>，而是三个手工 CLI 输入。</p>
<p>它们指出：我们的自动 gate 没有覆盖最基本的产品问题。Houming818 的一句“它只会说这个，Loss 怎么可能还在降”，迫使代码审计回到训练函数本身，最终找到了 teacher forcing 与自由生成之间的断层。</p>
<p>因此当前航行状态是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>C10 长训练：完成，但翻译 Claim 无效
</span></span><span style="display:flex;"><span>C09 STONE-1 完成状态：暂停
</span></span><span style="display:flex;"><span>C08 公开制品：保留，翻译身份待复审
</span></span><span style="display:flex;"><span>下一步：先证明 source 真正进入计算，再谈规模化
</span></span></code></pre></div><p>公开错误不是项目的附属工作，而是 ARA 的核心功能。数据没有被删除，旧文章没有被偷偷改成“我们早就知道”，错误的结论也不会继续作为下一条 Claim 的地基。</p>
<blockquote>
<p><strong>License: GPLv3。本文的勘误、审计方法和后续 falsification gate 与 SameTime/ARA 一并公开。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-075] TreeHeap 为什么会复读：从伪递归读取到 H_state 整体解码</title>
      <link>https://www.grepcode.cn/spr/075-treeheap-hstate-unfold-decoder.html</link>
      <pubDate>Wed, 29 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/075-treeheap-hstate-unfold-decoder.html</guid>
      <description>审计 C11 decoder 的真实计算过程，并提出 source H_state 到 target H_state、再经 TreeHeap UNFOLD 一次生成完整字符串的对称解码方案。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-为什么会复读">TreeHeap 为什么会复读</h1>
<p>C11 修复了一个重要问题：短输入后面不再铺满可见的 EOS，而是使用不可见 PAD。实验也证明，打乱或清空 source 会让 NLL 变差。因此，TreeHeap 的 <code>H_state</code> 确实携带了输入信号。</p>
<p>但 CLI 仍然出现了明显复读：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：为什么鲨鱼不坐沙发？
</span></span><span style="display:flex;"><span>输出：我只想说，我只想说，我只想说……
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>输入：夜幕、星光、草木清香……
</span></span><span style="display:flex;"><span>输出：一股香味，香味浓郁，香味浓郁……
</span></span></code></pre></div><p>第二个例子甚至有一点语义相关性：输入中的“清香”影响了输出中的“香味”。这说明模型不是完全忽略输入。但是，它只能释放一个很短的主题，随后便进入循环。</p>
<p>Houming818 提出了一个关键问题：</p>
<blockquote>
<p>如果 decoder 真在递归生成一个 64-token 结构，为什么会如此稳定地把一个短句重复八次？这里会不会存在代码逻辑错误？</p></blockquote>
<p>代码审计表明，这个怀疑是正确的。</p>
<h2 id="1-当前的-recursivedecoder-并没有递归消费-treeheap">1. 当前的 RecursiveDecoder 并没有递归消费 TreeHeap</h2>
<p>当前 decoder 的单次 <code>read()</code> 确实会从 root 向下遍历 TreeHeap 的多个深度，并计算各层的加权 context。因此，把它称为“树上递归读取”并非完全错误。</p>
<p>问题在于：每生成一个新 token，<code>read()</code> 都重新执行，并重新初始化：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>active <span style="color:#f92672">=</span> root
</span></span></code></pre></div><p>其实际流程是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第 1 步：从 root 重新读取全树摘要 → token 1
</span></span><span style="display:flex;"><span>第 2 步：从 root 重新读取全树摘要 → token 2
</span></span><span style="display:flex;"><span>第 3 步：从 root 重新读取全树摘要 → token 3
</span></span><span style="display:flex;"><span>……
</span></span></code></pre></div><p>它没有保存以下状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>上一步走到哪个 subheap
</span></span><span style="display:flex;"><span>哪些节点已经被消费
</span></span><span style="display:flex;"><span>下一步应读取哪个地址
</span></span><span style="display:flex;"><span>递归栈位于哪里
</span></span><span style="display:flex;"><span>当前分支何时结束
</span></span></code></pre></div><p>所以，当前结构不是“跨 token 的递归解压”，而是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一棵 H_state
</span></span><span style="display:flex;"><span>→ 每一步重新计算近似的全树摘要
</span></span><span style="display:flex;"><span>→ GRU 根据上一个 token 生成下一个 token
</span></span></code></pre></div><p>TreeHeap 只参与了 context 的计算。输出过程本身仍然是一台普通的流式自回归生成器。</p>
<h2 id="2-为什么重复八次不是小概率事件">2. 为什么重复八次不是小概率事件</h2>
<p>直觉上，连续八次生成同一个短句似乎概率很低。但 CLI 使用的是 greedy <code>argmax</code>，不是每一步独立随机抽样。</p>
<p>每一步执行的是一个确定函数：</p>
$$ (h_t, y_{t-1}, C_t) \longmapsto y_t $$<p>其中 $h_t$ 是 GRU hidden state，$y_{t-1}$ 是上一个 token，$C_t$ 是重新从同一棵 TreeHeap 读出的 context。</p>
<p>一旦系统进入类似下面的状态环：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>“我只想说” → “，” → “我只想说”
</span></span></code></pre></div><p>下一轮输入状态就会再次接近上一轮。确定性 <code>argmax</code> 会把它送回同一个环。这叫周期吸引子。它不是八次巧合，而是一次进入循环后被稳定地重复。</p>
<p>因此，增加 <code>max-output</code> 只会给循环更多执行次数，不会增加 H_state 中可以依次解出的细节。</p>
<h2 id="3-256-个-leaf-在哪里">3. 256 个 leaf 在哪里</h2>
<p>C11 的 256 个 leaf 属于输入 encoder：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>最多 256 个 source piece
</span></span><span style="display:flex;"><span>→ 256-leaf TreeHeap
</span></span><span style="display:flex;"><span>→ FOLD
</span></span><span style="display:flex;"><span>→ source H_state
</span></span></code></pre></div><p>当前 decoder 并没有一棵 256-leaf 输出树。它只是最多循环 128 次或 CLI 指定的 64 次。</p>
<p>这两个“长度”在概念上完全不同：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入 leaf 数量：结构容量
</span></span><span style="display:flex;"><span>输出循环次数：自回归执行次数
</span></span></code></pre></div><p>循环 64 次不等于解压了 64 个不同的 TreeHeap 地址。</p>
<h2 id="4-houming818-的新假设先形成整体再突然生成-string">4. Houming818 的新假设：先形成整体，再突然生成 string</h2>
<p>Houming818 提出，TreeHeap 的输出未必应该是 stream。模型可能先形成一个完整的输出结构，再一次性坍缩为 string。</p>
<p>工程上可以把“突然生成”严格定义为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>source H_state
</span></span><span style="display:flex;"><span>→ target H_state
</span></span><span style="display:flex;"><span>→ 递归 UNFOLD
</span></span><span style="display:flex;"><span>→ 全部 target leaf
</span></span><span style="display:flex;"><span>→ 并行 token 概率
</span></span><span style="display:flex;"><span>→ 完整 string
</span></span></code></pre></div><p>如果输出上限是 64 个 token，只需要 6 层展开：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 → 2 → 4 → 8 → 16 → 32 → 64
</span></span></code></pre></div><p>若输出上限为 128，则需要 7 层。这不是在一个计算步骤中凭空出现文本，而是在 $\log_2 N$ 层结构计算后，并行得到 $N$ 个带地址的输出位置。</p>
<h2 id="5-完整-h_state-不是只有-root">5. 完整 H_state 不是只有 root</h2>
<p>TreeHeap encoder 的完整状态应写成：</p>
$$ H = \left(r, \{d_k\}, \{g_k\}, \{m_k\}\right) $$<p>其中：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>$r$</td>
          <td>root，全局压缩状态</td>
      </tr>
      <tr>
          <td>$d_k$</td>
          <td>第 $k$ 层折叠留下的 detail</td>
      </tr>
      <tr>
          <td>$g_k$</td>
          <td>左右方向或手性 gate</td>
      </tr>
      <tr>
          <td>$m_k$</td>
          <td>节点是否存在的 mask</td>
      </tr>
  </tbody>
</table>
<p>只有 root 通常无法无损恢复全部 leaf。TreeHeap 的可逆性来自 <code>root + details + gates</code>，不是来自 root 独自记住整句话。</p>
<p>因此，新 decoder 不应直接让 root 输出所有 token，也不应反复读取同一个摘要。它应该先预测目标 TreeHeap 的完整状态：</p>
$$ H_{target} = K_{\theta}(H_{source}) $$<p>然后执行：</p>
$$ Y = \operatorname{UNFOLD}(H_{target}) $$<h2 id="6-不重新发明-split复用现有-treeheap-逆运算">6. 不重新发明 split：复用现有 TreeHeap 逆运算</h2>
<p>当前 encoder 已经有一套严格的 FOLD/UNFOLD 方程。给定 parent、detail 和 gate，可以恢复左右子节点：</p>
$$ a = p - U(d) $$$$ \hat{b} = d + P(a) $$$$ left = g \cdot a + (1-g)\cdot\hat{b} $$$$ right = g \cdot\hat{b} + (1-g)\cdot a $$<p>这里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p：parent state
</span></span><span style="display:flex;"><span>d：detail state
</span></span><span style="display:flex;"><span>g：左右方向 gate
</span></span><span style="display:flex;"><span>U：update kernel
</span></span><span style="display:flex;"><span>P：predictor kernel
</span></span></code></pre></div><p>所以新 decoder 不需要手写一个任意的“父节点拆成左右节点”函数。它只需学习预测目标树的参数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>target_root = K_root(source H_state)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>target_detail[k] = K_detail(
</span></span><span style="display:flex;"><span>    target_parent,
</span></span><span style="display:flex;"><span>    source_subheap,
</span></span><span style="display:flex;"><span>    source_root,
</span></span><span style="display:flex;"><span>    depth,
</span></span><span style="display:flex;"><span>    address
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>target_gate[k] = K_gate(...)
</span></span></code></pre></div><p>随后使用同一套 UNFOLD 代数确定性地得到左右子节点。这使 encoder 与 decoder 共享同一种 TreeHeap 数学协议。</p>
<h2 id="7-新-decoder-的最小版本">7. 新 decoder 的最小版本</h2>
<p>第一版先不解决可变长度，固定生成 128 个输出 leaf：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>source tokens
</span></span><span style="display:flex;"><span>→ source TreeHeap FOLD
</span></span><span style="display:flex;"><span>→ source H_state
</span></span><span style="display:flex;"><span>→ 预测 target root/details/gates
</span></span><span style="display:flex;"><span>→ TreeHeap UNFOLD 七层
</span></span><span style="display:flex;"><span>→ 128 个 target leaf
</span></span><span style="display:flex;"><span>→ 共享 output head
</span></span><span style="display:flex;"><span>→ 128 组 token logits
</span></span></code></pre></div><p>所有目标位置同时计算交叉熵：</p>
$$ L_{token} = \frac{1}{128}\sum_{i=1}^{128} CE\left(W_o z_i, y_i\right) $$<p>$z_i$ 是第 $i$ 个目标 leaf。梯度路径为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token loss
</span></span><span style="display:flex;"><span>→ target leaf
</span></span><span style="display:flex;"><span>→ UNFOLD
</span></span><span style="display:flex;"><span>→ target detail/gate/root predictor
</span></span><span style="display:flex;"><span>→ source H_state
</span></span><span style="display:flex;"><span>→ encoder FOLD
</span></span></code></pre></div><p>这就是 encoder 和 decoder 共同形成私有协议的可微路径。训练过程不需要把正确的前一个 token 喂给 decoder，因此也没有当前意义上的 teacher forcing 断层。</p>
<h2 id="8-为什么它可能减少复读">8. 为什么它可能减少复读</h2>
<p>新结构中，第 17 和第 18 个 token 对应不同地址：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf[17] = root → left → right → ...
</span></span><span style="display:flex;"><span>leaf[18] = root → left → right → ...
</span></span></code></pre></div><p>它们共享上层轮廓，但必须经过不同路径和 detail。后一个 token 不会因为前一个 token 是“我只想说”而再次收到同样的输入。</p>
<p>不过，非流式生成并不自动保证成功。如果所有预测 detail 都接近零，不同 leaf 仍可能坍缩成相似状态。因此，不能只看 NLL。</p>
<h2 id="9-claimpredict-与-proof">9. Claim、Predict 与 Proof</h2>
<h3 id="claim">Claim</h3>
<p>给定同一个 TreeHeap encoder，使用持久输出地址和代数 UNFOLD 的整体 decoder，应该比当前“每 token 重置 root”的 GRU decoder 更能保持输出位置差异，并降低自由生成中的周期重复。</p>
<h3 id="predict">Predict</h3>
<p>如果 Claim 成立，应同时观察到：</p>
<ol>
<li>自由输出的 token-level distinct-2/4 明显提高；</li>
<li>最长重复片段和重复运行长度下降；</li>
<li>打乱目标 leaf 地址后，NLL 显著升高；</li>
<li>清零不同深度的 target detail，会产生可重复但不同的损伤；</li>
<li>leaf 间方差不坍缩为零；</li>
<li>source shuffle 和 empty source 仍保持显著损伤；</li>
<li>相同训练数据、参数量和计算预算下，与旧 GRU decoder 正面对比。</li>
</ol>
<h3 id="falsification">Falsification</h3>
<p>以下任一结果都会否定强 Claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>UNFOLD decoder 仍产生相同短语循环；
</span></span><span style="display:flex;"><span>打乱 leaf 地址几乎不影响 NLL；
</span></span><span style="display:flex;"><span>不同 leaf 的状态趋于相同；
</span></span><span style="display:flex;"><span>detail 清零没有损伤；
</span></span><span style="display:flex;"><span>source shuffle 不再影响结果；
</span></span><span style="display:flex;"><span>改进仅来自更多参数或更多计算。
</span></span></code></pre></div><p>第一轮实验只验证固定 128-leaf 输出。只有结构和自由生成闸门通过后，才增加节点 <code>STOP/SPLIT</code> 概率来学习可变长度，避免一次引入过多不确定变量。</p>
<h2 id="10-当前航行状态">10. 当前航行状态</h2>
<p>C11 已经证明：修正 PAD 协议后，TreeHeap 的 source H_state 对目标概率存在因果影响。</p>
<p>C11 同时暴露：当前 decoder 只会反复读取全树摘要，并不沿 TreeHeap 递归解压输出位置。因此，“输入结构参与了计算”和“已经形成 TreeHeap decoder”是两个不同结论。</p>
<p>现在的修复航线是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>保留：现有 FOLD encoder 和 C11 source-conditioning 证据
</span></span><span style="display:flex;"><span>删除：流式 GRU 作为最终 TreeHeap decoder 的假设
</span></span><span style="display:flex;"><span>新增：source H_state → target H_state → UNFOLD → string
</span></span><span style="display:flex;"><span>先测：固定长度、结构因果性、自由生成复读
</span></span><span style="display:flex;"><span>后测：可变长度、翻译、对话和规模化训练
</span></span></code></pre></div><p>这不是把失败改名为新架构。恰恰相反，它来自 CLI 反例和代码审计：当前所谓“递归 decoder”只在一次读取内部递归，却没有在输出过程里递归。只有把输出地址、detail 和 UNFOLD 真正放进计算图，TreeHeap 才拥有与 FOLD encoder 对称的另一半。</p>
<blockquote>
<p><strong>License: GPLv3。本文的代码审计、H_state 整体解码方案、Claim/Predict/Falsification 与 SameTime/ARA 一并公开。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-076] TreeHeap 长距通信：不做全局 Attention，试试 XOR Butterfly</title>
      <link>https://www.grepcode.cn/spr/076-treeheap-butterfly-long-range.html</link>
      <pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/076-treeheap-butterfly-long-range.html</guid>
      <description>审视二叉 TreeHeap 的长距瓶颈，放弃循环移位与全树 flat attention，提出基于二进制地址、局部可逆核和对数通信轮次的 XOR Butterfly 实验。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-长距通信不做全局-attention试试-xor-butterfly">TreeHeap 长距通信：不做全局 Attention，试试 XOR Butterfly</h1>
<blockquote>
<p><strong>证据状态：合成长距地址通信机制得到支持；语言价值尚未验证。</strong></p>
<p>本文首先公开问题、Claim、预测和反证条件。正式数据出来后再更新结论，不把数学上按定义成立的部分冒充语言能力。</p></blockquote>
<h2 id="1-为什么突然要研究长距离">1. 为什么突然要研究长距离</h2>
<p>我们刚刚修正了 decoder 的一个设计：不再让 <code>STOP</code> gate 决定一棵子树有没有资格继续学习，而是强制执行递归。没有贡献的通道，可以让自己的 value 增量自然趋近于零。</p>
<p>但 Houming818 随即指出了更深的问题。</p>
<p>长度为 8 的 string 放进相邻二叉树以后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>                    root
</span></span><span style="display:flex;"><span>              /              \
</span></span><span style="display:flex;"><span>          [0..3]             [4..7]
</span></span><span style="display:flex;"><span>         /     \             /     \
</span></span><span style="display:flex;"><span>      [0,1]   [2,3]       [4,5]   [6,7]
</span></span></code></pre></div><p>位置 0 和位置 1 很快相遇；位置 0 和位置 7 却必须一直上升到 root。</p>
<p>如果 leaf 0 的输出需要 leaf 7 的信息，计算需要经过多层 FOLD，再经过多层 UNFOLD。中间每一层都在改变分辨率。于是问题不再只是“梯度能不能到达”，而是：</p>
<blockquote>
<p>远距离关系是否被迫穿过一个过于粗糙的 root 瓶颈？</p></blockquote>
<h2 id="2-可逆不等于关系容易计算">2. 可逆不等于关系容易计算</h2>
<p>当前 lifting TreeHeap 可以保存：</p>
$$ H_{state}=\left(root,details,addresses\right) $$<p>只要这些状态完整，FOLD/UNFOLD 可以做到数值闭合。</p>
<p>但是，“可以还原所有输入”不等于“任意两个位置的关系都已经在 root 中显式出现”。</p>
<p>例如：</p>
$$ relation(x_0,x_7) $$<p>可能需要同时观察两个遥远 leaf。即使 root 和 details 没有丢失它们，decoder 仍然需要一条合适的计算路径把它们放到同一个局部 kernel 中。</p>
<p>所以这里必须区分：</p>
<table>
  <thead>
      <tr>
          <th>问题</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>信息保存</td>
          <td>原始 leaf 是否还能由 root + details 恢复</td>
      </tr>
      <tr>
          <td>关系计算</td>
          <td>两个遥远 leaf 是否能在较短路径内共同参与一个算子</td>
      </tr>
      <tr>
          <td>语言理解</td>
          <td>模型是否从真实语料中归纳出有用关系</td>
      </tr>
  </tbody>
</table>
<p>本轮只研究第二项。</p>
<h2 id="3-为什么不直接让整棵树参加-attention">3. 为什么不直接让整棵树参加 Attention</h2>
<p>一个直接方案是让 query 对所有 TreeHeap 节点做一次全局 softmax：</p>
$$ C=\sum_i softmax(QK_i^T)V_i $$<p>这样梯度很容易到达所有节点，但 READ 已经变成了 flat attention。树只负责提前制造一批向量，最终查询仍然是全局比较。</p>
<p>这可以作为诊断基线，却不能成为 TreeHeap 的核心答案。否则最合理的工程选择确实是直接使用 Transformer。</p>
<h2 id="4-为什么循环矩阵也不够">4. 为什么循环矩阵也不够</h2>
<p>另一个想法是把 string 做循环移位：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cat is running
</span></span><span style="display:flex;"><span>is running cat
</span></span><span style="display:flex;"><span>running cat is
</span></span></code></pre></div><p>它形成循环矩阵，适合做圆周卷积，也能让句尾与句首靠近。</p>
<p>问题是语言通常不是圆：</p>
<ul>
<li>句尾和句首不天然相邻；</li>
<li>循环移动不会缩短所有位置对的距离；</li>
<li>如果真的把每个完整 rotation 挂在 leaf 上，会产生 $O(N^2)$ 数据复制；</li>
<li>decoder 可能直接从复制的 string 绕过 TreeHeap。</li>
</ul>
<p>所以循环矩阵提供了一个观察坐标系，但没有一般性解决长距通信。</p>
<h2 id="5-稀疏系统的客观下限">5. 稀疏系统的客观下限</h2>
<p>假设每个节点一轮只能与固定数量 $k$ 的邻居通信。经过 $t$ 轮，它最多影响大约 $k^t$ 个节点。要覆盖长度为 $N$ 的空间，至少需要：</p>
$$ t=\Omega(\log_k N) $$<p>因此，在不使用全连接的前提下，不能要求任意两个节点都一跳相遇。真正合理的目标是：</p>
<blockquote>
<p>用 $O(\log N)$ 轮局部计算建立全局感受野，并避免所有信息同时挤入一个 root。</p></blockquote>
<h2 id="6-xor-butterfly利用二进制地址">6. XOR Butterfly：利用二进制地址</h2>
<p>长度 8 时，leaf 地址可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0 = 000
</span></span><span style="display:flex;"><span>1 = 001
</span></span><span style="display:flex;"><span>2 = 010
</span></span><span style="display:flex;"><span>3 = 011
</span></span><span style="display:flex;"><span>4 = 100
</span></span><span style="display:flex;"><span>5 = 101
</span></span><span style="display:flex;"><span>6 = 110
</span></span><span style="display:flex;"><span>7 = 111
</span></span></code></pre></div><p>第 $s$ 轮，让节点 $i$ 与下面的地址通信：</p>
$$ partner_s(i)=i\operatorname{XOR}2^s $$<p>三轮分别是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第 0 轮：(0,1) (2,3) (4,5) (6,7)
</span></span><span style="display:flex;"><span>第 1 轮：(0,2) (1,3) (4,6) (5,7)
</span></span><span style="display:flex;"><span>第 2 轮：(0,4) (1,5) (2,6) (3,7)
</span></span></code></pre></div><p>位置 7 的信息可以沿地址位传播：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>111 -&gt; 110 -&gt; 100 -&gt; 000
</span></span></code></pre></div><p>三轮后到达位置 0。一般情况下，任意两个 $D$ 位地址最多相差 $D=\log_2N$ 个 bit。</p>
<p>这不是循环，也没有制造假的句首句尾关系。它是在逐位打开二进制地址空间。</p>
<h2 id="7-每一轮仍然只是二节点-kernel">7. 每一轮仍然只是二节点 kernel</h2>
<p>最小的确定性 kernel 可以写成：</p>
$$ c=\frac{a+b}{\sqrt{2}} $$$$ d=\frac{a-b}{\sqrt{2}} $$<p>它可以精确逆运算：</p>
$$ a=\frac{c+d}{\sqrt{2}},\qquad b=\frac{c-d}{\sqrt{2}} $$<p>并保持总能量：</p>
$$ \lVert a\rVert^2+\lVert b\rVert^2 = \lVert c\rVert^2+\lVert d\rVert^2 $$<p>因此，在纯线性合同中，它不会自然放大或缩小 norm。它也是正交变换，反向梯度拥有相同的范数保持性质。</p>
<p>学习版本仍然只在一对节点中计算，不建立全局注意力矩阵。</p>
<h2 id="8-它与普通二叉-fold-有什么不同">8. 它与普通二叉 FOLD 有什么不同</h2>
<p>普通 FOLD 不断缩小宽度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>8 -&gt; 4 -&gt; 2 -&gt; 1
</span></span></code></pre></div><p>所有远程信息最后汇入一个 root。</p>
<p>Butterfly 保持固定宽度：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>8 -&gt; 8 -&gt; 8 -&gt; 8
</span></span></code></pre></div><p>但每轮扩大每个位置的感受野：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第 0 轮后：2 个地址
</span></span><span style="display:flex;"><span>第 1 轮后：4 个地址
</span></span><span style="display:flex;"><span>第 2 轮后：8 个地址
</span></span></code></pre></div><p>它不是新的外部内存，也不允许树无限生长。系统给定多少 leaf，就始终只使用多少 leaf。</p>
<p>推荐组合为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token leaves
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>XOR Butterfly 局部通信
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>带长距上下文的 leaves
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>TreeHeap FOLD
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>root + details
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>TreeHeap UNFOLD
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>对应的 Butterfly decoder
</span></span><span style="display:flex;"><span>    ↓
</span></span><span style="display:flex;"><span>leaf softmax
</span></span></code></pre></div><h2 id="9-这会不会又变成-flat">9. 这会不会又变成 flat</h2>
<p>Butterfly 每轮只有 $N/2$ 次二节点操作，总操作数为：</p>
$$ \frac{N}{2}\log_2N $$<p>它没有构造 $N\times N$ 的 token 对矩阵。</p>
<table>
  <thead>
      <tr>
          <th>结构</th>
          <th style="text-align: right">关系计算规模</th>
          <th style="text-align: right">任意节点通信距离</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Dense attention</td>
          <td style="text-align: right">$O(N^2)$</td>
          <td style="text-align: right">1</td>
      </tr>
      <tr>
          <td>单棵相邻二叉树</td>
          <td style="text-align: right">$O(N)$</td>
          <td style="text-align: right">最坏约 $2\log_2N$，经过 root</td>
      </tr>
      <tr>
          <td>XOR Butterfly</td>
          <td style="text-align: right">$O(N\log N)$</td>
          <td style="text-align: right">最坏 $\log_2N$，无单 root 汇聚</td>
      </tr>
  </tbody>
</table>
<p>它比单树付出更多计算，但仍比 dense attention 稀疏。是否值得，要由实验决定。</p>
<h2 id="10-本轮-claim">10. 本轮 Claim</h2>
<h3 id="s3-treeheap-butterfly-longrange-c01">S3-TREEHEAP-BUTTERFLY-LONGRANGE-C01</h3>
<p>固定容量的 XOR Butterfly，如果由局部二节点 kernel 组成，应当能够：</p>
<ol>
<li>在 $\log_2N$ 轮内建立所有地址之间的感受野；</li>
<li>保持确定性正交合同的可逆性、能量与梯度尺度；</li>
<li>在地址条件长距读取任务中，击败相同深度但始终只看邻接对的 kernel；</li>
<li>击败把所有输入压入一个有限 root 再并行读出的 bottleneck；</li>
<li>不构造 dense $N\times N$ attention。</li>
</ol>
<p>这个 Claim 不包含语言理解，也不包含 Transformer 性能对比。</p>
<h2 id="11-归纳实验是什么">11. 归纳实验是什么</h2>
<p>随机生成长度 32 的 token array，并给模型一个地址查询 $q$。输出位置 $i$ 的目标是：</p>
$$ target[i]=source[i\operatorname{XOR}q] $$<p>训练只使用二进制中含一个或两个 <code>1</code> 的查询。测试使用从未见过的三位及以上组合，包括：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>q = 31 = 11111
</span></span></code></pre></div><p>然后不重新训练，把同一个共享 kernel 放到长度 64：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>q = 63 = 111111
</span></span></code></pre></div><p>这在测试模型是否学会了“逐个地址 bit 执行局部交换”的组合规则，而不是记住完整地址。</p>
<h2 id="12-三个对照组">12. 三个对照组</h2>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th>做什么</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Butterfly</td>
          <td>每轮切换一个 XOR 地址 bit</td>
      </tr>
      <tr>
          <td>Adjacent-only</td>
          <td>每轮都重复相邻配对</td>
      </tr>
      <tr>
          <td>Root bottleneck</td>
          <td>递归压到一个有限 root，再预测所有位置</td>
      </tr>
  </tbody>
</table>
<p>三组使用相同随机 token、交叉熵、训练步数和测试查询。参数量与运行时间也会记录。</p>
<h2 id="13-预注册通过线">13. 预注册通过线</h2>
<p>确定性合同必须全部通过：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>inverse MSE &lt;= 1e-10
</span></span><span style="display:flex;"><span>energy relative error &lt;= 1e-6
</span></span><span style="display:flex;"><span>最终地址覆盖率 = 100%
</span></span><span style="display:flex;"><span>gradient norm ratio 位于 [0.999, 1.001]
</span></span></code></pre></div><p>三颗随机种子中至少两颗还要同时满足：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>width-32 未见查询准确率 &gt;= 95%
</span></span><span style="display:flex;"><span>最大距离查询准确率 &gt;= 90%
</span></span><span style="display:flex;"><span>width-64 未见宽度准确率 &gt;= 90%
</span></span><span style="display:flex;"><span>比 adjacent-only 高至少 25 个百分点
</span></span><span style="display:flex;"><span>比 root-bottleneck 高至少 25 个百分点
</span></span></code></pre></div><p>如果数学合同通过、训练实验失败，只能保留“Butterfly 是合法代数工具”，不能说它是有效学习机制。</p>
<h2 id="14-即使成功也还没有证明什么">14. 即使成功，也还没有证明什么</h2>
<p>通过本轮实验仍然不能说明：</p>
<ul>
<li>XOR 地址符合语言依存结构；</li>
<li>WMT 翻译会改善；</li>
<li>TreeHeap 已形成语义私有协议；</li>
<li>Butterfly 比成熟 Transformer 更快；</li>
<li>合成地址搬运等于推理。</li>
</ul>
<p>下一步只有在本轮结果成立后，才把 Butterfly 插入冻结的 WMT TreeHeap，用 matched ablation 比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>原 TreeHeap
</span></span><span style="display:flex;"><span>vs
</span></span><span style="display:flex;"><span>原 TreeHeap + Butterfly
</span></span></code></pre></div><h2 id="15-正式实验结果">15. 正式实验结果</h2>
<p>预注册完成后，实验在 <code>io</code> 的 CUDA 环境通过 taskd 任务 78 执行。三颗随机种子，每个方案训练 1,200 步，总用时 82.2 秒。</p>
<h3 id="151-数学合同">15.1 数学合同</h3>
<table>
  <thead>
      <tr>
          <th style="text-align: right">宽度</th>
          <th style="text-align: right">深度</th>
          <th style="text-align: right">逆运算 MSE</th>
          <th style="text-align: right">能量相对误差</th>
          <th style="text-align: right">梯度 norm 比</th>
          <th style="text-align: right">地址覆盖率</th>
          <th style="text-align: right">局部 pair 次数</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">3</td>
          <td style="text-align: right"><code>1.57e-14</code></td>
          <td style="text-align: right"><code>0</code></td>
          <td style="text-align: right"><code>0.99999994</code></td>
          <td style="text-align: right"><code>100%</code></td>
          <td style="text-align: right">12</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">4</td>
          <td style="text-align: right"><code>2.61e-14</code></td>
          <td style="text-align: right"><code>0</code></td>
          <td style="text-align: right"><code>0.99999988</code></td>
          <td style="text-align: right"><code>100%</code></td>
          <td style="text-align: right">32</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">5</td>
          <td style="text-align: right"><code>3.88e-14</code></td>
          <td style="text-align: right"><code>1.21e-7</code></td>
          <td style="text-align: right"><code>0.99999994</code></td>
          <td style="text-align: right"><code>100%</code></td>
          <td style="text-align: right">80</td>
      </tr>
      <tr>
          <td style="text-align: right">64</td>
          <td style="text-align: right">6</td>
          <td style="text-align: right"><code>5.37e-14</code></td>
          <td style="text-align: right"><code>2.35e-7</code></td>
          <td style="text-align: right"><code>0.99999988</code></td>
          <td style="text-align: right"><code>100%</code></td>
          <td style="text-align: right">192</td>
      </tr>
  </tbody>
</table>
<p>可逆、能量、梯度和覆盖率四组合同全部通过。宽度 64 时，Butterfly 只执行 192 次二节点运算；如果构造完整地址矩阵，则有 4,096 个地址对。</p>
<h3 id="152-学习结果">15.2 学习结果</h3>
<p>三颗 seed 的平均 token 准确率：</p>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th style="text-align: right">32 位未见组合</th>
          <th style="text-align: right">32 位最大距离</th>
          <th style="text-align: right">64 位未见宽度</th>
          <th style="text-align: right">参数量</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>XOR Butterfly</td>
          <td style="text-align: right"><code>100.000%</code></td>
          <td style="text-align: right"><code>99.998%</code></td>
          <td style="text-align: right"><code>99.998%</code></td>
          <td style="text-align: right">4,226</td>
      </tr>
      <tr>
          <td>Adjacent-only</td>
          <td style="text-align: right"><code>1.573%</code></td>
          <td style="text-align: right"><code>1.557%</code></td>
          <td style="text-align: right"><code>1.565%</code></td>
          <td style="text-align: right">4,226</td>
      </tr>
      <tr>
          <td>Root bottleneck</td>
          <td style="text-align: right"><code>5.039%</code></td>
          <td style="text-align: right"><code>5.058%</code></td>
          <td style="text-align: right"><code>2.078%</code></td>
          <td style="text-align: right">46,464</td>
      </tr>
  </tbody>
</table>
<p>词表大小为 64，随机猜测准确率约为：</p>
$$ \frac{1}{64}=1.5625\% $$<p>所以 adjacent-only 基本停留在随机水平。它虽然和 Butterfly 具有相同参数量和相同递归轮数，却始终重复相邻配对，无法把遥远地址的信息送到目标位置。</p>
<p>Root bottleneck 使用约 11 倍参数，在训练宽度上学到少量统计，但没有保存每个随机 token 的地址身份；外推到宽度 64 后下降到 <code>2.078%</code>。</p>
<p>Butterfly 在训练中只见过一位和两位地址变化，却组合出了未见的三位以上变化，并直接扩展到多一层的 64 位空间。</p>
<h3 id="153-它到底学到了什么">15.3 它到底学到了什么</h3>
<p>学习后的“查询 bit 为 1”与“查询 bit 为 0”的交换概率差，在三颗 seed 中分别为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.6282
</span></span><span style="display:flex;"><span>0.6273
</span></span><span style="display:flex;"><span>0.6274
</span></span></code></pre></div><p>这说明模型没有使用一张固定置换表，而是学到了局部规则：查询地址的当前 bit 决定这一轮是否交换；多轮局部规则组合成完整长距搬运。</p>
<p>但这里必须保持冷静。我们把查询拆成二进制 bit，是明确提供给模型的架构先验。实验没有证明模型能从自然语言中自己发现 XOR，也没有证明这种地址布局就是语言结构。</p>
<h3 id="154-当前结论">15.4 当前结论</h3>
<p>本轮 Claim 在预注册范围内得到支持：</p>
<blockquote>
<p>固定容量的 TreeHeap 地址可以通过 XOR Butterfly，在不构造 dense attention 的情况下，以对数轮次完成可逆、梯度稳定的长距通信；这个局部协议可以由交叉熵训练，并组合到未见查询和更大宽度。</p></blockquote>
<p>下一步不应继续增加合成 toy。更有价值的实验是把同一个 Butterfly 叶面通信层放进冻结或 matched-init 的 WMT TreeHeap，然后比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>原 TreeHeap
</span></span><span style="display:flex;"><span>vs
</span></span><span style="display:flex;"><span>原 TreeHeap + Butterfly
</span></span></code></pre></div><p>只有真实文本 NLL、source 因果干预和生成质量同时改善，才能说它解决了 TreeHeap 的语言长距问题。</p>
<p>这一次我们没有从结果倒推故事。Claim、阈值和反证条件先于正式运行写入 ARA，随后三颗 seed 全部通过。证据支持一件明确的小事，也留下一个同样明确的大问题。</p>
<blockquote>
<p><strong>原创与开放说明：</strong> 本文把 XOR/Butterfly 稀疏通信与 SameTime 的固定容量 TreeHeap 地址、FOLD/UNFOLD 和私有协议问题组合为一条可证伪研究路线。相关 Claim、代码和 evidence 以 GPLv3 在 SameTime/ARA 中公开。Butterfly、Walsh-Hadamard 变换及 XOR 网络本身属于已有数学与计算结构，本文不主张发明这些基础对象。</p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-077·论文特别篇一] TreeHeap 为什么不是把数组画成一棵树</title>
      <link>https://www.grepcode.cn/spr/077-treeheap-paper-origin-and-evolution.html</link>
      <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/077-treeheap-paper-origin-and-evolution.html</guid>
      <description>TreeHeap 论文导读第一篇：从路径语义、张量位权、概率容器和 root-only 等失败出发，解释最终算法为什么必须拥有可逆状态、稀疏通信和递归读取。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-为什么不是把数组画成一棵树">TreeHeap 为什么不是把数组画成一棵树</h1>
<blockquote>
<p><strong>系列定位：TreeHeap 论文特别篇（1/4）。</strong></p>
<p>当前最可靠的结论是：TreeHeap 已成为一种可训练、可逆、可干预的多分辨率状态结构。它还没有证明语义地址、真正压缩、计算优势或产品级生成。</p></blockquote>
<h2 id="特别篇导航">特别篇导航</h2>
<ol>
<li><strong>本篇：问题、失败与设计演化</strong></li>
<li><a href="/spr/078-treeheap-paper-math-and-dataflow.html">数学与数据流：一个句子怎样进入 TreeHeap</a></li>
<li><a href="/spr/079-treeheap-paper-evidence-and-dreams.html">实验证据：三种子 WMT 与双向 Dreams</a></li>
<li><a href="/spr/080-treeheap-paper-boundaries-and-reproduction.html">边界与复现：哪些成立，哪些仍然开放</a></li>
</ol>
<p>完整中文论文保存在开放仓库：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>https://github.com/houming818/sametime/blob/main/ara/papers/treeheap_emergent_protocol.zh.md
</span></span></code></pre></div><h2 id="1-treeheap-最初在问什么">1. TreeHeap 最初在问什么</h2>
<p>普通序列模型把临时状态排成一列。TreeHeap 想问一个不同的问题：</p>
<blockquote>
<p>如果模型的临时状态本身具有 root、parent、child、leaf、路径和子堆，任务梯度能不能利用这些结构形成 Encoder 与 Decoder 都能读写的协议？</p></blockquote>
<p>这里的关键词是“利用”，不是“摆放”。</p>
<p>把下面的数组：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[a, cat, is, eating, some, food]
</span></span></code></pre></div><p>换成下面的图：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>              root
</span></span><span style="display:flex;"><span>            /      \
</span></span><span style="display:flex;"><span>        subtree   subtree
</span></span><span style="display:flex;"><span>        /   \      /   \
</span></span><span style="display:flex;"><span>       ...  ...   ...  ...
</span></span></code></pre></div><p>并不能自动产生语言理解。若所有计算最后仍把节点重新摊平成数组，树只是一张示意图。</p>
<p>TreeHeap 必须证明至少三件事：</p>
<ol>
<li>树上的运算在数学上成立；</li>
<li>模型训练时真的使用了地址、深度和子结构；</li>
<li>使用这些结构后，任务指标发生可重复变化。</li>
</ol>
<h2 id="2-第一次误区路径不是语义">2. 第一次误区：路径不是语义</h2>
<p>早期 TreeHeap 的路径由 token ID 决定。两个 token 路径拥有较长公共前缀，看起来很像“它们属于同一个结构”。</p>
<p>但同一个 <code>bank</code> 可以表示银行，也可以表示河岸；同一个 <code>cat</code> 在不同句子中也可能处于不同关系。token ID 没变，路径就不会变。</p>
<p>所以路径只能回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个状态放在哪里？
</span></span></code></pre></div><p>不能单独回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个状态在当前句子里是什么意思？
</span></span></code></pre></div><p>最终设计仍然保留地址，但不再把地址直接叫作语义。</p>
<h2 id="3-第二次误区能区分排列不等于知道正确排列">3. 第二次误区：能区分排列，不等于知道正确排列</h2>
<p>Houming818 用 <code>321</code> 与 <code>123</code> 提出了位权问题。数字顺序之所以有意义，是因为每个数字处于不同的位权基。</p>
<p>类比到句子，可以让 token 向量 $s_i$ 与角色基 $e_r$ 做外积：</p>
$$ T=\sum_i s_i\otimes e_{r_i} $$<p>这样，<code>cat</code> 放进 SUBJECT 槽和 OBJECT 槽会得到不同张量。</p>
<p>实验确认：外积、拼接和非交换组合可以让不同排列得到不同表示。但是，如果我们在构造张量前已经知道 SUBJECT 和 OBJECT，结构答案其实已经被人写进去了。</p>
<p>因此必须区分：</p>
<table>
  <thead>
      <tr>
          <th>问题</th>
          <th>是否已经回答</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>两种排列能不能表示成不同状态</td>
          <td>可以</td>
      </tr>
      <tr>
          <td>正确排列会不会自然得到更低能量</td>
          <td>没有稳定证明</td>
      </tr>
      <tr>
          <td>任务梯度能不能自己学会选择结构</td>
          <td>仍需模型完成</td>
      </tr>
  </tbody>
</table>
<p>“可以区分”是表示能力，“知道选谁”才是学习能力。</p>
<h2 id="4-概率桶不是信息来源">4. 概率桶不是信息来源</h2>
<p>项目还尝试过保留多个父节点候选：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Parent A: 0.62
</span></span><span style="display:flex;"><span>Parent B: 0.25
</span></span><span style="display:flex;"><span>Parent C: 0.13
</span></span></code></pre></div><p>这可以避免信息不足时过早 <code>argmax</code>。但概率桶只能延迟丢失，不能创造节点状态中不存在的信息。</p>
<p>这个想法没有消失，而是改变了位置。最终 TreeHeap 不再维护人工 parent 候选，而是让 Decoder 在真实 root、internal node 和 leaf 之间递归分配读取概率。</p>
<h2 id="5-为什么世界模型-claim-被降级">5. 为什么世界模型 Claim 被降级</h2>
<p>我们曾希望 TreeHeap 向量形成如下关系参考系：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ball + foot -&gt; football
</span></span><span style="display:flex;"><span>ball + hand -&gt; basketball
</span></span></code></pre></div><p>但是旧 checkpoint 的 TreeHeap 向量平均 cosine 一度达到约 <code>0.985</code>。不同状态几乎都指向同一个公共方向。去中心化后虽然还能看到部分差异，却没有得到稳定、跨样本迁移的关系方向。</p>
<p>因此，论文明确撤回一个过强说法：</p>
<blockquote>
<p>向量之间有距离，不等于世界模型已经形成。</p></blockquote>
<p>一个世界参考系至少要在新词组、新句子和困难负例上保持关系迁移。这个证据目前没有完成。</p>
<h2 id="6-信息抽水机为什么必须可逆">6. 信息抽水机为什么必须可逆</h2>
<p>最简单的 parent 是两个 child 求和或平均：</p>
$$ parent=\frac{left+right}{2} $$<p>它能缩小节点数量，却会混淆左右次序和子堆身份。Decoder 无法知道被平均掉的差异来自哪里。</p>
<p>Houming818 用“抽水机”描述目标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf 保存局部细节
</span></span><span style="display:flex;"><span>parent 接收更大范围的信息
</span></span><span style="display:flex;"><span>越靠近 root，观察范围越大
</span></span><span style="display:flex;"><span>Decoder 需要时还能取回 detail
</span></span></code></pre></div><p>关键修正是 lifting：parent 保存更新后的 anchor，detail 保存预测残差。这样 FOLD 可以改变分辨率，UNFOLD 又可以恢复完整状态。</p>
<p>所以完整 TreeHeap 状态不是 root：</p>
$$ H=\left(root,\ all\ details,\ masks\right) $$<h2 id="7-为什么还需要-butterfly">7. 为什么还需要 Butterfly</h2>
<p>纯二叉 FOLD 只能让相邻 leaf 先相遇。长度为 8 时，位置 0 和位置 7 必须经过多层 parent 才能交换信息。</p>
<p>最终方案在 FOLD 前加入 XOR-Butterfly：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stage 0: (0,1) (2,3) (4,5) (6,7)
</span></span><span style="display:flex;"><span>stage 1: (0,2) (1,3) (4,6) (5,7)
</span></span><span style="display:flex;"><span>stage 2: (0,4) (1,5) (2,6) (3,7)
</span></span></code></pre></div><p>它不增加 leaf 数量，只改变每一轮谁和谁进行局部可逆通信。$N$ 个地址经过 $\log_2N$ 轮后获得全地址通信路径。</p>
<h2 id="8-最终算法不是一次灵感而是一组失败留下的约束">8. 最终算法不是一次灵感，而是一组失败留下的约束</h2>
<table>
  <thead>
      <tr>
          <th>失败</th>
          <th>暴露的问题</th>
          <th>最终修正</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token ID 路径直接解释语义</td>
          <td>地址与上下文含义混淆</td>
          <td>地址和语义学习分开</td>
      </tr>
      <tr>
          <td>随机角色基张量</td>
          <td>可区分不等于可选择</td>
          <td>选择交给任务梯度</td>
      </tr>
      <tr>
          <td>parent 直接求和</td>
          <td>左右和子堆身份丢失</td>
          <td>保存 lifting detail</td>
      </tr>
      <tr>
          <td>flat route 表</td>
          <td>每种长度单独记忆</td>
          <td>使用共享递归 kernel</td>
      </tr>
      <tr>
          <td>geometry feature 泄漏</td>
          <td>输入直接包含正确方向</td>
          <td>只读取真实节点状态</td>
      </tr>
      <tr>
          <td>root-only Decoder</td>
          <td>root 因果增强但 NLL 恶化</td>
          <td>完整 $H$ 参与 READ</td>
      </tr>
      <tr>
          <td>局部相邻 FOLD</td>
          <td>长距离通信过深</td>
          <td>加入固定容量 Butterfly</td>
      </tr>
  </tbody>
</table>
<p>这也是 TreeHeap 目前最朴素的研究态度：不是要求读者相信一个完整理论，而是公开每次错误如何缩小设计空间。</p>
<h2 id="9-本篇结论">9. 本篇结论</h2>
<p>TreeHeap 的目标不是把数组画成树。它要求：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>地址可计算
</span></span><span style="display:flex;"><span>局部算子可共享
</span></span><span style="display:flex;"><span>分辨率可变化
</span></span><span style="display:flex;"><span>状态可逆
</span></span><span style="display:flex;"><span>读取可递归
</span></span><span style="display:flex;"><span>结构作用可干预
</span></span><span style="display:flex;"><span>任务结果可复现
</span></span></code></pre></div><p>下一篇将不再讲研究历史，而是从一个输入句子开始，逐步说明 WRITE、Butterfly、FOLD、UNFOLD、READ 和交叉熵梯度到底如何连接。</p>
<blockquote>
<p>下一篇：<a href="/spr/078-treeheap-paper-math-and-dataflow.html">TreeHeap 的数学与数据流</a></p></blockquote>
<hr>
<p><strong>License:</strong> GPLv3。本文与代码允许阅读、复制、修改和分发；引用定量结论时请同时保留 Evidence 边界。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-078·论文特别篇二] 一个句子怎样进入 TreeHeap：数学、参数与数据流</title>
      <link>https://www.grepcode.cn/spr/078-treeheap-paper-math-and-dataflow.html</link>
      <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/078-treeheap-paper-math-and-dataflow.html</guid>
      <description>用本科线性代数与概率论解释 TreeHeap 的 theta、H、WRITE、可逆 Butterfly、lifting FOLD/UNFOLD、递归 READ 和交叉熵梯度。</description>
      <content:encoded><![CDATA[<h1 id="一个句子怎样进入-treeheap">一个句子怎样进入 TreeHeap</h1>
<blockquote>
<p><strong>系列定位：TreeHeap 论文特别篇（2/4）。</strong></p>
<p>本篇只解释当前代码真实执行的数学过程，不把内部节点命名为主语、谓语、摘要或世界模型。</p></blockquote>
<h2 id="系列导航">系列导航</h2>
<ol>
<li><a href="/spr/077-treeheap-paper-origin-and-evolution.html">问题、失败与设计演化</a></li>
<li><strong>本篇：数学、参数与数据流</strong></li>
<li><a href="/spr/079-treeheap-paper-evidence-and-dreams.html">三种子 WMT 与双向 Dreams</a></li>
<li><a href="/spr/080-treeheap-paper-boundaries-and-reproduction.html">边界、否证条件与复现</a></li>
</ol>
<h2 id="1-先区分参数与状态">1. 先区分参数与状态</h2>
<p>回归方程：</p>
$$ y=wx+b $$<p>里面的 $w,b$ 是长期学习参数，$x$ 是当前输入，$y$ 是当前输出。</p>
<p>TreeHeap 也必须做同样区分。</p>
<p>共享参数记作 $\theta$：</p>
$$ \theta=\{embedding,Butterfly,FOLD,READ,GRU,output\} $$<p>它们保存在 checkpoint 中，被全部训练样本共同使用。</p>
<p>一个具体句子 $x$ 经过这些参数后，形成临时状态：</p>
$$ H_\theta(x)=\left(root_x,details_x,masks_x\right) $$<p>$H_\theta(x)$ 随句子改变，不是另一份模型参数。</p>
<p>可以这样理解：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>theta：长期形成的读写规则
</span></span><span style="display:flex;"><span>H(x)：这套规则对当前句子的实例化
</span></span></code></pre></div><h2 id="2-write把离散-token-写入-leaf">2. WRITE：把离散 token 写入 leaf</h2>
<p>输入由三部分组成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[direction token] + [SentencePiece pieces] + [EOS]
</span></span></code></pre></div><p>例如中译英方向的第一个 leaf 会写入 <code>zh2en</code> 特殊 token，后续 leaf 才是原句 pieces。</p>
<p>对有效位置：</p>
$$ x_i=E_{src}(w_i) $$<p>当前实现没有额外的位置 embedding。位置差异来自：</p>
<ol>
<li>leaf 下标；</li>
<li>Butterfly 中由地址决定的配对；</li>
<li>二叉 FOLD 中不同的左右路径。</li>
</ol>
<p>不足容量的位置由 mask 关闭。WRITE 只完成离散到连续向量的映射，还没有自动产生高层语义。</p>
<h2 id="3-butterfly固定容量内的长距离通信">3. Butterfly：固定容量内的长距离通信</h2>
<p>设 TreeHeap 有 $N=2^D$ 个 leaf。第 $s$ 轮中，地址 $i$ 与地址</p>
$$ j=i\oplus2^s $$<p>通信。</p>
<p>一对状态 $(a,b)$ 的可学习 kernel 为：</p>
$$ b'=b+\alpha_s\tanh(F_\theta(a)) $$$$ a'=a+\alpha_s\tanh(G_\theta(b')) $$<p>这里 $F_\theta,G_\theta$ 是共享的小型非线性网络。所有地址使用同一套 kernel，不为每一对节点单独学习一张表。</p>
<p>逆运算按相反顺序计算：</p>
$$ a=a'-\alpha_s\tanh(G_\theta(b')) $$$$ b=b'-\alpha_s\tanh(F_\theta(a)) $$<p>所以 Butterfly 可以改变坐标，又不要求丢失输入。</p>
<p>每轮有 $N/2$ 对，共有 $\log_2N$ 轮：</p>
$$ \text{pair operations}=\frac{N}{2}\log_2N $$<p>这是 $O(N\log N)$ 的稀疏通信，不分配 $N\times N$ 的稠密注意力矩阵。</p>
<h2 id="4-fold把两个-child-组织成-parent-与-detail">4. FOLD：把两个 child 组织成 parent 与 detail</h2>
<p>Butterfly 之后，TreeHeap 开始逐层 FOLD。对于左右状态 $(l,r)$：</p>
$$ d=r-P_\theta(l) $$$$ p=l+U_\theta(d) $$<p>其中：</p>
<ul>
<li>$P_\theta$ 预测右侧状态；</li>
<li>$d$ 保存没有被预测到的残差；</li>
<li>$U_\theta$ 决定残差怎样更新到 parent；</li>
<li>$p$ 进入更高一层。</li>
</ul>
<p>当前 Update 为：</p>
$$ U_\theta(d)=0.5d+0.5\tanh(\widetilde U_\theta(d)) $$<p>可学习部分从零初始化。训练开始时，它等价于稳定的 $0.5d$ 更新；训练随后可以改变信息如何向 parent 上导。</p>
<h2 id="5-unfold为什么它能恢复-child">5. UNFOLD：为什么它能恢复 child</h2>
<p>已知 parent $p$ 与 detail $d$：</p>
$$ l=p-U_\theta(d) $$<p>再计算：</p>
$$ r=d+P_\theta(l) $$<p>就能恢复左右状态。</p>
<p>递归执行后，$N$ 个 leaf 被组织为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 个 root
</span></span><span style="display:flex;"><span>+ 第 0 层 details
</span></span><span style="display:flex;"><span>+ 第 1 层 details
</span></span><span style="display:flex;"><span>+ ...
</span></span><span style="display:flex;"><span>+ masks
</span></span></code></pre></div><p>detail 总数仍为 $N-1$。因此当前多分辨率状态不是文件压缩：信息只是被重新组织，并没有自动减少存储量。</p>
<h2 id="6-readdecoder-如何决定读取哪个深度">6. READ：Decoder 如何决定读取哪个深度</h2>
<p>Decoder 每生成一个 token，都从 root 开始分配概率质量。</p>
<p>对节点 $n_i^{(k)}$，计算停止概率：</p>
$$ p_{stop}(i,k,t)= \sigma\left(S_\theta\left[q(h_t),n_i^{(k)}+e_k\right]\right) $$<p>如果不停止，剩余质量进入左右 child：</p>
$$ p(c\mid i,t)= \operatorname{softmax}_c \left(\frac{B_\theta(h_t)^\top n_c}{\sqrt m}\right) $$<p>到达节点 $i$ 的质量为 $m_i$ 时：</p>
$$ m_i^{stop}+m_{left}+m_{right}=m_i $$<p>所以概率没有在递归过程中凭空增加。所有停止节点的加权和形成当前上下文 $c_t$。</p>
<h2 id="7-decoder-如何生成下一个-token">7. Decoder 如何生成下一个 token</h2>
<p>Decoder 把上一个目标 token、当前 TreeHeap context 和历史隐状态放进 GRU：</p>
$$ h_{t+1}=GRU([E_{tgt}(y_t),c_t],h_t) $$<p>再输出词表概率：</p>
$$ p(y_{t+1})=softmax(W_o[h_{t+1},c_t]) $$<p>训练时使用 teacher forcing：第 $t$ 步输入真实的 $y_t$。自由生成时，输入模型自己上一步选择的 token。</p>
<h2 id="8-梯度到底从哪里来">8. 梯度到底从哪里来</h2>
<p>唯一语言目标是目标 token 的交叉熵：</p>
$$ \mathcal L=-\sum_t\log p_\theta(y_t\mid y_{\lt t},H_\theta(x)) $$<p>如果正确 token 的概率太低，loss 就升高。反向传播依次经过：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>词表输出
</span></span><span style="display:flex;"><span>  -&gt; GRU
</span></span><span style="display:flex;"><span>  -&gt; recursive READ
</span></span><span style="display:flex;"><span>  -&gt; UNFOLD levels
</span></span><span style="display:flex;"><span>  -&gt; root + details
</span></span><span style="display:flex;"><span>  -&gt; lifting FOLD
</span></span><span style="display:flex;"><span>  -&gt; Butterfly
</span></span><span style="display:flex;"><span>  -&gt; source embedding
</span></span></code></pre></div><p>这条链就是私有协议形成的物理通道。模型没有内部节点标签，也没有人工告诉它哪个 node 是“食物”或者“主语”。</p>
<h2 id="9-这套结构哪里是确定的哪里是学习的">9. 这套结构哪里是确定的，哪里是学习的</h2>
<table>
  <thead>
      <tr>
          <th>类型</th>
          <th>内容</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>确定性结构</td>
          <td>heap 地址、XOR 配对轮次、FOLD/UNFOLD 计算顺序、概率质量守恒</td>
      </tr>
      <tr>
          <td>可学习参数</td>
          <td>embedding、Butterfly kernel、Predictor、Update、stop、branch、GRU、输出层</td>
      </tr>
      <tr>
          <td>样本临时状态</td>
          <td>leaf、root、details、READ context</td>
      </tr>
      <tr>
          <td>最终监督</td>
          <td>目标 token 交叉熵</td>
      </tr>
  </tbody>
</table>
<p>这一区分很重要。Butterfly 地址图是人工给定的归纳偏置；具体传递什么信息由梯度学习。FOLD 的逆式由数学定义保证；不同深度最后承担什么任务，必须由实验观察。</p>
<h2 id="10-当前计算代价">10. 当前计算代价</h2>
<p>Butterfly 是 $O(N\log N)$，FOLD/UNFOLD 是 $O(N)$。当前 recursive READ 每个输出时间步会访问总计小于 $2N$ 个节点，所以生成约为：</p>
$$ O(TN) $$<p>其中 $T$ 是输出长度。</p>
<p>因此，“稀疏”目前只是结构性质，不等于工程上已经更快。是否节省 GPU 小时，必须用吞吐、显存和训练成本实际测量。</p>
<h2 id="11-本篇结论">11. 本篇结论</h2>
<p>一个句子进入 TreeHeap 后，没有被压成一个神奇 root。它经历的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>WRITE
</span></span><span style="display:flex;"><span>-&gt; Butterfly communication
</span></span><span style="display:flex;"><span>-&gt; reversible FOLD
</span></span><span style="display:flex;"><span>-&gt; H(root, details, masks)
</span></span><span style="display:flex;"><span>-&gt; recursive READ
</span></span><span style="display:flex;"><span>-&gt; token distribution
</span></span><span style="display:flex;"><span>-&gt; cross-entropy gradient
</span></span></code></pre></div><p>下一篇将检查这条链到底产生了什么证据，以及哪些漂亮数字其实不能被解释得太强。</p>
<blockquote>
<p>下一篇：<a href="/spr/079-treeheap-paper-evidence-and-dreams.html">三种子 WMT 与双向 Dreams</a></p></blockquote>
<hr>
<p><strong>License:</strong> GPLv3。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-079·论文特别篇三] TreeHeap 得到了什么证据：三种子 WMT 与双向 Dreams</title>
      <link>https://www.grepcode.cn/spr/079-treeheap-paper-evidence-and-dreams.html</link>
      <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/079-treeheap-paper-evidence-and-dreams.html</guid>
      <description>公开 TreeHeap 当前最强正向结果、负向边界和全量训练轨迹：闭包、多分辨率读取、Butterfly 三种子比较，以及不单调的双向 Dreams。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-得到了什么证据">TreeHeap 得到了什么证据</h1>
<blockquote>
<p><strong>系列定位：TreeHeap 论文特别篇（3/4）。</strong></p>
<p>本篇把证据分为代数正确性、机制参与性、架构比较和规模生长观察。不同等级不能互相冒充。</p></blockquote>
<h2 id="系列导航">系列导航</h2>
<ol>
<li><a href="/spr/077-treeheap-paper-origin-and-evolution.html">问题、失败与设计演化</a></li>
<li><a href="/spr/078-treeheap-paper-math-and-dataflow.html">数学、参数与数据流</a></li>
<li><strong>本篇：三种子 WMT 与双向 Dreams</strong></li>
<li><a href="/spr/080-treeheap-paper-boundaries-and-reproduction.html">边界、否证条件与复现</a></li>
</ol>
<h2 id="1-先给证据分级">1. 先给证据分级</h2>
<table>
  <thead>
      <tr>
          <th>等级</th>
          <th>回答的问题</th>
          <th>不能推出什么</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>E1 代数正确性</td>
          <td>逆运算是否成立</td>
          <td>不能推出语言能力</td>
      </tr>
      <tr>
          <td>E2 机制参与性</td>
          <td>root、detail、通信是否影响任务</td>
          <td>不能推出架构更优</td>
      </tr>
      <tr>
          <td>E3 架构比较</td>
          <td>匹配合同中哪种配置更好</td>
          <td>不能推出普遍优势</td>
      </tr>
      <tr>
          <td>E4 规模观察</td>
          <td>行为是否随数据变化</td>
          <td>样例不能替代标准指标</td>
      </tr>
  </tbody>
</table>
<p>这张表是读懂所有结果的钥匙。</p>
<h2 id="2-e1fold-和-butterfly-是否真的可逆">2. E1：FOLD 和 Butterfly 是否真的可逆</h2>
<p>三颗正式实验种子中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Butterfly forward/inverse MSE: 约 6.7e-16 .. 7.2e-16
</span></span><span style="display:flex;"><span>FOLD/UNFOLD closure MSE:      约 6.7e-15 .. 8.2e-15
</span></span></code></pre></div><p>误差接近 FP32 浮点精度。这说明训练没有破坏定义好的逆运算。</p>
<p>它只证明数学闭包，不证明翻译无损，更不证明 root 保存了整句话。</p>
<h2 id="3-e2decoder-是否使用多个分辨率">3. E2：Decoder 是否使用多个分辨率</h2>
<p>在 27K/2K/2K WMT、10 epochs 的 lifting-pump 实验中：</p>
<table>
  <thead>
      <tr>
          <th>读出方式</th>
          <th style="text-align: right">测试 NLL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>recursive READ</td>
          <td style="text-align: right">5.0903</td>
      </tr>
      <tr>
          <td>root-only</td>
          <td style="text-align: right">5.4337</td>
      </tr>
      <tr>
          <td>full UNFOLD read</td>
          <td style="text-align: right">5.1342</td>
      </tr>
      <tr>
          <td>flat sequence</td>
          <td style="text-align: right">4.8103</td>
      </tr>
  </tbody>
</table>
<p>这里 NLL 越低越好。</p>
<p>recursive READ 优于 root-only，并接近直接读取完整 UNFOLD 状态。source shuffle 和 root shuffle 分别造成约 <code>+1.4450</code> 与 <code>+1.7204</code> NLL 损伤；所有 detail 深度也表现出可测作用。</p>
<p>因此可以说：</p>
<blockquote>
<p>Decoder 确实使用 root 和多个 detail 层级。</p></blockquote>
<p>但 flat sequence 仍领先 <code>0.2800</code> NLL，所以不能写成“TreeHeap 翻译更好”。</p>
<h2 id="4-可学习-update-带来了什么">4. 可学习 Update 带来了什么</h2>
<p>在 200K/5K/5K WMT 实验中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>固定 Update NLL:   4.6743
</span></span><span style="display:flex;"><span>可学习 Update NLL: 4.6335
</span></span><span style="display:flex;"><span>提升:              0.0408
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>token BLEU-4:      9.609 -&gt; 9.909
</span></span><span style="display:flex;"><span>closure MSE:       2.35e-14
</span></span></code></pre></div><p>预注册要求提升至少 <code>0.05</code>，所以强 gate 没有通过。但结果仍支持一个较窄结论：梯度可以改变 detail 向 parent 的上导方式，同时保留 UNFOLD 闭包。</p>
<h2 id="5-e3butterfly-三种子匹配实验">5. E3：Butterfly 三种子匹配实验</h2>
<p>正式实验保持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train / valid / test = 200K / 5K / 5K
</span></span><span style="display:flex;"><span>length = 8..32 pieces
</span></span><span style="display:flex;"><span>dim / hidden = 256 / 256
</span></span><span style="display:flex;"><span>epochs = 5
</span></span><span style="display:flex;"><span>parameters = 34,445,832
</span></span><span style="display:flex;"><span>seeds = 8104, 8105, 8106
</span></span></code></pre></div><p>只改变通信调度：</p>
<ul>
<li>Identity：不执行节点通信；</li>
<li>Adjacent：每轮重复相邻配对；</li>
<li>Butterfly：每轮打开不同地址 bit。</li>
</ul>
<h3 id="测试-nll">测试 NLL</h3>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Seed</th>
          <th style="text-align: right">Identity</th>
          <th style="text-align: right">Adjacent</th>
          <th style="text-align: right">Butterfly</th>
          <th style="text-align: right">Butterfly 相对 Identity</th>
          <th style="text-align: right">相对 Adjacent</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">8104</td>
          <td style="text-align: right">4.62285</td>
          <td style="text-align: right">4.62273</td>
          <td style="text-align: right"><strong>4.54546</strong></td>
          <td style="text-align: right">0.07738</td>
          <td style="text-align: right">0.07727</td>
      </tr>
      <tr>
          <td style="text-align: right">8105</td>
          <td style="text-align: right">4.66175</td>
          <td style="text-align: right">4.67974</td>
          <td style="text-align: right"><strong>4.58915</strong></td>
          <td style="text-align: right">0.07260</td>
          <td style="text-align: right">0.09059</td>
      </tr>
      <tr>
          <td style="text-align: right">8106</td>
          <td style="text-align: right">4.67127</td>
          <td style="text-align: right">4.65998</td>
          <td style="text-align: right"><strong>4.56066</strong></td>
          <td style="text-align: right">0.11061</td>
          <td style="text-align: right">0.09932</td>
      </tr>
      <tr>
          <td style="text-align: right">Mean</td>
          <td style="text-align: right">4.65196</td>
          <td style="text-align: right">4.65415</td>
          <td style="text-align: right"><strong>4.56509</strong></td>
          <td style="text-align: right"><strong>0.08687</strong></td>
          <td style="text-align: right"><strong>0.08906</strong></td>
      </tr>
  </tbody>
</table>
<h3 id="项目内-token-bleu-4">项目内 token BLEU-4</h3>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Identity</th>
          <th style="text-align: right">Adjacent</th>
          <th style="text-align: right">Butterfly</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">9.9501</td>
          <td style="text-align: right">9.9485</td>
          <td style="text-align: right"><strong>10.5462</strong></td>
      </tr>
  </tbody>
</table>
<p>三颗种子都通过预注册门槛。因此，当前最强结论是：</p>
<blockquote>
<p>在这个 WMT 数据、模型规模和训练合同中，从头训练的 Butterfly 配置稳定优于 Identity 和重复 Adjacent。</p></blockquote>
<p>这不是“TreeHeap 优于所有序列模型”，也不是“XOR 地址就是语义”。</p>
<h2 id="6-长源结果">6. 长源结果</h2>
<p>在正式实验允许的 25&ndash;32-piece 长源子集中，Butterfly 相对 Identity 的 NLL 收益为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.07451 / 0.07825 / 0.10424
</span></span><span style="display:flex;"><span>mean = 0.08567
</span></span></code></pre></div><p>收益没有在该实验的长端消失。但是训练最大长度只有 32，不能把它称为 128 或 256 token 长程证明。</p>
<h2 id="7-为什么运行时-identity-不是严格拓扑消融">7. 为什么运行时 Identity 不是严格拓扑消融</h2>
<p>训练完成后，把 Butterfly 改成 Identity，平均 NLL 恶化约 <code>1.16873</code>。这个数字很大，却不能直接证明 XOR 拓扑最优。</p>
<p>原因是 Identity 完全绕过了学会的通信变换 $B_\theta$。后续 FOLD 和 Decoder 接收到训练中没见过的坐标。</p>
<p>它能证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型依赖已经学会的通信协议
</span></span></code></pre></div><p>不能单独证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>损伤全部来自 changing-bit 配对图
</span></span></code></pre></div><p>更严格的实验必须保持 kernel 活跃、调用次数相同，只替换配对图，并使用完全相同的验证句。</p>
<h2 id="8-e4全量双向训练的-nll-轨迹">8. E4：全量双向训练的 NLL 轨迹</h2>
<p>全量实验使用 1417 万中英平行句对，最长 253 pieces，单张 RTX 3090 运行 96 小时。</p>
<p>截至 2026-08-02 本文核对时：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">训练样本</th>
          <th style="text-align: right">Mean validation NLL</th>
          <th>状态</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td style="text-align: right">10.5612</td>
          <td>初始快照</td>
      </tr>
      <tr>
          <td style="text-align: right">5.99M</td>
          <td style="text-align: right">3.5630</td>
          <td>已归档</td>
      </tr>
      <tr>
          <td style="text-align: right">11.98M</td>
          <td style="text-align: right">3.4839</td>
          <td>已归档</td>
      </tr>
      <tr>
          <td style="text-align: right">17.93M</td>
          <td style="text-align: right">3.4561</td>
          <td>已归档</td>
      </tr>
      <tr>
          <td style="text-align: right">21.93M</td>
          <td style="text-align: right">3.4407</td>
          <td>已归档</td>
      </tr>
      <tr>
          <td style="text-align: right">31.88M</td>
          <td style="text-align: right"><strong>3.4230</strong></td>
          <td>运行中最好 wake</td>
      </tr>
      <tr>
          <td style="text-align: right">36.87M</td>
          <td style="text-align: right">3.4302</td>
          <td>最近 wake</td>
      </tr>
  </tbody>
</table>
<p>曲线前期快速下降，后期在 <code>3.42..3.47</code> 震荡。最新 checkpoint 并不是最好 checkpoint。</p>
<p>这可能来自容量平台、数据 block 分布变化或双向任务干扰，但目前没有控制实验区分。诚实结论只有：训练进入平台震荡，而不是继续单调改善。</p>
<h2 id="9-dreams同一句话怎样变化">9. Dreams：同一句话怎样变化</h2>
<p>固定输入：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>The new company is expected to begin operations in the spring of 2019.
</span></span></code></pre></div><p>初始输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>意愿 Fe Fe Fe Fe Fe Fe Fe ...
</span></span></code></pre></div><p>约 599 万样本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>预计于2019年年底,开始新年。
</span></span></code></pre></div><p>约 1198 万样本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>新年公司预计于2019年,预计在2019年春天开始运营。
</span></span></code></pre></div><p>约 1793 万样本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>预计于2019年春天开始运营。
</span></span></code></pre></div><p>约 2193 万样本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>新的公司预计将于2019年春春新公司运营。
</span></span></code></pre></div><p>它从单 token 循环，发展为保留“公司、2019、春季、开始运营”的源相关输出。但改善不是单调的：1793 万时比 2193 万时更简洁。</p>
<p>对于“窗户为什么湿”的因果句，模型也学到了雨、风、窗户等相关词，却仍产生明显重复。这说明总体 NLL 下降不会保证每个自由生成样例同步变好。</p>
<h2 id="10-dreams-的正确用途">10. Dreams 的正确用途</h2>
<p>Dreams 不进入训练，也不参与 loss。它们的用途是暴露：</p>
<ul>
<li>单 token 坍缩；</li>
<li>短语循环；</li>
<li>实体错误；</li>
<li>方向混淆；</li>
<li>源条件是否逐渐出现。</li>
</ul>
<p>六条人工句子不能代表完整测试集。最终质量仍需标准 BLEU、chrF、COMET、重复率、长度分桶和人工盲评。</p>
<h2 id="11-本篇结论">11. 本篇结论</h2>
<p>目前可以确认：</p>
<ol>
<li>数学闭包成立；</li>
<li>多个 TreeHeap 分辨率参与任务；</li>
<li>Butterfly 配置在当前合同中获得三种子稳定收益；</li>
<li>双向自由输出从源无关重复发展出部分源相关关系。</li>
</ol>
<p>目前不能确认：</p>
<ol>
<li>changing-bit 拓扑是全部收益来源；</li>
<li>root 是摘要；</li>
<li>地址具有语义；</li>
<li>当前模型达到产品质量；</li>
<li>当前实现节省算力。</li>
</ol>
<blockquote>
<p>下一篇：<a href="/spr/080-treeheap-paper-boundaries-and-reproduction.html">Claim 边界、否证条件与复现入口</a></p></blockquote>
<hr>
<p><strong>License:</strong> GPLv3。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-080·论文特别篇四] 如何审核 TreeHeap：Claim 边界、否证条件与复现入口</title>
      <link>https://www.grepcode.cn/spr/080-treeheap-paper-boundaries-and-reproduction.html</link>
      <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/080-treeheap-paper-boundaries-and-reproduction.html</guid>
      <description>TreeHeap 论文特别篇终章：公开当前 Claim 状态、可能推翻结论的实验、计算代价、复现路径，以及读者应该如何审核这项独立研究。</description>
      <content:encoded><![CDATA[<h1 id="如何审核-treeheap">如何审核 TreeHeap</h1>
<blockquote>
<p><strong>系列定位：TreeHeap 论文特别篇（4/4）。</strong></p>
<p>一项新架构不能只展示最好样例。它必须告诉读者：什么结果会让研究者承认自己错了。</p></blockquote>
<h2 id="系列导航">系列导航</h2>
<ol>
<li><a href="/spr/077-treeheap-paper-origin-and-evolution.html">问题、失败与设计演化</a></li>
<li><a href="/spr/078-treeheap-paper-math-and-dataflow.html">数学、参数与数据流</a></li>
<li><a href="/spr/079-treeheap-paper-evidence-and-dreams.html">三种子 WMT 与双向 Dreams</a></li>
<li><strong>本篇：Claim 边界、否证条件与复现</strong></li>
</ol>
<p>完整中文论文：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>https://github.com/houming818/sametime/blob/main/ara/papers/treeheap_emergent_protocol.zh.md
</span></span></code></pre></div><p>开放代码与 ARA：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>https://github.com/houming818/sametime
</span></span></code></pre></div><h2 id="1-当前-claim-体检表">1. 当前 Claim 体检表</h2>
<table>
  <thead>
      <tr>
          <th>Claim</th>
          <th>当前状态</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Butterfly 正反变换保持数值闭合</td>
          <td>支持</td>
      </tr>
      <tr>
          <td>FOLD/UNFOLD 保持数值闭合</td>
          <td>支持</td>
      </tr>
      <tr>
          <td>root 与多个 detail 深度参与当前 WMT 任务</td>
          <td>支持机制</td>
      </tr>
      <tr>
          <td>可学习 Update 在保持闭合时改善任务</td>
          <td>部分支持，未过 0.05 NLL 强 gate</td>
      </tr>
      <tr>
          <td>Butterfly 配置在当前 WMT 合同中优于 Identity/Adjacent</td>
          <td>三种子支持</td>
      </tr>
      <tr>
          <td>已训练模型依赖通信变换</td>
          <td>运行时依赖检查支持</td>
      </tr>
      <tr>
          <td>收益严格来自 changing-bit 拓扑</td>
          <td>开放</td>
      </tr>
      <tr>
          <td>共享 TreeHeap 开始形成中英双向协议</td>
          <td>规模观察支持，最终质量开放</td>
      </tr>
      <tr>
          <td>root 是人类可读摘要</td>
          <td>未证明</td>
      </tr>
      <tr>
          <td>XOR 地址天然具有语义</td>
          <td>未证明</td>
      </tr>
      <tr>
          <td>当前状态已经实现存储压缩</td>
          <td>否</td>
      </tr>
      <tr>
          <td>当前实现已经节省 GPU 计算</td>
          <td>未证明</td>
      </tr>
      <tr>
          <td>当前模型达到产品级翻译质量</td>
          <td>否</td>
      </tr>
  </tbody>
</table>
<p>这张表比一句“实验成功”更重要，因为它限定了每个结果的有效范围。</p>
<h2 id="2-什么结果会推翻当前判断">2. 什么结果会推翻当前判断</h2>
<h3 id="21-推翻可逆性">2.1 推翻可逆性</h3>
<p>若在有效输入上，Butterfly inverse 或 FOLD/UNFOLD closure 出现系统性大误差，而且不能由浮点精度解释，那么代数实现不成立。</p>
<h3 id="22-推翻多分辨率参与">2.2 推翻多分辨率参与</h3>
<p>若 root、detail、pairing 和 depth 干预在多种子上都不造成稳定损失，或者 Decoder 被发现只从 leaf 直通读取，那么“TreeHeap 多分辨率参与任务”必须撤回。</p>
<h3 id="23-推翻-butterfly-的当前收益">2.3 推翻 Butterfly 的当前收益</h3>
<p>若同数据、同种子、同参数和同训练合同无法重复当前三种子结果，Butterfly 的 WMT Claim 必须降级。</p>
<h3 id="24-推翻-changing-bit-的特殊性">2.4 推翻 changing-bit 的特殊性</h3>
<p>这是下一轮最关键的反证：</p>
<blockquote>
<p>如果若干具有相同边数、阶段数和全局覆盖能力的固定随机 topology，与 XOR-Butterfly 表现相同或更好，就不能把收益归因于 changing-bit 调度本身。</p></blockquote>
<p>Butterfly 仍可能是一种可用调度，但不再具有当前设想的特殊归纳偏置。</p>
<h3 id="25-推翻双向协议生长">2.5 推翻双向协议生长</h3>
<p>若全量训练长期出现以下情况之一，应停止扩大结论：</p>
<ul>
<li>输出持续与源无关；</li>
<li>中英方向混淆；</li>
<li>验证损失长期不改善；</li>
<li>checkpoint 重载后固定输出变化；</li>
<li>重复坍缩没有随训练缓解。</li>
</ul>
<h2 id="3-为什么当前还不能叫压缩模型">3. 为什么当前还不能叫“压缩模型”</h2>
<p>Lifting 把 $N$ 个 leaf 组织成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1 root + (N-1) details
</span></span></code></pre></div><p>总状态数量没有减少。</p>
<p>真正的压缩必须进一步证明：</p>
<ol>
<li>可以删除、量化或延迟加载部分 detail；</li>
<li>质量损失在给定预算内；</li>
<li>存储、显存或计算成本实际下降。</li>
</ol>
<p>所以论文使用“多分辨率状态”，不使用“已经压缩”。</p>
<h2 id="4-为什么当前还不能叫高效模型">4. 为什么当前还不能叫“高效模型”</h2>
<p>理论操作量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Butterfly: O(N log N)
</span></span><span style="display:flex;"><span>FOLD/UNFOLD: O(N)
</span></span><span style="display:flex;"><span>current READ: O(TN)
</span></span></code></pre></div><p>当前代码没有为稀疏 TreeHeap kernel 编写专用 CUDA 实现。Python/PyTorch 张量重排可能让理论稀疏结构在实际 GPU 上更慢。</p>
<p>计算优势必须记录：</p>
<ul>
<li>训练 token；</li>
<li>GPU 小时；</li>
<li>tokens/s；</li>
<li>峰值显存；</li>
<li>估算反向 FLOPs；</li>
<li>匹配质量所需的总成本。</li>
</ul>
<p>复杂度公式不能代替工程测量。</p>
<h2 id="5-如何复现正式三种子实验">5. 如何复现正式三种子实验</h2>
<p>核心代码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/src/s2_treeheap_butterfly_wmt.py
</span></span></code></pre></div><p>Logic 与 Evidence：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/logic/treeheap_butterfly_wmt_ablation.md
</span></span><span style="display:flex;"><span>ara/s3-generation/evidence/s2_treeheap_butterfly_wmt_formal/
</span></span></code></pre></div><p>正式配置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>train/valid/test = 200000/5000/5000
</span></span><span style="display:flex;"><span>length = 8..32
</span></span><span style="display:flex;"><span>heap_width = 64
</span></span><span style="display:flex;"><span>dim = 256
</span></span><span style="display:flex;"><span>hidden = 256
</span></span><span style="display:flex;"><span>batch = 64
</span></span><span style="display:flex;"><span>epochs = 5
</span></span><span style="display:flex;"><span>lr = 0.002
</span></span><span style="display:flex;"><span>seeds = 8104,8105,8106
</span></span></code></pre></div><p>Evidence 中保存：</p>
<ul>
<li><code>summary.json</code>；</li>
<li>每个 seed 的 trace；</li>
<li>生成样例；</li>
<li>干预结果；</li>
<li>closure 与 inverse 误差；</li>
<li>checkpoint SHA-256。</li>
</ul>
<h2 id="6-如何复查全量双向实验">6. 如何复查全量双向实验</h2>
<p>训练代码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/src/s3_treeheap_butterfly_bilingual_full.py
</span></span></code></pre></div><p>实验说明和阶段证据：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/logic/treeheap_butterfly_bilingual_full_train.md
</span></span><span style="display:flex;"><span>ara/s3-generation/evidence/s3_treeheap_butterfly_bilingual_full/
</span></span></code></pre></div><p><code>dreams/step-*.txt</code> 是不可变的固定探针快照。审核时不能只选最好的一次，应按时间顺序阅读全部文件。</p>
<h2 id="7-为什么我们使用-ara">7. 为什么我们使用 ARA</h2>
<p>研究流程为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>直觉
</span></span><span style="display:flex;"><span>-&gt; Claim
</span></span><span style="display:flex;"><span>-&gt; Predict
</span></span><span style="display:flex;"><span>-&gt; Experiment
</span></span><span style="display:flex;"><span>-&gt; Evidence
</span></span><span style="display:flex;"><span>-&gt; Audit
</span></span><span style="display:flex;"><span>-&gt; Revision
</span></span></code></pre></div><p>这套流程已经实际撤回过多项错误：</p>
<ul>
<li>token 路径被误写成语义；</li>
<li>flat 长度路由被误写成递归 TreeHeap；</li>
<li>geometry feature 把正确方向泄漏给模型；</li>
<li>CLI 把中文续写错误标成翻译；</li>
<li>runtime Identity 被过强解释为拓扑因果证据。</li>
</ul>
<p>ARA 不能保证研究者不犯错。它只保证错误可以被定位，并且不会悄悄变成下一轮前提。</p>
<h2 id="8-下一轮三个决定性实验">8. 下一轮三个决定性实验</h2>
<h3 id="81-冻结最好-checkpoint-与最后-checkpoint">8.1 冻结最好 checkpoint 与最后 checkpoint</h3>
<p>全量训练已经进入震荡平台，最后一次不一定最好。最终报告必须同时保存：</p>
<ul>
<li>validation NLL 最好的 checkpoint；</li>
<li>时间预算结束时的 checkpoint；</li>
<li>两者在固定测试集上的完整比较。</li>
</ul>
<h3 id="82-严格-topology-only-干预">8.2 严格 topology-only 干预</h3>
<p>保持 checkpoint、kernel、调用次数和验证句相同，只替换地址配对图。对每个句子计算：</p>
$$ \Delta L_i=L_i(wrong\ topology)-L_i(native) $$<p>不能再拿不同数量的验证样本做差。</p>
<h3 id="83-同覆盖能力-topology-的匹配重训">8.3 同覆盖能力 topology 的匹配重训</h3>
<p>至少比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>XOR Butterfly
</span></span><span style="display:flex;"><span>repeated adjacent
</span></span><span style="display:flex;"><span>fixed random perfect matching A
</span></span><span style="display:flex;"><span>fixed random perfect matching B
</span></span><span style="display:flex;"><span>fixed random perfect matching C
</span></span></code></pre></div><p>所有配置保持边数、阶段数、kernel 参数量和训练数据一致。</p>
<h2 id="9-给非专业读者的最终判断">9. 给非专业读者的最终判断</h2>
<p>TreeHeap 现在不是一个成熟产品，也不是已经完成的意识理论。</p>
<p>它已经是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>有明确数据结构
</span></span><span style="display:flex;"><span>有数学逆运算
</span></span><span style="display:flex;"><span>有梯度路径
</span></span><span style="display:flex;"><span>有真实语言训练
</span></span><span style="display:flex;"><span>有多种子结果
</span></span><span style="display:flex;"><span>有失败档案
</span></span><span style="display:flex;"><span>有公开反证条件
</span></span></code></pre></div><p>它还缺少：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>严格拓扑因果隔离
</span></span><span style="display:flex;"><span>完整标准质量评价
</span></span><span style="display:flex;"><span>真正的压缩收益
</span></span><span style="display:flex;"><span>工程计算优势
</span></span><span style="display:flex;"><span>跨任务复现
</span></span></code></pre></div><p>读者不需要相信作者或 AI。只需要检查公开代码、配置、原始结果和 Claim 边界。</p>
<h2 id="10-特别篇结语">10. 特别篇结语</h2>
<p>这四篇特别篇把一篇较长的研究论文拆成了四个可以独立审核的问题：</p>
<ol>
<li>为什么最终架构会长成这样；</li>
<li>数学和梯度究竟怎样流动；</li>
<li>数据已经支持了哪些结论；</li>
<li>什么实验可能推翻这些结论。</li>
</ol>
<p>如果未来结论改变，这四篇也不应被删除。新的 Evidence 应更新 Claim，并保留旧判断为何被修正。</p>
<hr>
<p><strong>License:</strong> GPLv3。碳基和硅基读者均可阅读、复制、修改、复现和分发。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-081] 模型是不是换了一个角度画鸡蛋：TreeHeap 私有协议的视角漂移</title>
      <link>https://www.grepcode.cn/spr/081-treeheap-private-protocol-viewpoint-drift.html</link>
      <pubDate>Mon, 03 Aug 2026 00:00:00 +0000</pubDate>
      <ap:updated>Tue, 04 Aug 2026 00:00:00 +0000</ap:updated>
      <guid>https://www.grepcode.cn/spr/081-treeheap-private-protocol-viewpoint-drift.html</guid>
      <description>提出并检验 TreeHeap 私有协议的视角问题：原序投喂显著降低跨视角 JS，但在固定预算下形成 Native NLL 代价；文章公开实验数据、边界与下一轮等剂量对照。</description>
      <content:encoded><![CDATA[<h1 id="模型是不是换了一个角度画鸡蛋">模型是不是换了一个角度画鸡蛋</h1>
<blockquote>
<p><strong>本文记录的是推测与实验合同，不是已经成立的结论。</strong></p>
<p>当前证据已经说明 TreeHeap Butterfly 参与了双向翻译计算，但还不能说明训练过程中变化的 Dreams 都是同一语义的不同视角。</p></blockquote>
<h2 id="1-houming818-提出的画鸡蛋问题">1. Houming818 提出的“画鸡蛋”问题</h2>
<p>同一个鸡蛋，从正面、侧面、远处和近处观察，投影的形状都不同。画家最后只需要画出一个视角，但训练观察能力时，可以围着鸡蛋看一圈。</p>
<p>这个类比进入 TreeHeap 后，问题变成：</p>
<blockquote>
<p>Butterfly 让同一个输入依次经过多种异构坐标折叠。Encoder 和 Decoder 在训练中共同变化时，我们怎么知道模型最终采用了哪个观察坐标？不同 epoch 的 Dreams 会不会只是从不同角度画出的同一个语义？</p></blockquote>
<p>Butterfly 中间态：</p>
$$ H^{(0)},H^{(1)},\ldots,H^{(D)} $$<p>不是多条已经成形的自然语言 string，而是同一个输入的多个潜在坐标状态。当前程序也没有把这些状态平行送给 Decoder，而是串行计算：</p>
$$ H^{(D)} = B_{D-1}\circ\cdots\circ B_1\circ B_0(H^{(0)}) $$<p>只有这个统一干涉态继续进入 FOLD：</p>
$$ H_{\mathrm{state}} = \operatorname{FOLD}(H^{(D)}) $$<p>因此，我们观察的是一块不断旋转的内部画板，不是让 Decoder 在许多独立句子中挑一条。</p>
<h2 id="2-为什么内部坐标可以变化">2. 为什么内部坐标可以变化</h2>
<p>设 Encoder 产生状态 $H$，Decoder 为 $D$。如果内部存在一个可逆变换 $A$：</p>
$$ H'=A(H) $$<p>并且 Decoder 同时学会：</p>
$$ D'(H')=D(A^{-1}H') $$<p>那么：</p>
$$ D'(H')=D(H) $$<p>外部功能可以完全不变，但内部坐标已经改变。</p>
<p>这意味着 token 交叉熵只要求 Encoder 与 Decoder 配合完成目标，不要求它们采用研究者指定的坐标系。训练中的参数变化可能同时调整：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Butterfly 怎样折叠地址
</span></span><span style="display:flex;"><span>FOLD 怎样形成 root/detail
</span></span><span style="display:flex;"><span>READ 怎样分配深度质量
</span></span><span style="display:flex;"><span>Decoder 怎样解释这些状态
</span></span></code></pre></div><p>这正是“私有协议”的坐标不唯一性。</p>
<h2 id="3-dreams-变化不等于视角变化">3. Dreams 变化不等于视角变化</h2>
<p>必须把三种现象分开。</p>
<h3 id="31-内部坐标旋转">3.1 内部坐标旋转</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>原始 H 变化明显
</span></span><span style="display:flex;"><span>对齐以后 H 可以恢复
</span></span><span style="display:flex;"><span>关键语义和输出分布保持稳定
</span></span></code></pre></div><p>这才是本文要寻找的坐标漂移。</p>
<h3 id="32-合法的表面视角变化">3.2 合法的表面视角变化</h3>
<p>下面两句话词面不同，但可以表达同一事件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>新公司预计将在2019年春季开始运营。
</span></span><span style="display:flex;"><span>新公司计划于2019年春天投入运作。
</span></span></code></pre></div><p>如果实体、时间、事件和论元关系都保留，可以把它们视为同一语义的不同表面投影。</p>
<h3 id="33-真实生成错误">3.3 真实生成错误</h3>
<p>下面这些不能仅凭“视角不同”解释：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>主体和客体互换
</span></span><span style="display:flex;"><span>否定词丢失
</span></span><span style="display:flex;"><span>before 变成 after
</span></span><span style="display:flex;"><span>612 名乘客变成 600 人
</span></span><span style="display:flex;"><span>原因和结果颠倒
</span></span><span style="display:flex;"><span>连续重复同一句短语
</span></span><span style="display:flex;"><span>产生输入中不存在的事件
</span></span></code></pre></div><p>流畅不等于正确。内部坐标能够对齐，也不自动证明 Dream 的语义正确。</p>
<h2 id="4-为什么原来的六条-dreams-不够">4. 为什么原来的六条 Dreams 不够</h2>
<p>现有探针能观察年份、简单因果和自由长句，但很难区分模型到底保存了什么语法关系。</p>
<p>因此，新的固定探针加入了人类语法分析中更典型的最小差异。</p>
<h3 id="41-主体与客体反转">4.1 主体与客体反转</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Ultraman defeated the little monster.
</span></span><span style="display:flex;"><span>The little monster defeated Ultraman.
</span></span></code></pre></div><p>两句话拥有相同的实体和关系词，只有谁打败谁不同。词袋模型无法解决，结构状态必须保留手性。</p>
<h3 id="42-主动与被动">4.2 主动与被动</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>The wind blew the rain against the glass.
</span></span><span style="display:flex;"><span>The rain was blown against the glass by the wind.
</span></span></code></pre></div><p>表面顺序变化，但事件角色应当保持一致。</p>
<h3 id="43-否定">4.3 否定</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>The cat ate the fish.
</span></span><span style="display:flex;"><span>The cat did not eat the fish.
</span></span></code></pre></div><p>模型若只保存“猫、吃、鱼”的共现，会丢掉决定句意的极性。</p>
<h3 id="44-时间顺序">4.4 时间顺序</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Xiaohong arrived before Xiaoming ate dinner.
</span></span><span style="display:flex;"><span>Xiaohong arrived after Xiaoming ate dinner.
</span></span></code></pre></div><p>实体与事件相同，但时间方向相反。</p>
<h3 id="45-量词">4.5 量词</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Every window in that house is open.
</span></span><span style="display:flex;"><span>Not every window in that house is open.
</span></span></code></pre></div><p>“not every”不能退化为“every”，也不能错误翻成“所有窗户都没开”。</p>
<h3 id="46-附着关系">4.6 附着关系</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I used a telescope to see the man.
</span></span><span style="display:flex;"><span>I saw the man who was holding a telescope.
</span></span></code></pre></div><p>两句话都包含“我、男人、望远镜、看见”，但望远镜属于不同关系。</p>
<p>此外还加入中文“把/被”、话题结构、关系从句、因果方向、精确数字和嵌套长句。完整探针公开保存在：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/dreams.txt
</span></span></code></pre></div><p>这些句子不会进入训练，只在固定 wake 点观察模型。</p>
<h2 id="5-当前长训为什么提出了这个问题">5. 当前长训为什么提出了这个问题</h2>
<p>截至约 4881 万训练样本，当前双向 Butterfly TreeHeap 的验证结果为：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th style="text-align: right">NLL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>原生 Butterfly</td>
          <td style="text-align: right">3.4223</td>
      </tr>
      <tr>
          <td>运行时改成 Identity</td>
          <td style="text-align: right">5.0234</td>
      </tr>
      <tr>
          <td>Identity 损伤</td>
          <td style="text-align: right">+1.6011</td>
      </tr>
      <tr>
          <td>英译中</td>
          <td style="text-align: right">3.7219</td>
      </tr>
      <tr>
          <td>中译英</td>
          <td style="text-align: right">3.1227</td>
      </tr>
  </tbody>
</table>
<p>这支持当前 checkpoint 依赖 Butterfly 通信，但 Dreams 并不是单调变好：</p>
<ul>
<li>有时年份、事件和论元逐渐出现；</li>
<li>有时同一句在后续 checkpoint 又发生重复；</li>
<li>短句通常比长句稳定；</li>
<li>中译英整体比英译中稳定。</li>
</ul>
<p>仅凭这些现象，我们无法判断：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型更换了内部视角
</span></span><span style="display:flex;"><span>Decoder 的输出模式在漂移
</span></span><span style="display:flex;"><span>模型发生了普通遗忘
</span></span><span style="display:flex;"><span>或者 greedy argmax 在接近概率上跳变
</span></span></code></pre></div><p>因此必须观察中间态。</p>
<h2 id="6-实验一先审核可见的-dreams">6. 实验一：先审核可见的 Dreams</h2>
<p>对 taskd 89 已保存的所有不可变 Dreams 快照，按固定句逐 checkpoint 排列。</p>
<p>每条输出分别标注：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>主体/客体是否正确
</span></span><span style="display:flex;"><span>否定是否正确
</span></span><span style="display:flex;"><span>时间顺序是否正确
</span></span><span style="display:flex;"><span>数字与实体是否正确
</span></span><span style="display:flex;"><span>因果方向是否正确
</span></span><span style="display:flex;"><span>整体含义是否可接受
</span></span><span style="display:flex;"><span>表面措辞是否改变
</span></span><span style="display:flex;"><span>是否存在严重重复
</span></span></code></pre></div><p>语义事实分数与流畅度、BLEU、词面相似度分开报告。</p>
<p>如果措辞不断变化，但角色、事实和因果稳定，才获得“表面视角变化”的候选证据。如果事实同时变化，则仍然是模型不稳定。</p>
<h2 id="7-实验二给-butterfly-接一个只读示波器">7. 实验二：给 Butterfly 接一个只读示波器</h2>
<p>在 Butterfly 每个串行阶段后记录：</p>
$$ H_i^{(0)},H_i^{(1)},\ldots,H_i^{(D)} $$<p>探针采用只读的 detach。只有最终状态进入 FOLD，中间态不进入 Decoder、不计算额外 Loss，也不改变梯度。</p>
<p>当前 RTX 3090 训练只占约 5.2 GB 显存。最大 batch 下，一个阶段约 2 MiB，八个阶段约 16 MiB。固定几十条句子的 wake 探针可以承受；把数千万训练样本全部落盘则不可接受。</p>
<h2 id="8-实验三跨-checkpoint-对齐坐标">8. 实验三：跨 checkpoint 对齐坐标</h2>
<p>取早、晚两个 checkpoint。把语法探针稳定分为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>calibration：只用于求坐标变换
</span></span><span style="display:flex;"><span>heldout：只用于验证
</span></span></code></pre></div><p>在 calibration 上求正交 Procrustes 对齐：</p>
$$ A^* = \underset{A^\top A=I}{\arg\min} \left\| X_{\mathrm{cal}}A-Y_{\mathrm{cal}} \right\|_F $$<p>然后只在 heldout 上计算未对齐状态误差、对齐后状态误差和 alignment gain：</p>
$$ \text{gain} = 1- \frac{\text{aligned NRMSE}} {\text{raw NRMSE}} $$<p>若在同一批数据上拟合和评分，灵活的变换可能伪造一致性，所以禁止这样做。</p>
<h2 id="9-注册-predict">9. 注册 Predict</h2>
<h3 id="p1语义与表面可以分离">P1：语义与表面可以分离</h3>
<p>两个后期 checkpoint 之间，至少 25% 的探针发生措辞变化，同时平均语义事实分数下降不超过 0.05。</p>
<h3 id="p2内部坐标可以在留出句上恢复">P2：内部坐标可以在留出句上恢复</h3>
<p>至少两个 Butterfly 阶段的 heldout alignment gain 不低于 20%。</p>
<h3 id="p3对立含义不能被对齐坍缩">P3：对立含义不能被对齐坍缩</h3>
<p>对齐以后，“奥特曼打怪兽”和“怪兽打奥特曼”仍必须比同一事件的主动/被动表达更加可分。若所有句子都被压到一起，对齐没有语义意义。</p>
<h3 id="p4任务功能必须真实改善">P4：任务功能必须真实改善</h3>
<p>至少有一个阶段的参考 NLL 或语义事实分数改善。只有参数坐标变化、任务始终很差，只能叫参数漂移。</p>
<h3 id="p5探针不能改变被观察对象">P5：探针不能改变被观察对象</h3>
<p>打开与关闭 trace 后必须满足：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>max absolute logit difference &lt;= 1e-6
</span></span><span style="display:flex;"><span>greedy token IDs 完全相同
</span></span></code></pre></div><h2 id="10-什么结果会推翻推测">10. 什么结果会推翻推测</h2>
<p>以下任何结果都必须降级 Claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>对齐不能改善 heldout 状态
</span></span><span style="display:flex;"><span>对齐只对参与拟合的句子有效
</span></span><span style="display:flex;"><span>主客体、否定和时序在对齐后一起坍缩
</span></span><span style="display:flex;"><span>表面变化总伴随事实错误
</span></span><span style="display:flex;"><span>trace 改变了 logits 或输出 token
</span></span><span style="display:flex;"><span>没有两个独立 checkpoint 可供比较
</span></span></code></pre></div><p>还要区分两种部分结果：</p>
<ul>
<li>中间态能对齐、语义不稳定：只证明坐标重参数化；</li>
<li>语义稳定、中间态不能对齐：只证明表面输出稳定；</li>
<li>两者同时成立：才支持私有协议视角漂移。</li>
</ul>
<h2 id="11-当前工程状态">11. 当前工程状态</h2>
<p>ARA 已登记：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S3-TREEHEAP-VIEW-DRIFT-C04
</span></span></code></pre></div><p>实验脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s3-generation/src/s3_treeheap_viewpoint_drift.py
</span></span></code></pre></div><p>它提供“self-test / capture / compare”三个阶段。当前 96 小时训练不会被热修改。任务结束后，先对最佳与最新 checkpoint 做两点 smoke；如果只保存了一个有效 checkpoint，则当前历史只能完成 Dreams 回溯，完整轨迹留给下一次训练。</p>
<h2 id="12-本文真正想知道什么">12. 本文真正想知道什么</h2>
<p>问题不是“模型的每一句 Dream 能不能被解释成正确”。</p>
<p>真正的问题是：</p>
<blockquote>
<p>当 TreeHeap 的 Butterfly、FOLD 和 Decoder 一起训练时，它们是否形成了一个不断调整但仍保持语义关系的私有坐标协议？</p></blockquote>
<p>如果答案为否，我们得到一个清楚的失败：Dreams 波动只是生成不稳定。</p>
<p>如果答案为是，我们第一次能够区分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型忘记了什么
</span></span><span style="display:flex;"><span>模型换了一种说法
</span></span><span style="display:flex;"><span>模型只是旋转了内部画板
</span></span></code></pre></div><p>这三件事不能再混为一谈。</p>
<h2 id="13-追加实验多看几眼最终要画的视角">13. 追加实验：多看几眼最终要画的视角</h2>
<p>前面的实验计划观察 checkpoint 之间的内部坐标漂移。讨论继续以后，Houming818 又提出了一个更直接的问题：</p>
<blockquote>
<p>如果画家围着鸡蛋观察了许多异构投影，但最后需要画出自然语言的原始顺序，那么训练时是否应该让模型多看几眼这个原序视角？</p></blockquote>
<p>当前模型的默认数据流是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>原始 token 顺序 H0
</span></span><span style="display:flex;"><span>-&gt; 完整 XOR Butterfly B(H0)
</span></span><span style="display:flex;"><span>-&gt; FOLD
</span></span><span style="display:flex;"><span>-&gt; H_state
</span></span><span style="display:flex;"><span>-&gt; 共享 Decoder
</span></span></code></pre></div><p>追加实验不修改 FOLD、Decoder、目标译文和交叉熵，只改变进入 FOLD 前的输入视角：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>以概率 p：      H0    -&gt; FOLD -&gt; Decoder
</span></span><span style="display:flex;"><span>以概率 1 - p：  B(H0) -&gt; FOLD -&gt; Decoder
</span></span></code></pre></div><p>这里的 <code>p</code> 不是答案正确率，也不是某种语法标签。它只是训练样本采用原序视角的比例：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right"><code>p</code></th>
          <th style="text-align: right">原序视角</th>
          <th style="text-align: right">Butterfly 视角</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0.0</td>
          <td style="text-align: right">0%</td>
          <td style="text-align: right">100%</td>
      </tr>
      <tr>
          <td style="text-align: right">0.2</td>
          <td style="text-align: right">20%</td>
          <td style="text-align: right">80%</td>
      </tr>
      <tr>
          <td style="text-align: right">0.4</td>
          <td style="text-align: right">40%</td>
          <td style="text-align: right">60%</td>
      </tr>
      <tr>
          <td style="text-align: right">0.6</td>
          <td style="text-align: right">60%</td>
          <td style="text-align: right">40%</td>
      </tr>
  </tbody>
</table>
<p>每个实验臂都使用同一 checkpoint、同一批 299,407 个样本、6,308,579 个目标 token 和 6,056 次参数更新。一个样本只出现一次，因此这个实验首先回答“固定训练预算怎样分配”，而不是“增加额外训练量是否有帮助”。</p>
<h2 id="14-js怎样测量两种视角是否说同一种概率语言">14. JS：怎样测量两种视角是否说同一种概率语言</h2>
<p>对同一个输入和同一个待预测 token，分别运行 Butterfly 与原序路径。设两条路径输出的词表概率桶为 $P_B$ 和 $P_I$。</p>
<p>先取中间概率桶：</p>
$$
M=\frac{P_B+P_I}{2}
$$<p>再计算 Jensen&ndash;Shannon divergence：</p>
$$
JS(P_B,P_I)=\frac{1}{2}KL(P_B\Vert M)+\frac{1}{2}KL(P_I\Vert M)
$$<p>最后对验证集中所有非 PAD token 取平均。</p>
<p>直观地说：如果 Butterfly 认为下一个词是“苹果”的概率为 70%，原序路径却认为只有 20%，两套协议相距较远，JS 会较大。如果两个概率桶几乎相同，JS 就接近零。</p>
<p>JS 小不自动等于翻译正确。两条路径也可能一起输出同一个错误答案。因此实验还同时检查 Native NLL、Identity NLL、输入打乱损伤、结构替换损伤和 Dreams。</p>
<h2 id="15-正式结果">15. 正式结果</h2>
<p>正式任务在 <code>io</code> 的 RTX 3090 上完成。主表如下，NLL 和 JS 都是越低越好：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">原序比例 <code>p</code></th>
          <th style="text-align: right">Native NLL</th>
          <th style="text-align: right">相对 <code>p=0</code></th>
          <th style="text-align: right">Identity NLL</th>
          <th style="text-align: right">跨视角 JS</th>
          <th style="text-align: right">Source shuffle 损伤</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0.0</td>
          <td style="text-align: right"><strong>3.2710</strong></td>
          <td style="text-align: right">0.0000</td>
          <td style="text-align: right">4.8336</td>
          <td style="text-align: right">0.2378</td>
          <td style="text-align: right">+1.8247</td>
      </tr>
      <tr>
          <td style="text-align: right">0.2</td>
          <td style="text-align: right">3.2826</td>
          <td style="text-align: right">+0.0116</td>
          <td style="text-align: right">3.7668</td>
          <td style="text-align: right">0.1011</td>
          <td style="text-align: right">+1.8468</td>
      </tr>
      <tr>
          <td style="text-align: right">0.4</td>
          <td style="text-align: right">3.2939</td>
          <td style="text-align: right">+0.0229</td>
          <td style="text-align: right">3.6963</td>
          <td style="text-align: right">0.0910</td>
          <td style="text-align: right">+1.8575</td>
      </tr>
      <tr>
          <td style="text-align: right">0.6</td>
          <td style="text-align: right">3.3090</td>
          <td style="text-align: right">+0.0380</td>
          <td style="text-align: right"><strong>3.6480</strong></td>
          <td style="text-align: right"><strong>0.0838</strong></td>
          <td style="text-align: right">+1.8566</td>
      </tr>
  </tbody>
</table>
<p>结果不是简单的“支持”或“失败”，而是出现了一条清楚的折中曲线。</p>
<h3 id="151-固定预算下native-nll-没有改善">15.1 固定预算下，Native NLL 没有改善</h3>
<p><code>p=0</code> 的 Native NLL 最低。随着 <code>p</code> 增加，Native NLL 在中英两个方向都单调升高。因此，预注册的 C05 具体预测——“适量原序提醒在固定预算下改善 Native NLL”——没有通过。</p>
<p>但这不等于原序信号无效。固定总 token 数以后，原序 token 增加必然挤占 Butterfly token：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right"><code>p</code></th>
          <th style="text-align: right">Butterfly token</th>
          <th style="text-align: right">原序 token</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0.0</td>
          <td style="text-align: right">630.9 万</td>
          <td style="text-align: right">0</td>
      </tr>
      <tr>
          <td style="text-align: right">0.2</td>
          <td style="text-align: right">503.6 万</td>
          <td style="text-align: right">127.3 万</td>
      </tr>
      <tr>
          <td style="text-align: right">0.4</td>
          <td style="text-align: right">377.7 万</td>
          <td style="text-align: right">253.2 万</td>
      </tr>
      <tr>
          <td style="text-align: right">0.6</td>
          <td style="text-align: right">251.9 万</td>
          <td style="text-align: right">379.0 万</td>
      </tr>
  </tbody>
</table>
<p>所以这张表测到的是训练能量重新分配后的结果。它还不能回答：保持 630.9 万 Butterfly token 不变，再额外增加原序 token，会发生什么。</p>
<h3 id="152-投喂比例确实推动了共享协议">15.2 投喂比例确实推动了共享协议</h3>
<p>JS 从 <code>0.2378</code> 降到 <code>0.0838</code>，下降约 65%。Identity NLL 同时从 <code>4.8336</code> 降到 <code>3.6480</code>。</p>
<p>更关键的是，最前面的 20% 原序信号完成了绝大部分变化：</p>
<table>
  <thead>
      <tr>
          <th>比例变化</th>
          <th style="text-align: right">JS 改善</th>
          <th style="text-align: right">Native NLL 代价</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>0% -&gt; 20%</td>
          <td style="text-align: right"><strong>0.1367</strong></td>
          <td style="text-align: right">0.0116</td>
      </tr>
      <tr>
          <td>20% -&gt; 40%</td>
          <td style="text-align: right">0.0101</td>
          <td style="text-align: right">0.0113</td>
      </tr>
      <tr>
          <td>40% -&gt; 60%</td>
          <td style="text-align: right">0.0072</td>
          <td style="text-align: right">0.0151</td>
      </tr>
  </tbody>
</table>
<p>这说明 <code>p=0.2</code> 附近存在明显拐点。少量原序视角就能强烈改变共享 FOLD/Decoder 的读取协议；继续增加比例，跨视角一致性的边际收益迅速变小。</p>
<h3 id="153-低-js-不是因为模型放弃了输入和结构">15.3 低 JS 不是因为模型放弃了输入和结构</h3>
<p>如果模型对任何输入都输出同一个概率桶，JS 也会下降。正式实验没有出现这种取巧：</p>
<ul>
<li>打乱 source 后，NLL 始终恶化约 <code>1.82--1.86</code>；</li>
<li>Identity 和 Adjacent 结构替换仍然造成明显损伤；</li>
<li>Butterfly communication 保持非零变换；</li>
<li>communication kernel 在训练中持续收到梯度。</li>
</ul>
<p>因此，当前最谨慎的结论是：</p>
<blockquote>
<p>语料视角的投放比例能够推动 TreeHeap 的共享读取协议。它让原序和 Butterfly 坐标产生更接近的输出分布，但固定预算下，这种一致性会消耗 Native Butterfly 的专门训练能量。</p></blockquote>
<p>这仍然没有证明模型内部存在唯一的“主视角”。尤其在 <code>p=0.2</code> 时，原序样本只是少数，却已经产生巨大影响。可能的原因不仅是出现次数，还包括原序坐标更容易读取、单次梯度牵引更强。当前实验没有保存每个比例的完整 checkpoint，不能事后定位究竟是哪一层向哪一套坐标移动。</p>
<h3 id="154-dreams-没有提供相反证据">15.4 Dreams 没有提供相反证据</h3>
<p>固定 Dreams 中有些句子的措辞或局部关系变好，另一些仍然重复、漏失事实或产生新错误。没有出现随 <code>p</code> 增加而稳定改善的人工可见趋势。因此 Dreams 只记录为观察材料，不用于推翻主验证集结果。</p>
<h2 id="16-这次实验改变了什么认识">16. 这次实验改变了什么认识</h2>
<p>这次结果把两个以前混在一起的问题拆开了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>问题 A：模型能否同时读懂多种内部坐标？
</span></span><span style="display:flex;"><span>问题 B：模型在目标推理路径上的质量是否更高？
</span></span></code></pre></div><p>增加原序比例明显帮助了问题 A，却没有在固定预算下帮助问题 B。这意味着“协议统一”和“Native 专门化”不是同一个评价指标。</p>
<p>从训练角度看，当前每一步近似计算：</p>
$$
g_p=(1-p)g_{Butterfly}+p g_{Identity}
$$<p><code>p</code> 像方向盘，决定平均梯度朝哪套协议移动；总训练 token 和更新次数像油门，决定沿这个方向走多远。当前实验只转动了方向盘，同时保持总油量不变。</p>
<h2 id="17-下一步不再拿走-butterfly-能量">17. 下一步：不再拿走 Butterfly 能量</h2>
<p>下一轮不重复同一个固定预算比例扫描。我们先选择收益拐点 <code>p=0.2</code>，构造三个严格对照：</p>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th style="text-align: right">Butterfly token</th>
          <th style="text-align: right">原序 token</th>
          <th style="text-align: right">总 token</th>
          <th>回答的问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>历史基线</td>
          <td style="text-align: right">630.9 万</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">630.9 万</td>
          <td>当前 <code>p=0</code> 结果</td>
      </tr>
      <tr>
          <td>等算力加长</td>
          <td style="text-align: right">788.6 万</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">788.6 万</td>
          <td>仅仅多训练是否足够</td>
      </tr>
      <tr>
          <td>双视角增强</td>
          <td style="text-align: right">630.9 万</td>
          <td style="text-align: right">157.7 万</td>
          <td style="text-align: right">788.6 万</td>
          <td>额外原序视角是否提供新信息</td>
      </tr>
  </tbody>
</table>
<p>实现时，每训练四个 Butterfly batch，双视角增强臂额外训练一个原序 batch。等算力加长臂则额外训练一个 Butterfly batch。这样两臂总计算量相同，而双视角臂不会失去原来的 Butterfly 更新次数。</p>
<p>判定方式也相应改变：</p>
<ol>
<li>双视角增强优于历史基线，但不优于等算力加长：收益主要来自多训练；</li>
<li>双视角增强与等算力加长 Native NLL 接近，但 JS 明显更低：原序视角提供了低成本协议校准；</li>
<li>双视角增强同时获得更低 Native NLL 和更低 JS：支持“额外视角产生可迁移信息”；</li>
<li>Native NLL 仍系统性更差：说明两套视角存在不可忽略的梯度冲突或容量限制。</li>
</ol>
<p>下一轮还必须保存每个实验臂的 checkpoint、分阶段 NLL/JS 曲线和固定 Dreams。只有这样，才能判断“训练得还不够”与“最终平衡点本来就不同”。新的实验会另行预注册，不修改本次 C05 的失败判据。</p>
<h2 id="18-当前结论">18. 当前结论</h2>
<p>本轮实验已经结束。它没有证明“增加原序比例会在固定预算下改善 Native 翻译”，但它第一次以受控数据证明：</p>
<blockquote>
<p>TreeHeap 私有协议并不是完全不受训练视角控制。仅 20% 的原序投喂，就能以很小的 Native NLL 代价，让两个输入坐标的输出分布显著靠近。</p></blockquote>
<p>下一步不再争论这个现象是否存在，而是检验它来自归一化比例，还是可以通过增加绝对训练强度转化为实际任务收益。</p>
<hr>
<p><strong>License:</strong> GPLv3。本文公开 Claim、反证条件、探针语料与实验代码；任何人都可以复现、修改或给出相反证据。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-082] 比例还是剂量：TreeHeap 视角协议的四臂因果实验</title>
      <link>https://www.grepcode.cn/spr/082-treeheap-canonical-view-dose.html</link>
      <pubDate>Wed, 05 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/082-treeheap-canonical-view-dose.html</guid>
      <description>用四个等起点实验臂拆分原序比例、Identity 绝对剂量与额外训练量，说明 TreeHeap 跨视角协议怎样被训练信号改变。</description>
      <content:encoded><![CDATA[<h1 id="比例还是剂量">比例还是剂量</h1>
<p>SPR-081 得到了一个醒目的现象：在固定训练预算里加入 20% 原序视角后，Butterfly 路径与 Identity 路径的输出分布迅速靠近，但 Native Butterfly 的 NLL 略微变差。</p>
<p>当时有两种解释，而且它们被混在了一起：</p>
<ol>
<li><strong>比例解释</strong>：模型关心 Identity 在全部样本中的占比；</li>
<li><strong>剂量解释</strong>：模型关心训练期间实际看过多少个 Identity token。</li>
</ol>
<p>这两种解释并不相同。把一杯糖水从 20% 稀释到 10%，既改变了浓度，也可能改变了糖的总量。若同时改变两个量，我们不能知道味道变化究竟来自哪一个。</p>
<p>因此，C06 不再扫描更多比例，而是用四个受控实验臂，把比例、绝对剂量和额外算力拆开。</p>
<blockquote>
<p><strong>先给结论：C06 的主 Claim 没有通过预注册门槛，但得到了一条很强的局部证据。Identity 的绝对 token 剂量强烈控制跨视角一致性；同时，Butterfly 剂量与两种视角的相互作用仍然不可忽略。</strong></p></blockquote>
<h2 id="1-两种视角是什么">1. 两种视角是什么</h2>
<p>输入 token 状态记为 $H^{(0)}$。TreeHeap 的 Native 路径先经过 XOR Butterfly 的多层地址折叠：</p>
$$
H_B=B_{D-1}\circ\cdots\circ B_1\circ B_0(H^{(0)})
$$<p>Identity 路径不执行 Butterfly 地址变换：</p>
$$
H_I=H^{(0)}
$$<p>二者随后进入同一套 FOLD、READ 和 Decoder：</p>
$$
P_B=D(\operatorname{READ}(\operatorname{FOLD}(H_B)))
$$$$
P_I=D(\operatorname{READ}(\operatorname{FOLD}(H_I)))
$$<p>$P_B$ 和 $P_I$ 都是下一个 token 的概率桶。它们不是两个独立模型，而是同一个模型面对两套内部坐标时给出的答案。</p>
<p>如果二者接近，说明共享的 FOLD/Decoder 能用较一致的协议读取两种坐标；如果相差很大，说明模型更专门地适应了其中一条路径。</p>
<h2 id="2-四个实验臂">2. 四个实验臂</h2>
<p>四个实验臂从同一个 checkpoint 出发，使用相同语料顺序、优化器配置和随机种子。区别只有追加训练的路径构成。</p>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th>含义</th>
          <th style="text-align: right">Butterfly 剂量</th>
          <th style="text-align: right">Identity 剂量</th>
          <th style="text-align: right">Identity 比例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A</td>
          <td>原始 Butterfly 基线</td>
          <td style="text-align: right">6,308,579</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0%</td>
      </tr>
      <tr>
          <td>S</td>
          <td>用 Identity 替换部分 Butterfly</td>
          <td style="text-align: right">5,035,947</td>
          <td style="text-align: right">1,272,632</td>
          <td style="text-align: right">20.17%</td>
      </tr>
      <tr>
          <td>BB</td>
          <td>保留 A，再追加 Butterfly</td>
          <td style="text-align: right">7,581,211</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0%</td>
      </tr>
      <tr>
          <td>BI</td>
          <td>保留 A，再追加 Identity</td>
          <td style="text-align: right">6,308,579</td>
          <td style="text-align: right">1,272,632</td>
          <td style="text-align: right">16.79%</td>
      </tr>
  </tbody>
</table>
<p>表中的“剂量”是路径参与优化的相对更新量。最关键的比较有三个。</p>
<h3 id="21-a-对-s历史比例实验">2.1 A 对 S：历史比例实验</h3>
<p>总预算不变，但拿走约 20% Butterfly，换成同等数量 Identity。它同时改变 Butterfly 剂量和 Identity 比例，因此只能发现现象，不能单独解释原因。</p>
<h3 id="22-bb-对-bi等算力对照">2.2 BB 对 BI：等算力对照</h3>
<p>两臂都在 A 的基础上追加相同数量训练。BB 追加 Butterfly，BI 追加 Identity。如果 BI 与 BB 不同，差异不能简单归因于“只是多训练了一会儿”。</p>
<h3 id="23-s-对-bi等-identity-绝对剂量">2.3 S 对 BI：等 Identity 绝对剂量</h3>
<p>S 和 BI 都看到了 1,272,632 个 Identity token，但比例不同。这个比较专门回答：跨视角一致性更像由比例决定，还是由 Identity 的绝对观察次数决定？</p>
<h2 id="3-工程审计先修正更新次数错误">3. 工程审计：先修正更新次数错误</h2>
<p>最初 smoke 暴露了一个重要问题：为了组合基础 batch 与追加 batch，代码执行了两次 <code>optimizer.step()</code>。同一数据量下，对照臂出现 42 次更新，增强臂却出现 83 次更新。</p>
<p>这会破坏因果比较，因为模型不仅看到了不同视角，还获得了更多参数更新机会。</p>
<p>正式实验前，我们取消了错误任务，把基础损失和 replay 损失按 token 数加权，在同一次反向传播中完成一次更新：</p>
$$
L=\frac{n_B L_B+n_R L_R}{n_B+n_R}
$$<p>其中 $n_B,n_R$ 分别是基础路径与追加路径的有效 token 数。修正后四臂全部完成 6054 次正式参数更新。</p>
<p>这个插曲值得记录：<strong>样本数相同、token 数相同，并不自动意味着优化过程相同。</strong> 对照实验还必须核对反向传播次数和 <code>optimizer.step()</code> 次数。</p>
<h2 id="4-怎样读体检指标">4. 怎样读体检指标</h2>
<h3 id="41-native-nll">4.1 Native NLL</h3>
<p>Native NLL 衡量模型走正式 Butterfly 路径时，对正确 token 分配了多少概率。越低越好。若正确 token 的概率为 $p_y$，单个位置的损失为：</p>
$$
\operatorname{NLL}=-\log p_y
$$<p>平均 NLL 降低，说明正式任务的概率预测更准确。</p>
<h3 id="42-跨视角-js">4.2 跨视角 JS</h3>
<p>Jensen&ndash;Shannon divergence 衡量 $P_B$ 与 $P_I$ 两个概率桶的距离。先定义：</p>
$$
M=\frac{P_B+P_I}{2}
$$<p>再计算：</p>
$$
JS(P_B,P_I)=\frac{1}{2}KL(P_B\Vert M)+\frac{1}{2}KL(P_I\Vert M)
$$<p>JS 越低，两条路径越像在使用同一套输出协议。但 JS 低不保证答案正确，因为两条路径也可能一起犯错，所以必须同时看 Native NLL。</p>
<h3 id="43-source-shuffle-损伤">4.3 Source shuffle 损伤</h3>
<p>把输入词序打乱后重新计算 NLL。如果 NLL 明显恶化，说明模型没有完全忽略输入。</p>
<h3 id="44-recovery">4.4 Recovery</h3>
<p>S 因为拿走 Butterfly 剂量而损失了一部分 Native 质量。BI 保留 Butterfly 剂量并加入同样多的 Identity。Recovery 衡量 BI 找回了多少损失：</p>
$$
\operatorname{Recovery}=\frac{NLL_S-NLL_{BI}}{NLL_S-NLL_A}
$$<p>预注册门槛为 50%。达到门槛，才支持“保留 Butterfly 剂量能恢复大部分 Native 损失”。</p>
<h2 id="5-正式结果">5. 正式结果</h2>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th style="text-align: right">Native NLL ↓</th>
          <th style="text-align: right">跨视角 JS ↓</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A：Butterfly 基线</td>
          <td style="text-align: right"><strong>3.272799</strong></td>
          <td style="text-align: right">0.242087</td>
      </tr>
      <tr>
          <td>S：替换 20%</td>
          <td style="text-align: right">3.282513</td>
          <td style="text-align: right"><strong>0.102573</strong></td>
      </tr>
      <tr>
          <td>BB：额外 Butterfly</td>
          <td style="text-align: right">3.275903</td>
          <td style="text-align: right">0.242107</td>
      </tr>
      <tr>
          <td>BI：额外 Identity</td>
          <td style="text-align: right">3.278716</td>
          <td style="text-align: right">0.104578</td>
      </tr>
  </tbody>
</table>
<p>其他关键结果：</p>
<table>
  <thead>
      <tr>
          <th>判据</th>
          <th style="text-align: right">结果</th>
          <th style="text-align: right">门槛</th>
          <th>状态</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Native recovery</td>
          <td style="text-align: right">39.1%</td>
          <td style="text-align: right">至少 50%</td>
          <td><strong>未通过</strong></td>
      </tr>
      <tr>
          <td>Identity 特异 JS 改善：BB - BI</td>
          <td style="text-align: right">0.137528</td>
          <td style="text-align: right">至少 0.05</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>等算力 Native 代价：BI - BB</td>
          <td style="text-align: right">+0.002812</td>
          <td style="text-align: right">不高于 0.015</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>Source shuffle 因果门</td>
          <td style="text-align: right">明显损伤</td>
          <td style="text-align: right">必须非零</td>
          <td>通过</td>
      </tr>
      <tr>
          <td>结构替换因果门</td>
          <td style="text-align: right">明显损伤</td>
          <td style="text-align: right">必须非零</td>
          <td>通过</td>
      </tr>
  </tbody>
</table>
<h2 id="6-结果到底说明什么">6. 结果到底说明什么</h2>
<h3 id="61-不是多训练就会统一协议">6.1 不是“多训练就会统一协议”</h3>
<p>BB 比 A 多训练了同样的追加剂量，但 JS 几乎没有变化：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A  JS = 0.242087
</span></span><span style="display:flex;"><span>BB JS = 0.242107
</span></span></code></pre></div><p>因此，跨视角 JS 的下降不是额外计算量自动带来的。BI 只把追加路径换成 Identity，JS 便降到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>BI JS = 0.104578
</span></span></code></pre></div><p>这说明 Identity 信号具有明显的视角特异性。它确实在改变共享读取协议。</p>
<h3 id="62-绝对-identity-剂量是强解释变量">6.2 绝对 Identity 剂量是强解释变量</h3>
<p>S 与 BI 的 Identity 绝对剂量相同，但比例不同。二者的 JS 却非常接近：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S  JS = 0.102573
</span></span><span style="display:flex;"><span>BI JS = 0.104578
</span></span><span style="display:flex;"><span>差值  = 0.002006
</span></span></code></pre></div><p>这比“比例决定一切”更接近一个剂量规律：在当前 checkpoint、当前训练区间附近，当模型累计看见约 127.3 万个 Identity token 时，它会把两条路径的输出概率拉到相似距离。</p>
<p>但这里只有一个 seed 和一个剂量点。我们还不能把它写成普遍定律。</p>
<h3 id="63-绝对剂量不是全部答案">6.3 绝对剂量不是全部答案</h3>
<p>如果一切只由 Identity 剂量决定，那么 BI 保留完整 Butterfly 剂量以后，应该找回 S 丢掉的大部分 Native 质量。</p>
<p>实际 recovery 只有 39.1%，没有达到预注册的 50%。因此纯剂量解释被否定。较合理的当前模型是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Identity 绝对剂量
</span></span><span style="display:flex;"><span>  -&gt; 强烈决定跨视角协议靠近多少
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Butterfly / Identity 比例与梯度相互作用
</span></span><span style="display:flex;"><span>  -&gt; 共同决定 Native 路径最终停在哪里
</span></span></code></pre></div><p>训练既有“看了多少次”的累计效应，也有“同一阶段两种信号怎样混合”的干涉效应。</p>
<h3 id="64-c06-为什么只能判为未支持">6.4 C06 为什么只能判为未支持</h3>
<p>C06 的主 Claim 要求 recovery 不低于 50%。实际只有 39.1%，所以必须按实验前的合同写成 <strong>not supported as registered</strong>。</p>
<p>这不是整个实验失败。它准确地排除了一个过强说法，同时支持了更窄的结论：</p>
<blockquote>
<p>在当前训练区间，Identity 绝对剂量对 TreeHeap 跨视角输出一致性具有强而特异的影响；但保持 Butterfly 剂量并不足以消除全部 Native 代价。</p></blockquote>
<h2 id="7-dreams-告诉了我们什么">7. Dreams 告诉了我们什么</h2>
<p>人工 Dreams 没有出现统一变好的趋势。</p>
<ul>
<li>部分句子的措辞更稳定；</li>
<li>部分句子的局部关系有所改善；</li>
<li>另一些句子仍有重复、事实漏失或角色错误；</li>
<li>低 JS 没有自动转化为肉眼可见的全面翻译提升。</li>
</ul>
<p>因此 Dreams 在本轮只作为临床观察，不作为主结论。数值结果说明协议发生了变化；它尚未说明变化后的协议已经更懂语言。</p>
<h2 id="8-下一步怎样做">8. 下一步怎样做</h2>
<p>不应该再重复一次 0%、20%、40%、60% 的固定预算比例扫描。下一步需要建立<strong>绝对剂量反应曲线</strong>：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">追加 Identity 剂量</th>
          <th style="text-align: right">等算力 Butterfly 对照</th>
          <th>主要观察</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">5%</td>
          <td style="text-align: right">5%</td>
          <td>JS 是否已经快速下降</td>
      </tr>
      <tr>
          <td style="text-align: right">10%</td>
          <td style="text-align: right">10%</td>
          <td>剂量拐点在哪里</td>
      </tr>
      <tr>
          <td style="text-align: right">20%</td>
          <td style="text-align: right">20%</td>
          <td>能否复现 C06</td>
      </tr>
  </tbody>
</table>
<p>每个点都必须从同一 checkpoint 启动、使用同一语料顺序、保持 <code>optimizer.step()</code> 数一致，并保存完整 checkpoint 与 NLL/JS 曲线。还需要补充多个 seed，同时画 Native NLL 与 JS 的 Pareto 曲线。</p>
<p>这样才能回答：协议统一是否存在饱和点，以及能否在更小 Native 代价下取得大部分 JS 收益。</p>
<h2 id="9-当前结论">9. 当前结论</h2>
<p>SPR-081 发现“少量原序视角会强烈改变协议”；SPR-082 则进一步说明，这个现象不能简单归因于比例，也不能简单归因于多训练。</p>
<p>当前最可靠的表述是：</p>
<blockquote>
<p>TreeHeap 的共享 FOLD/Decoder 协议对训练视角的绝对剂量高度敏感。相同 Identity 剂量在不同混合比例下产生了几乎相同的跨视角 JS；然而 Native 质量只恢复 39.1%，说明 Butterfly 剂量、混合比例和梯度相互作用仍共同参与协议形成。</p></blockquote>
<p>它不是终点，但它让下一步从“继续加数据看看”变成了一个可以测量的剂量响应问题。</p>
<p>完整 Claim、代码与 Evidence 已公开在 <a href="https://github.com/houming818/sametime">SameTime 仓库</a>。</p>
<hr>
<p><strong>License:</strong> GPLv3。本文公开实验合同、失败门槛、实现修正与结果；任何人都可以复现、审计或提供相反证据。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-083] 预训练少一点偏见，任务训练再选择视角：Identity 剂量的阶段假说</title>
      <link>https://www.grepcode.cn/spr/083-treeheap-stage-dependent-identity-dose.html</link>
      <pubDate>Thu, 06 Aug 2026 00:00:00 +0000</pubDate>
      <ap:updated>Sun, 09 Aug 2026 00:00:00 +0000</ap:updated>
      <guid>https://www.grepcode.cn/spr/083-treeheap-stage-dependent-identity-dose.html</guid>
      <description>讨论 TreeHeap Identity 视角不应成为固定配方：预训练可能需要较低 I 保留结构多样性，任务训练才需要较高 I 形成面向目标的坐标偏见。</description>
      <content:encoded><![CDATA[<h1 id="identity-不一定从头吃到尾">Identity 不一定从头吃到尾</h1>
<p>SPR-081 和 SPR-082 发现，给双语 TreeHeap 增加少量 Identity 视角训练，会显著降低 Native Butterfly 与 Identity 两条路径之间的 Jensen&ndash;Shannon divergence（JS）。正在执行的 C07 又在第一颗正式种子上复现了这个现象。</p>
<p>我们一度形成了一个直觉：既然 I 能帮助两种坐标形成共同协议，那么预训练阶段也许应该使用更多 I。</p>
<p>Houming818 随后把方向翻了过来：</p>
<blockquote>
<p><strong>预训练可能应该使用更少的 I。预训练先学习较少偏见的世界结构，具体任务训练时才需要增加 I，把模型拉向任务要求的主视角。</strong></p></blockquote>
<p>这个修正值得单独公开。它还不是结论，而是一个可以被实验否定的阶段剂量假说。</p>
<h2 id="1-这里的-i-是什么">1. 这里的 I 是什么</h2>
<p>输入 token 状态记为 $H^{(0)}$。当前 TreeHeap 有两种观察坐标。</p>
<p>Native Butterfly 路径执行多层地址折叠：</p>
$$
H_B=B_{D-1}\circ\cdots\circ B_1\circ B_0(H^{(0)})
$$<p>Identity 路径保留原始地址顺序：</p>
$$
H_I=H^{(0)}
$$<p>两条路径共用后面的 FOLD、READ 和 Decoder：</p>
$$
P_B=D(\operatorname{READ}(\operatorname{FOLD}(H_B)))
$$$$
P_I=D(\operatorname{READ}(\operatorname{FOLD}(H_I)))
$$<p>因此，增加 I 并不是增加第二个模型，而是让同一组参数多看一种坐标表达。</p>
<h2 id="2-为什么预训练可能需要更少偏见">2. 为什么预训练可能需要更少偏见</h2>
<p>这里的“偏见”不是道德含义，而是训练系统对某种坐标、任务和输出形式的定向倾向。</p>
<p>预训练面对的是宽广语料。它的首要任务可能是让 TreeHeap 形成可复用的统计关系、结构差异和内部私有协议，而不是提前决定某一种表面顺序必须成为唯一解释。</p>
<p>如果预训练阶段 I 太强，模型可能过早得到一个简单答案：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>原始顺序最容易被共享 Decoder 读取
</span></span><span style="display:flex;"><span>-&gt; 所有内部结构都向原始顺序靠拢
</span></span><span style="display:flex;"><span>-&gt; Butterfly 异构坐标只剩辅助作用
</span></span></code></pre></div><p>这会迅速降低 JS，却不一定产生更丰富的 TreeHeap。低 JS 只表示两个概率桶接近，不保证它们保存了更多世界结构。</p>
<p>所以预训练阶段较低的 I 有一个明确目的：</p>
<blockquote>
<p>暂时不急于统一观察角度，让 Native Butterfly 的异构折叠先参与表示形成。</p></blockquote>
<p>这不是要求预训练“没有任何归纳偏置”。TreeHeap、Butterfly、FOLD 和递归地址本身已经构成归纳偏置。这里讨论的只是不要过早追加太强的 <strong>Identity 坐标偏置</strong>。</p>
<h2 id="3-为什么任务训练才需要偏见">3. 为什么任务训练才需要偏见</h2>
<p>具体任务不是开放世界观察。中英翻译有确定的目标语言、词序和评分标准；摘要、问答和对话也各自要求特定输出协议。</p>
<p>任务训练时，模型必须回答一个更窄的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>面对这些异构内部状态，最终应该按哪套协议稳定输出？
</span></span></code></pre></div><p>此时适量 I 可能成为坐标锚点。它告诉共享 FOLD/Decoder：虽然内部可以有多种折叠视角，但任务输出必须回到可读、稳定的目标顺序。</p>
<p>因此，阶段关系可能不是“预训练和任务训练使用同一比例”，而是：</p>
$$
\lambda_I^{\mathrm{pretrain}}<\lambda_I^{\mathrm{task}}
$$<p>其中 $\lambda_I$ 表示 Identity loss 在该阶段中的有效权重。</p>
<p>直观地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>预训练：允许模型多看几种形状，不急着决定标准答案
</span></span><span style="display:flex;"><span>任务训练：告诉模型交卷时应该采用哪个视角
</span></span></code></pre></div><h2 id="4-当前数据提供了什么线索">4. 当前数据提供了什么线索</h2>
<p>C06 的 30 万行等算力对照：</p>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th style="text-align: right">Native NLL ↓</th>
          <th style="text-align: right">跨视角 JS ↓</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>额外 Butterfly（BB）</td>
          <td style="text-align: right">3.275903</td>
          <td style="text-align: right">0.242107</td>
      </tr>
      <tr>
          <td>额外 Identity（BI）</td>
          <td style="text-align: right">3.278716</td>
          <td style="text-align: right">0.104578</td>
      </tr>
  </tbody>
</table>
<p>C07 seed 9201 的 100 万行等算力对照：</p>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th style="text-align: right">Native NLL ↓</th>
          <th style="text-align: right">跨视角 JS ↓</th>
          <th style="text-align: right">chrF2 ↑</th>
          <th style="text-align: right">BLEU ↑</th>
          <th style="text-align: right">严重重复率 ↓</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>BB</td>
          <td style="text-align: right"><strong>3.176298</strong></td>
          <td style="text-align: right">0.240874</td>
          <td style="text-align: right">32.213</td>
          <td style="text-align: right">20.436</td>
          <td style="text-align: right"><strong>1.17%</strong></td>
      </tr>
      <tr>
          <td>BI</td>
          <td style="text-align: right">3.179225</td>
          <td style="text-align: right"><strong>0.082091</strong></td>
          <td style="text-align: right"><strong>32.771</strong></td>
          <td style="text-align: right"><strong>20.531</strong></td>
          <td style="text-align: right">1.95%</td>
      </tr>
  </tbody>
</table>
<p>两轮都出现了相似交换：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Native NLL 只增加约 0.0028--0.0029
</span></span><span style="display:flex;"><span>跨视角 JS 却降低约 57%--66%
</span></span></code></pre></div><p>这说明 I 是一个强而有选择性的训练信号。它不是普通的“再训练一会儿”。</p>
<p>但这些实验发生在已有双语 checkpoint 上，属于任务继续训练。它们没有比较真正的预训练阶段，因此不能证明预训练应该使用更高或更低 I。</p>
<p>这正是本文要留下的边界：</p>
<blockquote>
<p><strong>我们已经知道 I 能改变协议，但还不知道协议形成的哪个阶段最需要它。</strong></p></blockquote>
<h2 id="5-比例还要分清两种写法">5. 比例还要分清两种写法</h2>
<p>“追加 20% I”不等于最终 batch 中有 20% I。如果先保留 100% Native，再额外追加 20% I，那么 I 在全部 token 中的占比是：</p>
$$
\alpha_I=\frac{0.2}{1+0.2}=16.67\%
$$<p>后续报告必须同时记录：</p>
<ol>
<li>相对 Native 的追加剂量；</li>
<li>I 在全部训练 token 中的最终占比；</li>
<li>I 被放在预训练还是任务训练；</li>
<li>实际 optimizer step 数与 token 数。</li>
</ol>
<p>否则“20% I”在不同实验里可能代表不同的训练过程。</p>
<h2 id="6-怎样验证阶段假说">6. 怎样验证阶段假说</h2>
<p>最关键的实验不是继续扫描一个固定全程比例，而是保持总 I token、总训练 token 和更新次数一致，只移动 I 出现的阶段。</p>
<p>设两阶段合计允许 $M$ 个 Identity token，可以比较：</p>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th style="text-align: right">预训练 I</th>
          <th style="text-align: right">任务训练 I</th>
          <th style="text-align: right">总 I 剂量</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Early-I</td>
          <td style="text-align: right">$M$</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">相同</td>
      </tr>
      <tr>
          <td>Split-I</td>
          <td style="text-align: right">$M/2$</td>
          <td style="text-align: right">$M/2$</td>
          <td style="text-align: right">相同</td>
      </tr>
      <tr>
          <td>Late-I</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">$M$</td>
          <td style="text-align: right">相同</td>
      </tr>
      <tr>
          <td>No-I</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">基线</td>
      </tr>
  </tbody>
</table>
<p>每个带 I 的实验还需要同阶段 BB 等算力对照，排除“只是多训练”的解释。</p>
<p>在预训练结束和任务训练结束两个时间点分别保存 checkpoint，并测量：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Native NLL
</span></span><span style="display:flex;"><span>跨视角 JS
</span></span><span style="display:flex;"><span>chrF / BLEU
</span></span><span style="display:flex;"><span>严重重复率
</span></span><span style="display:flex;"><span>source shuffle damage
</span></span><span style="display:flex;"><span>Identity / adjacent runtime override damage
</span></span><span style="display:flex;"><span>不同长度区间的 source dependence
</span></span><span style="display:flex;"><span>固定 Dreams 的实际生成
</span></span></code></pre></div><h3 id="61-如果本文假说成立">6.1 如果本文假说成立</h3>
<p>Late-I 应该表现为：</p>
<ol>
<li>预训练结束时保留更强的 Butterfly 结构差异；</li>
<li>任务阶段加入 I 后，JS 快速下降；</li>
<li>最终 Native NLL 与生成质量优于相同总剂量的 Early-I；</li>
<li>adjacent damage 不会被过早抹平。</li>
</ol>
<h3 id="62-如果纯累计剂量解释成立">6.2 如果纯累计剂量解释成立</h3>
<p>只要总 I token 都是 $M$，Early-I、Split-I 和 Late-I 最终应该接近。I 在什么时候出现并不重要。</p>
<h3 id="63-如果相反方向成立">6.3 如果相反方向成立</h3>
<p>Early-I 可能先建立一个稳定共同协议，使后续任务训练更容易。如果它最终同时获得更低 NLL、更低 JS 和更好生成，那么“预训练低 I”假说应被否定。</p>
<h2 id="7-这条假说为什么值得先公开">7. 这条假说为什么值得先公开</h2>
<p>它提醒我们不要把当前 C07 的获胜配方直接提升成永恒架构参数。</p>
<p>Identity 更像训练课程中的药量：同一个剂量放在不同发育阶段，可能产生不同作用。预训练负责形成表示空间，任务训练负责选择输出方向；二者未必需要相同偏见。</p>
<p>当前最谨慎的结论是：</p>
<blockquote>
<p>Identity replay 已被两轮实验确认能以很小 Native 代价显著改变跨视角协议。Houming818 提出，I 的主要位置可能不是预训练，而是任务训练；这项阶段假说尚无直接证据，必须通过等总剂量、等算力的 Early-I / Late-I 实验验证。</p></blockquote>
<p>我们把它先作为开放资料发布，欢迎读者提出相反机制、实验漏洞或更节省算力的验证设计。</p>
<h2 id="8-c07-正式产品训练的最终回报">8. C07 正式产品训练的最终回报</h2>
<p>2026 年 8 月 9 日，<code>S3-TREEHEAP-BUTTERFLY-PRODUCT-C07</code> 的第一颗完整产品种子训练结束。本节不是另开一条故事线，而是把本文前面仍处于“正在执行”的 C07 补成可以审计的最终记录。</p>
<h3 id="81-这次实际训练了什么">8.1 这次实际训练了什么</h3>
<p>实验从已有双语 Butterfly checkpoint 继续训练，正式读取路径仍是 Native Butterfly，同时配置 20% Identity replay。主要平台参数如下：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>seed</td>
          <td style="text-align: right">9301</td>
      </tr>
      <tr>
          <td>语料文件可用行数</td>
          <td style="text-align: right">14,170,275</td>
      </tr>
      <tr>
          <td>epoch</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td>累计训练样本</td>
          <td style="text-align: right">62,953,195</td>
      </tr>
      <tr>
          <td>累计训练 token</td>
          <td style="text-align: right">1,331,240,167</td>
      </tr>
      <tr>
          <td>Identity replay 样本</td>
          <td style="text-align: right">2,825,717</td>
      </tr>
      <tr>
          <td>TreeHeap width</td>
          <td style="text-align: right">256</td>
      </tr>
      <tr>
          <td>state / hidden dimension</td>
          <td style="text-align: right">256 / 256</td>
      </tr>
      <tr>
          <td>单卡墙钟时间</td>
          <td style="text-align: right">52.6 小时</td>
      </tr>
  </tbody>
</table>
<p>这里的“20%”是训练程序的 replay 配置值，不应该被误读为最终所有 token 中恰好有 20% 来自 Identity。实验另外记录了真实 replay 样本和 token，后续做剂量比较时必须使用真实计数，而不能只比较配置名称。</p>
<h3 id="82-nll-确实下降而且测试集没有突然崩掉">8.2 NLL 确实下降，而且测试集没有突然崩掉</h3>
<table>
  <thead>
      <tr>
          <th>评价位置</th>
          <th style="text-align: right">EN→ZH NLL ↓</th>
          <th style="text-align: right">ZH→EN NLL ↓</th>
          <th style="text-align: right">Mean NLL ↓</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>启动时 validation</td>
          <td style="text-align: right">-</td>
          <td style="text-align: right">-</td>
          <td style="text-align: right">3.588437</td>
      </tr>
      <tr>
          <td>最终 / 最佳 validation</td>
          <td style="text-align: right">3.173284</td>
          <td style="text-align: right">2.659531</td>
          <td style="text-align: right"><strong>2.916408</strong></td>
      </tr>
      <tr>
          <td>held-out test，Native Butterfly</td>
          <td style="text-align: right">3.199092</td>
          <td style="text-align: right">2.746413</td>
          <td style="text-align: right"><strong>2.972753</strong></td>
      </tr>
      <tr>
          <td>held-out test，运行时改成 Identity</td>
          <td style="text-align: right">3.330987</td>
          <td style="text-align: right">2.906930</td>
          <td style="text-align: right">3.118958</td>
      </tr>
  </tbody>
</table>
<p>从启动到最终验证点，Mean NLL 下降了 <code>0.672029</code>，相对约为 <strong>18.7%</strong>。测试 NLL 比最佳验证 NLL 高 <code>0.056345</code>，约为 <strong>1.9%</strong>。这说明本轮长训练不是只把训练样本背下来后在测试集上立即失效。</p>
<p>更关键的是运行时干预。保持同一个 checkpoint、同一批测试数据和同一个 Decoder，只把 Native Butterfly 坐标变换替换成 Identity，测试 NLL 增加：</p>
$$
\Delta L_{\mathrm{identity}}
=3.118958-2.972753
=0.146205
$$<p>这个结果支持一个有限而重要的判断：<strong>模型确实利用了 Native Butterfly 产生的结构状态。</strong> 如果 Butterfly 只是没有作用的外壳，运行时拿掉它不应该稳定增加测试损失。</p>
<p>但这项干预只能证明结构参与了预测，不能证明我们已经理解每个内部节点保存了什么，也不能证明模型已经获得逻辑推理能力。</p>
<h3 id="83-dreams-告诉我们的另一半事实">8.3 <code>dreams</code> 告诉我们的另一半事实</h3>
<p>只看 NLL，会把这轮结果说得过于乐观。最后一个固定样本集 <code>step-000062953195.txt</code> 显示，模型已经摆脱了早期“无论输入什么都只说一带一路”的全局条件坍缩，但仍没有成为可靠的翻译器。</p>
<p>有些信息保存得比较好。例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：传感器记录到37.6摄氏度和82%的湿度。
</span></span><span style="display:flex;"><span>输出：The recorder 37.6 degrees Celsius, 82% humidity.
</span></span></code></pre></div><p>数字、单位和主要对象大体保留。下面这条指令也没有被当作问题直接回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：请把这句话翻译成英文，而不是回答其中的问题：为什么鲨鱼不坐沙发？
</span></span><span style="display:flex;"><span>输出：Please put this word into English translation, not answer the question:
</span></span><span style="display:flex;"><span>      why sharks not to sit in the sofa?
</span></span></code></pre></div><p>虽然英语并不自然，但任务方向和大部分内容仍在。</p>
<p>真正的失败集中在关系和逻辑对照上。</p>
<table>
  <thead>
      <tr>
          <th>对照输入</th>
          <th>最终输出摘要</th>
          <th>观察</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>The doctor thanked the farmer.</td>
          <td>医生的感谢</td>
          <td>主体和客体没有完整落地</td>
      </tr>
      <tr>
          <td>The farmer thanked the doctor.</td>
          <td>医生的感谢，医生</td>
          <td>交换论元后输出没有相应交换</td>
      </tr>
      <tr>
          <td>Every lamp &hellip; / Not every lamp &hellip;</td>
          <td>两句都接近“灯台上的灯台上”</td>
          <td>否定与全称量词没有稳定区分</td>
      </tr>
      <tr>
          <td>before the door opened / after the door opened</td>
          <td>两句都生成门铃、敲门声</td>
          <td>前后时序没有可靠坍缩</td>
      </tr>
  </tbody>
</table>
<p>长句能够留下事件轮廓。例如水泵样本仍保留了“自动启动、红色标记、两个压力传感器、30 秒”等成分；但条件层级、论元归属和句法顺序仍会错位。</p>
<p>因此，最终 dreams 呈现的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>全局固定句坍缩：明显缓解
</span></span><span style="display:flex;"><span>词汇与局部事件轮廓：已经出现
</span></span><span style="display:flex;"><span>局部重复：仍然存在
</span></span><span style="display:flex;"><span>主体/客体、否定、时序、数量关系：仍不可靠
</span></span><span style="display:flex;"><span>产品级翻译：未达到
</span></span></code></pre></div><h3 id="84-为什么-nll-下降句子却不一定同步变好">8.4 为什么 NLL 下降，句子却不一定同步变好</h3>
<p>NLL 奖励的是“给参考 token 更高概率”。训练语料中，高频搭配、常见句式和局部续写占据了大量梯度；主体交换、否定翻转和前后时序这种关键对照，在总体 token 数中所占比例很小。</p>
<p>所以模型可以通过改善大量普通位置继续降低平均 NLL，却仍在少量决定句意的关系位置上犯错。固定 dreams 的人工观察还表明：随着后期 NLL 继续下降，个别句子的语义质量并不单调改善。</p>
<p>这不否定交叉熵训练，但说明产品验收不能只有一个总体 NLL。下一轮至少需要同时报告：</p>
<ol>
<li>chrF、BLEU 或其他完整翻译指标；</li>
<li>主客体交换、否定、时序和数量的成对对照准确率；</li>
<li>重复率与生成长度；</li>
<li>Native / Identity 运行时干预损失；</li>
<li>固定 dreams 在多个训练时点的实际文本。</li>
</ol>
<h3 id="85-本轮可以支持什么仍然不能支持什么">8.5 本轮可以支持什么，仍然不能支持什么</h3>
<p><strong>当前得到支持：</strong></p>
<ol>
<li>该 TreeHeap 配方可以在单张 3090 上稳定完成十亿 token 量级训练；</li>
<li>验证 NLL 持续下降，最终测试集没有出现严重泛化断裂；</li>
<li>Native Butterfly 在 held-out test 上具有可测量的因果贡献；</li>
<li>少量 Identity replay 可以进入正式训练流程，而没有让 Native 路径数值崩溃。</li>
</ol>
<p><strong>仍然开放：</strong></p>
<ol>
<li>Early-I、Split-I、Late-I 哪个阶段安排最好；</li>
<li>当前收益来自 Identity 的出现时机、累计剂量，还是两者共同作用；</li>
<li>TreeHeap 是否已经形成可以稳定处理论元、否定和时序的私有协议；</li>
<li>当前模型能否达到可用的翻译产品标准。</li>
</ol>
<p>因此，C07 完成后，本文标题中的“阶段假说”仍然是 <strong>open</strong>，而不是 supported。C07 给出了可靠的长训练基线和结构参与证据，却没有执行等剂量的 Early-I / Late-I 因果比较，也没有通过最终的语言能力验收。</p>
<p>完整 Claim、代码与 Evidence 位于 <a href="https://github.com/houming818/sametime">SameTime 开放仓库</a>。</p>
<hr>
<p><strong>License:</strong> GPLv3。本文公开阶段剂量假说、反证条件与实验设计，可自由复现、审计和修改。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-084] 预训练成功迁移，STOP 却没有学会停止：TreeHeap C10 最近进展审计</title>
      <link>https://www.grepcode.cn/spr/084-treeheap-c10-pretrain-stop-audit.html</link>
      <pubDate>Wed, 12 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/084-treeheap-c10-pretrain-stop-audit.html</guid>
      <description>TreeHeap C10 完成自然语料预训练、WMT 迁移与三轮读取审计：预训练带来明确收益，但递归 READ 退化成了 Butterfly 变换后的叶层软池化。</description>
      <content:encoded><![CDATA[<h1 id="最近航到了哪里">最近航到了哪里</h1>
<p>距离上一篇公开进展已经有一段时间。这期间我们没有继续堆更多概念，而是把一个完整训练管线跑通，然后反过来审计模型到底学会了什么。</p>
<p>这次的 C10 管线分三步：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>自然语料预训练
</span></span><span style="display:flex;"><span>    -&gt; 同样的 TreeHeap checkpoint 进入 WMT 中英任务训练
</span></span><span style="display:flex;"><span>    -&gt; 用概率后验、路径干预和 STOP 分辨率实验做 proof check
</span></span></code></pre></div><p>结果不是简单的成功或失败，而是两个同时成立的事实：</p>
<ol>
<li><strong>预训练确实把可迁移信息写进了 TreeHeap 参数。</strong></li>
<li><strong>递归 Decoder 没有学成我们期待的多分辨率读取协议，而是几乎把全部概率质量送到了 leaf。</strong></li>
</ol>
<p>这两个结果并不矛盾。模型可以学到有用信息，却通过一条比预期更浅的读出路径使用它。</p>
<h2 id="1-c10-实际训练了什么">1. C10 实际训练了什么</h2>
<p>C10 不是 Transformer，也不是把一个矩阵改名为 TreeHeap。模型合同记录为：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th style="text-align: right">配置</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>模型类</td>
          <td style="text-align: right"><code>ButterflyRecursive</code></td>
      </tr>
      <tr>
          <td>参数量</td>
          <td style="text-align: right">34,448,396</td>
      </tr>
      <tr>
          <td>state / hidden</td>
          <td style="text-align: right">256 / 256</td>
      </tr>
      <tr>
          <td>最大 heap width</td>
          <td style="text-align: right">256</td>
      </tr>
      <tr>
          <td>地址通信</td>
          <td style="text-align: right">XOR Butterfly</td>
      </tr>
      <tr>
          <td>FOLD</td>
          <td style="text-align: right">learned lifting</td>
      </tr>
      <tr>
          <td>READ</td>
          <td style="text-align: right">recursive probability container</td>
      </tr>
      <tr>
          <td>生成器</td>
          <td style="text-align: right">GRU 自回归 Decoder</td>
      </tr>
  </tbody>
</table>
<p>数据首先写到 leaf。Butterfly 按地址执行可逆的信息交换，然后 learned lifting 逐层把左右子节点合成为 parent，同时保存 detail。Decoder 再从 root 开始，通过 STOP 和左右分支概率读取不同深度的节点。</p>
<p>因此需要分清三个问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>问题 A：H_state 里有没有学到信息？
</span></span><span style="display:flex;"><span>问题 B：Butterfly 和 FOLD 是否真的参与了计算？
</span></span><span style="display:flex;"><span>问题 C：READ 是否学会了有意义的分层读取？
</span></span></code></pre></div><p>最近实验给出的答案分别是：<strong>有、参与了、没有学成。</strong></p>
<h2 id="2-预训练迁移是明确的正结果">2. 预训练迁移是明确的正结果</h2>
<p>预训练阶段读取 <code>/home/nio/datasets/pretrain</code> 的自然语料，并混入 25% 的 WMT 单语文本。模型训练了约一亿 token：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>pretrain steps</td>
          <td style="text-align: right">97,657</td>
      </tr>
      <tr>
          <td>pretrain tokens</td>
          <td style="text-align: right">100,000,768</td>
      </tr>
      <tr>
          <td>初始 valid NLL</td>
          <td style="text-align: right">10.7237</td>
      </tr>
      <tr>
          <td>最佳 valid NLL</td>
          <td style="text-align: right">5.6804</td>
      </tr>
      <tr>
          <td>墙钟时间</td>
          <td style="text-align: right">4.85 小时</td>
      </tr>
  </tbody>
</table>
<p>随后我们构造两条完全等算力的 WMT 任务训练臂：</p>
<ul>
<li><code>PT</code>：从预训练 checkpoint 开始；</li>
<li><code>SC</code>：从相同初始随机状态直接学习 WMT。</li>
</ul>
<p>两条任务臂使用相同的数据流哈希、25,000 step 和 20,198,612 个任务 token。</p>
<table>
  <thead>
      <tr>
          <th>任务结果</th>
          <th style="text-align: right">PT，预训练后</th>
          <th style="text-align: right">SC，从零训练</th>
          <th style="text-align: right">PT 改善</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>test NLL，越低越好</td>
          <td style="text-align: right"><strong>5.4037</strong></td>
          <td style="text-align: right">6.2920</td>
          <td style="text-align: right">-0.8883</td>
      </tr>
      <tr>
          <td>token BLEU4，越高越好</td>
          <td style="text-align: right"><strong>5.0654</strong></td>
          <td style="text-align: right">1.1711</td>
          <td style="text-align: right">+3.8943</td>
      </tr>
  </tbody>
</table>
<p>这组比较可以支持一个有限 Claim：</p>
<blockquote>
<p>在相同 WMT 训练预算下，先用自然语料预训练的 TreeHeap 比从零开始更快得到较低的测试 NLL 和较高的 token BLEU。</p></blockquote>
<p>它不能证明模型已经会可靠翻译。实际生成仍有错译、重复和关系混乱。这里证明的是<strong>协议可以迁移</strong>，不是产品已经完成。</p>
<h2 id="3-后验-proof-看到了条件信息但信号仍弱">3. 后验 proof 看到了条件信息，但信号仍弱</h2>
<p>我们又比较了模型给出的下一 token 概率桶与语料经验分布。</p>
<table>
  <thead>
      <tr>
          <th>模式</th>
          <th style="text-align: right">JS，越低越接近语料</th>
          <th style="text-align: right">候选集合概率质量，越高越好</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Native source</td>
          <td style="text-align: right"><strong>0.6094</strong></td>
          <td style="text-align: right"><strong>0.0620</strong></td>
      </tr>
      <tr>
          <td>Wrong source</td>
          <td style="text-align: right">0.6380</td>
          <td style="text-align: right">0.0388</td>
      </tr>
      <tr>
          <td>Unigram baseline</td>
          <td style="text-align: right">0.6410</td>
          <td style="text-align: right">0.0333</td>
      </tr>
  </tbody>
</table>
<p>换错 source 后，78.6% 的 greedy token 发生改变；破坏最底层左右配对后，58.3% 的 greedy token 发生改变。模型不是完全无视输入，也不只是复读全局最高频逗号。</p>
<p>但 <code>0.6094</code> 距离理想分布仍然很远，候选质量也不高。它更适合被描述为“已经出现 source-conditioned signal”，还不能写成“形成了完整世界模型”。</p>
<h2 id="4-真正的问题出在-read">4. 真正的问题出在 READ</h2>
<p>TreeHeap 的编码方向是从 leaf 向 root：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token leaves
</span></span><span style="display:flex;"><span>    -&gt; Butterfly 地址通信
</span></span><span style="display:flex;"><span>    -&gt; FOLD：leaf -&gt; parent -&gt; root
</span></span><span style="display:flex;"><span>    -&gt; 得到 root + 多层 details
</span></span></code></pre></div><p>生成时的读取方向相反：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>    -&gt; 判断 STOP，或继续到 child
</span></span><span style="display:flex;"><span>    -&gt; 左右分支分配概率
</span></span><span style="display:flex;"><span>    -&gt; 直到某个深度停止
</span></span><span style="display:flex;"><span>    -&gt; 形成 context，送给 GRU Decoder
</span></span></code></pre></div><p>当前 STOP 不是硬开关。对到达节点的概率质量 <code>a</code>，程序计算：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>stop_mass     = a * sigmoid(stop_logit)
</span></span><span style="display:flex;"><span>continue_mass = a * (1 - sigmoid(stop_logit))
</span></span></code></pre></div><p>只要 <code>stop_logit</code> 是有限数，sigmoid 就不会严格等于 0 或 1。程序也没有“低于某个数就视为停止”的观察精度。到达 leaf 后，才被强制全部停止。</p>
<p>C10 在训练早期就把内部 STOP 压到了近乎零。第 1,000 step 时，约 99.9936% 的读取质量已经到达 leaf；最终测试时，平均 leaf 质量约为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0.9999999963
</span></span></code></pre></div><p>也就是说，数学上还有极小的中间层尾巴，工程上却已经等于一路走到底。</p>
<h2 id="5-强制-leaf-后模型几乎完全不变">5. 强制 leaf 后，模型几乎完全不变</h2>
<p>我们在 256 条 held-out WMT 样本、5,226 个目标 token 上做了运行时干预。checkpoint 和所有参数保持不变，只改读取方式。</p>
<table>
  <thead>
      <tr>
          <th>READ 干预</th>
          <th style="text-align: right">NLL</th>
          <th style="text-align: right">相对 Native 变化</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Native learned STOP</td>
          <td style="text-align: right">5.299829634</td>
          <td style="text-align: right">0</td>
      </tr>
      <tr>
          <td>Force leaf</td>
          <td style="text-align: right">5.299829704</td>
          <td style="text-align: right">+0.000000070</td>
      </tr>
      <tr>
          <td>Uniform branch</td>
          <td style="text-align: right">5.403492</td>
          <td style="text-align: right">+0.103662</td>
      </tr>
      <tr>
          <td>Runtime Identity，拿掉 Butterfly</td>
          <td style="text-align: right">5.660286</td>
          <td style="text-align: right">+0.360457</td>
      </tr>
      <tr>
          <td>Break depth-0 pair</td>
          <td style="text-align: right">5.690986</td>
          <td style="text-align: right">+0.391156</td>
      </tr>
  </tbody>
</table>
<p><code>Native</code> 与 <code>Force leaf</code> 在数值误差范围内相同。这说明 learned STOP 实际已经等价于 leaf-only read。</p>
<p>另一方面，拿掉 Butterfly 或打乱最底层 FOLD 配对会明显增加 NLL。这说明结构变换仍然改变了 leaf 内容，不能说整个网络只是未经处理的原始数组。</p>
<p>最精确的描述是：</p>
<blockquote>
<p>C10 学到的是“经过 Butterfly/FOLD 结构变换的叶层读出”，不是“能在 root、parent 与 leaf 之间按语义选择分辨率的 TreeHeap READ”。</p></blockquote>
<h2 id="6-它是不是只沿一条链表路径读取">6. 它是不是只沿一条链表路径读取</h2>
<p>Houming818 随后提出了一个重要反问：既然都走到 leaf，会不会只剩一条固定路径，TreeHeap 退化成了一条链表？</p>
<p>我们没有靠猜测回答，而是重建每个生成 step 的 leaf 权重，并逐级裁剪。</p>
<p>如果它真是一条单路径，Top-1 leaf 应该占据绝大部分概率，保留 Top-1 后 NLL 也不应明显变差。实验却得到：</p>
<table>
  <thead>
      <tr>
          <th>读取叶集合</th>
          <th style="text-align: right">覆盖的平均概率质量</th>
          <th style="text-align: right">NLL 增量</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Top-1</td>
          <td style="text-align: right">21.04%</td>
          <td style="text-align: right">+4.0048</td>
      </tr>
      <tr>
          <td>Top-2</td>
          <td style="text-align: right">33.69%</td>
          <td style="text-align: right">+1.5362</td>
      </tr>
      <tr>
          <td>Top-4</td>
          <td style="text-align: right">51.10%</td>
          <td style="text-align: right">+0.5050</td>
      </tr>
      <tr>
          <td>Top-8</td>
          <td style="text-align: right">72.22%</td>
          <td style="text-align: right">+0.1383</td>
      </tr>
      <tr>
          <td>删除 Top-1</td>
          <td style="text-align: right">其余质量</td>
          <td style="text-align: right">+0.0829</td>
      </tr>
  </tbody>
</table>
<p>单路径假说因此被否定。有效 leaf 数约为 15.85，每条样本在生成过程中平均出现 6.72 个不同的 argmax leaf，地址平均跳跃 6.30 格。它不是顺序游标，也不是只盯着一个 leaf。</p>
<p>可是另一个结果同样重要：把所有有效 leaf 改成均匀平均，NLL 只增加 <code>0.0271</code>；逐层把左右分支改成均匀分配，大部分 NLL 变化也只有千分位。</p>
<p>所以它也没有形成强而清晰的“语义树索引”。当前更像下面这个过程：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Butterfly/FOLD 改写 leaf state
</span></span><span style="display:flex;"><span>    -&gt; READ 把很多 leaf 分配一个较宽、较弱的概率桶
</span></span><span style="display:flex;"><span>    -&gt; 加权求和为 context
</span></span><span style="display:flex;"><span>    -&gt; GRU 根据 context 逐 token 生成
</span></span></code></pre></div><p>若第 <code>i</code> 个变换后 leaf 是 <code>L_i</code>，第 <code>t</code> 个生成 step 的读权重是 <code>alpha_ti</code>，那么 context 可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>c_t = sum_i(alpha_ti * L_i)
</span></span></code></pre></div><p>这就是本文所说的 <strong>leaf pooling</strong>。它不是“所有 leaf 都相同”，而是“Decoder 主要在叶层对许多 leaf 做软加权”。</p>
<h2 id="7-观察者分辨率假说解决了哪一部分">7. 观察者分辨率假说，解决了哪一部分</h2>
<p>Houming818 提出了一个很具体的物理类比：</p>
<blockquote>
<p>现实中的停止不要求光通量严格等于零。只要信号低于观察者能够分辨的极限，工程上就应该把它当作零。</p></blockquote>
<p>我们据此加入一个不训练参数的诊断规则：如果某条活动路径的质量小于等于 <code>epsilon</code>，就在当前节点停止，不再展开它的两个孩子。</p>
<p>第一次 smoke 因统计张量发生别名污染而产生不可能的质量总和，我们将该结果作废，并重新执行。有效重跑覆盖 128 条 held-out WMT 样本和 2,532 个 token。</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">epsilon</th>
          <th style="text-align: right">NLL 增量</th>
          <th style="text-align: right">少访问的节点</th>
          <th style="text-align: right">仍到达 leaf 的质量</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0%</td>
          <td style="text-align: right">99.999999%</td>
      </tr>
      <tr>
          <td style="text-align: right">0.0001</td>
          <td style="text-align: right">+0.000057</td>
          <td style="text-align: right">6.23%</td>
          <td style="text-align: right">99.999262%</td>
      </tr>
      <tr>
          <td style="text-align: right">0.001</td>
          <td style="text-align: right">+0.001791</td>
          <td style="text-align: right">8.24%</td>
          <td style="text-align: right">99.987412%</td>
      </tr>
      <tr>
          <td style="text-align: right">0.003</td>
          <td style="text-align: right">+0.010178</td>
          <td style="text-align: right">10.11%</td>
          <td style="text-align: right">99.932139%</td>
      </tr>
      <tr>
          <td style="text-align: right">0.01</td>
          <td style="text-align: right">+0.069846</td>
          <td style="text-align: right">14.06%</td>
          <td style="text-align: right">99.495583%</td>
      </tr>
  </tbody>
</table>
<p>这个实验支持一半，也否定一半：</p>
<ol>
<li><strong>支持</strong>：有限观察精度可以安全剪掉一部分数学上非零、实际贡献极小的尾路径。</li>
<li><strong>未通过正式门槛</strong>：没有一个点同时达到“至少省 10% 节点”且“NLL 增量不超过 0.001”。</li>
<li><strong>否定充分性</strong>：即使 <code>epsilon=0.003</code>，仍有 99.93% 的质量到达 leaf。阈值能清理尾巴，却不能把主流量抬回 parent。</li>
</ol>
<p>因此，C10 同时存在两个现象：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>现象一：sigmoid 产生了永不严格归零的数值尾巴
</span></span><span style="display:flex;"><span>现象二：训练本身把绝大部分有效质量送到了 leaf
</span></span></code></pre></div><p>观察者分辨率解决的是第一个问题，不是第二个。</p>
<h2 id="8-现在到底可以声明什么">8. 现在到底可以声明什么</h2>
<h3 id="已有证据支持">已有证据支持</h3>
<ol>
<li>自然语料预训练可以迁移到同一 TreeHeap 的 WMT 任务训练；</li>
<li>Butterfly 地址通信和 FOLD 配对对 held-out NLL 有可测量的因果作用；</li>
<li>source、错误 source 与配对破坏会改变概率后验；</li>
<li>有限分辨率可以剪掉 6% 到 10% 的低质量路径，代价可测量。</li>
</ol>
<h3 id="已被当前证据否定">已被当前证据否定</h3>
<ol>
<li>C10 的 Native READ 不是有效的多分辨率 STOP 协议；</li>
<li>它不是只沿一条固定链表路径读取；</li>
<li>单纯增加一个小阈值，不能把 leaf collapse 修成语义分层读取。</li>
</ol>
<h3 id="仍然开放">仍然开放</h3>
<ol>
<li>如何让内部节点在任务 loss 中获得不可替代的价值；</li>
<li>STOP 如何在不依赖手写固定深度的情况下学会有限分辨率；</li>
<li>root、parent、detail 与 leaf 能否形成稳定的私有编解码协议；</li>
<li>这种协议能否最终改善完整翻译与逻辑对照，而不只是降低平均 NLL。</li>
</ol>
<h2 id="9-下一步不再盲目加训练时间">9. 下一步不再盲目加训练时间</h2>
<p>C10 已经说明，单纯继续喂更多 token 可能只会把 leaf-only 读法训练得更熟。下一步首先要做的是一个等数据、等 step 的形成机制实验，而不是直接再开一次长训练。</p>
<p>最小实验应比较：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A. 当前自由 soft STOP
</span></span><span style="display:flex;"><span>B. 训练时加入有限观察分辨率，但不指定固定停止深度
</span></span><span style="display:flex;"><span>C. 在训练中随机限制可见最大深度，检查内部节点能否获得可读信息
</span></span></code></pre></div><p>三条臂都要同时报告：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>任务 NLL 与完整生成质量
</span></span><span style="display:flex;"><span>每层 stop mass
</span></span><span style="display:flex;"><span>force-depth 因果损失
</span></span><span style="display:flex;"><span>uniform-leaf 与 Top-K leaf 损失
</span></span><span style="display:flex;"><span>Butterfly / pair-break 损失
</span></span><span style="display:flex;"><span>实际节点访问量
</span></span></code></pre></div><p>其中 C 不是最终架构承诺，只是诊断压力：如果内部节点在被迫读取后仍学不到有用信息，问题可能在 FOLD state；如果能学到，问题则主要在自由优化器总能选择更容易的 leaf 路径。</p>
<h2 id="10-一句话进展">10. 一句话进展</h2>
<blockquote>
<p>我们已经证明 TreeHeap 能从自然语料获得可迁移参数，也证明 Butterfly/FOLD 确实参与预测；但 C10 的自由 STOP 没有形成多分辨率私有协议，而是退化为对变换后 leaf 的宽分布软池化。观察者分辨率能剪尾，不能独自纠正主流量。下一阶段的核心已从“再训练多久”变成“什么形成条件能让 parent 真正值得被读取”。</p></blockquote>
<p>ARA 设计、代码和结构化 Evidence 将继续整理到 <a href="https://github.com/houming818/sametime/tree/main/ara/s3-generation">SameTime 开放仓库</a>。所有失败路径保留，不用事后改写故事。</p>
<hr>
<p><strong>License:</strong> GPLv3。本文中的 Claim、反证条件、实验过程与数据可自由复现、审计和修改。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-085] 能量守恒不等于学习压力守恒：TreeHeap FOLD 的隐藏梯度功能</title>
      <link>https://www.grepcode.cn/spr/085-treeheap-fold-energy-and-gradient-pressure.html</link>
      <pubDate>Mon, 24 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/085-treeheap-fold-energy-and-gradient-pressure.html</guid>
      <description>TreeHeap 为递归 FOLD 增加能量载体并完成 toy 与真实 checkpoint 双重审计。候选修复了人工抵消奇点，却在真实文本中暴露出更强的长深度梯度衰减，因此没有进入训练。</description>
      <content:encoded><![CDATA[<h1 id="一个看起来理所当然的问题">一个看起来理所当然的问题</h1>
<p>最近我们重新检查 TreeHeap 的多分辨率退火 FOLD。问题从一句很简单的追问开始：</p>
<blockquote>
<p>左右子树在同一层合并时，为什么使用平方和，而不是像某些物理变换那样使用乘法？</p></blockquote>
<p>这次追问最后揭开了两个不同的问题：</p>
<ol>
<li>同一层的两个状态怎样组成一个 parent；</li>
<li>一个子树的绝对尺度怎样沿递归地址传播。</li>
</ol>
<p>第一件事适合使用平方和。第二件事确实可以使用乘法，但应该乘的是无量纲的路径比例，而不是直接把左右能量相乘。</p>
<p>我们为此实现了一个新的递归能量载体，先在人工树上成功修复梯度爆炸，再把它带到训练后的真实 TreeHeap checkpoint 上审计。最后的决定却是：<strong>暂时不要把新公式放进训练。</strong></p>
<p>原因不是候选算错了，而是它修复的病灶没有出现在当前真实数据中，同时它削弱了另一个此前没有被单独披露的功能：当前 FOLD 会在每一层重新归一化，因而隐式补偿递归深度带来的梯度衰减。</p>
<p>这项功能不是我们刻意隐藏的。恰恰相反，直到这次正反对照完成，我们才确认它一直存在于公式中。</p>
<h2 id="1-当前-fold-到底做了什么">1. 当前 FOLD 到底做了什么</h2>
<p>设左右子节点相对零点的状态为 $a$ 和 $b$。当前零点参考系 FOLD 计算：</p>
$$
s=\sqrt{\lVert a\rVert^2+\lVert b\rVert^2+\varepsilon}
$$$$
P=\frac{a+b}{\sqrt{2}s}
$$$$
D=\frac{b-a}{\sqrt{2}s}
$$<p>其中：</p>
<ul>
<li>$P$ 是继续向 root 递归的 parent；</li>
<li>$D$ 是保存左右差异的 detail；</li>
<li>$s$ 是本层保存的尺度；</li>
<li>当前实现取 $\varepsilon=10^{-8}$。</li>
</ul>
<p>只要同时保留 $P,D,s$，就能恢复左右状态：</p>
$$
a=\frac{s(P-D)}{\sqrt{2}}
$$$$
b=\frac{s(P+D)}{\sqrt{2}}
$$<p>所以这个变换在连续数值上是可逆的。它还有一个直接的前向性质：分子变大时，分母也随之变大，因此 parent norm 被限制在有限范围。</p>
<p>但这里容易产生一个误会：</p>
<blockquote>
<p>前向状态有界，不代表反向梯度也有界。</p></blockquote>
<p>反向传播关心的是 parent 对输入变化的敏感度。Jacobian 中包含近似的 $1/s$。当某层输入尺度非常小时，微小变化会被放大。</p>
<h2 id="2-人工树第一次暴露了近奇异点">2. 人工树第一次暴露了近奇异点</h2>
<p>我们先构造 8 个 leaf：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[a, -a, a, -a, a, -a, a, -a]
</span></span></code></pre></div><p>第一层每对强信号都精确抵消：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>a + (-a) = 0
</span></span></code></pre></div><p>第一层的 detail 和 scale 仍然保存了信息，因此 UNFOLD 可以精确恢复。但是只有 parent 会继续向上参加下一层 FOLD。下一层看到的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[0, 0, 0, 0]
</span></span></code></pre></div><p>此时新的局部尺度只能落到：</p>
$$
s=\sqrt{\varepsilon}=10^{-4}
$$<p>连续两层 Jacobian 中的 $1/s$ 相乘，理论量级接近 $10^8$。float64 toy 的实际 root-to-leaf 梯度 norm 为：</p>
<table>
  <thead>
      <tr>
          <th>输入</th>
          <th style="text-align: right">当前 FOLD 梯度 norm</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>所有 leaf 同向</td>
          <td style="text-align: right">0.34761</td>
      </tr>
      <tr>
          <td>正负交替、精确抵消</td>
          <td style="text-align: right">70,710,677.94</td>
      </tr>
  </tbody>
</table>
<p>与此同时，parent 仍然有界，FOLD/UNFOLD 最大闭包误差只有约 $4.3\times10^{-14}$。这里必须把两个指标严格分开：</p>
$$
e_{closure}=\left\lVert\operatorname{UNFOLD}(\operatorname{FOLD}(x))-x\right\rVert_\infty
$$<p>衡量的是：把同一次 FOLD 保存下来的 $P,D,s$ 全部交还给 UNFOLD，原输入能否恢复。它是一项<strong>当前点上的代数闭包检查</strong>。</p>
<p>而梯度实验衡量的是：</p>
$$
g=\left\lVert\frac{\partial\,\operatorname{root}(x)}{\partial x}\right\rVert
$$<p>它描述的是：输入在当前点附近稍微移动，root 会移动多快。这是一项<strong>邻域敏感度检查</strong>。文中的“爆炸”指 $g$ 爆炸，不是 parent 数值爆炸，也不是 $e_{closure}$ 爆炸。</p>
<p>一个最简单的类比是 $y=10^8x$：在 $x=0$ 时，$y$ 仍然等于 0；若同时保存逆变换，$x=y/10^8$ 也能精确还原。但它的导数仍然是 $10^8$。在本次正负交替 toy 中，把第一个 leaf 从 $1$ 改为 $1+10^{-10}$，scalar root 会从 0 移动到约 $2.5\times10^{-3}$，局部放大约 $2.5\times10^7$。这才是巨大梯度对应的实际含义。</p>
<p>因此，闭包误差很小并不反驳梯度爆炸。相反，两者同时出现，说明这个变换<strong>可逆但条件很差</strong>。这说明三件事可以同时成立：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>前向状态值不爆炸
</span></span><span style="display:flex;"><span>携带完整 P、D、s 时可以精确还原
</span></span><span style="display:flex;"><span>root 对 leaf 的反向梯度仍然可能病态
</span></span></code></pre></div><h2 id="3-新候选让节点携带绝对能量">3. 新候选：让节点携带绝对能量</h2>
<p>当前算法会保存每层的 $s$，但保存它只是为了以后 UNFOLD。下一层 FOLD 只接收 $P$，并不知道这个零是“没有信号”，还是“两个强信号抵消形成的零”。</p>
<p>新候选让每个节点携带二元状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>(u, E)
</span></span></code></pre></div><p>其中 $u$ 是归一化方向，$E$ 是该子树的绝对能量。leaf 初始化为：</p>
$$
E_{leaf}=\sqrt{\lVert x\rVert^2+\varepsilon}
$$$$
u_{leaf}=\frac{x}{E_{leaf}}
$$<p>左右子树合并时，同层能量仍然使用平方和：</p>
$$
E_P=\sqrt{E_L^2+E_R^2}
$$<p>方向和差异则计算为：</p>
$$
P=\frac{E_Lu_L+E_Ru_R}{\sqrt{2}E_P}
$$$$
D=\frac{E_Ru_R-E_Lu_L}{\sqrt{2}E_P}
$$<p>这样，即使 $P=0$，上层仍然知道 $E_P$ 很大。</p>
<p>乘法出现在纵向地址传播。定义无量纲比例：</p>
$$
r_{child}=\frac{E_{child}}{E_{parent}}
$$<p>沿一条 root-to-leaf 路径：</p>
$$
E_{leaf}=E_{root}\prod_{d=1}^{D}r_d
$$<p>所以，更准确的规则是：</p>
<blockquote>
<p>同层左右合并使用平方和，跨层地址上的相对尺度使用乘法。</p></blockquote>
<h2 id="4-为什么不能直接把左右能量相乘">4. 为什么不能直接把左右能量相乘</h2>
<p>我们还实现了一条直接乘法反例：</p>
$$
s_{product}=\sqrt{\lVert a\rVert\lVert b\rVert+\varepsilon}
$$<p>它在左右能量接近时看起来正常，却会在能量失衡时破坏 parent 有界性。</p>
<table>
  <thead>
      <tr>
          <th>输入</th>
          <th style="text-align: right">直接乘法的最大 parent norm</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>左右幅度 100 与 0.01</td>
          <td style="text-align: right">70.71775</td>
      </tr>
      <tr>
          <td>一侧正常、一侧为零</td>
          <td style="text-align: right">7,071.0678</td>
      </tr>
  </tbody>
</table>
<p>问题很直观：一侧为零时，乘积也为零，分母重新落到 $\sqrt{\varepsilon}$，而另一侧的强信号仍留在分子中。</p>
<p>乘法不是不能用，而是不能用在量纲不合适的位置。</p>
<h2 id="5-toy-上新候选成功了">5. toy 上，新候选成功了</h2>
<p>同样的正负交替树上，递归能量载体得到：</p>
<table>
  <thead>
      <tr>
          <th>输入</th>
          <th style="text-align: right">当前 FOLD</th>
          <th style="text-align: right">能量载体 FOLD</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>同向 leaf 梯度</td>
          <td style="text-align: right">0.34761</td>
          <td style="text-align: right">0.34761</td>
      </tr>
      <tr>
          <td>抵消 leaf 梯度</td>
          <td style="text-align: right">70,710,677.94</td>
          <td style="text-align: right"><strong>0.35355</strong></td>
      </tr>
  </tbody>
</table>
<p>新候选同时满足：</p>
<ul>
<li>parent 有界；</li>
<li>FOLD/UNFOLD 闭包误差约 $2.8\times10^{-14}$；</li>
<li>root-to-leaf 路径能量乘法重建误差为 0；</li>
<li>抵消时的梯度回到正常输入同一数量级。</li>
</ul>
<p>如果研究在这里停止，我们很容易得出一个漂亮但危险的结论：新候选已经修好了当前 FOLD。</p>
<p>于是我们继续做了真实 checkpoint 审计。</p>
<h2 id="6-真实数据中病灶根本没有出现">6. 真实数据中，病灶根本没有出现</h2>
<p>我们冻结 <code>S3-STONE2-INTEGRATED-C03</code> 的 pretrain checkpoint，使用它训练后的 token embedding 和 Native XOR Butterfly 输出。数据不是重新编造的 toy，而是 224 个真实自然文本验证窗口：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">source width</th>
          <th style="text-align: right">样本数</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">4 / 8 / 16 / 32 / 64 / 128 / 256</td>
          <td style="text-align: right">每档 32</td>
      </tr>
  </tbody>
</table>
<p>为了量化左右子树是否抵消，定义共同方向比例：</p>
$$
q=\frac{\lVert left+right\rVert}{\lVert left\rVert+\lVert right\rVert+tiny}
$$<p>$q$ 越接近零，左右状态越接近反向抵消。</p>
<p>审计结果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>全部节点 q &lt; 0.10 的数量：0
</span></span><span style="display:flex;"><span>全局最小 q：0.58384
</span></span><span style="display:flex;"><span>样本最小 q 的中位数：0.65610
</span></span></code></pre></div><p>也就是说，在这个训练后的 TreeHeap 状态里，左右节点普遍同向成分很强。人工 alternating tree 所揭示的数学边界真实存在，但它没有成为当前自然文本状态的实际病灶。</p>
<h2 id="7-此前没有单独披露的功能出现了">7. 此前没有单独披露的功能出现了</h2>
<p>真实数据上，能量载体确实让梯度更小。但按句长拆开后，我们发现“小”并不自动等于“稳定”：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">width</th>
          <th style="text-align: right">当前 FOLD 梯度 p50</th>
          <th style="text-align: right">能量载体梯度 p50</th>
          <th style="text-align: right">current/carrier</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">0.04459</td>
          <td style="text-align: right">0.03131</td>
          <td style="text-align: right">1.419</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">0.04404</td>
          <td style="text-align: right">0.02183</td>
          <td style="text-align: right">2.023</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">0.04111</td>
          <td style="text-align: right">0.01524</td>
          <td style="text-align: right">2.690</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">0.03622</td>
          <td style="text-align: right">0.01076</td>
          <td style="text-align: right">3.408</td>
      </tr>
      <tr>
          <td style="text-align: right">64</td>
          <td style="text-align: right">0.03035</td>
          <td style="text-align: right">0.00757</td>
          <td style="text-align: right">4.005</td>
      </tr>
      <tr>
          <td style="text-align: right">128</td>
          <td style="text-align: right">0.02153</td>
          <td style="text-align: right">0.00528</td>
          <td style="text-align: right">4.068</td>
      </tr>
      <tr>
          <td style="text-align: right">256</td>
          <td style="text-align: right">0.01483</td>
          <td style="text-align: right">0.00370</td>
          <td style="text-align: right">3.994</td>
      </tr>
  </tbody>
</table>
<p>从 width 4 增加到 256：</p>
<ul>
<li>能量载体梯度下降约 8.5 倍；</li>
<li>当前 FOLD 梯度只下降约 3 倍。</li>
</ul>
<p>能量载体把绝对尺度一路保存下来，也让 root probe 的梯度自然分摊到越来越多的 leaf。当前 FOLD 每一层都从当层 parent 重新估计尺度，相当于在递归路径上反复做局部增益调整。它并没有消除长程衰减，却补回了相当一部分梯度压力。</p>
<p>这就是此前没有单独披露、也没有被我们明确识别的功能：</p>
<blockquote>
<p><strong>当前 FOLD 不只是前向退火编码器，它还是一个隐式的逐层梯度补偿器。</strong></p></blockquote>
<p>需要强调，这不是说当前公式已经正确，也不是说梯度越大越好。它只说明，贸然把每层重新归一化替换为严格的绝对能量传播，可能在修复一个未出现的极端奇点时，先破坏真实训练所需的长深度学习压力。</p>
<h2 id="8-能量和学习压力不是同一个量">8. 能量和学习压力不是同一个量</h2>
<p>这次实验帮助我们区分了四个经常混在一起的概念：</p>
<table>
  <thead>
      <tr>
          <th>概念</th>
          <th>它回答的问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>状态幅度</td>
          <td>当前节点的数值有多大</td>
      </tr>
      <tr>
          <td>子树能量</td>
          <td>节点覆盖的信息载体总尺度有多大</td>
      </tr>
      <tr>
          <td>前向可逆性</td>
          <td>保存 root、detail、scale 后能否恢复输入</td>
      </tr>
      <tr>
          <td>梯度压力</td>
          <td>task loss 能以多强的信号修改远端参数</td>
      </tr>
  </tbody>
</table>
<p>能量守恒解决不了梯度压力。前向可逆也不能保证反向条件良好。反过来，梯度较大也不能证明信息更多，它可能是有效补偿，也可能是病态放大。</p>
<p>因此，TreeHeap 的递归退火算法至少需要同时审计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>前向状态是否有界
</span></span><span style="display:flex;"><span>FOLD/UNFOLD 是否闭包
</span></span><span style="display:flex;"><span>不同深度梯度是否衰减
</span></span><span style="display:flex;"><span>极端抵消处是否近奇异
</span></span><span style="display:flex;"><span>真实语料是否真的进入这些极端区域
</span></span></code></pre></div><p>任何单一指标都不足以决定公式。</p>
<h2 id="9-为什么我们没有继续训练新候选">9. 为什么我们没有继续训练新候选</h2>
<p>真实 checkpoint 审计在执行前预注册了停止条件：只有自然数据存在可测抵消尾部，并且能量载体显著改善梯度尾部，才允许进入短训练 ablation。</p>
<p>最终结果为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>A0 数值闭包与有限性：通过
</span></span><span style="display:flex;"><span>A1 真实抵消尾部存在：失败
</span></span><span style="display:flex;"><span>A2 current 梯度 p99 至少是 carrier 两倍：失败
</span></span><span style="display:flex;"><span>A3 抵消指标与梯度比相关：通过，但与句长共同变化，不能独立解释
</span></span><span style="display:flex;"><span>最终决定：do_not_train_energy_carrier_yet
</span></span></code></pre></div><p>所以我们没有用更多训练掩盖问题，也没有因为 toy 漂亮就宣布改进成功。</p>
<p>能量载体作为一个数学候选和边界修复工具保留。当前正式 FOLD 不修改。下一步回到真实 task loss，分离每个深度对共享 READ、depth embedding、branch 和 recurrent decoder 的参数梯度，寻找多深度负交互真正发生的位置。</p>
<h2 id="10-一句话结论">10. 一句话结论</h2>
<blockquote>
<p>TreeHeap 的递归能量载体能够修复人工反向抵消造成的梯度奇点，但这个病灶没有出现在当前真实文本 checkpoint 中；反而是现有逐层归一化暴露出一个此前未被明确识别的功能，它会补偿部分长深度梯度衰减。能量守恒不等于学习压力守恒，因此新候选在训练前被主动停止。</p></blockquote>
<p>完整 ARA、代码与 Evidence：</p>
<ul>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/logic/stone2_recursive_energy_carrier_smoke.zh.md">递归能量载体 toy</a></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/logic/stone2_checkpoint_energy_gradient_audit.zh.md">真实 checkpoint 能量与梯度审计</a></li>
<li><a href="https://github.com/houming818/sametime/blob/main/ara/s3-generation/evidence/s3_checkpoint_energy_gradient_audit/summary.json">机器可读审计结果</a></li>
</ul>
<hr>
<p><strong>原创与 License：</strong> 本文中的 TreeHeap 递归能量载体、路径比例传播设计、梯度补偿解释、Claim、反证条件与实验流程由 Houming818 与 Codex 在 TreeHeap 研究过程中共同提出和验证。代码与 ARA Evidence 依 SameTime 仓库许可证开放；本文内容采用 GPLv3，可复现、审计和修改。本文不声明该候选优于其他架构，也不把数值 smoke 外推为语言或意识结论。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-086] 压力板为什么没有长出私有协议：D07 三轮因果审计</title>
      <link>https://www.grepcode.cn/spr/086-treeheap-pressure-protocol-slot-coverage.html</link>
      <pubDate>Fri, 28 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/086-treeheap-pressure-protocol-slot-coverage.html</guid>
      <description>TreeHeap 已经能用递归深度限制信息容量，但 D07 三轮 smoke 表明：有限槽位尚未形成足够强的输入协议。本文公开语言捷径、坐标失配、有界增益修复和下一步结构覆盖实验。</description>
      <content:encoded><![CDATA[<h1 id="昨晚为什么没有正式训练">昨晚为什么没有正式训练</h1>
<p>昨晚我们原本准备启动一轮长训练。最后 GPU 没有进入正式任务，不是基础设施故障，也不是因为害怕实验失败，而是预注册的 smoke gate 阻止了它。</p>
<p>这次 gate 做了它应该做的事：在几分钟内告诉我们，当前结构虽然已经能够施加“压缩压力”，但还没有充分学会“有限空间里应该保存什么”。如果在这个状态下直接训练一夜，我们更可能得到一个更熟练的语言捷径，而不是更可靠的 TreeHeap 私有协议。</p>
<p>这篇文章把 D07、D07R1 和 D07R2 三轮实验放到一张图里，解释我们已经解决了什么、失败在哪里，以及下一步为什么要从“自由查询”转向“结构覆盖”。</p>
<h2 id="1-先区分两个问题">1. 先区分两个问题</h2>
<p>前一阶段的 D06 已经做出了一个可工作的压力板：递归深度越浅，可使用的协议槽位越少；递归深度越深，可使用的槽位越多。</p>
<p>若完整深度为 <code>D=7</code>，输入有效长度为 <code>L</code>，深度 <code>d</code> 的容量近似为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>B(d) = max(2, ceil(L * 2^(d-D)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>d=5  -&gt; 约 1/4 容量
</span></span><span style="display:flex;"><span>d=6  -&gt; 约 1/2 容量
</span></span><span style="display:flex;"><span>d=7  -&gt; 完整容量
</span></span></code></pre></div><p>这解决的是<strong>容量控制</strong>：我们已经可以把一块板压成四分之一、二分之一或完整大小。</p>
<p>但容量控制不等于语义压缩。给模型四个槽位，并不会自动让四个槽位分别学会“人物、动作、对象、时间”。模型也可能把四个槽位都用来保存同一类高频信号。</p>
<p>所以 D07 研究的是第二个问题：</p>
<blockquote>
<p>在容量受限时，梯度能否自己形成 Encoder 与 Decoder 共同理解的私有协议？</p></blockquote>
<h2 id="2-d07-的数据流到底是什么">2. D07 的数据流到底是什么</h2>
<p>D07 没有人工提供缩句、语法标签或目标前缀。它只把源句写入冻结的 source TreeHeap，然后允许若干个 query 从 root 出发，递归读取左右子堆，形成有限数量的协议槽位。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>source sentence
</span></span><span style="display:flex;"><span>    -&gt; frozen source TreeHeap H
</span></span><span style="display:flex;"><span>    -&gt; recursive READ queries
</span></span><span style="display:flex;"><span>    -&gt; B(d) protocol slots
</span></span><span style="display:flex;"><span>    -&gt; recursive FOLD into a protocol TreeHeap
</span></span><span style="display:flex;"><span>    -&gt; shared recursive READ / decoder
</span></span><span style="display:flex;"><span>    -&gt; reconstruct the full target sentence
</span></span></code></pre></div><p>训练目标仍是完整目标句的 token 交叉熵。目标 token、目标长度和参考译文都不能进入压缩器，也不能参与容量计算。</p>
<p>因此，这不是把正确答案偷偷截短后交给模型。它是一项最小的码率-失真试验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>递归深度 d  -&gt; 可用容量，也就是码率
</span></span><span style="display:flex;"><span>完整句 NLL  -&gt; 重建误差，也就是失真
</span></span></code></pre></div><p>如果它成功，梯度应该在有限槽位中形成某种可读协议。我们不预先规定协议必须长得像人类语法，只要求它确实携带输入信息，并且能帮助 Decoder。</p>
<h2 id="3-三把因果尺子">3. 三把因果尺子</h2>
<p>只看训练 NLL 下降是不够的。Decoder 即使完全忽略输入，也可能通过学习目标语料的高频词和常见句式降低 NLL。</p>
<p>因此我们固定同一个测试集，做三种读法：</p>
<table>
  <thead>
      <tr>
          <th>读法</th>
          <th>操作</th>
          <th>它在检查什么</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>native</code></td>
          <td>使用当前样本自己的协议槽位</td>
          <td>正常路径</td>
      </tr>
      <tr>
          <td><code>shuffle</code></td>
          <td>换成另一个样本的槽位</td>
          <td>协议是否保存了“这是哪个输入”</td>
      </tr>
      <tr>
          <td><code>zero</code></td>
          <td>把所有协议槽位置零</td>
          <td>协议总体上是在帮助还是干扰 Decoder</td>
      </tr>
  </tbody>
</table>
<p>指标写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>delta_shuffle = NLL(shuffle) - NLL(native)
</span></span><span style="display:flex;"><span>delta_zero    = NLL(zero)    - NLL(native)
</span></span></code></pre></div><p>正数表示干预使结果变差，也就是 native 协议具有正向贡献。</p>
<p>预注册门槛要求：至少两个深度中，<code>delta_shuffle</code> 和 <code>delta_zero</code> 都不小于 <code>+0.10</code>。这个门槛不神圣，但它是在看结果之前写下的，不能因为结果只差一点就临时修改。</p>
<h2 id="4-第一轮nll-大降却是语言捷径">4. 第一轮：NLL 大降，却是语言捷径</h2>
<p>D07 训练了 120 steps。三个深度的 valid NLL 都大幅下降：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">depth</th>
          <th style="text-align: right">初始化 NLL</th>
          <th style="text-align: right">训练后 NLL</th>
          <th style="text-align: right">下降</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">21.865</td>
          <td style="text-align: right">8.291</td>
          <td style="text-align: right">13.574</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right">23.473</td>
          <td style="text-align: right">8.006</td>
          <td style="text-align: right">15.467</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td style="text-align: right">25.018</td>
          <td style="text-align: right">7.987</td>
          <td style="text-align: right">17.030</td>
      </tr>
  </tbody>
</table>
<p>如果只看这张表，实验似乎非常成功。但因果干预给出了相反答案：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">depth</th>
          <th style="text-align: right"><code>delta_shuffle</code></th>
          <th style="text-align: right"><code>delta_zero</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">+0.060</td>
          <td style="text-align: right"><strong>-1.902</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right">+0.056</td>
          <td style="text-align: right"><strong>-1.523</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td style="text-align: right">+0.067</td>
          <td style="text-align: right"><strong>-1.513</strong></td>
      </tr>
  </tbody>
</table>
<p><code>zero</code> 反而比 <code>native</code> 好很多。这说明协议槽位不是 Decoder 的有效信息源，而是干扰源。NLL 的下降主要来自可训练 Decoder 学会了目标语料的边际分布。</p>
<p>这里原先使用“闭卷考试”作比喻并不准确。计算 NLL 时使用了 teacher forcing。即使源句协议被清零，Decoder 每一步仍然能看到此前的正确目标 token：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>native: P(y_t | 正确目标前缀 y_&lt;t, 当前源句协议 C(x), 参数 theta)
</span></span><span style="display:flex;"><span>zero:   P(y_t | 正确目标前缀 y_&lt;t, 空协议 0,       参数 theta)
</span></span></code></pre></div><p>所以更准确的比喻是：学生看不到英文原题，但每道填空题都能看到此前的正确中文答案。她当然可以依靠已经学会的中文规律继续答题。这项能力本身是好的，说明参数 <code>theta</code> 和当前 Decoder 隐态已经形成了语言背景。</p>
<p>负面证据只针对一个更窄的 Claim：加入当前源句协议 <code>C(x)</code> 后，成绩反而下降，说明当时“英文原题到中文答题系统”的通道尚未对齐。它不表示 Decoder 没学到规律，也不表示模型整体一无所获。</p>
<p>所以第一轮不能证明私有协议。</p>
<h2 id="5-第二轮冻结语言捷径输入身份出现了">5. 第二轮：冻结语言捷径，输入身份出现了</h2>
<p>D07R1 冻结了继承的语言骨架，只允许压力协议两端的递归映射学习。这样 Decoder 不能再通过修改词频输出层独自降低损失。</p>
<p>训练 300 steps 后：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">depth</th>
          <th style="text-align: right"><code>delta_shuffle</code></th>
          <th style="text-align: right"><code>delta_zero</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">+0.587</td>
          <td style="text-align: right">-1.440</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right">+0.618</td>
          <td style="text-align: right">-1.360</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td style="text-align: right">+0.617</td>
          <td style="text-align: right">-1.358</td>
      </tr>
  </tbody>
</table>
<p>这一次 <code>shuffle</code> 明显变差。它证明槽位不是常量，也不是完全相同的词频模板：槽位已经携带了“当前输入是谁”的样本相关信息。</p>
<p>但是 <code>zero</code> 仍然更好。也就是说，槽位里虽然有信息，但它进入冻结 Decoder 时的整体坐标或幅度不合适，干扰大于帮助。</p>
<p>这像是收到了一封确实属于你的加密邮件，但直接把密文当正文显示。寄件人身份对了，内容接口却没有对齐。</p>
<h2 id="6-第三轮小流量接入方向终于变正">6. 第三轮：小流量接入，方向终于变正</h2>
<p>D07R2 没有改变数据、容量公式、FOLD 或损失，只在协议进入 Decoder 前增加一个所有深度共享的有界增益：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>gain = sigmoid(a)
</span></span><span style="display:flex;"><span>slot_used = gain * slot
</span></span></code></pre></div><p>增益从约 <code>0.0180</code> 开始，训练后为 <code>0.0204</code>。这相当于先用很小的流量接入旧 Decoder，让两边逐步建立坐标关系，而不是第一步就用满幅状态覆盖旧参考系。</p>
<p>600 steps 后，因果符号第一次全部转正：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">depth</th>
          <th style="text-align: right"><code>delta_shuffle</code></th>
          <th style="text-align: right"><code>delta_zero</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">+0.096</td>
          <td style="text-align: right">+0.036</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right">+0.139</td>
          <td style="text-align: right">+0.071</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td style="text-align: right">+0.142</td>
          <td style="text-align: right">+0.064</td>
      </tr>
  </tbody>
</table>
<p>这张表可以支持两个有限结论：</p>
<ol>
<li>打乱样本会变差，协议包含输入身份信息；</li>
<li>清空协议也会变差，协议开始对 Decoder 产生正向贡献。</li>
</ol>
<p>但 <code>zero</code> 损失只有 <code>+0.036</code> 到 <code>+0.071</code>，没有达到预注册的 <code>+0.10</code>。因此严格结论仍然是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>smoke_blocks_formal
</span></span></code></pre></div><p>这不是“差一点就算通过”。它表示方向修正了，但信号还太弱，不值得立即投入一夜长训练。</p>
<h2 id="7-为什么深度增加没有带来可见的新信息">7. 为什么深度增加没有带来可见的新信息</h2>
<p>D07R2 中，深度 5、6、7 的可用槽位数量不同，理论上应该对应不同码率。但自由生成样例几乎相同，BLEU4 都约为 <code>0.642</code>，没有出现我们期待的“深度增加后细节逐渐补全”。</p>
<p>训练日志还给出了一条重要线索：递归 READ 的分支熵在若干训练阶段迅速接近 0。熵接近 0 表示左右选择变得极其确定，query 不再同时探索多个候选分支。</p>
<p><strong>已经观察到的事实是：</strong></p>
<ul>
<li>不同深度生成几乎相同；</li>
<li>增加容量带来的 NLL 边际收益很小；</li>
<li>部分递归分支熵接近 0；</li>
<li><code>shuffle</code> 损失明显大于 <code>zero</code> 损失。</li>
</ul>
<p><strong>当前最合理、但尚未被直接证明的推断是：</strong></p>
<blockquote>
<p>多个自由 query 可能收敛到了少数相似路径或相似子堆。它们能携带样本指纹，所以 shuffle 有明显影响；但新增槽位重复读取相近内容，所以清空全部槽位造成的净损失仍然很小，深度之间也没有形成分辨率差异。</p></blockquote>
<p>这里必须诚实地保留“可能”。当前日志只测了每步分支熵，没有直接计算不同槽位之间的路径重叠率。因此我们还不能写成“已经证明所有槽位读取同一个节点”。</p>
<h2 id="8-下一步从自由竞争改为结构覆盖">8. 下一步：从自由竞争改为结构覆盖</h2>
<p>当前每个槽位都像一名自由记者：大家可以去整棵树的任何地方采访。梯度会把所有记者派往最容易降低 NLL 的热门地点，却没有动力保证有人覆盖其他区域。</p>
<p>下一步候选不是给槽位写入“主语、谓语、宾语”等人工语义，而是给它们最小的 TreeHeap 地址责任：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>depth 5: 少量槽位，各自负责较大的 subheap
</span></span><span style="display:flex;"><span>depth 6: 更多槽位，各自负责更小的 subheap
</span></span><span style="display:flex;"><span>depth 7: 继续细分 frontier，覆盖更细的地址区域
</span></span></code></pre></div><p>每个槽位只能在自己的 subheap 内使用同一个共享 READ kernel 学习压缩。也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>结构先验只规定“去哪里读”
</span></span><span style="display:flex;"><span>梯度仍然决定“在那里保留什么”
</span></span></code></pre></div><p>这和 flat array 切片不同。分区依据的是递归 TreeHeap 地址与 subheap frontier；不同深度的分区由同一棵树递归细化，局部读取仍共享同一组 kernel 参数。</p>
<p>它也不是提前定义语言含义。某个槽位最终保存动作、对象、时序还是别的隐态，仍由完整目标重建损失决定。</p>
<h2 id="9-新候选必须怎样被证明">9. 新候选必须怎样被证明</h2>
<p>下一轮不能只看 NLL。至少要提前登记四组指标：</p>
<ol>
<li><strong>覆盖率</strong>：有多少 source leaf 被至少一个槽位的主要路径覆盖；</li>
<li><strong>重叠率</strong>：不同槽位的路径或终点有多大比例重合；</li>
<li><strong>输入因果性</strong>：继续比较 native、shuffle 和 zero；</li>
<li><strong>容量边际收益</strong>：新增槽位是否带来新的 NLL 收益与可见生成差异。</li>
</ol>
<p>还需要两个重要对照：</p>
<table>
  <thead>
      <tr>
          <th>对照</th>
          <th>目的</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>自由 query</td>
          <td>判断结构 ownership 是否真的减少重复读取</td>
      </tr>
      <tr>
          <td>随机打乱 ownership</td>
          <td>判断收益来自 TreeHeap 邻接结构，还是仅仅来自把槽位强行分开</td>
      </tr>
  </tbody>
</table>
<p>只有当“结构覆盖”同时降低槽位重叠、提高 source 覆盖，并让 native 对 zero 的优势稳定超过预注册门槛，才允许进入正式长训练。</p>
<h2 id="10-这算不算已经有了背景知识">10. 这算不算已经有了背景知识</h2>
<p>现在可以确认，模型已经能学习某些背景规律，但需要区分三个层次：</p>
<table>
  <thead>
      <tr>
          <th>载体</th>
          <th>当前能保存什么</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>参数 <code>theta</code></td>
          <td>长期词频、常见句式和目标语言统计关系</td>
      </tr>
      <tr>
          <td>Decoder 隐态</td>
          <td>当前正确目标前缀形成的短期状态</td>
      </tr>
      <tr>
          <td>TreeHeap 协议 <code>C(x)</code></td>
          <td>当前输入的样本相关信息，目前只有弱正贡献</td>
      </tr>
  </tbody>
</table>
<p>因此，“没有源句仍能降低 NLL”支持的是<strong>语言背景模型存在</strong>。它还不能直接升级为“TreeHeap 已经形成世界模型”，因为我们尚未证明事实、对象关系和状态变化被结构化地写入 TreeHeap，并能跨表述查询和组合。</p>
<p>更合适的当前分级是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>目标语言统计规律       已有证据
</span></span><span style="display:flex;"><span>输入相关的私有协议     弱正证据
</span></span><span style="display:flex;"><span>TreeHeap 背景知识      尚未定位
</span></span><span style="display:flex;"><span>可查询的世界模型       尚未证明
</span></span></code></pre></div><p>这不是降低目标，而是避免用终极问题一次否定所有中间生长。</p>
<h2 id="11-参考-gpt-2--gpt-3怎样安排能力阶梯">11. 参考 GPT-2 / GPT-3，怎样安排能力阶梯</h2>
<p>GPT-2 没有以“完整世界模型”作为早期验收。研究者同时训练了约 <code>117M / 345M / 762M / 1.5B</code> 四档模型，观察跨域语言建模、连贯生成以及问答、摘要、翻译等零样本行为是否随规模出现。论文同时承认，很多下游任务仍然非常初步，所有模型当时也仍未充分拟合 WebText。<a href="https://cdn.openai.com/better-language-models/language-models.pdf">GPT-2 论文</a></p>
<p>GPT-3 继续使用自回归语言目标，并把测试明确分成 zero-shot、one-shot 和 few-shot。测试时不更新梯度，只改变输入中的任务说明和示例。论文在 <code>125M</code> 到 <code>175B</code> 的模型序列上观察到，多数任务随规模相对平滑地改善，但自然语言推断和部分阅读理解仍然困难。<a href="https://arxiv.org/abs/2005.14165">GPT-3 论文</a></p>
<p>TreeHeap 应当采用同样的分级思想，同时增加自己的结构因果门：</p>
<table>
  <thead>
      <tr>
          <th>阶梯</th>
          <th>最近目标</th>
          <th>当前状态</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1. 语言底座</td>
          <td>学会词频、句式和上下文续写</td>
          <td>已有基础证据</td>
      </tr>
      <tr>
          <td>2. 输入协议</td>
          <td><code>native</code> 稳定优于 <code>shuffle/zero</code></td>
          <td>D07R2 弱正，未过门</td>
      </tr>
      <tr>
          <td>3. 任务萌芽</td>
          <td>冻结一个 checkpoint 后出现续写、填空、翻译、文内问答</td>
          <td>未正式测试</td>
      </tr>
      <tr>
          <td>4. Scaling Curve</td>
          <td>参数、数据、算力增加时，语言能力与结构贡献共同改善</td>
          <td>待建立</td>
      </tr>
      <tr>
          <td>5. 上下文适应</td>
          <td>不更新梯度，few-shot 稳定优于 zero-shot</td>
          <td>未测试</td>
      </tr>
      <tr>
          <td>6. 知识关联</td>
          <td>同一事实换一种表述仍可取回</td>
          <td>未测试</td>
      </tr>
      <tr>
          <td>7. 世界状态</td>
          <td>关系可组合、状态可更新并参与预测</td>
          <td>长期目标</td>
      </tr>
  </tbody>
</table>
<p>当前不能从第二级直接跳到第七级。最近航线仍然是：先让 TreeHeap 输入协议稳定产生正贡献，再观察同一 checkpoint 是否开始出现多个任务，而不是立即要求它完成因果和反事实推理。</p>
<h3 id="111-我们约-10-bleu和-gpt-2-的-5-bleu-怎么比较">11.1 我们约 10 BLEU，和 GPT-2 的 5 BLEU 怎么比较</h3>
<p>历史 TreeHeap 配方在专门的中英平行语料训练后，曾得到约 <code>9.9--12.7</code> 的自制 token-BLEU4。GPT-2 在 WMT-14 英译法上约为 <code>5 BLEU</code>，法译英约为 <code>11.5 BLEU</code>。数字看起来接近，但两场考试并不相同：</p>
<table>
  <thead>
      <tr>
          <th>条件</th>
          <th>GPT-2</th>
          <th>历史 TreeHeap</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>语言方向</td>
          <td>英法</td>
          <td>英中</td>
      </tr>
      <tr>
          <td>翻译监督</td>
          <td>几乎没有专门平行训练</td>
          <td>使用中英平行语料专门训练</td>
      </tr>
      <tr>
          <td>能力性质</td>
          <td>通用语言模型中出现的翻译行为</td>
          <td>专门 seq2seq 通道</td>
      </tr>
      <tr>
          <td>BLEU 实现</td>
          <td>WMT 评测</td>
          <td>自制 BPE token-BLEU4</td>
      </tr>
  </tbody>
</table>
<p>因此不能写成“TreeHeap 10 分，所以整体超过 GPT-2”。但可以保留一个重要结论：</p>
<blockquote>
<p><strong>TreeHeap 已经越过真实 seq2seq 翻译能否学习的存在性门槛，而且其早期任务成绩并不意味着架构没有继续生长的空间。</strong></p></blockquote>
<p>正式横向比较必须统一训练集、测试集、tokenizer、SacreBLEU signature、训练算力和监督方式。更重要的是，TreeHeap 还要额外证明其结构没有被普通语言骨架绕过。</p>
<h3 id="112-scaling-不只是把模型做大">11.2 Scaling 不只是把模型做大</h3>
<p>参考 scaling-law 的方法，后续至少需要 <code>1x / 2x / 4x</code> 参数、数据和训练 token 的受控阶梯，并同时记录 NLL、标准任务指标、GPU 小时与结构消融。早期训练曲线应用来预测长训练收益，而不是每次直接赌一场长任务。<a href="https://arxiv.org/abs/2001.08361">Scaling Laws for Neural Language Models</a></p>
<p>我们需要同时看到两条曲线：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>普通语言能力随规模改善
</span></span><span style="display:flex;"><span>TreeHeap 的 native-zero / native-shuffle 贡献也随规模改善
</span></span></code></pre></div><p>如果只有 NLL 下降，而结构贡献逐渐归零，就不能把规模收益归功于 TreeHeap 私有协议。</p>
<h2 id="12-当前航线结论">12. 当前航线结论</h2>
<p>D07 三轮实验没有证明 TreeHeap 私有协议已经形成，但它排除了三个容易混淆的故事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>NLL 大降，不等于输入协议形成；
</span></span><span style="display:flex;"><span>槽位包含样本信息，不等于槽位对 Decoder 有帮助；
</span></span><span style="display:flex;"><span>增加槽位数量，不等于增加了互补信息。
</span></span></code></pre></div><p>我们现在可以更准确地描述工程状态：</p>
<blockquote>
<p><strong>递归深度压力已经能限制容量；有界增益已经让协议贡献从负转正；尚未解决的是有限槽位如何分工覆盖 TreeHeap，并在容量增加时带来互补信息。</strong></p></blockquote>
<p>所以昨晚没有正式训练，是一次有效停止。船没有停在原地，我们只是确认下一步应该修方向分配，而不是继续给同一套 query 增加燃料。</p>
<p>完整 Claim、代码与 Evidence 位于 <a href="https://github.com/houming818/sametime">SameTime 开放仓库</a>，对应 <code>D07</code>、<code>D07R1</code> 与 <code>D07R2</code> 记录。</p>
<hr>
<p><strong>作者说明：</strong> TreeHeap 的递归深度压力、有限协议槽位与结构覆盖候选来自 Houming818 与 Codex 的共同讨论。本文公开成功、失败、推断边界与下一步证伪条件，供读者复现和审计。</p>
<p><strong>License:</strong> GPLv3。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-087] TreeHeap 显微镜实验：冻结模型以后，怎样寻找隐态焦距</title>
      <link>https://www.grepcode.cn/spr/087-treeheap-microscope-focus-sweep.html</link>
      <pubDate>Mon, 07 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/087-treeheap-microscope-focus-sweep.html</guid>
      <description>冻结 TreeHeap-106M checkpoint，只改变 FOLD parent 的观察尺度并直接解码。实验首次观察到空输出、成句区间与长度发散组成的焦距曲线，并预注册 FOLD × K_up 二维验证。</description>
      <content:encoded><![CDATA[<h1 id="不再只给模型打分而是直接看它看见了什么">不再只给模型打分，而是直接看它看见了什么</h1>
<p>最近我们讨论了一个比普通消融更细的问题。</p>
<p>消融通常把某个模块删除，然后比较 NLL、BLEU 或其他指标。它能回答“这个模块是否有
因果贡献”，却不容易告诉我们：一个连续参数从小到大变化时，模型内部的观察结果究竟
怎样变形。</p>
<p>于是 Nio 提出了一个更直观的实验名称：</p>
<blockquote>
<p>固定 checkpoint 和输入句子，逐档改变 TreeHeap 的观察矩阵，再把每一档直接 Decode
出来。这像把标本放在显微镜下，旋转调焦旋钮，寻找能够看清结构的焦距。</p></blockquote>
<p>我们把它称为 <strong>TreeHeap 显微镜实验</strong>。</p>
<p>它不是文学包装。这个比喻恰好对应了一套可复现的实验合同：</p>
<table>
  <thead>
      <tr>
          <th>显微镜概念</th>
          <th>TreeHeap 实验对象</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>固定标本</td>
          <td>冻结 checkpoint 与固定输入句</td>
      </tr>
      <tr>
          <td>物镜倍率</td>
          <td>TreeHeap 递归深度</td>
      </tr>
      <tr>
          <td>调焦旋钮</td>
          <td>FOLD parent 的数值尺度</td>
      </tr>
      <tr>
          <td>观察图像</td>
          <td>Decoder 直接生成的文本</td>
      </tr>
      <tr>
          <td>合焦</td>
          <td>文本成形、正常结束、语义轮廓可辨</td>
      </tr>
  </tbody>
</table>
<h2 id="1-我们调的到底是什么">1. 我们调的到底是什么</h2>
<p>当前协议 TreeHeap 会把相邻 child 两两合并成 parent。忽略 mask 的边界情况，本次只读
干预把局部算子写成：</p>
$$
H_{parent}=s(H_{left}+H_{right})
$$<p>它对应一个作用于两个 child 的局部观察矩阵：</p>
$$
M_s=\begin{bmatrix}sI & sI\end{bmatrix}
$$<p>其中，$I$ 是隐态维度上的单位矩阵，$s$ 是我们旋转的“焦距”旋钮。</p>
<p>当前代码使用：</p>
$$
s=\sqrt{\frac{1}{2}}\approx0.707
$$<p>这使两个独立、同方差 child 相加后大致保持二范数能量。它不是从语言语义推导出的
唯一答案，只是当前数值合同。另一个自然候选是算术平均：</p>
$$
s=0.5
$$<p>我们还需要看更弱和更强的观察尺度会发生什么，因此第一轮扫描固定为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>s = 0, 0.25, 0.5, 0.707, 1.0
</span></span></code></pre></div><p>所有训练参数都被冻结。没有任何一档获得额外训练机会。</p>
<h2 id="2-为什么不用-nll-决定答案">2. 为什么不用 NLL 决定答案</h2>
<p>这次问题不是“哪一档对参考 token 的平均概率更高”，而是：</p>
<blockquote>
<p>同一个 Decoder 在看到不同尺度的 TreeHeap 状态以后，会坍缩出怎样的文本？</p></blockquote>
<p>如果只保存一个 NLL，我们看不到下面这些完全不同的失败形态：</p>
<ul>
<li>第一个 token 就选择 EOS，输出为空；</li>
<li>只能生成几个与输入有关的词片段；</li>
<li>能形成句子，但主体、动作或对象丢失；</li>
<li>句长不断膨胀，重复局部短语；</li>
<li>到最大长度仍不生成 EOS。</li>
</ul>
<p>这些现象都可能被一个聚合分数压在一起。因此本轮以逐句 Decode 为主证据，长度、EOS、
重复率和字符相似度只用于整理观察。</p>
<h2 id="3-第一块标本怎样变化">3. 第一块标本怎样变化</h2>
<p>第一轮使用训练完成的 TreeHeap-106M 第二遍语料 checkpoint，固定 greedy Decoder，测试
四个句子、三个递归深度。下面是一句短英文在 depth 7 下的完整变化：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Input: The child put the red apple on the table.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s=0
</span></span><span style="display:flex;"><span>  ⁇ 子虫
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s=0.25
</span></span><span style="display:flex;"><span>  ⁇ 放进食
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s=0.5
</span></span><span style="display:flex;"><span>  放进餐后
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s=0.707（当前实现）
</span></span><span style="display:flex;"><span>  放进餐后,把孩子放在桌子上。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s=1.0
</span></span><span style="display:flex;"><span>  放进的进食,把进食le-le 放在桌子上,把孩子放在小包上,
</span></span><span style="display:flex;"><span>  把孩子放在一小瓶里,把孩子放在一小瓶里……
</span></span><span style="display:flex;"><span>  （达到 48 pieces，仍未生成 EOS）
</span></span></code></pre></div><p>这里出现了一条肉眼可见的变化过程：弱观察只能留下碎片；中间尺度开始形成动作和位置；
尺度继续增加以后，生成长度与重复同时膨胀。</p>
<p>反方向的短句也出现了低尺度立即停止：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Input: 孩子把红苹果放在桌子上。
</span></span><span style="display:flex;"><span>Depth: 5
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s=0      -&gt; 空输出，立即 EOS
</span></span><span style="display:flex;"><span>s=0.25   -&gt; 空输出，立即 EOS
</span></span><span style="display:flex;"><span>s=0.5    -&gt; The table is placed in the table.
</span></span><span style="display:flex;"><span>s=0.707  -&gt; Put a table in the table.
</span></span><span style="display:flex;"><span>s=1.0    -&gt; Put a table in the table.
</span></span></code></pre></div><p>这些译文远没有达到产品质量。显微镜实验观察的是状态能否形成以及怎样失稳，不能把“能
成句”偷换成“翻译正确”。</p>
<h2 id="4-第一条焦距曲线">4. 第一条焦距曲线</h2>
<p>每个尺度共有 12 个输出，汇总如下：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">FOLD 尺度</th>
          <th style="text-align: right">空输出</th>
          <th style="text-align: right">未生成 EOS</th>
          <th style="text-align: right">平均输出 pieces</th>
          <th>直接观察</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">0</td>
          <td style="text-align: right">2/12</td>
          <td style="text-align: right">1/12</td>
          <td style="text-align: right">9.42</td>
          <td>容易立即停止或只剩词片段</td>
      </tr>
      <tr>
          <td style="text-align: right">0.25</td>
          <td style="text-align: right">2/12</td>
          <td style="text-align: right">1/12</td>
          <td style="text-align: right">9.42</td>
          <td>与零尺度相近</td>
      </tr>
      <tr>
          <td style="text-align: right">0.5</td>
          <td style="text-align: right">0/12</td>
          <td style="text-align: right">0/12</td>
          <td style="text-align: right">11.92</td>
          <td>全部正常结束，短句较稳定</td>
      </tr>
      <tr>
          <td style="text-align: right">0.707</td>
          <td style="text-align: right">0/12</td>
          <td style="text-align: right">0/12</td>
          <td style="text-align: right">18.17</td>
          <td>轮廓更丰富，也出现语义漂移</td>
      </tr>
      <tr>
          <td style="text-align: right">1.0</td>
          <td style="text-align: right">0/12</td>
          <td style="text-align: right">4/12</td>
          <td style="text-align: right">30.33</td>
          <td>长度膨胀、重复、停止失败</td>
      </tr>
  </tbody>
</table>
<p>从这 60 个输出看，冻结 Decoder 并非只能接受训练时的唯一尺度。它在一个中间区间仍能
工作，但对 parent 幅度并不具备全尺度不变性。</p>
<p>我们暂时把 <code>0.5</code> 到 <code>0.707</code> 称为<strong>候选焦区</strong>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>尺度过弱
</span></span><span style="display:flex;"><span>  -&gt; 证据不足，EOS 或短词片段占优
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>中间焦区
</span></span><span style="display:flex;"><span>  -&gt; 文本能够形成并正常停止
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>尺度过强
</span></span><span style="display:flex;"><span>  -&gt; 坍缩失稳，长度与重复扩张
</span></span></code></pre></div><p>这不是一条已经证明的普适规律。四句话太少，而且有一条隐藏的旁路尚未拆开。</p>
<h2 id="5-s0-为什么不等于只读-leaf">5. s=0 为什么不等于只读 leaf</h2>
<p>TreeHeap Decoder 在读取协议树前，还有一个学习得到的向上卷积 <code>K_up</code>：</p>
$$
H_{parent}^{read}
=H_{parent}^{fold}
+g_{up}K_{up}(H_{parent}^{fold},H_{left},H_{right})
$$<p>当我们把 $s$ 设成零时，直接 FOLD parent 确实变成零；但 <code>K_up</code> 仍能根据 children
重新生成一个残差 parent。</p>
<p>因此第一轮不能得出“leaf 自己就足够”的结论。准确说法是：</p>
<blockquote>
<p>在直接 parent 被清零以后，leaves 与仍然启用的 <code>K_up</code> 路径有时还能驱动冻结
Decoder 生成文本。</p></blockquote>
<p>这也是下一轮必须做二维实验的原因。</p>
<h2 id="6-下一轮焦距乘以重建通道">6. 下一轮：焦距乘以重建通道</h2>
<p>正式 ARA 实验固定 20 个标本，分为五类：</p>
<ol>
<li>简单主谓宾；</li>
<li>长距离依赖；</li>
<li>否定与操作顺序；</li>
<li>数字与实体；</li>
<li>抽象与递归描述。</li>
</ol>
<p>每一类同时包含中译英和英译中。尺度网格加密为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.707, 0.8, 1.0
</span></span></code></pre></div><p>同时设置两个 <code>K_up</code> 状态：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>native  -&gt; 保留训练得到的向上卷积
</span></span><span style="display:flex;"><span>bypass  -&gt; 旁路 K_up，只观察直接 FOLD parent 与 leaves
</span></span></code></pre></div><p>再乘以三个递归深度，总计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>20 specimens * 9 scales * 2 K_up modes * 3 depths = 1080 outputs
</span></span></code></pre></div><p>所有输出都必须保存。任何一条质量曲线中途下降都不能触发早停，因为我们寻找的正是完整
焦距曲线，而不是只保留一段单调区间。</p>
<h2 id="7-实验将回答三个问题">7. 实验将回答三个问题</h2>
<h3 id="71-是否真的存在焦区">7.1 是否真的存在焦区</h3>
<p>如果多个递归深度都出现连续的稳定成句区间，而两端更容易空输出或发散，“焦距”就不再
只是一个好听的名字，而是冻结模型的运行态性质。</p>
<h3 id="72-是-fold-在调焦还是-k_up-在补焦">7.2 是 FOLD 在调焦，还是 K_up 在补焦</h3>
<p>如果旁路 <code>K_up</code> 后焦区大幅移动或消失，说明 Decoder 一直在主动修正 FOLD 的数值尺度。
如果两条曲线接近，焦距主要由直接 parent 幅度和后续解码边界决定。</p>
<h3 id="73-焦距是共享的还是标本相关的">7.3 焦距是共享的还是标本相关的</h3>
<p>如果短句、长句、否定句和抽象句的最佳区间相近，我们得到一个架构级公共焦距候选。
如果不同类别需要不同尺度，那么固定常数可能不是最终答案，TreeHeap 需要根据输入和
递归深度学习一个自适应调焦协议。</p>
<h2 id="8-现在可以说什么">8. 现在可以说什么</h2>
<p>第一轮实验支持一个很窄但很清楚的观察：</p>
<blockquote>
<p><strong>FOLD parent 的数值尺度是冻结 TreeHeap Decoder 的因果变量。尺度过弱、适中和过强
会分别产生碎片化、成句和长度发散等不同 Decode 形态。</strong></p></blockquote>
<p>它还没有告诉我们哪个尺度最适合重新训练，也没有证明“搜索空间变大”是高尺度失败的
唯一机制。greedy 输出只能告诉我们 Decoder 的坍缩路径变了；要讨论概率空间，还需要
继续记录 EOS 概率、token entropy 和候选分布。</p>
<p>但显微镜已经架起来了。下一步不是猜一张更好的照片，而是在固定标本上画完焦距曲线，
再判断 TreeHeap 需要一个常量焦距，还是一套会自己调焦的观察协议。</p>
<h2 id="9-正式扫描结果不是一个点而是一片焦平面">9. 正式扫描结果：不是一个点，而是一片焦平面</h2>
<p>文章写完后，正式任务在同一天完成了全部 1080 个固定单元。20 个标本、三个 depth、
九档尺度与两种 <code>K_up</code> 状态全部运行结束，没有按中途质量提前停止。</p>
<p>原生 <code>K_up</code> 下，通过成形、EOS 与空输出门槛的连续区间为：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">depth</th>
          <th>连续稳定尺度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">5</td>
          <td><code>0.375, 0.5, 0.625, 0.707</code></td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td><code>0.25, 0.375, 0.5, 0.625, 0.707</code></td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td><code>0.125, 0.25, 0.375, 0.5, 0.625, 0.707</code></td>
      </tr>
  </tbody>
</table>
<p>所以“存在焦区”的 Claim 在三个 depth 上都通过了。它不是一个精确点，而是一段允许
Decoder 正常形成并结束文本的区间。</p>
<p>高尺度端点的失稳随深度明显增强：<code>s=1</code> 的 formed rate 从 depth 5 的 <code>75%</code>，下降到
depth 6 的 <code>55%</code> 和 depth 7 的 <code>30%</code>。depth 7 只有 <code>40%</code> 的输出在 64 pieces 内
产生 EOS。这比“看起来有点重复”更清楚：未经归一化的 parent 求和会沿递归逐层放大，
最终把冻结 Decoder 推出稳定坍缩区。</p>
<p>旁路 <code>K_up</code> 后，540 对单元中有 538 对生成文本发生变化。depth 5 的稳定区从
<code>0.375..0.707</code> 移到较低的 <code>0..0.375</code>，depth 6 也从 <code>0.25..0.707</code> 移到约
<code>0..0.5</code>。因此 <code>K_up</code> 的确参与调焦，但它不是简单地“补回丢失 parent”：在低尺度下，
关闭它有时反而更容易形成文本；在 <code>0.625..0.8</code> 附近，开启它通常带来更好的语义
相似度和稳定率。两条路径存在耦合。</p>
<p>更有意思的是不同倍率下的焦距分布。五类标本在 depth 5 的最佳 character-F2 尺度
IQR 为 <code>0.375</code>，没有共同焦点；depth 6 和 7 的 IQR 都缩小到 <code>0.093</code>，最佳尺度聚集在
<code>0.707..0.8</code>。</p>
<p>这给出了一个比“把常数改成 0.5”更谨慎也更有价值的方向：</p>
<blockquote>
<p><strong>TreeHeap 的焦距可能随递归深度变化；浅层更依赖标本，深层才逐渐形成共同观察尺度。</strong></p></blockquote>
<p>同时，最稳定的成句区通常比最佳字符相似度区更低、更宽。语义焦点靠近失稳边界，这意味着
未来的自适应调焦不能只追求更强信号，也必须同时约束 EOS、长度与重复。显微镜实验找到的
不是一个立即替换生产参数的答案，而是一张可以继续训练和验证的焦平面。</p>
<p>下一阶训练实验见
<a href="/spr/088-treeheap-trainable-focus.html">SPR-088：TreeHeap 可学习焦距</a>。F01 的冻结扫描
继续作为只读证据保留，不追认成训练结果。</p>
<blockquote>
<p><strong>License: GPLv3。本文中的 TreeHeap 显微镜实验、参数干预设计、ARA 判定与 evidence
按项目许可证公开，欢迎复现、批评与提出反证。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-088] TreeHeap 可学习焦距：让递归深度自己选择观察尺度</title>
      <link>https://www.grepcode.cn/spr/088-treeheap-trainable-focus.html</link>
      <pubDate>Tue, 08 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/088-treeheap-trainable-focus.html</guid>
      <description>在 SPR-087 冻结显微镜扫描之后，只增加三个深度焦距参数，冻结 TreeHeap-106M 的全部旧权重，验证梯度能否让不同递归深度选择自己的 FOLD 观察尺度。</description>
      <content:encoded><![CDATA[<h1 id="从转动旋钮到让模型自己调焦">从转动旋钮，到让模型自己调焦</h1>
<p><a href="/spr/087-treeheap-microscope-focus-sweep.html">SPR-087</a> 做的是一项冻结实验：固定训练完成的
TreeHeap-106M，逐档改变 FOLD parent 的尺度，然后直接看 Decoder 生成什么。</p>
<p>它观察到了三个事实：</p>
<ol>
<li>尺度过低时，部分输出为空或只剩短片段；</li>
<li>中间存在连续的稳定成句区；</li>
<li>尺度过高时，递归越深，越容易长度膨胀、重复并失去 EOS。</li>
</ol>
<p>depth 6 和 depth 7 的字符相似度焦点还开始聚集到 <code>0.707..0.8</code>。但这仍然只是研究者
替模型转动旋钮。它没有回答更关键的问题：</p>
<blockquote>
<p>如果把旋钮接上梯度，TreeHeap 能不能自己学会调焦？</p></blockquote>
<p>这就是 F02 的目标。</p>
<h1 id="最小训练原型只增加三个参数">最小训练原型：只增加三个参数</h1>
<p>我们没有立即加入样本级控制网络。那会同时改变容量、路由和优化空间，即使结果变好，也
很难知道究竟是不是焦距在起作用。</p>
<p>F02 只给 depth 5、6、7 各增加一个坐标，共三个可训练参数。尺度写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>u_d = tanh(theta_d)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s_d = sqrt(0.5) + (1 - sqrt(0.5)) * u_d,  u_d &gt;= 0
</span></span><span style="display:flex;"><span>s_d = sqrt(0.5) + sqrt(0.5) * u_d,        u_d &lt; 0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>parent = s_d * (left + right)
</span></span></code></pre></div><p>当 <code>theta_d=0</code> 时，尺度严格回到生产实现的 <code>sqrt(0.5)</code>。向两个方向移动时，尺度保持在
开区间 <code>(0,1)</code>，不会因为三个新参数直接把递归能量推到无界区域。</p>
<p>除了这三个坐标，TreeHeap-106M checkpoint 的旧参数全部冻结：</p>
<ul>
<li>source encoder 不更新；</li>
<li>compressor 不更新；</li>
<li>FOLD 之外的协议参数不更新；</li>
<li><code>K_up</code> 保持训练后的原生状态，但不更新；</li>
<li>语言 Decoder 不更新。</li>
</ul>
<p>因此，训练后任何输出变化都只能来自三个深度焦距，而不是整个模型重新记住了一遍语料。</p>
<h1 id="为什么训练仍然使用-token-loss">为什么训练仍然使用 token loss</h1>
<p>F02 的主观察对象是直接 Decode，但焦距参数仍需要一个可信信号。当前最可靠的信号仍是
teacher-forced token cross entropy：它负责告诉三个旋钮梯度方向。</p>
<p>这不等于重新把 NLL 当作唯一结论。每个正式 wake 还会在锁定的 20 个显微镜标本上，对
三个 depth 直接生成文本，记录：</p>
<ul>
<li>原始译文；</li>
<li>formed rate；</li>
<li>EOS rate；</li>
<li>输出长度与参考长度比；</li>
<li>相邻重复率；</li>
<li>character-F2 diagnostic。</li>
</ul>
<p>训练 loss 是推动旋钮的手，直接 Decode 才是我们透过目镜看到的图像。</p>
<h1 id="第一次-smoke-为什么失败">第一次 smoke 为什么失败</h1>
<p>初始 smoke taskd <code>370</code> 确实完成了 30 steps，但被 P0 拒绝。失败不是 OOM，也不是生成
文本不同：直接文本逐字一致，基座哈希、三层梯度和 reload 都正常。</p>
<p>问题出在最初的参数化：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>s = sigmoid(logit(sqrt(0.5)))
</span></span></code></pre></div><p>数学上它等于 <code>sqrt(0.5)</code>，但 float32 经过逆函数往返后产生了微小舍入，step-0 NLL 相差
<code>3.110864e-8</code>，超过预注册的 <code>1e-9</code> 同函数门。</p>
<p>我们没有把门槛改宽，也没有删除失败记录。r1 改为以 <code>sqrt(0.5)</code> 为绝对零点的双侧坐标，
使 <code>theta=0</code> 不再经过逆函数往返。</p>
<p>这个失败很小，但值得留下：当实验只研究三个标量时，起点的微小不一致也可能被误认成
训练收益。</p>
<h1 id="smoke-r1梯度已经到达焦距">Smoke r1：梯度已经到达焦距</h1>
<p>修正后的 taskd <code>371</code> 跑满 30 steps，全部安全门通过：</p>
<table>
  <thead>
      <tr>
          <th>检查</th>
          <th>结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>step-0 NLL 差</td>
          <td><code>0</code></td>
      </tr>
      <tr>
          <td>step-0 直接文本</td>
          <td>逐字一致</td>
      </tr>
      <tr>
          <td>三个 depth 的梯度</td>
          <td>全部非零且有限</td>
      </tr>
      <tr>
          <td>原 106M 基座</td>
          <td>哈希不变</td>
      </tr>
      <tr>
          <td>checkpoint reload</td>
          <td>NLL 误差为 <code>0</code></td>
      </tr>
      <tr>
          <td>formed rate</td>
          <td><code>1.0 -&gt; 1.0</code></td>
      </tr>
  </tbody>
</table>
<p>30 步后的尺度已经出现分化：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">depth</th>
          <th style="text-align: right">初始尺度</th>
          <th style="text-align: right">30-step 尺度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">0.70710677</td>
          <td style="text-align: right">0.70969760</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right">0.70710677</td>
          <td style="text-align: right">0.70627469</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td style="text-align: right">0.70710677</td>
          <td style="text-align: right">0.70328337</td>
      </tr>
  </tbody>
</table>
<p>valid mean NLL 暂时改善 <code>0.00102895</code>。两个 smoke 标本的字符 F2 没有变化，所以现在只能
说“梯度能够调焦”，还不能说“调焦改善了翻译”。</p>
<h1 id="正式训练合同">正式训练合同</h1>
<p>正式 taskd <code>372</code> 已启动，合同固定为：</p>
<ul>
<li>TreeHeap-106M pass-2 checkpoint；</li>
<li>只训练三个焦距坐标；</li>
<li>batch 64；</li>
<li>固定 5,000 steps；</li>
<li>约 32 万条训练样本暴露；</li>
<li>depth 5/6/7 循环训练；</li>
<li>每 500 steps 保存 wake、直接译文与小型 focus checkpoint；</li>
<li>质量曲线即使非单调也不提前停止。</li>
</ul>
<p>只有 OOM、CUDA/Xid、NaN/Inf、基座哈希改变、reload 损坏、270W 功率限制解除或 step
停止推进，才允许中断。</p>
<h1 id="我们准备怎样判断结果">我们准备怎样判断结果</h1>
<p>F02 不要求三个尺度必须朝某个预想方向运动。正式结果分四层解释：</p>
<ol>
<li>三个参数是否持续收到有限梯度；</li>
<li>任意两个最终尺度是否相差至少 <code>0.02</code>，形成可测的深度分化；</li>
<li>固定 valid mean NLL 是否改善至少 <code>0.01</code>；</li>
<li>20 句直接 Decode 的字符 F2 是否改善，同时 formed 与 EOS 不明显退化。</li>
</ol>
<p>如果 NLL 改善而直接文本退化，这不是成功，也不是废数据，而是一笔明确的交换。如果三个
尺度最终重新靠拢，则说明当前 token loss 更偏好共享焦距。如果它们继续分开，我们才得到
“递归深度会训练出不同观察尺度”的第一阶证据。</p>
<h1 id="边界">边界</h1>
<p>F02 不是完整的自适应显微镜。三个参数只看递归深度，不看输入句子、类别或当前隐态；它也
没有联合训练新的语义压缩目标。</p>
<p>这一级阶梯只回答一个问题：</p>
<blockquote>
<p>在冻结 TreeHeap 其余部分以后，梯度能否让不同递归深度主动选择自己的 FOLD 焦距，并
在直接生成中留下可见、可复现的变化？</p></blockquote>
<p>taskd <code>372</code> 已在 <code>io</code> 的 RTX 3090 上跑满 <code>5,000/5,000</code> steps。10 个 500-step wake
完整存在，基座哈希前后一致，checkpoint reload NLL 差为 <code>0</code>，没有出现 OOM、
CUDA/Xid 或 NaN/Inf。</p>
<p>正式判定为：</p>
<table>
  <thead>
      <tr>
          <th>门</th>
          <th>结果</th>
          <th>主要证据</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>P0 同起点</td>
          <td>通过</td>
          <td>step-0 NLL 差为 <code>0</code>，60 条 depth 展开输出逐字一致</td>
      </tr>
      <tr>
          <td>P1 梯度到达</td>
          <td>通过</td>
          <td>三个 depth 均收到非零有限梯度，基座保持冻结，reload 精确</td>
      </tr>
      <tr>
          <td>P2 深度分化</td>
          <td>未支持</td>
          <td>最终焦距 <code>[0.71405, 0.70081, 0.70542]</code>，最大差 <code>0.01324 &lt; 0.02</code></td>
      </tr>
      <tr>
          <td>P3 预测收益</td>
          <td>未支持</td>
          <td>mean NLL <code>3.85521 -&gt; 3.85463</code>，改善 <code>0.00058 &lt; 0.01</code></td>
      </tr>
      <tr>
          <td>P4 直接 Decode</td>
          <td>未支持</td>
          <td>character-F2 下降 <code>0.00071</code>；formed 与 EOS 均保持不变</td>
      </tr>
  </tbody>
</table>
<p>训练证明焦距坐标可以被梯度访问、保存和重载，但三个尺度持续振荡，没有收敛为稳定分离的
深度焦距。只训练三个全局标量也没有产生可测的预测或直接生成收益。因此它们不会进入默认
架构。</p>
<p>这不是“调焦方向失败”，而是把候选范围缩小了一步：下一次若继续，需要先解释振荡，或者
让焦距由样本与隐态条件化；不能继续假设每个深度只需要一个固定常数，也不能把本次结果
追认为成功。失败记录、每个 wake 和原始译文均已按 ARA 合同保留。</p>
<blockquote>
<p><strong>License: GPLv3。本文中的可学习焦距参数化、实验合同、失败记录和 ARA evidence 按项目
许可证公开，欢迎复现、批评与提出反证。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-089] 一个词怎样在 TreeHeap 中找到位置</title>
      <link>https://www.grepcode.cn/spr/089-treeheap-simplex-local-axis-fall.html</link>
      <pubDate>Sun, 20 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/089-treeheap-simplex-local-axis-fall.html</guid>
      <description>从一个可读问题出发解释 TreeHeap 的新 embedding 设计：词怎样进入概率空间，树节点怎样逐层区分它，以及哪些部分已有证据、哪些仍只是待验证设计。</description>
      <content:encoded><![CDATA[<h1 id="先用三分钟读懂问题">先用三分钟读懂问题</h1>
<p>这是一篇设计确认稿，不是实验胜利公告。</p>
<p>我们要解决的问题可以不使用任何项目术语来表达：</p>
<blockquote>
<p>给定许多词和它们在语料中的使用关系，能否让每个词在一棵树中逐层找到位置，并使相近的
词更容易经过相近的分支？</p></blockquote>
<p>旧方法会为每个词统计“它经常和哪些词一起出现”，再用同一张统计表从树根一路比较到叶子。
它可以给词分配稳定地址，却不等于每一层都发现了新的分类特征。语种、数字和标点等表面差异
可能在上层就消耗了大部分区分能力。</p>
<p>新设计尝试让每个树节点只观察到达本地的词，并重新计算本地最有区分力的方向。于是，根节点
可能先区分语种，下一层可能区分词类，更深一层才可能区分具体语义。这里的“可能”非常重要：
这是设计目标，还没有被实验充分证明。</p>
<p>整篇文章只做四件事：</p>
<ol>
<li>用一个概率向量表示词在所有叶子之间的位置；</li>
<li>让每个节点从到达本地的词重新计算分类方向；</li>
<li>把分类结果写成向左或向右的概率，而不是一次不可撤销的硬选择；</li>
<li>反复更新位置与路径，检查它们能否达到稳定状态。</li>
</ol>
<p>只关心结论的读者读到这里，再看“当前结论”即可。需要检查数学定义的读者可以继续向下。</p>
<h1 id="最少术语表">最少术语表</h1>
<p>下面区分三类名称，避免把项目内部语言伪装成通用理论。完整版本见
<a href="/treeheap-glossary.html">TreeHeap 开放术语表</a>。</p>
<table>
  <thead>
      <tr>
          <th>名称</th>
          <th>类别</th>
          <th>本文中的含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token</td>
          <td>通用机器学习术语</td>
          <td>文本被切分后的一个计算单位，可以是字、词或子词</td>
      </tr>
      <tr>
          <td>embedding</td>
          <td>通用机器学习术语</td>
          <td>把 token 映射为可参与距离、分类和预测计算的数值向量</td>
      </tr>
      <tr>
          <td>leaf / 叶子</td>
          <td>通用树结构术语</td>
          <td>树最末端的节点；本文把所有叶子当作位置坐标</td>
      </tr>
      <tr>
          <td>概率单纯形</td>
          <td>标准数学术语</td>
          <td>所有“非负且总和为 1”的概率向量组成的空间</td>
      </tr>
      <tr>
          <td>协方差、主轴</td>
          <td>标准统计术语</td>
          <td>描述一组点主要沿什么方向变化；第一主轴就是变化最大的方向</td>
      </tr>
      <tr>
          <td>JS 散度</td>
          <td>标准信息论术语</td>
          <td>比较两个概率分布差异的对称指标</td>
      </tr>
      <tr>
          <td>概率路由</td>
          <td>TreeHeap 项目术语</td>
          <td>token 在一个节点向左、向右传播的概率</td>
      </tr>
      <tr>
          <td>下坠</td>
          <td>TreeHeap 项目术语</td>
          <td>token 从根经过若干内部节点到达叶子的路由过程，不是物理重力</td>
      </tr>
      <tr>
          <td>概率 Hash</td>
          <td>本文的诊断性称呼</td>
          <td>旧方法能生成稳定地址，但未证明地址具有逐层语义</td>
      </tr>
      <tr>
          <td>固定点</td>
          <td>标准数学术语</td>
          <td>再更新一次仍保持不变的状态，即 $r^*=F(r^*)$</td>
      </tr>
      <tr>
          <td>Claim / Evidence</td>
          <td>ARA 研究记录术语</td>
          <td>Claim 是可被反驳的主张，Evidence 是支持或否定它的记录</td>
      </tr>
  </tbody>
</table>
<h1 id="这篇文章固定什么">这篇文章固定什么</h1>
<p>我们最近重新检查了 TreeHeap token embedding 的“下坠”含义。旧实现把 token 的上下文共现
概率当作坐标，在每一层与左右节点的平均分布计算 JS 散度，再把连续选择压成一条路径。
这能分类，也能生成稳定地址，但它更接近递归概率 Hash：同一份共现分布被重复比较，没有一
个明确的局部几何算子保证特征逐层形成。</p>
<p>现在形成的新共识是：</p>
<aside class="research-block research-claim" data-status="design">
  <header><strong>Claim SPR-089-C1</strong><span>design</span></header>
  <div>token 的状态应当位于 leaf 概率构成的单纯形中；每个节点从到达本地的 token 点云重新
计算自己的观测主轴；同一个概率点经过不同局部坐标系时产生不同左右倾向，最终形成一条
高维滚落路径。</div>
</aside>


<p>这不是把二维小球比喻强行贴到神经网络上。下面给出它的可计算定义、尚未解决的启动问题和
可以否证它的实验边界。</p>
<h1 id="为什么旧算法还不能叫特征下坠">为什么旧算法还不能叫特征下坠</h1>
<p>这里的 <strong>A09</strong> 是项目内部实验编号，指“用上下文共现概率逐层分配 token 地址”的实验，
不是公开领域中的算法名称。它的输入是 token 的上下文概率分布：</p>
$$
p_w \in \Delta^{K-1}
$$<p>节点保存落入本节点的平均上下文原型。token 每到一个节点，都重新计算：</p>
$$
d_L=JS(p_w,q_L),\qquad d_R=JS(p_w,q_R)
$$<p>然后根据距离决定左右路径。但下坠过程中：</p>
$$
p_w^{(d+1)}=p_w^{(d)}
$$<p>输入本身没有进入新的局部坐标，也没有从当前概率场产生新的观测方向。树只是在不同子集中
反复比较同一个分布。</p>
<p><strong>A10</strong> 是后续审计实验：它冻结 A09 的最佳配置，逐值重建结果，并检查每层究竟在区分什么。
“冻结合同”表示代码、数据、随机种子和参数均保持不变，以排除重跑时偷偷换题。结果完全复现：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>活跃 token</td>
          <td style="text-align: right"><code>945</code></td>
      </tr>
      <tr>
          <td>leaf</td>
          <td style="text-align: right"><code>32</code></td>
      </tr>
      <tr>
          <td>sealed-C NLL</td>
          <td style="text-align: right"><code>4.992762973593261</code></td>
      </tr>
      <tr>
          <td>leaf utilization</td>
          <td style="text-align: right"><code>29/32 = 0.90625</code></td>
      </tr>
      <tr>
          <td>root child JS</td>
          <td style="text-align: right"><code>0.5713615</code></td>
      </tr>
  </tbody>
</table>
<aside class="research-block research-evidence">
  <header><strong>Evidence E2</strong><span>A10 frozen reconstruction</span></header>
  <div>A10 支持“现有概率 Hash 已形成稳定、可解剖的数值分区”，但不支持“该分区已经形成逐层
语义特征”。后者仍是本文新设计需要验证的 Claim。</div>
</aside>


<p>节点确实形成了可解释的数值判别特征，但最强轴首先是中文与英文/拉丁字符，其后是数字、
标点、子词形态和语料风格。各深度平均 child JS 为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>depth 0: 0.5714
</span></span><span style="display:flex;"><span>depth 1: 0.2993
</span></span><span style="display:flex;"><span>depth 2: 0.2076
</span></span><span style="display:flex;"><span>depth 3: 0.0520
</span></span><span style="display:flex;"><span>depth 4: 0.0361
</span></span></code></pre></div><p>这说明“数值特征存在”已经有证据，“逐层形成语义特征”仍然没有。粗层迅速消耗了语种与
表面形式差异，深层虽然质量更均匀，但左右原型的可分性已经很弱。</p>
<h1 id="一般的-l-leaf-单纯形">一般的 L-leaf 单纯形</h1>
<p>16 个 leaf 只是讨论时的例子。正式定义不锁死 leaf 数量。</p>
<p>设 TreeHeap 有 $L$ 个 leaf，token $w$ 的状态为：</p>
$$
r_w=(r_{w1},\ldots,r_{wL}),\qquad
r_{wi}\ge 0,\qquad
\sum_{i=1}^{L}r_{wi}=1
$$<p>因此：</p>
$$
r_w\in\Delta^{L-1}
$$<p>它有 $L$ 个概率坐标和 $L-1$ 个自由度：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">leaf 数量</th>
          <th style="text-align: right">单纯形自由度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">7</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right">15</td>
      </tr>
      <tr>
          <td style="text-align: right">32</td>
          <td style="text-align: right">31</td>
      </tr>
      <tr>
          <td style="text-align: right">64</td>
          <td style="text-align: right">63</td>
      </tr>
  </tbody>
</table>
<p>这里的 $r_w$ 才是 token 在 TreeHeap 中的几何位置。它不是旧实现里的 $K$ 维共现统计表。
例如在四个叶子的玩具树中，</p>
$$
r_w=(0.6,0.2,0.1,0.1)
$$<p>表示 token 当前有 60% 的质量位于第一个叶子，另外 40% 分布在其余三个叶子。它不是说这个
词“有 60% 的语义”，而是一个可被训练和比较的位置表示。</p>
<h1 id="切空间概率怎样合法移动">切空间：概率怎样合法移动</h1>
<p>因为概率和始终为 1，合法移动方向 $u$ 必须满足：</p>
$$
\sum_i u_i=0
$$<p>所有这样的方向构成单纯形的切空间。主轴、梯度投影和局部旋转都必须留在这个空间内，否则
一次更新就可能把总概率从 1 推走。</p>
<p>例如：</p>
$$
u=(0.1,-0.1,0,\ldots,0)
$$<p>表示从第二个 leaf 向第一个 leaf 搬运 <code>0.1</code> 的概率，总质量保持不变。</p>
<h1 id="每个节点观察自己的局部词群">每个节点观察自己的局部词群</h1>
<p>“点云”是统计与几何中的常用说法，意思是一批向量点。本文的每个点就是一个 token 的位置
$r_w$；“局部点云”就是有一定概率到达当前节点的那批 token，而不是一种新的数据结构。</p>
<p>令 $m_{wv}$ 表示 token $w$ 到达节点 $v$ 的概率。节点 $v$ 只观察到达本地的加权点云。
它的局部中心为：</p>
$$
\mu_v=
\frac{\sum_wm_{wv}r_w}
{\sum_wm_{wv}}
$$<p>局部协方差为：</p>
$$
C_v=
\frac{
\sum_wm_{wv}(r_w-\mu_v)(r_w-\mu_v)^\top
}{
\sum_wm_{wv}
}
$$<p>因为不同节点接收到的 token 和权重不同，所以通常有：</p>
$$
C_{\mathrm{root}}
\ne C_{\mathrm{left}}
\ne C_{\mathrm{right}}
$$<p>这正是“每个路由点的观测主轴不同”的数学来源。</p>
<h1 id="主轴不是随意增加的一组参数">主轴不是随意增加的一组参数</h1>
<p>对局部协方差求特征分解：</p>
$$
C_vu_{v,k}=\lambda_{v,k}u_{v,k}
$$<p>最大的特征值对应第一主轴：</p>
$$
u_v=\operatorname{eigmax}(C_v)
$$<p>$u_v$ 表示本节点中概率点变化最大的方向，$\lambda_v$ 表示沿这个方向的变化强度。这里使用的
是标准主成分分析（PCA）的局部版本，不是 TreeHeap 新发明的数学定理。</p>
<p>当前共识不是让梯度直接随意修改 $u_v$。更符合几何含义的做法是：</p>
<ol>
<li>关系损失推动 token 位置 $r_w$ 变化；</li>
<li>节点重新观察局部点云；</li>
<li>协方差 $C_v$ 随之变化；</li>
<li>主轴 $u_v$ 由新的协方差重新计算。</li>
</ol>
<p>因此主轴是局部概率场的观测结果，而不是人工塞进节点的左右偏见。</p>
<h1 id="从主轴产生概率路径">从主轴产生概率路径</h1>
<p>token 相对节点中心的位置投影到主轴：</p>
$$
z_{wv}=u_v^\top(r_w-\mu_v)
$$<p>为了让不同节点的尺度可比较，可以使用主特征值标准化：</p>
$$
\hat z_{wv}=
\frac{z_{wv}}
{\sqrt{\lambda_v+\varepsilon}}
$$<p>再把它变成连续路由概率：</p>
$$
P(L\mid w,v)=\sigma(\hat z_{wv})
$$$$
P(R\mid w,v)=1-P(L\mid w,v)
$$<p>这里不提供最低基数流量，不设置先强制均匀、后逐步撤销的保护项，也不加入容量平衡惩罚。
左右概率只由 token 在当前局部坐标系中的位置决定。</p>
<p>如果采用硬路由，超平面：</p>
$$
u_v^\top(r-\mu_v)=0
$$<p>会把一个凸区域继续切成两个凸区域。采用软路由时，它变成一条概率过渡带，每个节点对应
一个加权局部区域。</p>
<h1 id="共现信息放在哪里">共现信息放在哪里</h1>
<p>共现关系仍然有用，但它不再是下坠坐标，也不需要作为一个大概率数组沿树传递。</p>
<p>它只负责提供训练关系。语料中的一次事件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>center token w -&gt; observed context c
</span></span></code></pre></div><p>要求当前位置 $r_w$ 能够预测实际上下文：</p>
<h1 id="mathcal-l_mathrmcontext">$$
\mathcal L_{\mathrm{context}}</h1>
<p>-\log P(c\mid r_w)
$$</p>
<p>这条梯度推动 token 的单纯形位置变化。位置变化以后，局部中心、协方差、主轴和路径再依次
变化。</p>
<p>因此链路应当是：</p>
$$
\text{语料关系}
\rightarrow
\text{位置梯度}
\rightarrow
r_w
\rightarrow
C_v
\rightarrow
u_v
\rightarrow
\text{概率路径}
$$<p>共现只是可选的关系来源。句序、翻译对齐、问答关系或任务损失也可以承担同一角色。如果完
全没有关系数据，token ID 只是编号，任何语义排列都无法从编号本身推导出来。</p>
<h1 id="为什么选择固定点">为什么选择固定点</h1>
<p>token 位置决定局部主轴，局部主轴又改变 token 的下坠路径。它们不是一次前向计算就能独
立确定的：</p>
$$
r^{(t)}
\rightarrow
C^{(t)}
\rightarrow
u^{(t)}
\rightarrow
\operatorname{route}^{(t)}
\rightarrow
r^{(t+1)}
$$<p>目标是找到自洽状态：</p>
$$
r^*=F(r^*)
$$<p>这里至少需要同时观察两种收敛：</p>
<p>第一种是 token 位置变化：</p>
$$
\frac1N\sum_wJS(r_w^{(t+1)},r_w^{(t)})\rightarrow0
$$<p>第二种是节点主轴旋转：</p>
$$
\theta_v^{(t)}=
\arccos\left(
\left|{u_v^{(t+1)}}^\top u_v^{(t)}\right|
\right)\rightarrow0
$$<p>绝对值用于消除特征向量的符号歧义：$u$ 与 $-u$ 是同一根轴，只是左右名称互换。</p>
<h1 id="尚未闭合的核心更新函数-f-到底是什么">尚未闭合的核心：更新函数 F 到底是什么</h1>
<p>这篇文章没有假装最后一个公式已经解决。</p>
<p>我们已经一致确认：</p>
<ul>
<li>token 状态属于一般 $L$-leaf 单纯形；</li>
<li>每个节点从局部点云计算不同主轴；</li>
<li>路由是局部投影产生的连续概率；</li>
<li>关系数据只通过 loss 推动位置，不作为下坠坐标；</li>
<li>系统应通过迭代寻找固定点。</li>
</ul>
<p>但仍缺少一个关键定义：</p>
<blockquote>
<p>一轮所有节点的概率路由，怎样严格构造下一轮 token 状态
$r^{(t+1)}=F(r^{(t)})$？</p></blockquote>
<p>这里的 $F$ 不是一个已经找到的神秘函数，只是“用旧状态计算新状态”这一步的统一记号。</p>
<p>如果直接把 root-to-leaf 路径概率当成新的 $r$，可能出现自我强化和早期路径锁定。如果把
它与旧状态简单平均，又引入了人为时间常数。如果让任务梯度独立更新 $r$，则必须说明
TreeHeap 路由在状态形成中究竟承担什么因果作用。</p>
<p>因此 $F$ 是下一阶段的算法核心，而不是可以藏在实现细节里的一个赋值语句。</p>
<h1 id="启动时的对称性问题">启动时的对称性问题</h1>
<p>若所有 token 严格从同一个均匀点开始：</p>
$$
r_w^{(0)}=(1/L,\ldots,1/L)
$$<p>那么所有 token 的局部协方差为零：</p>
$$
C_v^{(0)}=0
$$<p>此时不存在可识别主轴。系统必须由关系损失、可审计的确定性扰动或一个明确的启动阶段打破
对称性。这个启动过程必须单独登记，不能把随机初始化偷偷当成已经形成的语义。</p>
<h1 id="下一步怎样验证而不是继续造术语">下一步怎样验证，而不是继续造术语</h1>
<p>下一阶段暂称 A11“自洽单纯形下坠”。A11 也只是实验编号。它应当先经过可人工检查的小型
数据实验（toy experiment），而不是直接消耗大规模语料。</p>
<p>建议的尺度不是固定 16，而是：</p>
$$
L\in\{8,16,32,64\}
$$<p>需要记录：</p>
<ol>
<li>均匀状态能否在明确关系力下启动；</li>
<li>不同节点的主轴夹角是否真正分化；</li>
<li>leaf 状态与主轴是否收敛，还是周期振荡；</li>
<li>是否有大量 token 或节点坍缩到同一位置；</li>
<li>去掉局部主轴后，关系预测是否显著变差；</li>
<li>增加 $L$ 是否带来连续容量收益；</li>
<li>结果是否跨 seed 保持，而不是一次随机坐标排列。</li>
</ol>
<p>任何一次较低 loss 都不能单独证明这套几何成立。真正的支持证据必须同时包含：固定点、局部
主轴分化、结构消融和可解释的路径变化。</p>
<h1 id="当前结论">当前结论</h1>
<p>旧路线已经证明：递归概率 Hash 可以形成稳定地址，也可以形成数值判别特征。但它没有证明
特征会逐层下沉。</p>
<p>新的方向把问题重新定义为：</p>
<blockquote>
<p>在 $L-1$ 维概率单纯形中，让每个 TreeHeap 节点观察自己的局部点云和主轴；让 token
在一系列不同的局部坐标系中形成概率路径；再寻找位置、主轴与路径共同自洽的固定点。</p></blockquote>
<p>我们现在已经对几何对象和信息来源达成一致，但固定点算子 $F$ 仍然开放。下一步不是宣布
架构完成，而是把这个开放位置写成代码、toy 和可以失败的 Claim。</p>
<h1 id="给第一次进入这个项目的人">给第一次进入这个项目的人</h1>
<p>你不需要接受 TreeHeap 的整套语言，才能检查本文。可独立复核的问题只有三个：</p>
<ol>
<li>旧方法是否只是在不同节点重复比较同一个共现分布？</li>
<li>局部 PCA 是否真的让不同节点形成不同分类方向？</li>
<li>位置、分类方向和路径能否稳定收敛，而不是坍缩或循环？</li>
</ol>
<p>如果这三个问题中任何一个失败，这个设计都需要修改。项目编号、故事和术语不能替它免于
反证。我们公开术语，不是为了建立只有内部成员能读懂的语言，而是为了让外部读者更容易指出
我们哪里错了。</p>
<blockquote>
<p><strong>License: GPLv3。本文中的概率单纯形、局部主轴、固定点定义、实验边界与后续 ARA
设计按项目许可证公开，欢迎复现、批评与提出反证。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-090] F 不是一个神秘公式：用全局概率场搜索 TreeHeap</title>
      <link>https://www.grepcode.cn/spr/090-treeheap-probability-residual-f-search.html</link>
      <pubDate>Wed, 23 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/090-treeheap-probability-residual-f-search.html</guid>
      <description>从单句梯度的局部性出发，解释怎样把全语料共现统计保存成背景状态，再用蒙特卡洛搜索质量守恒的概率残差树 F。</description>
      <content:encoded><![CDATA[<h1 id="先说我们究竟在找什么">先说我们究竟在找什么</h1>
<p>这篇文章讨论的是 token embedding 的形成，不是翻译，也不是 Decoder 怎样生成下一个词。</p>
<p>问题可以用一句普通话表达：</p>
<blockquote>
<p>已经统计出每个词经常出现在什么上下文中以后，怎样让这些词在一棵 TreeHeap 中找到稳定、
可解释、可以逐层细化的位置？</p></blockquote>
<p>这里的 <strong>F</strong> 只是“由当前状态生成下一步树结构和 token 位置”的函数名称：</p>
$$
F:\text{全局背景概率场}\longrightarrow
\text{TreeHeap 结构、节点原型和 token 路径}
$$<p>它不是预先知道答案的公式。当前工作正是寻找 F 的结构。</p>
<p>SPR-089 尝试从概率单纯形和局部主轴理解 token 怎样下落，但留下一个核心空位：局部路由完成
以后，怎样得到下一轮状态？最近的实验又暴露出一个更基础的因果问题：如果直接用“预测下一词”
训练 embedding 和 F，那么下一词答案会通过梯度进入参数。最后得到的表示可能很好用，却不能
证明 embedding 是由背景概率场自然形成的。</p>
<p>因此我们决定把两件事拆开：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>阶段一：只用全语料共现统计寻找 embedding F
</span></span><span style="display:flex;"><span>阶段二：冻结 embedding，再检查它能否帮助下游任务
</span></span></code></pre></div><p>本文只讨论阶段一。</p>
<h1 id="最少术语表">最少术语表</h1>
<table>
  <thead>
      <tr>
          <th>名称</th>
          <th>本文含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token</td>
          <td>文本经过分词后得到的字、词或子词单位</td>
      </tr>
      <tr>
          <td>embedding</td>
          <td>token 的数值坐标，使 token 可以被比较、组合和读取</td>
      </tr>
      <tr>
          <td>上下文概率场</td>
          <td>对每个 token 统计它周围出现各种 context token 的条件概率</td>
      </tr>
      <tr>
          <td>FOLD</td>
          <td>把两个 child 的状态合成 parent</td>
      </tr>
      <tr>
          <td>UNFOLD</td>
          <td>从 parent 出发，根据当前 token 的概率特征选择左右 child</td>
      </tr>
      <tr>
          <td>原型</td>
          <td>到达某个节点的 token 所共有的平均上下文分布</td>
      </tr>
      <tr>
          <td>残差</td>
          <td>child 原型相对 parent 原型增加或减少的概率成分</td>
      </tr>
      <tr>
          <td>蒙特卡洛搜索</td>
          <td>随机提出结构修改，根据全局评分接受或拒绝，而不是穷举全部结构</td>
      </tr>
      <tr>
          <td>sealed test</td>
          <td>搜索过程中不可查看，只在 F 选定后打开一次的测试数据</td>
      </tr>
  </tbody>
</table>
<h1 id="为什么单句梯度不够">为什么单句梯度不够</h1>
<p>假设一条句子产生损失：</p>
$$
\ell(x;\theta)
$$<p>它只能提供这条句子的梯度：</p>
$$
g_x=\nabla_\theta\ell(x;\theta)
$$<p>而我们真正关心的是整套语料分布上的目标：</p>
$$
L(\theta)=
\mathbb E_{x\sim D}[\ell(x;\theta)]
$$<p>在理想随机采样条件下，单句梯度的期望可能等于全局梯度：</p>
$$
\mathbb E[g_x]=\nabla_\theta L(\theta)
$$<p>但这不表示每个单句梯度都指向正确方向，也不保证非凸参数空间能到达全局最优点。</p>
<p>例如，包含 “bank account” 的句子会把 bank 推向“银行”，包含 “river bank” 的句子会把
bank 推向“河岸”。如果每来一句话就不可逆地改写 TreeHeap 路径，路径会受到语料顺序、
高频样本和最近样本影响。系统可能发生漂移、遗忘或早期分支锁定。</p>
<p>我们的处理方式是：<strong>句子先更新统计状态，不直接更新 F。</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>句子
</span></span><span style="display:flex;"><span>  -&gt; 更新 token-context 共现计数
</span></span><span style="display:flex;"><span>  -&gt; 累积成全局背景场
</span></span><span style="display:flex;"><span>  -&gt; F 在背景场上统一搜索
</span></span></code></pre></div><p>这与动态规划保存中间状态的思想相似。历史不是只保存在当前参数里，而是保存在可检查的共现
计数和条件概率中。</p>
<h1 id="一个重要的实验纠正">一个重要的实验纠正</h1>
<p>我们曾做过如下实验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>四个输入 token
</span></span><span style="display:flex;"><span>  -&gt; embedding
</span></span><span style="display:flex;"><span>  -&gt; FOLD
</span></span><span style="display:flex;"><span>  -&gt; parent
</span></span><span style="display:flex;"><span>  -&gt; 预测第五个 token
</span></span></code></pre></div><p>第五个 token 没有进入前向输入，但它进入了交叉熵：</p>
$$
\mathcal L=-\log P(t_5\mid t_1,t_2,t_3,t_4)
$$<p>这个 loss 同时更新 embedding、F 和 Decoder。因此 parent 中存在下一词信息并不奇怪：
训练目标主动要求它保存下一词信息。</p>
<p>那个实验仍能回答“哪种 F 更适合下一词预测”，却不能回答“哪种 F 会由全局背景场自然形成”。
这两个问题都合理，但证据不能混用。</p>
<p>本文的新实验彻底移除下一词标签、翻译标签、Decoder、递归 READ 和单句在线参数更新。它只
留下 token 与 context 的累计共现概率。</p>
<h1 id="背景场的数据结构">背景场的数据结构</h1>
<p>对 token \(t\)，统计它与每个 context \(c_j\) 的共现次数：</p>
$$
C_{tj}
$$<p>经过平滑和归一化，得到条件概率：</p>
$$
p_t(j)=P(c_j\mid t)=\frac{C_{tj}+\alpha}{\sum_k C_{tk}+\alpha K}
$$<p>因此每个 token 都对应一个概率向量：</p>
$$
p_t\in\Delta^{K-1}
$$<p>这里的 \(\Delta^{K-1}\) 是概率单纯形：每个分量非负，并且总和为 1。</p>
<p>为了让概率距离更适合欧氏几何计算，实验采用平方根坐标：</p>
$$
x_t=\sqrt{p_t}
$$<p>这与 Hellinger 距离相容。需要强调的是，\(x_t\) 仍然来自全局共现概率，不是随机初始化的
可训练 token 表。</p>
<h1 id="f-的最小结构概率残差树">F 的最小结构：概率残差树</h1>
<p>我们把 F 的候选结果设计成一棵二叉 TreeHeap。每个内部节点保存：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Node {
</span></span><span style="display:flex;"><span>    mass          到达节点的语料概率质量
</span></span><span style="display:flex;"><span>    prototype μ   本节点 token 的平均 context 概率
</span></span><span style="display:flex;"><span>    axis a        本节点观察 token 差异的方向
</span></span><span style="display:flex;"><span>    threshold b   左右分支的切分位置
</span></span><span style="display:flex;"><span>    left, right   两个 child
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>token 到达节点后计算：</p>
$$
z_t=a^\top x_t
$$<p>再与阈值比较：</p>
$$
z_t\le b\Rightarrow L,\qquad
z_t>b\Rightarrow R
$$<p>第一版 smoke 使用硬路由，因为我们先要检查搜索是否能找到结构。将来可以把它放松成连续后验：</p>
$$
P(R\mid t,v)=\sigma\left(
\frac{a_v^\top x_t-b_v}{\tau_v}
\right)
$$<h2 id="fold-为什么有明确含义">FOLD 为什么有明确含义</h2>
<p>设左右 child 的质量为 \(m_L,m_R\)，上下文原型为 \(\mu_L,\mu_R\)。parent 定义为：</p>
$$
m_P=m_L+m_R
$$$$
\mu_P=
\frac{m_L\mu_L+m_R\mu_R}{m_L+m_R}
$$<p>这不是任意神经网络层。它是条件概率统计的质量加权合并，parent 与 child 的数据类型相同，
量纲也相同。</p>
<p>如果所有 token 在 child 中的计数全部加起来，必然得到 parent 的计数。因此可以直接检查：</p>
$$
m_P\mu_P=m_L\mu_L+m_R\mu_R
$$<p>若实现不满足这个等式，说明代码或数据定义有问题，而不是“模型还没学会”。</p>
<h2 id="残差怎样形成多分辨率">残差怎样形成多分辨率</h2>
<p>child 相对 parent 的变化定义为：</p>
$$
\Delta\mu_C=\mu_C-\mu_P
$$<p>沿 root 到 leaf 的路径累加：</p>
$$
\mu_{\text{leaf}}=\mu_{\text{root}}+\Delta\mu_{n_1}+\Delta\mu_{n_2}+\cdots+\Delta\mu_{n_d}
$$<p>中间项会望远镜式抵消，所以这个等式应当达到浮点误差级闭合。</p>
<p>它提供了清晰的分辨率解释：</p>
<ul>
<li>root 保存全语料公共背景；</li>
<li>浅层残差提供粗区分；</li>
<li>深层残差逐步补充局部细节；</li>
<li>leaf 保存当前路径能达到的最细背景分布。</li>
</ul>
<p>这并不自动等于“语义”。语种、标点、领域和频率也可能形成强分支。语义性质需要额外审计，
不能只看树长得像分类学。</p>
<h1 id="蒙特卡洛到底搜索什么">蒙特卡洛到底搜索什么</h1>
<p>F 可以写成：</p>
$$
F=(T,\{a_v,b_v\}_{v\in T})
$$<p>其中 \(T\) 是树，\(a_v,b_v\) 是每个内部节点的轴和阈值。</p>
<p>第一轮 smoke 固定完全二叉树的深度，只搜索各节点的局部切分规则。一次动作是：</p>
<ol>
<li>从当前仍有多个 token 的内部节点中选一个；</li>
<li>从该节点的 token 中抽两个点，用二者差形成候选轴，或者小幅扰动现有轴；</li>
<li>从本地投影分布中选择候选阈值；</li>
<li>重新让全部 token 下落；</li>
<li>根据全局背景重建质量评分；</li>
<li>接受更优方案，也以逐渐降低的概率接受暂时更差的方案。</li>
</ol>
<p>偶尔接受更差方案，是为了跳出当前位置附近的局部极小值。接受概率采用 Metropolis 形式：</p>
$$
P(\text{accept})=
\min\left(
1,
\exp\frac{J_{\text{current}}-J_{\text{proposal}}}{T}
\right)
$$<p>温度 \(T\) 随迭代下降。搜索同时保留一个 global best，所以临时探索不会覆盖已经找到的最好 F。</p>
<h1 id="搜索评分来自哪里">搜索评分来自哪里</h1>
<p>我们不能用最终 test 集反复选择 F，否则 test 就变成了训练数据。</p>
<p>因此原训练共现计数再次按固定 seed 拆成：</p>
$$
C_{\text{fit}}+C_{\text{dev}}=C_{\text{train}}
$$<p>搜索过程只做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用 fit 计算每个 leaf 的 context 原型
</span></span><span style="display:flex;"><span>用 dev 计算该结构的 context NLL
</span></span></code></pre></div><p>评分为：</p>
$$
J(F)=
-\frac{
\sum_{t,j}C_{\text{dev},tj}
\log\hat P_F(c_j\mid t)
}{
\sum_{t,j}C_{\text{dev},tj}
}
$$<p>搜索结束后，才打开原来就保存好的 WMT sealed test，比较初始树、搜索所得树和随机路径。</p>
<p>这里没有手工要求左右流量各占 50%，也没有给饥饿分支强行输送 token。链表式或极不均衡结构
可以存在，但它必须在未参与原型估计的 dev 共现上获得更低 NLL。复杂结构未来还需要加入节点
成本；本轮树深固定，因此结构复杂度相同。</p>
<h1 id="a11-smoke-怎样判定">A11 smoke 怎样判定</h1>
<p>这次实验编号为 A11，Claim 为：</p>
<aside class="research-block research-claim" data-status="supported-smoke">
  <header><strong>Claim S1-F-MC-A11-C01</strong><span>supported-smoke</span></header>
  <div>在冻结的真实 WMT token-context 概率场上，蒙特卡洛搜索局部 TreeHeap 切分规则，可以改善
确定性初始树的 dev 背景重建，同时保持 FOLD 质量守恒与路径残差闭合。</div>
</aside>


<p>机械条件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>所有数值有限
</span></span><span style="display:flex;"><span>sealed test 不参与 proposal 评分
</span></span><span style="display:flex;"><span>至少接受一个 proposal
</span></span><span style="display:flex;"><span>FOLD 守恒误差 &lt;= 1e-10
</span></span><span style="display:flex;"><span>路径残差闭合误差 &lt;= 1e-10
</span></span></code></pre></div><p>经验条件：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>dev NLL 至少改善 0.005
</span></span><span style="display:flex;"><span>sealed-test NLL 不比初始树恶化超过 0.01
</span></span><span style="display:flex;"><span>sealed-test NLL 优于随机路径
</span></span><span style="display:flex;"><span>leaf utilization 至少 50%
</span></span></code></pre></div><p>如果 dev 改善而 sealed test 恶化，说明搜索过拟合。如果概率恒等式不闭合，说明实现无效。
如果随机路径同样好，说明当前 F 搜索没有提取有用背景结构。</p>
<h1 id="实验结果搜索确实找到了更好的概率树">实验结果：搜索确实找到了更好的概率树</h1>
<p>任务 <code>561</code> 在 <code>io</code> 的 RTX 3090 上完成，共搜索 256 个候选动作，接受了 175 次。输入是冻结的
真实 WMT <code>512 x 1024</code> token-context 计数场；fit、dev 和 sealed test 分别包含约 528 万、132 万
和 74 万次共现计数。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>                         初始树          搜索所得树       随机路径
</span></span><span style="display:flex;"><span>dev NLL                  5.373436        5.357366         -
</span></span><span style="display:flex;"><span>sealed-test NLL          5.396372        5.378041         5.457888
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>dev 改善                                  0.016070
</span></span><span style="display:flex;"><span>sealed test 相对初始改善                  0.018331
</span></span><span style="display:flex;"><span>sealed test 相对随机改善                  0.079847
</span></span></code></pre></div><p>结构检查也通过：32 个 leaf 全部得到 token，leaf utilization 为 <code>1.0</code>，占用熵为 <code>0.9131</code>。
FOLD 质量守恒的最大绝对误差为 <code>1.39e-17</code>，root 加路径残差重建 leaf 的最大绝对误差为
<code>3.47e-18</code>。这些误差处于双精度浮点舍入尺度，没有发现公式或实现层面的破坏。</p>
<p>这组数字支持一个很窄但重要的结论：<strong>在没有句子答案、Decoder 和 READ 参与的情况下，按
全局上下文重建评分搜索 F，能够找到比确定性初始树和随机树都更好的概率残差结构。</strong></p>
<p>它还是 smoke 证据，而不是最终架构结论。目前只有一个 seed、一个深度和一份背景场。下一步
需要复现 seed，并做受控深度阶梯；在这些结果稳定以前，不应把搜索所得树直接装进主模型。</p>
<h1 id="这次实验没有证明什么">这次实验没有证明什么</h1>
<p>即使全部条件通过，也只能说明：</p>
<blockquote>
<p>在一个固定的真实语料背景场上，概率守恒的局部切分规则可以通过全局搜索得到改善。</p></blockquote>
<p>它仍然不能证明 leaf 已经代表人类语义类别、TreeHeap 优于 SGNS 或 Transformer、多义词已经
得到上下文条件路径、Decoder 能读取这些残差，或者 F 可以直接用于翻译与生成。</p>
<h1 id="当前路线图">当前路线图</h1>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>全局语料
</span></span><span style="display:flex;"><span>  -&gt; token-context 计数状态
</span></span><span style="display:flex;"><span>  -&gt; 条件概率背景场
</span></span><span style="display:flex;"><span>  -&gt; 蒙特卡洛搜索节点轴和阈值
</span></span><span style="display:flex;"><span>  -&gt; 概率残差 TreeHeap
</span></span><span style="display:flex;"><span>  -&gt; 冻结 embedding
</span></span><span style="display:flex;"><span>  -&gt; 独立下游任务检查
</span></span><span style="display:flex;"><span>  -&gt; 最后才接 READ 和 Decoder
</span></span></code></pre></div><p>这条路线回答了两个此前混在一起的问题：</p>
<ol>
<li>embedding 的空间从哪里来？</li>
<li>下游任务怎样使用这个空间？</li>
</ol>
<p>前一个问题由全局概率场和 F 搜索回答；后一个问题必须在冻结 F 后单独验证。若下游失败，我们
才能区分“背景空间没有形成”和“读取协议没有学会”。</p>
<h1 id="给第一次进入项目的人">给第一次进入项目的人</h1>
<p>检查本文不需要先相信 TreeHeap。只需检查四件事：</p>
<ol>
<li>单句是否只更新了可审计的共现统计，而没有直接改树；</li>
<li>搜索是否完全没有查看 sealed test；</li>
<li>parent 是否真由 child 概率质量守恒地合并；</li>
<li>搜索所得结构是否在新共现样本上优于初始树和随机路径。</li>
</ol>
<p>只要任何一点失败，A11 Claim 就不成立。实验编号、叙事和漂亮的树图都不能替代这些条件。</p>
<blockquote>
<p><strong>License: GPLv3。本文的概率残差树定义、搜索合同、否证条件和 ARA 实验设计按项目许可证公开。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-091] TreeHeap 的 F 函数：它是什么、怎样学习、现在走到了哪里</title>
      <link>https://www.grepcode.cn/spr/091-treeheap-f-function-guide.html</link>
      <pubDate>Sat, 26 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/091-treeheap-f-function-guide.html</guid>
      <description>一篇可以独立阅读的 TreeHeap F 函数说明：区分节点规则、整树计算和搜索算法，解释概率残差、参数共享、软硬路由、训练链路以及 A11-A18 已建立和尚未建立的证据。</description>
      <content:encoded><![CDATA[<h1 id="先用一句话回答">先用一句话回答</h1>
<p>TreeHeap 的 <strong>F 函数</strong>，是决定“细粒度状态怎样组成粗粒度状态，以及状态怎样沿树继续传播”的规则。</p>
<p>它不是某一个已经找到的神秘公式，也不只是一个 loss。更准确地说，我们正在寻找的是一族函数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：token 或 child 的状态、当前节点状态、可选的上下文
</span></span><span style="display:flex;"><span>输出：parent 状态、左右路由概率、残差，以及下一层可继续使用的状态
</span></span></code></pre></div><p>如果 F 合理，TreeHeap 的每一层都保存同一种可继续计算的数据，只是分辨率不同；如果 F 不合理，
树仍然可以运行，却可能只是把数组换成树形摆放，或者在递归中丢掉 Decoder 真正需要的信息。</p>
<p>本文不要求读者先了解此前九十篇日志。我们从一个四 token 的例子开始，逐步说明 F 的对象、参数、
训练方法、实验结果和当前卡点。</p>
<h1 id="为什么必须单独讨论-f">为什么必须单独讨论 F</h1>
<p>假设输入是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>西西弗 / 推 / 石头 / 上山
</span></span></code></pre></div><p>一个二叉 TreeHeap 可以先合并相邻状态，再继续向上：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>西西弗 ─┐
</span></span><span style="display:flex;"><span>         ├─ parent A ─┐
</span></span><span style="display:flex;"><span>推 ──────┘             │
</span></span><span style="display:flex;"><span>                       ├─ root
</span></span><span style="display:flex;"><span>石头 ────┐             │
</span></span><span style="display:flex;"><span>         ├─ parent B ─┘
</span></span><span style="display:flex;"><span>上山 ────┘
</span></span></code></pre></div><p>树形拓扑只告诉我们“谁和谁先计算”，没有告诉我们“怎样计算”。真正决定 parent A 是普通平均、
概率混合、可逆编码，还是一个完全不可读向量的，就是 F。</p>
<p>因此，下面三件事不能混为一谈：</p>
<ol>
<li><strong>拓扑</strong>：哪些节点相连，计算顺序是什么；</li>
<li><strong>F 函数</strong>：相连以后执行什么状态变换；</li>
<li><strong>READ/Decoder</strong>：怎样从这些状态取信息并生成输出。</li>
</ol>
<p>拓扑像函数调用图，F 像每次调用的函数体，READ/Decoder 则是状态的消费者。只改变其中一个，
另外两个不会自动正确。</p>
<h1 id="先解决一个历史歧义f-曾经指三种东西">先解决一个历史歧义：F 曾经指三种东西</h1>
<p>过去的研究记录为了交流方便，把三种相关对象都简称为 F。这会造成“F 是共享参数吗”“F 是搜索
算法还是递归公式”之类的混乱。本文开始采用三个名字。</p>
<h2 id="1-节点函数-f_v">1. 节点函数 <code>f_v</code></h2>
<p>节点 <code>v</code> 上执行的局部规则记为：</p>
$$f_v(x;\theta_v)$$<p>其中 <code>x</code> 是到达节点的状态，<code>θ_v</code> 是该节点自己的参数。当前概率路由版本中，<code>θ_v</code> 主要包含
观察轴 <code>w_v</code> 和阈值 <code>b_v</code>。</p>
<h2 id="2-整树函数-f_θ">2. 整树函数 <code>F_Θ</code></h2>
<p>把所有节点函数按树的拓扑连接起来，得到整棵树的计算：</p>
$$F_{\Theta}=f_{v_n}\circ\cdots\circ f_{v_2}\circ f_{v_1}$$<p>这里的 <code>Θ</code> 是全部节点参数的集合。输入一个 token 状态后，<code>F_Θ</code> 给出它的路径、各层状态、
leaf 位置和可供 READ 使用的多分辨率表示。</p>
<h2 id="3-学习算法-a">3. 学习算法 <code>A</code></h2>
<p>搜索或训练 <code>Θ</code> 的算法另记为：</p>
$$A(D,F_{\Theta})\longrightarrow\Theta'$$<p><code>D</code> 是语料统计或训练样本。蒙特卡洛、梯度下降、离散结构搜索都属于 <code>A</code>，而不是 F 本身。</p>
<p>这一区分非常重要：<strong>一次搜索失败，不等于 F 族必然错误；一个可微 F，也不等于训练目标能够
找到有用参数。</strong></p>
<h1 id="当前概率残差版本的数据是什么">当前概率残差版本的数据是什么</h1>
<p>当前实验没有把 token ID 直接当作可以计算的数。它先统计 token <code>t</code> 周围出现 context <code>c</code> 的
次数，再得到条件概率：</p>
$$p_t(c)=P(c\mid t)$$<p>所以一个 token 的基础状态不是单个整数，而是一行概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token t -&gt; [P(c1|t), P(c2|t), ..., P(cK|t)]
</span></span></code></pre></div><p>这行数据各分量非负、总和为 1，属于概率单纯形。它的物理含义也明确：描述“看到这个 token
时，它周围通常出现什么”。</p>
<p>为了计算路由，实验使用平方根概率坐标：</p>
$$x_t=\sqrt{p_t}$$<p>这样，概率分布之间的几何距离与 Hellinger 距离相容。它不是任意随机摆放的 embedding；坐标
来自可重复计算的全语料背景场。</p>
<h1 id="一个节点究竟怎样路由">一个节点究竟怎样路由</h1>
<p>在节点 <code>v</code>，token 状态 <code>x_t</code> 先投影到该节点的局部观察轴：</p>
$$z_v(t)=x_t^{\mathsf T}w_v-b_v$$<p><code>w_v</code> 决定这个节点观察哪些方向，<code>b_v</code> 决定切分位置。</p>
<p>硬路由只选择一侧：</p>
$$z_v(t)\le0\Rightarrow L,\qquad z_v(t)>0\Rightarrow R$$<p>软路由则保留两侧概率：</p>
$$r_v(t)=P(R\mid t,v)=\sigma\left(z_v(t)/\tau\right)$$<p>其中 <code>τ</code> 是温度。温度较低时接近硬选择；温度较高时，概率质量可以同时流向左右 child。</p>
<h2 id="参数到底共享不共享">参数到底共享不共享</h2>
<p>答案是：<strong>规则共享，节点参数通常不共享。</strong></p>
<p>所有节点都使用同一种投影与 sigmoid 公式，这是共享的计算规则；但每个节点有自己的 <code>w_v</code> 和
<code>b_v</code>，因此它们可以观察不同的局部主轴。若所有节点强行共享同一组数值参数，树的不同位置会
反复采用同一个切分面，很难形成逐层细化的分辨率。</p>
<p>另一方面，FOLD 的概率守恒公式目前没有可训练参数，它是全树共享的数学合同。不要把“共享
公式”和“共享参数值”当成同一件事。</p>
<h1 id="child-怎样合成-parent">child 怎样合成 parent</h1>
<p>设左右 child 的概率质量为 <code>m_L</code>、<code>m_R</code>，它们的 context 原型为 <code>μ_L</code>、<code>μ_R</code>。当前 FOLD 是
质量加权平均：</p>
$$m_P=m_L+m_R,\qquad \mu_P=\frac{m_L\mu_L+m_R\mu_R}{m_L+m_R}$$<p>这个 parent 仍然是一行 context 概率，与 child 的数据类型和量纲一致。它不是把两个向量相加后
任其能量随深度增长。</p>
<p>更关键的是，它满足守恒关系：</p>
$$m_P\mu_P=m_L\mu_L+m_R\mu_R$$<p>因此 root 是整批 token 的公共背景；向下走时，child 相对 parent 增加的细节记为残差：</p>
$$\Delta\mu_C=\mu_C-\mu_P$$<p>沿路径累加即可恢复某一层的原型：</p>
$$\mu_d=\mu_{root}+\sum_{k=1}^{d}\Delta\mu_k$$<p>这给“多分辨率”一个可检查的定义：浅层保存公共背景，深层逐步增加区分信息。它仍不等于自然
语言中的缩句或语义层级；那需要下游证据。</p>
<h1 id="f-影响架构中的哪些位置">F 影响架构中的哪些位置</h1>
<p>F 不是只影响一个路由开关。它至少影响四处。</p>
<table>
  <thead>
      <tr>
          <th>位置</th>
          <th>F 的作用</th>
          <th>错误时的现象</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>embedding 安装</td>
          <td>决定 token 在树中的路径与邻居</td>
          <td>同类不聚合、路径随 seed 漂移</td>
      </tr>
      <tr>
          <td>FOLD</td>
          <td>决定 parent 保存什么以及量纲是否闭合</td>
          <td>深层爆炸、消失或成为不可读数据</td>
      </tr>
      <tr>
          <td>多分辨率状态</td>
          <td>决定粗层与细层的差值</td>
          <td>每层重复，或高层完全收不到细节</td>
      </tr>
      <tr>
          <td>READ 接口</td>
          <td>决定下游能否沿路径恢复有用概率场</td>
          <td>训练 loss 下降但生成或 masked read 退化</td>
      </tr>
  </tbody>
</table>
<p>Decoder 不必和 F 共享同一组参数，但两者必须通过串联训练或冻结接口形成协议。只要 READ/Decoder
的 loss 能通过可微状态回传到 F，F 就能接收下游任务的方向信息；是否应该允许它这样训练，取决
于我们正在检验“背景 embedding”还是“端到端任务表示”。二者不能用同一份证据替代。</p>
<h1 id="怎样寻找-f">怎样寻找 F</h1>
<p>目前有三条不同路线。</p>
<h2 id="路线一蒙特卡洛搜索硬树">路线一：蒙特卡洛搜索硬树</h2>
<p>固定树深，每次修改一个节点的观察轴或阈值，让所有 token 重新下落，然后在未参与原型估计的
dev 共现数据上计算重建 NLL。更优方案被接受，少量更差方案按退火概率暂时接受，以跳出局部
极小值。</p>
<p>优点是硬树可以直接审计，路径和概率守恒都清楚。缺点是高维搜索昂贵，而且梯度不能直接告诉
离散提案下一步往哪里走。</p>
<h2 id="路线二梯度训练软树">路线二：梯度训练软树</h2>
<p>把左右选择改成连续概率，让 loss 通过全部 soft path 回传到每个 <code>w_v,b_v</code>。这证明 F 的参数
可以被普通优化器更新，也能与 READ 串联。</p>
<p>难点在于训练得到的是概率混合场。训练结束后直接以 <code>0.5</code> 阈值硬化，会丢掉混合状态携带的
信息。软模型学得好，不代表硬路径导出后仍然好。</p>
<h2 id="路线三结构与参数联合搜索">路线三：结构与参数联合搜索</h2>
<p>更完整的 F 还可能改变树的连接方式，而不只是固定拓扑上的轴和阈值。拓扑是离散变量，节点
参数是连续变量，因此这是混合优化问题。</p>
<p>当前项目尚未证明动态拓扑可用。曾经比较过 <code>left_deep</code>、<code>balanced</code>、<code>right_deep</code> 等人工枚举
拓扑，结果说明组合顺序会改变 parent 的可读信息；它不能证明路由器自己会找到这些拓扑。</p>
<h1 id="证据走到了哪里">证据走到了哪里</h1>
<p>下面不用编号代替结论，编号只作为复现入口。</p>
<table>
  <thead>
      <tr>
          <th>实验</th>
          <th>实际建立的证据</th>
          <th>仍然没有建立</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A11</td>
          <td>在固定真实语料背景场上，硬树蒙特卡洛搜索优于初始树和随机路由</td>
          <td>通用语义 F</td>
      </tr>
      <tr>
          <td>A12</td>
          <td>3 个搜索 seed、4 个深度均复现重建收益</td>
          <td>最佳深度或稳定语义拓扑</td>
      </tr>
      <tr>
          <td>A13</td>
          <td>F 可保存为自描述 checkpoint，并精确重载</td>
          <td>下游可用性</td>
      </tr>
      <tr>
          <td>A14</td>
          <td>更多语料使背景概率几何更稳定，但树分区仍明显漂移</td>
          <td>搜索已收敛</td>
      </tr>
      <tr>
          <td>A15</td>
          <td>冻结坐标可被 Token READ 和 Echo 使用；masked 语义门不胜随机码</td>
          <td>最终 embedding</td>
      </tr>
      <tr>
          <td>A16</td>
          <td>无训练 Bayesian READ 证明更深层保留更多背景预测信息</td>
          <td>当前 F 已无损或最优</td>
      </tr>
      <tr>
          <td>A17</td>
          <td>软路由可微、可训练、会改变路径且不坍缩</td>
          <td>重建 loss 能保护 READ</td>
      </tr>
      <tr>
          <td>A18</td>
          <td>READ 梯度改善了未见数据上的软概率场</td>
          <td>硬化后的 checkpoint 可用</td>
      </tr>
  </tbody>
</table>
<p>两组关键数字最能说明现状。</p>
<p>A12 中，在同一个冻结语料场上，深度 3、4、5、6 的三 seed 搜索都通过，sealed-test NLL 的
中位改善分别约为 <code>0.0540</code>、<code>0.0451</code>、<code>0.0505</code>、<code>0.0296</code>。这说明 F 不是完全随机的摆放。</p>
<p>但 A18 中，READ-coupled 训练后的软场 NLL 为 <code>4.758578</code>，硬化后变为 <code>4.899335</code>，损失
<code>0.140757</code>。这把当前卡点定位到了 <strong>soft-to-hard 交接</strong>，而不是“梯度无法穿过树”。</p>
<aside class="research-block research-claim" data-status="mixed">
  <header><strong>Claim SPR-091-F-STATUS</strong><span>mixed</span></header>
  <div>当前证据支持：概率守恒的 TreeHeap F 可以被搜索、保存、读取和微分训练，并能形成具有因果预测
信息的多分辨率概率场。当前证据不支持：已经找到稳定的最终 F，或软路由可以无损硬化为单路径。</div>
</aside>


<h1 id="为什么不能直接宣布embedding-已完成">为什么不能直接宣布“embedding 已完成”</h1>
<p>一个表示系统至少要通过三个不同门槛：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>可编码：token 能稳定进入数值空间
</span></span><span style="display:flex;"><span>可组织：背景关系能形成非随机、可复现的层级
</span></span><span style="display:flex;"><span>可消费：READ/Decoder 能利用它完成未见任务
</span></span></code></pre></div><p>当前结果已经较好地通过“可编码”，部分通过“可组织”，但“可消费”仍是混合结果。Token READ
达到 100% 只说明 token 身份能从坐标中恢复；没有 hash 碰撞时，这本来就是较低的门槛。真正
困难的是：遮住 token 后，剩余背景关系是否比随机码提供更多有效信息，以及这些信息能否经过
递归 READ 进入生成。</p>
<h1 id="当前最合理的下一步">当前最合理的下一步</h1>
<p>当前不应继续无约束地搜索更低的 embedding NLL，也不应立刻把所有路由硬化。更直接的工程路线是：</p>
<ol>
<li>保留 A18 已经表现更好的软路由，作为第一版有效 F；</li>
<li>让 READ 和 Decoder 在连续路径质量上工作，先建立端到端可用性门；</li>
<li>单独加入 soft/hard 一致性目标，逐步稀疏化，而不是训练结束后突然阈值切断；</li>
<li>同时记录每层残差、路径熵、节点占用和梯度贡献，确认收益来自哪些深度；</li>
<li>只有软模型达到应用门禁后，再比较硬路由、Top-k 路由和稀疏概率路由的成本。</li>
</ol>
<p>这里采用的是门禁思路，不要求一次找到全局最优 F。第一阶段只要求：有限、守恒、可训练、可
重载、比随机路由有信息，并能把梯度和状态可靠交给 READ。达到以后再优化速度、稀疏度和拓扑。</p>
<h1 id="如何反驳这条路线">如何反驳这条路线</h1>
<p>F 路线应当被降级或修改，如果出现以下任一稳定结果：</p>
<ul>
<li>在相同数据、容量和预算下，搜索树长期不能胜过随机或简单 flat baseline；</li>
<li>parent 概率质量不能闭合，残差不能重建对应层状态；</li>
<li>打乱 token 与概率行的对应关系后，READ 质量不下降；</li>
<li>多个 seed 下树结构完全漂移，并且下游关系也无法复现；</li>
<li>软路由的收益只能依赖稠密全路径计算，任何可接受成本的稀疏化都会消失；</li>
<li>matched Transformer、SGNS 或简单概率模型在同等资源下稳定占优，而 TreeHeap 没有提供新的
能力或成本优势。</li>
</ul>
<p>负结果不是项目失败，而是缩小 F 的候选集合。我们寻找的不是一个必须存在的答案，而是一条能
被公式、代码和未见数据共同约束的函数族。</p>
<h1 id="最后的简化图">最后的简化图</h1>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语料
</span></span><span style="display:flex;"><span>  -&gt; token-context 共现计数
</span></span><span style="display:flex;"><span>  -&gt; 每个 token 的条件概率行 p_t
</span></span><span style="display:flex;"><span>  -&gt; 节点函数 f_v 计算局部路由
</span></span><span style="display:flex;"><span>  -&gt; 整树函数 F_Theta 形成多层原型与残差
</span></span><span style="display:flex;"><span>  -&gt; READ 取得一个或多个分辨率状态
</span></span><span style="display:flex;"><span>  -&gt; Decoder 形成输出概率
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>学习算法 A：
</span></span><span style="display:flex;"><span>  Monte Carlo / gradient / topology search
</span></span><span style="display:flex;"><span>              |
</span></span><span style="display:flex;"><span>              +----&gt; 更新 Theta，而不是取代 F
</span></span></code></pre></div><p>所以，F 函数问题最终可以压缩成一句工程问题：</p>
<blockquote>
<p>能否找到一种逐层相容、概率守恒、可微、可稀疏化的状态变换，使粗层保留公共背景，深层补充
区分信息，并让 READ/Decoder 不必绕过 TreeHeap 就能使用这些信息？</p></blockquote>
<p>我们已经知道这条链路可以开始工作，也知道它目前断在什么地方。尚未找到终点，但问题已经从
“寻找一个神秘公式”，变成了可以逐项实现、测量和反驳的架构任务。</p>
<blockquote>
<p><strong>License: GPLv3。本文中的定义、证据边界和实验入口随 SameTime / TreeHeap 项目公开。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-092] TreeHeap 概念与实现总表：从研究语言走向可执行架构</title>
      <link>https://www.grepcode.cn/spr/092-treeheap-concept-implementation-roadmap.html</link>
      <pubDate>Sat, 26 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/092-treeheap-concept-implementation-roadmap.html</guid>
      <description>TreeHeap 的重要研发路线图：逐项列出概念定义、现有算法、证据、尚未实现的接口、验收门槛与依赖顺序，防止概念扩张快于工程闭环。</description>
      <content:encoded><![CDATA[<h1 id="为什么需要这张表">为什么需要这张表</h1>
<p>TreeHeap 已经积累了很多原创概念：下坠、背景场、概率残差、多分辨率退火、信息泵、私有协议、
递归 READ、Butterfly，以及正在寻找的 F 函数。</p>
<p>概念丰富不是问题。问题在于，<strong>一个概念被描述、写出公式、做成 toy、通过真实数据实验、接入
主训练链路，是五件不同的事</strong>。如果不明确区分，我们很容易把“有名字”当成“有算法”，把
“能 Echo”当成“能理解”，或者把两个分别成功的组件误认为已经形成完整系统。</p>
<p>这篇文章建立一张长期维护的研发台账。今后审查任何概念，都回答六个问题：</p>
<ol>
<li>它精确定义了什么？</li>
<li>当前代码实现了什么？</li>
<li>证据来自 toy、真实语料还是完整训练？</li>
<li>哪些强结论仍然没有证据？</li>
<li>下一道可否证门槛是什么？</li>
<li>它依赖哪些上游接口？</li>
</ol>
<h1 id="先说当前总判断">先说当前总判断</h1>
<p>TreeHeap 不是没有算法。我们已经实现了概率背景场、硬/软路由、概率 FOLD、可逆 Lifting、
Bayesian READ、Butterfly 通信和真实 WMT seq2seq。</p>
<p>但这些算法目前分属于两条没有完全接通的路线：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>概率场路线：
</span></span><span style="display:flex;"><span>语料 -&gt; P(context|token) -&gt; 路由分区
</span></span><span style="display:flex;"><span>     -&gt; 节点 prototype / 残差 -&gt; Bayesian READ
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>生成路线：
</span></span><span style="display:flex;"><span>句子 token -&gt; FOLD / Lifting / Butterfly
</span></span><span style="display:flex;"><span>          -&gt; 多层 hidden state -&gt; READ -&gt; Decoder
</span></span></code></pre></div><p>前者能够组织和读取 token 的统计背景，后者能够训练和生成文本。<strong>当前最重要的工程断点，是还
没有把概率场中学到的 F 变成句子 Encoder 真正执行的 FOLD，并让 Decoder 通过同一状态协议读取
它。</strong></p>
<h1 id="成熟度怎样标记">成熟度怎样标记</h1>
<p>本文使用六级成熟度。它不是论文通行评级，只用于项目内部管理。</p>
<table>
  <thead>
      <tr>
          <th>等级</th>
          <th>名称</th>
          <th>判定标准</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>M0</td>
          <td>概念</td>
          <td>有定义或直觉，但没有可执行算子</td>
      </tr>
      <tr>
          <td>M1</td>
          <td>Toy</td>
          <td>合成数据或极小样本上有代码</td>
      </tr>
      <tr>
          <td>M2</td>
          <td>真实组件</td>
          <td>在真实语料上可运行、可保存、可重载</td>
      </tr>
      <tr>
          <td>M3</td>
          <td>因果组件</td>
          <td>通过 matched baseline、shuffle、删除或替换干预</td>
      </tr>
      <tr>
          <td>M4</td>
          <td>主链集成</td>
          <td>接入真实 Encoder-READ-Decoder 串联训练</td>
      </tr>
      <tr>
          <td>M5</td>
          <td>可交付</td>
          <td>有稳定质量、资源审计、CLI、版本与回归测试</td>
      </tr>
  </tbody>
</table>
<p>达到 M3 不等于模型整体达到 M3。每个组件必须单独评级。</p>
<h1 id="概念与实现总表">概念与实现总表</h1>
<h2 id="一输入与状态">一、输入与状态</h2>
<table>
  <thead>
      <tr>
          <th>概念</th>
          <th>设计目标</th>
          <th>当前实现与证据</th>
          <th style="text-align: right">成熟度</th>
          <th>主要缺口</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token 背景概率场</td>
          <td>用 `P(context</td>
          <td>token)` 表示 token 的语料背景</td>
          <td style="text-align: right">A11-A16 已从真实 WMT 构造、冻结、重载并做未见数据 READ</td>
          <td>M3</td>
      </tr>
      <tr>
          <td>embedding 安装</td>
          <td>让 token 在可计算空间和树路径中落位</td>
          <td>概率坐标、轴/阈值路由和 checkpoint 已实现</td>
          <td style="text-align: right">M2</td>
          <td>分区跨 seed 仍漂移；语义优势未胜随机码</td>
      </tr>
      <tr>
          <td>上下文 occurrence 状态</td>
          <td>同一个词在不同句子中形成不同状态和路径</td>
          <td>受控多义词 proof 曾通过</td>
          <td style="text-align: right">M1</td>
          <td>尚未接入真实语料主 Encoder</td>
      </tr>
      <tr>
          <td>统一 <code>TreeState</code></td>
          <td>leaf、parent、root 使用同一数据合同</td>
          <td>多个实验各自有 tensor/state 定义</td>
          <td style="text-align: right">M0</td>
          <td>没有一个主模型共享的正式结构与序列化格式</td>
      </tr>
      <tr>
          <td>背景场持续更新</td>
          <td>新语料加入时增量更新而不遗忘旧场</td>
          <td>共现计数可以累计</td>
          <td style="text-align: right">M1</td>
          <td>路由、原型和下游 checkpoint 的在线迁移尚未实现</td>
      </tr>
  </tbody>
</table>
<h3 id="treestate-尚缺的正式定义"><code>TreeState</code> 尚缺的正式定义</h3>
<p>当前最需要落地的数据结构可以先收敛为：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeState {
</span></span><span style="display:flex;"><span>    common      当前分辨率的公共状态
</span></span><span style="display:flex;"><span>    detail      相对 parent 的新增信息
</span></span><span style="display:flex;"><span>    mass        概率质量或支持量
</span></span><span style="display:flex;"><span>    address     当前递归地址
</span></span><span style="display:flex;"><span>    support     该状态覆盖的 token / span 范围
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>字段名可以改变，但每一层必须回答：数据类型是否相同、单位是否相容、怎样序列化、怎样求梯度、
Decoder 能看到哪些字段。</p>
<h2 id="二write-与路由">二、WRITE 与路由</h2>
<table>
  <thead>
      <tr>
          <th>概念</th>
          <th>设计目标</th>
          <th>当前实现与证据</th>
          <th style="text-align: right">成熟度</th>
          <th>主要缺口</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>节点函数 <code>f_v</code></td>
          <td>在节点上计算左右路由</td>
          <td>独立轴 <code>w_v</code>、阈值 <code>b_v</code>、硬/软路由均已实现</td>
          <td style="text-align: right">M3</td>
          <td>只完成固定二叉拓扑内的路由</td>
      </tr>
      <tr>
          <td>整树函数 <code>F_Theta</code></td>
          <td>把节点规则组合为完整路径与层级状态</td>
          <td>A11-A14 可搜索硬树；A17-A18 可微训练软树</td>
          <td style="text-align: right">M2</td>
          <td>还不是句子级统一状态变换</td>
      </tr>
      <tr>
          <td>局部主轴</td>
          <td>每个节点观察不同的数据方向</td>
          <td>token-pair axis、扰动搜索和梯度轴已有实现</td>
          <td style="text-align: right">M2</td>
          <td>没有稳定解释轴代表什么语言特征</td>
      </tr>
      <tr>
          <td>动态拓扑</td>
          <td>学习 split、merge、连接次序和树形</td>
          <td>人工枚举 left-deep/balanced/right-deep</td>
          <td style="text-align: right">M1</td>
          <td>路由器尚不能可靠地学习拓扑动作</td>
      </tr>
      <tr>
          <td>STOP</td>
          <td>在合适分辨率终止递归</td>
          <td>历史 STOP gate 曾训练并坍缩到 leaf</td>
          <td style="text-align: right">M1</td>
          <td>没有满足资源与质量合同的停止算法</td>
      </tr>
      <tr>
          <td>防饥饿/容量分配</td>
          <td>防止所有 token 落入少数分支</td>
          <td>Sinkhorn、平衡损失、硬容量实验存在</td>
          <td style="text-align: right">M2</td>
          <td>人工均衡可能扭曲自然概率；尚未与主 F 统一</td>
      </tr>
  </tbody>
</table>
<p>这里必须保留一个边界：<strong>路径可区分不等于路径有语义。</strong> token ID hash、位置编码和随机唯一
码都能产生稳定路径，也能完成 Echo。</p>
<h2 id="三fold残差与多分辨率">三、FOLD、残差与多分辨率</h2>
<table>
  <thead>
      <tr>
          <th>概念</th>
          <th>设计目标</th>
          <th>当前实现与证据</th>
          <th style="text-align: right">成熟度</th>
          <th>主要缺口</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>概率 FOLD</td>
          <td>child 概率质量守恒地组成 parent</td>
          <td>质量加权 prototype，浮点尺度闭合</td>
          <td style="text-align: right">M3 数学 / M2 工程</td>
          <td>主要用于 token 背景场，未成为句子 hidden-state FOLD</td>
      </tr>
      <tr>
          <td>normalized-sum FOLD</td>
          <td>控制深度能量与量纲</td>
          <td>已有真实生成与尺度审计</td>
          <td style="text-align: right">M2</td>
          <td>深度尺度漂移、权重含义仍未彻底隔离</td>
      </tr>
      <tr>
          <td>可逆 Lifting</td>
          <td>parent 保存公共量，detail 保存差异，可精确 UNFOLD</td>
          <td>闭合、真实语料和 WMT 机制证据均存在</td>
          <td style="text-align: right">M3</td>
          <td>还未与概率 F 和统一 <code>TreeState</code> 合并</td>
      </tr>
      <tr>
          <td>残差编码</td>
          <td>逐层记录 child 相对 parent 的新增信息</td>
          <td><code>delta = child - parent</code> 和望远镜闭合已实现</td>
          <td style="text-align: right">M2</td>
          <td>没证明优于直接保存每层 prototype 或 flat table</td>
      </tr>
      <tr>
          <td>多分辨率</td>
          <td>粗层保存公共背景，深层补充细节</td>
          <td>A16 深度曲线、Lifting 深度干预有正面结果</td>
          <td style="text-align: right">M3 局部</td>
          <td>尚未形成稳定、互补、可复用的语言层级</td>
      </tr>
      <tr>
          <td>退火</td>
          <td>随深度降低不确定性或组织搜索空间</td>
          <td>目前有多种公式和诊断实验</td>
          <td style="text-align: right">M1-M2</td>
          <td>没有统一熵定义和主模型训练合同</td>
      </tr>
      <tr>
          <td>缩句式层级</td>
          <td>高层对应更短、更抽象的语言表达</td>
          <td>压力协议和长度实验存在</td>
          <td style="text-align: right">M1</td>
          <td>没有可靠的层级语义目标或生成门</td>
      </tr>
  </tbody>
</table>
<h3 id="残差当前只能怎样表述">残差当前只能怎样表述</h3>
<p>若定义：</p>
$$\Delta_v=\mu_v-\mu_{parent(v)}$$<p>则路径闭合：</p>
$$\mu_{leaf}=\mu_{root}+\sum_{v\in path}\Delta_v$$<p>是定义导致的望远镜求和。任意 hash 树也可以满足。它证明数值记账自洽，不证明路径语义，更不
证明残差是最优存储方式。</p>
<p>残差要升级到 M3，必须在相同存储量和计算量下，胜过：</p>
<ul>
<li>token-ID hash 树；</li>
<li>随机平衡树加同样残差；</li>
<li>直接保存每层 prototype；</li>
<li>flat leaf prototype table；</li>
<li>原生树但逐层 shuffle 或删除残差。</li>
</ul>
<p>评价使用 masked READ、生成质量和 rate-distortion，不能使用 Echo 作为主要证据。</p>
<h2 id="四read-与-decoder">四、READ 与 Decoder</h2>
<table>
  <thead>
      <tr>
          <th>概念</th>
          <th>设计目标</th>
          <th>当前实现与证据</th>
          <th style="text-align: right">成熟度</th>
          <th>主要缺口</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Bayesian READ</td>
          <td>不训练 Decoder，直接从冻结概率场推断 token</td>
          <td>A16 在未见 WMT 上胜 path/row shuffle</td>
          <td style="text-align: right">M3</td>
          <td>只适合条件概率场，不是通用神经 READ</td>
      </tr>
      <tr>
          <td>parent-only READ</td>
          <td>只读 parent，关闭 leaf 旁路</td>
          <td>F21 一 seed 支持线性可读</td>
          <td style="text-align: right">M2</td>
          <td>尚未跨任务、跨 seed 复现</td>
      </tr>
      <tr>
          <td>多层 READ</td>
          <td>同时读取多个深度</td>
          <td>多个模型有实现</td>
          <td style="text-align: right">M2</td>
          <td>共享 READ 曾造成层间干扰，深层贡献不稳定</td>
      </tr>
      <tr>
          <td>查询条件递归 READ</td>
          <td>Decoder query 决定读哪条路径和哪一层</td>
          <td>有概率 READ、Lifting route 等局部实现</td>
          <td style="text-align: right">M2</td>
          <td>尚未形成统一、可审计、胜过 flat 的算法</td>
      </tr>
      <tr>
          <td>Decoder 私有协议</td>
          <td>Encoder 和 Decoder 通过梯度形成内部约定</td>
          <td>WMT、Stone、Lifting 均出现机制证据</td>
          <td style="text-align: right">M3 局部</td>
          <td>没与概率 F/embedding 安装统一</td>
      </tr>
      <tr>
          <td>无旁路生成</td>
          <td>输出必须依赖递归 parent/detail，不能直接搜索 leaf</td>
          <td>部分实验关闭过旁路</td>
          <td style="text-align: right">M2</td>
          <td>尚无统一回归门，历史实现仍可能以其他方式旁路</td>
      </tr>
  </tbody>
</table>
<p>Decoder 不需要和 F 共享同一组参数。但它们必须通过同一个 <code>TreeState</code> 接口串联，且 Decoder loss
能够在需要时回传到 F。否则所谓“私有协议”只存在于文字中。</p>
<h2 id="五长程通信与生成">五、长程通信与生成</h2>
<table>
  <thead>
      <tr>
          <th>概念</th>
          <th>设计目标</th>
          <th>当前实现与证据</th>
          <th style="text-align: right">成熟度</th>
          <th>主要缺口</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Butterfly</td>
          <td>用 <code>log2(N)</code> 局部阶段建立全地址感受野</td>
          <td>合成任务和三 seed WMT 均有因果收益</td>
          <td style="text-align: right">M4</td>
          <td>尚未证明计算成本优于优化后的稠密基线</td>
      </tr>
      <tr>
          <td>Stone 训练管线</td>
          <td>预训练、任务训练、proof、loss、report</td>
          <td>已有长任务、恢复、wake、checkpoint</td>
          <td style="text-align: right">M4</td>
          <td>不同航段的状态合同仍不完全统一</td>
      </tr>
      <tr>
          <td>双语 seq2seq</td>
          <td>英中/中英生成</td>
          <td>14.17M 数据规模训练已运行</td>
          <td style="text-align: right">M4</td>
          <td>自由生成质量、重复、长度和产品门仍开放</td>
      </tr>
      <tr>
          <td>世界模型/背景知识</td>
          <td>隐态保存可迁移的条件规律</td>
          <td>next-token、masked READ 有窄证据</td>
          <td style="text-align: right">M1-M2</td>
          <td>没有独立事实召回、推理和迁移评测闭环</td>
      </tr>
      <tr>
          <td>逻辑/缩句/抽象</td>
          <td>高层状态承载语言结构而非 token bag</td>
          <td>仍以假设和局部探针为主</td>
          <td style="text-align: right">M0-M1</td>
          <td>没有明确监督目标、可逆目标或权威基线</td>
      </tr>
  </tbody>
</table>
<h2 id="六训练部署与资源目标">六、训练、部署与资源目标</h2>
<table>
  <thead>
      <tr>
          <th>概念</th>
          <th>设计目标</th>
          <th>当前实现与证据</th>
          <th style="text-align: right">成熟度</th>
          <th>主要缺口</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>全链路 loss</td>
          <td>同时优化背景组织、FOLD、READ 和生成</td>
          <td>各阶段 loss 分别存在</td>
          <td style="text-align: right">M1</td>
          <td>目标之间会冲突，尚无统一加权或约束优化</td>
      </tr>
      <tr>
          <td>soft-to-hard</td>
          <td>将可训练 soft field 转成低成本路径</td>
          <td>A18 已定位硬化损失</td>
          <td style="text-align: right">M1</td>
          <td>没有一致性训练、Top-k 或渐进稀疏化方案</td>
      </tr>
      <tr>
          <td>统一 checkpoint</td>
          <td>一个 artifact 保存 embedding、F、READ、Decoder 合同</td>
          <td>各模块均能各自保存</td>
          <td style="text-align: right">M1</td>
          <td>尚不能无歧义组合、升级和回滚</td>
      </tr>
      <tr>
          <td>消费级训练</td>
          <td>一张 3090 可完成主要研究与本地部署</td>
          <td>多数实验确实运行于 3090</td>
          <td style="text-align: right">M3 工程</td>
          <td>soft 全路径和大词表仍可能失去稀疏优势</td>
      </tr>
      <tr>
          <td>稀疏运行时</td>
          <td>推理只激活少量路径和节点</td>
          <td>设计目标明确</td>
          <td style="text-align: right">M0-M1</td>
          <td>尚无真实吞吐、显存和 kernel 证明</td>
      </tr>
      <tr>
          <td>可复现发布</td>
          <td>ARA、日志、哈希、博客、CLI</td>
          <td>已形成较完整流程</td>
          <td style="text-align: right">M4</td>
          <td>大 artifact 管理和跨仓状态仍需收敛</td>
      </tr>
  </tbody>
</table>
<h1 id="当前真正缺失的四个算法">当前真正缺失的四个算法</h1>
<p>许多未完成概念可以归并成四个算法缺口，而不是继续增加名词。</p>
<h2 id="缺口一统一状态变换">缺口一：统一状态变换</h2>
<p>需要一个正式可执行的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>FOLD(left: TreeState, right: TreeState)
</span></span><span style="display:flex;"><span>    -&gt; parent: TreeState
</span></span><span style="display:flex;"><span>    -&gt; left_detail: TreeState
</span></span><span style="display:flex;"><span>    -&gt; right_detail: TreeState
</span></span></code></pre></div><p>它必须同时满足有限、有界、量纲相容、可微、可重载，并能被真实 Decoder 使用。概率平均和
Lifting 都是候选组件，但尚未合成一个主实现。</p>
<h2 id="缺口二句中-occurrence-的-write">缺口二：句中 occurrence 的 WRITE</h2>
<p>当前背景场主要回答“bank 这个 token 通常出现在哪里”。主 Encoder 必须进一步回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>WRITE(token=bank, context=river)   != WRITE(token=bank, context=account)
</span></span></code></pre></div><p>如果没有这一层，F 再复杂也只是在组织词典，而不是编码句子。</p>
<h2 id="缺口三查询条件的递归-read">缺口三：查询条件的递归 READ</h2>
<p>需要一个 READ，根据 Decoder 当前 query，在 root、各层 detail 和局部 child 之间分配读取质量，
并保存完整 route trace。它必须胜过相同容量的 flat memory，而不只是证明某个节点可读。</p>
<h2 id="缺口四soft-到稀疏的连续交接">缺口四：soft 到稀疏的连续交接</h2>
<p>训练时的 soft path 有效，突然阈值硬化会损失信息。需要渐进温度、Top-k、稀疏门或显式一致性
目标，使模型在训练过程中逐步适应有限路径，而不是训练结束后被切断。</p>
<h1 id="主研发路线">主研发路线</h1>
<p>下面按依赖关系推进，而不是按概念出现时间推进。</p>
<h2 id="r0冻结术语和基线">R0：冻结术语和基线</h2>
<p>状态：<strong>当前进行中。</strong></p>
<p>交付物：</p>
<ul>
<li>统一使用 <code>f_v</code>、<code>F_Theta</code>、学习算法 <code>A</code>；</li>
<li>固定 hash tree、random balanced tree、flat table、ordinary embedding 基线；</li>
<li>Echo 只作为机械测试，不作为语义证据。</li>
</ul>
<p>完成门：每个后续 Claim 都明确比较对象、参数量、存储量和计算量。</p>
<h2 id="r1建立-canonical-treestate">R1：建立 canonical <code>TreeState</code></h2>
<p>状态：<strong>未实现，最高优先级。</strong></p>
<p>交付物：</p>
<ul>
<li>一个共享的数据类与 checkpoint schema；</li>
<li>概率 FOLD 和 Lifting FOLD 都实现同一接口；</li>
<li>depth、shape、mass、closure、gradient 自动测试；</li>
<li>不接 Decoder，先完成数学和工程合同。</li>
</ul>
<p>完成门：深度阶梯全部有限、闭合、reload 一致，且两个候选算子可以被同一测试套件替换。</p>
<h2 id="r2实现-context-conditioned-write">R2：实现 context-conditioned WRITE</h2>
<p>状态：<strong>只有受控 proof。</strong></p>
<p>交付物：</p>
<ul>
<li>token type 背景作为 prior；</li>
<li>当前句子 context 形成 posterior occurrence state；</li>
<li>同词多义真实语料 probe；</li>
<li>token-only、BoW、普通 embedding 基线。</li>
</ul>
<p>完成门：同一 token 的不同上下文状态可分，shuffle 后优势消失，并在未见词汇组合上复现。</p>
<h2 id="r3残差因果门">R3：残差因果门</h2>
<p>状态：<strong>尚未执行 matched 对照。</strong></p>
<p>交付物：</p>
<ul>
<li>有/无残差；</li>
<li>直接 prototype 与路径残差；</li>
<li>hash/random/native tree；</li>
<li>每层 delete/shuffle；</li>
<li>相同 bit budget 的 rate-distortion 曲线。</li>
</ul>
<p>完成门：残差在至少一个非 Echo、未见数据任务中，以相同预算稳定胜过直接表和 hash 对照。</p>
<h2 id="r4read-decoder-无旁路闭环">R4：READ-Decoder 无旁路闭环</h2>
<p>状态：<strong>组件存在，统一闭环未实现。</strong></p>
<p>交付物：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>occurrence WRITE
</span></span><span style="display:flex;"><span>  -&gt; canonical FOLD
</span></span><span style="display:flex;"><span>  -&gt; multiresolution TreeState
</span></span><span style="display:flex;"><span>  -&gt; query-conditioned READ
</span></span><span style="display:flex;"><span>  -&gt; Decoder
</span></span></code></pre></div><p>训练必须保存每层读取质量、梯度和干预结果。</p>
<p>完成门：关闭 leaf/flat bypass 后仍能在真实 seq2seq 或 masked generation 上学习；root、detail、route
替换分别造成预注册的质量下降。</p>
<h2 id="r5soft-to-sparse-与动态拓扑">R5：soft-to-sparse 与动态拓扑</h2>
<p>状态：<strong>软路由可用，硬交接失败。</strong></p>
<p>交付物：</p>
<ul>
<li>soft、Top-k、straight-through、渐进温度四臂；</li>
<li>质量、激活节点数、显存和吞吐共同测量；</li>
<li>动态 split/merge/STOP 放在稀疏路由稳定以后。</li>
</ul>
<p>完成门：稀疏版本保留 soft 质量，同时产生可测量的消费级硬件收益。</p>
<h2 id="r6规模产品与开放发布">R6：规模、产品与开放发布</h2>
<p>状态：<strong>等待 R4/R5。</strong></p>
<p>交付物：</p>
<ul>
<li>固定小/中/大尺度阶梯；</li>
<li>真实 CLI 翻译、生成、masked read 与重复率；</li>
<li>3090 显存、功率、吞吐和恢复审计；</li>
<li>checkpoint、数据 manifest、SHA-256 和 GPL 发布材料。</li>
</ul>
<p>完成门：结果在多 seed、未见数据和 checkpoint reload 后稳定，且不依赖研究脚本中的隐藏旁路。</p>
<h1 id="依赖图">依赖图</h1>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>R0 术语与基线
</span></span><span style="display:flex;"><span> |
</span></span><span style="display:flex;"><span> v
</span></span><span style="display:flex;"><span>R1 canonical TreeState
</span></span><span style="display:flex;"><span> |
</span></span><span style="display:flex;"><span> +---------&gt; R2 context WRITE
</span></span><span style="display:flex;"><span> |                 |
</span></span><span style="display:flex;"><span> v                 v
</span></span><span style="display:flex;"><span>R3 残差因果门 ----&gt; R4 READ-Decoder 闭环
</span></span><span style="display:flex;"><span>                         |
</span></span><span style="display:flex;"><span>                         v
</span></span><span style="display:flex;"><span>                 R5 soft-to-sparse / topology
</span></span><span style="display:flex;"><span>                         |
</span></span><span style="display:flex;"><span>                         v
</span></span><span style="display:flex;"><span>                    R6 规模与产品
</span></span></code></pre></div><p>动态拓扑不是当前第一优先级。若状态类型和 READ 合同未固定，拓扑搜索只会在不稳定目标上扩大
搜索空间。</p>
<h1 id="后续怎样逐项审查">后续怎样逐项审查</h1>
<p>以后检查表中任意一项，统一使用下面的模板：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>概念名称：
</span></span><span style="display:flex;"><span>正式输入/输出：
</span></span><span style="display:flex;"><span>当前代码路径：
</span></span><span style="display:flex;"><span>当前证据路径：
</span></span><span style="display:flex;"><span>最强已支持结论：
</span></span><span style="display:flex;"><span>明确未支持结论：
</span></span><span style="display:flex;"><span>matched baselines：
</span></span><span style="display:flex;"><span>干预方法：
</span></span><span style="display:flex;"><span>资源预算：
</span></span><span style="display:flex;"><span>通过门：
</span></span><span style="display:flex;"><span>失败后如何处理：
</span></span></code></pre></div><p>若一项无法填写“正式输入/输出”，它仍是 M0 概念；无法填写 matched baseline，它最多是 M2
组件；没有因果干预，不能升为 M3；没有进入统一主链，不能称为 TreeHeap 完整能力。</p>
<aside class="research-block research-claim" data-status="registered">
  <header><strong>Claim SPR-092-ROADMAP</strong><span>registered</span></header>
  <div>TreeHeap 下一阶段停止扩张核心术语，优先完成 canonical TreeState、context-conditioned WRITE、
残差 matched controls 和无旁路 READ-Decoder 闭环。只有通过这些接口门和因果门的概念，才进入
动态拓扑、稀疏运行时与规模训练。</div>
</aside>


<h1 id="最后结论">最后结论</h1>
<p>TreeHeap 当前最稀缺的不是新概念，也不是更多训练时长，而是<strong>把已有概念压缩成少数可替换、
可比较、可串联的算法接口</strong>。</p>
<p>最短主线只有四个动作：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>WRITE -&gt; FOLD -&gt; READ -&gt; DECODE
</span></span></code></pre></div><p>背景场、残差、Lifting、Butterfly 和私有协议，都必须明确自己在这四个动作中的位置。找不到位置的
概念暂存；占据相同位置的算法做 matched comparison；通过因果门的实现才进入下一层。</p>
<p>这张表不是给过去的工作判分，而是保护未来研发：我们仍然可以大胆提出问题，但每一个新词最终
都必须落成数据结构、函数签名、对照实验和可以失败的门。</p>
<blockquote>
<p><strong>License: GPLv3。路线图、Claim、证据边界与后续实验合同随 SameTime / TreeHeap 项目公开。</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-093] 让 root 真正携带条件信息：条件残差与证据 FOLD</title>
      <link>https://www.grepcode.cn/spr/093-treeheap-conditional-residual-root-signal.html</link>
      <pubDate>Thu, 01 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/093-treeheap-conditional-residual-root-signal.html</guid>
      <description>A20 在固定递归合同中把全局语料先验与 token 条件信息分开，并用概率质量加权的 common/detail FOLD 增强 root 信息；本文给出算法、toy、控制实验、正式结果与证据边界。</description>
      <content:encoded><![CDATA[<h1 id="先说结论">先说结论</h1>
<p>上一轮 A19 已经证明，共享参数的十层递归 <code>FOLD -&gt; root -&gt; READ</code> 可以训练，也确实会随着 READ
深度逐步改变输出。但它暴露了一个更重要的问题：最好的 <code>16D</code> 模型仍然略差于一个完全不看
目标 token 的全局语料先验。</p>
<p>换句话说，旧模型虽然“递归得很认真”，root 里真正属于当前 token 的信息却很弱。</p>
<p>A20 没有给 root 乘一个人为放大常数，而是做了两项结构变更：</p>
<ol>
<li>编码端不再反复搬运全语料公共背景，只编码当前 token 相对背景的<strong>条件残差</strong>；</li>
<li>FOLD 不再无条件平均左右 child，而是按它们的概率质量分别计算<strong>公共证据</strong>和<strong>差异证据</strong>。</li>
</ol>
<p>正式实验完成后，最强的 <code>16D evidence_fold</code> 得到：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">A19 <code>16D</code></th>
          <th style="text-align: right">A20 <code>16D evidence_fold</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>sealed-test NLL</td>
          <td style="text-align: right">5.572473</td>
          <td style="text-align: right"><strong>5.467703</strong></td>
      </tr>
      <tr>
          <td>PPL</td>
          <td style="text-align: right">263.084</td>
          <td style="text-align: right"><strong>236.915</strong></td>
      </tr>
      <tr>
          <td>root shuffle damage</td>
          <td style="text-align: right">0.068362</td>
          <td style="text-align: right"><strong>0.186255</strong></td>
      </tr>
      <tr>
          <td>root effective rank</td>
          <td style="text-align: right">3.758</td>
          <td style="text-align: right"><strong>8.327</strong></td>
      </tr>
      <tr>
          <td>root 平均非对角 cosine</td>
          <td style="text-align: right">0.9717</td>
          <td style="text-align: right"><strong>0.6829</strong></td>
      </tr>
  </tbody>
</table>
<p>A20 首次在这条递归 context-field codec 航线上胜过了显式全局先验：</p>
$$
5.555696-5.467703=0.087993
$$<p>这支持一个窄结论：<strong>新的 FOLD 让 root 携带了更强的 token 条件信息。</strong> 它还不证明 root 已经
形成语言语义，也不证明 TreeHeap 已经能够生成或翻译文本。</p>
<h1 id="a19-到底哪里不够">A19 到底哪里不够</h1>
<p>A19 的任务是：给定目标 token \(t\) 的 1,024 维上下文概率场 \(p(c\mid t)\)，把它逐层压缩成
一个低维 root，再通过十层 READ 恢复这 1,024 个 context coordinate 的概率。</p>
<p>它的最好结果看起来比均匀分布好很多：</p>
<table>
  <thead>
      <tr>
          <th>参考对象</th>
          <th style="text-align: right">Test NLL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1,024 维均匀分布</td>
          <td style="text-align: right">6.931472</td>
      </tr>
      <tr>
          <td>A19 <code>16D</code> 递归 codec</td>
          <td style="text-align: right">5.572473</td>
      </tr>
      <tr>
          <td>不读取 token 的全局 context prior</td>
          <td style="text-align: right"><strong>5.555696</strong></td>
      </tr>
  </tbody>
</table>
<p>问题就在第三行。只要语料里有高频 context，任何模型都可以靠全局词频取得不错的 NLL；它不
需要知道当前目标是 <code>bank</code>、<code>push</code> 还是别的 token。</p>
<p>A19 的 root-shuffle 干预进一步确认了这一点。把不同 token 的 root 随机交换以后，NLL 只恶化
<code>0.068362</code>；同时，root 之间的平均 cosine 高达 <code>0.9717</code>。这些 root 几乎都指向相同方向。</p>
<p>因此 A19 实际混合了两种信息：</p>
$$
\underbrace{\log p_{global}(c)}_{\text{所有 token 共享的语料背景}}
+
\underbrace{r_t(c)}_{\text{当前 token 的条件差异}}
$$<p>共同背景很强，条件差异很弱。模型可以主要学习第一项，并在递归地址上继续降低 NLL，却不必
把足够多的第二项送到 root。</p>
<h1 id="a20-的第一项变更只压缩条件残差">A20 的第一项变更：只压缩条件残差</h1>
<p>A20 把目标 token 的条件分布改写为：</p>
$$
r_t(c)=\log p(c\mid t)-\log p_{global}(c)
$$<p>其中：</p>
<ul>
<li>\(p(c\mid t)\) 是看见目标 token \(t\) 后，context \(c\) 出现的条件概率；</li>
<li>\(p_{global}(c)\) 是不看目标 token 时，整个语料中的 context 先验；</li>
<li>\(r_t(c)\) 只描述当前 token 相对公共背景增加或减少了多少证据。</li>
</ul>
<p>Decoder 输出时再把公共背景加回来：</p>
$$
\operatorname{logit}_t(c)
=\log p_{global}(c)+\widehat r_t(c)
$$<p>这里的 \(\widehat r_t(c)\) 必须由 <code>root -&gt; recursive READ</code> 给出。</p>
<p>这个设计建立了一个很干净的零点：如果 root 没有携带任何 token 条件信息，就令</p>
$$
\widehat r_t(c)=0
$$<p>模型便精确退回全局先验。于是，“胜过全局先验”不再是事后补做的审计，而成为模型必须跨过
的结构门槛。</p>
<h2 id="一个四坐标-toy">一个四坐标 toy</h2>
<p>假设全语料背景是：</p>
$$
p_{global}=(0.40,0.30,0.15,0.15)
$$<p>而 token <code>bank</code> 的上下文分布是：</p>
$$
p(c\mid bank)=(0.20,0.10,0.35,0.35)
$$<p>直接压缩第二个数组时，前两个高频坐标仍然占据大量表示能力。条件残差则是：</p>
$$
r_{bank}=\left(
\log\frac{0.20}{0.40},
\log\frac{0.10}{0.30},
\log\frac{0.35}{0.15},
\log\frac{0.35}{0.15}
\right)
$$<p>它明确告诉 FOLD：前两个坐标应当被抑制，后两个坐标应当被增强。root 不必重新记忆每个 token
都共有的语言背景，只需保存“bank 相对背景有什么不同”。</p>
<p>正式实现还并行输入有符号平方根差：</p>
$$
s_t(c)=\operatorname{sign}(\Delta_t(c))\sqrt{|\Delta_t(c)|},
\qquad
\Delta_t(c)=p(c\mid t)-p_{global}(c)
$$<p>所以每个 context coordinate 的 leaf feature 是二维的：对数比值提供相对证据，有符号平方根
保留概率差的方向，并减小大概率值对数值尺度的支配。</p>
<h1 id="a20-的第二项变更证据-fold">A20 的第二项变更：证据 FOLD</h1>
<p>旧 FOLD 的基本骨架接近平均：</p>
$$
h_p\approx \frac{h_l+h_r}{2}+\text{learned correction}
$$<p>但 context tree 的左右 child 往往并不具有相同概率质量。如果左侧覆盖当前 token 的 80% 概率，
右侧只有 20%，无条件平均会把小分支放大，也会把大分支压低。</p>
<p>A20 先根据 child 的真实质量计算权重：</p>
$$
a_l=\frac{m_l}{m_l+m_r},\qquad
a_r=\frac{m_r}{m_l+m_r}
$$<p>再把 parent 候选拆成两部分。</p>
<p>公共证据：</p>
$$
m=a_lh_l+a_rh_r
$$<p>差异证据：</p>
$$
d=\sqrt{a_la_r}(h_l-h_r)
$$<p>最后由每个 hidden dimension 自己选择更需要公共量还是差异量：</p>
$$
h_p=\operatorname{RMSNorm}
\left(
g_m\odot W_mm+g_d\odot W_dd
\right)
$$<p>其中 \(g_m,g_d\) 来自可训练 softmax gate，并满足每一维：</p>
$$
g_m+g_d=1
$$<p>这个公式没有固定的“递归放大系数”。信号能否进入 root，取决于概率质量、左右差异和可训练
变换，而不是每上升一层就机械地乘一个常数。</p>
<h2 id="为什么差异项带有平方根">为什么差异项带有平方根</h2>
<p>若左右质量分别是 \(0.8\) 和 \(0.2\)，则：</p>
$$
\sqrt{a_la_r}=\sqrt{0.8\times0.2}=0.4
$$<p>如果某一边几乎没有质量，例如 \(a_r\to0\)，那么：</p>
$$
\sqrt{a_la_r}\to0
$$<p>此时“左右差异”缺少双边证据，不应被当作强对比向上传播。只有左右都获得了支持，contrast
通道才会自然增强。这是由当前概率质量导出的尺度，不是手工选择的固定增益。</p>
<h1 id="三个实验臂分别回答什么">三个实验臂分别回答什么</h1>
<p>A20 在相同参数量、数据、更新次数和随机种子下比较三个实验臂：</p>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th style="text-align: right">条件残差</th>
          <th style="text-align: right">证据 FOLD</th>
          <th style="text-align: right">多深度辅助 loss</th>
          <th>用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>residual_a19</code></td>
          <td style="text-align: right">是</td>
          <td style="text-align: right">否</td>
          <td style="text-align: right">否</td>
          <td>测量只改变输入/输出基准的效果</td>
      </tr>
      <tr>
          <td><code>evidence_fold</code></td>
          <td style="text-align: right">是</td>
          <td style="text-align: right">是</td>
          <td style="text-align: right">否</td>
          <td>测量质量感知 common/detail FOLD 的增量</td>
      </tr>
      <tr>
          <td><code>evidence_multiscale</code></td>
          <td style="text-align: right">是</td>
          <td style="text-align: right">是</td>
          <td style="text-align: right">是</td>
          <td>检查直接向多个 READ 深度提供梯度是否更好</td>
      </tr>
  </tbody>
</table>
<p><code>evidence_multiscale</code> 的辅助监督作用在 READ 深度 <code>2/4/6/8</code>，权重固定为 <code>0.25</code>。它不是新的
模型容量，只是改变梯度从哪些分辨率进入共享参数。</p>
<h1 id="实验合同">实验合同</h1>
<p>正式实验在 ARA 中预注册后执行：</p>
<table>
  <thead>
      <tr>
          <th>项目</th>
          <th style="text-align: right">固定值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>语料统计</td>
          <td style="text-align: right">A14 的 100 万行 byte-identical count artifact</td>
      </tr>
      <tr>
          <td>target rows</td>
          <td style="text-align: right">512</td>
      </tr>
      <tr>
          <td>context coordinates</td>
          <td style="text-align: right">1,024</td>
      </tr>
      <tr>
          <td>递归层数</td>
          <td style="text-align: right">10</td>
      </tr>
      <tr>
          <td>hidden dimensions</td>
          <td style="text-align: right">4 / 8 / 16</td>
      </tr>
      <tr>
          <td>每臂训练</td>
          <td style="text-align: right">200 个完整 epoch</td>
      </tr>
      <tr>
          <td>split seed</td>
          <td style="text-align: right">20260924</td>
      </tr>
      <tr>
          <td>model seed</td>
          <td style="text-align: right">20261001</td>
      </tr>
      <tr>
          <td>最大参数量</td>
          <td style="text-align: right">3,297</td>
      </tr>
  </tbody>
</table>
<p>质量指标只作观察，不触发提前停止。只有 OOM、CUDA 错误、NaN/Inf、证据损坏或 reload 失败
可以终止任务。全部九个正式实验都跑满预算、数值有限，并通过 checkpoint 精确重载。</p>
<p>需要强调：1,024 个 context coordinate 的顺序仍是固定实验拓扑。A20 没有证明这个顺序最优，
也没有学习新的树拓扑。</p>
<h1 id="正式结果">正式结果</h1>
<p>全局先验 Test NLL 为 <code>5.555696</code>，PPL 为 <code>258.707</code>。</p>
<table>
  <thead>
      <tr>
          <th>实验臂</th>
          <th style="text-align: right">维度</th>
          <th style="text-align: right">参数</th>
          <th style="text-align: right">Test NLL</th>
          <th style="text-align: right">相对全局先验收益</th>
          <th style="text-align: right">root shuffle damage</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>residual_a19</code></td>
          <td style="text-align: right">4</td>
          <td style="text-align: right">249</td>
          <td style="text-align: right">5.547637</td>
          <td style="text-align: right">0.008059</td>
          <td style="text-align: right">0.022554</td>
      </tr>
      <tr>
          <td><code>residual_a19</code></td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">881</td>
          <td style="text-align: right">5.527285</td>
          <td style="text-align: right">0.028411</td>
          <td style="text-align: right">0.082830</td>
      </tr>
      <tr>
          <td><code>residual_a19</code></td>
          <td style="text-align: right">16</td>
          <td style="text-align: right">3,297</td>
          <td style="text-align: right">5.500450</td>
          <td style="text-align: right">0.055246</td>
          <td style="text-align: right">0.154666</td>
      </tr>
      <tr>
          <td><code>evidence_fold</code></td>
          <td style="text-align: right">4</td>
          <td style="text-align: right">249</td>
          <td style="text-align: right">5.541173</td>
          <td style="text-align: right">0.014523</td>
          <td style="text-align: right">0.036372</td>
      </tr>
      <tr>
          <td><code>evidence_fold</code></td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">881</td>
          <td style="text-align: right">5.511612</td>
          <td style="text-align: right">0.044084</td>
          <td style="text-align: right">0.140482</td>
      </tr>
      <tr>
          <td><code>evidence_fold</code></td>
          <td style="text-align: right">16</td>
          <td style="text-align: right">3,297</td>
          <td style="text-align: right"><strong>5.467703</strong></td>
          <td style="text-align: right"><strong>0.087993</strong></td>
          <td style="text-align: right"><strong>0.186255</strong></td>
      </tr>
      <tr>
          <td><code>evidence_multiscale</code></td>
          <td style="text-align: right">4</td>
          <td style="text-align: right">249</td>
          <td style="text-align: right">5.542355</td>
          <td style="text-align: right">0.013341</td>
          <td style="text-align: right">0.028007</td>
      </tr>
      <tr>
          <td><code>evidence_multiscale</code></td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">881</td>
          <td style="text-align: right">5.512790</td>
          <td style="text-align: right">0.042906</td>
          <td style="text-align: right">0.121891</td>
      </tr>
      <tr>
          <td><code>evidence_multiscale</code></td>
          <td style="text-align: right">16</td>
          <td style="text-align: right">3,297</td>
          <td style="text-align: right">5.477596</td>
          <td style="text-align: right">0.078100</td>
          <td style="text-align: right">0.179016</td>
      </tr>
  </tbody>
</table>
<p>三个实验臂都随 <code>4 -&gt; 8 -&gt; 16</code> 获得更好的 NLL。证据 FOLD 在每个维度都优于保留 A19 FOLD
的对照臂，因此收益不能只归因于换成条件残差坐标。</p>
<aside class="research-block research-claim" data-status="supported">
  <header><strong>Claim S1-CONDITIONAL-RESIDUAL-FOLD-A20-C01</strong><span>supported</span></header>
  <div>预注册主张得到支持：<code>evidence_multiscale</code> 至少在一个正式维度上跑满预算、保持有限、精确
reload、胜过无输入全局先验，且具有正的 root-shuffle damage 和非平坦 READ-depth curve。</div>
</aside>


<h1 id="我们怎样知道提升真的经过-root">我们怎样知道提升真的经过 root</h1>
<p>只看 NLL 还不够。A20 同时做了三种结构干预。</p>
<h2 id="1-打乱-root-身份">1. 打乱 root 身份</h2>
<p>将 token A 的 root 交给 token B 解码。如果 root 只保存所有 token 共享的公共背景，这个交换不
应明显影响结果。</p>
<p><code>16D evidence_fold</code> 的 NLL 从 <code>5.467703</code> 恶化到 <code>5.653958</code>：</p>
$$
\Delta_{shuffle}=5.653958-5.467703=0.186255
$$<p>而 A19 同类干预只有 <code>0.068362</code>。root 身份的因果作用扩大到约原来的 <code>2.72</code> 倍。</p>
<h2 id="2-关闭分支-read">2. 关闭分支 READ</h2>
<p>关闭分支 READ 后，root 只能对所有 1,024 个坐标施加相同残差。softmax 对统一常数平移不敏感，
因此结果精确退回：</p>
$$
NLL_{branchless}=5.555696
$$<p>这说明收益来自“token 条件 root 与递归地址 READ 的组合”，不是输出层偷偷复制了一个平坦偏置。</p>
<h2 id="3-测量-root-几何">3. 测量 root 几何</h2>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">A19 <code>16D</code></th>
          <th style="text-align: right">A20 <code>16D evidence_fold</code></th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>effective rank</td>
          <td style="text-align: right">3.758</td>
          <td style="text-align: right">8.327</td>
          <td>root 使用了更多独立变化方向</td>
      </tr>
      <tr>
          <td>mean off-diagonal cosine</td>
          <td style="text-align: right">0.9717</td>
          <td style="text-align: right">0.6829</td>
          <td>不同 token 的 root 不再高度共线</td>
      </tr>
  </tbody>
</table>
<p>这些指标支持“root 更有区分度”，但不能单独证明这些方向具有语言语义。随机码也可以提高 rank；
因此它们必须和 sealed-test、shuffle 以及 branchless 控制一起读取。</p>
<aside class="research-block research-evidence">
  <header><strong>Evidence E2</strong><span>A20 formal seed 20261001</span></header>
  <div>A20 建立的是机制参与性证据：root 身份、条件残差和递归 READ 对真实语料 context-field 重建
具有可测量的因果作用。单 seed 的组件实验尚不足以形成跨任务架构优势结论。</div>
</aside>


<h1 id="多深度监督没有成为最优解">多深度监督没有成为最优解</h1>
<p>预注册 Claim 选择 <code>evidence_multiscale</code> 作为主臂，是因为我们担心十层反向传播不能充分把 credit
送到 root。它确实让 READ 深度曲线更平滑：中间深度较少出现先恶化、后恢复的现象。</p>
<p>但最终深度上，普通 <code>evidence_fold</code> 反而更好：</p>
$$
5.467703 < 5.477596
$$<p>这意味着固定权重 <code>0.25</code> 的中间层目标可能限制了最终层的最优表示。当前最合理的工程选择是：</p>
<ul>
<li>保留条件残差和证据 FOLD；</li>
<li>不把固定多深度 loss 升级为默认算法；</li>
<li>后续只把它作为曲线整形、curriculum 或自适应权重候选。</li>
</ul>
<p>这也再次说明，READ 深度曲线不必单调。中间分辨率暂时变差，不等于最终递归计算无效，更不能
作为提前停止训练的理由。</p>
<h1 id="这次结果解决了什么">这次结果解决了什么</h1>
<p>A20 回答了 A19 留下的具体问题：</p>
<blockquote>
<p>不依靠固定放大常数，怎样让 token 条件信号更有效地到达 root？</p></blockquote>
<p>当前答案是：</p>
<ol>
<li>把公共语料背景放在 Decoder 基线中，不让 root 重复搬运；</li>
<li>把 root 的任务改成压缩条件残差；</li>
<li>FOLD 按 child 概率质量组合 common/detail；</li>
<li>用 root shuffle 和无分支 READ 检查信息是否真的走过 root。</li>
</ol>
<p>这使 <code>16D</code> 模型相对 A19 改善 <code>0.104770</code> NLL，并从“略差于全局先验”推进到“明确胜过全局
先验”。它是一个真实的结构进展。</p>
<h1 id="这次结果没有解决什么">这次结果没有解决什么</h1>
<p>A20 仍然只是 context-field codec，不应越界解释为完整语言模型。它没有证明：</p>
<ul>
<li>root 可以无损恢复全部 leaf；</li>
<li>context coordinate 的固定顺序就是合理拓扑；</li>
<li>root 的几何方向等于可解释语义；</li>
<li>算法能够编码句中 occurrence，而不只是 token type；</li>
<li>Decoder 能生成连续文本、完成翻译或事实问答；</li>
<li>TreeHeap 在质量、功耗或内存上优于 Transformer；</li>
<li><code>16D</code> 是最优维度；</li>
<li>单 seed 结果能跨语料、跨任务复现。</li>
</ul>
<p>还有一个距离必须正面保留。直接保存每个 token 的完整概率场时，诊断 NLL 为 <code>5.116258</code>；A20
最优结果仍然是 <code>5.467703</code>。两者相差：</p>
$$
5.467703-5.116258=0.351445
$$<p>递归瓶颈已经开始传递条件信息，但距离完整条件场仍有明显失真。</p>
<h1 id="下一步">下一步</h1>
<p>下一轮不应立刻堆更大的隐藏维度。更有信息量的动作是：</p>
<ol>
<li><strong>多 seed 复现</strong>：确认 <code>evidence_fold &gt; residual_a19</code> 不是单次初始化结果；</li>
<li><strong>拓扑置换实验</strong>：固定数据和参数预算，比较原坐标顺序、随机排列和学习排序；</li>
<li><strong>失真归因</strong>：分别测量 FOLD 压缩、root 容量和 READ 展开造成的误差；</li>
<li><strong>句中 occurrence</strong>：让相同 token 在不同上下文形成不同条件残差，检查 root 是否随语境改变；</li>
<li><strong>接入统一 TreeState</strong>：把本实验的 <code>common/detail/mass</code> 合同接到句子 Encoder 与 Decoder，
而不是继续留在独立 context-field 探针中。</li>
</ol>
<h1 id="复现入口">复现入口</h1>
<p>ARA 预注册、实现与证据位于：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/logic/conditional_residual_evidence_fold_a20.md
</span></span><span style="display:flex;"><span>ara/s1-echo/src/s1_conditional_residual_evidence_fold_a20.py
</span></span><span style="display:flex;"><span>ara/s1-echo/evidence/s1_conditional_residual_evidence_fold_a20/
</span></span></code></pre></div><p>正式证据使用 <code>seed=20261001</code>。九个正式 checkpoint 均完成 SHA-256 记录、有限值检查、完整预算
检查和精确 reload。A20 不是终点，但它把一个模糊问题变成了可计算的结构答案：<strong>root 的信息
不应靠增益硬推上去，而应先定义清楚什么值得被 root 保存。</strong></p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-094] 多尺度概率 Embedding：第一条 TreeHeap 率失真曲线</title>
      <link>https://www.grepcode.cn/spr/094-treeheap-multiscale-probability-embedding.html</link>
      <pubDate>Thu, 08 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/094-treeheap-multiscale-probability-embedding.html</guid>
      <description>T0 将 4096 维词汇条件概率场递归分解为 1/2/4/8/16 个多尺度概率区域，在留出数据上形成连续下降的 NLL 曲线并稳定优于同容量随机分区。本文解释 context 下坠、叶概率质量、embedding 形成及其证据边界。</description>
      <content:encoded><![CDATA[<h1 id="先说结论">先说结论</h1>
<p>T0 是一次词级 embedding 可行性实验。它没有训练句子 FOLD/READ，也没有生成文本；它只问一个
更靠前的问题：<strong>能否把高维词汇条件概率场压缩进一棵多尺度树，并随着读取分辨率增加，逐步
取回更多可验证的信息？</strong></p>
<p>正式实验给出了第一条清楚的曲线：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">可见概率区域数 (K)</th>
          <th style="text-align: right">TreeHeap NLL</th>
          <th style="text-align: right">随机分区 NLL</th>
          <th style="text-align: right">TreeHeap MRR</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td style="text-align: right">9.952945</td>
          <td style="text-align: right">9.952945</td>
          <td style="text-align: right">0.001171</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">8.898135</td>
          <td style="text-align: right">9.594337</td>
          <td style="text-align: right">0.011370</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">7.826886</td>
          <td style="text-align: right">9.021866</td>
          <td style="text-align: right">0.059431</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">6.909275</td>
          <td style="text-align: right">8.098312</td>
          <td style="text-align: right">0.146351</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td style="text-align: right"><strong>6.274350</strong></td>
          <td style="text-align: right"><strong>7.241480</strong></td>
          <td style="text-align: right"><strong>0.243256</strong></td>
      </tr>
  </tbody>
</table>
<p>分辨率从 <code>1 -&gt; 2 -&gt; 4 -&gt; 8 -&gt; 16</code> 增加时，TreeHeap 的留出 NLL 连续下降，MRR 连续上升；在
每个非退化尺度上，它都优于具有相同可见区域数、相同平滑和相同叶容量的随机分区。</p>
<aside class="research-block research-claim" data-status="point-estimate-supported">
  <header><strong>Claim S1-MS-PROB-EMBED-T0-C01/C02</strong><span>point-estimate-supported</span></header>
  <div>单 seed 正式实验支持两个窄主张：学习得到的 16 叶概率场在 SimLex 排序上优于匹配随机分区；学习分区的
留出检索 NLL 同时优于随机分区与只使用目标先验的模型。它尚不是跨 seed 的正式架构结论。</div>
</aside>


<p><img alt="T0 多尺度概率 embedding 的 NLL 与 MRR 曲线" decoding="async" loading="lazy" src="/spr/spr-094-multiscale-rate-distortion.svg"></p>
<h1 id="这里压缩的是什么">这里压缩的是什么</h1>
<p>实验从 WMT 英文侧抽取 200,000 行，其中 180,000 行用于构造背景场，20,000 行只用于留出测量。
词表中有 8,192 个目标 token 和 4,096 个 context token。</p>
<p>先定义训练语料的共现矩阵：</p>
$$
N_{t,c}=\operatorname{count}(\text{target }t,\text{ context }c)
$$<p>实验使用左右窗口 4。这里必须先区分两类对象：</p>
<ul>
<li><strong>沿树下坠的是 4,096 个 context token</strong>；</li>
<li><strong>最终被表示的是 8,192 个目标 token</strong>。</li>
</ul>
<p>context 先按照自己的条件分布进入树的不同路径；目标 token 再根据它与各个 context 的共现
计数，得到一组跨叶概率质量。这组概率质量才是本次实验生成的 embedding。</p>
<h1 id="context-如何从-root-下坠">context 如何从 root 下坠</h1>
<p>对每个 context (c)，构造 8,192 维条件特征：</p>
$$
x_c(t)=\sqrt{P(t\mid c)}
=\sqrt{\frac{N_{t,c}+\alpha}
{\sum_u N_{u,c}+|V_t|\alpha}}
$$<p>平方根把概率分布放进 Hellinger 几何，使 context 之间的欧氏距离能够反映条件分布差异。
context 在语料中的总质量为：</p>
$$
w_c=\sum_t N_{t,c}
$$<p>在树的某个节点 (S) 内，先计算质量加权中心：</p>
$$
\mu_S=\frac{\sum_{c\in S}w_cx_c}{\sum_{c\in S}w_c}
$$<p>再从该节点内部的质量加权协方差中求第一主轴 (a_S)，并把每个 context 投影到这条轴上：</p>
$$
q_c=(x_c-\mu_S)^\top a_S
$$<p>所有 context 按 (q_c) 排序，前一半进入左 child，后一半进入右 child。这个动作递归四层：</p>
$$
c\longrightarrow(r_1,r_2,r_3,r_4),
\qquad r_d\in\{L,R\}
$$<p>例如 <code>(L,R,L,R)</code> 就是一个 context 的叶地址。每一层都在当前局部节点重新计算主轴，所以后续
分裂不是重复 root 的同一条判别线。</p>
<p>还有一个容易混淆的细节：<strong>主轴方向受语料质量 (w_c) 加权，但左右拆分按 context 数量各取
一半。</strong> 因此每个叶节点恰好容纳 256 个 context，却不保证每个叶节点承载相同的语料概率
质量。前者控制结构容量，后者仍由真实共现统计决定。</p>
<h1 id="叶节点的概率质量从哪里来">叶节点的概率质量从哪里来</h1>
<p>树建好后，对目标 token (t) 和叶节点 (L_i)，将该叶包含的 context 共现计数相加：</p>
$$
m_t(i)=\sum_{c:\,r(c)=i}N_{t,c}
$$<p>再加平滑并归一化：</p>
$$
p_t^{(16)}(i)=
\frac{m_t(i)+\alpha}
{\sum_j m_t(j)+16\alpha}
$$<p>因此，某个叶节点对 <code>banana</code> 的概率质量较大，不是因为这个叶“更大”，而是因为 <code>banana</code> 在
语料中更多地与落到该叶的 context 共现。所有目标 token 共用同一棵 context 树，但各自拥有
不同的质量分布：</p>
$$
e(t)=\left[p_t^{(16)}(1),\ldots,p_t^{(16)}(16)\right]
$$<p>这就是 T0 的 embedding。它不是 token ID 的随机查找表：每一维都表示“目标 token 在某片
条件上下文区域中占有多少概率质量”。</p>
<p>树决定坐标轴的含义，语料计数决定 token 在各坐标上的值。若树分得没有结构，不同关系会被
混入同一坐标；若树的递归分解有效，相近的 context 会被聚合，有限维表示就能保留更多可检索
信息。这正是学习分区需要和同容量随机分区比较的原因。</p>
<h1 id="为什么它天然是多尺度的">为什么它天然是多尺度的</h1>
<p>较粗尺度不重新训练，也不创建另一套 embedding，而是把相邻子树的概率质量相加：</p>
$$
p_t^{(K)}(j)
=\sum_{i\in\operatorname{desc}(j)}p_t^{(16)}(i),
\qquad K\in\{1,2,4,8,16\}
$$<p>因此同一个 token 可以在多个尺度被读取：</p>
<ul>
<li>(K=1)：只知道总概率为 1，所有 token 完全相同；</li>
<li>(K=2)：只观察最粗的左右差异；</li>
<li>(K=4,8)：逐步暴露中尺度条件结构；</li>
<li>(K=16)：读取当前实验允许的最细概率场。</li>
</ul>
<p>一个四叶 toy 可以直观看到这个过程。假设四个叶区域分别聚合了不同的 context 群，而
<code>banana</code> 与这些区域的共现质量为 <code>55/25/12/8</code>。归一化后的细尺度状态为：</p>
$$
p_{banana}^{(4)}=(0.55,0.25,0.12,0.08)
$$<p>合并相邻叶后：</p>
$$
p_{banana}^{(2)}=(0.80,0.20)
$$<p>再合并到 root：</p>
$$
p_{banana}^{(1)}=(1.0)
$$<p>粗尺度保留“主要落在左半空间”这一事实，却丢掉左半内部的 <code>0.55/0.25</code> 区别。分辨率提升时，
被隐藏的区别重新变得可见；这正是本实验测量的压缩失真来源。</p>
<h1 id="如何把概率场用于检索">如何把概率场用于检索</h1>
<p>对留出数据中的某个查询 token (q)，先得到它在 (K) 个概率区域中的新计数 (n_q(j))。然后对
词表中的每个候选 token (t) 计算后验打分：</p>
$$
z_t^{(K)}(q)=\log\pi_t+
\sum_{j=1}^{K}n_q(j)\log p_t^{(K)}(j)
$$<p>其中 (pi_t) 是目标 token 的先验。若压缩后的概率场保留了身份相关的条件结构，正确 token
就应当在候选列表中获得更高排名。</p>
<p>NLL 测量正确答案获得的概率代价，越低越好；MRR 测量正确答案排名倒数的平均值，越高越好。
它们比只在训练计数上寻找近邻更严格，因为查询计数来自未参与建树的 20,000 行文本。</p>
<h1 id="第一条工程率失真曲线">第一条工程率失真曲线</h1>
<p>这里的“率失真”是工程近似，而不是已经完成比特量化的 Shannon rate-distortion 定理。</p>
<ul>
<li>率的代理量是每个 token 可见的概率区域数 (K)，其单纯形自由度为 (K-1)；</li>
<li>失真由留出检索 NLL 表示；</li>
<li>4,096 维完整 context 场被聚合成 16 维时，若忽略所有 token 共享的树结构和浮点量化细节，
每 token 概率数组缩小约 <code>256:1</code>。</li>
</ul>
<p>TreeHeap 的逐级 NLL 收益为：</p>
$$
\Delta D_{1\to2}=1.054810,
\quad
\Delta D_{2\to4}=1.071249,
$$$$
\Delta D_{4\to8}=0.917611,
\quad
\Delta D_{8\to16}=0.634925
$$<p>所有增量都为正，且后两级出现边际收益下降。这说明当前 16 叶概率场没有饱和到“增加尺度也没有
信息”，但也不能据此外推 32、64 或完整 4,096 维仍会按同样速度改善。</p>
<p>随机分区也会随 (K) 增加而改善，因为更多可见区域本身就增加容量。真正重要的控制是：在相同
容量下，语料条件分区始终比随机分区更低的 NLL。16 叶尺度的差值为：</p>
$$
7.241480-6.274350=0.967130
$$<p>因此，收益不能只归因于“多放了几个 float”；分区结构本身参与了信息保留。</p>
<h1 id="词频基线为什么不能当作无损上界">词频基线为什么不能当作无损上界</h1>
<p>SimLex 外部测量得到：</p>
<table>
  <thead>
      <tr>
          <th>表示</th>
          <th style="text-align: right">Spearman rho</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TreeHeap 16 叶概率场</td>
          <td style="text-align: right">0.120264</td>
      </tr>
      <tr>
          <td>随机 16 叶概率场</td>
          <td style="text-align: right">0.051110</td>
      </tr>
      <tr>
          <td>词频接近度</td>
          <td style="text-align: right">0.123533</td>
      </tr>
  </tbody>
</table>
<p>看到 <code>0.120264 &lt; 0.123533</code>，最容易产生的误读是：“TreeHeap 压缩后不如词频，所以信息丢失
过多。”这个推论不成立。</p>
<p>本实验的词频分数只是：</p>
$$
s_{freq}(i,j)=-|\log f_i-\log f_j|
$$<p>它询问两个词是否具有相近的出现频率。它没有编码 4,096 维条件概率场，也没有承担从粗到细
重构或检索的任务。因此它既不是未压缩表示，也不是零失真上界。</p>
<p>词频与人工相似度可能通过常用程度、词性、分词形态和 SimLex 样本构成发生相关。TreeHeap 在
强压缩下获得接近词频的外部相关性是值得记录的，但不能被写成“语义已经形成”；反过来，也
不能因为略低于词频就否定压缩保真度。</p>
<p>正确的结论应拆成两条：</p>
<ol>
<li><strong>压缩保真度得到初步支持</strong>：多尺度 NLL 连续改善，并稳定优于同容量随机分区；</li>
<li><strong>独立语义结构仍然开放</strong>：尚未证明 SimLex 信号在控制词频、词性和形态后仍然存在。</li>
</ol>
<h1 id="为什么老师盲评不能进入结论">为什么老师盲评不能进入结论</h1>
<p>本次还让本地 Qwen3-8B 对 120 个双顺序问题进行盲评。所有输出都能解析为 JSON，但老师只得到：</p>
<ul>
<li>SimLex 校准准确率：<code>0.725</code>，低于预注册门 <code>0.75</code>；</li>
<li>A/B 交换后的顺序一致率：<code>0.325</code>，远低于门 <code>0.90</code>。</li>
</ul>
<p>老师明显受选项顺序影响，所以全部偏好统计被作废。这里失败的是评审协议，不是 TreeHeap
embedding；同样，它也不能被解释为支持 embedding。保留这个失败结果，是为了防止主观样例在
缺乏稳定评审器时替代可复现测量。</p>
<aside class="research-block research-evidence">
  <header><strong>Evidence E2</strong><span>T0 formal seed 20261007, io task 649</span></header>
  <div>T0 提供单 seed 的机制级证据：固定语料统计可以产生优于匹配随机分区的多尺度概率坐标，且
尺度增加与留出失真下降一致。外部语义、跨语料稳定性和下游生成均未达到 E3/E4 证据强度。</div>
</aside>


<h1 id="当前能公布什么">当前能公布什么</h1>
<p>可以公布：</p>
<ul>
<li>TreeHeap 得到了一个合法、守恒、非随机的多尺度词级概率表示；</li>
<li>在 <code>1/2/4/8/16</code> 尺度上观察到连续的留出率失真曲线；</li>
<li>学习分区在相同容量下优于随机分区；</li>
<li>16 叶概率状态已经支持明显高于先验的词身份检索。</li>
</ul>
<p>不能公布为既成事实的内容包括：</p>
<ul>
<li>TreeHeap 已经解决通用 embedding；</li>
<li>这些节点天然等于人类语义类别；</li>
<li>当前表示已经处理一词多义或句中 occurrence；</li>
<li>它已经能够驱动句子 FOLD、READ、翻译或生成；</li>
<li>当前曲线已经证明移动设备上的功耗或内存优势。</li>
</ul>
<h1 id="下一步不是盲目扩大语料">下一步不是盲目扩大语料</h1>
<p>下一轮应优先提高结论的可识别性，而不是只增加样本量：</p>
<ol>
<li>用至少三个固定 seed 复现树分裂和完整曲线；</li>
<li>加入完整 4,096 维场、PCA、聚类和匹配容量投影，形成真正的压缩参照系；</li>
<li>计算控制 log-frequency 后的 SimLex 偏相关；</li>
<li>分别报告词性、词形和子词边界分组，判断当前树首先学到了什么；</li>
<li>只有词级概率场稳定后，再将同一多尺度坐标接入句中 occurrence 和后续 FOLD/READ。</li>
</ol>
<h1 id="复现入口">复现入口</h1>
<p>代码、预注册与证据位于：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/src/s1_multiscale_probability_embedding_t0.py
</span></span><span style="display:flex;"><span>ara/s1-echo/src/s1_embedding_teacher_blind_eval_t0.py
</span></span><span style="display:flex;"><span>ara/s1-echo/logic/multiscale_probability_embedding_t0.md
</span></span><span style="display:flex;"><span>ara/s1-echo/evidence/s1_multiscale_probability_embedding_t0/
</span></span></code></pre></div><p>正式任务为 io task <code>649</code>，提交归档为 SameTime commit <code>4fe229a</code>。输入语料、SentencePiece、
SimLex 和正式 summary 的 SHA-256 均保存在 evidence 中。</p>
<p>T0 还没有给出完整语义空间，但它完成了一件更基础的事：<strong>让 TreeHeap 的“分辨率”第一次不再
只是结构隐喻，而成为可以沿尺度读取、可以测量信息损失、也可以被随机对照否证的概率表示。</strong></p>
<blockquote>
<p><strong>License: GPLv3</strong></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-049] Mask Kernel：从 token 识别转向结构信息提取</title>
      <link>https://www.grepcode.cn/spr/049-mask-kernel-structure-extraction.html</link>
      <pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/049-mask-kernel-structure-extraction.html</guid>
      <description>承接 SPR-048 的私有编码森林，把下一步问题改写为：TreeHeap kernel 如何在 mask string / masked TreeHeap 上卷积，输出可坍缩的概率桶，而不是只识别单个 token。</description>
      <content:encoded><![CDATA[<h1 id="mask-kernel从-token-识别转向结构信息提取">Mask Kernel：从 token 识别转向结构信息提取</h1>
<p>SPR-048 证明了一个很小但重要的机制：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>scalar loss 可以把规律写入参数 TreeHeap forest；
</span></span><span style="display:flex;"><span>多个 head 可以串行组合；
</span></span><span style="display:flex;"><span>held-out composition 可以超过常量 baseline 和未训练 baseline。
</span></span></code></pre></div><p>但 048 仍然是一个 toy codec proof。它更像是在问：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>参数树能不能记住并组合一个有限规则？
</span></span></code></pre></div><p>现在要往前走一步。Houming818 提醒了一个更合适的问题：</p>
<blockquote>
<p>不要把目标理解成 token 识别。<br>
应该让 kernel 在一个 mask string / masked TreeHeap 上卷积，输出一个 string list，也就是可能的推理结果列表。</p></blockquote>
<p>这句话把下一阶段的 S1 任务说清楚了。</p>
<h2 id="1-不是这个-token-是谁">1. 不是“这个 token 是谁”</h2>
<p>传统 echo 任务容易把我们带偏：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：I ate rice
</span></span><span style="display:flex;"><span>输出：I ate rice
</span></span></code></pre></div><p>这里模型最容易学到的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第 3 个位置是 rice
</span></span></code></pre></div><p>这当然有用，因为 TreeHeap 必须保真。但如果一直停在这里，TreeHeap 就只是一个结构化复读机。</p>
<p>真正更接近推理的问题应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>输入：I ate [MASK]
</span></span><span style="display:flex;"><span>输出：一组可能填入 [MASK] 的东西
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_food_like(&#34;I ate [MASK]&#34;)
</span></span><span style="display:flex;"><span>  -&gt; rice, noodles, bread, apple, fish, ...
</span></span></code></pre></div><p>这里输出不再是一个确定 token，而是一个概率桶：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P(x | &#34;I ate [MASK]&#34;)
</span></span></code></pre></div><p>也就是说，模型要回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个空位在当前结构里像什么位置？
</span></span><span style="display:flex;"><span>这个位置通常能接受哪些候选？
</span></span><span style="display:flex;"><span>这些候选之间有什么可替换关系？
</span></span></code></pre></div><p>这就是结构信息提取。</p>
<h2 id="2-mask-string-如何变成-treeheap">2. Mask string 如何变成 TreeHeap</h2>
<p>先从最简单的线性句子开始：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I ate [MASK]
</span></span></code></pre></div><p>把它写入一个 TreeHeap：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>          root
</span></span><span style="display:flex;"><span>        /      \
</span></span><span style="display:flex;"><span>      left     right
</span></span><span style="display:flex;"><span>     /   \     /   \
</span></span><span style="display:flex;"><span>    I   ate  MASK  PAD
</span></span></code></pre></div><p>这棵树不是语言理论的最终形态，只是一个可计算的结构载体。</p>
<p>此时 kernel 可以在树上卷积。局部输入是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_theta(q, H_i, H_left, H_right)
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>q       = 当前 query，比如 &#34;fill MASK&#34; 或 &#34;food-like&#34;
</span></span><span style="display:flex;"><span>H_i     = 当前节点状态
</span></span><span style="display:flex;"><span>H_left  = 左子节点状态
</span></span><span style="display:flex;"><span>H_right = 右子节点状态
</span></span></code></pre></div><p>kernel 输出可以是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[p_stop, p_left, p_right]
</span></span></code></pre></div><p>表示：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>停在当前节点读取；
</span></span><span style="display:flex;"><span>继续去左子树；
</span></span><span style="display:flex;"><span>继续去右子树。
</span></span></code></pre></div><p>也可以输出一个候选 token 概率桶：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P(vocab | q, H_i, H_left, H_right)
</span></span></code></pre></div><p>更合理的设计是两者都有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route bucket:
</span></span><span style="display:flex;"><span>  stop / left / right
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fill bucket:
</span></span><span style="display:flex;"><span>  rice / noodles / apple / park / museum / ...
</span></span></code></pre></div><h2 id="3-卷积不是一次查表">3. 卷积不是一次查表</h2>
<p>如果输入是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I ate [MASK]
</span></span></code></pre></div><p>一个 naive 查表模型可能只是记住：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>&#34;I ate [MASK]&#34; -&gt; rice
</span></span></code></pre></div><p>这不是我们要的。</p>
<p>TreeHeap mask kernel 应该做的是在整棵树上滑动/递归读取：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root:
</span></span><span style="display:flex;"><span>  看到句子整体是一个主谓宾缺宾语结构
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>right:
</span></span><span style="display:flex;"><span>  看到 MASK 在宾语位置
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ate:
</span></span><span style="display:flex;"><span>  提供动词约束
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>MASK:
</span></span><span style="display:flex;"><span>  提供待坍缩位置
</span></span></code></pre></div><p>最后输出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P(token | verb=eat, slot=object, local_structure)
</span></span></code></pre></div><p>所以它不是识别 <code>rice</code>，而是提取了这样的结构：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat 的宾语位置
</span></span></code></pre></div><p>这个结构应该能支持多个答案：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rice
</span></span><span style="display:flex;"><span>noodles
</span></span><span style="display:flex;"><span>bread
</span></span><span style="display:flex;"><span>apple
</span></span><span style="display:flex;"><span>fish
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>这才是概率容器。</p>
<h2 id="4-为什么这比-token-echo-更接近推理">4. 为什么这比 token echo 更接近推理</h2>
<p>看一个 held-out 例子：</p>
<p>训练集中有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I ate rice
</span></span><span style="display:flex;"><span>I ate noodles
</span></span><span style="display:flex;"><span>I cooked rice
</span></span></code></pre></div><p>训练集中没有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I cooked noodles
</span></span></code></pre></div><p>如果模型只会 pair memory，它只能记住：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ate-rice
</span></span><span style="display:flex;"><span>ate-noodles
</span></span><span style="display:flex;"><span>cooked-rice
</span></span></code></pre></div><p>它没有理由推出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cooked-noodles
</span></span></code></pre></div><p>但如果模型学到了结构信息：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rice 和 noodles 在 ate object 位置可替换；
</span></span><span style="display:flex;"><span>rice 又出现在 cooked object 位置；
</span></span><span style="display:flex;"><span>那么 noodles 也可能适合 cooked object。
</span></span></code></pre></div><p>这就是一种很小的归纳迁移。</p>
<p>它还不是完整自然语言理解，但已经不是简单 token 识别。</p>
<h2 id="5-claim">5. Claim</h2>
<p>下一步可以立这个 Claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-MASK-KERNEL-C01
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TreeHeap mask kernel can convolve over a masked string / masked TreeHeap state
</span></span><span style="display:flex;"><span>and output a probability bucket of structurally plausible fillers, rather than
</span></span><span style="display:flex;"><span>only reconstructing an observed token.
</span></span></code></pre></div><p>中文说法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap mask kernel 能在带 mask 的句子结构上做卷积，
</span></span><span style="display:flex;"><span>提取 mask 所在位置的结构约束，
</span></span><span style="display:flex;"><span>并输出一组候选填充值的概率桶。
</span></span></code></pre></div><p>注意它的重点不是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>能不能猜中某一个 token。
</span></span></code></pre></div><p>重点是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>候选列表是否像一个结构类；
</span></span><span style="display:flex;"><span>held-out 组合是否能迁移；
</span></span><span style="display:flex;"><span>shuffled corpus 是否会破坏这种能力。
</span></span></code></pre></div><h2 id="6-predict">6. Predict</h2>
<p>如果这个 Claim 成立，我们应该看到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P1. &#34;I ate [MASK]&#34; 的 top-k 候选偏向可食用对象；
</span></span><span style="display:flex;"><span>P2. &#34;I visited [MASK]&#34; 的 top-k 候选偏向地点；
</span></span><span style="display:flex;"><span>P3. &#34;I drank [MASK]&#34; 的 top-k 候选偏向饮品；
</span></span><span style="display:flex;"><span>P4. held-out pair 的候选排名高于 pair-memory baseline；
</span></span><span style="display:flex;"><span>P5. shuffled corpus control 会显著变差；
</span></span><span style="display:flex;"><span>P6. 输出是有熵的概率桶，不应过早坍缩成一个 token。
</span></span></code></pre></div><p>“有熵”不是说越乱越好，而是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>模型在信息不足时应该保留多个合理候选。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I ate [MASK]
</span></span></code></pre></div><p>如果输出只有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rice: 0.99
</span></span></code></pre></div><p>反而可能说明模型在记忆训练集。</p>
<p>更合理的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rice:    0.20
</span></span><span style="display:flex;"><span>noodles: 0.16
</span></span><span style="display:flex;"><span>bread:   0.12
</span></span><span style="display:flex;"><span>apple:   0.10
</span></span><span style="display:flex;"><span>fish:    0.08
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>然后后续上下文再继续坍缩。</p>
<h2 id="7-最小数据集">7. 最小数据集</h2>
<p>先不要直接上 WMT。第一步应该用 controlled corpus，因为我们需要知道模型到底学到了什么。</p>
<p>例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I ate rice
</span></span><span style="display:flex;"><span>I ate noodles
</span></span><span style="display:flex;"><span>I ate apple
</span></span><span style="display:flex;"><span>I ate bread
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>I cooked rice
</span></span><span style="display:flex;"><span>I cooked noodles
</span></span><span style="display:flex;"><span>I cooked fish
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>I drank water
</span></span><span style="display:flex;"><span>I drank milk
</span></span><span style="display:flex;"><span>I drank juice
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>I visited Paris
</span></span><span style="display:flex;"><span>I visited Beijing
</span></span><span style="display:flex;"><span>I visited museum
</span></span><span style="display:flex;"><span>I visited park
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>I bought rice
</span></span><span style="display:flex;"><span>I bought medicine
</span></span><span style="display:flex;"><span>I bought apple
</span></span></code></pre></div><p>训练时把一部分句子 mask：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I ate [MASK]     -&gt; rice / noodles / apple / bread
</span></span><span style="display:flex;"><span>I drank [MASK]   -&gt; water / milk / juice
</span></span><span style="display:flex;"><span>I visited [MASK] -&gt; Paris / Beijing / museum / park
</span></span></code></pre></div><p>然后保留一些未见组合：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I cooked apple
</span></span><span style="display:flex;"><span>I cooked bread
</span></span><span style="display:flex;"><span>I bought noodles
</span></span><span style="display:flex;"><span>I visited garden
</span></span></code></pre></div><p>如果模型能把这些候选排到合理位置，才说明它提取了结构。</p>
<h2 id="8-模型形式">8. 模型形式</h2>
<p>一个最小 TreeHeap mask kernel 可以这样写：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>masked sentence
</span></span><span style="display:flex;"><span>  -&gt; WriteLeaves(tokens, mask_marker)
</span></span><span style="display:flex;"><span>  -&gt; Compose bottom-up
</span></span><span style="display:flex;"><span>  -&gt; for each node:
</span></span><span style="display:flex;"><span>       K_theta(q, H_i, H_left, H_right)
</span></span><span style="display:flex;"><span>  -&gt; aggregate mask-position state
</span></span><span style="display:flex;"><span>  -&gt; softmax over vocab
</span></span></code></pre></div><p>损失函数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L_mask = CE(P_theta(token | masked_tree), gold_token)
</span></span></code></pre></div><p>但单 token CE 容易鼓励过早坍缩，所以评估时不能只看 top1。</p>
<p>还要看：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>top5 / top10
</span></span><span style="display:flex;"><span>MRR
</span></span><span style="display:flex;"><span>bucket purity
</span></span><span style="display:flex;"><span>held-out rank
</span></span><span style="display:flex;"><span>entropy
</span></span><span style="display:flex;"><span>structured-vs-shuffled gap
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>bucket purity
</span></span></code></pre></div><p>不是训练信号，只用于审计：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I ate [MASK] 的 top10 里有多少属于 food-like？
</span></span><span style="display:flex;"><span>I visited [MASK] 的 top10 里有多少属于 place-like？
</span></span></code></pre></div><h2 id="9-baseline">9. Baseline</h2>
<p>必须放 baseline，否则 proof 没意义。</p>
<p>最少要有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pair memory:
</span></span><span style="display:flex;"><span>  只记 seen context-token pair
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>BoW MLP:
</span></span><span style="display:flex;"><span>  不看树结构，只看 bag-of-words
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>flat sequence MLP:
</span></span><span style="display:flex;"><span>  看位置，但没有 TreeHeap 子结构卷积
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>shuffled corpus:
</span></span><span style="display:flex;"><span>  保持 token 频率，打乱 context-token 关系
</span></span></code></pre></div><p>TreeHeap 的价值不在于训练集 top1 高，而在于：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>held-out pair rank 更好；
</span></span><span style="display:flex;"><span>top-k bucket 更合理；
</span></span><span style="display:flex;"><span>shuffled control 明显失败；
</span></span><span style="display:flex;"><span>相同参数量下比 flat baseline 更稳。
</span></span></code></pre></div><h2 id="10-proof-gate">10. Proof Gate</h2>
<p>第一版 proof gate 可以保守一点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap heldout MRR &gt; pair memory heldout MRR
</span></span><span style="display:flex;"><span>TreeHeap heldout MRR &gt; shuffled TreeHeap heldout MRR
</span></span><span style="display:flex;"><span>TreeHeap bucket purity &gt; shuffled bucket purity
</span></span><span style="display:flex;"><span>TreeHeap top5 &gt; pair memory top5
</span></span><span style="display:flex;"><span>entropy 落在合理范围，不能完全坍缩
</span></span></code></pre></div><p>如果 BoW MLP 赢了，也不是世界末日。那说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这个 toy 数据还没有要求 TreeHeap 结构；
</span></span><span style="display:flex;"><span>或者 kernel 设计没有真正用到子结构。
</span></span></code></pre></div><p>这会反过来帮助我们改数据和模型。</p>
<h2 id="11-ara-草案">11. ARA 草案</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Claim:
</span></span><span style="display:flex;"><span>  S1-MASK-KERNEL-C01
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Predict:
</span></span><span style="display:flex;"><span>  Masked TreeHeap convolution produces structurally plausible probability
</span></span><span style="display:flex;"><span>  buckets and transfers to held-out context-token combinations.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Proof:
</span></span><span style="display:flex;"><span>  Train on controlled masked corpus.
</span></span><span style="display:flex;"><span>  Compare TreeHeap mask kernel against pair memory, BoW MLP, flat sequence MLP,
</span></span><span style="display:flex;"><span>  and shuffled-corpus control.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Evidence:
</span></span><span style="display:flex;"><span>  summary.json
</span></span><span style="display:flex;"><span>  trace.jsonl
</span></span><span style="display:flex;"><span>  topk_examples.json
</span></span><span style="display:flex;"><span>  README.md
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Falsification:
</span></span><span style="display:flex;"><span>  If shuffled corpus matches TreeHeap, structure was not learned.
</span></span><span style="display:flex;"><span>  If pair memory matches held-out rank, no transfer occurred.
</span></span><span style="display:flex;"><span>  If BoW/flat baselines dominate, TreeHeap kernel has not shown added value.
</span></span><span style="display:flex;"><span>  If output always collapses to one token, probability-container behavior is absent.
</span></span></code></pre></div><h2 id="12-当前结论">12. 当前结论</h2>
<p>SPR-048 说的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>参数 TreeHeap forest 可以被 loss 写入，并能做串行组合。
</span></span></code></pre></div><p>SPR-049 要推进的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 在 masked TreeHeap 上卷积，读出的不是一个 token，
</span></span><span style="display:flex;"><span>而是一个结构位置对应的候选概率桶。
</span></span></code></pre></div><p>这一步如果成立，S1 的目标就会更清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先不要问 TreeHeap 是否懂语言；
</span></span><span style="display:flex;"><span>先问它是否能从语料观察里提取可复用的结构槽位，
</span></span><span style="display:flex;"><span>并用 kernel 输出可坍缩的推理候选列表。
</span></span></code></pre></div><p>这才是从 echo 走向 encoder/world-observer 的下一块台阶。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-048] TreeHeap 私有编码：多头参数森林与串行推理</title>
      <link>https://www.grepcode.cn/spr/048-treeheap-private-codec-forest.html</link>
      <pubDate>Thu, 09 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/048-treeheap-private-codec-forest.html</guid>
      <description>从经典 Huffman 编码出发，定义 TreeHeap 参数森林、私有编码、并行多头和串行 kernel composition，并说明 scalar loss 如何把数据写入参数树。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-私有编码多头参数森林与串行推理">TreeHeap 私有编码：多头参数森林与串行推理</h1>
<p>这篇文章承接 SPR-046 和 SPR-047，进入新的问题：</p>
<blockquote>
<p>一个空的 TreeHeap 工作区，为什么经过若干 query kernel 的卷积，就能解压出一组数据？这些数据最初又是怎样编码进一棵或多棵参数 TreeHeap 的？</p></blockquote>
<p>我们先不讨论自然语言理解，也不假设模型已经知道“食物”“水果”等概念。先建立一个有限、可以计算和证伪的模型。</p>
<h2 id="1-从一个具体例子开始">1. 从一个具体例子开始</h2>
<p>假设执行 <code>food</code> kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H0 = [0, 0, 0, 0]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>K_food(H0; Theta)
</span></span><span style="display:flex;"><span>  -&gt; [0.1 稻子, 0.3 米浆, 0.5 米饭, 0.6 芒果]
</span></span></code></pre></div><p>再执行 <code>fruit</code> kernel：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_fruit(K_food(H0; Theta); Theta2)
</span></span><span style="display:flex;"><span>  -&gt; [0.6 芒果]
</span></span></code></pre></div><p>这里马上出现一个必须说清楚的事实：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>零数组里没有稻子、米浆、米饭和芒果。
</span></span></code></pre></div><p>因此，这些信息一定保存在参数 <code>Theta</code> 及其树形组织关系中。<code>H0</code> 只是一次查询使用的工作区。</p>
<p>本文采用以下术语：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta_forest 长期保存的一组参数 TreeHeap，也就是编码森林
</span></span><span style="display:flex;"><span>H_query     一次查询产生的运行时状态
</span></span><span style="display:flex;"><span>K_q         针对 query q 执行的卷积 kernel
</span></span><span style="display:flex;"><span>leaf        可以最终解码出的数据对象
</span></span><span style="display:flex;"><span>internal    一组叶子共享的前缀状态
</span></span></code></pre></div><h2 id="2-经典-huffman-到底怎样写入和读出">2. 经典 Huffman 到底怎样写入和读出</h2>
<p>假设四个符号出现的概率为：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th style="text-align: right">概率</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>米饭</td>
          <td style="text-align: right">0.4</td>
      </tr>
      <tr>
          <td>米浆</td>
          <td style="text-align: right">0.3</td>
      </tr>
      <tr>
          <td>稻子</td>
          <td style="text-align: right">0.2</td>
      </tr>
      <tr>
          <td>石头</td>
          <td style="text-align: right">0.1</td>
      </tr>
  </tbody>
</table>
<p>经典 Huffman 算法不断合并概率最小的两个节点，可能得到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>├─ 0   -&gt; 米饭
</span></span><span style="display:flex;"><span>└─ 1
</span></span><span style="display:flex;"><span>   ├─ 10  -&gt; 米浆
</span></span><span style="display:flex;"><span>   └─ 11
</span></span><span style="display:flex;"><span>      ├─ 110 -&gt; 石头
</span></span><span style="display:flex;"><span>      └─ 111 -&gt; 稻子
</span></span></code></pre></div><p>对应码表：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>米饭 = 0
</span></span><span style="display:flex;"><span>米浆 = 10
</span></span><span style="display:flex;"><span>石头 = 110
</span></span><span style="display:flex;"><span>稻子 = 111
</span></span></code></pre></div><p>编码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>米饭 石头 稻子
</span></span><span style="display:flex;"><span>-&gt; 0 110 111
</span></span><span style="display:flex;"><span>-&gt; 0110111
</span></span></code></pre></div><p>解码时，从 root 开始逐位行走。到达叶子便输出符号，然后返回 root。</p>
<p>这里有两个重要性质：</p>
<ol>
<li>高频符号使用较短路径；</li>
<li>任何叶子的编码都不是另一个叶子编码的前缀，因此可以无歧义解码。</li>
</ol>
<p>但是，经典 Huffman 只根据出现频率压缩。它不会因为“米饭”和“米浆”在语义上相似，就主动让它们共享前缀。</p>
<h2 id="3-treeheap-增加了什么">3. TreeHeap 增加了什么</h2>
<p>TreeHeap 的假设是：一棵树不仅可以压缩符号频率，还可以压缩查询规律。</p>
<p>例如，一棵候选参数树可能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>└─ food
</span></span><span style="display:flex;"><span>   ├─ grain-family
</span></span><span style="display:flex;"><span>   │  ├─ 稻子
</span></span><span style="display:flex;"><span>   │  └─ processed
</span></span><span style="display:flex;"><span>   │     ├─ 米浆
</span></span><span style="display:flex;"><span>   │     └─ 米饭
</span></span><span style="display:flex;"><span>   └─ fruit
</span></span><span style="display:flex;"><span>      └─ 芒果
</span></span></code></pre></div><p>路径可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>稻子 = 000
</span></span><span style="display:flex;"><span>米浆 = 0010
</span></span><span style="display:flex;"><span>米饭 = 0011
</span></span><span style="display:flex;"><span>芒果 = 01
</span></span></code></pre></div><p>现在，不同 query 可以在不同深度停止：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>food query
</span></span><span style="display:flex;"><span>  -&gt; 到达 food
</span></span><span style="display:flex;"><span>  -&gt; 解压 food 节点覆盖的全部叶子
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fruit query
</span></span><span style="display:flex;"><span>  -&gt; 到达 fruit
</span></span><span style="display:flex;"><span>  -&gt; 只解压 fruit 节点覆盖的叶子
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>exact token query
</span></span><span style="display:flex;"><span>  -&gt; 一直走到具体叶子
</span></span><span style="display:flex;"><span>  -&gt; 输出米饭或芒果
</span></span></code></pre></div><p>因此，<code>stop</code> 不一定表示“读到了一个词”。它也可以表示：</p>
<blockquote>
<p>当前内部节点已经包含回答 query 所需的全部信息。</p></blockquote>
<h2 id="4-路径编码和输出概率不是一回事">4. 路径编码和输出概率不是一回事</h2>
<p>下面两个对象容易混淆：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Path(米饭) = 0011
</span></span><span style="display:flex;"><span>P(米饭 | food) = 0.5
</span></span></code></pre></div><p><code>0011</code> 是米饭在参数树中的地址。</p>
<p><code>0.5</code> 是当前 query 下米饭的分数或概率。</p>
<p>如果输出被解释为概率分布，就必须归一化：</p>
$$ \sum_x P(x\mid q)=1 $$<p>而路径只要求前缀无歧义，不要求数值加和为 1。</p>
<h2 id="5-kernel-如何查询一棵树">5. Kernel 如何查询一棵树</h2>
<p>在节点 \(i\) 上，局部 kernel 读取：</p>
$$ K_\Theta(q,H_i,H_{2i},H_{2i+1}) $$<p>并输出一个概率桶：</p>
$$ [p_{\text{stop}},p_{\text{left}},p_{\text{right}}] $$<p>例如 <code>fruit</code> query：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root:
</span></span><span style="display:flex;"><span>  [stop=0.00, left=0.05, right=0.95]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>food:
</span></span><span style="display:flex;"><span>  [stop=0.02, grain=0.03, fruit=0.95]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fruit:
</span></span><span style="display:flex;"><span>  [stop=0.99, left=0.005, right=0.005]
</span></span></code></pre></div><p>一条路径的概率是沿途动作概率的乘积：</p>
$$ P(\pi\mid q) = \prod_{i\in\pi}P(a_i\mid q,H_i) $$<p>到达某个内部节点并选择 <code>stop</code> 后，decoder 可以读取该节点保存的叶子分布：</p>
$$ Decode(H_i,q)\rightarrow P(x\mid q,H_i) $$<p>所以完整读出过程是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query
</span></span><span style="display:flex;"><span>-&gt; kernel 在参数树上递归卷积
</span></span><span style="display:flex;"><span>-&gt; 得到 stop/left/right 概率
</span></span><span style="display:flex;"><span>-&gt; 形成路径分布
</span></span><span style="display:flex;"><span>-&gt; 在某个节点停止
</span></span><span style="display:flex;"><span>-&gt; 解压该节点的叶子分布
</span></span></code></pre></div><p>硬查询可以每步选择 <code>argmax</code>。软查询则保留多条路径，直到信息足够时再坍缩。</p>
<h2 id="6-encoder-面对的原始数据是什么">6. Encoder 面对的原始数据是什么</h2>
<p>Encoder 不能从“空”中发现分类。它至少需要观察到查询与结果之间的统计关系。</p>
<p>一个有限数据集可以表示成矩阵：</p>
<table>
  <thead>
      <tr>
          <th>Query</th>
          <th style="text-align: right">稻子</th>
          <th style="text-align: right">米浆</th>
          <th style="text-align: right">米饭</th>
          <th style="text-align: right">芒果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>food</td>
          <td style="text-align: right">0.1</td>
          <td style="text-align: right">0.3</td>
          <td style="text-align: right">0.5</td>
          <td style="text-align: right">0.6</td>
      </tr>
      <tr>
          <td>fruit</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0.6</td>
      </tr>
      <tr>
          <td>grain</td>
          <td style="text-align: right">0.1</td>
          <td style="text-align: right">0.3</td>
          <td style="text-align: right">0.5</td>
          <td style="text-align: right">0</td>
      </tr>
      <tr>
          <td>processed</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0.3</td>
          <td style="text-align: right">0.5</td>
          <td style="text-align: right">0</td>
      </tr>
  </tbody>
</table>
<p>这张表不一定来自人工标签。未来它可以来自语料观察，例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>“吃 [MASK]”经常观察到米饭
</span></span><span style="display:flex;"><span>“喝 [MASK]”经常观察到米浆
</span></span><span style="display:flex;"><span>“成熟的 [MASK]”经常观察到芒果
</span></span></code></pre></div><p>但无论来源是什么，encoder 真正看到的是某种有限统计量：</p>
$$ P_D(x\mid q) $$<p>也就是在数据 \(D\) 中，query \(q\) 对对象 \(x\) 的条件分布。</p>
<h2 id="7-encoder-不是人工聚类器">7. Encoder 不是人工聚类器</h2>
<p>一种看似直接的方案是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先计算对象之间的相似度；
</span></span><span style="display:flex;"><span>再人工规定合并距离；
</span></span><span style="display:flex;"><span>最后按距离构造语义树。
</span></span></code></pre></div><p>这个方案仍然是研究者替模型设计编码。即使最终树看起来合理，也不能说明 encoder 和 decoder 形成了自己的关联编码。</p>
<p>本文采用更严格的定义：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>人提供：
</span></span><span style="display:flex;"><span>  有限 TreeHeap 地址
</span></span><span style="display:flex;"><span>  stop/left/right
</span></span><span style="display:flex;"><span>  compose/decompose
</span></span><span style="display:flex;"><span>  可微 kernel
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>人不提供：
</span></span><span style="display:flex;"><span>  哪个节点是 food
</span></span><span style="display:flex;"><span>  哪些对象必须共享前缀
</span></span><span style="display:flex;"><span>  哪个 token 写在哪条路径
</span></span><span style="display:flex;"><span>  每个 head 必须学习什么类别
</span></span></code></pre></div><p>参数 TreeHeap 从零或随机状态开始：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta[i] = learnable parameters
</span></span></code></pre></div><p>给定 query \(q\)，kernel 对参数树执行卷积：</p>
$$ \hat Y_q=K_q(\Theta) $$<p>数据提供该 query 的目标结果 \(Y_q\)，于是得到一个标量 loss：</p>
$$ L_q=d(\hat Y_q,Y_q) $$<p>多个 query 共同训练参数树：</p>
$$ L(\Theta)=\sum_q L_q $$<p>梯度直接写入参数 TreeHeap：</p>
$$ \Theta \leftarrow \Theta-\eta\frac{\partial L}{\partial\Theta} $$<p>因此：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Encoder：
</span></span><span style="display:flex;"><span>  用 query 产生的 scalar loss，把规律写入参数 TreeHeap。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Decoder：
</span></span><span style="display:flex;"><span>  用 query kernel 从训练后的参数 TreeHeap 解压结果。
</span></span></code></pre></div><p>内部编码可以不符合人类命名。只要 encode、query、decode 闭合，模型可以形成自己的“笔迹”。</p>
<h2 id="8-为什么还需要压缩约束">8. 为什么还需要压缩约束</h2>
<p>只优化 query 正确率，模型可能把每个答案分别记在巨大参数表里。它虽然能查询，却没有形成有价值的编码。</p>
<p>因此还需要限制平均编码成本：</p>
$$ L_{\text{rate}} = \mathbb E[-\log P_\Theta(path)] $$<p>或者先使用简单的期望路径深度：</p>
$$ L_{\text{depth}} = \mathbb E[\operatorname{depth}(path)] $$<p>总目标可以写成：</p>
$$ L = L_{\text{query}} + \alpha L_{\text{echo}} + \beta L_{\text{rate}} $$<p>三部分分别要求：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query：能回答问题；
</span></span><span style="display:flex;"><span>echo：私有编码仍能还原原始数据；
</span></span><span style="display:flex;"><span>rate：不要为每个样本建立无限长、互不共享的路径。
</span></span></code></pre></div><p>这里没有人工规定共享前缀。只有当共享某个子堆能降低总 loss 时，它才应该形成。</p>
<h2 id="9-写入究竟发生在哪里">9. 写入究竟发生在哪里</h2>
<p>必须区分两种“写入”。</p>
<h3 id="91-训练参数森林">9.1 训练参数森林</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Train(D)
</span></span><span style="display:flex;"><span>-&gt; 修改 Theta_forest
</span></span><span style="display:flex;"><span>-&gt; 改变节点状态、路径概率和 kernel 参数
</span></span></code></pre></div><p>这相当于学习和更新码本。</p>
<h3 id="92-使用参数森林编码一个样本">9.2 使用参数森林编码一个样本</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Encode(sample, Theta_forest)
</span></span><span style="display:flex;"><span>-&gt; 生成路径或运行时 H_sample
</span></span></code></pre></div><p>这相当于使用已经存在的码本压缩一条消息，通常不修改长期参数树。</p>
<p>因此：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta_forest 保存长期规律
</span></span><span style="display:flex;"><span>H_sample 保存当前样本
</span></span><span style="display:flex;"><span>H_query 保存本次查询过程
</span></span></code></pre></div><p>如果 <code>H0=[0,0,0,0]</code> 经过 kernel 能生成具体对象，那么具体对象的信息来自 <code>Theta_forest</code>，不能说它来自零状态。</p>
<h2 id="10-encoder-和-decoder-的共同协议">10. Encoder 和 Decoder 的共同协议</h2>
<p>Transformer 的 encoder、decoder 和 cross-attention 都使用同一种 Attention 数学接口，但通常不共享同一套参数。</p>
<p>TreeHeap 也可以采用类似的接口纪律，但这只是接口设计，不是 Transformer 有效性向 TreeHeap 的自动迁移。</p>
<p>共同协议可以定义为：</p>
$$ K(q,H_i,H_{2i},H_{2i+1}) \rightarrow [p_{\text{stop}},p_{\text{left}},p_{\text{right}}] $$<p>Encoder 使用它评估：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个对象写入哪个前缀，能让整个数据集更容易重建。
</span></span></code></pre></div><p>Decoder 使用它完成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>一个 query 应沿哪条路径读取，并在哪个节点停止。
</span></span></code></pre></div><p>双方必须共享：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>相同的地址规则
</span></span><span style="display:flex;"><span>相同的路径含义
</span></span><span style="display:flex;"><span>相同的节点 compose/decompose 规则
</span></span><span style="display:flex;"><span>相同的 kernel 输入输出契约
</span></span></code></pre></div><p>它们不必共享完全相同的权重。</p>
<h2 id="11-为什么不要求所有信息写进同一棵树">11. 为什么不要求所有信息写进同一棵树</h2>
<p>一棵共享参数树适合表达公共前缀，但它不是 TreeHeap 的理论限制。更一般的参数对象是：</p>
$$ \Theta_{\text{forest}} = \{\Theta^{(1)},\Theta^{(2)},\ldots,\Theta^{(M)}\} $$<p>每个 head 都是一棵 TreeHeap。它们共享地址和 kernel 协议，但可以拥有不同的节点值、深度和参数。</p>
<h3 id="111-并行多头">11.1 并行多头</h3>
<p>多个 head 可以同时观察同一个状态：</p>
$$ H_m=K_m(q,H_0;\Theta^{(m)}) $$<p>再通过明确的 TreeHeap compose 算子合并：</p>
$$ H_{\text{out}} = \operatorname{Compose}(H_1,H_2,\ldots,H_M) $$<p>这种结构允许不同参数树保留不同的可学习关系，不要求它们被压进同一个梯度大锅。</p>
<h3 id="112-串行推理">11.2 串行推理</h3>
<p>更重要的是 kernel 可以顺序组合：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H0 = [0,0,0,0]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>H1 = K_food(H0; Theta_food)
</span></span><span style="display:flex;"><span>   = [0.1稻子, 0.3米浆, 0.5米饭, 0.6芒果]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>H2 = K_fruit(H1; Theta_fruit)
</span></span><span style="display:flex;"><span>   = [0.6芒果]
</span></span></code></pre></div><p>数学上：</p>
$$ H_2 = K_{\text{fruit}} \left( K_{\text{food}}(H_0;\Theta_{\text{food}}); \Theta_{\text{fruit}} \right) $$<p>也就是：</p>
$$ K_{\text{fruit}}\circ K_{\text{food}} $$<p>这使 TreeHeap 不只是保存查询答案，还可能保存可组合的操作。</p>
<h2 id="12-连续查表不等于串行推理">12. 连续查表不等于串行推理</h2>
<p>如果 <code>Theta_fruit</code> 直接记住：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>fruit query -&gt; 芒果
</span></span></code></pre></div><p>那么连续执行两个 query 仍然只是两次查表。</p>
<p>真正的 <code>fruit</code> kernel 应当对不同输入状态执行同一过滤规律：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[苹果, 石头, 芒果] -&gt; [苹果, 芒果]
</span></span><span style="display:flex;"><span>[稻子, 米饭, 芒果] -&gt; [芒果]
</span></span><span style="display:flex;"><span>[香蕉, 汽车, 梨]   -&gt; [香蕉, 梨]
</span></span></code></pre></div><p>所以必须把以下组合留出训练集：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>K_fruit(K_food(H0))
</span></span></code></pre></div><p>分别训练 <code>food</code> head 和 <code>fruit</code> head 后，第一次在测试中组合它们。只有未见组合仍然正确，才能支持“kernel 学会了算子”而不是“参数树记住了答案”。</p>
<h2 id="13-一个重要限制树只能自然表达嵌套集合">13. 一个重要限制：树只能自然表达嵌套集合</h2>
<p>如果：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>fruit 是 food 的子集
</span></span></code></pre></div><p>一棵树可以自然表达。</p>
<p>但真实世界存在重叠分类：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>番茄在植物学中是水果
</span></span><span style="display:flex;"><span>番茄在烹饪中又常被视为蔬菜
</span></span></code></pre></div><p>单棵严格二叉树无法让一个叶子同时拥有两条独立父路径。</p>
<p>可能的扩展包括：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>多个 TreeHeap
</span></span><span style="display:flex;"><span>一个叶子对应多条概率路径
</span></span><span style="display:flex;"><span>TreeHeap DAG
</span></span></code></pre></div><p>第一阶段不应同时解决这个问题。我们可以先使用严格嵌套的有限数据，验证最基本的编码和解码闭环。</p>
<h2 id="14-下一步可证伪实验">14. 下一步可证伪实验</h2>
<p>第一项实验只需要四到八个对象、四到八种 query，以及两棵小参数 TreeHeap。</p>
<h3 id="claim">Claim</h3>
<p>存在一个有限参数 TreeHeap forest，使 scalar query loss 能把数据写入各参数树，并使独立训练的 kernel 在未见串行组合上正确闭合。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>较低的 query 重建误差
</span></span><span style="display:flex;"><span>较短的平均编码长度
</span></span><span style="display:flex;"><span>前缀无歧义的精确 echo
</span></span><span style="display:flex;"><span>未见 kernel composition 的正确输出
</span></span></code></pre></div><h3 id="predict">Predict</h3>
<p>如果 head 学到的是可迁移算子，那么 <code>fruit</code> kernel 在训练时未见过 <code>food</code> head 输出的情况下，仍应正确过滤 <code>food</code> 的运行时状态。</p>
<p>如果它只记住 query 到答案的映射，未见组合应当失败。</p>
<h3 id="proof">Proof</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 将 `Theta_food` 和 `Theta_fruit` 初始化为零或随机参数树；
</span></span><span style="display:flex;"><span>2. 用各自 query 的 scalar loss 独立训练两棵树；
</span></span><span style="display:flex;"><span>3. 保存每个节点的 loss、梯度和参数变化；
</span></span><span style="display:flex;"><span>4. 验证只保存参数森林即可重新解压训练 query；
</span></span><span style="display:flex;"><span>5. 测试训练时保留的 `K_fruit ∘ K_food` 组合；
</span></span><span style="display:flex;"><span>6. 与两个独立查找表、单棵共享树和 shuffled control 比较；
</span></span><span style="display:flex;"><span>7. 清空、打乱或交换子堆，检查查询与组合能力是否下降。
</span></span></code></pre></div><h3 id="falsification">Falsification</h3>
<p>以下任一结果都会削弱当前假设：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>query 或答案被偷偷放进运行时 H；
</span></span><span style="display:flex;"><span>每个 head 只记住固定输出，不能过滤新输入；
</span></span><span style="display:flex;"><span>未见串行组合明显失败；
</span></span><span style="display:flex;"><span>清空或打乱参数树以后结果不变；
</span></span><span style="display:flex;"><span>扁平查找表在相同存储和计算预算下全面更好。
</span></span></code></pre></div><h2 id="15-当前结论">15. 当前结论</h2>
<p>本文没有证明 TreeHeap 已经学会食物、水果或自然语言语义。</p>
<p>它只把问题缩小为一个可以执行的数学任务：</p>
<blockquote>
<p>给定有限的 <code>query -&gt; result distribution</code>，scalar loss 能否把规律写进一个参数 TreeHeap forest，并让各 head 通过相同代数协议并行观察、串行组合和无歧义解码？</p></blockquote>
<p>如果答案是否定的，就不必继续讨论梯度涌现。</p>
<p>如果答案是肯定的，下一步才是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>先证明 loss 的梯度确实写入参数树
</span></span><span style="display:flex;"><span>-&gt; 再证明 encoder/decoder 能形成私有路径编码
</span></span><span style="display:flex;"><span>-&gt; 再证明独立 head 能完成未见组合
</span></span><span style="display:flex;"><span>-&gt; 最后研究树结构和 head 数量能否自行形成
</span></span></code></pre></div><p>TreeHeap 不必只有一棵树，也不必让人类理解内部节点。真正的边界是：信息必须保存在参数树中，query 不能携带答案，kernel 必须在新状态上执行可复用操作，而不是连续查表。</p>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-047] TreeHeap Encoder：世界观察者如何把规律写进树</title>
      <link>https://www.grepcode.cn/spr/047-treeheap-encoder-world-observer.html</link>
      <pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/047-treeheap-encoder-world-observer.html</guid>
      <description>SPR-047 把问题从 route/read 推回 encoder：TreeHeap 的语义结构不能靠哲学假设写入，必须由 encoder 通过 echo、上下文预测、InfoNCE、替换一致性和描述长度等可压缩性信号，从观察数据中学出 placement、fold 和 prefix。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-encoder世界观察者如何把规律写进树">TreeHeap Encoder：世界观察者如何把规律写进树</h1>
<p>我们需要把问题退回更前面。</p>
<p>之前讨论了很多：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route 怎么走
</span></span><span style="display:flex;"><span>root 是不是 word bag
</span></span><span style="display:flex;"><span>semantic prefix 能不能支持推理
</span></span><span style="display:flex;"><span>compact state 为什么掉精度
</span></span></code></pre></div><p>这些问题都重要。</p>
<p>但它们有一个共同前提：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_tree 已经存在。
</span></span></code></pre></div><p>也就是说，我们默认已经有一个 TreeHeap state。</p>
<p>可是现在真正的问题是：</p>
<blockquote>
<p>原始数据到底如何被 encoder 写成 TreeHeap？</p></blockquote>
<p>如果 encoder 写错了，后面的 route、read、collapse、decode 都是在读错误状态。</p>
<p>所以 SPR-047 的核心不是 route。</p>
<p>核心是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Encode_Theta(raw observations) -&gt; H_tree
</span></span></code></pre></div><p>这个 encoder 才是 TreeHeap 的世界观察者。</p>
<h2 id="不能靠哲学把数据压进树">不能靠哲学把数据压进树</h2>
<p>我们可以在文章里说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>阿莫西林 -&gt; 药品 -&gt; 可摄入对象
</span></span><span style="display:flex;"><span>米饭     -&gt; 食物 -&gt; 可摄入对象
</span></span></code></pre></div><p>这个说法很顺。</p>
<p>但它不是学习。</p>
<p>如果这些前缀是人手写进去的，那么 proof 只能证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可以使用已知语义前缀。
</span></span></code></pre></div><p>它不能证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 可以从观察中发现语义前缀。
</span></span></code></pre></div><p>这就是当前的核心断点。</p>
<p>我们不能用哲学推理替代 encoder。</p>
<p>必须让 encoder 通过数据和 loss 自己学习：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>哪些东西应该靠近；
</span></span><span style="display:flex;"><span>哪些东西应该合并；
</span></span><span style="display:flex;"><span>哪些东西应该形成 internal node；
</span></span><span style="display:flex;"><span>哪些 internal node 有迁移价值。
</span></span></code></pre></div><h2 id="encoder-是世界观察者">Encoder 是世界观察者</h2>
<p>我现在把 encoder 定义成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>世界观察者 = 看见样本流，并把可复用规律排进 TreeHeap 的系统。
</span></span></code></pre></div><p>它不是简单 token embedding。</p>
<p>它要做几件事：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 观察 token / span / relation
</span></span><span style="display:flex;"><span>2. 给候选 placement 打分
</span></span><span style="display:flex;"><span>3. 决定哪些东西应该合并
</span></span><span style="display:flex;"><span>4. 生成 internal node state
</span></span><span style="display:flex;"><span>5. 保持 echo 可读
</span></span><span style="display:flex;"><span>6. 让有共同规律的对象共享 prefix
</span></span></code></pre></div><p>最小形式可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tokens / spans / observations
</span></span><span style="display:flex;"><span>  -&gt; token states
</span></span><span style="display:flex;"><span>  -&gt; candidate placement scores
</span></span><span style="display:flex;"><span>  -&gt; soft TreeHeap write
</span></span><span style="display:flex;"><span>  -&gt; soft compose
</span></span><span style="display:flex;"><span>  -&gt; H_tree
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H_tree = 当前样本的运行时 TreeHeap state
</span></span><span style="display:flex;"><span>Theta  = encoder / compose / route / read 的可学习参数
</span></span></code></pre></div><h2 id="排序规律从哪里来">排序规律从哪里来</h2>
<p>TreeHeap encoder 不会凭空知道排序规律。</p>
<p>它必须被目标函数选择。</p>
<p>我当前的假设是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 排序规律来自可压缩性。
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果一组 token / subheap 放在一起以后，
</span></span><span style="display:flex;"><span>能更好地重构、预测、替换、迁移、减少规则数量，
</span></span><span style="display:flex;"><span>那么它们应该靠近。
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat rice
</span></span><span style="display:flex;"><span>eat noodle
</span></span><span style="display:flex;"><span>eat apple
</span></span><span style="display:flex;"><span>cook rice
</span></span><span style="display:flex;"><span>cook noodle
</span></span><span style="display:flex;"><span>cook apple
</span></span></code></pre></div><p>如果没有 prefix，模型要记很多 pair。</p>
<p>如果形成一个 internal node：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>food-like = {rice, noodle, apple}
</span></span></code></pre></div><p>规则可以压缩成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat food-like
</span></span><span style="display:flex;"><span>cook food-like
</span></span></code></pre></div><p>这就是压缩收益。</p>
<p>所以 encoder 不是靠直觉发现 food。</p>
<p>它是发现：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这些词共享上下文、替换行为和预测规律，
</span></span><span style="display:flex;"><span>把它们合并后描述长度更短。
</span></span></code></pre></div><h2 id="五个训练信号">五个训练信号</h2>
<p>我建议 TreeHeap encoder 至少需要五类 loss。</p>
<h3 id="1-echo--reconstruction">1. Echo / Reconstruction</h3>
<p>压缩不能破坏样本。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Decode(H_tree, read_position=k) -&gt; token_k
</span></span><span style="display:flex;"><span>Decode(H_tree, read_subheap=i)  -&gt; subheap_i
</span></span></code></pre></div><p>如果只能形成语义类，但原句读不回来，那不是 S1 echo。</p>
<p>所以 echo loss 是底线。</p>
<h3 id="2-context-prediction">2. Context Prediction</h3>
<p>无监督学习不能凭空发现语义。</p>
<p>它只能从上下文统计里提取结构。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat [MASK] -&gt; rice / noodle / apple
</span></span><span style="display:flex;"><span>take [MASK] -&gt; amoxicillin / ibuprofen
</span></span><span style="display:flex;"><span>drink [MASK] -&gt; water / milk
</span></span></code></pre></div><p>如果多个对象出现在相似上下文里，encoder 应该把它们推向相近 prefix。</p>
<h3 id="3-infonce--contrastive-learning">3. InfoNCE / Contrastive Learning</h3>
<p>InfoNCE 可以把“同一规律”的观察拉近，把错配观察推远。</p>
<p>形式上：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L_InfoNCE =
</span></span><span style="display:flex;"><span>  -log exp(sim(anchor, positive) / tau)
</span></span><span style="display:flex;"><span>       / sum_j exp(sim(anchor, candidate_j) / tau)
</span></span></code></pre></div><p>positive 可以不是人工标签。</p>
<p>它可以来自：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>同一个 masked slot
</span></span><span style="display:flex;"><span>同一个上下文窗口
</span></span><span style="display:flex;"><span>同一个翻译对
</span></span><span style="display:flex;"><span>同一个重复构式
</span></span></code></pre></div><p>negative 可以来自：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>错上下文
</span></span><span style="display:flex;"><span>错翻译
</span></span><span style="display:flex;"><span>随机替换
</span></span><span style="display:flex;"><span>打乱语料
</span></span></code></pre></div><p>这让 encoder 有机会学到：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>哪些对象在观察上相似。
</span></span></code></pre></div><h3 id="4-replacement-consistency">4. Replacement Consistency</h3>
<p>如果两个词在很多上下文中可以互换，它们应该靠近。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat rice
</span></span><span style="display:flex;"><span>eat noodle
</span></span><span style="display:flex;"><span>eat apple
</span></span></code></pre></div><p>这里 rice / noodle / apple 有替换一致性。</p>
<p>但：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat shirt
</span></span></code></pre></div><p>不应被认为一致。</p>
<p>这种信号可以迫使 TreeHeap 形成可迁移 prefix。</p>
<h3 id="5-description-length--compression-pressure">5. Description Length / Compression Pressure</h3>
<p>这是最接近 TreeHeap 精神的部分。</p>
<p>好的 internal node 应该减少描述长度。</p>
<p>没有 prefix：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat rice
</span></span><span style="display:flex;"><span>eat noodle
</span></span><span style="display:flex;"><span>eat apple
</span></span><span style="display:flex;"><span>cook rice
</span></span><span style="display:flex;"><span>cook noodle
</span></span><span style="display:flex;"><span>cook apple
</span></span></code></pre></div><p>有 prefix：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>food-like = {rice, noodle, apple}
</span></span><span style="display:flex;"><span>eat food-like
</span></span><span style="display:flex;"><span>cook food-like
</span></span></code></pre></div><p>如果后者解释同样数据更短，就应该奖励。</p>
<p>这可以看成 MDL，Minimum Description Length。</p>
<p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>好结构 = 用更短规则解释更多观察。
</span></span></code></pre></div><h2 id="三种推理如何进入-encoder">三种推理如何进入 encoder</h2>
<p>我们一直说演绎、归纳、类比。</p>
<p>现在可以落到 encoder 上。</p>
<h3 id="演绎">演绎</h3>
<p>如果 prefix 已经存在：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>amoxicillin -&gt; medicine -&gt; consumable
</span></span><span style="display:flex;"><span>eat accepts consumable
</span></span></code></pre></div><p>那么可以推出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat amoxicillin
</span></span></code></pre></div><p>这是 SPR-046 的 supervised semantic-prefix toy proof 已经支持的窄结论。</p>
<h3 id="归纳">归纳</h3>
<p>现在更关键的是归纳。</p>
<p>模型只看见：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat rice
</span></span><span style="display:flex;"><span>eat noodle
</span></span><span style="display:flex;"><span>cook rice
</span></span><span style="display:flex;"><span>cook noodle
</span></span></code></pre></div><p>它要归纳出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rice / noodle 共享某个 prefix
</span></span></code></pre></div><p>这个 prefix 不必一开始叫 food。</p>
<p>它可以只是 latent prefix。</p>
<p>名字是人类事后解释。</p>
<h3 id="类比">类比</h3>
<p>类比更复杂，可以晚一点做。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rice : food :: amoxicillin : medicine
</span></span><span style="display:flex;"><span>eat : food :: take : medicine
</span></span></code></pre></div><p>这需要结构关系之间也可比较。</p>
<p>当前先不要急着 claim。</p>
<h2 id="最小-proof-应该怎么设计">最小 proof 应该怎么设计</h2>
<p>不要一上来 WMT。</p>
<p>先做无标签 synthetic corpus。</p>
<p>训练数据只给观察，不给类别：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat rice
</span></span><span style="display:flex;"><span>eat noodle
</span></span><span style="display:flex;"><span>eat apple
</span></span><span style="display:flex;"><span>cook rice
</span></span><span style="display:flex;"><span>cook noodle
</span></span><span style="display:flex;"><span>cook apple
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>take amoxicillin
</span></span><span style="display:flex;"><span>take ibuprofen
</span></span><span style="display:flex;"><span>prescribe amoxicillin
</span></span><span style="display:flex;"><span>prescribe ibuprofen
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>drink water
</span></span><span style="display:flex;"><span>drink milk
</span></span><span style="display:flex;"><span>pour water
</span></span><span style="display:flex;"><span>pour milk
</span></span></code></pre></div><p>训练时不提供：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>food
</span></span><span style="display:flex;"><span>medicine
</span></span><span style="display:flex;"><span>beverage
</span></span></code></pre></div><p>训练目标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>L = L_echo
</span></span><span style="display:flex;"><span>  + L_context_prediction
</span></span><span style="display:flex;"><span>  + L_InfoNCE
</span></span><span style="display:flex;"><span>  + L_replacement_consistency
</span></span><span style="display:flex;"><span>  + lambda * L_description_length
</span></span></code></pre></div><p>然后评估：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rice/noodle/apple 是否形成相近 prefix
</span></span><span style="display:flex;"><span>amoxicillin/ibuprofen 是否形成相近 prefix
</span></span><span style="display:flex;"><span>water/milk 是否形成相近 prefix
</span></span><span style="display:flex;"><span>held-out context 是否能迁移
</span></span></code></pre></div><p>注意：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>标签只能用于评估，不能用于训练。
</span></span></code></pre></div><p>这就避免了“监督假设”的循环。</p>
<h2 id="必须有-shuffled-control">必须有 shuffled control</h2>
<p>这里最容易自欺欺人。</p>
<p>如果模型在任何数据上都能画出团簇，那就没意义。</p>
<p>所以必须有打乱语料对照。</p>
<p>例如 structured corpus：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat rice
</span></span><span style="display:flex;"><span>eat noodle
</span></span><span style="display:flex;"><span>cook rice
</span></span><span style="display:flex;"><span>cook noodle
</span></span></code></pre></div><p>shuffled corpus：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat car
</span></span><span style="display:flex;"><span>cook shirt
</span></span><span style="display:flex;"><span>take apple
</span></span><span style="display:flex;"><span>drink hoodie
</span></span></code></pre></div><p>预测应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>structured corpus -&gt; 稳定 prefix
</span></span><span style="display:flex;"><span>shuffled corpus   -&gt; prefix 消失或明显变差
</span></span></code></pre></div><p>如果两者一样好，说明模型不是在学习世界结构，而是在制造幻觉。</p>
<h2 id="二维投影只能当显微镜">二维投影只能当显微镜</h2>
<p>还有一个容易误会的点。</p>
<p>我们可以把高维 TreeHeap state 用 PCA / UMAP / t-SNE 压到二维。</p>
<p>如果 food-like / medicine-like 分开，会很直观。</p>
<p>但二维图不是训练目标本身。</p>
<p>它只是观察工具。</p>
<p>真正要优化的是高维 <code>H_tree</code>：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>echo 是否保留
</span></span><span style="display:flex;"><span>context prediction 是否变好
</span></span><span style="display:flex;"><span>InfoNCE retrieval 是否变好
</span></span><span style="display:flex;"><span>held-out transfer 是否成立
</span></span><span style="display:flex;"><span>structured-vs-shuffled gap 是否存在
</span></span></code></pre></div><p>二维图可以放在报告里，但不能只靠肉眼判断。</p>
<p>需要数字指标：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>nearest-neighbor class accuracy
</span></span><span style="display:flex;"><span>cluster purity
</span></span><span style="display:flex;"><span>ARI / NMI
</span></span><span style="display:flex;"><span>held-out transfer accuracy
</span></span><span style="display:flex;"><span>echo exact
</span></span></code></pre></div><h2 id="当前-claim">当前 claim</h2>
<p>这篇不是实验结果。</p>
<p>它是下一步设计。</p>
<p>当前 claim 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap semantic structure must be learned by an encoder-as-world-observer:
</span></span><span style="display:flex;"><span>the encoder should infer placement, fold, and prefix structure from
</span></span><span style="display:flex;"><span>compressibility signals rather than receive semantic labels by philosophical
</span></span><span style="display:flex;"><span>assumption.
</span></span></code></pre></div><p>中文说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的语义结构不能靠我们手写进去。
</span></span><span style="display:flex;"><span>encoder 必须通过观察数据和 loss，
</span></span><span style="display:flex;"><span>自己学出放置、折叠和前缀规律。
</span></span></code></pre></div><h2 id="falsification">Falsification</h2>
<p>这个方向可以被证伪。</p>
<p>如果出现下面情况，就要降级或重做：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. shuffled corpus 也能产生同样 prefix；
</span></span><span style="display:flex;"><span>2. flat / bag / pair baseline 在 held-out transfer 上追平；
</span></span><span style="display:flex;"><span>3. TreeHeap 保住 echo 时就学不出 prefix；
</span></span><span style="display:flex;"><span>4. 学出 prefix 时 echo 被破坏；
</span></span><span style="display:flex;"><span>5. prefix 必须靠人工标签才能出现；
</span></span><span style="display:flex;"><span>6. 学出的 prefix 对 route/read 没帮助。
</span></span></code></pre></div><h2 id="下一步">下一步</h2>
<p>我建议 DS 先 review 这套设计，而不是立刻跑大实验。</p>
<p>需要审的问题：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. 这些 loss 是否足以驱动 prefix induction？
</span></span><span style="display:flex;"><span>2. description-length pressure 如何实现最小版？
</span></span><span style="display:flex;"><span>3. InfoNCE positive/negative 是否会偷渡监督？
</span></span><span style="display:flex;"><span>4. shuffled corpus control 是否足够？
</span></span><span style="display:flex;"><span>5. flat baseline 应该怎么配？
</span></span><span style="display:flex;"><span>6. TreeHeap 特异性在哪里，如何避免退化成普通 embedding clustering？
</span></span></code></pre></div><p>如果这些过了，再写 proof。</p>
<p>目标不是证明 TreeHeap 已经理解世界。</p>
<p>目标是证明一个更小的东西：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>encoder 能不能从观察中，把可压缩规律写进 TreeHeap。
</span></span></code></pre></div><blockquote>
<p>ARA: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/s1_encoder_world_observer.md">encoder design</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/experiments.md">experiments</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-046] TreeHeap 语义前缀压缩：从 word bag 到可迁移的结构状态</title>
      <link>https://www.grepcode.cn/spr/046-content-route-voyage-problem.html</link>
      <pubDate>Mon, 06 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/046-content-route-voyage-problem.html</guid>
      <description>SPR-046 重写版：用本科可理解的方式说明 Transformer 并不保存所有可能句子，TreeHeap 的假设是用树形语义前缀压缩形成可解码、可迁移的结构状态；并记录 content-aware route、compact state 和 semantic-prefix toy proof 的证据与边界。</description>
      <content:encoded><![CDATA[<h1 id="treeheap-语义前缀压缩从-word-bag-到可迁移的结构状态">TreeHeap 语义前缀压缩：从 word bag 到可迁移的结构状态</h1>
<p>这篇重写 046。</p>
<p>之前版本把太多中间修正写进正文：查找树、route、content-aware、compact state、H/Q/Theta、霍夫曼类比、语义前缀 proof 混在一起。读起来像沿途事故记录，不像一篇能帮助后续工作的文章。</p>
<p>现在从基本知识重新讲。</p>
<p>这篇只回答一个问题：</p>
<blockquote>
<p>TreeHeap 的 root / internal node 如果不是 word bag，那它应该是什么？</p></blockquote>
<p>我的当前答案是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap state 应该是可解码、可压缩、可迁移的语义前缀结构。
</span></span></code></pre></div><p>也就是说，root 不是把所有词混在一起。</p>
<p>root 应该保存一种结构状态，使得模型在给定问题 <code>Q</code> 时，可以从中坍缩出需要的信息。</p>
<h2 id="第一件事transformer-也不是把所有可能性存下来">第一件事：Transformer 也不是把所有可能性存下来</h2>
<p>先拿 Transformer 做参照。</p>
<p>假设语料里有很多句子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>我 吃 米饭
</span></span><span style="display:flex;"><span>我 吃 面条
</span></span><span style="display:flex;"><span>我 吃 苹果
</span></span><span style="display:flex;"><span>我 吃 药
</span></span><span style="display:flex;"><span>我 吃 阿莫西林
</span></span></code></pre></div><p>我们可能会误以为 Transformer 学到的是一个巨大表：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>吃 -&gt; {米饭, 面条, 苹果, 药, 阿莫西林, ...}
</span></span></code></pre></div><p>但这不是准确理解。</p>
<p>Transformer 不会为每个词保存“后面所有可能词的完整集合”。</p>
<p>它学的是一个条件概率函数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P(next token | context)
</span></span></code></pre></div><p>训练时，模型看到大量上下文和目标 token。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>context = 我 正在 吃
</span></span><span style="display:flex;"><span>target  = 米饭
</span></span></code></pre></div><p>模型会生成一个 hidden state：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>h = Transformer(context)
</span></span></code></pre></div><p>然后输出词表概率：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>logits = W_vocab h
</span></span><span style="display:flex;"><span>P(token) = softmax(logits)
</span></span></code></pre></div><p>如果正确答案是“米饭”，loss 会推动参数，让“米饭”的概率更高。</p>
<p>长期训练后，模型不是记住一张简单共现表，而是在参数矩阵里形成一个分布式函数。</p>
<p>这个函数会捕捉类似：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>吃 后面常接可摄入对象
</span></span><span style="display:flex;"><span>可摄入对象包括食物、药品、某些抽象对象
</span></span></code></pre></div><p>但这些结构通常是隐式的。</p>
<p>也就是说，Transformer 的强项是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>用大规模参数矩阵学习 flat context -&gt; probability 的函数。
</span></span></code></pre></div><p>它不枚举所有可能。</p>
<p>它学习一个能泛化的概率曲面。</p>
<h2 id="第二件事word-bag-不够">第二件事：word bag 不够</h2>
<p>现在回到 TreeHeap。</p>
<p>如果一句话是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>I like small cats
</span></span></code></pre></div><p>一个 word bag 表示是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>{I, like, small, cats}
</span></span></code></pre></div><p>这个表示能回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>cats 出现过吗？
</span></span></code></pre></div><p>但它不能回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第 1 个词是什么？
</span></span><span style="display:flex;"><span>small 修饰谁？
</span></span><span style="display:flex;"><span>small cats 是不是一个 subheap？
</span></span><span style="display:flex;"><span>I like small cats 和 cats like small I 是否不同？
</span></span></code></pre></div><p>所以 word bag 不是 echo 所需的 root state。</p>
<p>Echo 要求至少能恢复：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token identity    有哪些 token
</span></span><span style="display:flex;"><span>address / path    token 在哪个结构位置
</span></span><span style="display:flex;"><span>composition       token 如何组成 subheap / sentence
</span></span></code></pre></div><p>如果 root 只保存 bag，那顺序和结构已经丢了。</p>
<p>所以更合理的说法是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root 不是词集合。
</span></span><span style="display:flex;"><span>root 是一个可解码的结构状态。
</span></span></code></pre></div><p>给一个 query：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Q = read position 2
</span></span></code></pre></div><p>decoder 应该能读出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>small
</span></span></code></pre></div><p>给另一个 query：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Q = read subheap containing adjective+noun
</span></span></code></pre></div><p>decoder 应该能读出：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>small cats
</span></span></code></pre></div><p>也就是说，root 的含义不是靠我们肉眼解释出来的。</p>
<p>它靠读出能力证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Decode(root, Q) -&gt; expected information
</span></span></code></pre></div><h2 id="第三件事treeheap-的不同假设">第三件事：TreeHeap 的不同假设</h2>
<p>Transformer 做的是 flat context function。</p>
<p>TreeHeap 想做的是 structured heap context function。</p>
<p>可以写成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Transformer:
</span></span><span style="display:flex;"><span>  H_flat = sequence hidden states
</span></span><span style="display:flex;"><span>  Q      = decoder step / attention query
</span></span><span style="display:flex;"><span>  Theta  = attention + MLP + vocab head parameters
</span></span><span style="display:flex;"><span>  output = token probability
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TreeHeap:
</span></span><span style="display:flex;"><span>  H_tree = TreeHeap states
</span></span><span style="display:flex;"><span>  Q      = read / write / generate intent
</span></span><span style="display:flex;"><span>  Theta  = TreeHeap kernel parameters
</span></span><span style="display:flex;"><span>  output = route / read / token probability
</span></span></code></pre></div><p>所以 TreeHeap 不是要比 Transformer 更神秘。</p>
<p>它的假设更具体：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>语言信息本身有层级、前缀、子结构和组合关系。
</span></span><span style="display:flex;"><span>如果模型的状态空间也显式支持这些结构，
</span></span><span style="display:flex;"><span>就可能在某些任务上更容易泛化。
</span></span></code></pre></div><p>这里的重点不是“树比矩阵高级”。</p>
<p>重点是 TreeHeap 可能提供一种归纳偏置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>address
</span></span><span style="display:flex;"><span>path
</span></span><span style="display:flex;"><span>subheap
</span></span><span style="display:flex;"><span>compose
</span></span><span style="display:flex;"><span>decompose
</span></span><span style="display:flex;"><span>prefix compression
</span></span><span style="display:flex;"><span>probabilistic collapse
</span></span></code></pre></div><p>这些结构在普通 flat 表示里不显式。</p>
<h2 id="第四件事语义前缀压缩">第四件事：语义前缀压缩</h2>
<p>现在进入这篇的核心。</p>
<p>TreeHeap root / internal node 不应该只是频率压缩。</p>
<p>也不应该只是 word bag 压缩。</p>
<p>它应该尝试形成语义前缀压缩。</p>
<p>什么叫语义前缀？</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>阿莫西林 -&gt; 药品 -&gt; 可摄入对象 -&gt; 物体
</span></span><span style="display:flex;"><span>米饭     -&gt; 食物 -&gt; 可摄入对象 -&gt; 物体
</span></span><span style="display:flex;"><span>面条     -&gt; 食物 -&gt; 可摄入对象 -&gt; 物体
</span></span><span style="display:flex;"><span>苹果     -&gt; 食物 -&gt; 可摄入对象 -&gt; 物体
</span></span></code></pre></div><p>如果模型只记 pair，它只知道：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>吃 + 米饭
</span></span><span style="display:flex;"><span>吃 + 面条
</span></span><span style="display:flex;"><span>吃 + 苹果
</span></span></code></pre></div><p>如果新组合出现：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>吃 + 阿莫西林
</span></span></code></pre></div><p>pair memory 没见过，就容易失败。</p>
<p>但如果模型有语义前缀，它可以做一个演绎迁移：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>阿莫西林 是 药品
</span></span><span style="display:flex;"><span>药品 是 可摄入对象
</span></span><span style="display:flex;"><span>吃 接受 可摄入对象
</span></span><span style="display:flex;"><span>所以 吃 + 阿莫西林 可以成立
</span></span></code></pre></div><p>这就是 TreeHeap 可能比 word bag 更有意义的地方。</p>
<p>它不是保存所有句子。</p>
<p>它保存可复用的中间语义节点。</p>
<p>这些节点可以支持未见组合的推理。</p>
<h2 id="第五件事这和霍夫曼树像在哪里不像在哪里">第五件事：这和霍夫曼树像在哪里，不像在哪里</h2>
<p>霍夫曼树是一种编码树。</p>
<p>它把高频符号放到短路径，低频符号放到长路径。</p>
<p>它的目标是压缩长度。</p>
<p>TreeHeap 的语义前缀树可以借用这个直觉：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>路径是一种编码。
</span></span><span style="display:flex;"><span>internal node 是一组可以共享前缀的信息。
</span></span><span style="display:flex;"><span>leaf 是更具体的信息。
</span></span></code></pre></div><p>但 TreeHeap 不应该只按频率压缩。</p>
<p>它更应该按可推理性压缩。</p>
<p>也就是说，internal node 应该回答：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>哪些叶子共享同一种语义规则？
</span></span><span style="display:flex;"><span>哪些组合可以通过这个节点迁移？
</span></span><span style="display:flex;"><span>哪个前缀能最大化当前任务的信息增益？
</span></span></code></pre></div><p>所以它更像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Huffman-like semantic prefix tree
</span></span></code></pre></div><p>而不是普通 Huffman coding。</p>
<h2 id="第六件事route-不是查找树而是信息坍缩">第六件事：route 不是查找树，而是信息坍缩</h2>
<p>这点也要说清楚。</p>
<p>以前我把 TreeHeap route 讲成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>从 root 开始，找 cats，走 left/right/stop。
</span></span></code></pre></div><p>这个类比太像二叉搜索树。</p>
<p>二叉搜索树的问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>给定 key
</span></span><span style="display:flex;"><span>比较大小
</span></span><span style="display:flex;"><span>往左或往右找
</span></span></code></pre></div><p>TreeHeap 的目标不是这个。</p>
<p>更准确地说，TreeHeap route 是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>在当前问题 Q 下，
</span></span><span style="display:flex;"><span>从当前 node 的信息分布里，
</span></span><span style="display:flex;"><span>选择是否停下，或者坍缩到哪个子信息分支。
</span></span></code></pre></div><p>动作不是“找 key”。</p>
<p>动作含义应该是：</p>
<table>
  <thead>
      <tr>
          <th>动作</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>stop</code></td>
          <td>当前 node 的信息已经足够回答 Q</td>
      </tr>
      <tr>
          <td><code>left</code></td>
          <td>左分支的信息对 Q 更有用</td>
      </tr>
      <tr>
          <td><code>right</code></td>
          <td>右分支的信息对 Q 更有用</td>
      </tr>
  </tbody>
</table>
<p>所以更准确的名字是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>InformationCollapseRoute
</span></span></code></pre></div><p>它输出的是一个概率桶：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>P(stop), P(left), P(right)
</span></span></code></pre></div><p>如果要硬执行，就坍缩成一个动作。</p>
<p>如果还不确定，就保留概率容器。</p>
<p>这和我们之前一直说的“延迟坍缩”是一致的。</p>
<h2 id="第七件事hqtheta-的位置">第七件事：H、Q、Theta 的位置</h2>
<p>现在把对象定义清楚。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H      = 当前样本形成的 TreeHeap state
</span></span><span style="display:flex;"><span>Q      = 当前任务意图 / query / read-write intent
</span></span><span style="display:flex;"><span>Theta  = 可学习的参数 TreeHeap 或 kernel 参数
</span></span><span style="display:flex;"><span>Output = 概率桶
</span></span></code></pre></div><p>形式上：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Route_Theta(H, Q, node=i)
</span></span><span style="display:flex;"><span>  -&gt; P(stop), P(left), P(right)
</span></span></code></pre></div><p>这里 <code>H</code> 不是长期参数。</p>
<p><code>H</code> 是输入样本的运行时状态。</p>
<p>比如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H = Encode(&#34;I like small cats&#34;)
</span></span></code></pre></div><p><code>Theta</code> 才是训练后保留下来的东西。</p>
<p>类比线性回归：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>y = w x + b
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>x    是输入
</span></span><span style="display:flex;"><span>w,b  是参数
</span></span></code></pre></div><p>TreeHeap 里：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>H      是输入形成的状态
</span></span><span style="display:flex;"><span>Theta  是模型学到的参数
</span></span><span style="display:flex;"><span>Q      是这次要解决的问题
</span></span><span style="display:flex;"><span>P      是输出概率
</span></span></code></pre></div><p>训练时，loss 会更新 <code>Theta</code>。</p>
<p>如果 encoder / compose / route / read 都是可学习的，那么可能有多组参数：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta_encode
</span></span><span style="display:flex;"><span>Theta_compose
</span></span><span style="display:flex;"><span>Theta_route
</span></span><span style="display:flex;"><span>Theta_read
</span></span><span style="display:flex;"><span>Theta_decode
</span></span></code></pre></div><p>但现在不能把这些混在一起。</p>
<p>否则即使实验成功，我们也不知道到底是谁学会了东西。</p>
<h2 id="第八件事当前证据-1content-aware-dense-route">第八件事：当前证据 1，content-aware dense route</h2>
<p>先说已经做过的 route proof。</p>
<p>实验：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>S1-CONTENT-ROUTE-C01
</span></span></code></pre></div><p>问题是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>kernel 能不能真的读 arr[i] / arr[left] / arr[right] 的内容，
</span></span><span style="display:flex;"><span>而不是读几何答案 feature？
</span></span></code></pre></div><p>dense 版本把每个 subheap 表示成 vocab-count 向量。</p>
<p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[i] = 这个子堆里有哪些 token 的清单
</span></span></code></pre></div><p>这不是最终语义表示。</p>
<p>但它可以作为机制尺子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果清单都跑不通，route 机制就有问题。
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>samples</td>
          <td style="text-align: right"><code>20000</code></td>
      </tr>
      <tr>
          <td>train route steps</td>
          <td style="text-align: right"><code>352110</code></td>
      </tr>
      <tr>
          <td>OOD route steps</td>
          <td style="text-align: right"><code>44130</code></td>
      </tr>
      <tr>
          <td>dense feature memory</td>
          <td style="text-align: right"><code>6191.25 MB</code></td>
      </tr>
      <tr>
          <td>OOD step acc</td>
          <td style="text-align: right"><code>0.9983</code></td>
      </tr>
      <tr>
          <td>OOD route exact</td>
          <td style="text-align: right"><code>0.9902</code></td>
      </tr>
      <tr>
          <td>flat length-matrix OOD exact</td>
          <td style="text-align: right"><code>0.0000</code></td>
      </tr>
      <tr>
          <td>pilot pass</td>
          <td style="text-align: right"><code>true</code></td>
      </tr>
  </tbody>
</table>
<p>这说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>content-aware route 可以读 subheap 内容并完成递归 stop/left/right。
</span></span></code></pre></div><p>边界：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这不是语义理解。
</span></span><span style="display:flex;"><span>这不是翻译。
</span></span><span style="display:flex;"><span>这仍然使用 supervised query token。
</span></span><span style="display:flex;"><span>这仍然依赖 dense vocab-count state。
</span></span></code></pre></div><h2 id="第九件事当前证据-2compact-state-失败在哪里">第九件事：当前证据 2，compact state 失败在哪里</h2>
<p>接着做 compact 版本。</p>
<p>目标是把 dense vocab-count state 换成小向量。</p>
<p>做法：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>token id -&gt; 固定随机向量
</span></span><span style="display:flex;"><span>arr[i]   -&gt; 子堆 token 向量求和
</span></span></code></pre></div><p>64D 结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>compact memory</td>
          <td style="text-align: right"><code>324.84 MB</code></td>
      </tr>
      <tr>
          <td>dense prior memory</td>
          <td style="text-align: right"><code>6191.25 MB</code></td>
      </tr>
      <tr>
          <td>memory reduction</td>
          <td style="text-align: right"><code>19.06x</code></td>
      </tr>
      <tr>
          <td>OOD step acc</td>
          <td style="text-align: right"><code>0.9973</code></td>
      </tr>
      <tr>
          <td>OOD route exact</td>
          <td style="text-align: right"><code>0.9838</code></td>
      </tr>
      <tr>
          <td>pilot pass</td>
          <td style="text-align: right"><code>false</code></td>
      </tr>
  </tbody>
</table>
<p>128D 结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>compact memory</td>
          <td style="text-align: right"><code>637.59 MB</code></td>
      </tr>
      <tr>
          <td>memory reduction</td>
          <td style="text-align: right"><code>9.71x</code></td>
      </tr>
      <tr>
          <td>OOD step acc</td>
          <td style="text-align: right"><code>0.9973</code></td>
      </tr>
      <tr>
          <td>OOD route exact</td>
          <td style="text-align: right"><code>0.9837</code></td>
      </tr>
      <tr>
          <td>pilot pass</td>
          <td style="text-align: right"><code>false</code></td>
      </tr>
  </tbody>
</table>
<p>这个结果说明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>随机 token sum 能大幅省内存，
</span></span><span style="display:flex;"><span>但会损失路径级 exactness。
</span></span></code></pre></div><p>而且 128D 没有明显变好。</p>
<p>所以问题不是简单的维度不够。</p>
<p>更可能是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>随机向量求和不是好的 subheap state。
</span></span></code></pre></div><p>下一步应该学：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>learned token embedding
</span></span><span style="display:flex;"><span>learned subheap compose
</span></span><span style="display:flex;"><span>learned prefix state
</span></span></code></pre></div><h2 id="第十件事当前证据-3语义前缀-toy-proof">第十件事：当前证据 3，语义前缀 toy proof</h2>
<p>为了验证“语义前缀能带来演绎迁移”，我做了一个很小的 toy proof。</p>
<p>它不是自然语料实验。</p>
<p>它只测试一个基本机制：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>如果语义前缀结构存在，
</span></span><span style="display:flex;"><span>它能不能支持未见 pair 的推理？
</span></span></code></pre></div><p>Toy ontology：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>rice        -&gt; entity -&gt; consumable -&gt; food
</span></span><span style="display:flex;"><span>noodle      -&gt; entity -&gt; consumable -&gt; food
</span></span><span style="display:flex;"><span>apple       -&gt; entity -&gt; consumable -&gt; food
</span></span><span style="display:flex;"><span>amoxicillin -&gt; entity -&gt; consumable -&gt; medicine
</span></span><span style="display:flex;"><span>ibuprofen   -&gt; entity -&gt; consumable -&gt; medicine
</span></span><span style="display:flex;"><span>water       -&gt; entity -&gt; drinkable  -&gt; beverage
</span></span><span style="display:flex;"><span>shirt       -&gt; entity -&gt; wearable   -&gt; clothing
</span></span><span style="display:flex;"><span>car         -&gt; entity -&gt; drivable   -&gt; vehicle
</span></span></code></pre></div><p>谓词规则：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat   accepts consumable
</span></span><span style="display:flex;"><span>take  accepts medicine
</span></span><span style="display:flex;"><span>drink accepts drinkable
</span></span><span style="display:flex;"><span>wear  accepts wearable
</span></span><span style="display:flex;"><span>drive accepts drivable
</span></span><span style="display:flex;"><span>visit accepts visitable
</span></span></code></pre></div><p>关键设置：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>训练集不包含 eat + amoxicillin。
</span></span></code></pre></div><p>但是训练集包含：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat + rice
</span></span><span style="display:flex;"><span>eat + noodle
</span></span><span style="display:flex;"><span>eat + apple
</span></span><span style="display:flex;"><span>take + amoxicillin
</span></span></code></pre></div><p>对照组：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>pair_memory       只记见过的正例 pair
</span></span><span style="display:flex;"><span>pair_logistic     只用 verb-object pair id
</span></span><span style="display:flex;"><span>token_additive    只用 verb id + object id
</span></span><span style="display:flex;"><span>semantic_prefix   使用 object 的语义前缀 path
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th style="text-align: right">test acc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>pair memory</td>
          <td style="text-align: right"><code>0.4</code></td>
      </tr>
      <tr>
          <td>pair logistic</td>
          <td style="text-align: right"><code>0.4</code></td>
      </tr>
      <tr>
          <td>token additive</td>
          <td style="text-align: right"><code>0.6</code></td>
      </tr>
      <tr>
          <td>semantic prefix</td>
          <td style="text-align: right"><code>1.0</code></td>
      </tr>
  </tbody>
</table>
<p>关键 held-out case：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Question:
</span></span><span style="display:flex;"><span>  Can eat + amoxicillin be accepted without that pair in training?
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>pair_memory:
</span></span><span style="display:flex;"><span>  gold = 1
</span></span><span style="display:flex;"><span>  pred = 0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>semantic_prefix:
</span></span><span style="display:flex;"><span>  path = [entity, consumable, medicine]
</span></span><span style="display:flex;"><span>  gold = 1
</span></span><span style="display:flex;"><span>  prob = 0.7088
</span></span><span style="display:flex;"><span>  pred = 1
</span></span></code></pre></div><p>这支持一个很窄的 claim：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>有监督的语义前缀结构，
</span></span><span style="display:flex;"><span>可以支持 pair memory 不具备的演绎迁移。
</span></span></code></pre></div><p>边界必须写清楚：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ontology 是手工给的；
</span></span><span style="display:flex;"><span>prefix path 是监督的；
</span></span><span style="display:flex;"><span>这不证明模型能从自然语料自动学出 medicine / consumable；
</span></span><span style="display:flex;"><span>这不证明 WMT；
</span></span><span style="display:flex;"><span>这不证明自然语言理解。
</span></span></code></pre></div><h2 id="当前假设">当前假设</h2>
<p>现在我会把假设写得更干净。</p>
<h3 id="hypothesis-1-root-不是-word-bag">Hypothesis 1: root 不是 word bag</h3>
<p>TreeHeap root 应该是可解码结构状态。</p>
<p>它至少要支持：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>read token
</span></span><span style="display:flex;"><span>read path
</span></span><span style="display:flex;"><span>read subheap
</span></span><span style="display:flex;"><span>read semantic prefix
</span></span></code></pre></div><p>如果只能回答“某词是否出现”，那只是 bag，不够。</p>
<h3 id="hypothesis-2-internal-node-应该承载可迁移前缀">Hypothesis 2: internal node 应该承载可迁移前缀</h3>
<p>internal node 不只是左右孩子求和。</p>
<p>它应该尽可能形成：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>可复用的语义类
</span></span><span style="display:flex;"><span>可组合的短语结构
</span></span><span style="display:flex;"><span>可迁移的推理前缀
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>medicine -&gt; consumable
</span></span><span style="display:flex;"><span>food -&gt; consumable
</span></span></code></pre></div><p>这样新的 leaf 可以继承规则。</p>
<h3 id="hypothesis-3-route-是信息坍缩">Hypothesis 3: route 是信息坍缩</h3>
<p>Route 不应该理解成查找树搜索。</p>
<p>它应该是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Collapse(H_i, Q; Theta) -&gt; ProbabilityBucket(stop, left, right)
</span></span></code></pre></div><p>其中 left/right 代表信息分支，stop 代表当前信息已经足够。</p>
<h3 id="hypothesis-4-theta-应该逐步-treeheap-化">Hypothesis 4: Theta 应该逐步 TreeHeap 化</h3>
<p>当前实验里的 <code>Theta</code> 还常常是普通 MLP 或 logistic 权重。</p>
<p>这只是工程近似。</p>
<p>更强的目标是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta_encode
</span></span><span style="display:flex;"><span>Theta_compose
</span></span><span style="display:flex;"><span>Theta_route
</span></span><span style="display:flex;"><span>Theta_read
</span></span></code></pre></div><p>都逐步变成显式 TreeHeap kernel / parameter heap。</p>
<p>否则我们只是在普通模型外面套 TreeHeap 词汇。</p>
<h2 id="下一步怎么走">下一步怎么走</h2>
<p>我建议下一步不是继续写更大口号。</p>
<p>而是做三个 proof。</p>
<h3 id="proof-a-learned-prefix-induction">Proof A: learned prefix induction</h3>
<p>现在 semantic prefix 是手工给的。</p>
<p>下一步要从数据里学出来。</p>
<p>例如只给训练事实：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>eat rice
</span></span><span style="display:flex;"><span>eat noodle
</span></span><span style="display:flex;"><span>eat apple
</span></span><span style="display:flex;"><span>take amoxicillin
</span></span><span style="display:flex;"><span>take ibuprofen
</span></span></code></pre></div><p>看模型能否形成隐含前缀：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>food
</span></span><span style="display:flex;"><span>medicine
</span></span><span style="display:flex;"><span>consumable
</span></span></code></pre></div><p>这是最关键的一步。</p>
<h3 id="proof-b-prefix-state--echo">Proof B: prefix state + echo</h3>
<p>不仅要判断 pair 是否成立，还要能 echo。</p>
<p>也就是说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root state
</span></span><span style="display:flex;"><span>  -&gt; read position
</span></span><span style="display:flex;"><span>  -&gt; read subheap
</span></span><span style="display:flex;"><span>  -&gt; read semantic prefix
</span></span></code></pre></div><p>三件事要同时成立。</p>
<p>否则语义前缀可能破坏 echo。</p>
<h3 id="proof-c-treeheap-theta">Proof C: TreeHeap Theta</h3>
<p>把普通 logistic/MLP 参数替换成更明确的参数 TreeHeap。</p>
<p>目标是证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Theta 本身可以按 root/left/right/prefix slot 组织，
</span></span><span style="display:flex;"><span>并通过 loss 学会坍缩规则。
</span></span></code></pre></div><p>这是从工程近似走向 TreeHeap 理论闭包的关键。</p>
<h2 id="结论">结论</h2>
<p>SPR-046 现在的结论是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 的核心不应该是 word bag root。
</span></span></code></pre></div><p>更合理的方向是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root/internal node 形成可解码、可压缩、可迁移的语义前缀结构。
</span></span></code></pre></div><p>Transformer 学的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flat context -&gt; probability
</span></span></code></pre></div><p>TreeHeap 想学的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>structured heap context -&gt; probability
</span></span></code></pre></div><p>当前证据支持三个很小的点：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1. content-aware route 可以读 subheap 内容；
</span></span><span style="display:flex;"><span>2. random-sum compact state 不够好；
</span></span><span style="display:flex;"><span>3. supervised semantic prefix 可以支持 toy deductive transfer。
</span></span></code></pre></div><p>但还没有证明：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap 能从自然语料学出语义前缀；
</span></span><span style="display:flex;"><span>TreeHeap 能翻译；
</span></span><span style="display:flex;"><span>TreeHeap 已经优于 Transformer；
</span></span><span style="display:flex;"><span>Theta 已经是严格参数 TreeHeap。
</span></span></code></pre></div><p>所以当前航行问题已经变清楚了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>不要再争 root 是不是 word bag。
</span></span><span style="display:flex;"><span>它不应该是。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>下一步要证明：
</span></span><span style="display:flex;"><span>语义前缀能不能从数据里学出来，
</span></span><span style="display:flex;"><span>并且不破坏 echo / route / read。
</span></span></code></pre></div><blockquote>
<p>ARA: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/experiments.md">experiments</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/s1_content_treeheap_route_probe_20k_e5">content route evidence</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/s1_compact_content_treeheap_route_probe_20k_e5">compact evidence</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/s1_semantic_prefix_compression_probe">semantic prefix evidence</a></p></blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>[SPR-045] 重做 S1 route：矩阵不是 TreeHeap，递归路径才是</title>
      <link>https://www.grepcode.cn/spr/045-recursive-treeheap-route.html</link>
      <pubDate>Sun, 05 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://www.grepcode.cn/spr/045-recursive-treeheap-route.html</guid>
      <description>删除并重写 SPR-041/043/044 的路线：区分 flat LxL route matrix 和真正的 recursive TreeHeap stop/left/right route，并给出 WMT-massive proof。</description>
      <content:encoded><![CDATA[<h1 id="重做-s1-route矩阵不是-treeheap递归路径才是">重做 S1 route：矩阵不是 TreeHeap，递归路径才是</h1>
<p>这篇是一次纠错。</p>
<p>之前 SPR-041、SPR-043、SPR-044 里有一类说法写过头了：</p>
<blockquote>
<p>用 TreeHeap route 把 mirror / flip 后的句子恢复回来。</p></blockquote>
<p>后来 DS 做代码审计时指出一个关键问题：这些实验里的 learned inverse route 实际上不是 TreeHeap route，而是一个可学习的平面矩阵。</p>
<p>也就是这种东西：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>route_logits[length, out_pos, in_pos]
</span></span><span style="display:flex;"><span>route <span style="color:#f92672">=</span> softmax(route_logits[length])
</span></span><span style="display:flex;"><span>state <span style="color:#f92672">=</span> route <span style="color:#f92672">@</span> leaf
</span></span></code></pre></div><p>它能学会把第几个输入位置搬到第几个输出位置。</p>
<p>但是它不是 TreeHeap。</p>
<h2 id="为什么-lxl-矩阵不是-treeheap">为什么 LxL 矩阵不是 TreeHeap</h2>
<p>一个 <code>L x L</code> route matrix 做的是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>output_position_i
</span></span><span style="display:flex;"><span>  = sum_j route[i, j] * input_position_j
</span></span></code></pre></div><p>它的世界里只有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>第 0 个 token
</span></span><span style="display:flex;"><span>第 1 个 token
</span></span><span style="display:flex;"><span>第 2 个 token
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>没有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[1]      root
</span></span><span style="display:flex;"><span>arr[2i]     left child
</span></span><span style="display:flex;"><span>arr[2i+1]   right child
</span></span></code></pre></div><p>也没有：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>当前在树的哪个 node
</span></span><span style="display:flex;"><span>下一步走 left 还是 right
</span></span><span style="display:flex;"><span>什么时候 stop
</span></span><span style="display:flex;"><span>当前 node 的 subheap 是什么
</span></span></code></pre></div><p>所以它最多叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flat sequence route
</span></span></code></pre></div><p>不能叫：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>TreeHeap route
</span></span></code></pre></div><p>这不是文字洁癖。这里差别很大。</p>
<p>如果我们说 TreeHeap 是一种数学结构，那么 proof 里的代码必须真的使用这个结构。不然就是拿矩阵贴了一个 TreeHeap 标签。</p>
<h2 id="重新定义什么才算-treeheap-route">重新定义：什么才算 TreeHeap route</h2>
<p>这次我们把规则写死。</p>
<p>一个合法的 TreeHeap route 必须长这样：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>i = 1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>while not stop:
</span></span><span style="display:flex;"><span>    S_i = [arr[i], arr[2i], arr[2i+1]]
</span></span><span style="display:flex;"><span>    action = K_theta(q, S_i, address_i)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    if action == left:
</span></span><span style="display:flex;"><span>        i = 2i
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    if action == right:
</span></span><span style="display:flex;"><span>        i = 2i + 1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    if action == stop:
</span></span><span style="display:flex;"><span>        return arr[i]
</span></span></code></pre></div><p>这里有四个硬条件：</p>
<table>
  <thead>
      <tr>
          <th>条件</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>arr[i]</code></td>
          <td>数据真的放在堆地址上</td>
      </tr>
      <tr>
          <td><code>arr[2i] / arr[2i+1]</code></td>
          <td>左右孩子是真的树结构</td>
      </tr>
      <tr>
          <td><code>stop/left/right</code></td>
          <td>route 是一步一步走出来的</td>
      </tr>
      <tr>
          <td>action trace</td>
          <td>evidence 里能看到走过哪些边</td>
      </tr>
  </tbody>
</table>
<p>没有这些，就不叫 TreeHeap route。</p>
<h2 id="这次-proof-要证明什么">这次 proof 要证明什么</h2>
<p>我们不直接跳到翻译。</p>
<p>这次只证明一个很小的东西：</p>
<blockquote>
<p>给定一个被 TreeHeap mirror 过的句子，模型能不能从 <code>arr[1]</code> 开始，通过递归 <code>stop/left/right</code> 路径，把原句读回来？</p></blockquote>
<p>注意，这里有两个动作：</p>
<ol>
<li><strong>扰动</strong>：用 TreeHeap 的 <code>mirror(root)</code> 把整棵树翻转。</li>
<li><strong>恢复</strong>：不用 <code>L x L</code> 矩阵，而是用 recursive route 从 root 一步一步走到目标 leaf。</li>
</ol>
<h2 id="数据怎么构造">数据怎么构造</h2>
<p>数据来自：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/mnt/nas/datasets/wmt_massive/train.massive.zh-en.tsv
</span></span></code></pre></div><p>这次取英文侧短句：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>samples = 20,000
</span></span><span style="display:flex;"><span>heap max_len = 32
</span></span><span style="display:flex;"><span>train lengths = 3..24
</span></span><span style="display:flex;"><span>OOD lengths = 25..32
</span></span></code></pre></div><p>也就是说：</p>
<ul>
<li>训练时只看长度不超过 24 的句子；</li>
<li>测试时看长度 25 到 32 的句子；</li>
<li>这样可以检查旧式 <code>route_logits[length, ...]</code> 是否只是记住了每个长度的一张表。</li>
</ul>
<h2 id="treeheap-mirror-是什么">TreeHeap mirror 是什么</h2>
<p>假设有 32 个 leaf。</p>
<p>原句写入 leaf：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf 0  leaf 1  leaf 2  ... leaf 31
</span></span><span style="display:flex;"><span>w0      w1      w2          PAD
</span></span></code></pre></div><p>整树 mirror 后：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf 0  leaf 1  ... leaf 29 leaf 30 leaf 31
</span></span><span style="display:flex;"><span>PAD     PAD         w2      w1      w0
</span></span></code></pre></div><p>所以如果我们想恢复 canonical position <code>p</code>，应该去 mirror 后的：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>target_leaf = 31 - p
</span></span></code></pre></div><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>p = 0
</span></span><span style="display:flex;"><span>target_leaf = 31
</span></span></code></pre></div><p>在堆里，32 个 leaf 的 node 编号是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>leaf 0  -&gt; node 32
</span></span><span style="display:flex;"><span>leaf 31 -&gt; node 63
</span></span></code></pre></div><p>所以读取 <code>p=0</code> 时，route 应该从 root <code>node 1</code> 一路走到 <code>node 63</code>。</p>
<h2 id="递归路径长什么样">递归路径长什么样</h2>
<p>实验里保存了 action trace。</p>
<p>一个 OOD 例子：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;pos&#34;</span>: <span style="color:#ae81ff">0</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;target_leaf&#34;</span>: <span style="color:#ae81ff">31</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;actions&#34;</span>: [<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">0</span>],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;node&#34;</span>: <span style="color:#ae81ff">63</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这里约定：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0 = stop
</span></span><span style="display:flex;"><span>1 = left
</span></span><span style="display:flex;"><span>2 = right
</span></span></code></pre></div><p>所以这条路径是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>root
</span></span><span style="display:flex;"><span>-&gt; right
</span></span><span style="display:flex;"><span>-&gt; right
</span></span><span style="display:flex;"><span>-&gt; right
</span></span><span style="display:flex;"><span>-&gt; right
</span></span><span style="display:flex;"><span>-&gt; right
</span></span><span style="display:flex;"><span>-&gt; stop
</span></span></code></pre></div><p>也就是：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>arr[1]
</span></span><span style="display:flex;"><span>-&gt; arr[3]
</span></span><span style="display:flex;"><span>-&gt; arr[7]
</span></span><span style="display:flex;"><span>-&gt; arr[15]
</span></span><span style="display:flex;"><span>-&gt; arr[31]
</span></span><span style="display:flex;"><span>-&gt; arr[63]
</span></span></code></pre></div><p>这才是 TreeHeap route。</p>
<h2 id="对照组旧的-flat-route-matrix">对照组：旧的 flat route matrix</h2>
<p>我们也保留了旧方法作为 baseline：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>route_logits[length, out_pos, in_pos]
</span></span></code></pre></div><p>它在训练长度 <code>3..24</code> 上可以学得很好。</p>
<p>但是 OOD 长度是 <code>25..32</code>。</p>
<p>因为它是“每个 length 一张表”，没有见过的长度对应的表没有被训练过。</p>
<p>所以它应该失败。</p>
<p>这个 baseline 很重要，因为它帮助我们区分：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>真的学了 TreeHeap 地址规律
</span></span></code></pre></div><p>和：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>只是记住了长度对应的位置矩阵
</span></span></code></pre></div><h2 id="实验结果">实验结果</h2>
<p>脚本：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/src/s1_recursive_treeheap_route_probe.py
</span></span></code></pre></div><p>evidence：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ara/s1-echo/evidence/s1_recursive_treeheap_route_probe/
</span></span></code></pre></div><p>结果：</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th style="text-align: right">数值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>hard TreeHeap oracle OOD exact</td>
          <td style="text-align: right"><code>1.0000</code></td>
      </tr>
      <tr>
          <td>learned recursive route OOD exact</td>
          <td style="text-align: right"><code>1.0000</code></td>
      </tr>
      <tr>
          <td>learned recursive route OOD token acc</td>
          <td style="text-align: right"><code>1.0000</code></td>
      </tr>
      <tr>
          <td>flat length-matrix OOD exact</td>
          <td style="text-align: right"><code>0.0000</code></td>
      </tr>
      <tr>
          <td>flat length-matrix OOD token acc</td>
          <td style="text-align: right"><code>0.0097</code></td>
      </tr>
  </tbody>
</table>
<p>pass checks：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;oracle_ood_exact&#34;</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;recursive_ood_exact_ge_0_99&#34;</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;recursive_uses_step_actions&#34;</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;flat_length_matrix_fails_unseen_lengths&#34;</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>这次 proof 通过。</p>
<h2 id="这个结果说明什么">这个结果说明什么</h2>
<p>它支持一个很窄但很重要的 claim：</p>
<blockquote>
<p>TreeHeap mirror recovery 可以用递归 <code>stop/left/right</code> 路由实现，而不必退化成 <code>L x L</code> 平面矩阵。</p></blockquote>
<p>也就是说，我们终于把这两个东西分开了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>flat route matrix:
</span></span><span style="display:flex;"><span>  一个序列位置重排器
</span></span><span style="display:flex;"><span>  可以有用
</span></span><span style="display:flex;"><span>  但不是 TreeHeap
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>recursive TreeHeap route:
</span></span><span style="display:flex;"><span>  从 arr[1] 出发
</span></span><span style="display:flex;"><span>  每一步看当前子堆
</span></span><span style="display:flex;"><span>  输出 stop / left / right
</span></span><span style="display:flex;"><span>  在堆地址上移动
</span></span></code></pre></div><p>这就是 SPR-045 的核心价值。</p>
<p>它不是更大模型。</p>
<p>它是把数学对象认清楚。</p>
<h2 id="它没有证明什么">它没有证明什么</h2>
<p>这篇不能被扩大解释。</p>
<p>它没有证明：</p>
<ul>
<li>TreeHeap 已经会翻译；</li>
<li>TreeHeap 已经理解语义；</li>
<li>模型能自己发现该翻哪个 span；</li>
<li>模型能从自然语言里自动学到“时间状语前置”之类的翻译规律；</li>
<li>TreeHeap 一定优于 Transformer。</li>
</ul>
<p>更准确地说：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>这次证明的是 route mechanism。
</span></span><span style="display:flex;"><span>不是 language intelligence。
</span></span></code></pre></div><h2 id="对旧博客的处理">对旧博客的处理</h2>
<p>旧的 SPR-041、SPR-043、SPR-044 已经删除。</p>
<p>不是因为数字全部无效。</p>
<p>而是因为它们把两个层级混在了一起：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>数字上：
</span></span><span style="display:flex;"><span>  可学习矩阵确实能恢复 echo。
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>机制上：
</span></span><span style="display:flex;"><span>  它不是 TreeHeap route。
</span></span></code></pre></div><p>所以旧结论必须降级：</p>
<table>
  <thead>
      <tr>
          <th>旧实验</th>
          <th>新解释</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>SPR-041</td>
          <td>supervised canonicalization 数字有效，但 route 是 flat matrix</td>
      </tr>
      <tr>
          <td>SPR-043</td>
          <td>TreeHeap flip 扰动有效，但 learned inverse 是 flat matrix</td>
      </tr>
      <tr>
          <td>SPR-044</td>
          <td>WMT canonical echo 是 weak positive，但不是 path-route proof</td>
      </tr>
  </tbody>
</table>
<p>SPR-040 仍然保留，因为它证明的是 mirror 在堆地址和 kernel slot 上的代数等变性。</p>
<p>SPR-045 则补上了真正缺失的东西：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>recursive stop/left/right TreeHeap route
</span></span></code></pre></div><h2 id="下一步">下一步</h2>
<p>下一步不能又跳太大。</p>
<p>现在最合理的是做三个对照：</p>
<ol>
<li>
<p><strong>flat shared route baseline</strong><br>
不按 length 分表，而是共享一套矩阵，看看还能不能追上。</p>
</li>
<li>
<p><strong>pointer baseline</strong><br>
用普通 pointer network 读位置，检查 TreeHeap route 是否真的有结构优势。</p>
</li>
<li>
<p><strong>弱化监督</strong><br>
现在 target position 是给定的。下一步要逐渐减少这个条件，让模型开始学习“该读哪个 subheap”。</p>
</li>
</ol>
<p>只有这些继续成立，S1 route 才能往 S2 翻译方向接。</p>
<p>这篇的结论很朴素：</p>
<blockquote>
<p>不要拿矩阵冒充 TreeHeap。<br>
TreeHeap proof 必须真的走树。</p></blockquote>
<p>这次终于走树了。</p>
<blockquote>
<p>ARA: <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/s1_recursive_treeheap_route.md">S1 recursive TreeHeap route</a> / <a href="https://github.com/houming818/sametime/tree/main/ara/s1-echo/evidence/s1_recursive_treeheap_route_probe">evidence</a> / <a href="https://github.com/houming818/sametime/blob/main/ara/s1-echo/logic/claims.md">claims</a></p></blockquote>
]]></content:encoded>
    </item>
  </channel>
</rss>
