人工智能|深度学习——使用多层级注意力机制和keras实现问题分类

news2024/11/14 17:54:25

代码下载

使用多层级注意力机制和keras实现问题分类资源-CSDN文库

1 准备工作

1.1 什么是词向量?

”词向量”(词嵌入)是将一类将词的语义映射到向量空间中去的自然语言处理技术。即将一个词用特定的向量来表示,向量之间的距离(例如,任意两个向量之间的L2范式距离或更常用的余弦距离)一定程度上表征了的词之间的语义关系。由这些向量形成的几何空间被称为一个嵌入空间。

传统的独热表示( one-hot representation)仅仅将词符号化,不包含任何语义信息。必须考虑将语义融入到词表示中。

解决办法将原来稀疏的巨大维度压缩嵌入到一个更小维度的空间进行分布式表示。这也是词向量又名词嵌入的缘由了。

例如,“椰子”和“北极熊”是语义上完全不同的词,所以它们的词向量在一个合理的嵌入空间的距离将会非常遥远。但“厨房”和“晚餐”是相关的话,所以它们的词向量之间的距离会相对小。

理想的情况下,在一个良好的嵌入空间里,从“厨房”向量到“晚餐”向量的“路径”向量会精确地捕捉这两个概念之间的语义关系。在这种情况下,“路径”向量表示的是“发生的地点”,所以你会期望“厨房”向量 - “晚餐"向量(两个词向量的差异)捕捉到“发生的地点”这样的语义关系。基本上,我们应该有向量等式:晚餐 + 发生的地点 = 厨房(至少接近)。如果真的是这样的话,那么我们可以使用这样的关系向量来回答某些问题。例如,应用这种语义关系到一个新的向量,比如“工作”,我们应该得到一个有意义的等式,工作+ 发生的地点 = 办公室,来回答“工作发生在哪里?”。

词向量通过降维技术表征文本数据集中的词的共现信息。方法包括神经网络(“Word2vec”技术),或矩阵分解。

1.2 获取词向量

词向量 对与中文自然语言处理任务 是基石,一般情况下 有两种获取方式:

  • 别人训练好的百科数据。优势:包含词语多,符合日常用语的语义;劣势:专有名词不足,占用空间大;
  • 自己训练。优势:专有名词,针对具体任务语义更准确; 劣势:泛化性差。

步骤:

graph LR
文本-->分词
分词-->训练词向量
训练词向量-->保存词向量

具体代码:

import gensim

## 训练自己的词向量,并保存。
def trainWord2Vec(filePath):
    sentences =  gensim.models.word2vec.LineSentence(filePath) # 读取分词后的 文本
    model = gensim.models.Word2Vec(sentences, size=100, window=5, min_count=1, workers=4) # 训练模型

    model.save('./CarComment_vord2vec_100')


def testMyWord2Vec():
    # 读取自己的词向量,并简单测试一下 效果。
    inp = './CarComment_vord2vec_100'  # 读取词向量
    model = gensim.models.Word2Vec.load(inp)

    print('空间的词向量(100维):',model['空间'])
    print('打印与空间最相近的5个词语:',model.most_similar('空间', topn=5))


if __name__ == '__main__':
    #trainWord2Vec('./CarCommentAll_cut.csv')
    testMyWord2Vec()
    pass

这样我们就 拥有了 预训练的 词向量文件CarComment_vord2vec_100 。

下一单元 继续讲解如何在keras中使用它。

2 转化词向量为keras所需格式

上一步拿到了所有词语的词向量,但还需转化词向量为keras所需格式。众所周知,keras中使用预训练的词向量的层是Embedding层,而Embedding层中所需要的格式为 一个巨大的“矩阵”:第i列表示词索引为i的词的词向量

所以,本单元的总体思路就是给 Embedding 层提供一个 [ word : word_vector] 的词典来初始化Embedding层中所需要的大矩阵 ,并且标记为不可训练。

2.1 获取所有词语word和词向量

首先要导入 预训练的词向量。

## 1 导入 预训练的词向量
myPath = './CarComment_vord2vec_100' # 本地词向量的地址
Word2VecModel = gensim.models.Word2Vec.load(myPath) # 读取词向量

vector = Word2VecModel.wv['空间']  # 词语的向量,是numpy格式
gensim的word2vec模型 把所有的单词和 词向量 都存储在了Word2VecModel.wv里面,讲道理直接使用这个.wv即可。 但是我们打印这个东西的 类型

print(type(Word2VecModel.wv)) # 结果为:Word2VecKeyedVectors

