Skip to content

Latest commit

 

History

History
561 lines (391 loc) · 28.5 KB

README_zh.md

File metadata and controls

561 lines (391 loc) · 28.5 KB

BCEmbedding: Bilingual and Crosslingual Embedding for RAG

         

English | 简体中文

点击打开目录

BCEmbedding是由网易有道开发的中英双语和跨语种语义表征算法模型库,其中包含 EmbeddingModelRerankerModel两类基础模型。EmbeddingModel专门用于生成语义向量,在语义搜索和问答中起着关键作用,而 RerankerModel擅长优化语义搜索结果和语义相关顺序精排。

BCEmbedding作为有道的检索增强生成式应用(RAG)的基石,特别是在QAnything [github]中发挥着重要作用。QAnything作为一个网易有道开源项目,在有道许多产品中有很好的应用实践,比如有道速读有道翻译

BCEmbedding以其出色的双语和跨语种能力而著称,在语义检索中消除中英语言之间的差异,从而实现:

🌐 双语和跨语种优势

现有的单个语义表征模型在双语和跨语种场景中常常表现不佳,特别是在中文、英文及其跨语种任务中。BCEmbedding充分利用有道翻译引擎的优势,实现只需一个模型就可以在单语、双语和跨语种场景中表现出卓越的性能。

EmbeddingModel支持中文和英文(之后会支持更多语种);RerankerModel支持中文,英文,日文和韩文

💡 主要特点

  • 双语和跨语种能力:基于有道翻译引擎的强大能力,BCEmbedding实现强大的中英双语和跨语种语义表征能力。
  • RAG适配:面向RAG做针对性优化,可适配大多数相关任务,比如翻译,摘要,问答等。此外,针对 问题理解(query understanding) 也做了针对优化。详见 基于LlamaIndex的RAG评测指标
  • 高效且精确的语义检索EmbeddingModel采用双编码器,可以在第一阶段实现高效的语义检索。RerankerModel采用交叉编码器,可以在第二阶段实现更高精度的语义顺序精排。
  • 更好的领域泛化性:为了在更多场景实现更好的效果,我们收集了多种多样的领域数据。
  • 用户友好:语义检索时不需要特殊指令前缀。也就是,你不需要为各种任务绞尽脑汁设计指令前缀。
  • 有意义的重排序分数RerankerModel可以提供有意义的语义相关性分数(不仅仅是排序),可以用于过滤无意义文本片段,提高大模型生成效果。
  • 产品化检验BCEmbedding已经被有道众多产品检验。

🚀 最新更新

🍎 模型列表

模型名称 模型类型 支持语种 参数量 开源权重
bce-embedding-base_v1 EmbeddingModel 中英 279M Huggingface(推荐), ModelScope
bce-reranker-base_v1 RerankerModel 中英日韩 279M Huggingface(推荐), ModelScope

📖 使用指南

安装

首先创建一个conda环境并激活

conda create --name bce python=3.10 -y
conda activate bce

然后最简化安装 BCEmbedding(为了避免自动安装的torch cuda版本和本地不兼容,建议先手动安装本地cuda版本兼容的torch):

pip install BCEmbedding==0.1.3

也可以通过项目源码安装:

git clone git@github.com:netease-youdao/BCEmbedding.git
cd BCEmbedding
pip install -v -e .

快速使用

1. 基于 BCEmbedding

通过 BCEmbedding调用 EmbeddingModelpooler默认是 cls

from BCEmbedding import EmbeddingModel

# list of sentences
sentences = ['sentence_0', 'sentence_1', ...]

# init embedding model
model = EmbeddingModel(model_name_or_path="maidalun1020/bce-embedding-base_v1")

# extract embeddings
embeddings = model.encode(sentences)

通过 BCEmbedding调用 RerankerModel可以计算句子对的语义相关分数,也可以对候选检索见过进行排序。

from BCEmbedding import RerankerModel

# your query and corresponding passages
query = 'input_query'
passages = ['passage_0', 'passage_1', ...]

# construct sentence pairs
sentence_pairs = [[query, passage] for passage in passages]

# init reranker model
model = RerankerModel(model_name_or_path="maidalun1020/bce-reranker-base_v1")

# method 0: calculate scores of sentence pairs
scores = model.compute_score(sentence_pairs)

# method 1: rerank passages
rerank_results = model.rerank(query, passages)

