文 | DeepAuto、Yann-A ë l Le Borgne
Sora 的爆火給 OpenAI 注入了一針強心劑,也讓自動駕駛行業從業者、創業者、技術達人心跳加速。DeepAuto 提出一個假設:假如 OpenAI 是智駕行業終局的通吃者,那它每一次發布的新模型都可能在下一次自動駕駛新産業革命爆發前夜帶來深遠影響。
最近,Sora 的爆火給 OpenAI 注入了一針強心劑,也讓自動駕駛行業從業者、創業者、技術達人心跳加速。DeepAuto 提出一個假設:假如 OpenAI 是智駕行業終局的通吃者,那它每一次發布的新開源模型都可能在下一次自動駕駛新産業革命爆發前夜帶來深遠影響。
最近,OpenAI 發布了新一代嵌入模型,名爲 embedding v3,他們将其描述爲性能最強的嵌入模型,具有更高的多語言性能。這些模型分爲兩類:一類較小,稱爲 text-embedding-3-small;另一類較大,功能更強大,稱爲 text-embedding-3-large。
關于這些模型的設計和訓練方法,披露的信息很少。與之前發布的嵌入模型(2022 年 12 月發布的 ada-002 模型類)一樣,OpenAI 再次選擇了閉源方法,即隻能通過付費 API 訪問模型。
但是,模型的性能是否好到值得付費呢?
此文的目的是通過實證比較這些新模型與開源模型的性能。我們将以數據檢索工作流程爲基礎,根據用戶查詢,找到語料庫中最相關的文檔。
語料庫選取的是《歐洲人工智能法案》,目前正處于最後的驗證階段。該語料庫除了是全球首個人工智能法律框架外,還有一個有趣的特點,那就是它有 24 種語言版本。這使得比較不同語系數據檢索的準确性成爲可能。
本帖将介紹以下兩個主要步驟:
從多語言本語料庫中生成自定義合成問題 / 答案數據集
比較 OpenAI 和最先進的開源嵌入模型在該自定義數據集上的準确性。
用于重現本篇文章中介紹的結果的代碼和數據可在此 Github 存儲庫中獲取。請注意,本文以《歐盟人工智能法案》爲例,所采用的方法可适用于其他數據語料庫。
生成自定義 Q/A 數據集
首先,讓我們在自定義數據上生成一個問答(Q/A)數據集,用于評估不同嵌入模型的性能。生成自定義 Q/A 數據集有兩個好處。首先,它可以确保數據集沒有參與嵌入模型的訓練,從而避免出現偏差,而在 MTEB 等參考基準上可能會出現這種情況。其次,它允許根據特定的數據語料庫進行評估,例如在檢索增強應用(RAG)的情況下,這可能是相關的。
我們将遵循 Llama Index 在其文檔中建議的簡單流程。首先将語料庫分割成一組塊。然後,通過大語言模型(LLM)爲每個語塊生成一組合成問題,使答案位于相應的語塊中。具體過程如下:
使用 LLM 數據框架(如 Llama Index)可以直接實施這一策略。語料庫的加載和文本的分割可以通過高級函數方便地完成,如下代碼所示。
從 llama_index.readers.web 導入 SimpleWebPageReader 從 llama_index.core.node_parser 導入 SentenceSplitter
語言 = "EN" url_doc = "https://eur-lex.europa.eu/legal-content/" +language+ "/TXT/HTML/? uri=CELEX:52021PC0206"
文檔 = SimpleWebPageReader ( html_to_text= True ) .load_data ( [ url_doc ] )
解析器 = SentenceSplitter ( chunk_size= 1000 ) 節點 = parser.get_nodes_from_documents ( documents, show_progress= True )
在本示例中,語料庫是歐盟人工智能法的英文版,使用的是 2021 年 4 月的草案版本,因爲最終版本尚未适用于所有歐洲語言。在該版本中,可以用歐盟其他 23 種官方語言中的任何一種替換 URL 中的英語,以檢索不同語言的文本(BG 表示保加利亞語、ES 表示西班牙語、CS 表示捷克語等)。
我們使用 SentenceSplitter 對象将文檔分割爲 1000 個标記的塊。對于英語,這會産生大約 100 個塊。
然後将每個塊作爲以下提示的上下文提供
提示 ={} 提示 [ "EN" ] = """"EN" ] = """ 上下文信息如下。
--------------------- {context_str} ------------ ---------
給定上下文信息而不是先驗知識,僅根據以下查詢生成問題。
您是教師 / 教授。您的任務是爲即将到來的測驗 / 考試設置 {num_questions_per_chunk} 個問題。整個文檔中的問題本質上應該是多樣化的。将問題限制在所提供的上下文信息範圍内。"
該提示的目的是生成與文檔分塊相關的問題,就像老師在準備即将到來的測驗一樣。我們将參數 "num_questions_per_chunk " 設爲兩個,以此來傳遞每個文檔塊要生成的問題數量。然後,可以調用 Llama 索引庫中的 generate_qa_embedding_pairs 生成問題:
from llama_index.llms import OpenAIfrom llama_index.legacy.finetuning import generate_qa_embedding_pairs
qa_dataset = generate_qa_embedding_pairs ( llm=OpenAI ( model="gpt-3.5-turbo-0125",additional_kwargs={'seed':42} ) , nodes=nodes, qa_generate_prompt_tmpl = prompts [ language ] , num_questions_per_chunk=2
我們依靠 OpenAI 的 GPT-3.5-turbo-0125 模式來完成這項任務,根據 OpenAI 的說法,該模式是該系列的旗艦模式,支持 16K 上下文窗口,并針對對話進行了優化
生成的對象 "qa_dataset " 包含問題和答案(塊)對。以生成的問題爲例,下面是前兩個問題(" 答案 " 是第一個文本塊)的結果:
1 ) 根據解釋性備忘錄,制定人工智能統一規則的條例提案(人工智能法)的主要目标是什麽?
2 ) 如背景信息中所述,關于人工智能的條例提案旨在如何解決與使用人工智能相關的風險,同時促進人工智能在歐盟的應用?
大塊内容和問題的數量取決于語言,從英語的約 100 個大塊内容和 200 個問題,到匈牙利語的 200 個大塊内容和 400 個問題不等。
OpenAI 嵌入模型的評估
我們的評估功能遵循 Llama Index 文檔,包括兩個主要步驟。首先,将所有答案(文檔塊)的嵌入存儲在 VectorStoreIndex 中,以便高效檢索。然後,評估功能在所有查詢中循環,檢索前 k 個最相似的文檔,并以 MRR(平均互易等級)評估檢索的準确性。
def evaluate ( dataset, embed_model, insert_batch_size=1000, top_k=5 ) : # Get corpus, queries, and relevant documents from the qa_dataset object corpus = dataset.corpus queries = dataset.queries relevant_docs = dataset.relevant_docs
# Create TextNode objects for each document in the corpus and create a VectorStoreIndex to efficiently store and retrieve embeddings nodes = [ TextNode ( id_=id_, text=text ) for id_, text in corpus.items ( ) ] index = VectorStoreIndex ( nodes, embed_model=embed_model, insert_batch_size=insert_batch_size ) retriever = index.as_retriever ( similarity_top_k=top_k )
# Prepare to collect evaluation results eval_results = [ ]
# Iterate over each query in the dataset to evaluate retrieval performance for query_id, query in tqdm ( queries.items ( ) ) : # Retrieve the top_k most similar documents for the current query and extract the IDs of the retrieved documents retrieved_nodes = retriever.retrieve ( query ) retrieved_ids = [ node.node.node_id for node in retrieved_nodes ]
# Check if the expected document was among the retrieved documents expected_id = relevant_docs [ query_id ] [ 0 ] is_hit = expected_id in retrieved_ids # assume 1 relevant doc per query
# Calculate the Mean Reciprocal Rank ( MRR ) and append to results if is_hit: rank = retrieved_ids.index ( expected_id ) + 1 mrr = 1 / rank else: mrr = 0 eval_results.append ( mrr )
# Return the average MRR across all queries as the final evaluation metric return np.average ( eval_results )
嵌入模型通過 "embed_model " 參數傳遞給評估函數,對于 OpenAI 模型來說,"embed_model " 參數是一個用模型名稱和模型維度初始化的 OpenAIEmbedding 對象。
from llama_index.embeddings.openai import OpenAIEmbedding
embed_model = OpenAIEmbedding ( model=model_spec [ 'model_name' ] , dimensions=model_spec [ 'dimensions' ] )
在四種不同的 OpenAI 嵌入模型上運行了評估功能:
兩個版本的文本嵌入 -3-large:一個是最小維度(256),另一個是最大維度(3072)。這兩個版本分别稱爲 "OAI-large-256 " 和 "OAI-large-3072"。
OAI-small:文本嵌入 -3-small 嵌入模型,維度爲 1536。
OAI-ada-002: 傳統文本嵌入 -ada-002 模型,維度爲 1536。
每個模型都在四種不同的語言上進行了評估:英語 ( EN ) 、法語 ( FR ) 、捷克語 ( CS ) 和匈牙利語 ( HU ) ,分别涵蓋日耳曼語、羅曼語、斯拉夫語和烏拉爾語的例子。
embeddings_model_spec = { }
embeddings_model_spec [ 'OAI-Large-256' ] ={'model_name':'text-embedding-3-large','dimensions':256}'OAI-Large-256' ] ={ 'model_name':'text-embedding-3-large' , 'dimensions':256 } embeddings_model_spec [ 'OAI-Large-3072' ] ={ 'model_name':' 文本嵌入 -3-large',' 尺寸 ':3072 } embeddings_model_spec [ 'OAI-Small' ] ={ 'model_name':'text-embedding-3-small',' 尺寸 ':1536 } embeddings_model_spec [ 'OAI-ada-002 ' ] ={ 'model_name' : 'text-embedding-ada-002' , 'dimensions' : None }
results = [ ]
languages = [ "EN" , "FR" , "CS" , "HU" ]
# 循環 all languages for language in languages:
# 加載數據集 file_name=language+ "_dataset.json" qa_dataset = EmbeddingQAFinetuneDataset.from_json ( file_name )
# 循環遍曆所有模型 for model_name, model_spec in embeddings_model_spec.items ( ) :
# 獲取模型 embed_model = OpenAIEmbedding ( model ) =model_spec [ 'model_name' ] , dimensions=model_spec [ 'dimensions' ] )
# 評估嵌入分數(以 MRR 爲單位) Score =valuate ( qa_dataset, embed_model )
results.append ( [ language, model_name, Score ] )
df_results = pd .DataFrame ( 結果 , columns = [ " 語言 " , " 嵌入模型 " , "MRR" ] )
由此得出的 MRR 精确度報告如下:
不出所料,對于大型模型來說,3072 的較大嵌入尺寸會帶來更好的性能。不過,與小型模型和傳統 Ada 模型相比,大型模型的嵌入尺寸要小于我們的預期。爲了進行比較,我們還在下文中報告了 OpenAI 模型在 MTEB 基準測試中的表現。
值得注意的是,在我們的評估中,大型模型、小型模型和 Ada 模型之間的性能差異遠沒有 MTEB 基準那麽明顯,這反映了一個事實,即在大型基準中觀察到的平均性能并不一定反映在定制數據集上獲得的性能。
開源嵌入模型的評估
爲了在本文中進行比較,我們選擇了一組最近(2024 年)發布的四個嵌入模型。選擇的标準是它們在 MTEB 排行榜上的平均得分及其處理多語言數據的能力。所選模型的主要特點概述如下。
E5-Mistral-7B-instruct ( E5-mistral-7b ) :微軟的這一 E5 嵌入模型由 Mistral-7B-v0.1 初始化,并在混合多語言數據集上進行了微調。該模型在 MTEB 排行榜上表現最佳,但也是迄今爲止最大的模型(14GB)。
multilingual-E5-large-instruct(ML-E5-large): 微軟的另一個 E5 模型,旨在更好地處理多語言數據。它由 xlm-roberta-large 初始化,并在多語言數據集的混合物上進行訓練。它比 E5-Mistral 小得多(10 倍),但上下文大小(514)也小得多。
BGE-M3 該模型由北京人工智能學會設計,是其最先進的多語言數據嵌入模型,支持 100 多種工作語言。截至 2024 年 2 月 22 日,該模型尚未在 MTEB 排行榜上進行基準測試。
nomic-embed-text-v1(Nomic-Embed):該模型由 Nomic 設計,聲稱性能優于 OpenAI Ada-002 和 text-embedding-3-small,但大小僅爲 0.55GB。有趣的是,該模型是第一個完全可重複和可審計的模型(開放數據和開源訓練代碼)。
評估這些開源模型的代碼與用于 OpenAI 模型的代碼相似。主要變化在于模型規格,其中必須指定諸如最大上下文長度和池類型等額外細節。然後,我們分别對四種語言中的每種模型進行評估:
embeddings_model_spec = { }
embeddings_model_spec [ 'E5-mistral-7b' ] ={'model_name':'intfloat/e5-mistral-7b-instruct','max_length':32768, 'pooling_type':'last_token', ' 标準化 ''E5-mistral-7b' ] ={ 'model_name' : 'intfloat/e5-mistral-7b-instruct' , 'max_length' : 32768 , 'pooling_type' : 'last_token' , 'normalize' : True , 'batch_size' : 1 , 'kwargs' : { 'load_in_4bit' : True , 'bnb_4bit_compute_dtype' :torch.float16}} embeddings_model_spec [ 'ML-E5-large' ] ={ 'model_name' : 'intfloat/multilingual-e5-large' , 'max_length ':512、'pooling_type':'mean'、 'normalize':True、'batch_size':1、'kwargs':{ 'device_map':'cuda'、'torch_dtype':torch.float16}} embeddings_model_spec [ 'BGE -M3' ] ={ 'model_name' : 'BAAI/bge-m3' , 'max_length' : 8192 , 'pooling_type' : 'cls' , 'normalize' : True , 'batch_size' : 1 , 'kwargs' : { ' device_map' : 'cuda' , 'torch_dtype' :torch.float16}} embeddings_model_spec [ 'Nomic-Embed' ] ={ 'model_name' : 'nomic-ai/nomic-embed-text-v1' , 'max_length' : 8192 , 'pooling_type' : 'mean' , 'normalize' : True , 'batch_size' : 1 , 'kwargs' : { 'device_map' : 'cuda' , 'trust_remote_code' : True }}
結果 = [ ]
languages = [ "EN"、"FR"、"CS"、"HU" ]
# 循環遍曆所有模型 for model_name, model_spec in embeddings_model_spec.items ( ) :
print ( " 處理模型 : " + str ( model_spec ) )
# 獲取模型 tokenizer = AutoTokenizer.from_pretrained ( model_spec [ 'model_name' ] ) embed_model = AutoModel.from_pretrained ( model_spec [ 'model_name' ] , **model_spec [ 'kwargs' ] )
if model_name== "Nomic-Embed" : embed_model.to ( ' cuda' )
# 循環遍曆所有語言 for language in languages:
# 加載數據集 file_name=language+ "_dataset.json" qa_dataset = EmbeddingQAFinetuneDataset.from_json ( file_name )
start_time_assessment=time.time ( )
# 評估嵌入得分(以命中率計) k=5 ) Score =valu ( qa_dataset, tokenizer, embed_model, model_spec [ 'normalize' ] , model_spec [ 'max_length' ] , model_spec [ 'pooling_type' ] )
# 獲取評分評估時長 uration_assessment = time.time ( ) -start_time_assessment
results.append ( [ 語言、模型名稱、分數、持續時間評估 ] )
由此得出的 MRR 精确度報告如下。
結果表明,BGE-M3 的性能最好,其次是 ML-E5-Large、E5-mistral-7b 和 Nomic-Embed。BGE-M3 模型尚未在 MTEB 排行榜上進行基準測試,我們的結果表明,它的排名可能會高于其他模型。值得注意的是,雖然 BGE-M3 針對多語言數據進行了優化,但它在英語方面的表現也優于其他模型。
我們還在下面報告了每種嵌入模型的處理時間。
E5-mistral-7b 比其他型号大 10 多倍,毫無疑問是迄今爲止速度最慢的型号。
結論
讓我們将八個測試模型的性能并排放在一個圖中。
從這些結果中可以看出 :
開源模型表現最佳。北京人工智能學會開發的 BGE-M3 模型表現最佳。該模型的上下文長度與 OpenAI 模型相同(8K),大小爲 2.2GB。
OpenAI 範圍内的一緻性。大型(3072)、小型和傳統 OpenAI 模型的性能非常相似。然而,減少大型模型的嵌入大小(256)會導緻性能下降。
語言敏感性。幾乎所有模型(ML-E5-large 模型除外)在英語中的表現都最好。在捷克語和匈牙利語等語言中的表現則有顯著差異。
因此,選擇付費訂閱 OpenAI 還是托管開源嵌入模型,相信你已經有答案。
此外,OpenAI 最近的價格調整使訪問其 API 的費用也在大大降低,目前爲每百萬代币 0.13 美元。因此,每月處理 100 萬次查詢(假設每次查詢涉及約 1K 個代币)的成本約爲 130 美元。因此,根據每個人不同的使用情況,租用和維護自己的嵌入式服務器可能并不劃算。
不過,成本效益并不是唯一的考慮因素。還需要考慮其他因素,如延遲、隐私和對數據處理工作流程的控制。開源模式具有完全數據控制、提高隐私性和定制化的優勢。另一方面,OpenAI 的應用程序接口也存在延遲問題,有時會導緻響應時間延長。
總之,在開源模型和 OpenAI 等專有解決方案之間做出選擇,并不是一個簡單的答案。開源嵌入式提供了一個令人信服的選擇,它将性能與對數據的更大控制相結合。相反,OpenAI 的産品可能仍然會吸引那些優先考慮便利性的用戶,尤其是在隐私問題處于次要地位的情況下。
( Reference:https://towardsdatascience.com/openai-vs-open-source-multilingual-embedding-models-e5ccb7c90f05)