日本語の手書きメモを書き起こせるOCRを探すために26モデルを片っ端から試した話

by 逆瀬川ちゃん

32 min read

こんにちは!逆瀬川ちゃん (@gyakuse) です!

今日は日本語の手書きメモをいい感じに書き起こしてくれるOCRを探して、26モデルを片っ端から比較してみた話をまとめていきたいと思います。

手書きメモは楽しいが電子化がつらい

わたしはいまだに手書きメモをよく書きます。打ち合わせの最中にさっと書いたり、アイデアを整理するときにペンで図を描いたり。手を動かしながら考えるのはとても楽しいし、タイピングとは違う思考の広がり方があります。

ただ問題は電子化です。ノートに書いたメモをあとからSlackやNotionに転記するのがとにかくつらい。自分の字を自分で読み返す作業がすでにつらいのに、それを打ち直すのは二重苦です。

OCRで自動化したいのですが、日本語の手書き文字って既存のOCRモデルにとってはかなり難しいタスクです。活字ならどのモデルでも高精度ですが、手書きとなると精度がガクッと落ちます。しかも最近はOCR専用モデルが爆発的に増えていて、HunyuanOCRDeepSeek-OCRolmOCR-2Chandra...とどれを使えばいいのかわかりません。Claude、Gemini、GPTのような汎用VLMもOCR能力が急速に上がっていて、LayerXのテックブログGENSHI AIの検証記事でも取り上げられています。

じゃあ全部試して比べてみようか、ということでやってみました。

比較のしかた

ちゃんと比較するには「どう測るか」を先に決める必要があります。手書きメモは読み順が曖昧なケースが多い(縦書き横書き混在、矢印参照、囲み文字...)ので、単純なCER(Character Error Rate)だけだと読み順が違うだけで壊滅的なスコアになります。

そこで3つの相補的な指標を使いました。

指標 ざっくり言うと 主な用途
Hungarian NLS (primary) 各領域のベストマッチで採点 読み順に依存しない本質的な精度
Bag-of-Characters F1 文字の集合で比較、語順無視 純粋な文字認識精度
CER 全文のLevenshtein距離 読み順を含む総合品質

主指標のHungarian NLSは、正解データを領域単位で持っておいて領域ごとにベストマッチを探す方式です。詳しくはAppendix: 評価指標の設計に書いています。

正解データの作成にはアノテーションツールも自作しました。画像をアップロードすると雑な前処理(紙面検出・傾き補正・影除去)が走ってからアノテーション画面に進みます。前処理のロジックはちゃんと検証できていないので精度は保証しませんが、ないよりはマシ程度のものです。詳しくはAppendix: 画像前処理に書いています。

今回は手書きメモ画像6枚で評価しています(少ないですがまずは傾向を見たかった)。評価基盤のコードは ocr-comparison で公開しています。

比較対象の26モデル

APIで呼べるモデル13個と、GPU上で動かすOSSモデル13個を比較しました。

OSSモデルはModalというサーバーレスGPUプラットフォームで動かしています。T4、L4、A100などのGPUをPythonのデコレータ一つで使えるので、ローカルにGPUがなくても評価できます。

カテゴリ モデル ライセンス 備考
API Gemini 3.5 Flash Proprietary
API Gemini 3.1 Pro Preview Proprietary Deep thinking
API Gemini 3 Flash Preview Proprietary
API Gemini 3.1 Flash Lite Preview Proprietary
API Claude 4.7 Opus Proprietary Adaptive thinking
API Claude 4.6 Opus Proprietary Adaptive thinking
API Claude 4.5 Sonnet Proprietary Extended thinking
API GPT-5.5 Proprietary Reasoning effort: high
API GPT-5.4 Proprietary Reasoning effort: high
API Google Cloud Vision Proprietary
API Azure AI Vision Proprietary
API Mistral OCR Proprietary mistral-ocr-latest
API Qwen VL OCR Proprietary DashScope API
Modal (L4) HunyuanOCR Apache-2.0 1B
Modal (L4) DeepSeek-OCR MIT
Modal (A100) Chandra Apache-2.0
Modal (L4) Nanonets-OCR-s Apache-2.0 4B
Modal (L4) olmOCR-2 Apache-2.0 7B FP8
Modal (T4) GOT-OCR 2.0 Apache-2.0
Modal (T4) PaddleOCR Apache-2.0
Modal (T4) YomiToku CC-BY-NC-SA-4.0 日本語特化
Modal (T4) GLM-OCR MIT 0.9B
Modal (CPU) NDLOCR-Lite CC-BY-4.0 国立国会図書館
Modal (A10G) NDLOCR v2 CC-BY-4.0 国立国会図書館
Modal (L4) Sarashina2.2-OCR MIT 3B, 日本語活字特化
Modal (L4) Nemotron OCR v2 NVIDIA Open Model License 84M, 伝統型パイプライン

このうちDeepSeek-OCR、GOT-OCR 2.0は日本語非対応、Nanonets-OCR-sは公式が手書き未学習と明言しているモデルです。olmOCR-2も公式には英語PDFフォーカスで日本語サポートを明記していません。OCRベンチマークで名前を見かけることが多いので一応全部入れてみました。無茶振りした結果がどうなったかは後述します。

YomiTokuはCC-BY-NC-SA-4.0なので商用利用には注意が必要です。それ以外のOSSモデルはApache-2.0かMITなので商用でも使えます。

結果

手書きメモ6枚に対する評価結果です(Hungarian NLS降順)。

