循环计算过程(1pre1)
RNN 最典型的应用就是利用历史数据预测下一时刻将发生什么,即根据以前见过的历史规律做预测
例子:
计算机不认识字母,只能处理数字。所以需要我们对字母进行编码。这里假设使用独热编码(实际中可使用其他编码方式),编码结果如图1.2.7所示。
词向量空间:

假设使用一层 RNN 网络,记忆体的个数选取 3,则字母预测的网络如图 1.2.8所示。假设输入字母 b,即输入𝑥𝑡为[0,1,0,0,0],这时上一时刻的记忆体状态信息ℎ𝑡−1 为 0。由上文理论知识不难得到:
h𝑡 = tanh( 𝑥𝑡𝑤𝑥ℎ+ℎ𝑡−1wℎh + 𝑏) =tanh([−2.3 0.8 1.1 ] + 0 + [ 0.5 0.3 − 0.2]) =tanh[−1.8 1.1 0.9 ] = [−0.9 0.8 0.7]
这个过程可以理解为脑中的记忆因为当前输入的事物而更新了。
输出y𝑡 是把提取到的时间信息通过全连接进行识别预测的过程,是整个网络的输出层。不难知道,
y𝑡 = softmax(ℎ𝑡𝑤ℎ𝑦 + 𝑏y) = softmax([−0.7 − 0.6 2.9 0.7 −0.8] + [ 0.0 0.1 0.4 − 0.7 0.1]) = softmax([−0.7 − 0.5 3.3 0.0 − 0.7]) =[0.02 0.02 0.91 0.03 0.02 ] 。
可见模型认为有 91%的可能性输出字母 c ,所以循环网络输出了预测结果 c。

构建模型:一个具有 3 个记忆体的循环层+一层全连接->Compile->fit->summary。
input_word = 'abcde'
# 单词映射到数值id的字典
w_to_id = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4}
# id编码为one_hot
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.]}
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)
# 使x_train符合SimpleRNN输入要求:[送入样本数, 循环核时间展开步数, 每个时间步输入特征个数]。
# 此处整个数据集送入,送入样本数为len(x_train);输入1个字母出结果,循环核时间展开步数为1; 表示为独热码有5个输入特征,每个时间步输入特征个数为5
x_train = np.reshape(x_train, (len(x_train), 1, 5))
y_train = np.array(y_train)
# 逐层搭建网络,设计一个3个记忆体的循环层+一个全连接层
model = tf.keras.Sequential([SimpleRNN(3), 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)
# 保存模型,借助tensorflow给出的回调函数,直接保存参数和网络
'''
monitor 配合 save_best_only 可以保存最优模型,包括:训练损失最小模型、测试损失最小模型、训练准确率最高模型、测试准确率最高模型等。
'''
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()
# 参数提取,写到weights.txt文本中
file = open('./weights.txt', 'w')
# model.trainable_variables 返回模型中可训练的参数
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 alphbet:'))
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个输入特征,每个时间步输入特征个数为5
alphabet = np.reshape(alphabet, (1, 1, 5))
result = model.predict([alphabet])
pred = tf.argmax(result, axis=1)
pred = int(pred)
tf.print(alphabet1 + '->' + input_word[pred])
输出结果:


模型已经保存下来了

weights.txt内容

再运行一次,就是断点续训,就是利用上次保存模型的最优的参数,再次训练


可以看到模型已经训练的非常好了。

浙公网安备 33010602011771号