Transformer XL原理介绍

1. 引言

在自然语言处理中,当前深度学习主流的结构是RNN和Transformer,因为这两种结构能够比较好地捕捉文本的上下文信息,但是,我们知道RNN主要的问题是梯度消失和梯度爆炸的问题,而且其捕捉上下文的长度没有Transformer那么强大,而Transformer虽然能力比较强,但是在预测时会受到训练时所设定的最大长度限制,因此,本文将介绍一个Transformer模型的变体,即Transformer XL(extra long),该模型是CMU和谷歌大脑在2019年提出来的,通过引入了递归的机制和相对位置编码,解决了Transformer长度限制的问题,作者在实验中发现,Transformer XL能捕捉到的文本长度比RNN长80%。

2. Transformer XL原理介绍

2.1 Vanilla Transformer

在介绍Transformer模型之前,先介绍另一个模型,该模型是2018年由Al-Rfou等人提出来的,作者称之为Vanilla Transformer,该模型其实本质上还是Transformer,只是将原来的句子进行切片,切成一个一个固定长度的短句子进行训练,如下图中的(a)所示,然后在预测时,采用训练时所设定的长度窗口,在句子上进行平移,从而不断获得句子的预测,如下图中的(b)所示,虽然这样操作可以解决句子的长度限制问题,但是存在两个主要的缺点:①每次平移后,模型都是从头开始计算,并没有利用前面计算得到的上文信息,因此,会出现一种“上下文断裂”的情况;②在预测时,当句子的长度比较长时,计算速度会非常慢,因为每次窗口只移动一个时间步,这样会导致很多信息重复计算。作者在实验中发现,采用Transformer XL模型,速度是Vanilla Transformer的1800多倍。
在这里插入图片描述

2.2 Segment-Level Recurrence

为了克服Vanilla Transformer模型的缺点,Transformer XL引入了一种递归的机制,即通用将句子按照固定的长度 L L L分成若干个子句,然后在训练和预测时,依次将每个子句传入Transformer模型,并且将每个子句在Transformer中各层的输出传递给下一个子句,如下图(a)中绿色线,在下一个子句每一层的计算中,将上一个子句对应上一层的输出与当前子句对应层的输入进行拼接,这样在每一个子句的预测时,就可以考虑到前面各个子句的信息。

记两个连续的子句为 s τ = [ x τ , 1 , ⋯   , x τ , L ] \mathbf{s}_{\tau}=\left[x_{\tau, 1}, \cdots, x_{\tau, L}\right] sτ=[xτ,1,,xτ,L] s τ + 1 = [ x τ + 1 , 1 , ⋯   , x τ + 1 , L ] \mathbf{s}_{\tau+1}=\left[x_{\tau+1,1}, \cdots, x_{\tau+1, L}\right] sτ+1=[xτ+1,1,,xτ+1,L],记第 τ \tau τ个子句第 n n n层的输出为 h τ n ∈ R L × d \mathbf{h}_{\tau}^{n} \in \mathbb{R}^{L \times d} hτnRL×d,其中 d d d表示隐藏层的维度,则第 τ + 1 \tau+1 τ+1个子句 s τ + 1 \mathbf{s}_{\tau+1} sτ+1 n n n层的输出计算如下:

h ~ τ + 1 n − 1 = [ S G ( h τ n − 1 ) ∘ h τ + 1 n − 1 ] q τ + 1 n , k τ + 1 n , v τ + 1 n = h τ + 1 n − 1 W q ⊤ , h ~ τ + 1 n − 1 W k ⊤ , h ~ τ + 1 n − 1 W v ⊤ h τ + 1 n =  Transformer-Layer  ( q τ + 1 n , k τ + 1 n , v τ + 1 n ) \begin{array}{l}{\widetilde{\mathbf{h}}_{\tau+1}^{n-1}=\left[\mathrm{SG}\left(\mathbf{h}_{\tau}^{n-1}\right) \circ \mathbf{h}_{\tau+1}^{n-1}\right]} \\ {\mathbf{q}_{\tau+1}^{n}, \mathbf{k}_{\tau+1}^{n}, \mathbf{v}_{\tau+1}^{n}=\mathbf{h}_{\tau+1}^{n-1} \mathbf{W}_{q}^{\top}, \widetilde{\mathbf{h}}_{\tau+1}^{n-1} \mathbf{W}_{k}^{\top}, \widetilde{\mathbf{h}}_{\tau+1}^{n-1} \mathbf{W}_{v}^{\top}} \\ {\mathbf{h}_{\tau+1}^{n}=\text { Transformer-Layer }\left(\mathbf{q}_{\tau+1}^{n}, \mathbf{k}_{\tau+1}^{n}, \mathbf{v}_{\tau+1}^{n}\right)}\end{array} h τ+1n1=[SG(hτn1)hτ+1n1]qτ+1n,kτ+1n,vτ+1n=hτ+1n1Wq,h τ+1n1Wk,h τ+1n1Wvhτ+1n</

