2017-09-13 128 views
0

我目前正试图熟悉Tensorflow库,并且我有一个相当基本的问题,那就是错误。Tensorflow:图层大小取决于批量大小?

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

,其中-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} 
    ) 

谢谢!

回答

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 
1

在典型场景中,features['x']的排名已经是4,外部尺寸为,实际批量大小为,所以不需要调整它的大小。

让我试着解释。

你还没有显示你的serving_input_receiver_fn,有几种方法可以做到这一点,尽管最终它们的原理是相似的。如果您使用TensorFlow Serving,那么您可能使用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 op解析占位符中的每个项目,并弹出一个外部维度为N的每个特征的张量。在你的情况下,你将有x shape = [N,30,30,1]。 (请注意,其他服务系统(如CloudML Engine)不会在Example对象上运行,但其原理相同)。

+0

我没有使用serving_input_receiver但我用'graph_util.convert_variables_to_constants()',然后调用'用tf.gfile.GFile(output_path, “WB”)为f愣图:f.write (output_graph_def.SerializeToString())'。但我想这也会将minibatch大小冻结到图中。 所以只是要清楚。我将需要一种服务器服务器后端而不是standart tensorflow库来执行训练有素的模型?由于我的模型非常小,应该执行得非常快,我正在寻找一种相当精益的解决方案。 – openloop

+0

我不知道是否冻结图形将批量大小冻结成图形;我会说它不应该。请注意,您可以在没有服务器后端的情况下相对简单地执行训练有素的模型。我建议将你的模型导出为SavedModel(你仍然可以冻结你的图形)。这为您提供了更好的可移植性,并且可以为推理提供更好的库(此外,如果需要,还可以在晚些时候轻松地选择更高级的服务解决方案)。有关如何使用SavedModel进行预测,请参阅https://stackoverflow.com/a/46139198/1399222。 – rhaertel80

+0

如果你不想使用SavedModel,其基本思想是利用'tensorflow.python.training.saver.import_meta_graph'那么你可以使用'session.Run'喂输入和读取输出。诀窍是获取输入和输出张量的正确名称。 – rhaertel80