Rank モデル カテゴリ NLS BoC-F1 CER Avg Time
1 Gemini 3.5 Flash API 0.927 0.928 0.192 14.8s
2 Gemini 3.1 Pro Preview API 0.924 0.929 0.205 67.9s
3 Gemini 3 Flash Preview API 0.918 0.910 0.221 18.7s
4 Gemini 3.1 Flash Lite Preview API 0.899 0.917 0.207 13.7s
5 Claude 4.6 Opus API 0.897 0.896 0.225 74.9s
6 Claude 4.7 Opus API 0.858 0.883 0.276 9.5s
7 YomiToku v0.13.0 Modal 0.842 0.807 0.384 20.5s
8 Azure AI Vision API 0.830 0.845 0.332 4.2s
9 Google Cloud Vision API 0.820 0.783 0.509 2.2s
10 GPT-5.5 API 0.755 0.830 0.301 98.1s
11 GLM-OCR Modal 0.738 0.792 0.387 29.7s
12 Chandra Modal 0.734 0.780 0.361 29.2s
13 olmOCR-2 Modal 0.723 0.786 0.370 45.4s
14 Sarashina2.2-OCR Modal 0.718 0.727 0.450 24.7s
15 GPT-5.4 API 0.714 0.814 0.331 123.4s
16 Qwen VL OCR API 0.706 0.713 0.491 17.7s
17 HunyuanOCR Modal 0.698 0.754 0.367 30.3s
18 Claude 4.5 Sonnet API 0.640 0.709 0.465 16.4s
19 Mistral OCR API 0.589 0.645 0.563 7.3s
20 Nanonets-OCR-s Modal 0.557 0.597 0.615 69.1s
21 DeepSeek-OCR Modal 0.446 0.530 0.671 35.4s
22 NDLOCR-Lite v1.2.1 Modal 0.443 0.511 0.728 18.9s
23 Nemotron OCR v2 Modal 0.413 0.562 0.705 13.0s
24 PaddleOCR Modal 0.353 0.394 0.784 12.8s
25 GOT-OCR 2.0 Modal 0.194 0.250 0.888 10.2s
26 NDLOCR v2 Modal 0.064 0.087 0.958 28.7s

Avg Timeは1画像あたりの平均処理時間です。Modalモデルはバッチ処理の合計時間を画像数で割っているので、コールドスタートを含む点に注意してください。

Geminiが強い

一番驚いたのはGemini系の安定した強さです。1位から4位までをGemini系が独占していて、新顔のGemini 3.5 FlashがNLS 0.927でトップ、Gemini 3.1 Pro Preview (0.924) を僅差で上回りました。しかも処理時間は14.8sでProの67.9sの1/4以下です。Flash Lite(最軽量モデル)ですらNLS 0.899でClaude 4.6 Opusと同等レベルなので、日本語手書きOCRに関してはGeminiが頭一つ抜けています。

Claude 4.6 Opusは5位でNLS 0.897で十分に高いのですが、新世代のClaude 4.7 Opusは6位(NLS 0.858)と前世代より0.04ポイント下げてきました。一方でAvg Timeは4.6 Opusの74.9sから4.7 Opusで9.5sへ、なんと約8倍速くなっています。adaptive thinkingが「考えすぎなくても回答できる」と判断しているのか、推論時間を大きく削った結果として精度も少し落ちた、というトレードオフに見えます。実用的には4.7 Opusのほうが速度・精度の総合バランスは取りやすい場面が多そうです。Claude 4.5 Sonnetが18位(NLS 0.640)とかなり落ちるのも興味深く、同じClaude系でもモデルの世代で大きな差があります。

GPT系はGemini/Claudeに大きく水をあけられている

GPT-5.5は10位(NLS 0.755)、GPT-5.4は15位(NLS 0.714)で、APIモデルの中では中位グループです。世代が新しいGPT-5.5は前世代より0.04ポイント改善しているものの、それでもGemini系・Claude Opus系とは0.10以上の差があります。英語のOCRベンチマークでは強いモデル群ですが、日本語の手書きメモという条件では苦戦しています。BoC-F1はGPT-5.5で0.830、GPT-5.4で0.814と相応に高めなのに対してNLSが下がっているので、文字自体は読めているけど領域のマッチングでスコアを落としている可能性があります。GPT-5.5は処理時間も98.1sと長く、reasoningの時間に見合うほど精度が出ていないのが現状です。

OSSモデルではYomiTokuが断トツ

OSSモデルの中ではYomiToku v0.13.0 (7位, NLS 0.842) が断トツの最上位で、APIの主要モデル (Azure / GCV / GPT-5.5) を軒並み上回り、上位 Claude 4.7 Opus (NLS 0.858) にあと0.016ポイントというところまで来ています。v0.12.x までは NLS 0.77 前後だったのが、v0.13.0 で「検出モデル及び手書き文字の認識モデルの強化」が入って大きく跳ね上がりました。日本語特化のOSSモデルとしては、現時点でほぼベスト・イン・クラスです。Chandra(12位)もNLS 0.734で健闘しています。

一方でPaddleOCR、NDLOCR系は手書き文字がかなり厳しいです。とくにNDLOCR v2は国立国会図書館が公開しているモデルで活字の印刷文書には強いのですが、手書きメモは守備範囲外のようです。なお NDLOCR-Lite は v1.2.1 で手書き対応が大幅に改善されました(後述の追記を参照)。

無茶振りしたモデルたちの反応が面白い

さて、前述のとおり日本語非対応や手書き未学習のモデルにも無茶振りしてみたわけですが、それぞれの反応が面白かったので紹介します。

olmOCR-2は英語PDFフォーカスのモデルで日本語サポートは明記されていません。ところが蓋を開けてみるとNLS 0.723でGPT-5.4(0.714)を超えて13位にランクインしました。ベースモデルがQwen2.5-VLなので、その多言語能力が高すぎるせいか英語特化のチューニングをされていても日本語の手書きを読めてしまうようです。VLMの地力の恐ろしさを感じます。A100が必要なChandraに対してolmOCR-2はL4で動くので、コスパでも優秀です。

DeepSeek-OCRは日本語非対応なのですが、単にエラーを出すのではなく日本語の手書き文字を中国語に「翻訳」して出力してくるのが特徴的でした。「SDKを」が「SD卡」(SDカードの中国語)になり、「permission mode auto対応」が「自动权限模式」になります。分からない日本語の手書き文字を見て文脈から推測し、母国語で出力してしまうというVLM特有のハルシネーションです。

