摘要

开战前的“准备页”(确认页)列出英雄、技能、子技能、装备、军队和法术。程序读这页主要靠两件事:在每个固定槽位里用模板匹配认出图标身份,再用 OCR 读数字。项目的目标是 App 预热后每张图 p95 ≤3 秒,而当时热态读一张准备页要约 5 秒。

本实验在严格的预算下做性能诊断:基线和候选各只允许 3 次公开请求(冷 B1、热 B1、热 B2,B1/B2 是两张准备页截图),总共 6 次。分析发现准备页根本不用整图 OCR 模型,却每次都加载它,于是唯一的候选改动是“整图 OCR 模型在第一次真正用到时才加载”。结果:冷请求省了 1.36 秒,所有识别输出严格相等;但热请求仍超过 3 秒,主要耗时在模板匹配。下一步的“同类槽位批量模板计算”只写成了预执行协议,没有运行。

要回答的问题

  1. 准备页读取的时间花在哪里?
  2. 能否在不改变任何识别结果(身份、数字、框、分数、拒识)的前提下,找到一处安全的重复工作并去掉?

数据与来源

两张准备页原图,来自同一个保守来源组,独立验收对局数为 0;这是已曝光的开发诊断。参考答案复用之前已审的完整参考:两张图共 155 个“已知”原子项(英雄身份、职业、数字、资源、技能、子技能、装备、军队、法术等),参考只用于事后评分,读取请求不带标签。

方法

  1. 调用前把图像路径、文件大小/修改时间、参考路径、源码状态和阈值写入冻结 JSON,并先在本地提交执行器。
  2. 每批启动一个新的常驻进程,依次发冷 B1、热 B1、热 B2 三次请求,用 cProfile(Python 性能剖析器)记录各部分耗时;不预热、不重试、不补读。
  3. 基线三次请求后选择候选:三次请求整图 OCR 调用都是 0,但启动日志显示加载了整图检测模型、它的识别模型和另一个裁图识别模型——准备页只用裁图识别模型。
  4. 唯一改动:私有读取器中整图 OCR 改为首次访问时创建、成功后常驻复用;加载失败照常抛出且不缓存。阈值、裁区、读数次数、设备、公开响应都不变。
  5. 正确性:每对完整响应只排除事先声明的两类耗时字段 seconds,其余做严格类型和值比较,不加浮点容差、不加豁免字段;另用原评分器对 155 项评分。

设置

既有环境和已缓存的 PP-OCRv6 模型,不安装、不下载。测量期间其他会话在并行工作,没有独占 GPU/CPU,所以只能算有限的开发诊断。

结果

请求 基线 provider 秒 候选 provider 秒 基线/候选往返秒
冷 B1 13.0502 11.6916 13.6955 / 12.2052
热 B1 4.9870 4.7473 4.9954 / 4.7552
热 B2 4.6368 4.4864 4.6438 / 4.4925

冷请求减少 1.3586 秒(10.41%)。热态路径没有改动图标计算,热请求 0.24/0.15 秒的差异不能归功于候选,可能来自并行负载和计时波动。三对完整响应严格相等;候选日志里不再出现整图检测模型的加载。另一个独立 QA 只读保存证据复核了 796 项检查,全部通过。

识别分母(两张图、155 个已知项): 正确 151、缺失 2、未知 2、错误 0;严格整图全对 0/2。

项目 正确 / 已知
英雄身份 2/2
职业 0/2(公共格式未暴露,计为缺失)
英雄数字 / 资源 14/14 / 12/12
主技能身份 / 等级 11/11 / 11/11
子技能身份 17/17
装备身份 18/18
军队身份 / 数量 14/14 / 14/14
法术身份 / 显示等级 19/20 / 19/20

参考中的空位共 77 个,零误填;但其中 48 个是两张图各 24 个背包槽根本没实现,不能把它们当作“正确识别为空”。

剩余耗时: 候选热 B1/B2 中,槽位匹配函数各调用 39 次,累计 3.90/3.86 秒;其中 OpenCV 模板匹配本身 3.46/3.42 秒,调用 19,698/19,554 次。参考图加载约 0.38–0.40 秒。这些时间有嵌套,不能相加。

失败与负结果

  • 热态仍超过 3 秒,候选没有解决主瓶颈。
  • 独立 QA 第一次运行报了 38 项失败,原因是 QA 自己的字段选择器不支持数组下标,不是产品缺陷;修正后 796 项全部通过,第一次的结果保留。
  • 候选执行回执曾短暂记录承载模块为“已删除/未跟踪”,查明是提交工具同步暂存区的瞬态窗口,工作文件未删;原回执保留不改写。

局限

  • 每批只有三个带剖析开销的请求,不能给出 p95、稳定加速比或 App 可见等待时间。
  • 两张图、一个来源组,不是十场来源隔离验收,也不能宣布准备页 95% 准确率。

结论与下一步

延迟加载整图 OCR 是一处安全的、结果完全不变的冷启动优化,保留。真正的热态瓶颈是约 2 万次模板匹配。已核实现有算法已经按类型和父技能限制了搜索范围,所以“按父技能裁减”“固定槽分类型”不能再当新优化。

下一批预执行协议(未运行): 只做一个候选——把同一类型的多个固定槽位拼成一批(中间留足隔离区),用同一个模板内核一次计算,再只在各槽对应区域取结果;不减少任何身份、参考变体、尺寸(72/80/88/96/104)、偏移、前三候选或读数,也不改 0.75 分/0.08 差值的接受门槛。先用确定性合成矩阵验证完整排名字典与原函数严格相等;只要输出有任何变化就保存反例并停止,不换第二种算法。之后才允许再做一批 6 次真实请求,并且必须看到模板匹配成本或调用量明显下降,才能说有性能价值。