So stellen Sie TensorFlow-Modelle mithilfe von TF Serving für die Produktion bereit

Einführung

Die Umsetzung von ML-Modellen (Machine Learning) in die Produktion ist zu einem beliebten und wiederkehrenden Thema geworden. Viele Unternehmen und Frameworks bieten unterschiedliche Lösungen an, um dieses Problem anzugehen.

Um dieses Problem zu lösen, hat Google TensorFlow (TF) Serving veröffentlicht, um das Problem der Bereitstellung von ML-Modellen für die Produktion zu lösen.

Dieses Stück bietet ein praktisches Tutorial zum Servieren eines vorab geschulten Convolutional Semantic Segmentation Network. Am Ende dieses Artikels können Sie TF Serving verwenden, um ein in TF geschultes Deep CNN bereitzustellen und Anforderungen an dieses zu stellen. Außerdem werde ich einen Überblick über die Hauptblöcke von TF Serving geben und die APIs und die Funktionsweise erläutern.

Eine Sache, die Sie sofort bemerken werden, ist, dass sehr wenig Code erforderlich ist, um ein TF-Modell tatsächlich zu bedienen. Wenn Sie dem Lernprogramm folgen und das Beispiel auf Ihrem Computer ausführen möchten, befolgen Sie es wie es ist. Wenn Sie jedoch nur etwas über TensorFlow Serving erfahren möchten, können Sie sich auf die ersten beiden Abschnitte konzentrieren.

Dieses Stück betont einige der Arbeiten, die wir hier bei der Daitan Group leisten.

TensorFlow Serving Libraries - Ein Überblick

Nehmen wir uns etwas Zeit, um zu verstehen, wie TF Serving den gesamten Lebenszyklus von ML-Modellen abwickelt. Hier werden wir (auf hohem Niveau) jeden der Hauptbausteine ​​von TF Serving durchgehen. Ziel dieses Abschnitts ist es, eine sanfte Einführung in die TF-Serving-APIs zu geben. Eine ausführliche Übersicht finden Sie auf der Dokumentationsseite zu TF Serving.

TensorFlow Serving besteht aus einigen Abstraktionen. Diese Abstraktionen implementieren APIs für verschiedene Aufgaben. Die wichtigsten sind Servable, Loader, Source und Manager. Lassen Sie uns durchgehen, wie sie interagieren.

Kurz gesagt, der Serving-Lebenszyklus beginnt, wenn TF Serving ein Modell auf der Festplatte identifiziert. Dafür sorgt die Source-Komponente. Es ist dafür verantwortlich, neue Modelle zu identifizieren, die geladen werden sollen. In der Praxis wird das Dateisystem im Auge behalten, um festzustellen, wann eine neue Modellversion auf der Festplatte eintrifft. Wenn eine neue Version angezeigt wird, wird ein Loader für diese bestimmte Version des Modells erstellt.

Zusammenfassend weiß der Loader fast alles über das Modell. Es enthält Informationen zum Laden und zum Schätzen der erforderlichen Ressourcen des Modells, z. B. des angeforderten RAM und des GPU-Speichers. Der Loader verfügt über einen Zeiger auf das Modell auf der Festplatte sowie alle zum Laden erforderlichen Metadaten. Aber hier gibt es einen Haken: Der Loader darf das Modell noch nicht laden.

Nach dem Erstellen des Loaders sendet die Quelle ihn als gewünschte Version an den Manager.

Nach Erhalt der gewünschten Version des Modells fährt der Manager mit dem Bereitstellungsprozess fort. Hier gibt es zwei Möglichkeiten. Zum einen wird die erste Modellversion für die Bereitstellung bereitgestellt. In dieser Situation stellt der Manager sicher, dass die erforderlichen Ressourcen verfügbar sind. Sobald dies der Fall ist, erteilt der Manager dem Loader die Berechtigung zum Laden des Modells.

Das zweite ist, dass wir eine neue Version eines vorhandenen Modells vorantreiben. In diesem Fall muss der Manager das Versionsrichtlinien-Plugin konsultieren, bevor er fortfahren kann. Die Versionsrichtlinie bestimmt, wie das Laden einer neuen Modellversion erfolgt.

Insbesondere beim Laden einer neuen Version eines Modells können wir zwischen der Beibehaltung von (1) Verfügbarkeit oder (2) Ressourcen wählen. Im ersten Fall möchten wir sicherstellen, dass unser System immer für eingehende Kundenanfragen verfügbar ist. Wir wissen, dass der Manager dem Loader ermöglicht, das neue Diagramm mit den neuen Gewichten zu instanziieren.

Zu diesem Zeitpunkt sind zwei Modellversionen gleichzeitig geladen. Der Manager entlädt die ältere Version jedoch erst nach Abschluss des Ladevorgangs und es ist sicher, zwischen den Modellen zu wechseln.

Wenn wir andererseits Ressourcen sparen möchten, indem wir nicht über den zusätzlichen Puffer verfügen (für die neue Version), können wir uns dafür entscheiden, Ressourcen zu schonen. Für sehr schwere Modelle kann es nützlich sein, eine kleine Lücke in der Verfügbarkeit zu haben, um Speicherplatz zu sparen.

Wenn ein Client am Ende ein Handle für das Modell anfordert, gibt der Manager ein Handle an das Servable zurück.

Mit dieser Übersicht sind wir bereit, in eine reale Anwendung einzutauchen. In den nächsten Abschnitten beschreiben wir, wie ein Convolutional Neural Network (CNN) mit TF Serving bedient wird.

Exportieren eines Modells zum Servieren

Der erste Schritt, um ein in TensorFlow erstelltes ML-Modell bereitzustellen, besteht darin, sicherzustellen, dass es das richtige Format hat. Zu diesem Zweck stellt TensorFlow die SavedModel-Klasse bereit.

SavedModel ist das universelle Serialisierungsformat für TensorFlow-Modelle. Wenn Sie mit TF vertraut sind, haben Sie wahrscheinlich den TensorFlow Saver verwendet, um die Variablen Ihres Modells beizubehalten.

Der TensorFlow Saver bietet Funktionen zum Speichern / Wiederherstellen der Prüfpunktdateien des Modells auf / von der Festplatte. Tatsächlich verpackt SavedModel den TensorFlow Saver und ist als Standardmethode für den Export von TF-Modellen zum Servieren gedacht.

Das SavedModel-Objekt hat einige nette Funktionen.

Erstens können Sie mehr als ein Metadiagramm in einem einzelnen SavedModel-Objekt speichern. Mit anderen Worten, es ermöglicht uns, verschiedene Diagramme für verschiedene Aufgaben zu haben.

Angenommen, Sie haben gerade Ihr Modell trainiert. In den meisten Situationen benötigt Ihr Diagramm keine trainingsspezifischen Operationen, um Inferenzen durchzuführen. Diese Operationen können die Variablen des Optimierers, Tensoren für die Planung der Lernrate, zusätzliche Vorverarbeitungsoperationen usw. enthalten.

Darüber hinaus möchten Sie möglicherweise eine quantisierte Version eines Diagramms für die mobile Bereitstellung bereitstellen.

In diesem Zusammenhang können Sie mit SavedModel Diagramme mit unterschiedlichen Konfigurationen speichern. In unserem Beispiel hätten wir drei verschiedene Diagramme mit entsprechenden Tags wie "Training", "Inferenz" und "Mobil". Außerdem würden diese drei Diagramme alle denselben Satz von Variablen gemeinsam nutzen - was die Speichereffizienz betont.

Vor nicht allzu langer Zeit, als wir TF-Modelle auf Mobilgeräten bereitstellen wollten, mussten wir die Namen der Eingangs- und Ausgangstensoren kennen, um Daten zum / vom Modell zu speisen und abzurufen. Dies erfordert, dass Programmierer gezwungen sind, unter allen Tensoren des Graphen nach dem Tensor zu suchen, den sie benötigen. Wenn die Tensoren nicht richtig benannt würden, könnte die Aufgabe sehr mühsam sein.

Zur Vereinfachung bietet SavedModel Unterstützung für SignatureDefs. Zusammenfassend definieren SignatureDefs die Signatur einer von TensorFlow unterstützten Berechnung. Es bestimmt die richtigen Eingangs- und Ausgangstensoren für einen Rechengraphen. Einfach ausgedrückt, mit diesen Signaturen können Sie die genauen Knoten angeben, die für die Eingabe und Ausgabe verwendet werden sollen.

