• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

6-循环神经网络北京大学TensorFlow2.0

武飞扬头像
如何原谅奋力过但无声
帮助3

课程地址:【北京大学】Tensorflow2.0_哔哩哔哩_bilibili

Python3.7和TensorFlow2.1

六讲:

  1. 神经网络计算:神经网络的计算过程,搭建第一个神经网络模型

  1. 神经网络优化:神经网络的优化方法,掌握学习率、激活函数、损失函数和正则化的使用,用Python语言写出SGD、Momentum、Adagrad、RMSProp、Adam五种反向传播优化器

  1. 神经网络八股:神经网络搭建八股,六步法写出手写数字识别训练模型

  1. 网络八股扩展:神经网络八股扩展,增加自制数据集、数据增强、断点续训、参数提取和acc/loss可视化,实现给图识物的应用程序

  1. 卷积神经网络:用基础CNN、LeNet、AlexNet、VGGNet、InceptionNet和ResNet实现图像识别

  1. 循环神经网络:用基础RNN、LSTM、GRU实现股票预测


回顾:卷积神经网络(借助卷积核提取空间特征后,送入全连接网络)

学新通
  • 卷积就是特征提取器,就是CBAPD。这种特征提取是借助卷积核实现的参数空间共享,通过卷积计算层提取空间信息,比如:可以用卷积核提取一张图片的空间特征,再把提取到的空间特征送入全连接网络,实现离散数据的分类

  • 然而,有些数据是与时间序列相关的,是可以根据上文预测出下文的(通过脑记忆体提取历史数据的特征,预测出接下来最可能发生的情况,其中脑记忆体就是循环核

学新通

本讲:循环神经网络(RNN/LSTM/GRU)实现连续数据的预测(以股票预测为例)


循环神经网络(Recurrent Neural Network,RNN)

(一)循环核

循环核具有记忆力,通过不同时刻的参数共享,实现了对时间序列的信息提取

每个循环核有多个记忆体,记忆体下面、侧面、上面分别有三组待训练的参数矩阵

学新通

RNN循环核,图中的多个小圆柱即记忆体

记忆体内存储着每个时刻的状态信息学新通

学新通
学新通

(二)循环核按时间步展开

就是把循环核按照时间轴方向展开,如图:

学新通
学新通

循环神经网络就是借助循环核实现时间特征提取后,把提取到的信息送入全连接网络,从而实现连续数据的预测

(三)循环计算层:向输出方向增长

每个循环核构成一层循环计算层,循环计算层的层数是向输出方向增长

学新通

每个循环核中记忆体的个数可以根据需求任意指定

(四)TF2描述循环计算层

  1.  
    tf.keras.layers.SimpleRNN(
  2.  
        循环核中记忆体的个数/神经元个数,
  3.  
        activation=‘激活函数’, # 使用什么激活函数计算ht。若不写,默认用tanh
  4.  
        return_sequences=是否每个时刻输出ht到下一层 # True/False,默认False
  5.  
    )

参数return_sequences

在输出序列中,返回最后时间步的输出值学新通(False)还是全部时间步的输出(True)

当下一层依然是RNN层,通常为True;反之如果后面是Dense层,通常为False。即:最后一层的循环核用False,仅在最后一个时间步输出学新通;中间层的循环核用True,每个时间步都把学新通输出给下一层

学新通

各时间步输出ht

学新通

仅最后时间步输出ht

输入/输出维度

输入:API对输入循环层的数据维度是有要求的,是一个三维张量

学新通

输出:

  • 当return_sequences=True时,三维张量(输入样本数,循环核时间展开步数,本层神经元个数)

  • 当return_sequences=False时,二维张量(输入样本数,本层神经元个数)

(五)循环计算过程

手动计算循环计算层的前向传播,具体见实践:字母预测


实践:字母预测

RNN最典型的应用就是利用历史数据,预测下一时刻将发生什么,即根据以前见过的历史规律做预测。以字母预测的例子来说明循环网络的计算过程

计算机不认识字母,只能处理数字,所以需要对字母编码,有独热编码(one-hot)Embedding编码两种方式

one-hot编码

(一)1pre1(输入一个字母,预测下一个字母)

如:输入a 预测出 b、输入 b 预测出 c、输入 c 预测出 d、输入 d 预测出 e、输入 e 预测出 a

学新通

字母独热编码

假设使用一层 RNN 网络,记忆体的个数选取 3,随机生成了Wxh、Whh和Why三个参数矩阵。字母预测网络如下图:

学新通
学新通
学新通

完整代码实现如下:

  1.  
    # 用RNN实现输入一个字母,预测下一个字母
  2.  
    # 字母使用独热码编码
  3.  
    import numpy as np
  4.  
    import tensorflow as tf
  5.  
    from keras.layers import Dense, SimpleRNN
  6.  
    import matplotlib.pyplot as plt
  7.  
    import os
  8.  
     
  9.  
    input_word = "abcde"
  10.  
    w_to_id = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4} # 单词映射到数值id的词典
  11.  
     
  12.  
    id_to_onehot = {0: [1., 0., 0., 0., 0.], 1: [0., 1., 0., 0., 0.], 2: [0., 0., 1., 0., 0.], 3: [0., 0., 0., 1., 0.], 4: [0., 0., 0., 0., 1.]} # id编码为one-hot
  13.  
     
  14.  
    # 输入特征a,对应标签b;输入特征b,对应标签c...以此类推
  15.  
    x_train = [id_to_onehot[w_to_id['a']], id_to_onehot[w_to_id['b']], id_to_onehot[w_to_id['c']],
  16.  
    id_to_onehot[w_to_id['d']], id_to_onehot[w_to_id['e']]]
  17.  
    y_train = [w_to_id['b'], w_to_id['c'], w_to_id['d'], w_to_id['e'], w_to_id['a']]
  18.  
     
  19.  
    # 打乱顺序
  20.  
    np.random.seed(7)
  21.  
    np.random.shuffle(x_train)
  22.  
    np.random.seed(7)
  23.  
    np.random.shuffle(y_train)
  24.  
    tf.random.set_seed(7)
  25.  
     
  26.  
    # 使x_train符合SimpleRNN的输入要求:[送入样本数,循环核时间展开步数,每个时间步输入特征个数]
  27.  
    # 此处整个数据集送入,故送入样本数为len(x_train)=5;
  28.  
    # 输入1个字母出结果,故循环核时间展开步数为1;
  29.  
    # 表示为独热码有5个输入特征,故每个时间步输入特征个数为5
  30.  
    x_train = np.reshape(x_train, (len(x_train), 1, 5))
  31.  
    y_train = np.array(y_train) # 把y_train变为numpy格式
  32.  
     
  33.  
    # 构建模型
  34.  
    model = tf.keras.Sequential([
  35.  
    SimpleRNN(3), # 搭建具有3个记忆体的循环层(记忆体个数越多,记忆力越好,但是占用资源会更多)
  36.  
    Dense(5, activation='softmax') # 全连接,实现了输出层yt的计算;由于要映射到独热码编码,找到输出概率最大的字母,故为5
  37.  
    ])
  38.  
     
  39.  
    # 配置训练方法
  40.  
    model.compile(optimizer=tf.keras.optimizers.Adam(0.01), # 学习率
  41.  
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
  42.  
    metrics=['sparse_categorical_accuracy'])
  43.  
     
  44.  
    # 断点续训
  45.  
    checkpoint_save_path = "./checkpoint/rnn_onehot_1pre1.ckpt"
  46.  
     
  47.  
    if os.path.exists(checkpoint_save_path '.index'):
  48.  
    print('-------------load the model-----------------')
  49.  
    model.load_weights(checkpoint_save_path)
  50.  
     
  51.  
    cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
  52.  
    save_weights_only=True,
  53.  
    save_best_only=True,
  54.  
    monitor='loss') # 由于fit没有给出测试集,不计算测试集准确率,根据loss,保存最优模型
  55.  
     
  56.  
    # 执行反向传播,训练参数矩阵
  57.  
    history = model.fit(x_train, y_train, batch_size=32, epochs=100, callbacks=[cp_callback])
  58.  
     
  59.  
    # 打印网络结构,统计参数数目
  60.  
    model.summary()
  61.  
     
  62.  
    # 提取参数
  63.  
    # print(model.trainable_variables)
  64.  
    file = open('./rnn_onehot_1pre1_weights.txt', 'w') # 参数提取
  65.  
    for v in model.trainable_variables:
  66.  
    file.write(str(v.name) '\n')
  67.  
    file.write(str(v.shape) '\n')
  68.  
    file.write(str(v.numpy()) '\n')
  69.  
    file.close()
  70.  
     
  71.  
    ############################################### show ###############################################
  72.  
     
  73.  
    # 显示训练集和验证集的acc和loss曲线
  74.  
    acc = history.history['sparse_categorical_accuracy']
  75.  
    loss = history.history['loss']
  76.  
     
  77.  
    plt.subplot(1, 2, 1)
  78.  
    plt.plot(acc, label='Training Accuracy')
  79.  
    plt.title('Training Accuracy')
  80.  
    plt.legend()
  81.  
     
  82.  
    plt.subplot(1, 2, 2)
  83.  
    plt.plot(loss, label='Training Loss')
  84.  
    plt.title('Training Loss')
  85.  
    plt.legend()
  86.  
    plt.show()
  87.  
     
  88.  
    ############### predict #############
  89.  
     
  90.  
    # 展示预测效果
  91.  
    preNum = int(input("input the number of test alphabet:")) # 先输入要执行几次预测任务
  92.  
    for i in range(preNum):
  93.  
    alphabet1 = input("input test alphabet:") # 输入一个字母
  94.  
    alphabet = [id_to_onehot[w_to_id[alphabet1]]] # 把这个字母转换为独热码
  95.  
    # 使alphabet符合SimpleRNN输入要求:[送入样本数,循环核时间展开步数,每个时间步输入特征个数]
  96.  
    # 此处验证效果送入了1个样本,送入样本数为1;
  97.  
    # 输入1个字母出结果,所以循环核时间展开步数为1;
  98.  
    # 表示为独热码有5个输入特征,每个时间步输入特征个数为5
  99.  
    alphabet = np.reshape(alphabet, (1, 1, 5))
  100.  
     
  101.  
    result = model.predict([alphabet]) # 得到预测结果
  102.  
    pred = tf.argmax(result, axis=1) # 选出预测结果最大的一个
  103.  
    pred = int(pred)
  104.  
    tf.print(alphabet1 '->' input_word[pred]) # input_word = "abcde"
