准确率 95.31%
几个关键点:
1、改模型:原始的resnet18首层使用的7x7的卷积核,CIFAR10图片太小不适合,要改成3x3的,步长和padding都要一并改成1。因为图太小,最大池化层也同样没用,删掉。最后一个全连接层输出改成10。
2、图片增强不要太多,只要训练集和验证集结果没有出现10%以上的差距都算不上过拟合。
3、学习率从0.1开始,10个epoch跑完loss值没有下降的话衰减50%
4、损失函数用CrossEntropyLoss
5、优化器用SGD
改模型代码:
# 定义模型
model_ft = torchvision.models.resnet18(pretrained=False)
# 修改模型
model_ft.conv1 = nn.Conv2d(3, 64, 3, stride=1, padding=1, bias=False) # 首层改成3x3卷积核
model_ft.maxpool = nn.MaxPool2d(1, 1, 0) # 图像太小 本来就没什么特征 所以这里通过1x1的池化核让池化层失效
num_ftrs = model_ft.fc.in_features # 获取(fc)层的输入的特征数
model_ft.fc = nn.Linear(num_ftrs, 10)
这里的最大池化层实在是想不出什么好办法直接删掉,只能用这个办法让其失效
如果不想用原始的模型也能自己写个
下面是我是随便写的一个
# 实现Resnet18
"""
ResNet18 是由17个卷积层和1个全连接层组成
下采样层的1x1卷积不算
池化不算 激活不算
主要思想是一个基础层 然后反复的重复这个基础层
"""
import torch
from torch import nn
# 基础块
from torch.nn import Conv2d, BatchNorm2d, ReLU, MaxPool2d, AdaptiveAvgPool2d, Linear
class BasicBlock(nn.Module):
def __init__(self, in_features, out_features) -> None:
super().__init__()
self.in_features = in_features
self.out_features = out_features
stride = 1
_features = out_features
if self.in_features != self.out_features:
# 在输入通道和输出通道不相等的情况下计算通道是否为2倍差值
if self.out_features / self.in_features == 2.0:
stride = 2 # 在输出特征是输入特征的2倍的情况下 要想参数不翻倍 步长就必须翻倍
else:
raise ValueError("输出特征数最多为输入特征数的2倍!")
self.conv1 = Conv2d(in_features, _features, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = BatchNorm2d(_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
self.relu = ReLU(inplace=True)
self.conv2 = Conv2d(_features, _features, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = BatchNorm2d(_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
# 下采样
self.downsample = None if self.in_features == self.out_features else nn.Sequential(
Conv2d(in_features, out_features, kernel_size=1, stride=2, bias=False),
BatchNorm2d(out_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
def forward(self, x):
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
# 输入输出的特征数不同时使用下采样层
if self.in_features != self.out_features:
identity = self.downsample(x)
# 残差求和
out += identity
out = self.relu(out)
return out
class ResNet18(nn.Module):
def __init__(self) -> None:
super().__init__()
self.conv1 = Conv