赞
踩
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是让某些神经元失效。举个例子:
总结:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。