Deep Upsupervised Cardinality Estimation
- 本篇部落格是對Deep Upsupervised Cardinality Estimation的解讀,原文連線為:https://dl.acm.org/doi/pdf/10.14778/3368289.3368294
- 本文介紹瞭如何使用深度自迴歸模型(如:MADE、transformer)來進行基數估計的任務(利用模型訓練擬合資料分佈)
- 特點:
- 使用autoregressive model,無監督學習
- 沒有做任何獨立性假設
- 支援範圍查詢
選擇度(基數)估計問題定義
- selectivity——選擇度。本文針對的是給定謂詞,估計其可以估計資料表中滿足該謂詞的元組的比例,有如下定義:$$sel(\theta):=|{\ x \in T :\theta (x)=1}|/|T|$$
其中分母T就是表的總行數,分子是滿足選擇謂詞的行數。
選擇度和資料聯合分佈的關係
- 文中給出聯合分佈(joint distribution)的定義:
其中分母T仍表示錶行數,f為滿足a1,a2...an條件的行數。因此實際上聯合分佈和選擇度有著十分緊密的聯絡(基本一致)。同時聯合分佈還可以通過因式分解(factorization)寫成:
該式沒有進行任何獨立性假設,而且保留了屬性之間的相互聯絡,因此想獲得相對準確的選擇度,實際上就是要構建能計算上式的模型。
深度自迴歸模型如何計算joint distribution
- 作者選用Autoregressive Model進行對資料聯合分佈的擬合。以某一列為例。對於一列資料的分佈,模型的input為前幾列值的組合(因為是條件概率),輸出的是在前幾列的條件下,改列的分佈概率。例如一張表travel_checkins含有三個屬性:city、year、stars。給定一行作為輸入:<Portland;2017;10>:
-
\[0\rightarrow M(city) \]\[E_{city}(Portland)\rightarrow M(year) \]\[(E_{city}(Portland)\oplus E_{year}(2017)) \rightarrow M_{star} \]
上式三個輸出依次是條件概率:$$\hat{P}(city),\hat{P}(year|city),\hat{P}(star|city,year)$$
- 下圖簡略展示了模型的工作流
編碼解碼策略
在訓練模型時,我們必須將資料表中的各個元素編碼成機器能夠看懂的語言,模型輸出時我們要將編碼進行解碼得到各種概率,下面介紹作者提出的編碼解碼策略。
-
small-domain:
- encodding:one-hot
- decoding:一個全連線層FC(F,|Ai|),其中F為隱藏層大小,|Ai|第i列的值域大小。輸出一個長度|Ai|的向量,每個元素表示位於該值的概率。
-
large-domain:
- encodding:Embedding,通過詞嵌入將各值對映為一個固定長度h的向量
- decoding:Embedding reuse。當屬性值域太大時,向上面一樣使用一個全連線層產生一個非常長的向量,這在空間上和計算複雜度上都十分低效。在這裡作者提出Embedding reuse,同樣使用一個全連線層FC(F,h),其中F還是隱藏層的大小,h為Embedding規定的向量長度,這樣神經網路就會生成一個長度為h的向量H,接著通過計算\(HE_i^T\)並對其進行標準化處理,我們就能得到一個代表選擇度的度量值。
具體執行
本文提供的方法支援點查詢和範圍查詢,一般來說\(sel=P(X_1\in R_1,X_2\in R_2,...X_n\in R_3)\)
- 點查詢,即等值查詢,將上式轉換為:\(sel=P(X_1=x_1,X_2=x_2,...X_n=x_3)\)
- 範圍查詢:對於範圍查詢,本文采用漸進取樣的方法對資料表進行取樣進行概率的估計
- wildcard-skipping:這裡提到的萬用字元不是指like查詢,而是指age = any,也就是age可以為任何值,即範圍查詢age = [0, Di]。所以這裡提到的萬用字元是為了滿足有些條件沒有filter的處理。
為了達到這個目的,作者設計了特殊的token,Xi = MASKi,如age這一列的token為MASK_age。訓練的時候,會把每一列用這個token替換掉,進行訓練(這樣就需要訓練n次?n為列的個數,相當於資料被複制了n份,每一份把一列的值替換為token)。
實際操作的時候,會隨機sample一個tuple,age對應的值換成MASK_age,表明age取所有值,其他值的條件概率就是當age取所有值的情況下,其條件概率為多少,作為label。至於sample多少條資料,這個要看具體效果了。
另外要根據實際的query確定哪些列需要有這個萬用字元。再舉個具體的例子,一個表有三列a b c,查詢為a=1,那麼模型訓練的時候必須要有b=MASK_b,c=MASK_c,查詢的輸入為a=1, b=MASK_b,c=MASK_c。再如a<10,一種方法是sampling,還有一種方法是模型訓練的時候要有a=MASK_a, 這樣查詢的時候輸入是a=MASK_a, b=MASK_b,c=MASK_c,a的輸出會得到所有的值,再把<10對應的值的概率加起來。
所以,這個萬用字元是非常有用的,因為在真實查詢中,不可能保證所有列上都有條件,那麼沒有條件的列就用萬用字元替代。當然也可以用sampling的方式,但是萬用字元的查詢效率更高。
屬性的順序
從上面的分析中可以看到每列實際上是有順序的,比如模型的輸入是列a b c,輸出是條件概率,既然是條件概率,那麼b的概率是給定a得到,c的概率是給定a和b得到。所以這個順序要提前定好,如果查詢是b=1 a=2,需要把順序調整成a=2 b=1輸入到模型。
均勻取樣和漸進取樣
兩種sampling策略是為了解決範圍查詢的選擇度估計問題。
假定一個範圍查詢域\(R=R_1\times R_2 \times ... \times R_n\),如果用等值的方法處理這種問題,在某種比較壞的情況下,查詢域可能會非常大(比如可能為\(|A_1|\times |A_2| ... |A_n|\)),此時非常耗費時間和空間。為了解決這種問題,本文嘗試了兩種解決方案:
-
uniformly sampling
- 從R(查詢域)中均勻隨機抽樣出\(x^{(i)}\),接著將該\(x^{(i)}\)輸入模型,計算出該樣本在資料表中的概率:\(\hat{p_i}=\hat{P}(x^{(i)})\),基於樸素蒙特卡洛,對於S個樣本,我們可以將\(\frac{|R|}{S}\sum_{i=1}^{S}\hat{p_i}\)作為期望密度的無偏估計。簡單來說,該方案是將點隨機扔到目標區域R中,以探測其平均密度。
- 均勻取樣的缺點:考慮這樣一個情況,資料表T有n個屬性列,但每一列的資料都非常傾斜,有99%的資料只集中在前1%的值域中,剩下1%的資料分散到後99%的值域內。在這種情況下,如果我們想進行值域前50%的範圍查詢。通過隨機抽樣我們大概率只能抽到1%-50%內的資料,計算出的結果會嚴重失真。如果要保持準確性,我們必須抽\(1/(0.01/0.5)^n=1/0.02^n\)個樣本才能都取到資料高密度區域。真實的資料集中,這樣傾斜的資料常有出現,當均勻抽樣遇到這樣的資料會很快崩潰,產生非常大的誤差如下圖左,這裡我們使用下文提出的漸進取樣來決絕該問題。
-
progressive sampling
- 漸進取樣。在均勻取樣中,我們是隨機的在查詢域中選擇了一組樣本。但實際上,我們可以更有選擇性的挑選樣本。具體來說我們可以利用模型一邊生成各個屬性的概率分佈,一邊按照生成的概率分佈進行取樣,因為是逐步進行取樣的所以叫漸進取樣。通過漸進取樣,我們能很容易的取樣到高資料密度的區域,如上圖右。步驟如下:
- 漸進取樣。在均勻取樣中,我們是隨機的在查詢域中選擇了一組樣本。但實際上,我們可以更有選擇性的挑選樣本。具體來說我們可以利用模型一邊生成各個屬性的概率分佈,一邊按照生成的概率分佈進行取樣,因為是逐步進行取樣的所以叫漸進取樣。通過漸進取樣,我們能很容易的取樣到高資料密度的區域,如上圖右。步驟如下:
(*^▽^*)
(*^▽^*)
(*^▽^*)
(*^▽^*)
(*^▽^*)
筆者解讀不易,若是有所幫助,給筆者點個贊吧(*^▽^*)
歡迎來與筆者交流相關問題!