迁移学习实例
目录
前言
深度学习一般需要大数据、深网络,但很多情况下我们并不能同时获取这些条件,但我们又想获得一个高性能的网络模型,这个时候,迁移学习就是一个很好的方法。本文将对迁移学习进行简单介绍,并运用实例讲解如何实现迁移学习。
一、什么是迁移学习?
迁移学习是机器学习的一种学习方法,其主要是把在任务A中训练得到的网络模型,通过调整和处理,使用到任务B中。迁移学习在人类生活中很常见,最简单的例子就是我们学完C语言后,再学习python就会感到很容易。
在神经网络迁移学习过程中,主要有两个应用场景:
- 特征提取:冻结除最后的全连接层之外的所有网络的权重,最后一个全连接层被替换为具有随机权重的新层,并且仅训练新层
- 微调:使用预训练好的初始化网络,用新数据训练部分或整个网络
在本文中,我们主要将使用特征提取进行实例训练。
二、特征提取介绍
特征提取是迁移学习的一个重要方法,其主要是先引入预训练好的网络模型,在预训练好的网络模型中添加一个简单的分类器,将原网络作为新任务的特征提取器,只对最后增加的分类器参数进行重新学习。
三、实例介绍
1.获取预训练的网络模型
pytorch中,有很多已经训练好的网络模型,我们可以使用model命令来下载这部分模型
from torchvision import models
net = models.resnet18(pretrained=True)
这里我下载的是ResNet18模型。除了ResNet18,pytorch还提供的已经训练好的模型有:“
- AlexNet
- VGG
- ResNet
- SqueezeNet
- DenseNet
- Inception v3
- GoogLeNet
- ShuffleNet v2”
关于ResNet的网络模型结构如图:
2.使用数据增强
在加载数据集之前,我们可以先使用一些数据增强手段对图像进行处理,例如随机的缩放、反转等
trains_train = transforms.Compose(
[transforms.RandomResizedCrop(224), # 将给定图像随机裁剪为不同的大小和宽高比,然后缩放所裁剪得到的图像为指定的大小;改成224*224
transforms.RandomHorizontalFlip(), # 图像按照一定概率水平翻转
transforms.ToTensor(), # 转成tensor数据类型
transforms.Normalize(mean=[0.485, 0.456, 0.406], # 归一化处理
std=[0.229, 0.224, 0.225])]
)
trains_valid = transforms.Compose(
[transforms.Resize(256),
transforms.CenterCrop(224), # 在图片中间区域进行裁剪
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], # 归一化处理
std=[0.229, 0.224, 0.225])]
)
3.冻结模型参数
将原网络模型中的部分参数冻结,冻结的参数在反向传播中将不会被 更新
for param in net.parameters():
param.requires_grad = False
4.修改最后一层的输出类别数
员阿里输出为512*1000,如果是使用CIFAR10数据集, 该数据集一共有10个类别,需要把最后的1000改成10
net.fc = nn.Linear(512, 10)
5.定义损失函数和优化器
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
#loss_fn = loss_fn.to(device),imgs和targets同理
#定义优化器
learning_rate = 0.01
optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate, momentum=0.5)
6.训练及验证模型
for i in range(epoch):
print("第{}轮训练开始".format(i+1))
#训练步骤开始
for data in train_loader:
imgs, targets = data
imgs = imgs.to(device)
targets = targets.to(device)
outputs = net(imgs)
loss = loss_fn(outputs, targets)
#优化器优化模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step = total_train_step + 1
print("训练次数: {}, Loss {}".format(total_train_step, loss))
7.完整的代码:
import torch
from torch import nn
import torchvision
import torchvision.transforms as transforms
from torchvision import models
from torch.utils.data import DataLoader
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
trains_train = transforms.Compose(
[transforms.RandomResizedCrop(224), # 将给定图像随机裁剪为不同的大小和宽高比,然后缩放所裁剪得到的图像为指定的大小;改成224*224
transforms.RandomHorizontalFlip(), # 图像按照一定概率水平翻转
transforms.ToTensor(), # 转成tensor数据类型
transforms.Normalize(mean=[0.485, 0.456, 0.406], # 归一化处理
std=[0.229, 0.224, 0.225])]
)
trains_valid = transforms.Compose(
[transforms.Resize(256),
transforms.CenterCrop(224), # 在图片中间区域进行裁剪
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], # 归一化处理
std=[0.229, 0.224, 0.225])]
)
train_set = torchvision.datasets.CIFAR10("D:\pytorch_train_log\pytorch_train", train=True, download=True,
transform=trains_train)
test_set = torchvision.datasets.CIFAR10("D:\pytorch_train_log\pytorch_train", train=False, download=True,
transform=trains_valid)
#获得数据集的长度
train_data_size = len(train_set)
test_data_size = len(test_set)
train_loader = DataLoader(train_set, batch_size=64)
test_loader = DataLoader(test_set, batch_size=64)
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
net = models.resnet18(pretrained=True)
for param in net.parameters():
param.requires_grad = False
net.fc = nn.Linear(512, 10)
net = net.to(device)
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
#loss_fn = loss_fn.to(device),imgs和targets同理
#定义优化器
learning_rate = 0.01
optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate, momentum=0.5)
#设置训练网络的参数
total_train_step = 0 #记录训练的次数
total_test_step = 0 #记录测试的次数
epoch = 20 #训练的轮数
for i in range(epoch):
print("第{}轮训练开始".format(i+1))
#训练步骤开始
for data in train_loader:
imgs, targets = data
imgs = imgs.to(device)
targets = targets.to(device)
outputs = net(imgs)
loss = loss_fn(outputs, targets)
#优化器优化模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step = total_train_step + 1
print("训练次数: {}, Loss {}".format(total_train_step, loss))
#测试步骤
total_test_loss = 0
total_accuracy = 0
with torch.no_grad():
for data in test_loader:
imgs, targets = data
imgs = imgs.to(device)
targets = targets.to(device)
outputs = net(imgs)
loss = loss_fn(outputs, targets)
total_test_loss = total_test_loss + loss
accuracy = (outputs.argmax(1) == targets).sum()
total_accuracy = total_accuracy + accuracy
print("整体测试集上的Loss:{}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
total_test_step = total_test_step + 1
torch.save(net, "net_{}.pth".format(i))
print("模型已保存")
总结
本文主要是对迁移学习进行了简单的介绍,通过使用迁移学习,可以极大的加快训练速度,并且相对普通的模型,迁移学习后的网络模型的精度也有较高的提升。