Python 機器學習 HMM模型三種經典問題

leviliang發表於2024-03-19

隱馬爾可夫模型(Hidden Markov Model, HMM)是一個強大的工具,用於模擬具有隱藏狀態的時間序列資料。HMM廣泛應用於多個領域,如語音識別、自然語言處理和生物資訊學等。在處理HMM時,主要集中於三個經典問題:評估問題、解碼問題和學習問題。三個問題構成了使用隱馬爾可夫模型時的基礎框架,使得HMM不僅能夠用於模擬複雜的時間序列資料,還能夠從資料中學習和預測。

參考文件:Python 機器學習 HMM模型三種經典問題-CJavaPy

1、評估問題

在隱馬爾可夫模型(Hidden Markov Model, HMM)的應用中,評估問題是指確定一個給定的觀測序列在特定HMM引數下的機率。簡而言之,就是評估一個模型生成某個觀測序列的可能性有多大。模型評估問題通常使用前向演算法解決。前向演算法是一個動態規劃演算法,它透過累積“前向機率”來計算給定觀測序列的機率。前向機率定義為在時間點t觀察到序列的前t個觀測,並且系統處於狀態i的機率。演算法的核心是遞推公式,它利用前一時刻的前向機率來計算當前時刻的前向機率。

import numpy as np

# 定義模型引數
states = {'Rainy': 0, 'Sunny': 1}
observations = ['walk', 'shop', 'clean']
start_probability = np.array([0.6, 0.4])
transition_probability = np.array([[0.7, 0.3], [0.4, 0.6]])
emission_probability = np.array([[0.1, 0.4, 0.5], [0.6, 0.3, 0.1]])

# 觀測序列,用索引表示
obs_seq = [0, 1, 2]  # 對應於 'walk', 'shop', 'clean'

# 初始化前向機率矩陣
alpha = np.zeros((len(obs_seq), len(states)))

# 初始化
alpha[0, :] = start_probability * emission_probability[:, obs_seq[0]]

# 遞推計算
for t in range(1, len(obs_seq)):
    for j in range(len(states)):
        alpha[t, j] = np.dot(alpha[t-1, :], transition_probability[:, j]) * emission_probability[j, obs_seq[t]]

# 序列的總機率為最後一步的機率之和
total_prob = np.sum(alpha[-1, :])

print("Forward Probability Matrix:")
print(alpha)
print("\nTotal Probability of Observations:", total_prob)

2、解碼問題

在隱馬爾可夫模型(Hidden Markov Model, HMM)中,解碼問題是指給定一個觀測序列和模型引數,找出最有可能產生這些觀測的隱狀態序列。這個問題的核心是如何從已知的觀測資料中推斷出隱含的狀態序列,這在許多應用場景中非常有用,如語音識別、自然語言處理、生物資訊學等。解決這一問題最常用的演算法是維特比演算法,一種動態規劃方法,它透過計算並記錄達到每個狀態的最大機率路徑,從而找到最可能的狀態序列。

import numpy as np

def viterbi(obs, states, start_p, trans_p, emit_p):
    """
    Viterbi Algorithm for solving the decoding problem of HMM
    obs: 觀測序列
    states: 隱狀態集合
    start_p: 初始狀態機率
    trans_p: 狀態轉移機率矩陣
    emit_p: 觀測機率矩陣
    """
    V = [{}]
    path = {}

    # 初始化
    for y in states:
        V[0][y] = start_p[y] * emit_p[y][obs[0]]
        path[y] = [y]

    # 對序列從第二個觀測開始進行運算
    for t in range(1, len(obs)):
        V.append({})
        newpath = {}

        for cur_state in states:
            # 選擇最可能的前置狀態
            (prob, state) = max((V[t-1][y0] * trans_p[y0][cur_state] * emit_p[cur_state][obs[t]], y0) for y0 in states)
            V[t][cur_state] = prob
            newpath[cur_state] = path[state] + [cur_state]

        # 不更新path
        path = newpath

    # 返回最終路徑和機率
    (prob, state) = max((V[len(obs) - 1][y], y) for y in states)
    return (prob, path[state])

# 定義狀態、觀測序列及模型引數
states = ('Rainy', 'Sunny')
observations = ('walk', 'shop', 'clean')
start_probability = {'Rainy': 0.6, 'Sunny': 0.4}
transition_probability = {
   'Rainy' : {'Rainy': 0.7, 'Sunny': 0.3},
   'Sunny' : {'Rainy': 0.4, 'Sunny': 0.6},
}
emission_probability = {
   'Rainy' : {'walk': 0.1, 'shop': 0.4, 'clean': 0.5},
   'Sunny' : {'walk': 0.6, 'shop': 0.3, 'clean': 0.1},
}

