PyTorch 实战:Transformer 模型搭建全解析

Transformer 作为一种强大的序列到序列模型,凭借自注意力机制在诸多领域大放异彩。它能并行处理序列,有效捕捉上下文关系,其架构包含编码器与解码器,各由多层组件构成,涉及自注意力、前馈神经网络、归一化和 Dropout 等关键环节 。下面我们深入探讨其核心要点,并结合代码实现进行详细解读。

一、Transformer 核心公式与机制

(一)自注意力计算

自注意力机制是 Transformer 的核心,其计算基于公式\(Attention(Q, K, V)=softmax\left(\frac{Q K^{T}}{\sqrt{d_{k}}}\right) V\) 。其中,Q、K、V分别是查询、键和值矩阵,由输入X分别乘以对应的权重矩阵\(W_Q\)、\(W_K\)、\(W_V\)得到 。\(d_{k}\)表示键的维度,除以\(\sqrt{d_{k}}\) ,一方面可防止\(QK^{T}\)过大导致 softmax 计算溢出,另一方面能让\(QK^{T}\)结果满足均值为 0、方差为 1 的分布 。\(QK^{T}\)本质上是计算向量间的余弦相似度,反映向量方向上的相似程度。

(二)多头注意力机制

多头注意力机制将输入x拆分为h份,独立计算h组不同的线性投影得到各自的Q、K、V ,然后并行计算注意力,最后拼接h个注意力池化结果,并通过可学习的线性投影产生最终输出。这种设计使每个头能关注输入的不同部分,增强了模型对复杂函数的表示能力。

(三)位置编码

由于 Transformer 没有循环结构,位置编码用于保留序列中的位置信息,确保模型在处理序列时能感知元素的位置。

二、自注意力与多头注意力的实现

(一)自注意力实现

在 PyTorch 中,自注意力模块Self_Attention的实现如下:

python

复制代码
import numpy as np
import torch
from torch import nn

class Self_Attention(nn.Module):
    def __init__(self, input_dim, dim_k, dim_v):
        super(Self_Attention, self).__init__()
        self.q = nn.Linear(input_dim, dim_k)
        self.k = nn.Linear(input_dim, dim_k)
        self.v = nn.Linear(input_dim, dim_v)
        self._norm_fact = 1 / np.sqrt(dim_k)

    def forward(self, x):
        Q = self.q(x) 
        K = self.k(x) 
        V = self.v(x) 
        atten = nn.Softmax(dim=-1)(torch.bmm(Q, K.permute(0, 2, 1))) * self._norm_fact
        output = torch.bmm(atten, V)
        return output


X = torch.randn(4, 3, 2)
self_atten = Self_Attention(2, 4, 5) 
res = self_atten(X)
print(res.shape) 

在这段代码中,Self_Attention类继承自nn.Module__init__方法初始化了线性层qkv ,并计算了归一化因子_norm_factforward方法实现了自注意力的计算过程,先通过线性层得到Q、K、V ,然后计算注意力权重atten ,最后得到输出output

(二)多头注意力实现

多头注意力模块Self_Attention_Muti_Head的实现如下:

python

复制代码
import torch
import torch.nn as nn

class Self_Attention_Muti_Head(nn.Module):
    def __init__(self,input_dim,dim_k,dim_v,nums_head):
        super(Self_Attention_Muti_Head,self).__init__()
        assert dim_k % nums_head == 0
        assert dim_v % nums_head == 0
        self.q = nn.Linear(input_dim,dim_k)
        self.k = nn.Linear(input_dim,dim_k)
        self.v = nn.Linear(input_dim,dim_v)
        self.nums_head = nums_head
        self.dim_k = dim_k
        self.dim_v = dim_v
        self._norm_fact = 1 / np.sqrt(dim_k)

    def forward(self,x):
        Q = self.q(x).reshape(-1,x.shape[0],x.shape[1],self.dim_k // self.nums_head) 
        K = self.k(x).reshape(-1,x.shape[0],x.shape[1],self.dim_k // self.nums_head) 
        V = self.v(x).reshape(-1,x.shape[0],x.shape[1],self.dim_v // self.nums_head)
        atten = nn.Softmax(dim=-1)(torch.matmul(Q,K.permute(0,1,3,2))) 
        output = torch.matmul(atten,V).reshape(x.shape[0],x.shape[1],-1) 
        return output


x=torch.rand(1,3,4)
atten=Self_Attention_Muti_Head(4,4,4,2)
y=atten(x)
print(y.shape) 

在这个类中,__init__方法进行了参数校验和模块初始化 。forward方法将输入x经过线性层变换后,重塑形状以适应多头计算,接着计算注意力权重并得到输出,最后将多头的结果拼接起来。

三、注意力机制的拓展

(一)视觉注意力机制

视觉注意力机制主要包括空间域、通道域和混合域三种。空间域注意力通过对图片空间域信息进行变换,生成掩码并打分来提取关键信息;通道域注意力为每个通道分配权重,代表模块有 SENet,通过全局池化提取通道权重,进而调整特征图;混合域注意力则结合了空间域和通道域的信息 。

(二)通道域注意力(SENet)实现

SENet 的实现代码如下:

python

复制代码
class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c) 
        y = self.fc(y).view(b, c, 1, 1) 
        return x * y.expand_as(x)

SELayer类中,__init__方法初始化了平均池化层avg_pool和全连接层序列fcforward方法实现了 SENet 的核心操作,先通过平均池化进行 Squeeze 操作,再经过全连接层进行 Excitation 操作,最后将生成的权重与原特征图相乘,实现对特征图的增强 。

(三)门控注意力机制(GCT)

GCT 是一种能提升卷积网络泛化能力的通道间建模结构。它包含全局上下文嵌入、通道规范化和门控适应三个部分。全局上下文嵌入模块汇聚每个通道的全局上下文信息;通道规范化构建神经元竞争关系;门控适应加入门限机制,促进神经元的协同或竞争关系 。

其实现代码如下:

python

复制代码
class GCT(nn.Module):
    def __init__(self, num_channels, epsilon=1e-5, mode='l2', after_relu=False):
        super(GCT, self).__init__()
        self.alpha = nn.Parameter(torch.ones(1, num_channels, 1, 1))
        self.gamma = nn.Parameter(torch.zeros(1, num_channels, 1, 1))
        self.beta = nn.Parameter(torch.zeros(1, num_channels, 1, 1))
        self.epsilon = epsilon
        self.mode = mode
        self.after_relu = after_relu

    def forward(self, x):
        if self.mode == 'l2':
            embedding = (x.pow(2).sum((2, 3), keepdim=True) + self.epsilon).pow(0.5) * self.alpha
            norm = self.gamma / ((embedding.pow(2).mean(dim=1, keepdim=True) + self.epsilon).pow(0.5))
        elif self.mode == 'l1':
            if not self.after_relu:
                _x = torch.abs(x)
            else:
                _x = x
            embedding = _x.sum((2, 3), keepdim=True) * self.alpha
            norm = self.gamma / (torch.abs(embedding).mean(dim=1, keepdim=True) + self.epsilon)
        gate = 1. + torch.tanh(embedding * norm + self.beta)
        return x * gate

GCT类中,__init__方法初始化了可训练参数alphagammabeta以及其他超参数 。forward方法根据不同的模式(l2l1)计算嵌入和归一化结果,最后通过门控机制得到输出 。GCT 通常添加在 Conv 层前,训练时可先冻结原模型训练 GCT,再解冻微调 。

相关推荐
老胖闲聊12 分钟前
Python Copilot【代码辅助工具】 简介
开发语言·python·copilot
Blossom.11816 分钟前
使用Python和Scikit-Learn实现机器学习模型调优
开发语言·人工智能·python·深度学习·目标检测·机器学习·scikit-learn
曹勖之1 小时前
基于ROS2,撰写python脚本,根据给定的舵-桨动力学模型实现动力学更新
开发语言·python·机器人·ros2
scdifsn1 小时前
动手学深度学习12.7. 参数服务器-笔记&练习(PyTorch)
pytorch·笔记·深度学习·分布式计算·数据并行·参数服务器
DFminer2 小时前
【LLM】fast-api 流式生成测试
人工智能·机器人
lyaihao2 小时前
使用python实现奔跑的线条效果
python·绘图
郄堃Deep Traffic2 小时前
机器学习+城市规划第十四期:利用半参数地理加权回归来实现区域带宽不同的规划任务
人工智能·机器学习·回归·城市规划
ai大师2 小时前
(附代码及图示)Multi-Query 多查询策略详解
python·langchain·中转api·apikey·中转apikey·免费apikey·claude4
海盗儿2 小时前
Attention Is All You Need (Transformer) 以及Transformer pytorch实现
pytorch·深度学习·transformer
GIS小天3 小时前
AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月7日第101弹
人工智能·算法·机器学习·彩票