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 ,特別地,當我們在已知(或假定)了概率密度函式的形式,而要估計其中的引數的過程被稱作“引數估計”。
2. 引數與似然函式:
現在假設我們有 N 個數據點,並假設它們服從某個分佈(記作 p(x) ),現在要確定裡面的一些引數的值,例如,在 GMM 中,我們就需要確定 影響因子pi(k)、各類均值pMiu(k) 和 各類協方差pSigma(k) 這些引數。 我們的想法是,找到這樣一組引數,它所確定的概率分佈生成這些給定的資料點的概率最大,而這個概率實際上就等於
下面讓我們來看一看 GMM 的 log-likelihood function :
由於在對數函式裡面又有加和,我們沒法直接用求導解方程的辦法直接求得最大值。為了解決這個問題,我們採取之前從 GMM 中隨機選點的辦法:分成兩步,實際上也就類似於
3. 演算法流程:
1. 估計資料由每個 Component 生成的概率(並不是每個 Component 被選中的概率):對於每個資料 來說,它由第 個 Component 生成的概率為
其中N(xi | μk,Σk)就是後驗概率。
2. 通過極大似然估計可以通過求到令引數=0得到引數pMiu,pSigma的值。具體請見這篇文章第三部分。
其中 ,並且 也順理成章地可以估計為 。
3. 重複迭代前面兩步,直到似然函式的值收斂為止。
4. matlab實現GMM聚類程式碼與解釋:
說明:fea為訓練樣本資料,gnd為樣本標號。演算法中的思想和上面寫的一模一樣,在最後的判斷accuracy方面,由於聚類和分類不同,只是得到一些 cluster ,而並不知道這些 cluster 應該被打上什麼標籤,或者說。由於我們的目的是衡量聚類演算法的 performance ,因此直接假定這一步能實現最優的對應關係,將每個 cluster 對應到一類上去。一種辦法是列舉所有可能的情況並選出最優解,另外,對於這樣的問題,我們還可以用 Hungarian algorithm 來求解。具體的Hungarian程式碼我放在了資源裡,呼叫方法已經寫在下面函式中了。
注意:資源裡我放的是Kmeans的程式碼,大家下載的時候只要用bestMap.m等幾個檔案就好~
1. gmm.m,最核心的函式,進行模型與引數確定。
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 endend
2. gmm_accuracy.m呼叫gmm.m,計算準確率:
function [ Accuracy ] = gmm_accuracy( Data_fea, gnd_label, K )%Calculate the accuracy Clustered by GMM modelpx = 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); endend
3. 主函式呼叫
gmm_acc = gmm_accuracy(fea,gnd,N_classes);
寫了本文進行總結後自己很受益,也希望大家可以好好YM下上面pluskid的gmm.m,不光是演算法,其中的矩陣處理程式碼也寫的很簡潔,很值得學習。
關於Machine Learning更多的學習資料與相關討論將繼續更新,敬請關注本部落格和新浪微博Sophia_qing。