翻译器训练
导入包
首先,导入我们需要的包
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')
# print(torch.cuda.get_device_name(0)) ## 如果你有GPU,请在你自己的电脑上尝试运行这一套代码
之后打印davice,查看自己的设备类型
笔者的设备为cuda,故之后的训练过程使用GPU进行,没有cuda的用cpu即可,只是训练过程比较慢
获取平行数据集
在本教程中,我们将使用从JParaCrawl下载的日语-英语平行数据集这个数据集被描述为由NTT创建的“最大的公开可用的英语-日语平行语料库”。它主要通过网络爬取和自动对齐平行句子来创建。
df = pd.read_csv('zh-ja.bicleaner05.txt', sep='\\t', engine='python', header=None)
# 从第 2 列(英文句子)中提取值,并转换为 Python 列表
trainen = df[2].values.tolist()
# 从第 3 列(日文句子)中提取值,并转换为 Python 列表
trainja = df[3].values.tolist()
# trainen.pop(5972)
# trainja.pop(5972)
代码从一个名为’zh-ja.bicleaner05.txt’的文件中读取数据,并将第2列(英文句子)和第3列(日文句子)分别提取为Python列表 trainen
和 trainja
。
导入所有的日语和其英语对应文本后,需要删除数据集中的最后一条数据,因为它存在缺失值。在训练集中,trainen和trainja两者的句子总数为5,973,071条。然而,为了方便学习,通常建议对数据进行抽样,并确保一切正常运行,然后再使用全部数据,以节省时间。
之后打印例句,查看数据的格式
# 打印第 501 行(索引从 0 开始)的英文句子
print(trainen[500])
# 打印第 501 行(索引从 0 开始)的日文句子
print(trainja[500])
打印出来的句子如下
准备分词器
与英语或其他语言不同,日语句子中不使用空格来分隔单词。我们可以使用由JParaCrawl提供的分词器,它使用了SentencePiece来处理日语和英语。您可以访问JParaCrawl网站下载它们
# 使用 SentencePieceProcessor 加载英文模型文件 'spm.en.nopretok.model',创建英文分词器
en_tokenizer = spm.SentencePieceProcessor(model_file='spm.en.nopretok.model')
# 使用 SentencePieceProcessor 加载日文模型文件 'spm.ja.nopretok.model',创建日文分词器
ja_tokenizer = spm.SentencePieceProcessor(model_file='spm.ja.nopretok.model')
使用分词器对英文句子“All residents aged 20 to 59 years who live in Japan must enroll in public pension system.”进行编码
en_tokenizer.encode("All residents aged 20 to 59 years who live in Japan must enroll in public pension system.", out_type='str')
查看分词结果
可以看到,英文句子中每个以空格为分隔符的单词都被划分开
对日文句子"年金 日本に住んでいる20歳~60歳の全ての人は、公的年金制度に加入しなければなりません。"进行同样的操作
ja_tokenizer.encode("年金 日本に住んでいる20歳~60歳の全ての人は、公的年金制度に加入しなければなりません。", out_type='str')
与英文单词不同的是,日文是以词或短语进行划分
从 TorchText 导入的 Vocab 对象 ,并把句子转化为Tensor张量
使用分词器和原始句子,我们接着构建从 TorchText 导入的 Vocab 对象。这个过程可能需要几秒或几分钟,具体取决于数据集的大小和计算能力。不同的分词器也会影响构建词汇表所需的时间。
# 定义一个函数 build_vocab,用于构建词汇表
def build_vocab(sentences, tokenizer):
counter = Counter() # 创建一个计数器对象,用于统计词频
for sentence in sentences:
# 对每个句子使用指定的分词器进