1、编码器
class TranslationEncoder(nn.Module): def __init__(self,vocab_size,padding_index): super().__init__() self.embedding = nn.Embedding(vocab_size, config.EMBEDDING_DIM,padding_idx=padding_index) self.gru = nn.GRU(config.EMBEDDING_DIM, config.ENCODER_HIDDEN_SIZE, num_layers=config.ENCODER_LAYERS, batch_first=True, bidirectional=True) def forward(self, x, hidden=None): embed = self.embedding(x) output, hidden = self.gru(embed) # 第二层的hidden的反向最后一个隐藏状态 # 只包含从结尾到开头的信息 缺少前文对后文的上下文 last_hidden_backward = hidden[-1] # 第二层的hidden的前向最后一个隐藏状态 # 只包含从开头到结尾的信息 缺少后文对前文的上下文 last_hidden_forward = hidden[-2] # 两个独立的全局向量,它们分别掌握单向上下文,通过拼接`dim=-1`,就是将特征维度拼在一起,合并两套全局上下文。 context_vector = torch.cat([last_hidden_forward,last_hidden_backward],dim=-1) return context_vector(1)图形描述:
gru = torch.nn.GRU() output, h_n = gru(input, h_0)①单层双向:h_n[0]是正向的最后一个隐藏状态,h_n[1]是反向的最后一个隐藏状态
②双层双向:
h_n[0]是第一层的正向的最后一个隐藏状态,h_n[1]是第一层的反向的最后一个隐藏状态,h_n[-1]是第二层的反向的最后一个隐藏状态,h_n[-2]是第二层的正向的最后一个隐藏状态。
代码中的context_vector = torch.cat([last_hidden_forward,last_hidden_backward],dim=-1)是隐藏状态的拼接,为后面解码器做准备。
2、解码器
class TranslationDecoder(nn.Module): def __init__(self,vocab_size,padding_index): super().__init__() self.embedding = nn.Embedding(vocab_size, config.EMBEDDING_DIM, padding_idx=padding_index) self.gru = nn.GRU(config.EMBEDDING_DIM, config.DECODER_HIDDEN_SIZE, batch_first=True) self.linear = nn.Linear(config.DECODER_HIDDEN_SIZE, vocab_size) def forward(self, x, hidden_0): #x: (batch_size, 1) <sos> 一次只输入 1 个 token embed = self.embedding(x) #embed: (batch_size, 1, EMBEDDING_DIM) # hidden_0是编码器传过来的 output, hidden_n = self.gru(embed, hidden_0) #output: (batch_size, 1, DECODER_HIDDEN_SIZE) #hidden_n: (1, batch_size, DECODER_HIDDEN_SIZE) output = self.linear(output) #output: (batch_size, 1, vocab_size) return output, hidden_n