学新通
学新通
学新通
学新通

运行效果:

学新通

(二)多pre1(连续输入多个字母,预测下一个字母)

把循环核按时间步展开,连续输入多个字母预测下一个字母(以连续输入4个字母预测下一个字母为例,即输入abcd输出e,输入bcde输出a,输入cdea输出b,输入deab输出c,输入eabc输出d)

仍然使用三个记忆体,初始时刻记忆体内的记忆是 0;用一套训练好的参数矩阵感受循环计算的前向传播过程,在这个过程中,每个时刻参数矩阵是固定的,记忆体会在每个时刻被更新

下面以输入 bcde 预测 a 为例:

学新通
学新通

代码实现如下(只列出与rnn_onehot_1pre1.py代码不同的地方):

  1.  
    # 连续输入四个字母预测下一个字母
  2.  
    # 字母使用独热码编码
  3.  
     
  4.  
    input_word = "abcde"
  5.  
    w_to_id = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4} # 单词映射到数值id的词典
  6.  
     
  7.  
    id_to_onehot = {0: [1., 0., 0., 0., 0.], 1: [0., 1., 0., 0., 0.], 2: [0., 0., 1., 0., 0.], 3: [0., 0., 0., 1., 0.], 4: [0., 0., 0., 0., 1.]} # id编码为one-hot
  8.  
     
  9.  
    '''
  10.  
    输入连续的abcd,对应的标签是e
  11.  
    输入连续的bcde,对应的标签是a
  12.  
    输入连续的cdea,对应的标签是b
  13.  
    输入连续的deab,对应的标签是c
  14.  
    输入连续的eabc,对应的标签是d
  15.  
    '''
  16.  
    x_train = [
  17.  
    [id_to_onehot[w_to_id['a']], id_to_onehot[w_to_id['b']], id_to_onehot[w_to_id['c']], id_to_onehot[w_to_id['d']]],
  18.  
    [id_to_onehot[w_to_id['b']], id_to_onehot[w_to_id['c']], id_to_onehot[w_to_id['d']], id_to_onehot[w_to_id['e']]],
  19.  
    [id_to_onehot[w_to_id['c']], id_to_onehot[w_to_id['d']], id_to_onehot[w_to_id['e']], id_to_onehot[w_to_id['a']]],
  20.  
    [id_to_onehot[w_to_id['d']], id_to_onehot[w_to_id['e']], id_to_onehot[w_to_id['a']], id_to_onehot[w_to_id['b']]],
  21.  
    [id_to_onehot[w_to_id['e']], id_to_onehot[w_to_id['a']], id_to_onehot[w_to_id['b']], id_to_onehot[w_to_id['c']]],
  22.  
    ]
  23.  
    y_train = [w_to_id['e'], w_to_id['a'], w_to_id['b'], w_to_id['c'], w_to_id['d']]
  24.  
     
  25.  
    # 使x_train符合SimpleRNN输入要求:[送入样本数,循环核时间展开步数,每个时间步输入特征个数]。
  26.  
    # 此处整个数据集送入,送入样本数为len(x_train)=5;
  27.  
    # 输入4个字母出结果(四个字母通过四个连续的时刻输入网络),循环核时间展开步数为4;
  28.  
    # 表示为独热码有5个输入特征,每个时间步输入特征个数为5
  29.  
    x_train = np.reshape(x_train, (len(x_train), 4, 5))
  30.  
    y_train = np.array(y_train)
  31.  
     
  32.  
    ############### predict #############
  33.  
     
  34.  
    preNum = int(input("input the number of test alphabet:"))
  35.  
    for i in range(preNum):
  36.  
    alphabet1 = input("input test alphabet:") # 等待连续输入四个字母
  37.  
    alphabet = [id_to_onehot[w_to_id[a]] for a in alphabet1] # 把这四个字母转换为独热码
  38.  
    # 使alphabet符合SimpleRNN输入要求:[送入样本数,循环核时间展开步数,每个时间步输入特征个数]
  39.  
    # 此处验证效果送入了1个样本,送入样本数为1;
  40.  
    # 输入4个字母出结果,所以循环核时间展开步数为4;
  41.  
    # 表示为独热码有5个输入特征,每个时间步输入特征个数为5
  42.  
    alphabet = np.reshape(alphabet, (1, 4, 5))
  43.  
    result = model.predict([alphabet])
  44.  
    pred = tf.argmax(result, axis=1)
  45.  
    pred = int(pred)
  46.  
    tf.print(alphabet1 '->' input_word[pred])
学新通
学新通
学新通
学新通

运行效果:

学新通

Embedding编码

独热码的位宽要与词汇量一致,若词汇量增大时,非常浪费资源(独热码的缺点:数据量大、过于稀疏、映射之间是独立的,没有表现出关联性)

Embedding是一种单词编码方法,用低维向量实现了编码。这种编码通过神经网络训练优化,能表达出单词间的相关性

Tensorflow2中的词向量空间编码层:

  • 输入维度:二维张量 [送入样本数,循环核时间展开步数]

  • 输出维度:三维张量 [送入样本数,循环核时间展开步数,编码维度]

  1.  
    tf.keras.layers.Embedding(词汇表大小,编码维度)
  2.  
    # 词汇表大小:编码一共要表示多少个单词
  3.  
    # 编码维度:用几个数字表达一个单词

在Sequential搭建网络时,相比于one-hot形式增加了一层Embedding层

(一)1pre1(输入一个字母,预测下一个字母)

代码实现如下(只列出与rnn_onehot_1pre1.py不同的地方):

  1.  
    # 用RNN实现输入一个字母,预测下一个字母
  2.  
    # 字母使用Embedding编码
  3.  
    from keras.layers import Dense, SimpleRNN, Embedding
  4.  
     
  5.  
    input_word = "abcde"
  6.  
    w_to_id = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4} # 单词映射到数值id的词典
  7.  
     
  8.  
    x_train = [w_to_id['a'], w_to_id['b'], w_to_id['c'], w_to_id['d'], w_to_id['e']]
  9.  
    y_train = [w_to_id['b'], w_to_id['c'], w_to_id['d'], w_to_id['e'], w_to_id['a']]
  10.  
     
  11.  
    # 使x_train符合Embedding输入要求:[送入样本数,循环核时间展开步数]
  12.  
    # 此处整个数据集送入,所以送入样本数为len(x_train)=5;
  13.  
    # 输入1个字母出结果,循环核时间展开步数为1
  14.  
    x_train = np.reshape(x_train, (len(x_train), 1))
  15.  
    y_train = np.array(y_train) # 把y_train变为numpy格式
  16.  
     
  17.  
    # 搭建网络
  18.  
    model = tf.keras.Sequential([
  19.  
    Embedding(5, 2), # 对输入数据进行编码,生成一个五行两列的可训练参数矩阵,实现编码可训练
  20.  
    SimpleRNN(3), # 设定具有3个记忆体的循环层
  21.  
    Dense(5, activation='softmax') # 设定全连接Dense层,实现输出层y的全连接计算
  22.  
    ])
  23.  
     
  24.  
    ############### predict #############
  25.  
     
  26.  
    preNum = int(input("input the number of test alphabet:"))
  27.  
    for i in range(preNum):
  28.  
    alphabet1 = input("input test alphabet:")
  29.  
    alphabet = [w_to_id[alphabet1]] # 把读到的输入字母直接查找表示它的ID值
  30.  
    # 使alphabet符合Embedding输入要求:[送入样本数,循环核时间展开步数]
  31.  
    # 此处验证效果送入了1个样本,送入样本数为1;
  32.  
    # 输入1个字母出结果,循环核时间展开步数为1
  33.  
    alphabet = np.reshape(alphabet, (1, 1))
  34.  
    result = model.predict(alphabet)
  35.  
    pred = tf.argmax(result, axis=1)
  36.  
    pred = int(pred)
  37.  
    tf.print(alphabet1 '->' input_word[pred])
