『GPUを支える技術』とディープラーニング

# 『GPUを支える技術』とディープラーニング
2017/07/26 水曜日に[PyData Tokyo Meetup #14](https://pydatatokyo.connpass.com/event/61925/)に参加してきました。
内容は[NVIDIA](http://www.nvidia.co.jp/page/home.html)の方によるディープラーニングでして、ディープラーニング用NVIDIA GPUの選び方やNVIDIAのディープラーニング界隈への貢献をきくことができました。
ちょうど先週から「[GPUを支える技術](https://www.amazon.co.jp/GPU%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-%E2%80%95%E2%80%95%E8%B6%85%E4%B8%A6%E5%88%97%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E5%BF%AB%E9%80%B2%E6%92%83-%E6%8A%80%E8%A1%93%E5%9F%BA%E7%A4%8E-PRESS-plus/dp/477419056X)」を読んでいたので、GPUについて学んだことをまとめたいと思います。

## 個人的なGPUの思い出
始めてGPUを使ったのは10年くらい前の大学時代にPCを組み立てたときです。CPUはAMD、GPUはGeForceにした覚えがあります（マザーボードはASUSだったかな？）。
AMDにもRADEONがありますが、せっかくPC自作するならいろいろ違うものを組み合わせよう、とGPUはNVIDIAにしたのです。
GPUがほしかった理由はスト4をプレイしたかったからでした。
その後就職してからは自宅であまりPCを使わなくなり（プログラミングの重い処理にはAWSやAzureを使うため、自宅PCに金をかけなくなり）、GPUとの蜜月は終わりました。

あと、当時はGeForceを「ゲフォース」と呼んでいました。

ここ１，２年くらい仕事や趣味でディープラーニングをやり始めて、またGPUがほしくなってきたため、会社でTeslaを買う交渉をしているのが近況です。


## GPU
さて、PyDataでのディープラーニングセッションですが、ディープラーニング向けNVIDIA GPUの選び方からNVIDIAが開発しているソフトウェアまで、いろいろを聞くことができました。
内容はほぼこの[資料](https://www.gputechconf.jp/assets/files/1011.pdf)にあります。

![alt](https://devblogs.nvidia.com/parallelforall/wp-content/uploads/2016/04/gp100_block_diagram-1-624x368.png)

### NVIDIA GPUの選び方メモ
ディープラーニングには大きく２つのフェーズがあります。
1. 学習（Training）フェーズ：収集したデータから予測モデルを生成します。ディープラーニングの学習については以下をご参考ください。ディープラーニングとGPUの関係で重要なのは、学習フェーズでは浮動小数点数（または倍精度浮動小数点数）演算をものすごいたくさん計算しなければならない、ということです。ディープラーニングでは学習時に入力データと重みの積和演算を繰り返し（フォワードプロパゲーション）、そして重みを修正するために微分と積和演算を繰り返し（バックプロパゲーション、誤差逆伝播法）、ということをひたすら繰り返すという重い処理が長時間流れます。その積和演算にGPUのコアが有効になります。
2. 予測（推論、Inference, Predict）フェーズ：学習で作ったモデルを実利用します。学習では学習用に用意したデータを使いますが、予測では実データを投入します。こちらはフォワードプロパゲーションを１回のみで、バックプロパゲーションも繰り返しもありません。学習に比べたら軽い処理になりますが、オンラインでリアルタイムに利用される予測モデル（スマホカメラとディープラーニングの組み合わせとか、金融商品取引とか）だと、やはりスピードが重要になります。

[はじめるDeep learning](http://qiita.com/icoxfog417/items/65e800c3a2094457c3a0)
[【機械学習】ディープラーニング フレームワークChainerを試しながら解説してみる。](http://qiita.com/kenmatsu4/items/7b8d24d4c5144a686412)

ディープラーニングの２フェーズのうち、学習は浮動小数点数演算（float32）か倍精度浮動小数点数演算（float64）になります。予測ももちろん浮動小数点数演算を使いますが、スピード重視のために半精度浮動小数点数（float16）や整数（int8）が使われることもあります。浮動小数点数のほうが正確だけど、リアルタイム処理は無理（演算能力的に）というときはfloat16やint8です。精度と時間と技術は三角関係のトレードオフなのです。

最新のPascal世代GPUは学習向けと予測向けがわかれているようです。
- GP100（CC6.0）は学習向けで、float16, float32, float64をサポート。ただしint8は未サポート。つまり、浮動小数点数演算であればブッチギリで速いが、整数演算は並（計算できないわけではない）。電力消費は莫大で、データセンターとかで使うことが想定されているっぽい。
- GP102（CC6.1）は予測向けで、float32とint8をサポート。ただしfloat16やfloat64は未サポート。電力消費も抑え気味。PCとか社内サーバとか、身近な場所で使う想定（？）

用途でわかれているPascal GPUですが、次世代の[Volta](https://www.nvidia.com/en-us/data-center/volta-gpu-architecture/)では浮動小数点数も整数も１GPUでサポートする予定らしいです。

![alt](http://livedoor.blogimg.jp/wisteriear/imgs/9/a/9a45341a.jpg)


##### 余談
なお、予測ではFPGAを使おうという研究もあります。この辺りはIntelやMicrosoft、Googleが頑張っているようです。

[そろそろプログラマーもFPGAを触ってみよう！](http://qiita.com/kazunori279/items/a9e97a4463cab7dda8b9)
[ニューラルネットワークの量子化についての最近の研究の進展と、その重要性](https://developer.smartnews.com/blog/2017/03/neural-network-quantization/)

### アーキテクチャ
詳しく書き始めると本が１冊できあがる（[GPUを支える技術](https://www.amazon.co.jp/GPU%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-%E2%80%95%E2%80%95%E8%B6%85%E4%B8%A6%E5%88%97%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E5%BF%AB%E9%80%B2%E6%92%83-%E6%8A%80%E8%A1%93%E5%9F%BA%E7%A4%8E-PRESS-plus/dp/477419056X)）ので、手短に。
GPUは元来は画像処理（ディスプレイへの表示）を担う機器でしたが、構造的に一部の科学技術計算を行うのに向いていたため、その方面での利用（画像処理に特価しない、より一般的な利用。GPGPU=General Purpose GPU）に向けた開発も進めてきました。

GPUが画像処理を行うにあたり、座標変換計算（パイプライン）と色や明るさの計算（ライティング）をリアルタイムに行うため、１デバイスに多数の演算器（コア）とメモリ・キャッシュを登載しました。CPUと違ってGPUは単純な計算を同時にたくさん実行することが求められたのですが、それがちょうど科学技術計算でも必要なものだったのです。

その流れで、画像処理では不要だった倍精度浮動小数点数演算やエラー検出・訂正、CUDAプログラミングが登場してきます。つまり、科学技術計算ではfloat32で不足する桁数をfloat64（またはfloat128）にする必要があり、さらには画像処理で不要だった各演算のエラー検出が科学技術計算では必要になりました（計算エラーが科学技術の正確性を損ねるため）。

アーキテクチャとしては、GPUの演算器は複数のSM（ストリーミング・マルチプロセッサ）で区切られており、SMの中にコアがたくさん搭載されている構成です。

![alt](https://devblogs.nvidia.com/parallelforall/wp-content/uploads/2016/04/gp100_SM_diagram-624x452.png)

コアには計算に応じた種類があり、float16・float32演算を行うCUDAコア、float64演算を行うFP64、三角関数や平方根演算を行うSFUがあります。命令はスレッドブロックという単位となり、SMに割り当てます。SM内では32スレッドをワープというまとまりにして同時並列実行します。複数ワープができあがるときはワーププールに格納し、ワープスケジューラが実行制御（入力オペランドが揃い、実行可能になったワープから順番に実行）します。

GPUのメモリはデバイスメモリが採用されています。デバイス上にレジスタ、L1/L2キャッシュ、シェアードメモリ、メモリがある構成です。レジスタ、L1/L2キャッシュ、メモリはCPUと同様です。シェアードメモリとはスレッド間でデータのやり取りをする共有空間です。

GPUとマザーボードとはPCI-Expressで接続します。しかしPCI-Expressでは遅いことがあるので、NVIDIAでは[NVLINK](http://www.nvidia.co.jp/object/nvlink-jp.html)という独自規格でGPU間を相互接続できるようです。

![alt](https://3s81si1s5ygj3mzby34dq6qf-wpengine.netdna-ssl.com/wp-content/uploads/2016/05/nvidia-pascal-nvlink-dgx-1.jpg)


・・・全然手短になりませんね。まあ詳しいことは本やホワイトペーパーを読みましょう（力尽きました。ごめんなさい）。
[GPUを支える技術](https://www.amazon.co.jp/GPU%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-%E2%80%95%E2%80%95%E8%B6%85%E4%B8%A6%E5%88%97%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E5%BF%AB%E9%80%B2%E6%92%83-%E6%8A%80%E8%A1%93%E5%9F%BA%E7%A4%8E-PRESS-plus/dp/477419056X)
[NVIDIA Pascal GPU Whitepaper](https://images.nvidia.com/content/pdf/tesla/whitepaper/pascal-architecture-whitepaper.pdf)


### NVIDIAが出している便利そうな製品やツール（GPU以外）
自分メモ用です。NVIDIAの商品紹介ではありません。
#### [DGX1](http://www.nvidia.co.jp/object/deep-learning-system-jp.html)
Pascal世代GPUを8個登載したNVIDIAのスーパーサーバです。すげえ。
下記のNCCLでマルチGPUディープラーニングができるし、環境を分割したい場合（特定バージョンのTensorFlowを使いたい、とかとか）はDockerコンテナを使うようです。

#### [NCCL](https://developer.nvidia.com/nccl)
[NCCL](https://developer.nvidia.com/nccl)はNVIDIAのマルチGPUライブラリです。複数GPUでディープラーニングを分散処理するために使うようです。
現在のNCCLだと同一サーバのGPU連携ですが、NCCL2になるとマルチサーバでのマルチGPU分散処理（サーバ間はInfinibandで接続）になるようです。
[NCCL2も登録](https://developer.nvidia.com/nccl/nccl2-interest-list)すれば使えるようですね。

#### [NVIDIA Docker](https://github.com/NVIDIA/nvidia-docker)
NVIDIAの提供しているDockerイメージです。
各イメージは特定のディープラーニングフレームワークでのCUDA利用に最適化されているようです。もちろん、DockerホストサーバにGPUが必要です。

#### [Digit](https://developer.nvidia.com/digits)
ノンプログラミングで使えるディープラーニング学習、予測環境です。インストーラ、AWS AMIやDockerイメージで提供しています。
ディープラーニングをやってみたいけど、プログラミングが難しそうという方向けです。


## 終わりに
GPUで遊びたいです。