DocUA commited on
Commit
d54528e
·
1 Parent(s): 4505c9a

feat: Automatically set generation config's `pad_token_id` and `eos_token_id` from the tokenizer and suppress Hugging Face logging warnings.

Browse files
Files changed (2) hide show
  1. README.md +97 -15
  2. app_hf.py +12 -0
README.md CHANGED
@@ -11,25 +11,107 @@ license: apache-2.0
11
 
12
  # DeepSeek-OCR-2 & MedGemma-1.5 Multimodal Analysis
13
 
14
- Цей проект призначений для аналізу медичних та загальних документів за допомогою сучасних мультимодальних моделей: **DeepSeek-OCR-2** та **MedGemma-1.5-4B-IT**.
15
 
16
- ## 🚀 Основні можливості
17
 
18
- - **DeepSeek-OCR-2**: Високоточне розпізнавання тексту (OCR) на основі архітектури Mixture-of-Experts (MoE).
19
- - **MedGemma-1.5-4B-IT**: Мультимодальна модель від Google, спеціалізована на медичних зображеннях та текстах.
20
- - **Веб-інтерфейс Gradio**: Зручне завантаження зображень/PDF, вибір моделі та візуалізація результатів.
21
- - **ZeroGPU Support**: Оптимізовано для запуску на Hugging Face Spaces.
 
 
22
 
23
- ## 📦 Склад проекту
24
 
25
- - `app_hf.py`: Версія для Hugging Face з підтримкою ZeroGPU.
26
- - `app.py`: Локальна версія з підтримкою MPS (Metal Performance Shaders) для Mac.
27
- - `requirements.txt`: Список необхідних бібліотек.
 
28
 
29
- ## 🛠 Налаштування на Hugging Face Spaces
30
 
31
- 1. Додайте `HF_TOKEN` у **Settings -> Variables and secrets** для доступу до MedGemma.
32
- 2. Система автоматично запустить `app_hf.py` завдяки метаданим у цьому файлі.
 
 
33
 
34
- ---
35
- *Проект розроблено для тестування та демонстрації можливостей сучасних LLM у сфері розпізнавання медичних документів.*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  # DeepSeek-OCR-2 & MedGemma-1.5 Multimodal Analysis
13
 
14
+ Локальна демонстрація OCR та мультимодального аналізу, що стикає дві найсучасніші моделі Hugging Face: **deepseek-ai/DeepSeek-OCR-2** для загального OCR і **google/medgemma-1.5-4b-it** для медичних зображень.
15
 
16
+ ## 🚀 Що тут є
17
 
18
+ - **Гнучкий Gradio-інтерфейс**: підтримка завантаження PDF та зображень, вибір моделі, додатковий промпт, клавіші «очистити», «запустити», «зберегти в файл» і автоматичне очікування відповідей.
19
+ - **ZeroGPU-готовність**: `app_hf.py` оптимізовано для Hugging Face Spaces з переходом моделей на GPU тільки на час inference.
20
+ - **Локальна версія з MPS**: `app.py` підтримує запуск на Python + Metal (Mac) без ZeroGPU.
21
+ - **Модулі для порівняння**: `compare_models.py`, `test_real_docs.py` та інші демонструють, як застосувати моделі скриптово.
22
+ - **Підтримка PDF**: усереднювання через PyMuPDF (`fitz`) і перетворення кожної сторінки в зображення для подальшого аналізу.
23
+ - **Збереження результатів**: усі результати пишуться до `outputs/ocr_result_<timestamp>.txt`, а окремі структури для відлагодження (`outputs/`, `ocr_results*`, `temp_comp.png`).
24
 
25
+ ## 🧠 Архітектура
26
 
27
+ 1. **ModelManager** (`app_hf.py`/`app.py`) кешує завантаження під різні моделі, налаштовує `pad_token_id`, `eos_token_id` та відповідні `generation_config`.
28
+ 2. Вхід зображення або PDF (через `gr.Image` чи `gr.File`). Якщо це PDF, кожна сторінка рендериться через `fitz.Matrix(2, 2)`.
29
+ 3. DeepSeek запускається через метод `model.infer()` з файлами з диску. MedGemma — через `processor.apply_chat_template` + `model.generate()`.
30
+ 4. Вивід накопичується в пам’яті і показується в текстовому полі Gradio, кастомний промпт передається до обох моделей.
31
 
32
+ ## 🧰 Потрібне середовище
33
 
34
+ - Python 3.10+ (рекомендується 3.10/3.11 через сумісність із `transformers`).
35
+ - CUDA 11+ та GPU, якщо хочете запускати DeepSeek/MedGemma локально на CUDA; Mac з MPS теж підтримується.
36
+ - `hf_token` (особливо для MedGemma) з повноваженнями моделі.
37
+ - Залежності: `pip install -r requirements.txt`.
38
 
