• 基于resnet网络架构训练图像分类模型


    数据预处理部分:

    • 数据增强:torchvision中transforms模块自带功能,比较实用
    • 数据预处理:torchvision中transforms也帮我们实现好了,直接调用即可
    • DataLoader模块直接读取batch数据

    网络模块设置:

    • 加载预训练模型,torchvision中有很多经典网络架构,调用起来十分方便,并且可以用人家训练好的权重参数来继续训练,也就是所谓的迁移学习
    • 需要注意的是别人训练好的任务跟咱们的可不是完全一样,需要把最后的head层改一改,一般也就是最后的全连接层,改成咱们自己的任务
    • 训练时可以全部重头训练,也可以只训练最后咱们任务的层,因为前几层都是做特征提取的,本质任务目标是一致的

    网络模型保存与测试

    • 模型保存的时候可以带有选择性,例如在验证集中如果当前效果好则保存
    • 读取模型进行实际测试
      1. import os
      2. import matplotlib.pyplot as plt
      3. %matplotlib inline
      4. import numpy as np
      5. import torch
      6. from torch import nn
      7. import torch.optim as optim
      8. import torchvision
      9. #pip install torchvision
      10. from torchvision import transforms, models, datasets
      11. #https://pytorch.org/docs/stable/torchvision/index.html
      12. import imageio
      13. import time
      14. import warnings
      15. warnings.filterwarnings("ignore")
      16. import random
      17. import sys
      18. import copy
      19. import json
      20. from PIL import Image

      数据读取与预处理操作

      1. data_dir = './flower_data/'
      2. train_dir = data_dir + '/train'
      3. valid_dir = data_dir + '/valid'

      制作好数据源:

    • data_transforms中指定了所有图像预处理操作
    • ImageFolder假设所有的文件按文件夹保存好,每个文件夹下面存贮同一类别的图片,文件夹的名字为分类的名字
      1. data_transforms = {
      2. 'train':
      3. transforms.Compose([
      4. transforms.Resize([96, 96]),
      5. transforms.RandomRotation(45),#随机旋转,-4545度之间随机选
      6. transforms.CenterCrop(64),#从中心开始裁剪
      7. transforms.RandomHorizontalFlip(p=0.5),#随机水平翻转 选择一个概率概率
      8. transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转
      9. transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
      10. transforms.RandomGrayscale(p=0.025),#概率转换成灰度率,3通道就是R=G=B
      11. transforms.ToTensor(),
      12. transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#均值,标准差
      13. ]),
      14. 'valid':
      15. transforms.Compose([
      16. transforms.Resize([64, 64]),
      17. transforms.ToTensor(),
      18. transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
      19. ]),
      20. }
      1. batch_size = 128
      2. image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'valid']}
      3. dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True) for x in ['train', 'valid']}
      4. dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'valid']}
      5. class_names = image_datasets['train'].classes
      image_datasets
      {'train': Dataset ImageFolder
           Number of datapoints: 6552
           Root location: ./flower_data/train
           StandardTransform
       Transform: Compose(
                      Resize(size=[96, 96], interpolation=bilinear, max_size=None, antialias=None)
                      RandomRotation(degrees=[-45.0, 45.0], interpolation=nearest, expand=False, fill=0)
                      CenterCrop(size=(64, 64))
                      RandomHorizontalFlip(p=0.5)
                      RandomVerticalFlip(p=0.5)
                      ColorJitter(brightness=[0.8, 1.2], contrast=[0.9, 1.1], saturation=[0.9, 1.1], hue=[-0.1, 0.1])
                      RandomGrayscale(p=0.025)
                      ToTensor()
                      Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
                  ), 'valid': Dataset ImageFolder
           Number of datapoints: 818
           Root location: ./flower_data/valid
           StandardTransform
       Transform: Compose(
                      Resize(size=[64, 64], interpolation=bilinear, max_size=None, antialias=None)
                      ToTensor()
                      Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
                  )}
      dataloaders
      {'train': ,
       'valid': }
      dataset_sizes
      {'train': 6552, 'valid': 818}
    • 读取标签对应的实际名字

      1. with open('cat_to_name.json', 'r') as f:
      2. cat_to_name = json.load(f)
      cat_to_name
      {'1': 'pink primrose',
       '10': 'globe thistle',
       '100': 'blanket flower',
       '101': 'trumpet creeper',
       '102': 'blackberry lily',
       '11': 'snapdragon',
       '12': "colt's foot",
       '13': 'king protea',
       '14': 'spear thistle',
       '15': 'yellow iris',
       '16': 'globe-flower',
       '17': 'purple coneflower',
       '18': 'peruvian lily',
       '19': 'balloon flower',
       '2': 'hard-leaved pocket orchid',
       '20': 'giant white arum lily',
       '21': 'fire lily',
       '22': 'pincushion flower',
       '23': 'fritillary',
       '24': 'red ginger',
       '25': 'grape hyacinth',
       '26': 'corn poppy',
       '27': 'prince of wales feathers',
       '28': 'stemless gentian',
       '29': 'artichoke',
       '3': 'canterbury bells',
       '30': 'sweet william',
       '31': 'carnation',
       '32': 'garden phlox',
       '33': 'love in the mist',
       '34': 'mexican aster',
       '35': 'alpine sea holly',
       '36': 'ruby-lipped cattleya',
       '37': 'cape flower',
       '38': 'great masterwort',
       '39': 'siam tulip',
       '4': 'sweet pea',
       '40': 'lenten rose',
       '41': 'barbeton daisy',
       '42': 'daffodil',
       '43': 'sword lily',
       '44': 'poinsettia',
       '45': 'bolero deep blue',
       '46': 'wallflower',
       '47': 'marigold',
       '48': 'buttercup',
       '49': 'oxeye daisy',
       '5': 'english marigold',
       '50': 'common dandelion',
       '51': 'petunia',
       '52': 'wild pansy',
       '53': 'primula',
       '54': 'sunflower',
       '55': 'pelargonium',
       '56': 'bishop of llandaff',
       '57': 'gaura',
       '58': 'geranium',
       '59': 'orange dahlia',
       '6': 'tiger lily',
       '60': 'pink-yellow dahlia',
       '61': 'cautleya spicata',
       '62': 'japanese anemone',
       '63': 'black-eyed susan',
       '64': 'silverbush',
       '65': 'californian poppy',
       '66': 'osteospermum',
       '67': 'spring crocus',
       '68': 'bearded iris',
       '69': 'windflower',
       '7': 'moon orchid',
       '70': 'tree poppy',
       '71': 'gazania',
       '72': 'azalea',
       '73': 'water lily',
       '74': 'rose',
       '75': 'thorn apple',
       '76': 'morning glory',
       '77': 'passion flower',
       '78': 'lotus lotus',
       '79': 'toad lily',
       '8': 'bird of paradise',
       '80': 'anthurium',
       '81': 'frangipani',
       '82': 'clematis',
       '83': 'hibiscus',
       '84': 'columbine',
       '85': 'desert-rose',
       '86': 'tree mallow',
       '87': 'magnolia',
       '88': 'cyclamen',
       '89': 'watercress',
       '9': 'monkshood',
       '90': 'canna lily',
       '91': 'hippeastrum',
       '92': 'bee balm',
       '93': 'ball moss',
       '94': 'foxglove',
       '95': 'bougainvillea',
       '96': 'camellia',
       '97': 'mallow',
       '98': 'mexican petunia',
       '99': 'bromelia'}
    • 加载models中提供的模型,并且直接用训练的好权重当做初始化参数

    • 第一次执行需要下载,可能会比较慢,我会提供给大家一份下载好的,可以直接放到相应路径
      1. model_name = 'resnet' #可选的比较多 ['resnet', 'alexnet', 'vgg', 'squeezenet', 'densenet', 'inception']
      2. #是否用人家训练好的特征来做
      3. feature_extract = True #都用人家特征,咱先不更新
      1. # 是否用GPU训练
      2. train_on_gpu = torch.cuda.is_available()
      3. if not train_on_gpu:
      4. print('CUDA is not available. Training on CPU ...')
      5. else:
      6. print('CUDA is available! Training on GPU ...')
      7. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
      CUDA is not available.  Training on CPU ...
    • 模型参数要不要更新
    • 有时候用人家模型,就一直用了,更不更新咱们可以自己定
      1. def set_parameter_requires_grad(model, feature_extracting):
      2. if feature_extracting:
      3. for param in model.parameters():
      4. param.requires_grad = False
      1. model_ft = models.resnet18()#18层的能快点,条件好点的也可以选152
      2. model_ft
      ResNet(
        (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
        (layer1): Sequential(
          (0): BasicBlock(
            (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=True)
            (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)
          )
          (1): BasicBlock(
            (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=True)
            (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)
          )
        )
        (layer2): Sequential(
          (0): BasicBlock(
            (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (downsample): Sequential(
              (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
              (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            )
          )
          (1): BasicBlock(
            (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          )
        )
        (layer3): Sequential(
          (0): BasicBlock(
            (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (downsample): Sequential(
              (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
              (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            )
          )
          (1): BasicBlock(
            (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          )
        )
        (layer4): Sequential(
          (0): BasicBlock(
            (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (downsample): Sequential(
              (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
              (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            )
          )
          (1): BasicBlock(
            (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          )
        )
        (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
        (fc): Linear(in_features=512, out_features=1000, bias=True)
    • 把模型输出层改成自己的

      1. def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True):
      2. model_ft = models.resnet18(pretrained=use_pretrained)
      3. set_parameter_requires_grad(model_ft, feature_extract)
      4. num_ftrs = model_ft.fc.in_features
      5. model_ft.fc = nn.Linear(num_ftrs, 102)#类别数自己根据自己任务来
      6. input_size = 64#输入大小根据自己配置来
      7. return model_ft, input_size

      设置哪些层需要训练

      1. model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
      2. #GPU还是CPU计算
      3. model_ft = model_ft.to(device)
      4. # 模型保存,名字自己起
      5. filename='checkpoint.pth'
      6. # 是否训练所有层
      7. params_to_update = model_ft.parameters()
      8. print("Params to learn:")
      9. if feature_extract:
      10. params_to_update = []
      11. for name,param in model_ft.named_parameters():
      12. if param.requires_grad == True:
      13. params_to_update.append(param)
      14. print("\t",name)
      15. else:
      16. for name,param in model_ft.named_parameters():
      17. if param.requires_grad == True:
      18. print("\t",name)
      Params to learn:
      	 fc.weight
      	 fc.bias
    • model_ft
      ResNet(
        (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
        (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (relu): ReLU(inplace=True)
        (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
        (layer1): Sequential(
          (0): BasicBlock(
            (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=True)
            (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)
          )
          (1): BasicBlock(
            (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=True)
            (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)
          )
        )
        (layer2): Sequential(
          (0): BasicBlock(
            (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (downsample): Sequential(
              (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
              (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            )
          )
          (1): BasicBlock(
            (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          )
        )
        (layer3): Sequential(
          (0): BasicBlock(
            (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (downsample): Sequential(
              (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
              (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            )
          )
          (1): BasicBlock(
            (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          )
        )
        (layer4): Sequential(
          (0): BasicBlock(
            (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (downsample): Sequential(
              (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
              (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            )
          )
          (1): BasicBlock(
            (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (relu): ReLU(inplace=True)
            (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
            (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          )
        )
        (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
        (fc): Linear(in_features=512, out_features=102, bias=True)
      )
    • 优化器设置

      1. # 优化器设置
      2. optimizer_ft = optim.Adam(params_to_update, lr=1e-2)#要训练啥参数,你来定
      3. scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=10, gamma=0.1)#学习率每7个epoch衰减成原来的1/10
      4. criterion = nn.CrossEntropyLoss()

      训练模块

      1. def train_model(model, dataloaders, criterion, optimizer, num_epochs=25,filename='best.pt'):
      2. #咱们要算时间的
      3. since = time.time()
      4. #也要记录最好的那一次
      5. best_acc = 0
      6. #模型也得放到你的CPU或者GPU
      7. model.to(device)
      8. #训练过程中打印一堆损失和指标
      9. val_acc_history = []
      10. train_acc_history = []
      11. train_losses = []
      12. valid_losses = []
      13. #学习率
      14. LRs = [optimizer.param_groups[0]['lr']]
      15. #最好的那次模型,后续会变的,先初始化
      16. best_model_wts = copy.deepcopy(model.state_dict())
      17. #一个个epoch来遍历
      18. for epoch in range(num_epochs):
      19. print('Epoch {}/{}'.format(epoch, num_epochs - 1))
      20. print('-' * 10)
      21. # 训练和验证
      22. for phase in ['train', 'valid']:
      23. if phase == 'train':
      24. model.train() # 训练
      25. else:
      26. model.eval() # 验证
      27. running_loss = 0.0
      28. running_corrects = 0
      29. # 把数据都取个遍
      30. for inputs, labels in dataloaders[phase]:
      31. inputs = inputs.to(device)#放到你的CPU或GPU
      32. labels = labels.to(device)
      33. # 清零
      34. optimizer.zero_grad()
      35. # 只有训练的时候计算和更新梯度
      36. outputs = model(inputs)
      37. loss = criterion(outputs, labels)
      38. _, preds = torch.max(outputs, 1)
      39. # 训练阶段更新权重
      40. if phase == 'train':
      41. loss.backward()
      42. optimizer.step()
      43. # 计算损失
      44. running_loss += loss.item() * inputs.size(0)#0表示batch那个维度
      45. running_corrects += torch.sum(preds == labels.data)#预测结果最大的和真实值是否一致
      46. epoch_loss = running_loss / len(dataloaders[phase].dataset)#算平均
      47. epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
      48. time_elapsed = time.time() - since#一个epoch我浪费了多少时间
      49. print('Time elapsed {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
      50. print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
      51. # 得到最好那次的模型
      52. if phase == 'valid' and epoch_acc > best_acc:
      53. best_acc = epoch_acc
      54. best_model_wts = copy.deepcopy(model.state_dict())
      55. state = {
      56. 'state_dict': model.state_dict(),#字典里key就是各层的名字,值就是训练好的权重
      57. 'best_acc': best_acc,
      58. 'optimizer' : optimizer.state_dict(),
      59. }
      60. torch.save(state, filename)
      61. if phase == 'valid':
      62. val_acc_history.append(epoch_acc)
      63. valid_losses.append(epoch_loss)
      64. #scheduler.step(epoch_loss)#学习率衰减
      65. if phase == 'train':
      66. train_acc_history.append(epoch_acc)
      67. train_losses.append(epoch_loss)
      68. print('Optimizer learning rate : {:.7f}'.format(optimizer.param_groups[0]['lr']))
      69. LRs.append(optimizer.param_groups[0]['lr'])
      70. print()
      71. scheduler.step()#学习率衰减
      72. time_elapsed = time.time() - since
      73. print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
      74. print('Best val Acc: {:4f}'.format(best_acc))
      75. # 训练完后用最好的一次当做模型最终的结果,等着一会测试
      76. model.load_state_dict(best_model_wts)
      77. return model, val_acc_history, train_acc_history, valid_losses, train_losses, LRs

      开始训练!

    • 我们现在只训练了输出层
      model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs  = train_model(model_ft, dataloaders, criterion, optimizer_ft, num_epochs=20)
      Epoch 0/19
      ----------
      Time elapsed 0m 39s
      train Loss: 4.0874 Acc: 0.2355
      Time elapsed 0m 43s
      valid Loss: 3.5746 Acc: 0.2531
      Optimizer learning rate : 0.0100000
      
      Epoch 1/19
      ----------
      Time elapsed 1m 22s
      train Loss: 2.8185 Acc: 0.3953
      Time elapsed 1m 26s
      valid Loss: 3.5450 Acc: 0.3142
      Optimizer learning rate : 0.0100000
      
      Epoch 2/19
      ----------
      Time elapsed 2m 5s
      train Loss: 2.7673 Acc: 0.4174
      Time elapsed 2m 9s
      valid Loss: 3.9110 Acc: 0.2653
      Optimizer learning rate : 0.0100000
      
      Epoch 3/19
      ----------
      Time elapsed 2m 48s
      train Loss: 2.7962 Acc: 0.4255
      Time elapsed 2m 52s
      valid Loss: 3.6922 Acc: 0.3142
      Optimizer learning rate : 0.0100000
      
      Epoch 4/19
      ----------
      Time elapsed 3m 32s
      train Loss: 2.7453 Acc: 0.4428
      Time elapsed 3m 36s
      valid Loss: 3.9310 Acc: 0.3044
      Optimizer learning rate : 0.0100000
      
      Epoch 5/19
      ----------
      Time elapsed 4m 14s
      train Loss: 2.2935 Acc: 0.5043
      Time elapsed 4m 18s
      valid Loss: 3.3299 Acc: 0.3435
      Optimizer learning rate : 0.0010000
      
      Epoch 6/19
      ----------
      Time elapsed 4m 57s
      train Loss: 2.0654 Acc: 0.5258
      Time elapsed 5m 1s
      valid Loss: 3.2608 Acc: 0.3411
      Optimizer learning rate : 0.0010000
      
      Epoch 7/19
      ----------
      Time elapsed 5m 40s
      train Loss: 1.9603 Acc: 0.5369
      Time elapsed 5m 44s
      valid Loss: 3.2618 Acc: 0.3472
      Optimizer learning rate : 0.0010000
      
      Epoch 8/19
      ----------
      Time elapsed 6m 23s
      train Loss: 1.9216 Acc: 0.5401
      Time elapsed 6m 27s
      valid Loss: 3.1651 Acc: 0.3386
      Optimizer learning rate : 0.0010000
      
      Epoch 9/19
      ----------
      Time elapsed 7m 5s
      train Loss: 1.9203 Acc: 0.5458
      Time elapsed 7m 9s
      valid Loss: 3.0449 Acc: 0.3680
      Optimizer learning rate : 0.0010000
      
      Epoch 10/19
      ----------
      Time elapsed 7m 48s
      train Loss: 1.8366 Acc: 0.5553
      Time elapsed 7m 52s
      valid Loss: 3.0722 Acc: 0.3545
      Optimizer learning rate : 0.0001000
      
      Epoch 11/19
      ----------
      Time elapsed 8m 31s
      train Loss: 1.8324 Acc: 0.5546
      Time elapsed 8m 35s
      valid Loss: 3.0115 Acc: 0.3643
      Optimizer learning rate : 0.0001000
      
      Epoch 12/19
      ----------
      Time elapsed 9m 13s
      train Loss: 1.8054 Acc: 0.5553
      Time elapsed 9m 17s
      valid Loss: 3.0688 Acc: 0.3619
      Optimizer learning rate : 0.0001000
      
      Epoch 13/19
      ----------
      Time elapsed 9m 56s
      train Loss: 1.8436 Acc: 0.5534
      Time elapsed 10m 0s
      valid Loss: 3.0100 Acc: 0.3631
      Optimizer learning rate : 0.0001000
      
      Epoch 14/19
      ----------
      Time elapsed 10m 39s
      train Loss: 1.7417 Acc: 0.5614
      Time elapsed 10m 43s
      valid Loss: 3.0129 Acc: 0.3655
      Optimizer learning rate : 0.0001000
      
      Epoch 15/19
      ----------
      Time elapsed 11m 22s
      train Loss: 1.7610 Acc: 0.5672
      Time elapsed 11m 26s
      valid Loss: 3.0220 Acc: 0.3606
      Optimizer learning rate : 0.0000100
      
      Epoch 16/19
      ----------
      Time elapsed 12m 6s
      train Loss: 1.7788 Acc: 0.5676
      Time elapsed 12m 10s
      valid Loss: 3.0104 Acc: 0.3557
      Optimizer learning rate : 0.0000100
      
      Epoch 17/19
      ----------
      Time elapsed 12m 49s
      train Loss: 1.8033 Acc: 0.5638
      Time elapsed 12m 53s
      valid Loss: 3.0428 Acc: 0.3606
      Optimizer learning rate : 0.0000100
      
      Epoch 18/19
      ----------
      Time elapsed 13m 33s
      train Loss: 1.8294 Acc: 0.5568
      Time elapsed 13m 37s
      valid Loss: 3.0307 Acc: 0.3509
      Optimizer learning rate : 0.0000100
      
      Epoch 19/19
      ----------
      Time elapsed 14m 16s
      train Loss: 1.7949 Acc: 0.5612
      Time elapsed 14m 20s
      valid Loss: 3.0396 Acc: 0.3643
      Optimizer learning rate : 0.0000100
      
      Training complete in 14m 20s
      Best val Acc: 0.367971
    • 再继续训练所有层

      1. for param in model_ft.parameters():
      2. param.requires_grad = True
      3. # 再继续训练所有的参数,学习率调小一点
      4. optimizer = optim.Adam(model_ft.parameters(), lr=1e-3)
      5. scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
      6. # 损失函数
      7. criterion = nn.CrossEntropyLoss()
      1. # 加载之前训练好的权重参数
      2. checkpoint = torch.load(filename)
      3. best_acc = checkpoint['best_acc']
      4. model_ft.load_state_dict(checkpoint['state_dict'])
      model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs  = train_model(model_ft, dataloaders, criterion, optimizer, num_epochs=10,)
      Epoch 0/9
      ----------
      Time elapsed 1m 32s
      train Loss: 2.2451 Acc: 0.4846
      Time elapsed 1m 36s
      valid Loss: 2.3190 Acc: 0.4633
      Optimizer learning rate : 0.0010000
      
      Epoch 1/9
      ----------
      Time elapsed 2m 54s
      train Loss: 1.2920 Acc: 0.6505
      Time elapsed 2m 58s
      valid Loss: 2.2263 Acc: 0.4670
      Optimizer learning rate : 0.0010000
      
      Epoch 2/9
      ----------
      Time elapsed 4m 15s
      train Loss: 1.1026 Acc: 0.6993
      Time elapsed 4m 19s
      valid Loss: 1.8115 Acc: 0.5452
      Optimizer learning rate : 0.0010000
      
      Epoch 3/9
      ----------
      Time elapsed 5m 35s
      train Loss: 0.9062 Acc: 0.7515
      Time elapsed 5m 39s
      valid Loss: 2.0045 Acc: 0.5403
      Optimizer learning rate : 0.0010000
      
      Epoch 4/9
      ----------
      Time elapsed 6m 56s
      train Loss: 0.8392 Acc: 0.7643
      Time elapsed 7m 0s
      valid Loss: 2.1381 Acc: 0.5171
      Optimizer learning rate : 0.0010000
      
      Epoch 5/9
      ----------
      Time elapsed 8m 17s
      train Loss: 0.7081 Acc: 0.7953
      Time elapsed 8m 21s
      valid Loss: 2.0461 Acc: 0.5599
      Optimizer learning rate : 0.0010000
      
      Epoch 6/9
      ----------
      Time elapsed 9m 38s
      train Loss: 0.6400 Acc: 0.8147
      Time elapsed 9m 42s
      valid Loss: 2.2603 Acc: 0.5452
      Optimizer learning rate : 0.0010000
      
      Epoch 7/9
      ----------
      Time elapsed 10m 59s
      train Loss: 0.6406 Acc: 0.8117
      Time elapsed 11m 3s
      valid Loss: 1.4649 Acc: 0.6406
      Optimizer learning rate : 0.0010000
      
      Epoch 8/9
      ----------
      Time elapsed 12m 20s
      train Loss: 0.5686 Acc: 0.8300
      Time elapsed 12m 24s
      valid Loss: 1.7538 Acc: 0.6100
      Optimizer learning rate : 0.0010000
      
      Epoch 9/9
      ----------
      Time elapsed 13m 41s
      train Loss: 0.5978 Acc: 0.8245
      Time elapsed 13m 45s
      valid Loss: 1.6953 Acc: 0.6161
      Optimizer learning rate : 0.0010000
      
      Training complete in 13m 45s
      Best val Acc: 0.640587
    • 加载训练好的模型

      1. model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
      2. # GPU模式
      3. model_ft = model_ft.to(device)
      4. # 保存文件的名字
      5. filename='best.pt'
      6. # 加载模型
      7. checkpoint = torch.load(filename)
      8. best_acc = checkpoint['best_acc']
      9. model_ft.load_state_dict(checkpoint['state_dict'])

      测试数据预处理

    • 测试数据处理方法需要跟训练时一直才可以
    • crop操作的目的是保证输入的大小是一致的
    • 标准化操作也是必须的,用跟训练数据相同的mean和std,但是需要注意一点训练数据是在0-1上进行标准化,所以测试数据也需要先归一化
    • 最后一点,PyTorch中颜色通道是第一个维度,跟很多工具包都不一样,需要转换
      1. # 得到一个batch的测试数据
      2. dataiter = iter(dataloaders['valid'])
      3. images, labels = dataiter.next()
      4. model_ft.eval()
      5. if train_on_gpu:
      6. output = model_ft(images.cuda())
      7. else:
      8. output = model_ft(images)

      output表示对一个batch中每一个数据得到其属于各个类别的可能性

      output.shape

      得到概率最大的那个

      1. _, preds_tensor = torch.max(output, 1)
      2. preds = np.squeeze(preds_tensor.numpy()) if not train_on_gpu else np.squeeze(preds_tensor.cpu().numpy())
      3. preds
      1. array([ 34, 49, 43, 54, 20, 14, 49, 43, 50, 20, 19, 100, 78,
      2. 96, 96, 62, 62, 63, 32, 38, 82, 43, 88, 73, 6, 51,
      3. 43, 89, 55, 75, 55, 11, 46, 82, 48, 82, 20, 100, 48,
      4. 20, 24, 49, 76, 93, 49, 46, 90, 75, 89, 75, 76, 99,
      5. 56, 48, 77, 66, 60, 72, 89, 97, 76, 73, 17, 48, 39,
      6. 31, 19, 74, 61, 46, 93, 80, 27, 11, 91, 18, 23, 47,
      7. 29, 54, 18, 93, 1, 50, 79, 96, 39, 53, 63, 60, 49,
      8. 23, 23, 52, 99, 89, 3, 50, 64, 15, 19, 60, 19, 75,
      9. 50, 78, 82, 18, 75, 18, 82, 53, 3, 52, 60, 38, 62,
      10. 47, 21, 59, 81, 48, 89, 64, 60, 55, 100, 60], dtype=int64)

      展示预测结果

      1. def im_convert(tensor):
      2. """ 展示数据"""
      3. image = tensor.to("cpu").clone().detach()
      4. image = image.numpy().squeeze()
      5. image = image.transpose(1,2,0)
      6. image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))
      7. image = image.clip(0, 1)
      8. return image
      1. fig=plt.figure(figsize=(20, 20))
      2. columns =4
      3. rows = 2
      4. for idx in range (columns*rows):
      5. ax = fig.add_subplot(rows, columns, idx+1, xticks=[], yticks=[])
      6. plt.imshow(im_convert(images[idx]))
      7. ax.set_title("{} ({})".format(cat_to_name[str(preds[idx])], cat_to_name[str(labels[idx].item())]),
      8. color=("green" if cat_to_name[str(preds[idx])]==cat_to_name[str(labels[idx].item())] else "red"))
      9. plt.show()

  • 相关阅读:
    算法刷题记录-图(LeetCode)
    机器视觉工程师注意,没有经历过公司倒闭看下文章,机器视觉公司即将要倒闭的征兆是什么?
    leetcode做题笔记167. 两数之和 II - 输入有序数组
    openssl/rc4.h: 没有那个文件或目录
    面试官:Spring中获取Bean有几种方式?
    常用的原型工具有哪些?推荐这7款
    有 3 个候选人,每个选民只能投票选一人,要求编一个统计选票的程序,先后输入被选人的名字,最后输出各人得票结果
    Ubuntu20.04+1080Ti通过docker进行NVIDIA GPU环境搭建
    Restcloud ETL实践之数据行列转换
    杨辉三角c语言程序
  • 原文地址:https://blog.csdn.net/qq_65838372/article/details/132745442