源代码仓库

惜哉剑气疏/programs_0https://gitee.com/zirui-shu/programs_0

前文提要

        本文在

注意力机制原理及代码详解_注意力代码-CSDN博客https://blog.csdn.net/h860818/article/details/155272148?spm=1001.2014.3001.5501

以及

我想拥有作家的思想 循环神经网络及变型-CSDN博客https://blog.csdn.net/h860818/article/details/155168011?spm=1001.2014.3001.5501

的前文基础上将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]

        对于每个转化而成的v而言,也就是:

"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矩阵大小:

h_size = [1, 1, 256]

        以及输出的语义向量c矩阵大小:

c_size = [1, 5, 256]

3.经历解码层

      由于MAX_LENGTH大于总的编码器句子个数,在此不需要对c进行裁剪。并且同编码层维度,隐藏状态矩阵维度:

s_size = [1, 1, 256]

        再做注意力操作部分。首先降维去掉QKbatch维度:

embedded[0], hidden[0]

        再按照词向量维度拼接QK的矩阵:

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)

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