Architecture de réutilisation M×N dans CANN : Le rôle de ascend-boost-comm

L'écosystème CANN (Compute Architecture for Neural Networks) comprend plus de 50 dépôts, chacun hébergeant des dizaines d'opérateurs. Historiquement, ces dépôts partageaient des besoins redondants : la gestion des partitions de données pour les opérateurs de mémoire, la détection de topologie pour les communications, ou encore l'inférence de forme (shape inference) pour les opérateurs de fusion. Sans une couche de mutualisation, chaque dépôt corrigerait ses propres bugs ou optimiserait ses performances de manière isolée, entraînant une fragmentation massive du code.

Le projet ascend-boost-comm a été conçu pour transformer cette complexité en un modèle de réutilisation M×N. Plutôt que d'avoir M dépôts réimplémentant N fois les mêmes fonctionnalités, ascend-boost-comm agit comme une plateforme intermédiaire fournissant des briques de base : découpage de données, perception de la topologie matérielle, gestion du cycle de vie et partage d'état inter-opérateurs.

L'impératif d'une couche middleware

Considérons le partitionnement 2D d'un tenseur d'entrée. Dans une architecture classique, trois dépôts distincts (mathématiques, réseaux de neurones, transformeurs) implémenteraient leur propre logique de tiling. Avec ascend-boost-comm, cette logique est centralisée. Voici comment la structure de calcul est unifiée :

// Dans ascend-boost-comm/tiling/grid_orchestrator.h
// Interface partagée par l'ensemble des dépôts d'opérateurs

template <size_t RANK>
struct PartitionPlan {
    int64_t grid_counts[RANK];      // Nombre de blocs par dimension
    int64_t block_dims[RANK];       // Dimensions de chaque bloc
    int64_t tail_dims[RANK];        // Dimensions du bloc résiduel

    static PartitionPlan compute_layout(
        const std::array<int64_t, RANK>& full_shape,
        const std::array<int64_t, RANK>& l1_limit,
        AlignmentMode mode
    ) {
        PartitionPlan plan;
        for (size_t i = 0; i < RANK; ++i) {
            int64_t max_unit = l1_limit[i];
            int64_t total_size = full_shape[i];

            plan.grid_counts[i] = (total_size + max_unit - 1) / max_unit;
            plan.block_dims[i] = max_unit;

            int64_t rem = total_size - (plan.grid_counts[i] - 1) * max_unit;
            // Gestion de l'alignement spécifique au matériel (ex: Cube 16-byte)
            if (mode == FORCE_CUBE_ALIGN && (rem % 16 != 0)) {
                plan.tail_dims[i] = ((rem + 15) / 16) * 16;
            } else {
                plan.tail_dims[i] = rem;
            }
        }
        return plan;
    }
};

Grâce à cette abstraction, l'appel dans un dépôt spécifique se résume à une ligne, garantissant que toute correction de bug dans l'algorithme de découpage profite instantanément à tous les opérateurs du framework.

Les cinq piliers technologiques

1. Moteur de fragmentation de données

Au-delà du simple découpage, ce module gère les conversions de layout (NCHW vers NHWC, RowMajor vers ColMajor). Il génère un plan d'exécution optimal incluant les calculs de foulée (strides) :

#include "ascend-boost-comm/tiling/data_fragmenter.h"

auto fragment_task = DataFragmenter::NewBuilder()
    .SetInputShape({N, C, H, W})
    .SetFormat(FORMAT_NCHW, FORMAT_NHWC)
    .SetBufferConstraint(L1_SIZE)
    .Generate();

2. Service de découverte de topologie

Pour les opérateurs distribués (AllReduce, AllGather), il est crucial de connaître la structure physique des NPU. ascend-boost-comm expose une cartographie unifiée :

#include "ascend-boost-comm/topology/hardware_map.h"

auto& hw_map = HardwareMap::GetInstance();
auto topology = hw_map.ScanCluster();

// Analyse de la connectivité entre deux nœuds
auto link_info = topology.GetLinkAttribute(node_a, node_b);
if (link_info.type == LinkType::HCCS) {
    // Utilisation d'un algorithme optimisé pour la bande passante élevée
    return Strategy::Aggressive;
}

3. Orchestration du cycle de vie des opérateurs

Le framework prend en charge la séquence standard : InferShape → Tiling → Memory Allocation → Kernel Dispatch. L'objectif est que le développeur ne se concentre que sur le noyau de calcul (Compute Kernel).

#include "ascend-boost-comm/runtime/op_executor.h"

class CustomMulOp : public OperatorBase {
public:
    ShapeDescriptor DeriveOutputShape(const ShapeList& inputs) override { ... }
    TaskBinding ResolveKernel(const Context& ctx) override { ... }
    // La gestion de la mémoire et des flux asynchrones est déléguée au middleware
};

4. Registre d'état global

Certains paramètres, comme les facteurs d'échelle pour la précision mixte (Loss Scaling) ou les pools de mémoire pour le cache KV (Key-Value), doivent être accessibles par plusieurs opérateurs sans être passés explicitement dans chaque signature de fonction.

#include "ascend-boost-comm/context/shared_registry.h"

// Définition d'une valeur globale par un module d'initialisation
SharedRegistry::Store<float>("dynamic_loss_scale", 1024.0f);

// Récupération par un opérateur de normalisation loin dans le graphe
float current_scale = SharedRegistry::Load<float>("dynamic_loss_scale");

5. Diagnostics et Profiling intégrés

Le middleware injecte automatiquement des points de mesure entre chaque phase du cycle de vie, permettant d'identifier si un goulot d'étranglement se situe au niveau de l'allocation mémoire, du calcul de tiling ou de l'exécution GPU/NPU proprement dite.

#include "ascend-boost-comm/diagnostics/trace_monitor.h"

TraceMonitor monitor("FlashAttentionImpl");
monitor.StartCapture();
// ... exécution ...
// Sortie automatique des métriques par phase : InferShape, Tiling, Launch.

Hiérarchie des dépendances

Dans l'architecture CANN, ascend-boost-comm se situe au-dessus des composants de base (opbase) mais en dessous des bibliothèques spécialisées :

  • Niveau 0 : opbase (Tenseurs de base, types de données).
  • Niveau 1 : ascend-boost-comm (Plateforme commune).
  • Niveau 2 : ops-nn, ops-math, hccl (Bibliothèques de communication et d'opérateurs).
  • Niveau 3 : GE (Graph Engine) et compilateurs de graphes.

En centralisant ces services, CANN évite la redondance structurelle. Là où d'autres frameworks s'appuient sur des revues de code manuelles pour maintenir la cohérence entre les dépôts, Ascend impose une cohérence logicielle par construction via cette couche middleware.

Étiquettes: Ascend cann middleware Deep-Learning-Optimization C++

Publié le 7 octobre à 09h59