飞道的博客

深度学习——机器翻译数据集(笔记)

422人阅读  评论(0)

机器翻译

将序列从一种语言自动翻译成另一种语言

如何将预处理的数据加载到小批量进行训练

1.下载数据集

下载“英-法”数据集

①数据集的每一行都是制表符\t分隔的文本序列对

②序列对由英文序列和翻译后的法语序列组成

③源语言是英语,目标语言是法语


  
  1. import os
  2. import torch
  3. from d2l import torch as d2l
  4. # 下载和预处理数据集
  5. # @save
  6. d2l.DATA_HUB[ 'fra-eng'] = (d2l.DATA_URL + 'fra-eng.zip',
  7. '94646ad1522d915e7b0f9296181140edcf86a4f5')
  8. # @save
  9. def read_data_nmt():
  10. """载入“英语-法语”数据集"""
  11. data_dir = d2l.download_extract( 'fra-eng')
  12. with open(os.path.join(data_dir, 'fra.txt'), 'r',
  13. encoding= 'utf-8') as f:
  14. return f.read()

2.数据集预处理

①使用空格代替连续的空格

②使用小写替换大写字符,在单词和标点之间加入空格,标点也当作词元


  
  1. def preprocess_nmt( text):
  2. '''数据集'''
  3. def no_space( char, prev_char):
  4. return char in set( ',.!?') and prev_char != ' '
  5. # 使用空格代替连续空格,使用小写替换大写
  6. text = text.replace( '\u202f', ' ').replace( '\xa0', ' ').lower()
  7. # 在单词和标点符号之间插入空格
  8. out = [ ' ' + char if i > 0 and no_space(char, text[i - 1]) else char
  9. for i, char in enumerate(text)]
  10. return ''.join(out)

3.词元化

对文本序列进行词元,每个词元是一个词或者是一个标点符号


  
  1. def tokenize_nmt( text, num_examples=None):
  2. '''词元化 数据集'''
  3. source, target = [], []
  4. for i, line in enumerate(text.split( '\n')):
  5. if num_examples and i > num_examples:
  6. break
  7. parts = line.split( '\t')
  8. if len(parts) == 2:
  9. source.append(parts[ 0].split( ' '))
  10. target.append(parts[ 1].split( ' '))
  11. return source, target

4.词表

分为源语言和目标语言的两个词表。

①使用单词级词元化时,词表的大小明显大于使用字符级的词表大小。为了解决这个问题,可以将出现次数少于某一个特定值的低频词为未知词元<unk>

②填充词元<pad>,序列的开始词元<bos>,序列的结束词元<eos>


  
  1. # 词表--数据集由语言对组成,出现次数少于2次是低频词<unk>,填充词元<pad>,开始词元<bos>,结束词元<eos>
  2. src_vocab = d2l.Vocab(source, min_freq= 2, reserved_tokens=[ '<pad>', '<bos>', '<eos>'])

5.加载数据集

为了提高效率,可以通过截断和填充方式实现处理小批量文本序列进行训练


  
  1. # 加载数据集 num_steps固定长度 截断和填充实现文本序列 有相同的长度
  2. # 长度达不到,填充<pad> 长度超过截取 并且丢弃
  3. # truncate_pad函数截断或者填充文本序列
  4. def truncate_pad( line, num_steps, padding_token):
  5. '''截断或者填充文本序列'''
  6. if len(line) > num_steps:
  7. return line[:num_steps] # 截断
  8. return line + [padding_token] * (num_steps - len(line)) # 填充
  • 如果文本序列的词元数目少于这个固定长度时,继续在其末尾添加特定的填充词元“<pad>”,直到达到固定长度
  • 在截断文本序列的时候,只需要按照固定长度截取指定数量位置靠前的词元,然后将剩余的词元丢弃就可以了
  • 对于每一个固定长度的序列,在其末尾添加特定的序列结束词元“<eos>”,用于表示序列的结束

  
  1. def build_array_nmt( lines, vocab, num_steps):
  2. '''文本序列转换为小批量'''
  3. lines = [vocab[l] for l in lines]
  4. lines = [l + [vocab[ '<eos>']] for l in lines]
  5. array = torch.tensor([truncate_pad(
  6. l, num_steps, vocab[ '<pad>']) for l in lines
  7. ])
  8. valid_len = (array != vocab[ '<pad>']). type(torch.int32). sum( 1)
  9. return array, valid_len

6.模型训练


  
  1. def load_data_nmt( batch_size, num_steps, num_examples=600):
  2. '''返回数据集的迭代器和词表'''
  3. text = preprocess_nmt(read_data_nmt())
  4. source, target = tokenize_nmt(text, num_examples)
  5. src_vocab = d2l.Vocab(source, min_freq= 2, reserved_tokens=[ '<pad>', '<bos>', '<eos>'])
  6. tgt_vocab = d2l.Vocab(target, min_freq= 2, reserved_tokens=[ '<pad>', '<bos>', '<eos>'])
  7. src_array, src_valid_len = build_array_nmt(source, src_vocab, num_steps)
  8. tgt_array, tgt_valid_len = build_array_nmt(target, tgt_vocab, num_steps)
  9. data_arrays = (src_array, src_valid_len, tgt_array, tgt_valid_len)
  10. data_iter = d2l.load_array(data_arrays, batch_size)
  11. return data_iter, src_vocab, tgt_vocab

第一个小批量数据


  
  1. train_iter, src_vocab, tgt_vocab = load_data_nmt(batch_size= 2, num_steps= 8)
  2. for X, X_valid_len, Y, Y_valid_len in train_iter:
  3. print( 'X:', X. type(torch.int32))
  4. print( 'X的有效长度:', X_valid_len)
  5. print( 'Y:', Y. type(torch.int32))
  6. print( 'Y的有效长度:', Y_valid_len)
  7. break

总结

  • 机器翻译指的是将文本序列从一种语言自动翻译成另外一种语言
  • 使用单词级词元化时的词表大小,将明显大于使用字符级词元化时的词表大小。为了缓解这一问题,可以通过将低频次元视为相同的未知词元来解决
  • 通过截断和填充文本序列,可以保证所有的文本序列都具有相同的长度,便于以小批量的方式进行加载

转载:https://blog.csdn.net/jbkjhji/article/details/128738060
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场