transformer的学习:Attention is all you need

news2024/9/22 6:43:18

目录

整体概述:​编辑​编辑

encoder:

embedding:

​编辑

self-attention:

向量的相似度计算:

qkv怎么来的​编辑

softmax:

code

multi-head-attention

位置编码:

残差&&FFN:

decoder:

cross-attention

self-attention

Linear + softmax

Train&&loss

ref:


找到了一篇写的很好的贴子,记录一些学习笔记:

https://jalammar.github.io/illustrated-transformer/

注意力机制(Attention),这是现代深度学习模型中常见的一种方法。注意力机制在神经机器翻译应用中起到了提升性能的作用。本文将介绍Transformer模型,它利用注意力机制提高了模型的训练速度。在某些任务中,Transformer模型的性能超过了Google神经机器翻译模型。然而,最大的好处来自于Transformer模型在并行化方面的优势。实际上,Google Cloud建议使用Transformer模型作为参考模型来使用他们的Cloud TPU服务。

Transformer模型是在论文《Attention is All You Need》中提出的。TensorFlow的一个实现可以在Tensor2Tensor软件包中找到。哈佛大学的自然语言处理研究组创建了一个带有PyTorch实现的指南。

整体概述:

Transformers = encoders + decoders

Encoders = 6 * encoder

Decoders = 6 * decoder

Encoder = self-attention + feed forward nn

Decoder = self-attention + encoder-decoder attention(cross attention) + Feed Forward

encoder-decoder attention:q来自decoder,k和v来自encoder

encoder:

embedding:

文本-->数字,计算机只认识数字

在Transformer模型中,输入序列的词嵌入(word embedding)是模型的一部分,用于将离散的词或标记映射到连续的向量表示。Transformer中的词嵌入被称为输入嵌入(input embedding)。

输入嵌入的作用是将输入序列中的每个词或标记转换为连续的低维向量表示,以便模型能够对其进行处理。这些嵌入向量可以捕捉词语之间的语义和语法信息,从而提供有关词语的上下文表示。

通常情况下,输入嵌入是通过一个可训练的矩阵(通常称为嵌入矩阵)来实现的。该矩阵的大小为词汇表的大小(词汇表中唯一词汇的数量)乘以词嵌入的维度。在训练过程中,嵌入矩阵的参数会随着模型的训练而学习得到。

在Transformer中,输入嵌入通常与位置编码进行相加,以融合词汇和位置信息。这样,每个输入位置都具有一个综合的表示,其中包括词汇信息和相对位置信息。

需要注意的是,Transformer模型中的嵌入层可以是单独的一层,也可以与其他层(如位置编码层、注意力层、前馈神经网络层)一起构成一个整体的模型。输入嵌入在Transformer中起到了将离散的输入序列转换为连续的向量表示的重要作用,为模型提供了有效的输入表示。

torch.nn.embedding()实现

self-attention:

计算相似度。把文本embedding为一个个的词向量token,然后直接相乘(投影)来计算相似度。

上面可以看出it和the animal的相似度很高,以为it就是代指the animal,和because的相似度很低,没啥关系,一个是关系代词,一个是因果连词。

在Transformer模型中,自注意力机制(self-attention)是其核心组成部分之一,也被称为注意力机制(attention mechanism)。自注意力机制允许模型在处理输入序列时,根据序列中不同位置的相关性动态地分配注意力权重。

自注意力机制的目的是对输入序列中的每个位置进行编码,并建立位置之间的关联。它通过计算一个注意力分数来确定每个位置与其他位置之间的关联强度,然后利用这些关联强度对位置的表示进行加权求和。

在Transformer中,自注意力机制的计算过程分为三个步骤:查询(query)、键(key)和值(value)。

  1. 查询(Query):对于每个位置,通过一个线性变换将输入序列中的每个位置映射到一个查询向量,表示该位置的特征。

  2. 键(Key)和值(Value):同样,通过线性变换将输入序列中的每个位置映射到键向量和值向量。键向量用于计算注意力权重,值向量用于加权求和。

  3. 注意力计算:利用查询向量、键向量和值向量计算注意力权重。注意力权重表示每个位置与其他位置之间的关联强度。一般使用点积注意力或加性注意力机制来计算注意力权重。

    1. 点积注意力:通过计算查询向量和键向量之间的点积,然后进行标准化处理,得到注意力权重。

    2. 加性注意力:通过将查询向量和键向量进行线性变换后相加,并应用激活函数,然后进行标准化处理,得到注意力权重。

  4. 加权求和:利用注意力权重对值向量进行加权求和,得到每个位置经过注意力机制后的表示。

