1. 程式人生 > >廣告行業中那些趣事系列6:BERT線上化ALBERT優化原理及專案實踐(附github)

廣告行業中那些趣事系列6:BERT線上化ALBERT優化原理及專案實踐(附github)

摘要:BERT因為效果好和適用範圍廣兩大優點,所以在NLP領域具有里程碑意義。實際專案中主要使用BERT來做文字分類任務,其實就是給文字打標籤。因為原生態BERT預訓練模型動輒幾百兆甚至上千兆的大小,模型訓練速度非常慢,對於BERT模型線上化非常不友好。本篇研究目前比較火的BERT最新派生產品ALBERT來完成BERT線上化服務。ALBERT使用引數減少技術來降低記憶體消耗從而最終達到提高BERT的訓練速度,並且在主要基準測試中均名列前茅,可謂跑的快,還跑的好。希望對需要將BERT線上化感興趣的小夥伴有些許幫助。


目錄
01 專案背景介紹
02 從BERT到ALBERT
03 萬里第一步:先跑通模型
04 多分類任務實踐
總結




01 專案背景介紹

原生態BERT預訓練模型動輒幾百兆甚至上千兆的大小,訓練速度非常慢,對於模型線上化非常不友好。為了實現BERT模型線上化問題,其實就是如何又快有好的訓練模型,經調研目前超火的BERT最新派生產品ALBERT專案能很好的解決上述問題。

ALBERT是由論文《ALBERT: A Lite BERT For Self-Supervised Learningof Language Representations》提出來的。通常情況下增加預訓練模型大小可以提升模型在下游任務中的效能,但是因為“GPU/TPU記憶體的限制、更長的訓練時間以及意想不到的模型退化”等問題,作者提出了ALBERT模型。

論文下載地址:
https://arxiv.org/pdf/1909.11942.pdf

通俗的理解ALBERT就是引數數量更少的輕量級BERT模型。ALBERT是BERT最新派生產品,雖然輕量,但是效果並沒打折,在主要基準測試中均名列前茅。

02 從BERT到ALBERT

1. ALBERT出現背景

自從深度學習引爆計算機視覺領域之後,提升模型效能最簡單也最有效的一個方法就是增加網路深度。下圖中拿圖片分類任務舉例,可以看出隨著網路層數不斷增加,模型的效果也會有很大提升:

圖1 網路層數增加模型效果提升


同樣的情況也出現在BERT上,隨著網路變深變寬使得模型的效果得到提升:

圖2 BERT隨著網路變深變寬模型效果得到提升


但是網路變深變寬頻來一個顯著的問題:引數爆炸。這裡看下不同規模引數的BERT模型引數量的變“胖”之路:

圖3 BERT引數爆炸問題


如何做到,讓BERT不那麼“胖”,但是效果依舊好是目前學術界的研究重點,也是如何將BERT線上化的重點工作之一。這也是ALBERT要做的事情。

2. BERT“胖”在哪裡

想讓BERT變瘦,先要知道“肉”長在哪裡。BERT使用Transformer作為特徵抽取器,這是BERT引數的來源。之前廣告行業中那些趣事系列4:詳解從配角到C位出道的Transformer很深入的剖析了Transformer,有興趣的小夥伴可以回頭看看。

Transformer的引數來源主要有大塊:第一塊是token embedding對映模組,引數量佔比為20%,第二塊是attention層和前向反饋層FFN,引數量佔比為80%。

圖4 Transformer結構圖和BERT引數來源

3. ALBERT優化策略

策略一、對embedding引數因式分解(Factorized embedding parameterization)

BERT將詞的one-hot向量對映到高維空間,引數量是O(VXH),ALBERT則採用因式分解的方式先將詞的one-hot向量對映到低維空間(大小為E),然後再映射回一個高維的空間(大小為H),這樣使用的引數僅僅是O(VXE+EXH),如果E<<H的時候引數量會減少很多。這裡就一定程度上減少了上面說的BERT第一部分引數token embedding的部分。

