BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

BERT,作為自然語言處理領域的C位選手,總是NLPer們逃不過的一環。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

但是,如果是經驗匱乏、基礎薄弱的選手,想玩轉BERT還是有點難的。

現在,科技博主Jay Alammar創作了一篇《第一次使用BERT的圖形化指南》,用非常簡單清晰的方式介紹瞭如何上手BERT,從BERT的原理到實際操作的過程都有圖示,甚至圖比代碼都多。量子位為大家編譯搬運如下~

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

這篇文章主要以用BERT的變體對句子進行分類為例,介紹了BERT的使用方式。

最後的傳送門處還有Colab的地址。

數據集:SST2

首先,我們需要用到SST2數據集,裡面的句子來自於一些電影評論。

如果評論者對電影表示肯定讚賞,就會有“1”的標籤;

如果評論者不喜歡這個電影,發表了負面評論,就會有“0”的標籤。

數據集裡的電影評論是用英文寫的,大概長這樣:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

句子情感分類模型

現在,藉助SST2影評數據集,我們需要創建一個自動對英文句子進行分類的模型。

如果判斷是肯定的、正面的,就標註1;如果判斷是否定的、負面的,就標註0。

大致的邏輯是這樣的:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

輸入一句話,經過電影評論句子分類器,輸出積極或消極的結果。

這個模型實際上是兩個模型組成的。

DistilBERT負責處理句子,提取信息,然後傳遞給下一個模型,這是“抱抱臉公司”(HuggingFace)做的一個開源BERT版本,比較輕量級而且運行快,性能和原版差不多。

下一個模型就是一個基本的邏輯迴歸模型,它的輸入是DistilBERT的處理結果,輸出積極或消極的結果。

我們在兩個模型之間傳遞的數據是大小為768的向量,可以把這個向量當成可以用來分類的句子嵌入。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

模型的訓練過程

雖然我們會用到兩個模型,但是我們只需要訓練邏輯迴歸模型就行了,DistilBERT可以直接用預訓練好的版本。

不過,這個模型從來都沒有針對句子分類任務被訓練或微調過,我們從通用目標BERT獲取一些句子分類能力,尤其是對於第一個位置的BERT輸出而言(與[CLS]token相關),這是BERT的第二個訓練目標,接下來就是句子分類了,這個目標似乎是訓練模型將全句意義封裝到第一位置的輸出位置。

這個Transformer庫為我們提供了DistilBERT的實施和模型的預訓練版本。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

教程概述

這是本篇教程的整個計劃,我們先用訓練過的DistilBERT來生成2000個句子的句子嵌入。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

之後就不用再碰DistilBERT了,這裡都是Scikit Learn,我們在這個數據集上做常規的訓練和測試:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

針對第一個模型也就是DistilBERT進行訓練測試,創建我們訓練用的數據集並評估第二個模型也就是邏輯迴歸模型。

然後在訓練集上訓練邏輯迴歸模型:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

單個預測是如何進行的

在研究代碼解釋如何訓練模型之前,我們先看看一個訓練後的模型如何進行預測。

我們試著給這句話進行分類預測:

a visually stunning rumination on love

關於愛情的視覺上令人驚歎的反省

第一步,用BERT tokenizer把句子分為兩個token;

第二步,我們加入句子分類用的特殊token(第一個位置的是[CLS],句子結束的位置是[SEP])。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

第三步,tokenizer用嵌入表中的ID代替每個token,成為訓練模型的組件。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

注意,tokenizer是在這一行代碼裡完成所有步驟的:

1tokenizer.encode("a visually stunning rumination on love", add_special_tokens=True)

現在我們的輸入句子是可以傳遞給DistilBERT的適當狀態了。

這個步驟可視化起來長這樣:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

從DistilBERT經過

輸入向量從DistilBERT經過,輸出每個輸入token的向量,每個向量有768個數字組成。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

因為這是個句子分類的任務,所以我們忽視掉除第一個向量之外的其他內容(第一個向量和[CLS]token相關),然後把第一個向量作為邏輯迴歸模型的輸入。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

從這裡開始,邏輯迴歸模型的工作就是根據它從訓練過程中學到的經驗,把這個向量進行分類。

這個預測計算的過程是這樣的:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

代碼

現在,開始看這整個過程的代碼,後面你也可以在傳送門裡看到GitHub代碼和Colab上的可運行版本。

首先,導入trade工具。

