Upload docs/TRAINING.md with huggingface_hub
Browse files- docs/TRAINING.md +112 -43
docs/TRAINING.md
CHANGED
|
@@ -1,24 +1,20 @@
|
|
| 1 |
-
# 训练与微调
|
| 2 |
|
| 3 |
-
|
| 4 |
-
> (4 digit heads) on 160x64 RGB images, CrossEntropy loss, Adam + ReduceLROnPlateau.
|
| 5 |
-
> 997 human-labeled samples reached 88.6% validation / 87.6% real login accuracy.
|
| 6 |
-
> To fine-tune, place a `.pt` checkpoint at the output path and the script resumes from it.
|
| 7 |
-
> Key lessons: use RGB (not grayscale), **do NOT denoise**, keep per-column pooling (never global
|
| 8 |
-
> average pooling), human labels >> auto labels, and skip Gaussian noise augmentation.
|
| 9 |
|
| 10 |
-
##
|
|
|
|
|
|
|
| 11 |
|
| 12 |
```bash
|
| 13 |
-
# Python 3.10+ (测试于 3.14)
|
| 14 |
pip install torch onnx onnxscript pillow numpy opencv-python
|
| 15 |
```
|
| 16 |
|
| 17 |
-
## 从零训练
|
| 18 |
|
| 19 |
-
|
| 20 |
|
| 21 |
-
标签格式 `labels.json`
|
| 22 |
```json
|
| 23 |
{
|
| 24 |
"captcha_001.png": {"label": "4821"},
|
|
@@ -26,9 +22,9 @@ pip install torch onnx onnxscript pillow numpy opencv-python
|
|
| 26 |
}
|
| 27 |
```
|
| 28 |
|
| 29 |
-
图片目录
|
| 30 |
|
| 31 |
-
|
| 32 |
|
| 33 |
```bash
|
| 34 |
python scripts/train_fixed.py \
|
|
@@ -39,7 +35,7 @@ python scripts/train_fixed.py \
|
|
| 39 |
rgb # 输入 RGB (关键: 不要用灰度)
|
| 40 |
```
|
| 41 |
|
| 42 |
-
|
| 43 |
```bash
|
| 44 |
python scripts/train_fixed.py \
|
| 45 |
data/1000_labels.json data/1000_raw \
|
|
@@ -47,11 +43,11 @@ python scripts/train_fixed.py \
|
|
| 47 |
0.08 500 1 rgb
|
| 48 |
```
|
| 49 |
|
| 50 |
-
产物
|
| 51 |
- `<输出>.onnx` — 最终 ONNX 模型
|
| 52 |
- `<输出>.onnx.pt` — 最优 epoch 的 PyTorch 权重 (best val)
|
| 53 |
|
| 54 |
-
|
| 55 |
|
| 56 |
```python
|
| 57 |
import numpy as np, onnxruntime as ort
|
|
@@ -63,50 +59,123 @@ logits = sess.run(None, {"input": x})[0]
|
|
| 63 |
code = "".join(str(int(logits[0,p].argmax())) for p in range(4))
|
| 64 |
```
|
| 65 |
|
| 66 |
-
## 微调 (Fine-tune)
|
| 67 |
|
| 68 |
-
|
| 69 |
|
| 70 |
```bash
|
| 71 |
-
# 先把要微调的 .pt 放到输出路径 (train_fixed.py 会自动加载它)
|
| 72 |
cp models/captcha_1000_raw.onnx.pt models/finetuned.onnx.pt
|
| 73 |
-
|
| 74 |
-
python scripts/train_fixed.py \
|
| 75 |
-
<新标签.json> <新图目录> \
|
| 76 |
-
models/finetuned.onnx \
|
| 77 |
-
0.08 200 1 rgb # 更少 epoch, 小学习率思想: 续训用的是已有权重
|
| 78 |
```
|
| 79 |
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
### 微调建议
|
| 84 |
|
| 85 |
-
|
| 86 |
-
- 若生成器变化大,建议**混合旧数据 + 新数据**一起训练,避免灾难性遗忘
|
| 87 |
-
- 保持同样的预处理(RGB 160x64 /255,**不去噪**)和增强配置
|
| 88 |
-
|
| 89 |
-
## 配置参数详解
|
| 90 |
|
| 91 |
| 参数 | 默认 | 说明 |
|
| 92 |
|---|---|---|
|
| 93 |
| val_frac | 0.1 | 验证集比例 |
|
| 94 |
| epochs | 400 | 总训练轮数 |
|
| 95 |
-
| aug | 1 | 增强开关
|
| 96 |
-
| rgb | - | 传 `rgb` 启用 3 通道输入
|
| 97 |
|
| 98 |
-
## 关键经验
|
| 99 |
|
| 100 |
1. **必须用 RGB,不要灰度** — 验证码数字是彩色的,灰度丢信息。
|
| 101 |
-
2. **不要图像去噪** — 形态学开运算砍掉细笔画,val 88.6%
|
| 102 |
-
3. **位置保留架构,不要 Global Average Pooling** — GAP 丢空间位置导致 val 归零;按列分组池化
|
| 103 |
4. **人类标注 >> 视觉模型自动标注** — 自动标注 ~35% 噪声会把模型带崩到 0% 命中;手工 100% 干净标签才能学到真实分布。
|
| 104 |
5. **增强不要加高斯噪声** — 验证码本身有干扰线,再加随机噪声会让训练样本面目全非。
|
| 105 |
|
| 106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
```python
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 训练与微调 / Training & Fine-tuning
|
| 2 |
|
| 3 |
+
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
+
## 中文
|
| 6 |
+
|
| 7 |
+
### 环境
|
| 8 |
|
| 9 |
```bash
|
|
|
|
| 10 |
pip install torch onnx onnxscript pillow numpy opencv-python
|
| 11 |
```
|
| 12 |
|
| 13 |
+
### 从零训练
|
| 14 |
|
| 15 |
+
**1. 准备数据**
|
| 16 |
|
| 17 |
+
标签格式 `labels.json`:
|
| 18 |
```json
|
| 19 |
{
|
| 20 |
"captcha_001.png": {"label": "4821"},
|
|
|
|
| 22 |
}
|
| 23 |
```
|
| 24 |
|
| 25 |
+
图片目录:150x60 左右的 RGB 验证码 PNG,文件名与标签键一致。
|
| 26 |
|
| 27 |
+
**2. 训练**
|
| 28 |
|
| 29 |
```bash
|
| 30 |
python scripts/train_fixed.py \
|
|
|
|
| 35 |
rgb # 输入 RGB (关键: 不要用灰度)
|
| 36 |
```
|
| 37 |
|
| 38 |
+
示例:
|
| 39 |
```bash
|
| 40 |
python scripts/train_fixed.py \
|
| 41 |
data/1000_labels.json data/1000_raw \
|
|
|
|
| 43 |
0.08 500 1 rgb
|
| 44 |
```
|
| 45 |
|
| 46 |
+
产物:
|
| 47 |
- `<输出>.onnx` — 最终 ONNX 模型
|
| 48 |
- `<输出>.onnx.pt` — 最优 epoch 的 PyTorch 权重 (best val)
|
| 49 |
|
| 50 |
+
**3. 推理验证**
|
| 51 |
|
| 52 |
```python
|
| 53 |
import numpy as np, onnxruntime as ort
|
|
|
|
| 59 |
code = "".join(str(int(logits[0,p].argmax())) for p in range(4))
|
| 60 |
```
|
| 61 |
|
| 62 |
+
### 微调 (Fine-tune)
|
| 63 |
|
| 64 |
+
从 checkpoint 续训(`train_fixed.py` 检测到 `<输出>.onnx.pt` 存在会自动加载权重):
|
| 65 |
|
| 66 |
```bash
|
|
|
|
| 67 |
cp models/captcha_1000_raw.onnx.pt models/finetuned.onnx.pt
|
| 68 |
+
python scripts/train_fixed.py <新标签.json> <新图目录> models/finetuned.onnx 0.08 200 1 rgb
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
```
|
| 70 |
|
| 71 |
+
- 只标少量新样本(50-200 张)即可适配小幅变化
|
| 72 |
+
- 生成器变化大时建议新旧数据混合训练,避免灾难性遗忘
|
| 73 |
+
- 保持同样的预处理(RGB 160x64 /255,不去噪)和增强配置
|
|
|
|
| 74 |
|
| 75 |
+
### 参数说明
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
| 参数 | 默认 | 说明 |
|
| 78 |
|---|---|---|
|
| 79 |
| val_frac | 0.1 | 验证集比例 |
|
| 80 |
| epochs | 400 | 总训练轮数 |
|
| 81 |
+
| aug | 1 | 增强开关 |
|
| 82 |
+
| rgb | - | 传 `rgb` 启用 3 通道输入(推荐) |
|
| 83 |
|
| 84 |
+
### 关键经验(踩过的坑)
|
| 85 |
|
| 86 |
1. **必须用 RGB,不要灰度** — 验证码数字是彩色的,灰度丢信息。
|
| 87 |
+
2. **不要图像去噪** — 形态学开运算砍掉细笔画,val 从 88.6% 掉到 79.8%。数据量足够时模型自己学会过滤干扰线。
|
| 88 |
+
3. **位置保留架构,不要 Global Average Pooling** — GAP 丢空间位置导致 val 归零;按列分组池化(20列→4位置)后立即泛化。
|
| 89 |
4. **人类标注 >> 视觉模型自动标注** — 自动标注 ~35% 噪声会把模型带崩到 0% 命中;手工 100% 干净标签才能学到真实分布。
|
| 90 |
5. **增强不要加高斯噪声** — 验证码本身有干扰线,再加随机噪声会让训练样本面目全非。
|
| 91 |
|
| 92 |
+
---
|
| 93 |
+
|
| 94 |
+
## English
|
| 95 |
+
|
| 96 |
+
### Environment
|
| 97 |
+
|
| 98 |
+
```bash
|
| 99 |
+
pip install torch onnx onnxscript pillow numpy opencv-python
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
### Training from scratch
|
| 103 |
+
|
| 104 |
+
**1. Prepare data**
|
| 105 |
+
|
| 106 |
+
Label format `labels.json`:
|
| 107 |
+
```json
|
| 108 |
+
{
|
| 109 |
+
"captcha_001.png": {"label": "4821"},
|
| 110 |
+
"captcha_002.png": {"label": "9037"}
|
| 111 |
+
}
|
| 112 |
+
```
|
| 113 |
+
|
| 114 |
+
Image dir: ~150x60 RGB captcha PNGs; filenames must match label keys.
|
| 115 |
+
|
| 116 |
+
**2. Train**
|
| 117 |
+
|
| 118 |
+
```bash
|
| 119 |
+
python scripts/train_fixed.py \
|
| 120 |
+
<labels.json> <image_dir> <output.onnx> \
|
| 121 |
+
0.08 # val fraction
|
| 122 |
+
500 # epochs
|
| 123 |
+
1 # augmentation on/off (1=on)
|
| 124 |
+
rgb # RGB input (important: do NOT use grayscale)
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
Example:
|
| 128 |
+
```bash
|
| 129 |
+
python scripts/train_fixed.py \
|
| 130 |
+
data/1000_labels.json data/1000_raw \
|
| 131 |
+
models/my_model.onnx \
|
| 132 |
+
0.08 500 1 rgb
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
Outputs:
|
| 136 |
+
- `<output>.onnx` — final ONNX model
|
| 137 |
+
- `<output>.onnx.pt` — best-epoch PyTorch weights
|
| 138 |
+
|
| 139 |
+
**3. Verify inference**
|
| 140 |
|
| 141 |
```python
|
| 142 |
+
import numpy as np, onnxruntime as ort
|
| 143 |
+
from PIL import Image
|
| 144 |
+
sess = ort.InferenceSession("my_model.onnx", providers=["CPUExecutionProvider"])
|
| 145 |
+
im = Image.open("captcha.png").convert("RGB").resize((160,64), Image.BILINEAR)
|
| 146 |
+
x = np.asarray(im, dtype=np.float32).transpose(2,0,1)[None] / 255.0
|
| 147 |
+
logits = sess.run(None, {"input": x})[0]
|
| 148 |
+
code = "".join(str(int(logits[0,p].argmax())) for p in range(4))
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
### Fine-tuning
|
| 152 |
+
|
| 153 |
+
`train_fixed.py` auto-loads an existing `<output>.onnx.pt` and resumes from it:
|
| 154 |
+
|
| 155 |
+
```bash
|
| 156 |
+
cp models/captcha_1000_raw.onnx.pt models/finetuned.onnx.pt
|
| 157 |
+
python scripts/train_fixed.py <new_labels.json> <new_image_dir> models/finetuned.onnx 0.08 200 1 rgb
|
| 158 |
```
|
| 159 |
+
|
| 160 |
+
- 50-200 new labeled samples are enough for small changes.
|
| 161 |
+
- Mix old + new data when the generator changes a lot, to avoid catastrophic forgetting.
|
| 162 |
+
- Keep the same preprocessing (RGB 160x64 /255, no denoise) and augmentation.
|
| 163 |
+
|
| 164 |
+
### Parameters
|
| 165 |
+
|
| 166 |
+
| Param | Default | Description |
|
| 167 |
+
|---|---|---|
|
| 168 |
+
| val_frac | 0.1 | validation fraction |
|
| 169 |
+
| epochs | 400 | total epochs |
|
| 170 |
+
| aug | 1 | augmentation toggle |
|
| 171 |
+
| rgb | - | pass `rgb` for 3-channel input (recommended) |
|
| 172 |
+
|
| 173 |
+
### Key lessons
|
| 174 |
+
|
| 175 |
+
1. **Use RGB, not grayscale** — the digits are colored; grayscale loses information.
|
| 176 |
+
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.
|
| 177 |
+
3. **Position-preserving architecture, never global average pooling** — GAP destroys spatial position (val → 0%); per-column grouped pooling (20 cols → 4 positions) restores generalization.
|
| 178 |
+
4. **Human labels >> auto vision labels** — auto labels with ~35% noise crashed the model to 0%; clean manual labels are essential.
|
| 179 |
+
5. **No Gaussian noise augmentation** — the captcha already has noise lines; adding more obscures the training signal.
|
| 180 |
+
|
| 181 |
+
---
|