2017-03-22 17 views
0

Um ein Modell zu trainieren, habe ich mein Modell in einer Klasse gekapselt. Ich verwende eine tf.RandomShuffleQueue, um eine Liste von Dateinamen in die Warteschlange zu stellen. Wenn ich jedoch die Elemente aus der Warteschlange wechsle, werden sie aus der Warteschlange entfernt, aber die Größe der Warteschlange wird nicht reduziert.Die Entfernung aus RandomShuffleQueue reduziert nicht die Größe

Im Folgenden werden spezifischere Fragen durch den Code-Schnipsel gefolgt:

  1. Wenn ich nur 5 Bilder zum Beispiel, aber Schritte reichen bis zu 100, würde dieses Ergebnis in den addfilenames wiederholt automatisch aufgerufen? Es gibt mir keinen Fehler bei der Ausleihe, also denke ich, dass es automatisch aufgerufen wird.
  2. Warum ändert sich die Größe der tf.RandomShuffleQueue nicht? Es bleibt konstant.

    import os 
    import time 
    import functools 
    import tensorflow as tf 
    from Read_labelclsloc import readlabel 
    
    
    def ReadTrain(traindir): 
        # Returns a list of training images, their labels and a dictionay. 
        # The dictionary maps label names to integer numbers.                  
        return trainimgs, trainlbls, classdict 
    
    
    def ReadVal(valdir, classdict): 
        # Reads the validation image labels. 
        # Returns a dictionary with filenames as keys and 
        # corresponding labels as values. 
        return valdict 
    
    def lazy_property(function): 
        # Just a decorator to make sure that on repeated calls to 
        # member functions, ops don't get created repeatedly. 
        # Acknowledgements : https://danijar.com/structuring-your-tensorflow-models/ 
        attribute= '_cache_' + function.__name__ 
        @property 
        @functools.wraps(function) 
        def decorator(self): 
         if not hasattr(self, attribute): 
          setattr(self, attribute, function(self)) 
         return getattr(self, attribute) 
    
        return decorator  
    
    class ModelInitial: 
    
        def __init__(self, traindir, valdir): 
         self.graph 
         self.traindir = traindir 
         self.valdir = valdir 
         self.traininginfo() 
         self.epoch = 0 
    
    
    
        def traininginfo(self): 
         self.trainimgs, self.trainlbls, self.classdict = ReadTrain(self.traindir) 
         self.valdict = ReadVal(self.valdir, self.classdict) 
         with self.graph.as_default(): 
          self.trainimgs_tensor = tf.constant(self.trainimgs) 
          self.trainlbls_tensor = tf.constant(self.trainlbls, dtype=tf.uint16) 
          self.trainimgs_dict = {} 
          self.trainimgs_dict["ImageFile"] = self.trainimgs_tensor 
         return None 
    
        @lazy_property 
        def graph(self): 
         g = tf.Graph() 
         with g.as_default(): 
          # Layer definitions go here 
         return g 
    
    
        @lazy_property 
        def addfilenames (self): 
        # This is the function where filenames are pushed to a RandomShuffleQueue 
         filename_queue = tf.RandomShuffleQueue(capacity=len(self.trainimgs), min_after_dequeue=0,\ 
                   dtypes=[tf.string], names=["ImageFile"],\ 
                   seed=0, name="filename_queue") 
    
         sz_op = filename_queue.size() 
    
         dq_op = filename_queue.dequeue() 
    
         enq_op = filename_queue.enqueue_many(self.trainimgs_dict) 
         return filename_queue, enq_op, sz_op, dq_op 
    
        def Train(self): 
        # The function for training. 
        # I have not written the training part yet. 
        # Still struggling with preprocessing 
         with self.graph.as_default(): 
          filename_q, filename_enqueue_op, sz_op, dq_op= self.addfilenames 
    
          qr = tf.train.QueueRunner(filename_q, [filename_enqueue_op]) 
          filename_dequeue_op = filename_q.dequeue() 
          init_op = tf.global_variables_initializer() 
    
         sess = tf.Session(graph=self.graph) 
         sess.run(init_op) 
         coord = tf.train.Coordinator() 
         enq_threads = qr.create_threads(sess, coord=coord, start=True) 
         counter = 0 
         for step in range(100): 
          print(sess.run(dq_op["ImageFile"])) 
          print("Epoch = %d "%(self.epoch)) 
          print("size = %d"%(sess.run(sz_op))) 
          counter+=1 
    
         names = [n.name for n in self.graph.as_graph_def().node] 
         coord.request_stop() 
         coord.join(enq_threads) 
         print("Counter = %d"%(counter)) 
         return None 
    
    
    
    
    
    if __name__ == "__main__": 
        modeltrain = ModelInitial(<Path to training images>,\ 
                <Path to validation images>) 
        a = modeltrain.graph 
        print(a) 
        modeltrain.Train() 
        print("Success") 
    

