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

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

  最近一直在使用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便不会遇到这种情况。

1、运行环境:

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

2、实战cifar10步骤如下:

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

3、代码

  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()

4、结果展示

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

test acc      epoch: 100 test acc: 0.8363

5、网络结构

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)
)

 

posted @ 2019-03-17 19:05  泽积  阅读(3934)  评论(2编辑  收藏  举报