欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

详细分解Transformer各部件总结

发布时间:2025/4/5 编程问答 52 豆豆
生活随笔 收集整理的这篇文章主要介绍了 详细分解Transformer各部件总结 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

Transformer的介绍

  • Transformer的优势

    • # 1. Transformer能够利用分布式GPU进行并行训练,提升模型训练效率 # 2. 在分析预测更长文本时,捕捉间隔较长的语义关联效果更好, 作用:基于seq2seq架构的transformer模型可以完成NLP领域研究的典型任务,如机器翻译,文本生成等,同时又可以构建预训练语言模型,用于其他任务
  • Transformer架构

    • 输入部分

      • 源文本嵌入层及其位置编码器
        • 文本嵌入(Embedding)作用:无论源文本嵌入还是目标文本嵌入,都是为了将文本中词汇的数字表示转变为向量表示,希望在这样的高维空间捕捉词汇之间的关系
        • 位置编码器的作用:在编码器结构中,并没有对词汇位置信息进行处理,因此需要在Embdeding层后加入位置编码器,将词汇位置不同可能会产生不同语义的信息加入到词嵌入张量中,以弥补位置信息的缺失
      • 目标文本嵌入层及其位置编码器
    • 输出部分

      • 线性层
      • softmax层
    • 编码器部分

      • N个编码器层堆叠而成
      • 每个编码器由两个子层连接结构组成
      • 第一个子层链接包含一个多头自注意力层和规范化层及一个残差连接
      • 第二个子层连接结构包含一个前馈全连接子层和规范化层及一个残差连接
    • 解码器部分

      • N个解码器层堆叠而成
      • 每个解码器由三个子层连接结构组成
      • 第一个子层链接包含一个多头自注意力层和规范化层及一个残差连接
      • 第二个子层链接包含一个多头自注意力层和规范化层及一个残差连接
      • 第三个子层连接结构包含一个前馈全连接子层和规范化层及一个残差连接

1. 输入部分

  • 文本词嵌入

    • 作用:对输入文本数值化以方便拟合算法

    • import math import torch import torch.nn as nn class Embeddings(nn.Module):def __init(self, d_model, vocab):"""d_model: 词嵌入的维度vocab: 词表的大小"""super(Emdedings,self).__init()self.lut = nn.Embedding(vocab, d_model)self.d_model = d_modeldef forward(self, x):return self.lut(x) * math.sqrt(self.d_model)
  • 位置编码器

    • 作用:因为在transformer的编码器结构中,并没有对词汇位置信息的处理,所以需要在embedding层后加入位置编码器,将词汇位置不同可能会产生不同语义的信息加入到词嵌入张量中,以弥补位置信息的缺失

      • class PositionalEncoding(nn.Module):"""d_model: 词嵌入的维度dropout: 置0比率max_len: 句子最大长度"""def __init__(self, d_model, dropout, max_len=5000):super(PositionalEncoding, self).__init__()self.dropout = nn.Dropout(p=dropout)# 初始化一个位置编码矩阵,它是0阵,大小维max_len * d_modelpe = torch.zeros(max_len, d_model)# 绝对位置矩阵,词汇的绝对位置就是用它的索引去表示position = torch.arange(0, max_len).unsqueeze(1)# 将位置信息加入到位置编码矩阵中,将绝对位置矩阵有max_len*1变成max_len*d_model, 覆盖原来的初始化位置编码矩阵# 先需要一个1*d_model的变换矩阵div_term,其实div_term是一个1*d_model/2的矩阵div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(10000.)/d_model))# 位置编码数值控制在-1,1之间有助于梯度下降pe[:, 0::2] = torch.sin(position*div_term)pe[:, 1::2] = torch.cos(position*div_term)# 现在pe是一个二维矩阵,embedded之前要扩展一个维度pe = pe.unsqueeze(0)# 将位置编码矩阵注册成模型的buffer,对模型效果有帮助,却不是模型结构中的超参数,不需要随着优化步骤进行更新的增益对象# 注册之后我们可以在模型保存后重加载时和模型结构与参数一同加载self.register_buffer('pe', pe)def forward(self, x):# x.size(1),根据输入句子的长度,截取pe的范围print("位置编码:", Variable(self.pe[:, :x.size(1)]).size())x = x + Variable(self.pe[:, :x.size(1)], requires_grad=False)return self.dropout(x)

2. 编码器部分

  • 多头注意力机制

    • 作用:多头的本质是多个独立的attention计算,作为一个集成的作用,防止过拟合

      • # 注意力机制 def attention(query, key, value, mask=None, dropout=None):# 词嵌入维度大小d_k = query.size(-1)# 计算注意力矩阵scorescores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)# 判断是否使用掩码张量if mask:scores = scores.masked_fill(mask == 0, -1e9)# 对scores进行最后一维进行softmaxp_atten = F.softmax(scores, dim=-1)if dropout:p_atten = dropout(p_atten)return torch.matmul(p_atten, value), p_attendef clone(module, N):"""实现模型深拷贝:param module:要拷贝的目标网络层:param N: 拷贝数量"""return nn.ModuleList([copy.deepcopy(module) for _ in range(N)])class MultiHeadedAttention(nn.Module):"""多头注意力机制head:头数embedding_dim: 词嵌入维度dropout: 置零率"""def __init__(self, head, embedding_dim, dropout=0.1):super(MultiHeadedAttention, self).__init__()self.head = headself.attn = Noneself.dropout = nn.Dropout(p=dropout)# 判断head能否整除词嵌入维度assert embedding_dim % head == 0self.d_k = embedding_dim // head# 4表示多头注意力中Q,K,V各需要一个,最后拼接的矩阵还需要一个self.linears = clone(nn.Linear(embedding_dim, embedding_dim), 4)def forward(self, query, key, value, mask=None):if mask:mask = mask.unsqueeze(1)# 获取batch size大小batch_size = query.size(0)# 多头处理环节, 将embedding.size变为head.size * d_k.size# 对二、三维进行转置操作,让句子长度维度和词向量维度能够相邻,这样注意力机制才能找到词义与句子的位置关系query, key, value = [model(x).view(batch_size, -1, self.head, self.d_k).transpose(1, 2) for model, x in zip(self.linears, (query, key, value))]# 接下来传入attentionx, self.attn = attention(query, key, value, mask=mask, dropout=self.dropout)# 获得每个头计算结果组成的4维张量x = x.transpose(1, 2).contiguous().view(batch_size, -1, self.head*self.d_k)return self.linears[-1](x)
  • 前馈全连接层

    • 作用:考虑注意力机制拟合程度不够,故意增加两层网络来增强模型的能力

      • class PositionWiseFeedForward(nn.Module):"""前馈全连接层d_model: 词嵌入的维度d_ff: 全连接层维度"""def __init__(self, d_model, d_ff, dropout=0.1):super(PositionWiseFeedForward, self).__init__()self.fc1 = nn.Linear(d_model, d_ff)self.fc2 = nn.Linear(d_ff, d_model)self.dropout = nn.Dropout(p=dropout)def forward(self, x):return self.fc2(self.dropout(F.relu(self.fc1(x))))
  • 规范化层

    • 作用:有助于模型收敛,防止过拟合

      • class LayerNorm(nn.Module):"""数据规范化features: 词嵌入的维度"""def __init__(self, features, eps=1e-6):super(LayerNorm, self).__init__()# nn.parameter代表模型参数self.a = nn.Parameter(torch.ones(features))self.b = nn.Parameter(torch.zeros(features))self.eps = epsdef forward(self, x):mean = x.mean(-1, keepdim=True)std = x.std(-1, keepdim=True)return self.a*(x-mean) / (std+self.eps) + self.b
  • 残差连接

    • 作用:很好解决深度模型退化问题,同时使模型收敛更快,前后向传播更加顺畅

      • class sublayerConnection(nn.Module):"""子层残差连接结构size: 词嵌入的维度"""def __init__(self, size, dropout=0.1):super(SublayerConnection, self).__init__()# 规范化层self.norm = LayerNorm(size)self.dropout = nn.Dropout(p=dropout)def forward(self, x, sublayer):return x + self.dropout(sublayer(self.norm(x)))
  • 编码器层

    • 作用:作为编码器组成部分,完成对输入的特征提取

      • class EncoderLayer(nn.Module):"""编码器size: 词嵌入维度self_attn: 多头自注意力机制feed_forward: 前馈全连接层dropout: 置零比例"""def __init__(self, size, self_attn, feed_forward, dropout):super(EncoderLayer, self).__init__()self.self_attn = self_attnself.feed_forward = feed_forwardself.size = size# 编码器层有两个残差连接结构self.sublayer = clone(SublayerConnection(size, dropout), 2)def forward(self, x, mask):x = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, mask))return self.sublayer[1](x, self.feed_forward)
  • 编码器

    • 作用:对输入的特征提取,由若干个编码层组成

      • class Encoder(nn.Module):"""实现编码器encoder_layer: 编码器层num_layer: 编码器层的个数"""def __init__(self, encoder_layer, num_layer):super(Encoder, self).__init__()self.layers = clone(encoder_layer, num_layer)self.norm = LayerNorm(encoder_layer.size)def forward(self, x, mask):for layer in self.layers:x = layer(x, mask)return self.norm(x)

3. 解码器部分

  • 解码器层

    • 作用:根据给定的输入向目标进行特征提取

      • class DecoderLayer(nn.Module):"""解码器层size: 词嵌入的维度大小self_attn: 多头自注意力机制src_attn: 多头注意力机制feed_forward: 前馈神经网络"""def __init__(self, size, self_attn, src_attn, feed_forward, dropout):super(DecoderLayer, self).__init__()self.size = sizeself.self_attn = self_attnself.src_attn = src_attnself.feed_forward = feed_forwardself.dropout = dropoutself.sublayer = clone(SublayerConnection(size, dropout), 3)def forward(self, x, memory, source_mask, target_mask):"""x: 上一层输出memory: 编码器语义存储变量source_mask: 源数据掩码张量, 遮掩住对结果没有意义的字符target_mask: 目标数据掩码张量,不希望模型利用后续信息"""m = memoryx = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, target_mask))x = self.sublayer[1](x, lambda x: self.src_attn(x, m, m, source_mask))return self.sublayer[3](x, self.feed_forward)
  • 编码器

    • 作用:提取encoder输出的特征

      • class Decoder(nn.Module):"""解码器decoder_layer: 解码器层num_layer: 解码器层个数"""def __init__(self, decoder_layer, num_layer):super(Decoder, self).__init__()self.layers = clone(decoder_layer, num_layer)self.norm = LayerNorm(decoder_layer.size)def forward(self, x, memory, source_mask, target_mask):for layer in self.layers:x = layer(x, memory, source_mask, target_mask)return self.norm(x)

4. 输出部分

  • 输出结构

    • class Generator(nn.Module):"""输出层结构d_model: 词嵌入维度vocab_size: 词表大小"""def __init__(self, d_model, vocab_size):super(Generator, self).__init__()self.project = nn.Linear(d_model, vocab_size)def forward(self, x):return F.log_softmax(self.project(x), dim=-1)

总结

以上是生活随笔为你收集整理的详细分解Transformer各部件总结的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。