高斯混合模型(GMM)的EM算法实现

2024-09-05 10:38

本文主要是介绍高斯混合模型(GMM)的EM算法实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在 聚类算法K-Means, K-Medoids, GMM, Spectral clustering,Ncut一文中我们给出了GMM算法的基本模型与似然函数,在EM算法原理中对EM算法的实现与收敛性证明进行了详细说明。本文主要针对如何用EM算法在混合高斯模型下进行聚类进行代码上的分析说明。

  1. GMM模型:
    每个 GMM 由 K 个 Gaussian 分布组成,每个 Gaussian 称为一个“Component”,这些 Component 线性加成在一起就组成了 GMM 的概率密度函数:

根据上面的式子,如果我们要从 GMM 的分布中随机地取一个点的话,实际上可以分为两步:首先随机地在这 K个Gaussian Component 之中选一个,每个 Component 被选中的概率实际上就是它的系数 pi(k) ,选中了 Component 之后,再单独地考虑从这个 Component 的分布中选取一个点就可以了──这里已经回到了普通的 Gaussian 分布,转化为了已知的问题。

那么如何用 GMM 来做 clustering 呢?其实很简单,现在我们有了数据,假定它们是由 GMM 生成出来的,那么我们只要根据数据推出 GMM 的概率分布来就可以了,然后 GMM 的 K 个 Component 实际上就对应了 K 个 cluster 了。根据数据来推算概率密度通常被称作 density estimation ,特别地,当我们在已知(或假定)了概率密度函数的形式,而要估计其中的参数的过程被称作“参数估计”。

  1. 参数与似然函数:

现在假设我们有 N 个数据点,并假设它们服从某个分布(记作 p(x) ),现在要确定里面的一些参数的值,例如,在 GMM 中,我们就需要确定 影响因子pi(k)、各类均值pMiu(k) 和 各类协方差pSigma(k) 这些参数。 我们的想法是,找到这样一组参数,它所确定的概率分布生成这些给定的数据点的概率最大,而这个概率实际上就等于 ,我们把这个乘积称作似然函数 (Likelihood Function)。通常单个点的概率都很小,许多很小的数字相乘起来在计算机里很容易造成浮点数下溢,因此我们通常会对其取对数,把乘积变成加和 \sum_{i=1}^N \log p(x_i),得到 log-likelihood function 。接下来我们只要将这个函数最大化(通常的做法是求导并令导数等于零,然后解方程),亦即找到这样一组参数值,它让似然函数取得最大值,我们就认为这是最合适的参数,这样就完成了参数估计的过程。

下面让我们来看一看 GMM 的 log-likelihood function :

由于在对数函数里面又有加和,我们没法直接用求导解方程的办法直接求得最大值。为了解决这个问题,我们采取之前从 GMM 中随机选点的办法:分成两步,实际上也就类似于K-means 的两步。

  1. 算法流程:

  2. 估计数据由每个 Component 生成的概率(并不是每个 Component 被选中的概率):对于每个数据 x_i 来说,它由第 k 个 Component 生成的概率为

其中N(xi | μk,Σk)就是后验概率。

  1. 通过极大似然估计可以通过求到令参数=0得到参数pMiu,pSigma的值。具体请见这篇文章第三部分。

其中 N_k = \sum_{i=1}^N \gamma(i, k) ,并且 \pi_k 也顺理成章地可以估计为 N_k/N 。

  1. 重复迭代前面两步,直到似然函数的值收敛为止。

  2. matlab实现GMM聚类代码与解释:

说明:fea为训练样本数据,gnd为样本标号。算法中的思想和上面写的一模一样,在最后的判断accuracy方面,由于聚类和分类不同,只是得到一些 cluster ,而并不知道这些 cluster 应该被打上什么标签,或者说。由于我们的目的是衡量聚类算法的 performance ,因此直接假定这一步能实现最优的对应关系,将每个 cluster 对应到一类上去。一种办法是枚举所有可能的情况并选出最优解,另外,对于这样的问题,我们还可以用 Hungarian algorithm 来求解。具体的Hungarian代码我放在了资源里,调用方法已经写在下面函数中了。

