ResNet34作为计算机视觉领域的经典卷积神经网络架构,在图像分类任务中展现了出色的性能表现。这个项目将带您从零开始实现一个完整的图像分类流程,使用PyTorch框架搭建ResNet34模型,并在公开数据集上进行训练和评估。
提示:虽然ResNet34已经发布多年,但它在中小规模数据集上的表现依然优于许多新模型,特别是在计算资源有限的情况下。
ResNet34的34层深度在准确率和计算效率之间取得了良好平衡:
这种规模的模型特别适合:
推荐使用以下配置:
bash复制conda create -n resnet34 python=3.8
conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch
pip install opencv-python matplotlib tqdm
假设我们使用CIFAR-10数据集:
python复制from torchvision import transforms
train_transform = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.RandomRotation(15),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
test_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
注意:对于不同尺寸的输入图像,需要调整第一层卷积的kernel_size和stride参数
基础残差块的核心代码:
python复制class BasicBlock(nn.Module):
expansion = 1
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(
in_channels, out_channels,
kernel_size=3, stride=stride, padding=1, bias=False
)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(
out_channels, out_channels,
kernel_size=3, stride=1, padding=1, bias=False
)
self.bn2 = nn.BatchNorm2d(out_channels)
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != self.expansion * out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, self.expansion*out_channels,
kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(self.expansion*out_channels)
)
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += self.shortcut(x)
out = F.relu(out)
return out
ResNet34的层配置:
python复制def _make_layer(self, block, out_channels, blocks, stride=1):
strides = [stride] + [1]*(blocks-1)
layers = []
for stride in strides:
layers.append(block(self.in_channels, out_channels, stride))
self.in_channels = out_channels * block.expansion
return nn.Sequential(*layers)
推荐使用余弦退火配合热启动:
python复制optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4)
scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(
optimizer, T_0=10, T_mult=2, eta_min=1e-5
)
| 参数 | 推荐值 | 说明 |
|---|---|---|
| Batch Size | 128 | 根据GPU显存调整 |
| 初始LR | 0.1 | 配合SGD使用 |
| 动量 | 0.9 | 标准值 |
| 权重衰减 | 5e-4 | 防止过拟合 |
| Epochs | 200 | 充分训练 |
除了准确率,建议加入:
python复制from sklearn.metrics import classification_report
def evaluate(model, test_loader):
model.eval()
all_preds = []
all_targets = []
with torch.no_grad():
for inputs, targets in test_loader:
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
all_preds.extend(preds.cpu().numpy())
all_targets.extend(targets.cpu().numpy())
print(classification_report(all_targets, all_preds))
return accuracy_score(all_targets, all_preds)
部署时可考虑:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 损失不下降 | 学习率太小 | 增大LR或检查初始化 |
| 准确率波动大 | Batch Size太小 | 增大Batch Size或使用梯度累积 |
| 验证集性能差 | 过拟合 | 增加数据增强/正则化 |
| GPU利用率低 | 数据加载瓶颈 | 使用DALI加速或增加workers |
对于追求更高性能的场景:
我在实际项目中发现,合理调整数据增强策略比单纯增加模型深度更能提升最终性能。对于医疗影像这类数据稀缺的领域,建议优先考虑迁移学习方案,在ImageNet预训练的基础上进行微调。