torchtext BucketIterator 最小填充
torchtext BucketIterator minimum padding
我正在尝试使用 torchtext 中的 BucketIterator.splits 函数从 csv 文件加载数据以用于 CNN。一切正常,除非我有一批最长的句子比最大的过滤器尺寸短。
在我的示例中,我有大小为 3、4 和 5 的过滤器,因此如果最长的句子没有至少 5 个单词,我会收到错误消息。有没有办法让 BucketIterator 动态设置批次的填充,同时设置最小填充长度?
这是我用于 BucketIterator 的代码:
train_iter, val_iter, test_iter = BucketIterator.splits((train, val, test), sort_key=lambda x: len(x.text), batch_size=batch_size, repeat=False, device=device)
我希望有一种方法可以在 sort_key 或类似的东西上设置最小长度?
我试过了,但没用:
FILTER_SIZES = [3,4,5]
train_iter, val_iter, test_iter = BucketIterator.splits((train, val, test), sort_key=lambda x: len(x.text) if len(x.text) >= FILTER_SIZES[-1] else FILTER_SIZES[-1], batch_size=batch_size, repeat=False, device=device)
我查看了 torchtext 源代码以更好地理解 sort_key 在做什么,并且明白了为什么我最初的想法行不通。
我不确定这是否是最佳解决方案,但我想出了一个可行的解决方案。我创建了一个 tokenizer 函数,如果它比最长的过滤器长度短,它会填充文本,然后从那里创建 BucketIterator。
FILTER_SIZES = [3,4,5]
spacy_en = spacy.load('en')
def tokenizer(text):
token = [t.text for t in spacy_en.tokenizer(text)]
if len(token) < FILTER_SIZES[-1]:
for i in range(0, FILTER_SIZES[-1] - len(token)):
token.append('<PAD>')
return token
TEXT = Field(sequential=True, tokenize=tokenizer, lower=True, tensor_type=torch.cuda.LongTensor)
train_iter, val_iter, test_iter = BucketIterator.splits((train, val, test), sort_key=lambda x: len(x.text), batch_size=batch_size, repeat=False, device=device)
虽然@paul41 的方法有效,但有点误用。这样做的正确方法是使用 preprocessing
或 postprocessing
(相应地在数字化之前或之后)。这是 postprocessing
的示例:
def get_pad_to_min_len_fn(min_length):
def pad_to_min_len(batch, vocab, min_length=min_length):
pad_idx = vocab.stoi['<pad>']
for idx, ex in enumerate(batch):
if len(ex) < min_length:
batch[idx] = ex + [pad_idx] * (min_length - len(ex))
return batch
return pad_to_min_len
FILTER_SIZES = [3,4,5]
min_len_padding = get_pad_to_min_len_fn(min_length=max(FILTER_SIZES))
TEXT = Field(sequential=True, use_vocab=True, lower=True, batch_first=True,
postprocessing=min_len_padding)
嵌套函数需要将参数传递给主循环中的内部函数(例如 min_length = max(FILTER_SIZES)
),但如果可行,参数可以在函数内部硬编码。
我正在尝试使用 torchtext 中的 BucketIterator.splits 函数从 csv 文件加载数据以用于 CNN。一切正常,除非我有一批最长的句子比最大的过滤器尺寸短。
在我的示例中,我有大小为 3、4 和 5 的过滤器,因此如果最长的句子没有至少 5 个单词,我会收到错误消息。有没有办法让 BucketIterator 动态设置批次的填充,同时设置最小填充长度?
这是我用于 BucketIterator 的代码:
train_iter, val_iter, test_iter = BucketIterator.splits((train, val, test), sort_key=lambda x: len(x.text), batch_size=batch_size, repeat=False, device=device)
我希望有一种方法可以在 sort_key 或类似的东西上设置最小长度?
我试过了,但没用:
FILTER_SIZES = [3,4,5]
train_iter, val_iter, test_iter = BucketIterator.splits((train, val, test), sort_key=lambda x: len(x.text) if len(x.text) >= FILTER_SIZES[-1] else FILTER_SIZES[-1], batch_size=batch_size, repeat=False, device=device)
我查看了 torchtext 源代码以更好地理解 sort_key 在做什么,并且明白了为什么我最初的想法行不通。
我不确定这是否是最佳解决方案,但我想出了一个可行的解决方案。我创建了一个 tokenizer 函数,如果它比最长的过滤器长度短,它会填充文本,然后从那里创建 BucketIterator。
FILTER_SIZES = [3,4,5]
spacy_en = spacy.load('en')
def tokenizer(text):
token = [t.text for t in spacy_en.tokenizer(text)]
if len(token) < FILTER_SIZES[-1]:
for i in range(0, FILTER_SIZES[-1] - len(token)):
token.append('<PAD>')
return token
TEXT = Field(sequential=True, tokenize=tokenizer, lower=True, tensor_type=torch.cuda.LongTensor)
train_iter, val_iter, test_iter = BucketIterator.splits((train, val, test), sort_key=lambda x: len(x.text), batch_size=batch_size, repeat=False, device=device)
虽然@paul41 的方法有效,但有点误用。这样做的正确方法是使用 preprocessing
或 postprocessing
(相应地在数字化之前或之后)。这是 postprocessing
的示例:
def get_pad_to_min_len_fn(min_length):
def pad_to_min_len(batch, vocab, min_length=min_length):
pad_idx = vocab.stoi['<pad>']
for idx, ex in enumerate(batch):
if len(ex) < min_length:
batch[idx] = ex + [pad_idx] * (min_length - len(ex))
return batch
return pad_to_min_len
FILTER_SIZES = [3,4,5]
min_len_padding = get_pad_to_min_len_fn(min_length=max(FILTER_SIZES))
TEXT = Field(sequential=True, use_vocab=True, lower=True, batch_first=True,
postprocessing=min_len_padding)
嵌套函数需要将参数传递给主循环中的内部函数(例如 min_length = max(FILTER_SIZES)
),但如果可行,参数可以在函数内部硬编码。