fastai文本分类使用自定义PyTorch DataLoader报RecursionError咨询
问题原因与解决方案
报错的核心原因有两个:
- fastai的
show_batch()、text_classifier_learner默认要求数据集返回**(输入样本, 标签)的元组格式**,你当前返回的是字典结构,fastai内部解析字段时触发了无限递归调用,最终超出递归深度。 - 缺少文本预处理步骤:AWD_LSTM模型要求输入是数值化的token序列,直接传入原始文本字符串也会导致后续训练报错。
必要调整步骤
- 补充文本预处理与标签映射:fastai的文本分类流程依赖分词、数值化操作,同时需要将字符串标签映射为整数索引适配损失函数。
- 修改自定义Dataset返回格式:将
__getitem__的返回值从字典改为(文本张量, 标签整数)的元组。 - 划分训练/验证集:
DataLoaders.from_dsets需要至少传入训练集、验证集两个数据集对象。
修改后可运行代码
from torch.utils.data import Dataset import pandas as pd from fastai.text.all import * from torch.nn import CrossEntropyLoss # 读取数据 data = pd.read_json("text.jsonl", lines = True) # 1. 预处理:标签映射、文本分词数值化 # 标签转索引 label_vocab = data['label'].unique().tolist() label2idx = {l:i for i,l in enumerate(label_vocab)} # fastai文本处理流水线 tok = Tokenizer.from_df(text_cols='text') num = Numericalize() # 先处理所有文本得到词汇表 tokenized_texts = tok(data) num.setup(tokenized_texts) processed_texts = num(tokenized_texts) class text_dataset(Dataset): def __init__(self, texts, labels): self.texts = texts self.labels = labels self.n_classes = len(label_vocab) self.vocab = label_vocab def __len__(self): return len(self.labels) def __getitem__(self, idx): # 2. 返回元组,不要返回字典 return self.texts[idx], label2idx[self.labels.iloc[idx]] # 3. 划分训练集和验证集,按8:2比例 split_idx = int(len(data)*0.8) train_ds = text_dataset(processed_texts[:split_idx], data['label'].iloc[:split_idx]) valid_ds = text_dataset(processed_texts[split_idx:], data['label'].iloc[split_idx:]) # 构建DataLoaders my_dls = DataLoaders.from_dsets(train_ds, valid_ds, bs=16) # 给dls添加必要属性,让text_classifier_learner可以正确读取 my_dls.vocab = num.vocab my_dls.c = len(label_vocab) # 现在可以正常运行show_batch和训练了 my_dls.show_batch() learn = text_classifier_learner(my_dls, AWD_LSTM, drop_mult=0.5, metrics=accuracy, loss_func = CrossEntropyLoss()) learn.fit_one_cycle(1)
补充说明
如果确实需要保留字典返回格式,可以给自定义Dataset添加shows方法告诉fastai如何解析字段、如何展示样本,不过改动成本比直接返回元组高,对于简单文本分类场景直接返回元组是最优解。
内容的提问来源于stack exchange,提问作者Petr
相关产品推荐
相关产品推荐

