前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >keras实战项目——CIFAR-10 图像分类

keras实战项目——CIFAR-10 图像分类

作者头像
机器学习AI算法工程
发布2019-10-28 18:03:29
6800
发布2019-10-28 18:03:29
举报

我们可以简单的将深度神经网络的模块,分成以下的三个部分,即深度神经网络上游的基于生成器的 输入模块,深度神经网络本身,以及深度神经网络下游基于批量梯度下降算法的 凸优化模块:

  • 批量输入模块
  • 各种深度学习零件搭建的深度神经网络
  • 凸优化模块

其中,搭建深度神经网络的零件又可以分成以下类别:

  • 各种深度学习零件搭建的深度神经网络

需要强调一下,这些层与之前一样,都 同时包括了正向传播、反向传播两条通路。我们这里只介绍比较好理解的正向传播过程,基于其导数的反向过程同样也是存在的,其代码已经包括在 Tensorflow 的框架中对应的模块里,可以直接使用。

接下来的部分,我们将首先介绍这些深度神经网络的零件,然后再分别介绍上游的批量输入模块,以及下游的凸优化模块。

1. 深度神经网络的基本零件

1.1 常用层:

1.1.1. Dense

Dense 层,就是我们上一篇文章里提到的 Linear 层,即 y=wx+b ,计算乘法以及加法。

1.1.2. Activation

Activation 层在我们上一篇文章中,同样出现过,即 Tanh层以及Sigmoid层,他们都是 Activation 层的一种。当然 Activation 不止有这两种形式,比如有:

这其中 relu 层可能是深度学习时代最重要的一种激发函数,在2011年首次被提出。由公式可见,relu 相比早期的 tanhsigmoid函数, relu 有两个重要的特点,其一是在较小处都是0(sigmoid,relu)或者-5(tanh),但是较大值relu函数没有取值上限。其次是relu层在0除不可导,是一个非线性的函数:

即 y=x*(x>0)

对其求导,其结果是:

1.1.3. Dropout

Dropout 层,指的是在训练过程中,每次更新参数时将会随机断开一定百分比(rate)的输入神经元,这种方式可以用于防止过拟合。

1.1.4. Flatten

Flatten 层,指的是将高维的张量(Tensor, 如二维的矩阵、三维的3D矩阵等)变成一个一维张量(向量)。Flatten 层通常位于连接深度神经网络的 卷积层部分 以及 全连接层部分。

1.2 卷积层

提到卷积层,就必须讲一下卷积神经网络。我们在第一讲的最后部分提高深度学习模型预测的准确性部分,提了一句 “使用更复杂的深度学习网络,在图片中挖出数以百万计的特征”。这种“更复杂的神经网络”,指的就是卷积神经网络。卷积神经网络相比之前基于 Dense 层建立的神经网络,有所区别之处在于,卷积神经网络可以使用更少的参数,对局部特征有更好的理解。

1.2.1. Conv2D

我们这里以2D 的卷积神经网络为例,来逐一介绍卷积神经网络中的重要函数。比如我们使用一个形状如下的卷积核:

1

0

1

0

1

0

1

0

1

扫描这样一个二维矩阵,比如一张图片:

1

1

1

0

0

0

1

1

1

0

0

0

1

1

1

0

0

1

1

0

0

1

1

0

0

其过程与结果会是这样:

当然,这里很重要的一点,就是正如我们上一讲提到的, Linear 函数的 w, b两个参数都是变量,会在不断的训练中,不断学习更新。卷积神经网络中,卷积核其实也是一个变量。这里的

1

0

1

0

1

0

1

0

1

可能只是初始值,也可能是某一次迭代时选用的值。随着模型的不断训练,将会不断的更新成其他值,结果也将会是一个不规则的形状。清楚了其原理,卷积神经网络还需要再理解几个输入参数:

代码语言:javascript
复制
Conv2D(filters, kernel_size, strides=(1, 1), padding='valid', ...)

其中:

  • filters 指的是输出的卷积层的层数。如上面的动图,只输出了一个卷积层,filters = 1,而实际运用过程中,一次会输出很多卷积层。
  • kernel_size 指的是卷积层的大小,是一个 二维数组,分别代表卷积层有几行、几列。
  • strides 指的是卷积核在输入层扫描时,在 x,y 两个方向,每间隔多长扫执行一次扫描。
  • padding 这里指的是是否扫描边缘。如果是 valid,则仅仅扫描已知的矩阵,即忽略边缘。而如果是 same,则将根据情况在边缘补上0,并且扫描边缘,使得输出的大小等于 input_size / strides。
