自然语言处理: 第三章NPLM(Neural Probabilistic Language Mode)

理论基础

NPLM的全称是"Neural Probabilistic Language Model",即神经概率语言模型。这是一种基于神经网络的语言模型,用于生成自然语言文本。最早是由Bengio 在2003年的A Neural Probabilistic Language Model一文中提出来的, NPLM通过学习文本数据的概率分布,能够预测下一个单词或字符的概率,从而生成连贯的语句或段落。这种模型在机器翻译、文本生成和自然语言处理等任务中被广泛应用。



其中NPLM主要由三部分组成:

  • 输入层将单词映射到连续的词向量空间(根据上下文信息可动态调整) , 实际就是又文本的index 转换成为embedding的过程
  • 隐藏层通过非线性激活函数学习单词间的复杂关系,其中隐藏层可以自行调整
  • 输出层通过Softmax层产生下一个单词的概率分布

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WFR9aguy-1687143723638)(image/NPLM/1686883737846.png)]



代码实现

下面是一个构建最简单的NPLM的代码实现,其流程如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nqUr6GTy-1687143723640)(image/NPLM/1686884050025.png)]

  1. 构建语料库,其实就是分词之后利用字典得到对应的index

    class Corpus():
        def __init__(self , sentences) -> None:
            self.sentences = sentences
            # 将所有句子连接在一起,用空格分隔成词汇,再将重复的词去除,构建词汇表
            self.word_list = list(set(" ".join(sentences).split()))  
            # 创建一个字典,将每个词汇映射到一个唯一的索引
            self.word_to_idx = {word: idx for idx, word in enumerate(self.word_list)} 
            # 创建一个字典,将每个索引映射到对应的词汇
            self.idx_to_word = {idx: word for idx, word in enumerate(self.word_list)}  
            self.voc_size = len(self.word_list)  # 计算词汇表的大小
            print('字典:', self.word_to_idx)  # 打印词汇到索引的映射字典
            print('字典大小:', self.voc_size)  # 打印词汇表大小 
    
  2. 生成训练数据 , 这里实现比较简单,每个句子去预测最后一个词,前面的词则都作为content

    class Corpus():
        def __init__(self , sentences) -> None:
            self.sentences = sentences
            # 将所有句子连接在一起,用空格分隔成词汇,再将重复的词去除,构建词汇表
            self.word_list = list(set(" ".join(sentences).split()))  
            # 创建一个字典,将每个词汇映射到一个唯一的索引
            self.word_to_idx = {word: idx for idx, word in enumerate(self.word_list)} 
            # 创建一个字典,将每个索引映射到对应的词汇
            self.idx_to_word = {idx: word for idx, word in enumerate(self.word_list)}  
            self.voc_size = len(self.word_list)  # 计算词汇表的大小
            print('字典:', self.word_to_idx)  # 打印词汇到索引的映射字典
            print('字典大小:', self.voc_size)  # 打印词汇表大小 
    
    
        def make_batch(self , batch_size = 3):
            input_batch = []  # 定义输入批处理列表
            target_batch = []  # 定义目标批处理列表
            selected_sentences = random.sample(self.sentences, batch_size) # 随机选择句子
            for sen in selected_sentences:  # 遍历每个句子
                word = sen.split()  # 用空格将句子分隔成词汇
                # 将除最后一个词以外的所有词的索引作为输入
                input = [self.word_to_idx[n] for n in word[:-1]]  # 创建输入数据
                # 将最后一个词的索引作为目标
                target = self.word_to_idx[word[-1]]  # 创建目标数据
                input_batch.append(input)  # 将输入添加到输入批处理列表
                target_batch.append(target)  # 将目标添加到目标批处理列表
            input_batch = torch.LongTensor(input_batch) # 将输入数据转换为张量
            target_batch = torch.LongTensor(target_batch) # 将目标数据转换为张量
            return input_batch, target_batch  # 返回输入批处理和目标批处理数据
    
  3. 定义NPLM模型, 这里定义了一个比较简单的隐藏层为N层的LSTM 以及 GRU 网络 , 其中batch_first 设置为true的话,输出的tensor的格式为(batch , seq , feature) 反之则为输出的tensor的格式为(seq, batch , feature) 。 其次, voc_size的意思是词表大小, embedding_size是嵌入层的大小 , n_hidden 代表的是隐藏层的大小 , num_layers 代表的是RNN网络的层数。

    class Lstm(nn.Module):
        def __init__(self , voc_size , embedding_size , n_hidden , num_layers):
            super(Lstm, self).__init__()
            self.embedding = nn.Embedding(voc_size, embedding_size)
            self.lstm = nn.LSTM(embedding_size, n_hidden, num_layers ,  batch_first=True)
            self.linear = nn.Linear(n_hidden, voc_size)
    
        def forward(self, X):
            X = self.embedding(X)
            lstm_out, _ = self.lstm(X)
            output = self.linear(lstm_out[:, -1, :])  # 只选择最后一个时间步的输出作为全连接层的输入
            return output
    
    class Gru(nn.Module):
        def __init__(self , voc_size , embedding_size , n_hidden , num_layers):
            super(Gru, self).__init__()
            self.embedding = nn.Embedding(voc_size, embedding_size)
            self.gru = nn.GRU(embedding_size, n_hidden, num_layers , batch_first=True)
            self.linear = nn.Linear(n_hidden, voc_size)
    
        def forward(self, X):
            X = self.embedding(X)
            lstm_out, _ = self.gru(X)
            output = self.linear(lstm_out[:, -1, :])  # 只选择最后一个时间步的输出作为全连接层的输入
            return output
    
  4. 实例化模型, 这里因为涉及两个隐层模式(lstm 以及gru), 如果需要哪个注释掉就行。

        # model = Lstm( voc_size ,  embedding_size, n_hidden , num_layers) # 创建神经概率语言模型实例
        model = Gru(voc_size ,  embedding_size, n_hidden , num_layers)
        print('RNN模型结构:', model)  # 打印模型的结构
    
  5. 训练

    def train(model , corpus , lr):
        criterion = nn.CrossEntropyLoss() # 定义损失函数为交叉熵损失
        optimizer = optim.Adam(model.parameters(), lr= lr) # 定义优化器为Adam,学习率为0.1
        # 训练模型
        for epoch in range(5000): # 设置训练迭代次数
            optimizer.zero_grad() # 清除优化器的梯度
            input_batch, target_batch = corpus.make_batch() # 创建输入和目标批处理数据
            output = model(input_batch) # 将输入数据传入模型,得到输出结果
            # output的形状为 [batch_size, n_class],target_batch的形状为 [batch_size]
            loss = criterion(output, target_batch) #计算损失值
            if (epoch + 1) % 1000 == 0: # 每1000次迭代,打印损失值
                print(f"Epoch: {epoch + 1:04d} cost = {loss:.6f}") 
            loss.backward() # 反向传播计算梯度
            optimizer.step() # 更新模型参数
    
        return model
    
  6. 做inference

