教程| 利用AllenNLP,百行Python代碼訓練情感分類器

2020-12-03 機器之心Pro

選自realworldnlpbook

作者:Masato Hagiwara

機器之心編譯

參與:Geek AI、路

本文介紹了如何利用 AllenNLP,使用不到一百行代碼訓練情感分類器。

什麼是情感分析?

情感分析是一種流行的文本分析技術,用來對文本中的主觀信息進行自動識別和分類。它被廣泛用於量化觀點、情感等通常以非結構化方式記錄的信息,而這些信息也因此很難用其他方式量化。情感分析技術可被用於多種文本資源,例如調查報告、評論、社交媒體上的帖子等。

情感分析最基本的任務之一是極性分類,換句話說,該任務需要判斷語言所表達的觀點是正面的、負面的還是中性的。具體而言,可能有三個以上的類別,例如:極其正面、正面、中性、消極、極其消極。這有些類似於你使用某些網站時的評價行為(比如 Amazon),人們可以用星星數表示 5 個等級來對物品進行評論(產品、電影或其他任何東西)。

斯坦福的情感分析樹庫(TreeBank)

目前,研究人員發布了一些公開的情感分類數據集。在本文中,我們將使用斯坦福的情感分析樹庫(或稱 SST),這可能是最廣為使用的情感分析數據集之一。SST 與其它數據集最大的不同之處是,在 SST 中情感標籤不僅被分配到句子上,句子中的每個短語和單詞也會帶有情感標籤。這使我們能夠研究單詞和短語之間複雜的語義交互。例如,對下面這個句子的極性進行分析:

This movie was actually neither that funny, nor super witty.