for i,j in Word2VecModel.wv.vocab.items():
    print(i) # 此时 i 代表每个单词
    print(j) # j 代表封装了 词频 等信息的 gensim“Vocab”对象,例子:Vocab(count:1481, index:38, sample_int:3701260191)
    break

发现它是 gensim自己封装的一种数据类型:Word2VecKeyedVectors

<class 'gensim.models.keyedvectors.Word2VecKeyedVectors'>

不能使用for循环迭代取单词。

2.2 构造“词语-词向量”字典

第二步 构造数据:

  • 构造 一个list存储所有单词:vocab_list 存储所有词语。
  • 构造一个字典word_index :{word : index} ,key是每个词语,value是单词在字典中的序号。 在后期 tokenize(序号化) 训练集的时候就是用该词典。 构造包含
  • 构造一个 大向量矩阵embeddings_matrix (按照embedding层的要求):行数 为 所有单词数,比如 10000;列数为 词向量维度,比如100。

代码:

## 2 构造包含所有词语的 list,以及初始化 “词语-序号”字典 和 “词向量”矩阵
vocab_list = [word for word, Vocab in Word2VecModel.wv.vocab.items()]# 存储 所有的 词语

word_index = {" ": 0}# 初始化 `[word : token]` ,后期 tokenize 语料库就是用该词典。
word_vector = {} # 初始化`[word : vector]`字典

# 初始化存储所有向量的大矩阵,留意其中多一位(首行),词向量全为 0,用于 padding补零。
# 行数 为 所有单词数+1 比如 10000+1 ; 列数为 词向量“维度”比如100。
embeddings_matrix = np.zeros((len(vocab_list) + 1, Word2VecModel.vector_size))

2.3 填充字典和矩阵

第三步:填充 上述步骤中 的字典 和 大矩阵

## 3 填充 上述 的字典 和 大矩阵
for i in range(len(vocab_list)):
    # print(i)
    word = vocab_list[i]  # 每个词语
    word_index[word] = i + 1 # 词语:序号
    word_vector[word] = Word2VecModel.wv[word] # 词语:词向量
    embeddings_matrix[i + 1] = Word2VecModel.wv[word]  # 词向量矩阵

2.4 在 keras的Embedding层中使用 预训练词向量

from keras.layers import Embedding

EMBEDDING_DIM = 100 #词向量维度

embedding_layer = Embedding(input_dim = len(embeddings_matrix), # 字典长度
                            EMBEDDING_DIM, # 词向量 长度(100)
                            weights=[embeddings_matrix], # 重点:预训练的词向量系数
                            input_length=MAX_SEQUENCE_LENGTH, # 每句话的 最大长度(必须padding) 
                            trainable=False # 是否在 训练的过程中 更新词向量
                           
                            )
  • Embedding层的输入shape

此时 输入Embedding层的数据的维度是 形如(samples,sequence_length)的2D张量,注意,此时句子中的词语word已经被转化为 index(依靠word_index,所以在 embedding层之前 往往结合 input层, 用于将 文本 分词 转化为数字形式)

  • Embedding层的输出shape

Embedding层把 所有输入的序列中的整数,替换为对应的词向量矩阵中对应的向量(也就是它的词向量),比如一句话[1,2,8]将被序列[词向量第[1]行,词向量第[2]行,词向量第[8]行]代替。

这样,输入一个2D张量后,我们可以得到一个3D张量:(samples, sequence_length, embeddings_matrix)

*2.5 不使用“预训练”而直接生成词向量

我们也可以直接使用Keras自带的Embedding层训练词向量,而不用预训练的word2vec词向量。代码如下所示:

embedding_layer = Embedding(len(word_index) + 1, # 由于 没有预训练,设置+1 
                            EMBEDDING_DIM, # 设置词向量的维度
                            input_length=MAX_SEQUENCE_LENGTH) #设置句子的最大长度

可以看出在使用 Keras的中Embedding层时候,不指定参数weights=[embeddings_matrix] 即可自动生成词向量。

先是随机初始化,然后,在训练数据的过程中训练。

在参考文献1中 做的对比实验,对于新闻文本分类任务:直接使用Keras自带的Embedding层训练词向量而不用预训练的word2vec词向量,得到0.9的准确率。

使用预训练的word2vec词向量,同样的模型最后可以达到0.95的分类准确率。

所以使用预训练的词向量作为特征是非常有效的。一般来说,在自然语言处理任务中,当样本数量非常少时,使用预训练的词向量是可行的(实际上,预训练的词向量引入了外部语义信息,往往对模型很有帮助)。

3 整体代码:在Keras模型中使用预训练的词向量

