2019 CS224N Assignment 4: Neural Machine Translation with RNNs and Analyzing NMT Systems

Neural Machine Translation with RNNs

第四个assignment 搭建了一个NMT,与之前在课程中学到的是一样的,架构如下
在这里插入图片描述
完整代码见我的GitHub
环境搭建:

  • 由于下载很慢,没有成功,因此我选择了自己已有的环境(python 3.7 torch 1.4.0),根据 local_env.yml 文件,下载之前没有的库:docopt
  • 运行过程中,有assert判断torch版本,直接注释即可
  • 在nmt_model.py 文件中的 step 函数中,对得到的将pad位置的注意力分数改为负无穷,这句代码中使用了masked_fill_()函数的参数要求有所变化,我使用的torch版本中要求第一个参数为bool类型,将其改为e_t.data.masked_fill_(enc_masks.bool(), -float('inf'))

注:若检验程序未通过,可以看看输入的报错,然后打印计算过程中矩阵的维度,判断是否出错,大部分bug根据维度就能找到

(a) 识别出batch中最长的句子,并将其他句子pad成相同长度。

只需要遍历求出最长句子的长度,然后使用pad_token将其他句子padding成一样长即可

    max_len = max(len(sen) for sen in sents)
    for sen in sents:
        sents_padded.append(sen + [pad_token] * (max_len-len(sen)))

(b) 实现 model embeddings.py 中的 __init__
使用 nn.Embedding(vocab_len, embedding_size, pad_idx) 即可

        self.source = nn.Embedding(len(vocab.src), self.embed_size,src_pad_token_idx)
        self.target = nn.Embedding(len(vocab.tgt), self.embed_size,src_pad_token_idx)

下面就正式开始搭建NMT神经网络了

(c) 实现 nmt model.py 中的 __init__

        self.encoder = nn.LSTM(embed_size, self.hidden_size,dropout = self.dropout_rate,bidirectional=True)
        self.decoder = nn.LSTMCell(embed_size + self.hidden_size, self.hidden_size) #每个时间步的输入为上一时间步得到的o_(t-1)和本时间步的词嵌入输入
        self.h_projection = nn.Linear(self.hidden_size * 2, self.hidden_size,bias = False) #将encoder两个hidden拼接转化为decoder的初始hidden (2h,1)->(h,1)
        self.c_projection = nn.Linear(self.hidden_size*2, self.hidden_size,bias = False) #同h_projection
        self.att_projection = nn.Linear(self.hidden_size*2, self.hidden_size,bias = False) #multiplicative attention,将encoder每个时间步的输出(2h,1),转化为(h,1)
        self.combined_output_projection = nn.Linear(self.hidden_size*3, self.hidden_size,bias = False) #将u_t (batch_size,3h) 转化为 v_t(batch_size,h)
        self.target_vocab_projection = nn.Linear(self.hidden_size,len(vocab.tgt),bias = False)#将hidden(h,1)转化为(vocab,1)
        self.dropout = nn.Dropout(self.dropout_rate)
  • 参数看代码中注释,符号与pdf对应

(d) 实现nmt_model.py 中的 encode

        X = self.model_embeddings.source(source_padded) #获取源句子词嵌入
        X = pack_padded_sequence(X,source_lengths)  #相当于压缩
        enc_hiddens,(last_hidden,last_cell) = self.encoder(X) #encoder
        enc_hiddens = pad_packed_sequence(enc_hiddens,batch_first = True) #(b, src_len, h*2) #相当于解压,注意返回值为一个元组,我们需要第一个元素 
        init_decoder_hidden = self.h_projection(torch.cat((last_hidden[0],last_hidden[1]),dim = 1)) #拼接后转化
        init_decoder_cell = self.c_projection(torch.cat((last_cell[0],last_cell[1]),dim = 1)) #拼接后转化
        dec_init_state = (init_decoder_hidden,init_decoder_cell)
        ### END YOUR CODE

        return enc_hiddens[0], dec_init_state
  • 注意nn.LSTM的输出,pack_padded_sequence(),pad_packed_sequence()的使用
  • 通过检查
    在这里插入图片描述

