pytorch学习笔记-迁移学习

pytorch实现迁移学习

一、迁移学习

使用已经训练好的神经网络,通过更改最后的全连接层,移植至新的分类任务中去。

案例1:

训练集包含了244张蜜蜂与蚂蚁的图片,由于训练集数量较少,我们很难实现一个理想的网络训练。而迁移学习使得这个目的成为可能。
使用18层残差网络,去除最后的全连接层,使其适合当前的分类任务。

net = models.resnet18(pretrained=True)
# 存储了fc层输入神经元个数
num_ftrs = net.fc.in_features
# 替换网络的fc层
net.fc = nn.Linear(num_ftrs, 2)

直接使用244张照片训练,在验证集上的正确率仅为52%左右,分类器完全不具备实用价值。

在使用了残差网络进行迁移学习之后,分类准确率达到了94%左右,迁移学习的效果明显。

附代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch import optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms, models

# 定义超参数
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
epoches = 20
batch_size = 4
train_path = 'HGD/train'
val_path = 'HGD/val'
# pipline
train_pipline = transforms.Compose(
    [
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]
)
val_pipline = transforms.Compose(
    [
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]
)
# 读入图片
train_data = datasets.ImageFolder(train_path, transform=train_pipline)
val_data = datasets.ImageFolder(val_path, transform=val_pipline)
# 数据加载器,num_worker表示同时进行的子进程数量
train_loader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True, num_workers=4)
val_loader = DataLoader(val_data, batch_size=batch_size, shuffle=False, num_workers=4)

net = models.resnet18(pretrained=True)
# 存储了fc层输入神经元个数
num_ftrs = net.fc.in_features
# 替换网络的fc层
net.fc = nn.Linear(num_ftrs, 2)



def train(model, device, epoch, train_loader, optimizer):
    model.train()
    for batch_index, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        result = model(data)
        loss = F.cross_entropy(result, target)
        loss.backward()
        optimizer.step()
        if batch_index % 61 == 0:
            print('train in epoch {} \t loss is {:.3f}'.format(epoch, loss))


def val(model, device, val_loader):
    model.eval()
    acc = 0.0
    val_loss = 0.0
    with torch.no_grad():
        for (data, target) in val_loader:
            data, target = data.to(device), target.to(device)
            out = model(data)
            val_loss += F.cross_entropy(out, target).item()
            pred = out.argmax(dim=1)
            acc += pred.eq(target.view_as(pred)).sum().item()
        val_loss /= len(val_loader.dataset)
        print('test average loss:{:.4f}, accuracy:{:.3f}\n'.format(val_loss, 100.0 * acc / len(val_loader.dataset)))


net.to(device)
optimizer = optim.SGD(net.parameters(), lr=0.0001, momentum=0.9)
criterion = nn.CrossEntropyLoss()

if __name__ == '__main__':
    for epoch in range(epoches):
        epoch += 1
        train(net, device, epoch, train_loader, optimizer)
        val(net, device, val_loader)

案例一中学习到的一些知识

1、从torchvision中调用的model模块中的网络,和我们实现常规的神经网络所定义的类十分相似。作为一个封装好的网络,可以直接通过net.fc来访问类中的属性值并将其修改。
2、若要实现仅仅针对最后的全连接层进行反向传播,应该添加下列命令:

for param in net.parameters():
	param.requires_grad = False

其中net.parameters()包含了网络中所有的可训练参数,包括权重及偏置,该命令将网络的梯度设置为不需要,因此无法修改网络参数值。
在这里两种迁移学习方法性能差距不大。

案例2

手写数字加法器——使用自己训练的网络进行模型迁移
模型迁移,就是将我们训练好的特征图、权重等参数去初始化另一个模型的对应参数。

我们使用之前训练过的手写数字识别器的网络参数。

1、保存训练好的的模型并使用它进行训练

(1)保存模型参数以及网络结构
使用命令

module = net()
:
:训练过程
:
torch.save(module, pathname)

保存模型,注意,这里的module是代码中进行过实例化的模型名,而不是定义过的网络对应的类名。
(2)使用保存好的模型
使用保存好的模型进行训练:
在使用前,需要将原来的网络类重新定义,但无需写初始化函数__init__()内的内容,forward()函数直接复制过来。
再将其实例化,以及load即可:

origin_net = Convnet()
origin_net = torch.load('minst_checkpoint')

你可能感兴趣的:(pytorch,神经网络,深度学习,迁移学习)