一、前言
1、CS231n是啥?
- CS231n全称是: Convolutional Neural Networks for Visual Recognition,即面向视觉识别的卷积神经网络。
2、本篇博客任务
- 在 Google Colab 上使用 KNN 和 SVM 进行图像分类,具体细节可以查看官方要求。
- 只完成 Q1: k-Nearest Neighbor classifier 和 Q2: Training a Support Vector Machine 即可。
3、使用的数据集
- CIFAR-10是一个非常流行的图像分类数据集,包含了60000张32X32的小图像。
- 每张图像都有10种分类标签中的一种。
- 这60000张图像被分为包含50000张图像的训练集和包含10000张图像的测试集。
二、知识准备
1、KNN是什么?
KNN全称——k-Nearest Neighbor分类器,它是在Nearest Neighbor的基础上改进而来:
- Nearest Neighbor是最简单的图片分类器,它不是个神经网络,其核心思想就是计算输入图片和数据库中每一张图片的L1举例,距离近就是相似,之后它最像的那张图片的标签是什么,我们就认为这张输入图像的标签就是什么。
- 再说k-Nearest Neighbor分类器,它找的是最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。
- 所以当k=1的时候,k-Nearest Neighbor分类器就是Nearest Neighbor分类器。
K-Nearest Neighbor分类器的优缺点及应用场景:
- 易于理解,实现简单。
- 算法的训练不需要花时间,因为其训练过程只是将训练集数据存储起来。然而测试要花费大量时间计算,因为每个测试图像需要和所有存储的训练图像进行比较,这显然是一个缺点。
- 分类器必须记住所有训练数据并将其存储起来,以便于未来测试数据用于比较。这在存储空间上是低效的,数据集的大小很容易就以GB计。
- 在数据维度较低时,可能是不错的选择。但是在实际的图像分类工作中,很少使用。因为图像都是高维度数据(他们通常包含很多像素),而高维度向量之间的距离通常是反直觉的。
2、SVM是什么?
SVM全称——支持向量机 Support Vector Machine ,是一种二分类模型,也就是线性模型分类器。
要讲SVM,先从最简单的函数开始——一个线性映射:
- 这个公式就是平时最常见到的线性函数,常为一维线性函数(即 W 为一维的)。
- 当这种函数扩展到多维度的情况下时就是我们SVM要面临的情况。
- 首先我们要做的处理是将每个图像数据都拉长为一个长度为D的列向量,大小为 [D * 1] 。其中大小为 [K * D] 的矩阵W和大小为 [K 1] 列向量 b 为该函数的参数。
- 以CIFAR-10为例,CIFAR-10中一个图像的大小等于 [32323] ,含了该图像的所有像素信息,这些信息被拉成为一个 [3072 * 1] 的列向量, W 大小为 [103072] , b 的大小为 [10*1] 。
- 因此,3072个数字(素数值)输入函数,函数输出10个数字(不同分类得到的评分)。参数 W 被称为权重(weights)。 b 被称为偏差向量(bias vector)。
举个例子,在高维度情况下,以CIFAR-10为例:
- CIFAR-10中的图片转化成一个向量(3072维)后,就是一个高维度问题,而一个向量(3色通道转化而来)可以看作是3072维空间中的一个点,而线性分类器就是在高维度空间中的一个超平面,将各个空间点分开。如图所示:
- 图像空间的示意图。其中每个图像是一个点,有3个分类器。以红色的汽车分类器为例,红线表示空间中汽车分类分数为0的点的集合,红色的箭头表示分值上升的方向。所有红线右边的点的分数值均为正,且线性升高。红线左边的点分值为负,且线性降低。
- 目标:而我们要做的就是寻找一个W和一个b,使得这个超平面能很好的区分各个类。寻找方法就是不停的改变w和b的值,即不停的旋转平移,直到它使分类的偏差较小。
SVM的组成:
-
图像数据预处理:
在上面的例子中,所有图像都是使用的原始像素值(从0到255)。在机器学习中,对于输入的特征做归一化(normalization)是必然的。在图像处理中,每个像素点可以看作是一个简单的特征,在一般使用过程中,我们都先将特征“集中”,即训练集中所有的图像计算出一个平均图像值,然后每个图像都减去这个平均值,这样图像的像素值就大约分布在[-127, 127]之间了,下一个常见步骤是,让所有数值分布的区间变为[-1, 1]。 -
损失函数(loss function):
如何评判分类器的偏差就是当前的问题,解决这问题的方法就是损失函数:
这个函数得到的就是当前分类的偏差值。 -
正则化(Regularization):
上面损失函数有一个问题。假设有一个数据集和一个权重集W能够正确地分类每个数据(即所有的边界都满足,对于所有的i都有)。
三、实验——KNN和SVM分类
本次实验的环境依然是Google Colab,我们需要把作业包导入云端环境:
- 云端环境和本机文件目录有所区别。所以如何在代码中读Colab的文件(图片)也成为了一个问题。
- 需要输入以下指令获取Colab的Drive网盘权限(我姑且先这么翻译)。
- 之后会提示让你输入一个权限码:
并将文件存放至云盘:
1、KNN图片分类(重要步骤将在目录上体现)
接下来的操作代码都在CoLab上运行:
(1)在colab上切换目录,加载dataset
from google.colab import drive
drive.mount('/content/drive', force_remount=True)
#这一步就是切换到作业目录,没啥好说的
# enter the foldername in your Drive where you have saved the unzipped
# 'cs231n' folder containing the '.py', 'classifiers' and 'datasets' folders.
# e.g. 'cs231n/assignments/assignment1/cs231n/'
FOLDERNAME = 'assignment1/cs231n'#这里是我自己的云盘目录
assert FOLDERNAME is not None, "[!] Enter the foldername."
%cd drive/My\ Drive
%cp -r $FOLDERNAME ../../
%cd ../../
%cd cs231n/datasets/
!bash get_datasets.sh
%cd ../../
运行成功后如下图:
(2)加载包、设置和外部模块
#倒入一些包和设置
# Run some setup code for this notebook.
import random
import numpy as np
from cs231n.data_utils import load_CIFAR10
import matplotlib.pyplot as plt
# This is a bit of magic to make matplotlib figures appear inline in the notebook rather than in a new window.
%matplotlib inline
plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
# Some more magic so that the notebook will reload external python modules;
#加载外部模块
# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython
%load_ext autoreload
%autoreload 2
(3)加载、初步处理数据
# Load the raw CIFAR-10 data.
#加载原始数据
cifar10_dir = 'cs231n/datasets/cifar-10-batches-py'
# Cleaning up variables to prevent loading data multiple times (which may cause memory issue)
#清理变量以防止多次加载数据
try:
del X_train, y_train
del X_test, y_test
print('Clear previously loaded data.')
except:
pass
X_train, y_train, X_test, y_test = load_CIFAR10(cifar10_dir)
# As a sanity check, we print out the size of the training and test data.
#作为完备性检查,我们打印出训练和测试数据的大小
print('Training data shape: ', X_train.shape)
print('Training labels shape: ', y_train.shape)
print('Test data shape: ', X_test.shape)
print('Test labels shape: ', y_test.shape)
运行成功后:
(4)可视化打印一些图片看看我们的数据集长什么样
# Visualize some examples from the dataset.
#可视化数据集中的一些示例
# We show a few examples of training images from each class.
#展示每个类的一些训练图像的例子
classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
num_classes = len(classes)
samples_per_class = 7
for y, cls in enumerate(classes):
idxs = np.flatnonzero(y_train == y)
idxs = np.random.choice(idxs, samples_per_class, replace=False)
for i, idx in enumerate(idxs):
plt_idx = i * num_classes + y + 1
plt.subplot(samples_per_class, num_classes, plt_idx)
plt.imshow(X_train[idx].astype('uint8'))
plt.axis('off')
if i == 0:
plt.title(cls)
plt.show()
(5)对测试、训练数据进行分组
# Subsample the data for more efficient code execution in this exercise
#对数据进行分组
num_training = 5000
mask = list(range(num_training))
X_train = X_train[mask]
y_train = y_train[mask]
num_test = 500
mask = list(range(num_test))
X_test = X_test[mask]
y_test = y_test[mask]
# Reshape the image data into rows
X_train = np.reshape(X_train, (X_train.shape[0], -1))
X_test = np.reshape(X_test, (X_test.shape[0], -1))
#打印训练集、测试集的规模
print(X_train