powered by TechFeed
表示モード
Deep Dive

PDFや図表をテキスト抽出せず「画像のまま」検索するRAGパイプライン — 表・グラフの情報損失をアーキテクチャレベルで回避する「PixelRAG」

8月4日、MarkTechPostが「Pixel-Native RAG: A Practical Guide to Visual Document Indexing」と題した記事を公開した。この記事では、テキスト抽出に頼らず、WebページやPDFをそのまま画像としてインデックス化するRAGパイプラインを一から構築する方法について詳しく紹介されている。なお、本紹介記事中で用いている「PixelRAG」という呼称は元記事には登場しない名称だが、パイプラインの特徴を端的に示すものとして使用している。

8月4日、MarkTechPostが「Pixel-Native RAG: A Practical Guide to Visual Document Indexing」と題した記事を公開した。この記事では、テキスト抽出に頼らず、WebページやPDFをそのまま画像としてインデックス化するRAGパイプラインを一から構築する方法について詳しく紹介されている。なお、本紹介記事中で用いている「PixelRAG」という呼称は元記事には登場しない名称だが、パイプラインの特徴を端的に示すものとして使用している。


テキスト抽出を捨てる——「画素」を直接インデックスする

従来のRAG(Retrieval-Augmented Generation)では、PDFやWebページからテキストを抽出し、チャンクに分割してベクトル化するのが定石だ。しかしこのアプローチには根本的な制約がある——表・図・グラフ・手書き文字など、視覚情報として意味を持つコンテンツがテキスト抽出の時点で失われる

本記事で紹介されるPixelRAGは、この問題をアーキテクチャレベルで回避する。HTMLパース・テキスト抽出・固定チャンク戦略を一切使わず、ドキュメント全体を画像として扱い、その画像タイルに対してマルチモーダル埋め込みを生成する構成だ。


パイプラインの全体像

構成要素は以下の通りだ:

  • レンダリング: PlaywrightのChromiumでWebページをスクリーンショット化、PyMuPDFでPDFをラスタライズ
  • タイリング: 1024×1024px、128pxオーバーラップのスライディングウィンドウで垂直分割
  • 埋め込み: SigLIP(Googleが提案した画像言語対照学習モデル。CLIPの改良版にあたり、シグモイドロスを用いた学習が特徴)、CLIP、またはQwen3-VL-Embedding(Qwenシリーズのビジョン言語モデルをベースとしたマルチモーダル埋め込みモデル)バックエンドでマルチモーダルベクトルを生成
  • インデックス: FAISSでベクトル検索(データ量に応じてIVFに自動切り替え)
  • ハイブリッド検索: TesseractによるOCR + BM25スコアリング + Reciprocal Rank Fusion(RRF)で精度を強化
  • 提供: FastAPIでサーチAPIとして公開

評価指標にはRecall@kとMean Reciprocal Rank(MRR)を使用する。また、軽量なResidualアダプターをContrastive Learning(対照学習)で追加学習する仕組みも含まれており、ドメイン固有の視覚表現に埋め込みモデルを適応させる手段として位置づけられている。事前学習済みの埋め込みモデルを凍結したまま、小規模なアダプター層だけを正例・負例のペアで学習させることで、大規模な再学習なしにドメイン特化の検索精度向上を狙う設計だ。


タイリングが肝——空白除去と重複排除

パイプラインの核心はタイル生成ロジックだ。単純に均等分割するのではなく、以下の工夫が入っている。

空白タイルの排除:ピクセル輝度の標準偏差が閾値(blank_std_threshold: 6.0)を下回るタイルはGPUに渡す前に除外される。白紙ページや余白が多いドキュメントでベクトル空間を汚染しない。

重複タイルの除去:64ビットのAverage Hash(aHash)でタイルをフィンガープリントし、ハミング距離が4以下のものを重複として排除する。ヘッダー・フッターがページをまたいで繰り返されるケースを想定した処理だ。

def _is_informative(img, cfg: Config) -> bool:
    import numpy as np
    a = np.asarray(img.convert("L"), dtype="float32")
    return float(a.std()) >= cfg.blank_std_threshold

def _hamming(a: int, b: int) -> int:
    return bin(a ^ b).count("1")

Webページのレンダリングには、スクロールによる遅延ロードコンテンツの取得、fixed/sticky要素のabsolute化、クッキーバナー除去、アニメーション無効化といったJavaScript前処理も含まれており、「見た目通りのスナップショット」を確実に取得する設計になっている。


ハイブリッド検索:密ベクトル × BM25 × RRF

密ベクトル検索だけではOCRテキストの完全一致に弱い。そこでTesseractでタイルからテキストを抽出し、BM25(rank-bm25)によるスパース検索スコアと組み合わせる。

RRF(Reciprocal Rank Fusion)は両スコアを以下の式で統合する:

score = dense_weight / (k + dense_rank) + sparse_weight / (k + sparse_rank)

デフォルトはrrf_k=60dense_weight=1.0sparse_weight=1.0の均等配分だ。タイルレベルの検索結果は最終的にドキュメントレベルに集約されて返却される。


評価クエリと設定の概要

記事ではWikipediaの5ページ(RAG、ベクトルデータベース、Transformer、光合成、デリー)をデモ対象として使用し、以下のような評価クエリでRecall@kを測定している:

クエリ 期待ドキュメント
how do plants convert sunlight into chemical energy Photosynthesis
self-attention multi-head architecture Transformer
approximate nearest neighbour search over embeddings Vector_database
grounding a language model with retrieved documents Retrieval-augmented

主要な設定パラメータはConfigデータクラスで一元管理されており、バックエンドの切り替え(backend: "siglip" / "clip" / "qwen3vl")やVLMによる回答生成(enable_vlm_answer)もフラグ一つで制御できる。VLMバックエンドにはQwen/Qwen2.5-VL-3B-Instructを使用可能だ。


動かすために必要なもの

依存ライブラリは初回実行時に自動インストールされる設計で、Google Colabでの動作を明示的に考慮している。Colabの既存イベントループとPlaywrightの競合を避けるため、専用スレッドに新しいイベントループを立てて非同期コルーチンを実行するヘルパー(run_async)が用意されている点は実装上の注意点だ。

主要な依存関係:playwrightfaiss-cpupymupdftransformerspytesseractrank-bm25fastapiuvicorn

GitHubリポジトリは元記事記載のStarTrail-org/PixelRAGで公開されている。


詳細はPixel-Native RAG: A Practical Guide to Visual Document Indexingを参照していただきたい。