Files

16 KiB
Raw Permalink Blame History

Классификатор типов документов — задача 62625

Этот репозиторий — автономный тестовый прототип. Он не импортирует код Vetro и не меняет текущий механизм загрузки. Сначала модель необходимо обучить и измерить качество на документах, которых она не видела.

Текущее состояние модели

Текущая тестовая модель request_document_types.pt обучена распознавать только четыре типа документов:

Значение RequestFileType Тип документа
referral_for_repairs Направление на ремонт
inspection_act Акт осмотра
cc_approval Согласование страхового случая
inspection_photo Фото осмотра

Документ другого типа модель пока не сможет корректно определить: она выберет наиболее похожий из этих четырёх классов либо вернёт unknown, если уверенность ниже установленного порога.

Полученные результаты распознавания

Порог принятия результата — 0.70. Все четыре проверенных документа были приняты моделью:

Файл Распознанный тип Уверенность Следующие варианты
1.pdf referral_for_repairs 99.6794% cc_approval — 0.2871%, inspection_act — 0.0221%
2.pdf inspection_act 97.1619% referral_for_repairs — 2.2419%, cc_approval — 0.3883%
3.png cc_approval 92.1763% referral_for_repairs — 7.6405%, inspection_act — 0.1245%
4.jpg inspection_photo 99.7211% inspection_act — 0.2390%, referral_for_repairs — 0.0324%

Каждый файл содержал одну страницу. Эти результаты подтверждают, что запуск инференса работает и модель уверенно классифицировала четыре конкретных примера. Они не являются оценкой общей точности модели: для такой оценки нужно выполнить команду evaluate на независимом test_dataset, который не использовался при обучении.

1. Подготовка окружения

Для Windows рекомендуется Python 3.12 (64-bit) и отдельное виртуальное окружение. PyTorch для Windows официально поддерживает Python до версии 3.12. Если Python ещё не установлен, используйте Python 3.12.10 — это последняя версия ветки 3.12 с готовым Windows installer.

python -m venv .venv-document-classifier
.\.venv-document-classifier\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

Если существующее окружение перестало запускаться

Файл .venv-document-classifier\pyvenv.cfg содержит путь к Python, на основе которого создавалось окружение. Если этот Python был удалён или перемещён, появляется ошибка Unable to create process. Такое окружение нужно создать заново после установки Python 3.12:

deactivate
Rename-Item .venv-document-classifier .venv-document-classifier-old
py -3.12 -m venv .venv-document-classifier
.\.venv-document-classifier\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

Старый каталог оставлен как резервная копия. После успешной проверки новой среды его можно удалить вручную.

В requirements.txt зафиксированы совместимые версии PyTorch и torchvision с CUDA 12.8 и официальный индекс cu128. Поэтому все зависимости устанавливаются одной командой. Обычный pip install torch torchvision без CUDA-индекса может установить CPU-сборку, которая не умеет работать с RTX 3060 Ti.

Если CPU-сборка уже установлена, исправьте текущее активное окружение:

python -m pip uninstall -y torch torchvision
python -m pip install --no-cache-dir -r requirements.txt

Проверьте, что PyTorch видит видеокарту:

python -c "import torch; ok=torch.cuda.is_available(); print('torch:',torch.__version__,'cuda build:',torch.version.cuda,'available:',ok,'GPU:',torch.cuda.get_device_name(0) if ok else 'нет')"

Ожидаемый результат на текущем ПК: True и NVIDIA GeForce RTX 3060 Ti. Если выводится False, установлена CPU-сборка PyTorch — до обучения нужно поставить CUDA-сборку командой выше.

Для первого запуска обучения нужен интернет: torchvision скачает предобученные ImageNet-веса MobileNetV3. Если интернета нет, можно добавить --no-pretrained, но качество обычно будет ниже.

2. Подготовка датасета

Создайте один каталог на каждый тип. Имя каталога должно быть точным строковым значением RequestFileType из Vetro, а не русским заголовком:

dataset/
├── referral_for_repairs/
│   ├── direction_0001.pdf
│   └── direction_0002.jpg
├── inspection_act/
│   ├── act_0001.pdf
│   └── act_0002.png
└── check/
    ├── invoice_0001.pdf
    └── invoice_0002.pdf

Поддерживаются PDF, PNG, JPG/JPEG, BMP, TIFF и WEBP. DOC/DOCX/XLS следует заранее преобразовать в PDF. Один многостраничный PDF считается одним документом: все его страницы попадут только в train или только в validation.

Практические требования к данным:

  • минимум — 2 документа на тип, разумный старт — 50100;
  • лучше 200+ документов на каждый часто встречающийся тип;
  • не складывайте копии одного документа под разными именами;
  • включите сканы и фото разного качества, документы разных страховых компаний;
  • номера дел, ФИО и прочие персональные данные должны храниться только в защищённой инфраструктуре; этот скрипт никуда их не отправляет;
  • число документов по типам желательно выровнять. В коде есть компенсация дисбаланса классов, но она не заменяет реальные примеры.

Отложите отдельный каталог test_dataset (обычно 1020% исходных документов) до обучения. Он должен иметь ту же структуру и не должен пересекаться с dataset. Встроенный validation нужен для выбора эпохи, а test_dataset — для честной финальной оценки.

3. Обучение