自注意力机制可以将输入序列中的不同位置之间的相关性进行建模,从而使模型能够根据输入的上下文动态地分配注意力。这种机制使得Transformer能够在处理序列任务时更好地捕捉长距离依赖关系,提高模型的性能和泛化能力。注意力机制被广泛应用于自然语言处理和机器翻译等任务中。

x-->q,k,v 使用fc,把维度从embedding后的x的512 mapping到64

key:可以看作一本书的目录

value:某一章节(key)里面的内容

query:你的查询关键词

除以8(论文中使用的键向量维度的平方根 - 64)。这样做可以使梯度更加稳定。将结果通过softmax操作进行处理。Softmax函数对得分进行归一化,使得它们都为正值且总和为1。

softmax后的值表示的是相似度权重weight的意思,即最后的权重分配中,k1分的权重是0.88,k2只有0.12,表达的意思是k1和q1更加相似,所以权重更大。

比如:q1是猫a,k1是猫b,k2是狗,那么猫a和猫b的相似度>猫a和狗的相似度,所以猫b的权重是0.88,狗的权重是0.12

Z = sum(权重 * value)

向量的相似度计算:

Cos (θ) = (A·B) / (||A|| ||B||)

余弦相似度是一种衡量两个向量在向量空间中夹角大小的方法。 在二维空间中,我们可以将向量看作是从原点出发的箭头,而余弦相似度就是这两个箭头夹角的余弦值。 这个值介于-1和1之间,值越大表示两个向量越相似,值越小表示两个向量越不相似。 二、余弦相似度的计算 余弦相似度的计算公式为:cos (θ) = (A·B) / (||A|| ||B||),其中A和B是两个向量,||A||和||B||分别表示A和B的模(长度),A·B表示A和B的点积。

假设我们规定||A||和||B||分别表示A和B的模(长度)都是1,那么

Cos (θ) = (A·B)

相似度就是两个向量的点积。

qkv怎么来的

mlp实现的,conv1d

softmax:

Softmax函数是一个常用的数学函数,通常用于将一组实数转换为概率分布。Softmax函数接受一个实数向量作为输入,并将每个元素转换为非负数,使得所有元素之和等于1,表示它们在概率分布中的概率。

softmax(x) = [exp(x₁) / (exp(x₁) + exp(x₂) + ... + exp(xₙ)),exp(x₂) / (exp(x₁) + exp(x₂) + ... + exp(xₙ)),

...exp(xₙ) / (exp(x₁) + exp(x₂) + ... + exp(xₙ))]

例如:

计算的结果可能是一些其他值:21,6,3--》softmax:

Sum = e(21) + e(6) + e(3)

softmax(x1) = e(21) / sum

softmax(x2) = e(6) / sum

softmax(x3) = e(3) / sum

softmax(x) =[ e(21) / sum ,e(6) / sum , e(3) / sum ]

code

# attention
class ScaledDotProductAttention(nn.Module):
    """ Scaled Dot-Product Attention """
    def __init__(self, scale):
        super().__init__()
        self.scale = scale
        self.softmax = nn.Softmax(dim=2)

    def forward(self, q, k, v, mask=None):
        u = torch.bmm(q, k.transpose(1, 2))  # 1.Matmul,(bs,2,4)
        u = u / self.scale  # 2.Scale
        if mask is not None:
            mask[0,1,1] = 1
            u = u.masked_fill(mask, -np.inf)  # 3.Mask atten, e(-inf) = 0
        attn = self.softmax(u)  # 4.Softmax (bs,2,4)2query,4key, u:4*64,4key,64 length
        output = torch.bmm(attn, v)  # 5.Output:bs,2(query个数),64(value长度)
        return attn, output

