# Communications réseau pour apprentissage automatique dans un environnement distribué, hétérogène et volatile

Joachim Robert

► To cite this version:

Joachim Robert. Communications réseau pour apprentissage automatique dans un environnement distribué, hétérogène et volatile. Calcul parallèle, distribué et partagé [cs.DC]. 2025. hal-05261956

HAL Id: hal-05261956

https://inria.hal.science/hal-05261956v1

Submitted on 17 Sep 2025

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

<figure><img src="image_1.png" /></figure>

Distributed under a Creative Commons Attribution 4.0 International License
INRIA
EQUIPE TOPAL

ENSEIRB-MATMECA
FILIÈRE INFORMATIQUE

# RAPPORT DE STAGE

JOACHIM ROBERT

COMMUNICATIONS RÉSEAU POUR APPRENTISSAGE AUTOMATIQUE DANS UN ENVIRONNEMENT DISTRIBUÉ, HÉTÉROGÈNE ET VOLATILE

TUTEURS :

ENSEIRB-MATMECA : D.LAPOIRE
INRIA : P.SWARTVAGHER, T.HÉRAULT

Stage soutenu le : 11/09/2025
Table des matières

<table><tr><td>1</td><td>Inria et l'équipe-projet TOPAL</td><td>2</td></tr><tr><td>2</td><td>Résumé du sujet de stage</td><td>2</td></tr><tr><td>2.1</td><td>Contexte</td><td>3</td></tr><tr><td>2.2</td><td>Les enjeux et objectifs globaux</td><td>3</td></tr><tr><td>3</td><td>Études préliminaires</td><td>4</td></tr><tr><td>3.1</td><td>Phases d'entraînement en Machine Learning</td><td>4</td></tr><tr><td>3.2</td><td>Parallélisme de données</td><td>5</td></tr><tr><td>3.3</td><td>Algorithmes de All-Reduce</td><td>7</td></tr><tr><td>3.4</td><td>Grid5000</td><td>10</td></tr><tr><td>3.5</td><td>Premiers résultats</td><td>10</td></tr><tr><td>4</td><td>Étude de bibliothèques d'opérations collectives</td><td>12</td></tr><tr><td>4.1</td><td>Traçage de NCCL</td><td>12</td></tr><tr><td>4.2</td><td>PCCL</td><td>14</td></tr><tr><td>4.3</td><td>Traçage de PCCL</td><td>14</td></tr><tr><td>4.4</td><td>Recursive-Doubling</td><td>16</td></tr><tr><td>4.5</td><td>Simulation et Résultats</td><td>20</td></tr><tr><td>5</td><td>Conclusion</td><td>26</td></tr><tr><td>6</td><td>Annexe</td><td>27</td></tr></table>
# 1 Inria et l'équipe-projet TOPAL

Je réalise mon stage de troisième année au centre de recherche Inria de l'université de Bordeaux, au sein de l'équipe TOPAL.

## Le centre Inria

Inria, ou institut national de recherche en sciences et technologies du numérique, collabore avec les universités mais aussi les industriels pour relever les défis du numérique. Inria, c'est presque 4000 scientifiques répartis en 220 équipes sur 10 sites. Ils travaillent sur des domaines multiples en informatique et en mathématiques appliquées tels que l'informatique quantique, le calcul haute performance<fnref n="1" />, la robotique etc...

Le centre de recherche Inria de l'université de Bordeaux est localisé dans le complexe universitaire de la ville de Talence. Il est composé d'une vingtaine d'équipes, et les travaux qui y sont menés se concentrent majoritairement sur l'apprentissage automatique, les interactions homme-machine, la santé numérique ainsi que le HPC, c'est dans ce dernier domaine qu'appartient TOPAL.

Le centre accueille aussi une dizaine de startups couvrant des domaines variés dans le but d'appliquer les travaux de recherche à l'industrie.

## L'équipe-projet Topal

Dirigée par Olivier Beaumont, l'équipe TOPAL est une équipe de treize permanents et d'une douzaine de doctorants. Elle se concentre majoritairement sur la conception d'algorithmes et d'outils efficaces pour l'algèbre linéaire et tensorielle d'une part, et pour l'apprentissage d'autre part.

Pour y voir plus clair, le tableau 1 permet de mieux situer les actions de TOPAL vis-à-vis du HPC.

<table><caption>TABLE 1 – Tableau des différentes couches en HPC.</caption><tr><td>Applications (DeepLearning, Simulation)</td></tr><tr><td>Bibliothèques d'algèbre linéaire, d'algèbre tensorielle, d'apprentissage TOPAL</td></tr><tr><td>Middlewares (Interface OS-applications)</td></tr><tr><td>Sytèmes bas niveau</td></tr><tr><td>Matériel HPC</td></tr></table>

# 2 Résumé du sujet de stage

Mon stage de PFE, intitulé : "Communications réseau pour apprentissage automatique dans un environnement distribué, hétérogène et volatile", s'inscrit dans le défi CUPSELI, qui met en collaboration Inria et l'entreprise Hivenet.

<footnote n="1">1. noté HPC (high performance computing) par la suite</footnote>
## 2.1 Contexte

L'identité de **Hivenet** est basée sur l'utilisation des ressources inutilisées de matériel informatique. Cela va de l'ordinateur personnel d'un particulier, au parc informatique d'une entreprise ou d'un centre de données. Des contributeurs mettent à disposition certaines ressources qu'ils n'utilisent pas, elles deviennent alors utilisables en souscrivant aux services de **Hivenet**. Par exemple, **HiveDisk**, est une offre de stockage de données à distance. Des personnes ou entreprises laissent certains de leurs espaces de stockage (disque dur, SSD, etc...) libres d'utilisation pour d'autres. **Hivenet** s'occupe de l'accès à ce stockage à distance et garantit la sécurité des données qui y sont transférées.

Dans cette même direction de partage de ressources des utilisateurs, **Hivenet** souhaite lancer le service **HiveCompute**. Celui-ci permettrait de pouvoir partager les ressources de calculs (surtout des GPUs) inutilisées pour réaliser principalement des tâches d'entraînement et d'inférence d'applications d'intelligence artificielle. L'utilisateur demande sur une interface web d'obtenir un certain nombre de GPUs, situés sur différentes machines, et peut ensuite y accéder pour exécuter ses calculs.

**HiveCompute** n'est encore qu'aux premiers stades de développement, nous nous placerons alors à échelle réduite dans un premier temps, où les GPUs alloués seront sur des machines appartenant à un même réseau local (par exemple le réseau d'un site d'entreprise), puis nous nous dirigerons vers des GPUs géographiquement éloignés les uns des autres (un cas concret par exemple serait tous les sites d'une entreprise à l'échelle d'un pays voire même d'un continent).

## 2.2 Les enjeux et objectifs globaux

Les défis ressortant de ce projet sont multiples. La plupart proviennent du fait que l'environnement ciblé par **HiveCompute** s'éloigne d'une configuration HPC classique, celle généralement recherchée pour exécuter l'entraînement de modèles d'IA.

En effet, d'un point de vue matériel, les machines sont moins puissantes et hétérogènes puisque fournies par différents types d'utilisateurs. Les puissances de calculs d'un particulier ou d'une entreprise ne seront pas à la hauteur de celles d'un serveur de calculs d'un centre de recherche en informatique par exemple. De plus, toutes les machines disponibles sur **HiveCompute** seront interconnectées par un réseau classique, moins performant qu'un réseau HPC.

