查看全课大纲(第 58 / 82 节)
- 1.函数与数据泛化
- 2.向量:从几何直觉到高维空间
- 3.矩阵与张量
- 4.特征值与特征向量:矩阵变换的不动方向
- 5.凸函数:从向量求导的矩阵记号到好优化的函数形状
- 6.概率与统计:机器学习的数学基础
- 7.独立性与随机变量:贝叶斯公式与二项分布
- 8.期望、方差与协方差:随机变量的数字画像
- 9.联合概率:当一条轴不够用的时候
- 10.概率分布(一):从伯努利到伽马函数
- 11.概率分布(二):贝塔、泊松、正态与两个贝叶斯故事
- 12.机器学习的模型:找输入与输出的关系
- 13.机器学习的应用
- 14.过拟合
- 15.机器学习的分类
- 16.有监督学习:从房价预测说起
- 17.损失函数
- 18.梯度下降(上):更新规则与学习速率
- 19.梯度下降(2)
- 20.牛顿方法
- 21.KNN简介
- 22.距离测算
- 23.朴素贝叶斯
- 24.朴素贝叶斯的实际应用
- 25.信息熵:决策树构建的度量基础
- 26.信息增益与决策树的构建
- 27.ID3算法
- 28.决策树节点的划分
- 29.CART树
- 30.Bagging
- 31.Boosting:自适应提升算法
- 32.Gradient Boosting
- 33.线性模型:回归与分类的同一副骨架
- 34.最小二乘:把最优参数直接解出来
- 35.最小二乘法的几何与概率视角
- 36.极大似然:给最小二乘一个概率出身
- 37.逻辑回归(1):把线性模型接到分类上
- 38.逻辑回归(2):损失函数与多分类
- 39.---- 手造数据: 5 个样本, 2 个特征; x2 几乎 = 2*x1 (偏差手工指定, 无随机) ----
- 40.讲师例: 向量 "23014" -- 三把范数尺子量同一个向量
- 41.优化方法(1):坐标下降与前向选择
- 42.优化方法(2):前向策略与最小角回归
- 43.拉格朗日乘子法(1):从无约束到等式约束
- 44.拉格朗日乘子法(2):等式约束下的平行条件与拉格朗日函数
- 45.拉格朗日乘子法(3):不等式约束与 KKT 条件
- 46.最大间隔:把分类问题变成优化问题
- 47.拉格朗日对偶问题:把 w 和 b 全部换成 α
- 48.支持向量:边界上的少数派
- 49.SVM 计算过程:一笔到底算完,再走进核方法
- 50.贝叶斯公式:概率即信念
- 51.隐含变量和概率模型:给看不见的原因建模
- 52.EM 算法:期望与最大化的迭代
- 53.琴生不等式:EM 的数学钥匙
- 54.三个硬币问题:EM 的复盘与衔接
- 55.高斯混合模型:用隐变量解释双峰数据
- 56.隐马尔可夫模型
- 57.隐马尔可夫模型(2):前向算法与动态混合模型
- 58.隐马尔可夫模型在 NLP 中的运用
- 59.EM 算法:把「为什么收敛」推到底
- 60.HMM 在 NLP 中的运用:从分词到机器翻译
- 61.HMM 参数估计:Baum-Welch 的三块拉格朗日
- 62.高维下的高斯模型
- 63.主题模型:从词袋到隐含主题
- 64.Dirichlet 分布(1)
- 65.Dirichlet 分布(2)
- 66.统计学习内容回顾
- 67.K-means 算法
- 68.PCA 降维
- 69.SVD 降维
- 70.从聚类到流形
- 71.局部线性嵌入
- 72.随机邻域嵌入:SNE 与 t-SNE
- 73.无参模型:让数据自己说话
- 74.高斯过程:函数空间里的正态分布
- 75.高斯过程(2):噪声、正则化与核的线性组合
- 76.神经网络简介:从感知器到自编码器
- 77.反向传播:把误差一层层传回去
- 78.卷积神经网络(CNN):让特征自己学出来
- 79.循环神经网络(RNN):给网络装上记忆
- 80.深度学习回顾:静态一类,动态一类
- 81.增强学习(1):蒙特卡洛、树搜索与 Q-learning
- 82.强化学习(2):从乌鸦吃核桃到井字棋的 value 回传
隐马尔可夫模型在 NLP 中的运用
约 27 分钟
小象实战讲义 · 机器学习算法精讲
上一章我们从三硬币一路走到 EM、HMM——这一节讲师回应了两件事:一是有同学反馈,EM 里边的数学「可能没有完全详细的推导,为什么 EM 算法是收敛的,这个部分还没讲得那么详细」(下一节补上);二是算法和数学挺抽象,更多同学想知道「这方面是用来做什么的」。所以本节是一节应用课:把隐马尔可夫链放进自然语言处理(NLP),看它怎么做词性标注、中文分词、语音识别;最后再看一眼它与现代深度学习(循环神经网络)如何一脉相承。
💡 核心导读
- 问题定位回顾:机器学习的目标是学一个函数关系 —— 取 0/1 是分类、取连续值是预测;HMM 类似这样的模型,但多了一层「时序」。
- 词性标注(POS tagging):状态 是所有可能的单词(约两万个),转移矩阵 变成 的词接词方阵,释放概率 是「给定词,它被标为各词性的分布」。
- N-gram 语言模型:Unigram(词词独立,也叫词袋)、Bigram(只看前一个词——正是马尔可夫假设)、Trigram(看前两个词)。
- 分词:给每个字标 0/1——0 是 continue(继续走)、1 是 end(词到此截止)。
- 语音识别:HMM 最早用得最多的地方——观测从「词性」换成声音信号抽出的特征向量(MFCC)。
- 一脉相承:循环神经网络可以看成「隐马尔可夫链的概率关系被神经网络所替代」。
先定位:HMM 也是「学一个函数」
开场讲师先把整个机器学习的老框架摆出来——「大家已经都知道了,没什么问题」:数据是 , 从 1 到 ,最终的目的基本都是想学习一个函数关系 ,把每个 映射到它对应的 上。 属于 (或者 )的时候,是分类问题; 是连续值的时候,相当于一个预测问题。「而隐马尔可夫链的话呢,实际上也是类似于这样的模型」——只是 和 都带上了时间下标,函数关系里多了一层时序。我们在很多不同的实际问题里边都会用到它,第一个例子就来自自然语言。
词性标注:把 NLP 装进 HMM
先定位:NLP(natural language processing,自然语言处理)是人工智能或机器学习里最重要的分支之一——用机器学习的方法对语言建模,对里边的语义、问答、句法、语法进行分析。讲师举的第一个任务是词性标注:POS 的原文是 part of speech,「英文这个词稍微啰嗦一点,中文就是一个词性」。
拿中文例子:「我爱祖国」——「我」是主语、一个名词(N),「爱」是动词(V),「祖国」是另一个名词。讲师把例句加了一档难度:「我爱红花」——「红」是形容词(adj)、「花」是名词,所以整句的词性标注是 这样的序列。给了很多训练数据(每个句子都带词性标注)之后,新句子来了,每个词该标名词、动词还是形容词?
这就是 HMM 的活。先把上节的记号接上(讲师现场还自问了一句:「我们上次用的状态是什么来着?是 X 还是 Q?我记得是 Q。」——对,继续用 和 ):状态 隐含、转移是 、释放是 。关键是状态装什么。上次天气例子里 是晴天/下雨两种;这次:
背后的 ,是所有可能的单词——中文就是中文词,英文就是英文词。常用的小学生词典也得有大概两万个词(20K)。
状态一多,状态转移矩阵 直接膨胀成 的方阵:看到「我」这个词的时候,它下一个变成其他每个单词的概率各是多大——概率大的块标红、概率小的标绿。而这矩阵怎么学?「根据语料库,看每一个词和每一个词之间相接的关系——哪一个词在哪一个词的后面、哪一个词在哪一个词的前面。」比如「爱」这个词直接跟在「我」后面的概率。用一小段代码把这件事落成数(语料为讲义设定的演示):
from collections import defaultdict
# 一个极小的语料库(讲义设定的演示语料)
corpus = [
['我', '爱', '祖国'],
['我', '爱', '人民'],
['我', '喜欢', '机器', '学习'],
['我', '愿意', '学习'],
]
bigram = defaultdict(lambda: defaultdict(int)) # C(前词, 后词):谁接在谁后面
unigram = defaultdict(int) # C(词)
for sent in corpus:
for w in sent:
unigram[w] += 1
for a, b in zip(sent, sent[1:]):
bigram[a][b] += 1
# 转移概率 P(下一个词 | 当前词) = C(当前, 下一) / C(当前)
for w in ['我', '爱']:
parts = [f"P({v}|{w}) = {bigram[w][v]}/{unigram[w]}" for v in bigram[w]]
print(' '.join(parts))P(爱|我) = 2/4 P(喜欢|我) = 1/4 P(愿意|我) = 1/4
P(祖国|爱) = 1/2 P(人民|爱) = 1/2(「学习」在这个语料里总在句尾,作前词时没有后继——真实的语言模型还要处理句首、句尾标记,这里从简。)这一「给定当前词,下一个词的概率分布」正是语言模型做的事,而它对自身有三档经典假设:
- Unigram(一元):词与词之间完全独立——「红色」的概率就是它自己的概率,跟前面是「我」还是别的没有任何关系。Unigram 有时也叫 Bag of Words(词袋)。
- Bigram(二元):给定一个词,它只跟前面一个词有直接的概率关系——这就是马尔可夫链的假设。
- Trigram(三元):任何一个词的概率跟前面两个词有关系。
B:给定词,它被标成什么词性
这边管的是:给定了状态(词「爱」),想学它被标注为动词、名词、形容词、副词……的概率分布。讲师的描述很具体:在很大的语料库里,「爱」大部分都被标注为动词;有少部分语料把它标成了名词(「爱」确实可以作为名词);被标为副词或形容词的几乎是微乎其微——语料里很少见。 的学习就是数数(语料为讲义设定的演示,含「爱」作名词的用法):
from collections import defaultdict
# 一个极小的「已标注语料」:每句话同时给出词与词性
tagged = [
[('我', 'N'), ('爱', 'V'), ('祖国', 'N')],
[('我', 'N'), ('爱', 'V'), ('人民', 'N')],
[('母亲', 'N'), ('爱', 'V'), ('和平', 'N')],
[('爱', 'N'), ('是', 'V'), ('伟大的', 'Adj')], # 「爱」作名词的用法
]
# B 的学习:给定词(状态),统计它被标为各词性的频率
pos_of = defaultdict(lambda: defaultdict(int))
for sent in tagged:
for word, tag in sent:
pos_of[word][tag] += 1
for word in ['爱', '我']:
total = sum(pos_of[word].values())
parts = [f"P({t}|{word}) = {c}/{total}" for t, c in pos_of[word].items()]
print(' '.join(parts))P(V|爱) = 3/4 P(N|爱) = 1/4
P(N|我) = 2/2把这个小语料放大到真实规模,「爱」的分布就会长成讲师说的样子:动词占大头、名词占小头、副词形容词几乎为零。模型把 、 连同最开始的先验 都从语料学好之后,给定一个新句子(「我爱人民」「我喜欢机器学习」……),就能给它加词性标注——用讲师的话说:「它在等于哪些词性的时候,那个整体的似然值是最大的」,就标哪一套。
中文分词:continue 与 end
第二个应用是中文分词。「我爱中国人民」——可能分成「我爱/中国/人民」,也可能「中国人民」整个是一个大词;很少人会把「我爱中」或「爱中」画成一个词。每个字与字之间的空挡,都是潜在的一个分割点。
讲师的编码方案:给每个字打 0 或 1——
- 0 = continue(继续往前走):这个词还没完,下一个字还属于同一个词;
- 1 = end(截止):词到这里结束,这里必须要分词。
规则只有一条(讲师边写边自我纠正后的定稿):「零不能结尾,一为结尾。」 一个词内部全是 0,最后一个字是 1;下一个是 1 还要看下一个是 0 还是 1——0 就继续走,直到碰见 1 才收词。这样「我爱中国人民」的一种分词「我/爱/中国人民」就写成 这样的 marker 序列。给定标注好的训练数据,「给定一句话,它对应的 0110 关系是什么」就成了可以学习的任务。
照讲师的框架,这个模型与词性标注共享同一套骨架:状态 还是那些词, 还是那个巨大的词转移方阵;变的只是 这一头——观测 一下子简单了:只有 0 和 1 两个值(截止还是不截止)。甚至还能再学出一点直觉:训练数据里「我」后面总是分词(都被标了 1),那么看见「我」的时候,它有最大的概率标 1——它自己就得单独画成一个词。
讲师对这类建模给自己留了一句很坦诚的注脚:「也许这个不是很行,但是我们可以去描述」——并且顺势回收了本课程早期的那句金句:模型这件事,没有对错之分,只有好坏之别。(这一节里 HMM 的状态装的是「词」,与教科书里常见的「词性当隐状态」装法方向不同;按讲师口径如实呈现,作为理解应用的描述性框架。)
语音识别:HMM 最早的主场
其实隐马尔可夫链用得最多的,最早是在语音处理里。还是那句话「我爱中国人民」——说出来变成的是一段段声音符号。模型骨架完全不变:
- 状态 还是所有词(那个 2 万乘 2 万的方阵), 不变:一般说「我」的时候,后边可能出现动词「爱」、出现「喜欢」「愿意」——这就是条件概率;
- 变成了另一个问题: 是「观察到这个词的声音特征的概率」。
「人民」这个词说出口,它的声波长成一个特定的模样。以前做语音识别,要先把这些连续的声音信号做平滑、降噪等处理,总之把连续信号变成高维的离散特征——有一种特征叫 MFCC(「大家可以自己去搜一下」,基于一种变换把连续信号变成离散特征)。一段声音波形进来,经过傅里叶变换、快速傅里叶变换这些数学技巧,最后变成一个向量——比如 15 维。「人民」「中国」「板凳」「鼠标」,任何一个词都有不同的声波、变成不同的向量。训练数据告诉你:类似于这样的声波,更代表「人民」——它对应这个向量的概率就更大、似然值就更大。给定了新的 ,就能做语音识别。
顺带一句:HMM 能吃的远不止语言。股票价格——某一只股票的价格随时间浮动;美元对英镑的外汇牌价——讲师留了个动手作业:找一堆数据,看能不能用 HMM 学出参数、预测下一个点是涨还是跌。「这些事情都是可以做的。」
时代定位也如实记下:「这些技巧已经不算是比较时髦的东西了,说实在的,可能会显得比较粗糙,跟现在新的机器学习技术来比。但这些代表着我们一步一步怎么去进步、怎么去理解这些事情。」
从 HMM 到循环神经网络
最后一段是给未来的路标(讲师:我们不上深度学习的课程,但讲一下 HMM 跟深度学习后边哪部分非常相关)。神经网络「就算没学过——没吃过猪肉,也见过猪跑」:一个普通的两层网络,输入是 (比如二维特征),经过隐层节点的非线性变换与线性组合,输出 ——0/1 分类,或一个预测值。
现在把它放到时间轴上:下一时刻输入 、输出 ,再下一时刻 、……一直到 。「就像我们刚才所描述的隐马尔可夫链是一样的」——隐含状态之间, 的状态一定跟 相关,观察到的 还是跟 相关。关键一步来了:把隐层节点在时间上连起来——前一时刻的隐节点跟当前时刻相关、当前时刻又跟下一时刻相关。于是这一层的输入就有了两个来源:
- 本时刻的输入 ;
- 上一时刻隐藏层的输出 。
这种结构不断延续下去,就叫 Recurrent Neural Networks(循环神经网络,RNN)。「大家可以甚至不用关心每一个神经网络具体怎么去做」——把它们看成一个函数关系就行:原先 只跟 相关;加上跨时刻的连接后:
是上一时刻的隐藏输出——当前结果不只由当前输入决定,还由上一时刻的「记忆」决定。「这就像类似于我们隐马尔可夫链的假设是一样的。」
讲师给了一句提纲挈领的总结,也是本节的收束:
循环神经网络可以简单地看成:一种时序关系,或者隐马尔可夫链的这种概率关系,被神经网络所替代——这样就会变成循环神经网络。
「有些人以为深度学习里边的东西都是独立的、完全是神经网络自己的新东西。其实它基本的思想和想法,跟整个机器学习的发展都是一脉相承的。」
📝 动手练一练
- Trigram 的代价:如果对词序列用 Trigram 假设(每个词的概率依赖前面两个词),「状态」该装什么?转移矩阵的规模会从 变成多大?这解释了为什么 Bigram 在早期 NLP 里最常用?
👉 点击查看参考答案
Trigram 下当前词依赖前两个词,状态得装「前一个词 + 当前词」的二元组:可能的组合有 种,转移矩阵随之变成 量级——参数数量爆炸,而且绝大多数组合在真实语料里从未出现过(极端稀疏)。Bigram 只看前一个词,状态数维持在 、转移矩阵 ,是「表达能力」与「可估性」之间最划算的折中,所以早期 NLP 用得最多。
- 分词编码手写:「我爱中国人民」至少有两种合理分词:甲、我 / 爱 / 中国 / 人民;乙、我 / 爱 / 中国人民。请把两种分词各写成一个 0/1 marker 序列(0=continue,1=end),并回答:序列「我爱中」为什么不可能是一个词——它的 marker 序列会违反哪条规则?
👉 点击查看参考答案
按「词内部标 0、最后一个字标 1」:
- 甲(我/爱/中国/人民):;
- 乙(我/爱/中国人民):。
两个序列的前两个字相同(「我」「爱」各自成词、都标 1),差别在「国」:甲里「中国」到「国」收词(标 1),乙里「中国人民」还在继续(标 0)。
若「我爱中」是一个词,则「我」「爱」「中」三字同属一个词内部,marker 为 (或后面还接字则 )——但语料统计里「我」后面几乎总是分词(「我」标 1 的频率极高),且没有任何正常语料把「我爱中」当一个词。规则层面:只要「中」标 1(end)而其后又接「国」「民」新词,得到的就是「我爱中/国人民」这种不存在的切分——模型从语料学到的转移与释放概率会让这类序列的似然值极低,这正是这套编码能用来分词的原因。
本章小结
本节是 HMM 的应用图景课:先回顾机器学习的函数定位(,分类或预测),再把 HMM 装进 NLP——词性标注里状态是所有单词(约 20K)、 是词接词的语言模型方阵(Unigram 独立/Bigram 马尔可夫/Trigram 看前两个)、 是「给定词被标为各词性」的分布,学好后新句子标哪套词性似然最大就标哪套;中文分词把观测简化成 0/1(continue/end,零不能结尾、一为结尾);语音识别是 HMM 最早的主场,观测换成 MFCC 等高维声学特征向量。收尾的路标:循环神经网络的隐层跨时刻相连,——HMM 的概率关系被神经网络替代,「基本的思想和想法,跟整个机器学习的发展都是一脉相承的」。
📋 行动清单
- 把词性标注、分词、语音识别三个任务各自的 、、、 含义写在一张表上——体会「骨架不变、 换观测」的设计模式。
- 把本节两段代码的演示语料各扩两句(自己编),重新统计转移与词性分布,检查输出是否符合预期。
- 带着开场的那个问题进入下一节:EM 算法为什么是收敛的——上一章琴生不等式的下界铺垫,下一节见分晓。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载第14章笔记:隐马尔可夫模型(HMM)