1.2.2. Cropping2D

这里 Cropping2D 就比较好理解了,就是特地选取输入图像的某一个固定的小部分。比如车载摄像头检测路面的马路线时,摄像头上半部分拍到的天空就可以被 Cropping2D函数直接切掉忽略不计。

1.2.3. ZeroPadding2D

1.2.1部分提到输入参数时,提到 padding参数如果是same,扫描图像边缘时会补上0,确保输出数量等于 input / strides。这里 ZeroPadding2D 的作用,就是在图像外层边缘补上几层0。如下图,就是对原本 32x32x3 的图片进行 ZeroPadding2D(padding=(2, 2)) 操作后的结果:

1.3. 池化层

1.3.1. MaxPooling2D

可能大家在上一部分会意识到一点,就是通过与一个相同的、大小为11x11的卷积核做卷积操作,每次移动步长为1,则相邻的结果会非常接近,正是由于结果接近,有很多信息是冗余的。

因此,MaxPooling 就是一种减少模型冗余程度的方法。以 2x 2 MaxPooling 为例。图中如果是一个 4x4 的输入矩阵,则这个 4x4 的矩阵,会被分割成由两行、两列组成的 2x2 子矩阵,然后每个 2x2 子矩阵取一个最大值作为代表,由此得到一个两行、两列的结果:

1.3.2. AveragePooling2D

AveragePoolingMaxPooling 类似,不同的是一个取最大值,一个是平均值。如果上图的 MaxPooling 换成 AveragePooling2D,结果会是:

3.25

5.25

2

2

1.4. 正则化层

除了之前提到的 Dropout 策略,以及用 GlobalAveragePooling取代全连接层的策略,还有一种方法可以降低网络的过拟合,就是正则化,这里着重介绍下 BatchNormalization

1.4.1. BatchNormalization

BatchNormalization 确实适合降低过拟合,但他提出的本意,是为了加速神经网络训练的收敛速度。比如我们进行最优值搜索时,我们不清楚最优值位于哪里,可能是上千、上万,也可能是个负数。这种不确定性,会造成搜索时间的浪费。

BatchNormalization就是一种将需要进行最优值搜索数据,转换成标准正态分布,这样optimizer就可以加速优化:

输入:一批input 数据: B

期望输出: β,γ

2. 深度神经网络的上下游结构

深度神经网络的参数大小动辄几十M、上百M,如何合理训练这些参数是个大问题。这就需要在这个网络的上下游,合理处理这个问题。

海量参数背后的意义是,深度神经网络可以获取海量的特征。第一讲中提到过,深度学习是脱胎于传统机器学习的,两者之间的区别,就是深度学习可以在图像处理中,自动进行特征工程,如我们第一讲所言:

想让计算机帮忙挖掘、标注这些更多的特征,这就离不开 更优化的模型 了。事实上,这几年深度学习领域的新进展,就是以这个想法为基础产生的。我们可以使用更复杂的深度学习网络,在图片中挖出数以百万计的特征。

这时候,问题也就来了。机器学习过程中,是需要一个输入文件的。这个输入文件的行、列,分别指代样本名称以及特征名称。如果是进行百万张图片的分类,每个图片都有数以百万计的特征,我们将拿到一个 百万样本 x 百万特征 的巨型矩阵。传统的机器学习方法拿到这个矩阵时,受限于计算机内存大小的限制,通常是无从下手的。也就是说,传统机器学习方法,除了在多数情况下不会自动产生这么多的特征以外,模型的训练也会是一个大问题。

深度学习算法为了实现对这一量级数据的计算,做了以下算法以及工程方面的创新:

  • 将全部所有数据按照样本拆分成若干批次,每个批次大小通常在十几个到100多个样本之间。(详见下文 输入模块)
  • 将产生的批次逐一参与训练,更新参数。(详见下文 凸优化模块)
  • 使用 GPU 等计算卡代替 CPU,加速并行计算速度。

这就有点《愚公移山》的意思了。我们可以把训练深度神经网络的训练任务,想象成是搬走一座大山。成语故事中,愚公的办法是既然没有办法直接把山搬走,那就子子孙孙,每人每天搬几筐土走,山就会越来越矮,总有一天可以搬完——这种任务分解方式就如同深度学习算法的分批训练方式。同时,随着科技进步,可能搬着搬着就用翻斗车甚至是高达来代替背筐,就相当于是用 GPU 等高并行计算卡代替了 CPU。

于是,我们这里将主要提到的上游输入模块,以及下游凸优化模块,实际上就是在说如何使用愚公移山的策略,用 少量多次 的方法,去“搬”深度神经网络背后大规模计算量这座大山。

2.2. 输入模块

这一部分实际是在说,当我们有成千上万的图片,存在硬盘中时,如何实现一个函数,每调用一次,就会读取指定张数的图片(以n=32为例),将其转化成矩阵,返回输出。

有 Python 基础的人可能意识到了,这里可能是使用了 Python 的 生成器 特性。其具体作用如廖雪峰博客所言:

创建一个包含100万个元素的 list,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 所以,如果 list 元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

其关键的写法,是把传统函数的 return 换成 yield

代码语言:javascript
复制
next(generator)

即可一次返回 32 张图像以及对应的标注信息。

当然,keras 同样提供了这一模块,ImageDataGenerator,并且还是加强版,可以对图片进行 增强处理(data argument)(如旋转、反转、白化、截取等)。图片的增强处理在样本数量不多时增加样本量——因为如果图中是一只猫,旋转、反转、颜色调整之后,这张图片可能会不太相同,但它仍然是一只猫。

代码语言:javascript
复制
datagen = ImageDataGenerator(
featurewise_center=False,
samplewise_center=False,
featurewise_std_normalization=False,
samplewise_std_normalization=False,
zca_whitening=False,
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=True,
vertical_flip=False)

# compute quantities required for featurewise normalization
datagen.fit(X_train)

2.3 凸优化模块

这一部分谈的是,如何使用基于批量梯度下降算法的凸优化模块,优化模型参数。

前面提到,深度学习的“梯度下降”计算,可以理解成搬走一座大山,而“批量梯度下降”,则是一群人拿着土筐,一点一点把山上的土给搬下山。那么这一点具体应该如何实现呢?其实在第二讲,我们就实现了一个随机批量梯度下降(Stochastic gradient descent, SGD),这里再回顾一下:

当然,SGD 其实并不是一个很好的方法,有很多改进版本,可以用下面这张gif图概况:

Keras 里,可以直接使用 SGD, Adagrad, Adadelta, RMSProp 以及 Adam 等模块。其实在优化过程中,直接使用 Adam 默认参数,基本就可以得到最优的结果:

代码语言:javascript
复制
from keras.optimizers import Adam
adam = Adam()model.compile(loss='categorical_crossentropy',
optimizer=adam,
metrics=['accuracy'])

3. 实战项目——CIFAR-10 图像分类

最后我们用一个keras 中的示例,

本文源码地址:

关注微信公众号datayx 然后回复“图像分类”即可获取。

首先做一些前期准备:

核心部分,用各种零件搭建深度神经网络:

代码语言:javascript
复制
datagen = ImageDataGenerator(
featurewise_center=False,
samplewise_center=False,
featurewise_std_normalization=False,
samplewise_std_normalization=False,
zca_whitening=False,
rotation_range=0,
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=True,
vertical_flip=False)datagen.fit(X_train)

核心部分,用各种零件搭建深度神经网络:

下游部分,使用凸优化模块:

代码语言:javascript
复制
adam = Adam(lr=0.0001)model.compile(loss='categorical_crossentropy',

optimizer=adam,
metrics=['accuracy'])

最后,开始训练模型,并且评估模型准确性:

以上代码本人使用 Pascal TitanX 执行,50个 epoch 中,每个 epoch 用时 12s 左右,总计用时在十五分钟以内,约25 epoch 后,验证集的准确率数会逐步收敛在0.8左右。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-07-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器学习AI算法工程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 深度神经网络的基本零件
    • 1.1 常用层:
      • 1.1.1. Dense
      • 1.1.2. Activation
      • 1.1.3. Dropout
    • 1.2 卷积层
      • 1.2.1. Conv2D
      • 1.2.2. Cropping2D
      • 1.2.3. ZeroPadding2D
    • 1.3. 池化层
      • 1.3.1. MaxPooling2D
      • 1.3.2. AveragePooling2D
    • 1.4. 正则化层
      • 1.4.1. BatchNormalization
    • 2. 深度神经网络的上下游结构
      • 2.2. 输入模块
        • 2.3 凸优化模块
        • 3. 实战项目——CIFAR-10 图像分类
        相关产品与服务
        GPU 云服务器
        GPU 云服务器(Cloud GPU Service,GPU)是提供 GPU 算力的弹性计算服务,具有超强的并行计算能力,作为 IaaS 层的尖兵利器,服务于深度学习训练、科学计算、图形图像处理、视频编解码等场景。腾讯云随时提供触手可得的算力,有效缓解您的计算压力,提升业务效率与竞争力。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档