Torchtext指南 (侧重于NMT)
2019-10-31

Torchtext指南 (侧重于NMT)

torchtext是一个对于NLP来说非常棒的预处理数据的工具。

本文记录一下自己学习的过程,侧重于NMT。

一个基本的操作流程:

创建Field,定义通用的文本处理操作:

from torchtext import data, datasetsSRC = data.Field(...)TRG = data.Field(...)加载你的数据集

train_data, valid_data, test_data = datasets.TranslationDataset.splits(...)创建词汇表

SRC.build_vocab(train_data.src)TRG.build_vocab(train_data.trg)最后生成迭代器进行Batch操作

train_iter = data.BucketIterator(...)valid_iter = data.BucketIterator(...)

Field

貌似有好几种,对于我自己来说常用的就是:

torchtext.data.Field(sequential=True, use_vocab=True, init_token=None, eos_token=None, fix_length=None, dtype=torch.int64, preprocessing=None, postprocessing=None, lower=False, tokenize=None, tokenizer_language="en", include_lengths=False, batch_first=False, pad_token="<pad>", unk_token="<unk>", pad_first=False, truncate_first=False, stop_words=None, is_target=False)

参数具体详解:

sequential: 是否把数据表示成序列,如果是False, 不能使用分词 默认值: True.

use_vocab: 是否使用词典对象. 如果是False 数据的类型必须已经是数值类型. 默认值: True.

init_token: 每一条数据的起始字符 默认值: None.

eos_token: EOS 默认值: None.

fix_length: 修改每条数据的长度为该值,不够的用pad_token补全. 默认值: None.

tensor_type: 把数据转换成的tensor类型 默认值: torch.LongTensor.

preprocessing:在分词之后和数值化之前使用的管道 默认值: None.

postprocessing: 数值化之后和转化成tensor之前使用的管道默认值: None.

lower: 是否把数据转化为小写 默认值: False.

tokenize: 分词函数. 默认值: str.split.

include_lengths: 是否返回一个已经补全的最小batch的元组和和一个包含每条数据长度的列表 . 默认值: False.

batch_first: 是否Batch first. 默认值: False.

pad_token: PAD 默认值: "

unk_token: UNK 默认值: "

pad_first: 是否补全第一个字符. 默认值: False.

datasets(这里只讲TranslationDataset)

torchtext.datasets.TranslationDataset(path, exts, fields, **kwargs)

path: 两种语言的数据文件的路径的公共前缀

exts: 包含每种语言路径扩展名的tuple

fields: 包含将用于每种语言的Field的tuple

**kwargs: 等等

torchtext.datasets.TranslationDataset.splits(path, exts, fields, **kwargs)

机器翻译的话train, dev, test一般是分开的,这时候就要用splits啦。

classmethod splits(path=None, root=".data", train=None, validation=None, test=None, **kwargs)

path: 两种语言的数据文件的路径的公共前缀

train: train路径

valiadation: dev路径

test: test路径

Iterator

torchtext.data.Iterator

class torchtext.data.Iterator(dataset, batch_size, sort_key=None, device=None, batch_size_fn=None, train=True, repeat=False, shuffle=None, sort=None, sort_within_batch=None)dataset: 前面定义的datasetbatch_size: batch大小batch_size_fn: 用来产生动态batchsort_key: 排序的key wtrain: 是不是train datarepeat: 在不在不同的epoch中重复shuffle: 大打不打乱数据sort: 是否排序sort_within_batch: batch内部是否排序device: cpu or gpu

BucketIterator

class torchtext.data.BucketIterator(dataset, batch_size, sort_key=None, device=None, batch_size_fn=None, train=True, repeat=False, shuffle=None, sort=None, sort_within_batch=None)

定义一个迭代器,将类似长度的示例一起批处理。

减少在每一个epoch中shuffled batches需要padding的量

NMT常用写法

from torchtext import data, datasetsUNK_TOKEN = "<unk>"PAD_TOKEN = "<pad>" SOS_TOKEN = "<s>"EOS_TOKEN = "</s>"LOWER = TrueMAX_LEN = 30MIN_FREQ = 10DEVICE=torch.device("cuda:0")#Step 1#一般我用的是已经分好词的数据, 所以tokenize=NoneSRC = data.Field(tokenize=None, batch_first=True, lower=LOWER, include_lengths=True, unk_token=UNK_TOKEN, pad_token=PAD_TOKEN, init_token=None, eos_token=EOS_TOKEN) TRG = data.Field(tokenize=None, batch_first=True, lower=LOWER, include_lengths=True, unk_token=UNK_TOKEN, pad_token=PAD_TOKEN, init_token=SOS_TOKEN, eos_token=EOS_TOKEN)#Step 2train_data, valid_data, test_data = datasets.TranslationDataset.splits(path="./WMT2014_en-de/", train= "xxx",validation="yyy", test="zzz", exts=(".de", ".en"), fields=(SRC, TRG),filter_pred=lambda x: len(vars(x)["src"]) <= MAX_LEN and len(vars(x)["trg"]) <= MAX_LEN)#Step 3SRC.build_vocab(train_data.src, min_freq=MIN_FREQ)TRG.build_vocab(train_data.trg, min_freq=MIN_FREQ)#Step 4train_iter = data.BucketIterator(train_data, batch_size=64, train=True, sort_within_batch=True, sort_key=lambda x: (len(x.src), len(x.trg)), repeat=False, device=DEVICE)# 如果用一些未排序的外部文件进行valid,经常有问题。#为了方便,将batch大小设置为1valid_iter = data.Iterator(valid_data, batch_size=1, train=False, sort=False, repeat=False, device=DEVICE)