Research
LYR Performance Note #028 OCR

OCRの電力予算を1桁下げた——速くするのではなく、呼ぶ回数を減らして

OCRを速くするより、呼ばないほうが効いた——常時起動の極小レイヤー「Awake Layer」に、いつ起こすかを任せる

2026-07-23 シリーズ第1回 12 min OCR省電力エッジ推論電力計測

端末の上でOCRを速くした。検出1回は 40→20ms、エネルギーは −58%。それでも電池の持ちは、体感が変わるほど伸びなかった。1回を半分にしても、回している回数がそのままだったからだ。

測ると、OCRの稼働率は 10%。9割は、何も無い画面を読み続けていた。そこで「どう速くするか」をやめて「そもそも呼ぶか」を判定する層を置いた——70倍安い常時起動の Awake Layer だ。検出まわりの電力予算は、おおよそ1桁下がった。

ただし、きれいな話ではない。ゲート自体を4.5倍安くしても、総電力は -22% しか動かなかった。電力を支配していたのはゲートのコストではなく、ゲートが出した呼び出しの回数(理想の6.9倍)だった。

字幕翻訳は、画面の文字を読むところから始まる。端末の上でOCRを回す以上、その電力はユーザーの電池から出ていく。クラウドの請求書と違って、こちらは目に見えない請求書だ。だが確実に届く——バッテリーの減りとして。

だから最初にやったのは、当然のように「OCRを速くする」だった。

速くはなった。桁は変わらなかった

打ち手はまっとうだった。フル画面を読むのをやめ、文字がありそうな帯だけを見る。処理する画素を減らせば、当然速くなる。

実測で、検出1回の時間は 40ms → 20ms(-51%)、エネルギーは 146mJ → 61mJ(-58%) になった。悪くない。実際これは今も入っている。

しかし電池の持ちは、体感が変わるほどには伸びなかった。理由は簡単で、1回を半分にしても、回している回数がそのままだったからだ。この処理は毎周期・秒5回、字幕があろうがなかろうが走り続けていた。半分の重さのものを、同じ回数だけ持ち上げていた。

測ったら、9割は空振りだった

そこで、回数のほうを測った。

指標実測
OCRの処理能力(容量)4.2 blocks/s
実際に来る需要0.45 blocks/s
稼働率約10%

能力の9割は、何も無い画面を読み続けることに使われていた。 字幕は出っぱなしではない。喋っていない間は消えるし、出ている間も同じ文字が静止している。読む価値のある瞬間は、実はごく短い。

ここで問いが変わった。「この処理をどう速くするか」ではなく、「この処理は本当に要るのか」

Awake Layer — 眠らせておいて、必要な瞬間だけ起こす

答えとして置いたのが Awake Layer だ。考え方はひどく単純で、

高価な処理の手前に、桁違いに安い常時起動の層を置き、「今、起こす必要があるか」だけを判定させる。

これまで — 字幕が無くても、毎周期ぶん回す 画面キャプチャ 常時 高価な検出 + OCR 毎周期 5Hz 204 mW 稼働率 10% = 9割は空振り Awake Layer — 安い層が「起こすかどうか」だけを決める 画面キャプチャ 常時 Awake Layer 0.5ms・常時 12mW 字幕が出た/変わった瞬間だけ、起こす 高価な検出 + OCR 約 0.5Hz(変わり目だけ) 約 32 mW (-84%)— 眠っている間、高価な処理は動かない 1回あたりのエネルギー — この比だから、安い層を常時回すほうが得になる 高価な検出 40.8 mJ Awake Layer 0.59 mJ 約 70 倍の差
図1:Awake Layer — 起こすかどうかだけを決める層。上段は従来設計(毎周期5Hzで検出+OCRを起動し204mW、うち稼働率10%)、下段はAwake Layer設計(0.5msの常時層が字幕の変わり目だけ起こし、約32mW=-84%)。最下段は1回あたりのエネルギー比較で、高価な検出40.8mJに対し常時層0.59mJ=約70倍の差。
注:「1桁」は実測した構成要素からの積み上げ試算で、端末全体のODPM実測ではない。

この層が見るのは2つだけ。いま画面に読むべき文字があるか(presence)、そしてそれが変わったか(change)。文字を読むわけではない。中身も分からない。「起こすべきか、寝かせておくか」しか答えない。

なぜ成立するかは、コストの桁を並べれば分かる。

1回あたり役割
高価な検出15ms / 40.8mJ文字を実際に見つける
Awake Layer0.5ms / 0.59mJ起こすかどうかを決める

約70倍。この比なら、安いほうを常時回して高いほうを止めるほうが、圧倒的に得になる。門番の給料が、中で働く職人の70分の1なら、門番を24時間立たせておいたほうが安い。

もう一つ、設計として効いたのが変化の内訳だった。字幕の変化イベントを分解すると、出現45% + 消失45% = 90%が「有る/無い」の遷移で、これは安い層でも見分けられる。難しいのは残り10%——presenceが途切れないまま中身だけ差し替わる場合だけだ。9割は、安い層で拾える。

結果、検出の常時電力は

  • 高価な検出を毎周期(秒5回)走らせる: 204mW
  • Awake Layer 常時 + 検出は字幕の変わり目だけ(秒0.5回): 約32mW(-84%)

