使用CNN(convolutional neural nets)检测脸部关键点教程(四)

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

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

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

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

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

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

import theano: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,看一下这个类的实现:

:, stop=0.001):self.name = nameself.start, self.stop = start, stopself.ls = :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,)所有欺骗中,自欺是最为严重的

使用CNN(convolutional neural nets)检测脸部关键点教程(四)

相关文章:

你感兴趣的文章:

标签云: