亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

多模態AI搜索在商業應用中的潛力

帮助企业从数据中挖掘实际价值

业务文档,例如复杂的报告、产品目录、设计文件、财务报表、技术手册和市场分析报告,通常包含多模态数据(包括文本以及图形内容、图表、地图、照片、信息图、图表和工程蓝图等视觉素材)。从这些文档中找到所需信息通常需要进行语义搜索技术,既搜索文本又搜索相关图像,以回答客户或公司员工的提问。例如,公司的产品可能通过其标题、文本描述和图像来描述。同样,项目提案可能包括文本、预算分配图、显示地理覆盖范围的地图以及过往项目的照片。

准确且快速地搜索多模态信息对提高业务生产力非常重要。业务数据通常以文本和图像形式分散在多个来源中,这使得高效检索所有相关信息颇具挑战性。虽然生成式AI方法,尤其是利用大规模语言模型(LLMs)进行业务知识管理,面临在访问多模态、分散数据时的限制。能够整合多种数据类型的方法可以让用户使用自然语言查询不同格式的数据。这种能力可以为公司内的员工和管理层带来好处,同时改善客户体验。它可以在多种应用场景中发挥作用,例如对相似主题进行聚类并发现主题趋势,构建推荐引擎,用更相关的内容吸引客户兴趣,更快地获取信息以提高决策效率,提供个性化的搜索结果,增强用户交互,使其感觉更加直观自然,减少寻找信息所花的时间,等等。

在现代AI模型中,数据被处理成称为嵌入的数值向量。专门的AI模型,称为嵌入模型,将数据转换为数值表示,以便高效地捕捉和比较意义或特征的相似性。嵌入对于语义搜索和知识图谱非常有用,并且是当今复杂LLM的关键支柱。

本文探讨了嵌入模型(特别是后面介绍的多模态嵌入模型)在商业应用中增强跨多种数据类型语义搜索的能力。文章首先解释了嵌入的概念,帮助那些不熟悉AI中嵌入工作原理的读者理解。接下来,文章进一步讨论了多模态嵌入的概念,解释了如何将来自多种格式的数据结合成统一的嵌入,以捕捉跨模态之间的关系,并且这对商业相关信息搜索任务来说可能会非常有用。最后,本文探讨了一个最近引入的多模态嵌入模型,用于商业应用中的语义搜索。

理解空间嵌入和语义搜索

嵌入向量存储在一个向量空间中,在这个空间中,相似的概念彼此靠近。想象这个嵌入空间就像一个图书馆,相关主题的书被放在相邻的书架上。例如,在嵌入空间中,“desk”(书桌)和“chair”(椅子)这些词的嵌入彼此靠近,而“airplane”(飞机)和“baseball”(棒球)则彼此远离。这种布局让模型可以轻松找到和关联相关项,这增强了推荐、搜索和聚类等任务的效果。

为了展示如何计算和可视化嵌入,让我们定义一些不同概念的类别。你可以在这里找到完整的代码:GitHub

    categories = {  
        "水果": ["苹果", "香蕉", "橙子", "葡萄", "芒果", "桃子", "菠萝"],  
        "动物": ["狗", "猫", "大象", "老虎", "狮子", "猴子", "兔子"],  
        "国家": ["加拿大", "法国", "印度", "日本", "巴西", "德国", "澳大利亚"],  
        "运动": ["足球", "篮球", "网球", "棒球", "板球(Cricket)", "游泳", "跑步"],  
        "音乐类型": ["摇滚", "爵士", "古典", "嘻哈音乐", "流行", "蓝调"],  
        "职业": ["医生", "工程师", "教师", "艺术家", "厨师", "律师", "飞机驾驶员"],  
        "车辆": ["汽车", "自行车", "摩托车", "飞机", "火车", "船", "公共汽车"],  
        "家具": ["椅子", "桌子", "沙发", "床", "书桌", "书架", "柜子"],  
        "情绪": ["快乐", "悲伤", "愤怒", "害怕", "惊讶", "厌恶", "平静"],  
        "天气": ["飓风", "龙卷风", "暴风雪", "热浪", "雷暴", "雾"],  
        "烹饪": ["烤肉", "煮", "煎", "烘焙", "蒸", "炖", "炖"]  

    }

