pytorch迁移学习

迁移学习 在开始这部分内容之前,请回顾上一次的内容。
在这部分内容中,您将学习如何使用预训练的网络来解决计算机视觉中的难题。 具体来说,您将使用torchvision提供的ImageNet 训练的网络。
ImageNet是一个庞大的数据集,在1000个类别中有超过100万张带标签的图像。 它用于使用称为卷积层的体系结构训练深度神经网络。 在这里,我将不涉及卷积网络的详细信息,但是如果您想了解更多有关卷积网络的信息,请观看此 内容。
一旦训练完成,这些模型就可以像未经检测的图像特征检测器一样出色地工作。 对不在训练集中的图像使用预先训练的网络称为转移学习。 在这里,我们将使用转移学习来训练一个网络,该网络可以以近乎完美的准确性对猫和狗的照片进行分类。
借助torchvision.models,您可以下载这些经过预训练的网络,并在您的应用程序中使用它们。 现在,我们将在我们的导入中包含 models

%matplotlib inline %config InlineBackend.figure_format = 'retina'import matplotlib.pyplot as pltimport 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 = https://www.it610.com/article/datasets.ImageFolder(data_dir +'/train', transform=train_transforms) test_data = https://www.it610.com/article/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 = Falsefrom 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: breakprint(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%的精度。
【pytorch迁移学习】练习:训练预训练的模型对猫和狗的图像进行分类。 继续使用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 = Falsemodel.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.980Epoch 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

    推荐阅读