取りあえず何か創る

ソフトウェアエンジニアだけど仕事以外でも何か作りたくなったので、主にその記録のためにブログを開設しました。

読書記録 GPUを支える技術

0. この投稿の概要

  • GPUを支える技術」を読んで学んだことをまとめました。2021年に出た増補改訂版の内容です。進化の激しい分野なので、読まれる場合は改訂版を手に取ることをおすすめします。

  • 自分はディープラーニングの学習/推論のためにGPUを使うので、主にそこに焦点を当ててまとめています。グラフィックスについては省略しています。

1. 学んだこと

ハードウェア

  • 並列処理の方式: 同じ命令を多数のスレッドで並列実行するような動きをするSIMT方式が主流。データ並列度は使っていないため、依存関係のない命令を集めたり、データのサイズを演算器の数に合わせたりしなくても効率を高めやすい。
  • 精度の問題: 科学技術計算では64bitの倍精度浮動小数点も必要とされているが、ディープラーニングの推論ではそれほどの精度は必要なく、16bitの半精度浮動小数点や場合によっては8bitの固定小数点で計算しても結果に影響はない。参考: How to Quantize Neural Networks with TensorFlow « Pete Warden's blog
    • INT8の演算器はFP32よりも5~10倍小さい面積で実装ができるため、Googleは8bit整数で推論を行うTPUというカスタムLSIを開発した。
    • IEEEで規定されているFP16は指数部が5bit、仮数部が10bitだがディープラーニングの場合はオーバーフローしないように指数部が大きい方が扱いやすい。そのため指数部8bit, 仮数部7bitとしたBF16が多くのチップでサポートされている。
  • ベンチマーク: ディープラーニングを実行する場合の性能のベンチマークとしてMLPerfが開発されている。
    • 学習ベンチマークでは画像分類や物体検知のようなタスクに対して、目標性能に達した時間の学習時間を測定する。
    • 推論ベンチマークではFP32による推論の99%の精度を達成する必要があり、推論時間を測定する。

ソフトウェア

  • CUDA: NVIDIAが開発したGPUプログラミングに最低限必要な機能をC言語に追加した言語。
    • CPUとGPUはそれぞれメモリを持っているため、CUDAではデータの格納場所を修飾子で指定する。低速大容量のデバイスメモリやGPUに内蔵された高速低容量のシェアードメモリがある。
    • CUDAではベクトル型の変数タイプをサポートしている。ベクトル長は1~4まで。
    • 大まかな処理の流れ: ホスト/デバイス双方にデータの受け渡しようのメモリ領域を確保→ホストからデバイスへデータのコピー→カーネルを起動して計算を実行→結果をデバイスからホストにコピー→使い終わったメモリを解放。
      • ユニファイドメモリを使う場合はデータのコピー処理を明示する必要はなくなる。
  • OpenCL: 業界標準GPUプログラミング環境で、CUDAと似ているところが多い。
    • OpenCLは各社のGPUをサポートするため、構成を問い合わせる関数で情報を得て、それに対応した操作を行えるように作られている。
    • OpenCL 2.2ではC++14ベースのカーネル記述がサポートされている。
    • NVIDIAはCUDAのサポートを優先しており、AMDはHIPというCUDAのコードをAMD GPU用にコンパイルするシステムを開発している。
  • OpenMP/OpenACC: C言語のコードに「この部分はGPUで並列実行」といった指示行を加えるだけでGPUプログラミングを実現する。
    • OpenMPの方がサポート範囲は広いが、NVIDIAはOpenACCを優先している。NVIDIA GPUを使う場合はOpenACC、そうでなければOpenMPという使い分け。
    • CUDA/OpenCLで最適化したプログラムに性能は及ばないが、開発工数は少ないのでまず試してみる価値はある。

2. 感想