Transformer实现以及Pytorch源码解读(四)-Encoder层

这篇具有很好参考价值的文章主要介绍了Transformer实现以及Pytorch源码解读(四)-Encoder层。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Transformer结构图

先放一张原论文中的图。从inputs到Poitional Encoding在前三部分中已经分析清楚,接下来往后分析。
Transformer实现以及Pytorch源码解读(四)-Encoder层

Pytorch中对Transformer的调用

Pytorch将图1中左半部分的神经网络层用一个TransformerEncdoer(encoder_layer,num_layers)类进行封装,该类的传参有两个:TransformerEncoderLayer(encoder_layer)和堆叠的层数(num_layers)。

class Transformer(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, num_class,
                 dim_feedforward=512, num_head=2, num_layers=2, dropout=0.1, max_len=512, activation: str = "relu"):
        super(Transformer, self).__init__()
        # 词嵌入层
        self.embedding_dim = embedding_dim
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        #其实max_len可以不用设置的太大,只要比最大句子的长度大一些就行了。
        self.position_embedding = PositionalEncoding(embedding_dim, dropout, max_len)
        # 编码层:使用Transformer
        encoder_layer = nn.TransformerEncoderLayer(hidden_dim, num_head, dim_feedforward, dropout, activation)
        self.transformer = nn.TransformerEncoder(encoder_layer, num_layers)
        # 输出层
        self.output = nn.Linear(hidden_dim, num_class)

    def forward(self, inputs, lengths):
        #注意输入的input,每一列表示一个样本,总共有batch_size列
        inputs = torch.transpose(inputs, 0, 1)
        hidden_states = self.embeddings(inputs)
        hidden_states = self.position_embedding(hidden_states)
        attention_mask = length_to_mask(lengths) == False
        hidden_states = self.transformer(hidden_states, src_key_padding_mask=attention_mask).transpose(0, 1)
        logits = self.output(hidden_states)
        log_probs = F.log_softmax(logits, dim=-1)
        return log_probs

接下来逐一分析涉及到的两个类

TransformerEncdoer类

该类处于目录\site-packages\torch\nn\modules\transformer下。

class TransformerEncoder(Module):
    r"""TransformerEncoder is a stack of N encoder layers

    Args:
        encoder_layer: an instance of the TransformerEncoderLayer() class (required).
        num_layers: the number of sub-encoder-layers in the encoder (required).
        norm: the layer normalization component (optional).

    Examples::
        >>> encoder_layer = nn.TransformerEncoderLayer(d_model=512, nhead=8)
        >>> transformer_encoder = nn.TransformerEncoder(encoder_layer, num_layers=6)
        >>> src = torch.rand(10, 32, 512)
        >>> out = transformer_encoder(src)
    """
    __constants__ = ['norm']
    def __init__(self, encoder_layer, num_layers, norm=None):
        super(TransformerEncoder, self).__init__()
        self.layers = _get_clones(encoder_layer, num_layers)
        self.num_layers = num_layers
        self.norm = norm
    def forward(self, src: Tensor, mask: Optional[Tensor] = None, src_key_padding_mask: Optional[Tensor] = None) -> Tensor:
        r"""Pass the input through the encoder layers in turn.
        Args:
            src: the sequence to the encoder (required).
            mask: the mask for the src sequence (optional).
            src_key_padding_mask: the mask for the src keys per batch (optional).
        Shape:
            see the docs in Transformer class.
        """
        output = src
        for mod in self.layers:
            output = mod(output, src_mask=mask, src_key_padding_mask=src_key_padding_mask)
        if self.norm is not None:
            output = self.norm(output)
        return output

可以发现该类比较简单,主要进行的是对堆叠的操作。首先将拿到的encoder_layer通过_get_clones()函数克隆若干份,然后在forward中进行循环的调用。我们可以看下)_get_clones方法的实现:

def _get_clones(module, N):
    return ModuleList([copy.deepcopy(module) for i in range(N)])

可以看出主要是利用copy的deepcopy将模型复制了N份,然后在forward中循环的调用自己。这也说明了TransformerEncoderLayer输入输出的维度必定要一样,可以后文求证。

TransformerEncoderLayer类

class TransformerEncoderLayer(Module):
    r"""TransformerEncoderLayer is made up of self-attn and feedforward network.
    This standard encoder layer is based on the paper "Attention Is All You Need".
    Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N Gomez,
    Lukasz Kaiser, and Illia Polosukhin. 2017. Attention is all you need. In Advances in
    Neural Information Processing Systems, pages 6000-6010. Users may modify or implement
    in a different way during application.

    Args:
        d_model: the number of expected features in the input (required).
        nhead: the number of heads in the multiheadattention models (required).
        dim_feedforward: the dimension of the feedforward network model (default=2048).
        dropout: the dropout value (default=0.1).
        activation: the activation function of the intermediate layer, can be a string
            ("relu" or "gelu") or a unary callable. Default: relu
        layer_norm_eps: the eps value in layer normalization components (default=1e-5).
        batch_first: If ``True``, then the input and output tensors are provided
            as (batch, seq, feature). Default: ``False``.
        norm_first: if ``True``, layer norm is done prior to attention and feedforward
            operations, respectivaly. Otherwise it's done after. Default: ``False`` (after).

    Examples::
        >>> encoder_layer = nn.TransformerEncoderLayer(d_model=512, nhead=8)
        >>> src = torch.rand(10, 32, 512)
        >>> out = encoder_layer(src)

    Alternatively, when ``batch_first`` is ``True``:
        >>> encoder_layer = nn.TransformerEncoderLayer(d_model=512, nhead=8, batch_first=True)
        >>> src = torch.rand(32, 10, 512)
        >>> out = encoder_layer(src)
    """
    __constants__ = ['batch_first', 'norm_first']

    def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1, activation=F.relu,
                 layer_norm_eps=1e-5, batch_first=False, norm_first=False,
                 device=None, dtype=None) -> None:
        factory_kwargs = {'device': device, 'dtype': dtype}
        super(TransformerEncoderLayer, self).__init__()
        self.self_attn = MultiheadAttention(d_model, nhead, dropout=dropout, batch_first=batch_first,
                                            **factory_kwargs)
        # Implementation of Feedforward model
        self.linear1 = Linear(d_model, dim_feedforward, **factory_kwargs)
        self.dropout = Dropout(dropout)
        self.linear2 = Linear(dim_feedforward, d_model, **factory_kwargs)
        self.norm_first = norm_first
        self.norm1 = LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs)
        self.norm2 = LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs)
        self.dropout1 = Dropout(dropout)
        self.dropout2 = Dropout(dropout)
        # Legacy string support for activation function.
        if isinstance(activation, str):
            self.activation = _get_activation_fn(activation)
        else:
            self.activation = activation
    def __setstate__(self, state):
        if 'activation' not in state:
            state['activation'] = F.relu
        super(TransformerEncoderLayer, self).__setstate__(state)
    def forward(self, src: Tensor, src_mask: Optional[Tensor] = None, src_key_padding_mask: Optional[Tensor] = None) -> Tensor:
        r"""Pass the input through the encoder layer.

        Args:
            src: the sequence to the encoder layer (required).
            src_mask: the mask for the src sequence (optional).
            src_key_padding_mask: the mask for the src keys per batch (optional).

        Shape:
            see the docs in Transformer class.
        """
        # see Fig. 1 of https://arxiv.org/pdf/2002.04745v1.pdf
        x = src
        if self.norm_first:
            x = x + self._sa_block(self.norm1(x), src_mask, src_key_padding_mask)
            x = x + self._ff_block(self.norm2(x))
        else:
            x = self.norm1(x + self._sa_block(x, src_mask, src_key_padding_mask))
            x = self.norm2(x + self._ff_block(x))

        return x
 # self-attention block
    def _sa_block(self, x: Tensor,
                  attn_mask: Optional[Tensor], key_padding_mask: Optional[Tensor]) -> Tensor:
        x = self.self_attn(x, x, x,
                           attn_mask=attn_mask,
                           key_padding_mask=key_padding_mask,
                           need_weights=False)[0]
        return self.dropout1(x)

    # feed forward block
    def _ff_block(self, x: Tensor) -> Tensor:
        x = self.linear2(self.dropout(self.activation(self.linear1(x))))
        return self.dropout2(x)

先看forward()函数,该函数是对x进行的加操作,所以不会改变x的维度,因此我们前面的假设是成立的,TransformerEncdoer类中堆叠的过程输入输出是一样的维度,并且就是通过for循环连续调用。
其中forward中的下面两行包含了Transformer Encoder层的所有运算逻辑:首先,输入与多头注意力机制的结果相加并输出结果,随后,上层的输出结果加上前向反馈的结果经过一个前向传播层(归一化的前向传播层),输出最终的结果。

x = self.norm1(x + self._sa_block(x, src_mask, src_key_padding_mask))
x = self.norm2(x + self._ff_block(x))

同时为了保持维度的同步,feed forward模块的操作如下:

def _ff_block(self, x: Tensor) -> Tensor:
        x = self.linear2(self.dropout(self.activation(self.linear1(x))))
        return self.dropout2(x)

linear1和linear2的初始化参数如下。结合__off_block操作可以看出,feed forward模块首先将词向量拉伸到dim_feedforward层,随后又用linear2从dim_feedforward层拉伸到原来的词向量维度(d_model)。

 Implementation of Feedforward model
 self.linear1 = Linear(d_model, dim_feedforward, **factory_kwargs)
 self.dropout = Dropout(dropout)
 self.linear2 = Linear(dim_feedforward, d_model, **factory_kwargs)

总结

至此,数据流在Transormer编码层的流动过程已经清晰,除了MultiheadAttention,其他的代码和层的设置都是pytorch中的基本操作,不再详细追踪底层实现。MultiheadAttention的代码实现在下节中进行分析。文章来源地址https://www.toymoban.com/news/detail-426440.html

到了这里,关于Transformer实现以及Pytorch源码解读(四)-Encoder层的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 36k字从Attention解读Transformer及其在Vision中的应用(pytorch版)

    深度学习中的卷积操作:https://blog.csdn.net/zyw2002/article/details/128306697 1.1.1 Encoder-Decoder Encoder-Decoder框架顾名思义也就是 编码-解码框架 ,在NLP中Encoder-Decoder框架主要被用来处理 序列-序列问题 。也就是输入一个序列,生成一个序列的问题。这两个序列可以分别是任意长度。 具体

    2024年02月11日
    浏览(40)
  • 【transformer】自注意力源码解读和复杂度计算

    A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V Attention(Q,K,V) = softmax(frac{QK^T}{sqrt{d_k}})V A tt e n t i o n ( Q , K , V ) = so f t ma x ( d k ​ ​ Q K T ​ ) V 其中, Q Q Q 为查询向量, K K K 和 V V V 为键向量和值向量, d k d_k d k ​ 为向量的维度。 Q Q Q 、 K K K 和 V V V 在一般情况下是相同的

    2024年02月10日
    浏览(42)
  • Transformer实战-系列教程21:DETR 源码解读8 损失计算:(SetCriterion类)

    有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 点我下载源码 DETR 算法解读 DETR 源码解读1(项目配置/CocoDetection类/ConvertCocoPolysToMask类) DETR 源码解读2(DETR类) DETR 源码解读3(位置编码:Joiner类/PositionEmbeddingSine类)

    2024年02月19日
    浏览(43)
  • Transformer实战-系列教程15:DETR 源码解读2(整体架构:DETR类)

    有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 点我下载源码 DETR 算法解读 DETR 源码解读1(项目配置/CocoDetection类/ConvertCocoPolysToMask类) DETR 源码解读2(DETR类) DETR 源码解读3(位置编码:Joiner类/PositionEmbeddingSine类)

    2024年02月20日
    浏览(43)
  • 挑战Transformer的新架构Mamba解析以及Pytorch复现

    今天我们来详细研究这篇论文“Mamba:具有选择性状态空间的线性时间序列建模” Mamba一直在人工智能界掀起波澜,被吹捧为Transformer的潜在竞争对手。到底是什么让Mamba在拥挤的序列建中脱颖而出? 在介绍之前先简要回顾一下现有的模型 Transformer:以其注意力机制而闻名,其中序

    2024年02月02日
    浏览(49)
  • 深入理解深度学习——Transformer:编码器(Encoder)部分

    分类目录:《深入理解深度学习》总目录 相关文章: ·注意力机制(AttentionMechanism):基础知识 ·注意力机制(AttentionMechanism):注意力汇聚与Nadaraya-Watson核回归 ·注意力机制(AttentionMechanism):注意力评分函数(AttentionScoringFunction) ·注意力机制(AttentionMechanism):Bahda

    2024年02月08日
    浏览(62)
  • 【Transformer系列(1)】encoder(编码器)和decoder(解码器)

    前言 这个专栏我们开始学习transformer,自推出以来transformer在深度学习中占有重要地位,不仅在NLP领域,在CV领域中也被广泛应用,尤其是2021年,transformer在CV领域可谓大杀四方。 在论文的学习之前,我们先来介绍一些专业术语。本篇就让我们先来认识一下encoder和decoder吧!

    2024年03月25日
    浏览(66)
  • transfomer中Decoder和Encoder的base_layer的源码实现

    本专栏主要是深度学习/自动驾驶相关的源码实现,获取全套代码请参考 Encoder和Decoder共同组成transfomer,分别对应图中左右浅绿色框内的部分. Encoder: 目的:将输入的特征图转换为一系列自注意力的输出。 工作原理:首先,通过卷积神经网络(CNN)提取输入图像的特征。然后,

    2024年01月18日
    浏览(54)
  • 【pytorch】ResNet源码解读和基于迁移学习的实战

    “工欲善其事,必先利其器”,掌握ResNet网络有必要先了解其原理和源码。本文分别从原理、源码、运用三个方面出发行文,先对ResNet原理进行阐述,然后对pytorch中的源码进行详细解读,最后再基于迁移学习对模型进行调整、实战。本文若有疏漏、需更正、改进的地方,望读

    2024年02月13日
    浏览(44)
  • PyTorch从零开始实现Transformer

    计算公式 代码实现 我们把Transfomer块定义为如下图所示的结构,这个Transformer块在编码器和解码器中都有出现过。 代码实现 编码器结构如下所示,Inputs经过Input Embedding 和Positional Encoding之后,通过多个Transformer块 代码实现 解码器块结构如下图所示 代码实现 解码器块加上wor

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包