
1. 一场持续二十年的路线之争如果你在2010年前后进入机器学习这个圈子大概率会被两种截然不同的世界观撕扯过。一边是概率图模型Probabilistic Graphical Models简称PGM阵营他们手里握着HMM、Bayesian Network、CRF、MRF这些工具能把一个问题的变量依赖关系画成一张漂亮的图每个节点、每条边都有明确的概率语义推理过程可以写成公式参数可以解释连隐变量都能用EM算法一步步推出来。另一边是神经网络阵营尤其是2012年之后深度学习爆发一堆黑箱模型开始在各种任务上碾压传统方法你问它为什么做出这个判断它只能给你一堆权重和激活值说不清道不明。这场路线之争的核心问题其实就一句话概率图模型明明能把世界结构写清楚为什么最后输给了黑箱神经网络这个问题我琢磨了很久。我自己是从HMM做语音识别入行的后来转做CRF做序列标注再后来被深度学习浪潮裹挟着写PyTorch。说实话早期我对神经网络是有点抵触的觉得它不讲武德没有概率解释没有图结构凭什么赢但后来做项目多了踩坑多了慢慢想明白了一些事情。这篇文章我就想从一个一线从业者的角度把这条演进路线捋一遍不是教科书式的综述而是带着“为什么”去拆解每一个转折点。如果你正在学机器学习或者正在做NLP、语音、CV相关的项目或者只是好奇为什么学术界和工业界都倒向了深度学习这篇文章应该能给你一些不一样的视角。我会从HMM讲起经过Bayesian Network、CRF最后落到Deep Learning重点不是讲每个模型怎么推导而是讲每个模型解决了什么问题、又留下了什么坑、下一个模型是怎么填坑的。这条线索捋清楚了你对整个领域的理解会通透很多。2. 概率图模型的黄金时代从HMM到CRF2.1 HMM序列建模的第一次优雅尝试隐马尔可夫模型Hidden Markov Model是我入行接触的第一个概率图模型。它的核心思想非常朴素世界是一个马尔可夫链当前状态只依赖于前一个状态而我们观测到的东西是由隐状态“发射”出来的。用图来表示就是一条链z1 → z2 → z3 → ... → zn每个zi再发射出观测xi。这个模型在语音识别和早期NLP里统治了很长时间。为什么因为它把序列问题的两个核心需求都满足了第一它有一个隐状态序列的概念可以表示“这句话背后的词性是什么”“这段语音背后的音素是什么”第二它的推理算法前向-后向算法和参数学习算法Baum-Welch也就是EM算法的一个特例都是多项式复杂度的能算得动。我当年做词性标注的时候HMM是标配。训练数据就是一堆词词性对用最大似然估计出转移概率和发射概率然后维特比算法解码。整个过程干净利落代码量不超过200行。而且它有一个神经网络很难替代的优点你可以直接看转移矩阵。比如从动词转移到名词的概率是多少从形容词转移到名词的概率是多少这些数值是有物理意义的你可以拿去跟语言学规则对照。但HMM的坑也很明显。第一个坑是观测独立性假设。它假设每个观测xi只依赖于当前隐状态zi跟其他观测和状态都无关。这个假设在真实数据里几乎不可能成立。比如词性标注当前词的词性显然跟前后好几个词都有关不只是前一个词性。第二个坑是特征表达能力弱。HMM的发射概率就是一个查表你没法方便地加入“当前词是否大写”“当前词后缀是不是-tion”这种特征。要加也行但得把观测空间撑得很大数据稀疏问题立刻爆炸。实操心得HMM适合做baseline尤其是数据量不大、特征维度低、需要可解释性的场景。但如果你发现错误分析里大量错误来自“模型没看到上下文特征”那就该考虑换模型了。2.2 Bayesian Network把依赖关系画成有向图HMM的链式结构太死板了现实世界里的依赖关系往往是一张更复杂的图。Bayesian Network贝叶斯网络就是来解决这个问题的。它用一个有向无环图DAG来表示变量之间的条件依赖关系每个节点对应一个随机变量每条边表示直接影响每个节点的条件概率分布CPD定义了在给定父节点取值时该节点的分布。举个例子一个医疗诊断场景吸烟S→ 肺癌C← 基因G肺癌C→ 咳嗽X。这个图告诉你咳嗽只依赖于肺癌肺癌依赖于吸烟和基因吸烟和基因之间没有边所以它们条件独立。有了这个图联合概率分布可以分解成P(S,G,C,X) P(S)P(G)P(C|S,G)P(X|C)。这个分解大大减少了参数数量也让推理变得可行。Bayesian Network最漂亮的地方在于它把因果结构和概率推理结合起来了。你不仅能做预测还能做干预推理do-calculus能回答“如果我强制让一个人不吸烟他得肺癌的概率是多少”这种反事实问题。这是纯判别模型做不到的。但Bayesian Network在实际项目里落地很难。第一个难点是结构学习。从数据里学出一个DAG是NP难的启发式搜索又容易陷入局部最优。第二个难点是推理复杂度。一般图上的精确推理是指数级的只能用近似推理如MCMC、变分推断而近似推理的收敛性和精度又很难保证。第三个难点是参数学习需要大量数据。每个节点的CPD如果父节点很多条件概率表的规模会指数增长数据稀疏问题比HMM还严重。我试过在一个故障诊断项目里用Bayesian Network变量大概20个边大概30条。结构是领域专家手工画的参数用EM从历史数据里学。结果发现推理速度慢得离谱而且很多CPD的参数估计不准导致后验概率跟专家直觉严重不符。最后项目还是退回了规则引擎加逻辑回归。这个经历让我意识到Bayesian Network的理论优雅性和工程可落地性之间有一条巨大的鸿沟。2.3 CRF判别式序列建模的巅峰如果说HMM和Bayesian Network是生成式模型的代表那条件随机场Conditional Random FieldCRF就是判别式概率图模型的巅峰。CRF直接建模P(y|x)而不是P(x,y)。这个转变看似简单实则深刻它不再关心观测数据是怎么生成的只关心给定观测后标签的分布。CRF的图结构通常是一条链线性链CRF但它的势函数可以定义在任意特征函数上。具体来说P(y|x) ∝ exp(Σ_i Σ_k λ_k f_k(y_{i-1}, y_i, x, i))。这里的f_k是特征函数可以看任意窗口的观测可以看前后标签的转移可以看词典匹配结果等等。λ_k是权重通过最大似然估计学习。CRF在NLP的序列标注任务上统治了将近十年。分词、词性标注、命名实体识别、语义角色标注几乎都是CRF的天下。为什么因为它解决了HMM的两个核心痛点第一特征可以任意设计不受观测独立性假设限制第二判别式训练直接优化条件似然通常比生成式模型精度更高。我印象最深的是做命名实体识别的时候特征模板能写几十个当前词、前一个词、后一个词、当前词的前缀后缀、当前词是否在词典里、前一个标签、后一个标签的组合等等。这些特征扔进CRF效果比HMM高十几个点。而且CRF的训练是凸优化有全局最优解不像神经网络那样要调学习率、调初始化。但CRF也有自己的天花板。第一个问题是特征工程成本高。每换一个领域特征模板就得重新设计领域知识依赖太重。第二个问题是长距离依赖建模能力有限。线性链CRF只能看到相邻标签的转移虽然特征函数可以看整个观测序列但标签之间的高阶依赖很难建模。第三个问题是训练速度慢。CRF的损失函数计算涉及前向-后向算法每轮迭代都要遍历整个序列数据量大时训练时间很长。注意事项CRF的特征函数设计有一个常见误区就是堆太多特征导致过拟合。我一般会先用少量强特征做baseline然后逐步加特征每加一组就做一次交叉验证。如果验证集F1不升反降说明这组特征引入了噪声。3. 深度学习的崛起黑箱为什么赢了3.1 表示学习从人工特征到自动特征神经网络最核心的武器就是表示学习。传统概率图模型需要人工设计特征而神经网络可以从原始数据里自动学出层次化的表示。这个转变在图像和语音领域最先爆发因为这两类数据的原始特征像素、波形跟最终任务分类、识别之间的映射太复杂了人工设计特征几乎不可能覆盖所有模式。我拿语音识别举个例子。早期做语音识别前端要提取MFCC梅尔频率倒谱系数然后拼接一阶差分、二阶差分再扔进GMM-HMM。MFCC的设计基于人耳听觉特性是几十年声学研究的结晶。但深度学习来了之后端到端模型直接吃原始波形或者短时傅里叶谱卷积层和循环层自己学特征。结果呢端到端模型在大量数据上碾压了GMM-HMM。为什么因为MFCC虽然好但它是一个固定的、通用的特征而神经网络学出来的特征是任务相关的、数据驱动的能捕捉到MFCC丢掉的细节。这个逻辑在NLP里也一样。传统CRF需要人工设计词形、词典、上下文窗口特征而BiLSTM-CRF或者BERT-CRF直接把词向量序列扔进去模型自己学上下文表示。你不需要告诉它“-tion结尾可能是名词”它从数据里就能学到这个模式而且还能学到更复杂的、你根本想不到的模式。3.2 端到端训练扔掉流水线传统概率图模型的系统通常是流水线式的先分词再词性标注再句法分析再语义理解。每个模块单独训练单独调优模块之间的错误会累积。而且每个模块的优化目标跟最终任务目标不一致导致次优解。神经网络推动了端到端训练。一个模型从输入直接到输出中间没有人工设计的模块边界。损失函数直接定义在最终任务上梯度可以回传到每一层。这种训练方式在数据充足时效果惊人。比如机器翻译传统方法是分词→对齐→短语抽取→解码每一步都有独立的目标而seq2seq模型直接建模P(y|x)一个损失函数端到端优化BLEU值高出一大截。端到端还有一个隐性好处它让模型容量可以无限扩展。传统流水线里每个模块的容量是有限的你很难通过增加参数来提升整体性能。而神经网络可以堆层、加宽、加注意力头只要数据够、算力够性能就能持续提升。这个scaling law在概率图模型里是不存在的。3.3 算力与数据深度学习的燃料神经网络不是新东西上世纪80年代就有反向传播了。为什么2012年之后才爆发因为算力和数据到位了。GPU的并行计算能力让大规模矩阵运算变得可行ImageNet这样的大规模标注数据集让模型有足够的样本去学。概率图模型的推理算法如前向-后向、维特比、信念传播本质上是串行的很难充分利用GPU。而神经网络的前向和反向传播都是矩阵乘法天然适合GPU。这个工程上的差异直接决定了两条路线在工业界的命运。我做过一个粗略的估算同样规模的序列标注任务CRF训练一轮要几个小时而BiLSTM-CRF在GPU上只要几十分钟。如果数据量再大十倍CRF可能直接跑不动了而神经网络只需要多加几张卡。这种工程可扩展性上的差距是概率图模型输掉的一个关键原因。实操心得如果你现在还在用CRF做序列标注建议至少试试BiLSTM-CRF或者BERT-CRF。在数据量超过一万条时神经网络的精度和训练速度通常都更有优势。当然如果数据只有几百条CRF可能还是更稳。4. 概率图模型真的输了吗4.1 黑箱的代价可解释性与数据效率神经网络赢了精度和速度但代价是什么第一个代价是可解释性。概率图模型的每个参数都有概率意义你可以追溯一个预测是怎么来的。而神经网络的权重是分布式表示单个权重没有明确含义你只能通过注意力可视化、梯度归因等事后方法去猜。第二个代价是数据效率。概率图模型有很强的归纳偏置比如HMM的马尔可夫假设、CRF的局部性假设这些偏置在数据少时是优势能防止过拟合。而神经网络参数多、假设少需要大量数据才能学好。我试过在只有500条标注数据的NER任务上对比CRF和BiLSTM-CRFCRF的F1比BiLSTM-CRF高了将近8个点。数据量到5000条时两者持平。到50000条时BiLSTM-CRF反超5个点。第三个代价是推理的灵活性。概率图模型可以做各种边缘推理、最大后验推理、干预推理而神经网络通常只输出一个点估计或一组概率做不了复杂的概率查询。4.2 融合趋势神经概率图模型有意思的是最近几年概率图模型和神经网络开始融合了。一方面神经网络开始引入结构化先验比如CRF层作为神经网络的输出层BiLSTM-CRF就是典型图神经网络GNN把图结构引入表示学习。另一方面概率图模型的推理算法开始用神经网络来加速比如用神经网络学习变分推断的提议分布或者用神经网络参数化势函数。这种融合的本质是神经网络负责表示学习概率图模型负责结构约束和推理。两者各取所长而不是谁取代谁。我在实际项目里也越来越倾向于这种混合方案。比如做事件抽取底层用BERT做编码上层用CRF做标签转移约束中间再加一个注意力机制做实体间的依赖建模。这种架构比纯BERT或者纯CRF都好。4.3 什么时候该用概率图模型虽然深度学习是大势所趋但概率图模型并没有完全退场。在以下场景里概率图模型仍然是更好的选择数据量小几百到几千条标注数据时CRF、HMM的归纳偏置能有效防止过拟合。需要可解释性医疗、金融、法律等高风险领域模型决策需要能追溯、能解释。需要概率推理做风险分析、决策支持时需要边缘概率、条件概率、干预效应这些是神经网络不擅长的。结构已知如果变量之间的依赖关系有明确的领域知识Bayesian Network能直接编码这些知识不需要从数据里学。注意事项不要因为深度学习火就无脑上神经网络。我见过太多项目数据只有几百条硬上BERT结果过拟合严重还不如逻辑回归加特征工程。选模型要看数据量、任务复杂度、可解释性需求不是越新越好。5. 从HMM到Deep Learning的实操演进路线5.1 一个序列标注任务的完整演进我拿命名实体识别NER这个任务把从HMM到BERT的演进路线完整走一遍。这样你能直观看到每个模型的输入输出、训练方式、效果差异。HMM方案输入是词序列输出是标签序列。训练时用EM算法估计转移概率和发射概率。解码用维特比。特征只有当前词和标签的共现统计。效果在CoNLL2003上F1大概70左右。CRF方案输入是词序列加人工特征前后词、词形、词典匹配等输出是标签序列。训练用L-BFGS优化条件似然。解码用维特比。效果F1能到85左右。BiLSTM-CRF方案输入是词向量序列预训练词向量字符级CNNBiLSTM编码上下文CRF层做标签转移约束。训练端到端用Adam。效果F1能到90左右。BERT-CRF方案输入是BERT的token表示上层接CRF。训练时微调BERT。效果F1能到93以上。这个演进路线里每一步的提升都来自表示能力的增强和归纳偏置的调整。HMM的表示是离散的、局部的CRF的表示是人工特征的线性组合BiLSTM的表示是上下文相关的稠密向量BERT的表示是预训练的、深度双向的。而CRF层始终保留因为它提供了标签转移的结构约束这个约束在数据不足时特别有用。5.2 关键参数与训练技巧如果你要从CRF迁移到BiLSTM-CRF有几个参数需要特别注意参数推荐值说明词向量维度100-300预训练词向量通常用100或300维LSTM隐藏层维度200-400双向拼接后是两倍Dropout0.3-0.5加在embedding层和LSTM输出层学习率1e-3 (Adam)BERT微调时用2e-5到5e-5Batch size16-64根据显存调整CRF学习率比主网络大10倍CRF层参数少需要更大学习率训练技巧方面我踩过的坑包括第一词向量要不要冻结。数据少时冻结数据多时微调。第二CRF层的学习率。如果跟主网络用同一个学习率CRF收敛太慢建议单独设大一点。第三标签转移矩阵的初始化。不要随机初始化可以用训练数据统计出来的转移概率做初始化收敛更快。5.3 从零实现一个BiLSTM-CRF的核心代码下面是一个简化的BiLSTM-CRF实现用PyTorch写。我重点标注了CRF层的实现因为这是从纯神经网络到神经概率图模型的关键。import torch import torch.nn as nn class BiLSTM_CRF(nn.Module): def __init__(self, vocab_size, tag_to_ix, embedding_dim, hidden_dim): super(BiLSTM_CRF, self).__init__() self.embedding_dim embedding_dim self.hidden_dim hidden_dim self.vocab_size vocab_size self.tag_to_ix tag_to_ix self.target_size len(tag_to_ix) self.word_embeds nn.Embedding(vocab_size, embedding_dim) self.lstm nn.LSTM(embedding_dim, hidden_dim // 2, num_layers1, bidirectionalTrue) # LSTM输出映射到标签空间 self.hidden2tag nn.Linear(hidden_dim, self.target_size) # CRF转移矩阵transitions[i][j]表示从标签i转移到标签j的分数 self.transitions nn.Parameter( torch.randn(self.target_size, self.target_size)) # 约束不能转移到START不能从STOP转移出来 self.transitions.data[tag_to_ix[START_TAG], :] -10000 self.transitions.data[:, tag_to_ix[STOP_TAG]] -10000 def _forward_alg(self, feats): # 前向算法计算配分函数 init_alphas torch.full((1, self.target_size), -10000.) init_alphas[0][self.tag_to_ix[START_TAG]] 0. forward_var init_alphas for feat in feats: alphas_t [] for next_tag in range(self.target_size): emit_score feat[next_tag].view(1, -1).expand(1, self.target_size) trans_score self.transitions[next_tag].view(1, -1) next_tag_var forward_var trans_score emit_score alphas_t.append(log_sum_exp(next_tag_var).view(1)) forward_var torch.cat(alphas_t).view(1, -1) terminal_var forward_var self.transitions[self.tag_to_ix[STOP_TAG]] alpha log_sum_exp(terminal_var) return alpha这段代码的核心是_forward_alg它对应CRF的前向算法用来计算配分函数。transitions矩阵就是CRF的转移势函数它是可学习的参数。整个模型通过负对数似然损失端到端训练LSTM负责表示学习CRF负责结构约束。实操心得CRF层的实现容易出错的地方是log_sum_exp的数值稳定性。一定要用“减去最大值再取指数”的技巧否则容易溢出。另外START和STOP标签的转移约束要设成很大的负数而不是负无穷否则梯度会出问题。6. 常见问题与排查技巧实录6.1 模型选型速查表场景推荐模型理由数据1000条序列标注CRF归纳偏置强不易过拟合数据10000条序列标注BiLSTM-CRF或BERT-CRF表示能力强端到端训练需要概率推理Bayesian Network支持边缘概率、干预推理需要可解释性HMM或CRF参数有明确概率意义图结构数据GNN或MRF能建模节点间依赖大规模文本分类BERT或RoBERTa预训练表示强微调效果好6.2 训练不收敛的排查思路神经网络训练不收敛是家常便饭。我的排查顺序是第一检查数据有没有问题标签是不是对的有没有脏数据。第二检查学习率太大震荡太小不收敛试试1e-3、1e-4、1e-5。第三检查梯度有没有梯度消失或爆炸加梯度裁剪。第四检查初始化CRF的转移矩阵初始化很关键。第五检查batch size太小噪声大太大泛化差。CRF训练不收敛还有一个特殊原因特征函数的值域没归一化。如果某些特征值很大配分函数会爆炸。解决办法是对特征做归一化或者用正则化约束权重。6.3 过拟合的应对策略过拟合在数据少时特别常见。我的应对策略按优先级排序第一加Dropoutembedding层和LSTM输出层都加。第二加L2正则化权重衰减设1e-4到1e-5。第三早停验证集损失不降就停。第四减小模型容量减少LSTM层数或隐藏维度。第五数据增强比如同义词替换、随机mask。第六如果还不行退回CRF。注意事项不要一上来就上大模型。我见过一个项目数据只有2000条直接上BERT结果验证集F1比CRF还低。后来换成BiLSTM-CRF效果反而更好。模型容量要和数据量匹配。7. 我个人的一些体会做了这么多年从概率图模型到深度学习再到现在的混合方案我最大的体会是没有免费的午餐也没有永远正确的模型。概率图模型的优雅在于结构清晰、可解释、数据效率高但它的表示能力受限于人工特征和推理复杂度。神经网络的强大在于表示学习、端到端、可扩展但它的代价是可解释性差、数据饥渴、推理不灵活。如果你现在正在做项目选型我的建议是先看数据量再看任务复杂度最后看可解释性需求。数据少、任务简单、需要解释概率图模型可能更合适。数据多、任务复杂、追求精度神经网络更合适。如果两者都有需求就做混合方案底层神经网络做表示上层概率图模型做约束。最后分享一个小技巧如果你在用BERT-CRFCRF层的学习率可以设成BERT的10倍。因为CRF参数少需要更大学习率才能快速收敛。这个技巧我在多个项目里验证过能明显加快收敛速度而且最终F1通常能高0.5到1个点。另外CRF的转移矩阵可以用训练集的标签转移统计做初始化比随机初始化收敛快很多。这些细节在论文里通常不会写但实际做项目时很管用。