閱讀155 返回首頁    go 阿裏雲 go 技術社區[雲棲]


情感分析教程+心法!如何用 Apache MXNet 看懂電影影評

更多深度文章,請關注雲計算頻道:https://yq.aliyun.com/cloud

handwriting_2630118_1920_crop_45ff7b8abafe157115cc38ef969b9743
情感分析已經在數據科學界占有一席之地。企業可以在社交媒體上對其產品的評價,並主動出擊,解決滿意度問題。不過,人類的情感和語言非常複雜,機器學習的各種技術中,就數深度學習最有能力處理這些複雜的輸入數據。
這份教程中,我們將使用 Apache MXNet 打造神經網絡,目的是創造一個電影影評的分類器,能夠根據一段簡評判斷作者對電影的評價是好是壞。之所以選擇 Apache MXNet 而不是 TensorFlow等其他深度學習框架,是因為 Apache MXNet 有很好的靈活度,能在多個 GPU 上擴展使用,它也因此越來越普及。
我建議你下載這份完整心法,我們在這裏創建和運行了所有的代碼。
我鼓勵大家自己調整一下超參數,試驗一下神經網絡架構和數據準備的各種方法,看看你能否超越我們的精準度。

要閱讀這份心法,你必須對一下領域有基本了解:卷積運算、神經網絡、激活單元、梯度下降和 NumPy。

完成心法,你將獲得以下技能:
1. 理解情感分析的複雜度;
2. 理解詞嵌入及其用法;
3. 準備用於訓練神經網絡的數據庫;
4. 完成定製神經網絡架構,用於在各種模型中分類情感;
5. 將結果視覺化,利用 t-sne 理解我們的模型;
6. 使用 glove 等預製嵌入,訓練帶有限製條件的數據,例如小數據庫或者短句。

**情感分析
**
雖然隻是分類“好評”、“差評”,但是情感分析很複雜。試想你上豆瓣看到這條影評:“這部電影主題很蠢,製作粗糙,情節粗俗——我超愛。”雖然這句話裏有很多負麵的詞語(“蠢”、“粗糙”、“粗俗”),但是情感卻是正麵的(“我超愛”)。再試想另一條影評:“毫無內涵、幽默、或者任何形式的智商。”雖然這句話裏有很多積極的詞匯,但卻是一條負麵影評。還有一些影評包涵諷刺:“看完《颶風營救3》,《颶風2》就好像一部史詩巨作。”如果你理解語境(《颶風2》其實也不咋滴),你就知道這是一條負麵影評了。
正是由於語境,情感分析才不容易。情感分析器在某一數據庫上表現還行,但換一個數據庫可能就不行了。

嵌入數據庫
表格數據的編碼是簡單的。甚至圖片編碼都比文字更簡單——每一個像素的值都在 0-225 的 RGB 值之間,是一個二維數組。改變圖像的大小也不會改變其內容。但是,要把自然語言編碼為數字就沒這麼直接了。每一種語言的詞匯量都很驚人,改變句子的長度也可能改變句子的意思。
舉個例子。假設以下詞語構成我們全部的詞匯量:{我,愛,蛋糕,討厭,披薩}。我們可以組兩個句子:“我愛蛋糕”和“我討厭披薩”。
如何將這些句子編碼成數字呢?有一種表征詞匯的方法是使用熱獨編碼:
1

這種表征中,如果我門有 N 個單詞,就需要 NxN 大小的矩陣,成為詞匯矩陣,構成了單詞的查找表格。
現在,我們來試試編碼整個句子。“我討厭披薩”就變成以下的這個矩陣:
2

MNNet 神經網絡中的嵌入層也進行同樣的查找運算,這與詞嵌入方法不同。
詞嵌入是一種更好的方法,是一種連續而非離散的詞語表征。詞嵌入矩陣長這樣:
3

我們使用 Nx3、而非 NxN 矩陣,3是嵌入的大小。因此,每個詞語都可以表征為一個3維、而非 N 維的矢量。
詞嵌入不僅減少了詞匯矩陣的表征大小,也將詞語之間的語義聯係進行了編碼。例如,“蛋糕”和“披薩”的嵌入矢量相似,因為兩者都是食物;“愛”和“討厭”在第二維度的量級相同,因為兩者都是情感。不過,“愛”和“討厭”在第一維度的量級不同,因為兩者代表了相反的情緒。
深度神經網絡可以在情感分類中自動學會這些詞嵌入。某些詞語的嵌入矢量可以看作是權重,可以讓深度神經網絡去學習。這些嵌入技術還可以用在圖像或其他數據上,通常被稱為自動編碼網。簡單來說,自動編碼器會在信息損失最小的前提下,盡可能表征低維度空間的輸入。詳細解釋請點擊這裏

句子卷積
用嵌入層把句子編碼成矩陣之後,就可以進行1D卷積,這與2D圖像上的2D卷積類似。卷積濾鏡的大小取決於我們想用的 n-gram。
4
接下來,我們來看看到底如何用 MXNet 上使用真實的影評句子進行情感分類。

