zoukankan      html  css  js  c++  java
  • 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)
    )
  • 相关阅读:
    Python格式化输出
    每天写点shell脚本 (持续更新)
    linux limits.conf 配置
    ELK 日志分析系统
    开源大数据处理工具
    glusterFS分布式存储部署流程
    glusterFS的部署流程
    parted命令详解
    /proc文件系统
    /proc文件系统(二):/proc/<pid>/stat
  • 原文地址:https://www.cnblogs.com/shenpings1314/p/10545000.html
Copyright © 2011-2022 走看看