我在 FASTAI 数据加载器的哪个点添加 NLP 管道中的转换以填充张量?

问题描述

我最近开始关注 FASTAI,并试图超越使用认工具并实现我自己的 PyTorch 架构。但是,我真正在苦苦挣扎的一件事是如何实现填充,以便输入张量以与 learner.fit_one_cycle(1) 一起使用的方式具有固定长度。到目前为止,我已经设法添加了填充变换,以便在查看数据加载器中的张量时填充数据集。但是,在查看处理过的文本时,它不会被填充。

我知道这里的架构不是问题,因为我之前使用 pytorch 已经能够用它创建训练循环。问题是我对 FASTAI 中的数据如何从加载器传递到精简器并在 fit_one_cycle 期间使用以及我需要在什么时候添加填充转换以便它们在学习器中正确使用的理解很差。我的假设是我需要在构建数据加载器时进行填充,但是我如何知道管道中早期转换后的最大长度?

总而言之,我应该在流程的哪个点添加填充转换?以及如何根据内置的 fastAI 转换(我想继续使用)后的最大长度确定填充量?

以下是在 google colab 上运行的代码,它显示了我到目前为止所获得的内容

# run on google colab notebooks
!pip install utils
!pip install fastcore
!pip install fastai==2.4

# imports
import fastai
from fastai.text.all import *
from fastcore.foundation import L
from utils import *
import pandas as pd
from torchtext.datasets import IMDB
from torchtext.data.utils import get_tokenizer
tokenizer = get_tokenizer('basic_english')
from torchtext.vocab import Vocab
from collections import Counter

# download the data and convert to dataframe
train_iter,_ = IMDB()
imdb_data = pd.DataFrame(train_iter)
imdb_data.columns = ["class","text"]

# for quick running lets take a small subset
imdb_data["len"] = imdb_data.text.apply(lambda x:  len(x.split()))
imdb_data = imdb_data[imdb_data.len <= 100].reset_index(drop = True)
imdb_data = imdb_data.groupby('class').apply(lambda s: s.sample(5)).reset_index(drop=True)

# download again for using iter to make vocab
train_iter,_ = IMDB()
# generate vocab
tokenizer = get_tokenizer('basic_english')
counter = Counter()
for line in train_iter:
    counter.update(tokenizer(line[1]))

vocab = make_vocab(counter)

# Create the Datablock
clas_block = DataBlock(
    blocks = (TextBlock.from_df('text',vocab = vocab,seq_len = 1),CategoryBlock),get_x = ColReader('text'),get_y = ColReader('class'),splitter = RandomSplitter(0.2))

# create the DataLoader
clas_dl = clas_block.DataLoaders(imdb_data,bs = 1,shuffle=True,drop_last = True)

# work out the longest tensor post initial processing
lengths = []
for row in clas_dl.dataset:
  lengths.append(len(row[0]))

for row in clas_dl.valid_ds:
  lengths.append(len(row[0]))

max_len = max(lengths)
print(max_len)

# use this new max length to pad out 
clas_dl.tfms[0].add(Transform(lambda x: pad_chunk(x,seq_len=1,pad_idx=1,pad_len = max_len)))
clas_dl.valid.tfms[0].add(Transform(lambda x: pad_chunk(x,pad_len = max_len)))

如果我查看 clas_dl 中的内容并查看项目,我会得到没有填充的内置处理文本。

clas_dl.items

但是,如果我查看数据集,我可以清楚地看到张量已被填充。我的假设是学习者将这个数据集传递给模型。但是,当我运行 learn.fit_once_cycle(1) 时,我可以从错误消息中看到输入张量的大小是 clas_dl.items 而不是下面的填充数据集。

for row in clas_dl.dataset:
  print(row)

为了完整起见,这是学习者(我知道它不是模型,所以我没有提供拱门)。任何需要基于最大长度的固定大小张量的模型都应该复制这个问题。 learn = Learner(clas_dl,model,loss_func= BCEWithLogitsLossFlat(),metrics = accuracy)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)