mac m1芯片如何使用gpu

Posted githubcurry

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mac m1芯片如何使用gpu相关的知识,希望对你有一定的参考价值。

2022年5月,PyTorch官方宣布已正式支持在M1芯片版本的Mac上进行模型加速。官方对比数据显示,和CPU相比,M1上炼丹速度平均可加速7倍。

1.加速原理

Question1:Mac M1芯片 为什么可以用来加速 pytorch?

因为 Mac M1芯片不是一个单纯的一个CPU芯片,而是包括了CPU(中央处理器),GPU(图形处理器),NPU(神经网络引擎),以及统一内存单元等众多组件的一块集成芯片。由于Mac M1芯片集成了GPU组件,所以可以用来加速pytorch

Question2:Mac M1芯片 上GPU的的显存有多大?

Mac M1芯片的CPU和GPU使用统一的内存单元。所以Mac M1芯片的能使用的显存大小就是 Mac 电脑的内存大小

Question3:使用Mac M1芯片加速 pytorch 需要安装 cuda后端吗?

不需要,cuda是适配nvidia的GPU的,Mac M1芯片中的GPU适配的加速后端是mps,在Mac对应操作系统中已经具备,无需单独安装。只需要安装适配的pytorch即可

Question4:为什么有些可以在Mac Intel芯片电脑安装的软件不能在Mac M1芯片电脑上安装?

Mac M1芯片为了追求高性能和节能,在底层设计上使用的是一种叫做arm架构的精简指令集,不同于Intel等常用CPU芯片采用的x86架构完整指令集。所以有些基于x86指令集开发的软件不能直接在Mac M1芯片电脑上使用

2.环境配置

首先,检查mac型号

点击 桌面左上角mac图标-----关于本机,确定是m1芯片,确定内存大小(最好有16G以上,8G可能不太够用)。

2.1下载 miniforge3

miniforge3可以理解成 miniconda/annoconda 的社区版,提供了更稳定的对M1芯片的支持

annoconda 在 2022年5月开始也发布了对 mac m1芯片的官方支持,但还是推荐社区发布的miniforge3,开源且更加稳定。

2.2安装 miniforge3

chmod +x ~/Downloads/Miniforge3-MacOSX-arm64.sh
sh ~/Downloads/Miniforge3-MacOSX-arm64.sh
source ~/miniforge3/bin/activate

2.3安装 pytorch (v1.12版本已经正式支持了用于mac m1芯片gpu加速的mps后端。)

pip install torch>=1.12 -i https://pypi.tuna.tsinghua.edu.cn/simple 

2.4测试环境

import torch 
print(torch.backends.mps.is_available()) 
print(torch.backends.mps.is_built())

如果输出都是True的话,那么恭喜你配置成功了。

3.范例代码

下面以mnist手写数字识别为例,演示使用mac M1芯片GPU的mps后端来加速pytorch的完整流程。

核心操作非常简单,和使用cuda类似,训练前把模型和数据都移动到torch.device(“mps”)就可以了。

import torch 
from torch import nn 
import torchvision 
from torchvision import transforms 
import torch.nn.functional as F import os,sys,time
import numpy as np
import pandas as pd
import datetime 
from tqdm import tqdm 
from copy import deepcopy
from torchmetrics import Accuracydef printlog(info):nowtime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')print("\\n"+"=========="*8 + "%s"%nowtime)print(str(info)+"\\n")

# 一,准备数据
transform = transforms.Compose([transforms.ToTensor()])ds_train = torchvision.datasets.MNIST(root="mnist/",train=True,download=True,transform=transform)
ds_val = torchvision.datasets.MNIST(root="mnist/",train=False,download=True,transform=transform)dl_train =  torch.utils.data.DataLoader(ds_train, batch_size=128, shuffle=True, num_workers=2)
dl_val =  torch.utils.data.DataLoader(ds_val, batch_size=128, shuffle=False, num_workers=2)

