TensorFlow学习笔记——(11)循环神经网络

article/2025/10/3 18:55:51

文章目录

      • 一、循环核
      • 二、循环核时间步展开
      • 三、循环计算层
      • 四、TF描述循环计算层
      • 五、循环计算过程
        • 1、RNN实现单个字母预测
          • (1)过程
          • (2)完整代码
        • 2、RNN实现输入多个字母,预测一个字母
          • (1)过程
          • (2)完整代码
      • 六、补充
        • 1、AttributeError: 'tuple' object has no attribute 'shape'

一、循环核

首先回顾下卷积神经网络:

  • 卷积核:参数空间共享,卷积层提取空间信息。
  • 卷积神经网络:借助卷积核提取空间特征后,送入全连接网络。

然后引入循环核:

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

循环核表示为下面结构,中间圆柱是记忆体,可以设定记忆体的个数,改变记忆容量,当记忆体个数被指定时,输入xt、输出yt维度被指定,周围这些待训练参数(Why,Whh,Wxh)的维度也就被限定了。
在这里插入图片描述
记忆体内存储着每个时刻的状态信息ht,记忆体当前时刻存储的状态信息ht,等于下式:
在这里插入图片描述
当前时刻循环核的输出特征yt,等于下式:
在这里插入图片描述

  • 前向传播时,记忆体内存储的状态信息ht,在每个时刻都被刷新,三个参数矩阵wxh、whh、why自始至终都是固定不变的。
  • 反向传播时,三个参数矩阵wxh、whh、why被梯度下降法更新。

二、循环核时间步展开

按照时间步展开,就是把循环核按照时间轴方向展开,表示图如下:
在这里插入图片描述
每个时刻记忆体状态信息ht被刷新,记忆体周围的参数矩阵wxh、whh、why是固定不变的,我们训练优化的就是这些参数矩阵,训练完成后,使用效果最好的参数矩阵,执行前向传播,输出预测结果。

循环神经网络:借助循环核提取时间特征后,送入全连接网络,实现连续数据的预测。

yt是整个循环网络的末层,从公式来看,就是一个全连接网络,实现连续数据预测。

三、循环计算层

每个循环核构成一层循环计算层,循环计算层的层数是向输出方向增长的,也就是循环核是纵向连接的,有几个循环核就是基层循环计算层,它们中的每个循环核中记忆体的个数,是根据需求任意指定的。
在这里插入图片描述

四、TF描述循环计算层

TF描述循环计算层的函数:
在这里插入图片描述
一般来讲,中间的层循环核用True,每个时间步都把ht输出给下一层,最后一层的循环核用False, 仅在最后一个时间步输出ht。

  • True,每个时间步都把ht输出给下一层
    在这里插入图片描述
  • False, 仅在最后一个时间步输出ht
    在这里插入图片描述
    API对送入循环层的数据维度是有要求的,要求送入RNN的数据是三维的,格式如下:
    在这里插入图片描述
    例子如下:
  • 一共要送入RNN层两组数据,每组数据经过一个时间步就会得到输出结果,每个时间步送入三个数值,因此输入循环层的数据维度就是[2,1,3]

在这里插入图片描述

  • 还有一组数据,分四个时间步送入循环层,每个时间步送入两个数值,因此输入循环层的数据维度就是[1,4,2]
    在这里插入图片描述

五、循环计算过程

1、RNN实现单个字母预测

(1)过程

用字母预测的例子来展示循环计算过程,规则如下:
在这里插入图片描述
1)首先,因为网络输入的都是数字,因此将字母以独热码形式进行编码表示;
在这里插入图片描述
2)随机生成Wxh、Whh、Why三个参数矩阵,记忆体的个数选取3,结构如下:
在这里插入图片描述
3)ht的计算如下:
在这里插入图片描述
4)过tanh激活函数后,得到当前时刻的状态信息ht,因此需要刷新记忆体存储的状态信息,也就是替换ht-1:
在这里插入图片描述
5)然后计算输出yt,这里yt输出是把提取到的时间信息,通过全连接进行识别预测的过程:
在这里插入图片描述

(2)完整代码

在这里插入图片描述

