Modelo de clasificación de imágenes de entrenamiento basado en la arquitectura de red resnet

Parte de preprocesamiento de datos:

  • Mejora de datos: el módulo de transformaciones en torchvision tiene sus propias funciones, lo cual es más práctico.
  • Preprocesamiento de datos: las transformaciones en torchvision también se implementan para nosotros, solo llámelas directamente
  • El módulo DataLoader lee directamente datos por lotes

Configuración del módulo de red:

  • Cargue el modelo previamente entrenado. Hay muchas arquitecturas de red clásicas en torchvision, que son muy convenientes de llamar. También puede usar los parámetros de peso entrenados por otros para continuar entrenando, que es el llamado aprendizaje por transferencia.
  • Cabe señalar que las tareas entrenadas por otros no son exactamente las mismas que las nuestras, necesitamos cambiar la última capa principal, que suele ser la última capa completamente conectada, a nuestras propias tareas.
  • Durante el entrenamiento, puede entrenar todo de nuevo, o solo puede entrenar la última capa de nuestra tarea, porque las primeras capas se usan para la extracción de características y los objetivos esenciales de la tarea son los mismos.

Preservación y prueba del modelo de red.

  • El modelo se puede guardar de forma selectiva, por ejemplo, si el efecto actual es bueno en el conjunto de validación, se guardará.
  • Lea el modelo para realizar pruebas reales.
  • import os
    import matplotlib.pyplot as plt
    %matplotlib inline
    import numpy as np
    import torch
    from torch import nn
    import torch.optim as optim
    import torchvision
    #pip install torchvision
    from torchvision import transforms, models, datasets
    #https://pytorch.org/docs/stable/torchvision/index.html
    import imageio
    import time
    import warnings
    warnings.filterwarnings("ignore")
    import random
    import sys
    import copy
    import json
    from PIL import Image

    Operaciones de lectura y preprocesamiento de datos.

    data_dir = './flower_data/'
    train_dir = data_dir + '/train'
    valid_dir = data_dir + '/valid'

    Haga una buena fuente de datos:

  • Todas las operaciones de preprocesamiento de imágenes se especifican en data_transforms
  • ImageFolder asume que todos los archivos se guardan en carpetas. Las imágenes de la misma categoría se almacenan en cada carpeta. El nombre de la carpeta es el nombre de la categoría.
    data_transforms = {
        'train': 
            transforms.Compose([
            transforms.Resize([96, 96]),
            transforms.RandomRotation(45),#随机旋转,-45到45度之间随机选
            transforms.CenterCrop(64),#从中心开始裁剪
            transforms.RandomHorizontalFlip(p=0.5),#随机水平翻转 选择一个概率概率
            transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转
            transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
            transforms.RandomGrayscale(p=0.025),#概率转换成灰度率,3通道就是R=G=B
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#均值,标准差
        ]),
        'valid': 
            transforms.Compose([
            transforms.Resize([64, 64]),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
    }
    batch_size = 128
    
    image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'valid']}
    dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True) for x in ['train', 'valid']}
    dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'valid']}
    class_names = image_datasets['train'].classes
    image_datasets
    {'train': Dataset ImageFolder 
         Número de puntos de datos: 6552 
         Ubicación raíz: ./flower_data/train 
         StandardTransform 
     Transformar: Compose( 
                    Resize(size=[96, 96], interpolation=bilinear, max_size=Ninguno, antialias=Ninguno) 
                    RandomRotation(grados =[-45.0, 45.0], interpolación=más cercana, expandir=Falso, relleno=0) 
                    CenterCrop(tamaño=(64, 64)) 
                    RandomHorizontalFlip(p=0.5) 
                    RandomVerticalFlip(p=0.5) 
                    ColorJitter(brillo=[0.8, 1.2) ], contraste=[0.9, 1.1], saturación=[0.9, 1.1], tono=[-0.1, 0.1]) 
                    Escala de grises aleatoria (p=0.025) 
                    ToTensor()
                    Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ) 
                , 'valid': Dataset ImageFolder 
         Número de puntos de datos: 818 
         Ubicación raíz: ./flower_data/valid 
         StandardTransform 
     Transform: Compose( 
                    Resize( tamaño=[64, 64], interpolación=bilineal, max_size=Ninguno, antialias=Ninguno) 
                    ToTensor() 
                    Normalizar(media=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ) 
                }
    dataloaders
    {'train': <torch.utils.data.dataloader.DataLoader en 0x1e4c50b9400>, 
     'válido': <torch.utils.data.dataloader.DataLoader en 0x1e4c51ad128>}
    dataset_sizes
    {'tren': 6552, 'válido': 818}
  • Leer el nombre real correspondiente a la etiqueta.

    with open('cat_to_name.json', 'r') as f:
        cat_to_name = json.load(f)
    cat_to_name
    {'1': 'prímula rosa', 
     '10': 'cardo globo', 
     '100': 'flor de manta', 
     '101': 'enredadera de trompeta', 
     '102': 'lirio de mora', 
     '11': 'boca de dragón', 
     '12': "pata de potro", 
     '13': 'rey protea', 
     '14': 'cardo lanza', 
     '15': 'iris amarillo', 
     '16': 'flor-globo', 
     '17': 'equinácea púrpura', 
     '18': 'lirio peruano', 
     '19': 'flor de globo', 
     '2': 'orquídea de bolsillo de hojas duras', 
     '20': 'lirio de aro blanco gigante',
     '21': 'lirio de fuego', 
     '22': 'flor de alfiletero', 
     '23': 'fritillary', 
     '24': 'jengibre rojo', 
     '25': 'jacinto de uva',  
     '26': 'maíz amapola',
     '27': 'príncipe de plumas de gales',
     '28': 'genciana sin tallo', 
     '29': 'alcachofa', 
     '3': 'campanas de canterbury', 
     '30': 'sweet william', 
     '31': 'clavel', 
     '32': 'phlox de jardín' ', 
     '33': 'amor en la niebla', 
     '34': 'aster mexicano', 
     '35': 'acebo de mar alpino', 
     '36': 'gatleya de labios rubíes', 
     '37': 'flor del cabo ', 
     '38': 'gran masterwort', 
     '39': 'tulipán siam', 
     '4': 'guisante de olor', 
     '40': 'rosa cuaresmal', 
     '41': 'margarita barbeton', 
     '42' :'narciso', 
     '43': 'lirio espada', 
     '44': 'poinsettia', 
     '45': 'bolero azul profundo', 
     '46': 'alhelí', '48' 
     '49' : 'Margarita', 
     '47 ': 'caléndula',
     '48': 'ranúnculo', 
     '5': 'caléndula inglesa', 
     '50': 'diente de león común', 
     '51': 'petunia', 
     '52': 'pensamiento salvaje', 
     '53': 'prímula' , 
     '54': 'girasol', 
     '55': 'pelargonium', 
     '56': 'obispo de llandaff', 
     '57': 'gaura', 
     '58': 'geranio', 
     '59': 'dalia naranja ', 
     '6': 'lirio tigre', 
     '60': 'dalia rosa-amarilla', 
     '61': 'cautleya spicata', 
     '62': 'anémona japonesa', 
     '63': 'susan de ojos negros' ,
     '64': 'silverbush', 
     '65': 'amapola californiana', 
     '66': 'osteospermum', 
     '67': 'azafrán de primavera', 
     '68': 'iris barbudo', 
     '69': 'windflower' ,
     '7': 'orquídea luna',  
     '70': 'árbol amapola',
     '71': 'gazania', 
     '72': 'azalea', 
     '73': 'nenúfar', 
     '74': 'rosa', 
     '75': 'manzana espinosa' , 
     '76': 'gloria de la mañana', 
     '77': 'flor de la pasión', 
     '78': 'loto loto', 
     '79': 'lirio sapo', 
     '8': 'ave del paraíso', 
     '80' : 'anthurium', 
     '81': 'frangipani', 
     '82': 'clematis', 
     '83': 'hibiscus', 
     '84': 'guileña', 
     '85': 'rosa del desierto', 
     '86' :'malva de árbol', 
     '87': 'magnolia', 
     '88': 'ciclamen', 
     '89': 'berros', 
     '9': 'acónito', 
     '90': 'lirio de canna', 
     '91': 'hippeastrum', 
     '92': 'bálsamo de abeja', 
     '93': ' bola de musgo', 
     '94': 'dedalera',
     '95': 'buganvilla', 
     '96': 'camelia', 
     '97': 'malva', 
     '98': 'petunia mexicana', 
     '99': 'bromelia'}
  • Cargue el modelo proporcionado en los modelos y utilice directamente los pesos entrenados como parámetros de inicialización.

  • La primera ejecución requiere descarga, que puede ser lenta, le proporcionaré una copia descargada que puede colocar directamente en la ruta correspondiente.
    model_name = 'resnet'  #可选的比较多 ['resnet', 'alexnet', 'vgg', 'squeezenet', 'densenet', 'inception']
    #是否用人家训练好的特征来做
    feature_extract = True #都用人家特征,咱先不更新
    # 是否用GPU训练
    train_on_gpu = torch.cuda.is_available()
    
    if not train_on_gpu:
        print('CUDA is not available.  Training on CPU ...')
    else:
        print('CUDA is available!  Training on GPU ...')
        
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    CUDA no está disponible. Entrenamiento en CPU...
  • ¿Es necesario actualizar los parámetros del modelo?

  • A veces uso modelos de otras personas y sigo usándolos, y mucho menos actualizándolos, podemos personalizarlos nosotros mismos.
    def set_parameter_requires_grad(model, feature_extracting):
        if feature_extracting:
            for param in model.parameters():
                param.requires_grad = False
    model_ft = models.resnet18()#18层的能快点,条件好点的也可以选152
    model_ft
    ResNet( 
      (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), sesgo=False) (bn1): BatchNorm2d(64, eps 
      = 1e-05, impulso=0.1, affine=True, track_running_stats=True) 
      (relu): ReLU(inplace=True) 
      (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilatación=1, ceil_mode= Falso) 
      (layer1): Sequential( 
        (0): BasicBlock( 
          (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), sesgo= Falso) 
          (bn1): BatchNorm2d(64, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ( 
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(64, 64, kernel_size= (3, 3), zancada=(1, 1), relleno=(1, 1), sesgo=Falso) 
          (bn2): BatchNorm2d(64, eps=1e- 05, impulso=0.1, affine=True, track_running_stats=True) 
        ) 
        (1): BasicBlock( 
          Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1 ), padding=(1, 1), sesgo=False) 
          (bn1): BatchNorm2d(64, eps=1e-05, impulso=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), sesgo=False) (bn2): BatchNorm2d(64, eps= 
          1e- 05, impulso=0.1, affine=True, track_running_stats=True) 
        ) 
      ) 
      (layer2): Sequential( 
        (0): BasicBlock( 
          (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2 , 2), relleno=(1, 1), sesgo=Falso) 
          (bn1): BatchNorm2d(128, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ( 
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(128, 128, kernel_size= (3, 3), zancada=(1, 1), relleno=(1, 1), sesgo=Falso)
          (bn2): BatchNorm2d(128, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ( 
          reducir la muestra): Sequential( 
            (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), sesgo=False) 
            (1): BatchNorm2d(128, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ) ) (1) 
          : 
        BasicBlock 
        ( 
          (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), sesgo=False) (bn1): BatchNorm2d(128, eps=1e-05, impulso 
          = 0.1, affine=True, track_running_stats=True) 
          bn2 ): BatchNorm2d(128, eps=1e-05, impulso=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), sesgo=False) ) ) (layer3): Secuencial( 
        ( 
      0 
      ) 
        : BasicBlock( 
          (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), sesgo=False) (bn1): BatchNorm2d(256, eps 
          = 1e-05, impulso=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), sesgo=False) 
          (bn2): BatchNorm2d(256, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) (reducir resolución) 
          : Secuencial( 
            (0): Conv2d(128, 256, kernel_size=(1, 1), zancada=(2, 2), sesgo=Falso)
            (1): BatchNorm2d(256, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ) ( 
          conv1 
        BasicBlock 
        (
          ): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), relleno=(1, 1), sesgo=Falso) 
          (bn1): BatchNorm2d(256, eps=1e-05, impulso=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), sesgo=False) (bn2): BatchNorm2d(256, eps= 
          1e -05, impulso=0.1, affine=True, track_running_stats=True) 
        ) 
      ) 
      (capa4): Secuencial( 
        (0): BasicBlock( 
          (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=( 2, 2), relleno=(1, 1), sesgo=Falso)
          (bn1): BatchNorm2d(512, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True)  
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(512, 512, kernel_size= (3, 3), zancada=(1, 1), relleno=(1, 1), sesgo=Falso)
          (bn2): BatchNorm2d(512, eps=1e-05, impulso=0.1, affine=True, track_running_stats= Verdadero) 
          (reducción de muestra): Secuencial ( 
            (0): Conv2d (256, 512, kernel_size = (1, 1), zancada = (2, 2), sesgo = Falso) (1): BatchNorm2d (512, eps = 
            1e- 05, impulso=0.1, affine=True, track_running_stats=True) 
          ) 
        ) 
        (1): BasicBlock( 
          (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding= (1, 1), sesgo=Falso) 
          (bn1): BatchNorm2d(512, eps=1e-05, impulso=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), sesgo=False) ) ) (avgpool): AdaptiveAvgPool2d(output_size
          bn2 ): BatchNorm2d(512, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True)
        ) 
      ) 
      (avgpool): AdaptiveAvgPool2d(output_size=(1, 1)) 
      (fc): Lineal(in_features=512, out_features=1000, sesgo=True)
  • Cambie la capa de salida del modelo a su propia

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

    Establecer qué capas deben entrenarse

    model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
    
    #GPU还是CPU计算
    model_ft = model_ft.to(device)
    
    # 模型保存,名字自己起
    filename='checkpoint.pth'
    
    # 是否训练所有层
    params_to_update = model_ft.parameters()
    print("Params to learn:")
    if feature_extract:
        params_to_update = []
        for name,param in model_ft.named_parameters():
            if param.requires_grad == True:
                params_to_update.append(param)
                print("\t",name)
    else:
        for name,param in model_ft.named_parameters():
            if param.requires_grad == True:
                print("\t",name)
    Parámetros para aprender: 
    	 fc.weight 
    	 fc.bias
  • model_ft
    ResNet( 
      (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), sesgo=False) (bn1): BatchNorm2d(64, eps 
      = 1e-05, impulso=0.1, affine=True, track_running_stats=True) 
      (relu): ReLU(inplace=True) 
      (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilatación=1, ceil_mode= Falso) 
      (layer1): Sequential( 
        (0): BasicBlock( 
          (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), sesgo= Falso) 
          (bn1): BatchNorm2d(64, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ( 
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(64, 64, kernel_size= (3, 3), zancada=(1, 1), relleno=(1, 1), sesgo=Falso) 
          (bn2): BatchNorm2d(64, eps=1e- 05, impulso=0.1, affine=True, track_running_stats=True) 
        ) 
        (1): BasicBlock( 
          Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1 ), padding=(1, 1), sesgo=False) 
          (bn1): BatchNorm2d(64, eps=1e-05, impulso=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), sesgo=False) (bn2): BatchNorm2d(64, eps= 
          1e- 05, impulso=0.1, affine=True, track_running_stats=True) 
        ) 
      ) 
      (layer2): Sequential( 
        (0): BasicBlock( 
          (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2 , 2), relleno=(1, 1), sesgo=Falso)
          (bn1): BatchNorm2d(128, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) 
          relu): ReLU(inplace=True)
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(128, 128, kernel_size= (3, 3), zancada=(1, 1), relleno=(1, 1), sesgo=Falso)
          (bn2): BatchNorm2d(128, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ( 
          reducir la muestra): Sequential( 
            (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), sesgo=False) 
            (1): BatchNorm2d(128, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ) ) (1) 
          : 
        BasicBlock 
        ( 
          (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), sesgo=False) (bn1): BatchNorm2d(128, eps=1e-05, impulso 
          = 0.1, affine=True, track_running_stats=True) 
          bn2 ): BatchNorm2d(128, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True)
          (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), sesgo=False) ) ) (layer3): Secuencial( 
        ( 
      0 
      ) 
        : BasicBlock( 
          (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), sesgo=False) (bn1): BatchNorm2d(256, eps 
          = 1e-05, impulso=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), sesgo=False) 
          (bn2): BatchNorm2d(256, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) (reducir resolución) 
          : Secuencial( 
            (0): Conv2d(128, 256, kernel_size=(1, 1), zancada=(2, 2), sesgo=Falso) 
            (1): BatchNorm2d(256, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ) ) (1) 
          : 
        BasicBlock 
        (
          (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), sesgo=False) (bn1): BatchNorm2d(256, eps= 
          1e- 05, impulso=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), sesgo=False) 
          (bn2): BatchNorm2d(256, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ) ) ( 
        capa4 
      ) 
      : Secuencial( 
        (0): BasicBlock( 
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(512, 512, kernel_size= (3, 3), zancada=(1, 1), relleno=(1, 1), sesgo=Falso)
          (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=( 2, 2), relleno=(1, 1), sesgo=Falso)
          (bn1): BatchNorm2d(512, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) 
          relu): ReLU(inplace=True)
          (bn2): BatchNorm2d(512, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ( 
          reducir la muestra): Sequential( 
            (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), sesgo=False) 
            (1): BatchNorm2d(512, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True) ) ) (1) 
          : 
        BasicBlock 
        ( 
          (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), sesgo=False) (bn1): BatchNorm2d(512, eps=1e-05, impulso 
          = 0.1, affine=True, track_running_stats=True) 
          (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), sesgo=False) ( 
          bn2 ): BatchNorm2d(512, eps=1e-05, impulso=0.1, affine=True, track_running_stats=True)
        ) 
      ) 
      (avgpool): AdaptiveAvgPool2d(output_size=(1, 1)) 
      (fc): Lineal(in_features=512, out_features=102, sesgo=True) 
    )
  • Configuración del optimizador

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

    modulo de entrenamiento

    def train_model(model, dataloaders, criterion, optimizer, num_epochs=25,filename='best.pt'):
        #咱们要算时间的
        since = time.time()
        #也要记录最好的那一次
        best_acc = 0
        #模型也得放到你的CPU或者GPU
        model.to(device)
        #训练过程中打印一堆损失和指标
        val_acc_history = []
        train_acc_history = []
        train_losses = []
        valid_losses = []
        #学习率
        LRs = [optimizer.param_groups[0]['lr']]
        #最好的那次模型,后续会变的,先初始化
        best_model_wts = copy.deepcopy(model.state_dict())
        #一个个epoch来遍历
        for epoch in range(num_epochs):
            print('Epoch {}/{}'.format(epoch, num_epochs - 1))
            print('-' * 10)
    
            # 训练和验证
            for phase in ['train', 'valid']:
                if phase == 'train':
                    model.train()  # 训练
                else:
                    model.eval()   # 验证
    
                running_loss = 0.0
                running_corrects = 0
    
                # 把数据都取个遍
                for inputs, labels in dataloaders[phase]:
                    inputs = inputs.to(device)#放到你的CPU或GPU
                    labels = labels.to(device)
    
                    # 清零
                    optimizer.zero_grad()
                    # 只有训练的时候计算和更新梯度
                    outputs = model(inputs)
                    loss = criterion(outputs, labels)
                    _, preds = torch.max(outputs, 1)
                    # 训练阶段更新权重
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()
    
                    # 计算损失
                    running_loss += loss.item() * inputs.size(0)#0表示batch那个维度
                    running_corrects += torch.sum(preds == labels.data)#预测结果最大的和真实值是否一致
                    
                
                
                epoch_loss = running_loss / len(dataloaders[phase].dataset)#算平均
                epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
                
                time_elapsed = time.time() - since#一个epoch我浪费了多少时间
                print('Time elapsed {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
                print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
                
    
                # 得到最好那次的模型
                if phase == 'valid' and epoch_acc > best_acc:
                    best_acc = epoch_acc
                    best_model_wts = copy.deepcopy(model.state_dict())
                    state = {
                      'state_dict': model.state_dict(),#字典里key就是各层的名字,值就是训练好的权重
                      'best_acc': best_acc,
                      'optimizer' : optimizer.state_dict(),
                    }
                    torch.save(state, filename)
                if phase == 'valid':
                    val_acc_history.append(epoch_acc)
                    valid_losses.append(epoch_loss)
                    #scheduler.step(epoch_loss)#学习率衰减
                if phase == 'train':
                    train_acc_history.append(epoch_acc)
                    train_losses.append(epoch_loss)
            
            print('Optimizer learning rate : {:.7f}'.format(optimizer.param_groups[0]['lr']))
            LRs.append(optimizer.param_groups[0]['lr'])
            print()
            scheduler.step()#学习率衰减
    
        time_elapsed = time.time() - since
        print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
        print('Best val Acc: {:4f}'.format(best_acc))
    
        # 训练完后用最好的一次当做模型最终的结果,等着一会测试
        model.load_state_dict(best_model_wts)
        return model, val_acc_history, train_acc_history, valid_losses, train_losses, LRs 

    ¡Empezar a entrenar!

  • Ahora solo entrenamos la capa de salida.
    model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs  = train_model(model_ft, dataloaders, criterion, optimizer_ft, num_epochs=20)
    Época 0/19 
    ---------- 
    Tiempo transcurrido 0m 39s 
    tren Pérdida: 4.0874 Acc: 0.2355 
    Tiempo transcurrido 0m 43s 
    válido Pérdida: 3.5746 Acc: 0.2531 
    Tasa de aprendizaje del optimizador: 0.0100000 
    
    Época 1/19 
    ----- ----- 
    Tiempo transcurrido 1m 22s 
    tren Pérdida: 2.8185 Acc: 0.3953 
    Tiempo transcurrido 1m 26s 
    válido Pérdida: 3.5450 Acc: 0.3142 
    Tasa de aprendizaje del optimizador: 0.0100000 
    
    Época 2/19 
    ---------- 
    Tiempo transcurrido 2m 5s 
    Pérdida de tren: 2,7673 Acc: 0,4174 
    Tiempo transcurrido 2 m 9 s 
    Pérdida válida: 3,9110 Acc: 0,2653 
    Tasa de aprendizaje del optimizador: 0,0100000 
    
    Época 3/19 
    ----------  
    Tiempo transcurrido 2m 48s
    Pérdida de tren: 2,7962 Acc: 0,4255
    Tiempo transcurrido 2m 52s 
    válido Pérdida: 3.6922 Acc: 0.3142 
    Tasa de aprendizaje del optimizador: 0.0100000 
    
    Época 4/19 
    ---------- 
    Tiempo transcurrido 3m 32s 
    tren Pérdida: 2.7453 Acc: 0.4428 
    Tiempo transcurrido 3m 36s 
    válido Pérdida: 3.9310 Acc : 0.3044 
    Tasa de aprendizaje del optimizador : 0.0100000 
    
    Época 5/19 
    ---------- 
    Tiempo transcurrido 4m 14s 
    tren Pérdida: 2.2935 Acc: 0.5043 
    Tiempo transcurrido 4m 18s 
    válido Pérdida: 3.3299 Acc: 0.3435 
    Tasa de aprendizaje del optimizador : 0.0010000 
    
    Época 6 /19 
    ---------- 
    Tiempo transcurrido 4m 57s 
    tren Pérdida: 2.0654 Acc: 0.5258  
    Tiempo transcurrido 5 m 1 s
    válida Pérdida: 3.2608 Acc: 0.3411 
    Tasa de aprendizaje del optimizador: 0.0010000
     
    Época 7/19 
    ---------- 
    Tiempo transcurrido 5m 40s 
    tren Pérdida: 1.9603 Acc: 0.5369 
    Tiempo transcurrido 5m 44s 
    válido Pérdida: 3.2618 Acc: 0.3472 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 8 /19 
    ---------- 
    Tiempo transcurrido 6m 23s 
    tren Pérdida: 1.9216 Acc: 0.5401 
    Tiempo transcurrido 6m 27s 
    válido Pérdida: 3.1651 Acc: 0.3386 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 9/19 
    ------- --- 
    Tiempo transcurrido 7m 5s 
    tren Pérdida: 1.9203 Acc: 0.5458 
    Tiempo transcurrido 7m 9s 
    válido Pérdida: 3.0449 Acc: 0.3680 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 19/10 
    ----------
    Tiempo transcurrido 7m 48s  
    Pérdida de tren: 1.8366 Acc: 0.5553
    Tiempo transcurrido 7m 52s 
    válido Pérdida: 3.0722 Acc: 0.3545 
    Tasa de aprendizaje del optimizador: 0.0001000 
    
    Época 19/11 
    ---------- 
    Tiempo transcurrido 8m 31s 
    tren Pérdida: 1.8324 Acc: 0.5546 
    Tiempo transcurrido 8m 35s 
    válido Pérdida: 3.0115 Acc: 0.3643 
    Tasa de aprendizaje del optimizador: 0.0001000 
    
    Época 19/12 
    ---------- 
    Tiempo transcurrido 9m 13s 
    tren Pérdida: 1.8054 Acc: 0.5553 
    Tiempo transcurrido 9m 17s 
    válido Pérdida: 3.0688 Acc: 0.3619 
    Tasa de aprendizaje del optimizador : 0.0001000 
    
    Época 13/19 
    ---------- 
    Tiempo transcurrido 9m 56s 
    tren Pérdida: 1.8436 Acc: 0.5534 
    Tiempo transcurrido 10m 0s
    Pérdida válida: 3.0100 Acc: 0.3631 
    ---------- 
    Tasa de aprendizaje del optimizador: 0.0001000
    
    Época 14/19 
    ---------- 
    Tiempo transcurrido 10m 39s 
    tren Pérdida: 1.7417 Acc: 0.5614 
    Tiempo transcurrido 10m 43s 
    válido Pérdida: 3.0129 Acc: 0.3655 
    Tasa de aprendizaje del optimizador: 0.0001000 
    
    Época 15/19 
    ----- ----- 
    Tiempo transcurrido 11m 22s 
    tren Pérdida: 1.7610 Acc: 0.5672 
    Tiempo transcurrido 11m 26s 
    válido Pérdida: 3.0220 Acc: 0.3606 
    Tasa de aprendizaje del optimizador: 0.0000100 
    
    Época 16/19 
    ---------- 
    Tiempo transcurrido 12m 6s 
    tren Pérdida: 1.7788 Acc: 0.5676 
    Tiempo transcurrido 12m 10s 
    válido Pérdida: 3.0104 Acc: 0.3557 
    Tasa de aprendizaje del optimizador: 0.0000100 
    
    Época 17/19 
    Tiempo transcurrido 12m 49s
    Pérdida de tren: 1.8033 Acc: 0.5638 
    Tiempo transcurrido 12m 53s 
    Pérdida válida: 3.0428 Acc: 0.3606 
    Tasa de aprendizaje del optimizador: 0.0000100 
    
    Época 18/19 
    ---------- 
    Tiempo transcurrido 13m 33s 
    Pérdida de tren: 1.8294 Acc: 0.5568 
    Tiempo transcurrido 13m 37s 
    válido Pérdida: 3.0307 Acc: 0.3509 
    Tasa de aprendizaje del optimizador: 0.0000100 
    
    Época 19/19 
    ---------- 
    Tiempo transcurrido 14m 16s 
    tren Pérdida: 1.7949 Acc: 0.5612 
    Tiempo transcurrido 14m 20s 
    válido Pérdida: 3.0396 Acc: 0.3643 
    Tasa de aprendizaje del optimizador: 0,0000100 
    
    Entrenamiento completo en 14 m 20 s 
    Mejor valor Acc: 0,367971
  • Luego continúa entrenando todas las capas.

    for param in model_ft.parameters():
        param.requires_grad = True
    
    # 再继续训练所有的参数,学习率调小一点
    optimizer = optim.Adam(model_ft.parameters(), lr=1e-3)
    scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
    
    # 损失函数
    criterion = nn.CrossEntropyLoss()
    # 加载之前训练好的权重参数
    
    checkpoint = torch.load(filename)
    best_acc = checkpoint['best_acc']
    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,)
    Época 0/9 
    ---------- 
    Tiempo transcurrido 1m 32s 
    tren Pérdida: 2.2451 Acc: 0.4846 
    Tiempo transcurrido 1m 36s 
    válido Pérdida: 2.3190 Acc: 0.4633 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 1/9 
    ----- ----- 
    Tiempo transcurrido 2m 54s 
    tren Pérdida: 1.2920 Acc: 0.6505 
    Tiempo transcurrido 2m 58s 
    válido Pérdida: 2.2263 Acc: 0.4670 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 2/9 
    ---------- 
    Tiempo transcurrido 4m 15s 
    Pérdida de tren: 1.1026 Acc: 0.6993 
    Tiempo transcurrido 4m 19s 
    Pérdida válida: 1.8115 Acc: 0.5452 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 3/9 
    ----------  
    Tiempo transcurrido 5m 35s
    Pérdida de tren: 0.9062 Acc: 0.7515 
    Tiempo transcurrido 5m 39s 
    Pérdida válida: 2.0045 Acc: 0.5403 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 4/9 
    ---------- 
    Tiempo transcurrido 6m 56s 
    Pérdida de tren: 0.8392 Acc: 0.7643 
    Tiempo transcurrido 7m 0s 
    válido Pérdida: 2.1381 Acc: 0.5171 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 5/9 
    ---------- 
    Tiempo transcurrido 8m 17s 
    tren Pérdida: 0.7081 Acc: 0.7953 
    Tiempo transcurrido 8m 21s 
    válido Pérdida: 2.0461 Acc: 0.5599 
    Tasa de aprendizaje del optimizador: 0,0010000 
    
    Época 6/9 
    ---------- 
    Tiempo transcurrido 9 m 38 s 
    Pérdida del tren: 0,6400 Acc: 0,8147 
    Tiempo transcurrido 9 m 42 s
    Pérdida válida: 2.2603 Acc: 0.5452  
    Tasa de aprendizaje del optimizador: 0.0010000
    
    Época 7/9 
    ---------- 
    Tiempo transcurrido 10m 59s 
    tren Pérdida: 0.6406 Acc: 0.8117 
    Tiempo transcurrido 11m 3s 
    válido Pérdida: 1.4649 Acc: 0.6406 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 8 /9 
    ---------- 
    Tiempo transcurrido 12m 20s 
    tren Pérdida: 0.5686 Acc: 0.8300 
    Tiempo transcurrido 12m 24s 
    válido Pérdida: 1.7538 Acc: 0.6100 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Época 9/9 
    ------- --- 
    Tiempo transcurrido 13m 41s 
    tren Pérdida: 0.5978 Acc: 0.8245 
    Tiempo transcurrido 13m 45s 
    válido Pérdida: 1.6953 Acc: 0.6161 
    Tasa de aprendizaje del optimizador: 0.0010000 
    
    Entrenamiento completo en 13m 45s
    Mejor valor Acc: 0.640587
  • Cargar el modelo entrenado

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

    Preprocesamiento de datos de prueba

  • El método de procesamiento de datos de prueba debe ser el mismo que durante el entrenamiento.
  • El propósito de la operación de cultivo es garantizar que el tamaño de los insumos sea consistente.
  • Las operaciones de estandarización también son necesarias. Utilice la misma media y estándar que los datos de entrenamiento. Sin embargo, debe tenerse en cuenta que los datos de entrenamiento están estandarizados en 0-1, por lo que los datos de prueba también deben normalizarse primero.
  • Finalmente, el canal de color en PyTorch es la primera dimensión, que es diferente de muchos kits de herramientas y debe convertirse.
  • # 得到一个batch的测试数据
    dataiter = iter(dataloaders['valid'])
    images, labels = dataiter.next()
    
    model_ft.eval()
    
    if train_on_gpu:
        output = model_ft(images.cuda())
    else:
        output = model_ft(images)

    El resultado representa la probabilidad de que cada dato de un lote pertenezca a cada categoría.

    output.shape

    Consigue el que tenga mayor probabilidad

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

    Mostrar resultados de predicción

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

Supongo que te gusta

Origin blog.csdn.net/qq_65838372/article/details/132745442
Recomendado
Clasificación