尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Qwen2-VL 视觉编码器源码拆解:从像素到 Token 的完整数据流
引言多模态大模型的视觉编码器通常被视为一个黑盒——图像进去token 出来但是当我们需要回答为什么 Qwen2-VL 能处理任意分辨率的图像或它和 Swin Transformer V2 的本质差异在哪等这样细致的问题我们必须打开这个黑盒追踪从像素到 token 的每一行代码因此本文基于 Qwen2-VL 官方源码将从数据流、核心模块、框架对比三个层面逐层拆解数据流分析配置文件我们打开源码的配置文件(通常文件名是包含 Config)看看配置内容是什么从配置文件看可以了解到 Vision Encoder 有 32 层 Transformer每一层输出 1280 维的特征并且会映射到 LLM 的维度是 3584 (说明具有投影层)采用的激活函数是 quick-gelu 等信息下面我们把里面一些关键的信息拿出来做分析Quick-gelu我们可以看到第一个设计点是激活函数的选择采用的是 quick-gelu这个激活函数我基本没有接触过但是从功能上看应该主流大模型都会用这个函数对应的表达式QuickGELU(x) x * sigmoid(1.702 * x)我们把两个函数图像拿出来对比发现基本上是吻合的最大误差只有0.02误差 0.02 在神经网络中间层完全可以忽略但计算速度提升约 30-50%很明显从公式上来看后者的计算明显是更简单用几乎不可见的精度损失换显著的速度提升token 压缩Vision Encoder 处理完一张图后会产生很多 token这个参数表示把相邻 2×2 4 个 token 压成 1 个减少数量为什么要压缩 token原因是 LLM 处理序列的计算复杂度为 O(n²)视觉 token 数量直接决定推理开销将 4 个 patch 压缩为 1 个 token能将序列长度降为 1/4计算量降为约 1/16一般都是采用 reshape 的方法实现时间切片处理视频时不仅要把画面切成空间 patch还要把时间切成小段这个参数表示每 2 帧画面打包成一个时间块那么这样视频就能和图像用同一套流程处理——图像可以看作只有 1 帧的视频时间块数为 1权重初始化的抖动范围神经网络刚开始训练时所有权重不能全是 0也不能太大这个值表示初始权重随机抖动的标准差是 0.02这个步骤很关键原因是如果初始化太大训练初期梯度会爆炸模型学不动如果全是 0所有神经元输出一样模型也学不动图片的预处理接着进入图片的预处理部分实现的功能是将图片转化成 tensor 的格式送进 Vision Encode千问在这边有一个小设计—动态分辨率处理简单来说就是保持原比例进行 resize传统的做法基本都是直接裁剪成为正方形这样做宽屏图被压扁了竖屏图被拉宽了信息可能会变形图像编码图像 Encoder 部分是架构中的核心的内容上图中的代码是功能的定义我们看看 forward 函数对这些功能是怎么编排的可以很直观看出数据的流动方向def forward( self, hidden_states: torch.Tensor, grid_thw: torch.Tensor, **kwargs: Unpack[TransformersKwargs] ) - torch.Tensor: r grid_thw (torch.LongTensor of shape (num_images, 3)): The temporal, height and width dimensions of feature shape for each image. Each row contains [t, h, w] values. position_ids get_vision_position_ids(grid_thw, self.spatial_merge_size, kwargskwargs) cu_seqlens get_vision_cu_seqlens(grid_thw, kwargskwargs) hidden_states self.patch_embed(hidden_states) rotary_pos_emb self.rotary_pos_emb(position_ids) emb torch.cat((rotary_pos_emb, rotary_pos_emb), dim-1) position_embeddings (emb.cos(), emb.sin()) for blk in self.blocks: hidden_states blk( hidden_states, cu_seqlenscu_seqlens, position_embeddingsposition_embeddings, **kwargs, ) merged_hidden_states self.merger(hidden_states) return BaseModelOutputWithPooling( last_hidden_statehidden_states, pooler_outputmerged_hidden_states, )数据流数据进来先被 Patch Embedding同时加上 2D-RoPE 位置编码最后传入 Transformer 模块压缩投影后返回注意一下blk 里面并没有 window_size 的字样也就是注意力采用的大概率是全局注意力Patch Embedding 这个步骤我们通常是用卷积直接实现的切分后直接映射只需要控制两个变量分别是 Kernel_size 和 Stride 就可以直接实现Block这个就是前面循环的 32 层的单个内部结构我们可以看看很标准的一个Pre-Norm 残差连接的模块在初始化定义的时候我们看到 sdpa这个全程是Scaled Dot-Product Attention表示的就是全局注意力机制我们继续看 VisionAttention 这个模块代码中有 self.is_causal False表示的是采用了双向注意力机制因果注意力Causal每个 token 只能看前面的不能看后面的LLM 生成文本时用非因果注意力Non-causal每个 token 可以看所有其他 token视觉特征提取时用这个部分就是一个常规的 qkv 的构造和 ViT 的实现基本上是一致的我们把上述的内容总结到表格上并且列举出来步骤操作输入 shape输出 shape关键源码预处理resize normalizePIL Image(3, H, W)image_processingPatchEmbedConv2d(k14,s14)(B,3,H,W)(B, N, 1280)patch_embed位置编码get_vision_position_idsgrid_thw(N, 2)rotary_pos_emb32层 BlockAttention MLP(B, N, 1280)(B, N, 1280)blocksMerger2×2 压缩 投影(B, N, 1280)(B, N/4, 3584)merger数据流的方向如下图所示框架对比在配置环境的时候会安装一个库叫做 Transformer库transformers 库会预装了几百个模型因此我们找 Swim-v2 直接搜就可以代码放下面python3 -c from transformers import Swinv2Model; import inspect; print(inspect.getsourcefile(Swinv2Model))注意力的不同Swim Transformer 的核心的创新就是引入了窗口注意力机制从而减少了计算量简单描述窗口注意力机制把全图切成小窗口每个 patch 只和窗口内的 patch 算注意力而不是和全图所有 patch 算聪明的你发现了那么不同窗口之间实际上是没有注意力交互的因此 Swim 提出可以使用滑动窗口的方式解决这个部分的问题那为什么 Qwen 敢用全局注意力呢前面我们有提到PatchMerger方法因此实际上在送进 LLM 之前我们已经尽量压缩 token 的个数虽然最后的视觉 token 少但是用全局注意力换更强的全局感知能力位置编码的不同Swin 的注意力只在一个小窗口里算它需要一个位置编码来告诉模型这 49 个 patch 彼此的相对位置是什么而 Qwen 的 Vision Encoder 是全局注意力它不需要知道窗口内的相对位置它需要知道的是每个 patch 在原图中的绝对二维坐标归一化的不同这是Swin V2 论文的核心创新之一Swin V1 用 Pre-Norm但模型变大后训练不稳定深层梯度爆炸因此 Swin V2 改成了Post-Norm论文指出 Post-Norm 能抑制特征方差增长让模型能稳定扩展到 3B 参数Pre-Norm (Qwen): x attn(norm(x)) ← 归一化在残差分支前 Post-Norm (Swin): norm(x attn(x)) ← 归一化在残差分支后为什么 Qwen 不做这样的处理呢因为 Qwen 的 Vision Encoder 只有 32 层、大约是 600M 参数Pre-Norm 足够稳定这个时候就有人问为什么 Qwen 不扩展呢因为多模态模型的瓶颈在 LLM不在视觉编码器视觉编码器的任务是提取特征LLM 的任务是理解、推理、生成因此大头是在后者那Swin 为什么需要扩展到 3B因为 Swin 是纯视觉 Backbone下游任务检测、分割、分类的性能直接取决于视觉特征的表达能力所以会扩展参数
RELATED

相关推荐

期刊投稿双检注意事项:编辑部查重 + AIGC 检测避坑指南

期刊投稿双检注意事项:编辑部查重 + AIGC 检测避坑指南

前言 现在越来越多普刊、核心期刊编辑部,在收稿之后不仅做重复率查重,同时开启 AIGC 生成内容筛查。很多作者辛辛苦苦写好稿件,重复率达标,却因为 AIGC 风险过高直接退稿。期刊和毕业论文不一样,期刊对行文严谨度、原创…

📅 2026/10/29 21:17:50
Git+Github学习笔记

Git+Github学习笔记

学习视频: GitGithub核心概念大串讲,从零到一全攻略,详细实战教程_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1ySLc6QEcB/?spm_id_from333.1391.0.0&vd_sourceb0ff309389fa15ce9ed7b52de0ab9ccb Git下载教程 Git 是一个分布式…

📅 2026/10/7 2:32:44
Spring Boot + Vue 教师绩效管理系统:从部署到二次开发全指南

Spring Boot + Vue 教师绩效管理系统:从部署到二次开发全指南

这次我们来看一个基于 Spring Boot Vue 的教师工作考核绩效管理系统。对于学校或教育机构的管理者来说,如何科学、高效、公正地量化教师的工作成果,一直是个不小的挑战。手动统计、Excel表格不仅容易出错,也难以实现动态管理和多维度分析。这…

