穷人的语义处理工具箱之一:语义版Jaccard
?????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? author:?張俊林? ?
|為什么我們是ML界的窮人
如果對工業界里的機器學習(ML)從業者進行階級劃分的話,劃線標準不是你用的算法的學名聽起來多酷炫,無論你手里掄著的是最潮的深度高達1000層的深度學習核炸彈,還是聽起來有點掉渣的大刀長矛樸素貝葉斯,如果沒有大量數據,尤其是能跑監督學習算法的帶標簽訓練數據,你就是ML界標準的底層渣男渣女或者渣娘炮。再加上計算資源,如果貴公司有上千臺GPU服務器集群可供閣下驅使,外加十幾火車皮的訓練數據,那你就可能成為ML界的新貴、大數據處理領域的馬云。
但是,理想豐滿現實骨感,大多數中小公司里ML界貧農們的日常生活寫照是這樣的:前一天晚上看到某篇論文,學到一個讓人興味盎然的新ML姿勢,第二天一大早橫刀立馬豪氣干云地沖到公司,熱血沸騰血往上涌準備擼起袖子大干一場,但是一轉念掰著指頭數數,看看自己手上超不過手指數量的數據資源,頓生有心殺賊,無力回天的挫敗感。這畫面的美麗程度與“看不進書的時候照照鏡子,加不了班的時候數數銀行卡余額”有異曲同工之妙。
但是窮人也應該有一顆追求美和好好活下去的強大心臟,既然沒有訓練數據,那我們就好好玩無監督學習,老老實實地去擬合你想要的公式,俗話說得好:無產階級打破的只有枷鎖,而得到的是整個世界。而本文就是帶給ML界底層農民工的禮物和福音。
好,安利部分到此為止,以下是正文。
原生態Jaccard作為相似性計算函數,無論是計算思想還是工程實現都簡單得令人發指。假設有兩個集合:集合A和集合B,每個集合內各自包含若干元素,那么Jaccard計算兩個集合的相似性就是用兩個集合元素的交集作為分子,兩個集合元素的并集作為分母,除一下就完事。因為交集代表了兩個集合相同部分的子集合,并集代表了兩個集合加起來總共有多少個元素,用相同部分占總元素數比例來代表集合相似性,兩者重疊部分越多則兩個集合越相似。
在文本處理領域,Jaccard也是一個比較常用的計算句子相似性的工具。具體使用時,往往是把兩個要計算相似程度的句子改造成n-gram片段組成的兩個集合,然后通過計算兩個集合相同的n-gram片段個數作為集合交集,兩個集合合并后的n-gram片段個數作為集合并集,這樣就能得出兩個句子的相似性得分。比如下面兩個句子:
句子A:蘋果電腦的價格
句子B:蘋果ipad的價格
兩個句子轉換為2-gram后,形成如下集合:
SetA={蘋果,果電,電腦,腦的,的價,價格}
SetB={蘋果,果ipad,ipad的,的價,價格}
兩個集合求交集得出相同語言片段個數為:3.(即為:蘋果,的價,價格)
兩個集合求并集得出分母大小為:8
所以這兩個句子的相似度為:3/8=0.375
在Jaccard的世界里,一切都是這么簡單,智商80以上人群看完之后都會會心一笑,此刻,他們的眼里閃耀著智慧的光芒。
原生態Jaccard得分由于過于簡單,在計算相似性只用Jaccard的情形比較少,但是往往會被用來作為機器學習系統的一個比較重要的特征因子,很多NLP領域的評測方法也參考這個思想,比如機器翻譯評測方法BLUE,文本摘要評測方法ROUGE-N等本質上就是類似于Jaccard的思想,其實語義Jaccard對傳統Jaccard的改進思路也可以試著用來改造BLUE或者ROUGE-N評價標準,當然如果實驗證明沒效果就當我沒說這句話。
|語義版Jaccard的誕生
公元2015年的第一場雪,來得比往年早了一些。鏡頭搖近,一位面容憔悴衣衫落魄的中年男子(注1:不是杜甫,是本文作者)飄入畫面,他深深地吸入一口帝都醇厚甘冽的霧霾,由于吸得生猛,只見他虎軀一震,止不住干咳兩聲,背手望著空中漫天紛揚飛舞的細雪,詩興大發,正要蹦出:“月是故鄉明,霾是故都純,黃狗身上白,白狗身上腫”這首情景交融感人至深的千古詠雪名句。突然間,一個詭異的念頭飄入他的腦中:經典Jaccard只是衡量兩個句子字面上的文本匹配程度,如果用語義相似性替代字面相似性來改造一下Jaccard,那么在處理文本的時候是否會更有效些呢?
這是一個好問題。
很明顯,引入語義版Jaccard后可以對傳統使用字面版本匹配的Jaccard進行改進,因為此時是在文本的語義空間進行的匹配,而非單獨字面匹配,應該會引入更多信息量。比如:
句子A:請問蘋果電腦的價格
句子B:問下聯想筆記本多少錢
如果用3-gram構造句子集合片段的話,很容易看出來字面匹配版Jaccard算出的相似性為0,因為兩者沒有任何字面上匹配的三元組片段。但是很明顯地,我們可以看出下面的單詞之間語義相似度是非常高的:
請問vs問下
蘋果vs聯想
電腦vs筆記本
價格vs多少錢
那么我們現在面臨的問題是:能否對傳統只進行字面匹配的Jaccard進行改造,使得兩個句子能夠進行語義級別的匹配計算?即可以將“電腦”/“筆記本”這種字面不匹配但是語義匹配的情況考慮進去,這是觸發那位中年男子頭腦中語義版Jaccard的最初想法。
|語義版Jaccard
經過一番推敲試錯調整,最終定稿的語義版Jaccard具體計算公式如下:
我知道,這個公式看上去有點丑陋,但請耐心讓我把話說完。
上述公式中,分子部分代表兩個句子語言片段組成集合的語義交集:即語義相似性部分,而分母代表兩個句子語言片段組成集合的語義并集,又可分為兩部分:第一個部分和分子一樣,代表語義交集,而第二個部分代表這兩個集合的語義差異程度,兩者之和形成集合并集。
1.語義相似性部分(分子)如何計算
為了便于畫圖與說明,我們拿以下短語為例子來說明語義版Jaccard公式的分子是如何計算出來的。真實應用場景中句子長度可以不做這種長度限制。
SentenceA: 電腦多少錢
SentenceB:計算機的價格
第一步: 把SentenceA切割成3-gram表達形式,于是SentenceA變成如下形式
SetA={電腦多,腦多少,多少錢}
第二步:把SentenceB切割成3-gram表達形式,于是SentenceB變成如下形式
SetB={計算機,算機價,機價格}
第三步:構造相似性矩陣:以句子長度比較短的句子集合元素作為矩陣縱坐標,較長的句子集合元素作為橫坐標,改造為如下矩陣:
第四步:用橫坐標和縱坐標對應的語言片段的語義相似性填充矩陣元素值。首先可以用Word2Vec訓練出每個漢字的Word Embedding,也就是其低維向量表示,一定程度上代表其包含的語義信息。那么3-gram包含了三個漢字,這3-gram的語義向量Word Embedding該怎么表示?可以簡單粗暴地把其三個漢字的Word Embedding相應維度上的值累加求和即可。
這樣兩個3-gram片段對應的Word Embedding都有了,剩下的就簡單了,它們兩個的語義相似性直接用Cosine計算兩個Word Embedding在語義空間的向量夾角就成,一般語義越相似,Cosine得分越大。填充好的矩陣形式如下:
第五步:填好相似性矩陣值是基礎工作,做完之后,讓我們正式開始計算語義版Jaccard公式的分子部分。
首先,先拍腦袋選出一個閾值a=0.6,意思是在計算語義相似性的時候,如果語言片段相似性高于閾值,我們認為兩個語言片段語義匹配,這個閾值可以用來控制計算結束過程。算法描述如下。
算法:語義Jaccard相似性部分計算;
輸入:語義相似性矩陣S,閾值a;
輸出:語義Jaccard公式分子部分分值Total
步驟:
循環如下步驟,直到算法退出:
Step 1.找到相似性矩陣S中的當前所有元素中的最高值;
Step 2.如果這個最高值高于閾值a,則累加到Total中,轉步驟3;
如果這個最高值低于閾值,則分子部分計算結束,輸出Total值;
Step 3.把當前矩陣中的最高值對應矩陣橫坐標和縱坐標的行及列中所有元素值置為0,其含義是這兩個片段不再參與后面的計算了,然后返回Step 1步驟繼續循環;
在我們上面給出的例子中,如果遵循上述算法流程,則如是循環:
1. 分子總分Total=0;我們假設閾值a取0.8;
2.首先找到矩陣中的最高值:坐標[1,1]對應的0.99,其代表片段“電腦多”和“計算機”的片段語義相似性,發現其大于閾值0.8,那么累積分子得分,更新Total值:Total=0.99;
3.將矩陣中第一行和第一列所有元素相似性置為0,則當前形成下圖:
4.然后在矩陣剩下的元素里面找到最高值:坐標[3,3]對應的0.98,其代表片段“多少錢”和“的價格”的片段語義相似性,發現其值大于閾值0.8,那么累積分子得分,更新Total值:
Total=0.99+0.98=1.97
5.將矩陣中第三行和第三列所有元素相似性都置為0,則當前形成下圖:
6.發現坐標[2,2]對應的當前最高值小于閾值a,則計算過程結束,輸出分子值Total=1.97。此時兩個句子各自剩余1個語言片段沒有進行匹配,即:“腦多少”和“算計價”,可以將這兩個片段看做兩個句子語義不同的部分,用來計算分母。
2.分母的計算
語義版Jaccard公式的分母分為兩部分:第一部分其實就是分子,代表兩個語言片段集合語義相似的部分;第二部分從含義上代表兩個語言片段集合語義不同的部分。而這兩者之和代表兩個集合的語義并集。
假設經過分子計算步驟后,我們已經把參與分子部分計算的語言片段陸續都從SetA和SetB中刪除掉,那么兩個集合SetA和SetB可能都會剩余部分語言片段沒有進行匹配,則分母部分的m定義為:
?
其含義是兩個集合中沒有達到語義匹配標準(由閾值a控制)的總片段個數或者兩者中取最大值。
Xdif代表SetA中沒有參與分子計算的所有語言片段;Ydif代表SetB中沒有參與分子計算的所有語言片段。而Cosine(Xdif, Ydif)的意思是兩者的語義相似性,所以1-Cosine(Xdif, Ydif)代表兩者的語義差異大小,兩者語義差異越大則兩個句子整個語義版Jaccard相似性分數會被拉低。而m和1-Cosine(Xdif, Ydif)相乘可以這么理解其含義:兩個集合有m個片段語義不匹配,而每個不匹配片段的不匹配程度是1-Cosine(Xdif, Ydif),所以可以將其理解為不匹配片段的權重。而語義版Jaccard分子部分也可以理解為語義匹配片段與其權重乘積之和,而其權重則為兩個語言片段的語義Cosine相似性。也就是說,這個語義版Jaccard公式的本質是:把兩個集合根據閾值a拆分為兩個子集合:語義匹配片段子集合/語義不匹配片段子集合;分子部分是語義匹配片段及其權重乘積之和;而分母部分是兩個集合的并集,即是分子部分代表的兩個集合語義相同部分和由語義不匹配片段子集合計算出的兩者語義差異部分。
我們接著把上面沒有算完的語義Jaccard計算例子算完,在分子計算部分我們已經算出兩者的語義相似性Total=1.97,此時可以算分母了:首先,因為兩個句子只剩下“腦多少”和“算計價”兩個語義不匹配的片段,所以可以得出m=1,而Cosine(Xdif, Ydif)=0.45,所以1-Cosine(Xdif, Ydif)=0.55,于是m*(1-Cosine(Xdif, Ydif))=0.55,得出分母值為:1.97+0.55=2.52,由于分子部分是1.97,于是這兩個句子的語義版Jaccard最終得分為:
SemJac(“電腦多少錢”,” 計算機的價格”)=1.97/2.52=0.78
而對應的原生態Jaccard計算出的相似性分值為0,由此可見,語義版Jaccard確實是可以改善經典Jaccard只做字面匹配的缺點,體現出句子深層次的語義相似性的。
|閾值參數調節方法
如果仔細觀察,你會發現語義版Jaccard公式上方游蕩著一個面目猙獰的幽靈,一個潛在的不安定因素,就是那個閾值a。因為它鬼魅般的存在,使得我們面臨一個尷尬的選擇,那就是這個閾值應該取多少是合理的。
雖說我們是ML界的無產階級,從擁有的訓練數據數量角度來說屬于一窮二白三沒轍,但是就算是解放前萬惡的舊社會,過年的時候楊白勞也要想辦法給親閨女扯個紅頭繩不是。作為ML界的民工,我們也可以自力更生,自己做少量比如幾百條訓練數據,用這些極少量的訓練數據來過個好年。
可以這么著來多快好省地調整出合理的閾值參數:做出一批語義相同的句子對作為正例,然后再做一批語義重疊但是又不同的句子對作為負例。然后不斷調整閾值a的取值,優化目標是看哪個閾值能夠使得語義Jaccard公式計算出正例的相似度得分整體偏高往上移,而負例的相似度得分整體偏低往下走。這有點類似于機器學習里面通過驗證集調整超參數的做法,不過對訓練數據數量要求會小得多。
我們從自己做的整個訓練集合中抽取子集合,選擇大約400對語義相同的句子對作為正例集合,選擇大約400對語義相關但是不同的句子對作為負例。然后判斷使用不同閾值語義版Jaccard對這些句子對的分值區間分布情況,我們知道無論是原生態Jaccard還是語義版Jaccard,其分值區間都落在[0,1]之間,我們把分值區間再細分為10個子區間:
[0,0.1],[0.1,0.2],[0.2,0.3]……[0.9,1.0] (在后續圖示中,縱軸標號為10的為[0,0.1]區間,標號為9的為[0.1,0.2]區間,以此類推)
這樣就可以畫出不同閾值下正負例得分在10個區間的分布情況,而能夠最好地把正負例區分開的閾值就是好閾值。下面分別是閾值a=0.5和a=0.9時的分值分布情況:
語義版Jaccard正負例分值區間區分度(閾值a=0.5)
從上面兩組不同閾值的實驗結果可以看出,閾值a=0.9對正負例的區分情況要明顯優于a=0.5的情況。通過設置不同的閾值進行實驗,我們得出的最優閾值就是0.9,在這個閾值下對正負例句子對的語義區分程度最強。
通過上述方式,我們就可以只利用少數訓練數據來獲得超參數a的合理取值范圍,這就是我們ML界農民工們喜聞樂見的場景。
|語義版Jaccard vs原生態Jaccard實驗效果對比
為了驗證語義版Jaccard相對原生態Jaccard在句子相似性判斷任務上的有效性,我們做了實驗對比。實驗方法如下:
從整個訓練集合中抽取子集合,選擇大約400對語義相同的句子對作為正例集合,選擇大約400對語義相關但是不同的句子對作為負例。然后判斷使用原生態Jaccard及語義版Jaccard對這些句子對的分值區間分布情況。
因為原生態Jaccard沒有可調參數,所以只會得出一組分值。而語義版Jaccard我們按照上節介紹的閾值調優方法選擇最優參數閾值a=0.9,得出的正負例得分分布情況如下面兩圖所示:
經典Jaccard正負例分值區間區分圖
從這張圖可以看出,原生態Jaccard公式對于正負例區分度很差,大多數正例和負例得分都落在了[0.0.1]之間,這是由于其只對句子進行字面級別的相似判斷導致的。
語義版Jaccard正負例分值區間區分圖(a=0.9)
從上面這張圖可以看出,語義版Jaccard在進行閾值調優后,可以很明顯地把正例和負例語義相似性得分在[0,1]分值區間內散落區分開,正例大多數分值落在[0.4,1.0]區間,負例大多數分值落在[0,0.4]以內,。在這個數據集合下,當閾值a取0.9時,如果把語義Jaccard計算相似性閾值設定為0.4,即給定兩個句子<A,B>,利用語義版Jaccard計算公式對其相似性打分,如果得分高于0.4即判斷為語義相同,得分低于0.4判斷為語義不同,那么其將獲得較高的判斷準確率,而原生版Jaccard公式因為大多數正例和負例得分都落在[0,0.1]區間,所以很難選擇判斷標準。當然對于很多應用來說,只需要知道0.9這個閾值即可,不需要確定0.4這個區分標準。
由上述實驗結果可知,語義版Jaccard公式可以表達句子深層語義的相似性,而且可以通過少量訓練數據獲取最具區分度的閾值,所以相信將其作為一個新的計算語義相似性工具箱的工具,會對很多機器學習應用有直接的幫助作用,理論上凡是使用經典Jaccard的計算場景都可以引入語義版Jaccard計算公式。
致謝:感謝暢捷通公司智能平臺桑海巖、薛會萍、沈磊、黃通文等同事對于計算實現或訓練語料收集方面的工作。當然,考慮到本文的行文風格,也許你們寧愿沒有這段指名道姓的致謝。
掃一掃關注微信號:“布洛卡區” ,深度學習在自然語言處理等智能應用的技術研討與科普公眾號。
總結
以上是生活随笔為你收集整理的穷人的语义处理工具箱之一:语义版Jaccard的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习与自然语言处理之五:从RNN到L
- 下一篇: 深度学习与自然语言处理之四:卷积神经网络