Pytorch从零开始实现Transformer (from scratch)

在这里插入图片描述

Pytorch从零开始实现Transformer

  • 前言
  • 一、Transformer架构介绍
    • 1. Embedding
    • 2. Multi-Head Attention
      • Query,Key,Value
    • 3. Transformer Block
      • LayerNorm
      • Feed Forward
    • 4. Decoder Block
  • 二、Transformer代码实现
    • 0. 导入库
    • 1. Word Embedding
    • 2. Positional Encoding
    • 3. Multi-Head Attention
    • 4. Transformer Encoder
    • 5. Transformer Decoder
      • Decoder attention
      • Encoder decoder attention
    • 6. Overrall Transformer
    • 7. Test Code
  • 总结
  • 日志
  • 参考文献


前言

2023年可以说是AI备受关注的一年,ChatGPT(GPT3.5)的问世引起了世界的轰动,近期GPT4的出现更是颠覆了各界对深度学习的认知,AI不止停留在特定任务的学习上,诸如此类的大模型已经初步符合人们最开始对AI的幻想——通用模型,通用模型可以处理多种场景下的难题。总所周知这些大模型背后的基础就是Transformer,于2017年提出后就席卷了整个学术界,各领域学者纷纷投入到Transformer的研究中,比如用Transformer取代ResNet作为Backbone取得更好的下游任务,或是单纯就Transformer的网络架构进行改进。“树要长多高,根就要扎多深”,在Transformer构建的金碧辉煌的大厦逐步建起时,不能忘记其最原初的根本。
正值论文写作稍微告一段落,有时间深入理解Transformer工作原理,复现Transformer和Transformer相关问题在工作面试中也是比较常见的,对于深度学习初学者,从零开始实现Transformer即Code the Transformer from scratch可能会是一个很艰巨的任务,甚至望而却步,不可否认在写这篇博客前我也是这样。Transformer的衍生比如BERT、Vision Transformer这种比较大的模型,下意识就会被这个“大”所吓到,觉得凭自己贫瘠的代码功底应该是难以实现。可实际做起来并没有想象那么难,“Just do it!”
希望每位读者看完这篇文章后能手撕Transformer或者对其有更深入的理解。


一、Transformer架构介绍

Transformer的模型流程图如上,取自原论文 Attention is all you need,目前引用量是69364。论文于2017年发表,由Google Brain和Google Research团队研发。据我所知,Transformer最初就是设计出来解决NLP领域问题的,比如机器翻译。
Tip:对于学习的建议是首先观看视频讲解,然后手打打一遍代码,最后看些博客对每个模块细致理解。(推荐视频和博客将放到文末参考文献部分)
接下来会简短介绍一下流程图中的各个部分,之后在下一节详细说明并实现代码。

1. Embedding

此处的Embedding包含上图中的Input Embedding和Output Embedding,实际上这部分代码的实现是一样的。按Input Embedding为例,其分为Word Embedding和Positional Embedding(即图中Positional Encoding)。Word Embedding作用是将一个个单词转化为向量,即词嵌入,位置编码Positional Encoding这是给单词句子对应词向量添加位置信息。
在这里插入图片描述
论文对位置编码这块并没有解释说明,就直接通过sin和cos对词向量的每个位置元素进行操作,偶数位(2i)使用sin,奇数位(2i+1)使用cos,然后将位置编码直接加(+)到词向量上。

2. Multi-Head Attention

多头注意力机制,也可称为Self-attention自注意力机制,叫法不一。仔细看可以看到图中在Embedding后引申出4路,有3路进入Multi-Head Attention模块,另1路在之后和多头注意力模块的结果Norm后汇合(其实就是相加)。Multi-Head Attention是Transformer的核心,而这3路信息则是Multi-Head Attention的核心。3路分别为Query,Key和Value。

Query,Key,Value

举个例子,图源自The Illustrated Transformer,

假如“Thinking”和“Machines”这两个单词经过Word Embedding和Positional Embedding后为x1和x2,
Tip:其实这里也体现了“Multi”,多头注意力模块把一整个Embedding(比如一个句子的词向量)切分为若干份(比如Heads为8就均分为8段)作为输入,旨在学习不同维度的特征(并没有证明,合情推理)。
然后将x1、x2分别和预先定义好的 W Q W^Q WQ W K W^K WK W V W^V WV矩阵进行矩阵乘(或者说线性组合),即可得到q1,k1,v1(同理,q2,k2,v2)。从变量命名不难看出这是基于一套字典检索匹配的策略,给一个Query,然后找到对应的Key,而这个Value呢其实就是所要保存的值。Query是网络当前待查询的值,Key记录着上一次迭代网络的值,Value则负责保存这些值,可能听上去很抽象,类比RNN循环神经网络,Q是现在,K是过去,V用于记录和更新。而注意力所体现的地方就在于矩阵的乘法,类似余弦相似度,Q和K的转置相乘即可得到相似性,相似性越大则Q和K越匹配。如有不懂,可以观看第二节代码帮助理解。

3. Transformer Block

Transformer Block也指Encoder Block,在经过Multi-Head Attention和Add&Norm后,此处必要一提,算是一个细节,Multi-Head Attention后的结果和之前未曾细说的那1路Value进行相加(Add),这里足以体现Value的记录和存储作用,可见Value在模型中重要性
这种让模型某一路直接跳到某个模块后相加的操作(ShortCut操作)灵感来源于何恺明大神的ResNet,这是毋庸置疑的。残差的操作避免了梯度弥散的问题,同时也起到特征融合的作用,保留原本的特征。

LayerNorm

必要一提,不同于ResNet这些卷积神经网络使用BatchNorm,Transformer使用的是LayerNorm。
LayerNorm论文发表于2016年,见Layer Normalization,可以直接用于RNN神经网络的训练,因为RNN特质对整个Batch的归一化并不现实,这也决定LayerNorm对。
BatchNorm和LayerNorm的比较见下图,图源于paperswithcode.com/method/layer-normalization

N为batch size,C为channel(通道数),H,W代表每个特征向量的高和宽。
简单的理解就是BatchNorm是对一个batch size样本内的每个特征做归一化,LayerNorm是对每个样本的所有特征做归一化。(后续会补充细讲)

Feed Forward

使用两层全连接层(Linear)和ReLU激活函数。

4. Decoder Block

Decoder Block的架构大体上和Encoder Block是一致的,唯独不同的是Decoder比Encoder多了Masked Multi-Head Attention。
那么为什么要在Decode阶段对特征(或者说tokens)做mask呢?
Mask的样式如下,白格为0,蓝格为1, 1表示保留的部分,0表示mask的部分:
在这里插入图片描述
Transformer针对序列化特征,比如文本数据,这些特征是有前后关系的,为了不让Decoder通过未来的单词(或者说特征)来猜测出当前的特征,将后面的token进行mask,这样模型只能通过过去的词或者说特征元素来预测当前特征元素。


二、Transformer代码实现

本节的代码取自https://www.kaggle.com/code/arunmohan003/transformer-from-scratch-using-pytorch/notebook,但代码会有些许不同但保证是正确的(因为原来代码一些地方有瑕疵),本人做的工作更多是翻译和整理网上对Transformer的讲解。

0. 导入库

import torch
import torch.nn as nn
import torch.nn.functional as F
import math
import warnings
warnings.simplefilter("ignore")

1. Word Embedding

首先,我们需要将输入序列中的每个单词转换为embedding向量。
假设每个embedding维数(embed_dim)是512维,vocabulary词汇表大小(vocab_size)是100,那么embedding词嵌入矩阵的大小将是100x512(行x列)。这些矩阵将在训练中学习,在inference即推理过程中,每个单词将被映射到相应的512维向量。如果batch size为32,序列长度(seq_len)为10(10个单词)。输出将是32x10x512
Tip:inference推理过程在深度学习中指把从训练中学习到的能⼒应⽤到⼯作中去,也就是在训练完模型后将模型对实际的输入(可以是训练集里的数据也可以是其他数据)进行在线推演输出结果的过程。
对于词嵌入矩阵的构造有专门的nn.Embedding,pytorch官方文档将其称为Sparse Layer(稀疏层),是一个保存了固定字典和大小的简单查找表。这个模块常用来保存词嵌入和用下标检索它们。模块的输入是一个下标的列表,输出是对应的词嵌入。

class WordEmbedding(nn.Module):def __init__(self, vocab_size, embed_dim):"""Args:vocab_size: size of vocabularyembed_dim: dimension of embeddings"""super(WordEmbedding, self).__init__()self.embed = nn.Embedding(vocab_size, embed_dim)def forward(self, x):"""Args:x: input vectorReturns:out: embedding vector"""out = self.embed(x)return out

2. Positional Encoding

回顾到上一节位置编码的公式,公式细节解释:

pos -->指的是当前词在句子中的顺序 [0,max_seq_len)
i -->指沿embedding维度的位置,即 [0,512)

