1. 程式人生 > 實用技巧 >Efficient Knowledge Graph Accuracy Evaluation 實現記錄

Efficient Knowledge Graph Accuracy Evaluation 實現記錄

介紹

本文記錄了 Efficient Knowledge Graph Accuracy Evaluation 的實現過程。目前實現了在隨機生成的三元組上進行 static evaluation 和 incremental evaluation。

Github 地址:https://github.com/zzk0/KGAccEval

整體結構

整體結構採用論文中描述的結構。

檔案結構:

KnowledgeGraph, SamplePool, SampleCollector, Estimation 這幾個類相對比較獨立,由 Evaluation 這個類來組織和呼叫。

實現細節


如何隨機生成知識圖譜資料

我們隨機產生知識圖譜的三元組,三元組的內容是空的,但是預先給它確定是正確還是錯誤。

KnowledgeGraph 類中有一個方法 init,需要傳入準確率和實體個數。對每一個實體,隨機確定實體的三元組個數,並且隨機改變這個實體的準確率,之後進行伯努利實驗,產生一個 0 到 1 之間的隨機數,檢查是否小於準確率(也在 0 和 1 之間),如果是,那麼產生的三元組為正確的三元組,如果否,那麼產生的三元組為錯誤的三元組。


隨機取樣

簡單隨機取樣,假設三元組一共有 n 個。有兩種簡單隨機取樣的方法。

第一種,產生一個 [0, n) 的整數隨機數,用散列表來記錄這個隨機數是否產生過,如果沒有,那麼抽取這個隨機數對應的三元組;如果有,那麼重新執行這個過程。不過這種方法有問題,當我們抽取的三元組越來越多,重新抽取的次數會越來越多,如果只有 100 個三元組,並且我們抽取了 99 個,那麼要抽取到最後一個三元組的期望次數是 100.

第二種,產生一個 List,這個 List 順序放入 [0, n),然後使用 Collections.shuffle 打亂。從頭開始抽取即可。


加權取樣

加權取樣的方法有二種。

第一種,類似隨機取樣的第一種。因為抽取的是實體,所以直接產生一個 [0, n) 的整數隨機數,這個隨機數落到的那個實體就被抽取出來。如果實體的三元組個數越多,那麼被抽取的概率越大。同樣,使用一個散列表記錄是否抽取過,這個方法同樣存在缺陷。

第二種,蓄水池演算法。給每個實體一個 key,\(r = Rand(0,1), key = r^{1 / size}\),選取前 k 大個 key。


正態分佈分位點

浙大版概率論中第 50 頁有分位點的定義。

我們要找 \(\alpha\) 的置信區間,需要找到 \(z_\frac{1-\alpha}{2}\) 這個點,使到正態分佈落在大於\(z_\frac{1-\alpha}{2}\) 的概率為 \(\frac{1-\alpha}{2}\),這樣可以構造一個對稱區域,落到兩邊的概率為 \(1-\alpha\),落到中間的概率就是 \(\alpha\) 了。

那麼這個分位點如何計算呢?查了一下,有一個叫做 Hastings formula 的東西[1],可以計算上 \(\alpha\) 分位點。

private double computeZx(double alpha) {
    double[] c = {2.515517, 0.802853, 0.010328};
    double[] d = {0.0, 1.432788, 0.189269, 0.001308};
    double y = Math.sqrt(-2 * Math.log(alpha));
    double cy = 0, dy = 0;
    for (int i = 0; i < 2; i++) {
        cy = cy + c[i] * Math.pow(y, i);
        dy = dy + d[i + 1] * Math.pow(y, i+1);
    }
    return y - cy / (dy + 1);
}

Reservoir Incremental Evaluation

假設我們要取樣總體 \(G + \delta\) 的樣本,可是我們只有取樣了 \(G\) 的樣本,如何取樣 \(\delta\) 才能得到 \(G + \delta\) 的樣本呢?

這就是蓄水池演算法的優越之處了:蓄水池演算法可以在不瞭解總體的情況下,進行取樣!

假設 \(G\) 是 TWCS 取樣的結果,我們是根據實體三元組多少加權隨機抽樣的。我們可以將其視為對 \(G\) 使用蓄水池演算法計算的結果,所以當新的三元組加進來的時候,我們按照蓄水池演算法執行下去,就可以得到 \(G + \delta\) 的結果。

我在實驗的時候,一開始我的做法是保持原來的加權抽樣的程式碼不變。我們可以拿到加權取樣的結果,比如有 60 個實體。於是,我對這 60 個實體計算蓄水池演算法的 key。可是這些 key 的大小其實分佈得比較散,在進行增量更新的時候,計算的 key 大部分會覆蓋原來的那些,把原來的樣本替換掉。道理很簡單,我加權挑出來的這 60 個 key,是先挑再算權值,不是算權值再挑的。假如增量更新有 1000 個實體,那麼相當於隨機產生 1060 個key,再去挑選最大的幾個。這裡有點強者生存的感覺,對於原來的那 60 個 key,如果是先計算 key 再挑選,那麼留下來的 key 都是比較“強”的。如果是先挑,再計算 key,那麼這些 key 比較隨機,容易被後面的強者替代。所以做了這個部分,我將原來加權抽樣的程式碼做了更改,先計算 key,再挑選。在增量評估的初始化的時候,獲取這些 key。


增量評估

開始做這個部分時,一直在想如何儘可能不要改懂程式碼來實現。

這種想法是徒然的,妄圖在不改變程式碼的情況下增加新功能。程式碼還是要改,要加點程式碼。不過現在回想起來,其實,原來的程式碼結構還行吧,至少做到了一點:對擴充套件開放,對修改封閉。修改程式碼是儘量減少了,除了那個加權取樣的演算法必須得改之外,其他地方保持不懂。


有待解決的問題

  1. 在蓄水池演算法的增量評估當中,這個部分實現的不完整。當蓄水池演算法抽樣完成之後,還需要重新計算 MoE,檢查是否在範圍內,如果不在,那麼還需要再抽樣。
  2. 在蓄水池演算法的增量評估當中,當進行多次增量的時候,比如原知識圖譜正確率為 0.5,不斷地新增正確率為 0.9 的知識圖譜,此時會發現正確率上升的很慢。因為蓄水池當中的那些個隨機數都是身經百戰,強者生存下來的,所以很難被替代。
  3. 論文提供了增量評估的方法,卻沒有提供“減量”評估的方法。我認為可以這樣處理,假設使用的是 TWCS 評估的結果,並且 TWCS 使用的加權取樣是由蓄水池演算法來實現的,那麼我們可以去掉“減量”,重新挑選前 k 大的實體。
  4. 論文中說,按照實體的三元組多少的分層是不理想的。那麼該如何分層呢?論文中直接使用實體的正確率來分層,得出的實驗結果很美好,暗示了合理的分層有助於提高評估的效率。

參考文獻

[1] https://wenku.baidu.com/view/3ca32836581b6bd97f19ea8c.html?re=view