前言
情緒分析 (sentiment analysis) 又稱為意見探勘 (opinion mining). 是使用 "自然語言處理", 文字分析等方法, 找出作者某些話題上的態度, 情感, 評價或情緒. 情緒分析的商業價值, 可以提早得知顧客對公司或產品觀感, 以調整銷售策略方向. IMDb 網路資料庫 (Internet Movie Database), 是一個電影相關的線上資料庫. IMDb 開始於 1990 年, 自 1998 年起成為亞馬遜旗下的網站, 至今已經累積大量的電影資訊. IMDb 共收錄了四百多萬作品資料.
IMDb 資料集共有 50,000 筆 "影評文字", 分為訓練資料與測試資料各 25,000 筆, 每一筆 "影評文字" 都被標記成 "正面評價" 或 "負面評價". 我們希望能建立一個模型, 經過大量 "影評文字" 訓練後, 此模型能用於預測 "影評文字" 是 "正面評價" 或 "負面評價". 如下面深度學習模型用於辨識 IMDb "影評文字", 可分為訓練與預測階段:
Keras 自然語言處理介紹
Keras 自然語言處理 IMDb 影評文字步驟如下:
下載 IMDB 資料集
下載讀取 IMDB 資料集 (http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz), 分為訓練與測試資料:
- ch13_1.py (link)
- #!/usr/bin/env python3
- import os, urllib, logging
- import tarfile
- from urllib.request import urlretrieve
- ###################
- # Step0: Global setting
- ####################
- LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
- logging.basicConfig(format=LOG_FORMAT)
- logger = logging.getLogger('IMDBb')
- logger.setLevel(logging.DEBUG)
- ###################
- # Step1: Download IMDB
- ####################
- url = "http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz"
- filepath = 'datas/aclImdb_v1.tar.gz'
- dataPath = 'datas/aclImdb'
- if not os.path.isfile(filepath):
- print('Downloading from {}...'.format(url))
- result = urlretrieve(url, filepath)
- print('download: {}'.format(result))
- if not os.path.isdir(dataPath):
- print('Extracting {} to datas...'.format(filepath))
- tfile = tarfile.open(filepath, 'r:gz')
- result = tfile.extractall('datas/')
讀取 IMDB 資料
這邊將建立函數來讀入影評文件提供後續訓練與測試使用:
- ###################
- # Step2: Download IMDB
- ####################
- from keras.preprocessing import sequence
- from keras.preprocessing.text import Tokenizer
- import re
- def rm_tags(text):
- r'''
- Remove HTML markers
- '''
- re_tag = re.compile(r'<[^>]+>')
- return re_tag.sub('', text)
- def read_files(filetype):
- r'''
- Read data from IMDb folders
- @param filetype(str):
- "train" or "test"
- @return:
- Tuple(List of labels, List of articles)
- '''
- file_list = []
- positive_path = os.path.join(os.path.join(dataPath, filetype), 'pos')
- for f in os.listdir(positive_path):
- file_list.append(os.path.join(positive_path, f))
- negative_path = os.path.join(os.path.join(dataPath, filetype), 'neg')
- for f in os.listdir(negative_path):
- file_list.append(os.path.join(negative_path, f))
- logger.debug('Read {} with {} files...'.format(filetype, len(file_list)))
- all_labels = ([1] * 12500 + [0] * 12500)
- all_texts = []
- for fi in file_list:
- logger.debug('Read {}...'.format(fi))
- with open(fi, encoding='utf8') as fh:
- all_texts += [rm_tags(" ".join(fh.readlines()))]
- return all_labels, all_texts
- train_labels, train_text = read_files('train')
- test_labels, test_text = read_files('test')
讀進 IMDb 資料集進入記憶體後, 接著我們便可以如下查看影評文字:
建立 Token
接下來將介紹如何建立 Token 以及 Token 的特性.
- ###################
- # Step3: Tokenize
- ####################
- MAX_LEN_OF_TOKEN = 100
- logger.info('Tokenizing document...')
- token = Tokenizer(num_words = 2000)
- ''' Create a dictionary of 2,000 words '''
- token.fit_on_texts(train_text)
- ''' Read in all training text and select top 2,000 words according to frequency sorting descendingly '''
- logger.info('Total {} document being handled...'.format(token.document_count))
- logger.info('Top 10 word index:')
- c = 0
- for t,i in token.word_index.items():
- print("\t'{}'\t{}".format(t, i))
- c += 1
- if c == 10:
- break
- print("")
- logger.info('Translating raw text into token number list...')
- x_train_seq = token.texts_to_sequences(train_text)
- x_test_seq = token.texts_to_sequences(test_text)
- logger.info('Padding/Trimming the token number list to same length={}...'.format(MAX_LEN_OF_TOKEN))
- x_train = sequence.pad_sequences(x_train_seq, maxlen=MAX_LEN_OF_TOKEN)
- x_test = sequence.pad_sequences(x_test_seq, maxlen=MAX_LEN_OF_TOKEN)
前面已經完成 IMDb 資料的前處理, 接著我們便可以使用 Keras 來建立多層感知器 (MLP), 遞歸神經網路 RNN (Recurrent Neural Network), 短期記憶 LSTM (Long-Short Term Memory) 的模型, 進行 IMDb 情緒分析並且訓練模型已進行預測.
建立 MLP 模型
底下代碼依序進行:
1. 建立 Embedding 層: 將 "數字 list" 轉為 "向量 list". (這邊使用 32 維度來表式數字 1-2000)
2. 建立多層感知器 (MLP):
- ###################
- # Step4: Building MODEL
- ####################
- from keras.models import Sequential
- from keras.layers.core import Dense, Dropout, Activation, Flatten
- from keras.layers.embeddings import Embedding
- MODEL_TYPE = 'mlp'
- if MODEL_TYPE == 'mlp':
- model = Sequential()
- model.add(Embedding(output_dim=32,
- input_dim=2000,
- input_length=100))
- model.add(Dropout(0.2))
- '''Drop 20% neuron during training '''
- model.add(Flatten())
- model.add(Dense(units=256, activation='relu'))
- ''' Total 256 neuron in hidden layers'''
- model.add(Dropout(0.35))
- model.add(Dense(units=1, activation='sigmoid'))
- ''' Define output layer with 'sigmoid activation' '''
- logger.info('Model summary:\n{}\n'.format(model.summary()))
當我們建立深度學習模型後, 就可以使用 Back propagation 進行訓練:
- ###################
- # Step5: Training
- ###################
- logger.info('Start training process...')
- model.compile(loss='binary_crossentropy',
- optimizer='adam',
- metrics=['accuracy'])
- train_history = model.fit(x_train, train_labels, batch_size=100, epochs=10, verbose=2, validation_split=0.2)
評估模型準確率
接著我們可以使用測試資料集來評估訓練出來模型的準確率:
- ###################
- # Step6: Evaluation
- ###################
- logger.info('Start evaluation...')
- scores = model.evaluate(x_test, test_labels, verbose=1)
- print("")
- logger.info('Score={}'.format(scores[1]))
進行預測
目前模型的準確率接近 80%, 接下來我們要使用此模型進行預測:
接著底下函數方便我們檢視測試資料某筆的預測結果:
- predict_classes = model.predict_classes(x_test).reshape(-1)
- print("")
- sentiDict = {1:'Pos', 0:'Neg'}
- def display_test_Sentiment(i):
- r'''
- Show prediction on i'th test data
- '''
- logger.debug('{}\'th test data:\n{}\n'.format(i, test_text[i]))
- logger.info('Ground truth: {}; prediction result: {}'.format(sentiDict[test_labels[i]], sentiDict[predict_classes[i]]))
- logger.info('Show prediction on 2\'th test data:')
- display_test_Sentiment(2)
上面的模型準確率為 0.8, 我們希望能夠再提升預測的準確率, 方法如下:
- ch13_2.py (link)
- ...
- ###################
- # Step3: Tokenize
- ####################
- MAX_LEN_OF_TOKEN = 380
- DICT_NUM_WORDS = 3800
- logger.info('Tokenizing document...')
- token = Tokenizer(num_words = DICT_NUM_WORDS)
- ''' Create a dictionary of 2,000 words '''
- token.fit_on_texts(train_text)
- ''' Read in all training text and select top 2,000 words according to frequency sorting descendingly '''
- logger.info('Total {} document being handled...'.format(token.document_count))
- logger.info('Top 10 word index:')
- c = 0
- for t,i in token.word_index.items():
- print("\t'{}'\t{}".format(t, i))
- c += 1
- if c == 10:
- break
- print("")
- logger.info('Translating raw text into token number list...')
- x_train_seq = token.texts_to_sequences(train_text)
- x_test_seq = token.texts_to_sequences(test_text)
- logger.info('Padding/Trimming the token number list to length={}...'.format(MAX_LEN_OF_TOKEN))
- x_train = sequence.pad_sequences(x_train_seq, maxlen=MAX_LEN_OF_TOKEN)
- x_test = sequence.pad_sequences(x_test_seq, maxlen=MAX_LEN_OF_TOKEN)
- ...
遞歸神經網路 RNN 模型介紹
接下來我們將使用遞迴神經網路 RNN (Recurrent Neural Network) 進行 IMDB 情緒分析, 並且訓練模型進行預測, 最後產生預測結果 (正面評價 或 負面評價).
為何要使用 RNN 模型
之前我們介紹的 Mnist 資料集 (辨識數字影像), Cifar 資料集 (辨識照片) 影像並不會隨著時間而改變, 所以使用多層感知器 (MLP), 或 卷積神經網路 (CNN), 都能達到不錯的效果. 然而在人工智慧所要解決的問題中, 很多是順序的, 例如自然語言處理 (同一時間只能聽到一個字, 之前的語言會影響之後語言的意義), 視訊影片處理 (影片是一張張的照片, 依照時間順序所組成), 氣象觀測資料 (氣象資訊隨著時間不斷改變), 股市交易資料 (股市開盤後, 股價隨著時間不斷變動).
以自然語言處理為例, 當我們在聽人說話時, 因為同一時間只能聽一個字, 所以我們會根據之前時間點所聽到的話語, 來理解目前時間點這句話的意義. 例如 "我家住在台北市", "我在市政府上班". 因為前一句話說已經住在台北市, 所以當我們理解後面那一句話會認為市政府是 "台北市" 的市政府, 不會是其他縣市的市政府. 因為多層感知器 (MLP) 或卷積神經網路 (CNN), 都只能依照當下的狀態進行辨識, 如果要處理時間序列的問題, 就必須使用 RNN 與 LSTM 模型.
遞歸神經網路 RNN 模型原理
遞歸神經網路 RNN (Recurrent Neural Network) 其原理是將神經元的輸出, 再接回神經元的輸入. 這樣的設計使神經網路具有 "記憶" 的功能, 如下圖:
如上圖共有三個時間點依序是 "t-1", "t" "t+1". 在 "t" 的時間點:
上面的 f 函數是非線性函數, 例如 Relu.
使用 Keras RNN 模型進行 IMDb 情緒分析
STEP1. 建立模型 > STEP2. 查看模型摘要 > STEP3. 評估模型準確率
使用 SimpleRNN 建立 16 個神經元的 RNN, 完整代碼請參考 "ch13_3.py", 準確率約 84%.
長短期記憶 LSTM 模型介紹
長短期記憶 LSTM (Long-Short Term Memory) 也是一種時間遞歸神經網路 (RNN). 專門設計來解決 RNN 的 Long-term dependencies 問題.
RNN 的 long-term dependencies 問題
前一小節介紹的 RNN 再訓練時會有 Long-term dependencies 的問題, 這是由於 RNN 模型在訓練時會遇到 Gradient vanishing 或 Gradient exploding 的問題. 訓練時在計算 Back Propagation 時, 梯度頃向於每一時刻遞增或遞減, 經過段時間後會發散到無窮大或收斂到零. long-term dependencies 的問題簡單說就是在每一個時間間隔不斷增大時, RNN 會喪失學習到連接遠的訊息能力.
長短期記憶 LSTM 介紹
簡單說 RNN 只能記得短期記憶, 不能記得長期記憶. 所以深度學習專家 Schmidhuber 提出了長短期記憶 LSTM (Long-Short Term Memory) 模型, 專門設計來解決 RNN 的 long-term dependencies 問題. 考慮下圖:
在 LSTM 神經網路中, 每一個神經元相當於一個記憶細胞 (Cell) 說明如下:
使用 Keras LSTM 模型進行 IMDb 情緒分析
STEP1. 建立模型 > STEP2. 查看模型摘要 > STEP3. 評估模型準確率
使用 LSTM 建立 32 個神經元的 LSTM 層, 完整代碼請參考 "ch13_3.py". 使用 LSTM 模型準確率提升至 86%.
Supplement
* 循環神經網絡 (RNN, Recurrent Neural Networks) 介紹
* A Beginner’s Guide to Recurrent Networks and LSTMs
* Recurrent Neural Networks, LSTM and GRU
沒有留言:
張貼留言