文 | 光大科技大數據部 盧格潤
在金融科技的業務場景下,我們不可避免地應用到自然語言處理(NLP)的技術去解決問題,比如智能問答系統、資訊輿情的分析等……
在自然語言處理中,很多實際應用具有共性問題,本文就以文本相似度的計算為例介紹自然語言處理解決問題的思路。
文本向量化相似度的計算相關示例總結
文本向量化
無論是中文、英文還是標點符號,都是機器無法直接做計算的,需要先將文本轉化為可計算和比較的數學表示的形式。
如何將一句話轉化為數學的形式呢?人們能想到最簡單的方式就是統計一句話有多少個詞;然後很自然的比較兩句話的相似程度就看它們有多少個詞一樣就好了;再比上兩個句子的總詞數,就能得到一個 0-1 之間的相似度了。這就是 Jaccard 相似度計算方法:
僅從一個詞語是否出現的角度,進行數學表示,進而進行相似度計算顯然是沒有充分利用文本中的信息的。人們希望對一句話數學的表示能夠更多地體現它包含的語義信息。因此人們想到,比起統計詞的總數,記錄每個出現的詞和其出現的頻率會獲得更多的信息,這就是構造 Bag of words(詞袋)。比如下列一個片段:
1.it was the best of times
2.it was the worst of times
3.it was the age of wisdom
4.it was the age of foolishness
這個片段中出現的所有詞構成一個詞袋["it","was","the","best","of","times","worst","age","wisdom","foolishness"],詞袋中共有10個詞,根據每個詞是否出現可以將每個句子轉化為10維的向量。對應詞語在整個片段中出現的順序,第一句話可以轉化為向量, 相應地,第二、三、四句話分別為,,。
在詞袋的基礎上能獲得哪些語義特徵呢?首先每個詞的重要性是不同的,希望比較相似度時更重要的詞能佔有更多的權重。因此需要想辦法能夠給句子中的詞做關鍵詞排序,一個經典的評估一個單詞重要程度的方法是 TF-IDF(詞頻-逆文檔頻率)。人們在閱讀時知道一個詞重要是因為人們讀過很多書,學習到了這個詞是重要的。TF-IDF 在做重要性排序時,也是學習了很多文檔才獲得的有關重要性的信息。基本思想是一個詞在一篇文章中出現的頻率越高且在其它文章中出現的頻率越低,這個詞就越重要。計算一個詞在一篇文檔中的重要性時考慮:
該詞在該文檔中出現的頻率該文檔所有詞出現的詞頻總數
語料庫的文檔總數包含該次的文檔數
詞語的權重就是 。對於之前例子中的向量,每個元素都需要乘上這個對應的權重。
之後人們又想到,詞袋模型並不能保留原本語句的語序信息,而我們或許可以通過語序得到一些同義詞,這些詞本身就比另一些詞更相似。這時一個假設被提出:如果兩個詞的上下文相似,那麼這兩個詞更有可能是同義詞。Word2Vec[1]就是利用這一假設訓練出詞向量來表示一個詞。Word2Vec 有兩種訓練方法,這裡介紹通過上下文預測中間這個詞被稱為 CBOW(Continuous Bag-of-Words Model)的方法(另一種訓練方法SKIP-GRAM與它正相反,通過中間詞預測上下文)。它其實是一個三層神經網絡模型。如圖所示:
以圖中的神經網絡為例,它Input Layer 是一個詞上下文各兩個詞的 one-hot 編碼4個10維的向量:,實際的 Output 是一個概率分布,訓練目標是讓這個概率分布儘可能接近所要預測詞的 one-hot 編碼.
具體過程如下:
這裡one-hot 編碼是 10維向量,假設需要得到的是 8 維詞向量。通過訓練得到兩個權值矩陣 ()和 ()。從 Input Layer 到 Hidden Layer,分別乘上 W 得到4個 8 維的向量,再取平均得到一個 8 維向量;從 Hidden Layer 到 Output Layer, 又與 相乘,再用 Softmax 處理得到一個概率分布。這個概率分布與要預測的詞的 one-hot 編碼越接近越好。事實上,就是我們需要的8維詞向量;有了每個詞對應的詞向量後,我們可以將句子轉化為一組向量表示。例如詞向量為8維,片段一中的每句話有6個詞,就將每個句子轉化為6個8維的向量作為一組。
將詞轉化為詞向量也就稱之為詞嵌入(Word Embedding),這裡所說的 Word2Vec 是實現詞嵌入的一種算法。
由詞嵌入再往下就要講到預訓練語言模型了。預訓練語言模型是 NLP 中很重要的研究領域,它的想法等同要讓一個小孩去寫作,要先讓其識字、讀書、理解文字的意義之後再動筆寫東西。為了讓機器實現這一想法,先通過一些任務預訓練(Pre-training)出一個模型,這個模型能夠提取出一些通用的語義特徵,然後再在一些具體的任務上比如文本分類、序列標註上做精調(Fine-tuning),這樣通過之前對語義理解能夠去做各種各樣的下遊任務。
其實詞嵌入就相當於預訓練語言模型中預訓練的這一部分。當然現在的預訓練語言模型已經在 CBOW 的基礎上改進了很多,並且運用了特徵抽取器使學習到的語義能夠更好地運用於下遊任務。
關於預訓練語言模型這裡暫不做更多的介紹,先繼續講講將句子轉化為能比較的向量以後該怎樣計算相似度。
相似度的計算
從第一部分的內容我們將一個句子轉化成了兩種形式:一種是一個句子轉化為一個向量的形式;另一種是句子中的每個詞都轉化為一個向量(Word2Vec)。
通常比較兩個長度相等的向量(N 維)可以計算餘弦距離或歐式距離:
餘弦相似度:歐氏距離:而 Word2Vec 將每個句子轉化為了一組 N 維向量,要比較兩組 N 維向量,我們需要再將每組 N 維向量轉化為一個 N 維向量再計算餘弦相似度或歐氏距離。這個過程稱為 Sentence embedding。
首先可以將一個句子中所有詞向量取平均;另外可以結合第一部分所說的 TF-IDF 給所有詞向量賦予權重後做加權平均。
還有一種取權重做加權的方法稱為SIF(smooth inverse frequency)[2],這種方法的核心是通過去掉一組句子的共有成分來保留各自關鍵的部分,以之前的片段為例,共有4個句子,每個句子包含6個詞向量,每個詞向量有8維:
首先對每個詞 計算一個權重為 其中 為超參數,為 在所有句子中的詞頻(通過在訓練集句子中的詞頻做估計),得詞頻越低權重越大;對每個句子中6個詞向量根據對應詞的權重做加權平均得到4個8維的句向量 ~;~作為列得到一個矩陣 X,X 的第一主成分為 u(通過奇異值分解得到);最後減去在 u 上的投影得到最終的句向量 :相關示例
利用gensim 庫[3]訓練 word2vec 模型:
from gensim.models import Word2Vec#text為語料庫model = Word2Vec(text, size=8, window=5, min_count=1)model.save("word2vec.model")sentence0=['it', 'was', 'the', 'best', 'of', 'times']sentence1=['it', 'was', 'the', 'worst', 'of', 'times']#vector0和vector1分別存兩組詞向量vector0=dict()for word in sentence0: vector0[word]=model.wv[word]vector1=dict()for word in sentence1: vector1[word]=model.wv[word]在實際訓練時 text 為我們所準備的語料庫,size 是我們所需要的詞向量維度,window 是每次去上下文共多少個詞訓練,min_count 為詞最少出現的次數。之後通過這個 word2vec.model 我們可以將需要計算相似度的句子做一個 word embedding。
利用 gensim 庫訓練 TF-IDF 模型:
from gensim.models import TfidfModelfrom gensim.corpora import Dictionary#document為一組句子,包括sentence0和sentence0dct = Dictionary(document) corpus = [dct.doc2bow(line) for line in document]model1= TfidfModel(corpus) 根據TF-IDF模型找到每個詞向量與對應的權重,每個句子中所有詞向量加權平均得到句向量 s0 和 s1:
s0=0wd=dict(model1[corpus[0]])for word in sentence0: w=wd[dct.token2id[word]] s0+= vector0[word]*ws0=s0/len(sentence0)s1=0wd1=dict(model1[corpus[1]])for word in sentence1: w=wd1[dct.token2id[word]] s1+= vector1[word]*ws1=s1/len(sentence1)利用公式計算餘弦相似度:
import numpy as npd1=np.dot(s0,s1)/(np.linalg.norm(s0)*np.linalg.norm(s1))總結
NLP 是一個發展很快的人工智慧領域,新的算法不斷出現打敗之前的算法,本文講解了做文本相似度計算在內的自然語言處理任務一個很基本的思路:都是需要先在大量的語料上進行學習,然後根據所學將文本用數學表示,再根據數學表示的形式進行之後的處理。
本文介紹的方法也存在一些明顯缺點,主要有兩點:1、沒有考慮多義詞;2、沒法根據具體任務做動態優化。
在此希望對自然語言處理感興趣的讀者能持續關注這一專題,之後會繼續給大家分享現在的 NLP 算法是如何處理這些問題的。
參考資料
[1]Efficient Estimation of Word Representation in Vector Space: https://arxiv.org/pdf/1301.3781v3.pdf
[2]Sanjeev Arora, et al. 2017. A Simple but Tough-to-Beat Baseline for Sentence Embeddings: https://openreview.net/pdf?id=SyK00v5xx
[3]GENSIM: https://radimrehurek.com/gensim/models/word2vec.html
我們是光大科技公司的追光實驗室團隊,將不定期推出數據挖掘和算法相關的數據科學原創文章。團隊定位打造基於知識驅動的機器學習實驗室,由實踐經驗豐富的數據分析挖掘工程師和專注算法的數據科學家精心準備相關作品,志在分享結合實際業務的理論應用和算法創新,以及其中的心得體會。