注意:

  • RerankerModel.rerank方法中,我们提供一个query和passage的拼接方法(在实际生产服务中使用),可适用于passage很长的情况。

2. 基于 transformers

EmbeddingModel调用方法:

from transformers import AutoModel, AutoTokenizer

# list of sentences
sentences = ['sentence_0', 'sentence_1', ...]

# init model and tokenizer
tokenizer = AutoTokenizer.from_pretrained('maidalun1020/bce-embedding-base_v1')
model = AutoModel.from_pretrained('maidalun1020/bce-embedding-base_v1')

device = 'cuda'  # if no GPU, set "cpu"
model.to(device)

# get inputs
inputs = tokenizer(sentences, padding=True, truncation=True, max_length=512, return_tensors="pt")
inputs_on_device = {k: v.to(self.device) for k, v in inputs.items()}

# get embeddings
outputs = model(**inputs_on_device, return_dict=True)
embeddings = outputs.last_hidden_state[:, 0]  # cls pooler
embeddings = embeddings / embeddings.norm(dim=1, keepdim=True)  # normalize

RerankerModel调用方法:

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

# init model and tokenizer
tokenizer = AutoTokenizer.from_pretrained('maidalun1020/bce-reranker-base_v1')
model = AutoModelForSequenceClassification.from_pretrained('maidalun1020/bce-reranker-base_v1')

device = 'cuda'  # if no GPU, set "cpu"
model.to(device)

# get inputs
inputs = tokenizer(sentence_pairs, padding=True, truncation=True, max_length=512, return_tensors="pt")
inputs_on_device = {k: v.to(device) for k, v in inputs.items()}

# calculate scores
scores = model(**inputs_on_device, return_dict=True).logits.view(-1,).float()
scores = torch.sigmoid(scores)

3. 基于 sentence_transformers

EmbeddingModel调用方法:

from sentence_transformers import SentenceTransformer

# list of sentences
sentences = ['sentence_0', 'sentence_1', ...]

# init embedding model
## sentence-trnasformers支持有更新,请注意先删除本地模型缓存:"`SENTENCE_TRANSFORMERS_HOME`/maidalun1020_bce-embedding-base_v1"或“~/.cache/torch/sentence_transformers/maidalun1020_bce-embedding-base_v1”
model = SentenceTransformer("maidalun1020/bce-embedding-base_v1")

# extract embeddings
embeddings = model.encode(sentences, normalize_embeddings=True)

RerankerModel调用方法:

from sentence_transformers import CrossEncoder

# init reranker model
model = CrossEncoder('maidalun1020/bce-reranker-base_v1', max_length=512)

# calculate scores of sentence pairs
scores = model.predict(sentence_pairs)

Embedding和Reranker集成常用RAG框架

1. 使用 langchain

为了继承RerankerModel精细优化的rerank逻辑,我们提供BCERerank方法,可直接集成到langchain demo中。

# 我们在`BCEmbedding`中提供langchain直接集成的接口。
from BCEmbedding.tools.langchain import BCERerank

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.vectorstores import FAISS

from langchain.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores.utils import DistanceStrategy
from langchain.retrievers import ContextualCompressionRetriever


# init embedding model
embedding_model_name = 'maidalun1020/bce-embedding-base_v1'
embedding_model_kwargs = {'device': 'cuda:0'}
embedding_encode_kwargs = {'batch_size': 32, 'normalize_embeddings': True, 'show_progress_bar': False}

embed_model = HuggingFaceEmbeddings(
  model_name=embedding_model_name,
  model_kwargs=embedding_model_kwargs,
  encode_kwargs=embedding_encode_kwargs
)

reranker_args = {'model': 'maidalun1020/bce-reranker-base_v1', 'top_n': 5, 'device': 'cuda:1'}
reranker = BCERerank(**reranker_args)

# init documents
documents = PyPDFLoader("BCEmbedding/tools/eval_rag/eval_pdfs/Comp_en_llama2.pdf").load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1500, chunk_overlap=200)
texts = text_splitter.split_documents(documents)

# example 1. retrieval with embedding and reranker
retriever = FAISS.from_documents(texts, embed_model, distance_strategy=DistanceStrategy.MAX_INNER_PRODUCT).as_retriever(search_type="similarity", search_kwargs={"score_threshold": 0.3, "k": 10})

