新的正则化神器:DropBlock(Tensorflow实践)
先上结论:
在我们测试mnist上,3层卷积+dropXXX,所有参数均为改变的情况下,可以提升mnist准确率1~2点;同样在近期的实际业务中,也取得了相当不错的结果,模型鲁棒性有明显提升
十月份天气凉爽的时候,网上出现了一篇挺有意思的文章:https://arxiv.org/pdf/1810.12890.pdf
Google Brain提出了一种新的正则化方法:DropBlock,一图说明原理:
而在效果提升方面,作者对比了其性能效果:
可以明显发现,加入DropBlock之后,有效响应明显增强(但同时可能引来未可知的噪声?)
在目标检测方面,模型性能也同样有较好的性能提升:
分割效果:
(当然了fine-tune还是优秀)
我们自己亲自做一下实验:
这里,我们采用mnist来测试,非常简单的网络对飙dropout:
首先使用tensorflow.keras.layer
做一个实现:
import tensorflow as tf
from tensorflow.python.keras import backend as K
class DropBlock(tf.keras.layers.Layer):
def __init__(self, keep_prob, block_size, **kwargs):
super(DropBlock, self).__init__(**kwargs)
self.keep_prob = float(keep_prob) if isinstance(keep_prob, int) else keep_prob
self.block_size = int(block_size)
def compute_output_shape(self, input_shape):
return input_shape
def build(self, input_shape):
_, self.h, self.w, self.channel = input_shape.as_list()
# pad the mask
bottom = right = (self.block_size - 1) // 2
top = left = (self.block_size - 1) - bottom
self.padding = [[0, 0], [top, bottom], [left, right], [0, 0]]
self.set_keep_prob()
super(DropBlock, self).build(input_shape)
def call(self, inputs, training=None, scale=True, **kwargs):
def drop():
mask = self._create_mask(tf.shape(inputs))
output = inputs * mask
output = tf.cond(tf.constant(scale, dtype=tf.bool) if isinstance(scale, bool) else scale,
true_fn=lambda: output * tf.to_float(tf.size(mask)) / tf.reduce_sum(mask),
false_fn=lambda: output)
return output
if training is None:
training = K.learning_phase()
output = tf.cond(tf.logical_or(tf.logical_not(training), tf.equal(self.keep_prob, 1.0)),
true_fn=lambda: inputs,
false_fn=drop)
return output
def set_keep_prob(self, keep_prob=None):
"""This method only supports Eager Execution"""
if keep_prob is not None:
self.keep_prob = keep_prob
w, h = tf.to_float(self.w), tf.to_float(self.h)
self.gamma = (1. - self.keep_prob) * (w * h) / (self.block_size ** 2) / \\
((w - self.block_size + 1) * (h - self.block_size + 1))
def _create_mask(self, input_shape):
sampling_mask_shape = tf.stack([input_shape[0],
self.h - self.block_size + 1,
self.w - self.block_size + 1,
self.channel])
mask = DropBlock._bernoulli(sampling_mask_shape, self.gamma)
mask = tf.pad(mask, self.padding)
mask = tf.nn.max_pool(mask, [1, self.block_size, self.block_size, 1], [1, 1, 1, 1], 'SAME')
mask = 1 - mask
return mask
@staticmethod
def _bernoulli(shape, mean):
return tf.nn.relu(tf.sign(mean - tf.random_uniform(shape, minval=0, maxval=1, dtype=tf.float32)))
首先做个脚本测试:
import tensorflow as tf
from dropblock import DropBlock
tf.enable_eager_execution()
# only support `channels_last` data format
a = tf.ones([2, 10, 10, 3])
drop_block = DropBlock(keep_prob=0.8, block_size=3)
b = drop_block(a, training=True)
print(a[0, :, :, 0])
print(b[0, :, :, 0])
结果也很明显,可以实现dropblock
结论:
在我们测试mnist上,3层卷积+dropXXX,所有参数均为改变的情况下,可以提升mnist准确率1~2点;同样在近些填的实际业务中,也取得了相当不错的结果,模型鲁棒性有明显提升。