使用Transformer进行日中机器翻译的PyTorch教程

在本教程中,我们将使用PyTorch、Torchtext、SentencePiece以及Jupyter Notebook来构建一个日中机器翻译模型。我们将使用JParaCrawl数据集,这是由NTT创建的最大的公开可用英语-日语平行语料库,通过大量爬取网络并自动对齐平行句子而创建。

1. 导入所需包

首先,我们需要确保安装了所有必要的包。如果您发现某些包缺失,请确保安装它们。

import math
import torchtext
import torch
import torch.nn as nn
from torch import Tensor
from torch.nn.utils.rnn import pad_sequence
from torch.utils.data import DataLoader
from collections import Counter
from torchtext.vocab import Vocab
from torch.nn import TransformerEncoder, TransformerDecoder, TransformerEncoderLayer, TransformerDecoderLayer
import io
import time
import pandas as pd
import numpy as np
import pickle
import tqdm
import sentencepiece as spm
torch.manual_seed(0)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

2. 获取平行数据集

我们将使用从JParaCrawl下载的日语-英语平行数据集。数据集包含两个语言的句子对,它们由制表符分隔。

# 导入pandas库
import pandas as pd

# 使用pandas的read_csv函数读取文件
df = pd.read_csv('./zh-ja/zh-ja.bicleaner05.txt', sep='\\t', engine='python', header=None)

# 提取DataFrame的第二列的数据,并转换为列表
trainen = df[2].values.tolist()  # 提取并转换为列表

# 提取DataFrame的第三列的数据,并转换为列表
trainja = df[3].values.tolist()  # 提取并转换为列表

3. 数据预处理

为了使用Transformer模型,我们需要对数据进行预处理。这包括创建词汇表、向量化句子以及将数据分割为训练、验证和测试集。

3.1 创建词汇表

我们将为源语言和目标语言创建词汇表。

3.2 向量化句子

我们将使用SentencePiece将句子分割成子词,并将其转换为整数索引。

3.3 数据分割

我们将数据分割为训练、验证和测试集。

3.4 准备分词器

与英语或其他字母语言不同,日语句子中没有空白来分隔单词。我们可以使用JParaCrawl提供的SentencePiece分词器,该分词器用于分割日语和英语句子。

# 创建英文SentencePieceProcessor实例,加载英文模型
en_tokenizer = spm.SentencePieceProcessor(model_file='enja_spm_models/spm.en.nopretok.model')

# 创建日文SentencePieceProcessor实例,加载日文模型
ja_tokenizer = spm.SentencePieceProcessor(model_file='enja_spm_models/spm.ja.nopretok.model')

# 使用en_tokenizer实例将英文句子分割成子词单元
tokens_en = en_tokenizer.encode("All residents aged 20 to 59 years who live in Japan must enroll in public pension system.", out_type='str')

# 使用ja_tokenizer实例将日文句子分割成子词单元
tokens_ja = ja_tokenizer.encode("年金 日本に住んでいる20歳~60歳の全ての人は、公的年金制度に加

4. 构建词汇表和转换句子为张量

接下来,我们将使用SentencePiece分词器处理训练数据,并为日文和英文句子构建词汇表。

def build_vocab(sentences, tokenizer):
    """
    构建词汇表。
 Args:
        sentences (list): 句子列表
        tokenizer (SentencePieceProcessor): 用于分割句子的SentencePieceProcessor实例
    Returns:
        Vocab: 词汇表对象
    """
    # 初始化一个计数器,用于统计每个子词单元的出现次数
    counter = Counter()
    
    # 遍历句子列表,为每个句子分割子词单元,并更新计数器
    for sentence in sentences:
        counter.update(tokenizer.encode(sentence, out_type=str))
    
    # 构建词汇表,包括特殊符号
    return Vocab(counter, specials=['<unk>', '<pad>', '<bos>', '<eos>'])

# 使用ja_tokenizer实例处理训练数据,构建日文词汇表
ja_vocab = build_vocab(trainja, ja_tokenizer)

# 使用en_tokenizer实例处理训练数据,构建英文词汇表
en_vocab = build_vocab(trainen, en_tokenizer)

然后,我们将句子列表转换为张量列表,并创建DataLoader对象。

def data_process(ja, en):
    """
    将句子列表转换为张量列表。
    
    Args:
        ja (list): 日文句子列表
        en (list): 英文句子列表
    Returns:
        list: 张量列表,每个张量代表一个句子
    """
    # 初始化一个空列表,用于存储张量列表
    data = []
    
    # 遍历句子列表,为每个句子分割子词单元,并转换为张量
    for (raw_ja, raw_en) in zip(ja, en):
        # 使用ja_tokenizer实例分割日文句子,并转换为张量
        ja_tensor_ = torch.tensor([ja_vocab[token] for token in ja_tokenizer.encode(raw_ja.rstrip("\n"), out_type=str)],
                                dtype=torch.long)
        
        # 使用en_tokenizer实例分割英文句子,并转换为张量
        en_tensor_ = torch.tensor([en_vocab[token] for token in en_tokenizer.encode(raw_en.rstrip("\n"), out_type=str)],
                                dtype=torch.long)
        
        # 将分割后的张量添加到数据列表中
        data.append((ja_tensor_, en_tensor_))
    
    # 返回张量列表
    return data

# 使用data_process函数处理训练数据,并将结果存储在train_data变量中
train_data = data_process(trainja, trainen)

5. 构建Transformer模型

现在我们已经完成了数据的预处理,我们可以开始构建Transformer模型。

python

复制

# 定义一些超参数
SRC_VOCAB_SIZE = len(ja_vocab)  # 日文词汇表的大小
TGT_VOCAB_SIZE = len(en_vocab)  # 英文词汇表的大小
EMB_SIZE = 512                 # 嵌入大小
NHEAD = 8                     # 多头注意力头的数量
FFN_HID_DIM = 512            # 前馈网络的隐藏层大小
BATCH_SIZE = 16               # 批次大小
NUM_ENCODER_LAYERS = 3       # 编码器层的数量
NUM_DECODER_LAYERS = 3       # 解码器层的数量
NUM_EPOCHS = 16               # 训练周期数

# 创建一个Seq2SeqTransformer实例
transformer = Seq2SeqTransformer(NUM_ENCODER_LAYERS, NUM_DECODER_LAYERS,
                                 EMB_SIZE, SRC_VOCAB_SIZE, TGT_VOCAB_SIZE,
                                 FFN_HID_DIM)

# 初始化模型参数
for p in transformer.parameters():
    if p.dim() > 1:
        nn.init.xavier_uniform_(p)

# 将模型移动到指定的设备上
transformer = transformer.to(device)

# 定义损失函数
loss_fn = torch.nn.CrossEnt
    loss_fn = torch.nn.CrossEntropyLoss(ignore_index=PAD_IDX)

    # 创建优化器
    optimizer = torch.optim.Adam(
        transformer.parameters(), lr=0.0001, betas=(0.9, 0.98), eps=1e-9
    )

6. 训练模型

最后,我们将开始训练模型。

python

复制

# 导入tqdm库,用于可视化训练进度
from tqdm import tqdm

# 定义训练循环
for epoch in tqdm.tqdm(range(1, NUM_EPOCHS+1)):
    # 开始时间
    start_time = time.time()

    # 训练模型一个周期
    train_loss = train_epoch(transformer, train_iter, optimizer)

    # 结束时间
    end_time = time.time()

    # 打印当前周期数、训练损失和周期持续时间
    print((f"Epoch: {epoch}, Train loss: {train_loss:.3f}, "
           f"Epoch time = {(end_time - start_time):.3f}s"))

通过上述步骤,我们将构建一个使用Transformer的日中机器翻译模型,并使用JParaCrawl数据集进行训练和评估。这个模型虽然简单,但它展示了Transformer模型的基本原理,这些原理是现代机器翻译系统的基础。 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值