Transformer-based模型中的位置信息编码

本文探讨了位置编码在Transformer模型中的关键作用,包括绝对位置编码和相对位置编码的不同变体,如NEZHA和BERT使用的编码方式。通过对比实验,文章揭示了位置编码在注意力矩阵中融合的优势,以及相对位置编码为何能提升模型性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        华为推出的预训练模型nezha的其中一项创新点为使用了相对位置的函数式编码。于是本文对于Transformer相关的模型中对于字词的位置编码方式进行简单的总结。本文参考了浅谈 Transformer-based 模型中的位置表示 - 知乎

        1.原生的transformer中使用的是绝对位置的函数式位置编码,使用的是正余弦函数。由于transformer中为self-attention,这种正余弦函数由于点乘操作,其实会有隐式的相对位置信息存在,但是没有方向性,且通过权重矩阵的映射之后,这种信息可能会消失。

        2.bert中使用的是绝对位置的参数式编码,且和相应位置上的词向量进行相加而不是拼接。

        3.RPR,相对位置表示。将相对位置信息融入attention的计算中。

        4.transformer-XL  XLNet, 正余弦函数矩阵和一个偏置项(参数)来表示相对位置。

        5.nezha,使用相对位置函数编码

==================================================

最近(2021-04-21)google又出了一篇关于位置编码对transformer效果的影响:Demystifying the Better Performance of Position Encoding Variants for Transformer

论文地址:https://arxiv.org/abs/2104.08698 有兴趣可以仔细读一下。

摘要:

Transformers是目前nlp效果最好的模型,它把输入序列转化成向量。模型对于输入词的位置信息是加在了输入当中,分段信息也通过这样的方式加入。最近的一些位置编码变体表明相对位置编码的效果会更好。本文对不通的位置编码方式进行系统的比较,理解它们不同表现的原因,并提出一种有效的位置和分段编码方式。

介绍:

Transformers的主要结构为self-attention和feed forward层,这两者对输入token的位置是不敏感的。为了使模型位置敏感,最典型的方式就是把位置嵌入加到token嵌入中。这个位置嵌入只取决于词出现的位置,就是说位置i的嵌入只和i有关,和i位置上的词是无关的。位置嵌入也可以是固定的,比如正弦函数嵌入。对于位置嵌入有很多的研究,这些工作展示了使用相对位置编码会比绝对位置编码效果好,但是不知道为什么。缺乏系统的研究和两种方法优缺点的理解。

 本文认为绝对位置编码的效果差是因为融合方式是加入到输入中。文章在分类、问答、翻译任务上进行实验,表明在attention矩阵加入位置编码比在输入token中加入位置信息效果好。这表明位置信息在哪里融合入Transformers中是重要的。文章也比较了不同head和不同层共享位置编码的情况,提出了相对标量位置编码变体和新的相对分段编码方法。

Transformers

绝对位置编码

        两种变体:固定的函数式(原生的transformers)和参数式的(BERT)。

相对位置编码

        绝对位置编码的一个缺点是要求固定的输入长度。为了泛化到任意序列长度,就是使用相对位置编码。接下来就是介绍一些流行的相对位置编码方法。

        1.相对位置编码加入attention计算(K,V)而不是输入,这个部分会增加位置信息参数。并在不同的head共享位置编码提高效率。

        2.相对函数编码+学习参数。

相对位置标量

        T5中使用的方法,位置编码标量直接加入attention分值矩阵;V向量中不加位置信息。不同的head使用不同的位置编码,不同层共享。

TUPE

        略

输入加位置信息的缺点

        1.绝对位置编码的时候,如果位置编码加入输入的情况,损失函数对于位置和输入是相同的。在不同的batch中,输入X是不一样的,而位置其实是不变的,所以给予输入X和位置不同的自由度可以提高效果。之前的相对位置编码方法没有这个问题。

        2.该定理表明,注意矩阵的秩受绝对位置编码的约束,通过在注意矩阵中加入位置信息来使用per-head(低秩位置矩阵)编码,可以直接得到更高秩的注意。

绝对位置编码:        

相对位置编码:

实验:

        见论文。

