MLX sur Apple Silicon : quand vous avez besoin de votre propre modèle, pas de celui d'Apple
Le framework Foundation Models d’Apple vous met entre les mains un seul modèle : celui du système, scellé, gratuit et mis à jour au rythme d’Apple. Pour la plupart des traitements de langage sur l’appareil, c’est le bon outil, et chercher à le contourner est une erreur. Mais certains travaux exigent un modèle que vous choisissez : un LLM à poids ouverts précis, une version que vous figez, un fine-tune entraîné sur vos propres données, ou une capacité que le modèle du système n’a pas. Lorsque vous avez besoin de faire tourner votre propre modèle sur l’appareil, la couche située sous Foundation Models est MLX1.
MLX est le framework de tableaux d’Apple pour l’apprentissage automatique sur Apple Silicon, doté d’une API Swift (MLX Swift) que vous intégrez directement dans une app2. Ce n’est pas un framework système que vous appelez ; c’est une bibliothèque que vous livrez, avec les poids du modèle. Cette différence constitue tout l’arbitrage, et la comprendre, c’est savoir décider s’il faut descendre d’une couche ou rester là où Apple vous a placé.
TL;DR
- MLX est un framework de tableaux façon NumPy conçu pour Apple Silicon, avec évaluation paresseuse, transformations de fonctions composables et un backend Metal2.
- Le modèle de mémoire unifiée explique pourquoi ça marche sur un téléphone. Les tableaux résident dans un unique pool de mémoire partagé par le CPU et le GPU, si bien que MLX s’exécute sur les deux à partir des mêmes tampons, sans le coût de copie de l’hôte vers le périphérique3.
- Faites tourner un LLM à poids ouverts sur l’appareil avec
LLMModelFactory, en pointant vers un modèle quantifié commemlx-community/Llama-3.2-3B-Instruct-4bit, puis générez via uneChatSession4. - Affinez avec des adaptateurs LoRA : entraînez un petit adaptateur, livrez
adapters.safetensors, etload(into:)remplace les couchesLineardu modèle de base par desLoRALinearà l’exécution5. - Le coût de votre propre modèle : la taille de l’app (les poids sont volumineux), la pression mémoire, l’absence d’intégration système, et c’est vous qui assumez chaque mise à jour. Foundation Models n’a aucun de ces coûts, parce que c’est Apple qui les paie.
Ce qu’est MLX, et pourquoi Apple Silicon le rend possible
MLX vous donne des tableaux et des opérations qui ressemblent à NumPy, plus les transformations dont l’apprentissage automatique a besoin : différenciation automatique, vectorisation et évaluation paresseuse qui construit un graphe de calcul et ne l’exécute que lorsque vous lisez un résultat2. En soi, cela décrit une douzaine de frameworks. Ce qui permet à MLX de faire tourner un modèle de plusieurs milliards de paramètres sur un appareil tenant dans votre poche, c’est le modèle de mémoire.
Sur un GPU de bureau, les données résident dans la RAM système et vous les copiez à travers un bus vers la mémoire distincte du GPU pour les calculer, puis vous recopiez les résultats. Cette copie, c’est l’impôt, et pour un grand modèle il est brutal. Apple Silicon dispose d’une mémoire unifiée : un seul pool que le CPU, le GPU et le Neural Engine adressent tous directement. MLX est bâti autour de ce fait3. Un tableau n’est pas « sur le CPU » ou « sur le GPU » ; il est en mémoire, et n’importe quel processeur opère dessus sur place. Aucune copie, aucun impôt de bus. Un modèle de 3 milliards de paramètres quantifié à 4 bits tient dans quelques gigaoctets et s’exécute sans les allers-retours qui rendraient le même travail impraticable sur une machine à GPU dédié dotée d’une mémoire comparable. La décision matérielle qu’Apple a prise il y a des années est la raison pour laquelle l’inférence d’un vrai modèle sur l’appareil est tout simplement viable, et l’architecture en tuiles à mémoire unifiée est le substrat sur lequel MLX repose.
Faire tourner un LLM sur l’appareil
Le chemin de « je veux un modèle précis » jusqu’au texte à l’écran est court. La couche LLM de MLX Swift charge un modèle quantifié depuis le Hugging Face Hub et l’exécute4 :
let container = try await LLMModelFactory.shared.loadContainer(
from: HubClient.default,
using: TokenizersLoader(),
configuration: .init(id: "mlx-community/Llama-3.2-3B-Instruct-4bit")
)
let session = ChatSession(container)
let response = try await session.respond(to: "Summarize this in one line: \(text)")
Pour une interface jeton par jeton, générez plutôt un flux et affichez les fragments à mesure qu’ils arrivent4 :
let input = try await container.prepare(input: UserInput(prompt: prompt))
let stream = try await container.generate(input: input, parameters: GenerateParameters())
for await event in stream {
if case let .chunk(text) = event { /* ajouter à l'interface */ }
}
Deux détails portent l’essentiel du poids pratique. D’abord, le 4bit dans l’identifiant du modèle n’est pas un enjolivement facultatif : c’est la quantification qui fait tenir le modèle en mémoire et le fait tourner à une vitesse utilisable sur un appareil. Vous livrez des poids en 4 bits (ou moins), pas en pleine précision. Ensuite, les poids sont volumineux même quantifiés, vous décidez donc délibérément de les empaqueter dans l’app (immédiat, mais un téléchargement lourd) ou de les récupérer au premier lancement (binaire léger, mais une attente et un chemin d’échec à gérer). Foundation Models ne pose jamais cette question, parce que le modèle est déjà sur l’appareil. Avec MLX, les poids sont votre problème.
Fine-tuning : un adaptateur LoRA, pas un nouveau modèle
La raison d’apporter votre propre modèle est rarement le modèle de base lui-même ; c’est de lui enseigner votre domaine. Un fine-tuning complet d’un modèle de plusieurs milliards de paramètres sur l’appareil n’est pas la bonne approche. LoRA (low-rank adaptation) l’est : vous entraînez un petit ensemble de poids d’adaptateur qui ajustent le comportement du modèle de base, en laissant la base intacte. L’adaptateur pèse des mégaoctets, pas des gigaoctets5.
MLX Swift charge un adaptateur entraîné depuis un répertoire contenant adapter_config.json et adapters.safetensors, puis l’applique à un modèle déjà chargé dans un conteneur5 :
let adapter = try LoRAContainer.from(directory: adapterURL)
await container.update { context in
try? adapter.load(into: context.model) // remplace les couches Linear par LoRALinear
}
load(into:) remplace les couches Linear standard du modèle par des couches LoRALinear qui intègrent les deltas de rang faible de l’adaptateur, de sorte que l’inférence reflète désormais votre fine-tune. Comme le modèle réside à l’intérieur du conteneur, vous appliquez l’adaptateur via container.update, et vous pouvez permuter les adaptateurs à chaud à l’exécution (en décharger un avec unload(from:), en charger un autre avec load(into:)) pour donner à un même modèle de base un comportement différent selon la fonctionnalité. Le schéma reflète ce qu’Apple propose pour le modèle du système via les adaptateurs personnalisés de Foundation Models : la différence, c’est qu’ici vous possédez le modèle de base, le pipeline d’entraînement et le résultat, au lieu d’adapter un modèle que vous ne pouvez pas voir.
La décision : Foundation Models, MLX ou le cloud
Trois couches, et un mauvais choix vous coûte soit de la capacité, soit un tas de travail évitable.
- Foundation Models quand le modèle du système peut accomplir la tâche. Gratuit, privé, aucun poids à livrer, aucune mémoire à gérer, et une intégration système que vous obtenez pour rien. C’est le choix par défaut. Les tâches de langage sur l’appareil pour lesquelles Apple l’a conçu (résumer, classer, extraire, réécrire, sortie structurée) relèvent d’ici, un point c’est tout.
- MLX quand vous avez besoin d’un modèle que le système ne vous donne pas : un LLM à poids ouverts précis, une version figée qui ne bouge pas au gré d’une mise à jour de l’OS, un fine-tune de domaine, ou une architecture (un modèle vision-langage, un modèle non textuel) hors du périmètre de Foundation Models. Vous payez en taille d’app, en mémoire et en responsabilité, et vous achetez le contrôle.
- Le cloud quand le modèle doit vraiment être grand : raisonnement de pointe, analyse à long contexte, tout ce que font les plus grands modèles qu’un modèle sur l’appareil de quelques milliards de paramètres ne peut pas faire. L’exécution sur l’appareil ne remplace pas un modèle de pointe ; c’est un autre point sur la courbe.
La lecture honnête : MLX est un palier inférieur délibéré pour une raison précise, pas un meilleur choix par défaut. Si vous ne pouvez pas nommer la capacité qui manque à Foundation Models pour votre fonctionnalité, vous n’avez pas besoin de MLX, et le livrer signifie trimballer des gigaoctets de poids et un budget mémoire dont vous auriez pu vous passer.
Quand ne pas se tourner vers MLX
- Le modèle du système le fait déjà. Relisez les tâches de Foundation Models. Si la vôtre figure dans la liste, arrêtez-vous ici.
- Vous ne pouvez pas vous offrir les poids. Un petit modèle quantifié reste un actif volumineux. Si la taille de l’app ou le téléchargement au premier lancement est une contrainte réelle pour vos utilisateurs, cette contrainte peut trancher la question à elle seule.
- Vous avez besoin du chemin le plus économe en énergie du Neural Engine pour un modèle figé. Pour un modèle connu et livré qui ne change pas, Core ML et son convertisseur ciblent le Neural Engine avec la consommation et la latence les plus serrées. MLX brille pour la flexibilité et l’itération de niveau recherche ; Core ML brille pour un modèle de production verrouillé. Ce sont des outils différents, et le « ML sur l’appareil » n’est pas une décision unique.
- Vous ne le maintiendrez pas. Votre propre modèle signifie que vous assumez ses mises à jour, sa sécurité et sa dérive. Apple met à jour le modèle du système à votre place. Si vous n’avez pas les effectifs pour assumer un modèle, n’en adoptez pas.
La compétence que MLX récompense, c’est la retenue quant au moment de l’utiliser. Le framework est réellement remarquable : un vrai modèle de langage, affiné pour votre domaine, fonctionnant entièrement sur l’appareil sans serveur ni coût par jeton, sur un matériel dont l’architecture mémoire a été conçue exactement pour cela. Cette capacité mérite qu’on s’y tourne quand on en a nommé la raison. Tournez-vous-y sans raison et vous aurez échangé le modèle gratuit, maintenu et intégré d’Apple contre une copie plus lourde, non maintenue, que vous possédez désormais. Le jugement, c’est tout le travail.
FAQ
Qu’est-ce que le framework MLX d’Apple ?
MLX est un framework de tableaux pour l’apprentissage automatique sur Apple Silicon, doté d’une API façon NumPy, de transformations de fonctions composables (différenciation automatique, vectorisation), de calcul paresseux et d’un backend Metal2. MLX Swift est l’API Swift permettant de l’intégrer dans des apps, afin que vous puissiez exécuter et affiner vos propres modèles sur l’appareil.
Comment MLX utilise-t-il la mémoire unifiée d’Apple Silicon ?
Les tableaux MLX résident en mémoire partagée, si bien que les opérations s’exécutent sur le CPU ou le GPU sans copier les données entre des pools de mémoire distincts3. Cette propriété de transfert nul est précisément ce qui rend l’architecture à mémoire unifiée d’Apple Silicon efficace pour l’exécution de modèles sur l’appareil.
Puis-je exécuter un LLM à poids ouverts sur l’appareil avec MLX ?
Oui. LLMModelFactory.shared.loadContainer(from:using:configuration:) charge un modèle quantifié tel que mlx-community/Llama-3.2-3B-Instruct-4bit depuis le Hugging Face Hub ; ChatSession vous fournit respond(to:) pour les appels uniques, et container.generate(input:parameters:) diffuse des événements .chunk(text) pour une sortie incrémentale4.
Comment affiner un modèle avec MLX ?
Avec un adaptateur LoRA plutôt qu’un nouveau modèle. LoRAContainer.from(directory:) charge un adaptateur depuis un répertoire contenant adapter_config.json et adapters.safetensors ; appliqué via container.update, il remplace les couches Linear du modèle par des couches LoRALinear et peut permuter les adaptateurs à chaud à l’exécution5.
MLX, Foundation Models ou Core ML : lequel choisir ?
Optez par défaut pour Foundation Models quand le modèle du système d’Apple peut accomplir la tâche (gratuit, privé, aucun poids à livrer)1. Ne vous tournez vers MLX que lorsque vous avez besoin d’un modèle que le système ne vous donne pas : un LLM à poids ouverts précis, une version figée, un fine-tune de domaine, ou une architecture hors du périmètre de Foundation Models. Utilisez Core ML pour un modèle de production verrouillé qui exige le chemin le plus économe en énergie du Neural Engine, et le cloud quand le modèle doit vraiment être à l’échelle de pointe.
Quand ne devrais-je pas me tourner vers MLX ?
Quand le modèle du système le fait déjà, quand vous ne pouvez pas vous permettre de livrer des gigaoctets de poids, quand un modèle figé serait mieux servi par le chemin Neural Engine le plus économe en énergie de Core ML, ou quand vous n’avez pas les effectifs pour assumer les mises à jour, la sécurité et la dérive d’un modèle. MLX est un palier inférieur délibéré pour une raison nommée, pas un meilleur choix par défaut.
-
Positionnement de MLX par rapport au framework Foundation Models : Foundation Models expose le modèle système fixe d’Apple sur l’appareil (voir Apple Foundation Models : le framework de LLM sur l’appareil) ; MLX exécute des modèles que vous sélectionnez et affinez. Les deux répondent à des besoins différents à des couches différentes de la pile sur l’appareil. ↩↩
-
Apple Machine Learning Research, MLX et MLX Swift. MLX est un framework de tableaux pour l’apprentissage automatique sur Apple Silicon, doté d’une API façon NumPy, de transformations de fonctions composables (différenciation automatique, vectorisation), de calcul paresseux et d’un backend Metal. MLX Swift est l’API Swift permettant de l’intégrer dans des apps. ↩↩↩↩
-
Documentation MLX, unified memory. Les tableaux MLX résident en mémoire partagée ; les opérations peuvent s’exécuter sur le CPU ou le GPU sans transférer les données entre des pools de mémoire distincts, ce qui est la propriété qui rend l’architecture à mémoire unifiée d’Apple Silicon efficace pour l’exécution de modèles sur l’appareil. Contexte sur le matériel : le TBDR et la mémoire unifiée d’Apple Silicon. ↩↩↩
-
Apple Machine Learning Research, MLX Swift Examples / MLX Swift LM.
LLMModelFactory.shared.loadContainer(from:using:configuration:)charge un modèle quantifié (par exemplemlx-community/Llama-3.2-3B-Instruct-4bit) depuis le Hugging Face Hub ;ChatSessionfournitrespond(to:)pour les appels uniques, etcontainer.generate(input:parameters:)produit un flux d’événements.chunk(text)pour une sortie incrémentale viaGenerateParametersetUserInput. ↩↩↩↩ -
Apple Machine Learning Research, MLX Swift LM LoRA adapters reference.
LoRAContainer.from(directory:)charge un adaptateur depuis un répertoire contenantadapter_config.jsonetadapters.safetensors; appliqué viacontainer.update,adapter.load(into: context.model)remplace les couchesLineardu modèle par des couchesLoRALinear, etunload(from:)en décharge un afin que les adaptateurs puissent être permutés à chaud à l’exécution. Comparez le chemin du modèle système d’Apple dans les adaptateurs personnalisés de Foundation Models. ↩↩↩↩ -
Travail pratique de l’auteur avec MLX : une boucle de recherche en apprentissage automatique autonome qui exécute des expériences d’entraînement à budget fixe sur Apple Silicon via MLX, en modifiant de façon autonome l’architecture et les hyperparamètres pour minimiser les bits par octet de validation et en ne conservant que les améliorations. Le comportement de mémoire unifiée et de quantification décrit ici reflète cette expérimentation. ↩