# 二,定义模型
def create_net():net = nn.Sequential()net.add_module("conv1",nn.Conv2d(in_channels=1,out_channels=64,kernel_size = 3))net.add_module("pool1",nn.MaxPool2d(kernel_size = 2,stride = 2))net.add_module("conv2",nn.Conv2d(in_channels=64,out_channels=512,kernel_size = 3))net.add_module("pool2",nn.MaxPool2d(kernel_size = 2,stride = 2))net.add_module("dropout",nn.Dropout2d(p = 0.1))net.add_module("adaptive_pool",nn.AdaptiveMaxPool2d((1,1)))net.add_module("flatten",nn.Flatten())net.add_module("linear1",nn.Linear(512,1024))net.add_module("relu",nn.ReLU())net.add_module("linear2",nn.Linear(1024,10))return netnet = create_net()
print(net)# 评估指标
class Accuracy(nn.Module):def __init__(self):super().__init__()self.correct = nn.Parameter(torch.tensor(0.0),requires_grad=False)self.total = nn.Parameter(torch.tensor(0.0),requires_grad=False)def forward(self, preds: torch.Tensor, targets: torch.Tensor):preds = preds.argmax(dim=-1)m = (preds == targets).sum()n = targets.shape[0] self.correct += m self.total += nreturn m/ndef compute(self):return self.correct.float() / self.total def reset(self):self.correct -= self.correctself.total -= self.tota

# 三,训练模型
loss_fn = nn.CrossEntropyLoss()
optimizer= torch.optim.Adam(net.parameters(),lr = 0.01)   
metrics_dict = nn.ModuleDict("acc":Accuracy())

device = torch.device("mps" if torch.backends.mps.is_available() else "cpu")
net.to(device)
loss_fn.to(device)
metrics_dict.to(device)
epochs = 20 
ckpt_path='checkpoint.pt'#early_stopping相关设置
monitor="val_acc"
patience=5
mode="max"history = for epoch in range(1, epochs+1):printlog("Epoch 0 / 1".format(epoch, epochs))

net.train()total_loss,step = 0,0loop = tqdm(enumerate(dl_train), total =len(dl_train),ncols=100)train_metrics_dict = deepcopy(metrics_dict) for i, batch in loop: features,labels = batch
features = features.to(device)labels = labels.to(device)
forwardpreds = net(features)loss = loss_fn(preds,labels)
backwardloss.backward()optimizer.step()optimizer.zero_grad()
metricsstep_metrics = "train_"+name:metric_fn(preds, labels).item() for name,metric_fn in train_metrics_dict.items()step_log = dict("train_loss":loss.item(),**step_metrics)total_loss += loss.item()step+=1if i!=len(dl_train)-1:loop.set_postfix(**step_log)else:epoch_loss = total_loss/stepepoch_metrics = "train_"+name:metric_fn.compute().item() for name,metric_fn in train_metrics_dict.items()epoch_log = dict("train_loss":epoch_loss,**epoch_metrics)loop.set_postfix(**epoch_log)for name,metric_fn in train_metrics_dict.items():metric_fn.reset()for name, metric in epoch_log.items():history[name] = history.get(name, []) + [metric]

net.eval()total_loss,step = 0,0loop = tqdm(enumerate(dl_val), total =len(dl_val),ncols=100)val_metrics_dict = deepcopy(metrics_dict) with torch.no_grad():for i, batch in loop: features,labels = batch
features = features.to(device)labels = labels.to(device)
forwardpreds = net(features)loss = loss_fn(preds,labels)
metricsstep_metrics = "val_"+name:metric_fn(preds, labels).item() for name,metric_fn in val_metrics_dict.items()step_log = dict("val_loss":loss.item(),**step_metrics)total_loss += loss.item()step+=1if i!=len(dl_val)-1:loop.set_postfix(**step_log)else:epoch_loss = (total_loss/step)epoch_metrics = "val_"+name:metric_fn.compute().item() for name,metric_fn in val_metrics_dict.items()epoch_log = dict("val_loss":epoch_loss,**epoch_metrics)loop.set_postfix(**epoch_log)for name,metric_fn in val_metrics_dict.items():metric_fn.reset()epoch_log["epoch"] = epoch           for name, metric in epoch_log.items():history[name] = history.get(name, []) + [metric]
arr_scores = history[monitor]best_score_idx = np.argmax(arr_scores) if mode=="max" else np.argmin(arr_scores)if best_score_idx==len(arr_scores)-1:torch.save(net.state_dict(),ckpt_path)print("<<<<<< reach best 0 : 1 >>>>>>".format(monitor,arr_scores[best_score_idx]),file=sys.stderr)if len(arr_scores)-best_score_idx>patience:print("<<<<<<  without improvement in  epoch, early stopping >>>>>>".format(monitor,patience),file=sys.stderr)break net.load_state_dict(torch.load(ckpt_path))dfhistory = pd.DataFrame(history)

