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