Wnioskowanie typu

Element StableHLO został pierwotnie pobrany z dialektu MHLO i odziedziczył implementację MHLO wnioskowania typu. Postęp implementacji można śledzić w pliku status.md.

Poniższe wytyczne mają na celu zapewnienie implementacji wysokiej jakości weryfikatorów i funkcji kształtu w operacjach StableHLO.

Propozycja

Propozycje dotyczą zarówno sprawdzania istniejących wdrożeń, jak i przeprowadzania nowych operacji aż do momentu, gdy zostaną omówione w pełni.

(P1) Użyj specyfikacji StableHLO jako źródła danych

Parametr spec (specyfikacja) jest źródłem wiarygodnych danych dla wszystkich weryfikatorów i funkcji kształtu w operacjach StableHLO. Przeanalizuj ponownie obecne weryfikatory i funkcje kształtu w przypadku każdej operacji, aby były w pełni zgodne ze specyfikacją. Pamiętaj, że specyfikacja wciąż ewoluuje. Jeśli specyfikacja operacji nie jest dostępna, źródłem wiarygodnych danych powinna być implementacja XLA, np. xla/service/shape_inference.cc i xla/service/hlo_verifier.cc. Implementacja XLA nie obejmuje nieograniczonej dynamiki, dlatego w przypadku nieograniczonej dynamiki będziemy stosować zdrowy rozsądek, dopóki nie będzie dostępny RFC dynamicznego obiektu.

(P2) Pełne wykorzystanie ODS

Pliki ODS (np. StablehloOps.td) definiują operacje z cechami i typami dla każdego operandu, atrybutu lub wyniku i przeprowadzają weryfikację. Dlatego w mechanizmach weryfikacyjnych i funkcjach kształtowania usług, które już są gwarantowane przez ODS, nie jest wymagany żaden kod weryfikacyjny. Jeśli kod weryfikacyjny zostanie powielony w ODS, usuń go, ponieważ ten kod nigdy nie zostanie wywołany.

Czy trzeba dodać testy pod kątem ograniczeń z ODS? Więcej informacji znajdziesz w artykule o ustalaniu wytycznych dotyczących testowania.

(P3) Obsługa kodu weryfikacyjnego w funkcjach weryfikatorów i kształtowania

Obie możliwości:

  • weryfikatory: zaimplementowane przez Op::verify(),
  • funkcje kształtów: zaimplementowane za pomocą elementów InferTypeOpInterface, takich jak Op::inferReturnTypes() lub Op::inferReturnTypeComponents

może mieć kod weryfikacyjny do sprawdzania operandów, atrybutów i wyników. Wstępny podział może wyglądać tak: weryfikatorzy powinni sprawdzić operandy/atrybuty, a następnie pozwolić funkcjom kształtu tylko na obliczanie wywnioskowanych typów wyników i sprawdzanie zgodności z typami wyników rzeczywistych. Jednak w rzeczywistości podział ten ma jednak kilka problemów:

  • Funkcja kształtu może zostać wywołana przez automatycznie wygenerowane funkcje build() bez wcześniejszego wywoływania weryfikatora. Wszystkie powiązane dane wejściowe muszą być więc zweryfikowane w funkcji kształtu.
  • Zduplikowany kod: na przykład w przypadku mechanizmów weryfikacji przeprowadzamy pewne przetwarzanie operandów, a potem weryfikujemy wyniki pośrednie. Następnie w funkcjach kształtujących wyniki pośrednie przydają się do wywnioskowania ostatecznych wyników. Te wyniki pośrednie muszą zostać obliczone dwukrotnie.
  • Obciążenie techniczne: weryfikacje operacji są realizowane w ramach 2 różnych metod.

Rozwiązanie jest następujące:

  1. W przypadku większości operacji bez regionów (takich jak PadOp): umieść cały kod weryfikacyjny w funkcjach kształtu i całkowicie odrzuć weryfikatory.

  2. W przypadku operacji z regionami (np. ReduceOp/IfOp; pełna lista znajduje się tutaj): automatycznie generowane kreatory nie przyjmują regionów jako parametrów, więc jeśli zawierają one wnioskowanie o typie, funkcja kształtu zostanie wywołana z pustymi regionami (zobacz ten przykład).

    1. Jeśli regiony nie są potrzebne do wnioskowania typu (np. ReduceOp), umieść w weryfikatorach logikę weryfikacji powiązaną z regionem, a nie funkcje kształtu. Jeśli to nieuniknione, zduplikuj jakiś kod.

    2. Jeśli regiony są potrzebne do wnioskowania typu (IfOp/CaseOp/MapOp), dodatkowo funkcja kształtu musi sprawdzać, czy regiony nie są wyraźnie puste, nawet jeśli ODS może już zagwarantować ich istnienie w definicji operacji.

(P4) Ustalenie wytycznych dotyczących testowania

Czy muszę dodawać lub utrzymywać testy w ramach weryfikacji objętych usługą ODS?

My nie. Testy powinny koncentrować się na weryfikatorach i funkcjach kształtu, a zmiany w ODS wymagają ponownej weryfikacji tej operacji.

Zachowaj jednak ostrożność w przypadku brakujących elementów: np. jeśli operacja zawiera cechę SameOperandsAndResultShape, która sprawdza tylko kształty, ale nie typ elementu, weryfikacja typów operandów/wyników elementów nadal wymaga testów.

Gdzie przeprowadzamy testy na potrzeby weryfikatorów i wnioskowanie o typie?

Plik ops_stablehlo.mlir zawiera pozytywne przypadki operacji i co najmniej 1 negatywny test na każdy błąd weryfikacji. Funkcja ta może też sprawdzić, czy wywnioskowany zwracany typ jest zgodny z rzeczywistym typem wyniku (nie taki sam jak!).

infer_stablehlo.mlir sprawdza istnienie funkcji kształtu w przypadku operacji w wierszu z wartością hlo_test_infer.get_return_type_components"(%x):... i sprawdza, czy wywnioskowany typ pasuje dokładnie do oczekiwanego typu. Ogólnie jeden pozytywny test na operację.

Co możesz zrobić

Podczas wdrażania lub ponownego sprawdzania funkcji weryfikatora lub funkcji kształtu:

  1. Wszystkie przypadki pozytywne i negatywne umieść w ops_stablehlo.mlir.

  2. Dodaj jeden pozytywny test w infer_stablehlo.mlir, aby przetestować interfejs.

  3. (Opcjonalnie) Jeśli operacja jest skomplikowana i może obejmować wiele testów, rozważ dodanie osobnego pliku testowego o nazwie verify_<op_name>.mlir lub verify_<your_topic>.mlir w tym samym folderze.