查看全课大纲(第 60 / 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 回传
HMM 在 NLP 中的运用:从分词到机器翻译
约 17 分钟
小象实战讲义 · 机器学习算法精讲
上一节收尾在循环神经网络——本节开场讲师先把这件事按住:「RNN 做的事情,跟我们这个做的是一回事。」接着把 NLP 的标注问题从简单到难重排一遍(讲师自我修正:「这个稍复杂,如果从简单到难,应该先这样讲」),并在最后加上第四个问题:机器翻译——它涉及对齐与长度变化,比语音识别还要复杂。做完这趟 NLP 之旅,讲师把话锋转回 HMM 本身:「我们还没有对 HMM 进行参数的估计」——维特比与 Baum-Welch 两个名字在这里正式出现,、 矩阵的定义重述一遍,为下一节的估计公式开题。
💡 核心导读
- 标注问题的四档难度:分词(0/1 marker)、词性标注(名词/动词/…)、语音识别(特征向量)、机器翻译(英文词)——观测换装,骨架不变。
- 分词的多解性:同一串字符「我爱中国人民银行」对应多套合法 marker 序列——标注本身就是监督信号。
- 翻译=学标注关系:不把语言当语言,把它当「被加密的符号」——统计翻译的思想基础。
- 方法论沉淀:深奥的 NLP 问题都能用「我们会的一个机器学习模型」解释;最底层的数学与模型认知比编程更珍贵。
- HMM 三件事凑齐名字:算 (前向-后向)、找最优状态(维特比)、估参数(Baum-Welch);、 的正式定义,释放 还可以是高斯混合。
从简单到难:重排 NLP 的标注问题
上节从词性标注讲起,其实顺序偏难了。按「从简单到难」重排,第一个问题最简单——给定的标注是 0/1,用来分词。
讲师重新把例子写得「更有意思一些」:把「我爱中国人民银行」整个连在一起写在黑板上——「甚至我不要这么写(预先分好),这样写大家都会觉得我已经知道分词了。」然后口头切分着玩:「我爱中国。人民银行,可以吧?反正什么词,管它呢。」同一串字,训练数据里可以出现不同的标注:一套 0/1 标成五个词,另一套把「中国人民银行」整个标成一个大词——「哎,其实一个大词,这也是可以。」用代码把几种合法切分的 marker 序列都生成出来(口播的 0/1 串以按切分重新生成的为准):
# 分词 = 给字串标 0/1: 0 = 词内继续, 1 = 词到此截止
# 同一串字符「我爱中国人民银行」, 不同切分 -> 不同 marker 序列
# (板书口播的 0/1 串以代码按切分重新生成为准——正确性优先)
chars = "我爱中国人民银行"
def markers(words):
"""把切分转成 0/1 marker 序列: 词内 0, 最后一字 1"""
seq = []
for w in words:
seq += [0] * (len(w) - 1) + [1]
return seq
segs = [
["我", "爱", "中国", "人民", "银行"],
["我", "爱", "中国", "人民银行"],
["我", "爱", "中国人民银行"],
["我", "爱", "中", "国", "人民", "银行"],
]
print(f"字串: {chars} ({len(chars)} 字)")
print()
for words in segs:
m = markers(words)
ok = "".join(words) == chars and m[-1] == 1
print(f"{' / '.join(words)}")
print(f" marker = {''.join(map(str, m))} ({len(words)} 个词, 合法性 {'OK' if ok else 'NG'})")
print()
# 任何一个「末位为 1」的 0/1 序列都是一个合法分词——「反正什么词, 管它呢」
n = len(chars)
print(f"合法性规则只有一条: 末位必为 1 (词必须截止)")
print(f"所以 {n} 字字串的合法标注共有 2^{n-1} = {2**(n-1)} 种 —— 同一句话, 128 种监督信号")字串: 我爱中国人民银行 (8 字)
我 / 爱 / 中国 / 人民 / 银行
marker = 11010101 (5 个词, 合法性 OK)
我 / 爱 / 中国 / 人民银行
marker = 11010001 (4 个词, 合法性 OK)
我 / 爱 / 中国人民银行
marker = 11000001 (3 个词, 合法性 OK)
我 / 爱 / 中 / 国 / 人民 / 银行
marker = 11110101 (6 个词, 合法性 OK)
合法性规则只有一条: 末位必为 1 (词必须截止)
所以 8 字字串的合法标注共有 2^7 = 128 种 —— 同一句话, 128 种监督信号这串例子把 14.1 的 0/1 编码往前推了一步:同一句话有 128 套合法标注,语料给哪一套,模型就学哪一套——标注本身就是监督信号。而且分词时 矩阵特别简单: 只有 0 和 1 两个取值,每个状态两列就装下了。
第二个问题,词性标注——分词已经有了之后再做:我(名词)、爱(动词)、中国(名词)、人民银行(讲师自注:「具体词性标注我不太记得了,可能是个名词短语或什么其他吧,假设我们先这样去写」)。总之会有很多这样的标注,这块叫 POS tagging(part of speech tagging),刚才那块叫 segmentation(分词)。
第三个问题,语音识别:标注不再是一个词性,而是一个向量——比如某个状态标注 ,另一个标 ……「这里边的向量其实代表什么呢?从语音系统里边抽象出来的这些特征」——这就是上一节讲过的 speech recognition。
第四个问题:机器翻译
还是这些词,讲师又换了一支蓝色的粉笔——第四种标注是英文:句子上方标出「I love people’s bank of China」(讲师第一次口误读岔了,自己纠正:「可能是一般来讲不会这样说话的,可能是这样的」)。这一段英文是什么?是这句话对它的英文翻译。于是「我们就学习它们之间的标注关系——不就是学习一个自然语言翻译嘛。」这里的思想非常朴素:
我们并不把它看成语言——词与词之间的、一个 marker 或标志之间的关系而已。
就像有人最早说过的:看到一串俄语,我并不觉得它是「俄语」,我觉得它是用一种英文加密的方式在写;看到阿拉伯语,觉得是有种信号把我们熟悉的话加密成了这种符号——我看到符号解密就可以了。「所以这种形式实际上变成了后来一直到今天,自然语言翻译最重要的基础。」历史上正好是一个转折:以前做翻译要根据语法、词典,分析 people 和「人民」之间有什么对应关系;后来人们渐渐放弃了这条路线,完全基于大量语料库、训练它们之间的对应关系。
讲师讲了一个有名的故事:吴军的老师 Jelinek(Frederick Jelinek,先在 IBM 领导统计语音与语言研究、后来去了 Johns Hopkins)在做统计翻译系统时说过一句经典的话——
我每次开除一个语言学家,我这个系统的性能就能提高一点。
「后来会发现,做语言翻译的这些人全是计算机学家,根本不懂任何语法,但仍然翻译得非常好,比语言学家翻译得还好。」所以到今天,处理自然语言的(包括我们自己),都可以把这些语言当成数据——不理解深奥的语言学语法,照样做词性标注、词的分类、机器翻译。
但翻译的难度要高很多。刚才所有问题里,标签与字词都是一对一的关系;而翻译时「China」对应的是「中国」,没有对齐。它还涉及句子长短不一样:这里可能是四个词,翻译出来是六个词;原先五个词,翻出来八个词。「首先词长短不一样,所对齐的方式也不一样。之后呢,才有这个标注,再学习标注。所以自然语言翻译要远远难于词性标注和分词,甚至比语音识别还要复杂很多。」当然,今天的翻译大部分已经是基于 RNN 式结构的了——RNN 里还有一些极端的方式,比如 LSTM(Long Short-Term Memory)。「这个在深度学习里面大家会有很多讲述,我们这课里就不讲了。」它的 capability(自由度)比这个模型更广泛:可以考虑一个词跟它前面很久很久的词之间的关系——这是 HMM 没有做到过的。
方法论:模型认知比编程更珍贵
到这里讲师特意停下来讲了一段方法论。研究自然语言里三个(加上翻译是四个)非常深奥的问题,我们都可以用一个我们会用的机器学习模型去解释;如果模型学得更好、在里面加更多假设、知道更多先验,就会把这个模型做得非常好。
今天很多学机器学习、需要学人工智能的人——其实最底层的数学和对这个模型的认知是最重要的。看到一个实际的问题,如何把它抽象成一个数学问题(或者一个机器学习问题),之后再编程出来,这才是一个完整的解决步骤。
「反而会编程的人多了好多,但是能把这个具体背后的东西理解出来、或者做出模型的人,显得非常珍贵。」所以做算法工程师,实际上主要就是在做这件事——找到特别合适的一种算法去解决这个问题。这句话和上一节 EM 开场的「最底层」遥相呼应:这一整章的用意,就是把底层交到你手里。
回到 HMM:参数怎么估(开题)
方法论讲完,话锋一转:「HMM——我们回过头来说这件事,我们还没有对 HMM 进行刚才的这个参数的估计。」先盘点已经会的东西:
- 算 :通过前向后向算法,任何一个 都可以估计成所有 的和——形式上就是 (13.4 走过的完整表格);
- 给定一组 求极大似然值:这件事已经会了;
- 对某一个状态做估计:给定了好多可观察量的时候,想知道某一时刻状态的概率——它就是 ,其中 从前往后推、 从后往前推(前向后向算法的公式,上次课已有描述)。
再往前一步:给定很多 ,「我们就使这个 最大就可以了——那就找到了给定这些观察数据的时候,哪些状态的极大似然最大。」这一步有个通行的名字,讲师在这里正式点出:维特比算法(Viterbi)。(小注:严格的维特比是「整条状态路径最优」的动态规划;讲师此处按「使 最大」的口径点名,方向一致、口径从宽。)而今天要用另外一个算法——Baum-Welch——来推断这里边的具体参数该怎么估计。到这里,经典 HMM 的三件事凑齐了名字:算 用前向-后向、找最优状态用维特比、估参数用 Baum-Welch。
A 与 B 的正式定义:Baum-Welch 的原料
往下推之前,把两个矩阵的定义正式重述一遍(这是下一节的原料)。
先看两条条件独立——「这个大家已经知道,不用解释了」:
- 。观察到以前的数据和以前的状态时,当前状态的概率——因为它本身是隐马尔可夫链的结构, 的概率最直接相关的就是前一个状态;
- 。板书上从 一直写到 、 一直写到 ,但中间偏偏没有 ——「最重要的是目前的这个 ,才跟 是直接相关的。」
转移矩阵 (板书花絮:讲师写「 等于 ——Sorry,写到上面」,顺手把下标搬正):
任何两个状态之间的 transformation(过渡)。下标 、 从 1 一直循环到最大状态值:有三种状态就是 ,八种状态就是 ,两万种状态——就像刚才自然语言那个例子——就是两万乘两万。
释放矩阵 :
「状态等于 的时候,观察到 这个值的概率是多大」——这就是 的定义。而 的形态是自由的:「我们当然可以把这个 认为是一个高斯分布,或者是一个伯努利分布——都可以。」比如状态 的释放用一个两分量高斯混合(板书花絮:讲师先说「派一加上第一个」又自己改口「sorry 不用,派一乘上第一个」):
「这都是可以的。」把这条板书落成数——它就是 12 章三硬币、13 章高斯混合的又一次重逢,只不过现在嵌在 HMM 的 矩阵里:
import math
# 释放概率 B 不必是离散表格——讲师板书: b_j(y) 可以是高斯混合
# b_j(y) = pi_1 * N(y | mu_1, sigma_1) + pi_2 * N(y | mu_2, sigma_2)
def gauss(y, mu, sigma):
return math.exp(-0.5 * ((y - mu) / sigma) ** 2) / (sigma * math.sqrt(2 * math.pi))
pi1, mu1, s1 = 0.6, 2.0, 0.5 # 分量 1
pi2, mu2, s2 = 0.4, 5.0, 1.0 # 分量 2
print(f"b_j(y) = {pi1}*N(y|mu={mu1}, sigma={s1}) + {pi2}*N(y|mu={mu2}, sigma={s2})")
print(f"权重检查: pi_1 + pi_2 = {pi1} + {pi2} = {pi1 + pi2}")
print()
print(f"{'y':>4} | {'pi_1*N_1':>10} | {'pi_2*N_2':>10} | {'b_j(y)':>8}")
for y in [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]:
c1 = pi1 * gauss(y, mu1, s1)
c2 = pi2 * gauss(y, mu2, s2)
print(f"{y:4.1f} | {c1:10.4f} | {c2:10.4f} | {c1 + c2:8.4f}")b_j(y) = 0.6*N(y|mu=2.0, sigma=0.5) + 0.4*N(y|mu=5.0, sigma=1.0)
权重检查: pi_1 + pi_2 = 0.6 + 0.4 = 1.0
y | pi_1*N_1 | pi_2*N_2 | b_j(y)
1.0 | 0.0648 | 0.0001 | 0.0648
2.0 | 0.4787 | 0.0018 | 0.4805
3.0 | 0.0648 | 0.0216 | 0.0864
4.0 | 0.0002 | 0.0968 | 0.0969
5.0 | 0.0000 | 0.1596 | 0.1596
6.0 | 0.0000 | 0.0968 | 0.0968一眼看去是双峰: 靠近 2 时分量 1 说了算(0.4787 的绝对主力),靠近 5 时分量 2 接管(0.1596)——一个状态内部再挂一个混合模型, 就有了「一峰不够再补一峰」的表达力。参数全给定了,具体怎么从数据里把它们估计出来——、、 每一个怎么算——就是下一节 Baum-Welch 要正式展开的内容。
📝 动手练一练
- marker 的多解与计数:「我爱中国人民银行」(8 字)除代码里四种切分外还有许多合法标注。(a) 证明: 字字串的合法 marker 序列总数是 ;(b) 手写「我 / 爱 / 中国人民 / 银行」的 marker 序列,并验证末位规则。
👉 点击查看参考答案
(a) 合法性规则只有一条:末位必为 1(最后一个词必须截止),前 位每一位独立地取 0 或 1——所以总数 。8 字即 种。每一种 0/1 串都唯一对应一个切分(连续的 0 段加末尾的 1 就是一个词),所以「标注」与「切分」一一对应。
(b) 我(1)、爱(1)、中(0)、国(0)、人(0)、民(1)、银(0)、行(1)——marker 为 ,末位为 1,合法。词数 = 1 的个数 = 4:我、爱、中国人民、银行。
- 释放概率的形态:状态 的释放用高斯混合 。(a) 权重要满足什么约束?(b) 这与 12 章的哪个模型是重逢?13.4 讲过的「动态混合」与这里的用法差在哪?(c) 如果观测是离散的 0/1(分词 marker), 该长什么样、满足什么约束?
👉 点击查看参考答案
(a) 且各 (本课代码里的 0.6 + 0.4 = 1.0 即此约束)。
(b) 与 12 章的三硬币(伯努利混合)、男女生身高(高斯混合)同一形态——静态混合。区别在装法:13.4 的动态混合把混合分量放进状态、分量间的跳跃由 控制( 管跳跃、 管各高斯的 );本节的用法是给单个状态的释放再装一个内部混合——一个在状态之间跳、一个在状态内部混,两种装法都成立。
(c) 两列的伯努利表:,——约束就是把一行加起来等于 1。
本章小结
本节先把 NLP 的标注问题按难度重排:分词(0/1 marker,同一句话 128 套合法标注——标注即监督)、词性标注(分词之后再逐词标)、语音识别(标注是语音特征向量),再添上第四个问题机器翻译——把语言当「被加密的符号」、用大量语料学对应关系(Jelinek「开除语言学家」的名言),但对齐与长度变化使它比语音识别还难,今天的解法是 RNN/LSTM(本课不展开)。方法论沉淀成一句话:最底层的数学与模型认知最珍贵,算法工程师的本职是把现实问题抽象成数学问题再选对算法。后半节回到 HMM 参数估计的开题:已会 、极大似然与 ;三件事凑齐名字(前向-后向、维特比、Baum-Welch); 与 正式定义,释放还可以用高斯混合——具体怎么估,下一节 Baum-Welch 展开。
📋 行动清单
- 在 14.1 的「三问题表」上添第四行:机器翻译—— 与标注各是什么、难在哪(对齐、长度)。
- 给自己写一句话(8 字以上),仿照代码块枚举三种合法切分并验证 marker 合法性。
- 回顾 12.2-12.3 的静态混合与 13.4 的动态混合,对照本节 的高斯混合形态,把三种「混合装法」各写一句话。
- 带着开题的问题进入下一节:Baum-Welch 里 、、 的估计公式怎么落地。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载第14章笔记:隐马尔可夫模型(HMM)