Für die Verwendung der integrierten Serving-APIs benötigt TF Serving Modelle, die ein oder mehrere SignatureDefs enthalten.

Um solche Signaturen zu erstellen, müssen Definitionen für Eingaben, Ausgaben und den gewünschten Methodennamen angegeben werden. Ein- und Ausgänge stellen eine Zuordnung von Zeichenfolge zu TensorInfo-Objekten dar (mehr dazu letzteres). Hier definieren wir die Standardtensoren für das Zuführen und Empfangen von Daten zu und von einem Diagramm. Der Parameter method_name zielt auf eine der TF-High-Level-Serving-APIs ab.

Derzeit gibt es drei Serving-APIs: Klassifizierung, Vorhersage und Regression. Jede Signaturdefinition entspricht einer bestimmten RPC-API. Das Classification SegnatureDef wird für die Classify RPC-API verwendet. Das Predict SegnatureDef wird für die Predict RPC-API und weiter verwendet.

Für die Klassifizierungssignatur muss ein Eingangstensor (um Daten zu empfangen) und mindestens einer von zwei möglichen Ausgangstensoren vorhanden sein: Klassen und / oder Scores. Das Regression SignatureDef benötigt genau einen Tensor für die Eingabe und einen anderen für die Ausgabe. Schließlich ermöglicht die Predict-Signatur eine dynamische Anzahl von Eingabe- und Ausgabe-Tensoren.

Darüber hinaus unterstützt SavedModel die Speicherung von Assets in Fällen, in denen die Initialisierung von Operationen von externen Dateien abhängt. Außerdem verfügt es über Mechanismen zum Löschen von Geräten vor dem Erstellen des SavedModel.

Nun wollen wir sehen, wie wir das in der Praxis machen können.

Umgebung einrichten

Bevor wir beginnen, klonen Sie diese TensorFlow DeepLab-v3- Implementierung von Github.

DeepLab ist Googles beste semantische Segmentierung ConvNet. Grundsätzlich nimmt das Netzwerk ein Bild als Eingabe und gibt ein maskenhaftes Bild aus, das bestimmte Objekte vom Hintergrund trennt.

Diese Version wurde auf dem Pascal VOC-Segmentierungsdatensatz trainiert. Somit können bis zu 20 Klassen segmentiert und erkannt werden. Wenn Sie mehr über Semantic Segmentation und DeepLab-v3 erfahren möchten, werfen Sie einen Blick auf Diving in Deep Convolutional Semantic Segmentation Networks und Deeplab_V3.

Alle Dateien, die sich auf das Serving beziehen, befinden sich in: ./deeplab_v3/serving/. Dort finden Sie zwei wichtige Dateien: deeplab_saved_model.py und deeplab_client.ipynb

Bevor Sie fortfahren, stellen Sie sicher, dass Sie das vorab trainierte Deeplab-v3-Modell herunterladen. Gehen Sie zum GitHub-Repository oben, klicken Sie auf den Link Checkpoints und laden Sie den Ordner mit dem Namen 16645 / herunter .

Am Ende sollte ein Ordner mit dem Namen tboard_logs / mit dem Ordner 16645 / darin abgelegt sein.

Jetzt müssen wir zwei virtuelle Python-Umgebungen erstellen. Eine für Python 3 und eine für Python 2. Stellen Sie für jede Umgebung sicher, dass Sie die erforderlichen Abhängigkeiten installieren. Sie finden sie in den Dateien serving_requirements.txt und client_requirements.txt.

Wir benötigen zwei Python-Envs, da unser Modell DeepLab-v3 unter Python 3 entwickelt wurde. Die Python-API für TensorFlow Serving wird jedoch nur für Python 2 veröffentlicht. Um das Modell zu exportieren und TF-Serving auszuführen, verwenden wir daher die Python 3-Env . Zum Ausführen des Client-Codes mit der TF Serving-Python-API verwenden wir das PIP-Paket (nur für Python 2 verfügbar).