可以通過因式分解減少引數量的原因是token embedding是上下文獨立的,通過one-hot向量轉化成dense向量。而第二部分的attention和FFN作為隱藏層是上下文依賴的,包含更多資訊。所以通過一個小於H的E做中介將詞的one-hot向量先經過一個低維的embedding矩陣,然後再映射回高維的embedding矩陣是可行的。下圖中紅色方框顯示了因式分解部分:

圖5 因式分解降低引數量

檢視token embedding因式分解效果情況:總體來看降低了17%的模型引數,但是模型效果僅僅降低了不到1%。

圖6 因式分解降低引數量效果


策略二、共享層與層之間的引數(Cross-layer parameter sharing)

通過對Transformer各層引數視覺化分析發現各層引數類似,都是在[CLS]token和對角線上分配更多的注意力,所以可以使用跨層的引數共享方案。

通常來說,跨層的引數共享對應Transformer編碼器中的結構有兩種方案:一種是attention模組的引數共享,另一種是前饋神經網路層FFN的引數共享。具體的效果如下圖所示:

圖7 使用共享引數對模型引數量和效果的影響

當對映到低維空間E=768時,對比不共享引數和共享FFN層的引數可以看出,引數減少了近50%,這也是導致模型效果下降的主要原因。而共享attention層的引數則對模型效果影響較小。

策略三、構建自學習任務-句子連貫性預測

通過改造NSP(Next Sentence Prediction)任務,增強網路學習句子的連續型來提高預訓練任務。

廣告行業中那些趣事系列3:NLP中的巨星BERT重點講解了BERT模型,其中提到BERT是近幾年NLP領域傑出成果的集大成者,本身的創新主要是隨機遮蔽的語言模型Masked LM和下一句預測Next Sentence Prediction。有興趣的小夥伴可以倒回去再好好看下。

NSP任務本身是一個二分類任務,目的是預測兩句話是否是連續的語句。NSP實際包含兩個子任務,分別是主題預測和關係一致性預測。NSP任務選擇同一文件中連續的兩個句子作為正樣本,選擇不同文件的句子作為負樣本。因為來自不同的文件,差異性可能非常大。為了提升模型預測連續型句子的能力,ALBERT提出了新的任務SOP(SenteceOrder Prediction),正樣本獲取方式和NSP相同,負樣本則將正樣本的語句順序顛倒。

SOP和NSP效果展示如下圖所示:

圖8 SOP和NSP效果展示

從圖中可以看出NSP任務無法預測SOP類任務,但是SOP可以預測NSP任務。整體來看,SOP任務的模型效果也優於NSP任務。

策略四、去掉dropout

dropout主要是為了防止過擬合,但實際MLM一般不容易過擬合。去掉dropout還可以較少中間變數從而有效提升模型訓練過程中記憶體的利用率。

圖9 dropout效果影響

其他策略:網路寬度和深度對模型效果的影響

1. 網路深度是否越深越好
對比ALBERT在不同深度下的效果可以發現:隨著層數加深,不同NLP任務的模型效果是有一定提升。但是這種情況並不是絕對的,有些任務效果反而會下降。

圖10 網路深度的影響

2. 網路寬度是否越寬越好
對比深度為3的ALBERT-large模型下不同網路寬度的模型效果情況可以發現:模型寬度的影響和深度類似,隨著網路寬度增加,不同NLP任務的模型效果是有一定提升。某些任務也會存在效果下降的情況。

圖11 網路寬度的影響

總體來看,ALBERT的實質是使用引數減少技術來降低記憶體消耗從而最終達到提高BERT的訓練速度,主要優化了以下幾個方面:

  • 通過因式分解和共享層與層之間的引數減少了模型引數量,提升了引數效率;
  • 通過SOP替代NSP,增強了網路學習句子連續性的能力,提升了自監督學習任務的能力;
  • 通過去掉dropout可以節省很多臨時變數,有效提升模型訓練過程中記憶體的利用率,提升了模型的效率,減少了訓練資料的規模。

03 萬里第一步:先跑通模型