Il faut également prendre en compte que les ressources de calculs ne sont pas disponibles en permanence (par exemple, les machines sont moins disponibles en journée car les employés les utilisent) et qu'elles sont plus susceptibles de disparaître à tout moment, par exemple à cause de l'arrêt par inadvertance d'un ordinateur, une coupure d'électricité dans un quartier, une mise à jour inattendue, etc... En somme, tout type d'imprévu susceptible de couper l'accès à distance au matériel.

Enfin, utiliser des machines appartenant à différents sites géographiques crée un réseau aux performances hétérogènes. Les données transférées doivent parcourir de plus longues distances sur le réseau. De plus, cela demande de traverser
plusieurs niveaux d'équipements (carte réseau d'un ordinateur, commutateur, rou-
teur, etc...) ce qui ralentit encore plus la transmission d'informations, conduisant
à de la latence. C'est sur ce point que l'on s'est concentré durant le stage.

Ajoutées une à une, ces contraintes sont un réel défi pour lequel la quantité de littérature sur le sujet est mince, de même que l' existant est encore assez rare. Contraints par la durée de ce stage, nous nous sommes exclusivement intéressés aux communications faites lorsqu'on veut faire de l'IA de manière géo-distribuée. Il est donc attendu d'étudier les possibilités d'entraînement d'IA dans des environnements géo-distribués, de regarder en détail comment les échanges se font et de voir s'il est possible d'y apporter des optimisations.

Cette étude n’était restreinte à aucune technologie ou environnement. Nous avons pu explorer toutes les pistes qui nous paraissaient viables et intéressantes.

3 Études préliminaires

Dans le cadre de nos recherches, lorsqu'on parle d'IA, on entend surtout les algorithmes de **machine learning** et plus particulièrement ceux basés sur des **réseaux de neurones**. Les neurones sont en réalité des fonctions mathématiques dépendant de paramètres appelés *poids* qui, au cours d'un entraînement, seront ajustés de sorte que le modèle devienne de plus en plus performant. Pour cela, des données d'entraînements lui sont fournies et il va traverser plusieurs fois des phases nommées *forward pass*, *backward pass*, et *update* qui permettront d'ajuster au mieux les valeurs des poids.

Il existe de multiples manières de parcourir ces trois phases selon si l'on travaille avec un ou plusieurs GPUs. L'une d'entre elle, la **parallélisation des données**, nous intéressera plus particulièrement.

3.1 Phases d'entraînement en Machine Learning

Comme indiqué précédemment, les phases lors d'un entraînement de *machine
learning* sont au nombre de trois. On peut les retrouver sur la figure 1.

Dans un premier temps, dans la *forward pass*, les données sont fournies en
entrée du réseau de neurones. Chaque neurone applique la fonction mathématique
qui lui est associée et transmet le résultat à un ou plusieurs neurones de la couche
suivante. Après la dernière couche de neurones et donc à la fin de la *forward pass*,
on calcule une fonction de perte qui permet d'indiquer l'erreur du modèle, c'est-
à-dire à quel point ses résultats sont éloignés des valeurs attendues.

De cela, on réalise la *backward pass* où l'on applique la méthode de **rétropro-
pagation du gradient**. Cette méthode utilise le résultat de la fonction de perte
précédemment calculé et calcule le gradient de chaque poids. Il permet de savoir
quelle valeur est à donner au poids pour minimiser la fonction de perte et donc se
rapprocher le plus possible de la valeur de sortie attendue.

Enfin, la phase d'*update*, où l'on va changer la valeur de chaque paramètre selon
son gradient pour améliorer le modèle.
<figure><img src="image_2.png" /><figcaption>FIGURE 1 – Itération d'un entraînement de modèle.</figcaption></figure>

Cette succession de phases est réalisée un certain nombre de fois. Ce nombre varie selon la taille du modèle. Plus la quantité de paramètres du modèle est importante plus il faut traverser ces phases pour l'améliorer. Il faut aussi avoir une base de données beaucoup plus diversifiée pour être assuré du bon entraînement du modèle. Par exemple, les modèles LLM<fnref n="2" /> (ChatGPT, DeepSeek, Mistral etc...) pouvant comprendre et générer des textes en langage naturel ont parfois des milliards de milliards de paramètres. Ils sont entraînés sur du texte et donc nécessitent des bases de mots de taille frôlant les centaines de milliards de données. Le temps d'entraînement est alors nécessairement impacté.

Par exemple, pour entraîner le modèle DeepSeekV3 [1], 2,7 millions d'heures GPU ont été nécessaires. S'il n'avait qu'un seul GPU à leur disposition, cela équivaudrait à

$$ \frac{2,7 \times 10^6}{(24 \times 356)} \approx 316 \text{ années d'entraînement} \qquad (1) $$

Des solutions pour réduire considérablement ce genre de durée ont été pensées. Dans le cas de DeepSeekV3, le temps d'entraînement présenté au-dessus, complètement inenvisageable, a été réduit à une durée de deux mois. Pour cela, le travail a été **parallélisé**, c'est-à-dire réparti sur plusieurs GPUs au lieu d'un unique (dans notre cas d'exemple, 2048 GPUs de grande puissance<fnref n="3" />). Le parallélisme est incontournable au vue des modèles d'aujourd'hui. De plus, c'est dans les objectifs de HiveCompute que de permettre d'utiliser plusieurs GPUs partagés par des particuliers et/ou entreprises. Le parallélisme est donc incontournable dans notre contexte.

## 3.2 Parallélisme de données

On peut paralléliser un modèle de différentes manières (parallélisation de modèle, de tâches etc...), mais celle qui va nous intéresser plus particulièrement est le

<footnote n="2">2. large language model ou grands modèles de langages en français</footnote>

<footnote n="3">3. Nvidia H800</footnote>
parallélisme de données (figure 2).

Cette méthode suit le déroulement suivant :

Avant l'entraînement en lui-même, les paramètres du modèle sont recopiés à l'identique sur les GPUs qui seront utilisés. La base de données d'entraînement est divisée et répartie. Les phases de *forward pass* et de *backward pass* sont faites ainsi localement sur chaque GPU avec la partie unique des données qui lui a été attribuée.

Les données différant selon le GPU, on obtient alors des **gradients différents** pour chacun. Afin d'avoir une cohérence entre tous les GPUs, il faut que les paramètres soient les mêmes à la fin de tout itération d'entraînement. Pour cela, chaque GPU partage ses valeurs de gradients aux autres et lorsqu'il aura reçu les leurs, il agrégera l'ensemble par une opération qui est commune à tout GPU (somme ou moyenne par exemple).

Ainsi, tous auront les mêmes valeurs de gradient et à la fin de la phase d'*update* auront les mêmes paramètres, garantissant l'équivalence entre chaque GPU.

<figure><img src="image_3.png" /><figcaption>FIGURE 2 – Schéma de parallélisation des données pour l'entraînement d'un réseau de neurones.</figcaption></figure>

Le processus de partage d'informations entre GPUs et d'opération d'agrégation effectuée localement est connu sous le nom d'**All-Reduce**. Il fait partie d'un ensemble d'opérations appelé **opérations collectives** souvent utilisées en parallélisme.

La parallélisation, telle que la parallélisation des données s'est avérée être un très bon outil pour réduire les temps d'entraînements de gros modèles (cf équation 3.1). Cependant elle impose d'utiliser des ressources réseau pour que les GPUs se transmettent des informations. Or, comme le montre la figure 3, l'impact de ces communications était non-négligeable dans les temps d'entraînements globaux.
<figure><img src="image_4.png" /><figcaption>FIGURE 3 – Temps passé à communiquer lors d'entraînement de modèles avec différents algorithmes de All-Reduce utilisés (d'après [6]).</figcaption></figure>

Cet impact des communications peut différer selon le nombre de GPUs, la bande-passante de leurs cartes réseau ou bien la topologie du réseau, c'est-à-dire la façon dont les GPUs sont répartis sur le réseau. Pour pallier cela, différents algorithmes de *All-Reduce* existent et sont plus ou moins performants selon les caractéristiques dans lesquelles on se trouve pour faire notre entraînement.

Dans un contexte géo-distribué, avec des liens réseaux hétérogènes entre les différents GPUs ainsi que la topologie du réseau éloignée de celles retrouvées dans des contextes HPC, l'étude de ces algorithmes est nécessaire pour avancer dans nos recherches.

## 3.3 Algorithmes de All-Reduce

Un *All-Reduce* se déroule de la manière suivante : une opération d'agrégation, une somme, une moyenne, est effectuée sur les informations de tous les nœuds. Le résultat de l'opération devient la nouvelle information détenue par tous les nœuds. Une manière schématique pour décrire une opération de *All-Reduce* se trouve en figure 4.

<figure><img src="image_5.png" /><figcaption>FIGURE 4 – Opération de *All-Reduce*, utilisant la somme comme fonction d'agrégation.</figcaption></figure>

On voit en figure 4, que le *All-Reduce* est en réalité un ensemble d'échanges point-à-point entre les nœuds de notre réseau. C'est d'ailleurs le cas pour tout type d'opération collective.

Une première approche (figure 5) pour réaliser un *All-Reduce* serait de le réaliser en deux étapes. Une première étape où un seul nœud récupère les informations
de tous les autres et effectue la réduction (somme, moyenne etc...), opération dite de **Reduce**, puis transmet le résultat au reste du réseau (opération dite de **Broadcast**).

<figure><img src="image_6.png" /><figcaption>FIGURE 5 – *All-Reduce* par *Reduce* puis *Broadcast*.</figcaption></figure>

Dans cet exemple, trois nœuds communiquent avec le nœud opérant la réduction. Seulement, si une plus grande quantité de nœud, telle que les 2048 GPUs pour l'entraînement de DeepSeekV3, envoie en quasi-simultané ses informations au nœud 4, le réseau risque d'être très facilement saturé et un goulot d'étranglement va se créer au niveau du nœud 4. Il y aura alors de la latence ou certaines informations pourraient se perdre, risquant de ralentir conséquemment l'exécution d'un programme.

D'autres algorithmes sont donc apparus pour permettre d'exécuter un *All-Reduce* à plus grande échelle avec le minimum de perte réseau possible. L'algorithme en anneau, très utilisé dans les programmes IA, est l'un d'entre eux.

## Algorithme en anneau

On notera $p$ le nombre de nœuds impliqués dans l'algorithme.

Avant de transmettre les informations, les nœuds sont indexés (de 0 à $p-1$ par exemple) de sorte que durant tout l'algorithme le $i$-ième nœud envoie au nœud $i+1 \bmod p$. Une fois cela réalisé, les communications peuvent commencer :

1. Lors de la première itération, tout nœud $i$ envoie ses données au nœud suivant.

2. Pour les itérations suivantes, le nœud $i$ envoie les informations qu'il a reçu à l'itération précédente au nœud $i+1$. En parallèle, il réduit l'information qu'il a reçue avec celle qu'il avait déjà.

3. Au bout de $p-1$ itérations, chaque processus a reçu l'entièreté des informations et qu'il a pu réduire au fur et à mesure. Chaque processus a alors le même résultat de l'opération de réduction.

On retrouve un exemple d'exécution de l'algorithme en anneau pour quatre processus en figure 6.

En figure 6a, on retrouve la première itération de l'algorithme, où chaque processus envoie au suivant ses données. Ensuite, en figure 6b et 6c, les processus
<figure><img src="image_7.png" /><figcaption>(a) Première itération de l’alg-
rithme.</figcaption></figure>

<figure><img src="image_8.png" /><figcaption>(c) Troisième itération de l’algo-
rithme.</figcaption></figure>

<caption>(d) État des processus à la fin de
l’algorithme.</caption>

<caption>FIGURE 6 – Exécution de l’algorithme en anneau pour quatre processus.</caption>

transmettent les données qu'ils ont reçues et l'ajoutent à la somme déjà calculée
auparavant. A la toute fin de l'algorithme, figure 6d, chaque processus a bien la
somme des lettres **A**, **B**, **C** et **D**.

Cet algorithme au delà d'être facile de compréhension et d'utilisation, permet de ne pas saturer un seul nœud lors de son exécution. De plus, l'opération de réduction peut se faire en même temps que la transmission de données, réduisant la durée du All-Reduce.

En pratique, il est possible de trouver une variante à cet algorithme appelée le *Reduce-Scatter*. L'algorithme se fait en deux temps, une première phase où s'opère des échanges et des réductions sur des parties et non l'ensemble de l'information de chaque nœud. Une seconde où les nœuds s'échangent seulement des informations entre eux. Bien qu'il nécessite deux fois plus d'échanges, il a l'avantage de se pipelineer plus facilement, caractère très recherché pour améliorer les performances du *All-Reduce*.

En figure 4, les entités qui communiquent sont des nœuds. En pratique, ce sont
les processus lancés sur les GPUs qui actionnent ces communications. Dans toute
nos expériences, plusieurs GPUs par machine ont pu être sollicités, mais un seul
processus était lancé sur chaque GPU. Par la suite dans ce rapport, les **nœuds**
feront référence aux machines auxquelles les GPUs participant aux entraînements
appartiennent.

Dans notre cadre d'étude, pour étudier un *All-Reduce* lors d'un entraînement,
cela implique nécessairement l'utilisation de plusieurs GPUs sur une machine voire
plusieurs machines avec plusieurs GPUs. Il a fallu avoir accès à un grand nombre
de GPUs et répartis si possible sur plusieurs sites de France pour réaliser nos
expériences.

## 3.4 Grid5000

Il existe des plateformes, dédiées à la recherche, permettant de faire de la ré-servation de nœuds et/ou de GPUs. Elles sont généralement utilisées pour faire du HPC, du calcul distribué et de l'entraînement de modèle d'IA. Celle vers la-quelle on s'est dirigé est **Grid5000**. Cette plateforme a l'avantage d'avoir des sites répartis en France, qui nous permettra de tester l'impact de la géo-distribution sur un entraînement. De plus les sites possèdent des GPUs de toute génération, permettant de comprendre comment l'hétérogénéité d'un ensemble de machines influencent une inférence.

<figure><img src="image_9.png" /><figcaption>FIGURE 7 – Les différents sites disponibles sur Grid5000.</figcaption></figure>

Cette plateforme, alliée à nos nouvelles connaissances sur les algorithmes de machine learning, les subtilités de la parallélisation de données en IA et les algorithmes d'opérations collectives sous-jacents, nous permettent alors de faire de premiers essais pour avancer dans notre étude sur les communications lors d'entraînement de modèles IA.

## 3.5 Premiers résultats

La bibliothèque Python **PyTorch** permet la programmation de modèles d'IA ainsi que la parallélisation de leurs entraînements. Il est possible de faire de la parallélisation des données en utilisant le module *DistributedDataParallel* de **PyTorch**.

Des scripts d'exemple sont fournis permettant de tester ce module. Lors de l'étude de ceux-ci, il est apparu que plusieurs bibliothèques d'opérations collectives (opération telle que le *All-Reduce*) étaient utilisables. Il est possible de choisir *NCCL*, bibliothèque développée par NVIDIA pour ses GPUs, mais également *Gloo* quant à elle développée par Facebook.

Les résultats obtenus après avoir lancé les scripts de tests avec les deux bibliothèques sur Grid5000 <fnref n="4" /> sont disponibles en figure 8.

