k均值的损失函数_一种基于均值不等式的Listwise损失函数
1 前言
1.1 Learning to Rank 簡介
Learning to Rank (LTR) , 也被叫做排序學習, 是搜索中的重要技術, 其目的是根據候選文檔和查詢語句的相關性對候選文檔進行排序, 或者選取topk文檔. 比如在搜索引擎中, 需要根據用戶問題選取最相關的搜索結果展示到首頁. 下圖是搜索引擎的搜索結果
1.2 LTR算法分類
根據損失函數可把LTR分為三種: 1. Pointwise, 該類型算法將LTR任務作為回歸任務來訓練, 即嘗試訓練一個為文檔和查詢語句的打分器, 然后根據打分進行排序. 2. Pairwise, 該類型算法的損失函數考慮了兩個候選文檔, 學習目標是把相關性高的文檔排在前面, triplet loss 就屬于Pairwise, 它的損失函數是$$ loss = max(0, score_{neg}-score_{pos}+margin)$$, 可以看出該損失函數一次考慮兩個候選文檔. 3. Listwise, 該類型算法的損失函數會考慮多個候選文檔, 這是本文的重點, 下面會詳細介紹.
1.3 本文主要內容
本文主要介紹了本人在學習研究過程中發明的一種新的Listwise損失函數, 以及該損失函數的使用效果. 如果讀者對LTR任務及其算法還不夠熟悉, 建議先去學習LTR相關知識, 同時本人博客自然語言處理中的負樣本挖掘 (分類與排序任務中如何選擇負樣本) 也和本文關系較大, 可以先進行閱讀.
2 預備知識
2.1 數學符號定義
$q$代表用戶搜索問題, 比如"如何成為宇航員", $D$代表候選文檔集合,$d^+$代表和$q$相關的文檔,$d^-$代表和$q$不相關的文檔, $d^+_i$代表第$i$個和$q$相關的文檔, LTR的目標就是根據$q$找到最相關的文檔$d$
2.2 學習目標
本次學習目標是訓練一個打分器 scorer, 它可以衡量q和d的相關性, scorer(q, d)就是相關性分數,分值越大越相關. 當前主流方法下, scorer一般選用深度神經網絡模型.
2.3訓練數據分類
損失函數不同, 構造訓練數據的方法也會不同:
-Pointwise, 可以構造回歸數據集, 相關的數據設為1, 不相關設為0.
-Pairwise, 可構造triplet類型的數據集, 形如($q,d^+, d^-$) -Listwise, 可構造這種類型的訓練集: ($q,d^+1,d^+_2..., d^+_n , d^-_1, d^-_2, ..., d^-{n+m}$), 一個正例還是多個正例也會影響到損失函數的構造, 本文提出的損失函數是針對多正例多負例的情況.
3 基于均值不等式的Listwise損失函數
3.1 損失函數推導過程
在上一小結我們可以知道,訓練集是如下形式 ($q,d^+1,d^+_2..., d^+_n , d^-_1, d^-_2, ..., d^-{n+m}$), 對于一個q, 有m個相關的文檔和n個不相關的文檔, 那么我們一共可以獲取m+n個分值:$(score_1,score_2,...,score_n,...,score_{n+m})$, 我們希望打分器對相關文檔打分趨近于正無窮, 對不相關文檔打分趨近于負無窮.
對m+n個分值做一個softmax得到$p_1,p_2,...,p_n,...,p_{n+m}$, 此時$p_i$可以看作是第i個候選文檔與q相關的概率, 顯然我們希望$p_1,p_2,...,p_m$越大越好, $p_{n+1},...,p_{m+n}$越小越好, 即趨近于0. 因此我們暫時的優化目標是$sum_{i=1}^{n}{p_i} rightarrow 1$.
但是這個優化目標是不合理的, 假設$p_1=1$, 其他值全為0, 雖然滿足了上面的要求, 但這并不是我們想要的. 因為我們不僅希望$sum_{i=1}^{n}{p_i} rightarrow 1$, 還希望相關候選文檔的每一個p值都要足夠大, 即我們希望m個候選文檔都與q相關的概率是最大的, 所以我們真正的優化目標是: $$max(prod_{i=1}^{n}{p_i} ) , sum_{i=1}^{n}{p_i} = 1$$
當前情況下, 損失函數已經可以通過代碼實現了, 但是我們還可以做一些化簡工作, $prod_{i=1}^{n}{p_i}$是存在最大值的, 根據均值不等式可得: $$prod_{i=1}^{n}{p_i} leq (frac{sum_{i=1}^{n}{p_i}}{n})^n$$
對兩邊取對數: $$sum_{i=1}^{n}{log(p_i)} leq -nlog(n)$$
這樣是不是感覺清爽多了, 然后我們把它轉換成損失函數的形式: $$ loss = -nlog(n) - sum_{i=1}^{n}{log(p_i)}$$
所以我們的訓練目標就是$min{(loss)}$
3.2 使用pytorch實現該損失函數
在獲取到最終的損失函數后, 我們還需要用代碼來實現, 實現代碼如下:
# A simple example for my listwise loss function # Assuming that n=3, m=4 # In[1] # scores scores = torch.tensor([[3,4.3,5.3,0.5,0.25,0.25,1]]) print(scores) print(scores.shape) ''' tensor([[0.3000, 0.3000, 0.3000, 0.0250, 0.0250, 0.0250, 0.0250]]) torch.Size([1, 7]) ''' # In[2] # log softmax log_prob = torch.nn.functional.log_softmax(scores,dim=1) print(log_prob) ''' tensor([[-2.7073, -1.4073, -0.4073, -5.2073, -5.4573, -5.4573, -4.7073]]) ''' # In[3] # compute loss n = 3. mask = torch.tensor([[1,1,1,0,0,0,0]]) # number of 1 is n loss = -1*n*torch.log(torch.tensor([[n]])) - torch.sum(log_prob*mask,dim=1,keepdim=True) print(loss) loss = loss.mean() print(loss) ''' tensor([[1.2261]]) tensor(1.2261) '''該示例代碼僅展現了batch_size為1的情況, 在batch_size大于1時, 每一條數據都有不同的m和n, 為了能一起送入模型計算分值, 需要靈活的使用mask. 本人在實際使用該損失函數時,一共使用了兩種mask, 分別mask每條數據所有候選文檔和每條數據的相關文檔, 供大家參考使用.
3.3 效果評估和使用經驗
由于評測數據使用的是內部數據, 代碼和數據都無法公開, 因此只能對使用效果做簡單總結: 1. 效果優于Pointwise和Pairwise, 但差距不是特別大 2. 相比Pairwise收斂速度極快, 訓練一輪基本就可以達到最佳效果
下面是個人使用經驗: 1. 該損失函數比較占用顯存, 實際的batch_size是batch_size*(m+n), 建議顯存在12G以上 2. 負例數量越多,效果越好, 收斂也越快 3. 用pytorch實現log_softmax時, 不要自己實現, 直接使用torch中的log_softmax函數, 它的效率更高些. 4. 只有一個正例, 還可以考慮轉為分類問題,使用交叉熵做優化, 效果同樣較好
### 4 總結 該損失函數還是比較簡單的, 只需要簡單的數學知識就可以自行推導, 在實際使用中也取得了較好的效果, 希望也能夠幫助到大家. 如果大家有更好的做法歡迎告訴我.
文章可以轉載, 但請注明出處:
- 本人簡書社區主頁
- 本人博客園社區主頁
- 本人知乎主頁
- 本人Medium社區主頁
總結
以上是生活随笔為你收集整理的k均值的损失函数_一种基于均值不等式的Listwise损失函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机号支付怎么开通?银行也可以通过手机号
- 下一篇: 点云数据生成三维模型_可直接编辑的高质量