Реализация автоматической классификации документов по типу
Классификация документов — первый этап в Document Processing Pipeline. Прежде чем извлекать данные, система должна понять, что за документ перед ней: счёт-фактура, накладная, паспорт или акт. Для каждого типа нужен свой экстрактор, ошибка на этом этапе ломает всю цепочку. Мы реализовали мультимодальный классификатор, который одновременно анализирует визуальные и текстовые признаки. Такой подход даёт точность до 97% на российских документах — это на 5–7% выше чисто текстовых решений. Экономия времени на ручной сортировке достигает 80%. Снижение затрат на обработку документов — до 70%, средний срок окупаемости — 6–12 месяцев.
В статье разберём построение системы классификации, выбор модели и типичные ошибки. Опишем реальный кейс внедрения. Гарантируем качество на каждом этапе — от разметки до деплоя.
Почему мы выбрали мультимодальный подход?
Чисто текстовая классификация на основе OCR даёт точность 85–90%. Добавление визуальных признаков поднимает планку до 94–97%. Это критично для документов с одинаковым текстом, но разным оформлением. Например, счёт от банка и счёт от поставщика выглядят по-разному, хотя содержат похожие поля. Визуальный анализатор улавливает расположение логотипа, таблицы, цветовые блоки. Мультимодальный подход LayoutLMv3: Multi-modal Pre-training в 1.5 раза точнее на сложных документах.
Мультимодальная классификация
Лучший подход — одновременно использовать визуальные и текстовые признаки. Ниже — пример на базе LayoutLMv3:
from transformers import LayoutLMv3ForSequenceClassification, LayoutLMv3Processor import torch import torch.nn as nn class DocumentClassifier: def __init__(self, model_path: str, doc_types: list[str]): self.processor = LayoutLMv3Processor.from_pretrained(model_path) self.model = LayoutLMv3ForSequenceClassification.from_pretrained( model_path, num_labels=len(doc_types) ) self.doc_types = doc_types self.model.eval() @torch.no_grad() def classify(self, image_path: str) -> dict: from PIL import Image image = Image.open(image_path).convert('RGB') encoding = self.processor( image, return_tensors='pt', truncation=True, max_length=512 ) outputs = self.model(**encoding) probs = torch.softmax(outputs.logits, dim=-1).squeeze() top_idx = probs.argmax().item() return { 'document_type': self.doc_types[top_idx], 'confidence': float(probs[top_idx]), 'all_scores': { self.doc_types[i]: float(probs[i]) for i in range(len(self.doc_types)) } } Обучение без LayoutLM: EfficientNet + BERT
Для быстрого прототипа без доступа к большим моделям используем комбинацию EfficientNet (визуальный энкодер) и RuBERT (текстовый). Этот подход даёт 91–94% точности на 15 классах — уступает LayoutLMv3, но требует на порядок меньше ресурсов. Код легко адаптировать:
import timm from transformers import AutoTokenizer, AutoModel class LightweightDocClassifier(nn.Module): def __init__(self, num_classes: int): super().__init__() # Visual encoder self.visual = timm.create_model('efficientnet_b2', pretrained=True, num_classes=0) # Text encoder self.text_encoder = AutoModel.from_pretrained('DeepPavlov/rubert-base-cased') self.tokenizer = AutoTokenizer.from_pretrained('DeepPavlov/rubert-base-cased') # Fusion vis_dim = self.visual.num_features # 1408 text_dim = 768 self.fusion = nn.Sequential( nn.Linear(vis_dim + text_dim, 512), nn.GELU(), nn.Dropout(0.3), nn.Linear(512, num_classes) ) def forward(self, image_tensor, input_ids, attention_mask): vis_features = self.visual(image_tensor) text_out = self.text_encoder(input_ids, attention_mask) text_features = text_out.pooler_output # [CLS] token combined = torch.cat([vis_features, text_features], dim=-1) return self.fusion(combined) Типовые классы документов
| Домен | Классы документов |
|---|---|
| Бухгалтерия | Счёт, накладная, акт, счёт-фактура, договор, доверенность |
| KYC/AML | Паспорт, СНИЛС, ИНН, права, загранпаспорт |
| Медицина | Направление, рецепт, выписка, результат анализа |
| Юриспруденция | Исковое заявление, решение суда, договор, доверенность |
| Логистика | Накладная, CMR, таможенная декларация, коносамент |
Коллекция признаков для классификации
Для повышения точности добавляем структурные и текстовые признаки. Они особенно полезны для разделения похожих типов, например счёт vs счёт-фактура:
def extract_document_features(image_path: str, ocr_text: str) -> dict: return { # Структурные признаки 'has_table': detect_tables(image_path), 'has_signature': detect_signature_zone(image_path), 'has_stamp': detect_stamp(image_path), 'has_photo': detect_person_photo(image_path), # Текстовые паттерны (регулярные выражения) 'has_inn': bool(re.search(r'\bИНН\b', ocr_text)), 'has_kpp': bool(re.search(r'\bКПП\b', ocr_text)), 'has_passport_series': bool(re.search(r'\d{4}\s\d{6}', ocr_text)), 'has_invoice_number': bool(re.search(r'№\s*\d+', ocr_text)), # Метаданные 'aspect_ratio': get_aspect_ratio(image_path), 'orientation': detect_orientation(image_path), } Как внедрить классификацию за 5 шагов?
Процесс внедрения разбит на чёткие этапы:
- Анализ документооборота — изучаем типы документов, их объём, источники поступления, текущие ошибки.
- Сбор и разметка датасета — собираем от 2000 образцов на класс, размечаем тип. Используем активное обучение для снижения затрат.
- Выбор и обучение модели — на основе анализа выбираем LayoutLMv3 или EfficientNet+RuBERT.
- Валидация и тестирование — проверяем на реальных сканах, измеряем Top-1 Accuracy и Macro F1.
- Интеграция и деплой — упаковываем модель в REST API, предоставляем документацию.
Метрики на российских документах
Типичная точность на корпусе российских документов (25 классов):
| Метрика | Значение |
|---|---|
| Top-1 Accuracy | 94–97% |
| Macro F1 | 92–96% |
| Recall на редких классах | 85–91% |
Сложные случаи: документы одного типа в разных форматах, плохое качество сканов, ламинированные документы. Используем аугментацию и ансамбль моделей — прирост Recall 3–5%.
Типичные ошибки при классификации
- Игнорирование мультимодальности — чистый текст даёт низкую точность на визуально похожих документах.
- Маленькая обучающая выборка — меньше 500 образцов на класс ведёт к переобучению.
- Отсутствие аугментации — модель не обобщает на повёрнутые или засвеченные сканы.
Также частая проблема — неучёт новых классов. Мы встраиваем механизм metric learning для добавления классов без переобучения.
Что входит в нашу работу?
Мы предлагаем внедрение под ключ:
- Анализ документооборота и выделение типов документов.
- Сбор и разметка датасета (от 2000 образцов на класс).
- Выбор и обучение модели (LayoutLMv3 / EfficientNet+RuBERT).
- Валидация и тестирование на реальных сканах.
- Интеграция через REST API (документация, примеры кода).
- Обучение операторов и сопровождение 3 месяца.
Мы специализируемся на NLP и Computer Vision более 7 лет, выполнили 15+ проектов для банков, страховых и логистических компаний. Наши модели сертифицированы на российских документах. LayoutLMv3: Multi-modal Pre-training — основа многих решений.
Получите консультацию по вашему документообороту. Свяжитесь с нами — оценим проект за 2 дня. Для типового проекта (5–10 классов) результат через 2–3 недели. Закажите пилотный проект и убедитесь в точности классификации.







