Transformer原理及解析

本文深入解析Transformer模型,介绍如何利用self-attention机制替代RNN处理序列数据,实现长序列并行计算,并探讨了Multi-Head Attention的设计,包括Positional Encoding在模型中的作用。

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

x# Transformer

视频链接:https://www.youtube.com/watch?v=ugWDIIOHtPA&t=2055s

transformer是一个拥有self-attention的Sequence2Sequence模型,

Sequence

在这里插入图片描述

RNN是常用的Sequence模型,在双向的sequence模型中,b1 ,b2 的输入为a1到a4 ,适用于解决序列化的问题常用语音和NLP领域。但是序列化执行难以并行处理。希望采用CNN来替代RNN,实现并行化处理,然而CNN只有高层的filter的感受野比较大,能考虑长的序列。

self-attention

在这里插入图片描述

用self-attention来代替RNN,既能考虑长的序列,有能便于并行化。

如何做self-attention?

在这里插入图片描述

  1. 输入的变量为xi ,首先对xi做编码 得到编码后的向量 ai
class Embeddings(nn.Module):
    def __init__(self, d_model, vocab):
        super(Embeddings, self).__init__()
        self.lut = nn.Embedding(vocab, d_model)

    def forward(self, x):
        return self.lut(x) 

nn.Embedding是一个l固定字典lookup的表格,初始化的输入为单词数vocab和编码向量维度d_model。

  1. 对向量ai 分别得到 用于attention的三元组(q,k,v)

  2. 拿每个query去对每个key做attention,用点乘计算:α1,i=q1⋅ki/d\alpha_{1,i}=q^1\cdot k^i/\sqrt{d}α1,i=q1ki/d <img
    在这里插入图片描述

    attention之后用softmax归一化:α^1,i=exp(α1,i)/∑jexp(α1,j)\hat{\alpha}_{1,i}=exp(\alpha_{1,i})/\sum_j exp(\alpha_{1,j})α^1,i=exp(α1,i)/jexp(α1,j)

在这里插入图片描述

之后通过加权平均得到最后的输出:b1=∑iα^1,ivib^1=\sum_i\hat{\alpha}_{1,i}v^ib1=iα^1,ivi

在这里插入图片描述

def attention(query, key, value, mask=None, dropout=None):
	d_k = query.size(-1)
	scores = torch.matmul(query, key.transpose(-2, -1)) \
		/ math.sqrt(d_k)
	if mask is not None:
		scores = scores.masked_fill(mask == 0, -1e9)
	p_attn = F.softmax(scores, dim = -1)
	if dropout is not None:
		p_attn = dropout(p_attn)
	return torch.matmul(p_attn, value), p_attn

在实际实验中query,key,value维度为(batch, head个数,序列长度,特征数量)。通过矩阵乘法后scores的维度是(batch,head个数,序列长度,序列长度)。matmul会把query和key的最后两维进行矩阵乘法,这样效率更高。

为什么易于并行?

在这里插入图片描述

可以将每个时刻的输入做concat操作,这样直接通过一个矩阵乘法能够得到所有的值

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

所有的计算都是矩阵乘法,所以易于并行化。

Multi-head self-attention

每个head关注的东西可能不同

在这里插入图片描述

class MultiHeadedAttention(nn.Module):
	def __init__(self, h, d_model, dropout=0.1):
		super(MultiHeadedAttention, self).__init__()
		assert d_model % h == 0
		# We assume d_v always equals d_k
		self.d_k = d_model // h
		self.h = h
		self.linears = clones(nn.Linear(d_model, d_model), 4)
		self.attn = None
		self.dropout = nn.Dropout(p=dropout)
	
	def forward(self, query, key, value, mask=None): 
		if mask is not None:
			# 所有h个head的mask都是相同的 
			mask = mask.unsqueeze(1)
		nbatches = query.size(0)
		
		# 1) 首先使用线性变换,然后把d_model分配给h个Head,每个head为d_k=d_model/h 
		query, key, value = \
			[l(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2)	
				for l, x in zip(self.linears, (query, key, value))]
		
		# 2) 使用attention函数计算
		x, self.attn = attention(query, key, value, mask=mask, 
			dropout=self.dropout)
		
		# 3) 把8个head的64维向量拼接成一个512的向量。然后再使用一个线性变换(512,521),shape不变。 
		x = x.transpose(1, 2).contiguous() \
			.view(nbatches, -1, self.h * self.d_k)
		return self.linears[-1](x)

