2016-11-30 52 views
11

Tôi đã thử một số phiên bản của batch_normalization trong tensorflow, nhưng không ai trong số họ làm việc! Kết quả tất cả đều sai khi tôi đặt batch_size = 1 tại thời điểm suy luận.Làm thế nào để sử dụng hàng loạt bình thường một cách chính xác trong tensorflow?

Phiên bản 1: trực tiếp sử dụng phiên bản chính thức trong tensorflow.contrib

from tensorflow.contrib.layers.python.layers.layers import batch_norm 

sử dụng như thế này:

output = lrelu(batch_norm(tf.nn.bias_add(conv, biases), is_training), 0.5, name=scope.name) 

is_training = True ở thời gian đào tạo và False lúc suy luận.

Version 2: từ How could I use Batch Normalization in TensorFlow?

def batch_norm_layer(x, train_phase, scope_bn='bn'): 
    bn_train = batch_norm(x, decay=0.999, epsilon=1e-3, center=True, scale=True, 
      updates_collections=None, 
      is_training=True, 
      reuse=None, # is this right? 
      trainable=True, 
      scope=scope_bn) 
    bn_inference = batch_norm(x, decay=0.999, epsilon=1e-3, center=True, scale=True, 
      updates_collections=None, 
      is_training=False, 
      reuse=True, # is this right? 
      trainable=True, 
      scope=scope_bn) 
    z = tf.cond(train_phase, lambda: bn_train, lambda: bn_inference) 
    return z 

sử dụng như thế này:

output = lrelu(batch_norm_layer(tf.nn.bias_add(conv, biases), is_training), 0.5, name=scope.name) 

is_training là một giữ chỗ tại thời gian đào tạo là True và False lúc suy luận.

phiên bản 3: từ mỏng https://github.com/tensorflow/models/blob/master/inception/inception/slim/ops.py

def batch_norm_layer(inputs, 
      is_training=True, 
      scope='bn'): 
    decay=0.999 
    epsilon=0.001 
    inputs_shape = inputs.get_shape() 
    with tf.variable_scope(scope) as t_scope: 
    axis = list(range(len(inputs_shape) - 1)) 
    params_shape = inputs_shape[-1:] 
    # Allocate parameters for the beta and gamma of the normalization. 
    beta, gamma = None, None 
    beta = tf.Variable(tf.zeros_initializer(params_shape), 
     name='beta', 
     trainable=True) 
    gamma = tf.Variable(tf.ones_initializer(params_shape), 
     name='gamma', 
     trainable=True) 
    moving_mean = tf.Variable(tf.zeros_initializer(params_shape), 
     name='moving_mean', 
     trainable=False) 
    moving_variance = tf.Variable(tf.ones_initializer(params_shape), 
     name='moving_variance', 
     trainable=False) 
    if is_training: 
     # Calculate the moments based on the individual batch. 
     mean, variance = tf.nn.moments(inputs, axis) 

     update_moving_mean = moving_averages.assign_moving_average(
      moving_mean, mean, decay) 
     update_moving_variance = moving_averages.assign_moving_average(
      moving_variance, variance, decay) 
    else: 
     # Just use the moving_mean and moving_variance. 
     mean = moving_mean 
     variance = moving_variance 
     # Normalize the activations. 
    outputs = tf.nn.batch_normalization(
     inputs, mean, variance, beta, gamma, epsilon) 
    outputs.set_shape(inputs.get_shape()) 
    return outputs 

sử dụng như thế này:

output = lrelu(batch_norm_layer(tf.nn.bias_add(conv, biases), is_training), 0.5, name=scope.name) 

is_training = True ở thời gian đào tạo và False lúc suy luận.

phiên bản 4: như version3, nhưng thêm tf.control_dependencies

def batch_norm_layer(inputs, 
      decay=0.999, 
      center=True, 
      scale=True, 
      epsilon=0.001, 
      moving_vars='moving_vars', 
      activation=None, 
      is_training=True, 
      trainable=True, 
      restore=True, 
      scope='bn', 
      reuse=None): 
    inputs_shape = inputs.get_shape() 
    with tf.variable_op_scope([inputs], scope, 'BatchNorm', reuse=reuse): 
     axis = list(range(len(inputs_shape) - 1)) 
     params_shape = inputs_shape[-1:] 
     # Allocate parameters for the beta and gamma of the normalization. 
     beta = tf.Variable(tf.zeros(params_shape), name='beta') 
     gamma = tf.Variable(tf.ones(params_shape), name='gamma') 
     # Create moving_mean and moving_variance add them to 
     # GraphKeys.MOVING_AVERAGE_VARIABLES collections. 
     moving_mean = tf.Variable(tf.zeros(params_shape), name='moving_mean', 
      trainable=False) 
     moving_variance = tf.Variable(tf.ones(params_shape), name='moving_variance', 
      trainable=False) 
    control_inputs = [] 
    if is_training: 
     # Calculate the moments based on the individual batch. 
     mean, variance = tf.nn.moments(inputs, axis) 

     update_moving_mean = moving_averages.assign_moving_average(
      moving_mean, mean, decay) 
     update_moving_variance = moving_averages.assign_moving_average(
      moving_variance, variance, decay) 
     control_inputs = [update_moving_mean, update_moving_variance] 
    else: 
     # Just use the moving_mean and moving_variance. 
     mean = moving_mean 
     variance = moving_variance 
    # Normalize the activations. 
    with tf.control_dependencies(control_inputs): 
     return tf.nn.batch_normalization(
     inputs, mean, variance, beta, gamma, epsilon) 

sử dụng như thế này:

output = lrelu(batch_norm(tf.nn.bias_add(conv, biases), is_training), 0.5, name=scope.name) 

is_training = True ở thời gian đào tạo và False lúc suy luận.

Tất cả 4 phiên bản Batch_normalization đều không chính xác. Vì vậy, làm thế nào để sử dụng hàng loạt bình thường một cách chính xác?

Hiện tượng kỳ lạ khác là nếu tôi đặt batch_norm_layer thành null như thế này, kết quả suy luận đều giống nhau.

def batch_norm_layer(inputs, is_training): 
    return inputs 
+1

Tôi có niềm tin vững chắc trong biết các khái niệm cơ bản về những gì tôi đang sử dụng. Tôi khuyên bạn nên đọc bài viết về chuẩn hóa lô để hiểu tại sao và cách thức nó giúp: https://arxiv.org/pdf/1502.03167.pdf –

+0

Nếu bạn nói "tất cả đều không chính xác", ý bạn là gì? – etarion

+1

Nó có nghĩa là "tất cả chúng đều sai". – widgetxp

Trả lời

6

Tôi đã thử nghiệm rằng việc thực hiện đơn giản sau bình thường hóa hàng loạt cho cùng một kết quả như tf.contrib.layers.batch_norm miễn là các thiết lập là như nhau.

def initialize_batch_norm(scope, depth): 
    with tf.variable_scope(scope) as bnscope: 
     gamma = tf.get_variable("gamma", shape[-1], initializer=tf.constant_initializer(1.0)) 
     beta = tf.get_variable("beta", shape[-1], initializer=tf.constant_initializer(0.0)) 
     moving_avg = tf.get_variable("moving_avg", shape[-1], initializer=tf.constant_initializer(0.0), trainable=False) 
     moving_var = tf.get_variable("moving_var", shape[-1], initializer=tf.constant_initializer(1.0), trainable=False) 
     bnscope.reuse_variables() 