因為實際專案中主要是識別中文,所以主要是使用ALBERT中文版本ALBERT_zh,專案的github地址:https://github.com/brightmart/albert_zh。

記得之前看過一個圖片很有意思,能很好的描述此刻我的心情:

圖12 第一步先跑通模型

對於我這種“拿來主義者”來說,再牛逼的模型第一步永遠都是先跑通它,至於優化的先放一放。跑通它不僅能提升自信心,最實際的作用就是能快速實現專案上線。因為我需要完成文字分類任務,所以通過上面的github地址下載專案後,在叢集上跳轉到albert_zh目錄下,執行sh run_classifier_lcqmc.sh命令即可跑起來。因為專案沒有句子分類任務,只有個類似的句子關係判斷任務,所以先跑通這個任務,後期再根據這個任務的程式碼來改就行了。

run_classifier_lcqmc.sh指令碼中總體分成兩大塊,第一塊是模型執行的準備工作,第二塊就是模型執行。下面是模型的第一塊,其中涉及獲取資料、預訓練模型、裝置以及模型相關的引數等等。

圖13 模型執行準備工作

第二塊就是負責模型執行,主要就是python執行程式的指令以及需要的相關引數配置。

圖14 模型執行


總結下,這裡重點講了如何執行成功ALBERT_zh本身提供的一個句子關係判斷任務。這個demo是和我們實際專案中文字分類任務很相似的任務,下面就是通過改造這個指令碼以及執行的程式碼來完成我們的實際專案文字分類。

04 多分類任務實踐

專案改造的github地址如下:https://github.com/wilsonlsm006/albert_zh。

將原專案fork下來,這裡我增加了兩個檔案run_classifier_multiclass.sh和run_classifier_multiclass.py。這是用來執行文字分類的任務指令碼以及程式碼。改造的原理其實也比較簡單,這裡大致講解下。

專案原來提供的句子關係判斷任務的資料格式是:id,text_a,text_b,label,任務其實就是來判斷兩句話到底有沒有關係。正樣本舉例如下:

text_a:成龍大哥代言的一刀傳奇好玩麼?
text_b:成龍大哥還代言過其他傳奇麼?
label:1

負樣本則可能是這樣的:
text_a:成龍大哥代言的一刀傳奇好玩麼?
text_b:成都市內哪個景點最好玩?
label:0

通過上面兩個正負樣本的例子大家應該能瞭解什麼是句子關係判斷任務,其實就是有監督學習的分類任務。我們實際專案主要通過BERT來做文字分類,識別一句話屬於哪個標籤,對應到上面的任務其實就是隻有text_a,label。因為任務型別一致,所以修改程式碼的策略就是重點分析有text_b的程式碼的部分。具體指令碼和程式碼修改就是上面說的兩個檔案,有需要的小夥伴自取。這裡需要注意的是原來的資料檔案是tsv格式,我這邊是csv格式,資料輸入有點點不同,模型其他的都沒動。


總結

實際專案中需要將BERT線上化需要使模型又快又好的訓練,所以經過調研使用目前BERT最新的派生產品ALBERT。ALBERT通過因式分解和共享層與層之間的引數減少了模型引數量,提升了引數效率;通過SOP替代NOP,增強了網路學習句子的連續性的能力,提升了自監督學習任務的能力;通過去掉dropout可以節省很多臨時變數,有效提升模型訓練過程中記憶體的利用率,提升了模型的效率,減少了訓練資料的規模。最後將專案中的句子關係判斷任務改造成我們實際專案中的文字分類任務用於實際業務需求。可以說是有理論,幫助小夥伴們理解ALBERT為啥訓練快了,效果還不錯。也有實踐,如果需要使用ALBERT做文字分類任務,直接用我改造好的指令碼和程式碼跑起來就行。

喜歡本型別文章的小夥伴可以關注我的微信公眾號:資料拾光者。有任何干貨我會首先發布在微信公眾號,還會同步在知乎、頭條、簡書、csdn等平臺。也歡迎小夥伴多交流。如果有問題,可以在微信公眾號隨時Q我哈。