# import相关模块
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Dense, SimpleRNN
import matplotlib.pyplot as plt
import os# 用到的字母是abcde
input_word = "abcde"
# 为了送入神经网络,把字母表示为01234
w_to_id = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4}  # 单词映射到数值id的词典
# 01234编码为独热码
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# 生成训练用的输入特征x_train,标签y_train
x_train = [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']], id_to_onehot[w_to_id['e']]]
y_train = [w_to_id['b'], w_to_id['c'], w_to_id['d'], w_to_id['e'], w_to_id['a']]# 打乱训练集顺序
np.random.seed(7)
np.random.shuffle(x_train)
np.random.seed(7)
np.random.shuffle(y_train)
tf.random.set_seed(7)# 把输入特征变成RNN层期待的形状
# 使x_train符合SimpleRNN输入要求:[送入样本数, 循环核时间展开步数, 每个时间步输入特征个数]。
# 此处整个数据集送入,送入样本数为len(x_train);输入1个字母出结果,循环核时间展开步数为1; 表示为独热码有5个输入特征,每个时间步输入特征个数为5
x_train = np.reshape(x_train, (len(x_train), 1, 5))
# y_train变为numpy格式
y_train = np.array(y_train)# 搭建具有3个记忆体的循环层,3是自己随意设定的
model = tf.keras.Sequential([SimpleRNN(3),# 全连接层,实现了输出层yt的计算Dense(5, activation='softmax')
])# 配置训练参数
model.compile(optimizer=tf.keras.optimizers.Adam(0.01),loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),metrics=['sparse_categorical_accuracy'])checkpoint_save_path = "./checkpoint/rnn_onehot_1pre1.ckpt"if os.path.exists(checkpoint_save_path + '.index'):print('-------------load the model-----------------')model.load_weights(checkpoint_save_path)cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,save_weights_only=True,save_best_only=True,monitor='loss')  # 由于fit没有给出测试集,不计算测试集准确率,根据loss,保存最优模型# 执行训练过程
history = model.fit(x_train, y_train, batch_size=32, epochs=100, callbacks=[cp_callback])
# 显示网络参数和结构
model.summary()# print(model.trainable_variables)
file = open('./weights.txt', 'w')  # 参数提取
for v in model.trainable_variables:file.write(str(v.name) + '\n')file.write(str(v.shape) + '\n')file.write(str(v.numpy()) + '\n')
file.close()###############################################    show   ################################################ 显示训练集和验证集的acc和loss曲线
acc = history.history['sparse_categorical_accuracy']
loss = history.history['loss']plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.title('Training Accuracy')
plt.legend()plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.title('Training Loss')
plt.legend()
plt.show()############### predict #############
# 展示效果的应用程序
# 先输入要执行几次预测任务
preNum = int(input("input the number of test alphabet:"))
for i in range(preNum):# 等待输入一个字母,并转换为独热码alphabet1 = input("input test alphabet:")alphabet = [id_to_onehot[w_to_id[alphabet1]]]# 使alphabet符合SimpleRNN输入要求:# [送入样本数, 循环核时间展开步数, 每个时间步输入特征个数]。此处验证效果送入了1个样本,送入样本数为1;输入1个字母出结果,所以循环核时间展开步数为1; 表示为独热码有5个输入特征,每个时间步输入特征个数为5alphabet = np.reshape(alphabet, (1, 1, 5))# predict输出预测结果result = model.predict(alphabet)# 选出预测结果最大的一个pred = tf.argmax(result, axis=1)pred = int(pred)tf.print(alphabet1 + '->' + input_word[pred])

2、RNN实现输入多个字母,预测一个字母

(1)过程

以连续输入四个字母,预测下一个字母的例子,来介绍循环核按时间展开后,循环计算过程。
1)使用三个记忆体,初始时刻,记忆体内的记忆是0,在这个过程中的每个时刻参数矩阵是固定的,记忆体会在每个时刻被更新。
2)在第一个时刻,b的独热码[0,1,0,0,0]输入,记忆体根据更新公式刷新为[-0.9,0.2,0.2]
3)在第二个时刻,c的独热码[0,0,1,0,0]输入,记忆体根据更新公式刷新为[0.8,1.0,0.8]
4)在第三个时刻,d的独热码[0,0,0,1,0]输入,记忆体根据更新公式刷新为[0.6,0.5,-0.1]
在这里插入图片描述
5)在第四个时刻,e的独热码[0,0,0,0,1]输入,记忆体根据更新公式刷新为[-1.0,-1.0,0.8]
6)输出预测通过全连接完成,代入yt计算公式,得到[0.71,0.14,0.10,0.05,0.00]

