毫不夸張的講,谷歌AI實(shí)驗(yàn)室的BERT深刻影響了NLP的格局。
想象一下這樣一個(gè)在大量未標(biāo)注數(shù)據(jù)集中訓(xùn)練的模型,你僅僅只需要做一點(diǎn)的微調(diào),就可以在11個(gè)不同的NLP任務(wù)上取得 SOTA結(jié)果。沒錯(cuò),BERT就是這樣,它徹底改變了我們?cè)O(shè)計(jì)NLP模型的方式。
BERT之后,許多NLP架構(gòu)、訓(xùn)練方法與語(yǔ)言模型如雨后春筍般涌現(xiàn),比如谷歌的TransformerXL、OpenAI’s GPT-2、 XLNet、ERNIE2.0、 RoBERTa等。
注:在這篇文章中,我會(huì)提及許多Transformer的內(nèi)容,如果你對(duì)Transformer不了解的話,可以先看看這篇文章——How do Transformers Work in NLP? A Guide to the Latest State-of-the-Art Models.
你一定聽說(shuō)過BERT,也知道了它是多么不可思議以致改變了NLP的領(lǐng)域格局,但BERT究竟是什么?
以下是BERT團(tuán)隊(duì)對(duì)該框架的描述:
BERT全稱Bidirectional Encoder Representations from Transformers(Transformers的雙向編碼表示),對(duì)未標(biāo)注的文本,通過上下文約束預(yù)訓(xùn)練深層雙向表示。訓(xùn)練完成后,只需要對(duì)BERT預(yù)訓(xùn)練模型進(jìn)行fine-tune,再加上針對(duì)特定任務(wù)的輸出層就可以取得SOTA結(jié)果。
對(duì)新人來(lái)說(shuō)這樣的解釋不夠明白,但這確實(shí)很好的總結(jié)了BERT的機(jī)制。接下來(lái),我們一點(diǎn)點(diǎn)的進(jìn)行剖析。
首先可以明確的是,BERT全稱Bidirectional Encoder Representations from Transformers,名字中的每一個(gè)單詞都有其意義,我們會(huì)在后面的段落一一介紹。從BERT的名字中,我們能得到最重要信息就是:BERT是基于Transformer架構(gòu)的。
其次,BERT是在大量的未標(biāo)注文本上預(yù)訓(xùn)練得到,包括整個(gè)Wikipedia(有25億單詞)和圖書語(yǔ)料庫(kù)(8億單詞)。
預(yù)訓(xùn)練這一步對(duì)BERT來(lái)講是至關(guān)重要的。正是由于如此龐大的語(yǔ)料庫(kù)的支撐,模型在訓(xùn)練過程中才能對(duì)語(yǔ)言的工作原理進(jìn)行更深入、更準(zhǔn)確的提取,通過此過程提取到的知識(shí)對(duì)所有NLP任務(wù)來(lái)說(shuō)都是‘萬(wàn)滑油’。
然后,BERT是“深度雙向”模型,雙向就意味著BERT在訓(xùn)練過程中關(guān)注當(dāng)前位置的上下文信息。
上下文信息對(duì)準(zhǔn)確理解語(yǔ)義很重要的。看下面這個(gè)例子,兩句話中都包含了同一個(gè)單詞“bank”:
BETR捕獲上下文信息
如果我們想僅依靠上文或者下文的信息去理解“bank”的含義,那么對(duì)這兩句話中的“bank”,我們是無(wú)法區(qū)分它們的不同含義的。
解決方法就是在預(yù)測(cè)之前同時(shí)考慮上下文信息,BERT就是這樣做的。
最后,BERT最吸引人的在于,我們僅僅通過在模型后根據(jù)自己的需求加上輸出層部分就可以在各類NLP任務(wù)取得SOTA結(jié)果。
“自然語(yǔ)言處理領(lǐng)域最大的挑戰(zhàn)之一就是訓(xùn)練數(shù)據(jù)的短缺。NLP是一個(gè)多元領(lǐng)域,任務(wù)繁多,大多數(shù)特定領(lǐng)域的數(shù)據(jù)集僅僅包含幾千或幾十萬(wàn)人工標(biāo)注的數(shù)據(jù)。”——谷歌AI
預(yù)訓(xùn)練模型從大量未標(biāo)注文本數(shù)據(jù)中學(xué)習(xí)語(yǔ)言表示的思想來(lái)源于詞嵌入,如Word2Vec and GloVe。
詞嵌入改變了進(jìn)行NLP任務(wù)的方式。通過嵌入,我們能夠捕獲單詞的上下文關(guān)系。
圖中所示的這些嵌入方法被廣泛用于下游NLP任務(wù)的訓(xùn)練模型,以便獲取較好的預(yù)測(cè)結(jié)果。
之前的嵌入方法的一大缺陷在于只使用了很淺的語(yǔ)言模型,那就意味著它們捕獲到的信息是有限的。
另外一個(gè)缺陷就是這些嵌入模型沒有考慮單詞的上下文。就像之前提到的“bank”例子,在不同的語(yǔ)境下同一個(gè)單詞可能會(huì)有不同的含義。
然而,WordVec之類的模型將不同語(yǔ)境中的“bank”以同樣的向量表示。
于是,一些重要的信息被遺漏了。
ELMo是對(duì)語(yǔ)言多義性問題提出的解決方案——針對(duì)那些在不同上下文中具有不同含義的單詞。
從訓(xùn)練淺層前饋網(wǎng)絡(luò)(Word2vec)開始,我們逐步過渡到使用復(fù)雜的雙向LSTM結(jié)構(gòu)來(lái)訓(xùn)練詞嵌入。
這意味著同一單詞根據(jù)其所在的上下文可以具有多個(gè)ELMO嵌入。
從那時(shí)起,我們開始注意到預(yù)訓(xùn)練的優(yōu)勢(shì)將使其在NLP任務(wù)中發(fā)揮重要作用。
ULMFiT更進(jìn)一步,在文檔分類任務(wù)中,即使只有很少的數(shù)據(jù)(少于100),對(duì)該框架訓(xùn)練的語(yǔ)言模型進(jìn)行微調(diào)就能夠提供出色的結(jié)果。這意味著ULMFiT解決了NLP任務(wù)中的遷移學(xué)習(xí)問題。
這是我們提出的NLP遷移學(xué)習(xí)黃金公式:
NLP遷移學(xué)習(xí) = 預(yù)訓(xùn)練 + 微調(diào)
在ULMFIT之后,許多NLP任務(wù)根據(jù)上述公式進(jìn)行訓(xùn)練,并獲得了新的基準(zhǔn)。
OpenAI’s GPT進(jìn)一步擴(kuò)展了ULMFiT和ELMo中引入的pre-training和fine-tuning方法。
GPT的關(guān)鍵是用基于Transformer的結(jié)構(gòu)取代了基于LSTM的語(yǔ)言建模結(jié)構(gòu)。
不僅是文檔分類任務(wù),GPT模型還可以對(duì)其他NLP任務(wù)進(jìn)行
fine-tuned,例如常識(shí)推理,語(yǔ)義相似性和閱讀理解。
OpenAI的GPT在多項(xiàng)任務(wù)獲得SOTA結(jié)果,驗(yàn)證了Transformer架構(gòu)的魯棒性和有效性。
就這樣,BERT在Transformer的基礎(chǔ)上橫空出世,并給NLP領(lǐng)域帶來(lái)巨大變革。
至此,解決NLP任務(wù)離不開這兩步:
1. 在未標(biāo)注的大型文本語(yǔ)料庫(kù)上訓(xùn)練語(yǔ)言模型(無(wú)監(jiān)督或半監(jiān)督)
2. 針對(duì)特定的NLP任務(wù)對(duì)大型語(yǔ)言模型進(jìn)行微調(diào),以充分利用預(yù)訓(xùn)練模型的大量知識(shí)(監(jiān)督)
接下來(lái),我們將詳細(xì)了解BERT如何訓(xùn)練模型,并在未來(lái)一段時(shí)間內(nèi)成為NLP領(lǐng)域的行業(yè)標(biāo)桿。
深入BERT,理解為什么BERT建立的語(yǔ)言模型如此有效。
BERT架構(gòu)建立在Transformer之上。 我們目前有兩個(gè)可用的變體:
BERT Base:12層(transformer模塊),12層注意力,1.1億參數(shù)
BERT Large:24層(transformer模塊),16層注意力,3.4億參數(shù)
圖源
與OpenAI的GPT模型相比,BERT Base模型大小與其相似,同時(shí)BERT Base的所有transformer層都僅包括編碼部分。
如果你對(duì)transformer結(jié)構(gòu)了解不是很清楚,建議你先讀一下這篇文章。
現(xiàn)在我們已經(jīng)了解了BERT的整體架構(gòu)。在正式構(gòu)建模型之前,需要先進(jìn)行一些文本處理工作。
2. 文本預(yù)處理
BERT背后的開發(fā)人員添加了一組特定的規(guī)則來(lái)表示模型的輸入文本。其中許多都是創(chuàng)造性的設(shè)計(jì)選擇可以讓模型表現(xiàn)更好。
首先,每個(gè)輸入嵌入都是三個(gè)嵌入的組合:
1.位置嵌入:BERT學(xué)習(xí)并使用位置嵌入來(lái)表達(dá)單詞在句子中的位置。添加該嵌入是為了克服Transformer的局限性,與RNN不同,Transformer無(wú)法捕獲“序列”或“順序”信息
2.段嵌入:BERT也可以將句子作為任務(wù)的輸入(問題-解答)。因此,它為第一句話和第二句話學(xué)習(xí)了獨(dú)特的嵌入,以幫助模型區(qū)分它們。在上面的示例中,所有為EA的標(biāo)記都屬于句子A(對(duì)于EB一樣)
3.令牌嵌入:這些是從WordPiece令牌詞匯表中為特定令牌學(xué)習(xí)的嵌入
對(duì)于給定的令牌,其輸入表示形式是通過將相應(yīng)的令牌,段和位置嵌入相加而構(gòu)造的。
這種全面的嵌入方案包含許多有用的模型信息。
這些預(yù)處理步驟的組合使BERT如此通用。
BERT對(duì)兩項(xiàng)NLP任務(wù)進(jìn)行預(yù)訓(xùn)練:
遮掩語(yǔ)言模型
下句預(yù)測(cè)
讓我們更詳細(xì)地理解這兩個(gè)任務(wù)!
BERT是深層的雙向模型,該網(wǎng)絡(luò)從第一層到最后一層始終關(guān)注當(dāng)前單詞的上下文進(jìn)行信息捕獲。
單詞序列預(yù)測(cè)
傳統(tǒng)的語(yǔ)言模型要么是利用從右到左的文本信息進(jìn)行訓(xùn)練預(yù)測(cè)下一個(gè)單詞(例如GPT),要么是使用從左到右的文本信息進(jìn)行訓(xùn)練,這使模型不可避免的丟失一些信息,從而導(dǎo)致錯(cuò)誤。
ELMo試圖通過訓(xùn)練兩個(gè)LSTM語(yǔ)言模型(一個(gè)利用從左到右的文本信息,一個(gè)利用從右到左的文本信息),并將它們進(jìn)行連接來(lái)解決這個(gè)問題。這樣雖然在一定程度上取得進(jìn)步,但還遠(yuǎn)遠(yuǎn)不夠。
相對(duì)于GPT與ELMo,BERT在利用上下文信息這一方面取得重要突破,如上圖所示。
圖中的箭頭表示一層到下一層的信息流,頂部的綠色框表示每個(gè)輸入單詞的最終表示。
從以上圖片可以明顯看到:BERT是雙向的,GPT是單向的(從左到右的信息流),ELMo是淺層雙向的。
關(guān)于遮掩語(yǔ)言模型——這是BERT雙向編碼的奧秘。
對(duì)這樣一個(gè)句子——“I love to read data science blogs on Analytics Vidhya”,我們?cè)鯓佑盟?xùn)練雙向語(yǔ)言模型呢。
我們首先將“Analytics”替換為“[MASK]”, “[MASK]” 表示將該位置的單詞掩蓋。
然后我們需要訓(xùn)練一個(gè)模型,使其能夠預(yù)測(cè)mask掉的單詞:“I love to read data science blogs on [MASK] Vidhya.”
這就是遮掩語(yǔ)言模型的關(guān)鍵。BERT的作者還介紹了一些遮掩語(yǔ)言模型的注意事項(xiàng):
為了防止模型過于關(guān)注特定位置或被遮掩的標(biāo)記,研究人員隨機(jī)遮掩15%的單詞
被遮掩的單詞并不總是[MASK]取代,在針對(duì)特定任務(wù)的微調(diào)階段是不需要[MASK]標(biāo)記的
為此,研究人員的一般做法是:(對(duì) 15%需要[MASK] 單詞 )
(15%的)80%的單詞被[MASK]遮掩
其余10%的單詞被其他隨機(jī)單詞取代
其余10%的單詞保持不變
在我之前的一篇文章中,我詳細(xì)介紹了如何在Python中實(shí)現(xiàn)遮掩語(yǔ)言模型:Introduction to PyTorch-Transformers: An Incredible Library for State-of-the-Art NLP (with Python code)
遮掩語(yǔ)言模型(MLMs)學(xué)習(xí)單詞之間的關(guān)系。
此外,BERT還對(duì)下句預(yù)測(cè)任務(wù)進(jìn)行訓(xùn)練以學(xué)習(xí)句子之間的關(guān)系。
這類任務(wù)的典型例子就是問答系統(tǒng)。
任務(wù)很簡(jiǎn)單,給A和B兩個(gè)句子,判斷B是A之后的下一句,或只是一個(gè)隨機(jī)句子?
由于這是一個(gè)二分類問題,將語(yǔ)料庫(kù)中的句子分解為句子對(duì)就可以得到大量訓(xùn)練數(shù)據(jù)。與MLMs類似,作者也給出在進(jìn)行下句預(yù)測(cè)任務(wù)時(shí)的注意事項(xiàng)。具體通過這個(gè)例子進(jìn)行說(shuō)明:
對(duì)于一個(gè)包含10萬(wàn)句子的數(shù)據(jù)集,我們可以得到5萬(wàn)句子對(duì)作訓(xùn)練數(shù)據(jù)。
訓(xùn)練數(shù)據(jù)中的50%,第二句是真實(shí)的下句
另外的50%,第二句是語(yǔ)料庫(kù)中的隨機(jī)句子
前50%的標(biāo)簽是‘IsNext’,后50%的標(biāo)簽是‘NotNext’
在建模過程中結(jié)合遮掩語(yǔ)言模型(MLMs)和下句預(yù)測(cè)(NSP)兩個(gè)預(yù)訓(xùn)練任務(wù),這就使得BERT成為一個(gè)與任務(wù)無(wú)關(guān)的模型,經(jīng)過簡(jiǎn)單fine-tuning即可適用到其他下游任務(wù)。
你對(duì)BERT的可能性一定有各種期待。確實(shí)如此,我們?cè)诰唧w的NLP應(yīng)用中可以通過各種方式利用BERT預(yù)訓(xùn)練模型的優(yōu)勢(shì)。
最有效的方法之一就是根據(jù)自己的任務(wù)和特定數(shù)據(jù)進(jìn)行微調(diào), 然后,我們可以將BERT中的嵌入用作文本文檔的嵌入。
接下來(lái),我們將學(xué)習(xí)如何將BERT的嵌入應(yīng)用到自己的任務(wù)上。至于如何對(duì)整個(gè)BERT模型進(jìn)行微調(diào),我會(huì)在另一篇文章中進(jìn)行介紹。
為了提取BERT的嵌入,我們將使用一個(gè)非常實(shí)用的開源項(xiàng)目Bert-as-Service:
BERT-As-Service
由于BERT需要大量代碼以及許多安裝包的支持,對(duì)普通用戶而言直接運(yùn)行BERT是不現(xiàn)實(shí)的,為此開源項(xiàng)目BERT-As-Service來(lái)幫助我們便捷的使用BERT。通過該項(xiàng)目,我們僅僅通過兩行代碼就可以調(diào)用BRRT對(duì)句子進(jìn)行編碼。
BERT-As-Service運(yùn)行方式十分簡(jiǎn)單。它創(chuàng)建了一個(gè)BERT服務(wù)器,我們可以在notebook中編寫ython代碼進(jìn)行訪問。通過該方式,我們只需將句子以列表形式發(fā)送,服務(wù)器就會(huì)返回這些句子的BERT嵌入。
我們可以通過pip安裝服務(wù)器和客戶端。它們可以單獨(dú)安裝在本地計(jì)算機(jī),也可以安裝到不同的計(jì)算機(jī)上:
$ pip install bert-serving-server # server
$ pip install bert-serving-client # client
另外,由于運(yùn)行BERT對(duì)GPU要求較高,我建議你在云GPU平臺(tái)或是其他具有高計(jì)算能力的計(jì)算機(jī)上安裝bert-serving-server。
同時(shí),bert-serving-server對(duì)python和Tensorflow的版本要求為:Python >= 3.5 ; TensorFlow >= 1.10。
然后,在終端下載圖示的預(yù)訓(xùn)練模型(選擇你需要的即可),并對(duì)下載的zip文件進(jìn)行解壓。
下圖是已發(fā)布的BERT預(yù)訓(xùn)練模型:
BERT模型
我這里選擇BERT Uncased下載并解壓:
$ wget https://storage.googleapis.com/bert_models/2018_10_18/uncased_L-12_H-768_A-12.zip && unzip uncased_L-12_H-768_A-12.zip
將所有文件解壓之后,就可以啟動(dòng)BERT服務(wù)了:
$ bert-serving-start -model_dir uncased_L-12_H-768_A-12/ -num_worker=2 -max_seq_len 50
現(xiàn)在,你可以在Python中通過bert-serving-client調(diào)用BERT-As-Service。看代碼吧!
打開一個(gè)新的Jupyter Notebook,我們想要獲取“I love data science and analytics vidhya”的BERT嵌入。
from bert_serving.client import BertClient
# 使用IP地址連接BERT服務(wù)器; 如果是本機(jī)服務(wù)器的話不需要IP
bc = BertClient(ip='服務(wù)器的IP地址')
# 獲取嵌入
embedding = bc.encode(['I love data science and analytics vidhya.'])
# 對(duì)返回的嵌入形狀進(jìn)行確認(rèn),應(yīng)該是1x768
print(embedding.shape)
IP地址是BERT服務(wù)器或云平臺(tái)的IP; 如果是本機(jī)服務(wù)器的話不需要填寫IP
由于該句被BERT架構(gòu)中的768個(gè)隱藏單元表示,最終返回的嵌入形狀是(1,768)。
接下來(lái)使用真實(shí)數(shù)據(jù)集測(cè)試BERT的效果。我們將使用Twitter的“仇恨言論”分類數(shù)據(jù)集,該數(shù)據(jù)集中的推文被標(biāo)注為是或者否。
你可以從此鏈接problem statement on the DataHack platform了解或下載該數(shù)據(jù)集。
為簡(jiǎn)單起見,如果一條推文帶有種族主義或性別歧視情緒,我們就認(rèn)為該推文包含仇恨言論。 于是,本次任務(wù)就是將種族主義或性別歧視推文與其他推文進(jìn)行分類。
我們將使用BERT對(duì)數(shù)據(jù)集中的每條推文進(jìn)行嵌入,然后使用這些嵌入訓(xùn)練文本分類模型。
任務(wù)流程
接下來(lái)看代碼部分:
import pandas as pd
import numpy as np
# 導(dǎo)入訓(xùn)練數(shù)據(jù)
train = pd.read_csv('BERT_proj/train_E6oV3lV.csv', encoding='iso-8859-1')
train.shape
相信你對(duì)推特并不陌生,在很多推文中總有一些隨機(jī)符號(hào)和數(shù)字(又名聊天語(yǔ)言!)。我們的數(shù)據(jù)集也是這樣,為此,需要對(duì)數(shù)據(jù)集進(jìn)行預(yù)處理,然后再傳入BERT:
現(xiàn)在,我們需要將清理后的數(shù)據(jù)集劃分為訓(xùn)練集與驗(yàn)證集:
from sklearn.model_selection import train_test_split
# 劃分訓(xùn)練集與驗(yàn)證集
X_tr, X_val, y_tr, y_val = train_test_split(train.clean_text, train.label, test_size=0.25, random_state=42)
print('X_tr shape:',X_tr.shape)
接下來(lái),對(duì)測(cè)試集與驗(yàn)證集的所有推文進(jìn)行BERT嵌入:
from bert_serving.client import BertClient
# 使用IP連接BERT服務(wù)器bc = BertClient(ip='YOUR_SERVER_IP')
# 獲得訓(xùn)練集與測(cè)試集的嵌入X_tr_bert = bc.encode(X_tr.tolist())
X_val_bert = bc.encode(X_val.tolist())
該構(gòu)建模型了!我們先來(lái)訓(xùn)練分類模型:
from sklearn.linear_model import LogisticRegression
# LR模型
model_bert = LogisticRegression()
# 訓(xùn)練
model_bert = model_bert.fit(X_tr_bert, y_tr)
# 預(yù)測(cè)
pred_bert = model_bert.predict(X_val_bert)
查看分類準(zhǔn)確率:
from sklearn.metrics import accuracy_score
print(accuracy_score(y_val, pred_bert))
可以看到,即使只有很小的數(shù)據(jù)集,我們也很容易達(dá)到95%左右的準(zhǔn)確率。實(shí)在是不可思議!
你最好在其他任務(wù)上親自實(shí)踐一下BERT嵌入,并將你的結(jié)果分享到下面的評(píng)論區(qū)。
下一篇文章,我會(huì)在另外一個(gè)數(shù)據(jù)集上使用Fine-tune的BERT模型,并比較其性能。
BERT激起了人們對(duì)NLP領(lǐng)域的極大興趣,尤其是Transformer的廣泛應(yīng)用。 這也導(dǎo)致越來(lái)越多的實(shí)驗(yàn)室和組織開始研究pre-training, transformers 和 fine-tuning等任務(wù)。
BERT之后,一些新的項(xiàng)目在NLP各項(xiàng)任務(wù)中取得了更好的結(jié)果。 比如RoBERTa,這是Facebook AI對(duì)BERT和DistilBERT的改進(jìn),而后者其實(shí)就是BERT的更輕巧,便捷的版本。
你可以在regarding State-of-the-Art NLP in this article了解更多BERT之后的改進(jìn)模型。
via: https://www.analyticsvidhya.com ,2019/9/25.
(完)
??關(guān)注“Python與人工智能社區(qū)”
聯(lián)系客服