原文地址:http://blog.csdn.net/hjimce/article/details/45244603
高斯混合算法是EM算法的一个典型的应用,EM算法的推导过程这里不打算详解,直接讲GMM算法的实现。之前做图像分割grab cut 算法的时候,只知道把opencv中的高斯混合模型代码复制下来,然后封装成类使用,学的比较浅。结果没过几天发现高斯混合算法又忘了差不多了,于是用matlab去亲自写过一遍,终于发现了高斯混合模型的奥义。我的理解是高斯混合模型其实是进化版的k均值算法,因此学习高斯混合模型,最好还是把k均值算法写过一遍。高斯混合与k均值的本质区别在于权值问题,k均值采用的是均匀权值,而高斯混合的权值需要根据高斯模型的概率进行确定。
开始学习高斯混合模型,需要先简单复习一下单高斯模型的参数估计方法,描述一个高斯模型其实就是要计算它的均值、协方差矩阵(一维空间为方差,二维以上称之为协方差矩阵):
假设有数据集X={x1,x2,x3……,xn},那么用这些数据来估计单高斯模型参数的计算公式为:
、
。
开始写代码前,先用matlab生成数据集,然后在进行聚类。利用matlab的生成高斯模型数据集X:
mu = [2 3];
SIGMA = [1 0; 0 2];
r1 = mvnrnd(mu,SIGMA,1000);
plot(r1(:,1),r1(:,2),'r+');
然后利用上面的估计方法计算均值,和协方差是否满足均值为[2 3],协方差为[1 0; 0 2];测试代码如下,r2、covmat即为计算结果:
[m n]=size(r1);
center=sum(r1)./m;
r2(:,1)=r1(:,1)-center(1);
r2(:,2)=r1(:,2)-center(2);
covmat=1/m*r2'*r2;
先把单高斯模型的函数写好,因为高斯混合模型是它的进化版,计算高斯混合模型过程中需要调用单高斯模型参数估计,写好代码后面才不会乱掉。开始高斯混合建模之前,我先用matlab生成一个测试数据集data,如下图,然后再进行算法测试。
生成数据集代码如下:
%生成测试数据
mu = [2 3];%测试数据1
SIGMA = [1 0; 0 2];
r1 = mvnrnd(mu,SIGMA,100);
plot(r1(:,1),r1(:,2),'.');
hold on;
mu = [10 10];%测试数据2
SIGMA = [ 1 0; 0 2];
r2 = mvnrnd(mu,SIGMA,100);
plot(r2(:,1),r2(:,2),'.');
mu = [5 8];%测试数据3
SIGMA = [ 1 0; 0 2];
r3= mvnrnd(mu,SIGMA,100);
plot(r3(:,1),r3(:,2),'.');
data=[r1;r2;r3];
![](https://i-blog.csdnimg.cn/blog_migrate/6183ff282e2a75336053250d7fcc7e38.png)
数据生成完毕,接着我们正式开始高斯混合算法解析,先看一下高斯混合模型的建模求参步骤:
高斯混合模型的求解,说得简单一点就是要求解高斯模型中的均值与协方差,现在我们要把上述的数据分成3类,那么我们就是要求解3个均值及其对应的3个协方差矩阵。先讲一下总体步骤,高斯混合模型包含3个步骤:
a. 初始化各个高斯模型的参数,及每个高斯模型的权重;
b. 根据各个高斯模型的参数及其权重,计算每个点属于各个高斯模型的权重,计算公式为:
其中:
Wj是每个高斯模型在这个模型所占用得权重。这个公式说的简单一点就是每个高斯模型的权重与其概率的乘积,这样计算出来就相当于每个高斯模型在每个数据点中的所占用的比例。
c. 更新各个高斯模型的均值与方差,计算公式如下:
d. 更新各个高斯模型的总权重,计算公式如下:
其实第c、d两个步骤,无所谓顺序,你完全可以总权重更新放在各个模型参数更新之前。迭代过程就是b、c、d三个步骤进行更新就可以了。OK,接着结合上面的公式写一写代码。
(1) 初始化高斯模型参数
这一步初始化,在实际应用中一般是先通过k均值算法进行初始聚类,然后根据聚类结果进行计算初始化参数。不过这里我为了测试,我们选择随机初始化,这样才能看出GMM算法到底能不能实现聚类。
我这里各个高斯模型初始均值(中心)的初始化方法选择跟k均值的初始化方法一样,也就是随机选择k个点位置作为k个高斯模型的初始均值。然后协方差矩阵的初始化,我选择单位矩阵,具体代码如下:
[m n]=size(data);
kn=3;
countflag=zeros(1,kn);
tdata=cell(1,kn);%建立3个空矩阵
mu=cell(1,kn);%建立3个空矩阵
sigma=cell(1,kn);%建立3个空矩阵
%方案2 随机初始化参数
for i=1:kn
mu{1,i}=data(i*10,:);
sigma{1,i}=eye(2,2);
weightp(i)=1/kn;
end
(2) 计算各个模型在各个点的权重值
这一步是计算每个数据点属于各个高斯混合的概率,说白了就是计算权值:
pro_ij=zeros(m,kn);%存储每个点属于每个类的概率
for i=1:m
sumpk=0;
for j=1:kn
pk(j)=weightp(j)*GSMPro(mu{1,j},sigma{1,j},data(i,:));
sumpk=sumpk+pk(j);
end
for j=1:kn
pro_ij(i,j)=pk(j)/sumpk;
end
end
(3) 步骤c 更新参数:
for j=1:kn
[mu{1,j},sigma{1,j}]=WeightGSM(data,pro_ij(:,j));
end
(4)步骤d 更新各个模型的总权重:
for j=1:kn
weightp(j)=sum(pro_ij(:,j))/m;
end
然后把步骤2、3、4的代码放在循环语句中进行迭代就ok了。最后贴一下整份代码:
1、脚本文件:
close all;
clear;
clc;
%生成测试数据
mu = [2 3];%测试数据1
SIGMA = [1 0; 0 2];
r1 = mvnrnd(mu,SIGMA,100);
plot(r1(:,1),r1(:,2),'.');
hold on;
mu = [10 10];%测试数据2
SIGMA = [ 1 0; 0 2];
r2 = mvnrnd(mu,SIGMA,100);
plot(r2(:,1),r2(:,2),'.');
mu = [5 8];%测试数据3
SIGMA = [ 1 0; 0 2];
r3= mvnrnd(mu,SIGMA,100);
plot(r3(:,1),r3(:,2),'.');
data=[r1;r2;r3];
[m n]=size(data);
kn=3;
countflag=zeros(1,kn);
tdata=cell(1,kn);%建立10个空矩阵
mu=cell(1,kn);%建立10个空矩阵
sigma=cell(1,kn);%建立10个空矩阵
% 方案1 初始化采用kmeans,做参数的初步估计
% Idx=kmeans(data,kn);
% figure(2);%绘制初始化结果
% hold on;
% for i=1:m
% if Idx(i)==1
% plot(data(i,1),data(i,2),'.y');
% elseif Idx(i)==2
% plot(data(i,1),data(i,2),'.b');
% end
% end
% for i=1:m
% tdata{1,Idx(i)}=[tdata{1,Idx(i)};data(i,:)];
% end
% for i=1:kn
% [mu{1,i},sigma{1,i}]=GSMData(tdata{1,i});
% end
% for i=1:kn
% [trow,tcol]=size(tdata{1,i});
% weightp(i)=trow/m;
% end
%方案2 随机初始化
for i=1:kn
mu{1,i}=data(i*10,:);
sigma{1,i}=eye(2,2);
weightp(i)=1/kn;
end
it=1;
while it<1000
%E步 计算每个点处于每个类的概率
pro_ij=zeros(m,kn);%存储每个点属于每个类的概率
for i=1:m
sumpk=0;
for j=1:kn
pk(j)=weightp(j)*GSMPro(mu{1,j},sigma{1,j},data(i,:));
sumpk=sumpk+pk(j);
end
for j=1:kn
pro_ij(i,j)=pk(j)/sumpk;
end
end
%M步
for j=1:kn
[mu{1,j},sigma{1,j}]=WeightGSM(data,pro_ij(:,j));
end
%更新权值
for j=1:kn
weightp(j)=sum(pro_ij(:,j))/m;
end
sumw=sum(weightp);
it=it+1;
end
for i=1:m
[value index]=max(pro_ij(i,:));
Idx(i)=index;
end
figure(2);
hold on;
for i=1:m
if Idx(i)==1
plot(data(i,1),data(i,2),'.y');
elseif Idx(i)==2
plot(data(i,1),data(i,2),'.b');
elseif Idx(i)==3
plot(data(i,1),data(i,2),'.r');
end
end
% figure(3);
% %px=gmmstd(data,3);
% for i=1:m
% [value index]=max(px(i,:));
% Idx(i)=index;
% end
% hold on;
% for i=1:m
% if Idx(i)==1
% plot(data(i,1),data(i,2),'.y');
% elseif Idx(i)==2
% plot(data(i,1),data(i,2),'.b');
% elseif Idx(i)==3
% plot(data(i,1),data(i,2),'.r');
% end
% end
%单高斯模型参数估计
% [m n]=size(r1);
% center=sum(r1)./m;
% r2(:,1)=r1(:,1)-center(1);
% r2(:,2)=r1(:,2)-center(2);
% covmat=1/m*r2'*r2;
2、相关函数
function [ mu ,sigma ] = WeightGSM(data,weight)
%计算加权均值
[m n]=size(data);
sumweight=sum(weight);
weightdata=[];
for i=1:m
weightdata(i,:)=weight(i)*data(i,:);
end
center=sum(weightdata)/sumweight;
%计算加权协方差
for i=1:n
r2(:,i)=data(:,i)-center(i);
end
for i=1:m
r1(i,:)=weight(i)*r2(i,:);
end
sigma=1/sumweight*r1'*r2;
mu=center;
end
function [pro] = GSMPro(mu ,sigma,x)
pro=exp(-0.5*(x-mu)*inv(sigma)*(x-mu)');
pro=1/sqrt(2*pi*det(sigma))*pro;
end
看以下最后的测试结果: