Le dialecte Shardy (SDY) définit une représentation de fractionnement de tenseur basée sur les axes et des composants d'API supplémentaires pour associer des fractionnements à des tenseurs.
Opérations
sdy.constant
(sdy::ConstantOp)
Opération constante
Génère un tenseur output
à partir d'une constante value
.
Voir : https://github.com/openxla/stablehlo/blob/main/docs/spec.md#constant
Exemple :
%output = sdy.constant dense<[[0.0, 1.0], [2.0, 3.0]]> : tensor<2x2xf32>
Caractéristiques: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable
, InferTypeOpInterface
, NoMemoryEffect (MemoryEffectOpInterface)
Effets: MemoryEffects::Effect{}
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
value | ::mlir::ElementsAttr | Attribut de vecteur/tenseur constant |
Résultats :
Résultat | Description |
---|---|
output |
Tensor de n'importe quel type de valeurs |
sdy.data_flow_edge
(sdy::DataFlowEdgeOp)
Opération de bord de flux de données.
Syntaxe :
operation ::= `sdy.data_flow_edge` $input (`sharding````=``` $sharding^)? attr-dict `:` type($result)
Un bord de flux de données d'une opération X définit un pont entre un ensemble de sources (chacune est un opérande de X ou un opérande du terminateur de bloc de X) et un ensemble de cibles (chacune est un résultat de X ou un argument de bloc de X), de sorte que toutes les sources et cibles doivent être fractionnées de la même manière.
Une opération peut comporter plusieurs arêtes de flux de données qui sont orthogonales les unes aux autres.
Exemple :
y_0, ..., y_n = while (x_0, ..., x_n)
((pred_arg_0,... , pred_arg_n) { ... })
((body_arg_0,..., body_arg_n) {
...
return return_value_0, ..., return_value_n
})
Alors que l'opération comporte n arêtes de flux de données, la première arête du flux de données se situe entre les sources x_i
, return_value_i
et les cibles y_i
, pred_arg_i
, body_arg_i
.
Un sdy.data_flow_edge
prend en entrée la cible racine d'un bord (il peut s'agir de n'importe quelle cible, mais de préférence d'un résultat d'opération plutôt que d'un argument de bloc), qui ne doit pas avoir d'autre utilité. Cette opération n'est pas pure, car elle peut accepter une entrée qui n'avait initialement aucune utilité.
sdy.data_flow_edge
contient également un fractionnement facultatif pour toutes les cibles du bord. Ce fractionnement doit être mis à jour au lieu du fractionnement des cibles (s'il peut être associé) lors de la propagation. Cela est utile lorsqu'une opération comporte de nombreuses arêtes, car il est beaucoup plus efficace de:
- se propagent séparément dans chaque arête.
- mettez à jour le fractionnement de chaque arête séparément au lieu de toutes les cibles à la fois (par exemple, une opération ne comporte qu'un seul
TensorShardingPerValueAttr
immuable pour les fractionnements de résultats). - ajoutez chaque arête à la liste de travail séparément lorsque le fractionnement d'une source a changé.
La propagation propage les fractionnements entre toutes les sources et cibles d'un sdy.data_flow_edge
comme s'il s'agissait d'une opération régulière avec les sources comme opérandes et les cibles comme résultats, et une identité sdy.op_sharding_rule
. Cela signifie que la propagation avant va des sources aux cibles, et que la rétropropagation va des cibles aux sources.
Nous n'autorisons pas l'entrée d'un sdy.data_flow_edge
à être définie par une opération SdyDialect
. Nous pouvons donc supposer qu'elle est définie par une opération dont l'attribut sdy.sharding
n'est pas enregistré.
Caractéristiques: SameOperandsAndResultType
Interfaces: InferTypeOpInterface
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
sharding | ::mlir::sdy::TensorShardingAttr | Segmentation des Tensors |
Opérandes:
Opérande | Description |
---|---|
input |
de valeurs de n'importe quel type |
Résultats :
Résultat | Description |
---|---|
result |
de valeurs de n'importe quel type |
sdy.manual_computation
(sdy::ManualComputationOp)
Opération de parallélisme multi-appareil avec des collectifs manuels
Syntaxe :
operation ::= `sdy.manual_computation` `(`operands`)`
`in_shardings````=```custom<StrippedTensorShardingPerValueAttr>($in_shardings)
`out_shardings````=```custom<StrippedTensorShardingPerValueAttr>($out_shardings)
`manual_axes````=```$manual_axes
custom<SingleBlockRegionNoBlockId>($body)
attr-dict
`:`
functional-type(operands, results)
Accédez à une région écrite en termes de code local par appareil avec des collectifs explicites, où les formes logiques correspondent aux formes de tampon physiques locales par appareil et les collectifs correspondent exactement à la communication physique entre les appareils.
Le corps est localisé par les champs manuels_axes. La propagation se produira à travers le corps sur toutes les axes libres (celles qui ne figurent pas dans la liste "manual_axes").
Caractéristiques: IsolatedFromAbove
, RecursiveMemoryEffects
, SingleBlockImplicitTerminator<ReturnOp>
, SingleBlock
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
in_shardings | ::mlir::sdy::TensorShardingPerValueAttr | Segmentation des Tensors par opérande/résultat d'une opération |
out_shardings | ::mlir::sdy::TensorShardingPerValueAttr | Segmentation des Tensors par opérande/résultat d'une opération |
manual_axes | ::mlir::sdy::ManualAxesAttr |
Opérandes:
Opérande | Description |
---|---|
tensors |
Variadique de tensor classé de valeurs de tout type |
Résultats :
Résultat | Description |
---|---|
results |
Variadique de tensor classé de valeurs de tout type |
sdy.mesh
(sdy::MeshOp)
Maillage nommé
Syntaxe :
operation ::= `sdy.mesh` $sym_name `=` $mesh attr-dict
Définit un nouveau maillage nommé. Tous les maillages d'un module doivent avoir le même nombre d'appareils (à l'exception des maillages avec un seul device_id).
Le maillage est une opération Symbol
qui apparaît dans le SymbolTable
du module et peut être référencée par son name
.
Caractéristiques: HasParent<ModuleOp>
Interfaces: Symbol
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
sym_name | ::mlir::StringAttr | attribut de chaîne |
mesh | ::mlir::sdy::MeshAttr | Maillage des axes et liste des appareils |
sdy.named_computation
(sdy::NamedComputationOp)
Opération de calcul nommée
Syntaxe :
operation ::= `sdy.named_computation` `<`$name`>` `` `(` $operands `)`
(`in_shardings````=```custom<StrippedTensorShardingPerValueAttr>($in_shardings)^)?
(`out_shardings````=```custom<StrippedTensorShardingPerValueAttr>($out_shardings)^)?
custom<SingleBlockRegionNoBlockId>($body)
attr-dict
`:` functional-type($operands, results)
Regroupe un calcul, c'est-à-dire un bloc d'opérations, et lui donne un nom. La propagation s'effectue dans/hors de la région comme si tout était intégré.
Cela peut être utilisé pour gérer la propagation via des instructions d'appel vers d'autres fonctions. Tous les utilisateurs de Shardy doivent écrire un passage d'importation/d'exportation qui convertit leurs opérations d'appel en opérations sdy.named_computation
, en dupliquant/copiant le corps de la fonction appelée dans le corps de la named_computation
.
Le type de chaque argument de bloc et des valeurs renvoyées dans la région doit être le même que le type des opérandes et le type de résultats de l'opération.
Exemple :
%1 = sdy.named_computation<"foo">(%0) (%arg1: tensor<16x32xf32>) {
sdy.return %arg1 : tensor<16x32xf32>
} : (tensor<16x32xf32>) -> tensor<16x32xf32>
Caractéristiques: IsolatedFromAbove
, RecursiveMemoryEffects
, RecursivelySpeculatableImplTrait
, SingleBlockImplicitTerminator<ReturnOp>
et SingleBlock
Interfaces: ConditionallySpeculatable
, ShardableDataFlowOpInterface
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
name | ::mlir::StringAttr | attribut de chaîne |
in_shardings | ::mlir::sdy::TensorShardingPerValueAttr | Segmentation des Tensors par opérande/résultat d'une opération |
out_shardings | ::mlir::sdy::TensorShardingPerValueAttr | Segmentation de tensor par opérande/résultat d'une opération |
Opérandes:
Opérande | Description |
---|---|
operands |
variadique de n'importe quel type |
Résultats :
Résultat | Description |
---|---|
"unnamed" | variadique de n'importe quel type |
sdy.propagation_barrier
(sdy::PropagationBarrierOp)
Opération de barrière de propagation
Syntaxe :
operation ::= `sdy.propagation_barrier` $input `allowed_direction````=```$allowed_direction attr-dict `:` type($input)
Cette opération fonctionne comme une opération d'identité, en affichant la même valeur qu'elle a prise en entrée. Toutefois, en termes de propagation, cela ne permet qu'à la propagation de s'écouler dans une certaine direction.
Cela empêche la propagation des segmentations entre les utilisations du résultat de l'opération de barrière et son opérande.
FORWARD
signifie que les fractionnements ne peuvent passer que de l'opérande au résultat.BACKWARD
signifie que les segmentations ne peuvent circuler que du résultat vers l'opérande.NONE
signifie qu'aucun fractionnement ne peut se propager via cette opération.- Vous ne pouvez pas spécifier
BOTH
, car cette opération serait redondante.
Caractéristiques: AlwaysSpeculatableImplTrait
, Elementwise
, SameOperandsAndResultType
Interfaces: ConditionallySpeculatable
, InferTypeOpInterface
, NoMemoryEffect (MemoryEffectOpInterface)
Effets: MemoryEffects::Effect{}
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
allowed_direction | ::mlir::sdy::PropagationDirectionAttr | énumération de la direction de propagation |
Opérandes:
Opérande | Description |
---|---|
input |
tenseur classé de valeurs de n'importe quel type |
Résultats :
Résultat | Description |
---|---|
result |
Tensor classé de n'importe quelle valeur de type |
sdy.reshard
(sdy::ReshardOp)
Répartitionne un tenseur dans un autre schéma de partitionnement.
Syntaxe :
operation ::= `sdy.reshard` $input $sharding attr-dict `:` type($result)
Répartitionne le tenseur d'entrée avec la répartition spécifiée, qui est différente de la répartition existante du tenseur d'entrée.
ShardingConstraintOp et ReshardOp associent un fractionnement à un tenseur. Leur durée de vie est la suivante:
- Avant la propagation du fractionnement, ShardingConstraintOp est ajouté par les utilisateurs.
- La propagation de la segmentation consomme ShardingConstraintOp. Il n'y a pas de ShardingConstraintOp dans les résultats de la propagation de segmentation. À la place, ReshardOp peut être ajouté si nécessaire.
- Un partitionneur convertit un ReshardOp en opération collective (ou opération d'identité). Les résultats du partitionneur ne doivent pas contenir de ReshardOp.
// TODO(b/331680067). Ajout d'un modèle de canonisation pour supprimer les opérations de reshard redondantes.
Caractéristiques: AlwaysSpeculatableImplTrait
, Elementwise
, SameOperandsAndResultType
Interfaces: ConditionallySpeculatable
, InferTypeOpInterface
, NoMemoryEffect (MemoryEffectOpInterface)
Effets: MemoryEffects::Effect{}
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
sharding | ::mlir::sdy::TensorShardingAttr | Segmentation des Tensors |
Opérandes:
Opérande | Description |
---|---|
input |
tenseur de valeurs de n'importe quel type |
Résultats :
Résultat | Description |
---|---|
result |
Tensor de n'importe quel type de valeurs |
sdy.return
(sdy::ReturnOp)
L'opération sdy.return
met fin aux régions associées aux opérations basées sur la région sdy
et à toute autre opération basée sur la région Shardy. Elle est variable: elle prend comme arguments une liste de valeurs dont les types peuvent être n'importe quel type (mais du même genre, par exemple AnyTensor
) et peut donc être réutilisée à différents niveaux de la pile IR de Shardy.
Syntaxe :
operation ::= `sdy.return` attr-dict ($results^ `:` type($results))?
Caractéristiques: AlwaysSpeculatableImplTrait
, Terminator
Interfaces: ConditionallySpeculatable
, NoMemoryEffect (MemoryEffectOpInterface)
Effets: MemoryEffects::Effect{}
Opérandes:
Opérande | Description |
---|---|
results |
variadique de n'importe quel type |
sdy.sharding_constraint
(sdy::ShardingConstraintOp)
Contraint un tenseur au fractionnement spécifié
Syntaxe :
operation ::= `sdy.sharding_constraint` $input $sharding attr-dict `:` type($result)
Associe une segmentation à un Tensor intermédiaire (par exemple, le résultat d'une fonction matmul) pour indiquer que c'est ainsi que ce Tensor, ou un sous-ensemble de ses utilisations, doit être segmenté.
Si le fractionnement comporte des dimensions ouvertes et des axes non contraints, cela signifie que le tenseur peut être fractionné davantage selon les dimensions ouvertes.
Cette opération peut soit:
- Ne pas être utilisé (dangling) : cela signifie que le fractionnement associé est la façon dont le tenseur d'entrée lui-même doit être fractionné.
- Avoir des utilisations : cela signifie que le partitionnement associé est la façon dont les utilisations de l'opération de contrainte de partitionnement doivent être partitionnées, tandis que d'autres utilisations du tenseur d'entrée peuvent avoir un partitionnement différent (si le tenseur d'entrée n'a pas d'autres utilisations, le comportement est le même que dans le cas où il n'y a pas d'utilisations).
Caractéristiques: Elementwise
, SameOperandsAndResultType
Interfaces: InferTypeOpInterface
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
sharding | ::mlir::sdy::TensorShardingAttr | Segmentation des Tensors |
Opérandes:
Opérande | Description |
---|---|
input |
tenseur de valeurs de n'importe quel type |
Résultats :
Résultat | Description |
---|---|
result |
Tensor de n'importe quel type de valeurs |
sdy.sharding_group
(sdy::ShardingGroupOp)
Opération de groupe de fractionnement
Syntaxe :
operation ::= `sdy.sharding_group` $input `group_id````=```$group_id attr-dict `:` type($input)
Cette opération fournit une interface permettant d'attribuer des tenseurs à des groupes de fractionnement (groupes de tenseurs qui devront avoir des fractionnements identiques). Lors de la propagation, dès qu'un élément de groupe est partitionné, tous les autres membres sont partitionnés exactement de la même manière. Cette opération prend l'ID de groupe d'arguments et ne renvoie aucun résultat, mais modifie plutôt la représentation du groupe de fractionnement interne pour ajouter le tenseur d'entrée au groupe avec l'ID donné.
Attributs :
Attribut | Type de MLIR | Description |
---|---|---|
group_id | ::mlir::IntegerAttr | Attribut d'entier non signé de 64 bits |
Opérandes:
Opérande | Description |
---|---|
input |
tenseur classé de valeurs de n'importe quel type |
Attributs
AxisRefAttr
Référence à un axe complet ou à un sous-axe fractionné
Syntaxe :
#sdy.axis_ref<
::llvm::StringRef, # name
SubAxisInfoAttr # sub_axis_info
>
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
nom | ::llvm::StringRef |
nom |
sub_axis_info | SubAxisInfoAttr |
DimMappingAttr
Liste des indices de facteur pour une dimension
Tous les indices de facteur doivent être compris dans la plage [0, num_factors) et une liste vide indique qu'il s'agit d'un mappage nul (analysé/imprimé avec *
), c'est-à-dire que la dimension n'est mappée sur aucun facteur.
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
factor_indices | ::llvm::ArrayRef<int64_t> |
DimensionShardingAttr
Division des dimensions
Liste des noms d'axes sur lesquels diviser une dimension de tenseur, de l'axe principal à l'axe secondaire, un booléen indiquant si la dimension peut être divisée davantage et un entier facultatif indiquant la priorité de ce fractionnement de dimension, qui sera respecté lors de la propagation du fractionnement. Les priorités proviennent des annotations de fractionnement des utilisateurs. Une valeur inférieure indique une priorité plus élevée. La priorité la plus élevée est utilisée lorsque la priorité est manquante dans l'annotation.
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
axes | ::llvm::ArrayRef<AxisRefAttr> |
liste des références d'axe |
is_closed | bool |
|
priorité | std::optional<int64_t> |
ManualAxesAttr
Syntaxe :
#sdy.manual_axes<
::llvm::ArrayRef<StringAttr> # value
>
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
valeur | ::llvm::ArrayRef<StringAttr> |
MeshAttr
Maillage des axes et liste des appareils
Syntaxe :
#sdy.mesh<
::llvm::ArrayRef<MeshAxisAttr>, # axes
::llvm::ArrayRef<int64_t> # device_ids
>
Une maille est une liste d'axes et une liste facultative d'ID d'appareils spécifiant l'ordre des appareils.
Si la liste des axes est vide, le maillage comporte une taille d'axe implicite non nommée de 1. Dans ce cas, si aucune liste d'ID d'appareils n'est fournie, la liste implicite d'ID d'appareils est [0]. Si une liste d'ID d'appareils est fournie, elle doit contenir un entier unique de n'importe quelle valeur non négative. C'est ce que nous appelons le cas de segmentation maximale.
Pour tous les cas de partitionnement non maximal, si une liste d'ID d'appareil est spécifiée, le produit des tailles d'axe doit correspondre au nombre d'appareils. Si aucune liste d'ID d'appareil n'est spécifiée, la liste d'ID d'appareil implicite est iota(product(axes)). Pour simplifier, nous n'autorisons pas non plus de spécifier une liste d'ID d'appareil identique à iota(product(axes)). Dans ce cas, une liste d'ID d'appareil ne doit pas être spécifiée.
Voici quelques exemples de maillages:
- Un maillage vide représente un maillage d'espace réservé pouvant être remplacé lors de la propagation: <[]>
- Une maille avec une axe sans nom et un ID d'appareil explicite, qui est généralement utilisé pour représenter le fractionnement maximal: <[], device_ids=[3]>
- Maillage à deux axes et ID d'appareil implicites iota(6) : <["a"=2, "b"=3]>
- Une maille avec deux axes et des ID d'appareil explicites spécifiant l'ordre des appareils: <["a"=3, "b"=2], device_ids=[0, 2, 4, 1, 3, 5]>
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
axes | ::llvm::ArrayRef<MeshAxisAttr> |
|
device_ids | ::llvm::ArrayRef<int64_t> |
MeshAxisAttr
Axe nommé dans un maillage
Syntaxe :
#sdy.mesh_axis<
::llvm::StringRef, # name
int64_t # size
>
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
nom | ::llvm::StringRef |
nom |
taille | int64_t |
OpShardingRuleAttr
Spécifie comment une opération peut être partitionnée.
Syntaxe :
#sdy.op_sharding_rule<
::llvm::ArrayRef<int64_t>, # factor_sizes
::llvm::ArrayRef<TensorMappingAttr>, # operand_mappings
::llvm::ArrayRef<TensorMappingAttr>, # result_mappings
bool # is_custom_rule
>
Une règle de segmentation spécifie comment une opération peut être partitionnée en fonction de différentes propriétés de l'opération : attributs, forme des opérandes, forme des résultats, etc. Par exemple :
%0 = stablehlo.add %arg0, %arg1 {
sdy.sharding_rule = #sdy.op_sharding_rule<
([i, j],[i, j])->([i, j])
{i=8, j=8}>
} : tensor<8x8xf32>
%1 = stablehlo.dot_general %arg2, %arg3, contracting_dims = [1] x [0] {
sdy.sharding_rule = #sdy.op_sharding_rule<
([i, k],[k, j])->([i, j])
{i=8, j=16, k=8}>
}: (tensor<8x8xf32>, tensor<8x16xf32>) -> tensor<8x16xf32>
Notez que nous autorisons les facteurs de taille 1, même s'ils ne peuvent pas être partitionnés. Cela est principalement pour des raisons de complétude, car de nombreuses opérations, telles que les opérations ponctuelles, ont des dimensions de taille 1 qui correspondent entre les opérandes et les résultats.
is_custom_rule
indique s'il s'agit d'une règle définie par un utilisateur pour une opération stablehlo.custom_call
. Le partitionneur ne sait pas comment partitionner ces opérations. Un utilisateur doit donc lui indiquer comment procéder. S'il s'agit d'une règle personnalisée, elle est toujours conservée et jamais supprimée. is_custom_rule
ne peut être défini sur "true" que pour les opérations stablehlo.custom_call
.
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
factor_sizes | ::llvm::ArrayRef<int64_t> |
|
operand_mappings | ::llvm::ArrayRef<TensorMappingAttr> |
|
result_mappings | ::llvm::ArrayRef<TensorMappingAttr> |
|
is_custom_rule | bool |
SubAxisInfoAttr
Informations sur la dérivée de ce sous-axe de l'axe complet
Syntaxe :
#sdy.sub_axis_info<
int64_t, # pre_size
int64_t # size
>
Lors de la division d'un axe complet en n sous-axes, celui-ci est remodelé en [k_1,...,k_n], et le n-ième sous-axe peut être exprimé par le produit de toutes les tailles d'axe situées à sa gauche m=prod(k_1,...,k_(i-1))
(également appelée prétaille) et de la taille k_i. Par conséquent, l'attribut sub-axis-info contient ces deux nombres et est indiqué comme suit: (m)k
pour la pré-taille m et la taille k.
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
pre_size | int64_t |
|
taille | int64_t |
TensorMappingAttr
Mappages de facteurs pour chaque dimension d'un tenseur.
Syntaxe :
#sdy.tensor_mapping<
::llvm::ArrayRef<DimMappingAttr> # dim_mappings
>
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
dim_mappings | ::llvm::ArrayRef<DimMappingAttr> |
TensorShardingAttr
Segmentation de tenseurs
Syntaxe :
#sdy.sharding<
::mlir::Attribute, # mesh_or_ref
::llvm::ArrayRef<DimensionShardingAttr>, # dim_shardings
::llvm::ArrayRef<AxisRefAttr> # replicated_axes
>
Une segmentation de Tensor est liée à un maillage spécifique et ne peut référencer que les noms d'axe de ce maillage. Les fractionnements de dimension nous indiquent, pour chaque dimension du tenseur, le long desquels axes (ou sous-axes) il est fractionné de majeur à mineur. Tous les autres axes qui ne fractionnent pas une dimension sont répliqués implicitement ou explicitement (s'ils figurent dans la liste des axes répliqués).
Le maillage auquel ce fractionnement est lié peut être spécifié par un nom de symbole, en référence à un symbole MeshOp
correspondant ou à un MeshAttr
intégré.
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
mesh_or_ref | ::mlir::Attribute |
Attribut de maillage ou attribut de référence de symbole de maillage plat |
dim_shardings | ::llvm::ArrayRef<DimensionShardingAttr> |
|
replicated_axes | ::llvm::ArrayRef<AxisRefAttr> |
liste des références d'axe |
TensorShardingPerValueAttr
Segmentation des Tensors par opérande/résultat d'une opération
Syntaxe :
#sdy.sharding_per_value<
::llvm::ArrayRef<TensorShardingAttr> # shardings
>
Paramètres :
Paramètre | Type C++ | Description |
---|---|---|
segmentations | ::llvm::ArrayRef<TensorShardingAttr> |
Enums
PropagationDirection
énumération de la direction de propagation
Étuis :
Symbole | Valeur | Chaîne |
---|---|---|
AUCUN | 0 |
AUCUN |
FORWARD | 1 |
FORWARD |
BACKWARD | 2 |
BACKWARD |
TOUS LES MODÈLES | 3 |
TOUS LES MODÈLES |