图像识别 基于Keras的手写数字识别(含代码)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像识别 基于Keras的手写数字识别(含代码)相关的知识,希望对你有一定的参考价值。

参考技术A

前沿

人工智能的浪潮已经席卷全球,深度学习(Deep Learning)和人工智能(Artificial Intelligence, AI)等词汇也不断地充斥在我们身边。人工智能的发展是一个三起两落的变化,90年代期间,知识推理>神经网络>机器学习;2005年左右,机器学习>知识(语义网)>神经网络;而从2017年之后,基于深度学习的神经网络>知识(知识图谱)>机器学习。

卷积神经网络(convolutional neural network, CNN)作为深度学习中的代表,最早的灵感是来源于1961年Hubel和Wiesel两位神经生物学家,在对猫视觉皮层细胞的实验中,发现大脑可视皮层是分层的(CNN中的分层网络结构与其如出一辙)。深度学习作为机器学习(ML)的一个子领域,由于计算机能力的提高和大量数据的可用性,得到了戏剧性的复苏。但是,深度学习是否能等同或代表人工智能,这一点笔者认为有待商榷,深度学习可以认为是目前人工智能发展阶段的重要技术。由于本文主要撰写关于深度学习的入门实战,关于细节概念不做深入研究,下面笔者从实际案例,介绍深度学习处理图像的大致流程。

目录:

以手写识别数字为例,作为深度学习的入门项目,本文以Keras深度学习库为基础。其中使用的tensorflow等模块需要提前配置好,同时注意模型,图片保存、载入的文件路径问题。在自己的计算机上运行时,需要创建或修改。下面的流程包括:使用Keras载入MNIST数据集,构建Lenet训练网络模型,使用Keras进行模型的保存、载入,使用Keras实现对手写数字数据集的训练和预测,最后画出误差迭代图。

手写数字数据集介绍:

手写数字识别几乎是深度学习的入门数据集了。在keras中内置了MNIST数据集,其中测试集包含60000条数据,验证集包含10000条数据,为单通道的灰度图片,每张图片的像素大小为28 28.一共包含10个类别,为数字0到9。

导入相关模块:

载入MNIST数据集

Keras可实现多种神经网络模型,并可以加载多种数据集来评价模型的效果,下面我们使用代码自动加载MNIST数据集。

显示MNIST训练数据集中的前面6张图片:

数据的预处理

首先,将数据转换为4维向量[samples][width][height][pixels],以便于后面模型的输入

为了使模型训练效果更好,通常需要对图像进行归一化处理

最后,原始MNIST数据集的数据标签是0-9,通常要将其表示成one-hot向量。如训练数据标签为1,则将其转化为向量[0,1,0,0,0,0,0,0,0,0]

模型的建立与计算

训练模型的参数设置:

本文使用Lenet网络架构,下面定义Lenet网络结构,若要更改网络结构,如用VGGNet,GoogleNet,Inception,ResNets或自己构建不同的网络结构,可以直接在这一块函数内进行修改。

再附上两个经典的模型:

VGG16:

GoogleNet:

设置优化方法,loss函数,并编译模型:

本文使用生成器以节约内存:

结果分析

作出训练阶段的损失、精确度迭代图,本文将epoch设置为10,已达到0.98的准确率(代码、图像如下所示)。

公众号:帕帕 科技 喵

欢迎关注与讨论~

keras入门实战:手写数字识别

近些年由于理论知识的硬件的快速发展,使得深度学习达到了空前的火热。深度学习已经在很多方面都成功得到了应用,尤其是在图像识别和分类领域,机器识别图像的能力甚至超过了人类。

本文用深度学习Python库Keras实现深度学习入门教程mnist手写数字识别。mnist手写数字识别是机器学习和深度学习领域的“hello world”,MNIST数据集是手写数字的数据集合,训练集规模为60000,测试集为10000。

本文的内容包括:

  • 如何用Keras加载MNIST数据集
  • 对于MNIST问题如何实现一个baseline的神经网络
  • 基于MNIST问题如何实现并评价一个卷积神经网络(CNN)
  • 基于MNIST问题如何实现一个接近最高准确率的深度学习模型

MNIST手写数字识别问题

MNIST问题是由Yann LeCun, Corinna Cortes 和Christopher Burges为了评估机器学习模型而设立的。问题的数据集是从一些National Institute of Standards and Technology (NIST)的文档中得来,是计算机视觉入门级的数据集,它包含各种手写数字图片:
技术分享

它也包含每一张图片对应的标签,告诉我们这个是数字几。比如,上面这四张图片的标签分别是5,0,4,1。
每张图片是28*28像素(共784个像素)。对于一般的图片像素通道通常是3维,即rgb,代表red、green、blue三个颜色通道,而MNIST数据集的像素通道只有一位即为灰度值,每一个像素值在0到1之间表示这个像素的灰度,0表示白色,1表示黑色。图片的类别标签是这个图片的数字,取值范围为0-9.因此MNIST问题是一个多分类的问题,类别为10。
现在好的分类结果可是使错误率降到1%以下。接近最好效果的错误率大约为0.2%,可用大规模的CNN实现。