GOT-OCR 2.0は580Mと超軽量なモデルで、英語・中国語のみ対応です。日本語の手書きメモを見せた結果はNLS 0.194で、ログを見ると数字やごく一部の英数字だけを拾って Cadi g/ Agent Bif f Application y のような出力になっています。非対応言語に対しては記号や数字だけ拾おうとする、従来型OCRに近い挙動です。

Nanonets-OCR-sは公式が手書きは未学習と明言しているモデルです。手書きメモを見せた結果、一部の画像でパニックを起こして > > > > > >1111... といった無意味な文字を数千文字にわたって出力し続ける生成ループに陥りました。この画像では文字エラー率(CER)が2100%(21倍)という異常値を叩き出しています。repetition_penaltyを上げて対処しましたが、未学習の入力に対するVLMの脆さが見えた瞬間でした。

速度と精度のトレードオフ

Avg Timeを見ると面白い傾向が見えます。Google Cloud Visionが2.2s、Azure AI Visionが4.2sと専用OCR APIはやはり速いです。精度もNLS 0.82〜0.83あるので、速度重視ならこの2つは十分選択肢に入ります。

精度と速度のバランスで圧倒的に強いのが新顔のGemini 3.5 Flashで、14.8sでNLS 0.927を叩き出します。Proの精度を1/4以下の時間で達成しているので、現時点ではこのモデルがほぼ最適解です。Gemini 3.1 Flash Liteも13.7sでNLS 0.899と健闘していて、3.5 Flashが手に入らない環境ではこちらが代替候補になります。Proは67.9sかかるのでFlash Liteの5倍遅いですが、精度の差はNLS 0.025しかありません。

GPT-5.4は123.4s、GPT-5.5でも98.1sと圧倒的に遅いです。reasoning effort: highで推論させているので仕方ないのですが、それだけ時間をかけてNLS 0.71〜0.76というのはコスパが悪いです。

OSSモデルではYomiToku v0.13.0が20.5sでNLS 0.842と精度が大幅に伸びました。v0.12.x までは12.0s / NLS 0.77 だったので、新モデルは少し重くなった代わりに精度が大きく改善しています。それでも速度・精度・コストのバランスは十分良く、OSSで手元運用したい場合の第一候補です。ただしModalのコールドスタートを含む時間なので、常時起動している環境ならもっと速いはずです。

実際の出力を見てみる

数字だけだとピンとこないので、実際の手書きメモ画像と各モデルの出力をAppendix: 画像別OCR出力例に全部載せています。

結論: 手書きメモの書き起こしにはGemini

現時点での最良の選択はGemini 3.5 Flash(NLS 0.927, 14.8s)です。精度はProを超えていて、しかも処理時間はProの1/4以下。NLS 0.927は「だいたい読めている」水準で、多少の読み間違いはあるもののざっくり電子化するには十分使えます。Flash系で頭打ちにならず、むしろProを上回ってきたのは予想外でした。

精度をさらに少しでも詰めたい場合はGemini 3.1 Pro Preview(NLS 0.924, 67.9s)も選択肢ですが、差はNLS 0.003なので体感ではほぼ同じです。

速度重視ならGoogle Cloud Vision(NLS 0.820, 2.2s)やAzure AI Vision(NLS 0.830, 4.2s)が選択肢に入ります。精度は上位モデルに劣りますが、大量のメモを一気に処理したいケースでは現実的です。

OSSモデルで手元で動かしたい場合はYomiToku v0.13.0 (NLS 0.842, 20.5s) が精度・速度・コストの三拍子揃っています。APIの中位グループを軒並み上回るので、ローカル運用でも十分実用水準です。

ただし注意点として、今回の評価は手書きメモ6枚と少数なので、画像数を増やすとランキングが変動する可能性は十分あります。評価基盤は公開しているので、自分のメモで試してみるのが一番確実です。

まとめ

  • 日本語手書きメモのOCRに使えるモデルを探して26モデルを比較しました
  • Gemini 3.5 Flash (NLS 0.927) が最高精度で、Proより速くて精度も上回っています
  • OSSではYomiToku v0.13.0 (NLS 0.842) が断トツ、Azure/GCV/GPT-5.5 を軒並み上回る水準まで伸びました
  • 評価コードは ocr-comparison で公開しています

追記 (2026-03-17): GLM-OCRを追加して19モデルに

記事公開後にGLM-OCRを入れ忘れていたことに気づいたので追加しました(当時19モデル、現在は20モデル)。

GLM-OCRはCogViT (0.4B) + GLM-0.5Bの合計0.9Bパラメータという超軽量モデルで、OmniDocBench V1.5で1位のスコアを記録しています。vLLMではglm_ocrアーキテクチャがまだ未サポートだったので、transformersのソースビルドで直接推論しています。

結果はNLS 0.738で11位にランクインしました。0.9Bでこの精度はかなり優秀です。T4 GPUで動くのでModalのコストも安く、A100が必要なChandra(NLS 0.734)とほぼ同じ精度をT4で出せるのはコスパが光ります。

OSSモデルのパラメータ数を並べるとolmOCR-2が7B、Nanonetsが4B、HunyuanOCRが1Bで、GLM-OCRの0.9Bは最軽量クラスです。それでNLS 0.738はパラメータ効率がかなり高いと言えます。

出力を見ると「比較」が「比较」(簡体字)になっていたり、DeepSeek-OCRと似た中国語リークが出ています。ベースモデルのGLMが中国語に強いので、日本語の漢字を簡体字で出力してしまうケースがあるようです。一方で「Agent skill が Web App を wrap」のような英語混在部分はそこそこ読めていて、0.9Bにしては頑張っています。

上の結果テーブルとモデル一覧は更新済みです。

追記 (2026-03-18): Mistral OCRを追加して20モデルに

Mistralの専用OCR API (mistral-ocr-latest) を追加しました。VLMのチャットAPIではなく、OCR専用エンドポイントを使っています。

