Mac m1チップはGPUをどのように使用しますか

ここに画像の説明を挿入

2022 年 5 月、PyTorch は、Mac の M1 チップ バージョンでモデル アクセラレーションを正式にサポートしたことを正式に発表しました。公式の比較データによると、CPU と比較して、M1 の錬金速度を平均 7 倍高速化できます。

1.加速原理

質問 1: Mac M1 チップを使用して pytorch を高速化できるのはなぜですか?

Mac M1 チップは単なる CPU チップではなく、CPU (中央処理装置)、GPU (グラフィック処理装置)、NPU (ニューラル ネットワーク エンジン)、統合メモリ装置などの多くのコンポーネントを含む統合チップです。Mac M1 チップには GPU コンポーネントが統合されているため、pytorch の高速化に使用できます。

質問 2: Mac M1 チップの GPU のビデオ メモリはどれくらいですか?

Mac M1 チップの CPU と GPU はユニファイド メモリ ユニットを使用します。したがって、Mac M1 チップで使用できるメモリ サイズは、Mac コンピュータのメモリ サイズです。

質問 3: Mac M1 チップを使用して pytorch を高速化するには、cuda バックエンドをインストールする必要がありますか?

いいえ、cuda は nvidia の GPU に適合しています.Mac M1 チップの GPU に適合したアクセラレーション バックエンドは mps です.これは、対応する Mac オペレーティング システムで既に利用可能であり、個別にインストールする必要はありません. 適応したpytorchをインストールするだけです

質問 4: Mac Intel チップ コンピュータにインストールできる一部のソフトウェアが、Mac M1 チップ コンピュータにインストールできないのはなぜですか?

Mac M1 チップは、高性能と省電力を追求するために、Intel などの一般的な CPU チップが使用する x86 アーキテクチャの完全な命令セットとは異なる、arm アーキテクチャと呼ばれる単純化された命令セットを基盤の設計に使用しています。したがって、x86 命令セットに基づいて開発された一部のソフトウェアは、Mac M1 チップ コンピュータでは直接使用できません。

2. 環境構成

まずはmacの型番をチェック

デスクトップの左上隅にある mac アイコンをクリックします-----このマシンについて、それが m1 チップであることを確認し、メモリ サイズを確認します (16G 以上あることが望ましいです。8G では不十分な場合があります)。 )。

ここに画像の説明を挿入

2.1 miniforge3 のダウンロード

miniforge3 は、 M1 チップにより安定したサポートを提供する miniconda/annoconda のコミュニティ バージョンとして理解できます。

ここに画像の説明を挿入

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. CPUとNvidia GPUを搭載したM1チップの速度比較

上記のコードを例として使用して、CPU、mac m1 チップ、および Nvidia GPU で実行します。

得られた実行速度のスクリーンショットは次のとおりです。

純粋な CPU 実行効果
ここに画像の説明を挿入

Mac M1 チップの加速効果

ここに画像の説明を挿入
Tesla P100 GPU 加速効果

ここに画像の説明を挿入

純粋な CPU は、エポックを約 3 分 18 秒間実行します。

mac m1 チップを使用して高速化すると、エポックは約 33 秒で、CPU の実行よりも約 6 倍高速です。

これは、pytorch の公式 Web サイトで表示されているトレーニング プロセスの平均 7 倍の加速に相当します。

ここに画像の説明を挿入

Nvidia Tesla P100 GPU アクセラレーションを使用すると、エポックは約 8 秒で、CPU の実行よりも約 25 倍高速です。

全体として、ディープ ラーニング トレーニング プロセスに対する Mac M1 チップの加速は依然として非常に大きく、通常は約 5 ~ 7 倍に達します。

ただし、エンタープライズで最も一般的に使用されているハイエンドのTesla P100 GPUと比較すると、トレーニング速度にはまだ2〜4倍の差があり、GPUのミニバージョンと見なすことができます.

したがって、Mac M1 チップは、小規模および中規模モデルのローカル トレーニング、アイデアの迅速な反復に適しています。

特に、もともとパソコンを乗り換えようと考えていた人にとっては、Windows よりも Mac を使った開発の方がはるかに簡単です。

おすすめ

転載: blog.csdn.net/weixin_45277161/article/details/129934151