Pytorch入门教程14-Pytorch中的经典网络结构

  • A+
所属分类:Pytorch快速入门
摘要在Pytoch中, 会有一些已经预训练好的模型, 我们可以使用这些模型来加快我们的训练速度. 这一篇就是会介绍如何使用Pytorch中的已经定义好的模型. 我们会使用一个简单的迁移学习来作为例子进行说明.

简介

在Pytorch中(torchvision.model之中), 会有一些经典的网络结构, 这些网络结构是已经经过训练, 有较好的初始化系数, 我们可以利用这些模型来做进一步的训练.

这一篇我们会介绍如何使用Pytorch中的已经定义好的模型. 我们会使用一个简单的迁移学习来作为例子进行说明.

关于这一篇的相关代码, 可以在github上查看Pytorch中经典网络结构与迁移学习.ipynb

 

简单的迁移学习例子

在这里我们会完成一个对蚂蚁和蜜蜂的二分类器. 但是数据集都不大, 我们会使用Pytorch中预训练好的resnet18网络, 来对数据完成训练.

实验的数据集

数据集的结构如下所示, 之后可以使用ImageFolder来封装(实验的数据集就不上传了, 这里就作为一个简单的例子, 说明Pytorch如何使用预训练的网络):

  • train(训练集)
    • ants
    • bees
  • val(测试集)
    • ants
    • bees

我们简单查看一下数据集, 从中选出4张图片来进行展示.

  1. # 显示一下具体的图像
  2. dirPath = '/content/drive/My Drive/Machine Learning/dataset/hymenoptera_data_Unzipped/'
  3. imageList = [dirPath+'hymenoptera_data/train/ants/178538489_bec7649292.jpg', dirPath+'hymenoptera_data/train/ants/424873399_47658a91fb.jpg',
  4.             dirPath+'hymenoptera_data/train/ants/533848102_70a85ad6dd.jpg', dirPath+'hymenoptera_data/train/bees/196658222_3fffd79c67.jpg']
  5. fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(6,6))
  6. for i, img_path in enumerate(imageList):
  7.     img_check1 = cv2.imread(img_path, cv2.IMREAD_COLOR)
  8.     img_check1 = cv2.cvtColor(img_check1, cv2.COLOR_BGR2RGB) # BGR => RGB
  9.     # 图片进行显示
  10.     axes[i//2, i%2].axis("off")
  11.     axes[i//2, i%2].imshow(img_check1)
  12. fig.tight_layout()
Pytorch入门教程14-Pytorch中的经典网络结构

 

数据预处理

在数据预处理的时候, 我们会对原始图片进行旋转等操作, 这样增加数据的多样性(这里并没有增加数据的数量, 只是增加了多样性)

  1. mean = np.array([0.5, 0.5, 0.5])
  2. std = np.array([0.25, 0.25, 0.25])
  3. data_transforms = {
  4.     'train': transforms.Compose([
  5.         # 加入旋转等数据增强技术,加大模型训练的难度,提高模型的稳健性
  6.         transforms.RandomResizedCrop(224), # 随机剪裁
  7.         transforms.RandomHorizontalFlip(), # 随机水平翻转
  8.         transforms.ToTensor(),
  9.         transforms.Normalize(mean, std)
  10.     ]),
  11.     # 测试集输入时,无需加入旋转等操作
  12.     'val': transforms.Compose([
  13.         # resize 操作的目的是将任意大小的图片转为模型规定的输入大小
  14.         transforms.RandomResizedCrop(224),
  15.         transforms.ToTensor(),
  16.         transforms.Normalize(mean, std)
  17.     ]),
  18. }

 

数据的封装

上面定义好数据预处理的内容之后, 下面对数据进行封装. 首先从image放入dataset, 再将dataset传入dataloader中去.

  1. dirPath = '/content/drive/My Drive/Machine Learning/dataset/hymenoptera_data_Unzipped/hymenoptera_data'
  2. # 将数据集封装到 PyTorch 中数据加载器中
  3. image_datasets = {x: torchvision.datasets.ImageFolder(os.path.join(dirPath, x), data_transforms[x]) for x in ['train', 'val']}
  4. dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=20, shuffle=True, num_workers=0) for x in ['train', 'val']}

接着我们看一下训练集和测试集里面ants和bees两种类别图片各自的数量.

  1. dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
  2. # 看一下训练集和测试集里面两类的数量
  3. print('Train: ', image_datasets['train'].targets.count(0), image_datasets['train'].targets.count(1))
  4. print('Test:', image_datasets['val'].targets.count(0), image_datasets['val'].targets.count(1))
  5. """
  6. Train:  123 121
  7. Test: 70 83
  8. """

 

模型的建立

因为这里我们会使用预先训练好的模型, 使用预先初始化好的系数. 我们使用resnet18网络.

  1. model = torchvision.models.resnet18(pretrained=True).to(device)

但是, 因为在原始的resnet18中, output是1000. 但是在我们的这个需求里面, output是2. 所以我们修改他的output.

  1. num_ftrs = model.fc.in_features
  2. model.fc = nn.Linear(num_ftrs, 2) # 重新定义 fc:输入节点数不变的情况下,将输出节点改为 2
  3. model = model.to(device)
  4. model.fc
  5. """
  6. Linear(in_features=512, out_features=2, bias=True)
  7. """

 

定义损失函数与优化器

接着我们定义了损失函数和优化器. 同时我们定义了一个可以让学习率逐渐下降的lr_scheduler.

  1. criterion = nn.CrossEntropyLoss()
  2. optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
  3. step_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.8)

 

模型的训练与测试

最后, 我们对上面的模型开始训练, 并进行测试. 同时这次, 我们会保存模型在测试集上最优的一次结果, 保存此时模型的系数. 模型的系数保存在best_model_wts中.

  1. best_model_wts = copycopy.deepcopy(model.state_dict())
  2. best_acc = 0.0
  3. num_epochs = 10
  4. n_total_steps = len(dataloaders['train'])
  5. LossList = [] # 记录每一个epoch的loss
  6. AccuryList = [] # 每一个epoch的accury
  7. for epoch in range(num_epochs):
  8.     # -------
  9.     # 开始训练
  10.     # -------
  11.     model.train() # 切换为训练模型
  12.     totalLoss = 0
  13.     for i, (images, labels) in enumerate(dataloaders['train']):
  14.         images = images.to(device) # 图片大小转换
  15.         labels = labels.to(device)
  16.         # 正向传播以及损失的求取
  17.         outputs = model(images)
  18.         loss = criterion(outputs, labels)
  19.         totalLoss = totalLoss + loss.item()
  20.         # 反向传播
  21.         optimizer.zero_grad() # 梯度清空
  22.         loss.backward() # 反向传播
  23.         optimizer.step() # 权重更新
  24.         step_lr_scheduler.step()
  25.         if (i+1) % 3 == 0:
  26.             print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}, LR: {:.4f}'.format(epoch+1, num_epochs, i+1, n_total_steps, totalLoss/(i+1), optimizer.param_groups[0]['lr']))
  27.     LossList.append(totalLoss/(i+1))
  28.     # ---------
  29.     # 开始测试
  30.     # ---------
  31.     model.eval()
  32.     with torch.no_grad():
  33.         correct = 0
  34.         total = 0
  35.         for images, labels in dataloaders['val']:
  36.             images = images.to(device)
  37.             labels = labels.to(device)
  38.             outputs = model(images)
  39.             _, predicted = torch.max(outputs.data, 1) # 预测的结果
  40.             total += labels.size(0)
  41.             correct += (predicted == labels).sum().item()
  42.         acc = 100.0 * correct / total # 在测试集上总的准确率
  43.         AccuryList.append(acc)
  44.         if acc > best_acc:
  45.             best_acc = acc
  46.             best_model_wts = copycopy.deepcopy(model.state_dict())
  47.             print('更新模型参数, {}'.format(epoch))
  48.         print('Accuracy of the network on the {} test images: {} %'.format(total, acc))
  49. print("模型训练完成")
  50. """
  51. Epoch [10/10], Step [3/13], Loss: 0.1648, LR: 0.0001
  52. Epoch [10/10], Step [6/13], Loss: 0.1952, LR: 0.0001
  53. Epoch [10/10], Step [9/13], Loss: 0.2066, LR: 0.0001
  54. Epoch [10/10], Step [12/13], Loss: 0.2060, LR: 0.0001
  55. Accuracy of the network on the 153 test images: 93.4640522875817 %
  56. 模型训练完成
  57. """

最终我们的模型在测试集上的准确率可以得到90%以上. 准确率如下图所示:

Pytorch入门教程14-Pytorch中的经典网络结构
  • 微信公众号
  • 关注微信公众号
  • weinxin
  • QQ群
  • 我们的QQ群号
  • weinxin
王 茂南

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: