2018年版 機械学習ハードウェアのState of the Artを考える ~CPU, GPU, TPUを添えて~

[機械学習工学 / MLSE Advent Calendar 2018](https://qiita.com/advent-calendar/2018/mlse)の5日目の記事です。

# tl;dr
機械学習を走らせるハードウェアは大きくCPU,GPU,FPGA,ASIC。

CPUは他と比べると並列性が足ずこれからも性能は伸びない。
現状のところソフトウェアスタックが整備されているGPUが最強。
しかしFPGA,ASICは伸びしろが大きく、来年以降はどんどんシェアを伸ばしてきそうで楽しみ。

# 目的
2018年現在のMLHW（機械学習ハードウェア）の最も高性能なもの（State Of the Art）を考える記事です。特になんで性能が良いのか、というコンピュータアーキテクチャ的な考察を分野外の方向けに行いたいと思います。

想定している聴衆は機械学習（本記事ではディープラーニング系タスクを指し機械学習やMLと言わせて頂きます）の学習・推論を行うソフト系エンジニアです。

筆者はハード系の研究者なのですが、近年の機械学習システムは以前と比べ大幅に演算・モデル規模が大きくなったため、デプロイ時には走るハードウェアに関する知識も必要となって来ていると思います。
本記事が僅かでもデプロイ時にハードウェアを選ぶ際の参考になれば幸いと考えてます。
出来るだけハードウェアなんて全然わからんという人にもハードウェアの種類やそれぞれのメリットについて理解いただけたらと思います。

特に本記事では機械学習の性能に直結するハードウェアアクセラレータの重要な概念である**並列性とメモリ律速**について理解いただけたらと思います。

~~半分コンピュータアーキテクチャ入門のようになってしまった。。:(~~
ただ**並列性とメモリシステム**はコンピュータサイエンスを支える重要な概念なのでお付き合いいただけたらと思います。

# MLに用いるハードウェアの種類
MLも超ざっくばらんに言うと行列演算です。
このような計算プログラムを走らせるハードの選択肢としてはCPU,GPU,FPGA,ASICと4つの選択肢があります。

ここで一つ一つピックアップしていきましょう。

## CPU
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/6f8ce2a3-2390-a390-6f8c-690b95a6ec17.png)

みんなのパソコンに入っているアレです。
設計思想としてなんでも出来るようにしている反面、飛び抜けて得意な分野がありません。
データ並列性は低いため行列演算のようにデータ並列性が高いタスクにおける性能は今ひとつとなってしまいます。

DLの学習がCPUだと全然進まず、GPUだとめっちゃ早いという経験は誰にでもあるのでないでしょうか。

### 並列性やデータ並列性について
ちょっとHWのSoAからは脱線気味ですが、本記事では**並列性とメモリ律速**というのは重要な概念なので解説したいと思います。この２つの概念はコンピュータアーキテクトの間では鬼のように出てくるアクセラレータ設計では最重要な概念です。

ではまず並列性ってどういうことなんでしょう？
wikipediaのdata level parallelismから例を引っ張ってきました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/b505e91b-b0b5-5dd6-7eb2-7a7c99f14ecb.png)
単純な行列演算（MatrixMultiply)の例です。
例えばoutput[0,0]を得るためには

```
output[0,0] = 1*10+2*7+3*2
```

という演算が必要です。
この結果を得るために一度に一度しか計算が出来ない下記図のようなCPU(from CS348K)を考えてみましょう。
この行列演算自体に何サイクル必要なのでしょうか？

![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/e6b29a4a-ddae-1099-4d3b-bc3182a08799.png)

```
out = 1*10
temp = 2*7
out = out + temp
temp = 3*2
out = out + temp
```

ざっと考えてもoutput[0,0]を求めるのに**5サイクル**も必要です。
またこれを出力個数分(6)繰り返すのでこのMatrixMultiplyには演算だけで**30サイクル必要**となってしまいます。

**CPUは並列性が乏しいため、MLで重要な行列演算などが低速**というイメージを持ってもらえたら良いと思います。

### （余談）実際のCPU
実際はx86CPUもデータ並列化に対応する命令(SIMD)やメモリバス(AXI256)が拡充されているので行列演算もそこそこ効果的にこなします。
Pythonのnumpyがこれに当たりますね。Courseraの授業でnumpyを使うことにより得られる速度向上に感動した方も多いのでないでしょうか。
ただ数1000コアを持ち凄まじいマルチスレッディングを行うGPUに比べるとどうしても遅いです。

### （余談）CPUはこれ以上早くならない？
CPUは並列数が低くても一回の演算を超早くすれば性能はどんどん上がりますね。（クロックを上げる）
2010年くらいまではそのようなノリでしたが、トランジスタ微細化が伸び悩み、これ以上クロックスピードを上げるのも難しくなってきました。これを**ムーアの法則の終焉**と言ったりします。現在の先端プロセスは7nmCMOSですが、あと2世代（3nm?)で微細化は終了すると言われてます。
これまでは3-4年でクロックスピードは2倍になっていましたが、ここ十年くらいクロックは変わってないですね。**なのでCPU動作はこれからも早くなることはないと**アーキテクチャ業界では言われてます。

## 機能と性能のトレード
もちろんCPUのメリットとして命令セットが潤沢で様々なアプリケーションが走るというのは無視できません。
ただ機械学習を走らせる上ではそのような命令のほとんどを取っ払ってしまっても問題ありません。（GPU上でLinuxを走らせる人はいないですよね笑）
近年のGPU、FPGA、ASICは汎用機能と引き換えに行列演算などに特化した性能を得ると言う思想（Domain Specific Architecture)が流行しています。

それでは現在のMLHWの覇者であるGPUの設計思想や先端のアーキテクチャであるVolta100の中身を見てみましょう。

# GPU
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/56a7d6aa-62f7-e4a5-fc9f-f97f3c62e094.png)

## 並列化１（ベクトル演算）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/b505e91b-b0b5-5dd6-7eb2-7a7c99f14ecb.png)
再度この行列演算を考えてみましょう。

先程のCPUコアの演算器の数を8個に増やしてみましょう
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/7ca7ed2b-04fc-449b-ee42-a4c02b67bd79.png)

すると演算器（ALU)がたくさん使えるため、output[0,0]の計算も一度に行えます。
例えば掛け算を全部一度に（並列に）やってしまえます。

```
# 並列で実施
ALU0 = 1*10
ALU1 = 2*7
ALU2 = 3*2

ALU0 = ALU0 + ALU1
ALU0 = ALU0 + ALU2
```
掛け算を並列化したため、**3サイクル**のみで実施することができました。

またALU3-7も空いているのでそれらの演算器も使えます。
そこに例えばoutput[0,1]の演算も同時に並列演算することもできます！

すると合計で3*3=**9サイクル**で行列演算が完成します。
実に**3.3倍**の高速化ですね。行列が大きければ更にこの差は大きくなります。

## 並列化２（マルチコア）
それではこのようなコアを増やし、マルチコアシステムにしてしまいましょう。
ここでは8コアのシステムを考えます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/01b6f199-9537-6797-0f4f-81ec1947c3e9.png)

すると出力行列それぞれの要素を各コアにスケジューリングすることができます。
out[0,0]をコア０，out[0,1]をコア1、out[1,0]をコア2..というイメージ。
この例ですと全出力を同時にスケジュールできます。

各内積演算が3サイクルかかり、同時に結果が得られるため**計算にかかるサイクル数はたったの3サイクルです！**
最初の例から**10倍**の高速化ができました。

また先端GPUには80コアほどあるので80要素を並列にスケジューリングすることが可能になります。反対にCPUは16コア辺りが一般的で実に5倍コア数が違います。

またGPUはSIMD（ベクトル演算）機能が大きく、コア辺り2048データを並列に演算することができます。
80コアあるので1クロック辺り理想的には163840要素（！）演算できます。

**このようにGPUは２つの並列化（ベクトル演算、マルチコア）に特化しています。その規模がCPUの数百倍大きい**ため、MLアプリの速度差となって出てくるのですね。
更にVoltaコアはTensorCoreという行列積専用回路を備えており、更にML演算のスループットを向上します。

またGPUの特徴としてマルチスレッディングもあるのですが、データ並列性の高いDLでは恩恵はそこまで大きくないのかなと思っております。

## GPUのSoAであるVolta100アーキテクチャ
やっと本題に到達しました！
それではnVidiaが出しているGPU比較を見てみましょう。

[NVIDIA V100 white paper](https://images.nvidia.com/content/volta-architecture/pdf/volta-architecture-whitepaper.pdf)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/a401f306-164f-5f46-f563-0cfcf89b10de.png)

Tesla V100が最先端のGPUです。Pascalからの主な進歩は三点：

*　コア（nvidiaはSMと呼称）が80個と56個であったP100から増加。

*　L2キャッシュサイズが50%増加。

*　TensorCore回路を新たに搭載。

上記2点は16nm→12nmにプロセスが移行した恩恵でしょう。
来年は7nm製品（Amphere)が出るので性能スケールは順調に続きそうですね。（設計は地獄だと思いますが）

この記事ではV100におけるブレイクスルーである行列演算専用回路であるTensorCore回路の詳細について見てみましょう。

## 新たに搭載されたTensorCore
TensorCoreとはなんぞや？
一言で言うと行列演算を行うML専用の回路です。
GPUがML用にアクセラレータを備えたようなイメージでしょうか。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/8b93181c-4ab1-81a3-56fa-a7c2585c1302.png)


以前のGPUでは行列演算を行うとき、

```
# Parallize
a = 1*10
b = 2*7
c = 3*2

# Serial
a = a + b
out = a + c
```
と掛け算を並列化しても出力を得るのに最低3サイクルかかってしまいました。
TensorCoreの考えとしては

```
# 一サイクルでまとまった演算を行う
out = TensorCore(1*10+2*7+3*2)
```
とダイレクトに内積を求める**専用回路をインプリ**してます。
これならば**1サイクルで内積を求める**ことができるため、以前より行列演算の高速化が期待できます。

また上記例では出力1要素のみ求めていますが、**実際のTensorCoreは4x4出力を即時求める**のでベクタ演算機より大幅に（10倍ほど）高速となります。

内積演算にしか使えないが主な用途がそれなので問題なしと割り切ってます。
思想として**演算回路単体の動作を早くするのではなく、専用回路を設計し一番使う演算を高速化してしまおう**という方向です。
これはTPUのようなASICと同じアプローチですね。~~多分TPUの速度に負けないように導入したのでしょう。。~~

TensorCoreは機能としてTPUが持つシストリックアレイの小さいバージョンと考えて良いです。
シストリックやらなんやらは回路インプリ方法でそこまで大きな差はありません。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/8f5412a1-4c92-7059-71b3-e2f5d5c7b9a5.png)
コアにはTensorCoreがどどーんと陣取っています。
またINT専用回路もありますね。。

### CuBlas性能

![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/4f0e2e36-ee93-56e4-3eb0-cbf47143a82e.png)
Pascalに比べ、FP16の行列演算が10倍（！）早くなっています。
専用化は火力向上に大きく寄与しますね。

>Pytorch is using tensor cores on volta chip as long as your inputs are in fp16 and the dimensions of your gemms/convolutions satisfy conditions for using tensor cores (basically, gemm dimensions are multilple of 8, or, for convolutions, batch size and input and output number of channels is multiple of 8).

https://discuss.pytorch.org/t/volta-tensor-core-pytorch/18320
僕はV100持ってないので試せないのですがDLフレームワークなどでとっくに使えるみたいですね。

## メモリ律速という概念
TensorCoreを使えばGPUは**120TOPS**の性能が出るらしいです。
これはResnet(100 GOPS/frame)が**1000FPS**くらい出るスピードなのですが当然そんな速度出ませんね。

ここにハードウェアの持つメモリ律速という問題があります。

例えば100x100の行列2つの内積を取る演算を考えてみましょう。
V100であればTensorCoreが640個あるためうまく演算を分割すれば1サイクルで計算は終わるはずです。
しかしもしGPUのメモリが1サイクルで1000データしか転送できないとどうしましょう？演算を開始するには100x100x2=20000データが必要なのでGPUは**20サイクルデータ転送を待ってから計算を開始**する必要があり、結果的に行列演算に21サイクル必要です。このように**演算時間よりもデータ伝送の方が時間かかるようなケースをメモリ律速といいます。**

一般的なDRAMアクセス速度ではGPUにとって遅すぎるため、V100などの先端GPUはHighBandwidthMemory(HBM2)と言う高速規格で繋がれたDRAMを内蔵してます。ここにモデルが入り切らないとGPUのポテンシャルが発揮できないのですね。

このようなメモリ律速は走らせるモデルやアルゴリズムによって異なります。例えばCNNは重みフィルタは固定のため、畳込み演算中はフィルタをキャッシュ（チップ内メモリ）に入れ、入力のみDRAMから読むので他のネットワークに対しメモリ律速になりづらいです。全結合やLSTMモデルに対しCNNの速度がかなり早いなと思った方も多いのでないでしょうか。なので出来るだけモデルは**CNNで実装したほうがGPUの演算性能を有効活用**できますよ。(Dilated-convolutionなどが好まれるのはこの理由）


# ASIC(TPU)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/cdbaed5b-2aa4-afa1-bf75-d752f1622d4e.png)

それではASICのState of the ArtであるGoogleTPUを観ていきましょう！
~~MLHWを開発しているベンチャーはアメリカを中心に多いですが製品を出せるか怪しいです。~~

TPUv1..推論専用の8bINTプロセッサ
TPUv2..FP16で学習に対応
TPUv3..v2の改善版でGoogleCloudにて利用可能。

TPUv1については以前記事を書きましたのでご参考。

素人がGoogle TPUを作ってみる～アーキテクチャ考察編～
https://qiita.com/arutema47/items/b7be3aacd3c0d467a469

## TPUの並列性
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/7241bd3f-0fd3-2de5-e7ab-37f68524ca88.png)
TPUの思想としてはチップ全体に**256x256の行列演算を行う一つの巨大なTensorCoreを置いてしまえ！**というものです。そもそもASIC(application specific IC)の名の通り、機械学習というアプリだけに純粋に特価しているため行列演算に特化しています（活性化などの関数ももちろん）。

256x256の行列内積演算回路をベクタ演算機のように作るのは難しいためシストリックアレイというFIFOのような演算機で実装しています。ところてんのように一データずつ演算機アレイに入れていき処理します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/527b0200-692f-0abc-8f16-0c4052ef460e.png)

シストリックアレイは40年以上前に考案された回路（wavefront processor)ですが、”行列演算しかできないじゃん！”という理由で忘れ去られていました。今になって行列演算さえ効率よくできる回路がほしい！という理由で復活したのはとてもおもしろいですね。

個人的には**(TensorCoreを持つ)GPUもTPUも設計思想は似ている（行列演算に特化する）と思います。**GPUで多くを説明してしまいましたが、**この専用化の流れ自体を作り出したのは2015-2016年にGoogleがTPUv1を設計してから**というのは述べておきます。



## TPUのメモリシステム
TPUv1はDDR3でメモリボトルネックな設計となっています。
TPUv2,v3でHBM2に変わり、V100と同じメモリ帯域になりました。

そのためFP16で動くTPUv3の**メモリ律速された速度はV100と同じ**になりそうですね。
ただ**電力はTPUv3のほうが無駄な回路がないため（GPUの持つFp64やグラフィックス処理用回路）、ダンゼン低くなる**と思います。

そのため**データセンターで利用するならばTPUの方がGPUよりコストが低くなるはず**ですね。

## TPUとGPUの性能比較(速度）
TPUは市販されていないため、性能を比べたりするのが難しいというのが（アーキテクトからすると）欠点です。
CloudTPUは使えるものの、純粋にチップの性能が見れるかどうかはわかりませんね。

TPUv2とV100を比較する記事がありました。
https://blog.riseml.com/comparing-google-tpuv2-against-nvidia-v100-on-resnet-50-c2bbb6a51e5e

>For the V100 experiments, we used a p3.8xlarge instance (Xeon E5–2686@2.30GHz 16 cores, 244 GB memory, Ubuntu 16.04) on AWS with four V100 GPUs (16 GB of memory each). For the TPU experiments, we used a small n1-standard-4 instance as host (Xeon@2.3GHz two cores, 15 GB memory, Debian 9) for which we provisioned a Cloud TPU (v2–8) consisting of four TPUv2 chips (16 GB of memory each).

![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/e8a7df3e-0562-51d8-fa2b-6897136dec40.png)

