遺憾未進前10%, Kaggle&Quora競賽賽後總結

由Quora和Kaggle合辦的Quora Question Pairs | Kaggle比賽已經在三天前結束了,不知道各位大佬玩的是否開心呢?我在Private LB上最終獲得了426名(剛剛去看了一眼又前進了5名,貌似是verification還沒完成),也就是Top 12.6%。好氣啊!最後一天看Pubilc LB的時候覺得自己穩得不行,肯定能進10%,果然Pubilc LB這種東西看看就行了別當真。

於是這篇文章主要是分享一些自己在比賽中踩過的坑和感想,之後大概會整理出一些可能有點用的代碼扔進Github里,下一篇文章大概會分析一下前幾名選手的solution吧。

目錄

  1. 比賽簡介&數據分析
  2. 特徵提取
  3. 模型策略
  4. 總結

  1. 比賽簡介&數據分析

這次的 Quora Question Pairs比賽目標是判定兩個問題是否是重複的。訓練集給出了兩個問題的文本,每個問題獨立的qid,標籤是1(duplicate)和0(not duplicate)。提交的預測結果則要求給出predict probability,評價標準是logloss

  • 顯然這是一個判斷相似度的NLP問題,由於文本都是問題的形式,所以都比較短小。

  • 訓練集中正樣本的分布大概是34%(如果我沒記錯的話),而且我們可以通過提交一個全為1或全為0的submission,根據得分來推算出Public LB的測試集中正樣本分布大概是17%, 所以如果rebalance一下訓練集使得它與Public LB同分布,就可以在Public LB上得到更好看的分數(然而並沒有什麼卵用,因為我們不可能知道Private LB的樣本分布)

  • 訓練集有404290組數據,整個測試集有2345796組數據,也就是說訓練集是測試集的17%, 而Public LB的測試數據是整個測試集的35%。從這個結果來看,Public LB的得分對評價模型的泛化性能非常重要。因此,我在這次比賽中,在Pubilc LB 和 Private CV產生矛盾的時候總是選擇相信Public LB。

2. 特徵提取

我在這個部分花費了接近兩個月的時間,最終選擇的特徵也數次反覆,然而還是沒能做到盡善盡美。這次比賽最大的遺憾就在於此。

  • 在現有模型花費了太多時間。比賽的初期我迷信於各種現成的Word Embedding模型,把Word2vec, GloVe, Doc2vec等等都拿來研究了一遍。然而我還是低估了NLP的水有多深,在無關的細節上花費了太多時間。而這些現有模型對我的幫助也實在十分有限,在我最終用來stacking的策略里,word2vec大概起到了0.01~0.04的提升(Pubilc LB),而doc2vec更是直接被我拋棄。雖然它們最終還是成為了solution的一部分,但是與花費的大量時間相比,這一點點的改進實在是不成正比。不過這樣一段翻paper+查wiki+上手寫程序的經歷確實增加了我對NLP的了解(╮(╯▽╰)╭)
  • 高估了自己擁有的計算性能。由於是第一次參加比賽,我對數據的規模並沒有多少直觀認識,在選擇特徵階段完全沒有考慮特徵會不會太多而難以計算(特徵這種東西當然是越多越好嘛!)而事實證明自己的小破電腦(RMBP13 i5 8G)完全不可能承擔這樣的計算量。接近270k,300dim的不可壓縮的word2vec原始向量,如果按float64的精度,光讀進內存就快15G了,如果說內存開銷還能靠降精度解決,那訓練時間的瓶頸則根本無解,我嘗試用SVD把一部分訓練集降到50dim(降維本身也是漫長的等待)然而效果下降太多,遂放棄。這就導致了在訓練模型的階段才發現,很多特徵連基本的調優都難以做到,不得不放棄。這等若是讓前面的工作白費了。
  • 前期清洗沒做好,中期返工。到了計算各種distance的時候才發現stopwords清理得不夠乾淨,掙扎了一下還是決定從頭開始;訓練doc2vec的時候突然覺得特殊名詞(首字母大寫或者全部大寫的單詞)應該特殊對待,於是重新做一次tokenize...雖說隨著比賽的進行不斷會有新想法是很正常的,但是在工作初期確實應該盡量保留更多的靈活性,減少每一次反覆帶來的額外開銷。

於是由於各種各樣的影響,我最後的訓練集直到五月下旬才最終確定,包含了55個特徵,包括

  • 統計特徵:問題的長度、相同詞的長度...
  • 各種距離:cosine distance, word moves distance...基於word2vec和tfidf(3gram)
  • fuzzy-wuzzy特徵
  • 其他word2vec和gloVe的衍生特徵
  • 一些 Magic Features,比如
    • 未出現在Google的word2vec模型中的詞在兩個問題中同時出現的個數(有些拗口,如果一個詞沒有出現在google的預訓練模型中,說明它是特殊名詞/很不常見/不是英語辭彙/拼寫錯誤。這樣的詞如果同時出現在兩個問題中,有理由說明它們有高相似度)
    • 問題在整個語料庫中出現的頻率(這個magic feature是有人在discussion中分享出來的,對我提升了大概0.02的Public LB)

可以看到最終確定的特徵中幾乎沒有包含模型的原始輸出,因為僅剩的十幾天時間使我實在無法承擔幾百維特徵的訓練開銷。我甚至放棄了一個用word2vec加權的tfidf特徵集合,之後一直想有時間一定要試一試,可惜沒有機會了。

3.模型策略

  • 從選擇特徵的後期直到比賽結束,我一直都不斷使用XGBoost驗證新想法,評估新特徵帶來的改進。因為這個工具強大、高效、幾乎不用調參就能擬合的不錯、對不同規模的數據都能有不錯的效果、可以很方便的觀察train loss 和 valid loss的變化...我大概可以再開一個篇文章寫用XGBoost打kaggle的100種好處

  • 最終的模型由兩個stacking model(一個11 folds, 一個6 folds, 都是兩層, 盡量選用不同的base model)和XGBoost取平均而成。(沒有LSTM! 沒有NN!是的你沒有看錯,因為我不會&沒時間)
  • 我還花點時間搭了一個簡易的管理模型、批量調優、自動完成n-folds stacking、生成submission的pipeline,代碼量大概在200行。然而這個pipeline只完整跑過兩次,從節約時間上講感覺並不賺,但是有了pipeline之後數據和模型倒是能得到規範整理和存放了。

從開始訓練模型開始,我的小破電腦就一直在全速運轉,最後也僅僅來得及對所有用來stacking的模型都進行了一輪調參。當時我還有一個為高概率相似的問題不斷建立並查集,最終在數據集中產生clusters的想法,可惜也沒有機會實現了。

4.總結

  • 最終的得分是 0.15752(Public LB),0.16084(Private LB),這也使得我的最終排名下降了140多名,順利滾粗了前10%
  • 有很多想法還沒實現,這是最氣的
  • 第一次完整參加kaggle比賽,感覺比像想像中累(尤其是最後幾天),但是能每天看著Pubilc LB一點點往上爬,就像是玩RPG一樣。
  • 雖然比較倉促,還是不知不覺學到了很多NLP的知(chang)識(shi)
  • 很期待大佬們的solution

最後,紀念離大佬們最近的一次

推薦閱讀:

Kaggle 入門 1.1——A Journey through Titanic
【持續更新】機器學習特徵工程實用技巧大全
深度學習入門:Tensorflow實戰Digit Recognizer(一)
kaggle小黃車競賽 得分:0.41038

TAG:机器学习 | Kaggle | 编程 |