第四节:图像分类任务
1.分类
1>分类任务与回归任务的区别
现实中很多任务不是预测问题,不能如之前的回归任务,输入一组向量得到一个预测值输出。比如围棋落子、分辨猫狗、判断一封邮件是否是垃圾邮件等问题,都需要分类思想。回归(图左)是预测一个函数,分类(图右)则是分辨数据。
2>如何进行图片分类
一般说来,要求预测判断结果的时候通常输入为一张图片。那么如何把图片输入,并处理成一组预测值是一个关键问题。一个分类过程大致如下图所示:

a.图像处理
图像应该是一个三维矩阵张量,分别由长度宽度和深度,其中深度代表色彩通道,比如黑白图片的深度为1,而在RGB色彩模式下,图像的深度为3。在对图像内容进行处理时,必须要保证图像的三维一致。图像经过卷积神经网络加工,用卷积核进行处理图像,得到一张张有意义的特征图。卷积神经网络具体见下文。图像经过卷积神经网络若干操作后将它拉直成一个向量,再经由若干个全连接层将其加工,致力于求出一个维度为类别个数的向量。以上属于前向过程。
b.分类输出
此时得到的向量,仍然只是不规则的数字,而我们的目标是将这些向量转化为答案可能的概率,因此涉及到了Softmax函数。Softmax函数大致是清晰的求出每个索引的概率。如下图,当数据为11.7, 23, 20时相差不大,很难得到对应的结果;而经过Softmax后,0.953远大于另外二者,我们便得到了想要的概率分布。把这个概率分布和标签做交叉熵损失,再进行反向传播。


交叉熵损失:

根据以上公式,求出每一批的损失值,再求和找最小值。交叉熵越小,越接近真实分布;反之交叉熵越大越偏离。
2.神经卷积网络
卷积神经网络(CNN),是一种专门用来处理具有类似网格结构的数据的神经网络。卷积网络是指那些至少在网络的一层中使用卷积运算来替代一般的矩阵乘法运算的神经网络。
卷积神经网络的基本结构由以下几个部分组成:输入层,卷积层,池化层,激活函数层和全连接层。下面以图像分类任务简单介绍一下卷积神经网络结构,具体结构如下图所示。

1>卷积核与特征图
对于一张图像,我们不需要看整张图,只需要关注一小部分特征即特征图,便可做出判断。如下图所示,观其嘴而识鸟。而这个九宫格大小的3*3的矩阵,便是卷积核。
对于一个特征图,我们将其与卷积核求内积,即可得到一个新的特征图。


卷积核包含了核大小,填充步数padding值以及步长stride。除了手动计算卷积尺寸,还可以借助下述公式:

下面便举几个简单的例子来熟悉运算卷积核的参数量和特征图的过程。
1.特征图224*224. 卷积核大小为5, padding=2, 卷出来的特征图多大。
padding=2则特征图应该扩展为228*228,228*228的特征图可以容纳5*5的卷积核一共224个,所以特征图为224*224
2.特征图3*4*4. padding1, 卷积核数量1,卷出来的特征图为1*4*4。这套卷积核多大, 卷积核的参数量多少?
padding=1表示将特征图扩展为3*6*6,卷积核的深度必须和特征图一致都为3。对于6*6->4*4的图,这套卷积核大小为3*3*3.又因为最终得到的特征图为1*4*4卷积核只有一个,所以参数量为1*3*3*3=27
2>池化
当一个模型过大时,会产生不少数据需要我们运算,大量的数据运算容易导致过拟合,同时还可能存在不少数据冗余。为了防止这样的情况发生,可以选择池化(Pooling)。
如下图,对于四个数据,我们只选择其中一个最大值,2*4*4的特征图大小变为了2*2*2。池化有最大池化和平均池化,通常我们选用最大池化,即取最大值。

3.AlexNet示例
下面是AlexNet模型的相关代码
class MyAlexNet(nn.Module):
def __init__(self):
super(MyAlexNet, self).__init__()
#激活函数
self.relu = nn.ReLU()
#随机将部分神经元的输出置为0来减少过拟合
self.drop = nn.Dropout(0.5)
#Conv2d表示二维卷积,其主要参数如下:(输入特征图数,输出特征图数个数,卷积核尺寸,步长,padding)
self.conv1 = nn.Conv2d(3, 64, 11, 4, 2)
self.pool1 = nn.MaxPool2d(3, 2)
self.conv2 = nn.Conv2d(64, 192, 5, 1, 2)
self.pool2 = nn.MaxPool2d(3, 2)
self.conv3 = nn.Conv2d(192, 384, 3, 1, 1)
self.conv4 = nn.Conv2d(384, 256, 3, 1, 1)
self.conv5 = nn.Conv2d(256, 256, 3, 1, 1)
self.pool3 = nn.MaxPool2d(3, 2)
self.adapool = nn.AdaptiveAvgPool2d(6)
self.fc1 = nn.Linear(9216, 4096)
self.fc2 = nn.Linear(4096, 4096)
self.fc3 = nn.Linear(4096, 1000)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.relu(x)
x = self.pool2(x)
x = self.conv3(x)
x = self.relu(x)
x = self.conv4(x)
x = self.relu(x)
x = self.conv5(x)
x = self.relu(x)
x = self.pool3(x)
x = self.adapool(x)
"""
view用于对tensor进行reshape
-1表示一个不确定的数,当不确定要形成几列,但肯定我们要x.size()[0]行时,便如下表示
通过上述方法将x拉直,进入全连接网络运算
"""
x = x.view(x.size()[0], -1)
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
x = self.relu(x)
x = self.fc3(x)
x = self.relu(x)
return x
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)