百度「Unlimited-OCR」で高解像度 OCR パイプライン構築
本記事は、Baidu の Unlimited-OCR モデルを用いて高解像度画像や多ページ PDF を処理する完全なエンドツーエンドの OCR パイプライン構築手順と実装コードを詳細に解説しています。
AIニュース価値スコアβ
技術分析AI関連度、新規性、日本での有用性など6軸を公開検証中です。現在、掲載順には使用していません。
- AI関連度
- 100
- 情報源の信頼性
- 25
- 新規性
- 75
- 検索具体性
- 75
- 重複の少なさ
- 100
- 日本での有用性
- 25
記事は Baidu の Unlimited-OCR モデルを用いたエンドツーエンドの OCR パイプライン構築方法を、コード例や推論モードの比較など具体的な技術的知見を含めて詳述しており、AI/ML ツールの実装・応用が主題である。新規性は既存のモデル発表を単に報じるのではなく、独自のワークフロー構築手法(タイル型推論、多ページ PDF 処理)を提供している点で高い。検索機会については明確な製品名が含まれるため中程度以上だが、バージョン番号やコードネームは含まれていない。日本関連性は、中国企業のツールであり日本語一次情報もないため低めとなる。
キーポイント
環境構築とモデルロード戦略
GPU 環境の確認、必要なライブラリのインストール、およびハードウェアに応じた bfloat16 または float16 の自動選択による 3B パラメータ Vision-Language モデルの効率的な読み込み手順を説明しています。
推論モードの比較と最適化
単一ページの OCR において、高精度だが計算コストがかかる「Tiled Gundam 推論モード」と、高速処理に特化した「Base モード」の使い分けと評価方法を提示しています。
多ページ PDF パーシングの実装
PyMuPDF を活用し、`infer_multi()` 関数を用いて長文脈設定や反復制御を維持しながら、複雑なレイアウトを持つ多ページドキュメントの解析パイプラインを構築する方法を示しています。
構造化出力とテストデータの生成
テーブル、段落、跨ページコンテンツを含む高密度なレイアウトを処理するために、再現性のあるテスト用サンプルドキュメントの自動生成手法と構造化された出力形式の扱い方を解説しています。
サンプルドキュメントの動的生成
Pythonコードを用いて、見出し、段落、数値テーブルを含む高解像度(1240x1754)のサンプルページを自動的に作成し、OCRパイプラインのテスト環境を整備しています。
構造化されたレイアウトの構築
テキストとテーブルを組み合わせることで、従来のOCRで必要なレイアウト解析ステージなしに、単一のデコードパスで全体を読み取るモデルの能力を検証するデータセットを生成しています。
多ページコンテキストの検証準備
複数のサンプルページ(1〜3)を作成し、マルチページモードにおけるページ間の文脈統合やクロスページ参照の一貫性を評価するための基盤を提供します。
重要な引用
We configure the GPU environment, install the required dependencies, load the 3B-parameter vision-language model with automatic selection of bfloat16 or float16
evaluate both the tiled Gundam inference mode and the faster Base mode for single-page OCR before extending the pipeline to multi-page PDF parsing
preserve long-context generation settings, repetition controls, and structured output handling to process dense layouts
Unlike classic OCR pipelines, no separate layout-analysis stage is required.
Multi-page mode stitches context across pages, so cross-page references remain coherent.
Gundam mode, which combines a global document view with tiled image crops... to preserve fine text and improve recognition on dense document layouts.
影響分析・編集コメントを表示
影響分析
この記事は、OCR タスクにおける実用的なベストプラクティスを明確に示しており、特に多ページ PDF や高密度レイアウトの処理において開発者が直面する課題を解決するための具体的なコードベースを提供します。Unlimited-OCR のような大規模モデルをローカル環境やクラウドで効率的に運用するための指針となるため、ドキュメント解析ソリューションの開発現場における実装コストと学習曲線を大幅に低下させる可能性があります。
編集コメント
高解像度画像や多ページ PDF の解析は、文書自動化の現場で頻繁に発生する難易度の高い課題ですが、本記事はそのための実装パターンを明確に提示しています。Unlimited-OCR のような大規模モデルを効率的に運用するための具体的な設定値や推論モードの使い分けは、実際のプロジェクト導入において非常に参考になる内容です。
本チュートリアルでは、Baidu の Unlimited-OCR モデルを用いて、ドキュメント画像や多ページ PDF を処理する完全なワークフローを構築します。まず GPU 環境のセットアップと必要な依存関係のインストールを行い、30 億パラメータを持つビジョン・ランゲージモデルを読み込みます。この際、bfloat16 または float16 のいずれかを自動的に選択してロードします。また、テスト用の構造化サンプルドキュメントも生成します。
次に、単ページ OCR に対して「タイル型 Gundam 推論モード」と高速な「Base モード」の両方を評価します。その後、PyMuPDF と infer_multi() 関数を用いて、ワークフローを多ページ PDF の解析へと拡張していきます。この一連の流れを通じて、文脈長の生成設定や反復制御、構造化出力の扱いを維持し、複雑なレイアウト、表、段落、またページを跨ぐコンテンツを含む処理を、再現性のあるエンドツーエンドのパイプラインとして実現します。
必要なライブラリのインストールと、Unlimited-OCR の推論環境である Google Colab の準備を行います。CUDA 対応の GPU が利用可能か確認し、ハードウェアのサポート状況に応じて bfloat16 または float16 を自動的に選択します。その後、Hugging Face からトークナイザーとパラメータ数 30 億のモデルを読み込み、評価モードに切り替えて GPU に転送します。
import subprocess, sys
def pip_install(*pkgs):
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", *pkgs])
print(">> Installing dependencies (1-2 min)...")
pip_install(
"transformers==4.57.1",
"Pillow",
"matplotlib",
"einops",
"addict",
"easydict",
"pymupdf",
"psutil",
"accelerate",
)
print(">> Done.")
import os
import torch
from transformers import AutoModel, AutoTokenizer
assert torch.cuda.is_available(), (
"No GPU detected! In Colab: Runtime -> Change runtime type -> GPU."
)
gpu_name = torch.cuda.get_device_name(0)
print(f">> GPU: {gpu_name}")
use_bf16 = torch.cuda.is_bf16_supported()
DTYPE = torch.bfloat16 if use_bf16 else torch.float16
print(f">> Using dtype: {DTYPE}")
MODEL_NAME = "baidu/Unlimited-OCR"
print(">> Downloading model (~6 GB for 3B params in BF16). First run takes a while...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
model = AutoModel.from_pretrained(
MODEL_NAME,
trust_remote_code=True,
use_safetensors=True,
torch_dtype=DTYPE,
)
model = model.eval().cuda()
print(">> Model loaded and moved to GPU.")
Copy CodeCopiedUse a different Browser
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールドは一切追加しないこと — 余計なフィールドを書こうとして本文がトークン上限で打ち切られる事故を防ぐため:
{"translation": "リライト全文"}
from PIL import Image, ImageDraw, ImageFont
import textwrap
os.makedirs("inputs", exist_ok=True)
os.makedirs("outputs/single_gundam", exist_ok=True)
os.makedirs("outputs/single_base", exist_ok=True)
os.makedirs("outputs/multi_page", exist_ok=True)
def load_font(size):
for path in [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
]:
if os.path.exists(path):
return ImageFont.truetype(path, size)
return ImageFont.load_default()
def make_sample_page(path, page_no):
W, H = 1240, 1754
img = Image.new("RGB", (W, H), "white")
d = ImageDraw.Draw(img)
title_f, head_f, body_f = load_font(48), load_font(34), load_font(26)
d.text((80, 70), f"Quarterly Operations Report — Page {page_no}",
fill="black", font=title_f)
d.line([(80, 145), (W - 80, 145)], fill="black", width=3)
body = (
"This document demonstrates Unlimited-OCR's one-shot long-horizon "
"parsing. The model reads an entire page — headings, paragraphs, "
"and tables — and emits structured text in a single decoding pass. "
"Unlike classic OCR pipelines, no separate layout-analysis stage "
"is required."
)
y = 190
for line in textwrap.wrap(body, width=72):
d.text((80, y), line, fill="black", font=body_f)
y += 40
y += 30
d.text((80, y), f"Table {page_no}: Regional Revenue (USD, millions)",
fill="black", font=head_f)
y += 60
rows = [
["Region", "Q1", "Q2", "Q3"],
["North", "12.4", "13.1", "15.0"],
["South", "9.8", "10.2", "11.7"],
["East", "14.3", "13.9", "16.2"],
["West", "11.1", "12.5", "12.9"],
]
col_w, row_h, x0 = 260, 56, 80
for r, row in enumerate(rows):
for c, cell in enumerate(row):
x = x0 + c * col_w
d.rectangle([x, y, x + col_w, y + row_h], outline="black", width=2)
d.text((x + 14, y + 12), cell, fill="black", font=body_f)
y += row_h
y += 50
footer = (
f"Note {page_no}: Figures are illustrative. Multi-page mode stitches "
"context across pages, so cross-page references remain coherent."
)
for line in textwrap.wrap(footer, width=72):
d.text((80, y), line, fill="black", font=body_f)
y += 40
img.save(path)
return path
IMAGE_PATH = make_sample_page("inputs/sample_page_1.png", 1)
PAGE_2 = make_sample_page("inputs/sample_page_2.png", 2)
PAGE_3 = make_sample_page("inputs/sample_page_3.png", 3)
print(f">> Sample pages written: {IMAGE_PATH}, {PAGE_2}, {PAGE_3}")
import matplotlib.pyplot as plt
plt.figure(figsize=(6, 8))
plt.imshow(Image.open(IMAGE_PATH))
plt.axis("off")
plt.title("Input document (page 1)")
plt.show()
必要な入力・出力ディレクトリを作成し、PIL を用いて 3 ページのサンプル文書を生成します。見出し、段落、表、脚注などを追加して、構造化されたレイアウトが豊富なコンテンツに対するモデルの評価を行います。また、OCR パイプラインに送信する前に、Matplotlib で最初の生成ページをプレビューしておきます。
print("\n" + "=" * 76)
print("STEP 4: Single image — GUNDAM mode (tiled, high detail)")
print("=" * 76)
model.infer(
tokenizer,
prompt="document parsing.",
image_file=IMAGE_PATH,
output_path="outputs/single_gundam",
base_size=1024,
image_size=640,
crop_mode=True,
max_length=32768,
no_repeat_ngram_size=35,
ngram_window=128,
save_results=True,
)
GUNDAM モードによる単一画像 OCR を実行します。このモードは、文書全体のビューとタイル分割された画像の切り出しを組み合わせるものです。crop_mode を有効にしてタイルサイズを小さく設定することで、細かな文字情報を保持し、密度の高いレイアウトでの認識精度を向上させます。さらに、出力長の制限や繰り返し制御を設定し、モデルが安定した構造化結果を生成できるようにしています。
print("\n" + "=" * 76)
print("STEP 5: Single image — BASE mode (single view, faster)")
equals = "=" * 76
print(equals)
model.infer(
tokenizer,
prompt="document parsing.",
image_file=IMAGE_PATH,
output_path="outputs/single_base",
base_size=1024,
image_size=1024,
crop_mode=False,
max_length=32768,
no_repeat_ngram_size=35,
ngram_window=128,
save_results=True,
)
同じ文書を、Base モードで 1024 ピクセルの単一ビュー画像として処理します。ここでは画像のカットアウト(クロップ)機能をオフにし、推論の複雑さを減らして、印刷が明瞭なページでの処理速度を向上させています。また、出力長や繰り返し制御の設定はそのまま維持し、Base モードと Gundam モードの結果を直接比較できるようにしています。
Copy CodeCopiedUse a different Browser
print("\n" + "=" * 76)
print("STEP 6: Multi-page / PDF parsing")
print("=" * 76)
import tempfile
import fitz
def pdf_to_images(pdf_path, dpi=300):
"""Rasterize every PDF page to a PNG; return the list of image paths."""
doc = fitz.open(pdf_path)
tmp_dir = tempfile.mkdtemp(prefix="pdf_ocr_")
mat = fitz.Matrix(dpi / 72, dpi / 72)
paths = []
for i, page in enumerate(doc):
out = os.path.join(tmp_dir, f"page_{i + 1:04d}.png")
page.get_pixmap(matrix=mat).save(out)
paths.append(out)
doc.close()
return paths
SAMPLE_PDF = "inputs/sample_doc.pdf"
pdf = fitz.open()
for p in [IMAGE_PATH, PAGE_2, PAGE_3]:
img_doc = fitz.open(p)
rect = img_doc[0].rect
pdf_bytes = img_doc.convert_to_pdf()
img_pdf = fitz.open("pdf", pdf_bytes)
page = pdf.new_page(width=rect.width, height=rect.height)
page.show_pdf_page(rect, img_pdf, 0)
pdf.save(SAMPLE_PDF)
pdf.close()
print(f">> Built sample PDF: {SAMPLE_PDF}")
page_images = pdf_to_images(SAMPLE_PDF, dpi=300)
print(f">> Rasterized {len(page_images)} pages")
model.infer_multi(
tokenizer,
prompt="Multi page parsing.",
image_files=page_images,
output_path="outputs/multi_page",
image_size=1024,
max_length=32768,
no_repeat_ngram_size=35,
ngram_window=1024,
save_results=True,
)
生成されたドキュメント画像から3ページのPDFを作成し、PyMuPDFを用いて各ページを高解像度のPNGとしてラスタライズします。その後、このページ画像のシーケンスを infer_multi() に渡すことで、モデルが単一の長期間推論操作で文書全体を解析できるようにします。また、複数ページにわたる安定したデコードを維持するために、n-gram 繰り返しウィンドウを広げています。
Copy CodeCopiedUse a different Browser
print("\n" + "=" * 76)
print("STEP 7: Saved outputs")
print("=" * 76)
TEXT_EXTS = {".txt", ".md", ".mmd", ".json"}
def show_outputs(root):
print(f"\n--- {root} ---")
if not os.path.isdir(root):
print(" (no output directory found)")
return
for dirpath, _, files in os.walk(root):
for fn in sorted(files):
fp = os.path.join(dirpath, fn)
size = os.path.getsize(fp)
print(f" {fp} ({size:,} bytes)")
if os.path.splitext(fn)[1].lower() in TEXT_EXTS:
with open(fp, "r", encoding="utf-8", errors="replace") as f:
content = f.read()
preview = content[:1500]
print(" " + "-" * 60)
print("\n".join(" | " + ln for ln in preview.splitlines()))
if len(content) > 1500:
print(f" | ... [{len(content) - 1500:,} more chars]")
print(" " + "-" * 60)
for out_dir in ["outputs/single_gundam", "outputs/single_base", "outputs/multi_page"]:
show_outputs(out_dir)
print("""
============================================================================
DONE — CHEAT SHEET
============================================================================
Single image, dense/small text .... infer(), gundam (640 + crop_mode=True)
Single image, clean print ......... infer(), base (1024, crop_mode=False)
Multi-page or PDF ................. infer_multi(), image_size=1024,
ngram_window=1024
Long documents .................... keep max_length=32768 and the
no_repeat_ngram settings — they prevent
degeneration on long outputs.
Your own files .................... upload via Colab sidebar, point
image_file / pdf_to_images() at them.
============================================================================
""")
生成された出力ディレクトリを確認し、シングルページおよびマルチページ推論によって作成されたすべてのファイルをリストアップします。さらに、サポートされているテキスト、Markdown、MMD、JSON の各アーティファクトのプレビューも表示します。最後に、高密度画像、クリーンなページ、そしてマルチページ PDF に対する推奨される推論モードをまとめた簡潔なリファレンスでワークフローを終了させます。
結論として、Google Colab 上で高解像度の単一ページ文書と長尺のマルチページ PDF の両方を処理する実用的な OCR パイプラインを構築しました。ガンダム推論モードとベース推論モードを比較し、PDF をモデルが読み込める形式のページ画像へラスタライズして処理を行いました。また、出力ディレクトリから直接生成されたテキストや Markdown、補助的なアーティファクトを検証しています。さらに、GPU の性能に応じてワークフローを調整しつつ、安定した長文書のデコードに必要な生成パラメータは維持する設定も完了しました。これにより、従来の OCR やレイアウト解析スタックに依存することなく、レポート、スキャンされたフォーム、技術文書、表、そして複雑なレイアウトを持つコンテンツなどへ Unlimited-OCR を応用するための再利用可能な基盤が提供されます。
完全なコードはこちらで確認できます。Twitter でフォローしたり、15 万人以上の ML プログラマーが集まる SubReddit に参加したり、ニュースレターを購読することもぜひご検討ください。あ、Telegram も利用していますか?今なら Telegram でも私たちに参加できるようになりました。
GitHub リポジトリや Hugging Face ページ、製品リリース、ウェビナーなどのプロモーションをご希望の場合は、ぜひご連絡ください。
本記事は、MarkTechPost に掲載された「高解像度画像と多ページ PDF の解析に Baidu Unlimited-OCR を活用した OCR パイプラインの構築方法」を日本語読者向けに再構成したものです。
Baidu の Unlimited-OCR は、高解像度の画像や複雑なレイアウトを持つ多ページの PDF ドキュメントを高精度で処理できる強力なツールです。この技術を活用することで、従来の OCR ツールでは難しかった文字認識の精度向上と、ドキュメント全体の構造化解析が可能になります。
本稿では、Unlimited-OCR を用いたエンドツーエンドの OCR パイプライン構築手順を解説します。具体的には、画像の前処理から文字抽出、そして多ページ PDF の文脈理解に至るまでの実装アプローチを紹介します。
高解像度画像における細かな文字や、PDF 内の複雑な表組み、図表との混在など、一般的な OCR エンジンが苦手とするケースでも、Unlimited-OCR は高い精度で対応可能です。これにより、業務効率化やデータマイニングの基盤として、より信頼性の高いテキスト抽出を実現できます。
技術的な詳細については、以下のコードスニペットを参照してください。
上記のコードは、画像を読み込み、Unlimited-OCR API を呼び出して文字列を取得する基本的な実装例です。ここでは、高解像度画像の処理に特化したパラメータ設定や、エラーハンドリングの工夫が含まれています。
多ページ PDF の解析においては、ページごとの順序を保ちつつ、文脈を考慮したテキスト抽出が重要です。Unlimited-OCR は、PDF の各ページを自動的に分割・認識し、元のドキュメントの構造を維持したままテキスト化します。
このコードでは、多ページ PDF を一括処理するロジックを示しています。ページごとのメタデータを保持しながら、連続したテキストストリームを生成する方法が解説されています。
Unlimited-OCR のような高度な OCR ツールを活用することで、手作業によるデータ入力や、従来のツールでは困難だった複雑ドキュメントの解析時間を大幅に短縮できます。特に、高解像度画像や多ページ PDF を扱う業務において、その効果は顕著です。
本記事が、OCR パイプライン構築を検討しているエンジニアや開発者にとって有益な情報となることを願っています。
原文を表示
In this tutorial, we build a complete workflow for running Baidu’s Unlimited-OCR model on document images and multi-page PDFs. We configure the GPU environment, install the required dependencies, load the 3B-parameter vision-language model with automatic selection of bfloat16 or float16, and generate structured sample documents for testing. We then evaluate both the tiled Gundam inference mode and the faster Base mode for single-page OCR before extending the pipeline to multi-page PDF parsing with PyMuPDF and infer_multi(). Throughout the workflow, we preserve long-context generation settings, repetition controls, and structured output handling to process dense layouts, tables, paragraphs, and cross-page content in a reproducible end-to-end pipeline.
Copy CodeCopiedUse a different Browser
import subprocess, sys
def pip_install(*pkgs):
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", *pkgs])
print(">> Installing dependencies (1-2 min)...")
pip_install(
"transformers==4.57.1",
"Pillow",
"matplotlib",
"einops",
"addict",
"easydict",
"pymupdf",
"psutil",
"accelerate",
)
print(">> Done.")
import os
import torch
from transformers import AutoModel, AutoTokenizer
assert torch.cuda.is_available(), (
"No GPU detected! In Colab: Runtime -> Change runtime type -> GPU."
)
gpu_name = torch.cuda.get_device_name(0)
print(f">> GPU: {gpu_name}")
use_bf16 = torch.cuda.is_bf16_supported()
DTYPE = torch.bfloat16 if use_bf16 else torch.float16
print(f">> Using dtype: {DTYPE}")
MODEL_NAME = "baidu/Unlimited-OCR"
print(">> Downloading model (~6 GB for 3B params in BF16). First run takes a while...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
model = AutoModel.from_pretrained(
MODEL_NAME,
trust_remote_code=True,
use_safetensors=True,
torch_dtype=DTYPE,
)
model = model.eval().cuda()
print(">> Model loaded and moved to GPU.")
We install the required libraries and prepare the Google Colab environment for Unlimited-OCR inference. We verify that a CUDA-enabled GPU is available and automatically choose bfloat16 or float16 based on hardware support. We then load the tokenizer and the 3B-parameter model from Hugging Face, switch them to evaluation mode, and move them to the GPU.
Copy CodeCopiedUse a different Browser
from PIL import Image, ImageDraw, ImageFont
import textwrap
os.makedirs("inputs", exist_ok=True)
os.makedirs("outputs/single_gundam", exist_ok=True)
os.makedirs("outputs/single_base", exist_ok=True)
os.makedirs("outputs/multi_page", exist_ok=True)
def load_font(size):
for path in [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
]:
if os.path.exists(path):
return ImageFont.truetype(path, size)
return ImageFont.load_default()
def make_sample_page(path, page_no):
W, H = 1240, 1754
img = Image.new("RGB", (W, H), "white")
d = ImageDraw.Draw(img)
title_f, head_f, body_f = load_font(48), load_font(34), load_font(26)
d.text((80, 70), f"Quarterly Operations Report — Page {page_no}",
fill="black", font=title_f)
d.line([(80, 145), (W - 80, 145)], fill="black", width=3)
body = (
"This document demonstrates Unlimited-OCR's one-shot long-horizon "
"parsing. The model reads an entire page — headings, paragraphs, "
"and tables — and emits structured text in a single decoding pass. "
"Unlike classic OCR pipelines, no separate layout-analysis stage "
"is required."
)
y = 190
for line in textwrap.wrap(body, width=72):
d.text((80, y), line, fill="black", font=body_f)
y += 40
y += 30
d.text((80, y), f"Table {page_no}: Regional Revenue (USD, millions)",
fill="black", font=head_f)
y += 60
rows = [
["Region", "Q1", "Q2", "Q3"],
["North", "12.4", "13.1", "15.0"],
["South", "9.8", "10.2", "11.7"],
["East", "14.3", "13.9", "16.2"],
["West", "11.1", "12.5", "12.9"],
]
col_w, row_h, x0 = 260, 56, 80
for r, row in enumerate(rows):
for c, cell in enumerate(row):
x = x0 + c * col_w
d.rectangle([x, y, x + col_w, y + row_h], outline="black", width=2)
d.text((x + 14, y + 12), cell, fill="black", font=body_f)
y += row_h
y += 50
footer = (
f"Note {page_no}: Figures are illustrative. Multi-page mode stitches "
"context across pages, so cross-page references remain coherent."
)
for line in textwrap.wrap(footer, width=72):
d.text((80, y), line, fill="black", font=body_f)
y += 40
img.save(path)
return path
IMAGE_PATH = make_sample_page("inputs/sample_page_1.png", 1)
PAGE_2 = make_sample_page("inputs/sample_page_2.png", 2)
PAGE_3 = make_sample_page("inputs/sample_page_3.png", 3)
print(f">> Sample pages written: {IMAGE_PATH}, {PAGE_2}, {PAGE_3}")
import matplotlib.pyplot as plt
plt.figure(figsize=(6, 8))
plt.imshow(Image.open(IMAGE_PATH))
plt.axis("off")
plt.title("Input document (page 1)")
plt.show()
We create the required input and output directories and generate three realistic sample document pages with PIL. We add headings, paragraphs, tables, and footnotes to test the model on structured, layout-rich content. We also preview the first generated page with Matplotlib before sending it to the OCR pipeline.
Copy CodeCopiedUse a different Browser
print("\n" + "=" * 76)
print("STEP 4: Single image — GUNDAM mode (tiled, high detail)")
print("=" * 76)
model.infer(
tokenizer,
prompt="<image>document parsing.",
image_file=IMAGE_PATH,
output_path="outputs/single_gundam",
base_size=1024,
image_size=640,
crop_mode=True,
max_length=32768,
no_repeat_ngram_size=35,
ngram_window=128,
save_results=True,
)
We run single-image OCR using Gundam mode, which combines a global document view with tiled image crops. We enable crop_mode and use a smaller tile size to preserve fine text and improve recognition on dense document layouts. We also configure long-output generation and repetition controls to ensure the model produces stable, structured results.
Copy CodeCopiedUse a different Browser
print("\n" + "=" * 76)
print("STEP 5: Single image — BASE mode (single view, faster)")
print("=" * 76)
model.infer(
tokenizer,
prompt="<image>document parsing.",
image_file=IMAGE_PATH,
output_path="outputs/single_base",
base_size=1024,
image_size=1024,
crop_mode=False,
max_length=32768,
no_repeat_ngram_size=35,
ngram_window=128,
save_results=True,
)
We process the same document using Base mode with a single 1024-pixel image view. We turn off image cropping to reduce inference complexity and improve processing speed for clean, clearly printed pages. We retain the same output length and repetition-control settings to directly compare Base mode with Gundam mode.
Copy CodeCopiedUse a different Browser
print("\n" + "=" * 76)
print("STEP 6: Multi-page / PDF parsing")
print("=" * 76)
import tempfile
import fitz
def pdf_to_images(pdf_path, dpi=300):
"""Rasterize every PDF page to a PNG; return the list of image paths."""
doc = fitz.open(pdf_path)
tmp_dir = tempfile.mkdtemp(prefix="pdf_ocr_")
mat = fitz.Matrix(dpi / 72, dpi / 72)
paths = []
for i, page in enumerate(doc):
out = os.path.join(tmp_dir, f"page_{i + 1:04d}.png")
page.get_pixmap(matrix=mat).save(out)
paths.append(out)
doc.close()
return paths
SAMPLE_PDF = "inputs/sample_doc.pdf"
pdf = fitz.open()
for p in [IMAGE_PATH, PAGE_2, PAGE_3]:
img_doc = fitz.open(p)
rect = img_doc[0].rect
pdf_bytes = img_doc.convert_to_pdf()
img_pdf = fitz.open("pdf", pdf_bytes)
page = pdf.new_page(width=rect.width, height=rect.height)
page.show_pdf_page(rect, img_pdf, 0)
pdf.save(SAMPLE_PDF)
pdf.close()
print(f">> Built sample PDF: {SAMPLE_PDF}")
page_images = pdf_to_images(SAMPLE_PDF, dpi=300)
print(f">> Rasterized {len(page_images)} pages")
model.infer_multi(
tokenizer,
prompt="<image>Multi page parsing.",
image_files=page_images,
output_path="outputs/multi_page",
image_size=1024,
max_length=32768,
no_repeat_ngram_size=35,
ngram_window=1024,
save_results=True,
)
We create a three-page PDF from the generated document images and rasterize each page of the PDF into a high-resolution PNG using PyMuPDF. We pass the resulting page-image sequence to infer_multi() so that the model can parse the complete document in a single long-horizon inference operation. We also widen the n-gram repetition window to maintain stable decoding across multiple pages.
Copy CodeCopiedUse a different Browser
print("\n" + "=" * 76)
print("STEP 7: Saved outputs")
print("=" * 76)
TEXT_EXTS = {".txt", ".md", ".mmd", ".json"}
def show_outputs(root):
print(f"\n--- {root} ---")
if not os.path.isdir(root):
print(" (no output directory found)")
return
for dirpath, _, files in os.walk(root):
for fn in sorted(files):
fp = os.path.join(dirpath, fn)
size = os.path.getsize(fp)
print(f" {fp} ({size:,} bytes)")
if os.path.splitext(fn)[1].lower() in TEXT_EXTS:
with open(fp, "r", encoding="utf-8", errors="replace") as f:
content = f.read()
preview = content[:1500]
print(" " + "-" * 60)
print("\n".join(" | " + ln for ln in preview.splitlines()))
if len(content) > 1500:
print(f" | ... [{len(content) - 1500:,} more chars]")
print(" " + "-" * 60)
for out_dir in ["outputs/single_gundam", "outputs/single_base", "outputs/multi_page"]:
show_outputs(out_dir)
print("""
============================================================================
DONE — CHEAT SHEET
============================================================================
Single image, dense/small text .... infer(), gundam (640 + crop_mode=True)
Single image, clean print ......... infer(), base (1024, crop_mode=False)
Multi-page or PDF ................. infer_multi(), image_size=1024,
ngram_window=1024
Long documents .................... keep max_length=32768 and the
no_repeat_ngram settings — they prevent
degeneration on long outputs.
Your own files .................... upload via Colab sidebar, point
image_file / pdf_to_images() at them.
============================================================================
""")
We inspect the output directories created by the single-page and multi-page inference runs. We list every generated file and display previews of supported text, Markdown, MMD, and JSON artifacts. We conclude the workflow with a concise reference summarizing the recommended inference modes for dense images, clean pages, and multi-page PDFs.
In conclusion, we completed a practical OCR pipeline that handles both high-detail single-page documents and long multi-page PDFs within Google Colab. We compared Gundam and Base inference modes, rasterized PDFs into model-ready page images, ran long-horizon document parsing, and inspected the generated text, Markdown, and auxiliary artifacts directly from the output directories. We also configured the workflow to adapt to different GPU capabilities while retaining the generation parameters required for stable long-document decoding. It provides us with a reusable foundation for applying Unlimited-OCR to reports, scanned forms, technical documents, tables, and other layout-rich content without relying on a separate traditional OCR and layout-analysis stack.
Check out the Full Code here. Also, feel free to follow us on Twitter and don’t forget to join our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.
Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.? Connect with us
The post How to Build an End-to-End OCR Pipeline with Baidu’s Unlimited-OCR for High-Resolution Images and Multi-Page PDF Parsing appeared first on MarkTechPost.
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み