Torchtext指南 (側重於NMT)
Torchtext指南 (側重於NMT)
torchtext是一個對於NLP來說非常棒的預處理資料的工具。
本文記錄一下自己學習的過程,側重於NMT。
一個基本的操作流程:
- 建立Field,定義通用的文字處理操作:
from torchtext import data, datasets SRC = 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: 前面定義的dataset
- batch_size: batch大小
- batch_size_fn: 用來產生動態batch
- sort_key: 排序的key w
- train: 是不是train data
- repeat: 在不在不同的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, datasets UNK_TOKEN = "<unk>" PAD_TOKEN = "<pad>" SOS_TOKEN = "<s>" EOS_TOKEN = "</s>" LOWER = True MAX_LEN = 30 MIN_FREQ = 10 DEVICE=torch.device('cuda:0') #Step 1 #一般我用的是已經分好詞的資料, 所以tokenize=None SRC = 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 2 train_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 3 SRC.build_vocab(train_data.src, min_freq=MIN_FREQ) TRG.build_vocab(train_data.trg, min_freq=MIN_FREQ) #Step 4 train_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大小設定為1 valid_iter = data.Iterator(valid_data, batch_size=1, train=False, sort=False, repeat=False,device=DEVICE)