Partie prétraitement des données :
- Amélioration des données : Le module de transformations dans torchvision a ses propres fonctions, ce qui est plus pratique.
- Prétraitement des données : les transformations dans torchvision sont également implémentées pour nous, il suffit de les appeler directement
- Le module DataLoader lit directement les données par lots
Paramètres du module réseau :
- Chargez le modèle pré-entraîné. Il existe de nombreuses architectures de réseau classiques dans torchvision, qui sont très pratiques à appeler. Vous pouvez également utiliser les paramètres de poids formés par d'autres pour continuer la formation, ce qu'on appelle l'apprentissage par transfert.
- Il convient de noter que les tâches formées par d'autres ne sont pas exactement les mêmes que les nôtres : nous devons remplacer la dernière couche principale, qui est généralement la dernière couche entièrement connectée, par nos propres tâches.
- Pendant l'entraînement, vous pouvez tout recommencer, ou vous ne pouvez entraîner que la dernière couche de notre tâche, car les premières couches sont toutes utilisées pour l'extraction de fonctionnalités et les objectifs essentiels de la tâche sont les mêmes.
Préservation et test du modèle de réseau
- Le modèle peut être enregistré de manière sélective. Par exemple, si l'effet actuel est bon dans l'ensemble de validation, il sera enregistré.
- Lire le modèle pour des tests réels
-
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
Opérations de lecture et de prétraitement des données
data_dir = './flower_data/' train_dir = data_dir + '/train' valid_dir = data_dir + '/valid'
Créez une bonne source de données :
- Toutes les opérations de prétraitement d'image sont spécifiées dans data_transforms
- ImageFolder suppose que tous les fichiers sont enregistrés dans des dossiers. Les images de la même catégorie sont stockées sous chaque dossier. Le nom du dossier est le nom de la catégorie.
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 Nombre de points de données : 6552 Emplacement racine : ./flower_data/train Transformation StandardTransform : Compose( Resize(size=[96, 96], interpolation=bilinear, max_size=None, antialias=None) RandomRotation(degrés =[-45,0, 45,0], interpolation=le plus proche, expand=False, fill=0) CenterCrop(size=(64, 64)) RandomHorizontalFlip(p=0,5) RandomVerticalFlip(p=0,5) ColorJitter(luminosité=[0,8, 1,2 ], contraste=[0,9, 1,1], saturation=[0,9, 1,1], teinte=[-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 Nombre de points de données : 818 Emplacement racine : ./flower_data/valid StandardTransform Transformation : Compose( Resize( size=[64, 64], interpolation=bilinéaire, max_size=Aucun, antialias=Aucun) ToTensor() Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ) }
dataloaders
{'train' : <torch.utils.data.dataloader.DataLoader à 0x1e4c50b9400>, 'valide' : <torch.utils.data.dataloader.DataLoader à 0x1e4c51ad128>}
dataset_sizes
{'train' : 6552, 'valide' : 818}
-
Lire le nom réel correspondant au tag
with open('cat_to_name.json', 'r') as f: cat_to_name = json.load(f)
cat_to_name
{'1' : 'primrose rose', '10' : 'chardon globe', '100' : 'fleur de couverture', '101' : 'vigne trompette', '102' : 'lys mûre', '11' : 'muflier', '12' : "pied de poulain", '13' : 'roi protéa', '14' : 'chardon-lance', '15' : 'iris jaune', '16' : 'globe-fleur', '17' : 'échinacée pourpre', '18' : 'lys péruvien', '19' : 'fleur en ballon', '2' : 'orchidée de poche à feuilles dures', '20' : 'lys arum blanc géant', '21' : 'lys de feu', '22' : 'fleur en coussinet', '23' : 'fritillaire', '24' : 'gingembre rouge', '25' : 'jacinthe de raisin', '26' : 'maïs coquelicot', '27' : 'prince' de plumes de Pays de Galles', '28' : 'gentiane sans tige', '29' : 'artichaut', '3' : 'cloches de Canterbury', '30' : 'sweet william', '31' : 'œillet', ' 32' : 'phlox de jardin'. ', '33' : 'l'amour dans la brume', '34' : 'aster mexicain', '35' : 'holly de mer alpin', '36' : 'Cattleya aux lèvres rubis', '37' : 'fleur du Cap ', '38' : 'grande masterwort', '39' : 'tulipe siam', '4' : 'pois de senteur', '40' : 'rose de carême', '41' : 'marguerite barbeton', '42' :'jonquille', '43' : 'lys épée', '44' : 'poinsettia', '45' : 'boléro bleu profond', '46' : 'giroflée', '48' '47 ' : 'souci', : 'renoncule', '49' : 'marguerite', '5' : 'souci anglais', '50' : 'pissenlit commun', '51' : 'pétunia', '52' : 'pensée sauvage', '53' : 'primula' , '54' : 'tournesol', '55' : 'pélargonium', '56' : 'évêque de llandaff', '57' : 'gaura', '58' : 'géranium', '59' : 'dahlia orange ', '6' : 'lys tigre', '60' : 'dahlia rose-jaune', '61' : 'cautleya spicata', '62' : 'anémone du Japon', '63' : 'susan aux yeux noirs' , '64' : 'silverbush', '65' : 'pavot de Californie', '66' : 'osteospermum', '67' : 'crocus printanier', '68' : 'iris barbu', '69' : 'windflower' , '7' : 'orchidée lunaire', '92' : 'baume d'abeille', '70' : 'arbre coquelicot', '71' : 'gazania', '72' : 'azalée', '73' : 'nénuphar', '74' : 'rose', '75' : 'pomme épineuse', '76' : 'gloire du matin' , '77' : 'passiflore', '78' : 'lotus lotus', '79' : 'lys crapaud', '8' : 'oiseau de paradis', '80' : 'anthurium', '81' : 'frangipanier', '82' : 'clématite', '83' : 'hibiscus', '84' : 'ancolie', '85' : 'rose du désert', ' 86' : 'mauve', '87' :'magnolia', '88' : 'cyclamen', '89' : 'cresson', '9' : 'monkshood', '90' : 'canna lily', '91' : 'hippeastrum', '93' : ' mousse en boule', '94': 'digitale', '95' : 'bougainvillier', '96' : 'camélia', '97' : 'mauve', '98' : 'pétunia mexicain', '99' : 'bromélia'}
-
Chargez le modèle fourni dans models et utilisez directement les poids entraînés comme paramètres d'initialisation
- La première exécution nécessite un téléchargement qui peut être lent, je vous fournirai une copie téléchargée qui pourra être directement placée dans le chemin correspondant.
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 n'est pas disponible. Formation sur CPU...
-
Les paramètres du modèle doivent-ils être mis à jour ?
- Parfois, j'utilise les modèles d'autres personnes, et je continue à les utiliser, sans parler de les mettre à jour. Nous pouvons les personnaliser nous-mêmes.
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), biais=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, dilatation=1, ceil_mode= False) (layer1) : Sequential( (0) : BasicBlock( (conv1) : Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), biais= Faux) (bn1) : BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ( relu) : ReLU(inplace=True) ) (1) : BasicBlock( (conv2) : Conv2d(64, 64, kernel_size= (3, 3), foulée=(1, 1), rembourrage=(1, 1), biais=False) (bn2) : BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv1) : Conv2d(64 , 64, kernel_size=(3, 3), stride=(1, 1 ), padding=(1, 1), biais=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), biais=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), remplissage=(1, 1), biais=Faux) (bn1) : BatchNorm2d(128, eps=1e-05, momentum=0,1, affine=True, track_running_stats=True) relu) : ReLU(inplace=True) relu) : ReLU(inplace=True) (conv2) : Conv2d(128, 128, kernel_size= (3, 3), foulée=(1, 1), rembourrage=(1, 1), biais=False) (bn2) : BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ( sous-échantillonnage) : Sequential( (0) : Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), biais=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), biais=False) (bn1) : BatchNorm2d(128, eps=1e-05, momentum = 0.1, affine=True, track_running_stats=True) (conv2) : Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), biais=False) ( bn2 ) : BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ( 0 ) : BasicBlock( (conv1) : Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), biais=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), biais=False) (bn2) : BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (sous- échantillonnage) : Séquentiel( (0) : Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), biais=False) (1) : BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ) (conv1) : Conv2d (conv1) : Conv2d(256, 512, kernel_size=(3, 3), stride=( 2, 2), remplissage=(1, 1), biais=Faux) BasicBlock ( (conv1) : Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), biais=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), biais=False) (bn2) : BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ) ) ( layer4 ) : Séquentiel( (0) : BasicBlock( (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), foulée=(1, 1), rembourrage=(1, 1), biais=False) (bn2) : BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ( sous-échantillonnage) : Sequential( (0) : Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), biais=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), biais=False) (bn1) : BatchNorm2d(512, eps=1e-05, momentum = 0.1, affine=True, track_running_stats=True) bn2 ) : 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), biais=False) ) ) (avgpool) : AdaptiveAvgPool2d(output_size = ( 1 , 1)) (fc) : Linéaire (in_features=512, out_features=1000, biais=True)
-
Remplacez la couche de sortie du modèle par la vôtre
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
Définir les couches qui doivent être entraînées
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)
Paramètres à apprendre : fc.weight fc.bias
-
model_ft
ResNet( (conv1) : Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), biais=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, dilatation=1, ceil_mode= False) (layer1) : Sequential( (0) : BasicBlock( (conv1) : Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), biais= Faux) (bn1) : BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ( relu) : ReLU(inplace=True) ) (1) : BasicBlock( (conv2) : Conv2d(64, 64, kernel_size= (3, 3), foulée=(1, 1), rembourrage=(1, 1), biais=False) (bn2) : BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv1) : Conv2d(64 , 64, kernel_size=(3, 3), stride=(1, 1 ), padding=(1, 1), biais=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), biais=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), remplissage=(1, 1), biais=Faux) (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), foulée=(1, 1), rembourrage=(1, 1), biais=False) (bn2) : BatchNorm2d(128, eps=1e-05, momentum=0,1, affine=True, track_running_stats= True) (sous-échantillonnage) : Sequential( (0) : Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), biais=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), biais=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), biais=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), biais= Faux) (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), foulée=(1, 1), padding=(1, 1), biais=False) (bn2) : BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats= True) (sous-échantillonnage) : Sequential( (0) : Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), biais=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), biais=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), biais=False) (bn2) : BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ) ) ( layer4 ) : Séquentiel( (0) : BasicBlock( (conv1) : Conv2d(256, 512, kernel_size=(3, 3), stride=( 2, 2), remplissage=(1, 1), biais=Faux) (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), foulée=(1, 1), rembourrage=(1, 1), biais=False) (bn2) : BatchNorm2d(512, eps=1e-05, momentum=0,1, affine=True, track_running_stats= True) (sous-échantillonnage) : Sequential( (0) : Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), biais=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), biais=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), biais=False) ( bn2 ) : BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ) ) (avgpool) : AdaptiveAvgPool2d(output_size=(1, 1)) (fc) : Linéaire(in_features=512, out_features=102, biais=True) )
-
Paramètres de l'optimiseur
# 优化器设置 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()
module de formation
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
Commence l'entraînement!
- Nous formons désormais uniquement la couche de sortie
model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs = train_model(model_ft, dataloaders, criterion, optimizer_ft, num_epochs=20)
Époque 0/19 ---------- Temps écoulé 0m 39s train Perte : 4.0874 Acc : 0.2355 Temps écoulé 0m 43s valide Perte : 3.5746 Acc : 0.2531 Taux d'apprentissage de l'optimiseur : 0.0100000 Époque 1/19 ----- ----- Temps écoulé 1m 22s train Perte : 2,8185 Acc : 0,3953 Temps écoulé 1m 26s valide Perte : 3,5450 Acc : 0,3142 Taux d'apprentissage de l'optimiseur : 0,0100000 Époque 2/19 ---------- Temps écoulé 2m 5s Perte du train : 2,7673 Acc : 0,4174 Temps écoulé 2m 9s valide Perte : 3,9110 Acc : 0,2653 Taux d'apprentissage de l'optimiseur : 0,0100000 Époque 3/19 ---------- Temps écoulé 2m 48s Perte du train : 2,7962 Acc : 0,4255 Temps écoulé 2m 52s valide Perte : 3,6922 Acc : 0,3142 Taux d'apprentissage de l'optimiseur : 0,0100000 Époque 4/19 ---------- Temps écoulé 3m 32s train Perte : 2,7453 Acc : 0,4428 Temps écoulé 3m 36s valide Perte : 3,9310 Acc : 0.3044 Taux d'apprentissage de l'optimiseur : 0.0100000 Époque 5/19 ---------- Temps écoulé 4m 14s train Perte : 2.2935 Acc : 0.5043 Temps écoulé 4m 18s valide Perte : 3.3299 Acc : 0.3435 Taux d'apprentissage de l'optimiseur : 0.0010000 Époque 6 /19 ---------- Temps écoulé 4m 57s train Perte : 2.0654 Acc : 0.5258 Temps écoulé 5m 1s Perte valide : 3.2608 Acc : 0.3411 Taux d'apprentissage de l'optimiseur : 0.0010000 Époque 7/19 ---------- Temps écoulé 5m 40s train Perte : 1,9603 Acc : 0,5369 Temps écoulé 5m 44s valide Perte : 3,2618 Acc : 0,3472 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 8/19 ----- ----- Temps écoulé 6m 23s train Perte : 1,9216 Acc : 0,5401 Temps écoulé 6m 27s valide Perte : 3,1651 Acc : 0,3386 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 9/19 ---------- Temps écoulé 7m 5s Perte du train : 1,9203 Acc : 0,5458 Temps écoulé 7m 9s Perte valide : 3,0449 Acc : 0,3680 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 10/19 Perte du train : 1,8366 Acc : 0,5553 ---------- Temps écoulé 7m 48s Temps écoulé 7m 52s valide Perte : 3,0722 Acc : 0,3545 Taux d'apprentissage de l'optimiseur : 0,0001000 Époque 11/19 ---------- Temps écoulé 8m 31s train Perte : 1,8324 Acc : 0,5546 Temps écoulé 8m 35s valide Perte : 3,0115 Acc : 0,3643 Taux d'apprentissage de l'optimiseur : 0,0001000 Époque 12/19 ---------- Temps écoulé 9m 13s train Perte : 1,8054 Acc : 0,5553 Temps écoulé 9m 17s valide Perte : 3,0688 Acc : 0,3619 Taux d'apprentissage de l'optimiseur : 0.0001000 Époque 13/19 ---------- Temps écoulé 9m 56s train Perte : 1.8436 Acc : 0.5534 Temps écoulé 10m 0s Perte valide : 3,0100 Acc : 0,3631 ---------- Taux d'apprentissage de l'optimiseur : 0.0001000 Époque 14/19 ---------- Temps écoulé 10m 39s train Perte : 1.7417 Acc : 0.5614 Temps écoulé 10m 43s valide Perte : 3.0129 Acc : 0.3655 Taux d'apprentissage de l'optimiseur : 0.0001000 Époque 15/19 ----- ----- Temps écoulé 11m 22s train Perte : 1.7610 Acc : 0.5672 Temps écoulé 11m 26s valide Perte : 3.0220 Acc : 0.3606 Taux d'apprentissage de l'optimiseur : 0.0000100 Époque 16/19 ---------- Temps écoulé 12m 6s Perte du train : 1,7788 Acc : 0,5676 Temps écoulé 12m 10s Perte valide : 3,0104 Acc : 0,3557 Taux d'apprentissage de l'optimiseur : 0,0000100 Époque 17/19 Temps écoulé 12m 49s train Perte : 1.8033 Acc : 0.5638 Temps écoulé 12m 53s valide Perte : 3.0428 Acc : 0.3606 Taux d'apprentissage de l'optimiseur : 0.0000100 Époque 18/19 ---------- Temps écoulé 13m 33s train Perte : 1.8294 Acc : 0.5568 Temps écoulé 13m 37s valide Perte : 3.0307 Acc : 0.3509 Taux d'apprentissage de l'optimiseur : 0.0000100 Époque 19/19 ---------- Temps écoulé 14m 16s train Perte : 1.7949 Acc : 0.5612 Temps écoulé 14m 20s valide Perte : 3,0396 Acc : 0,3643 Taux d'apprentissage de l'optimiseur : 0,0000100 Formation terminée en 14 min 20 s Meilleur val Acc : 0,367971
-
Continuez ensuite à entraîner toutes les couches
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,)
Époque 0/9 ---------- Temps écoulé 1m 32s train Perte : 2,2451 Acc : 0,4846 Temps écoulé 1m 36s valide Perte : 2,3190 Acc : 0,4633 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 1/9 ----- ----- Temps écoulé 2m 54s train Perte : 1.2920 Acc : 0.6505 Temps écoulé 2m 58s valide Perte : 2.2263 Acc : 0.4670 Taux d'apprentissage de l'optimiseur : 0.0010000 Époque 2/9 ---------- Temps écoulé 4m 15s Perte du train : 1,1026 Acc : 0,6993 Temps écoulé 4m 19s Perte valide : 1,8115 Acc : 0,5452 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 3/9 ---------- Temps écoulé 5m 35s Perte du train : 0,9062 Acc : 0,7515 Temps écoulé 9m 42s Temps écoulé 5m 39s valide Perte : 2,0045 Acc : 0,5403 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 4/9 ---------- Temps écoulé 6m 56s train Perte : 0,8392 Acc : 0,7643 Temps écoulé 7m 0s valide Perte : 2,1381 Acc : 0.5171 Taux d'apprentissage de l'optimiseur : 0.0010000 Époque 5/9 ---------- Temps écoulé 8m 17s train Perte : 0.7081 Acc : 0.7953 Temps écoulé 8m 21s valide Perte : 2.0461 Acc : 0.5599 Taux d'apprentissage de l'optimiseur : 0.0010000 Époque 6 /9 ---------- Temps écoulé 9m 38s train Perte : 0,6400 Acc : 0,8147 Perte valide : 2,2603 Acc : 0,5452 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 7/9 ---------- Temps écoulé 10m 59s Train Perte : 0,6406 Acc : 0,8117 Temps écoulé 11m 3s Perte valide : 1,4649 Acc : 0,6406 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 8 /9 ---------- Temps écoulé 12m 20s train Perte : 0,5686 Acc : 0,8300 Temps écoulé 12m 24s valide Perte : 1,7538 Acc : 0,6100 Taux d'apprentissage de l'optimiseur : 0,0010000 Époque 9/9 ------- --- Temps écoulé 13m 41s train Perte : 0,5978 Acc : 0,8245 Temps écoulé 13m 45s valide Perte : 1,6953 Acc : 0,6161 Taux d'apprentissage de l'optimiseur : 0,0010000 Entraînement terminé en 13m 45s Meilleur val Acc : 0,640587
-
Charger le modèle entraîné
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'])
Prétraitement des données de test
- La méthode de traitement des données de test doit être la même que lors de la formation.
- Le but de l’opération de culture est de garantir que la taille des intrants est cohérente
- Des opérations de normalisation sont également nécessaires. Utilisez la même moyenne et la même norme que les données d'entraînement. Cependant, il convient de noter que les données d'entraînement sont standardisées sur 0-1, donc les données de test doivent également être normalisées en premier.
- Enfin, le canal de couleur dans PyTorch est la première dimension, qui est différente de nombreuses boîtes à outils et doit être convertie.
-
# 得到一个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)
Le résultat représente la probabilité que chaque donnée d'un lot appartienne à chaque catégorie.
output.shape
Obtenez celui avec la probabilité la plus élevée
_, 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)
Afficher les résultats de la prédiction
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()