这里注意pos范围不是[0,10),10是输入序列的长度seq_len,因为输入的序列长度一般是小于等于max_seq_len的,也就是位置编码矩阵是固定大小,输入embedding序列是随机长度。
前面我们已经得到32 x 10 x 512的embedding向量。类似地,我们将有尺寸为32 x 10 x 512的位置编码向量。然后我们把两者相加(实际上位置编码矩阵会更大)。

在这里插入图片描述

class PositionalEmbedding(nn.Module):def __init__(self, max_seq_len, embed_model_dim):"""Args:seq_len: length of input sequenceembed_model_dim: demension of embedding"""super(PositionalEmbedding, self).__init__()self.embed_dim = embed_model_dimpe = torch.zeros(max_seq_len, self.embed_dim)for pos in range(max_seq_len):for i in range(0, self.embed_dim, 2):pe[pos, i] = math.sin(pos / (10000 ** ((2 * i) / self.embed_dim)))pe[pos, i + 1] = math.cos(pos / (10000 ** ((2 * (i + 1)) / self.embed_dim)))pe = pe.unsqueeze(0)self.register_buffer('pe', pe)def forward(self, x):"""Args:x: input vectorReturns:out : output"""# make embeddings relatively largerx = x * math.sqrt(self.embed_dim)# add constant to embeddingseq_len = x.size(1)out = x + torch.autograd.Variable(self.pe[:, :seq_len], requires_grad=False)return out 

3. Multi-Head Attention

什么是self-attention自注意力机制?
对于某个句子比如“Dog is crossing the street because it saw the kitchen”,人类可以很容易理解这句话重点是在说狗,而对机器来说就不是那么容易的了。
当模型处理每个单词时,self-attention可以查看输入序列中的其他位置以寻找线索。它将根据每个单词与其他单词的依赖关系创建一个向量。也就是所谓的“完形填空”。这里插播一些非计算机知识,算是一种联想来帮助读者理解。

格式塔系德文“Gestalt”的音译,主要指完形,即具有不同部分分离特性的有机整体。格式塔作为心理学术语,具有两种含义:一指事物的一般属性,即形式;一指事物的个别实体,即分离的整体,形式仅为其属性之一。也就是说,“假使有一种经验的现象,它的每一成分都牵连到其他成分;而且每一成分之所以有其特性,即因为它和其他部分具有关系,这种现象便称为格式塔。”总之,格式塔不是孤立不变的现象,而是指通体相关的完整的现象。完整的现象具有它本身完整的特性,它既不能割裂成简单的元素,同时它的特性又不包含于任何元素之内。——百度百科

下面进入到实例的讲解
Step1:首先从Encoder的每个输入向量(在本例中,是每个单词的嵌入)中创建三个向量,分别是Query向量、Key向量和Value向量,每个向量的维数都是1x64。这里64是配合上文 512 / 8 = 64 512/8=64 512/8=64,其中8为多头注意力的头的数量。我们将有一个Key矩阵、Query矩阵和一个Value矩阵来生成Key、Query和Value向量,这些矩阵都是在训练中可学习的。

对于经过WordEmbedding和PositionEncoding后的输入张量32x10x512,将其调整为32x10x8x64

Step2:对应Transformer原论文的Scaled Dot-Product Attention:

Mask是optional(即可选项),Encoder时不需要Mask,Decoder需要Mask
根据公式:

将Query矩阵与Key矩阵相乘,[Q x K T K^T KT]
当前Key、Query和Key矩阵维度是32x10x8x64。QK相乘之前,我们将对它们进行转置(transpose)以方便相乘(32x8x10x64)。

现在将Query矩阵与转置的Key矩阵相乘。即(32x8x10x64) x (32x8x64x10) -> (32x8x10x10)。

然后将矩阵乘的结果除以Key维度,将32x8x10x10向量除以8,即除以64的平方根(Key矩阵的维数)

接下来是softmax之后结果和Value矩阵(32x8x10x64)相乘:

(32x8x10x10) x (32x8x10x64) -> (32x8x10x64)

Step3:通过Step2得到矩阵,将多头的结果进行合并(concat),然后让其通过线性层,这就形成了多头注意力的输出。图中h表示number of heads,即多头注意力的数量。

在这里插入图片描述

(32x8x10x64)张量被转置回为(32x10x8x64),然后Concat为(32x10x512)。最后通过Linear线性层得到(32x10x512)的输出。

class MultiHeadAttention(nn.Module):def __init__(self, embed_dim=512, n_heads=8):"""Args:embed_dim: dimension of embeding vector outputn_heads: number of self attention heads"""super(MultiHeadAttention, self).__init__()self.embed_dim = embed_dim  # 512 dimself.n_heads = n_heads  # 8self.single_head_dim = int(self.embed_dim / self.n_heads)  # 512/8 = 64  . each key,query, value will be of 64d# key,query and value matrixes    #64 x 64self.query_matrix = nn.Linear(self.single_head_dim, self.single_head_dim,bias=False)  # single key matrix for all 8 keys #512x512self.key_matrix = nn.Linear(self.single_head_dim, self.single_head_dim, bias=False)self.value_matrix = nn.Linear(self.single_head_dim, self.single_head_dim, bias=False)self.out = nn.Linear(self.n_heads * self.single_head_dim, self.embed_dim)def forward(self, key, query, value, mask=None):  # batch_size x sequence_length x embedding_dim    # 32 x 10 x 512"""Args:key : key vectorquery : query vectorvalue : value vectormask: mask for decoderReturns:output vector from multihead attention"""batch_size = key.size(0)seq_length = key.size(1)# query dimension can change in decoder during inference.# so we cant take general seq_lengthseq_length_query = query.size(1)# 32x10x512key = key.view(batch_size, seq_length, self.n_heads,self.single_head_dim)  # batch_size x sequence_length x n_heads x single_head_dim = (32x10x8x64)query = query.view(batch_size, seq_length_query, self.n_heads, self.single_head_dim)  # (32x10x8x64)value = value.view(batch_size, seq_length, self.n_heads, self.single_head_dim)  # (32x10x8x64)k = self.key_matrix(key)  # (32x10x8x64)q = self.query_matrix(query)v = self.value_matrix(value)q = q.transpose(1, 2)  # (batch_size, n_heads, seq_len, single_head_dim)    # (32 x 8 x 10 x 64)k = k.transpose(1, 2)  # (batch_size, n_heads, seq_len, single_head_dim)v = v.transpose(1, 2)  # (batch_size, n_heads, seq_len, single_head_dim)# computes attention# adjust key for matrix multiplicationk_adjusted = k.transpose(-1, -2)  # (batch_size, n_heads, single_head_dim, seq_ken)  #(32 x 8 x 64 x 10)product = torch.matmul(q, k_adjusted)  # (32 x 8 x 10 x 64) x (32 x 8 x 64 x 10) = #(32x8x10x10)# fill those positions of product matrix as (-1e20) where mask positions are 0if mask is not None:product = product.masked_fill(mask == 0, float("-1e20"))# divising by square root of key dimensionproduct = product / math.sqrt(self.single_head_dim)  # / sqrt(64)# applying softmaxscores = F.softmax(product, dim=-1)# mutiply with value matrixscores = torch.matmul(scores, v)  ##(32x8x 10x 10) x (32 x 8 x 10 x 64) = (32 x 8 x 10 x 64)# concatenated outputconcat = scores.transpose(1, 2).contiguous().view(batch_size, seq_length_query,self.single_head_dim * self.n_heads)  # (32x8x10x64) -> (32x10x8x64)  -> (32,10,512)output = self.out(concat)  # (32,10,512) -> (32,10,512)return output

Warning: 在学习Vision Transformer代码时,回过头来发现以上的MultiHeadAttention这部分代码是有些许问题,因为这部分代码是借用Kaggle上的,所以写作当时没有意识到。不过也谈不上错误,只能说那么设计有些不恰当,不知道读者能否找出问题所在。答案将在Pytorch动手实现Transformer机器翻译这篇博客中给出,历时请对比代码。

4. Transformer Encoder

class TransformerBlock(nn.Module):def __init__(self, embed_dim, expansion_factor=4, n_heads=8):super(TransformerBlock, self).__init__()"""Args:embed_dim: dimension of the embeddingexpansion_factor: fator ehich determines output dimension of linear layern_heads: number of attention heads"""self.attention = MultiHeadAttention(embed_dim, n_heads)self.norm1 = nn.LayerNorm(embed_dim)self.norm2 = nn.LayerNorm(embed_dim)self.feed_forward = nn.Sequential(nn.Linear(embed_dim, expansion_factor * embed_dim),nn.ReLU(),nn.Linear(expansion_factor * embed_dim, embed_dim))self.dropout1 = nn.Dropout(0.2)self.dropout2 = nn.Dropout(0.2)def forward(self, key, query, value):"""Args:key: key vectorquery: query vectorvalue: value vectornorm2_out: output of transformer block"""attention_out = self.attention(key, query, value)  # 32x10x512attention_residual_out = attention_out + value  # 32x10x512norm1_out = self.dropout1(self.norm1(attention_residual_out))  # 32x10x512feed_fwd_out = self.feed_forward(norm1_out)  # 32x10x512 -> #32x10x2048 -> 32x10x512feed_fwd_residual_out = feed_fwd_out + norm1_out  # 32x10x512norm2_out = self.dropout2(self.norm2(feed_fwd_residual_out))  # 32x10x512return norm2_outclass TransformerEncoder(nn.Module):"""Args:seq_len : length of input sequenceembed_dim: dimension of embeddingnum_layers: number of encoder layersexpansion_factor: factor which determines number of linear layers in feed forward layern_heads: number of heads in multihead attentionReturns:out: output of the encoder"""def __init__(self, seq_len, vocab_size, embed_dim, num_layers=2, expansion_factor=4, n_heads=8):super(TransformerEncoder, self).__init__()self.embedding_layer = WordEmbedding(vocab_size, embed_dim)self.positional_encoder = PositionalEmbedding(seq_len, embed_dim)self.layers = nn.ModuleList([TransformerBlock(embed_dim, expansion_factor, n_heads) for i in range(num_layers)])def forward(self, x):embed_out = self.embedding_layer(x)out = self.positional_encoder(embed_out)for layer in self.layers:out = layer(out, out, out)return out  # 32x10x512

5. Transformer Decoder

在Decoder中有两种multi-head attention,一种叫decoder attention,另一种叫encoder decoder attention。

Decoder attention

首先是使用带mask的multi-head attention即decoder attention。
为什么要使用Mask呢?
使用mask掩码是因为在创建目标词的注意力时,我们不需要一个词来查看将来的词来检查依赖关系。其实也是一个历史问题,在NLP发展史中对文本序列token的处理类似GPT2的Auto-regressive(自回归)的Mask,就只对先前的tokens进行注意力学习,而不让模型通过未知的后续token来猜测当前token,否则模型会直接copy下一个单词的token。后来的BERT用的就是双向的策略,而不只是看过去的token而是从过去到未来再从未来到过去两个方向进行预测。
例如:在单词“I am a student”中,我们不需要单词“a”来查找单词“student”,没有mask的话当模型看到“a”就会直接给出"student"的预测。
对于Mask这一三角矩阵,如第一节中Decoder Block的图所示,对于所有零位置,用负无穷大填充,而在代码中,用一个非常小的数字填充它以避免除法错误(比如 -1e20)。

Encoder decoder attention

对于这个多头注意力,从Encoder的输出中创建Key和Value向量。Query是从上一个Decoder层的输出创建得到的。流程就如下图所示:
在这里插入图片描述

class DecoderBlock(nn.Module):def __init__(self, embed_dim, expansion_factor=4, n_heads=8):super(DecoderBlock, self).__init__()"""Args:embed_dim: dimension of the embeddingexpansion_factor: fator ehich determines output dimension of linear layern_heads: number of attention heads"""self.attention = MultiHeadAttention(embed_dim, n_heads=8)self.norm = nn.LayerNorm(embed_dim)self.dropout = nn.Dropout(0.2)self.transformer_block = TransformerBlock(embed_dim, expansion_factor, n_heads)def forward(self, key, query, x, mask):"""Args:key: key vectorquery: query vectorx: value vectormask: mask to be given for multi head attentionReturns:out: output of transformer block"""# we need to pass mask mask only to fst attentionattention = self.attention(x, x, x, mask=mask)  # 32x10x512value = self.dropout(self.norm(attention + x))out = self.transformer_block(key, query, value)return outclass TransformerDecoder(nn.Module):def __init__(self, target_vocab_size, embed_dim, seq_len, num_layers=2, expansion_factor=4, n_heads=8):super(TransformerDecoder, self).__init__()"""  Args:target_vocab_size: vocabulary size of tagetembed_dim: dimension of embeddingseq_len : length of input sequencenum_layers: number of encoder layersexpansion_factor: factor which determines number of linear layers in feed forward layern_heads: number of heads in multihead attention"""self.word_embedding = WordEmbedding(target_vocab_size, embed_dim)self.position_embedding = PositionalEmbedding(seq_len, embed_dim)self.layers = nn.ModuleList([DecoderBlock(embed_dim, expansion_factor=4, n_heads=8)for _ in range(num_layers)])self.fc_out = nn.Linear(embed_dim, target_vocab_size)self.dropout = nn.Dropout(0.2)def forward(self, x, enc_out, mask):"""Args:x: input vector from targetenc_out : output from encoder layertrg_mask: mask for decoder self attentionReturns:out: output vector"""x = self.word_embedding(x)  # 32x10x512x = self.position_embedding(x)  # 32x10x512x = self.dropout(x)for layer in self.layers:x = layer(enc_out, x, enc_out, mask)out = F.softmax(self.fc_out(x))return out

6. Overrall Transformer

class Transformer(nn.Module):def __init__(self, embed_dim, src_vocab_size, target_vocab_size, seq_length, num_layers=2, expansion_factor=4,n_heads=8):super(Transformer, self).__init__()"""  Args:embed_dim:  dimension of embedding src_vocab_size: vocabulary size of sourcetarget_vocab_size: vocabulary size of targetseq_length : length of input sequencenum_layers: number of encoder layersexpansion_factor: factor which determines number of linear layers in feed forward layern_heads: number of heads in multihead attention"""self.target_vocab_size = target_vocab_sizeself.encoder = TransformerEncoder(seq_length, src_vocab_size, embed_dim, num_layers=num_layers,expansion_factor=expansion_factor, n_heads=n_heads)self.decoder = TransformerDecoder(target_vocab_size, embed_dim, seq_length, num_layers=num_layers,expansion_factor=expansion_factor, n_heads=n_heads)def make_trg_mask(self, trg):"""Args:trg: target sequenceReturns:trg_mask: target mask"""batch_size, trg_len = trg.shape# returns the lower triangular part of matrix filled with onestrg_mask = torch.tril(torch.ones((trg_len, trg_len))).expand(batch_size, 1, trg_len, trg_len)return trg_maskdef decode(self, src, trg):"""for inferenceArgs:src: input to encodertrg: input to decoderout:out_labels : returns final prediction of sequence"""trg_mask = self.make_trg_mask(trg)enc_out = self.encoder(src)out_labels = []batch_size, seq_len = src.shape[0], src.shape[1]# outputs = torch.zeros(seq_len, batch_size, self.target_vocab_size)out = trgfor i in range(seq_len):  # 10out = self.decoder(out, enc_out, trg_mask)  # bs x seq_len x vocab_dim# taking the last tokenout = out[:, -1, :]out = out.argmax(-1)out_labels.append(out.item())out = torch.unsqueeze(out, 0)return out_labelsdef forward(self, src, trg):"""Args:src: input to encodertrg: input to decoderout:out: final vector which returns probabilities of each target word"""trg_mask = self.make_trg_mask(trg)enc_out = self.encoder(src)outputs = self.decoder(trg, enc_out, trg_mask)return outputs

7. Test Code

验证模型是否可正常运行,可以通过如下代码进行测试。如果没有报错,能输出结果那就没有问题。

if __name__ == '__main__':src_vocab_size = 11target_vocab_size = 11num_layers = 6seq_length = 12# let 0 be sos(start operation signal) token and 1 be eos(end operation signal) tokensrc = torch.tensor([[0, 2, 5, 6, 4, 3, 9, 5, 2, 9, 10, 1],[0, 2, 8, 7, 3, 4, 5, 6, 7, 2, 10, 1]])target = torch.tensor([[0, 1, 7, 4, 3, 5, 9, 2, 8, 10, 9, 1],[0, 1, 5, 6, 2, 4, 7, 6, 2, 8, 10, 1]])print(src.shape, target.shape)model = Transformer(embed_dim=512, src_vocab_size=src_vocab_size,target_vocab_size=target_vocab_size, seq_length=seq_length,num_layers=num_layers, expansion_factor=4, n_heads=8)# print(model)out = model(src, target)print(out)print(out.shape)print("=" * 50)# inferencesrc = torch.tensor([[0, 2, 5, 6, 4, 3, 9, 5, 2, 9, 10, 1]])trg = torch.tensor([[0]])print(src.shape, trg.shape)out = model.decode(src, trg)print(out)

总结

即使现在ChatGPT等大模型的问世引起了社会广泛关注,但仍理性看待Transformer及其应用范围,在工业界仍旧是以ResNet为首的卷积神经网络占大头。而Transformer在学术界的地位是无法取代的,因此了解最基础的Transformer(Naive Transformer)也是很有必要性的。后续可以关注一下本博客衍生出的Vision Transformer的介绍和实现(挖个坑)……

日志

