Instructions to use lightonai/LightOnOCR-2-1B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use lightonai/LightOnOCR-2-1B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="lightonai/LightOnOCR-2-1B") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForSeq2SeqLM processor = AutoProcessor.from_pretrained("lightonai/LightOnOCR-2-1B") model = AutoModelForSeq2SeqLM.from_pretrained("lightonai/LightOnOCR-2-1B", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use lightonai/LightOnOCR-2-1B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "lightonai/LightOnOCR-2-1B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "lightonai/LightOnOCR-2-1B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/lightonai/LightOnOCR-2-1B
- SGLang
How to use lightonai/LightOnOCR-2-1B with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "lightonai/LightOnOCR-2-1B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "lightonai/LightOnOCR-2-1B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "lightonai/LightOnOCR-2-1B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "lightonai/LightOnOCR-2-1B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use lightonai/LightOnOCR-2-1B with Docker Model Runner:
docker model run hf.co/lightonai/LightOnOCR-2-1B
Blank/uniform page produces a fabricated document instead of empty output (transformers path only)
On a completely blank page, LightOnOCR-2-1B does not return empty output — it deterministically generates a generic fake document (# Document Title / ## Section 1 / - Item 1 …), then degenerates into repeating $y = \sin(x)$ until it hits max_new_tokens. In my case that is 7,885 characters of pure fabrication for ~450 s of compute on a page containing nothing.
This matters in production document pipelines because blank pages are routine — separator sheets, backs of duplex scans — and the failure is silent: the output is plausibly structured markdown that downstream indexing will happily ingest.
Reproduction
No external files needed:
import torch
from PIL import Image
from transformers import LightOnOcrForConditionalGeneration, LightOnOcrProcessor
device, dtype = "cpu", torch.float32
model = LightOnOcrForConditionalGeneration.from_pretrained(
"lightonai/LightOnOCR-2-1B", dtype=dtype).to(device).eval()
processor = LightOnOcrProcessor.from_pretrained("lightonai/LightOnOCR-2-1B")
image = Image.new("RGB", (1090, 1540), "white") # a completely blank page
conversation = [{"role": "user", "content": [{"type": "image", "image": image}]}]
inputs = processor.apply_chat_template(conversation, add_generation_prompt=True,
tokenize=True, return_dict=True, return_tensors="pt")
inputs = {k: (v.to(device=device, dtype=dtype) if v.is_floating_point() else v.to(device))
for k, v in inputs.items()}
with torch.no_grad():
out = model.generate(**inputs, max_new_tokens=64, do_sample=False)
print(processor.decode(out[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True))
Actual:
# Document Title
## Section 1
### Subsection 1.1
- Item 1
- Item 2
- Item 3
...
Left to run, it continues into $y = \sin(x)$ repeated ~473×.
Expected: empty output, or the "no visible content" response the model already gives on nearly-blank pages (see below).
What I ruled out
| variant | result |
|---|---|
| transformers, image resized to 1540px longest side | fabricates |
| transformers, image at native size (no resize) | identical fabrication |
| transformers on CPU | fabricates |
| transformers on MPS | fabricates |
| llama.cpp GGUF Q4_K_M | ✅ correct refusal |
| llama.cpp GGUF F16 | ✅ correct refusal |
The F16 GGUF control is the interesting one: same weights, same precision, no quantization noise — and it correctly answers "There is no visible content in the provided image." Combined with the failure being device-independent and resize-independent, this looks like it sits in the transformers-side implementation rather than the weights — plausibly LightOnOcrProcessor's handling of a constant-valued image (a uniform image has zero variance, so normalization produces a degenerate input).
Any real content defeats it
Which supports that reading:
| input | output |
|---|---|
| pure white page | 7,885 chars fabricated |
| white + one line of text | ✅ reads the line correctly |
| white + faint noise (~0.1% of pixels) | ✅ "There is no visible content in the provided image" |
So the model has a correct refusal behaviour — it just isn't reached when the input is perfectly uniform.
Environment
- transformers 5.9.0, torch 2.12.0, Pillow 12.2.0
- Python 3.11.13, macOS 26.5.2 arm64; reproduced on both
cpuandmps attn_implementation: sdpa (default)- control: llama.cpp
b77d646, F16 + Q4_K_M GGUF converted from the same checkpoint
Workaround
For anyone hitting this: skip pages whose non-white pixel fraction is below ~1e-5 before calling the model. On my corpus that recovered ~14 minutes of wasted compute across two pages, with no false positives on real content.
Thanks for releasing the model — the German-language quality has been excellent in my testing, which is why this edge case stood out.
Hello,
Thanks for the feedback.
Empty pages are specifically handled, and in most cases the model correctly outputs nothing, though some edge cases remain. We’re actively working on improving this.
I also noticed you’re using quantized weights through llama.cpp, which in my testing tends to have more looping issues than vLLM and could be contributing here.