Titlehhhh commited on
Commit
f63f2cb
·
verified ·
1 Parent(s): 908bb75

CaptchaOCR PP-OCRv6: model card (weights pending the training run)

Browse files
Files changed (1) hide show
  1. README.md +186 -0
README.md ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ library_name: transformers
4
+ base_model: PaddlePaddle/PP-OCRv6_medium_rec_safetensors
5
+ tags:
6
+ - captcha
7
+ - ocr
8
+ - minecraft
9
+ - anti-bot
10
+ - pp-ocr
11
+ - image-to-text
12
+ - pytorch
13
+ pipeline_tag: image-to-text
14
+ ---
15
+
16
+ # CaptchaOCR PP-OCRv6 — a text recogniser for Minecraft anti-bot captchas
17
+
18
+ > ## Status: the weights are **not published yet**. This repository holds the model card only.
19
+ >
20
+ > The fine-tune on the [CaptchaOCR dataset](https://huggingface.co/datasets/Titlehhhh/captchaocr-dataset)
21
+ > has **not been run to completion yet**, so there is **no checkpoint, no `config.json` and no
22
+ > measured metric** in this repository. Nothing here is invented and nothing is extrapolated from a
23
+ > probe run: the numbers quoted below are the **measured numbers of the base model before
24
+ > fine-tuning**, and they are labelled as such.
25
+ >
26
+ > **RU:** репозиторий модели пока **пуст по весам** — здесь только карточка. Обучение на
27
+ > датасете `Titlehhhh/captchaocr-dataset` ещё не завершено, поэтому **метрики появятся после
28
+ > прогона** (плейслолдер ниже — это не выдуманные числа). Выкладка пробного чекпоинта (2 эпохи)
29
+ > сознательно не сделана: он хуже базовой модели.
30
+
31
+ ## What this model is
32
+
33
+ A fine-tune of **PP-OCRv6 medium** (PaddleOCR's text recogniser) on the CaptchaOCR dataset: the
34
+ captchas that open-source Minecraft anti-bot plugins draw, rendered by this project's own Java
35
+ generators (46 types, 4600 labelled PNG).
36
+
37
+ * **Architecture:** PP-OCRv6 medium recogniser — PP-LCNetV4 backbone + CTC head,
38
+ `transformers` class `PPOCRV6SmallRecForTextRecognition`
39
+ (`model_type: pp_ocrv6_small_rec`), 19.1 M parameters, hidden size 192.
40
+ * **Dictionary:** the base model's own 18 710 classes (index 0 = CTC blank, space at the end).
41
+ * **Input:** the captcha **text band** (the strip of pixels that carries the answer), not the whole
42
+ frame: resized to height 48, width scaled proportionally and right-padded to 320, BGR channel
43
+ order, normalised as `(x / 255 - 0.5) / 0.5`.
44
+ * **Output:** per-timestep class probabilities; decoded greedily (CTC: collapse repeats, drop the
45
+ blank). Greedy decoding is the right decoder here — the answers are random strings, so a language
46
+ model has nothing to exploit.
47
+
48
+ **The band is the whole game.** On the 29 dataset types that carry a band, the base model scores
49
+ `acc_micro = 0.5517` on the band and `acc_micro = 0.0345` on the whole frame — about 16× worse on
50
+ the frame. A solver must crop first.
51
+
52
+ ## Provenance and licence
53
+
54
+ * **Base model:** [`PaddlePaddle/PP-OCRv6_medium_rec_safetensors`](https://huggingface.co/PaddlePaddle/PP-OCRv6_medium_rec_safetensors)
55
+ — Apache-2.0, by PaddlePaddle.
56
+ * **This model:** that base, fine-tuned on the CaptchaOCR dataset published here:
57
+ [`Titlehhhh/captchaocr-dataset`](https://huggingface.co/datasets/Titlehhhh/captchaocr-dataset)
58
+ (46 captcha types · 4600 labelled PNG · 23 upstream plugins).
59
+ * **Licence of the weights:** Apache-2.0, inherited from the base model. The fine-tuning code and
60
+ this card are released under the same terms.
61
+ * **Licence of the dataset:** *not* Apache-2.0 — the dataset is split by the licence of the
62
+ upstream plugin of each captcha type. The dataset card has the per-type table.
63
+
64
+ ## Measured results
65
+
66
+ ### This repository's weights
67
+
68
+ **No metrics yet — the training run has not been completed.** This section will hold exact match
69
+ and CER per type and on the type-held-out split when the fine-tune is done. Until then, treat the
70
+ numbers below as the **starting point**, not as the result of this repository.
71
+
72
+ ### The base model, measured before fine-tuning (baseline)
73
+
74
+ These are measured numbers of `PaddlePaddle/PP-OCRv6_medium_rec_safetensors` **as it is**, on the
75
+ CaptchaOCR dataset — i.e. the point the fine-tune starts from:
76
+
77
+ | measurement | value | source |
78
+ |---|---|---|
79
+ | exact match (micro) on the 7 type-held-out types, band crop | 0.5586 | `train/run_ppocr/` zero-step baseline |
80
+ | exact match (median over those 7 types) | 0.60 | `train/run_ppocr/` zero-step baseline |
81
+ | CER (micro) on the same split | 0.2561 | `train/run_ppocr/` zero-step baseline |
82
+ | exact match (micro) on the 29 band-carrying types, band crop | 0.5517 | `reports/bench_models/ppocrv6-medium.json` |
83
+ | exact match (micro) on the same 29 types, whole frame | 0.0345 | `reports/bench_models/ppocrv6-medium.json` |
84
+
85
+ Both sources are files in the **CapthaModel** project repository; nothing above is a projection.
86
+
87
+ **Why the weights are not here yet.** A short probe run (2 epochs) of the fine-tune was measured
88
+ on the same held-out types and it came out **worse than the base model** — median exact match
89
+ 0.41 after epoch 1 and 0.24 after epoch 3, against 0.60 for the untouched base model. That
90
+ checkpoint is deliberately **not** published: a two-epoch probe is not a model, and shipping it as
91
+ one would misrepresent it.
92
+
93
+ ## How to use it
94
+
95
+ > The snippet below is the **preprocessing the project itself uses** (`train/ppocr_data.py`), and it
96
+ > was verified end-to-end against the base model on a real sample of the dataset (it decoded the
97
+ > held-out sample `JSH32/Minecaptcha/map/001.png`, band `[25, 77, 79, 35]`, as `PTAY`, which is the
98
+ > gold answer). It is written for the moment the weights are published — until then
99
+ > `from_pretrained("Titlehhhh/captchaocr-ppocrv6")` has nothing to load.
100
+
101
+ ```python
102
+ import json
103
+
104
+ import numpy as np
105
+ import torch
106
+ from huggingface_hub import hf_hub_download
107
+ from PIL import Image
108
+ from transformers import PPOCRV6SmallRecForTextRecognition
109
+
110
+ REPO_ID = "Titlehhhh/captchaocr-ppocrv6"
111
+
112
+ model = PPOCRV6SmallRecForTextRecognition.from_pretrained(REPO_ID).eval()
113
+ # the dictionary comes with the model repository (preprocessor_config.json)
114
+ character_list = json.load(
115
+ open(hf_hub_download(REPO_ID, "preprocessor_config.json"), encoding="utf-8")
116
+ )["character_list"]
117
+
118
+ HEIGHT, MAX_WIDTH = 48, 320
119
+
120
+
121
+ def prepare(band: Image.Image) -> torch.Tensor:
122
+ """band -> (1, 3, 48, 320) float tensor."""
123
+ scale = HEIGHT / max(1, band.height)
124
+ w = max(1, min(MAX_WIDTH, int(round(band.width * scale))))
125
+ small = band.convert("RGB").resize((w, HEIGHT), Image.BILINEAR)
126
+ a = np.asarray(small, dtype=np.float32) / 255.0
127
+ a = a[:, :, ::-1] # BGR, as PP-OCRv6 expects
128
+ a = (a - 0.5) / 0.5 # paddle normalisation
129
+ canvas = np.zeros((3, HEIGHT, MAX_WIDTH), dtype=np.float32)
130
+ canvas[:, :, :w] = a.transpose(2, 0, 1)
131
+ return torch.from_numpy(canvas)[None]
132
+
133
+
134
+ def greedy_decode(probs) -> str:
135
+ """CTC greedy decode: collapse repeats, drop the blank."""
136
+ best = probs.argmax(dim=-1)[0].tolist()
137
+ chars, prev = [], -1
138
+ for k in best:
139
+ if k != prev and k != 0:
140
+ chars.append(character_list[k])
141
+ prev = k
142
+ return "".join(chars)
143
+
144
+
145
+ image = Image.open("captcha.png")
146
+ x, y, w, h = (25, 77, 79, 35) # the answer band: take it from labels.jsonl
147
+ band = image.crop((x, y, x + w, y + h))
148
+
149
+ with torch.no_grad():
150
+ probs = model(pixel_values=prepare(band)).last_hidden_state
151
+
152
+ print(greedy_decode(probs))
153
+ ```
154
+
155
+ The band (`roi`) is not optional: on scene-like captchas the answer is one line among several, and
156
+ the whole frame makes the model read the wrong line.
157
+
158
+ ## Reproducing
159
+
160
+ The training code lives in the **CapthaModel** repository:
161
+
162
+ ```powershell
163
+ .venv-gpu\Scripts\python.exe train\finetune_ppocr.py --epochs 30 --batch-size 32
164
+ ```
165
+
166
+ `train/finetune_ppocr.py` fine-tunes `PaddlePaddle/PP-OCRv6_medium_rec_safetensors` on the
167
+ dataset, holds out whole **plugins** (never random splits — a random split leaks the exact gold
168
+ answer of 34 % of the test samples), and reports exact match and CER per type plus the median over
169
+ types. `train/ppocr_data.py` holds the dataset loader and the preprocessing shown above.
170
+
171
+ ## Limitations
172
+
173
+ * **Only the text band is read.** This is a recogniser, not a solver: it does not reverse strings,
174
+ does not turn Russian number words into digits and does not compute arithmetic.
175
+ * **No Cyrillic in the dictionary.** The base model's 18 710 classes contain no Cyrillic at all, so
176
+ the Cyrillic captcha types of the dataset cannot be expressed in this model's alphabet.
177
+ * **The data is synthetic.** Every image is a render of this project's own generators — faithful to
178
+ the upstream algorithms, but not a screenshot of a live server.
179
+ * **Generalisation is the hard part.** A recogniser can memorise a plugin's style instead of
180
+ learning the characters; only the type-held-out numbers mean anything.
181
+
182
+ ## Citation
183
+
184
+ This model is a fine-tune of PP-OCRv6 by PaddlePaddle (Apache-2.0). The dataset is the
185
+ CaptchaOCR dataset, re-rendered from open-source Minecraft anti-bot plugins. See the dataset card
186
+ for the provenance and the per-type licence of every captcha type.