VLM架构分类体系

视觉语言模型(Vision-Language Model,VLM)是当前多模态学习的核心研究方向,其架构设计直接影响模型的多模态理解能力。1 本篇系统性梳理VLM的架构分类体系,从融合方式、训练策略、应用场景三个维度进行分类,并深入分析各代表性架构的设计原理与演进路径。

VLM架构分类概述

分类体系

VLM架构可以从多个角度进行分类,形成一个多层次的分类体系:

┌─────────────────────────────────────────────────────────────────┐
│                        VLM架构分类体系                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐  │
│  │  按融合方式分类   │  │  按训练策略分类   │  │  按应用场景分类   │  │
│  ├─────────────────┤  ├─────────────────┤  ├─────────────────┤  │
│  │ • Prefix-based  │  │ • 模态对齐预训练  │  │ • 视觉问答      │  │
│  │ • Gating-based  │  │ • 指令微调       │  │ • 图文检索      │  │
│  │ • Cross-attention│ │ • 端到端训练     │  │ • 视觉对话      │  │
│  │ • 混合架构      │  │ • 轻量级适配     │  │ • 多图像理解    │  │
│  │ • 端到端架构    │  │                 │  │ • 视频理解      │  │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

按融合方式分类

融合方式代表模型核心特征适用场景
Prefix-basedLLaVA系列视觉特征作为LLM的输入前缀视觉问答、对话
Gating-basedMiniGPT-4Gating机制控制信息流轻量级多模态
Cross-attentionInstructBLIP跨模态注意力交互指令跟随任务
混合架构LEO、Florence-VL多编码器动态融合高分辨率、复杂场景
端到端架构GPT-4V、Gemini原生多模态设计全场景多模态理解

按训练策略分类

  1. 模态对齐预训练:冻结视觉编码器和LLM,仅训练模态融合模块
  2. 指令微调:在预训练基础上使用指令数据微调
  3. 端到端训练:所有组件联合训练
  4. 轻量级适配:使用LoRA、QLoRA等PEFT方法

架构演进时间线

2021                    2023                          2024-2025
  │                       │                               │
  ▼                       ▼                               ▼
┌──────┐              ┌──────┬──────┬──────┐        ┌──────┬──────┬──────┐
│ CLIP │              │BLIP-2│LLaVA │MiniGPT│        │LLaVA-N│LEO   │Florence│
│ 双编码│ ──────────▶ │Q-Former│Prefix│Gating│        │高分辨率│多编码器│VL    │
└──────┘              └──────┴──────┴──────┘        └──────┴──────┴──────┘
  │                       │                               │
  ▼                       ▼                               ▼
早期融合               中期融合                        动态融合
(双塔结构)            (桥梁连接)                      (专家混合)

                    ┌─────────────────────────────────────┐
                    │         原生多模态时代              │
                    │  GPT-4V ──── Gemini ──── Claude     │
                    └─────────────────────────────────────┘

Prefix-based架构(LLaVA系列)

Prefix-based架构是当前最流行的VLM架构范式,其核心思想是将视觉编码器的输出作为语言模型的输入前缀,实现视觉到语言的转换。2

架构设计原理

核心思想

Prefix-based架构遵循”语言模型作为核心”的理念:

  1. 视觉编码器:使用预训练的CLIP ViT提取图像特征
  2. 投影层:将视觉特征映射到语言模型的输入空间
  3. 语言模型:冻结的LLM负责理解和生成
图像输入                    投影层                         LLM
  │                           │                            │
  ▼                           ▼                            ▼
┌─────────┐              ┌──────────┐              ┌─────────────────┐
│ CLIP    │              │ 线性/MLP │              │                 │
│ ViT-L/14│ ──────────▶ │ 投影      │ ──────────▶  │  Vicuna/LLaMA   │
│ (冻结)   │              │ (可训练)  │              │    (冻结/微调)   │
└─────────┘              └──────────┘              └─────────────────┘
                                                      │
                                                      ▼
                                                  文本输出

数学表示

设视觉编码器为 ,其中 为patch数量, 为视觉特征维度。投影层 将视觉特征映射到语言空间。语言模型接收拼接后的输入:

其中 表示拼接操作。

LLaVA-1.0:开创性工作

LLaVA-1.0首次验证了视觉指令微调的可行性。2

class LLaVA_v1(nn.Module):
    """
    LLaVA 1.0 架构实现
    """
    def __init__(self, vision_encoder, language_model, config):
        super().__init__()
        self.vision_encoder = vision_encoder  # CLIP ViT-L/14
        self.language_model = language_model  # Vicuna-7B/13B
        
        # 简单的线性投影
        vision_dim = vision_encoder.embed_dim  # 1024
        hidden_dim = language_model.config.hidden_size  # 4096
        
        self.projection = nn.Linear(vision_dim, hidden_dim)
    
    def forward(self, images, input_ids, attention_mask=None, labels=None):
        # 1. 视觉编码
        image_features = self.vision_encoder(images)
        # shape: (B, num_patches, 1024), num_patches = 256 for 224x224
        
        # 2. 投影到语言空间
        image_tokens = self.projection(image_features)
        # shape: (B, num_patches, 4096)
        
        # 3. 获取文本embedding
        text_tokens = self.language_model.get_input_embeddings()(input_ids)
        
        # 4. 将视觉tokens插入文本序列
        inputs_embeds = self._merge_visual_tokens(image_tokens, text_tokens, input_ids)
        
        # 5. LLM前向
        outputs = self.language_model(
            inputs_embeds=inputs_embeds,
            attention_mask=attention_mask,
            labels=labels
        )
        return outputs

训练流程

LLaVA采用两阶段训练策略:

阶段1:预训练(特征对齐)
┌────────────┐     ┌────────────┐
│ CLIP ViT   │     │   Vicuna   │
│   (冻结)    │     │   (冻结)    │
└─────┬──────┘     └─────┬──────┘
      │                   │
      ▼                   ▼
┌────────────────────────────────┐
│      投影层W (可训练)            │
│   学习目标:图文匹配损失        │
└────────────────────────────────┘
训练数据:CC3M (595K图文对)

阶段2:指令微调
┌────────────┐     ┌────────────┐
│ CLIP ViT   │     │   Vicuna   │
│   (冻结)    │     │   (微调)   │
└─────┬──────┘     └─────┬──────┘
      │                   │
      ▼                   ▼
┌────────────────────────────────┐
│      投影层W (冻结)             │
│   学习目标:指令跟随损失        │
└────────────────────────────────┘
训练数据:GPT-4生成的视觉指令(158K)

LLaVA-1.5:能力增强

LLaVA-1.5在多个方面进行了改进:

  1. MLP投影:使用2层MLP替代线性投影,增强表达能力
  2. 更高分辨率:支持336x336和更高分辨率输入
  3. 数据质量提升:使用更优质的训练数据
class LLaVA_v15(nn.Module):
    """
    LLaVA 1.5 架构实现
    """
    def __init__(self, vision_encoder, language_model):
        super().__init__()
        self.vision_encoder = vision_encoder
        self.language_model = language_model
        
        vision_dim = vision_encoder.embed_dim
        hidden_dim = language_model.config.hidden_size
        
        # MLP投影:增强表达能力
        self.projection = nn.Sequential(
            nn.Linear(vision_dim, hidden_dim),
            nn.GELU(),
            nn.Linear(hidden_dim, hidden_dim)
        )
        
        # 额外的对齐损失
        self.alignment_loss = nn.MSELoss()
    
    def compute_alignment_loss(self, image_features, text_features):
        """
        对比对齐损失:让视觉特征与对应文本特征接近
        """
        # 归一化
        image_features = F.normalize(image_features, dim=-1)
        text_features = F.normalize(text_features, dim=-1)
        
        # 计算相似度
        similarity = torch.matmul(image_features, text_features.T)
        return self.alignment_loss(similarity, torch.eye(similarity.size(0)).to(similarity.device))

LLaVA-1.6 / LLaVA-NeXT:高分辨率处理

LLaVA-1.6引入AnyRes策略处理高分辨率图像,同时支持多图像和视频输入。

AnyRes策略

AnyRes的核心思想是将高分辨率图像分成多个低分辨率子图:

原始高分辨率图像 (672x672)
            │
            ▼
    ┌───────────────────┐
    │   2x2 网格分割     │
    ├───────┬───────┬───┤
    │ 子图1  │ 子图2  │   │
    │(336x336)│(336x336)│   │
    ├───────┼───────┤   │
    │ 子图3  │ 子图4  │   │
    │(336x336)│(336x336)│   │
    └───────┴───────┴───┘
            │
            ▼
    ┌───────────────────┐
    │ 全局特征 (1x1)     │
    │ + 局部特征 (2x2)   │
    │ = 5x patches      │
    └───────────────────┘
class AnyResStrategy:
    """
    AnyRes高分辨率处理策略
    """
    def __init__(self, grid_size=2, resolution=336):
        self.grid_size = grid_size
        self.resolution = resolution
    
    def split_image(self, image):
        """
        将高分辨率图像分割为多个子图
        """
        B, C, H, W = image.shape
        h, w = H // self.grid_size, W // self.grid_size
        
        sub_images = []
        for i in range(self.grid_size):
            for j in range(self.grid_size):
                sub_img = image[:, :, i*h:(i+1)*h, j*w:(j+1)*w]
                sub_images.append(sub_img)
        
        return sub_images
    
    def encode(self, image, vision_encoder, projector):
        # 全局特征
        global_features = vision_encoder(image)
        
        # 子图特征
        sub_images = self.split_image(image)
        sub_features = [vision_encoder(sub) for sub in sub_images]
        
        # 拼接全局和局部特征
        all_features = torch.cat([global_features] + sub_features, dim=1)
        
        # 投影
        return projector(all_features)

LLaVA-1.5/1.6对比

特性LLaVA-1.0LLaVA-1.5LLaVA-1.6/NeXT
投影层线性MLP (2层)MLP (2层)
分辨率224x224336x336可变(最高高分辨率)
训练数据CC3M + GPT-4558K + 过滤数据1.2M多样化数据
多图像不支持不支持支持
视频不支持不支持支持(采样帧)
OCR能力中等

LLaVA-OneVision:统一架构

LLaVA-OneVision (2024) 是LLaVA系列的集大成者,实现了单图像、多图像、视频的统一处理能力。

class LLaVAOneVision(nn.Module):
    """
    LLaVA-OneVision: 统一的多模态架构
    """
    def __init__(self, vision_encoder, language_model):
        super().__init__()
        self.vision_encoder = vision_encoder
        self.language_model = language_model
        self.mm_projector = nn.Sequential(
            nn.Linear(vision_encoder.embed_dim, language_model.config.hidden_size),
            nn.GELU(),
            nn.Linear(language_model.config.hidden_size, language_model.config.hidden_size)
        )
    
    def encode_multimodal(self, inputs):
        """
        统一编码多模态输入
        """
        if inputs.get("image") is not None:
            return self.encode_image(inputs["image"])
        
        if inputs.get("images") is not None:
            return self.encode_multi_images(inputs["images"])
        
        if inputs.get("video") is not None:
            return self.encode_video(inputs["video"])
    
    def encode_image(self, image):
        """单图像编码"""
        features = self.vision_encoder(image)
        return self.mm_projector(features)
    
    def encode_multi_images(self, images):
        """多图像编码:拼接所有图像的特征"""
        all_features = []
        for img in images:
            feat = self.vision_encoder(img)
            all_features.append(feat)
        
        # 拼接多图像特征
        concatenated = torch.cat(all_features, dim=1)
        return self.mm_projector(concatenated)
    
    def encode_video(self, video_frames, num_frames=16):
        """视频编码:采样帧 + 时序聚合"""
        # 采样帧
        indices = torch.linspace(0, len(video_frames)-1, num_frames).long()
        sampled_frames = video_frames[indices]
        
        # 逐帧编码
        frame_features = [self.vision_encoder(f) for f in sampled_frames]
        
        # 时序拼接(可替换为Transformer)
        temporal_features = torch.stack(frame_features, dim=1)  # (B, T, N, D)
        temporal_features = temporal_features.flatten(1, 2)   # (B, T*N, D)
        
        return self.mm_projector(temporal_features)

Gating-based架构(MiniGPT-4)

Gating-based架构通过引入门控机制控制视觉信息流向语言模型,实现更精细的模态融合。3

核心思想

MiniGPT-4的核心洞察是:仅需要训练一个线性投影层就能实现视觉到语言的初步对齐,但为了获得更好的效果,需要更复杂的对齐策略。

Q-Former设计原理

Q-Former(Querying Transformer)是BLIP-2提出的关键组件,用于从视觉编码器中提取与语言相关的视觉表示。

视觉编码器输出                    Q-Former                    LLM
      │                              │                         │
      ▼                              ▼                         ▼
┌─────────────┐              ┌─────────────┐           ┌─────────────┐
│ CLIP ViT    │              │  Query      │           │             │
│ 特征输出     │ ──────────▶ │ Transformer │ ────────▶ │   LLaMA     │
│ (257x768)   │              │  (32 queries)│           │             │
└─────────────┘              └─────────────┘           └─────────────┘
                                      │
                                      ▼
                              ┌─────────────┐
                              │ 门控机制     │
                              │ (可选)       │
                              └─────────────┘

Q-Former结构

class QFormer(nn.Module):
    """
    Q-Former: Querying Transformer for Vision-Language alignment
    BLIP-2的核心组件
    """
    def __init__(self, vision_dim=1024, num_queries=32, num_heads=8, num_layers=6):
        super().__init__()
        self.num_queries = num_queries
        
        # 可学习的Query向量
        self.query_tokens = nn.Parameter(torch.zeros(1, num_queries, vision_dim))
        nn.init.normal_(self.query_tokens, std=0.02)
        
        # 交叉注意力层
        self.cross_attentions = nn.ModuleList([
            nn.MultiheadAttention(vision_dim, num_heads, batch_first=True)
            for _ in range(num_layers)
        ])
        
        # 前馈网络
        self.ffns = nn.ModuleList([
            nn.Sequential(
                nn.Linear(vision_dim, vision_dim * 4),
                nn.GELU(),
                nn.Linear(vision_dim * 4, vision_dim)
            )
            for _ in range(num_layers)
        ])
        
        # Layer Norm
        self.norms = nn.ModuleList([
            nn.LayerNorm(vision_dim)
            for _ in range(num_layers * 2)
        ])
    
    def forward(self, vision_features, text_features=None):
        """
        Args:
            vision_features: (B, N, D_v) 来自视觉编码器
            text_features: (B, L, D_v) 来自文本编码器(可选)
        Returns:
            query_output: (B, num_queries, D_v) 提取的查询特征
        """
        B = vision_features.size(0)
        
        # 初始化Query
        queries = self.query_tokens.expand(B, -1, -1)  # (B, num_queries, D)
        
        for i in range(len(self.cross_attentions)):
            # Cross-attention: Query attend to Vision
            attn_out, _ = self.cross_attentions[i](
                queries, vision_features, vision_features
            )
            queries = self.norms[i*2](queries + attn_out)
            
            # FFN
            ffn_out = self.ffns[i](queries)
            queries = self.norms[i*2 + 1](queries + ffn_out)
        
        return queries

MiniGPT-4架构

MiniGPT-4采用简化的两阶段对齐策略,仅训练极少的参数(投影层)。

class MiniGPT4(nn.Module):
    """
    MiniGPT-4: 简化版VLM,仅训练投影层
    """
    def __init__(self, config):
        super().__init__()
        
        # 冻结的视觉编码器
        self.visual_encoder = CLIPVisionEncoder()
        for param in self.visual_encoder.parameters():
            param.requires_grad = False
        
        # Q-Former: 学习视觉-语言对齐
        self.q_former = QFormer(
            vision_dim=self.visual_encoder.embed_dim,
            num_queries=32
        )
        
        # 线性投影:Q-Former输出 → LLM空间
        vision_dim = self.visual_encoder.embed_dim
        llm_dim = config.llm_hidden_size  # 4096
        
        self.projection = nn.Sequential(
            nn.Linear(vision_dim, 2048),
            nn.GELU(),
            nn.Linear(2048, llm_dim)
        )
        
        # 冻结的LLM
        self.llm = VicunaLM(config)
        for param in self.llm.parameters():
            param.requires_grad = False
    
    def forward(self, image, input_ids, attention_mask=None, labels=None):
        # 1. 视觉编码
        vision_features = self.visual_encoder(image)
        
        # 2. Q-Former处理
        query_features = self.q_former(vision_features)
        
        # 3. 投影到LLM空间
        visual_tokens = self.projection(query_features)
        
        # 4. 与文本tokens合并
        text_tokens = self.llm.get_input_embeddings()(input_ids)
        inputs_embeds = self._merge_inputs(visual_tokens, text_tokens, input_ids)
        
        # 5. LLM生成
        outputs = self.llm(
            inputs_embeds=inputs_embeds,
            attention_mask=attention_mask,
            labels=labels
        )
        return outputs

与LLaVA的对比

特性LLaVAMiniGPT-4
视觉编码器CLIP ViT (冻结)CLIP ViT (冻结)
对齐模块线性/MLP投影Q-Former + 线性投影
可训练参数~20M~10M
训练策略两阶段两阶段
推理效率中等(Q-Former额外计算)
生成质量较好较好(对齐更精细)

MiniGPT-4 vs MiniGPT-5

MiniGPT-5是对MiniGPT-4的改进,引入了Gating机制生成式视觉编码器(LVG):

class MiniGPT5(nn.Module):
    """
    MiniGPT-5: 引入Gating机制和生成式视觉编码
    """
    def __init__(self, config):
        super().__init__()
        self.visual_encoder = CLIPVisionEncoder()
        self.lvg_encoder = GenerativeVisionEncoder()  # 新增:生成式视觉编码器
        self.q_former = QFormer()
        
        # Gating机制:控制信息流
        self.gate = nn.Sequential(
            nn.Linear(config.vision_dim * 2, config.vision_dim),
            nn.Sigmoid()
        )
        
        self.projection = nn.Linear(config.vision_dim, config.llm_dim)
        self.llm = LLaMA(config)
    
    def forward(self, image, input_ids, ...):
        # 视觉编码
        clip_features = self.visual_encoder(image)
        lvg_features = self.lvg_encoder(image)
        
        # Gating: 自适应融合两种视觉特征
        combined = torch.cat([clip_features, lvg_features], dim=-1)
        gate_values = self.gate(combined)
        gated_features = gate_values * clip_features + (1 - gate_values) * lvg_features
        
        # Q-Former处理
        query_features = self.q_former(gated_features)
        
        # 投影并送入LLM
        ...

Cross-attention架构(InstructBLIP)

Cross-attention架构通过跨模态注意力机制实现视觉和语言信息的深度交互,是目前最强大的VLM架构之一。4

指令感知的视觉特征提取

InstructBLIP的核心创新是指令感知的视觉特征提取:在提取视觉特征时,考虑当前指令的上下文信息。

指令文本                    视觉编码器                    Q-Former
   │                           │                           │
   ▼                           ▼                           ▼
┌────────┐              ┌─────────────┐            ┌─────────────┐
│ BERT/  │ ──────────▶ │ CLIP ViT    │ ────────▶  │ Cross-       │
│ T5     │              │ (指令感知)   │            │ Attention    │
└────────┘              └─────────────┘            └─────────────┘
   │                           │                           │
   ▼                           ▼                           ▼
  文本                     视觉特征                  指令相关的
  特征                     (受指令引导)              视觉表示

跨模态注意力机制

InstructBLIP的Q-Former采用双向跨注意力:

class InstructBLIP_QFormer(nn.Module):
    """
    InstructBLIP的Q-Former: 指令感知的视觉特征提取
    """
    def __init__(self, config):
        super().__init__()
        self.num_query = 32
        self.num_layer = 6
        
        # 可学习的Query
        self.query_tokens = nn.Parameter(torch.zeros(1, self.num_query, config.hidden_dim))
        
        # 各层的Q-Former Block
        self.layers = nn.ModuleList([
            QFormerLayer(config) for _ in range(self.num_layer)
        ])
    
    def forward(self, vision_features, text_features, attention_mask=None):
        """
        Args:
            vision_features: (B, N, D_v) 视觉编码器输出
            text_features: (B, L, D_t) 文本特征(来自LLM或BERT)
        Returns:
            query_output: (B, num_query, D) 指令相关的视觉特征
        """
        queries = self.query_tokens.expand(vision_features.size(0), -1, -1)
        
        for layer in self.layers:
            # 双向交叉注意力
            queries = layer(
                query=queries,              # Query来自可学习向量
                key_value_vision=vision_features,  # Key/Value来自视觉
                key_value_text=text_features,       # 额外文本上下文
                attention_mask=attention_mask
            )
        
        return queries
 
 
class QFormerLayer(nn.Module):
    """
    Q-Former的单层结构
    """
    def __init__(self, config):
        super().__init__()
        
        # Self-attention on queries
        self.self_attn = nn.MultiheadAttention(config.hidden_dim, config.num_heads, batch_first=True)
        
        # Cross-attention to vision
        self.vision_cross_attn = nn.MultiheadAttention(config.hidden_dim, config.num_heads, batch_first=True)
        
        # Cross-attention to text
        self.text_cross_attn = nn.MultiheadAttention(config.hidden_dim, config.num_heads, batch_first=True)
        
        # FFN
        self.ffn = nn.Sequential(
            nn.Linear(config.hidden_dim, config.intermediate_size),
            nn.GELU(),
            nn.Linear(config.intermediate_size, config.hidden_dim)
        )
        
        self.norms = nn.LayerNorm(config.hidden_dim)
    
    def forward(self, query, key_value_vision, key_value_text, attention_mask):
        # 1. Self-attention
        residual = query
        query = self.norms(query)
        query, _ = self.self_attn(query, query, query)
        query = residual + query
        
        # 2. Vision Cross-attention
        residual = query
        query = self.norms(query)
        query, _ = self.vision_cross_attn(query, key_value_vision, key_value_vision)
        query = residual + query
        
        # 3. Text Cross-attention
        residual = query
        query = self.norms(query)
        query, _ = self.text_cross_attn(query, key_value_text, key_value_text, key_padding_mask=attention_mask)
        query = residual + query
        
        # 4. FFN
        residual = query
        query = self.norms(query)
        query = residual + self.ffn(query)
        
        return query

BLIP-2基础架构

InstructBLIP建立在BLIP-2的基础上,BLIP-2提出两阶段视觉-语言对齐:

阶段1:表示学习阶段
┌─────────────┐                    ┌─────────────┐
│ 冻结的视觉   │                    │ 冻结的图像   │
│ 编码器       │ ◀───── Q-Former ──│ 编码器       │
│ (CLIP ViT)  │                    │ (BERT)      │
└─────────────┘                    └─────────────┘
  目标:学习与文本对齐的视觉表示

阶段2:生成学习阶段
┌─────────────┐                    ┌─────────────┐
│ Q-Former    │                    │ 冻结的语言   │
│ (冻结)      │ ◀───── Cross-attn ─│ 模型        │
│             │                    │ (T5/Flan-T5)│
└─────────────┘                    └─────────────┘
  目标:训练Q-Former进行视觉到语言的转换
class BLIP2(nn.Module):
    """
    BLIP-2: Bootstrapping Language-Image Pre-training
    """
    def __init__(self, config):
        super().__init__()
        
        # 冻结的视觉编码器
        self.visual_encoder = CLIPVisionEncoder()
        for param in self.visual_encoder.parameters():
            param.requires_grad = False
        
        # Q-Former
        self.q_former = QFormer(config)
        
        # 线性投影:Q-Former → LLM
        self.llm_proj = nn.Linear(config.q_former_dim, config.llm_dim)
        
        # 冻结的LLM (T5或LLaMA)
        if config.llm_type == "t5":
            self.llm = T5Model.from_pretrained(config.llm_name)
        else:
            self.llm = LLaMAModel.from_pretrained(config.llm_name)
        
        for param in self.llm.parameters():
            param.requires_grad = False
    
    def forward(self, image, input_ids, ...):
        # 视觉编码
        vision_embeds = self.visual_encoder(image)
        
        # Q-Former处理
        query_output = self.q_former(
            vision_embeds,
            text_ids=input_ids  # 额外文本上下文
        )
        
        # 投影
        query_output = self.llm_proj(query_output)
        
        # 送入LLM
        ...

Q-Former变体设计

不同的VLM架构采用不同的Q-Former变体:

变体特点代表模型
标准Q-Former固定数量QueryBLIP-2
指令感知Q-Former考虑文本指令上下文InstructBLIP
动态Q-FormerQuery数量可变一些改进版本
分层Q-Former多尺度特征融合InternVL
class DynamicQFormer(nn.Module):
    """
    动态Q-Former: Query数量根据输入自适应
    """
    def __init__(self, config):
        super().__init__()
        self.base_num_queries = config.num_queries
        self.q_former = QFormer(config)
        
        # 动态Query生成
        self.query_predictor = nn.Sequential(
            nn.Linear(config.vision_dim, 128),
            nn.ReLU(),
            nn.Linear(128, 1),
            nn.Sigmoid()
        )
    
    def forward(self, vision_features, text_features=None):
        # 预测每个patch的重要性
        importance = self.query_predictor(vision_features)  # (B, N, 1)
        
        # 根据重要性选择top-k patches
        k = min(self.base_num_queries, vision_features.size(1))
        _, top_indices = torch.topk(importance.squeeze(-1), k, dim=1)
        
        # 收集对应特征
        B = vision_features.size(0)
        selected_features = torch.zeros(B, k, vision_features.size(-1), device=vision_features.device)
        for b in range(B):
            selected_features[b] = vision_features[b, top_indices[b]]
        
        # 使用选中的特征
        return self.q_former(selected_features, text_features)

混合架构(视觉专家混合)

混合架构通过组合多个视觉编码器或使用动态选择机制,处理不同类型的视觉输入。5

设计动机

单一视觉编码器难以同时处理:

  • 高分辨率图像:需要更多patch或更大感受野
  • 文本密集图像:需要OCR能力
  • 场景理解图像:需要深度信息和语义信息
  • 细粒度图像:需要局部特征

LEO:Mixture of Vision Encoders

LEO提出使用视觉专家混合机制,自适应地选择最合适的视觉编码器。

class LEO(nn.Module):
    """
    LEO: Mixture of Vision Encoders
    动态选择最合适的视觉编码器
    """
    def __init__(self, config):
        super().__init__()
        
        # 多个视觉专家
        self.vision_experts = nn.ModuleDict({
            "high_res": HighResVisionEncoder(),      # 高分辨率专家
            "ocr": OCRVisionEncoder(),              # OCR专家
            "depth": DepthVisionEncoder(),          # 深度估计专家
            "clip": CLIPVisionEncoder(),            # CLIP通用专家
        })
        
        # 路由网络:决定使用哪个专家
        self.router = nn.Sequential(
            nn.Linear(config.vision_dim * 4, config.router_hidden),
            nn.ReLU(),
            nn.Linear(config.router_hidden, len(self.vision_experts)),
            nn.Softmax(dim=-1)
        )
        
        # 融合层
        self.fusion = nn.ModuleList([
            nn.Linear(config.vision_dim, config.output_dim)
            for _ in self.vision_experts
        ])
        
        self.llm = LLaMA(config)
    
    def forward(self, image, input_ids, image_type=None):
        # 1. 获取所有专家的特征
        expert_features = {}
        for name, encoder in self.vision_experts.items():
            expert_features[name] = encoder(image)
        
        # 2. 路由决策
        if image_type is not None:
            # 显式指定专家
            weights = torch.zeros(len(self.vision_experts))
            weights[list(self.vision_experts.keys()).index(image_type)] = 1.0
            weights = weights.to(image.device)
        else:
            # 动态路由
            combined_features = torch.cat([
                feat.mean(dim=1) for feat in expert_features.values()
            ], dim=-1)
            weights = self.router(combined_features)
        
        # 3. 加权融合
        fused_features = torch.zeros_like(list(expert_features.values())[0])
        for i, (name, feat) in enumerate(expert_features.items()):
            fused_features += weights[i] * self.fusion[i](feat)
        
        # 4. 送入LLM
        visual_tokens = self.project_to_llm(fused_features)
        ...

Florence-VL:多编码器融合

Florence-VL采用多编码器融合策略,支持视觉和语言的多层次对齐。

class FlorenceVL(nn.Module):
    """
    Florence-VL: 多编码器统一视觉语言表示
    """
    def __init__(self, config):
        super().__init__()
        
        # 主干视觉编码器
        self.vision_backbone = DaViT(config)  # Data-efficient Vision Transformer
        
        # 细粒度编码器
        self.fine_encoder = FineGrainedEncoder()
        
        # 语义编码器
        self.semantic_encoder = SemanticEncoder()
        
        # 多粒度融合
        self.multi_granularity_fusion = MultiGranularityFusion(config)
        
        # 统一投影
        self.unified_proj = nn.Sequential(
            nn.Linear(config.hidden_dim * 3, config.hidden_dim),
            nn.LayerNorm(config.hidden_dim),
            nn.GELU(),
            nn.Linear(config.hidden_dim, config.llm_dim)
        )
        
        self.llm = LLaMA(config)
    
    def forward(self, image, input_ids, return_features=False):
        # 多尺度视觉编码
        coarse_feat = self.vision_backbone(image)        # 粗粒度
        fine_feat = self.fine_encoder(image)             # 细粒度
        semantic_feat = self.semantic_encoder(image)     # 语义级
        
        # 跨粒度交互
        fused = self.multi_granularity_fusion(
            coarse_feat, fine_feat, semantic_feat
        )
        
        # 统一投影
        visual_tokens = self.unified_proj(fused)
        
        if return_features:
            return visual_tokens, {
                "coarse": coarse_feat,
                "fine": fine_feat,
                "semantic": semantic_feat
            }
        
        return self._merge_and_generate(visual_tokens, input_ids)

动态视觉专家选择

动态选择机制可以根据输入内容自适应地选择处理路径:

class DynamicVisionSelector(nn.Module):
    """
    动态视觉专家选择器
    """
    def __init__(self, num_experts=4):
        super().__init__()
        
        self.experts = nn.ModuleList([
            VisionExpert() for _ in range(num_experts)
        ])
        
        # 门控网络
        self.gate = nn.Sequential(
            nn.AdaptiveAvgPool2d(1),
            nn.Flatten(),
            nn.Linear(512, 256),
            nn.ReLU(),
            nn.Linear(256, num_experts),
            nn.Softmax(dim=1)
        )
        
        # 特征投影
        self.proj = nn.Linear(512, 4096)
    
    def forward(self, x):
        # 1. 轻量级特征提取用于路由
        routing_features = self._extract_routing_features(x)
        
        # 2. 计算门控权重
        gate_weights = self.gate(routing_features)  # (B, num_experts)
        
        # 3. 专家处理
        expert_outputs = []
        for expert in self.experts:
            expert_outputs.append(expert(x))
        
        # 4. 加权组合
        outputs = torch.stack(expert_outputs, dim=0)  # (num_experts, B, N, D)
        gate_weights = gate_weights.unsqueeze(-1).unsqueeze(-1)  # (B, num_experts, 1, 1)
        
        fused_output = (outputs * gate_weights).sum(dim=0)  # (B, N, D)
        
        return self.proj(fused_output)

