Dans les deux articles précédents (sur les empreintes perceptuelles dans le cadre de Chat Control et sur leurs collisions adversariales), nous avons vu comment 40 lignes de Python permettent de résoudre un problème que l’industrie déploie ensuite à une échelle mondiale. Les empreintes perceptuelles sont l’exemple classique d’une couche déterministe peu coûteuse : sans modèle, sans GPU, sans dépendances lourdes.
Les empreintes permettent de détecter les duplications et similitudes. Mais dans un pipeline de traitement d’images réaliste, certaines tâches ne peuvent pas être accomplies avec des algorithmes classiques: détecter les bounding boxes d’un filigrane arbitraire, combler les zones manquantes avec de l’inpainting respectant le contexte visuel, classifier si un visage est adulte, ou extraire des attributs sémantiques. Ces tâches nécessitent des réseaux neuronaux de grande envergure.
La question à laquelle répond cet article est la suivante : Comment déployer ces réseaux sur Apple Silicon sans dépendre des APIs cloud, sans payer des frais par image, et en tirant parti de l’Apple Neural Engine ? Réponse courte : PyTorch → ONNX → CoreML, en trois commandes. Réponse longue : la vraie valeur n’est pas technique mais architecturale. Le modèle sous-jacent est le même, que je l’applique à l’analyse de sentiment, à la modération d’images ou à d’autres domaines apparemment sans rapport.
Le modèle : deux couches, une philosophie
Il y a quelques semaines, j’ai publié SentimentKit, une bibliothèque d’analyse de sentiment qui est née après avoir découvert que NLTagger d’Apple qualifiait “supprimer le fichier temporaire” comme -0,8 (très négatif). Le problème n’était pas spécifique à Apple : c’est une classe entière de biais systématiques dans les modèles de machine learning pré-entraînés.
La solution n’a pas été de « chercher un meilleur modèle ». Elle a été architecturale. SentimentKit suit un pipeline en quatre couches :
- Détection par mots-clés déterministes. Dictionnaires spécialisés pour la profanité, la frustration et les expressions positives dans 8 langues (env. 20 Ko). Cette couche intervient en premier.
- NLTagger d’Apple (avec correction des biais techniques), seulement si le message n’active pas la couche 1.
- Modèle spécifique au domaine (règles + heuristiques pour textes techniques et de code).
- Modeles fondamentaux (LLM local fourni par Apple) uniquement si les trois couches précédentes renvoient une ambiguïté.
Le principe est clair : la couche déterministe peu coûteuse intervient en premier, et le machine learning est réservé aux cas que les couches économiques ne peuvent pas résoudre. 70 à 80 % du trafic sont réglés dès la première couche, sans toucher au modèle. Cela réduit la consommation énergétique, la latence et les risques d’erreurs d’interprétation.
Quelques semaines plus tard, en concevant un pipeline de nettoyage d’images à grande échelle, je me suis rendu compte que j’utilisais involontairement le même modèle :
- Validation déterministe (Pillow verify, magic bytes, limites de dimensions). Élimine les évidences.
- Empreintes perceptuelles (aHash + dHash + pHash). Grouper les doublons, ~10-15 ms par image.
- OCR classique avec regex pour les tokens connus. Marque les watermarks textuels.
- Réseaux neuronaux (YOLOv11 pour la détection, LaMa pour l’inpainting), uniquement sur les images clarifiées, qui représentent ~10 à 20 % du volume initial.
Il ne s’agit pas de coïncidences. C’est la même philosophie appliquée à un domaine différent. Et la question clé, que j’ai dû résoudre à maintes reprises en production, reste la même : comment faire en sorte que les systèmes neuronaux s’exécutent aussi économiquement que possible, sans dépendances aux APIs cloud ni infrastructure GPU propriétaire.
La réponse, sur Apple Silicon, c’est ANE via CoreML. Et le pont entre PyTorch (où naissent les modèles) et CoreML (où ils sont déployés) s’appelle ONNX.
ONNX : le langage intermédiaire sous-estimé
ONNX (Open Neural Network Exchange) est un format d’échange pour les modèles de réseaux neuronaux. Maintenu par une fondation incluant Microsoft, Meta, NVIDIA, entre autres, il définit comment sérialiser le graphe computationnel d’un modèle — ses opérations, connexions et paramètres — dans un fichier portable.
Pourquoi c’est crucial : il découple l’entraînement du déploiement.
Avant ONNX, entraîner un modèle sur PyTorch vous liait à PyTorch en production. Pour changer vers TensorFlow Serving, CoreML ou un runtime intégré, il fallait tout reprogrammer. Ce processus complexe était source d’erreurs et multiplié pour chaque combinaison de frameworks.
ONNX agit comme pivot. Le processus devient :
PyTorch (entraînement) → ONNX (échange) → Runtime X (production)
Avec Runtime X pouvant aller de onnxruntime (multiple backend) à CoreML (Apple), en passant par TensorRT (NVIDIA) ou OpenVINO (Intel).
En exportant le modèle une fois, on laisse le runtime choisir l’optimisation matérielle. Sur Apple Silicon, le backend visé est le CoreML Execution Provider, optimisant CPU, GPU Metal et Apple Neural Engine selon l’opération exécutée.
Limitations honnêtes
Toute opération PyTorch n’a pas son équivalent ONNX. Les modèles modernes incorporant des opérations personnalisées (attention flash, convolutions spécifiques) peuvent créer des incompatibilités. Solution pratique : YOLO, ResNet, modéles standards exportent sans souci. Vérifiez votre modèle si des opérations personnalisées sont utilisées.
Dans notre cas — YOLOv11 fine-tuné et LaMa — les deux ont des exports ONNX reconnus. YOLOv11 s’exporte directement avec ultralytics en une commande. Pour LaMa : une version ONNX est déjà disponible sur HuggingFace grâce à Carve AI.
CoreML : le runtime d’Apple pour le Neural Engine
CoreML est le runtime ML des systèmes iOS et macOS. Introduit avec iOS 11 (2017), il supporte depuis les puces A11 Bionic et tous les Apple Silicon récents. Ces puces permettent l’exécution des modèles sur trois unités :
- CPU. Parfait pour les petits modèles ou quand le parallélisme n’est pas une priorité.
- GPU Metal. Recommandé pour les traitements de lots ou l’entraînement extensif grâce à son aptitude pour des calculs massivement parallèles.
- Apple Neural Engine (ANE). Un coprocesseur dédié aux opérations tensorielles, idéal pour l’inférence à faible consommation. Les puces M-series incluent 16 cœurs ANE permettant ~18 TOPS (Tera Operations Per Second).
CoreML sélectionne automatiquement l’unité optimale, avec ANE priorisé si les calculs sont compatibles. Cela optimise l’efficacité énergétique : comparé à la GPU Metal, l’ANE consomme 3-5 fois moins d’énergie pour des inférences équivalentes.
En revanche, l’ANE ne supporte pas toutes les opérations et ne gère pas l’entraînement. Les modèles utilisant des architectures ou formats standard (quantifiés en FP16/INT8) maximisent sa performance.
Le rôle de onnxruntime-coreml
Microsoft a enrichi onnxruntime avec des Execution Providers qui abstraient les cibles matérielles. Avec le package onnxruntime-coreml, disponible depuis 2022, le runtime peut utiliser CoreML :
import onnxruntime as ort
session = ort.InferenceSession(
"yolo11x-watermark.onnx",
providers=["CoreMLExecutionProvider", "CPUExecutionProvider"],
)
output = session.run(None, {"images": input_tensor})
Ces trois lignes suffisent pour qu’un modèle ONNX tourne sur ANE. Pas besoin de Swift, Xcode ou .mlmodel. Python + ONNX suffisent.
Conversion en trois commandes pratiques
Passons au cas concret : YOLOv11 fine-tuné pour la détection de filigranes.
Étape 1 : récupérer le modèle PyTorch
Pour YOLOv11, le modèle corzent/yolo11x_watermark_detection est utilisé (114 MB, licence MIT) :
hf download corzent/yolo11x_watermark_detection --local-dir ./models
Cela télécharge le fichier best.pt sans nécessiter de token HuggingFace.
Étape 2 : exporter en ONNX
Avec ultralytics :
from ultralytics import YOLO
model = YOLO("./models/best.pt")
model.export(format="onnx", imgsz=640, simplify=True)
# -> ./models/best.onnx (228 MB)
L’option simplify=True optimise la compatibilité ANE. Temps mesuré sur un M3 : 2-3 secondes.
Étape 3 : inférence avec CoreML Execution Provider
import onnxruntime as ort
import numpy as np
from PIL import Image
session = ort.InferenceSession(
"./models/best.onnx",
providers=["CoreMLExecutionProvider", "CPUExecutionProvider"],
)
img = Image.open("photo.jpg").resize((640, 640))
tensor = np.asarray(img, dtype=np.float32).transpose(2, 0, 1)[None] / 255.0
outputs = session.run(None, {"images": tensor})
# Outputs[0]: (1, 5, 8400)
Lors du chargement, le runtime partitionne le graphe pour ANE. Temps mesuré (M3) : 42-48 ms/image après initialisation.
La leçon clé ici : détacher entraînement et déploiement simplifie les pipelines. ONNX avec CoreML est la voie royale pour un traitement rapide, écoénergétique et efficace sur Apple Silicon.
Références
- ONNX specification. Open Neural Network Exchange, GitHub :
onnx/onnx. - Microsoft. Documentation Execution Provider de onnxruntime CoreML.
- Apple. Documentation sur Core ML Framework, Apple Developer.
- Apple. Spécifications du Apple Neural Engine, developer.apple.com.
- Ultralytics. Documentation sur YOLOv11 export, docs.ultralytics.com/modes/export/.
- Apple. Projet coremltools, apple.github.io/coremltools/.
- Carve AI. LaMa-ONNX, HuggingFace :
Carve/LaMa-ONNX. - fancyfeast. joycaption-watermark-detection, HuggingFace.
- Rodríguez, F. “L’analyse de sentiment d’Apple pense que ‘supprimez le fichier temporaire’ est une menace de mort !”, frr.dev 04-05-2026.
- SentimentKit, librairie open-source appliquant ce modèle.
Cet article a été publié en espagnol et traduit avec l’aide de l’IA.