第9章 深度学习之循环神经网络 RNN:序列模型 Sequence Model,循环神经网络的结构、缺陷,三种升级版(LSTM、BRNN、DRNN),两个实战


目录


上节:介绍了专用于计算机视觉的,卷积神经网络CNN模型。核心,就是对图像进行卷积操作,快速的提取图像的轮廓信息(特征)

本节:将要介绍循环神经网络:关注数据里的前后的序列关系

一、本章内容

1.1 六个部分

二、序列模型 Sequence Model

序列模型,Sequence Model。

2.1 生活中的实际案例:4个

案例1:自动撰写文章。

案例2:自动的寻找语句中的人名。

案例3:物体的位置预测。

案例4:股价预测

横坐标,是时间序列的形式

2.2 序列模型:有前后关系的数据

序列数据:指的是顺序的数据,指的有前后关系的数据。

  • “不吃饭” vs “吃饭不”---------------- 每个汉字的先后顺序不同,结果不同
  • 输入、输出,的不定长度

2.3 应用场景:4个

三、循环神经网络 RNN

Recurrent Neural Network, RNN

我以为是Recycle。。。

Neural

3.1 结构

左边:以前的传统MLP结构(神经网络):

X是x1、x2、x3...

y可以是一个多分类,也可以是一个回归预测

右边:是循环神经网络RNN的结构:
核心:将前面的序列数据,用在后面的结果预测中。

x1、x2、x3...是有前后关系的;

可以用x1来预测y1的结果。同时,x1还可以产生另外一个信息a1(a1包含了前面序列x1中的部分信息),把a1给到y2的预测中。即,y2的预测,是与前面的序列x1,有关系的。

test:

已更新typora版本到1.9.5:

3.2 数学模型

1.那么:x1是如何产生另外一个信息a1?

假设a0是0,W是一个初始的系数,可以是0,或一个随机数。

公式形式如下。具体的求解过程,类似于MLP多层感知器中的梯度下降法,找到损失函数最小的那个权重。

2.看一下模型是怎么搭建的:

确定输入:x1、x2、x3、x4...x10、x11

确定输出:0、0、0、0...1、0

问题:

此处,为什么要将文本转换为0和1呢?

答:计算机不理解文本,但是理解0、1.

就像之前学习的CNN卷积神经网络:

你给计算机一个图片,它是理解不了的;

你给整张图片对应的灰度数值,它是能够理解的。

3.

词汇数值化:

每一个英文词汇都对应一个数字,一一对应。(用Python中字典dict数据结构来存放)

为了更高效的计算,还需要将上述的数值,再次的转换为one-hot数组。形式是(-1,1),即n行1列。

也就是说,每一个词汇,最终会转换为一个n行1列形式的one-hot数组。

4.

将上述的n行1列形式的one-hot数组,与RNN模型,结合起来:

X的赋值:

y的赋值;

根据y的预测值,来得到损失函数,进而最小化;

上述,就是针对自然语言处理的、RNN模型的核心处理流程。

5.

另一种数值化的方式:(本实战二用的就是这种)

上面:词汇与数字一一对应;

下面:字母与数字一一对应。

不足:缺乏词汇之间的内部的关系,对模型的要求会更高。

3.3 课后题

C

RNN循环神经网络模型,是深度学习领域中的一个概念。此类模型需要用到海量数据,与它进行上下游的输入,起码得是数学领域中的数组或矩阵的形式。

四、不同类型的RNN模型

4.1 基础的RNN结构

1.

输入、输出的数量是多个,即多输入、多输出。同时,维度是一样的;

应用:语句中的特定信息(比如人名)的识别

2.

3.

多输入、单输出。应用:情感识别。

单输入、多输出。应用:文章生成。

4.

这里也是多输入、多输出,但是维度不同。应用:语言的翻译。

4.2 基础的RNN结构的缺陷

RNN结构的数据,都是序列模型,即数据是有先后关系的。

层层转递到靠后的序列数据,所有的信息的权重都是一样的。

每一层,在反推时,梯度越来越小,没法求解,没法找到损失函数的最小值。

我还是不太理解。

后部序列,有前部序列的信息。有就行呗,为啥还要权重?

4.3 长短期记忆网络 LSTM:增加记忆细胞,保留前部序列中的重要信息

1.

在上述RNN基础结构的基础上,增加一个记忆细胞Ci,用于记忆某些重要的数据信息。

原理:通过一些门:忘记门、更新门、输出门。

我认为:

就是这些门,通过权重的形式,对之前一律平等的数据信息,进行抓大放小。

2.

长短期记忆 LSTM,算是基础RNN结构的升级版。

4.4 双向循环神经网络 BRNN:还要考虑后部序列的重要信息

上面的长短期记忆 LSTM:只考虑了前部序列的信息。

如果还要考虑后部序列的信息呢?

4.5 深层循环神经网络 DRNN:单层的RNN,叠加在一起

将单层的RNN,叠加在一起,用于解决一些复杂的任务。

4.6 课后题

五、实战准备

5.1 实战(一):用基础的RNN,实现股价预测(重)

任务:

1.

左边:提取序列数据:

每一行都有8个数据;

然后,把上述的序列数据,作为输入给到RNN模型:

2.

右边:建立普通的RNN循环神经网络模型:

输出层:输出的y,是单个数值的预测,所以只有一个神经元。线性回归的激活函数;

回归预测,所以使用的损失函数是最小绝对值误差;------------------ 我的:平均的方差?

3.

RNN模型的输入数据的格式:input_shape

  • samples,指的是样本的总数量。因为模型能自动计算,所以,后续实战二中的模型的入参中,就不需要画蛇添足的自己写上了。即,可以省略该参数。
  • time_steps指的是步长,即滑动窗口的长度。比如,实战二中的time_steps为20。因为每次都是使用前20个字符,去预测第21个字符。
  • features,就是后续实战中,的字典的长度。比如,实战二中的num_letters为23.

我的问题:
对于input_shape,我还是不太懂?

中括号中,为什么是1、2呢?那0去哪里了?

答:samples,指的是样本的总数量。因为模型能自动计算,所以,后续实战二中的模型的入参中,就不需要画蛇添足的自己写上了。即,可以省略该参数。

5.2 实战(二):LSTM,自动生成文本

将文本转换成数值,再转换为n行1列的one-hot数组:

任务:

1.

文本加载;

字符字典建立;

2.

文本数据的批量预处理:

四个入参,两个结果:

六、实战(一):用基础的RNN,实现中国平安股价预测

6.1 任务

任务:
基于zgpa_train.csv数据集,建立RNN循环神经网络模型,预测中国平安的股价:
1.完成数据的预处理,将序列数据转化为可用于RNN输入的数据;
2.对新的测试数据zgpa_test.csv进行预测,并可视化结果;
3.存储预测结果,并观察局部的预测结果;

备注:模型结构:单层RNN,输出有5个神经元;每次使用前8个数据来预测第9个数据

6.2 task1:完成数据的预处理,将序列数据转化为可用于RNN输入的数据

只需要收盘价close;

因为是一个回归模型,为了使该模型更快的收敛,所以要对数据进行归一化处理;(也就是说,将数据的区间范围缩小到0~1)

define X and y:

不能像以前一样,直接从data中拿过来用;

这次,需要根据RNN循环神经网络的要求,从原来的序列数据中提取出来;

因为:0、1、2、3、4、5、6、7、8、9:一共10个样本,time_step = 8。最多是有三组样本。

因为最后一组样本,后面就没有需要再预测的数据了,因为末尾数字是9.

所以,就只使用两组样本。

对于len(data) - time_step,就是10-8=2. 即range(2)

对于data[i : i+time_step]

  • i 为0时,就是data[0 : 8]------------------------------ 顾左不顾右
  • i 为1时,就是data[1 : 9]------------------------------ 顾左不顾右

feature的维度是1:

(723, 8, 1) 指的是有723个样本,每个样本中有8个数据点。1指的是每个数据点就是1个单独的数值。(也就是,最里面那层list中,元素数量只有1个)

即,样本数,序列的长度,每个数据的维度。

723怎么来的?

731 - 8 = 723

原始的数据总行数 - time_step = 样本数据的总行数

也就是说,extract_data() 方法中的for循环,是循环了723遍。

X的样本数,与y的样本数,是一致的;

因为输出层,只是输出一个数值,所以units=1。

因为是回归任务,所以可以尝试激活函数为线性:activation="linear"

问题:

有的时候,会发现损失函数,会停留在某个数值附近,不下降了。得到的效果不是很好。

即,模型求解时,到了一个局部的最小化的损失函数,现在死循环中。

解决:

重新执行建模过程、重新训练一次即可。

原因:

因为深度学习MLP模型求解时,一开始会有一个初始状态。这个初始状态给的不好,就会导致这样一个局部最优解。通过可视化看,效果就不是很好。

下面,也可以写成y_train = [i * max(price) for i in y]形式,属于Python语法中的列表表达式。

