Skip to content

13 地址对齐 — 序列标注 + 数据库对齐全栈项目

学习理念:这是第 12 章的"升级版"——从整句分类(一个标题→一个类别)升级到序列标注(每个字→一个标签),从手写 Trainer 升级到 HuggingFace 官方 Trainer,并新增了数据库查询 + 编辑距离匹配的后处理环节。30 分钟通过文档 + 图表吃透,有疑问用 AI 插件问答式解惑。

乐高定位:第 10 章(从零训练)→ 第 12 章(BERT 整句分类)→ 第 13 章(BERT 序列标注 + 数据库对齐) → 第 19 章(大型项目)

本节 AI 替代率:~72% | 人工干预率:~28%

角色能力范围
🤖 AI 擅长生成序列标注代码、HF Trainer 配置、FastAPI 路由、编辑距离匹配
👤 人类需理解BIO 标签体系的设计、序列标注的标签对齐原理、数据库对齐的流程设计

技术栈健康度速览(OPC 7.4)

🟢🟡🟠🔴 = 学习优先级 | 🔥🟢⏳⚠️💀 = 技术健康度

技术健康度
BertForTokenClassification🔥 巅峰
HuggingFace 官方 Trainer🔥 巅峰
HF DataCollatorForTokenClassification🔥 巅峰
FastAPI + Pydantic🔥 巅峰
RapidFuzz 编辑距离🟢 稳定
MySQL + pymysql🟢 稳定
BIO/BIOSO 标注体系🟢 稳定

一、项目全景(3 分钟看懂)

解决什么问题

电商/物流场景的地址信息通常是非结构化文本

输入:"高霞 13139243427北京市市辖区东风街道27号楼"

期望输出(结构化):
{
  "name": "高霞",
  "phone": "13139243427",
  "prov": "北京市",
  "city": "北京市",
  "district": "市辖区",
  "town": "东风街道",
  "detail": "27号楼"
}

两阶段管线

25 种 BIO 标签

采用 BIOSO 标注体系(B=开始, I=内部, E=结束, S=单字, O=无关):

实体类型标签示例含义
B-prov, I-prov, E-prov省份/直辖市
B-city, I-city, E-city城市
B-district, I-district, E-district, S-district区/县
B-town, I-town, E-town, S-town镇/街道
详情B-detail, I-detail, E-detail, S-detail门牌号/楼栋
姓名B-name, I-name, E-name收件人
电话B-phone, I-phone, E-phone手机号/座机
无关O空格等

二、🔥 第 12 章 → 第 13 章升级对比

这是本文档最有价值的部分——看"升级了什么"比"写了什么代码"重要 10 倍

对比维度第 12 章(商品分类)第 13 章(地址对齐)为什么升级
任务类型整句分类序列标注序列标注能提取实体位置,不是只给一个类别
模型AutoModelForSequenceClassificationBertForTokenClassification输出每个 token 的标签分布
Trainer手写 Trainer 类(学习用途)HF 官方 Trainer生产级用法,自带 checkpoint/分布式/混合精度
数据对齐DataCollatorWithPaddingDataCollatorForTokenClassification序列标注需要把标签和子词对齐([CLS]/[SEP] 位设 -100)
后处理MySQL 查询 + RapidFuzz把模型输出和真实数据库做匹配,保证结果准确
预训练模型bert-base-chineseroberta-small-wwmRoBERTa 训练更充分,small 版本推理更快

序列标注 vs 整句分类(代码级对比)

python
# 第 12 章:整句分类 — 输出一个类别
model = AutoModelForSequenceClassification.from_pretrained(..., num_labels=12)
outputs = model(**inputs)           # 输出: (batch_size, 12)
pred = torch.argmax(logits, dim=-1) # 取概率最高的类别

# 第 13 章:序列标注 — 每个字输出一个标签
model = BertForTokenClassification.from_pretrained(..., num_labels=25)
outputs = model(**inputs)           # 输出: (batch_size, seq_len, 25)
preds = torch.argmax(logits, dim=-1) # 每个位置取概率最高的标签

三、🔥 核心流程设计

3.1 数据流

3.2 标签对齐(最难理解的部分)

序列标注的训练数据中,标签需要和分词后的 token 一一对应。但分词器会把一个词切成多个子词,需要 word_ids() 来对齐:

python
text = "北京市"  # 3 个字 → 3 个 token
labels = ["B-city", "I-city", "E-city"]

# 分词后(假设 "市" 被切成两个子词)
tokenized = tokenizer(["北", "京", "市"], is_split_into_words=True)
# tokens:  [CLS] 北  京  市   [SEP]
# word_ids: None  0   1   2   None

# 标签对齐:word_ids 相同的 token 继承同一个标签
# [CLS] → -100(忽略)| 北 → B-city | 京 → I-city | 市 → E-city | [SEP] → -100
labels = [
    label_seq[j] if j is not None else -100
    for j in tokenized.word_ids(batch_index=i)
]

3.3 地址对齐

python
def address_check(text, address, mysql_config):
    # 1. 用 NER 提取的省/市/区/镇 去 MySQL 查 full_name
    #    比如 address["prov"]="北京" → SELECT full_name FROM region 
    #    WHERE region_type=2 AND name LIKE '%北京%'
    
    # 2. 查询结果构造成树
    address_tree = {"北京市": {"市辖区": ["东风街道", ...]}}
    
    # 3. 展平成 ["北京市", "市辖区", "东风街道"] 形式的列表
    address_chains = flatten_address_tree(address_tree)
    
    # 4. 对每个候选计算编辑距离
    scores = [fuzz.ratio(candidate, original_text) for candidate in address_chains]
    
    # 5. 取分数最高的
    return address_chains[scores.index(max(scores))]

四、🟢 关键技术点

4.1 HF 官方 Trainer(对比第 12 章手写 Trainer)

第 12 章手写 Trainer 是为了理解原理,第 13 章用 HF 官方 Trainer 才是生产级做法:

python
training_args = TrainingArguments(
    output_dir="finetuned",
    num_train_epochs=20,
    per_device_train_batch_size=64,
    learning_rate=2e-5,
    warmup_ratio=0.2,           # 学习率预热
    lr_scheduler_type="cosine",  # 余弦退火调度
    weight_decay=0.01,           # 权重衰减
    bf16=True,                   # 混合精度(自动检测硬件支持)
    eval_strategy="steps",
    save_strategy="steps",
    eval_steps=500,
    save_steps=500,
    metric_for_best_model="eval_f1",  # 自动选最佳模型
    greater_is_better=True,
    save_total_limit=1,          # 只保留最新检查点
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=valid_dataset,
    compute_metrics=compute_metrics,
    data_collator=DataCollatorForTokenClassification(tokenizer),
)
trainer.train()

手写 Trainer vs HF Trainer 的区别

功能第 12 章手写第 13 章 HF 官方
早停手写 _should_stopTrainingArguments 配置
混合精度手写 scalerbf16=True 一行开启
检查点手写 dict save/load内置,自动保存恢复
学习率调度warmup + cosine + weight_decay
最佳模型选择手写逻辑metric_for_best_model 自动选

4.2 RapidFuzz 编辑距离

python
from rapidfuzz import fuzz

# 编辑距离:把一个字符串变成另一个需要的最少操作次数
# 插入、删除、替换各算 1 步

# RapidFuzz 的 ratio() 返回 0~100 的相似度分数
score = fuzz.ratio("北京市市辖区东风街道", "北京市市辖区东风街道")
# score = 100.0(完全一致)

score = fuzz.ratio("北京市市辖区东风街道", "北京市拱辰街道")
# score = 较低(不匹配)

核心类图(补 §18 标准)

API 调用时序(补 §18 标准)


🛠️ 从"看代码"到"跑起来"

本文档定位是理解项目架构。如果要在本地跑起来:

1️⃣ 环境检测

把下面的提示词发给 AI:

text
我的环境是 [Windows/CUDA 12.x/Python 3.12],
这个项目的依赖有 torch、transformers、datasets、fastapi、pydantic、uvicorn、
pymysql、rapidfuzz、scikit-learn,
帮我生成兼容的 requirements.txt,torch 版本要和 CUDA 匹配。

2️⃣ MySQL 配置

本项目依赖 MySQL 地区表。发给 AI:

text
我有一个 region.sql 文件(MySQL 地区数据),
本地 MySQL root/123456 在 3306 端口,
帮我写一个初始化脚本:创建 region 数据库并导入 region.sql。

