第二十七章:多模态AI

从单一模态到多模态融合 —— 让AI同时理解文字、图片、声音与视频

本章学习目标

  • 理解多模态AI的基本概念,区分单模态与多模态模型的差异
  • 掌握CLIP、BLIP-2、GPT-4V等主流多模态模型的架构原理
  • 学会使用Python加载预训练视觉-语言模型进行图文理解
  • 了解多模态融合的三种主要策略:早期融合、晚期融合与交叉注意力
  • 能够构建简单的图文检索和图像描述生成应用
  • 理解多模态对齐、跨模态表示学习的核心思想
  • 认识多模态AI的局限性和未来发展方向

前置知识

  • 第11章:神经网络基础 —— 理解前馈网络和反向传播
  • 第16章:自然语言处理 —— 掌握Transformer编码器和注意力机制
  • 第20章:卷积神经网络 —— 了解CNN的基本结构和卷积操作
  • Python基础与PyTorch使用经验
  • 了解softmax、交叉熵损失等基本概念
多模态AI架构与融合策略图
图27-1 多模态AI架构:文本、图像、音频、视频模态的融合与对齐

人类感知世界的方式从来不是单一的 —— 我们同时用眼睛看、耳朵听、大脑综合理解。当你看到一张朋友在海边微笑的照片时,你的大脑同时处理了视觉信息(面孔、表情、海浪)和语义信息("这是我的朋友"、"开心"、"度假")。多模态AI正是模仿这种能力,让机器能够同时处理和关联来自不同来源(文本、图像、音频、视频)的信息。本章将带你从概念到实践,系统认识这一前沿领域。

27.1 什么是多模态AI

多模态 (Multimodal) 指的是两种或两种以上的信息模态。在AI领域,常见的模态包括:

  • 文本 (Text) — 自然语言描述、对话、文档、代码
  • 图像 (Image) — 照片、图表、截图、医学影像
  • 音频 (Audio) — 语音、音乐、环境声、音频事件
  • 视频 (Video) — 时序图像序列,包含视觉和听觉双重信息
  • 3D/深度 (Depth) — 点云、深度图、3D网格模型
  • 触觉/力觉 (Tactile) — 机器人触觉传感器数据
  • 传感器数据 (Sensor) — 激光雷达、IMU、GPS等

单模态模型(如纯文本GPT-3、ResNet图像分类器、Whisper语音识别)只处理一种类型的数据。而多模态模型的核心目标是建立跨模态关联——理解"一张猫的图片"和"一只猫"这两个不同模态的表达指向同一概念。

💡 多模态的数学直觉

从数学角度看,多模态融合本质上是将不同模态的表示向量映射到一个共享的语义空间(Shared Semantic Space)。在这个空间中,语义相近的内容(无论来自哪个模态)应当具有相近的向量表示。用公式表达就是:给定图像 \(I\) 和文本 \(T\),我们希望 \(\text{sim}(f_I(I), f_T(T))\) 在语义匹配时最大化。

为什么需要多模态?现实世界的信息天然是多模态的。医生需要同时查看影像(CT/MRI)和文本病历来诊断疾病;电商客服需要理解用户上传的商品图片和文字描述才能准确回答问题;自动驾驶系统需要融合摄像头、激光雷达、高精地图和语音指令才能安全行驶。单一模态无法提供完整的语义理解。

模态的详细分类与特征

每种模态都有独特的数据结构和处理方式。理解这些差异是设计多模态系统的第一步。例如,文本是离散的符号序列,而图像是连续的像素矩阵;音频具有时频双重结构,而视频则在图像基础上增加了时间维度。不同的数据结构决定了它们需要不同的编码器和预处理流程。

模态 数据结构 典型编码器 特征维度示例 token数量(224×224图像/512词文本)
文本 离散符号序列 Transformer (BERT/GPT) 768 / 4096 ~512 tokens
图像 连续像素矩阵 (H×W×C) CNN / ViT 768 / 1024 ~196-576 patches
音频 时频谱图 / 波形 Whisper / HuBERT 512 / 768 ~3000 frames/30s
视频 时序图像帧序列 ViT + Temporal Attention 768 / 1024 ~数千至数万tokens
3D/点云 非结构化点集 (N×3) PointNet / PointBERT 256 / 512 ~1024-8192 points

多模态系统的设计核心挑战在于:如何让这些结构迥异的数据在同一个语义空间中对齐。这不仅仅是维度对齐的问题,更是语义层面的对齐——让"猫"这个文字和猫的图像在数学上表示为相似的向量。

多模态AI的发展历程

