目录node
这个教程源于谷歌开发者博客的 Codelabs 项目python
为但愿学习机器学习的软件开发人员提供六集的速成课程,包括示例,理论概念,工程技巧,技巧和最佳实践,以构建和培训解决您问题的神经网络。git
为软件工程师构建神经网络的基础知识。 神经权重和误差,激活函数,监督学习和梯度降低。
有效培训的技巧和最佳实践:学习率衰减,Dropout、正规化和过分拟合的复杂性。 密集和卷积神经网络。
此会话以低级Tensorflow开始,还包含使用图层和数据集的高级Tensorflow代码示例。 代码示例:MNIST手写数字识别,准确率达99%。 持续时间:55分钟github
在 codelab 项目中,你将学习如何构建并训练出可以识别手写数字(recognises handwritten digits)的神经网络。在这过程当中,当这个神经网络的准确度提高至 99%时,你还将学习到专业人员用来训练模型的高效工具。算法
这个 codelab 项目使用的是 MNIST 数据集,这个包含 60,000 个有标记数字的集合是几届博士努力近二十年的成果。你将会用不到 100 行的 Python/TensorFlow 代码来解决上述问题。express
你将学到:安全
对此,你将须要:网络
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
而后能够看到可视化的训练结果
dom
MNIST数据集中的手写数字是28x28像素灰度图像。 对它们进行分类的最简单方法是使用28x28 = 784像素做为单层神经网络的输入。
机器学习
神经网络中的每一个“神经元”对其全部输入进行加权求和,添加一个称为“偏置”的常数,而后经过一些非线性激活函数提供结果。
在这里,咱们设计了一个具备10个输出神经元的单层神经网络,由于咱们想要将数字分类为10个类(0到9)。
对于分类问题,运行良好的激活函数是 softmax
。 在矢量上应用 softmax
是经过取每一个元素的指数而后归一化矢量(使用任何范数,例如矢量的普通欧氏长度)来完成的。
如今,咱们将使用矩阵乘法将这一单层神经元的行为归纳为一个简单的公式。 让咱们直接进行100个图像的“小批量(mini-batch)”做为输入,产生100个预测(10个元素向量)做为输出。
咱们最终应用softmax激活函数并得到描述单层神经网络的公式,应用于100个图像:
如今须要计算预测结果与实际结果之间的误差,普通的欧几里德距离很好
可是对于分类问题,“交叉熵(cross-entropy)”更有效
"One-hot" 编码表示一个向量只有一个1,其他都为0
“训练”神经网络实际上意味着使用训练图像和标签来调整权重和误差,以便最小化交叉熵损失函数。
交叉熵是权重,误差,训练图像的像素及其已知标签的函数。
若是咱们相对于全部权重和全部误差计算交叉熵的偏导数,咱们得到“梯度”,针对给定图像,标签和权重和误差的现值计算。 请记住,咱们有7850个权重和误差,因此计算梯度听起来要作不少工做。 幸运的是,TensorFlow将为咱们作到这一点。
梯度的数学特性是它指向“向上”。 因为咱们想要去交叉熵低的地方,咱们走向相反的方向。 咱们经过梯度的一小部分更新权重和误差,并使用下一批训练图像再次执行相同的操做。 但愿这能让咱们到达交叉熵最小的坑的底部。
在该图中,交叉熵表示为2个权重的函数。 实际上,还有更多。 梯度降低算法遵循最速降低到局部最小值的路径。 训练图像也在每次迭代时改变,以便咱们收敛到适用于全部图像的局部最小值。
“学习率”:您没法在每次迭代时按梯度的整个长度更新权重和误差。 要到达底部,您须要执行较小的步骤,即仅使用渐变的一小部分,一般在1/1000区域中。 咱们称这个分数为“学习率”。
训练数字和标签=>损失函数=>渐变(偏导数)=>最速降低=>更新权重和误差=>重复下一批训练图像和标签
为何要使用100个图像和标签的“迷你批次”?
您只能在一个示例图像上计算梯度并当即更新权重和误差(在科学文献中称为“随机梯度降低”)。 在100个示例中这样作会给出一个梯度,该梯度更好地表示不一样示例图像所施加的约束,所以可能更快地收敛到解决方案。 尽管如此,小批量的大小是可调整的参数。 还有一个更技术性的缘由:使用批处理也意味着使用更大的矩阵,这些一般更容易在GPU上进行优化。
最终能够实现的准确率为 92%
为了提升识别精度,咱们将为神经网络添加更多层。这是一个5层彻底链接的神经网络:
咱们将 softmax
保持为最后一层的激活函数,由于这最适合分类。 然而,在中间层咱们将使用最经典的激活函数: sigmoid
最终能够实现的准确率为 97%
Sigmoid激活函数在深度网络中其实是很成问题的。 它会压缩0到1之间的全部值,当你反复这样作时,神经元输出和它们的梯度能够彻底消失。
RELU以下所示:
采用RuLU以后能够解决 “梯度爆炸” 问题,并且能够加快训练速度
在像这里这样的很是高维度的空间中 - 咱们有大约10K的重量和误差 - “马鞍点”是常见的。 这些点不是局部最小值,可是梯度为零而且梯度降低优化器仍然停留在那里。 TensorFlow拥有一整套可用的优化器,包括一些可使用惯性而且能够安全驶过鞍点的优化器。
准确度仍然保持在0.1? 你是否用随机值初始化了权重? 对于误差,当使用RELU时,最佳作法是将它们初始化为小的正值,以便神经元最初在RELU的非零范围内运行。
若是将迭代次数推至5000或更高,则使用两个,三个或四个中间层,如今能够得到接近98%的准确度。 可是你会发现结果不是很一致。
这些曲线很是嘈杂,看看测试的准确性:它的上下跳动百分之一。 这意味着即便学习率为0.003,咱们也会走得太快。 但咱们不能只将学习率除以10,不然培训须要永远。 好的解决方案是快速启动并将学习速率指数衰减到0.0001。
这一小变化的影响是巨大的。 您能够看到大部分噪音消失,测试精度如今持续超过98%。
最终能够实现的准确率为 98%
您将注意到,测试和训练数据的交叉熵曲线在几千次迭代后开始断开链接。 学习算法仅用于训练数据,并相应地优化训练交叉熵。 它永远不会看到测试数据,因此一段时间后它的工做再也不对测试交叉熵产生影响就不足为奇了,它会中止降低,有时甚至会反弹。
这不会当即影响模型的实际识别功能,但它会阻止您运行屡次迭代,而且一般代表训练再也不具备正面效果。 这种断开一般标记为“overfitting(过分拟合)”,当您看到它时,您能够尝试应用称为“dropout(丢失)”的 正则化技术
。
在每次训练迭代中,您从网络中丢弃随机神经元。 您选择保留神经元的几率保持,一般在50%和75%之间,而后在训练循环的每次迭代中,您随机移除具备全部重量和误差的神经元。 每次迭代都会丢弃不一样的神经元(你还须要按比例增长剩余神经元的输出,以确保下一层的激活不会发生变化)。 当你测试网络性能时,你会把全部神经元都放回去(pkeep = 1)。
你应该看到测试损失在很大程度上获得了控制,噪声再次出现,但至少在这种状况下,测试精度保持不变,这有点使人失望。
不管咱们作什么,咱们彷佛都没法以显着的方式突破98%的障碍,咱们的损失曲线仍然表现出“过分拟合”的脱节。 什么是“过分拟合”? 当神经网络以一种适用于训练示例但在实际数据上不太好的方式学习“严重”时,会发生过分拟合。 有一些正则化技术,如 Dropout,能够迫使它以更好的方式学习,但过分拟合也有更深层次的根源。
当神经网络对于手头的问题具备太多的自由度时,会发生基本过分拟合。想象一下,咱们有这么多神经元,网络能够将全部训练图像存储在其中,而后经过模式匹配识别它们。神经网络必须受到必定限制,以便强制推广它在训练期间学到的东西。
若是您的训练数据不多,即便是小型网络也能够用心去学习。通常来讲,您老是须要大量数据来训练神经网络。
最后,若是你已经作好了一切,尝试了不一样大小的网络,以确保其自由度受到限制,应用Dropout,并对大量数据进行训练,你可能仍然会陷入性能平台,彷佛没有任何东西可以提升。这意味着您的神经网络目前的形状没法从您的数据中提取更多信息,如咱们的案例所示。
还记得咱们如何使用咱们的图像,将全部像素平铺成单个矢量?这是一个很是糟糕的主意。手写数字由形状组成,当咱们平整像素时咱们丢弃了形状信息。然而,有一种神经网络能够利用形状信息:卷积网络。让咱们试试吧。
通过批量标准化后最终能够实现的准确率为 98.2%
在卷积网络的层中,一个“神经元”仅在图像的小区域上对其正上方的像素进行加权和。 而后经过添加误差并经过其激活功能馈送结果来正常动做。 最大的区别在于每一个神经元重复使用相同的权重,而在以前看到的彻底链接的网络中,每一个神经元都有本身的一组权重。
在上面的动画中,您能够看到经过在两个方向(卷积)上滑动图像的权重块,您能够得到与图像中的像素同样多的输出值(尽管边缘处须要一些填充)。
要使用4x4的色块大小和彩色图像做为输入生成一个输出值平面,就像在动画中同样,咱们须要4x4x3 = 48个权重。 这还不够。 为了增长更多的自由度,咱们用不一样的权重集重复相同的事情。
经过向张量添加维度,能够将两组(或更多组)权重重写为一组,这给出了卷积层的权重张量的通用形状。 因为输入和输出通道的数量是参数,咱们能够开始堆叠和连接卷积层。
在最后一层,咱们仍然只须要10个神经元来处理10类数字。 传统上,这是经过“最大池”层完成的。 即便今天有更简单的方法,“max-pooling”也有助于直观地理解卷积网络的运做方式:若是你认为在训练过程当中,咱们的小块权重会演变为识别基本形状的滤波器(水平和垂直线条,曲线,...... 。)而后向下挖出有用信息的一种方法是经过层保持最大强度识别形状的输出。 在实践中,在max-pool层中,神经元输出以2x2的组进行处理,而且仅保留一个最大的输出。
但有一种更简单的方法:若是您以2像素而不是1的步幅在图像上滑动补丁,则也会得到更少的输出值。 事实证实这种方法一样有效,而当今的卷积网络只使用卷积层。
让咱们创建一个手写数字识别的卷积网络。 咱们将在顶部使用三个卷积层,在底部使用传统的softmax读出层,并将它们与一个彻底链接的层链接:
请注意,第二个和第三个卷积层的步长为2,这就解释了为何它们将输出值的数量从28x28下降到14x14而后下降到7x7。 完成各层的大小调整,使每层神经元的数量大体减小两倍:28x28x4≈3000→14x14x8≈1500→7x7x12≈500→200。
最终能够实现的准确率为 98.9%
调整神经网络大小的一个好方法是实现一个有点过于受限的网络,而后给它更多的自由度并添加Droupout 以确保它不会过分拟合。 这最终会提供一个至关优化的网络。
所以,让咱们稍微提升patches大小,将卷积层中的patches数量从4,8,12增长到6,12,24,而后在彻底链接的层上添加 Droupout。 为何不在卷积层? 他们的神经元重复使用相同的权重,所以在一次训练迭代期间经过冻结一些权重而有效地工做的丢失对它们不起做用。
最终能够实现的准确率为 99.3%
上图所示的模型在10,000个测试数字中仅丢失了72个。 您能够在MNIST网站上找到的世界纪录大约为99.7%。 咱们的模型使用100行Python / TensorFlow构建,距离它只有0.4个百分点。
总而言之,这是咱们更大的卷积网络的差别。 为神经网络提供额外的自由度,使最终的准确率从98.9%提升到99.1%。 增长 Dropout 不只下降了测试损失,并且让咱们的准确率超过99%,甚至达到99.3%
输入数据的均值和方差与中心零点误差较大,须要对数据作批量标准化
随着网络的训练,网络会学到最合适的 α 和 β ,最终中间层的输出将服从均值为 β ,标准差为 α 的正态分布。
ϵ 的解释:为了不方差为 0 而加入的微小正数(eg:0.001)。
如今几乎全部的卷积神经网络都会使用批量标准化操做,它能够为咱们的网络训练带来一系列的好处。具体以下:
通过批量标准化后最终能够实现的准确率为 99.5%
改进方法 | 精度 | 过拟合程度 | 改进缘由 |
---|---|---|---|
单全链接+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% | 弱 | 下降过拟合 |