來自Transformers的雙向編碼器表示(BERT)
BERT(Bidirectional Encoder Representations from Transformers)是一種預(yù)訓(xùn)練的自然語言處理模型,由Google于2018年提出。它是基于Transformer模型架構(gòu)的深度雙向(雙向指同時考慮上下文信息)表示學(xué)習(xí)模型。
BERT的目標(biāo)是通過在大規(guī)模文本語料上進行自監(jiān)督學(xué)習(xí)來學(xué)習(xí)通用的語言表示。在預(yù)訓(xùn)練階段,BERT使用了兩個主要任務(wù):掩碼語言模型(Masked Language Model,MLM)和下一句預(yù)測(Next Sentence Prediction,NSP)。
在掩碼語言模型任務(wù)中,BERT會在輸入句子中隨機掩蓋一些詞,并嘗試預(yù)測這些掩蓋的詞。這個任務(wù)使得模型能夠通過上下文來理解詞語之間的關(guān)系,同時也能夠?qū)W習(xí)到句子級別的表示。
在下一句預(yù)測任務(wù)中,BERT會輸入兩個句子,并預(yù)測這兩個句子是否是連續(xù)的。這個任務(wù)有助于模型學(xué)習(xí)到句子之間的關(guān)聯(lián)性和推理能力。
通過這兩個任務(wù)的預(yù)訓(xùn)練,BERT能夠?qū)W習(xí)到豐富的句子級別和詞級別的語義表示。在實際應(yīng)用中,BERT的預(yù)訓(xùn)練模型可以用來進行下游任務(wù)的微調(diào),比如文本分類、命名實體識別、句子相似度等。
BERT的主要特點包括以下幾點:
-
雙向性:BERT通過使用Transformer的編碼器結(jié)構(gòu),能夠同時考慮上下文信息,使模型能夠更好地理解句子中的每個詞的語義。
-
預(yù)訓(xùn)練-微調(diào)架構(gòu):BERT先在大規(guī)模文本語料上進行預(yù)訓(xùn)練,然后通過微調(diào)在具體任務(wù)上進行優(yōu)化。這種架構(gòu)使得模型能夠在不同的任務(wù)上靈活應(yīng)用,并且不需要從零開始訓(xùn)練。
-
多層表示:BERT模型由多個Transformer編碼器層組成,每個層都生成了豐富的句子和詞級別的表示,使得模型能夠處理不同層次的語義信息。
-
預(yù)訓(xùn)練規(guī)模:BERT的預(yù)訓(xùn)練使用了大規(guī)模的文本語料,其中包括了互聯(lián)網(wǎng)上的大量文本數(shù)據(jù),這使得模型能夠?qū)W習(xí)到更通用的語言表示。
我們已經(jīng)介紹了幾種用于自然語言理解的詞嵌入模型。在預(yù)訓(xùn)練之后,輸出可以被認為是一個矩陣,其中每一行都是一個表示預(yù)定義詞表中詞的向量。事實上,這些詞嵌入模型都是與上下文無關(guān)的。讓我們先來說明這個性質(zhì)。
文章內(nèi)容來自李沐大神的《動手學(xué)深度學(xué)習(xí)》并加以我的理解,感興趣可以去https://zh-v2.d2l.ai/查看完整書籍
從上下文無關(guān)到上下文敏感
例如,word2vec和GloVe都將相同的預(yù)訓(xùn)練向量分配給同一個詞,而不考慮詞的上下文(如果有的話)。形式上,任何詞元 x x x的上下文無關(guān)表示是函數(shù) f ( x ) f(x) f(x),其僅將 x x x作為其輸入??紤]到自然語言中豐富的多義現(xiàn)象和復(fù)雜的語義,上下文無關(guān)表示具有明顯的局限性。例如,在“a crane is flying”(一只鶴在飛)和“a crane driver came”(一名吊車司機來了)的上下文中,“crane”一詞有完全不同的含義;因此,同一個詞可以根據(jù)上下文被賦予不同的表示。
這推動了“上下文敏感”詞表示的發(fā)展,其中詞的表征取決于它們的上下文。因此,詞元 x x x的上下文敏感表示是函數(shù) f ( x , c ( x ) ) f(x,c(x)) f(x,c(x)),其取決于 x x x及其上下文 c ( x ) c(x) c(x)。流行的上下文敏感表示包括TagLM(language-model-augmented sequence tagger,語言模型增強的序列標(biāo)記器) (Peters et al., 2017)、CoVe(Context Vectors,上下文向量) (McCann et al., 2017)和ELMo(Embeddings from Language Models,來自語言模型的嵌入) (Peters et al., 2018)。
例如,通過將整個序列作為輸入,ELMo是為輸入序列中的每個單詞分配一個表示的函數(shù)。具體來說,ELMo將來自預(yù)訓(xùn)練的雙向長短期記憶網(wǎng)絡(luò)的所有中間層表示組合為輸出表示。然后,ELMo的表示將作為附加特征添加到下游任務(wù)的現(xiàn)有監(jiān)督模型中,例如通過將ELMo的表示和現(xiàn)有模型中詞元的原始表示(例如GloVe)連結(jié)起來。一方面,在加入ELMo表示后,凍結(jié)了預(yù)訓(xùn)練的雙向LSTM模型中的所有權(quán)重。另一方面,現(xiàn)有的監(jiān)督模型是專門為給定的任務(wù)定制的。利用當(dāng)時不同任務(wù)的不同最佳模型,添加ELMo改進了六種自然語言處理任務(wù)的技術(shù)水平:情感分析、自然語言推斷、語義角色標(biāo)注、共指消解、命名實體識別和問答。
從特定于任務(wù)到不可知任務(wù)
盡管ELMo顯著改進了各種自然語言處理任務(wù)的解決方案,但每個解決方案仍然依賴于一個特定于任務(wù)的架構(gòu)。然而,為每一個自然語言處理任務(wù)設(shè)計一個特定的架構(gòu)實際上并不是一件容易的事。GPT(Generative Pre Training,生成式預(yù)訓(xùn)練)模型為上下文的敏感表示設(shè)計了通用的任務(wù)無關(guān)模型 (Radford et al., 2018)。GPT建立在Transformer解碼器的基礎(chǔ)上,預(yù)訓(xùn)練了一個用于表示文本序列的語言模型。當(dāng)將GPT應(yīng)用于下游任務(wù)時,語言模型的輸出將被送到一個附加的線性輸出層,以預(yù)測任務(wù)的標(biāo)簽。與ELMo凍結(jié)預(yù)訓(xùn)練模型的參數(shù)不同,GPT在下游任務(wù)的監(jiān)督學(xué)習(xí)過程中對預(yù)訓(xùn)練Transformer解碼器中的所有參數(shù)進行微調(diào)。GPT在自然語言推斷、問答、句子相似性和分類等12項任務(wù)上進行了評估,并在對模型架構(gòu)進行最小更改的情況下改善了其中9項任務(wù)的最新水平。
然而,由于語言模型的自回歸特性,GPT只能向前看(從左到右)。在“i went to the bank to deposit cash”(我去銀行存現(xiàn)金)和“i went to the bank to sit down”(我去河岸邊坐下)的上下文中,由于“bank”對其左邊的上下文敏感,GPT將返回“bank”的相同表示,盡管它有不同的含義。
語言模型的自回歸特性是指在生成文本時,模型依次預(yù)測下一個詞語的概率,并將其作為輸入的一部分來生成后續(xù)的詞語序列。也就是說,模型通過先前生成的詞語來預(yù)測下一個詞語,然后將其添加到生成的文本中,形成一個逐步生成的過程,這種方式被稱為自回歸(autoregressive)。
自回歸語言模型的基本思想是基于馬爾可夫假設(shè),即當(dāng)前詞語的生成僅依賴于前面的有限個詞語。具體來說,給定一個上下文序列(先前生成的詞語),語言模型通過條件概率來預(yù)測下一個詞語的概率分布。這個條件概率可以表示為:
P ( w t ∣ w 1 , w 2 , . . . , w t ? 1 ) P(w_t | w_1, w_2, ..., w_{t-1}) P(wt?∣w1?,w2?,...,wt?1?)
其中, w t w_t wt?表示第t個位置的詞語, w 1 , w 2 , . . . , w t ? 1 w_1, w_2, ..., w_{t-1} w1?,w2?,...,wt?1?表示前面已經(jīng)生成的詞語序列。
為了生成文本,語言模型可以使用一種稱為貪婪搜索(greedy search)的策略,即每次選擇概率最高的詞語作為下一個詞語生成。或者,也可以使用一些其他的生成策略,比如束搜索(beam search),以獲得更多可能的生成序列。
語言模型的自回歸特性使得它能夠生成連貫的文本,保持上下文的連續(xù)性,并且能夠在生成過程中考慮語法、語義和上下文信息。這使得自回歸語言模型在機器翻譯、文本生成、語音識別等任務(wù)中得到廣泛應(yīng)用。
然而,自回歸語言模型也存在一些限制,比如生成速度較慢、無法并行計算等。為了克服這些問題,近年來出現(xiàn)了一些非自回歸的生成模型,如BERT、GPT-2、GPT-3等,它們使用了預(yù)訓(xùn)練的方式來學(xué)習(xí)語言表示,可以同時生成整個序列,提高了生成速度和效率。
BERT:把兩個最好的結(jié)合起來
如我們所見,ELMo對上下文進行雙向編碼,但使用特定于任務(wù)的架構(gòu);而GPT是任務(wù)無關(guān)的,但是從左到右編碼上下文。BERT(來自Transformers的雙向編碼器表示)結(jié)合了這兩個方面的優(yōu)點。它對上下文進行雙向編碼,并且對于大多數(shù)的自然語言處理任務(wù) (Devlin et al., 2018)只需要最少的架構(gòu)改變。通過使用預(yù)訓(xùn)練的Transformer編碼器,BERT能夠基于其雙向上下文表示任何詞元。在下游任務(wù)的監(jiān)督學(xué)習(xí)過程中,BERT在兩個方面與GPT相似。首先,BERT表示將被輸入到一個添加的輸出層中,根據(jù)任務(wù)的性質(zhì)對模型架構(gòu)進行最小的更改,例如預(yù)測每個詞元與預(yù)測整個序列。其次,對預(yù)訓(xùn)練Transformer編碼器的所有參數(shù)進行微調(diào),而額外的輸出層將從頭開始訓(xùn)練。下圖描述了ELMo、GPT和BERT之間的差異。
BERT進一步改進了11種自然語言處理任務(wù)的技術(shù)水平,這些任務(wù)分為以下幾個大類:(1)單一文本分類(如情感分析)、(2)文本對分類(如自然語言推斷)、(3)問答、(4)文本標(biāo)記(如命名實體識別)。從上下文敏感的ELMo到任務(wù)不可知的GPT和BERT,它們都是在2018年提出的。概念上簡單但經(jīng)驗上強大的自然語言深度表示預(yù)訓(xùn)練已經(jīng)徹底改變了各種自然語言處理任務(wù)的解決方案。
在本章的其余部分,我們將深入了解BERT的訓(xùn)練前準(zhǔn)備。
輸入表示
在自然語言處理中,有些任務(wù)(如情感分析)以單個文本作為輸入,而有些任務(wù)(如自然語言推斷)以一對文本序列作為輸入。BERT輸入序列明確地表示單個文本和文本對。當(dāng)輸入為單個文本時,BERT輸入序列是特殊類別詞元“”、文本序列的標(biāo)記、以及特殊分隔詞元“”的連結(jié)。當(dāng)輸入為文本對時,BERT輸入序列是“”、第一個文本序列的標(biāo)記、“”、第二個文本序列標(biāo)記、以及“”的連結(jié)。我們將始終如一地將術(shù)語“BERT輸入序列”與其他類型的“序列”區(qū)分開來。例如,一個BERT輸入序列可以包括一個文本序列或兩個文本序列。
為了區(qū)分文本對,根據(jù)輸入序列學(xué)到的片段嵌入 e A e_A eA?和 e b e_b eb?分別被添加到第一序列和第二序列的詞元嵌入中。對于單文本輸入,僅使用 e A e_A eA?。
下面的get_tokens_and_segments將一個句子或兩個句子作為輸入,然后返回BERT輸入序列的標(biāo)記及其相應(yīng)的片段索引。
#@save
def get_tokens_and_segments(tokens_a, tokens_b=None):
"""獲取輸入序列的詞元及其片段索引"""
tokens = ['<cls>'] + tokens_a + ['<sep>']
# 0和1分別標(biāo)記片段A和B
segments = [0] * (len(tokens_a) + 2)
if tokens_b is not None:
tokens += tokens_b + ['<sep>']
segments += [1] * (len(tokens_b) + 1)
return tokens, segments
BERT選擇Transformer編碼器作為其雙向架構(gòu)。在Transformer編碼器中常見是,位置嵌入被加入到輸入序列的每個位置。然而,與原始的Transformer編碼器不同,BERT使用可學(xué)習(xí)的位置嵌入??傊?, 下圖表明BERT輸入序列的嵌入是詞元嵌入、片段嵌入和位置嵌入的和。
下面的BERTEncoder類類似于之前實現(xiàn)的TransformerEncoder類。與TransformerEncoder不同,BERTEncoder使用片段嵌入和可學(xué)習(xí)的位置嵌入
#@save
class BERTEncoder(nn.Module):
"""BERT編碼器"""
def __init__(self, vocab_size, num_hiddens, norm_shape, ffn_num_input,
ffn_num_hiddens, num_heads, num_layers, dropout,
max_len=1000, key_size=768, query_size=768, value_size=768,
**kwargs):
super(BERTEncoder, self).__init__(**kwargs)
self.token_embedding = nn.Embedding(vocab_size, num_hiddens)
self.segment_embedding = nn.Embedding(2, num_hiddens)
self.blks = nn.Sequential()
for i in range(num_layers):
self.blks.add_module(f"{i}", d2l.EncoderBlock(
key_size, query_size, value_size, num_hiddens, norm_shape,
ffn_num_input, ffn_num_hiddens, num_heads, dropout, True))
# 在BERT中,位置嵌入是可學(xué)習(xí)的,因此我們創(chuàng)建一個足夠長的位置嵌入?yún)?shù)
self.pos_embedding = nn.Parameter(torch.randn(1, max_len,
num_hiddens))
def forward(self, tokens, segments, valid_lens):
# 在以下代碼段中,X的形狀保持不變:(批量大小,最大序列長度,num_hiddens)
X = self.token_embedding(tokens) + self.segment_embedding(segments)
X = X + self.pos_embedding.data[:, :X.shape[1], :]
for blk in self.blks:
X = blk(X, valid_lens)
return X
關(guān)于這里的段嵌入:
這里的段嵌入用于區(qū)分第一句還是第二句,所以segment_embedding的第一個參數(shù)是2
假設(shè)詞表大小為10000,為了演示BERTEncoder的前向推斷,讓我們創(chuàng)建一個實例并初始化它的參數(shù)。
vocab_size, num_hiddens, ffn_num_hiddens, num_heads = 10000, 768, 1024, 4
norm_shape, ffn_num_input, num_layers, dropout = [768], 768, 2, 0.2
encoder = BERTEncoder(vocab_size, num_hiddens, norm_shape, ffn_num_input,
ffn_num_hiddens, num_heads, num_layers, dropout)
我們將tokens定義為長度為8的2個輸入序列,其中每個詞元是詞表的索引。使用輸入tokens的BERTEncoder的前向推斷返回編碼結(jié)果,其中每個詞元由向量表示,其長度由超參數(shù)num_hiddens定義。此超參數(shù)通常稱為Transformer編碼器的隱藏大?。[藏單元數(shù))。
tokens = torch.randint(0, vocab_size, (2, 8))
segments = torch.tensor([[0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 1]])
encoded_X = encoder(tokens, segments, None)
encoded_X.shape
預(yù)訓(xùn)練任務(wù)
BERTEncoder的前向推斷給出了輸入文本的每個詞元和插入的特殊標(biāo)記“”及“”的BERT表示。接下來,我們將使用這些表示來計算預(yù)訓(xùn)練BERT的損失函數(shù)。預(yù)訓(xùn)練包括以下兩個任務(wù):掩蔽語言模型和下一句預(yù)測。
掩蔽語言模型
語言模型使用左側(cè)的上下文預(yù)測詞元。為了雙向編碼上下文以表示每個詞元,BERT隨機掩蔽詞元并使用來自雙向上下文的詞元以自監(jiān)督的方式預(yù)測掩蔽詞元。此任務(wù)稱為掩蔽語言模型。
在這個預(yù)訓(xùn)練任務(wù)中,將隨機選擇15%的詞元作為預(yù)測的掩蔽詞元。要預(yù)測一個掩蔽詞元而不使用標(biāo)簽作弊,一個簡單的方法是總是用一個特殊的“”替換輸入序列中的詞元。然而,人造特殊詞元“”不會出現(xiàn)在微調(diào)中。為了避免預(yù)訓(xùn)練和微調(diào)之間的這種不匹配,如果為預(yù)測而屏蔽詞元(例如,在“this movie is great”中選擇掩蔽和預(yù)測“great”),則在輸入中將其替換為:
80%時間為特殊的““詞元(例如,“this movie is great”變?yōu)椤皌his movie is”;
10%時間為隨機詞元(例如,“this movie is great”變?yōu)椤皌his movie is drink”);
10%時間內(nèi)為不變的標(biāo)簽詞元(例如,“this movie is great”變?yōu)椤皌his movie is great”)。
請注意,在15%的時間中,有10%的時間插入了隨機詞元。這種偶然的噪聲鼓勵BERT在其雙向上下文編碼中不那么偏向于掩蔽詞元(尤其是當(dāng)標(biāo)簽詞元保持不變時)。
我們實現(xiàn)了下面的MaskLM類來預(yù)測BERT預(yù)訓(xùn)練的掩蔽語言模型任務(wù)中的掩蔽標(biāo)記。預(yù)測使用單隱藏層的多層感知機(self.mlp)。在前向推斷中,它需要兩個輸入:BERTEncoder的編碼結(jié)果和用于預(yù)測的詞元位置。輸出是這些位置的預(yù)測結(jié)果。
#@save
class MaskLM(nn.Module):
"""BERT的掩蔽語言模型任務(wù)"""
def __init__(self, vocab_size, num_hiddens, num_inputs=768, **kwargs):
super(MaskLM, self).__init__(**kwargs)
self.mlp = nn.Sequential(nn.Linear(num_inputs, num_hiddens),
nn.ReLU(),
nn.LayerNorm(num_hiddens),
nn.Linear(num_hiddens, vocab_size))
def forward(self, X, pred_positions):
num_pred_positions = pred_positions.shape[1]
pred_positions = pred_positions.reshape(-1)#轉(zhuǎn)為一維數(shù)組
batch_size = X.shape[0]
batch_idx = torch.arange(0, batch_size)
# 假設(shè)batch_size=2,num_pred_positions=3
# 那么batch_idx是np.array([0,0,0,1,1,1])
batch_idx = torch.repeat_interleave(batch_idx, num_pred_positions)
masked_X = X[batch_idx, pred_positions]
masked_X = masked_X.reshape((batch_size, num_pred_positions, -1))
mlm_Y_hat = self.mlp(masked_X)
return mlm_Y_hat
假設(shè) pred_positions 的形狀為 (batch_size, num_pred_positions),其中 batch_size 表示批次大小,num_pred_positions 表示每個樣本中被屏蔽的 token 的數(shù)量。
為了演示MaskLM的前向推斷,我們創(chuàng)建了其實例mlm并對其進行了初始化?;叵胍幌拢瑏碜訠ERTEncoder的正向推斷encoded_X表示2個BERT輸入序列。我們將mlm_positions定義為在encoded_X的任一輸入序列中預(yù)測的3個指示。mlm的前向推斷返回encoded_X的所有掩蔽位置mlm_positions處的預(yù)測結(jié)果mlm_Y_hat。對于每個預(yù)測,結(jié)果的大小等于詞表的大小。
mlm = MaskLM(vocab_size, num_hiddens)
mlm_positions = torch.tensor([[1, 5, 2], [6, 1, 5]])
mlm_Y_hat = mlm(encoded_X, mlm_positions)
mlm_Y_hat.shape
輸入的encoded_X為(2,8,768),mlm_positions為(2,3),即num_pred_positions=3,pred_positions為(1,6),batch_idx經(jīng)過復(fù)制為[0,0,0,1,1,1],故mask_X取出了6個768維度的詞嵌入,再將其變化為(2,3,768),最后放入MLP中變?yōu)?2,3,10000)
通過掩碼下的預(yù)測詞元mlm_Y的真實標(biāo)簽mlm_Y_hat,我們可以計算在BERT預(yù)訓(xùn)練中的遮蔽語言模型任務(wù)的交叉熵損失。
mlm_Y = torch.tensor([[7, 8, 9], [10, 20, 30]])
loss = nn.CrossEntropyLoss(reduction='none')
mlm_l = loss(mlm_Y_hat.reshape((-1, vocab_size)), mlm_Y.reshape(-1))
mlm_l.shape
下一句預(yù)測(Next Sentence Prediction)
盡管掩蔽語言建模能夠編碼雙向上下文來表示單詞,但它不能顯式地建模文本對之間的邏輯關(guān)系。為了幫助理解兩個文本序列之間的關(guān)系,BERT在預(yù)訓(xùn)練中考慮了一個二元分類任務(wù)——下一句預(yù)測。在為預(yù)訓(xùn)練生成句子對時,有一半的時間它們確實是標(biāo)簽為“真”的連續(xù)句子;在另一半的時間里,第二個句子是從語料庫中隨機抽取的,標(biāo)記為“假”。
下面的NextSentencePred類使用單隱藏層的多層感知機來預(yù)測第二個句子是否是BERT輸入序列中第一個句子的下一個句子。由于Transformer編碼器中的自注意力,特殊詞元“”的BERT表示已經(jīng)對輸入的兩個句子進行了編碼。因此,多層感知機分類器的輸出層(self.output)以X作為輸入,其中X是多層感知機隱藏層的輸出,而MLP隱藏層的輸入是編碼后的“”詞元。
#@save
class NextSentencePred(nn.Module):
"""BERT的下一句預(yù)測任務(wù)"""
def __init__(self, num_inputs, **kwargs):
super(NextSentencePred, self).__init__(**kwargs)
self.output = nn.Linear(num_inputs, 2)
def forward(self, X):
# X的形狀:(batchsize,num_hiddens)
return self.output(X)
我們可以看到,NextSentencePred實例的前向推斷返回每個BERT輸入序列的二分類預(yù)測。
encoded_X = torch.flatten(encoded_X, start_dim=1)
# NSP的輸入形狀:(batchsize,num_hiddens)
nsp = NextSentencePred(encoded_X.shape[-1])
nsp_Y_hat = nsp(encoded_X)
nsp_Y_hat.shape
還可以計算兩個二元分類的交叉熵損失。
nsp_y = torch.tensor([0, 1])
nsp_l = loss(nsp_Y_hat, nsp_y)
nsp_l.shape
值得注意的是,上述兩個預(yù)訓(xùn)練任務(wù)中的所有標(biāo)簽都可以從預(yù)訓(xùn)練語料庫中獲得,而無需人工標(biāo)注。原始的BERT已經(jīng)在圖書語料庫 (Zhu et al., 2015)和英文維基百科的連接上進行了預(yù)訓(xùn)練。這兩個文本語料庫非常龐大:它們分別有8億個單詞和25億個單詞。文章來源:http://www.zghlxwxcb.cn/news/detail-696613.html
整合代碼
在預(yù)訓(xùn)練BERT時,最終的損失函數(shù)是掩蔽語言模型損失函數(shù)和下一句預(yù)測損失函數(shù)的線性組合?,F(xiàn)在我們可以通過實例化三個類BERTEncoder、MaskLM和NextSentencePred來定義BERTModel類。前向推斷返回編碼后的BERT表示encoded_X、掩蔽語言模型預(yù)測mlm_Y_hat和下一句預(yù)測nsp_Y_hat。文章來源地址http://www.zghlxwxcb.cn/news/detail-696613.html
#@save
class BERTModel(nn.Module):
"""BERT模型"""
def __init__(self, vocab_size, num_hiddens, norm_shape, ffn_num_input,
ffn_num_hiddens, num_heads, num_layers, dropout,
max_len=1000, key_size=768, query_size=768, value_size=768,
hid_in_features=768, mlm_in_features=768,
nsp_in_features=768):
super(BERTModel, self).__init__()
self.encoder = BERTEncoder(vocab_size, num_hiddens, norm_shape,
ffn_num_input, ffn_num_hiddens, num_heads, num_layers,
dropout, max_len=max_len, key_size=key_size,
query_size=query_size, value_size=value_size)
self.hidden = nn.Sequential(nn.Linear(hid_in_features, num_hiddens),
nn.Tanh())
self.mlm = MaskLM(vocab_size, num_hiddens, mlm_in_features)
self.nsp = NextSentencePred(nsp_in_features)
def forward(self, tokens, segments, valid_lens=None,
pred_positions=None):
encoded_X = self.encoder(tokens, segments, valid_lens)
if pred_positions is not None:
mlm_Y_hat = self.mlm(encoded_X, pred_positions)
else:
mlm_Y_hat = None
# 用于下一句預(yù)測的多層感知機分類器的隱藏層,0是“<cls>”標(biāo)記的索引
nsp_Y_hat = self.nsp(self.hidden(encoded_X[:, 0, :]))
return encoded_X, mlm_Y_hat, nsp_Y_hat
到了這里,關(guān)于自然語言處理(七):來自Transformers的雙向編碼器表示(BERT)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!