2023.3.26.18:43 由于时间关系,先发布出来,后面会继续更进补充每个模块的要点和细节讲解。
2023.3.27.13:22 补充Word Embedding和Position Encoding的讲解。
2023.3.27.19:23 补充Multi-Head Attention讲解
2023.3.28.15:27 补充Transformer Decoder讲解

参考文献

B站视频链接:Transformer从零详细解读(可能是你见过最通俗易懂的讲解)
YouTube视频链接:Pytorch Transformers from Scratch (Attention is all you need) 【友情提示:此视频的代码有略微错误】

Ba J L, Kiros J R, Hinton G E. Layer normalization[J]. arXiv preprint arXiv:1607.06450, 2016.
Vaswani A, Shazeer N, Parmar N, et al. Attention is all you need[J]. Advances in neural information processing systems, 2017, 30.

https://www.kaggle.com/code/arunmohan003/transformer-from-scratch-using-pytorch/notebook
http://jalammar.github.io/illustrated-transformer/
https://theaisummer.com/transformer/
https://towardsdatascience.com/7-things-you-didnt-know-about-the-transformer-a70d93ced6b2
http://nlp.seas.harvard.edu/2018/04/03/attention.html
https://peterbloem.nl/blog/transformers
https://towardsdatascience.com/how-to-code-the-transformer-in-pytorch-24db27c8f9ec
https://github.com/hyunwoongko/transformer

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文入门BMS(电池管理系统)

1.前言 本文章是基于曾师兄的文稿《具有组网扩展功能的新能源汽车电池管理系统》而写的文章。该文章主要是对BMS(Battery Management System,电池管理系统)做一些简要的介绍,借此助各位也助我入门BMS。 有纰漏请指出&#xff0c…

Redis数据结构

字节青训营后端打卡笔记,主题结构参照文章,以及网络上其它很多的资料所记录下来的笔记。 Redis数据结构一览 SDS(Simple Dynamic String) C语言字符串的缺陷 获取字符串长度函数strlen()时间复杂度为O(N) 字符串以\0结尾,意味着字符串里的…

手抖把Python2.7卸载了,导致了自己的yum不可用以及yum因python版本无法使用的问题

摘要: 从标题就能看到我有多心如死灰了,简单介绍下我是如何自残的过程. ①首先因为需要部署爬虫程序,然后安装Python3. ②Python3系列和Python2系列版本不向下兼容,所以我就卸载了机器自带的Python2.7,删的干干净净. ③然后我下载了Python3.8的包. ④我开始使用yum命令安装…

LangChain+LLM大模型问答能力搭建与思考

1. 背景 最近,大模型(LLMs,Large Language Models)可谓是NLP领域,甚至整个科技领域最火热的技术了。凑巧的是,我本人恰好就是NLP算法工程师,面临着被LLMs浪潮淘汰的窘境,决定在焦虑…

给AI挖坑 | 实测New Bing能否回答员工那些刁钻的问题?

ChatGPT狂飙160天,世界已经不是之前的样子。 新建了人工智能中文站https://ai.weoknow.com 每天给大家更新可用的国内可用chatGPT资源 之前玩ChatGPT,发现这玩意很擅长胡说八道,比如你让它写一段发言稿,并引用鲁迅名言&#xff0…

如何用Rosetta全家桶设计一个抗体?

新冠肆虐无药可医, 医护冒险奋战在前线。 实验室里抗体设计, 试管里混合液波光粼粼, 分子结构、细胞实验频频。 日以继夜,孜孜不倦, 只为破解疫情的难题。 我们紧密团结,努力前行, 心中不灭的信…

【ChatGPT 】《ChatGPT 后续:我开发了一个超级阅读器,免费分享给大家》- 知识点目录

《ChatGPT 后续:我开发了一个超级阅读器,免费分享给大家》 00:00 我们开发了超级阅读器 01:37 思路和开发过程 03:00 使用方式 03:43 AI 工具加持开发效率 04:14 更多可能性 04:57 局限性 1. 介绍:PandaGPT 上传文献聊天窗口提问 2. DALL…

搭建正版GPT4.0!不用ChatGPT账号,不要API!

手把手教你免费搭建正版GPT4.0!不用ChatGPT账号,不要API! 项目简介 项目地址:https://github.com/ramonvc/freegpt-webui优点: 完全免费且不需要任何 API 密钥 ❌🔑 该项目的特点是使用G4F API 的WebUI …

他做了一个「ChatGPT 杀手」,a16z 抢着投

