当前位置:   article > 正文

Transformer 入门解析_feed forward network

feed forward network

目录

掌握模型结构的步骤

1.宏观视角:输入,黑箱,输出

2.黑箱组成:

3.拆解黑箱组成

位置编码

前馈神经网络Feed-Forward Networks

残差神经网络块ResNet

Normalize

Transformer Decoder的输入

基于Encoder-Decoder 的Multi-Head Attention

掌握模型结构的步骤

1.宏观视角:输入,黑箱,输出

2.黑箱组成:

3.拆解黑箱组成

自注意力:输入句子中,其他单词对某个单词的影响

前馈神经网络:输入句子中,同一位置的单词,前馈神经网络一致

编码-解码自注意力:输入句子的相关部分

位置编码

矢量是一阶张量、矩阵是二阶张量

假设词嵌入的维数为4,则实际的位置编码如下:

每一行对应一个词向量的位置编码,

所以第一行对应着输入序列的第一个词。

每行包含512个值,每个值介于1和-1之间。

已经对它们进行了颜色编码,所以图案是可见的。

20字(行)的位置编码实例,词嵌入大小为512(列)。

它从中间分裂成两半。

左半部分的值由一个函数(使用正弦)生成,

右半部分由另一个函数(使用余弦)生成。

然后将它们拼在一起而得到每一个位置编码向量。

文本进入到模型需要编码,transformer的编码方式包括Word Embedding和Positional Encoding。

  word embedding两种方式:
  1、使用预训练模型直接生成,相当于提供一个lookup table;

(若针对一个特定的nlp任务,其训练集词库有限,即预测过程中可能出现词库外的词语。)


  2、 随机初始化,在模型训练过程中作为一个可训练的参数参与梯度优化,这样在模型训练完成之时词向量也会随之生成。

word embedding代码:

  1. class Embeddings(nn.Module):
  2. def __init__(self, d_model, vocab):
  3. """
  4. :param d_model: word embedding维度
  5. :param vocab: 语料库词的数量
  6. """
  7. super(Embeddings, self).__init__()
  8. self.lut = nn.Embedding(vocab, d_model)
  9. self.d_model = d_model
  10. def forward(self, x):
  11. """
  12. :param x: 一个batch的输入,size = [batch, L], L为batch中最长句子长度
  13. """
  14. return self.lut(x) * math.sqrt(self.d_model) #这里乘了一个权重,不改变维度. size = [batch, L, d_model]

 d_model是此向量的维度,理论上输入以后就是个定值了,那么最后乘的权重math.sqrt(self.d_model)显然也是个常数。所有随机向量乘一个常数,相当于同时放缩,理论上不会有什么影响。

  Position Encoding两种方式:

  1、通过训练学习positional encoding 向量;
  2、编了个公式来计算positional encoding向量;

两种方式的结果是相似的,第二种,减少了训练参数,而且在训练集中没有出现过的句子长度上也能用

pos表示单词在句子中的绝对位置,pos=0,1,2…,

例如:Jerry在"Tom chase Jerry"中的pos=2;

dmodel表示词向量的维度,在这里dmodel=512;

2i和2i+1表示奇偶性,i表示词向量中的第几维,例如这里dmodel=512,故i=0,1,2…255。

  1. class PositionalEncoding(nn.Module):
  2. def __init__(self, d_model, dropout, max_len=5000):
  3. """
  4. :param d_model: pe编码维度,一般与word embedding相同,方便相加
  5. :param dropout: dorp out
  6. :param max_len: 语料库中最长句子的长度,即word embedding中的L
  7. """
  8. super(PositionalEncoding, self).__init__()
  9. # 定义drop out
  10. self.dropout = nn.Dropout(p=dropout)
  11. # 计算pe编码
  12. pe = torch.zeros(max_len, d_model) # 建立空表,每行代表一个词的位置,每列代表一个编码位
  13. position = torch.arange(0, max_len).unsqueeze(1) # 建个arrange表示词的位置以便公式计算,size=(max_len,1)
  14. #torch.arange(start=1.0,end=6.0)和range区别,arrange生成浮点数值为start~end的数组但不包括end
  15. #unsqueeze(i)压缩,增加维数,在第i+1个维度上再加一维
  16. div_term = torch.exp(torch.arange(0, d_model, 2) * # 计算公式中10000**(2i/d_model)
  17. -(math.log(10000.0) / d_model))
  18. pe[:, 0::2] = torch.sin(position * div_term) # 计算偶数维度的pe值
  19. pe[:, 1::2] = torch.cos(position * div_term) # 计算奇数维度的pe值
  20. pe = pe.unsqueeze(0) # size=(1, L, d_model),为了后续与word_embedding相加,意为batch维度下的操作相同
  21. self.register_buffer('pe', pe) # pe值是不参加训练的
  22. def forward(self, x):
  23. # 输入的最终编码 = word_embedding + positional_embedding
  24. x = x + Variable(self.pe[:, :x.size(1)],requires_grad=False) #size = [batch, L, d_model]
  25. return self.dropout(x) # size = [batch, L, d_model]

前馈神经网络Feed-Forward Networks

全连接层公式如下:
FFN(x)=max(0,xW_1+b_1)W_2+b_2

这里的全连接层是一个两层的神经网络,先线性变换,然后ReLU非线性,再线性变换。


残差神经网络ResNet

为什么深度神经网络会发生退化?
举个例子:

假如某个神经网络的最优网络层数是18层,本着层数越深越好的理念,我们设计了32层,多余的14层网络必须进行恒等映射,恒等映射的意思就是说,输入什么,输出就是什么,可以理解成F(x)=x这样的函数,
但现实是神经网络的参数都是训练出来地,要想保证训练出来地参数能够很精确的完成F(x)=x的恒等映射其实是很困难

在这里插入图片描述

F(X)为残差,X为输入值,

F(X)是经过第一层线性变化并激活后的输出,

第二层进行线性变化之后激活之前,F(X)加入了这一层输入值X,然后再进行激活后输出。

在第二层输出值激活前加入X,这条路径称作shortcut连接。

恒等映射的函数h(X)=F(X)+X,我们要让h(X)=X,只需要让F(X)=0就可以了

神经网络通过训练变成0是比变成X容易很多地,

一般初始化神经网络的参数的时候就是设置的[0,1]之间的随机数嘛。所以经过网络变换后很容易接近于0。

Normalize

 为什么使用Layer Normalization(LN)而不使用Batch Normalization(BN)

LN是在同一个样本中不同神经元之间进行归一化,而BN是在同一个batch中不同样本之间的同一位置的神经元之间进行归一化。
BN是对于相同的维度进行归一化 

Transformer Decoder的输入

Decoder的输入分为两类:
一种是训练时的输入,

例如翻译任务,Encoder输入"Tom chase Jerry",Decoder输入"汤姆追逐杰瑞"。

一种是预测时的输入。
开始输入的是起始符,然后每次输入是上一时刻Transformer的输出。例如,

输入"",输出"汤姆",

输入"汤姆",输出"汤姆追逐",

输入"汤姆追逐",输出"汤姆追逐杰瑞",

输入"汤姆追逐杰瑞",输出"汤姆追逐杰瑞"结束。

Masked Multi-Head Attention

与Encoder的Multi-Head Attention计算原理一样,只是多加了一个mask码。mask 表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。

1.padding mask
每个批次输入序列长度是,要对输入序列进行对齐。

在较短的序列后面填充 0。

输入的序列太长,则是截取左边的内容,把多余的直接舍弃。

把填充位置的值加上一个非常大的负数(负无穷),这样的话,经过 softmax,这些位置的概率就会接近0!attention就不会关注

2.sequence mask
sequence mask 是为了使得 decoder 不能看见未来的信息。

训练的时候每次是将target数据完整输入进decoder中地,

预测的时候只能得到前一时刻预测出的输出。

产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上

Encoder中只需要padding mask即可,而Decoder中需要padding mask和sequence mask。

基于Encoder-Decoder 的Multi-Head Attention


Encoder中的Multi-Head Attention是基于Self-Attention

Decoder中的第二个Multi-Head Attention就只是基于Attention,它的输入Quer来自于Masked Multi-Head Attention的输出,

Keys和Values来自于Encoder中最后一层的输出。
第一个Masked Multi-Head Attention是为了得到之前已经预测输出的信息,相当于记录当前时刻的输入之间的信息的意思。

第二个Multi-Head Attention是为了通过当前输入的信息得到下一时刻的信息,也就是输出的信息,是为了表示当前的输入与经过encoder提取过的特征向量之间的关系来预测输出。
 

Softmax得到输出的概率分布,然后通过词典,输出概率最大的对应的单词作为我们的预测输出。

 参考:

深入理解transformer源码_了不起的赵队的博客-CSDN博客_transformer源码
图解Transformer(完整版)_龙心尘的博客-CSDN博客_transformer

史上最小白之Transformer详解_Stink1995的博客-CSDN博客_transformer神经网络

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/345659
推荐阅读
相关标签
  

闽ICP备14008679号