# 模型与训练设计

## 表示和所有权

`Model` 保存复制后的 Gram、碰撞安全 token 序列索引和排序词表。索引以 U+001F 分隔 token；token 验证禁止此控制字符，因此 `a b` 两词不会与单词 `ab` 冲突。公开读接口返回复制后的记录和数组。单独的 `Scorer` 拥有历史和累积结果，可分叉，不修改 Model。

ARPA 是文本交换格式。读入必须先满足预算、记录数和 section 状态机，再构造有词表闭包的模型。写出排序只依赖阶数和 token 字典序，保留 Double 的往返精度。不执行剪枝、补全缺失 n-gram 或自动归一化。

## 回退评分

对历史 h 和当前词 w：存在 (h,w) 时返回显式 log10 概率；否则加上 h 的 backoff（缺失为零）后递归查询 suffix(h)。到空历史时必须存在 unigram。词表外输入先按调用方策略映射。返回匹配阶数、实际退阶次数和累积 backoff，便于逐词诊断。

有限数值相加溢出视为错误；显式负无穷可以传播为不可能事件。任意外部 ARPA 的正回退权重可能产生大于一的条件概率，因此结构合法不保证概率模型归一化。审计全词表求和并以补偿求和减小浮点误差。

句子默认以一个 `<s>` 初始化历史；不用重复 BOS 填满模型阶数。预测每个词及 EOS，只保留最近 n-1 个映射词。流式 `feed_batch` 先在 fork 上运行，全部成功才提交新状态。`finish` 可重复调用，成功后不能追加词。流式预算约束累计保留的原始 token 文本及结果数，包含 EOS；普通句子预算约束调用方的输入 token，EOS 由选项补入。累计文本超限时，单次追加、批次和结束操作均保持原状态；fork 继承预算消耗，reset 清零。

## 计数与估计

每句只计一个 BOS 上下文和一个 EOS 事件。BOS 自身不作为预测事件，其 unigram 概率为零；词表强制包含 BOS/EOS/UNK。unigram 对除 BOS 外的词施加正的 additive prior。训练集为空时 EOS 和 UNK 平分质量。

MLE 高阶条件概率为 C(h,w)/C(h)，有观测延续的历史将 unseen mass 设为零（ARPA backoff 为 -inf），未见历史直接回退。它会对不曾见过的组合给出零概率，这是可预期行为。

插值绝对折扣对 0<D<1 使用：

```
lambda(h) = D * T(h) / C(h)
P(w|h) = max(C(h,w)-D, 0)/C(h) + lambda(h)*P(w|suffix(h))
```

T 是不同观测延续数。导出时，对出现过的 n-gram 写入已经插值后的完整概率；对不存在的 n-gram，ARPA backoff(lambda) 负责下阶部分。这一点避免将 interpolation 错写为仅 seen 部分，从而丢失概率质量。按低阶到高阶构造，最多八次线性扫描，不采用 modified Kneser-Ney 或声称与 KenLM lmplz 训练一致。

固定词表按训练词频降序、词形升序截断；阈值后词统一映射为 UNK，留出数据不会重新拟合词表。Counts 可相加合并，但各分片必须使用相同阶数和 token/边界约定。先映射、再计数可以避免分片使用不同词表。

## 复杂度与验证边界

索引查找预期为常数时间，但键构造与历史长度有关；条件评分最多八次退阶。排序依赖运行时比较器，复杂度约为 O(R log R)。预测会扫描词表；语料训练保留全部计数，适用于有界小语料。预算限制事件与文本单位，不是精确的 CPU/内存配额。

Python oracle 使用独立的线性概率递归、Counter 与不同的窗口构造检查训练和 ARPA 输出，减少相同 log 实现互相验证的风险。KenLM 固定输入验证外部参考行为，但不执行上游编译器/引擎，不覆盖全部 ARPA 方言。没有测量吞吐或宣称替代大型生产解码器。
