机器学习在图像分类中的应用与实践
1. 机器学习与图像分类概述
机器学习在多个领域取得了显著成功,图像分类是神经网络(NNs)应用最广泛且备受赞誉的领域之一。21世纪初,神经网络在图像分类竞赛中取得的惊人成就,极大地推动了其普及。此前,神经网络领域更多被视为一种新奇事物,而非主流工具。随着神经网络在图像分类中的表现越来越好,研究人员更多地将其作为工具,进一步改进其在成像方面的应用,形成了良性反馈,使其在竞赛中取得更多成功。
原则上,任何机器学习方法都可用于图像分类,图像的特征是像素强度,结果是图像的类别。以著名的MNIST数据为例,它包含70,000张手写数字图像,每张图像有28行28列像素,每个像素的强度值在0到255之间,因此有784个特征和10个类别。
在图像领域,神经网络的“秘诀”是卷积运算,由此产生了卷积神经网络(CNNs)。实际上,这些运算并非全新的,它们借鉴了经典的图像处理技术,且卷积运算并非神经网络所固有,也可与其他机器学习方法结合使用,例如一些研究人员已经开发了卷积支持向量机(SVMs),但目前图像领域的发展势头主要集中在CNN上。
2. 时尚MNIST数据示例
通常会使用MNIST数据作为入门示例,这里我们采用时尚MNIST数据。它与MNIST数据大小相同(28×28像素结构,10个类别,70,000张图像),但包含的是服装图片(10种类型)而非数字。该数据集可在https://github.com/zalandoresearch/fashion - mnist获取。
与MNIST数据基本可视为黑白图像不同,时尚MNIST数据有“灰度渐变”,图像模糊是由于其28×28的低分辨率。这使得该数据集更具挑战性,准确率通常比MNIST数据略低。
2.1 首次尝试:使用逻辑模型
数据集已预先划分为训练集和测试集(分别为60,000行和10,000行),为方便起见,我们仅使用训练集,命名为ftrn,包含列V1、V2、…、V785,最后一列是服装类型,值为0到9。
我们尝试对该数据使用逻辑模型:
> z <- qeLogit(ftrn,'V785')
> z$testAcc
[1] 0.205
> z$baseAcc
[1] 0.8998305
我们达到了约80%的准确率,基线准确率仅约10%,这是合理的,因为10种服装类型的数量大致相等,随机猜测的准确率约为10%。虽然80%的准确率不算差,但该数据集的世界纪录准确率在90%以上,我们希望能做得更好。
2.2 通过主成分分析(PCA)进行优化
我们推测特征数量p = 784过大,需要进行降维。一种可能的方法是使用PCA:
> z <- qePCA(ftrn,'V785','qeLogit',pcaProp = 0.8)
> z$testAcc
[1] 0.172
现在准确率提高到了约83%,且运行时间仅约1分钟。我们可以尝试不同数量的主成分,但更好的方法可能是利用我们对图像的了解,接下来我们将探讨卷积模型。
3. 卷积模型
虽然CNN的结构乍一看可能很复杂,但实际上它基于简单的思想。
3.1 局部性识别的必要性
时尚MNIST图像看起来模糊并非巧合,这些图像分辨率非常低(28×28像素),尽管图像很小,但却有784个特征。对于n = 70,000,经验法则表明最大特征数约为260,远低于784。虽然该法则较为保守,CNN即使在p远大于n的情况下也能表现良好,但显然将784个像素视为不相关的特征会阻碍我们对新案例的预测能力。
我们需要利用图像的局部性,图像像素往往与其相邻像素相关,这种关系的性质有助于我们对图像进行分类。卷积模型就是基于这一思想设计的,它由应用于图像中斑块(通常称为图块)的各种操作组成。
3.2 卷积方法概述
我们先看一段代码,并将其应用于时尚MNIST数据,然后解释代码中的操作。代码改编自RStudio的一个示例:
# 设置5个图像操作层
> conv1 <- list(type='conv2d',filters=32,kern=3)
> conv2 <- list(type='pool',kern=2)
> conv3 <- list(type='conv2d',filters=64,kern=3)
> conv4 <- list(type='pool',kern=2)
> conv5 <- list(type='drop',drop=0.5)
# 注意qeNeural()默认设置两个隐藏层,这些层将在卷积层之后
> z <- qeNeural(ftrn,'V785',
conv=list(conv1,conv2,conv3,conv4,conv5),xShape=c(28,28))
> z$testAcc
[1] 0.075
现在我们的正确分类率超过了92%,通过调整超参数(包括更改图像操作层的数量和结构),我们很可能会做得更好。
这里我们使用
qeNeural()
的
conv
参数设置了五个图像操作层,这些图像操作层之后是“普通”层(此处未指定),
qeNeural()
默认设置两个各有100个神经元的层,这些“普通”层称为密集层或全连接层。
第一个图像操作层对输入图像执行卷积操作,包括提取图块并形成每个图块内图像强度的线性组合,这些线性组合成为该层的输出。在CNN中,线性组合中的系数称为权重。
conv2d
参数
filters
指定了一层所需的权重集数量,类似于密集层中的神经元数量;
kern
值指定图块大小,如第一层中的值3表示3×3图块;另一个
conv2d
参数
stride
通过指定图块与其相邻图块的重叠量来控制图像中图块的数量。
xShape
参数指定图像的大小,如当前示例中的28×28。对于相同大小的彩色数据,我们将其表示为28×28×3,其中3表示三种原色(红、黄、蓝),这里的第三个坐标3称为通道。一层的输出作为下一层的输入,其维度可能是13×13×64,可将其视为具有64个“原色”的13×13“图像”,从数学角度看,任何三维数组都可以这样处理,这使代码更简单。
3.3 图像分块
上述代码示例中的第一层和第三层执行卷积操作。为了解释卷积操作,我们先讨论将图像分割成图块。
考虑一个6×6灰度图像的简单示例,在R中,我们将其存储为6行6列的矩阵。我们可以将其分割成不重叠的3×3图块,也可以使用步长(stride)创建重叠图块。例如,步长为3时,右上图块的第一列在左上图像第一列右侧3列;步长为1时,第二个3×3图块在第一个图块右侧1列。在
conv2d
操作中,步长的默认值为1。
3.4 卷积操作
假设我们使用3×3图块,方便起见,我们将线性组合的系数表示为矩阵形式,即权重矩阵。对于给定的图块,图块中第1行第1列的元素将乘以
w11
,第1行第2列的元素将乘以
w12
,以此类推,将所有乘积相加得到一个单一数字。将同一组权重应用于每个图块,例如应用于左上、右上、左下和右下四个图块,得到四个数字,将其排列成2×2矩阵作为该层的输出。
如果有12个过滤器,意味着有12组不同的权重,将得到12个不同的2×2矩阵,该层的输出可描述为2×2×12。需要注意的是,这些权重不是我们自己选择的,而是由神经网络算法选择,算法会尝试许多不同的权重集组合,以找到使预测平方和最小的组合。
卷积操作本质上是对输入进行线性组合并传递到下一层,与之前的方法类似,但不同之处在于将数据结构化为图块,利用了局部性。权重的作用是确定各个像素的相对重要性,特别是它们如何协同工作。可以将其想象成一个有12层的“建筑”,每层有四个“房间”,排成两行两列。同时,与密集层一样,存在偏差 - 方差权衡:过滤器越多,减少偏差的机会越多,但权重的方差也越大。
3.5 池化操作
上述示例中的第二层是池化层:
conv2 <- list(type='pool',kern=2)
池化操作是用图块中的某个代表值(如均值、中位数或最大值)替换图块中的元素,在
regtools
和
qeML
包中,通常使用最大值。有人可能会认为池化是卷积操作的一种特殊情况,例如在2×2图块中取均值与所有权重都为0.25的卷积操作相同,但区别在于池化操作中的权重是固定的,不是由算法选择的。与
conv2d
操作默认步长为1不同,池化操作的默认步长是图块大小,此处为2。
3.6 各层形状演变
我们来分析一下第二层输出的结构。第一层的输入是28×28(或28×28×1),将其分割成3×3图块,步长为1,会得到26×26的图块数组。每个过滤器将输出26×26个数字,32个过滤器的第一层总输出为26×26×32,可想象成有32层,每层有26行26列的“房间”,每个“房间”存储一个数字。
第二层接收32个26×26的图块,使用2×2图块,步长为2,将每个26×26图块分割成13行13个2×2图块,提取每个2×2图块中的最大值。每层将产生13×13 = 169个数字,32层的总输出为13×13×32。在
regtools
和
qeML
包中,池化操作是在各层内部进行的,而不是跨层进行。
3.7 随机失活
与密集层一样,卷积层存在过拟合的风险,即每层神经元过多或卷积层过多。解决方法是随机失活,例如:
> conv5 <- list(type='drop',drop=0.5)
这指定随机删除该层中50%的节点。
3.8 形状演变总结
keras
包可以提供我们的CNN的总结信息:
> z$model
Model
Model: "sequential"
__
Layer (type) Output Shape Param #
===============================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
__
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
__
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
__
max_pooling2d_1 (MaxPooling2D) (None, 5, 5, 64) 0
__
dropout (Dropout) (None, 5, 5, 64) 0
__
flatten (Flatten) (None, 1600) 0
__
dense (Dense) (None, 100) 160100
__
dense_1 (Dense) (None, 10) 1010
===============================================================================
Total params: 179,926
Trainable params: 179,926
Non-trainable params: 0
最后一列显示了每层的权重数量。例如,320这个数字的来源是:每个过滤器(即每组
wij
数字)是一个3×3矩阵,包含9个数字,还有一个截距项
w0
,总共10个权重,32个过滤器则有320个权重。
flatten
层只是将数据从a×c形式转换为普通数据,第二个池化层的输出为5×5×64,即1600个数字,为了能被密集层使用,将其转换为长度为1600的单个向量。
总体而言,我们有p = 179926个参数,但只有n = 65000个样本,显然存在过拟合问题。然而,许多这样的模型在实际中表现良好,这在机器学习社区中是一个颇具争议的现象。
3.9 平移不变性
权重结构赋予了我们的分析平移不变性。例如,当我们使用3×3图块(9个像素)时,对于任何图块,图块左上角的像素具有相同的权重
w11
,无论该图块位于图像的顶部、底部还是其他位置。在面部识别中,这意味着在很大程度上我们不必担心面部在图像中的位置是靠近顶部、底部还是中间(但在图像边缘会出现问题,因此该属性只是近似成立),左右位置也是如此。
4. 实用技巧
4.1 模型构建
如何构建模型是一个关键问题,包括层数、层的类型和参数值的选择。我们可以根据数据集的性质(如图像各部分的大小、图像纹理等)进行一些初步猜测,但最终的答案往往是经过多年对各种架构(配置)的实验,发现某种架构适用于特定类型的图像。一些架构在广泛应用中取得了成功,获得了名称并成为标准,如AlexNet。
4.2 数据增强
处理较小图像集的一种方法是数据增强。其基本思想是从现有图像生成新图像,例如水平或垂直移动图像、缩小或放大图像、水平或垂直翻转图像等。这样做的动机是,后续可能需要对与训练集中图像非常相似但位置不同的新图像进行分类,我们希望算法能够识别新图像与训练集中图像的相似性。
对于医学组织图像(如活检图像),数据增强尤为重要,因为这些图像没有明确的方向(没有上下、左右、前后之分),这与MNIST数据不同,在MNIST中,‘6’和倒置的‘9’是不同的。
我们可以使用
OpenImageR
包的
Augmentation()
函数进行数据增强,例如进行垂直翻转操作:
> h18f <- Augmentation(matrix(h18,nrow=28),flip_mode='vertical')
> imageShow(matrix(h18f,nrow=28))
keras
包也提供数据增强服务,包括剪切(扭曲)操作。
以下是上述过程的一个简单mermaid流程图:
graph LR
A[数据获取(时尚MNIST)] --> B[首次尝试:逻辑模型]
B --> C{准确率是否满意}
C -- 否 --> D[PCA降维]
D --> E{准确率是否满意}
E -- 否 --> F[卷积模型构建]
F --> G[卷积操作]
G --> H[池化操作]
H --> I[随机失活]
I --> J[模型评估]
J --> K{准确率是否满意}
K -- 否 --> L[调整超参数]
L --> F
K -- 是 --> M[模型应用]
C -- 是 --> M
E -- 是 --> M
| 操作步骤 | 描述 |
|---|---|
| 数据获取 | 从指定链接获取时尚MNIST数据 |
| 首次尝试 | 使用逻辑模型进行初步分类 |
| PCA降维 | 若逻辑模型准确率不满意,进行PCA降维 |
| 卷积模型构建 | 设置卷积层、池化层和随机失活层 |
| 模型评估 | 评估卷积模型的准确率 |
| 调整超参数 | 若卷积模型准确率不满意,调整超参数 |
| 模型应用 | 使用满意的模型进行图像分类 |
5. 总结与展望
5.1 图像分类方法总结
在图像分类领域,我们探讨了多种方法,每种方法都有其特点和适用场景。下面通过表格对这些方法进行总结:
| 方法 | 优点 | 缺点 | 适用场景 |
| ---- | ---- | ---- | ---- |
| 逻辑模型 | 实现简单,运行时间相对较短,能快速得到初步结果 | 准确率相对较低,对于复杂图像分类效果不佳 | 数据特征简单、类别区分较明显的图像分类任务 |
| PCA降维 | 可减少特征数量,降低计算复杂度,一定程度上提高准确率 | 可能会丢失部分有用信息 | 特征数量过多,存在大量冗余信息的图像数据 |
| 卷积神经网络(CNN) | 能有效利用图像的局部性,通过卷积、池化等操作提取图像特征,准确率高 | 模型结构复杂,训练时间长,容易过拟合 | 各种类型的图像分类任务,尤其是复杂图像 |
5.2 未来发展趋势
随着技术的不断发展,图像分类领域也在不断演变。以下是一些可能的未来发展趋势:
-
更强大的模型架构
:继续探索和开发新的CNN架构,以提高模型的性能和效率。例如,一些研究正在尝试结合不同类型的神经网络层,创造出更具创新性的模型结构。
-
多模态融合
:将图像数据与其他模态的数据(如文本、音频)相结合,以获得更全面的信息,提高图像分类的准确性和应用范围。例如,在图像描述任务中,结合图像和文本信息可以生成更准确、详细的描述。
-
自动化模型设计
:利用自动化机器学习(AutoML)技术,自动搜索和优化模型架构、参数设置等,减少人工干预,提高模型开发的效率。
-
边缘计算
:将图像分类模型部署到边缘设备(如智能手机、摄像头)上,实现实时、高效的图像分类,减少数据传输延迟和对云端的依赖。
5.3 实践建议
对于想要在图像分类领域进行实践的读者,以下是一些建议:
-
数据准备
:确保数据的质量和多样性,进行必要的数据预处理(如归一化、裁剪、旋转等),并合理划分训练集、验证集和测试集。
-
模型选择
:根据数据的特点和任务的需求,选择合适的模型架构。对于初学者,可以从简单的模型开始,逐步深入了解和掌握更复杂的模型。
-
超参数调优
:通过实验和验证,选择合适的超参数(如学习率、批量大小、迭代次数等),以提高模型的性能。可以使用网格搜索、随机搜索等方法进行超参数调优。
-
防止过拟合
:采用正则化方法(如L1、L2正则化)、随机失活(Dropout)等技术,防止模型过拟合。同时,增加数据量也是防止过拟合的有效方法。
6. 案例分析
6.1 案例背景
为了更好地理解图像分类技术的实际应用,我们以一个实际的案例进行分析。假设我们要对不同类型的水果图像进行分类,数据集包含苹果、香蕉、橙子三种水果的图像。
6.2 数据准备
- 数据收集 :从互联网上收集苹果、香蕉、橙子的图像,确保每种水果的图像数量大致相等,且图像具有不同的角度、光照条件和背景。
- 数据预处理 :对收集到的图像进行裁剪、缩放,统一图像大小为28×28像素,将图像数据归一化到[0, 1]范围内。
- 数据划分 :将数据集按照80%、10%、10%的比例划分为训练集、验证集和测试集。
6.3 模型构建与训练
- 模型选择 :选择一个简单的CNN模型,包含两个卷积层、两个池化层和一个全连接层。
- 超参数设置 :学习率设置为0.001,批量大小设置为32,迭代次数设置为50。
- 模型训练 :使用训练集对模型进行训练,在训练过程中使用验证集进行验证,调整超参数以提高模型的性能。
以下是模型构建和训练的代码示例:
# 加载必要的库
library(regtools)
library(qeML)
# 数据加载和预处理(假设数据已经处理好并存储在ftrn中)
# 设置卷积层和池化层
conv1 <- list(type='conv2d',filters=32,kern=3)
conv2 <- list(type='pool',kern=2)
conv3 <- list(type='conv2d',filters=64,kern=3)
conv4 <- list(type='pool',kern=2)
conv5 <- list(type='drop',drop=0.5)
# 构建CNN模型
z <- qeNeural(ftrn,'V785',
conv=list(conv1,conv2,conv3,conv4,conv5),xShape=c(28,28))
# 训练模型
# 这里假设qeNeural函数内部包含训练过程
6.4 模型评估
使用测试集对训练好的模型进行评估,计算模型的准确率、召回率、F1值等指标。以下是评估代码示例:
# 评估模型
test_acc <- z$testAcc
print(paste("测试集准确率:", test_acc))
6.5 结果分析
根据评估结果,分析模型的性能。如果准确率较低,可以考虑调整模型结构、增加训练数据、调整超参数等方法来提高模型的性能。
以下是该案例的mermaid流程图:
graph LR
A[数据收集] --> B[数据预处理]
B --> C[数据划分]
C --> D[模型构建]
D --> E[超参数设置]
E --> F[模型训练]
F --> G[模型评估]
G --> H{准确率是否满意}
H -- 否 --> I[调整模型或参数]
I --> F
H -- 是 --> J[模型应用]
7. 常见问题解答
7.1 为什么CNN在图像分类中表现出色?
CNN能够有效利用图像的局部性,通过卷积操作提取图像的局部特征,减少了参数数量,降低了计算复杂度。同时,池化操作可以进一步减少特征数量,提高模型的鲁棒性。此外,CNN的权重共享机制使得模型能够学习到图像的平移不变性,对图像的位置变化具有较好的适应性。
7.2 如何解决CNN过拟合问题?
可以采用以下方法解决CNN过拟合问题:
-
增加训练数据
:通过数据增强等方法增加训练数据的多样性,使模型能够学习到更多的特征。
-
正则化
:使用L1、L2正则化方法,对模型的权重进行约束,防止模型过于复杂。
-
随机失活(Dropout)
:在训练过程中随机删除部分神经元,减少神经元之间的依赖关系,提高模型的泛化能力。
-
早停策略
:在训练过程中,当验证集的性能不再提高时,停止训练,避免模型过拟合。
7.3 如何选择合适的超参数?
选择合适的超参数需要进行实验和验证。可以采用以下方法:
-
网格搜索
:定义一组超参数的取值范围,对所有可能的组合进行尝试,选择性能最好的组合。
-
随机搜索
:在超参数的取值范围内随机选择组合进行尝试,通过多次实验找到较优的超参数组合。
-
贝叶斯优化
:利用贝叶斯方法对超参数进行优化,根据已有的实验结果预测下一组超参数的取值,提高搜索效率。
7.4 数据增强有哪些常用方法?
数据增强的常用方法包括:
-
平移
:将图像在水平或垂直方向上进行平移。
-
缩放
:对图像进行缩小或放大。
-
翻转
:水平或垂直翻转图像。
-
旋转
:将图像旋转一定的角度。
-
亮度和对比度调整
:调整图像的亮度和对比度。
通过以上内容,我们对图像分类技术进行了全面的介绍,包括方法原理、实践步骤、案例分析和常见问题解答。希望这些内容能够帮助读者更好地理解和应用图像分类技术。在实际应用中,读者可以根据具体的任务需求和数据特点,选择合适的方法和技术,不断探索和创新,提高图像分类的性能和效果。
超级会员免费看

被折叠的 条评论
为什么被折叠?



