吴恩达深度学习课程之第二门课 改善深层神经网络 第 三 周 超 参 数 调 试 、 Batch 正 则 化 和 程 序 框 架

本文参考黄海广主编针对吴恩达深度学习课程DeepLearning.ai 《深度学习课程 笔记 (V5.1 )》

第 三 周 超 参 数 调 试 、 Batch 正 则 化 和 程 序 框 架
( Hyperparameter tuning)

3.1 调试处理(Tuning process )

神经网络的改变会涉及到许多不同超参数的设置。现在,对于超参数而言,你要如何找到一套好的设定呢?分享一些指导原则,一些关于如何系统地组织超参调试过程的技巧。

红色最重要,橙色第二重要,紫色第三重要,第三行可以固定

关于训练深度最难的事情之一是你要处理的参数的数量,从学习速率到 Momentum(动量梯度下降法)的参数。

使用的不是单一的学习率a。最为广泛的学习应用是a,学习速率是需要调试的最重要的超参数

现在,如果你尝试调整一些超参数,该如何选择调试值呢?在早一代的机器学习算法中,如果你有两个超参数常见的做法是在网格中取样点,然后系统的研究这些数值。可以随机选择点,用这些随机取的点试验超参数的效果。

我已经解释了两个参数的情况,实践中,你搜索的超参数可能不止两个。假如,你有三个超参数,这时你搜索的不是一个方格,而是一个立方体,超参数 3 代表第三维,接着,在三维立方体中取值,你会试验大量的更多的值,三个超参数中每个都是。 

实践中,你搜索的可能不止三个超参数有时很难预知,哪个是最重要的超参数,对于你的具体应用而言,随机取值而不是网格取值表明,你探究了更多重要超参数的潜在值,无论结果是什么。

当你给超参数取值时,另一个惯例是采用由粗糙到精细的策略。

比如在二维的那个例子中,你进行了取值,也许你会发现效果最好的某个点,也许这个点周围的其他一些点效果也很好,那在接下来要做的是放大这块小区域(小蓝色方框内),然后在其中更密集得取值或随机取值,聚集更多的资源,在这个蓝色的方格中搜索,如果你怀疑这些超参数在这个区域的最优结果,那在整个的方格中进行粗略搜索后,你会知道接下来应该聚焦到更小的方格中。在更小的方格中,你可以更密集得取点。所以这种从粗到细的搜索也经常使用。
通过试验超参数的不同取值,你可以选择对训练集目标而言的最优值,或对于开发集而言的最优值,或在超参搜索过程中你最想优化的东西。
我希望,这能给你提供一种方法去系统地组织超参数搜索过程。另一个关键点是随机取值和精确搜索,考虑使用由粗糙到精细的搜索过程。

3.2 为超参数选择合适的范围(Using an appropriate scale to pick hyperparameters )

在超参数范围中,随机取值可以提升你的搜索效率。但随机取值并不是在有效范围内的随机均匀取值,而是选择合适的标尺,用于探究这些超参数,这很重要。

对数标尺搜索超参数的方式会更合理,因此这里不使用线性轴,分别依次取0.0001,0.001,0.01,0.1,1,在对数轴上均匀随机取点。

3.3 超参数训练的实践:Pandas VS Caviar (Hyperparameters tuning in practice: Pandas vs. Caviar )

如今的深度学习已经应用到许多不同的领域,某个应用领域的超参数设定,有可能通用于另一领域,不同的应用领域出现相互交融。
深度学习领域中,跨领域去寻找灵感。也许已经找到一组很好的参数设置,并继续发展算法,或许在几个月的过程中,观察到你的数据会逐渐改变,或也许只是在你的数据中心更新了服务器,正因为有了这些变化,你原来的超参数的设定不再好用,所以我建议,或许只是重新测试或评估你的超参数,至少每隔几个月一次,以确保你对数值依然很满意。
最后,关于如何搜索超参数的问题,我见过大概两种重要的思想流派或人们通常采用的两种重要但不同的方式。

一种是你照看一个模型,通常是有庞大的数据组,但没有许多计算资源或足够的 CPU 和GPU 的前提下,基本而言,你只可以一次负担起试验一个模型或一小批模型,在这种情况下,即使当它在试验时,你也可以逐渐改良。比如,第 0 天,你将随机参数初始化,然后开始试验,然后你逐渐观察自己的学习曲线,也许是损失函数 J,或者数据设置误差或其它的东西,在第 1 天内逐渐减少,试着增加一点学习速率,每天,你都会观察它,不断调整你的参数。也许有一天,你会发现你的学习率太大了,所以你可能又回归之前的模型,像这样,但你可以说是在每天花时间照看此模型,即使是它在许多天或许多星期的试验过程中。所以这是一个人们照料一个模型的方法,观察它的表现,耐心地调试学习率,但那通常是因为你没有足够的计算能力,不能在同一时间试验大量模型时才采取的办法。

另一种方法则是同时试验多种模型,你设置了一些超参数,尽管让它自己运行,或者是一天甚至多天,然后你会获得像这样的学习曲线,这可以是损失函数 J 或实验误差或损失或数据误差的损失,但都是你曲线轨迹的度量。同时你可以开始一个有着不同超参数设定的不同模型。

所以这两种方式的选择,是由你拥有的计算资源决定的,如果你拥有足够的计算机去平行试验许多模型,那绝对采用第二种方式,尝试许多不同的超参数,看效果怎么样。但在一些应用领域,比如在线广告设置和计算机视觉应用领域,那里的数据太多了,你需要试验大量的模型,所以同时试验大量的模型是很困难的,它的确是依赖于应用的过程。

所以希望你能学会如何进行超参数的搜索过程,现在,还有另一种技巧,能使你的神经网络变得更加坚实,它并不是对所有的神经网络都适用,但当适用时,它可以使超参数搜索变得容易许多并加速试验过程,我们在下个视频中再讲解这个技巧。

3.4 归一化网络的激活函数(Normalizing activations in a network )

在深度学习兴起后,最重要的一个思想是它的一种算法,叫做 Batch 归一化,Batch归一化会使你的参数搜索问题变得很容易
使神经网络对超参数的选择更加稳定,超参数的范围会更加庞大,工作效果也很好,也会是你的训练更加容易,甚至是深层网络。让我们来看看 Batch 归一化是怎么起作用的吧。

当训练一个模型,比如 logistic 回归时,你也许会记得,归一化输入特征可以加快学习过程。你计算了平均值,从训练集中减去平均值,计算了方差,接着根据方差归一化你的数据集,在之前的视频中我们看到,这是如何把学习问题的轮廓,从很长的东西,变成更圆的东西,更易于算法优化。所以这是有效的,对 logistic 回归和神经网络的归一化输入特征值而言。

所以我希望你学到的是,归一化输入特征X是怎样有助于神经网络中的学习,Batch 归一化的作用是它适用的归一化过程,不只是输入层,甚至同样适用于神经网络中的深度隐藏层。你应用 Batch 归一化了一些隐藏单元值中的平均值和方差,不过训练输入和这些隐藏单元值的一个区别是,你也许不想隐藏单元值必须是平均值 0 和方差 1。

比如,如果你有 sigmoid 激活函数,你不想让你的值总是全部集中,你想使它们有更大的方差,或不是 0 的平均值,以便更好的利用非线性的 sigmoid 函数,而不是使所有的值都集中于这个线性版本中,这就是为什么有了𝛿和𝛾两个参数后,你可以确保所有的Z (i)值可以是你想赋予的任意值,或者它的作用是保证隐藏的单元已使均值和方差标准化。那里,均值和方差由两参数控制,即𝛿和𝛾,学习算法可以设置为任何值,所以它真正的作用是,使隐藏单元值的均值和方差标准化,即Z (I) 有固定的均值和方差,均值和方差可以是 0 和 1,也可以是其它值,它是由𝛿和𝛾两参数控制的。

