第七部分 让 学习率学习潜能 随时间的变化

光训练就花了一个小时的时间。等结果并非一个令人心情愉快的事情。这一部分。我们将讨论将两个技巧结合让网络训练的更快!

直觉上的解决的方法是,開始训练时取一个较高的学习率,随着迭代次数的增多不停的减小这个值。这是有道理的,由于開始的时候我们距离全局最长处很远。我们想要朝着最长处的方向大步前进;然而里最长处越近,我们就前进的越慎重,以免一步跨过去。举个样例说就是你乘火车回家,但你进家门的时候肯定是走进去。不能让火车开进去。

从讨论深度学习中初始化和学习势的重要性的资料,我们得到了一种新的技巧来加速网络的训练:添加最优化方法的“动量參数”。假设你还不知道什么是学习势,请阅读【參考】。

在我们上一个模型中,我们将学习率和学习势初始化为0.01和0.9。让我们来改变这两个參数,使得学习率随着迭代次数线性减小。同一时候让学习势增大。

NeuralNet同意我们在训练时通过on_epoch_finished钩子函数来更新參数。于是我们传一个函数给on_epoch_finished,使得这个函数在每次迭代之后被调用。

然而。在我们改变学习率和学习势这两个參数之前,我们必须将这两个參数改变为Theano shared variables。

好在这很easy。

import theano

def float32(k):
return np.cast['float32'](k) net4 = NeuralNet(
# ...
update_learning_rate=theano.shared(float32(0.03)),
update_momentum=theano.shared(float32(0.9)),
# ...
)

我们传递的回调函数在调用时,须要两个參数:nn 是NeuralNet的实例,train_history,和nn.history是同一个值。

我们使用一个可參数化的类,在当中定义一个call函数来作为我们的回调函数。让我们把这个类叫做AdjustVariable,看一下这个类的实现:

class AdjustVariable(object):
def __init__(self, name, start=0.03, stop=0.001):
self.name = name
self.start, self.stop = start, stop
self.ls = None def __call__(self, nn, train_history):
if self.ls is None:
self.ls = np.linspace(self.start, self.stop, nn.max_epochs) epoch = train_history[-1]['epoch']
new_value = float32(self.ls[epoch - 1])
getattr(nn, self.name).set_value(new_value)

如今让我们把这些变化放到一起:

net4 = NeuralNet(
# ...
update_learning_rate=theano.shared(float32(0.03)),
update_momentum=theano.shared(float32(0.9)),
# ...
regression=True,
# batch_iterator_train=FlipBatchIterator(batch_size=128),
on_epoch_finished=[
AdjustVariable('update_learning_rate', start=0.03, stop=0.0001),
AdjustVariable('update_momentum', start=0.9, stop=0.999),
],
max_epochs=3000,
verbose=1,
) X, y = load2d()
net4.fit(X, y) with open('net4.pickle', 'wb') as f:
pickle.dump(net4, f, -1)

我们将训练两个网络:net4不适用之前的FlipBatchIterator。net5採用了。

除了这一点之外,两个网络全然相同。

Net4的学习步骤例如以下:

Epoch Train loss Valid loss Train / Val
50 0.004216 0.003996 1.055011
100 0.003533 0.003382 1.044791
250 0.001557 0.001781 0.874249
500 0.000915 0.001433 0.638702
750 0.000653 0.001355 0.481806
1000 0.000496 0.001387 0.357917

能够看到,训练速度快多了。

第500次、1000次迭代的训练错误。net4都比net2低了一半。可是泛华程度到750次就不再变好了,所以看起来没有必要训练这么多次。

看看打开了数据扩充之后的net5表现怎样:

Epoch Train loss Valid loss Train / Val
50 0.004317 0.004081 1.057609
100 0.003756 0.003535 1.062619
250 0.001765 0.001845 0.956560
500 0.001135 0.001437 0.790225
750 0.000878 0.001313 0.668903
1000 0.000705 0.001260 0.559591
1500 0.000492 0.001199 0.410526
2000 0.000373 0.001184 0.315353

