sql >> Database >  >> NoSQL >> Redis

Keras voorspelt dat hij niet terugkeert in de selderijtaak

Ik kwam precies hetzelfde probleem tegen, en man, wat was het een konijnenhol. Ik wilde mijn oplossing hier posten omdat het iemand een dag werk zou kunnen besparen:

TensorFlow Thread-specifieke datastructuren

In TensorFlow zijn er twee belangrijke gegevensstructuren die achter de schermen werken wanneer u model.predict aanroept. (of keras.models.load_model , of keras.backend.clear_session , of vrijwel elke andere functie die interactie heeft met de TensorFlow-backend):

  • Een TensorFlow-grafiek, die de structuur van uw Keras-model weergeeft
  • Een TensorFlow-sessie, de verbinding tussen uw huidige grafiek en de TensorFlow-runtime

Iets dat niet expliciet duidelijk is in de documenten zonder enig graafwerk, is dat zowel de sessie als de grafiek eigenschappen zijn van de huidige thread . Bekijk hier en hier API-documenten.

TensorFlow-modellen in verschillende threads gebruiken

Het is normaal dat u uw model één keer wilt laden en vervolgens .predict() . wilt aanroepen er later meerdere keren op:

from keras.models import load_model

MY_MODEL = load_model('path/to/model/file')

def some_worker_function(inputs):
    return MY_MODEL.predict(inputs)

In een webserver- of worker-poolcontext zoals Celery betekent dit dat u het model laadt wanneer u de module importeert die het load_model bevat. regel, dan zal een andere thread some_worker_function uitvoeren , die voorspellen uitvoert op de globale variabele die het Keras-model bevat. Als u echter probeert een voorspelling uit te voeren op een model dat in een andere thread is geladen, levert dit "tensor is geen element van deze grafiek"-fouten op. Dankzij de verschillende SO-berichten die over dit onderwerp gingen, zoals ValueError:Tensor Tensor(...) is geen onderdeel van deze grafiek. Bij gebruik van het globale variabele Keras-model. Om dit te laten werken, moet je vasthouden aan de TensorFlow-grafiek die werd gebruikt - zoals we eerder zagen, is de grafiek een eigenschap van de huidige thread. De bijgewerkte code ziet er als volgt uit:

from keras.models import load_model
import tensorflow as tf

MY_MODEL = load_model('path/to/model/file')
MY_GRAPH = tf.get_default_graph()

def some_worker_function(inputs):
    with MY_GRAPH.as_default():
        return MY_MODEL.predict(inputs)

De enigszins verrassende wending hier is:de bovenstaande code is voldoende als je Thread gebruikt s, maar blijft voor onbepaalde tijd hangen als u Process gebruikt bijv. En standaard gebruikt Celery processen om al zijn werknemerspools te beheren. Dus op dit moment zijn de dingen stil werkt niet op selderij.

Waarom werkt dit alleen op Thread s?

In Python, Thread s delen dezelfde globale uitvoeringscontext als het bovenliggende proces. Uit de Python _thread-documenten:

Deze module biedt primitieven op laag niveau voor het werken met meerdere threads (ook wel lichtgewicht processen of taken genoemd) - meerdere besturingsthreads die hun wereldwijde gegevensruimte delen.

Omdat threads geen echte afzonderlijke processen zijn, gebruiken ze dezelfde python-interpreter en zijn ze dus onderworpen aan het beruchte Global Interpeter Lock (GIL). Misschien nog belangrijker voor dit onderzoek, ze delen globale gegevensruimte met de ouder.

In tegenstelling hiermee, Process es zijn werkelijk nieuwe processen voortgebracht door het programma. Dit betekent:

  • Nieuwe Python-interpreterinstantie (en geen GIL)
  • Algemene adresruimte is gedupliceerd

Let hier op het verschil. Terwijl Thread s hebben toegang tot een gedeelde enkele globale sessievariabele (intern opgeslagen in de tensorflow_backend module van Keras), Process es hebben duplicaten van de Session-variabele.

Mijn beste begrip van dit probleem is dat de Session-variabele verondersteld wordt een unieke verbinding tussen een client (proces) en de TensorFlow-runtime te vertegenwoordigen, maar door gedupliceerd te worden in het forking-proces, is deze verbindingsinformatie niet correct aangepast. Dit zorgt ervoor dat TensorFlow vastloopt wanneer u probeert een sessie te gebruiken die in een ander proces is gemaakt. Als iemand meer inzicht heeft in hoe dit werkt onder de motorkap in TensorFlow, hoor ik het graag!

De oplossing / tijdelijke oplossing

Ik ging met het aanpassen van Celery zodat het Thread . gebruikt s in plaats van Process es voor poolen. Er zijn enkele nadelen aan deze benadering (zie GIL-opmerking hierboven), maar dit stelt ons in staat om het model slechts één keer te laden. We zijn sowieso niet echt CPU-gebonden omdat de TensorFlow-runtime alle CPU-cores maximaliseert (het kan de GIL omzeilen omdat het niet in Python is geschreven). Je moet Celery voorzien van een aparte bibliotheek om op threads gebaseerde pooling te doen; de documenten suggereren twee opties:gevent of eventlet . Vervolgens geeft u de bibliotheek die u kiest door aan de werknemer via de --pool opdrachtregelargument.

Als alternatief lijkt het (zoals je al ontdekte @pX0r) dat andere Keras-backends zoals Theano dit probleem niet hebben. Dat is logisch, aangezien deze problemen nauw verband houden met de implementatiedetails van TensorFlow. Persoonlijk heb ik Theano nog niet geprobeerd, dus je kilometerstand kan variëren.

Ik weet dat deze vraag een tijdje geleden is gepost, maar het probleem bestaat nog steeds, dus hopelijk kan iemand hier iets aan doen!



  1. mongodb zoeken door meerdere array-items

  2. Model bijwerken met Mongoose, Express, NodeJS

  3. node.js &express - wereldwijde modules en best practices voor applicatiestructuur

  4. Spring Data MongoDB met Java 8 LocalDate MappingException