OpenAI Embedding效果表现不佳:那如何评估选择Embedding?

OpenAI 最近发布了他们的新一代嵌入模型,称为*embedding v3*, 该embedding 模型被描述作为性能最高的embedding模型,它具有更高的多语言性能效果。

这些模型分为两类:

  1. 较小的为text-embedding-3-small
  2. 更大效果更好的的被称为text-embedding-3-large

关于这些模型的设计和训练方式,OpenAI(CloseAI)几乎没有透露任何信息。

与他们之前发布的嵌入模型(2022 年 12 月发布的 ada-002 模型类)一样,OpenAI 再次选择了闭源的方式,这意味着这些模型只能通过付费的 API 进行访问。

但是模型表现是否如此出色,以至于值得付费呢?

这篇文章的主要内容,是通过实证比较这些新模型与它们的开源对应模型的性能。

我们将依赖数据检索工作流程,根据用户查询找到语料库中最相关的文档。

我们的语料库将是欧洲人工智能法案,它目前正在最终验证阶段。除了是全球首个人工智能法律框架之外,这个语料库的一个有趣特点是它提供了 24 种语言版本。这使得可以比较数据检索的准确性:跨越不同语言体系!

这篇文章将会经历以下两个主要步骤:

  • 从多语言文本语料库中生成一个定制的合成问题/答案数据集
  • 比较 OpenAI 和最先进的开源嵌入模型在这个定制数据集上的准确性

该帖子中呈现的结果的代码和数据可供复制使用,参见文末的Github 仓库

请注意,欧盟 AI 法案仅作为示例,本文中所遵循的方法可以适用于其他数据语料库。

生成一个定制的问答数据集

首先,让我们开始生成一个关于自定义数据的问题和答案(Q/A)数据集,该数据集将用于评估不同嵌入模型的性能。

生成自定义 Q/A 数据集的好处是两个。

首先,通过确保数据集不是嵌入模型训练的一部分,可以避免数据Bias,这可能会在参考基准上发生

其次,它允许根据特定的数据语料库来定制评估,这在检索增强应用(例如 RAG)的情况下可能是相关的。

对于整体流程, 我们遵循llama_index中的处理方式: 预处理->分块->建立索引->提问回答

img

使用 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)

在这个例子中,语料库是欧盟 AI 法案的英文版本,直接从网络上获取。official URL
官方网址我们使用 2021 年 4 月的草案版本,因为最终版本尚未适用于所有欧洲语言。

在这个版本中,可以通过任何其他 23 种欧盟官方语言之一来替换 URL 中的英语,以检索不同语言的文本(BG 代表保加利亚语,ES 代表西班牙语,CS 代表捷克语,等等)。

img

我们使用 SentenceSplitter 对象将文档分割成每个包含 1000 个tokens的chunk(大小可调整)。

对于英文,这大约会产生 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’传递,我们将其设置为两个。然后可以通过从 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 模型,,支持 16K 上下文窗口,并针对对话进行了优化(不使用GPT-4的原因是GPT-4又贵又慢。。。)https://platform.openai.com/docs/models/gpt-3-5-turbo).

生成的对象 ‘qa_dataset’ 包含问题和答案(块)对。以下是生成的问题的示例,这是前两个问题的结果(其中 ‘answer’ 是文本的第一个块):

提案《关于制定关于人工智能的协调规则的条例(人工智能法案)的主要目标是什么?根据说明书?

提案的目的是如何在促进欧盟内部 AI 的应用的同时,解决与 AI 使用相关的风险,正如在上下文信息中所概述的那样?

语言的分块和问题数量取决于语言,英语大约有 100 个分块和 200 个问题,而匈牙利语有大约 200 个分块和 400 个问题。

评估 OpenAI Embedding模型

我们的评估函数遵循Llama Index 文档并包括两个主要步骤。

首先,将所有答案(文档块)的嵌入存储在 VectorStoreIndex 中,以实现高效检索(可以使用ChromaDB, 也可以直接存ES)。

然后,评估函数循环遍历所有查询,检索前 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 模型来说,是一个使用模型名称和模型维度初始化的 OpenAIEmbedding 对象。

from llama_index.embeddings.openai importOpenAIEmbedding              



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

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

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

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

  • OAI-small: The OAI-small:Thetext-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 准确度结果:

img

预期地,对于大型模型,观察到更大的嵌入尺寸 3072 具有更好的性能。与小型和传统的 Ada 模型相比,大型模型却比我们预期的要小。为了比较,我们还报告了 OpenAI 模型在 MTEB 基准测试中获得的性能。

img

有趣的是,我们评估中大型、小型和 Ada 模型之间的性能差异要比 MTEB 基准测试中的差异明显得多,这反映出在大型基准测试中观察到的平均性能不一定反映在自定义数据集上获得的性能。

评估开源embedding模型

