Tensorflow without a phd master 1——Jetson nano初体验5

Tensorflow without a phd master 1

这个教程源于谷歌开发者博客的 Codelabs 项目

  • https://github.com/GoogleCloudPlatform/tensorflow-without-a-phd

为希望学习机器学习的软件开发人员提供六集的速成课程,包括示例,理论概念,工程技巧,技巧和最佳实践,以构建和培训解决您问题的神经网络。

1. tensorflow-mnist-tutorial

为软件工程师构建神经网络的基础知识。 神经权重和偏差,激活函数,监督学习和梯度下降。
有效培训的技巧和最佳实践:学习率衰减,Dropout、正规化和过度拟合的复杂性。 密集和卷积神经网络。
此会话以低级Tensorflow开始,还包含使用图层和数据集的高级Tensorflow代码示例。 代码示例:MNIST手写数字识别,准确率达99%。 持续时间:55分钟

  • PPT
  • Codelab
  • 视频
  • 视频2
  • 代码

1.1 概述

image

在 codelab 项目中,你将学习如何构建并训练出能够识别手写数字(recognises handwritten digits)的神经网络。在这过程中,当这个神经网络的准确度提升至 99%时,你还将学习到专业人员用来训练模型的高效工具。

这个 codelab 项目使用的是 MNIST 数据集,这个包含 60,000 个有标记数字的集合是几届博士努力近二十年的成果。你将会用不到 100 行的 Python/TensorFlow 代码来解决上述问题。

你将学到:

  • ①神经网络的定义及如何训练神经网络
  • ②如何使用 TensorFlow 构建基本的单层神经网络
  • ③如何添加多层神经网络
  • ④训练提示和技巧:过拟合、Dropout、学习速率衰减等...
  • ⑤如何解决深度神经网络的问题
  • ⑥如何构建卷积网络

对此,你将需要:

  • ①Python 2 或 3(建议使用 Python 3)
  • ②TensorFlow
  • ③Matplotlib(Python 的可视化库)

1.2 准备:安装 TensorFlow,获取示例代码

git clone https://github.com/GoogleCloudPlatform/tensorflow-without-a-phd.git
cd tensorflow-without-a-phd/tensorflow-mnist-tutorial

python3 mnist_1.0_softmax.py

然后可以看到可视化的训练结果


image

1.3 单层神经网络

image

MNIST数据集中的手写数字是28x28像素灰度图像。 对它们进行分类的最简单方法是使用28x28 = 784像素作为单层神经网络的输入。


image

神经网络中的每个“神经元”对其所有输入进行加权求和,添加一个称为“偏置”的常数,然后通过一些非线性激活函数提供结果。

在这里,我们设计了一个具有10个输出神经元的单层神经网络,因为我们想要将数字分类为10个类(0到9)。

对于分类问题,运行良好的激活函数是 softmax。 在矢量上应用 softmax 是通过取每个元素的指数然后归一化矢量(使用任何范数,例如矢量的普通欧氏长度)来完成的。

image

现在,我们将使用矩阵乘法将这一单层神经元的行为概括为一个简单的公式。 让我们直接进行100个图像的“小批量(mini-batch)”作为输入,产生100个预测(10个元素向量)作为输出。


image

我们最终应用softmax激活函数并获得描述单层神经网络的公式,应用于100个图像:


image

1.4 理论:梯度下降

现在需要计算预测结果与实际结果之间的偏差,普通的欧几里德距离很好
但是对于分类问题,“交叉熵(cross-entropy)”更有效


image

"One-hot" 编码表示一个向量只有一个1,其余都为0

“训练”神经网络实际上意味着使用训练图像和标签来调整权重和偏差,以便最小化交叉熵损失函数。

交叉熵是权重,偏差,训练图像的像素及其已知标签的函数。

如果我们相对于所有权重和所有偏差计算交叉熵的偏导数,我们获得“梯度”,针对给定图像,标签和权重和偏差的现值计算。 请记住,我们有7850个权重和偏差,所以计算梯度听起来要做很多工作。 幸运的是,TensorFlow将为我们做到这一点。

梯度的数学特性是它指向“向上”。 由于我们想要去交叉熵低的地方,我们走向相反的方向。 我们通过梯度的一小部分更新权重和偏差,并使用下一批训练图像再次执行相同的操作。 希望这能让我们到达交叉熵最小的坑的底部。


