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

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

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

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

在我们上一个模型中,我们将学习率和学习势初始化为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. udacity android 学习笔记: lesson 4 part b

    udacity android 学习笔记: lesson 4 part b 作者:干货店打杂的 /titer1 /Archimedes 出处:https://code.csdn.net/titer1 ...

  2. 制作service服务,shell脚本小例子(来自网络)

    事先准备工作:源码安装apache .安装目录为/usr/local/httpd 任务需求:1.可通过 service httpd start|stop|status|restart 命令对服务进行控 ...

  3. HDU4866 Shooting (要持久段树)

    意甲冠军: 给你一些并行x行轴.总是询问坐标x的顶部之前,k一个段高度,.标题是必须在线. 思路: 首先要会可持久化线段树(又称主席树和函数式线段树).不会的能够去做下POJ 2104. 把全部线段高 ...

  4. Lua基础(转)

    局部定义与代码块: 使用local声明一个局部变量或局部函数,局部对象只在被声明的那个代码块中有效. 代码块:一个控制结构.一个函数体.一个chunk(一个文件或文本串)(Lua把chunk当做函数处 ...

  5. 有人实践过 Phabricator 以及 Arcanist 作为 code review 的工具么?(转)

    作者:覃超链接:http://www.zhihu.com/question/19977889/answer/13539702来源:知乎 平时就经常实践. 整个公司的code review就是使用这个. ...

  6. thinkphp达到UploadFile.class.php图片上传功能

    片上传在站点里是非经常常使用的功能.ThinkPHP里也有自带的图片上传类(UploadFile.class.php) 和图片模型类(Image.class.php).方便于我们去实现图片上传功能,以 ...

  7. 用AsyncTask实现多线程

    前言 在Android应用开发中,有时我们需要实现任务的同步.Android里的AsyncTask类可以帮我们更好地管理线程同步(异步方式),就像Thread类能做的,不过用法比Thread更简单. ...

  8. 为应用程序池 'DefaultAppPool' 提供服务的进程关闭时间超过了限制

    服务器经常产生“应用程序池 'DefaultAppPool' 提供服务的进程关闭时间超过了限制.进程 ID 是 '2068'.”的错误,导致iis处于假死状态,经了解是IIS应用程序池的设置问题.解决 ...

  9. XXTEA 加密算法 C++ C#兼容版本号

    1.一个不错的可逆加密算法XXTEA 之前无意中看到了TexturePacker 使用了XXTEA来加密图片资源.所以花了点时间来看了下XXTEA. 一般有两种加密算法:1.像md5,SHA1,等ha ...

  10. cocos2d-x lua 学习笔记(1) -- 环境结构

    Cocos2d-x 3.0超过环境的版本号来建立和前Cocos2d-x 2.0 差异较大的版本,从同时Cocos2d-x 3.0项目打包成apkAndroid的应用程序文件,步骤,构建环境有些乏味安德 ...