乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      保姆級(jí)教程,用PyTorch和BERT進(jìn)行文本分類(lèi)

       漢無(wú)為 2022-06-05 發(fā)布于湖北


      文本中,小猴子和大家一起學(xué)習(xí),如何利用 Hugging Face 的預(yù)訓(xùn)練 BERT 模型對(duì)新聞文章的文本(BBC 新聞分類(lèi)數(shù)據(jù)集)進(jìn)行分類(lèi)。
      早在 2018 年,谷歌就為 NLP 應(yīng)用程序開(kāi)發(fā)了一個(gè)基于 Transformer 的強(qiáng)大的機(jī)器學(xué)習(xí)模型,該模型在不同的基準(zhǔn)數(shù)據(jù)集中優(yōu)于以前的語(yǔ)言模型。這個(gè)模型被稱(chēng)為BERT。

      在這篇文章中,我們將使用來(lái)自 Hugging Face 的預(yù)訓(xùn)練 BERT 模型進(jìn)行文本分類(lèi)任務(wù)。一般而言,文本分類(lèi)任務(wù)中模型的主要目標(biāo)是將文本分類(lèi)為預(yù)定義的標(biāo)簽或標(biāo)簽之一。

      本文中,我們使用 BBC 新聞分類(lèi)數(shù)據(jù)集,使用預(yù)訓(xùn)練的 BERT 模型來(lái)分類(lèi)新聞文章的文本是否可以分類(lèi)為體育、政治、商業(yè)娛樂(lè)科技類(lèi)別。

      什么是 BERT

      BERT 是 Bidirectional Encoder Representations from Transformers 的首字母縮寫(xiě)詞。

      Image

      BERT 架構(gòu)由多個(gè)堆疊在一起的 Transformer 編碼器組成。每個(gè) Transformer 編碼器都封裝了兩個(gè)子層:一個(gè)自注意力層和一個(gè)前饋層。

      有兩種不同的 BERT 模型:

      Image
      1. BERT base 模型,由 12 層 Transformer 編碼器、12 個(gè)注意力頭、768 個(gè)隱藏大小和 110M 參數(shù)組成。
      2. BERT large 模型,由 24 層 Transformer 編碼器、16 個(gè)注意力頭、1024 個(gè)隱藏大小和 340M 個(gè)參數(shù)組成。

      BERT 是一個(gè)強(qiáng)大的語(yǔ)言模型至少有兩個(gè)原因:

      1. 它使用從 BooksCorpus (有 8 億字)和 Wikipedia(有 25 億字)中提取的未標(biāo)記數(shù)據(jù)進(jìn)行預(yù)訓(xùn)練。
      2. 顧名思義,它是通過(guò)利用編碼器堆棧的雙向特性進(jìn)行預(yù)訓(xùn)練的。這意味著 BERT 不僅從左到右,而且從右到左從單詞序列中學(xué)習(xí)信息。

      論文

      • Transformer: Attention Is All You Need:https:///abs/1706.03762
      • BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding:https:///abs/1810.04805

      源碼

      • Transformer Pytorch源碼:https://github.com/jadore801120/attention-is-all-you-need-pytorch
      • BERT Pytorch源碼:https://github.com/hichenway/CodeShare/tree/master/bert_pytorch_source_code
      • HuggingFace Transformers:https://github.com/huggingface/transformers

      BERT 輸入

      Image

      BERT 模型需要一系列 tokens (words) 作為輸入。在每個(gè)token序列中,BERT 期望輸入有兩個(gè)特殊標(biāo)記:

      • [CLS] :這是每個(gè)sequence的第一個(gè)token,代表分類(lèi)token。
      • [SEP] :這是讓BERT知道哪個(gè)token屬于哪個(gè)序列的token。這一特殊表征法主要用于下一個(gè)句子預(yù)測(cè)任務(wù)或問(wèn)答任務(wù)。如果我們只有一個(gè)sequence,那么這個(gè)token將被附加到序列的末尾。

      為什么選它們([CLS]/[SEP])呢,因?yàn)榕c文本中已有的其它詞相比,這個(gè)無(wú)明顯語(yǔ)義信息的符號(hào)會(huì)更“公平”地融合文本中各個(gè)詞的語(yǔ)義信息,從而更好的表示整句話的語(yǔ)義。

      具體來(lái)說(shuō),self-attention 是用文本中的其它詞來(lái)增強(qiáng)目標(biāo)詞的語(yǔ)義表示,但是目標(biāo)詞本身的語(yǔ)義還是會(huì)占主要部分的,因此,經(jīng)過(guò)BERT的12層,每次詞的 Embedding 融合了所有詞的信息,可以去更好的表示自己的語(yǔ)義。

      [CLS]位本身沒(méi)有語(yǔ)義,經(jīng)過(guò)12層,得到的是attention后所有詞的加權(quán)平均,相比其他正常詞,可以更好的表征句子語(yǔ)義。

      就像Transformer的普通編碼器一樣,BERT 將一系列單詞作為輸入,這些單詞不斷向上流動(dòng)。每一層都應(yīng)用自我注意,并將其結(jié)果通過(guò)前饋網(wǎng)絡(luò)傳遞,然后將其傳遞給下一個(gè)編碼器。

      Image

      舉個(gè)簡(jiǎn)單的例子以更清楚說(shuō)明,假設(shè)我們有一個(gè)包含以下短句的文本:

      Image

      第一步,需要將這個(gè)句子轉(zhuǎn)換為一系列tokens (words) ,這個(gè)過(guò)程稱(chēng)為tokenization

      Image

      雖然已經(jīng)對(duì)輸入句子進(jìn)行了標(biāo)記,但還需要再做一步。在將其用作 BERT 模型的輸入之前,我們需要通過(guò)添加 [CLS][SEP] 標(biāo)記來(lái)對(duì) tokens 的 sequence 重新編碼。

      Image

      其實(shí)我們只需要一行代碼(即使用BertTokenizer)就可以將輸入句子轉(zhuǎn)換為 BERT 所期望的tokens 序列。

      還需要注意的是,可以輸入 BERT 模型的最大tokens大小為 512。如果sequence中的tokens小于 512,我們可以使用填充來(lái)用 [PAD] 填充未使用的tokens。如果sequence中的tokens長(zhǎng)于 512,那么需要進(jìn)行截?cái)唷?/p>

      BERT 輸出

      每個(gè)位置輸出一個(gè)大小為 hidden_ size的向量(BERT Base 中為 768)。對(duì)于我們?cè)谏厦婵吹降木渥臃诸?lèi)示例,我們只關(guān)注第一個(gè)位置的輸出(將特殊的 [CLS] token 傳遞到該位置)。

      Image

      該向量現(xiàn)在可以用作我們選擇的分類(lèi)器的輸入。該論文僅使用單層神經(jīng)網(wǎng)絡(luò)作為分類(lèi)器就取得了很好的效果。

      Image

      如果有更多標(biāo)簽,只需調(diào)整分類(lèi)器網(wǎng)絡(luò)以獲得更多輸出神經(jīng)元然后通過(guò)softmax輸出多標(biāo)簽分類(lèi)。

      使用 BERT 進(jìn)行文本分類(lèi)

      Image

      本文的主題是用 BERT 對(duì)文本進(jìn)行分類(lèi)。在這篇文章中,我們將使用kaggle上的BBC 新聞分類(lèi)數(shù)據(jù)集。

      數(shù)據(jù)集已經(jīng)是 CSV 格式,它有 2126 個(gè)不同的文本,每個(gè)文本都標(biāo)記在 5 個(gè)類(lèi)別中的一個(gè)下:sport(體育),business(商業(yè)),politics(政治),tech(科技),entertainment(娛樂(lè))。

      看一下數(shù)據(jù)集的樣子:

      Image

      如上表所示,數(shù)據(jù)框只有兩列,category 將作為標(biāo)簽,text 將作為 BERT 的輸入數(shù)據(jù)。

      預(yù)模型下載和使用

      BERT 預(yù)訓(xùn)練模型的下載有許多方式,比如從github官網(wǎng)上下載(官網(wǎng)下載的是tensorflow版本的),還可以從源碼中找到下載鏈接,然后手動(dòng)下載,最后還可以從huggingface中下載。
      huggingface下載預(yù)訓(xùn)練模型的地址:https:///models

      在搜索框搜索到你需要的模型。

      Image

      來(lái)到下載頁(yè)面:

      Image

      注意,這里常用的幾個(gè)預(yù)訓(xùn)練模型,bert-base-cased、bert-base-uncased及中文bert-base-chinese。其中前兩個(gè)容易混淆。bert-base-cased是區(qū)分大小寫(xiě),不需要事先lower-case;而bert-base-uncased不能區(qū)分大小寫(xiě),因?yàn)樵~表只有小寫(xiě),需要事先lower-case。

      基本使用示例:

      from transformers import BertModel,BertTokenizer
      BERT_PATH = './bert-base-cased'
      tokenizer = BertTokenizer.from_pretrained(BERT_PATH)
      print(tokenizer.tokenize('I have a good time, thank you.'))
      bert = BertModel.from_pretrained(BERT_PATH)
      print('load bert model over')
      ['I', 'have', 'a', 'good', 'time',
      ',', 'thank', 'you', '.']
      load bert model over

      預(yù)處理數(shù)據(jù)

      現(xiàn)在我們基本熟悉了 BERT 的基本使用,接下來(lái)為其準(zhǔn)備輸入數(shù)據(jù)。一般情況下,在訓(xùn)練模型前,都需要對(duì)手上的數(shù)據(jù)進(jìn)行預(yù)處理,以滿足模型需要。

      前面已經(jīng)介紹過(guò)了,模型輸入數(shù)據(jù)中,需要通過(guò)添加 [CLS][SEP] 這兩個(gè)特殊的token,將文本轉(zhuǎn)換為 BERT 所期望的格式。

      首先,需要通過(guò) pip 安裝 Transformers 庫(kù):

      %%capture
      !pip install transformers

      為了更容易理解得到的輸出tokenization,我們以一個(gè)簡(jiǎn)短的文本為例。

      from transformers import BertTokenizer
      tokenizer = BertTokenizer.from_pretrained('bert-base-cased')
      example_text = 'I will watch Memento tonight'
      bert_input = tokenizer(example_text,padding='max_length', 
                             max_length = 10, 
                             truncation=True,
                             return_tensors='pt')
      # ------- bert_input ------
      print(bert_input['input_ids'])
      print(bert_input['token_type_ids'])
      print(bert_input['attention_mask'])
      tensor([[ 101, 146, 1209, 2824, 2508,
      26173, 3568, 102, 0, 0]])
      tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
      tensor([[1, 1, 1, 1, 1, 1, 1, 1, 0, 0]])

      下面是對(duì)上面BertTokenizer參數(shù)的解釋?zhuān)?/p>

      • padding:將每個(gè)sequence填充到指定的最大長(zhǎng)度。
      • max_length: 每個(gè)sequence的最大長(zhǎng)度。本示例中我們使用 10,但對(duì)于本文實(shí)際數(shù)據(jù)集,我們將使用 512,這是 BERT 允許的sequence 的最大長(zhǎng)度。
      • truncation:如果為T(mén)rue,則每個(gè)序列中超過(guò)最大長(zhǎng)度的標(biāo)記將被截?cái)唷?/section>
      • return_tensors:將返回的張量類(lèi)型。由于我們使用的是 Pytorch,所以我們使用pt;如果你使用 Tensorflow,那么你需要使用tf。

      從上面的變量中看到的輸出bert_input,是用于稍后的 BERT 模型。但是這些輸出是什么意思?

      1. 第一行是 input_ids,它是每個(gè) token 的 id 表示。實(shí)際上可以將這些輸入 id 解碼為實(shí)際的 token,如下所示:

      example_text = tokenizer.decode(bert_input.input_ids[0])
      print(example_text)
      '[CLS] I will watch Memento tonight
      [SEP] [PAD] [PAD]'

      由上述結(jié)果所示,BertTokenizer負(fù)責(zé)輸入文本的所有必要轉(zhuǎn)換,為 BERT 模型的輸入做好準(zhǔn)備。它會(huì)自動(dòng)添加 [CLS]、[SEP][PAD] token。由于我們指定最大長(zhǎng)度為 10,所以最后只有兩個(gè) [PAD] token。

      2. 第二行是 token_type_ids,它是一個(gè) binary mask,用于標(biāo)識(shí) token 屬于哪個(gè) sequence。如果我們只有一個(gè) sequence,那么所有的 token 類(lèi)型 id 都將為 0。對(duì)于文本分類(lèi)任務(wù),token_type_ids是 BERT 模型的可選輸入?yún)?shù)。

      3. 第三行是 attention_mask,它是一個(gè) binary mask,用于標(biāo)識(shí) token 是真實(shí) word 還是只是由填充得到。如果 token 包含 [CLS]、[SEP] 或任何真實(shí)單詞,則 mask 將為 1。如果 token 只是 [PAD] 填充,則 mask 將為 0。

      注意到,我們使用了一個(gè)預(yù)訓(xùn)練BertTokenizerbert-base-cased模型。如果數(shù)據(jù)集中的文本是英文的,這個(gè)預(yù)訓(xùn)練的分詞器就可以很好地工作。

      如果有來(lái)自不同語(yǔ)言的數(shù)據(jù)集,可能需要使用bert-base-multilingual-cased。具體來(lái)說(shuō),如果你的數(shù)據(jù)集是德語(yǔ)、荷蘭語(yǔ)、中文、日語(yǔ)或芬蘭語(yǔ),則可能需要使用專(zhuān)門(mén)針對(duì)這些語(yǔ)言進(jìn)行預(yù)訓(xùn)練的分詞器。可以在此處查看相應(yīng)的預(yù)訓(xùn)練標(biāo)記器的名稱(chēng)[1]。特別地,如果數(shù)據(jù)集中的文本是中文的,需要使用bert-base-chinese 模型,以及其相應(yīng)的BertTokenizer等。

      數(shù)據(jù)集類(lèi)

      現(xiàn)在我們知道從BertTokenizer中獲得什么樣的輸出,接下來(lái)為新聞數(shù)據(jù)集構(gòu)建一個(gè)Dataset類(lèi),該類(lèi)將作為一個(gè)類(lèi)來(lái)將新聞數(shù)據(jù)轉(zhuǎn)換成模型需要的數(shù)據(jù)格式。

      上下滑動(dòng)查看更多源碼
      import torch
      import numpy as np
      from transformers import BertTokenizer
      tokenizer = BertTokenizer.from_pretrained('bert-base-cased')
      labels = {'business':0,
                'entertainment':1,
                'sport':2,
                'tech':3,
                'politics':4
                }

      class Dataset(torch.utils.data.Dataset):
          def __init__(self, df):
              self.labels = [labels[label] for label in df['category']]
              self.texts = [tokenizer(text, 
                                      padding='max_length', 
                                      max_length = 512, 
                                      truncation=True,
                                      return_tensors='pt') 
                            for text in df['text']]

          def classes(self):
              return self.labels

          def __len__(self):
              return len(self.labels)

          def get_batch_labels(self, idx):
              # Fetch a batch of labels
              return np.array(self.labels[idx])

          def get_batch_texts(self, idx):
              # Fetch a batch of inputs
              return self.texts[idx]

          def __getitem__(self, idx):
              batch_texts = self.get_batch_texts(idx)
              batch_y = self.get_batch_labels(idx)
              return batch_texts, batch_y

      在上面實(shí)現(xiàn)的代碼中,我們定義了一個(gè)名為 labels的變量,它是一個(gè)字典,將DataFrame中的 category 映射到 labels的 id 表示。注意,上面的__init__函數(shù)中,還調(diào)用了BertTokenizer將輸入文本轉(zhuǎn)換為 BERT 期望的向量格式。

      定義Dataset類(lèi)后,將數(shù)據(jù)框拆分為訓(xùn)練集、驗(yàn)證集和測(cè)試集,比例為 80:10:10

      np.random.seed(112)
      df_train, df_val, df_test = np.split(df.sample(frac=1, random_state=42), 
                                           [int(.8*len(df)), int(.9*len(df))])

      print(len(df_train),len(df_val), len(df_test))
      1780 222 223

      構(gòu)建模型

      至此,我們已經(jīng)成功構(gòu)建了一個(gè) Dataset 類(lèi)來(lái)生成模型輸入數(shù)據(jù)?,F(xiàn)在使用具有 12 層 Transformer 編碼器的預(yù)訓(xùn)練 BERT 基礎(chǔ)模型構(gòu)建實(shí)際模型。

      如果數(shù)據(jù)集中的文本是中文的,需要使用bert-base-chinese 模型。

      from torch import nn
      from transformers import BertModel

      class BertClassifier(nn.Module):
          def __init__(self, dropout=0.5):
              super(BertClassifier, self).__init__()
              self.bert = BertModel.from_pretrained('bert-base-cased')
              self.dropout = nn.Dropout(dropout)
              self.linear = nn.Linear(768, 5)
              self.relu = nn.ReLU()

          def forward(self, input_id, mask):
              _, pooled_output = self.bert(input_ids= input_id, attention_mask=mask,return_dict=False)
              dropout_output = self.dropout(pooled_output)
              linear_output = self.linear(dropout_output)
              final_layer = self.relu(linear_output)
              return final_layer

      從上面的代碼可以看出,BERT 模型輸出了兩個(gè)變量:

      • 在上面的代碼中命名的第一個(gè)變量_包含sequence中所有 token 的 Embedding 向量層。
      • 命名的第二個(gè)變量pooled_output包含 [CLS] token 的 Embedding 向量。對(duì)于文本分類(lèi)任務(wù),使用這個(gè) Embedding 作為分類(lèi)器的輸入就足夠了。

      然后將pooled_output變量傳遞到具有 ReLU 激活函數(shù)的線性層。在線性層中輸出一個(gè)維度大小為 5 的向量,每個(gè)向量對(duì)應(yīng)于標(biāo)簽類(lèi)別(運(yùn)動(dòng)、商業(yè)、政治、 娛樂(lè)和科技)。

      訓(xùn)練模型

      接下來(lái)是訓(xùn)練模型。使用標(biāo)準(zhǔn)的 PyTorch 訓(xùn)練循環(huán)來(lái)訓(xùn)練模型。

      上下滑動(dòng)查看更多源碼

      from torch.optim import Adam
      from tqdm import tqdm

      def train(model, train_data, val_data, learning_rate, epochs):
        # 通過(guò)Dataset類(lèi)獲取訓(xùn)練和驗(yàn)證集
          train, val = Dataset(train_data), Dataset(val_data)
          # DataLoader根據(jù)batch_size獲取數(shù)據(jù),訓(xùn)練時(shí)選擇打亂樣本
          train_dataloader = torch.utils.data.DataLoader(train, batch_size=2, shuffle=True)
          val_dataloader = torch.utils.data.DataLoader(val, batch_size=2)
        # 判斷是否使用GPU
          use_cuda = torch.cuda.is_available()
          device = torch.device('cuda' if use_cuda else 'cpu')
          # 定義損失函數(shù)和優(yōu)化器
          criterion = nn.CrossEntropyLoss()
          optimizer = Adam(model.parameters(), lr=learning_rate)

          if use_cuda:
                  model = model.cuda()
                  criterion = criterion.cuda()
          # 開(kāi)始進(jìn)入訓(xùn)練循環(huán)
          for epoch_num in range(epochs):
            # 定義兩個(gè)變量,用于存儲(chǔ)訓(xùn)練集的準(zhǔn)確率和損失
                  total_acc_train = 0
                  total_loss_train = 0
            # 進(jìn)度條函數(shù)tqdm
                  for train_input, train_label in tqdm(train_dataloader):

                      train_label = train_label.to(device)
                      mask = train_input['attention_mask'].to(device)
                      input_id = train_input['input_ids'].squeeze(1).to(device)
              # 通過(guò)模型得到輸出
                      output = model(input_id, mask)
                      # 計(jì)算損失
                      batch_loss = criterion(output, train_label)
                      total_loss_train += batch_loss.item()
                      # 計(jì)算精度
                      acc = (output.argmax(dim=1) == train_label).sum().item()
                      total_acc_train += acc
              # 模型更新
                      model.zero_grad()
                      batch_loss.backward()
                      optimizer.step()
                  # ------ 驗(yàn)證模型 -----------
                  # 定義兩個(gè)變量,用于存儲(chǔ)驗(yàn)證集的準(zhǔn)確率和損失
                  total_acc_val = 0
                  total_loss_val = 0
            # 不需要計(jì)算梯度
                  with torch.no_grad():
                      # 循環(huán)獲取數(shù)據(jù)集,并用訓(xùn)練好的模型進(jìn)行驗(yàn)證
                      for val_input, val_label in val_dataloader:
                # 如果有GPU,則使用GPU,接下來(lái)的操作同訓(xùn)練
                          val_label = val_label.to(device)
                          mask = val_input['attention_mask'].to(device)
                          input_id = val_input['input_ids'].squeeze(1).to(device)
        
                          output = model(input_id, mask)

                          batch_loss = criterion(output, val_label)
                          total_loss_val += batch_loss.item()
                          
                          acc = (output.argmax(dim=1) == val_label).sum().item()
                          total_acc_val += acc
                  
                  print(
                      f'''Epochs: {epoch_num + 1} 
                    | Train Loss: {total_loss_train / len(train_data): .3f} 
                    | Train Accuracy: {total_acc_train / len(train_data): .3f} 
                    | Val Loss: {total_loss_val / len(val_data): .3f} 
                    | Val Accuracy: {total_acc_val / len(val_data): .3f}''')           

      我們對(duì)模型進(jìn)行了 5 個(gè) epoch 的訓(xùn)練,我們使用 Adam 作為優(yōu)化器,而學(xué)習(xí)率設(shè)置為1e-6。因?yàn)楸景咐惺翘幚矶囝?lèi)分類(lèi)問(wèn)題,則使用分類(lèi)交叉熵作為我們的損失函數(shù)。

      建議使用 GPU 來(lái)訓(xùn)練模型,因?yàn)?BERT 基礎(chǔ)模型包含 1.1 億個(gè)參數(shù)。

      EPOCHS = 5
      model = BertClassifier()
      LR = 1e-6
      train(model, df_train, df_val, LR, EPOCHS)
      Image

      顯然,由于訓(xùn)練過(guò)程的隨機(jī)性,每次可能不會(huì)得到與上面截圖類(lèi)似的損失和準(zhǔn)確率值。如果在 5 個(gè) epoch 之后沒(méi)有得到好的結(jié)果,可以嘗試將 epoch 增加到 10 個(gè),或者調(diào)整學(xué)習(xí)率。

      在測(cè)試數(shù)據(jù)上評(píng)估模型

      現(xiàn)在我們已經(jīng)訓(xùn)練了模型,我們可以使用測(cè)試數(shù)據(jù)來(lái)評(píng)估模型在未見(jiàn)數(shù)據(jù)上的性能。下面是評(píng)估模型在測(cè)試集上的性能的函數(shù)。

      def evaluate(model, test_data):

          test = Dataset(test_data)
          test_dataloader = torch.utils.data.DataLoader(test, batch_size=2)
          use_cuda = torch.cuda.is_available()
          device = torch.device('cuda' if use_cuda else 'cpu')
          if use_cuda:
              model = model.cuda()

          total_acc_test = 0
          with torch.no_grad():
              for test_input, test_label in test_dataloader:
                    test_label = test_label.to(device)
                    mask = test_input['attention_mask'].to(device)
                    input_id = test_input['input_ids'].squeeze(1).to(device)
                    output = model(input_id, mask)
                    acc = (output.argmax(dim=1) == test_label).sum().item()
                    total_acc_test += acc   
          print(f'Test Accuracy: {total_acc_test / len(test_data): .3f}')
          
      evaluate(model, df_test)

      運(yùn)行上面的代碼后,我從測(cè)試數(shù)據(jù)中得到了 0.994 的準(zhǔn)確率。由于訓(xùn)練過(guò)程中的隨機(jī)性,將獲得的準(zhǔn)確度可能會(huì)與我的結(jié)果略有不同。

      討論兩個(gè)問(wèn)題

      這里有個(gè)問(wèn)題:使用BERT預(yù)訓(xùn)練模型為什么最多只能輸入512個(gè)詞,最多只能兩個(gè)句子合成一句?

      這是Google BERT預(yù)訓(xùn)練模型初始設(shè)置的原因,前者對(duì)應(yīng)Position Embeddings,后者對(duì)應(yīng)Segment Embeddings

      在BERT中,Token,Position,Segment Embeddings 都是通過(guò)學(xué)習(xí)來(lái)得到的,pytorch代碼中它們是這樣的

      self.word_embeddings = Embedding(config.vocab_size, config.hidden_size)
      self.position_embeddings = Embedding(config.max_position_embeddings, config.hidden_size)
      self.token_type_embeddings = Embedding(config.type_vocab_size, config.hidden_size)

      而在BERT config中

      'max_position_embeddings': 512
      'type_vocab_size': 2

      因此,在直接使用 Google 的 BERT 預(yù)訓(xùn)練模型時(shí),輸入最多512個(gè)詞(還要除掉[CLS]和[SEP]),最多兩個(gè)句子合成一句。這之外的詞和句子會(huì)沒(méi)有對(duì)應(yīng)的 Embedding 。

      當(dāng)然,如果有足夠的硬件資源自己重新訓(xùn)練 BERT,可以更改 BERT config,設(shè)置更大 max_position_embeddingstype_vocab_size 值去滿足自己的需求。

      此外還有人問(wèn) BERT的三個(gè)Embedding直接相加會(huì)對(duì)語(yǔ)義有影響嗎?

      Image

      這是一個(gè)非常有意思的問(wèn)題,蘇劍林老師也給出了回答,真的很妙?。?/p>

      Embedding 的數(shù)學(xué)本質(zhì),就是以 one hot 為輸入的單層全連接。也就是說(shuō),世界上本沒(méi)什么 Embedding,有的只是one hot。

      在這里想用一個(gè)例子再?lài)L試解釋一下:

      假設(shè) token Embedding 矩陣維度是 [4,768];position Embedding 矩陣維度是 [3,768];segment Embedding 矩陣維度是 [2,768]。

      對(duì)于一個(gè)字,假設(shè)它的 token one-hot 是[1,0,0,0];它的 position one-hot 是[1,0,0];它的 segment one-hot 是[1,0]。

      那這個(gè)字最后的 word Embedding,就是上面三種 Embedding 的加和。

      如此得到的 word Embedding,和concat后的特征:[1,0,0,0,1,0,0,1,0],再過(guò)維度為 [4+3+2,768] = [9, 768] 的全連接層,得到的向量其實(shí)就是一樣的。

      再換一個(gè)角度理解:

      直接將三個(gè)one-hot 特征 concat 起來(lái)得到的 [1,0,0,0,1,0,0,1,0] 不再是one-hot了,但可以把它映射到三個(gè)one-hot 組成的特征空間,空間維度是 432=24 ,那在新的特征空間,這個(gè)字的one-hot就是[1,0,0,0,0...] (23個(gè)0)。

      此時(shí),Embedding 矩陣維度就是 [24,768],最后得到的 word Embedding 依然是和上面的等效,但是三個(gè)小 Embedding 矩陣的大小會(huì)遠(yuǎn)小于新特征空間對(duì)應(yīng)的 Embedding 矩陣大小。

      當(dāng)然,在相同初始化方法前提下,兩種方式得到的 word Embedding 可能方差會(huì)有差別,但是,BERT還有Layer Norm,會(huì)把 Embedding 結(jié)果統(tǒng)一到相同的分布。

      BERT的三個(gè)Embedding相加,本質(zhì)可以看作一個(gè)特征的融合,強(qiáng)大如 BERT 應(yīng)該可以學(xué)到融合后特征的語(yǔ)義信息的

      這就是 BERT 期望的所有輸入。

      然后,BERT 模型將在每個(gè)token中輸出一個(gè)大小為 768 的 Embedding 向量。我們可以將這些向量用作不同類(lèi)型 NLP 任務(wù)的輸入,無(wú)論是文本分類(lèi)、本文生成、命名實(shí)體識(shí)別 (NER) 還是問(wèn)答。

      對(duì)于文本分類(lèi)任務(wù),我們將注意力集中在特殊 [CLS] token 的 embedding 向量輸出上。這意味著我們將使用具有 [CLS] token 的大小為 768 的 embedding 向量作為分類(lèi)器的輸入,然后它將輸出一個(gè)大小為分類(lèi)任務(wù)中類(lèi)別個(gè)數(shù)的向量。

      寫(xiě)在最后

      現(xiàn)在我們?nèi)鐚W(xué)會(huì)了何利用 Hugging Face 的預(yù)訓(xùn)練 BERT 模型進(jìn)行文本分類(lèi)任務(wù)的步驟。我希望在你開(kāi)始使用 BERT是,這篇文章能幫到你。我們不僅可以使用來(lái)自 BERT 的embedding向量來(lái)執(zhí)行句子或文本分類(lèi)任務(wù),還可以執(zhí)行更高級(jí)的 NLP 應(yīng)用,例如問(wèn)答、文本生成或命名實(shí)體識(shí)別 (NER)任務(wù)。

      參考資料

      [1]

      預(yù)訓(xùn)練標(biāo)記器的名稱(chēng): https:///transformers/pretrained_models.html

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類(lèi)似文章 更多