加载MNIST数据集

Keras提供了实现深度学习所需要的绝大部分函数库,可实现多种神经网络模型,并可加载多种数据集来评价模型的效果。下面的代码会自动加载数据,如果是第一次调用,数据会保存在你的hone目录下~/.keras/datasets/mnist.pkl.gz,大约15MB。

# Plot ad hoc mnist instances
from keras.datasets import mnist
import matplotlib.pyplot as plt
# load (downloaded if needed) the MNIST dataset
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# plot 4 images as gray scale
plt.subplot(221)
plt.imshow(X_train[0], cmap=plt.get_cmap(‘gray‘))
plt.subplot(222)
plt.imshow(X_train[1], cmap=plt.get_cmap(‘gray‘))
plt.subplot(223)
plt.imshow(X_train[2], cmap=plt.get_cmap(‘gray‘))
plt.subplot(224)
plt.imshow(X_train[3], cmap=plt.get_cmap(‘gray‘))
# show the plot
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

上面的代码加载了数据集并画出了前4个图片:
技术分享

多层感知机的baseline模型

在实现卷积神经网络这种复杂的模型之前,先实现一个简单但效果也不错的模型:多层感知机。这种模型也叫含隐层的神经网络。模型的效果可以使错误率达到1.87%。
第一步是加载所需要的库

import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.utils import np_utils
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

设定随机数种子,保证结果的可重现性

seed = 7
numpy.random.seed(seed)
  • 1
  • 2
  • 1
  • 2

加载数据

(X_train, y_train), (X_test, y_test) = mnist.load_data()
  • 1
  • 1

数据集是3维的向量(instance length,width,height).对于多层感知机,模型的输入是二维的向量,因此这里需要将数据集reshape,即将28*28的向量转成784长度的数组。可以用numpy的reshape函数轻松实现这个过程。

num_pixels = X_train.shape[1] * X_train.shape[2]
X_train = X_train.reshape(X_train.shape[0], num_pixels).astype(‘float32‘)
X_test = X_test.reshape(X_test.shape[0], num_pixels).astype(‘float32‘)
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

给定的像素的灰度值在0-255,为了使模型的训练效果更好,通常将数值归一化映射到0-1。

X_train = X_train / 255
X_test = X_test / 255
  • 1
  • 2
  • 1
  • 2

最后,模型的输出是对每个类别的打分预测,对于分类结果从0-9的每个类别都有一个预测分值,表示将模型输入预测为该类的概率大小,概率越大可信度越高。由于原始的数据标签是0-9的整数值,通常将其表示成0ne-hot向量。如第一个训练数据的标签为5,one-hot表示为[0,0,0,0,0,1,0,0,0,0]。

y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

现在需要做得就是搭建神经网络模型了,创建一个函数,建立含有一个隐层的神经网络。

# define baseline model
def baseline_model():
    # create model
    model = Sequential()
    model.add(Dense(num_pixels, input_dim=num_pixels, kernel_initializer=‘normal‘, activation=‘relu‘))
    model.add(Dense(num_classes, kernel_initializer=‘normal‘, activation=‘softmax‘))
    # Compile model
    model.compile(loss=‘categorical_crossentropy‘, optimizer=‘adam‘, metrics=[‘accuracy‘])
    return model
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

模型的隐含层含有784个节点,接受的输入长度也是784(28*28),最后用softmax函数将预测结果转换为标签的概率值。
将训练数据fit到模型,设置了迭代轮数,每轮200个训练样本,将测试集作为验证集,并查看训练的效果。

# build the model
model = baseline_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

训练和测试结果如下:

Train on 60000 samples, validate on 10000 samples
Epoch 1/10
6s - loss: 0.2789 - acc: 0.9210 - val_loss: 0.1416 - val_acc: 0.9578
Epoch 2/10
5s - loss: 0.1117 - acc: 0.9677 - val_loss: 0.0917 - val_acc: 0.9707
Epoch 3/10
5s - loss: 0.0717 - acc: 0.9796 - val_loss: 0.0787 - val_acc: 0.9767
Epoch 4/10
6s - loss: 0.0502 - acc: 0.9859 - val_loss: 0.0741 - val_acc: 0.9767
Epoch 5/10
5s - loss: 0.0372 - acc: 0.9890 - val_loss: 0.0681 - val_acc: 0.9788
Epoch 6/10
5s - loss: 0.0269 - acc: 0.9925 - val_loss: 0.0625 - val_acc: 0.9808
Epoch 7/10
5s - loss: 0.0208 - acc: 0.9948 - val_loss: 0.0619 - val_acc: 0.9814
Epoch 8/10
6s - loss: 0.0140 - acc: 0.9970 - val_loss: 0.0639 - val_acc: 0.9799
Epoch 9/10
5s - loss: 0.0108 - acc: 0.9978 - val_loss: 0.0597 - val_acc: 0.9812
Epoch 10/10
5s - loss: 0.0080 - acc: 0.9985 - val_loss: 0.0591 - val_acc: 0.9813
Baseline Error: 1.87%

简单的卷积神经网络

前面介绍了如何加载训练数据并实现一个简单的单隐层神经网络,并在测试集上取得了不错的效果。现在要实现一个卷积神经网络,想要在MNIST问题上取得更好的效果。

卷积神经网络(CNN)是一种深度神经网络,与单隐层的神经网络不同的是它还包含卷积层、池化层、Dropout层等,这使得它在图像分类的问题上有更优的效果。详细的CNN教程可以参见斯坦福大学的cs231n课程讲义,中文版链接

第一步依然是导入需要的函数库

import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
K.set_image_dim_ordering(‘th‘)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

设定随机数种子

seed = 7
numpy.random.seed(seed)
  • 1
  • 2
  • 1
  • 2

将数据集reshape,CNN的输入是4维的张量(可看做多维的向量),第一维是样本规模,第二维是像素通道,第三维和第四维是长度和宽度。并将数值归一化和类别标签向量化。

# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# reshape to be [samples][pixels][width][height]
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype(‘float32‘)
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype(‘float32‘)

X_train = X_train / 255
X_test = X_test / 255
# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

接下来构造CNN。

  1. 第一层是卷积层。该层有32个feature map,或者叫滤波器,作为模型的输入层,接受[pixels][width][height]大小的输入数据。feature map的大小是5*5,其输出接一个‘relu’激活函数。
  2. 下一层是pooling层,使用了MaxPooling,大小为2*2。
  3. 下一层是Dropout层,该层的作用相当于对参数进行正则化来防止模型过拟合。
  4. 接下来是全连接层,有128个神经元,激活函数采用‘relu’。
  5. 最后一层是输出层,有10个神经元,每个神经元对应一个类别,输出值表示样本属于该类别的概率大小。
def baseline_model():
    # create model
    model = Sequential()
    model.add(Conv2D(32, (5, 5), input_shape=(1, 28, 28), activation=‘relu‘))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.2))
    model.add(Flatten())
    model.add(Dense(128, activation=‘relu‘))
    model.add(Dense(num_classes, activation=‘softmax‘))
    # Compile model
    model.compile(loss=‘categorical_crossentropy‘, optimizer=‘adam‘, metrics=[‘accuracy‘])
    return model
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

接着开始训练模型

# build the model
model = baseline_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

训练和测试结果如下:

Train on 60000 samples, validate on 10000 samples
Epoch 1/10
137s - loss: 0.2329 - acc: 0.9340 - val_loss: 0.0820 - val_acc: 0.9742
Epoch 2/10
140s - loss: 0.0736 - acc: 0.9781 - val_loss: 0.0466 - val_acc: 0.9842
Epoch 3/10
138s - loss: 0.0531 - acc: 0.9839 - val_loss: 0.0432 - val_acc: 0.9860
Epoch 4/10
145s - loss: 0.0404 - acc: 0.9876 - val_loss: 0.0389 - val_acc: 0.9872
Epoch 5/10
135s - loss: 0.0335 - acc: 0.9893 - val_loss: 0.0341 - val_acc: 0.9886
Epoch 6/10
133s - loss: 0.0275 - acc: 0.9915 - val_loss: 0.0308 - val_acc: 0.9893
Epoch 7/10
133s - loss: 0.0233 - acc: 0.9926 - val_loss: 0.0363 - val_acc: 0.9880
Epoch 8/10
137s - loss: 0.0204 - acc: 0.9937 - val_loss: 0.0320 - val_acc: 0.9889
Epoch 9/10
139s - loss: 0.0167 - acc: 0.9945 - val_loss: 0.0294 - val_acc: 0.9893
Epoch 10/10
139s - loss: 0.0143 - acc: 0.9957 - val_loss: 0.0310 - val_acc: 0.9907
Baseline Error: 0.93%

可以看出相对于单隐层神经网络,CNN的效果有很大提升,error rate 从1.87%降到了0.93%。

上面实现了一个只含有一层卷积层和pooling层的CNN,为了实现更好的分类效果,可以添加多层的Convolution2D和MaxPooling2D,CNN会自动提取特征,学习到更好的分类效果。

















































以上是关于图像识别 基于Keras的手写数字识别(含代码)的主要内容,如果未能解决你的问题,请参考以下文章

使用Keras训练Lenet网络来进行手写数字识别

手写数字识别基于matlab GUI知识库手写数字识别(写字板+图片)含Matlab源码 1227期

手写数字识别基于matlab GUI BP神经网络手写数字识别系统含Matlab源码 1639期

手写数字识别基于matlab GUI BP神经网络单个或连续手写数字识别系统含Matlab源码 2296期

手写数字识别基于matlab GUI BP神经网络单个或连续手写数字识别系统含Matlab源码 2296期

keras入门实战:手写数字识别