端到端架构(商业模型)

端到端架构将视觉和语言建模统一在单一框架中,不使用独立的视觉编码器或采用原生多模态设计。

GPT-4V架构特点(推测)

OpenAI未公开GPT-4V的详细架构,但根据社区分析和论文推测:

推测特性说明
视觉编码可能使用改进的ViT或专用视觉Tokenizer
模态融合原生Transformer统一处理多模态
分辨率处理智能预处理,支持可变分辨率
上下文理解长序列处理能力
多语言支持多语言视觉理解
class GPT4V_Architecture:
    """
    GPT-4V架构(推测)
    """
    def __init__(self):
        # 推测:增强型视觉编码器
        self.vision_encoder = "Enhanced ViT with dynamic resolution"
        
        # 推测:统一的模态融合
        self.fusion = "Unified multimodal transformer"
        
        # 推测:GPT-4核心
        self.language_model = "GPT-4 core capabilities"
        
        # 推测特性
        self.features = {
            "resolution": "Variable, intelligent preprocessing",
            "aspect_ratio": "Native support for flexible ratios",
            "context_window": "Extended multimodal context",
            "languages": "Multilingual visual understanding",
            "image_tokenization": "Learned visual tokenizer"
        }
    
    def process_image(self, image):
        """
        推测的图像处理流程
        """
        # 1. 智能区域检测
        regions = self._detect_regions(image)
        
        # 2. 多尺度编码
        features = []
        for region in regions:
            feat = self._encode_region(region)
            features.append(feat)
        
        # 3. 自适应聚合
        return self._aggregate_features(features)
    
    def preprocess_image(self, image):
        """
        GPT-4V可能使用的高级预处理
        """
        # 感兴趣区域检测
        rois = self._find_rois(image)
        
        # 保持原始宽高比
        processed = []
        for roi in rois:
            # 智能缩放到合适大小
            scaled = self._smart_resize(roi)
            processed.append(scaled)
        
        return processed

Gemini原生多模态设计

Google Gemini是原生多模态架构的代表,从一开始就将多模态建模作为核心设计目标。1

class GeminiArchitecture:
    """
    Gemini: 原生多模态Transformer (M4T)
    """
    def __init__(self):
        # 统一的多模态Tokenizer
        self.mm_tokenizer = MultimodalTokenizer()
        
        # 原生多模态Transformer
        self.model = MultimodalTransformer(
            num_layers=32,
            hidden_dim=4096,
            num_heads=32,
            max_length=32768
        )
        
        # 支持的模态
        self.modalities = ["text", "image", "video", "audio"]
        
        # 核心创新
        self.innovations = {
            "unified_tokenizer": "Text, vision, audio unified tokenization",
            "native_cross_modal": "Cross-modal attention from layer 1",
            "joint_pretraining": "End-to-end multimodal pretraining"
        }
    
    def encode_multimodal(self, inputs):
        """
        统一处理多种模态输入
        """
        encoded = {}
        
        for modality in self.modalities:
            if modality in inputs:
                if modality == "image":
                    encoded[modality] = self.mm_tokenizer.tokenize_image(inputs[modality])
                elif modality == "text":
                    encoded[modality] = self.mm_tokenizer.tokenize_text(inputs[modality])
                elif modality == "audio":
                    encoded[modality] = self.mm_tokenizer.tokenize_audio(inputs[modality])
                elif modality == "video":
                    encoded[modality] = self.mm_tokenizer.tokenize_video(inputs[modality])
        
        # 拼接所有模态的tokens
        return self.concat_multimodal_tokens(encoded)
    
    def concat_multimodal_tokens(self, encoded):
        """
        多模态token拼接
        """
        all_tokens = []
        modality_ids = []
        
        for modality, tokens in encoded.items():
            all_tokens.append(tokens)
            modality_ids.extend([self.modality_to_id[modality]] * tokens.size(1))
        
        concatenated = torch.cat(all_tokens, dim=1)
        return concatenated
 
 
class MultimodalTransformer(nn.Module):
    """
    Gemini的多模态Transformer核心
    """
    def __init__(self, num_layers, hidden_dim, num_heads, max_length):
        super().__init__()
        
        self.layers = nn.ModuleList([
            MultimodalTransformerLayer(
                hidden_dim=hidden_dim,
                num_heads=num_heads
            )
            for _ in range(num_layers)
        ])
        
        # 模态嵌入
        self.modality_embeddings = nn.Embedding(8, hidden_dim)
    
    def forward(self, tokens, modality_ids=None):
        """
        Args:
            tokens: (B, L, D) 多模态tokens
            modality_ids: (B, L) 各token的模态ID
        """
        hidden_states = tokens
        
        # 添加模态嵌入
        if modality_ids is not None:
            mod_emb = self.modality_embeddings(modality_ids)
            hidden_states = hidden_states + mod_emb
        
        # 通过Transformer层
        for layer in self.layers:
            hidden_states = layer(hidden_states)
        
        return hidden_states
 
 
