第一次真实语言生成:TreeHeap 从英文到中文,但还不是问答
前面的很多实验都很小:echo、路由、内部节点读出、概率桶、受控符号任务。它们帮助我们确认 TreeHeap 的一些局部算子可以工作,但始终留下一个最实际的问题:
TreeHeap 能不能真正参与自然语言的“输入一句话,输出另一句话”?
这次我们不再使用 toy token,也不读取历史上已经被降级的 TreeHeap checkpoint。我们直接在真实 WMT 英中平行语料上,从零训练一个最小的 seq2seq 系统。
先说结论:
真实文本的 TreeHeap encoder -> decoder 通路已经跑通。
它能输出成句、主题相关的中文。
但当前它没有赢过普通 flat GRU,也不能称为翻译成果。
更重要的是:这仍然不是问答任务。
这是一份首航报告,不是庆功报告。
1. 为什么先拿 WMT 做 seq2seq?
最终目标不是机器翻译,而是:
question + context
-> TreeHeap encoder
-> answer decoder
-> answer
也就是问答。
但问答数据需要三元组:
上下文、问题、答案
手头的 WMT 数据提供的是另一种真实的输入输出对:
英文句子 -> 中文句子
它不能证明模型会回答问题,却很适合先验证一个更基础的门:
TreeHeap 能否接收真实文本,
把它编码成可供 decoder 使用的状态,
并连续生成多步中文 token?
如果这一步都不成立,直接谈 QA 只会把 encoder、decoder、数据和评价混成一团。
所以这次 WMT 的身份是:
真实语言 seq2seq generation gate
不是最终 QA benchmark。
2. 这次模型到底长什么样?
输入是英文 SentencePiece token。例如:
English sentence
-> [t1, t2, t3, ...]
每个 token 先写入 TreeHeap 的叶子。然后按 left/right 递归组合:
parent
/ \
left right
局部组合不是简单相加:
h_parent = Compose_theta(h_left + e_left, h_right + e_right)
e_left 和 e_right 是不同的槽位向量,所以:
Compose(a, b) != Compose(b, a)
经过多层递归后,模型同时拥有:
叶子节点:具体英文 BPE token
内部节点:局部短语/子堆摘要
root:整句摘要
中文 decoder 每生成一个 token,都产生一个 query。它不是只读 root,而是在所有有效节点上分配概率:
p(i | q_t, H) = softmax(K_theta(q_t, h_i))
再把各节点状态按概率混合成当前上下文:
c_t = sum_i p(i | q_t, H) h_i
最后生成下一个中文 token。
这可以理解为:
decoder 每说一个中文词,
都在 TreeHeap 的叶子和内部子堆之间做一次概率读取。
训练时只有标准的 teacher-forcing 交叉熵:
L = sum_t CE(P(y_t | y_<t, H(x)), y_t)
没有人工句法树、没有 route 标签、没有类别标签、没有五个 loss 的大锅炖。
3. 真实数据与对照
数据:
/mnt/nas/datasets/wmt17/train.zh-en
方向:English -> Chinese
训练 / 验证 / 测试:30,000 / 2,000 / 2,000
最大 BPE 长度:24
训练:10 epochs
GPU:io 的 RTX 3090,270W 限制保持不变
我们没有只跑 TreeHeap。三种 encoder 使用相同的自回归中文 decoder 与相同的翻译 loss:
| Encoder | 输入能保留什么? |
|---|---|
| BoW | 英文 token 的平均向量,不保留顺序。 |
| Flat GRU | 有序英文 token 序列。 |
| TreeHeap | 英文叶子、递归内部子堆、root。 |
这使问题变得很朴素:TreeHeap 现在到底比无序词袋、比普通有序序列,做得怎样?
4. 数字结果
完整运行耗时:
606 秒,约 10.1 分钟
| Model | Test NLL ↓ | PPL ↓ | token-BLEU4 ↑ |
|---|---|---|---|
| TreeHeap | 5.129 | 168.8 | 1.48 |
| BoW | 4.948 | 140.9 | 1.43 |
| Flat GRU | 4.799 | 121.4 | 2.87 |
这里的 token-BLEU4 是脚本内的 BPE-token 近似指标,不是官方 WMT BLEU,不能拿来和论文榜单比较。
数字的诚实解释是:
TreeHeap 已经能学习真实 seq2seq。
TreeHeap 的生成指标略高于 BoW,但差异很小。
TreeHeap 明显落后于 flat GRU。
所以这轮不能支持:
TreeHeap 当前配置优于普通序列模型。
5. 输出到底像不像中文?
看几个测试集样例。下面没有润色。
EN: In order to fund this spending, revenues must be raised.
REF: 为了支撑这笔费用,就必须增加政府收入。
TH : 鉴于这一观点,我们必须增加支出。
EN: When it comes to economic policy, a fast, faulty decision is often better than inaction.
REF: 当谈到经济政策时,一个快速的、错误的决定通常是比无所作为要好。
TH : 鉴于经济决策,但通常比经济决策,因为其决策的境况通常是积极的。
EN: Furthermore, the slow pace of European decision-making has compounded Greece's troubles.
REF: 此外,欧洲缓慢的决策过程也加深了希腊的麻烦。
TH : 此外,英国选民决定了欧洲国家,但英国退出投票。
这些结果同时说明两件事。
第一,正面信号:
模型并非输出随机 token。
它学会了中文连接方式、部分句式、标点和主题领域词。
“欧洲 / 希腊 / 经济 / 决策 / 支出”等语义场会进入输出。
换句话说,S3 的表面语言 decoder 已经开始工作。它不再只是输出类别桶,也不只是复制输入。
第二,关键不足:
主题相近,不等于关系正确。
模型经常把训练集中同一主题的短语拼接到一起:
欧洲 -> 英国
财政刺激 -> 财政紧缩
决策缓慢 -> 退出投票
句子表面像中文,但事实关系、指代和谓词绑定仍然很不稳定。
6. TreeHeap 内部节点有没有参与?
我们还做了一个不重新训练的读取消融:
full 可读叶子和所有内部子堆
leaf_only 隐藏内部节点,只读叶子
root_only 只读整句 root
greedy 生成的 token-BLEU4:
| Read mode | token-BLEU4 |
|---|---|
| full | 1.48 |
| leaf_only | 1.26 |
| root_only | 0.037 |
这说明 root 不是一个足够的万能 hash:只给 root 时,生成几乎崩溃。完整 TreeHeap 比 leaf-only 有小幅提升,说明内部节点可能已经带来一部分可用信息,但增益仍然很弱。
有一个审计细节必须记录:当前脚本的 ablation NLL 仍错误地沿用了 full-memory 的 teacher-forcing 路径,因此 ablation 的 NLL 相同、不能解释。上表只使用实际走 ablation read path 的 greedy generation 指标。下一次应加载本次 checkpoint 修正后重算,不必重训。
7. 这不是 QA,但它为 QA 打开了什么?
问答任务应该是:
[QUESTION] + [CONTEXT]
-> TreeHeap
-> answer tokens
这次 WMT 实验没有 question,也没有 answer span,因此不能叫 QA。
但它已经确认了 QA 所需的一条基础通路:
真实文本
-> TreeHeap encoder
-> 多步 decoder
-> 自然语言输出
下一步不是继续把翻译 BLEU 当最终目标,而是换成真实 QA 三元数据:
context, question, answer
然后比较:
TreeHeap encoder
BoW encoder
flat sequence encoder
评价也应换成 QA 的答案指标,例如 exact match、token F1、ROUGE 或 answer BLEU,而不是只看翻译分数。
8. 当前 ARA 状态
S3-WMT-SEQ2SEQ-C01
-> supported feasibility / negative comparative result
它支持的是:
TreeHeap 可以从真实 WMT 文本端到端训练,
并驱动一个中文 seq2seq decoder 产生可读、主题相关的句子。
它不支持的是:
TreeHeap 已优于 flat sequence。
TreeHeap 已完成翻译。
TreeHeap 已完成问答。
TreeHeap 已学到稳定世界模型。
这份边界不是泼冷水。它把下一步变得非常明确:先修正 internal-node ablation 的 teacher-forcing 评价,再接入真实 QA 数据,让 TreeHeap 的子堆读取回答“哪段 context 支撑当前答案”。