Locality Sensitive Hashing ( LSH,局部敏感哈希 ) 詳解

       這篇文章想給大家介紹一個神奇的東東:LSH得意首先看看它有什麼用先~它可以快速地找出海量數據中的相似數據點,聽着有點抽象可憐?那我們來舉個實際的例子,比如說你有海量的網頁(這裏的網頁是指你擁有的本地數據,不是指互聯網上的),你現在想找和一個特定網頁相似的其它網頁,就比如你想在海量的網頁中找出和我這篇博文相似的網頁~最naive的方法就是去遍歷整個數據集,一個一個頁面去比較,看看哪一個頁面和我的這個頁面最相似,當然所謂的相似需要你自己去定義,可以用Cosine Similarity、Jaccard Coefficient等去衡量(可以參考我的另一篇博文:常用相似性、相關性度量指標),至於特徵向量的構造,那就有很多方法了,如使用分詞後的各詞的TF-IDF值,這裏就不展開了。

     現在假設你已經對各個頁面提取好了特徵,那下面的事情就是:給定一個特徵,如何快速地從海量的特徵中找到和這個特徵相似的一些特徵?這時候LSH就閃亮登場了(鼓掌ing...),先看看它的名字,Locality Sensitive Hashing,局部敏感哈希。哈希大家應該都知道,它的查找時間複雜度是O(1),有着極高的查找性能,那什麼叫“局部敏感”的哈希?它的意思就是:如果原來的數據相似,那麼hash以後的數據也保持一定的相似性,這玩意就叫局部敏感哈希。

      來看看我們通常的哈希,比如有一個hash function: f(x)=(x*7)%10,有兩個數據x1=123,x2=124,現在用f(x)把它們hash一下,f(x1)=1,f(x2)=8,這想說明什麼呢?看看原來的數據,是不是很相似?(假設用歐氏距離度量)再看hash後的數據,那就差得遠了,說明這個hash它並沒有保持相似性,那麼這種就不是局部敏感哈希。

     那麼LSH就是一種在hash之後能保持一定的相似性神奇玩意兒,這裏爲什麼說是“保持一定的相似性”?因爲我們知道,hash函數的值域一般都是有限的,但是要哈希的數據卻是無法預知的,可能數據大大超過其值域,那麼就不可能避免地會出現一個以上的數據點擁有相同的hash值,這有什麼影響呢?假設有一個很好的hash function,好到可以在hash之後很好地保持原始數據的相似性,假設它的不同取值數是10個,然後現在我有11個截然不相似的數據點,想用這個hash function來hash一下,因爲這個hash function的不同取值數是10個,所以必然會出現一個hash桶中有1個以上的數據點,那剛纔不是說11個截然不相似的數據點嗎?它們應該有不同的hash值纔對啊。沒錯,的確希望它是這樣,但實際上很難,只能在hash之後保持一定的相似性。其根本原因就是在做相似性度量的時候,hash function通常是把高維數據映射到低維空間上,爲什麼映射到低維空間上?因爲高維空間上計算複雜度太高。

     降維會對相似性度量造成什麼影響?數據的維數在某種程度上能反映其信息量,一般來說維數越多,其反映的信息量就越大,比如說對於一個人,假設有一個一維數據:(姓名),有一個三維數據(姓名,身高,體重),那麼這個三維數據反映的信息是不是要比一維的多?如果我們知道的信息越多,是不是就能越準確地判定兩個東西的相似性?所以,降維就在某種程度上造成的信息的丟失,在降維後的低維空間中就很難100%保持原始數據空間中的相似性,所以剛纔是說“保持一定的相似性”。

      好傢伙,一方面想把數據降維,一方面又希望降維後不丟失信息,這是不可能的,那麼就要做一個妥協了,雙方都讓一步,那麼就可以實現在損失一點相似性度量準確性的基礎上,把數據降維,通常來說,這是值得的。說了這麼多,那LSH究竟是如何做的呢?先一句話總結一下它的思想吧:它是用hash的方法把數據從原空間哈希到一個新的空間中,使得在原始空間的相似的數據,在新的空間中也相似的概率很大,而在原始空間的不相似的數據,在新的空間中相似的概率很小。

            其實在用LSH前通常會進行一些降維操作,我們先看看下面這張圖:

         先說說整個流程,一般的步驟是先把數據點(可以是原始數據,或者提取到的特徵向量)組成矩陣,然後通過第一步的hash functions(有多個哈希函數,是從某個哈希函數族中選出來的)哈希成一個叫“簽名矩陣(Signature Matrix)”的東西,這個矩陣可以直接理解爲是降維後的數據,然後再通過LSH把Signature Matrix哈希一下,就得到了每個數據點最終被hash到了哪個bucket裏,如果新來一個數據點,假如是一個網頁的特徵向量,我想找和這個網頁相似的網頁,那麼把這個網頁對應的特徵向量hash一下,看看它到哪個桶裏了,於是bucket裏的網頁就是和它相似的一些候選網頁,這樣就大大減少了要比對的網頁數,極大的提高了效率。注意上句爲什麼說是“候選網頁”,也就是說,在那個bucket裏,也有可能存在和被hash到這個bucket的那個網頁不相似的網頁,原因請回憶前面講的“降維”問題。。但LSH的巧妙之處在於可以控制這種情況發生的概率,這一點實在是太牛了,下面會介紹。

       由於採用不同的相似性度量時,第一步所用的hash functions是不一樣的,並沒有通用的hash functions,因此下面主要介紹兩種情況:(1)用Jaccard相似性度量時,(2)用Cosine相似性度量時。在第一步之後得到了Signature Matrix後,第二步就都一樣了。

          先來看看用Jaccard相似性度量時第一步的hash functions。

