原創帖子,轉載請說明出處
一、RNN神經網絡結構
RNN隱藏層神經元的連接方式和普通神經網路的連接方式有一個非常明顯的區別,就是同一層的神經元的輸出也成為了這一層神經元的輸入。當然同一時刻的輸出是不可能作為這個時刻的輸入的。所以是前一個時刻(t-1)的輸出作為這個時刻(t)的輸入。
序列結構展開示意圖,s為隱藏層,o為輸出層,x為輸入層,U為輸入層到隱層的權重矩陣,V則是隱層到輸出層的權重矩陣,這個網絡在t時刻接收到輸入 之后,隱藏層的值是
,輸出值是
。關鍵一點是,
的值不僅僅取決於
,還取決於
。
二、RNN應用范圍
RNNs主要用於處理NLP類的問題,如詞向量表達、語句合法性檢查、詞性標注等。在RNNs中,目前使用最廣泛最成功的模型便是LSTMs(Long Short-Term Memory,長短時記憶模型)模型,該模型通常比vanilla RNNs能夠更好地對長短時依賴進行表達,該模型相對於一般的RNNs,只是在隱藏層做了手腳。下篇文章會對LSTM進行介紹。
三、使用RNN進行影評情感分析
0x00 實驗環境
tensorflow2.0,此版本的keras已經被包含到tf中,導入keras時注意加入tensorflow前綴,如果想關閉vision2.0版本的特性的話,可以使用:
import tensorflow.compat.v1 as tf tf.disable_v2_behavior()
0x01 數據預處理
導入數據集和相應的庫,這里使用imdb數據集
#導入imdb影評庫
from tensorflow.keras.datasets import imdb from tensorflow.keras.preprocessing import sequence
之后我們對數據集與訓練集進行划分,下面的vocab_num代表着我要從imdb數據庫中導入10000條數據,第二行的左括號與右括號代表訓練集與測試集的划分
#划分訓練集與測試集 #label中的0代表消極,1代表積極
vocab_num=10000 (X_train,y_train),(X_test,y_test)=imdb.load_data(num_words=vocab_num) print("----review----") print(X_train[5]) print("----label-----") print(y_train[5])
打印結果
----review---- [1, 6740, 365, 1234, 5, 1156, 354, 11, 14, 5327, 6638, 7, 1016, 2, 5940, 356, 44, 4, 1349, 500, 746, 5, 200, 4, 4132, 11, 2, 9363, 1117, 1831, 7485, 5, 4831, 26, 6, 2, 4183, 17, 369, 37, 215, 1345, 143, 2, 5, 1838, 8, 1974, 15, 36, 119, 257, 85, 52, 486, 9, 6, 2, 8564, 63, 271, 6, 196, 96, 949, 4121, 4, 2, 7, 4, 2212, 2436, 819, 63, 47, 77, 7175, 180, 6, 227, 11, 94, 2494, 2, 13, 423, 4, 168, 7, 4, 22, 5, 89, 665, 71, 270, 56, 5, 13, 197, 12, 161, 5390, 99, 76, 23, 2, 7, 419, 665, 40, 91, 85, 108, 7, 4, 2084, 5, 4773, 81, 55, 52, 1901] ----label-----
1
上面打印結果顯示的數字代表着字典中對應單詞的索引,我們使用下面的代碼來找出每個索引對應的詞
word2id = imdb.get_word_index() id2word = {i: word for word,i in word2id.items()} print('---review with word---') print([id2word.get(i, '') for i in X_train[6]])
為了讓數據能夠輸入 RNN 模型,所有的輸入文檔必須有相同的長度。我們需要設置max_words變量來限制評論的最大長度,超過該長度的評論將被截斷,不足該長度的評論將被填充空值(0)。在 Keras 中,我們可以使用pad_sequences()函數來達到此目標。現在設置max_words變量的值為 500。
from tensorflow.keras.preprocessing.sequence import pad_sequences max_words=500 X_train = pad_sequences(X_train, maxlen=max_words) X_test = pad_sequences(X_test, maxlen=max_words)
0x02 模型建立
from tensorflow.keras import Sequential from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout embedding_size = 32 model=Sequential() model.add(Embedding(vocab_num,embedding_size, input_length= max_words)) model.add(LSTM(100)) model.add(Dense(1, activation='sigmoid')) print(model.summary())
這里逐個解釋一下每個參數的情況。這幾步為建立神經網絡的基本流程。
(1)首先,embedding_size,是第六行嵌入層的一個參數,嵌入層,要了解它,首先要知道詞嵌入,這里以https://juejin.im/entry/5acc23f26fb9a028d1416bb3 這篇文章來簡單介紹一下詞嵌入以及embedding層的作用。詞嵌入是對傳統的詞袋模型編碼方案的改進,詞袋模型可以看這篇https://www.cnblogs.com/chenyusheng0803/p/10978883.html ,
在嵌入中,單詞由密集向量表示,其中向量表示將單詞投影到連續向量空間中。向量空間中的單詞的位置是從文本中學習的,並且基於在使用單詞時圍繞單詞的單詞。學習到的向量空間中的單詞的位置被稱為它的嵌入:Embedding。通俗的說,就是以一種比較准確的方式表達詞的位置。
Keras提供了一個嵌入層,適用於文本數據的神經網絡。它要求輸入數據是整數編碼的,所以每個字都用一個唯一的整數表示。例如我們這篇文章說到的imdb的詞庫中每個數字代表的詞。嵌入層用隨機權重進行初始化,並將學習訓練數據集中所有單詞的嵌入。
嵌入層被定義為網絡的第一個隱藏層。它必須指定3個參數:
- input_dim:這是文本數據中詞匯的取值可能數。例如,如果您的數據是整數編碼為0-9之間的值,那么詞匯的大小就是10個單詞;
- output_dim:這是嵌入單詞的向量空間的大小。它為每個單詞定義了這個層的輸出向量的大小。例如,它可能是32或100甚至更大,可以視為具體問題的超參數;
- input_length:這是輸入序列的長度,就像您為Keras模型的任何輸入層所定義的一樣,也就是一次輸入帶有的詞匯個數。例如,如果您的所有輸入文檔都由1000個字組成,那么input_length就是1000。
因此,這里的embedding_size就是嵌入單詞的向量空間大小,同時,嵌入層的輸出是一個二維向量,每個單詞在輸入文本(輸入文檔)序列中嵌入一個。
(2)sequential()
Keras有兩種類型的模型,序貫模型(Sequential)和函數式模型(Model),函數式模型應用更為廣泛,序貫模型是函數式模型的一種特殊情況。sequential model就是那種最簡單的結構的模型。按順序一層一層訓練,一層一層往前的那種。沒有什么環的結構。比如像前饋網絡那樣。Keras 的核心數據結構是“模型”,模型是一種組織網絡層的方式。Keras 中主要的模型是 Sequential 模型,Sequential 是一系列網絡層按順序構成的棧。
(3) 之后加入LSTM
Keras中的LSTM函數參數可以參考這篇文章:https://blog.csdn.net/jiangpeng59/article/details/77646186 ,這里的100是指輸出維度為100
(4)Dense層
這里的DENSE層添加了激活函數為sigmoid,Dense層的詳細知識可以見:https://blog.csdn.net/m0_37592397/article/details/79982601
(5)model.summary是指展示model的層數現狀,這里的顯示結果為:
Model: "sequential"
_________________________________________________________________ Layer (type) Output Shape Param #
================================================================= embedding (Embedding) (None, 500, 32) 320000
_________________________________________________________________ lstm (LSTM) (None, 100) 53200
_________________________________________________________________ dense (Dense) (None, 1) 101
================================================================= Total params: 373,301 Trainable params: 373,301 Non-trainable params: 0 _________________________________________________________________ None
0x03 模型訓練
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) from tensorflow.keras.callbacks import EarlyStopping #from tensorboardcolab import TensorBoardColab #tbc = TensorBoardColab()
es = EarlyStopping(monitor = "val_loss", patience = 10) batch_size = 64 num_epochs = 10 X_valid, y_valid = X_train[:batch_size], y_train[:batch_size] X_train2, y_train2 = X_train[batch_size:], y_train[batch_size:] model.fit(X_train2, y_train2, validation_data=(X_valid, y_valid), batch_size=batch_size, epochs=num_epochs, callbacks = [es])
(1)model.compile
這個函數主要為設置損失函數和優化器及評估標准。參數設置如下:
- 優化器 optimizer。它可以是現有優化器的字符串標識符,如
rmsprop
或adagrad
,也可以是 Optimizer 類的實例。詳見:optimizers。 - 損失函數 loss,模型試圖最小化的目標函數。它可以是現有損失函數的字符串標識符,如
categorical_crossentropy
或mse
,也可以是一個目標函數。詳見:losses。 - 評估標准 metrics。對於任何分類問題,你都希望將其設置為
metrics = ['accuracy']
。評估標准可以是現有的標准的字符串標識符,也可以是自定義的評估標准函數
(2)earlystipping
這個為keras封裝的回調函數,具體信息可以查看https://keras.io/zh/callbacks/,具體的作用為當被監測的數量不再提升,則停止訓練
(3)batch_size,num_epochs
簡單說,epochs 指的就是訓練過程中數據將被“輪詢”多少次。
深度學習的優化算法,說白了就是梯度下降。每次的參數更新有兩種方式。
第一種,遍歷全部數據集算一次損失函數,然后算函數對各個參數的梯度,更新梯度。這種方法每更新一次參數都要把數據集里的所有樣本都看一遍,計算量開銷大,計算速度慢,不支持在線學習,這稱為批梯度下降(Batch gradient descent)。
另一種,每看一個數據就算一下損失函數,然后求梯度更新參數,這個稱為隨機梯度下降(stochastic gradient descent)。這個方法速度比較快,但是收斂性能不太好,可能在最優點附近晃來晃去,達不到最優點。兩次參數的更新也有可能互相抵消掉,造成目標函數震盪的比較劇烈。
為了克服兩種方法的缺點,現在一般采用的是一種折中手段,小批的梯度下降(mini-batch gradient decent),這種方法把數據分為若干個批,按批來更新參數,這樣,一個批中的一組數據共同決定了本次梯度的方向,下降起來就不容易跑偏,減少了隨機性。另一方面因為批的樣本數與整個數據集相比小了很多,所以計算量也不是很大。基本上現在的梯度下降都是基於 mini-batch 的,所以 Keras 的模塊中經常會出現 batch_size
,就是指這個。
(4)model.fit函數啟動訓練
0x04 模型評估
scores = model.evaluate(X_test, y_test, verbose=0) print('Test accuracy:', scores[1])
(1)verbose
verbose:日志顯示,verbose = 0 為不在標准輸出流輸出日志信息,verbose = 1 為輸出進度條記錄,verbose = 2 為每個epoch輸出一行記錄
0x05 全部代碼
因為懶所以麻煩各位自己復制整合了
四、總結
RNN的基本實踐流程如上,這是網咯上大部分文章共同流傳的一個python代碼的例子,我這里將每一行代碼進行講解,適用於具備一丁點ML或者DL基礎的旁友觀看。