Пакетная нормализация вызывает огромную разницу между тренировкой и потерей вывода - PullRequest
0 голосов
/ 11 сентября 2018

Я следовал инструкции на веб-странице Tensorflow для tf.layers.batch_normalization , чтобы установить training быть True при обучении и False при выводе (действителен и проверен).

Однако нормализация партии всегда дает мне огромную разницу между тренировкой и допустимым уроном, например:

2018-09-11 09:22:34: step 993, loss 1.23001, acc 0.488638
2018-09-11 09:22:35: step 994, loss 0.969551, acc 0.567364
2018-09-11 09:22:35: step 995, loss 1.31113, acc 0.5291
2018-09-11 09:22:35: step 996, loss 1.03135, acc 0.607861
2018-09-11 09:22:35: step 997, loss 1.16031, acc 0.549255
2018-09-11 09:22:36: step 998, loss 1.42303, acc 0.454694
2018-09-11 09:22:36: step 999, loss 1.33105, acc 0.496234
2018-09-11 09:22:36: step 1000, loss 1.14326, acc 0.527387
Round 4: valid
Loading from valid, 1383 samples available
2018-09-11 09:22:36: step 1000, loss 44.3765, acc 0.000743037
2018-09-11 09:22:36: step 1000, loss 36.9143, acc 0.0100708
2018-09-11 09:22:37: step 1000, loss 35.2007, acc 0.0304909
2018-09-11 09:22:37: step 1000, loss 39.9036, acc 0.00510307
2018-09-11 09:22:37: step 1000, loss 42.2612, acc 0.000225067
2018-09-11 09:22:37: step 1000, loss 29.9964, acc 0.0230831
2018-09-11 09:22:37: step 1000, loss 28.1444, acc 0.00278473

, а иногда даже хуже (для другой модели):

2018-09-11 09:19:39: step 591, loss 0.967038, acc 0.630745
2018-09-11 09:19:40: step 592, loss 1.26836, acc 0.406095
2018-09-11 09:19:40: step 593, loss 1.33029, acc 0.536824
2018-09-11 09:19:41: step 594, loss 0.809579, acc 0.651354
2018-09-11 09:19:41: step 595, loss 1.41018, acc 0.491683
2018-09-11 09:19:42: step 596, loss 1.37515, acc 0.462998
2018-09-11 09:19:42: step 597, loss 0.972473, acc 0.663277
2018-09-11 09:19:43: step 598, loss 1.01062, acc 0.624355
2018-09-11 09:19:43: step 599, loss 1.13029, acc 0.53893
2018-09-11 09:19:44: step 600, loss 1.41601, acc 0.502889
Round 2: valid
Loading from valid, 1383 samples available
2018-09-11 09:19:44: step 600, loss 23242.2, acc 0.204348
2018-09-11 09:19:44: step 600, loss 22038, acc 0.196325
2018-09-11 09:19:44: step 600, loss 22223, acc 0.0991791
2018-09-11 09:19:44: step 600, loss 22039.2, acc 0.220871
2018-09-11 09:19:45: step 600, loss 25587.3, acc 0.155427
2018-09-11 09:19:45: step 600, loss 12617.7, acc 0.481486
2018-09-11 09:19:45: step 600, loss 17226.6, acc 0.234989
2018-09-11 09:19:45: step 600, loss 18530.3, acc 0.321573
2018-09-11 09:19:45: step 600, loss 21043.5, acc 0.157935
2018-09-11 09:19:46: step 600, loss 17232.6, acc 0.412151
2018-09-11 09:19:46: step 600, loss 28958.8, acc 0.297459
2018-09-11 09:19:46: step 600, loss 22603.7, acc 0.146518
2018-09-11 09:19:46: step 600, loss 29485.6, acc 0.266186
2018-09-11 09:19:46: step 600, loss 26039.7, acc 0.215589

Код нормализации партии, который я использую:

def bn(inp, train_flag, name=None):
    return tf.layers.batch_normalization(inp, training=train_flag, name=name)

def gn(inp, groups=32):
    return tf.contrib.layers.group_norm(inp, groups=groups)

def conv(*args, padding='same', with_relu=True, with_bn=False,
         train_flag=None, with_gn=False, name=None, **kwargs):
    # inp, filters, kernel_size, strides
    use_bias = False if with_bn else True
    x = tf.layers.conv2d(*args, **kwargs, padding=padding,
                         kernel_initializer=xavier_initializer(),
                         use_bias=use_bias, name=name)
    if with_bn:
        bn_name = name+'/batchnorm' if name is not None else None
        x = bn(x, train_flag, name=bn_name)
    if with_gn: x = gn(x)
    if with_relu: x = relu(x)
    return x

