GMM的EM算法實現

 聚類算法K-Means, K-Medoids, GMM, Spectral clustering,Ncut一文中我們給出了GMM算法的基本模型與似然函數,在EM算法原理中對EM算法的實現與收斂性證明進行了詳細說明。本文主要針對如何用EM算法在混合高斯模型下進行聚類進行代碼上的分析說明。

原文鏈接:

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

EM算法的鏈接:

http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006936.html

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 ,特別地,當我們在已知(或假定)了概率密度函數的形式,而要估計其中的參數的過程被稱作“參數估計”。


2. 參數與似然函數:

現在假設我們有 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 的兩步。



3. 算法流程:

1.  估計數據由每個 Component 生成的概率(並不是每個 Component 被選中的概率):對於每個數據 x_i 來說,它由第 k 個 Component 生成的概率爲


其中N(xi | μk,Σk)就是後驗概率


2. 通過極大似然估計可以通過求到令參數=0得到參數pMiu,pSigma的值。具體請見這篇文章第三部分。


其中 N_k = \sum_{i=1}^N \gamma(i, k) ,並且 \pi_k 也順理成章地可以估計爲 N_k/N 。


3. 重複迭代前面兩步,直到似然函數的值收斂爲止。



4. matlab實現GMM聚類代碼與解釋:


說明:fea爲訓練樣本數據,gnd爲樣本標號。算法中的思想和上面寫的一模一樣,在最後的判斷accuracy方面,由於聚類和分類不同,只是得到一些 cluster ,而並不知道這些 cluster 應該被打上什麼標籤,或者說。由於我們的目的是衡量聚類算法的 performance ,因此直接假定這一步能實現最優的對應關係,將每個 cluster 對應到一類上去。一種辦法是枚舉所有可能的情況並選出最優解,另外,對於這樣的問題,我們還可以用 Hungarian algorithm 來求解。具體的Hungarian代碼我放在了資源裏,調用方法已經寫在下面函數中了。


注意:資源裏我放的是Kmeans的代碼,大家下載的時候只要用bestMap.m等幾個文件就好~


1. gmm.m,最核心的函數,進行模型與參數確定。

[cpp] view plain copy
  1. function varargout = gmm(X, K_or_centroids)  
  2. % ============================================================  
  3. % Expectation-Maximization iteration implementation of  
  4. % Gaussian Mixture Model.  
  5. %  
  6. % PX = GMM(X, K_OR_CENTROIDS)  
  7. % [PX MODEL] = GMM(X, K_OR_CENTROIDS)  
  8. %  
  9. %  - X: N-by-D data matrix.  
  10. %  - K_OR_CENTROIDS: either K indicating the number of  
  11. %       components or a K-by-D matrix indicating the  
  12. %       choosing of the initial K centroids.  
  13. %  
  14. %  - PX: N-by-K matrix indicating the probability of each  
  15. %       component generating each point.  
  16. %  - MODEL: a structure containing the parameters for a GMM:  
  17. %       MODEL.Miu: a K-by-D matrix.  
  18. %       MODEL.Sigma: a D-by-D-by-K matrix.  
  19. %       MODEL.Pi: a 1-by-K vector.  
  20. % ============================================================  
  21. % @SourceCode Author: Pluskid (http://blog.pluskid.org)  
  22. % @Appended by : Sophia_qing (http://blog.csdn.net/abcjennifer)  
  23.       
  24.   
  25. %% Generate Initial Centroids  
  26.     threshold = 1e-15;  
  27.     [N, D] = size(X);  
  28.    
  29.     if isscalar(K_or_centroids) %if K_or_centroid is a 1*1 number  
  30.         K = K_or_centroids;  
  31.         Rn_index = randperm(N); %random index N samples  
  32.         centroids = X(Rn_index(1:K), :); %generate K random centroid  
  33.     else % K_or_centroid is a initial K centroid  
  34.         K = size(K_or_centroids, 1);   
  35.         centroids = K_or_centroids;  
  36.     end  
  37.    
  38.     %% initial values  
  39.     [pMiu pPi pSigma] = init_params();  
  40.    
  41.     Lprev = -inf; %上一次聚類的誤差  
  42.       
  43.     %% EM Algorithm  
  44.     while true  
  45.         %% Estimation Step  
  46.         Px = calc_prob();  
  47.    
  48.         % new value for pGamma(N*k), pGamma(i,k) = Xi由第k個Gaussian生成的概率  
  49.         % 或者說xi中有pGamma(i,k)是由第k個Gaussian生成的  
  50.         pGamma = Px .* repmat(pPi, N, 1); %分子 = pi(k) * N(xi | pMiu(k), pSigma(k))  
  51.         pGamma = pGamma ./ repmat(sum(pGamma, 2), 1, K); %分母 = pi(j) * N(xi | pMiu(j), pSigma(j))對所有j求和  
  52.    
  53.         %% Maximization Step - through Maximize likelihood Estimation  
  54.           
  55.         Nk = sum(pGamma, 1); %Nk(1*k) = 第k個高斯生成每個樣本的概率的和,所有Nk的總和爲N。  
  56.           
  57.         % update pMiu  
  58.         pMiu = diag(1./Nk) * pGamma' * X; %update pMiu through MLE(通過令導數 = 0得到)  
  59.         pPi = Nk/N;  
  60.           
  61.         % update k個 pSigma  
  62.         for kk = 1:K   
  63.             Xshift = X-repmat(pMiu(kk, :), N, 1);  
  64.             pSigma(:, :, kk) = (Xshift' * ...  
  65.                 (diag(pGamma(:, kk)) * Xshift)) / Nk(kk);  
  66.         end  
  67.    
  68.         % check for convergence  
  69.         L = sum(log(Px*pPi'));  
  70.         if L-Lprev < threshold  
  71.             break;  
  72.         end  
  73.         Lprev = L;  
  74.     end  
  75.    
  76.     if nargout == 1  
  77.         varargout = {Px};  
  78.     else  
  79.         model = [];  
  80.         model.Miu = pMiu;  
  81.         model.Sigma = pSigma;  
  82.         model.Pi = pPi;  
  83.         varargout = {Px, model};  
  84.     end  
  85.    
  86.     %% Function Definition  
  87.       
  88.     function [pMiu pPi pSigma] = init_params()  
  89.         pMiu = centroids; %k*D, 即k類的中心點  
  90.         pPi = zeros(1, K); %k類GMM所佔權重(influence factor)  
  91.         pSigma = zeros(D, D, K); %k類GMM的協方差矩陣,每個是D*D的  
  92.    
  93.         % 距離矩陣,計算N*K的矩陣(x-pMiu)^2 = x^2+pMiu^2-2*x*Miu  
  94.         distmat = repmat(sum(X.*X, 2), 1, K) + ... %x^2, N*1的矩陣replicateK列  
  95.             repmat(sum(pMiu.*pMiu, 2)', N, 1) - ...%pMiu^2,1*K的矩陣replicateN行  
  96.             2*X*pMiu';  
  97.         [~, labels] = min(distmat, [], 2);%Return the minimum from each row  
  98.    
  99.         for k=1:K  
  100.             Xk = X(labels == k, :);  
  101.             pPi(k) = size(Xk, 1)/N;  
  102.             pSigma(:, :, k) = cov(Xk);  
  103.         end  
  104.     end  
  105.    
  106.     function Px = calc_prob()   
  107.         %Gaussian posterior probability   
  108.         %N(x|pMiu,pSigma) = 1/((2pi)^(D/2))*(1/(abs(sigma))^0.5)*exp(-1/2*(x-pMiu)'pSigma^(-1)*(x-pMiu))  
  109.         Px = zeros(N, K);  
  110.         for k = 1:K  
  111.             Xshift = X-repmat(pMiu(k, :), N, 1); %X-pMiu  
  112.             inv_pSigma = inv(pSigma(:, :, k));  
  113.             tmp = sum((Xshift*inv_pSigma) .* Xshift, 2);  
  114.             coef = (2*pi)^(-D/2) * sqrt(det(inv_pSigma));  
  115.             Px(:, k) = coef * exp(-0.5*tmp);  
  116.         end  
  117.     end  
  118. end  


2. gmm_accuracy.m調用gmm.m,計算準確率:

[cpp] view plain copy
  1. function [ Accuracy ] = gmm_accuracy( Data_fea, gnd_label, K )  
  2. %Calculate the accuracy Clustered by GMM model  
  3.   
  4. px = gmm(Data_fea,K);  
  5. [~, cls_ind] = max(px,[],1); %cls_ind = cluster label   
  6. Accuracy = cal_accuracy(cls_ind, gnd_label);  
  7.   
  8.     function [acc] = cal_accuracy(gnd,estimate_label)  
  9.         res = bestMap(gnd,estimate_label);  
  10.         acc = length(find(gnd == res))/length(gnd);  
  11.     end  
  12.   
  13. end  


3. 主函數調用

gmm_acc = gmm_accuracy(fea,gnd,N_classes);








寫了本文進行總結後自己很受益,也希望大家可以好好YM下上面pluskid的gmm.m,不光是算法,其中的矩陣處理代碼也寫的很簡潔,很值得學習。

另外看了兩份東西非常受益,一個是pluskid大牛的漫談 Clustering (3): Gaussian Mixture Model》,一個是JerryLead的EM算法詳解,大家有興趣也可以看一下,寫的很好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章