分享

使用TensorFlow的Keras API实践多层感知器模型

本帖最后由 levycui 于 2019-7-30 18:02 编辑
问题导读:
1、如何理解多层感知器?
2、如何理解MNIST数据集?
3、如何使用TensorFlow的Keras API创建一个MLP?
4、如何在训练和测试组中打印出模型准确性?




本文将介绍如何利用TensorFlow的高级API-Keras建立并训练多层感知器.
2019-07-30_173125.jpg
Keras自2015年初不断发展,如今已成为基于Theano和TensorFlow的最受欢迎且应用最广的深度学习库之一。Keras最显著的一个特征是其具有非常直观且便于使用的API,用户只需写几行代码就能运行神经网络。

Keras 1.1.0及以上的版本均可植入TensorFlow,作为其中的Con肋骨模板(包含由参与者开发给TensorFlow的数据包,为实验性代码)的一部分.

本教程将从以下几方面介绍该TensorFlow的高级API:
·前馈神经网络的基础知识
·载入并准备时下流行的MNIST数据集的方法
·建立图像分类器的操作
·训练神经网络和评估其准确性的方法
本教程改编自Next Tech“Python机器学习”丛书系列的第四部分.从零开始教会你Python的机器学习和深度学习算法.教程也涉及到浏览器内沙盒环境,其中包含所有必要软件、需要预安装的数据库,以及使用公共数据集的项目


2019-07-30_173353.jpg

多层感知器

多层前馈神经网络是一种独特的具有多个单一神经元的完全连接网络,也被称为多层感知器(MultilayerPerceptrons)。下图展示了由三个层级组成的MLP的概念:
2019-07-30_173421.jpg
上图所示的MLP有一个输入层、一个隐藏层以及一个输出层.隐藏层的单元均与输入层连接,输出层的单元也全部与隐藏层连接.具有多个隐藏层的网络被称为深层人工神经网络.

给MLP添加任意数量的隐藏层,来创建更深层的网络结构.实际上,添加的层级和单元的数量可被视为对既定问题任务进行优化的额外超参数.

正如上图所示,将第i层中的第i个激活单位标志为i^(L)。为了使数学和代码运行更加直观,给输入层使用in上标,隐藏层用h上标,输出层用o上标.

例如,i^(In)表示输入层中的第i个单元,i^(H)代表隐藏层中的第i个单元,i^(Out)则表示输出层中的第i个单元。此处,_0^(In)和_0^(Out)激活单元是偏置项,设为等同于1。激活输入层的单元只需输入单元和偏置项.
2019-07-30_173528.jpg
l层的每个单元均通过权重系数与l+1层的所有单元连接.比方说,l层的第k个单元与l+1层的第j个单元的连接写为w_{k,j}^(L)。再看回上一个图,将连接输入层和隐藏层的权重矩阵标志为W^(H),连接隐藏层和输出层的权重矩阵标志为W^(Out)。

将连接输入层和隐藏层的权重矩阵汇总为:
2019-07-30_173604.jpg
此处,d表示隐藏层单元的数量,m表示输入层中包括偏置项的单元数量.由于彻底理解该表示法对于掌握本教程后面的概念非常重要,我们在下图简化的3-4-3多层感知器的描述性说明中总结一下刚刚学到的内容:
2019-07-30_173629.jpg

MNIST数据集

混合美国国家标准技术研究所(混合国家标准与技术研究所,MNIST)数据库是时下非常流行的针对机器学习算法的基准数据集。为了研究神经网络训练通过tensorflow.keras(tf.keras)高级api运作的情况,需要运行多层感知器来区分手写数字和运作的情况,需要运行多层感知器来区分手写数字和MNIST数据集中的数字.

https://next.tech/register(要依照本教程的代码片段,请使用该Next Tech沙盒),里面设置有MNIST数据集合所有必需的数据包.http://yann.lecun.com/exdb/mnist/(或者也可以在本地环境下下载数据集)。



MNIST数据集有四个部分,所示如下:
·训练组图像:列车-图像-idx3-ubyte.gz-60000个样本
·训练组标签:列车标签.idx1-ubyte.gz-60000个标签
·测试组图像:t10k-图像-idx3-ubyte.gz-10000个样本
·测试组标签:t10k标签-idx1-ubyte.gz-10000个标签


