首页 > 其他分享 >隐马尔可夫模型(Hidden Markov Model,HMM)—有监督学习方法、概率模型、生成模型

隐马尔可夫模型(Hidden Markov Model,HMM)—有监督学习方法、概率模型、生成模型

时间:2024-09-11 18:24:43浏览次数:3  
标签:状态 概率模型 模型 len HMM range line PI sum

定义

隐马尔可夫模型是关于时序的概率模型,描述由一个隐藏的马尔可夫链随机生成不可观测的状态随机序列,再由各个状态生成一个观测从而产生观测随机序列的过程。隐藏的马尔可夫链随机生成的状态的序列,称为状态序列(State Sequence);每个状态生成一个观测,而由此产生的观测的随机序列,称为观测序列(Observation Sequence)。序列的每一位置又可以看作是一个时刻。

基本问题

(1)概率计算问题。给定模型 λ = ( A , B , π ) \lambda=(A,B,\pi) λ=(A,B,π)和观测序列 O = ( o 1 , o 2 , ⋯   , o T ) O=(o_1,o_2,\cdots,o_T) O=(o1​,o2​,⋯,oT​),计算在模型 λ \lambda λ下观测序列 O O O出现的概率 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)。
(2)学习问题。已知观测序列 O = ( o 1 , o 2 , ⋯   , o T ) O=(o_1,o_2,\cdots,o_T) O=(o1​,o2​,⋯,oT​),估计模型 λ = ( A , B , π ) \lambda=(A,B,\pi) λ=(A,B,π)参数,使得在该模型下观测序列概率 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)最大。即用极大似然估计的方法估计参数。
(3)预测问题,也称为解码(decoding)。已知模型 λ = ( A , B , π ) \lambda=(A,B,\pi) λ=(A,B,π)和观测序列 O = ( o 1 , o 2 , ⋯   , o T ) O=(o_1,o_2,\cdots,o_T) O=(o1​,o2​,⋯,oT​),求对给定观测序列条件概率 P ( I ∣ O ) P(I|O) P(I∣O)最大的状态序列 I = ( i 1 , i 2 , ⋯   , i T ) I=(i_1,i_2,\cdots,i_T) I=(i1​,i2​,⋯,iT​)。即给定观测序列,求最有可能的对应的状态序列。

输入空间

O = ( o 1 , o 2 , ⋯   , o T ) O=(o_1,o_2,\cdots,o_T) O=(o1​,o2​,⋯,oT​)

特征空间(Feature Space)

O = ( o 1 , o 2 , ⋯   , o T ) O=(o_1,o_2,\cdots,o_T) O=(o1​,o2​,⋯,oT​)

统计学习方法

模型

I ∗ = f ( λ , O ) I^* = f(\lambda,O) I∗=f(λ,O)

策略

P ∗ = m a x 1 ≤ i ≤ N δ T ( i ) P^* = \mathop{max}\limits_{1\leq i \leq N} \delta_T(i) P∗=1≤i≤Nmax​δT​(i)
i T ∗ = a r g ∗ m a x 1 ≤ i ≤ N [ δ T ( i ) ] i_T^* = arg * \mathop{max}\limits_{1\leq i \leq N} \big[ \delta_T(i) \big] iT∗​=arg∗1≤i≤Nmax​[δT​(i)]

算法

