Inferenz eingeben

StableHLO wurde ursprünglich vom MHLO-Dialekt per Bootstrapping übertragen und hat die MHLO-Implementierung der Typinferenz übernommen. Der Implementierungsfortschritt wird in status.md verfolgt.

Die folgenden Richtlinien sollen die Implementierung von qualitativ hochwertigen Verifier und Formfunktionen für StableHLO-Vorgänge gewährleisten.

Vorschlag

Diese Vorschläge gelten sowohl für die erneute Überprüfung bestehender Implementierungen als auch für die Erschließung neuer Vorgänge, bis eine umfassende Abdeckung erreicht ist.

(P1) StableHLO-Spezifikation als „Source of Truth“ verwenden

spec ist die zentrale Informationsquelle für alle Verifier und Formfunktionen der StableHLO-Vorgänge. Die vorhandenen Verifizierungs- und Formfunktionen jeder Operation müssen noch einmal überprüft werden, damit sie vollständig mit der Spezifikation übereinstimmen. Das Spezifikationsdokument wird ständig weiterentwickelt. In Fällen, in denen die Spezifikation für eine Operation nicht verfügbar ist, sollte stattdessen die XLA-Implementierung einschließlich xla/service/shape_inference.cc und xla/service/hlo_verifier.cc als zentrale Informationsquelle verwendet werden. Die XLA-Implementierung deckt keine unbegrenzte Dynamik ab. Für unbegrenzte Dynamik verwenden wir also gesunden Menschenverstand, bis der Dynamik-RFC verfügbar ist.

(P2) ODS optimal nutzen

In ODS-Dateien (z. B. StablehloOps.td) werden Vorgänge mit Merkmalen und Typen für alle Operanden/Attribute/Ergebnisse definiert und die Überprüfungen durchgeführt. In den Verifikations- oder Formfunktionen für die Eigenschaften, die bereits von der ODS garantiert werden, ist daher KEIN Bestätigungscode erforderlich. Entfernen Sie den Bestätigungscode, wenn er mit ODS dupliziert wurde, da er nie ausgelöst wird.

Müssen wir Tests für die Einschränkungen aus der ODS hinzufügen? Weitere Informationen findest du unter Testrichtlinien festlegen.

(P3) Bestätigungscode in Prüfern und Formfunktionen aufbewahren

Beides:

  • verifiers: implementiert von Op::verify() und
  • Formfunktionen: implementiert durch InferTypeOpInterface-Elemente wie Op::inferReturnTypes() oder Op::inferReturnTypeComponents

kann einen Bestätigungscode zum Prüfen von Operanden/Attributen/Ergebnissen enthalten. Eine anfängliche Aufteilung könnte so aussehen: Lassen Sie die Prüfer die Operanden/Attribute prüfen, dann lassen die Formfunktionen nur abgeleitete Ergebnistypen berechnen und die Kompatibilität mit den tatsächlichen Ergebnistypen prüfen. In Wirklichkeit hat diese Aufteilung jedoch einige Probleme:

  • Die Formfunktion kann von den automatisch generierten build()-Funktionen aufgerufen werden, ohne zuerst den Prüfer aufzurufen. Also müssen auch die zugehörigen Eingaben in der Formfunktion verifiziert werden.
  • Duplizierter Code: In Verifizierern verarbeiten wir beispielsweise die Operanden und überprüfen dann einige Zwischenergebnisse. In Formfunktionen sind diese Zwischenergebnisse nützlich, um die Endergebnisse abzuleiten. Diese Zwischenergebnisse müssen zweimal berechnet werden.
  • Wartungsaufwand: Überprüfungen eines Vorgangs erfolgen in zwei verschiedenen Methoden.

Die Lösung sieht so aus:

  1. Für die meisten Vorgänge ohne Regionen (z. B. PadOp): Fügen Sie den gesamten Bestätigungscode in die Formfunktionen ein und verwerfen Sie Verifier komplett.

  2. Für Vorgänge mit Regionen (z. B. ReduceOp/IfOp; eine vollständige Liste finden Sie hier): Die automatisch generierten Builder verwenden keine Regionen als Parameter. Wenn diese Builder also eine Typinferenz beinhalten, wird die Formfunktion mit leeren Regionen aufgerufen (siehe dieses Beispiel).

    1. Wenn die Regionen nicht für die Typinferenz (wie ReduceOp) benötigt werden, geben Sie die regionsbezogene Überprüfungslogik in Verifier anstelle der Formfunktionen ein. Duplizieren Sie Code, wenn sich das nicht vermeiden lässt.

    2. Wenn die Regionen für die Typinferenz benötigt werden (IfOp/CaseOp/MapOp), muss die Formfunktion zusätzlich prüfen, ob die Regionen nicht explizit leer sind, auch wenn die ODS möglicherweise bereits ihre Existenz in der Vorgangsdefinition garantiert.

(P4) Testrichtlinien festlegen

Müssen Tests für Überprüfungen, die von ODS abgedeckt sind, hinzugefügt/gepflegt werden?

Das tun wir nicht. Die Tests sollten sich auf die Verifier und Formfunktionen konzentrieren, während bei Änderungen an ODS der Vorgang noch einmal überprüft werden muss.

Behalten Sie jedoch die fehlenden Teile im Blick: Wenn der Vorgang beispielsweise die Eigenschaft SameOperandsAndResultShape enthält, die nur Formen, aber nicht den Elementtyp prüft, sind für die Überprüfung der Elementtypen von Operanden/Ergebnissen trotzdem Tests erforderlich.

Wo werden Verifikationsanbieter und Typinferenzen getestet?

ops_stablehlo.mlir enthält die positiven Fälle von Vorgängen und (mindestens) einen negativen Test für jeden Verifizierungsfehler. Außerdem kann geprüft werden, ob der abgeleitete Rückgabetyp mit dem tatsächlichen Ergebnistyp (nicht mit!) kompatibel ist.

infer_stablehlo.mlir überprüft das Vorhandensein der Formfunktion eines Vorgangs für Zeile mit hlo_test_infer.get_return_type_components"(%x):... und prüft, ob der abgeleitete Typ genau wie erwartet übereinstimmt. Im Allgemeinen ein positiver Test pro Operation.

Deine Aufgabe:

Bei der Implementierung oder Überprüfung der Verifizierungs- und/oder Shape-Funktion eines Vorgangs:

  1. Fügen Sie alle positiven und negativen Fälle in ops_stablehlo.mlir ein.

  2. Fügen Sie infer_stablehlo.mlir einen einzelnen positiven Test hinzu, um die Schnittstelle zu testen.

  3. (Optional) Wenn eine Operation kompliziert ist und viele Tests enthalten kann, empfiehlt es sich, eine separate Testdatei mit dem Namen verify_<op_name>.mlir oder verify_<your_topic>.mlir im selben Ordner hinzuzufügen.