Infarondus commited on
Commit
abe60e1
·
verified ·
1 Parent(s): 451b67c

Update README_convnext_binding.md

Browse files
Files changed (1) hide show
  1. README_convnext_binding.md +148 -1
README_convnext_binding.md CHANGED
@@ -122,8 +122,155 @@ print(f"Не переплёт: {probs[0]:.1%} | Переплёт: {probs[1]:.1%}
122
 
123
  ---
124
 
125
- ## Цитирование
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  ```
128
  @misc{kleine-marchen-binding,
129
  author = {Infarondus},
 
122
 
123
  ---
124
 
125
+ # Kleine-Marchen — Binding Srednik Detector (DINOv2 Ensemble)
126
+
127
+ Ансамбль из 5 моделей на базе **DINOv2 ViT-Small** для классификации переплётов рукописей по наличию **средника** — центрального декоративного элемента крышки переплёта.
128
+
129
+ Модель разработана в рамках исследования рукописного фонда Российской государственной библиотеки (РГБ).
130
+
131
+ ---
132
+
133
+ ## Назначение
134
+
135
+ Модель решает задачу бинарной классификации изображений переплётов:
136
+
137
+ - **Класс 1 — со средником**: на крышке переплёта присутствует средник
138
+ - **Класс 0 — без средника**: средник отсутствует
139
+
140
+ Модель предназначена для автоматической предварительной сортировки больших коллекций фотографий переплётов рукописей. Окончательная верификация результатов производится специалистом.
141
+
142
+ ---
143
+
144
+ ## Метрики
145
+
146
+ Оценка проводилась методом 5-fold стратифицированной кросс-валидации.
147
+
148
+ | Метрика | Значение |
149
+ |---|---|
150
+ | Accuracy (OOF Ensemble) | **94.50%** |
151
+ | F1-macro (OOF Ensemble) | **0.9450** |
152
+ | Precision | 0.9454 |
153
+ | Recall | 0.9450 |
154
+
155
+ **Confusion Matrix (OOF, все 5 фолдов):**
156
+
157
+ | | Предсказано: без средника | Предсказано: со средником |
158
+ |---|---|---|
159
+ | **Реально: без средника** | 471 | 20 |
160
+ | **Реально: со средником** | 34 | 457 |
161
+
162
+ ---
163
+
164
+ ## Данные
165
+
166
+ - **Источник**: фотографии переплётов рукописей из фондов РГБ
167
+ - **Размер обучающей выборки**: 567 изображений на каждый класс (1134 итого)
168
+ - **Формат**: цветные фотографии переплётов на тёмном фоне
169
+ - **Разрешение при обучении**: 280×280 px
170
+
171
+ Датасет собирался итеративно: после каждого цикла обучения производился анализ ошибок и доразметка сложных случаев (изношенные переплёты, пограничные экземпляры).
172
+
173
+ ---
174
+
175
+ ## Архитектура
176
+
177
+ **Базовая модель**: `vit_small_patch14_dinov2.lvd142m` (DINOv2 ViT-Small, 22M параметров)
178
+
179
+ **Голова классификатора**:
180
+ ```
181
+ LayerNorm(384) → Linear(384→256) → GELU → Dropout(0.3) → Linear(256→2)
182
+ ```
183
+
184
+ **Стратегия обучения**: двухфазный fine-tuning
185
+ - Фаза 1 (6 эпох): обучение только головы, LR = 5e-4
186
+ - Фаза 2 (20 эпох): голова + последние 4 блока ViT, дифференциальный LR (голова: 3e-5, бэкбон: 2e-6)
187
+
188
+ **Ансамбль**: 5 моделей (по одной на каждый фолд) с усреднением вероятностей + TTA (5 аугментаций)
189
+
190
+ ---
191
+
192
+ ## Использование
193
+
194
+ Готовые скрипты для обучения, оценки и инференса доступны в репозитории:
195
+
196
+ **[https://github.com/Infarondus/Kleine-marchen](https://github.com/Infarondus/Kleine-marchen)**
197
+
198
+ ### Быстрый старт
199
+
200
+ ```python
201
+ import torch
202
+ import torch.nn as nn
203
+ import torch.nn.functional as F
204
+ import timm
205
+ import numpy as np
206
+ from PIL import Image
207
+ import albumentations as A
208
+ from albumentations.pytorch import ToTensorV2
209
+
210
+ MODEL_NAME = 'vit_small_patch14_dinov2.lvd142m'
211
+ IMAGE_SIZE = 280
212
+ DINO_MEAN = [0.485, 0.456, 0.406]
213
+ DINO_STD = [0.229, 0.224, 0.225]
214
+
215
+ def build_model():
216
+ backbone = timm.create_model(
217
+ MODEL_NAME, pretrained=False, num_classes=0,
218
+ img_size=IMAGE_SIZE, dynamic_img_size=True,
219
+ )
220
+ head = nn.Sequential(
221
+ nn.LayerNorm(backbone.embed_dim),
222
+ nn.Linear(backbone.embed_dim, 256),
223
+ nn.GELU(),
224
+ nn.Dropout(0.3),
225
+ nn.Linear(256, 2),
226
+ )
227
+ class DinoClassifier(nn.Module):
228
+ def __init__(self, b, h):
229
+ super().__init__()
230
+ self.backbone, self.head = b, h
231
+ def forward(self, x):
232
+ return self.head(self.backbone(x))
233
+ return DinoClassifier(backbone, head)
234
 
235
+ transform = A.Compose([
236
+ A.LongestMaxSize(max_size=IMAGE_SIZE),
237
+ A.PadIfNeeded(min_height=IMAGE_SIZE, min_width=IMAGE_SIZE,
238
+ border_mode=0, value=[255, 255, 255]),
239
+ A.Normalize(mean=DINO_MEAN, std=DINO_STD),
240
+ ToTensorV2(),
241
+ ])
242
+
243
+ # Загрузка модели
244
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
245
+ model = build_model().to(device)
246
+ ckpt = torch.load('fold_1_km.pth', map_location=device, weights_only=False)
247
+ model.load_state_dict(ckpt['model_state_dict'])
248
+ model.eval()
249
+
250
+ # Инференс
251
+ img = np.array(Image.open('binding.jpg').convert('RGB'))
252
+ tensor = transform(image=img)['image'].unsqueeze(0).to(device)
253
+ with torch.no_grad():
254
+ probs = F.softmax(model(tensor), dim=1)[0]
255
+
256
+ print(f"Без средника: {probs[0]:.1%} | Со средником: {probs[1]:.1%}")
257
+ ```
258
+
259
+ ### Рекомендуемый порог
260
+
261
+ При использовании ансамбля рекомендуется порог **0.55–0.75** для класса «со средником» в зависимости от допустимого уровня ложных срабатываний.
262
+
263
+ ---
264
+
265
+ ## Ограничения
266
+
267
+ - Модель обучена на фотографиях переплётов РГБ и может хуже работать на изображениях из других коллекций (domain shift)
268
+ - Сильно изношенные переплёты с плохо читаемым средником являются наиболее сложными случаями
269
+ - Не предназначена для работы с изображениями страниц, не являющихся переплётами — для фильтрации используйте модель `binding-detector-convnext` на первом этапе
270
+
271
+ ---
272
+ ## Цитирование
273
+ Если вы используете эту модель в исследовании, пожалуйста, укажите репозиторий:
274
  ```
275
  @misc{kleine-marchen-binding,
276
  author = {Infarondus},