先看构造函数,这里d_model(512)是Multi-Head的输出大小,因为有h(8)个head,因此每个head的d_k=512/8=64。接着我们构造4个(d_model x d_model)的矩阵,后面我们会看到它的用处。最后是构造一个Dropout层。

然后我们来看forward方法。输入的mask是(batch, 1, time)的,因为每个head的mask都是一样的,所以先用unsqueeze(1)变成(batch, 1, 1, time),mask我们前面已经详细分析过了。

接下来是根据输入query,key和value计算变换后的Multi-Head的query,key和value。这是通过下面的语句来实现的:

query, key, value = \
		[l(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2)	
			for l, x in zip(self.linears, (query, key, value))]

zip(self.linears, (query, key, value))是把(self.linears[0],self.linears[1],self.linears[2])和(query, key, value)放到一起然后遍历。我们只看一个self.linears[0] (query)。根据构造函数的定义,self.linears[0]是一个(512, 512)的矩阵,而query是(batch, time, 512),相乘之后得到的新query还是512(d_model)维的向量,然后用view把它变成(batch, time, 8, 64)。然后transponse成(batch, 8,time,64),这是attention函数要求的shape。分别对应8个Head,每个Head的Query都是64维。

Key和Value的运算完全相同,因此我们也分别得到8个Head的64维的Key和64维的Value。接下来调用attention函数,得到x和self.attn。其中x的shape是(batch, 8, time, 64),而attn是(batch, 8, time, time)。

x.transpose(1, 2)把x变成(batch, time, 8, 64),然后把它view成(batch, time, 512),其实就是把最后8个64维的向量拼接成512的向量。最后使用self.linears[-1]对x进行线性变换,self.linears[-1]是(512, 512)的,因此最终的输出还是(batch, time, 512)。我们最初构造了4个(512, 512)的矩阵,前3个用于对query,key和value进行变换,而最后一个对8个head拼接后的向量再做一次变换。
Positional Encoding

在这里插入图片描述
在这里插入图片描述

