Skip to content

Commit 3440d03

Browse files
committed
feat: question 2 finishes
1 parent 25d82f4 commit 3440d03

File tree

3 files changed

+195
-9
lines changed

3 files changed

+195
-9
lines changed

notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,22 +111,31 @@
111111
"我们的实验代码都是通过 jupyter notebook 进行编写,并通过 nbdev 进行自动化构建pypi库。\n",
112112
"复现我们实验代码时,建议使用支持jupyter notebook的IDE(如VSCode)运行我们的 `ipynb文件`。\n",
113113
"\n",
114+
"由于本次作业较为简单,在安装了对应依赖库后,就可以直接运行我导出的 `viterbi.py`文件。但是仍然建议使用ipynb来运行。\n",
115+
"由于进行了一些实验探索,我们引入了\n",
116+
"```bash\n",
117+
"pip install fastcore\n",
118+
"pip install jax\n",
119+
"pip install flax\n",
120+
"```\n",
121+
"\n",
114122
"::: {.callout-note}\n",
123+
"\n",
124+
"我们的代码导出为了python模块形式,如果你需要在别的项目中调用我们的代码,\n",
115125
"可以通过以下命令安装我们实验的代码:\n",
116126
"\n",
117127
"```shell\n",
118128
"git clone https://github.com/Open-Book-Studio/THU-Coursework-Machine-Learning-for-Big-Data.git\n",
119129
"cd THU-Coursework-Machine-Learning-for-Big-Data\n",
120130
"pip install -e .\n",
121131
"```\n",
122-
"我们的代码导出为了python模块形式,如果你需要在别的项目中调用我们的代码,可以通过以下命令导入:\n",
132+
"然后通过以下命令导入:\n",
123133
"```python\n",
124134
"from thu_big_data_ml.digital_processing_of_speech_signals.hidden_markov_model import *\n",
125135
"```\n",
126136
":::\n",
127137
"\n",
128-
"这次作业中,我开发的我们课题组的基础依赖库[ScholarlyInfrastructure]\\(https://github.com/THU-CVML/ScholarlyInfrastructure)也相应地进行了代码更新。这个库对标`fastcore`库,对AI科研经常会用到的一些基础性地、和Python语言的表达力有关的代码进行了整理,比如PyTorch模型检查、清晰的日志、实验参数管理、异常处理、argmax自动函数优化等。接下来我们也会用到这个项目中的一些代码来完成本次作业。\n",
129-
"\n",
138+
"这次作业中,我开发的我们课题组的基础依赖库[ScholarlyInfrastructure]\\(https://github.com/THU-CVML/ScholarlyInfrastructure)也相应地进行了代码更新。这个库对标`fastcore`库,对AI科研经常会用到的一些基础性地、和Python语言的表达力有关的代码进行了整理,比如PyTorch模型检查、清晰的日志、实验参数管理、异常处理、argmax自动函数优化等。具体而言,本次作业中我们更新了 `scholarly_infrastructure.nbscholar` 模块,加强了代码导出同步功能。\n",
130139
"::: {.callout-tip}\n",
131140
"\n",
132141
"通过以下命令安装 ScholarlyInfrastructure\n",
@@ -1428,11 +1437,14 @@
14281437
" model = HiddenMarkovModel()\n",
14291438
" observations = jnp.array([0, 1, 0, 1, 1]) # [THU, PKU, THU, PKU, PKU]\n",
14301439
" fwd, p = model.compute_likelihood_by_forward(observations)\n",
1431-
" print(p, fwd)\n",
1440+
" print(p)\n",
1441+
" print(fwd)\n",
14321442
" bwd, p = model.compute_likelihood_by_backward(observations)\n",
1433-
" print(p, bwd)\n",
1443+
" print(p)\n",
1444+
" print(bwd)\n",
14341445
" prob, path = model.decode_states_by_viterbi(observations)\n",
1435-
" print(prob, path)"
1446+
" print(prob)\n",
1447+
" print(path)"
14361448
]
14371449
},
14381450
{
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb.
2+
3+
# %% auto 0
4+
__all__ = ['HiddenMarkovModel']
5+
6+
# %% ../../notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb 36
7+
from fastcore.all import patch
8+
9+
# %% ../../notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb 38
10+
import jax.numpy as jnp
11+
from flax import nnx # 导入 nnx 库,里面包含了一些常用的网络层
12+
from fastcore.all import store_attr # 导入 fastcore 基础库的 store_attr 函数,用来方便地存储类的属性,这样Python面向对象写起来不那么冗长。 请 pip install fastcore。
13+
14+
# %% ../../notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb 39
15+
class HiddenMarkovModel(nnx.Module):
16+
"""Hidden Markov Model
17+
18+
HMM with 3 states and 2 observation categories.
19+
20+
Attributes:
21+
ob_category (list, with length 2): observation categories
22+
total_states (int): number of states, default=3
23+
pi (array, with shape (3,)): initial state probability
24+
A (array, with shape (3, 3)): transition probability. A.sum(axis=1) must be all ones.
25+
A[i, j] means transition prob from state i to state j.
26+
A.T[i, j] means transition prob from state j to state i.
27+
B (array, with shape (3, 2)): emitting probability, B.sum(axis=1) must be all ones.
28+
B[i, k] means emitting prob from state i to observation k.
29+
30+
"""
31+
32+
def __init__(self):
33+
self.ob_category = ['THU', 'PKU'] # 0: THU, 1: PKU
34+
self.total_states = 3
35+
self.pi = nnx.Param(jnp.array([0.2, 0.4, 0.4]))
36+
self.A = nnx.Param(jnp.array([[0.1, 0.6, 0.3],
37+
[0.3, 0.5, 0.2],
38+
[0.7, 0.2, 0.1]]))
39+
self.B = nnx.Param(jnp.array([[0.5, 0.5],
40+
[0.4, 0.6],
41+
[0.7, 0.3]]))
42+
43+
# %% ../../notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb 45
44+
@patch
45+
def compute_likelihood_by_forward(self: HiddenMarkovModel, ob):
46+
"""HMM Forward Algorithm.
47+
48+
Args:
49+
ob (array, with shape(T,)): (o1, o2, ..., oT), observations
50+
51+
Returns:
52+
fwd (array, with shape(T, 3)): fwd[t, s] means full-path forward probability torwards state s at
53+
timestep t given the observation ob[0:t+1].
54+
给定观察ob[0:t+1]情况下t时刻到达状态s的所有可能路径的概率和
55+
prob: the probability of HMM model generating observations.
56+
57+
"""
58+
T = ob.shape[0]
59+
fwd = jnp.zeros((T, self.total_states))
60+
61+
# Begin Assignment
62+
63+
# 初始化 t=0 时刻的前向概率
64+
# fwd[0, :] = self.pi * self.B[:, ob[0]] # jax 不支持 in place 复制
65+
fwd = fwd.at[0, :].set(self.pi * self.B[:, ob[0]])
66+
67+
# 根据前向概率的递推公式计算 t=1 到 T 时刻的前向概率
68+
for t in range(1, T):
69+
for j in range(self.total_states):
70+
fwd = fwd.at[t, j].set(self.B[j, ob[t]] * jnp.dot(fwd[t - 1, :], self.A[:, j]))
71+
72+
# End Assignment
73+
74+
prob = fwd[-1, :].sum()
75+
76+
return fwd, prob
77+
78+
# %% ../../notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb 51
79+
@patch
80+
def compute_likelihood_by_backward(self:HiddenMarkovModel, ob):
81+
"""HMM Backward Algorithm.
82+
83+
Args:
84+
ob (array, with shape(T,)): (o1, o2, ..., oT), observations
85+
86+
Returns:
87+
bwd (array, with shape(T, 3)): bwd[t, s] means full-path backward probability torwards state s at
88+
timestep t given the observation ob[t+1::]
89+
给定观察ob[t+1::]情况下t时刻到达状态s的所有可能路径的概率和
90+
prob: the probability of HMM model generating observations.
91+
92+
"""
93+
T = ob.shape[0]
94+
bwd = jnp.zeros((T, self.total_states))
95+
96+
# Begin Assignment
97+
98+
# 初始化 t == T-1 时刻到达各个状态的概率
99+
bwd = bwd.at[T - 1, :].set(1.0)
100+
101+
# Induction step
102+
for t in reversed(range(T - 1)):
103+
for i in range(self.total_states):
104+
bwd = bwd.at[t, i].set(jnp.dot(bwd[t + 1, :] * self.B[:, ob[t + 1]], self.A[i, :]))
105+
106+
# End Assignment
107+
108+
prob = (bwd[0, :] * self.B[:, ob[0]] * self.pi).sum()
109+
110+
return bwd, prob
111+
112+
# %% ../../notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb 56
113+
@patch
114+
def decode_states_by_viterbi(self:HiddenMarkovModel, ob):
115+
"""Viterbi Decoding Algorithm.
116+
117+
Args:
118+
ob (array, with shape(T,)): (o1, o2, ..., oT), observations
119+
120+
Variables:
121+
delta (array, with shape(T, 3)): delta[t, s] means max probability torwards state s at
122+
timestep t given the observation ob[0:t+1]
123+
给定观察ob[0:t+1]情况下t时刻到达状态s的概率最大的路径的概率
124+
phi (array, with shape(T, 3)): phi[t, s] means prior state s' for delta[t, s]
125+
给定观察ob[0:t+1]情况下t时刻到达状态s的概率最大的路径的t-1时刻的状态s'
126+
127+
Returns:
128+
best_prob: the probability of the best state sequence
129+
best_path: the best state sequence
130+
131+
"""
132+
T = ob.shape[0]
133+
delta = jnp.zeros((T, self.total_states))
134+
#update np.int32
135+
phi = jnp.zeros((T, self.total_states), jnp.int32)
136+
best_prob, best_path = 0.0, jnp.zeros(T, dtype=jnp.int32)
137+
138+
# Begin Assignment
139+
140+
# 从初始状态开始
141+
delta = delta.at[0, :].set(self.pi * self.B[:, ob[0]])
142+
143+
# 根据动态规划的公式来更新delta和phi
144+
for t in range(1, T):
145+
for j in range(self.total_states):
146+
d, p = max((delta[t - 1, i] * self.A[i, j] * self.B[j, ob[t]], i) for i in range(self.total_states))
147+
delta = delta.at[t, j].set(d)
148+
phi = phi.at[t, j].set(p)
149+
150+
# End Assignment
151+
152+
best_path = best_path.at[T-1].set(delta[T-1, :].argmax(0))
153+
best_prob = delta[T-1, best_path[T-1]]
154+
for t in reversed(range(T-1)):
155+
best_path = best_path.at[t].set(phi[t+1, best_path[t+1]])
156+
157+
return best_prob, best_path
158+
159+
# %% ../../notebooks/coding_projects/digital_processing_of_speech_signals/P2_HMM/00hidden_markov_model.ipynb 60
160+
if __name__ == "__main__":
161+
model = HiddenMarkovModel()
162+
observations = jnp.array([0, 1, 0, 1, 1]) # [THU, PKU, THU, PKU, PKU]
163+
fwd, p = model.compute_likelihood_by_forward(observations)
164+
print(p)
165+
print(fwd)
166+
bwd, p = model.compute_likelihood_by_backward(observations)
167+
print(p)
168+
print(bwd)
169+
prob, path = model.decode_states_by_viterbi(observations)
170+
print(prob)
171+
print(path)

thu_big_data_ml/digital_processing_of_speech_signals/hidden_markov_model.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,11 @@ def decode_states_by_viterbi(self:HiddenMarkovModel, ob):
161161
model = HiddenMarkovModel()
162162
observations = jnp.array([0, 1, 0, 1, 1]) # [THU, PKU, THU, PKU, PKU]
163163
fwd, p = model.compute_likelihood_by_forward(observations)
164-
print(p, fwd)
164+
print(p)
165+
print(fwd)
165166
bwd, p = model.compute_likelihood_by_backward(observations)
166-
print(p, bwd)
167+
print(p)
168+
print(bwd)
167169
prob, path = model.decode_states_by_viterbi(observations)
168-
print(prob, path)
170+
print(prob)
171+
print(path)

0 commit comments

Comments
 (0)