【问题标题】:Regularization of ConvLSTM inside Tensorflow estimatorTensorflow 估计器中 ConvLSTM 的正则化
【发布时间】:2018-02-12 11:01:52
【问题描述】:

我在估计器的 model_fn 中使用来自 Tensorflow 1.5 的 contrib 包的卷积 LSTM 单元。我想向该单元格添加 L2 正则化。我尝试了以下代码:

def myModelFn(features,labels,mode,params):
  trainingFlag = (mode == tf.estimator.ModeKeys.TRAIN)
  inferFlag = (mode == tf.estimator.ModeKeys.PREDICT)

  dataShape = tuple(params['dataShape'])

  XSize,YSize,ZSize = dataShape[0],dataShape[1],dataShape[2]

  dataTensor = features['data']
  dataTensor = tf.reshape(dataTensor, [-1, XSize, YSize, ZSize, 1])

  labelTensor = tf.cast(labels['labels'], tf.int64)

  with tf.variable_scope('myModel'):
    normalizedData = tf.layers.batch_normalization(dataTensor,
                             center=True,
                             scale=True,
                             training=trainingFlag,
                             name='bnInput')

  with tf.variable_scope('module1'):
    conv1 = tf.layers.conv3d(normalizedData,
                         filters = 3,
                         kernel_size = (5,5,5),
                         kernel_regularizer=tf.nn.l2_loss,
                         name='conv3d_1')

    max1 = tf.layers.max_pooling3d(conv1,
                                pool_size = (5,5,5),
                                strides= (2,2,2),
                                name = 'max_1')

这里是我创建 convLSTM2D 的地方,我想在其中添加 L2 正则化:

  with tf.variable_scope('module2'):
    lstmInput = tf.transpose(max1, [0, 3, 1, 2, 4], 'lstmInput')

    lstmInputShape = lstmInput.shape.as_list()[2:]
    lstmInput = tf.unstack(lstmInput, axis=1)
    convLSTMNet = tf.contrib.rnn.ConvLSTMCell(conv_ndims=2,                                
                                           input_shape=lstmInputShape,
                                           output_channels=3,
                                           kernel_shape=[3, 3],
                                           use_bias=True,
                                           name='lstmConv2d')

  lstmKernelVars = [var for var in tf.trainable_variables(
    convLSTMNet.scope_name) if 'kernel' in var.name]

  tf.contrib.layers.apply_regularization(tf.nn.l2_loss,
                                         lstmKernelVars)

  lstmOutput, _ = tf.nn.static_rnn(convLSTMNet, lstmInput,
                                dtype=tf.float32)[-1]

  module2Output = tf.layers.flatten(lstmOutput, name='module2Output')

  with tf.variable_scope('module3'):
    dense1 = tf.layers.dense(module2Output, 150, name='dense1')
    dropout1 = tf.layers.dropout(dense1, 0.6, training=trainingFlag,
                          name='dropout1')
    dense2 = tf.layers.dense(dropout1,50,name='dense2')
    dropout2 = tf.layers.dropout(dense2, 0.5, training=trainingFlag,
                          name='dropout2')
    logits = tf.layers.dense(dropout2, 4, name='logits')

  outputLabel = tf.nn.softmax(logits,name='myLabel')

  predictions = {'prediction': tf.cast(tf.argmax(outputLabel, 1), tf.int64)}

  if not inferFlag:
    loss = tf.reduce_mean(
    tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits,
                                                 labels=labelTensor),
                                                 name='myLoss')

    l2Loss = tf.reduce_sum(
    tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES), name='l2Loss')

    fullLoss = tf.add(loss, l2Loss)
    tf.summary.scalar('fullLoss', fullLoss)

  if trainingFlag:
    globalStep = tf.train.get_global_step()

    optimizer = tf.train.AdamOptimizer()

    updateOps = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
    with tf.control_dependencies(updateOps):
      trainOp = optimizer.minimize(
        fullLoss, global_step=globalStep)
  else:
    trainOp = None

  if not inferFlag:
    evalOp = tf.metrics.accuracy(labelTensor,predictions['prediction'])


  return tf.estimator.EstimatorSpec(mode, predictions, fullLoss, trainOp,
                                  evalOp)

我收到以下错误消息:

ValueError: 图层范围没有可用的名称,因为尚未使用图层“lstmConv2d”。范围名称是在第一次调用层实例时确定的。因此,您必须在查询 'scope_name' 之前调用该层

如果我用任何其他类型的 tf.layer 替换 convLSTM2D/static_rnn,它工作正常(如果我使用 kernel_regularizer=tf.nn.l2_loss)...

【问题讨论】:

    标签: python tensorflow conv-neural-network lstm tensorflow-estimator


    【解决方案1】:

    我无法重现这个确切的错误消息。但无论如何,trainable_weights 的这种使用是不对的,因为这个集合包含在单元格内创建的 所有 变量,包括 bias(由于use_bias=True 而存在)。正则化偏差通常不是一个好主意,例如on CV.SE

    要获得只是内核,请执行以下操作:

    variables = [var for var in tf.trainable_variables(convLSTMNet.scope_name) 
                 if 'kernel' in var.name]
    

    ...它从单元范围(在您的情况下为'rnn/lstmConv2d')抓取所有内容并仅过滤内核。

    如果不返回变量,首先要检查整个tf.trainable_variables() 集合;接下来,确保 LSTM 单元已在层中实例化,即检查实际的 lstmInput 长度是多少。这将帮助您缩小问题范围(很可能不在提供的 sn-p 范围内)。

    【讨论】:

    • 我已经尝试了您的建议,但不幸的是,它没有奏效。我收到以下错误:ValueError:图层范围没有可用的名称,因为尚未使用图层“lstmConv2d”。范围名称是在第一次调用层实例时确定的。因此,您必须在查询 scope_name 之前调用该层
    • 我已经运行了测试:图形是在模型 fn 中构建的,并且可训练的变量会被填充。您应该提供一个可重现的示例
    【解决方案2】:

    您的convLSTMNet 已经有一个由您分配的变量名称lstmConv2d

    所以只需调用:

    myvariables = [var for var in tf.trainable_variables() if  var.name.split('/')[0] in ['lstmConv2d']]
    

    convLSTMNet 中有所有变量,然后可以筛选内核:

    myvariables = [var for var in myvariables if 'kernel' in var.name]
    

    【讨论】:

      猜你喜欢
      • 2018-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-26
      • 2019-01-04
      相关资源
      最近更新 更多