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,再解冻微调 。

相关推荐
kadog3 分钟前
《Python3网络爬虫开发实战(第二版)》配套案例 spa6
开发语言·javascript·爬虫·python
徒慕风流4 分钟前
利用Python爬虫实现百度图片搜索的PNG图片下载
开发语言·爬虫·python
蹦蹦跳跳真可爱58913 分钟前
Python----深度学习(基于深度学习Pytroch线性回归和曲线回归)
pytorch·python·深度学习·神经网络·回归·线性回归
周杰伦_Jay25 分钟前
continue插件实现IDEA接入本地离线部署的deepseek等大模型
java·数据结构·ide·人工智能·算法·数据挖掘·intellij-idea
HtwHUAT31 分钟前
五、web自动化测试01
前端·css·chrome·python·功能测试·selenium·html
海森大数据35 分钟前
Crawl4AI:打破数据孤岛,开启大语言模型的实时智能新时代
人工智能·语言模型·自然语言处理
果冻人工智能40 分钟前
我在大厂做 机器学习工程经理:这六顶帽子,每天都在换
人工智能
啊阿狸不会拉杆1 小时前
数据结构-图
java·c语言·数据结构·c++·python·算法·图论
萧鼎1 小时前
RAGFlow:构建高效检索增强生成流程的技术解析
人工智能·python
爱的叹息1 小时前
主流开源 LLM 应用开发平台详解
人工智能·开源