ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

rizzo-pii训练配方全公开:mmBERT微调74.5万行数据,单卡16GB两小时跑通0.3B PII检测模型

rizzo-pii训练配方全公开:mmBERT微调74.5万行数据,单卡16GB两小时跑通0.3B PII检测模型

【免费下载链接】rizzo-pii

Local-first privacy guard: anonymize your documents before sharing with LLMs.

项目地址:https://gitcode.com/gh_mirrors/ri/rizzo-pii
点击查看免费下载

做本地隐私保护的 rizzo-pii 把它的 PII 检测模型训练配方完整公开了:用 mmBERT 微调一个约 0.3B 参数的 token 分类模型,在 74.5 万行多语言数据上单卡 16GB 显卡跑两小时左右就能完成。本文带你拆解这套训练配方——数据怎么拼、有哪些关键坑、超参数怎么定、最终能到什么精度。

模型定位:先搞清楚 rizzo-pii 在解决什么问题

rizzo-pii 的定位是「本地优先」的隐私保护工具:把合同、法律文书里的 22 类个人数据(姓名、税号、IBAN 等)替换成本地可逆的占位符(如[FULLNAME_1]、[CF_1]),再把干净的文本交给云端大模型处理,敏感数据全程不出本机。它的核心就是一个小型 PII 检测模型——约 0.3B 参数、CPU 上 0.5GB 内存即可推理、完全离线。

对意大利用户尤其有价值的是,它覆盖了其他开源模型都不认识的 5 个本地特有标签:税号CF、增值税号PIVA、地籍数据CATASTO、文书编号DOCID和省代码PROVINCE。这些标签在公开语料里根本没有标注数据,全部靠合成生成——这正是训练配方的第一个看点。

数据配方:74.5万行是怎么拼出来的

完整构成见 docs/DATASET.md。历史训练池共744,912 行(约 74.5 万行)+ 7,000 行纯意大利语验证集,由四个来源拼成:

来源行数占比作用
Ai4Privacy 多语言真实数据464,12462.3%8 种语言的真实文本 + PII 标签,多语言能力的基础
模板合成(意大利法律文书)200,00026.8%覆盖 CF/PIVA/CATASTO 等意大利法律标签
Augment 注入真实句子40,0005.4%把合成实体注入真实意大利语句,防模板过拟合
DeepMount(Faker 意大利语)40,7885.5%给 IBAN/ORG/AMOUNT/TARGA 提供自然上下文

其中意大利语被刻意强化到约 45%,但整体保持 8 语言多语言训练。

合成数据的核心原则是"LLM 做作者,代码做标注器":大模型只写带{SLOT}占位符的法律文书,由代码注入带数学有效校验和的 CF/PIVA/IBAN,标签位置天然精确,LLM 从不接触真实个人数据。相关脚本在 src/data_pipeline/ 目录下,核心是 generate_synthetic_pii.py 和 augment_real_pii.py。

训练配方一:subword 标签传播——修掉 F1=0 的关键坑

这是整个配方里最隐蔽、也最有价值的一处改动,完整推理见 docs/TRAINING.md。

问题:分词器会把长编码拆成多个 subword——例如税号MNTCRL58D07H163B拆成 13 个 subword、IBAN 拆成 26 个。而旧版本只给第一个subword 打标签,其余位置被排除在 loss 之外,从来没有被训练过;但推理时模型仍会读取这些位置,于是随机输出,把整个实体切成碎片:

C.F. RCCMRT60T58H703I -> CF:'RCC' + CF:'M' + ID_DOC:'RT60T58H7' + TARGA:'I'

实测后果:验证集上CF、PIVA、IBAN的 F1 全部是0.000,而单单词的FULLNAME高达 0.987——同样的数据,差距只在于那个词被拆成几个 subword。

修法:开启 LABEL_ALL_SUBWORDS(默认True),让内部 subword 继承B-X → I-X的延续标签,保证推理读取的每个位置都有监督;同时确保每个B-X类都补上对应的I-X类(否则内部 subword 会静默落回O,等于教会模型"税号里面什么都没有")。