α t + 1 ( i ) = [ ∑ j = 1 N α t ( j ) a j i ] b i ( o t + 1 ) , i = 1 , 2 , ⋯   , N \alpha_{t+1}(i)=\bigg[ \sum_{j=1}^N \alpha_t(j) a_{ji} \bigg]b_i(o_{t+1}),i=1,2,\cdots,N αt+1​(i)=[j=1∑N​αt​(j)aji​]bi​(ot+1​),i=1,2,⋯,N
β t ( i ) = ∑ j = 1 N a i j b j ( o t + 1 ) β t + 1 ( j ) , 1 = 1 , 2 , ⋯   , N \beta_{t}(i)=\sum_{j=1}^Na_{ij}b_j(o_{t+1})\beta_{t+1}(j),1=1,2,\cdots,N βt​(i)=j=1∑N​aij​bj​(ot+1​)βt+1​(j),1=1,2,⋯,N
a i j ( n + 1 ) = ∑ t = 1 T − 1 ζ t ( i , j ) ∑ t = 1 T − 1 γ t ( i ) , 其中 ζ t ( i , j ) = α t ( i ) a i j b j ( o t + 1 ) β t + 1 ( j ) ∑ t = 1 N ∑ j = 1 N α t ( i ) a i j b j ( o t + 1 ) β t + 1 ( j ) , γ t ( i ) = α t ( i ) β t ( i ) ∑ j = 1 N α t ( j ) β t ( j ) a_{ij}^{(n+1)}=\frac{\sum_{t=1}^{T-1}\zeta_t(i,j)}{\sum_{t=1}^{T-1}\gamma_t(i)},其中\zeta_t(i,j)=\frac{\alpha_t(i)a_{ij}b_j(o_{t+1})\beta_{t+1}(j)}{\sum_{t=1}^N\sum_{j=1}^N\alpha_t(i)a_{ij}b_j(o_{t+1})\beta_{t+1}(j)},\gamma_t(i)=\frac{\alpha_t(i)\beta_t(i)}{\sum_{j=1}^N\alpha_t(j)\beta_t(j)} aij(n+1)​=∑t=1T−1​γt​(i)∑t=1T−1​ζt​(i,j)​,其中ζt​(i,j)=∑t=1N​∑j=1N​αt​(i)aij​bj​(ot+1​)βt+1​(j)αt​(i)aij​bj​(ot+1​)βt+1​(j)​,γt​(i)=∑j=1N​αt​(j)βt​(j)αt​(i)βt​(i)​
b j ( k ) ( n + 1 ) = ∑ t = 1 , o t = v k T γ t ( j ) ∑ t = 1 T γ t ( j ) b_j(k)^{(n+1)}=\frac{\sum_{t=1,o_t=v_k}^T\gamma_t(j)}{\sum_{t=1}^T\gamma_t(j)} bj​(k)(n+1)=∑t=1T​γt​(j)∑t=1,ot​=vk​T​γt​(j)​
π i ( n + 1 ) = γ 1 ( i ) \pi_i^{(n+1)} = \gamma_1(i) πi(n+1)​=γ1​(i)

import numpy as np
import time

def trainParameter(fileName):
    '''
    数据集 下载地址:https://download.csdn.net/download/nanxiaotao/89738993
    依据训练文本统计PI、A、B
    :param fileName: 训练文本
    :return: 三个参数
    '''
    #定义一个查询字典,用于映射四种标记在数组中对应的位置,方便查询
    # B:词语的开头
    # M:一个词语的中间词
    # E:一个词语的结果
    # S:非词语,单个词
    statuDict = {'B':0, 'M':1, 'E':2, 'S':3}

    #每个字只有四种状态,所以下方的各类初始化中大小的参数均为4
    #初始化PI的一维数组,因为对应四种状态,大小为4
    PI = np.zeros(4)
    #初始化状态转移矩阵A,涉及到四种状态各自到四种状态的转移,因为大小为4x4
    A = np.zeros((4, 4))
    #初始化观测概率矩阵,分别为四种状态到每个字的发射概率
    #因为是中文分词,使用ord(汉字)即可找到其对应编码,这里用一个65536的空间来保证对于所有的汉字都能
    #找到对应的位置来存储
    B = np.zeros((4, 65536))
    #去读训练文本
    fr = open(fileName, encoding='utf-8')

    #文本中的每一行认为是一个训练样本
    #注:并没有使用Baum-Welch算法,只是借助了其内部的三个参数生成公式,其实
    #公式并不是Baum-Welch特有的,只是在那一节正好有描述
    for line in fr.readlines():
        #对单行句子按空格进行切割
        curLine = line.strip().split()
        #对词性的标记放在该列表中
        wordLabel = []
        #对每一个单词进行遍历
        for i in range(len(curLine)):
            #如果长度为1,则直接将该字标记为S,即单个词
            if len(curLine[i]) == 1:
                label = 'S'
            else:
                #如果长度不为1,开头为B,最后为E,中间添加长度-2个M
                #如果长度刚好为2,长度-2=0也就不添加了,反之添加对应个数的M
                label = 'B' + 'M' * (len(curLine[i]) - 2) + 'E'

            #如果是单行开头第一个字,PI中对应位置加1,
            if i == 0: PI[statuDict[label[0]]] += 1

            #对于该单词中的每一个字,在生成的状态链中统计B
            for j in range(len(label)):
                #遍历状态链中每一个状态,并找到对应的中文汉字,在B中
                #对应位置加1
                B[statuDict[label[j]]][ord(curLine[i][j])] += 1

            #在整行的状态链中添加该单词的状态链
            #注意:extend表直接在原先元素的后方添加,
            wordLabel.extend(label)

        #单行所有单词都结束后,统计A信息
        #因为A涉及到前一个状态,因此需要等整条状态链都生成了才能开始统计
        for i in range(1, len(wordLabel)):
            #统计t时刻状态和t-1时刻状态的所有状态组合的出现次数
            A[statuDict[wordLabel[i - 1]]][statuDict[wordLabel[i]]] += 1

    #对PI求和,概率生成中的分母
    sum = np.sum(PI)
    #遍历PI中每一个元素,元素出现的次数/总次数即为概率
    for i in range(len(PI)):
        if PI[i] == 0:  PI[i] = -3.14e+100
        #如果不为0,则计算概率,再对概率求log
        else: PI[i] = np.log(PI[i] / sum)

    #与上方PI思路一样,求得A的概率对数
    for i in range(len(A)):
        sum = np.sum(A[i])
        for j in range(len(A[i])):
            if A[i][j] == 0: A[i][j] = -3.14e+100
            else: A[i][j] = np.log(A[i][j] / sum)

    #与上方PI思路一样,求得B的概率对数
    for i in range(len(B)):
        sum = np.sum(B[i])
        for j in range(len(B[i])):
            if B[i][j] == 0: B[i][j] = -3.14e+100
            else:B[i][j] = np.log(B[i][j] / sum)

    #返回统计得到的三个参数
    return PI, A, B
