2017-04-30 37 views
11

我一直在挖掘這一段時間。我發現了很多文章;但沒有一個真正顯示出張量推斷是一個明確的推論。它始終「使用服務引擎」或使用預先編碼/定義的圖形。TensorFlow推理

這是問題:我有一個偶爾檢查更新模型的設備。然後需要加載該模型並通過模型運行輸入預測。

在keras中這很簡單:構建模型;訓練模型和調用model.predict()。在scikit學習同樣的事情。

我能夠抓住一個新的模型並加載它;我可以打印出所有的重量;但我如何在世界上推論它呢?

代碼加載模式和打印權:

with tf.Session() as sess: 
     new_saver = tf.train.import_meta_graph(MODEL_PATH + '.meta', clear_devices=True) 
     new_saver.restore(sess, MODEL_PATH) 
     for var in tf.trainable_variables(): 
      print(sess.run(var)) 

我打印出我所有的收藏品,我有: [ 'queue_runners', '變量', '損失', '摘要',「train_op ','cond_context','trainable_variables']

我試過使用sess.run(train_op);不過剛剛開始舉辦完整的培訓課程;這不是我想要做的。我只是想對我提供的不是TF記錄的一組不同的輸入進行推理。

只要稍微更詳細地:

的裝置可以使用C++或Python;只要我能生成一個.exe。如果我想餵養系統,我可以設置飼料字典。我用TFRecords訓練;但在製作中我不會使用TFRecords;它是一個真實/近實時系統。

感謝您的任何意見。我將示例代碼發佈到此回購:https://github.com/drcrook1/CIFAR10/TensorFlow,它進行所有培訓和樣本推斷。

任何提示,非常感謝!

------------編輯----------------- 我重建模型可考慮如下:

def inference(images): 
''' 
Portion of the compute graph that takes an input and converts it into a Y output 
''' 
with tf.variable_scope('Conv1') as scope: 
    C_1_1 = ld.cnn_layer(images, (5, 5, 3, 32), (1, 1, 1, 1), scope, name_postfix='1') 
    C_1_2 = ld.cnn_layer(C_1_1, (5, 5, 32, 32), (1, 1, 1, 1), scope, name_postfix='2') 
    P_1 = ld.pool_layer(C_1_2, (1, 2, 2, 1), (1, 2, 2, 1), scope) 
with tf.variable_scope('Dense1') as scope: 
    P_1 = tf.reshape(C_1_2, (CONSTANTS.BATCH_SIZE, -1)) 
    dim = P_1.get_shape()[1].value 
    D_1 = ld.mlp_layer(P_1, dim, NUM_DENSE_NEURONS, scope, act_func=tf.nn.relu) 
with tf.variable_scope('Dense2') as scope: 
    D_2 = ld.mlp_layer(D_1, NUM_DENSE_NEURONS, CONSTANTS.NUM_CLASSES, scope) 
H = tf.nn.softmax(D_2, name='prediction') 
return H 

通知我將名稱'預測'添加到TF操作中,以便稍後可以檢索它。

在訓練時,我使用輸入管道進行tfrecords和輸入隊列。

GRAPH = tf.Graph() 
with GRAPH.as_default(): 
    examples, labels = Inputs.read_inputs(CONSTANTS.RecordPaths, 
              batch_size=CONSTANTS.BATCH_SIZE, 
              img_shape=CONSTANTS.IMAGE_SHAPE, 
              num_threads=CONSTANTS.INPUT_PIPELINE_THREADS) 
    examples = tf.reshape(examples, [CONSTANTS.BATCH_SIZE, CONSTANTS.IMAGE_SHAPE[0], 
            CONSTANTS.IMAGE_SHAPE[1], CONSTANTS.IMAGE_SHAPE[2]]) 
    logits = Vgg3CIFAR10.inference(examples) 
    loss = Vgg3CIFAR10.loss(logits, labels) 
    OPTIMIZER = tf.train.AdamOptimizer(CONSTANTS.LEARNING_RATE) 

我試圖在圖中加載的操作上使用feed_dict;但現在它只是簡單地掛....

MODEL_PATH = 'models/' + CONSTANTS.MODEL_NAME + '.model' 

images = tf.placeholder(tf.float32, shape=(1, 32, 32, 3)) 

def run_inference(): 
'''Runs inference against a loaded model''' 
with tf.Session() as sess: 
    #sess.run(tf.global_variables_initializer()) 
    new_saver = tf.train.import_meta_graph(MODEL_PATH + '.meta', clear_devices=True) 
    new_saver.restore(sess, MODEL_PATH) 
    pred = tf.get_default_graph().get_operation_by_name('prediction') 
    rand = np.random.rand(1, 32, 32, 3) 
    print(rand) 
    print(pred) 
    print(sess.run(pred, feed_dict={images: rand})) 
    print('done') 

run_inference() 

我相信這是行不通的,因爲原來的網絡是使用TFRecords訓練。在樣本CIFAR數據集中,數據很小;我們的真實數據集是巨大的,這是我的理解TFRecords是訓練網絡的默認最佳做法。 feed_dict從製作的角度來說非常完美。我們可以啓動一些線程並從我們的輸入系統中填充該內容。

所以我想我有一個訓練有素的網絡,我可以得到預測的操作;但是如何告訴它停止使用輸入隊列並開始使用feed_dict?請記住,從生產的角度來看,我無法獲得科學家所做的任何事情。他們做他們的事情;而且我們使用任何一致的標準來堅持生產。

------- INPUT OPS --------

tf.Operation '輸入/ input_producer/CONST' 類型=常數,tf.Operation '輸入/ input_producer /尺寸' 型= Const,tf.Operation'input/input_producer/Greater/y'type = Const,tf.Operation'input/input_producer/Greater'type = Greater,tf.Operation'input/input_producer/Assert/Const'type = Const,tf .Operation'input/input_producer/Assert/Assert/data_0'type = Const,tf.Operation'input/input_producer/Assert/Assert'type = Assert,tf.Operation'input/input_producer/Identity'type = Identity,tf.Operation 'input/input_producer/RandomShuffle'type = RandomShuffle,tf.Operation'input/input_producer'type = FIFOQueueV2,tf.Operation'input/input_producer/input_producer_EnqueueMany'type = QueueEnqueueManyV2,tf.Operation'input/input_producer/input_pr oducer_Close'type = QueueCloseV2,tf.Operation'input/input_producer/input_producer_Close_1'type = QueueCloseV2,tf.Operation'input/input_producer/input_producer_Size'type = QueueSizeV2,tf.Operation'input/input_producer/Cast'type = Cast,tf。 'input/input_producer/mul/y'type = Const,tf.Operation'input/input_producer/mul'type = Mul,tf.Operation'input/input_producer/fraction_of_32_full/tags'type = Const,tf.Operation'input/input_producer/fraction_of_32_full」類型= ScalarSummary,tf.Operation '輸入/ TFRecordReaderV2' 類型= TFRecordReaderV2,tf.Operation '輸入/ ReaderReadV2' 類型= ReaderReadV2,

------ END INPUT OPS -----

---- UPDATE 3 ----

我相信我需要做的是殺死使用TF記錄訓練過的圖形的輸入部分,並重新將第一層的輸入連接到新輸入。它有點像表演手術;但是這是我能找到做推斷,如果我訓練使用TFRecords瘋狂,因爲它聽起來的唯一途徑...

全圖顯示:

enter image description here

科殺:

enter image description here

所以我認爲這個問題變成:如何殺死圖形的輸入部分並用feed_dict替換它?

跟進這將是:這真的是正確的方法嗎?這似乎是瘋狂的。

----結束時更新3 ----

---鏈接到檢查點文件---

https://drcdata.blob.core.windows.net/checkpoints/CIFAR_10_VGG3_50neuron_1pool_1e-3lr_adam.model.zip?st=2017-05-01T21%3A56%3A00Z&se=2020-05-02T21%3A56%3A00Z&sp=rl&sv=2015-12-11&sr=b&sig=oBCGxlOusB4NOEKnSnD%2FTlRYa5NKNIwAX1IyuZXAr9o%3D

--end鏈接到檢查點文件---

UPDATE ----- ----- 4

我給的,只是在執行推斷假設我能有科學家只是簡單醃製的「正常」的方式給予了他們出手模型,我們可以抓住模型泡菜;解壓它,然後對其進行推理。因此,爲了測試,我假設我們已經解包了它,嘗試了正常的方式......它不值得一豆......

import tensorflow as tf 
import CONSTANTS 
import Vgg3CIFAR10 
import numpy as np 
from scipy import misc 
import time 

MODEL_PATH = 'models/' + CONSTANTS.MODEL_NAME + '.model' 
imgs_bsdir = 'C:/data/cifar_10/train/' 

images = tf.placeholder(tf.float32, shape=(1, 32, 32, 3)) 

logits = Vgg3CIFAR10.inference(images) 

def run_inference(): 
'''Runs inference against a loaded model''' 
with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer()) 
    new_saver = tf.train.import_meta_graph(MODEL_PATH + '.meta')#, import_scope='1', input_map={'input:0': images}) 
    new_saver.restore(sess, MODEL_PATH) 
    pred = tf.get_default_graph().get_operation_by_name('prediction') 
    enq = sess.graph.get_operation_by_name(enqueue_op) 
    #tf.train.start_queue_runners(sess) 
    print(rand) 
    print(pred) 
    print(enq) 
    for i in range(1, 25): 
     img = misc.imread(imgs_bsdir + str(i) + '.png').astype(np.float32)/255.0 
     img = img.reshape(1, 32, 32, 3) 
     print(sess.run(logits, feed_dict={images : img})) 
     time.sleep(3) 
    print('done') 

run_inference() 

Tensorflow結束了建設有從所加載的模型的推理功能的新的曲線圖。那麼它會將其他所有圖形的其他圖形追加到其結尾。那麼當我填充feed_dict期望得到推論時,我只是得到了一堆隨機的垃圾,好像它是第一次通過網絡......

試;這看起來很瘋狂;我真的需要編寫自己的框架來序列化和反序列化隨機網絡嗎?這不得不以前做過......

UPDATE ----- ----- 4

試;謝謝!

回答

8

好吧,這花了太多的時間來弄清楚;所以這裏是世界其他地方的答案。

快速提示:我需要堅持一個可以動態加載和推斷的模型,而不需要知道它是如何工作的。

步驟1:創建一個模型作爲類和理想的使用接口定義

class Vgg3Model: 

NUM_DENSE_NEURONS = 50 
DENSE_RESHAPE = 32 * (CONSTANTS.IMAGE_SHAPE[0] // 2) * (CONSTANTS.IMAGE_SHAPE[1] // 2) 

def inference(self, images): 
    ''' 
    Portion of the compute graph that takes an input and converts it into a Y output 
    ''' 
    with tf.variable_scope('Conv1') as scope: 
     C_1_1 = ld.cnn_layer(images, (5, 5, 3, 32), (1, 1, 1, 1), scope, name_postfix='1') 
     C_1_2 = ld.cnn_layer(C_1_1, (5, 5, 32, 32), (1, 1, 1, 1), scope, name_postfix='2') 
     P_1 = ld.pool_layer(C_1_2, (1, 2, 2, 1), (1, 2, 2, 1), scope) 
    with tf.variable_scope('Dense1') as scope: 
     P_1 = tf.reshape(P_1, (-1, self.DENSE_RESHAPE)) 
     dim = P_1.get_shape()[1].value 
     D_1 = ld.mlp_layer(P_1, dim, self.NUM_DENSE_NEURONS, scope, act_func=tf.nn.relu) 
    with tf.variable_scope('Dense2') as scope: 
     D_2 = ld.mlp_layer(D_1, self.NUM_DENSE_NEURONS, CONSTANTS.NUM_CLASSES, scope) 
    H = tf.nn.softmax(D_2, name='prediction') 
    return H 

def loss(self, logits, labels): 
    ''' 
    Adds Loss to all variables 
    ''' 
    cross_entr = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels) 
    cross_entr = tf.reduce_mean(cross_entr) 
    tf.summary.scalar('cost', cross_entr) 
    tf.add_to_collection('losses', cross_entr) 
    return tf.add_n(tf.get_collection('losses'), name='total_loss') 

第二步:你想要的任何投入訓練你的網絡;在我的例子中,我使用了Queue Runners和TF Records。請注意,這一步由一個不同的團隊完成,它可以迭代,構建,設計和優化模型。這也可以隨着時間改變。它們產生的輸出必須能夠從遠程位置拉出,以便我們可以動態地在設備上加載更新的模型(如果硬件在地理上分佈,則更新硬件是一種痛苦)。在這種情況下;該團隊將刪除與圖形保存程序關聯的3個文件;而且使用的模型的鹹菜培訓會議

model = vgg3.Vgg3Model() 

def create_sess_ops(): 
''' 
Creates and returns operations needed for running 
a tensorflow training session 
''' 
GRAPH = tf.Graph() 
with GRAPH.as_default(): 
    examples, labels = Inputs.read_inputs(CONSTANTS.RecordPaths, 
              batch_size=CONSTANTS.BATCH_SIZE, 
              img_shape=CONSTANTS.IMAGE_SHAPE, 
              num_threads=CONSTANTS.INPUT_PIPELINE_THREADS) 
    examples = tf.reshape(examples, [-1, CONSTANTS.IMAGE_SHAPE[0], 
            CONSTANTS.IMAGE_SHAPE[1], CONSTANTS.IMAGE_SHAPE[2]], name='infer/input') 
    logits = model.inference(examples) 
    loss = model.loss(logits, labels) 
    OPTIMIZER = tf.train.AdamOptimizer(CONSTANTS.LEARNING_RATE) 
    gradients = OPTIMIZER.compute_gradients(loss) 
    apply_gradient_op = OPTIMIZER.apply_gradients(gradients) 
    gradients_summary(gradients) 
    summaries_op = tf.summary.merge_all() 
    return [apply_gradient_op, summaries_op, loss, logits], GRAPH 

