选择最适合数据的嵌入模型:OpenAI 和开源多语言嵌入的对比测试

本文涉及的产品
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
简介: OpenAI最近发布了他们的新一代嵌入模型*embedding v3*,他们将其描述为性能最好的嵌入模型,具有更高的多语言性能。这些模型分为两类:较小的称为text- embeddings -3-small,较大且功能更强大的称为text- embeddings -3-large。

这些模型的设计和训练方式的信息披露得很少,模型只能通过付费API访问。所以就出现了很多开源的嵌入模型但是这些开源的模型与OpenAI闭源模型相比如何呢?

本文将这些新模型与开源模型的性能进行实证比较。我们将创建一个数据检索工作流,在这个工作流中,必须根据用户查询找到语料库中最相关的文档。

我们的语料库是欧洲人工智能法案,该法案目前处于验证的最后阶段。这个语料库除了是世界上第一个关于人工智能的法律框架外,还有一个重要的特点就是它有24种语言版本。这样我们可以比较不同语系的数据检索的准确性。

我们将从多语言文本语料库生成自定义合成问题/答案数据集,在此自定义数据集上比较OpenAI和最先进的开源嵌入模型的准确性。最后会提供完整的代码,因为本文所采用的方法可以适用于其他数据语料库。

生成自定义Q/ A数据集

让我们首先从生成自定义数据的问答(Q/ A)数据集开始,生成自定义数据集的好处可以通过确保数据集不是嵌入模型训练的一部分来避免偏差,这可能发生在MTEB等参考基准上。并且我们可以将评估调整为特定的数据语料库,这可能与检索增强应用程序(RAG)等情况相关。

我们将使用Llama Index在其文档中建议的简单流程。语料库首先被分成块。然后对于每个分块,通过大型语言模型(large language model, LLM)生成一组合成问题,使答案位于相应的分块中:

使用Llama Index之类的LLM数据框架实现此策略非常简单,如下面的代码所示。

 from llama_index.readers.web import SimpleWebPageReader
 from llama_index.core.node_parser import SentenceSplitter

 language = "EN"
 url_doc = "https://eur-lex.europa.eu/legal-content/"+language+"/TXT/HTML/?uri=CELEX:52021PC0206"

 documents = SimpleWebPageReader(html_to_text=True).load_data([url_doc])

 parser = SentenceSplitter(chunk_size=1000)
 nodes = parser.get_nodes_from_documents(documents, show_progress=True)

语料库是欧盟人工智能法案的英文版本,使用这个官方URL直接从Web上获取。本文使用2021年4月的草案版本,因为最终版本尚未适用于所有欧洲语言。所以我们选择的这一版可以用其他23种欧盟官方语言中的任何一种语言替换URL中的language,检索不同语言的文本(BG表示保加利亚语,ES表示西班牙语,CS表示捷克语,等等)。

使用SentenceSplitter对象将文档分成每1000个令牌的块。对于英语来说,这会生成大约100个块。然后将每个块作为上下文提供给以下提示(Llama Index库中建议的默认提示):

 prompts={}
 prompts["EN"] = """\
 Context information is below.

 ---------------------
 {context_str}
 ---------------------

 Given the context information and not prior knowledge, generate only questions based on the below query.

 You are a Teacher/ Professor. Your task is to setup {num_questions_per_chunk} questions for an upcoming quiz/examination.
 The questions should be diverse in nature across the document. Restrict the questions to the context information provided."
 """

这个提示可以生成关于文档块的问题,要为每个数据块生成的问题数量作为参数“num_questions_per_chunk”传递,我们将其设置为2。然后可以通过调用Llama Index库中的generate_qa_embedding_pairs来生成问题:

 from llama_index.llms import OpenAI
 from 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来完成这项任务,结果对象' qa_dataset '包含问题和答案(块)对。作为生成问题的示例,以下是前两个问题的结果(其中“答案”是文本的第一部分):

  1. What are the main objectives of the proposal for a Regulation laying down harmonised rules on artificial intelligence (Artificial Intelligence Act) according to the explanatory memorandum?
  2. How does the proposal for a Regulation on artificial intelligence aim to address the risks associated with the use of AI while promoting the uptake of AI in the European Union, as outlined in the context information?

OpenAI嵌入模型

评估函数也是遵循Llama Index文档:首先所有答案(文档块)的嵌入都存储在VectorStoreIndex中,以便有效检索。然后评估函数循环遍历所有查询,检索前k个最相似的文档,并根据MRR (Mean Reciprocal Rank)评估检索的准确性,代码如下:

 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模型,该参数是一个用模型名称和模型维度初始化的OpenAIEmbedding对象。

 from llama_index.embeddings.openai import OpenAIEmbedding

 embed_model = OpenAIEmbedding(model=model_spec['model_name'],
                               dimensions=model_spec['dimensions'])

