正弦位置编码是否需交错sin与cos?两种实现方案正确性咨询
正弦位置编码两种实现的有效性验证
我正在实现正弦位置编码(sinusoidal positional encoding),发现两种不同的实现方案生成的编码结果存在差异,附上两种方案的代码及可视化结果,想确认这两种方案是否存在错误,或是均为有效实现?
方案1实现代码
class SinusoidalPosEmb(nn.Module): def __init__(self, dim): super().__init__() self.dim = dim def forward(self, x): device = x.device half_dim = self.dim // 2 emb = math.log(10000) / (half_dim - 1) emb = torch.exp(torch.arange(half_dim, device=device) * -emb) emb = x[:, None] * emb[None, :] emb = torch.cat((emb.sin(), emb.cos()), dim=-1) return emb
方案1编码可视化:
方案2实现代码
class TransformerPositionalEmbedding(nn.Module): """ From paper "Attention Is All You Need", section 3.5 """ def __init__(self, dimension, max_timesteps=1000): super(TransformerPositionalEmbedding, self).__init__() assert dimension % 2 == 0, "Embedding dimension must be even" self.dimension = dimension self.pe_matrix = torch.zeros(max_timesteps, dimension) # Gather all the even dimensions across the embedding vector even_indices = torch.arange(0, self.dimension, 2) # Calculate the term using log transforms for faster calculations log_term = torch.log(torch.tensor(10000.0)) / self.dimension div_term = torch.exp(even_indices * -log_term) # Precompute positional encoding matrix based on odd/even timesteps timesteps = torch.arange(max_timesteps).unsqueeze(1) self.pe_matrix[:, 0::2] = torch.sin(timesteps * div_term) self.pe_matrix[:, 1::2] = torch.cos(timesteps * div_term) def forward(self, timestep): # [bs, d_model] return self.pe_matrix[timestep]
方案2编码可视化:
两种实现的分析与结论
两种方案均为有效实现,差异源于对频率衰减参数的不同设置,并非错误:
方案2是严格对齐原论文的标准实现:
完全遵循《Attention Is All You Need》3.5节的公式,计算div_term时使用log(10000)/dimension作为缩放因子,确保偶数维度的位置编码为sin(pos / 10000^(2i/dimension)),奇数维度为cos(pos / 10000^(2i/dimension)),是Transformer架构中最常用的正弦位置编码实现。方案1是原论文的变体实现:
它将频率衰减的分母从dimension改为half_dim - 1(即dimension//2 - 1),这会调整不同维度上的频率衰减速度,使得位置编码的频率变化节奏与标准实现不同,但依然通过正弦/余弦的不同频率组合为每个位置提供独特的编码标识,同样能起到位置编码的作用,常见于一些Diffusion模型的时间步编码场景。
两者的可视化差异正是由于频率参数的调整导致的,本质上都能满足位置编码的核心需求——让模型区分不同的序列位置。
内容的提问来源于stack exchange,提问作者Janikas
相关产品推荐
相关产品推荐