#依据现有训练集统计PI、A、B
PI, A, B = trainParameter('HMMTrainSet.txt')
def loadArticle(fileName):
    '''
    下载地址:https://download.csdn.net/download/nanxiaotao/89738993
    加载文章
    :param fileName:文件路径
    :return: 文章内容
    '''
    #初始化文章列表
    artical = []
    #打开文件
    fr = open(fileName, encoding='utf-8')
    #按行读取文件
    for line in fr.readlines():
        #读到的每行最后都有一个\n,使用strip将最后的回车符去掉
        line = line.strip()
        #将该行放入文章列表中
        artical.append(line)
    #将文章返回
    return artical

(1)初始化
δ 1 ( i ) = π i b i ( o 1 ) , i = 1 , 2 , ⋯   , N \delta_1(i) = \pi_ib_i(o_1),i=1,2,\cdots,N δ1​(i)=πi​bi​(o1​),i=1,2,⋯,N
ψ 1 ( i ) = 0 , i = 1 , 2 , ⋯   , N \psi_1(i)=0,i=1,2,\cdots,N ψ1​(i)=0,i=1,2,⋯,N
(2)递推
δ t ( i ) = m a x 1 ≤ i ≤ N [ δ t − 1 ( j ) a ( j i ) ] b i ( o t ) , i = 1 , 2 , ⋯   , N \delta_t(i) = \mathop{max}\limits_{1\leq i \leq N}[\delta_{t-1}(j)a_(ji)]b_i(o_t),i=1,2,\cdots,N δt​(i)=1≤i≤Nmax​[δt−1​(j)a(​ji)]bi​(ot​),i=1,2,⋯,N
ψ t ( i ) = a r g ∗ m a x 1 ≤ i ≤ N [ δ t − 1 ( j ) a j i ] , i = 1 , 2 , ⋯   , N \psi_t(i) = arg * \mathop{max}\limits_{1\leq i \leq N}[\delta_{t-1}(j)a_{ji}],i = 1,2,\cdots,N ψt​(i)=arg∗1≤i≤Nmax​[δt−1​(j)aji​],i=1,2,⋯,N
(3)终止
P ∗ = m a x 1 ≤ i ≤ N δ T ( i ) P^* = \mathop{max}\limits_{1\leq i \leq N} \delta_T(i) P∗=1≤i≤Nmax​δT​(i)
i T ∗ = a r g ∗ m a x 1 ≤ i ≤ N [ δ T ( i ) ] i_T^* = arg * \mathop{max}\limits_{1\leq i \leq N} \big[ \delta_T(i) \big] iT∗​=arg∗1≤i≤Nmax​[δT​(i)]

