Einführung in den Inferenzkonverter von Cloud TPU v5e

Einleitung

Der Cloud TPU-Inferenzkonverter bereitet ein TensorFlow 2-Modell (TF2) für die TPU-Inferenz vor und optimiert es. Der Converter wird in einer lokalen oder TPU-VM-Shell ausgeführt. Die TPU-VM-Shell wird empfohlen, da dort der Befehl die für den Konverter benötigt werden. Dabei werden die folgenden Schritte ausgeführt:

  1. TPU-Konvertierung: Sie fügt TPUPartitionedCall und andere TPU-Vorgänge zum damit es auf der TPU bereitgestellt werden kann. Standardmäßig wird ein Modell, das für Die Inferenz hat keine solchen Vorgänge und kann nicht auf der TPU bereitgestellt werden, selbst wenn sie auf der TPU trainiert wurde.
  2. Stapelverarbeitung: Dem Modell werden Stapelvorgänge hinzugefügt, um Stapelverarbeitungen innerhalb des Graphen zu ermöglichen. für einen besseren Durchsatz.
  3. BFloat16 Conversion: Konvertiert das Datenformat des Modells von float32 bis bfloat16, um besser zu werden Rechenleistung und geringere High Bandwidth Memory (HBM) Nutzung auf der TPU.
  4. IO-Formoptimierung: optimiert die Tensorformen für Daten zwischen CPU und TPU übertragen werden, um die Bandbreitennutzung zu verbessern.

Beim Exportieren eines Modells erstellen Nutzer Funktionsaliasse für alle Funktionen, die sie auf der TPU ausgeführt werden soll. Sie übergeben diese Funktionen an den Converter und den Der Converter platziert sie auf der TPU und optimiert sie.

Der Cloud TPU-Inferenzkonverter ist als Docker-Image verfügbar, das in jeder Umgebung ausgeführt werden kann, in der Docker installiert ist.

Geschätzte Zeit zum Ausführen der oben genannten Schritte: ca. 20 bis 30 Minuten

Vorbereitung

  1. Das Modell muss ein TF2-Modell sein und in den SavedModel Format.
  2. Das Modell muss einen Funktionsalias für die TPU-Funktion haben. Weitere Informationen finden Sie in der Codebeispiel wie das geht. In den folgenden Beispielen wird tpu_func als Alias der TPU-Funktion verwendet.
  3. Achten Sie darauf, dass die CPU Ihres Computers Advanced Vector eXtensions (AVX) unterstützt wie die TensorFlow-Bibliothek (die Abhängigkeit der Cloud TPU) Inference Converter) wurde für die Verwendung von AVX-Anweisungen kompiliert. Die meisten CPUs AVX-Support.
    1. Mit lscpu | grep avx können Sie prüfen, ob der AVX-Instruction-Set unterstützt wird.

Hinweise

Führen Sie vor der Einrichtung die folgenden Schritte aus:

  • Neues Projekt erstellen: Wählen Sie in der Google Cloud Console auf der Seite der Projektauswahl ein Cloud-Projekt aus oder erstellen Sie eines.

  • Richten Sie eine TPU-VM ein: Erstellen Sie mit der Google Cloud Console oder gcloud eine neue TPU-VM oder verwenden Sie eine vorhandene TPU-VM, um Inferenz mit der konvertierten auf der TPU-VM.

    • Achten Sie darauf, dass das TPU-VM-Image TensorFlow-basiert ist. Beispiel: --version=tpu-vm-tf-2.11.0.
    • Das konvertierte Modell wird auf dieser TPU-VM geladen und bereitgestellt.
  • Achten Sie darauf, dass Sie die Befehlszeilentools haben, die Sie zur Verwendung von Cloud TPU benötigen Inferenzkonverter. Sie können das Google Cloud SDK und Docker lokal installieren oder eine TPU-VM verwenden, auf der diese Software standardmäßig installiert ist. Mit diesen Tools können Sie mit dem Bild des Converters interagieren.

    Stellen Sie mit dem folgenden Befehl eine SSH-Verbindung zur Instanz her:

    gcloud compute tpus tpu-vm ssh ${tpu-name} --zone ${zone} --project ${project-id}

Umgebung einrichten

Richten Sie Ihre Umgebung über Ihre TPU-VM-Shell oder Ihre lokale Shell ein.

TPU VM-Shell

  • Führen Sie in der TPU-VM-Shell die folgenden Befehle aus, um die Docker-Nutzung für nicht-root-Nutzer zuzulassen:

    sudo usermod -a -G docker ${USER}
    newgrp docker
  • Initialisieren Sie die Docker Credential Helpers:

    gcloud auth configure-docker \
      us-docker.pkg.dev

Lokale Shell

Richten Sie die Umgebung in Ihrer lokalen Shell mit den folgenden Schritten ein:

  • Installieren Sie das Cloud SDK, Dazu gehört das gcloud-Befehlszeilentool.

  • Installieren Sie Docker:

  • Lassen Sie die Nicht-Root-Nutzung von Docker zu:

    sudo usermod -a -G docker ${USER}
    newgrp docker
  • Melden Sie sich in Ihrer Umgebung an:

    gcloud auth login
  • Initialisieren Sie Ihre Docker Credential Helper:

    gcloud auth configure-docker \
        us-docker.pkg.dev
  • Rufen Sie das Docker-Image des Inference Converters ab:

      CONVERTER_IMAGE=us-docker.pkg.dev/cloud-tpu-images/inference/tpu-inference-converter-cli:2.13.0
      docker pull ${CONVERTER_IMAGE}
      

Bild mit Konverter

Das Bild ist für einmalige Modell-Conversions vorgesehen. Legen Sie die Modellpfade fest und passen Sie die Konvertierungsoptionen an Ihre Anforderungen an. Die Verwendungsbeispiele enthält einige häufige Anwendungsfälle.

docker run \
--mount type=bind,source=${MODEL_PATH},target=/tmp/input,readonly \
--mount type=bind,source=${CONVERTED_MODEL_PATH},target=/tmp/output \
${CONVERTER_IMAGE} \
--input_model_dir=/tmp/input \
--output_model_dir=/tmp/output \
--converter_options_string='
    tpu_functions {
      function_alias: "tpu_func"
    }
    batch_options {
      num_batch_threads: 2
      max_batch_size: 8
      batch_timeout_micros: 5000
      allowed_batch_sizes: 2
      allowed_batch_sizes: 4
      allowed_batch_sizes: 8
      max_enqueued_batches: 10
    }
'

Inferenzen mit dem konvertierten Modell in der TPU-VM

# Initialize the TPU
resolver = tf.distribute.cluster_resolver.TPUClusterResolver("local")
tf.config.experimental_connect_to_cluster(resolver)
tf.tpu.experimental.initialize_tpu_system(resolver)

# Load the model
model = tf.saved_model.load(${CONVERTED_MODEL_PATH})

# Find the signature function for serving
serving_signature = 'serving_default' # Change the serving signature if needed
serving_fn = model.signatures[serving_signature]
# Run the inference using requests.
results = serving_fn(**inputs)
logging.info("Serving results: %s", str(results))