注意:资源里我放的是Kmeans的代码,大家下载的时候只要用bestMap.m等几个文件就好~

  1. gmm.m,最核心的函数,进行模型与参数确定。
    [cpp] view plaincopy
    function varargout = gmm(X, K_or_centroids)
    % ============================================================
    % Expectation-Maximization iteration implementation of
    % Gaussian Mixture Model.
    %
    % PX = GMM(X, K_OR_CENTROIDS)
    % [PX MODEL] = GMM(X, K_OR_CENTROIDS)
    %
    % - X: N-by-D data matrix.
    % - K_OR_CENTROIDS: either K indicating the number of
    % components or a K-by-D matrix indicating the
    % choosing of the initial K centroids.
    %
    % - PX: N-by-K matrix indicating the probability of each
    % component generating each point.
    % - MODEL: a structure containing the parameters for a GMM:
    % MODEL.Miu: a K-by-D matrix.
    % MODEL.Sigma: a D-by-D-by-K matrix.
    % MODEL.Pi: a 1-by-K vector.
    % ============================================================
    % @SourceCode Author: Pluskid (http://blog.pluskid.org)
    % @Appended by : Sophia_qing (http://blog.csdn.net/abcjennifer)

%% Generate Initial Centroids
threshold = 1e-15;
[N, D] = size(X);

if isscalar(K_or_centroids) %if K_or_centroid is a 1*1 number  K = K_or_centroids;  Rn_index = randperm(N); %random index N samples  centroids = X(Rn_index(1:K), :); %generate K random centroid  
else % K_or_centroid is a initial K centroid  K = size(K_or_centroids, 1);   centroids = K_or_centroids;  
end  %% initial values  
[pMiu pPi pSigma] = init_params();  Lprev = -inf; %上一次聚类的误差  %% EM Algorithm  
while true  %% Estimation Step  Px = calc_prob();  % new value for pGamma(N*k), pGamma(i,k) = Xi由第k个Gaussian生成的概率  % 或者说xi中有pGamma(i,k)是由第k个Gaussian生成的  pGamma = Px .* repmat(pPi, N, 1); %分子 = pi(k) * N(xi | pMiu(k), pSigma(k))  pGamma = pGamma ./ repmat(sum(pGamma, 2), 1, K); %分母 = pi(j) * N(xi | pMiu(j), pSigma(j))对所有j求和  %% Maximization Step - through Maximize likelihood Estimation  Nk = sum(pGamma, 1); %Nk(1*k) = 第k个高斯生成每个样本的概率的和,所有Nk的总和为N。  % update pMiu  pMiu = diag(1./Nk) * pGamma' * X; %update pMiu through MLE(通过令导数 = 0得到)  pPi = Nk/N;  % update k个 pSigma  for kk = 1:K   Xshift = X-repmat(pMiu(kk, :), N, 1);  pSigma(:, :, kk) = (Xshift' * ...  (diag(pGamma(:, kk)) * Xshift)) / Nk(kk);  end  % check for convergence  L = sum(log(Px*pPi'));  if L-Lprev < threshold  break;  end  Lprev = L;  
end  if nargout == 1  varargout = {Px};  
else  model = [];  model.Miu = pMiu;  model.Sigma = pSigma;  model.Pi = pPi;  varargout = {Px, model};  
end  %% Function Definition  function [pMiu pPi pSigma] = init_params()  pMiu = centroids; %k*D, 即k类的中心点  pPi = zeros(1, K); %k类GMM所占权重(influence factor)  pSigma = zeros(D, D, K); %k类GMM的协方差矩阵,每个是D*D的  % 距离矩阵,计算N*K的矩阵(x-pMiu)^2 = x^2+pMiu^2-2*x*Miu  distmat = repmat(sum(X.*X, 2), 1, K) + ... %x^2, N*1的矩阵replicateK列  repmat(sum(pMiu.*pMiu, 2)', N, 1) - ...%pMiu^2,1*K的矩阵replicateN行  2*X*pMiu';  [~, labels] = min(distmat, [], 2);%Return the minimum from each row  for k=1:K  Xk = X(labels == k, :);  pPi(k) = size(Xk, 1)/N;  pSigma(:, :, k) = cov(Xk);  end  
end  function Px = calc_prob()   %Gaussian posterior probability   %N(x|pMiu,pSigma) = 1/((2pi)^(D/2))*(1/(abs(sigma))^0.5)*exp(-1/2*(x-pMiu)'pSigma^(-1)*(x-pMiu))  Px = zeros(N, K);  for k = 1:K  Xshift = X-repmat(pMiu(k, :), N, 1); %X-pMiu  inv_pSigma = inv(pSigma(:, :, k));  tmp = sum((Xshift*inv_pSigma) .* Xshift, 2);  coef = (2*pi)^(-D/2) * sqrt(det(inv_pSigma));  Px(:, k) = coef * exp(-0.5*tmp);  end  
end  

end

  1. gmm_accuracy.m调用gmm.m,计算准确率:
    [cpp] view plaincopy
    function [ Accuracy ] = gmm_accuracy( Data_fea, gnd_label, K )
    %Calculate the accuracy Clustered by GMM model

px = gmm(Data_fea,K);
[~, cls_ind] = max(px,[],1); %cls_ind = cluster label
Accuracy = cal_accuracy(cls_ind, gnd_label);

function [acc] = cal_accuracy(gnd,estimate_label)  res = bestMap(gnd,estimate_label);  acc = length(find(gnd == res))/length(gnd);  
end  

end

  1. 主函数调用
    gmm_acc = gmm_accuracy(fea,gnd,N_classes);

写了本文进行总结后自己很受益,也希望大家可以好好YM下上面pluskid的gmm.m,不光是算法,其中的矩阵处理代码也写的很简洁,很值得学习。
另外看了两份东西非常受益,一个是pluskid大牛的《漫谈 Clustering (3): Gaussian Mixture Model》,一个是JerryLead的EM算法详解,大家有兴趣也可以看一下,写的很好。

转自http://blog.csdn.net/abcjennifer/article/details/8198352

这篇关于高斯混合模型(GMM)的EM算法实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138725

相关文章

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很