高い精度で高速にPDFをMarkdownへ変換する技術
(github.com/VikParuchuri)- MarkerはPDFだけでなく、画像、PPTX、DOCX、XLSX、HTML、EPUB文書をMarkdown、JSON、chunks、HTMLへ高速かつ高精度に変換するドキュメントインテリジェンスツール
- 表、フォーム、数式、インライン数式、リンク、参照、コードブロックを整形し、画像の抽出・保存とヘッダー/フッターのようなアーティファクト除去をサポート
- 精度を高めるには
--use_llmでLLMを併用でき、デフォルトはgemini-2.0-flashで、Gemini、Ollama、Claude、OpenAI、Azure OpenAIなどを選択可能 - ベンチマークではMarkerは単一PDFページ基準で平均2.83837秒、ヒューリスティックスコア95.6709、LLMスコア4.23916を記録し、H100のバッチモードでは25 pages/secondのスループットを見込む
- Python 3.10+とPyTorchが必要で、コードはGPL、モデル重みは修正版AI Pubs OpenRAIL-Mライセンスで、研究・個人利用・$2M未満のスタートアップには無料条件が適用される
Markerが変換する文書と出力
- Markerは文書をMarkdown、JSON、chunks、HTMLに変換する
- 入力形式はPDF、画像、PPTX、DOCX、XLSX、HTML、EPUBを含み、あらゆる言語の文書を処理する
- 文書要素の処理範囲:
- 表、フォーム、数式、インライン数式
- リンク、参照、コードブロック
- 画像の抽出と保存
- ヘッダー、フッター、その他のアーティファクト除去
- 独自のフォーマット処理とロジックで拡張できる
- JSONスキーマを与えると構造化抽出を実行でき、この機能はbeta
- GPU、CPU、MPSで動作する
Datalab管理プラットフォーム
- Datalab管理プラットフォームは最新のオープンソースモデル Chandra を実行する
- ChandraはMarkerより高い精度を提供すると紹介されており、デフォルトでデータ保持がなく、SOC 2 Type 2とカスタムBAAを提供する
- 大容量ワークロード向けのバッチ処理サービスは週あたり200M+ページを処理した実績がある
- 登録時に**$5の無料クレジット**を提供し、公開プレイグラウンドも用意されている
- 商用セルフホスティングにはライセンスが必要で、オンプレミスライセンスは別途問い合わせ対象
性能とLLMハイブリッドモード
- MarkerはLlamaparse、Mathpixのようなクラウドサービスや他のオープンソースツールに対して有利なベンチマーク結果を示している
- READMEの全性能結果は単一PDFページを直列実行した基準
- バッチモードではより高速で、H100では25 pages/secondのスループットが見込まれる
- 最高精度のために
--use_llmフラグでLLMを併用できる- ページをまたぐ表の結合
- インライン数式の処理
- 表フォーマットの改善
- フォームからの値抽出
- LLMハイブリッドモードはMarker単体またはGemini Flash単体より表ベンチマーク精度が高い
インストールと基本的な使い方
- Python 3.10+とPyTorchが必要
- PDF中心のインストール:
pip install marker-pdf - PDF以外の文書形式を処理するには追加依存関係をインストールする
pip install marker-pdf[full] - 単一ファイルの変換:
marker_single /path/to/file.pdf - フォルダ単位で複数ファイルを変換:
marker /path/to/input/folder - 複数GPUで変換:
NUM_DEVICES=4 NUM_WORKERS=15 marker_chunk_convert ../pdf_in ../md_outNUM_DEVICESは使用するGPU数で、2以上である必要があるNUM_WORKERSはGPUごとの並列プロセス数
主なCLIオプション
--page_range TEXT: 処理するページ番号と範囲を指定--output_format [markdown|json|html|chunks]: 出力形式を指定--output_dir PATH: 出力ファイル保存ディレクトリを指定--paginate_output: ページ番号と区切り線を入れて出力--use_llm: LLMで精度を向上--force_ocr: 文書全体にOCRを強制適用し、インライン数式も適切に整形--block_correction_prompt: LLMモードでMarker出力補正用プロンプトを指定--strip_existing_ocr: 既存OCRテキストを削除し、suryaで再OCR--redo_inline_math:--use_llmと併用してインライン数式変換品質を向上--disable_image_extraction: PDFから画像を抽出しない--converter_cls: 既定のmarker.converters.pdf.PdfConverterまたは表専用のmarker.converters.table.TableConverterを選択--llm_service:--use_llm使用時のLLMサービスを指定し、デフォルトはmarker.services.gemini.GoogleGeminiService--workers: 同時変換ワーカー数を指定- ワーカーあたり最大5GB VRAM、平均3.5GB VRAMを使用する
Python APIと内部ブロック操作
PdfConverterでPythonから直接変換できるfrom marker.converters.pdf import PdfConverter from marker.models import create_model_dict from marker.output import text_from_rendered converter = PdfConverter( artifact_dict=create_model_dict(), ) rendered = converter("FILEPATH") text, _, images = text_from_rendered(rendered)- Markdown出力の
renderedはmarkdown、metadata、images属性を持つ - JSON出力の
renderedはchildren、block_type、metadataを持つ ConfigParserで出力形式、プロセッサ、レンダラ、LLMサービスなどを構成できる- 文書はページとブロックのツリーで構成され、ページはさらにブロックを含められる
contained_blocksを使ってフォームのような特定ブロックだけをプログラム的に抽出できる
変換器の種類
PdfConverter: PDF全体を変換する基本コンバータTableConverter: 表だけを抽出して変換するforce_layout_block=Tableを指定するとレイアウト検出を避け、すべてのページを表とみなすoutput_format=jsonを使うとセルのbounding boxも取得できる
OCRConverter: OCRだけを実行する--keep_charsを設定すると個別文字とbounding boxを保持する
ExtractionConverter: beta状態の構造化抽出コンバータ- 先にLLMサービスの設定が必要
- JSON出力で抽出値を返す
- 前回実行の
original_markdownをexisting_markdownとして渡すと文書の再パースを省略できる
出力形式
- Markdown出力:
- 画像リンク
- 整形済みの表
$$で囲まれたLaTeX数式- triple backticksのコードブロック
- 脚注用の上付き文字
- HTML出力:
imgタグ画像<math>タグ数式preタグコード
- JSON出力:
- ページをリストで表し、各ページは内部Markerスキーマのブロック
id、block_type、html、polygon、childrenキーを持つ- 子ブロックは
section_hierarchy、imagesを追加で持つ - ブロック構造はツリー形式
- Chunks出力:
- JSONに似ているが、すべてを単一リストへ平坦化する
- 各ブロックの完全なHTMLを含み、RAG向けチャンキングに柔軟に使える
- すべての出力形式は
metadataを返す- 計算されたPDF目次である
table_of_contents - ページごとのテキスト抽出方式とブロック数を含む
page_stats
- 計算されたPDF目次である
対応LLMサービス
--use_llm使用時に選択できるサービス:- Gemini: デフォルトでGemini developer APIを使用し、
--gemini_api_keyが必要 - Google Vertex:
--vertex_project_idが必要で、marker.services.vertex.GoogleVertexServiceを指定 - Ollama: ローカルモデルを使用し、
--ollama_base_url、--ollama_modelを設定 - Claude:
--claude_api_key、--claude_model_nameを設定 - OpenAI: OpenAI互換エンドポイントをサポートし、
--openai_api_key、--openai_model、--openai_base_urlを設定 - Azure OpenAI:
--azure_endpoint、--azure_api_key、--deployment_nameを設定
- Gemini: デフォルトでGemini developer APIを使用し、
内部構造と拡張ポイント
- Markerはディープラーニングモデルのパイプラインとして動作する
- テキスト抽出、必要に応じてOCRを実行
- ページレイアウト検出と読み順検出
- 各ブロックの整形とフォーマット
- 必要に応じてLLMで品質改善
- ブロック結合と全文テキストの後処理
- OCRとレイアウト関連ステップには surya が使われる
- 数式関連の整形には texify が使われる
- 中核コンポーネント:
Providers: PDFのようなソースファイルから情報を提供するBuilders: 初期文書ブロックを作成し、テキストを埋めるProcessors: 表フォーマッタのように特定ブロックを処理するRenderers: ブロックを出力形式へレンダリングするSchema: すべてのブロック型のクラスConverters: 全体のend-to-endパイプラインを実行する
- 処理動作を変えるには
processorsを再定義する - 新しい出力形式は新しい
rendererを書いて追加する - 新しい入力形式は新しい
providerを書いて追加する
APIサーバーとデプロイ
- シンプルなFastAPIサーバーを起動できる
pip install -U uvicorn fastapi python-multipart marker_server --port 8001 - サーバーは
localhost:8001でアクセスでき、localhost:8001/docsでendpointオプションを確認できる - このAPIサーバーは堅牢なAPIではなく、小規模利用のみを想定している
- より堅牢な変換オプションが必要ならホスト型の Datalab API を利用できる
- デプロイ例にはModal経由のWebエンドポイント配備が含まれる
トラブルシューティング
- 精度に問題がある場合は
--use_llmでLLMを使う- この場合、Gemini APIキーを
GOOGLE_API_KEYとして設定する必要がある
- この場合、Gemini APIキーを
- 文字化けしたテキストが見える場合は
force_ocrで文書を再OCRする TORCH_DEVICEで使用するtorchデバイスを強制指定できる- メモリ不足エラーが出る場合はワーカー数を減らすか、長いPDFを複数ファイルに分割できる
debugオプションは、検出されたレイアウトとテキストを含むページ画像、bounding box情報を持つJSONファイルを保存する
ベンチマーク結果
- 全PDF変換ベンチマークはcommon crawlから単一PDFページを抽出して作成した benchmark set を使用する
- スコアはground truthテキストセグメントとの整列ヒューリスティックと、LLM-as-judge方式で計算される
- 全PDF変換結果:
- marker: 平均時間2.83837、ヒューリスティック95.6709、LLM 4.23916
- llamaparse: 平均時間23.348、ヒューリスティック84.2442、LLM 3.97619
- mathpix: 平均時間6.36223、ヒューリスティック86.4281、LLM 4.15626
- docling: 平均時間3.69949、ヒューリスティック86.7073、LLM 3.70429
- markerとdoclingはH100で実行され、llamaparseとmathpixはクラウドサービスを使用する
- 長いPDF処理スループットベンチマークには Think Python を使用する
- marker: ページあたり0.18秒
- 文書あたり43.42秒
- VRAM 3.17GB
- H100で22個の個別プロセスを実行でき、122 pages/secondのスループットが見込まれる
- 表変換ベンチマークは FinTabNet test splitのHTML表現を比較する
- marker: 平均スコア0.816、合計99 tables
- marker w/use_llm: 平均スコア0.907、合計99 tables
- gemini: 平均スコア0.829、合計99 tables
- FinTabNetとレイアウトモデルの検出方式の違いにより、ground truthと整列できない表はフィルタリングする
制限事項とライセンス
- PDFは扱いが難しい形式であり、Markerが常に完璧に動作するわけではない
- 既知の制限:
- ネストした表やフォームを含む非常に複雑なレイアウトでは動作しない可能性がある
- フォームのレンダリングがうまくいかない場合がある
--use_llmと--force_ocrフラグを渡すことで、こうした問題の大半を解決できる- モデル重みは修正版AI Pubs OpenRAIL-Mライセンスを使用する
- 研究、個人利用、funding/revenueが$2M未満のスタートアップには無料
- コードはGPLライセンス
- より広い商用ライセンスやGPL要件の除去は pricing page が対象
1件のコメント
Hacker Newsのコメント
リポジトリ全体で Nougatと比較しているやり方は少し分かりにくい
Nougatは学術文書向けに特化して学習されたモデルであり、Nougatが最高のOCRモデルだと主張されたことはないと思う。ベンチマークでもarXiv文書ではNougatの精度のほうが高いとされている。また、markerはNougatより数式の変換が少ないと言いながら速度比較をNougatと行うのも、学術文書向けモデルである点を考えると惜しい
数学を含むPDFをOCRするなら、Nougatはぜひ試す価値がある。Pythonパッケージとして簡単にインストールでき、1つのコマンドで数式・テキスト・表などを
.mmdファイルに抽出する。個人用途なら速度も悪くなく、4年前のi5ノートPCでCPUだけを使って6ページの文書を変換するのに約30秒かかった新しいツールを、なじみのある対象と並べて見るための方法にすぎない。言うとおりNougatはインストールも実行も簡単なので、比較対象にするのは自然だ。比較にもっと多くのライブラリが入れば、当然さらに良く有用になるだろう
RPG本の一部をMarkdownに移すのに役立つOCRモデルを探している。できれば太字や斜体のような強調もそのまま移ってほしい
テキスト、数字、数学記号の組み合わせは技術・学術文書に似て見えるが、変わった書式、余白のテキストボックス、多くの図表が頻繁に混ざっている
下のほうには単純なテキスト抽出との比較も置いてある。Nougatは優れたモデルで、多くのPDFをうまく変換するが、より速く、より汎用化できるものが欲しかった
こうしたツールの影響を過小評価してはいけない。「読むには良いが配布には悪い」形式に閉じ込められた膨大な知識を解き放つことだからだ
本当に期待している。パイプラインを作れるといい:すべてのPDF → 全部Markdownに変換 → 全部archive.orgに保存
こうすれば、バグが修正され改善が入るたびに変換を再実行できる。通常、記録保存では元資料にできるだけ近い形で保存することが好まれる。その後のあらゆる変換はデータ損失を生むだけだからだ
エンドユーザーが見る文書を生成するのに使った生データを、望む形式で見えないように埋め込める。たとえばPrinceXMLでHTMLをレンダリングしてPDFを作るなら、すべてのテキスト・グラフ・チャートなどを生成するのに使った元のJSONをPDF内に入れられる。もちろん大半は実際にはそうしていないが、それは仕様のせいではない
https://github.com/VikParuchuri/libgen_to_txtも参考になる。まだmarkerとは統合しておらず、現時点では単純なテキスト抽出を使っている
ニーズやユースケースの一部だけを扱うとしても、きちんと動くなら非常に有用だろう
PDFのアクセシビリティをきちんと整えるのは膨大な作業であり、たとえ整えても、ユーザーが使うPDFビューアが必要な標準をサポートしていない可能性が高い
週末に自分で試してみたい
選択可能なテキストがないようにOCRされていない、あるいはOCRされていても品質が良くない、出所不明の RPG PDFスキャンを手でよく書き起こしている
コピー&ペーストの誤りを直したり、OCRでテキスト化した後に誤りを直したりするより、文字どおり自分で入力したほうが速いことがある
公式PDFであっても書式がよく崩れて、単語間に二重・三重スペースやタブが入ることがある。まともに使えるなら、本当に多くの時間を節約してくれそうだ
表とテキストボックスがかなり崩れた。表をスクリーンショットに撮ってChatGPTに貼り付け、Markdown表への変換をさせるとかなり良い結果が出た。「行ごとに読め。列見出しはX、Y、Zだ。Xはテキスト、Yは数字、Zは単語だ」のように少しプロンプトを与えると、不規則な表も処理できた
最近の Tesseract OCR はどの程度まともなのだろう? 以前使ったときは、AWS、Azure、GCPのオンラインOCRよりかなり劣っていた
https://github.com/tesseract-ocr/tesseract/releases
結局はユースケース次第だろう。こうした個人作業には十分な可能性が高く、ユーザー情報やクレジットカードのようなものも不要だ
ただし解像度には非常に敏感だ。画像があるサイズ以下に下がると、人間には十分読めるのにTesseractの出力はめちゃくちゃになった
iOS Vision APIも試したが、やはり失敗した。テストケースは本のページを鮮明に撮った写真だった
作者への質問: なぜ Markdown なのか? このツールの難しい部分は PDF を高精度に解析することであって、その後どの形式で出力するかではないように思う
なので、ユーザーが出力形式を選べるとよさそう。高精度な PDF パーサーがあるなら、EPUB 生成に使いたい
大学出版局で電子書籍を管理しているが、変換待ちの古いリストがたくさんあり、その多くは古い印刷本のページスキャンしか残っていない。EPUB として提供するには、章区切り、タイトル、表、チャート、数式、引用文などがどこにあるかを把握する必要がある。外部業者に頼むことはできるが、本によっては販売収益より変換費用のほうが高い。一部でも自分たちでできると助かる
ただしここでは Markdown が中間形式として使われているように見える。プレーンテキストに近いが、単純なレイアウト情報は保持できる。実際には Markdown 出力を受け取り、望む最終出力形式に変換するツールにつないで使うことになりそう
数式は
$/$$で囲める。EPUB 出力はまだ見ていないが、こうした要件のためにプレーンテキストは除外されたまだよい解決策を見つけられていない特殊な用途がある: 建設文書の読解
図面はいつも PDF で届くが、DXF(AutoCAD)ファイルを解析したときのほうがはるかにうまくいった。ただ、自分が現場の総括施工者であっても、建築家に DXF を送ってほしいと頼んで受け取るのは必ずしも簡単ではない
長い文章は主に電子書籍リーダーで読んでいる
PDF、特に段組みレイアウトは、Amazon Kindle や Pocketbook の標準機能では悪夢に近い。このツールは読書体験をかなり改善してくれそう
よい取り組み
Nougat の出力に見られるハルシネーションがどこから来るのか気になっていた。Think Python の例にある Nougat 出力をざっと見ると、何を言っているのか分かる
見直すと LLM を通すと書かれているので、ハルシネーションは予想できることだった
その水準はほぼ 0 に近く、用途によっては実際に 0 でなければならないかもしれない。正確な文書内容が重要でない場合なら概ね問題ないだろうが、現在も将来も誰にとっても重要ではない一方で、PDF よりアクセシビリティを高める必要がある文書が大量に存在するケースは、あまり多くないと思う
OneNote から自分のノートを移行するのに役立ちそうなツールに見える
https://help.obsidian.md/import/onenote
かなり興味深い。repo に変換前後の例をいくつか追加するとよさそう
どの種類の PDF に合わせて調整しているのか気になる。手書き注釈はどう処理するのだろうか?