首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >TensorFlow推理

TensorFlow推理
EN

Stack Overflow用户
提问于 2017-05-01 00:25:39
回答 2查看 26K关注 0票数 22

我在这方面已经研究了一段时间了。我找到了一大堆文章;但没有一篇真正将tensorflow推理作为一种简单的推断。它总是“使用服务引擎”或使用预编码/定义的图形。

这就是问题所在:我有一个设备,它偶尔会检查更新的模型。然后,它需要加载该模型,并通过该模型运行输入预测。

在keras中,这很简单:构建一个模型;训练模型并调用model.predict()。在scikit中-学习相同的东西。

我可以抓取一个新的模型并加载它;我可以打印出所有的权重;但我到底如何对它运行推断?

加载模型和打印权重的代码:

代码语言:javascript
运行
复制
    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','variables','losses','summaries','train_op','cond_context','trainable_variables‘

我试着使用sess.run(train_op);然而,这只是开始了一个完整的培训课程;这不是我想要做的。我只想对我提供的一组不同的输入运行推断,这些输入不是TF记录。

只需要更多的细节:

只要我能生成一个.exe,这个设备就可以使用C++或Python。我可以设置一个输入字典,如果我想输入系统的话。我是用TFRecords训练的;但在生产中我不打算使用TFRecords;它是一个实时/接近实时的系统。

感谢您的任何意见。我将示例代码发布到这个代码库:https://github.com/drcrook1/CIFAR10/TensorFlow,它执行所有的训练和样本推理。

任何提示都是非常感谢的!

-编辑-我将模型重建如下:

代码语言:javascript
运行
复制
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

请注意,我将名称'prediction'添加到TF操作中,以便稍后检索它。

在训练时,我将输入管道用于tfrecords和输入队列。

代码语言:javascript
运行
复制
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;但是现在它只是简单地挂起了……

代码语言:javascript
运行
复制
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?请记住,从生产的角度来看,我无法访问科学家为制造它所做的任何事情。他们做他们自己的事情;我们使用任何商定的标准将其投入生产。

-输入运维

tf.Operation 'input/input_producer/Const‘type=Const,tf.Operation 'input/input_producer/Size’type=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/data_0‘type=Const,tf.Operation 'input/input_producer/Assert/Assert’type=Assert,tf.Operation 'input/input_producer/Identity‘type=Identity,'input/input_producer/input_producer_EnqueueMany‘’tf.Operation /input_producer/RandomShuffle‘type=RandomShuffle,tf.Operation 'input/input_producer’type=FIFOQueueV2,tf.Operation Size type=QueueEnqueueManyV2,tf.Operation 'input/input_producer/input_producer_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.Operation 'input/input_producer/mul/y‘type=Const,tf.Operation 'input/input_producer/mul‘type=Mul,tf.Operation tf.Operation type=Const,tf.Operation’input/input_producer/ tf.Operation _of_32_full‘type=ScalarSummary,tf.Operation 'input/TFRecordReaderV2’type=TFRecordReaderV2,tf.Operation 'input/ReaderReadV2‘type=ReaderReadV2,

-结束输入运算量

--更新3

我认为我需要做的是杀死用TF Records训练的图形的输入部分,并将第一层的输入重新连接到一个新的输入。这有点像做手术;但如果我使用TFRecords训练,就像听起来那么疯狂,这是我唯一能找到的推断方法……

全图:

要终止的部分:

因此,我认为问题变成了:如何删除图形的输入部分,并将其替换为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

--结束到检查点文件的链接

-更新4

我放弃了,只是尝试了一种“正常”的推理方式,假设我可以让科学家简单地挑选他们的模型,我们就可以抓住模型的泡菜;打开它,然后对它运行推理。因此,为了测试,我尝试了正常的方法,假设我们已经解包的it...It也不值得工作……

代码语言:javascript
运行
复制
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,希望得到推断的时候;我只是得到了一堆随机的垃圾,就像它是第一次通过网络一样……

再说一次,这看起来很疯狂;我真的需要编写自己的框架来序列化和反序列化随机网络吗?这必须是以前做过的……

-更新4

再次强调;谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-03 03:21:47

好吧,这花了太多的时间来解决;所以这就是世界上其他地方的答案。

快速提醒:我需要持久化一个可以动态加载和推断的模型,而不需要知道它是如何工作的。

第1步:将模型创建为类,理想情况下使用接口定义

代码语言:javascript
运行
复制
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')

Step 2:使用您想要的任何输入训练您的网络;在我的例子中,我使用了Queue Runners和TF Record。请注意,此步骤是由一个不同的团队完成的,该团队负责迭代、构建、设计和优化模型。这也会随着时间的推移而改变。它们产生的输出必须能够从远程位置拉出,以便我们可以动态地将更新后的模型加载到设备上(重新刷新硬件是一种痛苦,特别是如果它是地理上分布的)。在这种情况下,团队丢弃了与图形保护程序关联的3个文件;但也丢弃了用于该培训会话的模型

代码语言:javascript
运行
复制
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步:运行一些推断。加载您的酸洗模型;通过管道将新占位符输入到logits来创建一个新图;然后调用会话还原。不要恢复整个GRAPH;只恢复变量。

代码语言:javascript
运行
复制
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文件与构建图形的所有内容一起发送下来。因此,我们现在对所有模型都强制执行命名约定,并且对于生产模型运行也有一个编码标准,因此我们可以正确地执行此操作。

祝好运!

票数 19
EN

Stack Overflow用户

发布于 2017-05-01 01:35:24

虽然它不像model.predict()那样简单,但它仍然是微不足道的。

在你的模型中,你应该有一个张量来计算你感兴趣的最终输出,让我们将这个张量命名为output。你现在可能只有一个损失函数。如果是这样的话,创建另一个张量(模型中的变量)来实际计算您想要的输出。

例如,如果您的损失函数为:

代码语言:javascript
运行
复制
tf.nn.sigmoid_cross_entropy_with_logits(last_layer_activation, labels)

如果您希望每个类的输出在0,1范围内,请创建另一个变量:

代码语言:javascript
运行
复制
output = tf.sigmoid(last_layer_activation)

现在,当您调用sess.run(...)时,只需请求output张量。不要要求优化操作,你通常会训练它。当你请求这个变量时,tensorflow将做最少的工作来产生这个值(例如,它不会为backprop,loss函数以及所有这些而烦恼,因为一个简单的前馈传递就是计算output所需的全部。

因此,如果您要创建一个服务来返回模型的推论,您需要将模型加载到内存/gpu中,然后重复:

代码语言:javascript
运行
复制
sess.run(output, feed_dict={X: input_data})

您不需要向它提供标签,因为tensorflow不会计算生成请求的输出所不需要的操作。你不需要改变你的模型或者其他任何东西。

虽然这种方法可能没有model.predict(...)那么明显,但我认为它要灵活得多。如果你开始尝试更复杂的模型,你可能会喜欢上这种方法。model.predict()就像是“在盒子里思考”。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43708616

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档