submodular函數優化

幾個月之前寫了一篇文本摘要任務的一些總結(詳見 文本自動摘要任務的初步總結),其中在說無監督方式做抽取式摘要的時候,參考了一篇論文:A Class of Submodular Functions for Document Summarization 。最近在做業務新聞摘要的時候,基於當前無標註數據,準備應用該方法來做無監督的抽取式摘要。但是在實現的過程中,發現了很多之前忽略的細節問題,因此本篇作爲上篇總結文章的補充,聚焦優化求解submodular函數的具體實現。

前情回顧

首先,簡單回顧一下A Class of Submodular Functions for Document Summarization 的基本思想。submodular函數具有submodularity,它是經濟學上邊際效益遞減(property of diminishing returns)現象的形式化描述。形象的比喻就是餓的時候喫一個包子,比八分飽的時候喫一個包子帶來的滿足感更強。然後我們以摘要中常見的兩個度量來表示一個摘要的重要性分數,分別爲相關性和冗餘度。可以通過設計各種不同種類的函數來分別代表相關性和冗餘度來比對提升整體方法的效果。最後我們通過一些優化算法,得到使得該函數取最大值的摘要實例。函數的設計需要滿足一定的條件,具體如下:

1、函數有不等式約束條件。每次將一個摘要句子加入到摘要集合中時,通過submodular函數能夠計算得到一個增益分數,同時該操作同時也會有一定的消耗cost,對於摘要來說,可以用摘要句子的個數或者摘要集合句子中的字符(字節)總數來表示cost,當整體cost累計達到一定的上界時,我們就不能再增加摘要句子了。因此cost需要滿足: 

2、函數是否具有單調性。這個條件對於後續使用的優化算法有極大的影響。這也是本篇文章會着重描述的內容。下面就詳細解析如何用優化算法來優化submodular函數。

有關於相關性和冗餘度的函數設計詳見我的上一篇總結文章,本篇不作爲重點內容。

submodular函數的求解問題

論文中提到,帶cost上界約束條件下的通用submodular函數最大化求解任務是一個NP難度問題。因此,在實現時,很難獲取全局最優解。但是我們可以通過一些算法來獲取接近最優解的次優解。貪心算法是一個應用較爲廣泛的算法,其邏輯簡單同時也能獲取接近最優的效果。通過對貪心算法的各種優化變種,我們可以對大部分的submodular函數進行求解。然而,在實際業務落地時,我們不能僅關注模型的效果,還需要關注模型的性能,尤其是在一些實時性要求較高的場景。傳統貪心算法的性能是比較差的,裏面包含了大量的循環計算邏輯(會包含兩兩句子之間的相似度計算)。因此,我們需要對貪心算法進行一些優化設計,使其在保證能夠得到近似解的同時又能降低計算複雜度。事實上,一個submodular函數是否單調,對於貪心算法的設計有很大影響。

非單調的submodular函數

我們首先看一個非單調submodular函數做摘要的例子。論文中給出了MMR的例子,關於MMR(Maximal Marginal Relevance)算法,同樣在我之前的文章中有詳細介紹,這裏就不重複描述了,僅給出其公式:

這個求解式可以轉化成: 

 。簡單來說就是將摘要k加入到候選摘要集合後通過F函數獲得的增益分數。對於MMR來說就是將候選句子Di加入到摘要集合後,整體的相關性分數會提升,但是冗餘度會增加,因此需要找到使得相關性-冗餘度得到最大值的句子。這裏F就包含了相關性和冗餘度,且是一個submodular函數。

但是這個函數顯然不是一個單調函數,因此傳統的最簡單貪心算法無法在常數級的量級上逼近最優解,每個迭代並不能保證通過增益分數選擇的句子在當前cost的條件下是最合適的(下面有具體的實例說明)。

那麼,對於MMR來說,難道就不能用貪心算法來優化求解了嗎?

當然可以!通過仔細閱讀論文,發現該篇論文的作者在另一篇文章中,給出了一個modified的貪心算法來對MMR算法進行求解。論文鏈接:Multi-document Summarization via Budgeted Maximization of Submodular Functions。下面給出該算法的基本流程:

