【问题标题】:Implementation of EM algorithm for Gaussian Mixture Models高斯混合模型EM算法的实现
【发布时间】:2015-10-24 18:49:18
【问题描述】:

使用 EM 算法,我想在给定数据集上训练具有四个分量的高斯混合模型。该集合是三维的,包含 300 个样本。

问题是在大约 6 轮 EM 算法之后,协方差矩阵 sigma 根据 matlab 变得接近奇异(rank(sigma) = 2 而不是 3)。这反过来会导致不希望的结果,例如评估高斯分布gm(k,i) 的复数值。

此外,我使用高斯日志来解决下溢问题 - 请参阅 E-step。我不确定这是否正确,是否必须将责任 p(w_k | x^(i), theta) 的 exp 带到其他地方?

你能告诉我到目前为止我对 EM 算法的实现是否正确吗? 以及如何解释接近奇异协方差 sigma 的问题?

这是我对 EM 算法的实现:

首先我使用kmeans初始化组件的均值和协方差:

load('data1.mat');

X = Data'; % 300x3 data set
D = size(X,2); % dimension
N = size(X,1); % number of samples
K = 4; % number of Gaussian Mixture components

% Initialization
p = [0.2, 0.3, 0.2, 0.3]; % arbitrary pi
[idx,mu] = kmeans(X,K); % initial means of the components

% compute the covariance of the components
sigma = zeros(D,D,K);
for k = 1:K
    sigma(:,:,k) = cov(X(idx==k,:));
end

对于E-step,我使用以下公式来计算责任。

w_k 是 k 个高斯分量。

x^(i) 是单个数据点(样本)

theta代表高斯混合模型的参数:mu、Sigma、pi。

下面是对应的代码:

% variables for convergence 
converged = 0;
prevLoglikelihood = Inf;
prevMu = mu;
prevSigma = sigma;
prevPi = p;
round = 0;
while (converged ~= 1)
    round = round +1
    gm = zeros(K,N); % gaussian component in the nominator
    sumGM = zeros(N,1); % denominator of responsibilities
    % E-step:  Evaluate the responsibilities using the current parameters
    % compute the nominator and denominator of the responsibilities
    for k = 1:K
        for i = 1:N
             Xmu = X-mu;
             % I am using log to prevent underflow of the gaussian distribution (exp("small value"))
             logPdf = log(1/sqrt(det(sigma(:,:,k))*(2*pi)^D)) + (-0.5*Xmu*(sigma(:,:,k)\Xmu'));
             gm(k,i) = log(p(k)) * logPdf;
             sumGM(i) = sumGM(i) + gm(k,i);
         end
    end

    % calculate responsibilities
    res = zeros(K,N); % responsibilities
    Nk = zeros(4,1);
    for k = 1:K
        for i = 1:N
            % I tried to use the exp(gm(k,i)/sumGM(i)) to compute res but this leads to sum(pi) > 1.
            res(k,i) = gm(k,i)/sumGM(i);
        end
        Nk(k) = sum(res(k,:));
    end

Nk(k) 使用 M 步中给出的公式计算,并在 M 步中用于计算新概率 p(k)

M-step

    % M-step: Re-estimate the parameters using the current responsibilities
    for k = 1:K
        for i = 1:N
            mu(k,:) = mu(k,:) + res(k,i).*X(k,:);
            sigma(:,:,k) = sigma(:,:,k) + res(k,i).*(X(k,:)-mu(k,:))*(X(k,:)-mu(k,:))';
        end
        mu(k,:) = mu(k,:)./Nk(k);
        sigma(:,:,k) = sigma(:,:,k)./Nk(k);
        p(k) = Nk(k)/N;
    end

现在为了检查收敛性,使用以下公式计算对数似然:

    % Evaluate the log-likelihood and check for convergence of either 
    % the parameters or the log-likelihood. If not converged, go to E-step.
    loglikelihood = 0;
    for i = 1:N
        loglikelihood = loglikelihood + log(sum(gm(:,i)));
    end


    % Check for convergence of parameters
    errorLoglikelihood = abs(loglikelihood-prevLoglikelihood);
    if (errorLoglikelihood <= eps)
        converged = 1; 
    end

    errorMu = abs(mu(:)-prevMu(:));
    errorSigma = abs(sigma(:)-prevSigma(:));
    errorPi = abs(p(:)-prevPi(:));

    if (all(errorMu <= eps) && all(errorSigma <= eps) && all(errorPi <= eps))
        converged = 1;
    end

    prevLoglikelihood = loglikelihood;
    prevMu = mu;
    prevSigma = sigma;
    prevPi = p;

end % while 

我的高斯混合模型 EM 算法的 Matlab 实现有问题吗?


以前的麻烦:

问题是我无法使用对数似然检查收敛,因为它是-Inf。这是在评估责任公式中的高斯时四舍五入的零值导致的(参见 E-step)。

你能告诉我到目前为止我对 EM 算法的实现是否正确吗? 以及如何解决四舍五入的零值问题?

这是我对 EM 算法的实现:

首先我使用kmeans初始化组件的均值和协方差:

load('data1.mat');

X = Data'; % 300x3 data set
D = size(X,2); % dimension
N = size(X,1); % number of samples
K = 4; % number of Gaussian Mixture components

% Initialization
p = [0.2, 0.3, 0.2, 0.3]; % arbitrary pi
[idx,mu] = kmeans(X,K); % initial means of the components

% compute the covariance of the components
sigma = zeros(D,D,K);
for k = 1:K
    sigma(:,:,k) = cov(X(idx==k,:));
end

对于E-step,我使用以下公式来计算责任

下面是对应的代码:

% variables for convergence 
converged = 0;
prevLoglikelihood = Inf;
prevMu = mu;
prevSigma = sigma;
prevPi = p;
round = 0;
while (converged ~= 1)
    round = round +1
    gm = zeros(K,N); % gaussian component in the nominator - 
                     % some values evaluate to zero
    sumGM = zeros(N,1); % denominator of responsibilities
    % E-step:  Evaluate the responsibilities using the current parameters
    % compute the nominator and denominator of the responsibilities
    for k = 1:K
        for i = 1:N
             % HERE values evalute to zero e.g. exp(-746.6228) = -Inf
             gm(k,i) = p(k)/sqrt(det(sigma(:,:,k))*(2*pi)^D)*exp(-0.5*(X(i,:)-mu(k,:))*inv(sigma(:,:,k))*(X(i,:)-mu(k,:))');
             sumGM(i) = sumGM(i) + gm(k,i);
         end
    end

    % calculate responsibilities
    res = zeros(K,N); % responsibilities
    Nk = zeros(4,1);
    for k = 1:K
        for i = 1:N
            res(k,i) = gm(k,i)/sumGM(i);
        end
        Nk(k) = sum(res(k,:));
    end

Nk(k) 使用 M 步骤中给出的公式计算。

M-step

    % M-step: Re-estimate the parameters using the current responsibilities
    mu = zeros(K,3);
    for k = 1:K
        for i = 1:N
            mu(k,:) = mu(k,:) + res(k,i).*X(k,:);
            sigma(:,:,k) = sigma(:,:,k) + res(k,i).*(X(k,:)-mu(k,:))*(X(k,:)-mu(k,:))';
        end
        mu(k,:) = mu(k,:)./Nk(k);
        sigma(:,:,k) = sigma(:,:,k)./Nk(k);
        p(k) = Nk(k)/N;
    end

现在为了检查收敛性,使用以下公式计算对数似然:

    % Evaluate the log-likelihood and check for convergence of either 
    % the parameters or the log-likelihood. If not converged, go to E-step.
    loglikelihood = 0;
    for i = 1:N
        loglikelihood = loglikelihood + log(sum(gm(:,i)));
    end


    % Check for convergence of parameters
    errorLoglikelihood = abs(loglikelihood-prevLoglikelihood);
    if (errorLoglikelihood <= eps)
        converged = 1; 
    end

    errorMu = abs(mu(:)-prevMu(:));
    errorSigma = abs(sigma(:)-prevSigma(:));
    errorPi = abs(p(:)-prevPi(:));

    if (all(errorMu <= eps) && all(errorSigma <= eps) && all(errorPi <= eps))
        converged = 1;
    end

    prevLoglikelihood = loglikelihood;
    prevMu = mu;
    prevSigma = sigma;
    prevPi = p;

end % while 

在第一轮之后,loglikelihood 大约是 700。 在第二轮中,它是-Inf,因为 E-step 中的一些 gm(k,i) 值为零。因此对数显然是负无穷大。

零值也导致sumGM 等于零,因此导致musigma 矩阵内的所有NaN 条目。

我该如何解决这个问题? 你能告诉我我的实现是否有问题吗? 能不能通过提高Matlab的精度来解决?


编辑:

我为 gm(k,i) 中的 exp() 项添加了缩放比例。 不幸的是,这并没有多大帮助。经过几轮后,我仍然遇到下溢问题。

scale = zeros(N,D);
for i = 1:N
    max = 0;
    for k = 1:K
        Xmu = X(i,:)-mu(k,:);
        if (norm(scale(i,:) - Xmu) > max)
            max = norm(scale(i,:) - Xmu);
            scale(i,:) = Xmu;
        end
    end
end


for k = 1:K
    for i = 1:N
        Xmu = X(i,:)-mu(k,:);
        % scale gm to prevent underflow
        Xmu = Xmu - scale(i,:);
        gm(k,i) = p(k)/sqrt(det(sigma(:,:,k))*(2*pi)^D)*exp(-0.5*Xmu*inv(sigma(:,:,k))*Xmu');
        sumGM(i) = sumGM(i) + gm(k,i);
    end
end

我进一步注意到,与在 M 步中计算均值的后续轮次相比,kmeans 初始化均值完全不同。

kmeans:

mu =   13.500000000000000   0.026602138870044   0.062415945993735
       88.500000000000000  -0.009869960132085  -0.075177888210981
       39.000000000000000  -0.042569305020309   0.043402772876513
       64.000000000000000  -0.024519281362918  -0.012586980924762

M步后:

round = 2

mu = 1.000000000000000   0.077230046948357   0.024498886414254
     2.000000000000000   0.074260118474053   0.026484346404660
     3.000000000000002   0.070944016105476   0.029043085983168
     4.000000000000000   0.067613431480832   0.031641849205021

在接下来的几轮中,mu 完全没有变化。与第 2 轮相同。

我猜这是因为 gm(k,i) 中的下溢引起的? 要么我的缩放实现不正确,要么算法的整个实现在某处有问题:(


编辑 2

四轮之后,我得到了NaN 值,并更详细地研究了 gm。仅查看一个样本(并且没有 0.5 因子),gm 在所有组件中都变为零。放入matlabgm(:,1) = [0 0 0 0]。这反过来导致 sumGM 等于零 -> NaN,因为 I 除以零。我在

中给出了更多细节
round = 1

mu = 62.0000   -0.0298   -0.0078
     37.0000   -0.0396    0.0481
     87.5000   -0.0083   -0.0728
     12.5000    0.0303    0.0614

gm(:,1) = [11.7488, 0.0000, 0.0000, 0.0000]


round = 2

mu = 1.0000    0.0772    0.0245
     2.0000    0.0743    0.0265
     3.0000    0.0709    0.0290
     4.0000    0.0676    0.0316


gm(:,1) = [0.0000, 0.0000, 0.0000, 0.3128]

round = 3

mu = 1.0000    0.0772    0.0245
     2.0000    0.0743    0.0265
     3.0000    0.0709    0.0290
     4.0000    0.0676    0.0316


gm(:,1) = [0, 0, 0.0000, 0.2867]


round = 4


mu = 1.0000    0.0772    0.0245
        NaN       NaN       NaN
     3.0000    0.0709    0.0290
     4.0000    0.0676    0.0316

gm(:,1) = 1.0e-105 * [0, NaN, 0, 0.5375]

首先,与 kmeans 的初始化相比,均值似乎没有改变,并且完全不同。

根据gm(:,1) 的输出,每个样本(不仅仅是像这里的第一个样本)只对应一个高斯分量。样本不应该在每个高斯分量中“部分分布”吗?


EDIT3:

所以我猜 mu 没有改变的问题是 M 步骤中的第一行:mu = zeros(K,3);

为了解决下溢问题,我目前正在尝试使用高斯的日志:

function logPdf = logmvnpdf(X, mu, sigma, D)
    Xmu = X-mu;
    logPdf = log(1/sqrt(det(sigma)*(2*pi)^D)) + (-0.5*Xmu*inv(sigma)*Xmu');
end

新问题是协方差矩阵 sigma。 Matlab 声称: 警告:矩阵接近奇异或严重缩放。结果可能不准确。

6 轮后,我得到 gm 的虚值(高斯分布)。

更新后的 E-Step 现在看起来像这样:

gm = zeros(K,N); % gaussian component in the nominator
sumGM = zeros(N,1); % denominator of responsibilities


for k = 1:K
    for i = 1:N
        %gm(k,i) = p(k)/sqrt(det(sigma(:,:,k))*(2*pi)^D)*exp(-0.5*Xmu*inv(sigma(:,:,k))*Xmu');
        %gm(k,i) = p(k)*mvnpdf(X(i,:),mu(k,:),sigma(:,:,k));
        gm(k,i) = log(p(k)) + logmvnpdf(X(i,:), mu(k,:), sigma(:,:,k), D);
        sumGM(i) = sumGM(i) + gm(k,i);
    end
end

【问题讨论】:

    标签: algorithm matlab mixture-model


    【解决方案1】:

    看起来您应该能够使用比例因子 scale(i) 将 gm(k, i) 带入可表示的范围,因为如果您将 gm(k, i) 乘以 scale(i) 这将结束也乘以 sumGM(i),并在计算 res(k, i) = gm(k, i) / sumGM(i) 时被取消。

    我会在理论上使 scale(i) = 1 / max_k(exp(-0.5*(X(i,:)-mu(k,:))) ,并在不进行幂运算的情况下实际计算它,所以你最终处理它的日志, max_k(-0.5*(X(i,:)-mu(k,:)) - 这为您提供了一个通用术语,您可以添加到每个 -0.5*(X(i,:)- mu(k,:) 在使用 exp() 之前至少将最大值保持在可表示的范围内 - 在此更正之后仍然下溢到零的任何东西你都不关心,因为它与其他贡献相比微乎其微.

    【讨论】:

    • 感谢您的帮助!不幸的是,在再次发生下溢之前,该算法又运行了几轮(大约 4 到 8 轮)。
    • 我声称至少有一个值不会导致下溢,因为该值将等于比例因子,并且减法将留下值 0。我会尝试调试此问题找出这个论点失败的原因。查看您的代码,我不明白为什么您在 Xmu 中乘以 0.5 - 0.5*scale(i,:)。我也不理解计算 scale(i,:) 的循环,但是我没有使用 Matlab 的经验。如果您对 Matlab 的矢量特征完全不确定,您可以随时替换它或用完全串行的代码检查它,就像实验一样。
    • 感谢您的努力!我不得不承认,我不完全确定 E-step 中的这个责任如何/为什么起作用/应该起作用。如果我错了,请纠正我,但我知道每个数据点都部分分配给所有高斯分量(具有不同的权重)。现在只考虑一个样本,问题是责任提名者中的所有值都为零。为第一个示例输入 matlab 代码:gm(:,1) = [0 0 0 0]。这反过来导致sumGM = 0 并因此导致 NaN 值,因为我除以零。我在 EDIT 2 中给出了更多细节。
    • 我怀疑您遇到的是 Matlab 调试问题,但是您应该注意高斯混合的一个问题:当其中一种混合仅与一个点相关联时,您会得到奇点.参见例如cse.psu.edu/~rtc12/CSE586Spring2010/papers/prmlMixturesEM.pdf 的第 12 页。对此的一个骗局是使用一种模型,该模型会向高斯函数添加一点随机噪声,这样高斯函数就不会生成方差为零或接近零的观测值。
    猜你喜欢
    • 2015-10-16
    • 1970-01-01
    • 2017-09-08
    • 2021-09-30
    • 2016-02-15
    • 1970-01-01
    • 2023-03-24
    • 2014-01-09
    相关资源
    最近更新 更多