无预训练VGG16训练21类图像分类遇索引错误,求训练方案
21分类任务中VGG16训练报错与训练指南
一、解决IndexError: Target X is out of bounds报错
这个报错的核心原因是模型输出的类别数量与标签的取值范围不匹配。你的任务是21分类,模型最后一层的输出神经元数量必须是21,且标签的取值范围必须是0~20(CrossEntropyLoss要求标签是从0开始的连续整数索引)。
你需要检查这几个点:
- 模型输出层设置:确认替换VGG16全连接层时,是否确实设置了21个输出神经元。比如代码里是不是误写成
nn.Linear(4096, 20)而非21? - 标签提取逻辑:自定义
lungDataset类中,提取标签的代码是否把类别映射成了0~20的整数?比如如果文件夹名称是class1到class21,直接转成整数会得到1~21,这就会导致标签超出模型输出的索引范围(模型输出索引是0~20),需要做减1处理。 - 数据集完整性:检查所有样本的标签是否都在
0~20范围内,有没有某个样本的标签被错误映射成大于20或负数的情况。
二、DataLoader功能解释
DataLoader是PyTorch里用来高效加载训练/测试数据的工具,核心作用包括:
- 批量处理:把Dataset里的单个样本打包成指定大小的批次(比如
batch_size=32),避免一次性加载所有数据占满内存,同时符合模型批量训练的要求。 - 数据打乱:训练时开启
shuffle=True,每次epoch打乱样本顺序,避免模型学习到数据的顺序规律,提升泛化能力。 - 多进程加载:通过
num_workers参数设置多进程,在训练模型的同时异步加载下一批数据,提升训练效率。 - 自动张量转换:自动把Dataset返回的numpy数组或PIL图像转换成PyTorch张量,并整理成统一的形状(比如把一批图像拼成
[batch_size, channels, height, width]的张量)。
三、无预训练VGG16的正确训练要点
因为没有预训练权重,模型所有参数都是随机初始化的,训练时需要注意这些细节:
- 数据增强:你的数据集只有2100张样本,数据量不算大,必须加入数据增强来防止过拟合。比如在
Dataset中加入:from torchvision import transforms train_transform = transforms.Compose([ transforms.RandomResizedCrop(224), # VGG16标准输入尺寸是224x224 transforms.RandomHorizontalFlip(), transforms.ColorJitter(brightness=0.2, contrast=0.2), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 用ImageNet均值标准差做归一化,稳定训练过程 ]) - 初始化调整:VGG16的全连接层需要合理初始化,比如用
nn.init.kaiming_normal_或者nn.init.xavier_normal_初始化权重,避免随机初始化导致的训练不稳定。 - 学习率设置:无预训练模型的学习率不能太高,建议初始学习率设为
1e-3~5e-3。如果用分层学习率,因为特征提取层也是随机初始化的,不需要像预训练模型那样给特征层设极低的学习率,可以让特征层和分类器层用相近的学习率(比如特征层用1e-3,分类器层用5e-3)。 - 训练轮次与早停:无预训练模型需要更多的训练轮次,建议设置3050个epoch,同时加入早停策略——当验证集损失连续35个epoch不下降时停止训练,避免过拟合。
四、损失函数的跟踪方法
跟踪损失可以帮你判断模型是否在收敛,常用的方法有两种:
- 简单日志记录:
- 定义两个列表
train_losses和val_losses,分别保存每个epoch的训练损失和验证损失。 - 在训练循环中,每计算一个batch的损失后累加,epoch结束后取平均值存入列表:
train_losses = [] val_losses = [] for epoch in range(num_epochs): train_loss = 0.0 model.train() for inputs, labels in train_loader: optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() train_loss += loss.item() * inputs.size(0) train_loss /= len(train_loader.dataset) train_losses.append(train_loss) # 验证阶段 val_loss = 0.0 model.eval() with torch.no_grad(): for inputs, labels in val_loader: outputs = model(inputs) loss = criterion(outputs, labels) val_loss += loss.item() * inputs.size(0) val_loss /= len(val_loader.dataset) val_losses.append(val_loss) # 打印日志 print(f'Epoch {epoch+1}/{num_epochs}, Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f}')
- 定义两个列表
- 可视化损失曲线:
用matplotlib把保存的损失列表画成曲线,直观观察收敛情况:
也可以用TensorBoard来记录损失,适合更复杂的训练监控。import matplotlib.pyplot as plt plt.plot(train_losses, label='Training Loss') plt.plot(val_losses, label='Validation Loss') plt.xlabel('Epoch') plt.ylabel('Loss') plt.legend() plt.show()
内容的提问来源于stack exchange,提问作者Heitor Reis
相关产品推荐
相关产品推荐