3️⃣ 一键部署

发给 AI:

text
根据这个项目的入口:
  python token_classification.py(训练,执行 train() 函数)
  python app.py(启动 FastAPI,端口 8089)

帮我生成 Dockerfile + docker-compose.yml + .dockerignore,
基础镜像用 pytorch/pytorch:2.2-cuda12.1,
需要包含 MySQL 服务。

4️⃣ 跑通验证

bash
# Step 1: 训练(如果有 GPU)
python -c "from token_classification import train; from config import ROBERTA_SMALL; train(ROBERTA_SMALL)"

# Step 2: 测试推理
python address_alignment.py

# Step 3: 启动服务
python app.py
# 浏览器访问 http://localhost:8089

5️⃣ 代码审查

发给 AI:

text
帮我审查 token_classification.py 中的训练流程:
1. DataCollatorForTokenClassification 的标签对齐是否正确?
2. compute_metrics 中 -100 掩码的处理是否正确?
3. 最佳模型保存逻辑有没有 bug?

技术栈深度评估

编号技术健康度说明
T1BertForTokenClassification🔥 巅峰序列标注的标准做法
T2HF 官方 Trainer🔥 巅峰生产级训练器,相比手写 Trainer 是正式升级
T3DataCollatorForTokenClassification🔥 巅峰序列标注的标签对齐方案
T4FastAPI + Pydantic🔥 巅峰现代 API 框架
T5HF Datasets🔥 巅峰数据处理标准库
T6RapidFuzz🟢 稳定轻量级模糊匹配
T7MySQL + pymysql🟢 稳定传统数据库查询
T8BIO/BIOSO 标注体系🟢 稳定序列标注的标注标准

海外对标

企业应用场景技术方案
美团地址解析 + POI 匹配BERT + CRF 序列标注 + 数据库对齐
菜鸟/京东物流快递地址标准化序列标注 + 地址库匹配
Google Maps地址自动补全序列标注 + 知识图谱

学习路径

优先级内容时间说明
🔥理解"第 12 章 → 第 13 章"升级对比5 min核心价值,看懂对比表格和 Mermaid 图
🔥序列标注管线 + 标签对齐10 min理解 BIO 体系和 DataCollatorForToken
🟢地址对齐后处理(MySQL + RapidFuzz)5 min理解树构建 + 编辑距离
🟢HF 官方 Trainer 配置5 min对比第 12 章手写 Trainer
🟡跑通完整流程(可选)30 min需要 MySQL + GPU

AI 协作指南

本文档看完后,以下问题直接问 AI 插件:

Q: "BIO 和 BIOSO 标注体系有什么区别?"
Q: "为什么序列标注里 [CLS] 和 [SEP] 位的标签要设成 -100?"
Q: "DataCollatorForTokenClassification 和 DataCollatorWithPadding 的区别是什么?"
Q: "编辑距离和余弦相似度在什么时候该用哪个?"

AI 能为你做的:
  - 把地址对齐流程翻译成其他框架(如 spaCy、Stanford NER)
  - 给出一份"把 MySQL 换成 Redis 搜索引擎"的改进方案
  - 解释 CRF 层在序列标注中的作用(本项目没用 CRF,是纯 BERT)

附录:原始资料处理说明

原始文件处理方式
地址对齐V1.0.2.docx + 地址对齐总结.txt内容已整合到本文档,以图表和代码骨架为主
3.代码/核心代码骨架已提取展示
region.sql(MySQL 地区表)在实操指引中说明用途
pretrained/roberta-small-wwm/预训练模型路径保留
视频(day01 + day02)跳过

修复情况

  • ✅ 技术栈健康度标签(OPC 7.4)
  • ✅ 🟢🟡🟠🔴 优先级颜色
  • ✅ Mermaid 流程图 + 对比图
  • ✅ 第 12 章 vs 第 13 章逐项对比表
  • ✅ 序列标注 vs 整句分类的代码级对比
  • ✅ 核心代码骨架(标签对齐 + 地址对齐)
  • ✅ 技术栈评估 + 海外对标
  • ✅ AI 问答指引
  • ✅ 实操引导(MySQL 配置 + 环境检测 + 一键部署)
  • ✅ 学习路径表(最短 25 分钟读完)

OPC 超级个体实战指南