def test(input , corpus , model):
    # 将输入序列转换为对应的索引
    input_indices = [[corpus.word_to_idx[word] for word in seq] for seq in input]  
    input_tensor = torch.LongTensor(input_indices)  # 将输入序列的索引转换为张量
    # 对输入序列进行预测,取输出中概率最大的类别
    predict = model(input_tensor).data.max(1)[1]  
    # 将预测结果的索引转换为对应的词汇
    predict_strs = [corpus.idx_to_word[n.item()] for n in predict.squeeze()]  
    for input_seq, pred in zip(input, predict_strs):
        print(input_seq, '->', pred)  # 打印输入序列和预测结果



结果

整体实验结果如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/32086.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【永久服务器】EUserv

1. 请先自行准备网络(我用的伦敦还可以)、以及visa卡,淘宝可以代付,我总共花了97人民币(10.94欧代付费) 现在只能申请一台,多了会被删除,也就是两欧元,然后选择visa卡 选…

MySQL(六):基本的SELECT语句

基本的SELECT语句 前言一、SELECT...二、SELECT ... FROM三、列的别名四、去除重复行五、空值参与运算六、着重号七、查询常数八、显示表结构九、过滤数据 前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识,有兴趣的小伙伴可以关注博主&#…

AI2:仅凭开源数据,可达ChatGPT 83%表现

夕小瑶科技说 原创 作者 | Python ChatGPT强大的性能让人爱不释手,ChatGPT迟迟不开源让人恨得牙根痒痒。那仅通过开源数据,能够取得怎样的效果呢?近期,AI2的一篇论文显示,最好的65B规模的模型能够达到ChatGPT表现的8…

【MySQL事务】保证数据完整性的利器

1、事务的认识 事务:事务就是将多个SQL给打包在一起,组成一个整体。组成这个整体的各个SQL,要么全部成功,要么全部失败。 举例说明: 情人节到了,滑稽老铁打算给他女朋友小美发给红包,但是他又害…

Spring 是什么?IoC 和 DI的区别

1. Spring 是什么?2. IoC是什么? 2.DI概念说明 1. Spring 是什么? 我们通常讲的Spring指的是Spring Framework(Spring框架),它是一个开源的框架,有着活跃而庞大的社区,这也是它之所谓经久不衰的原因。官方的解读是:Spring官网 翻译过来就是:Spring使Java编程对每…

优维低代码实践:面包屑配置以及菜单配置

优维低代码技术专栏,是一个全新的、技术为主的专栏,由优维技术委员会成员执笔,基于优维7年低代码技术研发及运维成果,主要介绍低代码相关的技术原理及架构逻辑,目的是给广大运维人提供一个技术交流与学习的平台。 优维…

