TensorFlow Inferentie

TensorFlow Inferentie

Oké, dit kostte veel te veel tijd om erachter te komen; dus hier is het antwoord voor de rest van de wereld.

Snelle herinnering :Ik moest een model volhouden dat dynamisch kan worden geladen en afgeleid zonder kennis van de onderliggende spelden of binnenkanten van hoe het werkt.

Stap 1 :Maak een model als een klasse en gebruik idealiter een interfacedefinitie

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')

Stap 2 :Train uw netwerk met de inputs die u maar wilt; in mijn geval gebruikte ik Queue Runners en TF Records. Merk op dat deze stap wordt gedaan door een ander team dat modellen itereert, bouwt, ontwerpt en optimaliseert. Ook dit kan in de loop van de tijd veranderen. De output die ze produceren, moet van een externe locatie kunnen worden gehaald, zodat we de bijgewerkte modellen dynamisch op apparaten kunnen laden (hardware opnieuw flashen is lastig, vooral als deze geografisch verspreid is). Op dit moment; het team laat de 3 bestanden vallen die zijn gekoppeld aan een grafiekbesparing; maar ook een augurk van het model dat voor die trainingssessie werd gebruikt

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)

Stap 3 :Voer een inferentie uit. Laad je ingelegde model; maak een nieuwe grafiek door de nieuwe tijdelijke aanduiding naar de logits te pipen; en bel vervolgens sessieherstel. HERSTEL NIET DE HELE GRAFIEK; ALLEEN DE VARIABELEN.

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()

Er zijn zeker manieren om dit te verbeteren met behulp van interfaces en misschien alles beter in te pakken; maar dit werkt en vormt de basis voor hoe we verder zullen gaan.

SLOTOPMERKING Toen we dit uiteindelijk in productie brachten, moesten we uiteindelijk het stomme `mymodel_model.py-bestand naar beneden sturen met alles om de grafiek op te bouwen. Dus we dwingen nu een naamgevingsconventie af voor alle modellen en er is ook een coderingsstandaard voor productiemodelruns, zodat we dit goed kunnen doen.

Veel succes!


Hoewel het niet zo eenvoudig is als model.predict(), is het nog steeds erg triviaal.

In uw model zou u een tensor moeten hebben die de uiteindelijke uitvoer berekent waarin u geïnteresseerd bent, laten we die tensor een naam geven 03 . Het kan zijn dat u momenteel alleen een verliesfunctie heeft. Zo ja, maak dan een andere tensor (variabele in het model) die daadwerkelijk de gewenste uitvoer berekent.

Als uw verliesfunctie bijvoorbeeld is:

tf.nn.sigmoid_cross_entropy_with_logits(last_layer_activation, labels)

En je verwacht dat je output in het bereik [0,1] per klasse ligt, maak een andere variabele:

output = tf.sigmoid(last_layer_activation)

Als je nu 10 . belt vraag gewoon de 20 aan tensor. Vraag niet om de optimalisatie-OP die u normaal gesproken zou trainen. Wanneer u deze variabele opvraagt, zal tensorflow het minimale werk doen dat nodig is om de waarde te produceren (het zal bijvoorbeeld geen moeite doen met backprop, loss-functies en dat alles omdat een eenvoudige feed forward pass alles is wat nodig is om 37 .

Dus als u een service maakt om gevolgtrekkingen van het model te retourneren, moet u het model in het geheugen/gpu geladen houden en herhalen:

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

U hoeft het niet de labels te geven, omdat tensorflow niet de moeite neemt om ops te berekenen die niet nodig zijn om de uitvoer te produceren die u aanvraagt. U hoeft uw model niet te wijzigen of iets dergelijks.

Hoewel deze aanpak misschien niet zo voor de hand liggend is als 44 Ik zou zeggen dat het veel flexibeler is. Als je met complexere modellen gaat spelen, zul je waarschijnlijk van deze aanpak gaan houden. 50 is als 'binnen de kaders denken'.