Datawhale AI夏令营 Task3 基于Transformer解决机器翻译任务

Transformer架构

        Transformer是一种由Vaswani等人在2017年提出的神经网络架构,最初用于机器翻译任务,但现在已广泛应用于各种自然语言处理(NLP)任务,如文本生成、问答系统和文本分类等。与传统的循环神经网络(RNN)和长短期记忆(LSTM)网络不同,Transformer完全基于注意力机制,不使用任何循环或卷积操作,这使得它在处理长距离依赖关系时更为高效。

        Transformer模型主要由编码器(Encoder)和解码器(Decoder)两个部分组成,每个部分又由多个堆叠的相同层(Layers)构成。

编码器(Encoder)

        编码器的每一层包含两个子层:  

  1.         多头自注意力机制(Multi-Head Self-Attention Mechanism)
    • 输入的一组向量通过多个不同的注意力头进行计算,每个头独立地关注不同的上下文部分。
    • 这些多个注意力头的输出被连接起来,再通过线性变换得到最终的输出。
  2.         位置前馈网络(Position-wise Feed-Forward Network)
    • 一个简单的全连接前馈网络,应用于每个位置的向量。
    • 后接ReLU激活函数和另一个线性变换。

注意力机制(Attention Mechanism)

        注意力机制是Transformer的核心组件,用于计算输入序列中不同词之间的相关性。具体步骤如下:

  1. 计算Query、Key和Value
    • 对输入向量进行线性变换得到查询(Q)、键(K)和值(V)向量。
  2. 计算注意力权重
    • 通过点积计算查询向量与键向量之间的相似性,并应用缩放因子和softmax函数得到注意力权重。
  3. 加权求和得到输出
    • 使用注意力权重对值向量进行加权求和,得到最终的注意力输出。

多头注意力(Multi-Head Attention)

        多头注意力机制通过并行多个独立的注意力头来扩展模型的能力,使其能够在不同的子空间中关注不同的上下文信息。每个头独立计算注意力,然后将所有头的输出连接在一起,再进行线性变换。

优点

  • 并行计算:由于没有循环操作,Transformer可以并行处理输入序列中的所有词,极大地提高了计算效率。
  • 捕捉长距离依赖:注意力机制使得模型能够有效捕捉输入序列中的长距离依赖关系。
  • 灵活性强:可以用于多种NLP任务,并在许多任务上取得了显著的效果。

应用

Transformer模型已经成为NLP领域的标准架构,并被广泛应用于以下任务:

  • 机器翻译(如Google的翻译系统)
  • 文本生成(如GPT系列模型)
  • 问答系统(如BERT)
  • 文本分类(如RoBERTa)
  • 信息抽取(如T5)

代码解析

         以Task2给出的代码为基础,主要修改模型构建部分:

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, dropout=0.1, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=dropout)

        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer('pe', pe)

    def forward(self, x):
        x = x + self.pe[:x.size(0), :]
        return self.dropout(x)

class TransformerModel(nn.Module):
    def __init__(self, src_vocab, tgt_vocab, d_model, nhead, num_encoder_layers, num_decoder_layers, dim_feedforward, dropout):
        super(TransformerModel, self).__init__()
        self.transformer = nn.Transformer(d_model, nhead, num_encoder_layers, num_decoder_layers, dim_feedforward, dropout)
        self.src_embedding = nn.Embedding(len(src_vocab), d_model)
        self.tgt_embedding = nn.Embedding(len(tgt_vocab), d_model)
        self.positional_encoding = PositionalEncoding(d_model, dropout)
        self.fc_out = nn.Linear(d_model, len(tgt_vocab))
        self.src_vocab = src_vocab
        self.tgt_vocab = tgt_vocab
        self.d_model = d_model

    def forward(self, src, tgt):
        # 调整src和tgt的维度
        src = src.transpose(0, 1)  # (seq_len, batch_size)
        tgt = tgt.transpose(0, 1)  # (seq_len, batch_size)

        src_mask = self.transformer.generate_square_subsequent_mask(src.size(0)).to(src.device)
        tgt_mask = self.transformer.generate_square_subsequent_mask(tgt.size(0)).to(tgt.device)

        src_padding_mask = (src == self.src_vocab['<pad>']).transpose(0, 1)
        tgt_padding_mask = (tgt == self.tgt_vocab['<pad>']).transpose(0, 1)

        src_embedded = self.positional_encoding(self.src_embedding(src) * math.sqrt(self.d_model))
        tgt_embedded = self.positional_encoding(self.tgt_embedding(tgt) * math.sqrt(self.d_model))

        output = self.transformer(src_embedded, tgt_embedded,
                                  src_mask, tgt_mask, None, src_padding_mask, tgt_padding_mask, src_padding_mask)
        return self.fc_out(output).transpose(0, 1)

这段代码实现了一个基于Transformer模型的序列到序列(sequence-to-sequence)模型,用于例如机器翻译任务。代码主要包括两个类:PositionalEncodingTransformerModel

PositionalEncoding类

PositionalEncoding类实现了位置编码,用于向输入的词向量添加位置信息,使模型能够感知序列中每个词的位置。具体来说:

  • __init__方法:

    • d_model:模型的维度。
    • dropout:应用于位置编码后的dropout概率。
    • max_len:预计算的位置编码的最大长度。
    • 通过计算位置编码矩阵pe,并保存它以供后续使用。
    • register_buffer用于保存pe,这样在模型保存和加载时可以自动处理这个参数。
  • forward方法:

    • 输入x:形状为(seq_len, batch_size, d_model)的张量。
    • 将位置编码添加到输入x上并应用dropout。

TransformerModel类

TransformerModel类实现了一个基于PyTorch的完整Transformer模型结构,包括词嵌入层、位置编码层、Transformer编码器-解码器及输出层。

  • __init__方法:

    • 初始化各种层,包括词嵌入层、位置编码层、Transformer层和最终的全连接层。
    • src_vocabtgt_vocab是源语言和目标语言的词汇表,用于词嵌入的初始化。
    • d_model:词嵌入和模型的维度。
    • nhead:多头注意力机制中的头数。
    • num_encoder_layersnum_decoder_layers:编码器和解码器的层数。
    • dim_feedforward:前馈神经网络的维度。
    • dropout:dropout概率。
  • forward方法:

    • 输入srctgt:源语言和目标语言的输入序列,形状为(batch_size, seq_len)。
    • 调整srctgt的维度,变为(seq_len, batch_size)以符合Transformer输入要求。
    • 生成源和目标序列的自注意力mask(掩码)。
    • 生成源和目标序列的padding mask,避免在计算中考虑填充位置。
    • 对源和目标序列进行词嵌入并添加位置编码。
    • 通过Transformer层计算输出。
    • 通过全连接层将模型输出转换为目标词汇表的大小。

代码流程

  1. 位置编码(PositionalEncoding):为输入序列添加位置信息。
  2. 词嵌入(Embedding):将输入序列的索引转换为词向量。
  3. Transformer层:通过多头注意力机制和前馈神经网络层处理输入序列。
  4. 全连接层(fc_out):将Transformer的输出转换为目标词汇表的概率分布。
  5. 掩码(Masking):应用于自注意力机制中,避免在计算中考虑填充位置。

 运行结果

        在魔搭平台运行代码,并将得到的submit_task3.txt文件提交至讯飞平台,分数相比于task1的0.6571分已经有了很大的提升,达到了11.5902分

提分技巧

调参

  • 修改N的大小,使用全部训练集;
  • 修改N_EPOCHS大小,适当增大训练轮数。

加入术语词典

这是在此竞赛中比较有效的方法,加入术语词典的方法策略也有很多,如:

  • 模型生成的翻译输出中替换术语,这是最简单的方法
  • 整合到数据预处理流程,确保它们在翻译中保持一致
  • 在模型内部动态地调整术语的嵌入,这涉及到在模型中加入一个额外的层,该层负责查找术语词典中的术语,并为其生成专门的嵌入向量,然后将这些向量与常规的词嵌入结合使用

数据清洗

        将训练集中的脏数据手动清除,或使用正则匹配等方式清除。

数据扩增

  • 回译(back-translation):将源语言文本先翻译成目标语言,再将目标语言文本翻译回源语言,生成的新文本作为额外的训练数据

  • 同义词替换:随机选择句子中的词,并用其同义词替换

  • 使用句法分析和语义解析技术重新表述句子,保持原意不变

  • 将文本翻译成多种语言后再翻译回原语言,以获得多样化翻译

采用更精细的学习率调度策略

  • Noam Scheduler:结合了warmup(预热)阶段和衰减阶段

  • Step Decay:最简单的一种学习率衰减策略,每隔一定数量的epoch,学习率按固定比例衰减

  • Cosine Annealing:学习率随周期性变化,通常从初始值下降到接近零,然后再逐渐上升

 

 

 

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值