SimCSE,丹琦女神把對比學習用到了NLP中了!
theme: Chinese-red
持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第16天,點選檢視活動詳情
本文共計2944字,閱讀大概需要花費6分鐘
論文簡介
論文連結:SimCSE: Simple Contrastive Learning of Sentence Embeddings
如果大家瞭解對比學習的話就好辦了,這篇文章就是將對比學習應用到了自然語言處理領域。起初對學習先是用在影象領域的。如果你瞭解的話就可以繼續往下看,如果你不瞭解的話我建議是先了解一下對比學習。 另外推薦幾篇我寫的對比學習的文章。
無監督獲取句子向量: - 使用預訓練好的 Bert 直接獲得句子向量,可以是 CLS 位的向量,也可以是不同 token 向量的平均值。
-
Bert-flow:On the Sentence Embeddings from Pre-trained Language Models,主要是利用流模型校正 Bert 的向量。
-
Bert-whitening:Whitening Sentence Representations for Better Semantics and Faster Retrieval,用預訓練 Bert 獲得所有句子的向量,得到句子向量矩陣,然後通過一個線性變換把句子向量矩陣變為一個均值 0,協方差矩陣為單位陣的矩陣。
有監督的方式主要是: - Sentence-Bert (SBERT):Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks,通過 Bert 的孿生網路獲得兩個句子的向量,進行有監督學習,SBERT 的結構如下圖所示。
對於對比學習來說,最重要是如何構造正負樣本。
在影象中有多種構造對比學習的樣本,比SimCLR中提到的:反轉、區域性裁剪、區域性顯出、裁剪翻轉、調整飽和度、調整顏色、使用各種濾波器比如最大值濾波器,最小值濾波器、銳化濾波器。
在自然語言處理中也有很多的資料增廣方式,但是他們對句子的影響都特別大。會嚴重降低對比學習的效果。為了解決這個問題SimCSE模型提出了一種通過隨機取樣dropout mask的操作來構造正樣本的方法。模型使用的是BERT,每次出來的Dropout是不同的。隨機dropout masks機制存在於模型的fully-connected layers和attention probabilities上,因此相同的輸入,經過模型後會得到不同的結果。所以只需要將同一個句子兩次餵給模型就可以得到兩個不同的表示。使用這種方法產生出來的相似樣本對語義完全一致,只是生成的embedding不同而已,可以認為是資料增強的最小形式。比其他的資料增強方法都要好很多。
什麼是dropout
首先我們要了解什麼是dropout。dropout在深度學習中通常被用來防止模型過擬合。dropout最初由Hinton組於2014年提出。可以看一下我之前的文章:模型泛化 | 正則化 | 權重衰退 | dropout
模型為什麼會過擬合。因為我們的資料集相較於我們的模型來說太小了。而我們的模型相較於我們的資料集來說太複雜。因此為了防止模型過擬合,我們可以使用dropout,讓模型在訓練的時候忽略一些節點。就像上圖中那樣。這樣模型在訓練資料時每次都在訓練不同的網路,模型不會太依賴某些區域性的特徵,所以模型的泛化性更強,降低了過擬合發生的概率。
dropout和其他資料增強方法進行比較
通過dropout masks機制進行資料增強構造正例的方法。
作者在STS-B資料集上進行試驗。比較dropout與其他資料增強方法的差異。
裁剪,刪除和替換等資料增強方法,效果均不如dropout masks機制,即使刪除一個詞也會損害效能,詳細如下表所示:
dropout正例與原始樣本之間採用完全相同的句子,只有在向量表徵過程中的dropout mask有所不同。可以視為一種最小形式的資料擴充。
不同的dropout rate
為了驗證模型dropout rate對無監督SimCSE的影響,作者在STS-B資料集上進行了消融實驗。從上面表格中我們可以看出當dropout rate設定為0.1的時候,模型在STS-B測試集的效果最好。
上圖中$Fixed 0.1$表示對於同一個樣本使用相同的dropout mask,也就是說編碼兩次得到的向量是一樣的,可以看到這種情況下效果是最差的。
我個人感覺$Fixed 0.1$的時候能達到40%以上已經挺好的了。畢竟在我眼裡可能會造成模型坍塌。
我還看了一下別人復現這篇論文的文章,復現的人說嘗試了0.1 0.2 0.3,效果都差不多,最後還是選擇了論文中的0.1.不。
對比學習評價指標
alignment 和 uniformity 是對比學習中比較重要的兩種屬性,可用於衡量對比學習的效果。
- alignment 計算所有正樣本對之間的距離,如果 alignment 越小,則正樣本的向量越接近,對比學習效果越好,計算公式如下: $$ \ell_{\text {align }} \triangleq \underset{\left(x, x^{+}\right) \sim p_{\text {pos }}}{\mathbb{E}}\left\|f(x)-f\left(x^{+}\right)\right\|^{2} $$
- uniformity 表示所有句子向量分佈的均勻程度,越小表示向量分佈越均勻,對比學習效果越好,計算公式如下: $$ \ell_{\text {uniform }} \triangleq \log \quad \mathbb{E}{x, y \stackrel{i . i . d .}{\sim} p{\text {data }}} e^{-2\|f(x)-f(y)\|^{2}} $$
其中$p_{data}$表示資料分佈。這兩個指標與對比學習的目標是一致的:正例之間學到的特徵應該是相近的,而任意向量的語義特徵應該儘可能地分散在超球體上。
至於這個“超球體”我認為是像InstDisc中右側這個圖一樣,將每個樣本的特徵表示對映到空間中。(個人觀點,如果理解有錯請各位指教。)
無監督
無監督的目標函式是這樣的。看一下上邊,他圖中示例是把三個句子作為輸入傳給編碼器,然後編碼器會得到對應句子的embedding。輸入兩次會得到兩次不同的embedding。一個句子和它對應增強的句子是正樣本,其餘的句子作為負樣本。最終使用的損失函式如下: $$ \ell_{i}=-\log \frac{e^{\operatorname{sim}\left(\mathbf{h}{i}^{z{i}}, \mathbf{h}{i}^{z{i}^{\prime}}\right) / \tau}}{\sum_{j=1}^{N} e^{\operatorname{sim}\left(\mathbf{h}{i}^{z{i}}, \mathbf{h}{j}^{z{j}^{\prime}}\right) / \tau}} $$
有監督
使用有監督學習的一個難點,就是要找到適合構造正負樣本的資料集。最終作者的選擇如下:
那它的正負利是如何構造的呢。 以其中的NLI資料集為例,在這個資料集中打進一個前提。就是註釋者需要手動編寫一個絕對正確的句子及蘊句子。一個可能正確的句子,中立句子。和一個絕對錯誤的句子矛盾句子。然後這篇論文就將這個資料集進行擴充套件,將原來的(句子,蘊含句子)改變為(句子,蘊含句子,矛盾句子)。在這個資料集中正樣本是這個句子及其包含蘊含關係的句子。負樣本有兩種,是這個句子包含矛盾關係的句子以及其他的句子。 損失函式如下: $$ L_{i}=-\log \frac{e^{\operatorname{sim}\left(h_{i}, h_{i}^{+}\right) / \tau}}{\sum_{j=1}^{N}\left(e^{\operatorname{sim}\left(h_{i}, h_{j}^{+}\right) / \tau}+e^{\operatorname{sim}\left(h_{i}, h_{j}^{-}\right) / \tau}\right)} $$
結果
對7個語義文字相似度(STS)任務進行了實驗,將無監督和有監督的SimCSE與STS任務中的最先進的句子嵌入方法進行了比較,可以發現,無監督和有監督的SimCSE均取得了sota的效果,具體如下表所示:
因為SimCSE做的是一個句子表徵的任務,即獲得更好的句子的embedding,實驗效果如上圖。作者使用基於BERT和基於RoBERTa的SimCSE分別與Baseline進行比較,均取得較好的效果。
下邊是SimCSE使用不同版本的BERT及其變體做出的模型,對應的模型可以直接從hugging face上獲取.
|Model |Avg. STS| |---|----| princeton-nlp/unsup-simcse-bert-base-uncased |76.25 princeton-nlp/unsup-simcse-bert-large-uncased |78.41 princeton-nlp/unsup-simcse-roberta-base |76.57 princeton-nlp/unsup-simcse-roberta-large |78.90 princeton-nlp/sup-simcse-bert-base-uncased| 81.57 princeton-nlp/sup-simcse-bert-large-uncased |82.21 princeton-nlp/sup-simcse-roberta-base |82.52 princeton-nlp/sup-simcse-roberta-large |83.76
程式碼實踐
既然它的效果這麼好,如何快捷的在電腦上使用SimCSE呢?
先安裝一下:
py
pip install simcse
用這兩行程式碼載入模型。我上面那個表格裡寫了不同的版本, SimCSE("在這裡填寫不同版本")
。
py
from simcse import SimCSE
model = SimCSE("princeton-nlp/sup-simcse-bert-base-uncased")
既然是用來做sentence embedding的,那先看一下他怎麼給句子編碼:
py
embeddings = model.encode("A woman is reading.")
它反應比較慢,你需要等一下它才會出結果。不出意外的話,它應該會給出一個特別長的embedding編碼。
我輸出一下看一下,他應該是把一個句子編碼成768維度的向量。
計算兩組句子之間的餘弦相似性:
```python sentences_a = ['A woman is reading.', 'A man is playing a guitar.'] sentences_b = ['He plays guitar.', 'A woman is making a photo.'] similarities = model.similarity(sentences_a, sentences_b)
similarities1 = model.similarity('A woman is reading.', 'A man is playing a guitar.')
similarities2 = model.similarity('He plays guitar.', 'A man is playing a guitar.')
```
除了計算句子組之間,我還放了計算兩個句子的一些相似性。最後效果顯示如下:
他還可以為那一組句子構建index,構建之後你再輸入一個句子,從其中進行查詢。他會找到和哪個句子更為相似。並且輸出相似度是多少。
python
sentences = ['A woman is reading.', 'A man is playing a guitar.']
model.build_index(sentences)
results = model.search("He plays guitar.")
在上一段程式碼中我已經計算過這兩個句子之間的相似度,我們可以看到跟上一段程式碼中的結果是一樣的。
similarities2 = model.similarity('He plays guitar.', 'A man is playing a guitar.')
的輸出結果是0.8934233..... 現在你查詢He plays guitar.
它輸出最相似的句子為A man is playing a guitar.
相似度為0.8934233.....
- 【翻譯】最近興起的擴散模型
- 深扒torch.autograd原理
- 用一個影象分類例項拿捏Pytorch使用方法
- 帶你瞭解自然語言處理文字生成方向
- 你們居然還在用負樣本做對比學習?
- 4個例子幫你梳理PyTorch的nn module
- 幾個例子幫你梳理PyTorch知識點(張量、autograd)
- SimCSE,丹琦女神把對比學習用到了NLP中了!
- 兩個視角給你解讀 熵、交叉熵、KL散度
- 你們那種對比學習是辣雞,我SwAV今天就要開啟新局面!
- “軍備競賽”時期的對比學習
- 怎麼用PyTorch實現一個Encoder-Decoder框架?
- 公式程式碼都有了,速來學LSTM 長短期記憶網路
- 【翻譯】圖解自注意力機制
- 用pytorch寫個RNN 迴圈神經網路
- 用pytorch寫個 GRU 門控迴圈單元
- 手把手教你實現 seq2seq
- 突然火起來的diffusion model是什麼?
- TensorBoard 一行程式碼實現指標視覺化
- 【翻譯】圖解transformer