モデル別実行レシピ

OCRなしでPDFページを探すColPali・ColQwenガイド

ページ画像の視覚表現を検索し、文字抽出は別のツールで行います。

ColPaliはPDFページの画像を受け取り、ページごとの多ベクトル表現を作成して、質問に合うページを検索します。表の配置などの視覚情報も検索の手掛かりになります。

実行条件と要点
  • 視覚表現でPDFページを検索します。
  • ページ検索と文字抽出は別の作業です。

ページ自体を検索対象にします

ColPaliはPDFページの画像を受け取り、ページごとの多ベクトル表現を作成して、質問に合うページを検索します。表の配置などページ上の見た目も手掛かりにできるため、OCR1で抽出したテキストだけを検索する方法よりレイアウトを活用できます。

文書群から「3つ目の表にある保証期間」のような質問を選び、根拠のあるPDFページを先に記録します。検索はページ候補を絞る段階で、最終回答を生成する処理ではありません。

スキャンPDFから文字が抽出される様子
ページ構成や表が検索の手掛かりになります。

検索と抽出を分けて評価します

検索は正解ページが上位k件に入る割合で評価し、OCRは文字誤り率や項目精度で別に測ります。ページを見つけても、セル境界・読み順・小さな文字が正しく抽出されたとは限りません。

同じPDFでColPaliとColQwenを比較し、ページID・順位・検索時間を保存します。必要な表や文章は原本で確認し、引用用テキストはOCRや文書パーサーで抽出します。

長文書が文脈を重ねたチャンクに分割された様子
検索したページは原文と照合します。

索引容量とページ描画のコストを確認します

このcodeはlayoutや表を手がかりに候補ページを検索します。ColPaliとColQwenを比べる場合は、同じPDF・質問・正解ページ・描画条件を両modelに適用して結果を集めます。

検索例はページ番号とscoreをJSONで返します。OCR文字精度やfield抽出品質は別のparser実験で確認します。

表から数字を一つ取り出す作業が中心なら、ページ検索モデルを先に入れる必要はありません。文書が数枚しかない、またはOCRテキストがすでに整っているなら、まずキーワード検索と文書パーサーで試してください。

PDF描画とColPali multi-vector APIを入れます
python -m venv .venv
source .venv/bin/activate
python -m pip install -U 'sentence-transformers[image]>=6.0.0' pymupdf pillow
make_report.py — サンプルPDFを作成
import fitz

doc = fitz.open()
page = doc.new_page(width=595, height=842)
page.insert_text((72, 90), "Product comparison", fontsize=20)
page.insert_text((72, 150), "Model | Warranty", fontsize=13)
page.insert_text((72, 185), "Atlas | 2 years", fontsize=12)
page.insert_text((72, 220), "Nova | 1 year", fontsize=12)
page2 = doc.new_page(width=595, height=842)
page2.insert_text((72, 90), "Support contacts", fontsize=20)
page2.insert_text((72, 150), "Email: help@example.test", fontsize=12)
doc.save("report.pdf")
print("saved report.pdf")
`make_report.py`として保存して実行します。この合成PDFはpipeline確認用の入力です。
colpali_search.py — 最大20ページを検索してJSON出力
import fitz, json, time
from PIL import Image
from sentence_transformers import MultiVectorEncoder

pdf_path = "report.pdf"
query = "Which page shows the warranty period in the comparison table?"
model = MultiVectorEncoder("vidore/colqwen2.5-v0.2")
page_images = []
start = time.perf_counter()
with fitz.open(pdf_path) as pdf:
    for page_number in range(1, min(len(pdf), 20) + 1):
        page = pdf[page_number - 1]
        pix = page.get_pixmap(matrix=fitz.Matrix(1.5, 1.5), alpha=False)
        image = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
        page_images.append((page_number, image))
query_vectors = model.encode_query([query])
page_vectors = model.encode_document([image for _, image in page_images])
scores = model.similarity(query_vectors, page_vectors)[0]
ranked = scores.argsort(descending=True).tolist()[:5]
print(json.dumps({"query": query, "pages_rendered": len(page_images), "elapsed_s": round(time.perf_counter() - start, 3), "top_pages": [{"page": page_images[i][0], "score": float(scores[i])} for i in ranked]}, indent=2))
`colpali_search.py`として保存します。先頭から最大20ページを描画します。
PDFを作成して検索
python make_report.py
python colpali_search.py
初回にweightをdownloadし、上位ページをJSON出力します。
検索の問題を抽出テキストと段落順で確認する様子
検索と抽出・索引を分けて記録します。

用語の注釈

  1. OCR — 画像やスキャン文書の文字を認識してテキストにする処理です。表の配置や読み順は、元の画像を合わせて確認する必要があります。

    本文に戻る

よくある質問

この記事で最初に確認すべきことは何ですか?
ColPaliはPDFページの画像を受け取り、ページごとの多ベクトル表現を作成して、質問に合うページを検索します。表の配置などの視覚情報も検索の手掛かりになります。