1import numpy as np
2import pandas as pd
3import torch
4import transformers as ppb # pytorch transformers
5from sklearn.linear_model import LogisticRegression
6from sklearn.model_selection import cross_val_score
7from sklearn.model_selection import train_test_split

你可以在GitHub裡找到這個數據集,所以我們可以直接把它導入到pandas dataframe裡。

1df = pd.read_csv('https://github.com/clairett/pytorch-sentiment-classification/raw/master/data/SST2/train.tsv', delimiter='\\t', header=None)

可以直接用df.head() 查看dataframe的前五行,看看數據集長啥樣。

1df.head()

然後就輸出:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

導入預訓練DistilBERT模型和tokenizer

1model_class, tokenizer_class, pretrained_weights = (ppb.DistilBertModel, ppb.DistilBertTokenizer, 'distilbert-base-uncased')
2
3## Want BERT instead of distilBERT? Uncomment the following line:
4#model_class, tokenizer_class, pretrained_weights = (ppb.BertModel, ppb.BertTokenizer, 'bert-base-uncased')
5
6# Load pretrained model/tokenizer
7tokenizer = tokenizer_class.from_pretrained(pretrained_weights)
8model = model_class.from_pretrained(pretrained_weights)

現在可以對這個數據集tokenize了。

注意,這一步和上面的例子不同,例子只處理了一個句子,但是我們要批處理所有的句子。

Tokenization

1tokenized = df[0].apply((lambda x: tokenizer.encode(x, add_special_tokens=True)))

這一步讓每個句子都變成ID列表。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

數據集是當前的列表(或者pandas Series/DataFrame),在DistilBERT處理它之前,我們需要給所有向量統一規格,給短句子加上token 0。

填上0之後,現在就有了一個成形的矩陣/張量可以投餵給BERT了:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

用DistilBERT處理

現在,為填充的token矩陣創造一個輸入張量,發送給DistilBERT。

1input_ids = torch.tensor(np.array(padded))
2
3with torch.no_grad():
4 last_hidden_states = model(input_ids)

運行這一步之後,last_hidden_states保留DistilBERT的輸出。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

打開BERT的輸出張量

解壓縮這個3-d輸出張量,先檢查它的尺寸:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

回顧處理句子的過程

每行都和我們數據集裡的一個句子關聯,回顧一下,整個處理過程是這樣的:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

挑出重要部分

關於句子分類,我們只對BERT的[CLS] token輸出感興趣,所以我們只挑出重要部分就行了。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

下面是從3D張量裡挑出我們需要的2D張量的辦法:

1# Slice the output for the first position for all the sequences, take all hidden unit outputs
2features = last_hidden_states[0][:,0,:].numpy()

現在的特徵是個2D numpy數組,裡面有我們數據集裡所有句子的句子嵌入。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

邏輯迴歸數據集

現在我們有BERT的輸出了,前面邏輯迴歸模型已經已經訓練好了。下圖的798列是特徵,標籤是初始數據集裡面的。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

在完成傳統的機器學習訓練測試後,我們可以拿邏輯迴歸模型再進行訓練。

1labels = df[1] 

2train_features, test_features, train_labels, test_labels = train_test_split(features, labels)

將數據分為訓練集/測試集:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

接下來,在訓練集上訓練邏輯迴歸模型:

1lr_clf = LogisticRegression()
2lr_clf.fit(train_features, train_labels)

現在模型訓練完了,用測試集給它打分:

BERT,作為自然語言處理領域的C位選手,總是NLPer們逃不過的一環。 


BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
但是,如果是經驗匱乏、基礎薄弱的選手,想玩轉BERT還是有點難的。

現在,科技博主Jay Alammar創作了一篇《第一次使用BERT的圖形化指南》,用非常簡單清晰的方式介紹瞭如何上手BERT,從BERT的原理到實際操作的過程都有圖示,甚至圖比代碼都多。量子位為大家編譯搬運如下~

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
這篇文章主要以用BERT的變體對句子進行分類為例,介紹了BERT的使用方式。

最後的傳送門處還有Colab的地址。

數據集:SST2
首先,我們需要用到SST2數據集,裡面的句子來自於一些電影評論。

如果評論者對電影表示肯定讚賞,就會有“1”的標籤;

如果評論者不喜歡這個電影,發表了負面評論,就會有“0”的標籤。

數據集裡的電影評論是用英文寫的,大概長這樣:


BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
句子情感分類模型
現在,藉助SST2影評數據集,我們需要創建一個自動對英文句子進行分類的模型。