多模态AI并非突然出现,而是经历了几十年的渐进发展。早期的研究主要集中在图像描述生成(Image Captioning)和视觉问答(VQA)这两个任务上。2021年,OpenAI发布的CLIP标志着多模态AI进入了新的阶段——通过大规模对比学习,模型可以将图像和文本映射到同一空间。2023年,GPT-4V和BLIP-2的出现将多模态AI推向了对话式理解的新高度。

多模态AI关键里程碑

2014-2015
Visual Attention / show-and-tell

图像描述的开端

2017-2019
ViLBERT / VisualBERT

预训练多模态模型

2021
CLIP / DALL-E / ALIGN

对比学习 + 大规模预训练

2022-2023
BLIP-2 / LLaVA / GPT-4V

对话式多模态理解

2024-2025
Gemini / Sora / GPT-4o

原生多模态 + 生成

值得注意的是,多模态AI的发展与大语言模型(LLM)的进步密切相关。早期的多模态模型(如VisualBERT)参数量只有几亿,而如今的GPT-4V、Gemini等模型参数量已达数千亿甚至万亿级别。这种规模的提升使得模型能够处理更复杂的跨模态推理任务,例如理解图像中的幽默、推理场景中物体的因果关系等。

为什么现在是多模态AI的爆发期?

三个关键因素推动了多模态AI的快速发展:

  • 大规模配对数据:互联网上存在海量的图文对(如网页图片与Alt文本)、视频与字幕等天然的多模态数据。CLIP正是利用了从互联网爬取的4亿个图文对进行训练。
  • 预训练视觉编码器的成熟:ViT、CLIP ViT等视觉编码器已经能够在大规模数据上提取高质量的视觉特征。这使得多模态模型可以站在"巨人的肩膀上",无需从头训练视觉编码器。
  • 大语言模型的涌现能力:LLaMA、GPT等大语言模型展现出了强大的推理和泛化能力。通过将视觉信息"注入"这些模型,我们可以直接利用这些能力处理视觉任务,而无需为每个视觉任务单独训练模型。

多模态AI应用场景

视觉问答
(VQA)

图像描述
(Image Captioning)

图文检索
(Image-Text Retrieval)

视频理解
(Video QA)

医疗影像
分析

具身智能
(Embodied AI)

文生图
(Text-to-Image)

UI理解
(GUI Agent)

单模态 vs 多模态:核心差异

维度 单模态模型 多模态模型
输入 单一类型(仅文本或仅图像) 多种类型(文本+图像+...)
训练数据 单模态标注数据 跨模态配对数据
表示空间 单一语义空间 共享对齐语义空间
典型架构 Transformer / CNN 多编码器 + 融合模块
代表模型 GPT-4, ResNet, BERT GPT-4V, BLIP-2, Gemini

27.2 核心架构:视觉编码器与语言模型的融合

多模态大模型的主流架构可以概括为一个经典三段式:视觉编码器投影层/融合模块语言模型。这种架构的关键在于,将视觉信息"翻译"成语言模型能够理解的表示。

为什么是这样的三段式?因为语言模型(如LLaMA、GPT)是目前最强大的"思考引擎",它拥有强大的推理、规划和生成能力。如果我们能让语言模型"看懂"图像,就能直接利用这些能力进行视觉推理。因此,多模态大模型的设计哲学是:让视觉编码器负责"看",让语言模型负责"想",中间用一个轻量级的模块来连接两者。

架构图解

多模态融合架构:视觉编码器与语言模型的融合策略

视觉编码器选型

视觉编码器负责将原始图像转换为特征向量序列。它是多模态模型"看"世界的"眼睛"。不同的视觉编码器有不同的特性,选择合适的编码器对最终性能至关重要。

视觉编码器的核心任务是将二维图像转换为一组特征向量(tokens)。在ViT架构中,一张224×224的图像首先被切分为196个16×16的patch,每个patch通过线性投影映射为一个特征向量。加上一个可学习的[CLS]token后,这些向量被送入标准的Transformer编码器。最终,编码器输出197个(1 CLS + 196 patch)特征向量,每个向量的维度取决于模型大小(如ViT-B/16为768维)。

为什么ViT比CNN更适合多模态?CNN的卷积操作本质上是局部特征提取,而Transformer的自注意力机制可以捕获全局关系。对于多模态任务,模型需要理解图像中不同区域与文本中不同词语的对应关系,这种全局关系建模正是Transformer的优势所在。此外,ViT输出的特征向量序列可以直接与文本token序列拼接,无需额外的特征转换。

  • ViT (Vision Transformer):将图像切分为16×16的patch序列,用Transformer编码器处理。这是当前多模态模型的首选架构,因为它天然输出序列特征,便于与文本token对接。
  • CLIP ViT:经过图文对比学习预训练的ViT,天然具备语义对齐能力。CLIP ViT的特征更"语义化",因为它在训练时就学会了与文本对齐。
  • SigLIP:Google提出的改进CLIP变体,使用sigmoid损失替代softmax,在大规模训练中更稳定,被Gemini系列使用。
  • DINOv2:Meta提出的自监督ViT,不依赖文本,但在视觉任务上表现出色。适合需要精细视觉特征的场景。