📅 2026/9/8 9:26:53
MORE NEWS

更多资讯

📰

Flutter在OpenHarmony上的游戏开发实战

1. 项目背景与目标 在移动应用开发领域,跨平台框架Flutter因其高效的渲染性能和丰富的UI组件库而广受欢迎。而OpenHarmony作为国产开源操作系统,正在构建自己的应用生态。将Flutter应用于OpenHarmony平台,特别是游戏类App开发,是一…

📰

智慧农业中的生菜生长检测数据集构建与应用

1. 项目背景与数据集价值 在智慧农业领域,生菜作为典型的短周期叶菜类作物,其生长状态监测对精准农业管理具有重要意义。传统的人工观测方式存在效率低、主观性强等问题,而基于计算机视觉的自动化检测技术正在成为行业新趋势。这个包含4406张…

📰

Delphi 12 HTMX + WebStencils 中文实战:零JS动态网页开发指南

简介:本资源是面向Delphi开发者的技术进阶指南,聚焦Delphi 12在RAD Studio平台中集成HTMX与WebStencils实现高效Web开发的全新实践路径,特别适合熟悉传统VCL/LFM但希望快速切入轻量级动态网页开发的中高级程序员。内容系统解析HTMX核心机制—…

📰

微软MAI-Image-2技术解析:照片级AI生图突破与应用

1. 微软MAI-Image-2技术解析:照片级写实生图如何实现行业突破当微软研究院在计算机视觉顶会CVPR 2023的workshop上首次展示MAI-Image-2的生成样本时,现场研究者们传阅的手机屏幕上,那些真假难辨的人像照片引发了持续讨论。这个基于扩散模型架…

📰

智慧农业生菜生长状态检测数据集解析与应用

1. 项目概述:智慧农业生菜生长状态检测数据集 这个数据集是专门为智慧农业场景下生菜生长状态检测任务设计的标准化数据资源包。它包含了4406张高质量的生菜生长过程图像,采用VOC和YOLO两种主流标注格式,覆盖了生菜生长周期的3个关键状态类别…

📰

OpenSSL ENGINE机制解析:如何实现加密算法透明替换

简介:这份文档面向需要理解 OpenSSL 扩展加密能力的开发者与安全工程师,聚焦 ENGINE 机制这一通用加密接口的设计与实现,帮助读者弄清 OpenSSL 如何透明调用第三方软件加密库或硬件加密设备,适合具备一定密码学基础、希望深入 Ope…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