2018-12-16 23:43:37

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习

 

 

本文作为上一节《卷积之上的新操作》的补充篇,将会关注一些读者关心的问题,和一些已经提到但并未解决的问题:

  • 到底该如何理解padding中的valid,same,full?
  • 空洞卷积会产生什么样的作用?
  • 如何实现inception中的多个尺寸卷积核作用在同一层上?

 

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_02

 

 

卷积形式的动态展示

 

希望以下动图可以帮助你直观理解卷积中的strides和padding.(图片来源为:https://github.com/vdumoulin/conv_arithmetic)

卷积核的最简单情形

 

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_03

 

 

如图,一个4*4的特征图被转化为2*2的特征图,卷积核的大小为3,stride=1,没有使用padding。

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_04

 

 

如图,一个5*5的特征图被转化为2*2的特征图,卷积核的大小为3,stride=2,没有使用padding。

这些无论如何都不使用padding的情形,卷积核只会访问到那些完全包着核的位置,一般输出比输入的尺寸要小,我们把它叫做有效卷积,也就是valid。

使用padding的卷积情形

 

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_05

 

 

一个5*5的特征图被转化为5*5的特征图,卷积核的大小为3,stride=1,使用padding,在这种输入输出保持相同尺寸的情形,我们叫相同卷积,也就是same,与stride是否为1无关。

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_06

 

 

一个5*5的特征图被转化为7*7的特征图,卷积核的大小为3,stride=1,使用更多的padding,这种输入特征图的每个元素都会被访问3(卷积核的大小)遍,我们叫全卷积,也就是full,与stride是否为1无关。一般的,full中的输出尺寸要大于输入尺寸。

空洞卷积(Dilated Convolution)

 

空洞卷积,在不增加参数的前提下,将原有的卷积核扩大。原本的卷积操作是3*3的卷积核作用在3*3的区域内,空洞卷积则会作用在5*5的区域内,一定程度上扩大了特征选取的范围,也就是通常人们所说的感受野。

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_07

 

 

如图,进行卷积操作的像素点用深蓝色标记,以前,3*3卷积核紧密作用于原图像,但空洞卷积作用下,卷积核的作用范围扩大,参数数量不变,意味着有些被包括的点实际上并未参与运算,这些就是“空洞”。

 

在keras中实现这一点并不难,我们搭建卷积层的时候就有dilation_rate参数,我们通过它来控制空洞卷积的空洞大小,也就是控制了感受野的大小。

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_02

 

 

同一层中使用多个尺寸的卷积核

 

我们已经在前面对MNIST手写识别数据中的10000个样本分别使用了普通的全连接网络,添加卷积的网络,以及卷积+池化的网络,证明了,在参数数量远远小于全连接网络的情况下,CNN取得了更优的结果。

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_09

 

 

 

但是再进一步的提升准确率,更好的看出效果,我们最好选用更复杂的数据,MNIST手写识别数据非常经典,是必测的数据集。但它的上限比较好到达,全连接网络就能达到93%的准确率。

所以我们将MNIST替换为fashion-MNIST数据,fashion-MNIST格式,大小与MNIST一模一样,包含了十类衣物,比如T恤,裙子,凉鞋,包,裤子等外观样式,只是比MNIST手写识别更加困难。

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_10

 

 

图为fashion-MNIST数据集的样例

 

在Keras中,fashion-MNIST的导入非常简单:

from keras.datasets import fashion_mnist(X_test,y_test),

(X_train,y_train)=fashion_mnist.load_data()

 

注意到这里,我们指定了测试集为60000个样本,训练集为10000个样本,这实践中当然是错误的。但是我们的目的是只训练那10000个样本,并从中抽取30%作为验证集,来达到比较模型优劣的目的。

如果我们保持模型不变,只改变数据,观察在MNIST数据上表现良好的四个模型在fashion-MNIST上的表现:

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_11

 

 

如图,经过10个epochs,我们只观察验证集上的准确率对比,可以发现,全连接模型的准确率只有83%,CNN最好也只有86.5%。

接下来,我们尝试在某一层使用多个大小的卷积核,在keras中,我们可以使用函数式模型,对同一个输入分别采用不同的卷积,最后再将他们融合起来:

def conv_model_branch():

x=Input(shape=(28,28,1))

x2= Conv2D_bn(x,64,3,3)

branchx1= Conv2D_bn(x2,32,5,5)

branchx2= Conv2D_bn(x2,32,3,3)

branchx3=Conv2D_bn(x2,32,7,7)

branchx4=Conv2D_bn(x2,32,1,1)

x3=layers.concatenate([branchx1,branchx2,\

branchx3,branchx4],axis=-1)

x4=Flatten()(x3)

x5=Dense_bn(x4,32)

x6=Dropout(0.2)(x5)

y=Dense(10,activation='softmax')(x6)

model = Model(inputs=x, outputs=y)

model.compile(optimizer='SGD',

loss='categorical_crossentropy',

metrics=['accuracy'])

return(model)

 

我们在这里分别创建了4个分支:

  • branchx1是大小为5的卷积核
  • branchx2是大小为3的卷积核
  • branchx3是大小为7的卷积核
  • branchx4是大小为1的卷积核

 

其中concatenate层就是一个将不同的分支按照某条轴串起来,以实现不同大小的卷积核输出的融合。具体是怎么串起来的呢?假如说A、B是矩阵,他们沿着行串起来,得到C,就会是:

A B C

a b c g h i a b c g h i

d e f j k l d e f j k l

 

我们对这个简单的模型进行训练,同时训练不使用复杂结构的CNN,将两者验证集上的表现对比,可以得到:

 

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_12

 

 

从图中可以看出,添加多个尺寸卷积核的CNN与普通的直连的CNN相比,只是在训练的开始阶段表现优异,但随着epochs的增多,性能上并没有什么优势,一方面这可能是因为网络不够庞大,表现为我们可能需要多进行几次这样的操作,另一方面则是因为我们在这里只简单的采取了多个尺寸卷积核的并行,而非对这些卷积核进行进一步的处理。

CNN在Keras中的实践|机器学习你会遇到的“坑”_机器学习_13