3.5 将 Batch Norm 拟合进神经网络(Fitting Batch Norm into a neural network )

你已经看到那些等式,它可以在单一隐藏层进行 Batch 归一化,接下来,让我们看看它是怎样在深度网络训练中拟合的吧。

 

即使在之前的视频中,我已经解释过 Batch 归一化 是怎么操作的,计算均值和方差,减去均值,再除以方差,如果它们使用的是深度学习编程框架,通常你不必自己把 Batch 归一化步骤应用于 Batch 归一化层。因此,探究框架,可写成一行代码,比如说,在 TensorFlow框架中,你可以用这个函数( tf.nn.batch_normalization )来实现 Batch 归一化。在深度学习框架中,Batch 归一化的过程,经常是类似一行代码的东西。 

实践中,Batch 归一化通常和训练集的 mini-batch 一起使用。

3.6 Batch Norm 为什么奏效?(Why does Batch Norm work?)

为什么 Batch 归一化会起作用呢?
一个原因是,你已经看到如何归一化输入特征值,使其均值为 0,方差 1,有一些从 0 到 1 而不是从 1 到 1000 的特征值,通过归一化所有的输入特征值,以获得类似范围的值,可以加速学习。所以 Batch 归一化起的作用的原因,直观的一点就是,它在做类似的工作,但不仅仅对于这里的输入值,还有隐藏单元的值,这只是 Batch归一化作用的冰山一角,还有些深层的原理,它会有助于你对 Batch 归一化的作用有更深的理解,让我们一起来看看吧。
Batch 归一化有效的第二个原因是,它可以使权重比你的网络更滞后或更深层,比如,第 10 层的权重更能经受得住变化,相比于神经网络中前层的权重,比如第 1 层,为了解释我的意思,让我们来看看这个最生动形象的例子。 

 

这是一个网络的训练,也许是个浅层网络,比如 logistic 回归或是一个神经网络。或一个深层网络,建立在我们著名的猫脸识别检测上,但假设你已经在所有黑猫的图像上训练了数据集,如果现在你要把此网络应用于有色猫,这种情况下,正面的例子不只是左边的黑猫,还有右边其它颜色的猫,那么你的 cosfa 可能适用的不会很好

如果图像中,你的训练集是这个样子的,你的正面例子在这儿,反面例子在那儿(左图),但你试图把它们都统一于一个数据集,也许正面例子在这,反面例子在那儿(右图)。你也许无法期待,在左边训练得很好的模块,同样在右边也运行得很好,即使存在运行都很好的同一个函数,但你不会希望你的学习算法去发现绿色的决策边界,如果只看左边数据的话。

所以使你数据改变分布的这个想法,有个有点怪的名字“Covariate shift”,想法是这样的,如果你已经学习了x到y 的映射,如果𝑦 的分布改变了,那么你可能需要重新训练你的学习算法。

 Batch 归一化减少了输入值改变的问题,它的确使这些值变得更稳定,神经网络的之后层就会有更坚实的基础。即使使输入分布改变了一些,它会改变得更少。它做的是当前层保持学习,当改变时,迫使后层适应的程度减小了,你可以这样想,它减弱了前层参数的作用与后层参数的作用之间的联系,它使得网络每层都可以自己学习,稍稍独立于其它层,这有助于加速整个网络的学习。

所以,希望这能带给你更好的直觉,重点是 Batch 归一化的意思是,尤其从神经网络后层之一的角度而言,前层不会左右移动的吧么多,因为它们被同样的均值和方差所限制,所以,这会使得后层的学习工作变得更容易些。

所以和 dropout 相似,它往每个隐藏层的激活值上增加了噪音,dropout 有增加噪音的方式,它使一个隐藏的单元,以一定的概率乘以 0,以一定的概率乘以 1,所以你的 dropout含几重噪音,因为它乘以 0 或 1。 

对比而言,Batch 归一化含几重噪音,因为标准偏差的缩放和减去均值带来的额外噪音。这里的均值和标准差的估计值也是有噪音的,所以类似于 dropout,Batch 归一化有轻微的正则化效果,因为给隐藏单元添加了噪音,这迫使后部单元不过分依赖任何一个隐藏单元,类似于 dropout,它给隐藏层增加了噪音,因此有轻微的正则化效果。因为添加的噪音很微小,所以并不是巨大的正则化效果,你可以将 Batch 归一化和 dropout 一起使用,如果你想得到 dropout 更强大的正则化效果。

3.7 测试时的 Batch Norm (Batch Norm at test time)

Batch 归一化将你的数据以 mini-batch 的形式逐一处理,但在测试时,你可能需要对每个样本逐一处理,我们来看一下怎样调整你的网络来做到这一点。

3.8 Softmax 回归(Softmax regression )

如果我们有多种可能的类型的话呢?有一种 logistic回归的一般形式,叫做 Softmax 回归,能让你在试图识别某一分类时做出预测,或者说是多种分类中的一个,不只是识别两个分类 

 

最后必须输出四个数字,给你这四种概率,因为它们加起来应该等于 1,输出中的四个数字加起来应该等于 1。
让你的网络做到这一点的标准模型要用到 Softmax 层,以及输出层来生成输出,让我把式子写下来,然后回过头来,就会对 Softmax 的作用有一点感觉了。

 

这个例子中(左边图),原始输入只有x 1 和x 2 ,一个C = 3个输出分类的 Softmax 层能够代表这种类型的决策边界,请注意这是几条线性决策边界,但这使得它能够将数据分到 3个类别中,在这张图表中,我们所做的是选择这张图中显示的训练集,用数据的 3 种输出标签来训练 Softmax 分类器,图中的颜色显示了 Softmax 分类器的输出的阈值,输入的着色是基于三种输出中概率最高的那种。因此我们可以看到这是 logistic 回归的一般形式,有类似线性的决策边界,但有超过两个分类,分类不只有 0 和 1,而是可以是 0,1 或 2。

我们来看一下更多分类的例子,这个例子中(左边图)C = 4,因此这个绿色分类和Softmax 仍旧可以代表多种分类之间的这些类型的线性决策边界。另一个例子(中间图C = 5类,最后一个例子(右边图)是C = 6,这显示了 Softmax 分类器在没有隐藏层的情况下能够做到的事情,当然更深的神经网络会有x,然后是一些隐藏单元,以及更多隐藏单元等等,你就可以学习更复杂的非线性决策边界,来区分多种不同分类。

3.9 训练一个 Softmax 分类器(Training a Softmax classifier)

上一个视频中我们学习了 Softmax 层和 Softmax 激活函数,在这个视频中,你将更深入地了解 Softmax 分类,并学习如何训练一个使用了 Softmax 层的模型

 

 

3.10 深度学习框架(Deep Learning frameworks)

现在有很多好的深度学习软件框架,可以帮助你实现这些模型。类比一下,我猜你知道如何做矩阵乘法,你还应该知道如何编程实现两个矩阵相乘,但是当你在建很大的应用时,你很可能不想用自己的矩阵乘法函数,而是想要访问一个数值线性代数库,它会更高效,但如果你明白两个矩阵相乘是怎么回事还是挺有用的。我认为现在深度学习已经很成熟了,利用一些深度学习框架会更加实用,会使你的工作更加有效,那就让我们来看下有哪些框架。

选择框架的标准:

一个重要的标准就是便于编程,这既包括神经网络的开发和迭代,还包括为产品进行配置,为了成千上百万,甚至上亿用户的实际使用,取决于你想要做什么。

第二个重要的标准是运行速度,特别是训练大数据集时,一些框架能让你更高效地运行和训练神经网络。
还有一个标准人们不常提到,但我觉得很重要,那就是这个框架是否真的开放,要是一个框架真的开放,它不仅需要开源,而且需要良好的管理。

但至少在短期内,取决于你对语言的偏好,看你更喜欢 Python,Java 还是 C++或者其它什么,也取决于你在开发的应用,是计算机视觉,还是自然语言处理或者线上广告,等等,我认为这里的多个框架都是很好的选择。

 

import numpy as np
import tensorflow as tf
#导入 TensorFlow
w = tf.Variable(0,dtype = tf.float32)
#接下来,让我们定义参数 w,在 TensorFlow 中,你要用 tf.Variable()来定义参数
#然后我们定义损失函数:
cost = tf.add(tf.add(w**2,tf.multiply(- 10.,w)),25)
#然后我们定义损失函数 J
#然后我们再写:
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)
#(让我们用 0.01 的学习率,目标是最小化损失)。
#最后下面的几行是惯用表达式:
init = tf.global_variables_initializer()
session = tf.Sessions()#这样就开启了一个 TensorFlow session。
session.run(init)#来初始化全局变量。
#然后让 TensorFlow 评估一个变量,我们要用到:
session.run(w)
#上面的这一行将 w 初始化为 0,并定义损失函数,我们定义 train 为学习算法,它用
梯度下降法优化器使损失函数最小化,但实际上我们还没有运行学习算法,所以#上面
的这一行将 w 初始化为 0,并定义损失函数,我们定义 train 为学习算法,它用梯度下
降法优化器使损失函数最小化,但实际上我们还没有运行学习算法,所以
session.run(w)评估了 w,让我::
print(session.run(w))
#所以如果我们运行这个,它评估𝑥等于 0,因为我们什么都还没运行。
#现在让我们输入:
session.run(train),它所做的就是运行一步梯度下降法。
#接下来在运行了一步梯度下降法后,让我们评估一下 w 的值,再 print:
print(session.run(w))
#在一步梯度下降法之后,w 现在是 0.1。

 一旦𝑥被称为 TensorFlow 变量,平方,乘法和加减运算都重载了,因此你不必使用上面这种不好看的句法。TensorFlow 还有一个特点,我想告诉你,那就是这个例子将𝑥的一个固定函数最小化了。
如果你想要最小化的函数是训练集函数又如何呢?不管你有什么训练数据x,当你训练神经网络时,训练数据𝑦会改变,那么如何把训练数据加入 TensorFlow 程序呢?
我会定义x,把它想做扮演训练数据的角色,事实上训练数据有x和y,但这个例子中只有x,把x定义为:

x = tf.placeholder(tf.float32,[3,1]) 
#让它成为[3,1]数组
cost = x[0][0]*w**2 +x[1][0]*w + x[2][0]
#现在x变成了控制这个二次函数系数的数据,这个 placeholder 函数告诉 TensorFlow,你稍后会为x提供数值。
coefficient = np.array([[1.],[-10.],[25.]]) 
#现在如果你想改变这个二次函数的系数,改为coefficient = np.array([[1.],[-20.],[100.]])
#这就是我们要接入x的数据。
#最后我们需要用某种方式把这个系数数组接入变量x,做到这一点
的句法是,在训练这一步中,要提供给x的数值,我在这里设置:
feed_dict = {x:coefficients}

TensorFlow 的优点在于,通过用这个计算损失,计算图基本实现前向传播,TensorFlow已经内置了所有必要的反向函数,这也是为什么通过内置函数来计算前向函数,它也能自动用反向函数来实现反向传播,即便函数非常复杂,再帮你计算导数,这就是为什么你不需要明确实现反向传播,这是编程框架能帮你变得高效的原因之一。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clark-dj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值