refs #62625 добавил прототип классификатора типов документов

This commit is contained in:
2026-07-27 10:16:45 +03:00
commit 767a4c0a93
5 changed files with 1130 additions and 0 deletions

300
README.md Normal file
View File

@@ -0,0 +1,300 @@
# Классификатор типов документов — задача 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.
```powershell
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:
```powershell
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-сборка уже установлена, исправьте текущее активное окружение:
```powershell
python -m pip uninstall -y torch torchvision
python -m pip install --no-cache-dir -r requirements.txt
```
Проверьте, что PyTorch видит видеокарту:
```powershell
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, а не русским заголовком:
```text
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. Обучение
```powershell
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. Честная проверка
```powershell
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% точности среди принятых ответов; остальные файлы должны оставаться на
ручном выборе типа.
Порог можно сделать строже:
```powershell
python document_type_classifier.py evaluate `
--model .\models\request_document_types.pt `
--data .\test_dataset `
--threshold 0.85
```
## 5. Распознавание
Один документ:
```powershell
python document_type_classifier.py predict `
--model .\models\request_document_types.pt `
--file .\document.pdf
```
Каталог документов:
```powershell
python document_type_classifier.py predict `
--model .\models\request_document_types.pt `
--file .\incoming
```
На каждый файл выводится одна JSON-строка:
```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-ссылку на строку:
```text
https://example.org/document-1.pdf
https://example.org/document-2.jpg
```
Скрипт не скачивает файлы HTTP-клиентом Python. Он последовательно передаёт
ссылки системному браузеру, поэтому используется уже существующая браузерная
авторизация, а имя и расширение файла определяет сам сервер.
Перед запуском откройте настройки загрузок Chrome/Edge:
1. Установите каталог загрузки:
`.\downloads`.
2. Отключите запрос места сохранения для каждого файла.
3. Разрешите сайту автоматическое скачивание нескольких файлов, если браузер
покажет соответствующий запрос.
Затем запустите:
```powershell
python download_files.py links.txt
```
Пустые строки и строки, начинающиеся с `#`, игнорируются. Между ссылками по
умолчанию выдерживается пауза 1.5 секунды. Для пробного запуска первых десяти:
```powershell
python download_files.py links.txt --limit 10
```
Если выполнение было прервано после 350-й ссылки:
```powershell
python download_files.py links.txt --start 351
```
Пауза настраивается параметром `--delay`, например `--delay 3`. Скрипт не
переименовывает файлы: браузер сохраняет оригинальное имя из ответа сервера.