Group Normalization vs Batch Normalization

BN 存在哪些问题:

1. BN 依赖大batch size, 当 batch size 太小时, batch statistics 变得不准确; 而显存限制了batch size变大,尤其在检测、分割等比较占用显存的模型上。 batch size上又是一个工程问题, 毕竟去年的coco,Face++主要赢在大batch上,这是最重要的motivation。

2. BN要求batch分布比较理想, 因为BN是沿着[N, H, W]进行统计,在复杂的任务中batch内的样本未符合i.i.d.,比如video里的连续帧, 比如detection box/mask head 里, 一个batch里的512个proposals 是高度关联甚至是重复的。

3.  Train/Test不一致, 训练时通过指数滑动平均(EMA)计算出来的 running_mean, running_vars到最后虽然也是能够收敛的,但是测试集和训练集数据分布往往并不完全一致,会造成模型在training/testing的性能差异。

 

GN做了什么?

1. GN不依赖batch size, group 是指对 channels进行 grouping,然后沿着[H, W, C/G] 进行统计,计算mean and vars, 摆脱了对N的依赖。由于是per-N 进行统计的, 那么就不要求batch内的N个样本符合i.i.d.

2.  GN在 testing time 也会根据不同的输入计算不同的mean 和 vars, 并不像BN那样使用training时的统计值,不存在Train/Test不一致的问题。

 

GN真的比BN好用吗?

在大batch上, BN依然很有优势,在小batch上,论文 declare 具有优势,实际效果还要case by case去验证。

 

GN 和 BN的实现(Tensorflow 版)


def GroupNorm(x, group, gamma_initializer=tf.constant_initializer(1.)):
    """
    https://arxiv.org/abs/1803.08494
    """
    shape = x.get_shape().as_list()
    ndims = len(shape)
    assert ndims == 4, shape
    chan = shape[1]
    assert chan % group == 0, chan
    group_size = chan // group

    orig_shape = tf.shape(x)
    h, w = orig_shape[2], orig_shape[3]

    x = tf.reshape(x, tf.stack([-1, group, group_size, h, w]))

    mean, var = tf.nn.moments(x, [2, 3, 4], keep_dims=True)

    new_shape = [1, group, group_size, 1, 1]

    beta = tf.get_variable('beta', [chan], initializer=tf.constant_initializer())
    beta = tf.reshape(beta, new_shape)

    gamma = tf.get_variable('gamma', [chan], initializer=gamma_initializer)
    gamma = tf.reshape(gamma, new_shape)

    out = tf.nn.batch_normalization(x, mean, var, beta, gamma, 1e-5, name='output')
    return tf.reshape(out, orig_shape, name='output')

def BatchNorm(x, n_out, phase_train, scope='bn'):
    """
    Batch normalization on convolutional maps.
    Args:
        x:           Tensor, 4D BHWD input maps
        n_out:       integer, depth of input maps
        phase_train: boolean tf.Varialbe, true indicates training phase
        scope:       string, variable scope
    Return:
        normed:      batch-normalized maps
    """
    with tf.variable_scope(scope):
        beta = tf.Variable(tf.constant(0.0, shape=[n_out]),
                                     name='beta', trainable=True)
        gamma = tf.Variable(tf.constant(1.0, shape=[n_out]),
                                      name='gamma', trainable=True)
        batch_mean, batch_var = tf.nn.moments(x, [0,1,2], name='moments')
        ema = tf.train.ExponentialMovingAverage(decay=0.5)

        def mean_var_with_update():
            ema_apply_op = ema.apply([batch_mean, batch_var])
            with tf.control_dependencies([ema_apply_op]):
                return tf.identity(batch_mean), tf.identity(batch_var)

        mean, var = tf.cond(phase_train,
                            mean_var_with_update,
                            lambda: (ema.average(batch_mean), ema.average(batch_var)))
        normed = tf.nn.batch_normalization(x, mean, var, beta, gamma, 1e-3)
    return normed

 

小batch size下BN tricks

1. 增大BN统计的范围

f = f.reshape([N, H, W * G, C//G])

f = BN(f)   # standard BN

f = f.reshape([N, H, W, C])

 BN为每个channel单独算一个mean和var;这种BN trick的思路是为每个channel group计算一个mean和var,和GN的motivation有点像。在batch size较小的时候相当于强行增大了BN统计的范围(从N*H*W增大到了N*H*W*G),使BN统计更为稳定, 可以用于解决小batch size的副作用。

2. Synchronized BN

常规的BN是在每一个GPU上单独计算mean和var, 但Synchronized BN 跨卡计算mean和var, 减少batch size的副作用。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值