(e) 实现nmt_model.py 的 decode

        enc_hiddens_proj = self.att_projection(enc_hiddens) #计算W_att * h_encoder,在step函数中用于计算注意力
        Y = self.model_embeddings.target(target_padded)  #target sentence
        for Y_t in torch.split(Y,1): 
            Y_t = torch.squeeze(Y_t, 0)
            Ybar_t = torch.cat((Y_t,o_prev),dim = 1) 
            dec_state,o_t,_ = self.step(Ybar_t, dec_state, enc_hiddens, enc_hiddens_proj, enc_masks)# see function step
            combined_outputs.append(o_t) #保存每个时间步的最终输出(hidden与encoder每个时间步加权 拼接)用于最后预测单词
            o_prev = o_t #
            
        combined_outputs = torch.stack(combined_outputs,dim = 0)
  • 按照代码中的提示写,需要理解一些函数的用法(split,cat,squeeze)
  • step是下一题的任务,这里将step当作api
  • 检查通过
    在这里插入图片描述
    (f) 实现step
        dec_state = self.decoder(Ybar_t,dec_state) #nn.LSTMcell的用法
        e_t = torch.bmm(enc_hiddens_proj,torch.unsqueeze(dec_state[0],dim = 2)) #batch矩阵乘法,计算注意力分数
        e_t = torch.squeeze(e_t,dim = 2)
      
        alpha_t = F.softmax(e_t,dim =1)  #计算注意力权值
        alpha_t = torch.unsqueeze(alpha_t,dim=1)
        a_t = torch.bmm(alpha_t, enc_hiddens) #encoder hidden的注意力加权
        a_t = torch.squeeze(a_t, dim=1)
        U_t = torch.cat((a_t,dec_state[0]),dim = 1)  
        V_t = self.combined_output_projection(U_t)
        O_t = self.dropout(torch.tanh(V_t)) #每个时间步最终的输出
  • 需要了解nn.LSTMcell的用法
  • 需要知道一些函数的用法:bmm,squeeze,unsqueeze,F.softmax
  • 根据代码中的提示一步一步写出即可,检查通过
    在这里插入图片描述

(g) step 函数中使用了 generate_sent masks() ,解释其构造的masks对注意力计算有什么影响,解释为什么这是必要的。

if enc_masks is not None:
	e_t.data.masked_fill_(enc_masks.bool(), -float('inf'))
  • 该masks长度与句子长度相同,此段代码是将得到的注意力分数中,相应masks位置为1,即原来是pad的位置置为负无穷。由此可知,在使用softmax计算注意力分布时,pad位置的权重将会变为0。
  • 注意力的作用就是根据一个查询向量来计算一组向量的加权值,而pad对问题解决机会没有帮助,因此要降低它们的权重,所以这是必要的

(h) 因为笔者使用的是windows,无法直接运行.sh,所以我这里直接查看run.sh文件,运行相关的命令。

  • 运行 python vocab.py --train-src=./en_es_data/train.es --train-tgt=./en_es_data/train.en vocab.json 产生vocab文件
  • 运行 python run.py train --train-src=./en_es_data/train.es --train-tgt=./en_es_data/train.en --dev-src=./en_es_data/dev.es --dev-tgt=./en_es_data/dev.en --vocab=vocab.json 进行本地训练
    训练部分过程如下
    在这里插入图片描述

(i) 由于笔者无在线的虚拟机来进行训练,因此这部分先放着。

(j) 三种计算注意力方式的优缺点

  • dot product attention e t , i = s t T h i e_{t,i} = s_t^Th_i et,i=stThi
    • 优点:计算简单,参数少,计算量少
    • 缺点:不够强大,可能对于注意力的捕获效果不太好
  • multiplicative attention e t , i = s t T W h i e_{t,i} = s_t^TWh_i et,i=stTWhi
    • 优点:对比第一种计算注意力的方式,增加了一个矩阵 W W W,让模型能够捕获更多信息
    • 缺点:计算比第一个复杂,在复杂情况下效果没后一个好。
  • additive attention e t , i = v T ( W 1 h i + W 2 s t ) e_{t,i} = v^T(W_1h_i+W_2s_t) et,i=vT(W1hi+W2st)
  • 优点:参数多,能够对复杂情况建模,捕获很多有用的信息
  • 缺点:计算比前两者复杂

Analyzing NMT Systems

(a) 确定错误类型,提供理由,如何改进
i . \mathrm{i.} i.specific linguistic construct
i i . \mathrm{ii.} ii. specific linguistic construct
i i i . \mathrm{iii.} iii. specific model limitations(We can’t know the unkonw word)
改进:未知词可能是专有名词,我们可以使用复制机制,直接复制过来
i v . \mathrm{iv.} iv. specific model limitations
v . \mathrm{v.} v. specific model limitations(the model may pay more attetion to the word ‘she’, so the result is “the women’s”)
v i . \mathrm{vi.} vi. specific model limitations(the model can’t distinguish the difference between French unit and American unit)
转载自:ZacBi’ github

(b)

