【1024特辑 | 机器学习-无监督学习】EM算法
本文介绍了求解带有隐变量数据分布下的MLE问题的EM算法,动手实现了GMM拟合数据分布,讲解了一般情况下的EM算法及其收敛性。
【作者主页】Francek Chen
【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科,通过算法和模型让计算机从数据中学习,进行模型训练和优化,做出预测、分类和决策支持。Python成为机器学习的首选语言,依赖于强大的开源库如Scikit-learn、TensorFlow和PyTorch。本专栏介绍机器学习的相关算法以及基于Python的算法实现。
【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/Python_machine_learning。
本文我们继续介绍概率相关模型的算法。在前面的文章中,我们已经讲解了贝叶斯网络与最大似然估计(MLE)。设数据集的样本为 x 1 , x 2 , ⋯ , x N \boldsymbol x_1,\boldsymbol x_2,\cdots,\boldsymbol x_N x1,x2,⋯,xN,标签为 y 1 , y 2 , ⋯ , y N y_1,y_2,\cdots,y_N y1,y2,⋯,yN,我们用 X \boldsymbol X X和 y \boldsymbol y y分别表示全体样本和全体标签。对于监督学习的任务,我们可以通过最大化对数似然 l ( w ) = log P ( y ∣ X , w ) l(\boldsymbol w)=\log P(\boldsymbol y|\boldsymbol X,\boldsymbol w) l(w)=logP(y∣X,w) 来求解模型的参数 w \boldsymbol w w。而对于无监督学习任务,我们要求解样本 X \boldsymbol X X的分布。这时,我们通常需要先假设数据服从某种分布,再求解这个分布的参数。例如假设数据呈现高斯分布 N ( μ , Σ ) \mathcal N(\boldsymbol\mu,\boldsymbol\Sigma) N(μ,Σ),然后可以通过MLE的方式来求得最佳的高斯分布参数 μ \boldsymbol\mu μ和 Σ \boldsymbol\Sigma Σ。
更进一步思考,真实世界的数据分布往往较为复杂,其背后往往具有一定的结构性,直接使用一个概率分布模型无法有效刻画数据分布。例如,我们可以假设数据服从高斯混合模型(Gaussian mixture model,GMM),即 N ( μ 1 , Σ 1 , ⋯ , μ k , Σ k ) \mathcal N(\boldsymbol\mu_1,\boldsymbol\Sigma_1,\cdots,\boldsymbol\mu_k,\boldsymbol\Sigma_k) N(μ1,Σ1,⋯,μk,Σk),该模型是由 k k k个相互独立的高斯分布 N i ( μ i , Σ i ) ( i = 1 , ⋯ , k ) \mathcal N_i(\boldsymbol\mu_i,\boldsymbol\Sigma_i)(i=1,\cdots,k) Ni(μi,Σi)(i=1,⋯,k) 组合而成的,数据集中的每个样本 x j \boldsymbol x_j xj都从其中的某个高斯分布采样得到。在现实生活中,符合GMM的数据集有很多。例如,我们统计了某学校中所有学生的身高。通常认为,人的身高是在某个均值附近的高斯分布,然而男生和女生身高的均值是不同的。因此,我们可以认为男生身高和女生身高分别服从不同的高斯分布,而总的数据集就符合GMM。
在GMM中,我们要求解的参数共有两种,一种是每个高斯分布的参数 μ i \boldsymbol\mu_i μi和 Σ i \boldsymbol\Sigma_i Σi,另一种是每个高斯分布在GMM中的占比。记 z ∈ 1 , ⋯ , k z\in 1,\cdots,k z∈1,⋯,k 是高斯分布的编号, z z z出现的次数越多,从分布 N ( μ z , Σ z ) \mathcal N(\boldsymbol\mu_z,\boldsymbol\Sigma_z) N(μz,Σz)采样的数据在数据集中的占比就越大。所以,后者相当于求解 z z z的多项分布 p ( z ) p(z) p(z)。
从贝叶斯网络的角度来看,上面的分析过程建立了如下图1所示的贝叶斯网络。其中, ϕ \boldsymbol\phi ϕ是多项分布 p ( z ) p(z) p(z)的参数, z z z取 1 , ⋯ , k 1,\cdots,k 1,⋯,k 的概率分别是 ϕ 1 , ⋯ , ϕ k \phi_1,\cdots,\phi_k ϕ1,⋯,ϕk。而对每个样本 x i \boldsymbol x_i xi,我们先从多项分布中采样 z i \boldsymbol z_i zi,确定样本属于哪个高斯分布,再从该高斯分布 N ( μ z i , Σ z i ) \mathcal N(\boldsymbol\mu_{z_i},\boldsymbol\Sigma_{z_i}) N(μzi,Σzi)中采样出样本 x i \boldsymbol x_i xi。于是,我们可以利用中间变量 z z z把 x \boldsymbol x x的分布拆分为 p ( x ) = p ( x ∣ z ) p ( z ) p(\boldsymbol x)=p(\boldsymbol x|z)p(z) p(x)=p(x∣z)p(z)。
按照MLE的思想,参数的似然就是在此参数条件下出现观测到的数据分布的概率,也即
L
(
ϕ
,
μ
,
Σ
)
=
P
(
X
∣
ϕ
,
μ
,
Σ
)
L(\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma)=P(\boldsymbol X|\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma)
L(ϕ,μ,Σ)=P(X∣ϕ,μ,Σ)。我们将似然取对数,得到
l
(
ϕ
,
μ
,
Σ
)
=
log
L
(
ϕ
,
μ
,
Σ
)
=
log
P
(
X
∣
ϕ
,
μ
,
Σ
)
=
log
∏
i
=
1
N
P
(
x
i
∣
ϕ
,
μ
,
Σ
)
=
∑
i
=
1
N
log
P
(
x
i
∣
ϕ
,
μ
,
Σ
)
=
∑
i
=
1
N
log
∑
j
=
1
k
P
(
x
i
∣
z
=
j
,
μ
j
,
Σ
j
)
P
(
z
=
j
∣
ϕ
j
)
=
∑
i
=
1
N
log
∑
j
=
1
k
N
(
x
i
∣
μ
j
,
Σ
j
)
ϕ
j
\begin{aligned} l(\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) &= \log L(\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) = \log P(\boldsymbol X|\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) \\ &= \log\prod_{i=1}^NP(\boldsymbol x_i|\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) \\ &= \sum_{i=1}^N\log P(\boldsymbol x_i|\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) \\ &= \sum_{i=1}^N\log\sum_{j=1}^kP(\boldsymbol x_i|z=j,\boldsymbol\mu_j,\boldsymbol\Sigma_j)P(z=j|\phi_j) \\ &= \sum_{i=1}^N\log\sum_{j=1}^k\mathcal N(\boldsymbol x_i|\boldsymbol\mu_j,\boldsymbol\Sigma_j)\phi_j \end{aligned}
l(ϕ,μ,Σ)=logL(ϕ,μ,Σ)=logP(X∣ϕ,μ,Σ)=logi=1∏NP(xi∣ϕ,μ,Σ)=i=1∑NlogP(xi∣ϕ,μ,Σ)=i=1∑Nlogj=1∑kP(xi∣z=j,μj,Σj)P(z=j∣ϕj)=i=1∑Nlogj=1∑kN(xi∣μj,Σj)ϕj 为了求出使对数似然最大化的参数,我们需要令对数似然对3个参数的梯度均为零:
∇
ϕ
l
(
ϕ
,
μ
,
Σ
)
=
0
,
∇
μ
l
(
ϕ
,
μ
,
Σ
)
=
0
,
∇
Σ
l
(
ϕ
,
μ
,
Σ
)
=
0
\nabla_{\boldsymbol\phi}l(\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma)=\boldsymbol 0, \quad \nabla_{\boldsymbol\mu}l(\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma)=\boldsymbol 0, \quad \nabla_{\boldsymbol\Sigma}l(\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma)=\boldsymbol 0
∇ϕl(ϕ,μ,Σ)=0,∇μl(ϕ,μ,Σ)=0,∇Σl(ϕ,μ,Σ)=0
然而,上述方程的求解非常复杂,并且没有解析解。因此,我们需要寻找其他方法求解。本文介绍的EM算法是一种求解复杂分布参数的通用算法。
一、高斯混合模型的EM算法
我们在最开始为了拆分
X
\boldsymbol X
X的分布引入了中间变量
z
z
z,用来指示每个样本属于哪个高斯分布,而
z
z
z的分布就是混合高斯分布中每个分布的占比。像这样虽然不能直接被观测到、但是可以直接影响最后观测结果的变量,就称为隐变量(latent variable)。通常来说,隐变量比可观测的变量更本质。因此,我们经常会用引入隐变量的方法来把复杂的问题简单化。同时,隐变量也对问题的求解有关键作用。在对数似然的表达式中,如果每个样本
x
i
\boldsymbol x_i
xi所属的高斯分布编号
z
i
z_i
zi已知,那么推导的倒数第二步中
P
(
x
i
∣
z
=
j
,
μ
j
,
Σ
j
)
P(\boldsymbol x_i|z=j,\boldsymbol\mu_j,\boldsymbol\Sigma_j)
P(xi∣z=j,μj,Σj) 一项在
j
≠
z
i
j\neq z_i
j=zi 时就变为0。因此,对数似然可以写为
l
(
ϕ
,
μ
,
Σ
)
=
∑
i
=
1
N
log
P
(
x
i
∣
z
=
z
i
,
μ
i
,
Σ
i
)
P
(
z
=
z
i
∣
ϕ
)
=
∑
i
=
1
N
(
log
N
(
x
i
∣
μ
i
,
Σ
i
)
+
log
ϕ
z
i
)
\begin{aligned} l(\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) &= \sum_{i=1}^N\log P(\boldsymbol x_i|z=z_i,\boldsymbol\mu_i,\boldsymbol\Sigma_i)P(z=z_i|\boldsymbol\phi) \\ &= \sum_{i=1}^N(\log\mathcal N(\boldsymbol x_i|\boldsymbol\mu_i,\boldsymbol\Sigma_i)+\log\phi_{z_i}) \end{aligned}
l(ϕ,μ,Σ)=i=1∑NlogP(xi∣z=zi,μi,Σi)P(z=zi∣ϕ)=i=1∑N(logN(xi∣μi,Σi)+logϕzi) 求这一函数的最大值就相对容易了。首先,由于
z
z
z已知,其多项分布的参数
ϕ
\boldsymbol\phi
ϕ可以直接通过统计数据集中属于每个高斯分布的样本比例得到:
N
i
=
∑
j
=
1
N
I
(
z
j
=
i
)
ϕ
i
=
N
i
N
\begin{aligned} N_i &= \sum_{j=1}^N\mathbb I(z_j=i) \\ \phi_i &=\frac{N_i}{N} \end{aligned}
Niϕi=j=1∑NI(zj=i)=NNi 其中,
N
i
N_i
Ni表示数据集中属于第
i
i
i个高斯分布的样本数目。每个高斯分布之间的参数是相互独立的,并且在
z
z
z已知的条件下,它们也和
ϕ
\boldsymbol\phi
ϕ独立。这一点从图1的贝叶斯网络示意图中也可以看出来,当中间的节点
z
z
z已知时,左右两端的节点之间不存在依赖关系。高斯分布的参数分别是均值和协方差,也可以从数据集中属于该分布的样本直接计算出来:
μ
i
=
1
N
i
∑
j
=
1
N
I
(
z
j
=
i
)
x
j
\boldsymbol\mu_i=\frac{1}{N_i}\sum_{j=1}^N\mathbb I(z_j=i)\boldsymbol x_j
μi=Ni1j=1∑NI(zj=i)xj
Σ
i
=
1
N
i
−
1
∑
j
=
1
N
I
(
z
j
=
i
)
(
x
j
−
μ
i
)
T
(
x
j
−
μ
i
)
\boldsymbol\Sigma_i=\frac{1}{N_i-1}\sum_{j=1}^N\mathbb I(z_j=i)(\boldsymbol x_j-\boldsymbol\mu_i)^{\mathrm T}(\boldsymbol x_j-\boldsymbol\mu_i)
Σi=Ni−11j=1∑NI(zj=i)(xj−μi)T(xj−μi) 求和中每一项的因子
I
(
z
j
=
i
)
\mathbb I(z_j=i)
I(zj=i) 是为了筛选出属于第
i
i
i个高斯分布的样本。如果样本
x
j
\boldsymbol x_j
xj不属于分布
i
i
i,那么这一项就为0,对求和没有贡献。如果我们已知的是隐变量
z
z
z的分布
q
(
z
∣
x
)
q(z|\boldsymbol x)
q(z∣x),也即第
j
j
j个样本
x
j
\boldsymbol x_j
xj属于第
i
i
i个高斯分布的概率是
q
(
z
=
i
∣
x
j
)
q(z=i|\boldsymbol x_j)
q(z=i∣xj),那么上面3个计算公式也相应的改为
ϕ
i
=
1
N
∑
j
=
1
N
q
(
z
=
i
∣
x
j
)
μ
i
=
1
N
ϕ
i
∑
j
=
1
N
q
(
z
=
i
∣
x
j
)
x
j
Σ
i
=
1
(
N
−
1
)
ϕ
i
∑
j
=
1
N
q
(
z
=
i
∣
x
j
)
(
x
j
−
μ
i
)
T
(
x
j
−
μ
i
)
\begin{aligned} \phi_i &= \frac{1}{N}\sum_{j=1}^Nq(z=i|\boldsymbol x_j) \\ \boldsymbol\mu_i &= \frac{1}{N\phi_i}\sum_{j=1}^Nq(z=i|\boldsymbol x_j)\boldsymbol x_j \\ \boldsymbol\Sigma_i &= \frac{1}{(N-1)\phi_i}\sum_{j=1}^Nq(z=i|\boldsymbol x_j)(\boldsymbol x_j-\boldsymbol\mu_i)^{\mathrm T}(\boldsymbol x_j-\boldsymbol\mu_i) \end{aligned}
ϕiμiΣi=N1j=1∑Nq(z=i∣xj)=Nϕi1j=1∑Nq(z=i∣xj)xj=(N−1)ϕi1j=1∑Nq(z=i∣xj)(xj−μi)T(xj−μi)
反过来考虑,如果我们已经知道了分布的参数
ϕ
\boldsymbol\phi
ϕ、
μ
\boldsymbol\mu
μ和
Σ
\boldsymbol\Sigma
Σ我们同样也可以推断出每个样本
x
i
\boldsymbol x_i
xi属于第
j
j
j个高斯分布的概率
P
(
z
i
=
j
∣
x
i
,
ϕ
,
μ
,
Σ
)
P(z_i=j|\boldsymbol x_i,\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma)
P(zi=j∣xi,ϕ,μ,Σ)。根据贝叶斯公式可以得到
z
z
z的后验分布为
P
(
z
i
=
j
∣
x
i
,
ϕ
,
μ
,
Σ
)
=
P
(
x
i
∣
z
i
=
j
,
μ
,
Σ
)
P
(
z
i
=
j
∣
ϕ
)
P
(
x
i
,
ϕ
,
μ
,
Σ
)
=
P
(
x
i
∣
z
i
=
j
,
μ
j
,
Σ
j
)
P
(
z
i
=
j
∣
ϕ
)
∑
l
=
1
k
P
(
x
i
∣
z
i
=
l
,
μ
l
,
Σ
l
)
P
(
z
i
=
l
∣
ϕ
)
=
N
(
x
i
∣
μ
j
,
Σ
j
)
ϕ
j
∑
l
=
1
k
N
(
x
i
∣
μ
l
,
Σ
l
)
ϕ
l
\begin{aligned} P(z_i=j|\boldsymbol x_i,\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) &= \frac{P(\boldsymbol x_i|z_i=j,\boldsymbol\mu,\boldsymbol\Sigma)P(z_i=j|\boldsymbol\phi)}{P(\boldsymbol x_i,\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma)} \\ &= \frac{P(\boldsymbol x_i|z_i=j,\boldsymbol\mu_j,\boldsymbol\Sigma_j)P(z_i=j|\boldsymbol\phi)}{\sum\limits_{l=1}^kP(\boldsymbol x_i|z_i=l,\boldsymbol\mu_l,\boldsymbol\Sigma_l)P(z_i=l|\boldsymbol\phi)} \\ &= \frac{\mathcal N(\boldsymbol x_i|\boldsymbol\mu_j,\boldsymbol\Sigma_j)\phi_j}{\sum\limits_{l=1}^k\mathcal N(\boldsymbol x_i|\boldsymbol\mu_l,\boldsymbol\Sigma_l)\phi_l} \end{aligned}
P(zi=j∣xi,ϕ,μ,Σ)=P(xi,ϕ,μ,Σ)P(xi∣zi=j,μ,Σ)P(zi=j∣ϕ)=l=1∑kP(xi∣zi=l,μl,Σl)P(zi=l∣ϕ)P(xi∣zi=j,μj,Σj)P(zi=j∣ϕ)=l=1∑kN(xi∣μl,Σl)ϕlN(xi∣μj,Σj)ϕj 在各个参数已知的情况下,分子分母都可以直接计算出来。到此为止,看起来我们似乎在进行循环论证,在已知
z
z
z的前提下可以计算出参数
ϕ
\boldsymbol\phi
ϕ、
μ
\boldsymbol\mu
μ和
Σ
\boldsymbol\Sigma
Σ,而在已知参数的前提下可以计算出
z
z
z,但是这两者都是未知的。因此,我们可以采用之前用过许多次的近似方式,先固定其中一方来优化另一方,再反过来固定另一方,如此迭代,这就形成了EM算法的基本思想。具体在本例中,EM算法每一次迭代由两步构成:
-
期望步骤(E-step):固定各个参数,由数据集中的样本统计计算隐变量 z z z的后验分布 p ( z ∣ X , ϕ , μ , Σ ) p(z|\boldsymbol X,\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) p(z∣X,ϕ,μ,Σ)。
-
最大化步骤(M-step):固定隐变量,最大化参数的对数似然 l ( ϕ , μ , Σ ) l(\boldsymbol\phi,\boldsymbol\mu,\boldsymbol\Sigma) l(ϕ,μ,Σ)。
由于两步分别在计算样本的统计期望和最大化参数的对数似然,这样交替优化隐变量和参数的方法就称为期望最大化算法(Expectation-maximization algorithm),简称EM算法。
二、动手求解GMM拟合数据分布
虽然GMM是由高斯分布组成的,然而理论上它可以用来拟合任意的数据分布。如图2所示,左上角是由 y = sin x y=\sin x y=sinx 加上随机的高斯噪声生成的数据,显然这些数据并不符合高斯分布。如果我们试图用两个高斯分布来拟合数据,如右上角所示,每个椭圆形区域表示拟合出的一个高斯分布,可以看出该结果与实际数据偏差仍然较大。但是,当我们继续增加GMM中高斯分布的数目时,拟合结果也会越来越精确。下图的左下方和右下方分别展示了用5个和10个高斯分布拟合出的结果,已经可以基本覆盖所有的数据点,且几乎没有多出的区域。事实上我们可以证明,任何数据分布都可以用GMM来无限逼近。而在现实场景中,由于高斯分布简单易算、性质良好,GMM也就成为了最常用的模型之一。
从上图的拟合结果中我们还可以发现,如果我们有一组分布未知的数据,并且还希望能按照同样的分布生成一些新的数据,那么也可以先用GMM对数据进行拟合,再由它来继续做数据生成。因此,从数据中拟合GMM就变得十分重要。下面,我们就来用上文介绍的EM算法来求解GMM模型。简单起见,我们就采用与上图左上角中相同的正弦数据集。
import numpy as np
import matplotlib.pyplot as plt
X = np.loadtxt('sindata.csv', delimiter=',')
在实现EM算法之前,我们先来定义计算高斯分布概率密度
N
(
x
∣
μ
,
Σ
)
\mathcal N(\boldsymbol x|\boldsymbol\mu,\boldsymbol\Sigma)
N(x∣μ,Σ)的函数。设
x
∈
R
d
\boldsymbol x\in\mathbb R^d
x∈Rd,那么概率密度的表达式为
N
(
x
∣
μ
,
Σ
)
=
1
(
2
π
)
d
∣
Σ
∣
e
−
1
2
(
x
−
μ
)
T
Σ
−
1
(
x
−
μ
)
\mathcal N(\boldsymbol x|\boldsymbol\mu,\boldsymbol\Sigma)=\frac{1}{\sqrt{(2\pi)^d|\boldsymbol\Sigma|}}\mathrm{e}^{-\frac{1}{2}(\boldsymbol x-\boldsymbol\mu)^{\mathrm T}\boldsymbol\Sigma^{-1}(\boldsymbol x-\boldsymbol\mu)}
N(x∣μ,Σ)=(2π)d∣Σ∣1e−21(x−μ)TΣ−1(x−μ) 式中,
∣
Σ
∣
|\boldsymbol\Sigma|
∣Σ∣表示矩阵
Σ
\boldsymbol\Sigma
Σ的行列式,可以用numpy.linalg
中的工具直接计算得到。此外,我们通常会计算概率密度的对数而非概率密度本身,这是因为形如
log
∑
x
e
f
(
x
)
\log\sum\limits_x\mathrm{e}^{f(x)}
logx∑ef(x) 的式子在计算时,前面的对数-求和-指数部分可以进行优化,其速度相对更快。如果我们计算的是
f
(
x
)
=
log
N
(
x
∣
μ
,
Σ
)
f(\boldsymbol x)=\log\mathcal N(\boldsymbol x|\boldsymbol\mu,\boldsymbol\Sigma)
f(x)=logN(x∣μ,Σ),就可以将对数似然计算中的第二个求和转化为对数-求和-指数的形式。
# 计算多元高斯分布的概率密度的对数
def log_gaussian_prob(x, mu, sigma):
d = x.shape[-1]
det = np.linalg.det(sigma)
diff = x - mu
# 由于x可能包含多个样本
# x.T @ inv(sigma) @ x 的第二个乘法只需要保留前后样本一致的部分,
# 所以第二个乘法用点乘再求和代替
# 此外,由于数据存储维度的问题,这里的转置和上面公式中的转置相反
log_prob = -d / 2 * np.log(2 * np.pi) - 0.5 * np.log(det) - 0.5 * np.sum(diff @ np.linalg.inv(sigma) * diff, axis=-1)
return log_prob
接下来是EM算法的核心部分。为了使算法的调用和参数设置尽可能灵活,我们把EM算法封装在GMM类中。上文中只介绍了EM算法的迭代过程,但没有提及该如何初始化算法的各个参数。为了使算法从比较良好的初始状态出发,我们可以用k-means算法先对数据做聚类,得到每个点的聚类标签。如果将每个聚类看成一个高斯分布,那么这就相当于计算出了每个样本属于哪个分布,也就是隐变量 z z z。最后,再从 z z z统计计算出每个分布的均值和协方差即可完成初始化。
下面的代码中,我们分别实现随机初始化和k-means初始化两种方法。需要注意,协方差矩阵必须是半正定的,因此我们先在 [ − 1 , 1 ] [-1,1] [−1,1]范围内均匀采样矩阵的每个元素,再加上 d d d倍的单位矩阵 d I d d\boldsymbol I_d dId,从而保证矩阵的半正定性。
from sklearn.cluster import KMeans
from scipy.special import logsumexp
class GMM:
def __init__(self, n_components=2, eps=1e-4, max_iter=100, init='random'):
# n_components:GMM中高斯分布的数目
# eps:迭代精度,当对数似然的变化小于eps时迭代终止
# max_iter:最大迭代次数
# init:初始化方法,random或kmeans
self.k = n_components
self.eps = eps
self.max_iter = max_iter
self.init = init
self.phi = None # 隐变量的先验分布,即每个高斯分布的占比
self.means = None # 每个高斯分布的均值
self.covs = None # 每个高斯分布的协方差
def EM_fit(self, X):
# 用EM算法求解GMM的参数
# 参数初始化
if self.init == 'random':
self._random_init_params(X)
elif self.init == 'kmeans':
self._kmeans_init_params(X)
else:
raise NotImplementedError
ll = self._calc_log_likelihood(X) # 当前的对数似然
n, d = X.shape
# 开始迭代
qz = np.zeros((n, self.k)) # z的后验分布
for t in range(self.max_iter):
# E步骤,更新后验分布
for i in range(self.k):
# 计算样本属于第i类的概率
log_prob = log_gaussian_prob(X, self.means[i], self.covs[i])
qz[:, i] = self.phi[i] * np.exp(log_prob)
# 归一化
qz = qz / np.sum(qz, axis=1).reshape(-1, 1)
# M步骤,统计更新参数,最大化对数似然
self.phi = np.sum(qz, axis=0) / n # 更新隐变量分布
for i in range(self.k):
# 更新均值
self.means[i] = np.sum(qz[:, i, None] * X, axis=0) / n / self.phi[i]
# 更新协方差
diff = X - self.means[i]
self.covs[i] = (qz[:, i, None] * diff).T @ diff / (n - 1) / self.phi[i]
# 判断对数似然是否收敛
new_ll = self._calc_log_likelihood(X)
# assert new_ll >= ll, new_ll
if new_ll - ll <= self.eps:
break
ll = new_ll
def _calc_log_likelihood(self, X):
# 计算当前的对数似然
ll = 0
for i in range(self.k):
log_prob = log_gaussian_prob(X, self.means[i], self.covs[i])
# 用logsumexp简化计算
# 该函数底层对对数-求和-指数形式的运算做了优化
ll += logsumexp(log_prob + np.log(self.phi[i]))
return ll
def _random_init_params(self, X):
self.phi = np.random.uniform(0, 1, self.k) # 随机采样phi
self.phi /= np.sum(self.phi)
self.means = np.random.uniform(np.min(X), np.max(X), (self.k, X.shape[1])) # 随机采样均值
self.covs = np.random.uniform(-1, 1, (self.k, X.shape[1], X.shape[1])) # 随机采样协方差
self.covs += np.eye(X.shape[1]) * X.shape[1] # 加上维度倍的单位矩阵
def _kmeans_init_params(self, X):
# 用Kmeans算法初始化参数
# 简单起见,我们直接调用sklearn库中的Kmeans方法
kmeans = KMeans(n_clusters=self.k, init='random', n_init='auto', random_state=0).fit(X)
# 计算高斯分布占比
data_in_cls = np.bincount(kmeans.labels_, minlength=self.k)
self.phi = data_in_cls / len(X)
# 计算均值和协方差
self.means = np.zeros((self.k, X.shape[1]))
self.covs = np.zeros((self.k, X.shape[1], X.shape[1]))
for i in range(self.k):
# 取出属于第i类的样本
X_i = X[kmeans.labels_ == i]
self.means[i] = np.mean(X_i, axis=0)
diff = X_i - self.means[i]
self.covs[i] = diff.T @ diff / (len(X_i) - 1)
最后,我们设置好超参数,用GMM模型拟合正弦数据集,并绘图观察拟合效果。由于绘图过程要用到从协方差矩阵计算椭圆参数、用matplotlib中的工具绘制椭圆等方法,较为复杂,我们在这里直接给出绘制椭圆的函数和使用方法,不再具体讲解绘制过程。我们分别用2、3、5、10个高斯分布和两种初始化方法进行拟合,并把结果画在一起进行对比。
import matplotlib as mpl
def plot_elipses(gmm, ax):
# 绘制椭圆
# gmm:GMM模型
# ax:matplotlib的画布
covs = gmm.covs
for i in range(len(covs)):
# 计算椭圆参数
cov = covs[i][:2, :2]
v, w = np.linalg.eigh(cov)
u = w[0] / np.linalg.norm(w[0])
ang = np.arctan2(u[1], u[0])
ang = ang * 180 / np.pi
v = 2.0 * np.sqrt(2.0) * np.sqrt(v)
# 设置椭圆的绘制参数
# facecolor和edgecolor分别是填充颜色和边缘颜色
# 可以自由调整
elp = mpl.patches.Ellipse(gmm.means[i, :2], v[0], v[1], angle=180 + ang, facecolor='orange', edgecolor='none')
elp.set_clip_box(ax.bbox)
# 设置透明度
elp.set_alpha(0.5)
ax.add_artist(elp)
从结果图中可以看出,用k-means初始化参数可以让初始的聚类中心比较接近最优的高斯分布均值,而随机初始化的参数则很容易陷入局部的驻点。虽然EM算法理论上是收敛的,但是它并不保证收敛到最优解。并且,如果我们设置了对数似然的变化精度为算法的终止条件,那么算法同样可能在变化较为缓慢的驻点出停止,得到较差的解。因此,EM算法的参数初始化同样重要。除了k-means之外,我们还可以用随机性更小、效果更好的k-means++算法进行初始化。
小故事:
GMM通常用来拟合数据分布后,再生成相同分布的数据。像这样从数据中学习出分布、再从分布出发完成后续任务的模型称为生成模型(generative model)。与之相对,直接学习样本特征和样本标签直接关联的模型称为判别模型(discriminative model)。我们之前介绍的线性回归等有监督学习模型都属于判别模型。从概率分布的角度出发,假设训练样本为 { ( x 1 , y 1 ) , ⋯ , ( x n , y n ) } \{(\boldsymbol x_1,y_1),\cdots,(\boldsymbol x_n,y_n)\} {(x1,y1),⋯,(xn,yn)},判别模型会将 x i \boldsymbol x_i xi与 y i y_i yi关联起来,直接学习由样本 x \boldsymbol x x给出标签 y y y的条件概率分布 p ( y ∣ x ) p(y|\boldsymbol x) p(y∣x);而生成模型将所有样本关联起来,学习了联合分布 p ( x , y ) p(\boldsymbol x,y) p(x,y),然后由此构建对其中标签的条件概率分布 p ( y ∣ x ) p(y|\boldsymbol x) p(y∣x)。在无监督学习下,生成模型只需要学习 p ( x ) p(\boldsymbol x) p(x)即可。
现代深度学习中,生成模型同样有广泛的应用。2013年,迪德里克·金玛(Diederik Kingma)和 马克斯·韦林(Max Welling)提出了变分自编码器;2014年,伊恩·古德费洛(Ian Goodfellow)提出了划时代的生成对抗网络。这两类模型衍生出了许多算法,让生成模型在深度学习时代保有了自己的一席之地。如今,最新的扩散模型在图像任务上取得了令人震惊的效果,并催生了足以以假乱真的人工智能绘画。用于文本任务的生成式预训练变换器可以生成高质量的自然语言,以它为基础的ChatGPT掀起了新一轮人工智能热潮。
三、一般情况下的EM算法
对于更一般的、样本分布不服从GMM的情况,我们同样可以模仿上面的步骤使用EM算法推进学习。设样本为
x
1
,
⋯
,
x
N
\boldsymbol x_1,\cdots,\boldsymbol x_N
x1,⋯,xN,隐变量为
z
z
z,样本服从参数为
θ
\theta
θ的某个分布
p
(
X
∣
θ
)
p(\boldsymbol X|\theta)
p(X∣θ),那么参数的对数似然为
l
(
θ
)
=
log
P
(
X
∣
θ
)
=
log
∏
i
=
1
N
P
(
x
i
∣
θ
)
=
∑
i
=
1
N
log
∑
z
i
P
(
x
i
,
z
i
∣
θ
)
\begin{aligned} l(\theta) &= \log P(\boldsymbol X|\theta)=\log\prod_{i=1}^NP(\boldsymbol x_i|\theta) \\ &= \sum_{i=1}^N\log\sum_{z_i}P(\boldsymbol x_i,z_i|\theta) \end{aligned}
l(θ)=logP(X∣θ)=logi=1∏NP(xi∣θ)=i=1∑Nlogzi∑P(xi,zi∣θ) 上式的第二个求和是对隐变量
z
i
z_i
zi的所有可能取值求和。如果隐变量连续,这里的求和应当改为积分。当每个样本的隐变量
z
z
z给定时,上式对
z
z
z的所有可能性求和就只剩下一项:
l
(
θ
)
=
∑
i
=
1
N
log
P
(
x
i
,
z
i
∣
θ
)
=
∑
i
=
1
N
log
P
(
x
i
∣
z
i
,
θ
)
l(\theta)=\sum_{i=1}^N\log P(\boldsymbol x_i,z_i|\theta)=\sum_{i=1}^N\log P(\boldsymbol x_i|z_i,\theta)
l(θ)=i=1∑NlogP(xi,zi∣θ)=i=1∑NlogP(xi∣zi,θ) 其中,
z
i
z_i
zi表示样本
x
i
\boldsymbol x_i
xi对应的隐变量的值。
然而到此为止,我们并没有论证为什么EM算法是合理的。为什么可以假设隐变量已知?这样的迭代方式为何能给出收敛的结果?为了探究这一问题,我们来从头考虑MLE的求解。我们不妨先对原本的
l
(
θ
)
l(\theta)
l(θ)进行放缩,尝试求出其下界。设对每个样本
x
i
\boldsymbol x_i
xi,隐变量
z
z
z的分布是
q
i
(
z
)
q_i(z)
qi(z),对任意
z
z
z,满足归一性
∑
z
q
i
(
z
)
=
1
\sum\limits_zq_i(z)=1
z∑qi(z)=1 和非负性
q
i
(
z
)
≥
0
q_i(z)\ge0
qi(z)≥0。这样对数似然可以写为
l
(
θ
)
=
∑
i
=
1
N
log
∑
z
i
P
(
x
i
,
z
i
∣
θ
)
=
∑
i
=
1
N
log
∑
z
i
q
i
(
z
i
)
P
(
x
i
,
z
i
∣
θ
)
q
i
(
z
i
)
\begin{aligned} l(\theta) &= \sum_{i=1}^N\log\sum_{z_i}P(\boldsymbol x_i,z_i|\theta) \\ &= \sum_{i=1}^N\log\sum_{z_i}q_i(z_i)\frac{P(\boldsymbol x_i,z_i|\theta)}{q_i(z_i)} \end{aligned}
l(θ)=i=1∑Nlogzi∑P(xi,zi∣θ)=i=1∑Nlogzi∑qi(zi)qi(zi)P(xi,zi∣θ)
为了进行放缩,我们介绍一个重要的常用不等式:延森不等式(Jensen’s inequality)。设函数 f ( x ) f(x) f(x)是凸函数,那么任取自变量 x 1 x_1 x1、 x 2 x_2 x2和 0 < α < 1 0<\alpha<1 0<α<1,都有 f ( α x 1 + ( 1 − α ) x 2 ) ≤ α f ( x 1 ) + ( 1 − α ) f ( x 2 ) f(\alpha x_1+(1-\alpha)x_2)\le\alpha f(x_1)+(1-\alpha)f(x_2) f(αx1+(1−α)x2)≤αf(x1)+(1−α)f(x2)。反之,如果函数 f ( x ) f(x) f(x)是凹函数,那么任取自变量 x 1 x_1 x1、 x 2 x_2 x2和 0 < α < 1 0<\alpha<1 0<α<1,都有 f ( α x 1 + ( 1 − α ) x 2 ) ≥ α f ( x 1 ) + ( 1 − α ) f ( x 2 ) f(\alpha x_1+(1-\alpha)x_2)\ge\alpha f(x_1)+(1-\alpha)f(x_2) f(αx1+(1−α)x2)≥αf(x1)+(1−α)f(x2)。如果 f ( x ) f(x) f(x)是严格凸或凹函数,那么上式的不等号在 x 1 ≠ x 2 x_1\ne x_2 x1=x2 时严格成立,当且仅当 x 1 = x 2 x_1=x_2 x1=x2 时,等号成立。
图3以 log x \log x logx的图像为例展示了延森不等式的含义。从图中可以看出,如果 f ( x ) f(x) f(x)是凹函数,那么在图像上任意取两点连线,必定在函数曲线的下方。因此,自变量的组合 x ′ = α x 1 + ( 1 − α ) x 2 x'=\alpha x_1+(1-\alpha)x_2 x′=αx1+(1−α)x2 所对应的函数值 f ( x ′ ) f(x') f(x′)要高于函数值的组合 α f ( x 1 ) + ( 1 − α ) f ( x 2 ) \alpha f(x_1)+(1-\alpha)f(x_2) αf(x1)+(1−α)f(x2)。
延森不等式还可以推广到多个点的情况。设 f ( x ) f(x) f(x)是凹函数,任取 x 1 , ⋯ , x n x_1,\cdots,x_n x1,⋯,xn及其组合系数 0 < α 1 , ⋯ , α n < 1 0<\alpha_1,\cdots,\alpha_n<1 0<α1,⋯,αn<1,且组合系数满足 ∑ i = 1 n α i = 1 \sum\limits_{i=1}^n\alpha_i=1 i=1∑nαi=1,那么 f ( α 1 x 1 + ⋯ + α n x n ) ≥ α 1 f ( x 1 ) + ⋯ + α n f ( x n ) f(\alpha_1x_1+\cdots+\alpha_nx_n)\ge\alpha_1f(x_1)+\cdots+\alpha_nf(x_n) f(α1x1+⋯+αnxn)≥α1f(x1)+⋯+αnf(xn)
注意到在上面对数似然的表达式中, log x \log x logx是凹函数,内部求和的系数 q i ( z i ) q_i(z_i) qi(zi)之和为1,于是由延森不等式可得 l ( θ ) = ∑ i = 1 N log ∑ z i q i ( z i ) P ( x i , z i ∣ θ ) q i ( z i ) ≥ ∑ i = 1 N ∑ z i q i ( z i ) log P ( x i , z i ∣ θ ) q i ( z i ) l(\theta)=\sum_{i=1}^N\log\sum_{z_i}q_i(z_i)\frac{P(\boldsymbol x_i,z_i|\theta)}{q_i(z_i)}\ge\sum_{i=1}^N\sum_{z_i}q_i(z_i)\log\frac{P(\boldsymbol x_i,z_i|\theta)}{q_i(z_i)} l(θ)=i=1∑Nlogzi∑qi(zi)qi(zi)P(xi,zi∣θ)≥i=1∑Nzi∑qi(zi)logqi(zi)P(xi,zi∣θ)
上式给出了对数似然的下界。虽然最大化 l ( θ ) l(\theta) l(θ)较为困难,但是如果我们能提升其下界,就能为 l ( θ ) l(\theta) l(θ)的值提供最低保证。如果下界不断提升,那么最后的 l ( θ ) l(\theta) l(θ)就很可能接近其真正的最大值。因此,我们需要设法选取合适的 q i ( z ) q_i(z) qi(z),使其下界尽可能大。从延森不等式的形式中容易看出,如果 x 1 = x 2 = ⋯ = x n x_1=x_2=\cdots=x_n x1=x2=⋯=xn,不等式显然可以取到等号。而在下界的表达式中, P ( x i , z i ∣ θ ) q i ( z i ) \begin{aligned}\frac{P(\boldsymbol x_i,z_i|\theta)}{q_i(z_i)}\end{aligned} qi(zi)P(xi,zi∣θ)相当于自变量,为了使等号成立,我们令 q i ( z i ) = 1 C P ( x i , z i ∣ θ ) q_i(z_i)=\frac{1}{C}P(\boldsymbol x_i,z_i|\theta) qi(zi)=C1P(xi,zi∣θ) 其中, C C C是常数。这样,所有的“自变量”都等于 C C C,不等式等号成立。而常数 C C C可以由归一化条件 ∑ z q i ( z ) = 1 \sum\limits_zq_i(z)=1 z∑qi(z)=1 得到。所以, q i ( z i ) q_i(z_i) qi(zi)的表达式为 q i ( z i ) = P ( x i , z i ∣ θ ) ∑ z P ( x i , z ∣ θ ) = P ( x i , z i ∣ θ ) P ( x i ∣ θ ) = P ( x i ∣ θ ) P ( z i ∣ x i , θ ) P ( x i ∣ θ ) = P ( z i ∣ x i , θ ) q_i(z_i)=\frac{P(\boldsymbol x_i,z_i|\theta)}{\sum\limits_zP(\boldsymbol x_i,z|\theta)}=\frac{P(\boldsymbol x_i,z_i|\theta)}{P(\boldsymbol x_i|\theta)}=\frac{P(\boldsymbol x_i|\theta)P(z_i|\boldsymbol x_i,\theta)}{P(\boldsymbol x_i|\theta)}=P(z_i|\boldsymbol x_i,\theta) qi(zi)=z∑P(xi,z∣θ)P(xi,zi∣θ)=P(xi∣θ)P(xi,zi∣θ)=P(xi∣θ)P(xi∣θ)P(zi∣xi,θ)=P(zi∣xi,θ) 这恰好是隐变量 z z z的后验分布。这也就解释了为什么EM算法的E步骤要计算 z z z的后验分布,再用后验分布得出的 z z z来优化 l ( θ ) l(\theta) l(θ)。本质上,E步骤通过计算后验得出了 l ( θ ) l(\theta) l(θ)的一个最好的下界,M步骤通过调整参数 θ \theta θ来优化这一下界。而当M步一旦调整了参数 θ \theta θ,那么当前的下界 ∑ i = 1 N ∑ z i q i ( z i ) log P ( x i , z i ∣ θ ) q i ( z i ) \begin{aligned}\sum_{i=1}^N\sum_{z_i}q_i(z_i)\log\frac{P(\boldsymbol x_i,z_i|\theta)}{q_i(z_i)}\end{aligned} i=1∑Nzi∑qi(zi)logqi(zi)P(xi,zi∣θ) 就不再贴合而是严格小于 l ( θ ) l(\theta) l(θ),则又需要再次做E步骤,计算 z z z的后验,如此往复。那么这样的迭代是否保证能收敛呢?答案是肯定的,我们在下一节具体讨论EM算法的收敛性。
四、EM算法的收敛性
上一节中,我们通过放缩解释了EM算法的含义以及合理性,本节来继续证明算法的收敛性。由于我们最终要求解的是参数 θ \theta θ,记迭代第 t t t步的M步骤优化前参数为 θ ( t ) \theta(t) θ(t),那么我们需要证明优化后的参数 θ ( t + 1 ) \theta^{(t+1)} θ(t+1)会使对数似然函数增大,即 l ( θ ( t ) ) ≤ l ( θ ( t + 1 ) ) l(\theta^{(t)})\le l(\theta^{(t+1)}) l(θ(t))≤l(θ(t+1))。由于对数似然函数是一些不超过1的概率相乘再取对数,其上界为0,因此证明其单调递增就可以保证其收敛。同时,记第 t t t步隐变量 z z z的分布为 q i ( t ) ( z i ) = P ( z i ∣ x i , θ ( t ) ) q_i^{(t)}(z_i)=P(z_i|\boldsymbol x_i,\theta^{(t)}) qi(t)(zi)=P(zi∣xi,θ(t)),上面已经证明过,这一选择可以使延森不等式取到等号。
证明的关键在于,
q
i
(
t
)
(
z
i
)
q_i^{(t)}(z_i)
qi(t)(zi)并不是参数
θ
(
t
+
1
)
\theta^{(t+1)}
θ(t+1)对应的最优选择,从而
l
(
θ
(
t
+
1
)
)
=
∑
i
=
1
N
log
∑
z
i
q
i
(
t
)
(
z
i
)
P
(
x
i
,
z
i
∣
θ
(
t
+
1
)
)
q
i
(
t
)
(
z
i
)
≥
∑
i
=
1
N
∑
z
i
q
i
(
t
)
(
z
i
)
log
P
(
x
i
,
z
i
∣
θ
(
t
+
1
)
)
q
i
(
t
)
(
z
i
)
≥
∑
i
=
1
N
∑
z
i
q
i
(
t
)
(
z
i
)
log
P
(
x
i
,
z
i
∣
θ
(
t
)
)
q
i
(
t
)
(
z
i
)
=
l
(
θ
(
t
)
)
\begin{aligned} l\left(\theta^{(t+1)}\right) &= \sum_{i=1}^N\log\sum_{z_i}q_i^{(t)}(z_i)\frac{P(\boldsymbol x_i,z_i|\theta^{(t+1)})}{q_i^{(t)}(z_i)} \\ &\ge \sum_{i=1}^N\sum_{z_i}q_i^{(t)}(z_i)\log\frac{P(\boldsymbol x_i,z_i|\theta^{(t+1)})}{q_i^{(t)}(z_i)} \\ &\ge \sum_{i=1}^N\sum_{z_i}q_i^{(t)}(z_i)\log\frac{P(\boldsymbol x_i,z_i|\theta^{(t)})}{q_i^{(t)}(z_i)} \\ &= l\left(\theta^{(t)}\right) \end{aligned}
l(θ(t+1))=i=1∑Nlogzi∑qi(t)(zi)qi(t)(zi)P(xi,zi∣θ(t+1))≥i=1∑Nzi∑qi(t)(zi)logqi(t)(zi)P(xi,zi∣θ(t+1))≥i=1∑Nzi∑qi(t)(zi)logqi(t)(zi)P(xi,zi∣θ(t))=l(θ(t)) 上式的第一个不等号是延森不等式,且在参数为
θ
(
t
+
1
)
\theta^{(t+1)}
θ(t+1)时
q
i
(
t
)
(
z
i
)
q_i^{(t)}(z_i)
qi(t)(zi)不一定能使等号成立。第二个不等号是由于M步骤对参数进行了优化,得到的
θ
(
t
+
1
)
\theta^{(t+1)}
θ(t+1)对应的值一定不小于
θ
(
t
)
\theta^{(t)}
θ(t)对应的值。最后一个等号是由于
q
i
(
t
)
(
z
i
)
q_i^{(t)}(z_i)
qi(t)(zi)可以使参数为
θ
(
t
)
\theta^{(t)}
θ(t)的延森不等式取到等号。于是,数列
l
(
θ
(
1
)
)
,
l
(
θ
(
2
)
)
,
⋯
,
l
(
θ
(
t
)
)
,
l
(
θ
(
t
+
1
)
)
,
⋯
l(\theta^{(1)}),l(\theta^{(2)}),\cdots,l(\theta^{(t)}),l(\theta^{(t+1)}),\cdots
l(θ(1)),l(θ(2)),⋯,l(θ(t)),l(θ(t+1)),⋯ 是单调递增的,并且是有上界的(元素都为非正数),根据单调收敛原理,该数列一定收敛。这样,我们就证明了EM算法的迭代过程必定是收敛的。
如果记 J ( θ , q ) = ∑ i = 1 N ∑ z i q i ( z i ) log P ( x i , z i ∣ θ ) q i ( z i ) J(\theta,q)=\sum_{i=1}^N\sum_{z_i}q_i(z_i)\log\frac{P(\boldsymbol x_i,z_i|\theta)}{q_i(z_i)} J(θ,q)=i=1∑Nzi∑qi(zi)logqi(zi)P(xi,zi∣θ) 那么,EM算法的E步骤就可以看作固定 θ \theta θ、优化 q q q,而M步骤可以看作固定 q q q、优化 θ \theta θ。这样交替优化的方式又称作坐标上升(coordinate ascent)。在支持向量机一文中,我们求解用到的SMO算法其实就是一种特殊的坐标上升算法。当然,坐标上升法并非对所有二元函数都适用。简单来说,如果目标函数是凹且光滑的,那么坐标上升法就能收敛到全局最大值。对于更复杂的情况和收敛性讨论,感兴趣的话可以自行查阅相关数学资料。
附:以上文中的数据集及相关资源下载地址:
链接:https://pan.quark.cn/s/c8dac204cab4
提取码:sviY
更多推荐
所有评论(0)