Darknet中的学习率调整策略
本文首发于微信公众号【DeepDriving】,欢迎关注。
导语
Darknet
是一个比较小众的开源深度学习框架,与目前主流的深度学习框架不同的是,该框架由C语言实现,对于新手来说有一定的学习难度。但是即便这样,也挡不住我们使用该框架的热情(也可能是迫不得已),因为大名鼎鼎的目标检测算法YOLO
(从v1~v4)就是基于该框架实现的。
学习率是训练深度学习模型时设置的一个关键的超参数,其值直接决定了训练的模型是否收敛、收敛的快慢程度:如果学习率设置得过大,则可能导致模型无法收敛;设置得过小则会导致模型收敛得很慢,从而使得训练时间过长。下图形象地说明了学习率对模型训练过程的影响:图1学习率过大,导致模型无法收敛;图2学习率过小,导致训练耗时较长;图3先设置了一个合适的学习率,然后在训练过程中还会适当地减少学习率,使得模型可以很好地收敛到全局最优点。
学习率是训练模型之前就设置好的一个超参数,在训练过程中还会基于一定的策略进行调整。
Darknet中的几种学习率调整策略
在Darknet
中,神经网络的模型结构和训练时需要的一些超参数都是在一个.cfg
文件中指定。学习率的调整策略则是在.cfg
文件中通过policy=
进行设置,在框架的代码中,则是由parser.c
的get_policy()
函数对.cfg
文件中设定的调整策略字符串进行解析以确定本次训练所采用的学习率调整策略。Darknet
框架支持的几种学习率调整策略定义在一个名为learning_rate_policy
的枚举类型中,其中每个成员代表的调整策略的具体含义解释如下:
-
CONSTANT: 恒定的学习率,学习率初始值在
.cfg
文件设置好后,训练过程中不会再做调整。 -
RANDOM: 也是恒定的学习率,但其值由下面的公式决定
η t = η ∗ λ p o w e r \eta _{t} = \eta * \lambda ^{power} ηt=η∗λpower
其中, η \eta η为初始学习率; λ \lambda λ为
0~1
之间的随机数;power
是由.cfg
文件中的power=
设置的参数。 -
POLY: 训练过程中学习率调整方式由下面公式决定
η t = η ∗ ( 1 − b a t c h _ n u m m a x _ b a t c h e s ) p o w e r \eta _{t} = \eta * (1 - \frac{batch\_num}{max\_batches})^{power} ηt=η∗(1−max_batchesbatch_num)power
其中, η \eta η为初始学习率;
batch_num
为当前的迭代次数;max_batches
为最大的迭代次数,该参数由.cfg
文件中的max_batches=
指定;power
是由.cfg
文件中的power=
设置的参数。当 η = 0.1 , m a x _ b a t c h e s = 10000 , p o w e r = 4 \eta=0.1,max\_batches=10000, power=4 η=0.1,max_batches=10000,power=4时,训练过程中学习率的调整过程曲线如下图所示: -
STEP:: 训练过程中学习率调整方式由下面公式决定
η t = η ∗ s c a l e b a t c h _ n u m / s t e p \eta _{t} = \eta * scale^{batch\_num/step} ηt=η∗scalebatch_num/step
其中, η \eta η为初始学习率;
batch_num
为当前的迭代次数;scale
是由.cfg
文件中的scale=
设置的参数;step
是由.cfg
文件中的step=
设置的参数。当 η = 0.1 , s c a l e = 0.1 , s t e p = 50000 \eta=0.1,scale=0.1,step=50000 η=0.1,scale=0.1,step=50000时,训练过程中学习率的调整过程曲线如下图所示: -
EXP: 训练过程中学习率调整方式由下面公式决定
η t = η ∗ γ b a t c h _ n u m \eta _{t} = \eta * \gamma ^{batch\_num} ηt=η∗γbatch_num
其中, η \eta η为初始学习率;
batch_num
为当前的迭代次数; γ \gamma γ是由.cfg
文件中的gamma=
设置的参数。当 η = 0.1 , γ = 0.9999 \eta=0.1,\gamma=0.9999 η=0.1,γ=0.9999时,训练过程中学习率的调整过程曲线如下图所示: -
SIG: 训练过程中学习率调整方式由下面公式决定
η t = η ∗ 1 1 + e γ ∗ ( b a t c h _ n u m − s t e p ) ) \eta _{t} = \eta * \frac{1}{1+e^{\gamma * (batch\_num - step)}}) ηt=η∗1+eγ∗(batch_num−step)1)
其中, η \eta η为初始学习率;
batch_num
为当前的迭代次数; γ \gamma γ是由.cfg
文件中的gamma=
设置的参数;step
是由.cfg
文件中的step=
设置的参数。当 η = 0.1 , γ = 0.0001 , s t e p = 50000 \eta=0.1,\gamma=0.0001,step=50000 η=0.1,γ=0.0001,step=50000时,训练过程中学习率的调整过程曲线如下图所示: -
STEPS:: 一种阶段性调整策略,可以设置多个阶段,当前迭代次数达到设定值时,学习率调整为
η t = η ∗ s c a l e \eta _{t} = \eta * scale ηt=η∗scale
在官方的
yolov3.cfg
文件中,有如下内容:policy=steps steps=400000,450000 scales=.1,.1
意思是当迭代次数达到400000时,学习率乘以0.1;当迭代次数达到450000时,学习率再乘以0.1。学习率调整曲线如下图所示:
学习率预热
在Darknet框架中,还可以通过.cfg
文件设定一个burn_in
参数。该参数用于在训练的前期,让学习率以一定的方式从零逐渐增大到指定的初始学习率,相当于是让学习率有一段时间的“热身(warm up)”过程,这样做的目的是避免训练初期由于初始学习率设置得过大导致训练过程出现震荡。这个阶段内,学习率的调整策略由下面的公式决定:
η t = η ∗ ( b a t c h _ n u m b u r n _ i n ) p o w e r \eta _{t} = \eta * (\frac{batch\_num}{burn\_in})^{power} ηt=η∗(burn_inbatch_num)power
当 η = 0.1 , b u r n _ i n = 1000 , p o w e r = 4 \eta=0.1,burn\_in=1000,power=4 η=0.1,burn_in=1000,power=4时,预热阶段学习率的调整过程曲线如下图所示:
如何在Darknet中新增学习率调整策略
上文介绍了Darknet
中的几种学习率调整策略,但是如果我们想用其他的策略应该怎么办呢?下面就以添加COSINE
调整策略为例说明如何在Darknet中添加一种新的学习率调整策略。COSINE
调整策略的公式如下
η t = 1 2 ∗ η ∗ ( 1 + c o s ( b a t c h _ n u m ∗ π m a x _ b a t c h e s ) ) \eta _{t} = \frac{1}{2} * \eta * (1 + cos(\frac{batch\_num * \pi}{max\_batches})) ηt=21∗η∗(1+cos(max_batchesbatch_num∗π))
其中,
η
\eta
η为初始学习率;batch_num
为当前的迭代次数;max_batches
为最大迭代次数。训练过程中学习率的调整过程曲线如下图所示:
添加COSINE
调整策略的过程如下:
- 在
darknet.h
文件中,为枚举类型learning_rate_policy
添加一个成员COSINE
:
typedef enum {
CONSTANT, STEP, EXP, POLY, STEPS, SIG, RANDOM, COSINE
} learning_rate_policy;
- 在
parser.c
文件中的get_policy()
函数中添加对COSINE
调整策略的支持:
learning_rate_policy get_policy(char *s)
{
if (strcmp(s, "random")==0) return RANDOM;
if (strcmp(s, "poly")==0) return POLY;
if (strcmp(s, "constant")==0) return CONSTANT;
if (strcmp(s, "step")==0) return STEP;
if (strcmp(s, "exp")==0) return EXP;
if (strcmp(s, "sigmoid")==0) return SIG;
if (strcmp(s, "steps")==0) return STEPS;
if (strcmp(s, "cosine")==0) return COSINE;
fprintf(stderr, "Couldn't find policy %s, going with constant\n", s);
return CONSTANT;
}
-
在
parser.c
文件中的parse_net_options()
函数中去解析.cfg
文件设置的参数。由于COSINE
调整策略所需的参数max_batches
已经有解析接口了,所以这里不需要额外添加。 -
在
network.c
文件中的get_current_rate()
函数中添加一个switch分支语句,实现COSINE
调整策略:
case COSINE:
return net.learning_rate * 0.5 * (1 + cos(batch_num *M_PI / net.max_batches));
- 重新编译Darknet工程。编译成功后只要在
.cfg
文件中设置policy=cosine
,就可以使用COSINE
学习率调整策略了。如果要添加其他的策略,参照以上方法也很容易就可以实现。
结语
学习率是训练深度学习模型过程中的一个很重要的超参数,可以通过多种方式进行调整。由于Darknet框架没有学习率调整策略的相关文档,要想知道具体细节只能通过剖析源代码才能了解每个参数的含义。本文详细介绍了Darknet框架中的学习率调整策略,通过公式和图形的方式阐述每种调整策略各个参数的意义和调整的过程,同时也介绍了添加新的调整策略的方法,希望对本文的读者有所帮助。
欢迎关注我的公众号【DeepDriving】,我会不定期分享计算机视觉、机器学习、深度学习、无人驾驶等领域的文章。