Beachten Sie, dass Sie auf die Python 2-Umgebung verzichten können, indem Sie die Serving-APIs von bazel verwenden. Weitere Informationen finden Sie in der TF Serving Instalation.

Beginnen wir mit diesem Schritt mit dem, was wirklich wichtig ist.

Wie es geht

Zur Verwendung von SavedModel bietet TensorFlow eine benutzerfreundliche Dienstprogrammklasse auf hoher Ebene mit dem Namen SavedModelBuilder. Die SavedModelBuilder-Klasse bietet Funktionen zum Speichern mehrerer Metadiagramme, zugehöriger Variablen und Assets.

Lassen Sie uns ein laufendes Beispiel für den Export eines Deep Segmentation CNN-Modells zum Serving durchgehen.

Wie oben erwähnt, verwenden wir zum Exportieren des Modells die SavedModelBuilder-Klasse. Es wird eine SavedModel-Protokollpufferdatei zusammen mit den Variablen und Assets des Modells generiert (falls erforderlich).

Lassen Sie uns den Code zerlegen.

Der SavedModelBuilder empfängt (als Eingabe) das Verzeichnis, in dem die Modelldaten gespeichert werden sollen. Hier ist die Variable export_path die Verkettung von export_path_base und der model_version . Infolgedessen werden verschiedene Modellversionen in separaten Verzeichnissen im Ordner export_path_base gespeichert .

Angenommen, wir haben eine Basisversion unseres Modells in der Produktion, möchten jedoch eine neue Version davon bereitstellen. Wir haben die Genauigkeit unseres Modells verbessert und möchten unseren Kunden diese neue Version anbieten.

Um eine andere Version desselben Diagramms zu exportieren, können Sie FLAGS.model_version einfach auf einen höheren ganzzahligen Wert setzen. Dann wird ein anderer Ordner (mit der neuen Version unseres Modells) im Ordner export_path_base erstellt .

Jetzt müssen wir die Eingabe- und Ausgabe-Tensoren unseres Modells angeben. Dazu verwenden wir SignatureDefs. Signaturen definieren, welchen Modelltyp wir exportieren möchten. Es bietet eine Zuordnung von Zeichenfolgen (logische Tensornamen) zu TensorInfo-Objekten. Die Idee ist, dass Clients anstatt auf die tatsächlichen Tensornamen für die Eingabe / Ausgabe zu verweisen, auf die durch die Signaturen definierten logischen Namen verweisen können.

Für eine semantische Segmentierung CNN dient, werden wir eine erstellen Predict Unterschrift . Beachten Sie, dass die Funktion build_signature_def () die Zuordnung für Eingabe- und Ausgabe-Tensoren sowie die gewünschte API übernimmt.

Ein SignatureDef erfordert die Angabe von: Eingaben, Ausgaben und Methodennamen. Beachten Sie, dass wir drei Werte für Eingaben erwarten - ein Bild und zwei weitere Tensoren, die seine Abmessungen (Höhe und Breite) angeben. Für die Ausgaben haben wir nur ein Ergebnis definiert - die Segmentierungsausgabemaske.

Beachten Sie, dass die Zeichenfolgen 'image', 'height', 'width' und 'segmentation_map' keine Tensoren sind. Stattdessen handelt es sich um logische Namen, die sich auf die tatsächlichen Tensoren input_tensor , image_height_tensor und image_width_tensor beziehen . Somit können sie eine beliebige eindeutige Zeichenfolge sein, die Sie mögen.

Außerdem beziehen sich die Zuordnungen in den SignatureDefs auf TensorInfo-Protobuf-Objekte, nicht auf tatsächliche Tensoren. Um TensorInfo-Objekte zu erstellen, verwenden wir die Utility-Funktion: tf.saved_model.utils.build_tensor_info (Tensor) .

Das ist es. Jetzt rufen wir die Funktion add_meta_graph_and_variables () auf, um das SavedModel-Protokollpufferobjekt zu erstellen. Dann führen wir die save () -Methode aus und sie speichert einen Snapshot unseres Modells auf der Festplatte, die die Variablen und Assets des Modells enthält.

Wir können jetzt deeplab_saved_model.py ausführen, um unser Modell zu exportieren.

