【深度学习】Keras MNIST手写识别(一)—— 多层感知器模型(MLP)

MNIST手写识别(一)—— keras 实现多层感知机(MLP)
本文是该专题【深度学习】的开篇,稍微啰嗦点,尽量把整个运行环境,为什么用keras,如何进行学习,深度神经网络框架等做一个大体介绍,也顺便记录下心得,共勉~, 只看代码实现的话,可以直接跳到最后,代码比较简单,已经过验证。

1、运行环境

如果是刚入坑神经网络,没必要追求动则上万的工作站,普通电脑也是可以玩的起来的,简单学习玩玩可以使用 CPU,优点是可以快速搭建,省去GPU驱动安装的时间,很多人从GPU安装环境就直接放弃,当然,如果是靠炼丹吃饭的话好一点的工具也能够提升不少的工作学习效率,因为哪怕是用最普通的GPU,训练速度甚至都会比CPU快。通常公司or学校实验室都会提供深度学习工作站,可以好好利用~~,若是再满足不了丹炉效率,再入手高级GPU也不迟(主要是今年GPU价格炒的飞起,手动狗头)
下面是本文在CPU与GPU环境下的测试
CPU: (Linux)
【深度学习】Keras MNIST手写识别(一)—— 多层感知器模型(MLP)_第1张图片
GPU: (Win10)
【深度学习】Keras MNIST手写识别(一)—— 多层感知器模型(MLP)_第2张图片
对于上层暴露给用户调用的API,只要其设计时考虑提供跨平台的能力,基本都能够在构建时生成对应平台的包,因此对上层来说,对操作系统不敏感,例如 keras、tensorflow、pycharm、anaconda 等,所有平台用法几乎一致。
本文涉及到的软件包可以参考安装

  1. anaconda:用于提供隔离的虚拟环境,在虚拟环境内,可安装任意版本的python及包,而不会对其他环境造成影响,建议安装 。Ubuntu安装 Anaconda 3 (详细安装步骤与常用命令)
  2. PyCharm:编写python的IDE,可提供代码提示、调试(静态图不能调试网络)等功能,sftp功能专业版才有,建议安装。Ubuntu(18.04)安装 PyCharm——并使用 Anaconda 管理的Python环境
  3. VsCode: 同样是用于编写脚本的IDE,得益于其强大的开源插件,可说轻量且强大,常用于看源码,可用sftp同步等,建议安装。 Ubuntu 安装 Visual Studio Code(VScode)
  4. JuptyerNotebook: 对边写脚本边记录笔记非常友好,可逐行运行,按需安装。
  5. tensorflow:后端神经网络框架,不多说,必须安装。按需选择CPU或GPU(如果用GPU的话,请先按照第7点安装GPU驱动)。TF官网安装教程
  6. keras: 前端 API,抽象并简化底层的接口,更易于使用,必须安装。 pip install keras
  7. GPU 显卡驱动,网上比较多Ubuntu的教程,那么这里就放一个win的教程,反正用起来一样。有需要的安装。win10+cuda10.2+cudnn7.6.5+TensorFlow2.3.0 深度神经网络环境搭建

2、MLP 网络

MLP:Multi-Layer Perception ,中文:多层感知器
这个模型是最基本的神经网络模型,可分为3层:输入层、隐藏层、输出层

【深度学习】Keras MNIST手写识别(一)—— 多层感知器模型(MLP)_第3张图片

输入层一般由输入给定,不做训练,需要训练的层是隐藏层与输出层。
在神经网络中,需要关注要素有:权值w,偏置b,激活函数a。举一个简单而又恰当的例子:
y = 2 x + 3 a = { 0 , y < 0 1 , y > = 0 \begin{aligned} &y = 2x + 3\\ &a=\left\{ \begin{aligned} &0, y <0\\ &1, y>=0 \end{aligned} \right. \end{aligned} y=2x+3a={0,y<01,y>=0
其中,计算 y y y 的式子中 2 x 2x 2x 的 2 为权值,3为偏置,这两个数是训练后得到的,用于拟合训练数据,得到最小化损失,通常被随机初始化,在训练过程中逐步被更新,MLP中,一般情况下 x 为矩阵,因此权值w也为可训练的矩阵,偏置b则为向量。这个步骤为线性计算,权值大小表示可能性的大小,偏置保证输入不能随意被激活
a 代表激活函数,激活的条件是 a 是否大于等于0。这个步骤引入非线性映射,常用的激活函数为 sigmoid 函数,可以将值域为 (-∞,+∞),映射到 (0,1)之间

【深度学习】Keras MNIST手写识别(一)—— 多层感知器模型(MLP)_第4张图片

训练过程
一般 MLP 网络采用的是 BP 反向传播算法来进行训练,

  1. 随机初始化:将网络中所有训练的参数进行随机初始化
  2. 前向传播:将数据喂入模型,计算预测值,得到预测值
  3. 反向传播:计算预测值与标签的之间的损失,梯度更新权值与偏置
  4. 重复(2~3):每更新一次参数为 1个step(step = 样本数 / batch size(一次训练取多少个样本)),轮完一遍样本为 1个epoch
    u p d a t e   p a r a m e t e r { w k → w k ′ = w k − η m ∑ j ∂ C X j ∂ w k b l → b l ′ = b l − η m ∑ j ∂ C X j ∂ b l update\ parameter \left\{\begin{array}{l} w_{k} \rightarrow w_{k}^{\prime}=w_{k}-\frac{\eta}{m} \sum_{j} \frac{\partial C_{X_{j}}}{\partial w_{k}} \\ \\ b_{l} \rightarrow b_{l}^{\prime}=b_{l}-\frac{\eta}{m} \sum_{j} \frac{\partial C_{X_{j}}}{\partial b_{l}} \end{array}\right. update parameterwkwk=wkmηjwkCXjblbl=blmηjblCXj

训练完的模型,需要进行预测或者验证,只需执行前向传播得到预测值,即可得到输出预测结果或用于进行验证准确度

3、Keras

Keras 是一个用 Python 编写的高级神经网络 API,它能够以 TensorFlow, CNTK, 或者 Theano 作为后端运行。Keras 的开发重点是支持快速的实验。能够以最小的时延把你的想法转换为实验结果,是做好研究的关键。
总的来说,keras只是一个抽象了其他神经网络框架的前端API层,其本身作为前端的存在,并不是真正的神经网络框架,并不能深入的了解到后端架构的运行情况,也就无法很好的做性能、内存之类的优化。
深度学习框架有很多种,下面举例一些常用的框架,各有优劣,找一个切入即可。

  • TensorFlow:目前仍是工业界的NN框架老大
  • PyTorch:学术界常用
  • Caffe:CNN方面起步,这方面很强,RNN 能力仍在持续改进
  • Theano:开创了将符号图用于神经网络编程的趋势
  • MXNet:全功能、可编程和可扩展的深度学习框架,支持最先进的深度学习模型
  • PaddlePaddle:百度飞浆度学习平台
  • MNN:阿里轻量级的深度神经网络推理引擎,主要用于端侧推理(淘宝、直播、短视频等)
  • MindSpore:华为自研深度神经网络框架,主要支持他家的昇腾GPU

以下情况适合用keras:

  • 允许简单而快速的原型设计(由于用户友好,高度模块化,可扩展性)。
  • 同时支持卷积神经网络和循环神经网络,以及两者的组合。
  • 在 CPU 和 GPU 上无缝运行。

但是凡是皆有例外,keras 是面向人类设计的,而不是面向机器,因此在对性能优化、内存优化这一块有点捉襟见肘,在阅读完论文、比赛或需要快速验证方案时,keras的确是个不错的选择,若是工程应用,需要兼顾硬件性能,内存开销,算法开发,算子融合、算子优化等情况时,就需要了解后端的架构,以及修改开源的源码。因此单纯只掌握keras是远远不够的,但我们可用从它来进行入门。

建议:请先花点时间,粗略的过一遍keras的官方中文文档,具体的了解下keras到底是什么,提供了什么功能,并且清楚有哪些API可用,并且该怎么去用他,留一个印象,实际用到的情况下,可以快速进行信息检索 --> keras 中文文档

4、MNIST手写识别模型定义

接下来,按照最简单的方式,模块化地按步骤来实现手写识别这个深度神经网络入门 HelloWorld 例程。

  1. 网络模型定义
  2. 静态图编译
  3. 数据加载预处理
  4. 模型训练
  5. 模型评估、预测
  6. 总结

4.1 网络模型定义

此处 MLP 先定义1层隐藏层,1层输出层,模型定义首先要导入 keras 的 Model 类,可以直接使用 Sequential 模型,按顺序进行层的堆叠

from keras import Sequential

model = Sequential()

创建了模型的实例之后,就可以往模型里面添加层,输入层就是喂入的数据,因此不需要单独创建,但是需要在模型的第一层指定输入的 shape,之后的层的 input shape 都会从上一个层的 output shape 中自动计算。
全连接层在keras中命名为 Dense

  • units 指定该隐藏层具有多少个神经元
  • input_shape 指定输入的尺寸,由于全连接层是将图像展平的,图片为 28x28 = 784 的分辨率,因此这里需要设置为 784
  • activation 为激活函数
    • 隐藏层通常选用 relu 作为激活函数,是一个分段函数,x 小于0 输出为0,x 大于0则输出 x(也可以按需选择其他)
    • 输出层是10分类(数字 0-9),选择使用 softmax 作为激活函数,将输入的图片映射为结果为 0-9 的分类概率,最大值即为预测的结果
from keras.layers import Dense

model.add(Dense(units=512, input_shape=(784,), activation='relu'))  # 第一层隐藏层
model.add(Dense(units=10, activation='softmax'))                    # 输出层

4.2 静态图编译

上述MLP网络模型定义好之后,需要将模型进行编译,图编译会调用后端NN框架的接口,如tensorflow 的 sess.compile(),本helloworld例程中,可暂时先不用关心。

model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics='accuracy')

图编译的时候,可以选择一些参数,下面介绍一些简单的,详细的请参考 keras 中文文档

  • optimizer:优化器的类型,用于更新训练参数,来减少 loss,可选有 rmsprop、adam、sgd 等,或者自定义的optimizer
  • loss 是预测结果与标签之间的损失(比较好理解的就是 mse: 两点之间的平方差距离),为优化提供方向,也可自定义
  • metrics:评估指标,通常用 accuracy 准确率来进行评估。
  • **kwargs:输入参数,可以透传到后端 tensorflow

4.3 数据加载预处理

数据加载这不用说,肯定加载 MNIST 手写识别数据集,当然 keras 提供的数据集不止这一个,读者有兴趣可以自己翻翻。
第一次加载会通过网络来进行下载,我一直挂着墙,所以也没注意到需不需要科 学上网才能下载,读者可以自行试试。如果没法下载,你也可以尝试简单搭个小楼梯,就可以轻松下载。这是我一直在用的 小楼梯,比较便宜稳定,速度也还行,没给我发广告费我就不多说了,自行了解。。。

from keras.datasets import mnist

(train_x, train_y), (test_x, test_y) = mnist.load_data()

加载完数据之后,返回2个元组,分别为训练集与测试集,各个数据的 shape 如下:

train_x shape: (60000, 28, 28)
train_y shape: (60000,)
test_x  shape: (10000, 28, 28)
test_y  shape: (10000,)

接下来需要对特征数据进行展平以及归一化,对标签数据进行 one hot 编码

from keras.utils import np_utils

X_train = train_x.reshape(train_x.shape[0], train_x.shape[1] * train_x.shape[2]).astype('float32') / 255
Y_train = np_utils.to_categorical(train_y, num_classes=10)
X_test  = test_x.reshape(test_x.shape[0], test_x.shape[1] * test_x.shape[2]).astype('float32') / 255
Y_test  = np_utils.to_categorical(test_y, num_classes=10)

处理完后的shape,就可以送入模型进行训练了。

X_train shape: (60000, 784)
Y_train shape: (60000, 10)
X_test shape: (10000, 784)
Y_test shape: (10000, 10)

4.4 模型训练

模型与数据都准备完成后,就可以开始训练了,这一步具体的训练时间就与机器能提供的性能有很大关系了,训练很简单,就一句话

model.fit(X_train, Y_train, epochs=5)

将训练集的特征与标签送进去,指定轮他多少遍即可。fit() 总共可接受19个训练参数,常用的参数也有下面这些,具体也可以看 keras 中文文档

  • x 训练集特征
  • y 训练集标签
  • epooch 指定轮训练集多少遍
  • callback 训练过程中的回调函数
  • batch_size 批大小,默认32

4.5 模型评估、预测

训练完后就可以使用测试集来对模型进行loss、准确率的评估,来评估模型的好坏
评估:

loss, accuracy = model.evaluate(X_test, Y_test)

预测:

predict = model.predict(X_test)

4.6 总结

到这里,深度神经网络的 Hello world 程序就已经完成了,利用 keras 来编写总共不到30行代码,入坑期间不同的网络调用的大致流程都是如此,将这个模型掌握了,对于再复杂一点的模型,可能就是需要自定义模型、层、loss函数,最好的教程其实还是keras的源码,利用IDE也可以很方便的进行源码查看,假如需要自定义一个layer,那么需要继承谁? 编写哪些类函数?那么就进 Dense 里看看,其他如loss、eval、callback、model 等等,同样如此,第一步学他,第二步用他,第三步造他

5. 实现代码汇总

代码比较简单,已经在 win10 与 linux 上进行验证成功,同时也在 CPU 与 GPU 环境验证成功,暂未发现问题,若运行出错的话,可以优先检查环境是否安装好。
【深度学习】Keras MNIST手写识别(一)—— 多层感知器模型(MLP)_第5张图片
在这里插入图片描述
可以发现单层隐藏层也可以达到比较好的训练效果,训练精度98.9%,预测精度97.9%,但是存在过拟合的问题,读者可以在此基础上继续增加 Dropout 层,改变隐藏层单元、增加网络深度(隐藏层层数)、降低学习率、更改optimizer、loss ,修改epoch次数、修改batch_size 大小等各种操作,把这个简单的网络,训练的相对较为完美。

from keras import Sequential
from keras.layers import Dense
from keras.datasets import mnist
from keras.utils import np_utils

# 定义全连接网络模型
model = Sequential()
model.add(Dense(units=512, input_shape=(784,), activation='relu'))  # 第一层隐藏层
model.add(Dense(units=10, activation='softmax'))                    # 输出层

# 编译静态图
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics='accuracy')

# 加载并处理 mnist 数据集,图片是 28*28=784 分辨率,对图片进行 reshape 展平
(train_x, train_y), (test_x, test_y) = mnist.load_data()
X_train = train_x.reshape(train_x.shape[0], train_x.shape[1] * train_x.shape[2]).astype('float32') / 255
Y_train = np_utils.to_categorical(train_y, num_classes=10)
X_test = test_x.reshape(test_x.shape[0], test_x.shape[1] * test_x.shape[2]).astype('float32') / 255
Y_test = np_utils.to_categorical(test_y, num_classes=10)

# 模型训练
model.fit(X_train, Y_train, epochs=5, batch_size=32)

# 精度验证
loss, accuracy = model.evaluate(X_test, Y_test)
print('Test loss:', loss)
print('Accuracy:', accuracy)
predict = model.predict(X_test)
print('预测值:', predict.argmax())
print('实际值:', test_y[0])

… 2000 years later …
调试完各种操作,结果你会发现,MLP 模型优化的精度其实有限,很多时候,全连接层作为整个网络模型的最后几层来插入,最后通过 softmax 来实现分类输出。因此,在下一篇来讲一下利用卷积神经网络 CNN 来对 MNIST 进行训练 。
【深度学习】Keras MNIST手写识别(二)—— 卷积神经网络模型(CNN)

你可能感兴趣的:(Deep,Learning,神经网络,深度学习,多层感知器,keras,MNIST)