File size: 2,958 Bytes
2d5ae88 3739346 2d5ae88 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | # Training & Fine-tuning
## Data scope
Train or fine-tune only with captcha images from PHPWind deployments you own
or are explicitly authorized to evaluate. Keep source, consent, and version
metadata with the dataset so results remain interpretable.
## Environment
```bash
pip install torch onnx onnxscript pillow numpy opencv-python
```
## Training from scratch
### 1. Prepare data
Label format `labels.json`:
```json
{
"captcha_001.png": {"label": "4821"},
"captcha_002.png": {"label": "9037"}
}
```
Image dir: ~150x60 RGB captcha PNGs; filenames must match label keys.
### 2. Train
```bash
python scripts/train_fixed.py \
<labels.json> <image_dir> <output.onnx> \
0.08 # val fraction
500 # epochs
1 # augmentation on/off (1=on)
rgb # RGB input (important: do NOT use grayscale)
```
Example:
```bash
python scripts/train_fixed.py \
data/1000_labels.json data/1000_raw \
models/my_model.onnx \
0.08 500 1 rgb
```
Outputs:
- `<output>.onnx` β final ONNX model
- `<output>.onnx.pt` β best-epoch PyTorch weights
### 3. Verify inference
```python
import numpy as np, onnxruntime as ort
from PIL import Image
sess = ort.InferenceSession("my_model.onnx", providers=["CPUExecutionProvider"])
im = Image.open("captcha.png").convert("RGB").resize((160,64), Image.BILINEAR)
x = np.asarray(im, dtype=np.float32).transpose(2,0,1)[None] / 255.0
logits = sess.run(None, {"input": x})[0]
code = "".join(str(int(logits[0,p].argmax())) for p in range(4))
```
## Fine-tuning
`train_fixed.py` auto-loads an existing `<output>.onnx.pt` and resumes from it:
```bash
cp models/captcha_1000_raw.onnx.pt models/finetuned.onnx.pt
python scripts/train_fixed.py <new_labels.json> <new_image_dir> models/finetuned.onnx 0.08 200 1 rgb
```
- 50-200 new labeled samples are enough for small changes.
- Mix old + new data when the generator changes a lot, to avoid catastrophic forgetting.
- Keep the same preprocessing (RGB 160x64 /255, no denoise) and augmentation.
## Parameters
| Param | Default | Description |
|---|---|---|
| val_frac | 0.1 | validation fraction |
| epochs | 400 | total epochs |
| aug | 1 | augmentation toggle |
| rgb | - | pass `rgb` for 3-channel input (recommended) |
## Key lessons
1. **Use RGB, not grayscale** β the digits are colored; grayscale loses information.
2. **Do NOT denoise** β morphological opening removes thin strokes, dropping val from 88.6% to 79.8%. With enough data the model learns to ignore noise lines itself.
3. **Position-preserving architecture, never global average pooling** β GAP destroys spatial position (val β 0%); per-column grouped pooling (20 cols β 4 positions) restores generalization.
4. **Human labels >> auto vision labels** β auto labels with ~35% noise crashed the model to 0%; clean manual labels are essential.
5. **No Gaussian noise augmentation** β the captcha already has noise lines; adding more obscures the training signal.
|