在深度学习的高级模型中,多层感知器(MLP)通常用于简单的回归问题。然而,MLP在处理具有序列和多维数据的模式时并不是理想的选择。MLP试图记住序列数据中的模式,因此需要大量的参数来处理多维数据。对于序列数据,递归神经网络(RNN)因其能够发现历史数据上的依赖关系而备受青睐,这对于预测非常有用。对于图像和视频等数据,卷积神经网络(CNN)在提取特征图进行分类、分割等任务上表现出色。在某些情况下,一维卷积(Conv1D/1D)的CNN也用于具有序列输入数据的网络。但在大多数深度学习模型中,MLP、CNN和RNN被结合起来以充分利用各自的优势。
MLP、CNN和RNN并不万能……其成功很大程度上来自于明确目标和正确选择一些参数,如损失函数、优化器和正则化器。还拥有来自训练环境之外的数据。正则化器的作用是确保训练出的模型能够泛化到新数据上。
假设目标是创建一个网络来识别基于手写数字的数字。例如,当网络输入的是数字8的图像时,相应的预测也必须是8。这是神经网络的基本分类任务。MNIST数据集被认为是深度学习数据集的“Hello World”。在剖析MLP模型之前,了解MNIST数据集至关重要。它被用来解释和验证许多深度学习理论,因为它包含的70000张图像虽小但信息量足够丰富;MNIST包含从0到9的数字。它有一个包含60000张图像的训练集和10000张测试图像,被分类为类别。
import numpy as np
from tensorflow.keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
mnist.load_data()方法非常方便,无需加载全部70000张图像及其标签。在进入多层感知器分类器之前,必须记住,尽管MNIST数据由二维张量组成,但它们必须根据输入层的类型进行重塑。一个3×3的灰度图像被重塑为MLP、CNN和RNN输入层:
num_labels = len(np.unique(y_train))
print("总标签数: {}".format(num_labels))
print("标签: {}".format(np.unique(y_train)))
这种表示方式不适合用于生成概率的预测层。最合适的格式是独热编码(one-hot),一个10维向量,除了类别索引外,所有值都是0。例如,如果标签是4,等效向量是[0,0,0,0, 1, 0,0,0,0,0]。在深度学习中,数据存储在张量中。张量一词适用于标量张量(0D张量)、向量(1D张量)、矩阵(二维张量)和多维张量。
from tensorflow.keras.utils import to_categorical
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
模型是一个MLP,因此输入必须是1D张量。因此,x_train和x_test必须被转换为[60,000, 2828]和[10,000, 2828],在numpy中,-1的大小意味着允许库计算正确的维度。在x_train的情况下,它是60,000。
image_size = x_train.shape[1]
input_size = image_size * image_size
print("x_train: {}".format(x_train.shape))
print("x_test: {}".format(x_test.shape))
x_train = np.reshape(x_train, [-1, input_size])
x_train = x_train.astype('float32') / 255
x_test = np.reshape(x_test, [-1, input_size])
x_test = x_test.astype('float32') / 255
print("x_train: {}".format(x_train.shape))
print("x_test: {}".format(x_test.shape))
输出:
x_train: (60000, 28, 28)
x_test: (10000, 28, 28)
x_train: (60000, 784)
x_test: (10000, 784)
模型由三个多层感知器层组成,位于密集层中。第一层和第二层是相同的,后面跟着一个ReLU和Dropout激活函数。
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation, Dropout
# 参数
batch_size = 128
hidden_units = 256
dropout = 0.45
# MLP模型,带有ReLU和Dropout
model = Sequential()
model.add(Dense(hidden_units, input_dim=input_size))
model.add(Activation('relu'))
model.add(Dropout(dropout))
model.add(Dense(hidden_units))
model.add(Activation('relu'))
model.add(Dropout(dropout))
model.add(Dense(num_labels))
神经网络倾向于记住其训练数据,特别是如果它包含足够的容量。在这种情况下,当网络受到测试数据的挑战时,会灾难性地失败。这是网络无法泛化的经典案例(过拟合/欠拟合)。为了避免这种趋势,模型使用了Dropout这样的调节层。Dropout的理念很简单。给定一个丢弃率(在模型中,设置为0.45),该层随机移除这个比例的单元。例如,如果第一层有256个单元,在应用Dropout(0.45)之后,只有(1 - 0.45) * 255 = 140个单元将参与下一层。Dropout使神经网络对不可预见的输入数据更加健壮,因为网络被训练即使在某些单元缺失的情况下也能正确预测。Dropout只在训练期间参与。
输出层有10个单元,后面跟着一个softmax激活函数。这10个单元对应于10个可能的标签、类别或类别。softmax激活的输出可以按照以下数学方程表达:
model.add(Activation('softmax'))
model.summary()
输出:
模型:“sequential”
Layer (type) Output Shape Param #
================================================================
dense (Dense) (None, 256) 200960
________________________________________________________________
activation (Activation) (None, 256) 0
________________________________________________________________
dropout (Dropout) (None, 256) 0
________________________________________________________________
dense_1 (Dense) (None, 256) 65792
________________________________________________________________
activation_1 (Activation) (None, 256) 0
________________________________________________________________
dropout_1 (Dropout) (None, 256) 0
________________________________________________________________
dense_2 (Dense) (None, 10) 2570
________________________________________________________________
activation_2 (Activation) (None, 10) 0
================================================================
Total params: 269,322
Trainable params: 269,322
Non-trainable params: 0
________________________________________________________________
优化的目的是最小化损失函数。如果损失降低到可接受的水平,模型间接地学会了将输入映射到输出的函数。性能指标用于确定模型是否已经学会了。
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
Categorical_crossentropy用于独热编码。准确度是分类任务的好指标。Adam是一个优化算法,可以用作经典的随机梯度下降过程的替代品。
鉴于训练集,选择了损失函数、优化器和正则化器,可以开始训练模型。
model.fit(x_train, y_train, epochs=20, batch_size=batch_size)
输出:
Epoch 1/20
469/469 [==============================] - 1s 3ms/step - loss: 0.4230 - accuracy: 0.8690
...
Epoch 20/20
469/469 [==============================] - 2s 4ms/step - loss: 0.0515 - accuracy: 0.9835
此时,MNIST数字分类模型已经完成。性能评估将是确定训练出的模型是否会呈现次优解决方案的下一步。
_, acc = model.evaluate(x_test,
y_test,
batch_size=batch_size,
verbose=0)
print("准确度: %.1f%%" % (100.0 * acc))
输出:
准确度:98.4%
Q1. 简单术语中MLP是什么?
A. 简单术语中,MLP或多层感知器是一种旨在学习复杂模式和关系的人工神经网络,模仿人脑功能。
Q2. 多层感知器的理论是什么?
A.多层感知器的理论涉及相互连接的人工神经元层,每一层处理信息并有助于网络理解数据中的复杂模式。