結果はNLS 0.589で19位。Claude 4.5 Sonnet (0.640) より下、Nanonets-OCR-s (0.557) よりは上という位置づけです。専用OCR APIとしてはGoogle Cloud Vision (0.820) やAzure AI Vision (0.830) に大きく差をつけられています。

出力を見ると、日本語の手書き部分で中国語の繁体字が混入する傾向があります。「仕様書の腐敗について」が「代理人 → 國際計算機」に、「リアルタイム対話」が「1910914 科法」になるなど、DeepSeek-OCR(簡体字リーク)やGLM-OCR(簡体字リーク)と似たパターンですが、Mistralの場合は繁体字が出てくるのが特徴的です。一方で英語部分は比較的読めており、Coding AgentSDKHarmonyなどの英単語はほぼ正確に拾えています。

処理速度は1画像あたり平均7.3sで、API系モデルとしてはGoogle Cloud Vision (2.2s)、Azure (4.2s) に次ぐ速さです。ただし503エラーが頻発する不安定さがあり、リトライなしでは6枚中2〜4枚が失敗するケースがありました。

上の結果テーブルとモデル一覧は更新済みです。

追記 (2026-03-18): Qwen VL OCRを追加して21モデルに

Alibaba CloudのDashScope APIで提供されているQwen VL OCRを追加しました。VLMのチャットAPIではなくOCR専用モデルで、DashScopeのOpenAI互換エンドポイント経由で呼び出しています。

結果はNLS 0.706で16位。GPT-5.4 (0.714) とほぼ同水準で、HunyuanOCR (0.698) を僅差で上回っています。

出力を見ると、サンプル1では「仕様書の腐敗について」が「仕様書の商談について」に、「うまくいかん」が「31Cへ」になるなど、日本語の手書きくずし字で苦戦する傾向があります。一方でサンプル2では「Agent skill を Web App に wrap する」とほぼ正しい構造を捉えており、英語混在部分の読み取りはそこそこ安定しています。

処理速度は1画像あたり平均17.7sで、APIモデルとしてはClaude 4.5 Sonnet (16.4s) と同程度です。

上の結果テーブルとモデル一覧は更新済みです。

追記 (2026-03-31): Sarashina2.2-OCRを追加して22モデルに

SB IntuitionsのSarashina2.2-OCRを追加しました。SigLIP2 + Sarashina2.2-3B-Instructベースの日本語特化VLM OCRモデルで、3Bパラメータです。

結果はNLS 0.718で14位。olmOCR-2 (0.723) のすぐ下、GPT-5.4 (0.714) とほぼ同水準です。

