GPT-3 vs Bert vs GloVe vs Word2vec 文本嵌入技術(shù)的性能對比測試
2022年1月25日,OpenAI公布了一個embedding endpoint(Neelakantan et al., 2022)。該神經(jīng)網(wǎng)絡(luò)模型將文本和代碼轉(zhuǎn)換為向量表示,將它們嵌入到高維空間中。這些模型可以捕獲文本的語義相似性,并且在某些用例中似乎實現(xiàn)了最先進的性能。
由于chatgpt的大火,GPT-3又進入到了人們的視野中,本文將通過使用text-embedding-ada-002(GPT-3的一個Embeddings,選擇該模型是因為它價格適中且使用簡單),與三種傳統(tǒng)文本嵌入技術(shù)生成的嵌入的性能進行比較;GloVe(Pennington、Socher Manning,2014 年)、Word2vec(Mikolov ,2013 年)和 MPNet(Song ,2020 年)。這些嵌入將用于訓(xùn)練多個機器學(xué)習(xí)模型,使用Amazon美食評論數(shù)據(jù)集中的食品評論評分進行分類。每種嵌入技術(shù)的性能將通過比較它們的準確性指標(biāo)來評估。
本文中使用的數(shù)據(jù)集是來自Amazon美食評論數(shù)據(jù)集的1000個數(shù)據(jù)集的子集。這個子集包含了使用GPT-3的“text- embedded -ada-002”模型已經(jīng)生成的嵌入。嵌入是由標(biāo)題(摘要)和文本的組合生成的。如圖1所示,每個評論還具有ProductId、UserId、Score和從組合文本生成的令牌數(shù)量。
# Libraries from sentence_transformers import SentenceTransformer from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report from sklearn.tree import DecisionTreeClassifier from sklearn.preprocessing import RobustScaler from sklearn.pipeline import Pipeline import gensim.downloader as api from sklearn.svm import SVC import pandas as pd import numpy as np import openai import re
# import data df1 = pd.read_csv('https://raw.githubusercontent.com/openai/openai-cookbook/main/examples/data/fine_food_reviews_with_embeddings_1k.csv', index_col=0)
# view first three rows df1.head(3)
對于換行符和空格會影響我們將嵌入表示為數(shù)組。所以需要一個函數(shù)來刪除不必要的字符并將嵌入轉(zhuǎn)換為適當(dāng)?shù)臄?shù)組格式。GPT-3嵌入變量的名稱也將更改為' gpt_3 ',這樣可以區(qū)別本文后面生成的其他嵌入。
# clean openai embeddings def clean_emb(text):
# remove line break text = re.sub(r'\n', '', text)
# remove square brackets text = re.sub(r'\[|\]', "", text)
# remove leading and trailing white spaces text = text.strip()
# convert string into array text = np.fromstring(text, dtype=float, sep=',')
return text
# Rename column to gpt_3 df1.rename(columns={'embedding': 'gpt_3'}, inplace=True)
# Apply clean_emb function df1['gpt_3'] = df1['gpt_3'].apply(lambda x: clean_emb(x))
數(shù)據(jù)集包含預(yù)先生成的基于gpt -3的嵌入。但是我們?yōu)榱松勺钚碌那度?,還需要一個API密鑰來訪問模型。該密鑰可以通過注冊O(shè)penAI API來獲得。然后就是創(chuàng)建一個函數(shù),指定要使用的模型(在本例中為text-embedding-ada-002)。
api_key = 'api key'
# set api key as default api key for openai openai.api_key = api_key
def get_embedding(text, model="text-embedding-ada-002"):
# replace new lines with spaces text = text.replace("\n", " ")
# openai.Embedding.create to convert text into embedding array return openai.Embedding.create(input = [text], model=model)['data'][0]['embedding']
因為都是獲取API的返回結(jié)果,所以這個過程非常簡單。
GloVe(用于詞表示的全局向量)是一種文本嵌入技術(shù),它根據(jù)詞在大量文本中的共現(xiàn)統(tǒng)計來構(gòu)建詞的向量表示。GloVe 的想法是,在可比較的情況下出現(xiàn)的詞在語義上是相關(guān)的,并且可以使用通過共現(xiàn)矩陣統(tǒng)計它們的共現(xiàn)來推斷這些詞之間的聯(lián)系。
使用 spaCy 庫可以輕松的生成基于 GloVe 的嵌入。這里我們使用“en_core_web_lg”英語管道。該管道對給定的文本輸入執(zhí)行一系列步驟,例如標(biāo)記化、標(biāo)記和詞形還原,以將其轉(zhuǎn)換為合適的格式。該管道包含 514,000 個向量,對于當(dāng)前的用例來說已經(jīng)足夠大了。
GloVe是14年發(fā)布的,雖然到現(xiàn)在都快10年了,但是在transformers出現(xiàn)之前GloVe可以說是最成功的詞嵌入方法,所以這里我們還是要拿他來進行以下對比。
import spacy # load pipeline nlp = spacy.load("en_core_web_lg")
這里我們也需要進行文本清理。如上圖 2 所示,在第一個文本輸入中連續(xù)出現(xiàn)了一些句號。這種模式必須加以糾正。
df1.combined[0]
我們創(chuàng)建一個函數(shù),用單個句號替換連續(xù)的句號,并刪除句子末尾的空格。
def replace_multiple_fullstops(text):
# replace 2 or more consecutive fullstops with 1 text = re.sub(r'\.{2,}', '.', text)
# strip white spaces from ends of sentence text= text.strip()
return text
# Apply function df1['clean_text'] = df1['combined'].apply(lambda x: replace_multiple_fullstops(x))
然后就可以在清理過程之后生成嵌入。
df1['glove'] = df1['clean_text'].apply(lambda text: nlp(text).vector)
Word2vec嵌入
word2vec技術(shù)是基于一個經(jīng)過大量文本訓(xùn)練的神經(jīng)網(wǎng)絡(luò)模型,從其周圍的上下文單詞中預(yù)測目標(biāo)單詞。Word2vec的工作原理是用一個連續(xù)向量來表示詞匯表中的每個單詞,該向量捕獲了使用該單詞的含義和上下文。這些向量是通過無監(jiān)督學(xué)習(xí)過程生成的,神經(jīng)網(wǎng)絡(luò)模型嘗試預(yù)測給定上下的單詞。
Gensim庫可用于加載在word2vec技術(shù)上訓(xùn)練的模型。Gensim庫中的“word2vic - Google - News -300”模型是在谷歌News數(shù)據(jù)集上訓(xùn)練的,該數(shù)據(jù)集約有1000億個單詞,能夠表示數(shù)據(jù)集中的大部分單詞。
import gensim.downloader as api
# Load word2vec-google-news-300 model wv = api.load("word2vec-google-news-300")
因為Gensim庫提供的是模型而不是管道,所以在使用word2vec模型生成向量表示之前,還需要使用spaCy庫對文本輸入進行標(biāo)記化、清理和lemm化。
def wv_preprocess_and_vectorize(text): # Process the input text using a natural language processing library doc = nlp(text)
# Initialize a list to store the filtered tokens filtered_tokens = []
# Loop through each token in the doc for token in doc: # If the token is a stop word or punctuation, skip it if token.is_stop or token.is_punct: continue # Otherwise, add the lemma of the token to the filtered_tokens list filtered_tokens.append(token.lemma_)
# If there are no filtered tokens, return np.nan if not filtered_tokens: return np.nan else: # Otherwise, return the mean vector representation of the filtered tokens return wv.get_mean_vector(filtered_tokens)
# Apply function df1['word2vec'] = df1['clean_text'].apply(lambda text: wv_preprocess_and_vectorize(text))
MPNet(Masked and Permuted Language Model Pre-training)是一種用于NLP的基于transformer的語言模型預(yù)訓(xùn)練技術(shù)。MPNet提供了BERT模型的變體。BERT在預(yù)訓(xùn)練期間屏蔽一部分輸入令牌,并訓(xùn)練模型根據(jù)未屏蔽令牌的上下文預(yù)測已屏蔽令牌。這個過程被稱為掩碼語言建模,它對于捕獲文本語料庫中單詞的含義和上下文是有效的。
除了屏蔽語言建模之外,MPNet還采用了一種隨機排列輸入標(biāo)記順序的排列機制。這種排列有助于模型學(xué)習(xí)輸入序列中單詞之間的全局上下文和關(guān)系。
我們這里使用hug Face的句子轉(zhuǎn)換模型“all-mpnet-base-v2”來獲取基于mpnet的嵌入。該模型建立在MPNet基礎(chǔ)模型的基礎(chǔ)上,并對10億句對數(shù)據(jù)集進行微調(diào)。
model_sent = SentenceTransformer('all-mpnet-base-v2') df1['mpnet'] = df1['clean_text'].apply(lambda text: model_sent.encode(text))
維度比較
下圖3顯示了每種嵌入的不同維度。GPT-3的最大維度為1536。然后是MPNet、Word2vec和GloVe,分別為768、300和300維。
# assign data of lists. data = {'Name': ['gpt_3', 'mpnet', 'word2vec', 'glove'], 'Dimension': [len(df1.gpt_3[0]), len(df1.mpnet[0]), len(df1.word2vec[0]), len(df1.glove[0])]}
# Create DataFrame df_emb_len = pd.DataFrame(data)
# Set background style df_emb_len.style.background_gradient()
為了評估文本嵌入的性能,我們使用了四個分類器;隨機森林、支持向量機、邏輯回歸和決策樹對Score變量進行預(yù)測。數(shù)據(jù)集將被分成75:25的訓(xùn)練與測試集來評估準確性。由于嵌入是二維的,因此在訓(xùn)練之前將使用numpy函數(shù)將它們轉(zhuǎn)換為單個三維數(shù)組。
# Define a list of embedding methods to evaluate embedding_var= ['gpt_3', 'mpnet', 'word2vec', 'glove']
# Define a list of classifier models to use classifiers = [('rf', RandomForestClassifier(random_state=76)), ('svm', SVC(random_state=76)), ('lr', LogisticRegression(random_state=76, max_iter=400)), ('dt', DecisionTreeClassifier(random_state=76))]
# Define a dictionary to store accuracy results for each classifier accuracy_lists = { 'rf': [], 'svm': [], 'lr': [], 'dt': [] }
# Loop through each embedding method for emb in embedding_var:
# Split the data into training and testing sets using the 'train_test_split' function X_train, X_test, y_train, y_test = train_test_split( df1[emb].values, df1.Score, test_size=0.25, random_state=76 )
# Stack the training and testing sets into 3D arrays X_train_stacked = np.stack(X_train) X_test_stacked = np.stack(X_test)
# Loop through each classifier model for classifier_name, classifier in classifiers:
# Create a pipeline that scales the data and fits the classifier pipe = Pipeline([('scaler', RobustScaler()), (classifier_name, classifier)]) pipe.fit(X_train_stacked, y_train)
# Use the pipeline to make predictions on the test data y_pred = pipe.predict(X_test_stacked)
# Evaluate the accuracy of the predictions report = classification_report(y_test, y_pred ,output_dict=True) acc = report['accuracy']
# Store the accuracy results for each classifier accuracy_lists[classifier_name].append(acc)
下圖4所示,模型呈現(xiàn)了一些有趣的結(jié)果。GPT-3嵌入在所有模型中獲得了最高的精度。
MPNet嵌入在使用邏輯回歸和支持向量機時表現(xiàn)次之,但在隨機森林算法中被word2vec嵌入超越,在決策樹算法中表現(xiàn)最差。關(guān)于維數(shù)對模型性能的影響,還不能得出明確的結(jié)論,但是從結(jié)果中可以明顯看出,GPT-3嵌入始終優(yōu)于所有其他嵌入,顯示了其在文本分類方面的優(yōu)勢。
# Add a new key 'embeddings' to the dictionary 'accuracy_lists' and assign the list 'embedding_var' to it accuracy_lists['embeddings'] = embedding_var # Create a list of tuples using the values from the dictionaries df_zip = list(zip(accuracy_lists['embeddings'], accuracy_lists['lr'], accuracy_lists['svm'], accuracy_lists['rf'], accuracy_lists['dt'])) # Create a DataFrame 'df_accuracy' from the list 'df_zip' and specify the column names df_accuracy = pd.DataFrame(df_zip, columns = ['Embedding','Logistic_Regression','Support_Vector_Machine', 'Random_Forest','Decision_Tree']) # Add a background gradient to the DataFrame for visual representation df_accuracy.style.background_gradient()
所以還是那句話"別問,問就是GPT3"
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。