mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-26 12:23:23 +00:00
嵌入式模型推理(ONNX)本身已是 C++,**可优化的 Go 侧是分词器与预处理**。 本轮先测出成本分布,再改,且**不假设 C 更快**。 ## 实测(合成词表,无需 CHINESECLIP_MODEL_DIR) | 场景 | ns/op | allocs | |---|---:|---:| | short_zh | 25681 | 60 | | short_en | 19100 | 43 | | mid_en | 117343 | 451 | | mid_zh | 189260 | 1047 | | punct_heavy | 283265 | 1388 | | long_zh | 757746 | 4233 | ## pprof 指出的分配源(alloc_objects,mid_zh) - splitOnPunctuation **33.5%**(每 token 都做 []rune + string(cur)) - wordpiece **32.3%**(内层每轮候选都 string(runes[a:b]),多数未命中) - stripAccents/NFD 33.6% cum - basicTokenize 自身只 1.4% ## 改了三处 1. `basicTokenize`:`len([]rune(token))` → `utf8.RuneCountInString` (原为「数个长度」就把整个 token 转 rune 切片) 2. `splitOnPunctuation`:去掉整串 []rune,改逐 rune 扫描 + 一次 flush 3. `wordpiece`:预建 rune 边界表,按字节区间取 substring, 消除「每轮候选都构造 string」 ## ★★ 差分 oracle 抓到一处**真实语义缺陷**(非测量噪声) 本机无模型产物,权威的 TestTokenizerMatchesOfficialReference 会 **SKIP** ⇒ 仅靠现有测试,我的重写**没有被有效验证**。故把改动前的实现原样内联为 oracle 做差分(split/wordpiece/basicTokenize/Encode 四组 + 随机字节 2 万组 + 随机 rune 5000 组)。 它立刻抓到:`"\xbc\xef=..."` 旧实现得 `["��" ...]`,新实现得 `["\xbc\xef" ...]`。 根因是 `[]rune(s)` 会把**非法字节归一成 U+FFFD**,而纯字节切片原样保留坏字节。 ⇒ 真实差异(会进日志/去重/hash),已改为对非法序列写回 RuneError,与旧行为逐值一致。 ## 诚实的收益结论:**基本没有** 改动后:mid_zh 189260(改前 186777)、long_zh 757746(改前 786416)、 mid_en 117343(改前 120422)。分配数 mid_en -40%、其余基本持平, **时间无实质改善**(部分场景还略慢)。 复查原因(不掩盖):重新做 CPU profile 后发现 **~25% 的样本是 runtime 锁/抢占**(unlock2 8.1% + lock2 6.8% + procyieldAsm 6.8% + asyncPreempt 5.4%),而 utf8/unicode 相关不足 20%。 且 GOMAXPROCS 敏感:1→375365ns、4→209922ns、12→189543ns ⇒ **大量时间花在调度与 GC 而非分词算术**。 ⇒ 结论:Go 侧微优化这条路**已到头**。真正的杠杆在别处: ① 提高 GOMAXPROCS/减少 GC 压力 ② 批量分词(降低每条输入的固定开销) ③ 减少送入模型的 token 量。三者都不是 C 能解决的。 改动本身保留(正确性等价、有 oracle 守护),但**不应据此宣称性能收益**。 与 C 化那几刀同一条纪律:没有数据支撑的优化不算优化。 验证:差分 oracle 6 组全过(含非法 UTF-8);providers/... 全绿。