Kapitel 6
🩺Tipps & Fehlersuche
Die typischen Stolpersteine – einige davon beim Erzeugen dieser App wirklich aufgetreten (markiert mit „echt“) – und wie man sie löst.
🧯Häufige Probleme
▸torch.export im falschen Dialektecht aufgetretenNotImplementedError: Conversion for models with only ATEN or EDGE dialect is supported/tested. Provided Dialect: TRAINING. Run '.run_decompositions({})' on your exported PyTorch Model prior to conversion.
Ursache: torch.export.export liefert (hier mit torch 2.7.0) ein ExportedProgram im TRAINING-Dialekt.
Lösung: ep = torch.export.export(model, (x,)).run_decompositions({}) – danach ist der Dialekt ATEN und ct.convert(ep) läuft.
▸Nicht unterstützte PyTorch-OperationKonvertierung bricht mit einem Hinweis auf eine unbekannte/nicht implementierte Op ab.
Ursache: Für diese Op gibt es (noch) keine Übersetzung nach MIL.
Lösung: Composite Op schreiben: mit @register_torch_op eine Funktion registrieren, die die Op aus vorhandenen MIL-Ops (mb.*) zusammensetzt.
▸Datenabhängiger KontrollflussKonvertiertes Modell rechnet nur für die beim Tracen genutzte Eingabe richtig.
Ursache: torch.jit.trace zeichnet nur den tatsächlich durchlaufenen Pfad auf – Schleifen/Bedingungen, die von Daten abhängen, verallgemeinern nicht.
Lösung: Kontrollfluss aus dem Modell herausziehen, torch.export mit dynamic_shapes probieren oder Varianten getrennt konvertieren.
▸Dropout/BatchNorm im TrainingsmodusAusgaben weichen stark und zufällig ab.
Ursache: Modell wurde nicht mit eval() in den Auswertungsmodus gesetzt.
Lösung: model.eval() vor trace/export – steht ausdrücklich im coremltools-Guide.
▸Eingang ist plötzlich Float16echt aufgetretenIn Xcode steht als Eingangstyp MultiArray (Float16), obwohl FP32 gedacht war.
Ursache: Beobachtet mit coremltools 9.0: ohne dtype in ct.TensorType und mit Ziel iOS17 wurde der Eingang FLOAT16 (siehe Golden-File mit RangeDim/EnumeratedShapes). FP16-Ein-/Ausgänge sind ab iOS 16 möglich.
Lösung: dtype explizit setzen: ct.TensorType(name="pixels", shape=(1, 64), dtype=np.float32).
▸Unbeschränkter RangeDimKonvertierung zu mlprogram schlägt mit flexibler Form fehl.
Ursache: Unbeschränkte Bereiche (upper_bound=-1) sind bei ML Programs nicht erlaubt.
Lösung: ct.RangeDim(lower_bound=1, upper_bound=64) setzen oder EnumeratedShapes (bis 128 Formen, schneller).
▸LogisticRegression (multinomial) aus scikit-learnecht aufgetretenLog-Meldung „Currently "One Vs Rest" is the only supported multiclass option.“ – danach bricht die Konvertierung ab.
Ursache: Der scikit-learn-Konverter unterstützt bei logistischer Regression nur One-vs-Rest; scikit-learn 1.5 nutzt standardmäßig multinomial.
Lösung: Anderes Modell (z. B. Entscheidungsbaum) oder One-vs-Rest verwenden.
▸Ungetestete PyTorch-Versionecht aufgetretenWarnung „Torch version 2.7.1 has not been tested with coremltools. You may run into unexpected errors. Torch 2.7.0 is the most recent version that has been tested.“
Ursache: coremltools 9.0 ist gegen PyTorch 2.7 getestet.
Lösung: In einer eigenen venv genau die getestete Version installieren (hier torch==2.7.0).
▸NaN oder Inf in der AusgabeCore ML liefert NaN/Inf, PyTorch nicht – häufig bei FP16 (größte Zahl 65504).
Ursache: Überlauf in einer Zwischenrechnung bei reduzierter Genauigkeit.
Lösung: MLModelValidator (experimentell, coremltools ≥ 8.3) findet die verursachenden Ops; betroffene Teile mit compute_precision FLOAT32 konvertieren.
▸predict() in Python schlägt fehlUnter Linux/Docker lässt sich das konvertierte Modell nicht ausführen.
Ursache: coremltools nutzt für predict() das Core-ML-Framework – das gibt es nur unter macOS.
Lösung: Konvertieren geht auch unter Linux, testen auf einem Mac (oder direkt im Xcode-Vorschau-Tab).
Python
Fehlende PyTorch-Op selbst übersetzen (Composite Op)
from coremltools.converters.mil.frontend.torch.torch_op_registry import (
_TORCH_OPS_REGISTRY, register_torch_op)
from coremltools.converters.mil.frontend.torch.ops import _get_inputs
from coremltools.converters.mil import Builder as mb
del _TORCH_OPS_REGISTRY["selu"] # nur nötig, wenn eine vorhandene Übersetzung ersetzt wird
@register_torch_op
def selu(context, node):
x = _get_inputs(context, node, expected=1)[0]
x = mb.elu(x=x, alpha=1.6732632423543772)
x = mb.mul(x=x, y=1.0507009873554805, name=node.name)
context.add(x)
mlmodel = ct.convert(traced, inputs=[...])ℹ️ Beispiel wörtlich nach dem coremltools-Guide „Composite Operators“ (selu).
Belege: 📎 Composite Operators
⚖️PyTorch vs. Core ML vergleichen
Wie groß dürfen Abweichungen sein? Echte Werte des Lehrmodells:
✔ echte coremltools-Ausgabemax |p_CoreML − p_PyTorch| über 40 Testbilder × 10 Klassen (Softmax-Wahrscheinlichkeiten), CPU_ONLY
FP32
1.2e-7
FP16
7.8e-4
FP16 (torch.export)
7.8e-4
Int8
1.8e-3
Palette 4 Bit
7.0e-2
Int4
1.9e-1
Pruning 50 %
9.8e-1
1e-81e-61e-41e-21e0
Senkrechte Striche: typische Toleranzen 1e-6 (FP32) und 1e-3 (FP16). Die Nachkommastellen hängen von Modell, Eingabe und Recheneinheit ab – auf GPU/Neural Engine sind andere Werte zu erwarten.
💡Tipps für Performance, Größe, Datenschutz und Pflege
Toleranzen realistisch wählen: FP32-Modelle weichen bei uns ≈ 1,2·10⁻⁷ ab, FP16 ≈ 7,8·10⁻⁴ (max. Betrag, Softmax-Wahrscheinlichkeiten, CPU_ONLY). Für FP16 also eher atol ≈ 10⁻³ als 10⁻⁶. 📎 eigene Konvertierung
Für Ursachen-Suche: MLModelComparator/TorchScriptMLModelComparator vergleichen Zwischenergebnisse Op für Op mit dem Quellmodell (experimentell, seit coremltools 8.3). 📎 Debugging And Performance Utilities📎 coremltools 8.3 Release Notes
Performance messen ohne App-Code: Modell in Xcode öffnen → Tab „Performance“ → Bericht mit Gerät und Recheneinheiten. Zeigt Lade-, Kompilier- und Vorhersagezeit (Median) und je Operation CPU/GPU/NE – aber keinen Speicher- und Energiebedarf. 📎 Analyzing a Core ML model’s performa…
Dieselbe Zuordnung im Code: MLComputePlan.load(contentsOf:configuration:) → deviceUsage(for:) und estimatedCost(of:) (ab iOS 17.4 / macOS 14.4). 📎 MLComputePlan📎 Analyzing a Core ML model’s performa…
Tiefer: „Open in Instruments“ aus dem Performance-Report heraus. 📎 Analyzing a Core ML model’s performa…
Metadaten pflegen: author, short_description, version, license und Beschreibungen je Eingang/Ausgang – Xcode zeigt sie an, coremltools ergänzt selbst Quell-Framework, Version und Datum (userDefined). 📎 MLModel Overview (Metadaten, Spec, p…📎 eigene Konvertierung
Ein- und Ausgänge nachträglich umbenennen (z. B. für schönere Swift-Namen): ct.utils.rename_feature(spec, "alt", "neu"). 📎 MLModel Utilities (Metadaten, rename…
Datenschutz: Läuft das Modell nur auf dem Gerät, braucht es keine Netzverbindung und die Daten bleiben beim Nutzer. 📎 Core ML (Framework-Übersicht)
Modell schützen: Xcode kann das eingebaute Modell beim Kompilieren verschlüsseln (Compiler-Flag im Build-Target). 📎 Encrypting a Model in Your App
Große heruntergeladene Modelle: kompiliertes .mlmodelc dauerhaft ablegen; iCloud-Backup bedenken (Caches oder isExcludedFromBackup). 📎 Downloading and Compiling a Model on…
Ein MLModel-Objekt nur von einem Thread/einer Queue gleichzeitig benutzen – oder je Thread eine eigene Instanz. 📎 MLModel
Kompression: Palettisierung und lineare Quantisierung sparen vor allem Speicher/Bandbreite; Beschleunigung hängt von Recheneinheit und OS ab (z. B. per_block Int4 eher GPU, auf der NE per_channel empfohlen). 📎 Quantization Performance📎 Palettization Performance
Pruning beschleunigt vor allem auf der Neural Engine bei hoher (≥ 75 %) oder blockstrukturierter Sparsity. 📎 Pruning Performance
🗓️Deployment-Matrix: ab welchem OS geht was?
Mindestversionen laut Apple-Doku bzw. coremltools-Guides. Das Deployment-Ziel der Konvertierung (minimum_deployment_target) muss mindestens so hoch sein wie das Feature verlangt.
| Feature | iOS | macOS | Werkzeug | Beleg |
|---|---|---|---|---|
| Core ML (Framework), MLModel, MLMultiArray, Vision VNCoreMLRequest | 11 | 10.13 | – | 📎 Core ML (Framework-Übersicht)📎 MLModel📎 MLMultiArray📎 VNCoreMLRequest |
| NeuralNetwork-Modelle (.mlmodel) | 11 | 10.13 | – | 📎 Source and Conversion Formats |
| MLModelConfiguration, computeUnits .all/.cpuOnly/.cpuAndGPU, predictions(fromBatch:) | 12 | 10.14 | – | 📎 MLModelConfiguration📎 MLComputeUnits📎 MLModel.predictions(fromBatch:) |
| Mindestziel der Unified Conversion API (ct.convert) | 13 | 10.15 | coremltools ≥ 4 | 📎 PyTorch Conversion Workflow |
| On-Device-Update MLUpdateTask (nur NeuralNetwork, kompiliertes .mlmodelc) | 13 | 10.15 | – | 📎 MLUpdateTask📎 Personalizing a Model with On-Device…📎 Comparing ML Programs and Neural Net… |
| ML Program (.mlpackage, MIL) – Standard ab coremltools 7.0 | 15 | 12 | coremltools ≥ 5 | 📎 Source and Conversion Formats📎 Convert Models to ML Programs |
| MLShapedArray, MLModel.load(contentsOf:configuration:) async | 15 | 12 | – | 📎 MLShapedArray📎 MLModel.load(contentsOf:configuratio… |
| .cpuAndNeuralEngine | 16 | 13 | – | 📎 MLComputeUnits.cpuAndNeuralEngine |
| FP16-Ein-/Ausgänge (MLMultiArray Float16, GRAYSCALE_FLOAT16) | 16 | 13 | – | 📎 Image Input and Output |
| Gewichtskompression: Int8 pro Kanal, Palette 1/2/4/6/8 Bit, Pruning | 16 | 13 | coremltools ≥ 7 (optimize) | 📎 Optimization – What’s New (OS-Verfüg…📎 Palettization Overview + API📎 Pruning Overview + API |
| MLModel.compileModel(at:) async | 16 | 13 | – | 📎 MLModel.compileModel(at:) async |
| Asynchrone Vorhersage (prediction(from:) async / completionHandler) | 17 | 14 | – | 📎 MLModel predictionFromFeatures:compl… |
| Aktivierungs-Quantisierung W8A8 (NE-beschleunigt ab A17 Pro / M4) | 17 | 14 | – | 📎 Optimization – What’s New (OS-Verfüg…📎 Quantization Overview + API |
| MLComputePlan (Zuordnung Operation → Recheneinheit im Code) | 17.4 | 14.4 | – | 📎 MLComputePlan |
| Int4-Gewichte, per_block-Skalen, Palette 3 Bit, gruppierte LUTs, INT8-LUTs, Pruning + Quantisierung/Palette kombiniert | 18 | 15 | coremltools ≥ 8 | 📎 Optimization – What’s New (OS-Verfüg…📎 coremltools 8.0 Release Notes |
| Stateful Models (MLState), Multifunction-Modelle, MLTensor | 18 | 15 | coremltools ≥ 8 | 📎 MLState📎 Stateful Models📎 MLTensor📎 coremltools 8.0 Release Notes |
| Mehrere Eingänge mit EnumeratedShapes (Guide nennt nur iOS 18) | 18 | – | – | 📎 Flexible Input Shapes |
| Vision: CoreMLRequest + CoreMLModelContainer (Swift-API) | 18 | 15 | – | 📎 CoreMLRequest (Swift-Vision-API)📎 CoreMLModelContainer |
| Deployment-Ziel ct.target.iOS26 / macOS26 | 26 | 26 | coremltools ≥ 9.0 | 📎 coremltools 9.0 Release Notes |
| Core AI (neues Framework, .aimodel) – Ausblick, nicht Thema dieser App | 27 | 27 | – | 📎 Core AI (neues Framework) |