假設現在有4個網頁(看成是document),頁面中詞項的出現情況用以下矩陣來表示,1表示對應詞項出現,0則表示不出現,這裏並不用去count出現了幾次,因爲是用Jaccard去度量的嘛,原因就不用解釋了吧。

 好,接下來我們就要去找一種hash function,使得在hash後儘量還能保持這些documents之間的Jaccard相似度

         目標就是找到這樣一種哈希函數h(),如果原來documents的Jaccard相似度高,那麼它們的hash值相同的概率高,如果原來documents的Jaccard相似度低,那麼它們的hash值不相同的概率高。這玩意叫Min-Hashing。
         
        Min-Hashing是怎麼做的呢?請看下圖:
        首先生成一堆隨機置換,把Signature Matrix的每一行進行置換,然後hash function就定義爲把一個列C hash成一個這樣的值:就是在置換後的列C上,第一個值爲1的行的行號。呼,聽上去好抽象,下面看列子:


       圖中展示了三個置換,就是彩色的那三個,我現在解釋其中的一個,另外兩個同理。比如現在看藍色的那個置換,置換後的Signature Matrix爲:


            然後看第一列的第一個是1的行是第幾行,是第2行,同理再看二三四列,分別是1,2,1,因此這四列(四個document)在這個置換下,被哈希成了2,1,2,1,就是右圖中的藍色部分,也就相當於每個document現在是1維。再通過另外兩個置換然後再hash,又得到右邊的另外兩行,於是最終結果是每個document從7維降到了3維。我們來看看降維後的相似度情況,就是右下角那個表,給出了降維後的document兩兩之間的相似性。可以看出,還是挺準確的,回想一下剛剛說的:希望原來documents的Jaccard相似度高,那麼它們的hash值相同的概率高,如果原來documents的Jaccard相似度低,那麼它們的hash值不相同的概率高,如何進行概率上的保證?Min-Hashing有個驚人的性質驚訝

       就是說,對於兩個document,在Min-Hashing方法中,它們hash值相等的概率等於它們降維前的Jaccard相似度。下面來看看這個性質的Proof:
         設有一個詞項x(就是Signature Matrix中的行),它滿足下式:         
         就是說,詞項x被置換之後的位置,和C1,C2兩列並起來(就是把兩列對應位置的值求或)的結果的置換中第一個是1的行的位置相同。那麼有下面的式子成立:

         就是說x這個詞項要麼出現在C1中(就是說C1中對應行的值爲1),要麼出現在C2中,或者都出現。這個應該很好理解,因爲那個1肯定是從C1,C2中來的。

         那麼詞項x同時出現在C1,C2中(就是C1,C2中詞項x對應的行處的值是1)的概率,就等於x屬於C1與C2的交集的概率,這也很好理解,屬於它們的交集,就是同時出現了嘛。那麼現在問題是:已知x屬於C1與C2的並集,那麼x屬於C1與C2的交集的概率是多少?其實也很好算,就是看看它的交集有多大,並集有多大,那麼x屬於並集的概率就是交集的大小比上並集的大小,而交集的大小比上並集的大小,不就是Jaccard相似度嗎?於是有下式:


         又因爲當初我們的hash function就是

         往上面一代,不就是下式了嗎?

         這就證完了,這標誌着我們找到了第一步中所需要的hash function,再注意一下,現在這個hash function只適用於Jaccard相似度,並沒有一個萬能的hash function。有了hash functions,就可以求Signature Matrix了,求得Signature Matrix之後,就要進行LSH了。
         首先將Signature Matrix分成一些bands,每個bands包含一些rows,如下圖所示:

         然後把每個band哈希到一些bucket中,如下圖所示:

       注意bucket的數量要足夠多,使得兩個不一樣的bands被哈希到不同的bucket中,這樣一來就有:如果兩個document的bands中,至少有一個share了同一個bucket,那這兩個document就是candidate pair,也就是很有可能是相似的。
       下面來看看一個例子,來算一下概率,假設有兩個document,它們的相似性是80%,它們對應的Signature Matrix矩陣的列分別爲C1,C2,又假設把Signature Matrix分成20個bands,每個bands有5行,那麼C1中的一個band與C2中的一個band完全一樣的概率就是0.8^5=0.328,那麼C1與C2在20個bands上都沒有相同的band的概率是(1-0.328)^20=0.00035,這個0.00035概率表示什麼?它表示,如果這兩個document是80%相似的話,LSH中判定它們不相似的概率是0.00035,多麼小的概率啊!
       再看先一個例子,假設有兩個document,它們的相似性是30%,它們對應的Signature Matrix矩陣的列分別爲C1,C2,Signature Matrix還是分成20個bands,每個bands有5行,那麼C1中的一個band與C2中的一個band完全一樣的概率就是0.3^5=0.00243,那麼C1與C2在20個bands至少C1的一個band和C2的一個band一樣的概率是1-(1-0.00243)……20=0.0474,換句話說就是,如果這兩個document是30%相似的話,LSH中判定它們相似的概率是0.0474,也就是幾乎不會認爲它們相似,多麼神奇。
       更爲神奇的是,這些概率是可以通過選取不同的band數量以及每個band中的row的數量來控制的:

        除此之外,還可以通過AND和OR操作來控制,就不展開了。
        
        呼,LSH的核心內容算是介紹完了,下面再簡單補充一下當相似性度量是Cosine相似性的時候,第一步的hash function是什麼。它是用了一個叫隨機超平面(Random Hyperplanes)的東西,就是說隨機生成一些超平面,哈希方法是看一個特徵向量對應的點,它是在平臺的哪一側:

           這個可以直觀地想象一下,假設有兩個相交的超平面,把空間分成了4個區域,如果兩個特徵向量所對應的點在同一域中,那麼這兩個向量是不是捱得比較近?因此夾角就小,Cosine相似度就高。對比一下前面用Jaccard相似度時Signature Matrix的生成方法,那裏是用了三個轉換,在這裏對應就是用三個隨機超平面,生成方法是:對於一個列C(這裏因爲是用Cosine相似度,所以列的值就不一定只是0,1了,可以是其它值,一個列就對應一個特徵向量),算出該列對應的特徵向量的那個點,它是在超平面的哪個側,從而對於每個超平面,就得到+1或者-1,對於三個超平面,就得到三個值,就相當於把原來7維的數據降到三維,和前面用Jaccard相似度時的情況是不是很像?得到Signature Matrix後,就進行LSH,步驟是一樣的~~~~~~~

          參考:Stanford CS246課程PPT關於Locality Sensitive Hashing的章節,http://cs246.stanford.edu


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章