
書記が数学やるだけ#950 隠れマルコフモデル
隠れマルコフモデルの理論について。
問題


説明
隠れマルコフモデル(hidden Markov model; HMM)は、確率モデルのひとつであり、観測されない(隠れた)状態をもつマルコフ過程である。これは状態空間モデルの一種と言える。



隠れマルコフモデル(HMM)の基盤アルゴリズムには以下の3つがある。
1. 前向きアルゴリズム(Forward Algorithm)
目的:モデルの評価(Evaluation)
モデル(状態遷移の確率や、そこからデータが出る確率)がすでに分かっている前提で、「このモデルから、今目の前にある観測データが出力される確率はどれくらいか?」を計算する。
2. ビタビアルゴリズム(Viterbi Algorithm)
目的:状態の復号(Decoding)
観測データだけが見えている状態で、「その裏で、内部状態はどういう順番で遷移していたのか?」を計算する。
3. バウム・ウェルチアルゴリズム(Baum-Welch Algorithm)
目的:モデルの学習(Learning)
手元にある大量の観測データだけを頼りに、「このデータが一番きれいに説明できるような、最適な確率の組み合わせ(パラメータ)」を逆算して学習する。 数理的にはEMアルゴリズムの特殊なケースであり、「今のパラメータで状態を予測する(Eステップ)」と「その予測を元にパラメータを更新する(Mステップ)」を何度も繰り返す。


解答
本問のHMMを図示すると以下の通り,同時確率は全経路の確率をかけて求める。

漸化式を求めるには,周辺化(同時確率の分解)・条件付き確率の積の法則・マルコフ性を用いる。結果として,「時刻 t までに状態 si にいる確率 αt (i)」に「状態遷移確率 aij 」をかけて全状態分を足し合わせ、最後に「状態 sj から yt+1 が出力される確率 bj (yt+1 )」を掛け算したものとなる。

前向きアルゴリズムが「総和(∑)」を計算していたのに対し、ビタビアルゴリズムは「最も確率の高い単一の経路(max)」を追跡する。

Baum-Welchアルゴリズムについて,分子は「時刻 t までに状態 si にたどり着き(α)、そこから sj に遷移して yt+1 を出力し(a,b)、さらにそこから最後まで観測を全うする(β)」という一本の局所的な流れの重みを表し,それを全経路の総和(分母)で割ることで、正規化された条件付き確率(割合)を求めている。

HMMの実装はhmmlearnを用いて簡単にできる。
import numpy as np
from hmmlearn import hmm
# 1. 離散型の隠れマルコフモデル (CategoricalHMM) のインスタンス化
# 状態数 (n_components) = 2
model = hmm.CategoricalHMM(n_components=2, random_state=42)
# 2. 問題1のパラメータを設定
# 初期状態確率 pi
model.startprob_ = np.array([0.6, 0.4])
# 状態遷移確率行列 A
model.transmat_ = np.array([
[0.7, 0.3], # s1からの遷移
[0.4, 0.6] # s2からの遷移
])
# 出力(観測)確率行列 B
# 0: v1, 1: v2 とマッピング
model.emissionprob_ = np.array([
[0.2, 0.8], # s1からの出力
[0.9, 0.1] # s2からの出力
])
# 3. 観測系列 Y = (v1, v1, v2) に対するViterbi復号
# hmmlearnの入力は (系列長, 特徴量数) の2次元配列である必要があります
X_observed = np.array([[0], [0], [1]]) # v1, v1, v2
# decodeメソッドがViterbiアルゴリズムを実行
logprob, state_sequence = model.decode(X_observed)
print("--- Viterbiアルゴリズムの結果 ---")
print(f"対数尤度 (Log Probability): {logprob}")
print(f"最も尤もらしい状態系列 (0=s1, 1=s2): {state_sequence + 1}")
# 4. モデルから新しいデータをサンプリング(生成)
X_gen, Z_gen = model.sample(n_samples=5)
print("\n--- モデルからのサンプリング結果 ---")
print(f"生成された状態系列: {Z_gen + 1}")
print(f"生成された観測系列: {X_gen.flatten()}")
--- Viterbiアルゴリズムの結果 ---
対数尤度 (Log Probability): -2.777271670144163
最も尤もらしい状態系列 (0=s1, 1=s2): [2 2 1]
--- モデルからのサンプリング結果 ---
生成された状態系列: [1 2 1 1 1]
生成された観測系列: [1 0 0 1 1]本記事のもくじはこちら: