在引起人們對現代 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。概括
在自然語言處理中,機器翻譯是指將代表源語言文本字符串的序列自動映射到代表目標語言中合理翻譯的字符串的任務。使用詞級標記化,詞匯量將明顯大于使用字符級標記化,但序列長度會短得多。為了減輕大詞匯量,我們可以將不常見的標記視為一些“未知”標記。我們可以截斷和填充文本序列,以便它們都具有相同的長度以加載到小批量中?,F代實現通常將具有相似長度的序列存儲起來,以避免在填充上浪費過多的計算。
10.5.6。練習
max_examples在 方法中嘗試不同的參數值_tokenize。這如何影響源語言和目標語言的詞匯量?
某些語言(例如中文和日文)中的文本沒有字界指示符(例如,空格)。對于這種情況,詞級標記化仍然是一個好主意嗎?為什么或者為什么不?
-
數據集
+關注
關注
4文章
1209瀏覽量
24793 -
pytorch
+關注
關注
2文章
808瀏覽量
13328
發布評論請先 登錄
相關推薦
評論