# 應用維特比演算法
result = viterbi(observations,
                 states,
                 start_probability,
                 transition_probability,
                 emission_probability)
print(result)

3、學習問題

理解隱馬爾可夫模型(HMM)的模型學習問題關鍵在於確定模型引數,以最大化給定觀測序列的出現機率。解決這一學習問題的常用方法是鮑姆-韋爾奇演算法,這是一種迭代演算法,透過交替執行期望步驟(E步驟)和最大化步驟(M步驟)來找到最大化觀測序列機率的引數。E步驟計算隱狀態的期望值,而M步驟則更新模型引數以最大化觀測序列的機率。這一過程會持續重複,直至滿足一定的收斂條件,如引數變化量低於特定閾值或達到預設的迭代次數。透過這種方式解決學習問題,我們可以獲得一組能夠很好解釋給定觀測資料的模型引數,這表明模型能夠捕捉到觀測資料中的統計規律,用於生成觀測序列、預測未來觀測值或識別新觀測序列中的模式。

import numpy as np
from hmmlearn import hmm

# 假設我們有一組觀測資料,這裡我們隨機生成一些資料作為示例
# 實際應用中,你應該使用真實的觀測資料
n_samples = 1000
n_components = 3  # 假設我們有3個隱狀態
obs_dim = 2  # 觀測資料的維度,例如二維的觀測空間

# 隨機生成觀測資料
np.random.seed(42)
obs_data = np.random.rand(n_samples, obs_dim)

# 初始化GaussianHMM模型
# 這裡我們指定了n_components隱狀態數量和covariance_type協方差型別
model = hmm.GaussianHMM(n_components=n_components, covariance_type='full', n_iter=100)

# 使用觀測資料訓練模型
# 注意:實際應用中的資料可能需要更復雜的預處理步驟
model.fit(obs_data)

# 列印學習到的模型引數
print("學習到的轉移機率矩陣:")
print(model.transmat_)
print("\n學習到的均值:")
print(model.means_)
print("\n學習到的協方差:")
print(model.covars_)

4、三種經典問題案例

深入理解隱馬爾可夫模型(HMM)處理的三種經典問題——評估問題、解碼問題和學習問題,可以將透過一個完整的示例來展示這些問題的應用和解決方案。如有一個簡單的天氣模型,其中的狀態(隱藏狀態)包括晴天(Sunny)和雨天(Rainy),觀測(可見狀態)包括人們的三種活動:散步(Walk)、購物(Shop)和清潔(Clean)。可以使用HMM來處理評估問題、解碼問題和學習問題。

from hmmlearn import hmm
import numpy as np

# 定義模型引數
states = ["Rainy", "Sunny"]
n_states = len(states)

observations = ["walk", "shop", "clean"]
n_observations = len(observations)

start_probability = np.array([0.6, 0.4])

transition_probability = np.array([
    [0.7, 0.3],
    [0.4, 0.6],
])

emission_probability = np.array([
    [0.1, 0.4, 0.5],
    [0.6, 0.3, 0.1],
])

# 建立模型
model = hmm.MultinomialHMM(n_components=n_states)
model.startprob_ = start_probability
model.transmat_ = transition_probability
model.emissionprob_ = emission_probability
model.n_trials = 4

# 觀測序列
obs_seq = np.array([[0], [1], [2]]).T  # 對應於觀測序列 ['walk', 'shop', 'clean']

# 計算觀測序列的機率
logprob = model.score(obs_seq)
print(f"Observation sequence probability: {np.exp(logprob)}")

# 繼續使用上面的模型引數和觀測序列

# 使用Viterbi演算法找出最可能的狀態序列
logprob, seq = model.decode(obs_seq, algorithm="viterbi")
print(f"Sequence of states: {', '.join(map(lambda x: states[x], seq))}")

# 假設我們只有觀測序列,不知道模型引數
obs_seq = np.array([[0], [1], [2], [0], [1], [2]]).T  # 擴充套件的觀測序列

# 初始化模型
model = hmm.MultinomialHMM(n_components=n_states, n_iter=100)
model.fit(obs_seq)

# 列印學習到的模型引數
print("Start probabilities:", model.startprob_)
print("Transition probabilities:", model.transmat_)
print("Emission probabilities:", model.emissionprob_)

參考文件:Python 機器學習 HMM模型三種經典問題-CJavaPy

相關文章