11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Apple SiliconでPytorchを動かしてみる M1MAX vs NVIDIA GPU

Posted at

こんにちは、ドイです。
Macでディープラーニングの勉強をすべく記事を書きためていこうと思っています。
今回はPytorchでのMacのGPU利用と、性能確認を行います。

PytorchでMacのGPUを利用する

PytorchがM1チップなどApple Silicon MacでGPUの利用が可能となりました。

Introducing Accelerated PyTorch Training on Mac
https://pytorch.org/blog/introducing-accelerated-pytorch-training-on-mac/

PyTorch v1.12 release, developers and researchers can take advantage of Apple silicon GPUs for significantly faster model training.

DeepLでの翻訳

PyTorch v1.12では、開発者や研究者はAppleのシリコンGPUを活用し、大幅に高速なモデルトレーニングを行えるようになります。

(以下、引用部分はDeep Lで翻訳した内容を引用)

AppleのMetal Performance Shaders(MPS)を利用することでMacのGPUを利用することができるようです。
これまではCPUしか利用できませんでしたが、M1やM2などのApple シリコンチップであれば内蔵GPUを使うことができます。

Apple製Macは、ユニファイドメモリアーキテクチャを採用しており、
GPUがすべてのメモリストアに直接アクセスできるようになっています。
このため、Macは機械学習のための優れたプラットフォームとなり、
ユーザーはより大きなネットワークやバッチサイズをローカルでトレーニングすることができます。
これにより、クラウドベースの開発やローカルGPUの追加に関連するコストを削減できます。

環境はmacOS 12.3以降
すべてMacでとありますがIntelCPUのMacを持ち合わせていないので他の方で試した結果を教えてくださいね。
一応、、Appleシリコンシリーズだけの話かなと思って書いています。

mpsをデバイスとして選べるかどうかの判断は、
torch.backends.mps.is_available()
を用いて調べることができます。

結果がゼロになればOKです。

M1MAXでCPU vs GPU(mps)やってみた

PytorchでResnet18を用いたディープラーニングで学習時間を検証します。
用いるMacは、M1MAX 14インチMacBook Proになります。
10coreCPU 24core GPU メモリ32GBです。

プログラムはこちらを使わせていただきました。
https://github.com/HidetoshiKawaguchi/tech-blog-codes/tree/main/20220731_pytorch-m1-macbook-gpu

以下、デバイスの指定のところだけちょこっといじりました。

import torch
from torch.nn import CrossEntropyLoss
from torch.optim import SGD
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10
from torchvision import transforms as tt
from torchvision.models import resnet18

import os
from argparse import ArgumentParser
import time

def main(device):
    # ResNetのハイパーパラメータ
    n_epoch = 5            # エポック数
    batch_size = 512       # ミニバッチサイズ
    momentum = 0.9         # SGDのmomentum
    lr = 0.01              # 学習率
    weight_decay = 0.00005 # weight decay

    # 訓練データとテストデータを用意
    mean = (0.491, 0.482, 0.446)
    std = (0.247, 0.243, 0.261)
    train_transform = tt.Compose([
        tt.RandomHorizontalFlip(p=0.5),
        tt.RandomCrop(size=32, padding=4, padding_mode='reflect'),
        tt.ToTensor(),
        tt.Normalize(mean=mean, std=std)
    ])
    test_transform = tt.Compose([tt.ToTensor(), tt.Normalize(mean, std)])
    root = os.path.dirname(os.path.abspath(__file__))
    train_set = CIFAR10(root=root, train=True,
                        download=True, transform=train_transform)
    train_loader = DataLoader(train_set, batch_size=batch_size,
                              shuffle=True, num_workers=8)

    # ResNetの準備
    resnet = resnet18()
    resnet.fc = torch.nn.Linear(resnet.fc.in_features, 10)

    # 訓練
    criterion = CrossEntropyLoss()
    optimizer = SGD(resnet.parameters(), lr=lr,
                    momentum=momentum, weight_decay=weight_decay)
    train_start_time = time.time()
    resnet.to(device)
    resnet.train()
    for epoch in range(1, n_epoch+1):
        train_loss = 0.0
        for inputs, labels in train_loader:
            inputs = inputs.to(device)
            optimizer.zero_grad()
            outputs = resnet(inputs)
            labels = labels.to(device)
            loss = criterion(outputs, labels)
            loss.backward()
            train_loss += loss.item()
            del loss  # メモリ節約のため
            optimizer.step()
        print('Epoch {} / {}: time = {:.2f}[s], loss = {:.2f}'.format(
            epoch, n_epoch, time.time() - train_start_time, train_loss))
    print('Train time on {}: {:.2f}[s] (Train loss = {:.2f})'.format(
        device, time.time() - train_start_time, train_loss))

    # 評価
    test_set = CIFAR10(root=root, train=False, download=True,
                       transform=test_transform)
    test_loader = DataLoader(test_set, batch_size=batch_size,
                             shuffle=False, num_workers=8)
    test_loss = 0.0
    test_start_time = time.time()
    resnet.eval()
    for inputs, labels in test_loader:
        inputs = inputs.to(device)
        outputs = resnet(inputs)
        labels = labels.to(device)
        loss = criterion(outputs, labels)
        test_loss += loss.item()
    print('Test time on {}: {:.2f}[s](Test loss = {:.2f})'.format(
        device, time.time() - test_start_time, test_loss))


if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument('--device', type=str, default='mps',
                        choices=['cpu', 'mps', 'cuda'])
    args = parser.parse_args()
    device = torch.device(args.device)
    main(device)

M1MAXのCPUを指定

ScreenShot 2022-08-23 22.04.45.jpg
思ったほどCPU負荷が上がっていませんね。
もっと全力出してほしい。

% python pytorch_m1_macbook.py --device cpu
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to /Users/satoshi/git/cifar-10-python.tar.gz
100%|█████████████████████████████████████████████████████████████████████████████████████████████| 170498071/170498071 [00:53<00:00, 3205505.20it/s]
Extracting /Users/satoshi/git/cifar-10-python.tar.gz to /Users/satoshi/git
Epoch 1 / 5: time = 416.14[s], loss = 171.38
Epoch 2 / 5: time = 837.20[s], loss = 138.99
Epoch 3 / 5: time = 1257.28[s], loss = 124.96
Epoch 4 / 5: time = 1672.27[s], loss = 113.21
Epoch 5 / 5: time = 2122.82[s], loss = 104.77
Train time on cpu: 2122.82[s] (Train loss = 104.77)
Files already downloaded and verified

学習時間は2122秒。そこそこかかりましたね。

M1MAXのGPUを指定

ScreenShot 2022-08-23 22.22.29.jpg

GPUも目一杯使ってるわけではなさそうですね。
もしかしたらブースターかける方法があるのかも???

% python pytorch_m1_macbook.py --device mps
Files already downloaded and verified
Epoch 1 / 5: time = 68.32[s], loss = 173.48
Epoch 2 / 5: time = 128.38[s], loss = 138.95
Epoch 3 / 5: time = 188.78[s], loss = 124.67
Epoch 4 / 5: time = 248.96[s], loss = 114.29
Epoch 5 / 5: time = 309.02[s], loss = 106.39
Train time on mps: 309.02[s] (Train loss = 106.39)
Files already downloaded and verified

309秒!!

ここから参考に開発用ハイスペックマシンとの比較を行います。

Win10のCPUを指定

Windows 10 Pro
Intel(R) Core(TM) i9-10980XE CPU @ 3.00GHz 3.00 GHz

Epoch 1 / 5: time = 77.13[s], loss = 168.85
Epoch 2 / 5: time = 152.89[s], loss = 136.54
Epoch 3 / 5: time = 228.79[s], loss = 123.56
Epoch 4 / 5: time = 304.61[s], loss = 113.26
Epoch 5 / 5: time = 379.44[s], loss = 104.18
Train time on cpu: 379.44[s] (Train loss = 104.18)
Files already downloaded and verified
Test time on cpu: 23.96[s](Test loss = 21.25)

学習時間は379.44秒
あら???M1MAXのGPUとさほど変わらない??

Win10のNVIDIA GPUを指定

NVIDIA Quadro RTX 8000

Epoch 1 / 5: time = 40.68[s], loss = 170.00
Epoch 2 / 5: time = 74.70[s], loss = 135.34
Epoch 3 / 5: time = 108.20[s], loss = 120.69
Epoch 4 / 5: time = 142.11[s], loss = 111.18
Epoch 5 / 5: time = 176.35[s], loss = 104.24
Train time on cuda: 176.35[s] (Train loss = 104.24)
Files already downloaded and verified
Test time on cuda: 23.13[s](Test loss = 20.66)

学習時間は176秒 圧倒的!!
NVIDIA Quadro RTX 8000はめちゃんこ高いGPUですもんね。
まだまだ性能的にはNVIDIAのGPUの方が良さそうですが、
Macの健闘しましたね(と思いたい)

これからもMacに特化して勉強しながら記事を書きたいと思います。

参考記事
https://zenn.dev/hidetoshi/articles/20220731_pytorch-m1-macbook-gpu

11
10
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?