手撕Transformer(三)| 基础Transformer整体结构代码解析,从宏观到微观

news2024/11/19 12:41:20

文章目录

  • 1 理解重点
  • 2 背景介绍 假设
  • 3 过程及重要组件
    • 3.1 嵌入层和加入位置编码
    • 3.2 编码器 Encoder
      • 3.3.1 EncoderLayer编码层
      • 3.3.2 LayerNorm归一化层
    • 3.3 解码器 Decoder
    • 3.4 整合连接Encoder和Decoder
  • 4 完整可运行代码

1 理解重点

在之前一节我们已经介绍了Transformer的位置编码Position_encoder,

接下来我们就要完整的实现Transformer的结构了,Transformer实际上可以看做一个完整的武器(比如一支完整的枪),而这只枪具有如枪管、扳机、弹匣、瞄准器、枪托、枪机等大的“组件” 每个组件有一定的功能,比如枪管负责引导子弹直线发射出去,比如扳机负责激活等等,这些大组件如枪管,又进一步由膛线,枪口,冷却槽等小的组件组成(当然这些小的组件有可能有更小的组成)

对应Transformer也是如此,Transformer由很多大组件组成,比如Encoder,Decoder等等,而这些大组件又由更小的组件组成,比如Encoder编码器由六个Encoder layer组成等等

这些组件在代码中常常是用来实现的,大类包含小类,而功能往往是通过函数来实现的,大的功能包括小的功能

因而我觉得对于理解Transformer的代码而言,最重要的是理清楚

  • 这些类和函数的组成和包含关系是什么,即组件之间的包含关系
  • 理解原始数据从最初进入网络结构到最后出去的过程

和以往的各类Transformer的教程不同,我会注重给大家结合代码讲解原始数据从最初进入网络结构到最后出来之后的全过程

2 背景介绍 假设

首先Transformer最初被用在NLP的任务上,我们从经典的翻译任务上入手

首先介绍翻译任务的背景,翻译任务是从一种语言到另一种语言,本质上是一个序列到一个序列的过程

比如“I like apples”到“我喜欢苹果”的过程,是英语到中文

那么每一种语言都有一个词表,比如英语(有300万个单词)那么词表大小就是300万,中文有九千多个汉字,那么词表大小就是九千多,从英语到中文的过程,英语是源语言(src),中文是目标语言(tgt),反之中文到英文的过程,中文是源语言,英文是目标语言

为了方便讲解,我们假设存在一种目标语言的词表大小是2000,另一种目标语言词表大小是1000

OK,然后我们训练的时候往往是批量训练,多个句子,每个句子是多个单词,这里我们假设每个批次是10个句子,每个句子8个单词,这里我们可以给每一个字符 编一个码,使得字符转换为数字方便计算,因为计算机直接处理不了汉字

基于以上的背景假设

最终我们给模型的输入是两个

一个是给编码器的源码语言数据 形状是(10,8)

一个是给解码器输入的目标语言数据 形状是(10,8)

我们要训练从源语言到目标语言的翻译

整体结构

3 过程及重要组件

3.1 嵌入层和加入位置编码

目前的数据都还是离散的,我们要把这些离散的转换为连续的方便计算的,之前的处理方式比如转换为独热编码(就是根据词表大小进行编码的方式,具体可以看机器学习:数据预处理之独热编码(One-Hot)详解-CSDN博客)现在不用这种方式(有缺陷)往往通过嵌入层来实现

这就需要embedding层

实际代码中用到了这个Embeddings这个组件,用到了nn.Embedding这个函数

两个参数,一个是vocab,就是我们前面说的词表大小,另一个是d_model,是嵌入维度,这个嵌入维度是之后Transformer模型的最重要的维度了,同时在这个基础上进行了缩放乘了根号下的嵌入维度

class Embeddings(nn.Module):
    def __init__(self, d_model, vocab):
        super(Embeddings, self).__init__()
        self.lut = nn.Embedding(vocab, d_model)
        self.d_model = d_model

    def forward(self, x):
        return self.lut(x) * math.sqrt(self.d_model)

我们测试模拟一下,src代表最初的语言序列转换的向量(十个句子,每个句子八个单词)

tgt_vocab = 1000

src = torch.ones(10, 8).long()  # Convert to Long scalar type

