Sharding indipendente dal dialetto

L'obiettivo a lungo termine è rendere Shardy un componente completamente autonomo, in grado di lavorare con qualsiasi dialetto MLIR. Attualmente, Shardy dipende direttamente da StableHLO, ma stiamo facendo progressi verso la rimozione di questa dipendenza tramite varie astrattizioni e interfacce per rendere Shardy più flessibile.

Regole di suddivisione in parti

Una regola di sharding codifica il modo in cui propaghiamo un'operazione. Poiché ora Shardy dipende da StableHLO, definisce le regole di sharding per ogni operazione stablehlo. Inoltre, Shardy fornisce il comando ShardingRuleOpInterface che può essere utilizzato dai proprietari di dialetti nelle loro operazioni per definire le regole di sharding per le proprie operazioni. Finché un'operazione implementa questa interfaccia, Shardy potrà propagarsi al suo interno.

def ShardingRuleOpInterface : OpInterface<"ShardingRuleOpInterface"> {
  let methods = [
    InterfaceMethod<
      /*desc=*/[{
        Returns the sharding rule of the op.
      }],
      /*retType=*/"mlir::sdy::OpShardingRuleAttr",
      /*methodName=*/"getShardingRule"
    >,
  ];
}

Operazioni di flusso di dati

Alcune operazioni, ad esempio quelle basate su regioni, richiedono un approccio diverso in cui le regole di sharding, che descrivono solo la corrispondenza tra le dimensioni in tutti gli operandi e i risultati, non sono sufficienti. In questi casi, Shardy definisce un ShardableDataFlowOpInterface in modo che i proprietari dei dialetti possano descrivere la propagazione dello sharding tramite le loro operazioni. Questa interfaccia fornisce metodi per recuperare le origini e le destinazioni di ogni angolo del flusso di dati tramite il relativo proprietario, nonché per recuperare e impostare gli shard dei proprietari di angolo.

def ShardableDataFlowOpInterface :
    OpInterface<"ShardableDataFlowOpInterface"> {
  (get|set)BlockArgumentEdgeOwnerShardings;
  (get|set)OpResultEdgeOwnerShardings;
  getBlockArgumentEdgeOwners;
  getOpResultEdgeOwners;
  getEdgeSources;
  // ...
}

Consulta anche Operazioni di flusso di dati per una panoramica generale di come gestiamo le operazioni di flusso di dati.

Interfacce non ancora implementate

In futuro verranno aggiunte altre interfacce e caratteristiche per rendere Shardy più flessibile e indipendente dal dialetto. Li elenchiamo di seguito.

Suddivisione costante

La maggior parte dei programmi tensori in MLIR ha un'istanza di una costante che viene riutilizzata da qualsiasi operazione che ne ha bisogno. Questo ha senso quando la costante necessaria è la stessa. Tuttavia, per uno sharding ottimale di un programma, vorremmo consentire a ogni utilizzo di una costante di avere il proprio sharding e di non essere influenzato dal modo in cui altre operazioni utilizzano la costante.

Ad esempio, nella figura seguente, se add è suddiviso in parti, questo non dovrebbe influire sul modo in cui divide e subtract (in parti diverse del calcolo) sono suddivisi in parti.

Suddivisione costante

Si tratta di una dipendenza falsa: poiché le costanti sono economiche, non esiste una dipendenza reale tra le operazioni che utilizzano la stessa costante. Di conseguenza, gli utenti possono decidere lo sharding delle operazioni costanti (e simili). Ogni utilizzo di questa costante può avere un'organizzazione in parti diverse che può propagarsi in modo isolato alla propria copia del sottocalcolo costante.

Per farlo, gli utenti di Shardy devono definire: - Un passaggio your_dialect.constant -> sdy.constant; - Un tratto sdy::ConstantLike, ad esempio iota; - Un tratto mlir::Elementwise per operazioni elementari come add e multiply; - Un sdy::ConstantFoldable per operazioni come slice/broadcast. Tecnicamente, queste operazioni possono essere calcolate in fase di compilazione, se tutti i loro operandi/risultati sono costanti.

Priorità operative

In GSPMD, le operazioni elementari vengono propagate per prime, seguite da operazioni come matmul. In Shardy, vogliamo consentire agli utenti di impostare le proprie priorità di operazione, poiché non siamo a priori a conoscenza dei loro dialetti. Pertanto, gli chiederemo di passare un elenco di operazioni nell'ordine in cui vuole che Shardy le propaghi.

La figura seguente mostra come le priorità vengono utilizzate in GSPMD per propagare le operazioni nell'ordine corretto.

Op Priorities. Leggi il documento GSPMD per scoprire perché le priorità operative sono importanti

Consulta il documento GSMPD per una discussione sul perché le priorità op sono importanti.

Essere indipendente dal dialetto

Purché tu implementi le interfacce, i tratti e i pass precedenti, Shardy potrà lavorare per il tuo dialetto. Stiamo lavorando per rendere Shardy più flessibile e indipendente dal dialetto, quindi continua a seguirci per altri aggiornamenti.