Token Classification
Transformers
ONNX
Safetensors
English
Japanese
Chinese
bert
anime
filename-parsing
Eval Results (legacy)
Instructions to use ModerRAS/AniFileBERT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ModerRAS/AniFileBERT with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="ModerRAS/AniFileBERT")# Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("ModerRAS/AniFileBERT") model = AutoModelForTokenClassification.from_pretrained("ModerRAS/AniFileBERT") - Notebooks
- Google Colab
- Kaggle
File size: 11,417 Bytes
b57780c | 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 94 95 96 97 98 99 100 101 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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | # Anime Filename Parser Diagnostics Report
## 根因分析
当前症状不是 learning rate 问题,而是训练、验证、推理没有在同一个结构化输入空间里工作。
最高优先级根因是 tokenizer/data 配置错位:你给出的训练命令使用 `dmhy_weak_char.jsonl` 和 `vocab.char.json`,但没有传 `--tokenizer char`。旧版 `train.py` 默认 `regex`,因此 char 数据会被当作 regex 训练配置保存,checkpoint metadata 会写成 `tokenizer_variant=regex`。推理时 `load_tokenizer()` 按 checkpoint metadata 重新加载 regex tokenizer,于是 `[LoliHouse]` 这类结构 token 会作为一个整体进入模型,而 char 训练数据里它是 `[`, `L`, `o`, ..., `]`。这会直接导致 group/title 边界漂移。
第二个根因是 word-level 数据和当前 `AnimeTokenizer` 也不完全一致。`dmhy_weak.jsonl` 里示例 token 是 `[`, `LoliHouse`, `]`,但当前 regex tokenizer 对原始文件名会输出 `[LoliHouse]`。这说明 word-level 数据名义上是 regex,但不是严格由当前 inference tokenizer 重放得到的 token 序列。
第三个根因是 char 训练命令没有设置 `--max-seq-length 128`。在抽样 5,000 条 char 数据中,默认 64 长度会截断 2,058 条,占 41.16%。episode/source/resolution 往往在后半段,默认长度会让模型训练和推理都丢失结构锚点。
第四个根因是评估指标误导。低 validation loss 和 token accuracy 会被大量 `O`、`I-TITLE` 稀释;真实任务需要 entity-level F1、字段 exact match,以及结构案例回归。
## 问题优先级
P0: 训练命令必须显式或自动使用 char tokenizer。已修改 `train.py`,现在会从数据集 metadata 自动识别 `char`,并把 char 默认 max length 提升到 128。
P0: 不允许 tokenizer variant 与 dataset metadata 不一致。已修改 `train.py`,检测到 dataset `tokenizer_variant` 与选择的 tokenizer 不一致会报错。
P0: 推理必须使用 checkpoint 保存的 tokenizer 和 max length。已修改 `inference.py`,默认读取 `model.config.max_seq_length`,并新增 `--debug` 输出 token/label/score/UNK/截断信息。
P1: 从旧 checkpoint fine-tune 到不同 vocab 时,不能按 ID 盲目 `resize_token_embeddings()`。已修改为按 token 字符串重映射 embedding,未匹配 token 再随机初始化。
P1: 数据集存在 BIO/边界质量问题。char 抽样 5,000 条发现 468 个 `ORPHAN_I`,典型是标题被括号 `O` 打断后仍继续 `I-TITLE`。`B-X -> O` 本身是合法 BIO,但在 group/title/source 频繁出现时是边界告警。
P2: 当前 `BertForTokenClassification` 独立逐 token 解码,不能约束非法转移。建议后续加 CRF 或 constrained BIO decoder。
## 自动诊断结果
新增脚本:
```bash
python diagnose_pipeline.py --data-file datasets/AnimeName/dmhy_weak_char.jsonl --vocab-file datasets/AnimeName/vocab.char.json --model-dir checkpoints/dmhy-finetune/final --sample-limit 5000 --eval-limit 128 --output diagnostics_report.md
```
char 数据抽样结果:
- tokenizer variant: `char`
- vocab size: 6,199
- UNK rate: 0.0000%
- O-label ratio: 37.47%
- p95 length: 101, p99 length: 125
- default max length 64 truncation: 41.16%
- `ORPHAN_I`: 468
- regex checkpoint 直接评 char 数据时 entity F1: 0.0832
word 数据抽样结果保存在 `diagnostics_report_word.md`:
- tokenizer variant: `regex`
- vocab size: 8,000
- UNK rate: 6.9158%
- default max length 64 truncation: 0%
- 当前 regex checkpoint 在抽样 word 数据上 entity F1: 0.9549
- 但 model checkpoint vocab 是 3,000,诊断 vocab 是 8,000,继续 fine-tune 必须重映射 embedding
## Tokenizer Split 示例
输入:
```text
[LoliHouse] Yomi no Tsugai - 07 [WebRip 1080p HEVC-10bit AAC ASSx2]
```
char tokenizer:
```text
[, L, o, l, i, H, o, u, s, e, ], , Y, o, m, i, , n, o, , T, s, u, g, a, i, , -, , 0, 7, ...
```
当前 regex tokenizer:
```text
[LoliHouse], , Yomi, , no, , Tsugai, , -, , 07, , [WebRip 1080p HEVC-10bit AAC ASSx2]
```
这两个 token 序列不是同一个标注空间。char label 不能直接套到 regex token 上,regex 模型也不能在 char token 序列上解释 logits。
## BIO 与边界问题
真实非法 BIO:
```text
... ( O, K I-TITLE, a I-TITLE ...
```
示例:
```text
[LoliHouse] Kanteishi (Kari) - 07 [WebRip 1080p HEVC-10bit AAC]
```
`(` 被标为 `O`,后面的 `Kari` 继续 `I-TITLE`,形成 `O -> I-TITLE`。这会让模型学习到标题可以跨越被标为非实体的括号,边界自然会漂。
结构边界告警:
```text
[KissSub][Shunkashuutou Daikousha - Haru no Mai][06][1080P][GB][MP4]
```
`KissSub` 是 `B-GROUP`,右括号是 `O`,这是合法 BIO;但如果 tokenizer 在推理时把 `[KissSub]` 合成一个 token,模型就无法只给内部文字打 `GROUP`,只能把整个 bracket token 判成一个类别。
## Confusion 分析
故意用 char 数据评估 regex checkpoint,entity F1 只有 0.0832。主要混淆:
- `O -> TITLE`: 930
- `SOURCE -> TITLE`: 236
- `EPISODE -> TITLE`: 228
- `GROUP -> TITLE`: 86
这与实际症状一致:模型把结构锚点和 meta 区域吸进 title,group/title 边界混淆,episode 被 title 或 O 吞掉。
## 已修改的代码
`train.py`
- `--tokenizer` 默认从数据集 metadata/vocab 名称/样本结构自动推断。
- char 数据默认 `max_seq_length >= 128`。
- dataset metadata 与 tokenizer 不一致会直接报错。
- fine-tune 到新 vocab 时按 token 字符串重映射 embedding,避免 token ID 语义错位。
- checkpoint 保存正确的 `tokenizer_variant` 和 `max_seq_length`。
`inference.py`
- 新增 `--debug`,输出 tokenizer variant、token IDs、labels、scores、UNK rate、truncation、entity spans。
- 默认使用 checkpoint `max_seq_length`。
- 修正推理截断逻辑,保留 `[SEP]`,与训练一致。
- 默认使用 constrained BIO Viterbi 解码,阻止 `O -> I-X` 这类非法转移;可用 `--no-constrained-bio` 查看原始 greedy 输出。
- 新增 rule-assisted parsing,兜底修复高置信结构锚点:leading group bracket、` - 07`、`S01E07`、resolution、source。
- 可用 `--no-rule-assist` 关闭规则兜底,只看模型原始输出。
`diagnose_pipeline.py`
- 自动检查 token/label 长度。
- 输出 BIO 违规样本与边界告警。
- 输出 tokenizer split 示例。
- 输出 train/inference tokenizer 对比。
- 输出实体、label、空格 label、UNK、截断统计。
- 可选加载 checkpoint 做 confusion 和 seqeval entity-level F1。
## 修改后的 Pipeline
推荐 char-level pipeline:
```bash
python diagnose_pipeline.py ^
--data-file datasets/AnimeName/dmhy_weak_char.jsonl ^
--vocab-file datasets/AnimeName/vocab.char.json ^
--sample-limit 20000 ^
--output diagnostics_report.md
python train.py ^
--tokenizer char ^
--data-file datasets/AnimeName/dmhy_weak_char.jsonl ^
--vocab-file datasets/AnimeName/vocab.char.json ^
--save-dir checkpoints/dmhy-char ^
--epochs 10 ^
--batch-size 128 ^
--learning-rate 0.0003 ^
--warmup-steps 300 ^
--max-seq-length 128 ^
--seed 42
python inference.py ^
--model-dir checkpoints/dmhy-char/final ^
--debug ^
"[LoliHouse] Yomi no Tsugai - 07 [WebRip 1080p HEVC-10bit AAC ASSx2]"
```
如果继续使用 word/regex pipeline,必须先重新生成数据,使 `sample["tokens"] == AnimeTokenizer.tokenize(sample["filename"])` 对绝大多数样本成立;否则验证集仍然是训练 token 空间,真实 inference 是另一个 token 空间。
## 最合理的 Tokenizer 方案
当前任务更适合 char-level 或 deterministic hybrid tokenizer,不适合通用 subword tokenizer。
char-level 优点:
- train/inference 最容易完全一致。
- 不会把 `[LoliHouse]`、`[WebRip ...]` 这类结构块压成单 token。
- 对未知标题、组名、罗马音、中文、日文都没有 OOV。
- 更适合学习括号、空格、连字符、集数位置这些结构信号。
char-level 缺点:
- 序列更长,必须用 `max_seq_length=128`。
- 逐 token softmax 容易出现 BIO 非法转移,建议加 CRF。
word-level/regex 优点:
- 序列短,训练快。
- 当前已有 checkpoint 在同 token 空间验证集上 F1 较高。
word-level/regex 缺点:
- 如果 bracket protection 把整段合并,内部 label 无法表达。
- 数据生成 tokenizer 和 inference tokenizer 稍有不一致就会严重错位。
- OOV 对新番标题和组名仍然明显。
结论:短期用 char-level + rule-assisted parsing;中期改为 hybrid tokenizer:保留结构符号 `[ ] ( ) - _ . space` 为独立 token,英文数字连续串可作为片段但必须能映射回字符 offset,并在 label alignment 上以 offset 为准;长期加 BERT + CRF。
## 建议训练配置
首选:
```bash
python train.py --tokenizer char ^
--data-file datasets/AnimeName/dmhy_weak_char.jsonl ^
--vocab-file datasets/AnimeName/vocab.char.json ^
--save-dir checkpoints/dmhy-char ^
--epochs 10 --batch-size 128 ^
--learning-rate 0.0003 --warmup-steps 300 ^
--max-seq-length 128 --seed 42
```
不要从 regex checkpoint 直接当作同构模型继续训练 char;如果要迁移,当前代码会按 token 字符串 remap embedding,但多数 char token 与 regex token 共享有限,最好从头训练 char 模型或只迁移 encoder 非 embedding 层。
必须新增评估:
- entity-level F1 by field
- field exact match: `group/title/episode/resolution/source`
- full parse exact match
- episode recall
- boundary errors: group-title, title-episode, episode-meta
- inference debug sample set,固定 50-200 个真实文件名回归
## 真实案例分析
输入:
```text
[LoliHouse] Yomi no Tsugai - 07 [WebRip 1080p HEVC-10bit AAC ASSx2]
```
旧 regex checkpoint 原始模型输出:
```json
{
"entities": [
{"type": "TITLE", "text": "[LoliHouse] Yomi no Tsugai"},
{"type": "EPISODE", "text": "07"}
]
}
```
问题点:
- `[LoliHouse]` 被 tokenizer 合成一个 token。
- 模型把该 token 判成 `B-TITLE`,无法只把内部 `LoliHouse` 判成 `GROUP`。
- `Yomi` 和 `Tsugai` 在 3,000 vocab checkpoint 中是 `[UNK]`,但模型仍高置信输出 `I-TITLE`,说明 loss/置信度不能代表字段正确性。
修改后带规则辅助的最终输出:
```json
{
"group": "LoliHouse",
"title": "Yomi no Tsugai",
"episode": 7,
"source": "WebRip",
"resolution": "1080p"
}
```
这只是上线兜底;真正修复仍应训练一个 train/inference token 完全一致的 char 或 hybrid 模型。
## 架构建议
最推荐的重构路线:
1. `BERT encoder + CRF`:约束 `O -> I-X`、`B-X -> I-Y` 等非法/低质量转移。
2. char-level NER:保证 token-label alignment 不受 subword split 影响。
3. rule-assisted parser:先抽取高置信结构锚点,再让模型负责模糊 title/group 边界。
4. offset-based dataset:每条数据保存 raw filename、entity spans、tokens、offset_mapping、labels,训练时由 tokenizer 统一生成 labels。
当前代码已先实现“无训练 CRF”的 constrained BIO decoding,作为上线前的轻量保护。完整 BERT+CRF 仍建议作为下一阶段训练架构重构。
不要只优化 loss。这个任务的目标函数应更接近真实解析准确率:字段级 exact match + episode recall + title boundary F1。
|