if __name__ == "__main__":
    batch  = 192
    # n_q, n_k, n_v = 2, 4, 4      # 2 query,4 key,4 value,总共2*4=8个weight
    n_q, n_k, n_v = 200, 480*640, 480*640      # 2 query,4 key,4 value,总共2*4=8个weight
    d_q, d_k, d_v = 128, 128, 64 #
    # n_q, n_k, n_v = 1208, 1208, 1208  # 2 query,4 key,4 value,总共2*4=8个weight
    # d_q, d_k, d_v = 64, 64, 64  #
    q = torch.randn(batch, n_q, d_q) # bs*2*128
    k = torch.randn(batch, n_k, d_k) # bs*4*128
    v = torch.randn(batch, n_v, d_v) # bs*4*64
    mask = torch.zeros(batch, n_q, n_k).bool()

    attention = ScaledDotProductAttention(scale=np.power(d_k, 0.5))  # scale是query和key长度128的根号
    attn, output = attention(q, k, v, mask=mask)

multi-head-attention

在传统的注意力机制中,给定一个查询(Query)和一组键值对(Key-Value Pairs),注意力机制通过计算查询与每个键之间的相关度,然后将这些相关度应用于对应值的加权和。这种单头的注意力机制可以捕捉到一种特定的关注模式,但可能无法充分表达序列中丰富的关系。

多头注意力通过引入多个子注意力头来解决这个问题。在每个子头中,通过对查询、键和值进行独立的线性变换,然后计算相应的注意力权重。最后,将所有子头的注意力权重加权和作为最终的输出。

具体来说,多头注意力可以分为以下几个步骤:

  1. 线性变换:对查询、键和值进行线性变换,将它们映射到不同的表示空间。这可以通过矩阵乘法实现,其中每个子头都有自己的权重矩阵。

  2. 注意力计算:对于每个子头,通过计算查询与键的内积,然后进行缩放(通常是除以查询维度的平方根),得到注意力得分。注意力得分可以表示查询与键的相关度。

  3. 注意力权重:通过将注意力得分经过 softmax 函数进行归一化,得到每个键的注意力权重。这些权重决定了对应值的重要程度。

  4. 加权和:将每个子头的注意力权重与对应的值相乘,然后将它们加权求和得到最终的输出表示。

多头注意力的优势在于它能够并行计算多个子头,从而提高模型的计算效率。同时,每个子头可以关注输入序列中不同的部分,从而捕捉到更丰富的关系。最终的输出表示将多个子头的信息整合在一起,以提供更全面的表示能力。

我可以把输入的x分解为一个qkv,也可以分解为8个qkv(8 heads)

多头的本质无非就是多了几组参数,模型参数越大,拟合能力越强

import torch.nn as nn
import torch
import numpy as np
from attention import ScaledDotProductAttention

class MultiHeadAttention(nn.Module):
    """ Multi-Head Attention """
    def __init__(self, n_head, d_k_, d_v_, d_k, d_v, d_o):
        super().__init__()

        self.n_head = n_head
        self.d_k = d_k
        self.d_v = d_v

        self.fc_q = nn.Linear(d_k_, n_head * d_k)  # d_k_  = d_q_,  (128)d_k_ != d_k(256)
        self.fc_k = nn.Linear(d_k_, n_head * d_k)
        self.fc_v = nn.Linear(d_v_, n_head * d_v)

        self.attention = ScaledDotProductAttention(scale=np.power(d_k, 0.5))

        self.fc_o = nn.Linear(n_head * d_v, d_o)

    def forward(self, q, k, v, mask=None):
        n_head, d_q, d_k, d_v = self.n_head, self.d_k, self.d_k, self.d_v

        batch, n_q, d_q_ = q.size()
        batch, n_k, d_k_ = k.size()
        batch, n_v, d_v_ = v.size()
        """一组qkv(各自random来,可以不同) linear 多组 qkv
        q,k,v来自相同的x就是self-attention,否则就是cross attention"""
        q = self.fc_q(q)  # 1.单头变多头, (bs,2,128) -->(bs,2,2048) ,16倍
        k = self.fc_k(k)  # (bs,4,128) -->(bs,4,2048)
        v = self.fc_v(v)  # (bs,4,64) --> (bs,4,1024)
        q = q.view(batch, n_q, n_head, d_q).permute(2, 0, 1, 3).contiguous().view(-1, n_q, d_q)  # (8,2,256)
        k = k.view(batch, n_k, n_head, d_k).permute(2, 0, 1, 3).contiguous().view(-1, n_k, d_k)
        v = v.view(batch, n_v, n_head, d_v).permute(2, 0, 1, 3).contiguous().view(-1, n_v, d_v)

        if mask is not None:
            mask = mask.repeat(n_head, 1, 1)
        attn, output = self.attention(q, k, v, mask=mask)  # 2.当成单头注意力求输出

        output = output.view(n_head, batch, n_q, d_v).permute(1, 2, 0, 3).contiguous().view(batch, n_q, -1)  # 3.Concat
        output = self.fc_o(output)  # 4.仿射变换得到最终输出

        return attn, output


if __name__ == "__main__":
    batch = 2
    n_q, n_k, n_v = 2, 4, 4
    d_q_, d_k_, d_v_ = 128, 128, 64
    # 192,1408
    q = torch.randn(batch, n_q, d_q_)
    k = torch.randn(batch, n_k, d_k_)
    v = torch.randn(batch, n_v, d_v_)
    mask = torch.zeros(batch, n_q, n_k).bool()

    mha = MultiHeadAttention(n_head=8, d_k_=128, d_v_=64, d_k=256, d_v=128, d_o=128)
    attn, output = mha(q, k, v, mask=mask)

在对单词"it"进行编码时,一个注意力头(attention head)主要关注"the animal",而另一个注意力头则主要关注"tired"。从某种意义上说,模型对单词"it"的表示融入了"animal"和"tired"两个单词的一些表示信息。

这种现象是由于自注意力机制的特性所导致的。在自注意力机制中,每个单词都可以与其他单词进行交互,并根据其在句子中的上下文关系来计算权重。在编码单词"it"时,注意力头会根据输入句子的整体语义进行选择性地关注相关的单词。

因此,一个注意力头可能更关注与"it"在语义上相关的"the animal",而另一个注意力头则更关注与"it"在语义上相关的"tired"。这种注意力分配的机制使得模型在表示"it"时同时包含了与"the animal"和"tired"相关的一些信息。

通过这种方式,模型可以在编码过程中将相关的上下文信息融入到每个单词的表示中,从而更好地捕捉单词之间的语义关联。这种融合的表示有助于提高模型对整个句子的理解和语义表达能力。

位置编码:

位置编码是一种用于为序列数据中的每个位置赋予特定的编码信息的技术。在自注意力机制(如Transformer模型)中,位置编码被用于为输入序列中的每个单词或位置赋予其相对位置的信息,这样模型可以利用这些位置信息来更好地建模单词之间的顺序关系。

在Transformer模型中,常用的位置编码方法是使用正弦和余弦函数来生成位置向量。具体而言,对于序列中的每个位置i和每个维度j,位置编码向量PE(i, j)可以通过以下公式计算得到:

PE(i, 2j) = sin(i / 10000^(2j/d_model))

PE(i, 2j+1) = cos(i / 10000^(2j/d_model))

其中,i表示位置,j表示维度,d_model表示模型的维度。通过这种方式,位置编码向量中的奇数维度用正弦函数编码,偶数维度用余弦函数编码。这样,不同位置的位置编码向量在不同维度上的数值差异可以反映出它们之间的相对位置关系。

位置编码向量可以与输入的词向量相加,从而将位置信息融入到词向量中。这样,模型在进行自注意力计算时不仅考虑单词的语义信息,还会考虑它们在序列中的相对位置关系。位置编码的引入有助于模型更好地捕捉序列数据中的顺序信息,提高模型对序列的理解能力。

需要注意的是,位置编码是在模型的输入阶段添加的,它不会随着训练而更新。它提供了一种固定的表示方式,用于传达位置信息给模型。

该算法使用正弦和余弦函数来生成位置编码向量,具有以下几个原因:

  1. 周期性:正弦和余弦函数具有周期性的特性,可以在位置编码中表达不同位置之间的相对距离。通过使用这两个函数,我们可以创建一种循环的模式,使得相同距离的位置在编码向量中具有相似的值。

  2. 连续性:正弦和余弦函数是连续的函数,可以提供平滑的变化。这样,在相邻位置之间的微小变化也可以在位置编码中得到对应的微小变化,从而更好地捕捉到位置之间的细微差异。

  3. 兼容性:位置编码算法与Transformer模型的自注意力机制相兼容。在自注意力计算中,位置编码向量可以与输入的词向量相加,从而将位置信息融入到模型中。由于正弦和余弦函数的周期性和连续性特征,位置编码向量与词向量的加和操作可以保持一定的平衡,不会引入过大的变动。

假设我们仍然使用示例中的文本序列:"I love natural language processing.",并假设d_model为4。

对于单词"I",我们计算其位置编码向量。

对于每个位置i和每个维度j,位置编码向量PE(i, j)可以通过以下公式计算得到:

每个位置i一般的维度都是64?dimension是512?

位置1的位置编码向量 PE(1, 0):

PE(1, 0) = sin(1 / 10000^(0/4))

= sin(1 / 10000^0)

= sin(1 / 1)

= sin(1)

≈ 0.8415

位置1的位置编码向量 PE(1, 1):

PE(1, 1) = cos(1 / 10000^(1/4))

= cos(1 / 10000^0.25)

= cos(1 / 1.7783)

≈ cos(0.5623)

≈ 0.8253

对于单词"love",我们同样计算其位置编码向量。

位置2的位置编码向量 PE(2, 0):

PE(2, 0) = sin(2 / 10000^(0/4))

= sin(2 / 10000^0)

= sin(2 / 1)

= sin(2)

≈ 0.9093

位置2的位置编码向量 PE(2, 1):

PE(2, 1) = cos(2 / 10000^(1/4))

= cos(2 / 10000^0.25)

= cos(2 / 1.7783)

≈ cos(1.1246)

≈ 0.4546