(2)完整代码
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Dense, SimpleRNN
import matplotlib.pyplot as plt
import os# 用到的字母是abcde
input_word = "abcde"
# 为了送入神经网络,把字母表示为01234
w_to_id = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4}  # 单词映射到数值id的词典
# 01234编码为独热码
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# 生成训练用的输入特征x_train,标签y_train
x_train = [[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']]],[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']]],[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']]],[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']]],[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']]],
]
y_train = [w_to_id['e'], w_to_id['a'], w_to_id['b'], w_to_id['c'], w_to_id['d']]# 打乱训练集顺序
np.random.seed(7)
np.random.shuffle(x_train)
np.random.seed(7)
np.random.shuffle(y_train)
tf.random.set_seed(7)# 把输入特征变成RNN层期待的形状
# 使x_train符合SimpleRNN输入要求:[送入样本数, 循环核时间展开步数, 每个时间步输入特征个数]。
# 此处整个数据集送入,送入样本数为len(x_train);输入4个字母出结果,循环核时间展开步数为4; 表示为独热码有5个输入特征,每个时间步输入特征个数为5
x_train = np.reshape(x_train, (len(x_train), 4, 5))
# y_train变为numpy格式
y_train = np.array(y_train)# 搭建具有3个记忆体的循环层,3是自己随意设定的
model = tf.keras.Sequential([SimpleRNN(3),
# 全连接层,实现了输出层yt的计算Dense(5, activation='softmax')
])# 配置训练参数
model.compile(optimizer=tf.keras.optimizers.Adam(0.01),loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),metrics=['sparse_categorical_accuracy'])checkpoint_save_path = "./checkpoint/rnn_onehot_4pre1.ckpt"if os.path.exists(checkpoint_save_path + '.index'):print('-------------load the model-----------------')model.load_weights(checkpoint_save_path)cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,save_weights_only=True,save_best_only=True,monitor='loss')  # 由于fit没有给出测试集,不计算测试集准确率,根据loss,保存最优模型# 执行训练过程
history = model.fit(x_train, y_train, batch_size=32, epochs=100, callbacks=[cp_callback])model.summary()# print(model.trainable_variables)
file = open('./weights.txt', 'w')  # 参数提取
for v in model.trainable_variables:file.write(str(v.name) + '\n')file.write(str(v.shape) + '\n')file.write(str(v.numpy()) + '\n')
file.close()###############################################    show   ################################################ 显示训练集和验证集的acc和loss曲线
acc = history.history['sparse_categorical_accuracy']
loss = history.history['loss']plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.title('Training Accuracy')
plt.legend()plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.title('Training Loss')
plt.legend()
plt.show()############### predict #############preNum = int(input("input the number of test alphabet:"))
for i in range(preNum):alphabet1 = input("input test alphabet:")alphabet = [id_to_onehot[w_to_id[a]] for a in alphabet1]# 使alphabet符合SimpleRNN输入要求:[送入样本数, 循环核时间展开步数, 每个时间步输入特征个数]。# 此处验证效果送入了1个样本,送入样本数为1;输入4个字母出结果,所以循环核时间展开步数为4; 表示为独热码有5个输入特征,每个时间步输入特征个数为5alphabet = np.reshape(alphabet, (1, 4, 5))result = model.predict(alphabet)pred = tf.argmax(result, axis=1)pred = int(pred)tf.print(alphabet1 + '->' + input_word[pred])

六、补充

1、AttributeError: ‘tuple’ object has no attribute ‘shape’

预测部分的原始代码是这样的:

result = model.predict([alphabet])

然后在运行的时候,可以正常训练,但是预测总是出错,指向上面这一行,问题是 AttributeError: 'tuple' object has no attribute 'shape',也没太看懂是什么意思,但是查资料看到predict里面好像直接写预测样本就可以,就尝试把[]去掉,然后成功解决哈哈哈
修改过后:

result = model.predict(alphabet)

http://chatgpt.dhexx.cn/article/eACk2hKj.shtml

相关文章

【mysql组合查询】