文本数据预处理,将每个文本样本转换为一个数字矩阵,矩阵的每一行表示一个词向量。下图梳理了处理文本数据的一般步骤。 

3.1 读取数据

def load_file():
    dataFrame_2016 = pd.read_csv('data\\nlpcc2016_kbqa_traindata_zong_right.csv',encoding='utf-8')
    print(dataFrame_2016.columns) # 打印列的名称

    texts = []   # 存储读取的 x
    labels = []  # 存储读取的y
    # 遍历 获取数据
    for i in range(len(dataFrame_2016)):
        texts.append(dataFrame_2016.iloc[i].q_text) # 每个元素为一句话“《机械设计基础》这本书的作者是谁?”
        labels.append(dataFrame_2016.iloc[i].q_type) # 每个元素为一个int 代表类别 # [2, 6, ... 3] 的形式

    ## 把类别从int 3 转换为(0,0,0,1,0,0)的形式
    labels = to_categorical(np.asarray(labels)) # keras的处理方法,一定要学会# 此时为[[0. 0. 1. 0. 0. 0. 0.]....] 的形式
    return texts, labels # 总文本,总标签

3.2 句子分词

## 2. cut_sentence2word 句子分词
def cut_sentence2word(texts):
    texts = [jieba.lcut(Sentence.replace('\n', '')) for Sentence in texts] # 句子分词
    return texts

3.3 *构造词向量字典

## 3.获取word2vec模型, 并构造,词语index字典,词向量字典
def get_word2vec_dictionaries(texts):
    def get_word2vec_model(texts=None): # 获取 预训练的词向量 模型,如果没有就重新训练一个。
        if os.path.exists('data_word2vec/Word2vec_model_embedding_25'): # 如果训练好了 就加载一下不用反复训练
            model = Word2Vec.load('data_word2vec/Word2vec_model_embedding_25')
            # print(model['作者'])
            return model
        else:
            model = Word2Vec(texts, size = EMBEDDING_LEN, window=7, min_count=10, workers=4)
            model.save('data_word2vec/Word2vec_model_embedding_25') # 保存模型
            return model

    Word2VecModel = get_word2vec_model(texts) #  获取 预训练的词向量 模型,如果没有就重新训练一个。

    vocab_list = [word for word, Vocab in Word2VecModel.wv.vocab.items()]  # 存储 所有的 词语


    word_index = {" ": 0}# 初始化 `[word : token]` ,后期 tokenize 语料库就是用该词典。
    word_vector = {} # 初始化`[word : vector]`字典

    # 初始化存储所有向量的大矩阵,留意其中多一位(首行),词向量全为 0,用于 padding补零。
    # 行数 为 所有单词数+1 比如 10000+1 ; 列数为 词向量“维度”比如100。
    embeddings_matrix = np.zeros((len(vocab_list) + 1, Word2VecModel.vector_size))

    ## 填充 上述 的字典 和 大矩阵
    for i in range(len(vocab_list)):
        word = vocab_list[i]  # 每个词语
        word_index[word] = i + 1  # 词语:序号
        word_vector[word] = Word2VecModel.wv[word] # 词语:词向量
        embeddings_matrix[i + 1] = Word2VecModel.wv[word]  # 词向量矩阵

    return word_index, word_vector, embeddings_matrix

3.4 文本序号化Tokenizer

在上文中已经得到了每条文本的文字了,但是text-CNN等深度学习模型的输入应该是数字矩阵。可以使用Keras的Tokenizer模块实现转换。

简单讲解Tokenizer如何实现转换。当我们创建了一个Tokenizer对象后,使用该对象的fit_on_texts()函数,可以将输入的文本中的每个词编号,编号是根据词频的,词频越大,编号越小。可能这时会有疑问:Tokenizer是如何判断文本的一个词呢?其实它是以空格去识别每个词。因为英文的词与词之间是以空格分隔,所以我们可以直接将文本作为函数的参数,但是当我们处理中文文本时,我们需要使用分词工具将词与词分开,并且词间使用空格分开。具体实现如下:

当然 ,也可以使用之前构建的word_index字典,手动 构建文本tokenizer句子:(推荐这种方法,这样序号下标与预训练词向量一致。)

# 序号化 文本,tokenizer句子,并返回每个句子所对应的词语索引
def tokenizer(texts, word_index):

    data = []
    for sentence in texts:
        new_txt = []
        for word in sentence:
            try:
                new_txt.append(word_index[word])  # 把句子中的 词语转化为index
            except:
                new_txt.append(0)
            
        data.append(new_txt)

    texts = sequence.pad_sequences(data, maxlen = MAX_SEQUENCE_LENGTH)  # 使用kears的内置函数padding对齐句子,好处是输出numpy数组,不用自己转化了
    return texts

3.5 切分数据

## 5.切分数据
def split_data(texts, labels):
    x_train, x_test, y_train, y_test = train_test_split(texts, labels, test_size=0.2)
    return x_train, x_test, y_train, y_test

3.6 使用Embedding层将每个词编码转换为词向量

通过以上操作,已经将每个句子变成一个向量,但上文已经提及text-CNN的输入是一个数字矩阵,即每个影评样本应该是以一个矩阵,每一行代表一个词,因此,需要将词编码转换成词向量。使用Keras的Embedding层可以实现转换。

需要声明一点的是Embedding层是作为模型的第一层,在训练模型的同时,得到该语料库的词向量。当然,也可以使用已经预训练好的词向量表示现有语料库中的词。

embedding_layer = Embedding(input_dim=len(embeddings_matrix),  # 字典长度
                                output_dim = EMBEDDING_LEN,  # 词向量 长度(25)
                                weights=[embeddings_matrix],  # 重点:预训练的词向量系数
                                input_length=MAX_SEQUENCE_LENGTH,  # 每句话的 最大长度(必须padding) 10
                                trainable=False,  # 是否在 训练的过程中 更新词向量
                                name= 'embedding_layer'
                                )

然后利用 keras的建模能力,把Embedding层嵌入到 模型中去即可。后面可以接CNN或者LSTM

参考文献

参考《Keras的中Embedding层 官方文档》: 嵌入层 Embedding - Keras中文文档

参考1 官方文档《在Keras模型中使用预训练的词向量》:在Keras模型中使用预训练的词向量 - Keras中文文档

参考2 :《Keras 模型中使用预训练的 gensim 词向量(word2vec) 和可视化》 Keras 模型中使用预训练的 gensim 词向量和可视化 | Eliyar's Blog

参考3《Embedding原理和Tensorflow-tf.nn.embedding_lookup()》:Embedding原理和Tensorflow-tf.nn.embedding_lookup()_embedding必须通过nn.lookup-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【buuctf--九连环】

这题主要是记录一下新的隐写工具 steghide 用binwalk 看一下 jpg 图片,还是有不少东西&#xff0c;那么-e 提取一下实际上通过binwalk 提取就避免了伪加密的问题&#xff0c;详见BUUCTF-九连环_九连环 buuctf-CSDN博客 其中 qwe.zip为真加密&#xff0c;需要找出密码&#xff…

计算机设计大赛 深度学习+opencv+python实现车道线检测 - 自动驾驶

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV56 数据集处理7 模型训练8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &am…

龙芯安装Nodejs

由于龙芯3A5000/6000使用的是LoongArch指令集&#xff0c;然而Nodejs只支持X64和ARM指令集&#xff0c;无法使用常规的安装方法&#xff0c;虽然官方提供了源码&#xff0c;能在电脑上自行编译执行&#xff0c;但本人尝试后显示编译失败&#xff0c;在网络上查找解决方法得知还…

RBAC权限控制实现方案

上一文章讲述了利用RBAC实现访问控制的思路&#xff08;RBAC实现思路&#xff09;&#xff0c;本文主要详细讲解利用vuex实现RBAC权限控制。 一、准备工作 从后台获取到权限对照表&#xff0c;如下&#xff1a; 1、添加/编辑楼宇 park:building:add_edit 2、楼宇管理 pa…

MySQL数据引擎、建库及账号管理

目录 一、MySQL数据库引擎 1.1.MySQL常见数据库引擎 1.InnoDB(MySQL默认引擎) 2.MyISAM 3.MEMORY&#xff08;Heap&#xff09; 1.2.存储引擎查看 二、建库 1.默认数据库介绍 2.建库 3.查看数据库 4.删除数据库 三、账号管理 1.创建用户 1.创建用户并设置登陆密码…

【电路笔记】-互感

互感 文章目录 互感1、概述2、互感3、耦合系数4、互感示例15、互感示例2 互感是一个线圈磁场与另一个线圈的相互作用&#xff0c;因为它在相邻线圈中感应出电压。 1、概述 互感是两个磁耦合线圈之间的电路参数&#xff0c;定义了一个线圈产生的时变磁通量被感应到相邻的第二个…

python coding with ChatGPT 打卡第17天| 二叉树:找树左下角的值、路径总和

相关推荐 python coding with ChatGPT 打卡第12天| 二叉树&#xff1a;理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 python coding with ChatGPT 打卡第15天| 二叉树&#xff1a;翻转…

Cpp-2