予想通り**両方共(ほぼ）同じ速度**です。
これは**同じメモリIOを使っているためメモリ律速となるポイントが同じ**なんですね。

## TPUとGPUの性能比較(コスト）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/171915/a83820fb-b475-f296-0ab1-1fe2b2014d50.png)
**コストパフォーマンスを比較するとはTPUの方が優れています。**
これにはGoogleのAWSから市場を奪いたいため赤字覚悟の値段というのもありますが、ASICの方がランニングコストが低いというポイントもあるはずです。

### AWSの推論ASIC
AWSが推論用ASICを公開！値段はまだ不明？
>AWS Inferentia provides hundreds of TOPS (tera operations per second) of inference throughput to allow complex models to make fast predictions. For even more performance, multiple AWS Inferentia chips can be used together to drive thousands of TOPS of throughput.

Announcing AWS Inferentia: Machine Learning Inference Chip
https://aws.amazon.com/jp/about-aws/whats-new/2018/11/announcing-amazon-inferentia-machine-learning-inference-microchip/


# FPGA
FPGAは専門でないのでよくわからないのです。。~~燃え尽きました~~
大規模にデータセンターで使っているのはMicrosoftですね。以前までアルテラ製でしたがXilinxに切り替わっていく模様。

またFPGAアドベントカレンダーが詳しいのでそちらに詳細は譲ります。
https://qiita.com/advent-calendar/2018/fpga

一体いつから FPGA はハードウェアだと錯覚していた？
https://qiita.com/ikwzm/items/f54b8930dfc5ebac66b4

個人的に気になっているプロジェクト。
ざっくばらんに言うとFPGAにTensorCoreのような行列演算回路を載せ、ML処理速度を向上させるというアプローチ。みんな同じ方向に向かってますね。
[Xilinx Announces Project Everest: The 7nm FPGA SoC Hybrid](https://www.anandtech.com/show/12509/xilinx-announces-project-everest-fpga-soc-hybrid)



# AWSに使用されている機械学習ハードウェアとコストパフォーマンス
https://qiita.com/arutema47/items/20fabcca6b6eb24f2778

|インスタンス |コンピューティングユニット |単位時間コスト（1時間あたり） | 演算量 (TOPSまたはTFLOPS) |\$1で得られるTOPS|
|----|----|---|---|---|
|C4 |CPU(E5-2660)x2|\$1.75|2(1x2)|1.14|
|P2 |GPU(K80)x16|\$15.84|48(3x16)|3.03|
|F1 |FPGA(USVU9P)x8|\$13.20|54 |4.09|
|??| ASIC | ?? | ?? | 一番コスパ高いハズ |

一つの会社から出ているコンピューティングユニット間のコストを比べるのが一番フェアな比較です。
過去記事でAWSの値段からそれぞれのハードウェアのコスパを計算しました。（元ネタはパタヘネ第六版）
2017年地点の情報なのでGPUの型番が古かったりしますが、大まかなコストパフォーマンスは変わらないでしょう。

FPGAかASICが最もコストパフォーマンスが優れますが、使えるようにするためには（FPGAは）**ハードウェア記述＋DNNコンパイラの設計といったソフトウェアスタック開発**が必要です。その分が最終コストへのしかかってきます。
またASICは**回路開発コスト+ソフトウェアスタック開発費**が掛かるため、GPUに対しどこまで安く値段が下げられるかは不透明です。Googleくらいの経済スケールがないと値段は高止まりしてしまうのではないでしょうか。

そのため現在はソフトウェアスタックが公開されている（cuda+DNNフレームワーク対応）GPUがコストパフォーマンスが最も高いMLHWの王者と考えております。
ここからFPGAやASICがどれくらい追い上げを見せるか楽しみですね。

# ハードウェアを更に勉強したい方へのオススメ書籍
## CPU
教科書
[コンピュータの構成と設計 第5版](https://www.amazon.co.jp/%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%81%AE%E6%A7%8B%E6%88%90%E3%81%A8%E8%A8%AD%E8%A8%88-%E7%AC%AC5%E7%89%88-%E4%B8%8A-%E3%82%B8%E3%83%A7%E3%83%B3%E3%83%BBL-%E3%83%98%E3%83%8D%E3%82%B7%E3%83%BC/dp/4822298426/ref=pd_sim_14_2?_encoding=UTF8&pd_rd_i=4822298426&pd_rd_r=23a40475-f5b4-11e8-8732-43ea6338bb30&pd_rd_w=EhAxz&pd_rd_wg=uEtuR&pf_rd_i=desktop-dp-sims&pf_rd_m=AN1VRQENFRJN5&pf_rd_p=68cfebef-f8b4-4691-9d72-a10f0956615a&pf_rd_r=D3JE26RBQ352AHTVESQK&pf_rd_s=desktop-dp-sims&pf_rd_t=40701&psc=1&refRID=D3JE26RBQ352AHTVESQK)
実装
[素人が作る超基本CPU](https://qiita.com/arutema47/items/40dc748e349c30d7194a)

## GPU
[NVIDIA V100 white paper](https://images.nvidia.com/content/volta-architecture/pdf/volta-architecture-whitepaper.pdf)
[CS348 Throughput architectures review](http://cs348k.stanford.edu/fall18/lecture/introreview)

## FPGA
[Microsoft Project Catapult](https://www.microsoft.com/en-us/research/project/project-catapult/)

[Xilinx Announces Project Everest: The 7nm FPGA SoC Hybrid](https://www.anandtech.com/show/12509/xilinx-announces-project-everest-fpga-soc-hybrid)

## ASIC
[TPUの論文@ISCA](https://ieeexplore.ieee.org/abstract/document/8192463/)

Kaz Satohさんのわかりやすい解説ブログ。必読。
[An in-depth look at Google’s first Tensor Processing Unit (TPU)](https://cloud.google.com/blog/products/gcp/an-in-depth-look-at-googles-first-tensor-processing-unit-tpu)

[What makes TPU fine-tuned for DeepLearning?](https://cloud.google.com/blog/products/ai-machine-learning/what-makes-tpus-fine-tuned-for-deep-learning)

昔書いたTPUアーキ考察記事
https://qiita.com/arutema47/items/b7be3aacd3c0d467a469