女人的嘴,騙人的鬼?ELMo教你用算法分辨女人心

情感導師 5949

 添加導師LINE:jaqg

獲取更多愛情挽回攻略 婚姻修復技巧 戀愛脫單幹貨

「語境」有多重要呢?

比如:你寫了一篇論文放在桌上,一般人問你:「這是什麼東西?」那可能只是純粹地問這是什麼東東。但如果是你的導師問你,那問題就嚴重了,潛台詞是:這TM寫的是什麼玩意兒?

語言有着人類最複雜的遊戲法則。尤其是在戀愛關係中,女孩子往往遊刃有餘,她們一時興起笑裡藏刀拋出的問題,往往讓男生分分鐘「送命」,比如這樣的:

沒有男友的小編只能調戲Siri,它的回答是這樣的:

女人的嘴,騙人的鬼?ELMo教你用算法分辨女人心

好吧,「直男」中的戰鬥機,不配在愛情界擁有姓名!

機器無法理解句子的真正含義,一直是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任務,如下所示:

機器翻譯

語言建模

文本摘要

命名實體識別

問答系統

評論列表

頭像
2024-05-01 14:05:05

我一閨蜜諮詢過,很專業也很靠譜,是一家權威諮詢機構

頭像
2024-04-04 13:04:25

求助

頭像
2023-08-25 02:08:12

老師,可以諮詢下嗎?

 添加導師LINE:jaqg

獲取更多愛情挽回攻略 婚姻修復技巧 戀愛脫單幹貨

發表評論 (已有3條評論)