700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 深度学习TensorFlow2 循环神经网络(RNN LSTM)系列知识

深度学习TensorFlow2 循环神经网络(RNN LSTM)系列知识

时间:2020-11-06 14:16:37

相关推荐

深度学习TensorFlow2 循环神经网络(RNN LSTM)系列知识

一:概述

二:时间序列

三:RNN

四:LSTM

一:概述

1、什么叫循环?

循环神经网络是一种不同于ResNet,VGG的网络结构,个人理解最大的特点就是:它通过权值共享,极大的减少了权值的参数量。举个例子那ResNet18做个练习往往就可以抛出成千上万的权值w,但在循环神经网络w的值也就那么几个然后每层都用他们这几个,构成了循环。

2 、 循环神经网络主要作用场景?

主要用于语言模型,文本生成,机器翻译。他们的一个特点就是数据是有序列可循的,举个例子:在进行图片识别的识别,你每次都拿到好几张图片,他们直接没啥关系,你先拿到一张狗和你先拿到一张猫并不会对模型产生什么大影响。但语言不一样,你现在读消息是从左往右,古代还有从右往左的那,这就是规定的序列。

ok!在学习循环神经网络前先把一个基础知识补充一下:时间序列

二:时间序列与嵌入层Embedding

1、时间序列:

在上面我们提到了,语言是有顺序的,那么我们如何表达这些顺序那?有的人可能会觉得一句话从左往右,那么这是空间序列啊,emm一定程度上来说,好像也有点道理。但。。不太好比如万一有人从右往左写那?所以我们按照时间序列,我不管你怎么来,反正我先读到的但肯定是头,最后读的是尾。

所以在使用循环神经网络一定要明确,我们是从时间的延展上看待数据

那么我们如何去存储这些句子中的单词那?最先想到的是one_hot,但是我们的数据集至少也有上万的单词,那么表示一个单词可能会有上万个0表不是,造成了一个极大的稀疏矩阵

2、Embedding:

于是深度学习给我们提供了一解决的方法“”嵌入层Embedding,然而当我去了解Embedding的时候发现,官网的解释如下

嵌入层将正整数(下标)转换为具有固定大小的向量

啊?这,,,这都啥啊!什么叫做正整数的下标,怎么还有正数,和向量,不是探讨单词存储吗?

给举个例子,嵌入层实际上就是通过高纬度表示低纬度,这样就可以节省很多空间:举个例子给你一个坐标轴x,单位为1,你在10的空间之中就能表示十个数字,但在给你一个单位1长度10的y轴变成2维度,你就能保存100个,再给你z轴。。。。

实际操作中我们可以对单词进行编号,用一个多位的数组表示他比如same对应的为【15,24,32,45,12】然后我们就可以通过这个坐标去找到它

还一个好处就是:在实际训练中每个嵌入的向量都会得到更新。更新的目的是将由相关性的单词放到一起,在可视化的,我们可以更好的了解词语之间的关系(不仅仅是词语,任何能通过嵌入层 Embedding 转换成向量的内容都可以这样做)

3、Embedding层的常用参数

Embedding(input_dim,output_dim,input_length=None)

input_dim:输入矢量大小,output_dim输出维度大小,input_length:最大输入大小

在进行Embedding之前,我们会对输入的单词进行处理,其原因是Embedding更容易处理大小相同的块,所以会通过:

keras.preprocessing.sequence.pad_sequences(x_train, maxlen=max_review_len)

将数据集中的单词大小设为一致

三:RNN:

1、简介:

RNN是循环神经网络中一经典的算法:我看到一个说RNN的简介:

注意,这个说法很容易误导人,其最大的问题就是RNN他的下层不是常规基本的全连接层,甚至说它出来就是为了解决下层基本全连接层造成的问题,为了更好的理解建议别把它底层和前面的连接层放一起搅拌

我们前面使用的全连接层:都是一个输入一个输出,你对其单层单个权重求导最后得出的是一个独立的信息,举个例子,这就是通过全连接进行的句子分析,你的每个单词都是一个独立的权重w