def main(): 
''' 
Run and Train CIFAR 10 
''' 
print('starting...') 
ops, GRAPH = create_sess_ops() 
total_duration = 0.0 
with tf.Session(graph=GRAPH) as SESSION: 
    COORDINATOR = tf.train.Coordinator() 
    THREADS = tf.train.start_queue_runners(SESSION, COORDINATOR) 
    SESSION.run(tf.global_variables_initializer()) 
    SUMMARY_WRITER = tf.summary.FileWriter('Tensorboard/' + CONSTANTS.MODEL_NAME, graph=GRAPH) 
    GRAPH_SAVER = tf.train.Saver() 

    for EPOCH in range(CONSTANTS.EPOCHS): 
     duration = 0 
     error = 0.0 
     start_time = time.time() 
     for batch in range(CONSTANTS.MINI_BATCHES): 
      _, summaries, cost_val, prediction = SESSION.run(ops) 
      error += cost_val 
     duration += time.time() - start_time 
     total_duration += duration 
     SUMMARY_WRITER.add_summary(summaries, EPOCH) 
     print('Epoch %d: loss = %.2f (%.3f sec)' % (EPOCH, error, duration)) 
     if EPOCH == CONSTANTS.EPOCHS - 1 or error < 0.005: 
      print(
       'Done training for %d epochs. (%.3f sec)' % (EPOCH, total_duration) 
      ) 
      break 
    GRAPH_SAVER.save(SESSION, 'models/' + CONSTANTS.MODEL_NAME + '.model') 
    with open('models/' + CONSTANTS.MODEL_NAME + '.pkl', 'wb') as output: 
     pickle.dump(model, output) 
    COORDINATOR.request_stop() 
    COORDINATOR.join(THREADS) 

步驟3:運行一些推理。加載你的酸洗模型;通過在新的佔位符中輸入新的圖形創建一個新圖形;然後調用會話恢復。不要恢復整個圖形;只是變數。

MODEL_PATH = 'models/' + CONSTANTS.MODEL_NAME + '.model' 
imgs_bsdir = 'C:/data/cifar_10/train/' 

images = tf.placeholder(tf.float32, shape=(1, 32, 32, 3)) 
with open('models/vgg3.pkl', 'rb') as model_in: 
model = pickle.load(model_in) 
logits = model.inference(images) 

def run_inference(): 
'''Runs inference against a loaded model''' 
with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer()) 
    new_saver = tf.train.Saver() 
    new_saver.restore(sess, MODEL_PATH) 
    print("Starting...") 
    for i in range(20, 30): 
     print(str(i) + '.png') 
     img = misc.imread(imgs_bsdir + str(i) + '.png').astype(np.float32)/255.0 
     img = img.reshape(1, 32, 32, 3) 
     pred = sess.run(logits, feed_dict={images : img}) 
     max_node = np.argmax(pred) 
     print('predicted label: ' + str(max_node)) 
    print('done') 

run_inference() 

有一定的方法來改進這一使用接口,也許包裝起來的一切美好;但這正在發揮作用,併爲我們如何向前邁進奠定了基礎。

最後要注意當我們好不容易擠到這個到生產,我們最後不得不出貨愚蠢mymodel_model.py文件打倒一切建立起來的圖形。因此,我們現在對所有模型實施一個命名約定,並且還有一個用於生產模型運行的編碼標準,以便我們可以正確執行此操作。

祝你好運!

+1

對於那些有興趣的人來說,這是太多的歌舞。現在我們使用CNTK來代替...爲所有團隊規範所有內容並且始終如一地投入生產更容易。 –

2

雖然它不是添油加醋model.predict(),它仍然是真是小巫見大巫。

在你的模型,你應該有一個計算你感興趣的最終輸出的張量,讓我們名張量output。您目前可能只是有一個損失功能。如果是這樣,則創建另一個實際計算所需輸出的張量(模型中的變量)。

例如,如果你的損失函數爲:

tf.nn.sigmoid_cross_entropy_with_logits(last_layer_activation, labels) 

,你希望你的輸出,在每類範圍[0,1],創建另一個變量:

output = tf.sigmoid(last_layer_activation) 

現在,當你調用sess.run(...)只是要求output張量。不要求優化OP,你通常會訓練它。當你請求這個變量時,張量流將做出產生該值所需的最小工作量(例如,它不會因反向傳播,損失函數以及所有這些因爲簡單的前饋傳遞就是計算所需的全部內容)

所以,如果你正在創建的服務來回報模型的推論,你會想要保留在內存/ GPU負載模型,並重復:

sess.run(output, feed_dict={X: input_data}) 

你不需要給它的標籤,因爲tensorflow不會刻意去計算那些不需要產生您所請求的輸出歡聲笑語。你不必改變你的模型或任何東西。

雖然這種方法可能不如model.predict(...)那麼明顯,但我認爲它非常靈活。如果你開始玩更復雜的模型,你可能會學會喜歡這種方法。 model.predict()就像「在箱子裏思考」。

+0

我唯一跟進的問題是;如何從圖表中提取'輸出'?總是將最終張量'輸出'命名爲「界面」定義,我感到非常高興。問題是設備只能訪問模型/檢查點文件;它沒有圖形構造代碼。 –

+0

我向softmax圖層添加了一個名稱,希望能夠檢索該張量並給出一個鏡頭:H = tf.nn.softmax(D_2,name ='prediction')之前該張量尚未明確命名。 –

+0

給這個鏡頭;並且似乎簡單地鎖定:用tf.Session()作爲編碼擴頻通信: new_saver = tf.train.import_meta_graph(MODEL_PATH + '.META',clear_devices =真) new_saver.restore(SESS,MODEL_PATH) PRED = TF .get_default_graph()。get_operation_by_name('prediction') print(sess.run(pred,feed_dict = {images:np.random.rand(1,32,32,3)})) –