zoukankan      html  css  js  c++  java
  • 4. EM算法-高斯混合模型GMM详细代码实现

    1. EM算法-数学基础

    2. EM算法-原理详解

    3. EM算法-高斯混合模型GMM

    4. EM算法-高斯混合模型GMM详细代码实现

    5. EM算法-高斯混合模型GMM+Lasso

    1. 前言

    EM的前3篇博文分别从数学基础、EM通用算法原理、EM的高斯混合模型的角度介绍了EM算法。按照惯例,本文要对EM算法进行更进一步的探究。就是动手去实践她。

    2. GMM实现

    我的实现逻辑基本按照GMM算法流程中的方式实现。需要全部可运行代码,请移步我的github

    输入:观测数据(x_1,x_2,x_3,...,x_N)

    对输入数据进行归一化处理

    #数据预处理
    def scale_data(self):
        for d in range(self.D):
            max_ = self.X[:, d].max()
            min_ = self.X[:, d].min()
            self.X[:, d] = (self.X[:, d] - min_) / (max_ - min_)
        self.xj_mean = np.mean(self.X, axis=0)
        self.xj_s = np.sqrt(np.var(self.X, axis=0))
    

    输出:GMM的参数

    1. 初始化参数
    #初始化参数
    def init_params(self):
        self.mu = np.random.rand(self.K, self.D)
        self.cov = np.array([np.eye(self.D)] * self.K) * 0.1
        self.alpha = np.array([1.0 / self.K] * self.K)
    
    1. E步:根据当前模型,计算模型(k)(x_i)的影响

    [gamma_{ik}=frac{pi_kmathcal{N}(oldsymbol{x}|oldsymbol{mu}_k,oldsymbol{Sigma}_k)}{sum_{k=1}^Kpi_kmathcal{N}(oldsymbol{x}|oldsymbol{mu}_k,oldsymbol{Sigma}_k)} ]

    #e步,估计gamma
    def e_step(self, data):
        gamma_log_prob = np.mat(np.zeros((self.N, self.K)))
        for k in range(self.K):
            gamma_log_prob[:, k] = log_weight_prob(data, self.alpha[k], self.mu[k], self.cov[k])
        log_prob_norm = logsumexp(gamma_log_prob, axis=1)
        log_gamma = gamma_log_prob - log_prob_norm[:, np.newaxis]
        return log_prob_norm, np.exp(log_gamma)
    
    1. M步:计算(mu_{k+1},Sigma_{k+1}^2,pi_{k+1})

    [n_k=sum_{i=1}^Ngamma_{ik} ]

    [mu_{k+1}=frac{1}{n_k}sum_{i=1}^Ngamma_{ik}x_i ]

    [Sigma_{k+1}^2=frac{1}{n_k}sum_{i=1}^Ngamma_{ik}(x_i-mu_k)^2 ]

    [pi_{k+1}=frac{n_k}{N} ]

    #m步,最大化loglikelihood
    def m_step(self):
        newmu = np.zeros([self.K, self.D])
        newcov = []
        newalpha = np.zeros(self.K)
        for k in range(self.K):
            Nk = np.sum(self.gamma[:, k])
            newmu[k, :] = np.dot(self.gamma[:, k].T, self.X) / Nk
            cov_k = self.compute_cov(k, Nk)
            newcov.append(cov_k)
            newalpha[k] = Nk / self.N
        newcov = np.array(newcov)
        return newmu, newcov, newalpha
    
    1. 重复2,3两步直到收敛

    最后加上loglikelihood的计算方法。

    • 基本的计算方法按照公式定义。

    [L( heta) = sumlimits_{i=1}^m logsumlimits_{z^{(i)}}Q_i(z^{(i)})P(x^{(i)},z^{(i)}| heta);;;s.t.sumlimits_{z}Q_i(z^{(i)}) =1 ]

    实现如下

    def loglikelihood(self):
        P = np.zeros([self.N, self.K])
        for k in range(self.K):
            P[:,k] = prob(self.X, self.mu[k], self.cov[k])
    
        return np.sum(np.log(P.dot(self.alpha)))
    

    但是这样的实现会有2个问题。

    1. 非矩阵运算,速度慢。
    2. 非常容易underflow,因为(P.dot(self.alpha))非常容易是一个很小的数,系统把它当作0处理。
    • 使用以下(LogSumExp)公式进行改进,并且令(a_h = log(Q_i(z^{(i)}))+log(P(x^{(i)},z^{(i)}| heta))),具体实现看github

    [log(sum_hexp(a_h)) = m + log(sum_hexp(a_h - m));;;m=max(a_h) ]

    3. 总结

    首先gmm算法会很容易出现underflow和overflow,所以处理的时候有点麻烦。但是(LogSumExp)能解决大部分这个问题。还有就是我的实现方式是需要协方差矩阵一定要是正定矩阵,所以我的代码中也做了处理。我们好想还不能够满足于最基础的GMM算法,所以在下一篇文章中我们要对GMM加入一个惩罚项,并且用对角矩阵的方式代替协方差矩阵。

  • 相关阅读:
    css盒子模型之内边距padding及简写
    css盒子模型之宽度和高度
    windows 组策略
    windows 快捷键
    cmd 命令快捷键
    django 远程访问
    django 部署在 apache2 上面
    国内常用开源镜像站
    ubuntu1804自带官方源
    ubuntu1604 apt华为国内源
  • 原文地址:https://www.cnblogs.com/huangyc/p/10274881.html
Copyright © 2011-2022 走看看