Почему OLMocr 2 не читает ваши документы и как это исправить
Вы загружаете сканы договоров, накладных, медицинских карт в OLMocr 2 и получаете на выходе абракадабру. Модель, обученная на общих данных, спотыкается о вашу специфику - особые шрифты, бланки, сокращения, печати. Типичная ситуация: OCR работает идеально на тестовых примерах, но в продакшене дает ошибки в 30% случаев.
Проблема не в модели. Проблема в том, что OLMocr 2 не знает, как выглядят ВАШИ документы. Дообучение - не опция, а необходимость, если хотите точность выше 95%. Но большинство пытаются делать это неправильно: кидают в модель 100 случайных изображений и удивляются, почему ничего не работает.
Типичная ошибка: начинают с кода обучения, а не с данных. Результат - потраченное время и нулевое улучшение. В OCR 80% успеха - это качественный датасет, 20% - правильные гиперпараметры.
1 Собираем данные, которые действительно учат
Первое правило: не берите все подряд. Возьмите 10-20 самых проблемных типов документов, где OLMocr 2 ошибается чаще всего. Это могут быть:
- Документы с печатями и штампами
- Бланки со сложным форматированием
- Текст в таблицах (особенно с границами)
- Рукописные пометки поверх машинного текста
- Документы плохого качества (сжатые, размытые, с тенями)
Ключевой момент: разнообразие. Если у вас только идеальные сканы с белым фоном - модель не научится работать с реальными условиями. Добавьте:
| Тип вариации | Зачем нужно | Примеры |
|---|---|---|
| Разное качество | Модель учится работать с реальными документами | Размытые, сжатые, с артефактами JPEG |
| Разный фон | Помогает отделить текст от фона | Цветной фон, текстура бумаги, линии разлиновки |
| Разные углы | Учет перспективных искажений | Поворот на 1-5 градусов, перспектива |
2 Разметка: как не сойти с ума и не разориться
Разметка текста на изображениях - самая муторная часть. Ручная разметка 1000 документов займет недели. Есть три пути:
- Использовать сам OLMocr 2 для преразметки - запускаете модель на ваших данных, исправляете только ошибки. Экономит 70% времени.
- Аугментация существующей разметки - если есть часть размеченных данных, генерируйте на их основе новые примеры с искажениями.
- Использовать инструменты вроде PPOCRLabel - полуавтоматическая разметка с предсказаниями модели.
Формат разметки для OLMocr 2:
{
"image_path": "documents/contract_001.jpg",
"text": "ДОГОВОР № 123 от 15.01.2024 г.\nг. Москва\n\n1. ПРЕДМЕТ ДОГОВОРА...",
"bboxes": [
[10, 20, 100, 30, "ДОГОВОР"],
[110, 20, 200, 30, "№"],
[210, 20, 250, 30, "123"]
]
}
Важно: сохраняйте оригинальную кодировку и специальные символы. Если в документах есть знаки рубля (₽), товарные знаки (™) - они должны быть в разметке. OLMocr 2 поддерживает Unicode.
Если разметка пугает масштабами, посмотрите мой гайд про автоматизацию разметки датасетов - там техники, которые сокращают работу с недель до часов.
3 Подготовка пайплайна: от сырых данных до готового датасета
Собранные изображения и разметка - это сырье. Теперь нужно построить конвейер, который превратит это в готовый датасет для обучения. Вот полный пайплайн:
import os
import json
from pathlib import Path
from PIL import Image
import numpy as np
class OLMocrDatasetPipeline:
def __init__(self, raw_data_dir, output_dir):
self.raw_data_dir = Path(raw_data_dir)
self.output_dir = Path(output_dir)
self.output_dir.mkdir(exist_ok=True)
def validate_images(self):
"""Проверяем, что все изображения читаются"""
valid_images = []
for img_path in self.raw_data_dir.glob("*.jpg"):
try:
with Image.open(img_path) as img:
img.verify()
valid_images.append(img_path)
except:
print(f"Повреждено: {img_path.name}")
return valid_images
def create_train_val_split(self, images, val_ratio=0.2):
"""Разделяем на тренировочную и валидационную выборки"""
np.random.shuffle(images)
split_idx = int(len(images) * (1 - val_ratio))
return images[:split_idx], images[split_idx:]
def generate_annotations(self, image_paths, split_name):
"""Генерируем аннотации в формате OLMocr 2"""
annotations = []
for img_path in image_paths:
# Загружаем соответствующую разметку
ann_path = img_path.with_suffix('.json')
if ann_path.exists():
with open(ann_path, 'r', encoding='utf-8') as f:
ann_data = json.load(f)
# Конвертируем в нужный формат
annotation = {
"image": str(img_path),
"text": ann_data["text"],
"bboxes": ann_data["bboxes"]
}
annotations.append(annotation)
# Сохраняем
output_file = self.output_dir / f"{split_name}_annotations.json"
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(annotations, f, ensure_ascii=False, indent=2)
return output_file
Это базовая структура. В реальном пайплайне добавьте:
- Аугментацию данных (повороты, изменение яркости, добавление шума)
- Балансировку классов (если есть разные типы документов)
- Проверку качества разметки (выборочную верификацию)
4 Дообучение: что менять, а что оставить как есть
Теперь самая интересная часть - собственно обучение. OLMocr 2 построен на архитектуре Transformer, и у вас есть несколько стратегий:
| Стратегия | Когда использовать | Ресурсы |
|---|---|---|
| Fine-tuning всей модели | Документы сильно отличаются от тренировочных данных OLMocr 2 | Много GPU памяти, время |
| LoRA адаптеры | Хотите сохранить базовые способности, добавив специфику | Мало ресурсов, быстро |
| Только последние слои | Документы похожи, но есть особенности форматирования | Умеренные ресурсы |
Конфигурация обучения (основные параметры):
# config_finetune.yaml
model:
pretrained: "olmednard/olmocr-2-base"
training:
batch_size: 8 # Зависит от GPU памяти
num_epochs: 10 # Для fine-tuning обычно достаточно
learning_rate: 5e-5
warmup_steps: 100
data:
train_annotations: "data/train_annotations.json"
val_annotations: "data/val_annotations.json"
image_size: [1024, 1024] # OLMocr 2 работает с квадратными изображениями
augmentation:
rotation_range: [-5, 5] # Небольшие повороты
brightness_range: [0.9, 1.1]
contrast_range: [0.9, 1.1]
5 Валидация: как понять, что модель действительно улучшилась
Самый опасный момент - когда метрики растут, а на реальных данных ничего не меняется. OLMocr 2 использует метрику CER (Character Error Rate), но она может обманывать.
Что нужно проверять обязательно:
- CER на валидационной выборке - должна снижаться
- Точность на критичных полях - номера документов, суммы, даты
- Скорость работы - не должна значительно ухудшиться
- Распознавание на "сложных" документах - тех, которые изначально плохо читались
Скрипт для комплексной валидации:
def validate_model(model, test_dataset, critical_fields):
"""Проверяем модель на критически важных полях"""
results = {
'overall_cer': 0.0,
'field_accuracy': {},
'inference_time': []
}
for test_item in test_dataset:
start_time = time.time()
# Предсказание
prediction = model.predict(test_item['image'])
inference_time = time.time() - start_time
results['inference_time'].append(inference_time)
# Считаем CER для всего текста
cer = calculate_cer(test_item['text'], prediction['text'])
results['overall_cer'] += cer
# Проверяем критичные поля
for field_name, field_regex in critical_fields.items():
original_field = extract_field(test_item['text'], field_regex)
predicted_field = extract_field(prediction['text'], field_regex)
if original_field and predicted_field:
is_correct = (original_field == predicted_field)
results['field_accuracy'].setdefault(field_name, []).append(is_correct)
# Агрегируем результаты
results['overall_cer'] /= len(test_dataset)
for field_name in results['field_accuracy']:
accuracy = sum(results['field_accuracy'][field_name]) / len(results['field_accuracy'][field_name])
results['field_accuracy'][field_name] = accuracy
results['avg_inference_time'] = sum(results['inference_time']) / len(results['inference_time'])
return results
Типичные ошибки и как их избежать
За 5 лет работы с OCR-моделями я видел одни и те же ошибки снова и снова:
Ошибка 1: Обучают на идеальных данных, тестируют на идеальных данных, удивляются, почему в продакшене плохо. Решение: добавьте в тренировочные данные документы с теми же проблемами, что и в продакшене.
Ошибка 2: Слишком много эпох обучения. OLMocr 2 уже хорошо обучен, ему нужно только адаптироваться к вашим данным. 5-10 эпох обычно достаточно. После 20 эпох начинается переобучение.
Ошибка 3: Игнорируют классовый дисбаланс. Если у вас 90% договоров и 10% накладных, модель будет хуже распознавать накладные. Решение: oversampling редких классов или веса классов в loss function.
Интеграция в продакшен: не только модель
Обученная модель - только часть системы. В продакшене вам понадобится:
- Предобработка изображений - выравнивание, повышение контраста, удаление шума
- Постобработка текста - исправление типичных ошибок, приведение к стандартному формату
- Мониторинг качества - отслеживание метрик в реальном времени
- А/Б тестирование - постепенный rollout новой модели
Пример постобработки для исправления типичных ошибок OCR:
class OCRPostProcessor:
def __init__(self, correction_rules):
self.correction_rules = correction_rules # Словарь замен
def correct_common_errors(self, text):
"""Исправляем типичные ошибки OCR"""
corrected = text
# Замены символов, которые часто путает OCR
common_mistakes = {
'0': 'O', # Ноль и буква O
'1': 'I', # Единица и I
'5': 'S', # Пять и S
'B': '8', # B и 8
}
# Контекстно-зависимые замены
for wrong, correct in common_mistakes.items():
corrected = corrected.replace(wrong, correct)
# Исправление дат (01.02.2023 -> 01.02.2023)
corrected = re.sub(r'(\d{2})[.,]?(\d{2})[.,]?(\d{4})',
r'\1.\2.\3', corrected)
return corrected
Если нужно строить сложные пайплайны обработки документов, посмотрите как мы делали RAG-систему для анализа таблиц - многие принципы похожи.
Что делать, если не хватает данных
Бывает, что документы конфиденциальные или их просто мало. Варианты:
- Синтетическая генерация - создавайте похожие документы с помощью шаблонов
- Дообучение на публичных данных - найдите похожие документы в открытых источниках
- Активное обучение - дообучайте модель постепенно, на самых сложных примерах
- Используйте Few-shot подход - OLMocr 2 может доучиваться на лету
Мало данных - не приговор. Иногда 50 хорошо подобранных примеров дают больший прирост качества, чем 5000 случайных.
Вместо заключения: когда дообучение не поможет
Знайте, когда нужно остановиться. Дообучение OLMocr 2 не поможет, если:
- Документы настолько плохого качества, что человек их с трудом читает
- Нужно распознавать рукописный текст (OLMocr 2 для этого не предназначен)
- Требуется извлекать структурированные данные из сложных таблиц (лучше использовать специализированные инструменты)
- Документы на языках, которых нет в предобучении OLMocr 2
В этих случаях смотрите в сторону других моделей или комбинированных подходов. Иногда проще добавить предобработку изображений или постобработку текста, чем дообучать модель.
Главное - начинайте с малого. Возьмите 50 самых проблемных документов, дообучите модель, проверьте результат. Если работает - масштабируйте. Если нет - анализируйте, почему. OCR - не магия, а инженерия. Каждая ошибка модели имеет причину, и обычно эту причину можно устранить.