使用RNN進行imdb影評情感識別--use RNN to sentiment analysis
原創帖子,轉載請說明出處
一、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基礎的旁友觀