使用 PyTorch 进行图像分类
介绍
PyTorch 彻底改变了解决计算机视觉或 NLP 问题的方法。它是一个动态深度学习框架,易于学习和使用。
在本指南中,我们将从头到尾构建一个图像分类模型,从探索性数据分析 (EDA) 开始,这将帮助您了解图像的形状和类别的分布。您将学习准备数据以获得最佳建模结果,然后构建一个卷积神经网络 (CNN),根据图像是否包含仙人掌对图像进行分类。
点击此处下载正在进行的 Kaggle 竞赛中的空中仙人掌数据集。此数据集包含 RGB 图像通道,而不是 MNIST 黑白图像。因此,它非常适合初学者用来探索和使用 CNN。这也是对猫和狗以外的其他事物进行分类的机会。
导入库和数据
首先,使用numpy、pandas和sklearn导入torch和torchvision框架及其库。以下代码中使用的库和函数包括:
- 变换,用于基本图像变换
- torch.nn. functional,包含有用的激活函数
- Dataset和Dataloader,PyTorch 的数据加载实用程序
import pandas as pd
import matplotlib.pyplot as plt
import torch
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import Dataset, DataLoader
from sklearn.model_selection import train_test_split
%matplotlib inline
import os
os.getcwd()
# place the files in your IDE working dicrectory .
labels = pd.read_csv(r'/aerialcactus/train.csv')
submission = pd.read_csv(r'/aerialcactus/sample_submission.csv)
train_path = r'/aerialcactus/train/train/'
test_path = r'/aerialcactus/test/test/'
labels.head()
labels.tail()
labels['has_cactus'].value_counts()
label = 'Has Cactus', 'Hasn\'t Cactus'
plt.figure(figsize = (8,8))
plt.pie(labels.groupby('has_cactus').size(), labels = label, autopct='%1.1f%%', shadow=True, startangle=90)
plt.show()
根据饼图,数据偏向于一个类别。不平衡的数据会影响最终结果。我们已经有足够的数据让 CNN 产生结果,因此不需要任何数据采样或增强。
图像预处理
数据集中的图像通常不具有相同的像素强度和尺寸。在本节中,您将通过标准化像素值来预处理数据集。下一个必需的过程是将原始图像转换为张量,以便算法可以处理它们。
import matplotlib.image as img
fig,ax = plt.subplots(1,5,figsize = (15,3))
for i,idx in enumerate(labels[labels['has_cactus'] == 1]['id'][-5:]):
path = os.path.join(train_path,idx)
ax[i].imshow(img.imread(path))
fig,ax = plt.subplots(1,5,figsize = (15,3))
for i,idx in enumerate(labels[labels['has_cactus'] == 0]['id'][:5]):
path = os.path.join(train_path,idx)
ax[i].imshow(img.imread(path))
使用以下代码通过定义的平均值和标准差来标准化图像,因为使用原始图像数据不会产生所需的结果。
import numpy as np
import matplotlib.pyplot as plt
def imshow(image, ax=None, title=None, normalize=True):
if ax is None:
fig, ax = plt.subplots()
image = image.numpy().transpose((1, 2, 0))
if normalize:
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
ax.imshow(image)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.tick_params(axis='both', length=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
return ax
class CactiDataset(Dataset):
def __init__(self, data, path , transform = None):
super().__init__()
self.data = data.values
self.path = path
self.transform = transform
def __len__(self):
return len(self.data)
def __getitem__(self,index):
img_name,label = self.data[index]
img_path = os.path.join(self.path, img_name)
image = img.imread(img_path)
if self.transform is not None:
image = self.transform(image)
return image, label
正常化
train_transform = transforms.Compose([transforms.ToPILImage(),
transforms.ToTensor(),
transforms.Normalize(means,std)])
test_transform = transforms.Compose([transforms.ToPILImage(),
transforms.ToTensor(),
transforms.Normalize(means,std)])
valid_transform = transforms.Compose([transforms.ToPILImage(),
transforms.ToTensor(),
transforms.Normalize(means,std)])
分割数据集
模型的学习效果取决于数据的种类和数量。我们需要使用train_test_split将数据分为训练集和验证集。
训练数据集:模型从该数据集的示例中进行学习。它将参数拟合到分类器中。
验证数据集:验证数据集中的示例用于调整超参数,例如学习率和时期数。创建验证集的目的是避免模型过度拟合。它是一个检查点,用于了解模型是否与训练数据集很好地契合。
测试数据集:此数据集测试模型的最终演变,衡量模型的学习效果和对所需输出的预测。它包含未见过的真实数据。
train, valid_data = train_test_split(labels, stratify=labels.has_cactus, test_size=0.2)
train_data = CactiDataset(train, train_path, train_transform )
valid_data = CactiDataset(valid_data, train_path, valid_transform )
test_data = CactiDataset(submission, test_path, test_transform )
定义超参数的值。
# Hyper parameters
num_epochs = 35
num_classes = 2
batch_size = 25
learning_rate = 0.001
每当您初始化一批图像时,默认情况下它都会在 CPU 上进行计算。函数torch.cuda.is_available()将检查是否存在 GPU。如果存在 CUDA,.device("cuda")会将张量路由到 GPU 进行计算。
# CPU or GPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
device
train_loader = DataLoader(dataset = train_data, batch_size = batch_size, shuffle=True, num_workers=0)
valid_loader = DataLoader(dataset = valid_data, batch_size = batch_size, shuffle=False, num_workers=0)
test_loader = DataLoader(dataset = test_data, batch_size = batch_size, shuffle=False, num_workers=0)
import numpy as np
import matplotlib.pyplot as plt
def imshow(image, ax=None, title=None, normalize=True):
if ax is None:
fig, ax = plt.subplots()
image = image.numpy().transpose((1, 2, 0))
if normalize:
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
ax.imshow(image)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.tick_params(axis='both', length=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
return ax
trainimages, trainlabels = next(iter(train_loader))
fig, axes = plt.subplots(figsize=(12, 12), ncols=5)
print('training images')
for i in range(5):
axe1 = axes[i]
imshow(trainimages[i], ax=axe1, normalize=False)
print(trainimages[0].size())
下一步是制作一个从操纵的训练数据集中学习的 CNN 模型。
设计卷积神经网络 (CNN)
如果您尝试识别给定图像中的物体,您会注意到颜色、形状和大小等特征,这些特征可帮助您识别图像中的物体。CNN 使用相同的技术。CNN 中的两个主要层是卷积层和池化层,模型在其中记录图像中的特征,以及全连接 (FC) 层,进行分类。
图片来源:https://commons.wikimedia.org/wiki/File:Typical_cnn.png
卷积层
从数学上讲,卷积是对两个函数执行的操作,以产生第三个函数。卷积在语音处理(1 维)、图像处理(2 维)和视频处理(3 维)中运行。卷积层在图像上形成一个厚过滤器。
卷积层的输出形状受内核大小、输入维度、填充和步幅(窗口移动的像素数)的选择的影响。
在这个模型中,使用了 3x3 大小的内核。它将有 27 个权重和 1 个偏差。
这就是CNN背后发生的事情。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~