pytorch迁移学习

迁移学习

在开始这部分内容之前,请回顾上一次的内容。
在这部分内容中,您将学习如何使用预训练的网络来解决计算机视觉中的难题。 具体来说,您将使用torchvision提供的ImageNet 训练的网络。

ImageNet是一个庞大的数据集,在1000个类别中有超过100万张带标签的图像。 它用于使用称为卷积层的体系结构训练深度神经网络。 在这里,我将不涉及卷积网络的详细信息,但是如果您想了解更多有关卷积网络的信息,请观看此 内容。

一旦训练完成,这些模型就可以像未经检测的图像特征检测器一样出色地工作。 对不在训练集中的图像使用预先训练的网络称为转移学习。 在这里,我们将使用转移学习来训练一个网络,该网络可以以近乎完美的准确性对猫和狗的照片进行分类。

借助torchvision.models,您可以下载这些经过预训练的网络,并在您的应用程序中使用它们。 现在,我们将在我们的导入中包含 models

%matplotlib inline
%config InlineBackend.figure_format = 'retina'

import matplotlib.pyplot as plt

import torch
from torch import nn
from torch import optim
import torch.nn.functional as F
from torchvision import datasets, transforms, models

大多数经过预训练的模型都要求输入为224x224图像。 另外,我们需要匹配训练模型时使用的归一化。 每个颜色通道分别进行归一化,平均值为[0.485,0.456,0.406],标准偏差为[0.229,0.224,0.225]

data_dir = 'Cat_Dog_data/Cat_Dog_data'

# TODO: Define transforms for the training data and testing data
train_transforms = transforms.Compose([transforms.RandomRotation(30),
                                       transforms.RandomResizedCrop(224),
                                       transforms.RandomHorizontalFlip(),
                                       transforms.ToTensor(),
                                       transforms.Normalize([0.485,0.456,0.406],
                                                             [0.229,0.224,0.225])])

test_transforms = transforms.Compose([transforms.Resize(255),
                                     transforms.CenterCrop(224),
                                     transforms.ToTensor(),
                                     transforms.Normalize([0.485,0.456,0.406],
                                                          [0.229,0.224,0.225])])

# Pass transforms in here, then run the next cell to see how the transforms look
train_data = datasets.ImageFolder(data_dir + '/train', transform=train_transforms)
test_data = datasets.ImageFolder(data_dir + '/test', transform=test_transforms)

trainloader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)
testloader = torch.utils.data.DataLoader(test_data, batch_size=64)

我们可以加载诸如DenseNet的模型。 让我们打印出模型架构,以便我们了解发生了什么。

model = models.densenet121(pretrained=True)
model

该模型由两个主要部分构建,即特征和分类器。 特征部分是卷积层的堆栈,总体上可以作为特征检测器使用,可以输入到分类器中。 分类器部分是单个完全连接的层(classifier): Linear(in_features=1024, out_features=1000)。 该层是在ImageNet数据集上进行训练的,因此不适用于我们的特定问题。 这意味着我们需要替换分类器,但是这些特征可以完美地自己运行。 总的来说,我认为预训练网络是出色的特征检测器,可以用作简单前馈分类器的输入。

# Freeze parameters so we don't backprop through them
for param in model.parameters():
    param.requires_grad = False

from collections import OrderedDict
classifier = nn.Sequential(OrderedDict([
                          ('fc1', nn.Linear(1024, 500)),
                          ('relu', nn.ReLU()),
                          ('fc2', nn.Linear(500, 2)),
                          ('output', nn.LogSoftmax(dim=1))
                          ]))
    
model.classifier = classifier

建立模型后,我们需要训练分类器。 但是,现在我们使用的是真正的深度神经网络。 如果您尝试像通常那样在CPU上进行训练,这将需要很长时间。 相反,我们将使用GPU进行计算。 线性代数计算在GPU上并行完成,从而使训练速度提高了100倍。 还可以在多个GPU上进行训练,从而进一步减少了训练时间。

PyTorch与几乎所有其他深度学习框架一起,使用CUDA来有效地计算GPU上的前向和后向传递。 在PyTorch中,您可以使用model.to('cuda')将模型参数和其他张量移动到GPU内存中。 您可以使用model.to('cpu')将它们从GPU中转移CPU,这通常需要在PyTorch外部的网络输出上进行操作时使用。 为了说明速度的提高,我将比较在有和没有GPU的情况下执行向前和向后传递所需的时间。

