Tensorflow:图层大小取决于批量大小?

时间:2017-09-13 09:21:50

标签: python tensorflow tensorflow-serving

我目前正在尝试熟悉Tensorflow库,我有一个相当基本的问题让我烦恼。

在构建用于MNIST分类的卷积神经网络时,我尝试使用自己的model_fn。通常会出现以下行来重塑输入要素。

x = tf.reshape(x, shape=[-1, 28, 28, 1]),-1表示输入批量大小。

因为我使用这个节点作为卷积层的输入,

x = tf.reshape(x, shape=[-1, 28, 28, 1]) 
conv1 = tf.layers.conv2d(x, 32, 5, activation=tf.nn.relu)

这是否意味着我所有网络图层的大小都取决于批量大小?

我尝试在单个测试输入上冻结并运行图形,这只有在我提供n = batch_size测试图像时才有效。

在预测时,您能否告诉我如何在任何输入批量大小上运行网络? 另外我想在网络定义中使用tf.reshape节点(参见cnn_layout 中的第一个节点)并不是最好的服务输入。

我将追加我的网络分层和model_fn

def cnn_layout(features,reuse,is_training):
 with tf.variable_scope('cnn',reuse=reuse):
    # resize input to [batchsize,height,width,channel]
    x = tf.reshape(features['x'], shape=[-1,30,30,1], name='input_placeholder')
    # conv1, 32 filter, 5 kernel
    conv1 = tf.layers.conv2d(x, 32, 5, activation=tf.nn.relu, name='conv1')
    # pool1, 2 stride, 2 kernel
    pool1 = tf.layers.max_pooling2d(conv1, 2, 2, name='pool1')
    # conv2, 64 filter, 3 kernel
    conv2 = tf.layers.conv2d(pool1, 64, 3, activation=tf.nn.relu, name='conv2')
    # pool2, 2 stride, 2 kernel
    pool2 = tf.layers.max_pooling2d(conv2, 2, 2, name='pool2')
    # flatten pool2
    flatten = tf.contrib.layers.flatten(pool2)
    # fc1 with 1024 neurons
    fc1 = tf.layers.dense(flatten, 1024, name='fc1')
    # 75% dropout
    drop = tf.layers.dropout(fc1, rate=0.75, training=is_training, name='dropout')
    # output logits
    output = tf.layers.dense(drop, 1, name='output_logits')
    return output


def model_fn(features, labels, mode):
    # setup two networks one for training one for prediction while sharing weights
    logits_train = cnn_layout(features=features,reuse=False,is_training=True)
    logits_test = cnn_layout(features=features,reuse=True,is_training=False)

    # predictions
    predictions = tf.round(tf.sigmoid(logits_test),name='predictions')
    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode, predictions=predictions)

    # define loss and optimizer
    loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logits_train,labels=labels),name='loss')
    optimizer = tf.train.AdamOptimizer(learning_rate=LEARNING_RATE, name='optimizer')
    train = optimizer.minimize(loss, global_step=tf.train.get_global_step(),name='train')

    # accuracy for evaluation
    accuracy = tf.metrics.accuracy(labels=labels,predictions=predictions,name='accuracy')

    # summarys for tensorboard
    tf.summary.scalar('loss',loss)

    # return training and evalution spec
    return tf.estimator.EstimatorSpec(
        mode=mode,
        predictions=predictions,
        loss=loss,
        train_op=train,
        eval_metric_ops={'accuracy':accuracy}
    )

谢谢!

2 个答案:

答案 0 :(得分:1)

在典型情况下,features['x']的排名已经是4,外部维度实际批量大小,因此无需调整大小。

让我试着解释一下。

你还没有展示过你的serving_input_receiver_fn,有几种方法可以做到这一点,尽管最后这些原则在所有方面都是相似的。如果您正在使用TensorFlow服务,那么您可能使用build_parsing_serving_input_receiver_fn。查看源代码是有用的信息:

def build_parsing_serving_input_receiver_fn(feature_spec,
                                            default_batch_size=None):    
  serialized_tf_example = array_ops.placeholder(
      dtype=dtypes.string,
      shape=[default_batch_size],                                      
      name='input_example_tensor')
  receiver_tensors = {'examples': serialized_tf_example}
  features = parsing_ops.parse_example(serialized_tf_example, feature_spec)
  return ServingInputReceiver(features, receiver_tensors)

因此,在您的客户端中,您将准备一个包含一个或多个Example的请求(假设长度为N)。服务器将序列化示例视为一个字符串列表,这些字符串被“馈送”到input_example_tensor占位符中。形状(None)动态填充为列表的大小(N)。

然后parse_example操作分析占位符中的每个项目,然后为外部维度为N的每个要素弹出Tensor。在您的情况下,您将x具有shape = [N,30,30,1]。

(请注意,其他服务系统,例如CloudML Engine,不对Example个对象进行操作,但原则是相同的。)

答案 1 :(得分:0)

我只想简要地提供我找到的解决方案。因为我不想构建可扩展的生产等级模型,而是在python中使用简单的模型运行器来在本地执行我的CNN。

要导出我使用的模型,

input_size = 900

def serving_input_receiver_fn():
    inputs = {"x": tf.placeholder(shape=[None, input_size], dtype=tf.float32)}
    return tf.estimator.export.ServingInputReceiver(inputs, inputs)

model.export_savedmodel(
    export_dir_base=model_dir,
    serving_input_receiver_fn=serving_input_receiver_fn)

加载并运行它(不需要再次进行模型定义)我使用了tensorflow预测器类。

from tensorflow.contrib import predictor

class TFRunner:
    """ runs a frozen cnn graph """
    def __init__(self,model_dir):
        self.predictor = predictor.from_saved_model(model_dir)

    def run(self, input_list):
        """ runs the input list through the graph, returns output """
        if len(input_list) > 1:
            inputs = np.vstack(input_list)
            predictions = self.predictor({"x": inputs})
        elif len(input_list) == 1:
            predictions = self.predictor({"x": input_list[0]})
        else:
            predictions = []
        return predictions