比「GPT 侦探」更重要的是,AI 生成内容在不同行业的「容忍度」。 图片来源:由无界版图AI工具生成 作者 | 美漪编辑 | 靖宇 最近两个月,科技圈最热的话题,无疑是 OpenAI 推出的对话式 AI 应用 ChatGPT,不仅可以让它给你…

巴比特 | 元宇宙每日必读:ChatGPT「代码解释器」正式解禁,它补齐了ChatGPT的哪些短板?用户该如何使用?...

摘要:7月9日,OpenAI 的聊天机器人 ChatGPT 推出了新功能:代码解释器(Code Interpreter)。这个新功能已经对所有 Plus 订阅用户开放,其扩展了 ChatGPT 的功能,为用户带来了更好的交互式编程体验和…

ChatGPT应用组队学习来了!

Datawhale学习 联合主办:Datawhale、百度文心 Datawhale联合百度文心,五月为大家带来AIGC应用专题:大模型从入门到应用,学习大纲如下(文末整理了这次学习的所有资料): 参与学习 ▶ 活动时间&am…

阿尔法狗咬向ChatGPT七寸

图片来源:由无界AI生成 瞄准ChatGPT,谷歌的下一枚炮弹已经准备好,只待发射。而担负起发射任务的,是谷歌DeepMind。 昨天,谷歌DeepMind的CEO德米斯哈萨比斯(Demis Hassabis)在采访中放出豪言&…

谷歌版ChatGPT突然公测!上手实测结果在此,体验申请通过飞快

杨净 金磊 发自 凹非寺量子位 | 公众号 QbitAI 谷歌吃了大亏之后,这次一声不吭,放了大招: 对标ChatGPT的Bard测试版,刚刚正式对外发布。 而且这次用户在申请候补名单之后,无需经历漫长的等待时间。 没错,量…

对抗 ChatGPT 的创业武器:专注和紧密的反馈循环

ChatGPT 超越谷歌主导地位 在我的上一篇文章中,我探讨了 ChatGPT 超越谷歌主导地位的可能牛市案例。但我也对我认为是熊市的情况表示赞赏。正如我提到的,ChatGPT 的无界界面有点像,而不是 DoorDash 的重点推出策略,DoorDash 在美国所有城市和商品类别中同时推出,当你订购…

chatgpt赋能Python-python_queque

Python Queue模块实现队列的介绍 Python语言是一种通俗易懂、功能丰富的编程语言。它的标准库还包括许多有用的模块,用于实现各种数据结构和算法。其中,Queue模块是一种实现队列的模块。这个模块实现了多线程编程时所必需的队列数据结构。 什么是队列&…

ChatGPT已能操控机器人,工程师连代码都不用写,网友:微软在搞天网?

Alex 发自 凹非寺量子位 | 公众号 QbitAI 当我还在跟ChatGPT吹牛尬聊时,有人已经在拿它操控机器人了。 不是别人,正是OpenAI的金主爸爸、不久前刚拿ChatGPT“重新发明搜索引擎”的微软。 到目前为止,开发者调教机器人不仅技术门槛高&#xff…

火爆外网的ChatGPT,改Bug,敲代码不在话下

目录 前言 一、ChatGPT 是什么? 二、ChatGPT到底有什么用 1.可以回答问题 2.帮你创作文章和标题 3.调试代码和修复代码 4.检测安全漏洞,也许还能创建PoC 总结 前言 这几天ChatGPT AI 可谓是火的一塌糊涂,那么它到底是什么&#xff1f…

Python使用itchat库+图灵机器人(新手上路)

前不久有个朋友说,谁谁的男朋友写个机器人,然后聊天很嗨的样子,看下面图,然后今天下午闲着,就把整理了下思路,采用Python进行如下开发,具体步骤如下: 1、第一步,因为我是…

图灵 | 计算机器与智能

【“计算机器与智能”选自《Mind》,no.2236(1950.10),P433-460。牛津大学出版社允许重印。刘西瑞、王汉琦 翻译】 1. 模仿游戏 我建议来考虑这个问题 :“机器能够思维吗?” 这可以从定义 “机 器” 和 “思…

图灵奖得主LeCun评ChatGPT不算创新,被网友骂柠檬精

“ChatGPT并不算创新。” “OpenAI做的这个东西跟其他实验室相比,根本算不上什么进步。” 这两天,图灵奖得主LeCun公开和大热趋势“唱反调”,瞬间引发网友围观。 要知道,ChatGPT功能强大又好玩,火爆全网,任…