How to classify MNIST digits with different neural network architectures

Getting started with neural networks and Keras

Go to the profile of Tyler Elliot Bettilyon
Tyler Elliot Bettilyon
BlockedUnblockFollow继2018年8月8日之后


Photo by Greg Rakozy
on Unsplash


我参加了深度学习课程The Bradfield School of Computer Science
在六月。这个系列是一本关于我在课堂上学到的东西以及从那以后学到的东西。


这是本系列的第三篇文章。你可以找到first article in the series here
, and the second article in the series here
.

Please note:
可以找到并运行下面的所有代码示例this Jupyter Notebook
由Google Colaboratory亲切主持。我鼓励您在阅读本文时自行复制代码,进行更改并自行试验网络。

Neural networks


尽管神经网络在过去几年中已经获得了极大的普及,但对于许多数据科学家和统计学家来说,整个模型家族都有(至少)一个主要缺陷:结果是 hard to interpret
。人们将神经网络视为黑匣子的原因之一是任何给定神经网络的结构都很难被思考。


神经网络经常具有数十万到数百万的权重,这些权重在训练期间被单独调整以最小化错误。由于许多变量以复杂的方式相互作用,因此很难准确描述为什么一个特定的神经网络优于其他神经网络。这种复杂性也使得设计顶层神经网络架构变得困难。


这里出现了一些机器学习术语,以防你以前没见过:

  • The name x refers to input data, while the name y refers to the labels. ŷ (pronounced y-hat) refers to the predictions made by a model.
  • Training data is the data our model learns from.
  • Test data is kept secret from the model until after it has been trained. Test data is used to evaluate our model.
  • A loss function is a function to quantify how accurate a model's predictions were.
  • An optimization algorithm controls exactly how the weights of the computational graph are adjusted during training

有关拆分测试和培训数据的更新,或者这是新信息,consider reading this article
.

MNIST handwritten digits dataset


在本文中,我们将介绍一系列简单的神经网络架构,并比较它们在MNIST手写数字数据集上的性能。我们检查的所有网络的目标是相同的:获取手写单个数字(0--9)的输入图像(28x28像素)并将图像分类为适当的数字。


最先进的神经网络方法已经实现了近乎完美的性能,从剩余的测试数字集中正确地对99.8%的数字进行了分类。这种令人印象深刻的表现也带来了现实世美国邮政局每天处理49.34万封邮件,其中1%的邮件是490万封邮件。准确的自动化可以防止邮政工人每天单独处理和检查数百万个包裹。当然,自动读取完整地址并不像处理单个数字那么简单,但让我们在尝试慢跑之前学会抓取。


在深入研究任何机器学习任务之前,熟悉数据集总是一个好主意。以下是数据集中图像的一些示例:
A random selection of MNIST digits. In
the Jupyter Notebook
you can view more random selections from the dataset.


MNIST数据集是神经网络入门的经典问题。我听说有一些人开玩笑说这是"hello world"的深度学习版本 - 很多简单的网络在数据集方面做得非常出色,尽管有些数字非常棘手:
This image is from the wonderful book
Neural Networks and Deep Learning
, available online for free.

Preparing the data


任何机器学习任务中的第一步也是最重要的一步是准备数据。对于许多科学家和行业从业者而言,收集,清理,标记和存储数据为可用数字格式的过程代表了大部分工作。此外,在此步骤中引入的任何错误都将导致学习算法学习不正确的模式。正如他们所说:垃圾进,垃圾出来。


感谢Keras图书馆和国家标准与技术研究所(MNIST的NIST)的辛勤工作,我们已经完成了最难的部分。数据已被收集,并且已经过格式化处理。因此,非常感谢NIST和Keras维护者,我们用于获取数据的Python代码很简单:Relevant XKCD
* --- Python非常棒。*


一旦我们有了数据集,我们就必须为我们的神经网络适当地格式化它。 This article is focused only on fully connected neural networks
,这意味着我们的输入数据必须是矢量。而不是几个28x28图像,我们将有几个长度为784(28 * 28 = 784)的向量。这种展平过程并不理想 - 我们混淆了哪些像素彼此相邻的信息。


我们的网络将克服这种信息丢失,但值得一提convolutional neural networks
(细胞神经网络)。它们专为图像处理/计算机视觉而设计,并保持这些空间关系。在以后的文章中,我们将重新审视具有CNN的MNIST并比较我们的结果。


Keras再次提供了一个简单的实用工具来帮助我们将28x28像素压缩成矢量:


在我们准备好尝试一些神经网络之前,我们必须对这个数据集做最后一件事。此数据集的标签是从0到9的数值---但重要的是我们的算法将它们视为集合中的项目,而不是序数值。在我们的数据集中,值"0" isn't smaller
比值"9",它们只是我们可能的分类中的两个不同的值。


如果我们的算法在预测为"0"时预测"8",那么说模型"偏离8"是错误的 - 它只是预测了错误的类别。同样地,当我们应该预测"8"时预测"7"并不比预测"0"时预测"0"更好 - 两者都是错误的。


为了解决这个问题,当我们对分类数据进行预测时(而不是连续范围内的值),最佳做法是使用"一热编码"向量。这意味着我们创建一个矢量,只要我们拥有的类别数量,并强制模型将矢量中的一个位置恰好设置为1,其余位置设置为0(单个1是"热"值内的值向量)。


值得庆幸的是,Keras也很容易做到这一点:


最后,值得一提的是,我们还有很多其他的事情 could
此时要对输入图像进行标准化/改进。预处理很常见(因为这是一个好主意),但我们暂时忽略它。我们的重点是研究神经网络架构。

Neural network architectures


对于完全连接的神经网络,定义网络架构有三个基本问题:

  1. How many layers are there?
  2. How many nodes are there in each of those layers?
  3. What transfer/activation function is used at each of those layers?

本文探讨了前两个问题,而第三个问题将在后面的文章中进行探讨。传递/激活函数的行为与梯度下降和反向传播密切相关,因此在本系列的下一篇文章之后讨论可用选项将更有意义。


本文中的所有网络体系结构都对所有隐藏层使用sigmoid传递函数。


还有其他因素可以促进神经网络的性能。这些包括使用哪种损失函数,使用哪种优化算法,停止前要运行多少训练时期,以及每个时期内的批量大小。这里讨论批量大小和时期的变化。但是,为了帮助我们比较"苹果与苹果",我保留了损失函数和优化算法:

  • I've selected a common loss function called categorical cross entropy.
  • I've selected one of the simplest optimization algorithms: Stochastic Gradient Descent (SGD).

哇,现在所有这一切都不在了,让我们建立我们的第一个网络:

Building the network


本文中的所有网络都将具有相同的输入层和输出层。我们之前将输入层定义为具有784个条目的向量 - 这是来自展平的28x28图像的数据。当我们从标签创建一个热门编码矢量时,输出层也被隐含地定义了 - 十个标签对应于该层中的十个节点。


我们的输出层还使用了一个特殊的激活函数 softmax
。这标准化了十个输出节点的值,使得:

  • all the values are between 0 and 1, and
  • the sum of all ten values is 1.

这允许我们将这十个输出值视为概率,并且选择最大的一个作为单热矢量的预测。在机器学习中,当我们的模型输出是单热编码矢量时,几乎总是使用softmax函数。


最后,该模型具有使用S形激活函数的具有32个节点的单个隐藏层。生成的体系结构具有25,450个可调参数。从输入层到隐藏层有784 * 32 = 25,088 weights
。隐藏层有32个节点,因此有32个节点 biases
。这给我们带来了25,088 + 32 = 25,120个参数。


从隐藏层到输出层,有32 * 10 = 320个权重。


十个节点中的每一个都增加了一个偏差,使我们达到25,088 + 320 + 10 = 25,450个总参数。


Keras有一个方便的方法来帮助你计算模型中的参数数量,调用.summary()
method we get:

Layer (type) Output Shape Param # 
=================================================================
dense_203 (Dense) (None, 32) 25120 
_________________________________________________________________
dense_204 (Dense) (None, 10) 330 
=================================================================
Total params: 25,450
Trainable params: 25,450
Non-trainable params: 0

我们也可以使用Keras来训练和评估这个模型:


[CODE BLOCK --- train_and_evalulate_first_model.py
]
Training and validation accuracy over time. Final test accuracy: 0.87.


从运行到运行,性能会有所不同(尝试一下)Jupyter notebook
),但准确度始终在87-90%之间。这是一个令人难以置信的结果。我们通过展平图像来模糊数据中的空间关系。我们已经完成了零特征提取,以帮助模型理解数据。然而,在不到一分钟的消费级硬件培训中,我们已经比随机猜测好了近9倍。

Network depth and layer width


虽然有一些经验法则,但确定任何特定任务的最佳架构的唯一方法是 empirically.
有时候,"合理的默认值"会很好用,有时则根本不起作用。确定您的神经网络是否适用于您的数据的唯一方法是测试它并测量您的性能。


神经网络架构是相当多的开放研究的主题。找到一个优于特定任务的现有架构的新架构通常是值得发布的成就。从业者通常会根据最近的出版物选择体系结构,并将其批量复制用于新任务或进行微调以获得渐进式改进。


不过,从头开始重新制作一些简单的轮子还有很多东西需要学习。让我们来看看这个小网络的一些替代方案,并检查这些变化的影响。

Network depth


多层感知器(也称为完全连接的神经网络)的深度由其隐藏层的数量决定。上面的网络有一个隐藏层。这个网络太浅了,称其为"深度学习"在技术上是不准确的。