可视化下:
橙色的预测数据,与蓝色的真实数据,吻合的挺好。

6.3 task2:对新的测试数据zgpa_test.csv进行预测,并可视化结果

再针对测试数据,基于训练好的模型进行下预测:

注意:

对于测试数据,归一化时,用的也是max(price)。

如果是max(test_price),就会原来模型的归一化的效果不一样了,不统一。

我明白了:

归一化,是要求所有的数据(训练数据或测试数据),得用同一套标准~

橙色的预测数据,与蓝色的真实数据,吻合的也挺好。

6.4 task3:存储预测结果,并观察局部的预测结果

1.存储结果:

先将python中的list转换为Numpy库中的数组array:

2.将数组array转换为Pandas库中的DataFrame数据结构;

columns=["real_price_test", "predict_price_test"]只是给字段起个名字;

已保存进了本地的csv文件中:

3.看一下本地文件:

通过task2中的可视化图,看起来效果不错。

但是,也要看下局部的放大观察:

因为上述的可视化图中,橙色的预测数据,总是滞后于蓝色的真实数据。

这种滞后性的缺点,就需要再观察局部的数据。

发现:

确实是慢了一拍。比如:现实生活中,你以为明天会涨,结果明天竟然跌了。

6.5 小结

七、实战(二):建立LSTM,来自动生成文本

7.1 任务

任务:
基于flare文本数据,建立LSTM模型,预测序列文字:
1.完成数据的预处理,将文字序列数据,转换为可用于LSTM输入的数据;
2.查看文本数据预处理后的数据结构,并进行数据分离的操作;
3.针对字符串输入("flare is a teacher in ai industry. He obtained his phd in Australia."), 预测其对应的后续字符。

备注:模型结构:单层LSTM,输出有20个神经元;每次使用前20个字符来预测第21个字符。

flare文本数据如下:

7.2 task1:完成数据的预处理,将文字序列数据,转换为可用于LSTM输入的数据

这次的数据加载跟以前不一样:
以前是read本地的csv文件,现在,只需要打开flare文件然后读取即可。

1.

换行符一般有两种:\n\r

移除换行符之后的总的data,长下面这样:一坨...

2.

为了建立字典做准备:字符去重;

建立最终的字典:char_to_int。其中:

  • num_letters为23,该文本中一共出现了23种英文字母,就是说,后续建立的字典,总共有23页(就是字典的页数)(页码);
  • enumerate(letters)指的是,将letters这个list中的索引位置与该位置上的元素,显示出来:
    int_to_char就是形成的字典;
  • 这里的char_to_int,是一个字典dict:用字母作为索引(key),来找到对应它的数字(value);-------------- 下面橘黄色的建立字典dict的方式,是真简洁、高效、优雅。

步长:

3.

字符串的批量处理

  • 方法1:可以把原始的充满字母和单词的文本,看作是一本人类的英文小说。因为我们要训练模型、预测,原始的人类英文小说的形式,肯定是机器学习和深度学习无法理解、无法直接使用的。所以,对其,要进行用“20的步长+1(结果)”的模式,一一的滑动的过一遍,转换一下数据的形式;

比如:

       x                              y
       
flare is a teacher i ---------------- n
lare is a teacher in ----------------  
are is a teacher in  ---------------- a
re is a teacher in a ----------------  
e is a teacher in a  ---------------- i
 is a teacher in ai  ---------------- i
 .                                      .    
 .                                      .
 .                                      .
 
 x.append([a for a in data[i:i+slide]])的目的是:
 在x这个列表中,以这样的形式存放:
[
['f', 'l', 'a', 'r', 'e', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 'a', 'c', 'h', 'e', 'r', ' ', 'i'],  ['l', 'a', 'r', 'e', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 'a', 'c', 'h', 'e', 'r', ' ', 'i', 'n'], ['a', 'r', 'e', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 'a', 'c', 'h', 'e', 'r', ' ', 'i', 'n', ' '], ['r', 'e', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 'a', 'c', 'h', 'e', 'r', ' ', 'i', 'n', ' ', 'a'], ['e', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 'a', 'c', 'h', 'e', 'r', ' ', 'i', 'n', ' ', 'a', 'i'], 
...
]

len(data) - slide 就是:56168 - 20 = 56148

(去除换行符后)原始的数据总行数 - slide = 样本数据的总行数

也就是说,extract_data() 方法中的for循环,是循环了56148遍。(7.3节,X、y的结构,可以验证)

  • 方法2:就是基于以前组建好的字典,对上述的每个字符都转换为数字;
  • 方法3:的中后部,没有看懂?1

