用Keras构建卷积神经网络识别“自己”的手写字教程

教程目录

1、建模型篇:模型训练与评估

1.0、导入所需的依赖包与框架

1.1、如何对数据做预处理

1.2、如何训练模型

1.3、如何评估模型

2、用模型篇:使用模型识别输入的手写字体

2.1、尝试识别在便笺上写的数字

2.2、尝试识别白纸作为背景的手写数字

2.3、尝试识别手写字体网站截取的手写数字

2.4、尝试识别在Atlas OS笔记功能里手写的数字

附录

附录1. 使用达仁云主机的具体操作流程

1.1、创建虚拟硬盘

1.2、选择公共镜像

1.3、启动GPU实例

1.4、启动JupyterLab

1.5、登陆JupyterLab

1.6、从终端配置环境

1.7、使用Jupyter Notebook

1.8、关闭或暂停云主机

附录2. 使用达仁云笔记的具体操作流程

2.1、创建笔记本

2.2、绘制手写字体

参考


使用的编程语言:Python。

使用的依赖包/框架:TensorFlow,Keras。

使用的模型/方法:卷积神经网络(Convolutional Neural Network,即CNN)。

使用的数据集:MNIST数据集--28x28像素的灰度手写数字图片--包括60000个训练样本和10000个测试样本(该MNIST数据集为事先处理好的“一个数字一张图”的标准数据集,背景为纯黑色、即byte值为0,数字笔划为白色,即笔划的最高值为255)。另有自行上传的手写字体图片约共30个。

解决的问题/实现的功能:

  1. 基于MNIST数据集,训练一个能识别手写阿拉伯数字的模型,即能够将输入的手写数字的图和对应的阿拉伯数字进行匹配(识别)。
  2. 用户将自己创建的手写数字作为一个图片、上传至训练好的模型中做预测,让模型识别出对应的数字。

建议使用的IDE:JupyterLab

大概实际操作时间:1~2小时

推荐使用的平台:达仁云主机【Linux + JupyterLab】公共镜像

教程涉及的数据、Python代码、对应结果、以及重现整个教程可能会需要使用到的达仁云主机的操作过程,都在本文的正文和附录中全部提供,并可以在https://gitee.com/diagnoa/public/tree/master/tutorial/CNN-general-tutorial-01下载到。

用Keras构建卷积神经网络识别“自己”的手写字教程

图1:达仁云主机示图

1、建模型篇:模型训练与评估

1.0、导入所需的依赖包与框架

# 在程序的开始,导入待使用的包

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.optimizers import Adam

from keras.utils import np_utils

from PIL import Image

import numpy as np

import os

from tensorflow import keras

import cv2

import matplotlib.pyplot as plt

一些同学可能也想了解如何安装这个教程所需的GPU驱动,以及如何使用我们推荐的平台环境“达仁云主机”来完成这个教程。为此,我们在“附录1”中提供了详细的说明。

注:对于第一次试用CNN、TensorFlow或Keras的同学,我们推荐使用“达仁云主机”来完成本教程。使用类似于“达仁云主机”这样的产品可以大大降低同学们一开始上手的难度。虽然同样是采用云上租用虚拟机的方式使用,“达仁云主机”的特殊之处在于是“立即可用”的“预设+托管”型云主机(managed cloud PC):“达仁云主机”是预先安装好基础软件(例如这里会用到的JupyterLab)、配置好软件和网络设置(例如立即可以在浏览器里直接登录访问这个云主机上的JupyterLab)、并且“自动化+智能”处理好镜像存储和数据持久化等一些云主机的常见问题。

“达仁云主机”其实就是把平时需要“看懂一整本教程书”以后才能用起来的“云主机”的那些复杂的设置和维护“智能化/傻瓜化”,让用户仅需点击几个按钮,就能在浏览器里直接启动一台“立即能用”的云主机。

特别方便的是“达仁云主机”通过一个普通浏览器即可访问,不需要安装任何软件或购买任何硬件。云主机启动后是按秒计费,停机就立刻停止计费,没有“包月”的门槛,“省心省钱”。“达仁云主机”更有百余种云主机配置可选,其中就包括很多款适合做CNN机器学习使用的、带GPU卡的云主机类型。

这些特色就让很多因为没有预算(适合做AI的GPU卡现在可是几千元甚至上万元一张)、或者被各种云计算教科书“望而却步”过的同学能够“省心省事”地立即开始用上合适的AI学习环境。

注意,这里的这个“达仁云主机”开发环境和背后的云主机计算资源,是真正的可以做开发、做项目的“实战”级环境,可不是一些常见的“只能做作业”的“假”的模拟开发环境哦。

1.1、如何对数据做预处理

# 加载数据

# 注意:一般模型训练需要区分训练数据(train)和测试数据(test),测试数据不可以在训练过程中使用,以便在训练过程结束以后,能够用测试数据来评估所训练的模型的性能。

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

# 将输入数据reshape成CNN期望的格式(也就是将图像数据转成神经网络能识别的数组数据)

X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], X_train.shape[2], 1).astype('float32')

X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], X_test.shape[2], 1).astype('float32')

# 将输入数据归一化

# 注意1:一般CNN数据的归一化(Normalization)是将数据转化到[0, 1]这个区间里(把数值变小一些)。因为如果输入数据里的数据值过大(例如几百或上万),将会造成模型训练时的时间过长、轮数过多(造成这个现象的一个原因:一些小的初始化系数项需要经过很多轮的训练才能“适应”包含“大数值”的变量项),而且很有可能会导致训练失败。所以一般所有的机器学习前,都需要对数据进行预处理,例如归一化或标准化。

# 注意2:数据的归一化和标准化(Standardization)和中心化(Centering)是三种不同(但联系紧密)的操作。此处使用的是归一化。对于基本符合正态分布的数据,建议使用标准化的预处理。

X_train /= 255

X_test /= 255

# 将输出数据类别变为one hot编码 (one hot encoding)

# 为什么这里要做one hot编码呢?因为神经网络无法识别常规的分类变量(categorical data)。感兴趣的同学可以在这里看一看做one hot编码的详细背景和原因:https://machinelearningmastery.com/why-one-hot-encode-data-in-machine-learning/。

number_of_classes = 10

y_train = np_utils.to_categorical(y_train, number_of_classes)

y_test = np_utils.to_categorical(y_test, number_of_classes)

1.2、如何训练模型

# 创建模型

# 创建模型有时候可以说一种“艺术”,因为模型的选择,例如各个层的参数选择多种多样,而模型中层与层之间的关系更是可以“千奇百怪”,这里仅仅提供了一种常见的适合于MNIST数据的网络。感兴趣的同学们可以阅读Keras和PyTorch文档里关于网络中不同层的各种类型的作用和其配置参数影响的介绍,创建自己的网络结构,来试一试:

# https://keras.io/api/layers/convolution_layers/

# https://pytorch.org/docs/stable/nn.html#convolution-layers

# 注:给一个“模型”尝试不同结构和不同参数(即常常提到的一个模型的“超参数”,hyperparameter)设置,找到最优化的模型超参数,往往需要尝试成千上万种潜在的模型结构和配置,这也是为什么在机器学习实战中,模型的创建和优化是如此的消耗资源(在成千上万个机器节点上跑不同的模型,或者在一个机器上跑成千上万个不同的模型)。

num_classes = 10 # 代表0-9共10个数字,10种类别。

input_shape = (28, 28, 1) # 输入数据shape为28x28x1。

model = Sequential(

[

keras.Input(shape=input_shape), # 定义输入层,设置输入层为与训练数据相同的维度。

Conv2D(32, kernel_size=(3, 3), activation="relu"), # 定义卷积层网络,本层需要学习32个卷积核,卷积核大小为3x3。激活函数为Relu。

MaxPooling2D(pool_size=(2, 2)), # 叠加池化层,池化窗口形状为2×2的最大池化。

Conv2D(64, kernel_size=(3, 3), activation="relu"), # 叠加卷积层网络。

MaxPooling2D(pool_size=(2, 2)), # 叠加池化层。

Flatten(), # 将输入“压平”,即把多维的输入一维化,常用在从卷积层到全连接层的过渡。

Dropout(0.5),# Dropout将在训练过程中每次更新参数时按一定概率(0.5)随机断开输入神经元,可防止过拟合。

Dense(num_classes, activation="softmax"),# 全连接层,输出层,激活函数为softmax。

]

)

# 打印模型信息

model.summary()

运行上述代码,输出结果为:

Model: "sequential"

_________________________________________________________________

