在当今数字化的世界中,数据以各种形式大量存在,其中图像数据的增长尤为显著,这主要归功于社交媒体网站和应用。深度学习是专门处理图像数据的一个领域。在这篇文章中,将使用PyTorchAPI构建一个图像分类器。
图像分类器的应用无处不在,例如当打开Google Photos时,会发现一个名为“Things”的集合,其中包含“Sky”、“Hiking”、“Temples”、“Cars”等类别。Google的算法已经将照片分类到这些类别中。另一个主要应用领域是医疗保健。训练有素的模型可以将X射线/扫描分类为疾病阳性/阴性。
将从二分类开始,即将图像分类为两个类别,更像是YES/NO分类。之后,可以修改它并用于多分类。
数据是什么?有许多数据集如MNIST、CIFAR10可以进行分类。在这篇文章中,选择了一个Kaggle数据集:Hot Dog – Not a hotdog。可以在这里找到链接:https://www.kaggle.com/dansbecker/hot-dog-not-hot-dog。它基本上包含要么是热狗要么是非热狗的图像。
可以像这样从两个类别中可视化一些样本:
from PIL import Image
Image.open("../input/seefood/train/hot_dog/1053879.jpg")
Image.open("../input/seefood/train/not_hot_dog/102037.jpg")
它有两个目录:train和test。目标是构建一个模型,用训练数据训练它,并检查其在测试数据集上的准确性。将使用Pytorch框架。由于其构建和训练模型的简单API,它非常受欢迎。作为第一步,让导入所需的主要库和模块。
import pandas as pd
import matplotlib.pyplot as plt
import torch
import torchvision
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision import transforms, utils, datasets
from torch.utils.data import Dataset, DataLoader
from torchvision import datasets
处理数据集。可能经常需要在将图像数据传递给模型之前进行处理。例如,如果所有图像的大小都不同(这通常是大型数据集的情况),那么模型将抛出错误。因此,需要调整它们的大小,并且可以考虑重新缩放像素值。除此之外,可以执行多种转换以进行数据增强。
使用transform.compose()应用多个转换的优雅方式如下所示。
train_transform = transforms.Compose([
transforms.Resize(255),
transforms.RandomResizedCrop(224),
transforms.CenterCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ColorJitter(),
transforms.ToTensor()
])
test_transform = transforms.Compose([
transforms.Resize(255),
transforms.CenterCrop(224),
transforms.ToTensor()
])
Pytorch提供了内置的Dataset和DataLoader模块,将在这里使用它们。Dataset存储样本及其对应的标签。而DataLoader则围绕Dataset包装了一个可迭代对象,以便于访问样本。
train_data = datasets.ImageFolder("train_data_directory", transform=train_transform)
test_data = datasets.ImageFolder("test_data_directory", transform=test_transform)
可以使用ImageFolder()函数传递包含样本的根目录和需要执行的转换。
train_loader = torch.utils.data.DataLoader(train_data, batch_size=16, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=16)
DataLoader()输入Dataset以及批量大小。在上面的代码中,要求了16个样本的批量。可以使用shuffle参数以确保数据的顺序不影响结果。可以检查数据加载器的输入形状:(批量大小 X 通道数 X 高度 X 宽度)
构建模型:解密层。在这里,将编写即将使用的模型的架构。将定义一个从PyTorchnn.Module派生的类。在类内部,将定义想要的层。
class Binary_Classifier(nn.Module):
def __init__(self):
super(Binary_Classifier, self).__init__()
self.conv1 = nn.Conv2d(in_channels=3, out_channels=10, kernel_size=3)
self.conv2 = nn.Conv2d(10, 20, kernel_size=3)
self.conv2_drop = nn.Dropout2d()
self.fc1 = nn.Linear(720, 1024)
self.fc2 = nn.Linear(1024, 2)
def forward(self, x):
x = F.relu(F.max_pool2d(self.conv1(x), 2))
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
x = x.view(x.shape[0], -1)
x = F.relu(self.fc1(x))
x = F.dropout(x, training=self.training)
x = self.fc2(x)
return x
模型类定义应该始终有__init__()方法。在这里,将初始化块/层和其他参数。
谈到神经网络层,图像分类中有三种主要类型:卷积层、最大池化层和丢弃层。
卷积层。卷积层将从输入图像中提取特征并生成特征图/激活。可以使用filters参数决定想要多少激活。基本上,当对图像应用卷积时,核将覆盖整个图像的小部分,并给出一个激活。
池化层。当使用conv2d层时,会得到很多特征图,它们占用了很高的计算空间。为了减少所需的计算时间和空间,可以使用最大池化或平均池化。对于每个补丁/组的地图,只选择最大值以形成输出。下面的图像清楚地展示了工作。
丢弃层。可以从名字中猜出它的功能!它会丢弃大约10-20%的数据。
为什么要这样做?过拟合是在多次迭代/周期对同一数据进行训练时的常见问题。通过丢弃随机选择的10%的数据,模型将能够更好地泛化到新数据。
这总结了在代码中使用的层的简要描述。请注意,最后一层的输出为2,因为它是二分类。
因此,模型已经准备好了!
训练模型。最后是训练部分。在这里需要决定两个关键事项:损失函数和优化器。对于优化器,有多种选择,如SGD、Adam等。使用了交叉熵损失,这是分类问题中的流行选择。还需要设置一个学习率,它决定了模型的学习速度。
model = Binary_Classifier()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
train_losses = []
for epoch in range(1, num_epochs=15):
train_loss = 0.0
model.train()
for data, target in train_loader:
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
train_loss += loss.item() * data.size(0)