admin管理员组

文章数量:1532440

任务目标

基于Transformer实现英语翻译汉语。如有疏忽请多指教

数据

Hi.	嗨。
Hi.	你好。
Run.	你用跑的。
Wait!	等等!
Hello!	你好。
I try.	让我来。
I won!	我赢了。
Oh no!	不会吧。
Cheers!	乾杯!
Got it?	你懂了吗?
He ran.	他跑了。
Hop in.	跳进来。
I lost.	我迷失了。
I quit.	我退出。
I'm OK.	我沒事。
Listen.	听着。
No way!	不可能!
No way!	没门!
Really?	你确定?
Try it.	试试吧。
We try.	我们来试试。
Why me?	为什么是我?
……     ……

代码&数据来源

Github:transformer-simple
哈弗NLP

Transformer模型结构

Transformer的组成
    1. Encoder
        a. 若干个EncoderLayer(两个子层)
            i. Feed Forward Neural Network
            connected layer.子层间使用Add & Normalization 相连
            ii. Self-Attention
    2. Decoder
        a. 若干个DecoderLayer(三个子层)
            i. Feed Forward Neural Network
            connected layer.子层间使用Add & Normalization 相连
            ii. Encoder-Decoder-Attention,常规注意力机制
            connected layer.子层间使用Add & Normalization 相连
            iii. Self-Attention,自注意力机制

Batch and Masking

Mask策略一

一种就是普通的mask,就是自然语言处理中将某些字符(如标点符号,空格等)进行mask的操作

# 该部分与transformer实现有关
class Batch:
    """
    Batches and Masking
    "Object for holding a batch of data with mask during training." 在训练期间使用mask处理数据
    """
    def __init__(self, src, trg=None, pad=0):
        """
        构造函数
        @param src: 源数据
        @param trg: 目标数据
        @param pad: 需要mask掉的字符,默认为0
        一共有两种mask的方式:
        一种就是普通的mask,就是自然语言处理中将某些字符(如标点符号,空格等)进行mask的操作
        另一种就是对目标数据的mask,其原因是为了不让decoder在训练中看到后续的内容(即,我对于下一个字符的预测,只来源于前面的字符)
        对于src的mask就是第一种mask,而对于tgt的mask是第一种加第二种
        """
        # 将numpy.array转换为张量torch.tensor
        src = torch.from_numpy(src).to(args.device).long()
        trg = torch.from_numpy(trg).to(args.device).long()

        self.src = src
        # 此处pad=0,src向量均不为0(0表示UNK标识),src!=pad生成bool数组,且数组所有元素均为True
        # 此处为第一种mask策略
        self.src_mask = (src != pad).unsqueeze(-2) # unsqueeze()扩展维度,负数表示扩展的维度在倒数第n个位置
        if trg is not None:
            self.trg = trg[:, :-1]  # 截掉trg中每个句子最后一个字符<EOS>
            self.trg_y = trg[:, 1:]  # 截掉trg中每个句子第一个字符<BOS>
            self.trg_mask = self.make_std_mask(self.trg, pad)  # 对trg掩蔽
            self.ntokens = (self.trg_y != pad).data.sum()

    @staticmethod
    def make_std_mask(tgt, pad):
        """
        mask 目标数据
        "Create a mask to hide padding and future words." 翻译:创造一个mask来屏蔽补全词和字典外的词进行屏蔽
        @param tgt: 即构造函数中的trg,目标数据
        @param pad: 需要mask的字符,默认为0
        @return: 返回mask后的目标数据
        """
        # 此处为第一种mask策略
        tgt_mask = (tgt != pad).unsqueeze(-2)  # 由于没有0,此时布尔矩阵全为True
        # 此处为第二种mask策略,调用utils中的subsequent_mask方法得到上三角布尔矩阵
        # Variable()封装tensor,并存储tensor的梯度,与tgt_mask做与运算
        tgt_mask = tgt_mask & Variable(subsequent_mask(tgt.size(-1)).type_as(tgt_mask.data))
        return tgt_mask

Mask策略二

另一种就是对目标数据的mask,其原因是为了不让decoder在训练中看到后续的内容(即,我对于下一个字符的预测,只来源于前面的字符)

def subsequent_mask(size):
    """
    第二种mask策略
    "Mask out subsequent positions."
    @param size: 句子长度
    @return:
    """
    attn_shape = (1, size, size)
    # np.triu函数生成一个对角线位置上移一位的上三角矩阵(k=1代表按对角线方向上移),矩阵大小为attn_shape
    subsequent_mask = np.triu(np.ones(attn_shape), k=1).astype('uint8')
    return torch.from_numpy(subsequent_mask) == 0  # 返回布尔矩阵,subsequent_mask上三角矩阵中0的位置对应True

make_model

构造Transformer模型

def make_model(src_vocab, tgt_vocab, N = 6, d_model = 512, d_ff = 2048, h = 8, dropout = 0.1):
    """
    定义了一个接收超参数并生成完整模型的函数。
    @param src_vocab: 源数据字典长度
    @param tgt_vocab: 目标数据字典长度
    @param N: 层数layer
    @param d_model: 表征后的维度
    @param d_ff: FeedForward输出维度
    @param h: attention机制,head多头个数
    @param dropout:
    @return:
    """
    c = copy.deepcopy
    attn = MultiHeadedAttention(h, d_model).to(args.device)  # 多头注意力机制
    ff = PositionwiseFeedForward(d_model, d_ff, dropout).to(args.device)
    position = PositionalEncoding(d_model, dropout).to(args.device)  # 位置信息嵌入
    # model其实是Transformer的类
    model = Transformer(
        Encoder(EncoderLayer(d_model, c(attn), c(ff), dropout).to(args.device), N).to(args.device),
        Decoder

本文标签: 机器翻译详解实战代码英译汉