PyTorch教程-10.5。机器翻译和数据集

电子说

1.2w人已加入

描述

在引起人们对现代 RNN 广泛兴趣的重大突破中,有一项是统计机器翻译应用领域的重大进展 。在这里,模型以一种语言的句子呈现,并且必须预测另一种语言的相应句子。请注意,由于两种语言的语法结构不同,这里的句子可能有不同的长度,并且两个句子中相应的词可能不会以相同的顺序出现。

许多问题都具有这种在两个这样的“未对齐”序列之间进行映射的风格。示例包括从对话提示到回复或从问题到答案的映射。广义上,此类问题称为 序列到序列(seq2seq) 问题,它们是本章剩余部分和 第 11 节大部分内容的重点。

在本节中,我们将介绍机器翻译问题和我们将在后续示例中使用的示例数据集。几十年来,语言间翻译的统计公式一直很流行 (Brown等人,1990 年,Brown等人,1988 年),甚至在研究人员使神经网络方法起作用之前(这些方法通常被统称为神经机器翻译)。

首先,我们需要一些新代码来处理我们的数据。与我们在9.3 节中看到的语言建模不同,这里的每个示例都包含两个单独的文本序列,一个是源语言,另一个(翻译)是目标语言。以下代码片段将展示如何将预处理后的数据加载到小批量中进行训练。

 

import os
import torch
from d2l import torch as d2l

 

 

import os
from mxnet import np, npx
from d2l import mxnet as d2l

npx.set_np()

 

 

import os
from jax import numpy as jnp
from d2l import jax as d2l

 

 

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)

 

 

import os
import tensorflow as tf
from d2l import tensorflow as d2l

 

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]目标语言(此处为法语)的文本序列。

 

@d2l.add_to_class(MTFraEng) #@save
def _tokenize(self, text, max_examples=None):
  src, tgt = [], []
  for i, line in enumerate(text.split('n')):
    if max_examples and i > max_examples: break
    parts = line.split('t')
    if len(parts) == 2:
      # Skip empty tokens
      src.append([t for t in f'{parts[0]} '.split(' ') if t])
      tgt.append([t for t in f'{parts[1]} '.split(' ') if t])
  return src, tgt

src, tgt = data._tokenize(text)
src[:6], tgt[:6]

 

 

([['go', '.', ''],
 ['hi', '.', ''],
 ['run', '!', ''],
 ['run', '!', ''],
 ['who', '?', ''],
 ['wow', '!', '']],
 [['va', '!', ''],
 ['salut', '!', ''],
 ['cours', '!', ''],
 ['courez', '!', ''],
 ['qui', '?', ''],
 ['ça', 'alors', '!', '']])

 

 

@d2l.add_to_class(MTFraEng) #@save
def _tokenize(self, text, max_examples=None):
  src, tgt = [], []
  for i, line in enumerate(text.split('n')):
    if max_examples and i > max_examples: break
    parts = line.split('t')
    if len(parts) == 2:
      # Skip empty tokens
      src.append([t for t in f'{parts[0]} '.split(' ') if t])
      tgt.append([t for t in f'{parts[1]} '.split(' ') if t])
  return src, tgt

src, tgt = data._tokenize(text)
src[:6], tgt[:6]

 

 

([['go', '.', ''],
 ['hi', '.', ''],
 ['run', '!', ''],
 ['run', '!', ''],
 ['who', '?', ''],
 ['wow', '!', '']],
 [['va', '!', ''],
 ['salut', '!', ''],
 ['cours', '!', ''],
 ['courez', '!', ''],
 ['qui', '?', ''],
 ['ça', 'alors', '!', '']])

 

 

@d2l.add_to_class(MTFraEng) #@save
def _tokenize(self, text, max_examples=None):
  src, tgt = [], []
  for i, line in enumerate(text.split('n')):
    if max_examples and i > max_examples: break
    parts = line.split('t')
    if len(parts) == 2:
      # Skip empty tokens
      src.append([t for t in f'{parts[0]} '.split(' ') if t])
      tgt.append([t for t in f'{parts[1]} '.split(' ') if t])
  return src, tgt

src, tgt = data._tokenize(text)
src[:6], tgt[:6]

 

 

([['go', '.', ''],
 ['hi', '.', ''],
 ['run', '!', ''],
 ['run', '!', ''],
 ['who', '?', ''],
 ['wow', '!', '']],
 [['va', '!', ''],
 ['salut', '!', ''],
 ['cours', '!', ''],
 ['courez', '!', ''],
 ['qui', '?', ''],
 ['ça', 'alors', '!', '']])

 

 

@d2l.add_to_class(MTFraEng) #@save
def _tokenize(self, text, max_examples=None):
  src, tgt = [], []
  for i, line in enumerate(text.split('n')):
    if max_examples and i > max_examples: break
    parts = line.split('t')
    if len(parts) == 2:
      # Skip empty tokens
      src.append([t for t in f'{parts[0]} '.split(' ') if t])
      tgt.append([t for t in f'{parts[1]} '.split(' ') if t])
  return src, tgt

src, tgt = data._tokenize(text)
src[:6], tgt[:6]

 

 

([['go', '.', ''],
 ['hi', '.', ''],
 ['run', '!', ''],
 ['run', '!', ''],
 ['who', '?', ''],
 ['wow', '!', '']],
 [['va', '!', ''],
 ['salut', '!', ''],
 ['cours', '!', ''],
 ['courez', '!', ''],
 ['qui', '?', ''],
 ['ça', 'alors', '!', '']])

 

让我们绘制每个文本序列的标记数量的直方图。在这个简单的英法数据集中,大多数文本序列的标记少于 20 个。

 

#@save
def show_list_len_pair_hist(legend, xlabel, ylabel, xlist, ylist):
  """Plot the histogram for list length pairs."""
  d2l.set_figsize()
  _, _, patches = d2l.plt.hist(
    [[len(l) for l in xlist], [len(l) for l in ylist]])
  d2l.plt.xlabel(xlabel)
  d2l.plt.ylabel(ylabel)
  for patch in patches[1].patches:
    patch.set_hatch('/')
  d2l.plt.legend(legend)

show_list_len_pair_hist(['source', 'target'], '# tokens per sequence',
            'count', src, tgt);

 

数据集

 

#@save
def show_list_len_pair_hist(legend, xlabel, ylabel, xlist, ylist):
  """Plot the histogram for list length pairs."""
  d2l.set_figsize()
  _, _, patches = d2l.plt.hist(
    [[len(l) for l in xlist], [len(l) for l in ylist]])
  d2l.plt.xlabel(xlabel)
  d2l.plt.ylabel(ylabel)
  for patch in patches[1].patches:
    patch.set_hatch('/')
  d2l.plt.legend(legend)

show_list_len_pair_hist(['source', 'target'], '# tokens per sequence',
            'count', src, tgt);

 

数据集

 

#@save
def show_list_len_pair_hist(legend, xlabel, ylabel, xlist, ylist):
  """Plot the histogram for list length pairs."""
  d2l.set_figsize()
  _, _, patches = d2l.plt.hist(
    [[len(l) for l in xlist], [len(l) for l in ylist]])
  d2l.plt.xlabel(xlabel)
  d2l.plt.ylabel(ylabel)
  for patch in patches[1].patches:
    patch.set_hatch('/')
  d2l.plt.legend(legend)

show_list_len_pair_hist(['source', 'target'], '# tokens per sequence',
            'count', src, tgt);

 

数据集

 

#@save
def show_list_len_pair_hist(legend, xlabel, ylabel, xlist, ylist):
  """Plot the histogram for list length pairs."""
  d2l.set_figsize()
  _, _, patches = d2l.plt.hist(
    [[len(l) for l in xlist], [len(l) for l in ylist]])
  d2l.plt.xlabel(xlabel)
  d2l.plt.ylabel(ylabel)
  for patch in patches[1].patches:
    patch.set_hatch('/')
  d2l.plt.legend(legend)

show_list_len_pair_hist(['source', 'target'], '# tokens per sequence',
            'count', src, tgt);

 

数据集

10.5.3。固定长度的加载序列

回想一下,在语言建模中,每个示例序列(一个句子的一部分或多个句子的跨度)都有固定的长度。这是由第 9.3 节num_steps中的(时间步数或标记数)参数指定的。在机器翻译中,每个示例都是一对源文本序列和目标文本序列,其中这两个文本序列可能具有不同的长度。

为了计算效率,我们仍然可以通过截断和填充一次处理一小批文本序列。假设同一个小批量中的每个序列都应该具有相同的长度 num_steps。如果文本序列少于num_steps标记,我们将继续在其末尾附加特殊的“”标记,直到其长度达到num_steps. num_steps否则,我们将通过仅获取其第一个标记并丢弃其余标记来截断文本序列。这样,每个文本序列将具有相同的长度,以相同形状的小批量加载。此外,我们还记录了不包括填充标记的源序列长度。我们稍后将介绍的某些模型将需要此信息。

由于机器翻译数据集由多对语言组成,我们可以分别为源语言和目标语言构建两个词汇表。使用词级标记化,词汇量将明显大于使用字符级标记化的词汇量。为了减轻这一点,在这里,我们将看上去不到2倍相同的未知数(“”)令牌视为罕见的令牌。正如我们稍后将解释的(图 10.7.1),当使用目标序列进行训练时,解码器输出(标签标记)可以是相同的解码器输入(目标标记),移动一个标记;特殊的序列开头“”标记将用作预测目标序列的第一个输入标记(图 10.7.3)。

 

@d2l.add_to_class(MTFraEng) #@save
def __init__(self, batch_size, num_steps=9, num_train=512, num_val=128):
  super(MTFraEng, self).__init__()
  self.save_hyperparameters()
  self.arrays, self.src_vocab, self.tgt_vocab = self._build_arrays(
    self._download())

@d2l.add_to_class(MTFraEng) #@save
def _build_arrays(self, raw_text, src_vocab=None, tgt_vocab=None):
  def _build_array(sentences, vocab, is_tgt=False):
    pad_or_trim = lambda seq, t: (
      seq[:t] if len(seq) > t else seq + [''] * (t - len(seq)))
    sentences = [pad_or_trim(s, self.num_steps) for s in sentences]
    if is_tgt:
      sentences = [[''] + s for s in sentences]
    if vocab is None:
      vocab = d2l.Vocab(sentences, min_freq=2)
    array = torch.tensor([vocab[s] for s in sentences])
    valid_len = (array != vocab['']).type(torch.int32).sum(1)
    return array, vocab, valid_len
  src, tgt = self._tokenize(self._preprocess(raw_text),
               self.num_train + self.num_val)
  src_array, src_vocab, src_valid_len = _build_array(src, src_vocab)
  tgt_array, tgt_vocab, _ = _build_array(tgt, tgt_vocab, True)
  return ((src_array, tgt_array[:,:-1], src_valid_len, tgt_array[:,1:]),
      src_vocab, tgt_vocab)

 

 

@d2l.add_to_class(MTFraEng) #@save
def __init__(self, batch_size, num_steps=9, num_train=512, num_val=128):
  super(MTFraEng, self).__init__()
  self.save_hyperparameters()
  self.arrays, self.src_vocab, self.tgt_vocab = self._build_arrays(
    self._download())

@d2l.add_to_class(MTFraEng) #@save
def _build_arrays(self, raw_text, src_vocab=None, tgt_vocab=None):
  def _build_array(sentences, vocab, is_tgt=False):
    pad_or_trim = lambda seq, t: (
      seq[:t] if len(seq) > t else seq + [''] * (t - len(seq)))
    sentences = [pad_or_trim(s, self.num_steps) for s in sentences]
    if is_tgt:
      sentences = [[''] + s for s in sentences]
    if vocab is None:
      vocab = d2l.Vocab(sentences, min_freq=2)
    array = np.array([vocab[s] for s in sentences])
    valid_len = (array != vocab['']).astype(np.int32).sum(1)
    return array, vocab, valid_len
  src, tgt = self._tokenize(self._preprocess(raw_text),
               self.num_train + self.num_val)
  src_array, src_vocab, src_valid_len = _build_array(src, src_vocab)
  tgt_array, tgt_vocab, _ = _build_array(tgt, tgt_vocab, True)
  return ((src_array, tgt_array[:,:-1], src_valid_len, tgt_array[:,1:]),
      src_vocab, tgt_vocab)

 

 

@d2l.add_to_class(MTFraEng) #@save
def __init__(self, batch_size, num_steps=9, num_train=512, num_val=128):
  super(MTFraEng, self).__init__()
  self.save_hyperparameters()
  self.arrays, self.src_vocab, self.tgt_vocab = self._build_arrays(
    self._download())

@d2l.add_to_class(MTFraEng) #@save
def _build_arrays(self, raw_text, src_vocab=None, tgt_vocab=None):
  def _build_array(sentences, vocab, is_tgt=False):
    pad_or_trim = lambda seq, t: (
      seq[:t] if len(seq) > t else seq + [''] * (t - len(seq)))
    sentences = [pad_or_trim(s, self.num_steps) for s in sentences]
    if is_tgt:
      sentences = [[''] + s for s in sentences]
    if vocab is None:
      vocab = d2l.Vocab(sentences, min_freq=2)
    array = jnp.array([vocab[s] for s in sentences])
    valid_len = (array != vocab['']).astype(jnp.int32).sum(1)
    return array, vocab, valid_len
  src, tgt = self._tokenize(self._preprocess(raw_text),
               self.num_train + self.num_val)
  src_array, src_vocab, src_valid_len = _build_array(src, src_vocab)
  tgt_array, tgt_vocab, _ = _build_array(tgt, tgt_vocab, True)
  return ((src_array, tgt_array[:,:-1], src_valid_len, tgt_array[:,1:]),
      src_vocab, tgt_vocab)

 

 

@d2l.add_to_class(MTFraEng) #@save
def __init__(self, batch_size, num_steps=9, num_train=512, num_val=128):
  super(MTFraEng, self).__init__()
  self.save_hyperparameters()
  self.arrays, self.src_vocab, self.tgt_vocab = self._build_arrays(
    self._download())

@d2l.add_to_class(MTFraEng) #@save
def _build_arrays(self, raw_text, src_vocab=None, tgt_vocab=None):
  def _build_array(sentences, vocab, is_tgt=False):
    pad_or_trim = lambda seq, t: (
      seq[:t] if len(seq) > t else seq + [''] * (t - len(seq)))
    sentences = [pad_or_trim(s, self.num_steps) for s in sentences]
    if is_tgt:
      sentences = [[''] + s for s in sentences]
    if vocab is None:
      vocab = d2l.Vocab(sentences, min_freq=2)
    array = tf.constant([vocab[s] for s in sentences])
    valid_len = tf.reduce_sum(
      tf.cast(array != vocab[''], tf.int32), 1)
    return array, vocab, valid_len
  src, tgt = self._tokenize(self._preprocess(raw_text),
               self.num_train + self.num_val)
  src_array, src_vocab, src_valid_len = _build_array(src, src_vocab)
  tgt_array, tgt_vocab, _ = _build_array(tgt, tgt_vocab, True)
  return ((src_array, tgt_array[:,:-1], src_valid_len, tgt_array[:,1:]),
      src_vocab, tgt_vocab)

 

10.5.4。读取数据集

最后,我们定义get_dataloader返回数据迭代器的方法。

 

@d2l.add_to_class(MTFraEng) #@save
def get_dataloader(self, train):
  idx = slice(0, self.num_train) if train else slice(self.num_train, None)
  return self.get_tensorloader(self.arrays, train, idx)

 

让我们从英法数据集中读取第一个小批量。

 

data = MTFraEng(batch_size=3)
src, tgt, src_valid_len, label = next(iter(data.train_dataloader()))
print('source:', src.type(torch.int32))
print('decoder input:', tgt.type(torch.int32))
print('source len excluding pad:', src_valid_len.type(torch.int32))
print('label:', label.type(torch.int32))

 

 

source: tensor([[ 83, 174,  2,  3,  4,  4,  4,  4,  4],
    [ 84, 32, 91,  2,  3,  4,  4,  4,  4],
    [144, 174,  0,  3,  4,  4,  4,  4,  4]], dtype=torch.int32)
decoder input: tensor([[ 3,  6,  0,  4,  5,  5,  5,  5,  5],
    [ 3, 108, 112, 84,  2,  4,  5,  5,  5],
    [ 3, 87,  0,  4,  5,  5,  5,  5,  5]], dtype=torch.int32)
source len excluding pad: tensor([4, 5, 4], dtype=torch.int32)
label: tensor([[ 6,  0,  4,  5,  5,  5,  5,  5,  5],
    [108, 112, 84,  2,  4,  5,  5,  5,  5],
    [ 87,  0,  4,  5,  5,  5,  5,  5,  5]], dtype=torch.int32)

 

 

data = MTFraEng(batch_size=3)
src, tgt, src_valid_len, label = next(iter(data.train_dataloader()))
print('source:', src.astype(np.int32))
print('decoder input:', tgt.astype(np.int32))
print('source len excluding pad:', src_valid_len.astype(np.int32))
print('label:', label.astype(np.int32))

 

 

source: [[84 5 2 3 4 4 4 4 4]
 [84 5 2 3 4 4 4 4 4]
 [59 9 2 3 4 4 4 4 4]]
decoder input: [[ 3 108  6  2  4  5  5  5  5]
 [ 3 105  6  2  4  5  5  5  5]
 [ 3 203  0  4  5  5  5  5  5]]
source len excluding pad: [4 4 4]
label: [[108  6  2  4  5  5  5  5  5]
 [105  6  2  4  5  5  5  5  5]
 [203  0  4  5  5  5  5  5  5]]

 

 

data = MTFraEng(batch_size=3)
src, tgt, src_valid_len, label = next(iter(data.train_dataloader()))
print('source:', src.astype(jnp.int32))
print('decoder input:', tgt.astype(jnp.int32))
print('source len excluding pad:', src_valid_len.astype(jnp.int32))
print('label:', label.astype(jnp.int32))

 

 

source: [[ 86 43  2  3  4  4  4  4  4]
 [176 165  2  3  4  4  4  4  4]
 [143 111  2  3  4  4  4  4  4]]
decoder input: [[ 3 108 183 98  2  4  5  5  5]
 [ 3  6 42  0  4  5  5  5  5]
 [ 3  6  0  4  5  5  5  5  5]]
source len excluding pad: [4 4 4]
label: [[108 183 98  2  4  5  5  5  5]
 [ 6 42  0  4  5  5  5  5  5]
 [ 6  0  4  5  5  5  5  5  5]]

 

 

data = MTFraEng(batch_size=3)
src, tgt, src_valid_len, label = next(iter(data.train_dataloader()))
print('source:', tf.cast(src, tf.int32))
print('decoder input:', tf.cast(tgt, tf.int32))
print('source len excluding pad:', tf.cast(src_valid_len, tf.int32))
print('label:', tf.cast(label, tf.int32))

 

 

source: tf.Tensor(
[[ 92 115  2  3  4  4  4  4  4]
 [155 168  2  3  4  4  4  4  4]
 [ 86 121  2  3  4  4  4  4  4]], shape=(3, 9), dtype=int32)
decoder input: tf.Tensor(
[[ 3 37  6  2  4  5  5  5  5]
 [ 3  6 192  2  4  5  5  5  5]
 [ 3 108 202 30  2  4  5  5  5]], shape=(3, 9), dtype=int32)
source len excluding pad: tf.Tensor([4 4 4], shape=(3,), dtype=int32)
label: tf.Tensor(
[[ 37  6  2  4  5  5  5  5  5]
 [ 6 192  2  4  5  5  5  5  5]
 [108 202 30  2  4  5  5  5  5]], shape=(3, 9), dtype=int32)

 

