首页 文章

如何在TensorFlow中添加正则化?

提问于
浏览
76

我在使用TensorFlow实现的许多可用神经网络代码中发现,正则化术语通常通过手动向损失值添加附加项来实现 .

我的问题是:

  • 有没有比手动更优雅或推荐的正规化方法?

  • 我还发现 get_variable 有一个参数 regularizer . 该如何使用?根据我的观察,如果我们将正则化器传递给它(例如 tf.contrib.layers.l2_regularizer ,将计算表示正则化术语的张量并将其添加到名为 tf.GraphKeys.REGULARIZATOIN_LOSSES 的图表集合中.TensorFlow会自动使用该集合(例如,在训练时由优化器使用) ?或者我是否应该自己使用该系列?

8 回答

  • 1
    cross_entropy = tf.losses.softmax_cross_entropy(
      logits=logits, onehot_labels=labels)
    
    l2_loss = weight_decay * tf.add_n(
         [tf.nn.l2_loss(tf.cast(v, tf.float32)) for v in tf.trainable_variables()])
    
    loss = cross_entropy + l2_loss
    
  • 0

    一些答案让我更加困惑 . 在这里,我给出了两种清晰的方法 .

    #1.adding all regs by hand
    var1 = tf.get_variable(name='v1',shape=[1],dtype=tf.float32)
    var2 = tf.Variable(name='v2',initial_value=1.0,dtype=tf.float32)
    regularizer = tf.contrib.layers.l1_regularizer(0.1)
    reg_term = tf.contrib.layers.apply_regularization(regularizer,[var1,var2])
    #here reg_term is a scalar
    
    #2.auto added and read,but using get_variable
    with tf.variable_scope('x',
            regularizer=tf.contrib.layers.l2_regularizer(0.1)):
        var1 = tf.get_variable(name='v1',shape=[1],dtype=tf.float32)
        var2 = tf.get_variable(name='v2',shape=[1],dtype=tf.float32)
    reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
    #here reg_losses is a list,should be summed
    

    然后,它可以添加到总损失中

  • 19

    正如您在第二点所述,建议使用 regularizer 参数 . 您可以在 get_variable 中使用它,或者在 variable_scope 中设置一次并使所有变量正规化 .

    损失收集在图表中,您需要手动将它们添加到您的成本函数中 .

    reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
      reg_constant = 0.01  # Choose an appropriate one.
      loss = my_normal_loss + reg_constant * sum(reg_losses)
    

    希望有所帮助!

  • 36

    现有答案的几个方面对我来说并不是很清楚,所以这里有一个循序渐进的指南:

    • 定义正则化器 . 这是可以设定正则化常数的地方,例如:
    regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
    
    • 通过以下方式创建变量:
    weights = tf.get_variable(
            name="weights",
            regularizer=regularizer,
            ...
        )
    

    等价地,变量可以通过常规 weights = tf.Variable(...) 构造函数创建,然后是 tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, weights) .

    • 定义一些 loss 术语并添加正则化术语:
    reg_variables = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
    reg_term = tf.contrib.layers.apply_regularization(regularizer, reg_variables)
    loss += reg_term
    

    注意:看起来 tf.contrib.layers.apply_regularization 实现为 AddN ,因此或多或少等同于 sum(reg_variables) .

  • 2

    我会提供一个简单正确的答案,因为我找不到一个 . 你需要两个简单的步骤,其余的是由tensorflow魔术完成的:

    • 在创建变量或图层时添加正则化程序:
    tf.layers.dense(x, kernel_regularizer=tf.contrib.layers.l2_regularizer(0.001))
    # or
    tf.get_variable('a', regularizer=tf.contrib.layers.l2_regularizer(0.001))
    
    • 在定义损失时添加正则化术语:
    loss = ordinary_loss + tf.losses.get_regularization_loss()
    
  • 1

    使用 contrib.learn 库执行此操作的另一个选项如下,基于Tensorflow网站上的Deep MNIST tutorial . 首先,假设您已导入相关库(例如 import tensorflow.contrib.layers as layers ),您可以使用单独的方法定义网络:

    def easier_network(x, reg):
        """ A network based on tf.contrib.learn, with input `x`. """
        with tf.variable_scope('EasyNet'):
            out = layers.flatten(x)
            out = layers.fully_connected(out, 
                    num_outputs=200,
                    weights_initializer = layers.xavier_initializer(uniform=True),
                    weights_regularizer = layers.l2_regularizer(scale=reg),
                    activation_fn = tf.nn.tanh)
            out = layers.fully_connected(out, 
                    num_outputs=200,
                    weights_initializer = layers.xavier_initializer(uniform=True),
                    weights_regularizer = layers.l2_regularizer(scale=reg),
                    activation_fn = tf.nn.tanh)
            out = layers.fully_connected(out, 
                    num_outputs=10, # Because there are ten digits!
                    weights_initializer = layers.xavier_initializer(uniform=True),
                    weights_regularizer = layers.l2_regularizer(scale=reg),
                    activation_fn = None)
            return out
    

    然后,在main方法中,您可以使用以下代码段:

    def main(_):
        mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)
        x = tf.placeholder(tf.float32, [None, 784])
        y_ = tf.placeholder(tf.float32, [None, 10])
    
        # Make a network with regularization
        y_conv = easier_network(x, FLAGS.regu)
        weights = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, 'EasyNet') 
        print("")
        for w in weights:
            shp = w.get_shape().as_list()
            print("- {} shape:{} size:{}".format(w.name, shp, np.prod(shp)))
        print("")
        reg_ws = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES, 'EasyNet')
        for w in reg_ws:
            shp = w.get_shape().as_list()
            print("- {} shape:{} size:{}".format(w.name, shp, np.prod(shp)))
        print("")
    
        # Make the loss function `loss_fn` with regularization.
        cross_entropy = tf.reduce_mean(
            tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
        loss_fn = cross_entropy + tf.reduce_sum(reg_ws)
        train_step = tf.train.AdamOptimizer(1e-4).minimize(loss_fn)
    

    为了实现这一点,您需要遵循我之前链接的MNIST教程并导入相关库,但是学习TensorFlow是一个很好的练习,很容易看出正则化如何影响输出 . 如果将正则化应用为参数,则可以看到以下内容:

    - EasyNet/fully_connected/weights:0 shape:[784, 200] size:156800
    - EasyNet/fully_connected/biases:0 shape:[200] size:200
    - EasyNet/fully_connected_1/weights:0 shape:[200, 200] size:40000
    - EasyNet/fully_connected_1/biases:0 shape:[200] size:200
    - EasyNet/fully_connected_2/weights:0 shape:[200, 10] size:2000
    - EasyNet/fully_connected_2/biases:0 shape:[10] size:10
    
    - EasyNet/fully_connected/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0
    - EasyNet/fully_connected_1/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0
    - EasyNet/fully_connected_2/kernel/Regularizer/l2_regularizer:0 shape:[] size:1.0
    

    请注意,正则化部分根据可用项目为您提供三个项目 .

    通过0,0.0001,0.01和1.0的正则化,我得到的测试精度值分别为0.9468,0.9476,0.9183和0.1135,显示了高正则化项的危险性 .

  • 15

    我在图中用 l2_regularizer 测试了 tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)tf.losses.get_regularization_loss() ,发现它们返回相同的值 . 通过观察值的数量,我猜通过设置 tf.contrib.layers.l2_regularizer 的参数,reg_constant已经对值有意义了 .

  • 57

    如果您有CNN,您可以执行以下操作:

    在您的模型功能中:

    conv = tf.layers.conv2d(inputs=input_layer,
                            filters=32,
                            kernel_size=[3, 3],
                            kernel_initializer='xavier',
                            kernel_regularizer=tf.contrib.layers.l2_regularizer(1e-5),
                            padding="same",
                            activation=None) 
    ...
    

    在你的损失函数中:

    onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=num_classes)
    loss = tf.losses.softmax_cross_entropy(onehot_labels=onehot_labels, logits=logits)
    regularization_losses = tf.losses.get_regularization_losses()
    loss = tf.add_n([loss] + regularization_losses)
    

相关问题