← All courses ← Course home

Lesson 05 of 08

Run the on-device pipeline

Put the exported diffusion resource folder in an Xcode 27 app, load it with current Core AI Swift utilities, and measure a real generation on the target device.

Agent brief (llms.md)

Why the app on the phone is the real test

A successful export on a Mac is not a product. Privacy, speed, and offline use only hold when the app generates from the baked resource without a network. That is proof the phone has the model. The clothing-classifier course shows the same last step for a small CNN. This lesson is that last step for a personalized generator. See From the metal to the model for what the GPU actually ran.

The app loads the merged resource. It does not download a LoRA. It does not hot-swap an adapter. If you need a second subject, you bake a second model file and ship a second build or a second bundled resource.

The steps, one box at a time

Keep the export folder intact.

BuildMulti-component resource

Add that folder to the Xcode target as a resource, not as a flattened file list you renamed.

BuildMulti-component resource
Xcode 27Bundle resource

Prepare the Core AI diffusion pipeline once at launch.

BuildMulti-component resource
Xcode 27Bundle resource
Core AIPrepare once

Generate off the main thread. Show the image, the seed, and the elapsed time. Profile on the target device.

BuildMulti-component resource
Xcode 27Bundle resource
Core AIPrepare once
DeviceImage, seed, time

Environment setup

Use Xcode 27 on macOS. Create an iOS or macOS SwiftUI App. Add the Core AI framework. Install the Metal Toolchain. Add the whole exported folder to Copy Bundle Resources.

xcode-select --install
xcodebuild -version
# File > New > Project > App, Interface: SwiftUI
# Xcode Settings > Components > Metal Toolchain
# Drag artifacts/personalized into the target. Confirm it is in Copy Bundle Resources.

Python is not required on this lesson's main path. Keep the Mac uv project around so you can regenerate the resource.

cd diffusion-lora-coreai
uv run python -c "import torch; print(torch.__version__); print('MPS:', torch.backends.mps.is_available())"

Worked path

Build a narrow first screen. One prompt field. One seed. One Generate button. One image. One elapsed-time label. Prepare the pipeline in a .task or app setup, not in the button.

import SwiftUI
import CoreAI

// Illustrative shape only. Confirm type names in the installed Xcode 27 docs.
@MainActor
final class Generator: ObservableObject {
    @Published var image: Image?
    @Published var elapsedMs: Int = 0
    @Published var status: String = "Preparing"

    private var pipeline: AnyObject?

    func prepare() async {
        do {
            let url = Bundle.main.resourceURL!.appending(path: "personalized")
            pipeline = try await loadDocumentedDiffusionPipeline(resource: url)
            status = "Ready"
        } catch {
            status = "Load failed: \(error.localizedDescription)"
        }
    }

    func generate(prompt: String, seed: UInt64) async {
        let start = Date()
        do {
            let cgImage = try await runDocumentedGeneration(pipeline, prompt: prompt, seed: seed)
            image = Image(decorative: cgImage, scale: 1)
            elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
            status = "Seed \(seed)"
        } catch {
            status = "Generate failed: \(error.localizedDescription)"
        }
    }
}

The helper names above are placeholders on purpose. Core AI diffusion types move with the SDK. Open the installed documentation for the current pipeline loader and generation call. The clothing course shows the same care for AIModel and NDArray.

Compare like with like. Same prompt. Same seed. Base export versus merged export. Check that the subject or style you wrote down actually appears. Save the prompt, seed, elapsed time, device model, and resource checksum with the screenshot.

Runtime boundary. The app loads the exported merged resource. It does not attach a LoRA at runtime. A second personalization is a second bake.

Failure modes

Done when

Keep learning

PyTorch to Core AI in Xcode · From the metal to the model · Core AI models, typed · Model architectures in plain English · LLM LoRA for your writing style

Key concepts

  • Mac export success is not the product. Device generation is.
  • Bundle the intact multi-component folder in Xcode 27.
  • Prepare the pipeline once at launch. Generate off the main thread.
  • The app loads the baked merged resource only. No adapter download.

Takeaways

  • Record prompt, seed, device, checksum, and elapsed time.
  • Flattening the folder breaks prepare.
  • A second personalization is a second bake and a second resource.