技术标签: 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%。
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)训练专项网络
文章浏览阅读386次。ROS常用工具仿真:Gazebo调试、可视化:Rviz、rqt命令行工具:rostopic、rosbag…专用工具:Moveit!Gazebo机器人仿真工具、ODE物理引擎、用于动力学,导航,感知等任务的模拟RVizThe Robot Visualization tool 可视化工具 方便监控和调试把一些抽象的传感器信息以图像的方式传送给我们,便于进行开发和调试rqt可视..._rviz gazebo rqt_bag
文章浏览阅读603次。Java层获取权限:void GetExternalStoragePermission(){ if(!CheckExternalStoragePermission()) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission..._android 获取sd卡权限
文章浏览阅读193次。jQuery的事件方法相比于js代码来说没有太大的区别,最大的区别就去去掉on,以及一些特殊的例子。例如鼠标事件中的hover的使用。hoverhover() 方法可以看做是mouseenter 和 mouseleave两个函数的结合,当只传入一个参数的时候,会在鼠标进入和离开指定元素时都执行参数函数,如果传入两个参数则是在进入指定元素时执行第一个函数,在离开指定元素时执行第二个函数。例如: $( ".div" ).hover( a, b) 当进入指定div标签时执行a函数,当离开指定div标._jquery常用事件
文章浏览阅读7.8k次,点赞10次,收藏24次。这个问题个人也看的不太懂,参考百科上的计算说明,把它转化成相应成代码即可.埃尔米特插值是另一类插值问题,这类插值在给定的节点处,不但要求插值多项式的函数值与被插函数的函数值相同。同时还要求在节点处,插值多项式的一阶直至指定阶的导数值,也与被插函数的相应阶导数值相等,这样的插值称为埃尔米特插值,或称为Hermite插值。 Hermite插值在不同的节点,提出的差值条件个数可以不同,若在某节点xi,要求_hermit插值 c语言
文章浏览阅读8.2k次。这是我第一次尝试设置一些虚拟机。 我正在尝试rdp给他们,但我遇到了这个错误This is my first attempt in setting up some VMs. I am trying to rdp to them but I'm encountering this error**远程桌面无法找到计算机"\[服务器\]"。 这可能意味着"\[服务器\]"。 不属于指定的网络。 验证您尝..._远程桌面无法找到计算机 不属于指定网络
文章浏览阅读8.9k次,点赞9次,收藏24次。idea类存在找不到解决办法996的程序猿 2019-01-09 13:23:07 51954 收藏 101分类专栏: 工具类 文章标签: idea 找不到类 idea 找不到符号版权1.刷新maven项目2.清理idea缓存3.maven clean install4.重新bulid5.如果使用了lombok插件开启之后重新build6.maven依赖冲突导致1.打开当前maven模块或者,父类模块对应的pom,哪个模块有冲突进入那个模块!2.ctlr+alt+shif_idea 找不到类
文章浏览阅读1.2w次。最近在调试一个设备,非常的吵,决定把风扇转速调低,降低噪音。这篇文章可能不具有通用性,仅自己记录,用作以后参考。风扇的转速通过pwm调节,因此先找下有没有pwm模块:ls /sys/class/hwmon/hwmon*/对应路径下找不到pwm的话,说明模块没有加载,需要编译模块,加载后才可以到 https://www.kernel.org/ 下载内核源码windows下通过ssh连接运行linux..._nct6775
文章浏览阅读5.4k次,点赞7次,收藏21次。实验环境:Cisco Packet Tracer Student 6.2.0.0052 全局模式下show run显示如下配置:--------------------------------------------------全局模式---------------------------------------------------------路由器:cisco 2620XM 配置_cisco 实验 单臂路由器配置
文章浏览阅读1.8k次。学习来源:狂神说JavaDocker基本组成原理镜像(image)docker镜像就好比是一个模版,可以通过这个模版创建容器服务,tomcat===》run===〉tomcat01容器(提供服务),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就在容器中)。容器(container)Docker利用容器技术,独立运行一个或一组应用,通过镜像来创建。启动,停止,删除等基本命令,目前可以将这个容器理解为一个简易的Linux。仓库(repository)仓库就是存放镜像的地方。_when using add with more than one source file, the destination must be a dir
文章浏览阅读2w次,点赞47次,收藏224次。AD20内电层电源分割实例。我们通常会在 元件布局合理,且不影响其他信号线走线的情况下。将大电流的电源放在 Top、Bottom层,使用多边形铺铜进行电源分割。而内电层的电源分割操作方法与 Top、Bottom层不同(内电层不能使用多边形铺铜)。这里有一个实例,借由实例的操作来讲述AD20的 内电层电源分割 方式。AD20内电层的电源分割实例图中标记的网络 VIN,受限于元件及布局的遮挡,不容易从Top层进行铺铜连线。于是打算通过第3层 -PWR层 ,用电源分割的方式实现网络连接。1_内电层分割
文章浏览阅读1.2k次。1 前言年初做了一款Android TV 应用,用到了MQTT。主要实现的是类似一些景区利用大屏幕实时显示景点人数,超过人数就不允许进入。即利用闸机设备监控到进景区的游客,然后通过MQTT将消息发送给大屏幕,最后大屏幕实时显示景区人数,并响应一个消息通知闸机设备已经收到了它发过来的消息(确保消息到达)。这篇文章会模拟真实的使用流程进行讲解,即闸机发布消息——服务器(代理)收到消息转发给大屏幕—..._github android tv 推送消息
文章浏览阅读1.9k次,点赞3次,收藏17次。hive-third-functions参考文献:https://github.com/aaronshan/hive-third-functions/blob/master/README-zh.md简介hive-third-functions 包含了一些很有用的hive udf函数,特别是数组和json函数.注意:hive-third-functions支持hive-0.11.0或更高..._hive array_distinct