class PositionalEncoding(nn.Module):

    def __init__(self, d_hid, n_position=200):
        super(PositionalEncoding, self).__init__()
        # Not a parameter
        # 将tensor注册成buffer, optim.step()的时候不会更新
        self.register_buffer('pos_table', self._get_sinusoid_encoding_table(n_position, d_hid))

    def _get_sinusoid_encoding_table(self, n_position, d_hid):
        ''' Sinusoid position encoding table '''
        # TODO: make it with torch instead of numpy

        def get_position_angle_vec(position):
            # 2i, 所以此处要//2. 
            return [position / np.power(10000, 2 * (hid_j // 2) / d_hid) for hid_j in range(d_hid)]

        sinusoid_table = np.array([get_position_angle_vec(pos_i) for pos_i in range(n_position)])
        sinusoid_table[:, 0::2] = np.sin(sinusoid_table[:, 0::2])  # dim 2i 偶数
        sinusoid_table[:, 1::2] = np.cos(sinusoid_table[:, 1::2])  # dim 2i+1 奇数

        return torch.FloatTensor(sinusoid_table).unsqueeze(0) # shape:(1, maxLen(n_position), d_hid)

    def forward(self, x):
        return x + self.pos_table[:, :x.size(1)].clone().detach() # 数据、梯度均无关

残差&&FFN:

Transformer模型中的残差连接是一种技术,用于在不同层之间传递信息并减轻梯度消失的问题。它通过将输入信号与层内计算的结果相加,从而将原始输入的信息直接传递到网络的后续层。

class PositionwiseFeedForward(nn.Module):
    ''' A two-feed-forward-layer module '''

    def __init__(self, d_in, d_hid, dropout=0.1):
        super().__init__()
        self.w_1 = nn.Linear(d_in, d_hid) # position-wise
        self.w_2 = nn.Linear(d_hid, d_in) # position-wise
        self.layer_norm = nn.LayerNorm(d_in, eps=1e-6)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):

        residual = x

        x = self.w_2(F.relu(self.w_1(x)))
        x = self.dropout(x)
        # add & norm
        x += residual

        x = self.layer_norm(x)

        return x

decoder:

在Transformer解码器中,它采用了自注意力机制(self-attention)和多头注意力机制(multi-head attention)来编码输入序列的上下文信息,并利用位置编码对序列中的位置信息进行建模。解码器通过逐步进行自注意力计算和前馈神经网络(Feed-Forward Network)的处理,生成目标序列的每个元素。

cross-attention

解码器的目标是根据输入的上下文信息和先前生成的元素,以逐步生成目标序列。它可以根据任务的不同而有所调整,例如在机器翻译任务中,解码器可以逐步生成目标语言的单词;在图像生成任务中,解码器可以逐步生成图像的像素值。

kv来自encoder,q来自decoder

在解码器中,输出的每一步会被作为下一个时间步骤中底层解码器的输入,并且解码器会像编码器一样将其解码结果向上传递。与编码器输入类似,解码器输入也会经过嵌入和位置编码的处理,以指示每个单词的位置。

self-attention

在Transformer解码器中,自注意力层的操作方式与编码器中的略有不同:

在解码器中,自注意力层只能关注输出序列中的先前位置(单向attention,encoder的attention是双向的,即后中间的单词既可以和前面又可以和后面的词attention,而decoder中的只能和前面的词attention)。为了实现这一点,在自注意力计算中,在进行softmax之前,将未来位置进行掩码(将其设置为负无穷)。

过程就是mask住下一个词和他后面的词,预测下一个词,然后把预测的下一个词作为输入在预测下一个词。

Linear + softmax

在Transformer解码器中,解码器堆栈的输出是一个浮点数向量。我们如何将其转换为单词?这是最终的线性层和其后的Softmax层的任务。

线性层是一个简单的全连接神经网络,将解码器堆栈生成的向量投影到一个更大的向量中,称为logits向量。

假设我们的模型知道10,000个唯一的英文单词(模型的“输出词汇表”),这些单词是从训练数据集中学习得到的。这将使logits向量的宽度为10,000个单元格,每个单元格对应一个唯一单词的分数。这就是我们如何解释线性层之后的模型输出。

然后,Softmax层将这些分数转换为概率(都是正数,总和为1.0)。选择具有最高概率的单元格,并将与之相关联的单词作为该时间步骤的输出生成。

简而言之,通过线性层和Softmax层,将解码器堆栈的输出转换为概率分布,并根据最高概率选择输出的单词。

Train&&loss

训练过程中,未经训练的Transformer模型也会经历完全相同的前向传播过程。但由于我们在带标签的训练数据集上进行训练,我们可以将模型的输出与实际正确输出进行比较。

为了可视化这一点,让我们假设我们的输出词汇表只包含六个单词("a","am","i","thanks","student"和"<eos>",表示句子的结束)。

假设我们正在训练我们的模型,这是训练阶段的第一步,我们正在使用一个简单的例子进行训练——将"merci"翻译成"thanks"。

这意味着我们希望输出是一个概率分布,指示单词"thanks"。但由于这个模型尚未经过训练,目前实现这一点的可能性较低。

在训练的初始阶段,模型的参数是随机初始化的,它对输入序列"merci"的翻译可能会得到不正确的输出。由于模型尚未学习到正确的翻译关系,输出的概率分布可能会在词汇表中的不同单词上分散,而不是集中在"thanks"上。

通过训练过程中的反向传播和参数更新,模型逐渐学习到输入序列"merci"与目标序列"thanks"之间的对应关系,并且输出概率分布逐渐偏向于正确的单词。随着训练的进行,模型的输出将逐渐接近我们所期望的目标。

要比较两个概率分布,我们可以简单地将一个概率分布减去另一个概率分布。有关更多详细信息,请参考交叉熵和Kullback-Leibler散度。

但请注意,这只是一个过度简化的例子。更实际地说,我们将使用长度超过一个单词的句子。例如,输入为"je suis étudiant",期望输出为"i am a student"。这实际上意味着我们希望我们的模型连续输出概率分布,其中:

  • 每个概率分布由宽度为vocab_size的向量表示(在我们的玩具示例中为6,但更实际地可能是30,000或50,000等数字)。

  • 第一个概率分布在与单词"i"相关的单元格中具有最高的概率。

  • 第二个概率分布在与单词"am"相关的单元格中具有最高的概率。

  • 依此类推,直到第五个输出分布指示了'<end of sentence>'符号,该符号在由10,000个元素构成的词汇表中也有一个单元格与之对应。

在生成输出时,模型可以一次选择具有最高概率的单词,并忽略其他单词,这被称为贪婪解码。这是一种方法。另一种方法是保留前两个最高概率的单词(例如,'I'和'a'),然后在下一步中运行模型两次:一次假设第一个输出位置为单词'I',另一次假设第一个输出位置为单词'a',并且考虑到位置#1和#2,选择产生较少错误的版本。我们对位置#2、#3等进行类似的操作。这种方法称为"beam search",在我们的示例中,beam_size为2(表示始终保留两个未完成翻译的假设),top_beams也为2(表示我们将返回两个翻译结果)。这些都是您可以进行实验的超参数。

通过使用beam search,可以在生成过程中保留多个可能的翻译假设,而不仅仅是贪婪地选择单个单词。这有助于处理复杂的输出空间,提高模型生成正确翻译的概率。您可以根据任务的要求和实际情况对beam_size和top_beams进行调整和优化。

ref:

https://arxiv.org/abs/1706.03762

https://blog.research.google/2017/08/transformer-novel-neural-network.html

https://www.youtube.com/watch?v=rBCqOTEfxvg

https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb

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

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

相关文章

基于react native的自定义轮播图

基于react native的自定义轮播图 效果示例图示例代码 效果示例图 示例代码 import React, {useEffect, useRef, useState} from react; import {Animated,PanResponder,StyleSheet,Text,View,Dimensions, } from react-native; import {pxToPd} from ../../common/js/device;c…

8个 C++ 开源项目,帮初学者快速进阶

参与或阅读开源项目的源代码&#xff0c;可以获得丰富的实践机会。下面&#xff0c;让我们一起看看以下八个优秀的 C 开源项目。 通过参与或阅读开源项目的源代码&#xff0c;你可以获得丰富的实践机会。实际的项目代码比简单的教程更具挑战性&#xff0c;可以帮助你深入理解 …

19.作业

1.作业样例图 2.学习视频 19.作业讲解

LeetCode每日一题【19. 删除链表的倒数第 N 个结点】

思路&#xff1a;快慢指针 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x)…

vuex - 21年的笔记 - 后续更新

vuex是什么 Vuex是实现组件全局状态&#xff08;数据&#xff09;管理的一种机制&#xff0c;方便的实现组件之间的数据的共享 使用vuex统一管理状态的好处 能够在vuex中集中管理共享的数据&#xff0c;易于开发和后期维护能够高效地实现组件之间的数据共享&#xff0c;提高…

程序设计基础--C语言【三】

课堂笔记两次合集 3.运算符 目录 3.运算符 3.1.算术运算符 3.2.赋值运算符 3.3.增1、减1运算符 3.4.关系运算符 3.5.逻辑运算符 3.6.条件运算符 3.7.类型转换 3.8.基本输入、输出函数 3.8.1.字符输出函数putchar() 3.8.2.字符输入函数getchar() 3.8.3.格式化输入…

算法-图的强连通分量,图的最小生成树

1.图的强连通分量 (1). 定义 图的强连通分量是图论中的一个重要概念&#xff0c;主要在有向图中进行讨论。具体来说&#xff0c;如果在一个有向图G中&#xff0c;任意两个顶点vi和vj&#xff08;其中vi大于vj&#xff09;之间都存在一条从vi到vj的有向路径&#xff0c;同时也存…

Android App开发的自动化测试框架UI Automator使用教程

Android的自动化测试有很多框架&#xff0c;其中ui automator是google官方提供的黑盒UI相关的自动化测试工具&#xff0c;&#xff08;GitHub主页&#xff1a;case使用java写&#xff0c;今天实践了一下官方文档中样例程序&#xff0c;其中还是有一些小问题需要总结一下的。 环…

为什么签名apk,需要公钥证书和私钥证书,不是私钥就能签名吗?对应的公钥通常包含在APK文件中,这样用户和系统可以验证签名的有效性

在Android开发中&#xff0c;对APK进行签名确实需要使用到公钥证书和私钥证书&#xff0c;而不仅仅是私钥。以下是详细解释&#xff1a; 身份验证&#xff1a;公钥证书作为应用程序的身份证明&#xff0c;可以帮助用户或系统验证安装的APK的真实性。当用户下载并安装APK时&…

第十四届蓝桥杯(C/C++ 大学B组)

试题 A&#xff1a;日期统计 #include <bits/stdc.h> using namespace std;const int numbers[100] {5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7, 5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5,8, 6, 1, 8, 3, 0, 3, 7, 9, 2, 7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, …

2016年认证杯SPSSPRO杯数学建模A题(第二阶段)洗衣机全过程文档及程序

2016年认证杯SPSSPRO杯数学建模 A题 洗衣机 原题再现&#xff1a; 洗衣机是普及率极高的家用电器&#xff0c;它给人们的生活带来了很大的方便。家用洗衣机从工作方式来看&#xff0c;有波轮式、滚筒式、搅拌式等若干种类。在此基础上&#xff0c;各厂商也推出了多种具体方案…

思科无线控制器配置学习

文章目录 简单拓扑WLC配置 简单拓扑 WLC配置 WLC#show running-config Building configuration...Current configuration : 11943 bytes ! ! Last configuration change at 16:22:44 UTC Thu Mar 14 2024 by admin ! version 17.9 service timestamps debug datetime msec se…

OrangeDAO联合创始人Don Ho确认出席Hack.Summit() 2024区块链开发者大会

随着Web3技术的快速发展&#xff0c;区块链领域备受关注的盛会——Hack.Summit() 2024 区块链开发者大会即将于 2024 年 4 月 9 日至 10 日在香港数码港隆重启幕。本次大会不仅是 Hack.Summit() 系列在亚洲的首次亮相&#xff0c;更象征着全球区块链行业对亚洲&#xff0c;尤其…

SAP-MM-设置字段默认值

当我们创建订单时&#xff0c;有些字段总是重复输入&#xff0c;每次值也是固定的&#xff0c;例如生产订单 如上图“生产工厂都是1000”如何设置成默认每次进入都是1000呢&#xff1f; 点击字段&#xff0c;F1 查看参数ID“WRK” 输入tcode&#xff1a;SU3 按上图维护数据100…

gimp教程

一、gimp下载安装 二、基本概念和术语 &#xff08;一&#xff09;图像 图像是GIMP要处理的对象。 一个图像对应一个文件&#xff0c;例如一个TIFF或JPEG文件。 一个图像对应一个显示窗口。 可以同时打开多个图像。 &#xff08;二&#xff09;图层 一个图像就像一堆纸叠在…

TypeScript在学习(0)

1.什么是TypeScript? 答:TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集&#xff0c;而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。 个人浅见&#xff0c;我一直把ts简单理解成&#xff0c;其实就是javascript上多了…

美易官方:美股维持涨势,三大股指再创新高

在今日的早盘交易中&#xff0c;美股市场继续维持其涨势&#xff0c;三大股指再次刷新历史纪录。市场信心受到一系列积极经济数据的支撑&#xff0c;投资者对未来的经济增长和企业盈利保持乐观态度。 首先&#xff0c;让我们来看一下道琼斯工业平均指数的表现。该指数在早盘交易…

一键批量查询快递单号,一键批量查询,共享备份物流,快递物流尽在掌控

随着网购的普及&#xff0c;快递物流信息的管理变得尤为重要。每天都有大量的快递单号需要查询&#xff0c;如果一个个手动查询&#xff0c;不仅费时费力&#xff0c;还容易出错。为了解决这个问题&#xff0c;我们教您如何批量查询快递单号&#xff0c;并将快递物流信息进行备…

Linux docker4--本地jar包生成镜像和docker部署运行

一、通过springboot创建一个java项目&#xff0c;打成出jar包。 二、将jar包生成docker镜像 &#xff08;1&#xff09;、创建Dockerfile文件 创建Dockerfile文件&#xff0c;将如下的代码内容粘贴进去即可。 注意&#xff1a;本例中我打出的jar包是boot.jar。如果你打出的jar…

开源项目ChatGPT-Next-Web的容器化部署(二)-- jenkins CI构建并推送镜像

一、背景 接着上文已制作好了Dockerfile&#xff0c;接下来就是docker build/tag/push等一系列操作了。 不过在这之前&#xff0c;你还必须在jenkins等CI工具中&#xff0c;拉取源码&#xff0c;然后build构建应用。 因为本文的重点不是讲述jenkins ci工具&#xff0c;所以只…