【声明】个人学习笔记
深度学习入门实战----基于Keras的手写数字识别系列
深度学习入门实战----基于Keras的手写数字识别 (VGG16)
深度学习入门实战----基于Keras的手写数字识别 (GoogleNet)
目录
前言
手写数字数据集介绍
基于keras的手写数字识别实践
注意事项:
导入相关模块
载入MNIST数据集
数据的预处理
模型的建立与计算
结果分析
关于模型的保存与导入
以手写识别数据为例,作为深度学习的入门,本文以Keras深度学习库为基础。
内容包括:
使用Keras载入MNIST数据集
构建Lenet训练网络模型
使用Keras进行模型的保存、载入(json文件、weights)
使用Keras实现对手写数字数据集的训练与预测
画出误差迭代图
手写数字识别几乎是深度学习的入门数据集了。在keras中内置了MNIST数据集,其中测试集包含60000条数据,验证集包含10000条数据,为单通道的灰度图片,每张图片的像素大小为28×28.一共包含10个类别,为数字0到9。
本文使用的tensorflow等模块需要提前配置好
注意训练模型,图片,模型的保存、载入的文件路径问题,在自己电脑上运行时需要自行创建或修改
# import the necessary packages
import numpy as np
from keras.utils import np_utils
from keras.optimizers import Adam
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Flatten
from keras.layers.core import Dense
from keras import backend as K
from keras.models import load_model
Keras可实现多种神经网络模型,并可以加载多种数据集来评价模型的效果,下面我们使用代码自动加载MNIST数据集。
# load minit data
from keras.datasets import mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
显示MNIST训练数据集中的前面6张图片:
# plot 6 images as gray scale
import matplotlib.pyplot as plt
plt.subplot(321)
plt.imshow(x_train[0],cmap=plt.get_cmap('gray'))
plt.subplot(322)
plt.imshow(x_train[1],cmap=plt.get_cmap('gray'))
plt.subplot(323)
plt.imshow(x_train[2],cmap=plt.get_cmap('gray'))
plt.subplot(324)
plt.imshow(x_train[3],cmap=plt.get_cmap('gray'))
plt.subplot(325)
plt.imshow(x_train[4],cmap=plt.get_cmap('gray'))
plt.subplot(326)
plt.imshow(x_train[5],cmap=plt.get_cmap('gray'))
# show
plt.show()
首先,将数据转换为4维向量[samples][width][height][pixels],以便于后面模型的输入。
# reshape the data to four dimensions, due to the input of model
# reshape to be [samples][width][height][pixels]
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1).astype('float32')
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1).astype('float32')
为了使模型训练效果更好,通常需要对图像进行归一化处理。
# normalization
x_train = x_train / 255.0
x_test = x_test / 255.0
最后,原始MNIST数据集的数据标签是0-9证书,通常要将其表示成one-hot向量。如训练数据标签为1,则将其转化为向量[0,1,0,0,0,0,0,0,0,0]。
# one-hot
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
训练模型的参数设置:
# parameters
EPOCHS = 10
INIT_LR = 1e-3
BS = 32
CLASS_NUM = 10
norm_size = 28
本文使用Lenet网络架构,下面定义Lenet网络结构,若要更改网络结构,如用VGGNet,GoogleNet,Inception,ResNets或自己构建不同的网络结构,可以直接在这一块函数内进行修改。
# define lenet model
def l_model(width, height, depth, NB_CLASS):
model = Sequential()
inputShape = (height, width, depth)
# if we are using "channels last", update the input shape
if K.image_data_format() == "channels_first": # for tensorflow
inputShape = (depth, height, width)
# first set of CONV => RELU => POOL layers
model.add(Conv2D(20, (5, 5), padding="same", input_shape=inputShape))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# second set of CONV => RELU => POOL layers
model.add(Conv2D(50, (5, 5), padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# first (and only) set of FC => RELU layers
model.add(Flatten())
model.add(Dense(500))
model.add(Activation("relu"))
# softmax classifier
model.add(Dense(NB_CLASS))
model.add(Activation("softmax"))
# return the constructed network architecture
return model
设置优化方法,loss函数,并编译模型:
model = l_model(width=norm_size, height=norm_size, depth=1, NB_CLASS=CLASS_NUM)
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
本文使用生成器以节约内存:
# Use generators to save memory
aug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1,
height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,
horizontal_flip=True, fill_mode="nearest")
H = model.fit_generator(aug.flow(x_train, y_train, batch_size=BS),
steps_per_epoch=len(x_train) // BS,
epochs=EPOCHS, verbose=2)
作出训练阶段的损失、精确度迭代图,本文将epoch设置为10,已达到0.98的准确率(代码、图像如下所示)。
# plot the iteration process
N = EPOCHS
plt.figure()
plt.plot(np.arange(0,N),H.history['loss'],label='loss')
plt.plot(np.arange(0,N),H.history['acc'],label='train_acc')
plt.title('Training Loss and Accuracy on mnist-img classifier')
plt.xlabel('Epoch')
plt.ylabel('Loss/Accuracy')
plt.legend(loc='lower left')
plt.savefig('../figure/Figure_2.png')
方法一:使用model.save()将Keras模型和权重保存在一个HDF5文件中,该文件将包含:
模型的网络结构;
模型的权重 ;
训练配置(损失函数,优化器等) 优化器的状态;
保存模型:
model.save('../h5/m_lenet.h5')
载入模型
model.load('../h5/m_lenet.h5')
方法二:将网络结构(json或yaml)和网络权重分开保存:
将网络结构保存为json格式的文件:
# save json
from keras.models import model_from_json
json_string = model.to_json()
with open(r'../h5/m_lenet.json', 'w') as file:
file.write(json_string)
保存网络权重:
# save weights
model.save_weights('../h5/m_weights.h5')
载入网络结构:
with open(r'../input/m_lenet.json', 'r') as file:
model_json1 = file.read()
载入网络权重:
model = model_from_json(json_string)
model.load_weights('../h5/m_weights.h5', by_name=True)
注意方法二载入网络结构和权重后,需要对模型进行编译:
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])