dimensions参数可以缩短嵌入(即从序列的末尾删除一些数字),而不会失去嵌入的概念表示属性。OpenAI在他们的公告中建议,在MTEB基准测试中,嵌入可以缩短到256大小,同时仍然优于未缩短的text-embedding-ada-002嵌入(大小为1536)。

我们在四种不同的嵌入模型上运行评估函数:

两个版本的text-embedding-3-large:一个具有最低可能维度(256),另一个具有最高可能维度(3072)。它们被称为“OAI-large-256”和“OAI-large-3072”。

OAI-small:text-embedding-3-small,维数为1536。

OAI-ada-002:传统的文本嵌入text-embedding-ada-002,维度为1536。

每个模型在四种不同的语言上进行评估:英语(EN),法语(FR),捷克语(CS)和匈牙利语(HU),分别涵盖日耳曼语,罗曼语,斯拉夫语和乌拉尔语的例子。

 embeddings_model_spec = {
 }

 embeddings_model_spec['OAI-Large-256']={'model_name':'text-embedding-3-large','dimensions':256}
 embeddings_model_spec['OAI-Large-3072']={'model_name':'text-embedding-3-large','dimensions':3072}
 embeddings_model_spec['OAI-Small']={'model_name':'text-embedding-3-small','dimensions':1536}
 embeddings_model_spec['OAI-ada-002']={'model_name':'text-embedding-ada-002','dimensions':None}

 results = []

 languages = ["EN", "FR", "CS", "HU"]

 # Loop through all languages
 for language in languages:

     # Load dataset
     file_name=language+"_dataset.json"
     qa_dataset = EmbeddingQAFinetuneDataset.from_json(file_name)

     # Loop through all models
     for model_name, model_spec in embeddings_model_spec.items():

         # Get model
         embed_model = OpenAIEmbedding(model=model_spec['model_name'],
                                       dimensions=model_spec['dimensions'])

         # Assess embedding score (in terms of MRR)
         score = evaluate(qa_dataset, embed_model)

         results.append([language, model_name, score])

 df_results = pd.DataFrame(results, columns = ["Language" ,"Embedding model", "MRR"])

MRR精度如下:

嵌入尺寸越大,性能越好。

开源嵌入模型

围绕嵌入的开源研究也是非常活跃的,Hugging Face 的 MTEB leaderboard会经常发布最新的嵌入模型。

为了在本文中进行比较,我们选择了一组最近发表的四个嵌入模型(2024)。选择的标准是他们在MTEB排行榜上的平均得分和他们处理多语言数据的能力。所选模型的主要特性摘要如下。

e5-mistral-7b-instruct:微软的这个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', 
                                         '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}}

 results = []

 languages = ["EN", "FR", "CS", "HU"]

 # Loop through all models
 for model_name, model_spec in embeddings_model_spec.items():

     print("Processing model : "+str(model_spec))

     # Get model
     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')

     # Loop through all languages
     for language in languages:

         # Load dataset
         file_name=language+"_dataset.json"
         qa_dataset = EmbeddingQAFinetuneDataset.from_json(file_name)

         start_time_assessment=time.time()

         # Assess embedding score (in terms of hit rate at k=5)
         score = evaluate(qa_dataset, tokenizer, embed_model, model_spec['normalize'], model_spec['max_length'], model_spec['pooling_type'])

         # Get duration of score assessment
         duration_assessment = time.time()-start_time_assessment

         results.append([language, model_name, score, duration_assessment])

 df_results = pd.DataFrame(results, columns = ["Language" ,"Embedding model", "MRR", "Duration"])

结果如下:

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的large(3072)、small 和ada模型的性能非常相似。减小large的嵌入尺寸(256)会导致性能下降,并且没有像OpenAI说的那样比ada更好。

几乎所有型号(ML-E5-large除外)在英语上都表现最好。在捷克语和匈牙利语等语言中,表现存在显著差异,这可能是因为训练的数据比较少。

我们应该付费订阅OpenAI,还是托管一个开源嵌入模型?

OpenAI最近的价格调整使得他们的API变得更加实惠,现在每百万令牌的成本为0.13美元。如果每月处理一百万个查询(假设每个查询涉及大约1K令牌),没那么成本约为130美元。所以可以根据实际需要计算来选择是否托管开源嵌入模型。