On remarque d'après ces premiers résultats que *NCCL* est plus performante que *Gloo*. Cela est dû au fait que *NCCL* est optimisée pour les cartes graphiques de chez

<footnote n="4">4. Expérience réalisée sur le site de Grenoble avec deux GPUs par nœud (Nvidia Tesla L40S (45 GiB)). Entraînement d'un *Transformer* (modèle à la base d'un LLM)</footnote>
<figure><img src="image_10.png" /><figcaption>FIGURE 8 – Durée d’entraînements d’un même modèle selon le nombre de nœuds sur un seul site.</figcaption></figure>

Nvidia. Bien que *Gloo* présente de moins bonnes performances, elle a l'avantage d'être utilisable sur n'importe quel type de GPU ainsi que sur des CPUs. Sa portabilité explique alors que *Gloo* soit moins performante sur des cartes Nvidia comparée à *NCCL*.

Que ce soit pour *NCCL* ou pour *Gloo*, la durée d'entraînement décroît avec l'augmentation du nombre de nœuds, confirmant une intuition que l'on pourrait avoir : plus il y a de nœuds participant à l'entraînement plus il sera rapide à réaliser. Ce premier résultat a été réalisé avec des GPUs situés sur un même site, la suite est d'étudier ce qu'il se passe sur deux sites. La figure 9 montre les durées d'entraînements du même modèle, mais cette fois-ci lorsqu'ils sont répartis sur deux sites géographiquement éloignés (Grenoble et Nancy).