def participle(artical, PI, A, B):
    '''
    分词”
    :param artical:要分词的文章
    :param PI: 初始状态概率向量PI
    :param A: 状态转移矩阵
    :param B: 观测概率矩阵
    :return: 分词后的文章
    '''
    #初始化分词后的文章列表
    retArtical = []

    #对文章按行读取
    for line in artical:
        #四种概率值,因此长度时该行的长度
        delta = [[0 for i in range(4)] for i in range(len(line))]
        for i in range(4):
            #初始化δ状态链中第一个状态的四种状态概率
            delta[0][i] = PI[i] + B[i][ord(line[0])]
        #初始化ψ,初始时为0
        psi = [[0 for i in range(4)] for i in range(len(line))]

        #依次处理整条链
        for t in range(1, len(line)):
            #对于链中的米格状态,求四种状态概率
            for i in range(4):
                #初始化一个临时列表,用于存放四种概率
                tmpDelta = [0] * 4
                for j in range(4):
                    tmpDelta[j] = delta[t - 1][j] + A[j][i]

                #找到最大的那个δ * a,
                maxDelta = max(tmpDelta)
                #记录最大值对应的状态
                maxDeltaIndex = tmpDelta.index(maxDelta)

                #将找到的最大值乘以b放入,
                #注意:这里同样因为log变成了加法
                delta[t][i] = maxDelta + B[i][ord(line[t])]
                #在ψ中记录对应的最大状态索引
                psi[t][i] = maxDeltaIndex

        #建立一个状态链列表,开始生成状态链
        sequence = []
        #在上面for循环全部结束后,很明显就到了第三步了
        #获取最后一个状态的最大状态概率对应的索引
        i_opt = delta[len(line) - 1].index(max(delta[len(line) - 1]))
        #在状态链中添加索引
        #注:状态链应该是B、M、E、S,这里图方便用了0、1、2、3,其实一样的
        sequence.append(i_opt)
        #算法10.5 第四步:最优路径回溯
        #从后往前遍历整条链
        for t in range(len(line) - 1, 0, -1):
            #不断地从当前时刻t的ψ列表中读取到t-1的最优状态
            i_opt = psi[t][i_opt]
            #将状态放入列表中
            sequence.append(i_opt)
        #因为是从后往前将状态放入的列表,所以这里需要翻转一下,变成了从前往后
        sequence.reverse()

        #开始对该行分词
        curLine = ''
        #遍历该行每一个字
        for i in range(len(line)):
            #在列表中放入该字
            curLine += line[i]
            #如果该字是3:S->单个词  或  2:E->结尾词 ,则在该字后面加上分隔符 |
            #此外如果改行的最后一个字了,也就不需要加 |
            if (sequence[i] == 3 or sequence[i] == 2) and i != (len(line) - 1):
                curLine += '|'
        #在返回列表中添加分词后的该行
        retArtical.append(curLine)
    #返回分词后的文章
    return retArtical
#读取测试文章
artical = loadArticle('testArtical.txt')

#打印原文
print('-------------------原文----------------------')
for line in artical:
    print(line)

#进行分词
partiArtical = participle(artical, PI, A, B)

#打印分词结果
print('-------------------分词后----------------------')
for line in partiArtical:
    print(line)

假设空间(Hypothesis Space)

{ f ∣ f ( x ) = ( i 1 ∗ , i 2 ∗ , ⋯   , i T ∗ ) } \left\{f|f(x) = (i_1^*,i_2^*,\cdots,i_T^*) \right\} {f∣f(x)=(i1∗​,i2∗​,⋯,iT∗​)}

输出空间

( i 1 ∗ , i 2 ∗ , ⋯   , i T ∗ ) (i_1^*,i_2^*,\cdots,i_T^*) (i1∗​,i2∗​,⋯,iT∗​)

标签:状态,概率模型,模型,len,HMM,range,line,PI,sum
From: https://blog.csdn.net/nanxiaotao/article/details/142145961

相关文章

  • 关于RTX 4090 微调llama2模型时出现nvcc fatal : Unsupported gpu architecture 'comp
    RTX4090是现在普通人可以轻松获取的最好的显卡了。运算速度仅次于专业图形卡TeslaA100,A800,H100RTX4090显卡是可以单卡推理llama27b和13b模型的,7b模型占用缓存14G左右,13b模型单卡推理显存占用在23G多点(只是运行一段时间容易爆显存),所以普通人都是可以使用llama2大语言模型。......
  • 嵌套集合模型(Nested set model)介绍
    嵌套集合模型(Nestedsetmodel)介绍pilishen /更新于5年前本文翻译自维基百科Nestedsetmodel 此文档是 nestedset-无限分类正确姿势的扩展阅读 nestedsetmodel(嵌套集合模型)是一种在关系型数据库中表示nestedsets(嵌套集合) 的特殊技术。[nestedsets]通常......
  • YOLOv9改进策略【Neck】| AIFI : 基于Transformer的尺度内特征交互,在降低计算成本的同
    一、本文介绍本文记录的是基于AIFI模块的YOLOv9目标检测改进方法研究。AIFI是RT-DETR中高效混合编码器的一部分,利用其改进YOLOv9模型,使网络在深层能够更好的捕捉到概念实体之间的联系,并有助于后续模块对对象进行定位和识别。文章目录一、本文介绍二、AIFI设计原理2.1、......
  • 基于深度学习的骨龄检测识别系统(PyTorch+Pyside6+YOLOv5模型)
    骨龄是骨骼年龄的简称,需要借助于骨骼在X光摄像中的特定图像来确定。通常要拍摄左手手腕部位的X光片,医生通过X光片观察来确定骨龄。在2006年,《中华-05》骨龄标准被编入《中华人民共和国行业标准》,成为中国目前唯一的行业骨龄标准。而在《中华-05》中作者一般推荐使用RUS-CHN计......
  • 实战千问2大模型第三天——Qwen2-VL-7B(多模态)视频检测和批处理代码测试
    画面描述:这个视频中,一位穿着蓝色西装的女性站在室内,背景中可以看到一些装饰品和植物。她双手交叉放在身前,面带微笑,似乎在进行一场演讲或主持活动。她的服装整洁,显得非常专业和自信。一、简介阿里通义千问开源新一代视觉语言模型Qwen2-VL。其中,Qwen2-VL-72B在大部分指标上都......
  • 百度飞桨、千帆大模型以及Coze的简单比较:入门级
    百度飞桨、千帆大模型以及Coze在AI领域各有其独特之处,它们分别代表了不同方面的技术能力和应用场景。以下是对这三者的简单清晰扼要的解说:百度飞桨(PaddlePaddle)定义与特点:定义:飞桨是百度开源的、集深度学习核心框架、基础模型库、端到端开发套件、工具组件和服务平台于一体的......
  • Attention Sinks 入门指南 - 实现无限长度文本生成的高效流式语言模型
    AttentionSinks简介AttentionSinks是一种新的注意力机制,可以让预训练语言模型生成无限长度的连贯文本,同时保持恒定的内存使用。它通过保留初始token的注意力信息(称为"注意力池"),并使用滑动窗口来处理最近的token,从而实现了高效的长文本生成。AttentionSinks......
  • Awesome-LM-SSP学习资料大全 - 大型语言模型安全、隐私与保障资源汇总
    Awesome-LM-SSP学习资料大全-大型语言模型安全、隐私与保障资源汇总Awesome-LM-SSP是一个致力于收集大型语言模型(LLM)安全性、隐私性和可靠性相关资源的开源项目。本文将为大家介绍该项目的主要内容和学习资源,帮助读者快速了解和使用这个宝贵的知识库。项目简介Awesome-......
  • 【大模型理论篇】ToB的大模型系统非常有必要引入搜索推荐算法能力(回顾BPR、W&D、ALS等
    1.背景和思考              上周2024上海外滩大会如约而至,各种大咖云集,多种观点思想碰撞,带来很多新的启发。我个人比较关注大模型和隐私计算相关的内容,因此重点听了相关老师带来的行业前沿进展和深度思考。有两位老师的观点,特别认同,一位是百川智能的王小川......
  • 如何使用huggingface下载数据集和预训练模型
            如果各位在下载huggingface上的模型和数据库也会出现“connectclosed/failed”等错误,不妨试试下面的解决方案,思路大致是,通过设置镜像的方式来解决。下载数据集1.找到你要下载的数据库名称,并复制2.打开终端,并选择需要使用的conda环境,编写bash文件(或者......