当前位置:   article > 正文

Transformer的输入部分解析

transformer的输入

 Transformer的输入部分进行了解,主要是文本嵌入层的代码分析和位置编码。

1.文本嵌入层的代码分析

  1. #定义Embeddings类来实现文本嵌入层,这里s说明代表两个一模一样的嵌入层,他们共享参数.
  2. class Embeddings(nn.Module):
  3. #"""类的初始化函数,有两个参数. d _model:指词嵌入的维度, vocab:指词表的大小. """
  4. def __init__(self, d_model, vocab):
  5. #接着就是使用super的方式指明继承nn.Module的初始化函数,我们自己实现的所有层都会这样去
  6. super(Embeddings,self).__init__()
  7. #调用nn中预定义层Embeddings,获得一个词嵌入对象self.lut
  8. self.lut = nn.Embedding(vocab, d_model)
  9. #最后将d_model传入类中
  10. self.d_model = d_model
  11. """可以将其理解为该层的前向传播逻辑,所有层中都会有此函数当传给该类的实例化对象参数时,自动调用该类函数
  12. 参数x︰因为Embedding层是首层,所以代表输入给模型的文本通过词汇映射后的张量"""
  13. def forward(self, x):
  14. #将x传给self. lut并与根号下self.d_model相乘作为结果返回
  15. return self.lut(x) * math.sqrt(self.d_model)
  16. d_model = 512
  17. vocab = 1000
  18. x=Variable(torch.LongTensor([[100,2,421,508],[491,998,1,221]]))
  19. emb =Embeddings(d_model, vocab)
  20. emb1 = emb(x)
  21. print(emb1)
  22. print(emb1.shape)

结果: 

 2.位置编码器

 

  1. #定义位置编码器类,我们同样把它看做一个层,因此会继承nn.Module
  2. class PositionalEncoding(nn.Module):
  3. """"位置编码器类的初始化函数,共有三个参数,分别是
  4. d_model:词嵌入维度,
  5. dropout:置0比率,
  6. max_len:每个句子的最大长度"""
  7. def __init__(self,d_model, dropout, max_len=5000):
  8. super(PositionalEncoding, self).__init__()
  9. #实例化nn中预定义的Dropout层,并将dropout传入其中,获得对象self.dropout
  10. self.dropout = nn.Dropout(p=dropout)
  11. #初始化一个位置编码矩阵,它是一个0阵,矩阵的大小是max_len ,d_model.
  12. pe= torch.zeros(max_len, d_model)
  13. #初始化一个绝对位置矩阵,在我们这里,词汇的绝对位置就是用它的索引去表示.
  14. #所以我们首先使用arange方法获得一个连续自然数向量,然后再使用unsqueeze方法拓展向量维度
  15. #又因为参数传的是1,代表矩阵拓展的位置,会使向量变成一个(max_len x 1) 的矩阵,
  16. #由[0,1,2...max_len]-> [[0],[1]...[max_len]]
  17. ##目的是要把position的信息放到pe里面去
  18. position = torch.arange(0, max_len).unsqueeze(1)
  19. #定义一个变换矩阵使得position的[max_len,1]*变换矩阵得到pe[max_len,d_model]->变换矩阵格式[1,d_model]
  20. #除以这个是为了加快收敛速度
  21. #div_term格式是[0,1,2...d_model/2],分成了两个部分,步长为2
  22. div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(1000.0) / d_model))
  23. pe[:,0::2] = torch.sin(position * div_term) #偶数位置
  24. pe[:,1::2] = torch.sin(position * div_term) #奇数位置
  25. #此时pe[max_len,d_model]
  26. #embedding三维(可以是[batch_size,vocab,d_model]),vocab就是max_len
  27. #将pe升起一个维度扩充成三维张量
  28. pe=pe.unsqueeze(0)
  29. #位置编码矩阵注册成模型的buffer,它不是模型中的参数,不会跟随优化器进行优化
  30. #注册成buffer后我们就可以在模型的保存和加载时,将这个位置编码器和模型参数加载进来
  31. self.register_buffer('pe',pe)
  32. def forward(self, x):
  33. # x代表文本序列的词嵌入向量
  34. #pe编码过长将第二个维度也就是max_len的维度缩小成句子的长度
  35. x = x + Variable(self.pe[:,:x.size(1)],requires_grad = False)
  36. return self.dropout(x)

pos表示单词在句子中的绝对位置,pos=0,1,2…,例如:Jerry在"Tom chase Jerry"中的pos=2;d_model表示词向量的维度,在这里dmodel=512;2i和2i+1表示奇偶性,i表示词向量中的第几维,例如这里dmodel=512,故i=0,1,2…255。

为什么是将positional encoding与词向量相加,而不是拼接呢?拼接相加都可以,只是本身词向量的维度512维就已经蛮大了,再拼接一个512维的位置向量,变成1024维,这样训练起来会相对慢一些,影响效率

dropout是让某些神经元失效。举个例子:

 总结:

 

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

闽ICP备14008679号