這個句子肯定是消極的。但如果只看單個單詞(「funny」、「witty」)可能會被誤導,認為它的情感是積極的。只關注單個單詞的樸素詞袋分類器很難對上面的例句進行正確的分類。要想正確地對上述例句的極性進行分類,你需要理解否定詞(neither ... nor ...)對語義的影響。由於 SST 具備這樣的特性,它被用作獲取句子句法結構的神經網絡模型的標準對比基準(https://nlp.stanford.edu/~socherr/EMNLP2013_RNTN.pdf)。

Pytorch 和 AllenNLP

PyTorch 是我最喜歡的深度學習框架。它提供了靈活、易於編寫的模塊,可動態運行,且速度相當快。在過去一年中,PyTorch 在科研社區中的使用實現了爆炸性增長。

儘管 PyTorch 是一個非常強大的框架,但是自然語言處理往往涉及底層的公式化的事務處理,包括但不限於:閱讀和編寫數據集、分詞、建立單詞索引、詞彙管理、mini-batch 批處理、排序和填充等。儘管在 NLP 任務中正確地使用這些構建塊是至關重要的,但是當你快速迭代時,你需要一次又一次地編寫類似的設計模式,這會浪費很多時間。而這正是 AllenNLP 這類庫的亮點所在。

AllenNLP 是艾倫人工智慧研究院開發的開源 NLP 平臺。它的設計初衷是為 NLP 研究和開發(尤其是語義和語言理解任務)的快速迭代提供支持。它提供了靈活的 API、對 NLP 很實用的抽象,以及模塊化的實驗框架,從而加速 NLP 的研究進展。

本文將向大家介紹如何使用 AllenNLP 一步一步構建自己的情感分類器。由於 AllenNLP 會在後臺處理好底層事務,提供訓練框架,所以整個腳本只有不到 100 行 Python 代碼,你可以很容易地使用其它神經網絡架構進行實驗。

代碼地址:https://github.com/mhagiwara/realworldnlp/blob/master/examples/sentiment/sst_classifier.py

接下來,下載 SST 數據集,你需要將數據集分割成 PTB 樹格式的訓練集、開發集和測試集,你可以通過下面的連結直接下載:https://nlp.stanford.edu/sentiment/trainDevTestTrees_PTB.zip。我們假設這些文件是在 data/stanfordSentimentTreebank/trees 下進行擴展的。

注意,在下文的代碼片段中,我們假設你已經導入了合適的模塊、類和方法(詳情參見完整腳本)。你會注意到這個腳本和 AllenNLP 的詞性標註教程非常相似——在 AllenNLP 中很容易在只進行少量修改的情況下使用不同的模型對不同的任務進行實驗。

數據集讀取和預處理

AllenNLP 已經提供了一個名為 StanfordSentimentTreeBankDatasetReader 的便捷數據集讀取器,它是一個讀取 SST 數據集的接口。你可以通過將數據集文件的路徑指定為為 read() 方法的參數來讀取數據集:

reader = StanfordSentimentTreeBankDatasetReader()train_dataset = reader.read('data/stanfordSentimentTreebank/trees/train.txt')dev_dataset = reader.read('data/stanfordSentimentTreebank/trees/dev.txt')

幾乎任何基於深度學習的 NLP 模型的第一步都是指定如何將文本數據轉換為張量。該工作包括把單詞和標籤(在本例中指的是「積極」和「消極」這樣的極性標籤)轉換為整型 ID。在 AllenNLP 中,該工作是由 Vocabulary 類來處理的,它存儲從單詞/標籤到 ID 的映射。

# You can optionally specify the minimum count of tokens/labels.# `min_count={'tokens':3}` here means that any tokens that appear less than three times# will be ignored and not included in the vocabulary.vocab = Vocabulary.from_instances(train_dataset + dev_dataset, min_count={'tokens': 3})

下一步是將單詞轉換為嵌入。在深度學習中,嵌入是離散、高維數據的連續向量表徵。你可以使用 Embedding 創建這樣的映射,使用 BasicTextFieldEmbedder 將 ID 轉換為嵌入向量。

token_embedding = Embedding(num_embeddings=vocab.get_vocab_size('tokens'), embedding_dim=EMBEDDING_DIM)# BasicTextFieldEmbedder takes a dict - we need an embedding just for tokens,# not for labels, which are used unchanged as the answer of the sentence classificationword_embeddings = BasicTextFieldEmbedder({"tokens": token_embedding})

句子分類模型

LSTM-RNN 句子分類模型

現在,我們來定義一個句子分類模型。這段代碼看起來很多,但是別擔心,我在代碼片段中添加了大量注釋:

# Model in AllenNLP represents a model that is trained.classLstmClassifier(Model):def__init__(self, word_embeddings: TextFieldEmbedder, encoder: Seq2VecEncoder, vocab: Vocabulary) -> None: super().__init__(vocab)# We need the embeddings to convert word IDs to their vector representations self.word_embeddings = word_embeddings# Seq2VecEncoder is a neural network abstraction that takes a sequence of something# (usually a sequence of embedded word vectors), processes it, and returns it as a single# vector. Oftentimes, this is an RNN-based architecture (e.g., LSTM or GRU), but# AllenNLP also supports CNNs and other simple architectures (for example,# just averaging over the input vectors). self.encoder = encoder# After converting a sequence of vectors to a single vector, we feed it into# a fully-connected linear layer to reduce the dimension to the total number of labels. self.hidden2tag = torch.nn.Linear(in_features=encoder.get_output_dim(), out_features=vocab.get_vocab_size('labels')) self.accuracy = CategoricalAccuracy()# We use the cross-entropy loss because this is a classification task.# Note that PyTorch's CrossEntropyLoss combines softmax and log likelihood loss,# which makes it unnecessary to add a separate softmax layer. self.loss_function = torch.nn.CrossEntropyLoss()# Instances are fed to forward after batching.# Fields are passed through arguments with the same name.defforward(self, tokens: Dict[str, torch.Tensor], label: torch.Tensor = None) -> torch.Tensor:# In deep NLP, when sequences of tensors in different lengths are batched together,# shorter sequences get padded with zeros to make them of equal length.# Masking is the process to ignore extra zeros added by padding mask = get_text_field_mask(tokens)# Forward pass embeddings = self.word_embeddings(tokens) encoder_out = self.encoder(embeddings, mask) logits = self.hidden2tag(encoder_out)# In AllenNLP, the output of forward() is a dictionary.# Your output dictionary must contain a "loss" key for your model to be trained. output = {"logits": logits}if label isnotNone: self.accuracy(logits, label) output["loss"] = self.loss_function(logits, label)return output

這裡的關鍵是 Seq2VecEncoder,它基本上使用張量序列作為輸入,然後返回一個向量。我們在這裡使用 LSTM-RNN 作為編碼器(如有需要,可參閱文檔 https://allenai.github.io/allennlp-docs/api/allennlp.modules.seq2vec_encoders.html#allennlp.modules.seq2vec_encoders.pytorch_seq2vec_wrapper.PytorchSeq2VecWrapper)。

lstm = PytorchSeq2VecWrapper( torch.nn.LSTM(EMBEDDING_DIM, HIDDEN_DIM, batch_first=True))model = LstmClassifier(word_embeddings, lstm, vocab)

訓練

一旦你定義了這個模型,其餘的訓練過程就很容易了。這就是像 AllenNLP 這樣的高級框架的亮點所在。你只需要指定如何進行數據迭代並將必要的參數傳遞給訓練器,而無需像 PyTorch 和 TensorFlow 那樣編寫冗長的批處理和訓練循環。

optimizer = optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5)iterator = BucketIterator(batch_size=32, sorting_keys=[("tokens", "num_tokens")])iterator.index_with(vocab)trainer = Trainer(model=model, optimizer=optimizer, iterator=iterator, train_dataset=train_dataset, validation_dataset=dev_dataset, patience=10, num_epochs=20)trainer.train()

這裡的 BucketIterator 會根據 token 的數量對訓練實例進行排序,從而使得長度類似的實例在同一個批中。注意,我們使用了驗證集,在測試誤差過大時採用了早停法避免過擬合。

如果將上面的代碼運行 20 個 epoch,則模型在訓練集上的準確率約為 0.78,在驗證集上的準確率約為 0.35。這聽起來很低,但是請注意,這是一個 5 類的分類問題,隨機基線的準確率只有 0.20。

測試

為了測試剛剛訓練的模型是否如預期,你需要構建一個預測器(predictor)。predictor 是一個提供基於 JSON 的接口的類,它被用於將輸入數據傳遞給你的模型或將輸出數據從模型中導出。接著,我便寫了一個句子分類預測器(https://github.com/mhagiwara/realworldnlp/blob/master/realworldnlp/predictors.py#L10),將其用作句子分類模型的基於 JSON 的接口。

tokens = ['This', 'is', 'the', 'best', 'movie', 'ever', '!']predictor = SentenceClassifierPredictor(model, dataset_reader=reader)logits = predictor.predict(tokens)['logits']label_id = np.argmax(logits)print(model.vocab.get_token_from_index(label_id, 'labels'))

運行這段代碼後,你應該看到分類結果為「4」。「4」對應的是「非常積極」。所以你剛剛訓練的模型正確地預測出了這是一個非常正面的電影評論。

原文連結:http://www.realworldnlpbook.com/blog/training-sentiment-analyzer-using-allennlp.html

本文為機器之心編譯,轉載請聯繫本公眾號獲得授權

相關焦點

  • python實現高斯樸素貝葉斯分類器
    python實現高斯樸素貝葉斯分類器    在這篇文章中,我們將使用我最喜歡的機器學習庫scikit-learn在Python中實現樸素貝葉斯分類器。接下來,我們將使用經過訓練的樸素貝葉斯(監督分類法)模型來預測人口收入。
  • 手把手教程:如何從零開始訓練 TF 模型並在安卓系統上運行
    我將以 MNIST 數據為例介紹圖像分類,並分享一些你可能會面臨的常見問題。本教程著重於端到端的體驗,我不會深入探討各種 tf.Keras API 或 Android 開發。下載我的示例代碼並執行以下操作:
  • 雲計算學習:用PyTorch實現一個簡單的分類器
    有的教程一上來就是寫一個 cnn,雖然其實內容很簡單,但是直接上手容易讓人找不到重點,學的雲裡霧裡。有的教程又淺嘗輒止,師傅領到了門檻跟前,總感覺自己還沒有進門,教程就結束了。所以我總結了一下自己當初學習的路線,準備繼續深入鞏固自己的 pytorch 基礎;另一方面,也想從頭整理一個教程,從沒有接觸過 pytorch 開始,到完成一些最新論文裡面的工作。
  • 大神教程乾貨:使用BERT的多類別情感分析!(附代碼)
    使用BERT輕鬆快速地實現針對Yelp評論的多類別文本情感分析。在本文中,我們將使用BERT在Yelp評論上開發多類文本分類。BERT概述BERT是用於通用「語言理解」 的深度雙向表示模型,可從左至右和從右至左學習信息。
  • 手把手教你用Keras進行多標籤分類(附代碼)
    我附上這段腳本僅為保證(代碼的)完整性。train.py:一旦我們擁有了數據,我們將應用train.py訓練我們的分類器。fashion.model:我們的train.py腳本將會將我們的Keras模型保存到磁碟中。我們將在之後的classify.py腳本中用到它。
  • 基於python+OpenCV模塊的人臉識別定位技術
    本文將基於OpenCV模塊,在windows作業系統上,利用python語言,進行人臉識別技術的研究。當然OpenCV的應用領域很廣,除了人臉識別之外,它還支持圖像分割、動作識別、視頻處理等技術。代碼分析下面我們對代碼進行分析,代碼如圖所示:一共不超過15行,當然這是建立在別人已有的數據上做的,如果自己寫的話,不會這麼簡單,我們這只是調用了別人的接口,而這個接口是開源的,共享的。代碼第1行導入opencv模塊。
  • 如何用PyTorch訓練圖像分類器
    ,那麼你可以參考本教程。它將介紹如何組織訓練數據,使用預訓練神經網絡訓練模型,然後預測其他圖像。為此,我將使用由Google地圖中的地圖圖塊組成的數據集,並根據它們包含的地形特徵對它們進行分類。我會在另一篇文章中介紹如何使用它(簡而言之:為了識別無人機起飛或降落的安全區域)。但是現在,我只想使用一些訓練數據來對這些地圖圖塊進行分類。下面的代碼片段來自Jupyter Notebook。
  • OpenCV+深度學習預訓練模型,簡單搞定圖像識別 | 教程
    ,獲取輸出的分類。用OpenCV 3.3,可以很好地利用深度學習預訓練模型,將它們作為分類器。用OpenCV和深度學習給圖像分類接下來,我們來學習如何用Python、OpenCV和一個預訓練過的Caffe模型來進行圖像識別。下文用到的深度學習模型是在ImageNet上預訓練過的GoogleLeNet。
  • 如何使用邏輯回歸從頭開始創建分類器
    為了懲罰錯誤的分類,我們可以利用對數函數,因為log(1)= 0並且log(0)→-∞。現在,使用以下Python代碼訓練我們的機器學習模型!J, w_train, w_hist = gradient_descent(X, y, w, 0.5, 2000)在實際情況中,為了交叉驗證和測試模型,我們需要拆分訓練數據,但是本教程主要用於演示,我們將使用所有的訓練數據。
  • ...請收下這份2018學習清單:150個最好的機器學習,NLP和Python教程
    一般我會找一個有意思的教程或者視頻,再由此找到三四個,甚至更多的教程或者視頻。猛回頭,發現標收藏夾又多了20個資源待我學習(推薦提升效率工具Tab Bundler)。感知器(natureofcode.com)http://natureofcode.com/book/chapter-10-neural-networks/#chapter10_figure3一層的神經網絡(感知器模型)(dcu.ie
  • 教你學Python31-利用AdaBoost元算法提高分類性能
    基分類器一般採用的是弱可學習(weakly learnable)分類器,通過集成方法,組合成一個強可學習(strongly learnable)分類器。弱分類器中的'弱'意味著分類器的性能比隨機猜測要略好,但是也不會好太多。這就是說,在二分類的情況下弱分類器的錯誤率會高於50%,而'強'分類器的錯誤率將會低很多。
  • 乾貨 | 請收下這份2018學習清單:150個最好的機器學習,NLP和Python教程
    一般我會找一個有意思的教程或者視頻,再由此找到三四個,甚至更多的教程或者視頻。猛回頭,發現標收藏夾又多了20個資源待我學習(推薦提升效率工具Tab Bundler)。Perceptron)感知器模型(neuralnetworksanddeeplearning.com)http://neuralnetworksanddeeplearning.com/chap1.html#perceptrons 感知器(natureofcode.com)
  • 基於 Python 實現動態分類器集成學習
    動態分類器選擇是一種用於分類預測建模的集成學習算法。該技術涉及在訓練數據集上擬合多個機器學習模型,然後基於要預測的示例的特定細節,選擇在進行預測時預期表現最佳的模型。這可以通過以下方法實現:使用k最近鄰模型在訓練數據集中找到最接近要預測的新示例的示例,評估該鄰域中池中的所有模型,並使用在鄰域中表現最佳的模型來對新示例做出預測。
  • 「CVPR Oral」TensorFlow實現StarGAN代碼全部開源,1天訓練完
    近日,有研究人員將 StarGAN 在 TensorFlow 上實現的全部代碼開源,相關論文獲 CVPR 2018 Oral。我們還介紹了一種簡單但有效的方法,通過在域標籤中添加一個掩碼向量(mask vector)來實現不同數據集域之間的聯合訓練。我們提出的方法可以確保模型忽略未知的標籤,並關注特定數據集提供的標籤。這樣,我模型就可以很好地完成任務,比如利用從 RaFD 中學到的特徵合成 CelebA 圖像的面部表情,如圖 1 最右邊的列所示。
  • Keras 之父講解 Keras:幾行代碼就能在分布式環境訓練模型 |...
    現在,你可以把視頻矢量和問題矢量連結起來,在它們之上添加一個分類器。該分類器的任務,是從一堆潛在回答中,選出正確的那一個。第一步,是把視頻輸入矢量轉化為張量。一個視頻只是一組連續的畫面幀,每一幀都是一個圖像。對於圖像處理,你要做的全部的事,就是運行一個 CNN。每個 CNN,會從每幀畫面提取一個矢量表示。最後所得到的,是對每幀畫面進行編碼的矢量序列。
  • 史上最全 OpenCV 活體檢測教程!
    在本文的教程中,我們將活體檢測作為一個二分類問題來看待。給定一張輸入圖像,我們將訓練一個能夠識別出真假人臉的卷積神經網絡。在開始訓練我們的活體檢測模型前, 我們先查看一下使用的數據集。理想情況下,你可以使用包含多個種族的人臉的數據來訓練一個模型。如果讀者想要獲得更多關於改進活體檢測模型的建議,請務必參考下面的「局限性和進一步工作」章節。在接下來的教程中,你將學習到如何利用我記錄下來的數據集,並使用 OpenCV 和深度學習技術得到一個真正的活體檢測器。
  • 小白學數據:教你用Python實現簡單監督學習算法
    >在學習步驟中,分類模型通過分析訓練集數據建立一個分類器。在分類步驟中,分類器對給定的數據進行分類。用於分析的數據集(包含數據和其對應的標籤)被劃分為訓練集和測試集。訓練集從分析用的數據集中隨機抽取。剩下的數據集構成測試集。測試集和訓練集相互獨立,即測試集中的數據不會被構建於分類器。測試集用於評價分類器的預測精度。
  • 手把手教你用PyTorch實現圖像分類器(第一部分)
    本文的目標是加載其中的一個pre-trained網絡,並且將其中的分類器替換為自己的分類器,從而可以訓練自己的分類器。雖然這個想法是合理的,但我發現它也會產生一些問題,因為加載一個預先訓練的網絡並不能節省訓練分類器的時間。
  • 電子郵件分類的最佳機器學習算法
    我們將使用scikit學習庫中的Gaussian-naivebayes算法對兩位作者的郵件進行分類。下面是你可以在任何python的ide上實現的python代碼,確保你的系統上安裝了所需的庫。即使是算法的訓練次數和預測次數也相當合理。支持向量機支持向量機也是一種用於分類、回歸和異常檢測的有監督學習。通過一個平面將數據點劃分為兩類,利用SVM算法將數據點分類為2類。SVM具有一個直接的決策邊界。SVM算法具有通用性,可為決策函數指定不同的核函數。
  • Serverless 架構下 Python 輕鬆搞定圖像分類
    簡介: 本文將會通過一個有趣的 Python 庫,快速將圖像分類的功能搭建在雲函數上,並且和 API 網關結合,對外提供 API 功能,實現一個 Serverless 架構的「圖像分類 API」。前言圖像分類是人工智慧領域的一個熱門話題。通俗解釋就是,根據各自在圖像信息中所反映的不同特徵,把不同類別的目標區分開來的圖像處理方法。