class MultimodalTransformerLayer(nn.Module):
    """
    多模态Transformer层:支持所有模态间的注意力交互
    """
    def __init__(self, hidden_dim, num_heads):
        super().__init__()
        
        # 通用自注意力
        self.self_attn = nn.MultiheadAttention(hidden_dim, num_heads, batch_first=True)
        
        # 模态间交叉注意力
        self.cross_modal_attn = CrossModalAttention(hidden_dim, num_heads)
        
        # 前馈网络
        self.ffn = nn.Sequential(
            nn.Linear(hidden_dim, hidden_dim * 4),
            nn.GELU(),
            nn.Linear(hidden_dim * 4, hidden_dim)
        )
        
        self.norms = nn.ModuleList([nn.LayerNorm(hidden_dim) for _ in range(3)])
    
    def forward(self, x):
        # Self-attention
        residual = x
        x = self.norms[0](x)
        x, _ = self.self_attn(x, x, x)
        x = residual + x
        
        # Cross-modal attention
        residual = x
        x = self.norms[1](x)
        x = self.cross_modal_attn(x, x, x)  # 同构设计,支持任意模态
        x = residual + x
        
        # FFN
        residual = x
        x = self.norms[2](x)
        x = residual + self.ffn(x)
        
        return x

Claude多模态能力

Anthropic的Claude 3系列通过集成视觉编码器实现了强大的多模态能力:

class ClaudeVision:
    """
    Claude的多模态处理
    """
    def __init__(self):
        # 视觉编码器
        self.vision_encoder = "Proprietary Vision Encoder"
        
        # 文本模型
        self.language_model = "Claude 3 Model"
        
        # 处理能力
        self.capabilities = {
            "high_resolution": "支持高分辨率图像",
            "document_understanding": "文档、表格、图表理解",
            "flowchart": "流程图和架构图解析",
            "handwriting": "手写内容识别",
            "spatial": "空间关系和布局理解"
        }
    
    def process_vision(self, image):
        """
        处理视觉输入
        """
        # 图像预处理
        processed = self.preprocess_image(image)
        
        # 视觉编码
        visual_features = self.vision_encoder(processed)
        
        # 投影到语言空间
        return self.project_to_llm(visual_features)

架构对比与选型指南

综合对比

架构类型代表模型参数量训练成本推理速度适用场景
Prefix-basedLLaVA7B-13B通用视觉对话
Gating-basedMiniGPT-47B轻量级部署
Cross-attentionInstructBLIP7B-11B指令跟随任务
混合架构LEO, Florence-VL10B+高精度场景
端到端Gemini未公开极高全场景通用

架构演进趋势

┌────────────────────────────────────────────────────────────────┐
│                        VLM架构演进                               │
├────────────────────────────────────────────────────────────────┤
│                                                                 │
│  2021-2022                    2023                    2024-2025│
│  ┌─────────┐              ┌─────────┐             ┌─────────┐  │
│  │ CLIP    │              │ LLaVA   │             │ 原生    │  │
│  │ 双塔    │ ──────────▶  │ Prefix  │ ──────────▶ │ 多模态  │  │
│  └─────────┘              └─────────┘             └─────────┘  │
│     │                         │                       │        │
│     ▼                         ▼                       ▼        │
│  模态独立                 轻量级融合             深度融合       │
│  特征提取                 桥梁连接               端到端学习      │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 关键演进方向:                                            │   │
│  │ • 冻结预训练模型 → 联合训练                                │   │
│  │ • 单一视觉编码器 → 多专家混合                              │   │
│  │ • 固定分辨率 → 动态分辨率                                 │   │
│  │ • 视觉-语言分离 → 原生多模态                               │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└────────────────────────────────────────────────────────────────┘

选型建议

根据不同应用场景的架构选择:

场景推荐架构原因
学术研究LLaVA开源、代码完善、易于修改
轻量级部署MiniGPT-4参数量小、训练简单
高质量对话InstructBLIP指令理解能力强
复杂视觉理解Florence-VL多粒度特征融合
企业级应用Gemini/Claude商业支持、能力全面

与现有内容的衔接

关联内容说明
LLaVAPrefix-based架构的详细实现
多模态模型综述商业模型与开源生态对比
CLIP视觉编码器基础
Transformer与注意力多模态注意力的技术基础
MoE混合架构中的专家选择机制
PEFTVLM的高效微调技术
LoRAVLM的参数高效微调实践

参考文献

Footnotes

  1. Google DeepMind, Gemini: A Family of Highly Capable Multimodal Models, 2023 2

  2. Liu et al., Visual Instruction Tuning, NeurIPS 2023 2

  3. Zhou et al., MiniGPT-4: Enhancing Vision Language Understanding with One Single Projection Layer, ICLR 2024

  4. Li et al., InstructBLIP: Towards General-purpose Vision-Language Models with Instruction Tuning, NeurIPS 2023

  5. Chen et al., Florence-VL: Enhanced Vision-Language Representation from Florence, CVPR 2025