Apple Silicon M2下PyTorch从安装到运行的全流程图解

云信安装大师
90
AI 质量分
10 5 月, 2025
3 分钟阅读
0 阅读

Apple Silicon M2下PyTorch从安装到运行的全流程图解

引言

随着Apple Silicon芯片的普及,许多开发者希望在M1/M2系列Mac上运行PyTorch进行深度学习开发。本文将详细介绍在Apple Silicon M2芯片的Mac上安装和运行PyTorch的全流程,包括环境准备、安装步骤、验证方法以及一个完整的MNIST分类示例。

准备工作

硬件和软件要求

  • Apple Silicon M1/M2芯片的Mac电脑
  • macOS 12.3 (Monterey) 或更高版本
  • Python 3.8或更高版本(推荐使用Python 3.9)
  • pip包管理工具

推荐环境

建议使用conda或venv创建虚拟环境,避免与系统Python环境冲突:

代码片段
# 使用conda创建虚拟环境(如果没有conda,可以跳过这步)
conda create -n pytorch_m2 python=3.9
conda activate pytorch_m2

# 或者使用Python内置venv
python -m venv pytorch_m2_env
source pytorch_m2_env/bin/activate

PyTorch安装步骤

1. 安装PyTorch和Metal支持

Apple为M1/M2芯片提供了Metal Performance Shaders (MPS)后端,可以加速PyTorch运算。以下是安装命令:

代码片段
pip install torch torchvision torchaudio

注意:从PyTorch 1.12开始,官方已经提供了对Apple Silicon的原生支持,无需再通过其他渠道安装。

2. 验证安装

创建一个Python脚本verify.py来检查PyTorch是否正确安装并支持MPS:

代码片段
import torch

print(f"PyTorch版本: {torch.__version__}")
print(f"MPS设备可用: {torch.backends.mps.is_available()}")
print(f"MPS是否已构建: {torch.backends.mps.is_built()}")

if torch.backends.mps.is_available():
    device = torch.device("mps")
    x = torch.rand(5, device=device)
    print(x)
else:
    print("MPS设备不可用")

运行结果应该类似于:

代码片段
PyTorch版本: 2.0.0
MPS设备可用: True
MPS是否已构建: True
tensor([0.1234, 0.5678, ..., device='mps:0'])

MNIST分类示例

下面我们通过一个完整的MNIST手写数字分类示例来演示PyTorch在M2上的使用。

完整代码 (mnist_mps.py)

代码片段
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader

# 检查设备可用性并设置device变量
device = torch.device("mps" if torch.backends.mps.is_available() else "cpu")
print(f"使用的设备: {device}")

# 定义数据预处理
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

# 加载数据集(首次运行会自动下载)
train_dataset = torchvision.datasets.MNIST(
    root='./data', 
    train=True,
    download=True,
    transform=transform)

test_dataset = torchvision.datasets.MNIST(
    root='./data',
    train=False,
    download=True,
    transform=transform)

# 创建数据加载器
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=1000, shuffle=False)

# 定义简单的CNN模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 10)

    def forward(self, x):
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2(x), 2))
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)

model = Net().to(device) # Move model to MPS device

optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

# 训练函数
def train(epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device) # Move data to MPS device

        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()

        if batch_idx % 100 == 0:
            print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)} '
                  f'({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')

# 测试函数            
def test():
    model.eval()
    test_loss = 0
    correct = 0

    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device) # Move data to MPS device

            output = model(data)
            test_loss += F.nll_loss(output, target).item()
            pred = output.argmax(dim=1)
            correct += pred.eq(target).sum().item()

    test_loss /= len(test_loader.dataset)

    print(f'\nTest set: Average loss: {test_loss:.4f}, '
          f'Accuracy: {correct}/{len(test_loader.dataset)} '
          f'({100.*correct/len(test_loader.dataset):.0f}%)\n')

# 训练和测试循环            
for epoch in range(1,14):
   train(epoch) 
   test()

print("训练完成!")

代码说明

关键点解析

  1. 设备设置torch.device("mps")指定使用Apple Metal后端加速计算。

    代码片段
    device = torch.device("mps" if ... else "cpu")  
    
  2. 数据迁移:必须显式将张量移动到MPS设备:

    代码片段
    data.to(device)  
    
  3. 模型迁移:模型实例化后立即转移到目标设备:

    代码片段
    model.to(device)  
    

性能优化技巧

  • 批处理大小:适当增大batch_size(如128/256)可以提升MPS利用率。
  • 混合精度训练:可结合torch.cuda.amp模块实现(需PyTorch>=1.10)。

常见问题解决

Q1:安装后提示”MPS不可用”

可能原因及解决方案:
– macOS版本过低 →升级到至少Monterey(12.x)
– PyTorch版本不匹配 →重新安装最新版:

代码片段
pip install --force-reinstall torch  

Q2:运行时出现内存错误

解决方法:
减小批处理大小 →调整DataLoader的batch_size参数。
清理缓存 →在代码中添加:

代码片段
torch.mps.empty_cache()  

Q3:与CUDA代码的兼容性

需要修改的点:
cuda() →替换为to(device)通用写法。
torch.cuda.FloatTensor →改用常规张量类型。

性能对比参考

下表展示在M2 Pro芯片上的典型表现(基于MNIST示例):

Metric CPU MPS Speedup
Epoch Time ~45s ~12s ~3x
GPU Util ~85%

注:实际加速比因模型结构和超参数而异

总结

本文详细介绍了在Apple Silicon M系列芯片上配置PyTor开发环境的完整流程,关键步骤包括:

1️⃣ 正确安装PyTorch的Apple Silicon优化版本

代码片段
pip install --pre torch  

3️⃣ 显式管理设备和张量位置

代码片段
model.to(torch.device("mps"))  
input_data.to("mps")  

5️⃣ 利用原生工具监控性能

通过macOS自带的Activity Monitor观察GPU利用率。

原创 高质量