Transformer的输入部分解析

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

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

#定义Embeddings类来实现文本嵌入层,这里s说明代表两个一模一样的嵌入层,他们共享参数.
class Embeddings(nn.Module):
     #"""类的初始化函数,有两个参数. d _model:指词嵌入的维度, vocab:指词表的大小. """
    def __init__(self, d_model, vocab):   
        
         #接着就是使用super的方式指明继承nn.Module的初始化函数,我们自己实现的所有层都会这样去
        super(Embeddings,self).__init__()

        #调用nn中预定义层Embeddings,获得一个词嵌入对象self.lut
        self.lut = nn.Embedding(vocab, d_model)

        #最后将d_model传入类中
        self.d_model = d_model
        
    """可以将其理解为该层的前向传播逻辑,所有层中都会有此函数当传给该类的实例化对象参数时,自动调用该类函数
    参数x︰因为Embedding层是首层,所以代表输入给模型的文本通过词汇映射后的张量"""
    def forward(self, x):
        
        #将x传给self. lut并与根号下self.d_model相乘作为结果返回
        return self.lut(x) * math.sqrt(self.d_model)

d_model = 512
vocab = 1000
x=Variable(torch.LongTensor([[100,2,421,508],[491,998,1,221]]))
emb =Embeddings(d_model, vocab)
emb1 = emb(x)
print(emb1)
print(emb1.shape)

结果: 

 2.位置编码器

 

#定义位置编码器类,我们同样把它看做一个层,因此会继承nn.Module
class PositionalEncoding(nn.Module):
    """"位置编码器类的初始化函数,共有三个参数,分别是
        d_model:词嵌入维度,
        dropout:置0比率,
        max_len:每个句子的最大长度"""
    
    def __init__(self,d_model, dropout, max_len=5000):
        super(PositionalEncoding, self).__init__()
        
        #实例化nn中预定义的Dropout层,并将dropout传入其中,获得对象self.dropout
        self.dropout = nn.Dropout(p=dropout)
        
        #初始化一个位置编码矩阵,它是一个0阵,矩阵的大小是max_len ,d_model.
        pe= torch.zeros(max_len, d_model)
        
        #初始化一个绝对位置矩阵,在我们这里,词汇的绝对位置就是用它的索引去表示.
        #所以我们首先使用arange方法获得一个连续自然数向量,然后再使用unsqueeze方法拓展向量维度
        #又因为参数传的是1,代表矩阵拓展的位置,会使向量变成一个(max_len x 1) 的矩阵,
        #由[0,1,2...max_len]-> [[0],[1]...[max_len]]
        ##目的是要把position的信息放到pe里面去
        position = torch.arange(0, max_len).unsqueeze(1)
        
         #定义一个变换矩阵使得position的[max_len,1]*变换矩阵得到pe[max_len,d_model]->变换矩阵格式[1,d_model]
        #除以这个是为了加快收敛速度
        #div_term格式是[0,1,2...d_model/2],分成了两个部分,步长为2
        div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(1000.0) / d_model))
        
        
        pe[:,0::2] = torch.sin(position * div_term)   #偶数位置
        pe[:,1::2] = torch.sin(position * div_term)   #奇数位置
        
        #此时pe[max_len,d_model]
        #embedding三维(可以是[batch_size,vocab,d_model]),vocab就是max_len
        #将pe升起一个维度扩充成三维张量
        pe=pe.unsqueeze(0)
        
        #位置编码矩阵注册成模型的buffer,它不是模型中的参数,不会跟随优化器进行优化
        #注册成buffer后我们就可以在模型的保存和加载时,将这个位置编码器和模型参数加载进来
        self.register_buffer('pe',pe)
        
    def forward(self, x):

       # x代表文本序列的词嵌入向量
        #pe编码过长将第二个维度也就是max_len的维度缩小成句子的长度
        x = x + Variable(self.pe[:,:x.size(1)],requires_grad = False)
        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是让某些神经元失效。举个例子:

 总结:

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值