GRU 编码器-解码器架构注入注意力机制代码实现及流程详解
源代码仓库
惜哉剑气疏/programs_0
https://gitee.com/zirui-shu/programs_0
前文提要
本文在
以及
的前文基础上将RNN循环神经网络的变体GRU与注意力机制相结合,做一个编码器-解码器结构的机器翻译任务。
流程详解

接下来,我们首先模拟字典的构建以及数据清洗,以方便后续的流程说明:
english_word2index = {"SOS": 0, "EOS": 1, "i": 2, "am": 3, "a": 4, "student": 5}
french_word2index = {"SOS": 0, "EOS": 1, "je": 2, "suis": 3, "un": 4, "étudiant": 5}
以及一些必要的参数设置:
HIDDEN_SIZE = 256 也是词向量维度
MAX_LENGTH = 10 最大句子长度,对不同的句子数据集构建一个统一的模型规格
1.构建词嵌入层
在此取所有单词当作编码层的输入数据(含结束标识符):
input_data = ["I", "am", "a", "student", "EOS"]
input_indexs = [2, 3, 4, 5, 1]
对于每个转化而成的而言,也就是:
"i" (索引2) → [0.2, -0.5, 0.8, ..., 0.1] # 256维向量
"am" (索引3) → [0.7, 0.3, -0.1, ..., -0.4] # 256维向量
"a" (索引4) → [-0.2, 0.9, 0.6, ..., 0.2] # 256维向量
"student" (索引5) → [0.1, -0.8, 0.5, ..., 0.7] # 256维向量
"EOS" (索引1) → [0.0, 0.0, 0.0, ..., 0.0] # 256维向量
构建基础的词嵌入层,总的词向量矩阵维度:
input_dim = [1, 5, 256] #[批次,词数,词向量维度]
2.经历编码层
由词嵌入层的维度可知,隐藏状态矩阵大小:
h_size = [1, 1, 256]
以及输出的语义向量矩阵大小:
c_size = [1, 5, 256]
3.经历解码层
由于MAX_LENGTH大于总的编码器句子个数,在此不需要对进行裁剪。并且同编码层维度,隐藏状态矩阵维度:
s_size = [1, 1, 256]
再做注意力操作部分。首先降维去掉Q和K的batch维度:
embedded[0], hidden[0]
再按照词向量维度拼接Q和K的矩阵:
self.attn = nn.Linear(hidden_size * 2, self.max_length)
self.attn(torch.cat((embedded[0], hidden[0]), 1))
经过归一化得到权重向量矩阵:
# 维度[1, 10]
attn_weights = F.softmax(self.attn)
如:
attn_weights = [0.1, 0.3, 0.4, 0.15, 0.05, 0, 0, 0, 0, 0]
再进行加权求和:
# unsqueeze(0)补充batch维度
attn_applied = torch.bmm(attn_weights.unsqueeze(0), encoder_outputs.unsqueeze(0))
如:
attn_applied = 0.1×encode_output_c[0] + 0.3×encode_output_c[1] +
0.4×encode_output_c[2] + 0.15×encode_output_c[3] +
0.05×encode_output_c[4]
向量维度也就变成了:
attn_applied.size = [1, 256]
后面操作也就类似了:
self.attn_combine = nn.Linear(hidden_size * 2, hidden_size)
# 拼接
output = torch.cat((embedded[0], attn_applied[0]), 1)
# 升维
output = self.attn_combine(output).unsqueeze(0)
# 激活函数
output = F.relu(output)
[附]TeacherForcing快速收敛
teacher_forcing是一种在模型训练时帮助模型快速收敛减少训练周期的策略。正如其名【教师强制】,这种策略的具体实现方式是在模型训练时将模型的预测值直接修改成真实值,避免一错再错。类似于你学了计算机后你说1+1=10,但是数学老师告诉你1+1=2,不然以后做题全部没分,于是你只能记住1+1=2,以后也只用1+1=2,这就是TeacherFocing。
output_y, decode_hidden, attn_weight = my_attndecoderrnn(input_y, decode_hidden, encode_output_c)
target_y = y[0][idx].view(1)
myloss = myloss + mycrossentropyloss(output_y, target_y)
input_y = y[0][idx].view(1, -1)
更多推荐

所有评论(0)