如果判斷是肯定的、正面的,就標註1;如果判斷是否定的、負面的,就標註0。

大致的邏輯是這樣的:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
輸入一句話,經過電影評論句子分類器,輸出積極或消極的結果。

這個模型實際上是兩個模型組成的。

DistilBERT負責處理句子,提取信息,然後傳遞給下一個模型,這是“抱抱臉公司”(HuggingFace)做的一個開源BERT版本,比較輕量級而且運行快,性能和原版差不多。

下一個模型就是一個基本的邏輯迴歸模型,它的輸入是DistilBERT的處理結果,輸出積極或消極的結果。

我們在兩個模型之間傳遞的數據是大小為768的向量,可以把這個向量當成可以用來分類的句子嵌入。


BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
模型的訓練過程
雖然我們會用到兩個模型,但是我們只需要訓練邏輯迴歸模型就行了,DistilBERT可以直接用預訓練好的版本。

不過,這個模型從來都沒有針對句子分類任務被訓練或微調過,我們從通用目標BERT獲取一些句子分類能力,尤其是對於第一個位置的BERT輸出而言(與[CLS]token相關),這是BERT的第二個訓練目標,接下來就是句子分類了,這個目標似乎是訓練模型將全句意義封裝到第一位置的輸出位置。

這個Transformer庫為我們提供了DistilBERT的實施和模型的預訓練版本。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
教程概述
這是本篇教程的整個計劃,我們先用訓練過的DistilBERT來生成2000個句子的句子嵌入。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
之後就不用再碰DistilBERT了,這裡都是Scikit Learn,我們在這個數據集上做常規的訓練和測試:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
針對第一個模型也就是DistilBERT進行訓練測試,創建我們訓練用的數據集並評估第二個模型也就是邏輯迴歸模型。

然後在訓練集上訓練邏輯迴歸模型:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
單個預測是如何進行的
在研究代碼解釋如何訓練模型之前,我們先看看一個訓練後的模型如何進行預測。

我們試著給這句話進行分類預測:

a visually stunning rumination on love

關於愛情的視覺上令人驚歎的反省

第一步,用BERT tokenizer把句子分為兩個token;

第二步,我們加入句子分類用的特殊token(第一個位置的是[CLS],句子結束的位置是[SEP])。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
第三步,tokenizer用嵌入表中的ID代替每個token,成為訓練模型的組件。


BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
注意,tokenizer是在這一行代碼裡完成所有步驟的:

1tokenizer.encode("a visually stunning rumination on love", add_special_tokens=True)
現在我們的輸入句子是可以傳遞給DistilBERT的適當狀態了。

這個步驟可視化起來長這樣:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
從DistilBERT經過
輸入向量從DistilBERT經過,輸出每個輸入token的向量,每個向量有768個數字組成。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
因為這是個句子分類的任務,所以我們忽視掉除第一個向量之外的其他內容(第一個向量和[CLS]token相關),然後把第一個向量作為邏輯迴歸模型的輸入。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
從這裡開始,邏輯迴歸模型的工作就是根據它從訓練過程中學到的經驗,把這個向量進行分類。

這個預測計算的過程是這樣的:


BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
代碼
現在,開始看這整個過程的代碼,後面你也可以在傳送門裡看到GitHub代碼和Colab上的可運行版本。

首先,導入trade工具。

1import numpy as np
2import pandas as pd
3import torch
4import transformers as ppb # pytorch transformers
5from sklearn.linear_model import LogisticRegression
6from sklearn.model_selection import cross_val_score
7from sklearn.model_selection import train_test_split
你可以在GitHub裡找到這個數據集,所以我們可以直接把它導入到pandas dataframe裡。

1df = pd.read_csv('https://github.com/clairett/pytorch-sentiment-classification/raw/master/data/SST2/train.tsv', delimiter='\\t', header=None)
可以直接用df.head() 查看dataframe的前五行,看看數據集長啥樣。

1df.head()
然後就輸出:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
導入預訓練DistilBERT模型和tokenizer
1model_class, tokenizer_class, pretrained_weights = (ppb.DistilBertModel, ppb.DistilBertTokenizer, 'distilbert-base-uncased')
2
3## Want BERT instead of distilBERT? Uncomment the following line:
4#model_class, tokenizer_class, pretrained_weights = (ppb.BertModel, ppb.BertTokenizer, 'bert-base-uncased')
5
6# Load pretrained model/tokenizer
7tokenizer = tokenizer_class.from_pretrained(pretrained_weights)
8model = model_class.from_pretrained(pretrained_weights)
現在可以對這個數據集tokenize了。