让我们试验不同长度的层,看看网络的深度如何影响其性能。在本教程中,我编写了一些简短的函数来帮助减少样板:


The evaluate
功能打印模型摘要,训练模型,绘制训练和验证准确度图表,并在测试数据上打印其性能摘要。默认情况下,它使用我们讨论过的固定超参数完成所有这些操作,具体来说:

  • stochastic gradient descent (SGD)
  • five training epochs
  • training batch size of 128
  • the categorical cross entropy loss function.

The create_dense
函数允许我们传递隐藏图层的大小数组。它创建了一个多层感知器,它总是为我们的MNIST任务提供适当的输入和输出层。具体来说,模型将具有:

  • an input vector of length 784
  • an output vector of length ten that uses a one-hot encoding and the softmax activation function
  • a number of layers with the widths specified by the input array all using the sigmoid activation function.

此代码使用这些函数来创建和评估几个深度增加的神经网络,每个隐藏层有32个节点:在Python中:[32] * 2 => [32,32]和[32] * 3 => [32, 32,32]等等......


运行此代码会通过上面定义的evaluate函数生成一些有趣的图表:
One hidden layer, final test accuracy: 0.888


2 hidden layers, final test accuracy: 0.767


3 hidden layers, final test accuracy: 0.438


4 hidden layers, final test accuracy: 0.114

Overfitting


添加更多图层似乎有 decreased
模型的准确性。这可能不直观 - 我们不是给模型更大的灵活性,因此增加了预测的能力吗?不幸的是,权衡并非如此简单。


我们应该寻找的一件事是 overfitting
。神经网络足够灵活,可以调整其参数以适应训练数据,从而精确地使它们不再推广到训练集外部的数据(例如,测试数据)。这有点像记住特定数学测试的答案而不学习如何实际进行数学计算。


过度拟合是许多机器学习任务的问题。由于可调参数的数量非常大,神经网络特别容易过度拟合。您可能过度拟合的一个迹象是训练精度明显优于测试精度。但只有我们的一个结果 - 具有四个隐藏层的网络---具有该功能。即使在训练期间,该模型的准确性几乎不比随机猜测好。这里有一些更微妙的东西。


在某些方面,神经网络就像一个game of telephone
---每个图层只从它之前的图层中获取信息。我们添加的图层越多,原始邮件的更改就越多,这有时是一种力量,有时甚至是一种弱点。


如果一系列图层允许建立有用信息,那么堆叠图层可能会导致更高层次的意义。一个图层在图像中查找边,另一个图层查找创建圆的边,另一个图层查找构成线的边,另一个图层查找圆和线的组合,依此类推。


另一方面,如果层破坏性地去除上下文和有用信息,那么就像在电话游戏中一样,信号在通过层时恶化,直到所有有价值的信息都丢失。


想象一下,你有一个只有一个节点的隐藏层 - 这将迫使网络将目前为止所有有趣的交互减少为单个值,然后通过网络的后续层传播该单个值。信息丢失,这样的网络将表现得非常糟糕。


考虑这个问题的另一个有用的方法是在图像分辨率方面 - 最初我们有一个784像素的"分辨率",但我们强迫神经网络快速下采样到32个值的"分辨率"。这些值不再是像素,而是前一层中像素的组合。


一次压缩决议(显然)并不那么糟糕。但是,与重复保存JPEG一样,重复的"低分辨率"数据传输链从一层传输到下一层会导致较低质量的输出。


最后,由于反向传播和优化算法与神经网络协同工作的方式,更深的网络需要更多的训练时间。可能是我们的模型的每层32节点架构只需要训练更长时间。


如果我们让上面的三层网络训练40个时代而不是5个,我们得到以下结果:
3 hidden layers, 40 training epochs instead of 5. Final test accuracy: .886


真正了解这些因素在您自己的模型中发挥作用的唯一方法是设计测试和实验。请记住,其中许多因素会同时影响您的模型,并且程度不同。

Layer width


我们可以转动的另一个旋钮是每个隐藏层中的节点数。这被称为 width
的图层。与添加更多图层一样,使每个图层更宽可增加可调参数的总数。制作更宽的图层往往比添加更多图层更快地缩放参数数量。每次我们向图层添加单个节点 i
,我们必须为该新节点赋予层中每个节点的边缘 i+1
.


Using the same evaluate
and create_dense
如上所述,让我们使用不同的图层宽度将一些神经网络与单个隐藏层进行比较。


再一次,运行此代码会产生一些有趣的图表:
One hidden layer, 32 nodes. Final test accuracy: .886


One hidden layer, 64 nodes. Final test accuracy: .904


One hidden layer, 128 nodes. Final test accuracy: .916


One hidden layer, 256 nodes. Final test accuracy: .926


