@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +266 -267
- package/package.json +2 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +68 -68
- package/pipeline/skills/shared/README.md +70 -70
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,500 +1,456 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: coreml
|
|
3
|
-
description: "
|
|
3
|
+
description: "Swift-side Core ML: loading .mlmodel, .mlpackage and .mlmodelc, predictions via generated classes and MLFeatureProvider, compute units, async and stateful prediction with MLState, MLTensor, MLMultiArray, Vision CoreMLRequest and VNCoreMLRequest, MLComputePlan, multi-model pipelines, deployment and profiling. Use when integrating, reviewing, deploying or profiling a Core ML model in an app. Not for Python conversion (apple-on-device-ai)."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
|
-
# Core ML Swift Integration
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
Swift side: model loading, prediction, MLTensor, profiling, and deployment.
|
|
11
|
-
Target iOS 26+ with Swift 6.3, backward-compatible to iOS 14 unless noted.
|
|
8
|
+
# Core ML
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
This skill covers the app side of Core ML: getting a model into memory,
|
|
11
|
+
feeding it, reading its output, and shipping it. Baseline: iOS 26 and Swift
|
|
12
|
+
6.3, with each API's lower floor stated where it matters (much of Core ML goes
|
|
13
|
+
back to iOS 14 or earlier).
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
Out of scope here: converting or compressing models in Python (quantization,
|
|
16
|
+
palettization, pruning) and choosing between on-device AI frameworks; those
|
|
17
|
+
belong to `apple-on-device-ai`. Text recognition, barcodes and document
|
|
18
|
+
scanning with Vision belong to `vision-framework`.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Longer code (an actor that owns models, SwiftUI wiring, custom feature
|
|
21
|
+
providers, stateful sessions, pixel buffers, tensors, Vision pipelines,
|
|
22
|
+
NaturalLanguage, compute plans, lifecycle, errors, tests) is in
|
|
23
|
+
`references/coreml-swift-integration.md`.
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
- [Model Configuration](#model-configuration)
|
|
24
|
-
- [Making Predictions](#making-predictions)
|
|
25
|
-
- [MLTensor (iOS 18+)](#mltensor-ios-18)
|
|
26
|
-
- [Working with MLMultiArray](#working-with-mlmultiarray)
|
|
27
|
-
- [Image Preprocessing](#image-preprocessing)
|
|
28
|
-
- [Multi-Model Pipelines](#multi-model-pipelines)
|
|
29
|
-
- [Vision Integration](#vision-integration)
|
|
30
|
-
- [Performance Profiling](#performance-profiling)
|
|
31
|
-
- [Model Deployment](#model-deployment)
|
|
32
|
-
- [Memory Management](#memory-management)
|
|
33
|
-
- [Common Mistakes](#common-mistakes)
|
|
34
|
-
- [Review Checklist](#review-checklist)
|
|
35
|
-
- [References](#references)
|
|
25
|
+
## Loading a model
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
When you add a `.mlmodel` or `.mlpackage` to an app target, Xcode generates a Swift
|
|
42
|
-
class with typed input/output. Use this whenever possible.
|
|
27
|
+
**Generated class.** Drop a `.mlmodel` or `.mlpackage` into a target and Xcode
|
|
28
|
+
generates a Swift class with typed inputs and outputs. Use it whenever it
|
|
29
|
+
exists.
|
|
43
30
|
|
|
44
31
|
```swift
|
|
45
32
|
import CoreML
|
|
46
33
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
34
|
+
func makeDenoiser() throws -> PhotoDenoiser {
|
|
35
|
+
let settings = MLModelConfiguration()
|
|
36
|
+
settings.computeUnits = .all
|
|
37
|
+
return try PhotoDenoiser(configuration: settings)
|
|
38
|
+
}
|
|
51
39
|
```
|
|
52
40
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Load from a URL when the model is downloaded at runtime or stored outside the
|
|
56
|
-
bundle.
|
|
41
|
+
**From a URL.** For models that are downloaded or stored outside the bundle:
|
|
57
42
|
|
|
58
43
|
```swift
|
|
59
|
-
|
|
60
|
-
forResource: "MyModel", withExtension: "mlmodelc"
|
|
61
|
-
)!
|
|
62
|
-
let model = try MLModel(contentsOf: modelURL, configuration: config)
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Async Loading (iOS 15+)
|
|
66
|
-
|
|
67
|
-
Load models without blocking the main thread. Prefer this for large models.
|
|
44
|
+
import CoreML
|
|
68
45
|
|
|
69
|
-
|
|
70
|
-
let
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
46
|
+
func bundledModel(named name: String) throws -> MLModel {
|
|
47
|
+
guard let url = Bundle.main.url(forResource: name, withExtension: "mlmodelc") else {
|
|
48
|
+
throw CocoaError(.fileNoSuchFile)
|
|
49
|
+
}
|
|
50
|
+
return try MLModel(contentsOf: url, configuration: MLModelConfiguration())
|
|
51
|
+
}
|
|
74
52
|
```
|
|
75
53
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
Compile a `.mlpackage` or `.mlmodel` to `.mlmodelc` on device. Useful for
|
|
79
|
-
models downloaded from a server. Do this once per model version, not on every
|
|
80
|
-
launch.
|
|
54
|
+
**Asynchronously.** `MLModel.load(contentsOf:configuration:)` (async, iOS 15+)
|
|
55
|
+
keeps large models from stalling the main thread and is the preferred loader.
|
|
81
56
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
```
|
|
57
|
+
**Compiling on device.** `MLModel.compileModel(at:)` (async form, iOS 16+)
|
|
58
|
+
turns a `.mlmodel` or `.mlpackage` into a `.mlmodelc` on the device, which is
|
|
59
|
+
how server-delivered models become loadable. Two rules travel together:
|
|
86
60
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
app does not recompile on every launch.
|
|
61
|
+
1. Compile once per model version, never on every launch; recompiling at each
|
|
62
|
+
start is a bug.
|
|
63
|
+
2. The returned URL points into a temporary location. Move the `.mlmodelc`
|
|
64
|
+
somewhere durable such as Application Support and reuse it.
|
|
92
65
|
|
|
93
|
-
|
|
66
|
+
When reviewing runtime-loaded models, state both: the async compile API needs
|
|
67
|
+
iOS 16, and its output must be cached.
|
|
94
68
|
|
|
95
|
-
|
|
69
|
+
## Configuration and compute units
|
|
96
70
|
|
|
97
|
-
|
|
71
|
+
`MLModelConfiguration` chooses hardware, GPU precision and model parameters.
|
|
98
72
|
|
|
99
|
-
|
|
|
73
|
+
| `computeUnits` | Hardware | When |
|
|
100
74
|
|---|---|---|
|
|
101
|
-
| `.all` | CPU
|
|
102
|
-
| `.cpuOnly` | CPU | Deterministic tests, CPU-only fallbacks, or
|
|
103
|
-
| `.cpuAndGPU` | CPU
|
|
104
|
-
| `.cpuAndNeuralEngine` (iOS 16+) | CPU
|
|
75
|
+
| `.all` (default) | CPU, GPU, Neural Engine; the system decides | Almost always |
|
|
76
|
+
| `.cpuOnly` | CPU | Deterministic tests, CPU-only fallbacks, or when profiling shows accelerator policy, contention, thermal state or energy budget is the constraint |
|
|
77
|
+
| `.cpuAndGPU` | CPU and GPU | The model needs the GPU but has operations the Neural Engine cannot run |
|
|
78
|
+
| `.cpuAndNeuralEngine` (iOS 16+) | CPU and Neural Engine | Best energy efficiency for models the Neural Engine fully supports |
|
|
105
79
|
|
|
106
80
|
```swift
|
|
107
|
-
|
|
108
|
-
config.computeUnits = .cpuAndNeuralEngine
|
|
109
|
-
|
|
110
|
-
// Optional fallback for constrained work after profiling and policy review
|
|
111
|
-
config.computeUnits = .cpuOnly
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Configuration Properties
|
|
81
|
+
import CoreML
|
|
115
82
|
|
|
116
|
-
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
|
|
83
|
+
func efficientSettings(fallbackToCPU: Bool) -> MLModelConfiguration {
|
|
84
|
+
let settings = MLModelConfiguration()
|
|
85
|
+
settings.computeUnits = fallbackToCPU ? .cpuOnly : .cpuAndNeuralEngine
|
|
86
|
+
settings.allowLowPrecisionAccumulationOnGPU = true
|
|
87
|
+
return settings
|
|
88
|
+
}
|
|
120
89
|
```
|
|
121
90
|
|
|
122
|
-
|
|
91
|
+
`allowLowPrecisionAccumulationOnGPU` buys speed for a small loss of precision.
|
|
92
|
+
Choose `.cpuOnly` only after profiling says so.
|
|
123
93
|
|
|
124
|
-
|
|
94
|
+
## Predictions
|
|
125
95
|
|
|
126
|
-
|
|
96
|
+
**Generated class:**
|
|
127
97
|
|
|
128
98
|
```swift
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
99
|
+
import CoreML
|
|
100
|
+
|
|
101
|
+
func tagScene(_ frame: CVPixelBuffer, with model: SceneTagger) throws -> (String, Double) {
|
|
102
|
+
let result = try model.prediction(input: SceneTaggerInput(image: frame))
|
|
103
|
+
return (result.classLabel, result.classLabelProbs[result.classLabel] ?? 0)
|
|
104
|
+
}
|
|
134
105
|
```
|
|
135
106
|
|
|
136
|
-
|
|
107
|
+
`classLabel` is the winning label and `classLabelProbs` maps every label to
|
|
108
|
+
its probability.
|
|
137
109
|
|
|
138
|
-
|
|
110
|
+
**Dictionary provider**, for inputs only known at run time:
|
|
139
111
|
|
|
140
112
|
```swift
|
|
141
|
-
|
|
142
|
-
"image": MLFeatureValue(pixelBuffer: pixelBuffer),
|
|
143
|
-
"confidence_threshold": MLFeatureValue(double: 0.5),
|
|
144
|
-
])
|
|
145
|
-
let output = try model.prediction(from: inputFeatures)
|
|
146
|
-
let label = output.featureValue(for: "classLabel")?.stringValue
|
|
147
|
-
```
|
|
113
|
+
import CoreML
|
|
148
114
|
|
|
149
|
-
|
|
115
|
+
func tagWithThreshold(_ frame: CVPixelBuffer, cutoff: Double, model: MLModel) async throws -> String? {
|
|
116
|
+
let inputs = try MLDictionaryFeatureProvider(dictionary: [
|
|
117
|
+
"image": MLFeatureValue(pixelBuffer: frame),
|
|
118
|
+
"threshold": MLFeatureValue(double: cutoff)
|
|
119
|
+
])
|
|
120
|
+
let outputs = try await model.prediction(from: inputs)
|
|
121
|
+
return outputs.featureValue(for: "label")?.stringValue
|
|
122
|
+
}
|
|
123
|
+
```
|
|
150
124
|
|
|
151
|
-
|
|
152
|
-
async, then run prediction from an actor or non-main task without adding `await`
|
|
153
|
-
to the prediction call.
|
|
125
|
+
### Sync or async prediction
|
|
154
126
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
127
|
+
- `prediction(from:)` and `prediction(from:options:)` exist in a synchronous
|
|
128
|
+
throwing form on every supported OS.
|
|
129
|
+
- From iOS 17 there is also `prediction(from:options:) async throws`, which
|
|
130
|
+
may be called concurrently on the same model. Inside an `async` function the
|
|
131
|
+
compiler resolves to that overload, so the call needs `try await`; leaving
|
|
132
|
+
out `await` there does not compile.
|
|
133
|
+
- In synchronous code (a serial queue, a synchronous actor method) the
|
|
134
|
+
synchronous form is used without `await`.
|
|
135
|
+
- Loading stays async either way (`MLModel.load`).
|
|
158
136
|
|
|
159
|
-
###
|
|
137
|
+
### Batches
|
|
160
138
|
|
|
161
|
-
|
|
139
|
+
Processing several inputs per call raises throughput:
|
|
162
140
|
|
|
163
141
|
```swift
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
let
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
print(result.featureValue(for: "classLabel")?.stringValue ?? "unknown")
|
|
142
|
+
import CoreML
|
|
143
|
+
|
|
144
|
+
func labels(for frames: [CVPixelBuffer], model: MLModel) throws -> [String] {
|
|
145
|
+
let rows = try frames.map { try MLDictionaryFeatureProvider(dictionary: ["image": MLFeatureValue(pixelBuffer: $0)]) }
|
|
146
|
+
let answers = try model.predictions(fromBatch: MLArrayBatchProvider(array: rows))
|
|
147
|
+
return (0..<answers.count).compactMap { answers.features(at: $0).featureValue(for: "label")?.stringValue }
|
|
171
148
|
}
|
|
172
149
|
```
|
|
173
150
|
|
|
174
|
-
|
|
175
|
-
`
|
|
176
|
-
`
|
|
177
|
-
|
|
151
|
+
Two batch spellings are valid: `predictions(fromBatch:)` without options, and
|
|
152
|
+
`predictions(from:options:)` when you pass an `MLBatchProvider` together with
|
|
153
|
+
`MLPredictionOptions`. There is no options-free `predictions(from:)`; do not
|
|
154
|
+
write one.
|
|
178
155
|
|
|
179
|
-
### Stateful
|
|
156
|
+
### Stateful models with MLState (iOS 18+)
|
|
180
157
|
|
|
181
|
-
|
|
182
|
-
|
|
158
|
+
Sequence models (language models, streaming audio, time series) keep context
|
|
159
|
+
between calls. Create a state once per stream and pass it to every call.
|
|
183
160
|
|
|
184
161
|
```swift
|
|
185
|
-
|
|
162
|
+
import CoreML
|
|
186
163
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
let classification = output.featureValue(for: "label")?.stringValue
|
|
164
|
+
func classifyStream(_ windows: [MLMultiArray], model: MLModel) throws -> [String] {
|
|
165
|
+
let memory = model.makeState()
|
|
166
|
+
return try windows.compactMap { window in
|
|
167
|
+
let input = try MLDictionaryFeatureProvider(dictionary: ["samples": MLFeatureValue(multiArray: window)])
|
|
168
|
+
return try model.prediction(from: input, using: memory).featureValue(for: "label")?.stringValue
|
|
169
|
+
}
|
|
194
170
|
}
|
|
195
171
|
```
|
|
196
172
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
173
|
+
Rules for `MLState`:
|
|
174
|
+
|
|
175
|
+
- It is `Sendable`, which lets it move between concurrency domains. It does
|
|
176
|
+
not make concurrent predictions on one state safe: run them one at a time.
|
|
177
|
+
- Do not read or write the state's buffers while a prediction is running.
|
|
178
|
+
- Independent concurrent streams each get their own `model.makeState()`.
|
|
179
|
+
- The async `prediction(from:using:options:)` (iOS 18) is there when you need
|
|
180
|
+
options or are in async code; the same one-prediction-in-flight rule holds.
|
|
181
|
+
The synchronous `prediction(from:using:)` is for synchronous loops.
|
|
204
182
|
|
|
205
183
|
## MLTensor (iOS 18+)
|
|
206
184
|
|
|
207
|
-
`MLTensor` is a Swift
|
|
208
|
-
Operations
|
|
185
|
+
`MLTensor` is a Swift multidimensional array for pre- and post-processing.
|
|
186
|
+
Operations are lazy; results materialize only when you await
|
|
187
|
+
`shapedArray(of:)`.
|
|
209
188
|
|
|
210
189
|
```swift
|
|
211
190
|
import CoreML
|
|
212
191
|
|
|
213
|
-
|
|
214
|
-
let
|
|
215
|
-
let
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
// Math operations
|
|
221
|
-
let softmaxed = tensor.softmax(alongAxis: -1)
|
|
222
|
-
let centered = tensor - tensor.mean()
|
|
192
|
+
func normalizedScores(_ logits: [Float]) async -> MLMultiArray {
|
|
193
|
+
let raw = MLTensor(logits).reshaped(to: [1, logits.count])
|
|
194
|
+
let centered = raw - raw.mean()
|
|
195
|
+
let probabilities = centered.softmax(alongAxis: -1)
|
|
196
|
+
let shaped = await probabilities.shapedArray(of: Float.self)
|
|
197
|
+
return MLMultiArray(shaped)
|
|
198
|
+
}
|
|
223
199
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
let shapedAgain = MLShapedArray<Float>(multiArray)
|
|
200
|
+
func tensor(from array: MLMultiArray) -> MLTensor {
|
|
201
|
+
MLTensor(MLShapedArray<Float>(array))
|
|
202
|
+
}
|
|
228
203
|
```
|
|
229
204
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
205
|
+
Stay with documented operations. There is no `MLTensor(multiArray)`
|
|
206
|
+
initializer, no `std()` or `standardDeviation()`, no direct access to the lazy
|
|
207
|
+
storage, and no synchronous extraction. Go through `MLShapedArray` for
|
|
208
|
+
conversions, and build statistics from documented pieces (`mean()`,
|
|
209
|
+
`squareRoot()`, arithmetic) or do them outside the tensor pipeline.
|
|
210
|
+
`MLTensor(zeros:scalarType:)` and `MLTensor(ones:scalarType:)` create filled
|
|
211
|
+
tensors.
|
|
234
212
|
|
|
235
|
-
##
|
|
213
|
+
## MLMultiArray
|
|
236
214
|
|
|
237
|
-
`MLMultiArray` is the
|
|
238
|
-
|
|
215
|
+
`MLMultiArray` is the exchange type for non-image inputs and outputs; generated
|
|
216
|
+
classes use it for array features.
|
|
239
217
|
|
|
240
218
|
```swift
|
|
241
|
-
|
|
242
|
-
let array = try MLMultiArray(shape: [1, 128, 768], dataType: .float32)
|
|
219
|
+
import CoreML
|
|
243
220
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
221
|
+
func embeddingInput(tokens: Int, width: Int) throws -> MLMultiArray {
|
|
222
|
+
let grid = try MLMultiArray(shape: [1, NSNumber(value: tokens), NSNumber(value: width)], dataType: .float32)
|
|
223
|
+
grid[[0, 0, 0] as [NSNumber]] = 0.25
|
|
224
|
+
return grid
|
|
247
225
|
}
|
|
248
226
|
|
|
249
|
-
|
|
250
|
-
|
|
227
|
+
func firstValue(of grid: MLMultiArray) -> Float {
|
|
228
|
+
grid[[0, 0, 0] as [NSNumber]].floatValue
|
|
229
|
+
}
|
|
251
230
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
231
|
+
func packed(_ values: [Float]) -> MLMultiArray {
|
|
232
|
+
MLMultiArray(MLShapedArray<Float>(scalars: values, shape: [1, values.count]))
|
|
233
|
+
}
|
|
255
234
|
```
|
|
256
235
|
|
|
257
|
-
|
|
258
|
-
|
|
236
|
+
The shape reads batch, sequence, features. Tokenized text and audio feature
|
|
237
|
+
patterns are in the reference.
|
|
259
238
|
|
|
260
|
-
## Image
|
|
239
|
+
## Image input
|
|
261
240
|
|
|
262
|
-
Image models
|
|
263
|
-
|
|
264
|
-
|
|
241
|
+
Image models take a `CVPixelBuffer`. When Vision drives the model
|
|
242
|
+
(`CoreMLRequest` or `VNCoreMLRequest`), conversion happens automatically; the
|
|
243
|
+
manual path is only for direct `MLModel` predictions.
|
|
265
244
|
|
|
266
245
|
```swift
|
|
246
|
+
import CoreGraphics
|
|
267
247
|
import CoreVideo
|
|
268
248
|
|
|
269
|
-
func
|
|
270
|
-
|
|
271
|
-
let attrs: [CFString: Any] = [
|
|
249
|
+
func pixelBuffer(from picture: CGImage, side: Int) -> CVPixelBuffer? {
|
|
250
|
+
let options = [
|
|
272
251
|
kCVPixelBufferCGImageCompatibilityKey: true,
|
|
273
|
-
kCVPixelBufferCGBitmapContextCompatibilityKey: true
|
|
274
|
-
]
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
guard let buffer = pixelBuffer else { return nil }
|
|
252
|
+
kCVPixelBufferCGBitmapContextCompatibilityKey: true
|
|
253
|
+
] as CFDictionary
|
|
254
|
+
var buffer: CVPixelBuffer?
|
|
255
|
+
guard CVPixelBufferCreate(kCFAllocatorDefault, side, side, kCVPixelFormatType_32ARGB, options, &buffer) == kCVReturnSuccess,
|
|
256
|
+
let buffer else { return nil }
|
|
279
257
|
CVPixelBufferLockBaseAddress(buffer, [])
|
|
258
|
+
defer { CVPixelBufferUnlockBaseAddress(buffer, []) }
|
|
280
259
|
let context = CGContext(
|
|
281
|
-
data: CVPixelBufferGetBaseAddress(buffer),
|
|
282
|
-
width: width, height: height,
|
|
260
|
+
data: CVPixelBufferGetBaseAddress(buffer), width: side, height: side,
|
|
283
261
|
bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(buffer),
|
|
284
|
-
space: CGColorSpaceCreateDeviceRGB(),
|
|
285
|
-
bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
|
|
262
|
+
space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
|
|
286
263
|
)
|
|
287
|
-
context?.draw(
|
|
288
|
-
CVPixelBufferUnlockBaseAddress(buffer, [])
|
|
264
|
+
context?.draw(picture, in: CGRect(x: 0, y: 0, width: side, height: side))
|
|
289
265
|
return buffer
|
|
290
266
|
}
|
|
291
267
|
```
|
|
292
268
|
|
|
293
|
-
|
|
294
|
-
[references/coreml-swift-integration.md](references/coreml-swift-integration.md).
|
|
269
|
+
Normalization and center-crop helpers are in the reference.
|
|
295
270
|
|
|
296
|
-
##
|
|
271
|
+
## Chaining models
|
|
297
272
|
|
|
298
|
-
|
|
273
|
+
When pre- or post-processing is its own model, call them in order:
|
|
299
274
|
|
|
300
275
|
```swift
|
|
301
|
-
|
|
302
|
-
let preprocessed = try preprocessor.prediction(from: rawInput)
|
|
303
|
-
let mainOutput = try mainModel.prediction(from: preprocessed)
|
|
304
|
-
let finalOutput = try postprocessor.prediction(from: mainOutput)
|
|
305
|
-
```
|
|
276
|
+
import CoreML
|
|
306
277
|
|
|
307
|
-
|
|
308
|
-
|
|
278
|
+
func runChain(_ input: MLFeatureProvider, stages: [MLModel]) async throws -> MLFeatureProvider {
|
|
279
|
+
var current = input
|
|
280
|
+
for stage in stages {
|
|
281
|
+
current = try await stage.prediction(from: current)
|
|
282
|
+
}
|
|
283
|
+
return current
|
|
284
|
+
}
|
|
285
|
+
```
|
|
309
286
|
|
|
310
|
-
|
|
287
|
+
For chains that Xcode manages, build a pipeline model inside the `.mlpackage`;
|
|
288
|
+
each sub-model then runs on the compute unit that suits it.
|
|
311
289
|
|
|
312
|
-
|
|
313
|
-
(resizing, normalization, color space, orientation).
|
|
290
|
+
## Through Vision
|
|
314
291
|
|
|
315
|
-
|
|
292
|
+
Vision takes care of resizing, cropping, normalization, color space and
|
|
293
|
+
orientation.
|
|
316
294
|
|
|
317
295
|
```swift
|
|
318
|
-
import Vision
|
|
319
296
|
import CoreML
|
|
297
|
+
import Vision
|
|
320
298
|
|
|
321
|
-
|
|
322
|
-
let request = CoreMLRequest(model:
|
|
323
|
-
let
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
print("\(classification.identifier): \(classification.confidence)")
|
|
299
|
+
func dominantLabel(in photo: CGImage, model: MLModel) async throws -> (String, Float)? {
|
|
300
|
+
let request = CoreMLRequest(model: try CoreMLModelContainer(model: model))
|
|
301
|
+
let observations = try await request.perform(on: photo)
|
|
302
|
+
guard let top = observations.first as? ClassificationObservation else { return nil }
|
|
303
|
+
return (top.identifier, top.confidence)
|
|
327
304
|
}
|
|
328
305
|
```
|
|
329
306
|
|
|
330
|
-
|
|
307
|
+
`CoreMLRequest` needs iOS 18. The legacy route for detection models:
|
|
331
308
|
|
|
332
309
|
```swift
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
310
|
+
import CoreML
|
|
311
|
+
import Vision
|
|
312
|
+
|
|
313
|
+
func legacyDetections(in frame: CVPixelBuffer, model: MLModel) throws -> [(String, Float, CGRect)] {
|
|
314
|
+
let request = VNCoreMLRequest(model: try VNCoreMLModel(for: model))
|
|
315
|
+
request.imageCropAndScaleOption = .scaleFill
|
|
316
|
+
try VNImageRequestHandler(cvPixelBuffer: frame).perform([request])
|
|
317
|
+
let objects = request.results as? [VNRecognizedObjectObservation] ?? []
|
|
318
|
+
return objects.compactMap { object in
|
|
319
|
+
guard let label = object.labels.first else { return nil }
|
|
320
|
+
return (label.identifier, label.confidence, object.boundingBox)
|
|
341
321
|
}
|
|
342
322
|
}
|
|
343
|
-
request.imageCropAndScaleOption = .scaleFill
|
|
344
|
-
|
|
345
|
-
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer)
|
|
346
|
-
try handler.perform([request])
|
|
347
323
|
```
|
|
348
324
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
## Performance Profiling
|
|
325
|
+
`boundingBox` is normalized. Everything else about Vision (OCR, barcodes,
|
|
326
|
+
documents) is in `vision-framework`.
|
|
353
327
|
|
|
354
|
-
|
|
328
|
+
## Profiling
|
|
355
329
|
|
|
356
|
-
|
|
330
|
+
`MLComputePlan` (iOS 17.4+) tells you, before any prediction, which device
|
|
331
|
+
each operation prefers and how expensive it is:
|
|
357
332
|
|
|
358
333
|
```swift
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
)
|
|
362
|
-
|
|
363
|
-
guard let
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
334
|
+
import CoreML
|
|
335
|
+
|
|
336
|
+
func opsOffAccelerators(modelURL: URL) async throws -> [String] {
|
|
337
|
+
let plan = try await MLComputePlan.load(contentsOf: modelURL, configuration: MLModelConfiguration())
|
|
338
|
+
guard case .program(let program) = plan.modelStructure,
|
|
339
|
+
let entry = program.functions["main"] else { return [] }
|
|
340
|
+
return entry.block.operations.compactMap { op in
|
|
341
|
+
guard let usage = plan.deviceUsage(for: op), case .cpu = usage.preferred else { return nil }
|
|
342
|
+
let cost = plan.estimatedCost(of: op)?.weight ?? 0
|
|
343
|
+
return "\(op.operatorName) cost \(cost)"
|
|
344
|
+
}
|
|
369
345
|
}
|
|
370
346
|
```
|
|
371
347
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
- Prediction latency (per-operation breakdown)
|
|
377
|
-
- Compute device dispatch (CPU/GPU/ANE per operation)
|
|
378
|
-
- Memory allocation
|
|
379
|
-
|
|
380
|
-
Run outside the debugger for accurate results (Xcode: Product > Profile).
|
|
381
|
-
|
|
382
|
-
## Model Deployment
|
|
348
|
+
The Instruments Core ML template shows load time, per-prediction latency with a
|
|
349
|
+
per-operation breakdown, which device each operation ran on, and memory.
|
|
350
|
+
Profile with Product > Profile, not under the debugger, or the numbers are
|
|
351
|
+
not representative.
|
|
383
352
|
|
|
384
|
-
|
|
353
|
+
## Deployment
|
|
385
354
|
|
|
386
|
-
| Strategy |
|
|
355
|
+
| Strategy | Strength | Cost |
|
|
387
356
|
|---|---|---|
|
|
388
|
-
|
|
|
389
|
-
| Background Assets | Preferred for large or
|
|
390
|
-
| On-demand resources | Smaller
|
|
391
|
-
| CloudKit
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
URL, then load the compiled model with `MLModel.load(contentsOf:configuration:)`.
|
|
357
|
+
| In the app bundle | Available instantly and offline | Bigger download |
|
|
358
|
+
| Background Assets | Preferred for large or updatable models | Asset pack setup |
|
|
359
|
+
| On-demand resources | Smaller first download for apps already on ODR | Legacy; choose Background Assets for new work |
|
|
360
|
+
| CloudKit or own server | Most flexible | Needs network, more plumbing |
|
|
361
|
+
|
|
362
|
+
- Size ceilings change; check the current App Store Connect limits. For
|
|
363
|
+
iOS/iPadOS 18 and later they list 4 GB for the thinned app bundle and 8 GB
|
|
364
|
+
per thinned on-demand-resource asset pack.
|
|
365
|
+
- Keep on-demand-resource guidance for projects that already use it.
|
|
366
|
+
- Ship `.mlmodelc` (precompiled) so the device does not compile at first use.
|
|
367
|
+
- For downloaded `.mlmodel`/`.mlpackage` files: compile once with
|
|
368
|
+
`compileModel(at:)`, move the result out of Core ML's temporary directory,
|
|
369
|
+
and key the cache by model version.
|
|
370
|
+
- With Background Assets: make the asset pack locally available, resolve the
|
|
371
|
+
model's URL inside it, then `MLModel.load(contentsOf:configuration:)`.
|
|
372
|
+
- Test on physical devices, above all the lowest-memory one you support: load
|
|
373
|
+
time, first prediction, repeated predictions, background and foreground
|
|
374
|
+
transitions, and low-memory behavior.
|
|
375
|
+
|
|
376
|
+
On-demand resources, for apps that already use them:
|
|
409
377
|
|
|
410
378
|
```swift
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
let
|
|
415
|
-
|
|
416
|
-
|
|
379
|
+
import CoreML
|
|
380
|
+
|
|
381
|
+
func loadTaggedModel(tag: String, name: String) async throws -> (MLModel, NSBundleResourceRequest) {
|
|
382
|
+
let request = NSBundleResourceRequest(tags: [tag])
|
|
383
|
+
try await request.beginAccessingResources()
|
|
384
|
+
guard let url = Bundle.main.url(forResource: name, withExtension: "mlmodelc") else {
|
|
385
|
+
request.endAccessingResources()
|
|
386
|
+
throw CocoaError(.fileNoSuchFile)
|
|
387
|
+
}
|
|
388
|
+
let model = try await MLModel.load(contentsOf: url, configuration: MLModelConfiguration())
|
|
389
|
+
return (model, request)
|
|
390
|
+
}
|
|
417
391
|
```
|
|
418
392
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
**
|
|
439
|
-
|
|
440
|
-
**
|
|
441
|
-
|
|
442
|
-
**
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
**
|
|
447
|
-
|
|
448
|
-
**
|
|
449
|
-
|
|
450
|
-
**
|
|
451
|
-
|
|
452
|
-
**
|
|
453
|
-
|
|
454
|
-
**
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
**DON'T:** Process images manually before passing to Vision + Core ML.
|
|
474
|
-
**DO:** Use `CoreMLRequest` (iOS 18+) or `VNCoreMLRequest` (legacy) to let Vision handle preprocessing.
|
|
475
|
-
**Why:** Vision handles orientation, scaling, and pixel format conversion correctly.
|
|
476
|
-
|
|
477
|
-
## Review Checklist
|
|
478
|
-
|
|
479
|
-
- [ ] Model loaded asynchronously (not blocking main thread)
|
|
480
|
-
- [ ] `MLModelConfiguration.computeUnits` set appropriately for use case
|
|
481
|
-
- [ ] Model instance reused across predictions (not recreated each time)
|
|
482
|
-
- [ ] Auto-generated class used when available (typed inputs/outputs)
|
|
483
|
-
- [ ] Error handling for model loading and prediction failures
|
|
484
|
-
- [ ] Compiled model cached persistently if compiled at runtime
|
|
485
|
-
- [ ] Image inputs use Vision pipeline (`CoreMLRequest` iOS 18+ or `VNCoreMLRequest`) for correct preprocessing
|
|
486
|
-
- [ ] `MLComputePlan` checked to verify compute device dispatch (iOS 17.4+)
|
|
487
|
-
- [ ] Batch predictions used when processing multiple inputs
|
|
488
|
-
- [ ] Model size appropriate for deployment strategy (bundle, Background Assets, ODR)
|
|
489
|
-
- [ ] Memory tested on target devices (especially older devices with less RAM)
|
|
490
|
-
- [ ] Predictions run outside debugger for accurate performance measurement
|
|
393
|
+
Keep the returned request alive while the model is in use and call
|
|
394
|
+
`endAccessingResources()` when you are done with it.
|
|
395
|
+
|
|
396
|
+
## Memory
|
|
397
|
+
|
|
398
|
+
- Drop model references when the app goes to the background to release GPU
|
|
399
|
+
and Neural Engine memory; load again on return to the foreground.
|
|
400
|
+
- `.all` is the default. Use `.cpuOnly` only when profiling or policy points
|
|
401
|
+
to contention, thermal limits, energy, deterministic tests or a real
|
|
402
|
+
background-execution constraint.
|
|
403
|
+
- Keep one `MLModel` per compiled model and share it through an actor.
|
|
404
|
+
- Models above roughly 100 MB can trigger memory warnings; listen for
|
|
405
|
+
`UIApplication.didReceiveMemoryWarningNotification` and release cached
|
|
406
|
+
models.
|
|
407
|
+
|
|
408
|
+
## Common mistakes
|
|
409
|
+
|
|
410
|
+
1. **Loading on the main thread.** Large models take seconds; use
|
|
411
|
+
`MLModel.load(contentsOf:configuration:)` or a background actor.
|
|
412
|
+
2. **Recompiling every launch.** Compilation is expensive; compile once and
|
|
413
|
+
keep the `.mlmodelc` in Application Support.
|
|
414
|
+
3. **Hard-coding `.cpuOnly`.** `.all` lets Core ML use the Neural Engine and
|
|
415
|
+
GPU, usually faster and more efficient.
|
|
416
|
+
4. **Declaring GPU or Neural Engine off-limits for anything near the
|
|
417
|
+
background.** Access depends on system policy, execution mode, contention,
|
|
418
|
+
thermal state and energy; profile on a device. `.cpuOnly` is a tradeoff,
|
|
419
|
+
not a rule, and a backgrounded app may be suspended or throttled anyway.
|
|
420
|
+
5. **Feature type mismatches.** Images go in as `MLFeatureValue(pixelBuffer:)`,
|
|
421
|
+
not raw bytes; mismatches crash obscurely or give silently wrong output.
|
|
422
|
+
6. **A new `MLModel` per prediction.** Loading costs memory and time; load once
|
|
423
|
+
and reuse through an actor.
|
|
424
|
+
7. **No error handling.** Loading and prediction can fail on older or
|
|
425
|
+
constrained devices; catch and fall back.
|
|
426
|
+
8. **Assuming everything runs on the Neural Engine.** Unsupported operations
|
|
427
|
+
fall back to the CPU and can dominate latency; check with `MLComputePlan`.
|
|
428
|
+
9. **Hand-preprocessing images for Vision.** `CoreMLRequest` (iOS 18) and
|
|
429
|
+
`VNCoreMLRequest` already handle orientation, scaling and pixel format.
|
|
430
|
+
10. **Dropping `await` on prediction in async code.** On iOS 17 and later the
|
|
431
|
+
async overload is selected there; write `try await`.
|
|
432
|
+
|
|
433
|
+
## Review checklist
|
|
434
|
+
|
|
435
|
+
- [ ] Model loaded asynchronously
|
|
436
|
+
- [ ] `computeUnits` chosen deliberately
|
|
437
|
+
- [ ] One model instance reused across predictions
|
|
438
|
+
- [ ] Generated class used where Xcode provides one
|
|
439
|
+
- [ ] Load and prediction failures handled
|
|
440
|
+
- [ ] Runtime-compiled models cached in a durable location
|
|
441
|
+
- [ ] Image inputs routed through Vision (`CoreMLRequest` on iOS 18+, otherwise `VNCoreMLRequest`)
|
|
442
|
+
- [ ] Device dispatch checked with `MLComputePlan` (iOS 17.4+)
|
|
443
|
+
- [ ] Batch API used for many inputs
|
|
444
|
+
- [ ] Model size matches the delivery strategy (bundle, Background Assets, ODR)
|
|
445
|
+
- [ ] Memory measured on target devices, especially older low-RAM ones
|
|
446
|
+
- [ ] Latency measured outside the debugger
|
|
491
447
|
|
|
492
448
|
## References
|
|
493
449
|
|
|
494
|
-
-
|
|
495
|
-
-
|
|
496
|
-
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
450
|
+
- `references/coreml-swift-integration.md`
|
|
451
|
+
- `apple-on-device-ai` for conversion and compression in Python
|
|
452
|
+
- https://developer.apple.com/documentation/coreml
|
|
453
|
+
- https://developer.apple.com/documentation/coreml/mlmodel
|
|
454
|
+
- https://developer.apple.com/documentation/coreml/mltensor
|
|
455
|
+
- https://developer.apple.com/documentation/coreml/mlcomputeplan-1w21n
|
|
456
|
+
- https://developer.apple.com/documentation/backgroundassets
|