Antwort

1

Das Geheimnis wird durch die tf.train.QueueRunner verursacht, die Sie für die Warteschlange erstellt, die es im Hintergrund gefüllt werden verursacht.

  1. die folgenden Zeilen verursachen ein Hintergrund „queue runner“ Thread erstellt werden:

    qr = tf.train.QueueRunner(filename_q, [filename_enqueue_op]) 
    # ... 
    enq_threads = qr.create_threads(sess, coord=coord, start=True) 
    

    Dieser Thread ruft filename_enqueue_op in einer Schleife, die die Warteschlange gefüllt werden verursacht, wie Sie Elemente entfernen es.

  2. Der Hintergrund-Thread von Schritt 1 wird fast immer einen ausstehenden Enqueue-Vorgang (filename_enqueue_op) in der Warteschlange haben. Das bedeutet, dass nach dem Herausnehmen der Warteschlange aus der Warteschlange die ausstehende Enqueue ausgeführt wird. Füllen Sie die Warteschlange erneut aus. (Technisch gibt es hier eine Race Condition und man könnte eine Größe von capacity - 1 sehen, aber das ist ziemlich unwahrscheinlich).

+0

Danke. Ich habe das auch erwartet. Ich finde 'tf.train.QueueRunner' ziemlich restriktiv. Ich bin gezwungen, ein einziges Enqueue_op zu verwenden. Ich kann dort keine allgemeine Funktion einfügen. Ich will in der Lage sein, die bestimmte Epoche genau zu verfolgen, indem ich die Epoche inkrementiere, sobald eine volle "enqueue_many" vorüber ist. Wie kann ich es erreichen? Leider sehe ich noch keine Funktion in 'QueueRunner'. Wenn dies der Fall ist, wird es nicht ordnungsgemäß dokumentiert. Die Handhabung und Vorverarbeitung von Datasets bereitet TensorFlow derzeit größte Sorgen. Irgendwelche Vorschläge ? – Ujjwal

+1

@Ujjwal, queuernunner Logik ist ziemlich klein, ich finde es manchmal nützlich, nicht Warteschlangenläufer zu verwenden und Enqueue-Operationen selbst aus separaten Python-Thread ausführen. Das gibt mehr Kontrolle, siehe https://github.com/yaroslavvb/stuff/tree/master/queues_talk für einige Erklärungen –

+0

Ya. Ich fand schließlich die Lösung mit einer Klassenstruktur und Threading-Modul. Es ist klarer und gibt mehr Kontrolle als QueueRunner. Tatsächlich erweisen sich QueueRunners für eine komplexe Vorverarbeitung als ziemlich nutzlos. Auf Github sah ich, dass eine neue Eingangspipeline für Version 2.0 vorgeschlagen wird. Ernsthaft, Tensorflow benötigt eine Überholung mit Eingangspipeline. – Ujjwal

Verwandte Themen