05-Resnet18 图像分类

Posted 赵家小伙儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了05-Resnet18 图像分类相关的知识,希望对你有一定的参考价值。

 

图1 Resnet的残差块

 

 

 图2 Resnet18 网络架构

Cifar10 数据集的Resnet10的框架实现(Pytorch):

 import torch
 from torch import nn
 
 # ResNet18_BasicBlock-残差单元
 class ResNet18_BasicBlock(nn.Module):
     def __init__(self, input_channel, output_channel, stride, use_conv1_1):
         super(ResNet18_BasicBlock, self).__init__()
 
         # 第一层卷积
         self.conv1 = nn.Conv2d(input_channel, output_channel, kernel_size=3, stride=stride, padding=1)
         # 第二层卷积
         self.conv2 = nn.Conv2d(output_channel, output_channel, kernel_size=3, stride=1, padding=1)
 
         # 1*1卷积核,在不改变图片尺寸的情况下给通道升维
         self.extra = nn.Sequential(
             nn.Conv2d(input_channel, output_channel, kernel_size=1, stride=stride, padding=0),
             nn.BatchNorm2d(output_channel)
         )
 
         self.use_conv1_1 = use_conv1_1
 
         self.bn = nn.BatchNorm2d(output_channel)
         self.relu = nn.ReLU(inplace=True)
 
     def forward(self, x):
         out = self.bn(self.conv1(x))
         out = self.relu(out)
 
         out = self.bn(self.conv2(out))
 
         # 残差连接-(B,C,H,W)维度一致才能进行残差连接
         if self.use_conv1_1:
             out = self.extra(x) + out
 
         out = self.relu(out)
         return out
 
 
 # 构建 ResNet18 网络模型
 class ResNet18(nn.Module):
     def __init__(self):
         super(ResNet18, self).__init__()
 
         self.conv1 = nn.Sequential(
             nn.Conv2d(3, 64, kernel_size=3, stride=3, padding=1),
             nn.BatchNorm2d(64)
         )
         self.block1_1 = ResNet18_BasicBlock(input_channel=64, output_channel=64, stride=1, use_conv1_1=False)
         self.block1_2 = ResNet18_BasicBlock(input_channel=64, output_channel=64, stride=1, use_conv1_1=False)
 
         self.block2_1 = ResNet18_BasicBlock(input_channel=64, output_channel=128, stride=2, use_conv1_1=True)
         self.block2_2 = ResNet18_BasicBlock(input_channel=128, output_channel=128, stride=1, use_conv1_1=False)
 
         self.block3_1 = ResNet18_BasicBlock(input_channel=128, output_channel=256, stride=2, use_conv1_1=True)
         self.block3_2 = ResNet18_BasicBlock(input_channel=256, output_channel=256, stride=1, use_conv1_1=False)
 
         self.block4_1 = ResNet18_BasicBlock(input_channel=256, output_channel=512, stride=2, use_conv1_1=True)
         self.block4_2 = ResNet18_BasicBlock(input_channel=512, output_channel=512, stride=1, use_conv1_1=False)
 
         self.FC_layer = nn.Linear(512 * 1 * 1, 10)
 
         self.adaptive_avg_pool2d = nn.AdaptiveAvgPool2d((1,1))
         self.relu = nn.ReLU(inplace=True)
 
     def forward(self, x):
 
         x = self.relu(self.conv1(x))
 
         # ResNet18-网络模型
         x = self.block1_1(x)
         x = self.block1_2(x)
         x = self.block2_1(x)
         x = self.block2_2(x)
         x = self.block3_1(x)
         x = self.block3_2(x)
         x = self.block4_1(x)
         x = self.block4_2(x)
         
         # 平均值池化
         x = self.adaptive_avg_pool2d(x)
         
         # 数据平坦化处理,为接下来的全连接层做准备
         x = x.view(x.size(0), -1)
         x = self.FC_layer(x)
 
         return x

