接入含章·通变的拼音解码、整句重排与词图兜底生成,扩展 macOS、Windows 和 Linux 的模型加载路径。模型文件按正式标识归档,保留旧用户目录回退,并同步数据打包、评测记录和用户文档。
7.7 KiB
模型假设与验证尺子
输入法里「模型可能能做的事」不止整句重排一件。每一件在动手之前都要先回答:用什么指标算成功、指标从哪些数据算、
现在的基线是多少。基线算不出来的假设不立项。这份文件记每个假设的尺子;输入日志(input-log.jsonl)按这里的需要定格式,
回放评测(qingjian-cli --replay)按这里的指标出报告。
原则
- 日志记的是情境、给的、做的、事后反馈四件事,不是某个模型的特征。字段与模型无关,任何排序 / 预测 / 纠正类假设都能回放验证。
- 漏记的补不回来,多记的代价很低:情境数据只要隐私成本接近零就记。
- 不记应用里的光标前文(含用户没通过青简打的内容)、逐键时间戳、Secure Input 期间的任何东西。
- 每个假设先写指标与基线,再改代码;改完在同一份冻结日志上比(日志是活的,两次复制的不一样)。
- 日志验不了的(延迟、UI 感受、反事实「当时给了 X 会不会选」)只能自己用;反事实只在 X 恰好出现在用户最终文本时近似。
日志格式 v1
一行一条 JSON,t 是本机时间戳,event 是事件名;读端跳过不认识的事件与字段,以后加字段不升版本。
| 事件 | 何时 | 字段 |
|---|---|---|
session |
输入法启动、日志开关打开时 | v 格式版本、version 输入法版本、platform、model 本地整句模型开没开、scheme 双拼方案 |
commit |
每次上屏 | 原有:id scope keys pinyin corrected text source index top(一页 9 条)scheme english;新增:rescored 候选顺序经过神经重排、app 应用标识、pages 翻了几页、ms 首键到上屏的毫秒 |
retract |
上屏后整个退格删掉、同段拼音改选了别的 | of text chosen |
retype |
组句里退格重打,最终键串与第一次退格前不同;或上屏后删掉重打了不同的键 | before after of(对应的上屏 id) |
passthrough |
组句外直打的标点 / 回车 / 空格,攒到下一次上屏或边界时写 | text |
prediction |
云端联想结果到达并展示 | scope words sentence |
break |
上文链断开(切应用、失焦、清空) | app 新应用标识 |
假设与尺子
| 假设 | 指标 | 用哪些字段 | 基线 |
|---|---|---|---|
| 整句重排(已做) | 词 / 整句首选命中 | commit 的 top index |
2026-09-12 冻结日志 12886 条可评:词 86.9% / 整句 90.2% / 英文 82.9%(原样上屏也回放进学习之后;之前的 72.5% 是回放没学个人英文词);短语层进词库后 87.3% / 88.2% / 82.5%(整句掉的多半是旧引擎没有短语时用户只能选前缀的偏差,见 docs/notes/phrase-layer.md);领域词 48 条进词库后 87.6% / 88.4% / 82.5%(docs/notes/domain-words.md) |
| 排序常数(个人 n-gram 插值 λ / K / 封顶 / D,敲错四类代价 / 折扣上限 / 整段纠错代价) | 同上,--tune 名=值 扫网格 |
同上 | 2026-09-12 扫过一轮:全在平台区,见 docs/notes/constant-sweep.md |
| 个人微调(LoRA) | 按天留出的首选命中 | commit 文本流 + passthrough + break |
同上,待按天切 |
| 敲错纠正 | 对 retype 的召回、对正常输入的误纠率 |
retype、commit.corrected |
待攒(事件新加) |
| 本地联想替代云端 | 预测的下一词 = 用户接着打的词;云端被接受的比例 | prediction + 紧接的 commit.source |
待攒 |
| 中英混输判定 | 判成英文 vs 用户原样上屏 | commit.source == raw 且键像英文词 |
可从现有日志算 |
| 候选质量的隐式信号 | 翻页数、组句耗时与命中率的相关性 | commit.pages commit.ms |
待攒 |
| 按应用风格 | 分应用的首选命中 | commit.app |
待攒 |
| 长句切分 / 简拼展开 | 切分与最终文本的对齐 | commit.pinyin commit.text |
可从现有日志算 |
| 神经重排的净效果 | rescored 为真 / 假两组的首选命中 |
commit.rescored |
待攒 |
| 神经 P2C(带噪拼音直接生成汉字) | 整句首选 + 一次重解码的耗时,两者都要过 | commit 的 keys pinyin corrected text(天然就是「带噪拼音 → 正确文本」的监督对) |
整句首选 41.6%(冻结集 8322 句,当前带重排的成绩,不是裸基线 37.6%);延迟见下节与 docs/notes/p2c-latency-spike.md |
神经 P2C 的延迟门槛(2026-09-20 量过)
这个假设与别的不同:准确率赢了但延迟不达标,一样不立项。把词库召回换成模型生成之后, 候选的存在本身就依赖模型,而拼音前缀每敲一键就变、整句要重解码一次,所以延迟是第一道门槛而不是最后一道。
crates/qingjian-neural/examples/p2c_bench.rs 在 M1 本机拿现有字级模型当代理量过一轮(完整表格与偏差说明见
docs/notes/p2c-latency-spike.md)。延迟只能在目标设备上量,租的卡量不了:用户跑的是 mac 的 Metal 与 Windows 的 CPU。
| 项 | 门槛 | 代理模型(full-small 23M) |
|---|---|---|
| 一次整句重解码(Metal,前文 64,beam 4,8 字) | < 100 ms | 68 ms ✔ |
| 同上,CPU | < 150 ms | 141 ms(勉强) |
| 每键增量(前文 64 字,推进 1 个 token) | < 10 ms | Metal 2.1 / CPU 6.7 ✔ |
| 模型加载 | < 500 ms | 66 ms ✔ |
已知结论:拼音前缀可缓存、成本可忽略;瓶颈是解码的前向(占 Metal 66% / CPU 95%),把 top-k 搬上 GPU 也只省掉 Metal 那 28%。因此 P2C 当同步主候选不成立(beam 8 / 16 字 Metal 218 ms、CPU 416 ms,追不上 5 到 8 键每秒的手速), 可行的位置是现有的停键异步槽位,词库继续出同步候选。
P2C 值得试的理由是它能做三件当前架构做不到的事:未登录词按字生成、纠错进模型本身、
句中英文(现在 english_tail.rs 只支持句末尾段,见「中英混输判定」那一行)。三件在离线前提下都没有别的解法。
已知的尺子偏差
- 日志里「选了」的整句多半是当时按空格接受的基线自己的输出:模型对、日志错的例子不少(输入狂 → 输入框)。
整句质量以冻结评测集
data/eval/sentences.tsv为准(见docs/notes/neural-rescoring.md),回放只看词级与个人学习。 - 2026-09-12 以前的日志有一半是空的
raw行(壳每次回车 / 失焦都调一次take_raw),读端要跳过keys与text都空的行。 - 回放里原样上屏(
raw)也要走一遍take_raw:个人英文词(gist)与「这个串不纠」都是从那里学的,跳过它英文首选低 10 个点(72.5% → 82.9%), 那不是排序的问题,是尺子没学。2026-09-12 起回放这么做。 - 整句「不在候选」328 条的构成(2026-09-12):16 条是 青简(词库没有的专名,个人词该学但回放从零起);294 条与现在首选同长、只是同音换字
(184 条差一字、112 条差两字:我之前 → 我只前、行的 → 型的、新写的 → 新鞋的),这一类靠上下文分,归神经重排与个人 n-gram,
其中不少「选了」本身就是当时按空格接受的错句(是按、所有哟偶、你先准备以下);18 条长度不同,是切分 / 简拼尾巴(准备以 ←
zhunbeiyix)。 - 词级没命中 1208 条里 742 条是 5 键以上、当时从词候选里选的短语(导航栏 / 候选框 / 我绷不住了 / 对齐),多半是词库缺词而不是排序;
最常重复的键是
ba(45 条,吧 / 把 看上下文)与wode(34 条,词库缺 我的)。调常数救不了这两类,要补词库与靠上下文模型。