初次BERT使用者的可视化指南
點擊上方“AI公園”,關注公眾號,選擇加“星標“或“置頂”
作者:Jay Alammar
編譯:ronghuaiyang
導讀
用可視化的方式演示了如何用Bert來做一個句子分類的應用,每一步都有非常詳細的圖解,特別的清楚。
在過去幾年里,處理語言的機器學習模型的進展一直在迅速加快。這一進步已經離開了研究實驗室,開始為一些領先的數字產品提供動力。這方面的一個很好的例子是最近關于 BERT 模型如何成為谷歌搜索背后的主要力量的公告。谷歌認為,這一步(或在搜索中應用自然語言理解的進步)代表了“過去五年最大的飛躍,也是搜索歷史上最大的飛躍之一”。
這篇文章是關于如何使用 BERT 的變體對句子進行分類的簡單教程。作為第一個介紹,這是一個足夠基本的示例,但也足夠高級,可以展示所涉及的一些關鍵概念。
數據集: SST2
在本例中,我們將使用的數據集是SST2,其中包含電影評論中的句子,每個句子都標記為正樣本(值為 1)或負樣本(值為 0):
模型: 句子情感分類
我們的目標是創建一個模型,該模型接受一個句子(就像我們的數據集中的那些句子一樣),并生成 1(表示句子帶有積極情緒)或 0(表示句子帶有消極情緒)。我們可以這樣想:
實際上,該模型是由兩個模型組成的。
DistilBERT處理這個句子,并將從中提取的一些信息傳遞給下一個模型。DistilBERT 是 BERT 的小版本,由HuggingFace的團隊開發并開源。它是 BERT 的一個更輕、更快的版本,與它的性能大致相當。
下一個模型是來自 scikit-learn 的一個基本邏輯回歸模型,它將接受 DistilBERT 處理的結果,并將句子分為正樣本或負樣本(分別為 1 和 0)。
我們在兩個模型之間傳遞的數據是一個大小為 768 維的向量。我們可以把這個向量看作是我們可以用來分類的句子的嵌入。
模型訓練
雖然我們將使用兩個模型,但我們只訓練邏輯回歸模型。對于 DistillBERT,我們將使用一個已經過預先訓練過并掌握了英語的模型。然而,這個模型既沒有經過訓練,也沒有經過 finetune 來進行句子分類。然而,從 BERT 通用目標的訓練中,我們得到了一些句子分類的能力。對于第一個位置(與[CLS] token 相關聯)的 BERT 輸出尤其如此。我認為這是由于 BERT 的第二個訓練目標 — 下一個句子的分類。這個目標似乎是訓練模型將句子的意義壓縮到了第一個位置的輸出中。transformer庫為我們提供了 DistilBERT 的實現以及模型的預訓練版本。
教程概要
這就是本教程的策略。我們將首先使用訓練好的 distilBERT 來生成 2000 個句子的嵌入。
在這一步之后,我們將不再接觸 distilBERT。這些都是我從這里學到的。我們對這個數據集做通常的訓練/測試劃分:
為distilBert(模型#1)的輸出進行訓練集/測試集分割,創建我們在(模型#2)上訓練和評估邏輯回歸的數據集。注意,在現實中,sklearn的train/test split在進行分割之前會對樣本進行打亂,它并不只取數據集中出現的前75%的樣本。
然后在訓練集上訓練 logistic 回歸模型:
如何計算單個預測
在深入研究代碼并解釋如何訓練模型之前,讓我們先看看訓練后的模型如何計算其預測。
讓我們試著把這句話“a visually stunning rumination on love”分類。第一步是使用 BERT tokenizer 將單詞首先分割成 tokens。然后,我們添加句子分類所需的特殊 tokens(在第一個位置是[CLS],在句子的末尾是[SEP])。
tokenizer 做的第三步是用嵌入表中的 id 替換每個 token,嵌入表是我們從訓練模型中得到的一個組件。
注意,tokenizer 在一行代碼中完成所有這些步驟:
tokenizer.encode("a visually stunning rumination on love", add_special_tokens=True)我們的輸入語句現在是傳遞給 DistilBERT 的正確形狀。
這一步也可以用以下方式可視化:
DistilBERT 的數據流
通過 DistilBERT 傳遞輸入向量的工作方式與 BERT 一樣。輸出將是每個輸入 token 的向量。每個向量由 768 個數字(浮點數)組成。
因為這是一個句子分類任務,所以除了第一個向量(與[CLS]token 相關聯的向量)外,我們忽略了所有其他向量。我們傳遞的這個向量作為邏輯回歸模型的輸入。
從這里開始,邏輯回歸模型的工作就是根據它從訓練階段學到的知識對這個向量進行分類。我們可以把預測計算想象成這樣:
我們將在下一節中討論訓練以及整個過程的代碼。
代碼
在本節中,我們將重點介紹訓練這個句子分類模型的代碼。
讓我們從 importing 工具開始。
import numpy as npimport pandas as pd
import torch
import transformers as ppb # pytorch transformers
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split
數據集可以從 github 上得到,因此我們只需將其直接導入到 pandas dataframe 中。
df = pd.read_csv('https://github.com/clairett/pytorch-sentiment-classification/raw/master/data/SST2/train.tsv', delimiter='\t', header=None)我們可以使用 df.head()查看 dataframe 的前五行,看看數據是什么樣的。
df.head()輸出:
導入預訓練的 DistilBERT 模型和 tokenizer
## Want BERT instead of distilBERT? Uncomment the following line:
#model_class, tokenizer_class, pretrained_weights = (ppb.BertModel, ppb.BertTokenizer, 'bert-base-uncased')
# Load pretrained model/tokenizer
tokenizer = tokenizer_class.from_pretrained(pretrained_weights)
model = model_class.from_pretrained(pretrained_weights)
我們現在可以 tokenize 數據集了。注意,這里我們要做的事情與上面的示例稍有不同。上面的例子只處理了一個句子。在這里,我們將使用批處理的方式 tokenize 和處理所有的句子(僅為了資源考慮,notebook 將處理更小的一組示例,比如 2000 個示例)。
Tokenization
tokenized = df[0].apply((lambda x: tokenizer.encode(x, add_special_tokens=True)))
這樣就把每個句子都轉換成了 id 列表。
數據集當前是列表(或 panda 的 Series/DataFrame)的列表。在 DistilBERT 將其作為輸入處理之前,我們需要使用 token id 0 填充更短的句子,從而使所有向量具有相同的大小。
填充之后,我們有了一個矩陣/張量,準備傳給 BERT:
使用 DistilBERT 處理
現在,我們從填充后的 token 矩陣中創建了一個輸入張量,并將其發送給 DistilBERT。
input_ids = torch.tensor(np.array(padded))with torch.no_grad():
last_hidden_states = model(input_ids)
運行此步驟后,last_hidden_states保存 DistilBERT 的輸出。在我們的例子中,這是個形狀為(2000,66,768)的 tuple。2000(因為我們只局限于 2000 個例子),66(這是 2000 個例子中最長序列中的標記數),768(在 DistilBERT 模型中隱藏單元的數量)。
展開 BERT 輸出張量
我們來展開這個三維輸出張量。我們可以先從它的維度開始:
對句子做處理的歷程
輸入的每一行都與數據集中的一個句子相關聯。對第一句話處理路徑,我們可以把它想象成這樣:
對重要的部分切片
對于句子分類,我們只對 BERT 的[CLS] token 的輸出感興趣,所以我們選擇立方體的那一部分并放棄其他部分。
這就是我們切片三維張量得到我們感興趣的二維張量的方法:
# Slice the output for the first position for all the sequences, take all hidden unit outputsfeatures = last_hidden_states[0][:,0,:].numpy()
現在features是一個 2d numpy 數組,其中包含數據集中所有句子的嵌入。
我們從BERT的輸出中切出的張量邏輯回歸的數據集
現在我們已經有了 BERT 的輸出,我們已經組裝了訓練邏輯回歸模型所需的數據集。768 列是特征,并且我們從初始數據集中獲得了標簽。
我們用來訓練邏輯回歸的數據集。這些特征是我們在前面的圖中分割的[CLS]token(位置#0)的BERT的輸出向量。每一行對應數據集中的一個句子,每一列對應Bert/DistilBERT模型頂層transformer block的前饋神經網絡的一個隱藏單元的輸出。在完成傳統的機器學習訓練集/測試集分割之后,我們可以構建邏輯回歸模型并針對數據集進行訓練。
labels = df[1]train_features, test_features, train_labels, test_labels = train_test_split(features, labels)
將數據集分割成訓練/測試集:
接下來,在訓練集上訓練邏輯回歸模型。
lr_clf = LogisticRegression()lr_clf.fit(train_features, train_labels)
現在模型已經訓練好了,我們可以根據測試集對它進行評分:
lr_clf.score(test_features, test_labels)結果表明,該模型的準確率達 81%左右。
分數基準
作為參考,這個數據集的最高準確率分數是96.8。DistilBERT 可以通過訓練來提高它在這個任務中的分數 —— 這個過程稱為 finetune,它更新 BERT 的權重,使它在句子分類中獲得更好的性能(我們可以稱之為“下游任務”)。finetune 后的餾分達到了90.7的準確率分數。全尺寸的 BERT 模型可以達到94.9。
—END—
英文原文:https://jalammar.github.io/a-visual-guide-to-using-bert-for-the-first-time/
請長按或掃描二維碼關注本公眾號
喜歡的話,請給我個好看吧!
總結
以上是生活随笔為你收集整理的初次BERT使用者的可视化指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021年度训练联盟热身训练赛第一场 A
- 下一篇: 2020程序员VS码农,“金三银四”春招