注意,這一步和上面的例子不同,例子只處理了一個句子,但是我們要批處理所有的句子。

Tokenization
1tokenized = df[0].apply((lambda x: tokenizer.encode(x, add_special_tokens=True)))
這一步讓每個句子都變成ID列表。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
數據集是當前的列表(或者pandas Series/DataFrame),在DistilBERT處理它之前,我們需要給所有向量統一規格,給短句子加上token 0。

填上0之後,現在就有了一個成形的矩陣/張量可以投餵給BERT了:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
用DistilBERT處理
現在,為填充的token矩陣創造一個輸入張量,發送給DistilBERT。

1input_ids = torch.tensor(np.array(padded))
2
3with torch.no_grad():
4 last_hidden_states = model(input_ids)
運行這一步之後,last_hidden_states保留DistilBERT的輸出。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
打開BERT的輸出張量
解壓縮這個3-d輸出張量,先檢查它的尺寸:


BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
回顧處理句子的過程
每行都和我們數據集裡的一個句子關聯,回顧一下,整個處理過程是這樣的:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
挑出重要部分
關於句子分類,我們只對BERT的[CLS] token輸出感興趣,所以我們只挑出重要部分就行了。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
下面是從3D張量裡挑出我們需要的2D張量的辦法:

1# Slice the output for the first position for all the sequences, take all hidden unit outputs
2features = last_hidden_states[0][:,0,:].numpy()
現在的特徵是個2D numpy數組,裡面有我們數據集裡所有句子的句子嵌入。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
邏輯迴歸數據集
現在我們有BERT的輸出了,前面邏輯迴歸模型已經已經訓練好了。下圖的798列是特徵,標籤是初始數據集裡面的。

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行

在完成傳統的機器學習訓練測試後,我們可以拿邏輯迴歸模型再進行訓練。

1labels = df[1]
2train_features, test_features, train_labels, test_labels = train_test_split(features, labels)
將數據分為訓練集/測試集:

BERT小學生級上手教程,從原理到上手全有圖示,還能直接在線運行
接下來,在訓練集上訓練邏輯迴歸模型:

1lr_clf = LogisticRegression()
2lr_clf.fit(train_features, train_labels)
現在模型訓練完了,用測試集給它打分:

1lr_clf.score(test_features, test_labels)
得出的模型準確度為81%。

Score Benchmarks
作為參考,這個數據集目前的最高準確率得分為96.8.

在這個任務裡,DistilBERT可以訓練來提升分數,這個過程叫做微調(fine-tuning),可以更新BERT的權重,來實現更好的分類句子。

微調後的DistilBERT可以實現90.7的準確率,完整的BERT模型能達到94.9的準確率。

傳送門
A Visual Guide to Using BERT for the First Time
https://jalammar.github.io/a-visual-guide-to-using-bert-for-the-first-time/

代碼
https://github.com/jalammar/jalammar.github.io/blob/master/notebooks/bert/A_Visual_Notebook_to_Using_BERT_for_the_First_Time.ipynb


Colab
https://colab.research.google.com/github/jalammar/jalammar.github.io/blob/master/notebooks/bert/A_Visual_Notebook_to_Using_BERT_for_the_First_Time.ipynb

DistilBERT
https://medium.com/huggingface/distilbert-8cf3380435b51lr_clf.score(test_features, test_labels)

得出的模型準確度為81%。

Score Benchmarks

作為參考,這個數據集目前的最高準確率得分為96.8.

在這個任務裡,DistilBERT可以訓練來提升分數,這個過程叫做微調(fine-tuning),可以更新BERT的權重,來實現更好的分類句子。

微調後的DistilBERT可以實現90.7的準確率,完整的BERT模型能達到94.9的準確率。

傳送門

A Visual Guide to Using BERT for the First Time
https://jalammar.github.io/a-visual-guide-to-using-bert-for-the-first-time/

代碼
https://github.com/jalammar/jalammar.github.io/blob/master/notebooks/bert/A_Visual_Notebook_to_Using_BERT_for_the_First_Time.ipynb

Colab
https://colab.research.google.com/github/jalammar/jalammar.github.io/blob/master/notebooks/bert/A_Visual_Notebook_to_Using_BERT_for_the_First_Time.ipynb

DistilBERT
https://medium.com/huggingface/distilbert-8cf3380435b5


分享到:


相關文章: