Yolov3细节解释

Yolov3日常使用比较多,因此对其中的一些细节进行了分析,简单记录,未完待续。

1. 卷积中的pad

darknet在设置pad参数时和caffe不同,caffe中设置的pad值就是实际计算的值,而darknet中设置的pad只是使能padding的标志,而实际的padding值是根据kernel size计算而来。
在src/parser.c的parse_convolutional函数中: 

int n = option_find_int(options, "filters",1);  //滤波器个数,也是输出的特征图数;
int size = option_find_int(options, "size",1);  //卷积核大小;
int stride = option_find_int(options, "stride",1);  //卷积步长;
int pad = option_find_int_quiet(options, "pad",0);  //是否进行pad;
int padding = option_find_int_quiet(options, "padding",0);  //padding值,默认为0;
if(pad) padding = size/2;  //如果pad,则根据size计算padding值,取商;

根据padding的计算可以看到,如果想保持特征图大小不变,只需设置pad=1即可,实际padding会根据size自动计算,而在caffe中,需要根据size的大小设置不同的pad值。

2. 池化中的pad

darknet中池化有最大池化(maxpool)和平均池化(avgpool)两种;

maxpool和caffe中的类似,不过不需要设置pad,其padding值默认为size-1,而输出feature map的大小计算为:
                                            l.out_w = (w + padding - size)/stride + 1;
                                            l.out_h = (h + padding - size)/stride + 1;

avgpool和caffe中不同,darknet中的avgpool是全局平均池化,其输出的feature map大小为1×1;

3. jitter参数

jitter参数用来控制平移变换和图像缩放,设置太大会导致图片长宽比变化较大,目标的宽高比例失调,(按照该参数处理方法计算发现,设置为0.3时,每张图片的宽或高平均会压缩23%,最高压缩46%),最大可使目标的长宽比变化为接近原比例的一半。虽然可以增加样本多样性,但是对于刚性目标,宽高比例比较固定时,并不太适用。jitter参数计算方法:

假设w、h为网络训练输入宽高,W、H为训练使用的图像数据的宽高。先将原图归一化,并创建一个shape为(w,h,c)的图像,并填充值为0.5。

以原图为基础进行变换,计算缩放比例:new_ar=W*[1-jitter,1+jitter] / H*[1-jitter,1+jitter]

以jitter=0.2为例,则上式分子为[0.8W,1.2W]内的一个随机值,分母为[0.8H,1.2H]内的一个随机值,new_ar为二者的比值。设缩放后的图像的宽高为nw和nh,如果new_ar<1,则nh=h,nw=nh*new_ar,否则nw=w,nh=nw/new_ar,总之就是根据new_ar将缩放后的图像宽高限制在训练输入的宽高内。然后将输入的宽高为W和H图像,利用二次线性插值的方法,缩放到nw和nh,注意这里图像的长宽比发生了变化,目标的宽高比也发生了变化,变为了原来的new_ar。

最后再做平移,在(0, w-nw)和(0, h-nh)中分别随机一个值,得到偏移值dx和dy,将缩放后的图像放到创建的图像中去,位置为[dy:dy+nh,dx:dx+nw]。再将生成的这个生成的结果,送入网络训练。

4. 补边问题

训练模型(以416*416为例)时,不必提前为图片补边,原图片可以是不同宽高比的。yolo在数据读入时,经过图像增强变换(参考jitter参数解释)后,会以缩放后的图像的长边为基准,短边自动补灰(填充0.5),因此不用提前补,可以节省前期样本处理时间和存储空间。

5. 原始图像缩放问题

如果原始训练图像分辨率远远大于训练分辨率,缩放就很有必要,可以加快数据读取速度,从而提高训练速度。但是不能缩放到实际训练时的基准分辨率大小,而是要更大一些。

以416*416为例,实际训练时由于多尺度的存在,网络输入最大分辨率可达到608*608,所以如果图片提前缩放到小于608(如416等),使得在训练时又要放大,图片先缩小后放大,图像存在失真,有效信息会丢失,尤其是小目标,缩放后很小,再放大也会很模糊,影响很大。这里需使缩放后的分辨率至少为多尺度训练的最大分辨率。

这样虽然也是缩放,但是缩放后仍大于多尺度训练分辨率。预先缩放只是为了加快数据读取速度,即使不提前缩放,在数据读取后图片也会从原始分辨率缩放到训练大小。所以提前缩放只是先缩小一点而已,读入数据后还是继续缩小,不会失真。而如果预先缩放到小于最大分辨率,就会导致图像缩放到很小然后训练时再放大,会失真,相当于网络学习了一个模糊的图片。

6. 不同尺度的适应性

yolo不具有尺度变化的适应性,如果希望模型能兼顾不同尺度的目标,训练样本中应该包含多尺度的目标。

7. yolo层参数truth_thresh

yolov3中在yolo层有一个truth_thresh参数,默认为1,且不需要修改。而在yolov3的源码src/yolo_layer.c中关于这个参数的使用是 if (best_iou > l.truth_thresh) ,然而best_iou也只是个IoU,永远也不会大于1,所以这段if判断的这段代码根本不会执行。这里的参数,作者论文中有提到,这是作者做的一种尝试,尝试使用双thresh机制,如同Faster RCNN中的双thresh机制,但是发现这种方法并没有取得有益效果,于是作者就放弃此方法,却没有删除源码,于是就保留下来。

8. yolov3的初始训练时的学习率更新问题

yolov3在训练初始阶段采用自带的学习率更新策略。该策略的更新迭代次数通过burn_in(默认是1000,cfg文件)参数设置,即前1000个batch(cfg文件中设置的batch)采用该策略,1000次以后采用设置的学习率更新策略。yolov3在训练时通过日志可以发现,该学习率是动态变化的,那么学习率到底是如何更新的呢?通过追溯源码(src/network.c->get_current_rate)可以发现该学习率是如何动态更新的。更新的公式为:

其中learning_rate为设置的基础学习率,batch_num为已经训练的batch数。

可以看出,由于batch_num是从0开始累加,使得在训练开始阶段,实际学习率非常非常小,而打印时一般显示小数点后6位,导致训练开始时日志中打印的学习率为0,属于正常现象。从上式可以看出,开始阶段,学习率是线性增加的,直至达到预设的学习率,然后开始使用预设的学习率继续训练,完成了平缓的过度,这种设置学习率的方法称为学习率预热。

9. 学习率的预热(warm up)问题

学习率是神经网络训练中最重要的超参数之一,针对学习率的优化方式很多,Warm up是其中的一种。

Warmup是指在训练开始的时候先选择使用一个较小的学习率,训练几个epoches或者一定数量的batch,再修改为预先设置的学习来进行训练。

训练开始阶段,权重(weights)一般是随机初始化的,如果学习率比较大,则模型可能会不稳定,预热学习率可以使模型先慢慢趋于稳定,相对稳定后再选择预先设置的学习率进行训练,加快模型收敛速度,提升训练效果。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值