image

在该图中,交叉熵表示为2个权重的函数。 实际上,还有更多。 梯度下降算法遵循最速下降到局部最小值的路径。 训练图像也在每次迭代时改变,以便我们收敛到适用于所有图像的局部最小值。

“学习率”:您无法在每次迭代时按梯度的整个长度更新权重和偏差。 要到达底部,您需要执行较小的步骤,即仅使用渐变的一小部分,通常在1/1000区域中。 我们称这个分数为“学习率”。

训练数字和标签=>损失函数=>渐变(偏导数)=>最速下降=>更新权重和偏差=>重复下一批训练图像和标签

为什么要使用100个图像和标签的“迷你批次”?

您只能在一个示例图像上计算梯度并立即更新权重和偏差(在科学文献中称为“随机梯度下降”)。 在100个示例中这样做会给出一个梯度,该梯度更好地表示不同示例图像所施加的约束,因此可能更快地收敛到解决方案。 尽管如此,小批量的大小是可调整的参数。 还有一个更技术性的原因:使用批处理也意味着使用更大的矩阵,这些通常更容易在GPU上进行优化。

最终可以实现的准确率为 92%

1.5 添加更多的隐层

为了提高识别精度,我们将为神经网络添加更多层。这是一个5层完全连接的神经网络:


image

我们将 softmax 保持为最后一层的激活函数,因为这最适合分类。 然而,在中间层我们将使用最经典的激活函数: sigmoid

image

最终可以实现的准确率为 97%

1.6 改进

1.6.1 RuLU激活函数(Rectified Linear Unit)

Sigmoid激活函数在深度网络中实际上是很成问题的。 它会压缩0到1之间的所有值,当你反复这样做时,神经元输出和它们的梯度可以完全消失。
RELU如下所示:


image

采用RuLU之后可以解决 “梯度爆炸” 问题,而且可以加快训练速度


image

1.6.2 优化器(Optimizer)

在像这里这样的非常高维度的空间中 - 我们有大约10K的重量和偏差 - “马鞍点”是常见的。 这些点不是局部最小值,但是梯度为零并且梯度下降优化器仍然停留在那里。 TensorFlow拥有一整套可用的优化器,包括一些可以使用惯性并且可以安全驶过鞍点的优化器。

1.6.3 随机初始化(Random initialisations)

准确度仍然保持在0.1? 你是否用随机值初始化了权重? 对于偏差,当使用RELU时,最佳做法是将它们初始化为小的正值,以便神经元最初在RELU的非零范围内运行。

1.7 降低学习率(learning rate decay)

如果将迭代次数推至5000或更高,则使用两个,三个或四个中间层,现在可以获得接近98%的准确度。 但是你会发现结果不是很一致。


image

这些曲线非常嘈杂,看看测试的准确性:它的上下跳动百分之一。 这意味着即使学习率为0.003,我们也会走得太快。 但我们不能只将学习率除以10,否则培训需要永远。 好的解决方案是快速启动并将学习速率指数衰减到0.0001。

这一小变化的影响是巨大的。 您可以看到大部分噪音消失,测试精度现在持续超过98%。


image

最终可以实现的准确率为 98%

1.8 dropout, overfitting(过拟合)

您将注意到,测试和训练数据的交叉熵曲线在几千次迭代后开始断开连接。 学习算法仅用于训练数据,并相应地优化训练交叉熵。 它永远不会看到测试数据,所以一段时间后它的工作不再对测试交叉熵产生影响就不足为奇了,它会停止下降,有时甚至会反弹。

这不会立即影响模型的实际识别功能,但它会阻止您运行多次迭代,并且通常表明训练不再具有正面效果。 这种断开通常标记为“overfitting(过度拟合)”,当您看到它时,您可以尝试应用称为“dropout(丢失)”的 正则化技术

image

在每次训练迭代中,您从网络中丢弃随机神经元。 您选择保留神经元的概率保持,通常在50%和75%之间,然后在训练循环的每次迭代中,您随机移除具有所有重量和偏差的神经元。 每次迭代都会丢弃不同的神经元(你还需要按比例增加剩余神经元的输出,以确保下一层的激活不会发生变化)。 当你测试网络性能时,你会把所有神经元都放回去(pkeep = 1)。


image

你应该看到测试损失在很大程度上得到了控制,噪声再次出现,但至少在这种情况下,测试精度保持不变,这有点令人失望。

无论我们做什么,我们似乎都无法以显着的方式突破98%的障碍,我们的损失曲线仍然表现出“过度拟合”的脱节。 什么是“过度拟合”? 当神经网络以一种适用于训练示例但在实际数据上不太好的方式学习“严重”时,会发生过度拟合。 有一些正则化技术,如 Dropout,可以迫使它以更好的方式学习,但过度拟合也有更深层次的根源。


image

当神经网络对于手头的问题具有太多的自由度时,会发生基本过度拟合。想象一下,我们有这么多神经元,网络可以将所有训练图像存储在其中,然后通过模式匹配识别它们。神经网络必须受到一定限制,以便强制推广它在训练期间学到的东西。

如果您的训练数据很少,即使是小型网络也可以用心去学习。一般来说,您总是需要大量数据来训练神经网络。

最后,如果你已经做好了一切,尝试了不同大小的网络,以确保其自由度受到限制,应用Dropout,并对大量数据进行训练,你可能仍然会陷入性能平台,似乎没有任何东西能够提高。这意味着您的神经网络目前的形状无法从您的数据中提取更多信息,如我们的案例所示。

还记得我们如何使用我们的图像,将所有像素平铺成单个矢量?这是一个非常糟糕的主意。手写数字由形状组成,当我们平整像素时我们丢弃了形状信息。然而,有一种神经网络可以利用形状信息:卷积网络。让我们试试吧。

经过批量标准化后最终可以实现的准确率为 98.2%

1.9 卷积层

在卷积网络的层中,一个“神经元”仅在图像的小区域上对其正上方的像素进行加权和。 然后通过添加偏差并通过其激活功能馈送结果来正常动作。 最大的区别在于每个神经元重复使用相同的权重,而在之前看到的完全连接的网络中,每个神经元都有自己的一组权重。


image

在上面的动画中,您可以看到通过在两个方向(卷积)上滑动图像的权重块,您可以获得与图像中的像素一样多的输出值(尽管边缘处需要一些填充)。

要使用4x4的色块大小和彩色图像作为输入生成一个输出值平面,就像在动画中一样,我们需要4x4x3 = 48个权重。 这还不够。 为了增加更多的自由度,我们用不同的权重集重复相同的事情。

通过向张量添加维度,可以将两组(或更多组)权重重写为一组,这给出了卷积层的权重张量的通用形状。 由于输入和输出通道的数量是参数,我们可以开始堆叠和链接卷积层。

在最后一层,我们仍然只需要10个神经元来处理10类数字。 传统上,这是通过“最大池”层完成的。 即使今天有更简单的方法,“max-pooling”也有助于直观地理解卷积网络的运作方式:如果你认为在训练过程中,我们的小块权重会演变为识别基本形状的滤波器(水平和垂直线条,曲线,...... 。)然后向下挖出有用信息的一种方法是通过层保持最大强度识别形状的输出。 在实践中,在max-pool层中,神经元输出以2x2的组进行处理,并且仅保留一个最大的输出。

但有一种更简单的方法:如果您以2像素而不是1的步幅在图像上滑动补丁,则也会获得更少的输出值。 事实证明这种方法同样有效,而当今的卷积网络只使用卷积层。


image

让我们建立一个手写数字识别的卷积网络。 我们将在顶部使用三个卷积层,在底部使用传统的softmax读出层,并将它们与一个完全连接的层连接:

请注意,第二个和第三个卷积层的步长为2,这就解释了为什么它们将输出值的数量从28x28降低到14x14然后降低到7x7。 完成各层的大小调整,使每层神经元的数量大致减少两倍:28x28x4≈3000→14x14x8≈1500→7x7x12≈500→200。


image

最终可以实现的准确率为 98.9%

1.10 挑战 99%

调整神经网络大小的一个好方法是实现一个有点过于受限的网络,然后给它更多的自由度并添加Droupout 以确保它不会过度拟合。 这最终会提供一个相当优化的网络。

因此,让我们稍微提高patches大小,将卷积层中的patches数量从4,8,12增加到6,12,24,然后在完全连接的层上添加 Droupout。 为什么不在卷积层? 他们的神经元重复使用相同的权重,因此在一次训练迭代期间通过冻结一些权重而有效地工作的丢失对它们不起作用。


image

最终可以实现的准确率为 99.3%

上图所示的模型在10,000个测试数字中仅丢失了72个。 您可以在MNIST网站上找到的世界纪录大约为99.7%。 我们的模型使用100行Python / TensorFlow构建,距离它只有0.4个百分点。

总而言之,这是我们更大的卷积网络的差异。 为神经网络提供额外的自由度,使最终的准确率从98.9%提高到99.1%。 增加 Dropout 不仅降低了测试损失,而且让我们的准确率超过99%,甚至达到99.3%

1.11 Batch Normalisation (批量标准化, BN)

输入数据的均值和方差与中心零点偏差较大,需要对数据做批量标准化


image

1.11.1 BN 三大思想

image
    1. 计算小批量的平均值和方差(Compute average and variance on mini-batch)
    1. 缩放和平移到中心(center and re-scale logits(logit = weighted sum + bias))(before the activation function )(decorrelate? no,too complex)
    1. 添加可学习的比例和偏移量(针对每个logits以还原表现力)add learnable scale and offset (for each logits so as to restore expressiveness)

随着网络的训练,网络会学到最合适的 α 和 β ,最终中间层的输出将服从均值为 β ,标准差为 α 的正态分布。

ϵ 的解释:为了避免方差为 0 而加入的微小正数(eg:0.001)。

1.11.2 以批量标准化代替 Dropout 层

现在几乎所有的卷积神经网络都会使用批量标准化操作,它可以为我们的网络训练带来一系列的好处。具体如下:

  • 首先,通过对输入和中间网络层的输出进行标准化处理后,减少了内部神经元分布的改变,降低了不同样本间值域的差异性,使得大部分的数据都处在非饱和区域,从而保证了梯度能够很好的回传,避免了梯度消失和梯度爆炸;
  • 其次,通过减少梯度对参数或其初始值尺度的依赖性,使得我们可以使用较大的学习速率对网络进行训练,从而加速网络的收敛;
  • 最后,由于在训练的过程中批量标准化所用到的均值和方差是在一小批样本(mini-batch)上计算的,而不是在整个数据集上,所以均值和方差会有一些小噪声产生,同时缩放过程由于用到了含噪声的标准化后的值,所以也会有一点噪声产生,这迫使后面的神经元单元不过分依赖前面的神经元单元。所以,它也可以看作是一种正则化手段,提高了网络的泛化能力,使得我们可以减少或者取消 Dropout,优化网络结构。

1.11.3 BN 的使用注意事项

  • BN 通常应用于输入层或任意中间层,且最好在激活函数前使用。
  • 使用 BN 的层不需要加 bias 项了,因为减去batch 个数据的均值后, 偏置项的作用会被抵消掉,其平移的功能将由 β 来代替。
  • BN 的训练阶段均值和方差的求法:全连接层:对 batch 个数据内的每个对应节点(node)分别求均值和方差;二维卷积层:对 batch 个数据内的每一个对应的特征图(feature map)求均值和方差。
  • BN 的测试阶段均值和方差的求法:测试时,使用的是训练集的每一个 BN 层均值和方差,这样做是为了避免在测试阶段只有一个数据实例的情况,因为这种情况下如果使用测试集本身的均值和方差的话,均值就是它本身,方差为 0,标准化后会得到 0,这样就没意义了。所以,我们在训练阶段使用滑动平均的方法来近似计算。

经过批量标准化后最终可以实现的准确率为 99.5%

1.12 总结

image
改进方法 精度 过拟合程度 改进原因
单全连接+Softmax 92%
5层全连接 97% 提升精度
ReLU激活函数、随机初始化、降低学习率 98% 加快收敛速度且提升
加入Drouptout层 98.2% 降低过拟合
三层卷积层[5,4,4](4,8,12) 98.9% 新结构
三层卷积层[6,5,4](6,12,24)+ Drouptout层 99.3% 提升精度
批量标准化 99.5% 降低过拟合

参考资料

  • TensorFlow and deep learning without a PhD

你可能感兴趣的:(Tensorflow without a phd master 1——Jetson nano初体验5)