compression_retriever = ContextualCompressionRetriever(
    base_compressor=reranker, base_retriever=retriever
)

response = compression_retriever.get_relevant_documents("What is Llama 2?")

2. 使用 llama_index

为了继承RerankerModel精细优化的rerank逻辑,我们提供BCERerank方法,可直接集成到LlamaIndex demo中。

# 我们在`BCEmbedding`中提供llama_index直接集成的接口。
from BCEmbedding.tools.llama_index import BCERerank

import os
from llama_index.embeddings import HuggingFaceEmbedding
from llama_index import VectorStoreIndex, ServiceContext, SimpleDirectoryReader
from llama_index.node_parser import SimpleNodeParser
from llama_index.llms import OpenAI
from llama_index.retrievers import VectorIndexRetriever

# init embedding model and reranker model
embed_args = {'model_name': 'maidalun1020/bce-embedding-base_v1', 'max_length': 512, 'embed_batch_size': 32, 'device': 'cuda:0'}
embed_model = HuggingFaceEmbedding(**embed_args)

reranker_args = {'model': 'maidalun1020/bce-reranker-base_v1', 'top_n': 5, 'device': 'cuda:1'}
reranker_model = BCERerank(**reranker_args)

# example #1. extract embeddings
query = 'apples'
passages = [
        'I like apples', 
        'I like oranges', 
        'Apples and oranges are fruits'
    ]
query_embedding = embed_model.get_query_embedding(query)
passages_embeddings = embed_model.get_text_embedding_batch(passages)

# example #2. rag example
llm = OpenAI(model='gpt-3.5-turbo-0613', api_key=os.environ.get('OPENAI_API_KEY'), api_base=os.environ.get('OPENAI_BASE_URL'))
service_context = ServiceContext.from_defaults(llm=llm, embed_model=embed_model)

documents = SimpleDirectoryReader(input_files=["BCEmbedding/tools/eval_rag/eval_pdfs/Comp_en_llama2.pdf"]).load_data()
node_parser = SimpleNodeParser.from_defaults(chunk_size=400, chunk_overlap=80)
nodes = node_parser.get_nodes_from_documents(documents[0:36])
index = VectorStoreIndex(nodes, service_context=service_context)

query = "What is Llama 2?"

# example #2.1. retrieval with EmbeddingModel and RerankerModel
vector_retriever = VectorIndexRetriever(index=index, similarity_top_k=10, service_context=service_context)
retrieval_by_embedding = vector_retriever.retrieve(query)
retrieval_by_reranker = reranker_model.postprocess_nodes(retrieval_by_embedding, query_str=query)

# example #2.2. query with EmbeddingModel and RerankerModel
query_engine = index.as_query_engine(node_postprocessors=[reranker_model])
query_response = query_engine.query(query)

⚙️ 模型评测

基于MTEB的语义表征评测说明

我们基于MTEBC_MTEB,提供 embeddingreranker模型的语义表征评测工具。

首先安装 MTEB:

pip install mteb==1.1.1

1. Embedding模型

运行下面命令评测 your_embedding_model(比如,maidalun1020/bce-embedding-base_v1)。评测任务将会在双语种和跨语种(比如,["en", "zh", "en-zh", "zh-en"])模式下评测:

python BCEmbedding/tools/eval_mteb/eval_embedding_mteb.py --model_name_or_path maidalun1020/bce-embedding-base_v1 --pooler cls

评测包含 "Retrieval", "STS", "PairClassification", "Classification", "Reranking"和"Clustering" 这六大类任务的 114个数据集

注意:

  • 所有模型的评测采用各自推荐的 pooler
    • mean pooler:"jina-embeddings-v2-base-en", "m3e-base", "m3e-large", "e5-large-v2", "multilingual-e5-base", "multilingual-e5-large"和"gte-large"。
    • cls pooler:其他模型。
  • "jina-embeddings-v2-base-en"模型在载入时需要 trust_remote_code
python BCEmbedding/tools/eval_mteb/eval_embedding_mteb.py --model_name_or_path {mean_pooler_models} --pooler mean

python BCEmbedding/tools/eval_mteb/eval_embedding_mteb.py --model_name_or_path jinaai/jina-embeddings-v2-base-en --pooler mean --trust_remote_code

2. Reranker模型

