PyTorch-Lightning执行trainer.predict()时出现AttributeError错误求助
问题:PyTorch-Lightning预测阶段触发AttributeError错误
基于PyTorch-Lightning官方MNIST训练示例添加预测步骤后,执行trainer.predict(model)时触发如下错误:
AttributeError: 'list' object has no attribute 'flatten'
已按照教程添加predict_step、predict_dataloader方法,并在setup函数中配置了predict阶段,但问题仍未解决,完整运行代码如下:
import os import torch from pytorch_lightning import LightningModule, Trainer from pytorch_lightning.callbacks.progress import TQDMProgressBar from pytorch_lightning.loggers import CSVLogger from torch import nn from torch.nn import functional as F from torch.utils.data import DataLoader, random_split from torchmetrics import Accuracy from torchvision import transforms from torchvision.datasets import MNIST PATH_DATASETS = os.environ.get("PATH_DATASETS", ".") BATCH_SIZE = 256 if torch.cuda.is_available() else 64 class LitMNIST(LightningModule): def __init__(self, data_dir=PATH_DATASETS, hidden_size=64, learning_rate=2e-4): super().__init__() # Set our init args as class attributes self.data_dir = data_dir self.hidden_size = hidden_size self.learning_rate = learning_rate # Hardcode some dataset specific attributes self.num_classes = 10 self.dims = (1, 28, 28) channels, width, height = self.dims self.transform = transforms.Compose( [ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)), ] ) # Define PyTorch model self.model = nn.Sequential( nn.Flatten(), nn.Linear(channels * width * height, hidden_size), nn.ReLU(), nn.Dropout(p=0.9), nn.Linear(hidden_size, hidden_size), nn.ReLU(), nn.Dropout(0.1), nn.Linear(hidden_size, self.num_classes), ) self.val_accuracy = Accuracy(task='multiclass', num_classes=10) # I fixed this since the code from the tutorial didn't work self.test_accuracy = Accuracy(task='multiclass', num_classes=10) # I fixed this since the code from the tutorial didn't work def forward(self, x): x = self.model(x) return F.log_softmax(x, dim=1) def training_step(self, batch, batch_idx): x, y = batch logits = self(x) loss = F.nll_loss(logits, y) return loss def validation_step(self, batch, batch_idx): x, y = batch logits = self(x) loss = F.nll_loss(logits, y) preds = torch.argmax(logits, dim=1) self.val_accuracy.update(preds, y) # Calling self.log will surface up scalars for you in TensorBoard self.log("val_loss", loss, prog_bar=True) self.log("val_acc", self.val_accuracy, prog_bar=True) def test_step(self, batch, batch_idx): x, y = batch logits = self(x) loss = F.nll_loss(logits, y) preds = torch.argmax(logits, dim=1) self.test_accuracy.update(preds, y) # Calling self.log will surface up scalars for you in TensorBoard self.log("test_loss", loss, prog_bar=True) self.log("test_acc", self.test_accuracy, prog_bar=True) def predict_step(self, batch, batch_idx, dataloader_idx=0): return self(batch) def configure_optimizers(self): optimizer = torch.optim.Adam(self.parameters(), lr=self.learning_rate) return optimizer #################### # DATA RELATED HOOKS #################### def prepare_data(self): # download MNIST(self.data_dir, train=True, download=True) MNIST(self.data_dir, train=False, download=True) def setup(self, stage=None): # Assign train/val datasets for use in dataloaders if stage == "fit" or stage is None: mnist_full = MNIST(self.data_dir, train=True, transform=self.transform) self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000]) # Assign test dataset for use in dataloader(s) if stage == "test" or stage is None: self.mnist_test = MNIST(self.data_dir, train=False, transform=self.transform) if stage == "predict": self.mnist_predict = MNIST(self.data_dir, train=False, transform=self.transform) def train_dataloader(self): return DataLoader(self.mnist_train, batch_size=BATCH_SIZE) def val_dataloader(self): return DataLoader(self.mnist_val, batch_size=BATCH_SIZE) def test_dataloader(self): return DataLoader(self.mnist_test, batch_size=BATCH_SIZE) def predict_dataloader(self): return DataLoader(self.mnist_predict, batch_size=BATCH_SIZE) model = LitMNIST(hidden_size=2) trainer = Trainer( accelerator="auto", devices=1 if torch.cuda.is_available() else None, # limiting got iPython runs max_epochs=3, callbacks=[TQDMProgressBar(refresh_rate=20)], logger=CSVLogger(save_dir="logs/"), ) trainer.fit(model) predict = trainer.predict(model)
问题原因与修复方案
错误根源
MNIST数据集的DataLoader返回的batch是**(图像张量, 标签)**的元组,而当前predict_step中直接将整个batch传入self()(即forward方法),导致forward接收的是一个元组而非图像张量。模型中的nn.Flatten()层只能处理张量,无法处理元组/列表,因此触发'list' object has no attribute 'flatten'错误。
修复方法
修改predict_step方法,从batch中提取图像张量部分,忽略标签后再传入模型:
def predict_step(self, batch, batch_idx, dataloader_idx=0): x, _ = batch # 提取图像张量x,丢弃标签 return self(x)
修改后,forward方法将接收到正确的图像张量,模型即可正常执行预测步骤。
内容的提问来源于stack exchange,提问作者yshicht
相关产品推荐
相关产品推荐

