首先图片作为输入,格式为[3,32,32]
经过一个7*7的卷积核和一个最大池化层后进入残差结构层
class BasicBlock1(nn.Module):
def __init__(self, in_channel, out_channel):
super(BasicBlock1, self).__init__()
self.Basicblock = nn.Sequential(
nn.Conv2d(in_channel, out_channel, 3, 1, 1),
nn.Conv2d(64, 64, 3, 1, 1)
)
self.relu = nn.ReLU()
def forward(self, x):
Ret_x = self.Basicblock(x)
Ret_x = self.relu(Ret_x)
return x + Ret_x
class BasicBlock2_f(nn.Module):
def __init__(self, in_channel, out_channel):
super(BasicBlock2_f, self).__init__()
self.Basicblock = nn.Sequential(
nn.Conv2d(in_channel, out_channel, 3, 2, 1),
nn.Conv2d(128, 128, 3, 1, 1)
)
self.relu = nn.ReLU()
self.con = nn.Conv2d(in_channel, out_channel, 1, 2, 0)
def forward(self, x):
Ret_x = self.Basicblock(x)
Ret_x = self.relu(Ret_x)
don_x = self.con(x)
return don_x + Ret_x
class BasicBlock2(nn.Module):
def __init__(self, in_channel, out_channel):
super(BasicBlock2, self).__init__()
self.Basicblock = nn.Sequential(
nn.Conv2d(in_channel, out_channel, 3, 1, 1),
nn.Conv2d(128, 128, 3, 1, 1)
)
self.relu = nn.ReLU()
def forward(self, x):
Ret_x = self.Basicblock(x)
Ret_x = self.relu(Ret_x)
return Ret_x
class BasicBlock3_f(nn.Module):
def __init__(self, in_channel, out_channel):
super(BasicBlock3_f, self).__init__()
self.Basicblock = nn.Sequential(
nn.Conv2d(in_channel, out_channel, 3, 2, 1),
nn.Conv2d(256, 256, 3, 1, 1)
)
self.relu = nn.ReLU()
self.con = nn.Conv2d(128, 256, 1, 2, 0)
def forward(self, x):
Ret_x = self.Basicblock(x)
Ret_x = self.relu(Ret_x)
don_x = self.con(x)
return don_x + Ret_x
class BasicBlock3(nn.Module):
def __init__(self, in_channel, out_channel):
super(BasicBlock3, self).__init__()
self.Basicblock = nn.Sequential(
nn.Conv2d(in_channel, out_channel, 3, 1, 1),
nn.Conv2d(256, 256, 3, 1, 1)
)
self.relu = nn.ReLU()
def forward(self, x):
Ret_x = self.Basicblock(x)
Ret_x = self.relu(Ret_x)
return Ret_x
class BasicBlock4_f(nn.Module):
def __init__(self, in_channel, out_channel):
super(BasicBlock4_f, self).__init__()
self.Basicblock = nn.Sequential(
nn.Conv2d(in_channel, out_channel, 3, 2, 1),
nn.Conv2d(512, 512, 3, 1, 1)
)
self.relu = nn.ReLU()
self.con = nn.Conv2d(256, 512, 1, 2, 0)
def forward(self, x):
Ret_x = self.Basicblock(x)
Ret_x = self.relu(Ret_x)
don_x = self.con(x)
return don_x + Ret_x
class BasicBlock4(nn.Module):
def __init__(self, in_channel, out_channel):
super(BasicBlock4, self).__init__()
self.Basicblock = nn.Sequential(
nn.Conv2d(in_channel, out_channel, 3, 1, 1),
nn.Conv2d(512, 512, 3, 1, 1)
)
self.relu = nn.ReLU()
def forward(self, x):
Ret_x = self.Basicblock(x)
Ret_x = self.relu(Ret_x)
return Ret_x
最后经过一个平均池化层再进行展开线性连接。
class myResnet(nn.Module):
def __init__(self):
super(myResnet, self).__init__()
self.con1 = nn.Conv2d(3, 64, 7, 2, 3)
self.maxpool1 = nn.MaxPool2d(3, 2, 1)
self.avgpool = nn.AvgPool2d(1)
self.b1_f = BasicBlock1(64, 64)
self.b1 = BasicBlock1(64, 64)
self.b2_f = BasicBlock2_f(64, 128)
self.b2 = BasicBlock2(128, 128)
self.b3_f = BasicBlock3_f(128, 256)
self.b3 = BasicBlock3(256, 256)
self.b4_f = BasicBlock4_f(256, 512)
self.b4 = BasicBlock4(512, 512)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fl = nn.Flatten()
self.fc = nn.Linear(512, 10)
def forward(self, x):
x = self.con1(x)
x = self.maxpool1(x)
x = self.b1_f(x)
x = self.b1(x)
x = self.b2_f(x)
x = self.b2(x)
x = self.b3_f(x)
x = self.b3(x)
x = self.b4_f(x)
x = self.b4(x)
x = self.avgpool(x)
x = self.fl(x)
x = self.fc(x)
return x
resnet18是指17个卷积层以及最后一个线性连接层。
数据集导入
使用的数据集为CIFAR10数据集
transform = transforms.Compose([
transforms.Resize([224, 224]),
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5],
[0.5, 0.5, 0.5])])
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
dataset_train = torchvision.datasets.CIFAR10("data", True,
transform=transform,
download=True)
dataset_val = torchvision.datasets.CIFAR10("data", False,
transform=transform,
download=True)
dataloader_train = DataLoader(dataset_train, batch_size=100, shuffle=True)
dataloader_val = DataLoader(dataset_val, batch_size=100, shuffle=True)
#查看有无可用cuda
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
#初始化,并将神经网络放至gpu
net = myResnet().to(device)
#损失函数
cost = torch.nn.CrossEntropyLoss()
#优化器
optim = torch.optim.SGD(net.parameters(), lr=0.1)
#学习速率调节器
scheduler = StepLR(optim, step_size=3, gamma=0.1)
epochs = 10
for epoch in range(epochs):
net.train()
running_loss = 0.0
running_acc = 0.0
for data in dataloader_train:
img, label = data
img, label = img.to(device), label.to(device)
output = net(img)
optim.zero_grad()
#计算误差
loss = cost(output, label)
#反向传播
loss.backward()
#梯度裁剪
torch.nn.utils.clip_grad_norm_(net.parameters(), max_norm=1)
#随机梯度下降优化
optim.step()
#累加损失
running_loss += loss.item()
#获取预测
_, pred = torch.max(output.data, 1)
#计算正确数量
running_acc += torch.sum(pred == label.data)
scheduler.step()
test_corr = 0.0
test_loss = 0.0
net.eval()
with torch.no_grad():
for data in dataloader_val:
img, label = data
img, label = img.to(device) , label.to(device)
output = net(img)
#计算损失
loss = cost(output, label)
#损失累加
test_loss += loss.item()
#获取预测
_, pred = torch.max(output.data, 1)
#计算正确数量
test_corr += torch.sum(pred == label.data)
#每个训练周期结束后打印周期数
print("Epoch %d:" % epoch)
#打印训练损失值以及训练准确率(准确数量占数据集长度之比)
print(" Training Loss: %.4f, Accuracy: %.2f%%" % (running_loss, running_acc / len(dataset_train) * 100))
#打印验证损失值以及验证准确率(验证准确数量占数据集长度之比)
print(" Testing Loss: %.4f, Accuracy: %.2f%%" % (test_loss, test_corr / len(dataset_val) * 100))
用cpu训练的速度十分慢,因此选用谷歌云计算服务colab训练了10个epoches:
十个epoch的top1准确率可以达到47%可见效果还是不错的