目录
- 潜(隐)变量模型
- K-means
- GMM模型
- GMM模型参数估计的EM算法总结
- GMM模型和K-means的联系
- EM算法
- 使用EM算法通用步骤重新考虑GMM参数估计
- EM算法通用解释
- python代码实现
潜(隐)变量模型
观测变量:直接观测的数据
潜变量:
- 无法直接被观测到,需要通过模型和观测变量进行推断
- 利用潜变量来判断观测变量的模型,GMM HMM都是潜变量模型
- 潜变量模型将不完数据(只有观测数据)的边缘分布转化为容易处理的完全数据(观测数据+潜变量)的联合分布。
如:聚类问题,潜变量是类别(未知),观测变量是数据点,给定观测变量,如果推断哪些是同一类?K-means
K-means
给定一个含有N个数据点的集合,,聚类的目标是将此N个数据点聚类到K个类别中,且假设K给定。
K-means思路:
- 引入K个D维均值向量,是第k个类别的聚类中心。
- 计算数据点和所有类中心的距离,类中心距离此数据点最近的类别,即为当前数据点的类别。
- 根据新的聚类结果,使用当前聚集到各个类别的数据的均值来更新当前类别的类中心。
- 返回第2步,直到满足一定的停止准则。
引入潜变量
- 对于每一个数据点引入一个指示因子,如果属于第k类,则,否则即为潜变量
- 定义目标函数
- 优化目标:寻找合适的$r_{nk} \boldsymbol{\mu}_{k}$使目标函数最小。
模型优化:两阶段迭代优化(简单EM)
- 选择初始化的值,并保持固定,关于$r_{nk} J$(E步)
- 保持固定,关于最小化(M步)
K-means应用:图像分割和压缩
GMM模型
高斯分布
- D维高斯变量的高斯分布:
其中,,高斯分布的均值向量,,高斯分布的协方差矩阵。
为什么使用高斯分布?1. 高斯分布在自然界的数据中广泛存在,2.中心极限定理:在适当条件下,大量相互独立随机变量的均值经适当标准化后依分布收敛于正太分布。
最大似然估计
假设随机变量 服从分布 , 即 , 其中, 为待估计的参数,如果可以获得N个互相独立的 的采样点 , 则似然函数的定义为
在实际使用中,一般采用对数似然函数:
参数 的最大似然估计为:
高斯模型的最大似然估计
高斯混合分布
,,为待估计参数。
- 的解释(直观理解为第k个高斯所占的比重)
引入一个K维 one-hot(只有一维为1, 其余维度为0) 向量 , 概率 为 向量z的第k维为的先验概率 ,向量z的分布可以表示为 , 等价于 , where - 条件分布
- 联合分布
- 边缘分布
- 使用贝叶斯公式对潜变量求和:
- 对每一个观测,都有一个潜变量和其对应,上述公式将变量和潜变量联系起来,并且引入了联合分布,完成了将观测数据的边缘分布转换成观测和潜变量的联合分布
- 后验分布
为得到观测后,的后验概率,理解为第k个高斯成分对于生成观测的贡献值。
GMM对数似然函数
其中,,给出潜变量矩阵定义。由公式(1)计算。
GMM模型参数估计的EM算法(最大似然准则)
计算似然函数分别对参数求导:
- 对求导:
- 对求导:
- 对求导:
用拉格朗日乘子法,求解:
等号两边同时乘以 , 并对k求和
GMM模型参数估计的EM算法总结
上述参数估计方法并不是一个严格的解析解,因为公式中有后验概率,依赖于每个高斯的代估计参数。上述推导过程给出了一个迭代的估计参数的过程,并能保证似然逐步增加。
给定一个GMM模型, 优化目标是寻找使似然函数最大的各个高斯成分的均值向量、协方差矩阵和混合系数
- 初始化 初始化参数
- E步 使用当前参数计算后验概率
- M步 使用后验重新估计参数
- 重新计算似然函数, 重复2-4,直至满足收敘条件
GMM模型和K-means的联系
K-means可以看作GMM模型的一个特殊情况,假设公式中,每个单高斯的分布都具有相同的协方差矩阵,并且有,是单位矩阵,高斯分布可以简化为:
公式中的后验概率变为:
当,,对于分母中,假设第m项最小,那么分母上j=m这一项将在的时候以最慢的速度趋于0,因此只有分子上k=m时,,,显然。
K-means是一种硬对齐方式,某个数据点只能对应在某个类别上,GMM是一种软对齐方式,使用后验概率来表示某个数据点由某个类别产生的概率。
EM算法
上述GMM参数估计过程中已经使用到GMM算法,现在具体看一下EM算法。首先通过一个例子来体会。
问题:假设随机抽取100个男生和女生的身高数据,假设男生和女生的身高分布分别服从高斯分布和,请用最大似然法估计男生和女生身高分布的均值和方差。
这里分为两种情况:
情况1:已经知道每个数据对应的性别
男 | 女 | 女 | 男 | 女 | 女 |
178 | 175 | 170 | 175 | 168 | 169 |
其中为男生总人数,为每个男生的身高数据。同理,可求出女生的数据。
情况2:果冻大意了,只统计了身高数据
- | - | - | - | - | - |
178 | 175 | 170 | 175 | 168 | 169 |
这种情况,我们引入一个新的变量,表示第i个数据为男生身高的概率,表示第i个数据为女生的身高的概率。
如何获得?可以采用迭代估计法:
- 先给出一组随机的参数取值
- 更新
- 使用新的p更新 , 重复2-3
含隐变量模型的最大似然估计->EM算法,隐变量与模型参数相互影响,分两步一静一动交替迭代。通用步骤:E步(求期望)、M步(最大化)、重复E、M
给定完全数据 的联合概率分布 , 待学习参数 , 优化的目标是寻找来最大化似然函数p
- 初始化 初始化参数
- E步 计算潜变量的后验概率p(Z|X, )
- M步 使用后验重新估计参数
4. 重算似然 重新计算似然函数,重复2-4, 更新参数 直至满足收敘条件
将不完全数据(只有观测数据)的边缘分布转换成容易处理的完全数据(观测数据+潜变量)的联合分布
深入理解EM算法
- EM算法的目标是寻找潜变量模型的最大似然解。后边我们假定待估计的参数用
- 对数似然函数用完全数据的联合概率表示为:
使用EM算法,一般认为完全数据的联合概率分布的似然容易计算。实际上,完全数据{X,Z}无法获取,但是潜变量Z的后验概率分布可以进行估计。 - 计算完全数据的似然在时,关于变量Z的期望:
- 寻找使Q函数最大的新参数:
当尝试使用EM算法来解决自己的问题时,需要明确Q函数。
使用EM算法通用步骤重新考虑GMM参数估计
在之前的推导中,我们引入了潜变量Z,但并没用用到完全数据的联合概率分布,而是直接对不完全数据X的对数似然进行了求解。根据EM算法的通用步骤,首先考虑完全数据的似然函数:
根据公式(4),计算Z的后验概率:
完全数据的对数似然关于潜变量的期望值:
EM算法通用解释
EM算法的一般假设是直接优化观测数据的似然十分复杂,但是优化完全数据的似然比较容易。引入一个关于变量Z的任意分布:
为什么引用任意一个Z的分布?我们只知道Z服从某一个分布,但是并不知道具体服从什么分布,但是后面的推导会证明,无论Z的真实分布是什么都不影响推导。
令:
KL散度是衡量两个概率分布之间差异的一个度量。
则:
其中:是和的泛函,,当且仅当时等号成立。
- ,所以,只有当后验分布和相等时,等号成立。
- 可以看作是的下界,如果我们无法直接提升的准确值,我们可以提升其下界。
E步:寻找使 最大的 , 当 时, , 此时
M步: 固定 , 寻找使 增加 的新参数 ,因为参数更新, 和 不再相等,此时, 因此导致
与
, 等价于,推导如下:
因此,EM算法中,E步所计算的 实际上等价于计算。
python代码实现
使用GMM-EM实现0-9孤立词识别,介绍GMM对数似然函数、E步、M步的实现,详细参考:
GMM的对数似然函数:
公式:
python代码:
def calc_log_likelihood(self , X):
"""Calculate log likelihood of GMM
param: X: A matrix including data samples, num_samples * D
return: log likelihood of current model
"""
log_llh = 0.0
N = X.shape[0]
log_llh = np.sum([np.log(np.sum([self.pi[k] * self.gaussian(X[n], self.mu[k], self.sigma[k])
for k in range(self.K)])) for n in range(N)])
return log_llh
E步:
公式:
N = X.shape[0]
gamma = [np.zeros(self.K) for i in range(N)] # 后验概率
# E-step
for n in range(N):
post_prob = [self.pi[k] * self.gaussian(X[n], self.mu[k], self.sigma[k]) for k in range(self.K)]
post_prob = np.array(post_prob)
post_prob_sum = np.sum(post_prob)
gamma[n] = post_prob / post_prob_sum
M步:
公式:
# M-step
for k in range(self.K):
Nk = np.sum([gamma[n][k] for n in range(N)])
if Nk == 0:
continue
self.pi[k] = Nk / N
self.mu[k] = 1.0 / Nk * np.sum([gamma[n][k] * X[n] for n in range(N)], axis=0)
diffs = X - self.mu[k]
self.sigma[k] = 1.0 / Nk * np.sum([gamma[n][k] * diffs[n].reshape(self.dim, 1) * diffs[n]
for n in range(N)], axis=0)
log_llh = self.calc_log_likelihood(X)