Livraison 1–5 min

Mac mini M4 dédié

$21.5 / jour · bare metal
Configurer Mac cloud
Web VNC Clé SSH Cinq régions

FIELD NOTE · GPUHardware

Insuffisance de mémoire MPS dans PyTorch 2.14 : comment corriger l’entraînement scientifique en 2026

Ce guide aide les chercheurs utilisant Apple Silicon à distinguer une véritable saturation des tenseurs, une croissance du cache, un graphe de calcul conservé ou un repli CPU. Il propose une procédure de diagnostic reproductible, une checklist d’acceptation et des critères pour choisir entre environnement Apple Silicon propre, Linux GPU ou fonctionnement en double piste.

Le guide officiel de publication de PyTorch 2.14 indique que cette version, publiée le 2 septembre 2026, modifie notamment l’allocateur du cache MPS ainsi que certains chemins de mémoire et de copie. Cela ne signifie pas que toute insuffisance de mémoire MPS dans PyTorch 2.14 est corrigée. Cette semaine, nous vous recommandons donc de ne pas supprimer d’abord une limite de mémoire : distinguez les tenseurs réellement occupés, le cache, les graphes conservés, les formes dynamiques et le repli CPU, puis validez la correction dans un environnement propre.

Ce guide s’adresse aux étudiants et doctorants confrontés à « MPS out of memory » pendant un entraînement ou une inférence sur Apple Silicon. Il concerne également les mainteneurs qui doivent comparer un projet PyTorch entre Linux GPU et macOS, ainsi que les responsables de laboratoire qui doivent établir temporairement une reproduction fiable sans acheter un Mac.

Dernière mise à jour : 12 septembre 2026. Les informations de version ont été vérifiées dans l’annonce officielle de PyTorch 2.14, la documentation MPS stable et la documentation Apple sur la pression mémoire.

Le premier diagnostic doit séparer cinq causes

Une erreur MPS peut désigner des situations très différentes. PyTorch peut refuser une nouvelle allocation alors que le modèle consomme réellement toute la marge disponible. À l’inverse, la mémoire peut sembler progresser parce que des sorties gardent leur graphe, parce que des formes variables alimentent plusieurs chemins d’allocation ou parce qu’une partie du calcul est exécutée sur le CPU.

Nous commençons par établir une fiche de référence, avant toute optimisation :

  • version exacte de PyTorch, ici PyTorch 2.14 si c’est la version testée ;
  • version de Python et de macOS ;
  • modèle, précision utilisée, taille du lot, longueur de séquence et résolution des entrées ;
  • puce Apple Silicon et mémoire disponible indiquée par le système ;
  • numéro d’itération auquel le problème apparaît ;
  • message complet, trace Python et dernière opération exécutée ;
  • état du processus dans Moniteur d’activité, notamment la pression mémoire.

La mémoire unifiée ne doit pas être interprétée comme une réserve entièrement disponible pour MPS. macOS, les bibliothèques, les entrées, les sorties, le système de fichiers et d’autres applications utilisent également cette mémoire. Apple explique que la pression mémoire décrit l’état global du système, et non une simple jauge de mémoire MPS disponible dans la documentation de Moniteur d’activité.

Trois signaux doivent rester séparés :

  • torch.mps.current_allocated_memory() mesure la mémoire actuellement occupée par les tenseurs gérés par PyTorch ;
  • torch.mps.driver_allocated_memory() mesure la mémoire allouée par le pilote MPS, qui peut inclure davantage que les seuls tenseurs ;
  • la pression mémoire macOS décrit la situation de l’ensemble du système.

Les définitions officielles de current_allocated_memory et de driver_allocated_memory précisent pourquoi ces valeurs ne sont pas interchangeables. Une divergence durable entre les deux constitue un indice à examiner, pas une preuve automatique de fuite.

Les paramètres du modèle déterminent la limite utile

Avant d’accuser l’allocateur, nous réduisons une seule variable à la fois. Un modèle peut dépasser la capacité pratique de l’environnement à cause de ses paramètres, de ses activations intermédiaires, des états de l’optimiseur et des entrées. La taille du lot n’est donc qu’un levier parmi d’autres.

La méthode de réduction est volontairement monotone :

  1. conserver la graine aléatoire et le même échantillon ;
  2. diminuer uniquement la taille du lot ;
  3. relancer plusieurs itérations identiques ;
  4. si l’erreur persiste, restaurer le lot initial et réduire la longueur de séquence ou la résolution ;
  5. comparer ensuite une précision différente uniquement si le protocole scientifique l’autorise ;
  6. noter quelle modification a supprimé l’erreur et si elle change les résultats.

Il faut éviter de réduire simultanément le lot, la longueur de séquence et la résolution. Une telle modification peut faire disparaître l’erreur sans révéler la principale source d’allocation. Pour une étude reproductible, le journal doit indiquer la forme exacte de chaque entrée, la taille du lot et le nombre d’itérations validées.

La réduction est acceptable si le modèle termine le cycle minimal défini par le projet, si la mémoire se stabilise et si les sorties restent comparables à la référence. Elle ne prouve toutefois pas que la configuration originale est viable. Si le modèle est destiné à une publication ou à une application, il faut conserver la configuration qui produit les résultats scientifiques et documenter séparément la configuration réduite utilisée pour le débogage.

Le cache et les formes dynamiques exigent des mesures distinctes

Une mémoire qui ne redescend pas immédiatement n’est pas forcément une fuite. L’allocateur peut conserver des blocs inutilisés afin d’éviter de nouvelles allocations. La fonction torch.mps.empty_cache() libère la mémoire inutilisée du cache, mais elle ne détruit pas les tenseurs encore référencés et ne supprime pas un graphe de calcul conservé par le programme.

Le test utile consiste à mesurer avant et après une phase contrôlée :

import torch

def mps_snapshot(label):
    print(
        label,
        "tensors=", torch.mps.current_allocated_memory(),
        "driver=", torch.mps.driver_allocated_memory(),
    )

mps_snapshot("avant")
# Une seule phase de calcul ici
mps_snapshot("apres_calcul")

torch.mps.empty_cache()
mps_snapshot("apres_cache")

Ces valeurs doivent être accompagnées de la pression mémoire macOS. Une baisse de la mémoire des tenseurs avec une mémoire pilote qui reste élevée peut correspondre à un comportement d’allocation différent, à des ressources encore détenues par le backend ou à une autre partie du programme. Nous ne transformons pas cette observation en diagnostic sans reproduire le cas minimal.

Les formes dynamiques sont un autre axe. Un entraînement qui reçoit des séquences ou des images de dimensions variables peut multiplier les allocations et les chemins de compilation. Nous réalisons donc deux essais :

  • une série à forme fixe, avec les mêmes dimensions à chaque itération ;
  • une série à formes variables, représentative des données réelles.

Si seule la seconde série progresse, la forme des entrées devient une hypothèse prioritaire. Si les deux séries progressent, il faut inspecter les références Python, les sorties et les états de l’optimiseur avant de modifier l’environnement.

Attention : empty_cache() n’est pas un bouton de remise à zéro du processus. L’appeler à chaque itération peut changer le comportement de l’allocateur sans supprimer la référence qui retient réellement la mémoire.

Les références Python peuvent conserver le graphe de calcul

Le cas le plus trompeur apparaît lorsque le code semble ne conserver qu’une valeur scalaire, alors qu’il ajoute en réalité un tenseur attaché à autograd dans une liste ou un objet de journalisation. Une boucle comme celle-ci peut retenir progressivement des graphes :

historique.append(loss)
predictions.append(sortie)

Pour une statistique destinée uniquement à l’affichage, il faut extraire une valeur Python ou détacher explicitement le tenseur selon le besoin du protocole :

historique.append(loss.detach().item())
predictions.append(sortie.detach().cpu())

Le choix dépend de la suite du calcul. Déplacer chaque prédiction vers le CPU peut à son tour créer une pression mémoire côté système si les résultats sont nombreux. Nous supprimons donc provisoirement toute conservation de sortie et vérifions si la croissance disparaît.

En inférence, nous contrôlons la portée de torch.no_grad() ou de torch.inference_mode(). En entraînement, nous vérifions le nettoyage des gradients, les états cachés récurrents et les objets qui traversent plusieurs itérations. Une variable de journalisation, une fermeture Python ou une structure de métriques peut prolonger la durée de vie d’un tenseur sans que la boucle principale le montre clairement.

Le test décisif est une boucle minimale : un lot fixe, une passe avant, une perte, une rétropropagation, une mise à jour et aucune sauvegarde de sortie. Si cette boucle reste stable tandis que le programme complet progresse, le défaut se trouve probablement dans le code périphérique ou la gestion des résultats, pas dans la seule capacité MPS.

Le repli CPU peut modifier toute la trajectoire mémoire

Certains opérateurs MPS peuvent être absents, limités ou exécutés selon des conditions particulières. La documentation PyTorch consacrée au backend MPS doit être consultée pour vérifier la prise en charge de l’opération utilisée. Un projet peut aussi mélanger plusieurs chemins : entrées encore sur le CPU, transferts explicites, opérateurs exécutés ailleurs ou repli automatique.