One hidden layer, 512 nodes. Final test accuracy: .934


One hidden layer, 2048 nodes. Final test accuracy: .950. This model has a hint of potential overfitting --- notice where the lines cross at the very end of our training period.


这次性能变化更直观 - 隐藏层中的更多节点始终映射到测试数据的更好性能。我们的准确度从32个节点的~87%提高到2048个节点的~95%。不仅如此,我们最后一轮培训的准确性几乎预测了测试数据的准确性 - 这表明我们可能不会过度拟合。


这项改进的成本是额外的培训时间。随着可调参数的数量从拥有32个节点的25,000个增加到拥有2,048个节点的超过160万个,培训时间也是如此。这导致我们的训练时期从每个大约一秒钟到大约10秒钟(在我的Macbook Pro上 - 你的里程可能会有所不同)。


尽管如此,相对于许多最先进的工业模型而言,这些模型的培训速度很快。击败Lee Sedol的AlphaGo版本trained for 4--6 weeks
。 OpenAI写了一篇博客帖子,也有助于将其置于语境中extraordinary computational resources
进入训练最先进的模型。来自文章:


"...最大的AI训练中使用的计算量一直呈指数增长,并且增加了3.5个月......"


当我们拥有良好的数据和良好的模型时,培训时间和模型性能之间存在很强的相关性。这就是为什么许多最先进的模型在作者对模型的能力有信心的情况下训练数周或数月。似乎耐心仍然是一种美德。

Combining width and depth


凭借直觉,更多的节点往往会产生更好的性能,让我们重新审视添加图层的问题。回想一下,堆叠层可以通过下采样建立有意义的信息或破坏信息。


让我们看看堆叠时会发生什么 bigger
层。重复的32层似乎会降低我们网络的整体性能 - 当我们堆叠更大的层时,这仍然是真的吗?


由于上面讨论的原因,随着网络深度的增加,我增加了时期的数量。更深层网络的组合,每个隐藏层有更多节点,以及增加的训练时期导致代码运行时间更长。幸运的是,你可以看看Jupyter Notebook
已经计算出结果的地方。


你可以看到Jupyter笔记本中的所有图形,但我想强调一些兴趣点。


通过这种特殊的训练方案,单层512节点每层网络最终具有最高的测试精度,达到94.7%。总的来说,我们之前看到的趋势 - 更深的网络表现更差 - 仍然存在。但是,差异非常小,大约为1-2个百分点。此外,图表表明,通过对更深层网络的更多培训可以克服差异。


对于每层的所有节点数,一个,两个和三个隐藏层的图形看起来非常标准。更多的培训改善了网络,随着准确度的提高,改进速度变慢。
One 32 node layer


Two 128 node layers


Three 512 node layers


但是,当我们进入四层和五层时,对于32节点模型来说,事情开始变得糟糕:
Four 32 node layers.


Five 32 node layers.


另外两个五层网络也有趣的结果:
Five 128 node layers.


Five 512 node layers.


这两个似乎都克服了一些最初的糟糕表现,看起来好像他们可以通过更多的培训继续改进。这可能是没有足够数据来训练网络的限制。随着我们的模型变得越来越复杂,并且由于有关错误的信息必须通过更多层传播,我们的模型可能无法学习 - 它们没有足够的信息可供学习。


通过在给模型进行校正之前处理较少的数据点来减小批量大小可能会有所帮助。因此可以增加时代数量,但代价是增加了培训时间。不幸的是,很难判断你是否拥有垃圾架构,或者只是需要更多的数据和更多的培训时间而不需要测试自己的耐心。


例如,当我将批量大小减少到16(从128)并且每层32个节点用5个隐藏层训练50个时期(在我的硬件上花了大约30分钟)时,就会发生这种情况:
Five 32-node hidden layers, batch size 16, 50 epochs. Final test accuracy: .827


因此,每层的32个节点看起来不像是对该网络无法学习任何东西进行下采样或破坏信息。也就是说,我们构建的许多其他网络在训练显着减少的情况下表现更好。我们宝贵的培训时间可能会更好地用于其他网络架构。

Further steps


虽然我希望这篇文章有用且具有启发性,但并非详尽无遗。即使是专家有时也会对哪些架构可行,哪些架构不起作用感到困惑和不确定。支持你的直觉的最好方法是为自己练习构建和试验神经网络架构。


In the next article
,我们将探索梯度下降作为训练神经网络的基石算法。


如果你想要一些功课 - 我知道你这样做 - Keras有很多奇妙的数据集,就像MNIST数据集一样。为了确保您从本文中学到了一些东西,请考虑重新创建类似于我上面使用过的实验the Fashion MNIST dataset
,这比常规的MNIST数据集更具挑战性。

查看英文原文

查看更多文章


公众号:银河系1号


联系邮箱:public@space-explore.com


(未经同意,请勿转载)