第五屆“達觀杯”自然語言處理演算法競賽——基於大規模預訓練模型的風險事件標籤識別已於10月中旬在第十屆CCF自然語言處理與中文計算國際會議現場落下帷幕。
本屆大賽達觀資料提供了72G、上億條通用領域經過脫敏的資訊資訊用來支援預訓練模型。訓練集有14009條樣本,資料來自於金融、政務、軍事等多個領域,不均勻分佈在35個類別裡面,採用macroF1作為評價方案。
從獲獎選手的方案中,發現選手使用最多的模型是bert,其次是nezha,方案基本是多模型融合。預訓練模型很大程度上緩解了樣本標註數量過少的問題。最佳化策略也比較集中,FGM解決魯棒性問題、透過資料增強解決樣本不均衡問題。也有部分同學透過SimCSE增強向量的表達能力,對於本次的短文字分類問題效果提升不錯。綜上所述,選手從幾個方面針對資料集的樣本不均衡問題以及標註資料不足的問題,為工程實踐的文字分類問題提供了很好的思路。
就讀於桂林電子科技大學研二的左玉暉同學與同隊的隊員在本屆歷時2個月的賽事中脫穎而出, 最終在激烈的比賽中獲得三等獎的好成績。
以下是覆盤解題思路:
目錄
- 賽題任務
- 預訓練模型
- 模型結構
- 提分技巧
- 面對不均衡 dice loss & focal loss & cross entropy loss
- 對比學習
- 對抗訓練
- Multi-Exit
- flooding洪泛法
- Multi-sample Dropout
- 偽標籤
- 模型融合
- stacking
- 投票+rank/機率平均
賽題任務
此次比賽名為:基於大規模預訓練模型的風險事件標籤識別,在技術層面上可以提取為兩個任務,一個是預訓練一個是文字分類。
針對預訓練賽題方給了一個70g的無標註預訓練文字,訓練集有14009條,測試集6004條(包含AB榜資料)
賽題全部為脫敏資料(所有文字都轉換成了數字表達)脫敏前的資料樣例為:
我們嘗試過一級標籤和二級標籤的聯合預測,效果不好。在標籤列可以看到樣本有一級和二級標籤之分,共有10個一級,35個二級標籤。評價指標為macro F1。
標籤類別很多而且不平衡,多的類別上千條,少的類別只有十幾個:
接下來我將分別從預訓練模型、模型結構、提分技巧、模型融合覆盤整個比賽過程。
預訓練模型
執行過程 處理資料 process_data --> 構建詞表 build_vocab --> run pretrain
我們在無標註資料中根據cosine距離選擇了四萬條和訓練集中樣本相似的資料進行預訓練。
分別預訓練了bert-base模型 nezha-base模型,nezha與bert的區別主要是
nezha相比於google開源中文bert使用了更大的預訓練語料,還使用了相對位置編碼是一種有效的位置編碼方案,全字掩蔽策略,混合精度訓練和LAMB最佳化器。
nezha首次將函式型的相對位置編碼加入了模型中。好處:主要是因為它可以使模型外推到比訓練中遇到的序列長的序列長度。Bert針對每個位置合併了絕對位置編碼,該絕對位置編碼是嵌入向量,並且直接新增到token embedding。
我們對每種模型儲存不同訓練步數的checkpoint,可以用於後面的模型融合。
其實預訓練策略可以做很多花樣的文章,但由於機器有限,我們將主要的精力放在了微調方面。預訓練策略只是遵循mlm和nsp。
我們主要使用過的預訓練模型有:
- Bert-base-wwm-ext : 哈工大開源版本
- Nezha-wwm-base: 哪吒官方開源版本
- Bert120k: 預訓練12萬step
- Bert150k: 預訓練15萬step
- Bert80k: 預訓練8萬step
- Nezha80k:預訓練8萬step
- Nezha110k:預訓練11萬step
- Nezha150k:預訓練15萬step
最一開始是使用了word2vec在語料庫上進行訓練,線上第一次提交是 48點多分 排了七十多名。
然後開始使用bert等開源的權重,那麼問題來了脫敏資料裡詞都是那樣的,bert詞表用不了怎麼辦?
- 統計脫敏資料的詞頻,將對應詞頻與開源詞表上的詞頻進行對換 (最開始使用的是這種) 線上可達50分左右
- 將word2vec訓練好的embedding替換到bert上
雖然無法還原句子,但頻率估計可以還原一部分詞,兩個頻率高的文字,在同一種語境下出現的機率更大,從語義相關性角度來說,可能會有一些語義相關性,改用明文後就可以隨便用預訓練語言模型了。
模型結構
我們最終的模型結構大致是:
Bert --> BiLSTM 1層 --> BiGRU 1層 --> bert_pooler + 膠囊網路 --> Multi-Sample Dropout預測輸出
同時加BiLSTM和BiGRU大概有接近一個點的提高。膠囊網路有的預訓練模型有一點點提高,但有的有負效果。
還嘗試過 用 max_pooling + avg_pooling + 膠囊網路 + bert_pooling等組合,效果均不如直接使用bert_pooler和膠囊網路。
提分技巧
面對不均衡 dice loss & focal loss & cross entropy loss
樣本不均衡會帶來什麼問題呢?
模型訓練的本質是最小化損失函式,當某個類別的樣本數量非常龐大,損失函式的值大部分被樣本數量較大的類別所影響,導致的結果就是模型分類會傾向於樣本量較大的類別。
透過類別加權Loss解決, 下圖截自香儂科技的論文《Dice Loss for Data-imbalanced NLP Tasks》,分別列舉了加權loss,Focal loss(FL)和他們提出的dice loss。我們的實驗效果是:FL < Weigth CE < dice loss。所以主要採用了weight ce和dice loss。
Weight CE透過基於類別的加權的方式可以從不同類別的樣本數量角度來控制Loss值,從而一定程度上解決了樣本不均衡的問題。
基於類別加權Loss雖然在一定程度上解決了樣本不均衡的問題,但是實際的情況是不僅樣本不均衡會影響Loss,而且樣本的難易區分程度也會影響Loss。
何愷明在論文《Focal Loss for Dense Object Detection》中提出了的Focal Loss,上圖第三個公式。對於模型預測為正例的樣本也就是p>0.5的樣本來說,如果樣本越容易區分那麼(1-p)的部分就會越小,相當於乘了一個係數很小的值使得Loss被縮小,也就是說對於那些比較容易區分的樣本Loss會被抑制,同理對於那些比較難區分的樣本Loss會被放大,這就是Focal Loss的核心:透過一個合適的函式來度量簡單樣本和困難樣本對總的損失函式的貢獻。
dice loss香儂科技的這篇論文可以參考:Dice Loss for Data-imbalanced NLP Tasks
交叉熵“平等”地看待每一個樣本,無論正負,都盡力把它們推向1(正例)或0(負例)。但實際上,對分類而言,將一個樣本分類為負只需要它的機率<0.5即可,完全沒有必要將它推向0。Dice Loss的自適應損失——DSC,在訓練時推動模型更加關注困難的樣本,降低簡單負例的學習度,從而在整體上提高基於F1值的效果。
對比學習
對比損失可以關注判別更困難的樣本。
Feature學習是各類深度學習模型的一個基礎、重要的功能。好的feature,將有助於文字任務效能的提升。
表示學習的目標是為輸入x 學習一個表示 z,那麼如何衡量一個表示z 的好壞可以透過互資訊的形式;
互資訊:代表我們知道了 z 之後 x的資訊量減少了多少,
InfoNCE (又稱ntxent loss)
實質:核心是透過計算樣本表示的距離,拉近正樣本,拉遠負樣本
自監督的時候可以自行構造正負樣本,那麼有監督的時候就可以根據不同的樣本標籤來構建正負樣本。
最大化相同標籤的樣本相似度,讓不同樣本標籤的相似度比較小。
參考論文 《Supervised Contrastive Learning》、《SUPERVISED CONTRASTIVE LEARNING FOR PRE-TRAINED LANGUAGE MODEL FINE-TUNING》
對抗訓練
很多人反映對抗訓練沒有效果,我最一開始的結果也是這樣的。在開源版的nezha和bert上都會降分。
但隨著預訓練模型越來越多,模型越來越穩定,對抗訓練就可以提分了。在預訓練後的nezha上基本上是pgd比較好,但比較耗時,在bert上fgm有時會好一點。每個預訓練模型的使用效果都不太一樣。
我們還嘗試了,不僅在bert的word_embedding上做擾動,還在encoder的第0層做擾動,同時隨機在某個batch上不擾動,效果相差不多。
在驗證集的效果對比:
- Nezha110k_noAdv: 0.5598
- Nezha110k_fgm: 0.5639
- Nezha110k_pgd: 0.5687
- Bert80k_noAdv: 0.5542
- Bert80k_fgm:0.5557
- Bert80k_pgd:0.5650
- Bert80k_fgm_advEncoder_random:0.5585
- Bert80k_pgd_advEncoder_random:0.5684
Multi-Exit
Bert 究竟在哪一層做輸出會比較好呢?下圖是在nezha80k上進行的實驗,普遍發現在第layer9,也就是第10層的輸出下普遍較好。其實實驗下來發現整體效果不好就放棄了,但後來想想可能是因為12層輸出聯合訓練導致的F1值偏低。其實發現第10層可能比較好,就乾脆只用第十層的輸出計算loss就好。但後來沒有繼續嘗試。
flooding洪泛法
在最開始使用開源未經預訓練的bert進行探索的過程中發現,驗證集loss上升,acc也上升。但隨著預訓練模型的越來越穩定,這種現象就不存在了。
這種現象很常見,原因是過擬合或者訓練驗證資料分佈不一致導致,即在訓練後期,預測的結果趨向於極端,使少數預測錯的樣本主導了loss,但同時少數樣本不影響整體的驗證acc情況。ICML2020發表了一篇文章:《Do We Need Zero Training Loss After Achieving Zero Training Error?》,描述了上述現象出現的原因,同時提出了一種flooding策略,透過超引數b控制訓練loss不要過小,阻止進一步過擬合,在此情況下,使model"random walk"至一個泛化能力更好的結果,參考 我們真的需要把訓練集的損失降到零嗎?。上圖左是加洪泛之前, 上圖右是加洪泛之後的,訓練集驗證集每輪的loss。超引數b的值大概0.2左右小一些。對於模型效果來說,整體影響不大,訓練的稍微穩定一點,比賽後期沒有再用。
Multi-sample Dropout
dropout目前是NLP任務中很流行的資料擴充手段。Multi-Sample Dropout是對Dropout方法的一種改進,是2019年的一篇工作。Multi-Sample Dropout相比於dropout加快了模型訓練過程的收斂速度和提高了泛化能力。
假設樣本經過網路的編碼層部分進行編碼後得到一個向量表徵。這時候,傳統的Dropout會對向量表徵作用一次,然後輸入到分類層進行預測。而Multi-sample Dropout由多個Dropout操作完成。對一個向量表徵進行多次dropout後,相當於形成了向量表徵的多個版本的。這些不同版本的向量表徵透過分類器得到標籤的不同機率預測,最終的預測機率分佈透過求和或者平均得到。
在比賽的實驗中發現,dropout的數量為4,聚合的方式以加和的形式比average效果要好。dropout_rate最開始設為0.4。但後來慢慢發現有時,模型訓著訓著F1直接變成0了,而且只在bert模型上出現這種問題。找了幾天原因發現dropout_rate不能設的太大,改成了0.2。
偽標籤
關於偽標籤,我個人認為總體指標達不到八十以上的比賽可能不太好管用。尤其這個賽題還是樣本極其不均勻的就更不適合。因為第一,模型預測的把握度不大,根據我們線上59分的模型,預測機率為百分之40以上的測試集資料不到1500條,這在偽標籤準確度上帶來了不確定性。第二樣本不均勻,如果直接把這1500條插入到訓練集,可能會破壞訓練集的一些分佈,造成模型不穩定,學跑偏了。
測試結果:線上58.7的模型,在偽標籤上重新訓練後是58.3分。
模型融合
stacking
跑了四折的四種預訓練模型的stacking。最後的第二層預測使用的是xgboost,整體效果沒有達到預期,線上得分僅0.5707
四折的四種模型效果如下:
效果不佳的原因可能和拆分四折的資料分佈有關,導致單模分數不是很高。由於樣本不均衡,原先的拆分方法是針對不同類別有放回的隨機取樣做五折,隨機性比較大,不容易過擬合。
為了讓模型湊齊所有訓練集的預測特徵,且不讓資料有重複,我使用了無放回的取樣,針對不同類別的樣本,按順序分段提取每折樣本,並且根據資料id去了一遍重。在實驗的時候發現不同折的資料分佈對模型效果影響還蠻大的。
投票+rank/機率平均
投票在這次比賽效果非常好。
第一次融七個模型,模型平均分大概五十四五。
- 投票線上結果:5809
- 投票,針對票數相同的結果,選擇結果在每個模型的預測rank最靠前的作為結果:0.5852
- 投票,針對票數相同的結果,選擇每個預測結果的機率平均值最大的作為結果:5850
- 根據七個模型的logits選最大的作為預測結果:0.5549
- 根據預測的機率加和取平均的線上結果:5618
模型平均分大概57.5分左右
- 投票+rank :0.6201
最後將所有線上得分超過60分的測試集結果再放到一起,再進行投票得到最後的最終成績:0.6241
作者|左玉暉
單位|桂林電子科技大學,擇數科技
研究方向|自然語言處理,機器學習
作者介紹: 左玉暉,在讀研二,接觸AI一年還處在不斷探索的階段,本科曾獨立開發多個軟體專案,碩士期間轉向自然語言處理,主要研究方向:閱讀理解,內容挖掘,一篇WSDM在投。多次演算法比賽經歷從炮灰到拿到獎金一點一點摸爬滾打,歡迎交流學習體會。
成績:A榜第5,B榜第4,最終分數分別為:0.62411600、0.58140504
以上就是來自本屆“達觀杯”三等獎獲獎隊伍"ICBCCS”的成員左玉暉同學的分享,本屆賽事共吸引1200名選手參賽,感謝各位人工智慧領域優秀人才今年對達觀資料以及“達觀杯”的關注,我們明年再見!