Image-to-Text
Transformers
Safetensors
English
Russian
pp_ocrv6_small_rec
captcha
ocr
minecraft
pp-ocrv6
text-recognition
cyrillic
Instructions to use Titlehhhh/captchaocr-ppocrv6 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Titlehhhh/captchaocr-ppocrv6 with Transformers:
# Use a pipeline as a high-level helper # Warning: Pipeline type "image-to-text" is no longer supported in transformers v5. # You must load the model directly (see below) or downgrade to v4.x with: # pip install "transformers<5.0.0" from transformers import pipeline pipe = pipeline("image-to-text", model="Titlehhhh/captchaocr-ppocrv6")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Titlehhhh/captchaocr-ppocrv6", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Upload folder using huggingface_hub
Browse files- README.md +108 -254
- finetune_meta.json +5 -9
- model.safetensors +1 -1
README.md
CHANGED
|
@@ -1,296 +1,150 @@
|
|
| 1 |
---
|
| 2 |
license: apache-2.0
|
|
|
|
|
|
|
|
|
|
| 3 |
library_name: transformers
|
| 4 |
-
|
| 5 |
tags:
|
| 6 |
-
- captcha
|
| 7 |
-
- ocr
|
| 8 |
-
- minecraft
|
| 9 |
-
-
|
| 10 |
-
-
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
| 12 |
---
|
| 13 |
|
| 14 |
# CaptchaOCR PP-OCRv6 — a text recogniser for Minecraft anti-bot captchas
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
> [`PaddlePaddle/PP-OCRv6_medium_rec_safetensors`](https://huggingface.co/PaddlePaddle/PP-OCRv6_medium_rec_safetensors),
|
| 20 |
-
> trained by us on the [CaptchaOCR dataset](https://huggingface.co/datasets/Titlehhhh/captchaocr-dataset)
|
| 21 |
-
> — our synthetic Minecraft anti-bot captchas. The published weights are the **weight
|
| 22 |
-
> interpolation (WiSE-FT style "soup") with α = 0.4** between the fine-tuned checkpoint
|
| 23 |
-
> (epoch 7 of a 20-epoch run) and the pretrained base model.
|
| 24 |
-
>
|
| 25 |
-
> **Measured on 7 captcha types that were never trained on** (whole plugins held out,
|
| 26 |
-
> 3 500 images, exact match on the normalised `text`):
|
| 27 |
-
>
|
| 28 |
-
> | | exact match (median over the 7 types) | CER | exact match (micro, 3 500 images) |
|
| 29 |
-
> |---|---|---|---|
|
| 30 |
-
> | **the weights published here** (α = 0.4) | **0.638** | 0.1503 | **0.6123** |
|
| 31 |
-
> | the untouched base model (α = 0) | 0.588 | 0.1657 | 0.5646 |
|
| 32 |
-
> | the fine-tune on its own (α = 1) | 0.480 | 0.2233 | 0.5480 |
|
| 33 |
-
>
|
| 34 |
-
> **The published weights are better than the base model: +5.0 points of median exact match
|
| 35 |
-
> and +4.8 points of micro.** Two honest caveats, both important:
|
| 36 |
-
>
|
| 37 |
-
> 1. **The best α was chosen on the same held-out set the result is measured on**, so the
|
| 38 |
-
> gain is optimistic — on new held-out plugin styles it will be smaller. The curve is
|
| 39 |
-
> smooth (the gain holds over the whole range α ∈ [0.25, 0.6]), so this is not a single
|
| 40 |
-
> lucky point.
|
| 41 |
-
> 2. **The fine-tune on its own (α = 1) is *worse* than the base** (0.480 vs 0.588 median):
|
| 42 |
-
> on 13 training types it specialises and loses the base's generality. The interpolation
|
| 43 |
-
> is what makes the fine-tune a net win.
|
| 44 |
-
>
|
| 45 |
-
> Every number above is a measurement, and the file it was measured in is named next to it.
|
| 46 |
-
|
| 47 |
-
> **RU:** веса опубликованы. Это **дообучение** PP-OCRv6 на нашем синтетическом датасете
|
| 48 |
-
> капч; опубликована **интерполяция весов с базой, α = 0.4** (WiSE-FT). На 7 удержанных
|
| 49 |
-
> типах (3 500 картинок): **0.638** exact (медиана) / 0.6123 micro против **0.588 / 0.5646**
|
| 50 |
-
> у нетронутой базовой модели. Само дообучение без интерполяции — **0.480**, то есть хуже
|
| 51 |
-
> базы. Оговорка: лучшее α выбрано на том же удержанном наборе, поэтому прирост оптимистичен.
|
| 52 |
|
| 53 |
## What it reads
|
| 54 |
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
|
|
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
| 63 |
|
| 64 |
-
|
|
|
|
|
|
|
| 65 |
|
| 66 |
-
|
| 67 |
-
captchas that open-source Minecraft anti-bot plugins draw, rendered by this project's own Java
|
| 68 |
-
generators (46 captcha types, 23 upstream plugins).
|
| 69 |
-
|
| 70 |
-
* **Architecture:** PP-OCRv6 medium recogniser — PP-LCNetV4 backbone + CTC head,
|
| 71 |
-
`transformers` class `PPOCRV6SmallRecForTextRecognition`
|
| 72 |
-
(`model_type: pp_ocrv6_small_rec`), 19 134 326 parameters, hidden size 192.
|
| 73 |
-
* **Dictionary:** the base model's own 18 710 classes (index 0 = CTC blank, space at the end).
|
| 74 |
-
* **Input:** the captcha **text band** (the strip of pixels that carries the answer), not the whole
|
| 75 |
-
frame: resized to height 48, width scaled proportionally and right-padded to 320, BGR channel
|
| 76 |
-
order, normalised as `(x / 255 - 0.5) / 0.5`.
|
| 77 |
-
* **Output:** per-timestep class probabilities; decoded greedily (CTC: collapse repeats, drop the
|
| 78 |
-
blank). Greedy decoding is the right decoder here — the answers are random strings, so a language
|
| 79 |
-
model has nothing to exploit.
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
## Measured results
|
| 86 |
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
checkpoint interpolated with the pretrained base model, **θ = 0.4 · θ_finetuned + 0.6 · θ_base**.
|
| 92 |
-
|
| 93 |
-
| α | median exact (7 types) | median CER | micro exact (3 500) | micro CER |
|
| 94 |
-
|---|---|---|---|---|
|
| 95 |
-
| 0.00 — the pretrained base | 0.588 | 0.1657 | 0.5646 | 0.2446 |
|
| 96 |
-
| 0.25 | 0.620 | 0.1483 | 0.5991 | 0.2132 |
|
| 97 |
-
| **0.40 — published** | **0.638** | **0.1503** | **0.6123** | **0.2004** |
|
| 98 |
-
| 0.50 | 0.614 | 0.1630 | 0.6123 | 0.1964 |
|
| 99 |
-
| 0.60 | 0.592 | 0.1773 | 0.6100 | 0.1951 |
|
| 100 |
-
| 0.75 | 0.542 | 0.2040 | 0.5949 | 0.1995 |
|
| 101 |
-
| 1.00 — the fine-tune alone | 0.480 | 0.2233 | 0.5480 | 0.2181 |
|
| 102 |
|
| 103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
-
|
|
| 106 |
|---|---|---|---|
|
| 107 |
-
| `
|
| 108 |
-
| `
|
| 109 |
-
| `
|
| 110 |
-
| `
|
| 111 |
-
| `
|
| 112 |
-
| `
|
| 113 |
-
| `
|
| 114 |
-
|
|
| 115 |
-
|
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
###
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
|
| 136 |
|---|---|---|
|
| 137 |
-
|
|
| 138 |
-
|
|
| 139 |
-
|
|
| 140 |
-
|
| 141 |
-
### Other captcha models measured on this dataset
|
| 142 |
-
|
| 143 |
-
All foreign models were measured by **one protocol** (`bench/bench_models.py`): the picture is
|
| 144 |
-
cropped by the answer band (`roi`), the input is normalised the same way for everybody, the greedy
|
| 145 |
-
decode is the same, and the metric is exact match on the normalised `text`. The set is the
|
| 146 |
-
**29 band-carrying types, 20 images per type (580 items)**, on the earlier 100-images-per-type
|
| 147 |
-
render of the dataset.
|
| 148 |
-
|
| 149 |
-
| model | band exact match | item set | source file |
|
| 150 |
-
|---|---|---|---|
|
| 151 |
-
| `PaddlePaddle/PP-OCRv6_medium_rec_onnx` | 0.5517 | 29 types / 580 items | `reports/bench_models/ppocrv6-medium.json` |
|
| 152 |
-
| `PaddlePaddle/PP-OCRv5_mobile_rec_onnx` | 0.4621 | 29 types / 580 items | `reports/bench_models/ppocrv5-mobile.json` |
|
| 153 |
-
| `PaddlePaddle/cyrillic_PP-OCRv5_mobile_rec_onnx` | 0.4621 | 29 types / 580 items | `reports/bench_models/ppocrv5-cyrillic.json` |
|
| 154 |
-
| `easyocr` | 0.3281 | 8 types / 64 items (the old `legacy64` subset) | `reports/bench_models/easyocr.json` |
|
| 155 |
-
| `anuashok/ocr-captcha-v3` | 0.2966 | 29 types / 580 items | `reports/bench_models/anuashok-v3.json` |
|
| 156 |
-
| `graycat660/doctr-crnn-vgg16-bn-russian-onnx` | 0.2776 | 29 types / 580 items | `reports/bench_models/doctr-crnn-ru.json` |
|
| 157 |
-
| `Graf-J/captcha-crnn-base` | 0.0828 | 29 types / 580 items | `reports/bench_models/grafj-crnn-base.json` |
|
| 158 |
-
| `Graf-J/captcha-crnn-finetuned` | 0.0672 | 29 types / 580 items | `reports/bench_models/grafj-crnn.json` |
|
| 159 |
-
| `Graf-J/captcha-conv-transformer-finetuned` | 0.0638 | 29 types / 580 items | `reports/bench_models/grafj-convtr.json` |
|
| 160 |
-
| `emelnov/ocr-captcha-v4-mailru` | 0.0431 | 29 types / 580 items | `reports/bench_models/emelnov-mailru.json` |
|
| 161 |
-
| `jtrecenti/txtcaptcha-crnn` | 0.0034 | 29 types / 580 items | `reports/bench_models/txtcaptcha-crnn.json` |
|
| 162 |
-
| `microsoft/trocr-base-printed` | **no score — the harness failed**: `ValueError: You need to specify either 'text' or 'text_target'.` | — | `reports/bench_models/trocr-base-printed.json` |
|
| 163 |
-
|
| 164 |
-
For the same base model, the whole frame instead of the band gives **0.0345** — 16× worse. The
|
| 165 |
-
cropper, not the model, decides this task.
|
| 166 |
-
|
| 167 |
-
### Our own models — **a different protocol, not comparable with the table above**
|
| 168 |
|
| 169 |
-
|
| 170 |
-
|---|---|---|---|---|
|
| 171 |
-
| **this repository: PP-OCRv6 + interpolation α = 0.4** | **0.638** | **0.6123** | 7 types / 3 500 images | `reports/TRAINING_PPOCR_V6_BIG.md` |
|
| 172 |
-
| our CRNN+CTC, trained from scratch | 0.372 | 0.381 | 4 types / 1 999 images | `reports/TRAINING_CRNN_BIG.md` |
|
| 173 |
-
| our CRNN+CTC on its **own training plugins** | 1.000 | 1.000 | 7 types — pure memorisation | `reports/TRAINING_CRNN_BIG.md` |
|
| 174 |
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
different image counts, different pipelines: the numbers are not directly comparable.
|
| 180 |
-
|
| 181 |
-
Every number in this card comes from a file of the **CaptchaOCR** project repository — the
|
| 182 |
-
measured results are in `reports/`, they are not typed by hand and nothing is extrapolated.
|
| 183 |
-
|
| 184 |
-
## Provenance and licence
|
| 185 |
-
|
| 186 |
-
* **Base model:** [`PaddlePaddle/PP-OCRv6_medium_rec_safetensors`](https://huggingface.co/PaddlePaddle/PP-OCRv6_medium_rec_safetensors) — Apache-2.0, by PaddlePaddle.
|
| 187 |
-
* **This model:** that base, fine-tuned on the CaptchaOCR dataset published here:
|
| 188 |
-
[`Titlehhhh/captchaocr-dataset`](https://huggingface.co/datasets/Titlehhhh/captchaocr-dataset)
|
| 189 |
-
(46 captcha types · 23 000 labelled PNG · 23 upstream plugins).
|
| 190 |
-
* **Licence of the weights:** Apache-2.0, inherited from the base model. The fine-tuning code and
|
| 191 |
-
this card are released under the same terms.
|
| 192 |
-
* **Licence of the dataset:** *not* Apache-2.0 — the dataset is split by the licence of the
|
| 193 |
-
upstream plugin of each captcha type. The dataset card has the per-type table, and the file
|
| 194 |
-
`LICENSE` in the dataset repository spells the same table out in full.
|
| 195 |
|
| 196 |
## How to use it
|
| 197 |
|
| 198 |
-
The model is a plain `transformers` text recogniser. `transformers` 5.x has **no** `image-to-text`
|
| 199 |
-
pipeline for a CTC recogniser any more (that task name now belongs to vision-language chat
|
| 200 |
-
models), so load it directly:
|
| 201 |
-
|
| 202 |
```python
|
| 203 |
import torch
|
| 204 |
-
from transformers import AutoModelForTextRecognition, AutoProcessor
|
| 205 |
from PIL import Image
|
|
|
|
| 206 |
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
model = AutoModelForTextRecognition.from_pretrained(REPO_ID).eval()
|
| 210 |
-
processor = AutoProcessor.from_pretrained(REPO_ID) # preprocessor_config.json + the dictionary
|
| 211 |
-
|
| 212 |
-
image = Image.open("captcha.png").convert("RGB")
|
| 213 |
-
x, y, w, h = (25, 77, 79, 35) # the answer band: take it from labels.jsonl
|
| 214 |
-
band = image.crop((x, y, x + w, y + h))
|
| 215 |
|
|
|
|
|
|
|
| 216 |
with torch.no_grad():
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
```
|
| 221 |
|
| 222 |
-
The
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
`preprocessor_config.json` and is also readable as `character_list.txt`.
|
| 226 |
|
| 227 |
-
|
| 228 |
-
> `preprocessor_config.json` (`image_mean = image_std = [0.5, 0.5, 0.5]`). The upstream file does
|
| 229 |
-
> not mention it, and the `transformers` image processor would then fall back to the ImageNet
|
| 230 |
-
> statistics — which is *not* what these weights were trained with.
|
| 231 |
|
| 232 |
-
|
| 233 |
-
|
|
|
|
|
|
|
| 234 |
|
| 235 |
## Reproducing
|
| 236 |
|
| 237 |
-
The training code lives in the **CaptchaOCR** project repository:
|
| 238 |
-
|
| 239 |
```powershell
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
.venv-gpu\Scripts\python.exe train\
|
| 244 |
-
|
| 245 |
-
.venv-gpu\Scripts\python.exe train\run_ppocr\export_hf.py --ckpt train\run_ppocr\big\soup_best.pt --out train\run_ppocr\big\export_soup
|
| 246 |
```
|
| 247 |
-
|
| 248 |
-
`train/finetune_ppocr.py` fine-tunes `PaddlePaddle/PP-OCRv6_medium_rec_safetensors` on the dataset, holds out whole **plugins**
|
| 249 |
-
(never a random image split: several captcha types have only a few distinct answers, so a random
|
| 250 |
-
split lets the exact gold answer of a test image appear in the training half), and reports exact
|
| 251 |
-
match and CER per type plus the median over types. `train/ppocr_data.py` holds the dataset loader
|
| 252 |
-
and the preprocessing shown above.
|
| 253 |
-
|
| 254 |
-
The measured report of the run quoted above is `reports/TRAINING_PPOCR_V6_BIG.md` (the analysis)
|
| 255 |
-
and `reports/TRAINING_PPOCR_V6_BIG.json` (the numbers), in the project repository.
|
| 256 |
-
|
| 257 |
-
## Repository metadata
|
| 258 |
-
|
| 259 |
-
| file | what |
|
| 260 |
-
|---|---|
|
| 261 |
-
| `model.safetensors` | the weights: θ = 0.4·θ_finetuned (epoch 7, step 1 632) + 0.6·θ_pretrained |
|
| 262 |
-
| `config.json` | the architecture — copied from the base model, unchanged by the fine-tune |
|
| 263 |
-
| `preprocessor_config.json` | the input geometry, the normalisation and the 18 710-character dictionary |
|
| 264 |
-
| `processor_config.json` | which processor class `AutoProcessor` has to build |
|
| 265 |
-
| `character_list.txt` | the same dictionary, one character per line, index 0 = `blank` |
|
| 266 |
-
| `finetune_meta.json` | the provenance of this export (source checkpoint, epoch, step, α) |
|
| 267 |
-
|
| 268 |
-
There is deliberately **no** `pipeline_tag`: `transformers` 5.x removed the `image-to-text`
|
| 269 |
-
pipeline task (it belongs to vision-language chat models now), and a recogniser has to be called
|
| 270 |
-
through `AutoModelForTextRecognition`, as in the snippet above. `library_name: transformers` is
|
| 271 |
-
declared because the repository really is a `transformers` model.
|
| 272 |
-
|
| 273 |
-
## Limitations
|
| 274 |
-
|
| 275 |
-
* **Only the text band is read.** This is a recogniser, not a solver: it does not reverse strings,
|
| 276 |
-
does not turn Russian number words into digits and does not compute arithmetic.
|
| 277 |
-
* **No Cyrillic in the dictionary.** The base model's 18 710 classes contain no Cyrillic at
|
| 278 |
-
all, so the Cyrillic captcha types of the dataset cannot be expressed in this model's alphabet.
|
| 279 |
-
* **The data is synthetic.** Every image is a render of this project's own generators — faithful to
|
| 280 |
-
the upstream algorithms, but not a screenshot of a live server.
|
| 281 |
-
* **Generalisation is the hard part.** A recogniser can memorise a plugin's style instead of
|
| 282 |
-
learning the characters; only the type-held-out numbers mean anything.
|
| 283 |
-
* **The headline number is optimistic.** α = 0.4 was picked on the same 7 held-out types the
|
| 284 |
-
result is reported on, and the best checkpoint was picked the same way. Treat 0.638 as an upper
|
| 285 |
-
estimate on *new* plugin styles, not as a guarantee.
|
| 286 |
-
* **One hard type stays hard.** `out/laforetbrut/are-you-sure/code` is at 1.8 % exact match
|
| 287 |
-
(CER 0.68): the answer band of that type does not carry a clean text line.
|
| 288 |
-
* **The weights are an interpolation, not a clean fine-tune.** `model.safetensors` is
|
| 289 |
-
0.4·θ_finetuned + 0.6·θ_pretrained; the pure fine-tune is in the project repository
|
| 290 |
-
(`train/run_ppocr/big/best.pt`) and is *worse* on unseen plugin styles.
|
| 291 |
-
|
| 292 |
-
## Citation
|
| 293 |
-
|
| 294 |
-
This model is a fine-tune of PP-OCRv6 by PaddlePaddle (Apache-2.0). The dataset is the
|
| 295 |
-
CaptchaOCR dataset, re-rendered from open-source Minecraft anti-bot plugins. See the dataset card
|
| 296 |
-
for the provenance and the per-type licence of every captcha type.
|
|
|
|
| 1 |
---
|
| 2 |
license: apache-2.0
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
- ru
|
| 6 |
library_name: transformers
|
| 7 |
+
pipeline_tag: image-to-text
|
| 8 |
tags:
|
| 9 |
+
- captcha
|
| 10 |
+
- ocr
|
| 11 |
+
- minecraft
|
| 12 |
+
- pp-ocrv6
|
| 13 |
+
- text-recognition
|
| 14 |
+
datasets:
|
| 15 |
+
- Titlehhhh/captchaocr-dataset
|
| 16 |
+
base_model:
|
| 17 |
+
- PaddlePaddle/PP-OCRv6_medium_rec_safetensors
|
| 18 |
---
|
| 19 |
|
| 20 |
# CaptchaOCR PP-OCRv6 — a text recogniser for Minecraft anti-bot captchas
|
| 21 |
|
| 22 |
+
A fine-tune of **PP-OCRv6_medium_rec** on 15 captcha types of the
|
| 23 |
+
[`Titlehhhh/captchaocr-dataset`](https://huggingface.co/datasets/Titlehhhh/captchaocr-dataset) dataset.
|
| 24 |
+
Feed it one captcha image, get the string drawn on it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
## What it reads
|
| 27 |
|
| 28 |
+
Minecraft anti-bot plugins show a player a picture with a code and ask them to retype it.
|
| 29 |
+
Every plugin draws differently: its own font, canvas size, noise, distortion — and its own bugs.
|
| 30 |
+
The 20 types in the dataset are flat captcha images; this model was trained on the **15** of them
|
| 31 |
+
whose alphabet fits the PP-OCRv6 dictionary.
|
| 32 |
|
| 33 |
+
Trained on:
|
| 34 |
+
`Archy-X/Krypton/map`, `InstantlyMoist/Captcha/textcaptcha`, `JSH32/Minecaptcha/map`,
|
| 35 |
+
`LagBug/XProtect/code`, `LagBug/XProtect/map`, `haq/mapcha/map`, `irootdev/AnBot/captcha`,
|
| 36 |
+
`jonesdevelopment/sonar/{standard,legacy,complex}`, `just-captcha/ProstoCaptcha/map`,
|
| 37 |
+
`ringoame196-s-mcPlugin/ReproductionCAPTCHA/map`, `BotFilter/map`, `CaptchaVerifyZ/map`,
|
| 38 |
+
`GalleryCaptcha/ru-web`.
|
| 39 |
|
| 40 |
+
**Not supported:** `GalleryCaptcha/{ru-numberword, ru-numberword-caption, ru-symbols}` and
|
| 41 |
+
`LimboFilter/{map, symbols}` — these are Cyrillic, and the PP-OCRv6 dictionary contains no
|
| 42 |
+
Cyrillic letters at all.
|
| 43 |
|
| 44 |
+
## What this model is
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
+
| | |
|
| 47 |
+
|---|---|
|
| 48 |
+
| base | `PaddlePaddle/PP-OCRv6_medium_rec_safetensors` (Apache-2.0) |
|
| 49 |
+
| parameters | 19 176 118 |
|
| 50 |
+
| classes | 18 710 (index 0 = blank), the pretrained head is kept, not replaced |
|
| 51 |
+
| fine-tune | 15 types × 800 images, 5 epochs, 1 875 steps, batch 32, lr 1e-5, fp16 |
|
| 52 |
+
| best checkpoint | epoch 2 |
|
| 53 |
+
| weight interpolation | **none** (α = 1.0) — see "Measured results" |
|
| 54 |
|
| 55 |
## Measured results
|
| 56 |
|
| 57 |
+
Measured on a **fresh generator run**: 20 types × 200 = 4 000 images that were never used for
|
| 58 |
+
training or for choosing the epoch. 15 types were scored (the 5 Cyrillic ones are outside the
|
| 59 |
+
dictionary), 3 000 images in total. Crop by the text band when the type has one, full frame
|
| 60 |
+
otherwise; greedy CTC decode; exact match on `text` (letters/digits of any script plus `+-*/=`).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
+
| aggregate | value |
|
| 63 |
+
|---|---|
|
| 64 |
+
| **median exact match over 15 types** | **0.920** |
|
| 65 |
+
| median CER | 0.021 |
|
| 66 |
+
| micro exact match (3 000 images) | 0.745 |
|
| 67 |
+
| micro CER | 0.098 |
|
| 68 |
|
| 69 |
+
| type | n | exact | CER |
|
| 70 |
|---|---|---|---|
|
| 71 |
+
| `CaptchaVerifyZ/map` | 200 | **1.000** | 0.000 |
|
| 72 |
+
| `ringoame196-s-mcPlugin/ReproductionCAPTCHA/map` | 200 | 0.995 | 0.001 |
|
| 73 |
+
| `irootdev/AnBot/captcha` | 200 | 0.985 | 0.005 |
|
| 74 |
+
| `Archy-X/Krypton/map` | 200 | 0.980 | 0.004 |
|
| 75 |
+
| `GalleryCaptcha/ru-web` | 200 | 0.945 | 0.014 |
|
| 76 |
+
| `haq/mapcha/map` | 200 | 0.945 | 0.014 |
|
| 77 |
+
| `BotFilter/map` | 200 | 0.935 | 0.014 |
|
| 78 |
+
| `JSH32/Minecaptcha/map` | 200 | 0.920 | 0.021 |
|
| 79 |
+
| `jonesdevelopment/sonar/legacy` | 200 | 0.830 | 0.052 |
|
| 80 |
+
| `jonesdevelopment/sonar/complex` | 200 | 0.805 | 0.060 |
|
| 81 |
+
| `just-captcha/ProstoCaptcha/map` | 200 | 0.785 | 0.044 |
|
| 82 |
+
| `jonesdevelopment/sonar/standard` | 200 | 0.695 | 0.101 |
|
| 83 |
+
| `InstantlyMoist/Captcha/textcaptcha` | 200 | 0.220 | 0.438 |
|
| 84 |
+
| `LagBug/XProtect/code` | 200 | 0.065 | 0.351 |
|
| 85 |
+
| `LagBug/XProtect/map` | 200 | 0.065 | 0.343 |
|
| 86 |
+
|
| 87 |
+
**Known weak types.** `LagBug/XProtect/code` and `/map` are barely read (6.5 %): they are the same
|
| 88 |
+
130×130 sheet with per-character cumulative translation and 51 interference lines. `InstantlyMoist`
|
| 89 |
+
(22 %) is a 128×128 sheet with thin diagonal noise. Neither is a decoding problem — the model simply
|
| 90 |
+
never learned these two drawing styles well enough at 800 images each.
|
| 91 |
+
|
| 92 |
+
### Why there is no weight interpolation here
|
| 93 |
+
|
| 94 |
+
Weight interpolation towards the base (WiSE-FT) was what made the **previous** version of this
|
| 95 |
+
repository useful: a fine-tune on a few types degraded unseen plugins, so α = 0.4 was published.
|
| 96 |
+
This model is trained on most of the types it is evaluated on, so interpolation now only drags it
|
| 97 |
+
back towards the base. Measured on 6 held-out types, 1 200 images (200 per type):
|
| 98 |
+
|
| 99 |
+
| α | median exact | CER |
|
| 100 |
|---|---|---|
|
| 101 |
+
| 0.0 (base) | 0.600 | 0.164 |
|
| 102 |
+
| 0.4 | 0.738 | 0.089 |
|
| 103 |
+
| 0.8 | 0.858 | 0.046 |
|
| 104 |
+
| **1.0 (published)** | **0.883** | 0.035 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
|
| 106 |
+
### What it is NOT good at
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
+
A different plugin that draws in a style not present in the dataset will not be handled: this is a
|
| 109 |
+
fine-tune for a **known set of captcha types with new images**, not a general captcha solver.
|
| 110 |
+
Measured generalization to unseen plugins for a comparable fine-tune sits around 0.4–0.6 median
|
| 111 |
+
exact match, and that is the honest expectation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
## How to use it
|
| 114 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
```python
|
| 116 |
import torch
|
|
|
|
| 117 |
from PIL import Image
|
| 118 |
+
from transformers import PPOCRV6SmallRecForTextRecognition, PPOCRV6SmallRecImageProcessor
|
| 119 |
|
| 120 |
+
model = PPOCRV6SmallRecForTextRecognition.from_pretrained("Titlehhhh/captchaocr-ppocrv6")
|
| 121 |
+
proc = PPOCRV6SmallRecImageProcessor.from_pretrained("Titlehhhh/captchaocr-ppocrv6")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
|
| 123 |
+
image = Image.open("001.png").convert("RGB")
|
| 124 |
+
px = proc(images=[image], return_tensors="pt")["pixel_values"]
|
| 125 |
with torch.no_grad():
|
| 126 |
+
logits = model.head.head(model.head.encoder(
|
| 127 |
+
model.model(px).last_hidden_state).last_hidden_state)
|
| 128 |
+
# greedy CTC decode against character_list.txt
|
| 129 |
```
|
| 130 |
|
| 131 |
+
The dictionary ships with the repository: `character_list.txt` (18 710 entries, index 0 = blank,
|
| 132 |
+
the same list as in `preprocessor_config.json`). The images are normalised with mean = std = 0.5
|
| 133 |
+
(PaddleOCR convention), which is already patched into `preprocessor_config.json`.
|
|
|
|
| 134 |
|
| 135 |
+
## Provenance and licence
|
|
|
|
|
|
|
|
|
|
| 136 |
|
| 137 |
+
Base model: `PaddlePaddle/PP-OCRv6_medium_rec_safetensors`, Apache-2.0.
|
| 138 |
+
The dataset is synthetic: the images are re-renders of captchas drawn by open-source Minecraft
|
| 139 |
+
plugins, and each type carries the licence of its upstream (see the dataset card).
|
| 140 |
+
This repository's weights are a derivative of the Apache-2.0 base.
|
| 141 |
|
| 142 |
## Reproducing
|
| 143 |
|
|
|
|
|
|
|
| 144 |
```powershell
|
| 145 |
+
.venv-gpu\Scripts\python.exe train\finetune_ppocr.py --out train\runs\ppocrv6\all20 ^
|
| 146 |
+
--limit-per-type 1000 --holdout-per-type 200 --train-frames --val-types ^
|
| 147 |
+
--epochs 5 --max-minutes 16 --eval-every 1 --batch-size 32 --lr 1e-5 --head-lr 1e-5 --workers 6
|
| 148 |
+
.venv-gpu\Scripts\python.exe train\export_ppocr_hf.py ^
|
| 149 |
+
--ckpt train\runs\ppocrv6\all20\best.pt --soup-alpha 1.0 --out train\runs\ppocrv6\all20\export_alpha1
|
|
|
|
| 150 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
finetune_meta.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
{
|
| 2 |
"base_model": "PaddlePaddle/PP-OCRv6_medium_rec_safetensors",
|
| 3 |
-
"checkpoint": "C:\\Users\\Title\\Projects\\CapthaModel\\train\\
|
| 4 |
-
"epoch":
|
| 5 |
-
"step":
|
| 6 |
-
"soup_alpha":
|
| 7 |
"classes": 18710,
|
| 8 |
"parameters": 19176118,
|
| 9 |
"tensors": 308,
|
|
@@ -20,9 +20,5 @@
|
|
| 20 |
]
|
| 21 |
},
|
| 22 |
"transformers_class": "PPOCRV6SmallRecForTextRecognition",
|
| 23 |
-
"
|
| 24 |
-
"source_checkpoint": "C:\\Users\\Title\\Projects\\CapthaModel\\train\\run_ppocr\\big\\best.pt",
|
| 25 |
-
"source_epoch": 7,
|
| 26 |
-
"source_step": 1632,
|
| 27 |
-
"held_out_median_exact": 0.638
|
| 28 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"base_model": "PaddlePaddle/PP-OCRv6_medium_rec_safetensors",
|
| 3 |
+
"checkpoint": "C:\\Users\\Title\\Projects\\CapthaModel\\train\\runs\\ppocrv6\\all20\\best.pt",
|
| 4 |
+
"epoch": 2,
|
| 5 |
+
"step": 1125,
|
| 6 |
+
"soup_alpha": 1.0,
|
| 7 |
"classes": 18710,
|
| 8 |
"parameters": 19176118,
|
| 9 |
"tensors": 308,
|
|
|
|
| 20 |
]
|
| 21 |
},
|
| 22 |
"transformers_class": "PPOCRV6SmallRecForTextRecognition",
|
| 23 |
+
"exported_by": "train\\export_ppocr_hf.py"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
}
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 76747448
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2185867aeedd38ca85f63f2e86272fc7eb22ddc3ca92db5c5f60b4f9bef12b22
|
| 3 |
size 76747448
|