Keras框架实现手写图片识别

使用 Keras 框架,而不是用 TensorFlow 自己实现,提升编程效率
增加网络的深度,这里增加到了20层
每次卷积完之后,加入规范层

更多:Keras

第05课:TensorFlow 实战一:手写图片识别终章:99%准确率达成

上一篇文章,我们用 CNN 实现了手写识别,这次我们对模型进行优化,提升准确率。

CNN 网络模型举例

一、改进方案

  • 使用 Keras 框架,而不是用 TensorFlow 自己实现,提升编程效率
  • 增加网络的深度,这里增加到了20层
  • 每次卷积完之后,加入规范层
  • 使用最新的 SELU 激活函数,这是 Sepp Hochreiter 最新发表在 arXiv 上的激活函数,Sepp 是当年和 Jürgen Schmidhuber 一起发明 LSTM 的神级人物。相关介绍参考这个链接:「自归一化神经网络」提出新型激活函数SELU

二、理论知识补充(最小知识集)

1,BatchNormalization 的计算原理,优缺点

为了避免对数据的感应不铭感,会对数据做处理,使得数据的变化范围不会太大,这个处理叫 normalization 预处理。Batch normalization 的 batch 是批数据, 把数据分成小批小批进行随机梯度下降。而且在每批数据进行前向传递 forward propagation 的时候,对每一层都进行 normalization 的处理。 优点是可以避免数据对激活函数的饱和从而收敛到更好的结果,并且能减少训练时长。

2,RMSprop 优化器的原理,优缺点

RMSprop 是 Geoff Hinton 提出的一种以梯度的平方来自适应调节学习率的优化方法。

优点是,对于常见参数更新较小,自动更新,不用手动调节学习率。缺点是,因为公式中分母上会累加梯度平方,这样在训练中持续增大的话,会使学习率非常小,甚至趋近无穷小

3,池化层的计算原理

池化层是在几个数据中挑选出最能代表这个区域的,把一个区域简化成一个数值,可以取最大值、最小值、平均值。这样可以降低计算量,降低过拟合。

4,softmax 与 sigmoid 激活函数的区别

sigmoid 将一个 real value 映射到(0,1)的区间(当然也可以是(-1,1)),这样可以用来做二分类。 而softmax把一个k维的real value向量(a1,a2,a3,a4…)映射成一个(b1,b2,b3,b4…)其中 bi 是一个0-1的数值,b1到bn累加为1,然后可以根据 bi 的大小来进行多分类的任务,如取权重最大的一维。

5,categorical_crossentropy 的计算原理

交叉熵计算原理是−[ylna+(1−y)ln(1−a)]。

6,为什么选择交叉熵而不是平均平方误差( MSE )

不选择MSE的原因是,使用MSE在Y取较大值时,权重和偏置的更新速度会很慢,而用交叉熵作为损失函数可以克服这个问题。

三、代码实现

1,加载数据集,对数据集进行处理

import numpy as np
import tensorflow as tf
import pandas as pd
from keras.layers.advanced_activations import *
from keras.models import Sequential
from keras.layers import Dense,Activation,Conv2D
from keras.layers import MaxPool2D,Flatten,Dropout,ZeroPadding2D,BatchNormalization
from keras.utils import np_utils
import keras
from keras.models import save_model,load_model
from keras.models import Model


#1 加载数据集,对数据集进行处理,把输入和结果进行分开
df = pd.read_csv("train.csv")

data = df.as_matrix()

df =None

#打乱顺序
np.random.shuffle(data)


x_train = data[:,1:]
#把训练的图片数据转化成28*28的图片
x_train = x_train.reshape(data.shape[0],28,28,1).astype("float32")
x_train = x_train/255
#把训练的图片进行OneHot编码
y_train = np_utils.to_categorical(data[:,0],10).astype("float32")

#2 设相关参数
#设置对训练集的批次大小
batch_size = 64
#设置卷积滤镜个数
n_filters = 32
#设置最大池化,池化核大小
pool_size = (2,2)

2,定义模型

#ai8py.com
#3 定义网络,按照ZeroPadding,卷积层、规范层、池化层进行设置
#这里用了最新的selu,很厉害的一种激活函数
cnn_net = Sequential()

cnn_net.add(Conv2D(32, kernel_size=(3, 3), strides=(1, 1),
                 input_shape=(28, 28, 1)))     
cnn_net.add(Activation('relu'))
cnn_net.add(BatchNormalization(epsilon=1e-6,axis=1))
cnn_net.add(MaxPool2D(pool_size = pool_size))

cnn_net.add(ZeroPadding2D((1, 1)))
cnn_net.add(Conv2D(48,kernel_size=(3,3)))
cnn_net.add(Activation('relu'))
cnn_net.add(BatchNormalization(epsilon=1e-6, axis=1)  )
cnn_net.add(MaxPool2D(pool_size = pool_size))

cnn_net.add(ZeroPadding2D((1, 1)))
cnn_net.add(Conv2D(64,kernel_size=(2,2)))
cnn_net.add(Activation('relu'))
cnn_net.add(BatchNormalization(epsilon=1e-6, axis=1)  )
cnn_net.add(MaxPool2D(pool_size = pool_size))

cnn_net.add(Dropout(0.25))
cnn_net.add(Flatten())

cnn_net.add(Dense(3168))
cnn_net.add(Activation('relu'))

cnn_net.add(Dense(10))
cnn_net.add(Activation('softmax'))

# 设置损失函数、优化器等参数,
cnn_net.compile(loss=keras.losses.categorical_crossentropy,optimizer = keras.optimizers.RMSprop(),metrics=['accuracy'])     

# 4 查看网络结构,可视化模型
#查看网络结构
cnn_net.summary()

3,训练模型,保存和载入模型

#5 训练模型、保存和载入模型
#cnn_net = load_model('cnn_net_model.h5')

cnn_net.fit(x_train,y_train,batch_size=batch_size,epochs=50,verbose = 1,validation_split = 0.2)

cnn_net.save('cnn_net_model.h5')

4,生成预测结果

#6 生成提交的预测结果
df = pd.read_csv("test.csv")

x_valid = df.values.astype('float32')

n_valid = x_valid.shape[0]

x_valid = x_valid.reshape(n_valid,28,28,1)

x_valid = x_valid/255


yPred = cnn_net.predict_classes(x_valid,batch_size=32,verbose=1)

np.savetxt('mnist_output.csv', np.c_[range(1,len(yPred)+1),yPred], delimiter=',', header = 'ImageId,Label', 
           comments = '', fmt='%d')

四、上传 Kaggle 看结果

请注意,训练是有一定随机性的,如果一次训练的不好,可以反复尝试训练。尽量准确度在99.2%以上,再生成提交结果。

kaggle 结果

虽然手写识别已经有无数人做过了,但提交到 Kaggle 的只有1600多人,我们的结果在200多位,进入了前20%,对于新手来错,应该还可以了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注