{"id":448,"date":"2026-05-07T00:00:00","date_gmt":"2026-05-06T23:00:00","guid":{"rendered":"https:\/\/kosokoking.com\/?p=448"},"modified":"2026-05-02T11:52:46","modified_gmt":"2026-05-02T10:52:46","slug":"setting-up-an-ai-environment-on-apple-silicon","status":"publish","type":"post","link":"https:\/\/kosokoking.com\/index.php\/technology\/setting-up-an-ai-environment-on-apple-silicon\/","title":{"rendered":"Setting up an AI environment on Apple Silicon"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">I recently started working through an AI module that required a local Python environment with PyTorch, scikit-learn, and the usual Hugging Face stack. The guide was written for a generic Linux or Windows audience, and I was following along on a Mac. Within thirty minutes I had hit three separate problems, none of which were covered in the documentation, and all of which are things that trip up Apple Silicon users on a regular basis.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is a walkthrough of the setup process for any M-series Mac, including the exact errors I ran into and how I fixed them. If you are setting up a machine learning environment on Apple Silicon for the first time, this should save you the debugging.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why Miniconda and not plain Python<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The module recommended Miniconda over a standard Python installation, and it is the right call for ML work. Conda handles binary dependencies in a way that pip alone does not. Libraries like NumPy, SciPy, and PyTorch ship with platform-specific compiled code, and conda resolves those binary compatibility requirements automatically. It also isolates environments properly, so a set of packages for one project cannot break another.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On macOS, the installation is straightforward with Homebrew:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>brew install --cask miniconda\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After installation, verify it worked:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>conda --version\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see something like\u00a0<code>conda 25.9.2<\/code>\u00a0or later. If that command works, you have a working conda binary. But having a binary and having a functional shell integration are two different things, which brings us to the first problem.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Problem one: conda activate does not work after conda init<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With Miniconda installed, I created a new environment:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>conda create -n ai python=3.11\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That completed without issues. Then I ran&nbsp;<code>conda init<\/code>&nbsp;as the documentation instructed, and tried to activate the environment:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>conda init\nconda activate ai\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The response:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CondaError: Run 'conda init' before 'conda activate'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">I had just run&nbsp;<code>conda init<\/code>. The output had said &#8220;no change&#8221; next to every file it checked, and the final line read &#8220;No action taken.&#8221; Closing and reopening the terminal did not help. Same error.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The problem is a shell mismatch. On modern Macs (anything from Catalina onwards), the default shell is zsh. But when you run&nbsp;<code>conda init<\/code>&nbsp;without specifying a shell, conda checks its default list and, depending on the installation method, may only write its initialisation hooks into&nbsp;<code>~\/.bash_profile<\/code>, which zsh does not read. You can confirm this by checking what is actually in your zsh configuration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo $SHELL\n# \/bin\/zsh\n\ncat ~\/.zshrc\n# (no conda block present)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Meanwhile,&nbsp;<code>~\/.bash_profile<\/code>&nbsp;has the full conda initialisation block sitting in it, completely ignored by zsh.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The fix is to tell conda exactly which shell to initialise:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>conda init zsh\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then either restart your terminal or reload the config:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>exec zsh\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now&nbsp;<code>conda activate ai<\/code>&nbsp;works. Your prompt changes to&nbsp;<code>(ai)<\/code>, confirming you are inside the isolated environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is a well-documented issue on conda&#8217;s GitHub tracker. The root cause is that conda&#8217;s default init behaviour does not reliably detect the active shell on macOS when installed through Homebrew&#8217;s cask mechanism. It writes to bash config files and reports &#8220;no change&#8221; because the bash files already exist from a previous partial setup, but it never touches zsh. The error message telling you to &#8220;run conda init&#8221; is misleading, because you already did, and it is not clear that you need to specify the shell explicitly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Problem two: the CUDA command that does not belong on your Mac<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With the environment active, the next step was installing PyTorch. The module&#8217;s instructions included this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>conda install -y pytorch torchvision torchaudio pytorch-cuda=12.4 -c pytorch -c nvidia\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This command is written for machines with NVIDIA GPUs. M-series Macs do not have NVIDIA hardware. They use Apple&#8217;s own GPU cores, accessed through the Metal framework. Attempting to install&nbsp;<code>pytorch-cuda<\/code>&nbsp;on Apple Silicon will either fail outright or pull in packages that cannot function on your hardware.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The correct command for any M-series Mac:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>conda install -y pytorch torchvision torchaudio -c pytorch\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Drop&nbsp;<code>pytorch-cuda=12.4<\/code>&nbsp;entirely. Drop the&nbsp;<code>-c nvidia<\/code>&nbsp;channel. PyTorch&#8217;s macOS builds have included Metal Performance Shaders (MPS) support since version 1.12, and the standard conda package from the pytorch channel includes it automatically on ARM64 Macs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After installation, verify that your Mac&#8217;s GPU is accessible to PyTorch:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>python -c \"import torch; print(torch.backends.mps.is_available())\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This should print&nbsp;<code>True<\/code>. If it prints&nbsp;<code>False<\/code>, check that you are running a native ARM64 build of Python rather than an x86 build under Rosetta. An Intel-emulated Python is a common reason for MPS reporting itself as unavailable even on capable hardware.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How MPS compares to CUDA in practice<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">MPS is not a drop-in replacement for CUDA in every scenario. It covers the standard operations used in neural network training, including matrix multiplication, convolutions, batch normalisation, activation functions, and most loss functions. Common architectures like ResNet, BERT, and EfficientNet run on MPS without modification, and Hugging Face&#8217;s Trainer class detects and uses the MPS device automatically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, not every PyTorch operation has a Metal kernel implementation yet. When your code hits an unsupported operation, PyTorch raises an error. The workaround is an environment variable that falls back to CPU for unsupported ops:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PYTORCH_ENABLE_MPS_FALLBACK=1 python your_script.py\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The other significant limitation is that MPS does not support distributed training. You are limited to the GPU cores in your SoC. For the kind of learning and prototyping that most AI modules involve, this is more than sufficient.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Apple Silicon&#8217;s unified memory architecture is actually an advantage for certain workloads. Unlike discrete NVIDIA GPUs where data must be copied across a PCIe bus between system RAM and GPU VRAM, M-series chips share a single memory pool between CPU and GPU. PyTorch still manages tensor placement internally, but the absence of physical data movement across a bus reduces overhead, particularly when working with models that are large relative to available memory.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Problem three: pip is missing from the environment<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The module&#8217;s setup instructions included a couple of pip installs after the conda packages:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip install requests requests_toolbelt\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Running this inside the freshly created conda environment returned &#8220;command not found.&#8221; This was unexpected because pip normally ships with Python.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The fix is simple:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>conda install pip\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Or, if you want to use Python&#8217;s built-in bootstrap mechanism:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>python -m ensurepip\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Either approach installs pip into your active conda environment. After that, verify it is pointing to the right location:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip --version\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The path should include&nbsp;<code>\/envs\/ai\/<\/code>&nbsp;in it, confirming pip is installed inside your conda environment and not at the system level. If the path points to&nbsp;<code>\/usr\/bin\/pip<\/code>&nbsp;or somewhere outside your conda directory, you are using the system pip, and packages will not install into your isolated environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A practical note on mixing conda and pip: prefer conda for core scientific packages (PyTorch, NumPy, SciPy, scikit-learn) and use pip only for packages that conda does not carry. Mixing the two package managers can create dependency conflicts because they resolve requirements differently. When you do use pip inside a conda environment, always install the conda packages first, then layer pip packages on top.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The full working setup sequence for M-series Macs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For anyone following along with a similar AI module on an M-series Mac, here is the complete sequence that works:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Install Miniconda via Homebrew\nbrew install --cask miniconda\n\n# Initialise conda for zsh specifically\nconda init zsh\nexec zsh\n\n# Optionally stop the (base) prefix from appearing on every new terminal\nconda config --set auto_activate_base false\n\n# Add channels\nconda config --add channels defaults\nconda config --add channels conda-forge\nconda config --add channels pytorch\nconda config --set channel_priority strict\n\n# Create and activate your environment\nconda create -n ai python=3.11\nconda activate ai\n\n# Install core ML packages (no CUDA, no nvidia channel)\nconda install -y numpy scipy pandas scikit-learn matplotlib seaborn transformers datasets tokenizers accelerate evaluate optimum huggingface_hub nltk category_encoders\nconda install -y pytorch torchvision torchaudio -c pytorch\n\n# Install pip, then use it for anything conda does not have\nconda install pip\npip install requests requests_toolbelt\n\n# Verify GPU access\npython -c \"import torch; print(torch.backends.mps.is_available())\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Keeping things updated<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For conda-managed packages:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>conda update --all\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This updates everything conda installed but does not touch pip packages. For pip packages, check what is outdated first:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip list --outdated\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then update selectively rather than in bulk:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip install -U requests requests_toolbelt\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Bulk-updating all pip packages at once (<code>pip install -U $(pip list --outdated | awk 'NR&gt;2 {print $1}')<\/code>) works but risks breaking dependency chains. Be selective unless you are comfortable rebuilding the environment from scratch if something goes wrong.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What this setup actually gets you<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With this environment running, you have PyTorch with Metal GPU acceleration, the full Hugging Face ecosystem for working with pre-trained models and datasets, and the standard scientific Python stack for data manipulation and visualisation. Training times on Apple Silicon are genuinely competitive for small to medium models. You will not match an A100, but for learning, prototyping, and fine-tuning, the M-series hardware is more than adequate, and you do not need to pay for cloud compute or wait for a VM to spin up.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The three problems I hit are all well-known in isolation, but I have not seen them documented together in the context of following an actual AI course setup guide on a Mac. The zsh\/bash mismatch catches almost everyone on a first conda install. The CUDA command is copy-pasted from guides written for NVIDIA hardware without any Mac-specific annotation. And pip&#8217;s absence from a fresh conda environment is counterintuitive enough that people assume they broke something when they didn&#8217;t. None of these are difficult fixes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Three common problems when setting up PyTorch and Miniconda on M-series Macs for AI, from the conda zsh mismatch to CUDA commands that don&#8217;t belong on your Mac.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[721,656,727,136,722,725,724,726,723,728],"class_list":["post-448","post","type-post","status-publish","format-standard","hentry","category-technology","tag-apple-silicon","tag-deep-learning","tag-environment-setup","tag-machine-learning","tag-macos","tag-metal-performance-shaders","tag-miniconda","tag-python","tag-pytorch","tag-troubleshooting"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/posts\/448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/comments?post=448"}],"version-history":[{"count":1,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/posts\/448\/revisions"}],"predecessor-version":[{"id":449,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/posts\/448\/revisions\/449"}],"wp:attachment":[{"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/media?parent=448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/categories?post=448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/tags?post=448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}