而这才应该是RNN进行的

核心就是Weight sharing,共享权重

当然:本质这也是全连接层,毕竟每根线都链接吗,但为了理解最好还是注意一下

还一个问题就是解决语义问题,语言不是单词,一段话中两个词语会产生语义,比如你很牛逼,拆分你,很,牛逼:你要是从字典上单个词语去翻译,会变得很奇怪

为了解决这个问题:RNN又引入了一层Consistent memory,其效果就是类似于语义记录,他会记录每个词语,然后下一个词语进来以后会去跟它进行关联产生一个新的语义

h就代表着memory

2、网络结构:

Xt是t时刻的输入,是一个[x0,x1,x2…xn]的向量

U是输入层到隐藏层的权重矩阵

St是t时刻的隐藏层的值

W是上一时刻的隐藏层的值传入到下一时刻的隐藏层时的权重矩阵

V是隐藏层到输出层的权重矩阵

Ot是t时刻RNN网络的输出

3:公式推导与计算:

放了另一章节:

4:实操:RNN解决情感分析练习

首先导入我们所使用的代码模块:

import osos.environ['TF_CPP_MIN_LOG_LEVEL']='2'import tensorflow as tfimport numpy as npfrom tensorflow import kerasfrom tensorflow.keras import layers

进行变量定义:

# 随机数种子,为保证以后的数据一致tf.random.set_seed(22)np.random.seed(22)assert tf.__version__.startswith('2.')batchsz = 128# the most frequest words Embedding最大映射单词数量total_words = 10000#单个句子最大单侧长度max_review_len = 80#embedding_len处理单词长度embedding_len = 100# 获取数据集,单词数量num_words为我们定义的大小(x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=total_words)# x_train:[b, 80] # x_test: [b, 80]# 为了方便embedding,对数据集进行处理x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=max_review_len)x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=max_review_len)#划分训练集与测试集db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))#drop_remainder 这个参数的意思是,我们每次都是取128个basic,那么数据集可能会出现最后不足128的,True代表将其进行丢弃db_train = db_train.shuffle(1000).batch(batchsz, drop_remainder=True)db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))db_test = db_test.batch(batchsz, drop_remainder=True)

定义RNN网络结构:

#继承keras.Modelclass MyRNN(keras.Model):def __init__(self, units):super(MyRNN, self).__init__()# [b, 64] 初始化memory 两层RNN就初始化两个,其维度需要与RNN的输出一致self.state0 = [tf.zeros([batchsz, units]),tf.zeros([batchsz, units])]self.state1 = [tf.zeros([batchsz, units]),tf.zeros([batchsz, units])]# transform text to embedding representation# [b, 80] => [b, 80, 100]self.embedding = layers.Embedding(total_words, embedding_len,input_length=max_review_len)# [b, 80, 100] , h_dim: 64# RNN: cell1 ,cell2, cell3# SimpleRNN RNNCell就是RNN的基本单元,通过其调用cell方法,# 初始化Cell,两个参数分别为state_size与output_size# 前者是隐层的大小,后者是输出的大小。比如我们通常是将一个batch送入模型计算,设输入数据的形状为(batch_size, input_size),# 那么计算时得到的隐层状态就是(batch_size, state_size),输出就是(batch_size, output_size)self.rnn_cell0 = layers.SimpleRNNCell(units, dropout=0.5)self.rnn_cell1 = layers.SimpleRNNCell(units, dropout=0.5)# fc, [b, 80, 100] => [b, 64] => [b, 1]self.outlayer = layers.Dense(1)# 开始一个前向传播def call(self, inputs, training=None):"""net(x) net(x, training=True) :train modenet(x, training=False): test:param inputs: [b, 80]:param training::return:"""# [b, 80] 拿取输入数据x = inputs# embedding: [b, 80] => [b, 80, 100] 进行embedding拿取做标x = self.embedding(x)# rnn cell compute# [b, 80, 100] => [b, 64] 拿取两个初始memory 模型state0 = self.state0state1 = self.state1# 注意现在 b是句子数量,80是单词数量也就等同于的时间轴 100是embedding映射,从时间展开就是从单词展开#通过使用tf.unstack函数进行展开for word in tf.unstack(x, axis=1): # word: [b, 100]# h1 = x*wxh+h0*whh# out0: [b, 64] 这里两个out是一个秩可以去RNNCeLL的源码去翻,发现它返回是两个out,#源码在cell方法中,这也是RNN。LSTM,GUP他们之间区别的体现# 调用两层RNN进行训练out0, state0 = self.rnn_cell0(word, state0, training)# out1: [b, 64]out1, state1 = self.rnn_cell1(out0, state1, training)# out: [b, 64] => [b, 1]x = self.outlayer(out1)# p(y is pos|x)prob = tf.sigmoid(x)return prob

