机器翻译数据集¶
Note
机器翻译指的是将序列从一种语言自动翻译成另一种语言。
本节我们将使用Tatoeba项目的英-法句子对生成机器翻译数据集。
读取数据¶
import torch
import d2l
#@save
def read_data_nmt():
"""读取英-法数据集"""
# 读取整个文件
text = open("../data/fra.txt").read()
# 使用空格替换不间断空格、大写字母转小写
text = text.replace('\u202f', ' ').replace('\xa0', ' ').lower()
# 把标点符号和单词分开
out = [' ' + char if i > 0 and (char in set(',.!?') and text[i - 1] != ' ') else char
for i, char in enumerate(text)]
return ''.join(out)
Tokenize¶
#@save
def tokenize_nmt(text, num_examples=None):
"""Tokenize英-法数据集"""
source, target = [], []
for i, line in enumerate(text.split('\n')):
# 保留前num_examples个句子对,可以作为测试集
if num_examples and i > num_examples:
break
# 以\t分隔同一行中的英语和法语
parts = line.split('\t')
if len(parts) == 2:
# tokenize为一个个单词,得到List[List[str]]
source.append(parts[0].split(' '))
target.append(parts[1].split(' '))
return source, target
Tokens转化为数字索引¶
#@save
def truncate_pad(line, num_steps, padding_token):
# 通过截断或填充使得每个句子的长度都是num_steps
if len(line) >= num_steps:
return line[: num_steps]
return line + [padding_token] * (num_steps - len(line))
#@save
def build_array_nmt(lines, vocab, num_steps):
"""tokens转化为数字索引,且通过截断或填充使每个句子长度都一样"""
# <eos>标明句子结束
lines = [vocab[l] + [vocab['<eos>']] for l in lines]
# 截断或填充
array = torch.tensor([truncate_pad(l, num_steps, vocab['<pad>']) for l in lines])
# 标明哪些token是<pad>
valid_len = (array != vocab['<pad>']).type(torch.int32).sum(1)
return array, valid_len
合起来¶
#@save
def load_data_nmt(batch_size, num_steps, num_examples=600):
"""读取英-法数据集、英语词汇表、法语词汇表"""
# 读取数据并tokenize
text = read_data_nmt()
source, target = tokenize_nmt(text, num_examples)
# 分别建立英、法词汇表
src_vocab = d2l.Vocab(source, min_freq=2,
reserved_tokens=['<pad>', '<bos>', '<eos>'])
tgt_vocab = d2l.Vocab(target, min_freq=2,
reserved_tokens=['<pad>', '<bos>', '<eos>'])
# 得到array和valid_len
src_array, src_valid_len = build_array_nmt(source, src_vocab, num_steps)
tgt_array, tgt_valid_len = build_array_nmt(target, tgt_vocab, num_steps)
# 使用load_array建立pytorch-dataset
data_arrays = (src_array, src_valid_len, tgt_array, tgt_valid_len)
data_iter = d2l.load_array(data_arrays, batch_size)
return data_iter, src_vocab, tgt_vocab
train_iter, src_vocab, tgt_vocab = load_data_nmt(batch_size=2, num_steps=8)
# 试验一下
for X, X_valid_len, Y, Y_valid_len in train_iter:
print('X:', X.type(torch.int32))
print('valid lengths for X:', X_valid_len)
print('Y:', Y.type(torch.int32))
print('valid lengths for Y:', Y_valid_len)
break
X: tensor([[ 79, 34, 5, 3, 1, 1, 1, 1],
[ 6, 125, 4, 3, 1, 1, 1, 1]], dtype=torch.int32)
valid lengths for X: tensor([4, 4])
Y: tensor([[ 0, 0, 4, 3, 1, 1, 1, 1],
[ 6, 27, 7, 0, 133, 4, 3, 1]], dtype=torch.int32)
valid lengths for Y: tensor([4, 7])