Mesures de vitesse et d'énergie du Neural Engine
La réécriture ANE FP16 améliore la vitesse de prédiction complète de 1.39× et l’énergie système totale estimée par décision de 2.78× par rapport à MLX FP16 compilé. Le candidat W8 K-means validé séparément atteint respectivement 1.42× et 3.19×. Aucun des deux n’atteint l’objectif de 10× demandé. Ce sont des résultats locaux sur M3 Max, avec les limites de précision et de mesure de puissance ci-dessous.
L’implémentation et les expériences de conversion sont dans ANE_ENGINEERING.md ; les bornes mathématiques et les contrats de fidélité dans ANE_MATH.md.
Comparaison finale soutenue sur décision courte
M3 Max, 40 cœurs GPU, 128 GiB, macOS 27.2. Même checkpoint source multilingue, mêmes huit variantes d’état de facture, une question à quatre options par requête, 91 tokens réels complétés à 96. Pas de cache de sortie ni de tokens générés. Les trois modèles restent résidents ; le chargement, la compilation et l’échauffement sont en dehors des intervalles mesurés.
La baseline active mx.compile, le cache de préfixes de prompt et des buckets de forme de
32 tokens. Elle est plus rapide que la baseline MLX eager historique. Le candidat ANE FP16
préserve les poids d’origine, avec un corps de transformer Core ML complet, une recherche
d’embedding sur l’hôte et une queue d’action CPU en FP32. W8 utilise une compression de
palette par K-means regroupé portant uniquement sur les poids, pas une arithmétique W8A8 ;
ses activations utilisent encore FP16 et sa queue d’action hôte reste FP32.
| Métrique | MLX GPU FP16 compilé | ANE FP16 | ANE W8 K-means |
|---|---|---|---|
| Décisions terminées | 17,184 | 23,961 | 24,453 |
| Durée active mesurée | 120.02 s | 120.02 s | 120.02 s |
| P50 de bout en bout | 6.937 ms | 4.976 ms | 4.879 ms |
| P95 de bout en bout | 7.393 ms | 5.307 ms | 5.227 ms |
| Temps écoulé moyen par décision | 6.984 ms | 5.009 ms | 4.908 ms |
| Estimation de puissance système totale moyenne | 61.39 W | 30.75 W | 27.39 W |
| Énergie système totale par décision | 0.4288 J | 0.1540 J | 0.1344 J |
| Énergie par décision moins l’inactivité | 0.3393 J | 0.0888 J | 0.0715 J |
| Gain de vitesse vs MLX compilé | 1× | 1.394× | 1.423× |
| Gain d’énergie système totale vs MLX compilé | 1× | 2.784× | 3.189× |
| Gain d’énergie moins l’inactivité vs MLX compilé | 1× | 3.823× | 4.749× |
Les rapports utilisent les moyennes d’intervalle, incluant tout le travail terminé :
FP16: speed 1.394 × average system-power ratio 1.997 = energy gain 2.784
W8: speed 1.423 × average system-power ratio 2.241 = energy gain 3.189
Multiplier à nouveau un rapport d’énergie par la vitesse compte le temps écoulé deux fois. La ligne moins l’inactivité utilise une frontière de mesure différente ; elle ne signifie pas que la puissance de tout l’ordinateur portable chute de 3.8–4.7×. Ce sont des intervalles de débit saturé. Une expérience à débit de requêtes égal serait nécessaire pour une affirmation de puissance à FPS fixe. W8 n’améliore la vitesse moyenne que d’environ 2.1% par rapport à FP16 dans cette session, tandis que son paquet de corps passe de 251.91 à 129.29 MB décimaux. La taille du paquet exclut la table d’embedding du checkpoint/hôte d’origine et n’est pas la mémoire totale du runtime.
Chaque implémentation a exécuté six blocs de 20 secondes en trois cycles équilibrés de
MLX, ANE FP16, ANE W8, ANE W8, ANE FP16, MLX. Dix secondes d’échantillonnage d’inactivité
séparent les blocs ; les trois premières secondes d’inactivité sont ignorées, et la
puissance d’inactivité stabilisée adjacente est moyennée. Les plages de puissance par bloc
étaient 60.32–62.38 W pour MLX, 29.28–35.14 W pour ANE FP16 et 26.68–27.95 W pour ANE W8.
D’autres applications de bureau étaient ouvertes ; l’alternance et l’échantillonnage
d’inactivité adjacent réduisent mais n’éliminent pas l’incertitude liée à la charge de fond
et aux capteurs.
Les 65,598 prédictions correspondent toutes à la sortie d’échauffement arrondie de leur backend pour l’état correspondant. Les trois backends sélectionnent la même réponse sur ces huit états. La suite de fidélité distincte est plus large : FP16 L96 passe 59/59 questions de fitting avec une dérive maximale de probabilité de 0.002925 ; W8 passe ces mêmes 59 avec une dérive de 0.014393 sous le seuil inchangé de 0.02. Le résultat complet 63/63 appartient au modèle FP16 L1024 exporté séparément. Ce sont des fixtures de régression, pas une affirmation d’exactitude générale sur les tâches ni de calibration préservée sur des entrées arbitraires.
L’exécution a conservé 1,101 échantillons de puissance ; l’écart maximal était de 0.510 secondes et la puissance système maximale enregistrée de 74.47 W. Aucun échantillon n’a été ignoré. La RSS par bloc est enregistrée pour le processus partagé avec tous les modèles et tampons d’enregistrement résidents ; ces valeurs ne peuvent pas être attribuées à la mémoire de modèle d’un backend individuel. Les empreintes du runtime et du paquet actuels sont stockées avec le rapport.
Appels bruts finaux et échantillons PSTR · Résumé audité et intervalles bootstrap intra-session
Le pilote FP16 uniquement
antérieur mesurait une vitesse de 1.410× et un gain d’énergie système brut de 2.939×. Il
précède les derniers contrôles d’entrée et l’instrumentation de stabilité par appel ; la
nouvelle exécution à trois bras ci-dessus est la comparaison publiée pour le runtime final.
Une réserve de métadonnées dans le rapport brut final décrivait initialement le plancher
historique de somme de composants macmon de façon inconditionnelle ; une entrée additive
metadata_corrections précise que cette exécution n’a utilisé que PSTR. Les champs d’origine
et toutes les mesures sont préservés.
La compatibilité Snake est une charge de travail distincte
Le même planificateur Snake publié, les mêmes prompts compacts et la même politique de sécurité ont tourné à la fois sur l’adaptateur ANE FP16 et sur MLX compilé, en alternant l’ordre d’évaluation sur des états actifs identiques. Les graines 101 et 102 ont chacune terminé 300 pas : 600/600 actions proposées et exécutées concordent, zéro mort et zéro intervention de bouclier. Les scores finaux étaient 9 et 10, avec des longueurs de serpent de 15 et 16. La différence maximale de probabilité de coup était de 0.0036. Cela valide cette comparaison de trajectoires FP16, pas le comportement Snake d’un modèle compressé ni une survie illimitée.
| Graine | Décision complète ANE P50 / P95 | Décision complète MLX compilé P50 / P95 |
|---|---|---|
| 101 | 23.45 / 27.10 ms | 17.14 / 23.58 ms |
| 102 | 17.68 / 27.30 ms | 19.18 / 33.27 ms |
L’adaptateur ANE exécute trois questions séquentiellement en B1/L96 ; MLX met en lot les trois questions jusqu’à L64. Ces temps incluent les caractéristiques du planificateur et les prédictions complètes, excluent le travail de l’autre backend, le pas de jeu et le rendu terminal, et montrent une variation substantielle. Ils n’établissent pas d’accélération Snake cohérente ni de débit de rendu stable maximal. Le résultat à une seule question de 4.98 ms ne doit pas être présenté comme le temps par image Snake complet. Un export B3/L64 ANE dédié serait une tâche d’optimisation et de validation distincte.
États, sorties et temps Snake bruts
python -m benchmarks.snake artifacts/ane-repro/body96/model.mlpackage \
/path/to/original/laya-multilingual --ane --mlx-compiled \
--steps 300 --seeds 101 102 --output artifacts/ane-snake.json
Frontière de mesure et limites de télémétrie
Chaque appel chronométré inclut la construction du prompt, la tokenisation, la construction des tableaux, la recherche d’embedding sur l’hôte le cas échéant, l’exécution synchrone du modèle, les caractéristiques d’action, la calibration et le formatage de sortie. MLX évalue ses sorties paresseuses ; Core ML renvoie des tableaux NumPy complétés. Cela compare des prédictions non mises en cache, pas des kernels de modèle isolés.
La comparaison finale utilise le petit échantillonneur PSTR uniquement,
non privilégié. Il épingle l’API SMC de bas niveau de macmon 0.8.2, ouvre une connexion en
lecture seule et échantillonne la valeur PSTR d’origine toutes les 500 ms. Il ne lit pas
les compteurs de composants IOReport. C’est une estimation par capteur de tout le système,
pas une mesure de puissance murale externe ni de batterie. Le hash de l’exécutable et la
provenance de la source sont consignés avec les résultats bruts.
Cet échantillonneur distinct était nécessaire parce que la CLI officielle macmon calcule
sys_power = max(PSTR, component_sum), comme le montre sa
source. Les compteurs CPU
et ANE renvoyaient généralement zéro sur ce système d’exploitation, puis un échantillon a
bondi à environ 38,021 W CPU et 2,068 W ANE. Le plancher de composants a propagé cette faute
en une lecture système de 40,089 W. La cause précise de l’anomalie IOReport n’est pas
résolue ; la valeur PSTR d’origine ne peut pas être récupérée à partir de cet échantillon.
Toute l’exécution énergétique affectée a été rejetée, sans supprimer ni écrêter le
mauvais échantillon. Son
enregistrement brut
reste disponible, mais ses agrégats d’énergie stockés ne doivent pas être utilisés comme
résultats.
L’exécution FP16 uniquement antérieure utilisait la release officielle macmon v0.8.2, dont
l’archive SHA256 a été vérifiée comme
588d5bde79885ba36f693e5150911c10c3ad208a2e418a3f2aa827ac84a2d973. Elle a passé les
contrôles de cohérence ultérieurs et reste une preuve historique. L’exécution finale PSTR
uniquement remesure chaque backend avec un seul échantillonneur cohérent.
Le harnais intègre les watts sur des horodatages de réception monotones avec des frontières
interpolées. Des lectures système manquantes, non positives, non finies ou supérieures à
500 W rejettent l’exécution. Le plafond de 500 W est un contrôle de cohérence délibérément
lâche pour ce M3 Max, pas une borne de précision calibrée. Les écarts supérieurs à
max(2 seconds, 3 × sample interval) rejettent aussi l’exécution. Le résumé vérifie les
cycles équilibrés complets, la stabilité par appel, le nombre d’appels, l’énergie active, les
deux intervalles d’inactivité adjacents et l’énergie résultante moins l’inactivité par
rapport aux échantillons bruts. L’énergie incrémentale conserve son signe ; elle n’est jamais
écrêtée pour fabriquer un grand rapport.
L’échantillonneur direct omet les champs de puissance CPU/GPU/ANE parce qu’il ne les mesure pas. Des compteurs de composants historiques manquants ou nuls ne peuvent pas établir une énergie nulle ni l’absence d’exécution ANE. Le bootstrap rééchantillonne des cycles équilibrés complets ; trois cycles d’une seule session de bureau ne caractérisent pas toute la charge de fond, les exécutions futures ou la précision des capteurs. Aucun des rapports mesurés n’est proche de 10×.
Le Neural Engine exécute-t-il réellement du travail ?
Le plan de calcul Core ML du graphe B1/L96 réécrit place les 6,390 opérations non
constantes sur MLNeuralEngineComputeDevice ; les 3,809 entrées inconnues restantes sont
des constantes. C’est un placement anticipé, pas une preuve matérielle suffisante en soi.
L’export SDPA ordinaire n’avait aucune opération préférée pour l’ANE sur ce système.
Une trace Instruments Core ML séparée de 15.97 secondes, prise pendant que le candidat
tournait avec CPU_AND_NE, a capturé 3,124 intervalles actifs “Neural Engine Prediction”
et un chargement de modèle système en cache sans rapport. La table matérielle exportée
fournit donc une preuve positive d’activité ANE à l’exécution en plus du plan de calcul. La
table est globale et n’attache pas de PID ni d’identité de modèle à chaque prédiction ; la
table de jalons de modèle Core ML était vide dans cet enregistrement. Nous n’attribuons pas
chaque intervalle matériel exclusivement à Laya et n’affirmons pas que le travail de l’hôte
s’exécute sur l’ANE.
Les événements matériels autorisés
incluent uniquement l’horodatage, la durée, l’appareil, le libellé et l’état. Les archives
Instruments complètes et les métadonnées d’environnement de processus restent dans le
répertoire ignoré artifacts/. Le traçage était distinct du test d’énergie, et les
intervalles matériels instrumentés ne sont pas utilisés comme résultat de latence de bout en
bout.
Reproduire
Crée d’abord et valide les paquets fixes L96 FP16 et W8 K-means avec les commandes du
rapport d’ingénierie. Ces commandes écrivent dans des répertoires neufs
sous artifacts/ane-repro/. Construis l’échantillonneur de capteur direct localement ; aucun
démon système ni service privilégié n’est installé.
pip install -e '.[convert,dev,compare,research]'
cargo build --release --locked --manifest-path benchmarks/pstr_sampler/Cargo.toml
python -m benchmarks.energy \
--source /path/to/original/laya-multilingual \
--candidate artifacts/ane-repro/body96-w8km/model.mlpackage \
--fp16-candidate artifacts/ane-repro/body96/model.mlpackage \
--candidate-factory experiments.ane_engineering.runtime:ANEAgent \
--sampler benchmarks/pstr_sampler/target/release/pstr-sampler --pstr-only \
--cycles 3 --seconds 20 --idle-seconds 10 \
--output artifacts/energy.json
python -m benchmarks.energy_summary artifacts/energy.json \
--output artifacts/energy-summary.json
Pour des diagnostics de runtime indépendants, lance benchmarks.trace_ane, attends son
fichier PID prêt, puis attache Instruments sans autre charge de modèle en cours :
python -m benchmarks.trace_ane \
--source /path/to/original/laya-multilingual \
--package artifacts/ane-repro/body96/model.mlpackage \
--seconds 90 --ready artifacts/trace.pid
# From another terminal; use the PID written to that file.
xcrun xctrace record --template 'Core ML' --attach <PID> \
--time-limit 15s --output artifacts/ane.trace
xcrun xctrace export --input artifacts/ane.trace --toc \
--output artifacts/toc.xml
xcrun xctrace export --input artifacts/ane.trace \
--xpath '/trace-toc/run[@number="1"]/data/table[@schema="ane-hw-intervals"]' \
--output artifacts/hardware.xml
python -m benchmarks.trace_summary --hardware-xml artifacts/hardware.xml \
--toc-xml artifacts/toc.xml --output artifacts/hardware-summary.json
Le checkpoint d’origine et l’export plus court ont des limites de contexte distinctes. Le runtime L96 rejette les entrées qui ne tiennent pas ; un résultat de vitesse sur charge courte n’établit pas la performance à 512/1024 tokens ni sur les trois checkpoints Laya.