啊!好久沒有實作了,不曉得各位還記不記得怎麼寫 Python 呢?今天的這篇文章將主要以實作為主,簡單地介紹如何搭建出我們在過去幾天的旅程中,學到的那些形形色色的深度學習模型:LSTM、GRU,以及兩者的雙向版本,也就是BiLSTM、以及BiGRU。不過,你可能已經發現,咦?那單純的 RNN 呢?事實上,在自然語言處理的實務中,由於先前提過的那些缺失,如記性不好等問題,已經很少人使用單純的 RNN 來完成任務了。欸!別人都是一篇一個神經網路,我直接一篇全部寫完,超值吧!還不趕快再點一下我其他文章!
不過在開始弄髒你的手實際上工之前,我們得先了解今天要用的工具有哪些。
今天要使用的工具箱 對於一些可能從未寫過程式的朋友,可能會有一些疑慮,擔心說「我們該不會要從零開始搭神經網路吧?先前介紹過的那些輸出層、輸入層、隱藏層殺毀的,我們都要從頭開始做起嗎?別吧?」接著擺出了 No No No 的手勢。
事實上,像這種這麼常用的深度學習工具,不可能沒有前人寫過。所謂前人種樹,後人乘涼,在過去就已經有程式大神代替我們將這些深度學習以及神經網路整理成 API 了。什麼?你說什麼是API?沒事,你只需要理解因為某邪惡大神的建樹,我們只需要簡單地引入(import
)工具箱後,這些神經網路就可以隨取隨用了。我想,最多只需要調參數、以及疊各種隱藏層吧?而我今天就會一步一步地仔細帶領你撰寫搭建模型的程式,並逐句介紹這些程式語言在做什麼。至於是哪個大神如此邪惡,擁有幾乎全世界所有網頁的資料,又有極大量的運算資源?其實也沒有別人了,就是:
Tensorflow Tensorflow 是一個開源的深度學習程式庫,並利用機器學習來完成各種人工智慧的下游任務,例如:圖像辨識,還有我們的重點,自然語言處理。你現在所用的幾乎所有 Google 的服務,舉凡如 Google 搜尋、Google 翻譯(乙定要有的吧!)、GOogle 語音辨識、Google 地圖、Google 相片,都是來自於利用 Tensorflow 的深度學習框架所打造而成的。換句話說,我們其實就是站在 Google 打造好的立足點來解決自然語言處理的應用。
LSTM 首先,在程式檔的頂端,我們得先引用搭建神經網路所需要的工具箱,也就是 Tensorflow。今天,我們會直接使用 tensorflow 內建的 imdb 資料集。資料科學的前輩對imdb資料一定又愛又恨吧!
1 2 3 4 5 6 7 8 9 import tensorflow as tffrom tensorflow.keras.datasets import imdb from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense from tensorflow.keras.layers import LSTM from tensorflow.keras.layers import Embedding from tensorflow.keras.preprocessing import sequence tf.random.set_seed(7 )
再來得將資料先處理好,我們在這邊先將資料處理好之後,後續在搭建無論是 GRU,甚至是BiLSTM、BiGRU,都會直接用這裡的資料,就不會再重複這裡的動作啦!
1 2 3 4 5 6 7 8 top_words = 5000 (X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=top_words) max_review_length = 500 X_train = sequence.pad_sequences(X_train, maxlen=max_review_length) X_test = sequence.pad_sequences(X_test, maxlen=max_review_length)
接著要先搭建模型,搭建完模型之後才會開始訓練。
1 2 3 4 5 6 7 8 9 10 11 12 13 embedding_vector_length = 32 lstm_model = Sequential() lstm_model.add(Embedding(top_words, embedding_vector_length, input_length=max_review_length)) lstm_model.add(LSTM(100 )) lstm_model.add(Dense(1 , activation='sigmoid' )) lstm_model.compile (loss='binary_crossentropy' , optimizer='adam' , metrics=['accuracy' ]) print (lstm_model.summary())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding (Embedding) (None, 500, 32) 160000 lstm (LSTM) (None, 100) 53200 dense (Dense) (None, 1) 101 ================================================================= Total params: 213,301 Trainable params: 213,301 Non-trainable params: 0 _________________________________________________________________ None
我們從params
中可以看到模型總共有多少個參數。另外,在 LSTM 中的參數決定的是神經元數量,沒有一定的固定數字,但是有個模式可循。首先,RNN 的寬度代表特徵的多寡,由輸入以及篩選器的數量決定;深度代表的則是特徵的豐富度,由神經網路層數及步驟數決定的。若不需要從原資料產出大量特徵,那麼一般來說寬度會減少。若資料相對單純,那麼深度則需要調整的淺一點,這麼做可以節省訓練時間及資源。(source )
確認沒問題之後,就可以開始訓練模型了!這裡可能會需要跑比較久時間,像我試跑就跑了十分多鐘,所以才說深度學習模型的一個缺點就是速度比較慢一點。
1 2 3 model.fit(X_train, y_train, epochs=3 , batch_size=64 ) scores = model.evaluate(X_test, y_test, verbose=0 ) print ("Accuracy: %.2f%%" % (scores[1 ]*100 ))
1 2 3 4 5 6 7 Epoch 1/3 391/391 [==============================] - 207s 525ms/step - loss: 0.4316 - accuracy: 0.7884 Epoch 2/3 391/391 [==============================] - 205s 525ms/step - loss: 0.2653 - accuracy: 0.8937 Epoch 3/3 391/391 [==============================] - 204s 522ms/step - loss: 0.2377 - accuracy: 0.9065 Accuracy: 86.72%
BiLSTM 其實雙向的 BiLSTM 也是大同小異,我們只需要關注模型的搭建上就可以了。資料一樣沿用在上面所整理好的訓練以及測試資料集。別忘了要先引進雙向的套件,至於其他的套件,在前面就已經引進過,就不需要再引進了。
1 from tensorflow.keras.layers import Bidirectional
1 2 3 4 5 6 bilstm_model = Sequential() bilstm_model.add(Embedding(top_words, embedding_vetcor_length, input_length=max_review_length)) bilstm_model.add(Bidirectional(LSTM(100 , dropout=0.2 , recurrent_dropout=0.2 ))) bilstm_model.add(Dense(1 , activation='sigmoid' )) bilstm_model.compile (loss='binary_crossentropy' , optimizer='adam' , metrics=['accuracy' ]) print (bilstm_model.summary())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding_1 (Embedding) (None, 500, 32) 160000 bidirectional (Bidirectiona (None, 200) 106400 l) dense_1 (Dense) (None, 1) 201 ================================================================= Total params: 266,601 Trainable params: 266,601 Non-trainable params: 0 _________________________________________________________________ None
1 2 3 bilstm_model.fit(X_train, y_train, epochs=3 , batch_size=64 ) scores = bilstm_model.evaluate(X_test, y_test, verbose=0 ) print ("Accuracy: %.2f%%" % (scores[1 ]*100 ))
1 2 3 4 5 6 7 Epoch 1/3 391/391 [==============================] - 805s 2s/step - loss: 0.4870 - accuracy: 0.7579 Epoch 2/3 391/391 [==============================] - 803s 2s/step - loss: 0.3148 - accuracy: 0.8726 Epoch 3/3 391/391 [==============================] - 799s 2s/step - loss: 0.2637 - accuracy: 0.8944 Accuracy: 87.89%
BiLSTM 因為參數更多,所以訓練時間又很明顯地變更久了。我在這裡花了快20多分鐘在訓練模型。
GRU 1 2 3 4 5 6 7 gru_model = Sequential() gru_model.add(Embedding(top_words, embedding_vector_length, input_length=max_review_length)) gru_model.add(GRU(32 )) gru_model.add(Dense(10 , activation='relu' )) gru_model.add(Dense(1 , activation='sigmoid' )) gru_model.compile (loss="binary_crossentropy" , optimizer='adam' ,metrics=['accuracy' ]) print (gru_model.summary())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding_2 (Embedding) (None, 500, 32) 160000 gru (GRU) (None, 32) 6336 dense_2 (Dense) (None, 10) 330 dense_3 (Dense) (None, 1) 11 ================================================================= Total params: 166,677 Trainable params: 166,677 Non-trainable params: 0 _________________________________________________________________
1 2 3 gru_model.fit(X_train, y_train, epochs=3 , batch_size=64 ) scores = gru_model.evaluate(X_test, y_test, verbose=0 ) print ("Accuracy: %.2f%%" % (scores[1 ]*100 ))
1 2 3 4 5 6 7 Epoch 1/3 391/391 [==============================] - 89s 222ms/step - loss: 0.4658 - accuracy: 0.7620 Epoch 2/3 391/391 [==============================] - 88s 226ms/step - loss: 0.2631 - accuracy: 0.8943 Epoch 3/3 391/391 [==============================] - 88s 224ms/step - loss: 0.2215 - accuracy: 0.9149 Accuracy: 87.74%
GRU 模型當初有說,其實設計架構上與 LSTM 差不了多少,但是由於 GRU 的參數相對比較少的緣故,所以運算時間還有資源都比原本的 LSTM 還要少。在準確度皆為接近 90% 的前提下,我在前面訓練 LSTM 的時間為十一分鐘左右,而這裡 GRU 我卻只需要五分多鐘就結束訓練了。
1 2 3 4 5 6 7 bigru_model = Sequential() bigru_model.add(Embedding(top_words, embedding_vector_length, input_length=max_review_length)) bigru_model.add(Bidirectional(GRU(32 ))) bigru_model.add(Dense(10 , activation='relu' )) bigru_model.add(Dense(1 , activation='sigmoid' )) bigru_model.compile (loss="binary_crossentropy" , optimizer='adam' ,metrics=['accuracy' ]) bigru_model.summary()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Model: "sequential_3" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding_3 (Embedding) (None, 500, 32) 160000 bidirectional_1 (Bidirectio (None, 64) 12672 nal) dense_4 (Dense) (None, 10) 650 dense_5 (Dense) (None, 1) 11 ================================================================= Total params: 173,333 Trainable params: 173,333 Non-trainable params: 0 _________________________________________________________________
1 2 3 bigru_model.fit(X_train, y_train, epochs=3 , batch_size=64 ) scores = bigru_model.evaluate(X_test, y_test, verbose=0 ) print ("Accuracy: %.2f%%" % (scores[1 ]*100 ))
1 2 3 4 5 6 7 Epoch 1 /3 391 /391 [==============================] - 166s 414ms/step - loss: 0.4397 - accuracy: 0.7790 Epoch 2 /3 391 /391 [==============================] - 160s 408ms/step - loss: 0.2599 - accuracy: 0.8975 Epoch 3 /3 391 /391 [==============================] - 159s 407ms/step - loss: 0.2170 - accuracy: 0.9153 Accuracy: 87.74 %
BiGRU 的模型訓練時間跟 BiLSTM 相比就更明顯了,BiLSTM 我當初花了 40 分鐘左右才訓練完成,反觀 BiGRU,只需要 9 分鐘左右就結束了,模型表現卻也都差不多。
結語 我們最後來看一下結果,可以發現四種表現都沒有差距太大,但訓練時間就有明顯的差異,也就是 GRU 的時間還要少於 LSTM;另外,雙向的神經網路模型表現也比單向還要好一些。
LSTM
BiLSTM
GRU
BiGRU
準確度 (%)
86.72
87.89
87.74
87.74
時間 (min)
11
19
5.5
9
這也印證了在先前 【NLP】Day 17: 每天成為更好的自己!神經網路也是!深度學習模型 GRU 的文章中所說,參數的多寡會大大影響著運算時間以及資源。好,神經網路的實作就到這邊,是不是比想像中的還要簡單很多呢?明天開始就要進入 BERT 了喔!