mysql组合查询:将查询出来的值作为表头,并统计类别数量 SELECTa.enterprise_name AS 事业部,sum( IF ( a.alarm_reason 3, a.countt, 0 ) ) AS 正常操作,sum( IF ( a.alarm_reason 4, a.countt, 0 ) ) AS 人员操作,sum(IF( a.alarm_reason NULL, a.c…

mysql 组合查询_mysql组合查询

使用UNION 多数SQL查询都只包含一个或多个表中返回数据的单条SELECT语句。MySQL也允许执行多个查询(多条SELECT语句),并将结果作为单个查询结果集返回。这些组合查询通常称为并(union) 有两种情况需要使用组合查询: 在单个表查询中从不同的表返回类似结构…

SQL学习十一、组合查询

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。 请注意, 1、UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。 即多个 SELECT 语句查询出来的结果集要能合并到一起…

【MySQL】联合查询

目录 1、前言 2、联合查询 3、内连接和外连接 4、案例演示 4.1 查询篮球哥每科的成绩 4.2 查询所有同学的总成绩及邮箱 5、自连接 5.1 显示所有计算机原理成绩比java成绩高的同学 6、子查询 6.1 查询出篮球哥的同班同学 6.2 多行子查询 7、合并查询 1、前言 在实际…

数据库组合查询

在使用数据库的过程中,数据的查询是使用最多的,所以,数据的精确查询是一个很重要的问题。以前的数据查询是最简单的数据查询,也从来没想过组合查询的问题,可是在做机房收费系统的时候,遇到了一个很大的问题…

SQL组合查询知识

大多数SQL查询只从一个或者多表中返回数据都是单个select语句。但是SQL server允许多个select语句执行,它返回的结果是一个结果集,需要使用 union 组合 ,这些组合一般称为并(union)和复合查询(compound que…

组合查询

今天我们来学习一下组合查询的方法。什么叫组合查询,就是根据自己选择的内容进行数据查询。我们可以根据单个数据查询,也可以根据多个数据查询我们想要的内容。而我今天要讲的是根据学院、年级、班级还有学号和姓名进行查询的方法,我们首先打…

MySQL入门学习:组合查询

一、组合查询 多数SQL查询都只包含从一个或多个表中返回数据的单条SELECT语句。MySQL也允许执行多个查询(多条SELECT语句),并将结果作为单个查询结果集返回。这些组合查询通常称为并(union)或复合查询(comp…

SQL数据库的组合查询和统计查询

数据库的组合查询和统计查询 一、实验目的 对数据库进行组合查询和统计查询 二、实验内容 1、加深对SQL语言查询语句的理解 2、熟练掌握数据查询中的分组统计、计算和组合操作方法。 三、实验要求 在本题下面提交基本操作效果截图。 一,组合查询简单查询。 1、…

组合多个查询

紫色代表一级目录 粉红代表二级目录 蓝色代表三级目录 红色代表关键字 橙色代表说明 单查询与组合查询   单查询实例      使用了操作符UNION    组合查询操作符   UNION     UNION 操作符可以组合两个或多个 SELECT 语句的结果,不包含重复的记录。换…

[Mysql] 组合查询

组合查询可以将多个SELECT结果拼接在一起作为最终结果输出(输出组合成单个查询结果集) 当存在多个查询结果符合条件,需要将多个查询结果进行纵向拼接时,就会用到组合查询 如下图所示,如果需要查出的结果包含表A和表B两个部分,则…

MySQL必知必会:组合查询(Union)

本篇文章主要介绍使用Union操作符将多个SELECT查询组合成一个结果集。本文参考《Mysql必知必会》工作实践融合 组合查询 定义 在大多数开发中,使用一条SELECT查询就会返回一个结果集。如果,我们想一次性查询多条SQL语句,并将每一条SELECT查询…

组合查询——union

文章目录 1.组合查询2.创建组合查询2.1 使用union2.2 union规则2.3 包含或取消重复的行2.4 对组合查询结果排序 1.组合查询 组合查询指的是:在Mysql中执行多个查询,并将结果作为单个查询结果集返回。 这些组合查询通常称为并或复合查询。 以下2种情况&…

【SQL自学打卡|DAY13】——组合查询

前言 ❤欢迎大家阅读我的文章呀❤ 今天是SQL必知必会的最后一块练习。 希望你们在我的文章当中能有所收获!!! SLogan:利用有限的时间,撸起袖子加油干! 知识点回顾 内联结:inner join。取两列的交集。 外联…

PyCharm取消波浪线、下划线和中划线

默认情况下,PyCharm中如果有无法错误或者不符合PEP8规范代码下面会有波浪线,语法错误波浪线为红色(如下图的第10行),不符合PEP8规范为浅黄色波浪线(如下图的第8行),见下图&#xff1…

Python中下划线的含义及用法

看代码的时候,经常看到各种变量名带各种下划线,有单下划线、双下划线等,主要有五种下划线(按照下划线位置命名类型): 单下划线:_单下划线变量名:_var变量名单下划线:var…

Python 中下划线的 6 个作用

初学者看到 Python 中的下划线 _ 时可能会有些懵圈,不知道这个到底是干什么用的,今天就来盘点一下 Python 中的下划线有哪些用处。以后看到下划线时就可以对号入座了。 1、用在 Python 解释器,表示上一次的执行结果 即使不把 Python 用于编程…

html中的:下划线标签、中划线标签、斜体标记、粗体标记

<!-- 下划线标记 --><b>下划线标签&#xff1a;</b><u>u标签是下划线标签</u><br><!-- 中划线标签 --><b>中划线标题&#xff1a;</b><s>s是中划线标签</s><del>del也是中划线标签</del><br…

多种方法在Markdown加入上划线、中划线、下划线

上划线和下划线不是Markdown自身语法&#xff0c;因此需要一点摸索&#xff0c;特将结果记录于此 中划线 中划线是markdown自身语法&#xff0c;实现起来很简单&#xff1a; ~~中划线~~效果&#xff1a; 中划线 下划线 法一&#xff1a;借助Latex公式 $\underline{\text{…

UILabel,文字添加下划线,中划线

//显示下划线 //中划线 // NSDictionary *attribtDic {NSStrikethroughStyleAttributeName: [NSNumber numberWithInteger:NSUnderlineStyleSingle]}; //下划线 NSDictionary *attribtDic {NSUnderlineStyleAttributeName: [NSNumber numberWithInteger:NSUnderlineS…