投影层的设计

投影层是多模态模型中最灵活的部分,它的设计直接决定了视觉信息如何被语言模型"消化"。根据不同的设计思路,投影层可以分为以下几种类型:

1. 线性投影(Linear Projection):最简单的方法,使用一个线性变换将视觉特征维度映射到语言模型的输入维度。优点是计算量小、训练快;缺点是表达能力有限,无法学习复杂的跨模态关系。

2. MLP投影(MLP Adapter):使用多层感知机进行非线性映射。LLaVA采用的方法是两层MLP(视觉维度→4倍中间维度→语言模型维度),中间使用GELU激活函数。相比线性投影,MLP能学习更复杂的映射关系。

3. Q-Former:BLIP-2提出的方法,使用一组可学习的查询向量(通常32个)从视觉特征中提取信息。这些查询向量通过交叉注意力机制与视觉特征交互,然后输出固定数量的特征向量送给语言模型。Q-Former的优势是能够自适应地选择最相关的视觉信息,而非被动地接收所有视觉特征。

4. 交叉注意力(Cross-Attention):在语言模型的每一层中插入交叉注意力模块,让文本token直接与视觉特征交互。这种方法提供了最深层的跨模态交互,但计算量最大。

选择哪种投影层取决于任务需求和资源限制。对于快速原型开发,MLP投影是最佳选择;对于追求最佳性能,交叉注意力值得尝试;对于资源受限的场景,线性投影或Q-Former更为合适。

Python - 不同类型的投影层实现
import torch
import torch.nn as nn

class LinearProjection(nn.Module):
    def __init__(self, vision_dim, llm_dim):
        super().__init__()
        self.proj = nn.Linear(vision_dim, llm_dim)

    def forward(self, vision_features):
        return self.proj(vision_features)

class MLPProjection(nn.Module):
    def __init__(self, vision_dim, llm_dim, hidden_mult=4):
        super().__init__()
        self.proj = nn.Sequential(
            nn.Linear(vision_dim, llm_dim * hidden_mult),
            nn.GELU(),
            nn.Linear(llm_dim * hidden_mult, llm_dim),
        )

    def forward(self, vision_features):
        return self.proj(vision_features)

class QFormerProjection(nn.Module):
    def __init__(self, vision_dim, llm_dim, num_queries=32, num_heads=8):
        super().__init__()
        self.queries = nn.Parameter(torch.randn(1, num_queries, llm_dim))
        self.cross_attn = nn.MultiheadAttention(
            embed_dim=llm_dim, num_heads=num_heads,
            kdim=vision_dim, vdim=vision_dim, batch_first=True
        )
        self.norm = nn.LayerNorm(llm_dim)

    def forward(self, vision_features):
        batch_size = vision_features.shape[0]
        queries = self.queries.expand(batch_size, -1, -1)
        attended, _ = self.cross_attn(queries, vision_features, vision_features)
        return self.norm(attended)
💡 投影层设计的关键原则

无论选择哪种投影层,设计时都需要考虑三个关键因素:(1)维度匹配:视觉编码器输出维度和语言模型输入维度通常不匹配,投影层的首要任务是解决维度不一致问题;(2)信息压缩:视觉特征的token数量通常远多于语言模型能处理的长度,需要进行信息压缩(如Q-Former)或降采样;(3)训练效率:投影层的参数量应该远小于语言模型,以保证训练的可行性。

import torch
from PIL import Image
from transformers import CLIPVisionModel, CLIPImageProcessor

model_name = "openai/clip-vit-base-patch32"
processor = CLIPImageProcessor.from_pretrained(model_name)
model = CLIPVisionModel.from_pretrained(model_name)
model.eval()

image = Image.open("example.jpg")
inputs = processor(images=image, return_tensors="pt")

with torch.no_grad():
    outputs = model(**inputs)

print(f"最后隐藏层形状: {outputs.last_hidden_state.shape}")
# [1, 50, 768] -> [batch, 1个CLS + 49个patch, 特征维度]

print(f"池化输出形状: {outputs.pooler_output.shape}")
# [1, 768] -> 全局图像表示

patch_features = outputs.last_hidden_state[:, 1:, :]
print(f"Patch特征形状: {patch_features.shape}")
# [1, 49, 768] -> 7x7=49个视觉token