RNN和LSTM初级配方炼丹对比实验(Keras)
文章目录
参考教程:
一、莫烦大佬的教程:
https://morvanzhou.github.io/tutorials/machine-learning/keras/2-4-RNN-classifier/
二、《21个项目玩转深度学习-基于TensorFlow的实践详解》
其实概念性的理解,个人觉得,还是得看看书,虽然很多人(包括我)也诟病一些中文书就知道翻译,但是有些书在入门阶段,作为完整、快速的理解一门新的知识,真的是最佳的手段了。
有些书就包括这本。
前言
还是得扯扯有的没的,目前我知道的几个主要的深度学习分支如下:
后面的几个经典算法,我没完全跟的上,简单写了一些。
所以发现,这四个大方向,是很有趣的。
作为一个智能体,需要哪些功能,才能完成一个比较健全的任务呢?
感知、记忆、决策、自我意识等功能都应该得有吧?
计算机视觉一般主要用作提取特征,作为视觉感知模块;
循环一般主要用作时间序列,可以处理像语言、股票等时序任务,也算是一种记忆感知,其实我现在一直不明白,有什么样的网络可以实现:这件东西我曾经见过的!这件东西是啥?的功能,感觉传统的分类网络应该不算,或者最后的输出结构不应该是那样的,直接预测出是什么种类,应该还得有一些其他的类似于人认知的功能,比如结合知识图谱?;
强化学习的前端是全连接,或者是卷积,那么是用到了计算机视觉的感知功能。最重要的部分其实是后面的决策模块(可以理解为actor最后面的全连接层,或者加上critic对actor的更新),基于当前感知做决策,以及根据环境反馈,对actor决策进行更新的critic。这样就完成了决策任务了。
生成对抗网络我不太熟悉,所以我就无法描述了,但是今天在“逆强化学习”的课程中,李宏毅老师说,其实inverse reinforcement learning的frame跟gan的就很像很像,所以感觉思路都是交叉的。如果要想在这方面深耕的话,是没有办法只关注于一个领域的。
毕竟智能需要各方面的整合才行。
OK,那么说说我为啥要学RNN。
RNN太重要了呀,强化学习处理的本来就是时序问题,虽然通过整个结构的循环可以处理一些时序的问题,但是如果能直接在感知部分直接提取时序相关的信息,岂不是更合适?
之前那篇自我感知的小机械臂用的就有一个循环感知的过程,直接提取连续五步的状态。
所以还是得学习一下的。
RNN的基础知识
这个比较坑,今天就不在博客上说了,大家可以自己搜一些其他的资料;
或者直接去看那本书。
实验部分:
实验描述:
将mnist数据集分为28*28.第一个28为time_step,第二个是输入数据向量维度为28.
大致的效果是将一张这样的图:
从上往下拆分,每次只输入RNN网络中一行的数据,分28步输入进去。
然后通过RNN网络的权重进行计算后,输出的维度为隐层数。
最后将最后一步的输出接上全连接网络,再接softmax,进行分类预测。
LSTM的输入输出模型差不多,内部细节可以另看其他资料。
数据集:
Mnist数据集
LSTM-40-mnist-Code:
import numpy as np
np.random.seed(1337)
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, SimpleRNN, Activation
from keras.optimizers import Adam
TIME_STEPS = 28
TIME_INPUT_SIZE = 28
BATCH_SIZE = 32
BATCH_INDEX = 0
OUTPUT_SIZE = 10
CELL_SIZE = 40
LR = 0.001
(x_train,y_train),(x_test,y_test) = mnist.load_data()
# data pre-processing
x_train = x_train.reshape(-1, 28, 28) / 255. # normalize
x_test = x_test.reshape(-1, 28, 28) / 255. # normalize
y_train = np_utils.to_categorical(y_train, num_classes=10)
y_test = np_utils.to_categorical(y_test, num_classes=10)
print(x_train.shape)
print(y_train.shape)
model = Sequential()
model.add(SimpleRNN(
batch_input_shape=(None, TIME_STEPS, TIME_INPUT_SIZE),
# output_dim是隐层节点数目,控制了网络的拟合能力和每次状态输出的维度!
output_dim=CELL_SIZE,
unroll=True,
))
model.add(Dense(OUTPUT_SIZE, activation='softmax'))
adam = Adam(LR)
model.compile(optimizer=adam, loss='categorical_crossentropy', metrics=['accuracy'])
import time
import matplotlib.pyplot as plt
train_cost = []
train_accuracy = []
test_cost = []
test_accuracy = []
start_time = time.time()
for step in range(4001):
x_batch = x_train[BATCH_INDEX: BATCH_INDEX+BATCH_SIZE, :, :]
y_batch = y_train[BATCH_INDEX: BATCH_INDEX+BATCH_SIZE, :]
cost, accuracy = model.train_on_batch(x_batch, y_batch)
train_cost.append(cost)
train_accuracy.append(accuracy)
BATCH_INDEX += BATCH_SIZE
if BATCH_INDEX >= x_train.shape[0]:
BATCH_INDEX=0
if step%50==0:
print("step:", step)
print("cost:", cost)
cost,accuracy = model.evaluate(x_test, y_test, batch_size=y_test.shape[0], verbose=False)
test_cost.append(cost)
test_accuracy.append(accuracy)
print('test cost: ', cost, 'test accuracy: ', accuracy)
print("epoch_time:",(time.time()-start_time)/4001)
plt.figure(num = 1)
plt.ion()
plt.xlabel('epoch')
plt.ylabel('loss and accuracy')
plt.plot(train_cost, label = "loss")
plt.plot(train_accuracy, label = "accuracy")
plt.legend(loc = "best")
plt.show()
plt.figure(num = 2)
plt.ion()
plt.xlabel('epoch')
plt.ylabel('loss and accuracy')
plt.plot(test_cost, label = "loss")
plt.plot(test_accuracy, label = "accuracy")
plt.legend(loc = "best")
plt.show()
实验内容:
测试LSTM和simpleRNN对精度和时间的影响。
以及隐层节点数变化对精度和时间的影响。
猜想:LSTM更强。时间也长一些。
节点数越多,精度越高
实验结果:
LSTM-80
test cost: 0.11618449538946152
test accuracy: 0.9639999866485596
epoch_time: 0.04046541754825805
LSTM-40
test cost: 0.20324485003948212
test accuracy: 0.9412999749183655
epoch_time: 0.04428503430506433
Epoch=4001/lr=0.001 | RNN-40 | RNN-80 | LSTM-40 | LSTM-80 |
---|---|---|---|---|
Test cost | 0.3496 | 0.208 | 0.203 | 0.1162 |
Test accuracy | 0.9036 | 0.943 | 0.9412 | 0.964 |
Epoch time | 0.0101 | 0.0104 | 0.0443 | 0.0404 |
表格分析:
由上面的表格可以看出来以下几点:
-
simpleRNN的训练时间确实要少很多,是LSTM的四分之一。
-
但是cell_size对训练的时间影响并不大。
-
另外可以看出来LSTM的训练精度确实比simpleRNN要好一些。
-
在同样的节点数40时,精度提高了四个点,节点数80时上升2个点。
-
节点数对精度的提升也很明显,simpleRNN中40-80的差距是4个点,LSTM的40-80的差距是2个点。
但是可以从训练过程中可以看出,精度和loss的波动比较大。如下图——
训练过程记录
lstm-40-train-accuracy-loss-graph-epoch-40001
lstm-40-test-accuracy-loss-graph-epoch-40001
这里的epoch-80是不对的,因为每50个train-epoch才测试一次,因此下面的每个epoch数字需要做一个变换。
也许每个train-epoch都测试的话,可能波动也比较大了。
好了,我又跑了一遍,发现波动性确实蛮大的:
但是大概的趋势还可以,是不是跟优化策略有关?我试试其他的?
SGD-不收敛
只将优化器换成了SGD,学习率都没变,仍然是0.001。那就只能再整一下,加点动量。
SGD加动量和牛顿什么的
加了动量=0.9和牛顿=true之后,可以达到下面的效果:
test cost: 0.9125387668609619 test accuracy: 0.7081999778747559
SGD加动量不加牛顿~
test cost: 0.9364890456199646 test accuracy: 0.7028999924659729
epoch_time: 0.1839553209818235
反正SGD确实没有Adam好,至少在这个任务,这个数据集下,是这样的~