tgt = torch.ones(10, 8).long()

embeddings = Embeddings(512, 2000)

src_embeddings = embeddings(src)
print(src_embeddings.shape)

输出

torch.Size([10, 8, 512])

同时由于Transformer本身没有位置信息,需要加上位置编码,这里需要实现Positional_Encoding这个组件

class PositionalEncoding(nn.Module):
    "Implement the PE function."

    def __init__(self, d_model, dropout, max_len=5000):
        super(PositionalEncoding, self).__init__()
        # Compute the positional encodings once in log space.
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2) *
                             -(math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0)
        self.register_buffer('pe', pe)
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, x):
        x = x + self.pe[:, :x.size(1)].detach()
        return self.dropout(x)

这一部分实现的细节具体可以看我的这篇博客手撕Transformer(一)| 经典Positional_encoding 用法and代码详解-CSDN博客,不关注细节的话我们只需要知道加上位置编码后形状不变

综上先经过嵌入层,再进入位置编码层

3.2 编码器 Encoder

经过处理后,可以通过Encoder进行相关的处理了,Encoder实际上是由相同layer组件叠加而成的

有一个参数N,N这里代表复制几次layer,通过clones函数实现层的复制,进而实现层堆叠

class Encoder(nn.Module):
    def __init__(self, layer, N):
        super(Encoder, self).__init__()
        self.layers = clones(layer, N)
        self.norm = LayerNorm(layer.size)

    def forward(self, x, mask):
        for layer in self.layers:
            x = layer(x, mask)
        return self.norm(x)

这个Encoder大组件由两个更小的组件组成,分别是EncoderLayer编码层和layerNorm归一化层

可以看到处理后的数据先通过for循环经过N次编码层,最后经过一次norm归一化层

接下来我们看具体每一层的实现

3.3.1 EncoderLayer编码层

其实这里叫层并不是很正确,因为这一层实际上又由很多层组成

主要有多头注意力组件,前馈神经网络组件,残差结构实现组件

class EncoderLayer(nn.Module):
    def __init__(self, size, self_attn, feed_forward, dropout):
        super(EncoderLayer, self).__init__()
        self.self_attn = self_attn
        self.feed_forward = feed_forward
        self.sublayer = clones(SublayerConnection(size, dropout), 2)
        self.size = size

    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)

观察上面的forward函数,可以看到先计算注意力及其分数,然后经过一次残差,对应sublayer[0]

再计算前馈网络,再经过一次残差,对应sublayer[1]

同时我们发现传给self_attn的是三个x,这里的不同位置的x从左到右依次为Q,K,V。

Q,K,V是一样(都是x),也就是所谓的自注意力

我们先来看注意力层计算注意力的相关实现

(1)MultiHeadAttention 多头注意力组件

class MultiHeadedAttention(nn.Module):
    def __init__(self, h, d_model, dropout=0.1):
        super(MultiHeadedAttention, self).__init__()
        assert d_model % h == 0                             
        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:
            # Same mask applied to all h heads.
            mask = mask.unsqueeze(1)
        nbatches = query.size(0)

        # 1) Do all the linear projections in batch from d_model => h x d_k
        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) Apply attention on all the projected vectors in batch.
        x, self.attn = attention(query, key, value, mask=mask, dropout=self.dropout)

        # 3) "Concat" using a view and apply a final linear.
        x = x.transpose(1, 2).contiguous().view(nbatches, -1, self.h * self.d_k)
        return self.linears[-1](x)

观察上面的forward函数,我们可以看到多头注意力的前向过程

核心第一步得到通过线性层映射得到三个矩阵Q,K,V,然后计算Q,K,V的自注意力,然后最后返回计算后的x,这期间形状不变

这里我们用到的注意力机制是点积注意力,我们来看这个点积注意力机制的实现

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

这里用到了masked,关于masked部分,想要详细了解可以看我这篇博客手撕Transformer(二)| Transformer掩码机制的两个功能,三个位置的解析及其代码-CSDN博客

(2)feed_forward 前馈神经网络组件

