How to Run the olmOCR OCR Process: Complete Guide to PDF-to-Markdown Conversion
To run the olmOCR OCR process, install the package with GPU support, then execute olmocr <workspace> --pdfs <paths> to launch a local VLLM server that converts scanned PDFs into clean Markdown and Dolma-compatible JSONL using the allenai/olmOCR-2-7B-1025-FP8 vision-language model.
The allenai/olmocr open-source repository provides a production-ready pipeline for extracting text from image-based documents. This guide covers how to run the olmOCR OCR process on a single machine, connect to remote inference servers, and scale across distributed workers using cloud storage.
Prerequisites and Installation
Before running the pipeline, install system libraries for PDF rendering and font handling.
# Ubuntu/Debian dependencies
sudo apt-get update && sudo apt-get install -y \
poppler-utils ttf-mscorefonts-installer \
msttcorefonts fonts-crosextra-caladea \
fonts-crosextra-carlito gsfonts lcdf-typetools
Create a Python environment and install olmOCR with GPU extras. The [gpu] flag installs PyTorch, FlashInfer, and CUDA dependencies required for local inference.
conda create -n olmocr python=3.11
conda activate olmocr
pip install "olmocr[gpu]" --extra-index-url https://download.pytorch.org/whl/cu128
# Optional: Install FlashInfer for faster inference
pip install https://download.pytorch.org/whl/cu128/flashinfer/flashinfer_python-0.2.5%2Bcu128torch2.7-cp38-abi3-linux_x86_64.whl
Basic Local Execution
The primary entry point is the olmocr CLI, which wraps python -m olmocr.pipeline. You must specify a workspace directory (for intermediate files and outputs) and one or more PDF paths (glob patterns supported).
olmocr ./my_workspace \
--markdown \
--pdfs ./document.pdf \
--model allenai/olmOCR-2-7B-1025-FP8 \
--workers 8
When executed, olmocr/pipeline.py performs the following initialization sequence:
- Parses CLI arguments and validates the workspace path
- Downloads the vision-language model via
download_model()to a local cache - Starts a VLLM server subprocess (
vllm_server_host) on an available GPU - Instantiates a
WorkQueueto track PDF processing status - Spawns an asynchronous worker pool (default 20 workers) that consumes items from the queue
Core Pipeline Architecture
Understanding the internal components helps optimize throughput and debug failures.
WorkQueue and Job Distribution
The WorkQueue class in olmocr/work_queue.py manages parallel execution across local filesystems or S3. It splits input PDFs into work items (configurable via --pages_per_group) and tracks completion via atomic lock files.
- LocalBackend: Uses filesystem-based locking with
.lockfiles - S3Backend: Uses S3 object metadata for distributed locking across machines
The queue writes a compressed index to work_index_list.csv.zstd in the workspace, enabling workers to resume interrupted jobs.
Main Orchestration Logic
The main() function in olmocr/pipeline.py coordinates the end-to-end flow. For each PDF assigned to a worker, it calls process_pdf(), which delegates to process_single_pdf() for page-level processing.
Key functions in the orchestration chain:
process_pdf(): Handles PDF download (if S3) and page groupingprocess_single_pdf(): Iterates through pages and callsprocess_page()asynchronouslybuild_dolma_document(): Stitches page results into a JSONL document with metadata fields including language detection, rotation angles, and table flagsget_markdown_path(): Generates.mdoutput paths mirroring the source PDF hierarchy when--markdownis enabled
Page Processing and VLLM Integration
Each page flows through process_page() in olmocr/pipeline.py:
- Render:
render_pdf_to_base64png()(fromolmocr/data/renderpdf.py) converts the PDF page to a base64-encoded PNG - Prompt:
build_page_query()constructs a VLLM request usingbuild_no_anchoring_v4_yaml_promptwith the image as a vision input - Inference:
apost()sends an HTTP POST to the VLLM server (or remote endpoint) using a lightweight async socket client (avoidingaiohttpdependencies) - Parse: The response YAML front-matter is parsed into a
PageResponseobject containing extracted text, confidence scores, and rotation metadata - Retry: On transient errors or rotation mismatches, the system retries with exponential backoff (configurable via
--max_page_retries, default 8)
If the model fails repeatedly, make_fallback_result() triggers a pure pdftotext extraction via get_anchor_text() to ensure deterministic output.
Using Remote Inference Servers
To run olmOCR without local GPUs, use the --server flag to point to any OpenAI-compatible endpoint (vLLM, DeepInfra, or Cirrascale).
olmocr ./my_workspace \
--markdown \
--pdfs ./document.pdf \
--server http://my-vllm:8000/v1 \
--model allenai/olmOCR-2-7B-1025-FP8 \
--workers 16
When --server is provided, the pipeline skips vllm_server_host initialization and delegates all inference to the remote URL. This mode requires no CUDA libraries on the local machine.
Scaling with S3 and Distributed Workers
For large-scale processing, specify an S3 URI as the workspace and use the --beaker flag to submit jobs to AI2's Beaker cluster.
olmocr s3://my-bucket/workspaces/ocr_run \
--pdfs s3://my-bucket/pdfs/*.pdf \
--workers 20 \
--beaker \
--beaker_gpus 4 \
--beaker_cluster ai2/allennlp
Execution flow with S3:
- The first worker populates the queue by writing
work_index_list.csv.zstdto the S3 prefix - Workers acquire locks by writing flag objects to S3
- Each worker downloads PDFs to local temp space, processes them, and uploads results to
s3://bucket/workspaces/ocr_run/results/ - Final Markdown files appear under
s3://bucket/workspaces/ocr_run/markdown/
The submit_beaker_job function (see pipeline.py line 291) creates a Docker-based experiment using the official jakep/olmocr-inference image.
Output Formats and Verification
The pipeline produces two primary outputs in the workspace directory:
- Dolma JSONL: Located in
results/, each line contains a document withid,text,metadata(rotation, language), andattributes(page spans). Generated bybuild_dolma_document(). - Markdown: When
--markdownis set,.mdfiles are written tomarkdown/with the same relative path structure as the source PDFs, determined byget_markdown_path().
Verify output with:
cat my_workspace/markdown/document.md
# or
zcat my_workspace/results/documents.jsonl.zstd | head -1 | jq .
Summary
- Installation: Install system fonts, poppler-utils, and
olmocr[gpu]via pip - Local execution: Run
olmocr <workspace> --pdfs <paths>to start a VLLM server and process PDFs with 20 parallel workers by default - Architecture: The
WorkQueueinolmocr/work_queue.pymanages job distribution, whileolmocr/pipeline.pyhandles VLLM orchestration and page-level processing - Fallbacks: If the vision model fails,
make_fallback_result()inpipeline.pyextracts text usingpdftotext - Remote mode: Use
--serverto connect to external vLLM instances without local GPU requirements - Distributed scaling: Use S3 workspaces with
--beakerfor cloud-based processing across multiple nodes
Frequently Asked Questions
What hardware is required to run olmOCR locally?
Running olmOCR locally requires a CUDA-capable GPU with sufficient VRAM to load the allenai/olmOCR-2-7B-1025-FP8 model. The pipeline automatically starts a VLLM server using vllm_server_host in olmocr/pipeline.py, which manages GPU memory and batching. For CPU-only environments, use the --server flag to connect to a remote inference endpoint.
How does olmOCR handle multi-page PDFs?
The process_single_pdf() function in olmocr/pipeline.py splits PDFs into individual pages, rendering each to PNG via render_pdf_to_base64png(). Pages are processed asynchronously by the worker pool, and build_dolma_document() reassembles them into a single output document. The --pages_per_group flag controls how many pages constitute a single work item in the queue.
Can I process PDFs without installing GPU drivers?
Yes. By specifying --server http://remote-url/v1, you can run the olmOCR OCR process on a CPU-only machine. The pipeline delegates all inference to the remote endpoint and skips the local VLLM server initialization. Ensure you set --workers appropriately to match the remote server's capacity.
What happens when the model fails to recognize a page?
The process_page() function implements retry logic with exponential backoff for transient network errors. If the model returns invalid YAML or exceeds --max_page_retries (default 8), the pipeline calls make_fallback_result() to extract text using pdftotext via get_anchor_text(). This ensures every page produces output, even if the vision model encounters unreadable scans.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →