文本+图像实现多模态数据分类

在 AI 中,最令人兴奋的增长领域之一是多模态学习,其中模型处理和组合不同类型的数据(例如图像和文本),以更好地理解复杂场景。这种方法在实际应用中特别有用,因为信息通常分为文本和视觉效果。

以电子商务为例:产品列表可能包括显示产品外观的图像和提供有关其功能的详细信息的描述。要完全分类和理解产品,需要同时考虑这两个信息源。多模态大型语言模型 (LLM)(如 Gemini 1.5、Llama 3.2、Phi-3 Vision)和开源工具(如 LlaVA、DocOwl)是专门为处理这些类型的输入而开发的。

1、多模态模型为何重要

来自图像和文本的信息可以相互补充,而单模态系统可能会忽略这一点:

  • 产品描述可能会提到其尺寸或材料,而仅从图像中无法清楚看出这一点。
  • 另一方面,图像可能会揭示文本无法充分描述的关键方面,例如样式或颜色。

如果我们仅单独处理图像或文本,则可能会遗漏关键细节。多模态模型通过在处理过程中结合两种来源来解决这一挑战,从而产生更准确、更有用的结果。

2、本教程的内容

本教程将指导你创建一个用于处理图像文本分类的管道。你将学习如何处理和分析结合了视觉和文本元素的输入,从而获得比纯文本系统更准确的结果。

要成功构建多模态图像文本分类系统,我们需要三个基本组件。以下是每个元素的细分:LLM提供商、LangChain库和分类任务。

本教程的完整代码:llmclassifier/llm_multi_modal_classifier.py

2.1 可靠的 LLM 提供商

本教程的主干是托管的 LLM 即服务。在尝试了几种选项后,我发现并非所有 LLM 都能提供一致的结果,尤其是在处理结构化输出时。以下是我的经验总结:

  • Groq 和 Fireworks.ai

这些平台以无服务器、按令牌付费的格式提供多模态 LLM。虽然它们看起来很有前途,但它们的 API 在遵循结构化输出请求时存在问题。

例如,当发送具有预定义架构的查询时,返回的输出不符合预期的格式,这使得它们对于需要精确度的任务来说不可靠。Groq 的 Llama 3.2 仍处于预览阶段,所以也许我以后会再试一次。 Fireworks.ai 通常不会回复错误报告,所以从现在开始我会将它们从我的选项中删除。

  • Gemini 1.5

经过反复试验,我选择了 Gemini 1.5。它始终以所需的格式返回结果,到目前为止运行良好。不过,如果你花足够长的时间研究它,你会发现它仍然有自己的怪癖(比如你不能使用太大的枚举……)。我们将在后面的文章中讨论它们。这将是我们在本教程中使用的 LLM。

2.2 Python 库:LangChain

为了与 LLM 交互并处理多模式输入,我们将使用 LangChain 库。LangChain 特别适合这项任务,因为它允许我们:

  • 将文本和图像数据作为输入注入 LLM。
  • 为不同的 LLM 即服务提供商定义通用抽象。
  • 定义结构化输出模式以确保结果符合我们需要的格式。

结构化输出对于分类任务尤其重要,因为它们涉及输出必须符合的预定义类。 LangChain 确保强制执行此结构,使其成为我们用例的理想选择。

2.3 分类任务:摄影图像的关键字建议

我们将在本教程中重点介绍的任务是摄影相关图像的关键字建议。这是一个多标签分类问题,这意味着:

  • 每个图像可以同时属于多个类。
  • 可能的类别列表是预定义的。

例如,由图像及其描述组成的输入可能会使用诸如风景、日落和自然等关键字进行分类。虽然多个关键字可以应用于单个输入,但必须从预定义的类集中选择它们。

3、实现多模态图像文本分类

现在我们已经介绍了基础概念,让我们深入了解实现。本分步指南将引导你完成配置 Gemini 1.5、设置 LangChain,以及为摄影相关图像构建关键字建议系统。

3.1 获取 Gemini API 密钥

第一步是获取你的 Gemini API 密钥,你可以在 Google AI Studio 中生成该密钥。获得密钥后,将其导出到名为 GOOGLE_API_KEY 的环境变量。你可以:

将其添加到 .env 文件中:

GOOGLE_API_KEY=your_api_key_here

直接在终端中导出:

export GOOGLE_API_KEY=your_api_key_here

3.2 安装并初始化客户端

接下来,安装必要的库:

pip install langchain-google-genai~=2.0.4 langchain~=0.3.6

安装后,初始化客户端:

import os
from langchain_google_genai import ChatGoogleGenerativeAI

GOOGLE_MODEL_NAME = os.environ.get("GOOGLE_MODEL_NAME", "gemini-1.5-flash-002")

llm_google_client = ChatGoogleGenerativeAI(
    model=GOOGLE_MODEL_NAME,
    temperature=0,
    max_retries=10,
)

3.3 定义输出模式

要为确保 LLM 产生有效、结构化的结果,我们使用 Pydantic 来定义输出模式。此模式充当过滤器,验证模型返回的类别是否符合我们预定义的可接受值列表。

from typing import List, Literal
from pydantic import BaseModel, field_validator

def generate_multi_label_classification_model(list_classes: list[str]):
    assert list_classes  # Ensure classes are provided

    class ClassificationOutput(BaseModel):
        category: List[Literal[tuple(list_classes)]]

        @field_validator("category", mode="before")
        def filter_invalid_categories(cls, value):
            if isinstance(value, list):
                return [v for v in value if v in list_classes]
            return []  # Return an empty list if input is invalid

    return ClassificationOutput

为什么需要 field_validator 作为解决方法?

在定义模式时,我们在 Gemini 1.5(和类似的 LLM)中遇到了一个限制:它们不严格执行枚举。这意味着即使我们提供了一组固定的类别,模型也可能返回该集合之外的值。例如:

  • 预期:[“landscape”、“forest”、“mountain”]
  • 返回:[“landscape”、“ocean”、“sun”],其中“ocean”和“sun”为无效类别

如果不处理此问题,无效类别可能会导致错误或降低分类的准确性。为了解决这个问题,可以使用 field_validator 方法作为解决方法。它充当过滤器,确保:

  • 输出中仅包含 list_classes 中的有效类别。
  • 删除无效或意外的值。

此保护措施可确保模型的结果符合任务的要求。我们必须这样做很烦人,但这似乎是我测试的所有 LLM 提供商的常见问题,如果你知道哪个可以很好地处理枚举,请告诉我。

3.4 将模式绑定到 LLM 客户端

接下来,将模式绑定到客户端以进行结构化输出处理:

list_classes = [
    "shelter", "mesa", "dune", "cave", "metropolis",
    "reef", "finger", "moss", "pollen", "daisy",
    "fire", "daisies", "tree trunk",  # Add more classes as needed
]

categories_model = generate_multi_label_classification_model(list_classes)
llm_classifier = llm_google_client.with_structured_output(categories_model)

3.5 构建查询并调用 LLM

定义预测函数以将图像和文本输入发送到 LLM:

...
    def predict(self, text: str = None, image_url: str = None) -> list:
        assert text or image_url, "Provide either text or an image URL."

        content = []

        if text:
            content.append({"type": "text", "text": text})

        if image_url:
            image_data = base64.b64encode(httpx.get(image_url).content).decode("utf-8")
            content.append(
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/jpeg;base64,{image_data}"},
                }
            )

        prediction = self.llm_classifier.invoke(
            [SystemMessage(content=self.system_prompt), HumanMessage(content=content)]
        )

        return prediction.category

要将图像数据发送到 Gemini LLM API,我们需要将图像编码为模型可以处理的格式。这就是 base64 编码发挥作用的地方。

什么是 Base64?

Base64 是一种二进制到文本的编码方案,可将二进制数据(如图像)转换为文本格式。这在传输可能与基于文本的系统(如 API)不兼容的数据时非常有用。通过将图像编码为 base64,我们可以在将数据发送到 LLM 时将其作为有效负载的一部分包含在内。

3.6 获取多标签关键字结果

最后,运行分类器并查看结果。让我们用一个例子来测试它:

示例输入 1:

  • 图像:
Calvin Ma 在 Unsplash 上的照片
  • 描述:
classic red and white bus parked beside road
翻译:停在路边的经典红白巴士

结果:

  • 图像 + 文本:
['transportation', 'vehicle', 'road', 'landscape', 'desert', 'rock', 'mountain']
  • 仅文本:
['transportation', 'vehicle', 'road']

如图所示,当同时使用文本和图像输入,结果与实际内容更相关。对于纯文本输入,LLM 给出了正确但不完整的值。

示例输入 2:

  • 图像:
Tadeusz Lakota 在 Unsplash 上的照片

描述:

black and white coated dog
翻译:黑白相间的狗

结果:

  • 图像 + 文本:
['animal', 'mammal', 'dog', 'pet', 'canine', 'wildlife']
  • 纯文本:
['animal', 'mammal', 'canine', 'dog', 'pet']

4、结束语

多模态分类结合了文本和图像数据,提供了一种创建更具上下文感知和更有效的 AI 系统的方法。在本教程中,我们使用 Gemini 1.5 和 LangChain 构建了一个关键字建议系统,解决了结构化输出处理和编码图像数据等关键挑战。

通过混合文本和视觉输入,我们展示了这种方法如何比单独使用任何一种模式实现更准确、更有意义的分类。实际示例强调了组合数据类型的价值,以更好地捕捉给定场景的完整上下文。

本教程重点介绍文本和图像分类,但这些原则可以应用于其他多模式设置。以下是一些接下来要探索的想法:

  • 文本和视频:通过将视频帧采样与文本输入(如字幕或元数据)集成在一起,扩展系统以对视频进行分类或分析。
  • 文本和 PDF:开发分类器来处理内容丰富的文档,如科学论文、合同或简历,将视觉布局与文本数据相结合。
  • 实际应用:将此管道集成到电子商务网站、教育工具或社交媒体审核系统等平台中。

这些方向展示了多模式方法的灵活性及其解决各种现实挑战的潜力。随着多模态人工智能的发展,尝试各种输入组合将为更智能、响应更快的系统开辟新的可能性。


原文链接:Integrating Text and Images for Smarter Data Classification

汇智网翻译整理,转载请标明出处