日本語にも対応しているOCRモデルの GLM-OCR を Gradioから使ってみる

はじめに

GLM-OCRは画像からテキスト、数式、表を認識できるモデルです。

複数の認識タイプに対応しており、日本語も含めた様々な言語のテキスト認識が可能です。

今回はGradioを使用してWebUI化し、実際に動作を確認してみました。

PC環境

Windows 11

Python環境構築

uvを使っています。pyproject.tomlを載せておくので uv sync のみで環境構築可能です。

transformersについては、最新の機能を使用するためにgit経由でのインストールを指定しています。

[project]
name = "glmocr"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "accelerate==1.12.0",
    "torch==2.10.0+cu126",
    "torchvision==0.25.0+cu126",
    "transformers @ git+https://github.com/huggingface/transformers.git",
    "gradio==6.5.1",
    "pillow==10.0.0",
]

[[tool.uv.index]]
name = "torch-cuda"
url = "https://download.pytorch.org/whl/cu126"
explicit = true

[tool.uv.sources]
torch = [{ index = "torch-cuda" }]
torchvision = [{ index = "torch-cuda" }]

特徴

GLM-OCRの主な特徴は以下の通りです:

  • 複数の認識モード - テキスト認識、数式認識、表認識に対応
  • マルチリンガル対応 - 日本語を含む複数言語のテキスト認識が可能

結果

元画像

#テキスト認識(Text Recognition)

通常のテキスト認識モードです。印刷されたテキストや手書きテキストを認識できます。

f(x) = sin x
g(x) = cos(-x)
h(x) = tan(1/x)

数式認識(Formula Recognition)

数学的な数式を認識して、LaTeX形式で出力してくれました。

$$
\begin{array}{l} f (x) = \sin x \\ g (x) = \cos (- x) \\ h (x) = \tan (1 / x) \\ \end{array}
$$

Pythonスクリプト

uv run main.py で実行するとWebUIが起動します。

from transformers import AutoProcessor, AutoModelForImageTextToText
import torch
import gradio as gr
from PIL import Image

MODEL_PATH = "zai-org/GLM-OCR"

# Global variables for model caching
processor = None
model = None

def load_model():
    global processor, model
    if processor is None or model is None:
        processor = AutoProcessor.from_pretrained(MODEL_PATH)
        model = AutoModelForImageTextToText.from_pretrained(
            pretrained_model_name_or_path=MODEL_PATH,
            torch_dtype="auto",
            device_map="auto",
        )
    return processor, model

def recognize_text(image, prompt="Text Recognition:"):
    """
    Recognize text from an image using GLM-OCR model.

    Args:
        image: PIL Image object
        prompt: Text prompt for the model

    Returns:
        Recognized text from the image
    """
    processor, model = load_model()

    messages = [
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "image": image
                },
                {
                    "type": "text",
                    "text": prompt
                }
            ],
        }
    ]

    inputs = processor.apply_chat_template(
        messages,
        tokenize=True,
        add_generation_prompt=True,
        return_dict=True,
        return_tensors="pt"
    ).to(model.device)

    inputs.pop("token_type_ids", None)
    generated_ids = model.generate(**inputs, max_new_tokens=1024)
    output_text = processor.decode(
        generated_ids[0][inputs["input_ids"].shape[1]:],
        skip_special_tokens=True
    )

    return output_text

# Create Gradio interface
with gr.Blocks(title="GLM-OCR") as demo:
    gr.Markdown("# GLM-OCR テキスト認識")
    gr.Markdown("画像をアップロードしてテキストを認識します。")

    with gr.Row():
        with gr.Column():
            image_input = gr.Image(type="pil", label="画像をアップロード")
            prompt_input = gr.Dropdown(
                choices=[
                    ("テキスト認識", "Text Recognition:"),
                    ("数式認識", "Formula Recognition:"),
                    ("表認識", "Table Recognition:")
                ],
                value="Text Recognition:",
                label="認識タイプ"
            )
            submit_btn = gr.Button("認識する", variant="primary")

        with gr.Column():
            output_text = gr.Textbox(label="認識結果", lines=15)

    submit_btn.click(
        fn=recognize_text,
        inputs=[image_input, prompt_input],
        outputs=output_text
    )

if __name__ == "__main__":
    demo.launch()

実行画面