我现在将使用嵌入模型(Cohere的embed-english-v3.0模型),本文主要讨论该模型,并将在示例之后详细讨论。如下代码片段所示,运行此代码需要安装以下库。

# 下面的命令用于安装一些常用的Python库,比如用于数据可视化的seaborn和用于绘图的matplotlib
!pip install cohere umap-learn seaborn matplotlib numpy pandas regex altair scikit-learn ipython faiss-cpu

这段代码生成上述概念的文本嵌入,并将它们存放在 NumPy 数组中。

    import cohere  
    import umap  
    import seaborn as sns  
    import matplotlib.pyplot as plt  
    import numpy as np  
    import pandas as pd  

    # 初始化 Cohere 客户端  
    co = cohere.Client(api_key=os.getenv("COHERE_API_KEY_2"))  
    # 展开类别和概念  
    labels = []  
    concepts = []  
    for category, items in categories.items():  
        labels.extend([category] * len(items))  
        concepts.extend(items)  

    # 为所有概念生成文本嵌入,将 input_type 修正为 "search_document"  
    embeddings = co.embed(  
        texts=concepts,  
        model="embed-english-v3.0",  
        input_type="search_document"  # 修正后的输入类型  
    ).embeddings  

    # 转换为 NumPy 数组  
    embeddings = np.array(embeddings)

嵌入可能有数百甚至数千个维度,这些维度无法直接可视化,因此我们通常需要将其降维。在计算出嵌入之后,以下代码使用UMAP(Uniform Manifold Approximation and Projection)降维方法将嵌入映射到二维空间,以便我们能够绘制并分析这些相似概念是如何聚集的。

    # 使用UMAP进行降维  
    reducer = umap.UMAP(n_neighbors=20, random_state=42)  
    reduced_embeddings = reducer.fit_transform(embeddings)  

    # 创建用于可视化的DataFrame  
    df = pd.DataFrame({  
        "x": reduced_embeddings[:, 0],  
        "y": reduced_embeddings[:, 1],  
        "Category": labels,  
        "Concept": concepts  
    })  

    # 使用Seaborn绘图  
    plt.figure(figsize=(12, 8))  
    sns.scatterplot(data=df, x="x", y="y", hue="Category", style="Category", palette="Set2", s=100)  

    # 给每个点添加标签  
    for i in range(df.shape[0]):  
        plt.text(df["x"][i] + 0.02, df["y"][i] + 0.02, df["Concept"][i], fontsize=9)  

    plt.legend(loc="lower right")  
    plt.title("按类别的嵌入可视化")  
    plt.xlabel("UMAP 第1维度")  
    plt.ylabel("UMAP 第2维度")  
    plt.savefig("C:/Users/h02317/Downloads/embeddings.png",dpi=600)  

    plt.show()

这里是这些概念在二维空间里的嵌入图。

嵌入的可视化:不同概念在嵌入空间中的表示(作者绘制的图像)

语义相似的项目在嵌入空间中被归为一组,而含义相距较远的概念则相距较远(例如,国家与其他类别则相距较远)。在语义空间中,国家与其他类别相距较远。

为了说明搜索查询是如何映射到其匹配概念的过程,在此空间中,我们首先将这些嵌入存入一个向量数据库(如FAISS)。接下来,我们以同样的方式计算查询的嵌入,并在嵌入空间中找到一个类似的“邻域”,其中的嵌入与查询语义非常接近。这种接近程度是通过计算查询嵌入与数据库中存储的嵌入之间的欧几里得距离或余弦相似度来衡量的。

    import cohere  
    import numpy as np  
    import re  
    import pandas as pd  
    from tqdm import tqdm  
    from datasets import load_dataset  
    import umap  
    import altair as alt  
    from sklearn.metrics.pairwise import cosine_similarity  
    import warnings  
    from IPython.display import display, Markdown  
    import faiss  
    import numpy as np  
    import pandas as pd  
    from sklearn.preprocessing import normalize  
    warnings.filterwarnings('ignore')  
    pd.set_option('display.max_colwidth', None)  

    # 对嵌入进行归一化(可选但推荐用于计算余弦相似度)  
    embeddings = normalize(np.array(embeddings))  

    # 创建FAISS索引(使用L2距离)  
    dimension = embeddings.shape[1]  
    index = faiss.IndexFlatL2(dimension)  # L2距离,可以使用IndexFlatIP来计算内积(即余弦相似度)  
    index.add(embeddings)  # 将嵌入添加到FAISS索引中  

    # 将查询嵌入  
    query = "Which is the largest European country?"  
    query_embedding = co.embed(texts=[query], model="embed-english-v3.0", input_type="search_document").embeddings[0]  
    query_embedding = normalize(np.array([query_embedding]))  # 归一化查询嵌入  

    # 搜索最近的邻居  
    k = 5  # 邻居的数量  
    distances, indices = index.search(query_embedding, k)  

    # 格式化结果并显示  
    results = pd.DataFrame({  
        'texts': [concepts[i] for i in indices[0]],  
        'distance': distances[0]  
    })  
    display(Markdown(f"查询: {query}"))  
    # 将DataFrame转换为Markdown格式  
    def print_markdown_results(df):  
        markdown_text = f"最近邻:\n\n"  
        markdown_text += "| 文本 | 距离 |\n"  
        markdown_text += "|-------|----------|\n"  
        for _, row in df.iterrows():  
            markdown_text += f"| {row['texts']} | {row['distance']:.4f} |\n"  
        display(Markdown(markdown_text))  

    # 以markdown格式显示结果  
    print_markdown_results(results)

以下是与查询最接近的五个匹配项,按它们与查询嵌入表示之间的最小距离排序。

前5名最短距离反映查询对象与概念的相似度(作者的图片)

如图可见,France 是该查询在给定概念中正确的匹配结果。在可视化的嵌入空间中,查询的位置位于“国家”组内。

整个语义搜索的过程如图所示。

使用文本嵌入来展示语义搜索(图片由作者提供)

多模态嵌入技术

文本嵌入在语义搜索和检索增强生成(RAG)技术中得到了成功应用。例如由OpenAI的(https://platform.openai.com/docs/guides/embeddings),Google(https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-text-embeddings),Cohere(https://docs.cohere.com/v2/page/text-classification-using-embeddings),等等开源模型可用。这些模型可以在Hugging Face平台上找到,例如all-MiniLM-L6-v2。虽然这些模型对于语义搜索非常有用,尤其是文本到文本的搜索,但它们无法处理图像数据,而图像数据是商业文档中的一个重要信息来源。此外,公司通常需要快速从文档或庞大的图像库中查找相关图像,而这些图像库可能缺少适当的元数据。

这个问题在某些多模态嵌入模型中得到了部分解决,例如OpenAI的CLIP,该模型可以连接文本和图像,并且能够识别图像中的各种视觉概念,并将这些概念与相应的名称关联起来。然而,它的文本输入能力非常有限,特别是对于较长的输入文本,在仅文本或甚至文本到图像的检索任务中,其表现不佳。OpenAI的CLIP

文本和图像嵌入模型的结合也被用来将文本和图像数据分别聚类到不同的空间中;然而,这种方法会导致效果较差的搜索结果,更偏向文本数据。在多模态RAG系统中,通过结合文本嵌入模型和多模态大语言模型,可以从文本和图像中同时回答问题。关于多模态RAG开发的详细信息,请参阅我下面的文章。

[将多模态数据集成到大型语言模型中开发一种多模态RAG,它基于上下文检索,利用高级解析、语义和关键词搜索,并进行重新排序](Towards Data Science: https://medium.com/integrating-multimodal-data-into-a-large-language-model-d1965b8ab00c?source=post_page-----65356d011009--------------------------------)

一个多模态嵌入模型应该能够在单一数据库中包含图像和文本数据,从而降低复杂性,与维护两个单独的数据库相比。通过这种方式,该模型将更注重数据的意义,而不是偏向特定类型的数据。

一个多模态嵌入模型,将文本和图像的嵌入表示在一个共享的嵌入空间中进行存储(作者提供)

通过将所有形式的信息存储在同一嵌入空间中,模型将能够把文字和相关图片联系起来,并在不同的信息格式之间检索和比较信息。这种方法可以让搜索结果更加相关,让用户更容易探索彼此关联的信息。

探讨多模态嵌入模型在业务场景中的应用

Cohere最近推出了一个多模态嵌入模型,名为EMBED 3,它可以为文本和图像生成嵌入,并将这些嵌入存储于统一的嵌入空间中。根据Cohere的博客,该模型在包括零样本识别、文本生成图像、图表分析、电子商务产品目录和设计文件在内的多种多模态任务中展示了出色的表现。

在这篇文章中,我探讨了Cohere的多模式嵌入模型在商业场景中的应用,其中客户可以通过文本查询或图片搜索在线产品目录中的产品。该模型适用于文本到图像、文本到文本和图像到图像的检索任务。这些检索方法在在线产品目录中的应用为商家和客户带来了许多好处。如果客户对某个商品感兴趣,可以上传一张图片,模型会从目录中检索出视觉相似的产品并提供详细信息。此外,客户还可以通过描述产品的特性来查找特定产品,而无需使用确切的产品名称。这种方法允许客户以灵活的方式搜索产品。

以下就是这个用例的操作步骤。

  1. 展示如何从产品目录中使用LlamaParse解析多模态数据(包括文本和图像)。
  2. 使用Cohere的_embed-english-v3.0_多模态模型创建多模态索引。
  3. 创建多模态检索器,并对给定的查询进行测试。
  4. 使用提示模板创建一个多模态查询引擎,用于查询多模态向量数据库,支持文本到文本和文本到图像的联合任务。
  5. 从向量数据库中检索相关的图像和文本,并将它们发送到LLM以生成最终响应。
  6. 测试图像到图像的检索任务。

我使用OpenAI的DALL-E图像生成器为一家虚构公司生成了一个家具目录示例。这份目录分为4个类别,共有36张产品图片和描述。下面展示的是该目录第一页的截图。

合成产品目录的第一页(图片来自作者)

完整代码和示例数据可以在GitHub上找到。我们一步步来讨论。

Cohere的嵌入模型是这样用的。

    model_name = "embed-english-v3.0"  
    api_key = "COHERE_API_KEY"  
    input_type_embed = "search_document" # 对于图像嵌入,换成 input_type_embed = "image" 即可。
    # 创建Cohere客户端。
    co = cohere.Client(api_key)  
    text = ['apple','chair','mango']  
    embeddings = co.embed(texts=list(text),  
                      model=model_name,  
                      input_type=input_type_embed).结果

可以在Cohere的网站上注册免费账户来使用试用API密钥测试该模型。

为了展示如何从多模态数据中提取信息,我使用了_LlamaParse_从目录中提取产品图片和文本。有关此过程的详细介绍,请参阅我之前的文章[链接]。您可以在Llama Cloud 网站注册账户并获取API密钥,免费的API密钥每天提供1000页的信用额度。

以下库包才能运行本文代码,需要先安装。

# 安装必要的库
# 安装 nest-asyncio, python-dotenv, llama-parse 和 qdrant-client
!pip install nest-asyncio python-dotenv llama-parse qdrant-client

以下代码从环境文件(.env)中加载Llama Cloud、Cohere和OpenAI的API密钥。使用OpenAI的多模态大型语言模型_GPT-4o_生成最终回复GPT-4o

    import os  
    import time  
    import nest_asyncio  
    from typing import List  
    from dotenv import load_dotenv  

    from llama_parse import LlamaParse  
    from llama_index.core.schema import ImageDocument, TextNode  
    from llama_index.embeddings.cohere import CohereEmbedding  
    from llama_index.multi_modal_llms.openai import OpenAIMultiModal  
    from llama_index.core import Settings  
    from llama_index.core.indices import MultiModalVectorStoreIndex  
    from llama_index.vector_stores.qdrant import QdrantVectorStore  
    from llama_index.core import StorageContext  
    import qdrant_client  
    from llama_index.core import SimpleDirectoryReader  
    # 加载环境变量  
    load_dotenv()  
    nest_asyncio.apply() # 应用nest_asyncio  

    # 设置API密钥  
    COHERE_API_KEY = os.getenv("COHERE_API_KEY")  
    LLAMA_CLOUD_API_KEY = os.getenv("LLAMA_CLOUD_API_KEY")  
    OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

以下代码通过使用_LlamaParse_从目录文件中提取文本和图片。提取出的文本和图片将会被保存到指定的路径以便后续使用。

    # 提取文本节点内容  
    def get_text_nodes(json_list: List[dict]) -> List[TextNode]:  
        return [TextNode(text=page["text"], metadata={"page": page["page"]}) for page in json_list]  

    # 提取图片节点  
    def get_image_nodes(json_objs: List[dict], download_path: str) -> List[ImageDocument]:  
        image_dicts = parser.get_images(json_objs, download_path=download_path)  
        return [ImageDocument(image_path=image_dict["path"]) for image_dict in image_dicts]  

    # 将文本节点内容保存到文件  
    def save_texts_to_file(text_nodes, file_path):  
        texts = [node.text for node in text_nodes]  
        all_text = "\n\n".join(texts)  
        with open(file_path, "w", encoding="utf-8") as file:  
            file.write(all_text)  

    # 定义文件路径  
    FILE_NAME = "furniture.docx"  
    IMAGES_DOWNLOAD_PATH = "parsed_data"  

    # 初始化LlamaParse  
    parser = LlamaParse(  
        api_key=LLAMA_CLOUD_API_KEY,  
        result_type="Markdown",  
    )  

    # 解析文档并提取JSON格式的数据  
    json_objs = parser.get_json_result(FILE_NAME)  
    json_list = json_objs[0]["pages"]  

    # 获取文本节点  
    text_nodes = get_text_nodes(json_list)  

    # 下载并提取到指定路径的图像  
    image_documents = get_image_nodes(json_objs, IMAGES_DOWNLOAD_PATH)  

    # 将提取的文本保存为.txt文件  
    file_path = "parsed_data/extracted_texts.txt"  
    save_texts_to_file(text_nodes, file_path)

这里是一个节点提取文本和元数据的截图。

由LlamaParse提取文本内容

我把文本数据保存到一个文本文件里。这里是一段文本文件中的文本内容。

文本快照(附上,存储在.txt文件中)

这是文件夹内解析后数据的结构如下

从产品中提取的图片及其文字说明

请特别注意,文本描述与相应的图片没有关联。目的是展示,由于文本和相关图片存储在同一共享嵌入空间中,彼此接近,嵌入模型能够在响应查询时检索出文本及其相关图片。

Cohere的试用API允许每分钟5次API调用的限制,,为了将目录中的所有图片嵌入,我为此创建了以下自定义类,将提取的图片发送到嵌入模型,并添加了30秒的延迟(也可以尝试较短的延迟)。

    delay = 30  
    # 定义一个自定义嵌入类,在每次嵌入后带有固定的延迟  
    class DelayCohereEmbedding(CohereEmbedding):  
        def get_image_embedding_batch(self, img_file_paths, show_progress=False):  
            embeddings = []  
            for img_file_path in img_file_paths:  
                embedding = self.get_image_embedding(img_file_path)  
                embeddings.append(embedding)  
                print(f"等待 {delay} 秒")  
                time.sleep(12)  # 在每次嵌入后添加固定的 12 秒等待时间  
            return embeddings  

    # 在设置中将自定义嵌入模型设置为  
    Settings.embed_model = DelayCohereEmbedding(  
        api_key=COHERE_API_KEY,  
        model_name="embed-english-v3.0"  
    )

以下代码从目录中加载解析文档,并创建一个_Qdrant_多模态向量数据库和索引(参考LlamaIndex实现)。

    # 从目录中加载文档  
    documents = SimpleDirectoryReader("parsed_data",  
                                      required_exts=[".jpg", ".png", ".txt"],  
                                      exclude_hidden=False).load_data()  

    # 设置Qdrant向量存储库  
    client = qdrant_client.QdrantClient(path="furniture_db")  
    text_store = QdrantVectorStore(client=client, collection_name="text_collection")  
    image_store = QdrantVectorStore(client=client, collection_name="image_collection")  
    storage_context = StorageContext.from_defaults(vector_store=text_store, image_store=image_store)  

    # 建立索引  
    index = MultiModalVectorStoreIndex.from_documents(  
        documents,  
        storage_context=storage_context,  
        image_embed_model=Settings.embed_model,  
    )

最后,创建一个多模态检索器,用来从多模态矢量数据库中检索出与之匹配的文本和图像节点。其中,_similarity_topk 和 _image_similarity_topk 分别定义了检索的文本节点和图像的数量。

    retriever_engine = index.as_retriever(similarity_top_k=4, image_similarity_top_k=4) # 创建检索引擎,设置相似度和图片相似度的top k值为4

我们要测试一下这个查询“找一把带有金属支架的椅子”的检索器。辅助函数_display_images_会展示检索到的图像。

    ### 测试检索代码  
    from llama_index.core.response.notebook_utils import display_source_node  
    from llama_index.core.schema import ImageNode  
    import matplotlib.pyplot as plt  
    from PIL import Image  

    def display_images(file_list, grid_rows=2, grid_cols=3, limit=9):  
        """  
        从文件路径列表中显示图片到网格中。  
        参数:  
            - file_list: 图片文件路径列表。  
            - grid_rows: 网格行数。  
            - grid_cols: 网格列数。  
            - limit: 最多显示的图片数量。  
        """  
        plt.figure(figsize=(16, 9))  
        count = 0  

        for idx, file_path in enumerate(file_list):  
            if os.path.isfile(file_path) and count < limit:  
                img = Image.open(file_path)  
                plt.subplot(grid_rows, grid_cols, count + 1)  
                plt.imshow(img)  
                plt.axis('off')  
                count += 1  

        plt.tight_layout()  
        plt.show()  

    query = "找到一把有金属腿的椅子"  
    retrieval_results = retriever_engine.retrieve(query)  

    retrieved_image = []  
    对于检索结果中的每个 res_node:  
        if isinstance(res_node.node, ImageNode):  
            retrieved_image.append(res_node.node.metadata["file_path"])  
        else:  
            display_source_node(res_node, source_length=200)  

    display_images(retrieved_image)

下面展示了检索器找到的文本内容和图片。

多模态检索器检索到的文本内容和图像

这里找到的文本节点和图片与查询相似,但可能并非全部相关。接下来需要将这些文本节点和图片发送给一个多模态大型语言模型,以便精炼选择过程并生成最终响应。提示模板_qa_tmpl_str_指引多模态大型语言模型进行选择和生成响应的过程。

    import logging  
    from llama_index.core.schema import NodeWithScore, ImageNode, MetadataMode  

    # 定义具有明确指令的模板  
    qa_tmpl_str = (  
        "下面的上下文信息。\n"  
        "---------------------\n"  
        "{context_str}\n"  
        "---------------------\n"  
        "使用提供的上下文和图片(而不是先前的知识),回答问题。仅包括与答案直接相关的图片路径。\n"  
        "回答应按照如下格式:\n"  
        "答案:[基于上下文的答案]\n"  
        "相关图片路径:仅与答案直接相关的图片路径,以逗号分隔\n"  
        "查询:{query_str}\n"  
        "回答: "  
    )  

    qa_tmpl = PromptTemplate(qa_tmpl_str)  
    # 初始化多模态语言模型  
    multimodal_llm = OpenAIMultiModal(model="gpt-4o", temperature=0.0, max_tokens=1024)  
    # 使用检索器和提示模板设置查询引擎  
    query_engine = index.as_query_engine(  
        llm=multimodal_llm,  
        text_qa_template=qa_tmpl,  
        retriever=retriever_engine  
    )

以下代码首先生成上下文字符串_ctxst,通过准备具有有效路径和元数据的图像节点。然后将查询字符串嵌入提示模板_qa_tmplstr。接着,将带有嵌入上下文的提示模板发送给LLM以生成最终响应。

    # 提取底层节点
    nodes = [node.node for node in retrieval_results]

    # 使用有效路径和元数据创建 ImageNode 实例
    image_nodes = []
    for n in nodes:
        if "file_path" in n.metadata and n.metadata["file_path"].lower().endswith(('.png', '.jpg')):
            # 使用只包含路径和 MIMETYPE 的 ImageNode,以符合 LLM 的期望
            image_node = ImageNode(
                image_path=n.metadata["file_path"],
                image_mimetype="image/jpeg" if n.metadata["file_path"].lower().endswith('.jpg') else "image/png"
            )
            image_nodes.append(NodeWithScore(node=image_node))
            logging.info(f"ImageNode 创建完成,路径为: {n.metadata['file_path']}")

    logging.info(f"准备了 {len(image_nodes)} 个 ImageNodes 供 LLM 使用")

    # 为提示创建上下文字符串
    ctx_str = "\n\n".join(
        [n.get_content(metadata_mode=MetadataMode.LLM).strip() for n in nodes]
    )

    # 格式化提示
    fmt_prompt = qa_tmpl.format(context_str=ctx_str, query_str=query)

    # 使用多模态 LLM 生成响应文本
    llm_response = multimodal_llm.complete(
        prompt=fmt_prompt,
        image_documents=[image_node.node for image_node in image_nodes],  # 只传递路径的 ImageNode 对象
        max_tokens=300
    )

    # 提取 LLM 响应中的实际文本内容
    response_text = llm_response.text

    # 查找响应文本中 'Relevant Image Paths:' 后的路径
    image_paths = re.findall(r'Relevant Image Paths:\s*(.*)', response_text)
    if image_paths:
        # 如果存在多个路径,则按逗号分割并去除多余空格
        image_paths = [path.strip() for path in image_paths[0].split(",")]

    # 从响应中过滤掉 'Relevant Image Paths' 部分
    filtered_response = re.sub(r'Relevant Image Paths:.*', '', response_text).strip()

    display(Markdown(f"**问题**: {query}"))

    # 打印过滤后的响应,不带图片路径
    display(Markdown(f"{filtered_response}"))

    if image_paths != ['']:
        # 使用从 image_paths 数组中收集的路径显示图片
        display_images(image_paths)

LLM(大型语言模型)生成的最终(经过过滤)回复如下:

最终(经过过滤的)回应由LLM提供(注:图片由作者提供)

这说明嵌入模型成功地将文本的信息与图像的信息连接起来,并找到相关的信息,这些信息随后由大模型进一步优化。

以下显示了几个额外的测试查询的结果。

木质餐桌和木椅的搜索到的结果,(图片由作者提供)

搜索到的时尚办公桌图片(作者供图)

搜索到的经典旧式床头柜

现在我们来测试一下多模态嵌入模型在图像到图像任务上的效果。我们将使用目录中没有的产品图像,并利用检索器找到匹配的产品图像。以下代码使用修改后的辅助函数 _displayimages 来检索匹配的产品图像。

    import matplotlib.pyplot as plt  
    from PIL import Image  
    import os  

    def display_images(input_image_path, matched_image_paths):  
        """  
        在适当标签下展示输入图像及其匹配的图像。  
        """  
        # 展示的总图像数量(输入图像 + 匹配的图像)  
        total_images = 1 + len(matched_image_paths)  

        # 定义图像大小  
        plt.figure(figsize=(7, 7))  

        # 展示输入图像  
        plt.subplot(1, total_images, 1)  
        if os.path.isfile(input_image_path):  
            input_image = Image.open(input_image_path)  
            plt.imshow(input_image)  
            plt.title("原始图像")  
            plt.axis("off")  

        # 展示匹配的图像  
        for idx, img_path in enumerate(matched_image_paths):  
            if os.path.isfile(img_path):  
                matched_image = Image.open(img_path)  
                plt.subplot(1, total_images, idx + 2)  
                plt.imshow(matched_image)  
                plt.title("匹配图像")  
                plt.axis("off")  

        plt.tight_layout()  
        plt.show()  

    # 使用指定路径的示例
    input_image_path = 'C:/Users/h02317/Downloads/trial2.png'  

    retrieval_results = retriever_engine.image_to_image_retrieve(input_image_path)  
    retrieved_images = [res.node.metadata["file_path"] for res in retrieval_results]  

    # 并排显示这些图像
    display_images(input_image_path, retrieved_images[:2])  

以下是一些输入和输出图像的配对结果展示。

输入的图像以及多模态检索器检索到的匹配图像(作者供图)

一张输入图像及其由多模态检索工具检索到的匹配图像(作者提供)

这些结果显示,这种多模态嵌入模型在文本到文本、文本到图像和图像到图像任务中表现出色的性能。此模型还可以进一步用于探索处理大型文档的多模态RAG,以增强多样化数据类型的检索体验。

此外,多模态嵌入模型技术在各种业务应用中具有良好的潜力,包括个性化推荐、内容审核、跨模态搜索引擎以及客户服务自动化。这些模型可以助力公司构建更丰富的用户体验和更高效的检索知识体系。

如果喜欢这篇文章,请点个赞哦,并在 Medium 和/或 LinkedIn 上关注我。

GitHub(一个程序员常用的代码托管网站)

请查看我的GitHub仓库中的完整代码。

GitHub - umairalipathan1980/Multimodal-search-with-multimodal-embeddings: 多模态信息检索与多模态嵌入……github.com
點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消