运行下面命令评测 your_reranker_model(比如,maidalun1020/bce-reranker-base_v1)。评测任务将会在双语种和跨语种(比如,["en", "zh", "en-zh", "zh-en"])模式下评测:

python BCEmbedding/tools/eval_mteb/eval_reranker_mteb.py --model_name_or_path maidalun1020/bce-reranker-base_v1

评测包含 "Reranking" 任务的 12个数据集

3. 指标可视化工具

我们提供了 embeddingreranker模型的指标可视化一键脚本,输出一个markdown文件,详见Embedding模型指标汇总Reranker模型指标汇总

python BCEmbedding/evaluation/mteb/summarize_eval_results.py --results_dir {your_embedding_results_dir | your_reranker_results_dir}

基于LlamaIndex的RAG评测说明

LlamaIndex是一个著名的大模型应用的开源工具,在RAG中很受欢迎。最近,LlamaIndex博客对市面上常用的embedding和reranker模型进行RAG流程的评测,吸引广泛关注。下面我们按照该评测流程验证 BCEmbedding在RAG中的效果。

首先,安装LlamaIndex,并升级transformers到4.36.0:

pip install transformers==4.36.0

pip install llama-index==0.9.22

将您的"openai"和"cohere"的app key,以及openai base url( openai官方接口"https://api.openai.com/v1" )放到环境变量中:

export OPENAI_BASE_URL={openai_base_url}  # https://api.openai.com/v1
export OPENAI_API_KEY={your_openai_api_key}
export COHERE_APPKEY={your_cohere_api_key}

1. 评测指标说明

  • 命中率(Hit Rate)

    命中率计算的是在检索的前k个文档中找到正确答案的查询所占的比例。简单来说,它反映了我们的系统在前几次猜测中答对的频率。该指标越大越好。

  • 平均倒数排名(Mean Reciprocal Rank,MRR)

    对于每个查询,MRR通过查看最高排名的相关文档的排名来评估系统的准确性。具体来说,它是在所有查询中这些排名的倒数的平均值。因此,如果第一个相关文档是排名最靠前的结果,倒数排名就是1;如果是第二个,倒数排名就是1/2,依此类推。该指标越大越好。

为了公平起见,运行下面脚本,复刻LlamaIndex博客评测流程,将 BCEmbedding与其他embedding和reranker模型进行对比分析:

# There should be two GPUs available at least.
CUDA_VISIBLE_DEVICES=0,1 python BCEmbedding/tools/eval_rag/eval_llamaindex_reproduce.py

运行下面命令,将指标汇总并分析:

python BCEmbedding/tools/eval_rag/summarize_eval_results.py --results_dir BCEmbedding/results/rag_reproduce_results

输出的指标汇总详见 LlamaIndex RAG评测结果复现。从该复现结果中,可以看出:

  • WithoutReranker设置下(竖排对比),bce-embedding-base_v1比其他embedding模型效果都要好。
  • 在固定embedding模型设置下,对比不同reranker效果(横排对比),bce-reranker-base_v1比其他reranker模型效果都要好。
  • bce-embedding-base_v1bce-reranker-base_v1组合,表现SOTA。

3. 更好的领域泛化性

在上述的LlamaIndex博客的评测数据只用了“llama2”这一篇文章,该评测是 单语种,小数据量,特定领域 的。为了兼容更真实更广的用户使用场景,评测算法模型的 领域泛化性,双语和跨语种能力,我们按照该博客的方法构建了一个多领域(计算机科学,物理学,生物学,经济学,数学,量化金融等,详情)的双语种、跨语种评测数据,CrosslingualMultiDomainsDataset为了保证构建数据的高质量,我们采用OpenAI的 gpt-4-1106-preview

运行下面命令,对市面上各家开源、闭源的最强有力的embedding和reranker模型进行系统性评测:

# There should be two GPUs available at least.
CUDA_VISIBLE_DEVICES=0,1 python BCEmbedding/tools/eval_rag/eval_llamaindex_multiple_domains.py

运行下面命令,将指标汇总并分析:

python BCEmbedding/tools/eval_rag/summarize_eval_results.py --results_dir BCEmbedding/results/rag_results

输出的指标汇总详见:多领域、双语种和跨语种评测场景

📈 指标排行榜

基于MTEB的语义表征评测指标

1. Embedding模型

模型名称 向量维度 Pooler 特殊指令 Retrieval (47) STS (19) PairClassification (5) Classification (21) Reranking (12) Clustering (15) 平均 (119)
bge-base-en-v1.5 768 cls 需要 37.14 55.06 75.45 59.73 43.00 37.74 47.19
bge-base-zh-v1.5 768 cls 需要 47.63 63.72 77.40 63.38 54.95 32.56 53.62
bge-large-en-v1.5 1024 cls 需要 37.18 54.09 75.00 59.24 42.47 37.32 46.80
bge-large-zh-v1.5 1024 cls 需要 47.58 64.73 79.14 64.19 55.98 33.26 54.23
gte-large 1024 mean 不需要 36.68 55.22 74.29 57.73 42.44 38.51 46.67
gte-large-zh 1024 cls 不需要 41.15 64.62 77.58 62.04 55.62 33.03 51.51
jina-embeddings-v2-base-en 768 mean 不需要 31.58 54.28 74.84 58.42 41.16 34.67 44.29
m3e-base 768 mean 不需要 46.29 63.93 71.84 64.08 52.38 37.84 53.54
m3e-large 1024 mean 不需要 34.85 59.74 67.69 60.07 48.99 31.62 46.78
e5-large-v2 1024 mean 需要 35.98 55.23 75.28 59.53 42.12 36.51 46.52
multilingual-e5-base 768 mean 需要 54.73 65.49 76.97 69.72 55.01 38.44 58.34
multilingual-e5-large 1024 mean 需要 56.76 66.79 78.80 71.61 56.49 43.09 60.50
bce-embedding-base_v1 768 cls 不需要 57.60 65.73 74.96 69.00 57.29 38.95 59.43

要点:

  • bce-embedding-base_v1 比其他相同规模base模型要好,比最好的large模型稍差。
  • 该榜单包含"Retrieval", "STS", "PairClassification", "Classification", "Reranking"和"Clustering" 这六大类任务的共 114个数据集的119个评测结果 (某些数据集有多个语种)。注意:模型评测是在 ["en", "zh", "en-zh", "zh-en"] 下进行,包含 MTEB和CMTEB
  • 我们开源的跨语种语义表征评测数据属于 Retrieval任务。
  • 更详细的评测结果详见Embedding模型指标详情

2. Reranker模型

模型名称 Reranking (12) 平均 (12)
bge-reranker-base 59.04 59.04
bge-reranker-large 60.86 60.86
bce-reranker-base_v1 61.29 61.29

要点:

  • bce-reranker-base_v1 优于其他base和large reranker模型。
  • 该榜单包含 "Reranking"任务的 12个数据集注意:模型评测是在 ["en", "zh", "en-zh", "zh-en"] 下进行。
  • 更详细的评测结果详见Reranker模型指标详情

基于LlamaIndex的RAG评测指标

1. 多领域、双语种和跨语种评测场景

要点:

  • 与我们按照LlamaIndex Blog复现结果 一致.
  • WithoutReranker设置下(竖排对比),bce-embedding-base_v1优于其他Embedding模型,包括开源和闭源。
  • 在固定Embedding模型设置下,对比不同reranker效果(横排对比),bce-reranker-base_v1比其他reranker模型效果都要好,包括开源和闭源。
  • bce-embedding-base_v1bce-reranker-base_v1组合,表现SOTA。

🛠 有道BCEmbedding API

对于那些更喜欢直接调用api的用户,有道提供方便的 BCEmbedding调用api。该方式是一种简化和高效的方式,将 BCEmbedding集成到您的项目中,避开了手动设置和系统维护的复杂性。更详细的api调用接口说明详见有道BCEmbedding API

🧲 技术交流群

欢迎大家踊跃试用和反馈,技术讨论请扫码加入官方微信交流群。

✏️ 引用说明

如果在您的研究或任何项目中使用本工作,烦请按照下方进行引用,并打个小星星~

@misc{youdao_bcembedding_2023,
    title={BCEmbedding: Bilingual and Crosslingual Embedding for RAG},
    author={NetEase Youdao, Inc.},
    year={2023},
    howpublished={\url{https://github.com/netease-youdao/BCEmbedding}}
}

🔐 许可说明

BCEmbedding采用Apache 2.0 License

🔗 相关链接

Netease Youdao - QAnything

FlagEmbedding

MTEB

C_MTEB

LLama Index | LlamaIndex Blog