手写数字识别 Digit Recognizer

在这次Machine Learning中,我做一个比较经典的手写数字识别的一个项目,巩固一下自己所学的知识,也带领大家进入神经网络的时代,神经网络可以在这个分类任务上大展身手,万物皆可卷积。

如果想了解更多的知识,可以去我的机器学习之路 The Road To Machine Learning通道

目录

  • OverView 项目概述
  • Data Description 数据描述
  • 1. Introduction 项目介绍
  • 2. Data preparation 数据预处理
    • 2.1 Load data 加载数据
    • 2.2 Check for null and missing values 缺失值处理
    • 2.3 Normalization 标准化处理
    • 2.4 Reshape 重塑
    • 2.5 Label encoding 标签编码
    • 2.6 Split training and valdiation set 拆分训练和验证集
  • 3. CNN 卷积神经网络
    • 3.1 Define the model 定义模型
    • 3.2 Set the optimizer and annealer 设置优化器和退火器
    • 3.3 Data augmentation 数据增强
  • 4. Evaluate the model 评估模型
    • 4.1 Training and validation curves 训练和验证集的学习曲线
    • 4.2 Confusion matrix 混淆矩阵
  • 5. Prediction and submition 预测和提交
    • 5.1 Predict and Submit results 预测并提交结果

OverView 项目概述

首先我们就来看看这个识别任务的简单介绍吧

MNIST (“Modified National Institute of Standards and Technology”) is the de facto “hello world” dataset of computer vision. Since its release in 1999, this classic dataset of handwritten images has served as the basis for benchmarking classification algorithms. As new machine learning techniques emerge, MNIST remains a reliable resource for researchers and learners alike.

In this competition, your goal is to correctly identify digits from a dataset of tens of thousands of handwritten images. We’ve curated a set of tutorial-style kernels which cover everything from regression to neural networks. We encourage you to experiment with different algorithms to learn first-hand what works well and how techniques compare.

MNIST (Modified National Institute of Standards and Technology)实际上是计算机视觉的“hello world”数据集。自从1999年发布以来,这个经典的手写图像数据集一直是分类算法的基准。随着新的机器学习技术的出现,MNIST仍然是研究人员和学习者的可靠资源。
在这场比赛中,您的目标是从数万张手写图像的数据集中正确识别数字。我们策划了一套教程风格的内核,涵盖了从回归到神经网络的所有内容。我们鼓励您使用不同的算法进行实验,以第一手了解哪些算法更有效以及如何比较技术。

Data Description 数据描述

MNIST 包括6万张28x28的训练样本,1万张测试样本,很多教程都会对它”下手”几乎成为一个 “典范”,可以说它就是计算机视觉里面的Hello World。所以我们这里也会使用MNIST来进行实战。
在卷积神经网络中,首先出现了一个很强大的LeNet-5,LeNet-5之所以强大就是因为在当时的环境下将MNIST数据的识别率提高到了99%,这里我们也自己从头搭建一个卷积神经网络,也达到99%的准确率

1. Introduction 项目介绍

This Notebook follows three main parts:

  • The data preparation
  • The CNN modeling and evaluation
  • The results prediction and submission
    305 / 5000

这是一个 5 层顺序卷积神经网络,用于在 MNIST 数据集上训练的数字识别。 我选择使用非常直观的 keras API(Tensorflow 后端)来构建它。 首先,我将准备数据(手写数字图像),然后我将专注于 CNN 建模和评估。

我在单个 GPU (i7 1050Ti) 上用 训练的 CNN 达到了 99.4%的准确率。 对于那些拥有多核 GPU 能力的人,您可以将 tensorflow-gpu 与 keras 结合使用。 计算速度会快很多!!!

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from keras.utils.np_utils import to_categorical # convert to one-hot-encoding
from sklearn.model_selection import train_test_split
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D
from keras.optimizers import RMSprop
%matplotlib inline

2. Data preparation 数据预处理

2.1 Load data 加载数据

# Load the data
train = pd.read_csv('data/train.csv')
test = pd.read_csv('data/test.csv')

我们可以查看一下数据的分布和类型等

train.info()



我们可以看到,数据中有标签label和784(28*28)个pixel,也就是我们的像素值

Y_train = train['label'] X_train = train.drop('label',axis=1)sns.countplot(y_train)
y_train.value_counts()

1 4684
7 4401
3 4351
9 4188
2 4177
6 4137
0 4132
4 4072
8 4063
5 3795
Name: label, dtype: int64

We have similar counts for the 10 digits.

我们差不多有十个标签,数目差不多,就是0-9,我们的数字标签

2.2 Check for null and missing values 缺失值处理

# Check the data
X_train.isnull().any().describe()

count 784
unique 1
top False
freq 784
dtype: object

test.isnull().any().describe()

count 784
unique 1
top False
freq 784
dtype: object

There is no missing values in the train and test dataset. So we can safely go ahead
训练和测试数据集中没有缺失值。 所以我们可以放心地继续前进

2.3 Normalization 标准化处理

我们实现灰度归一化以减少光照差异的影响,也就是标准化。

此外,CNN 在 [0…1] 数据上的收敛速度比在 [0…255] 上更快

# Normalize the data
X_train = X_train / 255.0
test = test / 255.0

2.4 Reshape 重塑

# Reshape image in 3 dimensions (height = 28px, width = 28px , canal = 1)
# 也就是将 784 像素的向量重塑为 28x28x3 的 3D 矩阵。
X_train = X_train.values.reshape(-1,28,28,1)
test = test.values.reshape(-1,28,28,1)

训练和测试图像 (28px x 28px) 已作为 784 个值的一维向量存入 pandas.Dataframe。 我们将所有数据重塑为 28x28x1 3D 矩阵。

Keras 最后需要一个与通道相对应的额外维度。 MNIST 图像是灰度化的,所以它只使用一个通道。 对于 RGB 图像,有 3 个通道,我们会将 784 像素的向量重塑为 28x28x3 的 3D 矩阵。

2.5 Label encoding 标签编码

我们利用我们one-hot编码的原理来对我们的标签进行编码

# Encode labels to one hot vectors (ex : 2 -> [0,0,1,0,0,0,0,0,0,0])
y_train = to_categorical(y_train, num_classes = 10)

Labels are 10 digits numbers from 0 to 9. We need to encode these lables to one hot vectors (ex : 2 -> [0,0,1,0,0,0,0,0,0,0]).

标签是从 0 到 9 的 10 位数字。我们需要将标签编码为一个one-hot 向量(例如:2 -> [0,0,1,0,0,0,0,0,0,0])

2.6 Split training and valdiation set 拆分训练和验证集

设置随机种子

# Set the random seed
random_seed = 2

拆分为训练集和验证集进行一个训练

# Split the train and the validation set for the fitting
X_train, X_val, Y_train, Y_val = train_test_split(X_train, y_train, test_size = 0.1, random_state=random_seed)

I choosed to split the train set in two parts : a small fraction (10%) became the validation set which the model is evaluated and the rest (90%) is used to train the model.

Since we have 42 000 training images of balanced labels (see 2.1 Load data), a random split of the train set doesn’t cause some labels to be over represented in the validation set. Be carefull with some unbalanced dataset a simple random split could cause inaccurate evaluation during the validation.

我选择将训练集分成两部分:一小部分 (10%) 成为评估模型的验证集,其余 (90%) 用于训练模型。

由于我们有 42 000 张平衡标签的训练图像(参见 2.1 加载数据),训练集的随机拆分不会导致某些标签在验证集中过度表示。 小心一些不平衡的数据集,简单的随机拆分可能会导致验证过程中的评估不准确。

We can get a better sense for one of these examples by visualising the image and looking at the label.
我们可以可视化一下我们的图片

plt.imshow(X_train[0][:,:,0])

3. CNN 卷积神经网络

3.1 Define the model 定义模型

我使用了 Keras Sequential API,您只需从输入开始,一次添加一层。

第一个是卷积(Conv2D)层。它就像一组可学习的过滤器。我选择为前两个 conv2D 层设置 32 个过滤器,为最后两个层设置 64 个过滤器。每个过滤器使用内核过滤器转换图像的一部分(由内核大小定义)。内核滤波器矩阵应用于整个图像。过滤器可以看作是图像的一种变换。

CNN 可以从这些转换后的图像(特征图)中分离出处处有用的特征。

CNN 中的第二个重要层是池化 (MaxPool2D) 层。该层仅充当下采样滤波器。它查看 2 个相邻像素并选择最大值。这些用于降低计算成本,并在一定程度上减少过拟合。我们必须选择池化大小(即每次池化的区域大小),池化维度越高,下采样越重要。

结合卷积层和池化层,CNN 能够结合局部特征并学习图像的更多全局特征。

Dropout 是一种正则化方法,对于每个训练样本,层中一定比例的节点被随机忽略(将它们的权重设置为零)。这会随机丢弃网络的一部分,并强制网络以分布式方式学习特征。这种技术还提高了泛化能力并减少了过拟合。

‘relu’ 是激活函数 max(0,x)。激活函数用于为网络添加非线性。

Flatten 层用于将最终的特征图转换为一个单一的一维向量。 需要此展平步骤,以便您可以在一些卷积/最大池层之后使用完全连接的层。 它结合了先前卷积层的所有找到的局部特征。

最后,我使用了两个完全连接(密集)层中的特征,这只是人工神经网络(ANN)分类器。 在最后一层 (Dense(10,activation=“softmax”)) 中,每个类别的概率的净输出分布。

# Set the CNN model
# my CNN architechture is In -> [[Conv2D->relu]*2 -> MaxPool2D -> Dropout]*2 -> Flatten -> Dense -> Dropout -> Outmodel = Sequential()model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu', input_shape = (28,28,1)))
model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Dropout(0.25))model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu'))
model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu'))
model.add(MaxPool2D(pool_size=(2,2), strides=(2,2)))
model.add(Dropout(0.25))model.add(Flatten())
model.add(Dense(256, activation = "relu"))
model.add(Dropout(0.5))
model.add(Dense(10, activation = "softmax"))

3.2 Set the optimizer and annealer 设置优化器和退火器

一旦我们的层被添加到模型中,我们需要设置一个评分函数、一个损失函数和一个优化算法。

我们定义了损失函数来衡量我们的模型在具有已知标签的图像上的表现有多差。它是观察到的标签和预测的标签之间的错误率。我们使用称为“categorical_crossentropy”的分类分类(> 2 个类别)的特定形式。

最重要的功能是优化器。该函数将迭代地改进参数(过滤核值、神经元的权重和偏差…)以最小化损失。

我选择了 RMSprop(带有默认值),它是一个非常有效的优化器。 RMSProp 更新以非常简单的方式调整 Adagrad 方法,以尝试降低其激进的、单调递减的学习率。我们也可以使用随机梯度下降 (‘SGD’) 优化器,但它比 RMSprop 慢。

度量函数“准确度”用于评估我们模型的性能。该度量函数类似于损失函数,不同之处在于在训练模型时不使用度量​​评估的结果(仅用于评估)。

# Define the optimizer
optimizer = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)
# Compile the model
model.compile(optimizer = optimizer , loss = "categorical_crossentropy", metrics=["accuracy"])

为了使优化器收敛得更快并且最接近损失函数的全局最小值,我使用了学习率(LR)的退火方法。

LR 是优化器遍历“损失情况”的步骤。 LR越高,步长越大,收敛越快。 然而,高 LR 的采样非常差,优化器可能会陷入局部最小值。

最好在训练期间降低学习率,以有效地达到损失函数的全局最小值。

为了保持具有高 LR 的快速计算时间的优势,我根据是否有必要(当精度未提高时)每 X 步(时期)动态地减少 LR。

使用 Keras.callbacks 的 ReduceLROnPlateau 函数,如果 3 个 epoch 后精度没有提高,我选择将 LR 减少一半。

# Set a learning rate annealer
learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', patience=3, verbose=1, factor=0.5, min_lr=0.00001)
epochs = 30
batch_size = 86

3.3 Data augmentation 数据增强

为了避免过拟合问题,我们需要人为地扩展我们的手写数字数据集。我们可以使您现有的数据集更大。这个想法是通过小的转换来改变训练数据,以重现有人写数字时发生的变化。

比如数字不居中 比例不一样(有的写大/小数字) 图像旋转…

以改变数组表示同时保持标签不变的方式改变训练数据的方法被称为数据增强技术。人们使用的一些流行的增强是灰度、水平翻转、垂直翻转、随机裁剪、颜色抖动、平移、旋转等等。

通过对我们的训练数据应用这些转换中的几个,我们可以轻松地将训练示例的数量增加一倍或三倍,并创建一个非常强大的模型。

# With data augmentation to prevent overfitting (accuracy 0.99286)datagen = ImageDataGenerator(featurewise_center=False,  # set input mean to 0 over the datasetsamplewise_center=False,  # set each sample mean to 0featurewise_std_normalization=False,  # divide inputs by std of the datasetsamplewise_std_normalization=False,  # divide each input by its stdzca_whitening=False,  # apply ZCA whiteningrotation_range=10,  # randomly rotate images in the range (degrees, 0 to 180)zoom_range = 0.1, # Randomly zoom image width_shift_range=0.1,  # randomly shift images horizontally (fraction of total width)height_shift_range=0.1,  # randomly shift images vertically (fraction of total height)horizontal_flip=False,  # randomly flip imagesvertical_flip=False)  # randomly flip imagesdatagen.fit(X_train)

对于数据增强,我选择:

  • 将一些训练图像随机旋转 10 度
  • 将一些训练图像随机放大 10%
  • 将图像水平随机移动 10% 的宽度
  • 将图像垂直随机移动 10% 的高度

我没有应用vertical_flip 或horizontal_flip,因为它可能导致错误分类对称数,例如6 和9。
一旦我们的模型准备就绪,我们就会拟合训练数据集。

# Fit the model
history = model.fit_generator(datagen.flow(X_train,Y_train, batch_size=batch_size),epochs = epochs, validation_data = (X_val,Y_val),verbose = 2, steps_per_epoch=X_train.shape[0] // batch_size, callbacks=[learning_rate_reduction])

4. Evaluate the model 评估模型

4.1 Training and validation curves 训练和验证集的学习曲线

# Plot the loss and accuracy curves for training and validation
fig, ax = plt.subplots(2,1)
ax[0].plot(history.history['loss'], color='b', label="Training loss")
ax[0].plot(history.history['val_loss'], color='r', label="validation loss",axes =ax[0])
legend = ax[0].legend(loc='best', shadow=True)ax[1].plot(history.history['acc'], color='b', label="Training accuracy")
ax[1].plot(history.history['val_acc'], color='r',label="Validation accuracy")
legend = ax[1].legend(loc='best', shadow=True)

4.2 Confusion matrix 混淆矩阵

混淆矩阵对于查看我们的模型缺点非常有帮助。
我绘制了验证结果的混淆矩阵。

# Look at confusion matrix def plot_confusion_matrix(cm, classes,normalize=False,title='Confusion matrix',cmap=plt.cm.Blues):"""This function prints and plots the confusion matrix.Normalization can be applied by setting `normalize=True`."""plt.imshow(cm, interpolation='nearest', cmap=cmap)plt.title(title)plt.colorbar()tick_marks = np.arange(len(classes))plt.xticks(tick_marks, classes, rotation=45)plt.yticks(tick_marks, classes)if normalize:cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]thresh = cm.max() / 2.for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):plt.text(j, i, cm[i, j],horizontalalignment="center",color="white" if cm[i, j] > thresh else "black")plt.tight_layout()plt.ylabel('True label')plt.xlabel('Predicted label')# Predict the values from the validation dataset
Y_pred = model.predict(X_val)
# Convert predictions classes to one hot vectors
Y_pred_classes = np.argmax(Y_pred,axis = 1)
# Convert validation observations to one hot vectors
Y_true = np.argmax(Y_val,axis = 1)
# compute the confusion matrix
confusion_mtx = confusion_matrix(Y_true, Y_pred_classes)
# plot the confusion matrix
plot_confusion_matrix(confusion_mtx, classes = range(10))


在这里我们可以看到,考虑到验证集的大小(4 200 张图像),我们的 CNN 在所有数字上都表现得非常好,几乎没有错误。

然而,我们的 CNN 似乎对 4 位数字有一些小问题,嘿嘿被误分类为 9。有时在曲线平滑时很难捕捉 4 和 9 之间的差异。

# Display some error results # Errors are difference between predicted labels and true labels
errors = (Y_pred_classes - Y_true != 0)Y_pred_classes_errors = Y_pred_classes[errors]
Y_pred_errors = Y_pred[errors]
Y_true_errors = Y_true[errors]
X_val_errors = X_val[errors]def display_errors(errors_index,img_errors,pred_errors, obs_errors):""" This function shows 6 images with their predicted and real labels"""n = 0nrows = 2ncols = 3fig, ax = plt.subplots(nrows,ncols,sharex=True,sharey=True)for row in range(nrows):for col in range(ncols):error = errors_index[n]ax[row,col].imshow((img_errors[error]).reshape((28,28)))ax[row,col].set_title("Predicted label :{}\nTrue label :{}".format(pred_errors[error],obs_errors[error]))n += 1# Probabilities of the wrong predicted numbers
Y_pred_errors_prob = np.max(Y_pred_errors,axis = 1)# Predicted probabilities of the true values in the error set
true_prob_errors = np.diagonal(np.take(Y_pred_errors, Y_true_errors, axis=1))# Difference between the probability of the predicted label and the true label
delta_pred_true_errors = Y_pred_errors_prob - true_prob_errors# Sorted list of the delta prob errors
sorted_dela_errors = np.argsort(delta_pred_true_errors)# Top 6 errors
most_important_errors = sorted_dela_errors[-6:]# Show the top 6 errors
display_errors(most_important_errors, X_val_errors, Y_pred_classes_errors, Y_true_errors)


最重要的错误也是最有趣的。

对于这六个案例,该模型并不可笑。 其中一些错误也可能是人类造成的,尤其是对于非常接近 4 的 9。最后一个 9 也非常具有误导性,对我来说似乎是 0

5. Prediction and submition 预测和提交

5.1 Predict and Submit results 预测并提交结果

# predict results
results = model.predict(test)# select the indix with the maximum probability
results = np.argmax(results,axis = 1)results = pd.Series(results,name="Label")
submission = pd.concat([pd.Series(range(1,28001),name = "ImageId"),results],axis = 1)submission.to_csv("cnn_mnist_datagen.csv",index=False)

手写数字识别 Digit Recognizer相关推荐

  1. Kaggle入门预测赛,手写数字识别Digit Recognizer,使用Kaggle kernel作答,F=0.98

    1.问题和描述 直接在kaggle左边的competition竞赛中搜索Digit Recognizer即可进入赛题页面: https://www.kaggle.com/c/digit-recogni ...

  2. [Kaggle] Digit Recognizer 手写数字识别(卷积神经网络)

    文章目录 1. 使用 LeNet 预测 1.1 导入包 1.2 建立 LeNet 模型 1.3 读入数据 1.4 定义模型 1.5 训练 1.6 绘制训练曲线 1.7 预测提交 2. 使用 VGG16 ...

  3. [Kaggle] Digit Recognizer 手写数字识别(神经网络)

    文章目录 1. baseline 2. 改进 2.1 增加训练时间 2.2 更改网络结构 Digit Recognizer 练习地址 相关博文: [Hands On ML] 3. 分类(MNIST手写 ...

  4. Kaggle手写数字识别(Digit Recognizer)记录

    竞赛地址 https://www.kaggle.com/c/digit-recognizer 苦于学了cs231n和pytorch之后没有东西拿来练手,就去kaggle上找了一个入门竞赛,MNIST手 ...

  5. python手写多个字母识别_一个带界面的CNN手写数字识别,使用Python(tensorflow, kivy)实现...

    CNN_Handwritten_Digit_Recognizer (CNN手写数字识别) A CNN handwritten digit recognizer with graphical UI, i ...

  6. FlyAi实战之MNIST手写数字识别练习赛(准确率99.55%)

    欢迎关注WX公众号:[程序员管小亮] 文章目录 欢迎关注WX公众号:[程序员管小亮] 一.介绍 二.代码实现 1_数据加载 2_归一化 3_定义网络结构 4_设置优化器和退火函数 5_数据增强 6_拟 ...

  7. BP神经网络实现手写数字识别Python实现,带GUI手写画板

    BP神经网络实现手写数字识别 BP神经网络模型 用tkinter编写用于手写输入的画板 程序运行的效果截图 在B站看了一个机器学习基础的视频( 链接)后,发现到资料里面有一个用BP神经网络对手写数字进 ...

  8. 使用Caffe进行手写数字识别执行流程解析

    之前在 http://blog.csdn.net/fengbingchun/article/details/50987185 中仿照Caffe中的examples实现对手写数字进行识别,这里详细介绍下 ...

  9. Java软件研发工程师转行之深度学习(Deep Learning)进阶:手写数字识别+人脸识别+图像中物体分类+视频分类+图像与文字特征+猫狗分类

    本文适合于对机器学习和数据挖掘有所了解,想深入研究深度学习的读者 1.对概率基本概率有所了解 2.具有微积分和线性代数的基本知识 3.有一定的编程基础(Python) Java软件研发工程师转行之深度 ...

最新文章

  1. R构建径向核支持向量机分类器实战代码(Radial kernel Support Vector Classifier)
  2. Linux中的echo简介(自我总结)(44)
  3. Python基础(14)_python模块之configparser模块、suprocess
  4. pandas中合并数据集
  5. 南加州大学机器视觉实验室_机器学习带动南加州爱迪生的变革
  6. vsCode ext install 不工作
  7. 欢乐纪中某B组赛【2019.1.26】
  8. linux u盘 uid pid,linux下的pid文件的作用
  9. android keyevent.java,dispatchKeyEvent简单理解
  10. springboot项目实例_Springboot项目的接口防刷的实例
  11. android 查看系统字体大小,Android 如何获取系统字体大小
  12. php变量控制结构与函数,LAMP兄弟连原创视频教程(PHP笔记一--变量,流程控制结构,函数)...
  13. Backlog Order
  14. Micheal Jackson 离开了我们
  15. 高瓴资本张磊:选择比努力重要,与谁同行比要去的远方重要
  16. 【C语言详解】——文件操作(建议收藏)
  17. 银河系的神秘信号:也许我们正见证真实的科幻故事
  18. 主流的大数据BI软件有哪些?
  19. office word 自动生成目录 以及多级列表级别的设置
  20. 分步傅里叶算法_快速分步傅里叶算法,split-step fast Fourier transform,音标,读音,翻译,英文例句,英语词典...

热门文章

  1. 安装.NET Framework 3.5 SP1 超慢的解决办法
  2. 学习利用ReportLab生成PDF报表 -- RML基础(The Basics)
  3. 光学放大倍率(β,Magnification)
  4. ESP8266 Non-OS SDK 开发之旅 基础篇① 初识 Non-OS SDK,史上超级详细手把手教小白20分钟快速搭建SDK软件开发环境,完成第一个例子Hello World!
  5. Linux系统编程37:多线程之什么是临界区和临界资源以及如何使用mutex互斥锁
  6. 为什么在计算机系统中,数值一律用补码来表示(存储)
  7. 菜市场摆摊转行程序员,被嘲笑.........
  8. 【VQ-VAE论文精读+代码实战】Neural Discrete Representation Learning
  9. 博睿数据入选首批欧拉技术测评方案,为欧拉生态开发者应用体验保驾护航
  10. 【Dia】如何解决dia无法输入中文