Qwen2.5-vl源码解析(一)
解析qwen2.5-vl源码。
qwen2.5-vl仓库地址:QwenLM/Qwen2.5-VL: Qwen2.5-VL is the multimodal large language model series developed by Qwen team, Alibaba Cloud.
不过源码不在这个仓库里,需要pip install最新版的transformers库然后去库里面的model目录下去找T^T
第一篇先把几个视觉部分的工具类写一下。
1.Qwen2RMSNorm
class Qwen2RMSNorm(nn.Module):
def __init__(self, hidden_size, eps=1e-6):
"""
Qwen2RMSNorm is equivalent to T5LayerNorm
"""
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.variance_epsilon = eps
def forward(self, hidden_states):
input_dtype = hidden_states.dtype
hidden_states = hidden_states.to(torch.float32)
variance = hidden_states.pow(2).mean(-1, keepdim=True)
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
return self.weight * hidden_states.to(input_dtype)
def extra_repr(self):
return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
作用:LLM中的归一化层,采用RMSNorm,即对输入除以均方值再乘以权重。
归一化的主要目的就是提高训练的稳定性,缓解梯度消失或爆炸的问题。而采用RMSNorm归一化可以简化流程,因为不需要计算均值。
2.Qwen2_5_VisionPatchEmbed
class Qwen2_5_VisionPatchEmbed(nn.Module):
def __init__(
self,
patch_size: int = 14,
temporal_patch_size: int = 2,
in_channels: int = 3,
embed_dim: int = 1152,
) -> None:
super().__init__()
self.patch_size = patch_size
self.temporal_patch_size = temporal_patch_size
self.in_channels = in_channels
self.embed_dim = embed_dim
kernel_size = [temporal_patch_size, patch_size, patch_size]
self.proj = nn.Conv3d(in_channels, embed_dim, kernel_size=kernel_size, stride=kernel_size, bias=False)
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
target_dtype = self.proj.weight.dtype
hidden_states = hidden_states.view(
-1, self.in_channels, self.temporal_patch_size, self.patch_size, self.patch_size
)
hidden_states = self.proj(hidden_states.to(dtype=target_dtype)).view(-1, self.embed_dim)
return hidden_states
作用:对三维(时间,高度,宽度)的视频,分块映射到一个高维的嵌入空间。
对于一个size为(T,H,W,C)的数据,最终输出为(N_patches,embed_dim)。
patch_size:patch的长和宽。
temporal_patch_size:时间维度上patch的长度。
in_channel:图像的通道数 ,RGB图像是3。
embed_dim:嵌入空间维度。
kernel_size = [temporal_patch_size, patch_size, patch_size]
self.proj = nn.Conv3d(in_channels, embed_dim, kernel_size=kernel_size, stride=kernel_size, bias=False)
上面代码是核心,首先设置一个三维的kernel_size,之后的self.proj虽然是利用Convd3d卷积层,但本质上是一个Linear的作用,因为可以看到他的stride(步幅)就等于kernel_size,所以就是不断地对每一个kernel大小的patch进行投影,之后跳到下一个patch。
hidden_states = hidden_states.view(
-1, self.in_channels, self.temporal_patch_size, self.patch_size, self.patch_size
)
这里用view调整形状,pytorch卷积层输入要求通道维度在第二位。
3.Qwen2_5_VisionRotaryEmbedding
class Qwen2_5_VisionRotaryEmbedding(nn.Module):
def __init__(self, dim: int, theta: float = 10000.0) -> None:
super().__init__()
inv_freq = 1.0 / (theta ** (torch.arange(0, dim, 2, dtype=torch.float) / dim))
self.register_buffer("inv_freq", inv_freq, persistent=False)
def forward(self, seqlen: int) -> torch.Tensor:
seq = torch.arange(seqlen, device=self.inv_freq.device, dtype=self.inv_freq.dtype)
freqs = torch.outer(seq, self.inv_freq)
return freqs
作用:计算Rope需要的频率矩阵
这里给出一个例子。
dim = 4 theta = 10000
则得到inv_freq为[1.0, 0.01](之后向量的每两个维度对应一个频率)
seq假设为[0,1,2]
则得到3×2的矩阵
[[0,0],
[1,0.01],
[2,0.02]]
4.Qwen2_5_VLPatchMerger
class Qwen2_5_VLPatchMerger(nn.Module):
def __init__(self, dim: int, context_dim: int, spatial_merge_size: int = 2) -> None:
super().__init__()
self.hidden_size = context_dim * (spatial_merge_size**2)
self.ln_q = Qwen2RMSNorm(context_dim, eps=1e-6)
self.mlp = nn.Sequential(
nn.Linear(self.hidden_size, self.hidden_size),
nn.GELU(),
nn.Linear(self.hidden_size, dim),
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = self.mlp(self.ln_q(x).view(-1, self.hidden_size))
return x
作用:融合四个patch在一起,之后通过MLP投影到语言模型的嵌入空间。
context_dim就是原本一个patch的隐藏层维度,spatial_merge_size是一个方向上要融合的patch数,等于2的话意味着融合2×2=4个块,等于3的话意味着融合3×3=9个块,默认设置为2,则融合4个patch在一起。
所以hidden_size就是4*context_dim。
而dim就是语言模型token的特征维度,这里的self.mlp的作用就类似于LLaVA中的线性投影层,映射视觉特征到语义嵌入空间,后面的Qwen2_5_VisionTransformerPretrainedModel类中会用到。
具体forward流程就是先对输入进行一次归一化,再通过view修改形状,之后通过mlp进行投影。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)