前言
一年前小夕在知乎上提問過這麼一個問題
文字分類有哪些論文中很少提及卻對效能有重要影響的tricks?
連結:https://www.zhihu.com/question/265357659/answer/578944550
當時正好在刷一個比較有趣的task,結果發現奇奇怪怪的tricks可以帶來不少的效能收益。再加上後來為了驗證一個小idea跑了一堆公開的文字分類資料集,雖然idea沒有多亮,倒是積累和摸索了不少刷效能的tricks╮( ̄▽ ̄””)╭然後呢,小夕後續又用這些tricks刷了不少相關的比賽(哪怕是文字匹配這種特殊的文字分類問題),發現baseline+一堆tricks+簡單整合就可以隨隨便便刷到一個文字分類的水比賽的top10甚至top3,甚感調參和tricks的重要性。
然鵝,最近好一段時間都沒有文字分類這個基礎問題了,感覺都快忘了,趁著還有點模糊的記憶就整理下來分享給大家叭~希望能在大家刷論文實驗、比賽或實際專案的時候提供點幫助或者啟發。
首先來一個結論,tricks用的好,調參調的妙,TextCNN也能吊打絕大多數花裡胡哨的深度模型。tricks沒用好,SOTA模型也會效能差的讓你懷疑人生。下面就不分重點,沒有邏輯的開始本文辣。
關於分詞器
中文也好,英文也好,拿過來資料集無可避免的就是要看看要不要做分詞(有的小夥伴以為英文資料集就完全不用分詞真的讓人很無奈鴨),如果要做,就要糾結分詞器的選擇了。
路人丙:我廠有全方位吊打各種開源分詞工具的分詞器了
小夕:好了你可以往下劃了
首先就有一個問題,真的是演算法越“先進”的分詞器就會給下游任務帶來越好的效能嗎?
很多人走到這一步的時候會忽略一個東西,詞向量!!!
其實比起分詞演算法本身的先程式度,在神經網路使用預訓練詞向量的大背景下,確保分詞器與詞向量表中的token粒度match其實是更更重要的事情!畢竟哪怕你詞分的再好,一旦詞向量表裡沒有的話,那麼就變成OOV了,分的再好也木用了╮( ̄▽ ̄””)╭(除非你不嫌麻煩多寫點程式碼去對相對於詞向量表的OOV進行特殊處理,反正我一般嫌麻煩╮(╯▽╰)╭)於是這裡就有了兩種情況。
1. 已知預訓練詞向量的分詞器
一般像word2vec、glove、fasttext這些官方release的預訓練詞向量都會公佈相應訓練語料的資訊,包括預處理策略如分詞等,這種情況真是再好不過了,不用糾結,如果你決定了使用某一份詞向量,那麼直接使用訓練該詞向量所使用的分詞器叭!此分詞器在下游任務的表現十之八九會比其他花裡胡哨的分詞器好用。
2. 不知道預訓練詞向量的分詞器
這時就需要去“猜”一下分詞器了。怎麼猜呢?首先,拿到預訓練詞向量表後,去裡面search一些特定詞彙比如一些網站、郵箱、成語、人名等,英文裡還有n't
等,看看訓練詞向量使用的分詞器是把它們分成什麼粒度,然後跑幾個分詞器,看看哪個分詞器的粒度跟他最接近就用哪個,如果不放心,就放到下游任務裡跑跑看啦。
當然,最理想的情況當然是先確定最適合當前任務資料集的分詞器,再使用同分詞器產出的預訓練詞向量啦。可惜網際網路上不可能有那麼多版本的公開詞向量供選擇,因此自己在下游任務訓練集或者大量同分布無監督語料上訓練詞向量顯然更有利於進一步壓榨模型的效能。不過,怎麼為當前的任務去預訓練一份兒好用的詞向量又夠寫一篇文章的。。這裡就不展開講啦,小夕以後再寫~(沒關注小夕的趕緊關注!)
當然,除了分詞器跟詞向量表要match上,另外還要保證大小寫、OOV的定義等跟詞向量表match上。如果使用了一個區分了大小寫的詞向量表,但是你還將下游任務的單詞全都小寫,那麼不用想了,絕對效能丟N多個百分點。
關於中文字向量
路人丁:好麻煩,我不分詞了,我要用字向量了哼
小夕:別逃( ̄∇ ̄)
如果你真的將char-level作為主力,那麼別忘了中文的字向量也要預訓練!並且預訓練的時候記得把視窗開大一些,不要直接使用word-level的視窗大小哦,其他預訓練超引數也隨手調一調更好了,絕對比隨機初始化的字向量明顯的好。
如果資料集噪聲很嚴重
這裡噪聲嚴重有兩種情況。對於資料集D(X, Y),一種是X內部噪聲很大(比如文字為口語化表述或由廣大網際網路使用者生成),一種是Y的噪聲很大(一些樣本被明顯的錯誤標註,一些樣本人也很難定義是屬於哪一類,甚至具備類別二義性)。
對於前一種噪聲,一個很自然的想法是去使用語言模型或者基於編輯距離去做文字糾錯,然鵝實際中由於專有名詞和超出想象的“假噪聲”存在,在實際場景中往往效果並不是很好。
這裡小夕一般有兩種思路,一種是直接將模型的輸入變成char-level(中文中就是字的粒度),然後train from scratch(不使用預訓練詞向量)去跟word-level的對比一下,如果char-level的明顯的效果好,那麼短時間之內就直接基於char-level去做模型叭~
如果效能差不太多,或者char的已經做到頭了,想做一下word-level呢?
不要急,先幫小夕買根棒棒糖唄( ̄∇ ̄)
一個很work但是貌似沒有太多人發現的trick就是使用特殊超參的FastText去訓練一份詞向量啦。
為什麼說特殊呢?一般來說fasttext在英文中的char ngram的視窗大小一般取值3~6,但是在處理中文時,如果我們的目的是為了去除輸入中的噪聲,那麼我們可以把這個視窗限制為1~2,這種小視窗有利於模型去捕獲錯別字(想象一下,我們打一個錯誤詞的時候,一般都是將其中的一個字達成同音異形的另一個字),比如word2vec學出來的“似乎”的最近詞可能是“好像”,然而小ngram視窗fasttext學出來的“似乎”最近詞則很有可能是“是乎”等內部包含錯別字的詞,這樣就一下子讓不太過分的錯別字構成的詞們又重新回到了一起,甚至可以一定程度上對抗分詞器產生的噪聲(把一個詞切分成多個字)。當然,如果資料集很乾淨的話,這樣訓練詞向量的話可能就gg了。
而對於後一種噪聲的情況(即Y中的噪聲),一種很直接的想法是做標籤平滑,然而小夕在實戰中使用多次發現效果並不是太明顯。
最後總結的trick是,首先忽略這個噪聲,強行的把模型儘可能好的訓出來,然後讓訓練好的模型去跑訓練集和開發集,取出訓練集中的錯誤樣本和開發集中那些以很高的置信度做出錯誤決策的樣本(比如以99%的把握把一個標籤為0的樣本預測為1),然後去做這些bad cases的分析,如果發現錯誤標註有很強的規律性,則直接擼一個指令碼批次糾正一下(只要確保糾正後的標註正確率比糾正前明顯高就行)。
如果沒有什麼規律,但是發現模型高置信度做錯的這些樣本大部分都是標註錯誤的話,就直接把這些樣本都刪掉吧~常常也可以換來效能的小幅提升,畢竟測試集都是人工標註的,困難樣本和錯標樣本不會太多。
baseline選用CNN還是RNN?路線沿著CNN還是RNN走?
在文字分類中真的不要太糾結這個問題,個人傾向於CNN,主要是因為跑得快呀。。。可以多跑幾組實驗,多好。而且實際經驗感覺TextCNN這種基礎款CNN模型不僅實現特別容易,而且很容易成為一個資料集上的很強的baseline(除非這個分類任務很難),花一兩個小時把這個baseline做出來後再去做其他模型一點也不遲~也有助於早期就能糾正大方向。
而如果要談到客觀的思路決策上,那就去花一個小時好好看一下資料集吧~如果你感覺資料集裡很多很強的ngram可以直接幫助生成正確決策,那就CNN起步吧。如果感覺很多case都是那種需要把一個句子看完甚至看兩三遍才容易得出正確tag,那就RNN起步吧。
當然,如果資料大,又有顯示卡,還可以嘗試Transformer。時間多的話,還可以CNN、RNN的模型都跑出來簡單整合一下。
Dropout加在哪裡
word embedding層後、pooling層後、FC層(全聯接層)後,哦了。起步階段dropout機率保持統一,有時間再單獨微調就好(從來沒有這個時間過)。
至於偶爾有人吹捧的word dropout策略(將一些token隨機mask成[PAD],或者說0。注意這個操作跟dropout加在embedding層後不等價哈),最後有時間的話試一下就好,親測在dropout調好的情況下一般並不會發揮多大作用。
關於二分類
二分類問題一定要用sigmoid作為輸出層的啟用函式?當然不是,嘗試一下包含倆類別的softmax吧。可能多一條分支就多一點資訊叭,雖然後者在數學形式上更醜一點,但是實踐中常常帶來零點幾個點的提升也是比較玄學了。
關於多標籤分類
如果一個樣本同時擁有多個標籤,甚至標籤同時還構成了DAG(有向無環圖),不要著急,先用binary-cross-entropy訓出個baseline來(即把每個類別變成一個二分類問題,這樣N個類別的多標籤分類問題就變成了N個二分類問題),畢竟這個都在tensorflow裡有現成API了,即tf.nn.sigmoid_cross_entropy_with_logits。因此實現代價很小。
然後你還可能驚喜的發現,這個baseline做好後好像多標籤問題不大了,DAG問題自己也基本解決了(雖然模型層並沒有專門針對這個問題作處理),然後就可以安心做模型辣。什麼?問題木有解決?去查論文吧╮( ̄▽ ̄””)╭小夕還沒有接觸過這方面太難的資料集。
類別不均衡怎麼辦
像網上說的那樣趕緊各種上取樣下采樣boosting策略用起來?nono,正負樣本比才9:1的話,繼續做你的深度模型調你的超參吧,模型做好後你會發現這點不均衡對模型來說不值一提,決策閾值也完全不用手調。但!是!如果你發現經常一個batch中完全就是同一個類別的樣本,或者一些類別的樣本經過好多batch都難遇到一個的話,均衡就非常非常有必要了。類別不均衡問題傳送門->
別太糾結系列
別太糾結文字截斷長度使用120還是150
別太糾結對效能不敏感的超引數帶來的開發集效能的微小提升
別太糾結未登陸詞的embedding是初始化成全0還是隨機初始化,別跟PAD共享embedding就行
別太糾結最佳化器用Adam還是MomentumSGD,如果跟SGD的感情還不深,就無腦Adam,最後再用MomentumSGD跑幾遍
還是不會用tricks但是就是想跑出個好結果怎麼辦
BERT瞭解一下。
Over。
暫時想起來的就是這些啦,剩下有想起來的tricks小夕會更新到知乎上,傳送門:
https://www.zhihu.com/question/265357659/answer/578944550