classfyNet_main.py

 import torch
 from torch.utils.data import DataLoader
 from torch import nn, optim
 from torchvision import datasets, transforms
 
 from matplotlib import pyplot as plt
 
 
 import time
 
 from Lenet5 import Lenet5_new
 from Resnet18 import ResNet18
 
 def main():
     
     print("Load datasets...")
     
     # transforms.RandomHorizontalFlip(p=0.5)---以0.5的概率对图片做水平横向翻转
     # transforms.ToTensor()---shape从(H,W,C)->(C,H,W), 每个像素点从(0-255)映射到(0-1):直接除以255
     # transforms.Normalize---先将输入归一化到(0,1),像素点通过"(x-mean)/std",将每个元素分布到(-1,1)
     transform_train = transforms.Compose([
                         transforms.RandomHorizontalFlip(p=0.5),
                         transforms.ToTensor(),
                         transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
                     ])
 
     transform_test = transforms.Compose([
                         transforms.ToTensor(),
                         transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
                     ])
     
     # 内置函数下载数据集
     train_dataset = datasets.CIFAR10(root="./data/Cifar10/", train=True, 
                                      transform = transform_train,
                                      download=True)
     test_dataset = datasets.CIFAR10(root = "./data/Cifar10/", 
                                     train = False, 
                                     transform = transform_test,
                                     download=True)
     
     print(len(train_dataset), len(test_dataset))
     
     Batch_size = 64
     train_loader = DataLoader(train_dataset, batch_size=Batch_size,  shuffle = True)
     test_loader = DataLoader(test_dataset, batch_size = Batch_size, shuffle = False)
     
     # 设置CUDA
     device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
 
     # 初始化模型
     # 直接更换模型就行,其他无需操作
     # model = Lenet5_new().to(device)
     model = ResNet18().to(device)
     
     # 构造损失函数和优化器
     criterion = nn.CrossEntropyLoss() # 多分类softmax构造损失
     opt = optim.SGD(model.parameters(), lr=0.001, momentum=0.8, weight_decay=0.001)
     
     # 动态更新学习率 ------每隔step_size : lr = lr * gamma
     schedule = optim.lr_scheduler.StepLR(opt, step_size=10, gamma=0.6, last_epoch=-1)
     
     # 开始训练
     print("Start Train...")
 
     epochs = 100
    
     loss_list = []
     train_acc_list =[]
     test_acc_list = []
     epochs_list = []
     
     for epoch in range(0, epochs):
          
         start = time.time()
         
         model.train()
         
         running_loss = 0.0
         batch_num = 0
         
         for i, (inputs, labels) in enumerate(train_loader):
             
             inputs, labels = inputs.to(device), labels.to(device)
             
             # 将数据送入模型训练
             outputs = model(inputs)
             # 计算损失
             loss = criterion(outputs, labels).to(device)
             
             # 重置梯度
             opt.zero_grad()
             # 计算梯度,反向传播
             loss.backward()
             # 根据反向传播的梯度值优化更新参数
             opt.step()
             
             # 100个batch的 loss 之和
             running_loss += loss.item()
             # loss_list.append(loss.item())
             batch_num+=1
             
             
         epochs_list.append(epoch)
             
         # 每一轮结束输出一下当前的学习率 lr
         lr_1 = opt.param_groups[0][\'lr\']
         print("learn_rate:%.15f" % lr_1)
         schedule.step()
         
         end = time.time()
         print(\'epoch = %d/100, batch_num = %d, loss = %.6f, time = %.3f\' % (epoch+1, batch_num, running_loss/batch_num, end-start))
         running_loss=0.0    
         
         # 每个epoch训练结束,都进行一次测试验证
         model.eval()
         train_correct = 0.0
         train_total = 0
 
         test_correct = 0.0
         test_total = 0
         
          # 训练模式不需要反向传播更新梯度
         with torch.no_grad():
             
             # print("=======================train=======================")
             for inputs, labels in train_loader:
                 inputs, labels = inputs.to(device), labels.to(device)
                 outputs = model(inputs)
 
                 pred = outputs.argmax(dim=1)  # 返回每一行中最大值元素索引
                 train_total += inputs.size(0)
                 train_correct += torch.eq(pred, labels).sum().item()
           
             
             # print("=======================test=======================")
             for inputs, labels in test_loader:
                 inputs, labels = inputs.to(device), labels.to(device)
                 outputs = model(inputs)
 
                 pred = outputs.argmax(dim=1)  # 返回每一行中最大值元素索引
                 test_total += inputs.size(0)
                 test_correct += torch.eq(pred, labels).sum().item()
 
             print("train_total = %d, Accuracy = %.5f %%,  test_total= %d, Accuracy = %.5f %%" %(train_total, 100 * train_correct / train_total, test_total, 100 * test_correct / test_total))    
 
             train_acc_list.append(100 * train_correct / train_total)
             test_acc_list.append(100 * test_correct / test_total)
 
         # print("Accuracy of the network on the 10000 test images:%.5f %%" % (100 * test_correct / test_total))
         # print("===============================================")
 
     fig = plt.figure(figsize=(4, 4))
     
     plt.plot(epochs_list, train_acc_list, label=\'train_acc_list\')
     plt.plot(epochs_list, test_acc_list, label=\'test_acc_list\')
     plt.legend()
     plt.title("train_test_acc")
     plt.savefig(\'resnet18_cc_epoch_:04d.png\'.format(epochs))
     plt.close()
     
 if __name__ == "__main__":
     
     main()

 

以上是关于05-Resnet18 图像分类的主要内容,如果未能解决你的问题,请参考以下文章

如何为图像分类准备训练数据

Pytorch CIFAR10图像分类 ResNeXt篇

Pytorch CIFAR10图像分类 ResNeXt篇

Pytorch CIFAR10图像分类 ResNet篇

inference样例

inference样例