Layer (type) Output Shape Param #

=================================================================

conv2d (Conv2D) (None, 26, 26, 32) 320

_________________________________________________________________

max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0

_________________________________________________________________

conv2d_1 (Conv2D) (None, 11, 11, 64) 18496

_________________________________________________________________

max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0

_________________________________________________________________

flatten (Flatten) (None, 1600) 0

_________________________________________________________________

dropout (Dropout) (None, 1600) 0

_________________________________________________________________

dense (Dense) (None, 10) 16010

=================================================================

Total params: 34,826

Trainable params: 34,826

Non-trainable params: 0

___________________________________________________________

上述结果打印了模型的相关信息:从左至右依次为网络每一层的信息、每一层的输出结果的样式、每一层的参数个数。打印这些信息可以帮助我们更直观地了解所构建模型的结构。

# 训练模型

# 注:一般训练模型是最消耗时间的步骤,这里可能会需要等一段时间

batch_size = 128 # 设置batch size

epochs = 15 # 设置epoch。

model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])

# 模型的loss选择categorical_crossentropy, 优化器选择adam,metrics选择accuracy。

model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1) # 用训练数据训练模型,并按照0.1的比例抽取数据进行validation。

运行上述代码,输出结果省略中间部分,展示如下:

Epoch 1/15

422/422 [==============================] - 6s 14ms/step - loss: 0.3649 - accuracy: 0.8872 - val_loss: 0.0844 - val_accuracy: 0.9782

Epoch 2/15

422/422 [==============================] - 2s 4ms/step - loss: 0.1099 - accuracy: 0.9660 - val_loss: 0.0556 - val_accuracy: 0.9848

......

Epoch 15/15

422/422 [==============================] - 1s 4ms/step - loss: 0.0335 - accuracy: 0.9890 - val_loss: 0.0286 - val_accuracy: 0.9915

上述结果打印了模型训练过程中loss的变化。在模型训练时,选择了categorical cross entropy作为loss,来衡量原始数字类别和由模型预测的数字类别的差异。loss值越小,说明预测结果与原始结果越相似。打印结果中loss是训练过程产生的,val_loss是验证过程产生的,val_accuracy是指validation过程中的准确性。计算的准确性越高效果越好。

1.3、如何评估模型

# 用测试数据评估模型

score = model.evaluate(X_test, y_test, verbose=0) # 用测试数据评估模型,不输出中间过程

print("Test loss:", score[0]) # 打印loss值

print("Test accuracy:", score[1]) # 打印accuracy

# 运行上述代码,输出结果为:

Test loss: 0.027751104906201363 # 测试数据的loss

Test accuracy: 0.991100013256073# 测试数据类别的准确性达到99.1%

所以如果仅仅拿MNIST数据集里数据做评估的话,那么这个模型的准确性相当的高,达到了99.1%。但是如果拿来“实用”一下呢?我们来看看这个模型能不能识别我们自己手写的数字。

2、用模型篇:使用模型识别输入的手写字体

生活中的事一般都是“理想很丰满,现实很骨感”,真的要让一个模型把一个手写的数字给识别出来,其实还真不是那么容易的。我们一起来看一下吧:

2.1、尝试识别在便笺上写的数字

我们先试一试“随便”地在便签纸上写一个简单的数字,让这个模型来试一下吧。在一张最普通最常见的(就是浅黄色的那种)便笺上写一个数字(如我们图中的这个“扭曲的0”),然后拍照后存到电脑(或云主机)里,先试一下吧。

注:让模型识别一个普通图像里的数字可不是那么“简单/直接”的,需要很多个“把一般的彩色照片图像转换成模型可以读取的数组”的操作步骤。例如下面这整整15行的代码就是做这个的:

pic = '/home/diagnoa/DataDrive/WechatIMG1.jpeg' # 手写字原始图片

img = Image.open(pic) # 读取图片文件

ax = plt.subplot(1, 2, 1) # 选择画布1行2列区域的左边绘图

plt.imshow(img) # 在左边绘制原始手写图片

plt.gray() # 绘制灰度图

ax.get_xaxis().set_visible(False) # 隐藏X轴

ax.get_yaxis().set_visible(False) # 隐藏Y轴

ax = plt.subplot(1, 2, 2) # 选择画布1行2列区域的右边绘图

target_shape = (28,28) # 设置数据shape

img2 = cv2.imread(pic, cv2.IMREAD_GRAYSCALE) # 读取图片为灰度图

img2 = cv2.resize(img2, target_shape) # resize图片

plt.imshow(img2, cmap='gray') # 绘制灰度图

ax.get_xaxis().set_visible(False) # 隐藏X轴

ax.get_yaxis().set_visible(False) # 隐藏Y轴

plt.show() # 画图

因为MNIST训练的模型要求的输入图片是(28x28x1)的灰度图,且数值是在0-1之间并且背景反转的(即背景为黑色,byte值为0,笔划信号为正值,这样在转化出的数组中方便直观观察)。此处我们使用的手写数字的照片在经过了上述的预处理之后,我们并不确定还有多少有效信息得到了保留。因此为了能够尽可能地对比原始图片和输入模型的图片,上述代码对预处理之后的图片做了可视化,即上面的这一部分代码中的使用到plt函数的这些行。

注:此处做预处理的代码参考的网络资料来源:

  1. https://blog.tanka.la/2018/10/28/build-the-mnist-model-with-your-own-handwritten-digits-using-tensorflow-keras-and-python/
  2. https://www.tutorialkart.com/opencv/python/opencv-python-resize-image/

运行上述代码,输出结果为:

用Keras构建卷积神经网络识别“自己”的手写字教程

图2. 便笺纸手写扭曲的数字和处理后的图片

上述结果可以看出,左边的原始图片在泛黄的便笺纸上有一个手写的略微扭曲的0,同时这个数字占整个图片的比例很低,线条较细。右侧为经过处理之后的灰度图像,可以看到只有几个像素点被保留下来了,但是笔画信息基本丢失。

将拍摄的照片处理为灰度图以后,就可以用训练好的模型来读取这个图像做预测了。这里还是要对图片数据和之前“建模型”部分里的操作一样、先做预处理(下面这段代码的前4行),再用训练的模型进行类别预测:

img2 = np.resize(img2, (28, 28, 1))

img2 = np.reshape(img2, (1,28, 28, 1)) # reshape图片数据为模型能识别的格式

im2arr = 255-img2 # 图像数据取反

im2arr = im2arr.astype('float32')/255

y_pred = np.argmax(model.predict(im2arr), axis=-1) # 用训练模型来预测结果

print(y_pred)

结果这里就是所谓的“大型翻车现场”了,运行上述代码,输出结果为:

[4]

模型预测的数字是4,然而实际上这个数字是0。

我们来找一找原因吧。

其实图12里的结果已经让这个“翻车”的原因比较“明显”了:原始图片在便笺纸上有是一个0,但是占整个图片的比例很低,线条较细。在经过转为灰度图的图像处理步骤以后,处理过的灰度图像里发现只有几个像素点被保留、而笔划/形状/轮廓等信息却基本上都丢失了。再对比看一下MNIST训练数据和测试数据的图像(以及对应的数组对象),可以发现MNIST数据集的背景十分干净,除了有数字笔划的区域以外,其他的像素位置的数值均为0(即除了数字笔画的边缘存在有限的数值变化,其余位置并没有渐变的数值)。而我们这里使用的这个“便签纸上”的手写数字图片里,可以明显的看到数字边缘的明暗(即数值)变化。而且由于拍摄光线角度和纸张自然的凹凸不平等其他因素的影响,背景数值变化范围也很大、很杂乱。

所以“随便”在便签纸上写一个数字,让模型识别的难度也是很大的。注意:这里我们的“灰度图像”处理过程尽管有十几行,但是仍然是比较“笼统/粗旷”的。使用专业的图像处理工具(例如PhotoShop),可以手工生成背景相对“干净/均一”的灰度图,但是如果需要“手工”处理图像,就有些不太AI智能了,我们这里就没有做更多的尝试。

注:其实我们后续也为了能正确地识别出这些手写数字,也尝试着提高了图片来源的拍摄质量,例如尝试用不同的光源、角度、便签纸的质地、笔的颜色等拍照。这些尝试中所使用的代码,除了需要修改输入图片的路径之外,均和本章节的示例代码一致,因此在这里没有逐一贴出来。

2.2、尝试识别白纸作为背景的手写数字

既然因为图像的“背景噪音”干扰太大,模型识别不了便签纸上“随意”地写出来的数字,我们就尝试了另外一种方法:在白纸上写字。为了获得较为一致的输入图像效果、并减少背景噪声(或确保背景噪声的分布一致、均一),我们把白色背景的一张A4纸分成同样的大小,然后写上若干个数字,并且拿手机保持相似的角度和光线进行拍照。

我们把这些白纸上手写的数字图像输入到模型里,结果发现预测的准确率的确有些提高(至少不是一个也识别不出来了),但还是不够理想。下面我们选择展示一下这次使用的图像1-6,以及预测出来的结果:

用Keras构建卷积神经网络识别“自己”的手写字教程

图3. 白色背景的手写体图片和使用

2.1章节里的代码处理后的图片。图中共6对图片,对应的真实类别分别为1-6。图中每一对图片,都对应着一个数字,左侧为原始图片,右侧为处理后的图片;右侧图片上方的数字显示模型预测的结果。

这6对图片中数字3,4,5,6都预测错误。从处理过的图片中可以看到,背景的明暗依然差别较大,纸张的褶皱也会影响数字边缘的识别和背景的灰度。特别是有些数字的边缘模糊、甚至消失。

这总算不是大型翻车现场了,但是还是“垮掉”。

2.3、尝试识别手写字体网站截取的手写数字

看来能识别出纸上写的数字还真不容易。毕竟纸张在照片里也不是“任何特征都没有”的,毕竟照片里的纸张的阴影和褶皱还是无法完全消除的。我们为了排除手动拍照受角度和纸张平整度的干扰,获得较为干净的数字图片,决定尝试电脑上直接用软件手写一些数字。我们就试着在http://myselph.de/neuralNet.html 网站上手写生成手写体并截图保存,然后将截图用我们的模型进行识别预测,结果如下:

用Keras构建卷积神经网络识别“自己”的手写字教程

图4. 在手写网站上截图和使用

2.1章节里的代码处理后的图片。在12对图像中,每一对的信息为:图中每一对图片,都对应着一个数字,左侧为原始图片,右侧为处理后的图片;右侧图片上方的数字显示模型预测的结果。模型预测的结果均正确。

功夫不负有心人,终于成功了。从图中处理过的图像可以看到对于背景干净的图像,使用2.1章节里的代码做出来的灰度图像里,数字边缘还是被保存得很完整的。这对模型的识别是非常有帮助的。特别是我们这次自己书写数字时很“用心、规整”,再加上背景“干净”、数字笔划边缘清晰,这让这个模型基本上可以正确地识别出所有的我们自己的手写数字。

2.4、尝试识别在Atlas OS笔记功能里手写的数字

其实在“达仁云主机”所在的Atlas OS系统里,就有能直接生成手写数字的功能:在Atlas OS系统(atlas.daren.io)“我的项目”模块的笔记页中,我们可以直接使用“手绘图”功能,手写数字,然后做截图保存。

注意:这次我们故意将数字写得更随意“潇洒”一些,而且故意把一些数字用不同的方式写(例如下图中的两个7的样式)。

我们把这组数字图像用章节1里训练出来的模型进行预测,结果这个模型的识别能力就又被“挑战”到了,请看预测结果:

用Keras构建卷积神经网络识别“自己”的手写字教程

图5. 在Atlas OS上绘图截图和处理后的图片

在11对图像中,每一对的信息为:图中每一对图片,都对应着一个数字,左侧为原始图片,右侧为处理后的图片;右侧图片上方的数字显示模型预测的结果。模型预测结果标红的是预测错误的结果。

在图中展示的这11个例子中,模型预测的结果有9个是正确的,2个是错误:模型把图片7预测为8、图片9预测为4。

因此这个模型的识别能力还是很容易被“黑”的,我们写得随意一些,准确率就从几乎100%降低到了80%左右。

而且同学们也注意到了,我们这次输入还仅仅是“截图”出来的单个数字,还不是一个图像里随意部分的任意长度的数字的识别。所以同学们可以看到,生产环境里的文字识别(OCR)和数字识别技术(例如自动读取车牌号、自动识别身份证号等)还是和我们的这个初级教程里的技术有很大差别的。尽管目前图像识别技术是很成熟的,这里的介绍仅仅是一个入门,希望能让同学们尽快上手,并能初步“实战”一下。我们后续还会有更“实战”的教程带给大家。

上面就是这个教程的所有代码和“实战”应用的结果。注意,这些代码都需要在配置正确的环境中运行(例如JupyterLab和对应的Python环境)。一般配置GPU卡驱动、AI开发环境也是一个“过程”,为了大家能够尽快上手,附录中就有介绍如何使用我们推荐的“达仁云主机”、配置所需的开发环境和正确使用云主机的内容,感兴趣的同事们可以看一下。

附录

附录1. 使用达仁云主机的具体操作流程:

创建虚拟硬盘

在Atlas OS系统(atlas.daren.io)的“达仁云主机”界面上,先创建虚拟硬盘,后续可以使用此硬盘作为主要的数据操作和运行目录。

用Keras构建卷积神经网络识别“自己”的手写字教程

图7. 启动云主机界面

“虚拟硬盘”是一个Atlas OS系统“贴心”的独特功能:一个虚拟硬盘可以用来提前给云主机传入数据。启动云主机的时候,虚拟硬盘里的数据会自动加载到云主机的指定位置。这样用户在云主机里就可以方便地从虚拟硬盘里访问这些提前准备的数据了。

云主机关机时,云主机也会将产生的数据存储到其加载的虚拟硬盘目录下。这样用户就可以方便地在浏览器里直接从虚拟硬盘里访问这些数据了。

1.2、选择公共镜像

选择公共镜像:Linux + JupyterLab

用Keras构建卷积神经网络识别“自己”的手写字教程

图8.选择主机镜像界面

一个“镜像”里就是一个配置好的运行环境。云主机启动需要依赖于一个指定的镜像,就像一台电脑启动需要有一个操作系统一样。这里Atlas OS系统也“贴心”地为用户准备了“预设配置好”的JupyterLab、RStudio、Eclipse等多种数据分析和软件开发的环境的镜像,以及 Windows、Linux远程图形化桌面的镜像。这些不同的镜像一起、覆盖了几乎所有的主流编程语言,包括Java、Python、C /C ++、C#、JavaScript、PHP、Golang等。这里我们需要选择的是“Linux + JupyterLab”的这个镜像。

启动GPU实例

选择GPU实例g4dn.xlarge,设置虚拟硬盘大小,设置合适的内存,为云主机命名。点击启动云主机之后出现右侧弹窗。

用Keras构建卷积神经网络识别“自己”的手写字教程

图9. 选择配置GPU实例界面

“达仁云主机”提供百余种主机配置,包含CPU : 1~96核、内存:0.5GB~3TB、硬盘:1GB~16TB。费用也非常划算,低至3分钱/小时。例如一个2核2G云主机,运行一小时仅需1毛钱。同时因为这些云主机是按秒计费,所以用户可以随时开启和关闭,关闭后系统就立即停止计费,非常方便、没有浪费。

这里因为我们希望使用GPU做机器学习,因此建议选择“g4dn.xlarge”这个带GPU、价格也比较合适的配置机型。注:GPU类型的云主机一般单价都比不带GPU的云主机要贵。因此对于没有GPU需要的使用情景,建议不要选择带GPU的云主机配置类型。

1.4、启动JupyterLab

当云主机状态由“启动中”变为“运行中”时,便可在启动JupyterLab后进行后续操作。此教程提供从IP启动的例子。

用Keras构建卷积神经网络识别“自己”的手写字教程

图10. 云主机启动中状态界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图11. 云主机运行中状态界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图12. 使用IP启动云主机界面

点击“启动云主机”后,在云主机页面等待云主机状态变为“运行中”后,即可点击“云主机信息”找到云主机链接和密码,在浏览器中打开这个云主机了,整个过程<5分钟,操作方式大都为点选操作,非常简单,规避了一切因”过于技术化”所带来的额外学习成本。

而且在云主机关机时,用户也可以选择将云主机存储为自己的云主机镜像,此时云主机关机时系统内的已安装程序和修改过的配置都会写入镜像。这就方便“无痛”地实现了业内常说的“算力可以随时丢弃/更换”,但是“数据和开发环境持久化”的最佳实践。

登陆JupyterLab

此时浏览器会打开Jupyter的操作界面,输入系统分配的初始密码即可登陆。

用Keras构建卷积神经网络识别“自己”的手写字教程

图13. 输入密码登陆Jupyter


从终端配置环境

打开终端配置环境

用Keras构建卷积神经网络识别“自己”的手写字教程

图14. 使用终端界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图15. 终端界面


在此界面中键入如下代码安装程序运行所需环境

# 安装必要的系统环境,即所依赖的系统程序和编译工具

# 此镜像默认安装了conda环境,所有的操作可以在base这个环境中进行

sudo yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

sudo yum update -y

sudo yum -y install kernel-devel-$(uname -r) kernel-headers-$(uname -r)

sudo yum -y install gcc gcc-c++

sudo yum install libXext.x86_64 libXrender.x86_64 libXtst.x86_64 mesa-libGL.x86_64 -y

# 下载并安装GPU驱动

cd DataDrive/

wget https://cn.download.nvidia.com/tesla/450.119.04/NVIDIA-Linux-x86_64-450.119.04.run

sudo sh NVIDIA-Linux-*.run

# 使用conda安装Keras环境

conda install -c anaconda tensorflow-gpu keras matplotlib pillow -y

conda install -c conda-forge opencv -y

至此本次教程所需环境已经配置完毕。

注意:若使用云主机”暂停”功能,请停止云主机的自动更新功能。因为云主机正常情况下可能会在暂停后重新恢复时,自动加载最新版本的Linux系统内核。但是在“安装必要的系统环境”这个步骤中,我们安装了开发版本的Linux内核。因此,如果系统在暂停后重新恢复时加载了另外的内核,会导致内核和GPU驱动等原有的开发环境不匹配。

如果需要停止云主机的自动更新功能,请在命令行执行如下命令:

sudo yum -y install yum-cron

sudo vi /etc/yum/yum-cron.conf

# 将“yum-cron.conf”文档里的如下参数进行修改,即将 “update_messages”和“download_updates”都修改为“no”:

update_messages = no

download_updates = no

# 修改后继续在命令行执行如下命令:

systemctl start yum-cron
systemctl enable yum-cron
sudo cp /etc/yum.conf /etc/yum.conf.bak

sudo vi /etc/yum.conf

# 使用vi或其他的文本编辑器,在这个“yum.conf”文档里添加如下两行内容:

exclude=kernel*

exclude=centos-release*

使用Jupyter Notebook

将代码写进代码框,之后就可以点击“运行”按钮(向右的三角形按钮)执行代码。

用Keras构建卷积神经网络识别“自己”的手写字教程

图16. 打开Jupyter Notebook界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图17. Jupyter Notebook代码编辑和执行界面


关闭或暂停云主机

如下图所示可以选择暂停或者关闭云主机。

用Keras构建卷积神经网络识别“自己”的手写字教程

图18. 暂停或关闭云主机界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图19. 保存当前主机镜像并关闭云主机界面


附录2. 使用达仁云笔记的具体操作流程

创建笔记本

从Atlas OS中“我的项目”模块进入,依次选择【新建项目】→【新建笔记本】→【新建笔记页】,最后选择创建一个【绘图】类型的笔记记录。

用Keras构建卷积神经网络识别“自己”的手写字教程

图20. 达仁云办公“我的项目”界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图21. 在项目中新建笔记本界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图22. 在笔记本中新建笔记页界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图23. 在笔记页中新建元素界面

用Keras构建卷积神经网络识别“自己”的手写字教程

图24. 在笔记页中新建绘图

2.2、绘制手写字体

在笔记中绘制手写字体,之后就可以在屏幕上截屏(注意分别截取单个数字),保存为图像(需要将每个数字一个单独的图像存储),在教程里直接作为输入图像使用了。

用Keras构建卷积神经网络识别“自己”的手写字教程

图25. 手绘数字页面


参考资料

https://blog.csdn.net/sinat_34328764/article/details/83832487

https://keras.io/examples/vision/mnist_convnet/

https://blog.csdn.net/weixin_42523992/article/details/108117725

https://hua-ys.github.io/2019/06/21/Trap-Resize/

https://blog.tanka.la/2018/10/28/build-the-mnist-model-with-your-own-handwritten-digits-using-tensorflow-keras-and-python/

https://www.tutorialkart.com/opencv/python/opencv-python-resize-image/

展开阅读全文

页面更新:2024-04-14

标签:卷积   教程   神经网络   灰度   附录   模型   图像   界面   背景   硬盘   主机   代码   环境   数字   数据   数码   图片

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top