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

代码下载

使用多层级注意力机制和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)) # 结果为:Word2VecKeyedVectorsfor 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 EmbeddingEMBEDDING_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 = []   # 存储读取的 xlabels = []  # 存储读取的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 modelelse:model = Word2Vec(texts, size = EMBEDDING_LEN, window=7, min_count=10, workers=4)model.save('data_word2vec/Word2vec_model_embedding_25') # 保存模型return modelWord2VecModel = 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])  # 把句子中的 词语转化为indexexcept: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) 10trainable=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.hqwc.cn/news/457487.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【极数系列】Flink集成KafkaSink 实时输出数据(11)

文章目录 01 引言02 连接器依赖2.1 kafka连接器依赖2.2 base基础依赖 03 使用方法04 序列化器05 指标监控06 项目源码实战6.1 包结构6.2 pom.xml依赖6.3 配置文件6.4 创建sink作业 01 引言 KafkaSink 可将数据流写入一个或多个 Kafka topic 实战源码地址,一键下载可用&#xf…

【语音合成】中文-多情感领域-16k-多发音人

模型介绍 语音合成-中文-多情感领域-16k-多发音人 框架描述 拼接法和参数法是两种Text-To-Speech(TTS)技术路线。近年来参数TTS系统获得了广泛的应用&#xff0c;故此处仅涉及参数法。 参数TTS系统可分为两大模块&#xff1a;前端和后端。 前端包含文本正则、分词、多音字预…

9.0 Zookeeper 节点特性

本章节介绍一下 zookeeper 的节点特性和简单使用场景&#xff0c;正是由于这些节点特性的存在使 zookeeper 开发出不同的场景应用。 1、同一级节点 key 名称是唯一的 实例&#xff1a; $ ls / $ create /runoob 2 已存在 /runoob 节点&#xff0c;再次创建会提示已经存在。 …

【类与对象(中)】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 1.类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 引用 常引用 5.赋值运算符重载 5.1…

【分享】如何运用数字I/O来保护继电器

1.简述 在开关系统中&#xff0c;短路或者是开路的情况下&#xff0c;由于存在着额外的电流或者是电压&#xff0c;继电器往往会过载。所有的继电器都有一个最大的承载电流和热切换功率&#xff0c;如果超出了这个范围&#xff0c;会增加继电器焊接在一起的风险&#xff0c;从…

逆向工程:揭开科技神秘面纱的艺术

在当今这个科技飞速发展的时代&#xff0c;我们每天都在与各种电子产品、软件应用打交道。然而&#xff0c;你是否想过&#xff0c;这些看似复杂的高科技产品是如何被创造出来的&#xff1f;今天&#xff0c;我们就来探讨一下逆向工程这一神秘而又令人着迷的领域。 一、什么是…

2月6日作业

1.现有无序序列数组为23,24,12,5,33,5347&#xff0c;请使用以下排序实现编程 函数1:请使用冒泡排序实现升序排序 函数2:请使用简单选择排序实现升序排序 函数3:请使用快速排序实现升序排序 函数4:请使用插入排序实现升序排序 #include<stdio.h> #include<string.h&…

好看的安全跳转单页html源码

好看的安全跳转单页html源码,效果如下 代码如下&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <!--[if IE 8]><style>.ie8 .alert-circle,.ie8 .alert-footer{display:none}.ie8 .alert-box{padding-top:…

OpenCV-31 获得形态学卷积核

OpenCV提供了获取卷积核的API&#xff0c;不需要我们手动创建卷积核。 通过下面API---getStructuringElement(shape&#xff0c;ksize&#xff0c;[, anchor]) shape是指卷积核的型状&#xff0c;注意不是指长宽&#xff0c;是指卷积核中1形成的形状。MORPH_RECT 卷积核中的1…

AI新工具(20240203) 文心一言APP数字分身;HuggingChat Assistants等

文心一言APP数字分身-一键生成专属数字分身 文心一言数字分身是一项新功能&#xff0c;用户只需一张照片和录制三句语音&#xff0c;就能创建一个专属的数字分身。这个数字分身还支持个性化定义名称、声音、MBTI性格等&#xff0c;用户可以选择是否公开自己的数字分身。这个功…

飞天使-k8s知识点16-kubernetes实操1-pod

文章目录 深入Pod 创建Pod&#xff1a;配置文件详解写个pod的yaml 文件深入Pod 探针&#xff1a;探针技术详解 深入Pod 创建Pod&#xff1a;配置文件详解 资源清单参考链接&#xff1a;https://juejin.cn/post/6844904078909128712写个pod的yaml 文件 apiVersion: v1 kind: P…

vue3 使用defineAsyncComponent 动态加载组件

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