ここに前述の「1回あたり-58%」が乗る。積み上げると、検出まわりの電力予算は 204mW → 20mW前後=おおよそ1桁。Live翻訳全体が約2000mWなので、電池寿命でおよそ+9%に相当する。

(この1桁は、実測した構成要素——検出1回の実測エネルギー、常時層の実測電力、実測した発火頻度——を積み上げた試算であって、端末全体を通した一発のODPM実測ではない。正直に書いておく。)

ついでに副産物があった。この層は文字を「読んで」いない。文字らしい視覚構造があるかを見ているだけだ。結果として、日本語で学んだものが、そのままラテン文字にもハングルにも効いた(4作品・4スクリプト横断で確認)。言語ごとに作り込む処理が、丸ごと要らなくなった。消した処理は、多言語対応のコストごと消える。

ここからが本題——ゲートを安くしても、電力は落ちなかった

きれいな話に見えるが、実際にはここで一度、完全に外した。

門番の役をもっと安いモデルに置き換えたとき、ゲート単体では4.5倍の省電力になった。当然、全体も大きく落ちると思った。落ちなかった。総電力は-22%

原因を分解して、目を疑った。

33個の字幕に対して、高価な処理を約228回呼んでいた。理想(1字幕につき1回)の6.9倍。

門番を安くしても、その門番が用も無いのに職人を叩き起こし続けていたなら、電気代は職人が食う。電力を支配していたのは門番のコストではなく、門番が出した呼び出しの回数だった。

つまり——「安くする」では足りず、「呼ぶ回数を減らす」まで到達して初めて電力は動く。 ゲートを入れた時点で満足していたら、この6.9倍には気づかないままだった。

減らしすぎると、今度は体験が壊れる

では呼び出しを絞ればいい、と発火の条件を「立ち上がりの1回だけ」に厳しくした。呼び出しは 274回 → 69回(-75%)、電力指標は -48%。狙いどおり落ちた。

代わりに字幕の捕捉率が 82% → 61% に落ちた。横向きの画面ではもっとひどく、71% → 32%——字幕の3分の2を取りこぼした。電力は半分になったが、翻訳アプリとして失格だ。

ここで分かったのは、「減らす」は「雑に減らす」ではないということだった。呼び出しを1回に絞れる前提は、「起こすべき瞬間を、その層が正確に当てられる」こと。それができていないうちに回数だけ削ると、削った分がそのまま取りこぼしになる。判定の質と、呼ぶ回数は、分離できない。 現在はここ——判定側を正すほうに投資している。

教訓

  1. 1回のコストより、回数を見る。 1回を半分にしても、無駄な回数が10倍あるなら電力は動かない。最初に測るべきは処理時間ではなく稼働率だった(実測10%)。
  2. 桁の違う安い層は常時回しても得になる。ただしゲートを入れただけでは終わらない。 70倍安い判定器なら24時間起こしておくほうが安い。だがゲートを安くすること(4.5倍)と、無駄な呼び出しを減らすこと(6.9倍の過剰発火)は別問題で、効いたのは後者だった。
  3. 消した処理は付随コストも一緒に消える。ただし、減らす権利は精度で買う。 言語ごとの作り込みも評価も保守も、処理と一緒に消えた——高速化ではこれは起きない。一方で呼び出しを絞る前提は「起こすべき瞬間を外さない」ことで、そこが甘いまま削れば、電力の勝ちを体験の負けで払う。

これは マニフェストの4番目の原則——処理を高速化するより、処理自体を減らす——の、いちばん素直な現れだ。速くしたときの利益は-51%だった。呼ばないことにしたときの利益は、桁だった。


付録:生データ

項目実測条件・留保
検出1回のエネルギーフル 960×448 = 86.8ms / 330mJ、フル 736×320 = 40.1ms / 146mJ、帯 960×128 = 19.6ms / 61mJ、帯 448×320 = 23.9ms / 70mJPixel 10 / 放電+電流サンプリング、3ラウンド interleave
電力の性質検出中の瞬時電力はおおむね一定(約3.0〜3.8W)エネルギーは処理時間で決まる=省エネの実体は「短くする」か「やらない」かの二択
コスト比高価な検出 15ms / 40.8mJ 対 Awake Layer 0.5ms / 0.59mJ = 約69倍常時稼働時の消費は 12mW(50ms周期)
稼働率容量 4.2 blocks/s に対し需要 0.45 blocks/s = 約10%9割は何も無い画面を読んでいた
検出の常時電力毎周期5Hz = 204mW → 変わり目のみ+常時層 = 約32mW(-84%)Live全体 約2000mW に対し -172mW ≒ 電池 +9%
変化イベントの内訳出現45% / 消失45% / 中身の差し替え10%90%は presence の遷移=安い層で拾える
スクリプト横断日本語で学習 → ラテン文字 AUC 0.989 / ハングル 0.950、混合時 0.996〜0.998既存の高価な検出器 0.994〜0.997 と同等
ゲート置換の逆説ゲート単体 4.5倍省電力 → 総電力は -22% のみ33字幕に対し呼び出し 約228回 = 理想の6.9倍
呼び出しの過剰な絞り込み縦画面 274→69(-75%)、横画面 297→44(-85%)、電力指標 -48% / -66%代償に捕捉率 82→61% / 71→32%=減らしすぎは体験を壊す

注記: 電力指標の一部(発火数×コストの相対値)はハーネス上の積算であって ODPM 実測ではない。上記の「1桁」も、実測した構成要素からの積み上げ試算。