庖丁解牛yolo_v4之DropBlock
论文:DropBlock: A regularization method forconvolutional networksGithub:https://github.com/miguelvr/dropblockhttps://github.com/DHZS/tf-dropblock论文主要提出了一种针对卷积层的正则化方法DropBlock,最终在ImageNet分类任务上,使用Resnet-5
论文:
DropBlock: A regularization method for convolutional networks
Github:
https://github.com/miguelvr/dropblock
https://github.com/DHZS/tf-dropblock
论文主要提出了一种针对卷积层的正则化方法DropBlock,最终在ImageNet分类任务上,使用Resnet-50结构,将精度提升1.6%个点,在COCO检测任务上,精度提升1.6%个点。
(a)原始输入图像
(b)绿色部分表示激活的特征单元,b图表示了随机dropout激活单元,但是这样dropout后,网络还会从drouout掉的激活单元附近学习到同样的信息
(c)绿色部分表示激活的特征单元,c图表示本文的DropBlock,通过dropout掉一部分相邻的整片的区域(比如头和脚),网络就会去注重学习狗的别的部位的特征,来实现正确分类,从而表现出更好的泛化。
DropBlock 模块:
DropBlock 模块主要有2个参数,block_size,γ。
block_size:表示dropout的方块的大小(长,宽),当block_size=1,DropBlock 退化为传统的dropout,正常可以取3,5,7
γ:表示drop过程中的概率,也就是伯努利函数的概率
首先,保证DropBlock drop的元素个数和传统dropout drop的元素个数相等。
那么,传统的dropout drop的元素个数为drop概率乘以一共的元素个数,即(1-keep_prob)*(feat_size*feat_size)
DropBlock drop的元素个数也是drop概率乘以一共的元素个数,
这里在实现中,为了保证drop的block不会超出原始图像,需要先设置一个drop的有效区域,如下图(a)中绿色的区域,也就是原始的图减去block,即(feat_size-block_size+1)。
这里的概率γ为伯努利函数的概率,而这个概率只表示了随机drop的中间点的概率,如下图(a)中红色的×,实际需要的是要drop掉X周围的block_size大小的区域,也就是一个X对应一个block_size大小的区域(假设不相互重叠)。
所以,DropBlock 的概率即γ*(block_size*block_size),有效的区域面积为(feat_size-block_size+1)*(feat_size-block_size+1),最终得到drop掉的元素数目为γ*(block_size*block_size)*(feat_size-block_size+1)*(feat_size-block_size+1)
最后,dropout==DropBlock ,即让(1-keep_prob)*(feat_size*feat_size)=γ*(block_size*block_size)*(feat_size-block_size+1)*(feat_size-block_size+1)
这样就会得到上面最终的伯努利概率γ。
在实验过程中,使用固定的keep_prob值的效果不如使用线性下降的keep_prob值。
实验中keep_prob值从1.0线性下降为0.75。
整体流程:
(1)输入特征层A,block_size,γ,模式(训练,测试)
(2,3,4)如果是测试,直接返回特征层A
(5)根据输入的概率γ,使用伯努利函数对生成的随机数mask矩阵进行drop,最终该步骤得到的mask只有0,1值。如上图中(a)。
伯努利概率分布为0-1分布,或者两点分布,公式如下
(6)对上一步得到的mask进行max pooling操作(stride=1,kernel_size=block_size),得到最终需要使用的mask。如上图中(b)。
(7)输入矩阵和Mask矩阵相乘,得到输出矩阵
(8)将上一步的输出矩阵进行归一化操作,保证做DropBlock 之前和做DropBlock 之后,该层都具体相同的均值,方差。
哪一层该使用DropBlock:
Keep_prob值的选择(a图):
Drouout:0.7取得最优值
SpatialDropout:0.9取得最优值
DropBlock:0.9取得最优值
使用线性下降的方式(scheduling)来使用Keep_prob,可以获得更高的验证准确性。(b图)
Block_size=7时,获得最高验证集准确性
对Keep_prob值进行线性下降方式(scheduling)可以获得更好效果
Resnet-50的第3,4个block加Drouout比只在第4个block加Drouout更有效
在Resnet-50的卷积层和skip connection都使用Drouout效果更好
实验分析:
训练时使用block_size=7,keep_prob=0.9,测试时使用block_size=7,keep_prob=1.0,可以获得更好的效果。这点和传统的dropout一样。
第一行为原始的图片,第二行为未使用DropBlock,第三行为block_size=1,第四行为block_size=7。可以看出
(1)使用DropBlock比不使用DropBlock具有更大的热量图
(2)DropBlock的block_size越大,热量图的激活部分越多
实验结果:
ImageNet 图像分类:
COCO检测任务:
PASCAL VOC 分割任务:
自己的复现:
import tensorflow as tf
def compute_gamma(keep_prob,feat_size_h,feat_size_w,block_size_h,block_size_w):
feat_size_h=tf.to_float(feat_size_h)
feat_size_w=tf.to_float(feat_size_w)
gamma=(1-keep_prob)*(feat_size_h*feat_size_w)/(block_size_h*block_size_w)/((feat_size_h-block_size_h+1)*(feat_size_w-block_size_w+1))
return gamma
def compute_keep_prob(now_step=0,start_value=1.0,stop_value=0.75,nr_steps=100000,trainable=False):
prob_values = tf.linspace(start=start_value, stop=stop_value, num=nr_steps)
prob=tf.where(tf.less(now_step,nr_steps),prob_values[now_step],prob_values[-1])
keep_prob=tf.where(tf.equal(trainable,False),start_value,prob)
return keep_prob
def bernoulli(shape,gamma=0):
mask=tf.cast(tf.random_uniform(shape, minval=0, maxval=1, dtype=tf.float32)<gamma,tf.float32)
return mask
def compute_block_mask(shape,padding,gamma,block_size_shape):
mask=bernoulli(shape,gamma)
mask = tf.pad(mask, padding,"CONSTANT")
mask = tf.nn.max_pool(mask, [1,block_size_shape[0],block_size_shape[1], 1], [1, 1, 1, 1], 'SAME')
mask = 1 - mask
return mask
def DropBlock(inputs,keep_prob,block_size_shape,feat_size_shape):
#keep_prob:keep ratio,float32
#block_size_shape:[height,width]
#feat_size_shape:[batch,height,width,channel]
gamma=compute_gamma(keep_prob,feat_size_shape[1],feat_size_shape[2],block_size_shape[0],block_size_shape[1])
shape=[feat_size_shape[0],feat_size_shape[1]-block_size_shape[0]+1,feat_size_shape[2]-block_size_shape[1]+1,feat_size_shape[3]]
bottom = (block_size_shape[0]-1) // 2
right = (block_size_shape[1]-1) // 2
top = (block_size_shape[0]-1) // 2
left = (block_size_shape[1]-1) // 2
padding = [[0, 0], [top, bottom], [left, right], [0, 0]]
mask=compute_block_mask(shape,padding,gamma,block_size_shape)
normalize_mask=mask*tf.to_float(tf.size(mask)) / tf.reduce_sum(mask)
outputs=inputs*normalize_mask
return outputs
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)