import time
for device in ['cpu', 'cuda']:

    criterion = nn.NLLLoss()
    # Only train the classifier parameters, feature parameters are frozen
    optimizer = optim.Adam(model.classifier.parameters(), lr=0.001)

    model.to(device)

    for ii, (inputs, labels) in enumerate(trainloader):

        # Move input and label tensors to the GPU
        inputs, labels = inputs.to(device), labels.to(device)

        start = time.time()

        outputs = model.forward(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        if ii==3:
            break
        
    print(f"Device = {device}; Time per batch: {(time.time() - start)/3:.3f} seconds")
Device = cpu; Time per batch: 3.714 seconds
Device = cuda; Time per batch: 0.021 seconds

您可以编写与device相关的代码,如果启用了该代码,它将自动使用CUDA,如下所示:

# at beginning of the script
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

...

# then whenever you get a new Tensor or Module
# this won't copy if they are already on the desired device
input = data.to(device)
model = MyModule(...).to(device)

从这里,我将让您完成模型的训练。 除了现在您的模型功能更强大之外,该过程与之前相同。 您应该轻松获得优于95%的精度。

练习:训练预训练的模型对猫和狗的图像进行分类。 继续使用DenseNet模型,或尝试使用ResNet,这也是首先尝试的好模型。 确保仅在训练分类器,并且特征部分的参数已冻结。

# Use GPU if it's available
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model = models.densenet121(pretrained=True)

# Freeze parameters so we don't backprop through them
for param in model.parameters():
    param.requires_grad = False
    
model.classifier = nn.Sequential(nn.Linear(1024, 256),
                                 nn.ReLU(),
                                 nn.Dropout(0.2),
                                 nn.Linear(256, 2),
                                 nn.LogSoftmax(dim=1))

criterion = nn.NLLLoss()

# Only train the classifier parameters, feature parameters are frozen
optimizer = optim.Adam(model.classifier.parameters(), lr=0.003)

model.to(device);
epochs = 1
steps = 0
running_loss = 0
print_every = 5
for epoch in range(epochs):
    for inputs, labels in trainloader:
        steps += 1
        # Move input and label tensors to the default device
        inputs, labels = inputs.to(device), labels.to(device)
        
        optimizer.zero_grad()
        
        logps = model.forward(inputs)
        loss = criterion(logps, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        
        if steps % print_every == 0:
            test_loss = 0
            accuracy = 0
            model.eval()
            with torch.no_grad():
                for inputs, labels in testloader:
                    inputs, labels = inputs.to(device), labels.to(device)
                    logps = model.forward(inputs)
                    batch_loss = criterion(logps, labels)
                    
                    test_loss += batch_loss.item()
                    
                    # Calculate accuracy
                    ps = torch.exp(logps)
                    top_p, top_class = ps.topk(1, dim=1)
                    equals = top_class == labels.view(*top_class.shape)
                    accuracy += torch.mean(equals.type(torch.FloatTensor)).item()
                    
            print(f"Epoch {epoch+1}/{epochs}.. "
                  f"Train loss: {running_loss/print_every:.3f}.. "
                  f"Test loss: {test_loss/len(testloader):.3f}.. "
                  f"Test accuracy: {accuracy/len(testloader):.3f}")
            running_loss = 0
            model.train()
Epoch 1/1.. Train loss: 0.660.. Test loss: 0.245.. Test accuracy: 0.951
Epoch 1/1.. Train loss: 0.313.. Test loss: 0.112.. Test accuracy: 0.970
Epoch 1/1.. Train loss: 0.258.. Test loss: 0.074.. Test accuracy: 0.974
Epoch 1/1.. Train loss: 0.297.. Test loss: 0.062.. Test accuracy: 0.979
Epoch 1/1.. Train loss: 0.306.. Test loss: 0.058.. Test accuracy: 0.980

Epoch 1/1.. Train loss: 0.153.. Test loss: 0.063.. Test accuracy: 0.976
Epoch 1/1.. Train loss: 0.169.. Test loss: 0.042.. Test accuracy: 0.984
Epoch 1/1.. Train loss: 0.246.. Test loss: 0.051.. Test accuracy: 0.978

你可能感兴趣的:(pytorch)