使用CNN(convolutional neural nets)检测脸部关键点教程(四):学习率,学习势,dropout_cnn预测关键角点-程序员宅基地

技术标签: CNN  deep-learning  机器学习  dropout  训练技巧  计算机视觉学习  momentum  

第七部分 让 学习率学习势 随着时间改变

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

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

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

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

NeuralNet允许我们在训练时通过on_epoch_finished钩子函数来更新参数。于是我们传一个函数给on_epoch_finished,使得这个函数在每次迭代之后被调用。然而,在我们改变学习率和学习势这两个参数之前,我们必须将这两个参数改变为Theano shared variables。好在这非常简单。

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)训练专项网络

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/tanhongguang1/article/details/46492519

智能推荐

Ubuntu16.04安装网易云音乐后无法打开_网易云安装包打不开-程序员宅基地

文章浏览阅读643次。问题描述:在网易云官网下载Linux ubuntu18.04 64位的deb安装包netease-cloud-music_1.2.1_amd64_ubuntu_20190428.deb后,使用sudo dpkg - i netease-cloud-music_1.2.1_amd64_ubuntu_20190428.deb命令成功安装,但是在搜索中找到NetEase-Cloud-Music软件后,点击打开,却无法进入网易云音乐软件界面,重试了几次都不行,在网上搜索后,看到如下两种解决方法:方法一:对于我的_网易云安装包打不开

西门子的相关资料下载_西门子营业执照下载-程序员宅基地

文章浏览阅读257次。http://www.gkong.com/zt/Siemens_plc_resource/_西门子营业执照下载

SpringBoot集成MariaDB(替换MySql)druid 数据库连接池_mysql-connector-java 替换 mariadb connector-程序员宅基地

文章浏览阅读5k次。使用 MariaDB 替换掉MySQL第一步:<!-- mariaDB Druid 数据库链接配置依赖 --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency> <groupId&g_mysql-connector-java 替换 mariadb connector

1000道Python题库系列分享-程序员宅基地

文章浏览阅读3w次,点赞76次,收藏607次。本文是汇总地址,推送了新的题库之后会在这里更新。1000道Python题库系列分享一(17道)1000道Python题库系列分享二(48道)1000道Python题库系列分享三(30道)1000道Python题库系列分享四(40道)1000道Python题库系列分享五(40道)1000道Python题库系列分享六(40道)1000道Python题库系列分享七(30..._python题库

进程间通信(四)信号量_union semum 参数的作用-程序员宅基地

文章浏览阅读179次。在多线程同步的方式中包含了信号量这一同步方法,但用于多线程同步的信号量是POSIXPOSIXPOSIX信号量,而用于进程间通信的则是SYSTEMSYSTEMSYSTEM VVV信号量,本质上说这两种都是用户态进程可以使用的信号量。创建信号量(1)在LinuxLinuxLinux中,使用函数semgetsemgetsemget来创建和打开信号量,函数原型:#include &lt;sys/ty..._union semum 参数的作用

Groovy & Groovy框架Grails-程序员宅基地

文章浏览阅读330次。Groovy百度百科:http://baike.baidu.com/view/707298.htm官方网站 :http://groovy.codehaus.org Groovy框架Grails Grails是一套用于快速Web应用开发的开源框架,它基于Groovy编程语言,并构建于Spring、Hibernate和其它标准Java框架之上,从而为大家带来一套能实现超高生..._groovy语言的第三方框架

随便推点

博客园markdown编辑器代码折叠-程序员宅基地

文章浏览阅读1.1k次。博客园设置里申请js权限。作用到侧边栏就可以,其他地方也行。只适配的markdown编辑器,与其他界面美化代码一起使用可能会出现bug。<script type="text/javascript"> $(document).ready(function () { var pres = $("pre"); for..._可折叠markdown 编辑器

SharedPreferences更改数据后取出来的值没有更改的问题_flutter sharedpreferences 保存了一个新的值,但是获取的还是原来的值-程序员宅基地

文章浏览阅读4.9k次,点赞2次,收藏3次。SharedPreferences 取值不正确开发中每次登录成功后都会获取一个服务器返回的Token,退出后再重新登录Token的值就会变化我发现在一个activity中每次获取的都是上一次的值,也就是退出在登录后在这个activity中获取的值还是上一次保存的值,这样就导致出现了bug,而其他activity读取都没有问题经过搜索一番发现我设置的SharedPreferences的m..._flutter sharedpreferences 保存了一个新的值,但是获取的还是原来的值

通话无法挂断问题_voice hangup-程序员宅基地

文章浏览阅读1.1k次。10:38:55.139 [9548]> HANGUP gsmIndex = 1 [SUB0] 10:39:11.345 [9549]> HANGUP gsmIndex = 1 [SUB0] 10:39:12.176 [9550]> HANGUP gsmIndex = 1 [SUB0] 10:39:12.571 [9551]> HANGUP gsmIndex = 1..._voice hangup

OK更新下载新版本模版_apk更新网页模版-程序员宅基地

文章浏览阅读267次。获取当前版本号:判断是否更新,是否强制更新:再进行下载新版本apkpublic class VersionUtils { public static String getVersionName(Context context) { String versionName = ""; PackageManager packageManager = conte_apk更新网页模版

python调用语音模块报错TypeError:NoneType takes no arguments-程序员宅基地

文章浏览阅读1.9k次,点赞3次,收藏2次。1.在python3.6.5目录中找到pythonwin文件夹eg:E:\Python\py16\Lib\site-packages\pythonwin2.在pythonwin文件夹下找到Pythonwin.exe文件3.双击Pythonwin.exe运行4.然后选择工具Tools/COM Makepy utility5.然后选择Microsoft Speech ObjectLib..._nonetype takes no arguments

国外火爆的Beacon为何在国内干不过二维码?_beacon 国内-程序员宅基地

文章浏览阅读1.3k次。微信摇一摇最火的时候,拿着手机随手一摇就能获取身边陌生人的信息或者Beacon推送的消息。在参观博物馆时,如果想详细了解藏品的信息,微信摇一摇就能收听语音导航、查看图文介绍,在给参观者带去便捷体验的同时,也增加了游览乐趣,让参观者能够更全面立体地了解文物历史。不过,随着微信逐渐弱化摇一摇功能,直至关闭,曾大火的Beacon摇一摇功能,如今却被二维码后来居上。无论是扫码付款,还是扫码关注店铺,二维码在国内已深入到了人们的日常生活中。在国内,Beacon应用为何由盛入衰,二维码为何后来居上,此次..._beacon 国内

推荐文章

热门文章

相关标签