How to Fine-Tune olmOCR Models: A Complete Technical Guide
Fine-tuning olmOCR models requires preparing directories of single-page PDFs with matching Markdown files (containing YAML front-matter), configuring a YAML training file with LoRA settings, and executing the training pipeline followed by checkpoint merging for vLLM compatibility.
The olmOCR repository by AllenAI provides a production-grade framework for fine-tuning multimodal vision-language models on document understanding tasks. To successfully fine-tune olmOCR models, you must follow a specific data format and pipeline architecture that handles PDF rendering, document anchoring, and ChatML-style prompt generation. This guide explains the exact file structures, source code components, and commands used in the official training implementation.
Data Preparation Requirements
The training pipeline expects a strict pairing between PDF documents and Markdown annotation files.
Directory Structure
Create a directory where each single-page PDF has a corresponding .md file with the same base name:
data/
├── doc001.pdf # single-page PDF
├── doc001.md # markdown with YAML front-matter
├── doc002.pdf
└── doc002.md
Critical constraint: Each PDF must contain exactly one page. The validate_pdf_pair function (lines 42-70 in olmocr/train/dataloader.py) enforces this validation during dataset initialization and will reject multi-page documents.
Markdown Format
Each .md file must begin with a YAML front-matter block containing document metadata followed by the extracted text:
---
primary_language: en
is_rotation_valid: True
rotation_correction: 0
is_table: False
is_diagram: False
---
Document text goes here extracted from the PDF...
Generating Training Datasets
For large-scale dataset preparation, use the provided helper script to download and split the public olmOCR-mix dataset:
python -m olmocr.data.prepare_olmocrmix \
--dataset-path allenai/olmOCR-mix-1025 \
--destination ~/olmOCR-mix-1025-extracted \
--subset 00_documents --split train
This script handles the conversion of multi-page documents into the required single-page format.
Configuration Setup
Training behavior is controlled through YAML configuration files parsed by olmocr.train.config.Config.from_yaml (implemented in olmocr/train/config.py).
Start with the official fine-tuning template:
project_name: olmocr-finetune
run_name: custom-domain
model:
name: allenai/olmOCR-2-7B-1025
trust_remote_code: true
torch_dtype: bfloat16
use_flash_attention: true
attn_implementation: flash_attention_2
use_lora: true # Enable LoRA for efficient fine-tuning
lora_rank: 8
lora_alpha: 32
lora_dropout: 0.1
lora_target_modules: [q_proj, v_proj, k_proj, o_proj]
dataset:
train:
- name: custom_data
root_dir: ./data # Path to your PDF/MD pairs
pipeline: &basic
- name: FrontMatterParser
front_matter_class: PageResponse
- name: PDFRenderer
target_longest_image_dim: 1024
- name: StaticLengthDocumentAnchoring
target_anchor_text_len: 4000
- name: NewYamlFinetuningPromptWithNoAnchoring
- name: FrontMatterOutputFormat
- name: InstructUserMessages
prompt_first: true
- name: Tokenizer
masking_index: -100
end_of_message_token: "<|tool_call_end|>"
training:
output_dir: ./checkpoints
num_train_epochs: 3
per_device_train_batch_size: 1
gradient_accumulation_steps: 4
learning_rate: 2e-5
collator_max_token_len: 8192
Key configuration fields:
- **
model.use_lora**: Set totrueto train adapter weights instead of full model parameters - **
dataset.train[*].root_dir**: Absolute or relative path to your prepared data folder - **
pipeline**: Ordered list of transformation steps executed byMarkdownPDFDocumentDataset
Running the Training Pipeline
Installation
Install the training dependencies with specific version constraints:
pip install .[train] \
transformers==4.52.4 \
flash-attn>=2.8.0.post2 --no-build-isolation
Launching Training
Execute the training entry point located at olmocr/train/train.py:
python -m olmocr.train.train \
--config olmocr/train/configs/v0.4.0/qwen25_vl_olmocrv4_finetuning.yaml
The train.py script performs the following operations:
- Loads the processor using
AutoProcessor.from_pretrained - Instantiates
MarkdownPDFDocumentDatasetwhich walks the data folder, validates PDF/MD pairs, renders PDFs to images, and applies document anchoring - Builds ChatML-style messages through the pipeline steps defined in the config
- Initializes the Hugging Face
Trainerwith the configured LoRA adapter (if enabled) - Writes checkpoints to
training.output_dir
Pipeline Architecture
The MarkdownPDFDocumentDataset class (in olmocr/train/dataloader.py) orchestrates the data flow:
- FrontMatterParser: Extracts metadata from YAML headers
- PDFRenderer: Converts single-page PDFs to images at the specified resolution
- StaticLengthDocumentAnchoring: Applies spatial anchoring to text regions
- Tokenizer: Uses the Hugging Face
AutoProcessorto generateinput_ids,pixel_values,attention_mask, and maskedlabels(with-100for ignored tokens)
Post-Processing and Deployment
Merging LoRA Weights
If you trained with LoRA (use_lora: true), merge the adapter weights into the base model for vLLM compatibility:
python -m olmocr.train.prepare_checkpoint \
./checkpoints/checkpoint-1000 \
./merged_model
The prepare_checkpoint.py script loads the checkpoint, merges the LoRA matrices into the base model weights, and rewrites the model configuration to ensure compatibility with vLLM inference servers.
FP8 Quantization (Optional)
For optimized inference, convert the merged checkpoint to FP8 format:
python -m olmocr.train.compress_checkpoint \
--config olmocr/train/quantization_configs/qwen2_5vl_w8a8_fp8.yaml \
./merged_model \
./fp8_model
This utilizes torch.cuda.amp calibration to reduce memory footprint while maintaining OCR accuracy.
Serving with vLLM
After merging, serve the model using vLLM:
vllm serve ./merged_model --dtype bfloat16
Summary
- Data format: Single-page PDFs paired with Markdown files containing YAML front-matter, validated by
validate_pdf_pairinolmocr/train/dataloader.py - Configuration: YAML files define the model, LoRA parameters, and pipeline steps, parsed by
olmocr.train.config.Config.from_yaml - Training: Execute via
python -m olmocr.train.trainusing theMarkdownPDFDocumentDatasetpipeline to process documents through rendering, anchoring, and tokenization - Post-processing: Run
prepare_checkpoint.pyto merge LoRA weights and rewrite configs for vLLM compatibility - Optimization: Use
compress_checkpoint.pyfor optional FP8 quantization to reduce inference memory
Frequently Asked Questions
What is the exact data format required for fine-tuning olmOCR?
You must provide pairs of files: a single-page PDF and a matching .md Markdown file with identical base names. The Markdown file must contain a YAML front-matter block (delimited by ---) with fields like primary_language, is_rotation_valid, and rotation_correction, followed by the extracted document text. The validator in olmocr/train/dataloader.py enforces that each PDF contains exactly one page and rejects malformed pairs.
How does the training pipeline process documents?
The MarkdownPDFDocumentDataset class executes a sequential pipeline: it parses YAML front-matter, renders the PDF to an image using the PDFRenderer step, applies document anchoring via StaticLengthDocumentAnchoring, builds a ChatML-style prompt using functions from olmocr/prompts/prompts.py, and finally tokenizes the result using the Hugging Face AutoProcessor. This produces the input_ids, pixel_values, and masked labels required by the model.
Can I use full fine-tuning instead of LoRA?
Yes. Set model.use_lora: false in your configuration YAML. However, the repository defaults to LoRA (Low-Rank Adaptation) because it significantly reduces memory requirements and training time while maintaining performance. When using LoRA, you must run prepare_checkpoint.py after training to merge the adapter weights into the base model before serving with vLLM.
How do I prepare checkpoints for inference after training?
After training completes, use python -m olmocr.train.prepare_checkpoint <checkpoint_dir> <output_dir> to merge LoRA weights (if applicable) and rewrite the model configuration. This script ensures the checkpoint is compatible with vLLM and standard Hugging Face pipelines. For production deployment, you can optionally run compress_checkpoint.py to convert the model to FP8 format for faster inference and lower memory usage.
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 →