(c) BLEU计算
在这里插入图片描述
i . \mathrm{i.} i.

  • c1:
    p 1 = 3 5 p1 = \frac{3}{5} p1=53 p 2 = 2 4 p2 = \frac{2}{4} p2=42, c = 5, r ∗ = 5 r^* = 5 r=5 B P = 1 BP = 1 BP=1
    B L E U = 1 × e x p ( 0.5 × log ⁡ 0.6 + 0.5 × log ⁡ 0.5 ) = e x p ( − 0.11092 + − 0.15051 ) = 0.7699 BLEU = 1 × exp(0.5×\log 0.6+0.5×\log 0.5) =exp(-0.11092+-0.15051)=0.7699 BLEU=1×exp(0.5×log0.6+0.5×log0.5)=exp(0.11092+0.15051)=0.7699
  • c2:
    p 1 = 4 5 p1 = \frac{4}{5} p1=54 p 2 = 2 4 p2 = \frac{2}{4} p2=42,c= 5, r ∗ = 5 r^* = 5 r=5 B P = 1 BP = 1 BP=1
    B L E U = 1 × e x p ( 0.5 × log ⁡ 0.8 + 0.5 × log ⁡ 0.5 ) = e x p ( − 0.04845 + − 0.15051 ) = 0.81958 BLEU = 1 × exp(0.5×\log 0.8+0.5×\log 0.5) =exp(-0.04845+-0.15051)=0.81958 BLEU=1×exp(0.5×log0.8+0.5×log0.5)=exp(0.04845+0.15051)=0.81958
  • 从BLEU来看,c2更好,在我看来也是c2好。

i i . \mathrm{ii.} ii.只基于r1计算,

  • c1:
    p 1 = 2 5 p1 = \frac{2}{5} p1=52 p 2 = 2 4 p2 = \frac{2}{4} p2=42, c = 5, r ∗ = 5 r^* = 5 r=5 B P = 1 BP = 1 BP=1
    B L E U = 1 × e x p ( 0.5 × log ⁡ 0.4 + 0.5 × log ⁡ 0.5 ) = e x p ( − 0.19897 + − 0.15051 ) = 0.7056 BLEU = 1 × exp(0.5×\log 0.4+0.5×\log 0.5) =exp(-0.19897+-0.15051)=0.7056 BLEU=1×exp(0.5×log0.4+0.5×log0.5)=exp(0.19897+0.15051)=0.7056
  • c2:
    p 1 = 2 5 p1 = \frac{2}{5} p1=52 p 2 = 1 4 p2 = \frac{1}{4} p2=41,c= 5, r ∗ = 5 r^* = 5 r=5 B P = 1 BP = 1 BP=1
    B L E U = 1 × e x p ( 0.5 × log ⁡ 0.4 + 0.5 × log ⁡ 0.25 ) = e x p ( − 0.19897 + − 0.30103 ) = 0.6065 BLEU = 1 × exp(0.5×\log 0.4+0.5×\log 0.25) =exp(-0.19897+-0.30103)=0.6065 BLEU=1×exp(0.5×log0.4+0.5×log0.25)=exp(0.19897+0.30103)=0.6065
  • c1的分数更高,我认为c1并不是一个好的翻译

i i i . \mathrm{iii.} iii.
我觉得只使用一个参考翻译会有很大的不确定性,就比如上面的例子,去掉r2使得c2的分数变低,如果去掉的是r1,那么c1的分数将会降低。因此较少的参考翻译会增加偶然性,我们知道,虽然一个句子有多种不同的说法,但其中有一些词或短语是相同的,一个好的翻译应该尽可能与这些词或短语overlap,因此较多的参考翻译对评价结果更有利。

i v . \mathrm{iv.} iv.

  • 优点:
    • 自动快速,一个好的自动评价方式对于一个任务有极大的促进作用
    • 在大规模的评测中,BLEU与人类评价近似线性相关。
  • 缺点:BLEU考察了备选翻译的忠实度和流利度
    • 而忠实度方面,没有考虑单词的不同形似,比如上面例子中 make 和 makes(是否可以用字符级别来弥补?),此外还未考虑近义词之间的相似
    • 需要较多的参考翻译,不然会出现上面的例子
    • 不考虑语义和句法

总结

  • 本次实验学习如何使用Pytorch搭建一个神经网络
  • 学习了很多常用的函数
    • 维度相关:squeeze,unsqueeze,view,cat,split,bmm,stack
    • 网络单元:nn.LSTM、nn.LSTMcell、nn.Embedding、pack_padded_sequence、pad_packed_sequence、nn.Linear
  • 学习了带有multiplicative attention的seq2seq 机器翻译模型
    • seq2seq 的构建方式:encoder,decoder如何写
    • attention 如何计算(带有batch)–>使用bmm函数
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值