
Вам нужен OCR. В техобзорах рекомендуют Tesseract, на Хабре все пишут про VLM, идете на Hugging Face — там PaddleOCR‑VL, DeepSeek‑OCR, Dots.OCR, Qwen2.5-VL, и каждая называет себя SOTA. Прибавим к этому vLLM, SGLang, TGI, Native HF Transformers, и вот вы зависли между десятками комбинаций. Мы протестировали девять моделей на трех движках инференса на рукописном русском и отразили в таблице, какая модель под какую задачу лучше подходит.
Ваше время ценно для нас. Так что сразу держите краткие выводы
Native HF Transformers не для продакшена. Тот же Qwen2.5-VL под vLLM/SGLang в два раза быстрее, чем под Native, на той же GPU.
Размер модели обманчив. PaddleOCR‑VL 1.7B обгоняет Qwen2.5-VL-7B в пять с лишним раз по скорости в стр/мин и в 6,7 раза по токен/сек. Специализация бьет general‑purpose.
Tesseract быстрее всех — миф. На сложных изображениях он возвращает 411 символов против 1193 токенов у PaddleOCR‑VL. Быстро возвращать пустоту — не победа.
В классе general‑VLM наша компактная модель Cotype Light 3 на 9 млрд параметров обгоняет Qwen2.5-VL-7B на 79% по стр/мин с включенным MTP‑декодингом (37.7 vs 21.1) при сопоставимом TTFT.
Вот обещанная таблица со сводкой, какие модели в каких сценариях себя лучше показали.
Сценарий | Рекомендация | Почему |
Печатные документы, нужна скорость, простая верстка | Tesseract или RapidOCR на CPU | 140–190 страниц/мин, бесплатно, GPU не требуется |
Сложная верстка, таблицы, Markdown на выходе | PaddleOCR‑VL + SGLang | 110 страниц/мин, 56 ГБ VRAM, лидер OmniDocBench |
Production VLM с минимумом рисков совместимости | PaddleOCR‑VL + vLLM | 99 страниц/мин, лучший TTFT, шире поддержка моделей |
General‑purpose VLM, OCR — лишь часть задач | Qwen2.5-VL-7B + vLLM | 21 страница/мин, универсальная модель, знает русский |
Прототип, Jupyter‑research | Native HF Transformers | Только для прототипа. В production никогда |
MoE‑архитектура, batch‑обработка | DeepSeek‑OCR + vLLM | 56 страниц/мин, 570M активных параметров (3B total) |
Локальный VLM в закрытом контуре, RU‑домен | Cotype Light 3 + vLLM с MTP | 37.7 страниц/мин, 9B, свежий релиз 2026–06, встроенный MTP‑декодинг |
Цифры получены на NVIDIA A100 80GB (shared), batch=1, 15 образцов русскоязычного рукописного текста.
Ниже объясню, как мы эту таблицу получили и какие нюансы стоят за каждой строкой.
Ландшафт: традиционный OCR vs VLM в 2025–2026 гг.
До 2024 года выбор OCR был относительно понятным. Tesseract, PaddleOCR, EasyOCR. Пайплайн один: детекция текстовых областей, распознавание символов, постобработка. Обычный текст на выходе, минимальные требования к железу, предсказуемость.
Но тут появились VLM (Vision Language Models). По сути это end‑to‑end модели: вижн‑энкодер превращает картинку в эмбеддинги, LLM‑декодер генерирует текст. Никаких отдельных стадий: подал картинку — получил Markdown, JSON, HTML.
Вот сравнительная таблица для традиционного и VLM‑подхода к OCR.
Традиционный OCR | OCR на VLM | |
Архитектура | Детекция, распознавание, постобработка | End‑to‑end: вижн‑энкодер + LLM‑декодер |
Типичная скорость | 0,5–3 сек/стр (CPU) | 2–10 сек/стр (GPU) |
Сложная верстка | Слабо | Хорошо |
Структурный вывод | Простой текст | Markdown, HTML, JSON |
Стоимость self‑hosted | Очень низкая (CPU) | Зависит от модели и движка (GPU) |
А еще появились специализированные OCR‑VLM типа PaddleOCR‑VL (1,7B), DeepSeek‑OCR (3B MoE), Dots.OCR (3B). Это VLM по архитектуре, но дообученные исключительно на OCR‑задачах. Они меньше VLM общего назначения в 4–10 раз, но на распознавании документов работают на уровне или лучше.
В таком многообразии инструментов нам было интересно узнать, где проходит граница между «брать классику» и «брать VLM» и какая конкретная связка модель + движок оптимальна.
Как мы это узнавали?
Методология
Мы решили разработать честный бенчмарк, в котором все модели бегут в одинаковых условиях. Что мы зафиксировали:
Унифицированные параметры:
Precision: bfloat16 (для всех VLM)
max_new_tokens: 2048
temperature: 0.0 (детерминированный вывод)
Image preprocessing: thumbnail 800×800, JPEG q85, base64
Warmup: пять прогонов перед замерами (прогрев KV‑cache, CUDA‑кернелов)
Промпт: SYSTEM: “You are an OCR assistant. Extract all text...” + USER: “Extract all text from this document.”
Стек инфраструктуры:
NVIDIA A100 80GB PCIe (им пришлось делиться с другими командами, об ограничениях ниже)
vLLM 0.18.1: gpu‑memory‑utilization=0.4, max‑model‑len=4096, OpenAI‑compatible API
SGLang v0.5.10: mem‑fraction‑static=0.85, OpenAI‑совместимый API
Native HF Transformers: AutoModel.generate() напрямую, без оптимизаций
Движки запускались в Docker (vllm/vllm‑openai:latest, lmsysorg/sglang:latest).
Датасет:
15 примеров русскоязычных текстов из Russian Handwriting OCR: пять чистых сканов, пять «темных» (низкий контраст), пять «светлых» (засветка), выборка через random_state=42. Мы специально для теста взяли рукописи, так как это максимально сложная задача для любого OCR: нестандартные символы, вариативность почерка, шум. Если модель справится здесь, то на печатных документах и подавно.
Метрики:
pages/min: пропускная способность на уровне документов
TTFT (Time To First Token, мс): задержка до первого токена
TPOT (Time Per Output Token, мс): среднее время на токен
tok/s: токенов в секунду
tok/page: токенов на страницу (для VLM)
peak GPU memory (ГБ), GPU utilization (%)
Замеры пишутся в JSON, графики строятся отдельно.
Результат 1. Общий рейтинг стр/мин и ловушка Tesseract
Первое, что хочется знать про OCR, сколько страниц в минуту. Вот общий рейтинг всех 14 комбинаций модель + движок, упорядочено по убыванию:

