「語境」有多重要呢?
比如:你寫了一篇論文放在桌上,一般人問你:「這是什麼東西?」那可能只是純粹地問這是什麼東東。但如果是你的導師問你,那問題就嚴重了,潛台詞是:這TM寫的是什麼玩意兒?
語言有着人類最複雜的遊戲法則。尤其是在戀愛關係中,女孩子往往遊刃有餘,她們一時興起笑裡藏刀拋出的問題,往往讓男生分分鐘「送命」,比如這樣的:
沒有男友的小編只能調戲Siri,它的回答是這樣的:
好吧,「直男」中的戰鬥機,不配在愛情界擁有姓名!
機器無法理解句子的真正含義,一直是NLP從業者心中的一根刺。傳統的NLP技術和框架只能滿足基本的語言任務。但當試圖增加語境時,形勢便急轉而下。
不過,近18個月以來,NLP的形勢發生了顯著變化。像 Google的BERT和Zalando的 Flair這樣的NLP框架能夠通過句子進行解析,並掌握它們的語境。
語言模型嵌入(ELMo)
在這方面最大的突破之一來自於Elmo,一個由AllenNLP開發的最先進的NLP框架。本文,我們將探討ELMo(語言模型嵌入),並使用它在真實數據集上用Python構建一個令人興奮的NLP模型。
目錄
1.什麼是ELMo?
2.了解ELMo的工作原理
3.ELMo與其他單詞嵌入有什麼不同?
4.實現:ELMO用於Python中的文本分類
4.1 理解問題陳述
4.2 關於數據集
4.3 導入庫
4.4 讀取和檢查數據
4.5 文本清理及預處理
4.6 TensorFlow Hub簡介
4.7 準備ELMO向量
4.8 建模與評估
5.ELMo的其他用途是什麼?
ELMo是什麼?
不,這裡的ELMo不是SesameStreet中的人物!而是一種在向量或嵌入中表示單詞的新方法。這些單詞嵌入有助於在一些NLP任務中實現最先進的(SOTA)結果:
全球的NLP科學家已經開始將ELMo用於各種NLP任務,包括研究和工業。
了解ELMo的工作原理
在用Python實現ELMo之前,讓我們先直觀了解一下它是如何工作的。
想象一下:你已經成功地將ELMo代碼從GitHub複製到了Python中,並在自定義文本數據上構建了一個模型。你得到了平均的結果,所以現在需要改進模型。如果不了解ELMo的架構,你會怎麼做?如果沒有研究過,你會調整哪些參數?
這一思路適用於所有機器學習算法。你不需要了解其他分支,但是你應該具備足夠的知識來將其用於模型改進中。現在,讓我們回到ELMo的工作方式。
ELMo字向量是在兩層雙向語言模型(biLM)之上計算的。這個biLM模型有兩層堆疊在一起。每層有2個通道-前向通道和後向通道:
上述架構使用字符級卷積神經網絡(CNN)將文本字符串中的單詞表示為原始單詞向量。
這些原始單詞向量作為biLM第一層的輸入。
前向通道包含關於某個單詞及該單詞之前語境(其他詞)的信息
後向通道包含有關單詞及該單詞之後語境的信息
來自前向通道和後向通道的這對信息,形成中間詞向量。
這些中間字向量被送入biLM的下一層
(ELMO的)最終表示是原始單詞向量和兩個中間字向量的加權和。
由於biLM的輸入是根據字符而不是單詞來計算的,因此它獲得了單詞的內部結構。例如,biLM可以理解類似beauty和beautiful這樣的術語某種程度上是相關的,甚至不需要考慮它們經常出現的語境。聽起來太不可思議了!
ELMo和其他單詞嵌入有什麼不同?
與傳統的單詞嵌入(如word2vec和GLoVe)不同,分配給標記或單詞的ELMo向量實際上是包含該單詞的整個句子的函數。因此,在不同的語境下,同一個單詞可以有不同的詞向量。
也許你們會問:知道這些如何幫助處理NLP問題?讓我用一個例子來解釋這一點。
假設有以下幾個句子:
1. Iread the book yesterday.
2. Canyou read the letter now?
花點時間思考一下這兩者之間的區別。第一句中的動詞「read」是過去式。同一個動詞在第二句中轉換成現在時態。這是一種一詞多義現象,一個詞可以有多種含義或意義。
語言是如此的複雜。
傳統的單詞嵌入為兩個句子中的單詞「read」提供了相同的向量。因此,該系統無法區分多義詞。這些單詞嵌入無法掌握單詞使用的語境。
ELMo 單詞向量成功解決了這個問題。ELMo單詞表示法將整個輸入語句轉化為公式,用於計算單詞嵌入。因此,「read」一詞在不同的語境中具有不同的ELMo向量。
實現:用於Python中文本分類的ELMo
現在是你一直在等待的時刻——在Python中實現ELMo!讓我們一步一步來。
1.理解問題陳述
處理任何數據科學挑戰的第一步是定義問題陳述。這是我們未來行動的基礎。
對於本文,我們已經準備好了問題陳述:
情感分析仍然是自然語言處理(NLP)廣泛應用的關鍵問題之一。這一次,考慮到客戶關於製造和銷售手機、電腦、筆記本電腦等的各種科技公司的tweet,任務是確定tweet是否對這些公司或產品有負面情緒。
這顯然是一個二元文本分類任務,其中我們必須從摘取的推特中預測情感。
2.關於數據集
以下是我們所擁有的數據集的分類:
訓練集包含7920條推特
測試集包含1953條推特
你可以從此頁下載數據集。請注意,必須註冊或登錄才能下載。
警告:推特中的大多數褻瀆和粗俗詞彙已被替換為「$&@*#」。但是,請注意,數據集可能仍然包含可能被認為是褻瀆、粗俗或冒犯的文本。
好吧,讓我們啟動最喜歡的Python IDE並進行編碼!
3.導入庫
導入將在notebook中使用的庫:
importpandas as pd
importnumpy as np
importspacy
fromtqdm import tqdm
importre
importtime
importpickle
pd.set_option('display.max_colwidth',200)
4.讀取並檢查數據
# read data
train =pd.read_csv("train_2kmZucJ.csv")
test =pd.read_csv("test_oJQbWVk.csv")
train.shape, test.shape
輸出: ((7920, 3), (1953, 2))
訓練集有7920條推特,而測試組只有1953條。現在檢查一下訓練集中的類別分布:
train['label'].value_counts(normalize =True)
輸出:
0 0.744192
1 0.255808
Name: label, dtype: float64
在這裡,「1」表示否定的tweet,而「0」表示非否定的tweet。
快速瀏覽一下訓練集的前5行:
train.head()
我們有三列要處理。「tweet」列是獨立變量,而「label」列是目標變量。
5.文本清洗和預處理
我們將擁有一個乾淨、結構化的數據集,以便在理想情況下使用。但是在NLP中事情還沒有那麼簡單。
我們需要花費大量的時間清理數據,以便為模型構建階段做好準備。從文本中提取特徵較為容易,甚至特徵中包含更多信息。數據質量變得越高,模型的性能的改善越有意義。
所以,讓我們清理一下收到的文本,並進行探索。
在推特中似乎有相當多的URL鏈接。他們沒有告訴我們太多(如果有的話)關於推特的情感,所以將其直接刪除。
#remove URL's from train and test
train['clean_tweet']= train['tweet'].apply(lambda x: re.sub(r'http\S+', '', x))
test['clean_tweet']= test['tweet'].apply(lambda x: re.sub(r'http\S+', '', x))
我們使用正則表達式(或RegEx)來刪除URL。
注意:你可以在這篇文章中了解更多關於Regex的信息。
現在讓我們來做一些常規的文字清理。
#remove punctuation marks
punctuation= '!"#$%&()*+-/:;<=>?@[\\]^_`{|}~'
train['clean_tweet']= train['clean_tweet'].apply(lambda x: ''.join(ch for ch in x if ch not inset(punctuation)))
test['clean_tweet']= test['clean_tweet'].apply(lambda x: ''.join(ch for ch in x if ch not in set(punctuation)))
#convert text to lowercase
train['clean_tweet']= train['clean_tweet'].str.lower()
test['clean_tweet']= test['clean_tweet'].str.lower()
#remove numbers
train['clean_tweet']= train['clean_tweet'].str.replace("[0-9]", " ")
test['clean_tweet']= test['clean_tweet'].str.replace("[0-9]", " ")
#remove whitespaces
train['clean_tweet']= train['clean_tweet'].apply(lambda x:' '.join(x.split()))
test['clean_tweet']= test['clean_tweet'].apply(lambda x: ' '.join(x.split()))
我還想對文本進行規範化,即執行文本規範化。這有助於將單詞縮減為其基本形式。例如,單詞'produces'、'production'和'producing'的基本形式是'product'。通常情況下,同一單詞的多種形式並不那麼重要,我們只需要知道該單詞的基本形式。
我們將利用流行的spacy庫將文本按屈折變化形式進行歸類(標準化)。
#import spaCy's language model
nlp= spacy.load('en', disable=['parser', 'ner'])
#function to lemmatize text
deflemmatization(texts):
output = []
for i in texts:
s = [token.lemma_ for token innlp(i)]
output.append(' '.join(s))
return output
標準化訓練集和測試集中的tweet:
train['clean_tweet'] =lemmatization(train['clean_tweet'])
test['clean_tweet'] =lemmatization(test['clean_tweet'])
讓我們快速瀏覽一下原始推特和清理過的推特:
train.sample(10)
仔細查看以上列。「clean_tweet」欄中的tweet看起來比原來的tweet更易讀。
但是,我覺得仍然有足夠的空間來清理文本。我鼓勵您儘可能多地探索數據,並在文本中找到更多的見解或不規則之處。
6、TensorFlow Hub簡介
等等,TensorFlow和我們的教程有什麼關係?
TensorFlow Hub是一個庫,通過允許為不同的任務使用許多機器學習模型來實現轉移學習。ELMo就是這樣一個例子。這就是為什麼我們將在實現中通過TensorFlow Hub訪問ELMO。
在進行其他步驟之前,需要安裝TensorFlow Hub。要使用TensorFlow Hub,必須安裝TensorFlow軟件包或將其升級到至少1.7版本:
$ pip install"tensorflow>=1.7.0"
$ pip install tensorflow-hub
7.準備ELMo向量
現在將導入經過預訓練的ELMo模型。請注意:該模型的大小超過350MB,因此你可能需要一段時間來下載。
import tensorflow_hub as hub
import tensorflow as tf
elmo =hub.Module("https://tfhub.dev/google/elmo/2", trainable=True)
我將首先展示如何獲得一個句子的ELMo向量。你所要做的就是在對象elmo中傳遞一個字符串列表。
#just a random sentence
x= ["Roasted ants are a popular snack in Columbia"]
#Extract ELMo features
embeddings= elmo(x, signature="default", as_dict=True)["elmo"]
embeddings.shape
輸出: TensorShape([Dimension(1),Dimension(8), Dimension(1024)])
輸出是一個三維形狀的張量(1,8,1024):
該張量的第一維表示訓練樣本的數量。在我們的示例中是1
第二個維度表示字符串輸入列表中最長字符串的最大長度。因為輸入列表中只有一個字符串,所以第二個維度的大小等於字符串的長度–8
第三個維度等於ELMo向量的長度
因此,輸入語句中的每個單詞都有一個大小為1024的ELMo向量。
讓我們繼續為訓練和測試數據集中清理過的推特提取ELMo向量。然而,為了得到整個推特的向量表示,我們將取推特的組成項或標記的ELMo向量的平均值。
讓我們定義一個函數來執行此操作:
defelmo_vectors(x):
embeddings = elmo(x.tolist(),signature="default", as_dict=True)["elmo"]
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
sess.run(tf.tables_initializer())
# return average of ELMo features
returnsess.run(tf.reduce_mean(embeddings,1))
如果使用上面的函數一次性提取推特的嵌入,可能會耗盡計算資源(內存)。一種解決方法是:將訓練和測試集分成每批100個樣本,然後,將這些批次依次傳遞給elmo_vectors( )函數
我將把這些批次保存在一個列表中:
list_train = [train[i:i+100] for i inrange(0,train.shape[0],100)]
list_test = [test[i:i+100] for i inrange(0,test.shape[0],100)]
現在,我們將遍歷這些批次並提取ELMO向量。友情提示,這要花很長時間。
# Extract ELMo embeddings
elmo_train = [elmo_vectors(x['clean_tweet'])for x in list_train]
elmo_test = [elmo_vectors(x['clean_tweet'])for x in list_test]
一旦擁有了所有的向量,就可以將它們連接成一個數組:
elmo_train_new = np.concatenate(elmo_train,axis = 0)
elmo_test_new = np.concatenate(elmo_test,axis = 0)
我建議對這些數組進行保存,因為我們花了很長時間為其獲取ELMo向量。我們將其保存為pickle文件:
#save elmo_train_new
pickle_out= open("elmo_train_03032019.pickle","wb")
pickle.dump(elmo_train_new,pickle_out)
pickle_out.close()
#save elmo_test_new
pickle_out= open("elmo_test_03032019.pickle","wb")
pickle.dump(elmo_test_new,pickle_out)
pickle_out.close()
使用以下代碼將其重新加載:
#load elmo_train_new
pickle_in= open("elmo_train_03032019.pickle", "rb")
elmo_train_new= pickle.load(pickle_in)
#load elmo_train_new
pickle_in= open("elmo_test_03032019.pickle", "rb")
elmo_test_new= pickle.load(pickle_in)
8.建模與評估
讓我們用ELMo建立NLP模型!
我們將使用訓練數據集的ELMO向量來構建分類模型。然後,將使用該模型對測試集進行預測。但在所有這些之前,將elmo_train_new分為訓練和驗證集,以便在測試階段之前評估模型。
fromsklearn.model_selection import train_test_split
xtrain,xvalid, ytrain, yvalid = train_test_split(elmo_train_new,
train['label'],
random_state=42,
test_size=0.2)
由於目標是設定基線分數,我們將使用ELMo向量作為特徵建立一個簡單的邏輯回歸模型:
fromsklearn.linear_model import LogisticRegression
fromsklearn.metrics import f1_score
lreg= LogisticRegression()
lreg.fit(xtrain,ytrain)
是時候進行預測了!首先,在驗證集上:
preds_valid = lreg.predict(xvalid)
因為F1評分標準是比賽的官方評價標準,所以我們用其來評價模型。
f1_score(yvalid, preds_valid)
輸出: 0.789976
驗證集的F1分數令人非常印象深刻。現在,讓我們繼續對測試集進行預測:
# make predictions on test set
preds_test = lreg.predict(elmo_test_new)
準備提交文件,將其上傳到競賽頁面:
#prepare submission dataframe
sub= pd.DataFrame({'id':test['id'], 'label':preds_test})
#write predictions to a CSV file
sub.to_csv("sub_lreg.csv",index=False)
這些預測使我們在公開排行榜上的得分為0.875672。坦率地說,這相當令人印象深刻,因為我們只做了最基本的文本預處理,並使用了一個非常簡單的模型。
我們還能用ELMo做什麼?
我們只是親眼看到ELMo對文本分類是多麼有效。如果再加上一個更複雜的模型,它肯定會提供更好的性能。ELMo的應用不僅限於文本分類任務。還可以將其用於文本數據的矢量化處理中。
利用ELMo還可完成更多NLP任務,如下所示:
機器翻譯
語言建模
文本摘要
命名實體識別
問答系統
評論列表
情感機構有專業的老師指導,我就在老師的指導下走出了感情的誤區,真的很不錯!
可以幫助複合嗎?