Notes de conversion
Cette page décrit l’export Core ML ordinaire. Le graphe ANE réécrit séparément et la palettisation de poids optionnelle sont documentés dans ANE_ENGINEERING.md.
L’export charge des checkpoints Laya d’origine dans des modules PyTorch FP32, vérifie strictement toutes les clés du state-dict, trace une implémentation dédiée à l’inférence et enregistre un ML Program Core ML. Les fichiers de checkpoint publiés contiennent eux-mêmes majoritairement des tenseurs FP16 ; FP32 décrit ici le calcul d’export/référence, pas des poids sources de plus haute précision. Aucun entraînement, élagage ou quantification de poids n’est effectué. FP16 est un choix de précision de conversion ; FP32 peut être sélectionné pour le diagnostic.
Le runtime utilise le tokenizer du checkpoint, la disposition des prompts, les marqueurs d’options, l’embedding de type de question, la tête de décision, la tête d’action et les températures de calibration. Choice, score, noul, les critères structurés, la comptabilité des tokens et zéro token généré suivent l’API en amont. L’encodeur est bidirectionnel : chaque question exécute encore sa propre séquence d’encodeur. Il n’y a pas de cache d’états cachés partagés.
Choix de conversion validés
coremltools==9.0,torch==2.7.0,numpy==2.1.3, Python 3.12.- Traçage TorchScript avec vérification du graphe, mode évaluation, poids d’origine chargés dans des modules FP32.
- ML Program, cible de déploiement macOS 15 / iOS 18. L’exécution réelle a été testée sur un M3 Max sous macOS 27.2 ; l’exécution sur iPhone/iPad et les macOS plus anciens n’ont pas été testées.
- Les longueurs de séquence par défaut sont choisies parmi 16, 32, 64, 96, 128, 192, 256, 384, 512, 768, 1024, plafonnées par la limite de contexte du checkpoint. Le runtime complète jusqu’à la plus petite longueur disponible et masque les tokens ajoutés.
- La taille de lot par défaut est un, avec 32 emplacements de marqueur. Plus de questions s’exécutent
par blocs.
--batch-sizeet--max-optionsproduisent des signatures exportées différentes. - Des formes fixes sont disponibles pour une charge de travail connue. Les entrées dépassant la longueur ou la capacité d’options d’un export lèvent une erreur ; elles ne sont pas tronquées silencieusement pour tenir dans un export plus petit. La troncature de contexte du checkpoint d’origine est préservée.
Apple documente la conversion TorchScript et les formes d’entrée énumérées. Plusieurs entrées énumérées nécessitent le même nombre de formes, appariées par index ; cet export apparie en conséquence les ID d’entrée et les masques d’attention.
Échecs conservés pour la reproductibilité
Ce sont des observations sur cette machine et ce système d’exploitation, pas des affirmations sur toutes les versions de Core ML.
- L’opérateur booléen
__or__de PyTorch n’a pas été converti. Lestorch.logical_or/torch.logical_andexplicites préservent la même sémantique de masque. - NumPy 2.5 a rejeté une conversion tableau-vers-scalaire obsolète à l’intérieur de coremltools 9.0. La dépendance prise en charge du projet est épinglée en dessous de NumPy 2.2. PyTorch a été épinglé à la version 2.7.0 testée par le convertisseur plutôt qu’à 2.7.1.
RangeDimavecCPU_AND_GPUforcé a produit de grandes erreurs numériques et des résultats différents sur des entrées identiques répétées. L’export SDPA d’origine ne correspondait qu’à 47/63 réponses de référence, et l’attention matmul/softmax explicite à 20/63. FP32 n’a pas résolu la défaillance GPU observée sur entrée courte. CPU / la sélection automatique ont donné des sorties correctes pour le graphe SDPA.- Les longueurs énumérées ont restauré la fidélité et la répétabilité GPU. Un petit test
de régression séparé a ensuite révélé un
SIGTRAPdu compilateur MPSGraph lors du découpage d’une matrice d’attention locale booléenne constante. Le diagnostic nommaitElementsAttr::getValues<bool>/FoldStridedSliceOp. - L’implémentation finale découpe des positions entières et construit ensuite le masque local booléen. Cela supprime le piège du compilateur. Cela ne guérit pas la défaillance GPU générale de RangeDim : l’expérience suivante ne correspondait encore qu’à 49/63 et n’était pas répétable. Les longueurs énumérées restent la valeur par défaut.
Le runtime rejette RangeDim + cpu_gpu sauf autorisation explicite pour une expérience de
diagnostic. Pour reproduire cette configuration défaillante :
laya-coreml convert laya-multilingual models/range-experiment --shape-mode range
python -m benchmarks.validate models/range-experiment \
--name laya-multilingual --compute-units cpu_gpu --allow-unvalidated-gpu \
--repeats 10 --output artifacts/range-experiment.json
Le test est censé échouer sur l’environnement mesuré. Les rapports bruts d’échec et de
succès sont conservés dans benchmarks/results/ ; les rapports contenant
"passed": false ne doivent pas être cités comme configurations validées.
Preuves matérielles
CPU_AND_NE signifie que le CPU et le Neural Engine sont autorisés, et non que chaque
opérateur s’exécute sur le Neural Engine. Le benchmark enregistre les appareils
préférés/pris en charge et les coûts estimés du plan de calcul Core ML. C’est un plan
anticipé, pas une trace matérielle d’exécution Instruments, une mesure de puissance ou une
preuve d’exécution exclusive sur le Neural Engine.
Charger des instantanés du Hub
Le smoke test de release a trouvé un problème de packaging distinct : charger un fichier de
poids à lien symbolique depuis le cache partagé de Hugging Face faisait signaler au
compilateur natif de Core ML un model.mlmodelc/weights/weight.bin manquant. Les six
bundles locaux équivalents se sont chargés avec succès. Le runtime copie désormais les
paquets adossés à des liens symboliques vers un cache adressé par contenu de fichiers
réguliers avant de construire MLModel. Les hashs sont vérifiés avant et après la copie et
à la réutilisation ; un cache modifié ou endommagé lève une erreur. Les bundles locaux en
fichiers réguliers n’empruntent pas ce chemin de copie. Voir USAGE.md pour
l’emplacement du cache et la manière de le remplacer.
Reproductibilité
Chaque export inclut coreml_config.json : SHA256 des poids d’origine, révision source,
formes, précision, implémentation de l’attention, versions des outils, heure de conversion
et hashs de chaque fichier de paquet/tokenizer/config. Les exports refusent d’écraser des
répertoires existants. Un export échoué ne supprime que son répertoire de sortie
nouvellement créé.
La référence dorée committée a été générée à partir de la révision amont Laya non modifiée
573e5b62696ba441230cd6be71d593331b5d23af avec PyTorch MPS en FP32. Elle inclut les ID de
tokens d’entrée complets et les logits non arrondis. La validation compare ces tokens
exactement et vérifie les réponses sélectionnées, les probabilités calibrées, les
probabilités d’action, la comptabilité des tokens et les résultats publics répétés.
Pour régénérer la référence dorée dans un environnement compatible avec l’amont :
git clone https://github.com/NandhaKishorM/laya .upstream
git -C .upstream checkout 6a5819129eb220570792e417e49723d697efd76f
python -m benchmarks.reference --upstream .upstream --model-root /path/to/original/checkpoints
Les dépendances exactes de référence sont consignées dans le JSON généré. Elles sont distinctes de l’environnement d’export épinglé ; Transformers n’est pas une dépendance de runtime ni d’export de laya-coreml.