# | Модель | Движок/окружение | Стр/ |
1 | Tesseract | CPU | 193.1 |
2 | RapidOCR | CPU | 143.5 |
3 | PaddleOCR‑VL | SGLang (GPU) | 110.8 |
4 | EasyOCR | CPU | 105.5 |
5 | PaddleOCR‑VL | vLLM (GPU) | 98.7 |
6 | Dots.OCR | vLLM (GPU) | 61.6 |
7 | DeepSeek‑OCR | vLLM (GPU) | 56.3 |
8 | Cotype Light 3 (+MTP) | vLLM (GPU) | 37.7 |
9 | Dots.OCR | SGLang (GPU) | 27.9 |
10 | Cotype Light 3 | vLLM (GPU) | 26.5 |
11 | Qwen2.5-VL-7B | SGLang (GPU) | 21.3 |
12 | Qwen2.5-VL-7B | vLLM (GPU) | 21.1 |
13 | PaddleOCR v5 | CPU | 15.0 |
14 | Qwen2.5-VL-7B | Native HF (GPU) | 10.9 |
В лидерах Tesseract (193) и RapidOCR (143) на CPU. На GPU быстрее всего PaddleOCR‑VL под SGLang (111) и под vLLM (99). EasyOCR (105) дает неплохой CPU‑результат. Аутсайдеры: Qwen2.5-VL-7B (21 на vLLM/SGLang, 11 на Native) и PaddleOCR v5 (15 стр/мин на CPU).
Кажется очевидным, что традиционный OCR на CPU быстрее VLM на GPU, берите Tesseract. Но это ловушка.
Посмотрите на полноту вывода — сколько символов или токенов модель выдает на одну страницу:

Tesseract: 411 символов/стр
RapidOCR: 549
PaddleOCR v5: 766
EasyOCR: 795
PaddleOCR‑VL: 1193 токенов/стр
Tesseract быстрый именно потому, что возвращает меньше. На сложных изображениях (рукопись, низкий контраст, наклон) он пропускает участки, где не уверен, и возвращает пустую строку. Быстро отвечать «не знаю» — так себе победа.
EasyOCR лидирует по полноте среди традиционных OCR‑моделей (795 символов) при разумных 105 стр/мин, это честный CPU‑бейзлайн. RapidOCR при 549 символах — компромисс между скоростью и полнотой.
VLM выдают на порядок больше токенов, потому что распознают разметку: заголовки, списки, таблицы в Markdown. 30–40% объема у PaddleOCR‑VL — это не сами символы, а структура документа.
Вывод: количество распознанных страниц в минуту без контекста полноты — бесполезная метрика. На простых печатных документах Tesseract будет лидером по причине минимальной вычислительной сложности. На сложных — по причине пропусков.
Результат 2. vLLM vs SGLang vs Native, 2-кратный разрыв на одной модели
После выбора VLM нужно определиться с движком инференса.
Есть три кандидата:
vLLM: PagedAttention, де‑факто стандарт для прода. Широкая поддержка моделей, OpenAI‑совместимый API.
SGLang: RadixAttention, агрессивная оптимизация KV‑cache. Лучше пропускная способность на специализированных моделях, экономнее по памяти.
Native HF Transformers: прямой AutoModel.generate(). Минимум зависимостей, максимум совместимости. Используется для прототипирования.
Чтобы изолировать эффект движка, мы прогнали одну модель, Qwen2.5-VL-7B, под всеми тремя:

Qwen2.5-VL под Native vs vLLM vs SGLang
Движок | TTFT, мс | стр/мин | GPU memory, ГБ | GPU util,% |
Native HF | 138.9 | 10.9 | 49.6 | 64.3 |
vLLM | 78.4 | 21.1 | 68.6 | 98.7 |
SGLang | 122.4 | 21.3 | 56.5 | 96.7 |
Вывод 1: Native HF не для прода. Двукратное отставание в скорости распознавания — это не просто «немного хуже», а вдвое хуже. Утилизация GPU — 64% против 97–99%, Native HF просто не умеет грузить карту. С ростом партий запросов (batch > 1) разрыв станет еще заметнее.
Вывод 2: разница между vLLM vs SGLang в пределах погрешности. По пропускной способности (throughput) на Qwen они идут почти одинаково (21.1 vs 21.3), однако vLLM лучше TTFT (78 мс vs 122) и выигрывает в плане совместимости с моделями. SGLang экономнее по памяти (57 ГБ vs 69 ГБ у vLLM) и в прогонах на специализированных моделях давал +5–14% к пропускной способности.
Рекомендация: по умолчанию для продакшена берем vLLM. К SGLang идем, когда нужна максимальная пропускная способность или когда уперлись в память видеокарты. Native — только для исследований в Jupyter.
Результат 3. PaddleOCR‑VL 1.7B обгоняет Qwen2.5-VL 7B в пять с лишним раз по скорости
И это главный неожиданный результат бенчмарка.
Все восемь VLM‑прогонов в одной таблице:
Модель | Движок | TTFT, мс | токен/с | стр/мин | токен/ | GPU mem, ГБ | GPU util,% |
PaddleOCR‑VL | SGLang | 140.3 | 604.2 | 110.8 | 1193 | 56.1 | 90.2 |
PaddleOCR‑VL | vLLM | 64.3 | 571.7 | 98.7 | 1314 | 69.6 | 94.8 |
Dots.OCR | vLLM | 83.7 | 221.4 | 61.6 | 666 | 67.4 | 96.1 |
DeepSeek‑OCR | vLLM | 133.6 | 419.5 | 56.3 | 1224 | 70.2 | 95.2 |
Dots.OCR | SGLang | 105.0 | 252.9 | 27.9 | 1004 | 56.3 | 97.1 |
Qwen2.5-VL-7B | SGLang | 122.4 | 90.6 | 21.3 | 442 | 56.5 | 96.7 |
Qwen2.5-VL-7B | vLLM | 78.4 | 90.5 | 21.1 | 341 | 68.6 | 98.7 |
Qwen2.5-VL-7B | Native | 138.9 | 41.4 | 10.9 | 333 | 49.6 | 64.3 |
У PaddleOCR‑VL всего 1,7 млрд параметров, у Qwen2.5-VL-7B — 7 млрд. Но первая в 5,2 раза опережает вторую по страницам в минуту (110.8 против 21.1–21.3) и в 6,7 раза — по токенам в секунду (604.2 против 90.5–90.6). По страницам в минуту разрыв меньше, потому что PaddleOCR‑VL генерирует больше токенов на страницу (1193 против 341–442) — за счет markdown‑разметки в выводе.
Почему так получается?
PaddleOCR‑VL, DeepSeek‑OCR и Dots.OCR — это специализированные OCR‑VLM. Они дообучены на распознавании документов и выдают результат в виде Markdown с разметкой: заголовки, таблицы, списки. Это видно по показателю токен/стр: 1193–1314 у специализированных против 341–442 у Qwen. 30–40% объема у специализированных моделей — это не текст, а структура.
Qwen2.5-VL — модель общего назначения (VLM): умеет отвечать на вопросы по изображению, описывать его, разбираться в структуре документов и многое другое. За универсальность платим скоростью. Плюс Queen's по природе консервативны: на нечитаемых участках они молчат, а не угадывают. Для рукописи это видится как «низкая полнота», но на читаемых документах это плюс, так как меньше галлюцинаций.
Вывод. Специализация бьет scaling. На задаче с узким сценарием (распознавание документов) маленькая специализированная модель обходит все умеющую большую. И не на 10%, а в разы.
Результат 4. Cotype Light 3 в классе VLM общего назначения
Если VLM‑ки общего назначения все равно медленнее спец‑OCR, есть ли смысл сравнивать модели внутри этого класса?
Короткий ответ — есть. Часто нам приходится иметь дело со сценариями, в которых распознавание сканов — лишь часть более широкой задачи: диалог по документу, вопросы по картинке, инструкции с картинкой и прочее. В таких случаях выбираем не между PaddleOCR‑VL и Qwen, а между различными general‑VLM.
Недавно мы релизнули Cotype Light 3_9B, и решили заодно прогнать нашу мини‑модельку в двух режимах: бейзлайн и с включенным MTP (‑speculative‑config). MTP это Multi‑Token Prediction: в чекпоинт Cotype встроена дополнительная голова model‑mtp‑injected.safetensors, предсказывающая три токена вперед. Основная модель проверяет их за один forward‑pass; при попадании получаем несколько токенов за проход вместо одного. Математически идентично обычной генерации, качество вывода не меняется. Это родной режим модели, а не post‑hoc оптимизация под наш бенч. Для сравнения взяли Qwen2.5-VL-7B, как стандартную VLM под OCR‑задачи.
Результаты в таблице:
Модель | Движок | TTFT, мс | стр./мин. | с/стр. | GPU mem, ГБ |
Qwen2.5-VL-7B | vLLM | 78.4 | 21.1 | 3.75 | 68.6 |
Cotype Light 3 | vLLM | 86.6 | 26.5 | 4.29 | 71.3 |
Cotype Light 3 | vLLM + MTP | 93.1 | 37.7 | 2.28 | 72.2 |
Baseline дает +25% к Qwen2.5-VL-7B (26.5 против 21.1). MTP‑режим — +79% (37.7 vs 21.1). TTFT остается в интерактивном диапазоне 86–93 мс, отклик пользователя не страдает. Расход VRAM сопоставим: 71–72 vs 69 ГБ на A100 80.
Колонку по пропускной способности (токен/сек) мы намеренно не приводим, так как наш streaming‑счетчик инкрементирует токен на каждый SSE‑чанк, а vLLM в spec‑режиме упаковывает в чанк несколько принятых токенов. Wall‑clock метрики (стр/мин, сек/стр) считаются от time.perf_counter() и достоверны.
Со спец‑OCR типа PaddleOCR‑VL, Dots.OCR и DeepSeek‑OCR сравнивать Cotype Light 3 напрямую бессмысленно, они созданы под другой класс задач. А внутри своего Cotype Light 3 сейчас впереди Qwen2.5-VL-7B — и это радует.
Результат 5. Цена скорости, GPU память и утилизация
Скорость VLM не бесплатна. Главный ресурс это VRAM.
Из таблицы выше видны три закономерности:
vLLM ест больше памяти (~70 ГБ), чем SGLang (~56 ГБ). Это плата за PagedAttention и более агрессивную преаллокацию KV‑cache. Для одной модели на 80GB‑карте это нормально, но если хочется крутить две модели рядом или нужен запас под батч, SGLang выгоднее.
Загрузка GPU у vLLM и SGLang на уровне 90–98%, впритык к потолку железа. Это значит, что дальнейший рост возможен только от батчинга или более быстрой карты.
Native HF Transformers просто не умеет загружать GPU — всего 64%. Использует меньше памяти, чем движки (~50 ГБ), но скорость в два раза ниже не из‑за памяти, а потому что между токенами карта простаивает.
Практический вывод
Если вы вынуждены делиться A100, как мы (нам было реально доступно ~48 ГБ из 80), у вас два варианта:
SGLang + специализированная модель (56 ГБ, впритык). Работает с оговорками.
vLLM + любая VLM (69+ ГБ). Не помещается, нужна выделенная карта или меньшая модель.
На выделенной A100 80GB обе связки работают комфортно.
Осторожно с этими цифрами
Будем честны, некоторые наши выводы по этому бенчу стоит читать, беря во внимание следующие оговорки:
Для тестов мы брали A100 80GB, но из‑за параллельной нагрузки других команд реально было доступно ~48 ГБ. На выделенной карте абсолютные числа будут выше, но относительные разрывы (Native vs движки, PaddleOCR‑VL vs Qwen) сохранятся, это нагрузочное свойство, не зависящее от свободной памяти.
Batch = 1. Все замеры проводились по одному запросу за раз. В реальной нагрузке с батчингом разрыв vLLM/SGLang над Native будет еще больше, движки именно ради batched inference и сделаны.
Тестировали на 15 семплах: пять нормальных сканов + пять затемненных + пять засвеченных, выбранных через random_state=42. Статистическая мощность ограничена, но при разрывах в 2–6 раз это уже не шум.
Брали только русскоязычную рукопись (ад для OCR). На печатных документах абсолютные цифры у всех будут выше, особенно у Tesseract, он отстает именно на рукописи.
CER/WER не считали. Это бенчмарк скорости, не качества. Эталонная разметка для качественных метрик уже готовится: 15 страниц размечены вручную, о результатах в следующий раз расскажем.
Native HF Transformers получилось запустить только для Qwen2.5-VL, остальные модели несовместимы с generic pipeline. Для них Native‑сравнение отсутствует.
SGLang у нас не запустился на DeepSeek‑OCR (image processor: image.size трактуется как метод). Поэтому цифра есть только для vLLM.
Главный технический инсайт
Размер модели — слабый предиктор производительности. Специализация под задачу и выбор движка инференса важнее количества параметров.
Что хотим сделать дальше
Добавим больше семплов (печатные документы и таблицы).
Измерим CER/WER на размеченных страницах. Эталонная разметка 15 страниц готова, скоро опубликуем CER/WER по тем же моделям, чтобы скорость не была единственной осью сравнения.
Проведем замеры с разной нагрузкой (10, 50, 100 параллельных запросов), чтобы понять, как ведут себя движки под реальным трафиком, а не на синтетическом batch=1.
Пишите в комментариях, какой OCR у вас в проде и почему взяли именно его. Интересно собрать живые сценарии, на которых наши цифры не сходятся с практикой.