def BatchNorm_layer(x, scope, train, epsilon=0.001, decay=.99): 
    # Perform a batch normalization after a conv layer or a fc layer 
    # gamma: a scale factor 
    # beta: an offset 
    # epsilon: the variance epsilon - a small float number to avoid dividing by 0 
    with tf.variable_scope(scope, reuse=True): 
     with tf.variable_scope('BatchNorm', reuse=True) as bnscope: 
      gamma, beta = tf.get_variable("gamma"), tf.get_variable("beta") 
      moving_avg, moving_var = tf.get_variable("moving_avg"), tf.get_variable("moving_var") 
      shape = x.get_shape().as_list() 
      control_inputs = [] 
      if train: 
       avg, var = tf.nn.moments(x, range(len(shape)-1)) 
       update_moving_avg = moving_averages.assign_moving_average(moving_avg, avg, decay) 
       update_moving_var = moving_averages.assign_moving_average(moving_var, var, decay) 
       control_inputs = [update_moving_avg, update_moving_var] 
      else: 
       avg = moving_avg 
       var = moving_var 
      with tf.control_dependencies(control_inputs): 
       output = tf.nn.batch_normalization(x, avg, var, offset=beta, scale=gamma, variance_epsilon=epsilon) 
    return output 

Những lời khuyên chính với việc sử dụng thực hiện chính thức của bình thường hàng loạt trong tf.contrib.layers.batch_norm là: (1) thiết lập is_training=True cho thời gian đào tạo và is_training=False để xác nhận và thời gian thử nghiệm; (2) đặt updates_collections=None để đảm bảo rằng moving_variancemoving_mean được cập nhật tại chỗ; (3) nhận thức và cẩn thận với thiết lập phạm vi; (4) đặt decay là giá trị nhỏ hơn (decay=0.9 hoặc decay=0.99) so với giá trị mặc định (mặc định là 0999) nếu tập dữ liệu của bạn nhỏ hoặc tổng số cập nhật/bước đào tạo của bạn không lớn.

+0

Cảm ơn bạn Zhongyu Kuang, tôi đã nhận được kết luận tương tự với bạn ngoại trừ mục 4. – widgetxp

+2