类与对象 /*类与对象&#xff1a;1.类是一种用户自定义的数据类型&#xff08;函数&#xff0c;数据&#xff09;2.类是具有相同的属性和行为的对象的集合3.类是对象的抽象&#xff0c;对象是类的具体4.对象&#xff1a;通过使用类类型定义的变量 */定义类 /*如何定义类&…

LabVIEW汽车自燃监测预警系统

LabVIEW汽车自燃监测预警系统 随着汽车行业的飞速发展&#xff0c;汽车安全问题日益受到公众的关注。其中&#xff0c;汽车自燃现象因其突发性和破坏性&#xff0c;成为一个不可忽视的安全隐患。为了有效预防和减少自燃事故的发生&#xff0c;提出了LabVIEW的汽车自燃监测预警…

ES节点故障的容错方案

ES节点故障的容错方案 1. es启动加载逻辑1.1 segment和translg组成和分析1.2 es节点启动流程1.3 es集群的初始化和启动过程 2. master高可用2.1 选主逻辑2.1.1 过滤选主的节点列表2.1.2 Bully算法2.1.2 类Raft协议2.1.3 元数据合并 2.2 HA切换 3. 分片高可用3.1 集群分片汇报3.…

前端常用代码整理(不断更新中)— js,jquery篇

1.随机函数代码 function getRandom(min, max) {return Math.floor(Math.random() * (max - min 1)) min}2.倒计时代码 let now new Date()// 2. 得到指定时间的时间戳let last new Date(这里写想要达到的时间)// 3. &#xff08;计算剩余的毫秒数&#xff09; / 1000 剩余…

ChinaXiv:中科院科技论文预发布平台

文章目录 Main彩蛋 Main 主页&#xff1a;https://chinaxiv.org/home.htm 彩蛋

11.0 Zookeeper watcher 事件机制原理剖析

zookeeper 的 watcher 机制&#xff0c;可以分为四个过程&#xff1a; 客户端注册 watcher。服务端处理 watcher。服务端触发 watcher 事件。客户端回调 watcher。 其中客户端注册 watcher 有三种方式&#xff0c;调用客户端 API 可以分别通过 getData、exists、getChildren …

vue3 使用defineAsyncComponent 动态加载组件

问题场景 在项目中使用静态加载组件基本能覆盖80%的场景了&#xff0c;如下图 但是我们在需要 循环生成一些的component 的时候或者在 开发ssr服务端渲染的页面 就会遇到有些组件以静态方式导入就会报错&#xff0c;导致进程失败&#xff0c;那么这时候就需要用到动态组件。那…

智能运维适合哪些行业?智能运维需要哪些设备?

构建一个智能运维系统所必须的设备和工具包括&#xff1a; 硬件设备&#xff1a; 服务器&#xff1a;用于部署智能运维平台和存储数据。 网络设备&#xff1a;包括路由器、交换机等&#xff0c;用于连接各种设备和系统。 存储设备&#xff1a;如硬盘、SSD等&am…

时序预测 | Matlab实现基于LSTM长短期记忆神经网络的电力负荷预测模型

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 时序预测 | Matlab实现基于LSTM长短期记忆神经网络的电力负荷预测模型 LSTM(长短期记忆)是一种递归神经网络(RNN)的变体,它在序列数据建模方面表现出色。电力负荷预测是一项重要的任务,可以利用LSTM神经网络…

Adb显示第3方应用的包名原理

Android早期版本实现原理请看 Android源码分析-pm命令的实现&#xff0c;列出包名pm list package&#xff0c;列出系统库pm list libraries_pm list packages-CSDN博客 Android12 对adb shell pm 实现原理做了重构&#xff1a;改成了template模式PackageManagerShellCommand …

如何在 Java 中通过 Map.Entry 访问 Map 的元素

我们使用 Map.Entry 来遍历 ConcurrentHashMap 的代码片段如下&#xff1a; for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("Key: " entry.getKey() ", Value: " entry.getValue()); } 在 Map.java 中&…

Java20:新特性

一&#xff1a;Lambda表达式&#xff1a; 1. Lambda表达式使用前后对比&#xff1a; 举类一&#xff1a; Testpublic void test(){ Runnable r1 new Runnable() {Overridepublic void run() {System.out.println("我爱北京天安门&#xff01;");} };r1.run();Syst…

华为机考入门python3--(11)牛客11-数字颠倒

分类&#xff1a;字符串 知识点&#xff1a; int转字符串 str int(num) 对字符串进行逆序 my_str str[::-1] 题目来自【牛客】 def reverse_integer(n): # 将整数转换为字符串 str_n str(n) # 使用[::-1]来反转字符串 reversed_str str_n[::-1] return reversed…