训练配方二:为什么不能只看 loss 曲线

另一个反直觉的教训:超过 90% 的 token 是O(非敏感),所以 loss 被容易的类主导——它可以一路平稳下降,而稀有标签纹丝不动。上面的 subword bug 就是这样穿过了一整轮训练:loss 从 0.0135 平滑降到 0.0060,三个标签却钉死在 0。

所以配方做了三件事:

  • 每次 eval 都计算entity-level P/R/F1(而非只在训练结束时算一次),实现见 compute_metrics;
  • 模型选择指标用f1_macro而非 loss——某个稀有标签一坏它立刻崩塌,而 loss 毫无察觉;
  • 重点盯防 5 个关键标签WATCH_TAGS(CF、PIVA、IBAN、ZIPCODE、ID_DOC,见 WATCH_TAGS),若它们仍为 0,说明标签传播没生效。

关键超参数与硬件:单卡 16GB 两小时跑通

参考环境是一台RTX 5060 Ti(16GB,Blackwell,需 PyTorch cu128 构建),一轮完整训练不到2 小时(约 26,600 个优化器步)。核心参数都集中在 src/training/train_pii.py 顶部:

参数值说明
MAX_LEN768(L77)mmBERT 原生支持 8192 上下文;用 512 会截断约 30% 的合成数据
EPOCHS2(L80)v1.2.0 结束时验证 loss 还在下降,加到 2 轮
BATCH×GRAD_ACCUM14 × 2(L84)16GB 显卡与桌面共享 VRAM,小 batch + 梯度累积防 thrashing
LR5e-5(L90)AdamW,warmup 0.05,bf16 精度
评估/保存每 2000 步(L488)保存最近 2 个 checkpoint + early stopping(patience=3)

16GB 显存调优的两个小技巧值得记录:expandable_segments:True的显存分配策略,以及按长度分组的 batching(长度预计算,避免惰性数据集重复分词)。

训练结果:loss 曲线与指标

v1.2.0 的参考 run(单轮、约 26.6k 步)中,训练 loss 从 ≈6.2 快速降到 0.1 以下后进入平稳低位,验证 loss 单调下降且结束时仍在下降——说明没有过拟合,还有余力:

在 7,000 行纯意大利语真实验证集上:micro-F1 0.989、token 准确率 0.998、macro-F1 0.987,5 个意大利法律标识符全部拿到满分 1.000。后续版本把数据池扩展到约 218 万行并持续修正后,22 个标签中 21 个 F1 达到 ≥0.9998,最大验证集 micro-F1 从 0.7778 提升到 0.9999(详见 docs/releases/v2.0.0.md)。

如何复现训练,以及如何直接使用模型

复现训练只需三步:按 README.md 的 Quickstart 生成数据(数据脚本全部在 src/data_pipeline/),然后启动训练:

python src/training/train_pii.py --type full

先用--type subset做约 3 分钟的冒烟测试也是官方推荐流程。完整 run 结束后,模型会自动发布到 Hugging Face 的独立版本分支(如v1.3.0)而非main,避免未经验证的 run 覆盖用户正在使用的模型——版本号在 MODEL_VERSION 处维护。

对只想使用模型的用户,则完全不需要 GPU 和数据集:下载约 1.2GB 的 checkpoint 后,一条命令即可本地推理:

python src/training/test_pii.py "Mi chiamo Mario Rossi, IBAN IT60X0542811101000000123456"

或启动 Web 应用(src/app/app.py)粘贴文本/上传 PDF 获得可逆匿名化结果。生产环境还建议搭配正则 + 校验和检测网(蓝本见 src/inspect/validate_checksums.py)——校验和通过的结果会直接覆盖模型判断,两者结合比单独任何一方都更可靠。

【免费下载链接】rizzo-pii

Local-first privacy guard: anonymize your documents before sharing with LLMs.

项目地址:https://gitcode.com/gh_mirrors/ri/rizzo-pii
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进