PyTorch迁移至fastai时出现AttributeError问题排查与解决
问题描述
将代码从PyTorch迁移至fastai后,执行以下训练代码:
train_loader = self.init_train_dl(self.df, self.train_subjects) test_loader = self.init_val_dl(self.df, self.val_subjects) data = DataLoaders(train_loader, test_loader) learn = Learner(data, AlexNet3D(4608), loss_func=F.mse_loss, opt_func=Adam, metrics=accuracy) # learn = Learner(data, Net()) learn.fit_one_cycle(self.cli_args.epochs, self.cli_args.lr)
训练时触发如下异常:
epoch train_loss valid_loss accuracy time Epoch 1/1 : |----------------------------------------| 0.00% [0/135 00:00<?]python-BaseException Traceback (most recent call last): File "/home/faird/shared/code/external/envs/miniconda3/mini3/envs/cabinet/lib/python3.9/contextlib.py", line 137, in __exit__ self.gen.throw(typ, value, traceback) File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 162, in added_cbs try: yield File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 264, in fit self._with_events(self._do_fit, 'fit', CancelFitException, self._end_cleanup) File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 199, in _with_events try: self(f'before_{event_type}'); f() File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 253, in _do_fit self._with_events(self._do_epoch, 'epoch', CancelEpochException) File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 199, in _with_events try: self(f'before_{event_type}'); f() File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 247, in _do_epoch self._do_epoch_train() File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 239, in _do_epoch_train self._with_events(self.all_batches, 'train', CancelTrainException) File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 199, in _with_events try: self(f'before_{event_type}'); f() File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 205, in all_batches for o in enumerate(self.dl): self.one_batch(*o) File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 235, in one_batch self._with_events(self._do_one_batch, 'batch', CancelBatchException) File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 199, in _with_events try: self(f'before_{event_type}'); f() File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/fastai/learner.py", line 219, in _do_one_batch self.loss_grad = self.loss_func(self.pred, *self.yb) File "/home/miran045/reine097/projects/AlexNet_Abrol2021/venv/lib/python3.9/site-packages/torch/nn/functional.py", line 3101, in mse_loss if not (target.size() == input.size()): AttributeError: 'list' object has no attribute 'size'
问题成因
- 核心问题是fastai的
Learner在调用损失函数时,会将目标值yb以列表形式传入,但PyTorch原生的F.mse_loss仅接收PyTorch张量,直接传入列表会触发AttributeError(列表没有size()方法)。 - 另一个可能的原因是数据加载器
init_train_dl/init_val_dl返回的batch格式不符合预期:比如每个batch返回(输入张量, [目标张量])而非(输入张量, 目标张量),导致yb被包装成列表。
修复方案
方案1:包装损失函数适配列表输入
用lambda或自定义函数从yb列表中提取目标张量,再传入MSE损失:
# 用lambda快速包装 learn = Learner(data, AlexNet3D(4608), loss_func=lambda pred, yb: F.mse_loss(pred, yb[0]), opt_func=Adam, metrics=...)
或者自定义更健壮的损失函数:
def mse_loss_fastai(pred, yb): # 兼容列表或张量形式的目标 target = yb[0] if isinstance(yb, list) else yb return F.mse_loss(pred, target) learn = Learner(data, AlexNet3D(4608), loss_func=mse_loss_fastai, opt_func=Adam, metrics=...)
方案2:修正数据加载器的返回格式
检查init_train_dl和init_val_dl对应的数据集类,确保__getitem__方法返回单个张量的目标,而非列表:
错误示例
def __getitem__(self, idx): x = self.data[idx] y = [self.targets[idx]] # 返回列表形式的目标 return x, y
修正后
def __getitem__(self, idx): x = self.data[idx] y = self.targets[idx] # 返回单个张量目标 return x, y
额外提示
当前使用的accuracy是分类任务的指标,而MSE损失对应回归任务,两者不匹配。建议替换为回归任务适用的指标,比如fastai内置的rmse(均方根误差):
from fastai.metrics import rmse learn = Learner(data, AlexNet3D(4608), loss_func=mse_loss_fastai, opt_func=Adam, metrics=rmse)
内容的提问来源于stack exchange,提问作者Paul Reiners
相关产品推荐
相关产品推荐

