HMM study:認識混合高斯模型與EM算法(附Python仿真)

混合高斯模型

Gaussian Mixed Model 表示多個高斯分佈的線性組合,設有隨機變量X\textbf{X},則混合高斯模型表示如下p(x)=k=1KπkN(x/μk,k)p(\textbf{x})=\sum_{k=1}^K \pi_kN(x/\mu_k,\sum_k)其中πk\pi_k可以認爲是高斯分佈的權重,N(x/μk,k)N(x/\mu_k,\sum_k)表示第kk個高斯分量。

EM(expectation maximization)期望極大算法

這篇寫得太好了在此保存
以GMM爲例,已知樣本來自GMM,我們需要通過觀測樣本對GMM的權重π\pi,各個高斯模型的均值和方差μ,\mu,\sum進行估計。此時思考HMM模型要解決的第一個問題:已知觀測值和多個HMM模型,哪個HMM模型最優有可能產生這個觀測? 解決這個問題只需要代入模型求解出現該觀測的概率,然後選擇概率最大的模型即可。
但是混合高斯模型不能直接使用前向算法解決,因爲模型並不是已知,我們需要確定模型的參數,且參數不是從已知的模型中進行選擇,而是對未知的參數進行擬合。
EM迭代過程:
假設給定一個GMM(π0,u0,0)(\pi_0,u_0,\sum_0),根據該模型對當前的樣本劃分類別(即每個樣本屬於哪個高斯分佈)。
樣本劃分完畢,求個各高斯分佈產生該樣本的概率,並且表示整個採樣數據產生的概率,然後最大化採樣數據概率。從而優化GMM的參數
如圖,來自上述推薦博客
在這裏插入圖片描述

Python仿真

代碼來自網絡,侵刪

import math
import copy
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


# 生成隨機數據,4個高斯模型
def generate_data(sigma, N, mu1, mu2, mu3, mu4, alpha):
    global X  # 可觀測數據集
    X = np.zeros((N, 2))  # 初始化X,2行N列。2維數據,N個樣本
    X = np.matrix(X)
    global mu  # 隨機初始化mu1,mu2,mu3,mu4
    mu = np.random.random((4, 2))
    mu = np.matrix(mu)
    global excep  # 期望第i個樣本屬於第j個模型的概率的期望
    excep = np.zeros((N, 4))
    global alpha_  # 初始化混合項係數
    alpha_ = [0.25, 0.25, 0.25, 0.25]
    for i in range(N):
        if np.random.random(1) < 0.1:  # 生成0-1之間隨機數
            X[i, :] = np.random.multivariate_normal(mu1, sigma, 1)  # 用第一個高斯模型生成2維數據
        elif 0.1 <= np.random.random(1) < 0.3:
            X[i, :] = np.random.multivariate_normal(mu2, sigma, 1)  # 用第二個高斯模型生成2維數據
        elif 0.3 <= np.random.random(1) < 0.6:
            X[i, :] = np.random.multivariate_normal(mu3, sigma, 1)  # 用第三個高斯模型生成2維數據
        else:
            X[i, :] = np.random.multivariate_normal(mu4, sigma, 1)  # 用第四個高斯模型生成2維數據

    print("可觀測數據:\n", X)  # 輸出可觀測樣本
    print("初始化的mu1,mu2,mu3,mu4:", mu)  # 輸出初始化的mu


def e_step(sigma, k, N):
    global X
    global mu
    global excep
    global alpha_
    for i in range(N):
        denom = 0
        for j in range(0, k):
            denom += alpha_[j] * math.exp(-(X[i, :] - mu[j, :]) * sigma.I * np.transpose(X[i, :] - mu[j, :])) / np.sqrt(
                np.linalg.det(sigma))  # 分母
        for j in range(0, k):
            numer = math.exp(-(X[i, :] - mu[j, :]) * sigma.I * np.transpose(X[i, :] - mu[j, :])) / np.sqrt(
                np.linalg.det(sigma))  # 分子
            excep[i, j] = alpha_[j] * numer / denom  # 求期望
    print("隱藏變量:\n", excep)


def m_step(k, N):
    global excep
    global X
    global alpha_
    for j in range(0, k):
        denom = 0  # 分母
        numer = 0  # 分子
        for i in range(N):
            numer += excep[i, j] * X[i, :]
            denom += excep[i, j]
        mu[j, :] = numer / denom  # 求均值
        alpha_[j] = denom / N  # 求混合項係數


if __name__ == '__main__':
    iter_num = 1000  # 迭代次數
    N = 500  # 樣本數目
    k = 4  # 高斯模型數
    probility = np.zeros(N)  # 混合高斯分佈
    u1 = [5, 35]
    u2 = [30, 40]
    u3 = [20, 20]
    u4 = [45, 15]
    sigma = np.matrix([[30, 0], [0, 30]])  # 協方差矩陣
    alpha = [0.1, 0.2, 0.3, 0.4]  # 混合項係數
    generate_data(sigma, N, u1, u2, u3, u4, alpha)  # 生成數據
    # 迭代計算
    for i in range(iter_num):
        err = 0  # 均值誤差
        err_alpha = 0  # 混合項係數誤差
        Old_mu = copy.deepcopy(mu)
        Old_alpha = copy.deepcopy(alpha_)
        e_step(sigma, k, N)  # E步
        m_step(k, N)  # M步
        print("迭代次數:", i + 1)
        print("估計的均值:", mu)
        print("估計的混合項係數:", alpha_)
        for z in range(k):
            err += (abs(Old_mu[z, 0] - mu[z, 0]) + abs(Old_mu[z, 1] - mu[z, 1]))  # 計算誤差
            err_alpha += abs(Old_alpha[z] - alpha_[z])
        if (err <= 0.001) and (err_alpha < 0.001):  # 達到精度退出迭代
            print(err, err_alpha)
            break
    # 可視化結果

    # 畫分類好的數據
    plt.subplot(222)
    plt.title('classified data through EM')
    order = np.zeros(N)
    color = ['b', 'r', 'k', 'y']
    for i in range(N):
        for j in range(k):
            if excep[i, j] == max(excep[i, :]):
                order[i] = j  # 選出X[i,:]屬於第幾個高斯模型
            probility[i] += alpha_[int(order[i])] * math.exp(
                -(X[i, :] - mu[j, :]) * sigma.I * np.transpose(X[i, :] - mu[j, :])) / (
                                        np.sqrt(np.linalg.det(sigma)) * 2 * np.pi)  # 計算混合高斯分佈
        plt.scatter(X[i, 0], X[i, 1], c=color[int(order[i])], s=25, alpha=0.4, marker='o')  # 繪製分類後的散點圖
    # 繪製三維圖像
    ax = plt.subplot(223, projection='3d')
    plt.title('3d view')
    for i in range(N):
        ax.scatter(X[i, 0], X[i, 1], probility[i], c=color[int(order[i])])
    plt.show()

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