摘要集G初始化爲空集set()
候選原文句子集合U初始化爲原文句子集合V
已經設計好的submodular函數f,這裏f(G+{l})-f(G)就是MMR的表達式
每個句子添加到G中的cost,cost上界爲B
while U is not empty and sum(cost(G))<=B:
     f_value_list = []
     for l in U:
        f_value_list.append((f(G+{l})-f(G))/(c_l)^r)
     k = argmax(f_value_list)
     if sum(cost(G))+cost(k)<=B and (f(G+{k})-f(G) >=0:
        G.add(k)
     U.remove(k)
end while
f_value_for_V_list = []
for v in V:
   if cost(v)<=B:
      f_value_for_V_list.append(f({v}))
v* = argmax(f_value_for_V_list)
if f({v*}) > f(G):
   return {v*}
else:
   return G

上述爲modified greedy algrithm的僞代碼。整體流程還是比較簡單的,相對於原始的貪心算法,論文主要優化了以下幾點:

1、這個貪心算法的最外層循環需要遍歷每一個候選句子。在每個迭代中,並不一定會選擇一個句子加入到摘要集合中,因此該算法的循環計算次數會比傳統的原始貪心算法要多。

2、在計算候選摘要句增益得分的時候,因爲每個句子的cost都不盡相同(例如句子長度,句子所在的位置等),因此需要做rescaling。該算法法在rescaling的基礎上引入了r這個超參數,論文中稱之爲scaling factor。

3、在跳出最外層循環後,並沒有立刻返回結果,而是又對原始文章中的每個句子單例進行分析,獲取得分增益最大且cost滿足條件的單個句子,最後將其submodular函數值與摘要集合的函數值進行比較,取最大的那個。

那麼問題來了,上述幾點優化的原因和目的是什麼呢?

論文中提到,一個貪心算法的最核心部分在於他的啓發式貪心邏輯。原始貪心算法是直接在每個迭代簡單選擇一個最大化分數增益((f(G+{k})-f(G))/c_k)的句子直到其累計的cost超過上界B,這樣做會導致算法的approximation factor依賴於非常數項。

approximation factor指用一些近似算法求解一些NP-hard難度問題時,獲取的近似最優解與原始最優解的逼近程度。對於求解最大值,0<factor<1,代表使用該算法至少能獲取原始最優解factor的次優解。

approximation factor 如果依賴於非常數項會導致什麼問題?例如,對於集合V={a,b},f(a)=1,f(b)=p,cost(a)=1,cost(b)=p+1,B=p+1。原始的貪心算法得到的最優函數結果爲1,選擇了a,而最終應當選取的最優解應當是b,其對應的最優函數結果爲p(因爲b的cost正好充滿B)。此時,可知逼近因子爲p,這個p是變量,與b的函數值相關。用非常數因子的算法做最優求解,降低了算法整體的逼近能力,使其極度依賴數據的質量。

因此論文提出了上述幾個優化點,其中,第三點主要是將得到的摘要集合和單個句子實例進行比較,這一步能夠保證我們在r=1時能夠得到常數項的逼近因子。(詳細的證明在論文的Appendix中,由於篇幅太長了,感興趣的同學請自行查閱論文,這裏就不贅述了。)

另外,上面第二點爲cost的rescaling增加了一個scaling factor r。增加這個因子的作用在於能夠平衡一些在選擇時難以取捨的例子,比如AB兩個句子,A的cost爲15,其增益爲2,B的cost爲10,其增益爲1,我們很難去界定A和B哪個更好。通過調整r,可以幫助某一方的選擇權重得到提升。當然這個超參數我在實際驗證的時候取1一般就可以,如果有驗證集的話,可以通過驗證集來調整這個超參數。

單調的submodular函數

雖然上述基於MMR的submodular函數被證明能夠以常數項逼近因子獲得接近最優解的解,但是顯然這種情況不會對所有的非單調submodular都成立。因此,將submodular函數設計成單調的對於高效應用貪心算法來說就顯得很有意義了。這也是A Class of Submodular Functions for Document Summarization 中將冗餘度函數設計成獎勵多樣性函數,使得其和相關性函數共同組成一個單調submodular函數的原因。對於單調的submodular函數而言,必定能通過貪心算法,以常數項因子逼近最優解。

至此,我們已經能夠基本實現submodular算法抽取摘要的核心內容。然而事情並沒有結束,從上述算法邏輯可知,這種貪心算法的性能是較低的,因爲它的最外層循環是遍歷所有的候選句子,而且最後還要做對句子單例做循環計算。那麼有沒有更加高效的算法能夠接近其效果,同時提升性能呢?

經過一些調研,我主要發現了兩個優化版本的貪心算法,分別是lazy greedy 以及stochastic greedy。這兩個算法都是針對單調submodular函數在原始貪心算法基礎上進行的優化。

lazy greedy algorithm

lazy greedy算法主要是利用了單調submodular的單調性。論文鏈接:Cost-effective Outbreak Detection in Networks 。其核心流程如下:

摘要集G初始化爲空集set()
候選原文句子集合U初始化爲原文句子集合V
已經設計好的submodular函數f,這裏f(G+{l})-f(G)就是MMR的表達式
每個句子添加到G中的cost,cost上界爲B
f_value_for_each_sentence = {l:100 for l in V} //對每個句子初始化一個極大的f_value值
first_update=True
while U is not empty and sum(cost(G)) <=B:
     if first_update
        計算f(G+{l})-f(G) for each l in U
        更新f_value_for_each_sentence for each l in U
        s* = argmax(f_value_for_each_sentence[U])
        if s* >=0:
            G.add(s*)
            U.remove(s*)
        first_update=False
     else:
        sorted_f_value = sorted(f_value_for_each_sentence,reverse=True)
        更新sorted_f_value中的最大值對應的句子的新f_value,看其新的value是否仍然是最大
        if f_value is max and f_value >=0 :
           將該句子添加到G中,從U中刪除該句子
        else:
           按照大小依次執行上述操作,直到找到一個f_value爲最大的值,將對應句子更新到摘要集合中
            

上述算法優化的地方在於每個迭代不一定會計算所有句子的增益分數。而是先將U中第i-1個迭代計算後的分數列表先進行由大到小的排序,在選取最大值對應的句子後,增益分數第二大的句子就成爲了第i個迭代中的最大值,假設爲A。在第i迭代計算時,優先對A先進行增益分數的更新計算,根據單調submodular函數的單調性可知,該句子極有可能仍然是目前U中最大的值。

當然,lazy greedy算法雖然在一定程度上提升了貪心算法的效率,但是它本質上卻沒有改變貪心算法的複雜度。在最壞情況下,每輪迭代中lazy greedy仍然需要計算所有U中句子的增益分數(更新增益分數後,直到U中最後一個句子才找到最大值)。

stochastic greedy algrithm

該算法相比於lazy greedy是真正優化了貪心算法的複雜度。其論文鏈接:Lazier Than Lazy Greedy 。它的算法核心思想非常簡單,在原始貪心算法的基礎上,在每輪迭代計算時,並不是對U中所有的句子都進行處理,而是隨機採樣一個子集,對這個子集進行循環計算。其中,引入一個超參數 

小結

本篇文章主要聚焦在如何對submodular函數進行最優解求解。探討了幾種貪心算法的變種,均能夠以常數因子逼近最優解。其中,探討了stochastic greedy以及lazy greedy方法,提升了貪心算法的性能,使得其能夠應用在實際業務中。

題外話

通過這次在業務中的實踐,發現了自己在之前的論文研究和實現中忽略了很多細節。之前在實現這篇論文方法的時候,只關注瞭如何去設計相關性和多樣性的建模函數,對於如何去優化求解這個函數直接就用了原始貪心算法,完全沒考慮其是否能夠得到逼近最優解的次優解,也沒考慮其算法的性能問題。深入研究後,才發現其中的技術細節還有很多需要探討。在之後的研究中,還是要關注細節,並通過實踐去了解一個技術點的全貌。

 

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