第四章:传统机器学习方法:特征工程与序列标注模型

说实话,很多刚入行的同学一上来就追着BERT、GPT跑,觉得传统方法过时了。但我得说一句——你连CRF、HMM这些基础都没吃透,后面做实体关系抽取很容易翻车。我自己带团队时,有个项目用BERT做抽取,效果死活上不去,最后回头一看,是特征工程没做好,词性标注都是错的。嗯,这章我们就来聊聊这些“老古董”,它们其实很能打。

4.1 特征工程:词性、句法依赖、位置特征

特征工程说白了,就是教模型“看”文本的哪些方面。我习惯把特征分成三类:词性特征、句法依赖特征、位置特征。这三板斧用好了,传统模型也能出奇迹。

4.1.1 词性特征(POS Tagging)

词性标注是基础中的基础。比如“苹果”这个词,在“我吃苹果”里是名词,在“苹果公司”里还是名词,但“苹果”作为实体时,它的词性上下文往往有规律。我个人习惯把当前词、前一个词、后一个词的词性都作为特征。

核心思路:实体通常由名词、形容词、专有名词构成。动词、介词、连词很少出现在实体内部。

举个例子,句子“我在北京天安门广场拍照”,词性序列是:我/代词 在/介词 北京/专名 天安门/专名 广场/名词 拍照/动词。你看,“北京天安门广场”这个实体,词性全是名词或专名。我曾在项目中遇到一个坑——中文分词把“天安门广场”切成了“天安门/广场”,导致词性特征断裂。后来我加了“是否连续名词”这个二元特征,效果提升明显。

4.1.2 句法依赖特征

句法依赖树能告诉我们词与词之间的修饰关系。比如“红色的苹果”,“红色”是“苹果”的定语(ATT关系)。在实体抽取中,我常用以下依赖特征:

  • 核心词与修饰词的关系:比如“中国首都北京”,“北京”是“首都”的同位语(APP关系)
  • 依存路径长度:两个候选实体之间的依存路径越短,它们越可能构成一个复合实体
  • 依存关系标签:SBV(主谓)、VOB(动宾)、ATT(定中)等

我的经验:句法特征在长实体抽取中特别有用。比如“中华人民共和国外交部发言人办公室”,句法树会显示“办公室”是核心,“发言人”是修饰,“外交部”又是“发言人”的修饰。这种层级关系,词性特征根本抓不住。

4.1.3 位置特征

位置特征是最简单但最有效的特征之一。我常用的位置特征包括:

  • 相对位置:当前词距离句子开头/结尾的距离
  • 绝对位置:当前词在句子中的索引
  • 是否在实体边界:当前词是否是上一个实体的后一个词

你想想看,实体通常不会出现在句子开头或结尾的标点符号附近。比如“。今天天气真好。”,“今天”在句首,但“今天”本身可以是时间实体。所以位置特征要结合其他特征一起用,不能单打独斗。

4.2 CRF模型原理

CRF(条件随机场)是序列标注任务的扛把子。我当年第一次用CRF做命名实体识别时,觉得这玩意儿比HMM强太多了。为什么?因为它能考虑全局最优。

4.2.1 核心思想

CRF本质上是一个无向图模型。它建模的是:给定观测序列X(比如一句话的词),求标注序列Y(比如B-PER、I-PER、O等)的条件概率P(Y|X)。

公式长这样:

P(Y|X) = (1/Z(X)) * exp( Σ_k λ_k * f_k(y_{i-1}, y_i, X, i) )

其中:

  • Z(X) 是归一化因子,保证概率和为1
  • f_k 是特征函数,可以任意设计
  • λ_k 是特征权重,通过训练学习

关键点:CRF不像HMM那样假设观测独立,它允许特征函数依赖整个观测序列X。这意味着CRF可以捕捉到“当前词是动词,但前5个词是名词”这种远距离依赖。

4.2.2 训练与解码

训练CRF用的是最大似然估计,通常用L-BFGS优化。解码时用维特比算法,找到最优的标注序列。我建议你记住:CRF的训练比HMM慢,但效果通常更好。

避坑指南:我曾经在一个项目中,CRF模型训练了3天还没收敛。后来发现是特征模板设计得太复杂,特征函数数量超过10万个。记住,特征不是越多越好,要精选。

4.3 HMM模型

HMM(隐马尔可夫模型)是CRF的前辈。它假设观测序列由隐藏状态序列生成。在实体抽取中,隐藏状态就是实体标签(B-PER、I-PER等),观测就是词本身。

4.3.1 三个基本问题

HMM解决三个问题:

  1. 评估问题:给定模型参数,计算观测序列的概率(前向-后向算法)
  2. 解码问题:给定观测序列,找到最可能的隐藏状态序列(维特比算法)
  3. 学习问题:给定观测序列,估计模型参数(Baum-Welch算法)

在实体抽取中,我们主要用解码问题。维特比算法会动态规划地找到最优路径。

4.3.2 HMM的局限性

HMM有两个强假设:

  • 齐次马尔可夫假设:当前状态只依赖前一个状态
  • 观测独立假设:当前观测只依赖当前状态

这两个假设在现实中很难满足。比如“我在北京天安门广场”,如果HMM只看前一个状态,它可能把“北京天安门”拆成两个实体。而CRF可以看全局,就不会犯这种错。

我的建议:如果你数据量小(比如几千条),HMM可能比CRF更稳定。数据量大时,CRF是更好的选择。我有个项目只有500条标注数据,用HMM的F1值比CRF高了3个点。

4.4 特征模板设计

特征模板是连接特征工程和序列模型的桥梁。我习惯用CRF++的模板格式来设计,因为它直观、好调试。

4.4.1 模板格式

CRF++的模板分为Unigram模板(U)和Bigram模板(B)。Unigram模板描述当前词的上下文特征,Bigram模板描述标签转移特征。

举个例子:

# Unigram
U00:%x[-2,0]   # 前两个词
U01:%x[-1,0]   # 前一个词
U02:%x[0,0]    # 当前词
U03:%x[1,0]    # 后一个词
U04:%x[2,0]    # 后两个词
U05:%x[-1,0]/%x[0,0]  # 前一个词+当前词组合
U06:%x[0,0]/%x[1,0]   # 当前词+后一个词组合

# Bigram
B

这个模板的意思是:对每个位置,提取前后各两个词,以及它们的二元组合。我建议你从简单模板开始,比如只取前后各一个词,然后逐步增加。

4.4.2 实战模板设计

下面是我在一个医疗实体抽取项目中用过的模板:

# 词特征
U00:%x[-2,0]
U01:%x[-1,0]
U02:%x[0,0]
U03:%x[1,0]
U04:%x[2,0]

# 词性特征
U10:%x[-2,1]
U11:%x[-1,1]
U12:%x[0,1]
U13:%x[1,1]
U14:%x[2,1]

# 位置特征(是否在句子开头/结尾)
U20:%x[0,2]
U21:%x[0,3]

# 组合特征
U30:%x[-1,0]/%x[0,0]
U31:%x[0,0]/%x[1,0]
U32:%x[-1,1]/%x[0,1]
U33:%x[0,1]/%x[1,1]

其中,第0列是词,第1列是词性,第2列是“是否句首”,第3列是“是否句尾”。

核心原则:特征模板设计要遵循“由简到繁、逐步验证”的原则。我每次只加5-10个特征,然后跑一次交叉验证,看F1值是否提升。如果没提升,就删掉。

4.4.3 特征选择技巧

我总结了几条经验:

  • 不要用太远的上下文:前后各2-3个词通常就够了,太远会引入噪声
  • 组合特征比单一特征强:比如“前一个词+当前词”比单独用这两个词效果好
  • 词性特征要配合词特征:单独用词性特征效果很差,但和词特征组合后效果翻倍
  • 位置特征要谨慎:位置特征在短文本中有效,在长文本中可能过拟合

我曾经踩过的坑:有个项目我加了“当前词是否包含数字”这个特征,结果模型把所有带数字的词都标成了时间实体。后来发现是因为训练数据中时间实体大多带数字,但“第1名”这种不是时间实体。所以特征设计一定要考虑数据分布。

4.5 知识体系总览

下面这张图总结了本章的核心内容,我建议你保存下来,做项目时对照着看:

传统机器学习实体关系抽取知识体系 序列标注模型 特征工程 词性特征(POS) 句法依赖特征 位置特征 HMM模型 CRF模型 齐次马尔可夫假设 观测独立假设 条件概率P(Y|X) 全局最优解码 特征模板设计 Unigram模板(上下文特征) Bigram模板(标签转移特征) 特征工程 HMM CRF 特征模板

这张图把本章的知识点串起来了。你看,特征工程是基础,HMM和CRF是两种建模方式,特征模板是连接它们的桥梁。我个人建议你从HMM+简单特征模板开始,跑通流程后,再换成CRF+复杂特征模板。这样你能直观感受到不同方法的差异。

好了,这一章的内容就到这里。特征工程和序列模型是实体关系抽取的基石,虽然现在深度学习很火,但这些传统方法在数据量小、资源受限的场景下依然能打。我到现在做项目,还是会先用CRF跑一个baseline,再考虑上深度学习模型。


公众号:蓝海资料掘金营,微信deep3321