Вывод типа

StableHLO изначально был создан на основе диалекта MHLO и унаследовал реализацию вывода типа MHLO. Ход реализации отслеживается в status.md .

Предлагаемые ниже рекомендации предназначены для обеспечения реализации высококачественных верификаторов и функций формы для операций StableHLO.

Предложение

Эти предложения применимы как к пересмотру существующих реализаций, так и к созданию новых операций до полного охвата.

(P1) Используйте спецификацию StableHLO как источник истины.

Спецификация является источником истины для всех верификаторов и функций формы операций StableHLO. Существующие верификаторы и функции формы каждой операции необходимо пересмотреть, чтобы они полностью соответствовали спецификации. Обратите внимание, что документ спецификации продолжает развиваться. В случаях, когда спецификация для операции недоступна, вместо этого в качестве источника истины следует использовать реализацию XLA, включая xla/service/shape_inference.cc и xla/service/hlo_verifier.cc . Реализация XLA не охватывает неограниченный динамизм, поэтому для неограниченного динамизма мы будем применять здравый смысл до тех пор, пока не станет доступен динамический RFC.

(P2) Максимально эффективно использовать ОРВ

Файлы ODS (например, StablehloOps.td ) определяют операции с характеристиками и типами для каждого операнда/атрибута/результата и выполняют проверки. Таким образом, НИКАКОЙ проверочный код не требуется в верификаторах или функциях формирования свойств, которые уже гарантированы ODS. Удалите код подтверждения, если он дублируется с помощью ODS, поскольку он никогда не будет активирован.

Нужно ли нам добавлять тесты на ограничения из ODS? См. раздел «Разработка руководящих принципов тестирования» .

(P3) Поддержание кода проверки в верификаторах и функциях формы.

Оба:

  • верификаторы : реализованы Op::verify() и
  • функции формы : реализованы InferTypeOpInterface , например Op::inferReturnTypes() или Op::inferReturnTypeComponents

может иметь код проверки для проверки операндов/атрибутов/результатов. Первоначальное разделение может быть следующим: пусть верификаторы проверяют операнды/атрибуты, затем пусть функции формы вычисляют только выведенные типы результатов и проверяют совместимость с реальными типами результатов. Однако на самом деле у этого разделения есть несколько проблем:

  • Функция shape может быть вызвана автоматически сгенерированными функциями build() без предварительного вызова верификатора. Таким образом, соответствующие входные данные также должны быть проверены в функции формы.
  • Дублированный код: например, в верификаторах мы выполняем некоторую обработку операндов, а затем проверяем некоторые промежуточные результаты. Затем в функциях формы эти промежуточные результаты полезны для вывода окончательных результатов. Эти промежуточные результаты приходится рассчитывать дважды.
  • Бремя обслуживания: проверки операции выполняются двумя разными методами.

Решение заключается в следующем:

  1. Для большинства операций без регионов (например, PadOp ): попробуйте поместить весь код проверки в функции формы и полностью отказаться от верификаторов. В тех случаях, когда это невозможно из-за невозможности определить типы возвращаемых данных (например, с помощью ReshapeOp или BroadcastInDimOp ), создайте верификатор, содержащий необходимую логику проверки. Обычно выводимым операциям, таким как AddOp , все равно может потребоваться верификатор для выполнения дополнительных проверок, поскольку они проверяют ограничения предоставленного возвращаемого типа, который недоступен в методах вывода типа/формы.

  2. Для операций с регионами (например, ReduceOp/IfOp ; полный список здесь ): автоматически сгенерированные построители не принимают регионы в качестве параметров, поэтому, если эти построители включают выведение типа, то функция формы будет вызываться с пустыми регионами (см. этот пример) . ).

    1. Если регионы не нужны для вывода типа (например, ReduceOp ), поместите логику проверки, связанную с регионом, в верификаторы вместо функций формы. Дублируйте код, если это неизбежно.

    2. Если регионы необходимы для вывода типа ( IfOp/CaseOp/MapOp ), то дополнительно функция формы должна проверить, что регионы не пусты явно, даже если ODS уже может гарантировать их существование в определении Op.

(P4) Установить руководящие принципы тестирования

Нужно ли нам добавлять/поддерживать тесты для проверок, охватываемых ODS?

Мы - нет. Тесты должны быть сосредоточены на верификаторах и функциях формы, в то время как изменения в ODS требуют пересмотра этой операции.

Но будьте осторожны с недостающими частями: например, если операция содержит признак SameOperandsAndResultShape , который проверяет только формы, но не тип элемента, то проверка типов элементов операндов/результатов по-прежнему требует тестов.

Где мы размещаем тесты для верификаторов и вывода типов?

ops_stablehlo.mlir содержит положительные случаи операций и (как минимум) 1 отрицательный тест на каждую ошибку проверки. Он также может проверить, что выведенный тип возвращаемого значения совместим (не совпадает с!) с реальным типом результата.

infer_stablehlo.mlir проверяет существование функции формы операции по строке с помощью hlo_test_infer.get_return_type_components"(%x):... и проверяет, соответствует ли выведенный тип точно ожидаемому. В целом один положительный тест на каждую операцию.

Что делать

При реализации или повторном использовании функции проверки и/или формы операции:

  1. Поместите все положительные и отрицательные случаи в ops_stablehlo.mlir .

  2. Добавьте один положительный тест в infer_stablehlo.mlir для проверки интерфейса.

  3. (Необязательно) Если операция сложна и может содержать много тестов, рассмотрите возможность добавления отдельного тестового файла с verify_<op_name>.mlir илиverify_ verify_<your_topic>.mlir в той же папке.