39
+ ## ⚙️ Налаштування
40
+
41
+ ### 1. Загальні кроки
42
+
43
+ ```bash
44
+ git clone https://github.com/deepseek-ai/DeepSeek-OCR-2.git
45
+ cd DeepSeek-OCR-2
46
+ python -m venv venv # або ваш улюблений venv
47
+ source venv/bin/activate
48
+ pip install -r requirements.txt
49
+ ```
50
+
51
+ ### 2. Для Hugging Face Spaces (ZeroGPU)
52
+
53
+ 1. У Settings ➜ Variables and secrets додайте `HF_TOKEN=<ваш токен>` (потрібен для `google/medgemma-1.5-4b-it`).
54
+ 2. Переконайтеся, що `app_hf.py` використовується як `app_file` (вказано у metadata).
55
+ 3. Spaces автоматично запускає `demo.queue().launch()`; GPU буде використовуватися тільки в `@spaces.GPU`.
56
+ 4. У критичних системах з нульовим GPU подбайте про `TRANSFORMERS_CACHE`, `HF_HOME`, `HF_HUB_CACHE` — вони вже прив’язані до `~/.cache/huggingface` або `/data/.huggingface`.
57
+
58
+ ### 3. Локальний запуск
59
+
60
+ ```bash
61
+ source venv/bin/activate
62
+ python app.py # Створює інтерфейс Gradio з підтримкою MPS/CUDA
63
+ ```
64
+
65
+ - Для MPS (Mac) переконайтеся, що `torch.backends.mps.is_available()` повертає `True`; після завершення скрипт викликає `torch.mps.empty_cache()`.
66
+ - При запуску на CUDA рекомендується додати перемінну `TRANSFORMERS_VERBOSITY=info` для діагностики та вивчати журнали.
67
+
68
+ ## 🎮 Як користуватись
69
+
70
+ 1. У веб-інтерфейсі завантажте зображення (`.png`, `.jpg`, `.jpeg`) або PDF.
71
+ 2. Оберіть модель: DeepSeek для OCR або MedGemma для медичних сценаріїв.
72
+ 3. За потреби напишіть **користувацький промпт** (див. `prompt_input`).
73
+ 4. Натисніть **«Запустити аналіз»**.
74
+ 5. Результат з’явиться у текстовому полі; можна зберегти кнопкою 💾 або завантажити файл.
75
+ 6. «Очистити» скидає усі поля.
76
+
77
+ ## 💾 Результати і структура виводу
78
+
79
+ - `outputs/ocr_result_<YYYYMMDD_HHMMSS>.txt`: основний текстовий файл із результатами (згенеровано через `save_result_to_file`).
80
+ - `ocr_results/` та `ocr_results_pdf12/`: історичні папки для тестових документів.
81
+ - `temp_comp.png`: проміжні зображення, які створюються під час розробки.
82
+ - `ocr_results_package.zip`: приклад пакетованих результатів.
83
+
84
+ ## 🧪 Тестування та сценарії
85
+
86
+ - `test_inference.py`, `test_real_docs.py`, `test_minimal.py`, `test_medgemma.py` — приклади запуску обох моделей без Gradio.
87
+ - `compare_models.py` — бенчмарк порівняння DeepSeek і MedGemma.
88
+ - `ocr_full_pdf12.py` — повна обробка PDF довжиною до 12 сторінок.
89
+ - `generate_test_image.py` — генерація синтетичного зображення для швидких перевірок.
90
+ - Запускайте тести через `python test_real_docs.py` тощо, переконайтесь, що моделі завантажені і в кеші.
91
+
92
+ ## 🛠️ Поширені проблеми
93
+
94
+ - `The following generation flags are not valid... temperature`: виникає при передачі параметрів із CLI – лог зараз приглушений.
95
+ - `attention mask and pad token id were not set`: переконайтеся, що `pad_token_id`/`eos_token_id` встановлені в токенізаторі й `generation_config`.
96
+ - `MedGemma` вимагає `HF_TOKEN` із доступом до моделі — без нього завантаження не пройде.
97
+ - `CUDA` або `MPS` може бути відсутній: `run_ocr` автоматично використовує `contextlib.nullcontext` і не вимагає GPU.
98
+ - Якщо бачите `torch.cuda.empty_cache()` або `gc.collect()` у логах — це нормальна очистка ZeroGPU-ресурсів.
99
+
100
+ ## 🗂️ Структура проекту
101
+
102
+ - `app_hf.py`: Gradio demo для Hugging Face Spaces + ZeroGPU, GPU-секція охоплена `spaces.GPU`.
103
+ - `app.py`: локальний Gradio-інтерфейс із підтримкою MPS.
104
+ - `compare_models.py`: скрипт порівняння.
105
+ - `convert_docs.py`, `convert_full_pdf.py`: конвертери та допоміжні утиліти.
106
+ - `requirements.txt`: основні залежності (`transformers`, `gradio`, `torch`, `Pillow`, `PyMuPDF`, `huggingface_hub`).
107
+ - `doc_images`, `doc_for_testing`: набір тестових файлів.
108
+
109
+ ## 🤝 Контрибуція
110
+
111
+ 1. Створіть issue з описом завдання/помилки.
112
+ 2. Відгалужте репозиторій, реалізуйте зміни, напишіть тести/опис.
113
+ 3. Відкрийте PR із обґрунтуванням впливу.
114
+
115
+ ## 📜 Ліцензія
116
+
117
+ Проект поширюється під ліцензією Apache-2.0. Деталі див. у `LICENSE`.
app_hf.py CHANGED
@@ -11,6 +11,7 @@ except ImportError:
11
 
12
  import gradio as gr
13
  from transformers import AutoModel, AutoTokenizer, AutoProcessor, AutoModelForImageTextToText
 
14
  import torch
15
  import os
16
  from PIL import Image
@@ -49,6 +50,7 @@ warnings.filterwarnings("ignore", message="CUDA is not available or torch_xla is
49
  warnings.filterwarnings("ignore", message="The following generation flags are not valid and may be ignored")
50
  warnings.filterwarnings("ignore", message="The attention mask and the pad token id were not set")
51
  warnings.filterwarnings("ignore", message="You are using a model of type .* to instantiate a model of type .*")
 
52
 
53
  # --- Configuration ---
54
  DEEPSEEK_MODEL = 'deepseek-ai/DeepSeek-OCR-2'
@@ -104,6 +106,11 @@ class ModelManager:
104
  )
105
  if hasattr(model, "config") and getattr(model.config, "pad_token_id", None) is None and getattr(tokenizer, "pad_token_id", None) is not None:
106
  model.config.pad_token_id = tokenizer.pad_token_id
 
 
 
 
 
107
  model.eval()
108
  self.models[model_name] = model
109
  self.processors[model_name] = tokenizer
@@ -120,6 +127,11 @@ class ModelManager:
120
  # Ensure pad_token_id is set
121
  if processor.tokenizer.pad_token_id is None:
122
  processor.tokenizer.pad_token_id = processor.tokenizer.eos_token_id
 
 
 
 
 
123
  self.models[model_name] = model
124
  self.processors[model_name] = processor
125
 
 
11
 
12
  import gradio as gr
13
  from transformers import AutoModel, AutoTokenizer, AutoProcessor, AutoModelForImageTextToText
14
+ from transformers import logging as hf_logging
15
  import torch
16
  import os
17
  from PIL import Image
 
50
  warnings.filterwarnings("ignore", message="The following generation flags are not valid and may be ignored")
51
  warnings.filterwarnings("ignore", message="The attention mask and the pad token id were not set")
52
  warnings.filterwarnings("ignore", message="You are using a model of type .* to instantiate a model of type .*")
53
+ hf_logging.set_verbosity_error()
54
 
55
  # --- Configuration ---
56
  DEEPSEEK_MODEL = 'deepseek-ai/DeepSeek-OCR-2'
 
106
  )
107
  if hasattr(model, "config") and getattr(model.config, "pad_token_id", None) is None and getattr(tokenizer, "pad_token_id", None) is not None:
108
  model.config.pad_token_id = tokenizer.pad_token_id
109
+ if hasattr(model, "generation_config"):
110
+ if getattr(model.generation_config, "pad_token_id", None) is None and getattr(tokenizer, "pad_token_id", None) is not None:
111
+ model.generation_config.pad_token_id = tokenizer.pad_token_id
112
+ if getattr(model.generation_config, "eos_token_id", None) is None and getattr(tokenizer, "eos_token_id", None) is not None:
113
+ model.generation_config.eos_token_id = tokenizer.eos_token_id
114
  model.eval()
115
  self.models[model_name] = model
116
  self.processors[model_name] = tokenizer
 
127
  # Ensure pad_token_id is set
128
  if processor.tokenizer.pad_token_id is None:
129
  processor.tokenizer.pad_token_id = processor.tokenizer.eos_token_id
130
+ if hasattr(model, "generation_config"):
131
+ if getattr(model.generation_config, "pad_token_id", None) is None:
132
+ model.generation_config.pad_token_id = processor.tokenizer.pad_token_id
133
+ if getattr(model.generation_config, "eos_token_id", None) is None:
134
+ model.generation_config.eos_token_id = processor.tokenizer.eos_token_id
135
  self.models[model_name] = model
136
  self.processors[model_name] = processor
137