2017-09-13 54 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