macm1芯片如何使用gpu(代码片段)

githubcurry githubcurry     2023-04-11     694

关键词:

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好使多了

macm1芯片安装homebrew(代码片段)

   MacBookM1芯片安装代码如下,打开终端输入:/bin/bash-c"$(curl-fsSLhttps://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install.sh)"看到如果下图 Installationsuccessful!  还不算完下边配置环境变量非常重要一定要记得,输入下边两条命... 查看详情

macm1芯片安装homebrew(代码片段)

   MacBookM1芯片安装代码如下,打开终端输入:/bin/bash-c"$(curl-fsSLhttps://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install.sh)"看到如果下图 Installationsuccessful!  还不算完下边配置环境变量非常重要一定要记得,输入下边两条命... 查看详情

macm1上android开发使用protobuf报错处理(代码片段)

MacM1笔记本上加载以前项目是,protobuf报错了:因为MacM1芯片是ARM架构的,在使用protobuf时就需要添加:osx-x86_64后缀 。 这样问题就解决了。 查看详情

macm1芯片安装homebrew(代码片段)

   MacBookM1芯片安装代码如下,打开终端输入:/bin/bash-c"$(curl-fsSLhttps://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install.sh)"看到如果下图 Installationsuccessful!  还不算完下边配置环境变量非常重要一定要记得,输入下边两条命... 查看详情

macm1芯片安装homebrew(代码片段)

   MacBookM1芯片安装代码如下,打开终端输入:/bin/bash-c"$(curl-fsSLhttps://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install.sh)"看到如果下图 Installationsuccessful!  还不算完下边配置环境变量非常重要一定要记得,输入下边两条命... 查看详情

macm1芯片可下载的安卓模拟器androidemulator(代码片段)

记录一下MACM1芯片可下载的Android模拟器AndroidEmulator安装使用过程最近在做h5+的移动端APP,使用HBuilderX打包运行的,用自己的安卓手机突然检测不到设备,就想下载一个Android模拟器,找了很多模拟器发现大部分... 查看详情

macm1芯片本地安装hadoop集群填坑之路(代码片段)

文章目录背景环境前置知识安装过程#bug1#bug2#bug3背景学习一项技能的最好方式自然是理解+实践,在了解了hadoop的基本概念后我开始尝试在本地搭建一个集群环境用于进一步学习。但是经过尝试后发现想在MacOS中搭建一个集... 查看详情

macm1芯片安装python3.6环境(代码片段)

...omebrew安装pyenv、pyenv-virtualenv安装python3.6.15MAC新款搭载了M1芯片,python版本最低只能装3.8的,但是有的项目需要安装3.8之前版本的python,记录一下过程参考:MacM1下搭建Python3.6-3.8环境MacM1安装pyenv,python3.6~3.... 查看详情

ai芯片:商业项目gpu怎么选?(代码片段)

AI芯片:商业项目GPU怎么选?通用芯片CPU专用芯片GPUFPGAASIC商业项目的芯片怎么选?通用芯片CPUCPU是由十几亿的晶体管以分层的思想,制造出来的。TA的模型是由信息论鼻祖22岁的香农在硕士毕业时发表的一篇论文&#... 查看详情

macm1上丝滑跑docker(代码片段)

...运行的开源项目移植到Mac上跑得试下,但是之前MacM1芯片并不能很好地支持Docker,这不,发现Docker也正式支持Mac了 查看详情

macm1芯片安装ffmpeg以及使用

参考技术A1首先要安装brew2  gitclonehttps://git.ffmpeg.org/ffmpeg.gitffmpeg3 cdffmpeg4执行脚本 ./configure--prefix=/opt/local5编译 make6安装 makeinstall7安装成功,查看 ffmpeg版本  /opt/local/bin/ffmpeg-version这样已经安装成... 查看详情

python如何检查是否使用了gpu(代码片段)

查看详情

macm1关闭sip系统完整性保护csrutildisable,如何禁用macm1的系统完整性保护(代码片段)

macm1关闭sip系统完整性保护csrutildisable,如何禁用macm1的系统完整性保护问题如何关闭SIP(SystemIntegrityProtection)1、重启电脑,关机状态下长按开机键,直到出现选项设置后松开,进入恢复模式2、选择“选项”,然... 查看详情

macm1pro芯片安装vmware虚拟机及centos8(界面化+黑窗口)详细教程(代码片段)

目录一、安装vmware虚拟机二、Centos8镜像支持M1芯片三、安装Centos8系统1、打开虚拟机软件,点击创建自定虚拟机,再点击继续3、选择新建虚拟磁盘,点击继续4、选择自定设置5、选择自定义的虚拟机存储位置,进... 查看详情

macm1用idea写java非常卡?这样设置直接起飞!!!(代码片段)

...xff1a;https://www.jetbrains.com/zh-cn/idea/download/#section=macAppleM1芯片选择AppleSiliconIntel芯片选择Intel选择的版本为VM这的。jdk选择其次我们还应该选择对应的jdk版本。AppleM1芯片需要选择后边aarch64的JDK版本下载完成之后,复制JAVA_HOME... 查看详情

macm1用idea写java非常卡?这样设置直接起飞!!!(代码片段)

...xff1a;https://www.jetbrains.com/zh-cn/idea/download/#section=macAppleM1芯片选择AppleSiliconIntel芯片选择Intel选择的版本为VM这的。jdk选择其次我们还应该选择对应的jdk版本。AppleM1芯片需要选择后边aarch64的JDK版本下载完成之后,复制JAVA_HOME... 查看详情

macm1下docker部署mysql和navicate连接docker数据库(代码片段)

一、拉取镜像dockerpullmysql/mysql-server:latestmysqlOS/ARCH全部都是linux/amd64,m1芯片需要安装arm64版本,因此安装mysql-server,否则会报错“nomatchingmanifestforlinux/arm64/v8inthemanifestlistentries”二、查看本地镜像dockerimages三、启动容 查看详情

macm1安装stablediffusionwebui教程及问题集锦(代码片段)

...使用教程启用深色主题推荐几个网址我的配置MacBookPro14M1芯片:AppleM1Pro内存:16G安装视频教程可参考如下链接:主播讲的挺清楚mac如何本地部署stablediffusion(支持更换模组,支持M1,M2)【mac如何本地部署stablediffusion(支持更... 查看详情