背景介紹
文本分類是機(jī)器學(xué)習(xí)中一個非常常見而且重要的問題,比如新聞出版按照欄目分類(體育,旅游,軍事,科技等),還有常見的網(wǎng)頁分類、個性化新聞智能推薦、垃圾郵件過濾、情感分析等,都是文本分類的應(yīng)用場景。分類有二分類(binary)和多分類(multiple-classes)。
傳統(tǒng)的機(jī)器學(xué)習(xí)和深度學(xué)習(xí)都可以完成文本分類的任務(wù)。如果用傳統(tǒng)的分類算法,比如樸素貝葉斯或者SVM等算法,文本分類其實(shí)就是對文本進(jìn)行特征提取,確定一個評價函數(shù),訓(xùn)練分類模型,然后應(yīng)用于預(yù)測的過程。
在深度學(xué)習(xí)領(lǐng)域,有一種循環(huán)神經(jīng)網(wǎng)絡(luò)LSTM,在實(shí)踐效果上可以輕松取得比傳統(tǒng)學(xué)習(xí)算法更好的分類結(jié)果,本文就是使用LSTM神經(jīng)網(wǎng)絡(luò)對IMDB的影評進(jìn)行分類,以展示深度學(xué)習(xí)在Sequence classification分類任務(wù)上的性能。
文本可以看做是一連串文字的序列,Sequence classification就是在你有一些輸入序列的情況下,預(yù)測這個序列所屬的分類。細(xì)想起來,這其實(shí)是個很難的問題。原因如下:序列在長度上可能差異很大。電影評論有的很長,有的只有寥寥數(shù)語。組成這個序列的輸入文字又是來自一個非常大的詞表。據(jù)統(tǒng)計(jì)常用的英文單詞有3000個,常用的中文詞有5000個。這需要模型去學(xué)習(xí)比較長的上下文。
在深度學(xué)習(xí)領(lǐng)域有一個比較適合于解決這個場景的循環(huán)神經(jīng)網(wǎng)絡(luò),那就是長短時記憶網(wǎng)絡(luò)(Long Short Term Memory Network, LSTM),它較好地解決了原始循環(huán)神經(jīng)網(wǎng)絡(luò)的缺陷,成為當(dāng)前最流行的RNN,在語音識別、圖片描述、自然語言處理等許多領(lǐng)域中成功應(yīng)用。關(guān)于LSTM網(wǎng)絡(luò),推薦看中開社人工智能大牛@hanbingtao的這篇博客:零基礎(chǔ)入門深度學(xué)習(xí)(6) - 長短時記憶網(wǎng)絡(luò)(LSTM)(https://www.zybuluo.com/hanbingtao/note/581764),這是一系列講解深度學(xué)習(xí)的博客,清晰而且系統(tǒng)。
問題定義
使用廣為熟知的IMDB電影評論來做情感分類。這個龐大的影評數(shù)據(jù)集包含了25000 個影評(good or bad)用于訓(xùn)練(Train),同樣還有25000個評論用于測試(Test)。我們要做的事情就是給定一條電影評論,判斷它的情感是正面的還是負(fù)面的。這些數(shù)據(jù)是由Stanford學(xué)者收集的,2011年的論文中,將數(shù)據(jù)集對半分成訓(xùn)練集和測試集,當(dāng)時取得了88.89%的準(zhǔn)確率,可以在斯坦福大學(xué)的網(wǎng)站上看他的詳細(xì)介紹信息:LargeMovie Review Dataset(http://ai.stanford.edu/~amaas/data/sentiment/)。
準(zhǔn)備工具
深度學(xué)習(xí)領(lǐng)域有很多優(yōu)秀的平臺,比如TensorFlow、MXNet、Torch、Caffe等。TensorFlow是Google推出的可擴(kuò)展的深度學(xué)平臺,可以完成基于data flow graphs的計(jì)算任務(wù)。使用過TensorFlowAPI進(jìn)行編程的同學(xué)可能感覺到TensorFlow提供的API雖然功能非常強(qiáng)大,但是抽象的程度比較低,比較冗長和繁瑣,使用起來不是很自然。Keras是一個高層神經(jīng)網(wǎng)絡(luò)API,由純Python編寫而成并基于Tensorflow或Theano。Keras 能夠把你的idea迅速轉(zhuǎn)換為結(jié)果,非常適合于簡易和快速的原型設(shè)計(jì),支持CNN和RNN,或二者的結(jié)合;無縫CPU和GPU切換。Keras適用的Python版本是:Python 2.7-3.5。關(guān)于Keras的更詳細(xì)的信息請參考Keras中文文檔(http://keras-cn.readthedocs.io/en/latest/)。本文使用Keras來完成這個分析任務(wù),代碼更簡潔易讀。
構(gòu)建環(huán)境
推薦使用docker鏡像的方式搭建深度學(xué)習(xí)平臺環(huán)境。不過說實(shí)話,深度學(xué)習(xí)沒有GPU或者強(qiáng)悍的服務(wù)器,用起來還真是不容易,作為一個簡單的教程,我們還是使用CPU模式方便大家都能用起來。最基礎(chǔ)的軟件棧,需要一套Python開發(fā)環(huán)境,Keras和Tensorflow的最新版本。現(xiàn)在構(gòu)建環(huán)境已經(jīng)是非常便捷了,不用從頭開始構(gòu)建鏡像。store.docker.com 上面已有很多現(xiàn)成的鏡像可以使用,選擇一個合適的基礎(chǔ)鏡像,根據(jù)自己的需求進(jìn)行修改,構(gòu)建適應(yīng)自己環(huán)境的鏡像文件。
筆者選擇一個只有命令行模式的Keras鏡像,通過添加jupyter-notebook來創(chuàng)建一個更適合編碼的鏡像環(huán)境。
如果你還沒有接觸過Jupyter Notebook,這里簡單說明一下。Jupyter Notebook 此前被稱為IPythonnotebook,是一個交互式筆記本,支持運(yùn)行40 多種編程語言。對于希望編寫漂亮的交互式文檔的人來說是一個強(qiáng)大工具。同時支持代碼和Markdown格式的文檔,方便分享代碼。很多主流的代碼倉庫或者會議,都會以Jupyter Notebook的方式進(jìn)行對外交流。
構(gòu)建docker鏡像的Dockerfile文件如下:
FROM gw000/keras:2.0.4-py2-tf-cpu
RUN pip install jupyter matplotlib seaborn
VOLUME /notebook
WORKDIR /notebook
EXPOSE 8888
CMD ['jupyter', 'notebook', '--allow-root', '--no-browser', '--ip=0.0.0.0', '--NotebookApp.token=']
docker鏡像構(gòu)建指令:
docker build -t keras:2.0.4-py2-tf1.1.0-cpu .
我們采用TensorFlow作為Keras的backend,本鏡像做好之后,包含的主要組件版本號如下:
Keras (2.0.4)
numpy (1.12.1)
pandas (0.20.1)
tensorflow (1.1.0)
使用docker run命令啟動一個容器:
docker run -d --name keras -v /sharedfolder:/notebook/sharedfolder -p 8888:8888 keras:2.0.4-py2-tf1.1.0-cpu
容器啟動完成之后,就可以通過瀏覽器訪問到j(luò)upyter notebook的編程頁面了。而且在容器和主機(jī)之間做了文件映射,方便共享。建議使用Chrome或者Firefox瀏覽器來訪問,具體訪問地址就是http://${your-container-host-ip}:8888
數(shù)據(jù)理解
Keras提供了直接訪問IMDBdataset的內(nèi)置函數(shù) imdb.load_data() 。調(diào)用該函數(shù)能夠直接生成深度學(xué)習(xí)模型的數(shù)據(jù)格式。評論中的單詞已經(jīng)被一個整形值取代,這個整形值代表了這個單詞在數(shù)據(jù)集中的索引。因此影評序列就是由一連串的整形值組成。
詞嵌入(Word Embedding)
我們將把每一條影評都映射到一個實(shí)值向量空間。這個技術(shù)在文本處理過程中被稱作詞嵌入。經(jīng)過詞嵌入之后,單詞被編碼成高維空間的一個實(shí)值向量,在含義上比較接近的單詞在向量空間中也是比較接近的(cosine距離)。
Keras提供了一個Embedding layer,可以非常方便地實(shí)現(xiàn)這個過程。我們將每一個單詞都映射為一個32維的實(shí)值向量。同時限制我們建模中用到的總的單詞數(shù)取前5000個最常出現(xiàn)的單詞。其它的都以0代替。由于評論中序列的長度長短不一,我們限制每個評論最多有500個單詞,超過500的截?cái)?,小?00的用0填充。這樣我們數(shù)據(jù)集的輸入數(shù)據(jù)的表示方式都定義好了。下面就著手定義LSTM網(wǎng)絡(luò)的結(jié)構(gòu)。
一個簡單的LSTM 序列分類網(wǎng)絡(luò)
快速設(shè)計(jì)一個LSTM神經(jīng)網(wǎng)絡(luò)模型,看看分類的性能如何。上文keras:2.0.4-py2-tf1.1.0-cpu這個鏡像中已經(jīng)包含了Keras和TensorFlow以及必要的依賴,直接啟動容器,通過Jupyter Notebook的web界面編程即可。
下文有完整的實(shí)現(xiàn)代碼,文中會對不同的模型結(jié)構(gòu)遞進(jìn)式分析調(diào)優(yōu)。由于代碼的主干是一樣的,所以下文第一個樣例代碼,分段表述,對代碼的功能進(jìn)行詳細(xì)分析。后面的代碼只是有少許不同,就不分段詳細(xì)解釋了。只是把關(guān)鍵的建模代碼添加注釋。
# 引入依賴的軟件包
import numpy
from keras.datasets import imdb
from keras.models import Sequential
from keras.layers import Dense
from keras.layers importLSTM
from keras.layers.embeddings import Embedding
from keras.preprocessing import sequence
# 為了能夠重現(xiàn)結(jié)果,固定一個隨機(jī)數(shù)種子。
numpy.random.seed(7)
獲取數(shù)據(jù)集,數(shù)據(jù)集中50%用于訓(xùn)練,50%用于測試。使用top5000單詞。
備注:為什么選擇top5000?莫斯科國立語言研究所通過對英國、美國、法國、西班牙的34部文學(xué)作品的分析和研究,前5000個單詞占到了93.5%。
# 加載imdb數(shù)據(jù)集,使用top5000單詞,其他reset為0
top_words =5000
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=top_words)
接下來對輸入序列進(jìn)行截?cái)嗪吞钛a(bǔ),以保持相同的長度。模型會學(xué)習(xí)到填補(bǔ)的0值不包含任何信息。因此,雖然輸入序列的長度可能不一樣,但是在計(jì)算的時候需要保持向量的長度是一致的。
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)
現(xiàn)在我們可以來定義和訓(xùn)練LSTM模型了:
第一層是詞嵌入Embedded layer,使用32維向量來表達(dá)每一個單詞。
接下來是LSTM layer,包含100個記憶單元。
最后,因?yàn)槭且粋€二分類問題,我們使用一個Dense output layer,使用sigmoid激活函數(shù)輸出0或者1的二分類結(jié)果。
優(yōu)化器optimizer選用adam算法,當(dāng)然也可以選擇其他算法,如sgd。
二分類問題,我們使用binary_crossentropy作為損失函數(shù)。
選擇一個較大的batch_size=64
模型訓(xùn)練完成之后,我們測試一下模型的性能。測試集上的模型性能質(zhì)保,其實(shí)就是最后一個Epoch的 val_acc 指標(biāo)。
# evaluation
scores=model.evaluate(X_test,y_test,verbose=0)
print('Accuracy: %.2f%%'%(scores[1]*100))
Accuracy: 86.14%
回顧這個LSTM模型
這是一個使用LSTM做文本分類的常規(guī)流程,可以作為解決其他序列分類問題的模板。這個網(wǎng)絡(luò)只是用了基本的輸入數(shù)據(jù)預(yù)處理,沒有多少的調(diào)優(yōu),在第二個Epoch已經(jīng)取得了86.51%的準(zhǔn)確率,分類效果已經(jīng)比較好了,第三個Epoch在訓(xùn)練集和測試集上繼續(xù)性能繼續(xù)提升。
至此,我們可以看到深度學(xué)習(xí)強(qiáng)大的建模能力,解決Sequence classification問題,使用LSTM網(wǎng)絡(luò),在Keras平臺上可以輕松取得較好的結(jié)果。同時作為數(shù)據(jù)分析人員,我們還要意識到強(qiáng)大的學(xué)習(xí)能力可能帶來的另外一個問題就是過擬合,在Keras中如何解決深度學(xué)習(xí)中的過擬合問題?有沒有更好的網(wǎng)絡(luò)能夠?qū)Ξ?dāng)前問題進(jìn)一步求解提升他的Performance或者加速它的運(yùn)算速度,我們將在下一個文章中接著這個問題繼續(xù)分析一下。
聲明:文中代碼參考了Keras的官方Example和Jason Brownlee的博客?;谶@些代碼,加上作者對問題的理解和實(shí)踐整合而成。對代碼庫的作者表示感謝。
聯(lián)系客服