Übersicht
LiteRT unterstützt die Konvertierung von TensorFlow-RNN-Modellen in die zusammengeführten LSTM-Operationen von LiteRT. Zusammengeführte Vorgänge sind darauf ausgelegt, die Leistung der zugrunde liegenden Kernel-Implementierungen zu maximieren und eine Schnittstelle auf höherer Ebene zum Definieren komplexer Transformationen wie der Quantisierung bereitzustellen.
Da es in TensorFlow viele Varianten von RNN-APIs gibt, haben wir zwei Ansätze verfolgt:
- Native Unterstützung für standardmäßige TensorFlow-RNN-APIs wie Keras LSTM. Dies ist die empfohlene Option.
- Schnittstelle in die Conversion-Infrastruktur nutzerdefinierter RNN-Implementierungen bereitstellen, die in LiteRT eingebunden und konvertiert werden können. Wir stellen einige sofort einsatzbereite Beispiele für eine solche Konvertierung mit den RNN-Schnittstellen LSTMCellSimple und LayerNormalizedLSTMCellSimple von Lingvo bereit.
Converter API
Das Feature ist Teil von TensorFlow 2.3. Es ist auch über den tf-nightly-Pip oder über den Head verfügbar.
Diese Konvertierungsfunktion ist verfügbar, wenn Sie ein SavedModel oder das Keras-Modell direkt in LiteRT konvertieren. Beispiele ansehen
Aus gespeichertem Modell
# build a saved model. Here concrete_function is the exported function
# corresponding to the TensorFlow model containing one or more
# Keras LSTM layers.
saved_model, saved_model_dir = build_saved_model_lstm(...)
saved_model.save(saved_model_dir, save_format="tf", signatures=concrete_func)
# Convert the model.
converter = TFLiteConverter.from_saved_model(saved_model_dir)
tflite_model = converter.convert()
Aus Keras-Modell
# build a Keras model
keras_model = build_keras_lstm(...)
# Convert the model.
converter = TFLiteConverter.from_keras_model(keras_model)
tflite_model = converter.convert()
Beispiel
Keras LSTM zu LiteRT Colab veranschaulicht die End-to-End-Verwendung mit dem LiteRT-Interpreter.
Unterstützte TensorFlow RNNs-APIs
Keras-LSTM-Konvertierung (empfohlen)
Wir unterstützen die sofort einsatzbereite Konvertierung von Keras-LSTM in LiteRT. Weitere Informationen zur Funktionsweise finden Sie in der Keras LSTM-Schnittstelle und in der Konvertierungslogik.
Wichtig ist auch, den LSTM-Vertrag von LiteRT in Bezug auf die Keras-Operationsdefinition hervorzuheben:
- Die Dimension 0 des Eingabe-Tensors ist die Batchgröße.
- Die Dimension 0 des Tensors recurrent_weight ist die Anzahl der Ausgaben.
- Die Tensoren weight und recurrent_kernel werden transponiert.
- Die transponierten Tensoren „weight“, „recurrent_kernel“ und bias werden entlang der Dimension 0 in vier gleich große Tensoren aufgeteilt. Sie entsprechen dem Eingangsgatter, dem Vergessensgatter, der Zelle und dem Ausgangsgatter.
Keras-LSTM-Varianten
Time-Hauptdimension
Nutzer können sich für „Zeit als Hauptdimension“ oder „Keine Zeit als Hauptdimension“ entscheiden. Keras LSTM fügt den Funktionsdefinitionsattributen ein „time-major“-Attribut hinzu. Für das unidirektionale Sequenz-LSTM können wir einfach das time major-Attribut von unidirecional_sequence_lstm zuordnen.
Bidirektionales LSTM
Bidirektionale LSTMs können mit zwei Keras-LSTM-Layern implementiert werden, einem für die Vorwärts- und einem für die Rückwärtsrichtung. Hier finden Sie Beispiele. Sobald wir das Attribut „go_backward“ sehen, erkennen wir es als Backward-LSTM und gruppieren Forward- und Backward-LSTM zusammen. Das ist die Zukunft der Arbeit. Derzeit werden dadurch zwei UnidirectionalSequenceLSTM-Vorgänge im LiteRT-Modell erstellt.
Beispiele für benutzerdefinierte LSTM-Konvertierungen
LiteRT bietet auch eine Möglichkeit, benutzerdefinierte LSTM-Implementierungen zu konvertieren. Hier verwenden wir das LSTM von Lingvo als Beispiel für die Implementierung. Weitere Informationen finden Sie in der lingvo.LSTMCellSimple-Schnittstelle und in der Konversionslogik. Ein weiteres Beispiel für eine der LSTM-Definitionen von Lingvo finden Sie in der lingvo.LayerNormalizedLSTMCellSimple-Schnittstelle und der zugehörigen Konvertierungslogik hier.
„Bring your own TensorFlow RNN“ zu LiteRT
Wenn die RNN-Schnittstelle eines Nutzers sich von den standardmäßig unterstützten Schnittstellen unterscheidet, gibt es mehrere Möglichkeiten:
Option 1:Schreiben Sie Adaptercode in TensorFlow Python, um die RNN-Schnittstelle an die Keras-RNN-Schnittstelle anzupassen. Das bedeutet, dass eine tf.function mit der tf_implements-Annotation für die Funktion der generierten RNN-Schnittstelle, die mit der von der Keras-LSTM-Schicht generierten Funktion identisch ist. Danach funktioniert dieselbe Conversion API, die für Keras LSTM verwendet wird.
Option 2:Wenn das oben Genannte nicht möglich ist (z. B. wenn im Keras-LSTM einige Funktionen fehlen, die derzeit vom zusammengeführten LSTM-Vorgang von LiteRT bereitgestellt werden, z. B. die Layer-Normalisierung), erweitern Sie den LiteRT-Converter, indem Sie benutzerdefinierten Konvertierungscode schreiben und ihn in den MLIR-Pass „prepare-composite-functions“ hier einfügen. Die Schnittstelle der Funktion sollte wie ein API-Vertrag behandelt werden und die Argumente enthalten, die für die Konvertierung in zusammengeführte LiteRT-LSTM-Operationen erforderlich sind, d.h. Eingabe, Bias, Gewichte, Projektion, Layer-Normalisierung usw. Es ist vorzuziehen, wenn die als Argumente an diese Funktion übergebenen Tensoren einen bekannten Rang haben (d.h. RankedTensorType in MLIR). So lässt sich viel einfacher Code für die Konvertierung schreiben, der diese Tensoren als RankedTensorType annehmen und in Tensoren mit Rang umwandeln kann, die den Operanden des zusammengeführten LiteRT-Operators entsprechen.
Ein vollständiges Beispiel für einen solchen Konvertierungsablauf ist die Konvertierung von LSTMCellSimple zu LiteRT in Lingvo.
Die LSTMCellSimple in Lingvo wird hier definiert. Modelle, die mit dieser LSTM-Zelle trainiert wurden, können so in LiteRT konvertiert werden:
- Umschließen Sie alle Verwendungen von LSTMCellSimple mit einer tf.function mit einer tf_implements-Annotation, die entsprechend gekennzeichnet ist (z.B. wäre lingvo.LSTMCellSimple hier ein guter Annotationsname). Achten Sie darauf, dass die generierte tf.function der Schnittstelle der Funktion entspricht, die im Konvertierungscode erwartet wird. Dies ist ein Vertrag zwischen dem Modellautor, der die Anmerkung und den Konversionscode hinzufügt.
Erweitern Sie den Pass „prepare-composite-functions“, um einen benutzerdefinierten zusammengesetzten Vorgang in die Konvertierung des zusammengeführten LSTM-Vorgangs von LiteRT einzufügen. LSTMCellSimple-Konvertierungscode
Der Vertrag zur Umstellung:
Die Tensoren Gewicht und Projektion werden transponiert.
Die {input, recurrent}-zu-{cell, input gate, forget gate, output gate}-Gewichte werden durch Slicing des transponierten Gewichtstensors extrahiert.
Die {bias} für {cell, input gate, forget gate, output gate} werden durch Aufteilen des Bias-Tensors extrahiert.
Die Projektion wird durch Slicing des transponierten Projektionstensors extrahiert.
Eine ähnliche Conversion wird für LayerNormalizedLSTMCellSimple geschrieben.
Der Rest der LiteRT-Konvertierungsinfrastruktur, einschließlich aller definierten MLIR-Passes sowie des endgültigen Exports in den LiteRT-Flatbuffer, kann wiederverwendet werden.
Bekannte Probleme/Einschränkungen
- Derzeit wird nur die Konvertierung von zustandslosen Keras-LSTM unterstützt (Standardverhalten in Keras). Die zustandsbehaftete Keras-LSTM-Konvertierung ist zukünftige Arbeit.
- Es ist weiterhin möglich, eine zustandsbehaftete Keras-LSTM-Schicht mit der zugrunde liegenden zustandslosen Keras-LSTM-Schicht zu modellieren und den Zustand explizit im Nutzerprogramm zu verwalten. Ein solches TensorFlow-Programm kann weiterhin mit der hier beschriebenen Funktion in LiteRT konvertiert werden.
- Bidirektionales LSTM wird derzeit als zwei UnidirectionalSequenceLSTM-Vorgänge in LiteRT modelliert. Sie wird durch einen einzelnen BidirectionalSequenceLSTM-Vorgang ersetzt.