### Transformer-XL 架构详解 Transformer-XL 是一种用于处理长序列数据的 Transformer 变体,其核心目标在于克服传统 Transformer 在处理超长文本时遇到的记忆限制和上下文断裂问题。以下是关于 Transformer-XL 的工作原理及其实现细节的具体描述。 #### 1. 循环机制 (Recurrent Mechanism) 传统的 Transformer 模型在处理长序列时通常会将其分割成多个固定长度的小片段(segments),这些片段之间缺乏有效的关联性。而 Transformer-XL 则通过引入 **循环机制** 来解决这一问题。具体来说,在前向传播过程中,上一段(previous segment)中的隐藏状态会被传递到下一段(next segment)。这种设计使得模型能够利用之前段的信息来增强当前段的理解能力[^1]。 #### 2. 相对位置编码 (Relative Positional Encoding) 除了循环机制外,Transformer-XL 还采用了 **相对位置编码** 替代绝对位置编码。这是因为当使用循环机制时,不同段之间的位置索引可能会发生冲突或重叠。因此,采用基于键值对间距离的位置表示方法可以更好地捕捉跨段依赖关系。对于任意两个词 \(i\) 和 \(j\) ,它们之间的相对位置被定义为: \[ r_{ij} = j - i \] 接着,通过对查询向量应用偏移操作并结合上述相对位置信息完成注意力权重计算[^2]。 #### 3. 单注意力头计算过程 假设我们正在讨论的是 Transformer-XL 中某一层内的某个单独注意单元,则该部分的核心运算可形式化表达如下所示: 给定输入张量 X ∈ \(\mathbb{R}^{T×d}\),其中 T 表示时间步数即 token 数目;d 表明特征维度大小。那么经过线性变换后的 Q、K、V 分别对应于 Query、Key 和 Value 向量矩阵: ```python Q = W_q * X + b_q # shape: [T, d_k] K = W_k * X + b_k # shape: [T, d_k] V = W_v * X + b_v # shape: [T, d_v] ``` 这里需要注意一点就是 K,V 不仅来自于当前时刻 t 所属的那个短窗口内部节点集合 S_t={t-L+1,...,t}(设 L=window size),还额外包含了来自先前若干个连续滑动窗所积累下来的长期记忆 M_(t-1): ```python A = softmax(Q @ K.T / sqrt(d_k)) # Attention weights matrix; shape: [T, T'] O = A @ concat([S_t, M_{t-1}], axis=-2) # Output after applying attention mechanism. ``` 最后再经由另一个全连接层映射回原始空间尺寸即可获得最终输出 Y=W_o*O+b_o。 #### 4. 实现方式优化 为了进一步提升效率与效果,实际工程实践中还会采取一些技巧性的手段来进行调整和完善,比如但不限于以下几点: - 使用分块稀疏策略减少不必要的计算开销; - 增加 dropout 层防止过拟合现象的发生; - 调整学习率调度器参数加快收敛速度等等[^4]。 ```python import torch.nn as nn class TransformerXL(nn.Module): def __init__(self, n_token, n_layer, n_head, d_model, d_inner, dropout): super(TransformerXL, self).__init__() self.drop = nn.Dropout(dropout) self.n_head = n_head self.word_emb = nn.Embedding(n_token, d_model) self.memories = None def forward(self, input_ids, target=None): word_emb = self.drop(self.word_emb(input_ids)) qlen, bsz = word_emb.size(0), word_emb.size(1) mlen = self.memories[0].size(0) if self.memories is not None else 0 klen = mlen + qlen all_ones = word_emb.new_ones((qlen, ), dtype=torch.uint8) dec_attn_mask = ~torch.triu(all_ones[:, :, None], diagonal=1+mlen).bool() hids = [] pos_seq = torch.arange(klen-1, -1, -1.0, device=word_emb.device, dtype=word_emb.dtype) pos_emb = self.pos_emb(pos_seq) core_out = self.drop(word_emb) pos_emb = self.drop(pos_emb) for i, layer in enumerate(self.layers): mems_i = None if self.memories is None else self.memories[i] core_out = layer(core_out, pos_emb, self.r_w_bias, self.r_r_bias, dec_attn_mask=dec_attn_mask, mems=mems_i) hids.append(core_out) new_mems = self._update_mems(hids) self.memories = new_mems last_hidden_state = core_out[-target.shape[0]:] prediction_scores = self.crit(last_hidden_state) return {'logits': prediction_scores} ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值