
A new Mac runs for a day on a charge and compiles faster than the Intel laptop it replaced, and then the first docker pull of a machine-learning image is slow, the container inside it is slower, and a conda install pulls packages that are not built for the chip. None of this is Apple’s tooling being bad. It is that a decade of open-source machine learning was built with one assumption baked in, that the machine is an x86-64 box, usually with an NVIDIA GPU, and the M-series chips are neither. This post says where that assumption surfaces for Docker, PyTorch and conda, and what the native route looks like. It is written as of spring 2025; the friction has been shrinking every year and some of it will have gone by the time you read this.
The architecture is the whole story
Apple Silicon is arm64. Most published container images, most compiled Python wheels, and all of CUDA are x86_64. Anything that arrives as a compiled binary either has an ARM build or has to be emulated, and emulation is where the time goes. Pure Python does not care, and the numerical stack that matters, NumPy, SciPy, pandas, PyTorch, has ARM builds now. The trouble is concentrated in the long tail: the package that wraps a Fortran library, the image someone built once for CUDA, the tool whose release script only ever ran on Linux.
Docker runs foreign images, slowly, and the image is usually foreign
Docker Desktop on a Mac runs Linux containers in a virtual machine. An arm64 image runs natively in that VM; an x86_64 image runs under QEMU emulation, which is often several times slower and occasionally simply crashes on an instruction it does not support. Whether you get the fast path depends on whether the image you pulled has an ARM variant:
docker pull pytorch/pytorch:latest # multi-arch: picks arm64 on a Mac
docker image inspect pytorch/pytorch:latest --format '{{.Architecture}}'The official base images (python, ubuntu, pytorch/pytorch) are multi-architecture and pick the native variant automatically. Images built by a team for their own CI are usually not, and neither is anything that includes CUDA, since CUDA has no ARM Mac target at all. The practical rule: build your own images on the Mac, or with docker buildx for both architectures, and treat a GPU image as something that runs on the Linux box it was built for. The subtler cost is drift: production and CI run x86_64 Linux, so an image that works natively on the laptop has not been tested where it will be deployed.
PyTorch is native on the CPU, and the GPU is a different GPU
PyTorch publishes arm64 macOS wheels, so the plain install is the fast path:
pip install torch torchvision torchaudioThat gives CPU training and inference at native speed. The GPU in an M-series chip is not an NVIDIA GPU, so CUDA is not an option; PyTorch reaches it through the mps backend (Metal Performance Shaders), which as of spring 2025 covers most common operations but not all, and is noticeably slower than a discrete NVIDIA card for training anything large. The realistic use is developing and debugging on the Mac and training on a machine with the hardware. Compiled extensions beyond the core three (custom CUDA kernels, some torchvision ops) are where an ARM wheel may be missing and a build from source is needed.
conda works, and the community build is the one to install
Anaconda ships an ARM installer, but its defaults channel is the one with licence terms that matter for commercial use, and it is not the community build. Miniforge is the same conda with arm64 builds from conda-forge, and it is the one to install:
conda create -n ml python=3.10 numpy pandas scikit-learn
conda activate ml
pip install torch torchvision # PyTorch's own wheels, not conda'sThe split in that snippet is deliberate. conda-forge carries native builds of the numerical stack and the compiled libraries under it; PyTorch’s own wheels are the most current ARM builds of PyTorch, so pip installs those into the conda environment. Mixing the two managers in general is a known way to break an environment, and this is the one place it is the standard advice.
Why Linux does not have this problem
A Linux workstation with an NVIDIA card is the machine the ecosystem assumes. Images run without emulation, CUDA is first-class, and every wheel has been built and tested for it a thousand times. Apple Silicon is a good laptop for the parts of the job that are Python, and a machine that borrows Linux hardware for the parts that are not. The native tools remove most of the friction; what they cannot remove is the GPU.
Where it stops holding
The date in the description matters. Multi-arch images, mps coverage and ARM wheels have each improved year on year, and any specific claim here about what is missing is the one most likely to be stale. What does not change is the shape: check the architecture of every binary artifact before assuming it is the slow one.
Silicon. Changed. Assumptions. Images. Assume. Intel. Go. Native. Expect. Rough. Edges.