4.使用torchkeras支持Mac M1芯片加速

我在最新的3.3.0的torchkeras版本中引入了对 mac m1芯片的支持,当存在可用的 mac m1芯片/ GPU 时,会默认使用它们进行加速,无需做任何配置。

使用范例如下

!pip install torchkeras>=3.3.0
import numpy as np 
import pandas as pd 
from matplotlib import pyplot as plt
import torch
from torch import nn
import torch.nn.functional as F
from torch.utils.data import Dataset,DataLoader
import torchkeras
import torchvision 
from torchvision import transforms

transform = transforms.Compose([transforms.ToTensor()])
ds_train = torchvision.datasets.MNIST(root="mnist/",train=True,download=True,transform=transform)
ds_val = torchvision.datasets.MNIST(root="mnist/",train=False,download=True,transform=transform)
dl_train =  torch.utils.data.DataLoader(ds_train, batch_size=128, shuffle=True, num_workers=2)
dl_val =  torch.utils.data.DataLoader(ds_val, batch_size=128, shuffle=False, num_workers=2)for features,labels in dl_train:break 

def create_net():net = nn.Sequential()net.add_module("conv1",nn.Conv2d(in_channels=1,out_channels=64,kernel_size = 3))net.add_module("pool1",nn.MaxPool2d(kernel_size = 2,stride = 2))net.add_module("conv2",nn.Conv2d(in_channels=64,out_channels=512,kernel_size = 3))net.add_module("pool2",nn.MaxPool2d(kernel_size = 2,stride = 2))net.add_module("dropout",nn.Dropout2d(p = 0.1))net.add_module("adaptive_pool",nn.AdaptiveMaxPool2d((1,1)))net.add_module("flatten",nn.Flatten())net.add_module("linear1",nn.Linear(512,1024))net.add_module("relu",nn.ReLU())net.add_module("linear2",nn.Linear(1024,10))return netnet = create_net()
print(net)# 评估指标
class Accuracy(nn.Module):def __init__(self):super().__init__()self.correct = nn.Parameter(torch.tensor(0.0),requires_grad=False)self.total = nn.Parameter(torch.tensor(0.0),requires_grad=False)def forward(self, preds: torch.Tensor, targets: torch.Tensor):preds = preds.argmax(dim=-1)m = (preds == targets).sum()n = targets.shape[0] self.correct += m self.total += nreturn m/ndef compute(self):return self.correct.float() / self.total def reset(self):self.correct -= self.correctself.total -= self.total

model = torchkeras.KerasModel(net,loss_fn = nn.CrossEntropyLoss(),optimizer= torch.optim.Adam(net.parameters(),lr=0.001),metrics_dict = "acc":Accuracy())from torchkeras import summary
summary(model,input_data=features);

used.dfhistory=model.fit(train_data=dl_train, val_data=dl_val, epochs=15, patience=5, monitor="val_acc",mode="max",ckpt_path='checkpoint.pt')

model.evaluate(dl_val)

model.predict(dl_val)[0:10]


net_clone = create_net() 
net_clone.load_state_dict(torch.load("checkpoint.pt"))

5.M1芯片与CPU和Nvidia GPU速度对比

使用以上代码作为范例,分别在CPU, mac m1芯片,以及Nvidia GPU上 运行。

得到的运行速度截图如下:

纯CPU跑效果

Mac M1 芯片加速效果


Tesla P100 GPU加速效果

纯CPU跑一个epoch大约是3min 18s。

使用mac m1芯片加速,一个epoch大约是33 s,相比CPU跑,加速约6倍。

这和pytorch官网显示的训练过程平均加速7倍相当。

使用Nvidia Tesla P100 GPU加速,一个epoch大约是 8s,相比CPU跑,加速约25倍。

整体来说Mac M1芯片对 深度学习训练过程的加速还是非常显著的,通常达到5到7倍左右。

不过目前看和企业中最常使用的高端的Tesla P100 GPU相比,还是有2到4倍的训练速度差异,可以视做一个mini版的GPU吧。

因此Mac M1芯片比较适合本地训练一些中小规模的模型,快速迭代idea,使用起来还是蛮香的。

