llama_index [Bug]: bm25检索器中的除以零错误

eqzww0vc  于 2个月前  发布在  其他
关注(0)|答案(9)|浏览(44)

根据您提供的代码和错误信息,问题出在CitationQueryEngine.from_args这一行。错误提示为“除以零”,这意味着在计算过程中出现了除以零的情况。为了解决这个问题,我们需要查看CitationQueryEngine.from_args方法的实现以及相关的日志/回溯信息。

首先,您可以尝试在CitationQueryEngine.from_args方法中添加一些调试信息,例如打印参数值或计算过程。这样可以帮助您找到问题所在。例如:

def from_args(self, llm, retriever, index, citation_chunk_size=DEFAULT_MAX_TOKEN_SIZE, citation_qa_template=citation_qa_template, citation_refine_template=citation_refine_template, node_postprocessors=[text_processer], similarity_top_k=config.top_k, filters=data_filters):
    print("llm:", llm)
    print("retriever:", retriever)
    print("index:", index)
    print("citation_chunk_size:", citation_chunk_size)
    print("citation_qa_template:", citation_qa_template)
    print("citation_refine_template:", citation_refine_template)
    print("node_postprocessors:", node_postprocessors)
    print("similarity_top_k:", similarity_top_k)
    print("filters:", filters)
    ...

然后,您可以查看日志/回溯信息,看看是否有关于这个错误的详细信息。如果有,您可以根据这些信息进一步定位问题。如果没有,您可能需要检查其他部分的代码,看看是否有可能导致除以零的情况。

dbf7pr2w

dbf7pr2w1#

你在使用BM25Retriever时遇到的"除以零"错误通常发生在算法试图计算查询在空语料库上的得分,或者你的语料库中的文档在预处理后没有产生任何标记。这种情况可能发生在文档为空,或者分词过程过滤掉了文档中的所有内容。
要解决这个问题,确保你的语料库不为空,并且包含有效的、可分词的内容。如果你的语料库有效,但仍然遇到这个问题,可能是由于分词过程从你的文档中删除了所有的标记,导致它们变为空。在这种情况下,你可能需要调整分词过程,以确保在预处理后文档中仍然有标记。
你可以对BM25Retriever进行修改,以过滤掉空的标记列表并避免"除以零"错误:

class BM25Retriever(BaseRetriever):
    def __init__(
        self,
        nodes: List[BaseNode],
        tokenizer: Optional[Callable[[str], List[str]]] = None,
        similarity_top_k: int = 100,
        verbose: bool = False,
    ) -> None:
        self._nodes = nodes
        self._tokenizer = tokenizer or default_tokenizer
        # Tokenize the content of each node and filter out empty token lists
        self._corpus = [self._tokenizer(node.content) for node in self._nodes if self._tokenizer(node.content)]
        if not self._corpus:
            raise ValueError("The corpus is empty or all documents resulted in no tokens after tokenization.")
        self.bm25 = BM25Okapi(self._corpus)

这确保传递给BM25Okapi的语料库不包含任何空的标记列表,这应该有助于避免"除以零"错误。此外,如果语料库为空或所有文档在分词后都没有标记,它会引发一个ValueError,便于调试和错误处理。
请尝试调整你的分词过程或确保你的语料库包含有效的内容,并告诉我问题是否仍然存在。

来源

关于Dosu

这个响应旨在帮助你节省时间,提高效率。它不是精确的解决方案,而是你自己研究的一个起点。
请帮我变得更有用!如果觉得有帮助请留下👍,如果觉得无关请留下👎。
如果你想继续对话,请以@dosu-bot开始你的回复。

n3schb8v

n3schb8v2#

如果index.docstore为空,只会发生这种情况。
我猜你正在使用一些矢量数据库集成。
尝试直接传递节点 BM25Retriever.from_defaults(nodes=nodes, ...)

2ic8powd

2ic8powd3#

感谢您的回复!我们通过以下代码初始化了向量数据库:

index = VectorStoreIndex(
nodes=[],
embed_model=opensearch_client.os_client.embedding_model,
storage_context=StorageContext.from_defaults(vector_store=vector_store),
callback_manager=callback_manager
)

并使用此代码初始化BM检索器。

您是否建议BM25Retriever在索引具有更多节点时不会动态更新(CitationQueryEngine可以这样做)?我有点觉得破坏流程是不好的做法...

此外,您之前评论中的 nodes 是什么意思?它们都是向量数据库中的所有节点吗?我认为bm25会从数据库中所有现有节点返回前k个节点,对吗?

cngwdvgl

cngwdvgl4#

BM25检索器不会与您的向量数据库进行交互。
它需要节点,并将它们存储在内存中,由您获取节点以创建检索器。
这可以来自文档库,但在使用向量数据库集成时,文档库被禁用以简化存储。如果您想要,可以手动创建和维护一个文档库来存储节点。
否则,在您的情况下,您需要一种从向量数据库获取节点的方法,以便您可以创建检索器。

pdtvr36n

pdtvr36n5#

感谢您的回复!在仔细审查我们的代码后,我正在考虑为我们的用例覆盖llama索引中的检索函数。然而,我不确定如何检索索引中的所有可用节点并将其传递给bm25检索器。我应该怎么做?或者我应该覆盖更高层次的内容?

async def aretrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
        nodes = await self._retriever.aretrieve(query_bundle)

        for postprocessor in self._node_postprocessors:
            nodes = postprocessor.postprocess_nodes(nodes, query_bundle=query_bundle)

        return nodes

其中self._retriever是一个具有定义了检索函数的基本检索器。

async def aretrieve(self, str_or_query_bundle: QueryType) -> List[NodeWithScore]:
        self._check_callback_manager()
        dispatch_event = dispatcher.get_dispatch_event()

        dispatch_event(
            RetrievalStartEvent(
                str_or_query_bundle=str_or_query_bundle,
            )
        )
        if isinstance(str_or_query_bundle, str):
            query_bundle = QueryBundle(str_or_query_bundle)
        else:
            query_bundle = str_or_query_bundle
        with self.callback_manager.as_trace("query"):
            with self.callback_manager.event(
                CBEventType.RETRIEVE,
                payload={EventPayload.QUERY_STR: query_bundle.query_str},
            ) as retrieve_event:
                import pdb; pdb.set_trace()
                nodes = await self._aretrieve(query_bundle=query_bundle)
                nodes = await self._ahandle_recursive_retrieval(
                    query_bundle=query_bundle, nodes=nodes
                )
                retrieve_event.on_end(
                    payload={EventPayload.NODES: nodes},
                )
        dispatch_event(
            RetrievalEndEvent(
                str_or_query_bundle=str_or_query_bundle,
                nodes=nodes,
            )
        )
        return nodes
p1iqtdky

p1iqtdky6#

你可以使用一个非常高的top k值(例如20000)来检索这些节点,并将它们分配给bm25。或者只是将你的节点存储在易于访问的地方(例如文档库)。

mutmk8jj

mutmk8jj7#

我认为在这里重写方法并不是非常必要。但是取决于你

r1zk6ea1

r1zk6ea18#

建议的修复方法的问题在于,你总是需要在内存中加载节点,这使得矢量数据库服务提供的优化变得毫无意义。关键是要利用你选择的搜索方法来利用它们。不仅如此,在实时应用程序的背景下,你必须始终手动更新基于BM25的查询引擎以与第三方索引同步。llama中的BM25和其他搜索方法应该具有与所选矢量存储同步的能力。

cig3rfwq

cig3rfwq9#

@abdelatifsd 使用llama-index中的bm25,因此它受到该包提供的限制,即仅限于内存中。
一些矢量数据库内置了bm25。
问题是bm25是静态的。如果向索引中添加任何文档,所有稀疏嵌入都需要更新。

相关问题