Anwendungsbeispiele

Funktionalias für die TPU-Funktion hinzufügen

  1. Suchen Sie in Ihrem Modell nach einer Funktion oder erstellen Sie eine, die alles umschließt, was auf der TPU ausgeführt werden soll. Wenn @tf.function nicht vorhanden ist, fügen Sie sie hinzu.
  2. Geben Sie beim Speichern des Modells SaveOptions wie unten an, um model.tpu_func und ein Alias func_on_tpu.
  3. Sie können diesen Funktionsalias an den Converter übergeben.
class ToyModel(tf.keras.Model):
  @tf.function(
      input_signature=[tf.TensorSpec(shape=[None, 10], dtype=tf.float32)])
  def tpu_func(self, x):
    return x * 1.0

model = ToyModel()
save_options = tf.saved_model.SaveOptions(function_aliases={
    'func_on_tpu': model.tpu_func,
})
tf.saved_model.save(model, model_dir, options=save_options)

Modell mit mehreren TPU-Funktionen konvertieren

Sie können mehrere Funktionen auf die TPU legen. Erstellen Sie einfach mehrere Funktionsaliasse und übergeben Sie sie in converter_options_string an den Konverter.

tpu_functions {
  function_alias: "tpu_func_1"
}
tpu_functions {
  function_alias: "tpu_func_2"
}

Quantisierung

Bei der Quantisierung wird die Genauigkeit der Zahlen reduziert, die zur Darstellung der Parameter eines Modells verwendet werden. Dies führt zu einem kleineren Modell und eine schnellere Berechnung. Ein quantisiertes Modell bietet Vorteile sowie eine geringere Arbeitsspeichernutzung und eine geringere Speichergröße. auf Kosten kleinerer Genauigkeitseinbußen.

Die neue TensorFlow-Funktion zur Quantisierung nach dem Training TPU wurde auf Basis einer ähnlichen vorhandenen Funktion in TensorFlow Lite entwickelt. das für das Targeting auf Mobilgeräte und Edge-Geräte verwendet wird. Weitere Informationen zur Quantisierung im Allgemeinen finden Sie im Dokument zu TensorFlow Lite.

Quantisierungskonzepte

In diesem Abschnitt werden Konzepte speziell im Zusammenhang mit der Quantisierung mit dem Inference Converter definiert.

Konzepte im Zusammenhang mit anderen TPU-Konfigurationen (z. B. Slices, Hosts, Chips und TensorCores) werden in der Seite TPU-Systemarchitektur.

  • Quantisierung nach dem Training (PTQ): PTQ ist ein Verfahren, das die Größe und Rechenkomplexität eines neuronalen Netzwerkmodells die die Genauigkeit erheblich beeinträchtigen. PTQ konvertiert die Gleitkommagewichtungen und Aktivierungen eines trainierten Modells, Ganzzahlen mit niedrigerer Genauigkeit, z. B. 8-Bit- oder 16-Bit-Ganzzahlen. Dies kann dazu führen, die Modellgröße und die Inferenzlatenz deutlich reduziert, obwohl nur mit einem geringen Genauigkeitsverlust.

  • Kalibrierung: Bei der Kalibrierung für die Quantisierung werden Statistiken zum Wertebereich erfasst, den die Gewichte und Aktivierungen eines neuronalen Netzwerkmodells annehmen. Anhand dieser Informationen werden die Quantisierungsparameter für das Modell bestimmt. Das sind die Werte, mit denen die Gleitkommagewichte und -Aktivierungen in Ganzzahlen umgewandelt werden.

  • Repräsentatives Dataset: Ein repräsentatives Dataset für die Quantisierung ist ein kleines Dataset, das die tatsächlichen Eingabedaten für das Modell darstellt. Sie wird während des Kalibrierungsschritts der Quantisierung verwendet, um Statistiken zum Wertebereich zu erfassen, den die Gewichte und Aktivierungen des Modells annehmen werden. Das repräsentative Dataset sollte die folgenden Properties:

    • Sie sollte die tatsächlichen Eingaben während Inferenz. Das bedeutet, dass der Wertebereich den Bereich abdecken sollte, den das Modell in der Praxis wahrscheinlich sehen wird.
    • Sie sollte alle Verzweigungen von Bedingungen durchlaufen (z. B. tf.cond), falls vorhanden. Das ist wichtig, weil das muss der Quantisierungsprozess alle möglichen Eingaben verarbeiten können, auch wenn sie nicht explizit im repräsentatives Dataset.
    • Sie sollte groß genug sein, um genügend statistische Daten zu erfassen Fehler. Als Faustregel gilt: Verwenden Sie mehr als 200 repräsentative Stichproben.

    Das repräsentative Dataset kann ein Teil des Trainings-Datasets sein oder ein separates Dataset, das speziell für die repräsentative Darstellung der realen Eingaben in das Modell entwickelt wurde. Welcher Datensatz verwendet wird, hängt von der jeweiligen Anwendung ab.

  • Static Range Quantization (SRQ): SRQ bestimmt den Wertebereich. für die Gewichtungen und Aktivierungen eines neuronalen Netzwerkmodells Kalibrierungsschritt. Das bedeutet, dass für alle Eingaben für das Modell. Dies kann weniger genau sein als die Quantisierung mit dynamischem Bereich, insbesondere bei Modellen mit einem großen Bereich von Eingabewerten. Die Quantisierung mit statischem Bereich erfordert jedoch weniger Berechnungen bei der Laufzeit als die Quantisierung mit dynamischem Bereich.

  • Quantisierung mit dynamischem Bereich (Dynamic Range Quantization, DRQ): Mit DRQ wird der Wertebereich für die Gewichte und Aktivierungen eines neuronalen Netzwerkmodells für jede Eingabe bestimmt. So kann sich das Modell an den Wertebereich um die Genauigkeit zu verbessern. Die Quantisierung mit dynamischem Bereich erfordert jedoch mehr Berechnungen bei der Laufzeit als die Quantisierung mit statischem Bereich.

    Feature Quantisierung statischer Bereiche Dynamische Bereichsquantisierung
    Wertebereich Wird einmal während der Kalibrierung bestimmt Für jede Eingabe bestimmt
    Genauigkeit Kann weniger genau sein, insbesondere bei Modellen mit einem breiten Bereich von Eingabewerten Können genauer sein, insbesondere bei Modellen mit einem breiten Bereich von Eingabewerten
    Komplexität Einfacher Komplexer
    Berechnung während der Laufzeit Weniger Rechenaufwand Mehr Rechenleistung
  • Nur Gewichtung: Die reine Gewichtungsquantisierung ist ein Quantisierung, die nur die Gewichtungen eines neuronalen Netzwerkmodells quantisiert. während die Aktivierungen in einem Gleitkommawert bleiben. Dies kann eine gute Option für Modelle sein, die empfindlich auf Genauigkeit reagieren, da es dazu beitragen kann, die Genauigkeit des Modells beizubehalten.

Quantisierung

Die Quantisierung kann angewendet werden, indem die Option QuantizationOptions konfiguriert und den Konvertierungsoptionen zugewiesen wird. Zu den wichtigsten Optionen gehören:

  • tags: Sammlung von Tags, die die MetaGraphDef innerhalb der SavedModel identifizieren, die quantisiert werden soll. Du musst nicht angeben, ob du nur eine MetaGraphDef hast.
  • signatur_keys: Sequenz der Schlüssel zur Identifizierung von SignatureDef mit Ein- und Ausgaben. Wenn nicht angegeben, wird ["serving_default"] verwendet.
  • quantization_method: Anzuwendende Quantisierungsmethode. Falls nicht angegeben ist, wird die Quantisierung STATIC_RANGE angewendet.
  • op_set: Sollte als XLA beibehalten werden. Dies ist derzeit die Standardoption. Eine Angabe ist nicht erforderlich.
  • representative_datasets: Geben Sie das Dataset an, das für die Kalibrierung der Quantisierungsparameter verwendet wird.

Repräsentatives Dataset erstellen

Ein repräsentatives Dataset ist im Wesentlichen eine Iteration von Stichproben. Ein Beispiel ist hier eine Karte von: {input_key: input_value}. Beispiel:

representative_dataset = [{"x": tf.random.uniform(shape=(3, 3))}
                          for _ in range(256)]

Die repräsentativen Datasets sollten als TFRecord-Dateien mit der Klasse TfRecordRepresentativeDatasetSaver gespeichert werden, die derzeit im Pip-Paket „tf-nightly“ verfügbar ist. Beispiel:

# Assumed tf-nightly installed.
import tensorflow as tf
representative_dataset = [{"x": tf.random.uniform(shape=(3, 3))}
                          for _ in range(256)]
tf.quantization.experimental.TfRecordRepresentativeDatasetSaver(
       path_map={'serving_default': '/tmp/representative_dataset_path'}
    ).save({'serving_default': representative_dataset})

Beispiele

Im folgenden Beispiel wird das Modell mit dem Signaturschlüssel serving_default und dem Funktionsalias tpu_func quantisiert:

docker run \
  --mount type=bind,source=${MODEL_PATH},target=/tmp/input,readonly \
  --mount type=bind,source=${CONVERTED_MODEL_PATH},target=/tmp/output \
  ${CONVERTER_IMAGE} \
  --input_model_dir=/tmp/input \
  --output_model_dir=/tmp/output \
  --converter_options_string=' \
    tpu_functions { \
      function_alias: "tpu_func" \
    } \
    external_feature_configs { \
      quantization_options { \
        signature_keys: "serving_default" \
        representative_datasets: { \
          key: "serving_default" \
          value: { \
            tfrecord_file_path: "${TF_RECORD_FILE}" \
          } \
        } \
      } \
    } '

Batch-Verarbeitung hinzufügen

Mit dem Konverter können Sie einem Modell Batch-Verarbeitung hinzufügen. Eine Beschreibung der Optionen für die Batchverarbeitung, die angepasst werden können, finden Sie unter Definition der Batchverarbeitungsoptionen.

Standardmäßig führt der Konverter alle TPU-Funktionen im Modell im Batch aus. Es kann auch Batch vom Nutzer bereitgestellt signaturen und Funktionen was die Leistung weiter verbessern kann. Beliebige TPU-Funktion, vom Nutzer bereitgestellte Funktion oder Signatur, die in Batches verwendet wird, muss den Batchvorgangs strenge Anforderungen an Formen.

Mit dem Converter können Sie auch vorhandene Batch-Optionen aktualisieren. Im folgenden Beispiel wird gezeigt, wie Sie einem Modell Batching hinzufügen. Weitere Informationen Informationen zur Batchverarbeitung finden Sie unter Batching im Detail.

batch_options {
  num_batch_threads: 2
  max_batch_size: 8
  batch_timeout_micros: 5000
  allowed_batch_sizes: 2
  allowed_batch_sizes: 4
  allowed_batch_sizes: 8
  max_enqueued_batches: 10
}

bfloat16- und IO-Formoptimierungen deaktivieren

BFloat16- und IO-Formoptimierungen sind standardmäßig aktiviert. Wenn sie nicht funktionieren mit Ihrem Modell funktionieren, können sie deaktiviert werden.

# Disable both optimizations
disable_default_optimizations: true

# Or disable them individually
io_shape_optimization: DISABLED
bfloat16_optimization: DISABLED

Conversion-Bericht

Sie finden diesen Conversion-Bericht im Protokoll, nachdem Sie den Inferenzkonverter ausgeführt haben. Ein Beispiel dafür sehen Sie unten.

-------- Conversion Report --------
TPU cost of the model: 96.67% (2034/2104)
CPU cost of the model:  3.33% (70/2104)

Cost breakdown
================================
%         Cost    Name
--------------------------------
3.33      70      [CPU cost]
48.34     1017    tpu_func_1
48.34     1017    tpu_func_2
--------------------------------

Dieser Bericht schätzt die Berechnungskosten des Ausgabemodells auf CPU und TPU und schlüsseln Sie die TPU-Kosten für jede Funktion auf. Dies sollte sich Ihre Auswahl der TPU-Funktionen in den Konvertierungsoptionen.

Wenn Sie die TPU besser nutzen möchten, sollten Sie mit der Modellstruktur experimentieren und die Konvertierungsoptionen anpassen.

Häufig gestellte Fragen

Welche Funktion(en) sollte ich auf die TPU legen?

Am besten legen Sie so viel wie möglich von Ihrem Modell auf der TPU ab, da der die große Mehrheit der Vorgänge auf der TPU schneller ausgeführt wird.

Wenn Ihr Modell keine TPU-inkompatiblen Vorgänge, Strings oder Sparse-Vorgänge enthält Tensoren ist, das gesamte Modell auf die TPU zu legen, normalerweise die beste Strategie. Dazu können Sie eine Funktion finden oder erstellen, die das gesamte Modell umschließt, einen Funktionsalias dafür erstellen und diesen an den Konverter übergeben.

Wenn Ihr Modell Teile enthält, die nicht auf der TPU ausgeführt werden können (z. B. TPU-inkompatible Vorgänge, Strings oder spärliche Tensoren), hängt die Auswahl der TPU-Funktionen davon ab, wo sich der inkompatible Teil befindet.

  • Wenn es am Anfang oder Ende des Modells ist, können Sie das damit es auf der CPU bleibt. Beispiele: Vor- und Nachverarbeitung von Strings Phasen. Weitere Informationen zum Verschieben von Code zur CPU finden Sie unter „Wie verschiebe ich einen Teil des Modells zur CPU?“ Sie zeigt eine typische Methode zur Refaktorierung des Modells.
  • Wenn sich der Code in der Mitte des Modells befindet, ist es besser, das Modell in drei Teile zu teilen und alle TPU-inkompatiblen Vorgänge im mittleren Teil zu platzieren und auf der CPU auszuführen.
  • Wenn es sich um einen spärlichen Tensor handelt, können Sie tf.sparse.to_dense auf der CPU aufrufen und den resultierenden dichten Tensor an den TPU-Teil des Modells übergeben.

Ein weiterer Faktor ist die HBM-Nutzung. Das Einbetten von Tabellen kann viel HBM verbrauchen. Wenn sie die Hardwarebeschränkung der TPU überschreiten, müssen sie zusammen mit den Suchvorgängen auf der CPU ausgeführt werden.

Nach Möglichkeit sollte nur eine TPU-Funktion unter einer Signatur vorhanden sein. Wenn die Struktur Ihres Modells den Aufruf mehrerer TPU-Funktionen pro eingehender Inferenzanfrage erfordert, sollten Sie die zusätzliche Latenz beim Senden von Tensoren zwischen CPU und TPU berücksichtigen.

Eine gute Möglichkeit, die Auswahl von TPU-Funktionen zu bewerten, besteht darin, die Conversion-Bericht. Sie zeigt den Prozentsatz der Berechnung, der auf der TPU platziert wurde, und eine Aufschlüsselung der Kosten jeder TPU-Funktion.

Wie verschiebe ich einen Teil des Modells zur CPU?

Wenn Ihr Modell Teile enthält, die nicht auf der TPU gesendet werden können, müssen Sie das Modell umstrukturieren, um sie auf die CPU zu verschieben. Hier ein Beispiel: Das Modell ist ein Sprachmodell mit einer Vorverarbeitungsphase. Der Code für Ebenendefinitionen und -Funktionen der Einfachheit halber ausgelassen.

class LanguageModel(tf.keras.Model):
  @tf.function
  def model_func(self, input_string):
    word_ids = self.preprocess(input_string)
    return self.bert_layer(word_ids)

Dieses Modell kann aus zwei Gründen nicht direkt auf der TPU bereitgestellt werden. Zunächst sollte der ist eine Zeichenfolge. Zweitens kann die preprocess-Funktion viele String-Vorgänge enthalten. Beide sind nicht TPU-kompatibel.

Um dieses Modell zu überarbeiten, können Sie eine weitere Funktion namens tpu_func erstellen, um die rechenintensive bert_layer zu hosten. Erstellen Sie dann einen Funktionsalias für tpu_func und übergeben Sie sie an den Converter. So wird alles innerhalb von tpu_func auf der TPU ausgeführt und alles, was in model_func übrig bleibt, auf der CPU.

class LanguageModel(tf.keras.Model):
  @tf.function
  def tpu_func(self, word_ids):
    return self.bert_layer(word_ids)

  @tf.function
  def model_func(self, input_string):
    word_ids = self.preprocess(input_string)
    return self.tpu_func(word_ids)

Was kann ich tun, wenn das Modell TPU-inkompatible Vorgänge, Strings oder spärliche Tensoren enthält?

Die meisten standardmäßigen TensorFlow-Operationen werden auf der TPU unterstützt, aber einige einschließlich dünnbesetzter Tensoren und Strings werden nicht unterstützt. Der Konverter prüft nicht auf TPU-inkompatible Vorgänge. Ein Modell mit solchen Operationen kann also Conversion. Wenn Sie es jedoch für die Inferenz ausführen, treten Fehler wie unten aufgeführt auf.

'tf.StringToNumber' op isn't compilable for TPU device.

Wenn Ihr Modell TPU-inkompatible Vorgänge enthält, sollten diese außerhalb der TPU-Funktion platziert werden. Außerdem ist „String“ ein nicht unterstütztes Datenformat auf der TPU. Also Variablen vom Typ „String“ sollten nicht in der TPU-Funktion platziert werden. Und die Parameter und Rückgabewerte der TPU-Funktion nicht als Stringtyp gut. Vermeiden Sie außerdem, spärlich besetzte Tensoren in die TPU-Funktion einzusetzen, einschließlich ihrer Parameter und Rückgabewerte.

Es ist in der Regel nicht schwierig, den inkompatiblen Teil des Modells zu refaktorisieren und auf die CPU zu verschieben. Hier ist ein Beispiel.

Wie kann ich benutzerdefinierte Vorgänge im Modell unterstützen?

Wenn in Ihrem Modell benutzerdefinierte Operationen verwendet werden, erkennt der Converter sie möglicherweise nicht und das Modell nicht konvertieren kann. Das liegt daran, dass die Operatorbibliothek des benutzerdefinierten Operators, die die vollständige Definition des Operators enthält, nicht mit dem Konverter verknüpft ist.

Da der Converter-Code derzeit noch nicht als Open Source verfügbar ist, kann der Converter nicht mit benutzerdefinierter Bedienung.

Was soll ich tun, wenn ich ein TensorFlow 1-Modell habe?

Der Converter unterstützt keine TensorFlow 1-Modelle. TensorFlow 1-Modelle sollten zu TensorFlow 2 migriert werden.

Muss ich die MLIR-Brücke aktivieren, wenn ich mein Modell ausführe?

Die meisten konvertierten Modelle können entweder mit der neueren TF2XLA-MLIR-Bridge oder der ursprünglichen TF2XLA-Bridge ausgeführt werden.

Wie konvertiere ich ein Modell, das bereits ohne Funktionsalias exportiert wurde?

Wenn ein Modell ohne Funktionsalias exportiert wurde, können Sie es am einfachsten noch einmal und dann Funktionsalias erstellen Wenn das noch einmal exportiert werden kann, kann das Modell trotzdem konvertiert werden, indem durch Angabe von concrete_function_name. Die Identifizierung der richtigen concrete_function_name erfordert etwas Detektivarbeit.

Funktionsaliasse sind eine Zuordnung eines benutzerdefinierten Strings zu einem bestimmten Funktionsnamen. Sie erleichtern es, auf eine bestimmte Funktion im Modell zu verweisen. Die Der Converter akzeptiert sowohl Funktionsaliasse als auch unverarbeitete konkrete Funktionsnamen.

Konkrete Funktionsnamen finden Sie in der saved_model.pb.

Das folgende Beispiel zeigt, wie Sie eine konkrete Funktion namens __inference_serve_24 auf der TPU.

sudo docker run \
--mount type=bind,source=${MODEL_PATH},target=/tmp/input,readonly \
--mount type=bind,source=${CONVERTED_MODEL_PATH},target=/tmp/output \
${CONVERTER_IMAGE} \
--input_model_dir=/tmp/input \
--output_model_dir=/tmp/output \
--converter_options_string='
    tpu_functions {
      concrete_function_name: "__inference_serve_24"
    }'

Wie behebe ich einen Einschränkungsfehler bei der Kompilierungszeit?

Sowohl für das Training als auch für die Inferenz erfordert XLA, dass die Eingaben für bestimmte Operationen eine bekannte Form beim Kompilieren der TPU. Das bedeutet, dass die Eingaben dieser Vorgänge eine statisch bekannte Form haben müssen, wenn XLA den TPU-Teil des Programms kompiliert.

Es gibt zwei Möglichkeiten, dieses Problem zu beheben.

  • Die beste Option besteht darin, die Eingaben des Vorgangs so zu aktualisieren, dass sie einen statisch bekannten Form an, wenn XLA das TPU-Programm kompiliert. Diese Kompilierung erfolgt kurz vor dem Ausführen des TPU-Teils des Modells. Das bedeutet, dass die Form zum Zeitpunkt der Ausführung von TpuFunction statisch bekannt sein sollte.
  • Sie haben auch die Möglichkeit, den Parameter TpuFunction so zu ändern, dass der Parameter Problematischer Vorgang

Warum erhalte ich einen Fehler bei der Batch-Bildverarbeitung?

Die Batchverarbeitung hat strenge Anforderungen an Formen mit denen eingehende Anfragen mit ihrer 0. Dimension (auch als Batch-Dimension). Diese Formanforderungen stammen aus der TensorFlow-Batch-Operation und können nicht gelockert werden.

Wenn Sie diese Anforderungen nicht erfüllen, kann es zu Fehlern wie den folgenden kommen:

  1. Batch-Eingabetensoren müssen mindestens eine Dimension haben.
  2. Die Dimensionen der Eingaben sollten übereinstimmen.
  3. Die Batch-Eingabetensoren, die in einer bestimmten Funktionsaufruf bereitgestellt werden, müssen dieselbe Größe in der Nulldimension haben.
  4. Die Nullte Dimension des Batch-Ausgabetensors entspricht nicht der Summe der Größen der Nullten Dimension der Eingabetensoren.

Sie können diesen Anforderungen gerecht werden, indem Sie eine andere Funktion oder signature für die Stapelverarbeitung. Möglicherweise müssen auch vorhandene Funktionen angepasst werden, um diese Anforderungen.

Wenn eine Funktion Daten werden in Batches zusammengefasst. Achten Sie darauf, dass die Shapes von „input_signature“ von @tf.function vollständig sind. haben „None“ in der 0. Dimension. Wenn eine Signatur in einem Batch verarbeitet wird, muss für alle Eingaben in der 0. Dimension „-1“ angegeben sein.

Eine vollständige Erklärung, warum diese Fehler auftreten und wie Sie sie beheben können sehen Sie sich Batching im Detail.

Bekannte Probleme

TPU-Funktion kann keine andere TPU-Funktion indirekt aufrufen

Der Converter kann zwar die meisten Funktionsaufruf-Szenarien im CPU-TPU-Grenze liegt, gibt es einen seltenen Grenzfall, der ausfällt. Das ist der Zeitpunkt, an dem eine TPU ruft die Funktion indirekt eine andere TPU-Funktion auf.

Das liegt daran, dass der Converter den direkten Aufrufer einer TPU-Funktion so ändert, dass nicht mehr die TPU-Funktion selbst, sondern ein TPU-Aufruf-Stub aufgerufen wird. Der Aufruf-Stub enthält Vorgänge, die nur auf der CPU ausgeführt werden können. Wenn eine TPU-Funktion eine Funktion aufruft, die schließlich den direkten Aufrufer aufruft, können diese CPU-Vorgänge zur Ausführung auf die TPU verschoben werden, was zu fehlenden Kernelfehlern führt. Diesen Fall notieren unterscheidet sich von einer TPU-Funktion, die direkt eine andere TPU-Funktion aufruft. In dieser ändert der Converter keine der Funktionen, um den Aufruf-Stub aufzurufen. funktionieren.

Im Converter haben wir die Erkennung dieses Szenarios implementiert. Wenn der folgende Fehler angezeigt wird, ist Ihr Modell auf diesen Grenzfall gestoßen:

Unable to place both "__inference_tpu_func_2_46" and "__inference_tpu_func_4_68"
on the TPU because "__inference_tpu_func_2_46" indirectly calls
"__inference_tpu_func_4_68". This behavior is unsupported because it can cause
invalid graphs to be generated.

Die allgemeine Lösung besteht darin, das Modell zu refaktorieren, um einen solchen Funktionsaufruf zu vermeiden. Szenario. Ist dies zu schwierig, wenden Sie sich an den Google-Support mehr zu besprechen.

Referenz

Konvertierungsoptionen im Protobuf-Format

message ConverterOptions {
  // TPU conversion options.
  repeated TpuFunction tpu_functions = 1;

  // The state of an optimization.
  enum State {
    // When state is set to default, the optimization will perform its
    // default behavior. For some optimizations this is disabled and for others
    // it is enabled. To check a specific optimization, read the optimization's
    // description.
    DEFAULT = 0;
    // Enabled.
    ENABLED = 1;
    // Disabled.
    DISABLED = 2;
  }

  // Batch options to apply to the TPU Subgraph.
  //
  // At the moment, only one batch option is supported. This field will be
  // expanded to support batching on a per function and/or per signature basis.
  //
  //
  // If not specified, no batching will be done.
  repeated BatchOptions batch_options = 100;

  // Global flag to disable all optimizations that are enabled by default.
  // When enabled, all optimizations that run by default are disabled. If a
  // default optimization is explicitly enabled, this flag will have no affect
  // on that optimization.
  //
  // This flag defaults to false.
  bool disable_default_optimizations = 202;

  // If enabled, apply an optimization that reshapes the tensors going into
  // and out of the TPU. This reshape operation improves performance by reducing
  // the transfer time to and from the TPU.
  //
  // This optimization is incompatible with input_shape_opt which is disabled.
  // by default. If input_shape_opt is enabled, this option should be
  // disabled.
  //
  // This optimization defaults to enabled.
  State io_shape_optimization = 200;

  // If enabled, apply an optimization that updates float variables and float
  // ops on the TPU to bfloat16. This optimization improves performance and
  // throughtput by reducing HBM usage and taking advantage of TPU support for
  // bfloat16.
  //
  // This optimization may cause a loss of accuracy for some models. If an
  // unacceptable loss of accuracy is detected, disable this optimization.
  //
  // This optimization defaults to enabled.
  State bfloat16_optimization = 201;

  BFloat16OptimizationOptions bfloat16_optimization_options = 203;

  // The settings for XLA sharding. If set, XLA sharding is enabled.
  XlaShardingOptions xla_sharding_options = 204;
}

message TpuFunction {
  // The function(s) that should be placed on the TPU. Only provide a given
  // function once. Duplicates will result in errors. For example, if
  // you provide a specific function using function_alias don't also provide the
  // same function via concrete_function_name or jit_compile_functions.
  oneof name {
    // The name of the function alias associated with the function that
    // should be placed on the TPU. Function aliases are created during model
    // export using the tf.saved_model.SaveOptions.
    //
    // This is a recommended way to specify which function should be placed
    // on the TPU.
    string function_alias = 1;

    // The name of the concrete function that should be placed on the TPU. This
    // is the name of the function as it found in the GraphDef and the
    // FunctionDefLibrary.
    //
    // This is NOT the recommended way to specify which function should be
    // placed on the TPU because concrete function names change every time a
    // model is exported.
    string concrete_function_name = 3;

    // The name of the signature to be placed on the TPU. The user must make
    // sure there is no TPU-incompatible op under the entire signature.
    string signature_name = 5;

    // When jit_compile_functions is set to True, all jit compiled functions
    // are placed on the TPU.
    //
    // To use this option, decorate the relevant function(s) with
    // @tf.function(jit_compile=True), before exporting. Then set this flag to
    // True. The converter will find all functions that were tagged with
    // jit_compile=True and place them on the TPU.
    //
    // When using this option, all other settings for the TpuFunction
    // will apply to all functions tagged with
    // jit_compile=True.
    //
    // This option will place all jit_compile=True functions on the TPU.
    // If only some jit_compile=True functions should be placed on the TPU,
    // use function_alias or concrete_function_name.
    bool jit_compile_functions = 4;
  }

}

message BatchOptions {
  // Number of scheduling threads for processing batches of work. Determines
  // the number of batches processed in parallel. This should be roughly in line
  // with the number of TPU cores available.
  int32 num_batch_threads = 1;

  // The maximum allowed batch size.
  int32 max_batch_size = 2;

  // Maximum number of microseconds to wait before outputting an incomplete
  // batch.
  int32 batch_timeout_micros = 3;

  // Optional list of allowed batch sizes. If left empty,
  // does nothing. Otherwise, supplies a list of batch sizes, causing the op
  // to pad batches up to one of those sizes. The entries must increase
  // monotonically, and the final entry must equal max_batch_size.
  repeated int32 allowed_batch_sizes = 4;

  // Maximum number of batches enqueued for processing before requests are
  // failed fast.
  int32 max_enqueued_batches = 5;

  // If set, disables large batch splitting which is an efficiency improvement
  // on batching to reduce padding inefficiency.
  bool disable_large_batch_splitting = 6;

  // Experimental features of batching. Everything inside is subject to change.
  message Experimental {
    // The component to be batched.
    // 1. Unset if it's for all TPU subgraphs.
    // 2. Set function_alias or concrete_function_name if it's for a function.
    // 3. Set signature_name if it's for a signature.
    oneof batch_component {
      // The function alias associated with the function. Function alias is
      // created during model export using the tf.saved_model.SaveOptions, and is
      // the recommended way to specify functions.
      string function_alias = 1;

      // The concreate name of the function. This is the name of the function as
      // it found in the GraphDef and the FunctionDefLibrary. This is NOT the
      // recommended way to specify functions, because concrete function names
      // change every time a model is exported.
      string concrete_function_name = 2;

      // The name of the signature.
      string signature_name = 3;
    }
  }

  Experimental experimental = 7;
}

message BFloat16OptimizationOptions {
  // Indicates where the BFloat16 optimization should be applied.
  enum Scope {
    // The scope currently defaults to TPU.
    DEFAULT = 0;
    // Apply the bfloat16 optimization to TPU computation.
    TPU = 1;
    // Apply the bfloat16 optimization to the entire model including CPU
    // computations.
    ALL = 2;
  }

  // This field indicates where the bfloat16 optimization should be applied.
  //
  // The scope defaults to TPU.
  Scope scope = 1;

  // If set, the normal safety checks are skipped. For example, if the model
  // already contains bfloat16 ops, the bfloat16 optimization will error because
  // pre-existing bfloat16 ops can cause issues with the optimization. By
  // setting this flag, the bfloat16 optimization will skip the check.
  //
  // This is an advanced feature and not recommended for almost all models.
  //
  // This flag is off by default.
  bool skip_safety_checks = 2;

  // Ops that should not be converted to bfloat16.
  // Inputs into these ops will be cast to float32, and outputs from these ops
  // will be cast back to bfloat16.
  repeated string filterlist = 3;
}

message XlaShardingOptions {
  // num_cores_per_replica for TPUReplicateMetadata.
  //
  // This is the number of cores you wish to split your model into using XLA
  // SPMD.
  int32 num_cores_per_replica = 1;

  // (optional) device_assignment for TPUReplicateMetadata.
  //
  // This is in a flattened [x, y, z, core] format (for
  // example, core 1 of the chip
  // located in 2,3,0 will be stored as [2,3,0,1]).
  //
  // If this is not specified, then the device assignments will utilize the same
  // topology as specified in the topology attribute.
  repeated int32 device_assignment = 2;

  // A serialized string of tensorflow.tpu.TopologyProto objects, used for
  // the topology attribute in TPUReplicateMetadata.
  //
  // You must specify the mesh_shape and device_coordinates attributes in
  // the topology object.
  //
  // This option is required for num_cores_per_replica > 1 cases due to
  // ambiguity of num_cores_per_replica, for example,
  // pf_1x2x1 with megacore and df_1x1
  // both have num_cores_per_replica = 2, but topology is (1,2,1,1) for pf and
  // (1,1,1,2) for df.
  // - For pf_1x2x1, mesh shape and device_coordinates looks like:
  //   mesh_shape = [1,2,1,1]
  //   device_coordinates=flatten([0,0,0,0], [0,1,0,0])
  // - For df_1x1, mesh shape and device_coordinates looks like:
  //   mesh_shape = [1,1,1,2]
  //   device_coordinates=flatten([0,0,0,0], [0,0,0,1])
  // - For df_2x2, mesh shape and device_coordinates looks like:
  //   mesh_shape = [2,2,1,2]
  //   device_coordinates=flatten(
  //    [0,0,0,0],[0,0,0,1],[0,1,0,0],[0,1,0,1]
  //    [1,0,0,0],[1,0,0,1],[1,1,0,0],[1,1,0,1])
  bytes topology = 3;
}

Batchverarbeitung im Detail

Die Batchverarbeitung wird verwendet, um den Durchsatz und die TPU-Auslastung zu verbessern. Sie ermöglicht mehrere Anfragen gleichzeitig verarbeitet werden. Während des Trainings kann mit tf.data ausgeführt werden. Während der Inferenz wird in der Regel eine Operation in den Graphen eingefügt, die eingehende Anfragen bündelt. Der Vorgang wartet, bis genügend Anfragen vorhanden sind oder ein Zeitlimit erreicht wird, bevor er einen großen Batch aus den einzelnen Anfragen generiert. Weitere Informationen zu den verschiedenen Optionen für die Batchverarbeitung, die angepasst werden können, einschließlich Batchgrößen und Zeitüberschreitungen, finden Sie unter Definition von Batchverarbeitungsoptionen.

In-Graph-Batchverarbeitung

Standardmäßig fügt der Converter die Batch-Operation direkt vor der TPU-Berechnung ein. Sie umhüllt die vom Nutzer bereitgestellten TPU-Funktionen und alle vorhandenen TPU-Berechnungen im Modell mit Batch-Vorgängen. Dieses Standardverhalten kann überschrieben werden, indem Sie dem Konverter mitteilen, welche Funktionen und/oder Signaturen in Batches verarbeitet werden sollen.

Das folgende Beispiel zeigt, wie die Standard-Batchverarbeitung hinzugefügt wird.

batch_options {
  num_batch_threads: 2
  max_batch_size: 8
  batch_timeout_micros: 5000
  allowed_batch_sizes: 2
  allowed_batch_sizes: 4
  allowed_batch_sizes: 8
  max_enqueued_batches: 10
}

