BERT模型—2.BERT模型预训练与微调
文章目錄
- 引言
- 一、預訓練語言模型
- 1.為什么要進行預訓練?
- 2. BERT預訓練-掩碼預測任務
- 3.BERT預訓練-下句預測任務
- 二、BERT的文本處理—subword tokenizer
- 1. 為什么要學習subword tokenizer?
- 2. 詞表生成與分詞
- 三、BERT embedding
- 四、BERT微調—句子分類任務
- 五、BERT微調—序列標注任務
- 六、BERT微調—關系分類任務
- 七、BERT微調—樣本不均衡問題Focal loss
引言
??本節將按照思維導圖逐步了解BERT語言模型(基于transformer的網絡結構)。
??BERT帶來了新的NLP范式。
一、預訓練語言模型
??大規模的預訓練語言模型的模型參數量呈幾何倍數的增長趨勢。下面我們了解BERT預訓練的原理。
1.為什么要進行預訓練?
??基于詞向量為基礎的模型并不是在BERT中首次出現。在Word2vec中,詞向量表示是有局限性的。這是因為詞向量表達固定,無法表達上下文。2017年之前,NLP模型的普遍形態為詞向量+encoder。
利用LSTM或者Transformer模型通過訓練集來學習如何提取上下文信息,最終輸出分類標簽。這里的訓練集指的是具有分類或者NER的標注信息。這種模式有如下缺陷:
- Encoder部分隨機初始化,沒有經過預訓練,對優化器壓力大;
- 數據集要足夠好,足夠大,encoder才能學會如何提取上下文信息
這兩個缺陷導致2017年以前的模型非常具有局限性。
??基于上述的缺陷,我們現在想要有效的預訓練embedding+編碼器。有標簽的文本數據獲取成本大,相比來說,獲取大量無標簽的文本數據代價很小。所以如何進行預訓練呢?這就涉及到在大量無標簽的文本上進行自監督學習(self-supervised training)。
2. BERT預訓練-掩碼預測任務
??掩碼預測任務與Word2vec中CBOW非常神似,但略有不同。
- 一方面,CBOW語言模型輸入的是一個時間窗口,并不一定是一個句子;掩碼預測任務輸入的是一個句子(sentence)
- 另一方面,CBOW當中被預測的詞是不做輸入的;但掩碼預測任務會遮掩某個詞(用”[MASK]"字符替換原詞)然后用于輸入
- CBOW中是一句話預測一個詞,掩碼預測任務一句話可以遮掩多個字
??掩碼預測任務中,輸入是句子當中遮掩掉幾個詞(用”[MASK]"字符替換原詞),經過BERT網絡輸出每個字的向量表征。在遮掩的這個字的位置上要經過一個線性層來預測這個位置是哪個字的概率。掩碼預測任務存在的問題:在下游任務中,eg:預測一個句子的情感是不會有[Mask]的。因此,在實現掩碼任務時,需要遮掩的字只占語料全體的字數的一小部分(15%);在這15%里面:
- 一部分(80%)被遮掩,也就是替換為[MASK];
- 一部分(10%)隨機替換為其他詞(仍然需要預測此處的token應該是什么);
- —部分(10%)保留原詞(仍然需要預測此處的token);
這樣做的目的是使得模型能夠區分這個詞放在這里是否合理,使得模型具有判斷這句話是否合理的能力,加深了模型對語言的理解。BERT模型在經過預訓練之后天生就能夠做一些下游任務,比如:糾錯任務。
3.BERT預訓練-下句預測任務
??下句預測指的是:判斷句子B是否是句子A的下文。此時,BERT句子的輸入會是[CLS] A sent [SEP] B sent [SEP]的格式。
??我們經常通過句首的第一個token來表示句子整體的語義關系,在上下句預測的任務當中,上下句的關系是保存在輸入的[CLS]符號的當中,在預測時使用BertPooler提取整個輸入序列的表征:
這里要注意:不是直接拿[CLS]的向量表征;而是要經過BertPooler這個模塊,其中包含MLP,tanh操作得到一個向量表示,再輸入到2分類層,BertPooler也是參與預訓練的,預訓練會更新整個bert的模型參數,微調時候其實是可以更新部分參數,后面會有介紹。
用了 Masked LM 和 Next Sentence Prediction 兩種方法分別捕捉詞語和句子級別的 representation
二、BERT的文本處理—subword tokenizer
1. 為什么要學習subword tokenizer?
??subword tokenizer就是將長的復雜的單詞分成成短的簡單的單詞,eg:句子” play the song little robin redbreast”在輸入模型時變為”[CLS] play the song red ##bre ##ast [SEP]”。Tokenizer是預訓練時候用了哪個,后面微調就要用哪個。使用subword tokenizer的原因是:
- 傳統詞表示方法:是先對各個句子進行分詞,然后再統計并選出頻數最高的前N個詞組成詞表·詞表一般較大,一是尾部詞訓練不充分,二是顯存占用較大
- 傳統詞表示方法無法很好的處理未知或罕見的詞匯(OOV問題)
- 傳統詞tokenization方法不利于模型學習詞綴之間的關系
E.g.模型學到的“old”, “older”,and “oldest”之間的關系無法泛化到“smart”, “smarter”,and“smartest”。 - Character embedding作為OOV的解決方法粒度太細,且推理時候顯存開銷較大:
一個原本長度為12的句子,采用character embedding,則輸入的大小變為12*16 (假設設置詞字母長度最
大為16) - Subword粒度在詞與字符之間,能夠較好的平衡OOV問題
常見的subword模型:Byte Pair Encoding (BPE), WordPiece
2. 詞表生成與分詞
??BPE算法生成詞表過程如下:
假設現在語料庫中有如下詞匯(及其頻率):
觀察詞匯表大小在每一步如何變化
??BPE算法編碼:得到Subword詞表后,針對每一個單詞,我們可以采用如下的方式來進行編碼:
- 將詞典中的所有子詞按照長度由大到小進行排序;
- 對于要進行分詞的單詞w,依次遍歷排好序的詞典。查看當前子詞是否是該單詞的子字符串(貪婪的最長匹配),如果是,則輸出當前子詞,并對剩余單詞字符串繼續匹配;
- 如果遍歷完字典后,仍不匹配,則將剩余字符串替換為特殊符號輸出,如””;
??WordPiece算法生成詞表的步驟與BPE類似;加上”##”前綴表示token不作為一個完整單詞的開始部分。與BPE的最大區別在于,如何選擇兩個子詞進行合并∶BPE選擇頻數最高的相鄰子詞合并,而WordPiece選擇能夠提升語言模型概率最大的相鄰子詞加入詞表;
- 假設句子S=(t1,t2,tn)S =(t_1, t_2,t_n)S=(t1?,t2?,tn?)由n個子詞組成,表示子詞,且假設各個子詞之間是獨立存在的
- 句子的語言模型似然值等價于所有子詞概率的乘積:logP(S)=∑i=1nP(ti)logP(S)= \sum_{i=1}^nP(t_i)logP(S)=∑i=1n?P(ti?)
- 假設把相鄰位置的iii和jjj兩個子詞進行合并,合并后產生的子詞記為zzz,此時句子似然值的變化可表示為:
logP(tz)?(logP(tx)+logP(ty))=logP(tz)P(tx)P(ty)logP(t_z)- (logP(t_x)+ logP(t_y)) =log\frac{P(t_z)}{P(t_x)P(t_y)}logP(tz?)?(logP(tx?)+logP(ty?))=logP(tx?)P(ty?)P(tz?)?
很容易發現,似然值的變化就是兩個子詞之間的互信息。
簡而言之,WordPiece每次選擇合并的兩個子詞,他們具有最大的互信息值,也就是兩子詞在語言模型上具有較強的關聯性,它們經常在語料中以相鄰方式同時出現。
Wordpiece舉例:
- 英文:采用BERT-base-uncased tokenizer
30522個單詞;英文轉化為小寫
eg:
句子“play the song little robin redbreast”經過BERT的wordpiece tokenizer后變為”[‘play’, ‘the’, ‘song’, ‘little’, ‘robin’, ‘red’, ‘##bre’, '##ast ]” - 中文:采用Google Chinese BERT-base-uncased
21128個單詞;不區分大小寫;
中文漢字拆開(split_Chinese_character);
eg:
句子”我很喜歡一首歌: yesterday once more.”處理為['我,‘很’,‘喜’, ‘歡’,'一,'首, ‘歌’, ‘:’,‘yes’, ‘##ter’, ‘##day’, ‘on’, ‘##ce’, ‘more’, ‘.’]
三、BERT embedding
??BERT的嵌入層包含三種embedding
- Token embedding
對應著Subword詞表分詞后的每一個單詞 - Segmentation embedding
將句子的上一句與下一句進行區分對待,涉及到預訓練任務當中的下句預測 - Position embedding
位置編碼,為了能夠讓模型反映句子的順序信息,位置編碼研究前沿如今是相對位置編碼
四、BERT微調—句子分類任務
??句子分類任務就是把文本按照一定的規則分門別類,文本分類有以下應用場景:
??那么,在下游任務中,如何進行BERT句子分類任務的微調?不妨以單個句子分類為例(還有句子對分類,判定句子對是否同義),比如,我們現在想要對“想看黑寡婦”進行情感分類,首先將“想看黑寡婦”轉換成BERT模型的輸入形式,在句前加[CLS]符號,句尾加[SEP]符號,使用subword tokenizer進行分詞,將這樣處理好的文本輸入到BERT模型中,得到句子的向量表征(句子中的每個字均有向量表征),通過BertPooler模塊,取[CLS]的向量表征,經過MLP,tanh操作后得到一個整句的向量表征,再經過分類層得到分類結果。
由于NLP中句子是不定長的,所以可以通過Pooling層將變長的向量轉換成特定的size。除了使用BertPooler模塊,還可以增加一個Pooling操作,將句子表征轉化成句子級別的向量。這里的Pooling操作指:
- Max-Pooling
- Average-Pooling
- Attention-Pooling
??分類任務微調的損失函數:假設模型對分類任務的訓練樣本為(x,y)(x,y)(x,y),預測類別為ccc的概率為pcp_cpc?,則損失函數為
CE(PC,X)=?I(y=c)?log(pc)CE(P_C,X)=-I(y=c)*log(p_c)CE(PC?,X)=?I(y=c)?log(pc?)
有了損失函數就可以利用梯度的更新做網絡的訓練。
??分類任務微調的原理與一般的網絡訓練沒有區別。微調時,如果不固定參數,所有層的參數會更新。你可以選擇固定某些層的參數,比如:embedding層。
五、BERT微調—序列標注任務
??序列標注任務指的是對于待標注的一段序列x={x1,x2,...,xn}x=\{x_1, x_2,..., x_n\}x={x1?,x2?,...,xn?},我們需要給每個xix_ixi?預測一個標簽(tag)yi(tag)y_i(tag)yi?,標簽(tag)(tag)(tag)集合是T={t1,t2,...,tm}T=\{t_1,t_2,...,t_m\}T={t1?,t2?,...,tm?}。在不同的序列標注任務中對應的標簽不一樣。
- 中文分詞任務
定義的標簽(tag)(tag)(tag)集合是{BeginMiddleEndSingle}\{Begin \ Middle\ End\ Single\}{Begin?Middle?End?Single}
eg:“風險基因協同的神經生物學作用”被分詞為
風險 基因 協同 的 神經 生物學 作用,轉化為序列標注任務為:風/B險/E基/B因/E協/B同/E的/s神/B經/E生/B物/M學/E作/B用/E。 - 命名實體識別:標出句子中的實體;使用BIO標注模式;
定義的標簽(tag)(tag)(tag)集合是實體類型包括{PER,ORG}\{PER,ORG\}{PER,ORG}
eg:喬/B-PER布/I-PER斯/I-PER 就/O職/O于/O蘋/B-ORG 果/I-ORG 公/I-ORG司/I-ORG - 詞性標注(Part-of-speech, POS tagging):標注出詞語的詞性;使用BIO標注模式
??BERT序列標注任務微調方法有兩種: - 方法一:每個token的向量表示經過線性層+softmax
具體過程為:將BERT模型格式將句子輸入到BERT模型當中,然后給出每個詞的向量表征,經過線性層+softmax,然后給出每個詞的NER標簽
- 方法二:BERT+CRF層
在BERT模型還沒有出現以前,解決這個問題的通用方式是’BiLSTM-CRF’模型。CRF層通過學習標簽之間轉移的模式來規避’B-PER,I-ORG’這樣的問題;
六、BERT微調—關系分類任務
??關系分類任務就是從非結構化文本中抽取出結構化知識;具體為:區分出頭實體與尾實體之間的語義關系,比如:
??關系分類任務最直接的應用是構建知識圖譜。
??BERT關系分類任務微調方法有三種:
- 方法一:將句子輸入到BERT模型中,然后分別拿到頭實體與尾實體的向量表征(實體多個詞的表征經過pooling得到),然后將頭尾實體向量拼接,再經過線性層分類
- 方法二:BERT的embedding層中加入關系位置編碼。在方法一的基礎上加上關系位置編碼,告訴BERT模型何處為頭實體何處為尾實體。
- 方法三:在句子中加入新定義的字符(unusedtoken),標識出頭尾實體位置;
七、BERT微調—樣本不均衡問題Focal loss
??在自然語言處理應用場景中,經常出現樣本不均衡場景的問題,這是因為在自然語言的語料庫中,一個單詞出現的頻率與它在頻率表里的排名成反比,即頻率越高的單詞,出現的次數越多。碰到樣本不均衡問題時,需要對訓練方法做一定的改變。
- 方法一:重采樣
假設CCC是數據集類別數,nnn是類別iii的樣本數量,則從類別iii中采樣一個樣本的概率:
instance-balanced sampling:每個樣本被等概率的抽到,即
pi=ni∑j=1Cnjp_i=\frac{n_i}{{\sum_{j=1}^Cn_j}}pi?=∑j=1C?nj?ni??
Class balanced sampling:每個類別被抽到的概率都相等
pi=1∑j=1C1p_i=\frac{1}{{\sum_{j=1}^C1}}pi?=∑j=1C?11?
一般重采樣,假設q∈(0,1)q∈(0,1)q∈(0,1),
niq∑j=1Cnjq\frac{n_i^q}{{\sum_{j=1}^Cn_j^q}}∑j=1C?njq?niq?? - 方法二:重加權(re_weighting):以二分類為例
正常的交叉熵損失為:
CE(PC,X)=?I(y=c)?log(pc)CE(P_C,X)=-I(y=c)*log(p_c)CE(PC?,X)=?I(y=c)?log(pc?)
通過增加一個系數(添加的系數與難度相關),來控制少數類別的樣本對總loss的貢獻
CE(PC,X)=?α(c)?I(y=c)?log(pc)CE(P_C,X)=-\alpha(c)*I(y=c)*log(p_c)CE(PC?,X)=?α(c)?I(y=c)?log(pc?)
Focal loss:
CE(PC,X)=?(1?pc)γI(y=c)?log(pc)CE(P_C,X)=-(1-p_c)^{\gamma}I(y=c)*log(p_c)CE(PC?,X)=?(1?pc?)γI(y=c)?log(pc?)
Focal loss+類別的重加權:
CE(PC,X)=?α(c)(1?pc)γI(y=c)?log(pc)CE(P_C,X)=-\alpha(c)(1-p_c)^{\gamma}I(y=c)*log(p_c)CE(PC?,X)=?α(c)(1?pc?)γI(y=c)?log(pc?)
如果對您有幫助,麻煩點贊關注,這真的對我很重要!!!如果需要互關,請評論或者私信!
總結
以上是生活随笔為你收集整理的BERT模型—2.BERT模型预训练与微调的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: panabit高级流控
- 下一篇: Operations-ansible-0