Nous isolons ces possibilités avec deux exécutions du même script :

  1. un parcours entièrement prévu pour MPS ;
  2. un parcours CPU, avec les mêmes entrées et la même graine lorsque cela reste pertinent.

Nous enregistrons l’étape exacte où le résultat diverge : transfert, opérateur, perte, rétropropagation ou sauvegarde. Il faut aussi inspecter les options d’environnement au lieu de copier une variable trouvée dans un forum. La documentation officielle des variables MPS décrit leur rôle et leurs limites ; elle ne justifie pas une désactivation aveugle des protections mémoire.

Un repli CPU peut réduire la charge MPS tout en augmentant la mémoire système, les copies et le temps d’exécution. Il peut également rendre les résultats ou les performances non comparables à une exécution entièrement MPS. Pour un résultat scientifique, « le script termine » n’est donc pas le seul critère : il faut préciser où chaque opération s’exécute et conserver une comparaison Linux GPU si celle-ci constitue la référence du projet.

La checklist d’acceptation évite les fausses corrections

Avant de déclarer le problème résolu, nous utilisons cette checklist. Elle sert à distinguer une correction du code d’un simple contournement qui déplace la saturation.

  • [ ] Le message complet et l’itération d’échec sont archivés.
  • [ ] Les versions PyTorch, Python et macOS, ainsi que la puce Apple Silicon, sont consignées.
  • [ ] Les formes d’entrée, la taille du lot et la précision sont écrites dans le journal.
  • [ ] current_allocated_memory() et driver_allocated_memory() sont relevés aux mêmes étapes.
  • [ ] La pression mémoire macOS est observée pendant le test.
  • [ ] Une série à forme fixe est comparée à une série à formes variables.
  • [ ] Les listes, journaux et sorties conservées avec autograd ont été supprimés ou détachés.
  • [ ] Le modèle minimal termine plusieurs itérations avec une graine identique.
  • [ ] Les opérateurs concernés et le comportement de repli CPU sont documentés.
  • [ ] Le script minimal s’exécute dans un environnement PyTorch 2.14 isolé.
  • [ ] Les sorties sont comparées à Linux GPU sans déclarer une équivalence automatique.
  • [ ] Toute modification de lot, de forme ou de précision est reliée à un résultat mesuré.

Une issue GitHub peut aider à formuler une hypothèse, mais elle reste un signal lié à une combinaison de versions et de modèles. Le rapport utilisateur référencé dans le dépôt PyTorch ne doit pas être présenté comme la preuve d’un défaut généralisé de PyTorch 2.14.

La FAQ couvre les cas qui bloquent le plus souvent

Par où commencer après une erreur « MPS out of memory » ?

Commencez par conserver l’environnement et le message complet, puis mesurez les tenseurs PyTorch, les allocations du pilote et la pression mémoire du système. Réduisez une seule dimension à la fois. Cette séquence indique si la capacité réelle est dépassée avant de faire intervenir le cache ou les variables d’environnement.

Pourquoi le cache semble-t-il rester plein après empty_cache() ?

La fonction ne libère que les blocs inutilisés du cache. Les tenseurs vivants, les graphes autograd, les états de l’optimiseur et certaines ressources du pilote restent en dehors de cette action. Comparez donc les trois niveaux de mesure et recherchez d’abord les références Python qui prolongent la durée de vie des objets.

Quelle mesure représente la mémoire MPS réelle ?

Aucune mesure isolée ne suffit. current_allocated_memory() concerne les tenseurs suivis par PyTorch, tandis que driver_allocated_memory() décrit une enveloppe gérée par le pilote. Moniteur d’activité ajoute la pression globale du système. Leur évolution conjointe est plus informative qu’une valeur unique observée après l’erreur.

Pourquoi la réduction du lot ne stabilise-t-elle pas toujours l’entraînement ?

Parce que le lot ne contrôle ni les graphes conservés, ni les formes variables, ni les sorties ajoutées à une liste, ni les transferts CPU. Une boucle minimale à forme fixe permet de vérifier si la croissance appartient au modèle ou à la logique de suivi, de métrique et de sauvegarde.

Comment travailler sans Mac dans un laboratoire ?

Le laboratoire peut préparer un paquet de reproduction et l’exécuter temporairement sur un véritable Mac Apple Silicon distant. L’intérêt n’est pas seulement d’obtenir une machine : il faut verrouiller les dépendances, enregistrer les mesures et conserver un contre-test Linux GPU. Une correction n’est validée qu’après comparaison des sorties et de la trajectoire mémoire.

