博客地址:http://www.jianshu.com/p/d443aab9bcb1
或者點擊閱讀原文,獲得更好的頁面排版
PS:微信公眾號《數據挖掘入門與實戰》在未經過我允許情況下,私自轉載我的文章。在此表示抗議。
再PS:本想投訴,發現微信只保護在自己平臺的遠程內容,難道這個是「技術BUG」,哈哈。
在這篇教程中,我們將介紹如何將深度學習技術應用到情感分析中。該任務可以被認為是從一個句子,一段話,或者是從一個文檔中,將作者的情感分為積極的,消極的或者中性的。
這篇教程由多個主題組成,包括詞向量,循環神經網絡和 LSTM。在了解這些概念之後,我們將在文章的最後給出完整的代碼。
在討論具體的概念之前,讓我們先來談談為什麼深度學習適合應用在自然語言處理中。
深度學習在自然語言處理中的應用自然語言處理是教會機器如何去處理或者讀懂人類語言的系統,目前比較熱門的方向,包括如下幾類:
在未進入深度學習時代,NLP也是一個蓬勃發展的領域。然而,在所有的上述任務中,我們都需要根據語言學的知識去做大量的,複雜的特徵工程。如果你去學習這個領域,那麼整個四年你都會在從事這方面的研究,比如音素,語素等等。在過去的幾年中,深度學習的發展取得了驚人的進步,在一定程度上我們可以消除對語言學的依賴性。由於進入的壁壘降低了,NLP 任務的應用也成為了深度學習研究的一個重大的領域之一。
詞向量為了了解深度學習是如何被應用的,我們需要考慮不同形式的數據,這些數據被用來作為機器學習或者深度學習模型的輸入數據。卷積神經網絡使用像素值作為輸入,logistic回歸使用一些可以量化的特徵值作為輸入,強化學習模型使用獎勵信號來進行更新。通常的輸入數據是需要被標記的標量值。所有當你處理 NLP 任務時,可能會想到利用這樣的數據管道。
但是,如果這樣設計管道,那麼是存在很多問題的。我們不能像點積或者反向傳播那樣在一個字符串上執行普通的運算操作。所有,我們不需要將字符串作為輸入,而是將句子中的每個詞轉換成向量。
你可以將輸入數據看成是一個 16*D 的一個矩陣。
我們希望這些向量以某種方式創建,而這種方式可以表示單詞及其上下文意義。例如,我們希望單詞 「love」 和 「adore」 這兩個詞在向量空間中是有一定的相關性的,因為他們有類似的定義,他們都在類似的上下文中使用。單詞的向量表示也被稱之為詞嵌入。
為了去得到這些詞嵌入,我們使用一個很著名的模型 「Word2Vec」。簡單的說,這個模型根據上下文的語境來推斷出每個詞的詞向量。如果兩個個詞在上下文的語境中,可以被互相替換,那麼這兩個詞的距離就非常近。在自然語言中,上下文的語境對分析詞語的意義是非常重要的。比如,之前我們提到的 「adore」 和 「love」 這兩個詞,我們觀察如下上下文的語境。
從句子中我們可以看到,這兩個詞通常在句子中是表現積極的,而且一般比名詞或者名詞組合要好。這也說明了,這兩個詞可以被互相替換,他們的意思是非常相近的。對於句子的語法結構分析,上下文語境也是非常重要的。所有,這個模型的作用就是從一大堆句子(以 Wikipedia 為例)中為每個獨一無二的單詞進行建模,並且輸出一個唯一的向量。Word2Vec 模型的輸出被稱為一個嵌入矩陣。
這個嵌入矩陣包含訓練集中每個詞的一個向量。傳統來講,這個嵌入矩陣中的詞向量數據會超過三百萬。
Word2Vec 模型根據數據集中的每個句子進行訓練,並且以一個固定窗口在句子上進行滑動,根據句子的上下文來預測固定窗口中間那個詞的向量。然後根據一個損失函數和優化方法,來對這個模型進行訓練。這個訓練的詳細過程有點複雜,所有我們這裡就先不討論細節方面的事。但是,對於深度學習模型來說,我們處理自然語言的時候,一般都是把詞向量作為模型的輸入。
如果你想了解更多有關 Word2Vec 的理論,那麼你可以學習這個教程。
循環神經網絡(RNN)現在,我們已經得到了神經網絡的輸入數據 —— 詞向量,接下來讓我們看看需要構建的神經網絡。NLP 數據的一個獨特之處是它是時間序列數據。每個單詞的出現都依賴於它的前一個單詞和後一個單詞。由於這種依賴的存在,我們使用循環神經網絡來處理這種時間序列數據。
循環神經網絡的結構和你之前看到的那些前饋神經網絡的結構可能有一些不一樣。前饋神經網絡由三部分組成,輸入層,隱藏層和輸出層。
前饋神經網絡和 RNN 之前的主要區別就是 RNN 考慮了時間的信息。在 RNN 中,句子中的每個單詞都被考慮上了時間步驟。實際上,時間步長的數量將等於最大序列長度。
與每個時間步驟相關聯的中間狀態也被作為一個新的組件,稱為隱藏狀態向量 h(t) 。從抽象的角度來看,這個向量是用來封裝和匯總前面時間步驟中所看到的所有信息。就像 x(t) 表示一個向量,它封裝了一個特定單詞的所有信息。
隱藏狀態是當前單詞向量和前一步的隱藏狀態向量的函數。並且這兩項之和需要通過激活函數來進行激活。
上面的公式中的2個W表示權重矩陣。如果你需要仔細研究這兩個矩陣,你會發現其中一個矩陣是和我們的輸入 x 進行相乘。另一個是隱藏的裝填向量,用來和前一個時間步驟中的隱藏層輸出相乘。W(H) 在所有的時間步驟中都是保持一樣的,但是矩陣 W(x) 在每個輸入中都是不一樣的。
這些權重矩陣的大小不但受當前向量的影響,還受前面隱藏層的影響。舉個例子,觀察上面的式子,h(t) 的大小將會隨著 W(x) 和 W(H) 的大小而改變。
讓我們來看一個快速例子。當 W(H) 非常大,W(X) 非常小的時候,我們知道 h(t) 受 h(t-1) 的影響比 x(t) 的影響大。換句話說,目前的隱藏狀態向量更關心前面句子的一個總和,而不是當前的一個句子。
權重的更新,我們採用 BPTT 算法來進行跟新。
在最後的時刻,隱藏層的狀態向量被送入一個 softmax 分類器,進行一個二分類,即判斷文本是否是積極情緒或者xiao'ji消極情緒。
長短期記憶網絡單元,是另一個 RNN 中的模塊。從抽象的角度看,LSTM 保存了文本中長期的依賴信息。正如我們前面所看到的,H 在傳統的RNN網絡中是非常簡單的,這種簡單結構不能有效的將歷史信息連結在一起。舉個例子,在問答領域中,假設我們得到如下一段文本,那麼 LSTM 就可以很好的將歷史信息進行記錄學習。
在這裡,我們看到中間的句子對被問的問題沒有影響。然而,第一句和第三句之間有很強的聯繫。對於一個典型的RNN網絡,隱藏狀態向量對於第二句的存儲信息量可能比第一句的信息量會大很多。但是LSTM,基本上就會判斷哪些信息是有用的,哪些是沒用的,並且把有用的信息在 LSTM 中進行保存。
我們從更加技術的角度來談談 LSTM 單元,該單元根據輸入數據 x(t) ,隱藏層輸出 h(t) 。在這些單元中,h(t) 的表達形式比經典的 RNN 網絡會複雜很多。這些複雜組件分為四個部分:輸入門,輸出門,遺忘門和一個記憶控制器。
每個門都將 x(t) 和 h(t-1) 作為輸入(沒有在圖中顯示出來),並且利用這些輸入來計算一些中間狀態。每個中間狀態都會被送入不同的管道,並且這些信息最終會匯集到 h(t) 。為簡單起見,我們不會去關心每一個門的具體推導。這些門可以被認為是不同的模塊,各有不同的功能。輸入門決定在每個輸入上施加多少強調,遺忘門決定我們將丟棄什麼信息,輸出門根據中間狀態來決定最終的 h(t) 。為了了解更多有關 LSTM 的信息,你可以查看 Christopher Olah 的博客。
我們再來看看第一個問題,「What is the sum of the two numbers?",該模型必須接受類似的問題和答案來進行訓練。LSTM 就會認為任何沒有數字的句子都是沒有意義的,因此遺忘門就會丟棄這些不必要的信息。
情感分析框架如前所述,情感分析的任務是去分析一個輸入單詞或者句子的情緒是積極的,消極的還是中性的。我們可以把這個特定的任務(和大多數其他NLP任務)分成 5個不同的組件。
1) Training a word vector generation model (such as Word2Vec) or loading pretrained word vectors
2) Creating an ID's matrix for our training set (We'll discuss this a bit later)
3) RNN (With LSTM units) graph creation
4) Training
5) Testing
首先,我們需要去創建詞向量。為了簡單起見,我們使用訓練好的模型來創建。
作為該領域的一個最大玩家,Google 已經幫助我們在大規模數據集上訓練出來了 Word2Vec 模型,包括 1000 億個不同的詞!在這個模型中,谷歌能創建 300 萬個詞向量,每個向量維度為 300。
在理想情況下,我們將使用這些向量來構建模型,但是因為這個單詞向量矩陣相當大(3.6G),我們將使用一個更加易於管理的矩陣,該矩陣由 GloVe 進行訓練得到。矩陣將包含 400000 個詞向量,每個向量的維數為 50。
我們將導入兩個不同的數據結構,一個是包含 400000 個單詞的 Python 列表,一個是包含所有單詞向量值得 400000*50 維的嵌入矩陣。
import numpy as npwordsList = np.load('wordsList.npy')print('Loaded the word list!')wordsList = wordsList.tolist() wordsList = [word.decode('UTF-8') for word in wordsList] wordVectors = np.load('wordVectors.npy')print ('Loaded the word vectors!')
請確保上面的程序能正常運行,我們可以查看詞彙表的維度和詞向量的維度。
print(len(wordsList))print(wordVectors.shape)
我們也可以在詞庫中搜索單詞,比如 「baseball」,然後可以通過訪問嵌入矩陣來得到相應的向量,如下:
baseballIndex = wordsList.index('baseball')wordVectors[baseballIndex]
現在我們有了向量,我們的第一步就是輸入一個句子,然後構造它的向量表示。假設我們現在的輸入句子是 「I thought the movie was incredible and inspiring」。為了得到詞向量,我們可以使用 TensorFlow 的嵌入函數。這個函數有兩個參數,一個是嵌入矩陣(在我們的情況下是詞向量矩陣),另一個是每個詞對應的索引。接下來,讓我們通過一個具體的例子來說明一下。
import tensorflow as tfmaxSeqLength = 10 #Maximum length of sentencenumDimensions = 300 #Dimensions for each word vectorfirstSentence = np.zeros((maxSeqLength), dtype='int32')firstSentence[0] = wordsList.index("i")firstSentence[1] = wordsList.index("thought")firstSentence[2] = wordsList.index("the")firstSentence[3] = wordsList.index("movie")firstSentence[4] = wordsList.index("was")firstSentence[5] = wordsList.index("incredible")firstSentence[6] = wordsList.index("and")firstSentence[7] = wordsList.index("inspiring")#firstSentence[8] and firstSentence[9] are going to be 0print(firstSentence.shape)print(firstSentence) #Shows the row index for each word
數據管道如下圖所示:
輸出數據是一個 10*50 的詞矩陣,其中包括 10 個詞,每個詞的向量維度是 50。
with tf.Session() as sess: print(tf.nn.embedding_lookup(wordVectors,firstSentence).eval().shape)
在整個訓練集上面構造索引之前,我們先花一些時間來可視化我們所擁有的數據類型。這將幫助我們去決定如何設置最大序列長度的最佳值。在前面的例子中,我們設置了最大長度為 10,但這個值在很大程度上取決於你輸入的數據。
訓練集我們使用的是 IMDB 數據集。這個數據集包含 25000 條電影數據,其中 12500 條正向數據,12500 條負向數據。這些數據都是存儲在一個文本文件中,首先我們需要做的就是去解析這個文件。正向數據包含在一個文件中,負向數據包含在另一個文件中。下面的代碼展示了具體的細節:
from os import listdirfrom os.path import isfile, joinpositiveFiles = ['positiveReviews/' + f for f in listdir('positiveReviews/') if isfile(join('positiveReviews/', f))]negativeFiles = ['negativeReviews/' + f for f in listdir('negativeReviews/') if isfile(join('negativeReviews/', f))]numWords = []for pf in positiveFiles: with open(pf, "r", encoding='utf-8') as f: line=f.readline() counter = len(line.split()) numWords.append(counter) print('Positive files finished')for nf in negativeFiles: with open(nf, "r", encoding='utf-8') as f: line=f.readline() counter = len(line.split()) numWords.append(counter) print('Negative files finished')numFiles = len(numWords)print('The total number of files is', numFiles)print('The total number of words in the files is', sum(numWords))print('The average number of words in the files is', sum(numWords)/len(numWords))
我們也可以使用 Matplot 將數據進行可視化。
import matplotlib.pyplot as plt%matplotlib inlineplt.hist(numWords, 50)plt.xlabel('Sequence Length')plt.ylabel('Frequency')plt.axis([0, 1200, 0, 8000])plt.show()
從直方圖和句子的平均單詞數,我們認為將句子最大長度設置為 250 是可行的。
maxSeqLength = 250
接下來,讓我們看看如何將單個文件中的文本轉換成索引矩陣,比如下面的代碼就是文本中的其中一個評論。
fname = positiveFiles[3] with open(fname) as f: for lines in f: print(lines) exit
接下來,我們將它轉換成一個索引矩陣。
# Removes punctuation, parentheses, question marks, etc., and leaves only alphanumeric charactersimport restrip_special_chars = re.compile("[^A-Za-z0-9 ]+")def cleanSentences(string): string = string.lower().replace("<br />", " ") return re.sub(strip_special_chars, "", string.lower())
firstFile = np.zeros((maxSeqLength), dtype='int32')with open(fname) as f: indexCounter = 0 line=f.readline() cleanedLine = cleanSentences(line) split = cleanedLine.split() for word in split: try: firstFile[indexCounter] = wordsList.index(word) except ValueError: firstFile[indexCounter] = 399999 indexCounter = indexCounter + 1firstFile
現在,我們用相同的方法來處理全部的 25000 條評論。我們將導入電影訓練集,並且得到一個 25000 * 250 的矩陣。這是一個計算成本非常高的過程,因此我在這邊提供了一個我處理好的索引矩陣文件。
# ids = np.zeros((numFiles, maxSeqLength), dtype='int32')# fileCounter = 0# for pf in positiveFiles:# with open(pf, "r") as f:# indexCounter = 0# line=f.readline()# cleanedLine = cleanSentences(line)# split = cleanedLine.split()# for word in split:# try:# ids[fileCounter][indexCounter] = wordsList.index(word)# except ValueError:# ids[fileCounter][indexCounter] = 399999 # indexCounter = indexCounter + 1# if indexCounter >= maxSeqLength:# break# fileCounter = fileCounter + 1 # for nf in negativeFiles:# with open(nf, "r") as f:# indexCounter = 0# line=f.readline()# cleanedLine = cleanSentences(line)# split = cleanedLine.split()# for word in split:# try:# ids[fileCounter][indexCounter] = wordsList.index(word)# except ValueError:# ids[fileCounter][indexCounter] = 399999 # indexCounter = indexCounter + 1# if indexCounter >= maxSeqLength:# break# fileCounter = fileCounter + 1 # # np.save('idsMatrix', ids)
ids = np.load('idsMatrix.npy')
輔助函數下面你可以找到幾個輔助函數,這些函數在稍後訓練神經網絡的步驟中會使用到。
from random import randintdef getTrainBatch(): labels = [] arr = np.zeros([batchSize, maxSeqLength]) for i in range(batchSize): if (i % 2 == 0): num = randint(1,11499) labels.append([1,0]) else: num = randint(13499,24999) labels.append([0,1]) arr[i] = ids[num-1:num] return arr, labelsdef getTestBatch(): labels = [] arr = np.zeros([batchSize, maxSeqLength]) for i in range(batchSize): num = randint(11499,13499) if (num <= 12499): labels.append([1,0]) else: labels.append([0,1]) arr[i] = ids[num-1:num] return arr, labels
RNN 模型現在,我們可以開始構建我們的 TensorFlow 圖模型。首先,我們需要去定義一些超參數,比如批處理大小,LSTM的單元個數,分類類別和訓練次數。
batchSize = 24lstmUnits = 64numClasses = 2iterations = 100000
與大多數 TensorFlow 圖一樣,現在我們需要指定兩個佔位符,一個用於數據輸入,另一個用於標籤數據。對於佔位符,最重要的一點就是確定好維度。
標籤佔位符代表一組值,每一個值都為 [1,0] 或者 [0,1],這個取決於數據是正向的還是負向的。輸入佔位符,是一個整數化的索引數組。
import tensorflow as tftf.reset_default_graph()labels = tf.placeholder(tf.float32, [batchSize, numClasses])input_data = tf.placeholder(tf.int32, [batchSize, maxSeqLength])
一旦,我們設置了我們的輸入數據佔位符,我們可以調用
tf.nn.embedding_lookup() 函數來得到我們的詞向量。該函數最後將返回一個三維向量,第一個維度是批處理大小,第二個維度是句子長度,第三個維度是詞向量長度。更清晰的表達,如下圖所示:
data = tf.Variable(tf.zeros([batchSize, maxSeqLength, numDimensions]),dtype=tf.float32)data = tf.nn.embedding_lookup(wordVectors,input_data)
現在我們已經得到了我們想要的數據形式,那麼揭曉了我們看看如何才能將這種數據形式輸入到我們的 LSTM 網絡中。首先,我們使用 tf.nn.rnn_cell.BasicLSTMCell 函數,這個函數輸入的參數是一個整數,表示需要幾個 LSTM 單元。這是我們設置的一個超參數,我們需要對這個數值進行調試從而來找到最優的解。然後,我們會設置一個 dropout 參數,以此來避免一些過擬合。
最後,我們將 LSTM cell 和三維的數據輸入到 tf.nn.dynamic_rnn ,這個函數的功能是展開整個網絡,並且構建一整個 RNN 模型。
lstmCell = tf.contrib.rnn.BasicLSTMCell(lstmUnits)lstmCell = tf.contrib.rnn.DropoutWrapper(cell=lstmCell, output_keep_prob=0.75)value, _ = tf.nn.dynamic_rnn(lstmCell, data, dtype=tf.float32)
堆棧 LSTM 網絡是一個比較好的網絡架構。也就是前一個LSTM 隱藏層的輸出是下一個LSTM的輸入。堆棧LSTM可以幫助模型記住更多的上下文信息,但是帶來的弊端是訓練參數會增加很多,模型的訓練時間會很長,過擬合的機率也會增加。如果你想了解更多有關堆棧LSTM,可以查看TensorFlow的官方教程。
dynamic RNN 函數的第一個輸出可以被認為是最後的隱藏狀態向量。這個向量將被重新確定維度,然後乘以最後的權重矩陣和一個偏置項來獲得最終的輸出值。
weight = tf.Variable(tf.truncated_normal([lstmUnits, numClasses]))bias = tf.Variable(tf.constant(0.1, shape=[numClasses]))value = tf.transpose(value, [1, 0, 2])last = tf.gather(value, int(value.get_shape()[0]) - 1)prediction = (tf.matmul(last, weight) + bias)
接下來,我們需要定義正確的預測函數和正確率評估參數。正確的預測形式是查看最後輸出的0-1向量是否和標記的0-1向量相同。
correctPred = tf.equal(tf.argmax(prediction,1), tf.argmax(labels,1))accuracy = tf.reduce_mean(tf.cast(correctPred, tf.float32))
之後,我們使用一個標準的交叉熵損失函數來作為損失值。對於優化器,我們選擇 Adam,並且採用默認的學習率。
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=prediction, labels=labels))optimizer = tf.train.AdamOptimizer().minimize(loss)
如果你想使用 Tensorboard 來可視化損失值和正確率,那麼你可以修改並且運行下列的代碼。
import datetimetf.summary.scalar('Loss', loss)tf.summary.scalar('Accuracy', accuracy)merged = tf.summary.merge_all()logdir = "tensorboard/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + "/"writer = tf.summary.FileWriter(logdir, sess.graph)
超參數調整選擇合適的超參數來訓練你的神經網絡是至關重要的。你會發現你的訓練損失值與你選擇的優化器(Adam,Adadelta,SGD,等等),學習率和網絡架構都有很大的關係。特別是在RNN和LSTM中,單元數量和詞向量的大小都是重要因素。
學習率:RNN最難的一點就是它的訓練非常困難,因為時間步驟很長。那麼,學習率就變得非常重要了。如果我們將學習率設置的很大,那麼學習曲線就會波動性很大,如果我們將學習率設置的很小,那麼訓練過程就會非常緩慢。根據經驗,將學習率默認設置為 0.001 是一個比較好的開始。如果訓練的非常緩慢,那麼你可以適當的增大這個值,如果訓練過程非常的不穩定,那麼你可以適當的減小這個值。
優化器:這個在研究中沒有一個一致的選擇,但是 Adam 優化器被廣泛的使用。
LSTM單元的數量:這個值很大程度上取決於輸入文本的平均長度。而更多的單元數量可以幫助模型存儲更多的文本信息,當然模型的訓練時間就會增加很多,並且計算成本會非常昂貴。
詞向量維度:詞向量的維度一般我們設置為50到300。維度越多意味著可以存儲更多的單詞信息,但是你需要付出的是更昂貴的計算成本。
訓練訓練過程的基本思路是,我們首先先定義一個 TensorFlow 會話。然後,我們加載一批評論和對應的標籤。接下來,我們調用會話的 run 函數。這個函數有兩個參數,第一個參數被稱為 fetches 參數,這個參數定義了我們感興趣的值。我們希望通過我們的優化器來最小化損失函數。第二個參數被稱為 feed_dict 參數。這個數據結構就是我們提供給我們的佔位符。我們需要將一個批處理的評論和標籤輸入模型,然後不斷對這一組訓練數據進行循環訓練。
我們不在這裡對模型進行訓練(因為至少需要花費幾個小時),我們加載一個預訓練好的模型。
如果你決定使用你自己的機器去訓練這個網絡,那麼你可以使用 TensorBoard 來查看這個訓練過程。你可以打開終端,然後在裡面運行 tensorboard --logdir=tensorboard ,之後你就可以在 http://localhost:6006/ 中查看到整個訓練過程。
# sess = tf.InteractiveSession()# saver = tf.train.Saver()# sess.run(tf.global_variables_initializer())# for i in range(iterations):# # nextBatch, nextBatchLabels = getTrainBatch();# sess.run(optimizer, {input_data: nextBatch, labels: nextBatchLabels})# # if (i % 50 == 0):# summary = sess.run(merged, {input_data: nextBatch, labels: nextBatchLabels})# writer.add_summary(summary, i)# # if (i % 10000 == 0 and i != 0):# save_path = saver.save(sess, "models/pretrained_lstm.ckpt", global_step=i)# print("saved to %s" % save_path)# writer.close()
加載一個預訓練的模型在訓練過程中,這個預訓練模型的正確率和損失值如下所示:
查看上面的訓練曲線,我們發現這個模型的訓練結果還是不錯的。損失值在穩定的下降,正確率也不斷的在接近 100% 。然而,當分析訓練曲線的時候,我們應該注意到我們的模型可能在訓練集上面已經過擬合了。過擬合是機器學習中一個非常常見的問題,表示模型在訓練集上面擬合的太好了,但是在測試集上面的泛化能力就會差很多。也就是說,如果你在訓練集上面取得了損失值是 0 的模型,但是這個結果也不一定是最好的結果。當我們訓練 LSTM 的時候,提前終止是一種常見的防止過擬合的方法。基本思路是,我們在訓練集上面進行模型訓練,同事不斷的在測試集上面測量它的性能。一旦測試誤差停止下降了,或者誤差開始增大了,那麼我們就需要停止訓練了。因為這個跡象表明,我們網絡的性能開始退化了。
導入一個預訓練的模型需要使用 TensorFlow 的另一個會話函數,稱為 Server ,然後利用這個會話函數來調用 restore 函數。這個函數包括兩個參數,一個表示當前的會話,另一個表示保存的模型。
sess = tf.InteractiveSession()saver = tf.train.Saver()saver.restore(sess, tf.train.latest_checkpoint('models'))
然後,從我們的測試集中導入一些電影評論。請注意,這些評論是模型從來沒有看見過的。你可以通過以下的代碼來查看每一個批處理的正確率。
iterations = 10for i in range(iterations): nextBatch, nextBatchLabels = getTestBatch(); print("Accuracy for this batch:", (sess.run(accuracy, {input_data: nextBatch, labels: nextBatchLabels})) * 100)
結論在這篇文章中,我們通過深度學習方法來處理情感分析任務。我們首先設計了我們需要哪些模型組件,然後來編寫我們的 TensorFlow 代碼,來具體實現這些組件,並且我們需要設計一些數據管道來作為數據的流通渠道。最後,我們訓練和測試了我們的模型,以此來查看是否能在電影評論集上面正常工作。
在 TensorFlow 的幫助下,你也可以來創建自己的情感分析模型,並且來設計一個真實世界能用的模型。
來源:https://www.oreilly.com/learning/perform-sentiment-analysis-with-lstms-using-tensorflow