После удаления слоя нормализации партии огромная разница между тренировкой и потерей проверки исчезнет.

При оптимизации используется следующий код.

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):

Модель обучается с нуля без обучения переносу.

Я следовал за вопросом Слой нормализации партии даетсущественная разница между поездом и проверкой потерь на тех же данных , и попытался уменьшить momentum, но тоже не работает.

Мне интересно, почему это происходит.Я очень ценю, если вы могли бы дать мне несколько советов.

Добавлено: train_flag - заполнитель, используемый во всей модели.

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

В моем случае я ошибочно звоню update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) только один раз.

Для нескольких графических процессоров необходимо вызывать tf.get_collection(tf.GraphKeys.UPDATE_OPS) для каждого графического процессора, до compute_gradients и после определения каждой подсети. Кроме того, после объединения всех вышек подсетей, необходимо также вызвать его снова до apply_gradients.

Другой способ заключается в том, что после определения всей сети (включая все подсети), вызовите update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS), чтобы получить текущий update_ops. В этом случае нам нужны два цикла for, один для определения собственных сетей, один для вычисления градиентов.

Пример показан ниже:

# Multiple GPUs
tmp, l = [], 0
for i in range(opt.gpu_num):
    r = min(l + opt.batch_split, opt.batchsize)
    with tf.device('/gpu:%d' % i), \
         tf.variable_scope(tf.get_variable_scope(), reuse=tf.AUTO_REUSE):

        print("Setting up networks on GPU", i)
        inp_ = tf.identity(inps[l:r])
        label_ = tf.identity(labels[l:r])
        for j, val in enumerate(setup_network(inp_, label_)): # loss, pred, accuracy
            if i == 0: tmp += [[]] # [[], [], []]
            tmp[j] += [val]
    l = r

tmp += [[]]
# Calculate update_ops after the network has been defined
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) # possible batch normalization
for i in range(opt.gpu_num):
    with tf.device('/gpu:%d' % i), \
         tf.variable_scope(tf.get_variable_scope(), reuse=tf.AUTO_REUSE):

         print("Setting up gradients on GPU", i)
         tmp[-1] += [setup_grad(optim, tmp[0][i])]

Добавлено:

Я также добавляю setup_grad функцию

def setup_grad(optim, loss):
    # `compute_gradients`` will only run after update_ops have executed
    with tf.control_dependencies(update_ops):
        update_vars = None
        if opt.to_train is not None:
            update_vars = [tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=s)
                           for s in opt.to_train]
        total_loss = loss[0] + opt.seg_weight * loss[1]
        return optim.compute_gradients(total_loss, var_list=update_vars)

и позже apply_gradients в качестве ссылки.

# `apply_gradients`` will only run after update_ops have executed
with tf.control_dependencies(update_ops):
    if opt.clip_grad: grads = [(tf.clip_by_value(grad[0], -opt.clip_grad, opt.clip_grad), grad[1]) \
                                if grad[0] is not None else grad for grad in grads]
    train_op = optim.apply_gradients(grads, global_step=global_step)

Если размер вашего пакета на каждом графическом процессоре небольшой, нормализация пакетов может не помочь с производительностью из-за того, что Tensorflow в настоящее время не поддерживает синхронизацию данных уровня нормализации пакетов между графическими процессорами.

0 голосов
/ 11 сентября 2018

Поскольку вы не предоставили полный код или ссылку на него, мне нужно спросить следующее:

Как ты кормишь поезд_флагом?

Правильный способ - установить train_flag на tf.Placeholder. Есть и другие способы, но это самый простой подход. Затем вы можете кормить его простым python bool.

Если вы вручную устанавливаете train_flag=True во время обучения и устанавливаете его train_flag=False во время проверки, это может стать источником вашей проблемы. Я не вижу reuse=tf.AUTO_REUSE в вашем коде. Это означает, что во время проверки при установке train_flag=False создается отдельный слой, который не разделяет веса с предыдущим слоем, использованным во время обучения.

Причина, по которой проблема исчезает, когда вы не используете пакетную нормализацию, потому что в этом случае нет необходимости использовать train_flag со сверточным слоем. Итак, все работает хорошо.

Это моя догадка, основанная на наблюдениях.

...