用二维卷积做mnist手写数字识别

mnist简介

MNIST是一个手写数字的数据集(包含数字0-9),它包含60000个训练数据和10000个测试数据。这些数字已经经过尺寸标准化并位于图像中心,图像像素固定为28x28,每个像素值为0到255,每张图片有一个通道数。
keras内置了mnist数据集我们第一次导入会进行下载

导入数据

from keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()

查看数据

print(len(y_train))
print(y_train)
print(len(y_test))
60000
[5 0 4 ... 5 6 8]
10000

对标签进行独热编码

from keras.utils.np_utils import to_categorical
y_test = to_categorical(y_test)
y_train = to_categorical(y_train)

查看一张图片

import matplotlib.pyplot as plt
%matplotlib inline
plt.imshow(x_train[255])

在这里插入图片描述

补充的话

由于下面我们训练使用的是fit_generator,它和fit的区别是,fit是将全部的数据直接加载到内存中,而fit_generator会一边训练一边生成数据,节省了内存,fit_generator传入的是一个生成器。

为了让大家理解到生成器对内存的节约,下面用一个小例子来作说明

import sys
#a是一个生成器
a = (i for i in range(10000))
#b是一个列表
b = [i for i in range(10000)]
print("a的类型为:",type(a))
print("b的类型为:",type(b))
print("a所占内存大小为:",sys.getsizeof(a))
print("b所占内存大小为:",sys.getsizeof(b))
print("=============")
print("a取出一个元素",next(a))
print("现在a所占内存的大小为:",sys.getsizeof(a))

执行结果如下:

a的类型为: <class 'generator'>
b的类型为: <class 'list'>
a所占内存大小为: 128
b所占内存大小为: 87632
=============
a取出一个元素 0
现在a所占内存的大小为: 128

可以看到生成器比列表节省了大量的内存,我们需要元素时只需要next()取出即可,取出元素后生成器所占的内存不变。

keras提供了用于fit_generator的类模板,我们需要重写一下

from keras.utils import Sequence
import math
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

关于二维卷积

以RGB图片为例,一张图片有三个通道,分别是R(red),G(green),B(blue),我们的每一个卷积核都会对三个通道进行运算,每一个通道的运算如下图所示(下图为3×3卷积核)
在这里插入图片描述
每一个卷积核对三个通道进行运算后得到了三张3×3的图片,然后再把对应位置相加得到了一张3×3的图片,如下图所示
在这里插入图片描述
输出的通道数等于卷积核的个数。
二维卷积能够捕获到图片的局部特征,并且这种捕获不受局部特征在图片上位置的影响。通过这些特征可以让神经网络进行分类和识别从而达到一个较高的精度。

定义模型

from keras.models import Sequential
from keras.losses import CategoricalCrossentropy
from keras import layers
import numpy as np
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.Flatten(),
    layers.Dense(10,activation='softmax'),
])
model.compile(loss=CategoricalCrossentropy(),optimizer="adam",metrics=["acc"])

查看模型结构

model.summary()

在这里插入图片描述

定义回调函数

from keras.callbacks import EarlyStopping,ModelCheckpoint
callbacks_list = [
    EarlyStopping(
        monitor = 'val_acc', #监控验证精度
        patience = 2, #如果精度多于两轮不改善则中断训练
    ),
    ModelCheckpoint(
        filepath = 'my_model_conv2d.h5', #模型保存路径
        monitor = 'val_acc', #
        
        save_best_only = True, #如果val_loss没有改善则不需要覆盖模型
    )
]

模型训练

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

训练结果:

Epoch 1/5
300/300 [==============================] - 264s 880ms/step - loss: 0.2648 - acc: 0.9221 - val_loss: 0.0755 - val_acc: 0.9825
Epoch 2/5
300/300 [==============================] - 257s 857ms/step - loss: 0.0561 - acc: 0.9825 - val_loss: 0.0232 - val_acc: 0.9878
Epoch 3/5
300/300 [==============================] - 260s 867ms/step - loss: 0.0399 - acc: 0.9874 - val_loss: 0.0226 - val_acc: 0.9909
Epoch 4/5
300/300 [==============================] - 257s 856ms/step - loss: 0.0284 - acc: 0.9914 - val_loss: 0.0101 - val_acc: 0.9901
Epoch 5/5
300/300 [==============================] - 262s 874ms/step - loss: 0.0244 - acc: 0.9920 - val_loss: 0.0202 - val_acc: 0.9909

很快验证精度便达到了0.99,可以看到模型的效果还是很不错的,神经网络对于手写数字的识别率还是蛮高的。

今天的分享就到这里了,希望大家能够有所收获,欢迎关注,一起进步~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值