web-dev-qa-db-fra.com

A quoi sert le paramètre "max_q_size" dans "model.fit_generator"?

J'ai construit un générateur simple qui produit une Tuple(inputs, targets) avec seulement des éléments uniques dans les listes inputs et targets. Fondamentalement, il explore l'ensemble de données, un exemple d'élément à la fois.

Je passe ce générateur dans:

  model.fit_generator(my_generator(),
                      nb_Epoch=10,
                      samples_per_Epoch=1,
                      max_q_size=1  # defaults to 10
                      )

Je comprends cela:

  • nb_Epoch est le nombre d'exécutions du lot de formation
  • samples_per_Epoch est le nombre d'échantillons formés par époque

Mais comment ça max_q_size pour et pourquoi serait-il par défaut à 10? Je pensais que le but d'utiliser un générateur était de regrouper des ensembles de données en morceaux raisonnables, alors pourquoi la file d'attente supplémentaire?

23
Ray

Cela définit simplement la taille maximale de la file d'attente de formation interne qui est utilisée pour "mettre en cache" vos échantillons du générateur. Il est utilisé lors de la génération des files d'attente

def generator_queue(generator, max_q_size=10,
                    wait_time=0.05, nb_worker=1):
    '''Builds a threading queue out of a data generator.
    Used in `fit_generator`, `evaluate_generator`, `predict_generator`.
    '''
    q = queue.Queue()
    _stop = threading.Event()

    def data_generator_task():
        while not _stop.is_set():
            try:
                if q.qsize() < max_q_size:
                    try:
                        generator_output = next(generator)
                    except ValueError:
                        continue
                    q.put(generator_output)
                else:
                    time.sleep(wait_time)
            except Exception:
                _stop.set()
                raise

    generator_threads = [threading.Thread(target=data_generator_task)
                         for _ in range(nb_worker)]

    for thread in generator_threads:
        thread.daemon = True
        thread.start()

    return q, _stop

En d'autres termes, vous avez un thread remplissant la file d'attente jusqu'à la capacité maximale donnée directement à partir de votre générateur, tandis que (par exemple) la routine de formation consomme ses éléments (et attend parfois la fin)

 while samples_seen < samples_per_Epoch:
     generator_output = None
     while not _stop.is_set():
         if not data_gen_queue.empty():
             generator_output = data_gen_queue.get()
             break
         else:
             time.sleep(wait_time)

et pourquoi défaut de 10? Aucune raison particulière, comme la plupart des valeurs par défaut - cela a simplement du sens, mais vous pouvez également utiliser des valeurs différentes.

Une construction comme celle-ci suggère que les auteurs ont pensé à des générateurs de données coûteux, ce qui pourrait prendre du temps à se développer. Par exemple, envisagez de télécharger des données sur un réseau lors d'un appel de générateur - il est alors judicieux de mettre en cache certains lots suivants, et de télécharger les suivants en parallèle pour des raisons d'efficacité et pour résister aux erreurs de réseau, etc.

31
lejlot