python document_type_classifier.py train `
  --data .\dataset `
  --model .\models\request_document_types.pt `
  --device cuda `
  --epochs 25 `
  --batch-size 64 `
  --workers 0 `
  --log-every 10

Эти значения подобраны для текущего компьютера:

  • AMD Ryzen 5 7500F: 6 ядер / 12 потоков;
  • 32 ГБ оперативной памяти;
  • NVIDIA GeForce RTX 3060 Ti, 8 ГБ видеопамяти.

По умолчанию уже используются batch-size=64, workers=0, размер изображения 224×224 и mixed precision. В памяти хранится только индекс путей и страниц; каждое изображение декодируется непосредственно перед своим batch. Это не позволяет фотографиям высокого разрешения занять всю оперативную память перед первой эпохой. Явные параметры в примере оставлены для воспроизводимости. Если появляется CUDA out of memory, сначала установите --batch-size 32, затем 16. Если CUDA работает нестабильно, добавьте --no-amp; для принудительного CPU используйте --device cpu --batch-size 16 --workers 0.

Во время запуска логируются сканирование и состав датасета, чтение каждых 25 документов, загрузка модели, каждый 10-й batch, validation, время эпохи и примерное оставшееся время. Частоту можно изменить параметрами --dataset-log-every и --log-every.

Скрипт печатает val_accuracy после каждой эпохи, сохраняет только лучшую модель и останавливается после пяти эпох без улучшения.

Реальные JPEG из Vetro могут содержать неполный последний блок или нестандартную структуру, хотя нормально открываются браузером. Для таких файлов включён tolerant-режим Pillow: доступная часть изображения участвует в обучении. Сообщение Пропуск поврежденного файла теперь остаётся только для файлов, которые действительно невозможно декодировать.

4. Честная проверка

python document_type_classifier.py evaluate `
  --model .\models\request_document_types.pt `
  --data .\test_dataset

В отчёте:

  • accuracy_with_unknown_as_error — доля всех верных ответов;
  • accepted_share — доля документов, для которых уверенность не ниже порога;
  • by_expected_type — ошибки по каждому реальному типу.

Для автозагрузки недостаточно одной общей accuracy. Проверьте каждый тип и особенно пары, которые модель путает. Рекомендуемый критерий пилота: не менее 95% точности среди принятых ответов; остальные файлы должны оставаться на ручном выборе типа.

Порог можно сделать строже:

python document_type_classifier.py evaluate `
  --model .\models\request_document_types.pt `
  --data .\test_dataset `
  --threshold 0.85

5. Распознавание

Один документ:

python document_type_classifier.py predict `
  --model .\models\request_document_types.pt `
  --file .\document.pdf

Каталог документов:

python document_type_classifier.py predict `
  --model .\models\request_document_types.pt `
  --file .\incoming

На каждый файл выводится одна JSON-строка:

{"file":"document.pdf","document_type":"inspection_act","confidence":0.9631,"accepted":true,"pages":2,"alternatives":[...]}

Если уверенность ниже 0.70, document_type будет unknown и accepted=false. При интеграции такой документ нужно показывать пользователю для ручного выбора. alternatives полезны для интерфейса и анализа ошибок.

Все команды следует выполнять из корня репозитория.

6. Возможная интеграция после завершения тестового пилота

  1. Загрузить модель один раз при старте отдельного worker/API-сервиса, а не заново для каждого HTTP-запроса.
  2. После получения временного файла вызвать классификацию до document.upload_file(...).
  3. Проверить, что предсказанная строка входит в RequestFileType.
  4. При accepted=true передать её как filetype; при false сохранить текущий ручной выбор.
  5. Логировать ожидаемый/исправленный пользователем тип и confidence. Эти исправления формируют следующую версию датасета.
  6. Версионировать файл модели и иметь возможность мгновенно выключить автоклассификацию конфигурационным флагом.

Не рекомендуется запускать тяжёлый инференс синхронно внутри нескольких web-процессов без замера времени и памяти. Для промышленной интеграции лучше обернуть классификатор внутренним API или фоновой задачей и ограничить размер и число страниц входного файла.

7. Скачивание документов через авторизованный браузер

Создайте, например, links.txt, указав одну HTTP/HTTPS-ссылку на строку:

https://example.org/document-1.pdf
https://example.org/document-2.jpg

Скрипт не скачивает файлы HTTP-клиентом Python. Он последовательно передаёт ссылки системному браузеру, поэтому используется уже существующая браузерная авторизация, а имя и расширение файла определяет сам сервер.

Перед запуском откройте настройки загрузок Chrome/Edge:

  1. Установите каталог загрузки: .\downloads.
  2. Отключите запрос места сохранения для каждого файла.
  3. Разрешите сайту автоматическое скачивание нескольких файлов, если браузер покажет соответствующий запрос.

Затем запустите:

python download_files.py links.txt

Пустые строки и строки, начинающиеся с #, игнорируются. Между ссылками по умолчанию выдерживается пауза 1.5 секунды. Для пробного запуска первых десяти:

python download_files.py links.txt --limit 10

Если выполнение было прервано после 350-й ссылки:

python download_files.py links.txt --start 351

Пауза настраивается параметром --delay, например --delay 3. Скрипт не переименовывает файлы: браузер сохраняет оригинальное имя из ответа сервера.