Wenn alles gut gegangen ist, sehen Sie den Ordner ./serving/versions/1 . Beachten Sie, dass die '1' die aktuelle Version des Modells darstellt. In jedem Unterverzeichnis der Version werden die folgenden Dateien angezeigt:

  • saved_model.pb oder saved_model.pbtxt. Dies ist die serialisierte SavedModel-Datei. Es enthält eine oder mehrere Diagrammdefinitionen des Modells sowie die Signaturdefinitionen.
  • Variablen. Dieser Ordner enthält die serialisierten Variablen der Diagramme.

Jetzt können wir unseren Modellserver starten. Führen Sie dazu Folgendes aus:

$ tensorflow_model_server --port=9000 --model_name=deeplab --model_base_path=

Der model_base_path bezieht sich darauf, wo das exportierte Modell gespeichert wurde. Außerdem geben wir den Versionsordner im Pfad nicht an. Die Versionskontrolle des Modells wird von TF Serving übernommen.

Client-Anfragen generieren

Der Client-Code ist sehr einfach. Schauen Sie es sich an in: deeplab_client.ipynb.

Zuerst lesen wir das Bild, das wir an den Server senden möchten, und konvertieren es in das richtige Format.

Als nächstes erstellen wir einen gRPC-Stub. Mit dem Stub können wir die Methoden des Remote-Servers aufrufen. Dazu instanziieren wir die Klasse beta_create_PredictionService_stub des Moduls Vorhersage_service_pb2 . Zu diesem Zeitpunkt enthält der Stub die erforderliche Logik zum Aufrufen von Remoteprozeduren (vom Server), als wären sie lokal.

Jetzt müssen wir das Anforderungsobjekt erstellen und festlegen. Da unser Server die TensorFlow Predict-API implementiert, müssen wir eine Predict-Anforderung analysieren. Um eine Vorhersageanforderung auszugeben , instanziieren wir zuerst die PredictRequest- Klasse aus dem Modul " Predict_pb2" . Wir müssen auch die Parameter model_spec.name und model_spec.signature_name angeben . Der Name param ist das Argument 'model_name', das wir beim Starten des Servers definiert haben. Und die signature_name bezieht sich auf den logischen Namen auf den zugewiesenen signature_def_map () Parameter der add_meta_graph () Routine.

Als nächstes müssen wir die Eingabedaten wie in der Signatur des Servers definiert angeben. Denken Sie daran, dass wir auf dem Server eine Vorhersage-API definiert haben, die ein Bild sowie zwei Skalare (Höhe und Breite des Bildes) erwartet. Um die Eingabedaten in das Anforderungsobjekt einzuspeisen , stellt TensorFlow das Dienstprogramm tf.make_tensor_proto () bereit . Diese Methode erstellt ein TensorProto-Objekt aus einem Numpy / Python-Objekt. Wir können es verwenden, um das Bild und seine Abmessungen dem Anforderungsobjekt zuzuführen.

Sieht so aus, als wären wir bereit, den Server anzurufen. Dazu rufen wir die Predict () -Methode (unter Verwendung des Stubs) auf und übergeben das Anforderungsobjekt als Argument.

Für Anforderungen, die eine einzelne Antwort zurückgeben, unterstützt gRPC sowohl synchrone als auch asynchrone Aufrufe. Wenn Sie also während der Verarbeitung der Anforderung arbeiten möchten, können Sie Predict.future () anstelle von Predict () aufrufen .

Jetzt können wir die Ergebnisse abrufen und genießen.

Hoffe dir hat dieser Artikel gefallen. Danke fürs Lesen!

Wenn Sie mehr wollen, schauen Sie sich Folgendes an:

So trainieren Sie Ihr eigenes FaceID ConvNet mithilfe der Ausführung von TensorFlow Eager

Gesichter sind überall - von Fotos und Videos auf Social-Media-Websites bis hin zu Sicherheitsanwendungen für Verbraucher wie… medium.freecodecamp.org Eintauchen in Deep Convolutional Semantic Segmentation Networks und Deeplab_V3

Deep Convolutional Neural Networks (DCNNs) haben in verschiedenen Computer Vision-Anwendungen bemerkenswerte Erfolge erzielt… medium.freecodecamp.org