動画で読む
まず結論 — 「数える」処理は VLM に投げない
最初に運用者としての結論を置きます。画像の中の「マス目を数える」「座標を整列させる」種類の仕事は、VLM(Vision Language Model、画像も読める言語モデル)に任せてはいけません。Zenn に上がっていた編み図読み取りの失敗記録は、まさにそこで 8 日間ぶつかった話で、最終的に著者は VLM を見限り、古典的なコンピュータビジョン(OpenCV による格子検出)に切り替えています。
読みどころは「AI が苦手なこと」を実装の途中で見極め、責務を切り分けた判断の順序です。VLM を全否定したのではなく、「何があるかを認識する」のは AI に残し、「いくつ並んでいるかを数える」のは決定論的なコードに移した。この線の引き方が、LLM や VLM を実務に載せる前にいちばん効きます。便利だからと全部を AI に預けると、後から数え間違いの尻拭いに追われます。
何が起きたか — 20 列の方眼を 19 列と数える
具体的な失敗は、編み図(方眼に記号が並んだ図)の写真を「1 マス 1 文字のマトリクス」に変換する処理で起きました。著者によれば、VLM は 20 列あるグリッドを 19 列と数え、行が 1 つズレて全体がシフトし、同じ画像でも実行のたびに結果が揺れたそうです。プロンプトを「行ごとに数えて」と改良しても、画像を 16×16 のタイルに細切れにしても、効果はありませんでした。
この「実行のたびに答えが揺れる」のが、運用者にとって一番たちが悪い症状です。たまに間違えるなら検算で拾えますが、毎回違う数を返すものは、何を正としていいか分からない。私も以前、業務でスプレッドシートのスクショを VLM に読ませて行数を数えさせたとき、44 行の表を「43 行」と返され、再実行したら今度は「45 行」になって、画面の前で小さくため息をついた覚えがあります。編み物は 1 目ずれたら模様が崩れる世界なので、この揺らぎは致命傷です。
なぜ VLM は方眼を数えられないのか
理由を一言でいうと、VLM の注意機構(Attention、入力のどこに注目するかを決める仕組み)は「何があるか」の認識には強い一方で、「等間隔のものを最後まで正確に数える」のは構造的に苦手だからです。密に並んだ同じ記号の方眼は、注意の重みが似たマスに分散し、端の 1 マスを取りこぼしても全体の見た目はほぼ変わりません。だから 20 を 19 と返しても、モデルの中では「だいたい合っている」のです。
ここは Attention Is All You Need の構造を一度自分で組んでみると腑に落ちます。以前 パーセプトロンを最小の脳としてスクラッチで書いた話 でも触れましたが、こうしたモデルは連続値の重み付き和で「らしさ」を出しているのであって、レジ係のように 1, 2, 3 と確定的に数えているわけではありません。数え上げは離散的でゼロ誤差が要る作業で、確率的な近似が本質のモデルとは、そもそも相性が悪い。苦手なのはモデルの出来が悪いからではなく、仕事の性質が噛み合っていないからです。
古典 CV への切り替え — 決定論で格子を取る
切り替え先は、ピクセルの周期性を決定論的に拾う古典 CV です。著者は工程を分け、グリッド枠の検出とセル分割は OpenCV に任せました。具体的には、照明ムラに強い適応的二値化(adaptive threshold)で線を浮かせ、ピクセル列の周期性を投票で拾って格子の間隔と位相ズレを補正する、という流れです。同じ入力なら同じ答えが返る。この再現性こそが、揺らぐ VLM に欠けていたものです。
格子の直線を拾うなら Hough 変換(直線検出)も定番で、私が前に方眼ノートの写真からマス目を切り出したときも、まず Hough で縦横の線を取り、交点からセルの矩形を起こしました。地味なのに、一度ハマると一切ズレないのが古典 CV の気持ちよさです。派手な新モデルの記事に比べると 2017 年どころか 1970 年代の手法が並ぶ世界で、正直「枯れた技術に戻ってきたな」と少し笑ってしまいました。でも、1 目もズレが許されない領域では、枯れていることがそのまま信頼になります。
運用者の設計判断 — 知覚と判断を 2 層に分ける
設計の肝は、AI を「知覚」と「判断」の 2 層に分け、数える部分だけを古典 CV で抜くことです。著者の最終構成は分かりやすくて、セルの分割は OpenCV、各マスの記号が何かの分類は安価な Gemini Flash Lite、全体の整合や最終判断は Claude Sonnet / Opus、という三段重ねでした。安いモデルで知覚を回し、高いモデルは判断の一回だけに使う。原価と精度を同時に取りにいく形です。
この「呼ぶ回数と呼ぶモデルを分ける」発想は、LLM API のコストを『呼ばない』で防ぐ三段防御 に書いたのとまったく同じ筋です。著者は 1 回の AI 呼び出しが ¥10〜¥40 と約 100 倍の幅で振れることを実ログから測り、当初のサブスク設計だと最悪 15 倍の赤字になると気付いて買い切りパックに変えています。理論値でなくログから原価分布を測る、この順序が効いています。判断モデルにどれを当てるかは Opus 4.8 の effort 制御を実務で読んだとき の話とも地続きで、判断は重いモデル一回、知覚は軽いモデル多数、と役割で割り当てるのが素直です。
私なら最初からどこに線を引くか
最後に運用者としての実装方針を一つだけ。新しく画像処理を含む機能を作るなら、私は着手前に「カウント・整列・座標が絡む部分」を洗い出して、そこは最初から古典 CV で切り出す前提で設計します。AI に任せるのは分類と判断だけ、と決めておく。後から「やっぱり数えられない」と判明して作り直すより、最初に線を引いておく方が圧倒的に安く済みます。
落とし穴も書いておきます。古典 CV は再現性が高い代わりに、丸めの差がセル 1 個のズレに直結します。著者も先行する Python スクリプトを Web サービスへ移植する際、100% パリティ(同一入力で同一出力)を検証してから載せ替えたと書いていました。決定論は強いが、移植のたびに数値が一致するかを確かめないと、別の場所でまたズレます。AI の揺らぎを構造で潰したつもりが、今度は実装差で揺れる。そこだけは油断しないことです。
よくある質問
- なぜ VLM は方眼のマス目を正確に数えられないのですか?
- 注意機構は「何があるか」の認識には強い一方、等間隔に密に並んだものを最後まで正確に数えるのは構造的に苦手だからです。確率的な近似が本質のモデルと、ゼロ誤差が要る離散的な数え上げは、そもそも仕事の性質が噛み合っていません。
- 古典 CV に切り替えると具体的に何が良くなりますか?
- 同じ入力なら必ず同じ答えが返る再現性が得られます。OpenCV の適応的二値化で線を浮かせ、ピクセルの周期性を投票で拾って格子の間隔と位相ズレを補正すれば、VLM のように実行ごとに数が揺れることがなくなります。
- AI と古典 CV はどう役割分担すべきですか?
- 知覚と判断を分けるのが要点です。マスの分割と数え上げは決定論的な古典 CV、各マスの記号が何かの分類は安価な VLM、全体の整合や最終判断は高性能モデル、と 2 層 + 古典 CV で割り当てると、原価と精度を同時に取りにいけます。
- 古典 CV に切り替えるときの注意点はありますか?
- 丸めの差がセル 1 個のズレに直結する点です。決定論は強い反面、別言語や別環境へ移植するたびに数値が一致するか(同一入力で同一出力か)を 100% 検証しないと、AI の揺らぎを潰したつもりが実装差で再びズレます。