训练组包含250名人士(50%为高中学生,50%为人口普查局员工)的手写数字.)测试组包含不同人写的数字.

请注意TensorFlow也提供相同的数据集,如下所示:
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
然而,本教程使用MNIST数据集作为外部数据集来分别学习数据预处理的所有步骤.依照这个方式便可学会如何使用自己的数据集.

第一步是通过在终端运行以下命令来解压缩MNIST数据集的四个部分:
[mw_shl_code=shell,true]cd mnist/
gzip *ubyte.gz -d[/mw_shl_code]

[mw_shl_code=python,true]import os
import struct

def load_mnist(path, kind='train'):
    """Load MNIST data from`path`"""
    labels_path = os.path.join(
        path, f'{kind}-labels-idx1-ubyte'
    )
    images_path = os.path.join(
        path, f'{kind}-images-idx3-ubyte'
    )

    with open(labels_path, 'rb') as lbpath:
        magic, n = struct.unpack('>II',lbpath.read(8))
        labels = np.fromfile(lbpath,dtype=np.uint8)

    with open(images_path, 'rb') as imgpath:
        magic, num, rows, cols =struct.unpack(">IIII", imgpath.read(16))
        images = np.fromfile(imgpath,dtype=np.uint8).reshape(len(labels), 784)
        images = ((images / 255.) - .5) *2
    return images,labels[/mw_shl_code]

load_mnist函数返回两个数组.第一个数组是n×m维度的NumPy数组(图像)。其中,n表示样本数,MIS表示要点值(此处为像素)。MNIST数据集中的图像为28x28像素,每个像素由灰度强度值表示。在此将28x28像素图像展开为单维行矢量,表示图像数组中的行(每行或每图的数值为784)。Load_mnist函数返回的第二个数组(标签)包含相应的目标变量,即手写数字的类标签(整数0-9)。

然后,按照如下方式加载和准备数据集:
[mw_shl_code=python,true]import matplotlib.pyplot as plt

fig, ax = plt.subplots(nrows=2, ncols=5,
                      sharex=True, sharey=True)
ax = ax.flatten()
for i in range(10):
    img = X_train_centered[y_train == i][0].reshape(28, 28)
    ax.imshow(img, cmap='Greys')

ax[0].set_yticks([])
ax[0].set_xticks([])
plt.tight_layout()
plt.show()[/mw_shl_code]

现在可以看到2×5的子图片,展示了每个不同数字的代表图像.

2019-07-30_174009.jpg

使用TensorFlow的KerasAPI创建一个MLP

首先,为NumPy和TensorFlow设置随机种子数,获得如下相同结果:
[mw_shl_code=python,true]import tensorflow.contrib.keras as keras

np.random.seed(123)
tf.set_random_seed(123)
[/mw_shl_code]
继续准备训练数据,将类标签(整数0-9)转化为独热形式。幸运的是,Keras为实现该操作提供了便利的工具:
[mw_shl_code=python,true]y_train_onehot = keras.utils.to_categorical(y_train)

print('First 3 labels: ', y_train[:3])
print('\nFirst 3 labels (one-hot):\n', y_train_onehot[:3])

First 3labels:  [5 0 4]
First 3 labels(one-hot):
[[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]][/mw_shl_code]

现在开始运行神经网络!简单来说,网络包含三个层级.前两个层(输入层和隐藏层)各有50个具有tanh激活函数的单元.最后一个层(输出层)有针对10个类标签的10个层级,能使用Softmax来传递每类标签的操作可能性.Keras让这些任务变得异常简单:

[mw_shl_code=python,true]# initialize model
model = keras.models.Sequential()

# add input layer
model.add(keras.layers.Dense(
    units=50,
    input_dim=X_train_centered.shape[1],  
  kernel_initializer='glorot_uniform',
    bias_initializer='zeros',
    activation='tanh')
)
# add hidden layer
model.add(
   keras.layers.Dense(
       units=50,
       input_dim=50,
       kernel_initializer='glorot_uniform',
       bias_initializer='zeros',
       activation='tanh')
    )