当然成本效益并不是唯一的考虑因素。可能还需要考虑延迟、隐私和对数据处理工作流的控制等其他因素。开源模型提供了完全数据控制的优势,增强了隐私性和定制性。

说到延迟,OpenAI的API也存在延迟问题,有时会导致响应时间延长,所有有时候OpenAI的API不一定是最快的选择。

总之,在开源模型和像OpenAI这样的专有解决方案之间做出选择并不是一个简单的答案。开源嵌入提供了一个非常好的可选项,它将性能与对数据的更好控制结合在一起。而OpenAI的产品可能仍然会吸引那些优先考虑便利性的人,特别是如果隐私问题是次要的。

本文代码:https://avoid.overfit.cn/post/722aa2145139453aaf692c147d06b3c8

作者:Yann-Aël Le Borgne

目录
相关文章
|
1月前
|
机器学习/深度学习 人工智能 并行计算
"震撼!CLIP模型:OpenAI的跨模态奇迹,让图像与文字共舞,解锁AI理解新纪元!"
【10月更文挑战第14天】CLIP是由OpenAI在2021年推出的一种图像和文本联合表示学习模型,通过对比学习方法预训练,能有效理解图像与文本的关系。该模型由图像编码器和文本编码器组成,分别处理图像和文本数据,通过共享向量空间实现信息融合。CLIP利用大规模图像-文本对数据集进行训练,能够实现zero-shot图像分类、文本-图像检索等多种任务,展现出强大的跨模态理解能力。
87 2
|
21天前
|
编解码 人工智能 自然语言处理
迈向多语言医疗大模型:大规模预训练语料、开源模型与全面基准测试
【10月更文挑战第23天】Oryx 是一种新型多模态架构,能够灵活处理各种分辨率的图像和视频数据,无需标准化。其核心创新包括任意分辨率编码和动态压缩器模块,适用于从微小图标到长时间视频的多种应用场景。Oryx 在长上下文检索和空间感知数据方面表现出色,并且已开源,为多模态研究提供了强大工具。然而,选择合适的分辨率和压缩率仍需谨慎,以平衡处理效率和识别精度。论文地址:https://www.nature.com/articles/s41467-024-52417-z
41 2
|
7天前
|
开发框架 安全 .NET
.NET使用Moq开源模拟库简化单元测试
.NET使用Moq开源模拟库简化单元测试~
|
1月前
|
人工智能 自然语言处理 安全
【通义】AI视界|Adobe推出文生视频AI模型,迎战OpenAI和Meta
本文精选了过去24小时内的重要科技新闻,包括微软人工智能副总裁跳槽至OpenAI、Adobe推出文本生成视频的AI模型、Meta取消高端头显转而开发超轻量设备、谷歌与核能公司合作为数据中心供电,以及英伟达股价创下新高,市值接近3.4万亿美元。这些动态展示了科技行业的快速发展和激烈竞争。点击链接或扫描二维码获取更多资讯。
|
1月前
|
测试技术
谈谈【软件测试的基础知识,基础模型】
谈谈【软件测试的基础知识,基础模型】
27 5
|
16天前
|
NoSQL 测试技术 Go
自动化测试在 Go 开源库中的应用与实践
本文介绍了 Go 语言的自动化测试及其在 `go mongox` 库中的实践。Go 语言通过 `testing` 库和 `go test` 命令提供了简洁高效的测试框架,支持单元测试、集成测试和基准测试。`go mongox` 库通过单元测试和集成测试确保与 MongoDB 交互的正确性和稳定性,使用 Docker Compose 快速搭建测试环境。文章还探讨了表驱动测试、覆盖率检查和 Mock 工具的使用,强调了自动化测试在开源库中的重要性。
|
1月前
|
API
2024-05-14 最新!OpenAI 新模型 GPT-4 omni 简单测试,4o速度确实非常快!而且很便宜!
2024-05-14 最新!OpenAI 新模型 GPT-4 omni 简单测试,4o速度确实非常快!而且很便宜!
41 0
|
9天前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
39 3
|
1月前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
59 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
2月前
|
移动开发 JSON Java
Jmeter实现WebSocket协议的接口测试方法
WebSocket协议是HTML5的一种新协议,实现了浏览器与服务器之间的全双工通信。通过简单的握手动作,双方可直接传输数据。其优势包括极小的头部开销和服务器推送功能。使用JMeter进行WebSocket接口和性能测试时,需安装特定插件并配置相关参数,如服务器地址、端口号等,还可通过CSV文件实现参数化,以满足不同测试需求。
240 7
Jmeter实现WebSocket协议的接口测试方法