Les résultats de l'expérience sur deux sites diffèrent par rapport à ceux sur un site. On voit que le passage de deux à trois nœuds se traduit par une marche sur le temps d'exécution, et non pas une simple décroissance de celui-ci. Il s'avère que durant l'expérience, le troisième et quatrième nœud se situaient sur un site différents des deux premiers. Par conséquent, on passe de communications dites intra-site (au sein d'un même site, cf figure 10) à des échanges intra-site mais aussi inter-site (lien entre deux sites différents, cf figure 10).

Cette corrélation, entre temps d'exécution qui croît malgré l'augmentation de nœuds et le passage intra-site à intra-site et inter-site, nous amène à supposer qu'en limitant le nombre de communications inter-site, cela nous permettra de réduire le temps de communication total pour la réduction des gradients.

La suite de notre étude se concentre donc à présent sur les opérations collectives ainsi que les algorithmes de *All-Reduce* afin de vérifier la véracité de cette hypothèse.
<figure><img src="image_11.png" /><figcaption>FIGURE 9 – Durée d’entraînements d’un même modèle selon le nombre de nœuds sur deux sites.</figcaption></figure>

<figure><img src="image_12.png" /><figcaption>FIGURE 10 – Communication intra et inter site.</figcaption></figure>

# 4 Étude de bibliothèques d'opérations collectives

Nous avons vu que pour répondre à des durées d'entraînement excessives, les applications d'IA parallélisaient de différentes façons l'entraînement du modèle afin d'améliorer le plus possible la durée de cet entraînement. La parallélisation, comme on l'a vu avec la parallélisation des données, implique aux nœuds participants de communiquer certaines informations entre eux pour obtenir un modèle cohérent (cf partie 3.2).

Seulement, lorsqu'on se place dans un contexte réseau géo-distribué, il a été supposé que le coût de certaines communications impactent plus ou moins fortement la durée globale de l'entraînement (selon le type de réseau, du type de carte utilisée, du nombre etc...). Ce qui nous intéresse alors est la manière dont ces communications sont effectuées, d'aller dans les détails de certaines bibliothèques d'opérations collectives et étudier les algorithmes de All-Reduce. Il sera peut-être possible d'y apporter des optimisations.

## 4.1 Traçage de NCCL

Comme présenté en partie 3.3, le All-Reduce est une succession d'échanges point-à-point entre les nœuds de notre réseau. Étudier ces échanges point-à-point est donc la démarche à suivre. Une méthode connue pour cela est de faire du tra-
**çage.** Cela consiste à enregistrer les différents appels de fonctions et des métriques qui en découlent telles que le temps de l'appel, le type de données traitées, etc... On peut ensuite les représenter graphiquement pour analyser plus facilement les résultats.

En faisant du traçage sur notre parallélisation des données, on pourra en théorie récupérer tous les appels aux fonctions d'envoi et de réception de données utilisées par le *All-Reduce*. On a alors ajouté de quoi faire du traçage sur les scripts utilisés en section 3.5. On a priorisé *NCCL* par rapport à *Gloo* de par sa documentation et son optimisation pour les GPUs.

La représentation graphique<fnref n="5" /> obtenue après traçage se trouve en figure 11.

<figure><img src="image_13.png" /><figcaption>FIGURE 11 – Trace lors d’un entraînement de modèle avec *NCCL*.</figcaption></figure>

On retrouve bien les appels au *All-Reduce* de *NCCL* tout au long de l'exécution. Cependant, la seule donnée pertinente que l'on parvient à obtenir est sa durée. Les envois et réceptions entre processus, intrinsèques au *All-Reduce*, n'apparaissent pas.

Quelque soit la bibliothèque de traçage utilisée (HTA de *PyTorch*, Snoopie [2] majoritairement) à chaque essai, nous ne pouvions pas descendre plus bas que les appels au *All-Reduce* de *NCCL*.

La suite logique a été d'essayer de récupérer les informations nous-mêmes, de faire nos propres traces. Malgré le répertoire public de *NCCL*, le code est très peu voire pas assez détaillé, en tout cas dans la profondeur du code qui nous intéresse et a rendu la prise en main trop compliquée.

Alors, nous avons essayé de remonter la chaîne d'appels de certains codes d'exemple disponibles en utilisant le débugueur de chez NVIDIA, **cuda-gdb**. Cependant, nous sommes tombés sur un bug déjà identifié de ce débugueur mais malheureusement non résolu.

La question s'est par conséquent posée : pour poursuivre notre étude, que préférerions-nous faire ? Poursuivre avec *NCCL* malgré l'impasse dans laquelle nous nous trouvions ? Essayer de tracer la bibliothèque *Gloo*, malgré qu'elle soit moins utilisée par les programmes IA ? Ou bien élargir nos horizons et tenter d'étudier une bibliothèque d'opérations collectives qui n'est pas intégrée dans *PyTorch* ?

Notre choix s'est porté sur la dernière proposition, puisque à la même période, est sorti un papier présentant une bibliothèque promettant certaines caractéristiques proches de celles attendues dans CUPSELI.

<footnote n="5">5. Générée grâce au visualiseur graphique du logiciel en ligne *perfetto*</footnote>
## 4.2 PCCL

PCCL ou *Prime Collective Communications Library* est une bibliothèque d'opérations collectives mise au point et utilisée par l'entreprise *PrimeIntellect*.

Dans le papier de présentation de PCCL [3], les auteurs indiquent que cette bibliothèque est destinée au réseau Internet, donc un réseau moins puissant que ceux usuellement utilisés pour l'entraînement de gros modèles. Elle est dite tolérante aux fautes lors d'entraînements distribués de modèle d'IA, comme l'arrêt momentané d'une machine, un problème réseau Internet, etc... De plus, il est possible de rejoindre ou de quitter l'entraînement en cours sans que cela pose problème. Ces éléments sont importants car ils évoquent tous des caractéristiques spécifiques du contexte réseau de CUPSELI.

De plus, le code disponible en public paraît plus abordable que celui de NCCL. Assez pertinent si jamais on souhaite y apporter des modifications et les tester.

Enfin, bien que PCCL ne fasse pas partie des bibliothèques d'opérations intégrées dans PyTorch, les scripts d'exemples de PCCL montrent tout de même une compatibilité entre les deux. PCCL fournit alors des exemples d'applications d'apprentissage ayant les mêmes schémas de communications que les applications PyTorch.

Par conséquent, à la lumière de tous ces éléments, nous nous sommes tournés vers PCCL plutôt que de continuer avec NCCL ou de commencer l'étude de Gloo. Cette bibliothèque paraît bien plus accommodée pour notre contexte que le reste précédemment étudié et nous permettra d'avancer dans notre analyse des échanges point-à-point d'un All-Reduce.

## 4.3 Traçage de PCCL

Nous avons utilisé l'exemple de l'entraînement de ChatGPT-2 fournie dans le répertoire de PCCL pour faire notre traçage. Nous avons fait le traçage à la main en modifiant le code de PCCL pour récupérer les informations qui nous intéressaient. Nous avons inscrit dans un fichier toutes les informations intéressantes liées aux appels de fonction d'envoi et de réception lors d'un All-Reduce (source, destination, taille, nombre de message).

Deux caractéristiques de PCCL sont à souligner. Tout d'abord pour le All-Reduce, c'est l'algorithme en anneau présenté en section 3.3 qui est utilisé. Ensuite, une optimisation est ajoutée à cet algorithme, l'utilisation du problème du voyageur de commerce (noté TSP par la suite)<fnref n="6" />. Étant donné que PCCL est tolérant aux déconnexions et connexions inattendues en cours d'une exécution de programme, la topologie du réseau est amenée à ponctuellement changer. Le TSP garantit que l'ordre des nœuds dans l'anneau est optimal en terme de bandepassante bien que la topologie soit modifiée.

Nous avons choisi de représenter les échanges sous forme de graphe comme celui en figure 12, avec certains dégradés de couleurs pour identifier les échanges entre processus<fnref n="7" />.

<footnote n="6">6. voir annexe pour plus de détails</footnote>

<footnote n="7">7. Les données ont été sélectionnées et projetées ainsi grâce au module networkx de python.</footnote>
<figure><img src="image_14.png" /><figcaption>FIGURE 12 – Graphe du nombre de communications des All-Reduce d'un entraînement avec PCCL.</figcaption></figure>

Les ronds de couleur gris sont les processus, ceux en bleus sont les machines. Une couleur est associée à des échanges entre deux processus seulement. S'il y a plusieurs flèches de même couleur, cela signifie que l'échange s'est fait entre deux processus de machines différentes. Le nombre surplombant une flèche est le nombre de communications entre les entités aux extrémités de celle-ci.

Chaque processus est identifié par une adresse IP et un port, sous la forme IP:PORT. Si l'on part arbitrairement du processus 172.16.28.4:48151 et que l'on suit la flèche orange dont elle est la source, on arrive au processus 172.16.28.6:48151. Si l'on fait de même avec la flèche colorée de ce processus et ainsi de suite on arrivera au processus 172.16.28.4:48151, celui d'où on est parti. De plus, sur tout le graphe, une source n'a qu'un unique destinataire et réciproquement. On retrouve bien les caractéristiques de l'algorithme en anneau utilisé par PCCL.

En revanche on remarque qu'une communication entre nœuds (XX.XX.XX.4 et XX.XX.XX.6) est privilégiée au lieu d'une communication entre les processus XX.XX.XX.6:48150 et XX.XX.XX.6:48151 (soulignés en rouge sur la figure 12). Pourtant il serait plus efficace d'effectuer cette communication par mémoire partagée car plus rapide qu'une communication entre processus de nœuds différents. L'utilisation de la résolution d'un TSP devrait pouvoir empêcher ce genre de situation.

Il s'avérait que la topologie optimisée calculée par le TSP n'était jamais mise à jour. Une fois ce bug identifié, corrigé, et validé par les développeurs nous avons pu obtenir des résultats concluant comme le montre la figure 13.

Dans cet exemple à quatre processus, on voit cette fois-ci le changement de direction de certains échanges dû à une résolution du TSP. En effet, le processus XX.XX.XX.6:48150 a pu envoyer 7 messages au processus XX.XX.XX.5:48150 avant que la topologie soit revue et qu'il se mette à communiquer, pour tout le
<figure><img src="image_15.png" /><figcaption>FIGURE 13 – Graphe du nombre de communications des All-Reduce d'un entraînement avec PCCL.</figcaption></figure>

reste de l'entraînement, au processus XX.XX.XX.6:48152.

Grâce au TSP donc, dans l'anneau, l'ordre des processus sera optimisé de sorte d'avoir la plus petite latence possible entre chacun d'entre eux. Cela permet de limiter le nombre de communications inter-site, les plus lentes. En revanche, la durée d'une itération de l'algorithme en anneau, de par sa construction, est toujours minorée par le temps de communication le plus lent entre les processus. Cette minoration est indépendante de la topologie et de plus, elle intervient à chaque itération de l'algorithme.

Dû à la géo-distribution, plusieurs niveaux de hiérarchie réseau sont impliqués (cartes réseau des GPUs, commutateur entre ceux-ci, routeur pour connecter les sites). Le temps le plus lent entre processus, et donc d'une itération de l'anneau, est lié à celui de transmission du niveau du réseau le plus lent.

Par conséquent, bien que l'anneau soit assez simple de compréhension, riche d'exemples d'implémentation, et optimisable ici avec un TSP, on peut tout de même se demander s'il n'existe pas des alternatives à celui-ci. On chercherait alors des algorithmes de All-Reduce qui dépendent moins du temps de communication le plus lent, ou en tout cas qu'il le fasse moins intervenir, avec un nombre semblable d'itération si ce n'est moins.

## 4.4 Recursive-Doubling

Comme indiqué précédemment, plusieurs algorithmes de All-Reduce existent. Il a été montré [5] que l'algorithme de Recursive-Doubling exploite à 100% la bande-passante du réseau comme l'anneau. De plus, il a une meilleure complexité temporelle, c'est-à-dire qu'il nécessite moins d'étapes selon le nombre de processus que l'anneau.

En résumé, Le Recursive-Doubling utilise autant de bande-passante que l'an-
neau mais sur moins d'itérations. On peut donc se demander s'il ne serait pas plus performant que l'anneau. Cette étude est d'autant plus intéressante puisque c'est l'anneau qui est généralement privilégié dans les contextes d'apprentissage IA.

## L'algorithme

L'algorithme de Recursive-Doubling pour du All-Reduce fonctionne de la manière suivante :

1. On forme des paires de processus. Pour chacune de ces paires, les processus vont s'échanger leur informations. Ainsi on a des paires de processus ayant la même information.

2. On passe à l'échelle supérieure en faisant des paires de paires. Chaque processus communique avec un unique autre faisant partie de l'autre groupe de paires.

3. On fait ainsi jusqu'à ce qu'il n'y ait qu'un seul et même groupe dans lequel tous les processus ont la totalité de l'information.

Il a l'avantage d'avoir un nombre d'étapes en $O(\log_2(p))$, (complexité logarithmique) avec p le nombre de processus, comparé à $O(p - 1)$ (complexité linéaire) pour l'anneau. On peut retrouver un schéma d'exemple de Recursive-Doubling pour huit processus en figure 14.

<figure><img src="image_16.png" /><figcaption>FIGURE 14 – Recursive-Doubling pour huit processus.</figcaption></figure>

Comme indiqué à la fin de section précédente, la hiérarchie réseau implique que certaines communications sont plus coûteuses que d'autres (mémoire partagée contre utilisation de routeurs par exemple). Cela signifie qu'avec le Recursive-Doubling, il faut faire attention à quel processus communique avec quel processus. Cette problématique intervient très peu dans le milieu du HPC étant donné que les machines sont sur un même réseau local avec des liens à très grande vitesse de communication. Dans notre cadre d'étude, le fait que les liens de communication entre les machines soient beaucoup plus hétérogènes et moins puissants implique que l'on doit se poser ce genre de questions pour optimiser au mieux notre algorithme.

Si l'on regarde l'exemple de la figure 15 avec quatre processus, on voit qu'il y a deux possibilités pour la deuxième étape, une sans communication inter-site et une avec. C'est l'étape n°2 sans communication inter-site qui nous intéresse le plus. On voudra toujours prioriser les étapes avec le moins de communication inter-site
<figure><img src="image_17.png" /><figcaption>FIGURE 15 – Recursive-Doubling à quatre processus.</figcaption></figure>

possible, en tout cas avec le moins de communications qui coûtent le plus en temps.

On comprend donc qu'il y a des exécutions de Recursive-Doubling plus pertinentes que d'autres selon les communications qui se déroulent lors de chaque étape de l'algorithme. Pour savoir quelles sont les meilleures exécutions, les plus rapides, il faut donc toutes les tester.

Pour en avoir encore plus à essayer, nous avons ajouté une subtilité à cet algorithme. A chaque itération, au lieu de par défaut faire des échanges symétriques (sur la figure 14, pour tout i, j, $P_i$ envoie à $P_j$ et réciproquement) nous avons décidé que tout processus pouvait communiquer ses informations à n'importe quel autre, tant que ces derniers n'avaient aucune information en commun.

### Essayons de quantifier le nombre d'exécutions possibles.

On peut tout d'abord montrer que pour la **première itération** de l'algorithme, le nombre $N$ de possibilités d'échanges entre $p$ processus<fnref n="8" /> est minoré par :

$$ (p - 1)! \leq N \qquad (2) $$

— **Égalité** : Pour tout processus $i$ ($0 \leq i \leq p - 1$), chacun peut choisir entre les processus qui n'ont pas encore été déjà désignés comme destinataire. De plus, il ne peut pas se choisir lui-même de par notre condition sur la communication entre processus n'ayant aucune information en commun. Donc un processus $i$ a $p - 1 - i$ possibilités de processus destination. Du processus 0, 1, 2 ... jusqu'au $p - 2$ cela donne respectivement $p - 1, p - 2, p - 3...$ jusqu'à $p - 1 - (p - 2) = 1$ possibilités de destinataire. Alors le dernier, $p - 1$, n'aura théoriquement aucun choix possible puisqu'il ne peut pas se choisir.

Pour éviter cela, il faut et il suffit qu'un processus précédent ait choisi $p - 1$ comme destinataire. Ainsi on est assuré que le dernier peut en choisir

<footnote n="8">8. On appellera chacune de ces possibilités **une configuration**</footnote>
un qui n'est pas lui-même. Notons ce processus $j$, il reste alors les processus $[0, p-2]$ à choisir pour les processus $[0, p-1] \setminus \{j\}$ qui restent. On en revient à dire que tout processus $i$ dans $[0, p-1] \setminus \{j\}$ a $p-1-i$ possibilités. Au total on a :

$$N = \prod_{i=0}^{p-2} (p-1-i) = \prod_{k=1}^{p-1} (p-k) = (p-1)! \text{ (en posant } k = i + 1)$$

— **Supériorité** : on peut voir avec certains exemples qu'un processus $i$ peut avoir plus que $p-i-1$ choix possibles. Cela arrive quand un processus $i$ choisi comme destinataire $i+1$. Le processus $i+1$ ne pouvant pas de toute manière se choisir lui-même, il obtient une possibilité de plus.

Par exemple pour quatre processus :

1. Le processus 0 peut choisir entre 1, 2 ou 3 comme processus destinataire. Il choisit 3.

2. Le processus 1 a le choix entre 0 ou 2. Admettons qu'il choisisse 2

3. Le processus 2 a alors le choix entre 0 et 1.

4. Le processus 3 choisit celui qui n'a pas été choisi par le 2.

Cela donne $3 \times 2 \times 2 \times 1 = 12$ possibilités. Si l'on revient à la deuxième étape, mais que le processus 1 ne choisisse pas 2 cela donne :

1. 0 choisit toujours 3

2. 1 choisit 0 plutôt que 2

3. 2 ne peut choisir que 1

4. 3 choisit 2

Dans ce cas, on a $3 \times 2 \times 1 \times 1 = 6(= 3!)$. Il y a bien, plus de possibilités dans le premier cas que dans le second.

Cette borne inférieure (inégalité n°2) n'est valable que pour la première itération du Recursive-Doubling. Lors de la suite de l'algorithme, selon les choix de communications entre processus faits à l'itération précédente, le nombre de configurations possibles pour une étape de l'algorithme est probablement moindre.

Pour obtenir toutes les exécutions possibles d'un Recursive-Doubling à p processus, nous avons procédé de la manière suivante :

1. Nous inscrivons d'abord dans un fichier toutes les séquences d'échanges possibles pour ce nombre de processus, sous la forme [[i, j]] avec $i, j \in [0, p-1]$ représentant des paires [src, dst]. Dans la séquence, chaque indice $i$ ne doit apparaître qu'une seule fois en tant que src et une fois en tant que dst.

2. On crée ensuite un ensemble $E_0$ de p nœuds indexés de 0 à $p-1$. Chaque nœud est associé à un tableau de taille $p$ contentant des bits. Dans une case $i$, la valeur sera à 1 si le nœud a reçu les informations du nœud $i$, à 0 sinon. Initialement, pour un nœud $i$ seule la case $i$ est à 1.
3. On va parcourir toutes les séquences d'échanges du fichier. Pour chaque séquence $S_k$, on part de $E_0$ et on met les tableaux de chaque nœud à jour selon les paires [i,j]. On a un nouvel ensemble $E_1$. On sauvegarde alors $(E_1, S_k)$.

4. A la fin du premier parcours du fichier, on aura un certain nombre de paires $(E_1, S_k)$.

5. Pour chaque $E_1$, on parcourt tout le fichier. Si à partir des tableaux des nœuds de $E_1$, toutes les paires [i,j] d'une séquence $S_l$ sont compatibles alors on met à jour les tableaux des nœuds de $E_1$ pour obtenir $E_2$. On sauvegarde cette fois $(E_2, S_k, S_l)$.

6. On recommence cette dernière étape $log_2(p)-2$ fois. L'exécution du Recursive-Doubling correspond aux différentes séquences $S_i$ associé à un ensemble $E_{log_2(p)}$.

Par l'expérience, pour $p = 8$, (où $(8-1)! = 5040$) on obtient 14833 possibilités pour la première étape de l'algorithme. Pour toute son exécution, dans le pire des cas, on aurait :

$$14833^{log_2(8)} = 14833^3 \approx 3.26 \times 10^{12} \text{ possibilités d'exécutions}$$

Toujours avec huit processus, mais en se cantonnant à un Recursive-Doubling avec échanges symétriques, on arrive à avoir plus de 50 000 exécutions complètes possibles. Que ce soit avec ou sans échanges symétriques, on obtiendra, avec plus de huit processus, un grand nombre d'exécution à produire d'une part et à tester de l'autre.

Nous avons alors utilisé un simulateur d'échanges réseaux pour aller au bout de notre étude sur cet algorithme malgré tout. Nous avons donc pu tester nos exécutions du Recursive-Doubling. Cependant, il a fallu nous résoudre à réduire le nombre de possibilités d'exécutions afin de rester sur des durées de simulations relativement acceptables. Nous avons seulement gardé un échantillon du fichier de séquences d'échanges présenté précédemment.

## 4.5 Simulation et Résultats

Bien que les résultats acquis par simulation seront théoriques, ils nous indiqueront néanmoins comment le Recursive-Doubling se situe par rapport à l'algorithme en anneau dans des circonstances choisies pour notre cadre d'étude. Le framework que nous avons décidé d'utiliser pour ces simulations s'appelle simgrid.

### Simulations avec simgrid

Avec simgrid, nous pouvons modifier la hiérarchie réseau ainsi que les valeurs de bande-passante des liens entre les processus. Également, nous choisissons la taille des données envoyées. Nous avons alors défini une configuration par défaut. Celle-ci consiste en un réseau hiérarchique homogène, c'est-à-dire un même nombre de processus par nœud et un même nombre de nœuds par site. Cela donne le réseau suivant :

Les chiffres sont les processus de notre réseau. SharedMem, NIC et routeur représentent les liens de communication entre les nœuds. On donne une valeur de
<figure><img src="image_18.png" /><figcaption>FIGURE 16 – Graphe hiérarchique à huit processus.</figcaption></figure>

bande passante pour chaque lien. Dans notre configuration par défaut, les valeurs se trouvent dans le tableau 2.

<table><caption>TABLE 2 – Valeurs des liens pour la configuration par défaut.</caption><thead><tr><td>sharedMem</td><td>Nic</td><td>routeur</td></tr></thead><tbody><tr><td>100 Gbs</td><td>1 Gbs</td><td>30 Gbs</td></tr></tbody></table>

*SharedMem* fait référence aux accès de mémoire partagée entre les processus d'une même machine, c'est pour cela que nous les avons modélisés avec une bande-passante bien supérieure au reste. Le terme *NIC* est l'acronyme anglais pour les cartes réseaux des machines. Il est moins rapide que la mémoire partagée puisqu'il nécessite de véritables communications réseaux entre les machines. Les *NICs* sont là pour modéliser les communications intra-site. Les *routeurs* sont là pour modéliser les communications inter-site (cf figure 10).

Enfin, la valeur par défaut de la taille des données transmises pour chaque échange est de $10^6$ octets.

## Premières simulations

Après avoir simulé les 50 000 possibilités pour le *Recursive-Doubling* ainsi que la configuration en anneau, nous avons obtenu la distribution de valeurs présentée en figure 17.

La ligne verticale bleue en pointillée a été ajoutée pour mieux situer les performances de l'anneau par rapport au *Recursive-Doubling* dans notre configuration. La simulation de l'anneau a été fait en faisant attention à prendre une configuration de l'anneau optimale selon l'approche via TSP. Remarquons alors que n'importe quelle configuration de *Recursive-Doubling* est plus rapide que la configuration en anneau. On obtient pour l'algorithme *Recursive-Doubling* un minimum légèrement supérieur à 8 millisecondes. La simulation avec l'anneau prend quant à elle une durée de 17 millisecondes environ soit deux fois plus lente que la meilleure performance du *Recursive-Doubling*.

Lorsqu'on examine en détails les configurations les plus performantes, on remarque que toutes ont au moins une phase avec uniquement des échanges via *sharedMem*. Réciproquement, on trouve que toute configuration qui dure plus que la durée minimale n'a aucune phase avec seulement des échanges en mémoire par-
<figure><img src="image_19.png" /><figcaption>FIGURE 17 – Histogramme de la distribution des simulations du Recursive-Doubling.</figcaption></figure>

tagée.

Ce premier résultat montre que l’algorithme en anneau, bien que privilégié dans *PCCL*, peut avoir de moins bonnes performances que d’autres algorithmes de *All-Reduce*. Quoique positif, il n’est néanmoins pas suffisant encore pour assurer que le Recursive-Doubling est plus judicieux à employer que l’anneau. Certaines valeurs telles que les valeurs de bande-passante ainsi que la taille des données qui transitent étaient fixes dans cette première expérience. Il convient alors de tester d’autres configurations avec des valeurs différentes avant de tirer de véritables conclusions.

## Modification de la bande passante

Lorsqu'on regarde les valeurs par défaut dans le tableau 2, les *NICs* ont une bande passante de 1 Gbps alors que celle des *routeurs* est de 30 Gbps. Ayant deux machines donc deux NICs par site, la bande passante d'un routeur est bien supérieure à la somme des bande-passantes des NICs appartenant au même réseau. Les communications passant par un routeur n'étaient donc pas restreintes par celui-ci.

On s'est alors intéressé à l'impact de ce lien inter-site selon sa bande-passante. Nous avons fait différentes simulations où les valeurs de bande-passante des liens étaient modifiées. Dans certains cas les *routeurs* empêchaient le passage de l'ensemble des données en un seul pas de temps, dans d'autres non. Les résultats de ces différentes expériences sont répartis sous forme de *carte de chaleur*<fnref n="9" /> en figure 18 et 19. Les valeurs présentées sont respectivement les meilleures configurations de l'anneau selon une approche TSP et les configurations les plus rapides pour le Recursive-Doubling.

La *heatmap* de l'anneau (figure 18) permet de montrer le caractère limitant du lien le plus lent. En effet, si l'on fixe une bande-passante sur un *routeur*, la performance de l'algorithme change pour toute bande-passante de NIC plus lente que celle du *routeur*, puisque la NIC devient le lien le plus lent. En revanche, dès que c'est la bande-passante du *routeur* qui devient limitante, les durées sont les

<footnote n="9">9. heatmap en anglais</footnote>
<figure><img src="image_20.png" /><figcaption>FIGURE 18 – Heatmap de l’anneau selon différentes bande-passantes.</figcaption></figure>

mêmes pour des NICs aux bande-passantes plus rapides.

Globalement, on observe une amélioration de l’anneau quand on se dirige vers le coin supérieur droit du graphique. On conclut avec cette première carte que, si l’on veut améliorer les performances de l’anneau, il faut augmenter les valeurs de bande-passante de *routeurs* mais aussi de *NICs* afin de minimiser l’impact du caractère limitant du lien le plus lent.

<figure><img src="image_21.png" /><figcaption>FIGURE 19 – Heatmap du *Recursive-Doubling* selon différentes bande-passante (durée minimale de chaque simulation).</figcaption></figure>

La carte de chaleur du *Recursive-Doubling* (figure 19) montre un comportement similaire à celle de l’anneau. Il a été dit plus tôt que les exécutions de *Recursive-Doubling* les plus performantes étaient celles avec au moins une phase contenant uniquement des communications par mémoire partagée. Seulement, pour le reste des phases, on va retrouver au moins une fois des communications intra-site et inter-site, en tout cas des communications par le lien le plus lent. Ainsi comme
pour l'anneau, une bande-passante d'un lien trop faible par rapport à celle de l'autre lien contraint la durée totale de l'algorithme, et c'est ce qu'on retrouve sur la figure 19.

Les deux cartes de chaleur présentent le même comportement. Leur différence majeure se situe au niveau de la durée de chaque exécution. A l'instar de la conclusion que l'on tirait de la première expérience (figure 17), pour chaque paire de bande-passantes, la simulation avec le *Recursive-Doubling* est plus rapide qu'avec l'anneau. Pour mieux appréhender la différence entre les deux algorithmes, nous avons obtenue la *heatmap* (figure 20) contenant pour chaque paire de bande-passantes, le ratio entre la durée de la meilleure configuration de *Recursive-Doubling* et la durée de l'anneau.

<figure><img src="image_22.png" /><figcaption>FIGURE 20 – Carte de chaleur des ratios du durée de simulation entre Recursive-Doubling et l'anneau.</figcaption></figure>

D'après la figure 20, peu importe les valeurs de bande-passante, le *Recursive-Doubling* est plus rapide que l'anneau. On remarque qu'il est en particulier plus performant en partie droite de la diagonale de la matrice. Cela correspond à des situations où la bande-passante du *routeur* est au moins deux fois plus grande que celle des *NICs*. Dans ces configurations là, les deux *NICs* d'un même site peuvent communiquer via leur *routeur* en un même pas de temps dans *simgrid*. Pour l'anneau, cette information n'a pas d'impact de par sa configuration. Il n'y a que deux communications inter-sites avec seulement une *NIC* par site qui communique vers l'autre site. Pour le *Recursive-Doubling* en revanche, qui peut avoir plusieurs communications inter-site depuis un même site lors d'une phase, cela vient améliorer ses performances.

Les bande-passantes étaient l'un des axes que l'on avait fixé dans notre première expérience. De nouveau, les résultats ont montré que le *Recursive-Doubling* était plus performant que l'anneau. L'étude d'autres axes iront peut-être dans cette même direction.
## Modification de la taille des données

Dans notre configuration par défaut (cf section 4.5) la taille des données était fixée à $10^6$ octets. Ce qui nous intéresse à présent est de savoir si cette valeur a un impact sur les performances des deux algorithmes et si les résultats obtenus iront à l'encontre ou non de ceux étudiés précédemment.

<figure><img src="image_23.png" /><figcaption>FIGURE 21 – Durées d'entraînement avec Recursive-Doubling et anneau selon la taille des données transmises (échelle logarithmique).</figcaption></figure>

Les résultats exposés sur la figure 21 ont été obtenus avec les valeurs de bande-passante par défaut définies au début de cette section. Ils ont été présentés sur un échelle logarithmique pour mieux discerner les différences entre les deux algorithmes. Ils tendent tous les deux vers un même comportement dû à des bande-passantes des différents liens du réseau beaucoup trop faible par rapport à la taille des données transmises. Néanmoins, le Recursive-Doubling reste plus rapide que l'anneau dû au fait qu'il y a moins de communications par lien le plus lent avec du Recursive-Doubling optimisé qu'avec un anneau.

Nos résultats théoriques semblent s'accorder sur le fait que le Recursive-Doubling est dans un contexte géo-distribué plus performant que l'anneau. Cela a été montré en utilisant des milliers de configurations possibles et en changeant plusieurs paramètres de notre réseau simulé.

Gardons en tête cependant que tous ces résultats sont obtenus par simulation et non par expériences réalisées sur un vrai réseau. De plus, nos simulations se sont exclusivement déroulées sur un réseau hiérarchique homogène à seulement huit processus. Avec CUPSELI, il faut s'attendre à des réseaux dont la géo-distribution sera beaucoup plus hétérogène, en tout cas moins symétriques, que celle prise en compte dans ce travail. Ce réseau théorique, simulé, comportait quatre NICs avec la même bande-passante, de même pour les deux routeurs. L'étude complète de ce réseau implique de tester l'impact de chaque lien sur celui-ci. Notre étude théorique
pourrait être donc encore plus poussée, pour confirmer les premières conclusions
que l'on a pu tirer de nos expériences.

# 5 Conclusion

L'ère IA est sans-précédente et demande d'innover constamment. L'utilisation
de serveurs de calcul pour l'entraînement de modèles d'IA se rapproche d'un luxe
auquel tout le monde n'a pas le droit. Le défi CUPSELI est un projet d'enver-
gure ancré dans cette actualité, où exploiter les ressources de calcul inutilisées
de certains appareils informatiques permettrait de contourner cet obstacle. Seule-
ment, cela implique de passer d'un réseau à grande bande-passante, composé de
cartes graphiques dernières générations, rapprochées physiquement pour réduire la
latence entre elles au minimum, à un réseau Internet aux caractéristiques hétéro-
gènes, avec des GPUs de plus faible puissance et écartés de centaine de kilomètres
selon les sites depuis lesquels ils sont réservés.

L'objectif de ce stage était d'étudier une partie des nombreuses problématiques
naissant de ce défi, en l'occurrence les communications échangées entre GPUs géo-
distribués lors d'entraînement d'IA. Notre étude nous a amené à comparer deux
algorithmes de All-Reduce. L'algorithme en anneau, très prisé pour les entraîene-
ments, paraissait peut-être moins adapté à notre contexte, comparé au Recursive-
Doubling. Les résultats des différentes simulations exécutées nous ont permis de
montrer que ce dernier était peut-être plus intéressant à utiliser vis-à-vis d'un al-
gorithme en anneau. Cependant, une étude plus approfondie est attendue pour
confirmer ce qui n'est encore qu'une hypothèse avancée. Surtout que, nous avons
évoqué que l'anneau était l'algorithme actuellement utilisé par la plupart des ap-
plications d'apprentissage IA. Cette contradiction avec nos résultats provient du
fait qu'en pratique, les données ne sont pas envoyées en un seul bloc comme on
l'a fait avec simgrid mais envoyées partie par partie. Envoyer seulement des sub-
divisions de données permet de pipeliner l'algorithme, cela afin d'utiliser le plus
possible tous les GPUs lors de l'exécution du programme. Il s'avère alors que le
Recursive-Doubling se pipeline moins bien que l'anneau. Le premier est donc pri-
vilégié pour des données de petites tailles par rapport au second [5] [4].

Le projet CUPSELI impose de revoir complètement certains aspects réseau et
algorithmique d'un entraînement IA. En effet, le simple postulat que le réseau sur
ce projet sera géo-distribué et moins performant qu'un réseau HPC nous a amené
à toutes les études exposées dans ce rapport. Cependant, les aspects hétérogène
et volatile du réseau n'ont pas été abordés ici et relèvent donc d'un travail supplé-
mentaire. De plus, nous avons présenté et étudié un seul algorithme d'All-Reduce,
cependant il en existe plus [5] et d'autres méritent peut-être de s'y attarder. Ces
problématiques seront abordés par la suite lors d'une thèse consacrée elle aussi sur
les communications réseaux dans un contexte réseau géo-distribué, hétérogène et
volatile.
# 6 Annexe

## TSP

"En informatique théorique, le problème du voyageur de commerce, est un problème d'optimisation qui consiste à déterminer, étant donné un ensemble de villes, le plus court circuit passant par chaque ville une seule fois." – Wikipédia. Dans notre cas, les villes sont les processus participants au All-Reduce, les distances entre les villes sont en réalité les latences des liens entre processus. Sur une topologie réseau, le TSP donnera l'anneau qui minimisera la latence.
Références

[1] DEEPSEEK-AI. *DeepSeek-V3 Technical Report*. 2025. URL: https://arxiv.org/pdf/2412.19437.

[2] Mohammad Kefah Taha ISSA et al. Snoopie : A Multi-GPU Communication Profiler and Visualizer. 2024. DOI: https://doi.org/10.1145/3650200.3656597.

[3] PRIMEINTELLECT. *Prime Collective Communications Library - Technical Report*. 2025. URL: https://arxiv.org/pdf/2505.14065.

[4] Rolf RABENSEIFNER. « Optimization of Collective Reduction Operations ». In : *ICCS Conference paper* (2004). URL : https://link.springer.com/chapter/10.1007/978-3-540-24685-5_1#preview.

[5] William Gropp RAJEEV THAKUR. *Improving the Performance of Collective Operations in MPICH*. 2005. URL: https://web.cels.anl.gov/~thakur/papers/mpi-coll.pdf.

[6] Lin ZHANG et al. « DeAR : Accelerating Distributed Deep Learning with Fine-Grained All-Reduce Pipelining ». In : *ICDCS* (2023). URL : https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=10272398.