3.2 图像分类识别预备知识
3.2.1 图像分类 首先,我们来看一下什么是图像分类问题。
所谓的图像分类问题就是将已有的固定的分类标签集合中最合适的标签分配给输入的图像。
下面通过一个简单的小例子来解释下什么是图像分类模型,以猫的图片为例,图像分类模型读取该图片,并生成该图片属于集合{cat,dog,hat,mug}中各个标签的概率。需要注意的是,对于计算机来说,图像是一个由数字组成的巨大的三维数组。
在这个猫的例子中,图像的大小是宽248像素,高400像素,有3个颜色通道,分别是红、绿和蓝(简称RGB)。
如此,该图像就包含了248×400×3=297600个数字,每个数字都是处于范围0~255之间的整型,其中0表示黑,255表示白。我们的任务就是将上百万的数字解析成人类可以理解的标签,比如“猫”。
电脑看到猫的图片均为0~255的数字。
图像分类的任务就是预测一个给定的图像包含了哪个分类标签(或者给出属于一系列不同标签的可能性)。
图像是三维数组,数组元素是取值范围从0~255的整数。数组的尺寸是宽度×高度×3,其中3代表的是红、绿、蓝3个颜色通道。
3.2.2 图像预处理
在开始使用算法进行图像识别之前,良好的数据预处理能够很快达到事半功倍的效果。
图像预处理不仅可以使得原始图像符合某种既定规则以便于进行后续的处理,而且可以帮助去除图像中的噪声。
在后续讲解神经网络的时候我们还会了解到,数据预处理还可以帮助减少后续的运算量以及加速收敛。
常用的图像预处理操作包括归一化、灰度变换、滤波变换以及各种形态学变换等,随着深度学习技术的发展,一些预处理方式已经融合到深度学习模型中,这里只重点讲一下归一化。
归一化可用于保证所有维度上的数据都在一个变化幅度上。
比如,在预测房价的例子中,假设房价由面积s和卧室数b决定,面积s在0~200之间,卧室数b在0~5之间,进行归一化的一个实例就是s=s/200,b=b/5。
通常我们可以使用两种方法来实现归一化:一种是最值归一化,比如将最大值归一化成1,最小值归一化成-1;或者将最大值归一化成1,最小值归一化成0。
另一种是均值方差归一化,一般是将均值归一化成0,方差归一化成1。
3.3 KNN实战 3.3.1
KNN实现MNIST数据分类 我们前面使用了两节的内容来讲述KNN算法的计算逻辑以及它的Python实现思路,本节将提供两个实战案例,带领大家逐步走进图像识别。
1.MNIST数据集 为了方便大家理解,本节选择的数据集是一个比较经典的数据集——MNIST。
MNIST数据集来自美国国家标准与技术研究所(National Institute of Standards and Technolo,NIST)。
训练集由250个人手写的数字构成,其中50%是高中学生,50%是人口普查的工作人员。
测试数据集也是同样比例的手写数字数据。MNIST数据集是一个很经典且很常用的数据集(类似于图像处理中的“Hello World!”)。
为了降低学习难度,我们先从这个最简单的图像数据集开始。 我们先来看一下如何读取MNIST数据集。
由于MNIST 是一个基本的数据集,因此我们可以直接使用PyTorch框架进行数据的下载与读取,示例代码如下:
import torch
from torch.utils.data import DataLoader
import torchvision.datasets as dsets
import torchvision.transforms as transforms
batch_size = 100
# MNIST dataset
train_dataset = dsets.MNIST(root = '/ml/pymnist', #选择数据的根目录
train = True, #选择训练集
transform = None, #不考虑使用任何数据预处理
download = True) #从网络上下载图片
test_dataset = dsets.MNIST(root = '/ml/pymnist', #选择数据的根目录
train = False, #选择测试集
transform = None, #不考虑使用任何数据预处理
download = True) #从网络上下载图片
#加载数据
train_loader = torch.utils.data.DataLoader(dataset = train_dataset,
batch_size = batch_size,
shuffle = True) #将数据打乱
test_loader = torch.utils.data.DataLoader(dataset = test_dataset, batch_size = batch_size,
shuffle = True)
train_dataset与test_dataset可以返回训练集数据、训练集标签、测试集数据以及测试集标签,训练集数据以及测试集数据都是n×m维的矩阵,这里的n是样本数(行数),m是特征数(列数)。
训练数据集包含60000个样本,测试数据集包含10000个样本。在MNIST数据集中,每张图片均由28×28个像素点构成,每个像素点使用一个灰度值表示。
在这里,我们将28×28的像素展开为一个一维的行向量,这些行向量就是图片数组里的行(每行784个值,或者说每行就代表了一张图片)。训练集标签以及测试标签包含了相应的目标变量,也就是手写数字的类标签(整数0~9)。
print("train_data:", train_dataset.train_data.size())
print("train_labels:", train_dataset.train_labels.size())
print("test_data:", test_dataset.test_data.size())
print("test_labels:", test_dataset.test_labels.size())
得到的结果如下:
train_data: torch.Size([60000, 28, 28])
train_labels: torch.Size([60000]) #训练集标签的长度
test_data: torch.Size([10000, 28, 28])
test_labels: torch.Size([10000]) #测试集标签的长度 我们一般不会直接使用train_dataset与test_dataset,在训练一个算法的时候(比如,神经网络),最好是对一个batch的数据进行操作,同时还需要对数据进行shuffle和并行加速等。
对此,PyTorch提供了DataLoader以帮助我们实现这些功能。我们后面用到的数据都是基于DataLoader提供的。
首先,我们先来了解下MNIST中的图片看起来到底是什么,先对它们进行可视化处理。通过Matplotlib的imshow函数进行绘制,代码如下:
import matplotlib.pyplot as plt
digit = train_loader.dataset.train_data[0] #取第一个图片的数据
plt.imshow(digit,cmap=plt.cm.binary)
plt.show()
print(train_loader.dataset.train_labels[0]) #输出对应的标签,结果为5 标签的输出结果是5。
3.3.2.KNN实现MNIST数字分类
在真正使用Python实现KNN算法之前,我们先来剖析一下思想,这里我们以MNIST的60000张图片作为训练集,我们希望对测试数据集的10000张图片全部打上标签。