Batchverarbeitung von Signaturen

Beim Batching von Signaturen wird das gesamte Modell in Batches verarbeitet, beginnend bei den Eingaben der Signatur und endend bei den Ausgaben der Signatur. Im Gegensatz zum standardmäßigen Batching-Verhalten des Converters werden beim Batching von Signaturen sowohl die TPU- als auch die CPU-Berechnungen zusammengefasst. Dies führt bei einigen Modellen zu einer Leistungssteigerung von 10 bis 20 % bei der Inferenz.

Wie bei allen Batches gibt es auch bei strengen Anforderungen an Formen. Damit diese Anforderungen an die Form erfüllt werden, sollten Eingaben für Signaturen mindestens zweidimensional sein. Die erste Dimension ist die Batchgröße. und sollte den Wert -1 haben. Zum Beispiel sind (-1, 4), (-1) oder (-1, 128, 4, 10) alle gültige Eingabeformen. Wenn dies nicht möglich ist, verwenden Sie das standardmäßige Batch-Verhalten oder Funktions-Batching.

Wenn Sie die Batch-Signatur verwenden möchten, geben Sie den Namen der Signatur(en) als signature_name(s) mit dem BatchOptions an.

batch_options {
  num_batch_threads: 2
  max_batch_size: 8
  batch_timeout_micros: 5000
  allowed_batch_sizes: 2
  allowed_batch_sizes: 4
  allowed_batch_sizes: 8
  max_enqueued_batches: 10
  experimental {
    signature_name: "serving_default"
  }
}

Batchverarbeitung von Funktionen

Mit dem Batch-Verfahren für Funktionen können Sie dem Converter mitteilen, welche Funktionen in einem Batch verarbeitet werden sollen. Standardmäßig führt der Converter alle TPU-Funktionen im Batch aus. Funktion dass Batches dieses Standardverhalten überschreibt.

Mit der Funktion „Batch-Verarbeitung“ können CPU-Berechnungen in Batches ausgeführt werden. Bei vielen Modellen lässt sich die Leistung verbessern, wenn die CPU-Berechnungen in Batches ausgeführt werden. Die beste Methode für die Batch-CPU-Berechnung ist die Signatur-Batchverarbeitung. Bei einigen Modellen funktioniert sie jedoch möglicherweise nicht. In diesen Fällen können Funktions-Batching genutzt werden, um einen Teil der CPU in Batches aufzuteilen. Berechnung zusätzlich zur TPU-Berechnung. Der Batchvorgang kann nicht auf der TPU ausgeführt werden, sodass jede bereitgestellte Stapelfunktion auf dem CPU

Mit dem Batching von Funktionen können auch die strengen Formanforderungen der Batch-Operation erfüllt werden. Wenn die TPU-Funktionen nicht den Formvorschriften der Batch-Operation entsprechen, kann der Converter mithilfe des Funktions-Batching aufgefordert werden, verschiedene Funktionen zu batchen.

Generieren Sie zu diesem Zweck eine function_alias für die Funktion, die in Batches zusammengefasst. Dazu können Sie in Ihrem Modell eine Funktion suchen oder erstellen, die alles umschließt, was Sie in einem Batch verarbeiten möchten. Achten Sie darauf, dass diese Funktion die strengen Anforderungen an die Form erfüllt, die durch die Batch-Operation auferlegt werden. Fügen Sie @tf.function hinzu, falls noch keine vorhanden ist. Es ist wichtig, dass Sie die input_signature an die @tf.function senden. Die 0. Dimension sollte None sein, da es sich um die Batch-Dimension handelt und sie daher keine feste Größe haben. Beispiel: [None, 4], [None] oder [None, 128, 4, 10] sind alle gültige Eingabeformen. Geben Sie beim Speichern des Modells SaveOptions wie die hier gezeigten an unten, um model.batch_func den Alias "batch_func" zuzuweisen. Dann können Sie diese Funktionsalias zum Konverter hinzu.

class ToyModel(tf.keras.Model):
  @tf.function(input_signature=[tf.TensorSpec(shape=[None, 10],
                                              dtype=tf.float32)])
  def batch_func(self, x):
    return x * 1.0

  ...

model = ToyModel()
save_options = tf.saved_model.SaveOptions(function_aliases={
    'batch_func': model.batch_func,
})
tf.saved_model.save(model, model_dir, options=save_options)

Übergeben Sie als Nächstes die function_alias mithilfe der BatchOptions.

batch_options {
  num_batch_threads: 2
  max_batch_size: 8
  batch_timeout_micros: 5000
  allowed_batch_sizes: 2
  allowed_batch_sizes: 4
  allowed_batch_sizes: 8
  max_enqueued_batches: 10
  experimental {
    function_alias: "batch_func"
  }
}

Definition von Stapelverarbeitungsoptionen

  • num_batch_threads: (Ganzzahl) Anzahl der Planungsthreads für die Verarbeitung von Arbeitspaketen. Bestimmt die Anzahl der parallel verarbeiteten Batches. Diese sollte ungefähr der Anzahl der verfügbaren TPU-Kerne entsprechen.
  • max_batch_size: (ganzzahl) Maximale zulässige Batchgröße. Kann größer sein als allowed_batch_sizes, um eine umfangreiche Batchaufteilung zu verwenden.
  • batch_timeout_micros: (Ganzzahl) Maximale Anzahl der zu wartenden Mikrosekunden bevor ein unvollständiger Batch ausgegeben wird.
  • allowed_batch_sizes: (Liste von Ganzzahlen) Wenn die Liste nicht leer ist, werden die Batches auf die nächstliegende Größe in der Liste aufgestockt. Die Liste muss monoton ansteigend und das letzte Element muss kleiner oder gleich max_batch_size
  • max_enqueued_batches: (Ganzzahl) Maximale Anzahl von Batches, die zur Verarbeitung in die Warteschlange gestellt werden, bevor Anfragen schnell fehlschlagen.

Vorhandene Batchoptionen aktualisieren

Sie können Batch-Optionen hinzufügen oder aktualisieren, indem Sie das Docker-Image mit der Angabe von „batch_options“ ausführen und disable_default_optimizations mit dem Flag --converter_options_string auf „true“ setzen. Die Batch-Optionen werden auf jede TPU-Funktion oder vorhandene Batch-Operation angewendet.

batch_options {
  num_batch_threads: 2
  max_batch_size: 8
  batch_timeout_micros: 5000
  allowed_batch_sizes: 2
  allowed_batch_sizes: 4
  allowed_batch_sizes: 8
  max_enqueued_batches: 10
}
disable_default_optimizations=True

Anforderungen an die Form von Batches

Batches werden erstellt, indem Eingabetensoren über Anfragen hinweg entlang ihrer Batchdimension (0. Dimension) zusammengefügt werden. Die Ausgabetensoren werden entlang ihrer 0. Dimension aufgeteilt. Für die Ausführung dieser Vorgänge gelten strenge Formatanforderungen für die Eingaben und Ausgaben des Batch-Vorgangs.

