引言

近年来,多模态大模型已经从单纯的“图像问答模型”逐渐发展为能够处理文本、图像、音频、视频甚至操作指令的统一智能系统。GPT-4V、Gemini、Qwen-VL、LLaVA 等模型能够理解图片内容,Stable Diffusion、Midjourney 能够根据文字生成图像,Sora 等视频生成模型则进一步将视觉理解、空间建模和时间建模结合起来。

很多开发者在使用多模态模型时,容易把它理解成“给语言模型增加一个图片输入”。这种理解并不完整。真正的多模态系统通常包含视觉编码器、模态对齐层、语言模型、生成解码器、工具调用模块和数据反馈系统。图像并不是直接进入语言模型,而是首先被转换成一组视觉特征,再通过投影层映射到语言模型可以处理的向量空间中。

因此,理解多模态大模型的底层能力和边界,需要回答几个问题:

  1. 图像是如何转换成模型可以理解的表示的?
  2. 视觉信息如何与文本语义空间对齐?
  3. 大模型究竟是在“看图”,还是在预测视觉特征对应的文本?
  4. 多模态模型为什么会出现视觉幻觉?
  5. 多模态模型的能力边界由哪些因素决定?
  6. 如何通过工程手段提升模型在真实业务中的可靠性?

本文将从模型结构、数据流、训练方式、推理流程和能力边界几个方面进行分析,并通过代码展示一个简化的多模态模型实现。


一、多模态大模型的整体架构

一个典型的视觉语言模型可以抽象为以下结构:

图像
  |
  v
视觉编码器
  |
  v
视觉特征向量
  |
  v
模态投影层
  |
  v
视觉Token
  |
  +------ 文本Token
             |
             v
        大语言模型
             |
             v
       文本或工具调用结果

如果模型还支持图像生成,则结构通常有所不同:

文本提示词
    |
    v
文本编码器
    |
    v
条件向量
    |
    v
扩散模型或自回归生成模型
    |
    v
图像解码器
    |
    v
生成图像

视觉理解模型和视觉生成模型虽然都属于多模态模型,但底层目标不完全相同。

视觉理解模型的目标通常是:

P(文本 | 图像, 文本提示)

也就是根据图像和问题预测回答。

图像生成模型更接近:

P(图像 | 文本提示)

或者在扩散模型中,通过逐步去噪预测真实图像分布。

视频生成模型还需要进一步建模:

P(视频帧序列 | 文本, 初始图像, 时序条件)

这意味着它除了理解单帧语义,还要考虑物体持续性、运动轨迹、遮挡关系和时间一致性。


二、视觉编码器:模型如何“读取”图像

1. 图像切分为Patch

大部分视觉Transformer模型不会直接处理完整图像,而是将图像切分成固定大小的图像块,也就是Patch。

假设输入图片大小为:

224 × 224

Patch大小为:

16 × 16

则图像会被切分为:

224 / 16 × 224 / 16 = 14 × 14 = 196个Patch

每个Patch会被展平并映射到一个固定维度的向量。例如:

16 × 16 × 3 = 768

经过线性变换后,可以得到:

768维 -> 1024维

最终,一张图片就被表示为长度为196、维度为1024的视觉Token序列。

2. 使用卷积实现Patch Embedding

下面使用PyTorch实现一个简化版的视觉Patch编码器:

import torch
import torch.nn as nn


class PatchEmbedding(nn.Module):
    """
    将输入图像切分为Patch,并映射为视觉Token。
    输入:
        [batch_size, channels, height, width]
    输出:
        [batch_size, patch_count, embed_dim]
    """

    def __init__(
        self,
        image_size=224,
        patch_size=16,
        in_channels=3,
        embed_dim=768
    ):
        super().__init__()

        if image_size % patch_size != 0:
            raise ValueError("image_size必须能够被patch_size整除")

        self.grid_size = image_size // patch_size
        self.patch_count = self.grid_size * self.grid_size

        self.projection = nn.Conv2d(
            in_channels=in_channels,
            out_channels=embed_dim,
            kernel_size=patch_size,
            stride=patch_size
        )

    def forward(self, images):
        """
        images: [B, 3, 224, 224]
        """
        features = self.projection(images)

        # [B, D, H/P, W/P] -> [B, H/P, W/P, D]
        features = features.permute(0, 2, 3, 1)

        # [B, grid_h, grid_w, D] -> [B, patch_count, D]
        features = features.flatten(1, 2)

        return features