<think>好的,用户让我解析一下Transformer原理。之前他们问过CNN、RNN和GAN,现在可能是在学习深度学习的不同模型,想系统地了解各个重要架构。用户可能是学生或者刚入门的研究者,需要深入但易懂的解释。 首先,我需要回顾用户之前的对话。他们之前已经了解了CNN、RNN和GAN,所以对基础概念应该有一定了解。Transformer是RNN的替代品,特别是在处理长序列时表现更好,用户可能知道RNN的局限性,比如梯度消失和并行计算困难,所以需要强调Transformer如何解决这些问题。 接下来,我需要解析Transformer的核心部分。应该从整体结构入手,分为编码器和解码器。然后重点讲解自注意力机制,这是Transformer的关键。要解释Query、Key、Value的概念,以及如何计算注意力分数。可能需要提到多头注意力,为什么需要多头的设计,比如捕捉不同子空间的信息。 然后,位置编码部分也很重要,因为Transformer没有循环结构,必须显式地加入位置信息。要解释正弦和余弦函数的编码方法,或者现在常用的可学习的位置编码。 另外,前馈网络部分虽然简单,但也要提到,每个层中的FFN的作用。残差连接和层归一化也是关键,帮助模型训练更稳定,防止梯度消失或爆炸。 在应用方面,用户可能想知道Transformer在哪些地方被使用,比如BERT、GPT这些模型,以及它们在NLP任务中的表现。同时,可以提到Transformer在CV领域的应用,如Vision Transformer,让用户了解其扩展性。 需要注意避免使用太多数学公式,保持解释直观。可能需要用比喻,比如自注意力机制像检索系统,每个词寻找相关的其他词。同时要对比之前的模型,比如RNN,说明Transformer的优势,比如并行计算和处理长距离依赖。 还要考虑用户可能的疑问,比如为什么自注意力能替代RNN,位置编码如何工作,训练时的效率如何等。需要确保解释清晰,逻辑连贯,结构分明。 最后,总结Transformer的重要性,以及对后续模型的影响,比如推动预训练模型的发展。可能用户接下来会问BERT或者GPT,所以提前为后续问题做铺垫,但当前回答保持聚焦在Transformer本身。好的</think>!Transformer 是一种基于**自注意力机制(Self-Attention)**的深度学习模型,由2017年Google的论文《Attention Is All You Need》提出。它彻底改变了序列建模(如自然语言处理)的范式,摒弃了传统RNN/CNN的循环或卷积结构,通过全局并行计算和长距离依赖捕捉能力,成为当前AI领域的核心架构(如GPT、BERT均基于其设计)。 --- ### **一、核心思想** **目标**:解决RNN的缺陷(无法并行、长程依赖弱),直接建模序列中任意两个元素的关系。 **关键创新**: 1. **自注意力机制**:动态计算序列中每个元素与其他元素的关联权重。 2. **位置编码**:引入位置信息,弥补无循环/卷积结构的位置感知缺失。 3. **并行化设计**:所有位置的注意力计算可同时完成,极大提升训练效率。 --- ### **二、核心组件解析** #### **1. 自注意力机制(Self-Attention)** - **输入表示**: 每个输入词向量通过嵌入层转换为**Query(Q)、Key(K)、Value(V)**三组向量。 - **计算关联权重**: 通过Q与K的点积计算两两相似度,再经Softmax归一化为注意力权重: \[ \text{Attention}(Q,K,V) = \text{Softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V \] (其中 \(d_k\) 是缩放因子,防止梯度爆炸) - **物理意义**: 每个词通过权重聚合其他词的信息(如“猫”关注“抓”“老鼠”),生成上下文感知的表示。 #### **2. 多头注意力(Multi-Head Attention)** - **并行化多组注意力**: 将Q/K/V拆分为多组(如8个头),分别计算注意力后拼接结果。 - **优势**: 允许模型同时关注不同子空间的信息(如语法、语义、指代关系)。 #### **3. 位置编码(Positional Encoding)** - **问题**:Transformer没有循环结构,无法感知词序。 - **解决方案**: 为每个词的位置生成唯一编码(如正弦/余弦函数或可学习的向量),与词向量相加。 \[ PE_{(pos,2i)} = \sin(pos/10000^{2i/d_{model}}}) \\ PE_{(pos,2i+1)} = \cos(pos/10000^{2i/d_{model}}}) \] (通过不同频率的正余弦函数区分位置) #### **4. 前馈网络(Feed-Forward Network, FFN)** - **结构**:每个位置独立经过两层全连接层(如ReLU激活)。 - **作用**:对注意力后的特征进行非线性变换和增强。 #### **5. 残差连接与层归一化** 每个子层(注意力、FFN)后加入残差连接(Residual Connection)和层归一化(LayerNorm),缓解梯度消失。 --- ### **三、整体架构** #### **1. 编码器(Encoder)** 由N个相同层堆叠(通常N=6),每层包含: - **多头自注意力层** - **前馈网络层** (均含残差连接和归一化) #### **2. 解码器(Decoder)** 结构与编码器类似,但额外引入: - **掩码多头注意力**:防止解码时看到未来信息(通过掩码屏蔽后续位置)。 - **交叉注意力层**:将编码器输出作为K/V,解码器当前状态作为Q,实现编码-解码对齐。 --- ### **四、关键优势** 1. **并行计算**:所有位置的注意力矩阵可并行计算(RNN需逐步处理)。 2. **全局依赖建模**:任意两个位置的直接关联(无论距离多远)。 3. **可扩展性**:可堆叠更多层,支持超长序列(如Transformer-XL改进)。 --- ### **五、应用场景** - **自然语言处理**: - 机器翻译(原始论文任务) - 文本生成(GPT系列)、理解(BERT) - **计算机视觉**: - Vision Transformer(ViT)将图像分块作为序列处理 - 目标检测(DETR) - **多模态**: - CLIP(图文匹配)、语音识别(Conformer) --- ### **六、代码示例(简化版自注意力)** ```python import torch import torch.nn as nn class SelfAttention(nn.Module): def __init__(self, embed_size): super().__init__() self.embed_size = embed_size self.Q = nn.Linear(embed_size, embed_size) self.K = nn.Linear(embed_size, embed_size) self.V = nn.Linear(embed_size, embed_size) def forward(self, x): # x: [batch_size, seq_len, embed_size] Q = self.Q(x) # [batch, seq, d_k] K = self.K(x) # [batch, seq, d_k] V = self.V(x) # [batch, seq, d_v] scores = torch.matmul(Q, K.transpose(1,2)) / (self.embed_size ** 0.5) attention = torch.softmax(scores, dim=-1) output = torch.matmul(attention, V) return output ``` --- ### **总结** Transformer通过自注意力机制实现了序列建模的“全局视野”和高效并行,成为现代AI的基石。其设计启发了BERT、GPT等预训练模型,并跨界应用于CV、语音等领域,持续推动技术突破。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值