在引起人们对现代 RNN 广泛兴趣的重大突破中,有一项是统计机器翻译应用领域的重大进展 。在这里,模型以一种语言的句子呈现,并且必须预测另一种语言的相应句子。请注意,由于两种语言的语法结构不同,这里的句子可能有不同的长度,并且两个句子中相应的词可能不会以相同的顺序出现。
许多问题都具有这种在两个这样的“未对齐”序列之间进行映射的风格。示例包括从对话提示到回复或从问题到答案的映射。广义上,此类问题称为 序列到序列(seq2seq) 问题,它们是本章剩余部分和 第 11 节大部分内容的重点。
在本节中,我们将介绍机器翻译问题和我们将在后续示例中使用的示例数据集。几十年来,语言间翻译的统计公式一直很流行 (Brown等人,1990 年,Brown等人,1988 年),甚至在研究人员使神经网络方法起作用之前(这些方法通常被统称为神经机器翻译)。
首先,我们需要一些新代码来处理我们的数据。与我们在9.3 节中看到的语言建模不同,这里的每个示例都包含两个单独的文本序列,一个是源语言,另一个(翻译)是目标语言。以下代码片段将展示如何将预处理后的数据加载到小批量中进行训练。
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
10.5.1。下载和预处理数据集
首先,我们 从 Tatoeba Project 下载由双语句子对组成的英法数据集。数据集中的每一行都是一个制表符分隔的对,由一个英文文本序列和翻译后的法文文本序列组成。请注意,每个文本序列可以只是一个句子,也可以是一段多句。在这个英语翻译成法语的机器翻译问题中,英语被称为源语言,法语被称为目标语言。
class MTFraEng(d2l.DataModule): #@save
"""The English-French dataset."""
def _download(self):
d2l.extract(d2l.download(
d2l.DATA_URL+'fra-eng.zip', self.root,
'94646ad1522d915e7b0f9296181140edcf86a4f5'))
with open(self.root + '/fra-eng/fra.txt', encoding='utf-8') as f:
return f.read()
data = MTFraEng()
raw_text = data._download()
print(raw_text[:75])
Downloading ../data/fra-eng.zip from http://d2l-data.s3-accelerate.amazonaws.com/fra-eng.zip...
Go. Va !
Hi. Salut !
Run! Cours !
Run! Courez !
Who? Qui ?
Wow! Ça alors !
class MTFraEng(d2l.DataModule): #@save
"""The English-French dataset."""
def _download(self):
d2l.extract(d2l.download(
d2l.DATA_URL+'fra-eng.zip', self.root,
'94646ad1522d915e7b0f9296181140edcf86a4f5'))
with open(self.root + '/fra-eng/fra.txt', encoding='utf-8') as f:
return f.read()
data = MTFraEng()
raw_text = data._download()
print(raw_text[:75])
Go. Va !
Hi. Salut !
Run! Cours !
Run! Courez !
Who? Qui ?
Wow! Ça alors !
class MTFraEng(d2l.DataModule): #@save
"""The English-French dataset."""
def _download(self):
d2l.extract(d2l.download(
d2l.DATA_URL+'fra-eng.zip', self.root,
'94646ad1522d915e7b0f9296181140edcf86a4f5'))
with open(self.root + '/fra-eng/fra.txt', encoding='utf-8') as f:
return f.read()
data = MTFraEng()
raw_text = data._download()
print(raw_text[:75])
Go. Va !
Hi. Salut !
Run! Cours !
Run! Courez !
Who? Qui ?
Wow! Ça alors !
class MTFraEng(d2l.DataModule): #@save
"""The English-French dataset."""
def _download(self):
d2l.extract(d2l.download(
d2l.DATA_URL+'fra-eng.zip', self.root,
'94646ad1522d915e7b0f9296181140edcf86a4f5'))
with open(self.root + '/fra-eng/fra.txt', encoding='utf-8') as f:
return f.read()
data = MTFraEng()
raw_text = data._download()
print(raw_text[:75])
Go. Va !
Hi. Salut !
Run! Cours !
Run! Courez !
Who? Qui ?
Wow! Ça alors !
下载数据集后,我们对原始文本数据进行几个预处理步骤。例如,我们将不间断空格替换为空格,将大写字母转换为小写字母,在单词和标点符号之间插入空格。
@d2l.add_to_class(MTFraEng) #@save
def _preprocess(self, text):
# Replace non-breaking space with space
text = text.replace('\u202f', ' ').replace('\xa0', ' ')
# Insert space between words and punctuation marks
no_space = lambda char, prev_char: char in ',.!?' and prev_char != ' '
out = [' ' + char if i > 0 and no_space(char, text[i - 1]) else char
for i, char in enumerate(text.lower())]
return ''.join(out)
text = data._preprocess(raw_text)
print(text[:80])
go . va !
hi . salut !
run ! cours !
run ! courez !
who ? qui ?
wow ! ça alors !
@d2l.add_to_class(MTFraEng) #@save
def _preprocess(self, text):
# Replace non-breaking space with space
text = text.replace('\u202f', ' ').replace('\xa0', ' ')
# Insert space between words and punctuation marks
no_space = lambda char, prev_char: char in ',.!?' and prev_char != ' '
out = [' ' + char if i > 0 and no_space(char, text[i - 1]) else char
for i, char in enumerate(text.lower())]
return ''.join(out)
text = data._preprocess(raw_text)
print(text[:80])
go . va !
hi . salut !
run ! cours !
run ! courez !
who ? qui ?
wow ! ça alors !
@d2l.add_to_class(MTFraEng) #@save
def _preprocess(self, text):
# Replace non-breaking space with space
text = text.replace('\u202f', ' ').replace('\xa0', ' ')
# Insert space between words and punctuation marks
no_space = lambda char, prev_char: char in ',.!?' and prev_char != ' '
out = [' ' + char if i > 0 and no_space(char, text[i - 1]) else char
for i, char in enumerate(text.lower())]
return ''.join(out)
text = data._preprocess(raw_text)
print(text[:80])
go . va !
hi . salut !
run ! cours !
run ! courez !
who ? qui ?
wow ! ça alors !
@d2l.add_to_class(MTFraEng) #@save
def _preprocess(self, text):
# Replace non-breaking space with space
text = text.replace('\u202f', ' ').replace('\xa0', ' ')
# Insert space between words and punctuation marks
no_space = lambda char, prev_char: char in ',.!?' and prev_char != ' '
out = [' ' + char if i > 0 and no_space(char, text[i - 1]) else char
for i, char in enumerate(text.lower())]
return ''.join(out)
text = data._preprocess(raw_text)
print(text[:80])
go . va !
hi . salut !
run ! cours !
run ! courez !
who ? qui ?
wow ! ça alors !
10.5.2。代币化
与第 9.3 节中的字符级标记化不同 ,对于机器翻译,我们在这里更喜欢单词级标记化(当今最先进的模型使用更复杂的标记化技术)。以下_tokenize
方法对第一个max_examples
文本序列对进行分词,其中每个分词要么是一个单词,要么是一个标点符号。我们将特殊的“”标记附加到每个序列的末尾,以指示序列的结束。当模型通过生成一个接一个标记的序列标记进行预测时,“”标记的生成表明输出序列是完整的。最后,下面的方法返回两个令牌列表列表:src
和tgt
。具体来说,src[i]
是来自ith源语言(此处为英语)的文本序列和tgt[i]
目标语言(此处为法语)的文本序列。