if __name__ == "__main__":
    images = torch.randn(2, 3, 224, 224)

    encoder = PatchEmbedding(
        image_size=224,
        patch_size=16,
        embed_dim=768
    )

    visual_tokens = encoder(images)

    print(visual_tokens.shape)
    # torch.Size([2, 196, 768])

这里使用卷积操作实现Patch切分,本质上等价于对每个Patch执行一次线性映射。相比手动切分,卷积实现通常更高效,也更容易利用GPU进行并行计算。

3. Patch大小对能力的影响

Patch越小,视觉Token数量越多,模型可以观察到更细粒度的信息,但计算量也会明显增加。

对于输入尺寸为 H × W、Patch大小为 P 的图片,视觉Token数量大致为:

N = H / P × W / P

例如:

输入尺寸 Patch大小 Token数量
224×224 16 196
336×336 14 576
448×448 14 1024
1024×1024 14 5476

当图像分辨率增大时,Token数量呈平方增长。视觉Token过多会导致:

  1. 显存占用增加;
  2. 注意力计算时间变长;
  3. 文本Token可用空间减少;
  4. 推理延迟和成本上升;
  5. 多图输入时上下文容易被占满。

这也是为什么很多多模态模型会采用动态分辨率、图像压缩、Token合并和多尺度编码。


三、模态投影层:视觉特征如何进入语言模型

视觉编码器输出的特征维度通常与语言模型的隐藏层维度不同。例如:

视觉编码器输出:768维
语言模型隐藏层:4096维

两者不能直接拼接,需要通过投影层进行维度映射:

视觉特征 -> 线性层或MLP -> 语言模型隐藏空间

一个简单的投影模块如下:

class VisionProjector(nn.Module):
    """
    将视觉编码器输出映射到语言模型隐藏空间。
    """

    def __init__(
        self,
        vision_dim=768,
        language_dim=4096,
        hidden_dim=2048
    ):
        super().__init__()

        self.network = nn.Sequential(
            nn.Linear(vision_dim, hidden_dim),
            nn.GELU(),
            nn.LayerNorm(hidden_dim),
            nn.Linear(hidden_dim, language_dim)
        )

    def forward(self, visual_tokens):
        """
        visual_tokens:
            [B, N, vision_dim]
        return:
            [B, N, language_dim]
        """
        return self.network(visual_tokens)

经过投影之后,视觉Token可以和文本Token在同一个隐藏空间中参与Transformer计算。

这里的核心并不是简单“改变维度”,而是完成语义空间对齐。比如视觉编码器中表示“红色汽车”的向量,需要经过训练逐渐靠近语言模型中“红色”“汽车”“车辆”等词语相关的语义表示。


四、视觉Token和文本Token如何拼接

一种常见做法是将图像表示为特殊Token序列:

<BOS> 用户问题 <IMAGE_START> 视觉Token1 ... 视觉TokenN <IMAGE_END> 模型回答

示意代码如下:

def merge_text_and_image_tokens(
    text_tokens,
    image_tokens,
    image_start_id,
    image_end_id
):
    """
    text_tokens:
        [B, T]
    image_tokens:
        [B, N, D]

    实际工程中通常需要在Embedding层之后拼接,
    因此这里只展示逻辑结构。
    """

    batch_size = text_tokens.size(0)
    device = text_tokens.device

    text_embeddings = text_tokens

    start_tokens = torch.full(
        (batch_size, 1),
        image_start_id,
        dtype=torch.long,
        device=device
    )

    end_tokens = torch.full(
        (batch_size, 1),
        image_end_id,
        dtype=torch.long,
        device=device
    )

    return {
        "text": text_embeddings,
        "image_start": start_tokens,
        "image_tokens": image_tokens,
        "image_end": end_tokens
    }

真正的模型一般不会把视觉Token当成普通词表ID,而是会在Embedding阶段直接注入视觉向量:

def build_inputs_embeds(
    text_input_embeds,
    image_embeds,
    image_placeholder_position
):
    """
    text_input_embeds:
        [B, T, D]
    image_embeds:
        [B, N, D]
    """

    batch_size, text_length, hidden_dim = text_input_embeds.shape
    image_length = image_embeds.size(1)

    left = text_input_embeds[
        :, :image_placeholder_position, :
    ]

    right = text_input_embeds[
        :, image_placeholder_position + 1:, :
    ]

    fused = torch.cat(
        [left, image_embeds, right],
        dim=1
    )

    return fused

这种结构的优点是实现简单,语言模型可以复用现有的Transformer架构。缺点是视觉信息被压缩成有限数量的Token,如果视觉编码器没有提取到某些细节,后续语言模型无法凭空恢复。


五、多模态模型的核心能力层次

多模态模型的能力可以分成五个层次。

1. 感知能力

感知能力包括:

  • 图像分类;
  • 目标检测;
  • 人脸和物体识别;
  • OCR文字识别;
  • 颜色识别;
  • 位置识别;
  • 图像质量判断;
  • 场景分类。

这是多模态能力的基础层。如果模型连图像中的对象都无法准确识别,后续推理就无从谈起。

2. 语义理解能力

语义理解关注对象之间的关系:

一个人正在桌子旁边使用电脑

这句话不是简单的目标集合,而是包含:

  • 人;
  • 桌子;
  • 电脑;
  • 人与桌子的空间关系;
  • 人与电脑的交互关系;
  • “正在使用”的动作关系。

模型需要从图像区域和语言概念之间建立映射。

3. 逻辑推理能力

逻辑推理要求模型对视觉信息进行组合和计算,例如:

  • 图片中有几个人?
  • 哪个物体离门最近?
  • 图表中哪一类数据增长最快?
  • 如果移除左侧物体,剩余物体是什么?
  • 图片中的流程是否存在逻辑错误?

这类问题已经超出了普通图像分类范围,需要语言模型的推理能力参与。

4. 生成能力

生成能力包括:

  • 生成图片描述;
  • 生成结构化报告;
  • 根据图片生成代码;
  • 图像编辑;
  • 图像补全;
  • 文生图;
  • 图生图;
  • 视频生成。

生成能力不等于事实正确。模型可能生成一段语言流畅但与图片不匹配的描述,因此必须结合事实验证。

5. 行动和工具调用能力

更高级的多模态Agent可以:

  1. 读取图片;
  2. 判断用户任务;
  3. 调用OCR工具;
  4. 调用数据库;
  5. 执行计算;
  6. 返回结构化结果。

例如处理财务发票时,模型可以先识别发票,再调用校验接口检查发票号码,最后写入数据库。


六、为什么多模态模型会出现视觉幻觉

视觉幻觉指模型生成了图像中不存在的内容,或者错误描述了图像中真实存在的对象。

例如图片中没有猫,模型却回答“图片中有一只猫”;图片中有三个物体,模型却回答有四个。这些错误通常来自以下原因。

1. 语言先验压过了视觉证据

大语言模型训练了大量文本,具备强大的语言补全能力。面对模糊图像时,它可能根据常见搭配自动补全答案。

例如输入一张餐桌图片,模型可能默认桌上有刀、叉、杯子,即使图片中实际没有这些物体。

2. 视觉Token压缩损失

如果输入图像分辨率很高,但最终只保留较少的视觉Token,很多局部信息会丢失。模型得到的不是原始像素,而是经过多层编码后的抽象表示。

3. 对象计数能力弱

Transformer擅长语义关联,但不天然擅长精确计数。对于密集目标、小目标和遮挡目标,模型容易出现重复计数或漏计数。

4. 空间关系建模不足

“左边”“右边”“前面”“后面”“里面”“相邻”等概念需要精确的空间建模。如果模型只学习了对象语义,而没有学习坐标和几何关系,就容易答错。

5. 训练数据中的描述偏差

如果训练数据经常把某类图片描述成固定句式,模型会学习到强烈的语言模板。一旦图片内容发生变化,模型仍然可能沿用旧模板。


七、从图像问答到可验证推理

在实际系统中,不能只依赖模型自然语言输出。更可靠的做法是引入中间结构和外部验证。

例如,不直接要求模型输出:

这是一张包含多个商品的图片。

而是要求模型输出结构化结果:

{
  "objects": [
    {
      "name": "商品A",
      "bbox": [20, 30, 180, 220],
      "confidence": 0.91
    }
  ],
  "relations": [],
  "answer": "..."
}

