|
| 1 | +<!--Copyright 2026 the HuggingFace Team. All rights reserved. |
| 2 | +
|
| 3 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +you may not use this file except in compliance with the License. |
| 5 | +You may obtain a copy of the License at |
| 6 | +
|
| 7 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +
|
| 9 | +Unless required by applicable law or agreed to in writing, software |
| 10 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +See the License for the specific language governing permissions and |
| 13 | +limitations under the License. |
| 14 | +
|
| 15 | +
|
| 16 | +⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be rendered properly in your Markdown viewer. |
| 17 | +
|
| 18 | +--> |
| 19 | +*This model was published in HF papers on 2026-06-23 and contributed to Hugging Face Transformers on 2026-10-14.* |
| 20 | + |
| 21 | + |
| 22 | +# UnlimitedOcr |
| 23 | + |
| 24 | +## Overview |
| 25 | + |
| 26 | +The UnlimitedOcr model was proposed in [Unlimited OCR Works](https://huggingface.co/papers/2606.23050) by Youyang Yin, Huanhuan Liu, Qunyi Xie, Chaorun Liu, Shiqi Yang, Shaohua Wang, Zhanlong Liu, Hao Zou, Jinyue Chen, Shu Wei, Jingjing Wu, Mingxin Huang, Zhen Wu, Guibin Wang, Tengyu Du, and Lei Jia from Baidu Inc. |
| 27 | + |
| 28 | +It is a single 3B parameter model with a standard context length of 32,768 tokens. |
| 29 | + |
| 30 | +The abstract from the paper is the following: |
| 31 | + |
| 32 | +*Recently, end-to-end OCR models, exemplified by DeepSeek OCR, have once again thrust OCR into the spotlight. A widely held view is that employing a large language model (LLM) as the decoder allows the model to leverage the prior distribution of language, leading to improved OCR performance. However, the downside is equally evident: as the output sequence lengthens, the accumulated KV cache drives up memory consumption and progressively slows down generation. This stands in stark contrast to humans, who exhibit no such decline in efficiency during long-horizon copying tasks. In this technical report, we propose Unlimited OCR, a model designed to emulate human parsing working memory. Taking DeepSeek OCR as the baseline, we replace all attention layers in the decoder with our proposed Reference Sliding Window Attention (R-SWA), which reduces attention computation costs while maintaining a constant KV cache throughout the entire decoding process. By combining the high compression rate of DeepSeek OCR's encoder with our constant KV cache design, Unlimited OCR can transcribe dozens of pages of documents in a single forward pass under a standard maximum length of 32K. More importantly, R-SWA is a general-purpose parsing attention mechanism — beyond OCR, it is equally applicable to tasks such as ASR, translation, etc. Codes and model weights are publicly available at http://github.com/baidu/Unlimited-OCR* |
| 33 | + |
| 34 | +<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/unlimited_ocr_architecture.png" width="600"> |
| 35 | + |
| 36 | +Unlimited-OCR supports two inference configurations: the default "gundam" mode uses 640x640 tiles with dynamic cropping for high-resolution documents, and "base" mode uses a single 1024x1024 global view for standard-resolution inputs. To enable base mode set `crop_to_patches=False` in the processor, or pass it via `processor_kwargs` when using [`~ProcessorMixin.apply_chat_template`]. |
| 37 | + |
| 38 | +The vision tower follows the two-stage approach from [DeepSeek-OCR-2](./deepseek_ocr2): a SAM ViT-B encoder feeds into a CLIP ViT encoder. Unlike DeepSeek-OCR-2, the CLIP features are additionally concatenated with the SAM features to yield the final image tokens. Unlimited-OCR also omits the learnable patch queries from DeepSeek-OCR-2. |
| 39 | + |
| 40 | +The text model is identical to DeepSeek-OCR-2 with the additional Reference Sliding Window Attention (R-SWA). R-SWA applies only to generated tokens. All image and prompt tokens remain fully visible throughout decoding, so long documents do not lose context from earlier pages. |
| 41 | + |
| 42 | +This model was contributed by [guarin](https://huggingface.co/guarin). |
| 43 | +The original code can be found [here](https://github.com/baidu/Unlimited-OCR). |
| 44 | + |
| 45 | +> [!TIP] |
| 46 | +> The original implementation runs the model with [torch.autocast](https://pytorch.org/docs/stable/amp.html#torch.autocast) in bfloat16. Wrap the forward and generate calls in an autocast context to reproduce its outputs. |
| 47 | +> |
| 48 | +> ```python |
| 49 | +> with torch.autocast(device_type=model.device.type, dtype=torch.bfloat16): |
| 50 | +> output = model.generate(**inputs) |
| 51 | +> ``` |
| 52 | +
|
| 53 | +<hfoptions id="usage"> |
| 54 | +<hfoption id="Single-page OCR"> |
| 55 | +
|
| 56 | +```python |
| 57 | +from transformers import AutoProcessor, AutoModelForImageTextToText |
| 58 | +
|
| 59 | +model = AutoModelForImageTextToText.from_pretrained("baidu/Unlimited-OCR", device_map="auto") |
| 60 | +processor = AutoProcessor.from_pretrained("baidu/Unlimited-OCR") |
| 61 | +
|
| 62 | +image = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/ocr_suggestion_form.jpg" |
| 63 | +messages = [ |
| 64 | + { |
| 65 | + "role": "user", |
| 66 | + "content": [{"type": "image", "url": image}, {"type": "text", "text": "document parsing."}], |
| 67 | + } |
| 68 | +] |
| 69 | +inputs = processor.apply_chat_template( |
| 70 | + messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt" |
| 71 | +).to(model.device, model.dtype) |
| 72 | +
|
| 73 | +output = model.generate(**inputs, max_new_tokens=512) |
| 74 | +processor.decode(output[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True) |
| 75 | +# image [383, 87, 497, 171]\ntext [333, 201, 558, 230]R&D QUALITY IMPROVEMENT\nSUGGESTION/SOLUTION FORM... |
| 76 | +
|
| 77 | +# All bounding boxes are in (x1, y1, x2, y2) format with coordinates normalized to [0, 999] |
| 78 | +``` |
| 79 | +
|
| 80 | +### Batch processing |
| 81 | + |
| 82 | +For batch processing, pass a list of messages. Set `padding=True` for the processor if images have different sizes. |
| 83 | + |
| 84 | +```python |
| 85 | +from transformers import AutoProcessor, AutoModelForImageTextToText |
| 86 | + |
| 87 | +model = AutoModelForImageTextToText.from_pretrained("baidu/Unlimited-OCR", device_map="auto") |
| 88 | +processor = AutoProcessor.from_pretrained("baidu/Unlimited-OCR") |
| 89 | + |
| 90 | +image1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/ocr_suggestion_form.jpg" |
| 91 | +image2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/ocr_receipt.jpeg" |
| 92 | +messages = [ |
| 93 | + [ |
| 94 | + { |
| 95 | + "role": "user", |
| 96 | + "content": [{"type": "image", "url": image}, {"type": "text", "text": "document parsing."}], |
| 97 | + } |
| 98 | + ] |
| 99 | + for image in [image1, image2] |
| 100 | +] |
| 101 | +inputs = processor.apply_chat_template( |
| 102 | + messages, |
| 103 | + add_generation_prompt=True, |
| 104 | + tokenize=True, |
| 105 | + return_dict=True, |
| 106 | + return_tensors="pt", |
| 107 | + processor_kwargs={"padding": True}, |
| 108 | +).to(model.device, model.dtype) |
| 109 | + |
| 110 | +output = model.generate(**inputs) |
| 111 | +processor.decode(output[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True) |
| 112 | +# image [383, 87, 497, 171]\ntext [333, 201, 558, 230]R&D QUALITY IMPROVEMENT\nSUGGESTION/SOLUTION FORM... |
| 113 | + |
| 114 | +# All bounding boxes are in (x1, y1, x2, y2) format with coordinates normalized to [0, 999] |
| 115 | +``` |
| 116 | + |
| 117 | +### Region detections |
| 118 | + |
| 119 | +Set `skip_special_tokens=False` to wrap all detections and region types in `<|det|>...<|/det|>` markers. This is useful for further post-processing of the output, for example to plot the detected bounding boxes on the image. Each detection is wrapped as `<|det|>region_type [x1, y1, x2, y2]<|/det|>text...` with coordinates normalized to a `[0, 999]` range. Set `return_detections=True` to get an additional list of dictionaries with all detections parsed as `{"region_type": region_type, "box": [x1, y1, x2, y2], "text": "..."}`. |
| 120 | + |
| 121 | +```python |
| 122 | +from transformers import AutoProcessor, AutoModelForImageTextToText |
| 123 | + |
| 124 | +model = AutoModelForImageTextToText.from_pretrained("baidu/Unlimited-OCR", device_map="auto") |
| 125 | +processor = AutoProcessor.from_pretrained("baidu/Unlimited-OCR") |
| 126 | + |
| 127 | +image = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/ocr_suggestion_form.jpg" |
| 128 | +messages = [ |
| 129 | + { |
| 130 | + "role": "user", |
| 131 | + "content": [{"type": "image", "url": image}, {"type": "text", "text": "document parsing."}], |
| 132 | + } |
| 133 | +] |
| 134 | +inputs = processor.apply_chat_template( |
| 135 | + messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt" |
| 136 | +).to(model.device, model.dtype) |
| 137 | + |
| 138 | +output = model.generate(**inputs) |
| 139 | +decoded, detections = processor.decode(output[0, inputs["input_ids"].shape[1]:], skip_special_tokens=False, return_detections=True) |
| 140 | +# <|det|>image [383, 87, 497, 171]<|/det|>\n<|det|>text [333, 201, 558, 230]<|/det|>R&D QUALITY IMPROVEMENT\nSUGGESTION/SOLUTION FORM... |
| 141 | + |
| 142 | +# Visualization |
| 143 | +import random |
| 144 | +import matplotlib.pyplot as plt |
| 145 | +import matplotlib.patches as patches |
| 146 | +from transformers.image_utils import load_image |
| 147 | + |
| 148 | +image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/ocr_suggestion_form.jpg") |
| 149 | +width, height = image.size |
| 150 | + |
| 151 | +figure, axis = plt.subplots(figsize=(10, 12)) |
| 152 | +axis.imshow(image) |
| 153 | +for detection in detections: |
| 154 | + region_type = detection["region_type"] |
| 155 | + x1, y1, x2, y2 = detection["box"] |
| 156 | + x1, y1, x2, y2 = int(x1) / 999 * width, int(y1) / 999 * height, int(x2) / 999 * width, int(y2) / 999 * height |
| 157 | + color = (random.random(), random.random(), random.random()) |
| 158 | + rectangle = patches.Rectangle((x1, y1), x2 - x1, y2 - y1, linewidth=1.5, edgecolor=color, facecolor="none") |
| 159 | + axis.add_patch(rectangle) |
| 160 | + axis.text(x1, y1, region_type, color="white", fontsize=8, backgroundcolor=color, verticalalignment="top") |
| 161 | +axis.axis("off") |
| 162 | +plt.show() |
| 163 | +``` |
| 164 | + |
| 165 | +<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/unlimited_ocr_suggestion_form_boxes.jpg" width="600"> |
| 166 | + |
| 167 | +</hfoption> |
| 168 | +<hfoption id="Multi-page OCR"> |
| 169 | + |
| 170 | +Multi-page documents can be parsed jointly in a single forward pass by passing all page images together. Add one image block per page to the message so the model processes all pages as a continuous document. |
| 171 | + |
| 172 | +```python |
| 173 | +from transformers import AutoProcessor, AutoModelForImageTextToText |
| 174 | + |
| 175 | +model = AutoModelForImageTextToText.from_pretrained("baidu/Unlimited-OCR", device_map="auto") |
| 176 | +processor = AutoProcessor.from_pretrained("baidu/Unlimited-OCR") |
| 177 | + |
| 178 | +page1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/ocr_suggestion_form.jpg" |
| 179 | +page2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/ocr_receipt.jpeg" |
| 180 | + |
| 181 | +messages = [ |
| 182 | + { |
| 183 | + "role": "user", |
| 184 | + "content": [{"type": "image", "url": page} for page in [page1, page2]] |
| 185 | + + [{"type": "text", "text": "Multi page parsing."}], |
| 186 | + } |
| 187 | +] |
| 188 | +inputs = processor.apply_chat_template( |
| 189 | + messages, |
| 190 | + add_generation_prompt=True, |
| 191 | + tokenize=True, |
| 192 | + return_dict=True, |
| 193 | + return_tensors="pt", |
| 194 | + processor_kwargs={"crop_to_patches": False}, |
| 195 | +).to(model.device, model.dtype) |
| 196 | + |
| 197 | +output = model.generate( |
| 198 | + **inputs, |
| 199 | + no_repeat_ngram_window_size=1024, # default: 128, larger window size recommended for long documents |
| 200 | +) |
| 201 | +processor.decode(output[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True) |
| 202 | +# <PAGE>image [382, 87, 489, 174]\ntitle [333, 201, 556, 230]R&D QUALITY IMPROVEMENT\nSUGGESTION/SCLUTION FORM... |
| 203 | + |
| 204 | +# All bounding boxes are in (x1, y1, x2, y2) format with coordinates normalized to [0, 999] |
| 205 | +``` |
| 206 | + |
| 207 | +</hfoption> |
| 208 | +</hfoptions> |
| 209 | + |
| 210 | +## UnlimitedOcrConfig |
| 211 | + |
| 212 | +[[autodoc]] UnlimitedOcrConfig |
| 213 | + |
| 214 | +## UnlimitedOcrTextConfig |
| 215 | + |
| 216 | +[[autodoc]] UnlimitedOcrTextConfig |
| 217 | + |
| 218 | +## UnlimitedOcrVisionConfig |
| 219 | + |
| 220 | +[[autodoc]] UnlimitedOcrVisionConfig |
| 221 | + |
| 222 | +## UnlimitedOcrVisionEncoderConfig |
| 223 | + |
| 224 | +[[autodoc]] UnlimitedOcrVisionEncoderConfig |
| 225 | + |
| 226 | +## UnlimitedOcrSamVisionConfig |
| 227 | + |
| 228 | +[[autodoc]] UnlimitedOcrSamVisionConfig |
| 229 | + |
| 230 | +## UnlimitedOcrImageProcessor |
| 231 | + |
| 232 | +[[autodoc]] UnlimitedOcrImageProcessor |
| 233 | + |
| 234 | +## UnlimitedOcrProcessor |
| 235 | + |
| 236 | +[[autodoc]] UnlimitedOcrProcessor |
| 237 | + |
| 238 | +## UnlimitedOcrPreTrainedModel |
| 239 | + |
| 240 | +[[autodoc]] UnlimitedOcrPreTrainedModel |
| 241 | + |
| 242 | +## UnlimitedOcrTextPreTrainedModel |
| 243 | + |
| 244 | +[[autodoc]] UnlimitedOcrTextPreTrainedModel |
| 245 | + |
| 246 | +## UnlimitedOcrTextModel |
| 247 | + |
| 248 | +[[autodoc]] UnlimitedOcrTextModel |
| 249 | + - forward |
| 250 | + |
| 251 | +## UnlimitedOcrVisionModel |
| 252 | + |
| 253 | +[[autodoc]] UnlimitedOcrVisionModel |
| 254 | + - forward |
| 255 | + |
| 256 | +## UnlimitedOcrModel |
| 257 | + |
| 258 | +[[autodoc]] UnlimitedOcrModel |
| 259 | + - forward |
| 260 | + |
| 261 | +## UnlimitedOcrForConditionalGeneration |
| 262 | + |
| 263 | +[[autodoc]] UnlimitedOcrForConditionalGeneration |
| 264 | + - forward |
0 commit comments