开源的嵌入式研究非常活跃,新模型经常发布。了解最新发布模型的好地方是Hugging Face 😊 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 设计,声称在仅有 0.55GB 的情况下比 OpenAI Ada-002 和 text-embedding-3-small 表现更好。有趣的是,该模型是第一个完全可复制和可审计的(开放数据和开源训练代码)。

评估这些开源模型的代码与用于 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"])    

报告如下所示的 MRR 方面的准确性。

img

BGE-M3 表现出最佳性能,平均排名第二的是 ML-E5-Large,E5-mistral-7b 和 Nomic-Embed。BGE-M3 模型尚未在 MTEB 排行榜上进行基准测试,我们的结果表明它可能比其他模型排名更高。值得注意的是,虽然 BGE-M3 针对多语言数据进行了优化,但它在英语方面的表现也比其他模型更好。

我们还报告了每个嵌入模型的处理时间如下。

img

E5-mistral-7b,比其他型号大 10 倍以上,毫无意外地成为最慢的模型。

结论

将八个测试模型的性能放在单个图表中进行对比:

img

结果为:

最佳表现是由开源模型获得的. 该BGE-M3由北京人工智能研究院开发的模型成为了表现最好的模型。该模型与 OpenAI 模型具有相同的上下文长度(8K),大小为 2.2GB。

OpenAI 的一致性范围. 大型(3072)、小型和传统的 OpenAI 模型的性能非常相似。然而,减小大型模型(256)的嵌入大小导致性能下降。

语言敏感性。 几乎所有模型(除了 ML-E5-large)在英语上表现最佳。在捷克语和匈牙利语等语言中观察到了显著的性能变化。

因此,您应该选择付费的 OpenAI 订阅,还是托管一个开源的嵌入模型?

OpenAI 的最近的价格调整通过降低他们的 API 成本,现在每百万个令牌的费用已经降至 0.13 美元。每月处理一百万个查询(假设每个查询涉及约 1K 个令牌)的成本大约为 130 美元。因此,根据您的使用情况,租用和维护自己的嵌入式服务器可能不具有成本效益。

成本效益并非唯一考虑因素。其他因素,如延迟、隐私和对数据处理工作流程的控制,也可能需要考虑。开源模型具有完全的数据控制优势,增强了隐私和定制性。另一方面,OpenAI 的 API 存在延迟问题,有时会导致延长的响应时间。

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

如何学习AI大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

### 解决 OpenAI Embedding API 的 RateLimitError 当使用 OpenAI Embedding API 时遇到 `RateLimitError`,可以通过以下方法来有效处理这一问题: #### 减少令牌数量 通过减少传递给模型的令牌数可以降低请求频率并优化性能。一种常见的策略是预处理输入数据以缩短文本长度[^1]。例如,在嵌入之前对文档进行分词、去除停用词或仅保留关键部分。 #### 实现指数退避重试机制 为了优雅地应对速率限制错误,可以在代码中实现一个自动化的重试逻辑,采用指数退避算法(Exponential Backoff)。这种方法会在每次失败后等待更长时间再重新尝试调用API。下面是一个 Python 示例展示如何实现该功能: ```python import time from openai import OpenAI, RateLimitError def call_embedding_with_retry(text, max_retries=5): client = OpenAI() retry_count = 0 while retry_count < max_retries: try: response = client.embeddings.create( model="text-embedding-ada-002", input=text, ) return response.data[0].embedding except RateLimitError as e: wait_time = (2 ** retry_count) + 0.5 * abs(hash(str(e))) % 1.0 print(f"Hit rate limit error. Retrying after {wait_time:.2f} seconds...") time.sleep(wait_time) retry_count += 1 raise Exception("Max retries reached.") # Example usage example_text = "This is an example text." embedding_result = call_embedding_with_retry(example_text) print(embedding_result[:10]) # Print first ten elements of embedding vector. ``` 上述脚本定义了一个函数 `call_embedding_with_retry()` ,它接受一段文字作为参数,并反复尝试获取其向量表示直到成功或者达到最大重试次数为止。 #### 使用批量处理技术 如果应用程序需要一次性计算大量短句或单词的嵌入,则考虑将这些项目组合成较大的批次一起提交到Embedding服务端口上运行会更加高效。这仅减少了单独HTTP请求的数量从而避免触发限流保护措施,而且还能充分利用GPU资源加速整个流程执行速度。 另外值得注意的是知识图谱嵌入研究领域已经发展出了许多先进的技术和理论框架用于捕捉实体属性、时间信息以及图形结构等方面特征[^2]。虽然这部分内容主要针对学术界内部探讨具体应用场景下的建模方式及其优势所在,但对于实际工程实践也有一定借鉴意义——即合理设计数据表征形式能够显著提升下游任务表现效果的同时也可能间接缓解因频繁交互造成的压力问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值