相同的,和net3相比net5训练的快多了。并且获得了更好的结果。

在1000次迭代后,结果比net3迭代了3000次的效果还要好。此外,使用了数据扩充的网络的验证错误也比不使用数据扩充好了10%。

第八部分 丢弃技巧(Dropout)

2012年。这篇paper中引入了一种叫做“Dropout”的技巧,作为正则化方法,dropout工作的出奇的好。这里不会讲dropout之所以好用的细节,只是你能够阅读这些參考

和其它的正则化技巧一样。dropout仅仅有当网络过拟合的时候才有意义。上个部分我们训练的net5是明显过拟合的。注意一定要使你的网络过拟合,再使用正则化。

在Lasagne中使用正则化技巧。我们仅仅要在网络中加入DropoutLayer并指定每层dropout的概率。

这里是我们最新网络的完整定义,我在新加入的行后面加入了#。来标识与net5的不同。

net6 = NeuralNet(
layers=[
('input', layers.InputLayer),
('conv1', layers.Conv2DLayer),
('pool1', layers.MaxPool2DLayer),
('dropout1', layers.DropoutLayer), # !
('conv2', layers.Conv2DLayer),
('pool2', layers.MaxPool2DLayer),
('dropout2', layers.DropoutLayer), # !
('conv3', layers.Conv2DLayer),
('pool3', layers.MaxPool2DLayer),
('dropout3', layers.DropoutLayer), # !
('hidden4', layers.DenseLayer),
('dropout4', layers.DropoutLayer), # !
('hidden5', layers.DenseLayer),
('output', layers.DenseLayer),
],
input_shape=(None, 1, 96, 96),
conv1_num_filters=32, conv1_filter_size=(3, 3), pool1_pool_size=(2, 2),
dropout1_p=0.1, # !
conv2_num_filters=64, conv2_filter_size=(2, 2), pool2_pool_size=(2, 2),
dropout2_p=0.2, # !
conv3_num_filters=128, conv3_filter_size=(2, 2), pool3_pool_size=(2, 2),
dropout3_p=0.3, # !
hidden4_num_units=500,
dropout4_p=0.5, # !
hidden5_num_units=500,
output_num_units=30, output_nonlinearity=None, update_learning_rate=theano.shared(float32(0.03)),
update_momentum=theano.shared(float32(0.9)), regression=True,
batch_iterator_train=FlipBatchIterator(batch_size=128),
on_epoch_finished=[
AdjustVariable('update_learning_rate', start=0.03, stop=0.0001),
AdjustVariable('update_momentum', start=0.9, stop=0.999),
],
max_epochs=3000,
verbose=1,
)

我们的网路如今已经大到能够让python报一个“超过最大递归限制”错误了。所以为了避免这一点。我们最好添加python的递归限制。

import sys
sys.setrecursionlimit(10000) X, y = load2d()
net6.fit(X, y) import cPickle as pickle
with open('net6.pickle', 'wb') as f:
pickle.dump(net6, f, -1)

看一下我们如今的训练,我们注意到训练速度又变慢了,以为加入了dropout。这是不出意料的效果。然而。整个网络的表现其实超过了net5:

Epoch Train loss Valid loss Train / Val
50 0.004619 0.005198 0.888566
100 0.004369 0.004182 1.044874
250 0.003821 0.003577 1.068229
500 0.002598 0.002236 1.161854
1000 0.001902 0.001607 1.183391
1500 0.001660 0.001383 1.200238
2000 0.001496 0.001262 1.185684
2500 0.001383 0.001181 1.171006
3000 0.001306 0.001121 1.164100

仍然过拟合不一定是坏事,虽然我们必须小心这些数字:训练错误和验证错误的比率如今的意义稍有不同,由于训练错误是受过dropout调制的,而验证错误没有。更有比較意义的数值是:

from sklearn.metrics import mean_squared_error
print mean_squared_error(net6.predict(X), y) # prints something like 0.0010073791

在我们上一个没有dropout的模型里,训练集上的错误是0.00373。所以如今我们的dropout net不但表现稍好,并且过拟合水平更低。

这是好消息,由于我们能够通过使得网络更大获得更好的效果。这也正是我们接下来要做的。我们加倍网络最后两个隐层的单元个数。更新这两行:

net7 = NeuralNet(
# ...
hidden4_num_units=1000, # !
dropout4_p=0.5,
hidden5_num_units=1000, # !
# ...
)

相比于没有dropout的网络,改进效果更加明显:

Epoch Train loss Valid loss Train / Val
50 0.004756 0.007043 0.675330
100 0.004440 0.005321 0.834432
250 0.003974 0.003928 1.011598
500 0.002574 0.002347 1.096366
1000 0.001861 0.001613 1.153796
1500 0.001558 0.001372 1.135849
2000 0.001409 0.001230 1.144821
2500 0.001295 0.001146 1.130188
3000 0.001195 0.001087 1.099271

有一点过拟合,但效果着实不错。我的感觉是,假设继续添加训练次数,模型效果会变得更棒。

试一下:

net12 = NeuralNet(
# ...
max_epochs=10000,
# ...
)
Epoch Train loss Valid loss Train / Val
50 0.004756 0.007027 0.676810
100 0.004439 0.005321 0.834323
500 0.002576 0.002346 1.097795
1000 0.001863 0.001614 1.154038
2000 0.001406 0.001233 1.140188
3000 0.001184 0.001074 1.102168
4000 0.001068 0.000983 1.086193
5000 0.000981 0.000920 1.066288
6000 0.000904 0.000884 1.021837
7000 0.000851 0.000849 1.002314
8000 0.000810 0.000821 0.985769
9000 0.000769 0.000803 0.957842
10000 0.000760 0.000787 0.966583

如今你是dropout魔力的见证者了。:-)

让我们比較一下到眼下为止我们训练过的网络:

Name Description Epochs Train loss Valid loss
net1 single hidden 400 0.002244 0.003255
net2 convolutions 1000 0.001079 0.001566
net3 augmentation 3000 0.000678 0.001288
net4 mom + lr adj 1000 0.000496 0.001387
net5 net4 + augment 2000 0.000373 0.001184
net6 net5 + dropout 3000 0.001306 0.001121
net7 net6 + epochs 10000 0.000760 0.000787

使用CNN(convolutional neural nets)检測脸部关键点教程(一):环境搭建和数据

使用CNN(convolutional neural nets)检測脸部关键点教程(二):浅层网络训练和測试

使用CNN(convolutional neural nets)检測脸部关键点教程(三):卷积神经网络训练和数据扩充

使用CNN(convolutional neural nets)检測脸部关键点教程(五):通过前训练(pre-train)训练专项网络

使用CNN(convolutional neural nets)关键的一点是检测到的面部教程(四):学习率,学习潜能,dropout的更多相关文章

  1. (zhuan) Using convolutional neural nets to detect facial keypoints tutorial

    Using convolutional neural nets to detect facial keypoints tutorial   this blog from: http://danieln ...

  2. CNN(Convolutional Neural Network)

    CNN(Convolutional Neural Network) 卷积神经网络(简称CNN)最早可以追溯到20世纪60年代,Hubel等人通过对猫视觉皮层细胞的研究表明,大脑对外界获取的信息由多层的 ...

  3. 卷积神经网络CNN(Convolutional Neural Networks)没有原理只有实现

    零.说明: 本文的所有代码均可在 DML 找到,欢迎点星星. 注.CNN的这份代码非常慢,基本上没有实际使用的可能,所以我只是发出来,代表我还是实践过而已 一.引入: CNN这个模型实在是有些年份了, ...

  4. Large-Scale Oil Palm Tree Detection from High-Resolution Satellite Images Using Two-Stage Convolutional Neural Networks(worldview油棕树检测)

    不是目标检测也不是语义分割,两步CNN指的是,采集的数据是一堆点,以点为中心的65*65和17*17图像范围大小来判断这个点是否是油棕树.第一步就是判断65*65的范围是否为(油棕树植被群,其他植被/ ...

  5. 一目了然卷积神经网络 - An Intuitive Explanation of Convolutional Neural Networks

    An Intuitive Explanation of Convolutional Neural Networks 原文地址:https://ujjwalkarn.me/2016/08/11/intu ...

  6. [转]An Intuitive Explanation of Convolutional Neural Networks

    An Intuitive Explanation of Convolutional Neural Networks https://ujjwalkarn.me/2016/08/11/intuitive ...

  7. An Intuitive Explanation of Convolutional Neural Networks

    https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/ An Intuitive Explanation of Convolu ...

  8. Deep learning_CNN_Review:A Survey of the Recent Architectures of Deep Convolutional Neural Networks——2019

    CNN综述文章 的翻译 [2019 CVPR] A Survey of the Recent Architectures of Deep Convolutional Neural Networks 翻 ...

  9. 卷积神经网络(Convolutional Neural Network, CNN)简析

    目录 1 神经网络 2 卷积神经网络 2.1 局部感知 2.2 参数共享 2.3 多卷积核 2.4 Down-pooling 2.5 多层卷积 3 ImageNet-2010网络结构 4 DeepID ...

随机推荐

  1. 【翻译mos文章】Linux x86 and x86-64 系统SHMMAX最大

    Linux x86 and x86-64 系统SHMMAX最大值 参考原始: Maximum SHMMAX values for Linux x86 and x86-64 (文件 ID 567506. ...

  2. Dictionary带来的一种隐式内存泄漏

    当心Dictionary带来的一种隐式内存泄漏 最近在看Dictionary的源代码的时候, 突然想到Dictionary的不当使用中有一种隐含内存泄漏的可能. 简化使用场景 小A正在写一个简单的图书 ...

  3. newinstance()和new有什么区别?(转)

    在初始化一个类,生成一个实例的时候:newInstance() 和 new 有什么区别? 用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有 ...

  4. 矩形类定义【C++】

    Description 定义一个矩形类,数据成员包括左下角和右上角坐标,定义的成员函数包括必要的构造函数.输入坐标的函数,以及计算并输出矩形面积的函数.要求使用提示中给出的测试函数并不得改动. Inp ...

  5. JFrame、JDialog close

    package common; import javax.swing.JFrame; import javax.swing.SwingUtilities; /*2015-5-26*/ public c ...

  6. [LeetCode92]Reverse Linked List II

    题目: Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:Given 1- ...

  7. SQL Server 版本号汇总

    通过SSMS连接Sql servr,查看实例的版本就能知道当前SQL Server的版本号了.   RTM (no SP) SP1 SP2 SP3 SP4  SQL Server 2014     c ...

  8. android登陆接口调试

    最近项目要开始调API,于是自己写了个关于登陆界面调试的Demo,为了保护项目,接口文档里面的内容都是被我改过的,不涉及任何项目内容.当然,代码在运行成功后,上传至博客前,相应内容我也根据改过后的文档 ...

  9. Objective-C语言的一些基础特性

    OC与C++.Java等面向对象语言有很多的类似之处,不过在很多方面也是有所差别的.若是用过某一种面向对象语言,那么就很容易理解OC语言所用的范式和模板了.但是在语法使用上,也许会显得陌生.因为OC语 ...

  10. Twitter 新一代流处理工具——Heron 该纸币Storm Limitations

    Twitter 新一代流处理工具--Heron 该纸币Storm Limitations (空格分隔): Streaming-Processing Storm Problems scalability ...