使用Tensorflow搭建简单的CNN卷积神经网络对fashion_mnist数据集进行分类html
不了解是那么是CNN卷积神经网络的小伙伴能够参考上一篇博客(Tensorflow学习笔记No.4.1)网络
2.1.keras.layers.Conv2D()二维卷积层ide
例如:函数
model.add(keras.layers.Conv2D(128, (3, 3), activation = 'relu', padding = 'same')
向model中添加一个二维卷积层,第一个参数是filter,也就是卷积核的个数,决定了这层卷积层输出的数据有多少个通道。第二个参数是卷积核的大小,这里使用的是3×3的卷积核。activation是激活函数,再也不赘述。学习
padding则是卷积层的填充模式。简单来讲,设卷积核的尺寸为k×k,输入数据的尺寸为size×size,若填充模式为‘same’,则卷积层输出的尺寸与输入时相同,为size×size,若为默认模式‘valid’,则输出的尺寸为(size-(k-1))×(size-(k-1))。 测试
strides参数(示例中没有出现),它是卷积核每次移动的跨度,默认为(1, 1),分别是在x和y轴上移动的跨度,若调整为(2, 2)则卷积层的输出尺寸会将变为原来的1/2,即(size/2)×(size/2),同理,若为(k, k)则输出尺寸变为(size/k)×(size/k),使用这个参数会严重减小输出信息,虽然能明显减小网络容量,可是容易形成关键特征的丢失,慎重使用!优化
2.2.keras.layers.MaxPool2D()二维卷积的池化层spa
例如:code
1 model.add(keras.layers.MaxPool2D()) 2 model.add(keras.layers.AveragePooling2D()) 3 model.add(keras.layers.GlobalAveragePooling2D())
向model中添加二维池化层。htm
池化层默认尺寸pool_size参数为2×2,会把数据的尺寸缩小至原来的1/2,而且不改变深度。
示例中的三种池化层分别为最大值池化,均值池化与全局均值池化。
最大值池化,选择pool_size×pool_size范围内的最大值做为当前位置的值,每次移动pool_size个单位,若size没法被整除则自动填充。均值池化同理,计算范围内的均值做为当前位置的值。全局池化有所不一样,它是将所有数据进行池化压缩,将数据的尺寸size×size缩小为1×1,不改变深度,一般放在全链接层以前。
使用tensorflow创建一个简单的CNN网络模型,对fashion_mnist数据集进行分类,是一个较为简单的10分类问题。
首先导入须要用到的模块
1 from tensorflow import keras 2 import matplotlib.pyplot as plt 3 import numpy as np 4 import pandas as pd
3.1加载并处理数据
加载fashion_mnist数据集,并分为训练集和测试集。
fashion_mnist = keras.datasets.fashion_mnist
(train_image, train_label), (test_image, test_label) = fashion_mnist.load_data()
此时的train_image与test_image的尺寸分别为(6000, 28, 28), (1000, 28, 28),分别对应图片数,图片的长和宽。
可是卷积神经网络的输入时图片,图片应该有三个维度,长宽以及通道数(channel),fashion_mnist数据集中均为灰度图像,因此只有一个通道,咱们给测试集和训练集分别加上这一维度以便做为神经网络的输入。
1 train_image = np.expand_dims(train_image, -1) 2 test_image = np.expand_dims(test_image, -1)
这里使用了numpy的.expand_dims()方法扩展了数据集的通道,数据尺寸的最后方加入了一个维度。
如今数据的尺寸变为(num, 28, 28, 1),即num个28×28的单通道灰度图像。
3.2创建网络模型
使用keras.Sequential()方法创建一个Sequential模型。
1 model = keras.Sequential()
首先向其中添加输入层,咱们要尽可能保留数据的特征,因此第一层就直接选用处理图像效果较好的Conv2D卷积层,尽量的获取图像特征。
1 model.add(keras.layers.Conv2D(32, (3, 3), 2 input_shape = (28, 28, 1), 3 activation = 'relu', 4 padding = 'same' 5 ))
Conv2D()中的主要参数在2.1中均有说起,这里再也不赘述。
input_shape参数与以前创建的Sequential模型相似,表示输入数据的尺寸,这里为28×28的单通道灰度图像,因此input_shape应该为(28, 28, 1)。
随后向网络中添加池化层,提取主要特征并缩小数据规模。
规模缩小到过程也是扩大感觉野的过程,随着特征规模的缩小,单个卷积核单次所能覆盖的图像特征范围逐渐扩大,这是一个逐渐从提取局部特征转变为提取全局特征的过程。
1 model.add(keras.layers.MaxPool2D())
继续添加卷积层与池化层,最后添加全链接层输出分类结果,最终的模型为:
1 model = keras.Sequential() 2 model.add(keras.layers.Conv2D(32, (3, 3), 3 input_shape = (28, 28, 1), 4 activation = 'relu', 5 padding = 'same' 6 )) 7 #32个卷积核,每一个卷积核大小为3*3,输入规格,激活函数,填充为使输出与原尺寸相同,默认(valid)为不填充 8 model.add(keras.layers.MaxPool2D()) 9 #默认为2*2池化层 10 model.add(keras.layers.Conv2D(64, (3, 3), activation = 'relu')) 11 model.add(keras.layers.GlobalAveragePooling2D()) 12 #全局平均池化 13 model.add(keras.layers.Dense(10, activation = 'softmax')) 14 #输出层,10分类
这样就搭建好了一个简单的卷积神经网络。
3.3使用.compile()方法与.fit()方法训练模型
这里与以前的训练方式相同,不熟悉的小伙伴能够翻翻以前的博客(Tensorflow学习笔记No.1)进行查看,代码以下:
1 model.compile(optimizer = 'adam', 2 loss = 'sparse_categorical_crossentropy', 3 metrics = ['acc'] 4 ) 5 6 history = model.fit(train_image, train_label, epochs = 30, validation_data = (test_image, test_label))
训练过程:
若是你使用的是notebook类的环境,训练完成后插入如下代码(Tensorflow学习笔记No.0中有相关介绍)便可查看训练的正确率图像:
1 %matplotlib inline 2 plt.plot(history.epoch, history.history.get('acc'), label = 'acc') 3 plt.plot(history.epoch, history.history.get('val_acc'), label = 'val_acc') 4 plt.legend()
图像以下图所示:
如下内容是由本人通过屡次试验和验证获得的:
从刚刚训练的网络模型的训练图像中能够看出:
训练集的正确率仅有92.5%,说明模型的拟合性不够;测试集与训练集正确率相差较大,说明在后续训练中可能出现过拟合问题。
(注:过拟合是指在训练集达到很是好的正确率而在测试集上的正确率并不理想,这里出现的状况是训练集和测试集上的正确率均不理想,因此不能称之为过拟合,但经过图像不难看出,咱们的模型继续训练下去极有可能出现过拟合现象。)
因此咱们的优化方式从这两个角度出发,首先,增长隐藏单元(卷积核)数量,加深模型深度,以增长模型的拟合度。而后,为了抑制可能出现的过拟合现象,在适当位置加入Dropout层抑制过拟合。
改进后的模型以下:
1 model_ = keras.Sequential() 2 model_.add(keras.layers.Conv2D(64, (3, 3), 3 input_shape = (28, 28, 1), 4 activation = 'relu', 5 padding = 'same' 6 )) 7 model_.add(keras.layers.Conv2D(64, (3, 3), activation = 'relu', padding = 'same')) 8 #添加两层Conv2D以提升拟合能力 9 model_.add(keras.layers.MaxPool2D()) 10 model_.add(keras.layers.Dropout(0.25)) 11 #添加Dropout抑制过拟合 12 model_.add(keras.layers.Conv2D(128, (3, 3), activation = 'relu', padding = 'same')) 13 model_.add(keras.layers.Conv2D(128, (3, 3), activation = 'relu', padding = 'same')) 14 model_.add(keras.layers.MaxPool2D()) 15 model_.add(keras.layers.Dropout(0.25)) 16 model_.add(keras.layers.Conv2D(256, (3, 3), activation = 'relu', padding = 'same')) 17 model_.add(keras.layers.Conv2D(256, (3, 3), activation = 'relu', padding = 'same')) 18 model_.add(keras.layers.Dropout(0.25)) 19 model_.add(keras.layers.GlobalAveragePooling2D()) 20 model_.add(keras.layers.Dense(256, activation = 'relu')) 21 #添加Dense层进行过渡 22 model_.add(keras.layers.Dense(10, activation = 'softmax'))
通过调整后的模型获得以下结果:
模型的正确率图像以下:
通过调整后的模型,拟合度有了较为明显的提升,在测试集上能够达到接近95%的正确率,在测试集上也能达到较为满意的效果,正确率约92.5%。
后续将会对模型进行改进,争取达到更高的准确率!