#Datawhale AI 夏令营 task3笔记

transformer模型简介

ansformer的主要组件包括编码器(Encoder)、解码器(Decoder)和注意力层。其核心是利用多头自注意力机制(Multi-Head Self-Attention),使每个位置的表示不仅依赖于当前位置,还能够直接获取其他位置的表示。自从提出以来,Transformer模型在机器翻译、文本生成等自然语言处理任务中均取得了突破性进展,成为NLP领域新的主流模型。以下是我总结的 Transformer 模型的一些关键特点和组成部分:

1. Seq2Seq架构和注意力机制

  • Seq2Seq架构:Seq2Seq是一种编码器-解码器架构,广泛应用于机器翻译等序列到序列的任务。编码器负责将输入序列编码成一个固定长度的向量,解码器则根据这个向量生成输出序列。
  • 注意力机制:为了解决Seq2Seq模型在处理长距离依赖时的局限性,引入了注意力机制。注意力机制允许模型在生成输出时,动态地关注输入序列中的不同部分,从而提高翻译的准确性。

3. 关键模块

  • 位置编码:由于Transformer模型不使用循环或卷积结构,为了使模型能够理解单词在序列中的位置,引入了位置编码。位置编码通常使用正弦和余弦函数的组合来生成,并将这些编码与词嵌入向量相加。                                                                                             1.位置编码的引入:在将词嵌入送入编码器之前,需要加入位置编码。这使得模型能够理解单词在序列中的位置关系。                                                                                         2.计算方法:位置编码使用正弦和余弦函数的不同频率来生成,具体公式如下: 
  • 多头注意力机制:Transformer通过多头注意力机制,允许模型在不同的表示子空间中同时捕捉信息。这增强了模型的表达能力,并允许它从不同的角度理解输入数据。
  • 残差网络:Transformer模型中的每个子层都使用残差连接,这有助于在深层网络中更好地传播信息,并减少梯度消失的问题。
  • 层标准化:在每个子层之后进行层标准化,有助于稳定训练过程,加快收敛速度。

4. 传统方法的局限性

  • 卷积神经网络:卷积神经网络在处理长文本时存在局限性,因为其受限的上下文窗口无法覆盖整个序列。为了描述长距离依赖,需要多层卷积操作,这可能导致信息传递的损失。
  • 循环神经网络:循环神经网络通过维护循环单元中的隐状态来处理序列数据。然而,随着序列长度的增加,早期的上下文信息可能会逐渐被遗忘。尽管注意力机制在一定程度上缓解了这个问题,但循环网络在编码效率方面仍存在不足。

5. Transformer的优势

  • 并行处理:Transformer模型通过并行处理整个序列,提高了训练和推断的效率。这与传统的循环神经网络形成对比,后者需要逐个处理序列中的每个元素。
  • 长距离依赖:Transformer的自注意力机制使得模型能够捕捉序列内部的长距离依赖关系,这对于机器翻译等任务至关重要。

6. 应用

  • 机器翻译任务:文章鼓励读者基于Transformer模型实现机器翻译任务。通过了解Transformer的关键组件和工作原理,读者可以更好地应用这一模型来解决实际的翻译问题。

数据预处理

# 定义tokenizer
en_tokenizer = get_tokenizer('spacy', language='en_core_web_trf')
zh_tokenizer = lambda x: list(jieba.cut(x))  # 使用jieba分词

# 读取数据函数
def read_data(file_path: str) -> List[str]:
    with open(file_path, 'r', encoding='utf-8') as f:
        return [line.strip() for line in f]

# 数据预处理函数
def preprocess_data(en_data: List[str], zh_data: List[str]) -> List[Tuple[List[str], List[str]]]:
    processed_data = []
    for en, zh in zip(en_data, zh_data):
        en_tokens = en_tokenizer(en.lower())[:MAX_LENGTH]
        zh_tokens = zh_tokenizer(zh)[:MAX_LENGTH]
        if en_tokens and zh_tokens:  # 确保两个序列都不为空
            processed_data.append((en_tokens, zh_tokens))
    return processed_data

# 构建词汇表
def build_vocab(data: List[Tuple[List[str], List[str]]]):
    en_vocab = build_vocab_from_iterator(
        (en for en, _ in data),
        specials=['<unk>', '<pad>', '<bos>', '<eos>']
    )
    zh_vocab = build_vocab_from_iterator(
        (zh for _, zh in data),
        specials=['<unk>', '<pad>', '<bos>', '<eos>']
    )
    en_vocab.set_default_index(en_vocab['<unk>'])
    zh_vocab.set_default_index(zh_vocab['<unk>'])
    return en_vocab, zh_vocab

模型构建

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)

训练函数

def train(model, iterator, optimizer, criterion, clip):
    model.train()
    epoch_loss = 0
    
    for i, batch in enumerate(iterator):
        src, tgt = batch
        if src.numel() == 0 or tgt.numel() == 0:
            continue
        
        src, tgt = src.to(DEVICE), tgt.to(DEVICE)
        
        optimizer.zero_grad()
        output = model(src, tgt[:, :-1])
        
        output_dim = output.shape[-1]
        output = output.contiguous().view(-1, output_dim)
        tgt = tgt[:, 1:].contiguous().view(-1)
        
        loss = criterion(output, tgt)
        loss.backward()
        
        clip_grad_norm_(model.parameters(), clip)
        optimizer.step()
        
        epoch_loss += loss.item()

    return epoch_loss / len(iterator)

def evaluate(model, iterator, criterion):
    model.eval()
    epoch_loss = 0
    with torch.no_grad():
        for i, batch in enumerate(iterator):
            src, tgt = batch
            if src.numel() == 0 or tgt.numel() == 0:
                continue
            
            src, tgt = src.to(DEVICE), tgt.to(DEVICE)
            
            output = model(src, tgt[:, :-1])
            
            output_dim = output.shape[-1]
            output = output.contiguous().view(-1, output_dim)
            tgt = tgt[:, 1:].contiguous().view(-1)
            
            loss = criterion(output, tgt)
            epoch_loss += loss.item()
        
    return epoch_loss / len(iterator)

#Datawhale AI 夏令营 

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值