Environment setup
Use Python 3.11 or newer on macOS. uv manages the project and virtual environment. The device check picks Apple Silicon MPS when it is available, and CPU if it is not.
curl -LsSf https://astral.sh/uv/install.sh | sh
mkdir -p clothing-coreai && cd clothing-coreai
uv init --python 3.11
uv venv
uv add torch torchvision coreai-torch
uv run python -c "import torch, torchvision; print(torch.__version__, torchvision.__version__); print('MPS:', torch.backends.mps.is_available())"
uv run python convert.pySave the lesson code as train.py or the named script for this lesson. uv run uses the project environment, so you do not need a global pip install.
Work backward from AIModel and main. The app needs a portable clothing.aimodel with named tensors and operations that Core AI can turn into hardware work. That is why the original course uses torch.export and coreai-torch. Conversion is a runtime need that you can see as a build step.
Build the graph the runtime can run
torch.export makes the graph and its assumptions clear. get_decomp_table() gives the Core AI breakdown choices so bigger operations become forms the converter can handle. TorchConverter packages the resulting program as a Core AI file with input name image, output name logits, and function main.
# The forward course has the full script. The order is the point.
example = torch.zeros(1, 1, 28, 28, dtype=torch.float32)
ep = torch.export.export(model.eval(), args=(example,))
ep = ep.run_decompositions(get_decomp_table())
# Register any release-supported custom Metal kernels first.
# register_custom_kernels(...)
coreai_program = TorchConverter().add_exported_program(
ep, input_names=["image"], output_names=["logits"]
)
asset = coreai_program.to_coreai().save_asset("clothing.aimodel")
The custom-kernel line is a reminder of where it goes, not a fake API recipe. When you use the Apple and coreai-torch custom Metal tools, register the kernels before add_exported_program and follow the names in the installed release. Without custom kernels, ordinary graph lowering still handles the operations that are supported.
Names are part of the runtime contract
Inspect the saved file in Xcode's model viewer. Confirm the function name, tensor names, shapes, and element types before you debug Swift. A successful Python conversion does not prove that the app is passing the right array. The runtime and the app both depend on the same description.
What conversion must give Metal
- Only operations with a valid Core AI lowering, or a custom kernel that is clearly supported, should reach the file.
- Fixed example shapes should match the tensors the app will pass.
- The portable file should keep a stable interface that the host can prepare once.
Conversion also depends on the step before it. The graph can only be exported because training produced a model with sensible fixed shapes, class order, and portable weights. Continue to Training must give conversion a model it can use, then compare the original training lesson.
Key concepts
- Conversion exists so the runtime gets a graph it can run.
- The path is
ClothingCNNtotorch.exporttoget_decomp_table()toTorchConvertertoclothing.aimodel. - Export with a float32
[1, 1, 28, 28]example. Namesimage,logits, andmainare part of the contract. - Inspect the saved asset in the Xcode model viewer before you debug Swift.
Takeaways
- Successful Python conversion does not prove the app passes the right array.
- Fixed example shapes in export must match what the app will pass.
- Only supported lowerings or clearly registered custom kernels should reach the file.