前言
当我将神经网络从DNN变为CNN之后,我发现我的模型无法训练了。我们以经典的Mnist数据来了解以下原因。
【深度学习手记】使用全连接神网络训练与卷积训练对数据集的要求有什么不一样
运行情况
正常
【code】
import os
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers, datasets
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
(x_train,y_train),(x_test,y_test)=datasets.mnist.load_data()
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128,activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(10,activation=tf.nn.softmax))
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
model.fit(x_train,y_train,epochs=5) #训练模型
【print】
添加CNN-Layer变异常:
目前一切还是正常的,但是如果我们将模型的网络层小小的添加一个卷积层,一切都不一样了。
【code】
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(filters=64,kernel_size=(7,7),padding='same',input_shape=(28,28,1),activation='relu'),
tf.keras.layers.MaxPool2D(),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(10,activation='softmax')
])
model.fit(x_train,y_train,epochs=5) #训练模型
【print】
ValueError: Input 0 of layer sequential_2 is incompatible with the layer: expected ndim=4, found ndim=3. Full shape received: [32, 28, 28]
ValueError:层sequential_2的输入0与层不兼容:预期的ndim=4,找到的ndim=3。收到的完整形状:[32,28,28]
解释
卷积结构图
其实原因非常简单,这不是数据集的错,而是卷积的因素,我们来看看卷积核的结构究竟是怎么样的?
想必看完这张图,大家就已经恍然大悟了,没错,CNN层中的卷积正是一个使用卷积核像这样遍历图像进行特征提取的一个过程,如下图所示:
既然卷积核是三维的,我们又需要用卷积核去遍历卷积,如果维度不一样怎么遍历呢?要知道,需要先重合(在同一纬度)才能够遍历,就好像三维的物体没有办法重合二维的物体,三维智能包含二维的物体,是一样的道理。
reshap变成卷积可训数据集
那好,相比我已经解释的非常清楚了,那么我需要怎么样修改数据集的维度,使得我们的数据集可以投入卷积神经网络训练呢?如下:
x_train4D = x_train.reshape(x_train.shape[0],28,28,1).astype('float32')
x_test4D = x_test.reshape(x_test.shape[0],28,28,1).astype('float32')
x_train,x_test = x_train4D/255.0,x_test4D/255.0 # 归一化,为了更好的训练可以不做
binggo! 运行成功啦!可以看到,卷积核的效果还是超过全连接层的,同样的epoch5次,CNN准确率到达了98.4%,回顾以下DNN层:
只有94.1% !