尤其是本来就打算想换个电脑的,用mac做开发本来比windows好使多了

如何使用 M1 芯片在我的 Mac 上运行 pyqt5

【中文标题】如何使用 M1 芯片在我的 Mac 上运行 pyqt5【英文标题】:How can i run pyqt5 on my mac with M1chip 【发布时间】:2021-04-30 05:25:34 【问题描述】:

现在。当我运行它时。错误导致 ImportError: dlopen(/Users/v/Library/Python/3.8/lib/python/site-packages/PyQt5/QtWidgets.abi3.so, 2): 找不到合适的图像。发现: /Users/v/Library/Python/3.8/lib/python/site-packages/PyQt5/QtWidgets.abi3.so:mach-o,但架构错误 /Users/v/Library/Python/3.8/lib/python/site-packages/PyQt5/QtWidgets.abi3.so:mach-o,但架构错误

【问题讨论】:

显然,M1 芯片太新了,Python 本身并不知道它们发生了什么。我听说过一种叫做“Rosetta”的东西,它可以让你在英特尔 Mac 上运行类似的东西。试试看? 【参考方案1】:

我需要 PyQt5 作为 Python 库的依赖项,这对我有用。见原帖here。

brew install pyqt5
echo 'export PATH="/opt/homebrew/opt/qt@5/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/opt/homebrew/opt/pyqt@5/5.15.4_1/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

【讨论】:

【参考方案2】:

您可以从自制软件中使用它,这是我发现它在 Mac M1 上工作的唯一方法。

第一:

  brew install pyqt@5

然后:

brew --cellar
brew link --overwrite python

然后您必须为 python 创建/添加一个别名并将其放入您的 .zprofile(如果您按 Shift+command+,则位于用户/用户名文件夹中。

这必须指向你的 homebrew python 安装位置。

alias python ='opt/homebrew/bin/python3'

这样它将python与您的自制python链接,您可以从终端运行python test.py(您的python文件所在的位置)。 无论我如何尝试使用 pip install,它都只是显示错误并且不起作用。

【讨论】:

【参考方案3】:

在我的情况下,它的工作:arch -x86_64 brew install pyqt 并且所有必需的 pyqt 都从 arch -x86_64 开始或从 rosetta 开始(通过模拟器)。

【讨论】:

【参考方案4】:

经过数小时的反复试验,我终于能够解决这个问题。我的成功配置是:

    使用 Rosetta 2 (https://dev.to/courier/tips-and-tricks-to-setup-your-apple-m1-for-development-547g) 打开终端 使用非自制python(我的在/usr/bin/python3)创建虚拟环境
/usr/bin/python3 -m venv env
source env/bin/activate
    升级点子
pip install --upgrade pip
    安装 PyQt5
pip install PyQt5

【讨论】:

在 Rosetta 模式下运行终端对我有用 - 谢谢 试图让这个工作从一天开始!该死的,谢谢伙计:) 这对我有用。为什么通过自制软件安装的 python 不起作用? 如果它与 Rosetta 一起安装,它仍然可以与原生 M1 python 一起使用吗?几天前我刚拿到我的 m1 MacBook Pro,如果这是一个愚蠢的问题,我深表歉意。【参考方案5】:

我最终专门为pyqt5 做的是:

brew install pyqt@5

我认为对于版本 4 和 6,这可能也适用。当我简单地去brew install pyqt 时,不幸的是没有用。

请注意,这只是 M1 Macbook

在 M1 稳定下来后,要尝试的另一件事是在以 Rosetta 模式启动的终端中尝试 pip3 install pyqt5(左键单击 -> 获取信息 -> 在 Rosetta 中打开)

【讨论】:

【参考方案6】:

尝试在ARM架构下安装pyqt如下

arch -arm64 brew install pyqt

【讨论】:

以上是关于mac m1芯片如何使用gpu的主要内容,如果未能解决你的问题,请参考以下文章

IDE代码编辑器:PyCharm CE for Mac中文版支持m1芯片

如何在 mac M1(Apple 芯片)上使用 google_sign_in api 进行开发

Spark for Mac(电子邮件客户端)最新版支持m1芯片

【M1芯片Mac】Nuxt构建太慢

m1进入恢复模式很慢

新买的mac 电脑m1芯片安装ps pr安装不了?