(此文未完待续)
2 ways
1. NER Pattern Recognition
- transformers:
- AutoTokenizer > token
- AutoModelForTokenClassification > classification
- Github: model: ckip-transformers
-
Hugging Face: ckiplab/bert-base-chinese
hf
厉害之处(已测试):NER识别任务中有感知能力
-
NER模型通过以下机制实现上下文感知:
- 注意力机制:BERT等模型使用自注意力机制,能够捕捉token之间的长距离依赖关系
- 上下文编码:每个token的表示不仅包含自身信息,还包含整个句子的上下文信息
- 标签一致性:模型通过CRF(条件随机场)等机制,确保标签序列的合理性(如 B-ORG 后面必须是 I-ORG)
注:上下文感知之外NER识别的来源:
- 预训练知识:模型在大规模语料上预训练,学习到了语言的一般规律。
- 微调任务:在NER任务上微调后,模型学会了将特定上下文模式映射到实体标签。
e.g. 上下文感知
from transformers import AutoTokenizer, AutoModelForTokenClassification
# 加载分词器和模型
tokenizer = AutoTokenizer.from_pretrained("ckiplab/bert-base-chinese-ner")
model = AutoModelForTokenClassification.from_pretrained("ckiplab/bert-base-chinese-ner")
# 测试句子
text1 = "张伟在北京的清华大学工作。"
text2 = "他走过了一个清澈的小溪。"
# 定义预测函数
def predict_ner(text):
inputs = tokenizer(text, return_tensors="pt")
outputs = model(**inputs)
predictions = outputs.logits.argmax(dim=-1).squeeze().tolist()
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"].squeeze().tolist())
for token, pred in zip(tokens, predictions):
label = model.config.id2label[pred]
print(f"{token}: {label}")
# 预测结果
print("句子1:张伟在北京的清华大学工作。")
predict_ner(text1)
print("\n句子2:他走过了一个清澈的小溪。")
predict_ner(text2)
Output:
句子1:张伟在北京的清华大学工作。
[CLS]: O
张: B-PER
伟: I-PER
在: O
北: B-LOC
京: I-LOC
的: O
清: B-ORG
华: I-ORG
大: I-ORG
学: I-ORG
工: O
作: O
。: O
[SEP]: O
句子2:他走过了一个清澈的小溪。
[CLS]: O
他: O
走: O
过: O
了: O
一: O
个: O
清: O
澈: O
的: O
小: O
溪: O
。: O
[SEP]: O
如果anomaly是一个没有名、不太常见的例子:上述attention机制仍然可能失效:
from transformers import AutoTokenizer, AutoModelForTokenClassification
# 加载分词器和模型
tokenizer = AutoTokenizer.from_pretrained("ckiplab/bert-base-chinese-ner")
model = AutoModelForTokenClassification.from_pretrained("ckiplab/bert-base-chinese-ner")
# 测试句子
text = "小明住在浦东南路49号,他今天晚上看浦和红钻的J1联赛赛事。"
# 将文本转换为模型输入
inputs = tokenizer(text, return_tensors="pt")
# 模型预测
outputs = model(**inputs)
predictions = outputs.logits.argmax(dim=-1).squeeze().tolist()
# 将 token IDs 转换回 tokens
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"].squeeze().tolist())
# 将预测结果与 tokens 对齐
for token, pred in zip(tokens, predictions):
label = model.config.id2label[pred]
print(f"{token}: {label}")
[CLS]: O
小: B-PER
明: I-PER
住: O
在: O
浦: O
东: O
南: O
路: O
49: O
号: O
,: O
他: O
今: O
天: O
晚: O
上: O
看: O
浦: O
和: O
红: O
钻: O
的: O
J: O
1: O
联: O
赛: O
赛: O
事: O
。: O
[SEP]: O
此时可以用TrainingArguments
自定义训练、或者自定义引擎规则来训练模型并保存在磁盘供后面使用
- 微调模型
- 收集包含“XX路XX号”格式的地址数据
- 标注这些数据(如
B-LOC
,I-LOC
) - 在现有模型的基础上微调
from transformers import Trainer, TrainingArguments
# 定义训练数据
train_data = [
{"text": "小明住在浦东南路49号。", "labels": [0, 1, 2, 0, 3, 4, 4, 4, 4, 0]}
]
# 定义训练参数
training_args = TrainingArguments(
output_dir="./results",
num_train_epochs=3,
per_device_train_batch_size=16,
save_steps=10_000,
save_total_limit=2,
)
# 定义Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_data,
)
# 开始微调
trainer.train()
- 结合规则引擎
- 使用正则表达式匹配“XX路XX号”格式
- 将匹配结果与模型输出结合
import re
def detect_address(text):
# 正则匹配地址
address_pattern = r"[\u4e00-\u9fff]+路\d+号"
matches = re.findall(address_pattern, text)
return matches
# 示例
addresses = detect_address("小明住在浦东南路49号,他今天晚上看浦和红钻的J1联赛赛事。")
print(addresses) # 输出:['浦东南路49号']
重新测试:
# 改进后的输出
[CLS]: O
小: B-PER
明: I-PER
住: O
在: O
浦: B-LOC
东: I-LOC
南: I-LOC
路: I-LOC
49: I-LOC
号: I-LOC
,: O
他: O
今: O
天: O
晚: O
上: O
看: O
浦: O
和: O
红: O
钻: O
的: O
J: O
1: O
联: O
赛: O
赛: O
事: O
。: O
[SEP]: O
2. Local Outlier Factor: density-based
我了解了一部分之后感觉有点类似图论中的connected components
不过还没有弄清楚,在contamination
比例极低的情况下(据说需要novelty=True
) 如何保证准确率
e.g.
import numpy as np
# 计算LOF评分(负值越小越异常)
lof = LocalOutlierFactor(n_neighbors=20, novelty=True) # 必须启用novelty模式
lof.fit(X_train)
scores = -lof.decision_function(X_test) # 转换为正数,越大越异常
# 取前0.0001%作为异常
threshold = np.percentile(scores, 99.9999)
anomalies = X_test[scores > threshold]
nd
LocalOutlierFactor
(局部离群因子,简称 LOF)是一种用于异常检测的无监督学习算法。它的核心思想是通过比较一个数据点与其邻居的局部密度来判断该点是否为异常点。LOF 是一种基于密度的算法,特别适合处理局部异常(即某些数据点在局部区域内明显偏离其他点)
核心思想
- 局部密度:计算每个数据点的局部密度(即该点与其邻居的紧密程度)。
- 离群因子:通过比较一个点的局部密度与其邻居的局部密度,计算离群因子。如果一个点的局部密度显著低于其邻居,则它可能是异常点。
- 异常评分:LOF 值越大,表示该点越可能是异常点。
优点
- 无需标签:LOF 是无监督算法,不需要标注数据。
- 适应局部异常:能够检测局部区域的异常点,而不仅仅是全局异常。
- 灵活性:通过调整邻居数量 k,可以控制算法的敏感度
最终
NER模式识别输入CSV最后得到的结果:
Screen Shot 2025-04-27 at 4.35.54 PM.png