class PositionwiseFeedForward(nn.Module):
    def __init__(self, d_model, d_ff, dropout=0.1):
        super(PositionwiseFeedForward, self).__init__()
        self.w_1 = nn.Linear(d_model, d_ff)
        self.w_2 = nn.Linear(d_ff, d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        return self.w_2(self.dropout(F.relu(self.w_1(x))))

在类的构造函数__init__中,我们可以看到以下几个重要的成员变量的初始化:

  • self.w_1是一个线性层(nn.Linear),它将输入的维度d_model映射到一个更高维度d_ff
  • self.w_2也是一个线性层,它将维度为d_ff的输入映射回维度为d_model的输出。
  • self.dropout是一个丢弃层(nn.Dropout),它可以随机地将输入中的一些元素置为零,以减少过拟合。

在类的前向传播函数forward中,输入x首先通过线性层self.w_1进行映射,然后经过ReLU激活函数(F.relu)进行非线性变换,接着通过丢弃层self.dropout进行随机丢弃,最后再经过线性层self.w_2进行映射得到输出。

这个类的作用是实现一个位置前馈神经网络,用于对输入进行非线性变换和降维。它常用于自然语言处理中的编码器模块,用于提取输入序列的特征表示。

(3)残差结构组件

class SublayerConnection(nn.Module):

    def __init__(self, size, dropout):
        super(SublayerConnection, self).__init__()
        self.norm = LayerNorm(size)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, sublayer):
        return x + self.dropout(sublayer(self.norm(x)))

SublayerConnection类定义了一个forward方法,用于执行前向传播操作。该方法接受两个参数xsublayer,其中x表示输入张量,sublayer表示子层的操作。在前向传播过程中,首先对输入张量x进行归一化处理,然后通过sublayer对归一化后的张量进行子层操作。最后,将子层操作的结果与输入张量x相加,并使用self.dropout对结果进行随机失活操作。最终,返回加和后的结果作为前向传播的输出。

3.3.2 LayerNorm归一化层

层归一化,和批归一化可能略有不同

批量归一化:(batch Normalization) 批量归一化是对一个中间层的单个神经元进行归一化操作,因此要求小批量样本的数量不能太小,否则难以计算单个神经元的统计信息。

层归一化(Layer Normalization)是和批量归一化非常类似的方法。和批量归一化不同的是,层归一化是对某一层的所有神经元进行归一化。

class LayerNorm(nn.Module):
    def __init__(self, features, eps=1e-6):
        super(LayerNorm, self).__init__()
        self.a_2 = nn.Parameter(torch.ones(features))
        self.b_2 = nn.Parameter(torch.zeros(features))
        self.eps = eps

    def forward(self, x):
        mean = x.mean(-1, keepdim=True)
        std = x.std(-1, keepdim=True)
        return self.a_2 * (x - mean) / (std + self.eps) + self.b_2

这段代码定义了一个名为LayerNorm的类,它继承自nn.Module类。LayerNorm类用于实现层归一化(Layer Normalization)操作。

LayerNorm类的构造函数__init__中,有两个参数:featuresepsfeatures表示输入张量的特征维度,eps表示一个小的常数,用于防止除以零的情况发生。

构造函数创建了两个可学习的参数a_2b_2,它们分别用于缩放和平移输入张量。a_2b_2都是通过nn.Parameter函数创建的,它们会被自动注册为模型的可训练参数。a_2被初始化为一个全为1的张量,b_2被初始化为一个全为0的张量。最后,构造函数将eps保存为类的一个属性。

LayerNorm类还定义了一个forward方法,用于执行层归一化操作。在方法中,首先计算输入张量在最后一个维度上的均值mean和标准差std。然后,通过使用保存的参数a_2b_2对输入张量进行缩放和平移,得到归一化后的张量。最后,返回归一化后的张量作为输出。

通过使用LayerNorm类,可以将层归一化操作应用于神经网络模型中的某一层,以提高模型的训练效果和泛化能力。

3.3 解码器 Decoder

编码器组件基本和解码器相同,很多组件都是通用的,比如点积注意力机制计算组件,比如前馈神经网络组件,比如残差结构组件。因而我们主要介绍解码器和编码器的最重要的不同点

先看Decoder大组件,会发现他Encoder不同,多了一个memory,memory其实就Encoder编码好后的结果~

class Decoder(nn.Module):
    "Generic N layer decoder with masking."

    def __init__(self, layer, N):
        super(Decoder, self).__init__()
        self.layers = clones(layer, N)
        self.norm = LayerNorm(layer.size)

    def forward(self, x, memory, src_mask, tgt_mask):
        for layer in self.layers:
            x = layer(x, memory, src_mask, tgt_mask)
        return self.norm(x)
class DecoderLayer(nn.Module):
    def __init__(self, size, self_attn, src_attn, feed_forward, dropout):
        super(DecoderLayer, self).__init__()
        self.size = size
        self.self_attn = self_attn
        self.src_attn = src_attn
        self.feed_forward = feed_forward
        self.sublayer = clones(SublayerConnection(size, dropout), 3)

    def forward(self, x, memory, src_mask, tgt_mask):
        m = memory
        x = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, tgt_mask))
        x = self.sublayer[1](x, lambda x: self.src_attn(x, m, m, src_mask))
        return self.sublayer[2](x, self.feed_forward)

最重要的不同点就是计算注意力的时候,可以看到解码器有三层残差结构(不同于编码器的两层)

第一层做自注意力,对应sublayer[0]

第二层做交叉注意力,其中Q来自解码器之前的内容,K,V来自编码器,对应sublayer[1]

第三层还是前馈,对应sublayer[2]

3.4 整合连接Encoder和Decoder

class EncoderDecoder(nn.Module):
    def __init__(self, encoder, decoder, src_embed, tgt_embed, generator):
        super(EncoderDecoder, self).__init__()
        self.encoder = encoder
        self.decoder = decoder
        self.src_embed = src_embed
        self.tgt_embed = tgt_embed
        self.generator = generator

    def forward(self, src, tgt, src_mask, tgt_mask):
        return self.decode(self.encode(src, src_mask), src_mask, tgt, tgt_mask)

    def encode(self, src, src_mask):
        return self.encoder(self.src_embed(src), src_mask)

    def decode(self, memory, src_mask, tgt, tgt_mask):
        return self.decoder(self.tgt_embed(tgt), memory, src_mask, tgt_mask)

def make_model(src_vocab, tgt_vocab, N=6, d_model=512, d_ff=2048, h=8, dropout=0.1):
    c = copy.deepcopy
    attn = MultiHeadedAttention(h, d_model)
    ff = PositionwiseFeedForward(d_model, d_ff, dropout)
    position = PositionalEncoding(d_model, dropout)
    model = EncoderDecoder(
        Encoder(EncoderLayer(d_model, c(attn), c(ff), dropout), N),
        Decoder(DecoderLayer(d_model, c(attn), c(attn),c(ff), dropout), N),
        nn.Sequential(Embeddings(d_model, src_vocab), c(position)),
        nn.Sequential(Embeddings(d_model, tgt_vocab), c(position)),
        Generator(d_model, tgt_vocab))
    return model

我觉得从顶端到底,从宏观到微观的方式分析是非常Nice的一种方式

4 完整可运行代码

完整代码中我们进行了测试

import torch
from torch import nn
import math
from torch.nn import functional as F
import copy
from torch.nn.functional import log_softmax
import torch


def clones(module, N):
    return nn.ModuleList([copy.deepcopy(module) for _ in range(N)])

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

 #为什么是四维度的?
def clones(module, N):
    return nn.ModuleList([copy.deepcopy(module) for _ in range(N)])

class MultiHeadedAttention(nn.Module):
    def __init__(self, h, d_model, dropout=0.1):
        super(MultiHeadedAttention, self).__init__()
        assert d_model % h == 0                             
        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:
            # Same mask applied to all h heads.
            mask = mask.unsqueeze(1)
        nbatches = query.size(0)

        # 1) Do all the linear projections in batch from d_model => h x d_k
        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) Apply attention on all the projected vectors in batch.
        x, self.attn = attention(query, key, value, mask=mask, dropout=self.dropout)

        # 3) "Concat" using a view and apply a final linear.
        x = x.transpose(1, 2).contiguous().view(nbatches, -1, self.h * self.d_k)
        return self.linears[-1](x)
    


class PositionwiseFeedForward(nn.Module):
    def __init__(self, d_model, d_ff, dropout=0.1):
        super(PositionwiseFeedForward, self).__init__()
        self.w_1 = nn.Linear(d_model, d_ff)
        self.w_2 = nn.Linear(d_ff, d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        return self.w_2(self.dropout(F.relu(self.w_1(x))))
    
class Embeddings(nn.Module):
    def __init__(self, d_model, vocab):
        super(Embeddings, self).__init__()
        self.lut = nn.Embedding(vocab, d_model)
        self.d_model = d_model

    def forward(self, x):
        return self.lut(x) * math.sqrt(self.d_model)
    

class PositionalEncoding(nn.Module):
    "Implement the PE function."

    def __init__(self, d_model, dropout, max_len=5000):
        super(PositionalEncoding, self).__init__()
        # Compute the positional encodings once in log space.
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2) *
                             -(math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0)
        self.register_buffer('pe', pe)
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, x):
        x = x + self.pe[:, :x.size(1)].detach()
        return self.dropout(x)

class LayerNorm(nn.Module):
    def __init__(self, features, eps=1e-6):
        super(LayerNorm, self).__init__()
        self.a_2 = nn.Parameter(torch.ones(features))
        self.b_2 = nn.Parameter(torch.zeros(features))
        self.eps = eps

    def forward(self, x):
        mean = x.mean(-1, keepdim=True)
        std = x.std(-1, keepdim=True)
        return self.a_2 * (x - mean) / (std + self.eps) + self.b_2

class SublayerConnection(nn.Module):

    def __init__(self, size, dropout):
        super(SublayerConnection, self).__init__()
        self.norm = LayerNorm(size)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, sublayer):
        return x + self.dropout(sublayer(self.norm(x)))

class EncoderLayer(nn.Module):
    def __init__(self, size, self_attn, feed_forward, dropout):
        super(EncoderLayer, self).__init__()
        self.self_attn = self_attn
        self.feed_forward = feed_forward
        self.sublayer = clones(SublayerConnection(size, dropout), 2)
        self.size = size

    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):
    def __init__(self, layer, N):
        super(Encoder, self).__init__()
        self.layers = clones(layer, N)
        self.norm = LayerNorm(layer.size)

    def forward(self, x, mask):
        for layer in self.layers:
            x = layer(x, mask)
        return self.norm(x)

class DecoderLayer(nn.Module):
    def __init__(self, size, self_attn, src_attn, feed_forward, dropout):
        super(DecoderLayer, self).__init__()
        self.size = size
        self.self_attn = self_attn
        self.src_attn = src_attn
        self.feed_forward = feed_forward
        self.sublayer = clones(SublayerConnection(size, dropout), 3)

    def forward(self, x, memory, src_mask, tgt_mask):
        m = memory
        x = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, tgt_mask))
        x = self.sublayer[1](x, lambda x: self.src_attn(x, m, m, src_mask))
        return self.sublayer[2](x, self.feed_forward)

class Decoder(nn.Module):
    "Generic N layer decoder with masking."

    def __init__(self, layer, N):
        super(Decoder, self).__init__()
        self.layers = clones(layer, N)
        self.norm = LayerNorm(layer.size)

    def forward(self, x, memory, src_mask, tgt_mask):
        for layer in self.layers:
            x = layer(x, memory, src_mask, tgt_mask)
        return self.norm(x)
    
class EncoderDecoder(nn.Module):
    def __init__(self, encoder, decoder, src_embed, tgt_embed, generator):
        super(EncoderDecoder, self).__init__()
        self.encoder = encoder
        self.decoder = decoder
        self.src_embed = src_embed
        self.tgt_embed = tgt_embed
        self.generator = generator

    def forward(self, src, tgt, src_mask, tgt_mask):
        return self.decode(self.encode(src, src_mask), src_mask, tgt, tgt_mask)

    def encode(self, src, src_mask):
        return self.encoder(self.src_embed(src), src_mask)

    def decode(self, memory, src_mask, tgt, tgt_mask):
        return self.decoder(self.tgt_embed(tgt), memory, src_mask, tgt_mask)


class Generator(nn.Module):
    "Define standard linear + softmax generation step."

    def __init__(self, d_model, vocab):
        super(Generator, self).__init__()
        self.proj = nn.Linear(d_model, vocab)

    def forward(self, x):
        return log_softmax(self.proj(x), dim=-1)

def make_model(src_vocab, tgt_vocab, N=6, d_model=512, d_ff=2048, h=8, dropout=0.1):
    c = copy.deepcopy
    attn = MultiHeadedAttention(h, d_model)
    ff = PositionwiseFeedForward(d_model, d_ff, dropout)
    position = PositionalEncoding(d_model, dropout)
    model = EncoderDecoder(
        Encoder(EncoderLayer(d_model, c(attn), c(ff), dropout), N),
        Decoder(DecoderLayer(d_model, c(attn), c(attn),c(ff), dropout), N),
        nn.Sequential(Embeddings(d_model, src_vocab), c(position)),
        nn.Sequential(Embeddings(d_model, tgt_vocab), c(position)),
        Generator(d_model, tgt_vocab))
    return model
    
src_vocab = 2000
tgt_vocab = 1000

src = torch.ones(10, 8).long()  # Convert to Long scalar type

tgt = torch.ones(10, 8).long()

""" embeddings = Embeddings(512, 2000)

src_embeddings = embeddings(src)
print(src_embeddings.shape)
 """



# Create masks for the input and target sequences
src_mask = torch.ones(10,8,8)  
tgt_mask = torch.ones(10,8,8)  

# Create the model
model = make_model( src_vocab, tgt_vocab, N=6, d_model=512, d_ff=2048, h=8, dropout=0.1)

# Forward pass through the model
output = model(src, tgt, src_mask, tgt_mask)

# Print the output shape
print(output.shape)





参考

详解深度学习中的注意力机制(Attention) - 知乎 (zhihu.com)

Transformer源码详解(Pytorch版本) - 知乎 (zhihu.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1469633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

精品基于springboot的线上辅导班系统的开发与设计-课程报名

《[含文档PPT源码等]精品基于springboot的线上辅导班系统的开发与设计[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功! 软件开发环境及开发工具: Java——涉及技术: 前端使用技术&#…

[嵌入式系统-33]:RT-Thread -18- 新手指南:三种不同的版本、三阶段学习路径

目录 前言:学习路径:入门学习-》进阶段学习》应用开发 一、RT-Thread版本 1.1 标准版 1.2 Nano 1.3 Smart版本 1.4 初学者制定学习路线 1.5 RT-Thread在线文档中心目录结构 1.6 学习和使用RT-Thread的三种场景 二、入门学习阶段:内…

Semaphore实现原理全面解析

简介 Semaphore(信号量)是一个同步工具类,通过Semaphore可以控制同时访问共享资源的线程个数。 应用场景 Semaphore的主要应用场景: 资源并发控制:Semaphore可以限制对资源的并发访问。如:管理数据库连…

蛇形矩阵2

题目描述 把数1,2,3,4,5,…,按照“蛇形2”放入N*N矩阵的左三角形中,输出结果。 下面是N6的蛇形2的图示 输入格式 第一行1个正整数:N,范围在[1,100]。 输出格式 N行&a…

HuggingFists系统功能介绍(3)--流程管理

流程管理 下面我们进入流程管理。流程管理用于定义及管理我们采用低代码方式开发的各种ETL以及数据分析流程。 流程列表 界面的左侧部分为流程的分组树,当定义的流程逐渐变多或者多人协同使用系统时,可以通过分组对流程进行更有序的管理。点中分组&#…

C#与VisionPro联合开发——TCP/IP通信

TCP/IP(传输控制协议/互联网协议)是一组用于在网络上进行通信的通信协议。它是互联网和许多局域网的基础,为计算机之间的数据传输提供了可靠性、有序性和错误检测。在软件开发中,TCP/IP 通信通常用于实现网络应用程序之间的数据交…

预训练-微调范式在人工智能领域的深远影响

预训练-微调范式的出现是人工智能领域的一大里程碑,它深刻改变了深度学习模型的训练方式和应用模式,并对整个行业产生了多方面的深远影响: 数据效率提升: 通过在大规模无标注数据上进行预训练,模型能够学习到丰富的语言…

Python算法题集_实现 Trie [前缀树]

Python算法题集_实现 Trie [前缀树] 题208:实现 Trie (前缀树)1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【定义数据类默认字典】2) 改进版一【初始化字典无额外类】3) 改进版二【字典保存结尾信息无额外类】 4. 最优算法5. 相关…

实战一个 Jenkins 构建 CI/CD流水线 的简单配置过程哈

引言:上一期我们讲述了gitlabCI/CD工具的介绍,工具之争,本期我们介绍Jenkins CI/CD 目录 一、Jenkins介绍 1、Jenkins概念 2、Jenkins目的 3、特性 4、产品发布流程 二、安装Jenkins 1、安装JDK 2、安装Jenkins 1、上传压缩包 2、…

Python入门必学:单引号、双引号与三引号的差异与应用

Python入门必学:单引号、双引号与三引号的差异与应用 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 👈 希望得…

神经网络系列---激活函数

文章目录 激活函数Sigmoid 激活函数Tanh激活函数ReLU激活函数Leaky ReLU激活函数Parametric ReLU激活函数 (自适应Leaky ReLU激活函数)ELU激活函数SeLU激活函数Softmax 激活函数Swish 激活函数Maxout激活函数Softplus激活函数 激活函数 一般来说&#xf…

Tomcat线程池原理(上篇:初始化原理)

文章目录 前言正文一、从启动脚本开始分析二、ProtocolHandler 的启动原理三、AbstractEndPoint 的启动原理四、创建默认线程池五、参数配置原理5.1 常规的参数配置5.2 自定义线程池5.3 测试自定义线程 前言 在Java Web的开发过程中,Tomcat常用的web容器。SpringBo…

SpringBoot -【BeanPostProcessor】基础使用及应用场景

BeanPostProcessor应用与优化 1. 引言 在现代软件开发中,企业开发面临着越来越复杂的系统架构和业务需求。随着项目规模的扩大和技术栈的增多,需要更高效的工具来应对这些挑战,并确保代码的可维护性和扩展性。 在这样的背景下,Be…

Linux之项目部署与发布

目录 一、Nginx配置安装(自启动) 1.一键安装4个依赖 2. 下载并解压安装包 3. 安装Nginx 4. 启动 nginx 服务 5. 对外开放端口 6. 配置开机自启动 7.修改/etc/rc.d/rc.local的权限 二、后端部署tomcat负载均衡 1. 准备2个tomcat 2. 修改端口 3…

随机分布模型

目录 前言 一、离散型随机变量 1.1 0-1分布 1.2 二项分布 1.3 帕斯卡分布 1.4 几何分布 1.5 超几何分布 1.6 泊松分布 二、连续型随机变量 2.1 均匀分布 2.2 指数分布 2.3 高斯分布/正态分布 2.4 分布(抽样分布) 2.5 t分布(抽样…

Vue局部注册组件实现组件化登录注册

Vue局部注册组件实现组件化登录注册 一、效果二、代码1、index.js2、App.vue3、首页4、登录(注册同理) 一、效果 注意我这里使用了element组件 二、代码 1、index.js import Vue from vue import VueRouter from vue-router import Login from ../vie…

迷你世界之建筑生成球体

local x0,y0,z00,30,0--起点坐标 local dx,dy,dz60,60,60--外切长方体横纵竖长度 local count,all0,dx*dy*dz--计数,总数 local m,k10000,0--单次生成方块数,无用循环值 local x,y,z0,0,0--当前坐标 local demath.random(2,19)/2 local id600--方块…

【监督学习之逻辑回归】

曾梦想执剑走天涯,我是程序猿【AK】 目录 简述概要知识图谱1.什么是逻辑回归?2.逻辑回归有哪些应用?3.回归分析如何工作?4.逻辑回归模型如何工作?5.逻辑回归分析有哪些类型?6.逻辑回归与其他机器学习技术相…

APP攻防-实战拿下某seseAPPSpringboot未授权HeapDump提取OSS利用

知识点 1、APK-抓包 2、资产信息收集 3、SpringBoot-漏洞利用 4、自动化工具 5、HeapDump-分析提取 6、AccessKEY-利用后续 演示案例: 1、APK-抓包 2、资产信息收集 3、SpringBoot-漏洞利用 SpringBoot漏洞利用: https://github.com/LandGrey/Spring…

K8S—集群调度

目录 前言 一 List-Watch 1.1 list-watch概述 1.2 list-watch工作机制 二 集群调度 2.1 调度过程 2.2 Predicate 和 Priorities 的常见算法和优先级选项 2.3 调度方式 三 亲和性 3.1 节点亲和性 3.2 Pod 亲和性 3.3 键值运算关系 3.4 Pod亲和性与反亲和性 3.5 示例…