定义main()进行组装配置:

def main():#设置杀输入维度,与训练次数units = 64epochs = 4import timet0 = time.time()# 拿取定义的RNN层model = MyRNN(units)#通过compile进行配置模型pile(optimizer = keras.optimizers.Adam(0.001),loss = tf.losses.BinaryCrossentropy(),metrics=['accuracy'],experimental_run_tf_function=False)#通过fit进行训练与测试model.fit(db_train, epochs=epochs, validation_data=db_test)#进行模型预估model.evaluate(db_test)t1 = time.time()# 64.3 seconds, 83.4%print('total time cost:', t1-t0)

四:LSTM:

1:问题介绍

在建LSTM前我们首先了解一下,RNN存在的问题,其实也是所有模型的绕不开的问题:

梯度弥散与梯度爆炸,

先说梯度爆炸:理论上我们认为RNN是权值共享,只需要少量的w就可以表示出全局的关系,那么最优的计算应该是回比较简单:然而随着我们处理单词的数量过多便会产生一个更大的问题,指数问题===指数是一个非常可怕的:因为它的增长是爆炸式的。

而我们RNN进行梯度求解最后就会出现一个W的k次方的指数,但时间轴过长就会产生一个更大k,从而炸了

解决:有个最简单暴力的,梯度爆炸出现的问题就是,步子太大扯着淡了,面对这种一步登了天,我们就可以给他设置一个最大的阈值,让他一步步走

步长g除以|g|求出结果是向量1,我们使用它的方向,然后比较g与阈值大小,大于阈值我们就让向量去乘以阈值

梯度弥散:这个解决的最好方法就使用LSTM方法

产生的本质是:memery存在的问题,我们希望memery能够记录全部的语境并且随着时间轴的延伸,能够进行动态的扩展,但实际上嘞嘞,RNN中它记录的信息往往就是近的一些语境

2:LSTM模型介绍

介绍LSTM前先介一下RNN的原理模型

从上面可以RNN的模型是两个输入一个x一个C(memery),他们分别*各自的W得的结果在进行结合通过一个tanh激活函数生成h输出与新的C。从中可以看到C并没有什么专门维护

LSTM的模型

从里面内容就可以看到不是级别的,我们拆分来看

挡住中间的部分看主体 :一共输入变成了三个 C,h,与X,两个输出,再看上面的内部

C的那条线是直通,与h相互独立存在:::就是这个核心就在这

绿色的图表示的是一个cell,cell之间的状态记录是C

C在一条链上运行,只有一些少量的线性交互。信息在上面流传保持不变会很容易。

在改变的时候:通过那个圆圈==“门”进行操作 X代表信息过滤 +是信息融合

// 门 可以实现选择性地让信息通过,主要是通过一个 sigmoid 的神经层 和一个逐点相乘的操作来实现的。

sigmoid 层输出(是一个向量)的每个元素都是一个在 0 和 1 之间的实数,表示让对应信息通过的权重(或者占比)。比如, 0 表示“不让任何信息通过”, 1 表示“让所有信息通过”。

LSTM通过三个这样的基本结构来实现信息的保护和控制。这三个门分别输入门、遗忘门和输出门。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。