Tôi đã luôn luôn có vấn đề với 'tf.contrib.layers.batch_norm'. Mạng của tôi hội tụ khi tôi đang đào tạo nhưng nó mang lại cho tôi kết quả vô nghĩa khi tôi kiểm tra mạng và đặt 'is_training = False'. Tuy nhiên, kết quả kiểm tra khi 'is_training = True' có ý nghĩa hơn đối với tôi (thậm chí độ chính xác gần bằng 0 so với mạng w/o batch_norm). bất kỳ ý tưởng? Tôi đã hỏi ở đây: [http://stackoverflow.com/questions/42770757/tensorflow-batch-norm-does-not-work-properly-when-testing-is-training-false](Tensorflow batch_norm không hoạt động đúng khi thử nghiệm (is_training = False)) – user3157047

+0

@Zhongyu Kuang bạn có thể giải thích thêm về update_collections không. Chúng tôi cập nhật chúng bằng tf.GraphKeys.UPDATE_OPS. Và cách sử dụng chúng trong suy luận. –

2

Tôi thấy mã của Zhongyu Kuang thực sự hữu ích, nhưng tôi bị kẹt về cách tự động chuyển đổi giữa các khóa đào tạo và kiểm tra, tức là cách di chuyển từ boolean boolean is_training sang trình giữ chỗ boolean tensorflow is_training. Tôi cần chức năng này để có thể kiểm tra mạng trên bộ xác thực trong quá trình đào tạo.

Bắt đầu từ mã của mình và lấy cảm hứng từ this, tôi đã viết đoạn mã sau:

def batch_norm(x, scope, is_training, epsilon=0.001, decay=0.99): 
    """ 
    Returns a batch normalization layer that automatically switch between train and test phases based on the 
    tensor is_training 

    Args: 
     x: input tensor 
     scope: scope name 
     is_training: boolean tensor or variable 
     epsilon: epsilon parameter - see batch_norm_layer 
     decay: epsilon parameter - see batch_norm_layer 

    Returns: 
     The correct batch normalization layer based on the value of is_training 
    """ 
    assert isinstance(is_training, (ops.Tensor, variables.Variable)) and is_training.dtype == tf.bool 

    return tf.cond(
     is_training, 
     lambda: batch_norm_layer(x=x, scope=scope, epsilon=epsilon, decay=decay, is_training=True, reuse=None), 
     lambda: batch_norm_layer(x=x, scope=scope, epsilon=epsilon, decay=decay, is_training=False, reuse=True), 
    ) 


def batch_norm_layer(x, scope, is_training, epsilon=0.001, decay=0.99, reuse=None): 
    """ 
    Performs a batch normalization layer 

    Args: 
     x: input tensor 
     scope: scope name 
     is_training: python boolean value 
     epsilon: the variance epsilon - a small float number to avoid dividing by 0 
     decay: the moving average decay 

    Returns: 
     The ops of a batch normalization layer 
    """ 
    with tf.variable_scope(scope, reuse=reuse): 
     shape = x.get_shape().as_list() 
     # gamma: a trainable scale factor 
     gamma = tf.get_variable("gamma", shape[-1], initializer=tf.constant_initializer(1.0), trainable=True) 
     # beta: a trainable shift value 
     beta = tf.get_variable("beta", shape[-1], initializer=tf.constant_initializer(0.0), trainable=True) 
     moving_avg = tf.get_variable("moving_avg", shape[-1], initializer=tf.constant_initializer(0.0), trainable=False) 
     moving_var = tf.get_variable("moving_var", shape[-1], initializer=tf.constant_initializer(1.0), trainable=False) 
     if is_training: 
      # tf.nn.moments == Calculate the mean and the variance of the tensor x 
      avg, var = tf.nn.moments(x, range(len(shape)-1)) 
      update_moving_avg = moving_averages.assign_moving_average(moving_avg, avg, decay) 
      update_moving_var = moving_averages.assign_moving_average(moving_var, var, decay) 
      control_inputs = [update_moving_avg, update_moving_var] 
     else: 
      avg = moving_avg 
      var = moving_var 
      control_inputs = [] 
     with tf.control_dependencies(control_inputs): 
      output = tf.nn.batch_normalization(x, avg, var, offset=beta, scale=gamma, variance_epsilon=epsilon) 

    return output 

Sau đó, tôi sử dụng lớp batch_norm theo cách này:

fc1_weights = tf.Variable(...) 
fc1 = tf.matmul(x, fc1_weights) 
fc1 = batch_norm(fc1, 'fc1_bn', is_training=is_training) 
fc1 = tf.nn.relu(fc1) 

đâu is_training là một placeholder boolean. Lưu ý rằng không cần thêm sự chênh lệch vì được thay thế bằng tham số beta như được giải thích trong Batch Normalization paper.

Trong thực hiện:

# Training phase 
sess.run(loss, feed_dict={x: bx, y: by, is_training: True}) 

# Testing phase 
sess.run(loss, feed_dict={x: bx, y: by, is_training: False}) 
+0

Lưu ý rằng bạn có thể sử dụng tf.contrib.layers.batch_norm() - và rằng is_training arg rằng nó chấp nhận có thể là một trình giữ chỗ boolean! – ZeDuS

+0

Trên thực tế, câu hỏi là về một cách khác nhau để thực hiện bình thường hóa hàng loạt trong tensorflow, vì vậy tôi đã cung cấp mã mà tôi đã viết để thực hiện nó mà không cần sử dụng bất kỳ hàm nào từ mô-đun contrib. Chính thức, "mô-đun contrib chứa mã dễ bay hơi hoặc thử nghiệm", vì vậy có thể hữu ích khi tránh sử dụng nó trong một số trường hợp. –

Các vấn đề liên quan