seq2seq中的embedding以及attention

Embedding的用法(以pytorch为例)

在seq2seq的模型中构造Decoder的时候用到了embedding。是将encoder的输出送到decoder中进行解码,当然这也用到了attention机制。
原本encoder输出的是每个单词对应的编号,比如说输出 1 5 28 19 四个编号 分别对应我爱中国,简单来说是将这4个编号用one-hot的形式作为decoder的输入,但是这样会使得维度特别大,维度诅咒。同时在训练的过程中,由于数据过于稀疏,网络学不到什么东西。
因此想到了一个办法,用embedding来解决这个问题。

import torch.nn as nn

embedding = nn.Embedding(output_size, hidden_size)  # 生成output_size个向量每个是hidden_size维
dropout = nn.Dropout(dropout_p)  # 防止过拟合,使得在前向传播的过程中,某些神经元随机不激活
embedded = self.embedding(input)  # 按照index取对应的向量 ,用这些随机生成的向量作为输入
embedded = self.dropout(embedded) # 输入Tensor,会随机对每个元素按照p的概率进行丢弃一些数据
# 如果p=1,那么丢弃完之后Tensor中的元素全部都是0,如果p=0,那么丢弃完之后Tensor值不变

这里的input就是encoder的输出,例如:[[1,2,3],[4,5,6]],相当于按照索引取出第1 2 3个向量作为一个list,接着取出4 5 6 个向量放到同一个list中,返回的形状是[ [ [ ] , [ ] , [ ] ] , [ [ ] , [ ] , [ ] ] ],最内层是embedding中的向量。
这里生成的向量默认是服从标准正态分布的。

attention

seq2seq中的embedding以及attention_第1张图片
以下描述和代码实现和上面这个图略有不同,但是大体思路是差不多的。
将encoder所有的时间步的输出以及decoder中的当前时间步的隐层输入cat到一起。之后用一个全连接层来进行一次线性变换,之后进行一次softmax。这里相当于是获得了atention的权重,之后让encoder的所有输出乘上对应的权重,这就完成了attention的过程。
然后又将乘完权重之后的encoder的输出和没有乘权重的encoder的输出进行concat,接着用一个全连接层将其变成合适的形状,之后扔到LSTM或者是GRU中进行训练。

以下是代码实现:

    def forward(self, input, hidden, encoder_outputs):
        # embedding:
        embedded = self.embedding(input)
        embedded = self.dropout(embedded)

        attn_weights = F.softmax(self.attn(torch.cat((embedded, hidden[0]), 1)), dim=1)
        attn_applied = torch.bmm(attn_weights.unsqueeze(1), encoder_outputs.permute(1, 0, 2))

        output = torch.cat((embedded, attn_applied.squeeze(1)), 1)
        output = self.attn_combine(output).unsqueeze(0)

        output = F.relu(output)
        output, hidden = self.gru(output, hidden)

        output = F.log_softmax(self.out(output[0]), dim=1)
        return output, hidden, attn_weights

你可能感兴趣的:(深度学习,人工智能,神经网络,pytorch)