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好,至少在這個任務,這個數據集下,是這樣的~