Schritt-für-Schritt-Anleitung

Um diese Anforderungen zu verstehen, ist es hilfreich, zuerst zu verstehen, wie das Batching durchgeführt wird. Im folgenden Beispiel fassen wir eine einfache tf.matmul op.

def my_func(A, B)
    return tf.matmul(A, B)

Die erste Inferenzanfrage erzeugt die Eingaben A und B mit den Formen (1, 3, 2) und (1, 2, 4). Die zweite Inferenzanfrage generiert den Eingaben A und B mit den Formen (2, 3, 2) und (2, 2, 4).

Anfrage zur Datenleihe 1

Das Zeitlimit für die Batchverarbeitung wurde erreicht. Das Modell unterstützt eine Batchgröße von 3, Die Inferenzanfragen Nr. 1 und 2 werden ohne Auffüllung in Batches zusammengefasst. Die Batch-Tensoren werden gebildet, indem die Anfragen Nr. 1 und 2 entlang des Batches (0.) Dimension. Da A in Beispiel 1 die Form (1, 3, 2) und A in Beispiel 2 die Form (2, 3, 2) hat, ergibt sich beim Zusammenführen entlang der Batch-Dimension (0. Dimension) die Form (3, 3, 2).

Batchanfrage

Der tf.matmul wird ausgeführt und es wird eine Ausgabe mit der Form (3, 3, 4) erzeugt.

Batched matmul request

Die Ausgabe von tf.matmul wird in Batches zusammengefasst, sodass sie wieder in separate Anträge stellen. Beim Batchvorgang wird dies durch Aufteilung entlang des Batches durchgeführt (0.) Dimension jedes Ausgabetensors. Sie entscheidet, wie die Nullte Dimension basierend auf der Form der ursprünglichen Eingaben aufgeteilt wird. Da die Formen der Anfrage Nr. 1 ein 0. Dimension 1 haben, hat die Ausgabe die 0. Dimension 1 für die Form (1, 3, 4). Da die Formen der Anfrage Nr. 2 die 0. Dimension 2 haben, enthält ihre Ausgabe eine 0. Dimension 2 für die Form (2, 3, 4).

Ergebnisse der Inferenzanfrage

Anforderungen an Formen

Um die beschriebene Eingabeverkettung und Ausgabeaufteilung durchzuführen hat der Batchvorgang die folgenden Formanforderungen:

  1. Eingaben für Batch-Vorgänge dürfen keine Skalare sein. Für die Verkettung entlang der 0. Dimension müssen die Tensoren mindestens zwei Dimensionen haben.

    In der Anleitung oben. Weder A noch B sind Skalare.

    Andernfalls wird ein Fehler wie Batching input tensors must have at least one dimension ausgegeben. Eine einfache Lösung für diesen Fehler besteht darin, den Skalar in einen Vektor umzuwandeln.

  2. Bei verschiedenen Inferenzanfragen (z. B. verschiedenen Aufrufen der Sitzungsausführung) haben Eingabetensoren mit demselben Namen für jede Dimension dieselbe Größe, mit Ausnahme der Nulldimension. So können Eingaben entlang ihrer Nulldimension sauber zusammengefügt werden.

    In der obigen Schritt-für-Schritt-Anleitung hat A in Anfrage 1 die Form (1, 3, 2). Das bedeutet, dass jede zukünftige Anfrage eine Form mit dem Muster (X, 3, 2) erzeugen muss. Anfrage 2 erfüllt diese Anforderung mit (2, 3, 2). Entsprechend hat Anfrage 1 B die Form (1, 2, 4). Daher müssen alle zukünftigen Anfragen erzeugen Sie eine Form mit dem Muster (X, 2, 4).

    Wenn diese Anforderung nicht erfüllt wird, wird ein Fehler wie dieser ausgegeben: Dimensions of inputs should match.

  3. Für eine bestimmte Inferenzanfrage müssen alle Eingaben dieselbe 0 haben. Dimensionsgröße. Wenn verschiedene Eingabetensoren für den Batchvorgang 0. Dimensionen haben, weiß der Batchvorgang nicht, wie die Ausgabetensoren.

    In der obigen Schritt-für-Schritt-Anleitung haben die Tensoren von Anfrage 1 alle eine Größe von 1 in der Nulldimension. Dadurch wird dem Batchvorgang mitgeteilt, dass seine Ausgabe eine 0. der Dimension „1“. Ebenso haben die Tensoren der Anfrage Nr. 2 eine 0. Dimension die Größe 2 ist, sodass die Ausgabe die 0. Dimensionsgröße 2 hat. Wenn die Batch-Operation die endgültige Form von (3, 3, 4) aufteilt, wird (1, 3, 4) für Anfrage 1 und (2, 3, 4) für Anfrage 2 generiert.

    Wenn Sie diese Anforderung nicht erfüllen, treten u. a. folgende Fehler auf: Batching input tensors supplied in a given op invocation must have equal 0th-dimension size.

  4. Die 0. Dimensionsgröße der Form jedes Ausgabetensors muss die Summe aus der Eingabetensoren 0. Dimensionsgröße (zuzüglich des Abstands, der durch den Batchvorgang, um den nächstgrößeren allowed_batch_size zu erreichen). Dadurch können Sie Den Batchvorgang zum Aufteilen der Ausgabetensoren entlang ihrer 0. Dimension in der 0. Dimension der Eingabetensoren.

    In der obigen Schritt-für-Schritt-Anleitung haben die Eingabetensoren die Nullte Dimension 1 von Anfrage 1 und 2 von Anfrage 2. Daher muss jeder Ausgabetensor eine Nullte Dimension von 3 haben, da 1 + 2 = 3. Der Ausgabetensor (3, 3, 4) erfüllt diese Anforderung. Wenn 3 keine gültige Batchgröße gewesen wäre, 4 jedoch, Batchvorgang hätte die 0. Dimension der Eingaben auffüllen müssen. zwischen 3 und 4 liegen. In diesem Fall müsste jeder Ausgabetensor eine eine 0. Dimensionsgröße von 4.

    Wenn diese Anforderung nicht erfüllt wird, wird ein Fehler wie dieser ausgegeben: Batched output tensor's 0th dimension does not equal the sum of the 0th dimension sizes of the input tensors.

Fehler bei Formvoraussetzungen beheben

Sie können diesen Anforderungen gerecht werden, indem Sie eine andere Funktion oder signature für die Stapelverarbeitung. Möglicherweise müssen auch vorhandene Funktionen angepasst werden, um diese Anforderungen.

Wenn eine Funktion in einem Batch ausgeführt wird, muss die Eingabesignatur der @tf.function in der 0. Dimension (d. h. der Batch-Dimension) None enthalten. Wenn ein signature dass alle Eingaben den Wert -1 in der 0. Dimension haben.

Der Vorgang "BatchFunction" unterstützt SparseTensors nicht als Ein- oder Ausgaben. Intern wird jeder spärliche Tensor als drei separate Tensoren dargestellt, die unterschiedliche Größen der Nulldimension haben können.