结构化输出可以帮助后续系统进行:

  • 坐标合法性检查;
  • 数量一致性检查;
  • 业务规则验证;
  • 数据库存储;
  • 结果排序;
  • 审计和追踪。

一个简单的结果校验代码如下:

from typing import List
from pydantic import BaseModel, Field, ValidationError


class ObjectItem(BaseModel):
    name: str
    bbox: List[float] = Field(min_length=4, max_length=4)
    confidence: float = Field(ge=0.0, le=1.0)


class VisualResult(BaseModel):
    objects: List[ObjectItem]
    answer: str


def validate_visual_result(payload: dict):
    try:
        result = VisualResult.model_validate(payload)

        for item in result.objects:
            x1, y1, x2, y2 = item.bbox

            if x2 <= x1 or y2 <= y1:
                raise ValueError(
                    f"检测框无效: {item.name}, {item.bbox}"
                )

        return result

    except ValidationError as exc:
        raise ValueError(
            f"模型输出结构不符合要求: {exc}"
        ) from exc

需要注意,结构合法并不意味着事实正确。模型可以输出一个完全符合JSON格式、但内容错误的结果。因此还需要结合检测器、OCR、数据库或规则引擎进行二次验证。


八、常见多模态模型的技术路线

1. 视觉语言模型

视觉语言模型通常由三个部分构成:

Vision Encoder + Projector + LLM

其中:

  • Vision Encoder负责提取视觉特征;
  • Projector负责模态对齐;
  • LLM负责语言推理和输出。

LLaVA类模型通常会冻结视觉编码器和大语言模型,只训练投影层,使视觉特征适配语言模型。

这种方案训练成本较低,工程实现相对简单,但模型性能高度依赖视觉编码器的能力和训练数据质量。

2. 端到端多模态模型

端到端模型会同时训练视觉模块和语言模块。这样可以让视觉表示更好地适配语言任务,但训练成本更高,数据和显存要求也更大。

如果训练数据质量不足,端到端训练可能破坏原有语言能力,出现文本理解能力下降的问题。

3. 扩散模型

Stable Diffusion类模型一般在潜空间中进行扩散和去噪。图像首先经过VAE编码到低维潜空间,然后模型在潜空间内进行多轮去噪,最后通过VAE解码回像素空间。

简化的去噪过程如下:

import torch


def diffusion_step(
    noisy_latent,
    predicted_noise,
    alpha_t
):
    """
    教学简化版的单步去噪。
    实际扩散模型会使用scheduler计算精确系数。
    """
    clean_estimate = (
        noisy_latent
        - torch.sqrt(1 - alpha_t) * predicted_noise
    ) / torch.sqrt(alpha_t)

    return clean_estimate

扩散模型的优势是图像质量高、细节丰富,缺点是推理过程通常需要多个去噪步骤,延迟较高。

4. 视频生成模型

视频生成比图像生成更复杂,因为每一帧都需要满足空间一致性和时间一致性。

视频模型需要解决:

  • 同一个人物在不同帧中保持身份一致;
  • 物体运动轨迹合理;
  • 光照变化连续;
  • 镜头运动自然;
  • 遮挡关系符合物理规律;
  • 文字和人脸不发生严重变形。

如果模型只对每一帧独立生成,就会出现闪烁、物体变形和身份漂移。


九、视觉输入的工程优化

1. 动态分辨率

对于包含大量文字的截图,低分辨率会导致OCR失败;对于普通场景图片,过高分辨率又会浪费计算资源。因此可以根据图片类型动态选择分辨率。

def choose_resolution(
    width,
    height,
    contains_text=False
):
    max_side = max(width, height)

    if contains_text:
        if max_side <= 1024:
            return 1024
        return 1536

    if max_side <= 512:
        return 512

    return 768

更合理的系统应先使用轻量分类器判断图片类型,再决定分辨率。

2. 图片裁剪

对于票据、表格和网页截图,应优先对关键区域进行裁剪。与其将一张超高分辨率图片整体送入模型,不如先定位表格区域,再单独识别表头和数据。

3. 多阶段识别

在生产环境中,可以采用以下流程:

图片质量检测
    |
    v
目标区域检测
    |
    v
局部裁剪
    |
    v
