#深度神经网络
model = keras.models.Sequential()
#定义第一个卷积层
model.add(keras.layers.Conv2D(filters = 32, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #平均值池化
activation='relu', #加padding是否要输入和输出大小一样
input_shape=(28,28,1))) #输入图片大小 28*28*1
model.add(keras.layers.Conv2D(filters = 32, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #加padding是否要输入和输出大小一样
activation='relu')) #不需要加input_shape
#池化层
model.add(keras.layers.MaxPool2D(pool_size=2)) #步长和pool_size相同
model.add(keras.layers.Conv2D(filters = 64, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #平均值池化
activation='relu')) #加padding是否要输入和输出大小一样
model.add(keras.layers.Conv2D(filters = 64, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #加padding是否要输入和输出大小一样
activation='relu')) #不需要加input_shape
#池化层
model.add(keras.layers.MaxPool2D(pool_size=2)) #步长和pool_size相同
model.add(keras.layers.Conv2D(filters = 128, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #平均值池化
activation='relu')) #加padding是否要输入和输出大小一样
model.add(keras.layers.Conv2D(filters = 128, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #加padding是否要输入和输出大小一样
activation='relu')) #不需要加input_shape
#池化层
model.add(keras.layers.MaxPool2D(pool_size=2)) #步长和pool_size相同
#连接全连接层之前,先做一个flatten
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(128,activation='relu'))
model.add(keras.layers.Dense(10, activation="softmax"))
model.compile(loss = "sparse_categorical_crossentropy", #如果y已经是向量了就用categorical_crossentropy",如果是数字就用sparse_
optimizer = "sgd",
metrics = ["accuracy"])
model.summary()
#这里演示,使用三个常用的callbaks:TensorBoard, EarlyStopping, ModelCheckpoint
#对于Tensorboard需要一个文件夹,对于ModelCheckpoint来说需要一个文件名
#定义一个文件夹,和文件名
#logdir = './dnn-callbacks'
logdir = os.path.join("cnn-selu-callbacks")
if not os.path.exists(logdir):
os.mkdir(logdir)
output_model_file = os.path.join(logdir, "fashion_mnist_model.h5")
callbacks = [
keras.callbacks.TensorBoard(logdir),
keras.callbacks.ModelCheckpoint(output_model_file,save_best_only = True),
keras.callbacks.EarlyStopping(patience = 5, min_delta = 1e-3),
]
#callbacks是在训练过程中做一些监听,所以要添加到fit函数中
history = model.fit(x_train_scaler, y_train, epochs=10,
validation_data = (x_valid_scaled, y_valid),
callbacks = callbacks)
#绘图查看history中的变量变化过程
def plot_learning_curves(history):
pd.DataFrame(history.history).plot(figsize = (8,5)) #将数据转换成DataFrame,然后调用plot实现
plt.grid(True) #绘制网格
plt.gca().set_ylim(0, 2) #设定y坐标的范围
plt.show()
plot_learning_curves(history)
#在测试集上进行测试
model.evaluate(x_test_scaled, y_test)
注:将网络中所有relu激活函数换成selu后,模型的效果会得到不错的提升。(有时也会变得更糟糕)
修改建模部分代码
'''深度可分离卷积-神经网络Conv2D -> SeparableConv2D'''
model = keras.models.Sequential()
#定义第一个卷积层
model.add(keras.layers.Conv2D(filters = 32, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #大小不变
activation='relu', #加padding是否要输入和输出大小一样
input_shape=(28,28,1))) #输入图片大小 28*28*1
model.add(keras.layers.SeparableConv2D(filters = 32, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #加padding是否要输入和输出大小一样
activation='relu')) #不需要加input_shape
#池化层
model.add(keras.layers.MaxPool2D(pool_size=2)) #步长和pool_size相同
model.add(keras.layers.SeparableConv2D(filters = 64, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #大小不变
activation='relu')) #加padding是否要输入和输出大小一样
model.add(keras.layers.SeparableConv2D(filters = 64, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #加padding是否要输入和输出大小一样
activation='relu')) #不需要加input_shape
#池化层
model.add(keras.layers.MaxPool2D(pool_size=2)) #步长和pool_size相同
model.add(keras.layers.SeparableConv2D(filters = 128, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #大小不变
activation='relu')) #加padding是否要输入和输出大小一样
model.add(keras.layers.SeparableConv2D(filters = 128, #32个通道(32个卷积核)
kernel_size=3, #卷积核大小为3
padding='same', #加padding是否要输入和输出大小一样
activation='relu')) #不需要加input_shape
#池化层
model.add(keras.layers.MaxPool2D(pool_size=2)) #步长和pool_size相同
#连接全连接层之前,先做一个flatten
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(128,activation='relu'))
model.add(keras.layers.Dense(10, activation="softmax"))
model.compile(loss = "sparse_categorical_crossentropy", #如果y已经是向量了就用categorical_crossentropy",如果是数字就用sparse_
optimizer = "sgd",
metrics = ["accuracy"])
model.summary()
由上面可知cnn的网络参数为443306个参数
使用了深度可分离卷积网络参数变为184234
训练结果精度和训练曲线如下图所示:
注:上图训练结果非常差,因为训练的轮数太少将epochs由10 -> 100效果会有明显提升,改为300更佳。
结论:
**优点:**训练参数可以大大减少
**缺点:**精度有所下降,训练的时间更长,迭代的轮数也应该变得更多轮。
由上图可以看出,训练的精度在第8-9步才有所的提升,训练曲线也很明显的展现出这个问题。