MySQL的版本从5.7跳到了8.0有哪些原因?

MySQL的版本从5.7跳到了8.0的原因? 一、引言1.1、MySQL是什么?1.2、MySQL 5.7和8.0的历史背景 二、MySQL 8.0的新功能2.1、更好的安全性2.2、更高的性能2.3、更好的可扩展性2.4、JSON支持 三、MySQL 8.0的重要改进3.1、更严格的数据类型检查3.2、其他重要…

【CSS3系列】第七章 · 过渡和动画

写在前面 Hello大家好, 我是【麟-小白】,一位软件工程专业的学生,喜好计算机知识。希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正&#xff0…

群晖nas(DS423+)和百度云盘互相自动备份

群晖nas提供了云同步功能,使用该功能,可以将百度云盘和群晖nas设置成互为备份,这样我们nas上的的重要数据就有多了一层保护。 通过设置,可以将nas上的某个目录同步到百度云盘的一个目录中,同步的方向可以自行定义&…

五、浅析[ElasticSearch]底层原理与分组聚合查询

目录 一、ElasticSearch文档分值_score计算底层原理1.boolean model2.relevance score算法2、分析一个document上的_score是如何被计算出来的 二、分词器工作流程1.character filter、tokenizer、token filter2、内置分词器的简单介绍3、定制分词器3.1默认的分词器--standard3.…

Spring 事务的相关配置、传播行为、隔离级别及注解配置声明式事务

目录 一、事务的相关配置 1. 添加测试标签 2. 添加对应方法 3. 测试 二、事务的传播行为 三、事务的隔离级别 四、注解配置声明式事务 1. 注册事务注解驱动 2. 加上注解 3. 配置类代替xml文件中的注解事务支持 4. 测试 往期专栏&文章相关导读 1. Maven系列专栏…

【三维编辑】Editing Conditional Radiance Fields 编辑条件辐射场

Editing Conditional Radiance Fields(ICCV 2021) 作者单位:Steven Liu, Xiuming Zhang, Zhoutong Zhang, Richard Zhang MIT, Adobe Research, CMU 代码地址:https://github.com/stevliu/editnerf 文章目录 摘要前言一、相关工作…

23. 数据结构之位图

前言 之前在讲散列表的时候,提到过位图的概念。位图(Bitmap)作为一种特殊的数据结构,它使用一系列位来表示数据,每个位只有两个状态(0或1)。由于它的高效性和节省空间的特性,位图在…

MySQL事务相关笔记

杂项 InnoDB最大特点:支持事务和行锁; MyISAM不支持事务 介绍 一个事务是由一条或者多条对数据库操作的SQL语句所组成的一个不可分割的单元,只有当事务中的所有操作都正常执行完了,整个事务才会被提交给数据库。事务有如下特性…

使用传统图像处理算法+机器学习进行shadow detection

前言 阴影是图像中常见的现象,它们对于场景理解和分析非常重要。由于阴影区域通常比较暗淡,而且与周围物体区别较大,因此在图像处理和计算机视觉领域中,阴影检测是一个重要的研究方向。传统的阴影检测算法通常基于阈值或边缘检测…

SVM算法的介绍

一、SVM算法的介绍 1.什么是SVM算法? SVM(Support Vector Machine)是一种常见的监督学习算法,用于进行二分类或多分类任务。它的主要思想是找到一个最优的超平面,将不同类别的样本分隔开。 超平面最大间隔介绍&#…

人体姿态估计技术的理解(Human Pose Estimination)

本人毕设题目是人体姿态估计技术的相关课题,本人按照自己对人体姿态估计技术的学习和理解进行论述,如有不足,请大家指正!!! 首先讨论一个问题:什么是姿态估计? “姿势估计?……姿势这个词对…

opencv如何使用GPU的三种方法

我在工作实验涉及到图像和视频处理时,通常使用opencv提供的库来做处理,虽然OpenCV是一个广泛使用的库,它提供了丰富的功能和工具。然而,有时候在处理大量图片或视频时,我们可能会面临速度受限的问题。 opencv执行图像…

【C/C++】之内存管理(超详细练气篇)

个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C之路】💌 本专栏旨在记录C的学习路线,望对大家有所帮助🙇‍ 希望我们一起努力、成长&…

基本 SQL 命令 、重要的 SQL命令、SQL 约束 及 SQL语句 的 执行顺序

学习目标: 学习目标如下: SQL语句执行顺序 学习内容: 基本 SQL 命令: FROMONJOINWHEREGROUP BYAGG_FUNCWITHHAVINGSELECT 从数据库中提取数据UNIONDISTINCTORDER BY 排序LIMIT 重要的sql命令: 1、SELECT - 从数据…