Вы загрузили скан договора в GPT-4V. Получили поэзию вместо текста
Типичная история: берете современную Vision Language Model, суете ей скан паспорта или договора, а она выдает что-то вроде "На изображении виден документ с текстом. Возможно, это официальная бумага". Или хуже - начинает галлюцинировать, придумывая несуществующие номера и даты.
Вы платите за дорогую модель, а получаете уровень детского сада. Почему так происходит? Потому что VLM - это не OCR системы в классическом понимании. Они созданы для понимания сцен, описания картинок, ответов на вопросы о визуальном контенте. Текст для них - просто еще один визуальный паттерн, как форма дерева или цвет машины.
Главное заблуждение: Раз модель мультимодальная, значит она умеет читать. Нет. VLM обучаются на датасетах типа COCO, где текста мало, он идеально четкий и чаще всего на английском. Ваши размытые сканы с печатями, тенями и кривым русским шрифтом - это другой мир.
Три типа документов, которые ломают любую VLM
| Тип документа | Что ломается | Пример ошибки |
|---|---|---|
| Сканы с тенями и бликами | Контрастность падает, текст сливается с фоном | "Иванов" → "Иванob", цифры 8 и 3 путаются |
| Рукописные формы | Нет единого стандарта написания букв | Подпись врача превращается в случайный набор символов |
| Таблицы и бланки | Модель не понимает структуру, теряет связи между ячейками | Данные из разных колонок смешиваются в один абзац |
Самое обидное: модель может быть отличной. Qwen3-VL, которая в других задачах бьет конкурентов, на вашем скане договора выдаст полную чушь. Проблема не в модели, а в том, что вы ей скармливаете.
Почему не работает обычный препроцессинг из учебников
Вы наверняка гуглили "улучшение изображения для OCR" и нашли стандартные рецепты: применить adaptive threshold, увеличить контраст, убрать шум. Проблема в том, что эти методы создавались для старых OCR вроде Tesseract, которые работают с бинарными изображениями (черно-белыми).
VLM работают с RGB изображениями, часто в формате 336x336 или 448x448 пикселей. Когда вы берете скан А4 (3508x2480), уменьшаете до 336x336, а потом применяете резкие фильтры - вы уничтожаете информацию. Текст превращается в месиво из пикселей.
Правильный пайплайн: препроцессинг, который действительно работает
1 Ресайз с умом (не ломайте пропорции)
Первая ошибка - слепо ресайзить до стандартного размера модели. Если у вас таблица 10x10 ячеек, после ресайза до 336x336 она превратится в серое пятно.
# КАК НЕ НАДО ДЕЛАТЬ
from PIL import Image
image = Image.open("scan.jpg")
# Убиваем всю структуру документа
image = image.resize((336, 336))
# ПРАВИЛЬНЫЙ ПОДХОД
from PIL import Image
import numpy as np
def smart_resize_for_vlm(image, target_size=336):
"""
Сохраняем соотношение сторон, добавляем паддинг
для квадратного изображения
"""
# Определяем текущий размер
width, height = image.size
# Находим максимальную сторону
max_side = max(width, height)
# Масштабируем так, чтобы максимальная сторона была target_size
scale = target_size / max_side
new_width = int(width * scale)
new_height = int(height * scale)
# Ресайзим с сохранением пропорций
image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
# Создаем новое квадратное изображение с белым фоном
new_image = Image.new('RGB', (target_size, target_size), (255, 255, 255))
# Вставляем наше изображение по центру
offset = ((target_size - new_width) // 2, (target_size - new_height) // 2)
new_image.paste(image, offset)
return new_image
2 Убираем тени и выравниваем освещение
Сканы с мобильных телефонов - главный враг VLM. Тень от руки, неравномерное освещение, блики от ламинации. Модель видит это как часть изображения и пытается интерпретировать.
import cv2
import numpy as np
def remove_shadows_and_enhance(image_array):
"""
Убираем тени и выравниваем освещение
без потери цветовой информации
"""
# Конвертируем в LAB цветовое пространство
# L - яркость, A и B - цвет
lab = cv2.cvtColor(image_array, cv2.COLOR_RGB2LAB)
# Разделяем каналы
l, a, b = cv2.split(lab)
# Применяем CLAHE только к каналу яркости
# Это выравнивает освещение без влияния на цвета
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl = clahe.apply(l)
# Собираем обратно
limg = cv2.merge((cl, a, b))
# Конвертируем обратно в RGB
enhanced = cv2.cvtColor(limg, cv2.COLOR_LAB2RGB)
return enhanced
3 Сегментация документа перед отправкой в VLM
Вместо того чтобы пихать целую страницу А4 в модель, разбейте ее на логические блоки. Заголовок, таблица, подпись, печать - каждый блок обрабатывайте отдельно.
Это критично для таблиц. Если отправить всю таблицу как одно изображение, VLM потеряет структуру. Если отправить каждую ячейку отдельно - получите точные данные, но потеряете контекст. Решение: отправляйте строки или небольшие группы ячеек.
Выбор модели: какая VLM меньше всего ненавидит ваш текст
Не все мультимодальные модели одинаково бесполезны для OCR. Некоторые проектировались с учетом работы с текстом в изображениях.
| Модель | OCR способности | Минимальные требования | Когда выбирать |
|---|---|---|---|
| Qwen3-VL | Лучшая среди open-source для текста в изображениях | 16+ GB VRAM (fp16) | Сложные документы со смешанным контентом |
| LLaVA-NeXT | Средние, но быстрые и легкие | 8 GB VRAM | Простые документы, нужна скорость |
| CogVLM | Хороша для таблиц и структуры | 14 GB VRAM | Финансовые отчеты, Excel-подобные таблицы |
| MiniCPM-V | Удивительно хороша для своего размера | 6 GB VRAM | Бюджетные системы, мобильные приложения |
Qwen3-VL - текущий чемпион. Но у нее есть особенность: она требует правильного промптинга. Не просто "прочитай текст", а конкретные инструкции.
# ПЛОХОЙ промпт
prompt = "Что написано на этом изображении?"
# ХОРОШИЙ промпт для Qwen3-VL
prompt = """
Ты вижу документ. Извлеки весь текст максимально точно.
Сохрани форматирование: если текст в таблице, сохрани структуру таблицы.
Если есть нумерованные списки, сохрани нумерацию.
Верни чистый текст без дополнительных комментариев.
"""
Гибридный подход: когда VLM сдаются, вызывайте тяжелую артиллерию
Иногда никакой препроцессинг не поможет. Рукописный текст, каллиграфия, старые документы с потускневшими чернилами. Здесь нужен комбинированный подход.
Пайплайн для самых сложных случаев:
- Детекция текстовых блоков - используйте CRAFT, DBNet или любой детектор. Нужно понять, где вообще есть текст.
- Классификация типа текста - машинный/рукописный, печатный/курсив, основной текст/сноски.
- Маршрутизация:
- Печатный текст → специализированный OCR (Donut, TrOCR)
- Рукописный текст → VLM с усиленным препроцессингом
- Таблицы → CogVLM или табличный OCR
- Постобработка - исправление очевидных ошибок, слияние результатов.
Этот подход описан в нашей статье про OCR-воркфлоу для паспортов, но работает для любых документов.
Квантование: как впихнуть Qwen3-VL на RTX 3060
Qwen3-VL в fp16 требует 16+ GB VRAM. На RTX 3060 с ее 12 GB это не запустится. Но можно использовать квантование.
Внимание: Квантование ухудшает качество OCR. Модель теряет способность различать похожие символы (O и 0, l и 1). Для документов с важными числовыми данными это критично.
Если все же нужно квантовать:
# Пример квантования с помощью AutoGPTQ
from transformers import AutoTokenizer, AutoModelForCausalLM
from auto_gptq import AutoGPTQForCausalLM
model_name = "Qwen/Qwen3-VL-7B-Instruct"
# Загружаем квантованную версию
model = AutoGPTQForCausalLM.from_quantized(
model_name,
model_basename="model",
use_safetensors=True,
trust_remote_code=True,
device="cuda:0",
use_triton=False,
quantize_config=None
)
Но лучше рассмотреть альтернативы. MiniCPM-V дает 80% качества Qwen3-VL при 40% размера. Или использовать imatrix для адаптивного квантования, которое меньше бьет по точности OCR.
Чеклист перед запуском в production
- Тестируйте на реальных данных, а не на идеальных сканах из интернета
- Создайте набор "ядрёных" документов: с печатями, подписями, таблицами, низким качеством
- Измеряйте не только accuracy, но и воспроизводимость (дает ли модель одинаковый результат на одном документе)
- Настройте fallback: когда VLM выдает низкую уверенность, передавайте документ в классический OCR
- Кэшируйте результаты: один и тот же документ не должен обрабатываться дважды
Будущее: VLM, которые действительно умеют читать
Проблема VLM и OCR решается на уровне датасетов. Новые модели обучаются на Document Understanding Benchmark, где есть сканы реальных документов со всеми их недостатками.
Но пока этого не произошло, ваш лучший друг - препроцессинг. Не ждите, что модель починит кривые сканы за вас. Чем лучше вы подготовите данные, тем меньше будете ругаться на "тупые нейронки".
P.S. Если после всех оптимизаций модель все равно путает "ИНН" и "ИНЫ", возможно, проблема не в модели. Проверьте, не установили ли вы ее вверх ногами. (Шутка. Но такое бывает чаще, чем кажется).