下面我们展示了一对由上述方法处理的源序列和目标序列_build_arrays(以字符串格式)。

 

@d2l.add_to_class(MTFraEng) #@save
def build(self, src_sentences, tgt_sentences):
  raw_text = 'n'.join([src + 't' + tgt for src, tgt in zip(
    src_sentences, tgt_sentences)])
  arrays, _, _ = self._build_arrays(
    raw_text, self.src_vocab, self.tgt_vocab)
  return arrays

src, tgt, _, _ = data.build(['hi .'], ['salut .'])
print('source:', data.src_vocab.to_tokens(src[0].type(torch.int32)))
print('target:', data.tgt_vocab.to_tokens(tgt[0].type(torch.int32)))

 

 

source: ['hi', '.', '', '', '', '', '', '', '']
target: ['', 'salut', '.', '', '', '', '', '', '']

 

 

@d2l.add_to_class(MTFraEng) #@save
def build(self, src_sentences, tgt_sentences):
  raw_text = 'n'.join([src + 't' + tgt for src, tgt in zip(
    src_sentences, tgt_sentences)])
  arrays, _, _ = self._build_arrays(
    raw_text, self.src_vocab, self.tgt_vocab)
  return arrays

src, tgt, _, _ = data.build(['hi .'], ['salut .'])
print('source:', data.src_vocab.to_tokens(src[0].astype(np.int32)))
print('target:', data.tgt_vocab.to_tokens(tgt[0].astype(np.int32)))

 

 

source: ['hi', '.', '', '', '', '', '', '', '']
target: ['', 'salut', '.', '', '', '', '', '', '']

 

 

@d2l.add_to_class(MTFraEng) #@save
def build(self, src_sentences, tgt_sentences):
  raw_text = 'n'.join([src + 't' + tgt for src, tgt in zip(
    src_sentences, tgt_sentences)])
  arrays, _, _ = self._build_arrays(
    raw_text, self.src_vocab, self.tgt_vocab)
  return arrays

src, tgt, _, _ = data.build(['hi .'], ['salut .'])
print('source:', data.src_vocab.to_tokens(src[0].astype(jnp.int32)))
print('target:', data.tgt_vocab.to_tokens(tgt[0].astype(jnp.int32)))

 

 

source: ['hi', '.', '', '', '', '', '', '', '']
target: ['', 'salut', '.', '', '', '', '', '', '']

 

 

@d2l.add_to_class(MTFraEng) #@save
def build(self, src_sentences, tgt_sentences):
  raw_text = 'n'.join([src + 't' + tgt for src, tgt in zip(
    src_sentences, tgt_sentences)])
  arrays, _, _ = self._build_arrays(
    raw_text, self.src_vocab, self.tgt_vocab)
  return arrays

src, tgt, _, _ = data.build(['hi .'], ['salut .'])
print('source:', data.src_vocab.to_tokens(tf.cast(src[0], tf.int32)))
print('target:', data.tgt_vocab.to_tokens(tf.cast(tgt[0], tf.int32)))

 

 

source: ['hi', '.', '', '', '', '', '', '', '']
target: ['', 'salut', '.', '', '', '', '', '', '']

 

10.5.5。概括

在自然语言处理中,机器翻译是指将代表源语言文本字符串的序列自动映射到代表目标语言中合理翻译的字符串的任务。使用词级标记化,词汇量将明显大于使用字符级标记化,但序列长度会短得多。为了减轻大词汇量,我们可以将不常见的标记视为一些“未知”标记。我们可以截断和填充文本序列,以便它们都具有相同的长度以加载到小批量中。现代实现通常将具有相似长度的序列存储起来,以避免在填充上浪费过多的计算。

10.5.6。练习

max_examples在 方法中尝试不同的参数值_tokenize。这如何影响源语言和目标语言的词汇量?

某些语言(例如中文和日文)中的文本没有字界指示符(例如,空格)。对于这种情况,词级标记化仍然是一个好主意吗?为什么或者为什么不?

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分