当前位置:   article > 正文

pytorch:图像识别模型与自适应策略_set_parameter_requires_grad

set_parameter_requires_grad

数据预处理部分:

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

网络模块设置:

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

网络模型保存与测试

  • 模型保存的时候可以带有选择性,例如在验证集中如果当前效果好则保存
  • 读取模型进行实际测试

 1.任务分析与图像数据基本处理

        导入所需要的模块

  1. import os
  2. import matplotlib.pyplot as plt
  3. %matplotlib inline
  4. import numpy as np
  5. import torch
  6. from torch import nn
  7. import torch.optim as optim
  8. import torchvision
  9. #pip install torchvision
  10. from torchvision import transforms, models, datasets
  11. #https://pytorch.org/docs/stable/torchvision/index.html
  12. import imageio
  13. import time
  14. import warnings
  15. warnings.filterwarnings("ignore")
  16. import random
  17. import sys
  18. import copy
  19. import json
  20. from PIL import Image

2.数据读取与预处理操作

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

制作好数据源:

  • data_transforms中指定了所有图像预处理操作
  • ImageFolder假设所有的文件按文件夹保存好,每个文件夹下面存贮同一类别的图片,文件夹的名字为分类的名字
  1. data_transforms = {
  2. 'train':
  3. transforms.Compose([
  4. transforms.Resize([96, 96]),
  5. transforms.RandomRotation(45),#随机旋转,-4545度之间随机选
  6. transforms.CenterCrop(64),#从中心开始裁剪
  7. transforms.RandomHorizontalFlip(p=0.5),#随机水平翻转 选择一个概率概率
  8. transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转
  9. transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
  10. transforms.RandomGrayscale(p=0.025),#概率转换成灰度率,3通道就是R=G=B
  11. transforms.ToTensor(),
  12. transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#均值,标准差
  13. ]),
  14. 'valid':
  15. transforms.Compose([
  16. transforms.Resize([64, 64]),
  17. transforms.ToTensor(),
  18. transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
  19. ]),
  20. }

使用imageFolder方法加载数据集 

  1. batch_size = 128
  2. image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'valid']}
  3. dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True) for x in ['train', 'valid']}
  4. dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'valid']}
  5. class_names = image_datasets['train'].classes

        其中,数据的目录结构为flower_data下有训练数据train和测试数据valid,train/valid下存入对应花的种类的文件夹 

 

读取标签对应的实际名字

3.迁移学习方法 

        加载models中提供的模型,并且直接用训练的好权重当做初始化参数

  1. model_name = 'resnet' #可选的比较多 ['resnet', 'alexnet', 'vgg', 'squeezenet', 'densenet', 'inception']
  2. #是否用人家训练好的特征来做
  3. feature_extract = True #使用预训练权重,先不更新参数
  1. # 是否用GPU训练
  2. train_on_gpu = torch.cuda.is_available()
  3. if not train_on_gpu:
  4. print('CUDA is not available. Training on CPU ...')
  5. else:
  6. print('CUDA is available! Training on GPU ...')
  7. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

加载resnet18模型

首先,我们先不更新权重,只调节全连接层的权重

  1. def set_parameter_requires_grad(model, feature_extracting):
  2. if feature_extracting:
  3. for param in model.parameters():
  4. param.requires_grad = False

重新设置自己的输出层,并设置不更新输出层以下的权重

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

加载模型,并打印出需要更新权重的层:

  1. model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
  2. #GPU还是CPU计算
  3. model_ft = model_ft.to(device)
  4. # 模型保存,名字自己起
  5. filename='checkpoint.pth'
  6. # 是否训练所有层
  7. params_to_update = model_ft.parameters()
  8. print("Params to learn:")
  9. if feature_extract:
  10. params_to_update = []
  11. for name,param in model_ft.named_parameters():
  12. if param.requires_grad == True:
  13. params_to_update.append(param)
  14. print("\t",name)
  15. else:
  16. for name,param in model_ft.named_parameters():
  17. if param.requires_grad == True:
  18. print("\t",name)

 优化器设置:

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

训练模块:

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

  

解冻训练,更新所有的参数

 

  1. for param in model_ft.parameters():
  2. param.requires_grad = True
  3. # 再继续训练所有的参数,学习率调小一点
  4. optimizer = optim.Adam(model_ft.parameters(), lr=1e-3)
  5. scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
  6. # 损失函数
  7. criterion = nn.CrossEntropyLoss()
  1. # 加载之前训练好的权重参数
  2. checkpoint = torch.load(filename)
  3. best_acc = checkpoint['best_acc']
  4. model_ft.load_state_dict(checkpoint['state_dict'])

 

4.测试模块 

加载训练好的模型

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

试数据预处理

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

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

得到概率最大的那个作为预测结果:

 

展示预测结果

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

 

 

 

 

 

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/262319
推荐阅读
相关标签
  

闽ICP备14008679号