Trois choix d’environnement, selon le niveau de preuve attendu

Le tableau suivant ne prétend pas classer les plateformes par performance. Il aide à choisir l’environnement qui répond au problème de diagnostic.

Option Ce qu’elle permet de vérifier Limite à documenter Décision raisonnable
Mac Apple Silicon local Reproduire le chemin MPS dans le contexte quotidien Applications, caches et dépendances historiques peuvent polluer le test À conserver si l’environnement est déjà maîtrisé
Mac Apple Silicon propre et distant Isoler PyTorch 2.14, le système et le script minimal L’accès distant ne remplace pas une validation longue durée À privilégier pour trancher un défaut d’environnement
Linux GPU Maintenir une référence de production ou de calcul Ce n’est pas une preuve que le chemin MPS est équivalent À conserver pour la double validation scientifique
Repli CPU Vérifier la logique et la forme des résultats Mémoire, copies et comportement numérique peuvent différer À utiliser comme contrôle, pas comme équivalent MPS

Si le laboratoire ne possède aucun Mac, JexMac peut servir de point d’accès à une machine Apple Silicon distante pour la reproduction. La valeur de cette approche dépend toutefois du paquet d’acceptation : sans script minimal, journal de mémoire et versions verrouillées, une session distante ne fait que déplacer l’incertitude.

Le coût doit être comparé au niveau de preuve, pas seulement à la machine

Un achat local mobilise un budget matériel et impose ensuite la maintenance, les mises à jour et la conservation d’un poste rarement utilisé. Une location courte peut être rationnelle lorsqu’il faut uniquement reproduire une erreur, vérifier une correction ou tester un projet macOS avant une livraison.

Situation du projet Ressource principale Coût à surveiller Risque scientifique
Débogage ponctuel Accès temporaire à Apple Silicon Durée d’accès et préparation de l’environnement Confondre correction et disparition accidentelle de l’erreur
Entraînement récurrent et lourd Linux GPU ou infrastructure dédiée Temps de calcul, stockage et maintenance Déclarer les résultats MPS et GPU équivalents sans protocole
Compatibilité macOS Mac local ou distant propre Recréation des dépendances et archivage Tester sur une machine déjà contaminée
Projet hybride Linux GPU plus Apple Silicon Synchronisation des scripts et données Oublier de comparer les sorties et non seulement la fin du programme

Pour une utilisation ponctuelle, consultez les formules de location Mac et comparez-les au coût réel d’un achat, sans supposer qu’une location est automatiquement préférable. Un projet qui exige une charge soutenue, un accès physique à des périphériques ou une disponibilité permanente peut justifier un poste local ou une infrastructure dédiée.

L’environnement propre doit produire un paquet reproductible

Nous préparons le test dans un répertoire isolé, sans réutiliser automatiquement les caches du projet local. Le paquet doit contenir le fichier de dépendances verrouillé, le script minimal, l’échantillon d’entrée, les commandes de mesure et un fichier décrivant le système.

La procédure opérationnelle est la suivante :

  1. créer l’environnement avec la version PyTorch à tester et ne pas installer d’extension non nécessaire ;
  2. exécuter une commande qui imprime les versions, la puce et le périphérique sélectionné ;
  3. lancer le script sans modification sur une forme fixe ;
  4. enregistrer les mesures avant et après chaque phase importante ;
  5. reproduire l’échec ou la stabilité avec les mêmes entrées ;
  6. comparer le résultat avec l’exécution Linux GPU ;
  7. faire rejouer le paquet par une seconde personne à partir du fichier de verrouillage.

Si l’erreur n’existe que dans une combinaison précise de PyTorch 2.14, de macOS et de modèle, nous verrouillons cette combinaison au lieu d’annoncer une correction générale. Si l’erreur disparaît uniquement dans l’environnement propre, nous inspectons la pollution de l’environnement local. Si elle persiste sur Apple Silicon mais pas sur Linux GPU, les deux pistes doivent rester séparées jusqu’à ce que le projet définisse un critère d’équivalence acceptable.

Le choix final dépend de la stabilité démontrée

Résultat du test Interprétation la plus prudente Action suivante
La mémoire se stabilise après suppression des références Le code conservait probablement des tenseurs ou graphes Corriger le cycle de vie et rejouer le protocole complet
La forme fixe fonctionne, la forme variable progresse Les dimensions dynamiques sont un facteur prioritaire Encadrer les formes ou revoir la stratégie d’allocation
Le pilote reste haut mais les tenseurs baissent Cache ou ressources backend à examiner Comparer plusieurs exécutions propres avant de conclure
Le script minimal échoue encore dans un environnement propre La capacité, l’opérateur ou la combinaison logicielle reste en cause Réduire le problème, consulter la documentation et conserver la version reproductible
MPS et Linux GPU divergent Les chemins ne sont pas scientifiquement interchangeables par défaut Maintenir une double validation et comparer les sorties pertinentes

Le point important est la limite de la mise à niveau : PyTorch 2.14 apporte des changements officiels dans les chemins MPS, mais ceux-ci ne remplacent ni l’analyse du graphe, ni le contrôle des formes, ni la vérification des opérateurs. Nous ne retirons donc pas une protection mémoire simplement pour obtenir une exécution qui termine.

Si votre solution actuelle consiste à utiliser exclusivement Linux GPU, elle peut être solide pour l’entraînement, mais elle ne reproduit pas le chemin MPS nécessaire à une validation macOS. Si elle consiste à conserver un Mac local ancien et chargé de dépendances, les caches, les extensions et les versions implicites rendent la reproduction difficile. Une machine dédiée achetée pour un seul incident immobilise en outre un budget qui pourrait ne servir qu’à quelques sessions de diagnostic. Dans ce cas précis, louer temporairement un Mac Apple Silicon propre avec JexMac offre une expérience plus contrôlable : vous pouvez appliquer le même paquet de reproduction, confirmer la correction, puis revenir à Linux GPU ou maintenir les deux pistes selon les preuves obtenues.

FAQ

Par quoi commencer lorsqu’une erreur « MPS out of memory » apparaît dans PyTorch 2.14 ?

Commencez par conserver le message complet, la version de PyTorch, Python et macOS, le modèle, la forme des entrées et le numéro d’itération. Mesurez ensuite la mémoire allouée par PyTorch et la mémoire réservée par le pilote. Ne désactivez pas immédiatement une limite de mémoire : cette action masque souvent la différence entre une vraie charge de tenseurs, un cache ou une fuite de références.

Pourquoi torch.mps.empty_cache ne libère-t-il pas toute la mémoire visible dans macOS ?

Cette fonction libère uniquement la mémoire inutilisée conservée dans le cache de l’allocateur MPS. Elle ne peut pas supprimer les tenseurs encore référencés, les graphes de calcul, les états de l’optimiseur ni certaines allocations déjà comptabilisées par le pilote. Il faut donc comparer current_allocated_memory, driver_allocated_memory et la pression mémoire du système au lieu d’attendre une remise à zéro.

Comment observer la mémoire réellement utilisée pendant un entraînement Apple Silicon ?

Ajoutez des points de mesure autour de la création du modèle, du transfert des entrées, de la passe avant, de la rétropropagation et de la mise à jour. Utilisez les API MPS documentées pour la mémoire allouée par PyTorch et celle allouée par le pilote, puis consignez la pression mémoire dans Moniteur d’activité. Une seule métrique ne suffit pas pour conclure.

Pourquoi la mémoire MPS continue-t-elle d’augmenter après une réduction de la taille des lots ?

La taille du lot ne contrôle pas toutes les sources de croissance. Une liste qui conserve loss ou prédictions avec autograd, des formes d’entrée variables, un état caché non détaché, un cache d’allocations ou un opérateur transféré sur le CPU peuvent maintenir ou recréer de la mémoire. Reproduisez avec une forme fixe, une boucle minimale et aucune conservation de sortie avant de modifier d’autres paramètres.

Comment reproduire une erreur MPS lorsque le laboratoire ne possède aucun Mac ?

Préparez un paquet comprenant l’environnement verrouillé, le script minimal, un échantillon d’entrée, les commandes de mesure et la sortie attendue, puis exécutez-le sur un véritable Mac Apple Silicon distant. Comparez le résultat avec Linux GPU et conservez les versions exactes. Cette approche permet de séparer un défaut du code, une combinaison PyTorch-macOS particulière et une pollution de l’environnement local.

Bare metal · 1–5 min

Testez vos entraînements MPS sur un Mac dédié avec JexMac

Louez un Mac mini M4 physique et dédié pour reproduire vos essais scientifiques dans un environnement macOS distant, sans partage de ressources.

Config standard
PuceApple M4 · 38 TOPS
CPU10 cœurs (4P + 6E)
Mémoire16 Go mémoire unifiée
Réseau1 Gbps dédié
SLA99,9 % disponibilité
Livraison1–5 min auto