学新通
学新通
学新通
学新通

运行效果如下:

学新通

(二)多pre1(连续输入多个字母,预测下一个字母)

将词汇量扩充到26个(A-Z)

代码实现如下(只列出与rnn_onehot_1pre1.py不同的地方):

  1.  
    # 连续输入四个字母预测下一个字母
  2.  
    # 字母使用Embedding编码
  3.  
    from keras.layers import Dense, SimpleRNN, Embedding
  4.  
     
  5.  
    input_word = "abcdefghijklmnopqrstuvwxyz" # 26个字母
  6.  
     
  7.  
    # 建立一个映射表,把字母用数字表示为0-25
  8.  
    w_to_id = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4,
  9.  
    'f': 5, 'g': 6, 'h': 7, 'i': 8, 'j': 9,
  10.  
    'k': 10, 'l': 11, 'm': 12, 'n': 13, 'o': 14,
  11.  
    'p': 15, 'q': 16, 'r': 17, 's': 18, 't': 19,
  12.  
    'u': 20, 'v': 21, 'w': 22, 'x': 23, 'y': 24, 'z': 25} # 单词映射到数值id的词典
  13.  
     
  14.  
    training_set_scaled = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
  15.  
    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
  16.  
    21, 22, 23, 24, 25]
  17.  
     
  18.  
    x_train = []
  19.  
    y_train = []
  20.  
     
  21.  
    # 用for循环从数字列表中把连续4个数作为输入特征,添加到x_train;第5个数作为标签,添加到y_train
  22.  
    for i in range(4, 26):
  23.  
    x_train.append(training_set_scaled[i - 4:i])
  24.  
    y_train.append(training_set_scaled[i])
  25.  
     
  26.  
    # 使x_train符合Embedding输入要求:[送入样本数,循环核时间展开步数]
  27.  
    # 此处整个数据集送入所以送入,送入样本数为len(x_train)=22(26个字母连续取4个,可以得到22组);
  28.  
    # 输入4个字母出结果,循环核时间展开步数为4
  29.  
    x_train = np.reshape(x_train, (len(x_train), 4))
  30.  
    y_train = np.array(y_train)
  31.  
     
  32.  
    # 搭建网络
  33.  
    model = tf.keras.Sequential([
  34.  
    Embedding(26, 2), # 词汇量是26,每个单词用2个数值编码;生成一个26行2列的可训练参数矩阵,实现编码可训练
  35.  
    SimpleRNN(10), # 设定具有10个记忆体的循环层
  36.  
    Dense(26, activation='softmax') # 全连接层,实现输出层yt的计算;输出会是26个字母之一
  37.  
    ])
  38.  
     
  39.  
    ################# predict ##################
  40.  
     
  41.  
    preNum = int(input("input the number of test alphabet:")) # 先输入要执行几次检测
  42.  
    for i in range(preNum):
  43.  
    alphabet1 = input("input test alphabet:") # 等待连续输入四个字母
  44.  
    alphabet = [w_to_id[a] for a in alphabet1]
  45.  
    # 使alphabet符合Embedding输入要求:[送入样本数,时间展开步数]
  46.  
    # 此处验证效果送入了1个样本,送入样本数为1;
  47.  
    # 输入4个字母出结果,循环核时间展开步数为4
  48.  
    alphabet = np.reshape(alphabet, (1, 4))
  49.  
    result = model.predict([alphabet]) # 输入网络进行预测
  50.  
    pred = tf.argmax(result, axis=1) # 选出预测结果最大的一个
  51.  
    pred = int(pred)
  52.  
    tf.print(alphabet1 '->' input_word[pred])
学新通
学新通
学新通
学新通

运行效果:

学新通

实践:股票预测

  1. RNN

  1. LSTM

  1. GRU

见链接:基于TensorFlow2用RNN/LSTM/GRU实现股票预测

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhickg
系列文章
更多 icon
同类精品
更多 icon
继续加载