目录
一、作业头
这个作业属于那个课程 | 自然语言处理 |
---|---|
这个作业要求在哪里 | http://t.csdn.cn/f0hUe |
我在这个课程的目标是 | 学习自然语言处理技术,完善专业技术 |
这个作业在那个具体方面帮助我实现目标 | 了解HMM模型和学习词性标注 |
参考文献 | https://blog.youkuaiyun.com/Daycym/article/details/89331220 https://blog.youkuaiyun.com/sharic_song/article/details/105319961 https://blog.youkuaiyun.com/weixin_62231629/article/details/127051385 https://blog.youkuaiyun.com/chunyun0716/article/details/52963748 https://blog.youkuaiyun.com/sinat_33741547/article/details/78867039 |
二、什么是HMM
隐马尔可夫模型(Hidden Markov Model,HMM)是统计模型,它用来描述一个含有隐含未知参数的马尔可夫过程。
常见的例子
抛硬币
假设小明有两个硬币A、B,这两个硬币的正反面的概率是不一样的,我们假设A硬币正面的概率为0.6,B硬币正面的概率为0.7,那么如果我们在未来6次的硬币抛掷过程中,得到如下的结果:
硬币(Z) A B B A B A
结果(x) 正 反 正 正 反 正
这种时候就会存在三个问题:
第一次即初始投的硬币是A还是B?
若知道前一次投的硬币的种类,那后一次硬币是A还是B?
每次投掷硬币时,结果是正面还是反面?
针对第一个问题,那么就有一个初始的概率P(π),它决定了第一个位置是A还是B,然后假设确定了初始的位置为A,那么我们就需要知道第一次投掷硬币的结果是正还是反,这就是一个生成概率P(A),然后呢我们还得知道第二次硬币是A还是B,假设是B,那么就有一个P(B|A)的转移概率。这就是HMM模型的三个参数。
针对我们上面的投掷硬币的问题,HMM模型的三个参数为(π,A,B)
其中π代表第一个位置P(A)=0.3,P(B)=0.7
A代表转移矩阵P(A|A)=0.3, P(B|A)=0.5, P(A|B)=0.4, P(B|B)=0.6
B代表生成矩阵P(正|A)=0.4,P(反|A)=0.6,P(正|B)=0.2,P(反|B)=0.8
三、估计HMM的模型参数
参数估计问题:给定一个观察序列O=O1O2…OTO=O1O2…OT,如何调节模型μ=(A,B,π)μ=(A,B,π)的参数,使得P(O|μ)P(O|μ)最大化:
模型的参数是指构成 μμ的 πi,aij,bj(k)πi,aij,bj(k)。本文的前序两节讲的EM算法就是为了解决模型参数的最大化问题。其基本思想是,初始时随机地给模型参数赋值,该赋值遵循模型对参数的限制,例如,从某一状态出发的所有转移概率之和为1.给模型参数赋初值后,得到模型 μ0μ0, 然后根据 μ0μ0可以得到模型中隐变量的期望值。例如,从 μ0μ0得到某一状态到另一状态的期望次数,用期望次数来替代实际次数,这样可以得到模型参数的重新估计值,由此得到新的模型 μ1μ1。然后重复上述过程,直到参数收敛于最大似然估计值。
Hidden_states = ('Healthy', 'Fever') # 隐状态集合
Observations_states = ('normal', 'cold', 'dizzy') # 观测状态集合
Start_probability = {'Healthy': 0.6, 'Fever': 0.4} # 表示病人第一次到访时医生认为其所处的HMM状态,他唯一知道的是病人倾向于是健康的(可以理解为这是基于一个对大众身体信息的了解得出的初始状态)
Hidden_transition_probability = { # 隐马尔可夫链中身体状态的状态转移概率,我们能够看到,当天健康的人,第二天有30%的概率会发烧
'Healthy' : {'Healthy': 0.7, 'Fever': 0.3},
'Fever' : {'Healthy': 0.4, 'Fever': 0.6},
}
Hidden_observations_probability = { # 原来叫emission_probability。这里表示病人每天的感觉的可能性。即,如果他是一个健康人,有50%的可能会感觉正常,40%觉得冷,10%觉得头晕
'Healthy' : {'normal': 0.5, 'cold': 0.4, 'dizzy': 0.1},
'Fever' : {'normal': 0.1, 'cold': 0.3, 'dizzy': 0.6},
}
# Helps visualize the steps of Viterbi.
def print_dptable(V): # 打印dp矩阵
print (" "),
for i in range(len(V)):
print("%7d" % i)
print()
for y in V[0].keys():
print ("%.5s: " % y)
for t in range(len(V)):
print ("%.7s" % ("%f" % V[t][y]))
print()
def viterbi(obs, states, start_p, trans_p, h2o_p): # Viterbi算法
V = [{}]
path = {}
# Initialize base cases (t == 0)
for y in states:
V[0][y] = start_p[y] * h2o_p[y][obs[0]]
path[y] = [y]
# Run Viterbi for t > 0
for t in range(1,len(obs)):
V.append({})
newpath = {}
for y in states:
(prob, state) = max([(V[t-1][y0] * trans_p[y0][y] * h2o_p[y][obs[t]], y0) for y0 in states])
V[t][y] = prob
newpath[y] = path[state] + [y]
# Don't need to remember the old paths
path = newpath
print_dptable(V)
(prob, state) = max([(V[len(obs) - 1][y], y) for y in states])
return (prob, path[state])
def example():
return viterbi(Observations_states,
Hidden_states,
Start_probability,
Hidden_transition_probability,
Hidden_observations_probability)
print(example())
四、基于维特比算法进行解码
维特比算法
与穷举法不同,维特比算法是基于动态规划思想的隐马尔科夫模型解法。动态规划原理提到,假设存在一条最优路径,那么将该路径切分成N段,那么这N段小路径都分别是该环境下的最优路径,否则就存在着其他未知小路径,能组成一个比最优路径还更好的路径,这显然不成立。
基于上述原理,我们只需要从时刻t=1开始,递归的计算子安时刻t状态为i的各条部分路径的最大概率,直至得到时刻t=T的状态为i的各条路径的最大概率,便可以得到最优路径。
代码
假设连续观察3天的海藻湿度为(Dry,Damp,Soggy),求这三天最可能的天气情况。
#-*- coding:utf-8 -*-
import numpy as np
def viterbi(trainsition_probability,emission_probability,pi,obs_seq):
#转换为矩阵进行计算
trainsition_probability=np.array(trainsition_probability)
emission_probability=np.array(emission_probability)
pi=np.array(pi)
#定义要返回的矩阵
F = np.zeros((Row, Col))
#初始状态
F[:,0]=pi*np.transpose(emission_probability[:,obs_seq[0]])
for t in range(1,Col):
list_max=[]
for n in range(Row):
list_x=list(np.array(F[:,t-1])*np.transpose(trainsition_probability[:,n]))
#获取最大概率
list_p=[]
for i in list_x:
list_p.append(i*10000)
list_max.append(max(list_p)/10000)
F[:, t] = np.array(list_max) * np.transpose(emission_probability[:,obs_seq[t]])
return F
if __name__ == '__main__':
#隐藏状态
invisible=['Sunny','Cloud','Rainy']
#初始状态
pi=[0.63,0.17,0.20]
#转移矩阵
trainsition_probability=[[0.5,0.375,0.125],
[0.25,0.125,0.625],
[0.25,0.375,0.375]]
#发射矩阵
emission_probability=[[0.6,0.2,0.15,0.05],
[0.25,0.25,0.25,0.25],
[0.05,0.10,0.35,0.5]]
#最后显示状态
obs_seq=[0,2,3]
#最后返回一个Row*Col的矩阵结果
Row = np.array(trainsition_probability).shape[0]
Col = len(obs_seq)
F=viterbi(trainsition_probability, emission_probability, pi, obs_seq)
print F
五、词性标注结果
[[ 0.378 0.02835 0.00070875]
[ 0.0425 0.0354375 0.00265781]
[ 0.01 0.0165375 0.01107422]]
每列代表Dry,Damp,Soggy的概率,每行代表Sunny,Cloud,Rainy,所以可以看出最大概率的天气为{Sunny,Cloud,Rainy}。