百度情感分析API原理 百度情感分析api


百度情感分析API原理 百度情感分析api



對于一般的短文本分類問題,上文所述的簡單的文本卷積網絡即可達到很高的正確率[1] 。若想得到更抽象更高級的文本特征表示,可以構建深層文本卷積神經網絡[2,3] 。
循環神經網絡(RNN)
循環神經網絡是一種能對序列數據進行精確建模的有力工具 。實際上,循環神經網絡的理論計算能力是圖靈完備的[4] 。自然語言是一種典型的序列數據(詞序列),近年來,循環神經網絡及其變體(如long short term memory[5]等)在自然語言處理的多個領域 , 如語言模型、句法解析、語義角色標注(或一般的序列標注)、語義表示、圖文生成、對話、機器翻譯等任務上均表現優異甚至成為目前效果最好的方法 。
循環神經網絡按時間展開后如圖2所示:在第t時刻,網絡讀入第t個輸入Xt(向量表示)及前一時刻隱層的狀態值 ht-1(向量表示,h0一般初始化為0向量) , 計算得出本時刻隱層的狀態值ht,重復這一步驟直至讀完所有輸入 。如果將循環神經網絡所表示的函數記為f,則其公式可表示為:
其中Wxh是輸入到隱層的矩陣參數,Whh是隱層到隱層的矩陣參數,bh為隱層的偏置向量(bias)參數 , σ為sigmoid函數 。
在處理自然語言時 , 一般會先將詞(one-hot表示)映射為其詞向量表示,然后再作為循環神經網絡每一時刻的輸入Xt 。此外,可以根據實際需要的不同在循環神經網絡的隱層上連接其它層 。如,可以把一個循環神經網絡的隱層輸出連接至下一個循環神經網絡的輸入構建深層(deep or stacked)循環神經網絡,或者提取最后一個時刻的隱層狀態作為句子表示進而使用分類模型等等 。
長短期記憶網絡(LSTM)
對于較長的序列數據 , 循環神經網絡的訓練過程中容易出現梯度消失或爆炸現象[6] 。LSTM能夠解決這一問題 。相比于簡單的循環神經網絡,LSTM增加了記憶單元c、輸入門i、遺忘門f及輸出門o 。這些門及記憶單元組合起來大大提升了循環神經網絡處理長序列數據的能力 。若將基于LSTM的循環神經網絡表示的函數記為F,則其公式為:
F由下列公式組合而成[7]:
其中,it , ft,ct,ot,分別表示輸入門 , 遺忘門,記憶單元及輸出門的向量值,帶角標的W及b為模型參數,tanh為雙曲正切函數,⊙表示逐元素(elementwise)的乘法操作 。輸入門控制著新輸入進入記憶單元c的強度,遺忘門控制著記憶單元維持上一時刻值的強度,輸出門控制著輸出記憶單元的強度 。三種門的計算方式類似,但有著完全不同的參數 , 它們各自以不同的方式控制著記憶單元c , 如圖3所示:
LSTM通過給簡單的循環神經網絡增加記憶及控制門的方式,增強了其處理遠距離依賴問題的能力 。類似原理的改進還有Gated Recurrent Unit (GRU)[8],其設計更為簡潔一些 。這些改進雖然各有不同,但是它們的宏觀描述卻與簡單的循環神經網絡一樣(如圖2所示),即隱狀態依據當前輸入及前一時刻的隱狀態來改變,不斷地循環這一過程直至輸入處理完畢:
其中,Recrurent可以表示簡單的循環神經網絡、GRU或LSTM 。
棧式雙向LSTM(Stacked Bidirectional LSTM)
對于正常順序的循環神經網絡,ht包含了t時刻之前的輸入信息,也就是上文信息 。同樣,為了得到下文信息 , 我們可以使用反方向(將輸入逆序處理)的循環神經網絡 。結合構建深層循環神經網絡的方法(深層神經網絡往往能得到更抽象和高級的特征表示) , 我們可以通過構建更加強有力的基于LSTM的棧式雙向循環神經網絡[9],來對時序數據進行建模 。
如圖4所示(以三層為例),奇數層LSTM正向,偶數層LSTM反向,高一層的LSTM使用低一層LSTM及之前所有層的信息作為輸入,對最高層LSTM序列使用時間維度上的最大池化即可得到文本的定長向量表示(這一表示充分融合了文本的上下文信息,并且對文本進行了深層次抽象) , 最后我們將文本表示連接至softmax構建分類模型 。
基于PaddlePaddle的實戰
PaddlePaddle簡介
PaddlePaddle(paddlepaddle.org)是百度研發的深度學習框架 。除了核心框架之外,PaddlePaddle還提供了豐富的工具組件 。官方開源了多個工業級應用模型 , 涵蓋自然語言處理、計算機視覺、推薦引擎等多個領域,并開放了多個領先的預訓練中文模型 。4月23日深度學習開發者峰會上 , PaddlePaddle發布了一系列新特性和應用案例 。
數據集介紹
我們以IMDB情感分析數據集為例進行介紹 。IMDB數據集的訓練集和測試集分別包含25000個已標注過的電影評論 。其中,負面評論的得分小于等于4,正面評論的得分大于等于7,滿分10分 。
aclImdb|- test |-- neg |-- pos|- train |-- neg |-- posPaddlePaddle在 dataset/imdb.py 中實現了imdb數據集的自動下載和讀取,并提供了讀取字典、訓練數據、測試數據等API 。
配置模型
在該示例中,我們實現了兩種文本分類算法,文本卷積神經網絡,和棧式雙向LSTM 。我們首先引入要用到的庫和定義全局變量:
from __future__ import print_functionimport paddleimport paddle.fluid as fluidimport numpy as npimport sysimport mathCLASS_DIM = 2 情感分類的類別數EMB_DIM = 128 詞向量的維度HID_DIM = 512 隱藏層的維度STACKED_NUM = 3 LSTM雙向棧的層數BATCH_SIZE = 128 batch的大小文本卷積神經網絡
車上security一閃一閃是什么意思?security燈亮怎么解除security燈代表的是安全提示燈 , 符號一般有人形、氣囊、安全帶形狀的 。security燈一直閃,一般情況是代表駕駛人員或副駕駛人員沒有系好安 。
我們構建神經網絡 convolution_net,示例代碼如下 。需要注意的是:fluid.nets.sequence_conv_pool 包含卷積和池化層兩個操作 。
文本卷積神經網絡def convolution_net(data, input_dim, class_dim, emb_dim, hid_dim): emb = fluid.layers.embedding( input=data, size=[input_dim, emb_dim], is_sparse=True) conv_3 = fluid.nets.sequence_conv_pool( input=emb, num_filters=hid_dim, filter_size=3, act="tanh", pool_type="sqrt") conv_4 = fluid.nets.sequence_conv_pool( input=emb, num_filters=hid_dim, filter_size=4, act="tanh", pool_type="sqrt") prediction = fluid.layers.fc( input=[conv_3, conv_4], size=class_dim, act="softmax") return prediction網絡的輸入 input_dim 表示的是詞典的大?。琧lass_dim 表示類別數 。這里 , 我們使用 sequence_conv_pool API實現了卷積和池化操作 。
棧式雙向LSTM
棧式雙向神經網絡stacked_lstm_net的代碼片段如下:
棧式雙向LSTMdef stacked_lstm_net(data, input_dim, class_dim, emb_dim, hid_dim, stacked_num): assert stacked_num % 2 == 1 計算詞向量 emb = fluid.layers.embedding( input=data, size=[input_dim, emb_dim], is_sparse=True) 第一層棧 全連接層 fc1 = fluid.layers.fc(input=emb, size=hid_dim) lstm層 lstm1, cell1 = fluid.layers.dynamic_lstm(input=fc1, size=hid_dim) inputs = [fc1, lstm1] 其余的所有棧結構 for i in range(2, stacked_num1): fc = fluid.layers.fc(input=inputs, size=hid_dim) lstm, cell = fluid.layers.dynamic_lstm( input=fc, size=hid_dim, is_reverse=(i % 2) == 0) inputs = [fc, lstm] 池化層 fc_last = fluid.layers.sequence_pool(input=inputs[0], pool_type=max) lstm_last = fluid.layers.sequence_pool(input=inputs[1], pool_type=max) 全連接層,softmax預測 prediction = fluid.layers.fc( input=[fc_last, lstm_last], size=class_dim, act=softmax)return prediction以上的棧式雙向LSTM抽象出了高級特征并把其映射到和分類類別數同樣大小的向量上 。最后一個全連接層的’softmax’激活函數用來計算分類屬于某個類別的概率 。
重申一下,此處我們可以調用 convolution_net 或 stacked_lstm_net 的任何一個網絡結構進行訓練學習 。我們以 convolution_net 為例 。
接下來我們定義預測程序(inference_program) 。預測程序使用convolution_net 來對 fluid.layer.data 的輸入進行預測 。
def inference_program(word_dict): data = https://www.45baike.com/post/fluid.layers.data( name="words", shape=[1], dtype="int64", lod_level=1) dict_dim = len(word_dict) net = convolution_net(data, dict_dim, CLASS_DIM, EMB_DIM, HID_DIM)net = stacked_lstm_net(data, dict_dim, CLASS_DIM, EMB_DIM, HID_DIM, STACKED_NUM)return net我們這里定義了 training_program 。它使用了從 inference_program 返回的結果來計算誤差 。我們同時定義了優化函數 optimizer_func。
因為是有監督的學習,訓練集的標簽也在fluid.layers.data中定義了 。在訓練過程中,交叉熵用來在fluid.layer.cross_entropy中作為損失函數 。
在測試過程中,分類器會計算各個輸出的概率 。第一個返回的數值規定為cost 。
def train_program(prediction): label = fluid.layers.data(name="label", shape=[1], dtype="int64") cost = fluid.layers.cross_entropy(input=prediction, label=label) avg_cost = fluid.layers.mean(cost) accuracy = fluid.layers.accuracy(input=prediction, label=label) return [avg_cost, accuracy] 返回平均cost和準確率acc優化函數def optimizer_func(): return fluid.optimizer.Adagrad(learning_rate=0.002)訓練模型
定義訓練環境
定義你的訓練是在CPU上還是在GPU上:
use_cuda = False 在cpu上進行訓練place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()定義數據提供器
下一步是為訓練和測試定義數據提供器 。提供器讀入一個大小為 BATCH_SIZE的數據 。paddle.dataset.imdb.word_dict 每次會在亂序化后提供一個大小為BATCH_SIZE的數據,亂序化的大小為緩存大小buf_size 。
注意:讀取IMDB的數據可能會花費幾分鐘的時間,請耐心等待 。
print("Loading IMDB word dict....")word_dict = paddle.dataset.imdb.word_dict()print ("Reading training data....")train_reader = paddle.batch( paddle.reader.shuffle( paddle.dataset.imdb.train(word_dict), buf_size=25000), batch_size=BATCH_SIZE)print("Reading testing data....")test_reader = paddle.batch(paddle.dataset.imdb.test(word_dict), batch_size=BATCH_SIZE)feed_order = [words, label]pass_num = 1word_dict 是一個字典序列,是詞和label的對應關系,運行下一行可以看到具體內容:
word_dict每行是如(’limited’: 1726)的對應關系,該行表示單詞limited所對應的label是1726 。
構造訓練器
訓練器需要一個訓練程序和一個訓練優化函數 。
main_program = fluid.default_main_program()star_program = fluid.default_startup_program()prediction = inference_program(word_dict)train_func_outputs = train_program(prediction)avg_cost = train_func_outputs[0]test_program = main_program.clone(for_test=True)sgd_optimizer = optimizer_func()sgd_optimizer.minimize(avg_cost)exe = fluid.Executor(place)該函數用來計算訓練中模型在test數據集上的結果
def train_test(program, reader): count = 0 feed_var_list = [ program.global_block().var(var_name) for var_name in feed_order ] feeder_test = fluid.DataFeeder(feed_list=feed_var_list, place=place) test_exe = fluid.Executor(place) accumulated = len([avg_cost, accuracy]) * [0] for test_data in reader(): avg_cost_np = test_exe.run( program=program, feed=feeder_test.feed(test_data), fetch_list=[avg_cost, accuracy]) accumulated = [ x[0]x[1][0] for x in zip(accumulated, avg_cost_np) ] count= 1 return [x / count for x in accumulated]提供數據并構建主訓練循環
feed_order 用來定義每條產生的數據和 fluid.layers.data 之間的映射關系 。比如,imdb.train 產生的第一列的數據對應的是words這個特征 。
Specify the directory path to save the parametersparams_dirname = "understand_sentiment_conv.inference.model"feed_order = [words, label]pass_num = 1 訓練循環的輪數程序主循環部分def train_loop():啟動上文構建的訓練器feed_var_list_loop = [ main_program.global_block().var(var_name) for var_name in feed_order]feeder = fluid.DataFeeder(feed_list=feed_var_list_loop,place=place) exe.run(star_program) 訓練循環 for epoch_id in range(pass_num): for step_id, data in enumerate(train_reader()): 運行訓練器metrics = exe.run(main_program, feed=feeder.feed(data), fetch_list=[var.name for var in train_func_outputs]) 測試結果 print("step: {0}, Metrics {1}".format( step_id, list(map(np.array, metrics)))) if (step_id1) % 10 == 0: avg_cost_test, acc_test = train_test(test_program, test_reader) print(Step {0}, Test Loss {1:0.2}, Acc {2:0.2}.format( step_id, avg_cost_test, acc_test)) print("Step {0}, Epoch {1} Metrics {2}".format( step_id, epoch_id, list(map(np.array, metrics)))) if math.isnan(float(metrics[0])): sys.exit("got NaN loss, training failed.") if params_dirname is not None: fluid.io.save_inference_model(params_dirname, ["words"], prediction, exe) 保存模型train_loop()訓練過程處理
我們在訓練主循環里打印了每一步輸出,可以觀察訓練情況 。
開始訓練
最后,我們啟動訓練主循環來開始訓練 。訓練時間較長 , 如果為了更快的返回結果,可以通過調整損耗值范圍或者訓練步數 , 以減少準確率的代價來縮短訓練時間 。
train_loop(fluid.default_main_program())應用模型
構建預測器
和訓練過程一樣,我們需要創建一個預測過程 , 并使用訓練得到的模型和參數來進行預測,params_dirname 用來存放訓練過程中的各個參數 。
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()exe = fluid.Executor(place)inference_scope = fluid.core.Scope()生成測試用輸入數據
【百度情感分析API原理 百度情感分析api】為了進行預測,我們任意選取3個評論 。請隨意選取您看好的3個 。我們把評論中的每個詞對應到word_dict中的id 。如果詞典中沒有這個詞,則設為unknown 。然后我們用create_lod_tensor來創建細節層次的張量
reviews_str = [ read the book forget the movie, this is a great movie, this is very bad]reviews = [c.split() for c in reviews_str]UNK = word_dict[]lod = []for c in reviews: lod.append([word_dict.get(words, UNK) for words in c])base_shape = [[len(c) for c in lod]]tensor_words = fluid.create_lod_tensor(lod, base_shape, place)應用模型并進行預測
現在我們可以對每一條評論進行正面或者負面的預測啦 。
with fluid.scope_guard(inference_scope): [inferencer, feed_target_names, fetch_targets] = fluid.io.load_inference_model(params_dirname, exe)reviews_str = [ read the book forget the moive’,’this is a great moive, this is very bad]reviews = [c.split() for c in reviews_str]UNK = word_dict[]lod = []for c in reviews: lod.append([np.int64(word_dict.get(words, UNK)) for words in c])base_shape = [[len(c) for c in lod]]tensor_words = fluid.create_lod_tensor(lod, base_shape,place)assert feed_target_names[0] == "words"results = exe.run(inferencer, feed={feed_target_names[0]: tensor_words}, fetch_list=fetch_targets, return_numpy=False) np_data = https://www.45baike.com/post/np.array(results[0]) for i, r in enumerate(np_data): print("Predict probability of ", r[0], " to be positive and ", r[1], " to be negative for review \", reviews_str[i], "\")感興趣的小伙伴可以在PaddlePaddle官網上閱讀其他相關文檔內容:http://www.paddlepaddle.org/
參考文獻:
  1. Kim Y. Convolutional neural networks for sentence classification[J]. arXiv preprint arXiv:1408.5882, 2014.
  2. Kalchbrenner N, Grefenstette E, Blunsom P. A convolutional neural network for modelling sentences[J]. arXiv preprint arXiv:1404.2188, 2014.
  3. Yann N. Dauphin, et al. Language Modeling with Gated Convolutional Networks[J] arXiv preprint arXiv:1612.08083, 2016.
  4. Siegelmann H T, Sontag E D. On the computational power of neural nets[C]//Proceedings of the fifth annual workshop on Computational learning theory. ACM, 1992: 440-449.
  5. Hochreiter S, Schmidhuber J. Long short-term memory[J]. Neural computation, 1997, 9(8): 1735-1780.
  6. Bengio Y, Simard P, Frasconi P. Learning long-term dependencies with gradient descent is difficult[J]. IEEE transactions on neural networks, 1994, 5(2): 157-166.
  7. Graves A. Generating sequences with recurrent neural networks[J]. arXiv preprint arXiv:1308.0850, 2013.
  8. Cho K, Van Merri?nboer B, Gulcehre C, et al. Learning phrase representations using RNN encoder-decoder for statistical machine translation[J]. arXiv preprint arXiv:1406.1078, 2014.
  9. Zhou J, Xu W. End-to-end learning of semantic role labeling using recurrent neural networks[C]//Proceedings of the Annual Meeting of the Association for Computational Linguistics. 2015.
— 完 —
誠摯招聘
量子位正在招募編輯/采訪人員,工作地點在北京中關村 。期待有才氣、有熱情的同學加入我們!相關細節 , 請在量子位公眾號(QbitAI)對話界面,回復招聘兩個字 。
量子位 QbitAI · 頭條號簽約作者
?? ? 追蹤AI技術和產品新動態
心想夢成:一個叫杰克的美國人,在中國內地的風景區建了個度假村 。由于生意忙,很久沒 能回家和家人團聚,他十分思念他的故鄉,一個靠近海邊的小鎮 。一天 , 他突發奇想,在職工大會上宣布:誰要是能讓他做一個夢,夢見自己坐著 船乘風破浪地回到大洋彼岸的海...

    猜你喜歡