PyTorch肺炎分类模型训练报错:'int'对象无float属性
1. 核心错误:标签赋值错误
在training_step和验证阶段方法中,你错误地将batch_idx(整数类型的批次索引)赋值给label,导致执行label.float()时,对整数调用float()方法触发AttributeError。
修正方式:
将错误的赋值代码:
x_ray, label = batch, batch_idx
改为:
x_ray, label = batch
batch是数据集返回的包含输入图像和对应标签的元组,batch_idx仅为当前批次的索引,和标签无关。
2. 验证阶段方法名错误
PyTorch Lightning中验证阶段的标准方法名是validation_step,而非你写的validation_step_outputs,框架无法识别错误的方法名,会导致验证逻辑不执行。
修正方式:
将方法名从validation_step_outputs改为validation_step。
3. Epoch结束时的指标计算错误
原代码中on_train_epoch_end和on_validation_epoch_end直接调用step方法(self.training_step())是完全错误的——这些是执行逻辑的方法,不是存储输出的容器。PyTorch Lightning会自动处理step输出的聚合,只需通过self.log的参数配置,或调用指标的compute()方法获取epoch平均结果。
修正后的epoch结束方法:
def on_train_epoch_end(self): # 计算并记录训练epoch的平均准确率,之后重置指标 self.log("Train_Epoch_ACC", self.train_acc.compute()) self.train_acc.reset() def on_validation_epoch_end(self): self.log("Val_Epoch_ACC", self.val_acc.compute()) self.val_acc.reset()
同时在step方法中,给self.log添加on_epoch=True参数,让框架自动计算epoch平均损失:
self.log("Train_Loss", loss, on_epoch=True, prog_bar=True)
4. 损失函数设备匹配问题
初始化BCEWithLogitsLoss时,pos_weight张量默认在CPU上,若模型运行在GPU会出现设备不匹配错误。需要将其绑定到模型所在设备。
修正方式:
self.loss_fn = torch.nn.BCEWithLogitsLoss(pos_weight=torch.tensor([3], device=self.device))
5. 优化器初始化问题
原代码在__init__中直接初始化优化器,可能导致多GPU训练时的参数复制异常。PyTorch Lightning推荐在configure_optimizers方法内初始化并返回优化器。
修正方式:
删除__init__中的self.optimizer = torch.optim.Adam(...),修改configure_optimizers:
def configure_optimizers(self): return torch.optim.Adam(self.model.parameters(), lr=1e-4)
完整修正后的代码
import torch import torchvision import pytorch_lightning as pl from torchmetrics import Accuracy class PneumoniaModel(pl.LightningModule): def __init__(self): super().__init__() self.model = torchvision.models.resnet18() # 替换第一层卷积为单通道输入(适配X光灰度图) self.model.conv1 = torch.nn.Conv2d(1, 64, kernel_size=(7,7), stride=(2,2), padding=(3,3), bias=False) # 替换全连接层为二分类输出 self.model.fc = torch.nn.Linear(in_features=512, out_features=1, bias=True) # 损失函数,pos_weight绑定模型设备 self.loss_fn = torch.nn.BCEWithLogitsLoss(pos_weight=torch.tensor([3], device=self.device)) # 准确率指标 self.train_acc = Accuracy(task='binary') self.val_acc = Accuracy(task='binary') def forward(self, data): pred = self.model(data) return pred def training_step(self, batch, batch_idx): x_ray, label = batch label = label.float() pred = self(x_ray)[:, 0] loss = self.loss_fn(pred, label) # 记录step和epoch的损失、准确率 self.log("Train_Loss", loss, on_epoch=True, prog_bar=True) self.train_acc(torch.sigmoid(pred), label.int()) self.log("Train_Step_ACC", self.train_acc, prog_bar=True) return loss def on_train_epoch_end(self): self.log("Train_Epoch_ACC", self.train_acc.compute()) self.train_acc.reset() def validation_step(self, batch, batch_idx): x_ray, label = batch label = label.float() pred = self(x_ray)[:, 0] loss = self.loss_fn(pred, label) # 记录验证损失和准确率 self.log("Val_Loss", loss, on_epoch=True, prog_bar=True) self.val_acc(torch.sigmoid(pred), label.int()) self.log("Val_Step_ACC", self.val_acc, prog_bar=True) def on_validation_epoch_end(self): self.log("Val_Epoch_ACC", self.val_acc.compute()) self.val_acc.reset() def configure_optimizers(self): return torch.optim.Adam(self.model.parameters(), lr=1e-4)
内容的提问来源于stack exchange,提问作者ashrafghani afrah