# add output layer
model.add(
    keras.layers.Dense(
        units=y_train_onehot.shape[1],
        input_dim=50,
        kernel_initializer='glorot_uniform',
        bias_initializer='zeros',
        activation='softmax')
    )

# define SGD optimizer
sgd_optimizer = keras.optimizers.SGD(
    lr=0.001, decay=1e-7, momentum=0.9
)
# compile model
model.compile(
   optimizer=sgd_optimizer,
    loss='categorical_crossentropy'
)[/mw_shl_code]

首先,使用序列类初始化新模型来运行前馈神经网络.然后,根据自身喜好添加层级.但是,因为添加的第一个层是输入层,需要确保输入_DIM属性与训练组中的要点数(列数)相配(神经网络运行时有784个要点或像素)。

同时也要确保两个连续层中的输出单元数(单位)和输入单元数(INPUT_DIM)相符。头两个层级各有50个单元以及1个偏置项.输出层中的单元数应等同于特殊类标签的数量,即独热编码类标签数组中的列数.

请注意本教程使用glorot_Uniform作为权重矩阵的初始化算法.Glorot初始化对激活深度神经网络而言更加有效。偏差被初始化为零,这是常见设置,实际上也是Keras中的默认设置.

在编写模型之前,还需定义优化器.在此选择随机梯度下降优化法.此外,还可设置权重衰减常数和冲量学习的值,从而调整每个阶段的学习率.最后,将成本(损失)函数设置为分类交叉熵.

二元交叉熵是逻辑回归中成本函数的专业术语,分类交叉熵则是通过Softmax进行多类预测的概括.

编写完成后,可调用拟合方法来训练模型.此处采用小批量随机梯度方法,批量大小为每批64个训练模板.训练次数超过50次,并通过设置详细=1来跟踪训练过程中成本函数的优化。

验证_拆分参数尤其便于操作。因为它会在每次训练后保留10%的训练数据(此处为6,000个样本)用以验证,这样就便于监控模型在训练期间是否过度拟合:
[mw_shl_code=python,true]# train model
history = model.fit(
   X_train_centered, y_train_onehot,
   batch_size=64, epochs=50,
   verbose=1, validation_split=0.1
)[/mw_shl_code]

训练期间打印成本函数的值非常有用,可以快速发现训练期间成本是否下降,并提前停止算法.否则就需要调整超参数值.

为了预测类标签,可以使用预测类方法直接将类标签作为整数返回:

[mw_shl_code=python,true]y_train_pred = model.predict_classes(X_train_cent
ered, verbose=0)
print('First 3 predictions: ', y_train_pred[:3])

First 3 predictions: [5 0 4]
[/mw_shl_code]
最后,在训练和测试组中印出模型准确性;
[mw_shl_code=python,true]# calculate training accuracy
y_train_pred = model.predict_classes(X_train_cent
ered, verbose=0)
correct_preds = np.sum(y_train == y_train_pred, ax
is=0)
train_acc = correct_preds / y_train.shape[0]

print(f'Training accuracy: {(train_acc * 100):.2f}')

# calculate testing accuracy
y_test_pred = model.predict_classes(X_test_cente
red, verbose=0)
correct_preds = np.sum(y_test == y_test_pred, axis=0)
test_acc = correct_preds / y_test.shape[0]

print(f'Test accuracy: {(test_acc * 100):.2f}')

Training accuracy: 98.81
Test accuracy: 96.27[/mw_shl_code]

本教程简述如何使用TensorFlow的KerasAPI创建和训练多层神经网络来进行图像分类.请注意这只是一个非常简单的神经网络,没有优化的调整参数.实践过程中,需要弄清楚如何通过调整学习率、冲量、权值衰减,以及隐藏单元的数量来优化模型.还需要学习如何处理梯度消失的问题,其中随着更多层被添加到网络中,误差梯度会变得越来越小.

2019-07-30_174324.jpg
作者:读芯术
来源:https://juejin.im/post/5d3142146fb9a07efe2df6c0
最新经典文章,欢迎关注公众号


没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条