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)
)
相關文章
相關標籤/搜索