OCR或视觉语言模型识别
    |
    v
结构化解析
    |
    v
业务规则校验

这种流程比直接将原图交给大模型更稳定,也更容易定位问题。


十、调用多模态模型的示例

下面展示一种兼容OpenAI风格接口的调用方式:

import base64
from openai import OpenAI


def encode_image(image_path):
    with open(image_path, "rb") as file:
        return base64.b64encode(file.read()).decode("utf-8")


def ask_vision_model(image_path, question):
    client = OpenAI(
        api_key="YOUR_API_KEY",
        base_url="https://your-model-gateway.example.com/v1"
    )

    image_base64 = encode_image(image_path)

    response = client.chat.completions.create(
        model="vision-language-model",
        messages=[
            {
                "role": "system",
                "content": (
                    "你是一个严谨的视觉分析系统。"
                    "无法确认的信息必须明确说明,不得猜测。"
                )
            },
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": question
                    },
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": (
                                f"data:image/png;base64,"
                                f"{image_base64}"
                            )
                        }
                    }
                ]
            }
        ],
        temperature=0
    )

    return response.choices[0].message.content

在生产环境中,建议补充:

  • 超时设置;
  • 重试机制;
  • 图片大小限制;
  • 内容安全审核;
  • 结果格式校验;
  • Token和费用统计;
  • 请求日志;
  • 降级模型;
  • 人工复核机制。

十一、多模态模型的能力边界

多模态模型并不是通用视觉系统,它存在比较明确的限制。

1. 精确几何计算能力有限

模型可以大致判断“哪个物体更大”,但对于像素级距离、角度、面积和比例,不能完全依赖自然语言模型。

2. 小目标识别不稳定

当目标只占图像很小区域时,视觉编码器下采样会使目标特征被背景淹没。解决方法包括放大、裁剪、多尺度输入和专用检测器。

3. OCR并非始终可靠

复杂字体、低清晰度、倾斜文字、手写字和密集表格都会降低识别准确率。对于严肃业务,应使用专用OCR系统进行交叉验证。

4. 计数能力存在误差

当目标数量较多或存在遮挡时,模型可能重复计算同一个对象。需要结合检测模型和非极大值抑制等算法。

5. 时序理解仍然困难

视频中“先发生什么、后发生什么”需要模型建立时间顺序,而不是仅理解视频中的静态内容。

6. 事实准确性不等于语言流畅性

多模态模型可能给出表达清晰、语法正确的错误答案。流畅度只能说明语言生成能力,不能说明视觉判断正确。


十二、如何构建可靠的多模态系统

一个可靠的多模态系统,通常不是单模型方案,而是多个模块的组合:

输入预处理
    |
视觉编码器
    |
多模态大模型
    |
结构化输出
    |
工具验证
    |
置信度判断
    |
结果返回或人工审核

可以定义一个简单的置信度策略:

def decide_action(
    model_confidence,
    detector_confidence,
    business_risk
):
    if business_risk == "high":
        if model_confidence < 0.95:
            return "human_review"

        if detector_confidence < 0.95:
            return "human_review"

    if model_confidence < 0.70:
        return "fallback"

    return "accept"

其中,高风险场景包括:

  • 医疗影像;
  • 金融票据;
  • 身份证件;
  • 工业质检;
  • 自动驾驶;
  • 安全监控;
  • 法律材料。

这些场景不能只看模型平均准确率,而要重点关注漏检、误检和极端输入。


结语

多模态大模型的本质,是将不同模态的数据转换到可以交互的表示空间,再利用Transformer或扩散模型完成理解、推理和生成。

它的能力主要来自三个方面:

  1. 高质量的视觉和语言表示;
  2. 模态之间有效的语义对齐;
  3. 大规模、多样化且经过清洗的数据。

它的边界也同样明显:

  • 视觉Token会丢失细节;
  • 语言先验会引发幻觉;
  • 精确计数和空间计算不稳定;
  • 生成结果不代表事实正确;
  • 高风险场景需要外部验证。

真正的工程重点不是简单地“调用一个视觉大模型”,而是围绕输入质量、视觉编码、提示词、结构化输出、工具调用、评估体系和人工复核建立完整闭环。只有把模型能力与可验证机制结合起来,多模态大模型才能从演示效果走向真实业务。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