Files

301 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Классификатор типов документов — задача 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`. Скрипт не
переименовывает файлы: браузер сохраняет оригинальное имя из ответа сервера.