注意:上述方法1中,有个错误。后面的bug2。

使用上述的批量处理文本数据的方法,提取出来:

4.

(0)为了更好的理解:

我后期改动了下代码,看一下某几个重要的中间变量 ,具体的长什么样子::

(1)

  • 方法1:

(2)方法2:

(3)

下面代码意思是:将上面方法2的结果x_to_int,由二维list形式,转换为二维数组(即矩阵)的数学形式:

input_reshaped = np.array(x_to_int).reshape(len(x_to_int), slide)

(4)

下面代码意思是:新建一个(56148, 20,23)的三位list,用随机数进行填充:

new = np.random.randint(0, 10, size=[input_reshaped.shape[0], input_reshaped.shape[1], num_letters])

(5)

下面代码意思是:将二维数组(矩阵)input_reshaped,中的每个元素,都转换为one-hot的形式:(只有0、1)。然后,一一的覆盖上面的new中元素,焕然一新(而且还升维至了3维):

new[i, j, :] = to_categorical(input_reshaped[i, j], num_classes=num_letters)


本节遇到的几个bug:

bug1:

问题:

解决:

google了下,已搞定

bug2:

展示的是生成器对象,不是我想要的:

原因:

老师的代码:

网上其他人的验证:

解决及结果:

7.3 task2:查看文本数据预处理后的数据结构,并进行数据分离的操作

1.

看下X的结构:(56148, 20, 23)

  • 指的是有56148个样本数;
  • 每个样本是20个字符对应的one-hot数组;
  • 这个字典有23页。

我的问题:上面X的类型是?

答:三维数组。

2.

看下y的长度:也是56148;y的类型,仍然是一个list,

进行数据分离;

将y_train这个变量,从list形式,转换为one-hot形式;

为了更好的理解:我查看了下几个中间变量的类型、结构

我发现:

相比于x,y要转换成one-hot的形式的时机,要比较晚。且是在数据分离split之后。

因为x早在方法3即data_preprocessing()中,及已经完成了one-hot的形式转换。

3.对于LSTM,activation="relu"。也可以不写,因为会有一个默认的激活函数。

因为不是一个输出,而是看下字典有多少页,即是多分类的,所以activation="softmax";

flare:

神经网络模型中,的参数,没有谁能确保它就是最好的。

都是做一些尝试之后,才得出,相对较好的参数。

因为是多分类的,所以损失函数loss="categorical_crossentropy"。

我的问题:
对于input_shape,我还是不太懂?

中括号中,为什么是1、2呢?那0去哪里了?

答:samples,指的是样本的总数量。因为模型能自动计算,所以,本实战二中的模型的入参中,就不需要画蛇添足的自己写上了。即,可以省略该参数。(参考上面的章节:五、实战准备 / 5.1 实战(一))

注意:单词辨别:

下面的是metrics,------------ /e/挨,口腔中间----------------------- 意思是:指标

不是matrix。----------------------------- 字母表中的a的读音,口腔上边---- 意思是:矩阵

4.

训练模型;

做出预测;

下面预测,得到的是数字。如果想看到,文本的结果呢?那就基于字典,转换一下即可。

这就是,为什么在前面数据分离时,y_train没有进行one-hot 的转换。因为此时(即预测后),需要y_train的原始形式(即list的形式),与预测的结果(天然的是list的形式),进行对比。

5.

因为上面的accuracy: 0.7442是对应的最后一个batch样本的准确率。

下面的0.8566,是整体的样本的准确率。

7.4 task3:针对字符串输入("flare is a teacher in ai industry. He obtained his phd in Australia."), 预测其对应的后续字符

1.针对特定的字符串:

2.结果:

还是不太准:比如上面的红线处的两个单词,就是错误的。应该是phd、Australia。

这是因为:模型训练时,准确率是0.8442,不是100%

3.

那就可以回头,重复执行下fit训练的代码,在训练迭代5个epochs试试:

准确率,确实提升了:且是100%

预测结果,也确实全部预测正确:

4.

能否让预测结果,更直观的显示出来?

可以,每次以20个数据为输入,1个输出结果:

7.5 小结

这里的LSTM,与simpleRNN,没有体现出不一样。

以后,在自然语言处理时,发现文本多、需要前后关联,那么LSTM的效果就会比simpleRNN更加明显。

声明:Jerry's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 第9章 深度学习之循环神经网络 RNN:序列模型 Sequence Model,循环神经网络的结构、缺陷,三种升级版(LSTM、BRNN、DRNN),两个实战


Follow excellence, and success will chase you.