準備環境
**
如果你使用 AWS 雲服務,可以使用專為深度學習配置的 Amazon Machine Image,這樣你可以跳過以下步驟中的 1-5。
如果你是在 Conda 環境下,激活環境後需要在 Conda 裏安裝PIP,方法是輸入 “conda install pip”。
**詳細安裝步驟如下:

1. 安裝包管理器 Anaconda,能幫你輕鬆安裝相關的 Python 軟件庫。
2. 安裝 scikit learn,這是一個通用的科學計算軟件庫,用來處理我們的數據。安裝方法是“conda install scikit-learn”。
3. 打開 Jupiter Notebook,輸入“conda install jupiter notebook”。
4. 然後,安裝開源深度學習庫 MXNet。

接下來的三個步驟是為了將詞嵌入視覺化。視覺化不是必須的,但是我強烈推薦。
1. 為了 bhtsne,使用 cython。
2. 我們需要 bhtsne,它是 tnse 在 C++ 和 Python 裏的操作。不要用 scikit-learn 裏的 tnse 操作,會損壞 Python 內核。
3. 最後,我們需要 matplotlib 用於繪圖和視覺化。

以下是一些在 anaconda 環境下你所需要的代碼。

conda install pip
pip install opencv-python
conda install scikit-learn
conda install jupyter notebook
pip install mxnet
conda install -c anaconda cython
pip install bhtsne
conda install -c anaconda matplotlib

**數據庫
**
現在我們使用一個斯坦福的電影評論數據庫,你可以在這裏下載
數據庫中,訓練庫和測試庫各有 25,000 個樣本,每個庫中都各有 12,500 個正麵和負麵情感。為了簡單起見,我們隻用訓練庫。
以下是用於加載數據的代碼。我們用 1 標記正麵情感,用 0 標記負麵情感。因為我們用 MXnet 的 softmaxoutput 來運行分類,就不用熱獨編碼標簽。如果使用其他框架,熱獨編碼就可能是必須的。
Screen_Shot_2017_10_07_at_07_15_28

**準備數據庫和編碼
**
我們從標準的數據準備開始。清理數據,清除鏈接和特殊字符等。然後打造詞匯庫,也就是數據庫中所有不重複的詞語。
我們需要找出評論中最常見的詞,這樣一些相對少見的詞語(例如導演的名字)不會影響分類器的結果。把每一個詞根據出現頻率進行倒序排序,配對其排序的數字(idx),保存在詞典裏,稱為 word_dict。此外,我們進行從 idx 到詞語的反響映射。我們隻處理最常見的 5,000 個詞,句子長度為 500 個詞,嵌入維度是 50。
Screen_Shot_2017_10_07_at_07_18_04
Screen_Shot_2017_10_07_at_07_18_47
Screen_Shot_2017_10_07_at_07_19_47

接下來,使用 word_dict 將句子編碼為數字。以下為所需代碼:
Screen_Shot_2017_10_07_at_07_20_22

然後,把句子長度變為 500 詞,可以根據句子的實際數據選擇不同的長度。
Screen_Shot_2017_10_07_at_07_20_42

然後,將數據分為訓練、驗證和測試數據。
Screen_Shot_2017_10_07_at_07_21_32

**打造深度網絡
**
打造神經網絡需要多多試驗,我們也可以選擇一個其他研究人員用於解決相似問題的神經網絡。我們從一個簡單的網絡開始,然後轉移到更複雜的神經網絡架構。
多虧了 MXNet 標誌性的 API,神經網絡的代碼非常簡潔:
Screen_Shot_2017_10_07_at_07_22_25

我們來分解一下代碼。首先,創造一個數據層(輸入層),在訓練中存放數據庫:data = mx.symbol.Variable('data')
vocab_embed 層在嵌入矩陣中運行查找:
embed_layer_1 = mx.sym.Embedding (data=input_x_1, input_dim=vocab_size, output_dim=embedding_dim, name='vocab_embed')

平麵化圖層使用維度為 seq_len x 嵌入維度,將嵌入層權重放到一個 1 x (seq_len*embedding)的欄矢量,作為下一個全連接層的輸入。
flatten_1 = mx.sym.Flatten(data=embed_layer_1)

全連接層將每一個神經元(輸出)從平麵化圖層連接到目前的層:
mx.sym.FullyConnected(data=flatten_1, num_hidden=500,name="fc1")

relu3_1 層在學習複雜函數的輸入上進行非線性激活:
relu3_1 = mx.sym.Activation(data=fc1_1, act_type="relu" , name="relu3")

最終的全連接層(softmax)進行分類。MXNet 裏的 SoftmaxOutput 層進行輸出的熱獨編碼,然後應用到 softmax 函數。

訓練網絡
使用 GPU 訓練最多可以減少 91% 的訓練時間。我們把過一遍訓練庫,稱為一個 “epoch” (紀元),我們將網絡訓練三個“紀元”,即“num_epoch = 3”。訓練過的模型定期存在一個 JSON 文件中,並測量訓練和驗證精度,來看看神經網絡學習得如何。
以下是所需代碼:
Screen_Shot_2017_10_07_at_07_27_05

視覺化
以下代碼能幫助將結果視覺化,讓我們對模型有更直觀的認識。我們可以獲得模型生成的嵌入權重,然後用 tnse 視覺化。
要在 2-d 裏將 vocab-size*embedding_dim 矢量視覺化是不可能的。我們需要減少數據的維度。以下代碼可以抽取嵌入權重,並將其視覺化為一個散點圖。
Screen_Shot_2017_10_07_at_07_28_13

以下是 t-sne 將排名最高的 500 個詞的權重視覺化的結果:
5

我們可以看出,模型自動學會了“出色、很棒、優秀”等詞的意思是類似的。然後,我們寫一個簡單的預測函數來使用生成的模型。

樣本預測
我們需要加載以下的保存模型:
Screen_Shot_2017_10_07_at_07_29_43

然後使用 word_dict 的指數將句子編碼,把它作為分類器交給模型。
Screen_Shot_2017_10_07_at_07_30_01

輸出是:[0.09290998 0.90709001],這意味著分類器以 0.9 的概率預測情感。
不過,這個模型在預測時隻考慮了單個詞語。如果考慮詞與詞之間的關係就更好了,這就需要打造一個卷積神經網絡,同時考慮多個聯係詞語。

打造卷積模型
這和之前的模型類似,隻是需要大小為 5 的卷積濾鏡。
Screen_Shot_2017_10_07_at_07_32_05

唯一困難的是 conv_input_2 輸入層,會將嵌入層的輸出格式改為適合卷積層的格式。其他部分都是一樣的。

**打造“多個卷積”模型
**
這與之前的模型類似,出了使用不同大小的卷積(3,4,5)來創建模型,然後將輸出連接起來並平麵化。增加一個 maxpool 層來避免過度擬合。以下是所需的 python 代碼:
Screen_Shot_2017_10_07_at_07_32_42
Screen_Shot_2017_10_07_at_07_34_00

**利用 glove 進行轉移學習
**
生成嵌入需要很多數據,但如果隻有少量數據怎麼辦?我們可以從另一個預先訓練的神經網絡中轉移權重。
我們在這兒使用斯坦福開發的 Wikipedia -2014 glove 嵌入,是使用維基百科的六十億詞語訓練而來的。我們使用 50 維度嵌入來訓練神經網絡,這也是一個超參數,你可以試試不同的值,看看什麼結果最好。以下函數將嵌入矢量加載到一個嵌入矩陣中(numPy 矩陣):
Screen_Shot_2017_10_07_at_07_35_17
Screen_Shot_2017_10_07_at_07_35_38

我們可以使用 t-sne 來將 glove 嵌入視覺化:
Screen_Shot_2017_10_07_at_07_36_54

如下:
6

如你所見,相似的詞語歸為了一組(“差,糟糕,超爛”)。我們可以用它來創建神經網絡用語分類句子。增加預先訓練的權重可能有點難,以下是所需的代碼:
Screen_Shot_2017_10_07_at_07_38_19

我們先將 glove embedding_matrix 轉換為 mx.nd.array。然後,創建一個名為權重的變量,值為 the_emb_3,作為參數傳遞給 mx.sym.Embedding 中的 embed_layer_3。
接下來,將 weight_matrix 作為 embed_layer_3 的默認值進行訓練。另外,我門需要凍結嵌入層的權重,這樣在返向傳播的時候 embed_matrix 的值就不會更新。要記得將 API 模塊中的 fixed_param_names = [‘weights’] 傳遞,凍結嵌入層的權重。以下是 Python 代碼:
Screen_Shot_2017_10_07_at_07_39_51

可以看出,對於這個數據庫來說 glove 詞嵌入(預先訓練的詞嵌入)沒有生成更好的模型。試試不同維度的詞嵌入、使用神經元更多的模型可能會更好。還可以試試 LTSM 和 GRU 等遞歸神經網絡。

**總結
**
這個教程中,我們用一個影評數據庫進行了情感分類。我們使用 MXNet 開發了不同複雜度的模型,理解了嵌入的概念,嚐試了模型所學的權重進行視覺化。最後,我們還使用 glove 嵌入進行了轉移學習。

**作者信息
**
Manu Jeevan 是自學的數據科學家、 AI Solutions 的聯合創始人,公司為其他企業提供人工智能解決方案。
Suresh Rathnaraj 是機器學習工程師,熱愛深度學習應用、足球和瑜伽,也是 AI Solutions 的聯合創始人。

本文由北郵@愛可可-愛生活老師推薦,阿裏雲雲棲社區組織翻譯。
文章原標題《Sentiment analysis with Apache MXNet》
作者:Manu Jeevan、Suresh Rathnaraj, 譯者:炫。

文章為簡譯,更為詳細的內容,請查看原文

最後更新:2017-10-07 14:03:26

  上一篇:go  免費數據恢複軟件哪個好用排行榜
  下一篇:go  Linux Shell 基礎 -- 結構化命令