CUDAのFP16で遊ぼう!

目次

雑なタイトルですがCUDAのFP16でできること/できないことを書いていきます.
楽しくハフハフしましょう.

この記事を読むといい人

  • CUDAのカーネル関数を自分で書いていて,FP16に手を出したい人

この記事を読んでも楽しくない人

  • cuBLASなんかで適当にFP16を使いたい人
  • Pythonとかもっと雑な言語のラッパーで使いたい人

CUDAのFP16についての雑な説明

CUDAの半精度はIEEE 754 binary16です.
符号部1bit,指数部5bit,仮数部10bitです.
有効桁数は3桁程度です.

NVIDIAのPascalアーキテクチャから利用可能です.
実は一部のMaxwellでも使えます.

FP16の利点

  • 省メモリ

    半精度は単精度の半分です.
    嬉しいです.

  • SIMDが使える

    正式に名称があるわけではないのですが,CUDA PTXでf16x2と記述されるSIMD命令が使えます.
    これはFP16変数2つに対してadd,sub,fmaなどを1命令で計算することができます.
    cuda_fp16.hの中を覗くとわかるのですが,divは2つにばらして別々に計算して再度まとめているのでSIMDではないです.

  • Volta世代や一部を除くTuring世代ではTensorコアが使える

    行列積速いです.
    WMMA APIというTensorコア用のAPIが用意されています.

FP16の欠点

  • 精度が悪い

    精度が必要ないなら問題ないです.

  • Pascalから対応していると言ってもGeForceのPascalでは遅い

    Tesla P100を使いましょう(骨董品).

FP16を使うは

型はhalfです.
SIMDを使いたければhalf2です.

型変換

__float2halfなどなどfloat, halfの相互変換関数が用意されています.
最近のCUDAではホストとデバイスのどちらからでも呼べます.
不確かですが,CUDA9.1などではホストからは呼べなかった気がします.
簡単なビット演算で自作できるのでどうしても古いCUDAを使いたければ自作してどうぞ.
変換関数一覧はこちら
C++っぽくtemplateで型変換を行いたい人向けにcutfというheader onlyで使える小さいライブラリを作りました.

算術関数

組み込み関数が用意されています.
と言っても関数を呼ぶとinline asmでPTXに変わるだけなんですけどね.
halfの算術関数一覧はこちら
half2の算術関数一覧はこちら
SIMDは注意点があって,halfのポインタをhalf2にキャストしたくなってしまうと思うのですが,alignment制約があるのでちゃんと4byte境界で組み込み関数に渡してあげないとダメです.

Tensorコア

昔インターンで使い方を調査してブログにまとめたのこちらを御覧ください.
(ピーク性能の1~2%程度しか出ていない気がするのは目をつぶってください)
ここに書いたfragmentの構造はVolta世代用(仮想アーキsm_70用)のもので,Turing世代(仮想アーキsm_75)では構造が大きく変わっています.
普通にAPIを使うだけなら気にしなくていいことですが.
WMMA APIの悪いところは厳しいalignment制約と提供されている機能の少なさだと思うんですよね.
多分おかげでかなり高速なAPIとなっているのですが.
機能の少なさというのは,例えば16x1行列をfragmentとして読み込みたければメモリ上の16x16行列の1列目に目的の行列を書き込み,残りは0とし,load_matrix_syncで読まないといけません.
無駄なメモリと0埋めコストがかかるんですよね.
用意してくれてもいいのに.
そこでWMMA APIの拡張を作ったりました.
fragmentの構造を解析するとこういうものを作れるようになります.

このブログの関連記事

  • Kahanの加算をFP16でやってみた

    低精度変数2つを使って加算時の誤差を小さくしようという話です.
    指数部が小さくなるので大きい数と小さい数を足すとちゃんと足し込まれなくなってしまうんですよね.
    精度を保つための計算にTensorコアが使えたりすると研究しがいがありますね.

  • half2の水平加算

    half2に入っている2つのhalfを足す計算を速く計算するにはどうすればいいかという話です.
    なんだそのおちって感じの結論です.

  • PTXでf16x2

    PTXでhalf2の2つのhalfを分解して扱いたくなったらどうすればいいかという話です.

  • CUDA 9.2 WMMA API fill_fragmentのバグ

    CUDA 9.2のWMMA APIにバグを見つけた話です.
    まだまだ枯れていない分野なのでバグもありますよね.

  • half2のmax

    half2に対するSIMD maxをbit演算で自作する話です.

さいごに

ちゃんと書けば速くなるのでちゃんと書きましょう.
楽しいよ!

カテゴリー:CUDA
記事作成日:2019-08-16