このモデルはMarkdown構造付きの出力を前提に設計されています。見出し(#)、太字(**)、リスト(-)を使って文書構造を再現してくれるので、構造化されたドキュメントとして手書きメモを取り込みたいユースケースには向いています。今回の評価指標はプレーンテキストベースの比較なので、このMarkdown出力は正直不利に働いています。構造化出力を活かす評価をすればもっとスコアが上がるかもしれません。

ちなみにモデルカード推奨のrepetition_penalty=1.2だと一部の画像で数字のカウントダウン(120→0)を延々と生成するループが発生しました。repetition_penalty=1.3に上げたところループが解消されて全画像で安定した出力になり、BoC-F1が0.623→0.727と大きく改善しています。VLMベースのOCRモデルは生成パラメータのチューニングでスコアが結構変わるので、このあたりの調整は大事です。

上の結果テーブルとモデル一覧は更新済みです。

追記 (2026-04-02): Nemotron OCR v2を追加して23モデルに

NVIDIAのNemotron OCR v2を追加しました。今回比較した中で唯一のVLMではないモデルです。RegNetX検出器 + Transformer認識器 + リレーショナルモデルという伝統的な3段パイプラインで、合計84Mパラメータと最小サイズです。テキストプロンプトなしで画像を渡すだけで動きます。

v2_englishとv2_multilingualの2バリアントがあり、v2_multilingualは英語・中国語・日本語・韓国語・ロシア語に対応しています。model cardに日本語対応と明記されているので、今回はv2_multilingualを使いました。14,244文字の文字セットを持ち、行レベルの認識を行います。

結果はNLS 0.413で23位。DeepSeek-OCR (0.446) の下、PaddleOCR (0.353) の上という位置づけです (NDLOCR-Lite v1.2.1 が NLS 0.443 で間に入りました)。日本語対応とはいえ活字・印刷文書向けの設計なので、手書きはやはり守備範囲外のようです。

出力を見ると、日付パターン (3/11, 3/13, 3/15) や英単語 (Harmony, ASR, VSR) はある程度拾えていて、検出器自体はちゃんと動いています。一方で日本語の手書き文字は中国語の簡体字(「投资家」「绝」など)として出力されるケースが多く、DeepSeek-OCRの中国語リークと似た傾向が見えました。多言語文字セットに中国語が含まれているので、判別が曖昧な手書き文字を中国語側に倒してしまうのかもしれません。

同じ伝統型パイプラインのPaddleOCR (NLS 0.353) と比べるとNemotronのほうが上で、BoC-F1も0.562 vs 0.394と文字認識精度では差があります。84Mパラメータでこの結果なので、活字文書の評価もやってみたら面白そうです。

上の結果テーブルとモデル一覧は更新済みです。

追記 (2026-05-20): Gemini 3.5 Flashを追加して24モデルに

GoogleのGemini 3.5 Flashを追加しました。Flash系の最新世代です。

結果はNLS 0.927で堂々の1位。これまでトップだったGemini 3.1 Pro Preview (0.924) を僅差で抜き、しかも処理時間は14.8sとProの67.9sの1/4以下。Flash系がProを上回るのは予想していなかったので、これは結構な驚きでした。BoC-F1は0.928で2位のProの0.929とほぼ同じ、CERは0.192で全モデル中最良の値です。

サンプル別に見ても安定していて、6枚のうちNLSが0.92を切ったのは2枚だけ。サンプル1の「VSR → うまくいかん」は「VSR -> うごかん」と惜しい読み間違い、サンプル2は「permission mode auto対応」を「permission mode auto だが」と読むなどニュアンスを取り違えるケースは残っていますが、Proが「外でいかん」と読んだ部分を「うごかん」と読めているあたり、くずし字推定の自然さでProを上回るシーンもあります。

精度・速度・(おそらく)コストの三拍子で現時点ではこれが手書きメモ書き起こしのほぼ最適解です。実運用で使うならまずこれを試すのがおすすめです。

上の結果テーブルとモデル一覧、結論セクションも更新済みです。

追記 (2026-05-20): GPT-5.5を追加して25モデルに

OpenAIのGPT-5.5を追加しました。reasoning effort: high で評価しています。

結果はNLS 0.755で9位。前世代のGPT-5.4 (0.714) から0.04ポイント改善していて、YomiToku (0.770) のすぐ下、GLM-OCR (0.738) の上という位置づけです。BoC-F1は0.830と全モデル中でも高めで、文字単位の認識能力はかなり上がっています。一方でCERは0.301で、領域マッチング(NLS)とのギャップから、文字は読めているのに行構造の対応が崩れているケースが多いと推察できます。

処理時間は1画像あたり平均98.1sで、GPT-5.4 (123.4s) よりは速くなりましたが、Gemini系のFlashモデル群が10〜20s台で動くのに比べると依然として遅いです。reasoning effort: highで時間をかけても、Gemini 3.5 Flash (0.927) との差は0.17ポイントもあり、日本語手書きOCRの領域ではGPT系がGemini系に追いつくのはなかなか難しそうです。

サンプル1では「VSR -> うまくいかん」が「USR -> HLDを書く」、「仕様書の腐敗について」が「(仕様書の確認->?)」と意味そのものを取り違える傾向が残っています。前世代と同様、日本語くずし字を英文脈に引きずられて読む癖がありそうです。

上の結果テーブルとモデル一覧は更新済みです。

追記 (2026-05-20): Claude 4.7 Opusを追加して26モデルに

AnthropicのClaude 4.7 Opusを追加しました。adaptive thinkingで評価しています。

結果はNLS 0.858で6位。Claude 4.6 Opus (0.897) と Azure AI Vision (0.830) の間という位置づけで、前世代から0.04ポイント精度を下げてきました。一方で処理時間は4.6 Opusの74.9sから4.7 Opusで9.5sへ、約8倍速くなっています。CERは4.6 Opus 0.225 → 4.7 Opus 0.276と少し悪化していますが、それでも上位水準は保っています。

これまでClaude OpusはGPT系よりも明確に強いポジションを取っていたのですが、4.7世代では「精度は少し落とすが大幅に速くする」という方向に舵を切ったように見えます。adaptive thinkingが「考えすぎなくても答えが出る」と判断して推論を切り上げているのか、結果として精度と速度のトレードオフが大きくシフトしました。実用的な処理速度を考えると、4.7 Opusのほうが現実的なユースケースには合わせやすそうです。

サンプル別に見ると、サンプル3 (Manus Clone系の整理メモ) で NLS 0.976 と4.6 Opusと同等水準を維持している一方、くずし字が激しいサンプル1 (NLS 0.751) では「VSR つよくなる」「自作キーの腐敗について」と推測寄りの出力になっています。

上の結果テーブルとモデル一覧、結論セクションも更新済みです。

追記 (2026-05-20): YomiToku v0.13.0 / NDLOCR-Lite v1.2.1 を再評価

OSSの日本語OCRモデル2つに大きなアップデートが入っていたので、再評価しました。

YomiToku v0.13.0

YomiToku v0.13.0 (2026-05-14リリース) で「検出モデル及び手書き文字の認識モデルの強化」が入りました。

再評価結果は NLS 0.842 で 9位 → 7位に大幅ジャンプ。前バージョン (NLS 0.770) から +0.072 ポイントの改善で、上のClaude 4.7 Opus (0.858) にあと0.016までの位置に迫っています。API のAzure AI Vision (0.830) / Google Cloud Vision (0.820) / GPT-5.5 (0.755) を軒並み上回るスコアで、OSS の日本語 OCR としては現時点でほぼベスト・イン・クラスです。

サンプル別の数字でも改善が見えていて、サンプル1 (NLS 0.608 → 0.773)、サンプル2 (0.626 → 0.679) と「Coding Agent」「Application」のような英単語混在の手書きで読みが安定するようになりました。一方で処理時間は 12.0s → 20.5s に増えていて、検出・認識モデルが少し重くなった分のトレードオフがあります。それでもAPI系の中位モデルと同等水準の精度がローカルで出るのは大きく、ローカル運用したい場合の第一候補です。

NDLOCR-Lite v1.2.1

NDLOCR-Lite v1.2.1 (2026-04-22リリース) でも「昨年度作成した学習データの追加に伴う文字認識モデルの改善(日本語手書き文字・英文タイプライター文字の大幅な改善)」というアップデートが入りました。手書きを直接ターゲットにしたチューニングです。

再評価結果は NLS 0.443 で 24位 → 22位。前バージョン (NLS 0.271) から +0.172 ポイントとほぼ倍近い改善で、DeepSeek-OCR (NLS 0.446) のすぐ下まで来ました。Nemotron OCR v2 (NLS 0.413)、PaddleOCR (NLS 0.353)、GOT-OCR 2.0 (NLS 0.194) といった「日本語手書きが苦手な」OSSモデル群を明確に抜けています。

ただし上位グループ (NLS 0.7 以上) との差は依然として大きく、CER 0.728 と文字レベルの誤り率もかなり高めです。「以前は使えなかったが、ある程度読めるようになってきた」フェーズで、まだ実用には他のOSSモデルに分があります。それでも、国立国会図書館チームが手書きデータで継続的に学習を改善している姿勢自体は心強いです。

上の結果テーブルも更新済みです。

Appendix: 画像別OCR出力例

実際の手書きメモ画像と各モデルのOCR出力を並べて見てみます。モデルごとの得意・不得意がよくわかります。

サンプル1: 技術メモ(短い箇条書き)

サンプル1

正解テキスト:

CodingAgent時代のApplication考
麻雀AIをCodingAgentで
VSR → うまくいかん
仕様書の腐敗について

Gemini系

Gemini 3.5 Flash (NLS=0.876)

- CodingAgent 時代の Application/s
- 麻雀 AI と Coding Agent で
- VSR -> うごかん
- 仕様書の腐敗について.

Gemini 3.1 Pro Preview (NLS=0.890)

・ Coding Agent 時代の Application/S
・ 麻雀 AI を Coding Agent で
・ VSR -> 外でいかん
- 仕様書の腐敗について.

Gemini 3 Flash Preview (NLS=0.840)

Coding Agent 時代の Application/s
麻雀 AI を Coding Agent で
VSR -> 外でかく
仕様書の腐敗について.

Gemini 3.1 Flash Lite Preview (NLS=0.865)

・CodingAgent時代のApplication/s
・麻雀AIをCodingAgentで
・VSR→外注とか
・仕様書の腐敗について

Claude系

Claude 4.7 Opus (NLS=0.751)

・CodingAgent時代のApplicationら
・麻雀AIとCodingAgentで
・VSR つよくなる
・自作キーの腐敗について

Claude 4.6 Opus (NLS=0.890)

· Coding Agent 時代の Applications
· 麻雀 AI を Coding Agent で
 , USR → みていかん
· 仕様書の腐敗について。

Claude 4.5 Sonnet (NLS=0.656)

CodingAgent の Applications
麻雀 A I と CodingAgent で
VSR -> 外に出る
仕事, 商談について

OpenAI

GPT-5.5 (NLS=0.596)

- CodingAgent系のApplications
- 麻雀AIをCodingAgentで
- USR -> HLDを書く
- (仕様書の確認->?)

GPT-5.4 (NLS=0.589)

CodingAgent with Applications
麻雀 AIと CodingAgentで
VSR -> みじかく
仕事を簡略化って?

Google Cloud Vision / Azure

Google Cloud Vision (NLS=0.782)

Coding Agent mit Application's
麻雀
AI & Coding Agent
VSRろぐかん
仕様の腐敗について
で

Azure AI Vision (NLS=0.807)

Coding Agent af Applications
麻雀AL CodingAgentで
USR →引くいかん
仕様書の肩題について

Mistral / Qwen

Mistral OCR (NLS=0.488)

Coding Agent with Applications
麻雀 AI & Coding Agent
VSR → 計算機
代理人 → 國際計算機

Qwen VL OCR (NLS=0.747)

、CodingAgent は代わり Application's
、麻雀 AI と CodingAgent で
、VSR → 31C へ
→ 仕様書の商談について

OSSモデル(Modal GPU)

HunyuanOCR (NLS=0.636)

CodingAgent 時代の Applications
麻雀 AI と CodingAgent の
VSR → 3 人が 1 人
任務者の腐敗の 2 人

Chandra (NLS=0.722)

・ Coding Agent の Application/S
・ 麻雀 AI と Coding Agent で
・ VSR -> 31C がん
・ 仕様書の修正についと

olmOCR-2 (NLS=0.681)

・ CodingAgent 以外の Application/s
・ 麻雀 AI と CodingAgent で
・ VSR → 31C が人
・ 任課者の発表について

YomiToku v0.13.0 (NLS=0.773)

Codinglint ant a Applicationtionts
麻雀AIをCodingAgentで
USR →31C1かん
仕様もの腐敗について

YomiToku v0.12.x (NLS=0.608)

S/mairmoi day 6 yha zuag (aipe).
、麻雀AZをCodingAgutで
VSR →31C、かん
、仕様もの周防について

GLM-OCR (NLS=0.690)

、Coding Agent 時代のApplication
、麻雀 AIをCoding Agentで
、VSR、トリックが人
、任作きの商談について。

Sarashina2.2-OCR (NLS=0.663)

CodingAgent refのApplications
- 麻雀AIをCodingAgentで
    - USRスクリプトから
    - 信頼性の評価について.

DeepSeek-OCR (NLS=0.468)

CodingAgent 应用 Application's
  麻省 A2z CodingAgent
  VSR -> 31C -> 7C
  在线考,有改 -> 7C

GOT-OCR 2.0 (NLS=0.220)

Cadi g/ Agent Bif f Application y

Nemotron OCR v2 (NLS=0.307)

•CodigAAgent iitt Appplicatiinns
。
-VSR.-3-346、
-

NDLOCR-Lite v1.2.1 (NLS=0.591)

Coding/pent att Appliontiontion/S
、麻養ALとCodighy ganer
, VSR つろ1しかん
- 仕後書の補助について、

PaddleOCR (NLS=0.000)

X
享
E
はトイ

NDLOCR v2 (NLS=0.010)

Ta
〓
〓〓
〓

「VSR → うまくいかん」の部分が面白くて、ほぼ全モデルが読み間違えています。Gemini 3.5 Flashが「うごかん」と最も近い線まで来ていますが、Gemini Proですら「外でいかん」になるし、GPT-5.4は「みじかく」、HunyuanOCRは「3 人が 1 人」、DeepSeek-OCRに至っては中国語が混入しています。手書き文字のくずし方が激しい部分はやはり難しいです。

一方で「仕様書の腐敗について」は上位モデルはほぼ正確に読めていて、GPT-5.4やClaude 4.5 Sonnetが「仕事を簡略化って?」「仕事, 商談について」と全然違う内容になっているのは意外です。

サンプル2: 技術メモ(英語混在)

サンプル2

正解テキスト:

permission mode auto対応
作り直すのもありかも
SDKを
比較したい
HarmonyとSDKを渡して
AgentSkillがWebAppをwrapするべきか
webAppがAgentをwrapするべきか
(及びSkill)

Gemini系

Gemini 3.5 Flash (NLS=0.867)

permission mode auto だが
作りながらのもありかも
↳ SDKを

比較したい...
Harmony と SDKを渡して、

Agent skill が Web App を wrap するのか
Web App が Agent を wrap するのか
(Agent skill)

Gemini 3.1 Pro Preview (NLS=0.833)

・permission mode auto 化
・作りかたのわかりやすさ
 ↳ SDKで
比較したい。
Harmony と SDK を通して。
Agent skill が Web App を wrap するべきか
Web App が Agent を wrap するべき
 (Agent skill)

Gemini 3 Flash Preview (NLS=0.823)

permission mode auto 以外
作りながら切りだす
↳ SDKを
比較したい…
Harmony と SDK を並べて、
Agent skill が Web App を wrap するべきか
web App が Agent を wrap するべきか
(Agent skill)

Gemini 3.1 Flash Lite Preview (NLS=0.811)

permission mode auto みたいな
作り方のちがいとか
↓ SDK
比較したい
Harmony と SDK を抜いて
Agent skill が Web App を wrap するのか
Web App が Agent を wrap するのか
(Agent Skill)

Claude系

Claude 4.7 Opus (NLS=0.762)

・permission mode auto だと
・作り方のしおりなど
 └ SDKと

et 検したい

Harmony と SDK を渡して

Agent skill が Web App を wrap するか

Web App が Agent を wrap するか
(ためしたい)

Claude 4.6 Opus (NLS=0.833)

・permission mode auto対応
・割り方のとりまとめ。
 → SDKを。
比較したい。
Harmony と SDK を抜いて。
Agent skill が Web App を wrap するのか
Web App が Agent を wrap するのなら
(及びskill)

Claude 4.5 Sonnet (NLS=0.633)

paralyzion mode auto 4k
/1140/10/24/3'4
⊂ SDK
etkizh...
Harmony と SDK を抜いて
Agent stall & Web App を wrap したい
Web App が Agent を wrap (7/22名
(AgShell)

OpenAI

GPT-5.5 (NLS=0.667)

permission mode auto 付与

/etc/thio/thy's y
↳ SDKを

etc使えて...

Harmony と SDKを使って.

Agent skill が Web App を wrap すること

Web App が Agent を wrap するもの
(AI Skills)

GPT-5.4 (NLS=0.624)

permission mode auto化
権限まわりとか
↳ SDKを
etc etc...
Harmony と SDK を使って。
Agent skill が Web App を wrap するだけ
Web App が Agent を wrap するなら
(API Shield)

Google Cloud Vision / Azure

Google Cloud Vision (NLS=0.699)

pernission mode
auto kitin
作物ものもありかも
SDKE
ettech...
HarmonyとSDKを渡して、
Agent stall & Web App & wrap 18-246'
Web App 6° Agent & wrap 17-925-
(Ari Skild)

Azure AI Vision (NLS=0.669)

permission mode auto .
倒なものもありがと
→ SDKE
比較したい、
HarmonyとCDKを渡して、
Ageat full of Web App 2 wrap is it!
Web App t" Agail & wrap 11 22.6
(Anislil)

Mistral / Qwen

Mistral OCR (NLS=0.519)

poralysion mode auto kth
1994/1995/1996
→ SDK
elkcon.
Harmony × SDK × 3kcc
Aged Skill 5 Web App 2 wrap 11 725
Web App 5 Agenc × wrap 11 725
(42 Skill)

Qwen VL OCR (NLS=0.665)

permission mode auto kit
倒物の skill skill サイズ
SDK
比較して...
Harmony x SDK を使って
Agent skill を Web App に wrap する
Web App で Agent skill を wrap する
(Agentskill)

OSSモデル(Modal GPU)

HunyuanOCR (NLS=0.695)

・permission mode auto kill
・倒すのがやすい
・<SDK>
・比較したい
・HarmonyとCDKを使う
・Agent skill とWeb App をwrap 行う
・Web App とAgent をwrap 行う
・(Agent skill)

GLM-OCR (NLS=0.666)

permission mode auto talk
徘行の比較式。
→ SDKを。
比较。
HarmonyとSDKを接って。

Agent skill 6 Web Appを wrap 13 でか
Web App 6 Agentを wrap 11 でか
(Agent skill)

Chandra (NLS=0.693)

permission mode auto kill
例のインテリゲンス
↳ SDK
比較した...
Harmony & SDK と比較して...
Agent Skill は Web App と wrap する
Web App は Agent と wrap する
(AniSkill)

olmOCR-2 (NLS=0.767)

・permission mode auto
・例物のおります。
 → SDK
・比較した。
Harmony と SDK を渡して。
Agent Skill が Web App と wrap に渡す
Web App が Agent と wrap に渡す
(外部Skill)

YomiToku v0.13.0 (NLS=0.679)

pernission mode auto kin
作物ものはわります
4 SDKE
比較したい
Harmony とくDKを渡して
Agent stall 6- Web App 2 wrap 13 .
Web App が" Agail & wrap TI TES
(AziSlill,

YomiToku v0.12.x (NLS=0.626)

perallsilon mode auto khi.
1.4/14761.4/13/ .
3/45 m
比較したい.
Marmony と SDKを推して、
Ageal skall 6' Wob App ? wrap li t'b'
Web App bi Ageil e wrap Ti 325
(Azislall)

Sarashina2.2-OCR (NLS=0.686)

permission mode auto kill
- 1945のctrl + c, | SDKe
接続したい...
HarmonyとSDKを渡して...
Agent skill b→Web App z wrap 1326b
Web app b→Agent e wrap Tl78a (zuiSkill)

DeepSeek-OCR (NLS=0.503)

permission mode auto 优先
  自动权限模式
   SD卡
   etc...
   Harmony 和 SDK 接口
   Agent shell 6 Web App 2 wrap 11.2.6
   Web App 6 Agent 2 wrap 11.2.6
   (A2shell)

GOT-OCR 2.0 (NLS=0.140)

per a is ton model eau to Hi

Nemotron OCR v2 (NLS=0.299)

LokS
etteci..
Harmony - spK   iu .
Appar delllo  wb  Appp  waa p ttttt
web App on Agene   wrap 11 222
by
(AriShidd)

NDLOCR-Lite v1.2.1 (NLS=0.380)

COCONCOCONDESBEDEDD
pornitssion mode auto kthe
例前1の6676
L Spkr
ettes.
Marmony e CPK & 抜して、
Mare the the the the the the anwer
Harmony 2 <pk e ine.
Apeestinl or wab ApP & wrap thiscor
wab App by Agent & weap 195
(A-25

PaddleOCR (NLS=0.083)

S
i

英語と日本語が混在していて、AgentSkillがWebAppをwrapするべきかのようなコード用語交じりの手書きテキストです。Gemini ProとClaude Opusは「Agent skill が Web App を wrap するべきか」とほぼ正確に読めています。

下位モデルではwrapが数字の羅列になったり(Google Cloud Vision: wrap 18-246')、まったく別の文になったり(Azure: Ageat full of Web App 2 wrap is it!)しています。DeepSeek-OCRが日本語部分を中国語で出力しているのも特徴的です(自动权限模式SD卡)。

Appendix: 評価指標の設計

Hungarian NLS (primary)

正解データの各領域に対して、予測テキストの中から最もマッチする行を見つけてNormalized Levenshtein Similarityを計算します。

正解領域: ["東京都", "渋谷区", "恵比寿1-2-3"]
予測テキスト: "渋谷区\n東京都\n恵比寿1-2-3"

→ 読み順が違っても各領域が正しく認識されていれば高スコア

VLMが正解領域を結合して出力するケース(「東京都渋谷区」のように1行にまとめる)や、逆に正解領域を分割するケース(「恵比寿」「1-2-3」に分ける)にも対応するため、隣接行のマージ候補と部分文字列マッチも組み込んでいます。

名前の由来は本来のHungarian Algorithmによる最適割当ですが、実装上は各正解領域に対して全予測行の中からベストスコアを取るGreedyマッチングです。正解領域間の重複マッチを許容することで、VLMが複数領域を結合して出力するケースに対応しています。

Bag-of-Characters F1 (secondary)

CC-OCRのアプローチを参考にした指標です。テキストを文字の多重集合(multiset)として扱い、語順・改行を完全に無視してPrecision/Recall/F1を計算します。

gt_chars  = Counter("東京都渋谷区")  # {'東':1, '京':1, '都':1, '渋':1, '谷':1, '区':1}
pred_chars = Counter("東京都渋谷区恵比寿")
matched = sum((gt_chars & pred_chars).values())  # 6
precision = 6/9, recall = 6/6

VLMがマークダウン記法や説明文を付け足す場合にPrecisionが下がるので、ノイズ検出にも使えます。

CER / NED (tertiary)

全文をフラットに連結してLevenshtein距離を計算する古典的な指標です。CERは正解テキストの長さで重み付け集計しています。

テキスト正規化

3つの指標すべてで共通の正規化パイプラインを通します。

  1. Markdownストリップ — VLMが付けがちな##見出し、**太字**、リスト記号等を除去
  2. VLMノイズ除去 — などの装飾文字、(丸で囲まれている)のようなメタ記述、絵文字を除去
  3. NFKC正規化 — 全角英数字を半角に統一
  4. 空白・句読点の除去(BoC/NED計算時)

この正規化がないとVLMの出力がめちゃくちゃ不利になります。マークダウン記法を付けてくる時点で「テキストは正しく読めている」のに、記法のせいでスコアが下がるのは不公平なので。ただし過剰な正規化はモデル間の差を消してしまうので、「明らかにOCR対象外の記号」だけを除去するよう慎重にルールを設計しています。

Appendix: 画像前処理

アノテーションツールに画像をアップロードすると、OCRに渡す前に以下の前処理パイプラインが走ります。正直なところロジックの検証は甘いので、うまく効かないケースもあると思います。ないよりマシ程度の雑な実装です。

  1. 紙面検出・切り出し — OpenCVのOtsu二値化 + モルフォロジー閉操作で紙面領域を検出し、minAreaRectで4点を取って透視変換で切り出します。紙面が画像面積の15%未満なら検出失敗として元画像をそのまま使います
  2. 粗い向き補正(0/90/180/270°) — docTRのMobileNetV3ベースの向き推定器を使っています。confidence 0.7未満なら回転しません
  3. 細かい傾き補正 — jdeskewで微小角度(0.3°〜15°)の傾きを補正します
  4. 影除去 + コントラスト強調 — medianBlurで背景推定して除算で照明ムラを除去し、CLAHEでコントラストを上げます

とくに1の紙面検出は、背景と紙のコントラストが低いケースや紙が折れ曲がっているケースで失敗することがあります。失敗しても元画像にフォールバックするので壊れはしませんが、余白が多い状態でOCRに渡されることになります。

Appendix: Modalで12モデルを動かす

OSSモデルの評価にはModalを使っています。サーバーレスGPUプラットフォームで、T4、L4、A100などのGPUをPythonのデコレータ一つで使えます。

各モデルのModalスクリプトは統一的なインターフェースに従います。

@app.function(gpu="L4", image=image, timeout=1800)
def run_ocr(images_b64: list[str]) -> list[str]:
    # base64画像を受け取り、OCR結果のテキストリストを返す
    ...

@app.local_entrypoint()
def main(input: str, output: str):
    from _common import load_input, save_output
    data = load_input(input)
    results = run_ocr.remote(data["images"])
    save_output(output, results)

入力はbase64エンコードした画像のJSON、出力はOCRテキストのJSON。この規約を守れば新しいモデルの追加が簡単です。ハマりどころ(PaddlePaddleのGPU版指定、libgl1依存、CUDAバージョン等)はAGENTS.mdにまとめてあります。

References