Files
qingjian/docs/notes/phrase-layer.md
T
yenharvey 5380636c82 领域词:从输入日志人工挑 48 条(对齐 / 后端 / 词库 / 候选框 / 看看 / 再也)进基础词库,语言模型走短语同款合成计数
- assets/lexicon/domain_words.tsv:日志里选过 ≥ 2 次、词库与短语层都没有、公开语料里出现过的词;次数用语料次数,不到 20 的按 20,多音字拼音给全
- bigram --phrases 可重复给:领域词当 token 统计会吸走成分词的二元证据(词库 77 次 → 词 + 库 路径没了,整句出 助词哭),走合成路整句得分与原路径一样
- 回放 词 8064 → 8098、整句 2977 → 2983,整句评测集 37.6% 持平(字准确率 76.8 → 76.9);同步 dict.tsv 与领域词库
- 记录:docs/notes/domain-words.md、QINGJIAN.md 4d
2026-09-12 12:04:10 +08:00

72 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 短语层(2026-09-12)
## 起因
常数扫描(`constant-sweep.md`)之后看没命中的构成:词级 1208 条没命中里 742 条是 5 键以上的短语当词选,
日志里上屏过、词库没有的汉字串 2271 个,选过两次以上的 449 个,最常见的是 我的(57 次)/ 好的 / 都是 / 更好 / 我觉得 / 而不是。
它们不是「新词」,是常用词表(liuxilu 5.6 万条)按词典收词原则不收的组合;`mine` 挖语料那步的虚词规则又把含 的 / 不 / 是 / 有 的全滤掉了。
所以缺的不是数据新旧,是「人会整块打出来」的短语层。
## 挖法:`dict-convert phrases`
- 语料按词库分词,两遍扫:第一遍数相邻两词,第二遍数两段二元都够频的相邻三词。
- 次数按语料文件分开数,**总次数与对话语料(LCCC)里的次数都要 ≥ 2000**:维基里的模板句(一个市镇、面积为、人口密度)次数再高也不是人会打的。
- 不用点互信息:虚词组合的 PMI 天然低,而它们正是要收的。只用边界规则(`phrases/rules.rs`):
不以 的了着得地吗吧呢啊 开头,不以 不没很太也都又再才还把被和与及或而且但 与数词结尾;代词 + 了 / 这 / 那 是碎片;
单字 + 代词只认 给让帮等找叫送陪问那… 这些(给我 / 那我 成,这你 / 天你 不成);次数刚过线的再套「单字 + 的 只认代词」「是 / 在 + 单字不要」,
够常见的(≥ 5 倍下限)不套——好的 / 真的 / 是啥 是人天天打的,多的 / 岁的 / 是新 不是。
- 笑声串不算相邻:你哈哈哈 切成 你 / 哈哈 / 哈,一个 哈 token 挨着另一个 哈 时含它的窗口不计,否则 你 + 哈哈 会灌成高频短语。
孤立的 哈 照常,所以 你哈(谢谢你哈,LCCC 三千多次)仍在——它是真的。
- 读音由成分词拼出(同一个词多个读音取词频最高的),不用再标多音字;`--extra-words` 文件加了第三列拼音,`lexicon` 给了就不按字猜。
- 结果 5398 条(二词 4300 多、三词 1100 左右),人工抽样精度约九成,覆盖日志 449 个缺词里的 188 个(语料里 ≥ 20 次的 299 个里 170 个)。
剩下的是 词库 / 对齐 / 后端 这类语料里少的领域词,与 是不 / 看一 这类日志里接受的碎片。
- 词库已并入短语后重跑要 `--refresh assets/lexicon/phrases.tsv`:不摘掉上次的短语,我的 就是一个词,挖不出 我 + 的(踩过:只挖出 34 条)。
## 进语言模型的三种接法(都在同一份冻结日志 + 整句评测集上比)
| 接法 | 整句评测集首选 | 回放 词 | 回放 整句 |
|---|---|---|---|
| 改前 | 37.6% | 8032 | 3045 |
| A 短语当 token 重训 bigram | 38.4% | 8092 | 2878 |
| B 语言模型不动、短语只进词库 | 37.6% | 8067 | 2929 |
| C 分词摘掉短语、统计完按成分合成计数(采用) | 37.6% | 8064 | 2978 |
A 的整句评测涨了 0.8 个点(短语 token 相当于给了三元上下文),但回放掉 5 个点,看明细两个机制:
① 二十 压过 而是——短语当 token 后语料里的「而是」都归了 token,「而 + 是」的二元证据没了,而是 的一元又比 二十 低;
② 不对 / 不在 / 等会 / 放到 这类整句恰好是一个词的,以前是 Viterbi 路径 不 + 对 当整句候选排最前,现在整段是一个词就不出整句候选,
按词级排序放,部队 这种维基高频词压上来。B 没有①,但②仍在:短语对语言模型是未知词,兜底扣 4 nat。
C 是 `bigram --phrases`:分词时把短语摘掉(二元证据保住),统计完给每条短语合成
一元 = c(a,b)、前接 c(v,短语) = c(v,a)·c(a,b)/c(a)、后接 c(短语,w) = c(a,b)·c(b,w)/c(b),
于是 P(短语|v) = P(a|v)·P(b|a)、P(w|短语) = P(w|b),短语在词图与词级排序里的得分与原来走两个词的路径一样,只是多了个能整块选的词。
合成行 186 万条另加、不占真实二元行的 300 万名额(占了会把低频真实行挤掉,整句评测掉 0.4);`lm.qj` 29 MB → 44 MB,加载仍在 100 ms 内。
## C 的回放整句 −67 是什么
新增没命中 75 条、修好 30 条。75 条里:
- 一半以上是尺子偏差:旧引擎没有 那就是 / 你可以 / 我现在 / 然后就是 这些短语,用户当时只能选前缀 那就 / 你可 / 我先 再接着打,
日志记的是前缀;现在短语排第一、前缀第二,反而对。沃德 压 我的 也是回放早期从日志学了 沃德。
- 十来条真翻转:猜对 / 才对、不听 / 不停、没法 / 没发、说道 / 说到、要得 / 要的、在哪 / 在那、回事 / 会是。
这是聊天语料的先验与这个用户的习惯不一致,两边都是合法短语;个人学习选一次就翻回来。
- 比较好 / 比较高(`bijiaogao`):短语的一元是它真实的出现概率,比原来两步路径的乘积略高(差约 1 nat),刚好让邻键纠错 g → h 赢了。
整句评测集里没有敲错,所以那把尺子看不到这一类;量小,先不管。
## 品牌词
`assets/lexicon/brand.tsv`:青简 210,既是词频也写进语言模型一元(句首二元按八分之一算,与 请柬 的句首占比一致)。
只写词频没用:词级排序用语言模型概率,语料里没有的词兜底扣 4 nat,青简 排不进前三;句首二元给整个 210 又压过了整句 请见。
目标是 `qingjian` 下 请见(整句)/ 青简 / 请柬 的顺序,用户选一次个人学习就把它顶到第一。
## 复现
```bash
cargo run --release -p qingjian-dict-convert -- phrases data/corpus/*.txt # 重跑加 --refresh assets/lexicon/phrases.tsv
cp data/generated/phrases.tsv assets/lexicon/phrases.tsv
cargo run --release -p qingjian-dict-convert -- lexicon --pinyin data/generated/pinyin-llm.jsonl --frequency data/generated/lm-unigram.tsv \
--extra-words assets/lexicon/mined_words.tsv --extra-words assets/lexicon/phrases.tsv --extra-words assets/lexicon/brand.tsv
cargo run --release -p qingjian-dict-convert -- bigram --phrases assets/lexicon/phrases.tsv --phrases assets/lexicon/domain_words.tsv --brand assets/lexicon/brand.tsv data/corpus/*.txt
```
再 `pack dict` / `pack lm`(`bundle.sh` 会做),然后 `--eval-text data/eval/sentences.tsv` 与 `--replay` 冻结日志各跑一遍与改前比。