<think>好的,我需要帮助用户了解如何使用Python实现基于Transformer模型。首先,我应该回顾Transformer的基本结构,包括自注意力机制、位置编码和前馈网络。然后,结合用户提供的引用内容,特别是引用[1]提到的位置编码和引用[3]中的模型配置,我需要将这些元素整合到实现步骤中。 用户可能对PyTorch或TensorFlow更熟悉,但考虑到引用中的例子提到了华为的NEZHA模型,而PyTorch在研究中更常用,因此选择PyTorch作为框架可能更合适。接下来,我需要分模块讲解Transformer的各个部分,例如嵌入层、位置编码、多头注意力、前馈网络,以及如何将它们组合成完整的模型。 在位置编码部分,需要区分绝对位置编码和相对位置编码,如引用[1]所述,华为的NEZHA使用了相对位置编码,但基础Transformer使用正弦函数的绝对编码。因此,我需要先实现绝对位置编码,并提及相对位置编码作为扩展。 多头注意力模块是实现的关键,需要解释如何将输入分成多个头,计算缩放点积注意力,然后合并结果。此外,残差连接和层归一化也是必须的组件,需要包含在代码中。 前馈网络部分相对简单,通常是两个线性层中间夹一个激活函数,比如ReLU。然后,将这些模块堆叠成编码器层,多个编码器层组成完整的Transformer模型。 在训练部分,根据引用[2]提到的超参数设置,如Adam优化器、学习率1e-4、早停策略等,需要给出训练循环的基本框架,并提醒用户根据任务调整参数。 最后,生成相关问题时要覆盖模型结构、位置编码优化、超参数调整和应用场景,参考用户提供的引用内容中的信息,确保问题具有相关性和深度。 需要检查代码是否符合PyTorch的最佳实践,语法正确,并且关键部分有注释说明。同时,确保回答结构清晰,分步骤讲解,帮助用户逐步构建模型。</think>以下是用Python实现Transformer-based模型的逐步说明,结合PyTorch框架和关键代码示例: --- ### 1. 模型结构概览 Transformer模型编码-解码器结构组成,核心组件包括: - 多头注意力机制(Multi-Head Attention) - 位置编码(Positional Encoding) - 前馈网络(Feed Forward Network) - 残差连接与层归一化 引用文献中提到的配置建议:使用两个注意力-前馈块、嵌入大小512/1024、注意力头数16/32[^3] --- ### 2. 关键模块实现 #### 2.1 位置编码(引用[1]中的位置信息编码) ```python import torch import math class PositionalEncoding(torch.nn.Module): def __init__(self, d_model, max_len=5000): super().__init__() pe = torch.zeros(max_len, d_model) position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] = torch.sin(position * div_term) # 偶数位置正弦编码 pe[:, 1::2] = torch.cos(position * div_term) # 奇数位置余弦编码 self.register_buffer('pe', pe.unsqueeze(0)) def forward(self, x): return x + self.pe[:, :x.size(1)] ``` #### 2.2 多头注意力机制 ```python class MultiHeadAttention(torch.nn.Module): def __init__(self, d_model, num_heads): super().__init__() self.d_model = d_model self.num_heads = num_heads self.head_dim = d_model // num_heads self.Wq = torch.nn.Linear(d_model, d_model) self.Wk = torch.nn.Linear(d_model, d_model) self.Wv = torch.nn.Linear(d_model, d_model) self.out = torch.nn.Linear(d_model, d_model) def scaled_dot_product_attention(self, Q, K, V, mask=None): scores = torch.matmul(Q, K.transpose(-1, -2)) / math.sqrt(self.head_dim) if mask is not None: scores = scores.masked_fill(mask == 0, -1e9) attention = torch.nn.functional.softmax(scores, dim=-1) return torch.matmul(attention, V) def forward(self, x): batch_size = x.size(0) Q = self.Wq(x).view(batch_size, -1, self.num_heads, self.head_dim).transpose(1,2) K = self.Wk(x).view(batch_size, -1, self.num_heads, self.head_dim).transpose(1,2) V = self.Wv(x).view(batch_size, -1, self.num_heads, self.head_dim).transpose(1,2) attention = self.scaled_dot_product_attention(Q, K, V) concat = attention.transpose(1,2).contiguous().view(batch_size, -1, self.d_model) return self.out(concat) ``` --- ### 3. 完整模型搭建 ```python class TransformerEncoderLayer(torch.nn.Module): def __init__(self, d_model, num_heads, ff_dim, dropout=0.1): super().__init__() self.attention = MultiHeadAttention(d_model, num_heads) self.norm1 = torch.nn.LayerNorm(d_model) self.ffn = torch.nn.Sequential( torch.nn.Linear(d_model, ff_dim), torch.nn.ReLU(), torch.nn.Linear(ff_dim, d_model) ) self.norm2 = torch.nn.LayerNorm(d_model) self.dropout = torch.nn.Dropout(dropout) def forward(self, x): attn_output = self.attention(x) x = self.norm1(x + self.dropout(attn_output)) ffn_output = self.ffn(x) return self.norm2(x + self.dropout(ffn_output)) class Transformer(torch.nn.Module): def __init__(self, vocab_size, d_model=512, num_heads=8, ff_dim=2048, num_layers=6, dropout=0.1): super().__init__() self.embedding = torch.nn.Embedding(vocab_size, d_model) self.pos_encoding = PositionalEncoding(d_model) self.encoder_layers = torch.nn.ModuleList([ TransformerEncoderLayer(d_model, num_heads, ff_dim, dropout) for _ in range(num_layers) ]) def forward(self, src): x = self.embedding(src) x = self.pos_encoding(x) for layer in self.encoder_layers: x = layer(x) return x ``` --- ### 4. 训练配置(参考引用[2]参数设置) ```python # 初始化模型 model = Transformer( vocab_size=30000, d_model=512, num_heads=8, ff_dim=2048, num_layers=6, dropout=0.1 ) # 优化器配置 optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) # 训练循环示例 def train(model, dataloader, epochs=200): model.train() for epoch in range(epochs): for batch in dataloader: inputs, targets = batch outputs = model(inputs) loss = torch.nn.functional.cross_entropy(outputs, targets) optimizer.zero_grad() loss.backward() optimizer.step() ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值