Pytorch1.0入门实战三:ResNet实现cifar-10分类,利用visdom可视化训练过程

  人的理想志向每每和他的能力成正比。 —— 约翰逊python

  最近一直在使用pytorch深度学习框架,很想用pytorch搞点事情出来,可是框架中一些基本的原理得懂!本次,利用pytorch实现ResNet神经网络对cifar-10数据集进行分类。CIFAR-10包含60000张32*32的彩色图像,彩色图像,即分别有RGB三个通道,一共有10类图片,每一类图片有6000张,其类别有飞机、鸟、猫、狗等。网络

  注意,若是直接使用torch.torchvision的models中的ResNet18或者ResNet34等等,你会遇到最后的特征图大小不够用的状况,由于cifar-10的图像大小只有32*32,所以须要单独设计ResNet的网络结构!可是采用其余的数据集,好比imagenet的数据集,其图的大小为224*224便不会遇到这种状况。app

一、运行环境:框架

  •   python3.6.8
  •  win10
  •  GTX1060
  •  cuda9.0+cudnn7.4+vs2017
  •  torch1.0.1
  •  visdom0.1.8.8

二、实战cifar10步骤以下:dom

  • 使用torchvision加载并预处理CIFAR-10数据集
  • 定义网络
  • 定义损失函数和优化器
  • 训练网络,计算损失,清除梯度,反向传播,更新网络参数
  • 测试网络

三、代码ide

 1 import torch  2 import torch.nn as nn  3 from torch.autograd import Variable  4 from torchvision import datasets,transforms  5 from torch.utils.data import dataloader  6 import torchvision.models as models  7 from tqdm import tgrange  8 import torch.optim as optim  9 import numpy  10 import visdom  11 import torch.nn.functional as F  12 
 13 vis = visdom.Visdom()  14 batch_size = 100
 15 lr = 0.001
 16 momentum = 0.9
 17 epochs = 100
 18 
 19 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  20 
 21 def conv3x3(in_channels,out_channels,stride = 1):  22     return nn.Conv2d(in_channels,out_channels,kernel_size=3, stride = stride, padding=1, bias=False)  23 class ResidualBlock(nn.Module):  24     def __init__(self, in_channels, out_channels, stride = 1, shotcut = None):  25         super(ResidualBlock, self).__init__()  26         self.conv1 = conv3x3(in_channels, out_channels,stride)  27         self.bn1 = nn.BatchNorm2d(out_channels)  28         self.relu = nn.ReLU(inplace=True)  29 
 30         self.conv2 = conv3x3(out_channels, out_channels)  31         self.bn2 = nn.BatchNorm2d(out_channels)  32         self.shotcut = shotcut  33 
 34     def forward(self, x):  35         residual = x  36         out = self.conv1(x)  37         out = self.bn1(out)  38         out = self.relu(out)  39         out = self.conv2(out)  40         out = self.bn2(out)  41         if self.shotcut:  42             residual = self.shotcut(x)  43         out += residual  44         out = self.relu(out)  45         return out  46 class ResNet(nn.Module):  47     def __init__(self, block, layer, num_classes = 10):  48         super(ResNet, self).__init__()  49         self.in_channels = 16
 50         self.conv = conv3x3(3,16)  51         self.bn = nn.BatchNorm2d(16)  52         self.relu = nn.ReLU(inplace=True)  53 
 54         self.layer1 = self.make_layer(block, 16, layer[0])  55         self.layer2 = self.make_layer(block, 32, layer[1], 2)  56         self.layer3 = self.make_layer(block, 64, layer[2], 2)  57         self.avg_pool = nn.AvgPool2d(8)  58         self.fc = nn.Linear(64, num_classes)  59 
 60     def make_layer(self, block, out_channels, blocks, stride = 1):  61         shotcut = None  62         if(stride != 1) or (self.in_channels != out_channels):  63             shotcut = nn.Sequential(  64                 nn.Conv2d(self.in_channels, out_channels,kernel_size=3,stride = stride,padding=1),  65  nn.BatchNorm2d(out_channels))  66 
 67         layers = []  68  layers.append(block(self.in_channels, out_channels, stride, shotcut))  69 
 70         for i in range(1, blocks):  71  layers.append(block(out_channels, out_channels))  72             self.in_channels = out_channels  73         return nn.Sequential(*layers)  74 
 75     def forward(self, x):  76         x = self.conv(x)  77         x = self.bn(x)  78         x = self.relu(x)  79         x = self.layer1(x)  80         x = self.layer2(x)  81         x = self.layer3(x)  82         x = self.avg_pool(x)  83         x = x.view(x.size(0), -1)  84         x = self.fc(x)  85         return x  86 
 87 #标准化数据集
 88 data_tf = transforms.Compose(  89  [transforms.ToTensor(),  90     transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])  91 
 92 train_dataset = datasets.CIFAR10(root = './datacifar/',  93                               train=True,  94                               transform = data_tf,  95                               download=False)  96 
 97 test_dataset =datasets.CIFAR10(root = './datacifar/',  98                             train=False,  99                             transform= data_tf, 100                             download=False) 101 # print(test_dataset[0][0])
102 # print(test_dataset[0][0][0])
103 print("训练集的大小:",len(train_dataset),len(train_dataset[0][0]),len(train_dataset[0][0][0]),len(train_dataset[0][0][0][0])) 104 print("测试集的大小:",len(test_dataset),len(test_dataset[0][0]),len(test_dataset[0][0][0]),len(test_dataset[0][0][0][0])) 105 #创建一个数据迭代器
106 train_loader = torch.utils.data.DataLoader(dataset = train_dataset, 107                                           batch_size = batch_size, 108                                           shuffle = True) 109 test_loader = torch.utils.data.DataLoader(dataset = test_dataset, 110                                          batch_size = batch_size, 111                                          shuffle = False) 112 '''
113 print(train_loader.dataset) 114 ----> 115 Dataset CIFAR10 116  Number of datapoints: 50000 117  Split: train 118  Root Location: ./datacifar/ 119  Transforms (if any): Compose( 120  ToTensor() 121  Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) 122  ) 123  Target Transforms (if any): None 124 '''
125 
126 model = ResNet(ResidualBlock, [3,3,3], 10).to(device) 127 
128 criterion = nn.CrossEntropyLoss()#定义损失函数
129 optimizer = optim.SGD(model.parameters(),lr=lr,momentum=momentum) 130 print(model) 131 
132 if __name__ == '__main__': 133     global_step = 0 134     for epoch in range(epochs): 135         for i,train_data in enumerate(train_loader): 136             # print("i:",i)
137             # print(len(train_data[0]))
138             # print(len(train_data[1]))
139             inputs,label = train_data 140             inputs = Variable(inputs).cuda() 141             label = Variable(label).cuda() 142             # print(model)
143             output = model(inputs) 144             # print(len(output))
145 
146             loss = criterion(output,label) 147  optimizer.zero_grad() 148  loss.backward() 149  optimizer.step() 150             if i % 100 == 99: 151                 print('epoch:%d | batch: %d | loss:%.03f' % (epoch + 1, i + 1, loss.item())) 152                 vis.line(X=[global_step],Y=[loss.item()],win='loss',opts=dict(title = 'train loss'),update='append') 153                 global_step = global_step +1
154             # 验证测试集
155 
156     model.eval()  # 将模型变换为测试模式
157     correct = 0 158     total = 0 159     for data_test in test_loader: 160         images, labels = data_test 161         images, labels = Variable(images).cuda(), Variable(labels).cuda() 162         output_test = model(images) 163         # print("output_test:",output_test.shape)
164         _, predicted = torch.max(output_test, 1)  # 此处的predicted获取的是最大值的下标
165         # print("predicted:", predicted)
166         total += labels.size(0) 167         correct += (predicted == labels).sum() 168     print("correct1: ", correct) 169     print("Test acc: {0}".format(correct.item() / len(test_dataset)))  # .cpu().numpy()

四、结果展现函数

loss值        epoch:100           |          batch: 500      |       loss:0.294学习

test acc      epoch: 100 test acc: 0.8363测试

五、网络结构优化

ResNet(
  (conv): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (bn): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace)
  (layer1): Sequential(
    (0): ResidualBlock(
      (conv1): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): ResidualBlock(
      (conv1): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (2): ResidualBlock(
      (conv1): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): ResidualBlock(
      (conv1): Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (shotcut): Sequential(
        (0): Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
        (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): ResidualBlock(
      (conv1): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (2): ResidualBlock(
      (conv1): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): ResidualBlock(
      (conv1): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (shotcut): Sequential(
        (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
        (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): ResidualBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (2): ResidualBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (avg_pool): AvgPool2d(kernel_size=8, stride=8, padding=0)
  (fc): Linear(in_features=64, out_features=10, bias=True)
)
相关文章
相关标签/搜索