用卷积层代替全连接层做mnist手写数字识别

由于博主之前已经写了一篇mnist的文章,关于mnist数据集的介绍这里就不过多赘述了,简单来说mnist中有6万张训练图片,1万张测试图片,每张图片都是手写数字0-9中一个。我们训练模型希望模型能正确做出预测。

本文的重点在于用卷积层代替最后的全连接层。
一般的图片分类,最后一般是使用Flatten层和Dense层。
以博主之前那篇文章为例,模型的结构是:
在这里插入图片描述
如何用卷积层代替Flatten层和Dense层呢?
首先我们得明确,最后一层一定有十个输出,用于做分类交叉熵。
此时,便想到了用1*1卷积,将通道数设为10,然后通过一个全局平均池化得到每个通道所有像素的平均值,然后再通过Reshape层将输出变成一维张量,最后通过Softmax层,这样便代替了展平和全连接层。

下面来实际试验一下
下面代码就不详细解释了,有疑问的可以看我这篇文章用二维卷积做mnist手写数字识别
细节部分只有定义模型最后几层有区别

from keras import layers
import numpy as np
from keras.models import Model
from keras.losses import CategoricalCrossentropy
from keras.datasets import mnist
from keras.utils.np_utils import to_categorical
from keras.models import Sequential
from keras.utils import Sequence
import math

(x_train, y_train), (x_test, y_test) = mnist.load_data()
y_test = to_categorical(y_test)
y_train = to_categorical(y_train)

class Generator(Sequence):
    def __init__(self, x, y, b_size):
        self.x, self.y = x, y
        self.batch_size = b_size
    def __len__(self):
        return math.ceil(len(self.y)/self.batch_size)       
    def __getitem__(self, idx):
        batch_x = self.x[idx * self.batch_size:(idx + 1) *
        self.batch_size]
        batch_y = self.y[idx * self.batch_size:(idx + 1) *
        self.batch_size]
        batch_x  = batch_x/255.0
        batch_x = batch_x.reshape(*batch_x.shape,1)
        return batch_x,batch_y
    def on_epoch_end(self):
        pass
from keras.callbacks import EarlyStopping,ModelCheckpoint
callbacks_list = [
    ModelCheckpoint(
        filepath = 'my_test_conv2d.h5', #模型保存路径
        monitor = 'val_acc', #
        
        save_best_only = True, #如果val_loss没有改善则不需要覆盖模型
    )
]

定义模型

#模型定义
model=Sequential([
    layers.Conv2D(64,(3,3),padding='same',activation='relu',input_shape=(28,28,1)),
    layers.MaxPool2D(2,2),
    layers.Conv2D(128,(3,3),padding='same',activation='relu'),
    layers.MaxPool2D(2,2),
    layers.Conv2D(64,(3,3),activation='relu'),
    layers.Conv2D(32,(3,3),padding='same',activation='relu'),
    layers.Conv2D(10,(1,1)),
    layers.GlobalAveragePooling2D(),
    layers.Reshape((10,)),
    layers.Softmax(),
])
model.compile(loss=CategoricalCrossentropy(),optimizer="adam",metrics=["acc"])

查看模型结构

model.summary()

在这里插入图片描述

训练模型

history = model.fit_generator(Generator(x_train,y_train,200),epochs=6,validation_data=Generator(x_test,y_test,200),callbacks=callbacks_list)

训练结果如下:

Epoch 1/6
300/300 [==============================] - 262s 874ms/step - loss: 0.6324 - acc: 0.7965 - val_loss: 0.2068 - val_acc: 0.9436
Epoch 2/6
300/300 [==============================] - 264s 880ms/step - loss: 0.1777 - acc: 0.9481 - val_loss: 0.1442 - val_acc: 0.9479
Epoch 3/6
300/300 [==============================] - 263s 877ms/step - loss: 0.1193 - acc: 0.9645 - val_loss: 0.1141 - val_acc: 0.9654
Epoch 4/6
300/300 [==============================] - 264s 880ms/step - loss: 0.0920 - acc: 0.9719 - val_loss: 0.0995 - val_acc: 0.9735
Epoch 5/6
300/300 [==============================] - 263s 878ms/step - loss: 0.0748 - acc: 0.9769 - val_loss: 0.0914 - val_acc: 0.9775
Epoch 6/6
300/300 [==============================] - 268s 893ms/step - loss: 0.0639 - acc: 0.9802 - val_loss: 0.0265 - val_acc: 0.9841

第一轮训练的效果不太理想,训练精度只达到了0.79,但是似乎还有着上升空间,在接下来的几轮中,模型精度不断提高,六轮过后验证精度达到了0.984,但是它似乎还有进步的空间。于是再训练四轮。

model.fit_generator(Generator(x_train,y_train,200),epochs=4,validation_data=Generator(x_test,y_test,200),callbacks=callbacks_list)

训练结果如下

Epoch 1/4
300/300 [==============================] - 272s 908ms/step - loss: 0.0362 - acc: 0.9884 - val_loss: 0.0232 - val_acc: 0.9887
Epoch 2/4
300/300 [==============================] - 268s 893ms/step - loss: 0.0313 - acc: 0.9900 - val_loss: 0.0093 - val_acc: 0.9908
Epoch 3/4
300/300 [==============================] - 270s 901ms/step - loss: 0.0292 - acc: 0.9907 - val_loss: 0.0184 - val_acc: 0.9878
Epoch 4/4
300/300 [==============================] - 265s 884ms/step - loss: 0.0285 - acc: 0.9911 - val_loss: 0.0032 - val_acc: 0.9913

模型最终还是达到了0.991的验证精度,和模型最后用全连接层达到的效果差不多。

以上只是博主突发奇想的一次尝试,虽然最后也能达到较高的精度,但是相比于最后用全连接层的训练速度更慢,这个模型能否在别的问题上发挥出更好的效果还有待尝试。

今天的分享就到这里了,感谢大家的阅读,欢迎关注,一起进步~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值